Merge "Update to use nativehelper/JNIPlatformHelp.h"
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index 9d3f4f9..a686dfb 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -6,6 +6,7 @@
clang_format = --commit ${PREUPLOAD_COMMIT} --style file --extensions c,h,cc,cpp
cmds/idlcli/
include/input/
+ include/powermanager/
libs/binder/fuzzer/
libs/binder/ndk/
libs/binderthreadstate/
@@ -18,6 +19,7 @@
opengl/libs/
services/bufferhub/
services/inputflinger/
+ services/powermanager/
services/surfaceflinger/
services/vibratorservice/
services/vr/
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index e6bfa14..581d3de 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -2296,8 +2296,7 @@
std::string final_path = ds.path_;
if (ds.options_->OutputToCustomFile()) {
- std::string bugreport_dir = dirname(ds.options_->use_outfile.c_str());
- final_path = ds.GetPath(bugreport_dir, ".zip");
+ final_path = ds.GetPath(ds.options_->out_dir, ".zip");
android::os::CopyFileToFile(ds.path_, final_path);
}
@@ -2418,7 +2417,7 @@
// clang-format off
case 'd': do_add_date = true; break;
case 'z': do_zip_file = true; break;
- case 'o': use_outfile = optarg; break;
+ case 'o': out_dir = optarg; break;
case 's': use_socket = true; break;
case 'S': use_control_socket = true; break;
case 'v': show_header_only = true; break;
diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h
index a133f7e..0d25d30 100644
--- a/cmds/dumpstate/dumpstate.h
+++ b/cmds/dumpstate/dumpstate.h
@@ -386,12 +386,12 @@
// The HAL is actually an API surface that can be validated, while the AIDL is not (@hide).
::android::hardware::dumpstate::V1_1::DumpstateMode dumpstate_hal_mode =
::android::hardware::dumpstate::V1_1::DumpstateMode::DEFAULT;
- // File descriptor to output zip file. Takes precedence over use_outfile..
+ // File descriptor to output zip file. Takes precedence over out_dir.
android::base::unique_fd bugreport_fd;
// File descriptor to screenshot file.
android::base::unique_fd screenshot_fd;
- // Partial path to output file.
- std::string use_outfile;
+ // Custom output directory.
+ std::string out_dir;
// Bugreport mode of the bugreport.
std::string bugreport_mode;
// Command-line arguments as string
@@ -421,7 +421,7 @@
/* Returns if options specified require writing to custom file location */
bool OutputToCustomFile() {
// Custom location is only honored in limited mode.
- return limited_only && !use_outfile.empty() && bugreport_fd.get() == -1;
+ return limited_only && !out_dir.empty() && bugreport_fd.get() == -1;
}
};
diff --git a/cmds/dumpstate/tests/dumpstate_test.cpp b/cmds/dumpstate/tests/dumpstate_test.cpp
index e167145..c7df1bb 100644
--- a/cmds/dumpstate/tests/dumpstate_test.cpp
+++ b/cmds/dumpstate/tests/dumpstate_test.cpp
@@ -172,7 +172,7 @@
EXPECT_FALSE(options_.do_add_date);
EXPECT_FALSE(options_.do_zip_file);
- EXPECT_EQ("", options_.use_outfile);
+ EXPECT_EQ("", options_.out_dir);
EXPECT_FALSE(options_.use_socket);
EXPECT_FALSE(options_.use_control_socket);
EXPECT_FALSE(options_.show_header_only);
@@ -366,7 +366,7 @@
EXPECT_TRUE(options_.use_control_socket);
EXPECT_FALSE(options_.do_vibrate);
EXPECT_TRUE(options_.limited_only);
- EXPECT_EQ(" abc", std::string(options_.use_outfile));
+ EXPECT_EQ(" abc", std::string(options_.out_dir));
// Other options retain default values
EXPECT_FALSE(options_.show_header_only);
diff --git a/include/android/multinetwork.h b/include/android/multinetwork.h
index 59b1deb..c6d1c94 100644
--- a/include/android/multinetwork.h
+++ b/include/android/multinetwork.h
@@ -126,8 +126,8 @@
ANDROID_RESOLV_NO_RETRY = 1 << 0,
/**
- * Do not cache the result of the lookup. The lookup may return a result that is already
- * in the cache, unless the ANDROID_RESOLV_NO_CACHE_LOOKUP flag is also specified.
+ * Don't lookup this request in the cache, and don't cache the result of the lookup.
+ * This flag implies {@link #ANDROID_RESOLV_NO_CACHE_LOOKUP}.
*/
ANDROID_RESOLV_NO_CACHE_STORE = 1 << 1,
diff --git a/include/powermanager/PowerHalController.h b/include/powermanager/PowerHalController.h
index 44b8915..dd34c0a 100644
--- a/include/powermanager/PowerHalController.h
+++ b/include/powermanager/PowerHalController.h
@@ -21,58 +21,59 @@
#include <android/hardware/power/Boost.h>
#include <android/hardware/power/IPower.h>
#include <android/hardware/power/Mode.h>
-
#include <powermanager/PowerHalWrapper.h>
-using android::hardware::power::Boost;
-using android::hardware::power::Mode;
-using android::hardware::power::V1_0::Feature;
-using android::hardware::power::V1_0::PowerHint;
-
namespace android {
+namespace power {
+
// -------------------------------------------------------------------------------------------------
// Connects to underlying Power HAL handles.
-class PowerHalConnector {
+class HalConnector {
public:
- PowerHalConnector() = default;
- virtual ~PowerHalConnector() = default;
+ HalConnector() = default;
+ virtual ~HalConnector() = default;
- virtual std::unique_ptr<PowerHalWrapper> connect();
+ virtual std::unique_ptr<HalWrapper> connect();
virtual void reset();
};
// -------------------------------------------------------------------------------------------------
// Controller for Power HAL handle.
-// This relies on PowerHalConnector to connect to the underlying Power HAL service and reconnects to
-// it after each failed api call. This also ensures connecting to the service is thread-safe.
-class PowerHalController : public PowerHalWrapper {
+// This relies on HalConnector to connect to the underlying Power HAL
+// service and reconnects to it after each failed api call. This also ensures
+// connecting to the service is thread-safe.
+class PowerHalController : public HalWrapper {
public:
- PowerHalController() : PowerHalController(std::make_unique<PowerHalConnector>()) {}
- explicit PowerHalController(std::unique_ptr<PowerHalConnector> connector)
- : mHalConnector(std::move(connector)) {}
+ PowerHalController() : PowerHalController(std::make_unique<HalConnector>()) {}
+ explicit PowerHalController(std::unique_ptr<HalConnector> connector)
+ : mHalConnector(std::move(connector)) {}
+ virtual ~PowerHalController() = default;
void init();
- PowerHalResult setBoost(Boost boost, int32_t durationMs) override;
- PowerHalResult setMode(Mode mode, bool enabled) override;
+ virtual HalResult setBoost(hardware::power::Boost boost, int32_t durationMs) override;
+ virtual HalResult setMode(hardware::power::Mode mode, bool enabled) override;
private:
std::mutex mConnectedHalMutex;
- std::unique_ptr<PowerHalConnector> mHalConnector;
+ std::unique_ptr<HalConnector> mHalConnector;
- // Shared pointers to keep global pointer and allow local copies to be used in different threads
- std::shared_ptr<PowerHalWrapper> mConnectedHal GUARDED_BY(mConnectedHalMutex) = nullptr;
- const std::shared_ptr<PowerHalWrapper> mDefaultHal = std::make_shared<EmptyPowerHalWrapper>();
+ // Shared pointers to keep global pointer and allow local copies to be used in
+ // different threads
+ std::shared_ptr<HalWrapper> mConnectedHal GUARDED_BY(mConnectedHalMutex) = nullptr;
+ const std::shared_ptr<HalWrapper> mDefaultHal = std::make_shared<EmptyHalWrapper>();
- std::shared_ptr<PowerHalWrapper> initHal();
- PowerHalResult processHalResult(PowerHalResult result, const char* functionName);
+ std::shared_ptr<HalWrapper> initHal();
+ HalResult processHalResult(HalResult result, const char* functionName);
};
// -------------------------------------------------------------------------------------------------
+}; // namespace power
+
}; // namespace android
#endif // ANDROID_POWERHALCONTROLLER_H
diff --git a/include/powermanager/PowerHalLoader.h b/include/powermanager/PowerHalLoader.h
index 487b95b..ed6f6f3 100644
--- a/include/powermanager/PowerHalLoader.h
+++ b/include/powermanager/PowerHalLoader.h
@@ -18,35 +18,36 @@
#define ANDROID_POWERHALLOADER_H
#include <android-base/thread_annotations.h>
-
#include <android/hardware/power/1.1/IPower.h>
#include <android/hardware/power/IPower.h>
-using IPowerV1_0 = android::hardware::power::V1_0::IPower;
-using IPowerV1_1 = android::hardware::power::V1_1::IPower;
-using IPowerAidl = android::hardware::power::IPower;
-
namespace android {
+namespace power {
+
// Loads available Power HAL services.
class PowerHalLoader {
public:
static void unloadAll();
- static sp<IPowerAidl> loadAidl();
- static sp<IPowerV1_0> loadHidlV1_0();
- static sp<IPowerV1_1> loadHidlV1_1();
+ static sp<hardware::power::IPower> loadAidl();
+ static sp<hardware::power::V1_0::IPower> loadHidlV1_0();
+ static sp<hardware::power::V1_1::IPower> loadHidlV1_1();
private:
static std::mutex gHalMutex;
- static sp<IPowerAidl> gHalAidl GUARDED_BY(gHalMutex);
- static sp<IPowerV1_0> gHalHidlV1_0 GUARDED_BY(gHalMutex);
- static sp<IPowerV1_1> gHalHidlV1_1 GUARDED_BY(gHalMutex);
+ static sp<hardware::power::IPower> gHalAidl GUARDED_BY(gHalMutex);
+ static sp<hardware::power::V1_0::IPower> gHalHidlV1_0 GUARDED_BY(gHalMutex);
+ static sp<hardware::power::V1_1::IPower> gHalHidlV1_1 GUARDED_BY(gHalMutex);
- static sp<IPowerV1_0> loadHidlV1_0Locked() EXCLUSIVE_LOCKS_REQUIRED(gHalMutex);
+ static sp<hardware::power::V1_0::IPower> loadHidlV1_0Locked()
+ EXCLUSIVE_LOCKS_REQUIRED(gHalMutex);
- PowerHalLoader() = default;
+ PowerHalLoader() = delete;
+ ~PowerHalLoader() = delete;
};
+}; // namespace power
+
} // namespace android
#endif // ANDROID_POWERHALLOADER_H
diff --git a/include/powermanager/PowerHalWrapper.h b/include/powermanager/PowerHalWrapper.h
index 6d8a6eb..c3e7601 100644
--- a/include/powermanager/PowerHalWrapper.h
+++ b/include/powermanager/PowerHalWrapper.h
@@ -18,111 +18,111 @@
#define ANDROID_POWERHALWRAPPER_H
#include <android-base/thread_annotations.h>
-
#include <android/hardware/power/1.1/IPower.h>
#include <android/hardware/power/Boost.h>
#include <android/hardware/power/IPower.h>
#include <android/hardware/power/Mode.h>
-using android::hardware::power::Boost;
-using android::hardware::power::Mode;
-using android::hardware::power::V1_0::Feature;
-using android::hardware::power::V1_0::PowerHint;
-using IPowerV1_1 = android::hardware::power::V1_1::IPower;
-using IPowerV1_0 = android::hardware::power::V1_0::IPower;
-using IPowerAidl = android::hardware::power::IPower;
-
namespace android {
+namespace power {
+
// State of Power HAL support for individual apis.
-enum class PowerHalSupport {
+enum class HalSupport {
UNKNOWN = 0,
ON = 1,
OFF = 2,
};
// State of the Power HAL api call result.
-enum class PowerHalResult {
+enum class HalResult {
SUCCESSFUL = 0,
FAILED = 1,
UNSUPPORTED = 2,
};
// Wrapper for Power HAL handlers.
-class PowerHalWrapper {
+class HalWrapper {
public:
- virtual ~PowerHalWrapper() = default;
+ virtual ~HalWrapper() = default;
- virtual PowerHalResult setBoost(Boost boost, int32_t durationMs) = 0;
- virtual PowerHalResult setMode(Mode mode, bool enabled) = 0;
+ virtual HalResult setBoost(hardware::power::Boost boost, int32_t durationMs) = 0;
+ virtual HalResult setMode(hardware::power::Mode mode, bool enabled) = 0;
};
// Empty Power HAL wrapper that ignores all api calls.
-class EmptyPowerHalWrapper : public PowerHalWrapper {
+class EmptyHalWrapper : public HalWrapper {
public:
- EmptyPowerHalWrapper() = default;
- ~EmptyPowerHalWrapper() = default;
+ EmptyHalWrapper() = default;
+ ~EmptyHalWrapper() = default;
- PowerHalResult setBoost(Boost boost, int32_t durationMs) override;
- PowerHalResult setMode(Mode mode, bool enabled) override;
+ virtual HalResult setBoost(hardware::power::Boost boost, int32_t durationMs) override;
+ virtual HalResult setMode(hardware::power::Mode mode, bool enabled) override;
};
// Wrapper for the HIDL Power HAL v1.0.
-class HidlPowerHalWrapperV1_0 : public PowerHalWrapper {
+class HidlHalWrapperV1_0 : public HalWrapper {
public:
- explicit HidlPowerHalWrapperV1_0(sp<IPowerV1_0> powerHal) : handleV1_0(std::move(powerHal)) {}
- virtual ~HidlPowerHalWrapperV1_0() = default;
+ explicit HidlHalWrapperV1_0(sp<hardware::power::V1_0::IPower> Hal)
+ : mHandleV1_0(std::move(Hal)) {}
+ virtual ~HidlHalWrapperV1_0() = default;
- PowerHalResult setBoost(Boost boost, int32_t durationMs) override;
- PowerHalResult setMode(Mode mode, bool enabled) override;
+ virtual HalResult setBoost(hardware::power::Boost boost, int32_t durationMs) override;
+ virtual HalResult setMode(hardware::power::Mode mode, bool enabled) override;
protected:
- virtual PowerHalResult sendPowerHint(PowerHint hintId, uint32_t data);
+ virtual HalResult sendPowerHint(hardware::power::V1_0::PowerHint hintId, uint32_t data);
private:
- sp<IPowerV1_0> handleV1_0;
- PowerHalResult setInteractive(bool enabled);
- PowerHalResult setFeature(Feature feature, bool enabled);
+ sp<hardware::power::V1_0::IPower> mHandleV1_0;
+ HalResult setInteractive(bool enabled);
+ HalResult setFeature(hardware::power::V1_0::Feature feature, bool enabled);
};
// Wrapper for the HIDL Power HAL v1.1.
-class HidlPowerHalWrapperV1_1 : public HidlPowerHalWrapperV1_0 {
+class HidlHalWrapperV1_1 : public HidlHalWrapperV1_0 {
public:
- HidlPowerHalWrapperV1_1(sp<IPowerV1_0> powerHalV1_0, sp<IPowerV1_1> powerHalV1_1)
- : HidlPowerHalWrapperV1_0(powerHalV1_0), handleV1_1(std::move(powerHalV1_1)) {}
- ~HidlPowerHalWrapperV1_1() = default;
+ HidlHalWrapperV1_1(sp<hardware::power::V1_0::IPower> handleV1_0,
+ sp<hardware::power::V1_1::IPower> handleV1_1)
+ : HidlHalWrapperV1_0(std::move(handleV1_0)), mHandleV1_1(std::move(handleV1_1)) {}
+ virtual ~HidlHalWrapperV1_1() = default;
protected:
- virtual PowerHalResult sendPowerHint(PowerHint hintId, uint32_t data) override;
+ virtual HalResult sendPowerHint(hardware::power::V1_0::PowerHint hintId,
+ uint32_t data) override;
private:
- sp<IPowerV1_1> handleV1_1;
+ sp<hardware::power::V1_1::IPower> mHandleV1_1;
};
// Wrapper for the AIDL Power HAL.
-class AidlPowerHalWrapper : public PowerHalWrapper {
+class AidlHalWrapper : public HalWrapper {
public:
- explicit AidlPowerHalWrapper(sp<IPowerAidl> powerHal) : handle(std::move(powerHal)) {}
- ~AidlPowerHalWrapper() = default;
+ explicit AidlHalWrapper(sp<hardware::power::IPower> handle) : mHandle(std::move(handle)) {}
+ virtual ~AidlHalWrapper() = default;
- PowerHalResult setBoost(Boost boost, int32_t durationMs) override;
- PowerHalResult setMode(Mode mode, bool enabled) override;
+ virtual HalResult setBoost(hardware::power::Boost boost, int32_t durationMs) override;
+ virtual HalResult setMode(hardware::power::Mode mode, bool enabled) override;
private:
// Control access to the boost and mode supported arrays.
std::mutex mBoostMutex;
std::mutex mModeMutex;
- sp<IPowerAidl> handle;
+ sp<hardware::power::IPower> mHandle;
// Android framework only sends boost upto DISPLAY_UPDATE_IMMINENT.
// Need to increase the array size if more boost supported.
- std::array<std::atomic<PowerHalSupport>, static_cast<int32_t>(Boost::DISPLAY_UPDATE_IMMINENT)+1>
- boostSupportedArray GUARDED_BY(mBoostMutex) = {PowerHalSupport::UNKNOWN};
+ std::array<std::atomic<HalSupport>,
+ static_cast<int32_t>(hardware::power::Boost::DISPLAY_UPDATE_IMMINENT) + 1>
+ mBoostSupportedArray GUARDED_BY(mBoostMutex) = {HalSupport::UNKNOWN};
// Android framework only sends mode upto DISPLAY_INACTIVE.
// Need to increase the array if more mode supported.
- std::array<std::atomic<PowerHalSupport>, static_cast<int32_t>(Mode::DISPLAY_INACTIVE)+1>
- modeSupportedArray GUARDED_BY(mModeMutex) = {PowerHalSupport::UNKNOWN};
+ std::array<std::atomic<HalSupport>,
+ static_cast<int32_t>(hardware::power::Mode::DISPLAY_INACTIVE) + 1>
+ mModeSupportedArray GUARDED_BY(mModeMutex) = {HalSupport::UNKNOWN};
};
+}; // namespace power
+
}; // namespace android
#endif // ANDROID_POWERHALWRAPPER_H
diff --git a/libs/cputimeinstate/cputimeinstate.cpp b/libs/cputimeinstate/cputimeinstate.cpp
index 0b77ab3..50f6289 100644
--- a/libs/cputimeinstate/cputimeinstate.cpp
+++ b/libs/cputimeinstate/cputimeinstate.cpp
@@ -88,16 +88,6 @@
return policyN1 - policyN2;
}
-static int bpf_obj_get_wronly(const char *pathname) {
- union bpf_attr attr;
-
- memset(&attr, 0, sizeof(attr));
- attr.pathname = ptr_to_u64((void *)pathname);
- attr.file_flags = BPF_F_WRONLY;
-
- return syscall(__NR_bpf, BPF_OBJ_GET, &attr, sizeof(attr));
-}
-
static bool initGlobals() {
std::lock_guard<std::mutex> guard(gInitializedMutex);
if (gInitialized) return true;
@@ -156,7 +146,7 @@
static bool attachTracepointProgram(const std::string &eventType, const std::string &eventName) {
std::string path = StringPrintf(BPF_FS_PATH "prog_time_in_state_tracepoint_%s_%s",
eventType.c_str(), eventName.c_str());
- int prog_fd = bpfFdGet(path.c_str(), BPF_F_RDONLY);
+ int prog_fd = retrieveProgram(path.c_str());
if (prog_fd < 0) return false;
return bpf_attach_tracepoint(prog_fd, eventType.c_str(), eventName.c_str()) >= 0;
}
@@ -183,7 +173,7 @@
if (!initGlobals()) return false;
if (gTracking) return true;
- unique_fd cpuPolicyFd(bpf_obj_get_wronly(BPF_FS_PATH "map_time_in_state_cpu_policy_map"));
+ unique_fd cpuPolicyFd(mapRetrieveWO(BPF_FS_PATH "map_time_in_state_cpu_policy_map"));
if (cpuPolicyFd < 0) return false;
for (uint32_t i = 0; i < gPolicyCpus.size(); ++i) {
@@ -192,7 +182,7 @@
}
}
- unique_fd freqToIdxFd(bpf_obj_get_wronly(BPF_FS_PATH "map_time_in_state_freq_to_idx_map"));
+ unique_fd freqToIdxFd(mapRetrieveWO(BPF_FS_PATH "map_time_in_state_freq_to_idx_map"));
if (freqToIdxFd < 0) return false;
freq_idx_key_t key;
for (uint32_t i = 0; i < gNPolicies; ++i) {
@@ -207,23 +197,23 @@
}
}
- unique_fd cpuLastUpdateFd(bpf_obj_get_wronly(BPF_FS_PATH "map_time_in_state_cpu_last_update_map"));
+ unique_fd cpuLastUpdateFd(mapRetrieveWO(BPF_FS_PATH "map_time_in_state_cpu_last_update_map"));
if (cpuLastUpdateFd < 0) return false;
std::vector<uint64_t> zeros(get_nprocs_conf(), 0);
uint32_t zero = 0;
if (writeToMapEntry(cpuLastUpdateFd, &zero, zeros.data(), BPF_ANY)) return false;
- unique_fd nrActiveFd(bpf_obj_get_wronly(BPF_FS_PATH "map_time_in_state_nr_active_map"));
+ unique_fd nrActiveFd(mapRetrieveWO(BPF_FS_PATH "map_time_in_state_nr_active_map"));
if (nrActiveFd < 0) return false;
if (writeToMapEntry(nrActiveFd, &zero, &zero, BPF_ANY)) return false;
- unique_fd policyNrActiveFd(bpf_obj_get_wronly(BPF_FS_PATH "map_time_in_state_policy_nr_active_map"));
+ unique_fd policyNrActiveFd(mapRetrieveWO(BPF_FS_PATH "map_time_in_state_policy_nr_active_map"));
if (policyNrActiveFd < 0) return false;
for (uint32_t i = 0; i < gNPolicies; ++i) {
if (writeToMapEntry(policyNrActiveFd, &i, &zero, BPF_ANY)) return false;
}
- unique_fd policyFreqIdxFd(bpf_obj_get_wronly(BPF_FS_PATH "map_time_in_state_policy_freq_idx_map"));
+ unique_fd policyFreqIdxFd(mapRetrieveWO(BPF_FS_PATH "map_time_in_state_policy_freq_idx_map"));
if (policyFreqIdxFd < 0) return false;
for (uint32_t i = 0; i < gNPolicies; ++i) {
auto freqIdx = getPolicyFreqIdx(i);
diff --git a/libs/graphicsenv/GraphicsEnv.cpp b/libs/graphicsenv/GraphicsEnv.cpp
index cfc7e98..119b3e0 100644
--- a/libs/graphicsenv/GraphicsEnv.cpp
+++ b/libs/graphicsenv/GraphicsEnv.cpp
@@ -39,6 +39,13 @@
#include <string>
#include <thread>
+// TODO(b/159240322): Extend this to x86 ABI.
+#if defined(__LP64__)
+#define UPDATABLE_DRIVER_ABI "arm64-v8a"
+#else
+#define UPDATABLE_DRIVER_ABI "armeabi-v7a"
+#endif // defined(__LP64__)
+
// TODO(ianelliott@): Get the following from an ANGLE header:
#define CURRENT_ANGLE_API_VERSION 2 // Current API verion we are targetting
// Version-2 API:
@@ -582,7 +589,28 @@
}
if (mDriverPath.empty()) {
- return nullptr;
+ // For an application process, driver path is empty means this application is not opted in
+ // to use updatable driver. Application process doesn't have the ability to set up
+ // environment variables and hence before `getenv` call will return.
+ // For a process that is not an application process, if it's run from an environment,
+ // for example shell, where environment variables can be set, then it can opt into using
+ // udpatable driver by setting UPDATABLE_GFX_DRIVER to 1. By setting to 1 the developer
+ // driver will be used currently.
+ // TODO(b/159240322) Support the production updatable driver.
+ const char* id = getenv("UPDATABLE_GFX_DRIVER");
+ if (id == nullptr || std::strcmp(id, "1")) {
+ return nullptr;
+ }
+ const sp<IGpuService> gpuService = getGpuService();
+ if (!gpuService) {
+ return nullptr;
+ }
+ mDriverPath = gpuService->getUpdatableDriverPath();
+ if (mDriverPath.empty()) {
+ return nullptr;
+ }
+ mDriverPath.append(UPDATABLE_DRIVER_ABI);
+ ALOGI("Driver path is setup via UPDATABLE_GFX_DRIVER: %s", mDriverPath.c_str());
}
auto vndkNamespace = android_get_exported_namespace("vndk");
diff --git a/libs/graphicsenv/IGpuService.cpp b/libs/graphicsenv/IGpuService.cpp
index de3503b..fa25c55 100644
--- a/libs/graphicsenv/IGpuService.cpp
+++ b/libs/graphicsenv/IGpuService.cpp
@@ -27,11 +27,11 @@
public:
explicit BpGpuService(const sp<IBinder>& impl) : BpInterface<IGpuService>(impl) {}
- virtual void setGpuStats(const std::string& driverPackageName,
- const std::string& driverVersionName, uint64_t driverVersionCode,
- int64_t driverBuildTime, const std::string& appPackageName,
- const int32_t vulkanVersion, GpuStatsInfo::Driver driver,
- bool isDriverLoaded, int64_t driverLoadingTime) {
+ void setGpuStats(const std::string& driverPackageName, const std::string& driverVersionName,
+ uint64_t driverVersionCode, int64_t driverBuildTime,
+ const std::string& appPackageName, const int32_t vulkanVersion,
+ GpuStatsInfo::Driver driver, bool isDriverLoaded,
+ int64_t driverLoadingTime) override {
Parcel data, reply;
data.writeInterfaceToken(IGpuService::getInterfaceDescriptor());
@@ -48,8 +48,8 @@
remote()->transact(BnGpuService::SET_GPU_STATS, data, &reply, IBinder::FLAG_ONEWAY);
}
- virtual void setTargetStats(const std::string& appPackageName, const uint64_t driverVersionCode,
- const GpuStatsInfo::Stats stats, const uint64_t value) {
+ void setTargetStats(const std::string& appPackageName, const uint64_t driverVersionCode,
+ const GpuStatsInfo::Stats stats, const uint64_t value) override {
Parcel data, reply;
data.writeInterfaceToken(IGpuService::getInterfaceDescriptor());
@@ -60,6 +60,27 @@
remote()->transact(BnGpuService::SET_TARGET_STATS, data, &reply, IBinder::FLAG_ONEWAY);
}
+
+ void setUpdatableDriverPath(const std::string& driverPath) override {
+ Parcel data, reply;
+ data.writeInterfaceToken(IGpuService::getInterfaceDescriptor());
+ data.writeUtf8AsUtf16(driverPath);
+
+ remote()->transact(BnGpuService::SET_UPDATABLE_DRIVER_PATH, data, &reply,
+ IBinder::FLAG_ONEWAY);
+ }
+
+ std::string getUpdatableDriverPath() override {
+ Parcel data, reply;
+ data.writeInterfaceToken(IGpuService::getInterfaceDescriptor());
+
+ status_t error = remote()->transact(BnGpuService::GET_UPDATABLE_DRIVER_PATH, data, &reply);
+ std::string driverPath;
+ if (error == OK) {
+ error = reply.readUtf8FromUtf16(&driverPath);
+ }
+ return driverPath;
+ }
};
IMPLEMENT_META_INTERFACE(GpuService, "android.graphicsenv.IGpuService");
@@ -126,6 +147,21 @@
return OK;
}
+ case SET_UPDATABLE_DRIVER_PATH: {
+ CHECK_INTERFACE(IGpuService, data, reply);
+
+ std::string driverPath;
+ if ((status = data.readUtf8FromUtf16(&driverPath)) != OK) return status;
+
+ setUpdatableDriverPath(driverPath);
+ return OK;
+ }
+ case GET_UPDATABLE_DRIVER_PATH: {
+ CHECK_INTERFACE(IGpuService, data, reply);
+
+ std::string driverPath = getUpdatableDriverPath();
+ return reply->writeUtf8AsUtf16(driverPath);
+ }
case SHELL_COMMAND_TRANSACTION: {
int in = data.readFileDescriptor();
int out = data.readFileDescriptor();
diff --git a/libs/graphicsenv/include/graphicsenv/IGpuService.h b/libs/graphicsenv/include/graphicsenv/IGpuService.h
index c7c6d1e..2d59fa0 100644
--- a/libs/graphicsenv/include/graphicsenv/IGpuService.h
+++ b/libs/graphicsenv/include/graphicsenv/IGpuService.h
@@ -42,6 +42,10 @@
// set target stats.
virtual void setTargetStats(const std::string& appPackageName, const uint64_t driverVersionCode,
const GpuStatsInfo::Stats stats, const uint64_t value = 0) = 0;
+
+ // setter and getter for updatable driver path.
+ virtual void setUpdatableDriverPath(const std::string& driverPath) = 0;
+ virtual std::string getUpdatableDriverPath() = 0;
};
class BnGpuService : public BnInterface<IGpuService> {
@@ -49,6 +53,8 @@
enum IGpuServiceTag {
SET_GPU_STATS = IBinder::FIRST_CALL_TRANSACTION,
SET_TARGET_STATS,
+ SET_UPDATABLE_DRIVER_PATH,
+ GET_UPDATABLE_DRIVER_PATH,
// Always append new enum to the end.
};
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index 1efd98b..a86eafa 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -110,7 +110,7 @@
mConnectedToCpu = false;
mProducerControlledByApp = controlledByApp;
mSwapIntervalZero = false;
- mMaxBufferCount = 0;
+ mMaxBufferCount = NUM_BUFFER_SLOTS;
}
Surface::~Surface() {
@@ -1585,6 +1585,7 @@
mStickyTransform = 0;
mAutoPrerotation = false;
mEnableFrameTimestamps = false;
+ mMaxBufferCount = NUM_BUFFER_SLOTS;
if (api == NATIVE_WINDOW_API_CPU) {
mConnectedToCpu = false;
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 88232fa..16b46df 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -353,6 +353,8 @@
mTransactionNestCount(other.mTransactionNestCount),
mAnimation(other.mAnimation),
mEarlyWakeup(other.mEarlyWakeup),
+ mExplicitEarlyWakeupStart(other.mExplicitEarlyWakeupStart),
+ mExplicitEarlyWakeupEnd(other.mExplicitEarlyWakeupEnd),
mContainsBuffer(other.mContainsBuffer),
mDesiredPresentTime(other.mDesiredPresentTime) {
mDisplayStates = other.mDisplayStates;
@@ -375,6 +377,8 @@
const uint32_t transactionNestCount = parcel->readUint32();
const bool animation = parcel->readBool();
const bool earlyWakeup = parcel->readBool();
+ const bool explicitEarlyWakeupStart = parcel->readBool();
+ const bool explicitEarlyWakeupEnd = parcel->readBool();
const bool containsBuffer = parcel->readBool();
const int64_t desiredPresentTime = parcel->readInt64();
@@ -443,6 +447,8 @@
mTransactionNestCount = transactionNestCount;
mAnimation = animation;
mEarlyWakeup = earlyWakeup;
+ mExplicitEarlyWakeupStart = explicitEarlyWakeupStart;
+ mExplicitEarlyWakeupEnd = explicitEarlyWakeupEnd;
mContainsBuffer = containsBuffer;
mDesiredPresentTime = desiredPresentTime;
mDisplayStates = displayStates;
@@ -470,6 +476,8 @@
parcel->writeUint32(mTransactionNestCount);
parcel->writeBool(mAnimation);
parcel->writeBool(mEarlyWakeup);
+ parcel->writeBool(mExplicitEarlyWakeupStart);
+ parcel->writeBool(mExplicitEarlyWakeupEnd);
parcel->writeBool(mContainsBuffer);
parcel->writeInt64(mDesiredPresentTime);
parcel->writeUint32(static_cast<uint32_t>(mDisplayStates.size()));
@@ -545,6 +553,8 @@
mContainsBuffer |= other.mContainsBuffer;
mEarlyWakeup = mEarlyWakeup || other.mEarlyWakeup;
+ mExplicitEarlyWakeupStart = mExplicitEarlyWakeupStart || other.mExplicitEarlyWakeupStart;
+ mExplicitEarlyWakeupEnd = mExplicitEarlyWakeupEnd || other.mExplicitEarlyWakeupEnd;
other.clear();
return *this;
}
@@ -559,6 +569,8 @@
mTransactionNestCount = 0;
mAnimation = false;
mEarlyWakeup = false;
+ mExplicitEarlyWakeupStart = false;
+ mExplicitEarlyWakeupEnd = false;
mDesiredPresentTime = -1;
}
@@ -682,9 +694,20 @@
flags |= ISurfaceComposer::eEarlyWakeup;
}
+ // If both mExplicitEarlyWakeupStart and mExplicitEarlyWakeupEnd are set
+ // it is equivalent for none
+ if (mExplicitEarlyWakeupStart && !mExplicitEarlyWakeupEnd) {
+ flags |= ISurfaceComposer::eExplicitEarlyWakeupStart;
+ }
+ if (mExplicitEarlyWakeupEnd && !mExplicitEarlyWakeupStart) {
+ flags |= ISurfaceComposer::eExplicitEarlyWakeupEnd;
+ }
+
mForceSynchronous = false;
mAnimation = false;
mEarlyWakeup = false;
+ mExplicitEarlyWakeupStart = false;
+ mExplicitEarlyWakeupEnd = false;
sp<IBinder> applyToken = IInterface::asBinder(TransactionCompletedListener::getIInstance());
sf->setTransactionState(composerStates, displayStates, flags, applyToken, mInputWindowCommands,
@@ -731,6 +754,14 @@
mEarlyWakeup = true;
}
+void SurfaceComposerClient::Transaction::setExplicitEarlyWakeupStart() {
+ mExplicitEarlyWakeupStart = true;
+}
+
+void SurfaceComposerClient::Transaction::setExplicitEarlyWakeupEnd() {
+ mExplicitEarlyWakeupEnd = true;
+}
+
layer_state_t* SurfaceComposerClient::Transaction::getLayerState(const sp<IBinder>& handle) {
if (mComposerStates.count(handle) == 0) {
// we don't have it, add an initialized layer_state to our list
diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
index a2fb849..645714a 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -81,12 +81,20 @@
// flags for setTransactionState()
enum {
eSynchronous = 0x01,
- eAnimation = 0x02,
+ eAnimation = 0x02,
- // Indicates that this transaction will likely result in a lot of layers being composed, and
- // thus, SurfaceFlinger should wake-up earlier to avoid missing frame deadlines. In this
- // case SurfaceFlinger will wake up at (sf vsync offset - debug.sf.early_phase_offset_ns)
- eEarlyWakeup = 0x04
+ // DEPRECATED - use eExplicitEarlyWakeup[Start|End]
+ eEarlyWakeup = 0x04,
+
+ // Explicit indication that this transaction and others to follow will likely result in a
+ // lot of layers being composed, and thus, SurfaceFlinger should wake-up earlier to avoid
+ // missing frame deadlines. In this case SurfaceFlinger will wake up at
+ // (sf vsync offset - debug.sf.early_phase_offset_ns). SurfaceFlinger will continue to be
+ // in the early configuration until it receives eExplicitEarlyWakeupEnd. These flags are
+ // expected to be used by WindowManager only and are guarded by
+ // android.permission.ACCESS_SURFACE_FLINGER
+ eExplicitEarlyWakeupStart = 0x08,
+ eExplicitEarlyWakeupEnd = 0x10,
};
enum VsyncSource {
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 32c0bab..eb757ba 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -345,10 +345,12 @@
std::unordered_map<sp<ITransactionCompletedListener>, CallbackInfo, TCLHash>
mListenerCallbacks;
- uint32_t mForceSynchronous = 0;
- uint32_t mTransactionNestCount = 0;
- bool mAnimation = false;
- bool mEarlyWakeup = false;
+ uint32_t mForceSynchronous = 0;
+ uint32_t mTransactionNestCount = 0;
+ bool mAnimation = false;
+ bool mEarlyWakeup = false;
+ bool mExplicitEarlyWakeupStart = false;
+ bool mExplicitEarlyWakeupEnd = false;
// Indicates that the Transaction contains a buffer that should be cached
bool mContainsBuffer = false;
@@ -547,6 +549,8 @@
void setDisplaySize(const sp<IBinder>& token, uint32_t width, uint32_t height);
void setAnimationTransaction();
void setEarlyWakeup();
+ void setExplicitEarlyWakeupStart();
+ void setExplicitEarlyWakeupEnd();
};
status_t clearLayerFrameStats(const sp<IBinder>& token) const;
diff --git a/libs/gui/tests/EndToEndNativeInputTest.cpp b/libs/gui/tests/EndToEndNativeInputTest.cpp
index 5188a09..b1d3ecb 100644
--- a/libs/gui/tests/EndToEndNativeInputTest.cpp
+++ b/libs/gui/tests/EndToEndNativeInputTest.cpp
@@ -104,6 +104,15 @@
return std::make_unique<InputSurface>(surfaceControl, width, height);
}
+ static std::unique_ptr<InputSurface> makeCursorInputSurface(
+ const sp<SurfaceComposerClient> &scc, int width, int height) {
+ sp<SurfaceControl> surfaceControl =
+ scc->createSurface(String8("Test Cursor Surface"), 0 /* bufHeight */,
+ 0 /* bufWidth */, PIXEL_FORMAT_RGBA_8888,
+ ISurfaceComposerClient::eCursorWindow);
+ return std::make_unique<InputSurface>(surfaceControl, width, height);
+ }
+
InputEvent* consumeEvent() {
waitForEventAvailable();
@@ -134,12 +143,14 @@
EXPECT_EQ(AMOTION_EVENT_ACTION_DOWN, mev->getAction());
EXPECT_EQ(x, mev->getX(0));
EXPECT_EQ(y, mev->getY(0));
+ EXPECT_EQ(0, mev->getFlags() & VERIFIED_MOTION_EVENT_FLAGS);
ev = consumeEvent();
ASSERT_NE(ev, nullptr);
ASSERT_EQ(AINPUT_EVENT_TYPE_MOTION, ev->getType());
mev = static_cast<MotionEvent*>(ev);
EXPECT_EQ(AMOTION_EVENT_ACTION_UP, mev->getAction());
+ EXPECT_EQ(0, mev->getFlags() & VERIFIED_MOTION_EVENT_FLAGS);
}
~InputSurface() {
@@ -537,5 +548,18 @@
injectTap(0, 0);
surface->expectTap(1, 1);
}
+
+TEST_F(InputSurfacesTest, input_ignores_cursor_layer) {
+ std::unique_ptr<InputSurface> surface = makeSurface(100, 100);
+ std::unique_ptr<InputSurface> cursorSurface =
+ InputSurface::makeCursorInputSurface(mComposerClient, 10, 10);
+
+ surface->showAt(10, 10);
+ surface->assertFocusChange(true);
+ cursorSurface->showAt(10, 10);
+
+ injectTap(11, 11);
+ surface->expectTap(1, 1);
+}
}
}
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index 81f168c..6d92143 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -30,6 +30,7 @@
#include <gui/SurfaceComposerClient.h>
#include <inttypes.h>
#include <private/gui/ComposerService.h>
+#include <ui/BufferQueueDefs.h>
#include <ui/Rect.h>
#include <utils/String8.h>
@@ -1974,4 +1975,29 @@
ASSERT_EQ(NO_ERROR, window->cancelBuffer(window.get(), buffer, fence));
}
+TEST_F(SurfaceTest, DefaultMaxBufferCountSetAndUpdated) {
+ sp<IGraphicBufferProducer> producer;
+ sp<IGraphicBufferConsumer> consumer;
+ BufferQueue::createBufferQueue(&producer, &consumer);
+
+ sp<DummyConsumer> dummyConsumer(new DummyConsumer);
+ consumer->consumerConnect(dummyConsumer, false);
+
+ sp<Surface> surface = new Surface(producer);
+ sp<ANativeWindow> window(surface);
+
+ int count = -1;
+ ASSERT_EQ(NO_ERROR, window->query(window.get(), NATIVE_WINDOW_MAX_BUFFER_COUNT, &count));
+ EXPECT_EQ(BufferQueueDefs::NUM_BUFFER_SLOTS, count);
+
+ consumer->setMaxBufferCount(10);
+ ASSERT_EQ(NO_ERROR, native_window_api_connect(window.get(), NATIVE_WINDOW_API_CPU));
+ EXPECT_EQ(NO_ERROR, window->query(window.get(), NATIVE_WINDOW_MAX_BUFFER_COUNT, &count));
+ EXPECT_EQ(10, count);
+
+ ASSERT_EQ(NO_ERROR, native_window_api_disconnect(window.get(), NATIVE_WINDOW_API_CPU));
+ ASSERT_EQ(NO_ERROR, window->query(window.get(), NATIVE_WINDOW_MAX_BUFFER_COUNT, &count));
+ EXPECT_EQ(BufferQueueDefs::NUM_BUFFER_SLOTS, count);
+}
+
} // namespace android
diff --git a/libs/vr/libpdx/fuzz/Android.bp b/libs/vr/libpdx/fuzz/Android.bp
index 20a03ea..3490775 100644
--- a/libs/vr/libpdx/fuzz/Android.bp
+++ b/libs/vr/libpdx/fuzz/Android.bp
@@ -16,4 +16,8 @@
"libutils",
"liblog",
],
+ fuzz_config: {
+ fuzz_on_haiku_host: false,
+ fuzz_on_haiku_device: false,
+ },
}
diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp
index 85e2c15..1afc693 100644
--- a/opengl/libs/EGL/Loader.cpp
+++ b/opengl/libs/EGL/Loader.cpp
@@ -364,7 +364,7 @@
f = (__eglMustCastToProperFunctionPointerType)gl_unimplemented;
/*
- * GL_EXT_debug_label is special, we always report it as
+ * GL_EXT_debug_marker is special, we always report it as
* supported, it's handled by GLES_trace. If GLES_trace is not
* enabled, then these are no-ops.
*/
diff --git a/services/gpuservice/GpuService.cpp b/services/gpuservice/GpuService.cpp
index bf0d6a9..bad5637 100644
--- a/services/gpuservice/GpuService.cpp
+++ b/services/gpuservice/GpuService.cpp
@@ -65,6 +65,14 @@
mGpuStats->insertTargetStats(appPackageName, driverVersionCode, stats, value);
}
+void GpuService::setUpdatableDriverPath(const std::string& driverPath) {
+ developerDriverPath = driverPath;
+}
+
+std::string GpuService::getUpdatableDriverPath() {
+ return developerDriverPath;
+}
+
status_t GpuService::shellCommand(int /*in*/, int out, int err, std::vector<String16>& args) {
ATRACE_CALL();
diff --git a/services/gpuservice/GpuService.h b/services/gpuservice/GpuService.h
index f4b8597..9a0460d 100644
--- a/services/gpuservice/GpuService.h
+++ b/services/gpuservice/GpuService.h
@@ -51,6 +51,8 @@
int64_t driverLoadingTime) override;
void setTargetStats(const std::string& appPackageName, const uint64_t driverVersionCode,
const GpuStatsInfo::Stats stats, const uint64_t value) override;
+ void setUpdatableDriverPath(const std::string& driverPath) override;
+ std::string getUpdatableDriverPath() override;
/*
* IBinder interface
@@ -75,6 +77,7 @@
*/
std::unique_ptr<GpuMem> mGpuMem;
std::unique_ptr<GpuStats> mGpuStats;
+ std::string developerDriverPath;
};
} // namespace android
diff --git a/services/gpuservice/tests/unittests/GpuMemTest.cpp b/services/gpuservice/tests/unittests/GpuMemTest.cpp
index aad79ae..6ba304c 100644
--- a/services/gpuservice/tests/unittests/GpuMemTest.cpp
+++ b/services/gpuservice/tests/unittests/GpuMemTest.cpp
@@ -57,11 +57,16 @@
}
void SetUp() override {
+ SKIP_IF_BPF_NOT_SUPPORTED;
+ ASSERT_EQ(0, bpf::setrlimitForTest());
+
mGpuMem = std::make_unique<GpuMem>();
mTestableGpuMem = TestableGpuMem(mGpuMem.get());
+ errno = 0;
mTestMap = bpf::BpfMap<uint64_t, uint64_t>(BPF_MAP_TYPE_HASH, TEST_MAP_SIZE,
BPF_F_NO_PREALLOC);
+ EXPECT_EQ(0, errno);
EXPECT_LE(0, mTestMap.getMap().get());
EXPECT_TRUE(mTestMap.isValid());
}
@@ -79,6 +84,8 @@
};
TEST_F(GpuMemTest, validGpuMemTotalBpfPaths) {
+ SKIP_IF_BPF_NOT_SUPPORTED;
+
EXPECT_EQ(mTestableGpuMem.getGpuMemTraceGroup(), "gpu_mem");
EXPECT_EQ(mTestableGpuMem.getGpuMemTotalTracepoint(), "gpu_mem_total");
EXPECT_EQ(mTestableGpuMem.getGpuMemTotalProgPath(),
@@ -87,16 +94,20 @@
}
TEST_F(GpuMemTest, bpfInitializationFailed) {
+ SKIP_IF_BPF_NOT_SUPPORTED;
+
EXPECT_EQ(dumpsys(), "Failed to initialize GPU memory eBPF\n");
}
TEST_F(GpuMemTest, gpuMemTotalMapEmpty) {
+ SKIP_IF_BPF_NOT_SUPPORTED;
mTestableGpuMem.setGpuMemTotalMap(mTestMap);
EXPECT_EQ(dumpsys(), "GPU memory total usage map is empty\n");
}
TEST_F(GpuMemTest, globalMemTotal) {
+ SKIP_IF_BPF_NOT_SUPPORTED;
ASSERT_RESULT_OK(mTestMap.writeValue(TEST_GLOBAL_KEY, TEST_GLOBAL_VAL, BPF_ANY));
mTestableGpuMem.setGpuMemTotalMap(mTestMap);
@@ -104,6 +115,7 @@
}
TEST_F(GpuMemTest, missingGlobalMemTotal) {
+ SKIP_IF_BPF_NOT_SUPPORTED;
ASSERT_RESULT_OK(mTestMap.writeValue(TEST_PROC_KEY_1, TEST_PROC_VAL_1, BPF_ANY));
mTestableGpuMem.setGpuMemTotalMap(mTestMap);
@@ -111,6 +123,7 @@
}
TEST_F(GpuMemTest, procMemTotal) {
+ SKIP_IF_BPF_NOT_SUPPORTED;
ASSERT_RESULT_OK(mTestMap.writeValue(TEST_PROC_KEY_1, TEST_PROC_VAL_1, BPF_ANY));
ASSERT_RESULT_OK(mTestMap.writeValue(TEST_PROC_KEY_2, TEST_PROC_VAL_2, BPF_ANY));
mTestableGpuMem.setGpuMemTotalMap(mTestMap);
diff --git a/services/inputflinger/dispatcher/Android.bp b/services/inputflinger/dispatcher/Android.bp
index d29d8df..390c6b8 100644
--- a/services/inputflinger/dispatcher/Android.bp
+++ b/services/inputflinger/dispatcher/Android.bp
@@ -68,5 +68,4 @@
export_header_lib_headers: [
"libinputdispatcher_headers",
],
- logtags: ["EventLogTags.logtags"],
}
diff --git a/services/inputflinger/dispatcher/EventLogTags.logtags b/services/inputflinger/dispatcher/EventLogTags.logtags
deleted file mode 100644
index 9c0f80e..0000000
--- a/services/inputflinger/dispatcher/EventLogTags.logtags
+++ /dev/null
@@ -1,42 +0,0 @@
-# The entries in this file map a sparse set of log tag numbers to tag names.
-# This is installed on the device, in /system/etc, and parsed by logcat.
-#
-# Tag numbers are decimal integers, from 0 to 2^31. (Let's leave the
-# negative values alone for now.)
-#
-# Tag names are one or more ASCII letters and numbers or underscores, i.e.
-# "[A-Z][a-z][0-9]_". Do not include spaces or punctuation (the former
-# impacts log readability, the latter makes regex searches more annoying).
-#
-# Tag numbers and names are separated by whitespace. Blank lines and lines
-# starting with '#' are ignored.
-#
-# Optionally, after the tag names can be put a description for the value(s)
-# of the tag. Description are in the format
-# (<name>|data type[|data unit])
-# Multiple values are separated by commas.
-#
-# The data type is a number from the following values:
-# 1: int
-# 2: long
-# 3: string
-# 4: list
-#
-# The data unit is a number taken from the following list:
-# 1: Number of objects
-# 2: Number of bytes
-# 3: Number of milliseconds
-# 4: Number of allocations
-# 5: Id
-# 6: Percent
-# Default value for data of type int/long is 2 (bytes).
-#
-# See system/core/logcat/event.logtags for the master copy of the tags.
-
-# 62000 - 62199 reserved for inputflinger
-
-62000 input_interaction (windows|4)
-62001 input_focus (window|3)
-
-# NOTE - the range 1000000-2000000 is reserved for partners and others who
-# want to define their own log tags without conflicting with the core platform.
\ No newline at end of file
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index c139dc5..91803c8 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -62,7 +62,6 @@
#include <binder/Binder.h>
#include <input/InputDevice.h>
#include <log/log.h>
-#include <log/log_event_list.h>
#include <openssl/hmac.h>
#include <openssl/rand.h>
#include <powermanager/PowerManager.h>
@@ -104,10 +103,6 @@
// Number of recent events to keep for debugging purposes.
constexpr size_t RECENT_QUEUE_MAX_SIZE = 10;
-// Event log tags. See EventLogTags.logtags for reference
-constexpr int LOGTAG_INPUT_INTERACTION = 62000;
-constexpr int LOGTAG_INPUT_FOCUS = 62001;
-
static inline nsecs_t now() {
return systemTime(SYSTEM_TIME_MONOTONIC);
}
@@ -722,7 +717,7 @@
for (TouchedMonitor& gestureMonitor : gestureMonitors) {
sp<Connection> connection =
getConnectionLocked(gestureMonitor.monitor.inputChannel->getConnectionToken());
- if (connection->responsive) {
+ if (connection != nullptr && connection->responsive) {
// This monitor could take more input. Drop all events preceding this
// event, so that gesture monitor could get a chance to receive the stream
ALOGW("Pruning the input queue because %s is unresponsive, but we have a "
@@ -1109,9 +1104,7 @@
target.inputChannel = channel;
target.flags = InputTarget::FLAG_DISPATCH_AS_IS;
entry->dispatchInProgress = true;
- std::string message = std::string("Focus ") + (entry->hasFocus ? "entering " : "leaving ") +
- channel->getName();
- android_log_event_list(LOGTAG_INPUT_FOCUS) << message << LOG_ID_EVENTS;
+
dispatchEventLocked(currentTime, entry, {target});
}
@@ -1349,8 +1342,6 @@
ALOGD("dispatchEventToCurrentInputTargets");
#endif
- updateInteractionTokensLocked(*eventEntry, inputTargets);
-
ALOG_ASSERT(eventEntry->dispatchInProgress); // should already have been set to true
pokeUserActivityLocked(*eventEntry);
@@ -2097,14 +2088,9 @@
auto otherInfo = otherHandle->getInfo();
if (!otherInfo->visible) {
return false;
- } else if (info->ownerPid == otherInfo->ownerPid && otherHandle->getToken() == nullptr) {
- // In general, if ownerPid is the same we don't want to generate occlusion
- // events. This line is now necessary since we are including all Surfaces
- // in occlusion calculation, so if we didn't check PID like this SurfaceView
- // would occlude their parents. On the other hand before we started including
- // all surfaces in occlusion calculation and had this line, we would count
- // windows with an input channel from the same PID as occluding, and so we
- // preserve this behavior with the getToken() == null check.
+ } else if (info->ownerPid == otherInfo->ownerPid) {
+ // If ownerPid is the same we don't generate occlusion events as there
+ // is no in-process security boundary.
return false;
} else if (otherInfo->trustedOverlay) {
return false;
@@ -2438,73 +2424,6 @@
traceOutboundQueueLength(connection);
}
-/**
- * This function is purely for debugging. It helps us understand where the user interaction
- * was taking place. For example, if user is touching launcher, we will see a log that user
- * started interacting with launcher. In that example, the event would go to the wallpaper as well.
- * We will see both launcher and wallpaper in that list.
- * Once the interaction with a particular set of connections starts, no new logs will be printed
- * until the set of interacted connections changes.
- *
- * The following items are skipped, to reduce the logspam:
- * ACTION_OUTSIDE: any windows that are receiving ACTION_OUTSIDE are not logged
- * ACTION_UP: any windows that receive ACTION_UP are not logged (for both keys and motions).
- * This includes situations like the soft BACK button key. When the user releases (lifts up the
- * finger) the back button, then navigation bar will inject KEYCODE_BACK with ACTION_UP.
- * Both of those ACTION_UP events would not be logged
- * Monitors (both gesture and global): any gesture monitors or global monitors receiving events
- * will not be logged. This is omitted to reduce the amount of data printed.
- * If you see <none>, it's likely that one of the gesture monitors pilfered the event, and therefore
- * gesture monitor is the only connection receiving the remainder of the gesture.
- */
-void InputDispatcher::updateInteractionTokensLocked(const EventEntry& entry,
- const std::vector<InputTarget>& targets) {
- // Skip ACTION_UP events, and all events other than keys and motions
- if (entry.type == EventEntry::Type::KEY) {
- const KeyEntry& keyEntry = static_cast<const KeyEntry&>(entry);
- if (keyEntry.action == AKEY_EVENT_ACTION_UP) {
- return;
- }
- } else if (entry.type == EventEntry::Type::MOTION) {
- const MotionEntry& motionEntry = static_cast<const MotionEntry&>(entry);
- if (motionEntry.action == AMOTION_EVENT_ACTION_UP) {
- return;
- }
- } else {
- return; // Not a key or a motion
- }
-
- std::unordered_set<sp<IBinder>, IBinderHash> newConnections;
- for (const InputTarget& target : targets) {
- if ((target.flags & InputTarget::FLAG_DISPATCH_AS_OUTSIDE) ==
- InputTarget::FLAG_DISPATCH_AS_OUTSIDE) {
- continue; // Skip windows that receive ACTION_OUTSIDE
- }
-
- sp<IBinder> token = target.inputChannel->getConnectionToken();
- sp<Connection> connection = getConnectionLocked(token); // get connection
- if (connection->monitor) {
- continue; // We only need to keep track of the non-monitor connections.
- }
-
- newConnections.insert(std::move(token));
- }
- if (newConnections == mInteractionConnections) {
- return; // no change
- }
- mInteractionConnections = newConnections;
- std::string windowList;
- for (const sp<IBinder>& token : newConnections) {
- sp<Connection> connection = getConnectionLocked(token);
- windowList += connection->getWindowName() + ", ";
- }
- std::string message = "Interaction with windows: " + windowList;
- if (windowList.empty()) {
- message += "<none>";
- }
- android_log_event_list(LOGTAG_INPUT_INTERACTION) << message << LOG_ID_EVENTS;
-}
-
void InputDispatcher::dispatchPointerDownOutsideFocus(uint32_t source, int32_t action,
const sp<IBinder>& newToken) {
int32_t maskedAction = action & AMOTION_EVENT_ACTION_MASK;
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index 7c2028a..e679c6b 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -49,7 +49,6 @@
#include <deque>
#include <optional>
#include <unordered_map>
-#include <unordered_set>
#include <InputListener.h>
#include <InputReporterInterface.h>
@@ -327,11 +326,6 @@
// Dispatcher state at time of last ANR.
std::string mLastAnrState GUARDED_BY(mLock);
- // The connection token of the channel that was last interacted with.
- std::unordered_set<sp<IBinder>, IBinderHash> mInteractionConnections GUARDED_BY(mLock);
- void updateInteractionTokensLocked(const EventEntry& entry,
- const std::vector<InputTarget>& targets) REQUIRES(mLock);
-
// Dispatch inbound events.
bool dispatchConfigurationChangedLocked(nsecs_t currentTime, ConfigurationChangedEntry* entry)
REQUIRES(mLock);
diff --git a/services/powermanager/PowerHalController.cpp b/services/powermanager/PowerHalController.cpp
index d26d582..178f545 100644
--- a/services/powermanager/PowerHalController.cpp
+++ b/services/powermanager/PowerHalController.cpp
@@ -15,40 +15,39 @@
*/
#define LOG_TAG "PowerHalController"
-#include <utils/Log.h>
-
#include <android/hardware/power/1.1/IPower.h>
#include <android/hardware/power/Boost.h>
#include <android/hardware/power/IPower.h>
#include <android/hardware/power/Mode.h>
-
#include <powermanager/PowerHalController.h>
#include <powermanager/PowerHalLoader.h>
+#include <utils/Log.h>
-using android::hardware::power::Boost;
-using android::hardware::power::Mode;
+using namespace android::hardware::power;
namespace android {
+namespace power {
+
// -------------------------------------------------------------------------------------------------
-std::unique_ptr<PowerHalWrapper> PowerHalConnector::connect() {
- sp<IPowerAidl> halAidl = PowerHalLoader::loadAidl();
+std::unique_ptr<HalWrapper> HalConnector::connect() {
+ sp<IPower> halAidl = PowerHalLoader::loadAidl();
if (halAidl) {
- return std::make_unique<AidlPowerHalWrapper>(halAidl);
+ return std::make_unique<AidlHalWrapper>(halAidl);
}
- sp<IPowerV1_0> halHidlV1_0 = PowerHalLoader::loadHidlV1_0();
- sp<IPowerV1_1> halHidlV1_1 = PowerHalLoader::loadHidlV1_1();
+ sp<V1_0::IPower> halHidlV1_0 = PowerHalLoader::loadHidlV1_0();
+ sp<V1_1::IPower> halHidlV1_1 = PowerHalLoader::loadHidlV1_1();
if (halHidlV1_1) {
- return std::make_unique<HidlPowerHalWrapperV1_1>(halHidlV1_0, halHidlV1_1);
+ return std::make_unique<HidlHalWrapperV1_1>(halHidlV1_0, halHidlV1_1);
}
if (halHidlV1_0) {
- return std::make_unique<HidlPowerHalWrapperV1_0>(halHidlV1_0);
+ return std::make_unique<HidlHalWrapperV1_0>(halHidlV1_0);
}
return nullptr;
}
-void PowerHalConnector::reset() {
+void HalConnector::reset() {
PowerHalLoader::unloadAll();
}
@@ -58,8 +57,9 @@
initHal();
}
-// Check validity of current handle to the power HAL service, and create a new one if necessary.
-std::shared_ptr<PowerHalWrapper> PowerHalController::initHal() {
+// Check validity of current handle to the power HAL service, and create a new
+// one if necessary.
+std::shared_ptr<HalWrapper> PowerHalController::initHal() {
std::lock_guard<std::mutex> lock(mConnectedHalMutex);
if (mConnectedHal == nullptr) {
mConnectedHal = mHalConnector->connect();
@@ -71,10 +71,10 @@
return mConnectedHal;
}
-// Check if a call to Power HAL function failed; if so, log the failure and invalidate the
-// current Power HAL handle.
-PowerHalResult PowerHalController::processHalResult(PowerHalResult result, const char* fnName) {
- if (result == PowerHalResult::FAILED) {
+// Check if a call to Power HAL function failed; if so, log the failure and
+// invalidate the current Power HAL handle.
+HalResult PowerHalController::processHalResult(HalResult result, const char* fnName) {
+ if (result == HalResult::FAILED) {
ALOGE("%s() failed: power HAL service not available.", fnName);
std::lock_guard<std::mutex> lock(mConnectedHalMutex);
// Drop Power HAL handle. This will force future api calls to reconnect.
@@ -84,16 +84,18 @@
return result;
}
-PowerHalResult PowerHalController::setBoost(Boost boost, int32_t durationMs) {
- std::shared_ptr<PowerHalWrapper> handle = initHal();
+HalResult PowerHalController::setBoost(Boost boost, int32_t durationMs) {
+ std::shared_ptr<HalWrapper> handle = initHal();
auto result = handle->setBoost(boost, durationMs);
return processHalResult(result, "setBoost");
}
-PowerHalResult PowerHalController::setMode(Mode mode, bool enabled) {
- std::shared_ptr<PowerHalWrapper> handle = initHal();
+HalResult PowerHalController::setMode(Mode mode, bool enabled) {
+ std::shared_ptr<HalWrapper> handle = initHal();
auto result = handle->setMode(mode, enabled);
return processHalResult(result, "setMode");
}
-}; // namespace android
+} // namespace power
+
+} // namespace android
diff --git a/services/powermanager/PowerHalLoader.cpp b/services/powermanager/PowerHalLoader.cpp
index 3ae5384..1f1b43a 100644
--- a/services/powermanager/PowerHalLoader.cpp
+++ b/services/powermanager/PowerHalLoader.cpp
@@ -21,15 +21,14 @@
#include <binder/IServiceManager.h>
#include <hardware/power.h>
#include <hardware_legacy/power.h>
-
#include <powermanager/PowerHalLoader.h>
-using IPowerV1_1 = android::hardware::power::V1_1::IPower;
-using IPowerV1_0 = android::hardware::power::V1_0::IPower;
-using IPowerAidl = android::hardware::power::IPower;
+using namespace android::hardware::power;
namespace android {
+namespace power {
+
// -------------------------------------------------------------------------------------------------
template <typename T, typename F>
@@ -53,9 +52,9 @@
// -------------------------------------------------------------------------------------------------
std::mutex PowerHalLoader::gHalMutex;
-sp<IPowerAidl> PowerHalLoader::gHalAidl = nullptr;
-sp<IPowerV1_0> PowerHalLoader::gHalHidlV1_0 = nullptr;
-sp<IPowerV1_1> PowerHalLoader::gHalHidlV1_1 = nullptr;
+sp<IPower> PowerHalLoader::gHalAidl = nullptr;
+sp<V1_0::IPower> PowerHalLoader::gHalHidlV1_0 = nullptr;
+sp<V1_1::IPower> PowerHalLoader::gHalHidlV1_1 = nullptr;
void PowerHalLoader::unloadAll() {
std::lock_guard<std::mutex> lock(gHalMutex);
@@ -64,31 +63,33 @@
gHalHidlV1_1 = nullptr;
}
-sp<IPowerAidl> PowerHalLoader::loadAidl() {
+sp<IPower> PowerHalLoader::loadAidl() {
std::lock_guard<std::mutex> lock(gHalMutex);
static bool gHalExists = true;
- static auto loadFn = []() { return waitForVintfService<IPowerAidl>(); };
- return loadHal<IPowerAidl>(gHalExists, gHalAidl, loadFn, "AIDL");
+ static auto loadFn = []() { return waitForVintfService<IPower>(); };
+ return loadHal<IPower>(gHalExists, gHalAidl, loadFn, "AIDL");
}
-sp<IPowerV1_0> PowerHalLoader::loadHidlV1_0() {
+sp<V1_0::IPower> PowerHalLoader::loadHidlV1_0() {
std::lock_guard<std::mutex> lock(gHalMutex);
return loadHidlV1_0Locked();
}
-sp<IPowerV1_1> PowerHalLoader::loadHidlV1_1() {
+sp<V1_1::IPower> PowerHalLoader::loadHidlV1_1() {
std::lock_guard<std::mutex> lock(gHalMutex);
static bool gHalExists = true;
- static auto loadFn = []() { return IPowerV1_1::castFrom(loadHidlV1_0Locked()); };
- return loadHal<IPowerV1_1>(gHalExists, gHalHidlV1_1, loadFn, "HIDL v1.1");
+ static auto loadFn = []() { return V1_1::IPower::castFrom(loadHidlV1_0Locked()); };
+ return loadHal<V1_1::IPower>(gHalExists, gHalHidlV1_1, loadFn, "HIDL v1.1");
}
-sp<IPowerV1_0> PowerHalLoader::loadHidlV1_0Locked() {
+sp<V1_0::IPower> PowerHalLoader::loadHidlV1_0Locked() {
static bool gHalExists = true;
- static auto loadFn = []() { return IPowerV1_0::getService(); };
- return loadHal<IPowerV1_0>(gHalExists, gHalHidlV1_0, loadFn, "HIDL v1.0");
+ static auto loadFn = []() { return V1_0::IPower::getService(); };
+ return loadHal<V1_0::IPower>(gHalExists, gHalHidlV1_0, loadFn, "HIDL v1.0");
}
// -------------------------------------------------------------------------------------------------
+} // namespace power
+
} // namespace android
diff --git a/services/powermanager/PowerHalWrapper.cpp b/services/powermanager/PowerHalWrapper.cpp
index d959a2c..5f4bfed 100644
--- a/services/powermanager/PowerHalWrapper.cpp
+++ b/services/powermanager/PowerHalWrapper.cpp
@@ -14,159 +14,162 @@
* limitations under the License.
*/
-#define LOG_TAG "PowerHalWrapper"
-#include <utils/Log.h>
-
+#define LOG_TAG "HalWrapper"
#include <android/hardware/power/Boost.h>
#include <android/hardware/power/Mode.h>
-
#include <powermanager/PowerHalWrapper.h>
+#include <utils/Log.h>
-using android::hardware::power::Boost;
-using android::hardware::power::Mode;
-using android::hardware::power::V1_0::Feature;
-using android::hardware::power::V1_0::PowerHint;
+using namespace android::hardware::power;
namespace android {
+namespace power {
+
// -------------------------------------------------------------------------------------------------
-PowerHalResult EmptyPowerHalWrapper::setBoost(Boost boost, int32_t durationMs) {
+inline HalResult toHalResult(const binder::Status& result) {
+ return result.isOk() ? HalResult::SUCCESSFUL : HalResult::FAILED;
+}
+
+template <typename T>
+inline HalResult toHalResult(const hardware::Return<T>& result) {
+ return result.isOk() ? HalResult::SUCCESSFUL : HalResult::FAILED;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+HalResult EmptyHalWrapper::setBoost(Boost boost, int32_t durationMs) {
ALOGV("Skipped setBoost %s with duration %dms because Power HAL not available",
- toString(boost).c_str(), durationMs);
- return PowerHalResult::UNSUPPORTED;
+ toString(boost).c_str(), durationMs);
+ return HalResult::UNSUPPORTED;
}
-PowerHalResult EmptyPowerHalWrapper::setMode(Mode mode, bool enabled) {
- ALOGV("Skipped setMode %s to %s because Power HAL not available",
- toString(mode).c_str(), enabled ? "true" : "false");
- return PowerHalResult::UNSUPPORTED;
+HalResult EmptyHalWrapper::setMode(Mode mode, bool enabled) {
+ ALOGV("Skipped setMode %s to %s because Power HAL not available", toString(mode).c_str(),
+ enabled ? "true" : "false");
+ return HalResult::UNSUPPORTED;
}
// -------------------------------------------------------------------------------------------------
-PowerHalResult HidlPowerHalWrapperV1_0::setBoost(Boost boost, int32_t durationMs) {
+HalResult HidlHalWrapperV1_0::setBoost(Boost boost, int32_t durationMs) {
if (boost == Boost::INTERACTION) {
- return sendPowerHint(PowerHint::INTERACTION, durationMs);
+ return sendPowerHint(V1_0::PowerHint::INTERACTION, durationMs);
} else {
- ALOGV("Skipped setBoost %s because Power HAL AIDL not available",
- toString(boost).c_str());
- return PowerHalResult::UNSUPPORTED;
+ ALOGV("Skipped setBoost %s because Power HAL AIDL not available", toString(boost).c_str());
+ return HalResult::UNSUPPORTED;
}
}
-PowerHalResult HidlPowerHalWrapperV1_0::setMode(Mode mode, bool enabled) {
+HalResult HidlHalWrapperV1_0::setMode(Mode mode, bool enabled) {
uint32_t data = enabled ? 1 : 0;
switch (mode) {
case Mode::LAUNCH:
- return sendPowerHint(PowerHint::LAUNCH, data);
+ return sendPowerHint(V1_0::PowerHint::LAUNCH, data);
case Mode::LOW_POWER:
- return sendPowerHint(PowerHint::LOW_POWER, data);
+ return sendPowerHint(V1_0::PowerHint::LOW_POWER, data);
case Mode::SUSTAINED_PERFORMANCE:
- return sendPowerHint(PowerHint::SUSTAINED_PERFORMANCE, data);
+ return sendPowerHint(V1_0::PowerHint::SUSTAINED_PERFORMANCE, data);
case Mode::VR:
- return sendPowerHint(PowerHint::VR_MODE, data);
+ return sendPowerHint(V1_0::PowerHint::VR_MODE, data);
case Mode::INTERACTIVE:
return setInteractive(enabled);
case Mode::DOUBLE_TAP_TO_WAKE:
- return setFeature(Feature::POWER_FEATURE_DOUBLE_TAP_TO_WAKE, enabled);
+ return setFeature(V1_0::Feature::POWER_FEATURE_DOUBLE_TAP_TO_WAKE, enabled);
default:
ALOGV("Skipped setMode %s because Power HAL AIDL not available",
- toString(mode).c_str());
- return PowerHalResult::UNSUPPORTED;
+ toString(mode).c_str());
+ return HalResult::UNSUPPORTED;
}
}
-PowerHalResult HidlPowerHalWrapperV1_0::sendPowerHint(PowerHint hintId, uint32_t data) {
- auto ret = handleV1_0->powerHint(hintId, data);
- return ret.isOk() ? PowerHalResult::SUCCESSFUL : PowerHalResult::FAILED;
+HalResult HidlHalWrapperV1_0::sendPowerHint(V1_0::PowerHint hintId, uint32_t data) {
+ return toHalResult(mHandleV1_0->powerHint(hintId, data));
}
-PowerHalResult HidlPowerHalWrapperV1_0::setInteractive(bool enabled) {
- auto ret = handleV1_0->setInteractive(enabled);
- return ret.isOk() ? PowerHalResult::SUCCESSFUL : PowerHalResult::FAILED;
+HalResult HidlHalWrapperV1_0::setInteractive(bool enabled) {
+ return toHalResult(mHandleV1_0->setInteractive(enabled));
}
-PowerHalResult HidlPowerHalWrapperV1_0::setFeature(Feature feature, bool enabled) {
- auto ret = handleV1_0->setFeature(feature, enabled);
- return ret.isOk() ? PowerHalResult::SUCCESSFUL : PowerHalResult::FAILED;
+HalResult HidlHalWrapperV1_0::setFeature(V1_0::Feature feature, bool enabled) {
+ return toHalResult(mHandleV1_0->setFeature(feature, enabled));
}
// -------------------------------------------------------------------------------------------------
-PowerHalResult HidlPowerHalWrapperV1_1::sendPowerHint(PowerHint hintId, uint32_t data) {
- auto ret = handleV1_1->powerHintAsync(hintId, data);
- return ret.isOk() ? PowerHalResult::SUCCESSFUL : PowerHalResult::FAILED;
+HalResult HidlHalWrapperV1_1::sendPowerHint(V1_0::PowerHint hintId, uint32_t data) {
+ return toHalResult(mHandleV1_1->powerHintAsync(hintId, data));
}
// -------------------------------------------------------------------------------------------------
-PowerHalResult AidlPowerHalWrapper::setBoost(Boost boost, int32_t durationMs) {
+HalResult AidlHalWrapper::setBoost(Boost boost, int32_t durationMs) {
std::unique_lock<std::mutex> lock(mBoostMutex);
// Quick return if boost is not supported by HAL
if (boost > Boost::DISPLAY_UPDATE_IMMINENT ||
- boostSupportedArray[static_cast<int32_t>(boost)] == PowerHalSupport::OFF) {
- ALOGV("Skipped setBoost %s because Power HAL doesn't support it",
- toString(boost).c_str());
- return PowerHalResult::UNSUPPORTED;
+ mBoostSupportedArray[static_cast<int32_t>(boost)] == HalSupport::OFF) {
+ ALOGV("Skipped setBoost %s because Power HAL doesn't support it", toString(boost).c_str());
+ return HalResult::UNSUPPORTED;
}
- if (boostSupportedArray[static_cast<int32_t>(boost)] == PowerHalSupport::UNKNOWN) {
+ if (mBoostSupportedArray[static_cast<int32_t>(boost)] == HalSupport::UNKNOWN) {
bool isSupported = false;
- auto isSupportedRet = handle->isBoostSupported(boost, &isSupported);
+ auto isSupportedRet = mHandle->isBoostSupported(boost, &isSupported);
if (!isSupportedRet.isOk()) {
- ALOGV("Skipped setBoost %s because Power HAL is not available to check support",
- toString(boost).c_str());
- return PowerHalResult::FAILED;
+ ALOGV("Skipped setBoost %s because Power HAL is not available to check "
+ "support",
+ toString(boost).c_str());
+ return HalResult::FAILED;
}
- boostSupportedArray[static_cast<int32_t>(boost)] =
- isSupported ? PowerHalSupport::ON : PowerHalSupport::OFF;
+ mBoostSupportedArray[static_cast<int32_t>(boost)] =
+ isSupported ? HalSupport::ON : HalSupport::OFF;
if (!isSupported) {
ALOGV("Skipped setBoost %s because Power HAL doesn't support it",
- toString(boost).c_str());
- return PowerHalResult::UNSUPPORTED;
+ toString(boost).c_str());
+ return HalResult::UNSUPPORTED;
}
}
lock.unlock();
- auto ret = handle->setBoost(boost, durationMs);
- return ret.isOk() ? PowerHalResult::SUCCESSFUL : PowerHalResult::FAILED;
+ return toHalResult(mHandle->setBoost(boost, durationMs));
}
-PowerHalResult AidlPowerHalWrapper::setMode(Mode mode, bool enabled) {
+HalResult AidlHalWrapper::setMode(Mode mode, bool enabled) {
std::unique_lock<std::mutex> lock(mModeMutex);
// Quick return if mode is not supported by HAL
if (mode > Mode::DISPLAY_INACTIVE ||
- modeSupportedArray[static_cast<int32_t>(mode)] == PowerHalSupport::OFF) {
- ALOGV("Skipped setMode %s because Power HAL doesn't support it",
- toString(mode).c_str());
- return PowerHalResult::UNSUPPORTED;
+ mModeSupportedArray[static_cast<int32_t>(mode)] == HalSupport::OFF) {
+ ALOGV("Skipped setMode %s because Power HAL doesn't support it", toString(mode).c_str());
+ return HalResult::UNSUPPORTED;
}
- if (modeSupportedArray[static_cast<int32_t>(mode)] == PowerHalSupport::UNKNOWN) {
+ if (mModeSupportedArray[static_cast<int32_t>(mode)] == HalSupport::UNKNOWN) {
bool isSupported = false;
- auto isSupportedRet = handle->isModeSupported(mode, &isSupported);
+ auto isSupportedRet = mHandle->isModeSupported(mode, &isSupported);
if (!isSupportedRet.isOk()) {
- ALOGV("Skipped setMode %s because Power HAL is not available to check support",
- toString(mode).c_str());
- return PowerHalResult::FAILED;
+ ALOGV("Skipped setMode %s because Power HAL is not available to check "
+ "support",
+ toString(mode).c_str());
+ return HalResult::FAILED;
}
- modeSupportedArray[static_cast<int32_t>(mode)] =
- isSupported ? PowerHalSupport::ON : PowerHalSupport::OFF;
+ mModeSupportedArray[static_cast<int32_t>(mode)] =
+ isSupported ? HalSupport::ON : HalSupport::OFF;
if (!isSupported) {
- ALOGV("Skipped setMode %s because Power HAL doesn't support it",
- toString(mode).c_str());
- return PowerHalResult::UNSUPPORTED;
+ ALOGV("Skipped setMode %s because Power HAL doesn't support it",
+ toString(mode).c_str());
+ return HalResult::UNSUPPORTED;
}
}
lock.unlock();
- auto ret = handle->setMode(mode, enabled);
- return ret.isOk() ? PowerHalResult::SUCCESSFUL : PowerHalResult::FAILED;
+ return toHalResult(mHandle->setMode(mode, enabled));
}
// -------------------------------------------------------------------------------------------------
-}; // namespace android
+} // namespace power
+
+} // namespace android
diff --git a/services/powermanager/TEST_MAPPING b/services/powermanager/TEST_MAPPING
index 9a67901..caaec55 100644
--- a/services/powermanager/TEST_MAPPING
+++ b/services/powermanager/TEST_MAPPING
@@ -1,10 +1,7 @@
{
"presubmit": [
{
- "name": "powermanager_test"
- },
- {
- "name": "thermalmanager_test"
+ "name": "libpowermanager_test"
}
]
}
diff --git a/services/powermanager/tests/Android.bp b/services/powermanager/tests/Android.bp
index 70837cf..49abc11 100644
--- a/services/powermanager/tests/Android.bp
+++ b/services/powermanager/tests/Android.bp
@@ -13,9 +13,10 @@
// limitations under the License.
cc_test {
- name: "powermanager_test",
+ name: "libpowermanager_test",
test_suites: ["device-tests"],
srcs: [
+ "IThermalManagerTest.cpp",
"PowerHalControllerTest.cpp",
"PowerHalLoaderTest.cpp",
"PowerHalWrapperAidlTest.cpp",
@@ -42,22 +43,3 @@
"libgmock",
],
}
-
-cc_test {
- name: "thermalmanager_test",
- test_suites: ["device-tests"],
- srcs: ["IThermalManagerTest.cpp",],
- cflags: [
- "-Wall",
- "-Werror",
- "-Wextra",
- ],
- shared_libs: [
- "libbase",
- "libhidlbase",
- "liblog",
- "libpowermanager",
- "libbinder",
- "libutils",
- ],
-}
diff --git a/services/powermanager/tests/PowerHalControllerTest.cpp b/services/powermanager/tests/PowerHalControllerTest.cpp
index ac1e19a..141b244 100644
--- a/services/powermanager/tests/PowerHalControllerTest.cpp
+++ b/services/powermanager/tests/PowerHalControllerTest.cpp
@@ -19,15 +19,12 @@
#include <android/hardware/power/Boost.h>
#include <android/hardware/power/IPower.h>
#include <android/hardware/power/Mode.h>
-
#include <gmock/gmock.h>
#include <gtest/gtest.h>
-
-#include <powermanager/PowerHalWrapper.h>
#include <powermanager/PowerHalController.h>
+#include <utils/Log.h>
#include <thread>
-#include <utils/Log.h>
using android::hardware::power::Boost;
using android::hardware::power::Mode;
@@ -36,6 +33,7 @@
using android::hardware::power::V1_0::PowerHint;
using namespace android;
+using namespace android::power;
using namespace std::chrono_literals;
using namespace testing;
@@ -45,23 +43,21 @@
public:
MOCK_METHOD(hardware::Return<void>, setInteractive, (bool interactive), (override));
MOCK_METHOD(hardware::Return<void>, powerHint, (PowerHint hint, int32_t data), (override));
- MOCK_METHOD(
- hardware::Return<void>, setFeature, (Feature feature, bool activate), (override));
- MOCK_METHOD(
- hardware::Return<void>, getPlatformLowPowerStats,
- (getPlatformLowPowerStats_cb _hidl_cb), (override));
+ MOCK_METHOD(hardware::Return<void>, setFeature, (Feature feature, bool activate), (override));
+ MOCK_METHOD(hardware::Return<void>, getPlatformLowPowerStats,
+ (getPlatformLowPowerStats_cb _hidl_cb), (override));
};
-class TestPowerHalConnector : public PowerHalConnector {
+class TestPowerHalConnector : public HalConnector {
public:
TestPowerHalConnector(sp<IPower> powerHal) : mHal(std::move(powerHal)) {}
virtual ~TestPowerHalConnector() = default;
- virtual std::unique_ptr<PowerHalWrapper> connect() override {
+ virtual std::unique_ptr<HalWrapper> connect() override {
mCountMutex.lock();
++mConnectedCount;
mCountMutex.unlock();
- return std::make_unique<HidlPowerHalWrapperV1_0>(mHal);
+ return std::make_unique<HidlHalWrapperV1_0>(mHal);
}
void reset() override {
@@ -70,13 +66,9 @@
mCountMutex.unlock();
}
- int getConnectCount() {
- return mConnectedCount;
- }
+ int getConnectCount() { return mConnectedCount; }
- int getResetCount() {
- return mResetCount;
- }
+ int getResetCount() { return mResetCount; }
private:
sp<IPower> mHal = nullptr;
@@ -89,8 +81,8 @@
public:
AlwaysFailingTestPowerHalConnector() : TestPowerHalConnector(nullptr) {}
- std::unique_ptr<PowerHalWrapper> connect() override {
- // Call parent to update counter, but ignore connected PowerHalWrapper.
+ std::unique_ptr<HalWrapper> connect() override {
+ // Call parent to update counter, but ignore connected HalWrapper.
TestPowerHalConnector::connect();
return nullptr;
}
@@ -103,7 +95,7 @@
void SetUp() override {
mMockHal = new StrictMock<MockIPowerV1_0>();
std::unique_ptr<TestPowerHalConnector> halConnector =
- std::make_unique<TestPowerHalConnector>(mMockHal);
+ std::make_unique<TestPowerHalConnector>(mMockHal);
mHalConnector = halConnector.get();
mHalController = std::make_unique<PowerHalController>(std::move(halConnector));
}
@@ -132,20 +124,22 @@
TEST_F(PowerHalControllerTest, TestUnableToConnectToPowerHalIgnoresAllApiCalls) {
std::unique_ptr<AlwaysFailingTestPowerHalConnector> halConnector =
- std::make_unique<AlwaysFailingTestPowerHalConnector>();
+ std::make_unique<AlwaysFailingTestPowerHalConnector>();
AlwaysFailingTestPowerHalConnector* failingHalConnector = halConnector.get();
PowerHalController halController(std::move(halConnector));
int powerHalConnectCount = failingHalConnector->getConnectCount();
EXPECT_EQ(powerHalConnectCount, 0);
- // Still works with EmptyPowerHalWrapper as fallback ignoring every api call and logging.
+ // Still works with EmptyPowerHalWrapper as fallback ignoring every api call
+ // and logging.
auto result = halController.setBoost(Boost::INTERACTION, 1000);
- ASSERT_EQ(PowerHalResult::UNSUPPORTED, result);
+ ASSERT_EQ(HalResult::UNSUPPORTED, result);
result = halController.setMode(Mode::LAUNCH, true);
- ASSERT_EQ(PowerHalResult::UNSUPPORTED, result);
+ ASSERT_EQ(HalResult::UNSUPPORTED, result);
- // PowerHalConnector was called every time to attempt to reconnect with underlying service.
+ // PowerHalConnector was called every time to attempt to reconnect with
+ // underlying service.
powerHalConnectCount = failingHalConnector->getConnectCount();
EXPECT_EQ(powerHalConnectCount, 2);
// PowerHalConnector was never reset.
@@ -160,15 +154,14 @@
{
InSequence seg;
EXPECT_CALL(*mMockHal.get(), powerHint(Eq(PowerHint::INTERACTION), Eq(100)))
- .Times(Exactly(1));
- EXPECT_CALL(*mMockHal.get(), powerHint(Eq(PowerHint::LAUNCH), Eq(1)))
- .Times(Exactly(1));
+ .Times(Exactly(1));
+ EXPECT_CALL(*mMockHal.get(), powerHint(Eq(PowerHint::LAUNCH), Eq(1))).Times(Exactly(1));
}
auto result = mHalController->setBoost(Boost::INTERACTION, 100);
- ASSERT_EQ(PowerHalResult::SUCCESSFUL, result);
+ ASSERT_EQ(HalResult::SUCCESSFUL, result);
result = mHalController->setMode(Mode::LAUNCH, true);
- ASSERT_EQ(PowerHalResult::SUCCESSFUL, result);
+ ASSERT_EQ(HalResult::SUCCESSFUL, result);
// PowerHalConnector was called only once and never reset.
powerHalConnectCount = mHalConnector->getConnectCount();
@@ -182,23 +175,23 @@
EXPECT_EQ(powerHalConnectCount, 0);
ON_CALL(*mMockHal.get(), powerHint(Eq(PowerHint::LAUNCH), _))
- .WillByDefault([](PowerHint, int32_t) {
- return hardware::Return<void>(hardware::Status::fromExceptionCode(-1));
- });
+ .WillByDefault([](PowerHint, int32_t) {
+ return hardware::Return<void>(hardware::Status::fromExceptionCode(-1));
+ });
- EXPECT_CALL(*mMockHal.get(), powerHint(_, _))
- .Times(Exactly(4));
+ EXPECT_CALL(*mMockHal.get(), powerHint(_, _)).Times(Exactly(4));
auto result = mHalController->setBoost(Boost::INTERACTION, 1000);
- ASSERT_EQ(PowerHalResult::SUCCESSFUL, result);
+ ASSERT_EQ(HalResult::SUCCESSFUL, result);
result = mHalController->setMode(Mode::LAUNCH, true);
- ASSERT_EQ(PowerHalResult::FAILED, result);
+ ASSERT_EQ(HalResult::FAILED, result);
result = mHalController->setMode(Mode::VR, false);
- ASSERT_EQ(PowerHalResult::SUCCESSFUL, result);
+ ASSERT_EQ(HalResult::SUCCESSFUL, result);
result = mHalController->setMode(Mode::LOW_POWER, true);
- ASSERT_EQ(PowerHalResult::SUCCESSFUL, result);
+ ASSERT_EQ(HalResult::SUCCESSFUL, result);
- // PowerHalConnector was called only twice: on first api call and after failed call.
+ // PowerHalConnector was called only twice: on first api call and after failed
+ // call.
powerHalConnectCount = mHalConnector->getConnectCount();
EXPECT_EQ(powerHalConnectCount, 2);
// PowerHalConnector was reset once after failed call.
@@ -211,9 +204,9 @@
EXPECT_EQ(powerHalConnectCount, 0);
auto result = mHalController->setBoost(Boost::CAMERA_LAUNCH, 1000);
- ASSERT_EQ(PowerHalResult::UNSUPPORTED, result);
+ ASSERT_EQ(HalResult::UNSUPPORTED, result);
result = mHalController->setMode(Mode::CAMERA_STREAMING_HIGH, true);
- ASSERT_EQ(PowerHalResult::UNSUPPORTED, result);
+ ASSERT_EQ(HalResult::UNSUPPORTED, result);
// PowerHalConnector was called only once and never reset.
powerHalConnectCount = mHalConnector->getConnectCount();
@@ -226,19 +219,19 @@
int powerHalConnectCount = mHalConnector->getConnectCount();
EXPECT_EQ(powerHalConnectCount, 0);
- EXPECT_CALL(*mMockHal.get(), powerHint(_, _))
- .Times(Exactly(10));
+ EXPECT_CALL(*mMockHal.get(), powerHint(_, _)).Times(Exactly(10));
std::vector<std::thread> threads;
for (int i = 0; i < 10; i++) {
threads.push_back(std::thread([&]() {
auto result = mHalController->setBoost(Boost::INTERACTION, 1000);
- ASSERT_EQ(PowerHalResult::SUCCESSFUL, result);
+ ASSERT_EQ(HalResult::SUCCESSFUL, result);
}));
}
std::for_each(threads.begin(), threads.end(), [](std::thread& t) { t.join(); });
- // PowerHalConnector was called only by the first thread to use the api and never reset.
+ // PowerHalConnector was called only by the first thread to use the api and
+ // never reset.
powerHalConnectCount = mHalConnector->getConnectCount();
EXPECT_EQ(powerHalConnectCount, 1);
int powerHalResetCount = mHalConnector->getResetCount();
@@ -250,36 +243,36 @@
EXPECT_EQ(powerHalConnectCount, 0);
ON_CALL(*mMockHal.get(), powerHint(Eq(PowerHint::LAUNCH), _))
- .WillByDefault([](PowerHint, int32_t) {
- return hardware::Return<void>(hardware::Status::fromExceptionCode(-1));
- });
+ .WillByDefault([](PowerHint, int32_t) {
+ return hardware::Return<void>(hardware::Status::fromExceptionCode(-1));
+ });
- EXPECT_CALL(*mMockHal.get(), powerHint(_, _))
- .Times(Exactly(40));
+ EXPECT_CALL(*mMockHal.get(), powerHint(_, _)).Times(Exactly(40));
std::vector<std::thread> threads;
for (int i = 0; i < 10; i++) {
threads.push_back(std::thread([&]() {
auto result = mHalController->setBoost(Boost::INTERACTION, 1000);
- ASSERT_EQ(PowerHalResult::SUCCESSFUL, result);
+ ASSERT_EQ(HalResult::SUCCESSFUL, result);
}));
threads.push_back(std::thread([&]() {
auto result = mHalController->setMode(Mode::LAUNCH, true);
- ASSERT_EQ(PowerHalResult::FAILED, result);
+ ASSERT_EQ(HalResult::FAILED, result);
}));
threads.push_back(std::thread([&]() {
auto result = mHalController->setMode(Mode::LOW_POWER, false);
- ASSERT_EQ(PowerHalResult::SUCCESSFUL, result);
+ ASSERT_EQ(HalResult::SUCCESSFUL, result);
}));
threads.push_back(std::thread([&]() {
auto result = mHalController->setMode(Mode::VR, true);
- ASSERT_EQ(PowerHalResult::SUCCESSFUL, result);
+ ASSERT_EQ(HalResult::SUCCESSFUL, result);
}));
}
std::for_each(threads.begin(), threads.end(), [](std::thread& t) { t.join(); });
// PowerHalConnector was called at least once by the first thread.
- // Reset and reconnect calls were made at most 10 times, once after each failure.
+ // Reset and reconnect calls were made at most 10 times, once after each
+ // failure.
powerHalConnectCount = mHalConnector->getConnectCount();
EXPECT_THAT(powerHalConnectCount, AllOf(Ge(1), Le(11)));
int powerHalResetCount = mHalConnector->getResetCount();
diff --git a/services/powermanager/tests/PowerHalLoaderTest.cpp b/services/powermanager/tests/PowerHalLoaderTest.cpp
index 2310a72..058e1b5 100644
--- a/services/powermanager/tests/PowerHalLoaderTest.cpp
+++ b/services/powermanager/tests/PowerHalLoaderTest.cpp
@@ -19,17 +19,18 @@
#include <android-base/logging.h>
#include <android/hardware/power/1.1/IPower.h>
#include <android/hardware/power/IPower.h>
+#include <gtest/gtest.h>
+#include <powermanager/PowerHalLoader.h>
#include <future>
-#include <gtest/gtest.h>
-
-#include <powermanager/PowerHalLoader.h>
using IPowerV1_0 = android::hardware::power::V1_0::IPower;
using IPowerV1_1 = android::hardware::power::V1_1::IPower;
using IPowerAidl = android::hardware::power::IPower;
using namespace android;
+using namespace android::power;
+using namespace testing;
// -------------------------------------------------------------------------------------------------
@@ -54,14 +55,10 @@
// -------------------------------------------------------------------------------------------------
template <typename T>
-class PowerHalLoaderTest : public testing::Test {
+class PowerHalLoaderTest : public Test {
public:
- sp<T> load() {
- return ::loadHal<T>();
- }
- void unload() {
- PowerHalLoader::unloadAll();
- }
+ sp<T> load() { return ::loadHal<T>(); }
+ void unload() { PowerHalLoader::unloadAll(); }
};
// -------------------------------------------------------------------------------------------------
@@ -95,7 +92,7 @@
std::vector<std::future<sp<TypeParam>>> futures;
for (int i = 0; i < 10; i++) {
futures.push_back(
- std::async(std::launch::async, &PowerHalLoaderTest<TypeParam>::load, this));
+ std::async(std::launch::async, &PowerHalLoaderTest<TypeParam>::load, this));
}
futures[0].wait();
diff --git a/services/powermanager/tests/PowerHalWrapperAidlTest.cpp b/services/powermanager/tests/PowerHalWrapperAidlTest.cpp
index 73b7466..a765659 100644
--- a/services/powermanager/tests/PowerHalWrapperAidlTest.cpp
+++ b/services/powermanager/tests/PowerHalWrapperAidlTest.cpp
@@ -19,14 +19,12 @@
#include <android/hardware/power/Boost.h>
#include <android/hardware/power/Mode.h>
#include <binder/IServiceManager.h>
-
#include <gmock/gmock.h>
#include <gtest/gtest.h>
-
#include <powermanager/PowerHalWrapper.h>
+#include <utils/Log.h>
#include <thread>
-#include <utils/Log.h>
using android::binder::Status;
using android::hardware::power::Boost;
@@ -34,6 +32,7 @@
using android::hardware::power::Mode;
using namespace android;
+using namespace android::power;
using namespace std::chrono_literals;
using namespace testing;
@@ -57,7 +56,7 @@
void SetUp() override;
protected:
- std::unique_ptr<PowerHalWrapper> mWrapper = nullptr;
+ std::unique_ptr<HalWrapper> mWrapper = nullptr;
sp<StrictMock<MockIPower>> mMockHal = nullptr;
};
@@ -65,7 +64,7 @@
void PowerHalWrapperAidlTest::SetUp() {
mMockHal = new StrictMock<MockIPower>();
- mWrapper = std::make_unique<AidlPowerHalWrapper>(mMockHal);
+ mWrapper = std::make_unique<AidlHalWrapper>(mMockHal);
ASSERT_NE(mWrapper, nullptr);
}
@@ -75,62 +74,61 @@
{
InSequence seq;
EXPECT_CALL(*mMockHal.get(), isBoostSupported(Eq(Boost::DISPLAY_UPDATE_IMMINENT), _))
- .Times(Exactly(1))
- .WillRepeatedly(DoAll(SetArgPointee<1>(true), Return(Status())));
+ .Times(Exactly(1))
+ .WillRepeatedly(DoAll(SetArgPointee<1>(true), Return(Status())));
EXPECT_CALL(*mMockHal.get(), setBoost(Eq(Boost::DISPLAY_UPDATE_IMMINENT), Eq(100)))
- .Times(Exactly(1));
+ .Times(Exactly(1));
}
auto result = mWrapper->setBoost(Boost::DISPLAY_UPDATE_IMMINENT, 100);
- ASSERT_EQ(PowerHalResult::SUCCESSFUL, result);
+ ASSERT_EQ(HalResult::SUCCESSFUL, result);
}
TEST_F(PowerHalWrapperAidlTest, TestSetBoostFailed) {
{
InSequence seq;
EXPECT_CALL(*mMockHal.get(), isBoostSupported(Eq(Boost::INTERACTION), _))
- .Times(Exactly(1))
- .WillRepeatedly(DoAll(SetArgPointee<1>(true), Return(Status())));
+ .Times(Exactly(1))
+ .WillRepeatedly(DoAll(SetArgPointee<1>(true), Return(Status())));
EXPECT_CALL(*mMockHal.get(), setBoost(Eq(Boost::INTERACTION), Eq(100)))
- .Times(Exactly(1))
- .WillRepeatedly(Return(Status::fromExceptionCode(-1)));
+ .Times(Exactly(1))
+ .WillRepeatedly(Return(Status::fromExceptionCode(-1)));
EXPECT_CALL(*mMockHal.get(), isBoostSupported(Eq(Boost::DISPLAY_UPDATE_IMMINENT), _))
- .Times(Exactly(1))
- .WillRepeatedly(Return(Status::fromExceptionCode(-1)));
+ .Times(Exactly(1))
+ .WillRepeatedly(Return(Status::fromExceptionCode(-1)));
}
auto result = mWrapper->setBoost(Boost::INTERACTION, 100);
- ASSERT_EQ(PowerHalResult::FAILED, result);
+ ASSERT_EQ(HalResult::FAILED, result);
result = mWrapper->setBoost(Boost::DISPLAY_UPDATE_IMMINENT, 1000);
- ASSERT_EQ(PowerHalResult::FAILED, result);
+ ASSERT_EQ(HalResult::FAILED, result);
}
TEST_F(PowerHalWrapperAidlTest, TestSetBoostUnsupported) {
EXPECT_CALL(*mMockHal.get(), isBoostSupported(Eq(Boost::INTERACTION), _))
- .Times(Exactly(1))
- .WillRepeatedly(DoAll(SetArgPointee<1>(false), Return(Status())));
+ .Times(Exactly(1))
+ .WillRepeatedly(DoAll(SetArgPointee<1>(false), Return(Status())));
auto result = mWrapper->setBoost(Boost::INTERACTION, 1000);
- ASSERT_EQ(PowerHalResult::UNSUPPORTED, result);
+ ASSERT_EQ(HalResult::UNSUPPORTED, result);
result = mWrapper->setBoost(Boost::CAMERA_SHOT, 10);
- ASSERT_EQ(PowerHalResult::UNSUPPORTED, result);
+ ASSERT_EQ(HalResult::UNSUPPORTED, result);
}
TEST_F(PowerHalWrapperAidlTest, TestSetBoostMultiThreadCheckSupportedOnlyOnce) {
{
InSequence seq;
EXPECT_CALL(*mMockHal.get(), isBoostSupported(Eq(Boost::INTERACTION), _))
- .Times(Exactly(1))
- .WillRepeatedly(DoAll(SetArgPointee<1>(true), Return(Status())));
- EXPECT_CALL(*mMockHal.get(), setBoost(Eq(Boost::INTERACTION), Eq(100)))
- .Times(Exactly(10));
+ .Times(Exactly(1))
+ .WillRepeatedly(DoAll(SetArgPointee<1>(true), Return(Status())));
+ EXPECT_CALL(*mMockHal.get(), setBoost(Eq(Boost::INTERACTION), Eq(100))).Times(Exactly(10));
}
std::vector<std::thread> threads;
for (int i = 0; i < 10; i++) {
threads.push_back(std::thread([&]() {
auto result = mWrapper->setBoost(Boost::INTERACTION, 100);
- ASSERT_EQ(PowerHalResult::SUCCESSFUL, result);
+ ASSERT_EQ(HalResult::SUCCESSFUL, result);
}));
}
std::for_each(threads.begin(), threads.end(), [](std::thread& t) { t.join(); });
@@ -140,62 +138,61 @@
{
InSequence seq;
EXPECT_CALL(*mMockHal.get(), isModeSupported(Eq(Mode::DISPLAY_INACTIVE), _))
- .Times(Exactly(1))
- .WillRepeatedly(DoAll(SetArgPointee<1>(true), Return(Status())));
+ .Times(Exactly(1))
+ .WillRepeatedly(DoAll(SetArgPointee<1>(true), Return(Status())));
EXPECT_CALL(*mMockHal.get(), setMode(Eq(Mode::DISPLAY_INACTIVE), Eq(false)))
- .Times(Exactly(1));
+ .Times(Exactly(1));
}
auto result = mWrapper->setMode(Mode::DISPLAY_INACTIVE, false);
- ASSERT_EQ(PowerHalResult::SUCCESSFUL, result);
+ ASSERT_EQ(HalResult::SUCCESSFUL, result);
}
TEST_F(PowerHalWrapperAidlTest, TestSetModeFailed) {
{
InSequence seq;
EXPECT_CALL(*mMockHal.get(), isModeSupported(Eq(Mode::LAUNCH), _))
- .Times(Exactly(1))
- .WillRepeatedly(DoAll(SetArgPointee<1>(true), Return(Status())));
+ .Times(Exactly(1))
+ .WillRepeatedly(DoAll(SetArgPointee<1>(true), Return(Status())));
EXPECT_CALL(*mMockHal.get(), setMode(Eq(Mode::LAUNCH), Eq(true)))
- .Times(Exactly(1))
- .WillRepeatedly(Return(Status::fromExceptionCode(-1)));
+ .Times(Exactly(1))
+ .WillRepeatedly(Return(Status::fromExceptionCode(-1)));
EXPECT_CALL(*mMockHal.get(), isModeSupported(Eq(Mode::DISPLAY_INACTIVE), _))
- .Times(Exactly(1))
- .WillRepeatedly(Return(Status::fromExceptionCode(-1)));
+ .Times(Exactly(1))
+ .WillRepeatedly(Return(Status::fromExceptionCode(-1)));
}
auto result = mWrapper->setMode(Mode::LAUNCH, true);
- ASSERT_EQ(PowerHalResult::FAILED, result);
+ ASSERT_EQ(HalResult::FAILED, result);
result = mWrapper->setMode(Mode::DISPLAY_INACTIVE, false);
- ASSERT_EQ(PowerHalResult::FAILED, result);
+ ASSERT_EQ(HalResult::FAILED, result);
}
TEST_F(PowerHalWrapperAidlTest, TestSetModeUnsupported) {
EXPECT_CALL(*mMockHal.get(), isModeSupported(Eq(Mode::LAUNCH), _))
- .Times(Exactly(1))
- .WillRepeatedly(DoAll(SetArgPointee<1>(false), Return(Status())));
+ .Times(Exactly(1))
+ .WillRepeatedly(DoAll(SetArgPointee<1>(false), Return(Status())));
auto result = mWrapper->setMode(Mode::LAUNCH, true);
- ASSERT_EQ(PowerHalResult::UNSUPPORTED, result);
+ ASSERT_EQ(HalResult::UNSUPPORTED, result);
result = mWrapper->setMode(Mode::CAMERA_STREAMING_HIGH, true);
- ASSERT_EQ(PowerHalResult::UNSUPPORTED, result);
+ ASSERT_EQ(HalResult::UNSUPPORTED, result);
}
TEST_F(PowerHalWrapperAidlTest, TestSetModeMultiThreadCheckSupportedOnlyOnce) {
{
InSequence seq;
EXPECT_CALL(*mMockHal.get(), isModeSupported(Eq(Mode::LAUNCH), _))
- .Times(Exactly(1))
- .WillRepeatedly(DoAll(SetArgPointee<1>(true), Return(Status())));
- EXPECT_CALL(*mMockHal.get(), setMode(Eq(Mode::LAUNCH), Eq(false)))
- .Times(Exactly(10));
+ .Times(Exactly(1))
+ .WillRepeatedly(DoAll(SetArgPointee<1>(true), Return(Status())));
+ EXPECT_CALL(*mMockHal.get(), setMode(Eq(Mode::LAUNCH), Eq(false))).Times(Exactly(10));
}
std::vector<std::thread> threads;
for (int i = 0; i < 10; i++) {
threads.push_back(std::thread([&]() {
auto result = mWrapper->setMode(Mode::LAUNCH, false);
- ASSERT_EQ(PowerHalResult::SUCCESSFUL, result);
+ ASSERT_EQ(HalResult::SUCCESSFUL, result);
}));
}
std::for_each(threads.begin(), threads.end(), [](std::thread& t) { t.join(); });
diff --git a/services/powermanager/tests/PowerHalWrapperHidlV1_0Test.cpp b/services/powermanager/tests/PowerHalWrapperHidlV1_0Test.cpp
index 5379054..6693d0b 100644
--- a/services/powermanager/tests/PowerHalWrapperHidlV1_0Test.cpp
+++ b/services/powermanager/tests/PowerHalWrapperHidlV1_0Test.cpp
@@ -20,12 +20,9 @@
#include <android/hardware/power/IPower.h>
#include <android/hardware/power/Mode.h>
#include <binder/IServiceManager.h>
-
#include <gmock/gmock.h>
#include <gtest/gtest.h>
-
#include <powermanager/PowerHalWrapper.h>
-
#include <utils/Log.h>
using android::hardware::power::Boost;
@@ -35,6 +32,7 @@
using android::hardware::power::V1_0::PowerHint;
using namespace android;
+using namespace android::power;
using namespace std::chrono_literals;
using namespace testing;
@@ -44,11 +42,9 @@
public:
MOCK_METHOD(hardware::Return<void>, setInteractive, (bool interactive), (override));
MOCK_METHOD(hardware::Return<void>, powerHint, (PowerHint hint, int32_t data), (override));
- MOCK_METHOD(
- hardware::Return<void>, setFeature, (Feature feature, bool activate), (override));
- MOCK_METHOD(
- hardware::Return<void>, getPlatformLowPowerStats,
- (getPlatformLowPowerStats_cb _hidl_cb), (override));
+ MOCK_METHOD(hardware::Return<void>, setFeature, (Feature feature, bool activate), (override));
+ MOCK_METHOD(hardware::Return<void>, getPlatformLowPowerStats,
+ (getPlatformLowPowerStats_cb _hidl_cb), (override));
};
// -------------------------------------------------------------------------------------------------
@@ -58,7 +54,7 @@
void SetUp() override;
protected:
- std::unique_ptr<PowerHalWrapper> mWrapper = nullptr;
+ std::unique_ptr<HalWrapper> mWrapper = nullptr;
sp<StrictMock<MockIPowerV1_0>> mMockHal = nullptr;
};
@@ -66,80 +62,75 @@
void PowerHalWrapperHidlV1_0Test::SetUp() {
mMockHal = new StrictMock<MockIPowerV1_0>();
- mWrapper = std::make_unique<HidlPowerHalWrapperV1_0>(mMockHal);
+ mWrapper = std::make_unique<HidlHalWrapperV1_0>(mMockHal);
ASSERT_NE(mWrapper, nullptr);
}
// -------------------------------------------------------------------------------------------------
TEST_F(PowerHalWrapperHidlV1_0Test, TestSetBoostSuccessful) {
- EXPECT_CALL(*mMockHal.get(), powerHint(Eq(PowerHint::INTERACTION), Eq(1000)))
- .Times(Exactly(1));
+ EXPECT_CALL(*mMockHal.get(), powerHint(Eq(PowerHint::INTERACTION), Eq(1000))).Times(Exactly(1));
auto result = mWrapper->setBoost(Boost::INTERACTION, 1000);
- ASSERT_EQ(PowerHalResult::SUCCESSFUL, result);
+ ASSERT_EQ(HalResult::SUCCESSFUL, result);
}
TEST_F(PowerHalWrapperHidlV1_0Test, TestSetBoostFailed) {
EXPECT_CALL(*mMockHal.get(), powerHint(Eq(PowerHint::INTERACTION), Eq(1000)))
- .Times(Exactly(1))
- .WillRepeatedly([](PowerHint, int32_t) {
- return hardware::Return<void>(hardware::Status::fromExceptionCode(-1));
- });
+ .Times(Exactly(1))
+ .WillRepeatedly([](PowerHint, int32_t) {
+ return hardware::Return<void>(hardware::Status::fromExceptionCode(-1));
+ });
auto result = mWrapper->setBoost(Boost::INTERACTION, 1000);
- ASSERT_EQ(PowerHalResult::FAILED, result);
+ ASSERT_EQ(HalResult::FAILED, result);
}
TEST_F(PowerHalWrapperHidlV1_0Test, TestSetBoostUnsupported) {
auto result = mWrapper->setBoost(Boost::CAMERA_LAUNCH, 10);
- ASSERT_EQ(PowerHalResult::UNSUPPORTED, result);
+ ASSERT_EQ(HalResult::UNSUPPORTED, result);
}
TEST_F(PowerHalWrapperHidlV1_0Test, TestSetModeSuccessful) {
{
InSequence seq;
- EXPECT_CALL(*mMockHal.get(), powerHint(Eq(PowerHint::LAUNCH), Eq(1)))
- .Times(Exactly(1));
- EXPECT_CALL(*mMockHal.get(), powerHint(Eq(PowerHint::LOW_POWER), Eq(0)))
- .Times(Exactly(1));
+ EXPECT_CALL(*mMockHal.get(), powerHint(Eq(PowerHint::LAUNCH), Eq(1))).Times(Exactly(1));
+ EXPECT_CALL(*mMockHal.get(), powerHint(Eq(PowerHint::LOW_POWER), Eq(0))).Times(Exactly(1));
EXPECT_CALL(*mMockHal.get(), powerHint(Eq(PowerHint::SUSTAINED_PERFORMANCE), Eq(1)))
- .Times(Exactly(1));
- EXPECT_CALL(*mMockHal.get(), powerHint(Eq(PowerHint::VR_MODE), Eq(0)))
- .Times(Exactly(1));
- EXPECT_CALL(*mMockHal.get(), setInteractive(Eq(true)))
- .Times(Exactly(1));
+ .Times(Exactly(1));
+ EXPECT_CALL(*mMockHal.get(), powerHint(Eq(PowerHint::VR_MODE), Eq(0))).Times(Exactly(1));
+ EXPECT_CALL(*mMockHal.get(), setInteractive(Eq(true))).Times(Exactly(1));
EXPECT_CALL(*mMockHal.get(),
setFeature(Eq(Feature::POWER_FEATURE_DOUBLE_TAP_TO_WAKE), Eq(false)))
- .Times(Exactly(1));
+ .Times(Exactly(1));
}
auto result = mWrapper->setMode(Mode::LAUNCH, true);
- ASSERT_EQ(PowerHalResult::SUCCESSFUL, result);
+ ASSERT_EQ(HalResult::SUCCESSFUL, result);
result = mWrapper->setMode(Mode::LOW_POWER, false);
- ASSERT_EQ(PowerHalResult::SUCCESSFUL, result);
+ ASSERT_EQ(HalResult::SUCCESSFUL, result);
result = mWrapper->setMode(Mode::SUSTAINED_PERFORMANCE, true);
- ASSERT_EQ(PowerHalResult::SUCCESSFUL, result);
+ ASSERT_EQ(HalResult::SUCCESSFUL, result);
result = mWrapper->setMode(Mode::VR, false);
- ASSERT_EQ(PowerHalResult::SUCCESSFUL, result);
+ ASSERT_EQ(HalResult::SUCCESSFUL, result);
result = mWrapper->setMode(Mode::INTERACTIVE, true);
- ASSERT_EQ(PowerHalResult::SUCCESSFUL, result);
+ ASSERT_EQ(HalResult::SUCCESSFUL, result);
result = mWrapper->setMode(Mode::DOUBLE_TAP_TO_WAKE, false);
- ASSERT_EQ(PowerHalResult::SUCCESSFUL, result);
+ ASSERT_EQ(HalResult::SUCCESSFUL, result);
}
TEST_F(PowerHalWrapperHidlV1_0Test, TestSetModeFailed) {
EXPECT_CALL(*mMockHal.get(), powerHint(Eq(PowerHint::LAUNCH), Eq(1)))
- .Times(Exactly(1))
- .WillRepeatedly([](PowerHint, int32_t) {
- return hardware::Return<void>(hardware::Status::fromExceptionCode(-1));
- });
+ .Times(Exactly(1))
+ .WillRepeatedly([](PowerHint, int32_t) {
+ return hardware::Return<void>(hardware::Status::fromExceptionCode(-1));
+ });
auto result = mWrapper->setMode(Mode::LAUNCH, 1);
- ASSERT_EQ(PowerHalResult::FAILED, result);
+ ASSERT_EQ(HalResult::FAILED, result);
}
TEST_F(PowerHalWrapperHidlV1_0Test, TestSetModeIgnored) {
auto result = mWrapper->setMode(Mode::CAMERA_STREAMING_HIGH, true);
- ASSERT_EQ(PowerHalResult::UNSUPPORTED, result);
+ ASSERT_EQ(HalResult::UNSUPPORTED, result);
}
diff --git a/services/powermanager/tests/PowerHalWrapperHidlV1_1Test.cpp b/services/powermanager/tests/PowerHalWrapperHidlV1_1Test.cpp
index 931c0d5..55bbd6d 100644
--- a/services/powermanager/tests/PowerHalWrapperHidlV1_1Test.cpp
+++ b/services/powermanager/tests/PowerHalWrapperHidlV1_1Test.cpp
@@ -21,12 +21,9 @@
#include <android/hardware/power/IPower.h>
#include <android/hardware/power/Mode.h>
#include <binder/IServiceManager.h>
-
#include <gmock/gmock.h>
#include <gtest/gtest.h>
-
#include <powermanager/PowerHalWrapper.h>
-
#include <utils/Log.h>
using android::hardware::power::Boost;
@@ -37,6 +34,7 @@
using IPowerV1_0 = android::hardware::power::V1_0::IPower;
using namespace android;
+using namespace android::power;
using namespace std::chrono_literals;
using namespace testing;
@@ -46,27 +44,21 @@
public:
MOCK_METHOD(hardware::Return<void>, setInteractive, (bool interactive), (override));
MOCK_METHOD(hardware::Return<void>, powerHint, (PowerHint hint, int32_t data), (override));
- MOCK_METHOD(
- hardware::Return<void>, setFeature, (Feature feature, bool activate), (override));
- MOCK_METHOD(
- hardware::Return<void>, getPlatformLowPowerStats,
- (getPlatformLowPowerStats_cb _hidl_cb), (override));
+ MOCK_METHOD(hardware::Return<void>, setFeature, (Feature feature, bool activate), (override));
+ MOCK_METHOD(hardware::Return<void>, getPlatformLowPowerStats,
+ (getPlatformLowPowerStats_cb _hidl_cb), (override));
};
class MockIPowerV1_1 : public IPowerV1_1 {
public:
MOCK_METHOD(hardware::Return<void>, setInteractive, (bool interactive), (override));
MOCK_METHOD(hardware::Return<void>, powerHint, (PowerHint hint, int32_t data), (override));
- MOCK_METHOD(
- hardware::Return<void>, setFeature, (Feature feature, bool activate), (override));
- MOCK_METHOD(
- hardware::Return<void>, getPlatformLowPowerStats,
- (getPlatformLowPowerStats_cb _hidl_cb), (override));
- MOCK_METHOD(
- hardware::Return<void>, powerHintAsync, (PowerHint hint, int32_t data), (override));
- MOCK_METHOD(
- hardware::Return<void>, getSubsystemLowPowerStats,
- (getSubsystemLowPowerStats_cb _hidl_cb), (override));
+ MOCK_METHOD(hardware::Return<void>, setFeature, (Feature feature, bool activate), (override));
+ MOCK_METHOD(hardware::Return<void>, getPlatformLowPowerStats,
+ (getPlatformLowPowerStats_cb _hidl_cb), (override));
+ MOCK_METHOD(hardware::Return<void>, powerHintAsync, (PowerHint hint, int32_t data), (override));
+ MOCK_METHOD(hardware::Return<void>, getSubsystemLowPowerStats,
+ (getSubsystemLowPowerStats_cb _hidl_cb), (override));
};
// -------------------------------------------------------------------------------------------------
@@ -76,7 +68,7 @@
void SetUp() override;
protected:
- std::unique_ptr<PowerHalWrapper> mWrapper = nullptr;
+ std::unique_ptr<HalWrapper> mWrapper = nullptr;
sp<StrictMock<MockIPowerV1_0>> mMockHalV1_0 = nullptr;
sp<StrictMock<MockIPowerV1_1>> mMockHalV1_1 = nullptr;
};
@@ -86,7 +78,7 @@
void PowerHalWrapperHidlV1_1Test::SetUp() {
mMockHalV1_0 = new StrictMock<MockIPowerV1_0>();
mMockHalV1_1 = new StrictMock<MockIPowerV1_1>();
- mWrapper = std::make_unique<HidlPowerHalWrapperV1_1>(mMockHalV1_0, mMockHalV1_1);
+ mWrapper = std::make_unique<HidlHalWrapperV1_1>(mMockHalV1_0, mMockHalV1_1);
ASSERT_NE(mWrapper, nullptr);
}
@@ -94,72 +86,72 @@
TEST_F(PowerHalWrapperHidlV1_1Test, TestSetBoostSuccessful) {
EXPECT_CALL(*mMockHalV1_1.get(), powerHintAsync(Eq(PowerHint::INTERACTION), Eq(1000)))
- .Times(Exactly(1));
+ .Times(Exactly(1));
auto result = mWrapper->setBoost(Boost::INTERACTION, 1000);
- ASSERT_EQ(PowerHalResult::SUCCESSFUL, result);
+ ASSERT_EQ(HalResult::SUCCESSFUL, result);
}
TEST_F(PowerHalWrapperHidlV1_1Test, TestSetBoostFailed) {
EXPECT_CALL(*mMockHalV1_1.get(), powerHintAsync(Eq(PowerHint::INTERACTION), Eq(1000)))
- .Times(Exactly(1))
- .WillRepeatedly([](PowerHint, int32_t) {
- return hardware::Return<void>(hardware::Status::fromExceptionCode(-1));
- });
+ .Times(Exactly(1))
+ .WillRepeatedly([](PowerHint, int32_t) {
+ return hardware::Return<void>(hardware::Status::fromExceptionCode(-1));
+ });
auto result = mWrapper->setBoost(Boost::INTERACTION, 1000);
- ASSERT_EQ(PowerHalResult::FAILED, result);
+ ASSERT_EQ(HalResult::FAILED, result);
}
TEST_F(PowerHalWrapperHidlV1_1Test, TestSetBoostUnsupported) {
auto result = mWrapper->setBoost(Boost::CAMERA_LAUNCH, 10);
- ASSERT_EQ(PowerHalResult::UNSUPPORTED, result);
+ ASSERT_EQ(HalResult::UNSUPPORTED, result);
}
TEST_F(PowerHalWrapperHidlV1_1Test, TestSetMode) {
{
InSequence seq;
EXPECT_CALL(*mMockHalV1_1.get(), powerHintAsync(Eq(PowerHint::LAUNCH), Eq(1)))
- .Times(Exactly(1));
+ .Times(Exactly(1));
EXPECT_CALL(*mMockHalV1_1.get(), powerHintAsync(Eq(PowerHint::LOW_POWER), Eq(0)))
- .Times(Exactly(1));
- EXPECT_CALL(*mMockHalV1_1.get(), powerHintAsync(Eq(PowerHint::SUSTAINED_PERFORMANCE), Eq(1)))
- .Times(Exactly(1));
+ .Times(Exactly(1));
+ EXPECT_CALL(*mMockHalV1_1.get(),
+ powerHintAsync(Eq(PowerHint::SUSTAINED_PERFORMANCE), Eq(1)))
+ .Times(Exactly(1));
EXPECT_CALL(*mMockHalV1_1.get(), powerHintAsync(Eq(PowerHint::VR_MODE), Eq(0)))
- .Times(Exactly(1));
- EXPECT_CALL(*mMockHalV1_0.get(), setInteractive(Eq(true)))
- .Times(Exactly(1));
+ .Times(Exactly(1));
+ EXPECT_CALL(*mMockHalV1_0.get(), setInteractive(Eq(true))).Times(Exactly(1));
EXPECT_CALL(*mMockHalV1_0.get(),
setFeature(Eq(Feature::POWER_FEATURE_DOUBLE_TAP_TO_WAKE), Eq(false)))
- .Times(Exactly(1));
+ .Times(Exactly(1));
}
auto result = mWrapper->setMode(Mode::LAUNCH, true);
- ASSERT_EQ(PowerHalResult::SUCCESSFUL, result);
+ ASSERT_EQ(HalResult::SUCCESSFUL, result);
result = mWrapper->setMode(Mode::LOW_POWER, false);
- ASSERT_EQ(PowerHalResult::SUCCESSFUL, result);
+ ASSERT_EQ(HalResult::SUCCESSFUL, result);
result = mWrapper->setMode(Mode::SUSTAINED_PERFORMANCE, true);
- ASSERT_EQ(PowerHalResult::SUCCESSFUL, result);
+ ASSERT_EQ(HalResult::SUCCESSFUL, result);
result = mWrapper->setMode(Mode::VR, false);
- ASSERT_EQ(PowerHalResult::SUCCESSFUL, result);
+ ASSERT_EQ(HalResult::SUCCESSFUL, result);
result = mWrapper->setMode(Mode::INTERACTIVE, true);
- ASSERT_EQ(PowerHalResult::SUCCESSFUL, result);
+ ASSERT_EQ(HalResult::SUCCESSFUL, result);
result = mWrapper->setMode(Mode::DOUBLE_TAP_TO_WAKE, false);
- ASSERT_EQ(PowerHalResult::SUCCESSFUL, result);
+ ASSERT_EQ(HalResult::SUCCESSFUL, result);
}
TEST_F(PowerHalWrapperHidlV1_1Test, TestSetModeFailed) {
EXPECT_CALL(*mMockHalV1_1.get(), powerHintAsync(Eq(PowerHint::LAUNCH), Eq(1)))
- .Times(Exactly(1))
- .WillRepeatedly([](PowerHint, int32_t) {
- return hardware::Return<void>(hardware::Status::fromExceptionCode(-1));
- });
+ .Times(Exactly(1))
+ .WillRepeatedly([](PowerHint, int32_t) {
+ return hardware::Return<void>(hardware::Status::fromExceptionCode(-1));
+ });
auto result = mWrapper->setMode(Mode::LAUNCH, 1);
- ASSERT_EQ(PowerHalResult::FAILED, result);
+ ASSERT_EQ(HalResult::FAILED, result);
}
TEST_F(PowerHalWrapperHidlV1_1Test, TestSetModeIgnored) {
auto result = mWrapper->setMode(Mode::CAMERA_STREAMING_HIGH, true);
- ASSERT_EQ(PowerHalResult::UNSUPPORTED, result);
+ ASSERT_EQ(HalResult::UNSUPPORTED, result);
}
diff --git a/services/sensorservice/SensorEventConnection.cpp b/services/sensorservice/SensorEventConnection.cpp
index ccf05d9..9b30dce 100644
--- a/services/sensorservice/SensorEventConnection.cpp
+++ b/services/sensorservice/SensorEventConnection.cpp
@@ -37,6 +37,7 @@
mCacheSize(0), mMaxCacheSize(0), mTimeOfLastEventDrop(0), mEventsDropped(0),
mPackageName(packageName), mOpPackageName(opPackageName), mDestroyed(false) {
mChannel = new BitTube(mService->mSocketBufferSize);
+ mTargetSdk = SensorService::getTargetSdkVersion(opPackageName);
#if DEBUG_CONNECTIONS
mEventsReceived = mEventsSentFromCache = mEventsSent = 0;
mTotalAcksNeeded = mTotalAcksReceived = 0;
@@ -439,8 +440,17 @@
bool success = true;
const auto iter = mHandleToAppOp.find(event.sensor);
if (iter != mHandleToAppOp.end()) {
- int32_t appOpMode = mService->sAppOpsManager.noteOp((*iter).second, mUid, mOpPackageName);
- success = (appOpMode == AppOpsManager::MODE_ALLOWED);
+ // Special handling for step count/detect backwards compatibility: if the app's target SDK
+ // is pre-Q, still permit delivering events to the app even if permission isn't granted
+ // (since this permission was only introduced in Q)
+ if ((event.type == SENSOR_TYPE_STEP_COUNTER || event.type == SENSOR_TYPE_STEP_DETECTOR) &&
+ mTargetSdk > 0 && mTargetSdk <= __ANDROID_API_P__) {
+ success = true;
+ } else {
+ int32_t appOpMode = mService->sAppOpsManager.noteOp(iter->second, mUid,
+ mOpPackageName);
+ success = (appOpMode == AppOpsManager::MODE_ALLOWED);
+ }
}
return success;
}
diff --git a/services/sensorservice/SensorEventConnection.h b/services/sensorservice/SensorEventConnection.h
index 13cee6f..8d5fcf7 100644
--- a/services/sensorservice/SensorEventConnection.h
+++ b/services/sensorservice/SensorEventConnection.h
@@ -175,6 +175,7 @@
int mEventsDropped;
String8 mPackageName;
const String16 mOpPackageName;
+ int mTargetSdk;
#if DEBUG_CONNECTIONS
int mEventsReceived, mEventsSent, mEventsSentFromCache;
int mTotalAcksNeeded, mTotalAcksReceived;
diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
index 2b4fd7f..3f88f77 100644
--- a/services/sensorservice/SensorService.cpp
+++ b/services/sensorservice/SensorService.cpp
@@ -1805,36 +1805,28 @@
const int32_t appOpMode = sAppOpsManager.checkOp(opCode,
IPCThreadState::self()->getCallingUid(), opPackageName);
bool appOpAllowed = appOpMode == AppOpsManager::MODE_ALLOWED;
+ int targetSdkVersion = getTargetSdkVersion(opPackageName);
bool canAccess = false;
- if (hasPermissionForSensor(sensor)) {
+ if (targetSdkVersion > 0 && targetSdkVersion <= __ANDROID_API_P__ &&
+ (sensor.getType() == SENSOR_TYPE_STEP_COUNTER ||
+ sensor.getType() == SENSOR_TYPE_STEP_DETECTOR)) {
+ // Allow access to step sensors if the application targets pre-Q, which is before the
+ // requirement to hold the AR permission to access Step Counter and Step Detector events
+ // was introduced.
+ canAccess = true;
+ } else if (hasPermissionForSensor(sensor)) {
// Ensure that the AppOp is allowed, or that there is no necessary app op for the sensor
if (opCode < 0 || appOpAllowed) {
canAccess = true;
}
- } else if (sensor.getType() == SENSOR_TYPE_STEP_COUNTER ||
- sensor.getType() == SENSOR_TYPE_STEP_DETECTOR) {
- int targetSdkVersion = getTargetSdkVersion(opPackageName);
- // Allow access to the sensor if the application targets pre-Q, which is before the
- // requirement to hold the AR permission to access Step Counter and Step Detector events
- // was introduced, and the user hasn't revoked the app op.
- //
- // Verifying the app op is required to ensure that the user hasn't revoked the necessary
- // permissions to access the Step Detector and Step Counter when the application targets
- // pre-Q. Without this check, if the user revokes the pre-Q install-time GMS Core AR
- // permission, the app would still be able to receive Step Counter and Step Detector events.
- if (appOpAllowed &&
- targetSdkVersion > 0 &&
- targetSdkVersion <= __ANDROID_API_P__) {
- canAccess = true;
- }
}
if (canAccess) {
sAppOpsManager.noteOp(opCode, IPCThreadState::self()->getCallingUid(), opPackageName);
} else {
- ALOGE("%s a sensor (%s) without holding its required permission: %s",
- operation, sensor.getName().string(), sensor.getRequiredPermission().string());
+ ALOGE("%s %s a sensor (%s) without holding %s", String8(opPackageName).string(),
+ operation, sensor.getName().string(), sensor.getRequiredPermission().string());
}
return canAccess;
diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h
index 0e69f60..26bfb49 100644
--- a/services/surfaceflinger/BufferLayer.h
+++ b/services/surfaceflinger/BufferLayer.h
@@ -148,10 +148,10 @@
virtual status_t updateActiveBuffer() = 0;
virtual status_t updateFrameNumber(nsecs_t latchTime) = 0;
- // We generate InputWindowHandles for all buffered layers regardless of whether they
+ // We generate InputWindowHandles for all non-cursor buffered layers regardless of whether they
// have an InputChannel. This is to enable the InputDispatcher to do PID based occlusion
// detection.
- bool needsInputInfo() const override { return true; }
+ bool needsInputInfo() const override { return !mPotentialCursor; }
protected:
struct BufferInfo {
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index 4dabd2b..81b3ccf 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -59,12 +59,14 @@
class DisplaySurface;
} // namespace compositionengine
-class DisplayDevice : public LightRefBase<DisplayDevice> {
+class DisplayDevice : public RefBase {
public:
constexpr static float sDefaultMinLumiance = 0.0;
constexpr static float sDefaultMaxLumiance = 500.0;
explicit DisplayDevice(DisplayDeviceCreationArgs& args);
+
+ // Must be destroyed on the main thread because it may call into HWComposer.
virtual ~DisplayDevice();
std::shared_ptr<compositionengine::Display> getCompositionDisplay() const {
@@ -246,21 +248,18 @@
class DisplayRenderArea : public RenderArea {
public:
- DisplayRenderArea(const sp<const DisplayDevice>& display,
- RotationFlags rotation = ui::Transform::ROT_0)
- : DisplayRenderArea(display, display->getBounds(),
- static_cast<uint32_t>(display->getWidth()),
- static_cast<uint32_t>(display->getHeight()),
- display->getCompositionDataSpace(), rotation) {}
-
- DisplayRenderArea(sp<const DisplayDevice> display, const Rect& sourceCrop, uint32_t reqWidth,
- uint32_t reqHeight, ui::Dataspace reqDataSpace, RotationFlags rotation,
- bool allowSecureLayers = true)
- : RenderArea(reqWidth, reqHeight, CaptureFill::OPAQUE, reqDataSpace,
- display->getViewport(), applyDeviceOrientation(rotation, display)),
- mDisplay(std::move(display)),
- mSourceCrop(sourceCrop),
- mAllowSecureLayers(allowSecureLayers) {}
+ static std::unique_ptr<RenderArea> create(wp<const DisplayDevice> displayWeak,
+ const Rect& sourceCrop, ui::Size reqSize,
+ ui::Dataspace reqDataSpace, RotationFlags rotation,
+ bool allowSecureLayers = true) {
+ if (auto display = displayWeak.promote()) {
+ // Using new to access a private constructor.
+ return std::unique_ptr<DisplayRenderArea>(
+ new DisplayRenderArea(std::move(display), sourceCrop, reqSize, reqDataSpace,
+ rotation, allowSecureLayers));
+ }
+ return nullptr;
+ }
const ui::Transform& getTransform() const override { return mTransform; }
Rect getBounds() const override { return mDisplay->getBounds(); }
@@ -307,6 +306,14 @@
}
private:
+ DisplayRenderArea(sp<const DisplayDevice> display, const Rect& sourceCrop, ui::Size reqSize,
+ ui::Dataspace reqDataSpace, RotationFlags rotation, bool allowSecureLayers)
+ : RenderArea(reqSize, CaptureFill::OPAQUE, reqDataSpace, display->getViewport(),
+ applyDeviceOrientation(rotation, display)),
+ mDisplay(std::move(display)),
+ mSourceCrop(sourceCrop),
+ mAllowSecureLayers(allowSecureLayers) {}
+
static RotationFlags applyDeviceOrientation(RotationFlags orientationFlag,
const sp<const DisplayDevice>& device) {
uint32_t inverseRotate90 = 0;
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index c355ebd..b800038 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -64,6 +64,8 @@
const uint32_t id;
};
+// See the comment for SurfaceFlinger::getHwComposer for the thread safety rules for accessing
+// this class.
class HWComposer {
public:
struct DeviceRequestedChanges {
diff --git a/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp b/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
index 1d8179c..4b4c050 100644
--- a/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
+++ b/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
@@ -85,6 +85,7 @@
const bool expectsExpensiveRendering = !mExpensiveDisplays.empty();
if (mNotifiedExpensiveRendering != expectsExpensiveRendering) {
+ std::lock_guard lock(mPowerHalMutex);
HalWrapper* const halWrapper = getPowerHal();
if (halWrapper == nullptr) {
return;
@@ -108,6 +109,7 @@
}
if (mSendUpdateImminent.load()) {
+ std::lock_guard lock(mPowerHalMutex);
HalWrapper* const halWrapper = getPowerHal();
if (halWrapper == nullptr) {
return;
diff --git a/services/surfaceflinger/DisplayHardware/PowerAdvisor.h b/services/surfaceflinger/DisplayHardware/PowerAdvisor.h
index 34e63e7..95eb0e2 100644
--- a/services/surfaceflinger/DisplayHardware/PowerAdvisor.h
+++ b/services/surfaceflinger/DisplayHardware/PowerAdvisor.h
@@ -19,6 +19,8 @@
#include <atomic>
#include <unordered_set>
+#include <utils/Mutex.h>
+
#include "../Scheduler/OneShotTimer.h"
#include "DisplayIdentification.h"
@@ -56,10 +58,11 @@
void notifyDisplayUpdateImminent() override;
private:
- HalWrapper* getPowerHal();
+ HalWrapper* getPowerHal() REQUIRES(mPowerHalMutex);
+ bool mReconnectPowerHal GUARDED_BY(mPowerHalMutex) = false;
+ std::mutex mPowerHalMutex;
std::atomic_bool mBootFinished = false;
- bool mReconnectPowerHal = false;
std::unordered_set<DisplayId> mExpensiveDisplays;
bool mNotifiedExpensiveRendering = false;
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 49112dd..f36b67d 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -866,13 +866,12 @@
}
// If we still have pending updates, we need to ensure SurfaceFlinger
- // will keep calling doTransaction, and so we set the transaction flags.
+ // will keep calling doTransaction, and so we force a traversal.
// However, our pending states won't clear until a frame is available,
- // and so there is no need to specifically trigger a wakeup. Rather
- // we set the flags and wait for something else to wake us up.
+ // and so there is no need to specifically trigger a wakeup.
if (!mPendingStates.empty()) {
setTransactionFlags(eTransactionNeeded);
- mFlinger->setTransactionFlagsNoWake(eTraversalNeeded);
+ mFlinger->setTraversalNeeded();
}
mCurrentState.modified = false;
@@ -2409,7 +2408,15 @@
// Position the touchable region relative to frame screen location and restrict it to frame
// bounds.
info.touchableRegion = info.touchableRegion.translate(info.frameLeft, info.frameTop);
- info.visible = canReceiveInput();
+ // For compatibility reasons we let layers which can receive input
+ // receive input before they have actually submitted a buffer. Because
+ // of this we use canReceiveInput instead of isVisible to check the
+ // policy-visibility, ignoring the buffer state. However for layers with
+ // hasInputInfo()==false we can use the real visibility state.
+ // We are just using these layers for occlusion detection in
+ // InputDispatcher, and obviously if they aren't visible they can't occlude
+ // anything.
+ info.visible = hasInputInfo() ? canReceiveInput() : isVisible();
auto cropLayer = mDrawingState.touchableRegionCrop.promote();
if (info.replaceTouchableRegionWithCrop) {
diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp
index 27353d8..398fd40 100644
--- a/services/surfaceflinger/RegionSamplingThread.cpp
+++ b/services/surfaceflinger/RegionSamplingThread.cpp
@@ -36,6 +36,7 @@
#include "DisplayDevice.h"
#include "Layer.h"
+#include "Promise.h"
#include "Scheduler/DispSync.h"
#include "SurfaceFlinger.h"
@@ -336,8 +337,20 @@
return;
}
- const auto device = mFlinger.getDefaultDisplayDevice();
- const auto orientation = ui::Transform::toRotationFlags(device->getOrientation());
+ wp<const DisplayDevice> displayWeak;
+
+ ui::LayerStack layerStack;
+ ui::Transform::RotationFlags orientation;
+ ui::Size displaySize;
+
+ {
+ // TODO(b/159112860): Don't keep sp<DisplayDevice> outside of SF main thread
+ const sp<const DisplayDevice> display = mFlinger.getDefaultDisplayDevice();
+ displayWeak = display;
+ layerStack = display->getLayerStack();
+ orientation = ui::Transform::toRotationFlags(display->getOrientation());
+ displaySize = display->getSize();
+ }
std::vector<RegionSamplingThread::Descriptor> descriptors;
Region sampleRegion;
@@ -346,20 +359,18 @@
descriptors.emplace_back(descriptor);
}
- const Rect sampledArea = sampleRegion.bounds();
-
auto dx = 0;
auto dy = 0;
switch (orientation) {
case ui::Transform::ROT_90:
- dx = device->getWidth();
+ dx = displaySize.getWidth();
break;
case ui::Transform::ROT_180:
- dx = device->getWidth();
- dy = device->getHeight();
+ dx = displaySize.getWidth();
+ dy = displaySize.getHeight();
break;
case ui::Transform::ROT_270:
- dy = device->getHeight();
+ dy = displaySize.getHeight();
break;
default:
break;
@@ -368,8 +379,13 @@
ui::Transform t(orientation);
auto screencapRegion = t.transform(sampleRegion);
screencapRegion = screencapRegion.translate(dx, dy);
- DisplayRenderArea renderArea(device, screencapRegion.bounds(), sampledArea.getWidth(),
- sampledArea.getHeight(), ui::Dataspace::V0_SRGB, orientation);
+
+ const Rect sampledBounds = sampleRegion.bounds();
+
+ SurfaceFlinger::RenderAreaFuture renderAreaFuture = promise::defer([=] {
+ return DisplayRenderArea::create(displayWeak, sampledBounds, sampledBounds.getSize(),
+ ui::Dataspace::V0_SRGB, orientation);
+ });
std::unordered_set<sp<IRegionSamplingListener>, SpHash<IRegionSamplingListener>> listeners;
@@ -393,9 +409,9 @@
constexpr bool roundOutwards = true;
Rect transformed = transform.transform(bounds, roundOutwards);
- // If this layer doesn't intersect with the larger sampledArea, skip capturing it
+ // If this layer doesn't intersect with the larger sampledBounds, skip capturing it
Rect ignore;
- if (!transformed.intersect(sampledArea, &ignore)) return;
+ if (!transformed.intersect(sampledBounds, &ignore)) return;
// If the layer doesn't intersect a sampling area, skip capturing it
bool intersectsAnyArea = false;
@@ -411,22 +427,22 @@
bounds.top, bounds.right, bounds.bottom);
visitor(layer);
};
- mFlinger.traverseLayersInDisplay(device, filterVisitor);
+ mFlinger.traverseLayersInLayerStack(layerStack, filterVisitor);
};
sp<GraphicBuffer> buffer = nullptr;
- if (mCachedBuffer && mCachedBuffer->getWidth() == sampledArea.getWidth() &&
- mCachedBuffer->getHeight() == sampledArea.getHeight()) {
+ if (mCachedBuffer && mCachedBuffer->getWidth() == sampledBounds.getWidth() &&
+ mCachedBuffer->getHeight() == sampledBounds.getHeight()) {
buffer = mCachedBuffer;
} else {
const uint32_t usage = GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_HW_RENDER;
- buffer = new GraphicBuffer(sampledArea.getWidth(), sampledArea.getHeight(),
+ buffer = new GraphicBuffer(sampledBounds.getWidth(), sampledBounds.getHeight(),
PIXEL_FORMAT_RGBA_8888, 1, usage, "RegionSamplingThread");
}
bool ignored;
- mFlinger.captureScreenCommon(renderArea, traverseLayers, buffer, false /* identityTransform */,
- true /* regionSampling */, ignored);
+ mFlinger.captureScreenCommon(std::move(renderAreaFuture), traverseLayers, buffer,
+ false /* identityTransform */, true /* regionSampling */, ignored);
std::vector<Descriptor> activeDescriptors;
for (const auto& descriptor : descriptors) {
@@ -437,7 +453,7 @@
ALOGV("Sampling %zu descriptors", activeDescriptors.size());
std::vector<float> lumas =
- sampleBuffer(buffer, sampledArea.leftTop(), activeDescriptors, orientation);
+ sampleBuffer(buffer, sampledBounds.leftTop(), activeDescriptors, orientation);
if (lumas.size() != activeDescriptors.size()) {
ALOGW("collected %zu median luma values for %zu descriptors", lumas.size(),
activeDescriptors.size());
diff --git a/services/surfaceflinger/RenderArea.h b/services/surfaceflinger/RenderArea.h
index 6b0455a..a6246d9 100644
--- a/services/surfaceflinger/RenderArea.h
+++ b/services/surfaceflinger/RenderArea.h
@@ -23,11 +23,9 @@
static float getCaptureFillValue(CaptureFill captureFill);
- RenderArea(uint32_t reqWidth, uint32_t reqHeight, CaptureFill captureFill,
- ui::Dataspace reqDataSpace, const Rect& displayViewport,
- RotationFlags rotation = ui::Transform::ROT_0)
- : mReqWidth(reqWidth),
- mReqHeight(reqHeight),
+ RenderArea(ui::Size reqSize, CaptureFill captureFill, ui::Dataspace reqDataSpace,
+ const Rect& displayViewport, RotationFlags rotation = ui::Transform::ROT_0)
+ : mReqSize(reqSize),
mReqDataSpace(reqDataSpace),
mCaptureFill(captureFill),
mRotationFlags(rotation),
@@ -70,8 +68,8 @@
RotationFlags getRotationFlags() const { return mRotationFlags; }
// Returns the size of the physical render area.
- int getReqWidth() const { return static_cast<int>(mReqWidth); }
- int getReqHeight() const { return static_cast<int>(mReqHeight); }
+ int getReqWidth() const { return mReqSize.width; }
+ int getReqHeight() const { return mReqSize.height; }
// Returns the composition data space of the render area.
ui::Dataspace getReqDataSpace() const { return mReqDataSpace; }
@@ -86,8 +84,7 @@
const Rect& getDisplayViewport() const { return mDisplayViewport; }
private:
- const uint32_t mReqWidth;
- const uint32_t mReqHeight;
+ const ui::Size mReqSize;
const ui::Dataspace mReqDataSpace;
const CaptureFill mCaptureFill;
const RotationFlags mRotationFlags;
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
index 6dbff14..a6036c6 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
@@ -595,4 +595,28 @@
return distance1 < distance2 ? *lowerBound : *std::prev(lowerBound);
}
+RefreshRateConfigs::KernelIdleTimerAction RefreshRateConfigs::getIdleTimerAction() const {
+ std::lock_guard lock(mLock);
+ const auto& deviceMin = getMinRefreshRate();
+ const auto& minByPolicy = getMinRefreshRateByPolicyLocked();
+ const auto& maxByPolicy = getMaxRefreshRateByPolicyLocked();
+
+ // Kernel idle timer will set the refresh rate to the device min. If DisplayManager says that
+ // the min allowed refresh rate is higher than the device min, we do not want to enable the
+ // timer.
+ if (deviceMin < minByPolicy) {
+ return RefreshRateConfigs::KernelIdleTimerAction::TurnOff;
+ }
+ if (minByPolicy == maxByPolicy) {
+ // Do not sent the call to toggle off kernel idle timer if the device min and policy min and
+ // max are all the same. This saves us extra unnecessary calls to sysprop.
+ if (deviceMin == minByPolicy) {
+ return RefreshRateConfigs::KernelIdleTimerAction::NoChange;
+ }
+ return RefreshRateConfigs::KernelIdleTimerAction::TurnOff;
+ }
+ // Turn on the timer in all other cases.
+ return RefreshRateConfigs::KernelIdleTimerAction::TurnOn;
+}
+
} // namespace android::scheduler
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
index 584a5e7..8a51b85 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
@@ -82,6 +82,8 @@
return configId != other.configId || hwcConfig != other.hwcConfig;
}
+ bool operator<(const RefreshRate& other) const { return getFps() < other.getFps(); }
+
bool operator==(const RefreshRate& other) const { return !(*this != other); }
private:
@@ -271,6 +273,17 @@
RefreshRateConfigs(const std::vector<std::shared_ptr<const HWC2::Display::Config>>& configs,
HwcConfigIndexType currentConfigId);
+ // Class to enumerate options around toggling the kernel timer on and off. We have an option
+ // for no change to avoid extra calls to kernel.
+ enum class KernelIdleTimerAction {
+ NoChange, // Do not change the idle timer.
+ TurnOff, // Turn off the idle timer.
+ TurnOn // Turn on the idle timer.
+ };
+ // Checks whether kernel idle timer should be active depending the policy decisions around
+ // refresh rates.
+ KernelIdleTimerAction getIdleTimerAction() const;
+
private:
friend class RefreshRateConfigsTest;
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index 9e24f909..730ea8f 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -55,13 +55,24 @@
virtual void kernelTimerChanged(bool expired) = 0;
};
-class Scheduler {
+class IPhaseOffsetControl {
+public:
+ virtual ~IPhaseOffsetControl() = default;
+ virtual void setPhaseOffset(scheduler::ConnectionHandle, nsecs_t phaseOffset) = 0;
+};
+
+class Scheduler : public IPhaseOffsetControl {
public:
using RefreshRate = scheduler::RefreshRateConfigs::RefreshRate;
using ConfigEvent = scheduler::RefreshRateConfigEvent;
// Indicates whether to start the transaction early, or at vsync time.
- enum class TransactionStart { EARLY, NORMAL };
+ enum class TransactionStart {
+ Early, // DEPRECATED. Start the transaction early. Times out on its own
+ EarlyStart, // Start the transaction early and keep this config until EarlyEnd
+ EarlyEnd, // End the early config started at EarlyStart
+ Normal // Start the transaction at the normal time
+ };
Scheduler(impl::EventControlThread::SetVSyncEnabledFunction,
const scheduler::RefreshRateConfigs&, ISchedulerCallback& schedulerCallback,
@@ -90,7 +101,7 @@
void onScreenReleased(ConnectionHandle);
// Modifies phase offset in the event thread.
- void setPhaseOffset(ConnectionHandle, nsecs_t phaseOffset);
+ void setPhaseOffset(ConnectionHandle, nsecs_t phaseOffset) override;
void getDisplayStatInfo(DisplayStatInfo* stats);
diff --git a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp
index abeacfe..a596bce 100644
--- a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp
+++ b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp
@@ -338,10 +338,14 @@
}
auto& callback = it->second;
- if (callback->wakeupTime()) {
+ auto const wakeupTime = callback->wakeupTime();
+ if (wakeupTime) {
callback->disarm();
- mIntendedWakeupTime = kInvalidTime;
- rearmTimer(mTimeKeeper->now());
+
+ if (*wakeupTime == mIntendedWakeupTime) {
+ mIntendedWakeupTime = kInvalidTime;
+ rearmTimer(mTimeKeeper->now());
+ }
return CancelResult::Cancelled;
}
return CancelResult::TooLate;
diff --git a/services/surfaceflinger/Scheduler/VSyncModulator.cpp b/services/surfaceflinger/Scheduler/VSyncModulator.cpp
index 510dc2d..2567c04 100644
--- a/services/surfaceflinger/Scheduler/VSyncModulator.cpp
+++ b/services/surfaceflinger/Scheduler/VSyncModulator.cpp
@@ -31,11 +31,11 @@
namespace android::scheduler {
-VSyncModulator::VSyncModulator(Scheduler& scheduler,
+VSyncModulator::VSyncModulator(IPhaseOffsetControl& phaseOffsetControl,
Scheduler::ConnectionHandle appConnectionHandle,
Scheduler::ConnectionHandle sfConnectionHandle,
const OffsetsConfig& config)
- : mScheduler(scheduler),
+ : mPhaseOffsetControl(phaseOffsetControl),
mAppConnectionHandle(appConnectionHandle),
mSfConnectionHandle(sfConnectionHandle),
mOffsetsConfig(config) {
@@ -51,14 +51,35 @@
}
void VSyncModulator::setTransactionStart(Scheduler::TransactionStart transactionStart) {
- if (transactionStart == Scheduler::TransactionStart::EARLY) {
+ switch (transactionStart) {
+ case Scheduler::TransactionStart::EarlyStart:
+ ALOGW_IF(mExplicitEarlyWakeup, "Already in TransactionStart::EarlyStart");
+ mExplicitEarlyWakeup = true;
+ break;
+ case Scheduler::TransactionStart::EarlyEnd:
+ ALOGW_IF(!mExplicitEarlyWakeup, "Not in TransactionStart::EarlyStart");
+ mExplicitEarlyWakeup = false;
+ break;
+ case Scheduler::TransactionStart::Normal:
+ case Scheduler::TransactionStart::Early:
+ // Non explicit don't change the explicit early wakeup state
+ break;
+ }
+
+ if (mTraceDetailedInfo) {
+ ATRACE_INT("mExplicitEarlyWakeup", mExplicitEarlyWakeup);
+ }
+
+ if (!mExplicitEarlyWakeup &&
+ (transactionStart == Scheduler::TransactionStart::Early ||
+ transactionStart == Scheduler::TransactionStart::EarlyEnd)) {
mRemainingEarlyFrameCount = MIN_EARLY_FRAME_COUNT_TRANSACTION;
mEarlyTxnStartTime = std::chrono::steady_clock::now();
}
// An early transaction stays an early transaction.
if (transactionStart == mTransactionStart ||
- mTransactionStart == Scheduler::TransactionStart::EARLY) {
+ mTransactionStart == Scheduler::TransactionStart::EarlyEnd) {
return;
}
mTransactionStart = transactionStart;
@@ -67,8 +88,8 @@
void VSyncModulator::onTransactionHandled() {
mTxnAppliedTime = std::chrono::steady_clock::now();
- if (mTransactionStart == Scheduler::TransactionStart::NORMAL) return;
- mTransactionStart = Scheduler::TransactionStart::NORMAL;
+ if (mTransactionStart == Scheduler::TransactionStart::Normal) return;
+ mTransactionStart = Scheduler::TransactionStart::Normal;
updateOffsets();
}
@@ -91,11 +112,10 @@
void VSyncModulator::onRefreshed(bool usedRenderEngine) {
bool updateOffsetsNeeded = false;
- // Apply a 1ms margin to account for potential data races
+ // Apply a margin to account for potential data races
// This might make us stay in early offsets for one
// additional frame but it's better to be conservative here.
- static const constexpr std::chrono::nanoseconds kMargin = 1ms;
- if ((mEarlyTxnStartTime.load() + kMargin) < mTxnAppliedTime.load()) {
+ if ((mEarlyTxnStartTime.load() + MARGIN_FOR_TX_APPLY) < mTxnAppliedTime.load()) {
if (mRemainingEarlyFrameCount > 0) {
mRemainingEarlyFrameCount--;
updateOffsetsNeeded = true;
@@ -121,8 +141,8 @@
const VSyncModulator::Offsets& VSyncModulator::getNextOffsets() const {
// Early offsets are used if we're in the middle of a refresh rate
// change, or if we recently begin a transaction.
- if (mTransactionStart == Scheduler::TransactionStart::EARLY || mRemainingEarlyFrameCount > 0 ||
- mRefreshRateChangePending) {
+ if (mExplicitEarlyWakeup || mTransactionStart == Scheduler::TransactionStart::EarlyEnd ||
+ mRemainingEarlyFrameCount > 0 || mRefreshRateChangePending) {
return mOffsetsConfig.early;
} else if (mRemainingRenderEngineUsageCount > 0) {
return mOffsetsConfig.earlyGl;
@@ -139,8 +159,8 @@
void VSyncModulator::updateOffsetsLocked() {
const Offsets& offsets = getNextOffsets();
- mScheduler.setPhaseOffset(mSfConnectionHandle, offsets.sf);
- mScheduler.setPhaseOffset(mAppConnectionHandle, offsets.app);
+ mPhaseOffsetControl.setPhaseOffset(mSfConnectionHandle, offsets.sf);
+ mPhaseOffsetControl.setPhaseOffset(mAppConnectionHandle, offsets.app);
mOffsets = offsets;
diff --git a/services/surfaceflinger/Scheduler/VSyncModulator.h b/services/surfaceflinger/Scheduler/VSyncModulator.h
index d777ef9..ab678c9 100644
--- a/services/surfaceflinger/Scheduler/VSyncModulator.h
+++ b/services/surfaceflinger/Scheduler/VSyncModulator.h
@@ -38,6 +38,9 @@
// switch in and out of gl composition.
static constexpr int MIN_EARLY_GL_FRAME_COUNT_TRANSACTION = 2;
+ // Margin used to account for potential data races
+ static const constexpr std::chrono::nanoseconds MARGIN_FOR_TX_APPLY = 1ms;
+
public:
// Wrapper for a collection of surfaceflinger/app offsets for a particular
// configuration.
@@ -62,7 +65,7 @@
bool operator!=(const OffsetsConfig& other) const { return !(*this == other); }
};
- VSyncModulator(Scheduler&, ConnectionHandle appConnectionHandle,
+ VSyncModulator(IPhaseOffsetControl&, ConnectionHandle appConnectionHandle,
ConnectionHandle sfConnectionHandle, const OffsetsConfig&);
void setPhaseOffsets(const OffsetsConfig&) EXCLUDES(mMutex);
@@ -91,13 +94,14 @@
Offsets getOffsets() const EXCLUDES(mMutex);
private:
+ friend class VSyncModulatorTest;
// Returns the next offsets that we should be using
const Offsets& getNextOffsets() const REQUIRES(mMutex);
// Updates offsets and persists them into the scheduler framework.
void updateOffsets() EXCLUDES(mMutex);
void updateOffsetsLocked() REQUIRES(mMutex);
- Scheduler& mScheduler;
+ IPhaseOffsetControl& mPhaseOffsetControl;
const ConnectionHandle mAppConnectionHandle;
const ConnectionHandle mSfConnectionHandle;
@@ -107,8 +111,9 @@
Offsets mOffsets GUARDED_BY(mMutex){mOffsetsConfig.late};
std::atomic<Scheduler::TransactionStart> mTransactionStart =
- Scheduler::TransactionStart::NORMAL;
+ Scheduler::TransactionStart::Normal;
std::atomic<bool> mRefreshRateChangePending = false;
+ std::atomic<bool> mExplicitEarlyWakeup = false;
std::atomic<int> mRemainingEarlyFrameCount = 0;
std::atomic<int> mRemainingRenderEngineUsageCount = 0;
std::atomic<std::chrono::steady_clock::time_point> mEarlyTxnStartTime = {};
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 4492f94..e68c484 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -23,6 +23,7 @@
#include "SurfaceFlinger.h"
+#include <android-base/properties.h>
#include <android/configuration.h>
#include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
#include <android/hardware/configstore/1.1/ISurfaceFlingerConfigs.h>
@@ -448,6 +449,9 @@
}
useFrameRateApi = use_frame_rate_api(true);
+
+ mKernelIdleTimerEnabled = mSupportKernelIdleTimer = sysprop::support_kernel_idle_timer(false);
+ base::SetProperty(KERNEL_IDLE_TIMER_PROP, mKernelIdleTimerEnabled ? "true" : "false");
}
SurfaceFlinger::~SurfaceFlinger() = default;
@@ -1670,7 +1674,7 @@
if (const auto displayId = getInternalDisplayIdLocked()) {
sp<DisplayDevice> display = getDefaultDisplayDeviceLocked();
if (display && display->isPoweredOn()) {
- setVsyncEnabledInHWC(*displayId, mHWCVsyncPendingState);
+ getHwComposer().setVsyncEnabled(*displayId, mHWCVsyncPendingState);
}
}
}
@@ -2748,7 +2752,8 @@
* (perform the transaction for each of them if needed)
*/
- if ((transactionFlags & eTraversalNeeded) || mTraversalNeededMainThread) {
+ if ((transactionFlags & eTraversalNeeded) || mForceTraversal) {
+ mForceTraversal = false;
mCurrentState.traverse([&](Layer* layer) {
uint32_t trFlags = layer->getTransactionFlags(eTransactionNeeded);
if (!trFlags) return;
@@ -2761,7 +2766,6 @@
mInputInfoChanged = true;
}
});
- mTraversalNeededMainThread = false;
}
/*
@@ -3224,7 +3228,7 @@
}
uint32_t SurfaceFlinger::setTransactionFlags(uint32_t flags) {
- return setTransactionFlags(flags, Scheduler::TransactionStart::NORMAL);
+ return setTransactionFlags(flags, Scheduler::TransactionStart::Normal);
}
uint32_t SurfaceFlinger::setTransactionFlags(uint32_t flags,
@@ -3237,8 +3241,8 @@
return old;
}
-uint32_t SurfaceFlinger::setTransactionFlagsNoWake(uint32_t flags) {
- return mTransactionFlags.fetch_or(flags);
+void SurfaceFlinger::setTraversalNeeded() {
+ mForceTraversal = true;
}
bool SurfaceFlinger::flushTransactionQueues() {
@@ -3438,18 +3442,39 @@
// so we don't have to wake up again next frame to preform an uneeded traversal.
if (isMainThread && (transactionFlags & eTraversalNeeded)) {
transactionFlags = transactionFlags & (~eTraversalNeeded);
- mTraversalNeededMainThread = true;
+ mForceTraversal = true;
}
+ const auto transactionStart = [](uint32_t flags) {
+ if (flags & eEarlyWakeup) {
+ return Scheduler::TransactionStart::Early;
+ }
+ if (flags & eExplicitEarlyWakeupEnd) {
+ return Scheduler::TransactionStart::EarlyEnd;
+ }
+ if (flags & eExplicitEarlyWakeupStart) {
+ return Scheduler::TransactionStart::EarlyStart;
+ }
+ return Scheduler::TransactionStart::Normal;
+ }(flags);
+
if (transactionFlags) {
if (mInterceptor->isEnabled()) {
mInterceptor->saveTransaction(states, mCurrentState.displays, displays, flags);
}
+ // TODO(b/159125966): Remove eEarlyWakeup completly as no client should use this flag
+ if (flags & eEarlyWakeup) {
+ ALOGW("eEarlyWakeup is deprecated. Use eExplicitEarlyWakeup[Start|End]");
+ }
+
+ if (!privileged && (flags & (eExplicitEarlyWakeupStart | eExplicitEarlyWakeupEnd))) {
+ ALOGE("Only WindowManager is allowed to use eExplicitEarlyWakeup[Start|End] flags");
+ flags &= ~(eExplicitEarlyWakeupStart | eExplicitEarlyWakeupEnd);
+ }
+
// this triggers the transaction
- const auto start = (flags & eEarlyWakeup) ? Scheduler::TransactionStart::EARLY
- : Scheduler::TransactionStart::NORMAL;
- setTransactionFlags(transactionFlags, start);
+ setTransactionFlags(transactionFlags, transactionStart);
if (flags & eAnimation) {
mAnimTransactionPending = true;
@@ -3486,6 +3511,13 @@
break;
}
}
+ } else {
+ // even if a transaction is not needed, we need to update VsyncModulator
+ // about explicit early indications
+ if (transactionStart == Scheduler::TransactionStart::EarlyStart ||
+ transactionStart == Scheduler::TransactionStart::EarlyEnd) {
+ mVSyncModulator->setTransactionStart(transactionStart);
+ }
}
}
@@ -4161,13 +4193,6 @@
static_cast<void>(schedule([this]() MAIN_THREAD { onInitializeDisplays(); }));
}
-void SurfaceFlinger::setVsyncEnabledInHWC(DisplayId displayId, hal::Vsync enabled) {
- if (mHWCVsyncState != enabled) {
- getHwComposer().setVsyncEnabled(displayId, enabled);
- mHWCVsyncState = enabled;
- }
-}
-
void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& display, hal::PowerMode mode) {
if (display->isVirtual()) {
ALOGE("%s: Invalid operation on virtual display", __FUNCTION__);
@@ -4196,7 +4221,7 @@
}
getHwComposer().setPowerMode(*displayId, mode);
if (display->isPrimary() && mode != hal::PowerMode::DOZE_SUSPEND) {
- setVsyncEnabledInHWC(*displayId, mHWCVsyncPendingState);
+ getHwComposer().setVsyncEnabled(*displayId, mHWCVsyncPendingState);
mScheduler->onScreenAcquired(mAppConnectionHandle);
mScheduler->resyncToHardwareVsync(true, getVsyncPeriod());
}
@@ -4215,7 +4240,7 @@
}
// Make sure HWVsync is disabled before turning off the display
- setVsyncEnabledInHWC(*displayId, hal::Vsync::DISABLE);
+ getHwComposer().setVsyncEnabled(*displayId, hal::Vsync::DISABLE);
getHwComposer().setPowerMode(*displayId, mode);
mVisibleRegionsDirty = true;
@@ -5322,8 +5347,7 @@
const auto& min = mRefreshRateConfigs->getMinRefreshRate();
if (current != min) {
- const auto kernelTimerEnabled = property_get_bool(KERNEL_IDLE_TIMER_PROP, false);
- const bool timerExpired = kernelTimerEnabled && expired;
+ const bool timerExpired = mKernelIdleTimerEnabled && expired;
if (Mutex::Autolock lock(mStateLock); mRefreshRateOverlay) {
mRefreshRateOverlay->changeRefreshRate(timerExpired ? min : current);
@@ -5333,6 +5357,35 @@
}));
}
+void SurfaceFlinger::toggleKernelIdleTimer() {
+ using KernelIdleTimerAction = scheduler::RefreshRateConfigs::KernelIdleTimerAction;
+
+ // If the support for kernel idle timer is disabled in SF code, don't do anything.
+ if (!mSupportKernelIdleTimer) {
+ return;
+ }
+ const KernelIdleTimerAction action = mRefreshRateConfigs->getIdleTimerAction();
+
+ switch (action) {
+ case KernelIdleTimerAction::TurnOff:
+ if (mKernelIdleTimerEnabled) {
+ ATRACE_INT("KernelIdleTimer", 0);
+ base::SetProperty(KERNEL_IDLE_TIMER_PROP, "false");
+ mKernelIdleTimerEnabled = false;
+ }
+ break;
+ case KernelIdleTimerAction::TurnOn:
+ if (!mKernelIdleTimerEnabled) {
+ ATRACE_INT("KernelIdleTimer", 1);
+ base::SetProperty(KERNEL_IDLE_TIMER_PROP, "true");
+ mKernelIdleTimerEnabled = true;
+ }
+ break;
+ case KernelIdleTimerAction::NoChange:
+ break;
+ }
+}
+
// A simple RAII class to disconnect from an ANativeWindow* when it goes out of scope
class WindowDisconnector {
public:
@@ -5362,27 +5415,33 @@
renderAreaRotation = ui::Transform::ROT_0;
}
- sp<DisplayDevice> display;
+ wp<DisplayDevice> displayWeak;
+ ui::LayerStack layerStack;
+ ui::Size reqSize(reqWidth, reqHeight);
{
Mutex::Autolock lock(mStateLock);
-
- display = getDisplayDeviceLocked(displayToken);
+ sp<DisplayDevice> display = getDisplayDeviceLocked(displayToken);
if (!display) return NAME_NOT_FOUND;
+ displayWeak = display;
+ layerStack = display->getLayerStack();
// set the requested width/height to the logical display viewport size
// by default
if (reqWidth == 0 || reqHeight == 0) {
- reqWidth = uint32_t(display->getViewport().width());
- reqHeight = uint32_t(display->getViewport().height());
+ reqSize = display->getViewport().getSize();
}
}
- DisplayRenderArea renderArea(display, sourceCrop, reqWidth, reqHeight, reqDataspace,
- renderAreaRotation, captureSecureLayers);
- auto traverseLayers = std::bind(&SurfaceFlinger::traverseLayersInDisplay, this, display,
- std::placeholders::_1);
- return captureScreenCommon(renderArea, traverseLayers, outBuffer, reqPixelFormat,
- useIdentityTransform, outCapturedSecureLayers);
+ RenderAreaFuture renderAreaFuture = promise::defer([=] {
+ return DisplayRenderArea::create(displayWeak, sourceCrop, reqSize, reqDataspace,
+ renderAreaRotation, captureSecureLayers);
+ });
+
+ auto traverseLayers = [this, layerStack](const LayerVector::Visitor& visitor) {
+ traverseLayersInLayerStack(layerStack, visitor);
+ };
+ return captureScreenCommon(std::move(renderAreaFuture), traverseLayers, reqSize, outBuffer,
+ reqPixelFormat, useIdentityTransform, outCapturedSecureLayers);
}
static Dataspace pickDataspaceFromColorMode(const ColorMode colorMode) {
@@ -5438,19 +5497,20 @@
status_t SurfaceFlinger::captureScreen(uint64_t displayOrLayerStack, Dataspace* outDataspace,
sp<GraphicBuffer>* outBuffer) {
- sp<DisplayDevice> display;
- uint32_t width;
- uint32_t height;
+ ui::LayerStack layerStack;
+ wp<DisplayDevice> displayWeak;
+ ui::Size size;
ui::Transform::RotationFlags captureOrientation;
{
Mutex::Autolock lock(mStateLock);
- display = getDisplayByIdOrLayerStack(displayOrLayerStack);
+ sp<DisplayDevice> display = getDisplayByIdOrLayerStack(displayOrLayerStack);
if (!display) {
return NAME_NOT_FOUND;
}
+ layerStack = display->getLayerStack();
+ displayWeak = display;
- width = uint32_t(display->getViewport().width());
- height = uint32_t(display->getViewport().height());
+ size = display->getViewport().getSize();
const auto orientation = display->getOrientation();
captureOrientation = ui::Transform::toRotationFlags(orientation);
@@ -5476,14 +5536,19 @@
pickDataspaceFromColorMode(display->getCompositionDisplay()->getState().colorMode);
}
- DisplayRenderArea renderArea(display, Rect(), width, height, *outDataspace, captureOrientation,
- false /* captureSecureLayers */);
+ RenderAreaFuture renderAreaFuture = promise::defer([=] {
+ return DisplayRenderArea::create(displayWeak, Rect(), size, *outDataspace,
+ captureOrientation, false /* captureSecureLayers */);
+ });
- auto traverseLayers = std::bind(&SurfaceFlinger::traverseLayersInDisplay, this, display,
- std::placeholders::_1);
+ auto traverseLayers = [this, layerStack](const LayerVector::Visitor& visitor) {
+ traverseLayersInLayerStack(layerStack, visitor);
+ };
+
bool ignored = false;
- return captureScreenCommon(renderArea, traverseLayers, outBuffer, ui::PixelFormat::RGBA_8888,
- false /* useIdentityTransform */,
+
+ return captureScreenCommon(std::move(renderAreaFuture), traverseLayers, size, outBuffer,
+ ui::PixelFormat::RGBA_8888, false /* useIdentityTransform */,
ignored /* outCapturedSecureLayers */);
}
@@ -5497,9 +5562,9 @@
class LayerRenderArea : public RenderArea {
public:
LayerRenderArea(SurfaceFlinger* flinger, const sp<Layer>& layer, const Rect crop,
- int32_t reqWidth, int32_t reqHeight, Dataspace reqDataSpace,
- bool childrenOnly, const Rect& displayViewport)
- : RenderArea(reqWidth, reqHeight, CaptureFill::CLEAR, reqDataSpace, displayViewport),
+ ui::Size reqSize, Dataspace reqDataSpace, bool childrenOnly,
+ const Rect& displayViewport)
+ : RenderArea(reqSize, CaptureFill::CLEAR, reqDataSpace, displayViewport),
mLayer(layer),
mCrop(crop),
mNeedsFiltering(false),
@@ -5574,8 +5639,7 @@
const bool mChildrenOnly;
};
- int reqWidth = 0;
- int reqHeight = 0;
+ ui::Size reqSize;
sp<Layer> parent;
Rect crop(sourceCrop);
std::unordered_set<sp<Layer>, ISurfaceComposer::SpHash<Layer>> excludeLayers;
@@ -5612,8 +5676,7 @@
// crop was not specified, or an invalid frame scale was provided.
return BAD_VALUE;
}
- reqWidth = crop.width() * frameScale;
- reqHeight = crop.height() * frameScale;
+ reqSize = ui::Size(crop.width() * frameScale, crop.height() * frameScale);
for (const auto& handle : excludeHandles) {
sp<Layer> excludeLayer = fromHandleLocked(handle).promote();
@@ -5634,15 +5697,18 @@
} // mStateLock
// really small crop or frameScale
- if (reqWidth <= 0) {
- reqWidth = 1;
+ if (reqSize.width <= 0) {
+ reqSize.width = 1;
}
- if (reqHeight <= 0) {
- reqHeight = 1;
+ if (reqSize.height <= 0) {
+ reqSize.height = 1;
}
- LayerRenderArea renderArea(this, parent, crop, reqWidth, reqHeight, reqDataspace, childrenOnly,
- displayViewport);
+ RenderAreaFuture renderAreaFuture = promise::defer([=]() -> std::unique_ptr<RenderArea> {
+ return std::make_unique<LayerRenderArea>(this, parent, crop, reqSize, reqDataspace,
+ childrenOnly, displayViewport);
+ });
+
auto traverseLayers = [parent, childrenOnly,
&excludeLayers](const LayerVector::Visitor& visitor) {
parent->traverseChildrenInZOrder(LayerVector::StateSet::Drawing, [&](Layer* layer) {
@@ -5665,14 +5731,14 @@
};
bool outCapturedSecureLayers = false;
- return captureScreenCommon(renderArea, traverseLayers, outBuffer, reqPixelFormat, false,
- outCapturedSecureLayers);
+ return captureScreenCommon(std::move(renderAreaFuture), traverseLayers, reqSize, outBuffer,
+ reqPixelFormat, false, outCapturedSecureLayers);
}
-status_t SurfaceFlinger::captureScreenCommon(RenderArea& renderArea,
+status_t SurfaceFlinger::captureScreenCommon(RenderAreaFuture renderAreaFuture,
TraverseLayersFunction traverseLayers,
- sp<GraphicBuffer>* outBuffer,
- const ui::PixelFormat reqPixelFormat,
+ ui::Size bufferSize, sp<GraphicBuffer>* outBuffer,
+ ui::PixelFormat reqPixelFormat,
bool useIdentityTransform,
bool& outCapturedSecureLayers) {
ATRACE_CALL();
@@ -5680,16 +5746,16 @@
// TODO(b/116112787) Make buffer usage a parameter.
const uint32_t usage = GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN |
GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE;
- *outBuffer =
- getFactory().createGraphicBuffer(renderArea.getReqWidth(), renderArea.getReqHeight(),
- static_cast<android_pixel_format>(reqPixelFormat), 1,
- usage, "screenshot");
+ *outBuffer = getFactory().createGraphicBuffer(bufferSize.getWidth(), bufferSize.getHeight(),
+ static_cast<android_pixel_format>(reqPixelFormat),
+ 1, usage, "screenshot");
- return captureScreenCommon(renderArea, traverseLayers, *outBuffer, useIdentityTransform,
- false /* regionSampling */, outCapturedSecureLayers);
+ return captureScreenCommon(std::move(renderAreaFuture), traverseLayers, *outBuffer,
+ useIdentityTransform, false /* regionSampling */,
+ outCapturedSecureLayers);
}
-status_t SurfaceFlinger::captureScreenCommon(RenderArea& renderArea,
+status_t SurfaceFlinger::captureScreenCommon(RenderAreaFuture renderAreaFuture,
TraverseLayersFunction traverseLayers,
const sp<GraphicBuffer>& buffer,
bool useIdentityTransform, bool regionSampling,
@@ -5702,23 +5768,28 @@
do {
std::tie(result, syncFd) =
- schedule([&] {
+ schedule([&]() -> std::pair<status_t, int> {
if (mRefreshPending) {
- ATRACE_NAME("Skipping screenshot for now");
- return std::make_pair(EAGAIN, -1);
+ ALOGW("Skipping screenshot for now");
+ return {EAGAIN, -1};
+ }
+ std::unique_ptr<RenderArea> renderArea = renderAreaFuture.get();
+ if (!renderArea) {
+ ALOGW("Skipping screen capture because of invalid render area.");
+ return {NO_MEMORY, -1};
}
status_t result = NO_ERROR;
int fd = -1;
Mutex::Autolock lock(mStateLock);
- renderArea.render([&] {
- result = captureScreenImplLocked(renderArea, traverseLayers, buffer.get(),
+ renderArea->render([&] {
+ result = captureScreenImplLocked(*renderArea, traverseLayers, buffer.get(),
useIdentityTransform, forSystem, &fd,
regionSampling, outCapturedSecureLayers);
});
- return std::make_pair(result, fd);
+ return {result, fd};
}).get();
} while (result == EAGAIN);
@@ -5877,17 +5948,17 @@
layersSortedByZ.traverseInReverseZOrder(stateSet, visitor);
}
-void SurfaceFlinger::traverseLayersInDisplay(const sp<const DisplayDevice>& display,
- const LayerVector::Visitor& visitor) {
+void SurfaceFlinger::traverseLayersInLayerStack(ui::LayerStack layerStack,
+ const LayerVector::Visitor& visitor) {
// We loop through the first level of layers without traversing,
// as we need to determine which layers belong to the requested display.
for (const auto& layer : mDrawingState.layersSortedByZ) {
- if (!layer->belongsToDisplay(display->getLayerStack(), false)) {
+ if (!layer->belongsToDisplay(layerStack, false)) {
continue;
}
// relative layers are traversed in Layer::traverseInZOrder
layer->traverseInZOrder(LayerVector::StateSet::Drawing, [&](Layer* layer) {
- if (!layer->belongsToDisplay(display->getLayerStack(), false)) {
+ if (!layer->belongsToDisplay(layerStack, false)) {
return;
}
if (!layer->isVisible()) {
@@ -5960,14 +6031,14 @@
currentPolicy.primaryRange.max, currentPolicy.appRequestRange.min,
currentPolicy.appRequestRange.max);
- // TODO(b/140204874): This hack triggers a notification that something has changed, so
- // that listeners that care about a change in allowed configs can get the notification.
- // Giving current ActiveConfig so that most other listeners would just drop the event
+ // TODO(b/140204874): Leave the event in until we do proper testing with all apps that might
+ // be depending in this callback.
const nsecs_t vsyncPeriod =
mRefreshRateConfigs->getRefreshRateFromConfigId(display->getActiveConfig())
.getVsyncPeriod();
mScheduler->onPrimaryDisplayConfigChanged(mAppConnectionHandle, display->getId()->value,
display->getActiveConfig(), vsyncPeriod);
+ toggleKernelIdleTimer();
auto configId = mScheduler->getPreferredConfigId();
auto& preferredRefreshRate = configId
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 5c81a54..6a3937f 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -302,7 +302,6 @@
// main thread function to enable/disable h/w composer event
void setPrimaryVsyncEnabledInternal(bool enabled) REQUIRES(mStateLock);
- void setVsyncEnabledInHWC(DisplayId displayId, hal::Vsync enabled);
// called on the main thread by MessageQueue when an internal message
// is received
@@ -536,6 +535,13 @@
void repaintEverythingForHWC() override;
// Called when kernel idle timer has expired. Used to update the refresh rate overlay.
void kernelTimerChanged(bool expired) override;
+ // Toggles the kernel idle timer on or off depending the policy decisions around refresh rates.
+ void toggleKernelIdleTimer();
+ // Keeps track of whether the kernel idle timer is currently enabled, so we don't have to
+ // make calls to sys prop each time.
+ bool mKernelIdleTimerEnabled = false;
+ // Keeps track of whether the kernel timer is supported on the SF side.
+ bool mSupportKernelIdleTimer = false;
/* ------------------------------------------------------------------------
* Message handling
*/
@@ -628,12 +634,12 @@
uint32_t peekTransactionFlags();
// Can only be called from the main thread or with mStateLock held
uint32_t setTransactionFlags(uint32_t flags);
- // Set the transaction flags, but don't trigger a wakeup! We use this cases where
- // there are still pending transactions but we know they won't be ready until a frame
+ // Indicate SF should call doTraversal on layers, but don't trigger a wakeup! We use this cases
+ // where there are still pending transactions but we know they won't be ready until a frame
// arrives from a different layer. So we need to ensure we performTransaction from invalidate
// but there is no need to try and wake up immediately to do it. Rather we rely on
- // onFrameAvailable to wake us up.
- uint32_t setTransactionFlagsNoWake(uint32_t flags);
+ // onFrameAvailable or another layer update to wake us up.
+ void setTraversalNeeded();
uint32_t setTransactionFlags(uint32_t flags, Scheduler::TransactionStart transactionStart);
void commitTransaction() REQUIRES(mStateLock);
void commitOffscreenLayers();
@@ -712,16 +718,17 @@
void startBootAnim();
using TraverseLayersFunction = std::function<void(const LayerVector::Visitor&)>;
+ using RenderAreaFuture = std::future<std::unique_ptr<RenderArea>>;
void renderScreenImplLocked(const RenderArea& renderArea, TraverseLayersFunction traverseLayers,
const sp<GraphicBuffer>& buffer, bool useIdentityTransform,
bool regionSampling, int* outSyncFd);
- status_t captureScreenCommon(RenderArea& renderArea, TraverseLayersFunction traverseLayers,
- sp<GraphicBuffer>* outBuffer, const ui::PixelFormat reqPixelFormat,
+ status_t captureScreenCommon(RenderAreaFuture, TraverseLayersFunction, ui::Size bufferSize,
+ sp<GraphicBuffer>* outBuffer, ui::PixelFormat,
bool useIdentityTransform, bool& outCapturedSecureLayers);
- status_t captureScreenCommon(RenderArea& renderArea, TraverseLayersFunction traverseLayers,
- const sp<GraphicBuffer>& buffer, bool useIdentityTransform,
- bool regionSampling, bool& outCapturedSecureLayers);
+ status_t captureScreenCommon(RenderAreaFuture, TraverseLayersFunction, const sp<GraphicBuffer>&,
+ bool useIdentityTransform, bool regionSampling,
+ bool& outCapturedSecureLayers);
sp<DisplayDevice> getDisplayByIdOrLayerStack(uint64_t displayOrLayerStack) REQUIRES(mStateLock);
sp<DisplayDevice> getDisplayByLayerStack(uint64_t layerStack) REQUIRES(mStateLock);
status_t captureScreenImplLocked(const RenderArea& renderArea,
@@ -729,8 +736,7 @@
const sp<GraphicBuffer>& buffer, bool useIdentityTransform,
bool forSystem, int* outSyncFd, bool regionSampling,
bool& outCapturedSecureLayers);
- void traverseLayersInDisplay(const sp<const DisplayDevice>& display,
- const LayerVector::Visitor& visitor);
+ void traverseLayersInLayerStack(ui::LayerStack, const LayerVector::Visitor&);
sp<StartPropertySetThread> mStartPropertySetThread;
@@ -999,7 +1005,7 @@
bool mTransactionPending = false;
bool mAnimTransactionPending = false;
SortedVector<sp<Layer>> mLayersPendingRemoval;
- bool mTraversalNeededMainThread = false;
+ bool mForceTraversal = false;
// global color transform states
Daltonizer mDaltonizer;
@@ -1211,6 +1217,7 @@
std::unique_ptr<scheduler::RefreshRateStats> mRefreshRateStats;
std::atomic<nsecs_t> mExpectedPresentTime = 0;
+ hal::Vsync mHWCVsyncPendingState = hal::Vsync::DISABLE;
/* ------------------------------------------------------------------------
* Generic Layer Metadata
@@ -1281,10 +1288,6 @@
// be any issues with a raw pointer referencing an invalid object.
std::unordered_set<Layer*> mOffscreenLayers;
- // Flags to capture the state of Vsync in HWC
- hal::Vsync mHWCVsyncState = hal::Vsync::DISABLE;
- hal::Vsync mHWCVsyncPendingState = hal::Vsync::DISABLE;
-
// Fields tracking the current jank event: when it started and how many
// janky frames there are.
nsecs_t mMissedFrameJankStart = 0;
diff --git a/services/surfaceflinger/TransactionCompletedThread.cpp b/services/surfaceflinger/TransactionCompletedThread.cpp
index 0cdff8f..ca24493 100644
--- a/services/surfaceflinger/TransactionCompletedThread.cpp
+++ b/services/surfaceflinger/TransactionCompletedThread.cpp
@@ -154,6 +154,9 @@
status_t TransactionCompletedThread::finalizePendingCallbackHandles(
const std::deque<sp<CallbackHandle>>& handles) {
+ if (handles.empty()) {
+ return NO_ERROR;
+ }
std::lock_guard lock(mMutex);
if (!mRunning) {
ALOGE("cannot add presented callback handle because the callback thread isn't running");
diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp
index 7574ff1..3c4a791 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -62,6 +62,7 @@
"StrongTypingTest.cpp",
"VSyncDispatchTimerQueueTest.cpp",
"VSyncDispatchRealtimeTest.cpp",
+ "VSyncModulatorTest.cpp",
"VSyncPredictorTest.cpp",
"VSyncReactorTest.cpp",
"mock/DisplayHardware/MockComposer.cpp",
diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
index 95e2ef5..456891e 100644
--- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
@@ -233,23 +233,22 @@
constexpr bool forSystem = true;
constexpr bool regionSampling = false;
- DisplayRenderArea renderArea(mDisplay, sourceCrop, DEFAULT_DISPLAY_WIDTH,
- DEFAULT_DISPLAY_HEIGHT, ui::Dataspace::V0_SRGB,
- ui::Transform::ROT_0);
+ auto renderArea = DisplayRenderArea::create(mDisplay, sourceCrop, sourceCrop.getSize(),
+ ui::Dataspace::V0_SRGB, ui::Transform::ROT_0);
auto traverseLayers = [this](const LayerVector::Visitor& visitor) {
- return mFlinger.traverseLayersInDisplay(mDisplay, visitor);
+ return mFlinger.traverseLayersInLayerStack(mDisplay->getLayerStack(), visitor);
};
// TODO: Eliminate expensive/real allocation if possible.
const uint32_t usage = GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN |
GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE;
- mCaptureScreenBuffer = new GraphicBuffer(renderArea.getReqWidth(), renderArea.getReqHeight(),
+ mCaptureScreenBuffer = new GraphicBuffer(renderArea->getReqWidth(), renderArea->getReqHeight(),
HAL_PIXEL_FORMAT_RGBA_8888, 1, usage, "screenshot");
int fd = -1;
status_t result =
- mFlinger.captureScreenImplLocked(renderArea, traverseLayers, mCaptureScreenBuffer.get(),
+ mFlinger.captureScreenImplLocked(*renderArea, traverseLayers, mCaptureScreenBuffer.get(),
useIdentityTransform, forSystem, &fd, regionSampling);
if (fd >= 0) {
close(fd);
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
index f24575e..fed591c 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
@@ -1420,6 +1420,34 @@
}
}
+TEST_F(RefreshRateConfigsTest, testComparisonOperator) {
+ EXPECT_TRUE(mExpected60Config < mExpected90Config);
+ EXPECT_FALSE(mExpected60Config < mExpected60Config);
+ EXPECT_FALSE(mExpected90Config < mExpected90Config);
+}
+
+TEST_F(RefreshRateConfigsTest, testKernelIdleTimerAction) {
+ using KernelIdleTimerAction = scheduler::RefreshRateConfigs::KernelIdleTimerAction;
+
+ auto refreshRateConfigs =
+ std::make_unique<RefreshRateConfigs>(m60_90Device,
+ /*currentConfigId=*/HWC_CONFIG_ID_90);
+ // SetPolicy(60, 90), current 90Hz => TurnOn.
+ EXPECT_EQ(KernelIdleTimerAction::TurnOn, refreshRateConfigs->getIdleTimerAction());
+
+ // SetPolicy(60, 90), current 60Hz => TurnOn.
+ ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {60, 90}}), 0);
+ EXPECT_EQ(KernelIdleTimerAction::TurnOn, refreshRateConfigs->getIdleTimerAction());
+
+ // SetPolicy(60, 60), current 60Hz => NoChange, avoid extra calls.
+ ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {60, 60}}), 0);
+ EXPECT_EQ(KernelIdleTimerAction::NoChange, refreshRateConfigs->getIdleTimerAction());
+
+ // SetPolicy(90, 90), current 90Hz => TurnOff.
+ ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_90, {90, 90}}), 0);
+ EXPECT_EQ(KernelIdleTimerAction::TurnOff, refreshRateConfigs->getIdleTimerAction());
+}
+
} // namespace
} // namespace scheduler
} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index 4652da0..f630103 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -341,9 +341,9 @@
regionSampling, ignored);
}
- auto traverseLayersInDisplay(const sp<const DisplayDevice>& display,
- const LayerVector::Visitor& visitor) {
- return mFlinger->SurfaceFlinger::traverseLayersInDisplay(display, visitor);
+ auto traverseLayersInLayerStack(ui::LayerStack layerStack,
+ const LayerVector::Visitor& visitor) {
+ return mFlinger->SurfaceFlinger::traverseLayersInLayerStack(layerStack, visitor);
}
auto getDisplayNativePrimaries(const sp<IBinder>& displayToken,
diff --git a/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp b/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp
index 793cb8b..d940dc5 100644
--- a/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp
+++ b/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp
@@ -701,6 +701,52 @@
EXPECT_THAT(cb.mCalls.size(), Eq(1));
}
+// b/154303580.
+TEST_F(VSyncDispatchTimerQueueTest, skipsRearmingWhenNotNextScheduled) {
+ Sequence seq;
+ EXPECT_CALL(mMockClock, alarmIn(_, 600)).InSequence(seq);
+ EXPECT_CALL(mMockClock, alarmCancel()).InSequence(seq);
+ CountingCallback cb1(mDispatch);
+ CountingCallback cb2(mDispatch);
+
+ EXPECT_EQ(mDispatch.schedule(cb1, 400, 1000), ScheduleResult::Scheduled);
+ EXPECT_EQ(mDispatch.schedule(cb2, 100, 2000), ScheduleResult::Scheduled);
+
+ mMockClock.setLag(100);
+ mMockClock.advanceBy(620);
+
+ EXPECT_EQ(mDispatch.cancel(cb2), CancelResult::Cancelled);
+
+ mMockClock.advanceBy(80);
+
+ EXPECT_THAT(cb1.mCalls.size(), Eq(1));
+ EXPECT_THAT(cb2.mCalls.size(), Eq(0));
+}
+
+TEST_F(VSyncDispatchTimerQueueTest, rearmsWhenCancelledAndIsNextScheduled) {
+ Sequence seq;
+ EXPECT_CALL(mMockClock, alarmIn(_, 600)).InSequence(seq);
+ EXPECT_CALL(mMockClock, alarmIn(_, 1280)).InSequence(seq);
+ EXPECT_CALL(mMockClock, alarmCancel()).InSequence(seq);
+ CountingCallback cb1(mDispatch);
+ CountingCallback cb2(mDispatch);
+
+ EXPECT_EQ(mDispatch.schedule(cb1, 400, 1000), ScheduleResult::Scheduled);
+ EXPECT_EQ(mDispatch.schedule(cb2, 100, 2000), ScheduleResult::Scheduled);
+
+ mMockClock.setLag(100);
+ mMockClock.advanceBy(620);
+
+ EXPECT_EQ(mDispatch.cancel(cb1), CancelResult::Cancelled);
+
+ EXPECT_THAT(cb1.mCalls.size(), Eq(0));
+ EXPECT_THAT(cb2.mCalls.size(), Eq(0));
+ mMockClock.advanceToNextCallback();
+
+ EXPECT_THAT(cb1.mCalls.size(), Eq(0));
+ EXPECT_THAT(cb2.mCalls.size(), Eq(1));
+}
+
class VSyncDispatchTimerQueueEntryTest : public testing::Test {
protected:
nsecs_t const mPeriod = 1000;
diff --git a/services/surfaceflinger/tests/unittests/VSyncModulatorTest.cpp b/services/surfaceflinger/tests/unittests/VSyncModulatorTest.cpp
new file mode 100644
index 0000000..9c1ec07
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/VSyncModulatorTest.cpp
@@ -0,0 +1,301 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "LibSurfaceFlingerUnittests"
+#define LOG_NDEBUG 0
+
+#include "Scheduler/VSyncModulator.h"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+using namespace testing;
+
+namespace android::scheduler {
+
+class MockScheduler : public IPhaseOffsetControl {
+public:
+ void setPhaseOffset(ConnectionHandle handle, nsecs_t phaseOffset) {
+ mPhaseOffset[handle] = phaseOffset;
+ }
+
+ nsecs_t getOffset(ConnectionHandle handle) { return mPhaseOffset[handle]; }
+
+private:
+ std::unordered_map<ConnectionHandle, nsecs_t> mPhaseOffset;
+};
+
+class VSyncModulatorTest : public testing::Test {
+protected:
+ static constexpr auto MIN_EARLY_FRAME_COUNT_TRANSACTION =
+ VSyncModulator::MIN_EARLY_FRAME_COUNT_TRANSACTION;
+ // Add a 1ms slack to avoid strange timer race conditions.
+ static constexpr auto MARGIN_FOR_TX_APPLY = VSyncModulator::MARGIN_FOR_TX_APPLY + 1ms;
+
+ // Used to enumerate the different offsets we have
+ enum {
+ SF_LATE,
+ APP_LATE,
+ SF_EARLY,
+ APP_EARLY,
+ SF_EARLY_GL,
+ APP_EARLY_GL,
+ };
+
+ std::unique_ptr<VSyncModulator> mVSyncModulator;
+ MockScheduler mMockScheduler;
+ ConnectionHandle mAppConnection{1};
+ ConnectionHandle mSfConnection{2};
+ VSyncModulator::OffsetsConfig mOffsets = {{SF_EARLY, APP_EARLY},
+ {SF_EARLY_GL, APP_EARLY_GL},
+ {SF_LATE, APP_LATE}};
+
+ void SetUp() override {
+ mVSyncModulator = std::make_unique<VSyncModulator>(mMockScheduler, mAppConnection,
+ mSfConnection, mOffsets);
+ mVSyncModulator->setPhaseOffsets(mOffsets);
+
+ EXPECT_EQ(APP_LATE, mMockScheduler.getOffset(mAppConnection));
+ EXPECT_EQ(SF_LATE, mMockScheduler.getOffset(mSfConnection));
+ };
+
+ void TearDown() override { mVSyncModulator.reset(); }
+};
+
+TEST_F(VSyncModulatorTest, Normal) {
+ mVSyncModulator->setTransactionStart(Scheduler::TransactionStart::Normal);
+ std::this_thread::sleep_for(MARGIN_FOR_TX_APPLY);
+ mVSyncModulator->onTransactionHandled();
+ EXPECT_EQ(APP_LATE, mMockScheduler.getOffset(mAppConnection));
+ EXPECT_EQ(SF_LATE, mMockScheduler.getOffset(mSfConnection));
+
+ for (int i = 0; i < MIN_EARLY_FRAME_COUNT_TRANSACTION; i++) {
+ mVSyncModulator->onRefreshed(false);
+ EXPECT_EQ(APP_LATE, mMockScheduler.getOffset(mAppConnection));
+ EXPECT_EQ(SF_LATE, mMockScheduler.getOffset(mSfConnection));
+ }
+}
+
+TEST_F(VSyncModulatorTest, EarlyEnd) {
+ mVSyncModulator->setTransactionStart(Scheduler::TransactionStart::EarlyEnd);
+ std::this_thread::sleep_for(MARGIN_FOR_TX_APPLY);
+ mVSyncModulator->onTransactionHandled();
+ EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
+ EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
+
+ for (int i = 0; i < MIN_EARLY_FRAME_COUNT_TRANSACTION - 1; i++) {
+ mVSyncModulator->onRefreshed(false);
+ EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
+ EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
+ }
+
+ mVSyncModulator->onRefreshed(false);
+ EXPECT_EQ(APP_LATE, mMockScheduler.getOffset(mAppConnection));
+ EXPECT_EQ(SF_LATE, mMockScheduler.getOffset(mSfConnection));
+}
+
+TEST_F(VSyncModulatorTest, EarlyStart) {
+ mVSyncModulator->setTransactionStart(Scheduler::TransactionStart::EarlyStart);
+ std::this_thread::sleep_for(MARGIN_FOR_TX_APPLY);
+ mVSyncModulator->onTransactionHandled();
+ EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
+ EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
+
+ for (int i = 0; i < 5 * MIN_EARLY_FRAME_COUNT_TRANSACTION; i++) {
+ mVSyncModulator->onRefreshed(false);
+ EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
+ EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
+ }
+
+ mVSyncModulator->setTransactionStart(Scheduler::TransactionStart::EarlyEnd);
+ std::this_thread::sleep_for(MARGIN_FOR_TX_APPLY);
+ mVSyncModulator->onTransactionHandled();
+ EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
+ EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
+
+ for (int i = 0; i < MIN_EARLY_FRAME_COUNT_TRANSACTION - 1; i++) {
+ mVSyncModulator->onRefreshed(false);
+ EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
+ EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
+ }
+
+ mVSyncModulator->onRefreshed(false);
+ EXPECT_EQ(APP_LATE, mMockScheduler.getOffset(mAppConnection));
+ EXPECT_EQ(SF_LATE, mMockScheduler.getOffset(mSfConnection));
+}
+
+TEST_F(VSyncModulatorTest, EarlyStartWithEarly) {
+ mVSyncModulator->setTransactionStart(Scheduler::TransactionStart::EarlyStart);
+ std::this_thread::sleep_for(MARGIN_FOR_TX_APPLY);
+ mVSyncModulator->onTransactionHandled();
+ EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
+ EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
+
+ for (int i = 0; i < 5 * MIN_EARLY_FRAME_COUNT_TRANSACTION; i++) {
+ mVSyncModulator->onRefreshed(false);
+ EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
+ EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
+ }
+
+ mVSyncModulator->setTransactionStart(Scheduler::TransactionStart::Early);
+ std::this_thread::sleep_for(MARGIN_FOR_TX_APPLY);
+ mVSyncModulator->onTransactionHandled();
+ EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
+ EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
+
+ for (int i = 0; i < 5 * MIN_EARLY_FRAME_COUNT_TRANSACTION; i++) {
+ mVSyncModulator->onRefreshed(false);
+ EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
+ EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
+ }
+
+ mVSyncModulator->setTransactionStart(Scheduler::TransactionStart::EarlyEnd);
+ std::this_thread::sleep_for(MARGIN_FOR_TX_APPLY);
+ mVSyncModulator->onTransactionHandled();
+ EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
+ EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
+
+ for (int i = 0; i < MIN_EARLY_FRAME_COUNT_TRANSACTION - 1; i++) {
+ mVSyncModulator->onRefreshed(false);
+ EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
+ EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
+ }
+
+ mVSyncModulator->onRefreshed(false);
+ EXPECT_EQ(APP_LATE, mMockScheduler.getOffset(mAppConnection));
+ EXPECT_EQ(SF_LATE, mMockScheduler.getOffset(mSfConnection));
+}
+
+TEST_F(VSyncModulatorTest, EarlyStartWithMoreTransactions) {
+ mVSyncModulator->setTransactionStart(Scheduler::TransactionStart::EarlyStart);
+ std::this_thread::sleep_for(MARGIN_FOR_TX_APPLY);
+ mVSyncModulator->onTransactionHandled();
+ EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
+ EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
+
+ for (int i = 0; i < 5 * MIN_EARLY_FRAME_COUNT_TRANSACTION; i++) {
+ mVSyncModulator->setTransactionStart(Scheduler::TransactionStart::Normal);
+ std::this_thread::sleep_for(MARGIN_FOR_TX_APPLY);
+ mVSyncModulator->onRefreshed(false);
+ EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
+ EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
+ }
+
+ mVSyncModulator->setTransactionStart(Scheduler::TransactionStart::EarlyEnd);
+ std::this_thread::sleep_for(MARGIN_FOR_TX_APPLY);
+ mVSyncModulator->onTransactionHandled();
+ EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
+ EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
+
+ for (int i = 0; i < MIN_EARLY_FRAME_COUNT_TRANSACTION - 1; i++) {
+ mVSyncModulator->onRefreshed(false);
+ EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
+ EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
+ }
+
+ mVSyncModulator->onRefreshed(false);
+ EXPECT_EQ(APP_LATE, mMockScheduler.getOffset(mAppConnection));
+ EXPECT_EQ(SF_LATE, mMockScheduler.getOffset(mSfConnection));
+}
+
+TEST_F(VSyncModulatorTest, EarlyStartAfterEarlyEnd) {
+ mVSyncModulator->setTransactionStart(Scheduler::TransactionStart::EarlyEnd);
+ std::this_thread::sleep_for(MARGIN_FOR_TX_APPLY);
+ mVSyncModulator->onTransactionHandled();
+ EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
+ EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
+
+ for (int i = 0; i < MIN_EARLY_FRAME_COUNT_TRANSACTION - 1; i++) {
+ mVSyncModulator->onRefreshed(false);
+ EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
+ EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
+ }
+
+ mVSyncModulator->setTransactionStart(Scheduler::TransactionStart::EarlyStart);
+ std::this_thread::sleep_for(MARGIN_FOR_TX_APPLY);
+ mVSyncModulator->onTransactionHandled();
+ EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
+ EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
+
+ for (int i = 0; i < 5 * MIN_EARLY_FRAME_COUNT_TRANSACTION; i++) {
+ mVSyncModulator->onRefreshed(false);
+ EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
+ EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
+ }
+
+ mVSyncModulator->setTransactionStart(Scheduler::TransactionStart::EarlyEnd);
+ std::this_thread::sleep_for(MARGIN_FOR_TX_APPLY);
+ mVSyncModulator->onTransactionHandled();
+ EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
+ EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
+
+ for (int i = 0; i < MIN_EARLY_FRAME_COUNT_TRANSACTION - 1; i++) {
+ mVSyncModulator->onRefreshed(false);
+ EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
+ EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
+ }
+
+ mVSyncModulator->onRefreshed(false);
+ EXPECT_EQ(APP_LATE, mMockScheduler.getOffset(mAppConnection));
+ EXPECT_EQ(SF_LATE, mMockScheduler.getOffset(mSfConnection));
+}
+
+TEST_F(VSyncModulatorTest, EarlyStartAfterEarlyEndWithMoreTransactions) {
+ mVSyncModulator->setTransactionStart(Scheduler::TransactionStart::EarlyEnd);
+ std::this_thread::sleep_for(MARGIN_FOR_TX_APPLY);
+ mVSyncModulator->onTransactionHandled();
+ EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
+ EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
+
+ for (int i = 0; i < MIN_EARLY_FRAME_COUNT_TRANSACTION - 1; i++) {
+ mVSyncModulator->onRefreshed(false);
+ EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
+ EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
+ }
+
+ mVSyncModulator->setTransactionStart(Scheduler::TransactionStart::EarlyStart);
+ std::this_thread::sleep_for(MARGIN_FOR_TX_APPLY);
+ mVSyncModulator->onTransactionHandled();
+ EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
+ EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
+
+ for (int i = 0; i < 5 * MIN_EARLY_FRAME_COUNT_TRANSACTION; i++) {
+ mVSyncModulator->setTransactionStart(Scheduler::TransactionStart::Normal);
+ std::this_thread::sleep_for(MARGIN_FOR_TX_APPLY);
+ mVSyncModulator->onRefreshed(false);
+ EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
+ EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
+ }
+
+ mVSyncModulator->setTransactionStart(Scheduler::TransactionStart::EarlyEnd);
+ std::this_thread::sleep_for(MARGIN_FOR_TX_APPLY);
+ mVSyncModulator->onTransactionHandled();
+ EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
+ EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
+
+ for (int i = 0; i < MIN_EARLY_FRAME_COUNT_TRANSACTION - 1; i++) {
+ mVSyncModulator->onRefreshed(false);
+ EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
+ EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
+ }
+
+ mVSyncModulator->onRefreshed(false);
+ EXPECT_EQ(APP_LATE, mMockScheduler.getOffset(mAppConnection));
+ EXPECT_EQ(SF_LATE, mMockScheduler.getOffset(mSfConnection));
+}
+
+} // namespace android::scheduler
diff --git a/services/vibratorservice/Android.bp b/services/vibratorservice/Android.bp
index b4342bd..e3c254d 100644
--- a/services/vibratorservice/Android.bp
+++ b/services/vibratorservice/Android.bp
@@ -16,6 +16,7 @@
name: "libvibratorservice",
srcs: [
+ "VibratorCallbackScheduler.cpp",
"VibratorHalWrapper.cpp",
],
diff --git a/services/vibratorservice/VibratorCallbackScheduler.cpp b/services/vibratorservice/VibratorCallbackScheduler.cpp
new file mode 100644
index 0000000..3f8cd67
--- /dev/null
+++ b/services/vibratorservice/VibratorCallbackScheduler.cpp
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <chrono>
+#include <thread>
+
+#include <vibratorservice/VibratorCallbackScheduler.h>
+
+namespace android {
+
+namespace vibrator {
+
+// -------------------------------------------------------------------------------------------------
+
+bool DelayedCallback::isExpired() const {
+ return mExpiration <= std::chrono::steady_clock::now();
+}
+
+DelayedCallback::Timestamp DelayedCallback::getExpiration() const {
+ return mExpiration;
+}
+
+void DelayedCallback::run() const {
+ mCallback();
+}
+
+bool DelayedCallback::operator<(const DelayedCallback& other) const {
+ return mExpiration < other.mExpiration;
+}
+
+bool DelayedCallback::operator>(const DelayedCallback& other) const {
+ return mExpiration > other.mExpiration;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+CallbackScheduler::~CallbackScheduler() {
+ {
+ std::lock_guard<std::mutex> lock(mMutex);
+ mFinished = true;
+ }
+ mCondition.notify_all();
+ if (mCallbackThread && mCallbackThread->joinable()) {
+ mCallbackThread->join();
+ }
+}
+
+void CallbackScheduler::schedule(std::function<void()> callback, std::chrono::milliseconds delay) {
+ {
+ std::lock_guard<std::mutex> lock(mMutex);
+ if (mCallbackThread == nullptr) {
+ mCallbackThread = std::make_unique<std::thread>(&CallbackScheduler::loop, this);
+ }
+ mQueue.emplace(DelayedCallback(callback, delay));
+ }
+ mCondition.notify_all();
+}
+
+void CallbackScheduler::loop() {
+ while (true) {
+ std::lock_guard<std::mutex> lock(mMutex);
+ if (mFinished) {
+ // Destructor was called, so let the callback thread die.
+ break;
+ }
+ while (!mQueue.empty() && mQueue.top().isExpired()) {
+ mQueue.top().run();
+ mQueue.pop();
+ }
+ if (mQueue.empty()) {
+ // Wait until a new callback is scheduled.
+ mCondition.wait(mMutex);
+ } else {
+ // Wait until next callback expires, or a new one is scheduled.
+ mCondition.wait_until(mMutex, mQueue.top().getExpiration());
+ }
+ }
+}
+
+// -------------------------------------------------------------------------------------------------
+
+}; // namespace vibrator
+
+}; // namespace android
diff --git a/services/vibratorservice/VibratorHalWrapper.cpp b/services/vibratorservice/VibratorHalWrapper.cpp
index db27bd9..1420bf5 100644
--- a/services/vibratorservice/VibratorHalWrapper.cpp
+++ b/services/vibratorservice/VibratorHalWrapper.cpp
@@ -23,6 +23,7 @@
#include <utils/Log.h>
+#include <vibratorservice/VibratorCallbackScheduler.h>
#include <vibratorservice/VibratorHalWrapper.h>
using android::hardware::vibrator::CompositeEffect;
@@ -46,10 +47,12 @@
template <class T>
HalResult<T> loadCached(const std::function<HalResult<T>()>& loadFn, std::optional<T>& cache) {
if (cache.has_value()) {
- return HalResult<T>::ok(cache.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;
@@ -62,27 +65,6 @@
return castEffect >= *iter.begin() && castEffect <= *std::prev(iter.end());
}
-template <class I, class T>
-using perform_fn = hardware::Return<void> (I::*)(T, V1_0::EffectStrength,
- V1_0::IVibrator::perform_cb);
-
-template <class I, class T>
-HalResult<milliseconds> perform(perform_fn<I, T> performFn, sp<I> handle, T effect,
- EffectStrength strength) {
- V1_0::Status status;
- int32_t lengthMs;
- V1_0::IVibrator::perform_cb effectCallback = [&status, &lengthMs](V1_0::Status retStatus,
- uint32_t retLengthMs) {
- status = retStatus;
- lengthMs = retLengthMs;
- };
-
- V1_0::EffectStrength effectStrength = static_cast<V1_0::EffectStrength>(strength);
- auto result = std::invoke(performFn, handle, effect, effectStrength, effectCallback);
-
- return HalResult<milliseconds>::fromReturn(result, status, milliseconds(lengthMs));
-}
-
// -------------------------------------------------------------------------------------------------
template <typename T>
@@ -179,7 +161,7 @@
class HalCallbackWrapper : public Aidl::BnVibratorCallback {
public:
- HalCallbackWrapper(const std::function<void()>& completionCallback)
+ HalCallbackWrapper(std::function<void()> completionCallback)
: mCompletionCallback(completionCallback) {}
binder::Status onComplete() override {
@@ -200,8 +182,17 @@
HalResult<void> AidlHalWrapper::on(milliseconds timeout,
const std::function<void()>& completionCallback) {
- auto cb = new HalCallbackWrapper(completionCallback);
- return HalResult<void>::fromStatus(mHandle->on(timeout.count(), cb));
+ HalResult<Capabilities> capabilities = getCapabilities();
+ bool supportsCallback = capabilities.isOk() &&
+ static_cast<int32_t>(capabilities.value() & Capabilities::ON_CALLBACK);
+ auto cb = supportsCallback ? new HalCallbackWrapper(completionCallback) : nullptr;
+
+ auto ret = HalResult<void>::fromStatus(mHandle->on(timeout.count(), cb));
+ if (!supportsCallback && ret.isOk()) {
+ mCallbackScheduler->schedule(completionCallback, timeout);
+ }
+
+ return ret;
}
HalResult<void> AidlHalWrapper::off() {
@@ -227,39 +218,56 @@
HalResult<Capabilities> AidlHalWrapper::getCapabilities() {
std::lock_guard<std::mutex> lock(mCapabilitiesMutex);
- static auto loadFn = [this]() {
- int32_t capabilities = 0;
- auto result = mHandle->getCapabilities(&capabilities);
- return HalResult<Capabilities>::fromStatus(result, static_cast<Capabilities>(capabilities));
- };
- return loadCached<Capabilities>(loadFn, mCapabilities);
+ return loadCached<Capabilities>(std::bind(&AidlHalWrapper::getCapabilitiesInternal, this),
+ mCapabilities);
}
HalResult<std::vector<Effect>> AidlHalWrapper::getSupportedEffects() {
std::lock_guard<std::mutex> lock(mSupportedEffectsMutex);
- static auto loadFn = [this]() {
- std::vector<Effect> supportedEffects;
- auto result = mHandle->getSupportedEffects(&supportedEffects);
- return HalResult<std::vector<Effect>>::fromStatus(result, supportedEffects);
- };
- return loadCached<std::vector<Effect>>(loadFn, mSupportedEffects);
+ return loadCached<std::vector<Effect>>(std::bind(&AidlHalWrapper::getSupportedEffectsInternal,
+ this),
+ mSupportedEffects);
}
HalResult<milliseconds> AidlHalWrapper::performEffect(
Effect effect, EffectStrength strength, const std::function<void()>& completionCallback) {
+ HalResult<Capabilities> capabilities = getCapabilities();
+ bool supportsCallback = capabilities.isOk() &&
+ static_cast<int32_t>(capabilities.value() & Capabilities::PERFORM_CALLBACK);
+ auto cb = supportsCallback ? new HalCallbackWrapper(completionCallback) : nullptr;
+
int32_t lengthMs;
- auto cb = new HalCallbackWrapper(completionCallback);
auto result = mHandle->perform(effect, strength, cb, &lengthMs);
- return HalResult<milliseconds>::fromStatus(result, milliseconds(lengthMs));
+ milliseconds length = milliseconds(lengthMs);
+
+ auto ret = HalResult<milliseconds>::fromStatus(result, length);
+ if (!supportsCallback && ret.isOk()) {
+ mCallbackScheduler->schedule(completionCallback, length);
+ }
+
+ return ret;
}
HalResult<void> AidlHalWrapper::performComposedEffect(
const std::vector<CompositeEffect>& primitiveEffects,
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(mHandle->compose(primitiveEffects, cb));
}
+HalResult<Capabilities> AidlHalWrapper::getCapabilitiesInternal() {
+ int32_t capabilities = 0;
+ auto result = mHandle->getCapabilities(&capabilities);
+ return HalResult<Capabilities>::fromStatus(result, static_cast<Capabilities>(capabilities));
+}
+
+HalResult<std::vector<Effect>> AidlHalWrapper::getSupportedEffectsInternal() {
+ std::vector<Effect> supportedEffects;
+ auto result = mHandle->getSupportedEffects(&supportedEffects);
+ return HalResult<std::vector<Effect>>::fromStatus(result, supportedEffects);
+}
+
// -------------------------------------------------------------------------------------------------
HalResult<void> HidlHalWrapperV1_0::ping() {
@@ -267,10 +275,14 @@
return HalResult<void>::fromReturn(result);
}
-HalResult<void> HidlHalWrapperV1_0::on(milliseconds timeout, const std::function<void()>&) {
+HalResult<void> HidlHalWrapperV1_0::on(milliseconds timeout,
+ const std::function<void()>& completionCallback) {
auto result = mHandleV1_0->on(timeout.count());
- auto status = result.withDefault(V1_0::Status::UNKNOWN_ERROR);
- return HalResult<void>::fromStatus(status);
+ auto ret = HalResult<void>::fromStatus(result.withDefault(V1_0::Status::UNKNOWN_ERROR));
+ if (ret.isOk()) {
+ mCallbackScheduler->schedule(completionCallback, timeout);
+ }
+ return ret;
}
HalResult<void> HidlHalWrapperV1_0::off() {
@@ -309,11 +321,10 @@
return HalResult<std::vector<Effect>>::unsupported();
}
-HalResult<milliseconds> HidlHalWrapperV1_0::performEffect(Effect effect, EffectStrength strength,
- const std::function<void()>&) {
+HalResult<milliseconds> HidlHalWrapperV1_0::performEffect(
+ Effect effect, EffectStrength strength, const std::function<void()>& completionCallback) {
if (isStaticCastValid<V1_0::Effect>(effect)) {
- V1_0::Effect e = static_cast<V1_0::Effect>(effect);
- return perform(&V1_0::IVibrator::perform, mHandleV1_0, e, strength);
+ return performInternalV1_0(effect, strength, completionCallback);
}
ALOGV("Skipped performEffect because Vibrator HAL does not support effect %s",
@@ -334,17 +345,44 @@
return HalResult<Capabilities>::fromReturn(result, capabilities);
}
+template <class I, class T>
+HalResult<milliseconds> HidlHalWrapperV1_0::performInternal(
+ perform_fn<I, T> performFn, sp<I> handle, T effect, EffectStrength strength,
+ const std::function<void()>& completionCallback) {
+ V1_0::Status status;
+ int32_t lengthMs;
+ auto effectCallback = [&status, &lengthMs](V1_0::Status retStatus, uint32_t retLengthMs) {
+ status = retStatus;
+ lengthMs = retLengthMs;
+ };
+
+ V1_0::EffectStrength effectStrength = static_cast<V1_0::EffectStrength>(strength);
+ auto result = std::invoke(performFn, handle, effect, effectStrength, effectCallback);
+ milliseconds length = milliseconds(lengthMs);
+
+ auto ret = HalResult<milliseconds>::fromReturn(result, status, length);
+ if (ret.isOk()) {
+ mCallbackScheduler->schedule(completionCallback, length);
+ }
+
+ return ret;
+}
+
+HalResult<milliseconds> HidlHalWrapperV1_0::performInternalV1_0(
+ Effect effect, EffectStrength strength, const std::function<void()>& completionCallback) {
+ V1_0::Effect e = static_cast<V1_0::Effect>(effect);
+ return performInternal(&V1_0::IVibrator::perform, mHandleV1_0, e, strength, completionCallback);
+}
+
// -------------------------------------------------------------------------------------------------
-HalResult<milliseconds> HidlHalWrapperV1_1::performEffect(Effect effect, EffectStrength strength,
- const std::function<void()>&) {
+HalResult<milliseconds> HidlHalWrapperV1_1::performEffect(
+ Effect effect, EffectStrength strength, const std::function<void()>& completionCallback) {
if (isStaticCastValid<V1_0::Effect>(effect)) {
- V1_0::Effect e = static_cast<V1_0::Effect>(effect);
- return perform(&V1_0::IVibrator::perform, mHandleV1_0, e, strength);
+ return performInternalV1_0(effect, strength, completionCallback);
}
if (isStaticCastValid<V1_1::Effect_1_1>(effect)) {
- V1_1::Effect_1_1 e = static_cast<V1_1::Effect_1_1>(effect);
- return perform(&V1_1::IVibrator::perform_1_1, mHandleV1_1, e, strength);
+ return performInternalV1_1(effect, strength, completionCallback);
}
ALOGV("Skipped performEffect because Vibrator HAL does not support effect %s",
@@ -352,21 +390,25 @@
return HalResult<milliseconds>::unsupported();
}
+HalResult<milliseconds> HidlHalWrapperV1_1::performInternalV1_1(
+ Effect effect, EffectStrength strength, const std::function<void()>& completionCallback) {
+ V1_1::Effect_1_1 e = static_cast<V1_1::Effect_1_1>(effect);
+ return performInternal(&V1_1::IVibrator::perform_1_1, mHandleV1_1, e, strength,
+ completionCallback);
+}
+
// -------------------------------------------------------------------------------------------------
-HalResult<milliseconds> HidlHalWrapperV1_2::performEffect(Effect effect, EffectStrength strength,
- const std::function<void()>&) {
+HalResult<milliseconds> HidlHalWrapperV1_2::performEffect(
+ Effect effect, EffectStrength strength, const std::function<void()>& completionCallback) {
if (isStaticCastValid<V1_0::Effect>(effect)) {
- V1_0::Effect e = static_cast<V1_0::Effect>(effect);
- return perform(&V1_0::IVibrator::perform, mHandleV1_0, e, strength);
+ return performInternalV1_0(effect, strength, completionCallback);
}
if (isStaticCastValid<V1_1::Effect_1_1>(effect)) {
- V1_1::Effect_1_1 e = static_cast<V1_1::Effect_1_1>(effect);
- return perform(&V1_1::IVibrator::perform_1_1, mHandleV1_1, e, strength);
+ return performInternalV1_1(effect, strength, completionCallback);
}
if (isStaticCastValid<V1_2::Effect>(effect)) {
- V1_2::Effect e = static_cast<V1_2::Effect>(effect);
- return perform(&V1_2::IVibrator::perform_1_2, mHandleV1_2, e, strength);
+ return performInternalV1_2(effect, strength, completionCallback);
}
ALOGV("Skipped performEffect because Vibrator HAL does not support effect %s",
@@ -374,6 +416,13 @@
return HalResult<milliseconds>::unsupported();
}
+HalResult<milliseconds> HidlHalWrapperV1_2::performInternalV1_2(
+ Effect effect, EffectStrength strength, const std::function<void()>& completionCallback) {
+ V1_2::Effect e = static_cast<V1_2::Effect>(effect);
+ return performInternal(&V1_2::IVibrator::perform_1_2, mHandleV1_2, e, strength,
+ completionCallback);
+}
+
// -------------------------------------------------------------------------------------------------
HalResult<void> HidlHalWrapperV1_3::setExternalControl(bool enabled) {
@@ -381,23 +430,19 @@
return HalResult<void>::fromStatus(result.withDefault(V1_0::Status::UNKNOWN_ERROR));
}
-HalResult<milliseconds> HidlHalWrapperV1_3::performEffect(Effect effect, EffectStrength strength,
- const std::function<void()>&) {
+HalResult<milliseconds> HidlHalWrapperV1_3::performEffect(
+ Effect effect, EffectStrength strength, const std::function<void()>& completionCallback) {
if (isStaticCastValid<V1_0::Effect>(effect)) {
- V1_0::Effect e = static_cast<V1_0::Effect>(effect);
- return perform(&V1_0::IVibrator::perform, mHandleV1_0, e, strength);
+ return performInternalV1_0(effect, strength, completionCallback);
}
if (isStaticCastValid<V1_1::Effect_1_1>(effect)) {
- V1_1::Effect_1_1 e = static_cast<V1_1::Effect_1_1>(effect);
- return perform(&V1_1::IVibrator::perform_1_1, mHandleV1_1, e, strength);
+ return performInternalV1_1(effect, strength, completionCallback);
}
if (isStaticCastValid<V1_2::Effect>(effect)) {
- V1_2::Effect e = static_cast<V1_2::Effect>(effect);
- return perform(&V1_2::IVibrator::perform_1_2, mHandleV1_2, e, strength);
+ return performInternalV1_2(effect, strength, completionCallback);
}
if (isStaticCastValid<V1_3::Effect>(effect)) {
- V1_3::Effect e = static_cast<V1_3::Effect>(effect);
- return perform(&V1_3::IVibrator::perform_1_3, mHandleV1_3, e, strength);
+ return performInternalV1_3(effect, strength, completionCallback);
}
ALOGV("Skipped performEffect because Vibrator HAL does not support effect %s",
@@ -418,6 +463,13 @@
return HalResult<Capabilities>::fromReturn(result, capabilities);
}
+HalResult<milliseconds> HidlHalWrapperV1_3::performInternalV1_3(
+ Effect effect, EffectStrength strength, const std::function<void()>& completionCallback) {
+ V1_3::Effect e = static_cast<V1_3::Effect>(effect);
+ return performInternal(&V1_3::IVibrator::perform_1_3, mHandleV1_3, e, strength,
+ completionCallback);
+}
+
// -------------------------------------------------------------------------------------------------
}; // namespace vibrator
diff --git a/services/vibratorservice/include/vibratorservice/VibratorCallbackScheduler.h b/services/vibratorservice/include/vibratorservice/VibratorCallbackScheduler.h
new file mode 100644
index 0000000..2c194b5
--- /dev/null
+++ b/services/vibratorservice/include/vibratorservice/VibratorCallbackScheduler.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_VIBRATOR_CALLBACK_SCHEDULER_H
+#define ANDROID_VIBRATOR_CALLBACK_SCHEDULER_H
+
+#include <android-base/thread_annotations.h>
+#include <chrono>
+#include <condition_variable>
+#include <queue>
+#include <thread>
+
+namespace android {
+
+namespace vibrator {
+
+// Wrapper for a callback to be executed after a delay.
+class DelayedCallback {
+public:
+ using Timestamp = std::chrono::time_point<std::chrono::steady_clock>;
+
+ DelayedCallback(std::function<void()> callback, std::chrono::milliseconds delay)
+ : mCallback(callback), mExpiration(std::chrono::steady_clock::now() + delay) {}
+ ~DelayedCallback() = default;
+
+ void run() const;
+ bool isExpired() const;
+ Timestamp getExpiration() const;
+
+ // Compare by expiration time, where A < B when A expires first.
+ bool operator<(const DelayedCallback& other) const;
+ bool operator>(const DelayedCallback& other) const;
+
+private:
+ std::function<void()> mCallback;
+ Timestamp mExpiration;
+};
+
+// Schedules callbacks to be executed after a delay.
+class CallbackScheduler {
+public:
+ CallbackScheduler() : mCallbackThread(nullptr), mFinished(false) {}
+ virtual ~CallbackScheduler();
+
+ virtual void schedule(std::function<void()> callback, std::chrono::milliseconds delay);
+
+private:
+ std::condition_variable_any mCondition;
+ std::mutex mMutex;
+
+ // Lazily instantiated only at the first time this scheduler is used.
+ std::unique_ptr<std::thread> mCallbackThread;
+
+ // Used to quit the callback thread when this instance is being destroyed.
+ bool mFinished GUARDED_BY(mMutex);
+
+ // Priority queue with reverse comparator, so tasks that expire first will be on top.
+ std::priority_queue<DelayedCallback, std::vector<DelayedCallback>,
+ std::greater<DelayedCallback>>
+ mQueue GUARDED_BY(mMutex);
+
+ void loop();
+};
+
+}; // namespace vibrator
+
+}; // namespace android
+
+#endif // ANDROID_VIBRATOR_CALLBACK_SCHEDULER_H
diff --git a/services/vibratorservice/include/vibratorservice/VibratorHalWrapper.h b/services/vibratorservice/include/vibratorservice/VibratorHalWrapper.h
index 1a1f64b..0f9aacb 100644
--- a/services/vibratorservice/include/vibratorservice/VibratorHalWrapper.h
+++ b/services/vibratorservice/include/vibratorservice/VibratorHalWrapper.h
@@ -21,6 +21,8 @@
#include <android/hardware/vibrator/1.3/IVibrator.h>
#include <android/hardware/vibrator/IVibrator.h>
+#include <vibratorservice/VibratorCallbackScheduler.h>
+
namespace android {
namespace vibrator {
@@ -46,7 +48,7 @@
hardware::vibrator::V1_0::Status status, T data);
// This will throw std::bad_optional_access if this result is not ok.
- T value() const { return mValue.value(); }
+ const T& value() const { return mValue.value(); }
bool isOk() const { return !mUnsupported && mValue.has_value(); }
bool isFailed() const { return !mUnsupported && !mValue.has_value(); }
bool isUnsupported() const { return mUnsupported; }
@@ -122,6 +124,8 @@
// Wrapper for Vibrator HAL handlers.
class HalWrapper {
public:
+ explicit HalWrapper(std::shared_ptr<CallbackScheduler> scheduler)
+ : mCallbackScheduler(std::move(scheduler)) {}
virtual ~HalWrapper() = default;
virtual HalResult<void> ping() = 0;
@@ -147,13 +151,19 @@
virtual HalResult<void> performComposedEffect(
const std::vector<hardware::vibrator::CompositeEffect>& primitiveEffects,
const std::function<void()>& completionCallback) = 0;
+
+protected:
+ // Shared pointer to allow CallbackScheduler to outlive this wrapper.
+ const std::shared_ptr<CallbackScheduler> mCallbackScheduler;
};
// Wrapper for the AIDL Vibrator HAL.
class AidlHalWrapper : public HalWrapper {
public:
- explicit AidlHalWrapper(sp<hardware::vibrator::IVibrator> handle)
- : mHandle(std::move(handle)) {}
+ AidlHalWrapper(std::shared_ptr<CallbackScheduler> scheduler,
+ sp<hardware::vibrator::IVibrator> handle)
+ : HalWrapper(std::move(scheduler)), mHandle(std::move(handle)) {}
+ virtual ~AidlHalWrapper() = default;
virtual HalResult<void> ping() override;
@@ -186,13 +196,19 @@
std::optional<Capabilities> mCapabilities GUARDED_BY(mCapabilitiesMutex);
std::optional<std::vector<hardware::vibrator::Effect>> mSupportedEffects
GUARDED_BY(mSupportedEffectsMutex);
+
+ // Loads directly from IVibrator handle, skipping caches.
+ HalResult<Capabilities> getCapabilitiesInternal();
+ HalResult<std::vector<hardware::vibrator::Effect>> getSupportedEffectsInternal();
};
// Wrapper for the HDIL Vibrator HAL v1.0.
class HidlHalWrapperV1_0 : public HalWrapper {
public:
- explicit HidlHalWrapperV1_0(sp<hardware::vibrator::V1_0::IVibrator> handle)
- : mHandleV1_0(std::move(handle)) {}
+ HidlHalWrapperV1_0(std::shared_ptr<CallbackScheduler> scheduler,
+ sp<hardware::vibrator::V1_0::IVibrator> handle)
+ : HalWrapper(std::move(scheduler)), mHandleV1_0(std::move(handle)) {}
+ virtual ~HidlHalWrapperV1_0() = default;
virtual HalResult<void> ping() override;
@@ -225,14 +241,31 @@
// Loads directly from IVibrator handle, skipping the mCapabilities cache.
virtual HalResult<Capabilities> getCapabilitiesInternal();
+
+ template <class I, class T>
+ using perform_fn =
+ hardware::Return<void> (I::*)(T, hardware::vibrator::V1_0::EffectStrength,
+ hardware::vibrator::V1_0::IVibrator::perform_cb);
+
+ template <class I, class T>
+ HalResult<std::chrono::milliseconds> performInternal(
+ perform_fn<I, T> performFn, sp<I> handle, T effect,
+ hardware::vibrator::EffectStrength strength,
+ const std::function<void()>& completionCallback);
+
+ HalResult<std::chrono::milliseconds> performInternalV1_0(
+ hardware::vibrator::Effect effect, hardware::vibrator::EffectStrength strength,
+ const std::function<void()>& completionCallback);
};
// Wrapper for the HDIL Vibrator HAL v1.1.
class HidlHalWrapperV1_1 : public HidlHalWrapperV1_0 {
public:
- explicit HidlHalWrapperV1_1(sp<hardware::vibrator::V1_0::IVibrator> handleV1_0)
- : HidlHalWrapperV1_0(handleV1_0),
+ HidlHalWrapperV1_1(std::shared_ptr<CallbackScheduler> scheduler,
+ sp<hardware::vibrator::V1_0::IVibrator> handleV1_0)
+ : HidlHalWrapperV1_0(std::move(scheduler), handleV1_0),
mHandleV1_1(hardware::vibrator::V1_1::IVibrator::castFrom(handleV1_0)) {}
+ virtual ~HidlHalWrapperV1_1() = default;
virtual HalResult<std::chrono::milliseconds> performEffect(
hardware::vibrator::Effect effect, hardware::vibrator::EffectStrength strength,
@@ -240,14 +273,20 @@
protected:
const sp<hardware::vibrator::V1_1::IVibrator> mHandleV1_1;
+
+ HalResult<std::chrono::milliseconds> performInternalV1_1(
+ hardware::vibrator::Effect effect, hardware::vibrator::EffectStrength strength,
+ const std::function<void()>& completionCallback);
};
// Wrapper for the HDIL Vibrator HAL v1.2.
class HidlHalWrapperV1_2 : public HidlHalWrapperV1_1 {
public:
- explicit HidlHalWrapperV1_2(sp<hardware::vibrator::V1_0::IVibrator> handleV1_0)
- : HidlHalWrapperV1_1(handleV1_0),
+ HidlHalWrapperV1_2(std::shared_ptr<CallbackScheduler> scheduler,
+ sp<hardware::vibrator::V1_0::IVibrator> handleV1_0)
+ : HidlHalWrapperV1_1(std::move(scheduler), handleV1_0),
mHandleV1_2(hardware::vibrator::V1_2::IVibrator::castFrom(handleV1_0)) {}
+ virtual ~HidlHalWrapperV1_2() = default;
virtual HalResult<std::chrono::milliseconds> performEffect(
hardware::vibrator::Effect effect, hardware::vibrator::EffectStrength strength,
@@ -255,14 +294,20 @@
protected:
const sp<hardware::vibrator::V1_2::IVibrator> mHandleV1_2;
+
+ HalResult<std::chrono::milliseconds> performInternalV1_2(
+ hardware::vibrator::Effect effect, hardware::vibrator::EffectStrength strength,
+ const std::function<void()>& completionCallback);
};
// Wrapper for the HDIL Vibrator HAL v1.3.
class HidlHalWrapperV1_3 : public HidlHalWrapperV1_2 {
public:
- explicit HidlHalWrapperV1_3(sp<hardware::vibrator::V1_0::IVibrator> handleV1_0)
- : HidlHalWrapperV1_2(handleV1_0),
+ HidlHalWrapperV1_3(std::shared_ptr<CallbackScheduler> scheduler,
+ sp<hardware::vibrator::V1_0::IVibrator> handleV1_0)
+ : HidlHalWrapperV1_2(std::move(scheduler), handleV1_0),
mHandleV1_3(hardware::vibrator::V1_3::IVibrator::castFrom(handleV1_0)) {}
+ virtual ~HidlHalWrapperV1_3() = default;
virtual HalResult<void> setExternalControl(bool enabled) override;
@@ -274,6 +319,9 @@
const sp<hardware::vibrator::V1_3::IVibrator> mHandleV1_3;
virtual HalResult<Capabilities> getCapabilitiesInternal() override;
+ HalResult<std::chrono::milliseconds> performInternalV1_3(
+ hardware::vibrator::Effect effect, hardware::vibrator::EffectStrength strength,
+ const std::function<void()>& completionCallback);
};
// -------------------------------------------------------------------------------------------------
diff --git a/services/vibratorservice/test/Android.bp b/services/vibratorservice/test/Android.bp
index 7c038e9..fa399ad 100644
--- a/services/vibratorservice/test/Android.bp
+++ b/services/vibratorservice/test/Android.bp
@@ -16,6 +16,7 @@
name: "libvibratorservice_test",
test_suites: ["device-tests"],
srcs: [
+ "VibratorCallbackSchedulerTest.cpp",
"VibratorHalWrapperAidlTest.cpp",
"VibratorHalWrapperHidlV1_0Test.cpp",
"VibratorHalWrapperHidlV1_1Test.cpp",
diff --git a/services/vibratorservice/test/VibratorCallbackSchedulerTest.cpp b/services/vibratorservice/test/VibratorCallbackSchedulerTest.cpp
new file mode 100644
index 0000000..aaeb8f9
--- /dev/null
+++ b/services/vibratorservice/test/VibratorCallbackSchedulerTest.cpp
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "VibratorHalWrapperAidlTest"
+
+#include <android-base/thread_annotations.h>
+#include <android/hardware/vibrator/IVibrator.h>
+#include <condition_variable>
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include <utils/Log.h>
+#include <thread>
+
+#include <vibratorservice/VibratorCallbackScheduler.h>
+
+using std::chrono::milliseconds;
+using std::chrono::steady_clock;
+using std::chrono::time_point;
+
+using namespace android;
+using namespace std::chrono_literals;
+using namespace testing;
+
+// -------------------------------------------------------------------------------------------------
+
+class VibratorCallbackSchedulerTest : public Test {
+public:
+ void SetUp() override {
+ mScheduler = std::make_unique<vibrator::CallbackScheduler>();
+ std::lock_guard<std::mutex> lock(mMutex);
+ mExpiredCallbacks.clear();
+ }
+
+protected:
+ std::mutex mMutex;
+ std::condition_variable_any mCondition;
+ std::unique_ptr<vibrator::CallbackScheduler> mScheduler = nullptr;
+ std::vector<int32_t> mExpiredCallbacks GUARDED_BY(mMutex);
+
+ std::function<void()> createCallback(int32_t id) {
+ return [=]() {
+ {
+ std::lock_guard<std::mutex> lock(mMutex);
+ mExpiredCallbacks.push_back(id);
+ }
+ mCondition.notify_all();
+ };
+ }
+
+ std::vector<int32_t> getExpiredCallbacks() {
+ std::lock_guard<std::mutex> lock(mMutex);
+ return std::vector<int32_t>(mExpiredCallbacks);
+ }
+
+ bool waitForCallbacks(uint32_t callbackCount, milliseconds timeout) {
+ time_point<steady_clock> expiration = steady_clock::now() + timeout;
+ while (steady_clock::now() < expiration) {
+ std::lock_guard<std::mutex> lock(mMutex);
+ if (callbackCount <= mExpiredCallbacks.size()) {
+ return true;
+ }
+ mCondition.wait_until(mMutex, expiration);
+ }
+ return false;
+ }
+};
+
+// -------------------------------------------------------------------------------------------------
+
+TEST_F(VibratorCallbackSchedulerTest, TestScheduleRunsOnlyAfterDelay) {
+ mScheduler->schedule(createCallback(1), 15ms);
+
+ // Not triggered before delay.
+ ASSERT_FALSE(waitForCallbacks(1, 10ms));
+ ASSERT_TRUE(getExpiredCallbacks().empty());
+
+ ASSERT_TRUE(waitForCallbacks(1, 10ms));
+ ASSERT_THAT(getExpiredCallbacks(), ElementsAre(1));
+}
+
+TEST_F(VibratorCallbackSchedulerTest, TestScheduleMultipleCallbacksRunsInDelayOrder) {
+ mScheduler->schedule(createCallback(1), 10ms);
+ mScheduler->schedule(createCallback(2), 5ms);
+ mScheduler->schedule(createCallback(3), 1ms);
+
+ ASSERT_TRUE(waitForCallbacks(3, 15ms));
+ ASSERT_THAT(getExpiredCallbacks(), ElementsAre(3, 2, 1));
+}
+
+TEST_F(VibratorCallbackSchedulerTest, TestScheduleInParallelRunsInDelayOrder) {
+ std::vector<std::thread> threads;
+ for (int i = 0; i < 5; i++) {
+ threads.push_back(std::thread(
+ [=]() { mScheduler->schedule(createCallback(i), milliseconds(10 + 2 * i)); }));
+ }
+ std::for_each(threads.begin(), threads.end(), [](std::thread& t) { t.join(); });
+
+ ASSERT_TRUE(waitForCallbacks(5, 25ms));
+ ASSERT_THAT(getExpiredCallbacks(), ElementsAre(0, 1, 2, 3, 4));
+}
+
+TEST_F(VibratorCallbackSchedulerTest, TestDestructorDropsPendingCallbacksAndKillsThread) {
+ mScheduler->schedule(createCallback(1), 5ms);
+ mScheduler.reset(nullptr);
+
+ // Should time out waiting for callback to run.
+ ASSERT_FALSE(waitForCallbacks(1, 10ms));
+ ASSERT_TRUE(getExpiredCallbacks().empty());
+}
diff --git a/services/vibratorservice/test/VibratorHalWrapperAidlTest.cpp b/services/vibratorservice/test/VibratorHalWrapperAidlTest.cpp
index 6db449a..0f2d7bc 100644
--- a/services/vibratorservice/test/VibratorHalWrapperAidlTest.cpp
+++ b/services/vibratorservice/test/VibratorHalWrapperAidlTest.cpp
@@ -24,6 +24,7 @@
#include <utils/Log.h>
#include <thread>
+#include <vibratorservice/VibratorCallbackScheduler.h>
#include <vibratorservice/VibratorHalWrapper.h>
#include "test_utils.h"
@@ -88,11 +89,13 @@
void SetUp() override {
mMockBinder = new StrictMock<MockBinder>();
mMockHal = new StrictMock<MockIVibrator>();
- mWrapper = std::make_unique<vibrator::AidlHalWrapper>(mMockHal);
+ mMockScheduler = std::make_shared<StrictMock<vibrator::MockCallbackScheduler>>();
+ mWrapper = std::make_unique<vibrator::AidlHalWrapper>(mMockScheduler, mMockHal);
ASSERT_NE(mWrapper, nullptr);
}
protected:
+ std::shared_ptr<StrictMock<vibrator::MockCallbackScheduler>> mMockScheduler = nullptr;
std::unique_ptr<vibrator::HalWrapper> mWrapper = nullptr;
sp<StrictMock<MockIVibrator>> mMockHal = nullptr;
sp<StrictMock<MockBinder>> mMockBinder = nullptr;
@@ -124,9 +127,13 @@
ASSERT_TRUE(mWrapper->ping().isFailed());
}
-TEST_F(VibratorHalWrapperAidlTest, TestOn) {
+TEST_F(VibratorHalWrapperAidlTest, TestOnWithCallbackSupport) {
{
InSequence seq;
+ EXPECT_CALL(*mMockHal.get(), getCapabilities(_))
+ .Times(Exactly(1))
+ .WillRepeatedly(
+ DoAll(SetArgPointee<0>(IVibrator::CAP_ON_CALLBACK), Return(Status())));
EXPECT_CALL(*mMockHal.get(), on(Eq(10), _))
.Times(Exactly(1))
.WillRepeatedly(DoAll(TriggerCallbackInArg1(), Return(Status())));
@@ -146,11 +153,46 @@
ASSERT_EQ(1, *callbackCounter.get());
ASSERT_TRUE(mWrapper->on(100ms, callback).isUnsupported());
- // Callback not triggered
+ // Callback not triggered for unsupported
ASSERT_EQ(1, *callbackCounter.get());
ASSERT_TRUE(mWrapper->on(1000ms, callback).isFailed());
- // Callback not triggered
+ // Callback not triggered on failure
+ ASSERT_EQ(1, *callbackCounter.get());
+}
+
+TEST_F(VibratorHalWrapperAidlTest, TestOnWithoutCallbackSupport) {
+ {
+ InSequence seq;
+ EXPECT_CALL(*mMockHal.get(), getCapabilities(_))
+ .Times(Exactly(1))
+ .WillRepeatedly(
+ DoAll(SetArgPointee<0>(IVibrator::CAP_COMPOSE_EFFECTS), Return(Status())));
+ EXPECT_CALL(*mMockHal.get(), on(Eq(10), _))
+ .Times(Exactly(1))
+ .WillRepeatedly(Return(Status()));
+ EXPECT_CALL(*mMockScheduler.get(), schedule(_, Eq(10ms)))
+ .Times(Exactly(1))
+ .WillRepeatedly(vibrator::TriggerSchedulerCallback());
+ EXPECT_CALL(*mMockHal.get(), on(Eq(11), _))
+ .Times(Exactly(1))
+ .WillRepeatedly(Return(
+ Status::fromExceptionCode(Status::Exception::EX_UNSUPPORTED_OPERATION)));
+ EXPECT_CALL(*mMockHal.get(), on(Eq(12), _))
+ .Times(Exactly(1))
+ .WillRepeatedly(Return(Status::fromExceptionCode(Status::Exception::EX_SECURITY)));
+ }
+
+ std::unique_ptr<int32_t> callbackCounter = std::make_unique<int32_t>();
+ auto callback = vibrator::TestFactory::createCountingCallback(callbackCounter.get());
+
+ ASSERT_TRUE(mWrapper->on(10ms, callback).isOk());
+ ASSERT_EQ(1, *callbackCounter.get());
+
+ ASSERT_TRUE(mWrapper->on(11ms, callback).isUnsupported());
+ ASSERT_TRUE(mWrapper->on(12ms, callback).isFailed());
+
+ // Callback not triggered for unsupported and on failure
ASSERT_EQ(1, *callbackCounter.get());
}
@@ -274,6 +316,10 @@
}));
}
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) {
@@ -314,11 +360,19 @@
}));
}
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, TestPerformEffect) {
+TEST_F(VibratorHalWrapperAidlTest, TestPerformEffectWithCallbackSupport) {
{
InSequence seq;
+ EXPECT_CALL(*mMockHal.get(), getCapabilities(_))
+ .Times(Exactly(1))
+ .WillRepeatedly(
+ DoAll(SetArgPointee<0>(IVibrator::CAP_PERFORM_CALLBACK), Return(Status())));
EXPECT_CALL(*mMockHal.get(), perform(Eq(Effect::CLICK), Eq(EffectStrength::LIGHT), _, _))
.Times(Exactly(1))
.WillRepeatedly(
@@ -342,12 +396,52 @@
result = mWrapper->performEffect(Effect::POP, EffectStrength::MEDIUM, callback);
ASSERT_TRUE(result.isUnsupported());
- // Callback not triggered
+ // Callback not triggered for unsupported
ASSERT_EQ(1, *callbackCounter.get());
result = mWrapper->performEffect(Effect::THUD, EffectStrength::STRONG, callback);
ASSERT_TRUE(result.isFailed());
- // Callback not triggered
+ // Callback not triggered on failure
+ ASSERT_EQ(1, *callbackCounter.get());
+}
+
+TEST_F(VibratorHalWrapperAidlTest, TestPerformEffectWithoutCallbackSupport) {
+ {
+ InSequence seq;
+ EXPECT_CALL(*mMockHal.get(), getCapabilities(_))
+ .Times(Exactly(1))
+ .WillRepeatedly(
+ DoAll(SetArgPointee<0>(IVibrator::CAP_ON_CALLBACK), Return(Status())));
+ EXPECT_CALL(*mMockHal.get(), perform(Eq(Effect::CLICK), Eq(EffectStrength::LIGHT), _, _))
+ .Times(Exactly(1))
+ .WillRepeatedly(DoAll(SetArgPointee<3>(10), Return(Status())));
+ EXPECT_CALL(*mMockScheduler.get(), schedule(_, Eq(10ms)))
+ .Times(Exactly(1))
+ .WillRepeatedly(vibrator::TriggerSchedulerCallback());
+ EXPECT_CALL(*mMockHal.get(), perform(Eq(Effect::POP), Eq(EffectStrength::MEDIUM), _, _))
+ .Times(Exactly(1))
+ .WillRepeatedly(Return(
+ Status::fromExceptionCode(Status::Exception::EX_UNSUPPORTED_OPERATION)));
+ EXPECT_CALL(*mMockHal.get(), perform(Eq(Effect::THUD), Eq(EffectStrength::STRONG), _, _))
+ .Times(Exactly(1))
+ .WillRepeatedly(Return(Status::fromExceptionCode(Status::Exception::EX_SECURITY)));
+ }
+
+ std::unique_ptr<int32_t> callbackCounter = std::make_unique<int32_t>();
+ auto callback = vibrator::TestFactory::createCountingCallback(callbackCounter.get());
+
+ auto result = mWrapper->performEffect(Effect::CLICK, EffectStrength::LIGHT, callback);
+ ASSERT_TRUE(result.isOk());
+ ASSERT_EQ(10ms, result.value());
+ ASSERT_EQ(1, *callbackCounter.get());
+
+ result = mWrapper->performEffect(Effect::POP, EffectStrength::MEDIUM, callback);
+ ASSERT_TRUE(result.isUnsupported());
+
+ result = mWrapper->performEffect(Effect::THUD, EffectStrength::STRONG, callback);
+ ASSERT_TRUE(result.isFailed());
+
+ // Callback not triggered for unsupported and on failure
ASSERT_EQ(1, *callbackCounter.get());
}
@@ -383,11 +477,11 @@
result = mWrapper->performComposedEffect(singleEffect, callback);
ASSERT_TRUE(result.isUnsupported());
- // Callback not triggered
+ // Callback not triggered for unsupported
ASSERT_EQ(1, *callbackCounter.get());
result = mWrapper->performComposedEffect(multipleEffects, callback);
ASSERT_TRUE(result.isFailed());
- // Callback not triggered
+ // Callback not triggered on failure
ASSERT_EQ(1, *callbackCounter.get());
}
diff --git a/services/vibratorservice/test/VibratorHalWrapperHidlV1_0Test.cpp b/services/vibratorservice/test/VibratorHalWrapperHidlV1_0Test.cpp
index 7f1016f..7eb4059 100644
--- a/services/vibratorservice/test/VibratorHalWrapperHidlV1_0Test.cpp
+++ b/services/vibratorservice/test/VibratorHalWrapperHidlV1_0Test.cpp
@@ -24,6 +24,7 @@
#include <utils/Log.h>
#include <thread>
+#include <vibratorservice/VibratorCallbackScheduler.h>
#include <vibratorservice/VibratorHalWrapper.h>
#include "test_utils.h"
@@ -59,11 +60,13 @@
public:
void SetUp() override {
mMockHal = new StrictMock<MockIVibratorV1_0>();
- mWrapper = std::make_unique<vibrator::HidlHalWrapperV1_0>(mMockHal);
+ mMockScheduler = std::make_shared<StrictMock<vibrator::MockCallbackScheduler>>();
+ mWrapper = std::make_unique<vibrator::HidlHalWrapperV1_0>(mMockScheduler, mMockHal);
ASSERT_NE(mWrapper, nullptr);
}
protected:
+ std::shared_ptr<StrictMock<vibrator::MockCallbackScheduler>> mMockScheduler = nullptr;
std::unique_ptr<vibrator::HalWrapper> mWrapper = nullptr;
sp<StrictMock<MockIVibratorV1_0>> mMockHal = nullptr;
};
@@ -89,17 +92,20 @@
.Times(Exactly(1))
.WillRepeatedly(
[](uint32_t) { return hardware::Return<V1_0::Status>(V1_0::Status::OK); });
+ EXPECT_CALL(*mMockScheduler.get(), schedule(_, Eq(1ms)))
+ .Times(Exactly(1))
+ .WillRepeatedly(vibrator::TriggerSchedulerCallback());
EXPECT_CALL(*mMockHal.get(), on(Eq(static_cast<uint32_t>(10))))
.Times(Exactly(1))
.WillRepeatedly([](uint32_t) {
return hardware::Return<V1_0::Status>(V1_0::Status::UNSUPPORTED_OPERATION);
});
- EXPECT_CALL(*mMockHal.get(), on(Eq(static_cast<uint32_t>(100))))
+ EXPECT_CALL(*mMockHal.get(), on(Eq(static_cast<uint32_t>(11))))
.Times(Exactly(1))
.WillRepeatedly([](uint32_t) {
return hardware::Return<V1_0::Status>(V1_0::Status::BAD_VALUE);
});
- EXPECT_CALL(*mMockHal.get(), on(Eq(static_cast<uint32_t>(1000))))
+ EXPECT_CALL(*mMockHal.get(), on(Eq(static_cast<uint32_t>(12))))
.Times(Exactly(1))
.WillRepeatedly([](uint32_t) {
return hardware::Return<V1_0::Status>(hardware::Status::fromExceptionCode(-1));
@@ -110,20 +116,14 @@
auto callback = vibrator::TestFactory::createCountingCallback(callbackCounter.get());
ASSERT_TRUE(mWrapper->on(1ms, callback).isOk());
- // TODO(b/153418251): check callback will be triggered once implemented
- ASSERT_EQ(0, *callbackCounter.get());
+ ASSERT_EQ(1, *callbackCounter.get());
ASSERT_TRUE(mWrapper->on(10ms, callback).isUnsupported());
- // Callback not triggered
- ASSERT_EQ(0, *callbackCounter.get());
+ ASSERT_TRUE(mWrapper->on(11ms, callback).isFailed());
+ ASSERT_TRUE(mWrapper->on(12ms, callback).isFailed());
- ASSERT_TRUE(mWrapper->on(100ms, callback).isFailed());
- // Callback not triggered
- ASSERT_EQ(0, *callbackCounter.get());
-
- ASSERT_TRUE(mWrapper->on(1000ms, callback).isFailed());
- // Callback not triggered
- ASSERT_EQ(0, *callbackCounter.get());
+ // Callback not triggered for unsupported and on failure
+ ASSERT_EQ(1, *callbackCounter.get());
}
TEST_F(VibratorHalWrapperHidlV1_0Test, TestOff) {
@@ -226,6 +226,10 @@
}));
}
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) {
@@ -240,9 +244,12 @@
.Times(Exactly(1))
.WillRepeatedly(
[](V1_0::Effect, V1_0::EffectStrength, MockIVibratorV1_0::perform_cb cb) {
- cb(V1_0::Status::OK, 100);
+ cb(V1_0::Status::OK, 10);
return hardware::Return<void>();
});
+ EXPECT_CALL(*mMockScheduler.get(), schedule(_, Eq(10ms)))
+ .Times(Exactly(1))
+ .WillRepeatedly(vibrator::TriggerSchedulerCallback());
EXPECT_CALL(*mMockHal.get(),
perform(Eq(V1_0::Effect::CLICK), Eq(V1_0::EffectStrength::MEDIUM), _))
.Times(Exactly(1))
@@ -269,24 +276,20 @@
auto result = mWrapper->performEffect(Effect::CLICK, EffectStrength::LIGHT, callback);
ASSERT_TRUE(result.isOk());
- ASSERT_EQ(100ms, result.value());
- // TODO(b/153418251): check callback will be triggered once implemented
- ASSERT_EQ(0, *callbackCounter.get());
+ ASSERT_EQ(10ms, result.value());
+ ASSERT_EQ(1, *callbackCounter.get());
result = mWrapper->performEffect(Effect::CLICK, EffectStrength::MEDIUM, callback);
ASSERT_TRUE(result.isUnsupported());
- // Callback not triggered
- ASSERT_EQ(0, *callbackCounter.get());
result = mWrapper->performEffect(Effect::CLICK, EffectStrength::STRONG, callback);
ASSERT_TRUE(result.isFailed());
- // Callback not triggered
- ASSERT_EQ(0, *callbackCounter.get());
result = mWrapper->performEffect(Effect::CLICK, EffectStrength::STRONG, callback);
ASSERT_TRUE(result.isFailed());
- // Callback not triggered
- ASSERT_EQ(0, *callbackCounter.get());
+
+ // Callback not triggered for unsupported and on failure
+ ASSERT_EQ(1, *callbackCounter.get());
}
TEST_F(VibratorHalWrapperHidlV1_0Test, TestPerformEffectUnsupported) {
@@ -295,6 +298,7 @@
// Using TICK that is only available in v1.1
auto result = mWrapper->performEffect(Effect::TICK, EffectStrength::LIGHT, callback);
ASSERT_TRUE(result.isUnsupported());
+ // No callback is triggered.
ASSERT_EQ(0, *callbackCounter.get());
}
diff --git a/services/vibratorservice/test/VibratorHalWrapperHidlV1_1Test.cpp b/services/vibratorservice/test/VibratorHalWrapperHidlV1_1Test.cpp
index d0531e6..d887efc 100644
--- a/services/vibratorservice/test/VibratorHalWrapperHidlV1_1Test.cpp
+++ b/services/vibratorservice/test/VibratorHalWrapperHidlV1_1Test.cpp
@@ -23,6 +23,7 @@
#include <utils/Log.h>
+#include <vibratorservice/VibratorCallbackScheduler.h>
#include <vibratorservice/VibratorHalWrapper.h>
#include "test_utils.h"
@@ -58,11 +59,13 @@
public:
void SetUp() override {
mMockHal = new StrictMock<MockIVibratorV1_1>();
- mWrapper = std::make_unique<vibrator::HidlHalWrapperV1_1>(mMockHal);
+ mMockScheduler = std::make_shared<StrictMock<vibrator::MockCallbackScheduler>>();
+ mWrapper = std::make_unique<vibrator::HidlHalWrapperV1_1>(mMockScheduler, mMockHal);
ASSERT_NE(mWrapper, nullptr);
}
protected:
+ std::shared_ptr<StrictMock<vibrator::MockCallbackScheduler>> mMockScheduler = nullptr;
std::unique_ptr<vibrator::HalWrapper> mWrapper = nullptr;
sp<StrictMock<MockIVibratorV1_1>> mMockHal = nullptr;
};
@@ -70,23 +73,28 @@
// -------------------------------------------------------------------------------------------------
TEST_F(VibratorHalWrapperHidlV1_1Test, TestPerformEffectV1_0) {
- EXPECT_CALL(*mMockHal.get(),
- perform(Eq(V1_0::Effect::CLICK), Eq(V1_0::EffectStrength::LIGHT), _))
- .Times(Exactly(1))
- .WillRepeatedly(
- [](V1_0::Effect, V1_0::EffectStrength, MockIVibratorV1_1::perform_cb cb) {
- cb(V1_0::Status::OK, 100);
- return hardware::Return<void>();
- });
+ {
+ InSequence seq;
+ EXPECT_CALL(*mMockHal.get(),
+ perform(Eq(V1_0::Effect::CLICK), Eq(V1_0::EffectStrength::LIGHT), _))
+ .Times(Exactly(1))
+ .WillRepeatedly(
+ [](V1_0::Effect, V1_0::EffectStrength, MockIVibratorV1_1::perform_cb cb) {
+ cb(V1_0::Status::OK, 10);
+ return hardware::Return<void>();
+ });
+ EXPECT_CALL(*mMockScheduler.get(), schedule(_, Eq(10ms)))
+ .Times(Exactly(1))
+ .WillRepeatedly(vibrator::TriggerSchedulerCallback());
+ }
std::unique_ptr<int32_t> callbackCounter = std::make_unique<int32_t>();
auto callback = vibrator::TestFactory::createCountingCallback(callbackCounter.get());
auto result = mWrapper->performEffect(Effect::CLICK, EffectStrength::LIGHT, callback);
ASSERT_TRUE(result.isOk());
- ASSERT_EQ(100ms, result.value());
- // TODO(b/153418251): check callback will be triggered once implemented
- ASSERT_EQ(0, *callbackCounter.get());
+ ASSERT_EQ(10ms, result.value());
+ ASSERT_EQ(1, *callbackCounter.get());
}
TEST_F(VibratorHalWrapperHidlV1_1Test, TestPerformEffectV1_1) {
@@ -100,6 +108,9 @@
cb(V1_0::Status::OK, 10);
return hardware::Return<void>();
});
+ EXPECT_CALL(*mMockScheduler.get(), schedule(_, Eq(10ms)))
+ .Times(Exactly(1))
+ .WillRepeatedly(vibrator::TriggerSchedulerCallback());
EXPECT_CALL(*mMockHal.get(),
perform_1_1(Eq(V1_1::Effect_1_1::TICK), Eq(V1_0::EffectStrength::MEDIUM), _))
.Times(Exactly(1))
@@ -128,23 +139,19 @@
auto result = mWrapper->performEffect(Effect::TICK, EffectStrength::LIGHT, callback);
ASSERT_TRUE(result.isOk());
ASSERT_EQ(10ms, result.value());
- // TODO(b/153418251): check callback will be triggered once implemented
- ASSERT_EQ(0, *callbackCounter.get());
+ ASSERT_EQ(1, *callbackCounter.get());
result = mWrapper->performEffect(Effect::TICK, EffectStrength::MEDIUM, callback);
ASSERT_TRUE(result.isUnsupported());
- // Callback not triggered
- ASSERT_EQ(0, *callbackCounter.get());
result = mWrapper->performEffect(Effect::TICK, EffectStrength::STRONG, callback);
ASSERT_TRUE(result.isFailed());
- // Callback not triggered
- ASSERT_EQ(0, *callbackCounter.get());
result = mWrapper->performEffect(Effect::TICK, EffectStrength::STRONG, callback);
ASSERT_TRUE(result.isFailed());
- // Callback not triggered
- ASSERT_EQ(0, *callbackCounter.get());
+
+ // Callback not triggered for unsupported and on failure
+ ASSERT_EQ(1, *callbackCounter.get());
}
TEST_F(VibratorHalWrapperHidlV1_1Test, TestPerformEffectUnsupported) {
@@ -153,5 +160,6 @@
// Using THUD that is only available in v1.2
auto result = mWrapper->performEffect(Effect::THUD, EffectStrength::LIGHT, callback);
ASSERT_TRUE(result.isUnsupported());
+ // No callback is triggered.
ASSERT_EQ(0, *callbackCounter.get());
}
diff --git a/services/vibratorservice/test/VibratorHalWrapperHidlV1_2Test.cpp b/services/vibratorservice/test/VibratorHalWrapperHidlV1_2Test.cpp
index 5d2c269..26d9350 100644
--- a/services/vibratorservice/test/VibratorHalWrapperHidlV1_2Test.cpp
+++ b/services/vibratorservice/test/VibratorHalWrapperHidlV1_2Test.cpp
@@ -23,6 +23,7 @@
#include <utils/Log.h>
+#include <vibratorservice/VibratorCallbackScheduler.h>
#include <vibratorservice/VibratorHalWrapper.h>
#include "test_utils.h"
@@ -61,11 +62,13 @@
public:
void SetUp() override {
mMockHal = new StrictMock<MockIVibratorV1_2>();
- mWrapper = std::make_unique<vibrator::HidlHalWrapperV1_2>(mMockHal);
+ mMockScheduler = std::make_shared<StrictMock<vibrator::MockCallbackScheduler>>();
+ mWrapper = std::make_unique<vibrator::HidlHalWrapperV1_2>(mMockScheduler, mMockHal);
ASSERT_NE(mWrapper, nullptr);
}
protected:
+ std::shared_ptr<StrictMock<vibrator::MockCallbackScheduler>> mMockScheduler = nullptr;
std::unique_ptr<vibrator::HalWrapper> mWrapper = nullptr;
sp<StrictMock<MockIVibratorV1_2>> mMockHal = nullptr;
};
@@ -73,43 +76,53 @@
// -------------------------------------------------------------------------------------------------
TEST_F(VibratorHalWrapperHidlV1_2Test, TestPerformEffectV1_0) {
- EXPECT_CALL(*mMockHal.get(),
- perform(Eq(V1_0::Effect::CLICK), Eq(V1_0::EffectStrength::LIGHT), _))
- .Times(Exactly(1))
- .WillRepeatedly(
- [](V1_0::Effect, V1_0::EffectStrength, MockIVibratorV1_2::perform_cb cb) {
- cb(V1_0::Status::OK, 100);
- return hardware::Return<void>();
- });
+ {
+ InSequence seq;
+ EXPECT_CALL(*mMockHal.get(),
+ perform(Eq(V1_0::Effect::CLICK), Eq(V1_0::EffectStrength::LIGHT), _))
+ .Times(Exactly(1))
+ .WillRepeatedly(
+ [](V1_0::Effect, V1_0::EffectStrength, MockIVibratorV1_2::perform_cb cb) {
+ cb(V1_0::Status::OK, 10);
+ return hardware::Return<void>();
+ });
+ EXPECT_CALL(*mMockScheduler.get(), schedule(_, Eq(10ms)))
+ .Times(Exactly(1))
+ .WillRepeatedly(vibrator::TriggerSchedulerCallback());
+ }
std::unique_ptr<int32_t> callbackCounter = std::make_unique<int32_t>();
auto callback = vibrator::TestFactory::createCountingCallback(callbackCounter.get());
auto result = mWrapper->performEffect(Effect::CLICK, EffectStrength::LIGHT, callback);
ASSERT_TRUE(result.isOk());
- ASSERT_EQ(100ms, result.value());
- // TODO(b/153418251): check callback will be triggered once implemented
- ASSERT_EQ(0, *callbackCounter.get());
+ ASSERT_EQ(10ms, result.value());
+ ASSERT_EQ(1, *callbackCounter.get());
}
TEST_F(VibratorHalWrapperHidlV1_2Test, TestPerformEffectV1_1) {
- EXPECT_CALL(*mMockHal.get(),
- perform_1_1(Eq(V1_1::Effect_1_1::TICK), Eq(V1_0::EffectStrength::LIGHT), _))
- .Times(Exactly(1))
- .WillRepeatedly(
- [](V1_1::Effect_1_1, V1_0::EffectStrength, MockIVibratorV1_2::perform_cb cb) {
- cb(V1_0::Status::OK, 100);
- return hardware::Return<void>();
- });
+ {
+ InSequence seq;
+ EXPECT_CALL(*mMockHal.get(),
+ perform_1_1(Eq(V1_1::Effect_1_1::TICK), Eq(V1_0::EffectStrength::LIGHT), _))
+ .Times(Exactly(1))
+ .WillRepeatedly([](V1_1::Effect_1_1, V1_0::EffectStrength,
+ MockIVibratorV1_2::perform_cb cb) {
+ cb(V1_0::Status::OK, 10);
+ return hardware::Return<void>();
+ });
+ EXPECT_CALL(*mMockScheduler.get(), schedule(_, Eq(10ms)))
+ .Times(Exactly(1))
+ .WillRepeatedly(vibrator::TriggerSchedulerCallback());
+ }
std::unique_ptr<int32_t> callbackCounter = std::make_unique<int32_t>();
auto callback = vibrator::TestFactory::createCountingCallback(callbackCounter.get());
auto result = mWrapper->performEffect(Effect::TICK, EffectStrength::LIGHT, callback);
ASSERT_TRUE(result.isOk());
- ASSERT_EQ(100ms, result.value());
- // TODO(b/153418251): check callback will be triggered once implemented
- ASSERT_EQ(0, *callbackCounter.get());
+ ASSERT_EQ(10ms, result.value());
+ ASSERT_EQ(1, *callbackCounter.get());
}
TEST_F(VibratorHalWrapperHidlV1_2Test, TestPerformEffectV1_2) {
@@ -120,9 +133,12 @@
.Times(Exactly(1))
.WillRepeatedly(
[](V1_2::Effect, V1_0::EffectStrength, MockIVibratorV1_2::perform_cb cb) {
- cb(V1_0::Status::OK, 100);
+ cb(V1_0::Status::OK, 10);
return hardware::Return<void>();
});
+ EXPECT_CALL(*mMockScheduler.get(), schedule(_, Eq(10ms)))
+ .Times(Exactly(1))
+ .WillRepeatedly(vibrator::TriggerSchedulerCallback());
EXPECT_CALL(*mMockHal.get(),
perform_1_2(Eq(V1_2::Effect::THUD), Eq(V1_0::EffectStrength::MEDIUM), _))
.Times(Exactly(1))
@@ -149,24 +165,20 @@
auto result = mWrapper->performEffect(Effect::THUD, EffectStrength::LIGHT, callback);
ASSERT_TRUE(result.isOk());
- ASSERT_EQ(100ms, result.value());
- // TODO(b/153418251): check callback will be triggered once implemented
- ASSERT_EQ(0, *callbackCounter.get());
+ ASSERT_EQ(10ms, result.value());
+ ASSERT_EQ(1, *callbackCounter.get());
result = mWrapper->performEffect(Effect::THUD, EffectStrength::MEDIUM, callback);
ASSERT_TRUE(result.isUnsupported());
- // Callback not triggered
- ASSERT_EQ(0, *callbackCounter.get());
result = mWrapper->performEffect(Effect::THUD, EffectStrength::STRONG, callback);
ASSERT_TRUE(result.isFailed());
- // Callback not triggered
- ASSERT_EQ(0, *callbackCounter.get());
result = mWrapper->performEffect(Effect::THUD, EffectStrength::STRONG, callback);
ASSERT_TRUE(result.isFailed());
- // Callback not triggered
- ASSERT_EQ(0, *callbackCounter.get());
+
+ // Callback not triggered for unsupported and on failure
+ ASSERT_EQ(1, *callbackCounter.get());
}
TEST_F(VibratorHalWrapperHidlV1_2Test, TestPerformEffectUnsupported) {
@@ -175,5 +187,6 @@
// Using TEXTURE_TICK that is only available in v1.3
auto result = mWrapper->performEffect(Effect::TEXTURE_TICK, EffectStrength::LIGHT, callback);
ASSERT_TRUE(result.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 a799257..5de6257 100644
--- a/services/vibratorservice/test/VibratorHalWrapperHidlV1_3Test.cpp
+++ b/services/vibratorservice/test/VibratorHalWrapperHidlV1_3Test.cpp
@@ -24,6 +24,7 @@
#include <utils/Log.h>
#include <thread>
+#include <vibratorservice/VibratorCallbackScheduler.h>
#include <vibratorservice/VibratorHalWrapper.h>
#include "test_utils.h"
@@ -68,11 +69,13 @@
public:
void SetUp() override {
mMockHal = new StrictMock<MockIVibratorV1_3>();
- mWrapper = std::make_unique<vibrator::HidlHalWrapperV1_3>(mMockHal);
+ mMockScheduler = std::make_shared<StrictMock<vibrator::MockCallbackScheduler>>();
+ mWrapper = std::make_unique<vibrator::HidlHalWrapperV1_3>(mMockScheduler, mMockHal);
ASSERT_NE(mWrapper, nullptr);
}
protected:
+ std::shared_ptr<StrictMock<vibrator::MockCallbackScheduler>> mMockScheduler = nullptr;
std::unique_ptr<vibrator::HalWrapper> mWrapper = nullptr;
sp<StrictMock<MockIVibratorV1_3>> mMockHal = nullptr;
};
@@ -210,6 +213,10 @@
}));
}
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_3Test, TestGetCapabilitiesDoesNotCacheFailedResult) {
@@ -258,63 +265,78 @@
}
TEST_F(VibratorHalWrapperHidlV1_3Test, TestPerformEffectV1_0) {
- EXPECT_CALL(*mMockHal.get(),
- perform(Eq(V1_0::Effect::CLICK), Eq(V1_0::EffectStrength::LIGHT), _))
- .Times(Exactly(1))
- .WillRepeatedly(
- [](V1_0::Effect, V1_0::EffectStrength, MockIVibratorV1_3::perform_cb cb) {
- cb(V1_0::Status::OK, 100);
- return hardware::Return<void>();
- });
+ {
+ InSequence seq;
+ EXPECT_CALL(*mMockHal.get(),
+ perform(Eq(V1_0::Effect::CLICK), Eq(V1_0::EffectStrength::LIGHT), _))
+ .Times(Exactly(1))
+ .WillRepeatedly(
+ [](V1_0::Effect, V1_0::EffectStrength, MockIVibratorV1_3::perform_cb cb) {
+ cb(V1_0::Status::OK, 10);
+ return hardware::Return<void>();
+ });
+ EXPECT_CALL(*mMockScheduler.get(), schedule(_, Eq(10ms)))
+ .Times(Exactly(1))
+ .WillRepeatedly(vibrator::TriggerSchedulerCallback());
+ }
std::unique_ptr<int32_t> callbackCounter = std::make_unique<int32_t>();
auto callback = vibrator::TestFactory::createCountingCallback(callbackCounter.get());
auto result = mWrapper->performEffect(Effect::CLICK, EffectStrength::LIGHT, callback);
ASSERT_TRUE(result.isOk());
- ASSERT_EQ(100ms, result.value());
- // TODO(b/153418251): check callback will be triggered once implemented
- ASSERT_EQ(0, *callbackCounter.get());
+ ASSERT_EQ(10ms, result.value());
+ ASSERT_EQ(1, *callbackCounter.get());
}
TEST_F(VibratorHalWrapperHidlV1_3Test, TestPerformEffectV1_1) {
- EXPECT_CALL(*mMockHal.get(),
- perform_1_1(Eq(V1_1::Effect_1_1::TICK), Eq(V1_0::EffectStrength::LIGHT), _))
- .Times(Exactly(1))
- .WillRepeatedly(
- [](V1_1::Effect_1_1, V1_0::EffectStrength, MockIVibratorV1_3::perform_cb cb) {
- cb(V1_0::Status::OK, 100);
- return hardware::Return<void>();
- });
+ {
+ InSequence seq;
+ EXPECT_CALL(*mMockHal.get(),
+ perform_1_1(Eq(V1_1::Effect_1_1::TICK), Eq(V1_0::EffectStrength::LIGHT), _))
+ .Times(Exactly(1))
+ .WillRepeatedly([](V1_1::Effect_1_1, V1_0::EffectStrength,
+ MockIVibratorV1_3::perform_cb cb) {
+ cb(V1_0::Status::OK, 10);
+ return hardware::Return<void>();
+ });
+ EXPECT_CALL(*mMockScheduler.get(), schedule(_, Eq(10ms)))
+ .Times(Exactly(1))
+ .WillRepeatedly(vibrator::TriggerSchedulerCallback());
+ }
std::unique_ptr<int32_t> callbackCounter = std::make_unique<int32_t>();
auto callback = vibrator::TestFactory::createCountingCallback(callbackCounter.get());
auto result = mWrapper->performEffect(Effect::TICK, EffectStrength::LIGHT, callback);
ASSERT_TRUE(result.isOk());
- ASSERT_EQ(100ms, result.value());
- // TODO(b/153418251): check callback will be triggered once implemented
- ASSERT_EQ(0, *callbackCounter.get());
+ ASSERT_EQ(10ms, result.value());
+ ASSERT_EQ(1, *callbackCounter.get());
}
TEST_F(VibratorHalWrapperHidlV1_3Test, TestPerformEffectV1_2) {
- EXPECT_CALL(*mMockHal.get(),
- perform_1_2(Eq(V1_2::Effect::THUD), Eq(V1_0::EffectStrength::LIGHT), _))
- .Times(Exactly(1))
- .WillRepeatedly(
- [](V1_2::Effect, V1_0::EffectStrength, MockIVibratorV1_3::perform_cb cb) {
- cb(V1_0::Status::OK, 100);
- return hardware::Return<void>();
- });
+ {
+ InSequence seq;
+ EXPECT_CALL(*mMockHal.get(),
+ perform_1_2(Eq(V1_2::Effect::THUD), Eq(V1_0::EffectStrength::LIGHT), _))
+ .Times(Exactly(1))
+ .WillRepeatedly(
+ [](V1_2::Effect, V1_0::EffectStrength, MockIVibratorV1_3::perform_cb cb) {
+ cb(V1_0::Status::OK, 10);
+ return hardware::Return<void>();
+ });
+ EXPECT_CALL(*mMockScheduler.get(), schedule(_, Eq(10ms)))
+ .Times(Exactly(1))
+ .WillRepeatedly(vibrator::TriggerSchedulerCallback());
+ }
std::unique_ptr<int32_t> callbackCounter = std::make_unique<int32_t>();
auto callback = vibrator::TestFactory::createCountingCallback(callbackCounter.get());
auto result = mWrapper->performEffect(Effect::THUD, EffectStrength::LIGHT, callback);
ASSERT_TRUE(result.isOk());
- ASSERT_EQ(100ms, result.value());
- // TODO(b/153418251): check callback will be triggered once implemented
- ASSERT_EQ(0, *callbackCounter.get());
+ ASSERT_EQ(10ms, result.value());
+ ASSERT_EQ(1, *callbackCounter.get());
}
TEST_F(VibratorHalWrapperHidlV1_3Test, TestPerformEffectV1_3) {
@@ -328,6 +350,9 @@
cb(V1_0::Status::OK, 10);
return hardware::Return<void>();
});
+ EXPECT_CALL(*mMockScheduler.get(), schedule(_, Eq(10ms)))
+ .Times(Exactly(1))
+ .WillRepeatedly(vibrator::TriggerSchedulerCallback());
EXPECT_CALL(*mMockHal.get(),
perform_1_3(Eq(V1_3::Effect::TEXTURE_TICK), Eq(V1_0::EffectStrength::MEDIUM),
_))
@@ -357,21 +382,17 @@
auto result = mWrapper->performEffect(Effect::TEXTURE_TICK, EffectStrength::LIGHT, callback);
ASSERT_TRUE(result.isOk());
ASSERT_EQ(10ms, result.value());
- // TODO(b/153418251): check callback will be triggered once implemented
- ASSERT_EQ(0, *callbackCounter.get());
+ ASSERT_EQ(1, *callbackCounter.get());
result = mWrapper->performEffect(Effect::TEXTURE_TICK, EffectStrength::MEDIUM, callback);
ASSERT_TRUE(result.isUnsupported());
- // Callback not triggered
- ASSERT_EQ(0, *callbackCounter.get());
result = mWrapper->performEffect(Effect::TEXTURE_TICK, EffectStrength::STRONG, callback);
ASSERT_TRUE(result.isFailed());
- // Callback not triggered
- ASSERT_EQ(0, *callbackCounter.get());
result = mWrapper->performEffect(Effect::TEXTURE_TICK, EffectStrength::STRONG, callback);
ASSERT_TRUE(result.isFailed());
- // Callback not triggered
- ASSERT_EQ(0, *callbackCounter.get());
+
+ // Callback not triggered for unsupported and on failure
+ ASSERT_EQ(1, *callbackCounter.get());
}
diff --git a/services/vibratorservice/test/test_utils.h b/services/vibratorservice/test/test_utils.h
index fc9b364..8d0b22e 100644
--- a/services/vibratorservice/test/test_utils.h
+++ b/services/vibratorservice/test/test_utils.h
@@ -28,6 +28,20 @@
using ::android::hardware::vibrator::CompositeEffect;
using ::android::hardware::vibrator::CompositePrimitive;
+// -------------------------------------------------------------------------------------------------
+
+class MockCallbackScheduler : public vibrator::CallbackScheduler {
+public:
+ MOCK_METHOD(void, schedule, (std::function<void()> callback, std::chrono::milliseconds delay),
+ (override));
+};
+
+ACTION(TriggerSchedulerCallback) {
+ arg0();
+}
+
+// -------------------------------------------------------------------------------------------------
+
class TestFactory {
public:
static CompositeEffect createCompositeEffect(CompositePrimitive primitive,
@@ -48,6 +62,8 @@
~TestFactory() = delete;
};
+// -------------------------------------------------------------------------------------------------
+
} // namespace vibrator
} // namespace android