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