summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmds/dumpstate/dumpstate.cpp7
-rw-r--r--data/etc/android.software.opengles.deqp.level-2023-03-01.xml2
-rw-r--r--data/etc/android.software.opengles.deqp.level-2024-03-01.xml4
-rw-r--r--data/etc/android.software.opengles.deqp.level-2025-03-01.xml21
-rw-r--r--data/etc/android.software.opengles.deqp.level-latest.xml4
-rw-r--r--data/etc/android.software.vulkan.deqp.level-2024-03-01.xml4
-rw-r--r--data/etc/android.software.vulkan.deqp.level-2025-03-01.xml21
-rw-r--r--data/etc/android.software.vulkan.deqp.level-latest.xml4
-rw-r--r--include/input/InputConsumerNoResampling.h86
-rw-r--r--include/input/KeyCharacterMap.h6
-rw-r--r--include/input/Resampler.h6
-rw-r--r--libs/binder/BackendUnifiedServiceManager.cpp23
-rw-r--r--libs/binder/IPCThreadState.cpp33
-rw-r--r--libs/binder/IServiceManager.cpp44
-rw-r--r--libs/binder/OS.h1
-rw-r--r--libs/binder/OS_android.cpp4
-rw-r--r--libs/binder/OS_non_android_linux.cpp4
-rw-r--r--libs/binder/include/binder/IServiceManager.h23
-rw-r--r--libs/binder/include/binder/Trace.h1
-rw-r--r--libs/binder/ndk/Android.bp1
-rw-r--r--libs/binder/ndk/binder_rpc.cpp352
-rw-r--r--libs/binder/ndk/ibinder.cpp133
-rw-r--r--libs/binder/ndk/ibinder_internal.h7
-rw-r--r--libs/binder/ndk/include_cpp/android/binder_interface_utils.h36
-rw-r--r--libs/binder/ndk/include_ndk/android/binder_ibinder.h44
-rw-r--r--libs/binder/ndk/include_ndk/android/persistable_bundle.h109
-rw-r--r--libs/binder/ndk/include_platform/android/binder_manager.h4
-rw-r--r--libs/binder/ndk/include_platform/android/binder_rpc.h261
-rw-r--r--libs/binder/ndk/libbinder_ndk.map.txt16
-rw-r--r--libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp31
-rw-r--r--libs/binder/rust/src/binder.rs25
-rw-r--r--libs/binder/rust/src/lib.rs7
-rw-r--r--libs/binder/rust/src/parcel/parcelable_holder.rs45
-rw-r--r--libs/binder/rust/tests/parcel_fuzzer/parcel_fuzzer.rs19
-rw-r--r--libs/binder/tests/Android.bp3
-rw-r--r--libs/binder/tests/binderRpcTest.cpp349
-rw-r--r--libs/binder/tests/parcel_fuzzer/binder_ndk.cpp3
-rw-r--r--libs/binder/trusty/OS.cpp4
-rw-r--r--libs/binder/trusty/ndk/include/android/llndk-versioning.h3
-rw-r--r--libs/debugstore/OWNERS1
-rw-r--r--libs/debugstore/rust/Android.bp1
-rw-r--r--libs/debugstore/rust/src/core.rs8
-rw-r--r--libs/gui/BLASTBufferQueue.cpp22
-rw-r--r--libs/gui/FenceMonitor.cpp36
-rw-r--r--libs/gui/IProducerListener.cpp6
-rw-r--r--libs/gui/SurfaceControl.cpp4
-rw-r--r--libs/gui/include/gui/BLASTBufferQueue.h3
-rw-r--r--libs/gui/include/gui/FenceMonitor.h8
-rw-r--r--libs/gui/include/gui/Flags.h (renamed from include/input/LooperInterface.h)27
-rw-r--r--libs/gui/include/gui/IProducerListener.h6
-rw-r--r--libs/gui/include/gui/Surface.h2
-rw-r--r--libs/input/InputConsumerNoResampling.cpp146
-rw-r--r--libs/input/KeyCharacterMap.cpp15
-rw-r--r--libs/input/Resampler.cpp5
-rw-r--r--libs/input/android/os/IInputConstants.aidl6
-rw-r--r--libs/input/tests/Android.bp1
-rw-r--r--libs/input/tests/InputConsumer_test.cpp242
-rw-r--r--libs/input/tests/InputPublisherAndConsumerNoResampling_test.cpp2
-rw-r--r--libs/input/tests/Resampler_test.cpp27
-rw-r--r--libs/input/tests/TestEventMatchers.h187
-rw-r--r--libs/input/tests/TestInputChannel.cpp21
-rw-r--r--libs/input/tests/TestLooper.cpp51
-rw-r--r--libs/input/tests/TestLooper.h56
-rw-r--r--libs/renderengine/OWNERS2
-rw-r--r--libs/renderengine/benchmark/RenderEngineBench.cpp3
-rw-r--r--libs/vibrator/TEST_MAPPING2
-rw-r--r--opengl/libs/EGL/egl_platform_entries.cpp6
-rw-r--r--services/inputflinger/dispatcher/Android.bp1
-rw-r--r--services/inputflinger/dispatcher/CancelationOptions.h3
-rw-r--r--services/inputflinger/dispatcher/InputDispatcher.cpp81
-rw-r--r--services/inputflinger/dispatcher/InputDispatcher.h5
-rw-r--r--services/inputflinger/dispatcher/InputEventTimeline.h10
-rw-r--r--services/inputflinger/dispatcher/InputState.cpp2
-rw-r--r--services/inputflinger/dispatcher/LatencyAggregator.cpp7
-rw-r--r--services/inputflinger/dispatcher/LatencyAggregator.h2
-rw-r--r--services/inputflinger/dispatcher/LatencyAggregatorWithHistograms.cpp345
-rw-r--r--services/inputflinger/dispatcher/LatencyAggregatorWithHistograms.h164
-rw-r--r--services/inputflinger/dispatcher/LatencyTracker.cpp24
-rw-r--r--services/inputflinger/dispatcher/LatencyTracker.h9
-rw-r--r--services/inputflinger/dispatcher/TouchState.cpp7
-rw-r--r--services/inputflinger/dispatcher/TouchState.h3
-rw-r--r--services/inputflinger/dispatcher/TouchedWindow.cpp50
-rw-r--r--services/inputflinger/dispatcher/TouchedWindow.h13
-rw-r--r--services/inputflinger/include/InputReaderBase.h9
-rw-r--r--services/inputflinger/reader/EventHub.cpp5
-rw-r--r--services/inputflinger/reader/InputDevice.cpp18
-rw-r--r--services/inputflinger/reader/InputReader.cpp9
-rw-r--r--services/inputflinger/reader/include/EventHub.h8
-rw-r--r--services/inputflinger/reader/include/InputDevice.h6
-rw-r--r--services/inputflinger/reader/include/InputReader.h2
-rw-r--r--services/inputflinger/tests/FakeEventHub.cpp5
-rw-r--r--services/inputflinger/tests/FakeEventHub.h4
-rw-r--r--services/inputflinger/tests/InputDispatcher_test.cpp93
-rw-r--r--services/inputflinger/tests/InputReader_test.cpp2
-rw-r--r--services/inputflinger/tests/InterfaceMocks.h5
-rw-r--r--services/inputflinger/tests/LatencyTracker_test.cpp4
-rw-r--r--services/inputflinger/tests/fuzzers/InputReaderFuzzer.cpp4
-rw-r--r--services/inputflinger/tests/fuzzers/LatencyTrackerFuzzer.cpp6
-rw-r--r--services/inputflinger/tests/fuzzers/MapperHelpers.h3
-rw-r--r--services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp22
-rw-r--r--services/surfaceflinger/FrontEnd/RequestedLayerState.cpp20
-rw-r--r--services/surfaceflinger/FrontEnd/RequestedLayerState.h1
-rw-r--r--services/surfaceflinger/Layer.cpp68
-rw-r--r--services/surfaceflinger/Layer.h73
-rw-r--r--services/surfaceflinger/OWNERS3
-rw-r--r--services/surfaceflinger/PowerAdvisor/OWNERS1
-rw-r--r--services/surfaceflinger/SurfaceFlinger.cpp24
-rw-r--r--services/surfaceflinger/Tracing/LayerDataSource.cpp7
-rw-r--r--services/surfaceflinger/Tracing/LayerTracing.cpp38
-rw-r--r--services/surfaceflinger/Tracing/LayerTracing.h7
-rw-r--r--services/surfaceflinger/TransactionCallbackInvoker.cpp4
-rw-r--r--services/surfaceflinger/tests/unittests/LayerLifecycleManagerTest.cpp10
-rw-r--r--services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp15
-rw-r--r--services/surfaceflinger/tests/unittests/TestableScheduler.h4
-rw-r--r--services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h28
-rw-r--r--services/vibratorservice/TEST_MAPPING5
116 files changed, 3080 insertions, 805 deletions
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 220fef6f8d..d427ecf280 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -170,6 +170,7 @@ void add_mountinfo();
#define ALT_PSTORE_LAST_KMSG "/sys/fs/pstore/console-ramoops-0"
#define BLK_DEV_SYS_DIR "/sys/block"
+#define AFLAGS "/system/bin/aflags"
#define RECOVERY_DIR "/cache/recovery"
#define RECOVERY_DATA_DIR "/data/misc/recovery"
#define UPDATE_ENGINE_LOG_DIR "/data/misc/update_engine_log"
@@ -1792,6 +1793,10 @@ Dumpstate::RunStatus Dumpstate::dumpstate() {
RunCommand("ACONFIG FLAGS", {PRINT_FLAGS},
CommandOptions::WithTimeout(10).Always().DropRoot().Build());
+ RunCommand("ACONFIG FLAGS DUMP", {AFLAGS, "list"},
+ CommandOptions::WithTimeout(10).Always().AsRootIfAvailable().Build());
+ RunCommand("WHICH ACONFIG FLAG STORAGE", {AFLAGS, "which-backing"},
+ CommandOptions::WithTimeout(10).Always().AsRootIfAvailable().Build());
RunCommand("STORAGED IO INFO", {"storaged", "-u", "-p"});
@@ -3533,7 +3538,7 @@ std::future<std::string> Dumpstate::MaybeSnapshotSystemTraceAsync() {
// the dumpstate's own activity which is irrelevant.
RunCommand(
SERIALIZE_PERFETTO_TRACE_TASK, {"perfetto", "--save-for-bugreport"},
- CommandOptions::WithTimeout(10).DropRoot().CloseAllFileDescriptorsOnExec().Build(),
+ CommandOptions::WithTimeout(30).DropRoot().CloseAllFileDescriptorsOnExec().Build(),
false, outFd);
// MaybeAddSystemTraceToZip() will take care of copying the trace in the zip
// file in the later stages.
diff --git a/data/etc/android.software.opengles.deqp.level-2023-03-01.xml b/data/etc/android.software.opengles.deqp.level-2023-03-01.xml
index d0b594c73d..7aef9ec6c4 100644
--- a/data/etc/android.software.opengles.deqp.level-2023-03-01.xml
+++ b/data/etc/android.software.opengles.deqp.level-2023-03-01.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright 2021 The Android Open Source Project
+<!-- Copyright 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.
diff --git a/data/etc/android.software.opengles.deqp.level-2024-03-01.xml b/data/etc/android.software.opengles.deqp.level-2024-03-01.xml
index 4eeed2af4f..3d8a17819c 100644
--- a/data/etc/android.software.opengles.deqp.level-2024-03-01.xml
+++ b/data/etc/android.software.opengles.deqp.level-2024-03-01.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright 2021 The Android Open Source Project
+<!-- Copyright 2024 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.
@@ -15,7 +15,7 @@
-->
<!-- This is the standard feature indicating that the device passes OpenGL ES
- dEQP tests associated with date 2023-03-01 (0x07E70301). -->
+ dEQP tests associated with date 2024-03-01 (0x7e80301). -->
<permissions>
<feature name="android.software.opengles.deqp.level" version="132645633" />
</permissions>
diff --git a/data/etc/android.software.opengles.deqp.level-2025-03-01.xml b/data/etc/android.software.opengles.deqp.level-2025-03-01.xml
new file mode 100644
index 0000000000..e005356555
--- /dev/null
+++ b/data/etc/android.software.opengles.deqp.level-2025-03-01.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2025 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<!-- This is the standard feature indicating that the device passes OpenGL ES
+ dEQP tests associated with date 2025-03-01 (0x7e90301). -->
+<permissions>
+ <feature name="android.software.opengles.deqp.level" version="132711169" />
+</permissions>
diff --git a/data/etc/android.software.opengles.deqp.level-latest.xml b/data/etc/android.software.opengles.deqp.level-latest.xml
index 62bb10161a..1ad35bce07 100644
--- a/data/etc/android.software.opengles.deqp.level-latest.xml
+++ b/data/etc/android.software.opengles.deqp.level-latest.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright 2023 The Android Open Source Project
+<!-- Copyright 2025 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.
@@ -17,5 +17,5 @@
<!-- This is the standard feature indicating that the device passes OpenGL ES
dEQP tests associated with the most recent level for this Android version. -->
<permissions>
- <feature name="android.software.opengles.deqp.level" version="132645633" />
+ <feature name="android.software.opengles.deqp.level" version="132711169" />
</permissions>
diff --git a/data/etc/android.software.vulkan.deqp.level-2024-03-01.xml b/data/etc/android.software.vulkan.deqp.level-2024-03-01.xml
index 8b2b4c8199..185edbf4bd 100644
--- a/data/etc/android.software.vulkan.deqp.level-2024-03-01.xml
+++ b/data/etc/android.software.vulkan.deqp.level-2024-03-01.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright 2021 The Android Open Source Project
+<!-- Copyright 2024 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.
@@ -15,7 +15,7 @@
-->
<!-- This is the standard feature indicating that the device passes Vulkan dEQP
- tests associated with date 2023-03-01 (0x07E70301). -->
+ tests associated with date 2024-03-01 (0x7e80301). -->
<permissions>
<feature name="android.software.vulkan.deqp.level" version="132645633" />
</permissions>
diff --git a/data/etc/android.software.vulkan.deqp.level-2025-03-01.xml b/data/etc/android.software.vulkan.deqp.level-2025-03-01.xml
new file mode 100644
index 0000000000..b424667b3a
--- /dev/null
+++ b/data/etc/android.software.vulkan.deqp.level-2025-03-01.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2025 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<!-- This is the standard feature indicating that the device passes Vulkan dEQP
+ tests associated with date 2025-03-01 (0x7e90301). -->
+<permissions>
+ <feature name="android.software.vulkan.deqp.level" version="132711169" />
+</permissions>
diff --git a/data/etc/android.software.vulkan.deqp.level-latest.xml b/data/etc/android.software.vulkan.deqp.level-latest.xml
index 0fc12b3b5f..4128a95ffd 100644
--- a/data/etc/android.software.vulkan.deqp.level-latest.xml
+++ b/data/etc/android.software.vulkan.deqp.level-latest.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright 2023 The Android Open Source Project
+<!-- Copyright 2025 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.
@@ -17,5 +17,5 @@
<!-- This is the standard feature indicating that the device passes Vulkan
dEQP tests associated with the most recent level for this Android version. -->
<permissions>
- <feature name="android.software.vulkan.deqp.level" version="132645633" />
+ <feature name="android.software.vulkan.deqp.level" version="132711169" />
</permissions>
diff --git a/include/input/InputConsumerNoResampling.h b/include/input/InputConsumerNoResampling.h
index 358a19158e..228347d818 100644
--- a/include/input/InputConsumerNoResampling.h
+++ b/include/input/InputConsumerNoResampling.h
@@ -16,8 +16,13 @@
#pragma once
+#include <functional>
+#include <map>
+#include <memory>
+#include <optional>
+
+#include <input/Input.h>
#include <input/InputTransport.h>
-#include <input/LooperInterface.h>
#include <input/Resampler.h>
#include <utils/Looper.h>
@@ -36,7 +41,7 @@ public:
/**
* When you receive this callback, you must (eventually) call "consumeBatchedInputEvents".
* If you don't want batching, then call "consumeBatchedInputEvents" immediately with
- * std::nullopt frameTime to receive the pending motion event(s).
+ * std::nullopt requestedFrameTime to receive the pending motion event(s).
* @param pendingBatchSource the source of the pending batch.
*/
virtual void onBatchedInputEventPending(int32_t pendingBatchSource) = 0;
@@ -67,26 +72,17 @@ public:
class InputConsumerNoResampling final {
public:
/**
- * This constructor is exclusively for test code. Any real use of InputConsumerNoResampling must
- * use the constructor that takes an sp<Looper> parameter instead of
- * std::shared_ptr<LooperInterface>.
- */
- explicit InputConsumerNoResampling(const std::shared_ptr<InputChannel>& channel,
- std::shared_ptr<LooperInterface> looper,
- InputConsumerCallbacks& callbacks,
- std::unique_ptr<Resampler> resampler);
-
- /**
* @param callbacks are used to interact with InputConsumerNoResampling. They're called whenever
* the event is ready to consume.
* @param looper needs to be sp and not shared_ptr because it inherits from
* RefBase
- * @param resampler the resampling strategy to use. If null, no resampling will be
- * performed.
+ * @param resamplerCreator callable that returns the resampling strategy to be used. If null, no
+ * resampling will be performed. resamplerCreator must never return nullptr.
*/
- explicit InputConsumerNoResampling(const std::shared_ptr<InputChannel>& channel,
- sp<Looper> looper, InputConsumerCallbacks& callbacks,
- std::unique_ptr<Resampler> resampler);
+ explicit InputConsumerNoResampling(
+ const std::shared_ptr<InputChannel>& channel, sp<Looper> looper,
+ InputConsumerCallbacks& callbacks,
+ std::function<std::unique_ptr<Resampler>()> resamplerCreator);
~InputConsumerNoResampling();
@@ -96,15 +92,17 @@ public:
void finishInputEvent(uint32_t seq, bool handled);
void reportTimeline(int32_t inputEventId, nsecs_t gpuCompletedTime, nsecs_t presentTime);
/**
- * If you want to consume all events immediately (disable batching), the you still must call
- * this. For frameTime, use a std::nullopt.
- * @param frameTime the time up to which consume the events. When there's double (or triple)
- * buffering, you may want to not consume all events currently available, because you could be
- * still working on an older frame, but there could already have been events that arrived that
- * are more recent.
+ * If you want to consume all events immediately (disable batching), then you still must call
+ * this. For requestedFrameTime, use a std::nullopt. It is not guaranteed that the consumption
+ * will occur at requestedFrameTime. The resampling strategy may modify it.
+ * @param requestedFrameTime the time up to which consume the events. When there's double (or
+ * triple) buffering, you may want to not consume all events currently available, because you
+ * could be still working on an older frame, but there could already have been events that
+ * arrived that are more recent.
* @return whether any events were actually consumed
*/
- bool consumeBatchedInputEvents(std::optional<nsecs_t> frameTime);
+ bool consumeBatchedInputEvents(std::optional<nsecs_t> requestedFrameTime);
+
/**
* Returns true when there is *likely* a pending batch or a pending event in the channel.
*
@@ -119,9 +117,15 @@ public:
private:
std::shared_ptr<InputChannel> mChannel;
- std::shared_ptr<LooperInterface> mLooper;
+ sp<Looper> mLooper;
InputConsumerCallbacks& mCallbacks;
- std::unique_ptr<Resampler> mResampler;
+ const std::function<std::unique_ptr<Resampler>()> mResamplerCreator;
+
+ /**
+ * A map to manage multidevice resampling. Each contained resampler is never null. This map is
+ * only modified by handleMessages.
+ */
+ std::map<DeviceId, std::unique_ptr<Resampler>> mResamplers;
// Looper-related infrastructure
/**
@@ -194,26 +198,42 @@ private:
/**
* Batch messages that can be batched. When an unbatchable message is encountered, send it
* to the InputConsumerCallbacks immediately. If there are batches remaining,
- * notify InputConsumerCallbacks.
+ * notify InputConsumerCallbacks. If a resampleable ACTION_DOWN message is received, then a
+ * resampler is inserted for that deviceId in mResamplers. If a resampleable ACTION_UP or
+ * ACTION_CANCEL message is received then the resampler associated to that deviceId is erased
+ * from mResamplers.
*/
void handleMessages(std::vector<InputMessage>&& messages);
/**
* Batched InputMessages, per deviceId.
* For each device, we are storing a queue of batched messages. These will all be collapsed into
- * a single MotionEvent (up to a specific frameTime) when the consumer calls
+ * a single MotionEvent (up to a specific requestedFrameTime) when the consumer calls
* `consumeBatchedInputEvents`.
*/
std::map<DeviceId, std::queue<InputMessage>> mBatches;
/**
* Creates a MotionEvent by consuming samples from the provided queue. If one message has
- * eventTime > frameTime, all subsequent messages in the queue will be skipped. It is assumed
- * that messages are queued in chronological order. In other words, only events that occurred
- * prior to the requested frameTime will be consumed.
- * @param frameTime the time up to which to consume events
+ * eventTime > adjustedFrameTime, all subsequent messages in the queue will be skipped. It is
+ * assumed that messages are queued in chronological order. In other words, only events that
+ * occurred prior to the adjustedFrameTime will be consumed.
+ * @param requestedFrameTime the time up to which to consume events.
* @param messages the queue of messages to consume from
*/
std::pair<std::unique_ptr<MotionEvent>, std::optional<uint32_t>> createBatchedMotionEvent(
- const nsecs_t frameTime, std::queue<InputMessage>& messages);
+ const nsecs_t requestedFrameTime, std::queue<InputMessage>& messages);
+
+ /**
+ * Consumes the batched input events, optionally allowing the caller to specify a device id
+ * and/or requestedFrameTime threshold. It is not guaranteed that consumption will occur at
+ * requestedFrameTime.
+ * @param deviceId The device id from which to consume events. If std::nullopt, consumes events
+ * from any device id.
+ * @param requestedFrameTime The time up to which consume the events. If std::nullopt, consumes
+ * input events with any timestamp.
+ * @return Whether or not any events were consumed.
+ */
+ bool consumeBatchedInputEvents(std::optional<DeviceId> deviceId,
+ std::optional<nsecs_t> requestedFrameTime);
/**
* A map from a single sequence number to several sequence numbers. This is needed because of
* batching. When batching is enabled, a single MotionEvent will contain several samples. Each
diff --git a/include/input/KeyCharacterMap.h b/include/input/KeyCharacterMap.h
index 92d5ec4d4e..67b37b1213 100644
--- a/include/input/KeyCharacterMap.h
+++ b/include/input/KeyCharacterMap.h
@@ -126,9 +126,9 @@ public:
bool getEvents(int32_t deviceId, const char16_t* chars, size_t numChars,
Vector<KeyEvent>& outEvents) const;
- /* Maps an Android key code to another Android key code. This mapping is applied after scanCode
- * and usageCodes are mapped to corresponding Android Keycode */
- void addKeyRemapping(int32_t fromKeyCode, int32_t toKeyCode);
+ /* Maps some Android key code to another Android key code. This mapping is applied after
+ * scanCode and usageCodes are mapped to corresponding Android Keycode */
+ void setKeyRemapping(const std::map<int32_t, int32_t>& keyRemapping);
/* Maps a scan code and usage code to a key code, in case this key map overrides
* the mapping in some way. */
diff --git a/include/input/Resampler.h b/include/input/Resampler.h
index dcb25b729f..4aaeddd159 100644
--- a/include/input/Resampler.h
+++ b/include/input/Resampler.h
@@ -92,12 +92,6 @@ private:
};
/**
- * Keeps track of the previous MotionEvent deviceId to enable comparison between the previous
- * and the current deviceId.
- */
- std::optional<DeviceId> mPreviousDeviceId;
-
- /**
* Up to two latest samples from MotionEvent. Updated every time resampleMotionEvent is called.
* Note: We store up to two samples in order to simplify the implementation. Although,
* calculations are possible with only one previous sample.
diff --git a/libs/binder/BackendUnifiedServiceManager.cpp b/libs/binder/BackendUnifiedServiceManager.cpp
index 5680798d0d..52b485a6f6 100644
--- a/libs/binder/BackendUnifiedServiceManager.cpp
+++ b/libs/binder/BackendUnifiedServiceManager.cpp
@@ -34,37 +34,47 @@ using AidlServiceManager = android::os::IServiceManager;
using IAccessor = android::os::IAccessor;
static const char* kStaticCachableList[] = {
+ // go/keep-sorted start
+ "accessibility",
+ "account",
"activity",
- "android.hardware.thermal.IThermal/default",
- "android.hardware.power.IPower/default",
- "android.frameworks.stats.IStats/default",
- "android.system.suspend.ISystemSuspend/default",
+ "alarm",
+ "android.system.keystore2.IKeystoreService/default",
"appops",
"audio",
"batterystats",
"carrier_config",
"connectivity",
+ "content",
"content_capture",
"device_policy",
"display",
"dropbox",
"econtroller",
+ "graphicsstats",
+ "input",
+ "input_method",
"isub",
+ "jobscheduler",
"legacy_permission",
"location",
"media.extractor",
"media.metrics",
"media.player",
"media.resource_manager",
+ "media_resource_monitor",
+ "mount",
"netd_listener",
"netstats",
"network_management",
"nfc",
+ "notification",
+ "package",
"package_native",
"performance_hint",
"permission",
- "permissionmgr",
"permission_checker",
+ "permissionmgr",
"phone",
"platform_compat",
"power",
@@ -76,9 +86,12 @@ static const char* kStaticCachableList[] = {
"time_detector",
"trust",
"uimode",
+ "user",
"virtualdevice",
"virtualdevice_native",
"webviewupdate",
+ "window",
+ // go/keep-sorted end
};
bool BinderCacheWithInvalidation::isClientSideCachingEnabled(const std::string& serviceName) {
diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp
index 1d26d8543d..6698d0c0cd 100644
--- a/libs/binder/IPCThreadState.cpp
+++ b/libs/binder/IPCThreadState.cpp
@@ -232,6 +232,15 @@ static const void* printReturnCommand(std::ostream& out, const void* _cmd) {
return cmd;
}
+static void printReturnCommandParcel(std::ostream& out, const Parcel& parcel) {
+ const void* cmds = parcel.data();
+ out << "\t" << HexDump(cmds, parcel.dataSize()) << "\n";
+ IF_LOG_COMMANDS() {
+ const void* end = parcel.data() + parcel.dataSize();
+ while (cmds < end) cmds = printReturnCommand(out, cmds);
+ }
+}
+
static const void* printCommand(std::ostream& out, const void* _cmd) {
static const size_t N = sizeof(kCommandStrings)/sizeof(kCommandStrings[0]);
const int32_t* cmd = (const int32_t*)_cmd;
@@ -1235,13 +1244,15 @@ status_t IPCThreadState::talkWithDriver(bool doReceive)
if (err >= NO_ERROR) {
if (bwr.write_consumed > 0) {
- if (bwr.write_consumed < mOut.dataSize())
+ if (bwr.write_consumed < mOut.dataSize()) {
+ std::ostringstream logStream;
+ printReturnCommandParcel(logStream, mIn);
LOG_ALWAYS_FATAL("Driver did not consume write buffer. "
- "err: %s consumed: %zu of %zu",
- statusToString(err).c_str(),
- (size_t)bwr.write_consumed,
- mOut.dataSize());
- else {
+ "err: %s consumed: %zu of %zu.\n"
+ "Return command: %s",
+ statusToString(err).c_str(), (size_t)bwr.write_consumed,
+ mOut.dataSize(), logStream.str().c_str());
+ } else {
mOut.setDataSize(0);
processPostWriteDerefs();
}
@@ -1252,14 +1263,8 @@ status_t IPCThreadState::talkWithDriver(bool doReceive)
}
IF_LOG_COMMANDS() {
std::ostringstream logStream;
- logStream << "Remaining data size: " << mOut.dataSize() << "\n";
- logStream << "Received commands from driver: ";
- const void* cmds = mIn.data();
- const void* end = mIn.data() + mIn.dataSize();
- logStream << "\t" << HexDump(cmds, mIn.dataSize()) << "\n";
- while (cmds < end) cmds = printReturnCommand(logStream, cmds);
- std::string message = logStream.str();
- ALOGI("%s", message.c_str());
+ printReturnCommandParcel(logStream, mIn);
+ ALOGI("%s", logStream.str().c_str());
}
return NO_ERROR;
}
diff --git a/libs/binder/IServiceManager.cpp b/libs/binder/IServiceManager.cpp
index 88761d772f..77b80ef3de 100644
--- a/libs/binder/IServiceManager.cpp
+++ b/libs/binder/IServiceManager.cpp
@@ -157,12 +157,21 @@ protected:
class AccessorProvider {
public:
- AccessorProvider(RpcAccessorProvider&& provider) : mProvider(std::move(provider)) {}
- sp<IBinder> provide(const String16& name) { return mProvider(name); }
+ AccessorProvider(std::set<std::string>&& instances, RpcAccessorProvider&& provider)
+ : mInstances(std::move(instances)), mProvider(std::move(provider)) {}
+ sp<IBinder> provide(const String16& name) {
+ if (mInstances.count(String8(name).c_str()) > 0) {
+ return mProvider(name);
+ } else {
+ return nullptr;
+ }
+ }
+ const std::set<std::string>& instances() { return mInstances; }
private:
AccessorProvider() = delete;
+ std::set<std::string> mInstances;
RpcAccessorProvider mProvider;
};
@@ -318,10 +327,32 @@ sp<IServiceManager> getServiceManagerShimFromAidlServiceManagerForTests(
return sp<CppBackendShim>::make(sp<BackendUnifiedServiceManager>::make(sm));
}
-std::weak_ptr<AccessorProvider> addAccessorProvider(RpcAccessorProvider&& providerCallback) {
+// gAccessorProvidersMutex must be locked already
+static bool isInstanceProvidedLocked(const std::string& instance) {
+ return gAccessorProviders.end() !=
+ std::find_if(gAccessorProviders.begin(), gAccessorProviders.end(),
+ [&instance](const AccessorProviderEntry& entry) {
+ return entry.mProvider->instances().count(instance) > 0;
+ });
+}
+
+std::weak_ptr<AccessorProvider> addAccessorProvider(std::set<std::string>&& instances,
+ RpcAccessorProvider&& providerCallback) {
+ if (instances.empty()) {
+ ALOGE("Set of instances is empty! Need a non empty set of instances to provide for.");
+ return std::weak_ptr<AccessorProvider>();
+ }
std::lock_guard<std::mutex> lock(gAccessorProvidersMutex);
+ for (const auto& instance : instances) {
+ if (isInstanceProvidedLocked(instance)) {
+ ALOGE("The instance %s is already provided for by a previously added "
+ "RpcAccessorProvider.",
+ instance.c_str());
+ return std::weak_ptr<AccessorProvider>();
+ }
+ }
std::shared_ptr<AccessorProvider> provider =
- std::make_shared<AccessorProvider>(std::move(providerCallback));
+ std::make_shared<AccessorProvider>(std::move(instances), std::move(providerCallback));
std::weak_ptr<AccessorProvider> receipt = provider;
gAccessorProviders.push_back(AccessorProviderEntry(std::move(provider)));
@@ -331,8 +362,9 @@ std::weak_ptr<AccessorProvider> addAccessorProvider(RpcAccessorProvider&& provid
status_t removeAccessorProvider(std::weak_ptr<AccessorProvider> wProvider) {
std::shared_ptr<AccessorProvider> provider = wProvider.lock();
if (provider == nullptr) {
- ALOGE("The provider supplied to removeAccessorProvider has already been removed.");
- return NAME_NOT_FOUND;
+ ALOGE("The provider supplied to removeAccessorProvider has already been removed or the "
+ "argument to this function was nullptr.");
+ return BAD_VALUE;
}
std::lock_guard<std::mutex> lock(gAccessorProvidersMutex);
size_t sizeBefore = gAccessorProviders.size();
diff --git a/libs/binder/OS.h b/libs/binder/OS.h
index 04869a170f..64b1fd48fd 100644
--- a/libs/binder/OS.h
+++ b/libs/binder/OS.h
@@ -27,6 +27,7 @@ namespace android::binder::os {
LIBBINDER_EXPORTED void trace_begin(uint64_t tag, const char* name);
LIBBINDER_EXPORTED void trace_end(uint64_t tag);
LIBBINDER_EXPORTED void trace_int(uint64_t tag, const char* name, int32_t value);
+LIBBINDER_EXPORTED uint64_t get_trace_enabled_tags();
status_t setNonBlocking(borrowed_fd fd);
diff --git a/libs/binder/OS_android.cpp b/libs/binder/OS_android.cpp
index 893ee15578..4e9230ce58 100644
--- a/libs/binder/OS_android.cpp
+++ b/libs/binder/OS_android.cpp
@@ -48,6 +48,10 @@ void trace_int(uint64_t tag, const char* name, int32_t value) {
atrace_int(tag, name, value);
}
+uint64_t get_trace_enabled_tags() {
+ return atrace_enabled_tags;
+}
+
} // namespace os
// Legacy trace symbol. To be removed once all of downstream rebuilds.
diff --git a/libs/binder/OS_non_android_linux.cpp b/libs/binder/OS_non_android_linux.cpp
index 0c64eb61c6..6bba823897 100644
--- a/libs/binder/OS_non_android_linux.cpp
+++ b/libs/binder/OS_non_android_linux.cpp
@@ -41,6 +41,10 @@ void trace_end(uint64_t) {}
void trace_int(uint64_t, const char*, int32_t) {}
+uint64_t get_trace_enabled_tags() {
+ return 0;
+}
+
uint64_t GetThreadId() {
return syscall(__NR_gettid);
}
diff --git a/libs/binder/include/binder/IServiceManager.h b/libs/binder/include/binder/IServiceManager.h
index 879f319c5e..2b23276d1c 100644
--- a/libs/binder/include/binder/IServiceManager.h
+++ b/libs/binder/include/binder/IServiceManager.h
@@ -24,6 +24,7 @@
#include <utils/String16.h>
#include <utils/Vector.h>
#include <optional>
+#include <set>
namespace android {
@@ -224,20 +225,36 @@ LIBBINDER_EXPORTED bool checkPermission(const String16& permission, pid_t pid, u
typedef std::function<status_t(const String16& name, sockaddr* outAddr, socklen_t addrSize)>
RpcSocketAddressProvider;
-typedef std::function<sp<IBinder>(const String16& name)> RpcAccessorProvider;
+/**
+ * This callback provides a way for clients to get access to remote services by
+ * providing an Accessor object from libbinder that can connect to the remote
+ * service over sockets.
+ *
+ * \param instance name of the service that the callback will provide an
+ * Accessor for. The provided accessor will be used to set up a client
+ * RPC connection in libbinder in order to return a binder for the
+ * associated remote service.
+ *
+ * \return IBinder of the Accessor object that libbinder implements.
+ * nullptr if the provider callback doesn't know how to reach the
+ * service or doesn't want to provide access for any other reason.
+ */
+typedef std::function<sp<IBinder>(const String16& instance)> RpcAccessorProvider;
class AccessorProvider;
/**
- * Register an accessor provider for the service manager APIs.
+ * Register a RpcAccessorProvider for the service manager APIs.
*
+ * \param instances that the RpcAccessorProvider knows about and can provide an
+ * Accessor for.
* \param provider callback that generates Accessors.
*
* \return A pointer used as a recept for the successful addition of the
* AccessorProvider. This is needed to unregister it later.
*/
[[nodiscard]] LIBBINDER_EXPORTED std::weak_ptr<AccessorProvider> addAccessorProvider(
- RpcAccessorProvider&& providerCallback);
+ std::set<std::string>&& instances, RpcAccessorProvider&& providerCallback);
/**
* Remove an accessor provider using the pointer provided by addAccessorProvider
diff --git a/libs/binder/include/binder/Trace.h b/libs/binder/include/binder/Trace.h
index 2f450cb36b..a3e6c8a12b 100644
--- a/libs/binder/include/binder/Trace.h
+++ b/libs/binder/include/binder/Trace.h
@@ -42,6 +42,7 @@ namespace os {
void trace_begin(uint64_t tag, const char* name);
void trace_end(uint64_t tag);
void trace_int(uint64_t tag, const char* name, int32_t value);
+uint64_t get_trace_enabled_tags();
} // namespace os
class LIBBINDER_EXPORTED ScopedTrace {
diff --git a/libs/binder/ndk/Android.bp b/libs/binder/ndk/Android.bp
index 5f45cb2f07..a7423b3d2a 100644
--- a/libs/binder/ndk/Android.bp
+++ b/libs/binder/ndk/Android.bp
@@ -95,6 +95,7 @@ cc_library {
"persistable_bundle.cpp",
"process.cpp",
"service_manager.cpp",
+ "binder_rpc.cpp",
],
static_libs: [
diff --git a/libs/binder/ndk/binder_rpc.cpp b/libs/binder/ndk/binder_rpc.cpp
new file mode 100644
index 0000000000..2cc5f8117e
--- /dev/null
+++ b/libs/binder/ndk/binder_rpc.cpp
@@ -0,0 +1,352 @@
+/*
+ * Copyright (C) 2024 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_rpc.h>
+#include <arpa/inet.h>
+#include <binder/IServiceManager.h>
+#include <linux/vm_sockets.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#include <variant>
+
+#include "ibinder_internal.h"
+#include "status_internal.h"
+
+using ::android::defaultServiceManager;
+using ::android::IBinder;
+using ::android::IServiceManager;
+using ::android::OK;
+using ::android::sp;
+using ::android::status_t;
+using ::android::String16;
+using ::android::String8;
+using ::android::binder::Status;
+
+#define LOG_ACCESSOR_DEBUG(...)
+// #define LOG_ACCESSOR_DEBUG(...) ALOGW(__VA_ARGS__)
+
+struct ABinderRpc_ConnectionInfo {
+ std::variant<sockaddr_vm, sockaddr_un, sockaddr_in> addr;
+};
+
+struct ABinderRpc_Accessor final : public ::android::RefBase {
+ static ABinderRpc_Accessor* make(const char* instance, const sp<IBinder>& binder) {
+ LOG_ALWAYS_FATAL_IF(binder == nullptr, "ABinderRpc_Accessor requires a non-null binder");
+ status_t status = android::validateAccessor(String16(instance), binder);
+ if (status != OK) {
+ ALOGE("The given binder is not a valid IAccessor for %s. Status: %s", instance,
+ android::statusToString(status).c_str());
+ return nullptr;
+ }
+ return new ABinderRpc_Accessor(binder);
+ }
+
+ sp<IBinder> asBinder() { return mAccessorBinder; }
+
+ ~ABinderRpc_Accessor() { LOG_ACCESSOR_DEBUG("ABinderRpc_Accessor dtor"); }
+
+ private:
+ ABinderRpc_Accessor(sp<IBinder> accessor) : mAccessorBinder(accessor) {}
+ ABinderRpc_Accessor() = delete;
+ sp<IBinder> mAccessorBinder;
+};
+
+struct ABinderRpc_AccessorProvider {
+ public:
+ static ABinderRpc_AccessorProvider* make(std::weak_ptr<android::AccessorProvider> cookie) {
+ if (cookie.expired()) {
+ ALOGE("Null AccessorProvider cookie from libbinder");
+ return nullptr;
+ }
+ return new ABinderRpc_AccessorProvider(cookie);
+ }
+ std::weak_ptr<android::AccessorProvider> mProviderCookie;
+
+ private:
+ ABinderRpc_AccessorProvider() = delete;
+
+ ABinderRpc_AccessorProvider(std::weak_ptr<android::AccessorProvider> provider)
+ : mProviderCookie(provider) {}
+};
+
+struct OnDeleteProviderHolder {
+ OnDeleteProviderHolder(void* data, ABinderRpc_AccessorProviderUserData_deleteCallback onDelete)
+ : mData(data), mOnDelete(onDelete) {}
+ ~OnDeleteProviderHolder() {
+ if (mOnDelete) {
+ mOnDelete(mData);
+ }
+ }
+ void* mData;
+ ABinderRpc_AccessorProviderUserData_deleteCallback mOnDelete;
+ // needs to be copyable for std::function, but we will never copy it
+ OnDeleteProviderHolder(const OnDeleteProviderHolder&) {
+ LOG_ALWAYS_FATAL("This object can't be copied!");
+ }
+
+ private:
+ OnDeleteProviderHolder() = delete;
+};
+
+ABinderRpc_AccessorProvider* ABinderRpc_registerAccessorProvider(
+ ABinderRpc_AccessorProvider_getAccessorCallback provider, const char** instances,
+ size_t numInstances, void* data,
+ ABinderRpc_AccessorProviderUserData_deleteCallback onDelete) {
+ if (provider == nullptr) {
+ ALOGE("Null provider passed to ABinderRpc_registerAccessorProvider");
+ return nullptr;
+ }
+ if (data && onDelete == nullptr) {
+ ALOGE("If a non-null data ptr is passed to ABinderRpc_registerAccessorProvider, then a "
+ "ABinderRpc_AccessorProviderUserData_deleteCallback must alse be passed to delete "
+ "the data object once the ABinderRpc_AccessorProvider is removed.");
+ return nullptr;
+ }
+ if (numInstances == 0 || instances == nullptr) {
+ ALOGE("No instances passed to ABinderRpc_registerAccessorProvider. numInstances: %zu",
+ numInstances);
+ return nullptr;
+ }
+ std::set<std::string> instanceStrings;
+ for (size_t i = 0; i < numInstances; i++) {
+ instanceStrings.emplace(instances[i]);
+ }
+ // call the onDelete when the last reference of this goes away (when the
+ // last reference to the generate std::function goes away).
+ std::shared_ptr<OnDeleteProviderHolder> onDeleteHolder =
+ std::make_shared<OnDeleteProviderHolder>(data, onDelete);
+ android::RpcAccessorProvider generate = [provider,
+ onDeleteHolder](const String16& name) -> sp<IBinder> {
+ ABinderRpc_Accessor* accessor = provider(String8(name).c_str(), onDeleteHolder->mData);
+ if (accessor == nullptr) {
+ ALOGE("The supplied ABinderRpc_AccessorProvider_getAccessorCallback returned nullptr");
+ return nullptr;
+ }
+ sp<IBinder> binder = accessor->asBinder();
+ ABinderRpc_Accessor_delete(accessor);
+ return binder;
+ };
+
+ std::weak_ptr<android::AccessorProvider> cookie =
+ android::addAccessorProvider(std::move(instanceStrings), std::move(generate));
+ return ABinderRpc_AccessorProvider::make(cookie);
+}
+
+void ABinderRpc_unregisterAccessorProvider(ABinderRpc_AccessorProvider* provider) {
+ if (provider == nullptr) {
+ LOG_ALWAYS_FATAL("Attempting to remove a null ABinderRpc_AccessorProvider");
+ }
+
+ status_t status = android::removeAccessorProvider(provider->mProviderCookie);
+ // There shouldn't be a way to get here because the caller won't have a
+ // ABinderRpc_AccessorProvider* without calling ABinderRpc_registerAccessorProvider
+ LOG_ALWAYS_FATAL_IF(status == android::BAD_VALUE, "Provider (%p) is not valid. Status: %s",
+ provider, android::statusToString(status).c_str());
+ LOG_ALWAYS_FATAL_IF(status == android::NAME_NOT_FOUND,
+ "Provider (%p) was already unregistered. Status: %s", provider,
+ android::statusToString(status).c_str());
+ LOG_ALWAYS_FATAL_IF(status != OK,
+ "Unknown error when attempting to unregister ABinderRpc_AccessorProvider "
+ "(%p). Status: %s",
+ provider, android::statusToString(status).c_str());
+
+ delete provider;
+}
+
+struct OnDeleteConnectionInfoHolder {
+ OnDeleteConnectionInfoHolder(void* data,
+ ABinderRpc_ConnectionInfoProviderUserData_delete onDelete)
+ : mData(data), mOnDelete(onDelete) {}
+ ~OnDeleteConnectionInfoHolder() {
+ if (mOnDelete) {
+ mOnDelete(mData);
+ }
+ }
+ void* mData;
+ ABinderRpc_ConnectionInfoProviderUserData_delete mOnDelete;
+ // needs to be copyable for std::function, but we will never copy it
+ OnDeleteConnectionInfoHolder(const OnDeleteConnectionInfoHolder&) {
+ LOG_ALWAYS_FATAL("This object can't be copied!");
+ }
+
+ private:
+ OnDeleteConnectionInfoHolder() = delete;
+};
+
+ABinderRpc_Accessor* ABinderRpc_Accessor_new(
+ const char* instance, ABinderRpc_ConnectionInfoProvider provider, void* data,
+ ABinderRpc_ConnectionInfoProviderUserData_delete onDelete) {
+ if (instance == nullptr) {
+ ALOGE("Instance argument must be valid when calling ABinderRpc_Accessor_new");
+ return nullptr;
+ }
+ if (data && onDelete == nullptr) {
+ ALOGE("If a non-null data ptr is passed to ABinderRpc_Accessor_new, then a "
+ "ABinderRpc_ConnectionInfoProviderUserData_delete callback must alse be passed to "
+ "delete "
+ "the data object once the ABinderRpc_Accessor is deleted.");
+ return nullptr;
+ }
+ std::shared_ptr<OnDeleteConnectionInfoHolder> onDeleteHolder =
+ std::make_shared<OnDeleteConnectionInfoHolder>(data, onDelete);
+ if (provider == nullptr) {
+ ALOGE("Can't create a new ABinderRpc_Accessor without a ABinderRpc_ConnectionInfoProvider "
+ "and it is "
+ "null");
+ return nullptr;
+ }
+ android::RpcSocketAddressProvider generate = [provider, onDeleteHolder](
+ const String16& name, sockaddr* outAddr,
+ size_t addrLen) -> status_t {
+ std::unique_ptr<ABinderRpc_ConnectionInfo> info(
+ provider(String8(name).c_str(), onDeleteHolder->mData));
+ if (info == nullptr) {
+ ALOGE("The supplied ABinderRpc_ConnectionInfoProvider returned nullptr");
+ return android::NAME_NOT_FOUND;
+ }
+ if (auto addr = std::get_if<sockaddr_vm>(&info->addr)) {
+ LOG_ALWAYS_FATAL_IF(addr->svm_family != AF_VSOCK,
+ "ABinderRpc_ConnectionInfo invalid family");
+ if (addrLen < sizeof(sockaddr_vm)) {
+ ALOGE("Provided outAddr is too small! Expecting %zu, got %zu", sizeof(sockaddr_vm),
+ addrLen);
+ return android::BAD_VALUE;
+ }
+ LOG_ACCESSOR_DEBUG(
+ "Connection info provider found AF_VSOCK. family %d, port %d, cid %d",
+ addr->svm_family, addr->svm_port, addr->svm_cid);
+ *reinterpret_cast<sockaddr_vm*>(outAddr) = *addr;
+ } else if (auto addr = std::get_if<sockaddr_un>(&info->addr)) {
+ LOG_ALWAYS_FATAL_IF(addr->sun_family != AF_UNIX,
+ "ABinderRpc_ConnectionInfo invalid family");
+ if (addrLen < sizeof(sockaddr_un)) {
+ ALOGE("Provided outAddr is too small! Expecting %zu, got %zu", sizeof(sockaddr_un),
+ addrLen);
+ return android::BAD_VALUE;
+ }
+ *reinterpret_cast<sockaddr_un*>(outAddr) = *addr;
+ } else if (auto addr = std::get_if<sockaddr_in>(&info->addr)) {
+ LOG_ALWAYS_FATAL_IF(addr->sin_family != AF_INET,
+ "ABinderRpc_ConnectionInfo invalid family");
+ if (addrLen < sizeof(sockaddr_in)) {
+ ALOGE("Provided outAddr is too small! Expecting %zu, got %zu", sizeof(sockaddr_in),
+ addrLen);
+ return android::BAD_VALUE;
+ }
+ *reinterpret_cast<sockaddr_in*>(outAddr) = *addr;
+ } else {
+ LOG_ALWAYS_FATAL(
+ "Unsupported address family type when trying to get ARpcConnection info. A "
+ "new variant was added to the ABinderRpc_ConnectionInfo and this needs to be "
+ "updated.");
+ }
+ return OK;
+ };
+ sp<IBinder> accessorBinder = android::createAccessor(String16(instance), std::move(generate));
+ if (accessorBinder == nullptr) {
+ ALOGE("service manager did not get us an accessor");
+ return nullptr;
+ }
+ LOG_ACCESSOR_DEBUG("service manager found an accessor, so returning one now from _new");
+ return ABinderRpc_Accessor::make(instance, accessorBinder);
+}
+
+void ABinderRpc_Accessor_delete(ABinderRpc_Accessor* accessor) {
+ delete accessor;
+}
+
+AIBinder* ABinderRpc_Accessor_asBinder(ABinderRpc_Accessor* accessor) {
+ if (!accessor) {
+ ALOGE("ABinderRpc_Accessor argument is null.");
+ return nullptr;
+ }
+
+ sp<IBinder> binder = accessor->asBinder();
+ sp<AIBinder> aBinder = ABpBinder::lookupOrCreateFromBinder(binder);
+ AIBinder* ptr = aBinder.get();
+ if (ptr == nullptr) {
+ LOG_ALWAYS_FATAL("Failed to lookupOrCreateFromBinder");
+ }
+ ptr->incStrong(nullptr);
+ return ptr;
+}
+
+ABinderRpc_Accessor* ABinderRpc_Accessor_fromBinder(const char* instance, AIBinder* binder) {
+ if (!binder) {
+ ALOGE("binder argument is null");
+ return nullptr;
+ }
+ sp<IBinder> accessorBinder = binder->getBinder();
+ if (accessorBinder) {
+ return ABinderRpc_Accessor::make(instance, accessorBinder);
+ } else {
+ ALOGE("Attempting to get an ABinderRpc_Accessor for %s but AIBinder::getBinder returned "
+ "null",
+ instance);
+ return nullptr;
+ }
+}
+
+ABinderRpc_ConnectionInfo* ABinderRpc_ConnectionInfo_new(const sockaddr* addr, socklen_t len) {
+ if (addr == nullptr || len < 0 || static_cast<size_t>(len) < sizeof(sa_family_t)) {
+ ALOGE("Invalid arguments in Arpc_Connection_new");
+ return nullptr;
+ }
+ // socklen_t was int32_t on 32-bit and uint32_t on 64 bit.
+ size_t socklen = len < 0 || static_cast<uintmax_t>(len) > SIZE_MAX ? 0 : len;
+
+ if (addr->sa_family == AF_VSOCK) {
+ if (len != sizeof(sockaddr_vm)) {
+ ALOGE("Incorrect size of %zu for AF_VSOCK sockaddr_vm. Expecting %zu", socklen,
+ sizeof(sockaddr_vm));
+ return nullptr;
+ }
+ sockaddr_vm vm = *reinterpret_cast<const sockaddr_vm*>(addr);
+ LOG_ACCESSOR_DEBUG("Arpc_ConnectionInfo_new found AF_VSOCK. family %d, port %d, cid %d",
+ vm.svm_family, vm.svm_port, vm.svm_cid);
+ return new ABinderRpc_ConnectionInfo(vm);
+ } else if (addr->sa_family == AF_UNIX) {
+ if (len != sizeof(sockaddr_un)) {
+ ALOGE("Incorrect size of %zu for AF_UNIX sockaddr_un. Expecting %zu", socklen,
+ sizeof(sockaddr_un));
+ return nullptr;
+ }
+ sockaddr_un un = *reinterpret_cast<const sockaddr_un*>(addr);
+ LOG_ACCESSOR_DEBUG("Arpc_ConnectionInfo_new found AF_UNIX. family %d, path %s",
+ un.sun_family, un.sun_path);
+ return new ABinderRpc_ConnectionInfo(un);
+ } else if (addr->sa_family == AF_INET) {
+ if (len != sizeof(sockaddr_in)) {
+ ALOGE("Incorrect size of %zu for AF_INET sockaddr_in. Expecting %zu", socklen,
+ sizeof(sockaddr_in));
+ return nullptr;
+ }
+ sockaddr_in in = *reinterpret_cast<const sockaddr_in*>(addr);
+ LOG_ACCESSOR_DEBUG("Arpc_ConnectionInfo_new found AF_INET. family %d, address %s, port %d",
+ in.sin_family, inet_ntoa(in.sin_addr), ntohs(in.sin_port));
+ return new ABinderRpc_ConnectionInfo(in);
+ }
+
+ ALOGE("ARpc APIs only support AF_VSOCK right now but the supplied sockadder::sa_family is: %hu",
+ addr->sa_family);
+ return nullptr;
+}
+
+void ABinderRpc_ConnectionInfo_delete(ABinderRpc_ConnectionInfo* info) {
+ delete info;
+}
diff --git a/libs/binder/ndk/ibinder.cpp b/libs/binder/ndk/ibinder.cpp
index af280d38a3..ff31dd0193 100644
--- a/libs/binder/ndk/ibinder.cpp
+++ b/libs/binder/ndk/ibinder.cpp
@@ -18,8 +18,10 @@
#include <android/binder_ibinder_platform.h>
#include <android/binder_stability.h>
#include <android/binder_status.h>
+#include <binder/Functional.h>
#include <binder/IPCThreadState.h>
#include <binder/IResultReceiver.h>
+#include <binder/Trace.h>
#if __has_include(<private/android_filesystem_config.h>)
#include <private/android_filesystem_config.h>
#endif
@@ -40,6 +42,23 @@ using ::android::statusToString;
using ::android::String16;
using ::android::String8;
using ::android::wp;
+using ::android::binder::impl::make_scope_guard;
+using ::android::binder::impl::scope_guard;
+using ::android::binder::os::get_trace_enabled_tags;
+using ::android::binder::os::trace_begin;
+using ::android::binder::os::trace_end;
+
+// transaction codes for getInterfaceHash and getInterfaceVersion are defined
+// in file : system/tools/aidl/aidl.cpp
+static constexpr int kGetInterfaceVersionId = 0x00fffffe;
+static const char* kInterfaceVersion = "getInterfaceVersion";
+static constexpr int kGetInterfaceHashId = 0x00fffffd;
+static const char* kInterfaceHash = "getInterfaceHash";
+static const char* kNdkTrace = "AIDL::ndk::";
+static const char* kServerTrace = "::server";
+static const char* kClientTrace = "::client";
+static const char* kSeparator = "::";
+static const char* kUnknownCode = "Unknown_Transaction_Code:";
namespace ABBinderTag {
@@ -90,6 +109,51 @@ static std::string SanitizeString(const String16& str) {
return sanitized;
}
+const std::string getMethodName(const AIBinder_Class* clazz, transaction_code_t code) {
+ // TODO(b/150155678) - Move getInterfaceHash and getInterfaceVersion to libbinder and remove
+ // hardcoded cases.
+ if (code <= clazz->getTransactionCodeToFunctionLength() && code >= FIRST_CALL_TRANSACTION) {
+ // Codes have FIRST_CALL_TRANSACTION as added offset. Subtract to access function name
+ return clazz->getFunctionName(code);
+ } else if (code == kGetInterfaceVersionId) {
+ return kInterfaceVersion;
+ } else if (code == kGetInterfaceHashId) {
+ return kInterfaceHash;
+ }
+ return kUnknownCode + std::to_string(code);
+}
+
+const std::string getTraceSectionName(const AIBinder_Class* clazz, transaction_code_t code,
+ bool isServer) {
+ if (clazz == nullptr) {
+ ALOGE("class associated with binder is null. Class is needed to add trace with interface "
+ "name and function name");
+ return kNdkTrace;
+ }
+
+ const std::string descriptor = clazz->getInterfaceDescriptorUtf8();
+ const std::string methodName = getMethodName(clazz, code);
+
+ size_t traceSize =
+ strlen(kNdkTrace) + descriptor.size() + strlen(kSeparator) + methodName.size();
+ traceSize += isServer ? strlen(kServerTrace) : strlen(kClientTrace);
+
+ std::string trace;
+ // reserve to avoid repeated allocations
+ trace.reserve(traceSize);
+
+ trace += kNdkTrace;
+ trace += clazz->getInterfaceDescriptorUtf8();
+ trace += kSeparator;
+ trace += methodName;
+ trace += isServer ? kServerTrace : kClientTrace;
+
+ LOG_ALWAYS_FATAL_IF(trace.size() != traceSize, "Trace size mismatch. Expected %zu, got %zu",
+ traceSize, trace.size());
+
+ return trace;
+}
+
bool AIBinder::associateClass(const AIBinder_Class* clazz) {
if (clazz == nullptr) return false;
@@ -203,6 +267,17 @@ status_t ABBinder::dump(int fd, const ::android::Vector<String16>& args) {
status_t ABBinder::onTransact(transaction_code_t code, const Parcel& data, Parcel* reply,
binder_flags_t flags) {
+ std::string sectionName;
+ bool tracingEnabled = get_trace_enabled_tags() & ATRACE_TAG_AIDL;
+ if (tracingEnabled) {
+ sectionName = getTraceSectionName(getClass(), code, true /*isServer*/);
+ trace_begin(ATRACE_TAG_AIDL, sectionName.c_str());
+ }
+
+ scope_guard guard = make_scope_guard([&]() {
+ if (tracingEnabled) trace_end(ATRACE_TAG_AIDL);
+ });
+
if (isUserCommand(code)) {
if (getClass()->writeHeader && !data.checkInterface(this)) {
return STATUS_BAD_TYPE;
@@ -385,6 +460,31 @@ AIBinder_Class::AIBinder_Class(const char* interfaceDescriptor, AIBinder_Class_o
mInterfaceDescriptor(interfaceDescriptor),
mWideInterfaceDescriptor(interfaceDescriptor) {}
+bool AIBinder_Class::setTransactionCodeMap(const char** transactionCodeMap, size_t length) {
+ if (mTransactionCodeToFunction != nullptr) {
+ ALOGE("mTransactionCodeToFunction is already set!");
+ return false;
+ }
+ mTransactionCodeToFunction = transactionCodeMap;
+ mTransactionCodeToFunctionLength = length;
+ return true;
+}
+
+const char* AIBinder_Class::getFunctionName(transaction_code_t code) const {
+ if (mTransactionCodeToFunction == nullptr) {
+ ALOGE("mTransactionCodeToFunction is not set!");
+ return nullptr;
+ }
+
+ if (code < FIRST_CALL_TRANSACTION ||
+ code - FIRST_CALL_TRANSACTION >= mTransactionCodeToFunctionLength) {
+ ALOGE("Function name for requested code not found!");
+ return nullptr;
+ }
+
+ return mTransactionCodeToFunction[code - FIRST_CALL_TRANSACTION];
+}
+
AIBinder_Class* AIBinder_Class_define(const char* interfaceDescriptor,
AIBinder_Class_onCreate onCreate,
AIBinder_Class_onDestroy onDestroy,
@@ -404,6 +504,24 @@ void AIBinder_Class_setOnDump(AIBinder_Class* clazz, AIBinder_onDump onDump) {
clazz->onDump = onDump;
}
+void AIBinder_Class_setTransactionCodeToFunctionNameMap(AIBinder_Class* clazz,
+ const char** transactionCodeToFunction,
+ size_t length) {
+ LOG_ALWAYS_FATAL_IF(clazz == nullptr || transactionCodeToFunction == nullptr,
+ "Valid clazz and transactionCodeToFunction are needed to set code to "
+ "function mapping.");
+ LOG_ALWAYS_FATAL_IF(!clazz->setTransactionCodeMap(transactionCodeToFunction, length),
+ "Failed to set transactionCodeToFunction to clazz! Is "
+ "transactionCodeToFunction already set?");
+}
+
+const char* AIBinder_Class_getFunctionName(AIBinder_Class* clazz, transaction_code_t code) {
+ LOG_ALWAYS_FATAL_IF(
+ clazz == nullptr,
+ "Valid clazz is needed to get function name for requested transaction code");
+ return clazz->getFunctionName(code);
+}
+
void AIBinder_Class_disableInterfaceTokenHeader(AIBinder_Class* clazz) {
LOG_ALWAYS_FATAL_IF(clazz == nullptr, "disableInterfaceTokenHeader requires non-null clazz");
@@ -734,6 +852,19 @@ static void DestroyParcel(AParcel** parcel) {
binder_status_t AIBinder_transact(AIBinder* binder, transaction_code_t code, AParcel** in,
AParcel** out, binder_flags_t flags) {
+ const AIBinder_Class* clazz = binder ? binder->getClass() : nullptr;
+
+ std::string sectionName;
+ bool tracingEnabled = get_trace_enabled_tags() & ATRACE_TAG_AIDL;
+ if (tracingEnabled) {
+ sectionName = getTraceSectionName(clazz, code, false /*isServer*/);
+ trace_begin(ATRACE_TAG_AIDL, sectionName.c_str());
+ }
+
+ scope_guard guard = make_scope_guard([&]() {
+ if (tracingEnabled) trace_end(ATRACE_TAG_AIDL);
+ });
+
if (in == nullptr) {
ALOGE("%s: requires non-null in parameter", __func__);
return STATUS_UNEXPECTED_NULL;
@@ -872,4 +1003,4 @@ void AIBinder_setInheritRt(AIBinder* binder, bool inheritRt) {
"AIBinder_setInheritRt must be called on a local binder");
localBinder->setInheritRt(inheritRt);
-}
+} \ No newline at end of file
diff --git a/libs/binder/ndk/ibinder_internal.h b/libs/binder/ndk/ibinder_internal.h
index f5b738c1ef..a93dc1f674 100644
--- a/libs/binder/ndk/ibinder_internal.h
+++ b/libs/binder/ndk/ibinder_internal.h
@@ -132,6 +132,9 @@ struct AIBinder_Class {
const ::android::String16& getInterfaceDescriptor() const { return mWideInterfaceDescriptor; }
const char* getInterfaceDescriptorUtf8() const { return mInterfaceDescriptor.c_str(); }
+ bool setTransactionCodeMap(const char** transactionCodeMap, size_t transactionCodeMapSize);
+ const char* getFunctionName(transaction_code_t code) const;
+ size_t getTransactionCodeToFunctionLength() const { return mTransactionCodeToFunctionLength; }
// whether a transaction header should be written
bool writeHeader = true;
@@ -151,6 +154,10 @@ struct AIBinder_Class {
// This must be a String16 since BBinder virtual getInterfaceDescriptor returns a reference to
// one.
const ::android::String16 mWideInterfaceDescriptor;
+ // Array which holds names of the functions
+ const char** mTransactionCodeToFunction = nullptr;
+ // length of mmTransactionCodeToFunctionLength array
+ size_t mTransactionCodeToFunctionLength = 0;
};
// Ownership is like this (when linked to death):
diff --git a/libs/binder/ndk/include_cpp/android/binder_interface_utils.h b/libs/binder/ndk/include_cpp/android/binder_interface_utils.h
index af56bf0da1..8296356d6b 100644
--- a/libs/binder/ndk/include_cpp/android/binder_interface_utils.h
+++ b/libs/binder/ndk/include_cpp/android/binder_interface_utils.h
@@ -30,6 +30,17 @@
#include <android/binder_auto_utils.h>
#include <android/binder_ibinder.h>
+#if defined(__ANDROID_VENDOR__)
+#include <android/llndk-versioning.h>
+#elif !defined(API_LEVEL_AT_LEAST)
+#if defined(__BIONIC__)
+#define API_LEVEL_AT_LEAST(sdk_api_level, vendor_api_level) \
+ (__builtin_available(android sdk_api_level, *))
+#else
+#define API_LEVEL_AT_LEAST(sdk_api_level, vendor_api_level) (true)
+#endif // __BIONIC__
+#endif // __ANDROID_VENDOR__
+
#if __has_include(<android/binder_shell.h>)
#include <android/binder_shell.h>
#define HAS_BINDER_SHELL_COMMAND
@@ -164,6 +175,10 @@ class ICInterface : public SharedRefBase {
* Helper method to create a class
*/
static inline AIBinder_Class* defineClass(const char* interfaceDescriptor,
+ AIBinder_Class_onTransact onTransact,
+ const char** codeToFunction, size_t functionCount);
+
+ static inline AIBinder_Class* defineClass(const char* interfaceDescriptor,
AIBinder_Class_onTransact onTransact);
private:
@@ -256,6 +271,13 @@ std::shared_ptr<ICInterface> ICInterface::asInterface(AIBinder* binder) {
AIBinder_Class* ICInterface::defineClass(const char* interfaceDescriptor,
AIBinder_Class_onTransact onTransact) {
+
+ return defineClass(interfaceDescriptor, onTransact, nullptr, 0);
+}
+
+AIBinder_Class* ICInterface::defineClass(const char* interfaceDescriptor,
+ AIBinder_Class_onTransact onTransact,
+ const char** codeToFunction, size_t functionCount) {
AIBinder_Class* clazz = AIBinder_Class_define(interfaceDescriptor, ICInterfaceData::onCreate,
ICInterfaceData::onDestroy, onTransact);
if (clazz == nullptr) {
@@ -274,6 +296,20 @@ AIBinder_Class* ICInterface::defineClass(const char* interfaceDescriptor,
AIBinder_Class_setHandleShellCommand(clazz, ICInterfaceData::handleShellCommand);
}
#endif
+
+// TODO(b/368559337): fix versioning on product partition
+#if !defined(__ANDROID_PRODUCT__) && \
+ (defined(__ANDROID_UNAVAILABLE_SYMBOLS_ARE_WEAK__) || __ANDROID_API__ >= 36)
+ if API_LEVEL_AT_LEAST (36, 202504) {
+ if (codeToFunction != nullptr) {
+ AIBinder_Class_setTransactionCodeToFunctionNameMap(clazz, codeToFunction,
+ functionCount);
+ }
+ }
+#else
+ (void)codeToFunction;
+ (void)functionCount;
+#endif // defined(__ANDROID_UNAVAILABLE_SYMBOLS_ARE_WEAK__) || __ANDROID_API__ >= 36
return clazz;
}
diff --git a/libs/binder/ndk/include_ndk/android/binder_ibinder.h b/libs/binder/ndk/include_ndk/android/binder_ibinder.h
index 72d255e816..2f6c4e3642 100644
--- a/libs/binder/ndk/include_ndk/android/binder_ibinder.h
+++ b/libs/binder/ndk/include_ndk/android/binder_ibinder.h
@@ -219,6 +219,50 @@ typedef binder_status_t (*AIBinder_onDump)(AIBinder* binder, int fd, const char*
void AIBinder_Class_setOnDump(AIBinder_Class* clazz, AIBinder_onDump onDump) __INTRODUCED_IN(29);
/**
+ * Associates a mapping of transaction codes(transaction_code_t) to function names for the given
+ * class.
+ *
+ * Trace messages will use the provided names instead of bare integer codes when set. If not set by
+ * this function, trace messages will only be identified by the bare code. This should be called one
+ * time during clazz initialization. clazz and transactionCodeToFunctionMap should have same
+ * lifetime. Resetting/clearing the transactionCodeToFunctionMap is not allowed.
+ *
+ * Available since API level 36.
+ *
+ * \param clazz class which should use this transaction to code function map.
+ * \param transactionCodeToFunctionMap array of function names indexed by transaction code.
+ * Transaction codes start from 1, functions with transaction code 1 will correspond to index 0 in
+ * transactionCodeToFunctionMap. When defining methods, transaction codes are expected to be
+ * contiguous, and this is required for maximum memory efficiency.
+ * You can use nullptr if certain transaction codes are not used. Lifetime should be same as clazz.
+ * \param length number of elements in the transactionCodeToFunctionMap
+ *
+ * \return true if setting codeToFunction to clazz is successful. return false if clazz or
+ * codeToFunction is nullptr.
+ */
+void AIBinder_Class_setTransactionCodeToFunctionNameMap(AIBinder_Class* clazz,
+ const char** transactionCodeToFunctionMap,
+ size_t length) __INTRODUCED_IN(36);
+
+/**
+ * Get function name associated with transaction code for given class
+ *
+ * This function returns function name associated with provided transaction code for given class.
+ * AIBinder_Class_setTransactionCodeToFunctionNameMap should be called first to associate function
+ * to transaction code mapping.
+ *
+ * Available since API level 36.
+ *
+ * \param clazz class for which function name is requested
+ * \param transactionCode transaction_code_t for which function name is requested.
+ *
+ * \return function name in form of const char* if transaction code is valid for given class.
+ * if transaction code is invalid or transactionCodeToFunctionMap is not set, nullptr is returned
+ */
+const char* AIBinder_Class_getFunctionName(AIBinder_Class* clazz, transaction_code_t code)
+ __INTRODUCED_IN(36);
+
+/**
* This tells users of this class not to use a transaction header. By default, libbinder_ndk users
* read/write transaction headers implicitly (in the SDK, this must be manually written by
* android.os.Parcel#writeInterfaceToken, and it is read/checked with
diff --git a/libs/binder/ndk/include_ndk/android/persistable_bundle.h b/libs/binder/ndk/include_ndk/android/persistable_bundle.h
index 5e0d4da97b..1d516aea9d 100644
--- a/libs/binder/ndk/include_ndk/android/persistable_bundle.h
+++ b/libs/binder/ndk/include_ndk/android/persistable_bundle.h
@@ -17,13 +17,6 @@
#pragma once
#include <android/binder_parcel.h>
-#if defined(__ANDROID_VENDOR__)
-#include <android/llndk-versioning.h>
-#else
-#if !defined(__INTRODUCED_IN_LLNDK)
-#define __INTRODUCED_IN_LLNDK(level) __attribute__((annotate("introduced_in_llndk=" #level)))
-#endif
-#endif // __ANDROID_VENDOR__
#include <stdbool.h>
#include <stdint.h>
#include <sys/cdefs.h>
@@ -83,8 +76,7 @@ typedef char* _Nullable (*_Nonnull APersistableBundle_stringAllocator)(int32_t s
*
* \return Pointer to a new APersistableBundle
*/
-APersistableBundle* _Nullable APersistableBundle_new() __INTRODUCED_IN(__ANDROID_API_V__)
- __INTRODUCED_IN_LLNDK(202404);
+APersistableBundle* _Nullable APersistableBundle_new() __INTRODUCED_IN(__ANDROID_API_V__);
/**
* Create a new APersistableBundle based off an existing APersistableBundle.
@@ -98,7 +90,7 @@ APersistableBundle* _Nullable APersistableBundle_new() __INTRODUCED_IN(__ANDROID
* \return Pointer to a new APersistableBundle
*/
APersistableBundle* _Nullable APersistableBundle_dup(const APersistableBundle* _Nonnull pBundle)
- __INTRODUCED_IN(__ANDROID_API_V__) __INTRODUCED_IN_LLNDK(202404);
+ __INTRODUCED_IN(__ANDROID_API_V__);
/**
* Delete an APersistableBundle. This must always be called when finished using
@@ -109,7 +101,7 @@ APersistableBundle* _Nullable APersistableBundle_dup(const APersistableBundle* _
* Available since API level 202404.
*/
void APersistableBundle_delete(APersistableBundle* _Nullable pBundle)
- __INTRODUCED_IN(__ANDROID_API_V__) __INTRODUCED_IN_LLNDK(202404);
+ __INTRODUCED_IN(__ANDROID_API_V__);
/**
* Check for equality of APersistableBundles.
@@ -123,7 +115,7 @@ void APersistableBundle_delete(APersistableBundle* _Nullable pBundle)
*/
bool APersistableBundle_isEqual(const APersistableBundle* _Nonnull lhs,
const APersistableBundle* _Nonnull rhs)
- __INTRODUCED_IN(__ANDROID_API_V__) __INTRODUCED_IN_LLNDK(202404);
+ __INTRODUCED_IN(__ANDROID_API_V__);
/**
* Read an APersistableBundle from an AParcel.
@@ -142,7 +134,7 @@ bool APersistableBundle_isEqual(const APersistableBundle* _Nonnull lhs,
*/
binder_status_t APersistableBundle_readFromParcel(
const AParcel* _Nonnull parcel, APersistableBundle* _Nullable* _Nonnull outPBundle)
- __INTRODUCED_IN(__ANDROID_API_V__) __INTRODUCED_IN_LLNDK(202404);
+ __INTRODUCED_IN(__ANDROID_API_V__);
/**
* Write an APersistableBundle to an AParcel.
@@ -162,7 +154,7 @@ binder_status_t APersistableBundle_readFromParcel(
*/
binder_status_t APersistableBundle_writeToParcel(const APersistableBundle* _Nonnull pBundle,
AParcel* _Nonnull parcel)
- __INTRODUCED_IN(__ANDROID_API_V__) __INTRODUCED_IN_LLNDK(202404);
+ __INTRODUCED_IN(__ANDROID_API_V__);
/**
* Get the size of an APersistableBundle. This is the number of mappings in the
@@ -175,7 +167,7 @@ binder_status_t APersistableBundle_writeToParcel(const APersistableBundle* _Nonn
* \return number of mappings in the object
*/
int32_t APersistableBundle_size(const APersistableBundle* _Nonnull pBundle)
- __INTRODUCED_IN(__ANDROID_API_V__) __INTRODUCED_IN_LLNDK(202404);
+ __INTRODUCED_IN(__ANDROID_API_V__);
/**
* Erase any entries added with the provided key.
@@ -188,7 +180,7 @@ int32_t APersistableBundle_size(const APersistableBundle* _Nonnull pBundle)
* \return number of entries erased. Either 0 or 1.
*/
int32_t APersistableBundle_erase(APersistableBundle* _Nonnull pBundle, const char* _Nonnull key)
- __INTRODUCED_IN(__ANDROID_API_V__) __INTRODUCED_IN_LLNDK(202404);
+ __INTRODUCED_IN(__ANDROID_API_V__);
/**
* Put a boolean associated with the provided key.
@@ -201,8 +193,7 @@ int32_t APersistableBundle_erase(APersistableBundle* _Nonnull pBundle, const cha
* Available since API level 202404.
*/
void APersistableBundle_putBoolean(APersistableBundle* _Nonnull pBundle, const char* _Nonnull key,
- bool val) __INTRODUCED_IN(__ANDROID_API_V__)
- __INTRODUCED_IN_LLNDK(202404);
+ bool val) __INTRODUCED_IN(__ANDROID_API_V__);
/**
* Put an int32_t associated with the provided key.
@@ -215,8 +206,7 @@ void APersistableBundle_putBoolean(APersistableBundle* _Nonnull pBundle, const c
* Available since API level 202404.
*/
void APersistableBundle_putInt(APersistableBundle* _Nonnull pBundle, const char* _Nonnull key,
- int32_t val) __INTRODUCED_IN(__ANDROID_API_V__)
- __INTRODUCED_IN_LLNDK(202404);
+ int32_t val) __INTRODUCED_IN(__ANDROID_API_V__);
/**
* Put an int64_t associated with the provided key.
@@ -229,8 +219,7 @@ void APersistableBundle_putInt(APersistableBundle* _Nonnull pBundle, const char*
* Available since API level 202404.
*/
void APersistableBundle_putLong(APersistableBundle* _Nonnull pBundle, const char* _Nonnull key,
- int64_t val) __INTRODUCED_IN(__ANDROID_API_V__)
- __INTRODUCED_IN_LLNDK(202404);
+ int64_t val) __INTRODUCED_IN(__ANDROID_API_V__);
/**
* Put a double associated with the provided key.
@@ -243,8 +232,7 @@ void APersistableBundle_putLong(APersistableBundle* _Nonnull pBundle, const char
* Available since API level 202404.
*/
void APersistableBundle_putDouble(APersistableBundle* _Nonnull pBundle, const char* _Nonnull key,
- double val) __INTRODUCED_IN(__ANDROID_API_V__)
- __INTRODUCED_IN_LLNDK(202404);
+ double val) __INTRODUCED_IN(__ANDROID_API_V__);
/**
* Put a string associated with the provided key.
@@ -258,8 +246,7 @@ void APersistableBundle_putDouble(APersistableBundle* _Nonnull pBundle, const ch
* Available since API level 202404.
*/
void APersistableBundle_putString(APersistableBundle* _Nonnull pBundle, const char* _Nonnull key,
- const char* _Nonnull val) __INTRODUCED_IN(__ANDROID_API_V__)
- __INTRODUCED_IN_LLNDK(202404);
+ const char* _Nonnull val) __INTRODUCED_IN(__ANDROID_API_V__);
/**
* Put a boolean vector associated with the provided key.
@@ -275,8 +262,7 @@ void APersistableBundle_putString(APersistableBundle* _Nonnull pBundle, const ch
*/
void APersistableBundle_putBooleanVector(APersistableBundle* _Nonnull pBundle,
const char* _Nonnull key, const bool* _Nonnull vec,
- int32_t num) __INTRODUCED_IN(__ANDROID_API_V__)
- __INTRODUCED_IN_LLNDK(202404);
+ int32_t num) __INTRODUCED_IN(__ANDROID_API_V__);
/**
* Put an int32_t vector associated with the provided key.
@@ -292,7 +278,7 @@ void APersistableBundle_putBooleanVector(APersistableBundle* _Nonnull pBundle,
*/
void APersistableBundle_putIntVector(APersistableBundle* _Nonnull pBundle, const char* _Nonnull key,
const int32_t* _Nonnull vec, int32_t num)
- __INTRODUCED_IN(__ANDROID_API_V__) __INTRODUCED_IN_LLNDK(202404);
+ __INTRODUCED_IN(__ANDROID_API_V__);
/**
* Put an int64_t vector associated with the provided key.
@@ -308,8 +294,7 @@ void APersistableBundle_putIntVector(APersistableBundle* _Nonnull pBundle, const
*/
void APersistableBundle_putLongVector(APersistableBundle* _Nonnull pBundle,
const char* _Nonnull key, const int64_t* _Nonnull vec,
- int32_t num) __INTRODUCED_IN(__ANDROID_API_V__)
- __INTRODUCED_IN_LLNDK(202404);
+ int32_t num) __INTRODUCED_IN(__ANDROID_API_V__);
/**
* Put a double vector associated with the provided key.
@@ -325,8 +310,7 @@ void APersistableBundle_putLongVector(APersistableBundle* _Nonnull pBundle,
*/
void APersistableBundle_putDoubleVector(APersistableBundle* _Nonnull pBundle,
const char* _Nonnull key, const double* _Nonnull vec,
- int32_t num) __INTRODUCED_IN(__ANDROID_API_V__)
- __INTRODUCED_IN_LLNDK(202404);
+ int32_t num) __INTRODUCED_IN(__ANDROID_API_V__);
/**
* Put a string vector associated with the provided key.
@@ -343,7 +327,7 @@ void APersistableBundle_putDoubleVector(APersistableBundle* _Nonnull pBundle,
void APersistableBundle_putStringVector(APersistableBundle* _Nonnull pBundle,
const char* _Nonnull key,
const char* _Nullable const* _Nullable vec, int32_t num)
- __INTRODUCED_IN(__ANDROID_API_V__) __INTRODUCED_IN_LLNDK(202404);
+ __INTRODUCED_IN(__ANDROID_API_V__);
/**
* Put an APersistableBundle associated with the provided key.
@@ -359,7 +343,7 @@ void APersistableBundle_putStringVector(APersistableBundle* _Nonnull pBundle,
void APersistableBundle_putPersistableBundle(APersistableBundle* _Nonnull pBundle,
const char* _Nonnull key,
const APersistableBundle* _Nonnull val)
- __INTRODUCED_IN(__ANDROID_API_V__) __INTRODUCED_IN_LLNDK(202404);
+ __INTRODUCED_IN(__ANDROID_API_V__);
/**
* Get a boolean associated with the provided key.
@@ -374,7 +358,7 @@ void APersistableBundle_putPersistableBundle(APersistableBundle* _Nonnull pBundl
*/
bool APersistableBundle_getBoolean(const APersistableBundle* _Nonnull pBundle,
const char* _Nonnull key, bool* _Nonnull val)
- __INTRODUCED_IN(__ANDROID_API_V__) __INTRODUCED_IN_LLNDK(202404);
+ __INTRODUCED_IN(__ANDROID_API_V__);
/**
* Get an int32_t associated with the provided key.
@@ -388,8 +372,7 @@ bool APersistableBundle_getBoolean(const APersistableBundle* _Nonnull pBundle,
* \return true if a value exists for the provided key
*/
bool APersistableBundle_getInt(const APersistableBundle* _Nonnull pBundle, const char* _Nonnull key,
- int32_t* _Nonnull val) __INTRODUCED_IN(__ANDROID_API_V__)
- __INTRODUCED_IN_LLNDK(202404);
+ int32_t* _Nonnull val) __INTRODUCED_IN(__ANDROID_API_V__);
/**
* Get an int64_t associated with the provided key.
@@ -404,7 +387,7 @@ bool APersistableBundle_getInt(const APersistableBundle* _Nonnull pBundle, const
*/
bool APersistableBundle_getLong(const APersistableBundle* _Nonnull pBundle,
const char* _Nonnull key, int64_t* _Nonnull val)
- __INTRODUCED_IN(__ANDROID_API_V__) __INTRODUCED_IN_LLNDK(202404);
+ __INTRODUCED_IN(__ANDROID_API_V__);
/**
* Get a double associated with the provided key.
@@ -419,7 +402,7 @@ bool APersistableBundle_getLong(const APersistableBundle* _Nonnull pBundle,
*/
bool APersistableBundle_getDouble(const APersistableBundle* _Nonnull pBundle,
const char* _Nonnull key, double* _Nonnull val)
- __INTRODUCED_IN(__ANDROID_API_V__) __INTRODUCED_IN_LLNDK(202404);
+ __INTRODUCED_IN(__ANDROID_API_V__);
/**
* Get a string associated with the provided key.
@@ -440,8 +423,7 @@ bool APersistableBundle_getDouble(const APersistableBundle* _Nonnull pBundle,
int32_t APersistableBundle_getString(const APersistableBundle* _Nonnull pBundle,
const char* _Nonnull key, char* _Nullable* _Nonnull val,
APersistableBundle_stringAllocator stringAllocator,
- void* _Nullable context) __INTRODUCED_IN(__ANDROID_API_V__)
- __INTRODUCED_IN_LLNDK(202404);
+ void* _Nullable context) __INTRODUCED_IN(__ANDROID_API_V__);
/**
* Get a boolean vector associated with the provided key and place it in the
@@ -468,7 +450,7 @@ int32_t APersistableBundle_getString(const APersistableBundle* _Nonnull pBundle,
int32_t APersistableBundle_getBooleanVector(const APersistableBundle* _Nonnull pBundle,
const char* _Nonnull key, bool* _Nullable buffer,
int32_t bufferSizeBytes)
- __INTRODUCED_IN(__ANDROID_API_V__) __INTRODUCED_IN_LLNDK(202404);
+ __INTRODUCED_IN(__ANDROID_API_V__);
/**
* Get an int32_t vector associated with the provided key and place it in the
@@ -494,8 +476,7 @@ int32_t APersistableBundle_getBooleanVector(const APersistableBundle* _Nonnull p
*/
int32_t APersistableBundle_getIntVector(const APersistableBundle* _Nonnull pBundle,
const char* _Nonnull key, int32_t* _Nullable buffer,
- int32_t bufferSizeBytes) __INTRODUCED_IN(__ANDROID_API_V__)
- __INTRODUCED_IN_LLNDK(202404);
+ int32_t bufferSizeBytes) __INTRODUCED_IN(__ANDROID_API_V__);
/**
* Get an int64_t vector associated with the provided key and place it in the
@@ -521,8 +502,8 @@ int32_t APersistableBundle_getIntVector(const APersistableBundle* _Nonnull pBund
*/
int32_t APersistableBundle_getLongVector(const APersistableBundle* _Nonnull pBundle,
const char* _Nonnull key, int64_t* _Nullable buffer,
- int32_t bufferSizeBytes) __INTRODUCED_IN(__ANDROID_API_V__)
- __INTRODUCED_IN_LLNDK(202404);
+ int32_t bufferSizeBytes)
+ __INTRODUCED_IN(__ANDROID_API_V__);
/**
* Get a double vector associated with the provided key and place it in the
@@ -549,7 +530,7 @@ int32_t APersistableBundle_getLongVector(const APersistableBundle* _Nonnull pBun
int32_t APersistableBundle_getDoubleVector(const APersistableBundle* _Nonnull pBundle,
const char* _Nonnull key, double* _Nullable buffer,
int32_t bufferSizeBytes)
- __INTRODUCED_IN(__ANDROID_API_V__) __INTRODUCED_IN_LLNDK(202404);
+ __INTRODUCED_IN(__ANDROID_API_V__);
/**
* Get a string vector associated with the provided key and place it in the
@@ -586,7 +567,7 @@ int32_t APersistableBundle_getStringVector(const APersistableBundle* _Nonnull pB
int32_t bufferSizeBytes,
APersistableBundle_stringAllocator stringAllocator,
void* _Nullable context)
- __INTRODUCED_IN(__ANDROID_API_V__) __INTRODUCED_IN_LLNDK(202404);
+ __INTRODUCED_IN(__ANDROID_API_V__);
/**
* Get an APersistableBundle* associated with the provided key.
@@ -605,7 +586,7 @@ int32_t APersistableBundle_getStringVector(const APersistableBundle* _Nonnull pB
bool APersistableBundle_getPersistableBundle(const APersistableBundle* _Nonnull pBundle,
const char* _Nonnull key,
APersistableBundle* _Nullable* _Nonnull outBundle)
- __INTRODUCED_IN(__ANDROID_API_V__) __INTRODUCED_IN_LLNDK(202404);
+ __INTRODUCED_IN(__ANDROID_API_V__);
/**
* Get all of the keys associated with this specific type and place it in the
@@ -638,7 +619,7 @@ int32_t APersistableBundle_getBooleanKeys(const APersistableBundle* _Nonnull pBu
int32_t bufferSizeBytes,
APersistableBundle_stringAllocator stringAllocator,
void* _Nullable context)
- __INTRODUCED_IN(__ANDROID_API_V__) __INTRODUCED_IN_LLNDK(202404);
+ __INTRODUCED_IN(__ANDROID_API_V__);
/**
* Get all of the keys associated with this specific type and place it in the
@@ -669,8 +650,7 @@ int32_t APersistableBundle_getBooleanKeys(const APersistableBundle* _Nonnull pBu
int32_t APersistableBundle_getIntKeys(const APersistableBundle* _Nonnull pBundle,
char* _Nullable* _Nullable outKeys, int32_t bufferSizeBytes,
APersistableBundle_stringAllocator stringAllocator,
- void* _Nullable context) __INTRODUCED_IN(__ANDROID_API_V__)
- __INTRODUCED_IN_LLNDK(202404);
+ void* _Nullable context) __INTRODUCED_IN(__ANDROID_API_V__);
/**
* Get all of the keys associated with this specific type and place it in the
@@ -701,8 +681,7 @@ int32_t APersistableBundle_getIntKeys(const APersistableBundle* _Nonnull pBundle
int32_t APersistableBundle_getLongKeys(const APersistableBundle* _Nonnull pBundle,
char* _Nullable* _Nullable outKeys, int32_t bufferSizeBytes,
APersistableBundle_stringAllocator stringAllocator,
- void* _Nullable context) __INTRODUCED_IN(__ANDROID_API_V__)
- __INTRODUCED_IN_LLNDK(202404);
+ void* _Nullable context) __INTRODUCED_IN(__ANDROID_API_V__);
/**
* Get all of the keys associated with this specific type and place it in the
@@ -734,8 +713,8 @@ int32_t APersistableBundle_getDoubleKeys(const APersistableBundle* _Nonnull pBun
char* _Nullable* _Nullable outKeys,
int32_t bufferSizeBytes,
APersistableBundle_stringAllocator stringAllocator,
- void* _Nullable context) __INTRODUCED_IN(__ANDROID_API_V__)
- __INTRODUCED_IN_LLNDK(202404);
+ void* _Nullable context)
+ __INTRODUCED_IN(__ANDROID_API_V__);
/**
* Get all of the keys associated with this specific type and place it in the
@@ -767,8 +746,8 @@ int32_t APersistableBundle_getStringKeys(const APersistableBundle* _Nonnull pBun
char* _Nullable* _Nullable outKeys,
int32_t bufferSizeBytes,
APersistableBundle_stringAllocator stringAllocator,
- void* _Nullable context) __INTRODUCED_IN(__ANDROID_API_V__)
- __INTRODUCED_IN_LLNDK(202404);
+ void* _Nullable context)
+ __INTRODUCED_IN(__ANDROID_API_V__);
/**
* Get all of the keys associated with this specific type and place it in the
@@ -801,7 +780,7 @@ int32_t APersistableBundle_getBooleanVectorKeys(const APersistableBundle* _Nonnu
int32_t bufferSizeBytes,
APersistableBundle_stringAllocator stringAllocator,
void* _Nullable context)
- __INTRODUCED_IN(__ANDROID_API_V__) __INTRODUCED_IN_LLNDK(202404);
+ __INTRODUCED_IN(__ANDROID_API_V__);
/**
* Get all of the keys associated with this specific type and place it in the
@@ -834,7 +813,7 @@ int32_t APersistableBundle_getIntVectorKeys(const APersistableBundle* _Nonnull p
int32_t bufferSizeBytes,
APersistableBundle_stringAllocator stringAllocator,
void* _Nullable context)
- __INTRODUCED_IN(__ANDROID_API_V__) __INTRODUCED_IN_LLNDK(202404);
+ __INTRODUCED_IN(__ANDROID_API_V__);
/**
* Get all of the keys associated with this specific type and place it in the
@@ -867,7 +846,7 @@ int32_t APersistableBundle_getLongVectorKeys(const APersistableBundle* _Nonnull
int32_t bufferSizeBytes,
APersistableBundle_stringAllocator stringAllocator,
void* _Nullable context)
- __INTRODUCED_IN(__ANDROID_API_V__) __INTRODUCED_IN_LLNDK(202404);
+ __INTRODUCED_IN(__ANDROID_API_V__);
/**
* Get all of the keys associated with this specific type and place it in the
@@ -899,7 +878,7 @@ int32_t APersistableBundle_getDoubleVectorKeys(const APersistableBundle* _Nonnul
int32_t bufferSizeBytes,
APersistableBundle_stringAllocator stringAllocator,
void* _Nullable context)
- __INTRODUCED_IN(__ANDROID_API_V__) __INTRODUCED_IN_LLNDK(202404);
+ __INTRODUCED_IN(__ANDROID_API_V__);
/**
* Get all of the keys associated with this specific type and place it in the
@@ -932,7 +911,7 @@ int32_t APersistableBundle_getStringVectorKeys(const APersistableBundle* _Nonnul
int32_t bufferSizeBytes,
APersistableBundle_stringAllocator stringAllocator,
void* _Nullable context)
- __INTRODUCED_IN(__ANDROID_API_V__) __INTRODUCED_IN_LLNDK(202404);
+ __INTRODUCED_IN(__ANDROID_API_V__);
/**
* Get all of the keys associated with this specific type and place it in the
@@ -963,6 +942,6 @@ int32_t APersistableBundle_getStringVectorKeys(const APersistableBundle* _Nonnul
int32_t APersistableBundle_getPersistableBundleKeys(
const APersistableBundle* _Nonnull pBundle, char* _Nullable* _Nullable outKeys,
int32_t bufferSizeBytes, APersistableBundle_stringAllocator stringAllocator,
- void* _Nullable context) __INTRODUCED_IN(__ANDROID_API_V__) __INTRODUCED_IN_LLNDK(202404);
+ void* _Nullable context) __INTRODUCED_IN(__ANDROID_API_V__);
__END_DECLS
diff --git a/libs/binder/ndk/include_platform/android/binder_manager.h b/libs/binder/ndk/include_platform/android/binder_manager.h
index 41b30a0a0f..cc4943b9c3 100644
--- a/libs/binder/ndk/include_platform/android/binder_manager.h
+++ b/libs/binder/ndk/include_platform/android/binder_manager.h
@@ -18,7 +18,6 @@
#include <android/binder_ibinder.h>
#include <android/binder_status.h>
-#include <android/llndk-versioning.h>
#include <sys/cdefs.h>
__BEGIN_DECLS
@@ -257,8 +256,7 @@ void AServiceManager_getUpdatableApexName(const char* instance, void* context,
* \return the result of dlopen of the specified HAL
*/
void* AServiceManager_openDeclaredPassthroughHal(const char* interface, const char* instance,
- int flag) __INTRODUCED_IN(__ANDROID_API_V__)
- __INTRODUCED_IN_LLNDK(202404);
+ int flag) __INTRODUCED_IN(__ANDROID_API_V__);
/**
* Prevent lazy services without client from shutting down their process
diff --git a/libs/binder/ndk/include_platform/android/binder_rpc.h b/libs/binder/ndk/include_platform/android/binder_rpc.h
new file mode 100644
index 0000000000..4c5471ff70
--- /dev/null
+++ b/libs/binder/ndk/include_platform/android/binder_rpc.h
@@ -0,0 +1,261 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android/binder_ibinder.h>
+#include <sys/socket.h>
+
+__BEGIN_DECLS
+
+/**
+ * This represents an IAccessor implementation from libbinder that is
+ * responsible for providing a pre-connected socket file descriptor for a
+ * specific service. The service is an RpcServer and the pre-connected socket is
+ * used to set up a client RpcSession underneath libbinder's IServiceManager APIs
+ * to provide the client with the service's binder for remote communication.
+ */
+typedef struct ABinderRpc_Accessor ABinderRpc_Accessor;
+
+/**
+ * This represents an object that supplies ABinderRpc_Accessors to libbinder
+ * when they are requested. They are requested any time a client is attempting
+ * to get a service through IServiceManager APIs when the services aren't known by
+ * servicemanager.
+ */
+typedef struct ABinderRpc_AccessorProvider ABinderRpc_AccessorProvider;
+
+/**
+ * This represents information necessary for libbinder to be able to connect to a
+ * remote service.
+ * It supports connecting to linux sockets and is created using sockaddr
+ * types for sockets supported by libbinder like sockaddr_in, sockaddr_un,
+ * sockaddr_vm.
+ */
+typedef struct ABinderRpc_ConnectionInfo ABinderRpc_ConnectionInfo;
+
+/**
+ * These APIs provide a way for clients of binder services to be able to get a
+ * binder object of that service through the existing libbinder/libbinder_ndk
+ * Service Manager APIs when that service is using RPC Binder over sockets
+ * instead kernel binder.
+ *
+ * Some of these APIs are used on Android hosts when kernel binder is supported
+ * and the usual servicemanager process is available. Some of these APIs are
+ * only required when there is no kernel binder or extra servicemanager process
+ * such as the case of microdroid or similar VMs.
+ */
+
+/**
+ * This callback is responsible for returning ABinderRpc_Accessor objects for a given
+ * service instance. These ABinderRpc_Accessor objects are implemented by
+ * libbinder_ndk and backed by implementations of android::os::IAccessor in
+ * libbinder.
+ *
+ * \param instance name of the service like
+ * `android.hardware.vibrator.IVibrator/default`
+ * \param data the data that was associated with this instance when the callback
+ * was registered.
+ * \return The ABinderRpc_Accessor associated with the service `instance`. This
+ * callback gives up ownership of the object once it returns it. The
+ * caller of this callback (libbinder_ndk) is responsible for deleting it
+ * with ABinderRpc_Accessor_delete.
+ */
+typedef ABinderRpc_Accessor* _Nullable (*ABinderRpc_AccessorProvider_getAccessorCallback)(
+ const char* _Nonnull instance, void* _Nullable data);
+
+/**
+ * This callback is responsible deleting the `void* data` object that is passed
+ * in to ABinderRpc_registerAccessorProvider for the ABinderRpc_AccessorProvider_getAccessorCallback
+ * to use. That object is owned by the ABinderRpc_AccessorProvider and must remain valid for the
+ * lifetime of the callback because it may be called and use the object.
+ * This _delete callback is called after the ABinderRpc_AccessorProvider is remove and
+ * is guaranteed never to be called again.
+ *
+ * \param data a pointer to data that the ABinderRpc_AccessorProvider_getAccessorCallback uses which
+ * is to be deleted by this call.
+ */
+typedef void (*ABinderRpc_AccessorProviderUserData_deleteCallback)(void* _Nullable data);
+
+/**
+ * Inject an ABinderRpc_AccessorProvider_getAccessorCallback into the process for
+ * the Service Manager APIs to use to retrieve ABinderRpc_Accessor objects associated
+ * with different RPC Binder services.
+ *
+ * \param provider callback that returns ABinderRpc_Accessors for libbinder to set up
+ * RPC clients with.
+ * \param instances array of instances that are supported by this provider. It
+ * will only be called if the client is looking for an instance that is
+ * in this list. These instances must be unique per-process. If an
+ * instance is being registered that was previously registered, this call
+ * will fail and the ABinderRpc_AccessorProviderUserData_deleteCallback
+ * will be called to clean up the data.
+ * \param number of instances in the instances array.
+ * \param data pointer that is passed to the ABinderRpc_AccessorProvider callback.
+ * IMPORTANT: The ABinderRpc_AccessorProvider now OWNS that object that data
+ * points to. It can be used as necessary in the callback. The data MUST
+ * remain valid for the lifetime of the provider callback.
+ * Do not attempt to give ownership of the same object to different
+ * providers throguh multiple calls to this function because the first
+ * one to be deleted will call the onDelete callback.
+ * \param onDelete callback used to delete the objects that `data` points to.
+ * This is called after ABinderRpc_AccessorProvider is guaranteed to never be
+ * called again. Before this callback is called, `data` must remain
+ * valid.
+ * \return nullptr on error if the data pointer is non-null and the onDelete
+ * callback is null or if an instance in the instances list was previously
+ * registered. In the error case of duplicate instances, if data was
+ * provided with a ABinderRpc_AccessorProviderUserData_deleteCallback,
+ * the callback will be called to delete the data.
+ * Otherwise returns a pointer to the ABinderRpc_AccessorProvider that
+ * can be used to remove with ABinderRpc_unregisterAccessorProvider.
+ */
+ABinderRpc_AccessorProvider* _Nullable ABinderRpc_registerAccessorProvider(
+ ABinderRpc_AccessorProvider_getAccessorCallback _Nonnull provider,
+ const char* _Nullable* _Nonnull instances, size_t numInstances, void* _Nullable data,
+ ABinderRpc_AccessorProviderUserData_deleteCallback _Nullable onDelete) __INTRODUCED_IN(36);
+
+/**
+ * Remove an ABinderRpc_AccessorProvider from libbinder. This will remove references
+ * from the ABinderRpc_AccessorProvider and will no longer call the
+ * ABinderRpc_AccessorProvider_getAccessorCallback.
+ *
+ * Note: The `data` object that was used when adding the accessor will be
+ * deleted by the ABinderRpc_AccessorProviderUserData_deleteCallback at some
+ * point after this call. Do not use the object and do not try to delete
+ * it through any other means.
+ * Note: This will abort when used incorrectly if this provider was never
+ * registered or if it were already unregistered.
+ *
+ * \param provider to be removed and deleted
+ *
+ */
+void ABinderRpc_unregisterAccessorProvider(ABinderRpc_AccessorProvider* _Nonnull provider)
+ __INTRODUCED_IN(36);
+
+/**
+ * Callback which returns the RPC connection information for libbinder to use to
+ * connect to a socket that a given service is listening on. This is needed to
+ * create an ABinderRpc_Accessor so it can connect to these services.
+ *
+ * \param instance name of the service to connect to
+ * \param data userdata for this callback. The pointer is provided in
+ * ABinderRpc_Accessor_new.
+ * \return ABinderRpc_ConnectionInfo with socket connection information for `instance`
+ */
+typedef ABinderRpc_ConnectionInfo* _Nullable (*ABinderRpc_ConnectionInfoProvider)(
+ const char* _Nonnull instance, void* _Nullable data) __INTRODUCED_IN(36);
+/**
+ * This callback is responsible deleting the `void* data` object that is passed
+ * in to ABinderRpc_Accessor_new for the ABinderRpc_ConnectionInfoProvider to use. That
+ * object is owned by the ABinderRpc_Accessor and must remain valid for the
+ * lifetime the Accessor because it may be used by the connection info provider
+ * callback.
+ * This _delete callback is called after the ABinderRpc_Accessor is removed and
+ * is guaranteed never to be called again.
+ *
+ * \param data a pointer to data that the ABinderRpc_AccessorProvider uses which is to
+ * be deleted by this call.
+ */
+typedef void (*ABinderRpc_ConnectionInfoProviderUserData_delete)(void* _Nullable data);
+
+/**
+ * Create a new ABinderRpc_Accessor. This creates an IAccessor object in libbinder
+ * that can use the info from the ABinderRpc_ConnectionInfoProvider to connect to a
+ * socket that the service with `instance` name is listening to.
+ *
+ * \param instance name of the service that is listening on the socket
+ * \param provider callback that can get the socket connection information for the
+ * instance. This connection information may be dynamic, so the
+ * provider will be called any time a new connection is required.
+ * \param data pointer that is passed to the ABinderRpc_ConnectionInfoProvider callback.
+ * IMPORTANT: The ABinderRpc_ConnectionInfoProvider now OWNS that object that data
+ * points to. It can be used as necessary in the callback. The data MUST
+ * remain valid for the lifetime of the provider callback.
+ * Do not attempt to give ownership of the same object to different
+ * providers through multiple calls to this function because the first
+ * one to be deleted will call the onDelete callback.
+ * \param onDelete callback used to delete the objects that `data` points to.
+ * This is called after ABinderRpc_ConnectionInfoProvider is guaranteed to never be
+ * called again. Before this callback is called, `data` must remain
+ * valid.
+ * \return an ABinderRpc_Accessor instance. This is deleted by the caller once it is
+ * no longer needed.
+ */
+ABinderRpc_Accessor* _Nullable ABinderRpc_Accessor_new(
+ const char* _Nonnull instance, ABinderRpc_ConnectionInfoProvider _Nonnull provider,
+ void* _Nullable data, ABinderRpc_ConnectionInfoProviderUserData_delete _Nullable onDelete)
+ __INTRODUCED_IN(36);
+
+/**
+ * Delete an ABinderRpc_Accessor
+ *
+ * \param accessor to delete
+ */
+void ABinderRpc_Accessor_delete(ABinderRpc_Accessor* _Nonnull accessor) __INTRODUCED_IN(36);
+
+/**
+ * Return the AIBinder associated with an ABinderRpc_Accessor. This can be used to
+ * send the Accessor to another process or even register it with servicemanager.
+ *
+ * \param accessor to get the AIBinder for
+ * \return binder of the supplied accessor with one strong ref count
+ */
+AIBinder* _Nullable ABinderRpc_Accessor_asBinder(ABinderRpc_Accessor* _Nonnull accessor)
+ __INTRODUCED_IN(36);
+
+/**
+ * Return the ABinderRpc_Accessor associated with an AIBinder. The instance must match
+ * the ABinderRpc_Accessor implementation, and the AIBinder must a proxy binder for a
+ * remote service (ABpBinder).
+ * This can be used when receivng an AIBinder from another process that the
+ * other process obtained from ABinderRpc_Accessor_asBinder.
+ *
+ * \param instance name of the service that the Accessor is responsible for.
+ * \param accessorBinder proxy binder from another processes ABinderRpc_Accessor.
+ * \return ABinderRpc_Accessor representing the other processes ABinderRpc_Accessor
+ * implementation. This function does not take ownership of the
+ * ABinderRpc_Accessor (so the caller needs to delete with
+ * ABinderRpc_Accessor_delete), and it preserves the recount of the bidner
+ * object.
+ */
+ABinderRpc_Accessor* _Nullable ABinderRpc_Accessor_fromBinder(const char* _Nonnull instance,
+ AIBinder* _Nonnull accessorBinder)
+ __INTRODUCED_IN(36);
+
+/**
+ * Create a new ABinderRpc_ConnectionInfo with sockaddr. This can be supported socket
+ * types like sockaddr_vm (vsock) and sockaddr_un (Unix Domain Sockets).
+ *
+ * \param addr sockaddr pointer that can come from supported socket
+ * types like sockaddr_vm (vsock) and sockaddr_un (Unix Domain Sockets).
+ * \param len length of the concrete sockaddr type being used. Like
+ * sizeof(sockaddr_vm) when sockaddr_vm is used.
+ * \return the connection info based on the given sockaddr
+ */
+ABinderRpc_ConnectionInfo* _Nullable ABinderRpc_ConnectionInfo_new(const sockaddr* _Nonnull addr,
+ socklen_t len)
+ __INTRODUCED_IN(36);
+
+/**
+ * Delete an ABinderRpc_ConnectionInfo object that was created with
+ * ABinderRpc_ConnectionInfo_new.
+ *
+ * \param info object to be deleted
+ */
+void ABinderRpc_ConnectionInfo_delete(ABinderRpc_ConnectionInfo* _Nonnull info) __INTRODUCED_IN(36);
+
+__END_DECLS
diff --git a/libs/binder/ndk/libbinder_ndk.map.txt b/libs/binder/ndk/libbinder_ndk.map.txt
index 826e199093..c885816e56 100644
--- a/libs/binder/ndk/libbinder_ndk.map.txt
+++ b/libs/binder/ndk/libbinder_ndk.map.txt
@@ -248,6 +248,22 @@ LIBBINDER_NDK35 { # introduced=VanillaIceCream
AServiceManager_openDeclaredPassthroughHal; # systemapi llndk=202404
};
+LIBBINDER_NDK36 { # introduced=36
+ global:
+ AIBinder_Class_setTransactionCodeToFunctionNameMap;
+ AIBinder_Class_setTransactionCodeToFunctionNameMap; # llndk=202504
+ AIBinder_Class_getFunctionName;
+ AIBinder_Class_getFunctionName; # llndk=202504
+ ABinderRpc_registerAccessorProvider; # systemapi
+ ABinderRpc_unregisterAccessorProvider; # systemapi
+ ABinderRpc_Accessor_new; # systemapi
+ ABinderRpc_Accessor_delete; # systemapi
+ ABinderRpc_Accessor_asBinder; # systemapi
+ ABinderRpc_Accessor_fromBinder; # systemapi
+ ABinderRpc_ConnectionInfo_new; # systemapi
+ ABinderRpc_ConnectionInfo_delete; # systemapi
+};
+
LIBBINDER_NDK_PLATFORM {
global:
AParcel_getAllowFds;
diff --git a/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
index 3cd2b9a891..e5a3da460e 100644
--- a/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
+++ b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
@@ -1108,6 +1108,37 @@ TEST(NdkBinder_ScopedAResource, Release) {
EXPECT_EQ(deleteCount, 0);
}
+void* EmptyOnCreate(void* args) {
+ return args;
+}
+void EmptyOnDestroy(void* /*userData*/) {}
+binder_status_t EmptyOnTransact(AIBinder* /*binder*/, transaction_code_t /*code*/,
+ const AParcel* /*in*/, AParcel* /*out*/) {
+ return STATUS_OK;
+}
+
+TEST(NdkBinder_DeathTest, SetCodeMapTwice) {
+ const char* codeToFunction1[] = {"function-1", "function-2", "function-3"};
+ const char* codeToFunction2[] = {"function-4", "function-5"};
+ const char* interfaceName = "interface_descriptor";
+ AIBinder_Class* clazz =
+ AIBinder_Class_define(interfaceName, EmptyOnCreate, EmptyOnDestroy, EmptyOnTransact);
+ AIBinder_Class_setTransactionCodeToFunctionNameMap(clazz, codeToFunction1, 3);
+ // Reset/clear is not allowed
+ EXPECT_DEATH(AIBinder_Class_setTransactionCodeToFunctionNameMap(clazz, codeToFunction2, 2), "");
+}
+
+TEST(NdkBinder_DeathTest, SetNullCodeMap) {
+ const char* codeToFunction[] = {"function-1", "function-2", "function-3"};
+ const char* interfaceName = "interface_descriptor";
+ AIBinder_Class* clazz =
+ AIBinder_Class_define(interfaceName, EmptyOnCreate, EmptyOnDestroy, EmptyOnTransact);
+ EXPECT_DEATH(AIBinder_Class_setTransactionCodeToFunctionNameMap(nullptr, codeToFunction, 3),
+ "");
+ EXPECT_DEATH(AIBinder_Class_setTransactionCodeToFunctionNameMap(clazz, nullptr, 0), "");
+ EXPECT_DEATH(AIBinder_Class_setTransactionCodeToFunctionNameMap(nullptr, nullptr, 0), "");
+}
+
int main(int argc, char* argv[]) {
::testing::InitGoogleTest(&argc, argv);
diff --git a/libs/binder/rust/src/binder.rs b/libs/binder/rust/src/binder.rs
index 9a252b853b..23026e593c 100644
--- a/libs/binder/rust/src/binder.rs
+++ b/libs/binder/rust/src/binder.rs
@@ -136,6 +136,31 @@ impl TryFrom<i32> for Stability {
}
}
+/// Same as `Stability`, but in the form of a trait. Used when the stability should be encoded in
+/// the type.
+///
+/// When/if the `adt_const_params` Rust feature is stabilized, this could be replace by using
+/// `Stability` directly with const generics.
+pub trait StabilityType {
+ /// The `Stability` represented by this type.
+ const VALUE: Stability;
+}
+
+/// `Stability::Local`.
+#[derive(Debug)]
+pub enum LocalStabilityType {}
+/// `Stability::Vintf`.
+#[derive(Debug)]
+pub enum VintfStabilityType {}
+
+impl StabilityType for LocalStabilityType {
+ const VALUE: Stability = Stability::Local;
+}
+
+impl StabilityType for VintfStabilityType {
+ const VALUE: Stability = Stability::Vintf;
+}
+
/// A local service that can be remotable via Binder.
///
/// An object that implement this interface made be made into a Binder service
diff --git a/libs/binder/rust/src/lib.rs b/libs/binder/rust/src/lib.rs
index e70f4f0232..e048696e88 100644
--- a/libs/binder/rust/src/lib.rs
+++ b/libs/binder/rust/src/lib.rs
@@ -128,9 +128,10 @@ pub type Result<T> = std::result::Result<T, Status>;
/// without AIDL.
pub mod binder_impl {
pub use crate::binder::{
- IBinderInternal, InterfaceClass, Remotable, Stability, ToAsyncInterface, ToSyncInterface,
- TransactionCode, TransactionFlags, FIRST_CALL_TRANSACTION, FLAG_CLEAR_BUF, FLAG_ONEWAY,
- FLAG_PRIVATE_LOCAL, LAST_CALL_TRANSACTION,
+ IBinderInternal, InterfaceClass, LocalStabilityType, Remotable, Stability, StabilityType,
+ ToAsyncInterface, ToSyncInterface, TransactionCode, TransactionFlags, VintfStabilityType,
+ FIRST_CALL_TRANSACTION, FLAG_CLEAR_BUF, FLAG_ONEWAY, FLAG_PRIVATE_LOCAL,
+ LAST_CALL_TRANSACTION,
};
pub use crate::binder_async::BinderAsyncRuntime;
pub use crate::error::status_t;
diff --git a/libs/binder/rust/src/parcel/parcelable_holder.rs b/libs/binder/rust/src/parcel/parcelable_holder.rs
index f90611361f..87b42ab68d 100644
--- a/libs/binder/rust/src/parcel/parcelable_holder.rs
+++ b/libs/binder/rust/src/parcel/parcelable_holder.rs
@@ -15,6 +15,7 @@
*/
use crate::binder::Stability;
+use crate::binder::StabilityType;
use crate::error::StatusCode;
use crate::parcel::{
BorrowedParcel, Deserialize, Parcel, Parcelable, Serialize, NON_NULL_PARCELABLE_FLAG,
@@ -60,7 +61,7 @@ enum ParcelableHolderData {
/// `Send` nor `Sync`), mainly because it internally contains
/// a `Parcel` which in turn is not thread-safe.
#[derive(Debug)]
-pub struct ParcelableHolder {
+pub struct ParcelableHolder<STABILITY: StabilityType> {
// This is a `Mutex` because of `get_parcelable`
// which takes `&self` for consistency with C++.
// We could make `get_parcelable` take a `&mut self`
@@ -68,13 +69,17 @@ pub struct ParcelableHolder {
// improvement, but then callers would require a mutable
// `ParcelableHolder` even for that getter method.
data: Mutex<ParcelableHolderData>,
- stability: Stability,
+
+ _stability_phantom: std::marker::PhantomData<STABILITY>,
}
-impl ParcelableHolder {
+impl<STABILITY: StabilityType> ParcelableHolder<STABILITY> {
/// Construct a new `ParcelableHolder` with the given stability.
- pub fn new(stability: Stability) -> Self {
- Self { data: Mutex::new(ParcelableHolderData::Empty), stability }
+ pub fn new() -> Self {
+ Self {
+ data: Mutex::new(ParcelableHolderData::Empty),
+ _stability_phantom: Default::default(),
+ }
}
/// Reset the contents of this `ParcelableHolder`.
@@ -91,7 +96,7 @@ impl ParcelableHolder {
where
T: Any + Parcelable + ParcelableMetadata + std::fmt::Debug + Send + Sync,
{
- if self.stability > p.get_stability() {
+ if STABILITY::VALUE > p.get_stability() {
return Err(StatusCode::BAD_VALUE);
}
@@ -157,30 +162,36 @@ impl ParcelableHolder {
/// Return the stability value of this object.
pub fn get_stability(&self) -> Stability {
- self.stability
+ STABILITY::VALUE
+ }
+}
+
+impl<STABILITY: StabilityType> Default for ParcelableHolder<STABILITY> {
+ fn default() -> Self {
+ Self::new()
}
}
-impl Clone for ParcelableHolder {
- fn clone(&self) -> ParcelableHolder {
+impl<STABILITY: StabilityType> Clone for ParcelableHolder<STABILITY> {
+ fn clone(&self) -> Self {
ParcelableHolder {
data: Mutex::new(self.data.lock().unwrap().clone()),
- stability: self.stability,
+ _stability_phantom: Default::default(),
}
}
}
-impl Serialize for ParcelableHolder {
+impl<STABILITY: StabilityType> Serialize for ParcelableHolder<STABILITY> {
fn serialize(&self, parcel: &mut BorrowedParcel<'_>) -> Result<(), StatusCode> {
parcel.write(&NON_NULL_PARCELABLE_FLAG)?;
self.write_to_parcel(parcel)
}
}
-impl Deserialize for ParcelableHolder {
+impl<STABILITY: StabilityType> Deserialize for ParcelableHolder<STABILITY> {
type UninitType = Self;
fn uninit() -> Self::UninitType {
- Self::new(Default::default())
+ Self::new()
}
fn from_init(value: Self) -> Self::UninitType {
value
@@ -191,16 +202,16 @@ impl Deserialize for ParcelableHolder {
if status == NULL_PARCELABLE_FLAG {
Err(StatusCode::UNEXPECTED_NULL)
} else {
- let mut parcelable = ParcelableHolder::new(Default::default());
+ let mut parcelable = Self::new();
parcelable.read_from_parcel(parcel)?;
Ok(parcelable)
}
}
}
-impl Parcelable for ParcelableHolder {
+impl<STABILITY: StabilityType> Parcelable for ParcelableHolder<STABILITY> {
fn write_to_parcel(&self, parcel: &mut BorrowedParcel<'_>) -> Result<(), StatusCode> {
- parcel.write(&self.stability)?;
+ parcel.write(&STABILITY::VALUE)?;
let mut data = self.data.lock().unwrap();
match *data {
@@ -236,7 +247,7 @@ impl Parcelable for ParcelableHolder {
}
fn read_from_parcel(&mut self, parcel: &BorrowedParcel<'_>) -> Result<(), StatusCode> {
- if self.stability != parcel.read()? {
+ if self.get_stability() != parcel.read()? {
return Err(StatusCode::BAD_VALUE);
}
diff --git a/libs/binder/rust/tests/parcel_fuzzer/parcel_fuzzer.rs b/libs/binder/rust/tests/parcel_fuzzer/parcel_fuzzer.rs
index ce0f742934..ee20a22345 100644
--- a/libs/binder/rust/tests/parcel_fuzzer/parcel_fuzzer.rs
+++ b/libs/binder/rust/tests/parcel_fuzzer/parcel_fuzzer.rs
@@ -21,7 +21,8 @@ mod read_utils;
use crate::read_utils::READ_FUNCS;
use binder::binder_impl::{
- Binder, BorrowedParcel, IBinderInternal, Parcel, Stability, TransactionCode,
+ Binder, BorrowedParcel, IBinderInternal, LocalStabilityType, Parcel, TransactionCode,
+ VintfStabilityType,
};
use binder::{
declare_binder_interface, BinderFeatures, Interface, Parcelable, ParcelableHolder, SpIBinder,
@@ -121,13 +122,15 @@ fn do_read_fuzz(read_operations: Vec<ReadOperation>, data: &[u8]) {
}
ReadOperation::ReadParcelableHolder { is_vintf } => {
- let stability = if is_vintf { Stability::Vintf } else { Stability::Local };
- let mut holder: ParcelableHolder = ParcelableHolder::new(stability);
- match holder.read_from_parcel(parcel.borrowed_ref()) {
- Ok(result) => result,
- Err(err) => {
- println!("error occurred while reading from parcel: {:?}", err)
- }
+ let result = if is_vintf {
+ ParcelableHolder::<VintfStabilityType>::new()
+ .read_from_parcel(parcel.borrowed_ref())
+ } else {
+ ParcelableHolder::<LocalStabilityType>::new()
+ .read_from_parcel(parcel.borrowed_ref())
+ };
+ if let Err(e) = result {
+ println!("error occurred while reading from parcel: {e:?}")
}
}
diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp
index 0e653af707..8b0dda33dd 100644
--- a/libs/binder/tests/Android.bp
+++ b/libs/binder/tests/Android.bp
@@ -532,6 +532,9 @@ cc_test {
static_libs: [
"libbinder_rpc_single_threaded",
],
+ shared_libs: [
+ "libbinder_ndk",
+ ],
}
cc_test {
diff --git a/libs/binder/tests/binderRpcTest.cpp b/libs/binder/tests/binderRpcTest.cpp
index 0ef200bcbe..077a33a201 100644
--- a/libs/binder/tests/binderRpcTest.cpp
+++ b/libs/binder/tests/binderRpcTest.cpp
@@ -46,6 +46,13 @@
#include "binderRpcTestCommon.h"
#include "binderRpcTestFixture.h"
+// TODO need to add IServiceManager.cpp/.h to libbinder_no_kernel
+#ifdef BINDER_WITH_KERNEL_IPC
+#include "android-base/logging.h"
+#include "android/binder_manager.h"
+#include "android/binder_rpc.h"
+#endif // BINDER_WITH_KERNEL_IPC
+
using namespace std::chrono_literals;
using namespace std::placeholders;
using android::binder::borrowed_fd;
@@ -1204,27 +1211,29 @@ TEST_P(BinderRpcAccessor, InjectAndGetServiceHappyPath) {
auto proc = createRpcTestSocketServerProcess({.numThreads = kNumThreads});
EXPECT_EQ(OK, proc.rootBinder->pingBinder());
- auto receipt = addAccessorProvider([&](const String16& name) -> sp<IBinder> {
- return createAccessor(name,
- [&](const String16& name, sockaddr* outAddr,
- socklen_t addrSize) -> status_t {
- if (outAddr == nullptr ||
- addrSize < proc.proc->sessions[0].addrLen) {
- return BAD_VALUE;
- }
- if (name == kInstanceName) {
- if (proc.proc->sessions[0].addr.ss_family == AF_UNIX) {
- sockaddr_un* un = reinterpret_cast<sockaddr_un*>(
- &proc.proc->sessions[0].addr);
- ALOGE("inside callback: %s", un->sun_path);
- }
- std::memcpy(outAddr, &proc.proc->sessions[0].addr,
- proc.proc->sessions[0].addrLen);
- return OK;
- }
- return NAME_NOT_FOUND;
- });
- });
+ auto receipt = addAccessorProvider(
+ {String8(kInstanceName).c_str()}, [&](const String16& name) -> sp<IBinder> {
+ return createAccessor(name,
+ [&](const String16& name, sockaddr* outAddr,
+ socklen_t addrSize) -> status_t {
+ if (outAddr == nullptr ||
+ addrSize < proc.proc->sessions[0].addrLen) {
+ return BAD_VALUE;
+ }
+ if (name == kInstanceName) {
+ if (proc.proc->sessions[0].addr.ss_family ==
+ AF_UNIX) {
+ sockaddr_un* un = reinterpret_cast<sockaddr_un*>(
+ &proc.proc->sessions[0].addr);
+ ALOGE("inside callback: %s", un->sun_path);
+ }
+ std::memcpy(outAddr, &proc.proc->sessions[0].addr,
+ proc.proc->sessions[0].addrLen);
+ return OK;
+ }
+ return NAME_NOT_FOUND;
+ });
+ });
EXPECT_FALSE(receipt.expired());
@@ -1251,7 +1260,8 @@ TEST_P(BinderRpcAccessor, InjectNoAccessorProvided) {
bool isProviderDeleted = false;
- auto receipt = addAccessorProvider([&](const String16&) -> sp<IBinder> { return nullptr; });
+ auto receipt = addAccessorProvider({String8(kInstanceName).c_str()},
+ [&](const String16&) -> sp<IBinder> { return nullptr; });
EXPECT_FALSE(receipt.expired());
sp<IBinder> binder = defaultServiceManager()->checkService(kInstanceName);
@@ -1261,6 +1271,32 @@ TEST_P(BinderRpcAccessor, InjectNoAccessorProvided) {
EXPECT_EQ(status, OK);
}
+TEST_P(BinderRpcAccessor, InjectDuplicateAccessorProvider) {
+ const String16 kInstanceName("super.cool.service/better_than_default");
+ const String16 kInstanceName2("super.cool.service/better_than_default2");
+
+ auto receipt =
+ addAccessorProvider({String8(kInstanceName).c_str(), String8(kInstanceName2).c_str()},
+ [&](const String16&) -> sp<IBinder> { return nullptr; });
+ EXPECT_FALSE(receipt.expired());
+ // reject this because it's associated with an already used instance name
+ auto receipt2 = addAccessorProvider({String8(kInstanceName).c_str()},
+ [&](const String16&) -> sp<IBinder> { return nullptr; });
+ EXPECT_TRUE(receipt2.expired());
+
+ // the first provider should still be usable
+ sp<IBinder> binder = defaultServiceManager()->checkService(kInstanceName);
+ EXPECT_EQ(binder, nullptr);
+
+ status_t status = removeAccessorProvider(receipt);
+ EXPECT_EQ(status, OK);
+}
+
+TEST_P(BinderRpcAccessor, InjectAccessorProviderNoInstance) {
+ auto receipt = addAccessorProvider({}, [&](const String16&) -> sp<IBinder> { return nullptr; });
+ EXPECT_TRUE(receipt.expired());
+}
+
TEST_P(BinderRpcAccessor, InjectNoSockaddrProvided) {
constexpr size_t kNumThreads = 10;
const String16 kInstanceName("super.cool.service/better_than_default");
@@ -1271,12 +1307,15 @@ TEST_P(BinderRpcAccessor, InjectNoSockaddrProvided) {
bool isProviderDeleted = false;
bool isAccessorDeleted = false;
- auto receipt = addAccessorProvider([&](const String16& name) -> sp<IBinder> {
- return createAccessor(name, [&](const String16&, sockaddr*, socklen_t) -> status_t {
- // don't fill in outAddr
- return NAME_NOT_FOUND;
- });
- });
+ auto receipt = addAccessorProvider({String8(kInstanceName).c_str()},
+ [&](const String16& name) -> sp<IBinder> {
+ return createAccessor(name,
+ [&](const String16&, sockaddr*,
+ socklen_t) -> status_t {
+ // don't fill in outAddr
+ return NAME_NOT_FOUND;
+ });
+ });
EXPECT_FALSE(receipt.expired());
@@ -1287,6 +1326,260 @@ TEST_P(BinderRpcAccessor, InjectNoSockaddrProvided) {
EXPECT_EQ(status, OK);
}
+constexpr const char* kARpcInstance = "some.instance.name.IFoo/default";
+const char* kARpcSupportedServices[] = {
+ kARpcInstance,
+};
+const uint32_t kARpcNumSupportedServices = 1;
+
+struct ConnectionInfoData {
+ sockaddr_storage addr;
+ socklen_t len;
+ bool* isDeleted;
+ ~ConnectionInfoData() {
+ if (isDeleted) *isDeleted = true;
+ }
+};
+
+struct AccessorProviderData {
+ sockaddr_storage addr;
+ socklen_t len;
+ bool* isDeleted;
+ ~AccessorProviderData() {
+ if (isDeleted) *isDeleted = true;
+ }
+};
+
+void accessorProviderDataOnDelete(void* data) {
+ delete reinterpret_cast<AccessorProviderData*>(data);
+}
+void infoProviderDataOnDelete(void* data) {
+ delete reinterpret_cast<ConnectionInfoData*>(data);
+}
+
+ABinderRpc_ConnectionInfo* infoProvider(const char* instance, void* cookie) {
+ if (instance == nullptr || cookie == nullptr) return nullptr;
+ ConnectionInfoData* data = reinterpret_cast<ConnectionInfoData*>(cookie);
+ return ABinderRpc_ConnectionInfo_new(reinterpret_cast<const sockaddr*>(&data->addr), data->len);
+}
+
+ABinderRpc_Accessor* getAccessor(const char* instance, void* cookie) {
+ if (instance == nullptr || cookie == nullptr) return nullptr;
+ if (0 != strcmp(instance, kARpcInstance)) return nullptr;
+
+ AccessorProviderData* data = reinterpret_cast<AccessorProviderData*>(cookie);
+
+ ConnectionInfoData* info = new ConnectionInfoData{
+ .addr = data->addr,
+ .len = data->len,
+ .isDeleted = nullptr,
+ };
+
+ return ABinderRpc_Accessor_new(instance, infoProvider, info, infoProviderDataOnDelete);
+}
+
+class BinderARpcNdk : public ::testing::Test {};
+
+TEST_F(BinderARpcNdk, ARpcProviderNewDelete) {
+ bool isDeleted = false;
+
+ AccessorProviderData* data = new AccessorProviderData{{}, 0, &isDeleted};
+
+ ABinderRpc_AccessorProvider* provider =
+ ABinderRpc_registerAccessorProvider(getAccessor, kARpcSupportedServices,
+ kARpcNumSupportedServices, data,
+ accessorProviderDataOnDelete);
+
+ ASSERT_NE(provider, nullptr);
+ EXPECT_FALSE(isDeleted);
+
+ ABinderRpc_unregisterAccessorProvider(provider);
+
+ EXPECT_TRUE(isDeleted);
+}
+
+TEST_F(BinderARpcNdk, ARpcProviderDuplicateInstance) {
+ const char* instance = "some.instance.name.IFoo/default";
+ const uint32_t numInstances = 2;
+ const char* instances[numInstances] = {
+ instance,
+ "some.other.instance/default",
+ };
+
+ bool isDeleted = false;
+
+ AccessorProviderData* data = new AccessorProviderData{{}, 0, &isDeleted};
+
+ ABinderRpc_AccessorProvider* provider =
+ ABinderRpc_registerAccessorProvider(getAccessor, instances, numInstances, data,
+ accessorProviderDataOnDelete);
+
+ ASSERT_NE(provider, nullptr);
+ EXPECT_FALSE(isDeleted);
+
+ const uint32_t numInstances2 = 1;
+ const char* instances2[numInstances2] = {
+ instance,
+ };
+ bool isDeleted2 = false;
+ AccessorProviderData* data2 = new AccessorProviderData{{}, 0, &isDeleted2};
+ ABinderRpc_AccessorProvider* provider2 =
+ ABinderRpc_registerAccessorProvider(getAccessor, instances2, numInstances2, data2,
+ accessorProviderDataOnDelete);
+
+ EXPECT_EQ(provider2, nullptr);
+ // If it fails to be registered, the data is still cleaned up with
+ // accessorProviderDataOnDelete
+ EXPECT_TRUE(isDeleted2);
+
+ ABinderRpc_unregisterAccessorProvider(provider);
+
+ EXPECT_TRUE(isDeleted);
+}
+
+TEST_F(BinderARpcNdk, ARpcProviderRegisterNoInstance) {
+ const uint32_t numInstances = 0;
+ const char* instances[numInstances] = {};
+
+ bool isDeleted = false;
+ AccessorProviderData* data = new AccessorProviderData{{}, 0, &isDeleted};
+
+ ABinderRpc_AccessorProvider* provider =
+ ABinderRpc_registerAccessorProvider(getAccessor, instances, numInstances, data,
+ accessorProviderDataOnDelete);
+ ASSERT_EQ(provider, nullptr);
+}
+
+TEST_F(BinderARpcNdk, ARpcAccessorNewDelete) {
+ bool isDeleted = false;
+
+ ConnectionInfoData* data = new ConnectionInfoData{{}, 0, &isDeleted};
+
+ ABinderRpc_Accessor* accessor =
+ ABinderRpc_Accessor_new("gshoe_service", infoProvider, data, infoProviderDataOnDelete);
+ ASSERT_NE(accessor, nullptr);
+ EXPECT_FALSE(isDeleted);
+
+ ABinderRpc_Accessor_delete(accessor);
+ EXPECT_TRUE(isDeleted);
+}
+
+TEST_F(BinderARpcNdk, ARpcConnectionInfoNewDelete) {
+ sockaddr_vm addr{
+ .svm_family = AF_VSOCK,
+ .svm_port = VMADDR_PORT_ANY,
+ .svm_cid = VMADDR_CID_ANY,
+ };
+
+ ABinderRpc_ConnectionInfo* info =
+ ABinderRpc_ConnectionInfo_new(reinterpret_cast<sockaddr*>(&addr), sizeof(sockaddr_vm));
+ EXPECT_NE(info, nullptr);
+
+ ABinderRpc_ConnectionInfo_delete(info);
+}
+
+TEST_F(BinderARpcNdk, ARpcAsFromBinderAsBinder) {
+ bool isDeleted = false;
+
+ ConnectionInfoData* data = new ConnectionInfoData{{}, 0, &isDeleted};
+
+ ABinderRpc_Accessor* accessor =
+ ABinderRpc_Accessor_new("gshoe_service", infoProvider, data, infoProviderDataOnDelete);
+ ASSERT_NE(accessor, nullptr);
+ EXPECT_FALSE(isDeleted);
+
+ {
+ ndk::SpAIBinder binder = ndk::SpAIBinder(ABinderRpc_Accessor_asBinder(accessor));
+ EXPECT_NE(binder.get(), nullptr);
+
+ ABinderRpc_Accessor* accessor2 =
+ ABinderRpc_Accessor_fromBinder("wrong_service_name", binder.get());
+ // The API checks for the expected service name that is associated with
+ // the accessor!
+ EXPECT_EQ(accessor2, nullptr);
+
+ accessor2 = ABinderRpc_Accessor_fromBinder("gshoe_service", binder.get());
+ EXPECT_NE(accessor2, nullptr);
+
+ // this is a new ABinderRpc_Accessor object that wraps the underlying
+ // libbinder object.
+ EXPECT_NE(accessor, accessor2);
+
+ ndk::SpAIBinder binder2 = ndk::SpAIBinder(ABinderRpc_Accessor_asBinder(accessor2));
+ EXPECT_EQ(binder.get(), binder2.get());
+
+ ABinderRpc_Accessor_delete(accessor2);
+ }
+
+ EXPECT_FALSE(isDeleted);
+ ABinderRpc_Accessor_delete(accessor);
+ EXPECT_TRUE(isDeleted);
+}
+
+TEST_F(BinderARpcNdk, ARpcRequireProviderOnDeleteCallback) {
+ EXPECT_EQ(nullptr,
+ ABinderRpc_registerAccessorProvider(getAccessor, kARpcSupportedServices,
+ kARpcNumSupportedServices,
+ reinterpret_cast<void*>(1), nullptr));
+}
+
+TEST_F(BinderARpcNdk, ARpcRequireInfoOnDeleteCallback) {
+ EXPECT_EQ(nullptr,
+ ABinderRpc_Accessor_new("the_best_service_name", infoProvider,
+ reinterpret_cast<void*>(1), nullptr));
+}
+
+TEST_F(BinderARpcNdk, ARpcNoDataNoProviderOnDeleteCallback) {
+ ABinderRpc_AccessorProvider* provider =
+ ABinderRpc_registerAccessorProvider(getAccessor, kARpcSupportedServices,
+ kARpcNumSupportedServices, nullptr, nullptr);
+ ASSERT_NE(nullptr, provider);
+ ABinderRpc_unregisterAccessorProvider(provider);
+}
+
+TEST_F(BinderARpcNdk, ARpcNoDataNoInfoOnDeleteCallback) {
+ ABinderRpc_Accessor* accessor =
+ ABinderRpc_Accessor_new("the_best_service_name", infoProvider, nullptr, nullptr);
+ ASSERT_NE(nullptr, accessor);
+ ABinderRpc_Accessor_delete(accessor);
+}
+
+TEST_F(BinderARpcNdk, ARpcNullArgs_ConnectionInfo_new) {
+ sockaddr_storage addr;
+ EXPECT_EQ(nullptr, ABinderRpc_ConnectionInfo_new(reinterpret_cast<const sockaddr*>(&addr), 0));
+}
+
+TEST_P(BinderRpcAccessor, ARpcGetService) {
+ constexpr size_t kNumThreads = 10;
+ bool isDeleted = false;
+
+ auto proc = createRpcTestSocketServerProcess({.numThreads = kNumThreads});
+ EXPECT_EQ(OK, proc.rootBinder->pingBinder());
+
+ AccessorProviderData* data =
+ new AccessorProviderData{proc.proc->sessions[0].addr, proc.proc->sessions[0].addrLen,
+ &isDeleted};
+
+ ABinderRpc_AccessorProvider* provider =
+ ABinderRpc_registerAccessorProvider(getAccessor, kARpcSupportedServices,
+ kARpcNumSupportedServices, data,
+ accessorProviderDataOnDelete);
+
+ EXPECT_NE(provider, nullptr);
+ EXPECT_FALSE(isDeleted);
+
+ {
+ ndk::SpAIBinder binder = ndk::SpAIBinder(AServiceManager_checkService(kARpcInstance));
+ ASSERT_NE(binder.get(), nullptr);
+ EXPECT_EQ(STATUS_OK, AIBinder_ping(binder.get()));
+ }
+
+ ABinderRpc_unregisterAccessorProvider(provider);
+ EXPECT_TRUE(isDeleted);
+
+ waitForExtraSessionCleanup(proc);
+}
+
#endif // BINDER_WITH_KERNEL_IPC
#ifdef BINDER_RPC_TO_TRUSTY_TEST
diff --git a/libs/binder/tests/parcel_fuzzer/binder_ndk.cpp b/libs/binder/tests/parcel_fuzzer/binder_ndk.cpp
index 3a1471eabe..e3a337171f 100644
--- a/libs/binder/tests/parcel_fuzzer/binder_ndk.cpp
+++ b/libs/binder/tests/parcel_fuzzer/binder_ndk.cpp
@@ -49,7 +49,8 @@ static binder_status_t onTransact(AIBinder*, transaction_code_t, const AParcel*,
return STATUS_UNKNOWN_TRANSACTION;
}
-static AIBinder_Class* g_class = ::ndk::ICInterface::defineClass("ISomeInterface", onTransact);
+static AIBinder_Class* g_class =
+ ::ndk::ICInterface::defineClass("ISomeInterface", onTransact, nullptr, 0);
class BpSomeInterface : public ::ndk::BpCInterface<ISomeInterface> {
public:
diff --git a/libs/binder/trusty/OS.cpp b/libs/binder/trusty/OS.cpp
index 157ab3c85d..ba9e457a75 100644
--- a/libs/binder/trusty/OS.cpp
+++ b/libs/binder/trusty/OS.cpp
@@ -42,6 +42,10 @@ void trace_end(uint64_t) {}
void trace_int(uint64_t, const char*, int32_t) {}
+uint64_t get_trace_enabled_tags() {
+ return 0;
+}
+
uint64_t GetThreadId() {
return 0;
}
diff --git a/libs/binder/trusty/ndk/include/android/llndk-versioning.h b/libs/binder/trusty/ndk/include/android/llndk-versioning.h
index 3ae3d8f577..e955a34bdf 100644
--- a/libs/binder/trusty/ndk/include/android/llndk-versioning.h
+++ b/libs/binder/trusty/ndk/include/android/llndk-versioning.h
@@ -15,4 +15,5 @@
*/
#pragma once
-#define __INTRODUCED_IN_LLNDK(x) /* nothing on Trusty */
+// TODO(b/349936395): set to true for Trusty
+#define API_LEVEL_AT_LEAST(sdk_api_level, vendor_api_level) (false)
diff --git a/libs/debugstore/OWNERS b/libs/debugstore/OWNERS
index 428a1a2215..c8e22b70ff 100644
--- a/libs/debugstore/OWNERS
+++ b/libs/debugstore/OWNERS
@@ -1,3 +1,2 @@
benmiles@google.com
-gaillard@google.com
mohamadmahmoud@google.com
diff --git a/libs/debugstore/rust/Android.bp b/libs/debugstore/rust/Android.bp
index 55ba3c32d1..9475333a72 100644
--- a/libs/debugstore/rust/Android.bp
+++ b/libs/debugstore/rust/Android.bp
@@ -23,7 +23,6 @@ rust_defaults {
rustlibs: [
"libcrossbeam_queue",
"libparking_lot",
- "libonce_cell",
"libcxx",
],
shared_libs: ["libutils"],
diff --git a/libs/debugstore/rust/src/core.rs b/libs/debugstore/rust/src/core.rs
index 1dfa512151..6bf79d4e57 100644
--- a/libs/debugstore/rust/src/core.rs
+++ b/libs/debugstore/rust/src/core.rs
@@ -17,12 +17,14 @@ use super::event::Event;
use super::event_type::EventType;
use super::storage::Storage;
use crate::cxxffi::uptimeMillis;
-use once_cell::sync::Lazy;
use std::fmt;
-use std::sync::atomic::{AtomicU64, Ordering};
+use std::sync::{
+ atomic::{AtomicU64, Ordering},
+ LazyLock,
+};
// Lazily initialized static instance of DebugStore.
-static INSTANCE: Lazy<DebugStore> = Lazy::new(DebugStore::new);
+static INSTANCE: LazyLock<DebugStore> = LazyLock::new(DebugStore::new);
/// The `DebugStore` struct is responsible for managing debug events and data.
pub struct DebugStore {
diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp
index c65eafa541..25e6a52ed1 100644
--- a/libs/gui/BLASTBufferQueue.cpp
+++ b/libs/gui/BLASTBufferQueue.cpp
@@ -31,7 +31,6 @@
#include <sys/epoll.h>
#include <sys/eventfd.h>
-#include <gui/FenceMonitor.h>
#include <gui/FrameRateUtils.h>
#include <gui/GLConsumer.h>
#include <gui/IProducerListener.h>
@@ -476,16 +475,6 @@ void BLASTBufferQueue::releaseBufferCallbackLocked(
ATRACE_CALL();
BQA_LOGV("releaseBufferCallback %s", id.to_string().c_str());
- if (CC_UNLIKELY(atrace_is_tag_enabled(ATRACE_TAG_GRAPHICS))) {
- if (!mFenceMonitor) {
- std::string monitorName = "release :";
- monitorName.append(mName.c_str());
- mFenceMonitor.emplace(monitorName.c_str());
- }
-
- mFenceMonitor->queueFence(releaseFence);
- }
-
// Calculate how many buffers we need to hold before we release them back
// to the buffer queue. This will prevent higher latency when we are running
// on a lower refresh rate than the max supported. We only do that for EGL
@@ -1135,6 +1124,17 @@ public:
AsyncWorker::getInstance().post(
[listener = mListener, slots = slots]() { listener->onBuffersDiscarded(slots); });
}
+
+ void onBufferDetached(int slot) override {
+ AsyncWorker::getInstance().post(
+ [listener = mListener, slot = slot]() { listener->onBufferDetached(slot); });
+ }
+
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_CONSUMER_ATTACH_CALLBACK)
+ void onBufferAttached() override {
+ AsyncWorker::getInstance().post([listener = mListener]() { listener->onBufferAttached(); });
+ }
+#endif
};
// Extends the BufferQueueProducer to create a wrapper around the listener so the listener calls
diff --git a/libs/gui/FenceMonitor.cpp b/libs/gui/FenceMonitor.cpp
index e38f1a8ce6..230c81a0b3 100644
--- a/libs/gui/FenceMonitor.cpp
+++ b/libs/gui/FenceMonitor.cpp
@@ -25,18 +25,9 @@
namespace android::gui {
FenceMonitor::FenceMonitor(const char* name) : mName(name), mFencesQueued(0), mFencesSignaled(0) {
- mThread = std::thread(&FenceMonitor::loop, this);
-}
-
-FenceMonitor::~FenceMonitor() {
- {
- std::lock_guard<std::mutex> lock(mMutex);
- mStopped = true;
- mCondition.notify_one();
- }
- if (mThread.joinable()) {
- mThread.join();
- }
+ std::thread thread(&FenceMonitor::loop, this);
+ pthread_setname_np(thread.native_handle(), mName);
+ thread.detach();
}
void FenceMonitor::queueFence(const sp<Fence>& fence) {
@@ -44,26 +35,24 @@ void FenceMonitor::queueFence(const sp<Fence>& fence) {
std::lock_guard<std::mutex> lock(mMutex);
if (fence->getSignalTime() != Fence::SIGNAL_TIME_PENDING) {
- snprintf(message, sizeof(message), "%s fence %u has signaled", mName.c_str(),
- mFencesQueued);
+ snprintf(message, sizeof(message), "%s fence %u has signaled", mName, mFencesQueued);
ATRACE_NAME(message);
// Need an increment on both to make the trace number correct.
mFencesQueued++;
mFencesSignaled++;
return;
}
- snprintf(message, sizeof(message), "Trace %s fence %u", mName.c_str(), mFencesQueued);
+ snprintf(message, sizeof(message), "Trace %s fence %u", mName, mFencesQueued);
ATRACE_NAME(message);
mQueue.push_back(fence);
mCondition.notify_one();
mFencesQueued++;
- ATRACE_INT(mName.c_str(), int32_t(mQueue.size()));
+ ATRACE_INT(mName, int32_t(mQueue.size()));
}
void FenceMonitor::loop() {
- pthread_setname_np(pthread_self(), mName.c_str());
- while (!mStopped) {
+ while (true) {
threadLoop();
}
}
@@ -73,18 +62,15 @@ void FenceMonitor::threadLoop() {
uint32_t fenceNum;
{
std::unique_lock<std::mutex> lock(mMutex);
- while (mQueue.empty() && !mStopped) {
+ while (mQueue.empty()) {
mCondition.wait(lock);
}
- if (mStopped) {
- return;
- }
fence = mQueue[0];
fenceNum = mFencesSignaled;
}
{
char message[64];
- snprintf(message, sizeof(message), "waiting for %s %u", mName.c_str(), fenceNum);
+ snprintf(message, sizeof(message), "waiting for %s %u", mName, fenceNum);
ATRACE_NAME(message);
status_t result = fence->waitForever(message);
@@ -96,8 +82,8 @@ void FenceMonitor::threadLoop() {
std::lock_guard<std::mutex> lock(mMutex);
mQueue.pop_front();
mFencesSignaled++;
- ATRACE_INT(mName.c_str(), int32_t(mQueue.size()));
+ ATRACE_INT(mName, int32_t(mQueue.size()));
}
}
-} // namespace android::gui
+} // namespace android::gui \ No newline at end of file
diff --git a/libs/gui/IProducerListener.cpp b/libs/gui/IProducerListener.cpp
index 7700795e1d..8b9b090496 100644
--- a/libs/gui/IProducerListener.cpp
+++ b/libs/gui/IProducerListener.cpp
@@ -184,4 +184,10 @@ bool BnProducerListener::needsReleaseNotify() {
void BnProducerListener::onBuffersDiscarded(const std::vector<int32_t>& /*discardedSlots*/) {
}
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_CONSUMER_ATTACH_CALLBACK)
+bool BnProducerListener::needsAttachNotify() {
+ return true;
+}
+#endif
+
} // namespace android
diff --git a/libs/gui/SurfaceControl.cpp b/libs/gui/SurfaceControl.cpp
index c5f9c38ca3..f126c0be2f 100644
--- a/libs/gui/SurfaceControl.cpp
+++ b/libs/gui/SurfaceControl.cpp
@@ -139,9 +139,9 @@ sp<Surface> SurfaceControl::generateSurfaceLocked()
uint32_t ignore;
auto flags = mCreateFlags & (ISurfaceComposerClient::eCursorWindow |
ISurfaceComposerClient::eOpaque);
- mBbqChild = mClient->createSurface(String8("bbq-wrapper"), 0, 0, mFormat,
+ mBbqChild = mClient->createSurface(String8::format("[BBQ] %s", mName.c_str()), 0, 0, mFormat,
flags, mHandle, {}, &ignore);
- mBbq = sp<BLASTBufferQueue>::make("bbq-adapter", mBbqChild, mWidth, mHeight, mFormat);
+ mBbq = sp<BLASTBufferQueue>::make("[BBQ]" + mName, mBbqChild, mWidth, mHeight, mFormat);
// This surface is always consumed by SurfaceFlinger, so the
// producerControlledByApp value doesn't matter; using false.
diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h
index ba58a15e17..8592cffd15 100644
--- a/libs/gui/include/gui/BLASTBufferQueue.h
+++ b/libs/gui/include/gui/BLASTBufferQueue.h
@@ -20,7 +20,6 @@
#include <com_android_graphics_libgui_flags.h>
#include <gui/BufferItem.h>
#include <gui/BufferItemConsumer.h>
-#include <gui/FenceMonitor.h>
#include <gui/IGraphicBufferConsumer.h>
#include <gui/IGraphicBufferProducer.h>
#include <gui/SurfaceComposerClient.h>
@@ -317,8 +316,6 @@ private:
std::unordered_set<uint64_t> mSyncedFrameNumbers GUARDED_BY(mMutex);
- std::optional<gui::FenceMonitor> mFenceMonitor GUARDED_BY(mMutex);
-
#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL)
class BufferReleaseReader {
public:
diff --git a/libs/gui/include/gui/FenceMonitor.h b/libs/gui/include/gui/FenceMonitor.h
index ac5cc0a574..62ceddee5f 100644
--- a/libs/gui/include/gui/FenceMonitor.h
+++ b/libs/gui/include/gui/FenceMonitor.h
@@ -19,7 +19,6 @@
#include <cstdint>
#include <deque>
#include <mutex>
-#include <thread>
#include <ui/Fence.h>
@@ -29,20 +28,17 @@ class FenceMonitor {
public:
explicit FenceMonitor(const char* name);
void queueFence(const sp<Fence>& fence);
- ~FenceMonitor();
private:
void loop();
void threadLoop();
- std::string mName;
+ const char* mName;
uint32_t mFencesQueued;
uint32_t mFencesSignaled;
std::deque<sp<Fence>> mQueue;
std::condition_variable mCondition;
std::mutex mMutex;
- std::thread mThread;
- std::atomic_bool mStopped = false;
};
-} // namespace android::gui
+} // namespace android::gui \ No newline at end of file
diff --git a/include/input/LooperInterface.h b/libs/gui/include/gui/Flags.h
index 2d6719c965..735375a1e7 100644
--- a/include/input/LooperInterface.h
+++ b/libs/gui/include/gui/Flags.h
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,24 +16,9 @@
#pragma once
-#include <utils/Looper.h>
-#include <utils/StrongPointer.h>
+#include <com_android_graphics_libgui_flags.h>
-namespace android {
-
-/**
- * LooperInterface allows the use of TestLooper in InputConsumerNoResampling without reassigning to
- * Looper. LooperInterface is needed to control how InputConsumerNoResampling consumes and batches
- * InputMessages.
- */
-class LooperInterface {
-public:
- virtual ~LooperInterface() = default;
-
- virtual int addFd(int fd, int ident, int events, const sp<LooperCallback>& callback,
- void* data) = 0;
- virtual int removeFd(int fd) = 0;
-
- virtual sp<Looper> getLooper() const = 0;
-};
-} // namespace android
+#define WB_CAMERA3_AND_PROCESSORS_WITH_DEPENDENCIES \
+ (COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CAMERA3_AND_PROCESSORS) && \
+ COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ) && \
+ COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS)) \ No newline at end of file
diff --git a/libs/gui/include/gui/IProducerListener.h b/libs/gui/include/gui/IProducerListener.h
index 3dcc6b6670..43bf6a7d4b 100644
--- a/libs/gui/include/gui/IProducerListener.h
+++ b/libs/gui/include/gui/IProducerListener.h
@@ -90,6 +90,9 @@ public:
Parcel* reply, uint32_t flags = 0);
virtual bool needsReleaseNotify();
virtual void onBuffersDiscarded(const std::vector<int32_t>& slots);
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_CONSUMER_ATTACH_CALLBACK)
+ virtual bool needsAttachNotify();
+#endif
};
#else
@@ -103,6 +106,9 @@ public:
virtual ~StubProducerListener();
virtual void onBufferReleased() {}
virtual bool needsReleaseNotify() { return false; }
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_CONSUMER_ATTACH_CALLBACK)
+ virtual bool needsAttachNotify() { return false; }
+#endif
};
} // namespace android
diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h
index e74f9ad1dc..14a351316d 100644
--- a/libs/gui/include/gui/Surface.h
+++ b/libs/gui/include/gui/Surface.h
@@ -34,8 +34,6 @@
#include <shared_mutex>
#include <unordered_set>
-#include <com_android_graphics_libgui_flags.h>
-
namespace android {
class GraphicBuffer;
diff --git a/libs/input/InputConsumerNoResampling.cpp b/libs/input/InputConsumerNoResampling.cpp
index de55828a39..ce8bb43a76 100644
--- a/libs/input/InputConsumerNoResampling.cpp
+++ b/libs/input/InputConsumerNoResampling.cpp
@@ -17,8 +17,6 @@
#define LOG_TAG "InputConsumerNoResampling"
#define ATRACE_TAG ATRACE_TAG_INPUT
-#include <chrono>
-
#include <inttypes.h>
#include <android-base/logging.h>
@@ -39,6 +37,8 @@ namespace {
using std::chrono::nanoseconds;
+using android::base::Result;
+
/**
* Log debug messages relating to the consumer end of the transport channel.
* Enable this via "adb shell setprop log.tag.InputTransportConsumer DEBUG" (requires restart)
@@ -46,27 +46,6 @@ using std::chrono::nanoseconds;
const bool DEBUG_TRANSPORT_CONSUMER =
__android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG "Consumer", ANDROID_LOG_INFO);
-/**
- * RealLooper is a wrapper of Looper. All the member functions exclusively call the internal looper.
- * This class' behavior is the same as Looper.
- */
-class RealLooper final : public LooperInterface {
-public:
- RealLooper(sp<Looper> looper) : mLooper{looper} {}
-
- int addFd(int fd, int ident, int events, const sp<LooperCallback>& callback,
- void* data) override {
- return mLooper->addFd(fd, ident, events, callback, data);
- }
-
- int removeFd(int fd) override { return mLooper->removeFd(fd); }
-
- sp<Looper> getLooper() const override { return mLooper; }
-
-private:
- sp<Looper> mLooper;
-};
-
std::unique_ptr<KeyEvent> createKeyEvent(const InputMessage& msg) {
std::unique_ptr<KeyEvent> event = std::make_unique<KeyEvent>();
event->initialize(msg.body.key.eventId, msg.body.key.deviceId, msg.body.key.source,
@@ -190,24 +169,18 @@ InputMessage createTimelineMessage(int32_t inputEventId, nsecs_t gpuCompletedTim
msg.body.timeline.graphicsTimeline[GraphicsTimeline::PRESENT_TIME] = presentTime;
return msg;
}
-
-bool isPointerEvent(const MotionEvent& motionEvent) {
- return (motionEvent.getSource() & AINPUT_SOURCE_CLASS_POINTER) == AINPUT_SOURCE_CLASS_POINTER;
-}
} // namespace
-using android::base::Result;
-
// --- InputConsumerNoResampling ---
-InputConsumerNoResampling::InputConsumerNoResampling(const std::shared_ptr<InputChannel>& channel,
- std::shared_ptr<LooperInterface> looper,
- InputConsumerCallbacks& callbacks,
- std::unique_ptr<Resampler> resampler)
+InputConsumerNoResampling::InputConsumerNoResampling(
+ const std::shared_ptr<InputChannel>& channel, sp<Looper> looper,
+ InputConsumerCallbacks& callbacks,
+ std::function<std::unique_ptr<Resampler>()> resamplerCreator)
: mChannel{channel},
mLooper{looper},
- mCallbacks(callbacks),
- mResampler{std::move(resampler)},
+ mCallbacks{callbacks},
+ mResamplerCreator{std::move(resamplerCreator)},
mFdEvents(0) {
LOG_ALWAYS_FATAL_IF(mLooper == nullptr);
mCallback = sp<LooperEventCallback>::make(
@@ -218,16 +191,9 @@ InputConsumerNoResampling::InputConsumerNoResampling(const std::shared_ptr<Input
setFdEvents(ALOOPER_EVENT_INPUT);
}
-InputConsumerNoResampling::InputConsumerNoResampling(const std::shared_ptr<InputChannel>& channel,
- sp<Looper> looper,
- InputConsumerCallbacks& callbacks,
- std::unique_ptr<Resampler> resampler)
- : InputConsumerNoResampling(channel, std::make_shared<RealLooper>(looper), callbacks,
- std::move(resampler)) {}
-
InputConsumerNoResampling::~InputConsumerNoResampling() {
ensureCalledOnLooperThread(__func__);
- consumeBatchedInputEvents(std::nullopt);
+ consumeBatchedInputEvents(/*requestedFrameTime=*/std::nullopt);
while (!mOutboundQueue.empty()) {
processOutboundEvents();
// This is our last chance to ack the events. If we don't ack them here, we will get an ANR,
@@ -253,8 +219,7 @@ int InputConsumerNoResampling::handleReceiveCallback(int events) {
int handledEvents = 0;
if (events & ALOOPER_EVENT_INPUT) {
- std::vector<InputMessage> messages = readAllMessages();
- handleMessages(std::move(messages));
+ handleMessages(readAllMessages());
handledEvents |= ALOOPER_EVENT_INPUT;
}
@@ -348,7 +313,6 @@ void InputConsumerNoResampling::setFdEvents(int events) {
}
void InputConsumerNoResampling::handleMessages(std::vector<InputMessage>&& messages) {
- // TODO(b/297226446) : add resampling
for (const InputMessage& msg : messages) {
if (msg.header.type == InputMessage::Type::MOTION) {
const int32_t action = msg.body.motion.action;
@@ -358,14 +322,31 @@ void InputConsumerNoResampling::handleMessages(std::vector<InputMessage>&& messa
action == AMOTION_EVENT_ACTION_HOVER_MOVE) &&
(isFromSource(source, AINPUT_SOURCE_CLASS_POINTER) ||
isFromSource(source, AINPUT_SOURCE_CLASS_JOYSTICK));
+
+ const bool canResample = (mResamplerCreator != nullptr) &&
+ (isFromSource(source, AINPUT_SOURCE_CLASS_POINTER));
+ if (canResample) {
+ if (action == AMOTION_EVENT_ACTION_DOWN) {
+ if (std::unique_ptr<Resampler> resampler = mResamplerCreator();
+ resampler != nullptr) {
+ const auto [_, inserted] =
+ mResamplers.insert(std::pair(deviceId, std::move(resampler)));
+ LOG_IF(WARNING, !inserted) << deviceId << "already exists in mResamplers";
+ }
+ }
+ }
+
if (batchableEvent) {
// add it to batch
mBatches[deviceId].emplace(msg);
} else {
- // consume all pending batches for this event immediately
- // TODO(b/329776327): figure out if this could be smarter by limiting the
- // consumption only to the current device.
- consumeBatchedInputEvents(std::nullopt);
+ // consume all pending batches for this device immediately
+ consumeBatchedInputEvents(deviceId, /*requestedFrameTime=*/std::nullopt);
+ if (canResample &&
+ (action == AMOTION_EVENT_ACTION_UP || action == AMOTION_EVENT_ACTION_CANCEL)) {
+ LOG_IF(INFO, mResamplers.erase(deviceId) == 0)
+ << deviceId << "does not exist in mResamplers";
+ }
handleMessage(msg);
}
} else {
@@ -483,13 +464,18 @@ void InputConsumerNoResampling::handleMessage(const InputMessage& msg) const {
}
std::pair<std::unique_ptr<MotionEvent>, std::optional<uint32_t>>
-InputConsumerNoResampling::createBatchedMotionEvent(const nsecs_t frameTime,
+InputConsumerNoResampling::createBatchedMotionEvent(const nsecs_t requestedFrameTime,
std::queue<InputMessage>& messages) {
std::unique_ptr<MotionEvent> motionEvent;
std::optional<uint32_t> firstSeqForBatch;
- const nanoseconds resampleLatency =
- (mResampler != nullptr) ? mResampler->getResampleLatency() : nanoseconds{0};
- const nanoseconds adjustedFrameTime = nanoseconds{frameTime} - resampleLatency;
+
+ LOG_IF(FATAL, messages.empty()) << "messages queue is empty!";
+ const DeviceId deviceId = messages.front().body.motion.deviceId;
+ const auto resampler = mResamplers.find(deviceId);
+ const nanoseconds resampleLatency = (resampler != mResamplers.cend())
+ ? resampler->second->getResampleLatency()
+ : nanoseconds{0};
+ const nanoseconds adjustedFrameTime = nanoseconds{requestedFrameTime} - resampleLatency;
while (!messages.empty() &&
(messages.front().body.motion.eventTime <= adjustedFrameTime.count())) {
@@ -505,45 +491,63 @@ InputConsumerNoResampling::createBatchedMotionEvent(const nsecs_t frameTime,
}
messages.pop();
}
+
// Check if resampling should be performed.
- if (motionEvent != nullptr && isPointerEvent(*motionEvent) && mResampler != nullptr) {
- InputMessage* futureSample = nullptr;
- if (!messages.empty()) {
- futureSample = &messages.front();
- }
- mResampler->resampleMotionEvent(nanoseconds{frameTime}, *motionEvent, futureSample);
+ InputMessage* futureSample = nullptr;
+ if (!messages.empty()) {
+ futureSample = &messages.front();
+ }
+ if ((motionEvent != nullptr) && (resampler != mResamplers.cend())) {
+ resampler->second->resampleMotionEvent(nanoseconds{requestedFrameTime}, *motionEvent,
+ futureSample);
}
+
return std::make_pair(std::move(motionEvent), firstSeqForBatch);
}
bool InputConsumerNoResampling::consumeBatchedInputEvents(
- std::optional<nsecs_t> requestedFrameTime) {
+ std::optional<DeviceId> deviceId, std::optional<nsecs_t> requestedFrameTime) {
ensureCalledOnLooperThread(__func__);
// When batching is not enabled, we want to consume all events. That's equivalent to having an
- // infinite frameTime.
- const nsecs_t frameTime = requestedFrameTime.value_or(std::numeric_limits<nsecs_t>::max());
+ // infinite requestedFrameTime.
+ requestedFrameTime = requestedFrameTime.value_or(std::numeric_limits<nsecs_t>::max());
bool producedEvents = false;
- for (auto& [_, messages] : mBatches) {
- auto [motion, firstSeqForBatch] = createBatchedMotionEvent(frameTime, messages);
+
+ for (auto deviceIdIter = (deviceId.has_value()) ? (mBatches.find(*deviceId))
+ : (mBatches.begin());
+ deviceIdIter != mBatches.cend(); ++deviceIdIter) {
+ std::queue<InputMessage>& messages = deviceIdIter->second;
+ auto [motion, firstSeqForBatch] = createBatchedMotionEvent(*requestedFrameTime, messages);
if (motion != nullptr) {
LOG_ALWAYS_FATAL_IF(!firstSeqForBatch.has_value());
mCallbacks.onMotionEvent(std::move(motion), *firstSeqForBatch);
producedEvents = true;
} else {
- // This is OK, it just means that the frameTime is too old (all events that we have
- // pending are in the future of the frametime). Maybe print a
- // warning? If there are multiple devices active though, this might be normal and can
- // just be ignored, unless none of them resulted in any consumption (in that case, this
- // function would already return "false" so we could just leave it up to the caller).
+ // This is OK, it just means that the requestedFrameTime is too old (all events that we
+ // have pending are in the future of the requestedFrameTime). Maybe print a warning? If
+ // there are multiple devices active though, this might be normal and can just be
+ // ignored, unless none of them resulted in any consumption (in that case, this function
+ // would already return "false" so we could just leave it up to the caller).
+ }
+
+ if (deviceId.has_value()) {
+ // We already consumed events for this device. Break here to prevent iterating over the
+ // other devices.
+ break;
}
}
std::erase_if(mBatches, [](const auto& pair) { return pair.second.empty(); });
return producedEvents;
}
+bool InputConsumerNoResampling::consumeBatchedInputEvents(
+ std::optional<nsecs_t> requestedFrameTime) {
+ return consumeBatchedInputEvents(/*deviceId=*/std::nullopt, requestedFrameTime);
+}
+
void InputConsumerNoResampling::ensureCalledOnLooperThread(const char* func) const {
sp<Looper> callingThreadLooper = Looper::getForThread();
- if (callingThreadLooper != mLooper->getLooper()) {
+ if (callingThreadLooper != mLooper) {
LOG(FATAL) << "The function " << func << " can only be called on the looper thread";
}
}
diff --git a/libs/input/KeyCharacterMap.cpp b/libs/input/KeyCharacterMap.cpp
index 1cf5612d45..b0563abaf7 100644
--- a/libs/input/KeyCharacterMap.cpp
+++ b/libs/input/KeyCharacterMap.cpp
@@ -317,19 +317,8 @@ bool KeyCharacterMap::getEvents(int32_t deviceId, const char16_t* chars, size_t
return true;
}
-void KeyCharacterMap::addKeyRemapping(int32_t fromKeyCode, int32_t toKeyCode) {
- if (fromKeyCode == toKeyCode) {
- mKeyRemapping.erase(fromKeyCode);
-#if DEBUG_MAPPING
- ALOGD("addKeyRemapping: Cleared remapping forKeyCode=%d ~ Result Successful.", fromKeyCode);
-#endif
- return;
- }
- mKeyRemapping.insert_or_assign(fromKeyCode, toKeyCode);
-#if DEBUG_MAPPING
- ALOGD("addKeyRemapping: fromKeyCode=%d, toKeyCode=%d ~ Result Successful.", fromKeyCode,
- toKeyCode);
-#endif
+void KeyCharacterMap::setKeyRemapping(const std::map<int32_t, int32_t>& keyRemapping) {
+ mKeyRemapping = keyRemapping;
}
status_t KeyCharacterMap::mapKey(int32_t scanCode, int32_t usageCode, int32_t* outKeyCode) const {
diff --git a/libs/input/Resampler.cpp b/libs/input/Resampler.cpp
index 51fadf8ec1..328fa684f6 100644
--- a/libs/input/Resampler.cpp
+++ b/libs/input/Resampler.cpp
@@ -247,11 +247,6 @@ nanoseconds LegacyResampler::getResampleLatency() const {
void LegacyResampler::resampleMotionEvent(nanoseconds frameTime, MotionEvent& motionEvent,
const InputMessage* futureSample) {
- if (mPreviousDeviceId && *mPreviousDeviceId != motionEvent.getDeviceId()) {
- mLatestSamples.clear();
- }
- mPreviousDeviceId = motionEvent.getDeviceId();
-
const nanoseconds resampleTime = frameTime - RESAMPLE_LATENCY;
updateLatestSamples(motionEvent);
diff --git a/libs/input/android/os/IInputConstants.aidl b/libs/input/android/os/IInputConstants.aidl
index e23fc94c5e..31592cd6e3 100644
--- a/libs/input/android/os/IInputConstants.aidl
+++ b/libs/input/android/os/IInputConstants.aidl
@@ -49,6 +49,12 @@ interface IInputConstants
const int POLICY_FLAG_INJECTED_FROM_ACCESSIBILITY = 0x20000;
/**
+ * The key event triggered a key gesture. Used in policy flag to notify that a key gesture was
+ * triggered using the event.
+ */
+ const int POLICY_FLAG_KEY_GESTURE_TRIGGERED = 0x40000;
+
+ /**
* Common input event flag used for both motion and key events for a gesture or pointer being
* canceled.
*/
diff --git a/libs/input/tests/Android.bp b/libs/input/tests/Android.bp
index 3ec167a288..81c6175805 100644
--- a/libs/input/tests/Android.bp
+++ b/libs/input/tests/Android.bp
@@ -27,7 +27,6 @@ cc_test {
"Resampler_test.cpp",
"RingBuffer_test.cpp",
"TestInputChannel.cpp",
- "TestLooper.cpp",
"TfLiteMotionPredictor_test.cpp",
"TouchResampling_test.cpp",
"TouchVideoFrame_test.cpp",
diff --git a/libs/input/tests/InputConsumer_test.cpp b/libs/input/tests/InputConsumer_test.cpp
index 55be453287..cbb332ed7f 100644
--- a/libs/input/tests/InputConsumer_test.cpp
+++ b/libs/input/tests/InputConsumer_test.cpp
@@ -16,16 +16,22 @@
#include <input/InputConsumerNoResampling.h>
+#include <gtest/gtest.h>
+
+#include <chrono>
#include <memory>
#include <optional>
-#include <utility>
+#include <TestEventMatchers.h>
#include <TestInputChannel.h>
-#include <TestLooper.h>
#include <android-base/logging.h>
+#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <input/BlockingQueue.h>
+#include <input/Input.h>
#include <input/InputEventBuilders.h>
+#include <input/Resampler.h>
+#include <utils/Looper.h>
#include <utils/StrongPointer.h>
namespace android {
@@ -34,23 +40,57 @@ namespace {
using std::chrono::nanoseconds;
+using ::testing::AllOf;
+using ::testing::Matcher;
+
+struct Pointer {
+ int32_t id{0};
+ ToolType toolType{ToolType::FINGER};
+ float x{0.0f};
+ float y{0.0f};
+ bool isResampled{false};
+
+ PointerBuilder asPointerBuilder() const {
+ return PointerBuilder{id, toolType}.x(x).y(y).isResampled(isResampled);
+ }
+};
} // namespace
class InputConsumerTest : public testing::Test, public InputConsumerCallbacks {
protected:
InputConsumerTest()
: mClientTestChannel{std::make_shared<TestInputChannel>("TestChannel")},
- mTestLooper{std::make_shared<TestLooper>()} {
- Looper::setForThread(mTestLooper->getLooper());
- mConsumer =
- std::make_unique<InputConsumerNoResampling>(mClientTestChannel, mTestLooper, *this,
- std::make_unique<LegacyResampler>());
+ mLooper{sp<Looper>::make(/*allowNonCallbacks=*/false)} {
+ Looper::setForThread(mLooper);
+ mConsumer = std::make_unique<
+ InputConsumerNoResampling>(mClientTestChannel, mLooper, *this,
+ []() { return std::make_unique<LegacyResampler>(); });
+ }
+
+ void invokeLooperCallback() const {
+ sp<LooperCallback> callback;
+ ASSERT_TRUE(mLooper->getFdStateDebug(mClientTestChannel->getFd(), /*ident=*/nullptr,
+ /*events=*/nullptr, &callback, /*data=*/nullptr));
+ callback->handleEvent(mClientTestChannel->getFd(), ALOOPER_EVENT_INPUT, /*data=*/nullptr);
+ }
+
+ void assertOnBatchedInputEventPendingWasCalled() {
+ ASSERT_GT(mOnBatchedInputEventPendingInvocationCount, 0UL)
+ << "onBatchedInputEventPending has not been called.";
+ --mOnBatchedInputEventPendingInvocationCount;
+ }
+
+ void assertReceivedMotionEvent(const Matcher<MotionEvent>& matcher) {
+ std::unique_ptr<MotionEvent> motionEvent = mMotionEvents.pop();
+ ASSERT_NE(motionEvent, nullptr);
+ EXPECT_THAT(*motionEvent, matcher);
}
- void assertOnBatchedInputEventPendingWasCalled();
+ InputMessage nextPointerMessage(std::chrono::nanoseconds eventTime, DeviceId deviceId,
+ int32_t action, const Pointer& pointer);
std::shared_ptr<TestInputChannel> mClientTestChannel;
- std::shared_ptr<TestLooper> mTestLooper;
+ sp<Looper> mLooper;
std::unique_ptr<InputConsumerNoResampling> mConsumer;
BlockingQueue<std::unique_ptr<KeyEvent>> mKeyEvents;
@@ -61,6 +101,7 @@ protected:
BlockingQueue<std::unique_ptr<TouchModeEvent>> mTouchModeEvents;
private:
+ uint32_t mLastSeq{0};
size_t mOnBatchedInputEventPendingInvocationCount{0};
// InputConsumerCallbacks interface
@@ -96,10 +137,17 @@ private:
};
};
-void InputConsumerTest::assertOnBatchedInputEventPendingWasCalled() {
- ASSERT_GT(mOnBatchedInputEventPendingInvocationCount, 0UL)
- << "onBatchedInputEventPending has not been called.";
- --mOnBatchedInputEventPendingInvocationCount;
+InputMessage InputConsumerTest::nextPointerMessage(std::chrono::nanoseconds eventTime,
+ DeviceId deviceId, int32_t action,
+ const Pointer& pointer) {
+ ++mLastSeq;
+ return InputMessageBuilder{InputMessage::Type::MOTION, mLastSeq}
+ .eventTime(eventTime.count())
+ .deviceId(deviceId)
+ .source(AINPUT_SOURCE_TOUCHSCREEN)
+ .action(action)
+ .pointer(pointer.asPointerBuilder())
+ .build();
}
TEST_F(InputConsumerTest, MessageStreamBatchedInMotionEvent) {
@@ -118,11 +166,11 @@ TEST_F(InputConsumerTest, MessageStreamBatchedInMotionEvent) {
mClientTestChannel->assertNoSentMessages();
- mTestLooper->invokeCallback(mClientTestChannel->getFd(), ALOOPER_EVENT_INPUT);
+ invokeLooperCallback();
assertOnBatchedInputEventPendingWasCalled();
- mConsumer->consumeBatchedInputEvents(std::nullopt);
+ mConsumer->consumeBatchedInputEvents(/*frameTime=*/std::nullopt);
std::unique_ptr<MotionEvent> downMotionEvent = mMotionEvents.pop();
ASSERT_NE(downMotionEvent, nullptr);
@@ -156,7 +204,7 @@ TEST_F(InputConsumerTest, LastBatchedSampleIsLessThanResampleTime) {
mClientTestChannel->assertNoSentMessages();
- mTestLooper->invokeCallback(mClientTestChannel->getFd(), ALOOPER_EVENT_INPUT);
+ invokeLooperCallback();
assertOnBatchedInputEventPendingWasCalled();
@@ -182,4 +230,166 @@ TEST_F(InputConsumerTest, LastBatchedSampleIsLessThanResampleTime) {
mClientTestChannel->assertFinishMessage(/*seq=*/2, true);
mClientTestChannel->assertFinishMessage(/*seq=*/3, true);
}
+
+TEST_F(InputConsumerTest, BatchedEventsMultiDeviceConsumption) {
+ mClientTestChannel->enqueueMessage(InputMessageBuilder{InputMessage::Type::MOTION, /*seq=*/0}
+ .deviceId(0)
+ .action(AMOTION_EVENT_ACTION_DOWN)
+ .build());
+
+ invokeLooperCallback();
+ assertReceivedMotionEvent(AllOf(WithDeviceId(0), WithMotionAction(AMOTION_EVENT_ACTION_DOWN)));
+
+ mClientTestChannel->enqueueMessage(InputMessageBuilder{InputMessage::Type::MOTION, /*seq=*/1}
+ .deviceId(0)
+ .action(AMOTION_EVENT_ACTION_MOVE)
+ .build());
+ mClientTestChannel->enqueueMessage(InputMessageBuilder{InputMessage::Type::MOTION, /*seq=*/2}
+ .deviceId(0)
+ .action(AMOTION_EVENT_ACTION_MOVE)
+ .build());
+ mClientTestChannel->enqueueMessage(InputMessageBuilder{InputMessage::Type::MOTION, /*seq=*/3}
+ .deviceId(0)
+ .action(AMOTION_EVENT_ACTION_MOVE)
+ .build());
+
+ mClientTestChannel->enqueueMessage(InputMessageBuilder{InputMessage::Type::MOTION, /*seq=*/4}
+ .deviceId(1)
+ .action(AMOTION_EVENT_ACTION_DOWN)
+ .build());
+
+ invokeLooperCallback();
+ assertReceivedMotionEvent(AllOf(WithDeviceId(1), WithMotionAction(AMOTION_EVENT_ACTION_DOWN)));
+
+ mClientTestChannel->enqueueMessage(InputMessageBuilder{InputMessage::Type::MOTION, /*seq=*/5}
+ .deviceId(0)
+ .action(AMOTION_EVENT_ACTION_UP)
+ .build());
+
+ invokeLooperCallback();
+ assertReceivedMotionEvent(AllOf(WithDeviceId(0), WithMotionAction(AMOTION_EVENT_ACTION_MOVE)));
+
+ mClientTestChannel->assertFinishMessage(/*seq=*/0, /*handled=*/true);
+ mClientTestChannel->assertFinishMessage(/*seq=*/4, /*handled=*/true);
+ mClientTestChannel->assertFinishMessage(/*seq=*/1, /*handled=*/true);
+ mClientTestChannel->assertFinishMessage(/*seq=*/2, /*handled=*/true);
+ mClientTestChannel->assertFinishMessage(/*seq=*/3, /*handled=*/true);
+}
+
+/**
+ * The test supposes a 60Hz Vsync rate and a 200Hz input rate. The InputMessages are intertwined as
+ * in a real use cases. The test's two devices should be resampled independently. Moreover, the
+ * InputMessage stream layout for the test is:
+ *
+ * DOWN(0, 0ms)
+ * MOVE(0, 5ms)
+ * MOVE(0, 10ms)
+ * DOWN(1, 15ms)
+ *
+ * CONSUME(16ms)
+ *
+ * MOVE(1, 20ms)
+ * MOVE(1, 25ms)
+ * MOVE(0, 30ms)
+ *
+ * CONSUME(32ms)
+ *
+ * MOVE(0, 35ms)
+ * UP(1, 40ms)
+ * UP(0, 45ms)
+ *
+ * CONSUME(48ms)
+ *
+ * The first field is device ID, and the second field is event time.
+ */
+TEST_F(InputConsumerTest, MultiDeviceResampling) {
+ mClientTestChannel->enqueueMessage(nextPointerMessage(0ms, /*deviceId=*/0,
+ AMOTION_EVENT_ACTION_DOWN,
+ Pointer{.x = 0, .y = 0}));
+
+ mClientTestChannel->assertNoSentMessages();
+
+ invokeLooperCallback();
+ assertReceivedMotionEvent(AllOf(WithDeviceId(0), WithMotionAction(AMOTION_EVENT_ACTION_DOWN),
+ WithSampleCount(1)));
+
+ mClientTestChannel->enqueueMessage(nextPointerMessage(5ms, /*deviceId=*/0,
+ AMOTION_EVENT_ACTION_MOVE,
+ Pointer{.x = 1.0f, .y = 2.0f}));
+ mClientTestChannel->enqueueMessage(nextPointerMessage(10ms, /*deviceId=*/0,
+ AMOTION_EVENT_ACTION_MOVE,
+ Pointer{.x = 2.0f, .y = 4.0f}));
+ mClientTestChannel->enqueueMessage(nextPointerMessage(15ms, /*deviceId=*/1,
+ AMOTION_EVENT_ACTION_DOWN,
+ Pointer{.x = 10.0f, .y = 10.0f}));
+
+ invokeLooperCallback();
+ mConsumer->consumeBatchedInputEvents(16'000'000 /*ns*/);
+
+ assertReceivedMotionEvent(AllOf(WithDeviceId(1), WithMotionAction(AMOTION_EVENT_ACTION_DOWN),
+ WithSampleCount(1)));
+ assertReceivedMotionEvent(
+ AllOf(WithDeviceId(0), WithMotionAction(AMOTION_EVENT_ACTION_MOVE), WithSampleCount(3),
+ WithSample(/*sampleIndex=*/2,
+ Sample{11ms,
+ {PointerArgs{.x = 2.2f, .y = 4.4f, .isResampled = true}}})));
+
+ mClientTestChannel->enqueueMessage(nextPointerMessage(20ms, /*deviceId=*/1,
+ AMOTION_EVENT_ACTION_MOVE,
+ Pointer{.x = 11.0f, .y = 12.0f}));
+ mClientTestChannel->enqueueMessage(nextPointerMessage(25ms, /*deviceId=*/1,
+ AMOTION_EVENT_ACTION_MOVE,
+ Pointer{.x = 12.0f, .y = 14.0f}));
+ mClientTestChannel->enqueueMessage(nextPointerMessage(30ms, /*deviceId=*/0,
+ AMOTION_EVENT_ACTION_MOVE,
+ Pointer{.x = 5.0f, .y = 6.0f}));
+
+ invokeLooperCallback();
+ assertOnBatchedInputEventPendingWasCalled();
+ mConsumer->consumeBatchedInputEvents(32'000'000 /*ns*/);
+
+ assertReceivedMotionEvent(
+ AllOf(WithDeviceId(1), WithMotionAction(AMOTION_EVENT_ACTION_MOVE), WithSampleCount(3),
+ WithSample(/*sampleIndex=*/2,
+ Sample{27ms,
+ {PointerArgs{.x = 12.4f, .y = 14.8f, .isResampled = true}}})));
+
+ mClientTestChannel->enqueueMessage(nextPointerMessage(35ms, /*deviceId=*/0,
+ AMOTION_EVENT_ACTION_MOVE,
+ Pointer{.x = 8.0f, .y = 9.0f}));
+ mClientTestChannel->enqueueMessage(nextPointerMessage(40ms, /*deviceId=*/1,
+ AMOTION_EVENT_ACTION_UP,
+ Pointer{.x = 12.0f, .y = 14.0f}));
+ mClientTestChannel->enqueueMessage(nextPointerMessage(45ms, /*deviceId=*/0,
+ AMOTION_EVENT_ACTION_UP,
+ Pointer{.x = 8.0f, .y = 9.0f}));
+
+ invokeLooperCallback();
+ mConsumer->consumeBatchedInputEvents(48'000'000 /*ns*/);
+
+ assertReceivedMotionEvent(
+ AllOf(WithDeviceId(1), WithMotionAction(AMOTION_EVENT_ACTION_UP), WithSampleCount(1)));
+
+ assertReceivedMotionEvent(
+ AllOf(WithDeviceId(0), WithMotionAction(AMOTION_EVENT_ACTION_MOVE), WithSampleCount(3),
+ WithSample(/*sampleIndex=*/2,
+ Sample{37'500'000ns,
+ {PointerArgs{.x = 9.5f, .y = 10.5f, .isResampled = true}}})));
+
+ assertReceivedMotionEvent(
+ AllOf(WithDeviceId(0), WithMotionAction(AMOTION_EVENT_ACTION_UP), WithSampleCount(1)));
+
+ // The sequence order is based on the expected consumption. Each sequence number corresponds to
+ // one of the previously enqueued messages.
+ mClientTestChannel->assertFinishMessage(/*seq=*/1, /*handled=*/true);
+ mClientTestChannel->assertFinishMessage(/*seq=*/4, /*handled=*/true);
+ mClientTestChannel->assertFinishMessage(/*seq=*/2, /*handled=*/true);
+ mClientTestChannel->assertFinishMessage(/*seq=*/3, /*handled=*/true);
+ mClientTestChannel->assertFinishMessage(/*seq=*/5, /*handled=*/true);
+ mClientTestChannel->assertFinishMessage(/*seq=*/6, /*handled=*/true);
+ mClientTestChannel->assertFinishMessage(/*seq=*/9, /*handled=*/true);
+ mClientTestChannel->assertFinishMessage(/*seq=*/7, /*handled=*/true);
+ mClientTestChannel->assertFinishMessage(/*seq=*/8, /*handled=*/true);
+ mClientTestChannel->assertFinishMessage(/*seq=*/10, /*handled=*/true);
+}
} // namespace android
diff --git a/libs/input/tests/InputPublisherAndConsumerNoResampling_test.cpp b/libs/input/tests/InputPublisherAndConsumerNoResampling_test.cpp
index 467c3b46ce..1210f711de 100644
--- a/libs/input/tests/InputPublisherAndConsumerNoResampling_test.cpp
+++ b/libs/input/tests/InputPublisherAndConsumerNoResampling_test.cpp
@@ -364,7 +364,7 @@ private:
if (!mConsumer->probablyHasInput()) {
ADD_FAILURE() << "should deterministically have input because there is a batch";
}
- mConsumer->consumeBatchedInputEvents(std::nullopt);
+ mConsumer->consumeBatchedInputEvents(/*frameTime=*/std::nullopt);
};
void onFocusEvent(std::unique_ptr<FocusEvent> event, uint32_t seq) override {
mFocusEvents.push(std::move(event));
diff --git a/libs/input/tests/Resampler_test.cpp b/libs/input/tests/Resampler_test.cpp
index 26dee393c1..fae8518e87 100644
--- a/libs/input/tests/Resampler_test.cpp
+++ b/libs/input/tests/Resampler_test.cpp
@@ -87,7 +87,6 @@ InputSample::operator InputMessage() const {
struct InputStream {
std::vector<InputSample> samples{};
int32_t action{0};
- DeviceId deviceId{0};
/**
* Converts from InputStream to MotionEvent. Enables calling LegacyResampler methods only with
* the relevant data for tests.
@@ -100,8 +99,8 @@ InputStream::operator MotionEvent() const {
MotionEventBuilder motionEventBuilder =
MotionEventBuilder(action, AINPUT_SOURCE_CLASS_POINTER)
.downTime(0)
- .eventTime(static_cast<std::chrono::nanoseconds>(firstSample.eventTime).count())
- .deviceId(deviceId);
+ .eventTime(
+ static_cast<std::chrono::nanoseconds>(firstSample.eventTime).count());
for (const Pointer& pointer : firstSample.pointers) {
const PointerBuilder pointerBuilder =
PointerBuilder(pointer.id, pointer.toolType).x(pointer.x).y(pointer.y);
@@ -289,28 +288,6 @@ TEST_F(ResamplerTest, SinglePointerNotEnoughDataToResample) {
assertMotionEventIsNotResampled(originalMotionEvent, motionEvent);
}
-TEST_F(ResamplerTest, SinglePointerDifferentDeviceIdBetweenMotionEvents) {
- MotionEvent motionFromFirstDevice =
- InputStream{{InputSample{4ms, {{.id = 0, .x = 1.0f, .y = 1.0f, .isResampled = false}}},
- InputSample{8ms, {{.id = 0, .x = 2.0f, .y = 2.0f, .isResampled = false}}}},
- AMOTION_EVENT_ACTION_MOVE,
- .deviceId = 0};
-
- mResampler->resampleMotionEvent(10ms, motionFromFirstDevice, nullptr);
-
- MotionEvent motionFromSecondDevice =
- InputStream{{InputSample{11ms,
- {{.id = 0, .x = 3.0f, .y = 3.0f, .isResampled = false}}}},
- AMOTION_EVENT_ACTION_MOVE,
- .deviceId = 1};
- const MotionEvent originalMotionEvent = motionFromSecondDevice;
-
- mResampler->resampleMotionEvent(12ms, motionFromSecondDevice, nullptr);
- // The MotionEvent should not be resampled because the second event came from a different device
- // than the previous event.
- assertMotionEventIsNotResampled(originalMotionEvent, motionFromSecondDevice);
-}
-
TEST_F(ResamplerTest, SinglePointerSingleSampleInterpolation) {
MotionEvent motionEvent =
InputStream{{InputSample{10ms,
diff --git a/libs/input/tests/TestEventMatchers.h b/libs/input/tests/TestEventMatchers.h
new file mode 100644
index 0000000000..3589de599f
--- /dev/null
+++ b/libs/input/tests/TestEventMatchers.h
@@ -0,0 +1,187 @@
+/**
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <chrono>
+#include <ostream>
+#include <vector>
+
+#include <android-base/logging.h>
+#include <gtest/gtest.h>
+#include <input/Input.h>
+
+namespace android {
+
+namespace {
+
+using ::testing::Matcher;
+
+} // namespace
+
+/**
+ * This file contains a copy of Matchers from .../inputflinger/tests/TestEventMatchers.h. Ideally,
+ * implementations must not be duplicated.
+ * TODO(b/365606513): Find a way to share TestEventMatchers.h between inputflinger and libinput.
+ */
+
+struct PointerArgs {
+ float x{0.0f};
+ float y{0.0f};
+ bool isResampled{false};
+};
+
+struct Sample {
+ std::chrono::nanoseconds eventTime{0};
+ std::vector<PointerArgs> pointers{};
+};
+
+class WithDeviceIdMatcher {
+public:
+ using is_gtest_matcher = void;
+ explicit WithDeviceIdMatcher(DeviceId deviceId) : mDeviceId(deviceId) {}
+
+ bool MatchAndExplain(const InputEvent& event, std::ostream*) const {
+ return mDeviceId == event.getDeviceId();
+ }
+
+ void DescribeTo(std::ostream* os) const { *os << "with device id " << mDeviceId; }
+
+ void DescribeNegationTo(std::ostream* os) const { *os << "wrong device id"; }
+
+private:
+ const DeviceId mDeviceId;
+};
+
+inline WithDeviceIdMatcher WithDeviceId(int32_t deviceId) {
+ return WithDeviceIdMatcher(deviceId);
+}
+
+class WithMotionActionMatcher {
+public:
+ using is_gtest_matcher = void;
+ explicit WithMotionActionMatcher(int32_t action) : mAction(action) {}
+
+ bool MatchAndExplain(const MotionEvent& event, std::ostream*) const {
+ bool matches = mAction == event.getAction();
+ if (event.getAction() == AMOTION_EVENT_ACTION_CANCEL) {
+ matches &= (event.getFlags() & AMOTION_EVENT_FLAG_CANCELED) != 0;
+ }
+ return matches;
+ }
+
+ void DescribeTo(std::ostream* os) const {
+ *os << "with motion action " << MotionEvent::actionToString(mAction);
+ if (mAction == AMOTION_EVENT_ACTION_CANCEL) {
+ *os << " and FLAG_CANCELED";
+ }
+ }
+
+ void DescribeNegationTo(std::ostream* os) const { *os << "wrong action"; }
+
+private:
+ const int32_t mAction;
+};
+
+inline WithMotionActionMatcher WithMotionAction(int32_t action) {
+ return WithMotionActionMatcher(action);
+}
+
+class WithSampleCountMatcher {
+public:
+ using is_gtest_matcher = void;
+ explicit WithSampleCountMatcher(size_t sampleCount) : mExpectedSampleCount{sampleCount} {}
+
+ bool MatchAndExplain(const MotionEvent& motionEvent, std::ostream*) const {
+ return (motionEvent.getHistorySize() + 1) == mExpectedSampleCount;
+ }
+
+ void DescribeTo(std::ostream* os) const { *os << "sample count " << mExpectedSampleCount; }
+
+ void DescribeNegationTo(std::ostream* os) const { *os << "different sample count"; }
+
+private:
+ const size_t mExpectedSampleCount;
+};
+
+inline WithSampleCountMatcher WithSampleCount(size_t sampleCount) {
+ return WithSampleCountMatcher(sampleCount);
+}
+
+class WithSampleMatcher {
+public:
+ using is_gtest_matcher = void;
+ explicit WithSampleMatcher(size_t sampleIndex, const Sample& sample)
+ : mSampleIndex{sampleIndex}, mSample{sample} {}
+
+ bool MatchAndExplain(const MotionEvent& motionEvent, std::ostream* os) const {
+ if (motionEvent.getHistorySize() < mSampleIndex) {
+ *os << "sample index out of bounds";
+ return false;
+ }
+
+ if (motionEvent.getHistoricalEventTime(mSampleIndex) != mSample.eventTime.count()) {
+ *os << "event time mismatch. sample: "
+ << motionEvent.getHistoricalEventTime(mSampleIndex)
+ << " expected: " << mSample.eventTime.count();
+ return false;
+ }
+
+ if (motionEvent.getPointerCount() != mSample.pointers.size()) {
+ *os << "pointer count mismatch. sample: " << motionEvent.getPointerCount()
+ << " expected: " << mSample.pointers.size();
+ return false;
+ }
+
+ for (size_t pointerIndex = 0; pointerIndex < motionEvent.getPointerCount();
+ ++pointerIndex) {
+ const PointerCoords& pointerCoords =
+ *(motionEvent.getHistoricalRawPointerCoords(pointerIndex, mSampleIndex));
+ if ((pointerCoords.getX() != mSample.pointers[pointerIndex].x) ||
+ (pointerCoords.getY() != mSample.pointers[pointerIndex].y)) {
+ *os << "sample coordinates mismatch at pointer index " << pointerIndex
+ << ". sample: (" << pointerCoords.getX() << ", " << pointerCoords.getY()
+ << ") expected: (" << mSample.pointers[pointerIndex].x << ", "
+ << mSample.pointers[pointerIndex].y << ")";
+ return false;
+ }
+ if (motionEvent.isResampled(pointerIndex, mSampleIndex) !=
+ mSample.pointers[pointerIndex].isResampled) {
+ *os << "resampling flag mismatch. sample: "
+ << motionEvent.isResampled(pointerIndex, mSampleIndex)
+ << " expected: " << mSample.pointers[pointerIndex].isResampled;
+ return false;
+ }
+ }
+ return true;
+ }
+
+ void DescribeTo(std::ostream* os) const { *os << "motion event sample properties match."; }
+
+ void DescribeNegationTo(std::ostream* os) const {
+ *os << "motion event sample properties do not match expected properties.";
+ }
+
+private:
+ const size_t mSampleIndex;
+ const Sample mSample;
+};
+
+inline WithSampleMatcher WithSample(size_t sampleIndex, const Sample& sample) {
+ return WithSampleMatcher(sampleIndex, sample);
+}
+
+} // namespace android
diff --git a/libs/input/tests/TestInputChannel.cpp b/libs/input/tests/TestInputChannel.cpp
index d5f00b699b..26a0ca2106 100644
--- a/libs/input/tests/TestInputChannel.cpp
+++ b/libs/input/tests/TestInputChannel.cpp
@@ -19,6 +19,11 @@
#include <TestInputChannel.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include <array>
+
#include <android-base/logging.h>
#include <android-base/unique_fd.h>
#include <binder/IBinder.h>
@@ -27,13 +32,25 @@
namespace android {
namespace {
-constexpr int FAKE_FD{-1};
+
+/**
+ * Returns a stub file descriptor by opening a socket pair and closing one of the fds. The returned
+ * fd can be used to construct an InputChannel.
+ */
+base::unique_fd generateFileDescriptor() {
+ std::array<int, 2> kFileDescriptors;
+ LOG_IF(FATAL, ::socketpair(AF_UNIX, SOCK_SEQPACKET, 0, kFileDescriptors.data()) != 0)
+ << "TestInputChannel. Failed to create socket pair.";
+ LOG_IF(FATAL, ::close(kFileDescriptors[1]) != 0)
+ << "TestInputChannel. Failed to close file descriptor.";
+ return base::unique_fd{kFileDescriptors[0]};
+}
} // namespace
// --- TestInputChannel ---
TestInputChannel::TestInputChannel(const std::string& name)
- : InputChannel{name, base::unique_fd(FAKE_FD), sp<BBinder>::make()} {}
+ : InputChannel{name, generateFileDescriptor(), sp<BBinder>::make()} {}
void TestInputChannel::enqueueMessage(const InputMessage& message) {
mReceivedMessages.push(message);
diff --git a/libs/input/tests/TestLooper.cpp b/libs/input/tests/TestLooper.cpp
deleted file mode 100644
index e0f01ed25d..0000000000
--- a/libs/input/tests/TestLooper.cpp
+++ /dev/null
@@ -1,51 +0,0 @@
-/**
- * Copyright 2024 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 <TestLooper.h>
-
-#include <android-base/logging.h>
-
-namespace android {
-
-TestLooper::TestLooper() : mLooper(sp<Looper>::make(/*allowNonCallbacks=*/false)) {}
-
-int TestLooper::addFd(int fd, int ident, int events, const sp<LooperCallback>& callback,
- void* data) {
- mCallbacks[fd] = callback;
- constexpr int SUCCESS{1};
- return SUCCESS;
-}
-
-int TestLooper::removeFd(int fd) {
- if (auto it = mCallbacks.find(fd); it != mCallbacks.cend()) {
- mCallbacks.erase(fd);
- constexpr int SUCCESS{1};
- return SUCCESS;
- }
- constexpr int FAILURE{0};
- return FAILURE;
-}
-
-void TestLooper::invokeCallback(int fd, int events) {
- auto it = mCallbacks.find(fd);
- LOG_IF(FATAL, it == mCallbacks.cend()) << "Fd does not exist in mCallbacks.";
- mCallbacks[fd]->handleEvent(fd, events, /*data=*/nullptr);
-}
-
-sp<Looper> TestLooper::getLooper() const {
- return mLooper;
-}
-} // namespace android \ No newline at end of file
diff --git a/libs/input/tests/TestLooper.h b/libs/input/tests/TestLooper.h
deleted file mode 100644
index 3242bc7699..0000000000
--- a/libs/input/tests/TestLooper.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/**
- * Copyright 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <map>
-
-#include <input/LooperInterface.h>
-
-namespace android {
-/**
- * TestLooper provides a mechanism to directly trigger Looper's callback.
- */
-class TestLooper final : public LooperInterface {
-public:
- TestLooper();
-
- /**
- * Adds a file descriptor to mCallbacks. Ident, events, and data parameters are ignored. If
- * addFd is called with an existent file descriptor and a different callback, the previous
- * callback is overwritten.
- */
- int addFd(int fd, int ident, int events, const sp<LooperCallback>& callback,
- void* data) override;
-
- /**
- * Removes a file descriptor from mCallbacks. If fd is not in mCallbacks, returns FAILURE.
- */
- int removeFd(int fd) override;
-
- /**
- * Calls handleEvent of the file descriptor. Fd must be in mCallbacks. Otherwise, invokeCallback
- * fatally logs.
- */
- void invokeCallback(int fd, int events);
-
- sp<Looper> getLooper() const override;
-
-private:
- std::map<int /*fd*/, sp<LooperCallback>> mCallbacks;
- sp<Looper> mLooper;
-};
-} // namespace android \ No newline at end of file
diff --git a/libs/renderengine/OWNERS b/libs/renderengine/OWNERS
index 66e1aa1ca1..17ab29fd29 100644
--- a/libs/renderengine/OWNERS
+++ b/libs/renderengine/OWNERS
@@ -5,4 +5,6 @@ alecmouri@google.com
djsollen@google.com
jreck@google.com
lpy@google.com
+nscobie@google.com
+sallyqi@google.com
scroggo@google.com
diff --git a/libs/renderengine/benchmark/RenderEngineBench.cpp b/libs/renderengine/benchmark/RenderEngineBench.cpp
index a9264b3914..595573d24a 100644
--- a/libs/renderengine/benchmark/RenderEngineBench.cpp
+++ b/libs/renderengine/benchmark/RenderEngineBench.cpp
@@ -17,6 +17,7 @@
#include <RenderEngineBench.h>
#include <android-base/file.h>
#include <benchmark/benchmark.h>
+#include <com_android_graphics_libgui_flags.h>
#include <gui/SurfaceComposerClient.h>
#include <log/log.h>
#include <renderengine/ExternalTexture.h>
@@ -321,5 +322,7 @@ BENCHMARK_CAPTURE(BM_homescreen_blur, kawase_dual_filter, RenderEngine::Threaded
BENCHMARK_CAPTURE(BM_homescreen, SkiaGLThreaded, RenderEngine::Threaded::YES,
RenderEngine::GraphicsApi::GL);
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS_EDGE_EXTENSION_SHADER
BENCHMARK_CAPTURE(BM_homescreen_edgeExtension, SkiaGLThreaded, RenderEngine::Threaded::YES,
RenderEngine::GraphicsApi::GL);
+#endif
diff --git a/libs/vibrator/TEST_MAPPING b/libs/vibrator/TEST_MAPPING
index d782b43b57..e206761efa 100644
--- a/libs/vibrator/TEST_MAPPING
+++ b/libs/vibrator/TEST_MAPPING
@@ -1,5 +1,5 @@
{
- "postsubmit": [
+ "presubmit": [
{
"name": "libvibrator_test"
}
diff --git a/opengl/libs/EGL/egl_platform_entries.cpp b/opengl/libs/EGL/egl_platform_entries.cpp
index 6e35041662..6713a5c69d 100644
--- a/opengl/libs/EGL/egl_platform_entries.cpp
+++ b/opengl/libs/EGL/egl_platform_entries.cpp
@@ -2141,6 +2141,10 @@ EGLBoolean eglPresentationTimeANDROIDImpl(EGLDisplay dpy, EGLSurface surface,
}
egl_surface_t const* const s = get_surface(surface);
+ if (!s->getNativeWindow()) {
+ setError(EGL_BAD_SURFACE, EGL_FALSE);
+ return EGL_FALSE;
+ }
native_window_set_buffers_timestamp(s->getNativeWindow(), time);
return EGL_TRUE;
@@ -2405,7 +2409,7 @@ EGLBoolean eglGetFrameTimestampsANDROIDImpl(EGLDisplay dpy, EGLSurface surface,
case 0:
return EGL_TRUE;
case -ENOENT:
- return setError(EGL_BAD_ACCESS, (EGLBoolean)EGL_FALSE);
+ return setErrorQuiet(EGL_BAD_ACCESS, (EGLBoolean)EGL_FALSE);
case -ENOSYS:
return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
case -EINVAL:
diff --git a/services/inputflinger/dispatcher/Android.bp b/services/inputflinger/dispatcher/Android.bp
index 1a0ec48525..8b2b8432c3 100644
--- a/services/inputflinger/dispatcher/Android.bp
+++ b/services/inputflinger/dispatcher/Android.bp
@@ -46,6 +46,7 @@ filegroup {
"InputState.cpp",
"InputTarget.cpp",
"LatencyAggregator.cpp",
+ "LatencyAggregatorWithHistograms.cpp",
"LatencyTracker.cpp",
"Monitor.cpp",
"TouchedWindow.cpp",
diff --git a/services/inputflinger/dispatcher/CancelationOptions.h b/services/inputflinger/dispatcher/CancelationOptions.h
index 4a0889f596..568d348ba9 100644
--- a/services/inputflinger/dispatcher/CancelationOptions.h
+++ b/services/inputflinger/dispatcher/CancelationOptions.h
@@ -32,7 +32,8 @@ struct CancelationOptions {
CANCEL_POINTER_EVENTS = 1,
CANCEL_NON_POINTER_EVENTS = 2,
CANCEL_FALLBACK_EVENTS = 3,
- ftl_last = CANCEL_FALLBACK_EVENTS,
+ CANCEL_HOVER_EVENTS = 4,
+ ftl_last = CANCEL_HOVER_EVENTS
};
// The criterion to use to determine which events should be canceled.
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 0be107de2b..3337c47248 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -155,6 +155,10 @@ constexpr std::chrono::milliseconds SLOW_INTERCEPTION_THRESHOLD = 50ms;
// Number of recent events to keep for debugging purposes.
constexpr size_t RECENT_QUEUE_MAX_SIZE = 10;
+// Interval at which we should push the atom gathering input event latencies in
+// LatencyAggregatorWithHistograms
+constexpr nsecs_t LATENCY_STATISTICS_PUSH_INTERVAL = 6 * 3600 * 1000000000LL; // 6 hours
+
// Event log tags. See EventLogTags.logtags for reference.
constexpr int LOGTAG_INPUT_INTERACTION = 62000;
constexpr int LOGTAG_INPUT_FOCUS = 62001;
@@ -748,7 +752,8 @@ std::vector<TouchedWindow> getHoveringWindowsLocked(const TouchState* oldState,
}
touchedWindow.dispatchMode = InputTarget::DispatchMode::AS_IS;
}
- touchedWindow.addHoveringPointer(entry.deviceId, pointer);
+ const auto [x, y] = resolveTouchedPosition(entry);
+ touchedWindow.addHoveringPointer(entry.deviceId, pointer, x, y);
if (canReceiveForegroundTouches(*newWindow->getInfo())) {
touchedWindow.targetFlags |= InputTarget::Flags::FOREGROUND;
}
@@ -875,6 +880,8 @@ std::pair<bool /*cancelPointers*/, bool /*cancelNonPointers*/> expandCancellatio
return {false, true};
case CancelationOptions::Mode::CANCEL_FALLBACK_EVENTS:
return {false, true};
+ case CancelationOptions::Mode::CANCEL_HOVER_EVENTS:
+ return {true, false};
}
}
@@ -944,8 +951,13 @@ InputDispatcher::InputDispatcher(InputDispatcherPolicyInterface& policy,
mFocusedDisplayId(ui::LogicalDisplayId::DEFAULT),
mWindowTokenWithPointerCapture(nullptr),
mAwaitedApplicationDisplayId(ui::LogicalDisplayId::INVALID),
- mLatencyAggregator(),
- mLatencyTracker(&mLatencyAggregator) {
+ mInputEventTimelineProcessor(
+ input_flags::enable_per_device_input_latency_metrics()
+ ? std::move(std::unique_ptr<InputEventTimelineProcessor>(
+ new LatencyAggregatorWithHistograms()))
+ : std::move(std::unique_ptr<InputEventTimelineProcessor>(
+ new LatencyAggregator()))),
+ mLatencyTracker(*mInputEventTimelineProcessor) {
mLooper = sp<Looper>::make(false);
mReporter = createInputReporter();
@@ -1018,6 +1030,11 @@ void InputDispatcher::dispatchOnce() {
const nsecs_t nextAnrCheck = processAnrsLocked();
nextWakeupTime = std::min(nextWakeupTime, nextAnrCheck);
+ if (input_flags::enable_per_device_input_latency_metrics()) {
+ const nsecs_t nextStatisticsPush = processLatencyStatisticsLocked();
+ nextWakeupTime = std::min(nextWakeupTime, nextStatisticsPush);
+ }
+
// We are about to enter an infinitely long sleep, because we have no commands or
// pending or queued events
if (nextWakeupTime == LLONG_MAX) {
@@ -1098,6 +1115,21 @@ nsecs_t InputDispatcher::processAnrsLocked() {
return LLONG_MIN;
}
+/**
+ * Check if enough time has passed since the last latency statistics push.
+ * Return the time at which we should wake up next.
+ */
+nsecs_t InputDispatcher::processLatencyStatisticsLocked() {
+ const nsecs_t currentTime = now();
+ // Log the atom recording latency statistics if more than 6 hours passed from the last
+ // push
+ if (currentTime - mLastStatisticPushTime >= LATENCY_STATISTICS_PUSH_INTERVAL) {
+ mInputEventTimelineProcessor->pushLatencyStatistics();
+ mLastStatisticPushTime = currentTime;
+ }
+ return mLastStatisticPushTime + LATENCY_STATISTICS_PUSH_INTERVAL;
+}
+
std::chrono::nanoseconds InputDispatcher::getDispatchingTimeoutLocked(
const std::shared_ptr<Connection>& connection) {
if (connection->monitor) {
@@ -2512,7 +2544,8 @@ InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, const Motio
if (isHoverAction) {
// The "windowHandle" is the target of this hovering pointer.
- tempTouchState.addHoveringPointerToWindow(windowHandle, entry.deviceId, pointer);
+ tempTouchState.addHoveringPointerToWindow(windowHandle, entry.deviceId, pointer, x,
+ y);
}
// Set target flags.
@@ -4516,6 +4549,14 @@ void InputDispatcher::notifyKey(const NotifyKeyArgs& args) {
newEntry->traceTracker = mTracer->traceInboundEvent(*newEntry);
}
+ if (input_flags::enable_per_device_input_latency_metrics()) {
+ if (args.id != android::os::IInputConstants::INVALID_INPUT_EVENT_ID &&
+ IdGenerator::getSource(args.id) == IdGenerator::Source::INPUT_READER &&
+ !mInputFilterEnabled) {
+ mLatencyTracker.trackNotifyKey(args);
+ }
+ }
+
needWake = enqueueInboundEventLocked(std::move(newEntry));
mLock.unlock();
} // release lock
@@ -4648,9 +4689,7 @@ void InputDispatcher::notifyMotion(const NotifyMotionArgs& args) {
if (args.id != android::os::IInputConstants::INVALID_INPUT_EVENT_ID &&
IdGenerator::getSource(args.id) == IdGenerator::Source::INPUT_READER &&
!mInputFilterEnabled) {
- std::set<InputDeviceUsageSource> sources = getUsageSourcesForMotionArgs(args);
- mLatencyTracker.trackListener(args.id, args.eventTime, args.readTime, args.deviceId,
- sources, args.action, InputEventType::MOTION);
+ mLatencyTracker.trackNotifyMotion(args);
}
needWake = enqueueInboundEventLocked(std::move(newEntry));
@@ -5420,6 +5459,32 @@ void InputDispatcher::setInputWindowsLocked(
}
}
+ // Check if the hovering should stop because the window is no longer eligible to receive it
+ // (for example, if the touchable region changed)
+ if (const auto& it = mTouchStatesByDisplay.find(displayId); it != mTouchStatesByDisplay.end()) {
+ TouchState& state = it->second;
+ for (TouchedWindow& touchedWindow : state.windows) {
+ std::vector<DeviceId> erasedDevices = touchedWindow.eraseHoveringPointersIf(
+ [this, displayId, &touchedWindow](const PointerProperties& properties, float x,
+ float y) REQUIRES(mLock) {
+ const bool isStylus = properties.toolType == ToolType::STYLUS;
+ const ui::Transform displayTransform = getTransformLocked(displayId);
+ const bool stillAcceptsTouch =
+ windowAcceptsTouchAt(*touchedWindow.windowHandle->getInfo(),
+ displayId, x, y, isStylus, displayTransform);
+ return !stillAcceptsTouch;
+ });
+
+ for (DeviceId deviceId : erasedDevices) {
+ CancelationOptions options(CancelationOptions::Mode::CANCEL_HOVER_EVENTS,
+ "WindowInfo changed",
+ traceContext.getTracker());
+ options.deviceId = deviceId;
+ synthesizeCancelationEventsForWindowLocked(touchedWindow.windowHandle, options);
+ }
+ }
+ }
+
// Release information for windows that are no longer present.
// This ensures that unused input channels are released promptly.
// Otherwise, they might stick around until the window handle is destroyed
@@ -6060,7 +6125,7 @@ void InputDispatcher::dumpDispatchStateLocked(std::string& dump) const {
dump += StringPrintf(INDENT2 "KeyRepeatTimeout: %" PRId64 "ms\n",
ns2ms(mConfig.keyRepeatTimeout));
dump += mLatencyTracker.dump(INDENT2);
- dump += mLatencyAggregator.dump(INDENT2);
+ dump += mInputEventTimelineProcessor->dump(INDENT2);
dump += INDENT "InputTracer: ";
dump += mTracer == nullptr ? "Disabled" : "Enabled";
}
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index 1904058080..d90b9de80e 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -28,6 +28,7 @@
#include "InputTarget.h"
#include "InputThread.h"
#include "LatencyAggregator.h"
+#include "LatencyAggregatorWithHistograms.h"
#include "LatencyTracker.h"
#include "Monitor.h"
#include "TouchState.h"
@@ -326,6 +327,7 @@ private:
std::chrono::nanoseconds mMonitorDispatchingTimeout GUARDED_BY(mLock);
nsecs_t processAnrsLocked() REQUIRES(mLock);
+ nsecs_t processLatencyStatisticsLocked() REQUIRES(mLock);
std::chrono::nanoseconds getDispatchingTimeoutLocked(
const std::shared_ptr<Connection>& connection) REQUIRES(mLock);
@@ -697,7 +699,8 @@ private:
DeviceId deviceId) const REQUIRES(mLock);
// Statistics gathering.
- LatencyAggregator mLatencyAggregator GUARDED_BY(mLock);
+ nsecs_t mLastStatisticPushTime = 0;
+ std::unique_ptr<InputEventTimelineProcessor> mInputEventTimelineProcessor GUARDED_BY(mLock);
LatencyTracker mLatencyTracker GUARDED_BY(mLock);
void traceInboundQueueLengthLocked() REQUIRES(mLock);
void traceOutboundQueueLength(const Connection& connection);
diff --git a/services/inputflinger/dispatcher/InputEventTimeline.h b/services/inputflinger/dispatcher/InputEventTimeline.h
index 951fcc8d0c..4552708adc 100644
--- a/services/inputflinger/dispatcher/InputEventTimeline.h
+++ b/services/inputflinger/dispatcher/InputEventTimeline.h
@@ -121,13 +121,21 @@ struct InputEventTimeline {
class InputEventTimelineProcessor {
protected:
InputEventTimelineProcessor() {}
- virtual ~InputEventTimelineProcessor() {}
public:
+ virtual ~InputEventTimelineProcessor() {}
+
/**
* Process the provided timeline
*/
virtual void processTimeline(const InputEventTimeline& timeline) = 0;
+
+ /**
+ * Trigger a push for the input event latency statistics
+ */
+ virtual void pushLatencyStatistics() = 0;
+
+ virtual std::string dump(const char* prefix) const = 0;
};
} // namespace inputdispatcher
diff --git a/services/inputflinger/dispatcher/InputState.cpp b/services/inputflinger/dispatcher/InputState.cpp
index 4df23c54d6..9b5a79b24d 100644
--- a/services/inputflinger/dispatcher/InputState.cpp
+++ b/services/inputflinger/dispatcher/InputState.cpp
@@ -638,6 +638,8 @@ bool InputState::shouldCancelMotion(const MotionMemento& memento,
return memento.source & AINPUT_SOURCE_CLASS_POINTER;
case CancelationOptions::Mode::CANCEL_NON_POINTER_EVENTS:
return !(memento.source & AINPUT_SOURCE_CLASS_POINTER);
+ case CancelationOptions::Mode::CANCEL_HOVER_EVENTS:
+ return memento.hovering;
default:
return false;
}
diff --git a/services/inputflinger/dispatcher/LatencyAggregator.cpp b/services/inputflinger/dispatcher/LatencyAggregator.cpp
index 4ddd2e9e95..d0e9d7c983 100644
--- a/services/inputflinger/dispatcher/LatencyAggregator.cpp
+++ b/services/inputflinger/dispatcher/LatencyAggregator.cpp
@@ -28,6 +28,8 @@ using android::base::StringPrintf;
using dist_proc::aggregation::KllQuantile;
using std::chrono_literals::operator""ms;
+namespace {
+
// Convert the provided nanoseconds into hundreds of microseconds.
// Use hundreds of microseconds (as opposed to microseconds) to preserve space.
static inline int64_t ns2hus(nsecs_t nanos) {
@@ -74,6 +76,8 @@ static std::chrono::milliseconds getSlowEventMinReportingInterval() {
return std::chrono::milliseconds(std::stoi(millis));
}
+} // namespace
+
namespace android::inputdispatcher {
/**
@@ -125,6 +129,9 @@ void LatencyAggregator::processTimeline(const InputEventTimeline& timeline) {
processSlowEvent(timeline);
}
+// This version of LatencyAggregator doesn't push any atoms
+void LatencyAggregator::pushLatencyStatistics() {}
+
void LatencyAggregator::processStatistics(const InputEventTimeline& timeline) {
std::scoped_lock lock(mLock);
// Before we do any processing, check that we have not yet exceeded MAX_SIZE
diff --git a/services/inputflinger/dispatcher/LatencyAggregator.h b/services/inputflinger/dispatcher/LatencyAggregator.h
index d6d168602a..468add1435 100644
--- a/services/inputflinger/dispatcher/LatencyAggregator.h
+++ b/services/inputflinger/dispatcher/LatencyAggregator.h
@@ -57,6 +57,8 @@ public:
*/
void processTimeline(const InputEventTimeline& timeline) override;
+ void pushLatencyStatistics() override;
+
std::string dump(const char* prefix) const;
~LatencyAggregator();
diff --git a/services/inputflinger/dispatcher/LatencyAggregatorWithHistograms.cpp b/services/inputflinger/dispatcher/LatencyAggregatorWithHistograms.cpp
new file mode 100644
index 0000000000..881a96b28e
--- /dev/null
+++ b/services/inputflinger/dispatcher/LatencyAggregatorWithHistograms.cpp
@@ -0,0 +1,345 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "LatencyAggregatorWithHistograms"
+#include "../InputDeviceMetricsSource.h"
+#include "InputDispatcher.h"
+
+#include <inttypes.h>
+#include <log/log_event_list.h>
+#include <statslog.h>
+
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
+#include <input/Input.h>
+#include <log/log.h>
+#include <server_configurable_flags/get_flags.h>
+
+using android::base::StringPrintf;
+using std::chrono_literals::operator""ms;
+
+namespace {
+
+// Convert the provided nanoseconds into hundreds of microseconds.
+// Use hundreds of microseconds (as opposed to microseconds) to preserve space.
+static inline int64_t ns2hus(nsecs_t nanos) {
+ return ns2us(nanos) / 100;
+}
+
+// Category (=namespace) name for the input settings that are applied at boot time
+static const char* INPUT_NATIVE_BOOT = "input_native_boot";
+// Feature flag name for the threshold of end-to-end touch latency that would trigger
+// SlowEventReported atom to be pushed
+static const char* SLOW_EVENT_MIN_REPORTING_LATENCY_MILLIS =
+ "slow_event_min_reporting_latency_millis";
+// Feature flag name for the minimum delay before reporting a slow event after having just reported
+// a slow event. This helps limit the amount of data sent to the server
+static const char* SLOW_EVENT_MIN_REPORTING_INTERVAL_MILLIS =
+ "slow_event_min_reporting_interval_millis";
+
+// If an event has end-to-end latency > 200 ms, it will get reported as a slow event.
+std::chrono::milliseconds DEFAULT_SLOW_EVENT_MIN_REPORTING_LATENCY = 200ms;
+// If we receive two slow events less than 1 min apart, we will only report 1 of them.
+std::chrono::milliseconds DEFAULT_SLOW_EVENT_MIN_REPORTING_INTERVAL = 60000ms;
+
+static std::chrono::milliseconds getSlowEventMinReportingLatency() {
+ std::string millis = server_configurable_flags::
+ GetServerConfigurableFlag(INPUT_NATIVE_BOOT, SLOW_EVENT_MIN_REPORTING_LATENCY_MILLIS,
+ std::to_string(
+ DEFAULT_SLOW_EVENT_MIN_REPORTING_LATENCY.count()));
+ return std::chrono::milliseconds(std::stoi(millis));
+}
+
+static std::chrono::milliseconds getSlowEventMinReportingInterval() {
+ std::string millis = server_configurable_flags::
+ GetServerConfigurableFlag(INPUT_NATIVE_BOOT, SLOW_EVENT_MIN_REPORTING_INTERVAL_MILLIS,
+ std::to_string(
+ DEFAULT_SLOW_EVENT_MIN_REPORTING_INTERVAL.count()));
+ return std::chrono::milliseconds(std::stoi(millis));
+}
+
+} // namespace
+
+namespace android::inputdispatcher {
+
+int32_t LatencyStageIndexToAtomEnum(LatencyStageIndex latencyStageIndex) {
+ switch (latencyStageIndex) {
+ case LatencyStageIndex::EVENT_TO_READ:
+ return util::INPUT_EVENT_LATENCY_REPORTED__LATENCY_STAGE__EVENT_TO_READ;
+ case LatencyStageIndex::READ_TO_DELIVER:
+ return util::INPUT_EVENT_LATENCY_REPORTED__LATENCY_STAGE__READ_TO_DELIVER;
+ case LatencyStageIndex::DELIVER_TO_CONSUME:
+ return util::INPUT_EVENT_LATENCY_REPORTED__LATENCY_STAGE__DELIVER_TO_CONSUME;
+ case LatencyStageIndex::CONSUME_TO_FINISH:
+ return util::INPUT_EVENT_LATENCY_REPORTED__LATENCY_STAGE__CONSUME_TO_FINISH;
+ case LatencyStageIndex::CONSUME_TO_GPU_COMPLETE:
+ return util::INPUT_EVENT_LATENCY_REPORTED__LATENCY_STAGE__CONSUME_TO_GPU_COMPLETE;
+ case LatencyStageIndex::GPU_COMPLETE_TO_PRESENT:
+ return util::INPUT_EVENT_LATENCY_REPORTED__LATENCY_STAGE__GPU_COMPLETE_TO_PRESENT;
+ case LatencyStageIndex::END_TO_END:
+ return util::INPUT_EVENT_LATENCY_REPORTED__LATENCY_STAGE__END_TO_END;
+ default:
+ return util::INPUT_EVENT_LATENCY_REPORTED__LATENCY_STAGE__UNKNOWN_LATENCY_STAGE;
+ }
+}
+
+int32_t InputEventTypeEnumToAtomEnum(InputEventActionType inputEventActionType) {
+ switch (inputEventActionType) {
+ case InputEventActionType::UNKNOWN_INPUT_EVENT:
+ return util::INPUT_EVENT_LATENCY_REPORTED__INPUT_EVENT_TYPE__UNKNOWN_INPUT_EVENT;
+ case InputEventActionType::MOTION_ACTION_DOWN:
+ return util::INPUT_EVENT_LATENCY_REPORTED__INPUT_EVENT_TYPE__MOTION_ACTION_DOWN;
+ case InputEventActionType::MOTION_ACTION_MOVE:
+ return util::INPUT_EVENT_LATENCY_REPORTED__INPUT_EVENT_TYPE__MOTION_ACTION_MOVE;
+ case InputEventActionType::MOTION_ACTION_UP:
+ return util::INPUT_EVENT_LATENCY_REPORTED__INPUT_EVENT_TYPE__MOTION_ACTION_UP;
+ case InputEventActionType::MOTION_ACTION_HOVER_MOVE:
+ return util::INPUT_EVENT_LATENCY_REPORTED__INPUT_EVENT_TYPE__MOTION_ACTION_HOVER_MOVE;
+ case InputEventActionType::MOTION_ACTION_SCROLL:
+ return util::INPUT_EVENT_LATENCY_REPORTED__INPUT_EVENT_TYPE__MOTION_ACTION_SCROLL;
+ case InputEventActionType::KEY:
+ return util::INPUT_EVENT_LATENCY_REPORTED__INPUT_EVENT_TYPE__KEY;
+ }
+}
+
+void LatencyAggregatorWithHistograms::processTimeline(const InputEventTimeline& timeline) {
+ processStatistics(timeline);
+ processSlowEvent(timeline);
+}
+
+void LatencyAggregatorWithHistograms::addSampleToHistogram(
+ const InputEventLatencyIdentifier& identifier, LatencyStageIndex latencyStageIndex,
+ nsecs_t latency) {
+ // Only record positive values for the statistics
+ if (latency > 0) {
+ auto it = mHistograms.find(identifier);
+ if (it != mHistograms.end()) {
+ it->second[static_cast<size_t>(latencyStageIndex)].addSample(ns2hus(latency));
+ }
+ }
+}
+
+void LatencyAggregatorWithHistograms::processStatistics(const InputEventTimeline& timeline) {
+ // Only gather data for Down, Move and Up motion events and Key events
+ if (!(timeline.inputEventActionType == InputEventActionType::MOTION_ACTION_DOWN ||
+ timeline.inputEventActionType == InputEventActionType::MOTION_ACTION_MOVE ||
+ timeline.inputEventActionType == InputEventActionType::MOTION_ACTION_UP ||
+ timeline.inputEventActionType == InputEventActionType::KEY))
+ return;
+
+ // Don't collect data for unidentified devices. This situation can occur for the first few input
+ // events produced when an input device is first connected
+ if (timeline.vendorId == 0xFFFF && timeline.productId == 0xFFFF) return;
+
+ InputEventLatencyIdentifier identifier = {timeline.vendorId, timeline.productId,
+ timeline.sources, timeline.inputEventActionType};
+ // Check if there's a value in mHistograms map associated to identifier.
+ // If not, add an array with 7 empty histograms as an entry
+ if (mHistograms.count(identifier) == 0) {
+ if (static_cast<int32_t>(timeline.inputEventActionType) - 1 < 0) {
+ LOG(FATAL) << "Action index is smaller than 0. Action type: "
+ << ftl::enum_string(timeline.inputEventActionType);
+ return;
+ }
+ size_t actionIndex =
+ static_cast<size_t>(static_cast<int32_t>(timeline.inputEventActionType) - 1);
+ if (actionIndex >= NUM_INPUT_EVENT_TYPES) {
+ LOG(FATAL) << "Action index greater than the number of input event types. Action Type: "
+ << ftl::enum_string(timeline.inputEventActionType)
+ << "; Action Type Index: " << actionIndex;
+ return;
+ }
+
+ std::array<Histogram, 7> histograms =
+ {Histogram(allBinSizes[binSizesMappings[0][actionIndex]]),
+ Histogram(allBinSizes[binSizesMappings[1][actionIndex]]),
+ Histogram(allBinSizes[binSizesMappings[2][actionIndex]]),
+ Histogram(allBinSizes[binSizesMappings[3][actionIndex]]),
+ Histogram(allBinSizes[binSizesMappings[4][actionIndex]]),
+ Histogram(allBinSizes[binSizesMappings[5][actionIndex]]),
+ Histogram(allBinSizes[binSizesMappings[6][actionIndex]])};
+ mHistograms.insert({identifier, histograms});
+ }
+
+ // Process common ones first
+ const nsecs_t eventToRead = timeline.readTime - timeline.eventTime;
+ addSampleToHistogram(identifier, LatencyStageIndex::EVENT_TO_READ, eventToRead);
+
+ // Now process per-connection ones
+ for (const auto& [connectionToken, connectionTimeline] : timeline.connectionTimelines) {
+ if (!connectionTimeline.isComplete()) {
+ continue;
+ }
+ const nsecs_t readToDeliver = connectionTimeline.deliveryTime - timeline.readTime;
+ const nsecs_t deliverToConsume =
+ connectionTimeline.consumeTime - connectionTimeline.deliveryTime;
+ const nsecs_t consumeToFinish =
+ connectionTimeline.finishTime - connectionTimeline.consumeTime;
+ const nsecs_t gpuCompletedTime =
+ connectionTimeline.graphicsTimeline[GraphicsTimeline::GPU_COMPLETED_TIME];
+ const nsecs_t presentTime =
+ connectionTimeline.graphicsTimeline[GraphicsTimeline::PRESENT_TIME];
+ const nsecs_t consumeToGpuComplete = gpuCompletedTime - connectionTimeline.consumeTime;
+ const nsecs_t gpuCompleteToPresent = presentTime - gpuCompletedTime;
+ const nsecs_t endToEnd = presentTime - timeline.eventTime;
+
+ addSampleToHistogram(identifier, LatencyStageIndex::READ_TO_DELIVER, readToDeliver);
+ addSampleToHistogram(identifier, LatencyStageIndex::DELIVER_TO_CONSUME, deliverToConsume);
+ addSampleToHistogram(identifier, LatencyStageIndex::CONSUME_TO_FINISH, consumeToFinish);
+ addSampleToHistogram(identifier, LatencyStageIndex::CONSUME_TO_GPU_COMPLETE,
+ consumeToGpuComplete);
+ addSampleToHistogram(identifier, LatencyStageIndex::GPU_COMPLETE_TO_PRESENT,
+ gpuCompleteToPresent);
+ addSampleToHistogram(identifier, LatencyStageIndex::END_TO_END, endToEnd);
+ }
+}
+
+void LatencyAggregatorWithHistograms::pushLatencyStatistics() {
+ for (auto& [id, histograms] : mHistograms) {
+ auto [vendorId, productId, sources, action] = id;
+ for (size_t latencyStageIndex = static_cast<size_t>(LatencyStageIndex::EVENT_TO_READ);
+ latencyStageIndex < static_cast<size_t>(LatencyStageIndex::SIZE);
+ ++latencyStageIndex) {
+ // Convert sources set to vector for atom logging:
+ std::vector<int32_t> sourcesVector = {};
+ for (auto& elem : sources) {
+ sourcesVector.push_back(static_cast<int32_t>(elem));
+ }
+
+ // convert histogram bin counts array to vector for atom logging:
+ std::array arr = histograms[latencyStageIndex].getBinCounts();
+ std::vector<int32_t> binCountsVector(arr.begin(), arr.end());
+
+ if (static_cast<int32_t>(action) - 1 < 0) {
+ ALOGW("Action index is smaller than 0. Action type: %s",
+ ftl::enum_string(action).c_str());
+ continue;
+ }
+ size_t actionIndex = static_cast<size_t>(static_cast<int32_t>(action) - 1);
+ if (actionIndex >= NUM_INPUT_EVENT_TYPES) {
+ ALOGW("Action index greater than the number of input event types. Action Type: %s; "
+ "Action Type Index: %zu",
+ ftl::enum_string(action).c_str(), actionIndex);
+ continue;
+ }
+
+ stats_write(android::util::INPUT_EVENT_LATENCY_REPORTED, vendorId, productId,
+ sourcesVector, InputEventTypeEnumToAtomEnum(action),
+ LatencyStageIndexToAtomEnum(
+ static_cast<LatencyStageIndex>(latencyStageIndex)),
+ histogramVersions[latencyStageIndex][actionIndex], binCountsVector);
+ }
+ }
+ mHistograms.clear();
+}
+
+// TODO (b/270049345): For now, we just copied the code from LatencyAggregator to populate the old
+// atom, but eventually we should migrate this to use the new SlowEventReported atom
+void LatencyAggregatorWithHistograms::processSlowEvent(const InputEventTimeline& timeline) {
+ static const std::chrono::duration sSlowEventThreshold = getSlowEventMinReportingLatency();
+ static const std::chrono::duration sSlowEventReportingInterval =
+ getSlowEventMinReportingInterval();
+ for (const auto& [token, connectionTimeline] : timeline.connectionTimelines) {
+ if (!connectionTimeline.isComplete()) {
+ continue;
+ }
+ mNumEventsSinceLastSlowEventReport++;
+ const nsecs_t presentTime =
+ connectionTimeline.graphicsTimeline[GraphicsTimeline::PRESENT_TIME];
+ const std::chrono::nanoseconds endToEndLatency =
+ std::chrono::nanoseconds(presentTime - timeline.eventTime);
+ if (endToEndLatency < sSlowEventThreshold) {
+ continue;
+ }
+ // This is a slow event. Before we report it, check if we are reporting too often
+ const std::chrono::duration elapsedSinceLastReport =
+ std::chrono::nanoseconds(timeline.eventTime - mLastSlowEventTime);
+ if (elapsedSinceLastReport < sSlowEventReportingInterval) {
+ mNumSkippedSlowEvents++;
+ continue;
+ }
+
+ const nsecs_t eventToRead = timeline.readTime - timeline.eventTime;
+ const nsecs_t readToDeliver = connectionTimeline.deliveryTime - timeline.readTime;
+ const nsecs_t deliverToConsume =
+ connectionTimeline.consumeTime - connectionTimeline.deliveryTime;
+ const nsecs_t consumeToFinish =
+ connectionTimeline.finishTime - connectionTimeline.consumeTime;
+ const nsecs_t gpuCompletedTime =
+ connectionTimeline.graphicsTimeline[GraphicsTimeline::GPU_COMPLETED_TIME];
+ const nsecs_t consumeToGpuComplete = gpuCompletedTime - connectionTimeline.consumeTime;
+ const nsecs_t gpuCompleteToPresent = presentTime - gpuCompletedTime;
+
+ android::util::stats_write(android::util::SLOW_INPUT_EVENT_REPORTED,
+ timeline.inputEventActionType ==
+ InputEventActionType::MOTION_ACTION_DOWN,
+ static_cast<int32_t>(ns2us(eventToRead)),
+ static_cast<int32_t>(ns2us(readToDeliver)),
+ static_cast<int32_t>(ns2us(deliverToConsume)),
+ static_cast<int32_t>(ns2us(consumeToFinish)),
+ static_cast<int32_t>(ns2us(consumeToGpuComplete)),
+ static_cast<int32_t>(ns2us(gpuCompleteToPresent)),
+ static_cast<int32_t>(ns2us(endToEndLatency.count())),
+ static_cast<int32_t>(mNumEventsSinceLastSlowEventReport),
+ static_cast<int32_t>(mNumSkippedSlowEvents));
+ mNumEventsSinceLastSlowEventReport = 0;
+ mNumSkippedSlowEvents = 0;
+ mLastSlowEventTime = timeline.readTime;
+ }
+}
+
+std::string LatencyAggregatorWithHistograms::dump(const char* prefix) const {
+ std::string statisticsStr = StringPrintf("%s Histograms:\n", prefix);
+ for (const auto& [id, histograms] : mHistograms) {
+ auto [vendorId, productId, sources, action] = id;
+
+ std::string identifierStr =
+ StringPrintf("%s Identifier: vendor %d, product %d, sources: {", prefix, vendorId,
+ productId);
+ bool firstSource = true;
+ for (const auto& source : sources) {
+ if (!firstSource) {
+ identifierStr += ", ";
+ }
+ identifierStr += StringPrintf("%d", static_cast<int32_t>(source));
+ firstSource = false;
+ }
+ identifierStr += StringPrintf("}, action: %d\n", static_cast<int32_t>(action));
+
+ std::string histogramsStr;
+ for (size_t stageIndex = 0; stageIndex < static_cast<size_t>(LatencyStageIndex::SIZE);
+ stageIndex++) {
+ const auto& histogram = histograms[stageIndex];
+ const std::array<int, NUM_BINS>& binCounts = histogram.getBinCounts();
+
+ histogramsStr += StringPrintf("%s %zu: ", prefix, stageIndex);
+ histogramsStr += StringPrintf("%d", binCounts[0]);
+ for (size_t bin = 1; bin < NUM_BINS; bin++) {
+ histogramsStr += StringPrintf(", %d", binCounts[bin]);
+ }
+ histogramsStr += StringPrintf("\n");
+ }
+ statisticsStr += identifierStr + histogramsStr;
+ }
+
+ return StringPrintf("%sLatencyAggregatorWithHistograms:\n", prefix) + statisticsStr +
+ StringPrintf("%s mLastSlowEventTime=%" PRId64 "\n", prefix, mLastSlowEventTime) +
+ StringPrintf("%s mNumEventsSinceLastSlowEventReport = %zu\n", prefix,
+ mNumEventsSinceLastSlowEventReport) +
+ StringPrintf("%s mNumSkippedSlowEvents = %zu\n", prefix, mNumSkippedSlowEvents);
+}
+
+} // namespace android::inputdispatcher
diff --git a/services/inputflinger/dispatcher/LatencyAggregatorWithHistograms.h b/services/inputflinger/dispatcher/LatencyAggregatorWithHistograms.h
new file mode 100644
index 0000000000..2ceb0e7cb7
--- /dev/null
+++ b/services/inputflinger/dispatcher/LatencyAggregatorWithHistograms.h
@@ -0,0 +1,164 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android-base/thread_annotations.h>
+#include <utils/Timers.h>
+
+#include "InputEventTimeline.h"
+
+namespace android::inputdispatcher {
+
+static constexpr size_t NUM_BINS = 20;
+static constexpr size_t NUM_INPUT_EVENT_TYPES = 6;
+
+enum class LatencyStageIndex : size_t {
+ EVENT_TO_READ = 0,
+ READ_TO_DELIVER = 1,
+ DELIVER_TO_CONSUME = 2,
+ CONSUME_TO_FINISH = 3,
+ CONSUME_TO_GPU_COMPLETE = 4,
+ GPU_COMPLETE_TO_PRESENT = 5,
+ END_TO_END = 6,
+ SIZE = 7, // must be last
+};
+
+// Let's create a full timeline here:
+// eventTime
+// readTime
+// <---- after this point, the data becomes per-connection
+// deliveryTime // time at which the event was sent to the receiver
+// consumeTime // time at which the receiver read the event
+// finishTime // time at which the dispatcher reads the response from the receiver that the event
+// was processed
+// GraphicsTimeline::GPU_COMPLETED_TIME
+// GraphicsTimeline::PRESENT_TIME
+
+/**
+ * Keep histograms with latencies of the provided events
+ */
+class LatencyAggregatorWithHistograms final : public InputEventTimelineProcessor {
+public:
+ /**
+ * Record a complete event timeline
+ */
+ void processTimeline(const InputEventTimeline& timeline) override;
+
+ void pushLatencyStatistics() override;
+
+ std::string dump(const char* prefix) const override;
+
+private:
+ // ---------- Slow event handling ----------
+ void processSlowEvent(const InputEventTimeline& timeline);
+ nsecs_t mLastSlowEventTime = 0;
+ // How many slow events have been skipped due to rate limiting
+ size_t mNumSkippedSlowEvents = 0;
+ // How many events have been received since the last time we reported a slow event
+ size_t mNumEventsSinceLastSlowEventReport = 0;
+
+ // ---------- Statistics handling ----------
+ /**
+ * Data structure to gather time samples into NUM_BINS buckets
+ */
+ class Histogram {
+ public:
+ Histogram(const std::array<int, NUM_BINS - 1>& binSizes) : mBinSizes(binSizes) {
+ mBinCounts.fill(0);
+ }
+
+ // Increments binCounts of the appropriate bin when adding a new sample
+ void addSample(int64_t sample) {
+ size_t binIndex = getSampleBinIndex(sample);
+ mBinCounts[binIndex]++;
+ }
+
+ const std::array<int32_t, NUM_BINS>& getBinCounts() const { return mBinCounts; }
+
+ private:
+ // reference to an array that represents the range of values each bin holds.
+ // in bin i+1 live samples such that *mBinSizes[i] <= sample < *mBinSizes[i+1]
+ const std::array<int, NUM_BINS - 1>& mBinSizes;
+ std::array<int32_t, NUM_BINS>
+ mBinCounts; // the number of samples that currently live in each bin
+
+ size_t getSampleBinIndex(int64_t sample) {
+ auto it = std::upper_bound(mBinSizes.begin(), mBinSizes.end(), sample);
+ return std::distance(mBinSizes.begin(), it);
+ }
+ };
+
+ void processStatistics(const InputEventTimeline& timeline);
+
+ // Identifier for the an input event. If two input events have the same identifiers we
+ // want to use the same histograms to count the latency samples
+ using InputEventLatencyIdentifier =
+ std::tuple<uint16_t /*vendorId*/, uint16_t /*productId*/,
+ const std::set<InputDeviceUsageSource> /*sources*/,
+ InputEventActionType /*inputEventActionType*/>;
+
+ // Maps an input event identifier to an array of 7 histograms, one for each latency
+ // stage. It is cleared after an atom push
+ std::map<InputEventLatencyIdentifier, std::array<Histogram, 7>> mHistograms;
+
+ void addSampleToHistogram(const InputEventLatencyIdentifier& identifier,
+ LatencyStageIndex latencyStageIndex, nsecs_t time);
+
+ // Stores all possible arrays of bin sizes. The order in the vector does not matter, as long
+ // as binSizesMappings points to the right index
+ static constexpr std::array<std::array<int, NUM_BINS - 1>, 6> allBinSizes = {
+ {{10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100},
+ {1, 2, 3, 4, 5, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32},
+ {15, 30, 45, 60, 75, 90, 105, 120, 135, 150, 165, 180, 195, 210, 225, 240, 255, 270,
+ 285},
+ {40, 80, 120, 160, 200, 240, 280, 320, 360, 400, 440, 480, 520, 560, 600, 640, 680,
+ 720, 760},
+ {20, 40, 60, 80, 100, 120, 140, 160, 180, 200, 220, 240, 260, 280, 300, 320, 340, 360,
+ 380},
+ {200, 300, 400, 500, 600, 700, 800, 900, 1000, 1100, 1200, 1300, 1400, 1500, 1600,
+ 1700, 1800, 1900, 2000}}};
+
+ // Stores indexes in allBinSizes to use with each {LatencyStage, InputEventType} pair.
+ // Bin sizes for a certain latencyStage and inputEventType are at:
+ // *(allBinSizes[binSizesMappings[latencyStageIndex][inputEventTypeIndex]])
+ // inputEventTypeIndex is the int value of InputEventActionType enum decreased by 1 since we
+ // don't want to record latencies for unknown events.
+ // e.g. MOTION_ACTION_DOWN is 0, MOTION_ACTION_MOVE is 1...
+ static constexpr std::array<std::array<int8_t, NUM_INPUT_EVENT_TYPES>,
+ static_cast<size_t>(LatencyStageIndex::SIZE)>
+ binSizesMappings = {{{0, 0, 0, 0, 0, 0},
+ {1, 1, 1, 1, 1, 1},
+ {1, 1, 1, 1, 1, 1},
+ {2, 2, 2, 2, 2, 2},
+ {3, 3, 3, 3, 3, 3},
+ {4, 4, 4, 4, 4, 4},
+ {5, 5, 5, 5, 5, 5}}};
+
+ // Similar to binSizesMappings, but holds the index of the array of bin ranges to use on the
+ // server. The index gets pushed with the atom within the histogram_version field.
+ static constexpr std::array<std::array<int8_t, NUM_INPUT_EVENT_TYPES>,
+ static_cast<size_t>(LatencyStageIndex::SIZE)>
+ histogramVersions = {{{0, 0, 0, 0, 0, 0},
+ {1, 1, 1, 1, 1, 1},
+ {1, 1, 1, 1, 1, 1},
+ {2, 2, 2, 2, 2, 2},
+ {3, 3, 3, 3, 3, 3},
+ {4, 4, 4, 4, 4, 4},
+ {5, 5, 5, 5, 5, 5}}};
+};
+
+} // namespace android::inputdispatcher
diff --git a/services/inputflinger/dispatcher/LatencyTracker.cpp b/services/inputflinger/dispatcher/LatencyTracker.cpp
index 69024b326a..0852026823 100644
--- a/services/inputflinger/dispatcher/LatencyTracker.cpp
+++ b/services/inputflinger/dispatcher/LatencyTracker.cpp
@@ -62,9 +62,27 @@ static void eraseByValue(std::multimap<K, V>& map, const V& value) {
}
}
-LatencyTracker::LatencyTracker(InputEventTimelineProcessor* processor)
- : mTimelineProcessor(processor) {
- LOG_ALWAYS_FATAL_IF(processor == nullptr);
+LatencyTracker::LatencyTracker(InputEventTimelineProcessor& processor)
+ : mTimelineProcessor(&processor) {}
+
+void LatencyTracker::trackNotifyMotion(const NotifyMotionArgs& args) {
+ std::set<InputDeviceUsageSource> sources = getUsageSourcesForMotionArgs(args);
+ trackListener(args.id, args.eventTime, args.readTime, args.deviceId, sources, args.action,
+ InputEventType::MOTION);
+}
+
+void LatencyTracker::trackNotifyKey(const NotifyKeyArgs& args) {
+ int32_t keyboardType = AINPUT_KEYBOARD_TYPE_NONE;
+ for (auto& inputDevice : mInputDevices) {
+ if (args.deviceId == inputDevice.getId()) {
+ keyboardType = inputDevice.getKeyboardType();
+ break;
+ }
+ }
+ std::set<InputDeviceUsageSource> sources =
+ std::set{getUsageSourceForKeyArgs(keyboardType, args)};
+ trackListener(args.id, args.eventTime, args.readTime, args.deviceId, sources, args.action,
+ InputEventType::KEY);
}
void LatencyTracker::trackListener(int32_t inputEventId, nsecs_t eventTime, nsecs_t readTime,
diff --git a/services/inputflinger/dispatcher/LatencyTracker.h b/services/inputflinger/dispatcher/LatencyTracker.h
index b4053ba1b3..eb58222ce6 100644
--- a/services/inputflinger/dispatcher/LatencyTracker.h
+++ b/services/inputflinger/dispatcher/LatencyTracker.h
@@ -42,7 +42,7 @@ public:
* Create a LatencyTracker.
* param reportingFunction: the function that will be called in order to report full latency.
*/
- LatencyTracker(InputEventTimelineProcessor* processor);
+ LatencyTracker(InputEventTimelineProcessor& processor);
/**
* Start keeping track of an event identified by inputEventId. This must be called first.
* If duplicate events are encountered (events that have the same eventId), none of them will be
@@ -59,6 +59,13 @@ public:
nsecs_t deliveryTime, nsecs_t consumeTime, nsecs_t finishTime);
void trackGraphicsLatency(int32_t inputEventId, const sp<IBinder>& connectionToken,
std::array<nsecs_t, GraphicsTimeline::SIZE> timeline);
+ /**
+ * trackNotifyMotion and trackNotifyKeys are intermediates between InputDispatcher and
+ * trackListener. They compute the InputDeviceUsageSource set and call trackListener with
+ * the relevant parameters for latency computation.
+ */
+ void trackNotifyMotion(const NotifyMotionArgs& args);
+ void trackNotifyKey(const NotifyKeyArgs& args);
std::string dump(const char* prefix) const;
void setInputDevices(const std::vector<InputDeviceInfo>& inputDevices);
diff --git a/services/inputflinger/dispatcher/TouchState.cpp b/services/inputflinger/dispatcher/TouchState.cpp
index 0c9ad3c7b7..2bf63beb05 100644
--- a/services/inputflinger/dispatcher/TouchState.cpp
+++ b/services/inputflinger/dispatcher/TouchState.cpp
@@ -112,17 +112,18 @@ android::base::Result<void> TouchState::addOrUpdateWindow(
}
void TouchState::addHoveringPointerToWindow(const sp<WindowInfoHandle>& windowHandle,
- DeviceId deviceId, const PointerProperties& pointer) {
+ DeviceId deviceId, const PointerProperties& pointer,
+ float x, float y) {
for (TouchedWindow& touchedWindow : windows) {
if (touchedWindow.windowHandle == windowHandle) {
- touchedWindow.addHoveringPointer(deviceId, pointer);
+ touchedWindow.addHoveringPointer(deviceId, pointer, x, y);
return;
}
}
TouchedWindow touchedWindow;
touchedWindow.windowHandle = windowHandle;
- touchedWindow.addHoveringPointer(deviceId, pointer);
+ touchedWindow.addHoveringPointer(deviceId, pointer, x, y);
windows.push_back(touchedWindow);
}
diff --git a/services/inputflinger/dispatcher/TouchState.h b/services/inputflinger/dispatcher/TouchState.h
index 5a70dd5e2c..451d91704c 100644
--- a/services/inputflinger/dispatcher/TouchState.h
+++ b/services/inputflinger/dispatcher/TouchState.h
@@ -49,7 +49,8 @@ struct TouchState {
DeviceId deviceId, const std::vector<PointerProperties>& touchingPointers,
std::optional<nsecs_t> firstDownTimeInTarget);
void addHoveringPointerToWindow(const sp<android::gui::WindowInfoHandle>& windowHandle,
- DeviceId deviceId, const PointerProperties& pointer);
+ DeviceId deviceId, const PointerProperties& pointer, float x,
+ float y);
void removeHoveringPointer(DeviceId deviceId, int32_t pointerId);
void clearHoveringPointers(DeviceId deviceId);
diff --git a/services/inputflinger/dispatcher/TouchedWindow.cpp b/services/inputflinger/dispatcher/TouchedWindow.cpp
index 1f86f6635a..fa5be1a719 100644
--- a/services/inputflinger/dispatcher/TouchedWindow.cpp
+++ b/services/inputflinger/dispatcher/TouchedWindow.cpp
@@ -36,6 +36,13 @@ bool hasPointerId(const std::vector<PointerProperties>& pointers, int32_t pointe
}) != pointers.end();
}
+bool hasPointerId(const std::vector<TouchedWindow::HoveringPointer>& pointers, int32_t pointerId) {
+ return std::find_if(pointers.begin(), pointers.end(),
+ [&pointerId](const TouchedWindow::HoveringPointer& pointer) {
+ return pointer.properties.id == pointerId;
+ }) != pointers.end();
+}
+
} // namespace
bool TouchedWindow::hasHoveringPointers() const {
@@ -78,16 +85,18 @@ bool TouchedWindow::hasHoveringPointer(DeviceId deviceId, int32_t pointerId) con
return hasPointerId(state.hoveringPointers, pointerId);
}
-void TouchedWindow::addHoveringPointer(DeviceId deviceId, const PointerProperties& pointer) {
- std::vector<PointerProperties>& hoveringPointers = mDeviceStates[deviceId].hoveringPointers;
+void TouchedWindow::addHoveringPointer(DeviceId deviceId, const PointerProperties& properties,
+ float x, float y) {
+ std::vector<HoveringPointer>& hoveringPointers = mDeviceStates[deviceId].hoveringPointers;
const size_t initialSize = hoveringPointers.size();
- std::erase_if(hoveringPointers, [&pointer](const PointerProperties& properties) {
- return properties.id == pointer.id;
+ std::erase_if(hoveringPointers, [&properties](const HoveringPointer& pointer) {
+ return pointer.properties.id == properties.id;
});
if (hoveringPointers.size() != initialSize) {
- LOG(ERROR) << __func__ << ": " << pointer << ", device " << deviceId << " was in " << *this;
+ LOG(ERROR) << __func__ << ": " << properties << ", device " << deviceId << " was in "
+ << *this;
}
- hoveringPointers.push_back(pointer);
+ hoveringPointers.push_back({properties, x, y});
}
Result<void> TouchedWindow::addTouchingPointers(DeviceId deviceId,
@@ -173,8 +182,8 @@ bool TouchedWindow::hasActiveStylus() const {
return true;
}
}
- for (const PointerProperties& properties : state.hoveringPointers) {
- if (properties.toolType == ToolType::STYLUS) {
+ for (const HoveringPointer& pointer : state.hoveringPointers) {
+ if (pointer.properties.toolType == ToolType::STYLUS) {
return true;
}
}
@@ -270,8 +279,8 @@ void TouchedWindow::removeHoveringPointer(DeviceId deviceId, int32_t pointerId)
}
DeviceState& state = stateIt->second;
- std::erase_if(state.hoveringPointers, [&pointerId](const PointerProperties& properties) {
- return properties.id == pointerId;
+ std::erase_if(state.hoveringPointers, [&pointerId](const HoveringPointer& pointer) {
+ return pointer.properties.id == pointerId;
});
if (!state.hasPointers()) {
@@ -279,6 +288,22 @@ void TouchedWindow::removeHoveringPointer(DeviceId deviceId, int32_t pointerId)
}
}
+std::vector<DeviceId> TouchedWindow::eraseHoveringPointersIf(
+ std::function<bool(const PointerProperties&, float /*x*/, float /*y*/)> condition) {
+ std::vector<DeviceId> erasedDevices;
+ for (auto& [deviceId, state] : mDeviceStates) {
+ std::erase_if(state.hoveringPointers, [&](const HoveringPointer& pointer) {
+ if (condition(pointer.properties, pointer.x, pointer.y)) {
+ erasedDevices.push_back(deviceId);
+ return true;
+ }
+ return false;
+ });
+ }
+
+ return erasedDevices;
+}
+
void TouchedWindow::removeAllHoveringPointersForDevice(DeviceId deviceId) {
const auto stateIt = mDeviceStates.find(deviceId);
if (stateIt == mDeviceStates.end()) {
@@ -312,6 +337,11 @@ std::string TouchedWindow::dump() const {
return out;
}
+std::ostream& operator<<(std::ostream& out, const TouchedWindow::HoveringPointer& pointer) {
+ out << pointer.properties << " at (" << pointer.x << ", " << pointer.y << ")";
+ return out;
+}
+
std::ostream& operator<<(std::ostream& out, const TouchedWindow& window) {
out << window.dump();
return out;
diff --git a/services/inputflinger/dispatcher/TouchedWindow.h b/services/inputflinger/dispatcher/TouchedWindow.h
index 4f0ad1628a..c38681eef0 100644
--- a/services/inputflinger/dispatcher/TouchedWindow.h
+++ b/services/inputflinger/dispatcher/TouchedWindow.h
@@ -38,7 +38,7 @@ struct TouchedWindow {
bool hasHoveringPointers() const;
bool hasHoveringPointers(DeviceId deviceId) const;
bool hasHoveringPointer(DeviceId deviceId, int32_t pointerId) const;
- void addHoveringPointer(DeviceId deviceId, const PointerProperties& pointer);
+ void addHoveringPointer(DeviceId deviceId, const PointerProperties& pointer, float x, float y);
void removeHoveringPointer(DeviceId deviceId, int32_t pointerId);
// Touching
@@ -69,6 +69,15 @@ struct TouchedWindow {
void clearHoveringPointers(DeviceId deviceId);
std::string dump() const;
+ struct HoveringPointer {
+ PointerProperties properties;
+ float x;
+ float y;
+ };
+
+ std::vector<DeviceId> eraseHoveringPointersIf(
+ std::function<bool(const PointerProperties&, float /*x*/, float /*y*/)> condition);
+
private:
struct DeviceState {
std::vector<PointerProperties> touchingPointers;
@@ -78,7 +87,7 @@ private:
// NOTE: This is not initialized in case of HOVER entry/exit and DISPATCH_AS_OUTSIDE
// scenario.
std::optional<nsecs_t> downTimeInTarget;
- std::vector<PointerProperties> hoveringPointers;
+ std::vector<HoveringPointer> hoveringPointers;
bool hasPointers() const { return !touchingPointers.empty() || !hoveringPointers.empty(); };
};
diff --git a/services/inputflinger/include/InputReaderBase.h b/services/inputflinger/include/InputReaderBase.h
index 69874c90f3..2f6c6d74e7 100644
--- a/services/inputflinger/include/InputReaderBase.h
+++ b/services/inputflinger/include/InputReaderBase.h
@@ -93,6 +93,9 @@ struct InputReaderConfiguration {
// The touchpad settings changed.
TOUCHPAD_SETTINGS = 1u << 13,
+ // The key remapping has changed.
+ KEY_REMAPPING = 1u << 14,
+
// All devices must be reopened.
MUST_REOPEN = 1u << 31,
};
@@ -246,6 +249,9 @@ struct InputReaderConfiguration {
// True if a pointer icon should be shown for direct stylus pointers.
bool stylusPointerIconEnabled;
+ // Keycodes to be remapped.
+ std::map<int32_t /* fromKeyCode */, int32_t /* toKeyCode */> keyRemapping;
+
InputReaderConfiguration()
: virtualKeyQuietTime(0),
defaultPointerDisplayId(ui::LogicalDisplayId::DEFAULT),
@@ -333,9 +339,6 @@ public:
virtual int32_t getKeyCodeState(int32_t deviceId, uint32_t sourceMask, int32_t keyCode) = 0;
virtual int32_t getSwitchState(int32_t deviceId, uint32_t sourceMask, int32_t sw) = 0;
- virtual void addKeyRemapping(int32_t deviceId, int32_t fromKeyCode,
- int32_t toKeyCode) const = 0;
-
virtual int32_t getKeyCodeForKeyLocation(int32_t deviceId, int32_t locationKeyCode) const = 0;
/* Toggle Caps Lock */
diff --git a/services/inputflinger/reader/EventHub.cpp b/services/inputflinger/reader/EventHub.cpp
index e11adb8c76..0865eed4a2 100644
--- a/services/inputflinger/reader/EventHub.cpp
+++ b/services/inputflinger/reader/EventHub.cpp
@@ -1177,7 +1177,8 @@ bool EventHub::markSupportedKeyCodes(int32_t deviceId, const std::vector<int32_t
return false;
}
-void EventHub::addKeyRemapping(int32_t deviceId, int32_t fromKeyCode, int32_t toKeyCode) const {
+void EventHub::setKeyRemapping(int32_t deviceId,
+ const std::map<int32_t, int32_t>& keyRemapping) const {
std::scoped_lock _l(mLock);
Device* device = getDeviceLocked(deviceId);
if (device == nullptr) {
@@ -1185,7 +1186,7 @@ void EventHub::addKeyRemapping(int32_t deviceId, int32_t fromKeyCode, int32_t to
}
const std::shared_ptr<KeyCharacterMap> kcm = device->getKeyCharacterMap();
if (kcm) {
- kcm->addKeyRemapping(fromKeyCode, toKeyCode);
+ kcm->setKeyRemapping(keyRemapping);
}
}
diff --git a/services/inputflinger/reader/InputDevice.cpp b/services/inputflinger/reader/InputDevice.cpp
index 70f024ea96..6185f1ab9e 100644
--- a/services/inputflinger/reader/InputDevice.cpp
+++ b/services/inputflinger/reader/InputDevice.cpp
@@ -365,6 +365,18 @@ std::list<NotifyArgs> InputDevice::configureInternal(nsecs_t when,
// so update the enabled state when there is a change in display info.
out += updateEnableState(when, readerConfig, forceEnable);
}
+
+ if (!changes.any() || changes.test(InputReaderConfiguration::Change::KEY_REMAPPING)) {
+ const bool isFullKeyboard =
+ (mSources & AINPUT_SOURCE_KEYBOARD) == AINPUT_SOURCE_KEYBOARD &&
+ mKeyboardType == KeyboardType::ALPHABETIC;
+ if (isFullKeyboard) {
+ for_each_subdevice([&readerConfig](auto& context) {
+ context.setKeyRemapping(readerConfig.keyRemapping);
+ });
+ bumpGeneration();
+ }
+ }
}
return out;
}
@@ -689,12 +701,6 @@ void InputDevice::updateMetaState(int32_t keyCode) {
});
}
-void InputDevice::addKeyRemapping(int32_t fromKeyCode, int32_t toKeyCode) {
- for_each_subdevice([fromKeyCode, toKeyCode](auto& context) {
- context.addKeyRemapping(fromKeyCode, toKeyCode);
- });
-}
-
void InputDevice::bumpGeneration() {
mGeneration = mContext->bumpGeneration();
}
diff --git a/services/inputflinger/reader/InputReader.cpp b/services/inputflinger/reader/InputReader.cpp
index a6f5df7593..8b664d5c4e 100644
--- a/services/inputflinger/reader/InputReader.cpp
+++ b/services/inputflinger/reader/InputReader.cpp
@@ -626,15 +626,6 @@ bool InputReader::markSupportedKeyCodesLocked(int32_t deviceId, uint32_t sourceM
return result;
}
-void InputReader::addKeyRemapping(int32_t deviceId, int32_t fromKeyCode, int32_t toKeyCode) const {
- std::scoped_lock _l(mLock);
-
- InputDevice* device = findInputDeviceLocked(deviceId);
- if (device != nullptr) {
- device->addKeyRemapping(fromKeyCode, toKeyCode);
- }
-}
-
int32_t InputReader::getKeyCodeForKeyLocation(int32_t deviceId, int32_t locationKeyCode) const {
std::scoped_lock _l(mLock);
diff --git a/services/inputflinger/reader/include/EventHub.h b/services/inputflinger/reader/include/EventHub.h
index 657126a825..edc30379b2 100644
--- a/services/inputflinger/reader/include/EventHub.h
+++ b/services/inputflinger/reader/include/EventHub.h
@@ -281,8 +281,8 @@ public:
virtual bool hasMscEvent(int32_t deviceId, int mscEvent) const = 0;
- virtual void addKeyRemapping(int32_t deviceId, int32_t fromKeyCode,
- int32_t toKeyCode) const = 0;
+ virtual void setKeyRemapping(int32_t deviceId,
+ const std::map<int32_t, int32_t>& keyRemapping) const = 0;
virtual status_t mapKey(int32_t deviceId, int32_t scanCode, int32_t usageCode,
int32_t metaState, int32_t* outKeycode, int32_t* outMetaState,
@@ -513,8 +513,8 @@ public:
bool hasMscEvent(int32_t deviceId, int mscEvent) const override final;
- void addKeyRemapping(int32_t deviceId, int32_t fromKeyCode,
- int32_t toKeyCode) const override final;
+ void setKeyRemapping(int32_t deviceId,
+ const std::map<int32_t, int32_t>& keyRemapping) const override final;
status_t mapKey(int32_t deviceId, int32_t scanCode, int32_t usageCode, int32_t metaState,
int32_t* outKeycode, int32_t* outMetaState,
diff --git a/services/inputflinger/reader/include/InputDevice.h b/services/inputflinger/reader/include/InputDevice.h
index 021978dee7..62cc4da5ec 100644
--- a/services/inputflinger/reader/include/InputDevice.h
+++ b/services/inputflinger/reader/include/InputDevice.h
@@ -124,8 +124,6 @@ public:
int32_t getMetaState();
void updateMetaState(int32_t keyCode);
- void addKeyRemapping(int32_t fromKeyCode, int32_t toKeyCode);
-
void setKeyboardType(KeyboardType keyboardType);
void bumpGeneration();
@@ -329,8 +327,8 @@ public:
inline bool hasMscEvent(int mscEvent) const { return mEventHub->hasMscEvent(mId, mscEvent); }
- inline void addKeyRemapping(int32_t fromKeyCode, int32_t toKeyCode) const {
- mEventHub->addKeyRemapping(mId, fromKeyCode, toKeyCode);
+ inline void setKeyRemapping(const std::map<int32_t, int32_t>& keyRemapping) const {
+ mEventHub->setKeyRemapping(mId, keyRemapping);
}
inline status_t mapKey(int32_t scanCode, int32_t usageCode, int32_t metaState,
diff --git a/services/inputflinger/reader/include/InputReader.h b/services/inputflinger/reader/include/InputReader.h
index 2cc0a00496..100387195a 100644
--- a/services/inputflinger/reader/include/InputReader.h
+++ b/services/inputflinger/reader/include/InputReader.h
@@ -65,8 +65,6 @@ public:
int32_t getKeyCodeState(int32_t deviceId, uint32_t sourceMask, int32_t keyCode) override;
int32_t getSwitchState(int32_t deviceId, uint32_t sourceMask, int32_t sw) override;
- void addKeyRemapping(int32_t deviceId, int32_t fromKeyCode, int32_t toKeyCode) const override;
-
int32_t getKeyCodeForKeyLocation(int32_t deviceId, int32_t locationKeyCode) const override;
void toggleCapsLockState(int32_t deviceId) override;
diff --git a/services/inputflinger/tests/FakeEventHub.cpp b/services/inputflinger/tests/FakeEventHub.cpp
index 31fbf209a3..943de6e3cf 100644
--- a/services/inputflinger/tests/FakeEventHub.cpp
+++ b/services/inputflinger/tests/FakeEventHub.cpp
@@ -151,9 +151,10 @@ void FakeEventHub::addKeyCodeMapping(int32_t deviceId, int32_t fromKeyCode, int3
getDevice(deviceId)->keyCodeMapping.insert_or_assign(fromKeyCode, toKeyCode);
}
-void FakeEventHub::addKeyRemapping(int32_t deviceId, int32_t fromKeyCode, int32_t toKeyCode) const {
+void FakeEventHub::setKeyRemapping(int32_t deviceId,
+ const std::map<int32_t, int32_t>& keyRemapping) const {
Device* device = getDevice(deviceId);
- device->keyRemapping.insert_or_assign(fromKeyCode, toKeyCode);
+ device->keyRemapping = keyRemapping;
}
void FakeEventHub::addLed(int32_t deviceId, int32_t led, bool initialState) {
diff --git a/services/inputflinger/tests/FakeEventHub.h b/services/inputflinger/tests/FakeEventHub.h
index 3d8dddd532..2dfbb2388a 100644
--- a/services/inputflinger/tests/FakeEventHub.h
+++ b/services/inputflinger/tests/FakeEventHub.h
@@ -55,7 +55,7 @@ class FakeEventHub : public EventHubInterface {
KeyedVector<int32_t, int32_t> absoluteAxisValue;
KeyedVector<int32_t, KeyInfo> keysByScanCode;
KeyedVector<int32_t, KeyInfo> keysByUsageCode;
- std::unordered_map<int32_t, int32_t> keyRemapping;
+ std::map<int32_t, int32_t> keyRemapping;
KeyedVector<int32_t, bool> leds;
// fake mapping which would normally come from keyCharacterMap
std::unordered_map<int32_t, int32_t> keyCodeMapping;
@@ -129,7 +129,7 @@ public:
void addKey(int32_t deviceId, int32_t scanCode, int32_t usageCode, int32_t keyCode,
uint32_t flags);
void addKeyCodeMapping(int32_t deviceId, int32_t fromKeyCode, int32_t toKeyCode);
- void addKeyRemapping(int32_t deviceId, int32_t fromKeyCode, int32_t toKeyCode) const;
+ void setKeyRemapping(int32_t deviceId, const std::map<int32_t, int32_t>& keyRemapping) const;
void addVirtualKeyDefinition(int32_t deviceId, const VirtualKeyDefinition& definition);
void addSensorAxis(int32_t deviceId, int32_t absCode, InputDeviceSensorType sensorType,
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index f066b031f3..c5702e92d9 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -1913,6 +1913,99 @@ TEST_F(InputDispatcherTest, HoverMoveAndScroll) {
window->consumeMotionEvent(WithMotionAction(ACTION_SCROLL));
}
+/**
+ * Two windows: a trusted overlay and a regular window underneath. Both windows are visible.
+ * Mouse is hovered, and the hover event should only go to the overlay.
+ * However, next, the touchable region of the trusted overlay shrinks. The mouse position hasn't
+ * changed, but the cursor would now end up hovering above the regular window underneatch.
+ * If the mouse is now clicked, this would generate an ACTION_DOWN event, which would go to the
+ * regular window. However, the trusted overlay is also watching for outside touch.
+ * The trusted overlay should get two events:
+ * 1) The ACTION_OUTSIDE event, since the click is now not inside its touchable region
+ * 2) The HOVER_EXIT event, since the mouse pointer is no longer hovering inside this window
+ *
+ * This test reproduces a crash where there is an overlap between dispatch modes for the trusted
+ * overlay touch target, since the event is causing both an ACTION_OUTSIDE, and as a HOVER_EXIT.
+ */
+TEST_F(InputDispatcherTest, MouseClickUnderShrinkingTrustedOverlay) {
+ std::shared_ptr<FakeApplicationHandle> app = std::make_shared<FakeApplicationHandle>();
+ sp<FakeWindowHandle> overlay = sp<FakeWindowHandle>::make(app, mDispatcher, "Trusted overlay",
+ ui::LogicalDisplayId::DEFAULT);
+ overlay->setTrustedOverlay(true);
+ overlay->setWatchOutsideTouch(true);
+ overlay->setFrame(Rect(0, 0, 200, 200));
+
+ sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(app, mDispatcher, "Regular window",
+ ui::LogicalDisplayId::DEFAULT);
+ window->setFrame(Rect(0, 0, 200, 200));
+
+ mDispatcher->onWindowInfosChanged({{*overlay->getInfo(), *window->getInfo()}, {}, 0, 0});
+ // Hover the mouse into the overlay
+ mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
+ .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(110))
+ .build());
+ overlay->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
+
+ // Now, shrink the touchable region of the overlay! This will cause the cursor to suddenly have
+ // the regular window as the touch target
+ overlay->setTouchableRegion(Region({0, 0, 0, 0}));
+ mDispatcher->onWindowInfosChanged({{*overlay->getInfo(), *window->getInfo()}, {}, 0, 0});
+
+ // Now we can click with the mouse. The click should go into the regular window
+ mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE)
+ .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(110))
+ .build());
+ overlay->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
+ overlay->consumeMotionEvent(WithMotionAction(ACTION_OUTSIDE));
+ window->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
+}
+
+/**
+ * Similar to above, but also has a spy on top that also catches the HOVER
+ * events. Also, instead of ACTION_DOWN, we are continuing to send the hovering
+ * stream to ensure that the spy receives hover events correctly.
+ */
+TEST_F(InputDispatcherTest, MouseClickUnderShrinkingTrustedOverlayWithSpy) {
+ std::shared_ptr<FakeApplicationHandle> app = std::make_shared<FakeApplicationHandle>();
+ sp<FakeWindowHandle> spyWindow =
+ sp<FakeWindowHandle>::make(app, mDispatcher, "Spy", ui::LogicalDisplayId::DEFAULT);
+ spyWindow->setFrame(Rect(0, 0, 200, 200));
+ spyWindow->setTrustedOverlay(true);
+ spyWindow->setSpy(true);
+ sp<FakeWindowHandle> overlay = sp<FakeWindowHandle>::make(app, mDispatcher, "Trusted overlay",
+ ui::LogicalDisplayId::DEFAULT);
+ overlay->setTrustedOverlay(true);
+ overlay->setWatchOutsideTouch(true);
+ overlay->setFrame(Rect(0, 0, 200, 200));
+
+ sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(app, mDispatcher, "Regular window",
+ ui::LogicalDisplayId::DEFAULT);
+ window->setFrame(Rect(0, 0, 200, 200));
+
+ mDispatcher->onWindowInfosChanged(
+ {{*spyWindow->getInfo(), *overlay->getInfo(), *window->getInfo()}, {}, 0, 0});
+ // Hover the mouse into the overlay
+ mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
+ .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(110))
+ .build());
+ spyWindow->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
+ overlay->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
+
+ // Now, shrink the touchable region of the overlay! This will cause the cursor to suddenly have
+ // the regular window as the touch target
+ overlay->setTouchableRegion(Region({0, 0, 0, 0}));
+ mDispatcher->onWindowInfosChanged(
+ {{*spyWindow->getInfo(), *overlay->getInfo(), *window->getInfo()}, {}, 0, 0});
+
+ // Now we can click with the mouse. The click should go into the regular window
+ mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
+ .pointer(PointerBuilder(0, ToolType::MOUSE).x(110).y(110))
+ .build());
+ spyWindow->consumeMotionEvent(WithMotionAction(ACTION_HOVER_MOVE));
+ overlay->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT));
+ window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
+}
+
using InputDispatcherMultiDeviceTest = InputDispatcherTest;
/**
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index 4a9e89319d..17c37d5a41 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -3330,11 +3330,11 @@ TEST_F(KeyboardInputMapperTest, Process_SimpleKeyPress) {
TEST_F(KeyboardInputMapperTest, Process_KeyRemapping) {
mFakeEventHub->addKey(EVENTHUB_ID, KEY_A, 0, AKEYCODE_A, 0);
mFakeEventHub->addKey(EVENTHUB_ID, KEY_B, 0, AKEYCODE_B, 0);
- mFakeEventHub->addKeyRemapping(EVENTHUB_ID, AKEYCODE_A, AKEYCODE_B);
KeyboardInputMapper& mapper =
constructAndAddMapper<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD);
+ mFakeEventHub->setKeyRemapping(EVENTHUB_ID, {{AKEYCODE_A, AKEYCODE_B}});
// Key down by scan code.
process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_A, 1);
NotifyKeyArgs args;
diff --git a/services/inputflinger/tests/InterfaceMocks.h b/services/inputflinger/tests/InterfaceMocks.h
index 5a3d79da5e..f41b39ac8e 100644
--- a/services/inputflinger/tests/InterfaceMocks.h
+++ b/services/inputflinger/tests/InterfaceMocks.h
@@ -97,7 +97,8 @@ public:
MOCK_METHOD(bool, hasRelativeAxis, (int32_t deviceId, int axis), (const));
MOCK_METHOD(bool, hasInputProperty, (int32_t deviceId, int property), (const));
MOCK_METHOD(bool, hasMscEvent, (int32_t deviceId, int mscEvent), (const));
- MOCK_METHOD(void, addKeyRemapping, (int32_t deviceId, int fromKeyCode, int toKeyCode), (const));
+ MOCK_METHOD(void, setKeyRemapping,
+ (int32_t deviceId, (const std::map<int32_t, int32_t>& keyRemapping)), (const));
MOCK_METHOD(status_t, mapKey,
(int32_t deviceId, int scanCode, int usageCode, int32_t metaState,
int32_t* outKeycode, int32_t* outMetaState, uint32_t* outFlags),
@@ -247,8 +248,6 @@ public:
MOCK_METHOD(int32_t, getMetaState, (), ());
MOCK_METHOD(void, updateMetaState, (int32_t keyCode), ());
- MOCK_METHOD(void, addKeyRemapping, (int32_t fromKeyCode, int32_t toKeyCode), ());
-
MOCK_METHOD(void, setKeyboardType, (KeyboardType keyboardType), ());
MOCK_METHOD(void, bumpGeneration, (), ());
diff --git a/services/inputflinger/tests/LatencyTracker_test.cpp b/services/inputflinger/tests/LatencyTracker_test.cpp
index 0f92833e64..3f14c2312b 100644
--- a/services/inputflinger/tests/LatencyTracker_test.cpp
+++ b/services/inputflinger/tests/LatencyTracker_test.cpp
@@ -87,7 +87,7 @@ protected:
connection1 = sp<BBinder>::make();
connection2 = sp<BBinder>::make();
- mTracker = std::make_unique<LatencyTracker>(this);
+ mTracker = std::make_unique<LatencyTracker>(*this);
setDefaultInputDeviceInfo(*mTracker);
}
void TearDown() override {}
@@ -106,6 +106,8 @@ private:
void processTimeline(const InputEventTimeline& timeline) override {
mReceivedTimelines.push_back(timeline);
}
+ void pushLatencyStatistics() override {}
+ std::string dump(const char* prefix) const { return ""; };
std::deque<InputEventTimeline> mReceivedTimelines;
};
diff --git a/services/inputflinger/tests/fuzzers/InputReaderFuzzer.cpp b/services/inputflinger/tests/fuzzers/InputReaderFuzzer.cpp
index 3e4a19becd..5442a65f2f 100644
--- a/services/inputflinger/tests/fuzzers/InputReaderFuzzer.cpp
+++ b/services/inputflinger/tests/fuzzers/InputReaderFuzzer.cpp
@@ -155,10 +155,6 @@ public:
return reader->getLightPlayerId(deviceId, lightId);
}
- void addKeyRemapping(int32_t deviceId, int32_t fromKeyCode, int32_t toKeyCode) const {
- reader->addKeyRemapping(deviceId, fromKeyCode, toKeyCode);
- }
-
int32_t getKeyCodeForKeyLocation(int32_t deviceId, int32_t locationKeyCode) const {
return reader->getKeyCodeForKeyLocation(deviceId, locationKeyCode);
}
diff --git a/services/inputflinger/tests/fuzzers/LatencyTrackerFuzzer.cpp b/services/inputflinger/tests/fuzzers/LatencyTrackerFuzzer.cpp
index 695eb3c5dd..908fa40f05 100644
--- a/services/inputflinger/tests/fuzzers/LatencyTrackerFuzzer.cpp
+++ b/services/inputflinger/tests/fuzzers/LatencyTrackerFuzzer.cpp
@@ -38,6 +38,10 @@ public:
connectionTimeline.isComplete();
}
};
+
+ void pushLatencyStatistics() override {}
+
+ std::string dump(const char* prefix) const { return ""; };
};
static sp<IBinder> getConnectionToken(FuzzedDataProvider& fdp,
@@ -53,7 +57,7 @@ extern "C" int LLVMFuzzerTestOneInput(uint8_t* data, size_t size) {
FuzzedDataProvider fdp(data, size);
EmptyProcessor emptyProcessor;
- LatencyTracker tracker(&emptyProcessor);
+ LatencyTracker tracker(emptyProcessor);
// Make some pre-defined tokens to ensure that some timelines are complete.
std::array<sp<IBinder> /*token*/, 10> predefinedTokens;
diff --git a/services/inputflinger/tests/fuzzers/MapperHelpers.h b/services/inputflinger/tests/fuzzers/MapperHelpers.h
index 7e362f4e35..fa8270a3d9 100644
--- a/services/inputflinger/tests/fuzzers/MapperHelpers.h
+++ b/services/inputflinger/tests/fuzzers/MapperHelpers.h
@@ -202,7 +202,8 @@ public:
int32_t getSwitchState(int32_t deviceId, int32_t sw) const override {
return mFdp->ConsumeIntegral<int32_t>();
}
- void addKeyRemapping(int32_t deviceId, int32_t fromKeyCode, int32_t toKeyCode) const override {}
+ void setKeyRemapping(int32_t deviceId,
+ const std::map<int32_t, int32_t>& keyRemapping) const override {}
int32_t getKeyCodeForKeyLocation(int32_t deviceId, int32_t locationKeyCode) const override {
return mFdp->ConsumeIntegral<int32_t>();
}
diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp
index ac15b92175..ee605b7a3e 100644
--- a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp
+++ b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp
@@ -279,24 +279,6 @@ void updateVisibility(LayerSnapshot& snapshot, bool visible) {
snapshot.getDebugString().c_str());
}
-bool needsInputInfo(const LayerSnapshot& snapshot, const RequestedLayerState& requested) {
- if (requested.potentialCursor) {
- return false;
- }
-
- if (snapshot.inputInfo.token != nullptr) {
- return true;
- }
-
- if (snapshot.hasBufferOrSidebandStream()) {
- return true;
- }
-
- return requested.windowInfoHandle &&
- requested.windowInfoHandle->getInfo()->inputConfig.test(
- gui::WindowInfo::InputConfig::NO_INPUT_CHANNEL);
-}
-
void updateMetadata(LayerSnapshot& snapshot, const RequestedLayerState& requested,
const LayerSnapshotBuilder::Args& args) {
snapshot.metadata.clear();
@@ -1162,7 +1144,7 @@ void LayerSnapshotBuilder::updateInput(LayerSnapshot& snapshot,
}
updateVisibility(snapshot, snapshot.isVisible);
- if (!needsInputInfo(snapshot, requested)) {
+ if (!requested.needsInputInfo()) {
return;
}
@@ -1172,7 +1154,7 @@ void LayerSnapshotBuilder::updateInput(LayerSnapshot& snapshot,
bool noValidDisplay = !displayInfoOpt.has_value();
auto displayInfo = displayInfoOpt.value_or(sDefaultInfo);
- if (!requested.windowInfoHandle) {
+ if (!requested.hasInputInfo()) {
snapshot.inputInfo.inputConfig = InputConfig::NO_INPUT_CHANNEL;
}
fillInputFrameInfo(snapshot.inputInfo, displayInfo.transform, snapshot);
diff --git a/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp b/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp
index 17d2610d7a..5734ccf38f 100644
--- a/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp
+++ b/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp
@@ -62,6 +62,8 @@ RequestedLayerState::RequestedLayerState(const LayerCreationArgs& args)
metadata.merge(args.metadata);
changes |= RequestedLayerState::Changes::Metadata;
handleAlive = true;
+ // TODO: b/305254099 remove once we don't pass invisible windows to input
+ windowInfoHandle = nullptr;
if (parentId != UNASSIGNED_LAYER_ID) {
canBeRoot = false;
}
@@ -553,6 +555,24 @@ bool RequestedLayerState::hasInputInfo() const {
windowInfo->inputConfig.test(gui::WindowInfo::InputConfig::NO_INPUT_CHANNEL);
}
+bool RequestedLayerState::needsInputInfo() const {
+ if (potentialCursor) {
+ return false;
+ }
+
+ if ((sidebandStream != nullptr) || (externalTexture != nullptr)) {
+ return true;
+ }
+
+ if (!windowInfoHandle) {
+ return false;
+ }
+
+ const auto windowInfo = windowInfoHandle->getInfo();
+ return windowInfo->token != nullptr ||
+ windowInfo->inputConfig.test(gui::WindowInfo::InputConfig::NO_INPUT_CHANNEL);
+}
+
bool RequestedLayerState::hasBlur() const {
return backgroundBlurRadius > 0 || blurRegions.size() > 0;
}
diff --git a/services/surfaceflinger/FrontEnd/RequestedLayerState.h b/services/surfaceflinger/FrontEnd/RequestedLayerState.h
index 48b9640486..1d96dff336 100644
--- a/services/surfaceflinger/FrontEnd/RequestedLayerState.h
+++ b/services/surfaceflinger/FrontEnd/RequestedLayerState.h
@@ -87,6 +87,7 @@ struct RequestedLayerState : layer_state_t {
aidl::android::hardware::graphics::composer3::Composition getCompositionType() const;
bool hasValidRelativeParent() const;
bool hasInputInfo() const;
+ bool needsInputInfo() const;
bool hasBlur() const;
bool hasFrameUpdate() const;
bool hasReadyFrame() const;
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index c17ea3b579..dcb0812b67 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -355,26 +355,6 @@ aidl::android::hardware::graphics::composer3::Composition Layer::getCompositionT
// transaction
// ----------------------------------------------------------------------------
-uint32_t Layer::doTransaction(uint32_t flags) {
- SFTRACE_CALL();
-
- const State& s(getDrawingState());
-
- if (s.sequence != mLastCommittedTxSequence) {
- // invalidate and recompute the visible regions if needed
- mLastCommittedTxSequence = s.sequence;
- flags |= eVisibleRegion;
- }
-
- if (!mPotentialCursor && (flags & Layer::eVisibleRegion)) {
- mFlinger->mUpdateInputInfo = true;
- }
-
- commitTransaction();
-
- return flags;
-}
-
void Layer::commitTransaction() {
// Set the present state for all bufferlessSurfaceFramesTX to Presented. The
// bufferSurfaceFrameTX will be presented in latchBuffer.
@@ -389,12 +369,6 @@ void Layer::commitTransaction() {
mDrawingState.bufferlessSurfaceFramesTX.clear();
}
-uint32_t Layer::clearTransactionFlags(uint32_t mask) {
- const auto flags = mTransactionFlags & mask;
- mTransactionFlags &= ~mask;
- return flags;
-}
-
void Layer::setTransactionFlags(uint32_t mask) {
mTransactionFlags |= mask;
}
@@ -769,10 +743,6 @@ void Layer::prepareReleaseCallbacks(ftl::Future<FenceResult> futureFenceResult,
// Older fences for the same layer stack can be dropped when a new fence arrives.
// An assumption here is that RenderEngine performs work sequentially, so an
// incoming fence will not fire before an existing fence.
- SFTRACE_NAME(
- ftl::Concat("Adding additional fence for: ", ftl::truncated<20>(mName.c_str()),
- ", Replacing?: ", mAdditionalPreviousReleaseFences.contains(layerStack))
- .c_str());
mAdditionalPreviousReleaseFences.emplace_or_replace(layerStack,
std::move(futureFenceResult));
}
@@ -871,16 +841,6 @@ bool Layer::setTransformToDisplayInverse(bool transformToDisplayInverse) {
return true;
}
-bool Layer::setBufferCrop(const Rect& bufferCrop) {
- if (mDrawingState.bufferCrop == bufferCrop) return false;
-
- mDrawingState.sequence++;
- mDrawingState.bufferCrop = bufferCrop;
-
- setTransactionFlags(eTransactionNeeded);
- return true;
-}
-
void Layer::releasePreviousBuffer() {
mReleasePreviousBuffer = true;
if (!mBufferInfo.mBuffer ||
@@ -1495,10 +1455,6 @@ void Layer::onCompositionPresented(const DisplayDevice* display,
mBufferInfo.mFrameLatencyNeeded = false;
}
-bool Layer::willReleaseBufferOnLatch() const {
- return !mDrawingState.buffer && mBufferInfo.mBuffer;
-}
-
bool Layer::latchBufferImpl(bool& recomputeVisibleRegions, nsecs_t latchTime, bool bgColorOnly) {
SFTRACE_FORMAT_INSTANT("latchBuffer %s - %" PRIu64, getDebugName(),
getDrawingState().frameNumber);
@@ -1559,34 +1515,10 @@ bool Layer::latchBufferImpl(bool& recomputeVisibleRegions, nsecs_t latchTime, bo
return true;
}
-bool Layer::isProtected() const {
- return (mBufferInfo.mBuffer != nullptr) &&
- (mBufferInfo.mBuffer->getUsage() & GRALLOC_USAGE_PROTECTED);
-}
-
bool Layer::getTransformToDisplayInverse() const {
return mBufferInfo.mTransformToDisplayInverse;
}
-Rect Layer::getBufferCrop() const {
- // this is the crop rectangle that applies to the buffer
- // itself (as opposed to the window)
- if (!mBufferInfo.mCrop.isEmpty()) {
- // if the buffer crop is defined, we use that
- return mBufferInfo.mCrop;
- } else if (mBufferInfo.mBuffer != nullptr) {
- // otherwise we use the whole buffer
- return mBufferInfo.mBuffer->getBounds();
- } else {
- // if we don't have a buffer yet, we use an empty/invalid crop
- return Rect();
- }
-}
-
-uint32_t Layer::getBufferTransform() const {
- return mBufferInfo.mTransform;
-}
-
ui::Dataspace Layer::translateDataspace(ui::Dataspace dataspace) {
ui::Dataspace updatedDataspace = dataspace;
// translate legacy dataspaces to modern dataspaces
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 9caa20cfb8..9bc557e917 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -88,12 +88,6 @@ public:
// Windows that are not in focus, but voted for a specific mode ID.
static constexpr int32_t PRIORITY_NOT_FOCUSED_WITH_MODE = 2;
- enum { // flags for doTransaction()
- eDontUpdateGeometryState = 0x00000001,
- eVisibleRegion = 0x00000002,
- eInputInfoChanged = 0x00000004
- };
-
using FrameRate = scheduler::LayerInfo::FrameRate;
using FrameRateCompatibility = scheduler::FrameRateCompatibility;
using FrameRateSelectionStrategy = scheduler::LayerInfo::FrameRateSelectionStrategy;
@@ -171,9 +165,6 @@ public:
static bool isLayerFocusedBasedOnPriority(int32_t priority);
static void miniDumpHeader(std::string& result);
- // Provide unique string for each class type in the Layer hierarchy
- const char* getType() const { return "Layer"; }
-
// This second set of geometry attributes are controlled by
// setGeometryAppliesWithResize, and their default mode is to be
// immediate. If setGeometryAppliesWithResize is specified
@@ -200,7 +191,6 @@ public:
bool willPresent);
sp<LayerFE> getCompositionEngineLayerFE(const frontend::LayerHierarchy::TraversalPath&);
- sp<LayerFE> getOrCreateCompositionEngineLayerFE(const frontend::LayerHierarchy::TraversalPath&);
// If we have received a new buffer this frame, we will pass its surface
// damage down to hardware composer. Otherwise, we must send a region with
@@ -208,18 +198,7 @@ public:
Region getVisibleRegion(const DisplayDevice*) const;
void updateLastLatchTime(nsecs_t latchtime);
- /*
- * isProtected - true if the layer may contain protected contents in the
- * GRALLOC_USAGE_PROTECTED sense.
- */
- bool isProtected() const;
- /*
- * usesSourceCrop - true if content should use a source crop
- */
- bool usesSourceCrop() const { return hasBufferOrSidebandStream(); }
-
Rect getCrop(const Layer::State& s) const { return s.crop; }
- bool needsFiltering(const DisplayDevice*) const;
// from graphics API
static ui::Dataspace translateDataspace(ui::Dataspace dataspace);
@@ -242,23 +221,6 @@ public:
bool latchBufferImpl(bool& /*recomputeVisibleRegions*/, nsecs_t /*latchTime*/,
bool bgColorOnly);
- /*
- * Returns true if the currently presented buffer will be released when this layer state
- * is latched. This will return false if there is no buffer currently presented.
- */
- bool willReleaseBufferOnLatch() const;
-
- /*
- * returns the rectangle that crops the content of the layer and scales it
- * to the layer's size.
- */
- Rect getBufferCrop() const;
-
- /*
- * Returns the transform applied to the buffer.
- */
- uint32_t getBufferTransform() const;
-
sp<GraphicBuffer> getBuffer() const;
/**
* Returns active buffer size in the correct orientation. Buffer size is determined by undoing
@@ -313,8 +275,6 @@ public:
const char* getDebugName() const;
- uint32_t getTransactionFlags() const { return mTransactionFlags; }
-
static bool computeTrustedPresentationState(const FloatRect& bounds,
const FloatRect& sourceBounds,
const Region& coveredRegion,
@@ -332,9 +292,6 @@ public:
// Sets the masked bits.
void setTransactionFlags(uint32_t mask);
- // Clears and returns the masked bits.
- uint32_t clearTransactionFlags(uint32_t mask);
-
int32_t getSequence() const { return sequence; }
// For tracing.
@@ -348,14 +305,6 @@ public:
void writeCompositionStateToProto(perfetto::protos::LayerProto* layerProto,
ui::LayerStack layerStack);
- gui::WindowInfo::Type getWindowType() const { return mWindowType; }
-
- /*
- * doTransaction - process the transaction. This is a good place to figure
- * out which attributes of the surface have changed.
- */
- uint32_t doTransaction(uint32_t transactionFlags);
-
inline const State& getDrawingState() const { return mDrawingState; }
inline State& getDrawingState() { return mDrawingState; }
@@ -366,13 +315,6 @@ public:
void getFrameStats(FrameStats* outStats) const;
void onDisconnect();
- ui::Transform getTransform() const;
-
- half4 getColor() const;
- int32_t getBackgroundBlurRadius() const;
- bool drawShadows() const { return mEffectiveShadowRadius > 0.f; };
-
- bool isHandleAlive() const { return mHandleAlive; }
bool onHandleDestroyed() { return mHandleAlive = false; }
/**
@@ -383,7 +325,6 @@ public:
*/
Rect getCroppedBufferSize(const Layer::State& s) const;
- void setFrameTimelineInfoForBuffer(const FrameTimelineInfo& /*info*/) {}
void setFrameTimelineVsyncForBufferTransaction(const FrameTimelineInfo& info, nsecs_t postTime,
gui::GameMode gameMode);
void setFrameTimelineVsyncForBufferlessTransaction(const FrameTimelineInfo& info,
@@ -412,14 +353,9 @@ public:
// this to be called once.
sp<IBinder> getHandle();
const std::string& getName() const { return mName; }
- void setInputInfo(const gui::WindowInfo& info);
virtual uid_t getOwnerUid() const { return mOwnerUid; }
- pid_t getOwnerPid() { return mOwnerPid; }
-
- int32_t getOwnerAppId() { return mOwnerAppId; }
-
// Used to check if mUsedVsyncIdForRefreshRateSelection should be expired when it stop updating.
nsecs_t mMaxTimeForUseVsyncId = 0;
// True when DrawState.useVsyncIdForRefreshRateSelection previously set to true during updating
@@ -431,9 +367,6 @@ public:
// the same.
const int32_t sequence;
- bool mPendingHWCDestroy{false};
-
- bool setBufferCrop(const Rect& /* bufferCrop */);
// See mPendingBufferTransactions
void decrementPendingBufferCount();
std::atomic<int32_t>* getPendingBufferCounter() { return &mPendingBufferTransactions; }
@@ -513,10 +446,6 @@ protected:
int64_t mEnteredTrustedPresentationStateTime = -1;
uint32_t mTransactionFlags{0};
- // Updated in doTransaction, used to track the last sequence number we
- // committed. Currently this is really only used for updating visible
- // regions.
- int32_t mLastCommittedTxSequence = -1;
// Timestamp history for UIAutomation. Thread safe.
FrameTracker mFrameTracker;
@@ -632,7 +561,7 @@ private:
// You can understand the trace this way:
// - If the integer increases, a buffer arrived at the server.
// - If the integer decreases in latchBuffer, that buffer was latched
- // - If the integer decreases in setBuffer or doTransaction, a buffer was dropped
+ // - If the integer decreases in setBuffer, a buffer was dropped
std::atomic<int32_t> mPendingBufferTransactions{0};
// Contains requested position and matrix updates. This will be applied if the client does
diff --git a/services/surfaceflinger/OWNERS b/services/surfaceflinger/OWNERS
index ffc1dd7979..fa0ecee6b5 100644
--- a/services/surfaceflinger/OWNERS
+++ b/services/surfaceflinger/OWNERS
@@ -5,6 +5,8 @@ alecmouri@google.com
domlaskowski@google.com
jreck@google.com
lpy@google.com
+mattbuckley@google.com
+melodymhsu@google.com
pdwilliams@google.com
racarr@google.com
ramindani@google.com
@@ -12,3 +14,4 @@ rnlee@google.com
sallyqi@google.com
scroggo@google.com
vishnun@google.com
+xwxw@google.com
diff --git a/services/surfaceflinger/PowerAdvisor/OWNERS b/services/surfaceflinger/PowerAdvisor/OWNERS
new file mode 100644
index 0000000000..9f40e27a10
--- /dev/null
+++ b/services/surfaceflinger/PowerAdvisor/OWNERS
@@ -0,0 +1 @@
+file:platform/frameworks/base:/ADPF_OWNERS \ No newline at end of file
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 65a0ed3065..06560d06ba 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -946,16 +946,20 @@ void SurfaceFlinger::init() FTL_FAKE_GUARD(kMainThreadContext) {
}));
}));
- mLayerTracing.setTakeLayersSnapshotProtoFunction([&](uint32_t traceFlags) {
- auto snapshot = perfetto::protos::LayersSnapshotProto{};
- mScheduler
- ->schedule([&]() FTL_FAKE_GUARD(mStateLock) FTL_FAKE_GUARD(kMainThreadContext) {
- snapshot = takeLayersSnapshotProto(traceFlags, TimePoint::now(),
- mLastCommittedVsyncId, true);
- })
- .wait();
- return snapshot;
- });
+ mLayerTracing.setTakeLayersSnapshotProtoFunction(
+ [&](uint32_t traceFlags,
+ const LayerTracing::OnLayersSnapshotCallback& onLayersSnapshot) {
+ // Do not wait the future to avoid deadlocks
+ // between main and Perfetto threads (b/313130597)
+ static_cast<void>(mScheduler->schedule(
+ [&, onLayersSnapshot]() FTL_FAKE_GUARD(mStateLock)
+ FTL_FAKE_GUARD(kMainThreadContext) {
+ auto snapshot =
+ takeLayersSnapshotProto(traceFlags, TimePoint::now(),
+ mLastCommittedVsyncId, true);
+ onLayersSnapshot(std::move(snapshot));
+ }));
+ });
// Commit secondary display(s).
processDisplayChangesLocked();
diff --git a/services/surfaceflinger/Tracing/LayerDataSource.cpp b/services/surfaceflinger/Tracing/LayerDataSource.cpp
index ed1e2ec89c..cc0063cd2a 100644
--- a/services/surfaceflinger/Tracing/LayerDataSource.cpp
+++ b/services/surfaceflinger/Tracing/LayerDataSource.cpp
@@ -82,10 +82,13 @@ void LayerDataSource::OnFlush(const LayerDataSource::FlushArgs& args) {
}
}
-void LayerDataSource::OnStop(const LayerDataSource::StopArgs&) {
+void LayerDataSource::OnStop(const LayerDataSource::StopArgs& args) {
ALOGD("Received OnStop event (mode = 0x%02x, flags = 0x%02x)", mMode, mFlags);
if (auto* p = mLayerTracing.load()) {
- p->onStop(mMode);
+ // In dump mode we need to defer the stop (through HandleStopAsynchronously()) till
+ // the layers snapshot has been captured and written to perfetto. We must avoid writing
+ // to perfetto within the OnStop callback to prevent deadlocks (b/313130597).
+ p->onStop(mMode, mFlags, args.HandleStopAsynchronously());
}
}
diff --git a/services/surfaceflinger/Tracing/LayerTracing.cpp b/services/surfaceflinger/Tracing/LayerTracing.cpp
index d40b888504..d78f9bbbae 100644
--- a/services/surfaceflinger/Tracing/LayerTracing.cpp
+++ b/services/surfaceflinger/Tracing/LayerTracing.cpp
@@ -32,7 +32,7 @@
namespace android {
LayerTracing::LayerTracing() {
- mTakeLayersSnapshotProto = [](uint32_t) { return perfetto::protos::LayersSnapshotProto{}; };
+ mTakeLayersSnapshotProto = [](uint32_t, const OnLayersSnapshotCallback&) {};
LayerDataSource::Initialize(*this);
}
@@ -45,7 +45,7 @@ LayerTracing::~LayerTracing() {
}
void LayerTracing::setTakeLayersSnapshotProtoFunction(
- const std::function<perfetto::protos::LayersSnapshotProto(uint32_t)>& callback) {
+ const std::function<void(uint32_t, const OnLayersSnapshotCallback&)>& callback) {
mTakeLayersSnapshotProto = callback;
}
@@ -62,7 +62,10 @@ void LayerTracing::onStart(Mode mode, uint32_t flags) {
// It might take a while before a layers change occurs and a "spontaneous" snapshot is
// taken. Let's manually take a snapshot, so that the trace's first entry will contain
// the current layers state.
- addProtoSnapshotToOstream(mTakeLayersSnapshotProto(flags), Mode::MODE_ACTIVE);
+ auto onLayersSnapshot = [this](perfetto::protos::LayersSnapshotProto&& snapshot) {
+ addProtoSnapshotToOstream(std::move(snapshot), Mode::MODE_ACTIVE);
+ };
+ mTakeLayersSnapshotProto(flags, onLayersSnapshot);
ALOGD("Started active tracing (traced initial snapshot)");
break;
}
@@ -89,9 +92,7 @@ void LayerTracing::onStart(Mode mode, uint32_t flags) {
break;
}
case Mode::MODE_DUMP: {
- auto snapshot = mTakeLayersSnapshotProto(flags);
- addProtoSnapshotToOstream(std::move(snapshot), Mode::MODE_DUMP);
- ALOGD("Started dump tracing (dumped single snapshot)");
+ ALOGD("Started dump tracing");
break;
}
default: {
@@ -125,10 +126,27 @@ void LayerTracing::onFlush(Mode mode, uint32_t flags, bool isBugreport) {
ALOGD("Flushed generated tracing");
}
-void LayerTracing::onStop(Mode mode) {
- if (mode == Mode::MODE_ACTIVE) {
- mIsActiveTracingStarted.store(false);
- ALOGD("Stopped active tracing");
+void LayerTracing::onStop(Mode mode, uint32_t flags, std::function<void()>&& deferredStopDone) {
+ switch (mode) {
+ case Mode::MODE_ACTIVE: {
+ mIsActiveTracingStarted.store(false);
+ deferredStopDone();
+ ALOGD("Stopped active tracing");
+ break;
+ }
+ case Mode::MODE_DUMP: {
+ auto onLayersSnapshot = [this, deferredStopDone = std::move(deferredStopDone)](
+ perfetto::protos::LayersSnapshotProto&& snapshot) {
+ addProtoSnapshotToOstream(std::move(snapshot), Mode::MODE_DUMP);
+ deferredStopDone();
+ ALOGD("Stopped dump tracing (written single snapshot)");
+ };
+ mTakeLayersSnapshotProto(flags, onLayersSnapshot);
+ break;
+ }
+ default: {
+ deferredStopDone();
+ }
}
}
diff --git a/services/surfaceflinger/Tracing/LayerTracing.h b/services/surfaceflinger/Tracing/LayerTracing.h
index 2895ba7026..e99fe4c7f1 100644
--- a/services/surfaceflinger/Tracing/LayerTracing.h
+++ b/services/surfaceflinger/Tracing/LayerTracing.h
@@ -87,6 +87,7 @@ EOF
class LayerTracing {
public:
using Mode = perfetto::protos::pbzero::SurfaceFlingerLayersConfig::Mode;
+ using OnLayersSnapshotCallback = std::function<void(perfetto::protos::LayersSnapshotProto&&)>;
enum Flag : uint32_t {
TRACE_INPUT = 1 << 1,
@@ -102,7 +103,7 @@ public:
LayerTracing(std::ostream&);
~LayerTracing();
void setTakeLayersSnapshotProtoFunction(
- const std::function<perfetto::protos::LayersSnapshotProto(uint32_t)>&);
+ const std::function<void(uint32_t, const OnLayersSnapshotCallback&)>&);
void setTransactionTracing(TransactionTracing&);
// Start event from perfetto data source
@@ -110,7 +111,7 @@ public:
// Flush event from perfetto data source
void onFlush(Mode mode, uint32_t flags, bool isBugreport);
// Stop event from perfetto data source
- void onStop(Mode mode);
+ void onStop(Mode mode, uint32_t flags, std::function<void()>&& deferredStopDone);
void addProtoSnapshotToOstream(perfetto::protos::LayersSnapshotProto&& snapshot, Mode mode);
bool isActiveTracingStarted() const;
@@ -123,7 +124,7 @@ private:
void writeSnapshotToPerfetto(const perfetto::protos::LayersSnapshotProto& snapshot, Mode mode);
bool checkAndUpdateLastVsyncIdWrittenToPerfetto(Mode mode, std::int64_t vsyncId);
- std::function<perfetto::protos::LayersSnapshotProto(uint32_t)> mTakeLayersSnapshotProto;
+ std::function<void(uint32_t, const OnLayersSnapshotCallback&)> mTakeLayersSnapshotProto;
TransactionTracing* mTransactionTracing;
std::atomic<bool> mIsActiveTracingStarted{false};
diff --git a/services/surfaceflinger/TransactionCallbackInvoker.cpp b/services/surfaceflinger/TransactionCallbackInvoker.cpp
index 2b20648e42..c6856aea75 100644
--- a/services/surfaceflinger/TransactionCallbackInvoker.cpp
+++ b/services/surfaceflinger/TransactionCallbackInvoker.cpp
@@ -30,7 +30,6 @@
#include <binder/IInterface.h>
#include <common/FlagManager.h>
#include <common/trace.h>
-#include <ftl/concat.h>
#include <utils/RefBase.h>
namespace android {
@@ -130,9 +129,6 @@ status_t TransactionCallbackInvoker::addCallbackHandle(const sp<CallbackHandle>&
if (FlagManager::getInstance().ce_fence_promise()) {
for (auto& future : handle->previousReleaseFences) {
- SFTRACE_NAME(ftl::Concat("Merging fence for layer: ",
- ftl::truncated<20>(handle->name.c_str()))
- .c_str());
mergeFence(handle->name.c_str(), future.get().value_or(Fence::NO_FENCE), prevFence);
}
} else {
diff --git a/services/surfaceflinger/tests/unittests/LayerLifecycleManagerTest.cpp b/services/surfaceflinger/tests/unittests/LayerLifecycleManagerTest.cpp
index b4efe0fe14..c7cc21ce07 100644
--- a/services/surfaceflinger/tests/unittests/LayerLifecycleManagerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerLifecycleManagerTest.cpp
@@ -619,4 +619,14 @@ TEST_F(LayerLifecycleManagerTest, isSimpleBufferUpdate) {
}
}
+TEST_F(LayerLifecycleManagerTest, testInputInfoOfRequestedLayerState) {
+ // By default the layer has no buffer, so it doesn't need an input info
+ EXPECT_FALSE(getRequestedLayerState(mLifecycleManager, 111)->needsInputInfo());
+
+ setBuffer(111);
+ mLifecycleManager.commitChanges();
+
+ EXPECT_TRUE(getRequestedLayerState(mLifecycleManager, 111)->needsInputInfo());
+}
+
} // namespace android::surfaceflinger::frontend
diff --git a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp
index 90207232b0..75d2fa3c7f 100644
--- a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp
@@ -1762,6 +1762,7 @@ TEST_F(LayerSnapshotTest, hideLayerWithNanMatrix) {
UPDATE_AND_VERIFY(mSnapshotBuilder, {2});
EXPECT_TRUE(getSnapshot(1)->isHiddenByPolicy());
}
+
TEST_F(LayerSnapshotTest, edgeExtensionPropagatesInHierarchy) {
if (!com::android::graphics::libgui::flags::edge_extension_shader()) {
GTEST_SKIP() << "Skipping test because edge_extension_shader is off";
@@ -1920,4 +1921,18 @@ TEST_F(LayerSnapshotTest, multipleEdgeExtensionIncreaseBoundSizeWithinCrop) {
EXPECT_GE(getSnapshot({.id = 1221})->transformedBounds.top, 0);
}
+TEST_F(LayerSnapshotTest, shouldUpdateInputWhenNoInputInfo) {
+ // By default the layer has no buffer, so we don't expect it to have an input info
+ EXPECT_FALSE(getSnapshot(111)->hasInputInfo());
+
+ setBuffer(111);
+
+ UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER);
+
+ EXPECT_TRUE(getSnapshot(111)->hasInputInfo());
+ EXPECT_TRUE(getSnapshot(111)->inputInfo.inputConfig.test(
+ gui::WindowInfo::InputConfig::NO_INPUT_CHANNEL));
+ EXPECT_FALSE(getSnapshot(2)->hasInputInfo());
+}
+
} // namespace android::surfaceflinger::frontend
diff --git a/services/surfaceflinger/tests/unittests/TestableScheduler.h b/services/surfaceflinger/tests/unittests/TestableScheduler.h
index d92f891148..9de3346fb0 100644
--- a/services/surfaceflinger/tests/unittests/TestableScheduler.h
+++ b/services/surfaceflinger/tests/unittests/TestableScheduler.h
@@ -131,7 +131,9 @@ public:
using Scheduler::resyncAllToHardwareVsync;
auto& mutableLayerHistory() { return mLayerHistory; }
- auto& mutableAttachedChoreographers() { return mAttachedChoreographers; }
+ auto& mutableAttachedChoreographers() NO_THREAD_SAFETY_ANALYSIS {
+ return mAttachedChoreographers;
+ }
size_t layerHistorySize() NO_THREAD_SAFETY_ANALYSIS {
return mLayerHistory.mActiveLayerInfos.size() + mLayerHistory.mInactiveLayerInfos.size();
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index 347a396e74..c043b880ec 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -490,8 +490,10 @@ public:
return mFlinger->SurfaceFlinger::getDisplayNativePrimaries(displayToken, primaries);
}
- auto& getTransactionQueue() { return mFlinger->mTransactionHandler.mLocklessTransactionQueue; }
- auto& getPendingTransactionQueue() {
+ auto& getTransactionQueue() NO_THREAD_SAFETY_ANALYSIS {
+ return mFlinger->mTransactionHandler.mLocklessTransactionQueue;
+ }
+ auto& getPendingTransactionQueue() NO_THREAD_SAFETY_ANALYSIS {
ftl::FakeGuard guard(kMainThreadContext);
return mFlinger->mTransactionHandler.mPendingTransactionQueues;
}
@@ -659,8 +661,10 @@ public:
* post-conditions.
*/
- const auto& displays() const { return mFlinger->mDisplays; }
- const auto& physicalDisplays() const { return mFlinger->mPhysicalDisplays; }
+ const auto& displays() const NO_THREAD_SAFETY_ANALYSIS { return mFlinger->mDisplays; }
+ const auto& physicalDisplays() const NO_THREAD_SAFETY_ANALYSIS {
+ return mFlinger->mPhysicalDisplays;
+ }
const auto& currentState() const { return mFlinger->mCurrentState; }
const auto& drawingState() const { return mFlinger->mDrawingState; }
const auto& transactionFlags() const { return mFlinger->mTransactionFlags; }
@@ -673,13 +677,17 @@ public:
auto& mutableDisplayModeController() { return mFlinger->mDisplayModeController; }
auto& mutableCurrentState() { return mFlinger->mCurrentState; }
auto& mutableDisplayColorSetting() { return mFlinger->mDisplayColorSetting; }
- auto& mutableDisplays() { return mFlinger->mDisplays; }
- auto& mutablePhysicalDisplays() { return mFlinger->mPhysicalDisplays; }
+ auto& mutableDisplays() NO_THREAD_SAFETY_ANALYSIS { return mFlinger->mDisplays; }
+ auto& mutablePhysicalDisplays() NO_THREAD_SAFETY_ANALYSIS {
+ return mFlinger->mPhysicalDisplays;
+ }
auto& mutableDrawingState() { return mFlinger->mDrawingState; }
auto& mutableGeometryDirty() { return mFlinger->mGeometryDirty; }
auto& mutableVisibleRegionsDirty() { return mFlinger->mVisibleRegionsDirty; }
auto& mutableMainThreadId() { return mFlinger->mMainThreadId; }
- auto& mutablePendingHotplugEvents() { return mFlinger->mPendingHotplugEvents; }
+ auto& mutablePendingHotplugEvents() NO_THREAD_SAFETY_ANALYSIS {
+ return mFlinger->mPendingHotplugEvents;
+ }
auto& mutableTransactionFlags() { return mFlinger->mTransactionFlags; }
auto& mutableDebugDisableHWC() { return mFlinger->mDebugDisableHWC; }
auto& mutableMaxRenderTargetSize() { return mFlinger->mMaxRenderTargetSize; }
@@ -687,7 +695,7 @@ public:
auto& mutableHwcDisplayData() { return getHwComposer().mDisplayData; }
auto& mutableHwcPhysicalDisplayIdMap() { return getHwComposer().mPhysicalDisplayIdMap; }
auto& mutablePrimaryHwcDisplayId() { return getHwComposer().mPrimaryHwcDisplayId; }
- auto& mutableActiveDisplayId() { return mFlinger->mActiveDisplayId; }
+ auto& mutableActiveDisplayId() NO_THREAD_SAFETY_ANALYSIS { return mFlinger->mActiveDisplayId; }
auto& mutablePreviouslyComposedLayers() { return mFlinger->mPreviouslyComposedLayers; }
auto& mutableActiveDisplayRotationFlags() {
@@ -695,7 +703,9 @@ public:
}
auto& mutableMinAcquiredBuffers() { return SurfaceFlinger::minAcquiredBuffers; }
- auto& mutableLayerSnapshotBuilder() { return mFlinger->mLayerSnapshotBuilder; };
+ auto& mutableLayerSnapshotBuilder() NO_THREAD_SAFETY_ANALYSIS {
+ return mFlinger->mLayerSnapshotBuilder;
+ }
auto fromHandle(const sp<IBinder>& handle) { return LayerHandle::getLayer(handle); }
diff --git a/services/vibratorservice/TEST_MAPPING b/services/vibratorservice/TEST_MAPPING
index af486736d8..1eb3a581b7 100644
--- a/services/vibratorservice/TEST_MAPPING
+++ b/services/vibratorservice/TEST_MAPPING
@@ -4,11 +4,6 @@
"name": "libvibratorservice_test"
}
],
- "postsubmit": [
- {
- "name": "libvibratorservice_test"
- }
- ],
"imports": [
{
"path": "cts/tests/vibrator"