Merge "Fix drag and drop access wrong pointer id"
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index 6d837c2..3480d63 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -1,8 +1,10 @@
[Builtin Hooks]
+rustfmt = true
bpfmt = true
clang_format = true
[Builtin Hooks Options]
+rustfmt = --config-path=rustfmt.toml
# Only turn on clang-format check for the following subfolders.
clang_format = --commit ${PREUPLOAD_COMMIT} --style file --extensions c,h,cc,cpp
cmds/idlcli/
diff --git a/cmds/servicemanager/Access.cpp b/cmds/servicemanager/Access.cpp
index b7e520f..711038c 100644
--- a/cmds/servicemanager/Access.cpp
+++ b/cmds/servicemanager/Access.cpp
@@ -30,6 +30,7 @@
constexpr bool kIsVendor = false;
#endif
+#ifdef __ANDROID__
static std::string getPidcon(pid_t pid) {
android_errorWriteLog(0x534e4554, "121035042");
@@ -45,7 +46,6 @@
static struct selabel_handle* getSehandle() {
static struct selabel_handle* gSehandle = nullptr;
-
if (gSehandle != nullptr && selinux_status_updated()) {
selabel_close(gSehandle);
gSehandle = nullptr;
@@ -78,8 +78,10 @@
ad->tname->c_str());
return 0;
}
+#endif
Access::Access() {
+#ifdef __ANDROID__
union selinux_callback cb;
cb.func_audit = auditCallback;
@@ -91,6 +93,7 @@
CHECK(selinux_status_open(true /*fallback*/) >= 0);
CHECK(getcon(&mThisProcessContext) == 0);
+#endif
}
Access::~Access() {
@@ -98,6 +101,7 @@
}
Access::CallingContext Access::getCallingContext() {
+#ifdef __ANDROID__
IPCThreadState* ipc = IPCThreadState::self();
const char* callingSid = ipc->getCallingSid();
@@ -108,6 +112,9 @@
.uid = ipc->getCallingUid(),
.sid = callingSid ? std::string(callingSid) : getPidcon(callingPid),
};
+#else
+ return CallingContext();
+#endif
}
bool Access::canFind(const CallingContext& ctx,const std::string& name) {
@@ -124,6 +131,7 @@
bool Access::actionAllowed(const CallingContext& sctx, const char* tctx, const char* perm,
const std::string& tname) {
+#ifdef __ANDROID__
const char* tclass = "service_manager";
AuditCallbackData data = {
@@ -133,9 +141,18 @@
return 0 == selinux_check_access(sctx.sid.c_str(), tctx, tclass, perm,
reinterpret_cast<void*>(&data));
+#else
+ (void)sctx;
+ (void)tctx;
+ (void)perm;
+ (void)tname;
+
+ return true;
+#endif
}
bool Access::actionAllowedFromLookup(const CallingContext& sctx, const std::string& name, const char *perm) {
+#ifdef __ANDROID__
char *tctx = nullptr;
if (selabel_lookup(getSehandle(), &tctx, name.c_str(), SELABEL_CTX_ANDROID_SERVICE) != 0) {
LOG(ERROR) << "SELinux: No match for " << name << " in service_contexts.\n";
@@ -145,6 +162,14 @@
bool allowed = actionAllowed(sctx, tctx, perm, name);
freecon(tctx);
return allowed;
+#else
+ (void)sctx;
+ (void)name;
+ (void)perm;
+ (void)kIsVendor;
+
+ return true;
+#endif
}
} // android
diff --git a/cmds/servicemanager/Android.bp b/cmds/servicemanager/Android.bp
index 3b753c6..25bd9a3 100644
--- a/cmds/servicemanager/Android.bp
+++ b/cmds/servicemanager/Android.bp
@@ -87,3 +87,35 @@
],
static_libs: ["libgmock"],
}
+
+cc_fuzz {
+ name: "servicemanager_fuzzer",
+ defaults: ["servicemanager_defaults"],
+ host_supported: true,
+ static_libs: [
+ "libbase",
+ "libbinder_random_parcel",
+ "libcutils",
+ ],
+ target: {
+ android: {
+ shared_libs: [
+ "libbinder_ndk",
+ "libbinder",
+ ],
+ },
+ host: {
+ static_libs: [
+ "libbinder_ndk",
+ "libbinder",
+ ],
+ },
+ },
+ srcs: ["ServiceManagerFuzzer.cpp"],
+ fuzz_config: {
+ cc: [
+ "smoreland@google.com",
+ "waghpawan@google.com",
+ ],
+ },
+}
diff --git a/cmds/servicemanager/ServiceManagerFuzzer.cpp b/cmds/servicemanager/ServiceManagerFuzzer.cpp
new file mode 100644
index 0000000..9e2e53f
--- /dev/null
+++ b/cmds/servicemanager/ServiceManagerFuzzer.cpp
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <fuzzbinder/libbinder_driver.h>
+#include <utils/StrongPointer.h>
+
+#include "Access.h"
+#include "ServiceManager.h"
+
+using ::android::Access;
+using ::android::fuzzService;
+using ::android::ServiceManager;
+using ::android::sp;
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ if (size > 50000) {
+ return 0;
+ }
+
+ auto accessPtr = std::make_unique<Access>();
+ auto serviceManager = sp<ServiceManager>::make(std::move(accessPtr));
+ fuzzService(serviceManager, FuzzedDataProvider(data, size));
+
+ return 0;
+}
\ No newline at end of file
diff --git a/libs/binder/FdTrigger.h b/libs/binder/FdTrigger.h
index 5c7102e..a25dc11 100644
--- a/libs/binder/FdTrigger.h
+++ b/libs/binder/FdTrigger.h
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+#pragma once
#include <memory>
diff --git a/libs/binder/RpcTransportRaw.cpp b/libs/binder/RpcTransportRaw.cpp
index 7cc58cd..51326f6 100644
--- a/libs/binder/RpcTransportRaw.cpp
+++ b/libs/binder/RpcTransportRaw.cpp
@@ -24,6 +24,7 @@
#include "FdTrigger.h"
#include "RpcState.h"
+#include "RpcTransportUtils.h"
namespace android {
@@ -55,90 +56,6 @@
return OK;
}
- template <typename SendOrReceive>
- status_t interruptableReadOrWrite(
- FdTrigger* fdTrigger, iovec* iovs, int niovs, SendOrReceive sendOrReceiveFun,
- const char* funName, int16_t event,
- const std::optional<android::base::function_ref<status_t()>>& altPoll) {
- MAYBE_WAIT_IN_FLAKE_MODE;
-
- if (niovs < 0) {
- return BAD_VALUE;
- }
-
- // Since we didn't poll, we need to manually check to see if it was triggered. Otherwise, we
- // may never know we should be shutting down.
- if (fdTrigger->isTriggered()) {
- return DEAD_OBJECT;
- }
-
- // If iovs has one or more empty vectors at the end and
- // we somehow advance past all the preceding vectors and
- // pass some or all of the empty ones to sendmsg/recvmsg,
- // the call will return processSize == 0. In that case
- // we should be returning OK but instead return DEAD_OBJECT.
- // To avoid this problem, we make sure here that the last
- // vector at iovs[niovs - 1] has a non-zero length.
- while (niovs > 0 && iovs[niovs - 1].iov_len == 0) {
- niovs--;
- }
- if (niovs == 0) {
- // The vectors are all empty, so we have nothing to send.
- return OK;
- }
-
- bool havePolled = false;
- while (true) {
- ssize_t processSize = sendOrReceiveFun(iovs, niovs);
- if (processSize < 0) {
- int savedErrno = errno;
-
- // Still return the error on later passes, since it would expose
- // a problem with polling
- if (havePolled || (savedErrno != EAGAIN && savedErrno != EWOULDBLOCK)) {
- LOG_RPC_DETAIL("RpcTransport %s(): %s", funName, strerror(savedErrno));
- return -savedErrno;
- }
- } else if (processSize == 0) {
- return DEAD_OBJECT;
- } else {
- while (processSize > 0 && niovs > 0) {
- auto& iov = iovs[0];
- if (static_cast<size_t>(processSize) < iov.iov_len) {
- // Advance the base of the current iovec
- iov.iov_base = reinterpret_cast<char*>(iov.iov_base) + processSize;
- iov.iov_len -= processSize;
- break;
- }
-
- // The current iovec was fully written
- processSize -= iov.iov_len;
- iovs++;
- niovs--;
- }
- if (niovs == 0) {
- LOG_ALWAYS_FATAL_IF(processSize > 0,
- "Reached the end of iovecs "
- "with %zd bytes remaining",
- processSize);
- return OK;
- }
- }
-
- if (altPoll) {
- if (status_t status = (*altPoll)(); status != OK) return status;
- if (fdTrigger->isTriggered()) {
- return DEAD_OBJECT;
- }
- } else {
- if (status_t status = fdTrigger->triggerablePoll(mSocket.get(), event);
- status != OK)
- return status;
- if (!havePolled) havePolled = true;
- }
- }
- }
-
status_t interruptableWriteFully(
FdTrigger* fdTrigger, iovec* iovs, int niovs,
const std::optional<android::base::function_ref<status_t()>>& altPoll,
@@ -198,7 +115,8 @@
};
return TEMP_FAILURE_RETRY(sendmsg(mSocket.get(), &msg, MSG_NOSIGNAL));
};
- return interruptableReadOrWrite(fdTrigger, iovs, niovs, send, "sendmsg", POLLOUT, altPoll);
+ return interruptableReadOrWrite(mSocket.get(), fdTrigger, iovs, niovs, send, "sendmsg",
+ POLLOUT, altPoll);
}
status_t interruptableReadFully(
@@ -255,7 +173,8 @@
};
return TEMP_FAILURE_RETRY(recvmsg(mSocket.get(), &msg, MSG_NOSIGNAL));
};
- return interruptableReadOrWrite(fdTrigger, iovs, niovs, recv, "recvmsg", POLLIN, altPoll);
+ return interruptableReadOrWrite(mSocket.get(), fdTrigger, iovs, niovs, recv, "recvmsg",
+ POLLIN, altPoll);
}
private:
diff --git a/libs/binder/RpcTransportUtils.h b/libs/binder/RpcTransportUtils.h
new file mode 100644
index 0000000..00cb2af
--- /dev/null
+++ b/libs/binder/RpcTransportUtils.h
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#include <android-base/unique_fd.h>
+#include <poll.h>
+
+#include "FdTrigger.h"
+#include "RpcState.h"
+
+namespace android {
+
+template <typename SendOrReceive>
+status_t interruptableReadOrWrite(
+ int socketFd, FdTrigger* fdTrigger, iovec* iovs, int niovs, SendOrReceive sendOrReceiveFun,
+ const char* funName, int16_t event,
+ const std::optional<android::base::function_ref<status_t()>>& altPoll) {
+ MAYBE_WAIT_IN_FLAKE_MODE;
+
+ if (niovs < 0) {
+ return BAD_VALUE;
+ }
+
+ // Since we didn't poll, we need to manually check to see if it was triggered. Otherwise, we
+ // may never know we should be shutting down.
+ if (fdTrigger->isTriggered()) {
+ return DEAD_OBJECT;
+ }
+
+ // If iovs has one or more empty vectors at the end and
+ // we somehow advance past all the preceding vectors and
+ // pass some or all of the empty ones to sendmsg/recvmsg,
+ // the call will return processSize == 0. In that case
+ // we should be returning OK but instead return DEAD_OBJECT.
+ // To avoid this problem, we make sure here that the last
+ // vector at iovs[niovs - 1] has a non-zero length.
+ while (niovs > 0 && iovs[niovs - 1].iov_len == 0) {
+ niovs--;
+ }
+ if (niovs == 0) {
+ // The vectors are all empty, so we have nothing to send.
+ return OK;
+ }
+
+ bool havePolled = false;
+ while (true) {
+ ssize_t processSize = sendOrReceiveFun(iovs, niovs);
+ if (processSize < 0) {
+ int savedErrno = errno;
+
+ // Still return the error on later passes, since it would expose
+ // a problem with polling
+ if (havePolled || (savedErrno != EAGAIN && savedErrno != EWOULDBLOCK)) {
+ LOG_RPC_DETAIL("RpcTransport %s(): %s", funName, strerror(savedErrno));
+ return -savedErrno;
+ }
+ } else if (processSize == 0) {
+ return DEAD_OBJECT;
+ } else {
+ while (processSize > 0 && niovs > 0) {
+ auto& iov = iovs[0];
+ if (static_cast<size_t>(processSize) < iov.iov_len) {
+ // Advance the base of the current iovec
+ iov.iov_base = reinterpret_cast<char*>(iov.iov_base) + processSize;
+ iov.iov_len -= processSize;
+ break;
+ }
+
+ // The current iovec was fully written
+ processSize -= iov.iov_len;
+ iovs++;
+ niovs--;
+ }
+ if (niovs == 0) {
+ LOG_ALWAYS_FATAL_IF(processSize > 0,
+ "Reached the end of iovecs "
+ "with %zd bytes remaining",
+ processSize);
+ return OK;
+ }
+ }
+
+ if (altPoll) {
+ if (status_t status = (*altPoll)(); status != OK) return status;
+ if (fdTrigger->isTriggered()) {
+ return DEAD_OBJECT;
+ }
+ } else {
+ if (status_t status = fdTrigger->triggerablePoll(socketFd, event); status != OK)
+ return status;
+ if (!havePolled) havePolled = true;
+ }
+ }
+}
+
+} // namespace android
diff --git a/libs/binder/rust/binder_tokio/lib.rs b/libs/binder/rust/binder_tokio/lib.rs
index 9dcef42..2d2bf7c 100644
--- a/libs/binder/rust/binder_tokio/lib.rs
+++ b/libs/binder/rust/binder_tokio/lib.rs
@@ -28,22 +28,22 @@
//!
//! [`Tokio`]: crate::Tokio
-use binder::{BinderAsyncPool, BoxFuture, FromIBinder, StatusCode, Strong};
use binder::binder_impl::BinderAsyncRuntime;
+use binder::{BinderAsyncPool, BoxFuture, FromIBinder, StatusCode, Strong};
use std::future::Future;
/// Retrieve an existing service for a particular interface, sleeping for a few
/// seconds if it doesn't yet exist.
-pub async fn get_interface<T: FromIBinder + ?Sized + 'static>(name: &str) -> Result<Strong<T>, StatusCode> {
+pub async fn get_interface<T: FromIBinder + ?Sized + 'static>(
+ name: &str,
+) -> Result<Strong<T>, StatusCode> {
if binder::is_handling_transaction() {
// See comment in the BinderAsyncPool impl.
return binder::get_interface::<T>(name);
}
let name = name.to_string();
- let res = tokio::task::spawn_blocking(move || {
- binder::get_interface::<T>(&name)
- }).await;
+ let res = tokio::task::spawn_blocking(move || binder::get_interface::<T>(&name)).await;
// The `is_panic` branch is not actually reachable in Android as we compile
// with `panic = abort`.
@@ -58,16 +58,16 @@
/// Retrieve an existing service for a particular interface, or start it if it
/// is configured as a dynamic service and isn't yet started.
-pub async fn wait_for_interface<T: FromIBinder + ?Sized + 'static>(name: &str) -> Result<Strong<T>, StatusCode> {
+pub async fn wait_for_interface<T: FromIBinder + ?Sized + 'static>(
+ name: &str,
+) -> Result<Strong<T>, StatusCode> {
if binder::is_handling_transaction() {
// See comment in the BinderAsyncPool impl.
return binder::wait_for_interface::<T>(name);
}
let name = name.to_string();
- let res = tokio::task::spawn_blocking(move || {
- binder::wait_for_interface::<T>(&name)
- }).await;
+ let res = tokio::task::spawn_blocking(move || binder::wait_for_interface::<T>(&name)).await;
// The `is_panic` branch is not actually reachable in Android as we compile
// with `panic = abort`.
diff --git a/libs/binder/rust/src/binder.rs b/libs/binder/rust/src/binder.rs
index 5d6206d..63c8684 100644
--- a/libs/binder/rust/src/binder.rs
+++ b/libs/binder/rust/src/binder.rs
@@ -17,7 +17,7 @@
//! Trait definitions for binder objects
use crate::error::{status_t, Result, StatusCode};
-use crate::parcel::{Parcel, BorrowedParcel};
+use crate::parcel::{BorrowedParcel, Parcel};
use crate::proxy::{DeathRecipient, SpIBinder, WpIBinder};
use crate::sys;
@@ -133,7 +133,7 @@
match stability {
0 => Ok(Local),
1 => Ok(Vintf),
- _ => Err(StatusCode::BAD_VALUE)
+ _ => Err(StatusCode::BAD_VALUE),
}
}
}
@@ -158,7 +158,12 @@
/// Handle and reply to a request to invoke a transaction on this object.
///
/// `reply` may be [`None`] if the sender does not expect a reply.
- fn on_transact(&self, code: TransactionCode, data: &BorrowedParcel<'_>, reply: &mut BorrowedParcel<'_>) -> Result<()>;
+ fn on_transact(
+ &self,
+ code: TransactionCode,
+ data: &BorrowedParcel<'_>,
+ reply: &mut BorrowedParcel<'_>,
+ ) -> Result<()>;
/// Handle a request to invoke the dump transaction on this
/// object.
@@ -454,28 +459,19 @@
/// Construct a new weak reference from a strong reference
fn new(binder: &Strong<I>) -> Self {
let weak_binder = binder.as_binder().downgrade();
- Weak {
- weak_binder,
- interface_type: PhantomData,
- }
+ Weak { weak_binder, interface_type: PhantomData }
}
/// Upgrade this weak reference to a strong reference if the binder object
/// is still alive
pub fn upgrade(&self) -> Result<Strong<I>> {
- self.weak_binder
- .promote()
- .ok_or(StatusCode::DEAD_OBJECT)
- .and_then(FromIBinder::try_from)
+ self.weak_binder.promote().ok_or(StatusCode::DEAD_OBJECT).and_then(FromIBinder::try_from)
}
}
impl<I: FromIBinder + ?Sized> Clone for Weak<I> {
fn clone(&self) -> Self {
- Self {
- weak_binder: self.weak_binder.clone(),
- interface_type: PhantomData,
- }
+ Self { weak_binder: self.weak_binder.clone(), interface_type: PhantomData }
}
}
@@ -614,7 +610,12 @@
/// contains a `T` pointer in its user data. fd should be a non-owned file
/// descriptor, and args must be an array of null-terminated string
/// poiinters with length num_args.
- unsafe extern "C" fn on_dump(binder: *mut sys::AIBinder, fd: i32, args: *mut *const c_char, num_args: u32) -> status_t;
+ unsafe extern "C" fn on_dump(
+ binder: *mut sys::AIBinder,
+ fd: i32,
+ args: *mut *const c_char,
+ num_args: u32,
+ ) -> status_t;
}
/// Interface for transforming a generic SpIBinder into a specific remote
diff --git a/libs/binder/rust/src/binder_async.rs b/libs/binder/rust/src/binder_async.rs
index 579f9f9..d90acaf 100644
--- a/libs/binder/rust/src/binder_async.rs
+++ b/libs/binder/rust/src/binder_async.rs
@@ -41,7 +41,10 @@
/// boxed `Future` trait object, and including `after_spawn` in the trait function
/// allows the caller to avoid double-boxing if they want to do anything to the value
/// returned from the spawned thread.
- fn spawn<'a, F1, F2, Fut, A, B, E>(spawn_me: F1, after_spawn: F2) -> BoxFuture<'a, Result<B, E>>
+ fn spawn<'a, F1, F2, Fut, A, B, E>(
+ spawn_me: F1,
+ after_spawn: F2,
+ ) -> BoxFuture<'a, Result<B, E>>
where
F1: FnOnce() -> A,
F2: FnOnce(A) -> Fut,
diff --git a/libs/binder/rust/src/lib.rs b/libs/binder/rust/src/lib.rs
index dbfb1c2..67872a9 100644
--- a/libs/binder/rust/src/lib.rs
+++ b/libs/binder/rust/src/lib.rs
@@ -106,8 +106,8 @@
use binder_ndk_sys as sys;
-pub use binder::{BinderFeatures, FromIBinder, IBinder, Interface, Strong, Weak};
pub use crate::binder_async::{BinderAsyncPool, BoxFuture};
+pub use binder::{BinderFeatures, FromIBinder, IBinder, Interface, Strong, Weak};
pub use error::{ExceptionCode, Status, StatusCode};
pub use native::{
add_service, force_lazy_services_persist, is_handling_transaction, register_lazy_service,
diff --git a/libs/binder/rust/src/native.rs b/libs/binder/rust/src/native.rs
index 3edeebf..9e2cef1 100644
--- a/libs/binder/rust/src/native.rs
+++ b/libs/binder/rust/src/native.rs
@@ -97,10 +97,7 @@
// ends.
sys::AIBinder_new(class.into(), rust_object as *mut c_void)
};
- let mut binder = Binder {
- ibinder,
- rust_object,
- };
+ let mut binder = Binder { ibinder, rust_object };
binder.mark_stability(stability);
binder
}
@@ -343,7 +340,9 @@
vec![]
} else {
slice::from_raw_parts(args, num_args as usize)
- .iter().map(|s| CStr::from_ptr(*s)).collect()
+ .iter()
+ .map(|s| CStr::from_ptr(*s))
+ .collect()
};
let object = sys::AIBinder_getUserData(binder);
@@ -418,10 +417,7 @@
// We are transferring the ownership of the AIBinder into the new Binder
// object.
let mut ibinder = ManuallyDrop::new(ibinder);
- Ok(Binder {
- ibinder: ibinder.as_native_mut(),
- rust_object: userdata as *mut B,
- })
+ Ok(Binder { ibinder: ibinder.as_native_mut(), rust_object: userdata as *mut B })
}
}
diff --git a/libs/binder/rust/src/parcel.rs b/libs/binder/rust/src/parcel.rs
index 256fa8b..53a24af 100644
--- a/libs/binder/rust/src/parcel.rs
+++ b/libs/binder/rust/src/parcel.rs
@@ -22,10 +22,10 @@
use crate::sys;
use std::convert::TryInto;
+use std::fmt;
use std::marker::PhantomData;
use std::mem::ManuallyDrop;
use std::ptr::{self, NonNull};
-use std::fmt;
mod file_descriptor;
mod parcelable;
@@ -33,8 +33,8 @@
pub use self::file_descriptor::ParcelFileDescriptor;
pub use self::parcelable::{
- Deserialize, DeserializeArray, DeserializeOption, Serialize, SerializeArray, SerializeOption,
- Parcelable, NON_NULL_PARCELABLE_FLAG, NULL_PARCELABLE_FLAG,
+ Deserialize, DeserializeArray, DeserializeOption, Parcelable, Serialize, SerializeArray,
+ SerializeOption, NON_NULL_PARCELABLE_FLAG, NULL_PARCELABLE_FLAG,
};
pub use self::parcelable_holder::{ParcelableHolder, ParcelableMetadata};
@@ -78,9 +78,7 @@
// a valid pointer. If it fails, the process will crash.
sys::AParcel_create()
};
- Self {
- ptr: NonNull::new(ptr).expect("AParcel_create returned null pointer")
- }
+ Self { ptr: NonNull::new(ptr).expect("AParcel_create returned null pointer") }
}
/// Create an owned reference to a parcel object from a raw pointer.
@@ -116,10 +114,7 @@
// lifetime of the returned `BorrowedParcel` is tied to `self`, so the
// borrow checker will ensure that the `AParcel` can only be accessed
// via the `BorrowParcel` until it goes out of scope.
- BorrowedParcel {
- ptr: self.ptr,
- _lifetime: PhantomData,
- }
+ BorrowedParcel { ptr: self.ptr, _lifetime: PhantomData }
}
/// Get an immutable borrowed view into the contents of this `Parcel`.
@@ -127,9 +122,7 @@
// Safety: Parcel and BorrowedParcel are both represented in the same
// way as a NonNull<sys::AParcel> due to their use of repr(transparent),
// so casting references as done here is valid.
- unsafe {
- &*(self as *const Parcel as *const BorrowedParcel<'_>)
- }
+ unsafe { &*(self as *const Parcel as *const BorrowedParcel<'_>) }
}
}
@@ -165,10 +158,7 @@
/// since this is a mutable borrow, it must have exclusive access to the
/// AParcel for the duration of the borrow.
pub unsafe fn from_raw(ptr: *mut sys::AParcel) -> Option<BorrowedParcel<'a>> {
- Some(Self {
- ptr: NonNull::new(ptr)?,
- _lifetime: PhantomData,
- })
+ Some(Self { ptr: NonNull::new(ptr)?, _lifetime: PhantomData })
}
/// Get a sub-reference to this reference to the parcel.
@@ -177,10 +167,7 @@
// lifetime of the returned `BorrowedParcel` is tied to `self`, so the
// borrow checker will ensure that the `AParcel` can only be accessed
// via the `BorrowParcel` until it goes out of scope.
- BorrowedParcel {
- ptr: self.ptr,
- _lifetime: PhantomData,
- }
+ BorrowedParcel { ptr: self.ptr, _lifetime: PhantomData }
}
}
@@ -269,7 +256,7 @@
/// ```
pub fn sized_write<F>(&mut self, f: F) -> Result<()>
where
- for<'b> F: FnOnce(&'b mut WritableSubParcel<'b>) -> Result<()>
+ for<'b> F: FnOnce(&'b mut WritableSubParcel<'b>) -> Result<()>,
{
let start = self.get_data_position();
self.write(&0i32)?;
@@ -324,17 +311,17 @@
///
/// This appends `size` bytes of data from `other` starting at offset
/// `start` to the current parcel, or returns an error if not possible.
- pub fn append_from(&mut self, other: &impl AsNative<sys::AParcel>, start: i32, size: i32) -> Result<()> {
+ pub fn append_from(
+ &mut self,
+ other: &impl AsNative<sys::AParcel>,
+ start: i32,
+ size: i32,
+ ) -> Result<()> {
let status = unsafe {
// Safety: `Parcel::appendFrom` from C++ checks that `start`
// and `size` are in bounds, and returns an error otherwise.
// Both `self` and `other` always contain valid pointers.
- sys::AParcel_appendFrom(
- other.as_native(),
- self.as_native_mut(),
- start,
- size,
- )
+ sys::AParcel_appendFrom(other.as_native(), self.as_native_mut(), start, size)
};
status_result(status)
}
@@ -406,7 +393,7 @@
/// ```
pub fn sized_write<F>(&mut self, f: F) -> Result<()>
where
- for<'b> F: FnOnce(&'b mut WritableSubParcel<'b>) -> Result<()>
+ for<'b> F: FnOnce(&'b mut WritableSubParcel<'b>) -> Result<()>,
{
self.borrowed().sized_write(f)
}
@@ -438,7 +425,12 @@
///
/// This appends `size` bytes of data from `other` starting at offset
/// `start` to the current parcel, or returns an error if not possible.
- pub fn append_from(&mut self, other: &impl AsNative<sys::AParcel>, start: i32, size: i32) -> Result<()> {
+ pub fn append_from(
+ &mut self,
+ other: &impl AsNative<sys::AParcel>,
+ start: i32,
+ size: i32,
+ ) -> Result<()> {
self.borrowed().append_from(other, start, size)
}
@@ -492,7 +484,7 @@
///
pub fn sized_read<F>(&self, f: F) -> Result<()>
where
- for<'b> F: FnOnce(ReadableSubParcel<'b>) -> Result<()>
+ for<'b> F: FnOnce(ReadableSubParcel<'b>) -> Result<()>,
{
let start = self.get_data_position();
let parcelable_size: i32 = self.read()?;
@@ -500,17 +492,13 @@
return Err(StatusCode::BAD_VALUE);
}
- let end = start.checked_add(parcelable_size)
- .ok_or(StatusCode::BAD_VALUE)?;
+ let end = start.checked_add(parcelable_size).ok_or(StatusCode::BAD_VALUE)?;
if end > self.get_data_size() {
return Err(StatusCode::NOT_ENOUGH_DATA);
}
let subparcel = ReadableSubParcel {
- parcel: BorrowedParcel {
- ptr: self.ptr,
- _lifetime: PhantomData,
- },
+ parcel: BorrowedParcel { ptr: self.ptr, _lifetime: PhantomData },
end_position: end,
};
f(subparcel)?;
@@ -633,7 +621,7 @@
///
pub fn sized_read<F>(&self, f: F) -> Result<()>
where
- for<'b> F: FnOnce(ReadableSubParcel<'b>) -> Result<()>
+ for<'b> F: FnOnce(ReadableSubParcel<'b>) -> Result<()>,
{
self.borrowed_ref().sized_read(f)
}
@@ -716,15 +704,13 @@
impl fmt::Debug for Parcel {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.debug_struct("Parcel")
- .finish()
+ f.debug_struct("Parcel").finish()
}
}
impl<'a> fmt::Debug for BorrowedParcel<'a> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.debug_struct("BorrowedParcel")
- .finish()
+ f.debug_struct("BorrowedParcel").finish()
}
}
@@ -813,10 +799,7 @@
assert!(parcel.set_data_position(start).is_ok());
}
- assert_eq!(
- parcel.read::<f32>().unwrap(),
- 1143139100000000000000000000.0
- );
+ assert_eq!(parcel.read::<f32>().unwrap(), 1143139100000000000000000000.0);
assert_eq!(parcel.read::<f32>().unwrap(), 40.043392);
unsafe {
@@ -842,10 +825,7 @@
unsafe {
assert!(parcel.set_data_position(start).is_ok());
}
- assert_eq!(
- parcel.read::<Option<String>>().unwrap().unwrap(),
- "Hello, Binder!",
- );
+ assert_eq!(parcel.read::<Option<String>>().unwrap().unwrap(), "Hello, Binder!",);
unsafe {
assert!(parcel.set_data_position(start).is_ok());
}
@@ -864,13 +844,7 @@
assert!(parcel.write(&["str1", "str2", "str3"][..]).is_ok());
assert!(parcel
- .write(
- &[
- String::from("str4"),
- String::from("str5"),
- String::from("str6"),
- ][..]
- )
+ .write(&[String::from("str4"), String::from("str5"), String::from("str6"),][..])
.is_ok());
let s1 = "Hello, Binder!";
@@ -882,14 +856,8 @@
assert!(parcel.set_data_position(start).is_ok());
}
- assert_eq!(
- parcel.read::<Vec<String>>().unwrap(),
- ["str1", "str2", "str3"]
- );
- assert_eq!(
- parcel.read::<Vec<String>>().unwrap(),
- ["str4", "str5", "str6"]
- );
+ assert_eq!(parcel.read::<Vec<String>>().unwrap(), ["str1", "str2", "str3"]);
+ assert_eq!(parcel.read::<Vec<String>>().unwrap(), ["str4", "str5", "str6"]);
assert_eq!(parcel.read::<Vec<String>>().unwrap(), [s1, s2, s3]);
}
@@ -900,9 +868,9 @@
let arr = [1i32, 2i32, 3i32];
- parcel.sized_write(|subparcel| {
- subparcel.write(&arr[..])
- }).expect("Could not perform sized write");
+ parcel
+ .sized_write(|subparcel| subparcel.write(&arr[..]))
+ .expect("Could not perform sized write");
// i32 sub-parcel length + i32 array length + 3 i32 elements
let expected_len = 20i32;
@@ -913,15 +881,9 @@
parcel.set_data_position(start).unwrap();
}
- assert_eq!(
- expected_len,
- parcel.read().unwrap(),
- );
+ assert_eq!(expected_len, parcel.read().unwrap(),);
- assert_eq!(
- parcel.read::<Vec<i32>>().unwrap(),
- &arr,
- );
+ assert_eq!(parcel.read::<Vec<i32>>().unwrap(), &arr,);
}
#[test]
diff --git a/libs/binder/rust/src/parcel/file_descriptor.rs b/libs/binder/rust/src/parcel/file_descriptor.rs
index 4d3d59a..de6d649 100644
--- a/libs/binder/rust/src/parcel/file_descriptor.rs
+++ b/libs/binder/rust/src/parcel/file_descriptor.rs
@@ -15,7 +15,7 @@
*/
use super::{
- Deserialize, DeserializeArray, DeserializeOption, BorrowedParcel, Serialize, SerializeArray,
+ BorrowedParcel, Deserialize, DeserializeArray, DeserializeOption, Serialize, SerializeArray,
SerializeOption,
};
use crate::binder::AsNative;
@@ -115,10 +115,7 @@
// descriptor. The read function passes ownership of the file
// descriptor to its caller if it was non-null, so we must take
// ownership of the file and ensure that it is eventually closed.
- status_result(sys::AParcel_readParcelFileDescriptor(
- parcel.as_native(),
- &mut fd,
- ))?;
+ status_result(sys::AParcel_readParcelFileDescriptor(parcel.as_native(), &mut fd))?;
}
if fd < 0 {
Ok(None)
@@ -136,9 +133,7 @@
impl Deserialize for ParcelFileDescriptor {
fn deserialize(parcel: &BorrowedParcel<'_>) -> Result<Self> {
- Deserialize::deserialize(parcel)
- .transpose()
- .unwrap_or(Err(StatusCode::UNEXPECTED_NULL))
+ Deserialize::deserialize(parcel).transpose().unwrap_or(Err(StatusCode::UNEXPECTED_NULL))
}
}
diff --git a/libs/binder/rust/src/parcel/parcelable.rs b/libs/binder/rust/src/parcel/parcelable.rs
index 0c7e48d..c241e4d 100644
--- a/libs/binder/rust/src/parcel/parcelable.rs
+++ b/libs/binder/rust/src/parcel/parcelable.rs
@@ -22,8 +22,8 @@
use std::convert::{TryFrom, TryInto};
use std::ffi::c_void;
+use std::mem::{self, ManuallyDrop, MaybeUninit};
use std::os::raw::{c_char, c_ulong};
-use std::mem::{self, MaybeUninit, ManuallyDrop};
use std::ptr;
use std::slice;
@@ -109,17 +109,14 @@
// so the function signature matches what bindgen generates.
let index = index as usize;
- let slice: &[T] = slice::from_raw_parts(array.cast(), index+1);
+ let slice: &[T] = slice::from_raw_parts(array.cast(), index + 1);
let mut parcel = match BorrowedParcel::from_raw(parcel) {
None => return StatusCode::UNEXPECTED_NULL as status_t,
Some(p) => p,
};
- slice[index].serialize(&mut parcel)
- .err()
- .unwrap_or(StatusCode::OK)
- as status_t
+ slice[index].serialize(&mut parcel).err().unwrap_or(StatusCode::OK) as status_t
}
/// Helper trait for types that can be deserialized as arrays.
@@ -265,10 +262,7 @@
///
/// The opaque data pointer passed to the array read function must be a mutable
/// pointer to an `Option<Vec<MaybeUninit<T>>>`.
-unsafe extern "C" fn allocate_vec<T>(
- data: *mut c_void,
- len: i32,
-) -> bool {
+unsafe extern "C" fn allocate_vec<T>(data: *mut c_void, len: i32) -> bool {
let vec = &mut *(data as *mut Option<Vec<MaybeUninit<T>>>);
if len < 0 {
*vec = None;
@@ -286,7 +280,6 @@
true
}
-
macro_rules! parcelable_primitives {
{
$(
@@ -303,11 +296,7 @@
// has the same alignment and size as T, so the pointer to the vector
// allocation will be compatible.
let mut vec = ManuallyDrop::new(vec);
- Vec::from_raw_parts(
- vec.as_mut_ptr().cast(),
- vec.len(),
- vec.capacity(),
- )
+ Vec::from_raw_parts(vec.as_mut_ptr().cast(), vec.len(), vec.capacity())
}
macro_rules! impl_parcelable {
@@ -522,11 +511,7 @@
// `AParcel`. If the string pointer is null,
// `AParcel_writeString` requires that the length is -1 to
// indicate that we want to serialize a null string.
- status_result(sys::AParcel_writeString(
- parcel.as_native_mut(),
- ptr::null(),
- -1,
- ))
+ status_result(sys::AParcel_writeString(parcel.as_native_mut(), ptr::null(), -1))
},
Some(s) => unsafe {
// Safety: `Parcel` always contains a valid pointer to an
@@ -540,10 +525,7 @@
status_result(sys::AParcel_writeString(
parcel.as_native_mut(),
s.as_ptr() as *const c_char,
- s.as_bytes()
- .len()
- .try_into()
- .or(Err(StatusCode::BAD_VALUE))?,
+ s.as_bytes().len().try_into().or(Err(StatusCode::BAD_VALUE))?,
))
},
}
@@ -602,9 +584,7 @@
impl Deserialize for String {
fn deserialize(parcel: &BorrowedParcel<'_>) -> Result<Self> {
- Deserialize::deserialize(parcel)
- .transpose()
- .unwrap_or(Err(StatusCode::UNEXPECTED_NULL))
+ Deserialize::deserialize(parcel).transpose().unwrap_or(Err(StatusCode::UNEXPECTED_NULL))
}
}
@@ -704,10 +684,7 @@
// and `Status` always contains a valid pointer to an `AStatus`, so
// both parameters are valid and safe. This call does not take
// ownership of either of its parameters.
- status_result(sys::AParcel_writeStatusHeader(
- parcel.as_native_mut(),
- self.as_native(),
- ))
+ status_result(sys::AParcel_writeStatusHeader(parcel.as_native_mut(), self.as_native()))
}
}
}
@@ -881,8 +858,7 @@
Ok(())
} else {
use $crate::Parcelable;
- this.get_or_insert_with(Self::default)
- .read_from_parcel(parcel)
+ this.get_or_insert_with(Self::default).read_from_parcel(parcel)
}
}
}
@@ -915,8 +891,8 @@
#[cfg(test)]
mod tests {
- use crate::parcel::Parcel;
use super::*;
+ use crate::parcel::Parcel;
#[test]
fn test_custom_parcelable() {
@@ -934,11 +910,11 @@
impl Deserialize for Custom {
fn deserialize(parcel: &BorrowedParcel<'_>) -> Result<Self> {
Ok(Custom(
- parcel.read()?,
- parcel.read()?,
- parcel.read()?,
- parcel.read::<Option<Vec<String>>>()?.unwrap(),
- ))
+ parcel.read()?,
+ parcel.read()?,
+ parcel.read()?,
+ parcel.read::<Option<Vec<String>>>()?.unwrap(),
+ ))
}
}
@@ -1157,12 +1133,7 @@
assert_eq!(vec, [i64::max_value(), i64::min_value(), 42, -117]);
- let f32s = [
- std::f32::NAN,
- std::f32::INFINITY,
- 1.23456789,
- std::f32::EPSILON,
- ];
+ let f32s = [std::f32::NAN, std::f32::INFINITY, 1.23456789, std::f32::EPSILON];
unsafe {
assert!(parcel.set_data_position(start).is_ok());
@@ -1178,12 +1149,7 @@
assert!(vec[0].is_nan());
assert_eq!(vec[1..], f32s[1..]);
- let f64s = [
- std::f64::NAN,
- std::f64::INFINITY,
- 1.234567890123456789,
- std::f64::EPSILON,
- ];
+ let f64s = [std::f64::NAN, std::f64::INFINITY, 1.234567890123456789, std::f64::EPSILON];
unsafe {
assert!(parcel.set_data_position(start).is_ok());
diff --git a/libs/binder/rust/src/parcel/parcelable_holder.rs b/libs/binder/rust/src/parcel/parcelable_holder.rs
index 432da5d..c829d37 100644
--- a/libs/binder/rust/src/parcel/parcelable_holder.rs
+++ b/libs/binder/rust/src/parcel/parcelable_holder.rs
@@ -48,10 +48,7 @@
#[derive(Debug, Clone)]
enum ParcelableHolderData {
Empty,
- Parcelable {
- parcelable: Arc<dyn AnyParcelable>,
- name: String,
- },
+ Parcelable { parcelable: Arc<dyn AnyParcelable>, name: String },
Parcel(Parcel),
}
@@ -77,10 +74,7 @@
impl ParcelableHolder {
/// Construct a new `ParcelableHolder` with the given stability.
pub fn new(stability: Stability) -> Self {
- Self {
- data: Mutex::new(ParcelableHolderData::Empty),
- stability,
- }
+ Self { data: Mutex::new(ParcelableHolderData::Empty), stability }
}
/// Reset the contents of this `ParcelableHolder`.
@@ -101,10 +95,8 @@
return Err(StatusCode::BAD_VALUE);
}
- *self.data.get_mut().unwrap() = ParcelableHolderData::Parcelable {
- parcelable: p,
- name: T::get_descriptor().into(),
- };
+ *self.data.get_mut().unwrap() =
+ ParcelableHolderData::Parcelable { parcelable: p, name: T::get_descriptor().into() };
Ok(())
}
@@ -130,10 +122,7 @@
let mut data = self.data.lock().unwrap();
match *data {
ParcelableHolderData::Empty => Ok(None),
- ParcelableHolderData::Parcelable {
- ref parcelable,
- ref name,
- } => {
+ ParcelableHolderData::Parcelable { ref parcelable, ref name } => {
if name != parcelable_desc {
return Err(StatusCode::BAD_VALUE);
}
@@ -199,10 +188,7 @@
let mut data = self.data.lock().unwrap();
match *data {
ParcelableHolderData::Empty => parcel.write(&0i32),
- ParcelableHolderData::Parcelable {
- ref parcelable,
- ref name,
- } => {
+ ParcelableHolderData::Parcelable { ref parcelable, ref name } => {
let length_start = parcel.get_data_position();
parcel.write(&0i32)?;
@@ -251,9 +237,7 @@
// TODO: C++ ParcelableHolder accepts sizes up to SIZE_MAX here, but we
// only go up to i32::MAX because that's what our API uses everywhere
let data_start = parcel.get_data_position();
- let data_end = data_start
- .checked_add(data_size)
- .ok_or(StatusCode::BAD_VALUE)?;
+ let data_end = data_start.checked_add(data_size).ok_or(StatusCode::BAD_VALUE)?;
let mut new_parcel = Parcel::new();
new_parcel.append_from(parcel, data_start, data_size)?;
diff --git a/libs/binder/rust/src/proxy.rs b/libs/binder/rust/src/proxy.rs
index 4df557b..862fc2a 100644
--- a/libs/binder/rust/src/proxy.rs
+++ b/libs/binder/rust/src/proxy.rs
@@ -22,7 +22,8 @@
};
use crate::error::{status_result, Result, StatusCode};
use crate::parcel::{
- Parcel, BorrowedParcel, Deserialize, DeserializeArray, DeserializeOption, Serialize, SerializeArray, SerializeOption,
+ BorrowedParcel, Deserialize, DeserializeArray, DeserializeOption, Parcel, Serialize,
+ SerializeArray, SerializeOption,
};
use crate::sys;
@@ -431,10 +432,7 @@
impl Deserialize for SpIBinder {
fn deserialize(parcel: &BorrowedParcel<'_>) -> Result<SpIBinder> {
- parcel
- .read_binder()
- .transpose()
- .unwrap_or(Err(StatusCode::UNEXPECTED_NULL))
+ parcel.read_binder().transpose().unwrap_or(Err(StatusCode::UNEXPECTED_NULL))
}
}
@@ -563,6 +561,9 @@
/// The cookie in this struct represents an Arc<F> for the owned callback.
/// This struct owns a ref-count of it, and so does every binder that we
/// have been linked with.
+///
+/// Dropping the `DeathRecipient` will `unlink_to_death` any binders it is
+/// currently linked to.
#[repr(C)]
pub struct DeathRecipient {
recipient: *mut sys::AIBinder_DeathRecipient,
@@ -610,7 +611,10 @@
//
// All uses of linkToDeath in this file correctly increment the
// ref-count that this onUnlinked callback will decrement.
- sys::AIBinder_DeathRecipient_setOnUnlinked(recipient, Some(Self::cookie_decr_refcount::<F>));
+ sys::AIBinder_DeathRecipient_setOnUnlinked(
+ recipient,
+ Some(Self::cookie_decr_refcount::<F>),
+ );
}
DeathRecipient {
recipient,
diff --git a/libs/binder/rust/src/state.rs b/libs/binder/rust/src/state.rs
index 0aef744..cc18741 100644
--- a/libs/binder/rust/src/state.rs
+++ b/libs/binder/rust/src/state.rs
@@ -124,7 +124,8 @@
/// kernel is too old to support this feature.
pub fn with_calling_sid<T, F>(check_permission: F) -> T
where
- for<'a> F: FnOnce(Option<&'a std::ffi::CStr>) -> T {
+ for<'a> F: FnOnce(Option<&'a std::ffi::CStr>) -> T,
+ {
// Safety: AIBinder_getCallingSid returns a c-string pointer
// that is valid for a transaction. Also, the string returned
// is thread local. By restricting the lifetime of the CStr
diff --git a/libs/binder/rust/tests/integration.rs b/libs/binder/rust/tests/integration.rs
index c9d6af0..4e10fa9 100644
--- a/libs/binder/rust/tests/integration.rs
+++ b/libs/binder/rust/tests/integration.rs
@@ -60,9 +60,7 @@
if let Some(extension_name) = extension_name {
let extension =
BnTest::new_binder(TestService::new(&extension_name), BinderFeatures::default());
- service
- .set_extension(&mut extension.as_binder())
- .expect("Could not add extension");
+ service.set_extension(&mut extension.as_binder()).expect("Could not add extension");
}
binder::add_service(&service_name, service.as_binder())
.expect("Could not register service");
@@ -73,10 +71,7 @@
}
fn print_usage() {
- eprintln!(
- "Usage: {} SERVICE_NAME [EXTENSION_NAME]",
- RUST_SERVICE_BINARY
- );
+ eprintln!("Usage: {} SERVICE_NAME [EXTENSION_NAME]", RUST_SERVICE_BINARY);
eprintln!(concat!(
"Spawn a Binder test service identified by SERVICE_NAME,",
" optionally with an extesion named EXTENSION_NAME",
@@ -90,10 +85,7 @@
impl TestService {
fn new(s: &str) -> Self {
- Self {
- s: s.to_string(),
- dump_args: Mutex::new(Vec::new()),
- }
+ Self { s: s.to_string(), dump_args: Mutex::new(Vec::new()) }
}
}
@@ -111,11 +103,15 @@
fn try_from(c: u32) -> Result<Self, Self::Error> {
match c {
_ if c == TestTransactionCode::Test as u32 => Ok(TestTransactionCode::Test),
- _ if c == TestTransactionCode::GetDumpArgs as u32 => Ok(TestTransactionCode::GetDumpArgs),
+ _ if c == TestTransactionCode::GetDumpArgs as u32 => {
+ Ok(TestTransactionCode::GetDumpArgs)
+ }
_ if c == TestTransactionCode::GetSelinuxContext as u32 => {
Ok(TestTransactionCode::GetSelinuxContext)
}
- _ if c == TestTransactionCode::GetIsHandlingTransaction as u32 => Ok(TestTransactionCode::GetIsHandlingTransaction),
+ _ if c == TestTransactionCode::GetIsHandlingTransaction as u32 => {
+ Ok(TestTransactionCode::GetIsHandlingTransaction)
+ }
_ => Err(StatusCode::UNKNOWN_TRANSACTION),
}
}
@@ -200,15 +196,16 @@
TestTransactionCode::Test => reply.write(&service.test()?),
TestTransactionCode::GetDumpArgs => reply.write(&service.get_dump_args()?),
TestTransactionCode::GetSelinuxContext => reply.write(&service.get_selinux_context()?),
- TestTransactionCode::GetIsHandlingTransaction => reply.write(&service.get_is_handling_transaction()?),
+ TestTransactionCode::GetIsHandlingTransaction => {
+ reply.write(&service.get_is_handling_transaction()?)
+ }
}
}
impl ITest for BpTest {
fn test(&self) -> Result<String, StatusCode> {
let reply =
- self.binder
- .transact(TestTransactionCode::Test as TransactionCode, 0, |_| Ok(()))?;
+ self.binder.transact(TestTransactionCode::Test as TransactionCode, 0, |_| Ok(()))?;
reply.read()
}
@@ -243,31 +240,45 @@
let binder = self.binder.clone();
P::spawn(
move || binder.transact(TestTransactionCode::Test as TransactionCode, 0, |_| Ok(())),
- |reply| async move { reply?.read() }
+ |reply| async move { reply?.read() },
)
}
fn get_dump_args(&self) -> binder::BoxFuture<'static, Result<Vec<String>, StatusCode>> {
let binder = self.binder.clone();
P::spawn(
- move || binder.transact(TestTransactionCode::GetDumpArgs as TransactionCode, 0, |_| Ok(())),
- |reply| async move { reply?.read() }
+ move || {
+ binder.transact(TestTransactionCode::GetDumpArgs as TransactionCode, 0, |_| Ok(()))
+ },
+ |reply| async move { reply?.read() },
)
}
fn get_selinux_context(&self) -> binder::BoxFuture<'static, Result<String, StatusCode>> {
let binder = self.binder.clone();
P::spawn(
- move || binder.transact(TestTransactionCode::GetSelinuxContext as TransactionCode, 0, |_| Ok(())),
- |reply| async move { reply?.read() }
+ move || {
+ binder.transact(
+ TestTransactionCode::GetSelinuxContext as TransactionCode,
+ 0,
+ |_| Ok(()),
+ )
+ },
+ |reply| async move { reply?.read() },
)
}
fn get_is_handling_transaction(&self) -> binder::BoxFuture<'static, Result<bool, StatusCode>> {
let binder = self.binder.clone();
P::spawn(
- move || binder.transact(TestTransactionCode::GetIsHandlingTransaction as TransactionCode, 0, |_| Ok(())),
- |reply| async move { reply?.read() }
+ move || {
+ binder.transact(
+ TestTransactionCode::GetIsHandlingTransaction as TransactionCode,
+ 0,
+ |_| Ok(()),
+ )
+ },
+ |reply| async move { reply?.read() },
)
}
}
@@ -374,7 +385,7 @@
use binder_tokio::Tokio;
- use super::{BnTest, ITest, IATest, ITestSameDescriptor, TestService, RUST_SERVICE_BINARY};
+ use super::{BnTest, IATest, ITest, ITestSameDescriptor, TestService, RUST_SERVICE_BINARY};
pub struct ScopedServiceProcess(Child);
@@ -405,9 +416,7 @@
impl Drop for ScopedServiceProcess {
fn drop(&mut self) {
self.0.kill().expect("Could not kill child process");
- self.0
- .wait()
- .expect("Could not wait for child process to die");
+ self.0.wait().expect("Could not wait for child process to die");
}
}
@@ -428,10 +437,7 @@
);
// The service manager service isn't an ITest, so this must fail.
- assert_eq!(
- binder::get_interface::<dyn ITest>("manager").err(),
- Some(StatusCode::BAD_TYPE)
- );
+ assert_eq!(binder::get_interface::<dyn ITest>("manager").err(), Some(StatusCode::BAD_TYPE));
assert_eq!(
binder::get_interface::<dyn IATest<Tokio>>("manager").err(),
Some(StatusCode::BAD_TYPE)
@@ -450,7 +456,9 @@
Some(StatusCode::NAME_NOT_FOUND)
);
assert_eq!(
- binder_tokio::get_interface::<dyn IATest<Tokio>>("this_service_does_not_exist").await.err(),
+ binder_tokio::get_interface::<dyn IATest<Tokio>>("this_service_does_not_exist")
+ .await
+ .err(),
Some(StatusCode::NAME_NOT_FOUND)
);
@@ -511,8 +519,9 @@
async fn trivial_client_async() {
let service_name = "trivial_client_test";
let _process = ScopedServiceProcess::new(service_name);
- let test_client: Strong<dyn IATest<Tokio>> =
- binder_tokio::get_interface(service_name).await.expect("Did not get manager binder service");
+ let test_client: Strong<dyn IATest<Tokio>> = binder_tokio::get_interface(service_name)
+ .await
+ .expect("Did not get manager binder service");
assert_eq!(test_client.test().await.unwrap(), "trivial_client_test");
}
@@ -529,8 +538,9 @@
async fn wait_for_trivial_client_async() {
let service_name = "wait_for_trivial_client_test";
let _process = ScopedServiceProcess::new(service_name);
- let test_client: Strong<dyn IATest<Tokio>> =
- binder_tokio::wait_for_interface(service_name).await.expect("Did not get manager binder service");
+ let test_client: Strong<dyn IATest<Tokio>> = binder_tokio::wait_for_interface(service_name)
+ .await
+ .expect("Did not get manager binder service");
assert_eq!(test_client.test().await.unwrap(), "wait_for_trivial_client_test");
}
@@ -539,9 +549,7 @@
let mut out_ptr = ptr::null_mut();
assert_eq!(selinux_sys::getcon(&mut out_ptr), 0);
assert!(!out_ptr.is_null());
- CStr::from_ptr(out_ptr)
- .to_str()
- .expect("context was invalid UTF-8")
+ CStr::from_ptr(out_ptr).to_str().expect("context was invalid UTF-8")
}
}
@@ -551,18 +559,16 @@
let _process = ScopedServiceProcess::new(service_name);
let test_client: Strong<dyn ITest> =
binder::get_interface(service_name).expect("Did not get manager binder service");
- assert_eq!(
- test_client.get_selinux_context().unwrap(),
- get_expected_selinux_context()
- );
+ assert_eq!(test_client.get_selinux_context().unwrap(), get_expected_selinux_context());
}
#[tokio::test]
async fn get_selinux_context_async() {
let service_name = "get_selinux_context_async";
let _process = ScopedServiceProcess::new(service_name);
- let test_client: Strong<dyn IATest<Tokio>> =
- binder_tokio::get_interface(service_name).await.expect("Did not get manager binder service");
+ let test_client: Strong<dyn IATest<Tokio>> = binder_tokio::get_interface(service_name)
+ .await
+ .expect("Did not get manager binder service");
assert_eq!(
test_client.get_selinux_context().await.unwrap(),
get_expected_selinux_context()
@@ -586,13 +592,11 @@
async fn get_selinux_context_async_to_sync() {
let service_name = "get_selinux_context";
let _process = ScopedServiceProcess::new(service_name);
- let test_client: Strong<dyn IATest<Tokio>> =
- binder_tokio::get_interface(service_name).await.expect("Did not get manager binder service");
+ let test_client: Strong<dyn IATest<Tokio>> = binder_tokio::get_interface(service_name)
+ .await
+ .expect("Did not get manager binder service");
let test_client = test_client.into_sync();
- assert_eq!(
- test_client.get_selinux_context().unwrap(),
- get_expected_selinux_context()
- );
+ assert_eq!(test_client.get_selinux_context().unwrap(), get_expected_selinux_context());
}
struct Bools {
@@ -605,10 +609,7 @@
self.binder_died.load(Ordering::Relaxed)
}
fn assert_died(&self) {
- assert!(
- self.is_dead(),
- "Did not receive death notification"
- );
+ assert!(self.is_dead(), "Did not receive death notification");
}
fn assert_dropped(&self) {
assert!(
@@ -639,9 +640,7 @@
let mut death_recipient = {
let flag = binder_died.clone();
- let set_on_drop = SetOnDrop {
- binder_dealloc: binder_dealloc.clone(),
- };
+ let set_on_drop = SetOnDrop { binder_dealloc: binder_dealloc.clone() };
DeathRecipient::new(move || {
flag.store(true, Ordering::Relaxed);
// Force the closure to take ownership of set_on_drop. When the closure is
@@ -650,14 +649,9 @@
})
};
- binder
- .link_to_death(&mut death_recipient)
- .expect("link_to_death failed");
+ binder.link_to_death(&mut death_recipient).expect("link_to_death failed");
- let bools = Bools {
- binder_died,
- binder_dealloc,
- };
+ let bools = Bools { binder_died, binder_dealloc };
(bools, death_recipient)
}
@@ -675,9 +669,7 @@
let (bools, recipient) = register_death_notification(&mut remote);
drop(service_process);
- remote
- .ping_binder()
- .expect_err("Service should have died already");
+ remote.ping_binder().expect_err("Service should have died already");
// Pause to ensure any death notifications get delivered
thread::sleep(Duration::from_secs(1));
@@ -701,22 +693,15 @@
let (bools, mut recipient) = register_death_notification(&mut remote);
- remote
- .unlink_to_death(&mut recipient)
- .expect("Could not unlink death notifications");
+ remote.unlink_to_death(&mut recipient).expect("Could not unlink death notifications");
drop(service_process);
- remote
- .ping_binder()
- .expect_err("Service should have died already");
+ remote.ping_binder().expect_err("Service should have died already");
// Pause to ensure any death notifications get delivered
thread::sleep(Duration::from_secs(1));
- assert!(
- !bools.is_dead(),
- "Received unexpected death notification after unlinking",
- );
+ assert!(!bools.is_dead(), "Received unexpected death notification after unlinking",);
bools.assert_not_dropped();
drop(recipient);
@@ -771,9 +756,7 @@
let dump_args = ["dump", "args", "for", "testing"];
let null_out = File::open("/dev/null").expect("Could not open /dev/null");
- remote
- .dump(&null_out, &dump_args)
- .expect("Could not dump remote service");
+ remote.dump(&null_out, &dump_args).expect("Could not dump remote service");
let remote_args = test_client.get_dump_args().expect("Could not fetched dumped args");
assert_eq!(dump_args, remote_args[..], "Remote args don't match call to dump");
@@ -799,9 +782,7 @@
let mut remote = binder::get_service(service_name);
assert!(remote.is_binder_alive());
- let extension = remote
- .get_extension()
- .expect("Could not check for an extension");
+ let extension = remote.get_extension().expect("Could not check for an extension");
assert!(extension.is_none());
}
@@ -811,9 +792,7 @@
let mut remote = binder::get_service(service_name);
assert!(remote.is_binder_alive());
- let maybe_extension = remote
- .get_extension()
- .expect("Could not check for an extension");
+ let maybe_extension = remote.get_extension().expect("Could not check for an extension");
let extension = maybe_extension.expect("Remote binder did not have an extension");
@@ -850,15 +829,12 @@
#[test]
fn reassociate_rust_binder() {
let service_name = "testing_service";
- let service_ibinder = BnTest::new_binder(
- TestService::new(service_name),
- BinderFeatures::default(),
- )
- .as_binder();
+ let service_ibinder =
+ BnTest::new_binder(TestService::new(service_name), BinderFeatures::default())
+ .as_binder();
- let service: Strong<dyn ITest> = service_ibinder
- .into_interface()
- .expect("Could not reassociate the generic ibinder");
+ let service: Strong<dyn ITest> =
+ service_ibinder.into_interface().expect("Could not reassociate the generic ibinder");
assert_eq!(service.test().unwrap(), service_name);
}
@@ -866,10 +842,7 @@
#[test]
fn weak_binder_upgrade() {
let service_name = "testing_service";
- let service = BnTest::new_binder(
- TestService::new(service_name),
- BinderFeatures::default(),
- );
+ let service = BnTest::new_binder(TestService::new(service_name), BinderFeatures::default());
let weak = Strong::downgrade(&service);
@@ -882,10 +855,8 @@
fn weak_binder_upgrade_dead() {
let service_name = "testing_service";
let weak = {
- let service = BnTest::new_binder(
- TestService::new(service_name),
- BinderFeatures::default(),
- );
+ let service =
+ BnTest::new_binder(TestService::new(service_name), BinderFeatures::default());
Strong::downgrade(&service)
};
@@ -896,10 +867,7 @@
#[test]
fn weak_binder_clone() {
let service_name = "testing_service";
- let service = BnTest::new_binder(
- TestService::new(service_name),
- BinderFeatures::default(),
- );
+ let service = BnTest::new_binder(TestService::new(service_name), BinderFeatures::default());
let weak = Strong::downgrade(&service);
let cloned = weak.clone();
@@ -915,14 +883,10 @@
#[test]
#[allow(clippy::eq_op)]
fn binder_ord() {
- let service1 = BnTest::new_binder(
- TestService::new("testing_service1"),
- BinderFeatures::default(),
- );
- let service2 = BnTest::new_binder(
- TestService::new("testing_service2"),
- BinderFeatures::default(),
- );
+ let service1 =
+ BnTest::new_binder(TestService::new("testing_service1"), BinderFeatures::default());
+ let service2 =
+ BnTest::new_binder(TestService::new("testing_service2"), BinderFeatures::default());
assert!((service1 >= service1));
assert!((service1 <= service1));
@@ -931,20 +895,20 @@
#[test]
fn binder_parcel_mixup() {
- let service1 = BnTest::new_binder(
- TestService::new("testing_service1"),
- BinderFeatures::default(),
- );
- let service2 = BnTest::new_binder(
- TestService::new("testing_service2"),
- BinderFeatures::default(),
- );
+ let service1 =
+ BnTest::new_binder(TestService::new("testing_service1"), BinderFeatures::default());
+ let service2 =
+ BnTest::new_binder(TestService::new("testing_service2"), BinderFeatures::default());
let service1 = service1.as_binder();
let service2 = service2.as_binder();
let parcel = service1.prepare_transact().unwrap();
- let res = service2.submit_transact(super::TestTransactionCode::Test as TransactionCode, parcel, 0);
+ let res = service2.submit_transact(
+ super::TestTransactionCode::Test as TransactionCode,
+ parcel,
+ 0,
+ );
match res {
Ok(_) => panic!("submit_transact should fail"),
@@ -967,15 +931,18 @@
// Should also be false in spawned thread.
std::thread::spawn(|| {
assert!(!binder::is_handling_transaction());
- }).join().unwrap();
+ })
+ .join()
+ .unwrap();
}
#[tokio::test]
async fn get_is_handling_transaction_async() {
let service_name = "get_is_handling_transaction_async";
let _process = ScopedServiceProcess::new(service_name);
- let test_client: Strong<dyn IATest<Tokio>> =
- binder_tokio::get_interface(service_name).await.expect("Did not get manager binder service");
+ let test_client: Strong<dyn IATest<Tokio>> = binder_tokio::get_interface(service_name)
+ .await
+ .expect("Did not get manager binder service");
// Should be true externally.
assert!(test_client.get_is_handling_transaction().await.unwrap());
@@ -985,11 +952,15 @@
// Should also be false in spawned task.
tokio::spawn(async {
assert!(!binder::is_handling_transaction());
- }).await.unwrap();
+ })
+ .await
+ .unwrap();
// And in spawn_blocking task.
tokio::task::spawn_blocking(|| {
assert!(!binder::is_handling_transaction());
- }).await.unwrap();
+ })
+ .await
+ .unwrap();
}
}
diff --git a/libs/binder/rust/tests/serialization.rs b/libs/binder/rust/tests/serialization.rs
index f6bdf5c..6220db4 100644
--- a/libs/binder/rust/tests/serialization.rs
+++ b/libs/binder/rust/tests/serialization.rs
@@ -23,7 +23,7 @@
};
// Import from impl API for testing only, should not be necessary as long as you
// are using AIDL.
-use binder::binder_impl::{BorrowedParcel, Binder, TransactionCode};
+use binder::binder_impl::{Binder, BorrowedParcel, TransactionCode};
use std::ffi::{c_void, CStr, CString};
use std::sync::Once;
@@ -64,13 +64,7 @@
macro_rules! assert {
($expr:expr) => {
if !$expr {
- eprintln!(
- "assertion failed: `{:?}`, {}:{}:{}",
- $expr,
- file!(),
- line!(),
- column!()
- );
+ eprintln!("assertion failed: `{:?}`, {}:{}:{}", $expr, file!(), line!(), column!());
return Err(StatusCode::FAILED_TRANSACTION);
}
};
@@ -119,9 +113,7 @@
bindings::Transaction_TEST_BOOL => {
assert!(parcel.read::<bool>()?);
assert!(!parcel.read::<bool>()?);
- assert_eq!(parcel.read::<Vec<bool>>()?, unsafe {
- bindings::TESTDATA_BOOL
- });
+ assert_eq!(parcel.read::<Vec<bool>>()?, unsafe { bindings::TESTDATA_BOOL });
assert_eq!(parcel.read::<Option<Vec<bool>>>()?, None);
reply.write(&true)?;
@@ -148,9 +140,7 @@
assert_eq!(parcel.read::<u16>()?, 0);
assert_eq!(parcel.read::<u16>()?, 1);
assert_eq!(parcel.read::<u16>()?, u16::max_value());
- assert_eq!(parcel.read::<Vec<u16>>()?, unsafe {
- bindings::TESTDATA_CHARS
- });
+ assert_eq!(parcel.read::<Vec<u16>>()?, unsafe { bindings::TESTDATA_CHARS });
assert_eq!(parcel.read::<Option<Vec<u16>>>()?, None);
reply.write(&0u16)?;
@@ -163,9 +153,7 @@
assert_eq!(parcel.read::<i32>()?, 0);
assert_eq!(parcel.read::<i32>()?, 1);
assert_eq!(parcel.read::<i32>()?, i32::max_value());
- assert_eq!(parcel.read::<Vec<i32>>()?, unsafe {
- bindings::TESTDATA_I32
- });
+ assert_eq!(parcel.read::<Vec<i32>>()?, unsafe { bindings::TESTDATA_I32 });
assert_eq!(parcel.read::<Option<Vec<i32>>>()?, None);
reply.write(&0i32)?;
@@ -178,9 +166,7 @@
assert_eq!(parcel.read::<i64>()?, 0);
assert_eq!(parcel.read::<i64>()?, 1);
assert_eq!(parcel.read::<i64>()?, i64::max_value());
- assert_eq!(parcel.read::<Vec<i64>>()?, unsafe {
- bindings::TESTDATA_I64
- });
+ assert_eq!(parcel.read::<Vec<i64>>()?, unsafe { bindings::TESTDATA_I64 });
assert_eq!(parcel.read::<Option<Vec<i64>>>()?, None);
reply.write(&0i64)?;
@@ -193,9 +179,7 @@
assert_eq!(parcel.read::<u64>()?, 0);
assert_eq!(parcel.read::<u64>()?, 1);
assert_eq!(parcel.read::<u64>()?, u64::max_value());
- assert_eq!(parcel.read::<Vec<u64>>()?, unsafe {
- bindings::TESTDATA_U64
- });
+ assert_eq!(parcel.read::<Vec<u64>>()?, unsafe { bindings::TESTDATA_U64 });
assert_eq!(parcel.read::<Option<Vec<u64>>>()?, None);
reply.write(&0u64)?;
@@ -232,16 +216,9 @@
let s: Option<String> = parcel.read()?;
assert_eq!(s, None);
let s: Option<Vec<Option<String>>> = parcel.read()?;
- for (s, expected) in s
- .unwrap()
- .iter()
- .zip(unsafe { bindings::TESTDATA_STRS }.iter())
- {
- let expected = unsafe {
- expected
- .as_ref()
- .and_then(|e| CStr::from_ptr(e).to_str().ok())
- };
+ for (s, expected) in s.unwrap().iter().zip(unsafe { bindings::TESTDATA_STRS }.iter()) {
+ let expected =
+ unsafe { expected.as_ref().and_then(|e| CStr::from_ptr(e).to_str().ok()) };
assert_eq!(s.as_deref(), expected);
}
let s: Option<Vec<Option<String>>> = parcel.read()?;
@@ -252,10 +229,7 @@
.iter()
.map(|s| {
s.as_ref().map(|s| {
- CStr::from_ptr(s)
- .to_str()
- .expect("String was not UTF-8")
- .to_owned()
+ CStr::from_ptr(s).to_str().expect("String was not UTF-8").to_owned()
})
})
.collect()
@@ -284,12 +258,8 @@
assert!(ibinders[1].is_none());
assert!(parcel.read::<Option<Vec<Option<SpIBinder>>>>()?.is_none());
- let service = unsafe {
- SERVICE
- .as_ref()
- .expect("Global binder service not initialized")
- .clone()
- };
+ let service =
+ unsafe { SERVICE.as_ref().expect("Global binder service not initialized").clone() };
reply.write(&service)?;
reply.write(&(None as Option<&SpIBinder>))?;
reply.write(&[Some(&service), None][..])?;
@@ -300,10 +270,7 @@
assert!(status.is_ok());
let status: Status = parcel.read()?;
assert_eq!(status.exception_code(), ExceptionCode::NULL_POINTER);
- assert_eq!(
- status.get_description(),
- "Status(-4, EX_NULL_POINTER): 'a status message'"
- );
+ assert_eq!(status.get_description(), "Status(-4, EX_NULL_POINTER): 'a status message'");
let status: Status = parcel.read()?;
assert_eq!(status.service_specific_error(), 42);
assert_eq!(
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index fef83ea..4b4d46a 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -1948,6 +1948,7 @@
mReqHeight = 0;
mReqUsage = 0;
mCrop.clear();
+ mDataSpace = Dataspace::UNKNOWN;
mScalingMode = NATIVE_WINDOW_SCALING_MODE_FREEZE;
mTransform = 0;
mStickyTransform = 0;
diff --git a/rustfmt.toml b/rustfmt.toml
new file mode 120000
index 0000000..ee92d9e
--- /dev/null
+++ b/rustfmt.toml
@@ -0,0 +1 @@
+../../build/soong/scripts/rustfmt.toml
\ No newline at end of file
diff --git a/services/inputflinger/Android.bp b/services/inputflinger/Android.bp
index 41878e3..554514d 100644
--- a/services/inputflinger/Android.bp
+++ b/services/inputflinger/Android.bp
@@ -168,3 +168,38 @@
"libinputflinger_headers",
],
}
+
+// This target will build everything 'input-related'. This could be useful for
+// large refactorings of the input code. This is similar to 'm checkbuild', but
+// just for input code.
+// Use 'm checkinput' to build, and then (optionally) use 'm installclean' to
+// remove any of the installed artifacts that you may not want on your actual
+// build.
+phony {
+ name: "checkinput",
+ required: [
+ // native targets
+ "libinput",
+ "libinputflinger",
+ "inputflinger_tests",
+ "inputflinger_benchmarks",
+ "libinput_tests",
+ "libpalmrejection_test",
+ "libandroid_runtime",
+ "libinputservice_test",
+ "Bug-115739809",
+ "StructLayout_test",
+
+ // Java/Kotlin targets
+ "CtsWindowManagerDeviceTestCases",
+ "InputTests",
+ "CtsHardwareTestCases",
+ "CtsInputTestCases",
+ "CtsViewTestCases",
+ "CtsWidgetTestCases",
+ "FrameworksCoreTests",
+ "FrameworksServicesTests",
+ "CtsSecurityTestCases",
+ "CtsSecurityBulletinHostTestCases",
+ ],
+}
diff --git a/services/surfaceflinger/Scheduler/Android.bp b/services/surfaceflinger/Scheduler/Android.bp
index 5de796d..5bd8a99 100644
--- a/services/surfaceflinger/Scheduler/Android.bp
+++ b/services/surfaceflinger/Scheduler/Android.bp
@@ -18,6 +18,7 @@
"libbase",
"libcutils",
"liblog",
+ "libui",
"libutils",
],
}
@@ -39,6 +40,7 @@
name: "libscheduler",
defaults: ["libscheduler_defaults"],
srcs: [
+ "src/PresentLatencyTracker.cpp",
"src/Timer.cpp",
],
local_include_dirs: ["include"],
@@ -50,6 +52,7 @@
test_suites: ["device-tests"],
defaults: ["libscheduler_defaults"],
srcs: [
+ "tests/PresentLatencyTrackerTest.cpp",
"tests/TimerTest.cpp",
],
static_libs: [
diff --git a/services/surfaceflinger/Scheduler/include/scheduler/PresentLatencyTracker.h b/services/surfaceflinger/Scheduler/include/scheduler/PresentLatencyTracker.h
new file mode 100644
index 0000000..23ae83f
--- /dev/null
+++ b/services/surfaceflinger/Scheduler/include/scheduler/PresentLatencyTracker.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <memory>
+#include <queue>
+#include <utility>
+
+#include <scheduler/Time.h>
+
+namespace android {
+
+class FenceTime;
+
+namespace scheduler {
+
+// Computes composite-to-present latency by tracking recently composited frames pending to present.
+class PresentLatencyTracker {
+public:
+ // For tests.
+ static constexpr size_t kMaxPendingFrames = 4;
+
+ // Returns the present latency of the latest frame.
+ Duration trackPendingFrame(TimePoint compositeTime,
+ std::shared_ptr<FenceTime> presentFenceTime);
+
+private:
+ struct PendingFrame {
+ PendingFrame(TimePoint compositeTime, std::shared_ptr<FenceTime> presentFenceTime)
+ : compositeTime(compositeTime), presentFenceTime(std::move(presentFenceTime)) {}
+
+ const TimePoint compositeTime;
+ const std::shared_ptr<FenceTime> presentFenceTime;
+ };
+
+ std::queue<PendingFrame> mPendingFrames;
+};
+
+} // namespace scheduler
+} // namespace android
diff --git a/services/surfaceflinger/Scheduler/include/scheduler/Time.h b/services/surfaceflinger/Scheduler/include/scheduler/Time.h
index 6fa548e..2b3ad2d 100644
--- a/services/surfaceflinger/Scheduler/include/scheduler/Time.h
+++ b/services/surfaceflinger/Scheduler/include/scheduler/Time.h
@@ -32,13 +32,13 @@
struct Duration;
struct TimePoint : scheduler::SchedulerClock::time_point {
- explicit TimePoint(const Duration&);
+ explicit constexpr TimePoint(const Duration&);
// Implicit conversion from std::chrono counterpart.
constexpr TimePoint(scheduler::SchedulerClock::time_point p)
: scheduler::SchedulerClock::time_point(p) {}
- static TimePoint fromNs(nsecs_t);
+ static constexpr TimePoint fromNs(nsecs_t);
nsecs_t ns() const;
};
@@ -47,16 +47,16 @@
// Implicit conversion from std::chrono counterpart.
constexpr Duration(TimePoint::duration d) : TimePoint::duration(d) {}
- static Duration fromNs(nsecs_t ns) { return {std::chrono::nanoseconds(ns)}; }
+ static constexpr Duration fromNs(nsecs_t ns) { return {std::chrono::nanoseconds(ns)}; }
nsecs_t ns() const { return std::chrono::nanoseconds(*this).count(); }
};
using Period = Duration;
-inline TimePoint::TimePoint(const Duration& d) : scheduler::SchedulerClock::time_point(d) {}
+constexpr TimePoint::TimePoint(const Duration& d) : scheduler::SchedulerClock::time_point(d) {}
-inline TimePoint TimePoint::fromNs(nsecs_t ns) {
+constexpr TimePoint TimePoint::fromNs(nsecs_t ns) {
return TimePoint(Duration::fromNs(ns));
}
diff --git a/services/surfaceflinger/Scheduler/src/PresentLatencyTracker.cpp b/services/surfaceflinger/Scheduler/src/PresentLatencyTracker.cpp
new file mode 100644
index 0000000..8f3e081
--- /dev/null
+++ b/services/surfaceflinger/Scheduler/src/PresentLatencyTracker.cpp
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2022 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 <scheduler/PresentLatencyTracker.h>
+
+#include <cutils/compiler.h>
+#include <log/log.h>
+#include <ui/FenceTime.h>
+
+namespace android::scheduler {
+
+Duration PresentLatencyTracker::trackPendingFrame(TimePoint compositeTime,
+ std::shared_ptr<FenceTime> presentFenceTime) {
+ Duration presentLatency = Duration::zero();
+ while (!mPendingFrames.empty()) {
+ const auto& pendingFrame = mPendingFrames.front();
+ const auto presentTime =
+ TimePoint::fromNs(pendingFrame.presentFenceTime->getCachedSignalTime());
+
+ if (presentTime == TimePoint::fromNs(Fence::SIGNAL_TIME_PENDING)) {
+ break;
+ }
+
+ if (presentTime == TimePoint::fromNs(Fence::SIGNAL_TIME_INVALID)) {
+ ALOGE("%s: Invalid present fence", __func__);
+ } else {
+ presentLatency = presentTime - pendingFrame.compositeTime;
+ }
+
+ mPendingFrames.pop();
+ }
+
+ mPendingFrames.emplace(compositeTime, std::move(presentFenceTime));
+
+ if (CC_UNLIKELY(mPendingFrames.size() > kMaxPendingFrames)) {
+ ALOGE("%s: Too many pending frames", __func__);
+ mPendingFrames.pop();
+ }
+
+ return presentLatency;
+}
+
+} // namespace android::scheduler
diff --git a/services/surfaceflinger/Scheduler/tests/PresentLatencyTrackerTest.cpp b/services/surfaceflinger/Scheduler/tests/PresentLatencyTrackerTest.cpp
new file mode 100644
index 0000000..8952ca9
--- /dev/null
+++ b/services/surfaceflinger/Scheduler/tests/PresentLatencyTrackerTest.cpp
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2022 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 <gtest/gtest.h>
+
+#include <algorithm>
+#include <array>
+
+#include <scheduler/PresentLatencyTracker.h>
+#include <ui/FenceTime.h>
+
+namespace android::scheduler {
+namespace {
+
+using FencePair = std::pair<sp<Fence>, std::shared_ptr<FenceTime>>;
+
+FencePair makePendingFence(FenceToFenceTimeMap& fenceMap) {
+ const auto fence = sp<Fence>::make();
+ return {fence, fenceMap.createFenceTimeForTest(fence)};
+}
+
+} // namespace
+
+TEST(PresentLatencyTrackerTest, skipsInvalidFences) {
+ PresentLatencyTracker tracker;
+
+ const TimePoint kCompositeTime = TimePoint::fromNs(999);
+ EXPECT_EQ(tracker.trackPendingFrame(kCompositeTime, FenceTime::NO_FENCE), Duration::zero());
+ EXPECT_EQ(tracker.trackPendingFrame(kCompositeTime, FenceTime::NO_FENCE), Duration::zero());
+ EXPECT_EQ(tracker.trackPendingFrame(kCompositeTime, FenceTime::NO_FENCE), Duration::zero());
+
+ FenceToFenceTimeMap fenceMap;
+ const auto [fence, fenceTime] = makePendingFence(fenceMap);
+ EXPECT_EQ(tracker.trackPendingFrame(kCompositeTime, fenceTime), Duration::zero());
+
+ fenceTime->signalForTest(9999);
+
+ EXPECT_EQ(tracker.trackPendingFrame(kCompositeTime, FenceTime::NO_FENCE),
+ Duration::fromNs(9000));
+}
+
+TEST(PresentLatencyTrackerTest, tracksPendingFrames) {
+ PresentLatencyTracker tracker;
+
+ FenceToFenceTimeMap fenceMap;
+ std::array<FencePair, PresentLatencyTracker::kMaxPendingFrames> fences;
+ std::generate(fences.begin(), fences.end(), [&fenceMap] { return makePendingFence(fenceMap); });
+
+ // The present latency is 0 if all fences are pending.
+ const TimePoint kCompositeTime = TimePoint::fromNs(1234);
+ for (const auto& [fence, fenceTime] : fences) {
+ EXPECT_EQ(tracker.trackPendingFrame(kCompositeTime, fenceTime), Duration::zero());
+ }
+
+ // If multiple frames have been presented...
+ constexpr size_t kPresentCount = fences.size() / 2;
+ for (size_t i = 0; i < kPresentCount; i++) {
+ fences[i].second->signalForTest(kCompositeTime.ns() + static_cast<nsecs_t>(i));
+ }
+
+ const auto fence = makePendingFence(fenceMap);
+
+ // ...then the present latency is measured using the latest frame.
+ constexpr Duration kPresentLatency = Duration::fromNs(static_cast<nsecs_t>(kPresentCount) - 1);
+ EXPECT_EQ(tracker.trackPendingFrame(kCompositeTime, fence.second), kPresentLatency);
+}
+
+} // namespace android::scheduler
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 4f54f17..3b15ac4 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -686,23 +686,22 @@
readPersistentProperties();
mPowerAdvisor->onBootFinished();
- const bool powerHintEnabled = mFlagManager.use_adpf_cpu_hint();
- mPowerAdvisor->enablePowerHint(powerHintEnabled);
- const bool powerHintUsed = mPowerAdvisor->usePowerHintSession();
- ALOGD("Power hint is %s",
- powerHintUsed ? "supported" : (powerHintEnabled ? "unsupported" : "disabled"));
- if (powerHintUsed) {
- std::optional<pid_t> renderEngineTid = getRenderEngine().getRenderEngineTid();
- std::vector<int32_t> tidList;
- tidList.emplace_back(gettid());
- if (renderEngineTid.has_value()) {
- tidList.emplace_back(*renderEngineTid);
- }
- if (!mPowerAdvisor->startPowerHintSession(tidList)) {
- ALOGW("Cannot start power hint session");
+
+ // try to enable power hint session again using mendel flag now that boot is finished,
+ // but only if we didn't already try earlier
+ if (!mPowerAdvisor->usePowerHintSession() && mFlagManager.use_adpf_cpu_hint()) {
+ mPowerAdvisor->enablePowerHint(true);
+ // check again to make sure it's actually supported
+ if (mPowerAdvisor->usePowerHintSession()) {
+ startPowerHintSession();
}
}
+ ALOGD("Power hint session is %s",
+ mPowerAdvisor->usePowerHintSession()
+ ? "enabled"
+ : (!mPowerAdvisor->supportsPowerHintSession() ? "unsupported" : "disabled"));
+
mBootStage = BootStage::FINISHED;
if (property_get_bool("sf.debug.show_refresh_rate_overlay", false)) {
@@ -826,6 +825,11 @@
mPowerAdvisor->init();
+ mPowerAdvisor->enablePowerHint(mFlagManager.use_adpf_cpu_hint());
+ if (mPowerAdvisor->usePowerHintSession()) {
+ startPowerHintSession();
+ }
+
char primeShaderCache[PROPERTY_VALUE_MAX];
property_get("service.sf.prime_shader_cache", primeShaderCache, "1");
if (atoi(primeShaderCache)) {
@@ -1448,18 +1452,6 @@
}));
}
-status_t SurfaceFlinger::clearAnimationFrameStats() {
- Mutex::Autolock _l(mStateLock);
- mAnimFrameTracker.clearStats();
- return NO_ERROR;
-}
-
-status_t SurfaceFlinger::getAnimationFrameStats(FrameStats* outStats) const {
- Mutex::Autolock _l(mStateLock);
- mAnimFrameTracker.getStats(outStats);
- return NO_ERROR;
-}
-
status_t SurfaceFlinger::overrideHdrTypes(const sp<IBinder>& displayToken,
const std::vector<ui::Hdr>& hdrTypes) {
Mutex::Autolock lock(mStateLock);
@@ -2316,32 +2308,6 @@
mLayersPendingRefresh.clear();
}
-nsecs_t SurfaceFlinger::trackPresentLatency(nsecs_t compositeTime,
- std::shared_ptr<FenceTime> presentFenceTime) {
- // Update queue of past composite+present times and determine the
- // most recently known composite to present latency.
- getBE().mCompositePresentTimes.push({compositeTime, std::move(presentFenceTime)});
- nsecs_t compositeToPresentLatency = -1;
- while (!getBE().mCompositePresentTimes.empty()) {
- SurfaceFlingerBE::CompositePresentTime& cpt = getBE().mCompositePresentTimes.front();
- // Cached values should have been updated before calling this method,
- // which helps avoid duplicate syscalls.
- nsecs_t displayTime = cpt.display->getCachedSignalTime();
- if (displayTime == Fence::SIGNAL_TIME_PENDING) {
- break;
- }
- compositeToPresentLatency = displayTime - cpt.composite;
- getBE().mCompositePresentTimes.pop();
- }
-
- // Don't let mCompositePresentTimes grow unbounded, just in case.
- while (getBE().mCompositePresentTimes.size() > 16) {
- getBE().mCompositePresentTimes.pop();
- }
-
- return compositeToPresentLatency;
-}
-
bool SurfaceFlinger::isHdrLayer(Layer* layer) const {
// Treat all layers as non-HDR if:
// 1. They do not have a valid HDR dataspace. Currently we treat those as PQ or HLG. and
@@ -2429,9 +2395,11 @@
// We use the CompositionEngine::getLastFrameRefreshTimestamp() which might
// be sampled a little later than when we started doing work for this frame,
// but that should be okay since CompositorTiming has snapping logic.
- const nsecs_t compositeTime = mCompositionEngine->getLastFrameRefreshTimestamp();
- const nsecs_t presentLatency =
- trackPresentLatency(compositeTime, mPreviousPresentFences[0].fenceTime);
+ const TimePoint compositeTime =
+ TimePoint::fromNs(mCompositionEngine->getLastFrameRefreshTimestamp());
+ const Duration presentLatency =
+ mPresentLatencyTracker.trackPendingFrame(compositeTime,
+ mPreviousPresentFences[0].fenceTime);
const auto& schedule = mScheduler->getVsyncSchedule();
const TimePoint vsyncDeadline = schedule.vsyncDeadlineAfter(TimePoint::fromNs(now));
@@ -2439,7 +2407,7 @@
const nsecs_t vsyncPhase = mVsyncConfiguration->getCurrentConfigs().late.sfOffset;
const CompositorTiming compositorTiming(vsyncDeadline.ns(), vsyncPeriod.ns(), vsyncPhase,
- presentLatency);
+ presentLatency.ns());
for (const auto& layer: mLayersWithQueuedFrames) {
layer->onPostComposition(display, glCompositionDoneFenceTime,
@@ -2519,22 +2487,7 @@
}
}
- if (mAnimCompositionPending) {
- mAnimCompositionPending = false;
-
- if (mPreviousPresentFences[0].fenceTime->isValid()) {
- mAnimFrameTracker.setActualPresentFence(mPreviousPresentFences[0].fenceTime);
- } else if (isDisplayConnected) {
- // The HWC doesn't support present fences, so use the refresh
- // timestamp instead.
- const nsecs_t presentTime = display->getRefreshTimestamp();
- mAnimFrameTracker.setActualPresentTime(presentTime);
- }
- mAnimFrameTracker.advanceFrame();
- }
-
mTimeStats->incrementTotalFrames();
-
mTimeStats->setPresentFenceGlobal(mPreviousPresentFences[0].fenceTime);
const size_t sfConnections = mScheduler->getEventThreadConnectionCount(mSfConnectionHandle);
@@ -3203,7 +3156,6 @@
doCommitTransactions();
signalSynchronousTransactions(CountDownLatch::eSyncTransaction);
- mAnimTransactionPending = false;
}
void SurfaceFlinger::updateInputFlinger() {
@@ -3491,10 +3443,6 @@
mLayersPendingRemoval.clear();
}
- // If this transaction is part of a window animation then the next frame
- // we composite should be considered an animation as well.
- mAnimCompositionPending = mAnimTransactionPending;
-
mDrawingState = mCurrentState;
// clear the "changed" flags in current state
mCurrentState.colorMatrixChanged = false;
@@ -4239,10 +4187,6 @@
if (transactionFlags) {
setTransactionFlags(transactionFlags);
}
-
- if (flags & eAnimation) {
- mAnimTransactionPending = true;
- }
}
return needsTraversal;
@@ -4802,8 +4746,7 @@
{}, mPid, getuid(), transactionId);
setPowerModeInternal(display, hal::PowerMode::ON);
- const nsecs_t vsyncPeriod = display->refreshRateConfigs().getActiveMode()->getVsyncPeriod();
- mAnimFrameTracker.setDisplayRefreshPeriod(vsyncPeriod);
+
mActiveDisplayTransformHint = display->getTransformHint();
}
@@ -5015,17 +4958,14 @@
void SurfaceFlinger::dumpStatsLocked(const DumpArgs& args, std::string& result) const {
StringAppendF(&result, "%" PRId64 "\n", getVsyncPeriodFromHWC());
+ if (args.size() < 2) return;
- if (args.size() > 1) {
- const auto name = String8(args[1]);
- mCurrentState.traverseInZOrder([&](Layer* layer) {
- if (layer->getName() == name.string()) {
- layer->dumpFrameStats(result);
- }
- });
- } else {
- mAnimFrameTracker.dumpStats(result);
- }
+ const auto name = String8(args[1]);
+ mCurrentState.traverseInZOrder([&](Layer* layer) {
+ if (layer->getName() == name.string()) {
+ layer->dumpFrameStats(result);
+ }
+ });
}
void SurfaceFlinger::clearStatsLocked(const DumpArgs& args, std::string&) {
@@ -5037,8 +4977,6 @@
layer->clearFrameStats();
}
});
-
- mAnimFrameTracker.clearStats();
}
void SurfaceFlinger::dumpTimeStats(const DumpArgs& args, bool asProto, std::string& result) const {
@@ -5050,11 +4988,7 @@
}
void SurfaceFlinger::logFrameStats() {
- mDrawingState.traverse([&](Layer* layer) {
- layer->logFrameStats();
- });
-
- mAnimFrameTracker.logAndResetStats("<win-anim>");
+ mDrawingState.traverse([&](Layer* layer) { layer->logFrameStats(); });
}
void SurfaceFlinger::appendSfConfigString(std::string& result) const {
@@ -6549,8 +6483,13 @@
1 /* layerCount */, usage, "screenshot");
const status_t bufferStatus = buffer->initCheck();
- LOG_ALWAYS_FATAL_IF(bufferStatus != OK, "captureScreenCommon: Buffer failed to allocate: %d",
- bufferStatus);
+ if (bufferStatus != OK) {
+ // Animations may end up being really janky, but don't crash here.
+ // Otherwise an irreponsible process may cause an SF crash by allocating
+ // too much.
+ ALOGE("%s: Buffer failed to allocate: %d", __func__, bufferStatus);
+ return ftl::yield<FenceResult>(base::unexpected(bufferStatus)).share();
+ }
const std::shared_ptr<renderengine::ExternalTexture> texture = std::make_shared<
renderengine::impl::ExternalTexture>(buffer, getRenderEngine(),
renderengine::impl::ExternalTexture::Usage::
@@ -7218,6 +7157,18 @@
return true;
}
+void SurfaceFlinger::startPowerHintSession() const {
+ std::optional<pid_t> renderEngineTid = getRenderEngine().getRenderEngineTid();
+ std::vector<int32_t> tidList;
+ tidList.emplace_back(gettid());
+ if (renderEngineTid.has_value()) {
+ tidList.emplace_back(*renderEngineTid);
+ }
+ if (!mPowerAdvisor->startPowerHintSession(tidList)) {
+ ALOGW("Cannot start power hint session");
+ }
+}
+
// gui::ISurfaceComposer
binder::Status SurfaceComposerAIDL::bootFinished() {
@@ -7547,40 +7498,6 @@
return binderStatusFromStatusT(status);
}
-binder::Status SurfaceComposerAIDL::clearAnimationFrameStats() {
- status_t status = checkAccessPermission();
- if (status == OK) {
- status = mFlinger->clearAnimationFrameStats();
- }
- return binderStatusFromStatusT(status);
-}
-
-binder::Status SurfaceComposerAIDL::getAnimationFrameStats(gui::FrameStats* outStats) {
- status_t status = checkAccessPermission();
- if (status != OK) {
- return binderStatusFromStatusT(status);
- }
-
- FrameStats stats;
- status = mFlinger->getAnimationFrameStats(&stats);
- if (status == NO_ERROR) {
- outStats->refreshPeriodNano = stats.refreshPeriodNano;
- outStats->desiredPresentTimesNano.reserve(stats.desiredPresentTimesNano.size());
- for (const auto& t : stats.desiredPresentTimesNano) {
- outStats->desiredPresentTimesNano.push_back(t);
- }
- outStats->actualPresentTimesNano.reserve(stats.actualPresentTimesNano.size());
- for (const auto& t : stats.actualPresentTimesNano) {
- outStats->actualPresentTimesNano.push_back(t);
- }
- outStats->frameReadyTimesNano.reserve(stats.frameReadyTimesNano.size());
- for (const auto& t : stats.frameReadyTimesNano) {
- outStats->frameReadyTimesNano.push_back(t);
- }
- }
- return binderStatusFromStatusT(status);
-}
-
binder::Status SurfaceComposerAIDL::overrideHdrTypes(const sp<IBinder>& display,
const std::vector<int32_t>& hdrTypes) {
// overrideHdrTypes is used by CTS tests, which acquire the necessary
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 7d23c3c..a247bae 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -55,6 +55,7 @@
#include <compositionengine/FenceResult.h>
#include <compositionengine/OutputColorSetting.h>
#include <scheduler/Fps.h>
+#include <scheduler/PresentLatencyTracker.h>
#include "ClientCache.h"
#include "DisplayDevice.h"
@@ -169,13 +170,6 @@
using DisplayColorSetting = compositionengine::OutputColorSetting;
struct SurfaceFlingerBE {
- // Only accessed from the main thread.
- struct CompositePresentTime {
- nsecs_t composite = -1;
- std::shared_ptr<FenceTime> display = FenceTime::NO_FENCE;
- };
- std::queue<CompositePresentTime> mCompositePresentTimes;
-
static const size_t NUM_BUCKETS = 8; // < 1-7, 7+
nsecs_t mFrameBuckets[NUM_BUCKETS] = {};
nsecs_t mTotalTime = 0;
@@ -567,8 +561,6 @@
void setAutoLowLatencyMode(const sp<IBinder>& displayToken, bool on);
void setGameContentType(const sp<IBinder>& displayToken, bool on);
void setPowerMode(const sp<IBinder>& displayToken, int mode);
- status_t clearAnimationFrameStats();
- status_t getAnimationFrameStats(FrameStats* outStats) const;
status_t overrideHdrTypes(const sp<IBinder>& displayToken,
const std::vector<ui::Hdr>& hdrTypes);
status_t onPullAtom(const int32_t atomId, std::string* pulledData, bool* success);
@@ -953,11 +945,7 @@
/*
* Compositing
*/
- void postComposition();
-
- // Returns the composite-to-present latency of the latest presented frame.
- nsecs_t trackPresentLatency(nsecs_t compositeTime, std::shared_ptr<FenceTime> presentFenceTime);
-
+ void postComposition() REQUIRES(kMainThreadContext);
void postFrame() REQUIRES(kMainThreadContext);
/*
@@ -1134,7 +1122,6 @@
State mCurrentState{LayerVector::StateSet::Current};
std::atomic<int32_t> mTransactionFlags = 0;
std::vector<std::shared_ptr<CountDownLatch>> mTransactionCommittedSignals;
- bool mAnimTransactionPending = false;
std::atomic<uint32_t> mUniqueTransactionId = 1;
SortedVector<sp<Layer>> mLayersPendingRemoval;
@@ -1182,8 +1169,6 @@
bool mSomeDataspaceChanged = false;
bool mForceTransactionDisplayChange = false;
- bool mAnimCompositionPending = false;
-
// Tracks layers that have pending frames which are candidates for being
// latched.
std::unordered_set<sp<Layer>, SpHash<Layer>> mLayersWithQueuedFrames;
@@ -1252,9 +1237,6 @@
TransactionCallbackInvoker mTransactionCallbackInvoker;
- // Thread-safe.
- FrameTracker mAnimFrameTracker;
-
// We maintain a pool of pre-generated texture names to hand out to avoid
// layer creation needing to run on the main thread (which it would
// otherwise need to do to access RenderEngine).
@@ -1325,6 +1307,7 @@
sp<VsyncModulator> mVsyncModulator;
std::unique_ptr<scheduler::RefreshRateStats> mRefreshRateStats;
+ scheduler::PresentLatencyTracker mPresentLatencyTracker GUARDED_BY(kMainThreadContext);
struct FenceWithFenceTime {
sp<Fence> fence = Fence::NO_FENCE;
@@ -1416,6 +1399,8 @@
bool early = false;
} mPowerHintSessionMode;
+ void startPowerHintSession() const;
+
nsecs_t mAnimationTransactionTimeout = s2ns(5);
friend class SurfaceComposerAIDL;
@@ -1459,8 +1444,15 @@
binder::Status captureDisplayById(int64_t, const sp<IScreenCaptureListener>&) override;
binder::Status captureLayers(const LayerCaptureArgs&,
const sp<IScreenCaptureListener>&) override;
- binder::Status clearAnimationFrameStats() override;
- binder::Status getAnimationFrameStats(gui::FrameStats* outStats) override;
+
+ // TODO(b/239076119): Remove deprecated AIDL.
+ [[deprecated]] binder::Status clearAnimationFrameStats() override {
+ return binder::Status::ok();
+ }
+ [[deprecated]] binder::Status getAnimationFrameStats(gui::FrameStats*) override {
+ return binder::Status::ok();
+ }
+
binder::Status overrideHdrTypes(const sp<IBinder>& display,
const std::vector<int32_t>& hdrTypes) override;
binder::Status onPullAtom(int32_t atomId, gui::PullAtomData* outPullData) override;
diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h
index 3338da0..b41d7b9 100644
--- a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h
@@ -570,7 +570,6 @@
mFlinger->setAutoLowLatencyMode(display, mFdp.ConsumeBool());
mFlinger->setGameContentType(display, mFdp.ConsumeBool());
mFlinger->setPowerMode(display, mFdp.ConsumeIntegral<int>());
- mFlinger->clearAnimationFrameStats();
overrideHdrTypes(display, &mFdp);
@@ -615,11 +614,9 @@
mFlinger->getMaxAcquiredBufferCountForCurrentRefreshRate(mFdp.ConsumeIntegral<uid_t>());
- mFlinger->postComposition();
-
- mFlinger->trackPresentLatency(mFdp.ConsumeIntegral<nsecs_t>(), FenceTime::NO_FENCE);
-
+ FTL_FAKE_GUARD(kMainThreadContext, mFlinger->postComposition());
FTL_FAKE_GUARD(kMainThreadContext, mFlinger->postFrame());
+
mFlinger->calculateExpectedPresentTime({});
mFlinger->enableHalVirtualDisplays(mFdp.ConsumeBool());
diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp b/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp
index 1a91a69..95219b5 100644
--- a/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp
@@ -19,6 +19,8 @@
#include <fuzzer/FuzzedDataProvider.h>
#include <processgroup/sched_policy.h>
+#include <scheduler/PresentLatencyTracker.h>
+
#include "Scheduler/DispSyncSource.h"
#include "Scheduler/OneShotTimer.h"
#include "Scheduler/VSyncDispatchTimerQueue.h"
@@ -58,6 +60,7 @@
private:
void fuzzRefreshRateSelection();
void fuzzRefreshRateConfigs();
+ void fuzzPresentLatencyTracker();
void fuzzVSyncModulator();
void fuzzVSyncPredictor();
void fuzzVSyncReactor();
@@ -382,9 +385,16 @@
refreshRateStats.setPowerMode(mFdp.PickValueInArray(kPowerModes));
}
+void SchedulerFuzzer::fuzzPresentLatencyTracker() {
+ scheduler::PresentLatencyTracker tracker;
+ tracker.trackPendingFrame(TimePoint::fromNs(mFdp.ConsumeIntegral<nsecs_t>()),
+ FenceTime::NO_FENCE);
+}
+
void SchedulerFuzzer::process() {
fuzzRefreshRateSelection();
fuzzRefreshRateConfigs();
+ fuzzPresentLatencyTracker();
fuzzVSyncModulator();
fuzzVSyncPredictor();
fuzzVSyncReactor();
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_OnInitializeDisplaysTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_OnInitializeDisplaysTest.cpp
index 3d576f4..98249bf 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_OnInitializeDisplaysTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_OnInitializeDisplaysTest.cpp
@@ -78,11 +78,6 @@
auto displayDevice = primaryDisplay.mutableDisplayDevice();
EXPECT_EQ(PowerMode::ON, displayDevice->getPowerMode());
- // The display refresh period should be set in the orientedDisplaySpaceRect tracker.
- FrameStats stats;
- mFlinger.getAnimFrameTracker().getStats(&stats);
- EXPECT_EQ(DEFAULT_VSYNC_PERIOD, stats.refreshPeriodNano);
-
// The display transaction needed flag should be set.
EXPECT_TRUE(hasTransactionFlagSet(eDisplayTransactionNeeded));
}
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index 60285f9..81e3f4a 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -481,7 +481,6 @@
* Read-only access to private data to assert post-conditions.
*/
- const auto& getAnimFrameTracker() const { return mFlinger->mAnimFrameTracker; }
const auto& getHasPoweredOff() const { return mFlinger->mHasPoweredOff; }
const auto& getVisibleRegionsDirty() const { return mFlinger->mVisibleRegionsDirty; }
auto& getHwComposer() const {
diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp
index 3818b25..0a33760 100644
--- a/vulkan/libvulkan/swapchain.cpp
+++ b/vulkan/libvulkan/swapchain.cpp
@@ -1234,11 +1234,15 @@
decodePixelFormat(native_pixel_format).c_str(), strerror(-err), err);
return VK_ERROR_SURFACE_LOST_KHR;
}
- err = native_window_set_buffers_data_space(window, native_dataspace);
- if (err != android::OK) {
- ALOGE("native_window_set_buffers_data_space(%d) failed: %s (%d)",
- native_dataspace, strerror(-err), err);
- return VK_ERROR_SURFACE_LOST_KHR;
+
+ /* Respect consumer default dataspace upon HAL_DATASPACE_ARBITRARY. */
+ if (native_dataspace != HAL_DATASPACE_ARBITRARY) {
+ err = native_window_set_buffers_data_space(window, native_dataspace);
+ if (err != android::OK) {
+ ALOGE("native_window_set_buffers_data_space(%d) failed: %s (%d)",
+ native_dataspace, strerror(-err), err);
+ return VK_ERROR_SURFACE_LOST_KHR;
+ }
}
err = native_window_set_buffers_dimensions(