Merge "Rotary encoder rotation count telemetry" into main
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 d0b594c..7aef9ec 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 4eeed2a..3d8a178 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 0000000..e005356
--- /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 62bb101..1ad35bc 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 8b2b4c8..185edbf 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 0000000..b424667
--- /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 0fc12b3..4128a95 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/libs/binder/ndk/include_cpp/android/binder_interface_utils.h b/libs/binder/ndk/include_cpp/android/binder_interface_utils.h
index 8296356..acb6970 100644
--- a/libs/binder/ndk/include_cpp/android/binder_interface_utils.h
+++ b/libs/binder/ndk/include_cpp/android/binder_interface_utils.h
@@ -298,7 +298,8 @@
#endif
// TODO(b/368559337): fix versioning on product partition
-#if !defined(__ANDROID_PRODUCT__) && \
+// TODO(b/370091328): APEX modules call this function even it is unavailable.
+#if !defined(__ANDROID_APEX__) && !defined(__ANDROID_PRODUCT__) && \
(defined(__ANDROID_UNAVAILABLE_SYMBOLS_ARE_WEAK__) || __ANDROID_API__ >= 36)
if API_LEVEL_AT_LEAST (36, 202504) {
if (codeToFunction != nullptr) {
@@ -309,7 +310,8 @@
#else
(void)codeToFunction;
(void)functionCount;
-#endif // defined(__ANDROID_UNAVAILABLE_SYMBOLS_ARE_WEAK__) || __ANDROID_API__ >= 36
+#endif // !defined(__ANDROID_APEX__) && !defined(__ANDROID_PRODUCT__) && \
+// (defined(__ANDROID_UNAVAILABLE_SYMBOLS_ARE_WEAK__) || __ANDROID_API__ >= 36)
return clazz;
}
diff --git a/libs/binder/rust/src/binder.rs b/libs/binder/rust/src/binder.rs
index 9a252b8..23026e5 100644
--- a/libs/binder/rust/src/binder.rs
+++ b/libs/binder/rust/src/binder.rs
@@ -136,6 +136,31 @@
}
}
+/// 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 e70f4f0..e048696 100644
--- a/libs/binder/rust/src/lib.rs
+++ b/libs/binder/rust/src/lib.rs
@@ -128,9 +128,10 @@
/// 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 f906113..87b42ab 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 @@
/// `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 @@
// 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 @@
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 @@
/// Return the stability value of this object.
pub fn get_stability(&self) -> Stability {
- self.stability
+ STABILITY::VALUE
}
}
-impl Clone for ParcelableHolder {
- fn clone(&self) -> ParcelableHolder {
+impl<STABILITY: StabilityType> Default for ParcelableHolder<STABILITY> {
+ fn default() -> Self {
+ Self::new()
+ }
+}
+
+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 @@
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 @@
}
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 ce0f742..ee20a22 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 @@
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 @@
}
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/renderengine/OWNERS b/libs/renderengine/OWNERS
index 66e1aa1..17ab29f 100644
--- a/libs/renderengine/OWNERS
+++ b/libs/renderengine/OWNERS
@@ -5,4 +5,6 @@
djsollen@google.com
jreck@google.com
lpy@google.com
+nscobie@google.com
+sallyqi@google.com
scroggo@google.com
diff --git a/services/inputflinger/InputFilterCallbacks.cpp b/services/inputflinger/InputFilterCallbacks.cpp
index 5fbdc84..493459a 100644
--- a/services/inputflinger/InputFilterCallbacks.cpp
+++ b/services/inputflinger/InputFilterCallbacks.cpp
@@ -44,7 +44,8 @@
InputFilterThread(std::shared_ptr<IInputThreadCallback> callback) : mCallback(callback) {
mLooper = sp<Looper>::make(/*allowNonCallbacks=*/false);
mThread = std::make_unique<InputThread>(
- "InputFilter", [this]() { loopOnce(); }, [this]() { mLooper->wake(); });
+ "InputFilter", [this]() { loopOnce(); }, [this]() { mLooper->wake(); },
+ /*isInCriticalPath=*/false);
}
ndk::ScopedAStatus finish() override {
diff --git a/services/inputflinger/InputThread.cpp b/services/inputflinger/InputThread.cpp
index 449eb45..7cf4e39 100644
--- a/services/inputflinger/InputThread.cpp
+++ b/services/inputflinger/InputThread.cpp
@@ -26,6 +26,16 @@
namespace {
+bool applyInputEventProfile(const Thread& thread) {
+#if defined(__ANDROID__)
+ return SetTaskProfiles(thread.getTid(), {"InputPolicy"});
+#else
+ // Since thread information is not available and there's no benefit of
+ // applying the task profile on host, return directly.
+ return true;
+#endif
+}
+
// Implementation of Thread from libutils.
class InputThreadImpl : public Thread {
public:
@@ -45,12 +55,13 @@
} // namespace
-InputThread::InputThread(std::string name, std::function<void()> loop, std::function<void()> wake)
- : mName(name), mThreadWake(wake) {
+InputThread::InputThread(std::string name, std::function<void()> loop, std::function<void()> wake,
+ bool isInCriticalPath)
+ : mThreadWake(wake) {
mThread = sp<InputThreadImpl>::make(loop);
- mThread->run(mName.c_str(), ANDROID_PRIORITY_URGENT_DISPLAY);
- if (input_flags::enable_input_policy_profile()) {
- if (!applyInputEventProfile()) {
+ mThread->run(name.c_str(), ANDROID_PRIORITY_URGENT_DISPLAY);
+ if (input_flags::enable_input_policy_profile() && isInCriticalPath) {
+ if (!applyInputEventProfile(*mThread)) {
LOG(ERROR) << "Couldn't apply input policy profile for " << name;
}
}
@@ -74,14 +85,4 @@
#endif
}
-bool InputThread::applyInputEventProfile() {
-#if defined(__ANDROID__)
- return SetTaskProfiles(mThread->getTid(), {"InputPolicy"});
-#else
- // Since thread information is not available and there's no benefit of
- // applying the task profile on host, return directly.
- return true;
-#endif
-}
-
-} // namespace android
\ No newline at end of file
+} // namespace android
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index b0beeca..3337c47 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -993,7 +993,8 @@
return ALREADY_EXISTS;
}
mThread = std::make_unique<InputThread>(
- "InputDispatcher", [this]() { dispatchOnce(); }, [this]() { mLooper->wake(); });
+ "InputDispatcher", [this]() { dispatchOnce(); }, [this]() { mLooper->wake(); },
+ /*isInCriticalPath=*/true);
return OK;
}
diff --git a/services/inputflinger/dispatcher/trace/ThreadedBackend.cpp b/services/inputflinger/dispatcher/trace/ThreadedBackend.cpp
index 3c3c15a..4f61885 100644
--- a/services/inputflinger/dispatcher/trace/ThreadedBackend.cpp
+++ b/services/inputflinger/dispatcher/trace/ThreadedBackend.cpp
@@ -41,7 +41,7 @@
: mBackend(std::move(innerBackend)),
mTracerThread(
"InputTracer", [this]() { threadLoop(); },
- [this]() { mThreadWakeCondition.notify_all(); }) {}
+ [this]() { mThreadWakeCondition.notify_all(); }, /*isInCriticalPath=*/false) {}
template <typename Backend>
ThreadedBackend<Backend>::~ThreadedBackend() {
diff --git a/services/inputflinger/include/InputThread.h b/services/inputflinger/include/InputThread.h
index fcd913d..ed92b8f 100644
--- a/services/inputflinger/include/InputThread.h
+++ b/services/inputflinger/include/InputThread.h
@@ -28,17 +28,15 @@
*/
class InputThread {
public:
- explicit InputThread(std::string name, std::function<void()> loop,
- std::function<void()> wake = nullptr);
+ explicit InputThread(std::string name, std::function<void()> loop, std::function<void()> wake,
+ bool isInCriticalPath);
virtual ~InputThread();
bool isCallingThread();
private:
- std::string mName;
std::function<void()> mThreadWake;
sp<Thread> mThread;
- bool applyInputEventProfile();
};
} // namespace android
diff --git a/services/inputflinger/reader/InputReader.cpp b/services/inputflinger/reader/InputReader.cpp
index e579390..8b664d5 100644
--- a/services/inputflinger/reader/InputReader.cpp
+++ b/services/inputflinger/reader/InputReader.cpp
@@ -122,7 +122,8 @@
return ALREADY_EXISTS;
}
mThread = std::make_unique<InputThread>(
- "InputReader", [this]() { loopOnce(); }, [this]() { mEventHub->wake(); });
+ "InputReader", [this]() { loopOnce(); }, [this]() { mEventHub->wake(); },
+ /*isInCriticalPath=*/true);
return OK;
}
diff --git a/services/inputflinger/rust/bounce_keys_filter.rs b/services/inputflinger/rust/bounce_keys_filter.rs
index e05e8e5..a8959d9 100644
--- a/services/inputflinger/rust/bounce_keys_filter.rs
+++ b/services/inputflinger/rust/bounce_keys_filter.rs
@@ -25,6 +25,7 @@
};
use input::KeyboardType;
use log::debug;
+use std::any::Any;
use std::collections::{HashMap, HashSet};
#[derive(Debug)]
@@ -134,6 +135,17 @@
self.next.destroy();
}
+ fn save(
+ &mut self,
+ state: HashMap<&'static str, Box<dyn Any + Send + Sync>>,
+ ) -> HashMap<&'static str, Box<dyn Any + Send + Sync>> {
+ self.next.save(state)
+ }
+
+ fn restore(&mut self, state: &HashMap<&'static str, Box<dyn Any + Send + Sync>>) {
+ self.next.restore(state);
+ }
+
fn dump(&mut self, dump_str: String) -> String {
let mut result = "Bounce Keys filter: \n".to_string();
result += &format!("\tthreshold = {:?}ns\n", self.bounce_key_threshold_ns);
diff --git a/services/inputflinger/rust/input_filter.rs b/services/inputflinger/rust/input_filter.rs
index e221244..39c3465 100644
--- a/services/inputflinger/rust/input_filter.rs
+++ b/services/inputflinger/rust/input_filter.rs
@@ -33,6 +33,8 @@
use crate::sticky_keys_filter::StickyKeysFilter;
use input::ModifierState;
use log::{error, info};
+use std::any::Any;
+use std::collections::HashMap;
use std::sync::{Arc, Mutex, RwLock};
/// Virtual keyboard device ID
@@ -43,6 +45,11 @@
fn notify_key(&mut self, event: &KeyEvent);
fn notify_devices_changed(&mut self, device_infos: &[DeviceInfo]);
fn destroy(&mut self);
+ fn save(
+ &mut self,
+ state: HashMap<&'static str, Box<dyn Any + Send + Sync>>,
+ ) -> HashMap<&'static str, Box<dyn Any + Send + Sync>>;
+ fn restore(&mut self, state: &HashMap<&'static str, Box<dyn Any + Send + Sync>>);
fn dump(&mut self, dump_str: String) -> String;
}
@@ -105,6 +112,7 @@
fn notifyConfigurationChanged(&self, config: &InputFilterConfiguration) -> binder::Result<()> {
{
let mut state = self.state.lock().unwrap();
+ let saved_state = state.first_filter.save(HashMap::new());
state.first_filter.destroy();
let mut first_filter: Box<dyn Filter + Send + Sync> =
Box::new(BaseFilter::new(self.callbacks.clone()));
@@ -138,6 +146,7 @@
);
}
state.first_filter = first_filter;
+ state.first_filter.restore(&saved_state);
}
Result::Ok(())
}
@@ -175,6 +184,18 @@
// do nothing
}
+ fn save(
+ &mut self,
+ state: HashMap<&'static str, Box<dyn Any + Send + Sync>>,
+ ) -> HashMap<&'static str, Box<dyn Any + Send + Sync>> {
+ // do nothing
+ state
+ }
+
+ fn restore(&mut self, _state: &HashMap<&'static str, Box<dyn Any + Send + Sync>>) {
+ // do nothing
+ }
+
fn dump(&mut self, dump_str: String) -> String {
// do nothing
dump_str
@@ -367,6 +388,8 @@
use com_android_server_inputflinger::aidl::com::android::server::inputflinger::{
DeviceInfo::DeviceInfo, KeyEvent::KeyEvent,
};
+ use std::any::Any;
+ use std::collections::HashMap;
use std::sync::{Arc, RwLock, RwLockWriteGuard};
#[derive(Default)]
@@ -415,6 +438,16 @@
fn destroy(&mut self) {
self.inner().is_destroy_called = true;
}
+ fn save(
+ &mut self,
+ state: HashMap<&'static str, Box<dyn Any + Send + Sync>>,
+ ) -> HashMap<&'static str, Box<dyn Any + Send + Sync>> {
+ // do nothing
+ state
+ }
+ fn restore(&mut self, _state: &HashMap<&'static str, Box<dyn Any + Send + Sync>>) {
+ // do nothing
+ }
fn dump(&mut self, dump_str: String) -> String {
// do nothing
dump_str
diff --git a/services/inputflinger/rust/slow_keys_filter.rs b/services/inputflinger/rust/slow_keys_filter.rs
index 8830aac..085e80e 100644
--- a/services/inputflinger/rust/slow_keys_filter.rs
+++ b/services/inputflinger/rust/slow_keys_filter.rs
@@ -26,7 +26,8 @@
};
use input::KeyboardType;
use log::debug;
-use std::collections::HashSet;
+use std::any::Any;
+use std::collections::{HashMap, HashSet};
use std::sync::{Arc, RwLock, RwLockReadGuard, RwLockWriteGuard};
// Policy flags from Input.h
@@ -187,6 +188,19 @@
slow_filter.next.destroy();
}
+ fn save(
+ &mut self,
+ state: HashMap<&'static str, Box<dyn Any + Send + Sync>>,
+ ) -> HashMap<&'static str, Box<dyn Any + Send + Sync>> {
+ let mut slow_filter = self.write_inner();
+ slow_filter.next.save(state)
+ }
+
+ fn restore(&mut self, state: &HashMap<&'static str, Box<dyn Any + Send + Sync>>) {
+ let mut slow_filter = self.write_inner();
+ slow_filter.next.restore(state);
+ }
+
fn dump(&mut self, dump_str: String) -> String {
let mut slow_filter = self.write_inner();
let mut result = "Slow Keys filter: \n".to_string();
diff --git a/services/inputflinger/rust/sticky_keys_filter.rs b/services/inputflinger/rust/sticky_keys_filter.rs
index 161a5fc..7a1d0ec 100644
--- a/services/inputflinger/rust/sticky_keys_filter.rs
+++ b/services/inputflinger/rust/sticky_keys_filter.rs
@@ -24,7 +24,8 @@
DeviceInfo::DeviceInfo, KeyEvent::KeyEvent, KeyEventAction::KeyEventAction,
};
use input::ModifierState;
-use std::collections::HashSet;
+use std::any::Any;
+use std::collections::{HashMap, HashSet};
// Modifier keycodes: values are from /frameworks/native/include/android/keycodes.h
const KEYCODE_ALT_LEFT: i32 = 57;
@@ -40,10 +41,17 @@
const KEYCODE_META_RIGHT: i32 = 118;
const KEYCODE_FUNCTION: i32 = 119;
const KEYCODE_NUM_LOCK: i32 = 143;
+static STICKY_KEYS_DATA: &str = "sticky_keys_data";
pub struct StickyKeysFilter {
next: Box<dyn Filter + Send + Sync>,
listener: ModifierStateListener,
+ data: Data,
+}
+
+#[derive(Default)]
+/// Data that will be saved and restored across configuration changes
+struct Data {
/// Tracking devices that contributed to the modifier state.
contributing_devices: HashSet<i32>,
/// State describing the current enabled modifiers. This contain both locked and non-locked
@@ -61,21 +69,15 @@
next: Box<dyn Filter + Send + Sync>,
listener: ModifierStateListener,
) -> StickyKeysFilter {
- Self {
- next,
- listener,
- contributing_devices: HashSet::new(),
- modifier_state: ModifierState::None,
- locked_modifier_state: ModifierState::None,
- }
+ Self { next, listener, data: Default::default() }
}
}
impl Filter for StickyKeysFilter {
fn notify_key(&mut self, event: &KeyEvent) {
let up = event.action == KeyEventAction::UP;
- let mut modifier_state = self.modifier_state;
- let mut locked_modifier_state = self.locked_modifier_state;
+ let mut modifier_state = self.data.modifier_state;
+ let mut locked_modifier_state = self.data.locked_modifier_state;
if !is_ephemeral_modifier_key(event.keyCode) {
// If non-ephemeral modifier key (i.e. non-modifier keys + toggle modifier keys like
// CAPS_LOCK, NUM_LOCK etc.), don't block key and pass in the sticky modifier state with
@@ -93,7 +95,7 @@
}
} else if up {
// Update contributing devices to track keyboards
- self.contributing_devices.insert(event.deviceId);
+ self.data.contributing_devices.insert(event.deviceId);
// If ephemeral modifier key, capture the key and update the sticky modifier states
let modifier_key_mask = get_ephemeral_modifier_key_mask(event.keyCode);
let symmetrical_modifier_key_mask = get_symmetrical_modifier_key_mask(event.keyCode);
@@ -108,38 +110,62 @@
modifier_state |= modifier_key_mask;
}
}
- if self.modifier_state != modifier_state
- || self.locked_modifier_state != locked_modifier_state
+ if self.data.modifier_state != modifier_state
+ || self.data.locked_modifier_state != locked_modifier_state
{
- self.modifier_state = modifier_state;
- self.locked_modifier_state = locked_modifier_state;
+ self.data.modifier_state = modifier_state;
+ self.data.locked_modifier_state = locked_modifier_state;
self.listener.modifier_state_changed(modifier_state, locked_modifier_state);
}
}
fn notify_devices_changed(&mut self, device_infos: &[DeviceInfo]) {
// Clear state if all contributing devices removed
- self.contributing_devices.retain(|id| device_infos.iter().any(|x| *id == x.deviceId));
- if self.contributing_devices.is_empty()
- && (self.modifier_state != ModifierState::None
- || self.locked_modifier_state != ModifierState::None)
+ self.data.contributing_devices.retain(|id| device_infos.iter().any(|x| *id == x.deviceId));
+ if self.data.contributing_devices.is_empty()
+ && (self.data.modifier_state != ModifierState::None
+ || self.data.locked_modifier_state != ModifierState::None)
{
- self.modifier_state = ModifierState::None;
- self.locked_modifier_state = ModifierState::None;
+ self.data.modifier_state = ModifierState::None;
+ self.data.locked_modifier_state = ModifierState::None;
self.listener.modifier_state_changed(ModifierState::None, ModifierState::None);
}
self.next.notify_devices_changed(device_infos);
}
+ fn save(
+ &mut self,
+ mut state: HashMap<&'static str, Box<dyn Any + Send + Sync>>,
+ ) -> HashMap<&'static str, Box<dyn Any + Send + Sync>> {
+ let data = Data {
+ contributing_devices: self.data.contributing_devices.clone(),
+ modifier_state: self.data.modifier_state,
+ locked_modifier_state: self.data.locked_modifier_state,
+ };
+ state.insert(STICKY_KEYS_DATA, Box::new(data));
+ self.next.save(state)
+ }
+
+ fn restore(&mut self, state: &HashMap<&'static str, Box<dyn Any + Send + Sync>>) {
+ if let Some(value) = state.get(STICKY_KEYS_DATA) {
+ if let Some(data) = value.downcast_ref::<Data>() {
+ self.data.contributing_devices = data.contributing_devices.clone();
+ self.data.modifier_state = data.modifier_state;
+ self.data.locked_modifier_state = data.locked_modifier_state;
+ }
+ }
+ self.next.restore(state)
+ }
+
fn destroy(&mut self) {
self.next.destroy();
}
fn dump(&mut self, dump_str: String) -> String {
let mut result = "Sticky Keys filter: \n".to_string();
- result += &format!("\tmodifier_state = {:?}\n", self.modifier_state);
- result += &format!("\tlocked_modifier_state = {:?}\n", self.locked_modifier_state);
- result += &format!("\tcontributing_devices = {:?}\n", self.contributing_devices);
+ result += &format!("\tmodifier_state = {:?}\n", self.data.modifier_state);
+ result += &format!("\tlocked_modifier_state = {:?}\n", self.data.locked_modifier_state);
+ result += &format!("\tcontributing_devices = {:?}\n", self.data.contributing_devices);
self.next.dump(dump_str + &result)
}
}
@@ -245,6 +271,7 @@
};
use input::KeyboardType;
use input::ModifierState;
+ use std::collections::HashMap;
use std::sync::{Arc, RwLock};
static DEVICE_ID: i32 = 1;
@@ -452,6 +479,45 @@
}
#[test]
+ fn test_modifier_state_restored_on_recreation() {
+ let test_filter = TestFilter::new();
+ let test_callbacks = TestCallbacks::new();
+ let mut sticky_keys_filter = setup_filter(
+ Box::new(test_filter.clone()),
+ Arc::new(RwLock::new(Strong::new(Box::new(test_callbacks.clone())))),
+ );
+ sticky_keys_filter.notify_key(&KeyEvent { keyCode: KEYCODE_CTRL_LEFT, ..BASE_KEY_DOWN });
+ sticky_keys_filter.notify_key(&KeyEvent { keyCode: KEYCODE_CTRL_LEFT, ..BASE_KEY_UP });
+
+ let saved_state = sticky_keys_filter.save(HashMap::new());
+ sticky_keys_filter.destroy();
+
+ // Create a new Sticky keys filter
+ let test_filter = TestFilter::new();
+ let mut sticky_keys_filter = setup_filter(
+ Box::new(test_filter.clone()),
+ Arc::new(RwLock::new(Strong::new(Box::new(test_callbacks.clone())))),
+ );
+ sticky_keys_filter.restore(&saved_state);
+ assert_eq!(
+ test_callbacks.get_last_modifier_state(),
+ ModifierState::CtrlLeftOn | ModifierState::CtrlOn
+ );
+ assert_eq!(test_callbacks.get_last_locked_modifier_state(), ModifierState::None);
+
+ sticky_keys_filter.notify_key(&KeyEvent { keyCode: KEYCODE_CTRL_LEFT, ..BASE_KEY_DOWN });
+ sticky_keys_filter.notify_key(&KeyEvent { keyCode: KEYCODE_CTRL_LEFT, ..BASE_KEY_UP });
+ assert_eq!(
+ test_callbacks.get_last_modifier_state(),
+ ModifierState::CtrlLeftOn | ModifierState::CtrlOn
+ );
+ assert_eq!(
+ test_callbacks.get_last_locked_modifier_state(),
+ ModifierState::CtrlLeftOn | ModifierState::CtrlOn
+ );
+ }
+
+ #[test]
fn test_key_events_have_sticky_modifier_state() {
let test_filter = TestFilter::new();
let test_callbacks = TestCallbacks::new();
diff --git a/services/surfaceflinger/OWNERS b/services/surfaceflinger/OWNERS
index ffc1dd7..fa0ecee 100644
--- a/services/surfaceflinger/OWNERS
+++ b/services/surfaceflinger/OWNERS
@@ -5,6 +5,8 @@
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 @@
sallyqi@google.com
scroggo@google.com
vishnun@google.com
+xwxw@google.com