Merge "Add initializer support to FatVector"
diff --git a/libs/binder/Binder.cpp b/libs/binder/Binder.cpp
index f2d223d..d964d25 100644
--- a/libs/binder/Binder.cpp
+++ b/libs/binder/Binder.cpp
@@ -133,6 +133,7 @@
public:
// unlocked objects
bool mRequestingSid = false;
+ bool mInheritRt = false;
sp<IBinder> mExtension;
int mPolicy = SCHED_NORMAL;
int mPriority = 0;
@@ -327,6 +328,27 @@
return e->mPriority;
}
+bool BBinder::isInheritRt() {
+ Extras* e = mExtras.load(std::memory_order_acquire);
+
+ return e && e->mInheritRt;
+}
+
+void BBinder::setInheritRt(bool inheritRt) {
+ Extras* e = mExtras.load(std::memory_order_acquire);
+
+ if (!e) {
+ if (!inheritRt) {
+ return;
+ }
+
+ e = getOrCreateExtras();
+ if (!e) return; // out of memory
+ }
+
+ e->mInheritRt = inheritRt;
+}
+
pid_t BBinder::getDebugPid() {
return getpid();
}
diff --git a/libs/binder/BufferedTextOutput.cpp b/libs/binder/BufferedTextOutput.cpp
index 8cf6097..88c85bf 100644
--- a/libs/binder/BufferedTextOutput.cpp
+++ b/libs/binder/BufferedTextOutput.cpp
@@ -18,7 +18,6 @@
#include <binder/Debug.h>
#include <cutils/atomic.h>
-#include <cutils/threads.h>
#include <utils/Log.h>
#include <utils/RefBase.h>
#include <utils/Vector.h>
@@ -91,22 +90,6 @@
static pthread_mutex_t gMutex = PTHREAD_MUTEX_INITIALIZER;
-static thread_store_t tls;
-
-BufferedTextOutput::ThreadState* BufferedTextOutput::getThreadState()
-{
- ThreadState* ts = (ThreadState*) thread_store_get( &tls );
- if (ts) return ts;
- ts = new ThreadState;
- thread_store_set( &tls, ts, threadDestructor );
- return ts;
-}
-
-void BufferedTextOutput::threadDestructor(void *st)
-{
- delete ((ThreadState*)st);
-}
-
static volatile int32_t gSequence = 0;
static volatile int32_t gFreeBufferIndex = -1;
@@ -266,16 +249,14 @@
BufferedTextOutput::BufferState* BufferedTextOutput::getBuffer() const
{
if ((mFlags&MULTITHREADED) != 0) {
- ThreadState* ts = getThreadState();
- if (ts) {
- while (ts->states.size() <= (size_t)mIndex) ts->states.add(nullptr);
- BufferState* bs = ts->states[mIndex].get();
- if (bs != nullptr && bs->seq == mSeq) return bs;
-
- ts->states.editItemAt(mIndex) = new BufferState(mIndex);
- bs = ts->states[mIndex].get();
- if (bs != nullptr) return bs;
- }
+ thread_local ThreadState ts;
+ while (ts.states.size() <= (size_t)mIndex) ts.states.add(nullptr);
+ BufferState* bs = ts.states[mIndex].get();
+ if (bs != nullptr && bs->seq == mSeq) return bs;
+
+ ts.states.editItemAt(mIndex) = new BufferState(mIndex);
+ bs = ts.states[mIndex].get();
+ if (bs != nullptr) return bs;
}
return mGlobalState;
diff --git a/libs/binder/BufferedTextOutput.h b/libs/binder/BufferedTextOutput.h
index 1b27bb2..fdd532a 100644
--- a/libs/binder/BufferedTextOutput.h
+++ b/libs/binder/BufferedTextOutput.h
@@ -47,10 +47,7 @@
private:
struct BufferState;
struct ThreadState;
-
- static ThreadState*getThreadState();
- static void threadDestructor(void *st);
-
+
BufferState*getBuffer() const;
uint32_t mFlags;
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index 88a631a..91e465f 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -222,6 +222,9 @@
if (local->isRequestingSid()) {
obj.flags |= FLAT_BINDER_FLAG_TXN_SECURITY_CTX;
}
+ if (local->isInheritRt()) {
+ obj.flags |= FLAT_BINDER_FLAG_INHERIT_RT;
+ }
obj.hdr.type = BINDER_TYPE_BINDER;
obj.binder = reinterpret_cast<uintptr_t>(local->getWeakRefs());
obj.cookie = reinterpret_cast<uintptr_t>(local);
@@ -2055,8 +2058,11 @@
if (size >= 0 && size < INT32_MAX) {
*outLen = size;
const char* str = (const char*)readInplace(size+1);
- if (str != nullptr && str[size] == '\0') {
- return str;
+ if (str != nullptr) {
+ if (str[size] == '\0') {
+ return str;
+ }
+ android_errorWriteLog(0x534e4554, "172655291");
}
}
*outLen = 0;
@@ -2138,8 +2144,11 @@
if (size >= 0 && size < INT32_MAX) {
*outLen = size;
const char16_t* str = (const char16_t*)readInplace((size+1)*sizeof(char16_t));
- if (str != nullptr && str[size] == u'\0') {
- return str;
+ if (str != nullptr) {
+ if (str[size] == u'\0') {
+ return str;
+ }
+ android_errorWriteLog(0x534e4554, "172655291");
}
}
*outLen = 0;
diff --git a/libs/binder/TEST_MAPPING b/libs/binder/TEST_MAPPING
index d7a44e5..97e282e 100644
--- a/libs/binder/TEST_MAPPING
+++ b/libs/binder/TEST_MAPPING
@@ -59,6 +59,9 @@
},
{
"name": "rustBinderTest"
+ },
+ {
+ "name": "binderRustNdkInteropTest"
}
]
}
diff --git a/libs/binder/include/binder/Binder.h b/libs/binder/include/binder/Binder.h
index d6da397..7079544 100644
--- a/libs/binder/include/binder/Binder.h
+++ b/libs/binder/include/binder/Binder.h
@@ -87,6 +87,11 @@
int getMinSchedulerPolicy();
int getMinSchedulerPriority();
+ // Whether realtime scheduling policies are inherited.
+ bool isInheritRt();
+ // This must be called before the object is sent to another process. Not thread safe.
+ void setInheritRt(bool inheritRt);
+
pid_t getDebugPid();
protected:
diff --git a/libs/binder/rust/src/binder.rs b/libs/binder/rust/src/binder.rs
index 037ee95..ed3b9ec 100644
--- a/libs/binder/rust/src/binder.rs
+++ b/libs/binder/rust/src/binder.rs
@@ -21,7 +21,8 @@
use crate::proxy::{DeathRecipient, SpIBinder};
use crate::sys;
-use std::ffi::{c_void, CString};
+use std::ffi::{c_void, CStr, CString};
+use std::os::raw::c_char;
use std::os::unix::io::AsRawFd;
use std::ptr;
@@ -205,6 +206,22 @@
pub(crate) unsafe fn from_ptr(ptr: *const sys::AIBinder_Class) -> InterfaceClass {
InterfaceClass(ptr)
}
+
+ /// Get the interface descriptor string of this class.
+ pub fn get_descriptor(&self) -> String {
+ unsafe {
+ // SAFETY: The descriptor returned by AIBinder_Class_getDescriptor
+ // is always a two-byte null terminated sequence of u16s. Thus, we
+ // can continue reading from the pointer until we hit a null value,
+ // and this pointer can be a valid slice if the slice length is <=
+ // the number of u16 elements before the null terminator.
+
+ let raw_descriptor: *const c_char = sys::AIBinder_Class_getDescriptor(self.0);
+ CStr::from_ptr(raw_descriptor).to_str()
+ .expect("Expected valid UTF-8 string from AIBinder_Class_getDescriptor")
+ .into()
+ }
+ }
}
impl From<InterfaceClass> for *const sys::AIBinder_Class {
@@ -507,12 +524,7 @@
}
fn from_binder(mut binder: $crate::SpIBinder) -> $crate::Result<Self> {
- use $crate::AssociateClass;
- if binder.associate_class(<$native as $crate::Remotable>::get_class()) {
- Ok(Self { binder, $($fname: $finit),* })
- } else {
- Err($crate::StatusCode::BAD_TYPE)
- }
+ Ok(Self { binder, $($fname: $finit),* })
}
}
@@ -567,16 +579,35 @@
impl $crate::FromIBinder for dyn $interface {
fn try_from(mut ibinder: $crate::SpIBinder) -> $crate::Result<Box<dyn $interface>> {
use $crate::AssociateClass;
- if !ibinder.associate_class(<$native as $crate::Remotable>::get_class()) {
- return Err($crate::StatusCode::BAD_TYPE.into());
+
+ let existing_class = ibinder.get_class();
+ if let Some(class) = existing_class {
+ if class != <$native as $crate::Remotable>::get_class() &&
+ class.get_descriptor() == <$native as $crate::Remotable>::get_descriptor()
+ {
+ // The binder object's descriptor string matches what we
+ // expect. We still need to treat this local or already
+ // associated object as remote, because we can't cast it
+ // into a Rust service object without a matching class
+ // pointer.
+ return Ok(Box::new(<$proxy as $crate::Proxy>::from_binder(ibinder)?));
+ }
}
- let service: $crate::Result<$crate::Binder<$native>> = std::convert::TryFrom::try_from(ibinder.clone());
- if let Ok(service) = service {
- Ok(Box::new(service))
- } else {
- Ok(Box::new(<$proxy as $crate::Proxy>::from_binder(ibinder)?))
+ if ibinder.associate_class(<$native as $crate::Remotable>::get_class()) {
+ let service: $crate::Result<$crate::Binder<$native>> =
+ std::convert::TryFrom::try_from(ibinder.clone());
+ if let Ok(service) = service {
+ // We were able to associate with our expected class and
+ // the service is local.
+ return Ok(Box::new(service));
+ } else {
+ // Service is remote
+ return Ok(Box::new(<$proxy as $crate::Proxy>::from_binder(ibinder)?));
+ }
}
+
+ Err($crate::StatusCode::BAD_TYPE.into())
}
}
diff --git a/libs/binder/rust/src/proxy.rs b/libs/binder/rust/src/proxy.rs
index 5002fc6..485bb42 100644
--- a/libs/binder/rust/src/proxy.rs
+++ b/libs/binder/rust/src/proxy.rs
@@ -91,7 +91,7 @@
/// Return the interface class of this binder object, if associated with
/// one.
- pub(crate) fn get_class(&mut self) -> Option<InterfaceClass> {
+ pub fn get_class(&mut self) -> Option<InterfaceClass> {
unsafe {
// Safety: `SpIBinder` guarantees that it always contains a valid
// `AIBinder` pointer. `AIBinder_getClass` returns either a null
diff --git a/libs/binder/rust/tests/Android.bp b/libs/binder/rust/tests/Android.bp
index 3db40ba..5ae9c53 100644
--- a/libs/binder/rust/tests/Android.bp
+++ b/libs/binder/rust/tests/Android.bp
@@ -30,3 +30,52 @@
auto_gen_config: false,
test_suites: ["general-tests"],
}
+
+cc_test {
+ name: "binderRustNdkInteropTest",
+ srcs: [
+ "binderRustNdkInteropTest.cpp",
+ ],
+ shared_libs: [
+ "libbinder",
+ "libbinder_ndk",
+ ],
+ static_libs: [
+ "IBinderRustNdkInteropTest-ndk_platform",
+ "libbinder_ndk_rust_interop",
+ ],
+ test_suites: ["general-tests"],
+ require_root: true,
+
+ // rustBinderTestService uses a custom config
+ auto_gen_config: true,
+}
+
+aidl_interface {
+ name: "IBinderRustNdkInteropTest",
+ unstable: true,
+ srcs: [
+ "IBinderRustNdkInteropTest.aidl",
+ "IBinderRustNdkInteropTestOther.aidl",
+ ],
+ backend: {
+ ndk: {
+ enabled: true,
+ },
+ rust: {
+ enabled: true,
+ },
+ },
+}
+
+rust_ffi_static {
+ name: "libbinder_ndk_rust_interop",
+ crate_name: "binder_ndk_rust_interop",
+ srcs: [
+ "ndk_rust_interop.rs",
+ ],
+ rustlibs: [
+ "libbinder_rs",
+ "IBinderRustNdkInteropTest-rust",
+ ],
+}
diff --git a/libs/binder/rust/tests/IBinderRustNdkInteropTest.aidl b/libs/binder/rust/tests/IBinderRustNdkInteropTest.aidl
new file mode 100644
index 0000000..7f5e837
--- /dev/null
+++ b/libs/binder/rust/tests/IBinderRustNdkInteropTest.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+interface IBinderRustNdkInteropTest {
+ @utf8InCpp String echo(@utf8InCpp String str);
+}
diff --git a/libs/binder/rust/tests/IBinderRustNdkInteropTestOther.aidl b/libs/binder/rust/tests/IBinderRustNdkInteropTestOther.aidl
new file mode 100644
index 0000000..82a0323
--- /dev/null
+++ b/libs/binder/rust/tests/IBinderRustNdkInteropTestOther.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+interface IBinderRustNdkInteropTestOther {
+ @utf8InCpp String echo(@utf8InCpp String str);
+}
diff --git a/libs/binder/rust/tests/binderRustNdkInteropTest.cpp b/libs/binder/rust/tests/binderRustNdkInteropTest.cpp
new file mode 100644
index 0000000..59ca6ed
--- /dev/null
+++ b/libs/binder/rust/tests/binderRustNdkInteropTest.cpp
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <aidl/BnBinderRustNdkInteropTest.h>
+#include <aidl/IBinderRustNdkInteropTest.h>
+#include <android/binder_ibinder.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+#include <binder/Status.h>
+#include <gtest/gtest.h>
+
+using namespace android;
+using ::ndk::ScopedAStatus;
+using ::ndk::SharedRefBase;
+using ::ndk::SpAIBinder;
+
+static const char* kNdkServerName = "NdkServer-BinderRustNdkInteropTest";
+static const char* kRustServerName = "RustServer-BinderRustNdkInteropTest";
+
+extern "C" {
+int rust_call_ndk(const char* service_name);
+int rust_start_service(const char* service_name);
+}
+
+class NdkServer : public aidl::BnBinderRustNdkInteropTest {
+ ScopedAStatus echo(const std::string& in, std::string* out) override {
+ *out = in;
+ return ScopedAStatus::ok();
+ }
+};
+
+TEST(RustNdkInterop, RustCanCallNdk) {
+ ASSERT_EQ(STATUS_OK, rust_call_ndk(kNdkServerName));
+}
+
+TEST(RustNdkInterop, NdkCanCallRust) {
+ ASSERT_EQ(STATUS_OK, rust_start_service(kRustServerName));
+
+ SpAIBinder binder = SpAIBinder(AServiceManager_checkService(kRustServerName));
+ ASSERT_NE(nullptr, binder.get());
+ EXPECT_EQ(STATUS_OK, AIBinder_ping(binder.get()));
+
+ auto interface = aidl::IBinderRustNdkInteropTest::fromBinder(binder);
+ // TODO(b/167723746): this test requires that fromBinder allow association
+ // with an already associated local binder by treating it as remote.
+ EXPECT_EQ(interface, nullptr);
+
+ // std::string in("testing");
+ // std::string out;
+ // EXPECT_TRUE(interface->echo(in, &out).isOk());
+ // EXPECT_EQ(in, out);
+}
+
+int main(int argc, char** argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+
+ // so we can host a client and service concurrently
+ ABinderProcess_setThreadPoolMaxThreadCount(1);
+ ABinderProcess_startThreadPool();
+
+ std::shared_ptr<NdkServer> ndkServer = SharedRefBase::make<NdkServer>();
+ EXPECT_EQ(STATUS_OK, AServiceManager_addService(ndkServer->asBinder().get(), kNdkServerName));
+
+ return RUN_ALL_TESTS();
+}
diff --git a/libs/binder/rust/tests/integration.rs b/libs/binder/rust/tests/integration.rs
index 953d328..bb8c492 100644
--- a/libs/binder/rust/tests/integration.rs
+++ b/libs/binder/rust/tests/integration.rs
@@ -173,6 +173,30 @@
}
}
+/// Trivial testing binder interface
+pub trait ITestSameDescriptor: Interface {}
+
+declare_binder_interface! {
+ ITestSameDescriptor["android.os.ITest"] {
+ native: BnTestSameDescriptor(on_transact_same_descriptor),
+ proxy: BpTestSameDescriptor,
+ }
+}
+
+fn on_transact_same_descriptor(
+ _service: &dyn ITestSameDescriptor,
+ _code: TransactionCode,
+ _data: &Parcel,
+ _reply: &mut Parcel,
+) -> binder::Result<()> {
+ Ok(())
+}
+
+impl ITestSameDescriptor for BpTestSameDescriptor {}
+
+impl ITestSameDescriptor for Binder<BnTestSameDescriptor> {}
+
+
#[cfg(test)]
mod tests {
use selinux_bindgen as selinux_sys;
@@ -185,9 +209,9 @@
use std::thread;
use std::time::Duration;
- use binder::{DeathRecipient, FromIBinder, IBinder, SpIBinder, StatusCode};
+ use binder::{Binder, DeathRecipient, FromIBinder, IBinder, Interface, SpIBinder, StatusCode};
- use super::{ITest, RUST_SERVICE_BINARY};
+ use super::{BnTest, ITest, ITestSameDescriptor, RUST_SERVICE_BINARY, TestService};
pub struct ScopedServiceProcess(Child);
@@ -435,4 +459,40 @@
assert_eq!(extension.test().unwrap(), extension_name);
}
}
+
+ /// Test re-associating a local binder object with a different class.
+ ///
+ /// This is needed because different binder service (e.g. NDK vs Rust)
+ /// implementations are incompatible and must not be interchanged. A local
+ /// service with the same descriptor string but a different class pointer
+ /// may have been created by an NDK service and is therefore incompatible
+ /// with the Rust service implementation. It must be treated as remote and
+ /// all API calls parceled and sent through transactions.
+ ///
+ /// Further tests of this behavior with the C NDK and Rust API are in
+ /// rust_ndk_interop.rs
+ #[test]
+ fn associate_existing_class() {
+ let service = Binder::new(BnTest(Box::new(TestService {
+ s: "testing_service".to_string(),
+ })));
+
+ // This should succeed although we will have to treat the service as
+ // remote.
+ let _interface: Box<dyn ITestSameDescriptor> = FromIBinder::try_from(service.as_binder())
+ .expect("Could not re-interpret service as the ITestSameDescriptor interface");
+ }
+
+ /// Test that we can round-trip a rust service through a generic IBinder
+ #[test]
+ fn reassociate_rust_binder() {
+ let service_name = "testing_service";
+ let service_ibinder = BnTest::new_binder(TestService { s: service_name.to_string() })
+ .as_binder();
+
+ let service: Box<dyn ITest> = service_ibinder.into_interface()
+ .expect("Could not reassociate the generic ibinder");
+
+ assert_eq!(service.test().unwrap(), service_name);
+ }
}
diff --git a/libs/binder/rust/tests/ndk_rust_interop.rs b/libs/binder/rust/tests/ndk_rust_interop.rs
new file mode 100644
index 0000000..70a6dc0
--- /dev/null
+++ b/libs/binder/rust/tests/ndk_rust_interop.rs
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//! Rust Binder NDK interop tests
+
+use std::ffi::CStr;
+use std::os::raw::{c_char, c_int};
+use ::IBinderRustNdkInteropTest::binder::{self, Interface, StatusCode};
+use ::IBinderRustNdkInteropTest::aidl::IBinderRustNdkInteropTest::{
+ BnBinderRustNdkInteropTest, IBinderRustNdkInteropTest,
+};
+use ::IBinderRustNdkInteropTest::aidl::IBinderRustNdkInteropTestOther::{
+ IBinderRustNdkInteropTestOther,
+};
+
+/// Look up the provided AIDL service and call its echo method.
+///
+/// # Safety
+///
+/// service_name must be a valid, non-null C-style string (null-terminated).
+#[no_mangle]
+pub unsafe extern "C" fn rust_call_ndk(service_name: *const c_char) -> c_int {
+ let service_name = CStr::from_ptr(service_name).to_str().unwrap();
+
+ // The Rust class descriptor pointer will not match the NDK one, but the
+ // descriptor strings match so this needs to still associate.
+ let service: Box<dyn IBinderRustNdkInteropTest> = match binder::get_interface(service_name) {
+ Err(e) => {
+ eprintln!("Could not find Ndk service {}: {:?}", service_name, e);
+ return StatusCode::NAME_NOT_FOUND as c_int;
+ }
+ Ok(service) => service,
+ };
+
+ match service.echo("testing") {
+ Ok(s) => if s != "testing" {
+ return StatusCode::BAD_VALUE as c_int;
+ },
+ Err(e) => return e.into(),
+ }
+
+ // Try using the binder service through the wrong interface type
+ let wrong_service: Result<Box<dyn IBinderRustNdkInteropTestOther>, StatusCode> =
+ binder::get_interface(service_name);
+ match wrong_service {
+ Err(e) if e == StatusCode::BAD_TYPE => {}
+ Err(e) => {
+ eprintln!("Trying to use a service via the wrong interface errored with unexpected error {:?}", e);
+ return e as c_int;
+ }
+ Ok(_) => {
+ eprintln!("We should not be allowed to use a service via the wrong interface");
+ return StatusCode::BAD_TYPE as c_int;
+ }
+ }
+
+ StatusCode::OK as c_int
+}
+
+struct Service;
+
+impl Interface for Service {}
+
+impl IBinderRustNdkInteropTest for Service {
+ fn echo(&self, s: &str) -> binder::Result<String> {
+ Ok(s.to_string())
+ }
+}
+
+/// Start the interop Echo test service with the given service name.
+///
+/// # Safety
+///
+/// service_name must be a valid, non-null C-style string (null-terminated).
+#[no_mangle]
+pub unsafe extern "C" fn rust_start_service(service_name: *const c_char) -> c_int {
+ let service_name = CStr::from_ptr(service_name).to_str().unwrap();
+ let service = BnBinderRustNdkInteropTest::new_binder(Service);
+ match binder::add_service(&service_name, service.as_binder()) {
+ Ok(_) => StatusCode::OK as c_int,
+ Err(e) => e as c_int,
+ }
+}
diff --git a/libs/binder/tests/binderLibTest.cpp b/libs/binder/tests/binderLibTest.cpp
index ad4729d..0f7d159 100644
--- a/libs/binder/tests/binderLibTest.cpp
+++ b/libs/binder/tests/binderLibTest.cpp
@@ -30,6 +30,7 @@
#include <binder/IServiceManager.h>
#include <private/binder/binder_module.h>
+#include <linux/sched.h>
#include <sys/epoll.h>
#include <sys/prctl.h>
@@ -53,6 +54,7 @@
static constexpr int kSchedPolicy = SCHED_RR;
static constexpr int kSchedPriority = 7;
+static constexpr int kSchedPriorityMore = 8;
static String16 binderLibTestServiceName = String16("test.binderLib");
@@ -1088,6 +1090,25 @@
EXPECT_EQ(kSchedPriority, priority);
}
+TEST_F(BinderLibTest, InheritRt) {
+ sp<IBinder> server = addServer();
+ ASSERT_TRUE(server != nullptr);
+
+ const struct sched_param param {
+ .sched_priority = kSchedPriorityMore,
+ };
+ EXPECT_EQ(0, sched_setscheduler(getpid(), SCHED_RR, ¶m));
+
+ Parcel data, reply;
+ status_t ret = server->transact(BINDER_LIB_TEST_GET_SCHEDULING_POLICY, data, &reply);
+ EXPECT_EQ(NO_ERROR, ret);
+
+ int policy = reply.readInt32();
+ int priority = reply.readInt32();
+
+ EXPECT_EQ(kSchedPolicy, policy & (~SCHED_RESET_ON_FORK));
+ EXPECT_EQ(kSchedPriorityMore, priority);
+}
TEST_F(BinderLibTest, VectorSent) {
Parcel data, reply;
@@ -1460,6 +1481,8 @@
testService->setMinSchedulerPolicy(kSchedPolicy, kSchedPriority);
+ testService->setInheritRt(true);
+
/*
* Normally would also contain functionality as well, but we are only
* testing the extension mechanism.
diff --git a/libs/binder/tests/fuzzers/BinderFuzzFunctions.h b/libs/binder/tests/fuzzers/BinderFuzzFunctions.h
index 9ac65bb..69f1b9d 100644
--- a/libs/binder/tests/fuzzers/BinderFuzzFunctions.h
+++ b/libs/binder/tests/fuzzers/BinderFuzzFunctions.h
@@ -37,8 +37,8 @@
bbinder->isRequestingSid();
},
[](FuzzedDataProvider* fdp, const sp<BBinder>& bbinder) -> void {
- bool request_sid = fdp->ConsumeBool();
- bbinder->setRequestingSid(request_sid);
+ bool requestSid = fdp->ConsumeBool();
+ bbinder->setRequestingSid(requestSid);
},
[](FuzzedDataProvider*, const sp<BBinder>& bbinder) -> void {
bbinder->getExtension();
@@ -63,6 +63,13 @@
[](FuzzedDataProvider*, const sp<BBinder>& bbinder) -> void {
bbinder->getMinSchedulerPriority();
},
+ [](FuzzedDataProvider* fdp, const sp<BBinder>& bbinder) -> void {
+ bool inheritRt = fdp->ConsumeBool();
+ bbinder->setInheritRt(inheritRt);
+ },
+ [](FuzzedDataProvider*, const sp<BBinder>& bbinder) -> void {
+ bbinder->isInheritRt();
+ },
[](FuzzedDataProvider*, const sp<BBinder>& bbinder) -> void {
bbinder->getDebugPid();
}};
diff --git a/libs/cputimeinstate/Android.bp b/libs/cputimeinstate/Android.bp
index b1943a4..e3cd085 100644
--- a/libs/cputimeinstate/Android.bp
+++ b/libs/cputimeinstate/Android.bp
@@ -33,5 +33,6 @@
"-Wall",
"-Wextra",
],
+ require_root: true,
}
diff --git a/libs/cputimeinstate/cputimeinstate.cpp b/libs/cputimeinstate/cputimeinstate.cpp
index 6058430..4209dc5 100644
--- a/libs/cputimeinstate/cputimeinstate.cpp
+++ b/libs/cputimeinstate/cputimeinstate.cpp
@@ -59,6 +59,7 @@
static unique_fd gTisMapFd;
static unique_fd gConcurrentMapFd;
static unique_fd gUidLastUpdateMapFd;
+static unique_fd gPidTisMapFd;
static std::optional<std::vector<uint32_t>> readNumbersFromFile(const std::string &path) {
std::string data;
@@ -139,6 +140,12 @@
unique_fd{bpf_obj_get(BPF_FS_PATH "map_time_in_state_uid_last_update_map")};
if (gUidLastUpdateMapFd < 0) return false;
+ gPidTisMapFd = unique_fd{mapRetrieveRO(BPF_FS_PATH "map_time_in_state_pid_time_in_state_map")};
+ if (gPidTisMapFd < 0) return false;
+
+ unique_fd trackedPidMapFd(mapRetrieveWO(BPF_FS_PATH "map_time_in_state_pid_tracked_map"));
+ if (trackedPidMapFd < 0) return false;
+
gInitialized = true;
return true;
}
@@ -222,7 +229,8 @@
}
gTracking = attachTracepointProgram("sched", "sched_switch") &&
- attachTracepointProgram("power", "cpu_frequency");
+ attachTracepointProgram("power", "cpu_frequency") &&
+ attachTracepointProgram("sched", "sched_process_free");
return gTracking;
}
@@ -502,5 +510,106 @@
return true;
}
+bool startTrackingProcessCpuTimes(pid_t pid) {
+ if (!gInitialized && !initGlobals()) return false;
+
+ unique_fd trackedPidHashMapFd(
+ mapRetrieveWO(BPF_FS_PATH "map_time_in_state_pid_tracked_hash_map"));
+ if (trackedPidHashMapFd < 0) return false;
+
+ unique_fd trackedPidMapFd(mapRetrieveWO(BPF_FS_PATH "map_time_in_state_pid_tracked_map"));
+ if (trackedPidMapFd < 0) return false;
+
+ for (uint32_t index = 0; index < MAX_TRACKED_PIDS; index++) {
+ // Find first available [index, pid] entry in the pid_tracked_hash_map map
+ if (writeToMapEntry(trackedPidHashMapFd, &index, &pid, BPF_NOEXIST) != 0) {
+ if (errno != EEXIST) {
+ return false;
+ }
+ continue; // This index is already taken
+ }
+
+ tracked_pid_t tracked_pid = {.pid = pid, .state = TRACKED_PID_STATE_ACTIVE};
+ if (writeToMapEntry(trackedPidMapFd, &index, &tracked_pid, BPF_ANY) != 0) {
+ return false;
+ }
+ return true;
+ }
+ return false;
+}
+
+// Marks the specified task identified by its PID (aka TID) for CPU time-in-state tracking
+// aggregated with other tasks sharing the same TGID and aggregation key.
+bool startAggregatingTaskCpuTimes(pid_t pid, uint16_t aggregationKey) {
+ if (!gInitialized && !initGlobals()) return false;
+
+ unique_fd taskAggregationMapFd(
+ mapRetrieveWO(BPF_FS_PATH "map_time_in_state_pid_task_aggregation_map"));
+ if (taskAggregationMapFd < 0) return false;
+
+ return writeToMapEntry(taskAggregationMapFd, &pid, &aggregationKey, BPF_ANY) == 0;
+}
+
+// Retrieves the times in ns that each thread spent running at each CPU freq, aggregated by
+// aggregation key.
+// Return contains no value on error, otherwise it contains a map from aggregation keys
+// to vectors of vectors using the format:
+// { aggKey0 -> [[t0_0_0, t0_0_1, ...], [t0_1_0, t0_1_1, ...], ...],
+// aggKey1 -> [[t1_0_0, t1_0_1, ...], [t1_1_0, t1_1_1, ...], ...], ... }
+// where ti_j_k is the ns tid i spent running on the jth cluster at the cluster's kth lowest freq.
+std::optional<std::unordered_map<uint16_t, std::vector<std::vector<uint64_t>>>>
+getAggregatedTaskCpuFreqTimes(pid_t tgid, const std::vector<uint16_t> &aggregationKeys) {
+ if (!gInitialized && !initGlobals()) return {};
+
+ uint32_t maxFreqCount = 0;
+ std::vector<std::vector<uint64_t>> mapFormat;
+ for (const auto &freqList : gPolicyFreqs) {
+ if (freqList.size() > maxFreqCount) maxFreqCount = freqList.size();
+ mapFormat.emplace_back(freqList.size(), 0);
+ }
+
+ bool dataCollected = false;
+ std::unordered_map<uint16_t, std::vector<std::vector<uint64_t>>> map;
+ std::vector<tis_val_t> vals(gNCpus);
+ for (uint16_t aggregationKey : aggregationKeys) {
+ map.emplace(aggregationKey, mapFormat);
+
+ aggregated_task_tis_key_t key{.tgid = tgid, .aggregation_key = aggregationKey};
+ for (key.bucket = 0; key.bucket <= (maxFreqCount - 1) / FREQS_PER_ENTRY; ++key.bucket) {
+ if (findMapEntry(gPidTisMapFd, &key, vals.data()) != 0) {
+ if (errno != ENOENT) {
+ return {};
+ }
+ continue;
+ } else {
+ dataCollected = true;
+ }
+
+ // Combine data by aggregating time-in-state data grouped by CPU cluster aka policy.
+ uint32_t offset = key.bucket * FREQS_PER_ENTRY;
+ uint32_t nextOffset = offset + FREQS_PER_ENTRY;
+ for (uint32_t j = 0; j < gNPolicies; ++j) {
+ if (offset >= gPolicyFreqs[j].size()) continue;
+ auto begin = map[key.aggregation_key][j].begin() + offset;
+ auto end = nextOffset < gPolicyFreqs[j].size() ? begin + FREQS_PER_ENTRY
+ : map[key.aggregation_key][j].end();
+ for (const auto &cpu : gPolicyCpus[j]) {
+ std::transform(begin, end, std::begin(vals[cpu].ar), begin,
+ std::plus<uint64_t>());
+ }
+ }
+ }
+ }
+
+ if (!dataCollected) {
+ // Check if eBPF is supported on this device. If it is, gTisMap should not be empty.
+ time_key_t key;
+ if (getFirstMapKey(gTisMapFd, &key) != 0) {
+ return {};
+ }
+ }
+ return map;
+}
+
} // namespace bpf
} // namespace android
diff --git a/libs/cputimeinstate/cputimeinstate.h b/libs/cputimeinstate/cputimeinstate.h
index b7600f5..87a328a 100644
--- a/libs/cputimeinstate/cputimeinstate.h
+++ b/libs/cputimeinstate/cputimeinstate.h
@@ -41,5 +41,10 @@
getUidsUpdatedConcurrentTimes(uint64_t *lastUpdate);
bool clearUidTimes(unsigned int uid);
+bool startTrackingProcessCpuTimes(pid_t pid);
+bool startAggregatingTaskCpuTimes(pid_t pid, uint16_t aggregationKey);
+std::optional<std::unordered_map<uint16_t, std::vector<std::vector<uint64_t>>>>
+getAggregatedTaskCpuFreqTimes(pid_t pid, const std::vector<uint16_t> &aggregationKeys);
+
} // namespace bpf
} // namespace android
diff --git a/libs/cputimeinstate/testtimeinstate.cpp b/libs/cputimeinstate/testtimeinstate.cpp
index 0d5f412..519689b 100644
--- a/libs/cputimeinstate/testtimeinstate.cpp
+++ b/libs/cputimeinstate/testtimeinstate.cpp
@@ -19,6 +19,8 @@
#include <sys/sysinfo.h>
+#include <pthread.h>
+#include <semaphore.h>
#include <numeric>
#include <unordered_map>
#include <vector>
@@ -504,5 +506,85 @@
for (size_t i = 0; i < freqs->size(); ++i) EXPECT_EQ((*freqs)[i].size(), (*times)[i].size());
}
+uint64_t timeNanos() {
+ struct timespec spec;
+ clock_gettime(CLOCK_MONOTONIC, &spec);
+ return spec.tv_sec * 1000000000 + spec.tv_nsec;
+}
+
+// Keeps CPU busy with some number crunching
+void useCpu() {
+ long sum = 0;
+ for (int i = 0; i < 100000; i++) {
+ sum *= i;
+ }
+}
+
+sem_t pingsem, pongsem;
+
+void *testThread(void *) {
+ for (int i = 0; i < 10; i++) {
+ sem_wait(&pingsem);
+ useCpu();
+ sem_post(&pongsem);
+ }
+ return nullptr;
+}
+
+TEST(TimeInStateTest, GetAggregatedTaskCpuFreqTimes) {
+ uint64_t startTimeNs = timeNanos();
+
+ sem_init(&pingsem, 0, 1);
+ sem_init(&pongsem, 0, 0);
+
+ pthread_t thread;
+ ASSERT_EQ(pthread_create(&thread, NULL, &testThread, NULL), 0);
+
+ // This process may have been running for some time, so when we start tracking
+ // CPU time, the very first switch may include the accumulated time.
+ // Yield the remainder of this timeslice to the newly created thread.
+ sem_wait(&pongsem);
+ sem_post(&pingsem);
+
+ pid_t tgid = getpid();
+ startTrackingProcessCpuTimes(tgid);
+
+ pid_t tid = pthread_gettid_np(thread);
+ startAggregatingTaskCpuTimes(tid, 42);
+
+ // Play ping-pong with the other thread to ensure that both threads get
+ // some CPU time.
+ for (int i = 0; i < 9; i++) {
+ sem_wait(&pongsem);
+ useCpu();
+ sem_post(&pingsem);
+ }
+
+ pthread_join(thread, NULL);
+
+ std::optional<std::unordered_map<uint16_t, std::vector<std::vector<uint64_t>>>> optionalMap =
+ getAggregatedTaskCpuFreqTimes(tgid, {0, 42});
+ ASSERT_TRUE(optionalMap);
+
+ std::unordered_map<uint16_t, std::vector<std::vector<uint64_t>>> map = *optionalMap;
+ ASSERT_EQ(map.size(), 2u);
+
+ uint64_t testDurationNs = timeNanos() - startTimeNs;
+ for (auto pair : map) {
+ uint16_t aggregationKey = pair.first;
+ ASSERT_TRUE(aggregationKey == 0 || aggregationKey == 42);
+
+ std::vector<std::vector<uint64_t>> timesInState = pair.second;
+ uint64_t totalCpuTime = 0;
+ for (size_t i = 0; i < timesInState.size(); i++) {
+ for (size_t j = 0; j < timesInState[i].size(); j++) {
+ totalCpuTime += timesInState[i][j];
+ }
+ }
+ ASSERT_GT(totalCpuTime, 0ul);
+ ASSERT_LE(totalCpuTime, testDurationNs);
+ }
+}
+
} // namespace bpf
} // namespace android
diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp
index 3a3a96f..b9ab561 100644
--- a/libs/gui/BLASTBufferQueue.cpp
+++ b/libs/gui/BLASTBufferQueue.cpp
@@ -150,6 +150,16 @@
if (mRequestedSize != newSize) {
mRequestedSize.set(newSize);
mBufferItemConsumer->setDefaultBufferSize(mRequestedSize.width, mRequestedSize.height);
+ if (mLastBufferScalingMode != NATIVE_WINDOW_SCALING_MODE_FREEZE) {
+ // If the buffer supports scaling, update the frame immediately since the client may
+ // want to scale the existing buffer to the new size.
+ mSize = mRequestedSize;
+ SurfaceComposerClient::Transaction t;
+ t.setFrame(mSurfaceControl,
+ {0, 0, static_cast<int32_t>(mSize.width),
+ static_cast<int32_t>(mSize.height)});
+ t.apply();
+ }
}
}
@@ -276,6 +286,8 @@
// Ensure BLASTBufferQueue stays alive until we receive the transaction complete callback.
incStrong((void*)transactionCallbackThunk);
+ mLastBufferScalingMode = bufferItem.mScalingMode;
+
t->setBuffer(mSurfaceControl, buffer);
t->setAcquireFence(mSurfaceControl,
bufferItem.mFence ? new Fence(bufferItem.mFence->dup()) : Fence::NO_FENCE);
@@ -348,7 +360,6 @@
bool BLASTBufferQueue::rejectBuffer(const BufferItem& item) {
if (item.mScalingMode != NATIVE_WINDOW_SCALING_MODE_FREEZE) {
- mSize = mRequestedSize;
// Only reject buffers if scaling mode is freeze.
return false;
}
diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h
index bdf128a..1139390 100644
--- a/libs/gui/include/gui/BLASTBufferQueue.h
+++ b/libs/gui/include/gui/BLASTBufferQueue.h
@@ -146,6 +146,11 @@
bool mAutoRefresh GUARDED_BY(mMutex) = false;
std::queue<int64_t> mNextFrameTimelineVsyncIdQueue GUARDED_BY(mMutex);
+
+ // Last acquired buffer's scaling mode. This is used to check if we should update the blast
+ // layer size immediately or wait until we get the next buffer. This will support scenarios
+ // where the layer can change sizes and the buffer will scale to fit the new size.
+ uint32_t mLastBufferScalingMode = NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW;
};
} // namespace android
diff --git a/libs/gui/include/gui/JankInfo.h b/libs/gui/include/gui/JankInfo.h
new file mode 100644
index 0000000..47daf95
--- /dev/null
+++ b/libs/gui/include/gui/JankInfo.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+namespace android {
+
+// Jank information tracked by SurfaceFlinger for the purpose of funneling to telemetry.
+enum JankType {
+ // No Jank
+ None = 0x0,
+ // Jank not related to SurfaceFlinger or the App
+ Display = 0x1,
+ // SF took too long on the CPU
+ SurfaceFlingerDeadlineMissed = 0x2,
+ // SF took too long on the GPU
+ SurfaceFlingerGpuDeadlineMissed = 0x4,
+ // Either App or GPU took too long on the frame
+ AppDeadlineMissed = 0x8,
+ // Predictions live for 120ms, if prediction is expired for a frame, there is definitely a
+ // jank
+ // associated with the App if this is for a SurfaceFrame, and SF for a DisplayFrame.
+ PredictionExpired = 0x10,
+ // Latching a buffer early might cause an early present of the frame
+ SurfaceFlingerEarlyLatch = 0x20,
+};
+
+} // namespace android
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.cpp b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
index c7e65a1..8dc0c68 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.cpp
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
@@ -492,8 +492,7 @@
// displays might have different scaling when compared to the physical screen.
canvas->clipRect(getSkRect(display.physicalDisplay));
- SkMatrix screenTransform;
- screenTransform.setTranslate(display.physicalDisplay.left, display.physicalDisplay.top);
+ canvas->translate(display.physicalDisplay.left, display.physicalDisplay.top);
const auto clipWidth = display.clip.width();
const auto clipHeight = display.clip.height();
@@ -507,31 +506,33 @@
static_cast<SkScalar>(rotatedClipWidth);
const auto scaleY = static_cast<SkScalar>(display.physicalDisplay.height()) /
static_cast<SkScalar>(rotatedClipHeight);
- screenTransform.preScale(scaleX, scaleY);
+ canvas->scale(scaleX, scaleY);
// Canvas rotation is done by centering the clip window at the origin, rotating, translating
// back so that the top left corner of the clip is at (0, 0).
- screenTransform.preTranslate(rotatedClipWidth / 2, rotatedClipHeight / 2);
- screenTransform.preRotate(toDegrees(display.orientation));
- screenTransform.preTranslate(-clipWidth / 2, -clipHeight / 2);
- screenTransform.preTranslate(-display.clip.left, -display.clip.top);
+ canvas->translate(rotatedClipWidth / 2, rotatedClipHeight / 2);
+ canvas->rotate(toDegrees(display.orientation));
+ canvas->translate(-clipWidth / 2, -clipHeight / 2);
+ canvas->translate(-display.clip.left, -display.clip.top);
for (const auto& layer : layers) {
- const SkMatrix drawTransform = getDrawTransform(layer, screenTransform);
+ canvas->save();
+
+ // Layers have a local transform that should be applied to them
+ canvas->concat(getSkM44(layer->geometry.positionTransform).asM33());
SkPaint paint;
const auto& bounds = layer->geometry.boundaries;
const auto dest = getSkRect(bounds);
+ const auto layerRect = canvas->getTotalMatrix().mapRect(dest);
std::unordered_map<uint32_t, sk_sp<SkSurface>> cachedBlurs;
-
if (mBlurFilter) {
- const auto layerRect = drawTransform.mapRect(dest);
if (layer->backgroundBlurRadius > 0) {
ATRACE_NAME("BackgroundBlur");
auto blurredSurface = mBlurFilter->generate(canvas, surface,
layer->backgroundBlurRadius, layerRect);
cachedBlurs[layer->backgroundBlurRadius] = blurredSurface;
- drawBlurRegion(canvas, getBlurRegion(layer), drawTransform, blurredSurface);
+ drawBlurRegion(canvas, getBlurRegion(layer), layerRect, blurredSurface);
}
if (layer->blurRegions.size() > 0) {
for (auto region : layer->blurRegions) {
@@ -677,12 +678,9 @@
paint.setColorFilter(SkColorFilters::Matrix(toSkColorMatrix(display.colorTransform)));
for (const auto effectRegion : layer->blurRegions) {
- drawBlurRegion(canvas, effectRegion, drawTransform,
- cachedBlurs[effectRegion.blurRadius]);
+ drawBlurRegion(canvas, effectRegion, layerRect, cachedBlurs[effectRegion.blurRadius]);
}
- canvas->save();
- canvas->concat(drawTransform);
if (layer->shadow.length > 0) {
const auto rect = layer->geometry.roundedCornersRadius > 0
? getSkRect(layer->geometry.roundedCornersCrop)
@@ -738,7 +736,7 @@
}
inline SkRRect SkiaGLRenderEngine::getRoundedRect(const LayerSettings* layer) {
- const auto rect = getSkRect(layer->geometry.roundedCornersCrop);
+ const auto rect = getSkRect(layer->geometry.boundaries);
const auto cornerRadius = layer->geometry.roundedCornersRadius;
return SkRRect::MakeRectXY(rect, cornerRadius, cornerRadius);
}
@@ -769,13 +767,6 @@
matrix[0][3], matrix[1][3], matrix[2][3], matrix[3][3]);
}
-inline SkMatrix SkiaGLRenderEngine::getDrawTransform(const LayerSettings* layer,
- const SkMatrix& screenTransform) {
- // Layers have a local transform matrix that should be applied to them.
- const auto layerTransform = getSkM44(layer->geometry.positionTransform).asM33();
- return SkMatrix::Concat(screenTransform, layerTransform);
-}
-
inline SkPoint3 SkiaGLRenderEngine::getSkPoint3(const vec3& vector) {
return SkPoint3::Make(vector.x, vector.y, vector.z);
}
@@ -805,18 +796,20 @@
}
void SkiaGLRenderEngine::drawBlurRegion(SkCanvas* canvas, const BlurRegion& effectRegion,
- const SkMatrix& drawTransform,
- sk_sp<SkSurface> blurredSurface) {
+ const SkRect& layerRect, sk_sp<SkSurface> blurredSurface) {
ATRACE_CALL();
SkPaint paint;
paint.setAlpha(static_cast<int>(effectRegion.alpha * 255));
- const auto matrix = mBlurFilter->getShaderMatrix();
- paint.setShader(blurredSurface->makeImageSnapshot()->makeShader(matrix));
+ const auto matrix = getBlurShaderTransform(canvas, layerRect);
+ paint.setShader(blurredSurface->makeImageSnapshot()->makeShader(
+ SkTileMode::kClamp,
+ SkTileMode::kClamp,
+ SkSamplingOptions({SkFilterMode::kLinear, SkMipmapMode::kNone}),
+ &matrix));
auto rect = SkRect::MakeLTRB(effectRegion.left, effectRegion.top, effectRegion.right,
effectRegion.bottom);
- drawTransform.mapRect(&rect);
if (effectRegion.cornerRadiusTL > 0 || effectRegion.cornerRadiusTR > 0 ||
effectRegion.cornerRadiusBL > 0 || effectRegion.cornerRadiusBR > 0) {
@@ -833,6 +826,24 @@
}
}
+SkMatrix SkiaGLRenderEngine::getBlurShaderTransform(const SkCanvas* canvas,
+ const SkRect& layerRect) {
+ // 1. Apply the blur shader matrix, which scales up the blured surface to its real size
+ auto matrix = mBlurFilter->getShaderMatrix();
+ // 2. Since the blurred surface has the size of the layer, we align it with the
+ // top left corner of the layer position.
+ matrix.postConcat(SkMatrix::Translate(layerRect.fLeft, layerRect.fTop));
+ // 3. Finally, apply the inverse canvas matrix. The snapshot made in the BlurFilter is in the
+ // original surface orientation. The inverse matrix has to be applied to align the blur
+ // surface with the current orientation/position of the canvas.
+ SkMatrix drawInverse;
+ if (canvas->getTotalMatrix().invert(&drawInverse)) {
+ matrix.postConcat(drawInverse);
+ }
+
+ return matrix;
+}
+
EGLContext SkiaGLRenderEngine::createEglContext(EGLDisplay display, EGLConfig config,
EGLContext shareContext, bool useContextPriority,
Protection protection) {
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.h b/libs/renderengine/skia/SkiaGLRenderEngine.h
index f5eed1e..ef06bfa 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.h
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.h
@@ -77,15 +77,15 @@
inline BlurRegion getBlurRegion(const LayerSettings* layer);
inline SkColor getSkColor(const vec4& color);
inline SkM44 getSkM44(const mat4& matrix);
- inline SkMatrix getDrawTransform(const LayerSettings* layer, const SkMatrix& screenTransform);
inline SkPoint3 getSkPoint3(const vec3& vector);
base::unique_fd flush();
bool waitFence(base::unique_fd fenceFd);
void drawShadow(SkCanvas* canvas, const SkRect& casterRect, float casterCornerRadius,
const ShadowSettings& shadowSettings);
- void drawBlurRegion(SkCanvas* canvas, const BlurRegion& blurRegion,
- const SkMatrix& drawTransform, sk_sp<SkSurface> blurrendSurface);
+ void drawBlurRegion(SkCanvas* canvas, const BlurRegion& blurRegion, const SkRect& layerRect,
+ sk_sp<SkSurface> blurredSurface);
+ SkMatrix getBlurShaderTransform(const SkCanvas* canvas, const SkRect& layerRect);
EGLDisplay mEGLDisplay;
EGLContext mEGLContext;
diff --git a/libs/renderengine/skia/filters/BlurFilter.cpp b/libs/renderengine/skia/filters/BlurFilter.cpp
index f19b64a..8927be8 100644
--- a/libs/renderengine/skia/filters/BlurFilter.cpp
+++ b/libs/renderengine/skia/filters/BlurFilter.cpp
@@ -66,11 +66,10 @@
float numberOfPasses = std::min(kMaxPasses, (uint32_t)ceil(tmpRadius));
float radiusByPasses = tmpRadius / (float)numberOfPasses;
- SkImageInfo scaledInfo = SkImageInfo::MakeN32Premul((float)input->width() * kInputScale,
- (float)input->height() * kInputScale);
+ SkImageInfo scaledInfo = SkImageInfo::MakeN32Premul((float)rect.width() * kInputScale,
+ (float)rect.height() * kInputScale);
+ SkRect scaledRect = SkRect::MakeWH(scaledInfo.width(), scaledInfo.height());
- SkRect scaledRect = {rect.fLeft * kInputScale, rect.fTop * kInputScale,
- rect.fRight * kInputScale, rect.fBottom * kInputScale};
auto drawSurface = canvas->makeSurface(scaledInfo);
const float stepX = radiusByPasses;
@@ -80,7 +79,8 @@
SkSamplingOptions linear(SkFilterMode::kLinear, SkMipmapMode::kNone);
SkRuntimeShaderBuilder blurBuilder(mBlurEffect);
blurBuilder.child("input") =
- input->makeImageSnapshot()->makeShader(SkTileMode::kClamp, SkTileMode::kClamp, linear);
+ input->makeImageSnapshot(rect.round())
+ ->makeShader(SkTileMode::kClamp, SkTileMode::kClamp, linear);
blurBuilder.uniform("in_inverseScale") = kInverseInputScale;
blurBuilder.uniform("in_blurOffset") =
SkV2{stepX * kInverseInputScale, stepY * kInverseInputScale};
@@ -127,10 +127,6 @@
lastDrawTarget = readSurface;
}
- {
- ATRACE_NAME("Flush Offscreen Surfaces");
- lastDrawTarget->flushAndSubmit();
- }
return lastDrawTarget;
}
diff --git a/libs/vibrator/OWNERS b/libs/vibrator/OWNERS
new file mode 100644
index 0000000..0997e9f
--- /dev/null
+++ b/libs/vibrator/OWNERS
@@ -0,0 +1,2 @@
+lsandrade@google.com
+michaelwr@google.com
diff --git a/services/inputflinger/reader/EventHub.cpp b/services/inputflinger/reader/EventHub.cpp
index c5210b5..9671dec 100644
--- a/services/inputflinger/reader/EventHub.cpp
+++ b/services/inputflinger/reader/EventHub.cpp
@@ -475,25 +475,25 @@
}
InputDeviceIdentifier EventHub::getDeviceIdentifier(int32_t deviceId) const {
- AutoMutex _l(mLock);
+ std::lock_guard<std::mutex> lock(mLock);
Device* device = getDeviceLocked(deviceId);
return device != nullptr ? device->identifier : InputDeviceIdentifier();
}
Flags<InputDeviceClass> EventHub::getDeviceClasses(int32_t deviceId) const {
- AutoMutex _l(mLock);
+ std::lock_guard<std::mutex> lock(mLock);
Device* device = getDeviceLocked(deviceId);
return device != nullptr ? device->classes : Flags<InputDeviceClass>(0);
}
int32_t EventHub::getDeviceControllerNumber(int32_t deviceId) const {
- AutoMutex _l(mLock);
+ std::lock_guard<std::mutex> lock(mLock);
Device* device = getDeviceLocked(deviceId);
return device != nullptr ? device->controllerNumber : 0;
}
void EventHub::getConfiguration(int32_t deviceId, PropertyMap* outConfiguration) const {
- AutoMutex _l(mLock);
+ std::lock_guard<std::mutex> lock(mLock);
Device* device = getDeviceLocked(deviceId);
if (device != nullptr && device->configuration) {
*outConfiguration = *device->configuration;
@@ -507,7 +507,7 @@
outAxisInfo->clear();
if (axis >= 0 && axis <= ABS_MAX) {
- AutoMutex _l(mLock);
+ std::lock_guard<std::mutex> lock(mLock);
Device* device = getDeviceLocked(deviceId);
if (device != nullptr && device->hasValidFd() && device->absBitmask.test(axis)) {
@@ -534,7 +534,7 @@
bool EventHub::hasRelativeAxis(int32_t deviceId, int axis) const {
if (axis >= 0 && axis <= REL_MAX) {
- AutoMutex _l(mLock);
+ std::lock_guard<std::mutex> lock(mLock);
Device* device = getDeviceLocked(deviceId);
return device != nullptr ? device->relBitmask.test(axis) : false;
}
@@ -542,7 +542,7 @@
}
bool EventHub::hasInputProperty(int32_t deviceId, int property) const {
- AutoMutex _l(mLock);
+ std::lock_guard<std::mutex> lock(mLock);
Device* device = getDeviceLocked(deviceId);
return property >= 0 && property <= INPUT_PROP_MAX && device != nullptr
@@ -552,7 +552,7 @@
int32_t EventHub::getScanCodeState(int32_t deviceId, int32_t scanCode) const {
if (scanCode >= 0 && scanCode <= KEY_MAX) {
- AutoMutex _l(mLock);
+ std::lock_guard<std::mutex> lock(mLock);
Device* device = getDeviceLocked(deviceId);
if (device != nullptr && device->hasValidFd() && device->keyBitmask.test(scanCode)) {
@@ -565,7 +565,7 @@
}
int32_t EventHub::getKeyCodeState(int32_t deviceId, int32_t keyCode) const {
- AutoMutex _l(mLock);
+ std::lock_guard<std::mutex> lock(mLock);
Device* device = getDeviceLocked(deviceId);
if (device != nullptr && device->hasValidFd() && device->keyMap.haveKeyLayout()) {
@@ -588,7 +588,7 @@
int32_t EventHub::getSwitchState(int32_t deviceId, int32_t sw) const {
if (sw >= 0 && sw <= SW_MAX) {
- AutoMutex _l(mLock);
+ std::lock_guard<std::mutex> lock(mLock);
Device* device = getDeviceLocked(deviceId);
if (device != nullptr && device->hasValidFd() && device->swBitmask.test(sw)) {
@@ -604,7 +604,7 @@
*outValue = 0;
if (axis >= 0 && axis <= ABS_MAX) {
- AutoMutex _l(mLock);
+ std::lock_guard<std::mutex> lock(mLock);
Device* device = getDeviceLocked(deviceId);
if (device != nullptr && device->hasValidFd() && device->absBitmask.test(axis)) {
@@ -624,7 +624,7 @@
bool EventHub::markSupportedKeyCodes(int32_t deviceId, size_t numCodes, const int32_t* keyCodes,
uint8_t* outFlags) const {
- AutoMutex _l(mLock);
+ std::lock_guard<std::mutex> lock(mLock);
Device* device = getDeviceLocked(deviceId);
if (device != nullptr && device->keyMap.haveKeyLayout()) {
@@ -652,7 +652,7 @@
status_t EventHub::mapKey(int32_t deviceId, int32_t scanCode, int32_t usageCode, int32_t metaState,
int32_t* outKeycode, int32_t* outMetaState, uint32_t* outFlags) const {
- AutoMutex _l(mLock);
+ std::lock_guard<std::mutex> lock(mLock);
Device* device = getDeviceLocked(deviceId);
status_t status = NAME_NOT_FOUND;
@@ -692,7 +692,7 @@
}
status_t EventHub::mapAxis(int32_t deviceId, int32_t scanCode, AxisInfo* outAxisInfo) const {
- AutoMutex _l(mLock);
+ std::lock_guard<std::mutex> lock(mLock);
Device* device = getDeviceLocked(deviceId);
if (device != nullptr && device->keyMap.haveKeyLayout()) {
@@ -706,13 +706,13 @@
}
void EventHub::setExcludedDevices(const std::vector<std::string>& devices) {
- AutoMutex _l(mLock);
+ std::lock_guard<std::mutex> lock(mLock);
mExcludedDevices = devices;
}
bool EventHub::hasScanCode(int32_t deviceId, int32_t scanCode) const {
- AutoMutex _l(mLock);
+ std::lock_guard<std::mutex> lock(mLock);
Device* device = getDeviceLocked(deviceId);
if (device != nullptr && scanCode >= 0 && scanCode <= KEY_MAX) {
return device->keyBitmask.test(scanCode);
@@ -721,7 +721,7 @@
}
bool EventHub::hasLed(int32_t deviceId, int32_t led) const {
- AutoMutex _l(mLock);
+ std::lock_guard<std::mutex> lock(mLock);
Device* device = getDeviceLocked(deviceId);
int32_t sc;
if (device != nullptr && device->mapLed(led, &sc) == NO_ERROR) {
@@ -731,7 +731,7 @@
}
void EventHub::setLedState(int32_t deviceId, int32_t led, bool on) {
- AutoMutex _l(mLock);
+ std::lock_guard<std::mutex> lock(mLock);
Device* device = getDeviceLocked(deviceId);
if (device != nullptr && device->hasValidFd()) {
device->setLedStateLocked(led, on);
@@ -742,7 +742,7 @@
std::vector<VirtualKeyDefinition>& outVirtualKeys) const {
outVirtualKeys.clear();
- AutoMutex _l(mLock);
+ std::lock_guard<std::mutex> lock(mLock);
Device* device = getDeviceLocked(deviceId);
if (device != nullptr && device->virtualKeyMap) {
const std::vector<VirtualKeyDefinition> virtualKeys =
@@ -752,7 +752,7 @@
}
const std::shared_ptr<KeyCharacterMap> EventHub::getKeyCharacterMap(int32_t deviceId) const {
- AutoMutex _l(mLock);
+ std::lock_guard<std::mutex> lock(mLock);
Device* device = getDeviceLocked(deviceId);
if (device != nullptr) {
return device->getKeyCharacterMap();
@@ -761,7 +761,7 @@
}
bool EventHub::setKeyboardLayoutOverlay(int32_t deviceId, std::shared_ptr<KeyCharacterMap> map) {
- AutoMutex _l(mLock);
+ std::lock_guard<std::mutex> lock(mLock);
Device* device = getDeviceLocked(deviceId);
if (device != nullptr && map != nullptr && device->keyMap.keyCharacterMap != nullptr) {
device->keyMap.keyCharacterMap->combine(*map);
@@ -822,7 +822,7 @@
}
void EventHub::vibrate(int32_t deviceId, const VibrationElement& element) {
- AutoMutex _l(mLock);
+ std::lock_guard<std::mutex> lock(mLock);
Device* device = getDeviceLocked(deviceId);
if (device != nullptr && device->hasValidFd()) {
ff_effect effect;
@@ -857,7 +857,7 @@
}
void EventHub::cancelVibrate(int32_t deviceId) {
- AutoMutex _l(mLock);
+ std::lock_guard<std::mutex> lock(mLock);
Device* device = getDeviceLocked(deviceId);
if (device != nullptr && device->hasValidFd()) {
if (device->ffEffectPlaying) {
@@ -930,7 +930,7 @@
size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) {
ALOG_ASSERT(bufferSize >= 1);
- AutoMutex _l(mLock);
+ std::lock_guard<std::mutex> lock(mLock);
struct input_event readBuffer[bufferSize];
@@ -1184,7 +1184,7 @@
}
std::vector<TouchVideoFrame> EventHub::getVideoFrames(int32_t deviceId) {
- AutoMutex _l(mLock);
+ std::lock_guard<std::mutex> lock(mLock);
Device* device = getDeviceLocked(deviceId);
if (device == nullptr || !device->videoDevice) {
@@ -1593,7 +1593,7 @@
}
bool EventHub::isDeviceEnabled(int32_t deviceId) {
- AutoMutex _l(mLock);
+ std::lock_guard<std::mutex> lock(mLock);
Device* device = getDeviceLocked(deviceId);
if (device == nullptr) {
ALOGE("Invalid device id=%" PRId32 " provided to %s", deviceId, __func__);
@@ -1603,7 +1603,7 @@
}
status_t EventHub::enableDevice(int32_t deviceId) {
- AutoMutex _l(mLock);
+ std::lock_guard<std::mutex> lock(mLock);
Device* device = getDeviceLocked(deviceId);
if (device == nullptr) {
ALOGE("Invalid device id=%" PRId32 " provided to %s", deviceId, __func__);
@@ -1625,7 +1625,7 @@
}
status_t EventHub::disableDevice(int32_t deviceId) {
- AutoMutex _l(mLock);
+ std::lock_guard<std::mutex> lock(mLock);
Device* device = getDeviceLocked(deviceId);
if (device == nullptr) {
ALOGE("Invalid device id=%" PRId32 " provided to %s", deviceId, __func__);
@@ -1809,7 +1809,7 @@
void EventHub::requestReopenDevices() {
ALOGV("requestReopenDevices() called");
- AutoMutex _l(mLock);
+ std::lock_guard<std::mutex> lock(mLock);
mNeedToReopenDevices = true;
}
@@ -1817,7 +1817,7 @@
dump += "Event Hub State:\n";
{ // acquire lock
- AutoMutex _l(mLock);
+ std::lock_guard<std::mutex> lock(mLock);
dump += StringPrintf(INDENT "BuiltInKeyboardId: %d\n", mBuiltInKeyboardId);
@@ -1868,8 +1868,7 @@
void EventHub::monitor() {
// Acquire and release the lock to ensure that the event hub has not deadlocked.
- mLock.lock();
- mLock.unlock();
+ std::unique_lock<std::mutex> lock(mLock);
}
}; // namespace android
diff --git a/services/inputflinger/reader/InputReader.cpp b/services/inputflinger/reader/InputReader.cpp
index e263f01..6216d78 100644
--- a/services/inputflinger/reader/InputReader.cpp
+++ b/services/inputflinger/reader/InputReader.cpp
@@ -56,7 +56,7 @@
mQueuedListener = new QueuedInputListener(listener);
{ // acquire lock
- AutoMutex _l(mLock);
+ std::lock_guard<std::mutex> lock(mLock);
refreshConfigurationLocked(0);
updateGlobalMetaStateLocked();
@@ -87,8 +87,9 @@
int32_t oldGeneration;
int32_t timeoutMillis;
bool inputDevicesChanged = false;
+ std::vector<InputDeviceInfo> inputDevices;
{ // acquire lock
- AutoMutex _l(mLock);
+ std::lock_guard<std::mutex> lock(mLock);
oldGeneration = mGeneration;
timeoutMillis = -1;
@@ -107,8 +108,8 @@
size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);
{ // acquire lock
- AutoMutex _l(mLock);
- mReaderIsAliveCondition.broadcast();
+ std::lock_guard<std::mutex> lock(mLock);
+ mReaderIsAliveCondition.notify_all();
if (count) {
processEventsLocked(mEventBuffer, count);
@@ -127,12 +128,13 @@
if (oldGeneration != mGeneration) {
inputDevicesChanged = true;
+ inputDevices = getInputDevicesLocked();
}
} // release lock
// Send out a message that the describes the changed input devices.
if (inputDevicesChanged) {
- mPolicy->notifyInputDevicesChanged(getInputDevicesLocked());
+ mPolicy->notifyInputDevicesChanged(inputDevices);
}
// Flush queued events out to the listener.
@@ -216,7 +218,7 @@
bumpGenerationLocked();
if (device->getClasses().test(InputDeviceClass::EXTERNAL_STYLUS)) {
- notifyExternalStylusPresenceChanged();
+ notifyExternalStylusPresenceChangedLocked();
}
}
@@ -256,7 +258,7 @@
device->removeEventHubDevice(eventHubId);
if (device->getClasses().test(InputDeviceClass::EXTERNAL_STYLUS)) {
- notifyExternalStylusPresenceChanged();
+ notifyExternalStylusPresenceChangedLocked();
}
if (device->hasEventHubDevices()) {
@@ -301,7 +303,7 @@
device->process(rawEvents, count);
}
-InputDevice* InputReader::findInputDevice(int32_t deviceId) {
+InputDevice* InputReader::findInputDeviceLocked(int32_t deviceId) {
auto deviceIt =
std::find_if(mDevices.begin(), mDevices.end(), [deviceId](const auto& devicePair) {
return devicePair.second->getId() == deviceId;
@@ -389,7 +391,7 @@
return mLedMetaState;
}
-void InputReader::notifyExternalStylusPresenceChanged() {
+void InputReader::notifyExternalStylusPresenceChangedLocked() {
refreshConfigurationLocked(InputReaderConfiguration::CHANGE_EXTERNAL_STYLUS_PRESENCE);
}
@@ -405,6 +407,7 @@
}
void InputReader::dispatchExternalStylusState(const StylusState& state) {
+ std::lock_guard<std::mutex> lock(mLock);
for (auto& devicePair : mDevices) {
std::shared_ptr<InputDevice>& device = devicePair.second;
device->updateExternalStylusState(state);
@@ -479,7 +482,7 @@
}
std::vector<InputDeviceInfo> InputReader::getInputDevices() const {
- AutoMutex _l(mLock);
+ std::lock_guard<std::mutex> lock(mLock);
return getInputDevicesLocked();
}
@@ -498,19 +501,19 @@
}
int32_t InputReader::getKeyCodeState(int32_t deviceId, uint32_t sourceMask, int32_t keyCode) {
- AutoMutex _l(mLock);
+ std::lock_guard<std::mutex> lock(mLock);
return getStateLocked(deviceId, sourceMask, keyCode, &InputDevice::getKeyCodeState);
}
int32_t InputReader::getScanCodeState(int32_t deviceId, uint32_t sourceMask, int32_t scanCode) {
- AutoMutex _l(mLock);
+ std::lock_guard<std::mutex> lock(mLock);
return getStateLocked(deviceId, sourceMask, scanCode, &InputDevice::getScanCodeState);
}
int32_t InputReader::getSwitchState(int32_t deviceId, uint32_t sourceMask, int32_t switchCode) {
- AutoMutex _l(mLock);
+ std::lock_guard<std::mutex> lock(mLock);
return getStateLocked(deviceId, sourceMask, switchCode, &InputDevice::getSwitchState);
}
@@ -519,7 +522,7 @@
GetStateFunc getStateFunc) {
int32_t result = AKEY_STATE_UNKNOWN;
if (deviceId >= 0) {
- InputDevice* device = findInputDevice(deviceId);
+ InputDevice* device = findInputDeviceLocked(deviceId);
if (device && !device->isIgnored() && sourcesMatchMask(device->getSources(), sourceMask)) {
result = (device->*getStateFunc)(sourceMask, code);
}
@@ -542,7 +545,8 @@
}
void InputReader::toggleCapsLockState(int32_t deviceId) {
- InputDevice* device = findInputDevice(deviceId);
+ std::lock_guard<std::mutex> lock(mLock);
+ InputDevice* device = findInputDeviceLocked(deviceId);
if (!device) {
ALOGW("Ignoring toggleCapsLock for unknown deviceId %" PRId32 ".", deviceId);
return;
@@ -557,7 +561,7 @@
bool InputReader::hasKeys(int32_t deviceId, uint32_t sourceMask, size_t numCodes,
const int32_t* keyCodes, uint8_t* outFlags) {
- AutoMutex _l(mLock);
+ std::lock_guard<std::mutex> lock(mLock);
memset(outFlags, 0, numCodes);
return markSupportedKeyCodesLocked(deviceId, sourceMask, numCodes, keyCodes, outFlags);
@@ -568,7 +572,7 @@
uint8_t* outFlags) {
bool result = false;
if (deviceId >= 0) {
- InputDevice* device = findInputDevice(deviceId);
+ InputDevice* device = findInputDeviceLocked(deviceId);
if (device && !device->isIgnored() && sourcesMatchMask(device->getSources(), sourceMask)) {
result = device->markSupportedKeyCodes(sourceMask, numCodes, keyCodes, outFlags);
}
@@ -584,7 +588,7 @@
}
void InputReader::requestRefreshConfiguration(uint32_t changes) {
- AutoMutex _l(mLock);
+ std::lock_guard<std::mutex> lock(mLock);
if (changes) {
bool needWake = !mConfigurationChangesToRefresh;
@@ -598,26 +602,26 @@
void InputReader::vibrate(int32_t deviceId, const std::vector<VibrationElement>& pattern,
ssize_t repeat, int32_t token) {
- AutoMutex _l(mLock);
- InputDevice* device = findInputDevice(deviceId);
+ std::lock_guard<std::mutex> lock(mLock);
+ InputDevice* device = findInputDeviceLocked(deviceId);
if (device) {
device->vibrate(pattern, repeat, token);
}
}
void InputReader::cancelVibrate(int32_t deviceId, int32_t token) {
- AutoMutex _l(mLock);
+ std::lock_guard<std::mutex> lock(mLock);
- InputDevice* device = findInputDevice(deviceId);
+ InputDevice* device = findInputDeviceLocked(deviceId);
if (device) {
device->cancelVibrate(token);
}
}
bool InputReader::isInputDeviceEnabled(int32_t deviceId) {
- AutoMutex _l(mLock);
+ std::lock_guard<std::mutex> lock(mLock);
- InputDevice* device = findInputDevice(deviceId);
+ InputDevice* device = findInputDeviceLocked(deviceId);
if (device) {
return device->isEnabled();
}
@@ -626,9 +630,9 @@
}
bool InputReader::canDispatchToDisplay(int32_t deviceId, int32_t displayId) {
- AutoMutex _l(mLock);
+ std::lock_guard<std::mutex> lock(mLock);
- InputDevice* device = findInputDevice(deviceId);
+ InputDevice* device = findInputDeviceLocked(deviceId);
if (!device) {
ALOGW("Ignoring invalid device id %" PRId32 ".", deviceId);
return false;
@@ -654,7 +658,7 @@
}
void InputReader::dump(std::string& dump) {
- AutoMutex _l(mLock);
+ std::lock_guard<std::mutex> lock(mLock);
mEventHub->dump(dump);
dump += "\n";
@@ -729,11 +733,9 @@
void InputReader::monitor() {
// Acquire and release the lock to ensure that the reader has not deadlocked.
- mLock.lock();
+ std::unique_lock<std::mutex> lock(mLock);
mEventHub->wake();
- mReaderIsAliveCondition.wait(mLock);
- mLock.unlock();
-
+ mReaderIsAliveCondition.wait(lock);
// Check the EventHub
mEventHub->monitor();
}
diff --git a/services/inputflinger/reader/include/EventHub.h b/services/inputflinger/reader/include/EventHub.h
index edb82d3..a3f881e 100644
--- a/services/inputflinger/reader/include/EventHub.h
+++ b/services/inputflinger/reader/include/EventHub.h
@@ -502,7 +502,7 @@
void releaseControllerNumberLocked(int32_t num);
// Protect all internal state.
- mutable Mutex mLock;
+ mutable std::mutex mLock;
// The actual id of the built-in keyboard, or NO_BUILT_IN_KEYBOARD if none.
// EventHub remaps the built-in keyboard to id 0 externally as required by the API.
diff --git a/services/inputflinger/reader/include/InputReader.h b/services/inputflinger/reader/include/InputReader.h
index 563018a..9b07681d 100644
--- a/services/inputflinger/reader/include/InputReader.h
+++ b/services/inputflinger/reader/include/InputReader.h
@@ -18,6 +18,7 @@
#define _UI_INPUTREADER_INPUT_READER_H
#include <PointerControllerInterface.h>
+#include <android-base/thread_annotations.h>
#include <utils/Condition.h>
#include <utils/Mutex.h>
@@ -84,8 +85,9 @@
protected:
// These members are protected so they can be instrumented by test cases.
- virtual std::shared_ptr<InputDevice> createDeviceLocked(
- int32_t deviceId, const InputDeviceIdentifier& identifier);
+ virtual std::shared_ptr<InputDevice> createDeviceLocked(int32_t deviceId,
+ const InputDeviceIdentifier& identifier)
+ REQUIRES(mLock);
// With each iteration of the loop, InputReader reads and processes one incoming message from
// the EventHub.
@@ -97,33 +99,37 @@
public:
explicit ContextImpl(InputReader* reader);
-
- void updateGlobalMetaState() override;
- int32_t getGlobalMetaState() override;
- void disableVirtualKeysUntil(nsecs_t time) override;
- bool shouldDropVirtualKey(nsecs_t now, int32_t keyCode, int32_t scanCode) override;
- void fadePointer() override;
- std::shared_ptr<PointerControllerInterface> getPointerController(int32_t deviceId) override;
- void requestTimeoutAtTime(nsecs_t when) override;
- int32_t bumpGeneration() override;
- void getExternalStylusDevices(std::vector<InputDeviceInfo>& outDevices) override;
- void dispatchExternalStylusState(const StylusState& outState) override;
- InputReaderPolicyInterface* getPolicy() override;
- InputListenerInterface* getListener() override;
- EventHubInterface* getEventHub() override;
- int32_t getNextId() override;
- void updateLedMetaState(int32_t metaState) override;
- int32_t getLedMetaState() override;
+ // lock is already held by the input loop
+ void updateGlobalMetaState() NO_THREAD_SAFETY_ANALYSIS override;
+ int32_t getGlobalMetaState() NO_THREAD_SAFETY_ANALYSIS override;
+ void disableVirtualKeysUntil(nsecs_t time) NO_THREAD_SAFETY_ANALYSIS override;
+ bool shouldDropVirtualKey(nsecs_t now, int32_t keyCode,
+ int32_t scanCode) NO_THREAD_SAFETY_ANALYSIS override;
+ void fadePointer() NO_THREAD_SAFETY_ANALYSIS override;
+ std::shared_ptr<PointerControllerInterface> getPointerController(int32_t deviceId)
+ NO_THREAD_SAFETY_ANALYSIS override;
+ void requestTimeoutAtTime(nsecs_t when) NO_THREAD_SAFETY_ANALYSIS override;
+ int32_t bumpGeneration() NO_THREAD_SAFETY_ANALYSIS override;
+ void getExternalStylusDevices(std::vector<InputDeviceInfo>& outDevices)
+ NO_THREAD_SAFETY_ANALYSIS override;
+ void dispatchExternalStylusState(const StylusState& outState)
+ NO_THREAD_SAFETY_ANALYSIS override;
+ InputReaderPolicyInterface* getPolicy() NO_THREAD_SAFETY_ANALYSIS override;
+ InputListenerInterface* getListener() NO_THREAD_SAFETY_ANALYSIS override;
+ EventHubInterface* getEventHub() NO_THREAD_SAFETY_ANALYSIS override;
+ int32_t getNextId() NO_THREAD_SAFETY_ANALYSIS override;
+ void updateLedMetaState(int32_t metaState) NO_THREAD_SAFETY_ANALYSIS override;
+ int32_t getLedMetaState() NO_THREAD_SAFETY_ANALYSIS override;
} mContext;
friend class ContextImpl;
+ // Test cases need to override the locked functions
+ mutable std::mutex mLock;
private:
std::unique_ptr<InputThread> mThread;
- mutable Mutex mLock;
-
- Condition mReaderIsAliveCondition;
+ std::condition_variable mReaderIsAliveCondition;
// This could be unique_ptr, but due to the way InputReader tests are written,
// it is made shared_ptr here. In the tests, an EventHub reference is retained by the test
@@ -132,76 +138,79 @@
sp<InputReaderPolicyInterface> mPolicy;
sp<QueuedInputListener> mQueuedListener;
- InputReaderConfiguration mConfig;
+ InputReaderConfiguration mConfig GUARDED_BY(mLock);
// The event queue.
static const int EVENT_BUFFER_SIZE = 256;
- RawEvent mEventBuffer[EVENT_BUFFER_SIZE];
+ RawEvent mEventBuffer[EVENT_BUFFER_SIZE] GUARDED_BY(mLock);
// An input device can represent a collection of EventHub devices. This map provides a way
// to lookup the input device instance from the EventHub device id.
- std::unordered_map<int32_t /*eventHubId*/, std::shared_ptr<InputDevice>> mDevices;
+ std::unordered_map<int32_t /*eventHubId*/, std::shared_ptr<InputDevice>> mDevices
+ GUARDED_BY(mLock);
// An input device contains one or more eventHubId, this map provides a way to lookup the
// EventHubIds contained in the input device from the input device instance.
std::unordered_map<std::shared_ptr<InputDevice>, std::vector<int32_t> /*eventHubId*/>
- mDeviceToEventHubIdsMap;
+ mDeviceToEventHubIdsMap GUARDED_BY(mLock);
// low-level input event decoding and device management
- void processEventsLocked(const RawEvent* rawEvents, size_t count);
+ void processEventsLocked(const RawEvent* rawEvents, size_t count) REQUIRES(mLock);
- void addDeviceLocked(nsecs_t when, int32_t eventHubId);
- void removeDeviceLocked(nsecs_t when, int32_t eventHubId);
- void processEventsForDeviceLocked(int32_t eventHubId, const RawEvent* rawEvents, size_t count);
- void timeoutExpiredLocked(nsecs_t when);
+ void addDeviceLocked(nsecs_t when, int32_t eventHubId) REQUIRES(mLock);
+ void removeDeviceLocked(nsecs_t when, int32_t eventHubId) REQUIRES(mLock);
+ void processEventsForDeviceLocked(int32_t eventHubId, const RawEvent* rawEvents, size_t count)
+ REQUIRES(mLock);
+ void timeoutExpiredLocked(nsecs_t when) REQUIRES(mLock);
- void handleConfigurationChangedLocked(nsecs_t when);
+ void handleConfigurationChangedLocked(nsecs_t when) REQUIRES(mLock);
- int32_t mGlobalMetaState;
- void updateGlobalMetaStateLocked();
- int32_t getGlobalMetaStateLocked();
+ int32_t mGlobalMetaState GUARDED_BY(mLock);
+ void updateGlobalMetaStateLocked() REQUIRES(mLock);
+ int32_t getGlobalMetaStateLocked() REQUIRES(mLock);
- int32_t mLedMetaState;
- void updateLedMetaStateLocked(int32_t metaState);
- int32_t getLedMetaStateLocked();
+ int32_t mLedMetaState GUARDED_BY(mLock);
+ void updateLedMetaStateLocked(int32_t metaState) REQUIRES(mLock);
+ int32_t getLedMetaStateLocked() REQUIRES(mLock);
- void notifyExternalStylusPresenceChanged();
- void getExternalStylusDevicesLocked(std::vector<InputDeviceInfo>& outDevices);
+ void notifyExternalStylusPresenceChangedLocked() REQUIRES(mLock);
+ void getExternalStylusDevicesLocked(std::vector<InputDeviceInfo>& outDevices) REQUIRES(mLock);
void dispatchExternalStylusState(const StylusState& state);
// The PointerController that is shared among all the input devices that need it.
std::weak_ptr<PointerControllerInterface> mPointerController;
- std::shared_ptr<PointerControllerInterface> getPointerControllerLocked(int32_t deviceId);
- void updatePointerDisplayLocked();
- void fadePointerLocked();
+ std::shared_ptr<PointerControllerInterface> getPointerControllerLocked(int32_t deviceId)
+ REQUIRES(mLock);
+ void updatePointerDisplayLocked() REQUIRES(mLock);
+ void fadePointerLocked() REQUIRES(mLock);
- int32_t mGeneration;
- int32_t bumpGenerationLocked();
+ int32_t mGeneration GUARDED_BY(mLock);
+ int32_t bumpGenerationLocked() REQUIRES(mLock);
- int32_t mNextInputDeviceId;
- int32_t nextInputDeviceIdLocked();
+ int32_t mNextInputDeviceId GUARDED_BY(mLock);
+ int32_t nextInputDeviceIdLocked() REQUIRES(mLock);
- std::vector<InputDeviceInfo> getInputDevicesLocked() const;
+ std::vector<InputDeviceInfo> getInputDevicesLocked() const REQUIRES(mLock);
- nsecs_t mDisableVirtualKeysTimeout;
- void disableVirtualKeysUntilLocked(nsecs_t time);
- bool shouldDropVirtualKeyLocked(nsecs_t now, int32_t keyCode, int32_t scanCode);
+ nsecs_t mDisableVirtualKeysTimeout GUARDED_BY(mLock);
+ void disableVirtualKeysUntilLocked(nsecs_t time) REQUIRES(mLock);
+ bool shouldDropVirtualKeyLocked(nsecs_t now, int32_t keyCode, int32_t scanCode) REQUIRES(mLock);
- nsecs_t mNextTimeout;
- void requestTimeoutAtTimeLocked(nsecs_t when);
+ nsecs_t mNextTimeout GUARDED_BY(mLock);
+ void requestTimeoutAtTimeLocked(nsecs_t when) REQUIRES(mLock);
- uint32_t mConfigurationChangesToRefresh;
- void refreshConfigurationLocked(uint32_t changes);
+ uint32_t mConfigurationChangesToRefresh GUARDED_BY(mLock);
+ void refreshConfigurationLocked(uint32_t changes) REQUIRES(mLock);
// state queries
typedef int32_t (InputDevice::*GetStateFunc)(uint32_t sourceMask, int32_t code);
int32_t getStateLocked(int32_t deviceId, uint32_t sourceMask, int32_t code,
- GetStateFunc getStateFunc);
+ GetStateFunc getStateFunc) REQUIRES(mLock);
bool markSupportedKeyCodesLocked(int32_t deviceId, uint32_t sourceMask, size_t numCodes,
- const int32_t* keyCodes, uint8_t* outFlags);
+ const int32_t* keyCodes, uint8_t* outFlags) REQUIRES(mLock);
// find an InputDevice from an InputDevice id
- InputDevice* findInputDevice(int32_t deviceId);
+ InputDevice* findInputDeviceLocked(int32_t deviceId) REQUIRES(mLock);
};
} // namespace android
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index 99eaac6..5a4c881 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -1030,8 +1030,9 @@
using InputReader::loopOnce;
protected:
- virtual std::shared_ptr<InputDevice> createDeviceLocked(
- int32_t eventHubId, const InputDeviceIdentifier& identifier) {
+ virtual std::shared_ptr<InputDevice> createDeviceLocked(int32_t eventHubId,
+ const InputDeviceIdentifier& identifier)
+ REQUIRES(mLock) {
if (!mNextDevices.empty()) {
std::shared_ptr<InputDevice> device(std::move(mNextDevices.front()));
mNextDevices.pop();
diff --git a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
index ef5f5ad..b45c213 100644
--- a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
+++ b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
@@ -94,19 +94,19 @@
}
}
-std::string toString(TimeStats::JankType jankType) {
+std::string toString(JankType jankType) {
switch (jankType) {
- case TimeStats::JankType::None:
+ case JankType::None:
return "None";
- case TimeStats::JankType::Display:
+ case JankType::Display:
return "Composer/Display - outside SF and App";
- case TimeStats::JankType::SurfaceFlingerDeadlineMissed:
+ case JankType::SurfaceFlingerDeadlineMissed:
return "SurfaceFlinger Deadline Missed";
- case TimeStats::JankType::AppDeadlineMissed:
+ case JankType::AppDeadlineMissed:
return "App Deadline Missed";
- case TimeStats::JankType::PredictionExpired:
+ case JankType::PredictionExpired:
return "Prediction Expired";
- case TimeStats::JankType::SurfaceFlingerEarlyLatch:
+ case JankType::SurfaceFlingerEarlyLatch:
return "SurfaceFlinger Early Latch";
default:
return "Unclassified";
@@ -154,16 +154,16 @@
return FrameTimelineEvent::PRESENT_ON_TIME;
}
-FrameTimelineEvent::JankType JankTypeToProto(TimeStats::JankType jankType) {
+FrameTimelineEvent::JankType JankTypeToProto(JankType jankType) {
switch (jankType) {
- case TimeStats::None:
+ case JankType::None:
return FrameTimelineEvent::JANK_NONE;
- case TimeStats::Display:
+ case JankType::Display:
return FrameTimelineEvent::JANK_DISPLAY_HAL;
- case TimeStats::SurfaceFlingerDeadlineMissed:
+ case JankType::SurfaceFlingerDeadlineMissed:
return FrameTimelineEvent::JANK_SF_DEADLINE_MISSED;
- case TimeStats::AppDeadlineMissed:
- case TimeStats::PredictionExpired:
+ case JankType::AppDeadlineMissed:
+ case JankType::PredictionExpired:
return FrameTimelineEvent::JANK_APP_DEADLINE_MISSED;
default:
return FrameTimelineEvent::JANK_UNKNOWN;
@@ -217,7 +217,7 @@
mPredictions(predictions),
mActuals({0, 0, 0}),
mActualQueueTime(0),
- mJankType(TimeStats::JankType::None),
+ mJankType(JankType::None),
mJankMetadata(0) {}
void SurfaceFrame::setPresentState(PresentState state) {
@@ -259,13 +259,13 @@
mActuals.presentTime = presentTime;
}
-void SurfaceFrame::setJankInfo(TimeStats::JankType jankType, int32_t jankMetadata) {
+void SurfaceFrame::setJankInfo(JankType jankType, int32_t jankMetadata) {
std::lock_guard<std::mutex> lock(mMutex);
mJankType = jankType;
mJankMetadata = jankMetadata;
}
-TimeStats::JankType SurfaceFrame::getJankType() const {
+JankType SurfaceFrame::getJankType() const {
std::lock_guard<std::mutex> lock(mMutex);
return mJankType;
}
@@ -300,7 +300,7 @@
std::lock_guard<std::mutex> lock(mMutex);
StringAppendF(&result, "%s", indent.c_str());
StringAppendF(&result, "Layer - %s", mDebugName.c_str());
- if (mJankType != TimeStats::JankType::None) {
+ if (mJankType != JankType::None) {
// Easily identify a janky Surface Frame in the dump
StringAppendF(&result, " [*] ");
}
@@ -454,7 +454,7 @@
}
}
if (signalTime != Fence::SIGNAL_TIME_INVALID) {
- int32_t totalJankReasons = TimeStats::JankType::None;
+ int32_t totalJankReasons = JankType::None;
auto& displayFrame = pendingPresentFence.second;
displayFrame->surfaceFlingerActuals.presentTime = signalTime;
@@ -475,14 +475,14 @@
if ((displayFrame->jankMetadata & EarlyFinish) &&
(displayFrame->jankMetadata & EarlyPresent)) {
- displayFrame->jankType = TimeStats::JankType::SurfaceFlingerEarlyLatch;
+ displayFrame->jankType = JankType::SurfaceFlingerEarlyLatch;
} else if ((displayFrame->jankMetadata & LateFinish) &&
(displayFrame->jankMetadata & LatePresent)) {
- displayFrame->jankType = TimeStats::JankType::SurfaceFlingerDeadlineMissed;
+ displayFrame->jankType = JankType::SurfaceFlingerDeadlineMissed;
} else if (displayFrame->jankMetadata & EarlyPresent ||
displayFrame->jankMetadata & LatePresent) {
// Cases where SF finished early but frame was presented late and vice versa
- displayFrame->jankType = TimeStats::JankType::Display;
+ displayFrame->jankType = JankType::Display;
}
}
@@ -503,12 +503,12 @@
const auto& predictionState = surfaceFrame->getPredictionState();
if (predictionState == PredictionState::Expired) {
// Jank analysis cannot be done on apps that don't use predictions
- surfaceFrame->setJankInfo(TimeStats::JankType::PredictionExpired, 0);
+ surfaceFrame->setJankInfo(JankType::PredictionExpired, 0);
} else if (predictionState == PredictionState::Valid) {
const auto& actuals = surfaceFrame->getActuals();
const auto& predictions = surfaceFrame->getPredictions();
int32_t jankMetadata = 0;
- TimeStats::JankType jankType = TimeStats::JankType::None;
+ JankType jankType = JankType::None;
if (std::abs(actuals.endTime - predictions.endTime) > kDeadlineThreshold) {
jankMetadata |= actuals.endTime > predictions.endTime ? LateFinish
: EarlyFinish;
@@ -520,13 +520,13 @@
: EarlyPresent;
}
if (jankMetadata & EarlyPresent) {
- jankType = TimeStats::JankType::SurfaceFlingerEarlyLatch;
+ jankType = JankType::SurfaceFlingerEarlyLatch;
} else if (jankMetadata & LatePresent) {
if (jankMetadata & EarlyFinish) {
// TODO(b/169890654): Classify this properly
- jankType = TimeStats::JankType::Display;
+ jankType = JankType::Display;
} else {
- jankType = TimeStats::JankType::AppDeadlineMissed;
+ jankType = JankType::AppDeadlineMissed;
}
}
@@ -576,7 +576,7 @@
void FrameTimeline::dumpDisplayFrame(std::string& result,
const std::shared_ptr<DisplayFrame>& displayFrame,
nsecs_t baseTime) {
- if (displayFrame->jankType != TimeStats::JankType::None) {
+ if (displayFrame->jankType != JankType::None) {
// Easily identify a janky Display Frame in the dump
StringAppendF(&result, " [*] ");
}
@@ -610,11 +610,11 @@
nsecs_t baseTime = (mDisplayFrames.empty()) ? 0 : findBaseTime(mDisplayFrames[0]);
for (size_t i = 0; i < mDisplayFrames.size(); i++) {
const auto& displayFrame = mDisplayFrames[i];
- if (displayFrame->jankType == TimeStats::JankType::None) {
+ if (displayFrame->jankType == JankType::None) {
// Check if any Surface Frame has been janky
bool isJanky = false;
for (const auto& surfaceFrame : displayFrame->surfaceFrames) {
- if (surfaceFrame->getJankType() != TimeStats::JankType::None) {
+ if (surfaceFrame->getJankType() != JankType::None) {
isJanky = true;
break;
}
diff --git a/services/surfaceflinger/FrameTimeline/FrameTimeline.h b/services/surfaceflinger/FrameTimeline/FrameTimeline.h
index 9a74d50..fe83ebf 100644
--- a/services/surfaceflinger/FrameTimeline/FrameTimeline.h
+++ b/services/surfaceflinger/FrameTimeline/FrameTimeline.h
@@ -18,6 +18,7 @@
#include <../TimeStats/TimeStats.h>
#include <gui/ISurfaceComposer.h>
+#include <gui/JankInfo.h>
#include <perfetto/trace/android/frame_timeline_event.pbzero.h>
#include <perfetto/tracing.h>
#include <ui/FenceTime.h>
@@ -208,7 +209,7 @@
PresentState getPresentState() const override;
PredictionState getPredictionState() const override { return mPredictionState; };
pid_t getOwnerPid() const override { return mOwnerPid; };
- TimeStats::JankType getJankType() const;
+ JankType getJankType() const;
int64_t getToken() const { return mToken; };
nsecs_t getBaseTime() const;
uid_t getOwnerUid() const { return mOwnerUid; };
@@ -219,7 +220,7 @@
void setAcquireFenceTime(nsecs_t acquireFenceTime) override;
void setPresentState(PresentState state) override;
void setActualPresentTime(nsecs_t presentTime);
- void setJankInfo(TimeStats::JankType jankType, int32_t jankMetadata);
+ void setJankInfo(JankType jankType, int32_t jankMetadata);
// All the timestamps are dumped relative to the baseTime
void dump(std::string& result, const std::string& indent, nsecs_t baseTime);
@@ -241,7 +242,7 @@
TimelineItem mActuals GUARDED_BY(mMutex);
nsecs_t mActualQueueTime GUARDED_BY(mMutex);
mutable std::mutex mMutex;
- TimeStats::JankType mJankType GUARDED_BY(mMutex); // Enum for the type of jank
+ JankType mJankType GUARDED_BY(mMutex); // Enum for the type of jank
int32_t mJankMetadata GUARDED_BY(mMutex); // Additional details about the jank
};
@@ -301,7 +302,7 @@
std::vector<std::unique_ptr<SurfaceFrame>> surfaceFrames;
PredictionState predictionState = PredictionState::None;
- TimeStats::JankType jankType = TimeStats::JankType::None; // Enum for the type of jank
+ JankType jankType = JankType::None; // Enum for the type of jank
int32_t jankMetadata = 0x0; // Additional details about the jank
};
diff --git a/services/surfaceflinger/TimeStats/TimeStats.cpp b/services/surfaceflinger/TimeStats/TimeStats.cpp
index 28a3a81..2405884 100644
--- a/services/surfaceflinger/TimeStats/TimeStats.cpp
+++ b/services/surfaceflinger/TimeStats/TimeStats.cpp
@@ -681,21 +681,21 @@
t.jankPayload.totalFrames++;
static const constexpr int32_t kValidJankyReason =
- TimeStats::JankType::SurfaceFlingerDeadlineMissed |
- TimeStats::JankType::SurfaceFlingerGpuDeadlineMissed |
- TimeStats::JankType::AppDeadlineMissed | TimeStats::JankType::Display;
+ JankType::SurfaceFlingerDeadlineMissed |
+ JankType::SurfaceFlingerGpuDeadlineMissed |
+ JankType::AppDeadlineMissed | JankType::Display;
if (reasons & kValidJankyReason) {
t.jankPayload.totalJankyFrames++;
- if ((reasons & TimeStats::JankType::SurfaceFlingerDeadlineMissed) != 0) {
+ if ((reasons & JankType::SurfaceFlingerDeadlineMissed) != 0) {
t.jankPayload.totalSFLongCpu++;
}
- if ((reasons & TimeStats::JankType::SurfaceFlingerGpuDeadlineMissed) != 0) {
+ if ((reasons & JankType::SurfaceFlingerGpuDeadlineMissed) != 0) {
t.jankPayload.totalSFLongGpu++;
}
- if ((reasons & TimeStats::JankType::Display) != 0) {
+ if ((reasons & JankType::Display) != 0) {
t.jankPayload.totalSFUnattributed++;
}
- if ((reasons & TimeStats::JankType::AppDeadlineMissed) != 0) {
+ if ((reasons & JankType::AppDeadlineMissed) != 0) {
t.jankPayload.totalAppUnattributed++;
}
}
diff --git a/services/surfaceflinger/TimeStats/TimeStats.h b/services/surfaceflinger/TimeStats/TimeStats.h
index 4fa0a02..a83b2bf 100644
--- a/services/surfaceflinger/TimeStats/TimeStats.h
+++ b/services/surfaceflinger/TimeStats/TimeStats.h
@@ -31,6 +31,7 @@
#include <statslog.h>
#include <timestatsproto/TimeStatsHelper.h>
#include <timestatsproto/TimeStatsProtoHeader.h>
+#include <gui/JankInfo.h>
#include <ui/FenceTime.h>
#include <utils/String16.h>
#include <utils/Vector.h>
@@ -110,26 +111,6 @@
virtual void setPresentFence(int32_t layerId, uint64_t frameNumber,
const std::shared_ptr<FenceTime>& presentFence) = 0;
- // Subset of jank metadata tracked by FrameTimeline for the purpose of funneling to telemetry.
- enum JankType {
- // No Jank
- None = 0x0,
- // Jank not related to SurfaceFlinger or the App
- Display = 0x1,
- // SF took too long on the CPU
- SurfaceFlingerDeadlineMissed = 0x2,
- // SF took too long on the GPU
- SurfaceFlingerGpuDeadlineMissed = 0x4,
- // Either App or GPU took too long on the frame
- AppDeadlineMissed = 0x8,
- // Predictions live for 120ms, if prediction is expired for a frame, there is definitely a
- // jank
- // associated with the App if this is for a SurfaceFrame, and SF for a DisplayFrame.
- PredictionExpired = 0x10,
- // Latching a buffer early might cause an early present of the frame
- SurfaceFlingerEarlyLatch = 0x20,
- };
-
// Increments janky frames, tracked globally. Because FrameTimeline is the infrastructure
// responsible for computing jank in the system, this is expected to be called from
// FrameTimeline, rather than directly from SurfaceFlinger or individual layers. If there are no
diff --git a/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp b/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp
index cb617d6..411e780 100644
--- a/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp
+++ b/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp
@@ -379,9 +379,9 @@
TEST_F(FrameTimelineTest, presentFenceSignaled_reportsLongSfCpu) {
EXPECT_CALL(*mTimeStats,
incrementJankyFrames(sUidOne, sLayerNameOne,
- HasBit(TimeStats::JankType::SurfaceFlingerDeadlineMissed)));
+ HasBit(JankType::SurfaceFlingerDeadlineMissed)));
EXPECT_CALL(*mTimeStats,
- incrementJankyFrames(HasBit(TimeStats::JankType::SurfaceFlingerDeadlineMissed)));
+ incrementJankyFrames(HasBit(JankType::SurfaceFlingerDeadlineMissed)));
auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions(
{std::chrono::duration_cast<std::chrono::nanoseconds>(10ms).count(),
@@ -407,8 +407,8 @@
TEST_F(FrameTimelineTest, presentFenceSignaled_reportsDisplayMiss) {
EXPECT_CALL(*mTimeStats,
- incrementJankyFrames(sUidOne, sLayerNameOne, HasBit(TimeStats::JankType::Display)));
- EXPECT_CALL(*mTimeStats, incrementJankyFrames(HasBit(TimeStats::JankType::Display)));
+ incrementJankyFrames(sUidOne, sLayerNameOne, HasBit(JankType::Display)));
+ EXPECT_CALL(*mTimeStats, incrementJankyFrames(HasBit(JankType::Display)));
auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions(
{std::chrono::duration_cast<std::chrono::nanoseconds>(10ms).count(),
@@ -434,8 +434,8 @@
TEST_F(FrameTimelineTest, presentFenceSignaled_reportsAppMiss) {
EXPECT_CALL(*mTimeStats,
incrementJankyFrames(sUidOne, sLayerNameOne,
- HasBit(TimeStats::JankType::AppDeadlineMissed)));
- EXPECT_CALL(*mTimeStats, incrementJankyFrames(HasBit(TimeStats::JankType::AppDeadlineMissed)));
+ HasBit(JankType::AppDeadlineMissed)));
+ EXPECT_CALL(*mTimeStats, incrementJankyFrames(HasBit(JankType::AppDeadlineMissed)));
auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions(
{std::chrono::duration_cast<std::chrono::nanoseconds>(10ms).count(),
diff --git a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
index a90f424..bbcc0c9 100644
--- a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
@@ -356,11 +356,11 @@
EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000);
- mTimeStats->incrementJankyFrames(TimeStats::JankType::SurfaceFlingerDeadlineMissed);
- mTimeStats->incrementJankyFrames(TimeStats::JankType::SurfaceFlingerGpuDeadlineMissed);
- mTimeStats->incrementJankyFrames(TimeStats::JankType::Display);
- mTimeStats->incrementJankyFrames(TimeStats::JankType::AppDeadlineMissed);
- mTimeStats->incrementJankyFrames(TimeStats::JankType::None);
+ mTimeStats->incrementJankyFrames(JankType::SurfaceFlingerDeadlineMissed);
+ mTimeStats->incrementJankyFrames(JankType::SurfaceFlingerGpuDeadlineMissed);
+ mTimeStats->incrementJankyFrames(JankType::Display);
+ mTimeStats->incrementJankyFrames(JankType::AppDeadlineMissed);
+ mTimeStats->incrementJankyFrames(JankType::None);
const std::string result(inputCommand(InputCommand::DUMP_ALL, FMT_STRING));
std::string expectedResult = "totalTimelineFrames = " + std::to_string(5);
@@ -383,13 +383,13 @@
insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000);
mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0),
- TimeStats::JankType::SurfaceFlingerDeadlineMissed);
+ JankType::SurfaceFlingerDeadlineMissed);
mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0),
- TimeStats::JankType::SurfaceFlingerGpuDeadlineMissed);
- mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0), TimeStats::JankType::Display);
+ JankType::SurfaceFlingerGpuDeadlineMissed);
+ mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0), JankType::Display);
mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0),
- TimeStats::JankType::AppDeadlineMissed);
- mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0), TimeStats::JankType::None);
+ JankType::AppDeadlineMissed);
+ mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0), JankType::None);
const std::string result(inputCommand(InputCommand::DUMP_ALL, FMT_STRING));
std::string expectedResult = "totalTimelineFrames = " + std::to_string(5);
@@ -848,13 +848,13 @@
std::chrono::duration_cast<std::chrono::nanoseconds>(1ms).count()));
mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0),
- TimeStats::JankType::SurfaceFlingerDeadlineMissed);
+ JankType::SurfaceFlingerDeadlineMissed);
mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0),
- TimeStats::JankType::SurfaceFlingerGpuDeadlineMissed);
- mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0), TimeStats::JankType::Display);
+ JankType::SurfaceFlingerGpuDeadlineMissed);
+ mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0), JankType::Display);
mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0),
- TimeStats::JankType::AppDeadlineMissed);
- mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0), TimeStats::JankType::None);
+ JankType::AppDeadlineMissed);
+ mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0), JankType::None);
EXPECT_TRUE(inputCommand(InputCommand::CLEAR, FMT_STRING).empty());
@@ -987,11 +987,11 @@
mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(3000000));
mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(5000000));
- mTimeStats->incrementJankyFrames(TimeStats::JankType::SurfaceFlingerDeadlineMissed);
- mTimeStats->incrementJankyFrames(TimeStats::JankType::SurfaceFlingerGpuDeadlineMissed);
- mTimeStats->incrementJankyFrames(TimeStats::JankType::Display);
- mTimeStats->incrementJankyFrames(TimeStats::JankType::AppDeadlineMissed);
- mTimeStats->incrementJankyFrames(TimeStats::JankType::None);
+ mTimeStats->incrementJankyFrames(JankType::SurfaceFlingerDeadlineMissed);
+ mTimeStats->incrementJankyFrames(JankType::SurfaceFlingerGpuDeadlineMissed);
+ mTimeStats->incrementJankyFrames(JankType::Display);
+ mTimeStats->incrementJankyFrames(JankType::AppDeadlineMissed);
+ mTimeStats->incrementJankyFrames(JankType::None);
EXPECT_THAT(mDelegate->mAtomTags,
UnorderedElementsAre(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO,
@@ -1062,13 +1062,13 @@
insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 2, 2000000);
mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0),
- TimeStats::JankType::SurfaceFlingerDeadlineMissed);
+ JankType::SurfaceFlingerDeadlineMissed);
mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0),
- TimeStats::JankType::SurfaceFlingerGpuDeadlineMissed);
- mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0), TimeStats::JankType::Display);
+ JankType::SurfaceFlingerGpuDeadlineMissed);
+ mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0), JankType::Display);
mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0),
- TimeStats::JankType::AppDeadlineMissed);
- mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0), TimeStats::JankType::None);
+ JankType::AppDeadlineMissed);
+ mTimeStats->incrementJankyFrames(UID_0, genLayerName(LAYER_ID_0), JankType::None);
EXPECT_THAT(mDelegate->mAtomTags,
UnorderedElementsAre(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO,