Merge "SurfaceFlinger: fix refresh rate override when changing refresh rate" into sc-dev
diff --git a/cmds/installd/Android.bp b/cmds/installd/Android.bp
index 5c2211f..a546236 100644
--- a/cmds/installd/Android.bp
+++ b/cmds/installd/Android.bp
@@ -189,8 +189,8 @@
"liblog",
"libutils",
],
- static_libs: [
- "libapexd",
+ required: [
+ "apexd"
],
}
diff --git a/cmds/installd/otapreopt_chroot.cpp b/cmds/installd/otapreopt_chroot.cpp
index 379cf92..c04b558 100644
--- a/cmds/installd/otapreopt_chroot.cpp
+++ b/cmds/installd/otapreopt_chroot.cpp
@@ -20,6 +20,7 @@
#include <sys/stat.h>
#include <sys/wait.h>
+#include <array>
#include <fstream>
#include <sstream>
@@ -31,10 +32,6 @@
#include <libdm/dm.h>
#include <selinux/android.h>
-#include <apex_file_repository.h>
-#include <apex_constants.h>
-#include <apexd.h>
-
#include "installd_constants.h"
#include "otapreopt_utils.h"
@@ -64,47 +61,14 @@
}
}
-static std::vector<apex::ApexFile> ActivateApexPackages() {
- // The logic here is (partially) copied and adapted from
- // system/apex/apexd/apexd.cpp.
- //
- // Only scan the APEX directory under /system, /system_ext and /vendor (within the chroot dir).
- std::vector<std::string> apex_dirs{apex::kApexPackageSystemDir, apex::kApexPackageSystemExtDir,
- apex::kApexPackageVendorDir};
- // Initialize ApexFileRepository used internally in ScanPackagesDirAndActivate.
- // This is a quick fix to fix apex activation in otapreopt_chroot.
- apex::ApexFileRepository::GetInstance().AddPreInstalledApex(apex_dirs);
- for (const auto& dir : apex_dirs) {
- // Cast call to void to suppress warn_unused_result.
- static_cast<void>(apex::ScanPackagesDirAndActivate(dir.c_str()));
- }
- return apex::GetActivePackages();
-}
+static void ActivateApexPackages() {
+ std::vector<std::string> apexd_cmd{"/system/bin/apexd", "--otachroot-bootstrap"};
+ std::string apexd_error_msg;
-static void CreateApexInfoList(const std::vector<apex::ApexFile>& apex_files) {
- // Setup the apex-info-list.xml file
- const std::string apex_info_file = std::string(apex::kApexRoot) + "/" + apex::kApexInfoList;
- std::fstream xml(apex_info_file.c_str(), std::ios::out | std::ios::trunc);
- if (!xml.is_open()) {
- PLOG(ERROR) << "Failed to open " << apex_info_file;
- exit(216);
- }
-
- // we do not care about inactive apexs
- std::vector<apex::ApexFile> inactive;
- apex::CollectApexInfoList(xml, apex_files, inactive);
- xml.flush();
- xml.close();
-}
-
-static void DeactivateApexPackages(const std::vector<apex::ApexFile>& active_packages) {
- for (const apex::ApexFile& apex_file : active_packages) {
- const std::string& package_path = apex_file.GetPath();
- base::Result<void> status = apex::DeactivatePackage(package_path);
- if (!status.ok()) {
- LOG(ERROR) << "Failed to deactivate " << package_path << ": "
- << status.error();
- }
+ bool exec_result = Exec(apexd_cmd, &apexd_error_msg);
+ if (!exec_result) {
+ PLOG(ERROR) << "Running otapreopt failed: " << apexd_error_msg;
+ exit(220);
}
}
@@ -269,8 +233,7 @@
// Try to mount APEX packages in "/apex" in the chroot dir. We need at least
// the ART APEX, as it is required by otapreopt to run dex2oat.
- std::vector<apex::ApexFile> active_packages = ActivateApexPackages();
- CreateApexInfoList(active_packages);
+ ActivateApexPackages();
// Check that an ART APEX has been activated; clean up and exit
// early otherwise.
@@ -278,16 +241,27 @@
"com.android.art",
"com.android.runtime",
};
- for (std::string_view apex : kRequiredApexs) {
- if (std::none_of(active_packages.begin(), active_packages.end(),
- [&](const apex::ApexFile& package) {
- return package.GetManifest().name() == apex;
- })) {
- LOG(FATAL_WITHOUT_ABORT) << "No activated " << apex << " APEX package.";
- DeactivateApexPackages(active_packages);
- exit(217);
+ std::array<bool, arraysize(kRequiredApexs)> found_apexs{ false, false };
+ DIR* apex_dir = opendir("/apex");
+ if (apex_dir == nullptr) {
+ PLOG(ERROR) << "unable to open /apex";
+ exit(220);
+ }
+ for (dirent* entry = readdir(apex_dir); entry != nullptr; entry = readdir(apex_dir)) {
+ for (int i = 0; i < found_apexs.size(); i++) {
+ if (kRequiredApexs[i] == std::string_view(entry->d_name)) {
+ found_apexs[i] = true;
+ break;
+ }
}
}
+ closedir(apex_dir);
+ auto it = std::find(found_apexs.cbegin(), found_apexs.cend(), false);
+ if (it != found_apexs.cend()) {
+ LOG(ERROR) << "No activated " << kRequiredApexs[std::distance(found_apexs.cbegin(), it)]
+ << " package!";
+ exit(221);
+ }
// Setup /linkerconfig. Doing it after the chroot means it doesn't need its own category
if (selinux_android_restorecon("/linkerconfig", 0) < 0) {
@@ -323,9 +297,6 @@
LOG(ERROR) << "Running otapreopt failed: " << error_msg;
}
- // Tear down the work down by the apexd logic. (i.e. deactivate packages).
- DeactivateApexPackages(active_packages);
-
if (!exec_result) {
exit(213);
}
diff --git a/cmds/installd/tests/installd_dexopt_test.cpp b/cmds/installd/tests/installd_dexopt_test.cpp
index fbf1e0c..e272025 100644
--- a/cmds/installd/tests/installd_dexopt_test.cpp
+++ b/cmds/installd/tests/installd_dexopt_test.cpp
@@ -351,7 +351,7 @@
uid = kTestAppUid;
}
if (class_loader_context == nullptr) {
- class_loader_context = "&";
+ class_loader_context = "PCL[]";
}
int32_t dexopt_needed = 0; // does not matter;
std::optional<std::string> out_path; // does not matter
@@ -478,7 +478,7 @@
bool should_binder_call_succeed,
/*out */ binder::Status* binder_result) {
std::optional<std::string> out_path = oat_dir ? std::make_optional<std::string>(oat_dir) : std::nullopt;
- std::string class_loader_context = "&";
+ std::string class_loader_context = "PCL[]";
int32_t target_sdk_version = 0; // default
std::string profile_name = "primary.prof";
std::optional<std::string> dm_path_opt = dm_path ? std::make_optional<std::string>(dm_path) : std::nullopt;
diff --git a/include/android/surface_control.h b/include/android/surface_control.h
index eb9c528..91726cd 100644
--- a/include/android/surface_control.h
+++ b/include/android/surface_control.h
@@ -286,6 +286,9 @@
* The frameworks takes ownership of the \a acquire_fence_fd passed and is responsible
* for closing it.
*
+ * Note that the buffer must be allocated with AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE
+ * as the surface control might be composited using the GPU.
+ *
* Available since API level 29.
*/
void ASurfaceTransaction_setBuffer(ASurfaceTransaction* transaction,
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
index 8854ba2..144dbd3 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -73,6 +73,7 @@
"PermissionController.cpp",
"ProcessInfoService.cpp",
"IpPrefix.cpp",
+ ":activity_manager_procstate_aidl",
]
cc_library {
@@ -130,8 +131,8 @@
"Status.cpp",
"TextOutput.cpp",
"Utils.cpp",
+ ":packagemanager_aidl",
":libbinder_aidl",
- ":activity_manager_procstate_aidl",
],
target: {
@@ -232,9 +233,6 @@
filegroup {
name: "libbinder_aidl",
srcs: [
- "aidl/android/content/pm/IPackageChangeObserver.aidl",
- "aidl/android/content/pm/IPackageManagerNative.aidl",
- "aidl/android/content/pm/PackageChangeEvent.aidl",
"aidl/android/os/IClientCallback.aidl",
"aidl/android/os/IServiceCallback.aidl",
"aidl/android/os/IServiceManager.aidl",
@@ -243,6 +241,16 @@
path: "aidl",
}
+filegroup {
+ name: "packagemanager_aidl",
+ srcs: [
+ "aidl/android/content/pm/IPackageChangeObserver.aidl",
+ "aidl/android/content/pm/IPackageManagerNative.aidl",
+ "aidl/android/content/pm/PackageChangeEvent.aidl",
+ ],
+ path: "aidl",
+}
+
aidl_interface {
name: "libbinder_aidl_test_stub",
unstable: true,
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index 6f34159..7fedba2 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -41,11 +41,12 @@
#include <binder/TextOutput.h>
#include <cutils/ashmem.h>
+#include <cutils/compiler.h>
#include <utils/Flattenable.h>
#include <utils/Log.h>
-#include <utils/misc.h>
-#include <utils/String8.h>
#include <utils/String16.h>
+#include <utils/String8.h>
+#include <utils/misc.h>
#include <private/binder/binder_module.h>
#include "RpcState.h"
@@ -590,12 +591,14 @@
}
status_t Parcel::writeInterfaceToken(const char16_t* str, size_t len) {
- const IPCThreadState* threadState = IPCThreadState::self();
- writeInt32(threadState->getStrictModePolicy() | STRICT_MODE_PENALTY_GATHER);
- updateWorkSourceRequestHeaderPosition();
- writeInt32(threadState->shouldPropagateWorkSource() ?
- threadState->getCallingWorkSourceUid() : IPCThreadState::kUnsetWorkSource);
- writeInt32(kHeader);
+ if (CC_LIKELY(!isForRpc())) {
+ const IPCThreadState* threadState = IPCThreadState::self();
+ writeInt32(threadState->getStrictModePolicy() | STRICT_MODE_PENALTY_GATHER);
+ updateWorkSourceRequestHeaderPosition();
+ writeInt32(threadState->shouldPropagateWorkSource() ? threadState->getCallingWorkSourceUid()
+ : IPCThreadState::kUnsetWorkSource);
+ writeInt32(kHeader);
+ }
// currently the interface identification token is just its name as a string
return writeString16(str, len);
@@ -642,31 +645,34 @@
size_t len,
IPCThreadState* threadState) const
{
- // StrictModePolicy.
- int32_t strictPolicy = readInt32();
- if (threadState == nullptr) {
- threadState = IPCThreadState::self();
+ if (CC_LIKELY(!isForRpc())) {
+ // StrictModePolicy.
+ int32_t strictPolicy = readInt32();
+ if (threadState == nullptr) {
+ threadState = IPCThreadState::self();
+ }
+ if ((threadState->getLastTransactionBinderFlags() & IBinder::FLAG_ONEWAY) != 0) {
+ // For one-way calls, the callee is running entirely
+ // disconnected from the caller, so disable StrictMode entirely.
+ // Not only does disk/network usage not impact the caller, but
+ // there's no way to communicate back violations anyway.
+ threadState->setStrictModePolicy(0);
+ } else {
+ threadState->setStrictModePolicy(strictPolicy);
+ }
+ // WorkSource.
+ updateWorkSourceRequestHeaderPosition();
+ int32_t workSource = readInt32();
+ threadState->setCallingWorkSourceUidWithoutPropagation(workSource);
+ // vendor header
+ int32_t header = readInt32();
+ if (header != kHeader) {
+ ALOGE("Expecting header 0x%x but found 0x%x. Mixing copies of libbinder?", kHeader,
+ header);
+ return false;
+ }
}
- if ((threadState->getLastTransactionBinderFlags() &
- IBinder::FLAG_ONEWAY) != 0) {
- // For one-way calls, the callee is running entirely
- // disconnected from the caller, so disable StrictMode entirely.
- // Not only does disk/network usage not impact the caller, but
- // there's no way to commuicate back any violations anyway.
- threadState->setStrictModePolicy(0);
- } else {
- threadState->setStrictModePolicy(strictPolicy);
- }
- // WorkSource.
- updateWorkSourceRequestHeaderPosition();
- int32_t workSource = readInt32();
- threadState->setCallingWorkSourceUidWithoutPropagation(workSource);
- // vendor header
- int32_t header = readInt32();
- if (header != kHeader) {
- ALOGE("Expecting header 0x%x but found 0x%x. Mixing copies of libbinder?", kHeader, header);
- return false;
- }
+
// Interface descriptor.
size_t parcel_interface_len;
const char16_t* parcel_interface = readString16Inplace(&parcel_interface_len);
diff --git a/libs/binder/TEST_MAPPING b/libs/binder/TEST_MAPPING
index 7490b88..b58d919 100644
--- a/libs/binder/TEST_MAPPING
+++ b/libs/binder/TEST_MAPPING
@@ -43,6 +43,9 @@
"name": "aidl_integration_test"
},
{
+ "name": "memunreachable_binder_test"
+ },
+ {
"name": "libbinderthreadstateutils_test"
},
{
diff --git a/libs/binder/ndk/include_ndk/android/binder_ibinder.h b/libs/binder/ndk/include_ndk/android/binder_ibinder.h
index a44c261..8941e49 100644
--- a/libs/binder/ndk/include_ndk/android/binder_ibinder.h
+++ b/libs/binder/ndk/include_ndk/android/binder_ibinder.h
@@ -36,11 +36,6 @@
__BEGIN_DECLS
-#ifndef __ANDROID_API__
-#error Android builds must be compiled against a specific API. If this is an \
- android platform host build, you must use libbinder_ndk_host_user.
-#endif
-
typedef uint32_t binder_flags_t;
enum {
/**
diff --git a/libs/binder/ndk/include_ndk/android/binder_status.h b/libs/binder/ndk/include_ndk/android/binder_status.h
index 05b25e7..b4dc08a 100644
--- a/libs/binder/ndk/include_ndk/android/binder_status.h
+++ b/libs/binder/ndk/include_ndk/android/binder_status.h
@@ -32,6 +32,16 @@
__BEGIN_DECLS
+#ifndef __ANDROID_API__
+#error Android builds must be compiled against a specific API. If this is an \
+ android platform host build, you must use libbinder_ndk_host_user.
+#endif
+
+/**
+ * Low-level status types for use in binder. This is the least preferable way to
+ * return an error for binder services (where binder_exception_t should be used,
+ * particularly EX_SERVICE_SPECIFIC).
+ */
enum {
STATUS_OK = 0,
@@ -62,6 +72,10 @@
*/
typedef int32_t binder_status_t;
+/**
+ * Top level exceptions types for Android binder errors, mapping to Java
+ * exceptions. Also see Parcel.java.
+ */
enum {
EX_NONE = 0,
EX_SECURITY = -1,
@@ -170,7 +184,8 @@
/**
* New status with binder_status_t. This is typically for low level failures when a binder_status_t
* is returned by an API on AIBinder or AParcel, and that is to be returned from a method returning
- * an AStatus instance.
+ * an AStatus instance. This is the least preferable way to return errors.
+ * Prefer exceptions (particularly service-specific errors) when possible.
*
* Available since API level 29.
*
diff --git a/libs/binder/ndk/include_platform/android/binder_manager.h b/libs/binder/ndk/include_platform/android/binder_manager.h
index 5df0012..5516914 100644
--- a/libs/binder/ndk/include_platform/android/binder_manager.h
+++ b/libs/binder/ndk/include_platform/android/binder_manager.h
@@ -26,6 +26,9 @@
* This registers the service with the default service manager under this instance name. This does
* not take ownership of binder.
*
+ * WARNING: when using this API across an APEX boundary, do not use with unstable
+ * AIDL services. TODO(b/139325195)
+ *
* \param binder object to register globally with the service manager.
* \param instance identifier of the service. This will be used to lookup the service.
*
@@ -39,6 +42,9 @@
* service is not available This also implicitly calls AIBinder_incStrong (so the caller of this
* function is responsible for calling AIBinder_decStrong).
*
+ * WARNING: when using this API across an APEX boundary, do not use with unstable
+ * AIDL services. TODO(b/139325195)
+ *
* \param instance identifier of the service used to lookup the service.
*/
__attribute__((warn_unused_result)) AIBinder* AServiceManager_checkService(const char* instance);
@@ -48,6 +54,9 @@
* it. This also implicitly calls AIBinder_incStrong (so the caller of this function is responsible
* for calling AIBinder_decStrong).
*
+ * WARNING: when using this API across an APEX boundary, do not use with unstable
+ * AIDL services. TODO(b/139325195)
+ *
* \param instance identifier of the service used to lookup the service.
*/
__attribute__((warn_unused_result)) AIBinder* AServiceManager_getService(const char* instance);
@@ -78,6 +87,9 @@
* This also implicitly calls AIBinder_incStrong (so the caller of this function is responsible
* for calling AIBinder_decStrong).
*
+ * WARNING: when using this API across an APEX boundary, do not use with unstable
+ * AIDL services. TODO(b/139325195)
+ *
* \param instance identifier of the service used to lookup the service.
*
* \return service if registered, null if not.
diff --git a/libs/binder/ndk/include_platform/android/binder_parcel_platform.h b/libs/binder/ndk/include_platform/android/binder_parcel_platform.h
index d54c1a1..6372449 100644
--- a/libs/binder/ndk/include_platform/android/binder_parcel_platform.h
+++ b/libs/binder/ndk/include_platform/android/binder_parcel_platform.h
@@ -20,9 +20,7 @@
__BEGIN_DECLS
-#if defined(__ANDROID_APEX__) || defined(__ANDROID_VNDK__)
-#error this is only for platform code
-#endif
+#if !defined(__ANDROID_APEX__) && !defined(__ANDROID_VNDK__)
/**
* Gets whether or not FDs are allowed by this AParcel
@@ -33,6 +31,9 @@
*/
bool AParcel_getAllowFds(const AParcel*);
+#endif
+
+#if !defined(__ANDROID_APEX__)
/**
* Data written to the parcel will be zero'd before being deleted or realloced.
*
@@ -43,5 +44,6 @@
* \param parcel The parcel to clear associated data from.
*/
void AParcel_markSensitive(const AParcel* parcel);
+#endif
__END_DECLS
diff --git a/libs/binder/ndk/include_platform/android/binder_stability.h b/libs/binder/ndk/include_platform/android/binder_stability.h
index 44ed48f..ce7255e 100644
--- a/libs/binder/ndk/include_platform/android/binder_stability.h
+++ b/libs/binder/ndk/include_platform/android/binder_stability.h
@@ -30,9 +30,7 @@
FLAG_PRIVATE_VENDOR = 0x10000000,
};
-// TODO(b/180646847): __ANDROID_APEX__ here is what allows product partition to
-// talk to system.
-#if defined(__ANDROID_VNDK__) && !defined(__ANDROID_APEX__)
+#if defined(__ANDROID_VENDOR__)
enum {
FLAG_PRIVATE_LOCAL = FLAG_PRIVATE_VENDOR,
@@ -47,7 +45,7 @@
AIBinder_markVendorStability(binder);
}
-#else // defined(__ANDROID_VNDK__) && !defined(__ANDROID_APEX__)
+#else // defined(__ANDROID_VENDOR__)
enum {
FLAG_PRIVATE_LOCAL = 0,
@@ -64,7 +62,7 @@
AIBinder_markSystemStability(binder);
}
-#endif // defined(__ANDROID_VNDK__) && !defined(__ANDROID_APEX__)
+#endif // defined(__ANDROID_VENDOR__)
/**
* This interface has system<->vendor stability
diff --git a/libs/binder/ndk/libbinder_ndk.map.txt b/libs/binder/ndk/libbinder_ndk.map.txt
index 8d08275..f1db653 100644
--- a/libs/binder/ndk/libbinder_ndk.map.txt
+++ b/libs/binder/ndk/libbinder_ndk.map.txt
@@ -117,6 +117,7 @@
ABinderProcess_setupPolling; # apex
AIBinder_getCallingSid; # apex
AIBinder_setRequestingSid; # apex
+ AParcel_markSensitive; # llndk
AServiceManager_isDeclared; # apex llndk
AServiceManager_forEachDeclaredInstance; # apex llndk
AServiceManager_registerLazyService; # llndk
@@ -139,7 +140,6 @@
LIBBINDER_NDK_PLATFORM {
global:
AParcel_getAllowFds;
- AParcel_markSensitive;
extern "C++" {
AIBinder_fromPlatformBinder*;
AIBinder_toPlatformBinder*;
diff --git a/libs/binder/rust/src/binder.rs b/libs/binder/rust/src/binder.rs
index 3899d47..321b422 100644
--- a/libs/binder/rust/src/binder.rs
+++ b/libs/binder/rust/src/binder.rs
@@ -56,6 +56,26 @@
}
}
+/// Interface stability promise
+///
+/// An interface can promise to be a stable vendor interface ([`Vintf`]), or
+/// makes no stability guarantees ([`Local`]). [`Local`] is
+/// currently the default stability.
+pub enum Stability {
+ /// Default stability, visible to other modules in the same compilation
+ /// context (e.g. modules on system.img)
+ Local,
+
+ /// A Vendor Interface Object, which promises to be stable
+ Vintf,
+}
+
+impl Default for Stability {
+ fn default() -> Self {
+ Stability::Local
+ }
+}
+
/// A local service that can be remotable via Binder.
///
/// An object that implement this interface made be made into a Binder service
@@ -94,6 +114,8 @@
pub const FLAG_ONEWAY: TransactionFlags = sys::FLAG_ONEWAY;
/// Corresponds to TF_CLEAR_BUF -- clear transaction buffers after call is made.
pub const FLAG_CLEAR_BUF: TransactionFlags = sys::FLAG_CLEAR_BUF;
+/// Set to the vendor flag if we are building for the VNDK, 0 otherwise
+pub const FLAG_PRIVATE_LOCAL: TransactionFlags = sys::FLAG_PRIVATE_LOCAL;
/// Internal interface of binder local or remote objects for making
/// transactions.
@@ -602,6 +624,23 @@
$interface[$descriptor] {
native: $native($on_transact),
proxy: $proxy {},
+ stability: $crate::Stability::default(),
+ }
+ }
+ };
+
+ {
+ $interface:path[$descriptor:expr] {
+ native: $native:ident($on_transact:path),
+ proxy: $proxy:ident,
+ stability: $stability:expr,
+ }
+ } => {
+ $crate::declare_binder_interface! {
+ $interface[$descriptor] {
+ native: $native($on_transact),
+ proxy: $proxy {},
+ stability: $stability,
}
}
};
@@ -616,12 +655,33 @@
} => {
$crate::declare_binder_interface! {
$interface[$descriptor] {
+ native: $native($on_transact),
+ proxy: $proxy {
+ $($fname: $fty = $finit),*
+ },
+ stability: $crate::Stability::default(),
+ }
+ }
+ };
+
+ {
+ $interface:path[$descriptor:expr] {
+ native: $native:ident($on_transact:path),
+ proxy: $proxy:ident {
+ $($fname:ident: $fty:ty = $finit:expr),*
+ },
+ stability: $stability:expr,
+ }
+ } => {
+ $crate::declare_binder_interface! {
+ $interface[$descriptor] {
@doc[concat!("A binder [`Remotable`]($crate::Remotable) that holds an [`", stringify!($interface), "`] object.")]
native: $native($on_transact),
@doc[concat!("A binder [`Proxy`]($crate::Proxy) that holds an [`", stringify!($interface), "`] remote interface.")]
proxy: $proxy {
$($fname: $fty = $finit),*
},
+ stability: $stability,
}
}
};
@@ -635,6 +695,8 @@
proxy: $proxy:ident {
$($fname:ident: $fty:ty = $finit:expr),*
},
+
+ stability: $stability:expr,
}
} => {
#[doc = $proxy_doc]
@@ -669,7 +731,7 @@
impl $native {
/// Create a new binder service.
pub fn new_binder<T: $interface + Sync + Send + 'static>(inner: T) -> $crate::Strong<dyn $interface> {
- let binder = $crate::Binder::new($native(Box::new(inner)));
+ let binder = $crate::Binder::new_with_stability($native(Box::new(inner)), $stability);
$crate::Strong::new(Box::new(binder))
}
}
diff --git a/libs/binder/rust/src/lib.rs b/libs/binder/rust/src/lib.rs
index 5bbd2a3..30928a5 100644
--- a/libs/binder/rust/src/lib.rs
+++ b/libs/binder/rust/src/lib.rs
@@ -107,8 +107,9 @@
pub mod parcel;
pub use crate::binder::{
- FromIBinder, IBinder, IBinderInternal, Interface, InterfaceClass, Remotable, Strong,
- TransactionCode, TransactionFlags, Weak, FIRST_CALL_TRANSACTION, FLAG_CLEAR_BUF, FLAG_ONEWAY,
+ FromIBinder, IBinder, IBinderInternal, Interface, InterfaceClass, Remotable,
+ Stability, Strong, TransactionCode, TransactionFlags, Weak,
+ FIRST_CALL_TRANSACTION, FLAG_CLEAR_BUF, FLAG_ONEWAY, FLAG_PRIVATE_LOCAL,
LAST_CALL_TRANSACTION,
};
pub use error::{status_t, ExceptionCode, Result, Status, StatusCode};
diff --git a/libs/binder/rust/src/native.rs b/libs/binder/rust/src/native.rs
index 185645e..3b3fd08 100644
--- a/libs/binder/rust/src/native.rs
+++ b/libs/binder/rust/src/native.rs
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-use crate::binder::{AsNative, Interface, InterfaceClassMethods, Remotable, TransactionCode};
+use crate::binder::{AsNative, Interface, InterfaceClassMethods, Remotable, Stability, TransactionCode};
use crate::error::{status_result, status_t, Result, StatusCode};
use crate::parcel::{Parcel, Serialize};
use crate::proxy::SpIBinder;
@@ -49,11 +49,19 @@
unsafe impl<T: Remotable> Send for Binder<T> {}
impl<T: Remotable> Binder<T> {
- /// Create a new Binder remotable object.
+ /// Create a new Binder remotable object with default stability
///
/// This moves the `rust_object` into an owned [`Box`] and Binder will
/// manage its lifetime.
pub fn new(rust_object: T) -> Binder<T> {
+ Self::new_with_stability(rust_object, Stability::default())
+ }
+
+ /// Create a new Binder remotable object with the given stability
+ ///
+ /// This moves the `rust_object` into an owned [`Box`] and Binder will
+ /// manage its lifetime.
+ pub fn new_with_stability(rust_object: T, stability: Stability) -> Binder<T> {
let class = T::get_class();
let rust_object = Box::into_raw(Box::new(rust_object));
let ibinder = unsafe {
@@ -65,10 +73,12 @@
// ends.
sys::AIBinder_new(class.into(), rust_object as *mut c_void)
};
- Binder {
+ let mut binder = Binder {
ibinder,
rust_object,
- }
+ };
+ binder.mark_stability(stability);
+ binder
}
/// Set the extension of a binder interface. This allows a downstream
@@ -161,6 +171,42 @@
pub fn get_descriptor() -> &'static str {
T::get_descriptor()
}
+
+ /// Mark this binder object with the given stability guarantee
+ fn mark_stability(&mut self, stability: Stability) {
+ match stability {
+ Stability::Local => self.mark_local_stability(),
+ Stability::Vintf => {
+ unsafe {
+ // Safety: Self always contains a valid `AIBinder` pointer, so
+ // we can always call this C API safely.
+ sys::AIBinder_markVintfStability(self.as_native_mut());
+ }
+ }
+ }
+ }
+
+ /// Mark this binder object with local stability, which is vendor if we are
+ /// building for the VNDK and system otherwise.
+ #[cfg(vendor_ndk)]
+ fn mark_local_stability(&mut self) {
+ unsafe {
+ // Safety: Self always contains a valid `AIBinder` pointer, so
+ // we can always call this C API safely.
+ sys::AIBinder_markVendorStability(self.as_native_mut());
+ }
+ }
+
+ /// Mark this binder object with local stability, which is vendor if we are
+ /// building for the VNDK and system otherwise.
+ #[cfg(not(vendor_ndk))]
+ fn mark_local_stability(&mut self) {
+ unsafe {
+ // Safety: Self always contains a valid `AIBinder` pointer, so
+ // we can always call this C API safely.
+ sys::AIBinder_markSystemStability(self.as_native_mut());
+ }
+ }
}
impl<T: Remotable> Interface for Binder<T> {
diff --git a/libs/binder/rust/sys/BinderBindings.hpp b/libs/binder/rust/sys/BinderBindings.hpp
index ef142b5..65fa2ca 100644
--- a/libs/binder/rust/sys/BinderBindings.hpp
+++ b/libs/binder/rust/sys/BinderBindings.hpp
@@ -21,6 +21,7 @@
#include <android/binder_parcel_platform.h>
#include <android/binder_process.h>
#include <android/binder_shell.h>
+#include <android/binder_stability.h>
#include <android/binder_status.h>
namespace android {
@@ -80,6 +81,7 @@
enum {
FLAG_ONEWAY = FLAG_ONEWAY,
FLAG_CLEAR_BUF = FLAG_CLEAR_BUF,
+ FLAG_PRIVATE_LOCAL = FLAG_PRIVATE_LOCAL,
};
} // namespace consts
diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp
index 8da97bb..1976b49 100644
--- a/libs/gui/BLASTBufferQueue.cpp
+++ b/libs/gui/BLASTBufferQueue.cpp
@@ -606,7 +606,9 @@
// Apply the transaction since we have already acquired the desired frame.
t->apply();
} else {
- mPendingTransactions.emplace_back(frameNumber, std::move(*t));
+ mPendingTransactions.emplace_back(frameNumber, *t);
+ // Clear the transaction so it can't be applied elsewhere.
+ t->clear();
}
}
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index ceab6ec..97f8f47 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -477,6 +477,26 @@
return reply.readInt32();
}
+ virtual status_t overrideHdrTypes(const sp<IBinder>& display,
+ const std::vector<ui::Hdr>& hdrTypes) {
+ Parcel data, reply;
+ SAFE_PARCEL(data.writeInterfaceToken, ISurfaceComposer::getInterfaceDescriptor());
+ SAFE_PARCEL(data.writeStrongBinder, display);
+
+ std::vector<int32_t> hdrTypesVector;
+ for (ui::Hdr i : hdrTypes) {
+ hdrTypesVector.push_back(static_cast<int32_t>(i));
+ }
+ SAFE_PARCEL(data.writeInt32Vector, hdrTypesVector);
+
+ status_t result = remote()->transact(BnSurfaceComposer::OVERRIDE_HDR_TYPES, data, &reply);
+ if (result != NO_ERROR) {
+ ALOGE("overrideHdrTypes failed to transact: %d", result);
+ return result;
+ }
+ return result;
+ }
+
status_t enableVSyncInjections(bool enable) override {
Parcel data, reply;
status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
@@ -1963,6 +1983,20 @@
SAFE_PARCEL(reply->writeInt32, extraBuffers);
return NO_ERROR;
}
+ case OVERRIDE_HDR_TYPES: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
+ sp<IBinder> display = nullptr;
+ SAFE_PARCEL(data.readStrongBinder, &display);
+
+ std::vector<int32_t> hdrTypes;
+ SAFE_PARCEL(data.readInt32Vector, &hdrTypes);
+
+ std::vector<ui::Hdr> hdrTypesVector;
+ for (int i : hdrTypes) {
+ hdrTypesVector.push_back(static_cast<ui::Hdr>(i));
+ }
+ return overrideHdrTypes(display, hdrTypesVector);
+ }
default: {
return BBinder::onTransact(code, data, reply, flags);
}
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index d7b2c2e..0b01084 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -1985,6 +1985,11 @@
return ComposerService::getComposerService()->getAnimationFrameStats(outStats);
}
+status_t SurfaceComposerClient::overrideHdrTypes(const sp<IBinder>& display,
+ const std::vector<ui::Hdr>& hdrTypes) {
+ return ComposerService::getComposerService()->overrideHdrTypes(display, hdrTypes);
+}
+
status_t SurfaceComposerClient::getDisplayedContentSamplingAttributes(const sp<IBinder>& display,
ui::PixelFormat* outFormat,
ui::Dataspace* outDataspace,
diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
index 35990d1..9f9ca74 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -267,6 +267,13 @@
*/
virtual status_t getAnimationFrameStats(FrameStats* outStats) const = 0;
+ /* Overrides the supported HDR modes for the given display device.
+ *
+ * Requires the ACCESS_SURFACE_FLINGER permission.
+ */
+ virtual status_t overrideHdrTypes(const sp<IBinder>& display,
+ const std::vector<ui::Hdr>& hdrTypes) = 0;
+
virtual status_t enableVSyncInjections(bool enable) = 0;
virtual status_t injectVSync(nsecs_t when) = 0;
@@ -570,6 +577,7 @@
GET_DYNAMIC_DISPLAY_INFO,
ADD_FPS_LISTENER,
REMOVE_FPS_LISTENER,
+ OVERRIDE_HDR_TYPES,
// Always append new enum to the end.
};
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index a643e9e..c38375c 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -572,6 +572,9 @@
static status_t clearAnimationFrameStats();
static status_t getAnimationFrameStats(FrameStats* outStats);
+ static status_t overrideHdrTypes(const sp<IBinder>& display,
+ const std::vector<ui::Hdr>& hdrTypes);
+
static void setDisplayProjection(const sp<IBinder>& token, ui::Rotation orientation,
const Rect& layerStackRect, const Rect& displayRect);
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index 8d7f8c9..5ac3f19 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -772,6 +772,10 @@
status_t getAnimationFrameStats(FrameStats* /*outStats*/) const override {
return NO_ERROR;
}
+ status_t overrideHdrTypes(const sp<IBinder>& /*display*/,
+ const std::vector<ui::Hdr>& /*hdrTypes*/) override {
+ return NO_ERROR;
+ }
status_t enableVSyncInjections(bool /*enable*/) override {
return NO_ERROR;
}
diff --git a/libs/renderengine/skia/AutoBackendTexture.cpp b/libs/renderengine/skia/AutoBackendTexture.cpp
index c535597..ae3d88a 100644
--- a/libs/renderengine/skia/AutoBackendTexture.cpp
+++ b/libs/renderengine/skia/AutoBackendTexture.cpp
@@ -28,19 +28,19 @@
namespace renderengine {
namespace skia {
-AutoBackendTexture::AutoBackendTexture(GrDirectContext* context, AHardwareBuffer* buffer,
- bool isRender) {
+AutoBackendTexture::AutoBackendTexture(GrDirectContext* context, AHardwareBuffer* buffer) {
ATRACE_CALL();
AHardwareBuffer_Desc desc;
AHardwareBuffer_describe(buffer, &desc);
- bool createProtectedImage = 0 != (desc.usage & AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT);
+ const bool createProtectedImage = 0 != (desc.usage & AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT);
+ const bool isRenderable = 0 != (desc.usage & AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER);
GrBackendFormat backendFormat =
GrAHardwareBufferUtils::GetBackendFormat(context, buffer, desc.format, false);
mBackendTexture =
GrAHardwareBufferUtils::MakeBackendTexture(context, buffer, desc.width, desc.height,
&mDeleteProc, &mUpdateProc, &mImageCtx,
createProtectedImage, backendFormat,
- isRender);
+ isRenderable);
mColorType = GrAHardwareBufferUtils::GetSkColorTypeFromBufferFormat(desc.format);
}
diff --git a/libs/renderengine/skia/AutoBackendTexture.h b/libs/renderengine/skia/AutoBackendTexture.h
index bb75878..a6f73db 100644
--- a/libs/renderengine/skia/AutoBackendTexture.h
+++ b/libs/renderengine/skia/AutoBackendTexture.h
@@ -69,7 +69,7 @@
};
// Creates a GrBackendTexture whose contents come from the provided buffer.
- AutoBackendTexture(GrDirectContext* context, AHardwareBuffer* buffer, bool isRender);
+ AutoBackendTexture(GrDirectContext* context, AHardwareBuffer* buffer);
void ref() { mUsageCount++; }
diff --git a/libs/renderengine/skia/Cache.cpp b/libs/renderengine/skia/Cache.cpp
index f8dd7f5..69c6a09 100644
--- a/libs/renderengine/skia/Cache.cpp
+++ b/libs/renderengine/skia/Cache.cpp
@@ -28,8 +28,11 @@
namespace android::renderengine::skia {
-static void drawShadowLayer(SkiaRenderEngine* renderengine, const DisplaySettings& display,
- sp<GraphicBuffer> dstBuffer) {
+// Warming shader cache, not framebuffer cache.
+constexpr bool kUseFrameBufferCache = false;
+
+static void drawShadowLayers(SkiaRenderEngine* renderengine, const DisplaySettings& display,
+ sp<GraphicBuffer> dstBuffer) {
// Somewhat arbitrary dimensions, but on screen and slightly shorter, based
// on actual use.
FloatRect rect(0, 0, display.physicalDisplay.width(), display.physicalDisplay.height() - 30);
@@ -39,6 +42,7 @@
.boundaries = rect,
.roundedCornersCrop = rect,
},
+ // drawShadow ignores alpha
.shadow =
ShadowSettings{
.ambientColor = vec4(0, 0, 0, 0.00935997f),
@@ -61,9 +65,8 @@
0.f, 0.f, 1.f, 0.f,
167.355743f, 1852.257812f, 0.f, 1.f) }) {
layer.geometry.positionTransform = transform;
- renderengine->drawLayers(display, layers, dstBuffer, false /* useFrameBufferCache*/,
+ renderengine->drawLayers(display, layers, dstBuffer, kUseFrameBufferCache,
base::unique_fd(), nullptr);
- renderengine->assertShadersCompiled(identity ? 1 : 2);
identity = false;
}
}
@@ -76,14 +79,6 @@
.geometry =
Geometry{
.boundaries = rect,
- // This matrix is based on actual data seen when opening the dialer.
- // What seems to be important in matching the actual use cases are:
- // - it is not identity
- // - the layer will be drawn (not clipped out etc)
- .positionTransform = mat4(.19f, .0f, .0f, .0f,
- .0f, .19f, .0f, .0f,
- .0f, .0f, 1.f, .0f,
- 169.f, 1527.f, .0f, 1.f),
.roundedCornersCrop = rect,
},
.source = PixelSource{.buffer =
@@ -94,27 +89,60 @@
}},
};
+ // This matrix is based on actual data seen when opening the dialer.
+ // translate and scale creates new shaders when combined with rounded corners
+ // clang-format off
+ auto scale_and_translate = mat4(.19f, .0f, .0f, .0f,
+ .0f, .19f, .0f, .0f,
+ .0f, .0f, 1.f, .0f,
+ 169.f, 1527.f, .0f, 1.f);
+ // clang-format on
+
// Test both drawRect and drawRRect
auto layers = std::vector<const LayerSettings*>{&layer};
- for (float roundedCornersRadius : {0.0f, 500.f}) {
- layer.geometry.roundedCornersRadius = roundedCornersRadius;
- // No need to check UNKNOWN, which is treated as SRGB.
- for (auto dataspace : {ui::Dataspace::SRGB, ui::Dataspace::DISPLAY_P3}) {
- layer.sourceDataspace = dataspace;
- for (bool isOpaque : {true, false}) {
- layer.source.buffer.isOpaque = isOpaque;
- for (auto alpha : {half(.23999f), half(1.0f)}) {
- layer.alpha = alpha;
- renderengine->drawLayers(display, layers, dstBuffer,
- false /* useFrameBufferCache*/, base::unique_fd(),
- nullptr);
- renderengine->assertShadersCompiled(1);
+ for (auto transform : {mat4(), scale_and_translate}) {
+ layer.geometry.positionTransform = transform;
+ // fractional corner radius creates a shader that is used during home button swipe
+ for (float roundedCornersRadius : {0.0f, 0.05f, 500.f}) {
+ // roundedCornersCrop is always set, but it is this radius that triggers the behavior
+ layer.geometry.roundedCornersRadius = roundedCornersRadius;
+ // No need to check UNKNOWN, which is treated as SRGB.
+ for (auto dataspace : {ui::Dataspace::SRGB, ui::Dataspace::DISPLAY_P3}) {
+ layer.sourceDataspace = dataspace;
+ for (bool isOpaque : {true, false}) {
+ layer.source.buffer.isOpaque = isOpaque;
+ for (auto alpha : {half(.23999f), half(1.0f)}) {
+ layer.alpha = alpha;
+ renderengine->drawLayers(display, layers, dstBuffer, kUseFrameBufferCache,
+ base::unique_fd(), nullptr);
+ }
}
}
}
}
}
+static void drawSolidLayers(SkiaRenderEngine* renderengine, const DisplaySettings& display,
+ sp<GraphicBuffer> dstBuffer) {
+ const Rect& displayRect = display.physicalDisplay;
+ FloatRect rect(0, 0, displayRect.width(), displayRect.height());
+ LayerSettings layer{
+ .geometry =
+ Geometry{
+ .boundaries = rect,
+ },
+ .alpha = 1,
+ .source =
+ PixelSource{
+ .solidColor = half3(0.1f, 0.2f, 0.3f),
+ },
+ };
+
+ auto layers = std::vector<const LayerSettings*>{&layer};
+ renderengine->drawLayers(display, layers, dstBuffer, kUseFrameBufferCache, base::unique_fd(),
+ nullptr);
+}
+
void Cache::primeShaderCache(SkiaRenderEngine* renderengine) {
const nsecs_t timeBefore = systemTime();
// The dimensions should not matter, so long as we draw inside them.
@@ -133,14 +161,13 @@
usage, "primeShaderCache_dst");
// This buffer will be the source for the call to drawImageLayers. Draw
// something to it as a placeholder for what an app draws. We should draw
- // something, but the details are not important. We only need one version of
- // the shadow's SkSL, so draw it here, giving us both a placeholder image
- // and a chance to compile the shadow's SkSL.
+ // something, but the details are not important. Make use of the shadow layer drawing step
+ // to populate it.
sp<GraphicBuffer> srcBuffer =
new GraphicBuffer(displayRect.width(), displayRect.height(), PIXEL_FORMAT_RGBA_8888, 1,
usage, "drawImageLayer_src");
- drawShadowLayer(renderengine, display, srcBuffer);
-
+ drawSolidLayers(renderengine, display, dstBuffer);
+ drawShadowLayers(renderengine, display, srcBuffer);
drawImageLayers(renderengine, display, dstBuffer, srcBuffer);
const nsecs_t timeAfter = systemTime();
const float compileTimeMs = static_cast<float>(timeAfter - timeBefore) / 1.0E6;
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.cpp b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
index c5ee15d..c7001b9 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.cpp
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
@@ -499,7 +499,7 @@
std::shared_ptr<AutoBackendTexture::LocalRef> imageTextureRef =
std::make_shared<AutoBackendTexture::LocalRef>();
imageTextureRef->setTexture(
- new AutoBackendTexture(grContext.get(), buffer->toAHardwareBuffer(), false));
+ new AutoBackendTexture(grContext.get(), buffer->toAHardwareBuffer()));
cache.insert({buffer->getId(), imageTextureRef});
}
// restore the original state of the protected context if necessary
@@ -653,7 +653,7 @@
ATRACE_NAME("Cache miss");
surfaceTextureRef = std::make_shared<AutoBackendTexture::LocalRef>();
surfaceTextureRef->setTexture(
- new AutoBackendTexture(grContext.get(), buffer->toAHardwareBuffer(), true));
+ new AutoBackendTexture(grContext.get(), buffer->toAHardwareBuffer()));
if (useFramebufferCache) {
ALOGD("Adding to cache");
cache.insert({buffer->getId(), surfaceTextureRef});
@@ -860,9 +860,8 @@
imageTextureRef = iter->second;
} else {
imageTextureRef = std::make_shared<AutoBackendTexture::LocalRef>();
- imageTextureRef->setTexture(new AutoBackendTexture(grContext.get(),
- item.buffer->toAHardwareBuffer(),
- false));
+ imageTextureRef->setTexture(
+ new AutoBackendTexture(grContext.get(), item.buffer->toAHardwareBuffer()));
cache.insert({item.buffer->getId(), imageTextureRef});
}
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index 485fc99..76f6e74 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -386,7 +386,9 @@
void pokeUserActivity(nsecs_t, int32_t, int32_t) override {}
- bool checkInjectEventsPermissionNonReentrant(int32_t, int32_t) override { return false; }
+ bool checkInjectEventsPermissionNonReentrant(int32_t pid, int32_t uid) override {
+ return pid == INJECTOR_PID && uid == INJECTOR_UID;
+ }
void onPointerDownOutsideFocus(const sp<IBinder>& newToken) override {
std::scoped_lock lock(mLock);
@@ -1090,7 +1092,8 @@
const sp<InputDispatcher>& dispatcher, int32_t action, int32_t repeatCount,
int32_t displayId = ADISPLAY_ID_NONE,
InputEventInjectionSync syncMode = InputEventInjectionSync::WAIT_FOR_RESULT,
- std::chrono::milliseconds injectionTimeout = INJECT_EVENT_TIMEOUT) {
+ std::chrono::milliseconds injectionTimeout = INJECT_EVENT_TIMEOUT,
+ bool allowKeyRepeat = true) {
KeyEvent event;
nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC);
@@ -1099,10 +1102,13 @@
INVALID_HMAC, action, /* flags */ 0, AKEYCODE_A, KEY_A, AMETA_NONE,
repeatCount, currentTime, currentTime);
+ int32_t policyFlags = POLICY_FLAG_FILTERED | POLICY_FLAG_PASS_TO_USER;
+ if (!allowKeyRepeat) {
+ policyFlags |= POLICY_FLAG_DISABLE_KEY_REPEAT;
+ }
// Inject event until dispatch out.
return dispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID, syncMode,
- injectionTimeout,
- POLICY_FLAG_FILTERED | POLICY_FLAG_PASS_TO_USER);
+ injectionTimeout, policyFlags);
}
static InputEventInjectionResult injectKeyDown(const sp<InputDispatcher>& dispatcher,
@@ -1110,6 +1116,16 @@
return injectKey(dispatcher, AKEY_EVENT_ACTION_DOWN, /* repeatCount */ 0, displayId);
}
+// Inject a down event that has key repeat disabled. This allows InputDispatcher to idle without
+// sending a subsequent key up. When key repeat is enabled, the dispatcher cannot idle because it
+// has to be woken up to process the repeating key.
+static InputEventInjectionResult injectKeyDownNoRepeat(const sp<InputDispatcher>& dispatcher,
+ int32_t displayId = ADISPLAY_ID_NONE) {
+ return injectKey(dispatcher, AKEY_EVENT_ACTION_DOWN, /* repeatCount */ 0, displayId,
+ InputEventInjectionSync::WAIT_FOR_RESULT, INJECT_EVENT_TIMEOUT,
+ /* allowKeyRepeat */ false);
+}
+
static InputEventInjectionResult injectKeyUp(const sp<InputDispatcher>& dispatcher,
int32_t displayId = ADISPLAY_ID_NONE) {
return injectKey(dispatcher, AKEY_EVENT_ACTION_UP, /* repeatCount */ 0, displayId);
@@ -1254,7 +1270,7 @@
.build();
// Inject event until dispatch out.
- return injectMotionEvent(dispatcher, event);
+ return injectMotionEvent(dispatcher, event, injectionTimeout, injectionMode);
}
static InputEventInjectionResult injectMotionDown(const sp<InputDispatcher>& dispatcher,
@@ -2749,13 +2765,14 @@
TEST_F(InputDispatcherFocusOnTwoDisplaysTest, SetInputWindow_MultiDisplayFocus) {
// Test inject a key down with display id specified.
- ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(mDispatcher, ADISPLAY_ID_DEFAULT))
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+ injectKeyDownNoRepeat(mDispatcher, ADISPLAY_ID_DEFAULT))
<< "Inject key event should return InputEventInjectionResult::SUCCEEDED";
windowInPrimary->consumeKeyDown(ADISPLAY_ID_DEFAULT);
windowInSecondary->assertNoEvents();
// Test inject a key down without display id specified.
- ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(mDispatcher))
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDownNoRepeat(mDispatcher))
<< "Inject key event should return InputEventInjectionResult::SUCCEEDED";
windowInPrimary->assertNoEvents();
windowInSecondary->consumeKeyDown(ADISPLAY_ID_NONE);
@@ -2768,7 +2785,7 @@
AKEY_EVENT_FLAG_CANCELED);
// Test inject a key down, should timeout because of no target window.
- ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, injectKeyDown(mDispatcher))
+ ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, injectKeyDownNoRepeat(mDispatcher))
<< "Inject key event should return InputEventInjectionResult::TIMED_OUT";
windowInPrimary->assertNoEvents();
windowInSecondary->consumeFocusEvent(false);
@@ -2990,7 +3007,8 @@
// Have two windows, one with focus. Inject KeyEvent with action DOWN on the window that doesn't
// have focus. Ensure no window received the onPointerDownOutsideFocus callback.
TEST_F(InputDispatcherOnPointerDownOutsideFocus, OnPointerDownOutsideFocus_NonMotionFailure) {
- ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(mDispatcher, ADISPLAY_ID_DEFAULT))
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+ injectKeyDownNoRepeat(mDispatcher, ADISPLAY_ID_DEFAULT))
<< "Inject key event should return InputEventInjectionResult::SUCCEEDED";
mFocusedWindow->consumeKeyDown(ADISPLAY_ID_DEFAULT);
@@ -3271,7 +3289,7 @@
// Send a regular key and respond, which should not cause an ANR.
TEST_F(InputDispatcherSingleWindowAnr, WhenKeyIsConsumed_NoAnr) {
- ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(mDispatcher));
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDownNoRepeat(mDispatcher));
mWindow->consumeKeyDown(ADISPLAY_ID_NONE);
ASSERT_TRUE(mDispatcher->waitForIdle());
mFakePolicy->assertNotifyAnrWasNotCalled();
@@ -3284,7 +3302,8 @@
InputEventInjectionResult result =
injectKey(mDispatcher, AKEY_EVENT_ACTION_DOWN, 0 /*repeatCount*/, ADISPLAY_ID_DEFAULT,
- InputEventInjectionSync::NONE, 10ms /*injectionTimeout*/);
+ InputEventInjectionSync::NONE, 10ms /*injectionTimeout*/,
+ false /* allowKeyRepeat */);
ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, result);
// Key will not go to window because we have no focused window.
// The 'no focused window' ANR timer should start instead.
@@ -3320,7 +3339,7 @@
// Send a key to the app and have the app not respond right away.
TEST_F(InputDispatcherSingleWindowAnr, OnKeyDown_BasicAnr) {
// Inject a key, and don't respond - expect that ANR is called.
- ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(mDispatcher));
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDownNoRepeat(mDispatcher));
std::optional<uint32_t> sequenceNum = mWindow->receiveEvent();
ASSERT_TRUE(sequenceNum);
const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
@@ -3347,7 +3366,7 @@
// injection times out (instead of failing).
const InputEventInjectionResult result =
injectKey(mDispatcher, AKEY_EVENT_ACTION_DOWN, 0 /* repeatCount */, ADISPLAY_ID_DEFAULT,
- InputEventInjectionSync::WAIT_FOR_RESULT, 10ms);
+ InputEventInjectionSync::WAIT_FOR_RESULT, 10ms, false /* allowKeyRepeat */);
ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, result);
const std::chrono::duration timeout = mApplication->getDispatchingTimeout(DISPATCHING_TIMEOUT);
mFakePolicy->assertNotifyNoFocusedWindowAnrWasCalled(timeout, mApplication);
@@ -3366,7 +3385,7 @@
// injection times out (instead of failing).
const InputEventInjectionResult result =
injectKey(mDispatcher, AKEY_EVENT_ACTION_DOWN, 0 /* repeatCount */, ADISPLAY_ID_DEFAULT,
- InputEventInjectionSync::WAIT_FOR_RESULT, 10ms);
+ InputEventInjectionSync::WAIT_FOR_RESULT, 10ms, false /* allowKeyRepeat */);
ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, result);
const std::chrono::duration appTimeout =
mApplication->getDispatchingTimeout(DISPATCHING_TIMEOUT);
@@ -3955,7 +3974,8 @@
// Key will not be sent anywhere because we have no focused window. It will remain pending.
InputEventInjectionResult result =
injectKey(mDispatcher, AKEY_EVENT_ACTION_DOWN, 0 /*repeatCount*/, ADISPLAY_ID_DEFAULT,
- InputEventInjectionSync::NONE, 10ms /*injectionTimeout*/);
+ InputEventInjectionSync::NONE, 10ms /*injectionTimeout*/,
+ false /* allowKeyRepeat */);
ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, result);
// Wait until dispatcher starts the "no focused window" timer. If we don't wait here,
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h
index b0e42b7..a56f28a 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h
@@ -70,7 +70,7 @@
size_t getCreationCost() const;
size_t getDisplayCost() const;
- bool hasBufferUpdate(std::vector<const LayerState*>::const_iterator layers) const;
+ bool hasBufferUpdate() const;
bool hasReadyBuffer() const;
// Decomposes this CachedSet into a vector of its layers as individual CachedSets
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Flattener.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Flattener.h
index 5b9a9f0..2bd3249 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Flattener.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Flattener.h
@@ -45,8 +45,6 @@
// Renders the newest cached sets with the supplied output dataspace
void renderCachedSets(renderengine::RenderEngine&, ui::Dataspace outputDataspace);
- void reset();
-
void dump(std::string& result) const;
private:
diff --git a/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp b/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp
index 137697b..4d3036a 100644
--- a/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp
@@ -116,12 +116,11 @@
return static_cast<size_t>(mBounds.width() * mBounds.height());
}
-bool CachedSet::hasBufferUpdate(std::vector<const LayerState*>::const_iterator layers) const {
+bool CachedSet::hasBufferUpdate() const {
for (const Layer& layer : mLayers) {
if (layer.getFramesSinceBufferUpdate() == 0) {
return true;
}
- ++layers;
}
return false;
}
diff --git a/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp b/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp
index 30b5761..60ebbb2 100644
--- a/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp
@@ -60,18 +60,6 @@
mNewCachedSet->render(renderEngine, outputDataspace);
}
-void Flattener::reset() {
- resetActivities(0, std::chrono::steady_clock::now());
-
- mUnflattenedDisplayCost = 0;
- mFlattenedDisplayCost = 0;
- mInitialLayerCounts.clear();
- mFinalLayerCounts.clear();
- mCachedSetCreationCount = 0;
- mCachedSetCreationCost = 0;
- mInvalidatedCachedSetAges.clear();
-}
-
void Flattener::dump(std::string& result) const {
const auto now = std::chrono::steady_clock::now();
@@ -208,7 +196,7 @@
if (mNewCachedSet &&
mNewCachedSet->getFingerprint() ==
(*incomingLayerIter)->getHash(LayerStateField::Buffer)) {
- if (mNewCachedSet->hasBufferUpdate(incomingLayerIter)) {
+ if (mNewCachedSet->hasBufferUpdate()) {
ALOGV("[%s] Dropping new cached set", __func__);
++mInvalidatedCachedSetAges[0];
mNewCachedSet = std::nullopt;
@@ -242,7 +230,7 @@
}
}
- if (!currentLayerIter->hasBufferUpdate(incomingLayerIter)) {
+ if (!currentLayerIter->hasBufferUpdate()) {
currentLayerIter->incrementAge();
merged.emplace_back(*currentLayerIter);
diff --git a/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp b/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp
index 377f817..7842efb 100644
--- a/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp
@@ -201,13 +201,7 @@
cachedSet.addLayer(layer2.getState(), kStartTime + 10ms);
cachedSet.addLayer(layer3.getState(), kStartTime + 20ms);
- std::vector<const LayerState*> incomingLayers = {
- layer1.getState(),
- layer2.getState(),
- layer3.getState(),
- };
-
- EXPECT_FALSE(cachedSet.hasBufferUpdate(incomingLayers.begin()));
+ EXPECT_FALSE(cachedSet.hasBufferUpdate());
}
TEST_F(CachedSetTest, hasBufferUpdate_BufferUpdate) {
@@ -221,13 +215,7 @@
mTestLayers[1]->layerState->resetFramesSinceBufferUpdate();
- std::vector<const LayerState*> incomingLayers = {
- layer1.getState(),
- layer2.getState(),
- layer3.getState(),
- };
-
- EXPECT_TRUE(cachedSet.hasBufferUpdate(incomingLayers.begin()));
+ EXPECT_TRUE(cachedSet.hasBufferUpdate());
}
TEST_F(CachedSetTest, append) {
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index f4a2a3f..b7b2cc6 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -354,8 +354,20 @@
return mCompositionDisplay->getDisplayColorProfile()->getSupportedPerFrameMetadata();
}
-const HdrCapabilities& DisplayDevice::getHdrCapabilities() const {
- return mCompositionDisplay->getDisplayColorProfile()->getHdrCapabilities();
+void DisplayDevice::overrideHdrTypes(const std::vector<ui::Hdr>& hdrTypes) {
+ mOverrideHdrTypes = hdrTypes;
+}
+
+HdrCapabilities DisplayDevice::getHdrCapabilities() const {
+ const HdrCapabilities& capabilities =
+ mCompositionDisplay->getDisplayColorProfile()->getHdrCapabilities();
+ std::vector<ui::Hdr> hdrTypes = capabilities.getSupportedHdrTypes();
+ if (!mOverrideHdrTypes.empty()) {
+ hdrTypes = mOverrideHdrTypes;
+ }
+ return HdrCapabilities(hdrTypes, capabilities.getDesiredMaxLuminance(),
+ capabilities.getDesiredMaxAverageLuminance(),
+ capabilities.getDesiredMinLuminance());
}
std::atomic<int32_t> DisplayDeviceState::sNextSequenceId(1);
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index 7156613..68846d3 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -126,13 +126,15 @@
bool hasHLGSupport() const;
bool hasDolbyVisionSupport() const;
+ void overrideHdrTypes(const std::vector<ui::Hdr>& hdrTypes);
+
// The returned HdrCapabilities is the combination of HDR capabilities from
// hardware composer and RenderEngine. When the DisplayDevice supports wide
// color gamut, RenderEngine is able to simulate HDR support in Display P3
// color space for both PQ and HLG HDR contents. The minimum and maximum
// luminance will be set to sDefaultMinLumiance and sDefaultMaxLumiance
// respectively if hardware composer doesn't return meaningful values.
- const HdrCapabilities& getHdrCapabilities() const;
+ HdrCapabilities getHdrCapabilities() const;
// Return true if intent is supported by the display.
bool hasRenderIntent(ui::RenderIntent intent) const;
@@ -217,6 +219,8 @@
const bool mIsPrimary;
std::optional<DeviceProductInfo> mDeviceProductInfo;
+
+ std::vector<ui::Hdr> mOverrideHdrTypes;
};
struct DisplayDeviceState {
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index a0dbf6f..a387587 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -1287,6 +1287,21 @@
return NO_ERROR;
}
+status_t SurfaceFlinger::overrideHdrTypes(const sp<IBinder>& displayToken,
+ const std::vector<ui::Hdr>& hdrTypes) {
+ Mutex::Autolock lock(mStateLock);
+
+ auto display = getDisplayDeviceLocked(displayToken);
+ if (!display) {
+ ALOGE("%s: Invalid display token %p", __FUNCTION__, displayToken.get());
+ return NAME_NOT_FOUND;
+ }
+
+ display->overrideHdrTypes(hdrTypes);
+ dispatchDisplayHotplugEvent(display->getPhysicalId(), true /* connected */);
+ return NO_ERROR;
+}
+
status_t SurfaceFlinger::getDisplayedContentSamplingAttributes(const sp<IBinder>& displayToken,
ui::PixelFormat* outFormat,
ui::Dataspace* outDataspace,
@@ -3435,6 +3450,7 @@
const bool acquireFenceChanged = (s.what & layer_state_t::eAcquireFenceChanged);
if (acquireFenceChanged && s.acquireFence &&
s.acquireFence->getStatus() == Fence::Status::Unsignaled) {
+ ATRACE_NAME("fence unsignaled");
ready = false;
}
@@ -5014,6 +5030,7 @@
case DESTROY_DISPLAY:
case ENABLE_VSYNC_INJECTIONS:
case GET_ANIMATION_FRAME_STATS:
+ case OVERRIDE_HDR_TYPES:
case GET_HDR_CAPABILITIES:
case SET_DESIRED_DISPLAY_MODE_SPECS:
case GET_DESIRED_DISPLAY_MODE_SPECS:
@@ -5030,9 +5047,11 @@
case NOTIFY_POWER_BOOST:
case SET_GLOBAL_SHADOW_SETTINGS:
case ACQUIRE_FRAME_RATE_FLEXIBILITY_TOKEN: {
- // ACQUIRE_FRAME_RATE_FLEXIBILITY_TOKEN is used by CTS tests, which acquire the
- // necessary permission dynamically. Don't use the permission cache for this check.
- bool usePermissionCache = code != ACQUIRE_FRAME_RATE_FLEXIBILITY_TOKEN;
+ // ACQUIRE_FRAME_RATE_FLEXIBILITY_TOKEN and OVERRIDE_HDR_TYPES are used by CTS tests,
+ // which acquire the necessary permission dynamically. Don't use the permission cache
+ // for this check.
+ bool usePermissionCache =
+ code != ACQUIRE_FRAME_RATE_FLEXIBILITY_TOKEN && code != OVERRIDE_HDR_TYPES;
if (!callingThreadHasUnscopedSurfaceFlingerAccess(usePermissionCache)) {
IPCThreadState* ipc = IPCThreadState::self();
ALOGE("Permission Denial: can't access SurfaceFlinger pid=%d, uid=%d",
@@ -5908,8 +5927,11 @@
const status_t bufferStatus = buffer->initCheck();
LOG_ALWAYS_FATAL_IF(bufferStatus != OK, "captureScreenCommon: Buffer failed to allocate: %d",
bufferStatus);
- return captureScreenCommon(std::move(renderAreaFuture), traverseLayers, buffer,
- false /* regionSampling */, grayscale, captureListener);
+ getRenderEngine().cacheExternalTextureBuffer(buffer);
+ status_t result = captureScreenCommon(std::move(renderAreaFuture), traverseLayers, buffer,
+ false /* regionSampling */, grayscale, captureListener);
+ getRenderEngine().unbindExternalTextureBuffer(buffer->getId());
+ return result;
}
status_t SurfaceFlinger::captureScreenCommon(RenderAreaFuture renderAreaFuture,
@@ -5949,15 +5971,6 @@
regionSampling, grayscale, captureResults);
});
- // TODO(b/180767535): Remove this once we optimize buffer lifecycle for RenderEngine
- // Only do this when we're not doing region sampling, to allow the region sampling thread to
- // manage buffer lifecycle itself.
- if (!regionSampling &&
- getRenderEngine().getRenderEngineType() ==
- renderengine::RenderEngine::RenderEngineType::SKIA_GL_THREADED) {
- getRenderEngine().unbindExternalTextureBuffer(buffer->getId());
- }
-
captureResults.result = result;
captureListener->onScreenCaptureCompleted(captureResults);
}));
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 8d2f66d..e4ff6c9 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -642,6 +642,8 @@
void setPowerMode(const sp<IBinder>& displayToken, int mode) override;
status_t clearAnimationFrameStats() override;
status_t getAnimationFrameStats(FrameStats* outStats) const override;
+ status_t overrideHdrTypes(const sp<IBinder>& displayToken,
+ const std::vector<ui::Hdr>& hdrTypes) override;
status_t enableVSyncInjections(bool enable) override;
status_t injectVSync(nsecs_t when) override;
status_t getLayerDebugInfo(std::vector<LayerDebugInfo>* outLayers) override;
diff --git a/services/vibratorservice/VibratorHalController.cpp b/services/vibratorservice/VibratorHalController.cpp
index 70f9876..c1795f5 100644
--- a/services/vibratorservice/VibratorHalController.cpp
+++ b/services/vibratorservice/VibratorHalController.cpp
@@ -87,45 +87,6 @@
// -------------------------------------------------------------------------------------------------
-static constexpr int MAX_RETRIES = 1;
-
-template <typename T>
-HalResult<T> HalController::processHalResult(HalResult<T> result, const char* functionName) {
- if (result.isFailed()) {
- ALOGE("%s failed: %s", functionName, result.errorMessage());
- std::lock_guard<std::mutex> lock(mConnectedHalMutex);
- mConnectedHal->tryReconnect();
- }
- return result;
-}
-
-template <typename T>
-HalResult<T> HalController::apply(HalController::hal_fn<T>& halFn, const char* functionName) {
- std::shared_ptr<HalWrapper> hal = nullptr;
- {
- std::lock_guard<std::mutex> lock(mConnectedHalMutex);
- if (mConnectedHal == nullptr) {
- // Init was never called, so connect to HAL for the first time during this call.
- mConnectedHal = mConnector(mCallbackScheduler);
-
- if (mConnectedHal == nullptr) {
- ALOGV("Skipped %s because Vibrator HAL is not available", functionName);
- return HalResult<T>::unsupported();
- }
- }
- hal = mConnectedHal;
- }
-
- HalResult<T> ret = processHalResult(halFn(hal), functionName);
- for (int i = 0; i < MAX_RETRIES && ret.isFailed(); i++) {
- ret = processHalResult(halFn(hal), functionName);
- }
-
- return ret;
-}
-
-// -------------------------------------------------------------------------------------------------
-
bool HalController::init() {
std::lock_guard<std::mutex> lock(mConnectedHalMutex);
if (mConnectedHal == nullptr) {
@@ -134,11 +95,6 @@
return mConnectedHal != nullptr;
}
-HalResult<void> HalController::ping() {
- hal_fn<void> pingFn = [](std::shared_ptr<HalWrapper> hal) { return hal->ping(); };
- return apply(pingFn, "ping");
-}
-
void HalController::tryReconnect() {
std::lock_guard<std::mutex> lock(mConnectedHalMutex);
if (mConnectedHal == nullptr) {
@@ -148,96 +104,6 @@
}
}
-HalResult<void> HalController::on(milliseconds timeout,
- const std::function<void()>& completionCallback) {
- hal_fn<void> onFn = [&](std::shared_ptr<HalWrapper> hal) {
- return hal->on(timeout, completionCallback);
- };
- return apply(onFn, "on");
-}
-
-HalResult<void> HalController::off() {
- hal_fn<void> offFn = [](std::shared_ptr<HalWrapper> hal) { return hal->off(); };
- return apply(offFn, "off");
-}
-
-HalResult<void> HalController::setAmplitude(float amplitude) {
- hal_fn<void> setAmplitudeFn = [&](std::shared_ptr<HalWrapper> hal) {
- return hal->setAmplitude(amplitude);
- };
- return apply(setAmplitudeFn, "setAmplitude");
-}
-
-HalResult<void> HalController::setExternalControl(bool enabled) {
- hal_fn<void> setExternalControlFn = [&](std::shared_ptr<HalWrapper> hal) {
- return hal->setExternalControl(enabled);
- };
- return apply(setExternalControlFn, "setExternalControl");
-}
-
-HalResult<void> HalController::alwaysOnEnable(int32_t id, Effect effect, EffectStrength strength) {
- hal_fn<void> alwaysOnEnableFn = [&](std::shared_ptr<HalWrapper> hal) {
- return hal->alwaysOnEnable(id, effect, strength);
- };
- return apply(alwaysOnEnableFn, "alwaysOnEnable");
-}
-
-HalResult<void> HalController::alwaysOnDisable(int32_t id) {
- hal_fn<void> alwaysOnDisableFn = [&](std::shared_ptr<HalWrapper> hal) {
- return hal->alwaysOnDisable(id);
- };
- return apply(alwaysOnDisableFn, "alwaysOnDisable");
-}
-
-HalResult<Capabilities> HalController::getCapabilities() {
- hal_fn<Capabilities> getCapabilitiesFn = [](std::shared_ptr<HalWrapper> hal) {
- return hal->getCapabilities();
- };
- return apply(getCapabilitiesFn, "getCapabilities");
-}
-
-HalResult<std::vector<Effect>> HalController::getSupportedEffects() {
- hal_fn<std::vector<Effect>> getSupportedEffectsFn = [](std::shared_ptr<HalWrapper> hal) {
- return hal->getSupportedEffects();
- };
- return apply(getSupportedEffectsFn, "getSupportedEffects");
-}
-
-HalResult<std::vector<CompositePrimitive>> HalController::getSupportedPrimitives() {
- hal_fn<std::vector<CompositePrimitive>> getSupportedPrimitivesFn =
- [](std::shared_ptr<HalWrapper> hal) { return hal->getSupportedPrimitives(); };
- return apply(getSupportedPrimitivesFn, "getSupportedPrimitives");
-}
-
-HalResult<float> HalController::getResonantFrequency() {
- hal_fn<float> getResonantFrequencyFn = [](std::shared_ptr<HalWrapper> hal) {
- return hal->getResonantFrequency();
- };
- return apply(getResonantFrequencyFn, "getResonantFrequency");
-}
-
-HalResult<float> HalController::getQFactor() {
- hal_fn<float> getQFactorFn = [](std::shared_ptr<HalWrapper> hal) { return hal->getQFactor(); };
- return apply(getQFactorFn, "getQFactor");
-}
-
-HalResult<milliseconds> HalController::performEffect(
- Effect effect, EffectStrength strength, const std::function<void()>& completionCallback) {
- hal_fn<milliseconds> performEffectFn = [&](std::shared_ptr<HalWrapper> hal) {
- return hal->performEffect(effect, strength, completionCallback);
- };
- return apply(performEffectFn, "performEffect");
-}
-
-HalResult<milliseconds> HalController::performComposedEffect(
- const std::vector<CompositeEffect>& primitiveEffects,
- const std::function<void()>& completionCallback) {
- hal_fn<milliseconds> performComposedEffectFn = [&](std::shared_ptr<HalWrapper> hal) {
- return hal->performComposedEffect(primitiveEffects, completionCallback);
- };
- return apply(performComposedEffectFn, "performComposedEffect");
-}
-
}; // namespace vibrator
}; // namespace android
diff --git a/services/vibratorservice/VibratorHalWrapper.cpp b/services/vibratorservice/VibratorHalWrapper.cpp
index baee74f..1010aa5 100644
--- a/services/vibratorservice/VibratorHalWrapper.cpp
+++ b/services/vibratorservice/VibratorHalWrapper.cpp
@@ -19,16 +19,19 @@
#include <android/hardware/vibrator/1.3/IVibrator.h>
#include <android/hardware/vibrator/IVibrator.h>
#include <hardware/vibrator.h>
+#include <cmath>
#include <utils/Log.h>
#include <vibratorservice/VibratorCallbackScheduler.h>
#include <vibratorservice/VibratorHalWrapper.h>
+using android::hardware::vibrator::Braking;
using android::hardware::vibrator::CompositeEffect;
using android::hardware::vibrator::CompositePrimitive;
using android::hardware::vibrator::Effect;
using android::hardware::vibrator::EffectStrength;
+using android::hardware::vibrator::PrimitivePwle;
using std::chrono::milliseconds;
@@ -45,20 +48,6 @@
// -------------------------------------------------------------------------------------------------
template <class T>
-HalResult<T> loadCached(const std::function<HalResult<T>()>& loadFn, std::optional<T>& cache) {
- if (cache.has_value()) {
- // Return copy of cached value.
- return HalResult<T>::ok(*cache);
- }
- HalResult<T> ret = loadFn();
- if (ret.isOk()) {
- // Cache copy of returned value.
- cache.emplace(ret.value());
- }
- return ret;
-}
-
-template <class T>
bool isStaticCastValid(Effect effect) {
T castEffect = static_cast<T>(effect);
auto iter = hardware::hidl_enum_range<T>();
@@ -133,6 +122,117 @@
// -------------------------------------------------------------------------------------------------
+Info HalWrapper::getInfo() {
+ getCapabilities();
+ getPrimitiveDurations();
+ std::lock_guard<std::mutex> lock(mInfoMutex);
+ if (mInfoCache.mSupportedEffects.isFailed()) {
+ mInfoCache.mSupportedEffects = getSupportedEffectsInternal();
+ }
+ if (mInfoCache.mSupportedBraking.isFailed()) {
+ mInfoCache.mSupportedBraking = getSupportedBrakingInternal();
+ }
+ if (mInfoCache.mMinFrequency.isFailed()) {
+ mInfoCache.mMinFrequency = getMinFrequencyInternal();
+ }
+ if (mInfoCache.mResonantFrequency.isFailed()) {
+ mInfoCache.mResonantFrequency = getResonantFrequencyInternal();
+ }
+ if (mInfoCache.mFrequencyResolution.isFailed()) {
+ mInfoCache.mFrequencyResolution = getFrequencyResolutionInternal();
+ }
+ if (mInfoCache.mQFactor.isFailed()) {
+ mInfoCache.mQFactor = getQFactorInternal();
+ }
+ if (mInfoCache.mMaxAmplitudes.isFailed()) {
+ mInfoCache.mMaxAmplitudes = getMaxAmplitudesInternal();
+ }
+ return mInfoCache.get();
+}
+
+HalResult<milliseconds> HalWrapper::performComposedEffect(const std::vector<CompositeEffect>&,
+ const std::function<void()>&) {
+ ALOGV("Skipped performComposedEffect because it's not available in Vibrator HAL");
+ return HalResult<milliseconds>::unsupported();
+}
+
+HalResult<void> HalWrapper::performPwleEffect(const std::vector<PrimitivePwle>&,
+ const std::function<void()>&) {
+ ALOGV("Skipped performPwleEffect because it's not available in Vibrator HAL");
+ return HalResult<void>::unsupported();
+}
+
+HalResult<Capabilities> HalWrapper::getCapabilities() {
+ std::lock_guard<std::mutex> lock(mInfoMutex);
+ if (mInfoCache.mCapabilities.isFailed()) {
+ mInfoCache.mCapabilities = getCapabilitiesInternal();
+ }
+ return mInfoCache.mCapabilities;
+}
+
+HalResult<std::vector<milliseconds>> HalWrapper::getPrimitiveDurations() {
+ std::lock_guard<std::mutex> lock(mInfoMutex);
+ if (mInfoCache.mSupportedPrimitives.isFailed()) {
+ mInfoCache.mSupportedPrimitives = getSupportedPrimitivesInternal();
+ if (mInfoCache.mSupportedPrimitives.isUnsupported()) {
+ mInfoCache.mPrimitiveDurations = HalResult<std::vector<milliseconds>>::unsupported();
+ }
+ }
+ if (mInfoCache.mPrimitiveDurations.isFailed() && mInfoCache.mSupportedPrimitives.isOk()) {
+ mInfoCache.mPrimitiveDurations =
+ getPrimitiveDurationsInternal(mInfoCache.mSupportedPrimitives.value());
+ }
+ return mInfoCache.mPrimitiveDurations;
+}
+
+HalResult<std::vector<Effect>> HalWrapper::getSupportedEffectsInternal() {
+ ALOGV("Skipped getSupportedEffects because it's not available in Vibrator HAL");
+ return HalResult<std::vector<Effect>>::unsupported();
+}
+
+HalResult<std::vector<Braking>> HalWrapper::getSupportedBrakingInternal() {
+ ALOGV("Skipped getSupportedBraking because it's not available in Vibrator HAL");
+ return HalResult<std::vector<Braking>>::unsupported();
+}
+
+HalResult<std::vector<CompositePrimitive>> HalWrapper::getSupportedPrimitivesInternal() {
+ ALOGV("Skipped getSupportedPrimitives because it's not available in Vibrator HAL");
+ return HalResult<std::vector<CompositePrimitive>>::unsupported();
+}
+
+HalResult<std::vector<milliseconds>> HalWrapper::getPrimitiveDurationsInternal(
+ const std::vector<CompositePrimitive>&) {
+ ALOGV("Skipped getPrimitiveDurations because it's not available in Vibrator HAL");
+ return HalResult<std::vector<milliseconds>>::unsupported();
+}
+
+HalResult<float> HalWrapper::getMinFrequencyInternal() {
+ ALOGV("Skipped getMinFrequency because it's not available in Vibrator HAL");
+ return HalResult<float>::unsupported();
+}
+
+HalResult<float> HalWrapper::getResonantFrequencyInternal() {
+ ALOGV("Skipped getResonantFrequency because it's not available in Vibrator HAL");
+ return HalResult<float>::unsupported();
+}
+
+HalResult<float> HalWrapper::getFrequencyResolutionInternal() {
+ ALOGV("Skipped getFrequencyResolution because it's not available in Vibrator HAL");
+ return HalResult<float>::unsupported();
+}
+
+HalResult<float> HalWrapper::getQFactorInternal() {
+ ALOGV("Skipped getQFactor because it's not available in Vibrator HAL");
+ return HalResult<float>::unsupported();
+}
+
+HalResult<std::vector<float>> HalWrapper::getMaxAmplitudesInternal() {
+ ALOGV("Skipped getMaxAmplitudes because it's not available in Vibrator HAL");
+ return HalResult<std::vector<float>>::unsupported();
+}
+
+// -------------------------------------------------------------------------------------------------
+
HalResult<void> AidlHalWrapper::ping() {
return HalResult<void>::fromStatus(IInterface::asBinder(getHal())->pingBinder());
}
@@ -184,37 +284,6 @@
return HalResult<void>::fromStatus(getHal()->alwaysOnDisable(id));
}
-HalResult<Capabilities> AidlHalWrapper::getCapabilities() {
- std::lock_guard<std::mutex> lock(mCapabilitiesMutex);
- return loadCached<Capabilities>(std::bind(&AidlHalWrapper::getCapabilitiesInternal, this),
- mCapabilities);
-}
-
-HalResult<std::vector<Effect>> AidlHalWrapper::getSupportedEffects() {
- std::lock_guard<std::mutex> lock(mSupportedEffectsMutex);
- return loadCached<std::vector<Effect>>(std::bind(&AidlHalWrapper::getSupportedEffectsInternal,
- this),
- mSupportedEffects);
-}
-
-HalResult<std::vector<CompositePrimitive>> AidlHalWrapper::getSupportedPrimitives() {
- std::lock_guard<std::mutex> lock(mSupportedPrimitivesMutex);
- return loadCached<std::vector<
- CompositePrimitive>>(std::bind(&AidlHalWrapper::getSupportedPrimitivesInternal, this),
- mSupportedPrimitives);
-}
-
-HalResult<float> AidlHalWrapper::getResonantFrequency() {
- std::lock_guard<std::mutex> lock(mResonantFrequencyMutex);
- return loadCached<float>(std::bind(&AidlHalWrapper::getResonantFrequencyInternal, this),
- mResonantFrequency);
-}
-
-HalResult<float> AidlHalWrapper::getQFactor() {
- std::lock_guard<std::mutex> lock(mQFactorMutex);
- return loadCached<float>(std::bind(&AidlHalWrapper::getQFactorInternal, this), mQFactor);
-}
-
HalResult<milliseconds> AidlHalWrapper::performEffect(
Effect effect, EffectStrength strength, const std::function<void()>& completionCallback) {
HalResult<Capabilities> capabilities = getCapabilities();
@@ -235,44 +304,32 @@
}
HalResult<milliseconds> AidlHalWrapper::performComposedEffect(
- const std::vector<CompositeEffect>& primitiveEffects,
+ const std::vector<CompositeEffect>& primitives,
const std::function<void()>& completionCallback) {
// This method should always support callbacks, so no need to double check.
auto cb = new HalCallbackWrapper(completionCallback);
+
+ auto durations = getPrimitiveDurations().valueOr({});
milliseconds duration(0);
- for (const auto& effect : primitiveEffects) {
- auto durationResult = getPrimitiveDuration(effect.primitive);
- if (durationResult.isOk()) {
- duration += durationResult.value();
+ for (const auto& effect : primitives) {
+ auto primitiveIdx = static_cast<size_t>(effect.primitive);
+ if (primitiveIdx < durations.size()) {
+ duration += durations[primitiveIdx];
+ } else {
+ // Make sure the returned duration is positive to indicate successful vibration.
+ duration += milliseconds(1);
}
duration += milliseconds(effect.delayMs);
}
- return HalResult<milliseconds>::fromStatus(getHal()->compose(primitiveEffects, cb), duration);
+
+ return HalResult<milliseconds>::fromStatus(getHal()->compose(primitives, cb), duration);
}
-HalResult<milliseconds> AidlHalWrapper::getPrimitiveDuration(CompositePrimitive primitive) {
- std::lock_guard<std::mutex> lock(mSupportedPrimitivesMutex);
- if (mPrimitiveDurations.empty()) {
- constexpr auto primitiveRange = enum_range<CompositePrimitive>();
- constexpr auto primitiveCount = std::distance(primitiveRange.begin(), primitiveRange.end());
- mPrimitiveDurations.resize(primitiveCount);
- }
- auto primitiveIdx = static_cast<size_t>(primitive);
- if (primitiveIdx >= mPrimitiveDurations.size()) {
- // Safety check, should not happen if enum_range is correct.
- return HalResult<milliseconds>::unsupported();
- }
- auto& cache = mPrimitiveDurations[primitiveIdx];
- if (cache.has_value()) {
- return HalResult<milliseconds>::ok(*cache);
- }
- int32_t duration;
- auto result = getHal()->getPrimitiveDuration(primitive, &duration);
- if (result.isOk()) {
- // Cache copy of returned value.
- cache.emplace(duration);
- }
- return HalResult<milliseconds>::fromStatus(result, milliseconds(duration));
+HalResult<void> AidlHalWrapper::performPwleEffect(const std::vector<PrimitivePwle>& primitives,
+ const std::function<void()>& completionCallback) {
+ // This method should always support callbacks, so no need to double check.
+ auto cb = new HalCallbackWrapper(completionCallback);
+ return HalResult<void>::fromStatus(getHal()->composePwle(primitives, cb));
}
HalResult<Capabilities> AidlHalWrapper::getCapabilitiesInternal() {
@@ -287,24 +344,72 @@
return HalResult<std::vector<Effect>>::fromStatus(result, supportedEffects);
}
+HalResult<std::vector<Braking>> AidlHalWrapper::getSupportedBrakingInternal() {
+ std::vector<Braking> supportedBraking;
+ auto result = getHal()->getSupportedBraking(&supportedBraking);
+ return HalResult<std::vector<Braking>>::fromStatus(result, supportedBraking);
+}
+
HalResult<std::vector<CompositePrimitive>> AidlHalWrapper::getSupportedPrimitivesInternal() {
std::vector<CompositePrimitive> supportedPrimitives;
auto result = getHal()->getSupportedPrimitives(&supportedPrimitives);
return HalResult<std::vector<CompositePrimitive>>::fromStatus(result, supportedPrimitives);
}
+HalResult<std::vector<milliseconds>> AidlHalWrapper::getPrimitiveDurationsInternal(
+ const std::vector<CompositePrimitive>& supportedPrimitives) {
+ std::vector<milliseconds> durations;
+ constexpr auto primitiveRange = enum_range<CompositePrimitive>();
+ constexpr auto primitiveCount = std::distance(primitiveRange.begin(), primitiveRange.end());
+ durations.resize(primitiveCount);
+
+ for (auto primitive : supportedPrimitives) {
+ auto primitiveIdx = static_cast<size_t>(primitive);
+ if (primitiveIdx >= durations.size()) {
+ // Safety check, should not happen if enum_range is correct.
+ continue;
+ }
+ int32_t duration = 0;
+ auto status = getHal()->getPrimitiveDuration(primitive, &duration);
+ if (!status.isOk()) {
+ return HalResult<std::vector<milliseconds>>::failed(status.toString8().c_str());
+ }
+ durations[primitiveIdx] = milliseconds(duration);
+ }
+
+ return HalResult<std::vector<milliseconds>>::ok(durations);
+}
+
+HalResult<float> AidlHalWrapper::getMinFrequencyInternal() {
+ float minFrequency = 0;
+ auto result = getHal()->getFrequencyMinimum(&minFrequency);
+ return HalResult<float>::fromStatus(result, minFrequency);
+}
+
HalResult<float> AidlHalWrapper::getResonantFrequencyInternal() {
float f0 = 0;
auto result = getHal()->getResonantFrequency(&f0);
return HalResult<float>::fromStatus(result, f0);
}
+HalResult<float> AidlHalWrapper::getFrequencyResolutionInternal() {
+ float frequencyResolution = 0;
+ auto result = getHal()->getFrequencyResolution(&frequencyResolution);
+ return HalResult<float>::fromStatus(result, frequencyResolution);
+}
+
HalResult<float> AidlHalWrapper::getQFactorInternal() {
float qFactor = 0;
auto result = getHal()->getQFactor(&qFactor);
return HalResult<float>::fromStatus(result, qFactor);
}
+HalResult<std::vector<float>> AidlHalWrapper::getMaxAmplitudesInternal() {
+ std::vector<float> amplitudes;
+ auto result = getHal()->getBandwidthAmplitudeMap(&litudes);
+ return HalResult<std::vector<float>>::fromStatus(result, amplitudes);
+}
+
sp<Aidl::IVibrator> AidlHalWrapper::getHal() {
std::lock_guard<std::mutex> lock(mHandleMutex);
return mHandle;
@@ -370,44 +475,6 @@
}
template <typename I>
-HalResult<Capabilities> HidlHalWrapper<I>::getCapabilities() {
- std::lock_guard<std::mutex> lock(mCapabilitiesMutex);
- return loadCached<Capabilities>(std::bind(&HidlHalWrapper<I>::getCapabilitiesInternal, this),
- mCapabilities);
-}
-
-template <typename I>
-HalResult<std::vector<Effect>> HidlHalWrapper<I>::getSupportedEffects() {
- ALOGV("Skipped getSupportedEffects because Vibrator HAL AIDL is not available");
- return HalResult<std::vector<Effect>>::unsupported();
-}
-
-template <typename I>
-HalResult<std::vector<CompositePrimitive>> HidlHalWrapper<I>::getSupportedPrimitives() {
- ALOGV("Skipped getSupportedPrimitives because Vibrator HAL AIDL is not available");
- return HalResult<std::vector<CompositePrimitive>>::unsupported();
-}
-
-template <typename I>
-HalResult<float> HidlHalWrapper<I>::getResonantFrequency() {
- ALOGV("Skipped getResonantFrequency because Vibrator HAL AIDL is not available");
- return HalResult<float>::unsupported();
-}
-
-template <typename I>
-HalResult<float> HidlHalWrapper<I>::getQFactor() {
- ALOGV("Skipped getQFactor because Vibrator HAL AIDL is not available");
- return HalResult<float>::unsupported();
-}
-
-template <typename I>
-HalResult<std::chrono::milliseconds> HidlHalWrapper<I>::performComposedEffect(
- const std::vector<CompositeEffect>&, const std::function<void()>&) {
- ALOGV("Skipped composed effect because Vibrator HAL AIDL is not available");
- return HalResult<std::chrono::milliseconds>::unsupported();
-}
-
-template <typename I>
HalResult<Capabilities> HidlHalWrapper<I>::getCapabilitiesInternal() {
hardware::Return<bool> result = getHal()->supportsAmplitudeControl();
Capabilities capabilities =
diff --git a/services/vibratorservice/VibratorManagerHalWrapper.cpp b/services/vibratorservice/VibratorManagerHalWrapper.cpp
index 8a08e5b..a9d499d 100644
--- a/services/vibratorservice/VibratorManagerHalWrapper.cpp
+++ b/services/vibratorservice/VibratorManagerHalWrapper.cpp
@@ -30,7 +30,8 @@
const constexpr char* MISSING_VIBRATOR_MESSAGE_PREFIX = "No vibrator with id=";
HalResult<void> LegacyManagerHalWrapper::ping() {
- return mController->ping();
+ auto pingFn = [](std::shared_ptr<HalWrapper> hal) { return hal->ping(); };
+ return mController->doWithRetry<void>(pingFn, "ping");
}
void LegacyManagerHalWrapper::tryReconnect() {
diff --git a/services/vibratorservice/benchmarks/VibratorHalControllerBenchmarks.cpp b/services/vibratorservice/benchmarks/VibratorHalControllerBenchmarks.cpp
index f40980c..53f3daf 100644
--- a/services/vibratorservice/benchmarks/VibratorHalControllerBenchmarks.cpp
+++ b/services/vibratorservice/benchmarks/VibratorHalControllerBenchmarks.cpp
@@ -20,6 +20,10 @@
#include <vibratorservice/VibratorHalController.h>
using ::android::enum_range;
+using ::android::hardware::vibrator::CompositeEffect;
+using ::android::hardware::vibrator::CompositePrimitive;
+using ::android::hardware::vibrator::Effect;
+using ::android::hardware::vibrator::EffectStrength;
using ::benchmark::Counter;
using ::benchmark::Fixture;
using ::benchmark::kMicrosecond;
@@ -33,7 +37,7 @@
public:
void SetUp(State& /*state*/) override { mController.init(); }
- void TearDown(State& /*state*/) override { mController.off(); }
+ void TearDown(State& state) override { turnVibratorOff(state); }
static void DefaultConfig(Benchmark* b) { b->Unit(kMicrosecond); }
@@ -46,8 +50,8 @@
auto getOtherArg(const State& state, std::size_t index) const { return state.range(index + 0); }
- bool hasCapabilities(const vibrator::HalResult<vibrator::Capabilities>& result,
- vibrator::Capabilities&& query, State& state) {
+ bool hasCapabilities(vibrator::Capabilities&& query, State& state) {
+ auto result = mController.getInfo().capabilities;
if (result.isFailed()) {
state.SkipWithError(result.errorMessage());
return false;
@@ -58,6 +62,10 @@
return (result.value() & query) == query;
}
+ void turnVibratorOff(State& state) {
+ checkHalResult(halCall<void>(mController, [](auto hal) { return hal->off(); }), state);
+ }
+
template <class R>
bool checkHalResult(const vibrator::HalResult<R>& result, State& state) {
if (result.isFailed()) {
@@ -66,6 +74,12 @@
}
return true;
}
+
+ template <class R>
+ vibrator::HalResult<R> halCall(vibrator::HalController& controller,
+ const vibrator::HalFunction<vibrator::HalResult<R>>& halFn) {
+ return controller.doWithRetry<R>(halFn, "benchmark");
+ }
};
#define BENCHMARK_WRAPPER(fixt, test, code) \
@@ -93,7 +107,7 @@
BENCHMARK_WRAPPER(VibratorBench, ping, {
for (auto _ : state) {
state.ResumeTiming();
- auto ret = mController.ping();
+ auto ret = halCall<void>(mController, [](auto hal) { return hal->ping(); });
state.PauseTiming();
checkHalResult(ret, state);
}
@@ -111,10 +125,11 @@
for (auto _ : state) {
state.ResumeTiming();
- auto ret = mController.on(duration, callback);
+ auto ret =
+ halCall<void>(mController, [&](auto hal) { return hal->on(duration, callback); });
state.PauseTiming();
if (checkHalResult(ret, state)) {
- checkHalResult(mController.off(), state);
+ turnVibratorOff(state);
}
}
});
@@ -125,18 +140,18 @@
for (auto _ : state) {
state.PauseTiming();
- if (!checkHalResult(mController.on(duration, callback), state)) {
+ auto ret =
+ halCall<void>(mController, [&](auto hal) { return hal->on(duration, callback); });
+ if (!checkHalResult(ret, state)) {
continue;
}
state.ResumeTiming();
- checkHalResult(mController.off(), state);
+ turnVibratorOff(state);
}
});
BENCHMARK_WRAPPER(VibratorBench, setAmplitude, {
- auto result = mController.getCapabilities();
-
- if (!hasCapabilities(result, vibrator::Capabilities::AMPLITUDE_CONTROL, state)) {
+ if (!hasCapabilities(vibrator::Capabilities::AMPLITUDE_CONTROL, state)) {
return;
}
@@ -148,22 +163,23 @@
state.PauseTiming();
vibrator::HalController controller;
controller.init();
- if (!checkHalResult(controller.on(duration, callback), state)) {
+ auto result =
+ halCall<void>(controller, [&](auto hal) { return hal->on(duration, callback); });
+ if (!checkHalResult(result, state)) {
continue;
}
state.ResumeTiming();
- auto ret = controller.setAmplitude(amplitude);
+ auto ret =
+ halCall<void>(controller, [&](auto hal) { return hal->setAmplitude(amplitude); });
state.PauseTiming();
if (checkHalResult(ret, state)) {
- checkHalResult(controller.off(), state);
+ turnVibratorOff(state);
}
}
});
BENCHMARK_WRAPPER(VibratorBench, setAmplitudeCached, {
- auto result = mController.getCapabilities();
-
- if (!hasCapabilities(result, vibrator::Capabilities::AMPLITUDE_CONTROL, state)) {
+ if (!hasCapabilities(vibrator::Capabilities::AMPLITUDE_CONTROL, state)) {
return;
}
@@ -171,19 +187,19 @@
auto callback = []() {};
auto amplitude = 1.0f;
- checkHalResult(mController.on(duration, callback), state);
+ auto onResult =
+ halCall<void>(mController, [&](auto hal) { return hal->on(duration, callback); });
+ checkHalResult(onResult, state);
for (auto _ : state) {
- checkHalResult(mController.setAmplitude(amplitude), state);
+ auto ret =
+ halCall<void>(mController, [&](auto hal) { return hal->setAmplitude(amplitude); });
+ checkHalResult(ret, state);
}
-
- checkHalResult(mController.off(), state);
});
BENCHMARK_WRAPPER(VibratorBench, setExternalControl, {
- auto result = mController.getCapabilities();
-
- if (!hasCapabilities(result, vibrator::Capabilities::EXTERNAL_CONTROL, state)) {
+ if (!hasCapabilities(vibrator::Capabilities::EXTERNAL_CONTROL, state)) {
return;
}
@@ -192,103 +208,85 @@
vibrator::HalController controller;
controller.init();
state.ResumeTiming();
- auto ret = controller.setExternalControl(true);
+ auto ret =
+ halCall<void>(controller, [](auto hal) { return hal->setExternalControl(true); });
state.PauseTiming();
if (checkHalResult(ret, state)) {
- checkHalResult(controller.setExternalControl(false), state);
+ auto result = halCall<void>(controller,
+ [](auto hal) { return hal->setExternalControl(false); });
+ checkHalResult(result, state);
}
}
});
BENCHMARK_WRAPPER(VibratorBench, setExternalControlCached, {
- auto result = mController.getCapabilities();
-
- if (!hasCapabilities(result, vibrator::Capabilities::EXTERNAL_CONTROL, state)) {
+ if (!hasCapabilities(vibrator::Capabilities::EXTERNAL_CONTROL, state)) {
return;
}
for (auto _ : state) {
state.ResumeTiming();
- auto ret = mController.setExternalControl(true);
+ auto result =
+ halCall<void>(mController, [](auto hal) { return hal->setExternalControl(true); });
state.PauseTiming();
- if (checkHalResult(ret, state)) {
- checkHalResult(mController.setExternalControl(false), state);
+ if (checkHalResult(result, state)) {
+ auto ret = halCall<void>(mController,
+ [](auto hal) { return hal->setExternalControl(false); });
+ checkHalResult(ret, state);
}
}
});
BENCHMARK_WRAPPER(VibratorBench, setExternalAmplitudeCached, {
- auto result = mController.getCapabilities();
-
- if (!hasCapabilities(result, vibrator::Capabilities::EXTERNAL_AMPLITUDE_CONTROL, state)) {
+ if (!hasCapabilities(vibrator::Capabilities::EXTERNAL_AMPLITUDE_CONTROL, state)) {
return;
}
auto amplitude = 1.0f;
- checkHalResult(mController.setExternalControl(true), state);
+ auto onResult =
+ halCall<void>(mController, [](auto hal) { return hal->setExternalControl(true); });
+ checkHalResult(onResult, state);
for (auto _ : state) {
- checkHalResult(mController.setAmplitude(amplitude), state);
+ auto ret =
+ halCall<void>(mController, [&](auto hal) { return hal->setAmplitude(amplitude); });
+ checkHalResult(ret, state);
}
- checkHalResult(mController.setExternalControl(false), state);
+ auto offResult =
+ halCall<void>(mController, [](auto hal) { return hal->setExternalControl(false); });
+ checkHalResult(offResult, state);
});
-BENCHMARK_WRAPPER(VibratorBench, getCapabilities, {
+BENCHMARK_WRAPPER(VibratorBench, getInfo, {
for (auto _ : state) {
state.PauseTiming();
vibrator::HalController controller;
controller.init();
state.ResumeTiming();
- checkHalResult(controller.getCapabilities(), state);
+ auto result = controller.getInfo();
+ checkHalResult(result.capabilities, state);
+ checkHalResult(result.supportedEffects, state);
+ checkHalResult(result.supportedPrimitives, state);
+ checkHalResult(result.primitiveDurations, state);
+ checkHalResult(result.resonantFrequency, state);
+ checkHalResult(result.qFactor, state);
}
});
-BENCHMARK_WRAPPER(VibratorBench, getCapabilitiesCached, {
+BENCHMARK_WRAPPER(VibratorBench, getInfoCached, {
// First call to cache values.
- checkHalResult(mController.getCapabilities(), state);
+ mController.getInfo();
for (auto _ : state) {
- checkHalResult(mController.getCapabilities(), state);
- }
-});
-
-BENCHMARK_WRAPPER(VibratorBench, getSupportedEffects, {
- for (auto _ : state) {
- state.PauseTiming();
- vibrator::HalController controller;
- controller.init();
- state.ResumeTiming();
- checkHalResult(controller.getSupportedEffects(), state);
- }
-});
-
-BENCHMARK_WRAPPER(VibratorBench, getSupportedEffectsCached, {
- // First call to cache values.
- checkHalResult(mController.getSupportedEffects(), state);
-
- for (auto _ : state) {
- checkHalResult(mController.getSupportedEffects(), state);
- }
-});
-
-BENCHMARK_WRAPPER(VibratorBench, getSupportedPrimitives, {
- for (auto _ : state) {
- state.PauseTiming();
- vibrator::HalController controller;
- controller.init();
- state.ResumeTiming();
- checkHalResult(controller.getSupportedPrimitives(), state);
- }
-});
-
-BENCHMARK_WRAPPER(VibratorBench, getSupportedPrimitivesCached, {
- // First call to cache values.
- checkHalResult(mController.getSupportedPrimitives(), state);
-
- for (auto _ : state) {
- checkHalResult(mController.getSupportedPrimitives(), state);
+ auto result = mController.getInfo();
+ checkHalResult(result.capabilities, state);
+ checkHalResult(result.supportedEffects, state);
+ checkHalResult(result.supportedPrimitives, state);
+ checkHalResult(result.primitiveDurations, state);
+ checkHalResult(result.resonantFrequency, state);
+ checkHalResult(result.qFactor, state);
}
});
@@ -296,12 +294,12 @@
public:
static void DefaultArgs(Benchmark* b) {
vibrator::HalController controller;
- auto effectsResult = controller.getSupportedEffects();
+ auto effectsResult = controller.getInfo().supportedEffects;
if (!effectsResult.isOk()) {
return;
}
- std::vector<hardware::vibrator::Effect> supported = effectsResult.value();
+ std::vector<Effect> supported = effectsResult.value();
b->ArgNames({"Effect", "Strength"});
if (supported.empty()) {
@@ -309,11 +307,11 @@
return;
}
- for (const auto& effect : enum_range<hardware::vibrator::Effect>()) {
+ for (const auto& effect : enum_range<Effect>()) {
if (std::find(supported.begin(), supported.end(), effect) == supported.end()) {
continue;
}
- for (const auto& strength : enum_range<hardware::vibrator::EffectStrength>()) {
+ for (const auto& strength : enum_range<EffectStrength>()) {
b->Args({static_cast<long>(effect), static_cast<long>(strength)});
}
}
@@ -323,18 +321,16 @@
bool hasArgs(const State& state) const { return this->getOtherArg(state, 0) >= 0; }
auto getEffect(const State& state) const {
- return static_cast<hardware::vibrator::Effect>(this->getOtherArg(state, 0));
+ return static_cast<Effect>(this->getOtherArg(state, 0));
}
auto getStrength(const State& state) const {
- return static_cast<hardware::vibrator::EffectStrength>(this->getOtherArg(state, 1));
+ return static_cast<EffectStrength>(this->getOtherArg(state, 1));
}
};
BENCHMARK_WRAPPER(VibratorEffectsBench, alwaysOnEnable, {
- auto result = mController.getCapabilities();
-
- if (!hasCapabilities(result, vibrator::Capabilities::ALWAYS_ON_CONTROL, state)) {
+ if (!hasCapabilities(vibrator::Capabilities::ALWAYS_ON_CONTROL, state)) {
return;
}
if (!hasArgs(state)) {
@@ -347,18 +343,20 @@
for (auto _ : state) {
state.ResumeTiming();
- auto ret = mController.alwaysOnEnable(id, effect, strength);
+ auto ret = halCall<void>(mController, [&](auto hal) {
+ return hal->alwaysOnEnable(id, effect, strength);
+ });
state.PauseTiming();
if (checkHalResult(ret, state)) {
- checkHalResult(mController.alwaysOnDisable(id), state);
+ auto disableResult =
+ halCall<void>(mController, [&](auto hal) { return hal->alwaysOnDisable(id); });
+ checkHalResult(disableResult, state);
}
}
});
BENCHMARK_WRAPPER(VibratorEffectsBench, alwaysOnDisable, {
- auto result = mController.getCapabilities();
-
- if (!hasCapabilities(result, vibrator::Capabilities::ALWAYS_ON_CONTROL, state)) {
+ if (!hasCapabilities(vibrator::Capabilities::ALWAYS_ON_CONTROL, state)) {
return;
}
if (!hasArgs(state)) {
@@ -371,11 +369,16 @@
for (auto _ : state) {
state.PauseTiming();
- if (!checkHalResult(mController.alwaysOnEnable(id, effect, strength), state)) {
+ auto enableResult = halCall<void>(mController, [&](auto hal) {
+ return hal->alwaysOnEnable(id, effect, strength);
+ });
+ if (!checkHalResult(enableResult, state)) {
continue;
}
state.ResumeTiming();
- checkHalResult(mController.alwaysOnDisable(id), state);
+ auto disableResult =
+ halCall<void>(mController, [&](auto hal) { return hal->alwaysOnDisable(id); });
+ checkHalResult(disableResult, state);
}
});
@@ -390,10 +393,12 @@
for (auto _ : state) {
state.ResumeTiming();
- auto ret = mController.performEffect(effect, strength, callback);
+ auto ret = halCall<std::chrono::milliseconds>(mController, [&](auto hal) {
+ return hal->performEffect(effect, strength, callback);
+ });
state.PauseTiming();
if (checkHalResult(ret, state)) {
- checkHalResult(mController.off(), state);
+ turnVibratorOff(state);
}
}
});
@@ -402,12 +407,12 @@
public:
static void DefaultArgs(Benchmark* b) {
vibrator::HalController controller;
- auto primitivesResult = controller.getSupportedPrimitives();
+ auto primitivesResult = controller.getInfo().supportedPrimitives;
if (!primitivesResult.isOk()) {
return;
}
- std::vector<hardware::vibrator::CompositePrimitive> supported = primitivesResult.value();
+ std::vector<CompositePrimitive> supported = primitivesResult.value();
b->ArgNames({"Primitive"});
if (supported.empty()) {
@@ -415,11 +420,11 @@
return;
}
- for (const auto& primitive : enum_range<hardware::vibrator::CompositePrimitive>()) {
+ for (const auto& primitive : enum_range<CompositePrimitive>()) {
if (std::find(supported.begin(), supported.end(), primitive) == supported.end()) {
continue;
}
- if (primitive == hardware::vibrator::CompositePrimitive::NOOP) {
+ if (primitive == CompositePrimitive::NOOP) {
continue;
}
b->Args({static_cast<long>(primitive)});
@@ -430,35 +435,35 @@
bool hasArgs(const State& state) const { return this->getOtherArg(state, 0) >= 0; }
auto getPrimitive(const State& state) const {
- return static_cast<hardware::vibrator::CompositePrimitive>(this->getOtherArg(state, 0));
+ return static_cast<CompositePrimitive>(this->getOtherArg(state, 0));
}
};
BENCHMARK_WRAPPER(VibratorPrimitivesBench, performComposedEffect, {
- auto result = mController.getCapabilities();
-
- if (!hasCapabilities(result, vibrator::Capabilities::COMPOSE_EFFECTS, state)) {
+ if (!hasCapabilities(vibrator::Capabilities::COMPOSE_EFFECTS, state)) {
return;
}
if (!hasArgs(state)) {
return;
}
- hardware::vibrator::CompositeEffect effect;
+ CompositeEffect effect;
effect.primitive = getPrimitive(state);
effect.scale = 1.0f;
effect.delayMs = static_cast<int32_t>(0);
- std::vector<hardware::vibrator::CompositeEffect> effects;
+ std::vector<CompositeEffect> effects;
effects.push_back(effect);
auto callback = []() {};
for (auto _ : state) {
state.ResumeTiming();
- auto ret = mController.performComposedEffect(effects, callback);
+ auto ret = halCall<std::chrono::milliseconds>(mController, [&](auto hal) {
+ return hal->performComposedEffect(effects, callback);
+ });
state.PauseTiming();
if (checkHalResult(ret, state)) {
- checkHalResult(mController.off(), state);
+ turnVibratorOff(state);
}
}
});
diff --git a/services/vibratorservice/include/vibratorservice/VibratorHalController.h b/services/vibratorservice/include/vibratorservice/VibratorHalController.h
index f884ff0..354e56c 100644
--- a/services/vibratorservice/include/vibratorservice/VibratorHalController.h
+++ b/services/vibratorservice/include/vibratorservice/VibratorHalController.h
@@ -29,19 +29,22 @@
std::shared_ptr<HalWrapper> connectHal(std::shared_ptr<CallbackScheduler> scheduler);
+template <typename T>
+using HalFunction = std::function<T(std::shared_ptr<HalWrapper>)>;
+
// Controller for Vibrator HAL handle.
// This relies on a given Connector to connect to the underlying Vibrator HAL service and reconnects
// after each failed api call. This also ensures connecting to the service is thread-safe.
-class HalController : public HalWrapper {
+class HalController {
public:
using Connector =
std::function<std::shared_ptr<HalWrapper>(std::shared_ptr<CallbackScheduler>)>;
HalController() : HalController(std::make_shared<CallbackScheduler>(), &connectHal) {}
HalController(std::shared_ptr<CallbackScheduler> callbackScheduler, Connector connector)
- : HalWrapper(std::move(callbackScheduler)),
- mConnector(connector),
- mConnectedHal(nullptr) {}
+ : mConnector(connector),
+ mConnectedHal(nullptr),
+ mCallbackScheduler(std::move(callbackScheduler)) {}
virtual ~HalController() = default;
/* Connects to the newest HAL version available, possibly waiting for the registered service to
@@ -51,53 +54,65 @@
*/
virtual bool init();
- /* reloads HAL service instance without waiting. This relies on the HAL version found by init()
+ /* Reloads HAL service instance without waiting. This relies on the HAL version found by init()
* to rapidly reconnect to the specific HAL service, or defers to init() if it was never called.
*/
- virtual void tryReconnect() override;
+ virtual void tryReconnect();
- virtual HalResult<void> ping() override;
- HalResult<void> on(std::chrono::milliseconds timeout,
- const std::function<void()>& completionCallback) final override;
- HalResult<void> off() final override;
+ /* Returns info loaded from the connected HAL. This allows partial results to be returned if any
+ * of the Info fields has failed, but also retried on any failure.
+ */
+ Info getInfo() {
+ static Info sDefaultInfo = InfoCache().get();
+ return apply<Info>([](std::shared_ptr<HalWrapper> hal) { return hal->getInfo(); },
+ sDefaultInfo, "getInfo");
+ }
- HalResult<void> setAmplitude(float amplitude) final override;
- HalResult<void> setExternalControl(bool enabled) final override;
-
- HalResult<void> alwaysOnEnable(int32_t id, hardware::vibrator::Effect effect,
- hardware::vibrator::EffectStrength strength) final override;
- HalResult<void> alwaysOnDisable(int32_t id) final override;
-
- HalResult<Capabilities> getCapabilities() final override;
- HalResult<std::vector<hardware::vibrator::Effect>> getSupportedEffects() final override;
- HalResult<std::vector<hardware::vibrator::CompositePrimitive>> getSupportedPrimitives()
- final override;
-
- HalResult<float> getResonantFrequency() final override;
- HalResult<float> getQFactor() final override;
-
- HalResult<std::chrono::milliseconds> performEffect(
- hardware::vibrator::Effect effect, hardware::vibrator::EffectStrength strength,
- const std::function<void()>& completionCallback) final override;
-
- HalResult<std::chrono::milliseconds> performComposedEffect(
- const std::vector<hardware::vibrator::CompositeEffect>& primitiveEffects,
- const std::function<void()>& completionCallback) final override;
+ /* Calls given HAL function, applying automatic retries to reconnect with the HAL when the
+ * result has failed. Parameter functionName is for logging purposes.
+ */
+ template <typename T>
+ HalResult<T> doWithRetry(const HalFunction<HalResult<T>>& halFn, const char* functionName) {
+ return apply(halFn, HalResult<T>::unsupported(), functionName);
+ }
private:
+ static constexpr int MAX_RETRIES = 1;
+
Connector mConnector;
std::mutex mConnectedHalMutex;
// Shared pointer to allow local copies to be used by different threads.
std::shared_ptr<HalWrapper> mConnectedHal GUARDED_BY(mConnectedHalMutex);
+ // Shared pointer to allow copies to be passed to possible recreated mConnectedHal instances.
+ std::shared_ptr<CallbackScheduler> mCallbackScheduler;
+ /* Calls given HAL function, applying automatic retries to reconnect with the HAL when the
+ * result has failed. Given default value is returned when no HAL is available, and given
+ * function name is for logging purposes.
+ */
template <typename T>
- HalResult<T> processHalResult(HalResult<T> result, const char* functionName);
+ T apply(const HalFunction<T>& halFn, T defaultValue, const char* functionName) {
+ if (!init()) {
+ ALOGV("Skipped %s because Vibrator HAL is not available", functionName);
+ return defaultValue;
+ }
+ std::shared_ptr<HalWrapper> hal;
+ {
+ std::lock_guard<std::mutex> lock(mConnectedHalMutex);
+ hal = mConnectedHal;
+ }
- template <typename T>
- using hal_fn = std::function<HalResult<T>(std::shared_ptr<HalWrapper>)>;
+ for (int i = 0; i < MAX_RETRIES; i++) {
+ T result = halFn(hal);
+ if (result.checkAndLogFailure(functionName)) {
+ tryReconnect();
+ } else {
+ return result;
+ }
+ }
- template <typename T>
- HalResult<T> apply(hal_fn<T>& halFn, const char* functionName);
+ return halFn(hal);
+ }
};
}; // namespace vibrator
diff --git a/services/vibratorservice/include/vibratorservice/VibratorHalWrapper.h b/services/vibratorservice/include/vibratorservice/VibratorHalWrapper.h
index 667702d..8720d9d 100644
--- a/services/vibratorservice/include/vibratorservice/VibratorHalWrapper.h
+++ b/services/vibratorservice/include/vibratorservice/VibratorHalWrapper.h
@@ -48,7 +48,7 @@
if (status.isOk()) {
return HalResult<T>::ok(data);
}
- return HalResult<T>::failed(std::string(status.toString8().c_str()));
+ return HalResult<T>::failed(status.toString8().c_str());
}
static HalResult<T> fromStatus(hardware::vibrator::V1_0::Status status, T data);
@@ -61,10 +61,18 @@
// This will throw std::bad_optional_access if this result is not ok.
const T& value() const { return mValue.value(); }
+ const T valueOr(T&& defaultValue) const { return mValue.value_or(defaultValue); }
bool isOk() const { return !mUnsupported && mValue.has_value(); }
bool isFailed() const { return !mUnsupported && !mValue.has_value(); }
bool isUnsupported() const { return mUnsupported; }
const char* errorMessage() const { return mErrorMessage.c_str(); }
+ bool checkAndLogFailure(const char* functionName) const {
+ if (isFailed()) {
+ ALOGE("%s failed: %s", functionName, errorMessage());
+ return true;
+ }
+ return false;
+ }
private:
std::optional<T> mValue;
@@ -96,6 +104,13 @@
bool isFailed() const { return !mUnsupported && mFailed; }
bool isUnsupported() const { return mUnsupported; }
const char* errorMessage() const { return mErrorMessage.c_str(); }
+ bool checkAndLogFailure(const char* functionName) const {
+ if (isFailed()) {
+ ALOGE("%s failed: %s", functionName, errorMessage());
+ return true;
+ }
+ return false;
+ }
private:
std::string mErrorMessage;
@@ -133,7 +148,8 @@
EXTERNAL_CONTROL = hardware::vibrator::IVibrator::CAP_EXTERNAL_CONTROL,
EXTERNAL_AMPLITUDE_CONTROL = hardware::vibrator::IVibrator::CAP_EXTERNAL_AMPLITUDE_CONTROL,
COMPOSE_EFFECTS = hardware::vibrator::IVibrator::CAP_COMPOSE_EFFECTS,
- ALWAYS_ON_CONTROL = hardware::vibrator::IVibrator::CAP_ALWAYS_ON_CONTROL
+ COMPOSE_PWLE_EFFECTS = hardware::vibrator::IVibrator::CAP_COMPOSE_PWLE_EFFECTS,
+ ALWAYS_ON_CONTROL = hardware::vibrator::IVibrator::CAP_ALWAYS_ON_CONTROL,
};
inline Capabilities operator|(Capabilities lhs, Capabilities rhs) {
@@ -156,6 +172,62 @@
// -------------------------------------------------------------------------------------------------
+class Info {
+public:
+ const HalResult<Capabilities> capabilities;
+ const HalResult<std::vector<hardware::vibrator::Effect>> supportedEffects;
+ const HalResult<std::vector<hardware::vibrator::Braking>> supportedBraking;
+ const HalResult<std::vector<hardware::vibrator::CompositePrimitive>> supportedPrimitives;
+ const HalResult<std::vector<std::chrono::milliseconds>> primitiveDurations;
+ const HalResult<float> minFrequency;
+ const HalResult<float> resonantFrequency;
+ const HalResult<float> frequencyResolution;
+ const HalResult<float> qFactor;
+ const HalResult<std::vector<float>> maxAmplitudes;
+
+ bool checkAndLogFailure(const char*) const {
+ return capabilities.checkAndLogFailure("getCapabilities") ||
+ supportedEffects.checkAndLogFailure("getSupportedEffects") ||
+ supportedBraking.checkAndLogFailure("getSupportedBraking") ||
+ supportedPrimitives.checkAndLogFailure("getSupportedPrimitives") ||
+ primitiveDurations.checkAndLogFailure("getPrimitiveDuration") ||
+ minFrequency.checkAndLogFailure("getMinFrequency") ||
+ resonantFrequency.checkAndLogFailure("getResonantFrequency") ||
+ frequencyResolution.checkAndLogFailure("getFrequencyResolution") ||
+ qFactor.checkAndLogFailure("getQFactor") ||
+ maxAmplitudes.checkAndLogFailure("getMaxAmplitudes");
+ }
+};
+
+class InfoCache {
+public:
+ Info get() {
+ return {mCapabilities, mSupportedEffects, mSupportedBraking,
+ mSupportedPrimitives, mPrimitiveDurations, mMinFrequency,
+ mResonantFrequency, mFrequencyResolution, mQFactor,
+ mMaxAmplitudes};
+ }
+
+private:
+ static const constexpr char* MSG = "never loaded";
+ HalResult<Capabilities> mCapabilities = HalResult<Capabilities>::failed(MSG);
+ HalResult<std::vector<hardware::vibrator::Effect>> mSupportedEffects =
+ HalResult<std::vector<hardware::vibrator::Effect>>::failed(MSG);
+ HalResult<std::vector<hardware::vibrator::Braking>> mSupportedBraking =
+ HalResult<std::vector<hardware::vibrator::Braking>>::failed(MSG);
+ HalResult<std::vector<hardware::vibrator::CompositePrimitive>> mSupportedPrimitives =
+ HalResult<std::vector<hardware::vibrator::CompositePrimitive>>::failed(MSG);
+ HalResult<std::vector<std::chrono::milliseconds>> mPrimitiveDurations =
+ HalResult<std::vector<std::chrono::milliseconds>>::failed(MSG);
+ HalResult<float> mMinFrequency = HalResult<float>::failed(MSG);
+ HalResult<float> mResonantFrequency = HalResult<float>::failed(MSG);
+ HalResult<float> mFrequencyResolution = HalResult<float>::failed(MSG);
+ HalResult<float> mQFactor = HalResult<float>::failed(MSG);
+ HalResult<std::vector<float>> mMaxAmplitudes = HalResult<std::vector<float>>::failed(MSG);
+
+ friend class HalWrapper;
+};
+
// Wrapper for Vibrator HAL handlers.
class HalWrapper {
public:
@@ -168,6 +240,8 @@
*/
virtual void tryReconnect() = 0;
+ Info getInfo();
+
virtual HalResult<void> ping() = 0;
virtual HalResult<void> on(std::chrono::milliseconds timeout,
const std::function<void()>& completionCallback) = 0;
@@ -180,25 +254,43 @@
hardware::vibrator::EffectStrength strength) = 0;
virtual HalResult<void> alwaysOnDisable(int32_t id) = 0;
- virtual HalResult<Capabilities> getCapabilities() = 0;
- virtual HalResult<std::vector<hardware::vibrator::Effect>> getSupportedEffects() = 0;
- virtual HalResult<std::vector<hardware::vibrator::CompositePrimitive>>
- getSupportedPrimitives() = 0;
-
- virtual HalResult<float> getResonantFrequency() = 0;
- virtual HalResult<float> getQFactor() = 0;
-
virtual HalResult<std::chrono::milliseconds> performEffect(
hardware::vibrator::Effect effect, hardware::vibrator::EffectStrength strength,
const std::function<void()>& completionCallback) = 0;
virtual HalResult<std::chrono::milliseconds> performComposedEffect(
- const std::vector<hardware::vibrator::CompositeEffect>& primitiveEffects,
- const std::function<void()>& completionCallback) = 0;
+ const std::vector<hardware::vibrator::CompositeEffect>& primitives,
+ const std::function<void()>& completionCallback);
+
+ virtual HalResult<void> performPwleEffect(
+ const std::vector<hardware::vibrator::PrimitivePwle>& primitives,
+ const std::function<void()>& completionCallback);
protected:
// Shared pointer to allow CallbackScheduler to outlive this wrapper.
const std::shared_ptr<CallbackScheduler> mCallbackScheduler;
+
+ // Load and cache vibrator info, returning cached result is present.
+ HalResult<Capabilities> getCapabilities();
+ HalResult<std::vector<std::chrono::milliseconds>> getPrimitiveDurations();
+
+ // Request vibrator info to HAL skipping cache.
+ virtual HalResult<Capabilities> getCapabilitiesInternal() = 0;
+ virtual HalResult<std::vector<hardware::vibrator::Effect>> getSupportedEffectsInternal();
+ virtual HalResult<std::vector<hardware::vibrator::Braking>> getSupportedBrakingInternal();
+ virtual HalResult<std::vector<hardware::vibrator::CompositePrimitive>>
+ getSupportedPrimitivesInternal();
+ virtual HalResult<std::vector<std::chrono::milliseconds>> getPrimitiveDurationsInternal(
+ const std::vector<hardware::vibrator::CompositePrimitive>& supportedPrimitives);
+ virtual HalResult<float> getMinFrequencyInternal();
+ virtual HalResult<float> getResonantFrequencyInternal();
+ virtual HalResult<float> getFrequencyResolutionInternal();
+ virtual HalResult<float> getQFactorInternal();
+ virtual HalResult<std::vector<float>> getMaxAmplitudesInternal();
+
+private:
+ std::mutex mInfoMutex;
+ InfoCache mInfoCache GUARDED_BY(mInfoMutex);
};
// Wrapper for the AIDL Vibrator HAL.
@@ -230,52 +322,38 @@
hardware::vibrator::EffectStrength strength) override final;
HalResult<void> alwaysOnDisable(int32_t id) override final;
- HalResult<Capabilities> getCapabilities() override final;
- HalResult<std::vector<hardware::vibrator::Effect>> getSupportedEffects() override final;
- HalResult<std::vector<hardware::vibrator::CompositePrimitive>> getSupportedPrimitives()
- override final;
-
- HalResult<float> getResonantFrequency() override final;
- HalResult<float> getQFactor() override final;
-
HalResult<std::chrono::milliseconds> performEffect(
hardware::vibrator::Effect effect, hardware::vibrator::EffectStrength strength,
const std::function<void()>& completionCallback) override final;
HalResult<std::chrono::milliseconds> performComposedEffect(
- const std::vector<hardware::vibrator::CompositeEffect>& primitiveEffects,
+ const std::vector<hardware::vibrator::CompositeEffect>& primitives,
const std::function<void()>& completionCallback) override final;
+ HalResult<void> performPwleEffect(
+ const std::vector<hardware::vibrator::PrimitivePwle>& primitives,
+ const std::function<void()>& completionCallback) override final;
+
+protected:
+ HalResult<Capabilities> getCapabilitiesInternal() override final;
+ HalResult<std::vector<hardware::vibrator::Effect>> getSupportedEffectsInternal() override final;
+ HalResult<std::vector<hardware::vibrator::Braking>> getSupportedBrakingInternal()
+ override final;
+ HalResult<std::vector<hardware::vibrator::CompositePrimitive>> getSupportedPrimitivesInternal()
+ override final;
+ HalResult<std::vector<std::chrono::milliseconds>> getPrimitiveDurationsInternal(
+ const std::vector<hardware::vibrator::CompositePrimitive>& supportedPrimitives)
+ override final;
+ HalResult<float> getMinFrequencyInternal() override final;
+ HalResult<float> getResonantFrequencyInternal() override final;
+ HalResult<float> getFrequencyResolutionInternal() override final;
+ HalResult<float> getQFactorInternal() override final;
+ HalResult<std::vector<float>> getMaxAmplitudesInternal() override final;
+
private:
const std::function<HalResult<sp<hardware::vibrator::IVibrator>>()> mReconnectFn;
std::mutex mHandleMutex;
- std::mutex mCapabilitiesMutex;
- std::mutex mSupportedEffectsMutex;
- std::mutex mSupportedPrimitivesMutex;
- std::mutex mResonantFrequencyMutex;
- std::mutex mQFactorMutex;
sp<hardware::vibrator::IVibrator> mHandle GUARDED_BY(mHandleMutex);
- std::optional<Capabilities> mCapabilities GUARDED_BY(mCapabilitiesMutex);
- std::optional<std::vector<hardware::vibrator::Effect>> mSupportedEffects
- GUARDED_BY(mSupportedEffectsMutex);
- std::optional<std::vector<hardware::vibrator::CompositePrimitive>> mSupportedPrimitives
- GUARDED_BY(mSupportedPrimitivesMutex);
- std::vector<std::optional<std::chrono::milliseconds>> mPrimitiveDurations
- GUARDED_BY(mSupportedPrimitivesMutex);
- std::optional<float> mResonantFrequency GUARDED_BY(mResonantFrequencyMutex);
- std::optional<float> mQFactor GUARDED_BY(mQFactorMutex);
-
- // Loads and caches from IVibrator.
- HalResult<std::chrono::milliseconds> getPrimitiveDuration(
- hardware::vibrator::CompositePrimitive primitive);
-
- // Loads directly from IVibrator handle, skipping caches.
- HalResult<Capabilities> getCapabilitiesInternal();
- HalResult<std::vector<hardware::vibrator::Effect>> getSupportedEffectsInternal();
- HalResult<std::vector<hardware::vibrator::CompositePrimitive>> getSupportedPrimitivesInternal();
-
- HalResult<float> getResonantFrequencyInternal();
- HalResult<float> getQFactorInternal();
sp<hardware::vibrator::IVibrator> getHal();
};
@@ -302,26 +380,11 @@
hardware::vibrator::EffectStrength strength) override final;
HalResult<void> alwaysOnDisable(int32_t id) override final;
- HalResult<Capabilities> getCapabilities() override final;
- HalResult<std::vector<hardware::vibrator::Effect>> getSupportedEffects() override final;
- HalResult<std::vector<hardware::vibrator::CompositePrimitive>> getSupportedPrimitives()
- override final;
-
- HalResult<float> getResonantFrequency() override final;
- HalResult<float> getQFactor() override final;
-
- HalResult<std::chrono::milliseconds> performComposedEffect(
- const std::vector<hardware::vibrator::CompositeEffect>& primitiveEffects,
- const std::function<void()>& completionCallback) override final;
-
protected:
std::mutex mHandleMutex;
- std::mutex mCapabilitiesMutex;
sp<I> mHandle GUARDED_BY(mHandleMutex);
- std::optional<Capabilities> mCapabilities GUARDED_BY(mCapabilitiesMutex);
- // Loads directly from IVibrator handle, skipping the mCapabilities cache.
- virtual HalResult<Capabilities> getCapabilitiesInternal();
+ virtual HalResult<Capabilities> getCapabilitiesInternal() override;
template <class T>
using perform_fn =
diff --git a/services/vibratorservice/test/VibratorHalControllerTest.cpp b/services/vibratorservice/test/VibratorHalControllerTest.cpp
index e438d78..279496a 100644
--- a/services/vibratorservice/test/VibratorHalControllerTest.cpp
+++ b/services/vibratorservice/test/VibratorHalControllerTest.cpp
@@ -31,8 +31,6 @@
#include "test_utils.h"
-using android::hardware::vibrator::CompositeEffect;
-using android::hardware::vibrator::CompositePrimitive;
using android::hardware::vibrator::Effect;
using android::hardware::vibrator::EffectStrength;
@@ -42,7 +40,11 @@
using namespace std::chrono_literals;
using namespace testing;
-static constexpr int MAX_ATTEMPTS = 2;
+static const auto ON_FN = [](std::shared_ptr<vibrator::HalWrapper> hal) {
+ return hal->on(10ms, []() {});
+};
+static const auto OFF_FN = [](std::shared_ptr<vibrator::HalWrapper> hal) { return hal->off(); };
+static const auto PING_FN = [](std::shared_ptr<vibrator::HalWrapper> hal) { return hal->ping(); };
// -------------------------------------------------------------------------------------------------
@@ -63,21 +65,11 @@
MOCK_METHOD(vibrator::HalResult<void>, alwaysOnEnable,
(int32_t id, Effect effect, EffectStrength strength), (override));
MOCK_METHOD(vibrator::HalResult<void>, alwaysOnDisable, (int32_t id), (override));
- MOCK_METHOD(vibrator::HalResult<vibrator::Capabilities>, getCapabilities, (), (override));
- MOCK_METHOD(vibrator::HalResult<std::vector<Effect>>, getSupportedEffects, (), (override));
- MOCK_METHOD(vibrator::HalResult<std::vector<CompositePrimitive>>, getSupportedPrimitives, (),
- (override));
-
- MOCK_METHOD(vibrator::HalResult<float>, getResonantFrequency, (), (override));
- MOCK_METHOD(vibrator::HalResult<float>, getQFactor, (), (override));
-
MOCK_METHOD(vibrator::HalResult<milliseconds>, performEffect,
(Effect effect, EffectStrength strength,
const std::function<void()>& completionCallback),
(override));
- MOCK_METHOD(vibrator::HalResult<milliseconds>, performComposedEffect,
- (const std::vector<CompositeEffect>& primitiveEffects,
- const std::function<void()>& completionCallback),
+ MOCK_METHOD(vibrator::HalResult<vibrator::Capabilities>, getCapabilitiesInternal, (),
(override));
vibrator::CallbackScheduler* getCallbackScheduler() { return mCallbackScheduler.get(); }
@@ -104,64 +96,6 @@
int32_t mConnectCounter;
std::shared_ptr<MockHalWrapper> mMockHal;
std::unique_ptr<vibrator::HalController> mController;
-
- void setHalExpectations(int32_t cardinality, std::vector<CompositeEffect> compositeEffects,
- vibrator::HalResult<void> voidResult,
- vibrator::HalResult<vibrator::Capabilities> capabilitiesResult,
- vibrator::HalResult<std::vector<Effect>> effectsResult,
- vibrator::HalResult<std::vector<CompositePrimitive>> primitivesResult,
- vibrator::HalResult<float> resonantFrequencyResult,
- vibrator::HalResult<float> qFactorResult,
- vibrator::HalResult<milliseconds> durationResult) {
- EXPECT_CALL(*mMockHal.get(), ping())
- .Times(Exactly(cardinality))
- .WillRepeatedly(Return(voidResult));
- EXPECT_CALL(*mMockHal.get(), on(Eq(10ms), _))
- .Times(Exactly(cardinality))
- .WillRepeatedly(Return(voidResult));
- EXPECT_CALL(*mMockHal.get(), off())
- .Times(Exactly(cardinality))
- .WillRepeatedly(Return(voidResult));
- EXPECT_CALL(*mMockHal.get(), setAmplitude(Eq(1.0f)))
- .Times(Exactly(cardinality))
- .WillRepeatedly(Return(voidResult));
- EXPECT_CALL(*mMockHal.get(), setExternalControl(Eq(true)))
- .Times(Exactly(cardinality))
- .WillRepeatedly(Return(voidResult));
- EXPECT_CALL(*mMockHal.get(),
- alwaysOnEnable(Eq(1), Eq(Effect::CLICK), Eq(EffectStrength::LIGHT)))
- .Times(Exactly(cardinality))
- .WillRepeatedly(Return(voidResult));
- EXPECT_CALL(*mMockHal.get(), alwaysOnDisable(Eq(1)))
- .Times(Exactly(cardinality))
- .WillRepeatedly(Return(voidResult));
- EXPECT_CALL(*mMockHal.get(), getCapabilities())
- .Times(Exactly(cardinality))
- .WillRepeatedly(Return(capabilitiesResult));
- EXPECT_CALL(*mMockHal.get(), getSupportedEffects())
- .Times(Exactly(cardinality))
- .WillRepeatedly(Return(effectsResult));
- EXPECT_CALL(*mMockHal.get(), getSupportedPrimitives())
- .Times(Exactly(cardinality))
- .WillRepeatedly(Return(primitivesResult));
- EXPECT_CALL(*mMockHal.get(), getResonantFrequency())
- .Times(Exactly(cardinality))
- .WillRepeatedly(Return(resonantFrequencyResult));
- EXPECT_CALL(*mMockHal.get(), getQFactor())
- .Times(Exactly(cardinality))
- .WillRepeatedly(Return(qFactorResult));
- EXPECT_CALL(*mMockHal.get(), performEffect(Eq(Effect::CLICK), Eq(EffectStrength::LIGHT), _))
- .Times(Exactly(cardinality))
- .WillRepeatedly(Return(durationResult));
- EXPECT_CALL(*mMockHal.get(), performComposedEffect(Eq(compositeEffects), _))
- .Times(Exactly(cardinality))
- .WillRepeatedly(Return(durationResult));
-
- if (cardinality > 1) {
- // One reconnection call after each failure.
- EXPECT_CALL(*mMockHal.get(), tryReconnect()).Times(Exactly(14 * cardinality));
- }
- }
};
// -------------------------------------------------------------------------------------------------
@@ -175,127 +109,52 @@
ASSERT_EQ(1, mConnectCounter);
}
+TEST_F(VibratorHalControllerTest, TestGetInfoRetriesOnAnyFailure) {
+ EXPECT_CALL(*mMockHal.get(), tryReconnect()).Times(Exactly(1));
+ EXPECT_CALL(*mMockHal.get(), getCapabilitiesInternal())
+ .Times(Exactly(2))
+ .WillOnce(Return(vibrator::HalResult<vibrator::Capabilities>::failed("message")))
+ .WillRepeatedly(Return(vibrator::HalResult<vibrator::Capabilities>::ok(
+ vibrator::Capabilities::ON_CALLBACK)));
+
+ auto result = mController->getInfo();
+ ASSERT_FALSE(result.capabilities.isFailed());
+
+ ASSERT_EQ(1, mConnectCounter);
+}
+
TEST_F(VibratorHalControllerTest, TestApiCallsAreForwardedToHal) {
- std::vector<Effect> effects = {Effect::CLICK, Effect::TICK};
- std::vector<CompositePrimitive> primitives = {CompositePrimitive::CLICK,
- CompositePrimitive::THUD};
- constexpr float F0 = 123.f;
- constexpr float Q_FACTOR = 12.f;
- const std::vector<CompositeEffect> compositeEffects =
- {vibrator::TestFactory::createCompositeEffect(CompositePrimitive::SPIN, 100ms, 0.5f),
- vibrator::TestFactory::createCompositeEffect(CompositePrimitive::THUD, 1000ms, 1.0f)};
+ EXPECT_CALL(*mMockHal.get(), on(_, _))
+ .Times(Exactly(1))
+ .WillRepeatedly(Return(vibrator::HalResult<void>::ok()));
- setHalExpectations(/* cardinality= */ 1, compositeEffects, vibrator::HalResult<void>::ok(),
- vibrator::HalResult<vibrator::Capabilities>::ok(
- vibrator::Capabilities::ON_CALLBACK),
- vibrator::HalResult<std::vector<Effect>>::ok(effects),
- vibrator::HalResult<std::vector<CompositePrimitive>>::ok(primitives),
- vibrator::HalResult<float>::ok(F0), vibrator::HalResult<float>::ok(Q_FACTOR),
- vibrator::HalResult<milliseconds>::ok(100ms));
-
- ASSERT_TRUE(mController->ping().isOk());
- ASSERT_TRUE(mController->on(10ms, []() {}).isOk());
- ASSERT_TRUE(mController->off().isOk());
- ASSERT_TRUE(mController->setAmplitude(1.0f).isOk());
- ASSERT_TRUE(mController->setExternalControl(true).isOk());
- ASSERT_TRUE(mController->alwaysOnEnable(1, Effect::CLICK, EffectStrength::LIGHT).isOk());
- ASSERT_TRUE(mController->alwaysOnDisable(1).isOk());
-
- auto getCapabilitiesResult = mController->getCapabilities();
- ASSERT_TRUE(getCapabilitiesResult.isOk());
- ASSERT_EQ(vibrator::Capabilities::ON_CALLBACK, getCapabilitiesResult.value());
-
- auto getSupportedEffectsResult = mController->getSupportedEffects();
- ASSERT_TRUE(getSupportedEffectsResult.isOk());
- ASSERT_EQ(effects, getSupportedEffectsResult.value());
-
- auto getSupportedPrimitivesResult = mController->getSupportedPrimitives();
- ASSERT_TRUE(getSupportedPrimitivesResult.isOk());
- ASSERT_EQ(primitives, getSupportedPrimitivesResult.value());
-
- auto getResonantFrequencyResult = mController->getResonantFrequency();
- ASSERT_TRUE(getResonantFrequencyResult.isOk());
- ASSERT_EQ(F0, getResonantFrequencyResult.value());
-
- auto getQFactorResult = mController->getQFactor();
- ASSERT_TRUE(getQFactorResult.isOk());
- ASSERT_EQ(Q_FACTOR, getQFactorResult.value());
-
- auto performEffectResult =
- mController->performEffect(Effect::CLICK, EffectStrength::LIGHT, []() {});
- ASSERT_TRUE(performEffectResult.isOk());
- ASSERT_EQ(100ms, performEffectResult.value());
-
- auto performComposedEffectResult =
- mController->performComposedEffect(compositeEffects, []() {});
- ASSERT_TRUE(performComposedEffectResult.isOk());
- ASSERT_EQ(100ms, performComposedEffectResult.value());
+ auto result = mController->doWithRetry<void>(ON_FN, "on");
+ ASSERT_TRUE(result.isOk());
ASSERT_EQ(1, mConnectCounter);
}
TEST_F(VibratorHalControllerTest, TestUnsupportedApiResultDoNotResetHalConnection) {
- setHalExpectations(/* cardinality= */ 1, std::vector<CompositeEffect>(),
- vibrator::HalResult<void>::unsupported(),
- vibrator::HalResult<vibrator::Capabilities>::unsupported(),
- vibrator::HalResult<std::vector<Effect>>::unsupported(),
- vibrator::HalResult<std::vector<CompositePrimitive>>::unsupported(),
- vibrator::HalResult<float>::unsupported(),
- vibrator::HalResult<float>::unsupported(),
- vibrator::HalResult<milliseconds>::unsupported());
+ EXPECT_CALL(*mMockHal.get(), off())
+ .Times(Exactly(1))
+ .WillRepeatedly(Return(vibrator::HalResult<void>::unsupported()));
ASSERT_EQ(0, mConnectCounter);
-
- ASSERT_TRUE(mController->ping().isUnsupported());
- ASSERT_TRUE(mController->on(10ms, []() {}).isUnsupported());
- ASSERT_TRUE(mController->off().isUnsupported());
- ASSERT_TRUE(mController->setAmplitude(1.0f).isUnsupported());
- ASSERT_TRUE(mController->setExternalControl(true).isUnsupported());
- ASSERT_TRUE(
- mController->alwaysOnEnable(1, Effect::CLICK, EffectStrength::LIGHT).isUnsupported());
- ASSERT_TRUE(mController->alwaysOnDisable(1).isUnsupported());
- ASSERT_TRUE(mController->getCapabilities().isUnsupported());
- ASSERT_TRUE(mController->getSupportedEffects().isUnsupported());
- ASSERT_TRUE(mController->getSupportedPrimitives().isUnsupported());
- ASSERT_TRUE(mController->getResonantFrequency().isUnsupported());
- ASSERT_TRUE(mController->getQFactor().isUnsupported());
- ASSERT_TRUE(mController->performEffect(Effect::CLICK, EffectStrength::LIGHT, []() {})
- .isUnsupported());
- ASSERT_TRUE(mController->performComposedEffect(std::vector<CompositeEffect>(), []() {})
- .isUnsupported());
-
+ auto result = mController->doWithRetry<void>(OFF_FN, "off");
+ ASSERT_TRUE(result.isUnsupported());
ASSERT_EQ(1, mConnectCounter);
}
TEST_F(VibratorHalControllerTest, TestFailedApiResultResetsHalConnection) {
- setHalExpectations(MAX_ATTEMPTS, std::vector<CompositeEffect>(),
- vibrator::HalResult<void>::failed("message"),
- vibrator::HalResult<vibrator::Capabilities>::failed("message"),
- vibrator::HalResult<std::vector<Effect>>::failed("message"),
- vibrator::HalResult<std::vector<CompositePrimitive>>::failed("message"),
- vibrator::HalResult<float>::failed("message"),
- vibrator::HalResult<float>::failed("message"),
- vibrator::HalResult<milliseconds>::failed("message"));
+ EXPECT_CALL(*mMockHal.get(), on(_, _))
+ .Times(Exactly(2))
+ .WillRepeatedly(Return(vibrator::HalResult<void>::failed("message")));
+ EXPECT_CALL(*mMockHal.get(), tryReconnect()).Times(Exactly(1));
ASSERT_EQ(0, mConnectCounter);
- ASSERT_TRUE(mController->ping().isFailed());
- ASSERT_TRUE(mController->on(10ms, []() {}).isFailed());
- ASSERT_TRUE(mController->off().isFailed());
- ASSERT_TRUE(mController->setAmplitude(1.0f).isFailed());
- ASSERT_TRUE(mController->setExternalControl(true).isFailed());
- ASSERT_TRUE(mController->alwaysOnEnable(1, Effect::CLICK, EffectStrength::LIGHT).isFailed());
- ASSERT_TRUE(mController->alwaysOnDisable(1).isFailed());
- ASSERT_TRUE(mController->getCapabilities().isFailed());
- ASSERT_TRUE(mController->getSupportedEffects().isFailed());
- ASSERT_TRUE(mController->getSupportedPrimitives().isFailed());
- ASSERT_TRUE(mController->getResonantFrequency().isFailed());
- ASSERT_TRUE(mController->getQFactor().isFailed());
- ASSERT_TRUE(
- mController->performEffect(Effect::CLICK, EffectStrength::LIGHT, []() {}).isFailed());
- ASSERT_TRUE(
- mController->performComposedEffect(std::vector<CompositeEffect>(), []() {}).isFailed());
-
+ auto result = mController->doWithRetry<void>(ON_FN, "on");
+ ASSERT_TRUE(result.isFailed());
ASSERT_EQ(1, mConnectCounter);
}
@@ -312,7 +171,9 @@
}
ASSERT_EQ(0, mConnectCounter);
- ASSERT_TRUE(mController->ping().isOk());
+
+ auto result = mController->doWithRetry<void>(PING_FN, "ping");
+ ASSERT_TRUE(result.isOk());
ASSERT_EQ(1, mConnectCounter);
}
@@ -325,7 +186,10 @@
std::vector<std::thread> threads;
for (int i = 0; i < 10; i++) {
- threads.push_back(std::thread([&]() { ASSERT_TRUE(mController->ping().isOk()); }));
+ threads.push_back(std::thread([&]() {
+ auto result = mController->doWithRetry<void>(PING_FN, "ping");
+ ASSERT_TRUE(result.isOk());
+ }));
}
std::for_each(threads.begin(), threads.end(), [](std::thread& t) { t.join(); });
@@ -341,33 +205,17 @@
});
ASSERT_EQ(0, mConnectCounter);
- ASSERT_FALSE(mController->init());
- ASSERT_TRUE(mController->ping().isUnsupported());
- ASSERT_TRUE(mController->on(10ms, []() {}).isUnsupported());
- ASSERT_TRUE(mController->off().isUnsupported());
- ASSERT_TRUE(mController->setAmplitude(1.0f).isUnsupported());
- ASSERT_TRUE(mController->setExternalControl(true).isUnsupported());
- ASSERT_TRUE(
- mController->alwaysOnEnable(1, Effect::CLICK, EffectStrength::LIGHT).isUnsupported());
- ASSERT_TRUE(mController->alwaysOnDisable(1).isUnsupported());
- ASSERT_TRUE(mController->getCapabilities().isUnsupported());
- ASSERT_TRUE(mController->getSupportedEffects().isUnsupported());
- ASSERT_TRUE(mController->getSupportedPrimitives().isUnsupported());
- ASSERT_TRUE(mController->getResonantFrequency().isUnsupported());
- ASSERT_TRUE(mController->getQFactor().isUnsupported());
- ASSERT_TRUE(mController->performEffect(Effect::CLICK, EffectStrength::LIGHT, []() {})
- .isUnsupported());
- ASSERT_TRUE(mController->performComposedEffect(std::vector<CompositeEffect>(), []() {})
- .isUnsupported());
+ ASSERT_TRUE(mController->doWithRetry<void>(OFF_FN, "off").isUnsupported());
+ ASSERT_TRUE(mController->doWithRetry<void>(PING_FN, "ping").isUnsupported());
// One connection attempt per api call.
- ASSERT_EQ(15, mConnectCounter);
+ ASSERT_EQ(2, mConnectCounter);
}
TEST_F(VibratorHalControllerTest, TestScheduledCallbackSurvivesReconnection) {
{
InSequence seq;
- EXPECT_CALL(*mMockHal.get(), on(Eq(10ms), _))
+ EXPECT_CALL(*mMockHal.get(), on(_, _))
.Times(Exactly(1))
.WillRepeatedly([&](milliseconds timeout, std::function<void()> callback) {
mMockHal.get()->getCallbackScheduler()->schedule(callback, timeout);
@@ -380,14 +228,14 @@
EXPECT_CALL(*mMockHal.get(), ping())
.Times(Exactly(1))
.WillRepeatedly(Return(vibrator::HalResult<void>::failed("message")));
- EXPECT_CALL(*mMockHal.get(), tryReconnect()).Times(Exactly(1));
}
std::unique_ptr<int32_t> callbackCounter = std::make_unique<int32_t>();
auto callback = vibrator::TestFactory::createCountingCallback(callbackCounter.get());
- ASSERT_TRUE(mController->on(10ms, callback).isOk());
- ASSERT_TRUE(mController->ping().isFailed());
+ auto onFn = [&](std::shared_ptr<vibrator::HalWrapper> hal) { return hal->on(10ms, callback); };
+ ASSERT_TRUE(mController->doWithRetry<void>(onFn, "on").isOk());
+ ASSERT_TRUE(mController->doWithRetry<void>(PING_FN, "ping").isFailed());
mMockHal.reset();
ASSERT_EQ(0, *callbackCounter.get());
diff --git a/services/vibratorservice/test/VibratorHalWrapperAidlTest.cpp b/services/vibratorservice/test/VibratorHalWrapperAidlTest.cpp
index a8ddb99..d1db82b 100644
--- a/services/vibratorservice/test/VibratorHalWrapperAidlTest.cpp
+++ b/services/vibratorservice/test/VibratorHalWrapperAidlTest.cpp
@@ -76,20 +76,19 @@
MOCK_METHOD(Status, compose,
(const std::vector<CompositeEffect>& e, const sp<IVibratorCallback>& cb),
(override));
+ MOCK_METHOD(Status, composePwle,
+ (const std::vector<PrimitivePwle>& e, const sp<IVibratorCallback>& cb), (override));
MOCK_METHOD(Status, getSupportedAlwaysOnEffects, (std::vector<Effect> * ret), (override));
MOCK_METHOD(Status, alwaysOnEnable, (int32_t id, Effect e, EffectStrength s), (override));
MOCK_METHOD(Status, alwaysOnDisable, (int32_t id), (override));
MOCK_METHOD(Status, getQFactor, (float * ret), (override));
MOCK_METHOD(Status, getResonantFrequency, (float * ret), (override));
- MOCK_METHOD(Status, getFrequencyResolution, (float *freqResolutionHz), (override));
- MOCK_METHOD(Status, getFrequencyMinimum, (float *freqMinimumHz), (override));
+ MOCK_METHOD(Status, getFrequencyResolution, (float* ret), (override));
+ MOCK_METHOD(Status, getFrequencyMinimum, (float* ret), (override));
MOCK_METHOD(Status, getBandwidthAmplitudeMap, (std::vector<float> * ret), (override));
- MOCK_METHOD(Status, getPwlePrimitiveDurationMax, (int32_t *durationMs), (override));
- MOCK_METHOD(Status, getPwleCompositionSizeMax, (int32_t *maxSize), (override));
+ MOCK_METHOD(Status, getPwlePrimitiveDurationMax, (int32_t * ret), (override));
+ MOCK_METHOD(Status, getPwleCompositionSizeMax, (int32_t * ret), (override));
MOCK_METHOD(Status, getSupportedBraking, (std::vector<Braking> * ret), (override));
- MOCK_METHOD(Status, composePwle,
- (const std::vector<PrimitivePwle>& e, const sp<IVibratorCallback>& cb),
- (override));
MOCK_METHOD(int32_t, getInterfaceVersion, (), (override));
MOCK_METHOD(std::string, getInterfaceHash, (), (override));
MOCK_METHOD(IBinder*, onAsBinder, (), (override));
@@ -300,204 +299,143 @@
ASSERT_TRUE(mWrapper->alwaysOnDisable(3).isFailed());
}
-TEST_F(VibratorHalWrapperAidlTest, TestGetCapabilitiesDoesNotCacheFailedResult) {
+TEST_F(VibratorHalWrapperAidlTest, TestGetInfoDoesNotCacheFailedResult) {
+ constexpr float F_MIN = 100.f;
+ constexpr float F0 = 123.f;
+ constexpr float F_RESOLUTION = 0.5f;
+ constexpr float Q_FACTOR = 123.f;
+ std::vector<Effect> supportedEffects = {Effect::CLICK, Effect::TICK};
+ std::vector<CompositePrimitive> supportedPrimitives = {CompositePrimitive::CLICK};
+ std::vector<Braking> supportedBraking = {Braking::CLAB};
+ std::vector<float> amplitudes = {0.f, 1.f, 0.f};
+
+ std::vector<std::chrono::milliseconds> primitiveDurations;
+ constexpr auto primitiveRange = enum_range<CompositePrimitive>();
+ constexpr auto primitiveCount = std::distance(primitiveRange.begin(), primitiveRange.end());
+ primitiveDurations.resize(primitiveCount);
+ primitiveDurations[static_cast<size_t>(CompositePrimitive::CLICK)] = 10ms;
+
EXPECT_CALL(*mMockHal.get(), getCapabilities(_))
- .Times(Exactly(3))
- .WillOnce(
- Return(Status::fromExceptionCode(Status::Exception::EX_UNSUPPORTED_OPERATION)))
+ .Times(Exactly(2))
.WillOnce(Return(Status::fromExceptionCode(Status::Exception::EX_SECURITY)))
.WillRepeatedly(DoAll(SetArgPointee<0>(IVibrator::CAP_ON_CALLBACK), Return(Status())));
+ EXPECT_CALL(*mMockHal.get(), getSupportedEffects(_))
+ .Times(Exactly(2))
+ .WillOnce(Return(Status::fromExceptionCode(Status::Exception::EX_SECURITY)))
+ .WillRepeatedly(DoAll(SetArgPointee<0>(supportedEffects), Return(Status())));
+ EXPECT_CALL(*mMockHal.get(), getSupportedBraking(_))
+ .Times(Exactly(2))
+ .WillOnce(Return(Status::fromExceptionCode(Status::Exception::EX_SECURITY)))
+ .WillRepeatedly(DoAll(SetArgPointee<0>(supportedBraking), Return(Status())));
+ EXPECT_CALL(*mMockHal.get(), getSupportedPrimitives(_))
+ .Times(Exactly(2))
+ .WillOnce(Return(Status::fromExceptionCode(Status::Exception::EX_SECURITY)))
+ .WillRepeatedly(DoAll(SetArgPointee<0>(supportedPrimitives), Return(Status())));
+ EXPECT_CALL(*mMockHal.get(), getPrimitiveDuration(Eq(CompositePrimitive::CLICK), _))
+ .Times(Exactly(1))
+ .WillRepeatedly(DoAll(SetArgPointee<1>(10), Return(Status())));
+ EXPECT_CALL(*mMockHal.get(), getFrequencyMinimum(_))
+ .Times(Exactly(2))
+ .WillOnce(Return(Status::fromExceptionCode(Status::Exception::EX_SECURITY)))
+ .WillRepeatedly(DoAll(SetArgPointee<0>(F_MIN), Return(Status())));
+ EXPECT_CALL(*mMockHal.get(), getResonantFrequency(_))
+ .Times(Exactly(2))
+ .WillOnce(Return(Status::fromExceptionCode(Status::Exception::EX_SECURITY)))
+ .WillRepeatedly(DoAll(SetArgPointee<0>(F0), Return(Status())));
+ EXPECT_CALL(*mMockHal.get(), getFrequencyResolution(_))
+ .Times(Exactly(2))
+ .WillOnce(Return(Status::fromExceptionCode(Status::Exception::EX_SECURITY)))
+ .WillRepeatedly(DoAll(SetArgPointee<0>(F_RESOLUTION), Return(Status())));
+ EXPECT_CALL(*mMockHal.get(), getQFactor(_))
+ .Times(Exactly(2))
+ .WillOnce(Return(Status::fromExceptionCode(Status::Exception::EX_SECURITY)))
+ .WillRepeatedly(DoAll(SetArgPointee<0>(Q_FACTOR), Return(Status())));
+ EXPECT_CALL(*mMockHal.get(), getBandwidthAmplitudeMap(_))
+ .Times(Exactly(2))
+ .WillOnce(Return(Status::fromExceptionCode(Status::Exception::EX_SECURITY)))
+ .WillRepeatedly(DoAll(SetArgPointee<0>(amplitudes), Return(Status())));
- ASSERT_TRUE(mWrapper->getCapabilities().isUnsupported());
- ASSERT_TRUE(mWrapper->getCapabilities().isFailed());
+ vibrator::Info failed = mWrapper->getInfo();
+ ASSERT_TRUE(failed.capabilities.isFailed());
+ ASSERT_TRUE(failed.supportedEffects.isFailed());
+ ASSERT_TRUE(failed.supportedBraking.isFailed());
+ ASSERT_TRUE(failed.supportedPrimitives.isFailed());
+ ASSERT_TRUE(failed.primitiveDurations.isFailed());
+ ASSERT_TRUE(failed.minFrequency.isFailed());
+ ASSERT_TRUE(failed.resonantFrequency.isFailed());
+ ASSERT_TRUE(failed.frequencyResolution.isFailed());
+ ASSERT_TRUE(failed.qFactor.isFailed());
+ ASSERT_TRUE(failed.maxAmplitudes.isFailed());
- auto result = mWrapper->getCapabilities();
- ASSERT_TRUE(result.isOk());
- ASSERT_EQ(vibrator::Capabilities::ON_CALLBACK, result.value());
+ vibrator::Info successful = mWrapper->getInfo();
+ ASSERT_EQ(vibrator::Capabilities::ON_CALLBACK, successful.capabilities.value());
+ ASSERT_EQ(supportedEffects, successful.supportedEffects.value());
+ ASSERT_EQ(supportedBraking, successful.supportedBraking.value());
+ ASSERT_EQ(supportedPrimitives, successful.supportedPrimitives.value());
+ ASSERT_EQ(primitiveDurations, successful.primitiveDurations.value());
+ ASSERT_EQ(F_MIN, successful.minFrequency.value());
+ ASSERT_EQ(F0, successful.resonantFrequency.value());
+ ASSERT_EQ(F_RESOLUTION, successful.frequencyResolution.value());
+ ASSERT_EQ(Q_FACTOR, successful.qFactor.value());
+ ASSERT_EQ(amplitudes, successful.maxAmplitudes.value());
}
-TEST_F(VibratorHalWrapperAidlTest, TestGetCapabilitiesCachesResult) {
+TEST_F(VibratorHalWrapperAidlTest, TestGetInfoCachesResult) {
+ constexpr float F_MIN = 100.f;
+ constexpr float F0 = 123.f;
+ std::vector<Effect> supportedEffects = {Effect::CLICK, Effect::TICK};
+
EXPECT_CALL(*mMockHal.get(), getCapabilities(_))
.Times(Exactly(1))
.WillRepeatedly(DoAll(SetArgPointee<0>(IVibrator::CAP_ON_CALLBACK), Return(Status())));
-
- std::vector<std::thread> threads;
- for (int i = 0; i < 10; i++) {
- threads.push_back(std::thread([&]() {
- auto result = mWrapper->getCapabilities();
- ASSERT_TRUE(result.isOk());
- ASSERT_EQ(vibrator::Capabilities::ON_CALLBACK, result.value());
- }));
- }
- std::for_each(threads.begin(), threads.end(), [](std::thread& t) { t.join(); });
-
- auto result = mWrapper->getCapabilities();
- ASSERT_TRUE(result.isOk());
- ASSERT_EQ(vibrator::Capabilities::ON_CALLBACK, result.value());
-}
-
-TEST_F(VibratorHalWrapperAidlTest, TestGetSupportedEffectsDoesNotCacheFailedResult) {
- std::vector<Effect> supportedEffects;
- supportedEffects.push_back(Effect::CLICK);
- supportedEffects.push_back(Effect::TICK);
-
- EXPECT_CALL(*mMockHal.get(), getSupportedEffects(_))
- .Times(Exactly(3))
- .WillOnce(
- Return(Status::fromExceptionCode(Status::Exception::EX_UNSUPPORTED_OPERATION)))
- .WillOnce(Return(Status::fromExceptionCode(Status::Exception::EX_SECURITY)))
- .WillRepeatedly(DoAll(SetArgPointee<0>(supportedEffects), Return(Status())));
-
- ASSERT_TRUE(mWrapper->getSupportedEffects().isUnsupported());
- ASSERT_TRUE(mWrapper->getSupportedEffects().isFailed());
-
- auto result = mWrapper->getSupportedEffects();
- ASSERT_TRUE(result.isOk());
- ASSERT_EQ(supportedEffects, result.value());
-}
-
-TEST_F(VibratorHalWrapperAidlTest, TestGetSupportedEffectsCachesResult) {
- std::vector<Effect> supportedEffects;
- supportedEffects.push_back(Effect::CLICK);
- supportedEffects.push_back(Effect::TICK);
-
EXPECT_CALL(*mMockHal.get(), getSupportedEffects(_))
.Times(Exactly(1))
.WillRepeatedly(DoAll(SetArgPointee<0>(supportedEffects), Return(Status())));
-
- std::vector<std::thread> threads;
- for (int i = 0; i < 10; i++) {
- threads.push_back(std::thread([&]() {
- auto result = mWrapper->getSupportedEffects();
- ASSERT_TRUE(result.isOk());
- ASSERT_EQ(supportedEffects, result.value());
- }));
- }
- std::for_each(threads.begin(), threads.end(), [](std::thread& t) { t.join(); });
-
- auto result = mWrapper->getSupportedEffects();
- ASSERT_TRUE(result.isOk());
- ASSERT_EQ(supportedEffects, result.value());
-}
-
-TEST_F(VibratorHalWrapperAidlTest, TestGetSupportedPrimitivesDoesNotCacheFailedResult) {
- std::vector<CompositePrimitive> supportedPrimitives;
- supportedPrimitives.push_back(CompositePrimitive::CLICK);
- supportedPrimitives.push_back(CompositePrimitive::THUD);
-
- EXPECT_CALL(*mMockHal.get(), getSupportedPrimitives(_))
- .Times(Exactly(3))
- .WillOnce(
- Return(Status::fromExceptionCode(Status::Exception::EX_UNSUPPORTED_OPERATION)))
- .WillOnce(Return(Status::fromExceptionCode(Status::Exception::EX_SECURITY)))
- .WillRepeatedly(DoAll(SetArgPointee<0>(supportedPrimitives), Return(Status())));
-
- ASSERT_TRUE(mWrapper->getSupportedPrimitives().isUnsupported());
- ASSERT_TRUE(mWrapper->getSupportedPrimitives().isFailed());
-
- auto result = mWrapper->getSupportedPrimitives();
- ASSERT_TRUE(result.isOk());
- ASSERT_EQ(supportedPrimitives, result.value());
-}
-
-TEST_F(VibratorHalWrapperAidlTest, TestGetSupportedPrimitivesCachesResult) {
- std::vector<CompositePrimitive> supportedPrimitives;
- supportedPrimitives.push_back(CompositePrimitive::CLICK);
- supportedPrimitives.push_back(CompositePrimitive::THUD);
-
+ EXPECT_CALL(*mMockHal.get(), getQFactor(_))
+ .Times(Exactly(1))
+ .WillRepeatedly(
+ Return(Status::fromExceptionCode(Status::Exception::EX_UNSUPPORTED_OPERATION)));
EXPECT_CALL(*mMockHal.get(), getSupportedPrimitives(_))
.Times(Exactly(1))
- .WillRepeatedly(DoAll(SetArgPointee<0>(supportedPrimitives), Return(Status())));
-
- std::vector<std::thread> threads;
- for (int i = 0; i < 10; i++) {
- threads.push_back(std::thread([&]() {
- auto result = mWrapper->getSupportedPrimitives();
- ASSERT_TRUE(result.isOk());
- ASSERT_EQ(supportedPrimitives, result.value());
- }));
- }
- std::for_each(threads.begin(), threads.end(), [](std::thread& t) { t.join(); });
-
- auto result = mWrapper->getSupportedPrimitives();
- ASSERT_TRUE(result.isOk());
- ASSERT_EQ(supportedPrimitives, result.value());
-}
-
-TEST_F(VibratorHalWrapperAidlTest, TestGetResonantFrequencyDoesNotCacheFailedResult) {
- constexpr float F0 = 123.f;
- EXPECT_CALL(*mMockHal.get(), getResonantFrequency(_))
- .Times(Exactly(3))
- .WillOnce(
- Return(Status::fromExceptionCode(Status::Exception::EX_UNSUPPORTED_OPERATION)))
- .WillOnce(Return(Status::fromExceptionCode(Status::Exception::EX_SECURITY)))
- .WillRepeatedly(DoAll(SetArgPointee<0>(F0), Return(Status())));
-
- ASSERT_TRUE(mWrapper->getResonantFrequency().isUnsupported());
- ASSERT_TRUE(mWrapper->getResonantFrequency().isFailed());
-
- auto result = mWrapper->getResonantFrequency();
- ASSERT_TRUE(result.isOk());
- ASSERT_EQ(F0, result.value());
-}
-
-TEST_F(VibratorHalWrapperAidlTest, TestGetResonantFrequencyCachesResult) {
- constexpr float F0 = 123.f;
+ .WillRepeatedly(
+ Return(Status::fromExceptionCode(Status::Exception::EX_UNSUPPORTED_OPERATION)));
+ EXPECT_CALL(*mMockHal.get(), getFrequencyMinimum(_))
+ .Times(Exactly(1))
+ .WillRepeatedly(DoAll(SetArgPointee<0>(F_MIN), Return(Status())));
EXPECT_CALL(*mMockHal.get(), getResonantFrequency(_))
.Times(Exactly(1))
.WillRepeatedly(DoAll(SetArgPointee<0>(F0), Return(Status())));
-
- std::vector<std::thread> threads;
- for (int i = 0; i < 10; i++) {
- threads.push_back(std::thread([&]() {
- auto result = mWrapper->getResonantFrequency();
- ASSERT_TRUE(result.isOk());
- ASSERT_EQ(F0, result.value());
- }));
- }
- std::for_each(threads.begin(), threads.end(), [](std::thread& t) { t.join(); });
-
- auto result = mWrapper->getResonantFrequency();
- ASSERT_TRUE(result.isOk());
- ASSERT_EQ(F0, result.value());
-}
-
-TEST_F(VibratorHalWrapperAidlTest, TestGetQFactorDoesNotCacheFailedResult) {
- constexpr float Q_FACTOR = 123.f;
- EXPECT_CALL(*mMockHal.get(), getQFactor(_))
- .Times(Exactly(3))
- .WillOnce(
- Return(Status::fromExceptionCode(Status::Exception::EX_UNSUPPORTED_OPERATION)))
- .WillOnce(Return(Status::fromExceptionCode(Status::Exception::EX_SECURITY)))
- .WillRepeatedly(DoAll(SetArgPointee<0>(Q_FACTOR), Return(Status())));
-
- ASSERT_TRUE(mWrapper->getQFactor().isUnsupported());
- ASSERT_TRUE(mWrapper->getQFactor().isFailed());
-
- auto result = mWrapper->getQFactor();
- ASSERT_TRUE(result.isOk());
- ASSERT_EQ(Q_FACTOR, result.value());
-}
-
-TEST_F(VibratorHalWrapperAidlTest, TestGetQFactorCachesResult) {
- constexpr float Q_FACTOR = 123.f;
- EXPECT_CALL(*mMockHal.get(), getQFactor(_))
+ EXPECT_CALL(*mMockHal.get(), getFrequencyResolution(_))
.Times(Exactly(1))
- .WillRepeatedly(DoAll(SetArgPointee<0>(Q_FACTOR), Return(Status())));
+ .WillRepeatedly(
+ Return(Status::fromExceptionCode(Status::Exception::EX_UNSUPPORTED_OPERATION)));
+ EXPECT_CALL(*mMockHal.get(), getBandwidthAmplitudeMap(_))
+ .Times(Exactly(1))
+ .WillRepeatedly(
+ Return(Status::fromExceptionCode(Status::Exception::EX_UNSUPPORTED_OPERATION)));
+ EXPECT_CALL(*mMockHal.get(), getSupportedBraking(_))
+ .Times(Exactly(1))
+ .WillRepeatedly(
+ Return(Status::fromExceptionCode(Status::Exception::EX_UNSUPPORTED_OPERATION)));
std::vector<std::thread> threads;
for (int i = 0; i < 10; i++) {
- threads.push_back(std::thread([&]() {
- auto result = mWrapper->getQFactor();
- ASSERT_TRUE(result.isOk());
- ASSERT_EQ(Q_FACTOR, result.value());
- }));
+ threads.push_back(
+ std::thread([&]() { ASSERT_TRUE(mWrapper->getInfo().capabilities.isOk()); }));
}
std::for_each(threads.begin(), threads.end(), [](std::thread& t) { t.join(); });
- auto result = mWrapper->getQFactor();
- ASSERT_TRUE(result.isOk());
- ASSERT_EQ(Q_FACTOR, result.value());
+ vibrator::Info info = mWrapper->getInfo();
+ ASSERT_EQ(vibrator::Capabilities::ON_CALLBACK, info.capabilities.value());
+ ASSERT_EQ(supportedEffects, info.supportedEffects.value());
+ ASSERT_TRUE(info.supportedBraking.isUnsupported());
+ ASSERT_TRUE(info.supportedPrimitives.isUnsupported());
+ ASSERT_TRUE(info.primitiveDurations.isUnsupported());
+ ASSERT_EQ(F_MIN, info.minFrequency.value());
+ ASSERT_EQ(F0, info.resonantFrequency.value());
+ ASSERT_TRUE(info.frequencyResolution.isUnsupported());
+ ASSERT_TRUE(info.qFactor.isUnsupported());
+ ASSERT_TRUE(info.maxAmplitudes.isUnsupported());
}
TEST_F(VibratorHalWrapperAidlTest, TestPerformEffectWithCallbackSupport) {
@@ -580,6 +518,9 @@
}
TEST_F(VibratorHalWrapperAidlTest, TestPerformComposedEffect) {
+ std::vector<CompositePrimitive> supportedPrimitives = {CompositePrimitive::CLICK,
+ CompositePrimitive::SPIN,
+ CompositePrimitive::THUD};
std::vector<CompositeEffect> emptyEffects, singleEffect, multipleEffects;
singleEffect.push_back(
vibrator::TestFactory::createCompositeEffect(CompositePrimitive::CLICK, 10ms, 0.0f));
@@ -590,24 +531,26 @@
{
InSequence seq;
- EXPECT_CALL(*mMockHal.get(), compose(Eq(emptyEffects), _))
+ EXPECT_CALL(*mMockHal.get(), getSupportedPrimitives(_))
.Times(Exactly(1))
- .WillRepeatedly(DoAll(TriggerCallbackInArg1(), Return(Status())));
-
+ .WillRepeatedly(DoAll(SetArgPointee<0>(supportedPrimitives), Return(Status())));
EXPECT_CALL(*mMockHal.get(), getPrimitiveDuration(Eq(CompositePrimitive::CLICK), _))
.Times(Exactly(1))
.WillRepeatedly(DoAll(SetArgPointee<1>(1), Return(Status())));
- EXPECT_CALL(*mMockHal.get(), compose(Eq(singleEffect), _))
- .Times(Exactly(1))
- .WillRepeatedly(Return(
- Status::fromExceptionCode(Status::Exception::EX_UNSUPPORTED_OPERATION)));
-
EXPECT_CALL(*mMockHal.get(), getPrimitiveDuration(Eq(CompositePrimitive::SPIN), _))
.Times(Exactly(1))
.WillRepeatedly(DoAll(SetArgPointee<1>(2), Return(Status())));
EXPECT_CALL(*mMockHal.get(), getPrimitiveDuration(Eq(CompositePrimitive::THUD), _))
.Times(Exactly(1))
.WillRepeatedly(DoAll(SetArgPointee<1>(3), Return(Status())));
+
+ EXPECT_CALL(*mMockHal.get(), compose(Eq(emptyEffects), _))
+ .Times(Exactly(1))
+ .WillRepeatedly(DoAll(TriggerCallbackInArg1(), Return(Status())));
+ EXPECT_CALL(*mMockHal.get(), compose(Eq(singleEffect), _))
+ .Times(Exactly(1))
+ .WillRepeatedly(Return(
+ Status::fromExceptionCode(Status::Exception::EX_UNSUPPORTED_OPERATION)));
EXPECT_CALL(*mMockHal.get(), compose(Eq(multipleEffects), _))
.Times(Exactly(1))
.WillRepeatedly(Return(Status::fromExceptionCode(Status::Exception::EX_SECURITY)));
@@ -633,38 +576,91 @@
}
TEST_F(VibratorHalWrapperAidlTest, TestPerformComposedCachesPrimitiveDurationsAndIgnoresFailures) {
+ std::vector<CompositePrimitive> supportedPrimitives = {CompositePrimitive::SPIN,
+ CompositePrimitive::THUD};
std::vector<CompositeEffect> multipleEffects;
multipleEffects.push_back(
vibrator::TestFactory::createCompositeEffect(CompositePrimitive::SPIN, 10ms, 0.5f));
multipleEffects.push_back(
vibrator::TestFactory::createCompositeEffect(CompositePrimitive::THUD, 100ms, 1.0f));
- EXPECT_CALL(*mMockHal.get(), getPrimitiveDuration(Eq(CompositePrimitive::SPIN), _))
- .Times(Exactly(1))
- .WillRepeatedly(DoAll(SetArgPointee<1>(1), Return(Status())));
- EXPECT_CALL(*mMockHal.get(), getPrimitiveDuration(Eq(CompositePrimitive::THUD), _))
- .Times(Exactly(2))
- .WillOnce(Return(Status::fromExceptionCode(Status::Exception::EX_SECURITY)))
- .WillRepeatedly(DoAll(SetArgPointee<1>(2), Return(Status())));
- EXPECT_CALL(*mMockHal.get(), compose(Eq(multipleEffects), _))
- .Times(Exactly(3))
- .WillRepeatedly(DoAll(TriggerCallbackInArg1(), Return(Status())));
+ {
+ InSequence seq;
+ EXPECT_CALL(*mMockHal.get(), getSupportedPrimitives(_))
+ .Times(Exactly(1))
+ .WillRepeatedly(DoAll(SetArgPointee<0>(supportedPrimitives), Return(Status())));
+ EXPECT_CALL(*mMockHal.get(), getPrimitiveDuration(Eq(CompositePrimitive::SPIN), _))
+ .Times(Exactly(1))
+ .WillRepeatedly(DoAll(SetArgPointee<1>(2), Return(Status())));
+ EXPECT_CALL(*mMockHal.get(), getPrimitiveDuration(Eq(CompositePrimitive::THUD), _))
+ .Times(Exactly(1))
+ .WillRepeatedly(Return(Status::fromExceptionCode(Status::Exception::EX_SECURITY)));
+ EXPECT_CALL(*mMockHal.get(), compose(Eq(multipleEffects), _))
+ .Times(Exactly(1))
+ .WillRepeatedly(DoAll(TriggerCallbackInArg1(), Return(Status())));
+
+ EXPECT_CALL(*mMockHal.get(), getPrimitiveDuration(Eq(CompositePrimitive::SPIN), _))
+ .Times(Exactly(1))
+ .WillRepeatedly(DoAll(SetArgPointee<1>(2), Return(Status())));
+ EXPECT_CALL(*mMockHal.get(), getPrimitiveDuration(Eq(CompositePrimitive::THUD), _))
+ .Times(Exactly(1))
+ .WillRepeatedly(DoAll(SetArgPointee<1>(2), Return(Status())));
+ EXPECT_CALL(*mMockHal.get(), compose(Eq(multipleEffects), _))
+ .Times(Exactly(2))
+ .WillRepeatedly(DoAll(TriggerCallbackInArg1(), Return(Status())));
+ }
std::unique_ptr<int32_t> callbackCounter = std::make_unique<int32_t>();
auto callback = vibrator::TestFactory::createCountingCallback(callbackCounter.get());
auto result = mWrapper->performComposedEffect(multipleEffects, callback);
ASSERT_TRUE(result.isOk());
- ASSERT_EQ(111ms, result.value()); // Failed primitive duration counted as 0.
+ ASSERT_EQ(112ms, result.value()); // Failed primitive durations counted as 1.
ASSERT_EQ(1, *callbackCounter.get());
result = mWrapper->performComposedEffect(multipleEffects, callback);
ASSERT_TRUE(result.isOk());
- ASSERT_EQ(113ms, result.value()); // Second fetch succeeds and returns primitive duration.
+ ASSERT_EQ(114ms, result.value()); // Second fetch succeeds and returns primitive duration.
ASSERT_EQ(2, *callbackCounter.get());
result = mWrapper->performComposedEffect(multipleEffects, callback);
ASSERT_TRUE(result.isOk());
- ASSERT_EQ(113ms, result.value()); // Cached durations not fetched again, same duration returned.
+ ASSERT_EQ(114ms, result.value()); // Cached durations not fetched again, same duration returned.
ASSERT_EQ(3, *callbackCounter.get());
}
+
+TEST_F(VibratorHalWrapperAidlTest, TestPerformPwleEffect) {
+ std::vector<PrimitivePwle> emptyPrimitives, multiplePrimitives;
+ multiplePrimitives.push_back(vibrator::TestFactory::createActivePwle(0, 1, 0, 1, 10ms));
+ multiplePrimitives.push_back(vibrator::TestFactory::createBrakingPwle(Braking::NONE, 100ms));
+
+ {
+ InSequence seq;
+ EXPECT_CALL(*mMockHal.get(), composePwle(Eq(emptyPrimitives), _))
+ .Times(Exactly(1))
+ .WillRepeatedly(Return(
+ Status::fromExceptionCode(Status::Exception::EX_UNSUPPORTED_OPERATION)));
+ EXPECT_CALL(*mMockHal.get(), composePwle(Eq(multiplePrimitives), _))
+ .Times(Exactly(2))
+ .WillOnce(Return(Status::fromExceptionCode(Status::Exception::EX_SECURITY)))
+ .WillRepeatedly(DoAll(TriggerCallbackInArg1(), Return(Status())));
+ ;
+ }
+
+ std::unique_ptr<int32_t> callbackCounter = std::make_unique<int32_t>();
+ auto callback = vibrator::TestFactory::createCountingCallback(callbackCounter.get());
+
+ auto result = mWrapper->performPwleEffect(emptyPrimitives, callback);
+ ASSERT_TRUE(result.isUnsupported());
+ // Callback not triggered on failure
+ ASSERT_EQ(0, *callbackCounter.get());
+
+ result = mWrapper->performPwleEffect(multiplePrimitives, callback);
+ ASSERT_TRUE(result.isFailed());
+ // Callback not triggered for unsupported
+ ASSERT_EQ(0, *callbackCounter.get());
+
+ result = mWrapper->performPwleEffect(multiplePrimitives, callback);
+ ASSERT_TRUE(result.isOk());
+ ASSERT_EQ(1, *callbackCounter.get());
+}
diff --git a/services/vibratorservice/test/VibratorHalWrapperHidlV1_0Test.cpp b/services/vibratorservice/test/VibratorHalWrapperHidlV1_0Test.cpp
index 33c47cf..96b2582 100644
--- a/services/vibratorservice/test/VibratorHalWrapperHidlV1_0Test.cpp
+++ b/services/vibratorservice/test/VibratorHalWrapperHidlV1_0Test.cpp
@@ -31,11 +31,13 @@
namespace V1_0 = android::hardware::vibrator::V1_0;
+using android::hardware::vibrator::Braking;
using android::hardware::vibrator::CompositeEffect;
using android::hardware::vibrator::CompositePrimitive;
using android::hardware::vibrator::Effect;
using android::hardware::vibrator::EffectStrength;
using android::hardware::vibrator::IVibrator;
+using android::hardware::vibrator::PrimitivePwle;
using namespace android;
using namespace std::chrono_literals;
@@ -188,7 +190,7 @@
ASSERT_TRUE(mWrapper->alwaysOnDisable(1).isUnsupported());
}
-TEST_F(VibratorHalWrapperHidlV1_0Test, TestGetCapabilitiesDoesNotCacheFailedResult) {
+TEST_F(VibratorHalWrapperHidlV1_0Test, TestGetInfoDoesNotCacheFailedResult) {
EXPECT_CALL(*mMockHal.get(), supportsAmplitudeControl())
.Times(Exactly(2))
.WillOnce([]() {
@@ -196,49 +198,52 @@
})
.WillRepeatedly([]() { return hardware::Return<bool>(true); });
- ASSERT_TRUE(mWrapper->getCapabilities().isFailed());
+ ASSERT_TRUE(mWrapper->getInfo().capabilities.isFailed());
- auto result = mWrapper->getCapabilities();
- ASSERT_TRUE(result.isOk());
- ASSERT_EQ(vibrator::Capabilities::AMPLITUDE_CONTROL, result.value());
+ vibrator::Info info = mWrapper->getInfo();
+ ASSERT_EQ(vibrator::Capabilities::AMPLITUDE_CONTROL, info.capabilities.value());
+ ASSERT_TRUE(info.supportedEffects.isUnsupported());
+ ASSERT_TRUE(info.supportedBraking.isUnsupported());
+ ASSERT_TRUE(info.supportedPrimitives.isUnsupported());
+ ASSERT_TRUE(info.primitiveDurations.isUnsupported());
+ ASSERT_TRUE(info.minFrequency.isUnsupported());
+ ASSERT_TRUE(info.resonantFrequency.isUnsupported());
+ ASSERT_TRUE(info.frequencyResolution.isUnsupported());
+ ASSERT_TRUE(info.qFactor.isUnsupported());
+ ASSERT_TRUE(info.maxAmplitudes.isUnsupported());
}
-TEST_F(VibratorHalWrapperHidlV1_0Test, TestGetCapabilitiesWithoutAmplitudeControl) {
+TEST_F(VibratorHalWrapperHidlV1_0Test, TestGetInfoWithoutAmplitudeControl) {
EXPECT_CALL(*mMockHal.get(), supportsAmplitudeControl()).Times(Exactly(1)).WillRepeatedly([]() {
return hardware::Return<bool>(false);
});
- auto result = mWrapper->getCapabilities();
- ASSERT_TRUE(result.isOk());
- ASSERT_EQ(vibrator::Capabilities::NONE, result.value());
+ ASSERT_EQ(vibrator::Capabilities::NONE, mWrapper->getInfo().capabilities.value());
}
-TEST_F(VibratorHalWrapperHidlV1_0Test, TestGetCapabilitiesCachesResult) {
+TEST_F(VibratorHalWrapperHidlV1_0Test, TestGetInfoCachesResult) {
EXPECT_CALL(*mMockHal.get(), supportsAmplitudeControl()).Times(Exactly(1)).WillRepeatedly([]() {
return hardware::Return<bool>(true);
});
std::vector<std::thread> threads;
for (int i = 0; i < 10; i++) {
- threads.push_back(std::thread([&]() {
- auto result = mWrapper->getCapabilities();
- ASSERT_TRUE(result.isOk());
- ASSERT_EQ(vibrator::Capabilities::AMPLITUDE_CONTROL, result.value());
- }));
+ threads.push_back(
+ std::thread([&]() { ASSERT_TRUE(mWrapper->getInfo().capabilities.isOk()); }));
}
std::for_each(threads.begin(), threads.end(), [](std::thread& t) { t.join(); });
- auto result = mWrapper->getCapabilities();
- ASSERT_TRUE(result.isOk());
- ASSERT_EQ(vibrator::Capabilities::AMPLITUDE_CONTROL, result.value());
-}
-
-TEST_F(VibratorHalWrapperHidlV1_0Test, TestGetSupportedEffectsUnsupported) {
- ASSERT_TRUE(mWrapper->getSupportedEffects().isUnsupported());
-}
-
-TEST_F(VibratorHalWrapperHidlV1_0Test, TestGetSupportedPrimitivesUnsupported) {
- ASSERT_TRUE(mWrapper->getSupportedPrimitives().isUnsupported());
+ vibrator::Info info = mWrapper->getInfo();
+ ASSERT_EQ(vibrator::Capabilities::AMPLITUDE_CONTROL, info.capabilities.value());
+ ASSERT_TRUE(info.supportedEffects.isUnsupported());
+ ASSERT_TRUE(info.supportedBraking.isUnsupported());
+ ASSERT_TRUE(info.supportedPrimitives.isUnsupported());
+ ASSERT_TRUE(info.primitiveDurations.isUnsupported());
+ ASSERT_TRUE(info.minFrequency.isUnsupported());
+ ASSERT_TRUE(info.resonantFrequency.isUnsupported());
+ ASSERT_TRUE(info.frequencyResolution.isUnsupported());
+ ASSERT_TRUE(info.qFactor.isUnsupported());
+ ASSERT_TRUE(info.maxAmplitudes.isUnsupported());
}
TEST_F(VibratorHalWrapperHidlV1_0Test, TestPerformEffect) {
@@ -325,3 +330,18 @@
// No callback is triggered.
ASSERT_EQ(0, *callbackCounter.get());
}
+
+TEST_F(VibratorHalWrapperHidlV1_0Test, TestPerformPwleEffectUnsupported) {
+ std::vector<PrimitivePwle> emptyPrimitives, multiplePrimitives;
+ multiplePrimitives.push_back(vibrator::TestFactory::createActivePwle(0, 1, 0, 1, 10ms));
+ multiplePrimitives.push_back(vibrator::TestFactory::createBrakingPwle(Braking::NONE, 100ms));
+
+ std::unique_ptr<int32_t> callbackCounter = std::make_unique<int32_t>();
+ auto callback = vibrator::TestFactory::createCountingCallback(callbackCounter.get());
+
+ ASSERT_TRUE(mWrapper->performPwleEffect(emptyPrimitives, callback).isUnsupported());
+ ASSERT_TRUE(mWrapper->performPwleEffect(multiplePrimitives, callback).isUnsupported());
+
+ // No callback is triggered.
+ ASSERT_EQ(0, *callbackCounter.get());
+}
diff --git a/services/vibratorservice/test/VibratorHalWrapperHidlV1_3Test.cpp b/services/vibratorservice/test/VibratorHalWrapperHidlV1_3Test.cpp
index 08652f4..a6f1a74 100644
--- a/services/vibratorservice/test/VibratorHalWrapperHidlV1_3Test.cpp
+++ b/services/vibratorservice/test/VibratorHalWrapperHidlV1_3Test.cpp
@@ -105,7 +105,7 @@
ASSERT_TRUE(mWrapper->setExternalControl(false).isFailed());
}
-TEST_F(VibratorHalWrapperHidlV1_3Test, TestGetCapabilitiesSuccessful) {
+TEST_F(VibratorHalWrapperHidlV1_3Test, TestGetInfoSuccessful) {
{
InSequence seq;
EXPECT_CALL(*mMockHal.get(), supportsAmplitudeControl())
@@ -116,14 +116,12 @@
});
}
- auto result = mWrapper->getCapabilities();
- ASSERT_TRUE(result.isOk());
ASSERT_EQ(vibrator::Capabilities::AMPLITUDE_CONTROL | vibrator::Capabilities::EXTERNAL_CONTROL |
vibrator::Capabilities::EXTERNAL_AMPLITUDE_CONTROL,
- result.value());
+ mWrapper->getInfo().capabilities.value());
}
-TEST_F(VibratorHalWrapperHidlV1_3Test, TestGetCapabilitiesOnlyAmplitudeControl) {
+TEST_F(VibratorHalWrapperHidlV1_3Test, TestGetInfoOnlyAmplitudeControl) {
{
InSequence seq;
EXPECT_CALL(*mMockHal.get(), supportsAmplitudeControl()).Times(Exactly(1)).WillOnce([]() {
@@ -134,12 +132,10 @@
});
}
- auto result = mWrapper->getCapabilities();
- ASSERT_TRUE(result.isOk());
- ASSERT_EQ(vibrator::Capabilities::AMPLITUDE_CONTROL, result.value());
+ ASSERT_EQ(vibrator::Capabilities::AMPLITUDE_CONTROL, mWrapper->getInfo().capabilities.value());
}
-TEST_F(VibratorHalWrapperHidlV1_3Test, TestGetCapabilitiesOnlyExternalControl) {
+TEST_F(VibratorHalWrapperHidlV1_3Test, TestGetInfoOnlyExternalControl) {
{
InSequence seq;
EXPECT_CALL(*mMockHal.get(), supportsAmplitudeControl()).Times(Exactly(1)).WillOnce([]() {
@@ -150,12 +146,10 @@
});
}
- auto result = mWrapper->getCapabilities();
- ASSERT_TRUE(result.isOk());
- ASSERT_EQ(vibrator::Capabilities::EXTERNAL_CONTROL, result.value());
+ ASSERT_EQ(vibrator::Capabilities::EXTERNAL_CONTROL, mWrapper->getInfo().capabilities.value());
}
-TEST_F(VibratorHalWrapperHidlV1_3Test, TestGetCapabilitiesNone) {
+TEST_F(VibratorHalWrapperHidlV1_3Test, TestGetInfoNoCapabilities) {
{
InSequence seq;
EXPECT_CALL(*mMockHal.get(), supportsAmplitudeControl())
@@ -166,12 +160,10 @@
});
}
- auto result = mWrapper->getCapabilities();
- ASSERT_TRUE(result.isOk());
- ASSERT_EQ(vibrator::Capabilities::NONE, result.value());
+ ASSERT_EQ(vibrator::Capabilities::NONE, mWrapper->getInfo().capabilities.value());
}
-TEST_F(VibratorHalWrapperHidlV1_3Test, TestGetCapabilitiesFailed) {
+TEST_F(VibratorHalWrapperHidlV1_3Test, TestGetInfoFailed) {
{
InSequence seq;
EXPECT_CALL(*mMockHal.get(), supportsAmplitudeControl())
@@ -190,11 +182,11 @@
});
}
- ASSERT_TRUE(mWrapper->getCapabilities().isFailed());
- ASSERT_TRUE(mWrapper->getCapabilities().isFailed());
+ ASSERT_TRUE(mWrapper->getInfo().capabilities.isFailed());
+ ASSERT_TRUE(mWrapper->getInfo().capabilities.isFailed());
}
-TEST_F(VibratorHalWrapperHidlV1_3Test, TestGetCapabilitiesCachesResult) {
+TEST_F(VibratorHalWrapperHidlV1_3Test, TestGetInfoCachesResult) {
{
InSequence seq;
EXPECT_CALL(*mMockHal.get(), supportsAmplitudeControl())
@@ -207,20 +199,15 @@
std::vector<std::thread> threads;
for (int i = 0; i < 10; i++) {
- threads.push_back(std::thread([&]() {
- auto result = mWrapper->getCapabilities();
- ASSERT_TRUE(result.isOk());
- ASSERT_EQ(vibrator::Capabilities::AMPLITUDE_CONTROL, result.value());
- }));
+ threads.push_back(
+ std::thread([&]() { ASSERT_TRUE(mWrapper->getInfo().capabilities.isOk()); }));
}
std::for_each(threads.begin(), threads.end(), [](std::thread& t) { t.join(); });
- auto result = mWrapper->getCapabilities();
- ASSERT_TRUE(result.isOk());
- ASSERT_EQ(vibrator::Capabilities::AMPLITUDE_CONTROL, result.value());
+ ASSERT_EQ(vibrator::Capabilities::AMPLITUDE_CONTROL, mWrapper->getInfo().capabilities.value());
}
-TEST_F(VibratorHalWrapperHidlV1_3Test, TestGetCapabilitiesDoesNotCacheFailedResult) {
+TEST_F(VibratorHalWrapperHidlV1_3Test, TestGetInfoDoesNotCacheFailedResult) {
{
InSequence seq;
EXPECT_CALL(*mMockHal.get(), supportsAmplitudeControl())
@@ -247,22 +234,16 @@
}
// Call to supportsAmplitudeControl failed.
- auto result = mWrapper->getCapabilities();
- ASSERT_TRUE(result.isFailed());
+ ASSERT_TRUE(mWrapper->getInfo().capabilities.isFailed());
// Call to supportsExternalControl failed.
- result = mWrapper->getCapabilities();
- ASSERT_TRUE(result.isFailed());
+ ASSERT_TRUE(mWrapper->getInfo().capabilities.isFailed());
// Returns successful result from third call.
- result = mWrapper->getCapabilities();
- ASSERT_TRUE(result.isOk());
- ASSERT_EQ(vibrator::Capabilities::AMPLITUDE_CONTROL, result.value());
+ ASSERT_EQ(vibrator::Capabilities::AMPLITUDE_CONTROL, mWrapper->getInfo().capabilities.value());
// Returns cached successful result.
- result = mWrapper->getCapabilities();
- ASSERT_TRUE(result.isOk());
- ASSERT_EQ(vibrator::Capabilities::AMPLITUDE_CONTROL, result.value());
+ ASSERT_EQ(vibrator::Capabilities::AMPLITUDE_CONTROL, mWrapper->getInfo().capabilities.value());
}
TEST_F(VibratorHalWrapperHidlV1_3Test, TestPerformEffectV1_0) {
diff --git a/services/vibratorservice/test/VibratorManagerHalWrapperAidlTest.cpp b/services/vibratorservice/test/VibratorManagerHalWrapperAidlTest.cpp
index b29376b..3de1576 100644
--- a/services/vibratorservice/test/VibratorManagerHalWrapperAidlTest.cpp
+++ b/services/vibratorservice/test/VibratorManagerHalWrapperAidlTest.cpp
@@ -40,6 +40,8 @@
using namespace android;
using namespace testing;
+static const auto OFF_FN = [](std::shared_ptr<vibrator::HalWrapper> hal) { return hal->off(); };
+
class MockBinder : public BBinder {
public:
MOCK_METHOD(status_t, linkToDeath,
@@ -70,20 +72,19 @@
MOCK_METHOD(Status, compose,
(const std::vector<CompositeEffect>& e, const sp<IVibratorCallback>& cb),
(override));
+ MOCK_METHOD(Status, composePwle,
+ (const std::vector<PrimitivePwle>& e, const sp<IVibratorCallback>& cb), (override));
MOCK_METHOD(Status, getSupportedAlwaysOnEffects, (std::vector<Effect> * ret), (override));
MOCK_METHOD(Status, alwaysOnEnable, (int32_t id, Effect e, EffectStrength s), (override));
MOCK_METHOD(Status, alwaysOnDisable, (int32_t id), (override));
MOCK_METHOD(Status, getQFactor, (float * ret), (override));
MOCK_METHOD(Status, getResonantFrequency, (float * ret), (override));
- MOCK_METHOD(Status, getFrequencyResolution, (float *freqResolutionHz), (override));
- MOCK_METHOD(Status, getFrequencyMinimum, (float *freqMinimumHz), (override));
+ MOCK_METHOD(Status, getFrequencyResolution, (float* ret), (override));
+ MOCK_METHOD(Status, getFrequencyMinimum, (float* ret), (override));
MOCK_METHOD(Status, getBandwidthAmplitudeMap, (std::vector<float> * ret), (override));
- MOCK_METHOD(Status, getPwlePrimitiveDurationMax, (int32_t *durationMs), (override));
- MOCK_METHOD(Status, getPwleCompositionSizeMax, (int32_t *maxSize), (override));
+ MOCK_METHOD(Status, getPwlePrimitiveDurationMax, (int32_t * ret), (override));
+ MOCK_METHOD(Status, getPwleCompositionSizeMax, (int32_t * ret), (override));
MOCK_METHOD(Status, getSupportedBraking, (std::vector<Braking> * ret), (override));
- MOCK_METHOD(Status, composePwle,
- (const std::vector<PrimitivePwle>& e, const sp<IVibratorCallback>& cb),
- (override));
MOCK_METHOD(int32_t, getInterfaceVersion, (), (override));
MOCK_METHOD(std::string, getInterfaceHash, (), (override));
MOCK_METHOD(IBinder*, onAsBinder, (), (override));
@@ -256,12 +257,11 @@
Return(Status::fromExceptionCode(Status::Exception::EX_SECURITY))))
.WillRepeatedly(DoAll(SetArgPointee<1>(mMockVibrator), Return(Status())));
- EXPECT_CALL(*mMockVibrator.get(), getCapabilities(_))
+ EXPECT_CALL(*mMockVibrator.get(), off())
.Times(Exactly(3))
- .WillOnce(
- Return(Status::fromExceptionCode(Status::Exception::EX_UNSUPPORTED_OPERATION)))
.WillOnce(Return(Status::fromExceptionCode(Status::Exception::EX_SECURITY)))
- .WillRepeatedly(DoAll(SetArgPointee<0>(IVibrator::CAP_ON_CALLBACK), Return(Status())));
+ .WillOnce(Return(Status::fromExceptionCode(Status::Exception::EX_SECURITY)))
+ .WillRepeatedly(Return(Status()));
// Get vibrator controller is successful even if first getVibrator.
auto result = mWrapper->getVibrator(kVibratorId);
@@ -271,10 +271,10 @@
auto vibrator = result.value();
// First getVibrator call fails.
ASSERT_FALSE(vibrator->init());
- // First and second getCapabilities calls fail, reload IVibrator with getVibrator.
- ASSERT_FALSE(vibrator->getCapabilities().isOk());
- // Third call to getCapabilities worked after IVibrator reloaded.
- ASSERT_TRUE(vibrator->getCapabilities().isOk());
+ // First and second off() calls fail, reload IVibrator with getVibrator.
+ ASSERT_TRUE(vibrator->doWithRetry<void>(OFF_FN, "off").isFailed());
+ // Third call to off() worked after IVibrator reloaded.
+ ASSERT_TRUE(vibrator->doWithRetry<void>(OFF_FN, "off").isOk());
}
TEST_F(VibratorManagerHalWrapperAidlTest, TestPrepareSynced) {
diff --git a/services/vibratorservice/test/VibratorManagerHalWrapperLegacyTest.cpp b/services/vibratorservice/test/VibratorManagerHalWrapperLegacyTest.cpp
index 6c2aabb..0850ef3 100644
--- a/services/vibratorservice/test/VibratorManagerHalWrapperLegacyTest.cpp
+++ b/services/vibratorservice/test/VibratorManagerHalWrapperLegacyTest.cpp
@@ -41,7 +41,6 @@
virtual ~MockHalController() = default;
MOCK_METHOD(bool, init, (), (override));
- MOCK_METHOD(vibrator::HalResult<void>, ping, (), (override));
MOCK_METHOD(void, tryReconnect, (), (override));
};
@@ -63,13 +62,9 @@
// -------------------------------------------------------------------------------------------------
TEST_F(VibratorManagerHalWrapperLegacyTest, TestPing) {
- EXPECT_CALL(*mMockController.get(), ping())
- .Times(Exactly(2))
- .WillOnce(Return(vibrator::HalResult<void>::failed("message")))
- .WillRepeatedly(Return(vibrator::HalResult<void>::ok()));
+ EXPECT_CALL(*mMockController.get(), init()).Times(Exactly(1)).WillOnce(Return(false));
- ASSERT_TRUE(mWrapper->ping().isFailed());
- ASSERT_TRUE(mWrapper->ping().isOk());
+ ASSERT_TRUE(mWrapper->ping().isUnsupported());
}
TEST_F(VibratorManagerHalWrapperLegacyTest, TestTryReconnect) {
@@ -85,8 +80,7 @@
}
TEST_F(VibratorManagerHalWrapperLegacyTest, TestGetVibratorIds) {
- std::vector<int32_t> expectedIds;
- expectedIds.push_back(0);
+ std::vector<int> expectedIds = {0};
EXPECT_CALL(*mMockController.get(), init())
.Times(Exactly(2))
diff --git a/services/vibratorservice/test/test_utils.h b/services/vibratorservice/test/test_utils.h
index 8d0b22e..1933a11 100644
--- a/services/vibratorservice/test/test_utils.h
+++ b/services/vibratorservice/test/test_utils.h
@@ -25,8 +25,12 @@
namespace vibrator {
+using ::android::hardware::vibrator::ActivePwle;
+using ::android::hardware::vibrator::Braking;
+using ::android::hardware::vibrator::BrakingPwle;
using ::android::hardware::vibrator::CompositeEffect;
using ::android::hardware::vibrator::CompositePrimitive;
+using ::android::hardware::vibrator::PrimitivePwle;
// -------------------------------------------------------------------------------------------------
@@ -53,6 +57,25 @@
return effect;
}
+ static PrimitivePwle createActivePwle(float startAmplitude, float startFrequency,
+ float endAmplitude, float endFrequency,
+ std::chrono::milliseconds duration) {
+ ActivePwle pwle;
+ pwle.startAmplitude = startAmplitude;
+ pwle.endAmplitude = endAmplitude;
+ pwle.startFrequency = startFrequency;
+ pwle.endFrequency = endFrequency;
+ pwle.duration = duration.count();
+ return pwle;
+ }
+
+ static PrimitivePwle createBrakingPwle(Braking braking, std::chrono::milliseconds duration) {
+ BrakingPwle pwle;
+ pwle.braking = braking;
+ pwle.duration = duration.count();
+ return pwle;
+ }
+
static std::function<void()> createCountingCallback(int32_t* counter) {
return [counter]() { *counter += 1; };
}