Merge "Update parcel data pointer after realloc with size 0" into rvc-qpr-dev am: 44dfbadd4a am: 3cb9373307
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/native/+/12038643
Change-Id: I1fb9df49de559d70d0816cd962499c318c0360cf
diff --git a/.gitignore b/.gitignore
index 0d20b64..685e379 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,3 @@
+*.iml
*.pyc
+.idea/
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index 0473bb8..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,7 +19,9 @@
opengl/libs/
services/bufferhub/
services/inputflinger/
+ services/powermanager/
services/surfaceflinger/
+ services/vibratorservice/
services/vr/
vulkan/
diff --git a/TEST_MAPPING b/TEST_MAPPING
index 8173c89..5db44c7 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -58,6 +58,14 @@
},
{
"name": "libsurfaceflinger_unittest"
+ },
+ {
+ "name": "CtsGraphicsTestCases",
+ "options": [
+ {
+ "include-filter": "android.graphics.cts.VulkanPreTransformTest"
+ }
+ ]
}
]
}
diff --git a/cmds/atrace/atrace.cpp b/cmds/atrace/atrace.cpp
index 28fdaa4..fc3572c 100644
--- a/cmds/atrace/atrace.cpp
+++ b/cmds/atrace/atrace.cpp
@@ -239,6 +239,10 @@
{ OPT, "events/kmem/ion_heap_shrink/enable" },
{ OPT, "events/ion/ion_stat/enable" },
} },
+ { "thermal", "Thermal event", 0, {
+ { REQ, "events/thermal/thermal_temperature/enable" },
+ { OPT, "events/thermal/cdev_update/enable" },
+ } },
};
struct TracingVendorCategory {
diff --git a/cmds/atrace/atrace.rc b/cmds/atrace/atrace.rc
index f442dae..d2ccef1 100644
--- a/cmds/atrace/atrace.rc
+++ b/cmds/atrace/atrace.rc
@@ -166,6 +166,12 @@
chmod 0666 /sys/kernel/tracing/events/filemap/mm_filemap_delete_from_page_cache/enable
chmod 0666 /sys/kernel/debug/tracing/events/filemap/mm_filemap_delete_from_page_cache/enable
+ # thermal
+ chmod 0666 /sys/kernel/debug/tracing/events/thermal/thermal_temperature/enable
+ chmod 0666 /sys/kernel/tracing/events/thermal/thermal_temperature/enable
+ chmod 0666 /sys/kernel/debug/tracing/events/thermal/cdev_update/enable
+ chmod 0666 /sys/kernel/tracing/events/thermal/cdev_update/enable
+
# Tracing disabled by default
write /sys/kernel/debug/tracing/tracing_on 0
write /sys/kernel/tracing/tracing_on 0
diff --git a/cmds/dumpstate/Android.bp b/cmds/dumpstate/Android.bp
index ead491e..4058934 100644
--- a/cmds/dumpstate/Android.bp
+++ b/cmds/dumpstate/Android.bp
@@ -152,6 +152,8 @@
"tests/dumpstate_smoke_test.cpp",
],
static_libs: ["libgmock"],
+ test_config: "dumpstate_smoke_test.xml",
+ test_suites: ["device-tests"],
}
diff --git a/cmds/dumpstate/TEST_MAPPING b/cmds/dumpstate/TEST_MAPPING
index 083944f..8b03cfd 100644
--- a/cmds/dumpstate/TEST_MAPPING
+++ b/cmds/dumpstate/TEST_MAPPING
@@ -1,7 +1,21 @@
{
"presubmit": [
+ // TODO(159590499) add BugreportManagerTestCases
+ {
+ "name": "dumpstate_smoke_test"
+ },
{
"name": "dumpstate_test"
}
+ ],
+ "postsubmit": [
+ {
+ "name": "BugreportManagerTestCases"
+ }
+ ],
+ "imports": [
+ {
+ "path": "frameworks/base/packages/Shell"
+ }
]
-}
\ No newline at end of file
+}
diff --git a/cmds/dumpstate/dumpstate_smoke_test.xml b/cmds/dumpstate/dumpstate_smoke_test.xml
new file mode 100644
index 0000000..0aff200
--- /dev/null
+++ b/cmds/dumpstate/dumpstate_smoke_test.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<configuration description="Config for dumpstate_smoke_test">
+ <option name="test-suite-tag" value="apct" />
+ <option name="test-suite-tag" value="apct-native" />
+
+ <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/>
+ <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+ <option name="cleanup" value="true" />
+ <option name="push" value="dumpstate_smoke_test->/data/local/tmp/dumpstate_smoke_test" />
+ </target_preparer>
+
+ <test class="com.android.tradefed.testtype.GTest" >
+ <option name="native-test-device-path" value="/data/local/tmp" />
+ <option name="module-name" value="dumpstate_smoke_test" />
+ <option name="native-test-timeout" value="600000" />
+ </test>
+</configuration>
diff --git a/cmds/dumpstate/tests/dumpstate_smoke_test.cpp b/cmds/dumpstate/tests/dumpstate_smoke_test.cpp
index 6f2d754..bb0e5ad 100644
--- a/cmds/dumpstate/tests/dumpstate_smoke_test.cpp
+++ b/cmds/dumpstate/tests/dumpstate_smoke_test.cpp
@@ -209,13 +209,12 @@
static std::shared_ptr<std::vector<SectionInfo>> sections;
static Dumpstate& ds;
static std::chrono::milliseconds duration;
- static void SetUpTestCase() {
+ static void GenerateBugreport() {
// clang-format off
char* argv[] = {
(char*)"dumpstate",
(char*)"-d",
- (char*)"-z",
- (char*)"-B"
+ (char*)"-z"
};
// clang-format on
sp<DumpstateListener> listener(new DumpstateListener(dup(fileno(stdout)), sections));
@@ -236,20 +235,20 @@
std::chrono::milliseconds ZippedBugreportGenerationTest::duration = 0s;
TEST_F(ZippedBugreportGenerationTest, IsGeneratedWithoutErrors) {
+ GenerateBugreport();
EXPECT_EQ(access(getZipFilePath().c_str(), F_OK), 0);
}
-TEST_F(ZippedBugreportGenerationTest, Is3MBto30MBinSize) {
+TEST_F(ZippedBugreportGenerationTest, Is3MBMBinSize) {
struct stat st;
EXPECT_EQ(stat(getZipFilePath().c_str(), &st), 0);
EXPECT_GE(st.st_size, 3000000 /* 3MB */);
- EXPECT_LE(st.st_size, 30000000 /* 30MB */);
}
-TEST_F(ZippedBugreportGenerationTest, TakesBetween30And150Seconds) {
+TEST_F(ZippedBugreportGenerationTest, TakesBetween30And300Seconds) {
EXPECT_GE(duration, 30s) << "Expected completion in more than 30s. Actual time "
<< duration.count() << " s.";
- EXPECT_LE(duration, 150s) << "Expected completion in less than 150s. Actual time "
+ EXPECT_LE(duration, 300s) << "Expected completion in less than 300s. Actual time "
<< duration.count() << " s.";
}
@@ -266,7 +265,8 @@
CloseArchive(handle);
}
- void FileExists(const char* filename, uint32_t minsize, uint32_t maxsize) {
+ void FileExists(const char* filename, uint32_t minsize,
+ uint32_t maxsize = std::numeric_limits<uint32_t>::max()) {
ZipEntry entry;
GetEntry(handle, filename, &entry);
EXPECT_GT(entry.uncompressed_length, minsize);
@@ -285,7 +285,7 @@
main_entry.uncompressed_length);
// contains main entry file
- FileExists(bugreport_txt_name.c_str(), 1000000U, 50000000U);
+ FileExists(bugreport_txt_name.c_str(), 1000000U);
}
TEST_F(ZippedBugReportContentsTest, ContainsVersion) {
@@ -301,8 +301,9 @@
}
TEST_F(ZippedBugReportContentsTest, ContainsBoardSpecificFiles) {
- FileExists("dumpstate_board.bin", 1000000U, 80000000U);
- FileExists("dumpstate_board.txt", 100000U, 1000000U);
+ // TODO(b/160109027): cf_x86_phone-userdebug does not dump them.
+ // FileExists("dumpstate_board.bin", 1000000U, 80000000U);
+ // FileExists("dumpstate_board.txt", 100000U, 1000000U);
}
TEST_F(ZippedBugReportContentsTest, ContainsProtoFile) {
diff --git a/cmds/idlcli/Android.bp b/cmds/idlcli/Android.bp
index 402767a..64bfdf9 100644
--- a/cmds/idlcli/Android.bp
+++ b/cmds/idlcli/Android.bp
@@ -37,10 +37,16 @@
defaults: ["idlcli-defaults"],
srcs: [
"CommandVibrator.cpp",
+ "vibrator/CommandAlwaysOnDisable.cpp",
+ "vibrator/CommandAlwaysOnEnable.cpp",
"vibrator/CommandCompose.cpp",
"vibrator/CommandGetCapabilities.cpp",
"vibrator/CommandGetCompositionDelayMax.cpp",
"vibrator/CommandGetCompositionSizeMax.cpp",
+ "vibrator/CommandGetPrimitiveDuration.cpp",
+ "vibrator/CommandGetSupportedAlwaysOnEffects.cpp",
+ "vibrator/CommandGetSupportedEffects.cpp",
+ "vibrator/CommandGetSupportedPrimitives.cpp",
"vibrator/CommandOff.cpp",
"vibrator/CommandOn.cpp",
"vibrator/CommandPerform.cpp",
diff --git a/cmds/idlcli/utils.h b/cmds/idlcli/utils.h
index a8e5954..b874455 100644
--- a/cmds/idlcli/utils.h
+++ b/cmds/idlcli/utils.h
@@ -17,6 +17,7 @@
#ifndef FRAMEWORK_NATIVE_CMDS_IDLCLI_UTILS_H_
#define FRAMEWORK_NATIVE_CMDS_IDLCLI_UTILS_H_
+#include <android/binder_enums.h>
#include <hidl/HidlSupport.h>
#include <iomanip>
@@ -66,7 +67,7 @@
} // namespace overrides
-template <typename T, typename R = hardware::hidl_enum_range<T>>
+template <typename T, typename R = ndk::enum_range<T>>
inline std::istream &operator>>(std::istream &stream, T &out) {
using overrides::operator>>;
auto validRange = R();
diff --git a/cmds/idlcli/vibrator.h b/cmds/idlcli/vibrator.h
index ca5142d..6c30a9e 100644
--- a/cmds/idlcli/vibrator.h
+++ b/cmds/idlcli/vibrator.h
@@ -16,8 +16,12 @@
#ifndef FRAMEWORK_NATIVE_CMDS_IDLCLI_VIBRATOR_H_
#define FRAMEWORK_NATIVE_CMDS_IDLCLI_VIBRATOR_H_
+#include <future>
+
+#include <aidl/android/hardware/vibrator/BnVibratorCallback.h>
#include <aidl/android/hardware/vibrator/IVibrator.h>
#include <android/binder_manager.h>
+#include <android/binder_process.h>
#include <android/hardware/vibrator/1.3/IVibrator.h>
#include "utils.h"
@@ -101,6 +105,18 @@
namespace V1_3 = ::android::hardware::vibrator::V1_3;
namespace aidl = ::aidl::android::hardware::vibrator;
+class VibratorCallback : public aidl::BnVibratorCallback {
+public:
+ ndk::ScopedAStatus onComplete() override {
+ mPromise.set_value();
+ return ndk::ScopedAStatus::ok();
+ }
+ void waitForComplete() { mPromise.get_future().wait(); }
+
+private:
+ std::promise<void> mPromise;
+};
+
} // namespace vibrator
} // namespace idlcli
diff --git a/cmds/idlcli/vibrator/CommandAlwaysOnDisable.cpp b/cmds/idlcli/vibrator/CommandAlwaysOnDisable.cpp
new file mode 100644
index 0000000..9afa300
--- /dev/null
+++ b/cmds/idlcli/vibrator/CommandAlwaysOnDisable.cpp
@@ -0,0 +1,79 @@
+/*
+ * 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 "utils.h"
+#include "vibrator.h"
+
+namespace android {
+namespace idlcli {
+
+class CommandVibrator;
+
+namespace vibrator {
+
+class CommandAlwaysOnDisable : public Command {
+ std::string getDescription() const override { return "Disarm always-on haptic source."; }
+
+ std::string getUsageSummary() const override { return "<id>"; }
+
+ UsageDetails getUsageDetails() const override {
+ UsageDetails details{
+ {"<id>", {"Source ID (device-specific)."}},
+ };
+ return details;
+ }
+
+ Status doArgs(Args &args) override {
+ if (auto id = args.pop<decltype(mId)>()) {
+ mId = *id;
+ std::cout << "Source ID: " << mId << std::endl;
+ } else {
+ std::cerr << "Missing or Invalid Source ID!" << std::endl;
+ return USAGE;
+ }
+ if (!args.empty()) {
+ std::cerr << "Unexpected Arguments!" << std::endl;
+ return USAGE;
+ }
+ return OK;
+ }
+
+ Status doMain(Args && /*args*/) override {
+ std::string statusStr;
+ Status ret;
+
+ if (auto hal = getHal<aidl::IVibrator>()) {
+ auto status = hal->call(&aidl::IVibrator::alwaysOnDisable, mId);
+
+ statusStr = status.getDescription();
+ ret = status.isOk() ? OK : ERROR;
+ } else {
+ return UNAVAILABLE;
+ }
+
+ std::cout << "Status: " << statusStr << std::endl;
+
+ return ret;
+ }
+
+ int32_t mId;
+};
+
+static const auto Command =
+ CommandRegistry<CommandVibrator>::Register<CommandAlwaysOnDisable>("alwaysOnDisable");
+
+} // namespace vibrator
+} // namespace idlcli
+} // namespace android
diff --git a/cmds/idlcli/vibrator/CommandAlwaysOnEnable.cpp b/cmds/idlcli/vibrator/CommandAlwaysOnEnable.cpp
new file mode 100644
index 0000000..bb7f9f2
--- /dev/null
+++ b/cmds/idlcli/vibrator/CommandAlwaysOnEnable.cpp
@@ -0,0 +1,102 @@
+/*
+ * 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 "utils.h"
+#include "vibrator.h"
+
+namespace android {
+namespace idlcli {
+
+class CommandVibrator;
+
+namespace vibrator {
+
+using aidl::Effect;
+using aidl::EffectStrength;
+
+class CommandAlwaysOnEnable : public Command {
+ std::string getDescription() const override {
+ return "Arm always-on haptic source with an effect.";
+ }
+
+ std::string getUsageSummary() const override { return "<id> <effect> <strength>"; }
+
+ UsageDetails getUsageDetails() const override {
+ UsageDetails details{
+ {"<id>", {"Source ID (device-specific)."}},
+ {"<effect>", {"Effect ID."}},
+ {"<strength>", {"0-2."}},
+ };
+ return details;
+ }
+
+ Status doArgs(Args &args) override {
+ if (auto id = args.pop<decltype(mId)>()) {
+ mId = *id;
+ std::cout << "Source ID: " << mId << std::endl;
+ } else {
+ std::cerr << "Missing or Invalid Source ID!" << std::endl;
+ return USAGE;
+ }
+ if (auto effect = args.pop<decltype(mEffect)>()) {
+ mEffect = *effect;
+ std::cout << "Effect: " << toString(mEffect) << std::endl;
+ } else {
+ std::cerr << "Missing or Invalid Effect!" << std::endl;
+ return USAGE;
+ }
+ if (auto strength = args.pop<decltype(mStrength)>()) {
+ mStrength = *strength;
+ std::cout << "Strength: " << toString(mStrength) << std::endl;
+ } else {
+ std::cerr << "Missing or Invalid Strength!" << std::endl;
+ return USAGE;
+ }
+ if (!args.empty()) {
+ std::cerr << "Unexpected Arguments!" << std::endl;
+ return USAGE;
+ }
+ return OK;
+ }
+
+ Status doMain(Args && /*args*/) override {
+ std::string statusStr;
+ Status ret;
+
+ if (auto hal = getHal<aidl::IVibrator>()) {
+ auto status = hal->call(&aidl::IVibrator::alwaysOnEnable, mId, mEffect, mStrength);
+
+ statusStr = status.getDescription();
+ ret = status.isOk() ? OK : ERROR;
+ } else {
+ return UNAVAILABLE;
+ }
+
+ std::cout << "Status: " << statusStr << std::endl;
+
+ return ret;
+ }
+
+ int32_t mId;
+ Effect mEffect;
+ EffectStrength mStrength;
+};
+
+static const auto Command =
+ CommandRegistry<CommandVibrator>::Register<CommandAlwaysOnEnable>("alwaysOnEnable");
+
+} // namespace vibrator
+} // namespace idlcli
+} // namespace android
diff --git a/cmds/idlcli/vibrator/CommandCompose.cpp b/cmds/idlcli/vibrator/CommandCompose.cpp
index 4721a5f..97c057f 100644
--- a/cmds/idlcli/vibrator/CommandCompose.cpp
+++ b/cmds/idlcli/vibrator/CommandCompose.cpp
@@ -28,10 +28,13 @@
class CommandCompose : public Command {
std::string getDescription() const override { return "Compose vibration."; }
- std::string getUsageSummary() const override { return "<delay> <primitive> <scale> ..."; }
+ std::string getUsageSummary() const override {
+ return "[options] <delay> <primitive> <scale> ...";
+ }
UsageDetails getUsageDetails() const override {
UsageDetails details{
+ {"-b", {"Block for duration of vibration."}},
{"<delay>", {"In milliseconds"}},
{"<primitive>", {"Primitive ID."}},
{"<scale>", {"0.0 (exclusive) - 1.0 (inclusive)."}},
@@ -41,6 +44,17 @@
}
Status doArgs(Args &args) override {
+ while (args.get<std::string>().value_or("").find("-") == 0) {
+ auto opt = *args.pop<std::string>();
+ if (opt == "--") {
+ break;
+ } else if (opt == "-b") {
+ mBlocking = true;
+ } else {
+ std::cerr << "Invalid Option '" << opt << "'!" << std::endl;
+ return USAGE;
+ }
+ }
while (!args.empty()) {
CompositeEffect effect;
if (auto delay = args.pop<decltype(effect.delayMs)>()) {
@@ -50,9 +64,8 @@
std::cerr << "Missing or Invalid Delay!" << std::endl;
return USAGE;
}
- // TODO: Use range validation when supported by AIDL
- if (auto primitive = args.pop<std::underlying_type_t<decltype(effect.primitive)>>()) {
- effect.primitive = static_cast<decltype(effect.primitive)>(*primitive);
+ if (auto primitive = args.pop<decltype(effect.primitive)>()) {
+ effect.primitive = *primitive;
std::cout << "Primitive: " << toString(effect.primitive) << std::endl;
} else {
std::cerr << "Missing or Invalid Primitive!" << std::endl;
@@ -76,21 +89,33 @@
}
Status doMain(Args && /*args*/) override {
- std::string statusStr;
- Status ret;
- if (auto hal = getHal<aidl::IVibrator>()) {
- auto status = hal->call(&aidl::IVibrator::compose, mComposite, nullptr);
- statusStr = status.getDescription();
- ret = status.isOk() ? OK : ERROR;
- } else {
+ auto hal = getHal<aidl::IVibrator>();
+
+ if (!hal) {
return UNAVAILABLE;
}
- std::cout << "Status: " << statusStr << std::endl;
+ ABinderProcess_setThreadPoolMaxThreadCount(1);
+ ABinderProcess_startThreadPool();
- return ret;
+ std::shared_ptr<VibratorCallback> callback;
+
+ if (mBlocking) {
+ callback = ndk::SharedRefBase::make<VibratorCallback>();
+ }
+
+ auto status = hal->call(&aidl::IVibrator::compose, mComposite, callback);
+
+ if (status.isOk() && callback) {
+ callback->waitForComplete();
+ }
+
+ std::cout << "Status: " << status.getDescription() << std::endl;
+
+ return status.isOk() ? OK : ERROR;
}
+ bool mBlocking;
std::vector<CompositeEffect> mComposite;
};
diff --git a/cmds/idlcli/vibrator/CommandGetPrimitiveDuration.cpp b/cmds/idlcli/vibrator/CommandGetPrimitiveDuration.cpp
new file mode 100644
index 0000000..460d39e
--- /dev/null
+++ b/cmds/idlcli/vibrator/CommandGetPrimitiveDuration.cpp
@@ -0,0 +1,86 @@
+/*
+ * 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 <future>
+
+#include "utils.h"
+#include "vibrator.h"
+
+namespace android {
+namespace idlcli {
+
+class CommandVibrator;
+
+namespace vibrator {
+
+using aidl::CompositePrimitive;
+
+class CommandGetPrimitiveDuration : public Command {
+ std::string getDescription() const override {
+ return "Retrieve effect primitive's duration in milliseconds.";
+ }
+
+ std::string getUsageSummary() const override { return "<primitive>"; }
+
+ UsageDetails getUsageDetails() const override {
+ UsageDetails details{
+ {"<primitive>", {"Primitive ID."}},
+ };
+ return details;
+ }
+
+ Status doArgs(Args &args) override {
+ if (auto primitive = args.pop<decltype(mPrimitive)>()) {
+ mPrimitive = *primitive;
+ std::cout << "Primitive: " << toString(mPrimitive) << std::endl;
+ } else {
+ std::cerr << "Missing or Invalid Primitive!" << std::endl;
+ return USAGE;
+ }
+ if (!args.empty()) {
+ std::cerr << "Unexpected Arguments!" << std::endl;
+ return USAGE;
+ }
+ return OK;
+ }
+
+ Status doMain(Args && /*args*/) override {
+ std::string statusStr;
+ int32_t duration;
+ Status ret;
+
+ if (auto hal = getHal<aidl::IVibrator>()) {
+ auto status = hal->call(&aidl::IVibrator::getPrimitiveDuration, mPrimitive, &duration);
+ statusStr = status.getDescription();
+ ret = status.isOk() ? OK : ERROR;
+ } else {
+ return UNAVAILABLE;
+ }
+
+ std::cout << "Status: " << statusStr << std::endl;
+ std::cout << "Duration: " << duration << std::endl;
+
+ return ret;
+ }
+
+ CompositePrimitive mPrimitive;
+};
+
+static const auto Command = CommandRegistry<CommandVibrator>::Register<CommandGetPrimitiveDuration>(
+ "getPrimitiveDuration");
+
+} // namespace vibrator
+} // namespace idlcli
+} // namespace android
diff --git a/cmds/idlcli/vibrator/CommandGetSupportedAlwaysOnEffects.cpp b/cmds/idlcli/vibrator/CommandGetSupportedAlwaysOnEffects.cpp
new file mode 100644
index 0000000..edfcd91
--- /dev/null
+++ b/cmds/idlcli/vibrator/CommandGetSupportedAlwaysOnEffects.cpp
@@ -0,0 +1,75 @@
+/*
+ * 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 "utils.h"
+#include "vibrator.h"
+
+namespace android {
+namespace idlcli {
+
+class CommandVibrator;
+
+namespace vibrator {
+
+using aidl::Effect;
+
+class CommandGetSupportedAlwaysOnEffects : public Command {
+ std::string getDescription() const override { return "List of supported always-on effects."; }
+
+ std::string getUsageSummary() const override { return ""; }
+
+ UsageDetails getUsageDetails() const override {
+ UsageDetails details{};
+ return details;
+ }
+
+ Status doArgs(Args &args) override {
+ if (!args.empty()) {
+ std::cerr << "Unexpected Arguments!" << std::endl;
+ return USAGE;
+ }
+ return OK;
+ }
+
+ Status doMain(Args && /*args*/) override {
+ std::string statusStr;
+ std::vector<Effect> effects;
+ Status ret;
+
+ if (auto hal = getHal<aidl::IVibrator>()) {
+ auto status = hal->call(&aidl::IVibrator::getSupportedAlwaysOnEffects, &effects);
+ statusStr = status.getDescription();
+ ret = status.isOk() ? OK : ERROR;
+ } else {
+ return UNAVAILABLE;
+ }
+
+ std::cout << "Status: " << statusStr << std::endl;
+ std::cout << "Effects:" << std::endl;
+ for (auto &e : effects) {
+ std::cout << " " << toString(e) << std::endl;
+ }
+
+ return ret;
+ }
+};
+
+static const auto Command =
+ CommandRegistry<CommandVibrator>::Register<CommandGetSupportedAlwaysOnEffects>(
+ "getSupportedAlwaysOnEffects");
+
+} // namespace vibrator
+} // namespace idlcli
+} // namespace android
diff --git a/cmds/idlcli/vibrator/CommandGetSupportedEffects.cpp b/cmds/idlcli/vibrator/CommandGetSupportedEffects.cpp
new file mode 100644
index 0000000..7658f22
--- /dev/null
+++ b/cmds/idlcli/vibrator/CommandGetSupportedEffects.cpp
@@ -0,0 +1,74 @@
+/*
+ * 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 "utils.h"
+#include "vibrator.h"
+
+namespace android {
+namespace idlcli {
+
+class CommandVibrator;
+
+namespace vibrator {
+
+using aidl::Effect;
+
+class CommandGetSupportedEffects : public Command {
+ std::string getDescription() const override { return "List supported effects."; }
+
+ std::string getUsageSummary() const override { return ""; }
+
+ UsageDetails getUsageDetails() const override {
+ UsageDetails details{};
+ return details;
+ }
+
+ Status doArgs(Args &args) override {
+ if (!args.empty()) {
+ std::cerr << "Unexpected Arguments!" << std::endl;
+ return USAGE;
+ }
+ return OK;
+ }
+
+ Status doMain(Args && /*args*/) override {
+ std::string statusStr;
+ std::vector<Effect> effects;
+ Status ret;
+
+ if (auto hal = getHal<aidl::IVibrator>()) {
+ auto status = hal->call(&aidl::IVibrator::getSupportedEffects, &effects);
+ statusStr = status.getDescription();
+ ret = status.isOk() ? OK : ERROR;
+ } else {
+ return UNAVAILABLE;
+ }
+
+ std::cout << "Status: " << statusStr << std::endl;
+ std::cout << "Effects:" << std::endl;
+ for (auto &e : effects) {
+ std::cout << " " << toString(e) << std::endl;
+ }
+
+ return ret;
+ }
+};
+
+static const auto Command = CommandRegistry<CommandVibrator>::Register<CommandGetSupportedEffects>(
+ "getSupportedEffects");
+
+} // namespace vibrator
+} // namespace idlcli
+} // namespace android
diff --git a/cmds/idlcli/vibrator/CommandGetSupportedPrimitives.cpp b/cmds/idlcli/vibrator/CommandGetSupportedPrimitives.cpp
new file mode 100644
index 0000000..d101681
--- /dev/null
+++ b/cmds/idlcli/vibrator/CommandGetSupportedPrimitives.cpp
@@ -0,0 +1,75 @@
+/*
+ * 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 "utils.h"
+#include "vibrator.h"
+
+namespace android {
+namespace idlcli {
+
+class CommandVibrator;
+
+namespace vibrator {
+
+using aidl::CompositePrimitive;
+
+class CommandGetSupportedPrimitives : public Command {
+ std::string getDescription() const override { return "List of supported effect primitive."; }
+
+ std::string getUsageSummary() const override { return ""; }
+
+ UsageDetails getUsageDetails() const override {
+ UsageDetails details{};
+ return details;
+ }
+
+ Status doArgs(Args &args) override {
+ if (!args.empty()) {
+ std::cerr << "Unexpected Arguments!" << std::endl;
+ return USAGE;
+ }
+ return OK;
+ }
+
+ Status doMain(Args && /*args*/) override {
+ std::string statusStr;
+ std::vector<CompositePrimitive> primitives;
+ Status ret;
+
+ if (auto hal = getHal<aidl::IVibrator>()) {
+ auto status = hal->call(&aidl::IVibrator::getSupportedPrimitives, &primitives);
+ statusStr = status.getDescription();
+ ret = status.isOk() ? OK : ERROR;
+ } else {
+ return UNAVAILABLE;
+ }
+
+ std::cout << "Status: " << statusStr << std::endl;
+ std::cout << "Primitives:" << std::endl;
+ for (auto &e : primitives) {
+ std::cout << " " << toString(e) << std::endl;
+ }
+
+ return ret;
+ }
+};
+
+static const auto Command =
+ CommandRegistry<CommandVibrator>::Register<CommandGetSupportedPrimitives>(
+ "getSupportedPrimitives");
+
+} // namespace vibrator
+} // namespace idlcli
+} // namespace android
diff --git a/cmds/idlcli/vibrator/CommandOn.cpp b/cmds/idlcli/vibrator/CommandOn.cpp
index 4e7e493..8212fc1 100644
--- a/cmds/idlcli/vibrator/CommandOn.cpp
+++ b/cmds/idlcli/vibrator/CommandOn.cpp
@@ -13,9 +13,14 @@
* limitations under the License.
*/
+#include <thread>
+
#include "utils.h"
#include "vibrator.h"
+using std::chrono::milliseconds;
+using std::this_thread::sleep_for;
+
namespace android {
namespace idlcli {
@@ -26,16 +31,28 @@
class CommandOn : public Command {
std::string getDescription() const override { return "Turn on vibrator."; }
- std::string getUsageSummary() const override { return "<duration>"; }
+ std::string getUsageSummary() const override { return "[options] <duration>"; }
UsageDetails getUsageDetails() const override {
UsageDetails details{
+ {"-b", {"Block for duration of vibration."}},
{"<duration>", {"In milliseconds."}},
};
return details;
}
Status doArgs(Args &args) override {
+ while (args.get<std::string>().value_or("").find("-") == 0) {
+ auto opt = *args.pop<std::string>();
+ if (opt == "--") {
+ break;
+ } else if (opt == "-b") {
+ mBlocking = true;
+ } else {
+ std::cerr << "Invalid Option '" << opt << "'!" << std::endl;
+ return USAGE;
+ }
+ }
if (auto duration = args.pop<decltype(mDuration)>()) {
mDuration = *duration;
} else {
@@ -52,9 +69,21 @@
Status doMain(Args && /*args*/) override {
std::string statusStr;
Status ret;
+ std::shared_ptr<VibratorCallback> callback;
if (auto hal = getHal<aidl::IVibrator>()) {
- auto status = hal->call(&aidl::IVibrator::on, mDuration, nullptr);
+ ABinderProcess_setThreadPoolMaxThreadCount(1);
+ ABinderProcess_startThreadPool();
+
+ int32_t cap;
+ hal->call(&aidl::IVibrator::getCapabilities, &cap);
+
+ if (mBlocking && (cap & aidl::IVibrator::CAP_ON_CALLBACK)) {
+ callback = ndk::SharedRefBase::make<VibratorCallback>();
+ }
+
+ auto status = hal->call(&aidl::IVibrator::on, mDuration, callback);
+
statusStr = status.getDescription();
ret = status.isOk() ? OK : ERROR;
} else if (auto hal = getHal<V1_0::IVibrator>()) {
@@ -65,11 +94,20 @@
return UNAVAILABLE;
}
+ if (ret == OK && mBlocking) {
+ if (callback) {
+ callback->waitForComplete();
+ } else {
+ sleep_for(milliseconds(mDuration));
+ }
+ }
+
std::cout << "Status: " << statusStr << std::endl;
return ret;
}
+ bool mBlocking;
uint32_t mDuration;
};
diff --git a/cmds/idlcli/vibrator/CommandPerform.cpp b/cmds/idlcli/vibrator/CommandPerform.cpp
index 69c7e37..c897686 100644
--- a/cmds/idlcli/vibrator/CommandPerform.cpp
+++ b/cmds/idlcli/vibrator/CommandPerform.cpp
@@ -13,9 +13,14 @@
* limitations under the License.
*/
+#include <thread>
+
#include "utils.h"
#include "vibrator.h"
+using std::chrono::milliseconds;
+using std::this_thread::sleep_for;
+
namespace android {
namespace idlcli {
@@ -51,16 +56,17 @@
static_assert(static_cast<uint8_t>(V1_3::Effect::TEXTURE_TICK) ==
static_cast<uint8_t>(aidl::Effect::TEXTURE_TICK));
-using V1_0::EffectStrength;
-using V1_3::Effect;
+using aidl::Effect;
+using aidl::EffectStrength;
class CommandPerform : public Command {
std::string getDescription() const override { return "Perform vibration effect."; }
- std::string getUsageSummary() const override { return "<effect> <strength>"; }
+ std::string getUsageSummary() const override { return "[options] <effect> <strength>"; }
UsageDetails getUsageDetails() const override {
UsageDetails details{
+ {"-b", {"Block for duration of vibration."}},
{"<effect>", {"Effect ID."}},
{"<strength>", {"0-2."}},
};
@@ -68,6 +74,17 @@
}
Status doArgs(Args &args) override {
+ while (args.get<std::string>().value_or("").find("-") == 0) {
+ auto opt = *args.pop<std::string>();
+ if (opt == "--") {
+ break;
+ } else if (opt == "-b") {
+ mBlocking = true;
+ } else {
+ std::cerr << "Invalid Option '" << opt << "'!" << std::endl;
+ return USAGE;
+ }
+ }
if (auto effect = args.pop<decltype(mEffect)>()) {
mEffect = *effect;
std::cout << "Effect: " << toString(mEffect) << std::endl;
@@ -93,12 +110,23 @@
std::string statusStr;
uint32_t lengthMs;
Status ret;
+ std::shared_ptr<VibratorCallback> callback;
if (auto hal = getHal<aidl::IVibrator>()) {
+ ABinderProcess_setThreadPoolMaxThreadCount(1);
+ ABinderProcess_startThreadPool();
+
+ int32_t cap;
+ hal->call(&aidl::IVibrator::getCapabilities, &cap);
+
+ if (mBlocking && (cap & aidl::IVibrator::CAP_PERFORM_CALLBACK)) {
+ callback = ndk::SharedRefBase::make<VibratorCallback>();
+ }
+
int32_t aidlLengthMs;
- auto status =
- hal->call(&aidl::IVibrator::perform, static_cast<aidl::Effect>(mEffect),
- static_cast<aidl::EffectStrength>(mStrength), nullptr, &aidlLengthMs);
+ auto status = hal->call(&aidl::IVibrator::perform, mEffect, mStrength, callback,
+ &aidlLengthMs);
+
statusStr = status.getDescription();
lengthMs = static_cast<uint32_t>(aidlLengthMs);
ret = status.isOk() ? OK : ERROR;
@@ -111,17 +139,20 @@
};
if (auto hal = getHal<V1_3::IVibrator>()) {
- hidlRet = hal->call(&V1_3::IVibrator::perform_1_3,
- static_cast<V1_3::Effect>(mEffect), mStrength, callback);
+ hidlRet =
+ hal->call(&V1_3::IVibrator::perform_1_3, static_cast<V1_3::Effect>(mEffect),
+ static_cast<V1_0::EffectStrength>(mStrength), callback);
} else if (auto hal = getHal<V1_2::IVibrator>()) {
- hidlRet = hal->call(&V1_2::IVibrator::perform_1_2,
- static_cast<V1_2::Effect>(mEffect), mStrength, callback);
+ hidlRet =
+ hal->call(&V1_2::IVibrator::perform_1_2, static_cast<V1_2::Effect>(mEffect),
+ static_cast<V1_0::EffectStrength>(mStrength), callback);
} else if (auto hal = getHal<V1_1::IVibrator>()) {
hidlRet = hal->call(&V1_1::IVibrator::perform_1_1,
- static_cast<V1_1::Effect_1_1>(mEffect), mStrength, callback);
+ static_cast<V1_1::Effect_1_1>(mEffect),
+ static_cast<V1_0::EffectStrength>(mStrength), callback);
} else if (auto hal = getHal<V1_0::IVibrator>()) {
hidlRet = hal->call(&V1_0::IVibrator::perform, static_cast<V1_0::Effect>(mEffect),
- mStrength, callback);
+ static_cast<V1_0::EffectStrength>(mStrength), callback);
} else {
return UNAVAILABLE;
}
@@ -130,12 +161,21 @@
ret = hidlRet.isOk() && status == V1_0::Status::OK ? OK : ERROR;
}
+ if (ret == OK && mBlocking) {
+ if (callback) {
+ callback->waitForComplete();
+ } else {
+ sleep_for(milliseconds(lengthMs));
+ }
+ }
+
std::cout << "Status: " << statusStr << std::endl;
std::cout << "Length: " << lengthMs << std::endl;
return ret;
}
+ bool mBlocking;
Effect mEffect;
EffectStrength mStrength;
};
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index 0782b43..e7014c8 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -2246,7 +2246,7 @@
#if CRATE_DEBUG
LOG(WARNING) << "retVector.size() =" << retVector.size();
for (auto& item : retVector) {
- CrateManager::dump(item);
+ CrateManager::dump(*item);
}
#endif
@@ -2278,7 +2278,7 @@
if (cratedFolder == nullptr) {
return;
}
- retVector->push_back(std::move(crateMetadata));
+ retVector.push_back(std::move(crateMetadata));
};
std::function<void(FTSENT*)> onHandingPackage = [&](FTSENT* packageDir) -> void {
@@ -2290,7 +2290,7 @@
#if CRATE_DEBUG
LOG(DEBUG) << "retVector.size() =" << retVector.size();
for (auto& item : retVector) {
- CrateManager::dump(item);
+ CrateManager::dump(*item);
}
#endif
diff --git a/cmds/installd/binder/android/os/IInstalld.aidl b/cmds/installd/binder/android/os/IInstalld.aidl
index 4ac70a4..eeda6c5 100644
--- a/cmds/installd/binder/android/os/IInstalld.aidl
+++ b/cmds/installd/binder/android/os/IInstalld.aidl
@@ -117,10 +117,11 @@
int userId, int snapshotId, int storageFlags);
void restoreAppDataSnapshot(@nullable @utf8InCpp String uuid, in @utf8InCpp String packageName,
int appId, @utf8InCpp String seInfo, int user, int snapshotId, int storageflags);
- void destroyCeSnapshotsNotSpecified(@nullable @utf8InCpp String uuid, int userId,
- in int[] retainSnapshotIds);
void destroyAppDataSnapshot(@nullable @utf8InCpp String uuid, @utf8InCpp String packageName,
int userId, long ceSnapshotInode, int snapshotId, int storageFlags);
+ void destroyCeSnapshotsNotSpecified(@nullable @utf8InCpp String uuid, int userId,
+ in int[] retainSnapshotIds);
+
void tryMountDataMirror(@nullable @utf8InCpp String volumeUuid);
void onPrivateVolumeRemoved(@nullable @utf8InCpp String volumeUuid);
diff --git a/include/android/input.h b/include/android/input.h
index dbfd61e..7c39234 100644
--- a/include/android/input.h
+++ b/include/android/input.h
@@ -55,6 +55,7 @@
#include <sys/types.h>
#include <android/keycodes.h>
#include <android/looper.h>
+#include <jni.h>
#if !defined(__INTRODUCED_IN)
#define __INTRODUCED_IN(__api_level) /* nothing */
@@ -931,6 +932,15 @@
/** Get the input event source. */
int32_t AInputEvent_getSource(const AInputEvent* event);
+/**
+ * Releases interface objects created by {@link AKeyEvent_fromJava()}
+ * and {@link AMotionEvent_fromJava()}.
+ * After returning, the specified AInputEvent* object becomes invalid and should no longer be used.
+ * The underlying Java object remains valid and does not change its state.
+ */
+
+void AInputEvent_release(const AInputEvent* event);
+
/*** Accessors for key events only. ***/
/** Get the key event action. */
@@ -977,6 +987,15 @@
*/
int64_t AKeyEvent_getEventTime(const AInputEvent* key_event);
+/**
+ * Creates a native AInputEvent* object associated with the specified Java android.view.KeyEvent.
+ * The result may be used with generic and KeyEvent-specific AInputEvent_* functions.
+ * The object returned by this function must be disposed using {@link AInputEvent_release()}.
+ * User must guarantee that lifetime for object referenced by keyEvent is prolongated
+ * up to release of returned AInputEvent*.
+ */
+const AInputEvent* AKeyEvent_fromJava(JNIEnv* env, jobject keyEvent);
+
/*** Accessors for motion events only. ***/
/** Get the combined motion event action code and pointer index. */
@@ -1292,6 +1311,14 @@
float AMotionEvent_getHistoricalAxisValue(const AInputEvent* motion_event,
int32_t axis, size_t pointer_index, size_t history_index);
+/**
+ * Creates a native AInputEvent* object associated with the specified Java android.view.MotionEvent.
+ * The result may be used with generic and MotionEvent-specific AInputEvent_* functions.
+ * The object returned by this function must be disposed using {@link AInputEvent_release()}.
+ * User must guarantee that object referenced by motionEvent won't be recycled and
+ * its lifetime is prolongated up to release of returned AInputEvent*.
+ */
+const AInputEvent* AMotionEvent_fromJava(JNIEnv* env, jobject motionEvent);
struct AInputQueue;
/**
diff --git a/include/input/DisplayViewport.h b/include/input/DisplayViewport.h
index 2427a07..334fe34 100644
--- a/include/input/DisplayViewport.h
+++ b/include/input/DisplayViewport.h
@@ -17,12 +17,12 @@
#ifndef _LIBINPUT_DISPLAY_VIEWPORT_H
#define _LIBINPUT_DISPLAY_VIEWPORT_H
-#include <cinttypes>
-#include <optional>
-
#include <android-base/stringprintf.h>
#include <input/Input.h>
+#include <cinttypes>
+#include <optional>
+
using android::base::StringPrintf;
namespace android {
@@ -39,22 +39,21 @@
* Keep in sync with values in InputManagerService.java.
*/
enum class ViewportType : int32_t {
- VIEWPORT_INTERNAL = 1,
- VIEWPORT_EXTERNAL = 2,
- VIEWPORT_VIRTUAL = 3,
+ INTERNAL = 1,
+ EXTERNAL = 2,
+ VIRTUAL = 3,
};
static const char* viewportTypeToString(ViewportType type) {
- switch(type) {
- case ViewportType::VIEWPORT_INTERNAL:
+ switch (type) {
+ case ViewportType::INTERNAL:
return "INTERNAL";
- case ViewportType::VIEWPORT_EXTERNAL:
+ case ViewportType::EXTERNAL:
return "EXTERNAL";
- case ViewportType::VIEWPORT_VIRTUAL:
+ case ViewportType::VIRTUAL:
return "VIRTUAL";
- default:
- return "UNKNOWN";
}
+ return "UNKNOWN";
}
/*
@@ -97,7 +96,7 @@
isActive(false),
uniqueId(),
physicalPort(std::nullopt),
- type(ViewportType::VIEWPORT_INTERNAL) {}
+ type(ViewportType::INTERNAL) {}
bool operator==(const DisplayViewport& other) const {
return displayId == other.displayId && orientation == other.orientation &&
@@ -134,7 +133,7 @@
isActive = false;
uniqueId.clear();
physicalPort = std::nullopt;
- type = ViewportType::VIEWPORT_INTERNAL;
+ type = ViewportType::INTERNAL;
}
std::string toString() const {
diff --git a/include/input/IInputFlinger.h b/include/input/IInputFlinger.h
deleted file mode 100644
index d23e3b7..0000000
--- a/include/input/IInputFlinger.h
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (C) 2013 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 _LIBINPUT_IINPUT_FLINGER_H
-#define _LIBINPUT_IINPUT_FLINGER_H
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <binder/IInterface.h>
-
-#include <input/InputWindow.h>
-#include <input/ISetInputWindowsListener.h>
-
-namespace android {
-
-/*
- * This class defines the Binder IPC interface for accessing various
- * InputFlinger features.
- */
-class IInputFlinger : public IInterface {
-public:
- DECLARE_META_INTERFACE(InputFlinger)
-
- virtual void setInputWindows(const std::vector<InputWindowInfo>& inputHandles,
- const sp<ISetInputWindowsListener>& setInputWindowsListener) = 0;
- virtual void registerInputChannel(const sp<InputChannel>& channel) = 0;
- virtual void unregisterInputChannel(const sp<InputChannel>& channel) = 0;
-};
-
-
-/**
- * Binder implementation.
- */
-class BnInputFlinger : public BnInterface<IInputFlinger> {
-public:
- enum {
- SET_INPUT_WINDOWS_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION,
- REGISTER_INPUT_CHANNEL_TRANSACTION,
- UNREGISTER_INPUT_CHANNEL_TRANSACTION
- };
-
- virtual status_t onTransact(uint32_t code, const Parcel& data,
- Parcel* reply, uint32_t flags = 0);
-};
-
-} // namespace android
-
-#endif // _LIBINPUT_IINPUT_FLINGER_H
diff --git a/include/input/ISetInputWindowsListener.h b/include/input/ISetInputWindowsListener.h
deleted file mode 100644
index 15d31b2..0000000
--- a/include/input/ISetInputWindowsListener.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <binder/IInterface.h>
-#include <binder/Parcel.h>
-
-namespace android {
-
-class ISetInputWindowsListener : public IInterface {
-public:
- DECLARE_META_INTERFACE(SetInputWindowsListener)
- virtual void onSetInputWindowsFinished() = 0;
-};
-
-class BnSetInputWindowsListener: public BnInterface<ISetInputWindowsListener> {
-public:
- enum SetInputWindowsTag : uint32_t {
- ON_SET_INPUT_WINDOWS_FINISHED
- };
-
- virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply,
- uint32_t flags = 0) override;
-};
-
-}; // namespace android
diff --git a/include/input/Input.h b/include/input/Input.h
index 54b4e5a..ac901ae 100644
--- a/include/input/Input.h
+++ b/include/input/Input.h
@@ -280,9 +280,9 @@
public:
// Used to divide integer space to ensure no conflict among these sources./
enum class Source : int32_t {
- INPUT_READER = 0x0 << SOURCE_SHIFT,
- INPUT_DISPATCHER = 0x1 << SOURCE_SHIFT,
- OTHER = 0x3 << SOURCE_SHIFT, // E.g. app injected events
+ INPUT_READER = static_cast<int32_t>(0x0u << SOURCE_SHIFT),
+ INPUT_DISPATCHER = static_cast<int32_t>(0x1u << SOURCE_SHIFT),
+ OTHER = static_cast<int32_t>(0x3u << SOURCE_SHIFT), // E.g. app injected events
};
IdGenerator(Source source);
@@ -294,7 +294,7 @@
private:
const Source mSource;
- static constexpr int32_t SOURCE_MASK = 0x3 << SOURCE_SHIFT;
+ static constexpr int32_t SOURCE_MASK = static_cast<int32_t>(0x3u << SOURCE_SHIFT);
};
/**
diff --git a/include/input/InputApplication.h b/include/input/InputApplication.h
index 86de394..b6b9353 100644
--- a/include/input/InputApplication.h
+++ b/include/input/InputApplication.h
@@ -21,6 +21,7 @@
#include <binder/IBinder.h>
#include <binder/Parcel.h>
+#include <binder/Parcelable.h>
#include <input/Input.h>
#include <utils/RefBase.h>
@@ -31,16 +32,18 @@
/*
* Describes the properties of an application that can receive input.
*/
-struct InputApplicationInfo {
+struct InputApplicationInfo : public Parcelable {
sp<IBinder> token;
std::string name;
- nsecs_t dispatchingTimeout;
+ std::chrono::nanoseconds dispatchingTimeout;
- status_t write(Parcel& output) const;
- static InputApplicationInfo read(const Parcel& from);
+ InputApplicationInfo() = default;
+
+ status_t readFromParcel(const android::Parcel* parcel) override;
+
+ status_t writeToParcel(android::Parcel* parcel) const override;
};
-
/*
* Handle for an application that can receive input.
*
@@ -57,10 +60,6 @@
return !mInfo.name.empty() ? mInfo.name : "<invalid>";
}
- inline nsecs_t getDispatchingTimeout(nsecs_t defaultValue) const {
- return mInfo.token ? mInfo.dispatchingTimeout : defaultValue;
- }
-
inline std::chrono::nanoseconds getDispatchingTimeout(
std::chrono::nanoseconds defaultValue) const {
return mInfo.token ? std::chrono::nanoseconds(mInfo.dispatchingTimeout) : defaultValue;
@@ -80,6 +79,7 @@
* Returns true on success, or false if the handle is no longer valid.
*/
virtual bool updateInfo() = 0;
+
protected:
InputApplicationHandle();
virtual ~InputApplicationHandle();
diff --git a/include/input/InputDevice.h b/include/input/InputDevice.h
index 20a17e3..c7685b7 100644
--- a/include/input/InputDevice.h
+++ b/include/input/InputDevice.h
@@ -144,10 +144,10 @@
};
/* Types of input device configuration files. */
-enum InputDeviceConfigurationFileType {
- INPUT_DEVICE_CONFIGURATION_FILE_TYPE_CONFIGURATION = 0, /* .idc file */
- INPUT_DEVICE_CONFIGURATION_FILE_TYPE_KEY_LAYOUT = 1, /* .kl file */
- INPUT_DEVICE_CONFIGURATION_FILE_TYPE_KEY_CHARACTER_MAP = 2, /* .kcm file */
+enum class InputDeviceConfigurationFileType : int32_t {
+ CONFIGURATION = 0, /* .idc file */
+ KEY_LAYOUT = 1, /* .kl file */
+ KEY_CHARACTER_MAP = 2, /* .kcm file */
};
/*
diff --git a/include/input/InputTransport.h b/include/input/InputTransport.h
index 7ca9031..0219cf7 100644
--- a/include/input/InputTransport.h
+++ b/include/input/InputTransport.h
@@ -34,7 +34,9 @@
#include <android-base/chrono_utils.h>
#include <binder/IBinder.h>
+#include <binder/Parcelable.h>
#include <input/Input.h>
+#include <sys/stat.h>
#include <utils/BitSet.h>
#include <utils/Errors.h>
#include <utils/RefBase.h>
@@ -174,6 +176,18 @@
void getSanitizedCopy(InputMessage* msg) const;
};
+struct InputChannelInfo : public Parcelable {
+ std::string mName;
+ android::base::unique_fd mFd;
+ sp<IBinder> mToken;
+
+ InputChannelInfo() = default;
+ InputChannelInfo(const std::string& name, android::base::unique_fd fd, sp<IBinder> token)
+ : mName(name), mFd(std::move(fd)), mToken(token){};
+ status_t readFromParcel(const android::Parcel* parcel) override;
+ status_t writeToParcel(android::Parcel* parcel) const override;
+};
+
/*
* An input channel consists of a local unix domain socket used to send and receive
* input messages across processes. Each channel has a descriptive name for debugging purposes.
@@ -183,10 +197,10 @@
* The input channel is closed when all references to it are released.
*/
class InputChannel : public RefBase {
-protected:
+public:
+ InputChannel();
virtual ~InputChannel();
-public:
static sp<InputChannel> create(const std::string& name, android::base::unique_fd fd,
sp<IBinder> token);
@@ -200,8 +214,10 @@
static status_t openInputChannelPair(const std::string& name,
sp<InputChannel>& outServerChannel, sp<InputChannel>& outClientChannel);
- inline std::string getName() const { return mName; }
- inline int getFd() const { return mFd.get(); }
+ inline std::string getName() const { return mInfo.mName; }
+ inline int getFd() const { return mInfo.mFd.get(); }
+ inline sp<IBinder> getToken() const { return mInfo.mToken; }
+ inline InputChannelInfo& getInfo() { return mInfo; }
/* Send a message to the other endpoint.
*
@@ -231,8 +247,9 @@
/* Return a new object that has a duplicate of this channel's fd. */
sp<InputChannel> dup() const;
- status_t write(Parcel& out) const;
- static sp<InputChannel> read(const Parcel& from);
+ status_t readFromParcel(const android::Parcel* parcel);
+
+ status_t writeToParcel(android::Parcel* parcel) const;
/**
* The connection token is used to identify the input connection, i.e.
@@ -248,12 +265,23 @@
*/
sp<IBinder> getConnectionToken() const;
+ bool operator==(const InputChannel& inputChannel) const {
+ struct stat lhsInfo, rhsInfo;
+ if (fstat(mInfo.mFd.get(), &lhsInfo) != 0) {
+ return false;
+ }
+ if (fstat(inputChannel.getFd(), &rhsInfo) != 0) {
+ return false;
+ }
+ // If file descriptors are pointing to same inode they are duplicated fds.
+ return inputChannel.getName() == getName() &&
+ inputChannel.getConnectionToken() == mInfo.mToken &&
+ lhsInfo.st_ino == rhsInfo.st_ino;
+ }
+
private:
InputChannel(const std::string& name, android::base::unique_fd fd, sp<IBinder> token);
- std::string mName;
- android::base::unique_fd mFd;
-
- sp<IBinder> mToken;
+ InputChannelInfo mInfo;
};
/*
@@ -325,7 +353,6 @@
status_t receiveFinishedSignal(uint32_t* outSeq, bool* outHandled);
private:
-
sp<InputChannel> mChannel;
};
diff --git a/include/input/InputWindow.h b/include/input/InputWindow.h
index 2dac5b6..582e73d 100644
--- a/include/input/InputWindow.h
+++ b/include/input/InputWindow.h
@@ -17,6 +17,8 @@
#ifndef _UI_INPUT_WINDOW_H
#define _UI_INPUT_WINDOW_H
+#include <binder/Parcel.h>
+#include <binder/Parcelable.h>
#include <input/Input.h>
#include <input/InputTransport.h>
#include <ui/Rect.h>
@@ -27,33 +29,31 @@
#include "InputApplication.h"
namespace android {
-class Parcel;
/*
* Describes the properties of a window that can receive input.
*/
-struct InputWindowInfo {
+struct InputWindowInfo : public Parcelable {
InputWindowInfo() = default;
- InputWindowInfo(const Parcel& from);
// Window flags from WindowManager.LayoutParams
- enum {
- FLAG_ALLOW_LOCK_WHILE_SCREEN_ON = 0x00000001,
- FLAG_DIM_BEHIND = 0x00000002,
- FLAG_BLUR_BEHIND = 0x00000004,
- FLAG_NOT_FOCUSABLE = 0x00000008,
- FLAG_NOT_TOUCHABLE = 0x00000010,
- FLAG_NOT_TOUCH_MODAL = 0x00000020,
+ enum : uint32_t {
+ FLAG_ALLOW_LOCK_WHILE_SCREEN_ON = 0x00000001,
+ FLAG_DIM_BEHIND = 0x00000002,
+ FLAG_BLUR_BEHIND = 0x00000004,
+ FLAG_NOT_FOCUSABLE = 0x00000008,
+ FLAG_NOT_TOUCHABLE = 0x00000010,
+ FLAG_NOT_TOUCH_MODAL = 0x00000020,
FLAG_TOUCHABLE_WHEN_WAKING = 0x00000040,
- FLAG_KEEP_SCREEN_ON = 0x00000080,
- FLAG_LAYOUT_IN_SCREEN = 0x00000100,
- FLAG_LAYOUT_NO_LIMITS = 0x00000200,
- FLAG_FULLSCREEN = 0x00000400,
- FLAG_FORCE_NOT_FULLSCREEN = 0x00000800,
- FLAG_DITHER = 0x00001000,
- FLAG_SECURE = 0x00002000,
- FLAG_SCALED = 0x00004000,
- FLAG_IGNORE_CHEEK_PRESSES = 0x00008000,
+ FLAG_KEEP_SCREEN_ON = 0x00000080,
+ FLAG_LAYOUT_IN_SCREEN = 0x00000100,
+ FLAG_LAYOUT_NO_LIMITS = 0x00000200,
+ FLAG_FULLSCREEN = 0x00000400,
+ FLAG_FORCE_NOT_FULLSCREEN = 0x00000800,
+ FLAG_DITHER = 0x00001000,
+ FLAG_SECURE = 0x00002000,
+ FLAG_SCALED = 0x00004000,
+ FLAG_IGNORE_CHEEK_PRESSES = 0x00008000,
FLAG_LAYOUT_INSET_DECOR = 0x00010000,
FLAG_ALT_FOCUSABLE_IM = 0x00020000,
FLAG_WATCH_OUTSIDE_TOUCH = 0x00040000,
@@ -62,7 +62,14 @@
FLAG_TURN_SCREEN_ON = 0x00200000,
FLAG_DISMISS_KEYGUARD = 0x00400000,
FLAG_SPLIT_TOUCH = 0x00800000,
+ FLAG_HARDWARE_ACCELERATED = 0x01000000,
+ FLAG_LAYOUT_IN_OVERSCAN = 0x02000000,
+ FLAG_TRANSLUCENT_STATUS = 0x04000000,
+ FLAG_TRANSLUCENT_NAVIGATION = 0x08000000,
+ FLAG_LOCAL_FOCUS_MODE = 0x10000000,
FLAG_SLIPPERY = 0x20000000,
+ FLAG_LAYOUT_ATTACHED_IN_DECOR = 0x40000000,
+ FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS = 0x80000000,
};
// Window types from WindowManager.LayoutParams
@@ -107,8 +114,8 @@
TYPE_MAGNIFICATION_OVERLAY = FIRST_SYSTEM_WINDOW + 27,
TYPE_ACCESSIBILITY_OVERLAY = FIRST_SYSTEM_WINDOW + 32,
TYPE_DOCK_DIVIDER = FIRST_SYSTEM_WINDOW + 34,
+ TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY = FIRST_SYSTEM_WINDOW + 39,
TYPE_NOTIFICATION_SHADE = FIRST_SYSTEM_WINDOW + 40,
- TYPE_TRUSTED_APPLICATION_OVERLAY = FIRST_SYSTEM_WINDOW + 42,
LAST_SYSTEM_WINDOW = 2999,
};
@@ -129,7 +136,7 @@
std::string name;
int32_t layoutParamsFlags = 0;
int32_t layoutParamsType = 0;
- nsecs_t dispatchingTimeout = -1;
+ std::chrono::nanoseconds dispatchingTimeout = std::chrono::seconds(5);
/* These values are filled in by SurfaceFlinger. */
int32_t frameLeft = -1;
@@ -163,6 +170,12 @@
bool hasFocus = false;
bool hasWallpaper = false;
bool paused = false;
+ /* This flag is set when the window is of a trusted type that is allowed to silently
+ * overlay other windows for the purpose of implementing the secure views feature.
+ * Trusted overlays, such as IME windows, can partly obscure other windows without causing
+ * motion events to be delivered to them with AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED.
+ */
+ bool trustedOverlay = false;
int32_t ownerPid = -1;
int32_t ownerUid = -1;
int32_t inputFeatures = 0;
@@ -175,23 +188,21 @@
void addTouchableRegion(const Rect& region);
bool touchableRegionContainsPoint(int32_t x, int32_t y) const;
- bool frameContainsPoint(int32_t x, int32_t y) const;
- /* Returns true if the window is of a trusted type that is allowed to silently
- * overlay other windows for the purpose of implementing the secure views feature.
- * Trusted overlays, such as IME windows, can partly obscure other windows without causing
- * motion events to be delivered to them with AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED.
- */
- bool isTrustedOverlay() const;
+ bool frameContainsPoint(int32_t x, int32_t y) const;
bool supportsSplitTouch() const;
bool overlaps(const InputWindowInfo* other) const;
- status_t write(Parcel& output) const;
- static InputWindowInfo read(const Parcel& from);
+ bool operator==(const InputWindowInfo& inputChannel) const;
+
+ status_t writeToParcel(android::Parcel* parcel) const override;
+
+ status_t readFromParcel(const android::Parcel* parcel) override;
};
+std::string inputWindowFlagsToString(uint32_t flags);
/*
* Handle for a window that can receive input.
@@ -201,26 +212,19 @@
*/
class InputWindowHandle : public RefBase {
public:
+ explicit InputWindowHandle();
+ InputWindowHandle(const InputWindowHandle& other);
+ InputWindowHandle(const InputWindowInfo& other);
- inline const InputWindowInfo* getInfo() const {
- return &mInfo;
- }
+ inline const InputWindowInfo* getInfo() const { return &mInfo; }
sp<IBinder> getToken() const;
int32_t getId() const { return mInfo.id; }
- sp<IBinder> getApplicationToken() {
- return mInfo.applicationInfo.token;
- }
+ sp<IBinder> getApplicationToken() { return mInfo.applicationInfo.token; }
- inline std::string getName() const {
- return !mInfo.name.empty() ? mInfo.name : "<invalid>";
- }
-
- inline nsecs_t getDispatchingTimeout(nsecs_t defaultValue) const {
- return mInfo.token ? mInfo.dispatchingTimeout : defaultValue;
- }
+ inline std::string getName() const { return !mInfo.name.empty() ? mInfo.name : "<invalid>"; }
inline std::chrono::nanoseconds getDispatchingTimeout(
std::chrono::nanoseconds defaultValue) const {
@@ -230,13 +234,14 @@
/**
* Requests that the state of this object be updated to reflect
* the most current available information about the application.
+ * As this class is created as RefBase object, no pure virtual function is allowed.
*
* This method should only be called from within the input dispatcher's
* critical section.
*
* Returns true on success, or false if the handle is no longer valid.
*/
- virtual bool updateInfo() = 0;
+ virtual bool updateInfo() { return false; }
/**
* Updates from another input window handle.
@@ -249,8 +254,11 @@
*/
void releaseChannel();
+ // Not override since this class is not derrived from Parcelable.
+ status_t readFromParcel(const android::Parcel* parcel);
+ status_t writeToParcel(android::Parcel* parcel) const;
+
protected:
- explicit InputWindowHandle();
virtual ~InputWindowHandle();
InputWindowInfo mInfo;
diff --git a/include/input/VelocityTracker.h b/include/input/VelocityTracker.h
index 727865a..ee010a3 100644
--- a/include/input/VelocityTracker.h
+++ b/include/input/VelocityTracker.h
@@ -18,8 +18,8 @@
#define _LIBINPUT_VELOCITY_TRACKER_H
#include <input/Input.h>
-#include <utils/Timers.h>
#include <utils/BitSet.h>
+#include <utils/Timers.h>
namespace android {
@@ -30,6 +30,22 @@
*/
class VelocityTracker {
public:
+ enum class Strategy : int32_t {
+ DEFAULT = -1,
+ MIN = 0,
+ IMPULSE = 0,
+ LSQ1 = 1,
+ LSQ2 = 2,
+ LSQ3 = 3,
+ WLSQ2_DELTA = 4,
+ WLSQ2_CENTRAL = 5,
+ WLSQ2_RECENT = 6,
+ INT1 = 7,
+ INT2 = 8,
+ LEGACY = 9,
+ MAX = LEGACY,
+ };
+
struct Position {
float x, y;
};
@@ -62,8 +78,8 @@
};
// Creates a velocity tracker using the specified strategy.
- // If strategy is NULL, uses the default strategy for the platform.
- VelocityTracker(const char* strategy = nullptr);
+ // If strategy is not provided, uses the default strategy for the platform.
+ VelocityTracker(const Strategy strategy = Strategy::DEFAULT);
~VelocityTracker();
@@ -102,16 +118,21 @@
inline BitSet32 getCurrentPointerIdBits() const { return mCurrentPointerIdBits; }
private:
- static const char* DEFAULT_STRATEGY;
+ // The default velocity tracker strategy.
+ // Although other strategies are available for testing and comparison purposes,
+ // this is the strategy that applications will actually use. Be very careful
+ // when adjusting the default strategy because it can dramatically affect
+ // (often in a bad way) the user experience.
+ static const Strategy DEFAULT_STRATEGY = Strategy::LSQ2;
nsecs_t mLastEventTime;
BitSet32 mCurrentPointerIdBits;
int32_t mActivePointerId;
- VelocityTrackerStrategy* mStrategy;
+ std::unique_ptr<VelocityTrackerStrategy> mStrategy;
- bool configureStrategy(const char* strategy);
+ bool configureStrategy(const Strategy strategy);
- static VelocityTrackerStrategy* createStrategy(const char* strategy);
+ static std::unique_ptr<VelocityTrackerStrategy> createStrategy(const Strategy strategy);
};
diff --git a/include/powermanager/IPowerManager.h b/include/powermanager/IPowerManager.h
deleted file mode 100644
index 964e318..0000000
--- a/include/powermanager/IPowerManager.h
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright (C) 2011 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_IPOWERMANAGER_H
-#define ANDROID_IPOWERMANAGER_H
-
-#include <utils/Errors.h>
-#include <binder/IInterface.h>
-#include <hardware/power.h>
-
-namespace android {
-
-// ----------------------------------------------------------------------------
-
-class IPowerManager : public IInterface
-{
-public:
- // These transaction IDs must be kept in sync with the method order from
- // IPowerManager.aidl.
- enum {
- ACQUIRE_WAKE_LOCK = IBinder::FIRST_CALL_TRANSACTION,
- ACQUIRE_WAKE_LOCK_UID = IBinder::FIRST_CALL_TRANSACTION + 1,
- RELEASE_WAKE_LOCK = IBinder::FIRST_CALL_TRANSACTION + 2,
- UPDATE_WAKE_LOCK_UIDS = IBinder::FIRST_CALL_TRANSACTION + 3,
- POWER_HINT = IBinder::FIRST_CALL_TRANSACTION + 4,
- UPDATE_WAKE_LOCK_SOURCE = IBinder::FIRST_CALL_TRANSACTION + 5,
- IS_WAKE_LOCK_LEVEL_SUPPORTED = IBinder::FIRST_CALL_TRANSACTION + 6,
- USER_ACTIVITY = IBinder::FIRST_CALL_TRANSACTION + 7,
- WAKE_UP = IBinder::FIRST_CALL_TRANSACTION + 8,
- GO_TO_SLEEP = IBinder::FIRST_CALL_TRANSACTION + 9,
- NAP = IBinder::FIRST_CALL_TRANSACTION + 10,
- IS_INTERACTIVE = IBinder::FIRST_CALL_TRANSACTION + 11,
- IS_POWER_SAVE_MODE = IBinder::FIRST_CALL_TRANSACTION + 12,
- GET_POWER_SAVE_STATE = IBinder::FIRST_CALL_TRANSACTION + 13,
- SET_POWER_SAVE_MODE_ENABLED = IBinder::FIRST_CALL_TRANSACTION + 14,
- REBOOT = IBinder::FIRST_CALL_TRANSACTION + 21,
- REBOOT_SAFE_MODE = IBinder::FIRST_CALL_TRANSACTION + 22,
- SHUTDOWN = IBinder::FIRST_CALL_TRANSACTION + 23,
- CRASH = IBinder::FIRST_CALL_TRANSACTION + 24,
- };
-
- DECLARE_META_INTERFACE(PowerManager)
-
- // The parcels created by these methods must be kept in sync with the
- // corresponding methods from IPowerManager.aidl.
- // FIXME remove the bool isOneWay parameters as they are not oneway in the .aidl
- virtual status_t acquireWakeLock(int flags, const sp<IBinder>& lock, const String16& tag,
- const String16& packageName, bool isOneWay = false) = 0;
- virtual status_t acquireWakeLockWithUid(int flags, const sp<IBinder>& lock, const String16& tag,
- const String16& packageName, int uid, bool isOneWay = false) = 0;
- virtual status_t releaseWakeLock(const sp<IBinder>& lock, int flags, bool isOneWay = false) = 0;
- virtual status_t updateWakeLockUids(const sp<IBinder>& lock, int len, const int *uids,
- bool isOneWay = false) = 0;
- virtual status_t powerHint(int hintId, int data) = 0;
- virtual status_t goToSleep(int64_t event_time_ms, int reason, int flags) = 0;
- virtual status_t reboot(bool confirm, const String16& reason, bool wait) = 0;
- virtual status_t shutdown(bool confirm, const String16& reason, bool wait) = 0;
- virtual status_t crash(const String16& message) = 0;
-};
-
-// ----------------------------------------------------------------------------
-
-}; // namespace android
-
-#endif // ANDROID_IPOWERMANAGER_H
diff --git a/include/powermanager/PowerHalController.h b/include/powermanager/PowerHalController.h
new file mode 100644
index 0000000..dd34c0a
--- /dev/null
+++ b/include/powermanager/PowerHalController.h
@@ -0,0 +1,79 @@
+/*
+ * 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_POWERHALCONTROLLER_H
+#define ANDROID_POWERHALCONTROLLER_H
+
+#include <android-base/thread_annotations.h>
+#include <android/hardware/power/Boost.h>
+#include <android/hardware/power/IPower.h>
+#include <android/hardware/power/Mode.h>
+#include <powermanager/PowerHalWrapper.h>
+
+namespace android {
+
+namespace power {
+
+// -------------------------------------------------------------------------------------------------
+
+// Connects to underlying Power HAL handles.
+class HalConnector {
+public:
+ HalConnector() = default;
+ virtual ~HalConnector() = default;
+
+ virtual std::unique_ptr<HalWrapper> connect();
+ virtual void reset();
+};
+
+// -------------------------------------------------------------------------------------------------
+
+// Controller for Power HAL handle.
+// 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<HalConnector>()) {}
+ explicit PowerHalController(std::unique_ptr<HalConnector> connector)
+ : mHalConnector(std::move(connector)) {}
+ virtual ~PowerHalController() = default;
+
+ void init();
+
+ 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<HalConnector> mHalConnector;
+
+ // 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<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
new file mode 100644
index 0000000..ed6f6f3
--- /dev/null
+++ b/include/powermanager/PowerHalLoader.h
@@ -0,0 +1,53 @@
+/*
+ * 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_POWERHALLOADER_H
+#define ANDROID_POWERHALLOADER_H
+
+#include <android-base/thread_annotations.h>
+#include <android/hardware/power/1.1/IPower.h>
+#include <android/hardware/power/IPower.h>
+
+namespace android {
+
+namespace power {
+
+// Loads available Power HAL services.
+class PowerHalLoader {
+public:
+ static void unloadAll();
+ 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<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<hardware::power::V1_0::IPower> loadHidlV1_0Locked()
+ EXCLUSIVE_LOCKS_REQUIRED(gHalMutex);
+
+ PowerHalLoader() = delete;
+ ~PowerHalLoader() = delete;
+};
+
+}; // namespace power
+
+} // namespace android
+
+#endif // ANDROID_POWERHALLOADER_H
diff --git a/include/powermanager/PowerHalWrapper.h b/include/powermanager/PowerHalWrapper.h
new file mode 100644
index 0000000..c3e7601
--- /dev/null
+++ b/include/powermanager/PowerHalWrapper.h
@@ -0,0 +1,128 @@
+/*
+ * 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_POWERHALWRAPPER_H
+#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>
+
+namespace android {
+
+namespace power {
+
+// State of Power HAL support for individual apis.
+enum class HalSupport {
+ UNKNOWN = 0,
+ ON = 1,
+ OFF = 2,
+};
+
+// State of the Power HAL api call result.
+enum class HalResult {
+ SUCCESSFUL = 0,
+ FAILED = 1,
+ UNSUPPORTED = 2,
+};
+
+// Wrapper for Power HAL handlers.
+class HalWrapper {
+public:
+ virtual ~HalWrapper() = default;
+
+ 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 EmptyHalWrapper : public HalWrapper {
+public:
+ EmptyHalWrapper() = default;
+ ~EmptyHalWrapper() = default;
+
+ 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 HidlHalWrapperV1_0 : public HalWrapper {
+public:
+ explicit HidlHalWrapperV1_0(sp<hardware::power::V1_0::IPower> Hal)
+ : mHandleV1_0(std::move(Hal)) {}
+ virtual ~HidlHalWrapperV1_0() = default;
+
+ virtual HalResult setBoost(hardware::power::Boost boost, int32_t durationMs) override;
+ virtual HalResult setMode(hardware::power::Mode mode, bool enabled) override;
+
+protected:
+ virtual HalResult sendPowerHint(hardware::power::V1_0::PowerHint hintId, uint32_t data);
+
+private:
+ 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 HidlHalWrapperV1_1 : public HidlHalWrapperV1_0 {
+public:
+ 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 HalResult sendPowerHint(hardware::power::V1_0::PowerHint hintId,
+ uint32_t data) override;
+
+private:
+ sp<hardware::power::V1_1::IPower> mHandleV1_1;
+};
+
+// Wrapper for the AIDL Power HAL.
+class AidlHalWrapper : public HalWrapper {
+public:
+ explicit AidlHalWrapper(sp<hardware::power::IPower> handle) : mHandle(std::move(handle)) {}
+ virtual ~AidlHalWrapper() = default;
+
+ 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<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<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<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/binder/ActivityManager.cpp b/libs/binder/ActivityManager.cpp
index 5e4c98f..d005058 100644
--- a/libs/binder/ActivityManager.cpp
+++ b/libs/binder/ActivityManager.cpp
@@ -98,6 +98,15 @@
return PROCESS_STATE_UNKNOWN;
}
+bool ActivityManager::setSchedPolicyCgroup(const int32_t tid, const int32_t group)
+{
+ sp<IActivityManager> service = getService();
+ if (service != nullptr) {
+ return service->setSchedPolicyCgroup(tid, group);
+ }
+ return false;
+}
+
status_t ActivityManager::linkToDeath(const sp<IBinder::DeathRecipient>& recipient) {
sp<IActivityManager> service = getService();
if (service != nullptr) {
diff --git a/libs/binder/IActivityManager.cpp b/libs/binder/IActivityManager.cpp
index 1eb5363..a3021122 100644
--- a/libs/binder/IActivityManager.cpp
+++ b/libs/binder/IActivityManager.cpp
@@ -104,6 +104,17 @@
}
return reply.readInt32();
}
+
+ virtual bool setSchedPolicyCgroup(const int32_t tid, const int32_t group)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IActivityManager::getInterfaceDescriptor());
+ data.writeInt32(tid);
+ data.writeInt32(group);
+ remote()->transact(SET_SCHED_POLICY_CGROUP_TRANSACTION, data, &reply);
+ if (reply.readExceptionCode() != 0) return false;
+ return reply.readBool();
+ }
};
// ------------------------------------------------------------------------------------
diff --git a/libs/binder/fuzzer/binder.cpp b/libs/binder/fuzzer/binder.cpp
index 52c730c..8c0495c 100644
--- a/libs/binder/fuzzer/binder.cpp
+++ b/libs/binder/fuzzer/binder.cpp
@@ -135,6 +135,7 @@
PARCEL_READ_WITH_STATUS(std::string, readUtf8FromUtf16),
PARCEL_READ_WITH_STATUS(std::unique_ptr<std::string>, readUtf8FromUtf16),
+ PARCEL_READ_WITH_STATUS(std::optional<std::string>, readUtf8FromUtf16),
[] (const ::android::Parcel& p, uint8_t /*data*/) {
FUZZ_LOG() << "about to read c-str";
const char* str = p.readCString();
@@ -143,6 +144,7 @@
PARCEL_READ_OPT_STATUS(android::String8, readString8),
PARCEL_READ_OPT_STATUS(android::String16, readString16),
PARCEL_READ_WITH_STATUS(std::unique_ptr<android::String16>, readString16),
+ PARCEL_READ_WITH_STATUS(std::optional<android::String16>, readString16),
[] (const ::android::Parcel& p, uint8_t /*data*/) {
FUZZ_LOG() << "about to readString16Inplace";
size_t outLen = 0;
@@ -156,17 +158,22 @@
// TODO(b/131868573): can force read of arbitrarily sized vector
// PARCEL_READ_WITH_STATUS(std::vector<ByteEnum>, readEnumVector),
// PARCEL_READ_WITH_STATUS(std::unique_ptr<std::vector<ByteEnum>>, readEnumVector),
+ // PARCEL_READ_WITH_STATUS(std::optional<std::vector<ByteEnum>>, readEnumVector),
// PARCEL_READ_WITH_STATUS(std::vector<IntEnum>, readEnumVector),
// PARCEL_READ_WITH_STATUS(std::unique_ptr<std::vector<IntEnum>>, readEnumVector),
+ // PARCEL_READ_WITH_STATUS(std::optional<std::vector<IntEnum>>, readEnumVector),
// PARCEL_READ_WITH_STATUS(std::vector<LongEnum>, readEnumVector),
// PARCEL_READ_WITH_STATUS(std::unique_ptr<std::vector<LongEnum>>, readEnumVector),
+ // PARCEL_READ_WITH_STATUS(std::optional<std::vector<LongEnum>>, readEnumVector),
// only reading one parcelable type for now
// TODO(b/131868573): can force read of arbitrarily sized vector
// PARCEL_READ_WITH_STATUS(std::unique_ptr<std::vector<std::unique_ptr<ExampleParcelable>>>, readParcelableVector),
+ // PARCEL_READ_WITH_STATUS(std::optional<std::vector<std::optional<ExampleParcelable>>>, readParcelableVector),
// PARCEL_READ_WITH_STATUS(std::vector<ExampleParcelable>, readParcelableVector),
PARCEL_READ_WITH_STATUS(ExampleParcelable, readParcelable),
PARCEL_READ_WITH_STATUS(std::unique_ptr<ExampleParcelable>, readParcelable),
+ PARCEL_READ_WITH_STATUS(std::optional<ExampleParcelable>, readParcelable),
// only reading one binder type for now
PARCEL_READ_WITH_STATUS(android::sp<android::os::IServiceManager>, readStrongBinder),
@@ -174,30 +181,42 @@
// TODO(b/131868573): can force read of arbitrarily sized vector
// PARCEL_READ_WITH_STATUS(::std::unique_ptr<std::vector<android::sp<android::IBinder>>>, readStrongBinderVector),
+ // PARCEL_READ_WITH_STATUS(::std::optional<std::vector<android::sp<android::IBinder>>>, readStrongBinderVector),
// PARCEL_READ_WITH_STATUS(std::vector<android::sp<android::IBinder>>, readStrongBinderVector),
// TODO(b/131868573): can force read of arbitrarily sized vector
// PARCEL_READ_WITH_STATUS(std::unique_ptr<std::vector<int8_t>>, readByteVector),
+ // PARCEL_READ_WITH_STATUS(std::optional<std::vector<int8_t>>, readByteVector),
// PARCEL_READ_WITH_STATUS(std::vector<int8_t>, readByteVector),
// PARCEL_READ_WITH_STATUS(std::unique_ptr<std::vector<uint8_t>>, readByteVector),
+ // PARCEL_READ_WITH_STATUS(std::optional<std::vector<uint8_t>>, readByteVector),
// PARCEL_READ_WITH_STATUS(std::vector<uint8_t>, readByteVector),
// PARCEL_READ_WITH_STATUS(std::unique_ptr<std::vector<int32_t>>, readInt32Vector),
+ // PARCEL_READ_WITH_STATUS(std::optional<std::vector<int32_t>>, readInt32Vector),
// PARCEL_READ_WITH_STATUS(std::vector<int32_t>, readInt32Vector),
// PARCEL_READ_WITH_STATUS(std::unique_ptr<std::vector<int64_t>>, readInt64Vector),
+ // PARCEL_READ_WITH_STATUS(std::optional<std::vector<int64_t>>, readInt64Vector),
// PARCEL_READ_WITH_STATUS(std::vector<int64_t>, readInt64Vector),
// PARCEL_READ_WITH_STATUS(std::unique_ptr<std::vector<uint64_t>>, readUint64Vector),
+ // PARCEL_READ_WITH_STATUS(std::optional<std::vector<uint64_t>>, readUint64Vector),
// PARCEL_READ_WITH_STATUS(std::vector<uint64_t>, readUint64Vector),
// PARCEL_READ_WITH_STATUS(std::unique_ptr<std::vector<float>>, readFloatVector),
+ // PARCEL_READ_WITH_STATUS(std::optional<std::vector<float>>, readFloatVector),
// PARCEL_READ_WITH_STATUS(std::vector<float>, readFloatVector),
// PARCEL_READ_WITH_STATUS(std::unique_ptr<std::vector<double>>, readDoubleVector),
+ // PARCEL_READ_WITH_STATUS(std::optional<std::vector<double>>, readDoubleVector),
// PARCEL_READ_WITH_STATUS(std::vector<double>, readDoubleVector),
// PARCEL_READ_WITH_STATUS(std::unique_ptr<std::vector<bool>>, readBoolVector),
+ // PARCEL_READ_WITH_STATUS(std::optional<std::vector<bool>>, readBoolVector),
// PARCEL_READ_WITH_STATUS(std::vector<bool>, readBoolVector),
// PARCEL_READ_WITH_STATUS(std::unique_ptr<std::vector<char16_t>>, readCharVector),
+ // PARCEL_READ_WITH_STATUS(std::optional<std::vector<char16_t>>, readCharVector),
// PARCEL_READ_WITH_STATUS(std::vector<char16_t>, readCharVector),
// PARCEL_READ_WITH_STATUS(std::unique_ptr<std::vector<std::unique_ptr<android::String16>>>, readString16Vector),
+ // PARCEL_READ_WITH_STATUS(std::optional<std::vector<std::optional<android::String16>>>, readString16Vector),
// PARCEL_READ_WITH_STATUS(std::vector<android::String16>, readString16Vector),
// PARCEL_READ_WITH_STATUS(std::unique_ptr<std::vector<std::unique_ptr<std::string>>>, readUtf8VectorFromUtf16Vector),
+ // PARCEL_READ_WITH_STATUS(std::optional<std::vector<std::optional<std::string>>>, readUtf8VectorFromUtf16Vector),
// PARCEL_READ_WITH_STATUS(std::vector<std::string>, readUtf8VectorFromUtf16Vector),
[] (const android::Parcel& p, uint8_t /*len*/) {
@@ -234,6 +253,7 @@
// TODO(b/131868573): can force read of arbitrarily sized vector
// PARCEL_READ_WITH_STATUS(std::unique_ptr<std::vector<android::base::unique_fd>>, readUniqueFileDescriptorVector),
+ // PARCEL_READ_WITH_STATUS(std::optional<std::vector<android::base::unique_fd>>, readUniqueFileDescriptorVector),
// PARCEL_READ_WITH_STATUS(std::vector<android::base::unique_fd>, readUniqueFileDescriptorVector),
[] (const android::Parcel& p, uint8_t len) {
diff --git a/libs/binder/include/binder/ActivityManager.h b/libs/binder/include/binder/ActivityManager.h
index 9108e31..7043b17 100644
--- a/libs/binder/include/binder/ActivityManager.h
+++ b/libs/binder/include/binder/ActivityManager.h
@@ -77,7 +77,7 @@
void unregisterUidObserver(const sp<IUidObserver>& observer);
bool isUidActive(const uid_t uid, const String16& callingPackage);
int getUidProcessState(const uid_t uid, const String16& callingPackage);
-
+ bool setSchedPolicyCgroup(const int32_t tid, const int32_t group);
status_t linkToDeath(const sp<IBinder::DeathRecipient>& recipient);
status_t unlinkToDeath(const sp<IBinder::DeathRecipient>& recipient);
diff --git a/libs/binder/include/binder/IActivityManager.h b/libs/binder/include/binder/IActivityManager.h
index e0248f6..fe58a41 100644
--- a/libs/binder/include/binder/IActivityManager.h
+++ b/libs/binder/include/binder/IActivityManager.h
@@ -39,13 +39,15 @@
virtual void unregisterUidObserver(const sp<IUidObserver>& observer) = 0;
virtual bool isUidActive(const uid_t uid, const String16& callingPackage) = 0;
virtual int32_t getUidProcessState(const uid_t uid, const String16& callingPackage) = 0;
+ virtual bool setSchedPolicyCgroup(const int32_t tid, const int32_t group) = 0;
enum {
OPEN_CONTENT_URI_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION,
REGISTER_UID_OBSERVER_TRANSACTION,
UNREGISTER_UID_OBSERVER_TRANSACTION,
IS_UID_ACTIVE_TRANSACTION,
- GET_UID_PROCESS_STATE_TRANSACTION
+ GET_UID_PROCESS_STATE_TRANSACTION,
+ SET_SCHED_POLICY_CGROUP_TRANSACTION
};
};
diff --git a/libs/binder/include/binder/IInterface.h b/libs/binder/include/binder/IInterface.h
index 7116154..33ee680 100644
--- a/libs/binder/include/binder/IInterface.h
+++ b/libs/binder/include/binder/IInterface.h
@@ -247,8 +247,6 @@
"android.hardware.ISoundTriggerHwService",
"android.hardware.IStreamListener",
"android.hardware.IStreamSource",
- "android.input.IInputFlinger",
- "android.input.ISetInputWindowsListener",
"android.media.IAudioFlinger",
"android.media.IAudioFlingerClient",
"android.media.IAudioPolicyService",
@@ -282,7 +280,6 @@
"android.os.IComplexTypeInterface",
"android.os.IPermissionController",
"android.os.IPingResponder",
- "android.os.IPowerManager",
"android.os.IProcessInfoService",
"android.os.ISchedulingPolicyService",
"android.os.IStringConstants",
diff --git a/libs/dumputils/dump_utils.cpp b/libs/dumputils/dump_utils.cpp
index 2e14408..3ec4b3a 100644
--- a/libs/dumputils/dump_utils.cpp
+++ b/libs/dumputils/dump_utils.cpp
@@ -86,7 +86,7 @@
static void read_extra_hals_to_dump_from_property() {
// extra hals to dump are already filled
- if (extra_hal_interfaces_to_dump.size() > 0) {
+ if (!extra_hal_interfaces_to_dump.empty()) {
return;
}
std::string value = android::base::GetProperty("ro.dump.hals.extra", "");
diff --git a/libs/graphicsenv/GraphicsEnv.cpp b/libs/graphicsenv/GraphicsEnv.cpp
index 3d0f8bb..119b3e0 100644
--- a/libs/graphicsenv/GraphicsEnv.cpp
+++ b/libs/graphicsenv/GraphicsEnv.cpp
@@ -29,7 +29,6 @@
#include <android-base/strings.h>
#include <android/dlext.h>
#include <binder/IServiceManager.h>
-#include <cutils/properties.h>
#include <graphicsenv/IGpuService.h>
#include <log/log.h>
#include <nativeloader/dlext_namespaces.h>
@@ -74,7 +73,7 @@
static std::string vndkVersionStr() {
#ifdef __BIONIC__
- return android::base::GetProperty("ro.vndk.version", "");
+ return base::GetProperty("ro.vndk.version", "");
#endif
return "";
}
@@ -345,10 +344,8 @@
}
bool GraphicsEnv::checkAngleRules(void* so) {
- char manufacturer[PROPERTY_VALUE_MAX];
- char model[PROPERTY_VALUE_MAX];
- property_get("ro.product.manufacturer", manufacturer, "UNSET");
- property_get("ro.product.model", model, "UNSET");
+ auto manufacturer = base::GetProperty("ro.product.manufacturer", "UNSET");
+ auto model = base::GetProperty("ro.product.model", "UNSET");
auto ANGLEGetFeatureSupportUtilAPIVersion =
(fpANGLEGetFeatureSupportUtilAPIVersion)dlsym(so,
@@ -401,7 +398,8 @@
ALOGW("ANGLE feature-support library cannot obtain SystemInfo");
break;
}
- if (!(ANGLEAddDeviceInfoToSystemInfo)(manufacturer, model, systemInfoHandle)) {
+ if (!(ANGLEAddDeviceInfoToSystemInfo)(manufacturer.c_str(), model.c_str(),
+ systemInfoHandle)) {
ALOGW("ANGLE feature-support library cannot add device info to SystemInfo");
break;
}
@@ -653,8 +651,7 @@
mAngleNamespace = android_create_namespace("ANGLE",
nullptr, // ld_library_path
mAnglePath.c_str(), // default_library_path
- ANDROID_NAMESPACE_TYPE_SHARED |
- ANDROID_NAMESPACE_TYPE_ISOLATED,
+ ANDROID_NAMESPACE_TYPE_SHARED_ISOLATED,
nullptr, // permitted_when_isolated_path
nullptr);
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index e62a61f..6881be3 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -371,10 +371,8 @@
data.writeStrongBinder(display);
remote()->transact(BnSurfaceComposer::GET_DISPLAY_INFO, data, &reply);
const status_t result = reply.readInt32();
- if (result == NO_ERROR) {
- memcpy(info, reply.readInplace(sizeof(DisplayInfo)), sizeof(DisplayInfo));
- }
- return result;
+ if (result != NO_ERROR) return result;
+ return reply.read(*info);
}
virtual status_t getDisplayConfigs(const sp<IBinder>& display, Vector<DisplayConfig>* configs) {
@@ -1093,22 +1091,22 @@
return NO_ERROR;
}
- virtual status_t notifyPowerHint(int32_t hintId) {
+ virtual status_t notifyPowerBoost(int32_t boostId) {
Parcel data, reply;
status_t error = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
if (error != NO_ERROR) {
- ALOGE("notifyPowerHint: failed to write interface token: %d", error);
+ ALOGE("notifyPowerBoost: failed to write interface token: %d", error);
return error;
}
- error = data.writeInt32(hintId);
+ error = data.writeInt32(boostId);
if (error != NO_ERROR) {
- ALOGE("notifyPowerHint: failed to write hintId: %d", error);
+ ALOGE("notifyPowerBoost: failed to write boostId: %d", error);
return error;
}
- error = remote()->transact(BnSurfaceComposer::NOTIFY_POWER_HINT, data, &reply,
+ error = remote()->transact(BnSurfaceComposer::NOTIFY_POWER_BOOST, data, &reply,
IBinder::FLAG_ONEWAY);
if (error != NO_ERROR) {
- ALOGE("notifyPowerHint: failed to transact: %d", error);
+ ALOGE("notifyPowerBoost: failed to transact: %d", error);
return error;
}
return NO_ERROR;
@@ -1442,10 +1440,8 @@
const sp<IBinder> display = data.readStrongBinder();
const status_t result = getDisplayInfo(display, &info);
reply->writeInt32(result);
- if (result == NO_ERROR) {
- memcpy(reply->writeInplace(sizeof(DisplayInfo)), &info, sizeof(DisplayInfo));
- }
- return NO_ERROR;
+ if (result != NO_ERROR) return result;
+ return reply->write(info);
}
case GET_DISPLAY_CONFIGS: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
@@ -1989,15 +1985,15 @@
}
return setDisplayBrightness(displayToken, brightness);
}
- case NOTIFY_POWER_HINT: {
+ case NOTIFY_POWER_BOOST: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
- int32_t hintId;
- status_t error = data.readInt32(&hintId);
+ int32_t boostId;
+ status_t error = data.readInt32(&boostId);
if (error != NO_ERROR) {
- ALOGE("notifyPowerHint: failed to read hintId: %d", error);
+ ALOGE("notifyPowerBoost: failed to read boostId: %d", error);
return error;
}
- return notifyPowerHint(hintId);
+ return notifyPowerBoost(boostId);
}
case SET_GLOBAL_SHADOW_SETTINGS: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index e43446a..1030b82 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -55,7 +55,7 @@
output.writeFloat(color.g);
output.writeFloat(color.b);
#ifndef NO_INPUT
- inputInfo.write(output);
+ inputHandle->writeToParcel(&output);
#endif
output.write(transparentRegion);
output.writeUint32(transform);
@@ -152,7 +152,7 @@
color.b = input.readFloat();
#ifndef NO_INPUT
- inputInfo = InputWindowInfo::read(input);
+ inputHandle->readFromParcel(&input);
#endif
input.read(transparentRegion);
@@ -404,7 +404,7 @@
#ifndef NO_INPUT
if (other.what & eInputInfoChanged) {
what |= eInputInfoChanged;
- inputInfo = other.inputInfo;
+ inputHandle = new InputWindowHandle(*other.inputHandle);
}
#endif
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index cf269b3..a86eafa 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -1493,7 +1493,7 @@
int result = mGraphicBufferProducer->getLastQueuedBuffer(&graphicBuffer, &spFence, matrix);
if (graphicBuffer != nullptr) {
- *buffer = reinterpret_cast<AHardwareBuffer*>(graphicBuffer.get());
+ *buffer = graphicBuffer->toAHardwareBuffer();
AHardwareBuffer_acquire(*buffer);
} else {
*buffer = nullptr;
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 83bc069..d797a35 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -1359,7 +1359,7 @@
mStatus = BAD_INDEX;
return *this;
}
- s->inputInfo = info;
+ s->inputHandle = new InputWindowHandle(info);
s->what |= layer_state_t::eInputInfoChanged;
return *this;
}
@@ -1893,8 +1893,8 @@
return ComposerService::getComposerService()->setDisplayBrightness(displayToken, brightness);
}
-status_t SurfaceComposerClient::notifyPowerHint(int32_t hintId) {
- return ComposerService::getComposerService()->notifyPowerHint(hintId);
+status_t SurfaceComposerClient::notifyPowerBoost(int32_t boostId) {
+ return ComposerService::getComposerService()->notifyPowerBoost(boostId);
}
status_t SurfaceComposerClient::setGlobalShadowSettings(const half4& ambientColor,
diff --git a/libs/gui/SurfaceControl.cpp b/libs/gui/SurfaceControl.cpp
index a332a1f..8dcb71b 100644
--- a/libs/gui/SurfaceControl.cpp
+++ b/libs/gui/SurfaceControl.cpp
@@ -178,17 +178,28 @@
}
sp<SurfaceControl> SurfaceControl::readFromParcel(const Parcel* parcel) {
- sp<IBinder> client = parcel->readStrongBinder();
- sp<IBinder> handle = parcel->readStrongBinder();
- if (client == nullptr || handle == nullptr)
- {
- ALOGE("Invalid parcel");
- return nullptr;
+ bool invalidParcel = false;
+ status_t status;
+ sp<IBinder> client;
+ if ((status = parcel->readStrongBinder(&client)) != OK) {
+ ALOGE("Failed to read client: %s", statusToString(status).c_str());
+ invalidParcel = true;
+ }
+ sp<IBinder> handle;
+ if ((status = parcel->readStrongBinder(&handle)) != OK) {
+ ALOGE("Failed to read handle: %s", statusToString(status).c_str());
+ invalidParcel = true;
}
sp<IBinder> gbp;
- parcel->readNullableStrongBinder(&gbp);
-
+ if ((status = parcel->readNullableStrongBinder(&gbp)) != OK) {
+ ALOGE("Failed to read gbp: %s", statusToString(status).c_str());
+ invalidParcel = true;
+ }
uint32_t transformHint = parcel->readUint32();
+
+ if (invalidParcel) {
+ return nullptr;
+ }
// We aren't the original owner of the surface.
return new SurfaceControl(new SurfaceComposerClient(
interface_cast<ISurfaceComposerClient>(client)),
diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
index 8d3160a..645714a 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -496,14 +496,14 @@
virtual status_t setDisplayBrightness(const sp<IBinder>& displayToken, float brightness) = 0;
/*
- * Sends a power hint to the composer. This function is asynchronous.
+ * Sends a power boost to the composer. This function is asynchronous.
*
- * hintId
- * hint id according to android::hardware::power::V1_0::PowerHint
+ * boostId
+ * boost id according to android::hardware::power::Boost
*
* Returns NO_ERROR upon success.
*/
- virtual status_t notifyPowerHint(int32_t hintId) = 0;
+ virtual status_t notifyPowerBoost(int32_t boostId) = 0;
/*
* Sets the global configuration for all the shadows drawn by SurfaceFlinger. Shadow follows
@@ -591,7 +591,7 @@
GET_DISPLAY_BRIGHTNESS_SUPPORT,
SET_DISPLAY_BRIGHTNESS,
CAPTURE_SCREEN_BY_ID,
- NOTIFY_POWER_HINT,
+ NOTIFY_POWER_BOOST,
SET_GLOBAL_SHADOW_SETTINGS,
GET_AUTO_LOW_LATENCY_MODE_SUPPORT,
SET_AUTO_LOW_LATENCY_MODE,
diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h
index e60f677..00ae220 100644
--- a/libs/gui/include/gui/LayerState.h
+++ b/libs/gui/include/gui/LayerState.h
@@ -201,7 +201,7 @@
mat4 colorTransform;
#ifndef NO_INPUT
- InputWindowInfo inputInfo;
+ sp<InputWindowHandle> inputHandle = new InputWindowHandle();
#endif
client_cache_t cachedBuffer;
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index adcb898..eb757ba 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -217,14 +217,14 @@
static status_t setDisplayBrightness(const sp<IBinder>& displayToken, float brightness);
/*
- * Sends a power hint to the composer. This function is asynchronous.
+ * Sends a power boost to the composer. This function is asynchronous.
*
- * hintId
- * hint id according to android::hardware::power::V1_0::PowerHint
+ * boostId
+ * boost id according to android::hardware::power::Boost
*
* Returns NO_ERROR upon success.
*/
- static status_t notifyPowerHint(int32_t hintId);
+ static status_t notifyPowerBoost(int32_t boostId);
/*
* Sets the global configuration for all the shadows drawn by SurfaceFlinger. Shadow follows
diff --git a/libs/gui/tests/EndToEndNativeInputTest.cpp b/libs/gui/tests/EndToEndNativeInputTest.cpp
index b1d3ecb..152f7ad 100644
--- a/libs/gui/tests/EndToEndNativeInputTest.cpp
+++ b/libs/gui/tests/EndToEndNativeInputTest.cpp
@@ -36,15 +36,16 @@
#include <gui/SurfaceComposerClient.h>
#include <gui/SurfaceControl.h>
-#include <input/InputWindow.h>
-#include <input/IInputFlinger.h>
-#include <input/InputTransport.h>
+#include <android/os/IInputFlinger.h>
#include <input/Input.h>
+#include <input/InputTransport.h>
+#include <input/InputWindow.h>
#include <ui/DisplayConfig.h>
#include <ui/Rect.h>
#include <ui/Region.h>
+using android::os::IInputFlinger;
namespace android {
namespace test {
@@ -71,7 +72,7 @@
InputChannel::openInputChannelPair("testchannels", mServerChannel, mClientChannel);
mInputFlinger = getInputFlinger();
- mInputFlinger->registerInputChannel(mServerChannel);
+ mInputFlinger->registerInputChannel(mServerChannel->getInfo());
populateInputInfo(width, height);
@@ -153,9 +154,7 @@
EXPECT_EQ(0, mev->getFlags() & VERIFIED_MOTION_EVENT_FLAGS);
}
- ~InputSurface() {
- mInputFlinger->unregisterInputChannel(mServerChannel);
- }
+ ~InputSurface() { mInputFlinger->unregisterInputChannel(mServerChannel->getInfo()); }
void doTransaction(std::function<void(SurfaceComposerClient::Transaction&,
const sp<SurfaceControl>&)> transactionBody) {
@@ -189,7 +188,7 @@
mInputInfo.name = "Test info";
mInputInfo.layoutParamsFlags = InputWindowInfo::FLAG_NOT_TOUCH_MODAL;
mInputInfo.layoutParamsType = InputWindowInfo::TYPE_BASE_APPLICATION;
- mInputInfo.dispatchingTimeout = seconds_to_nanoseconds(5);
+ mInputInfo.dispatchingTimeout = 5s;
mInputInfo.globalScaleFactor = 1.0;
mInputInfo.canReceiveKeys = true;
mInputInfo.hasFocus = true;
@@ -207,7 +206,7 @@
InputApplicationInfo aInfo;
aInfo.token = new BBinder();
aInfo.name = "Test app info";
- aInfo.dispatchingTimeout = seconds_to_nanoseconds(5);
+ aInfo.dispatchingTimeout = 5s;
mInputInfo.applicationInfo = aInfo;
}
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index 9906166..6d92143 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -850,7 +850,7 @@
float* /*outAppRequestRefreshRateMax*/) override {
return NO_ERROR;
};
- status_t notifyPowerHint(int32_t /*hintId*/) override { return NO_ERROR; }
+ status_t notifyPowerBoost(int32_t /*boostId*/) override { return NO_ERROR; }
status_t setGlobalShadowSettings(const half4& /*ambientColor*/, const half4& /*spotColor*/,
float /*lightPosY*/, float /*lightPosZ*/,
diff --git a/libs/input/Android.bp b/libs/input/Android.bp
index 7037680..ade9c25 100644
--- a/libs/input/Android.bp
+++ b/libs/input/Android.bp
@@ -46,14 +46,14 @@
target: {
android: {
srcs: [
- "IInputFlinger.cpp",
"InputApplication.cpp",
"InputTransport.cpp",
"InputWindow.cpp",
- "ISetInputWindowsListener.cpp",
"LatencyStatistics.cpp",
"VelocityControl.cpp",
"VelocityTracker.cpp",
+ "android/os/IInputFlinger.aidl",
+ "android/os/ISetInputWindowsListener.aidl",
],
shared_libs: [
@@ -72,6 +72,11 @@
},
},
},
+
+ aidl: {
+ local_include_dirs: ["."],
+ export_aidl_headers: true
+ },
}
subdirs = ["tests"]
diff --git a/libs/input/IInputFlinger.cpp b/libs/input/IInputFlinger.cpp
deleted file mode 100644
index 8ec5165..0000000
--- a/libs/input/IInputFlinger.cpp
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * Copyright (C) 2013 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 <stdint.h>
-#include <sys/types.h>
-
-#include <binder/Parcel.h>
-#include <binder/IPCThreadState.h>
-#include <binder/IServiceManager.h>
-
-#include <input/IInputFlinger.h>
-
-namespace android {
-
-class BpInputFlinger : public BpInterface<IInputFlinger> {
-public:
- explicit BpInputFlinger(const sp<IBinder>& impl) :
- BpInterface<IInputFlinger>(impl) { }
-
- virtual void setInputWindows(const std::vector<InputWindowInfo>& inputInfo,
- const sp<ISetInputWindowsListener>& setInputWindowsListener) {
- Parcel data, reply;
- data.writeInterfaceToken(IInputFlinger::getInterfaceDescriptor());
-
- data.writeUint32(static_cast<uint32_t>(inputInfo.size()));
- for (const auto& info : inputInfo) {
- info.write(data);
- }
- data.writeStrongBinder(IInterface::asBinder(setInputWindowsListener));
-
- remote()->transact(BnInputFlinger::SET_INPUT_WINDOWS_TRANSACTION, data, &reply,
- IBinder::FLAG_ONEWAY);
- }
-
- virtual void registerInputChannel(const sp<InputChannel>& channel) {
- Parcel data, reply;
- data.writeInterfaceToken(IInputFlinger::getInterfaceDescriptor());
- channel->write(data);
- remote()->transact(BnInputFlinger::REGISTER_INPUT_CHANNEL_TRANSACTION, data, &reply);
- }
-
- virtual void unregisterInputChannel(const sp<InputChannel>& channel) {
- Parcel data, reply;
- data.writeInterfaceToken(IInputFlinger::getInterfaceDescriptor());
- channel->write(data);
- remote()->transact(BnInputFlinger::UNREGISTER_INPUT_CHANNEL_TRANSACTION, data, &reply);
- }
-};
-
-IMPLEMENT_META_INTERFACE(InputFlinger, "android.input.IInputFlinger");
-
-status_t BnInputFlinger::onTransact(
- uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) {
- switch(code) {
- case SET_INPUT_WINDOWS_TRANSACTION: {
- CHECK_INTERFACE(IInputFlinger, data, reply);
- size_t count = data.readUint32();
- if (count > data.dataSize()) {
- return BAD_VALUE;
- }
- std::vector<InputWindowInfo> handles;
- for (size_t i = 0; i < count; i++) {
- handles.push_back(InputWindowInfo::read(data));
- }
- const sp<ISetInputWindowsListener> setInputWindowsListener =
- ISetInputWindowsListener::asInterface(data.readStrongBinder());
- setInputWindows(handles, setInputWindowsListener);
- break;
- }
- case REGISTER_INPUT_CHANNEL_TRANSACTION: {
- CHECK_INTERFACE(IInputFlinger, data, reply);
- sp<InputChannel> channel = InputChannel::read(data);
- registerInputChannel(channel);
- break;
- }
- case UNREGISTER_INPUT_CHANNEL_TRANSACTION: {
- CHECK_INTERFACE(IInputFlinger, data, reply);
- sp<InputChannel> channel = InputChannel::read(data);
- unregisterInputChannel(channel);
- break;
- }
- default:
- return BBinder::onTransact(code, data, reply, flags);
- }
- return NO_ERROR;
-}
-
-};
diff --git a/libs/input/ISetInputWindowsListener.cpp b/libs/input/ISetInputWindowsListener.cpp
deleted file mode 100644
index a0330da..0000000
--- a/libs/input/ISetInputWindowsListener.cpp
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (C) 2019 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 <input/ISetInputWindowsListener.h>
-
-namespace android {
-
-class BpSetInputWindowsListener : public BpInterface<ISetInputWindowsListener> {
-public:
- explicit BpSetInputWindowsListener(const sp<IBinder>& impl)
- : BpInterface<ISetInputWindowsListener>(impl) {
- }
-
- virtual ~BpSetInputWindowsListener() = default;
-
- virtual void onSetInputWindowsFinished() {
- Parcel data, reply;
- data.writeInterfaceToken(ISetInputWindowsListener::getInterfaceDescriptor());
- remote()->transact(BnSetInputWindowsListener::ON_SET_INPUT_WINDOWS_FINISHED, data, &reply,
- IBinder::FLAG_ONEWAY);
- }
-};
-
-IMPLEMENT_META_INTERFACE(SetInputWindowsListener, "android.input.ISetInputWindowsListener");
-
-status_t BnSetInputWindowsListener::onTransact(uint32_t code, const Parcel& data, Parcel* reply,
- uint32_t flags) {
- switch(code) {
- case ON_SET_INPUT_WINDOWS_FINISHED: {
- CHECK_INTERFACE(ISetInputWindowsListener, data, reply);
- onSetInputWindowsFinished();
- return NO_ERROR;
- }
- default: {
- return BBinder::onTransact(code, data, reply, flags);
- }
- }
-}
-
-} // namespace android
diff --git a/libs/input/InputApplication.cpp b/libs/input/InputApplication.cpp
index 1d9f8a7..41721a7 100644
--- a/libs/input/InputApplication.cpp
+++ b/libs/input/InputApplication.cpp
@@ -22,29 +22,34 @@
namespace android {
+status_t InputApplicationInfo::readFromParcel(const android::Parcel* parcel) {
+ if (parcel == nullptr) {
+ ALOGE("%s: Null parcel", __func__);
+ return BAD_VALUE;
+ }
+ token = parcel->readStrongBinder();
+ dispatchingTimeout = decltype(dispatchingTimeout)(parcel->readInt64());
+ status_t status = parcel->readUtf8FromUtf16(&name);
+
+ return status;
+}
+
+status_t InputApplicationInfo::writeToParcel(android::Parcel* parcel) const {
+ if (parcel == nullptr) {
+ ALOGE("%s: Null parcel", __func__);
+ return BAD_VALUE;
+ }
+ status_t status = parcel->writeStrongBinder(token)
+ ?: parcel->writeInt64(dispatchingTimeout.count())
+ ?: parcel->writeUtf8AsUtf16(name) ;
+
+ return status;
+}
+
// --- InputApplicationHandle ---
-InputApplicationHandle::InputApplicationHandle() {
-}
+InputApplicationHandle::InputApplicationHandle() {}
-InputApplicationHandle::~InputApplicationHandle() {
-}
-
-InputApplicationInfo InputApplicationInfo::read(const Parcel& from) {
- InputApplicationInfo ret;
- ret.token = from.readStrongBinder();
- ret.name = from.readString8().c_str();
- ret.dispatchingTimeout = from.readInt64();
-
- return ret;
-}
-
-status_t InputApplicationInfo::write(Parcel& output) const {
- output.writeStrongBinder(token);
- output.writeString8(String8(name.c_str()));
- output.writeInt64(dispatchingTimeout);
-
- return OK;
-}
+InputApplicationHandle::~InputApplicationHandle() {}
} // namespace android
diff --git a/libs/input/InputDevice.cpp b/libs/input/InputDevice.cpp
index 4db9e06..dbd6293 100644
--- a/libs/input/InputDevice.cpp
+++ b/libs/input/InputDevice.cpp
@@ -46,9 +46,9 @@
static void appendInputDeviceConfigurationFileRelativePath(std::string& path,
const std::string& name, InputDeviceConfigurationFileType type) {
- path += CONFIGURATION_FILE_DIR[type];
+ path += CONFIGURATION_FILE_DIR[static_cast<int32_t>(type)];
path += name;
- path += CONFIGURATION_FILE_EXTENSION[type];
+ path += CONFIGURATION_FILE_EXTENSION[static_cast<int32_t>(type)];
}
std::string getInputDeviceConfigurationFilePathByDeviceIdentifier(
diff --git a/libs/input/InputTransport.cpp b/libs/input/InputTransport.cpp
index 11af23e..c6043ac 100644
--- a/libs/input/InputTransport.cpp
+++ b/libs/input/InputTransport.cpp
@@ -246,6 +246,28 @@
}
}
+// --- InputChannelInfo ---
+
+status_t InputChannelInfo::writeToParcel(android::Parcel* parcel) const {
+ if (parcel == nullptr) {
+ ALOGE("%s: Null parcel", __func__);
+ return BAD_VALUE;
+ }
+ status_t status = parcel->writeStrongBinder(mToken)
+ ?: parcel->writeUtf8AsUtf16(mName) ?: parcel->writeUniqueFileDescriptor(mFd);
+ return status;
+}
+
+status_t InputChannelInfo::readFromParcel(const android::Parcel* parcel) {
+ if (parcel == nullptr) {
+ ALOGE("%s: Null parcel", __func__);
+ return BAD_VALUE;
+ }
+ mToken = parcel->readStrongBinder();
+ status_t status = parcel->readUtf8FromUtf16(&mName) ?: parcel->readUniqueFileDescriptor(&mFd);
+ return status;
+}
+
// --- InputChannel ---
sp<InputChannel> InputChannel::create(const std::string& name, android::base::unique_fd fd,
@@ -260,15 +282,17 @@
}
InputChannel::InputChannel(const std::string& name, android::base::unique_fd fd, sp<IBinder> token)
- : mName(name), mFd(std::move(fd)), mToken(token) {
+ : mInfo(name, std::move(fd), token) {
if (DEBUG_CHANNEL_LIFECYCLE) {
- ALOGD("Input channel constructed: name='%s', fd=%d", mName.c_str(), mFd.get());
+ ALOGD("Input channel constructed: name='%s', fd=%d", mInfo.mName.c_str(), mInfo.mFd.get());
}
}
+InputChannel::InputChannel() {}
+
InputChannel::~InputChannel() {
if (DEBUG_CHANNEL_LIFECYCLE) {
- ALOGD("Input channel destroyed: name='%s', fd=%d", mName.c_str(), mFd.get());
+ ALOGD("Input channel destroyed: name='%s', fd=%d", getName().c_str(), getFd());
}
}
@@ -308,7 +332,7 @@
msg->getSanitizedCopy(&cleanMsg);
ssize_t nWrite;
do {
- nWrite = ::send(mFd.get(), &cleanMsg, msgLength, MSG_DONTWAIT | MSG_NOSIGNAL);
+ nWrite = ::send(getFd(), &cleanMsg, msgLength, MSG_DONTWAIT | MSG_NOSIGNAL);
} while (nWrite == -1 && errno == EINTR);
if (nWrite < 0) {
@@ -343,7 +367,7 @@
status_t InputChannel::receiveMessage(InputMessage* msg) {
ssize_t nRead;
do {
- nRead = ::recv(mFd.get(), msg, sizeof(InputMessage), MSG_DONTWAIT);
+ nRead = ::recv(getFd(), msg, sizeof(InputMessage), MSG_DONTWAIT);
} while (nRead == -1 && errno == EINTR);
if (nRead < 0) {
@@ -383,7 +407,7 @@
sp<InputChannel> InputChannel::dup() const {
android::base::unique_fd newFd(::dup(getFd()));
if (!newFd.ok()) {
- ALOGE("Could not duplicate fd %i for channel %s: %s", getFd(), mName.c_str(),
+ ALOGE("Could not duplicate fd %i for channel %s: %s", getFd(), getName().c_str(),
strerror(errno));
const bool hitFdLimit = errno == EMFILE || errno == ENFILE;
// If this process is out of file descriptors, then throwing that might end up exploding
@@ -394,38 +418,19 @@
getName().c_str());
return nullptr;
}
- return InputChannel::create(mName, std::move(newFd), mToken);
+ return InputChannel::create(getName(), std::move(newFd), getConnectionToken());
}
-status_t InputChannel::write(Parcel& out) const {
- status_t s = out.writeCString(getName().c_str());
- if (s != OK) {
- return s;
- }
-
- s = out.writeStrongBinder(mToken);
- if (s != OK) {
- return s;
- }
-
- s = out.writeUniqueFileDescriptor(mFd);
- return s;
+status_t InputChannel::writeToParcel(android::Parcel* parcel) const {
+ return mInfo.writeToParcel(parcel);
}
-sp<InputChannel> InputChannel::read(const Parcel& from) {
- std::string name = from.readCString();
- sp<IBinder> token = from.readStrongBinder();
- android::base::unique_fd rawFd;
- status_t fdResult = from.readUniqueFileDescriptor(&rawFd);
- if (fdResult != OK) {
- return nullptr;
- }
-
- return InputChannel::create(name, std::move(rawFd), token);
+status_t InputChannel::readFromParcel(const android::Parcel* parcel) {
+ return mInfo.readFromParcel(parcel);
}
sp<IBinder> InputChannel::getConnectionToken() const {
- return mToken;
+ return mInfo.mToken;
}
// --- InputPublisher ---
diff --git a/libs/input/InputWindow.cpp b/libs/input/InputWindow.cpp
index 85a2015..ae9b3f0 100644
--- a/libs/input/InputWindow.cpp
+++ b/libs/input/InputWindow.cpp
@@ -17,17 +17,127 @@
#define LOG_TAG "InputWindow"
#define LOG_NDEBUG 0
+#include <android-base/stringprintf.h>
#include <binder/Parcel.h>
-#include <input/InputWindow.h>
#include <input/InputTransport.h>
+#include <input/InputWindow.h>
#include <log/log.h>
-#include <ui/Rect.h>
-#include <ui/Region.h>
-
namespace android {
+const char* inputWindowFlagToString(uint32_t flag) {
+ switch (flag) {
+ case InputWindowInfo::FLAG_ALLOW_LOCK_WHILE_SCREEN_ON: {
+ return "ALLOW_LOCK_WHILE_SCREEN_ON";
+ }
+ case InputWindowInfo::FLAG_DIM_BEHIND: {
+ return "DIM_BEHIND";
+ }
+ case InputWindowInfo::FLAG_BLUR_BEHIND: {
+ return "BLUR_BEHIND";
+ }
+ case InputWindowInfo::FLAG_NOT_FOCUSABLE: {
+ return "NOT_FOCUSABLE";
+ }
+ case InputWindowInfo::FLAG_NOT_TOUCHABLE: {
+ return "NOT_TOUCHABLE";
+ }
+ case InputWindowInfo::FLAG_NOT_TOUCH_MODAL: {
+ return "NOT_TOUCH_MODAL";
+ }
+ case InputWindowInfo::FLAG_TOUCHABLE_WHEN_WAKING: {
+ return "TOUCHABLE_WHEN_WAKING";
+ }
+ case InputWindowInfo::FLAG_KEEP_SCREEN_ON: {
+ return "KEEP_SCREEN_ON";
+ }
+ case InputWindowInfo::FLAG_LAYOUT_IN_SCREEN: {
+ return "LAYOUT_IN_SCREEN";
+ }
+ case InputWindowInfo::FLAG_LAYOUT_NO_LIMITS: {
+ return "LAYOUT_NO_LIMITS";
+ }
+ case InputWindowInfo::FLAG_FULLSCREEN: {
+ return "FULLSCREEN";
+ }
+ case InputWindowInfo::FLAG_FORCE_NOT_FULLSCREEN: {
+ return "FORCE_NOT_FULLSCREEN";
+ }
+ case InputWindowInfo::FLAG_DITHER: {
+ return "DITHER";
+ }
+ case InputWindowInfo::FLAG_SECURE: {
+ return "SECURE";
+ }
+ case InputWindowInfo::FLAG_SCALED: {
+ return "SCALED";
+ }
+ case InputWindowInfo::FLAG_IGNORE_CHEEK_PRESSES: {
+ return "IGNORE_CHEEK_PRESSES";
+ }
+ case InputWindowInfo::FLAG_LAYOUT_INSET_DECOR: {
+ return "LAYOUT_INSET_DECOR";
+ }
+ case InputWindowInfo::FLAG_ALT_FOCUSABLE_IM: {
+ return "ALT_FOCUSABLE_IM";
+ }
+ case InputWindowInfo::FLAG_WATCH_OUTSIDE_TOUCH: {
+ return "WATCH_OUTSIDE_TOUCH";
+ }
+ case InputWindowInfo::FLAG_SHOW_WHEN_LOCKED: {
+ return "SHOW_WHEN_LOCKED";
+ }
+ case InputWindowInfo::FLAG_SHOW_WALLPAPER: {
+ return "SHOW_WALLPAPER";
+ }
+ case InputWindowInfo::FLAG_TURN_SCREEN_ON: {
+ return "TURN_SCREEN_ON";
+ }
+ case InputWindowInfo::FLAG_DISMISS_KEYGUARD: {
+ return "DISMISS_KEYGUARD";
+ }
+ case InputWindowInfo::FLAG_SPLIT_TOUCH: {
+ return "SPLIT_TOUCH";
+ }
+ case InputWindowInfo::FLAG_HARDWARE_ACCELERATED: {
+ return "HARDWARE_ACCELERATED";
+ }
+ case InputWindowInfo::FLAG_LAYOUT_IN_OVERSCAN: {
+ return "LAYOUT_IN_OVERSCAN";
+ }
+ case InputWindowInfo::FLAG_TRANSLUCENT_STATUS: {
+ return "TRANSLUCENT_STATUS";
+ }
+ case InputWindowInfo::FLAG_TRANSLUCENT_NAVIGATION: {
+ return "TRANSLUCENT_NAVIGATION";
+ }
+ case InputWindowInfo::FLAG_LOCAL_FOCUS_MODE: {
+ return "LOCAL_FOCUS_MODE";
+ }
+ case InputWindowInfo::FLAG_SLIPPERY: {
+ return "SLIPPERY";
+ }
+ case InputWindowInfo::FLAG_LAYOUT_ATTACHED_IN_DECOR: {
+ return "LAYOUT_ATTACHED_IN_DECOR";
+ }
+ case InputWindowInfo::FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS: {
+ return "DRAWS_SYSTEM_BAR_BACKGROUNDS";
+ }
+ }
+ return "UNKNOWN";
+}
+
+std::string inputWindowFlagsToString(uint32_t flags) {
+ std::string result;
+ for (BitSet32 bits(flags); !bits.isEmpty();) {
+ uint32_t bit = bits.clearLastMarkedBit(); // counts from left
+ const uint32_t flag = 1 << (32 - bit - 1);
+ result += android::base::StringPrintf("%s | ", inputWindowFlagToString(flag));
+ }
+ return result;
+}
+
// --- InputWindowInfo ---
void InputWindowInfo::addTouchableRegion(const Rect& region) {
touchableRegion.orSelf(region);
@@ -42,20 +152,6 @@
&& y >= frameTop && y < frameBottom;
}
-// TODO(b/155781676): Remove and replace call points with trustedOverlay when that is ready.
-bool InputWindowInfo::isTrustedOverlay() const {
- return layoutParamsType == TYPE_INPUT_METHOD || layoutParamsType == TYPE_INPUT_METHOD_DIALOG ||
- layoutParamsType == TYPE_MAGNIFICATION_OVERLAY || layoutParamsType == TYPE_STATUS_BAR ||
- layoutParamsType == TYPE_NOTIFICATION_SHADE ||
- layoutParamsType == TYPE_NAVIGATION_BAR ||
- layoutParamsType == TYPE_NAVIGATION_BAR_PANEL ||
- layoutParamsType == TYPE_SECURE_SYSTEM_OVERLAY ||
- layoutParamsType == TYPE_DOCK_DIVIDER ||
- layoutParamsType == TYPE_ACCESSIBILITY_OVERLAY ||
- layoutParamsType == TYPE_INPUT_CONSUMER ||
- layoutParamsType == TYPE_TRUSTED_APPLICATION_OVERLAY;
-}
-
bool InputWindowInfo::supportsSplitTouch() const {
return layoutParamsFlags & FLAG_SPLIT_TOUCH;
}
@@ -65,94 +161,130 @@
&& frameTop < other->frameBottom && frameBottom > other->frameTop;
}
-status_t InputWindowInfo::write(Parcel& output) const {
+bool InputWindowInfo::operator==(const InputWindowInfo& info) const {
+ return info.token == token && info.id == id && info.name == name &&
+ info.layoutParamsFlags == layoutParamsFlags &&
+ info.layoutParamsType == layoutParamsType &&
+ info.dispatchingTimeout == dispatchingTimeout && info.frameLeft == frameLeft &&
+ info.frameTop == frameTop && info.frameRight == frameRight &&
+ info.frameBottom == frameBottom && info.surfaceInset == surfaceInset &&
+ info.globalScaleFactor == globalScaleFactor && info.windowXScale == windowXScale &&
+ info.windowYScale == windowYScale &&
+ info.touchableRegion.hasSameRects(touchableRegion) && info.visible == visible &&
+ info.canReceiveKeys == canReceiveKeys && info.trustedOverlay == trustedOverlay &&
+ info.hasFocus == hasFocus && info.hasWallpaper == hasWallpaper &&
+ info.paused == paused && info.ownerPid == ownerPid && info.ownerUid == ownerUid &&
+ info.inputFeatures == inputFeatures && info.displayId == displayId &&
+ info.portalToDisplayId == portalToDisplayId &&
+ info.replaceTouchableRegionWithCrop == replaceTouchableRegionWithCrop &&
+ info.applicationInfo.name == applicationInfo.name &&
+ info.applicationInfo.token == applicationInfo.token &&
+ info.applicationInfo.dispatchingTimeout == applicationInfo.dispatchingTimeout;
+}
+
+status_t InputWindowInfo::writeToParcel(android::Parcel* parcel) const {
+ if (parcel == nullptr) {
+ ALOGE("%s: Null parcel", __func__);
+ return BAD_VALUE;
+ }
if (name.empty()) {
- output.writeInt32(0);
+ parcel->writeInt32(0);
return OK;
}
- output.writeInt32(1);
- status_t s = output.writeStrongBinder(token);
- if (s != OK) return s;
+ parcel->writeInt32(1);
- output.writeInt32(id);
- output.writeString8(String8(name.c_str()));
- output.writeInt32(layoutParamsFlags);
- output.writeInt32(layoutParamsType);
- output.writeInt64(dispatchingTimeout);
- output.writeInt32(frameLeft);
- output.writeInt32(frameTop);
- output.writeInt32(frameRight);
- output.writeInt32(frameBottom);
- output.writeInt32(surfaceInset);
- output.writeFloat(globalScaleFactor);
- output.writeFloat(windowXScale);
- output.writeFloat(windowYScale);
- output.writeBool(visible);
- output.writeBool(canReceiveKeys);
- output.writeBool(hasFocus);
- output.writeBool(hasWallpaper);
- output.writeBool(paused);
- output.writeInt32(ownerPid);
- output.writeInt32(ownerUid);
- output.writeInt32(inputFeatures);
- output.writeInt32(displayId);
- output.writeInt32(portalToDisplayId);
- applicationInfo.write(output);
- output.write(touchableRegion);
- output.writeBool(replaceTouchableRegionWithCrop);
- output.writeStrongBinder(touchableRegionCropHandle.promote());
- return OK;
+ status_t status = parcel->writeStrongBinder(token) ?:
+ parcel->writeInt64(dispatchingTimeout.count()) ?:
+ parcel->writeInt32(id) ?:
+ parcel->writeUtf8AsUtf16(name) ?:
+ parcel->writeInt32(layoutParamsFlags) ?:
+ parcel->writeInt32(layoutParamsType) ?:
+ parcel->writeInt32(frameLeft) ?:
+ parcel->writeInt32(frameTop) ?:
+ parcel->writeInt32(frameRight) ?:
+ parcel->writeInt32(frameBottom) ?:
+ parcel->writeInt32(surfaceInset) ?:
+ parcel->writeFloat(globalScaleFactor) ?:
+ parcel->writeFloat(windowXScale) ?:
+ parcel->writeFloat(windowYScale) ?:
+ parcel->writeBool(visible) ?:
+ parcel->writeBool(canReceiveKeys) ?:
+ parcel->writeBool(hasFocus) ?:
+ parcel->writeBool(hasWallpaper) ?:
+ parcel->writeBool(paused) ?:
+ parcel->writeBool(trustedOverlay) ?:
+ parcel->writeInt32(ownerPid) ?:
+ parcel->writeInt32(ownerUid) ?:
+ parcel->writeInt32(inputFeatures) ?:
+ parcel->writeInt32(displayId) ?:
+ parcel->writeInt32(portalToDisplayId) ?:
+ applicationInfo.writeToParcel(parcel) ?:
+ parcel->write(touchableRegion) ?:
+ parcel->writeBool(replaceTouchableRegionWithCrop) ?:
+ parcel->writeStrongBinder(touchableRegionCropHandle.promote());
+
+ return status;
}
-InputWindowInfo InputWindowInfo::read(const Parcel& from) {
- InputWindowInfo ret;
-
- if (from.readInt32() == 0) {
- return ret;
+status_t InputWindowInfo::readFromParcel(const android::Parcel* parcel) {
+ if (parcel == nullptr) {
+ ALOGE("%s: Null parcel", __func__);
+ return BAD_VALUE;
+ }
+ if (parcel->readInt32() == 0) {
+ return OK;
}
- ret.token = from.readStrongBinder();
- ret.id = from.readInt32();
- ret.name = from.readString8().c_str();
- ret.layoutParamsFlags = from.readInt32();
- ret.layoutParamsType = from.readInt32();
- ret.dispatchingTimeout = from.readInt64();
- ret.frameLeft = from.readInt32();
- ret.frameTop = from.readInt32();
- ret.frameRight = from.readInt32();
- ret.frameBottom = from.readInt32();
- ret.surfaceInset = from.readInt32();
- ret.globalScaleFactor = from.readFloat();
- ret.windowXScale = from.readFloat();
- ret.windowYScale = from.readFloat();
- ret.visible = from.readBool();
- ret.canReceiveKeys = from.readBool();
- ret.hasFocus = from.readBool();
- ret.hasWallpaper = from.readBool();
- ret.paused = from.readBool();
- ret.ownerPid = from.readInt32();
- ret.ownerUid = from.readInt32();
- ret.inputFeatures = from.readInt32();
- ret.displayId = from.readInt32();
- ret.portalToDisplayId = from.readInt32();
- ret.applicationInfo = InputApplicationInfo::read(from);
- from.read(ret.touchableRegion);
- ret.replaceTouchableRegionWithCrop = from.readBool();
- ret.touchableRegionCropHandle = from.readStrongBinder();
+ token = parcel->readStrongBinder();
+ dispatchingTimeout = decltype(dispatchingTimeout)(parcel->readInt64());
+ status_t status = parcel->readInt32(&id) ?:
+ parcel->readUtf8FromUtf16(&name) ?:
+ parcel->readInt32(&layoutParamsFlags) ?:
+ parcel->readInt32(&layoutParamsType) ?:
+ parcel->readInt32(&frameLeft) ?:
+ parcel->readInt32(&frameTop) ?:
+ parcel->readInt32(&frameRight) ?:
+ parcel->readInt32(&frameBottom) ?:
+ parcel->readInt32(&surfaceInset) ?:
+ parcel->readFloat(&globalScaleFactor) ?:
+ parcel->readFloat(&windowXScale) ?:
+ parcel->readFloat(&windowYScale) ?:
+ parcel->readBool(&visible) ?:
+ parcel->readBool(&canReceiveKeys) ?:
+ parcel->readBool(&hasFocus) ?:
+ parcel->readBool(&hasWallpaper) ?:
+ parcel->readBool(&paused) ?:
+ parcel->readBool(&trustedOverlay) ?:
+ parcel->readInt32(&ownerPid) ?:
+ parcel->readInt32(&ownerUid) ?:
+ parcel->readInt32(&inputFeatures) ?:
+ parcel->readInt32(&displayId) ?:
+ parcel->readInt32(&portalToDisplayId) ?:
+ applicationInfo.readFromParcel(parcel) ?:
+ parcel->read(touchableRegion) ?:
+ parcel->readBool(&replaceTouchableRegionWithCrop);
- return ret;
-}
+ touchableRegionCropHandle = parcel->readStrongBinder();
-InputWindowInfo::InputWindowInfo(const Parcel& from) {
- *this = read(from);
+ return status;
}
// --- InputWindowHandle ---
-InputWindowHandle::InputWindowHandle() {
+InputWindowHandle::InputWindowHandle() {}
+
+InputWindowHandle::~InputWindowHandle() {}
+
+InputWindowHandle::InputWindowHandle(const InputWindowHandle& other) : mInfo(other.mInfo) {}
+
+InputWindowHandle::InputWindowHandle(const InputWindowInfo& other) : mInfo(other) {}
+
+status_t InputWindowHandle::writeToParcel(android::Parcel* parcel) const {
+ return mInfo.writeToParcel(parcel);
}
-InputWindowHandle::~InputWindowHandle() {
+status_t InputWindowHandle::readFromParcel(const android::Parcel* parcel) {
+ return mInfo.readFromParcel(parcel);
}
void InputWindowHandle::releaseChannel() {
diff --git a/libs/input/Keyboard.cpp b/libs/input/Keyboard.cpp
index 56900c1..25025f2 100644
--- a/libs/input/Keyboard.cpp
+++ b/libs/input/Keyboard.cpp
@@ -105,8 +105,7 @@
status_t KeyMap::loadKeyLayout(const InputDeviceIdentifier& deviceIdentifier,
const std::string& name) {
- std::string path(getPath(deviceIdentifier, name,
- INPUT_DEVICE_CONFIGURATION_FILE_TYPE_KEY_LAYOUT));
+ std::string path(getPath(deviceIdentifier, name, InputDeviceConfigurationFileType::KEY_LAYOUT));
if (path.empty()) {
return NAME_NOT_FOUND;
}
@@ -122,8 +121,8 @@
status_t KeyMap::loadKeyCharacterMap(const InputDeviceIdentifier& deviceIdentifier,
const std::string& name) {
- std::string path = getPath(deviceIdentifier, name,
- INPUT_DEVICE_CONFIGURATION_FILE_TYPE_KEY_CHARACTER_MAP);
+ std::string path =
+ getPath(deviceIdentifier, name, InputDeviceConfigurationFileType::KEY_CHARACTER_MAP);
if (path.empty()) {
return NAME_NOT_FOUND;
}
diff --git a/libs/input/VelocityTracker.cpp b/libs/input/VelocityTracker.cpp
index c6cc4fc..7c28ac5 100644
--- a/libs/input/VelocityTracker.cpp
+++ b/libs/input/VelocityTracker.cpp
@@ -104,107 +104,73 @@
// --- VelocityTracker ---
-// The default velocity tracker strategy.
-// Although other strategies are available for testing and comparison purposes,
-// this is the strategy that applications will actually use. Be very careful
-// when adjusting the default strategy because it can dramatically affect
-// (often in a bad way) the user experience.
-const char* VelocityTracker::DEFAULT_STRATEGY = "lsq2";
-
-VelocityTracker::VelocityTracker(const char* strategy) :
- mLastEventTime(0), mCurrentPointerIdBits(0), mActivePointerId(-1) {
- char value[PROPERTY_VALUE_MAX];
-
- // Allow the default strategy to be overridden using a system property for debugging.
- if (!strategy) {
- int length = property_get("persist.input.velocitytracker.strategy", value, nullptr);
- if (length > 0) {
- strategy = value;
- } else {
- strategy = DEFAULT_STRATEGY;
- }
- }
-
+VelocityTracker::VelocityTracker(const Strategy strategy)
+ : mLastEventTime(0), mCurrentPointerIdBits(0), mActivePointerId(-1) {
// Configure the strategy.
if (!configureStrategy(strategy)) {
- ALOGD("Unrecognized velocity tracker strategy name '%s'.", strategy);
- if (!configureStrategy(DEFAULT_STRATEGY)) {
- LOG_ALWAYS_FATAL("Could not create the default velocity tracker strategy '%s'!",
- strategy);
+ ALOGE("Unrecognized velocity tracker strategy %" PRId32 ".", strategy);
+ if (!configureStrategy(VelocityTracker::DEFAULT_STRATEGY)) {
+ LOG_ALWAYS_FATAL("Could not create the default velocity tracker strategy '%" PRId32
+ "'!",
+ strategy);
}
}
}
VelocityTracker::~VelocityTracker() {
- delete mStrategy;
}
-bool VelocityTracker::configureStrategy(const char* strategy) {
- mStrategy = createStrategy(strategy);
+bool VelocityTracker::configureStrategy(Strategy strategy) {
+ if (strategy == VelocityTracker::Strategy::DEFAULT) {
+ mStrategy = createStrategy(VelocityTracker::DEFAULT_STRATEGY);
+ } else {
+ mStrategy = createStrategy(strategy);
+ }
return mStrategy != nullptr;
}
-VelocityTrackerStrategy* VelocityTracker::createStrategy(const char* strategy) {
- if (!strcmp("impulse", strategy)) {
- // Physical model of pushing an object. Quality: VERY GOOD.
- // Works with duplicate coordinates, unclean finger liftoff.
- return new ImpulseVelocityTrackerStrategy();
- }
- if (!strcmp("lsq1", strategy)) {
- // 1st order least squares. Quality: POOR.
- // Frequently underfits the touch data especially when the finger accelerates
- // or changes direction. Often underestimates velocity. The direction
- // is overly influenced by historical touch points.
- return new LeastSquaresVelocityTrackerStrategy(1);
- }
- if (!strcmp("lsq2", strategy)) {
- // 2nd order least squares. Quality: VERY GOOD.
- // Pretty much ideal, but can be confused by certain kinds of touch data,
- // particularly if the panel has a tendency to generate delayed,
- // duplicate or jittery touch coordinates when the finger is released.
- return new LeastSquaresVelocityTrackerStrategy(2);
- }
- if (!strcmp("lsq3", strategy)) {
- // 3rd order least squares. Quality: UNUSABLE.
- // Frequently overfits the touch data yielding wildly divergent estimates
- // of the velocity when the finger is released.
- return new LeastSquaresVelocityTrackerStrategy(3);
- }
- if (!strcmp("wlsq2-delta", strategy)) {
- // 2nd order weighted least squares, delta weighting. Quality: EXPERIMENTAL
- return new LeastSquaresVelocityTrackerStrategy(2,
- LeastSquaresVelocityTrackerStrategy::WEIGHTING_DELTA);
- }
- if (!strcmp("wlsq2-central", strategy)) {
- // 2nd order weighted least squares, central weighting. Quality: EXPERIMENTAL
- return new LeastSquaresVelocityTrackerStrategy(2,
- LeastSquaresVelocityTrackerStrategy::WEIGHTING_CENTRAL);
- }
- if (!strcmp("wlsq2-recent", strategy)) {
- // 2nd order weighted least squares, recent weighting. Quality: EXPERIMENTAL
- return new LeastSquaresVelocityTrackerStrategy(2,
- LeastSquaresVelocityTrackerStrategy::WEIGHTING_RECENT);
- }
- if (!strcmp("int1", strategy)) {
- // 1st order integrating filter. Quality: GOOD.
- // Not as good as 'lsq2' because it cannot estimate acceleration but it is
- // more tolerant of errors. Like 'lsq1', this strategy tends to underestimate
- // the velocity of a fling but this strategy tends to respond to changes in
- // direction more quickly and accurately.
- return new IntegratingVelocityTrackerStrategy(1);
- }
- if (!strcmp("int2", strategy)) {
- // 2nd order integrating filter. Quality: EXPERIMENTAL.
- // For comparison purposes only. Unlike 'int1' this strategy can compensate
- // for acceleration but it typically overestimates the effect.
- return new IntegratingVelocityTrackerStrategy(2);
- }
- if (!strcmp("legacy", strategy)) {
- // Legacy velocity tracker algorithm. Quality: POOR.
- // For comparison purposes only. This algorithm is strongly influenced by
- // old data points, consistently underestimates velocity and takes a very long
- // time to adjust to changes in direction.
- return new LegacyVelocityTrackerStrategy();
+std::unique_ptr<VelocityTrackerStrategy> VelocityTracker::createStrategy(
+ VelocityTracker::Strategy strategy) {
+ switch (strategy) {
+ case VelocityTracker::Strategy::IMPULSE:
+ return std::make_unique<ImpulseVelocityTrackerStrategy>();
+
+ case VelocityTracker::Strategy::LSQ1:
+ return std::make_unique<LeastSquaresVelocityTrackerStrategy>(1);
+
+ case VelocityTracker::Strategy::LSQ2:
+ return std::make_unique<LeastSquaresVelocityTrackerStrategy>(2);
+
+ case VelocityTracker::Strategy::LSQ3:
+ return std::make_unique<LeastSquaresVelocityTrackerStrategy>(3);
+
+ case VelocityTracker::Strategy::WLSQ2_DELTA:
+ return std::make_unique<
+ LeastSquaresVelocityTrackerStrategy>(2,
+ LeastSquaresVelocityTrackerStrategy::
+ WEIGHTING_DELTA);
+ case VelocityTracker::Strategy::WLSQ2_CENTRAL:
+ return std::make_unique<
+ LeastSquaresVelocityTrackerStrategy>(2,
+ LeastSquaresVelocityTrackerStrategy::
+ WEIGHTING_CENTRAL);
+ case VelocityTracker::Strategy::WLSQ2_RECENT:
+ return std::make_unique<
+ LeastSquaresVelocityTrackerStrategy>(2,
+ LeastSquaresVelocityTrackerStrategy::
+ WEIGHTING_RECENT);
+
+ case VelocityTracker::Strategy::INT1:
+ return std::make_unique<IntegratingVelocityTrackerStrategy>(1);
+
+ case VelocityTracker::Strategy::INT2:
+ return std::make_unique<IntegratingVelocityTrackerStrategy>(2);
+
+ case VelocityTracker::Strategy::LEGACY:
+ return std::make_unique<LegacyVelocityTrackerStrategy>();
+
+ default:
+ break;
}
return nullptr;
}
diff --git a/libs/input/android/InputChannelInfo.aidl b/libs/input/android/InputChannelInfo.aidl
new file mode 100644
index 0000000..2e83b96
--- /dev/null
+++ b/libs/input/android/InputChannelInfo.aidl
@@ -0,0 +1,20 @@
+/* //device/java/android/android/view/InputChannel.aidl
+**
+** 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.
+*/
+
+package android;
+
+parcelable InputChannelInfo cpp_header "input/InputTransport.h";
diff --git a/libs/input/android/InputWindowInfo.aidl b/libs/input/android/InputWindowInfo.aidl
new file mode 100644
index 0000000..eeaf400
--- /dev/null
+++ b/libs/input/android/InputWindowInfo.aidl
@@ -0,0 +1,20 @@
+/* //device/java/android/android/view/InputChannel.aidl
+**
+** 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.
+*/
+
+package android;
+
+parcelable InputWindowInfo cpp_header "input/InputWindow.h";
diff --git a/libs/input/android/os/IInputFlinger.aidl b/libs/input/android/os/IInputFlinger.aidl
new file mode 100644
index 0000000..8ff9dae
--- /dev/null
+++ b/libs/input/android/os/IInputFlinger.aidl
@@ -0,0 +1,30 @@
+/**
+ * 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.
+ */
+
+package android.os;
+
+import android.InputChannelInfo;
+import android.InputWindowInfo;
+import android.os.ISetInputWindowsListener;
+
+/** @hide */
+interface IInputFlinger
+{
+ void setInputWindows(in InputWindowInfo[] inputHandles,
+ in @nullable ISetInputWindowsListener setInputWindowsListener);
+ void registerInputChannel(in InputChannelInfo info);
+ void unregisterInputChannel(in InputChannelInfo info);
+}
diff --git a/libs/input/android/os/ISetInputWindowsListener.aidl b/libs/input/android/os/ISetInputWindowsListener.aidl
new file mode 100644
index 0000000..bb58fb6
--- /dev/null
+++ b/libs/input/android/os/ISetInputWindowsListener.aidl
@@ -0,0 +1,23 @@
+/**
+ * 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.
+ */
+
+package android.os;
+
+/** @hide */
+oneway interface ISetInputWindowsListener
+{
+ void onSetInputWindowsFinished();
+}
diff --git a/libs/input/tests/InputChannel_test.cpp b/libs/input/tests/InputChannel_test.cpp
index ada275d..7f4bd6e 100644
--- a/libs/input/tests/InputChannel_test.cpp
+++ b/libs/input/tests/InputChannel_test.cpp
@@ -23,6 +23,7 @@
#include <errno.h>
#include <binder/Binder.h>
+#include <binder/Parcel.h>
#include <gtest/gtest.h>
#include <input/InputTransport.h>
#include <utils/StopWatch.h>
@@ -197,5 +198,36 @@
}
}
+TEST_F(InputChannelTest, InputChannelParcelAndUnparcel) {
+ sp<InputChannel> serverChannel, clientChannel;
+
+ status_t result =
+ InputChannel::openInputChannelPair("channel parceling", serverChannel, clientChannel);
+
+ ASSERT_EQ(OK, result) << "should have successfully opened a channel pair";
+
+ InputChannel chan;
+ Parcel parcel;
+ ASSERT_EQ(OK, serverChannel->writeToParcel(&parcel));
+ parcel.setDataPosition(0);
+ chan.readFromParcel(&parcel);
+
+ EXPECT_EQ(chan == *serverChannel, true)
+ << "inputchannel should be equal after parceling and unparceling.\n"
+ << "name " << chan.getName() << " name " << serverChannel->getName();
+}
+
+TEST_F(InputChannelTest, DuplicateChannelAndAssertEqual) {
+ sp<InputChannel> serverChannel, clientChannel;
+
+ status_t result =
+ InputChannel::openInputChannelPair("channel dup", serverChannel, clientChannel);
+
+ ASSERT_EQ(OK, result) << "should have successfully opened a channel pair";
+
+ sp<InputChannel> dupChan = serverChannel->dup();
+
+ EXPECT_EQ(*serverChannel == *dupChan, true) << "inputchannel should be equal after duplication";
+}
} // namespace android
diff --git a/libs/input/tests/InputWindow_test.cpp b/libs/input/tests/InputWindow_test.cpp
index d1cb527..cdea922 100644
--- a/libs/input/tests/InputWindow_test.cpp
+++ b/libs/input/tests/InputWindow_test.cpp
@@ -22,17 +22,19 @@
#include <input/InputWindow.h>
#include <input/InputTransport.h>
+using std::chrono_literals::operator""s;
+
namespace android {
namespace test {
TEST(InputWindowInfo, ParcellingWithoutToken) {
- InputWindowInfo i;
+ InputWindowInfo i, i2;
i.token = nullptr;
Parcel p;
- ASSERT_EQ(OK, i.write(p));
+ ASSERT_EQ(OK, i.writeToParcel(&p));
p.setDataPosition(0);
- InputWindowInfo i2 = InputWindowInfo::read(p);
+ i2.readFromParcel(&p);
ASSERT_TRUE(i2.token == nullptr);
}
@@ -44,7 +46,7 @@
i.name = "Foobar";
i.layoutParamsFlags = 7;
i.layoutParamsType = 39;
- i.dispatchingTimeout = 12;
+ i.dispatchingTimeout = 12s;
i.frameLeft = 93;
i.frameTop = 34;
i.frameRight = 16;
@@ -67,10 +69,10 @@
i.touchableRegionCropHandle = touchableRegionCropHandle;
Parcel p;
- i.write(p);
-
+ i.writeToParcel(&p);
p.setDataPosition(0);
- InputWindowInfo i2 = InputWindowInfo::read(p);
+ InputWindowInfo i2;
+ i2.readFromParcel(&p);
ASSERT_EQ(i.token, i2.token);
ASSERT_EQ(i.id, i2.id);
ASSERT_EQ(i.name, i2.name);
diff --git a/libs/input/tests/VelocityTracker_test.cpp b/libs/input/tests/VelocityTracker_test.cpp
index bf452c0..249d9d4 100644
--- a/libs/input/tests/VelocityTracker_test.cpp
+++ b/libs/input/tests/VelocityTracker_test.cpp
@@ -191,8 +191,9 @@
return events;
}
-static void computeAndCheckVelocity(const char* strategy,
- const std::vector<MotionEventEntry>& motions, int32_t axis, float targetVelocity) {
+static void computeAndCheckVelocity(const VelocityTracker::Strategy strategy,
+ const std::vector<MotionEventEntry>& motions, int32_t axis,
+ float targetVelocity) {
VelocityTracker vt(strategy);
float Vx, Vy;
@@ -217,7 +218,7 @@
static void computeAndCheckQuadraticEstimate(const std::vector<MotionEventEntry>& motions,
const std::array<float, 3>& coefficients) {
- VelocityTracker vt("lsq2");
+ VelocityTracker vt(VelocityTracker::Strategy::LSQ2);
std::vector<MotionEvent> events = createMotionEventStream(motions);
for (MotionEvent event : events) {
vt.addMovement(&event);
@@ -243,7 +244,8 @@
{14730us, {{293, NAN}}},
{14730us, {{293, NAN}}}, // ACTION_UP
};
- computeAndCheckVelocity("impulse", motions, AMOTION_EVENT_AXIS_X, 1600);
+ computeAndCheckVelocity(VelocityTracker::Strategy::IMPULSE, motions, AMOTION_EVENT_AXIS_X,
+ 1600);
}
TEST_F(VelocityTrackerTest, ThreePointsZeroVelocityTest) {
@@ -254,8 +256,8 @@
{ 11283us, {{293, NAN}} },
{ 11283us, {{293, NAN}} }, // ACTION_UP
};
- computeAndCheckVelocity("impulse", motions, AMOTION_EVENT_AXIS_X, 0);
- computeAndCheckVelocity("lsq2", motions, AMOTION_EVENT_AXIS_X, 0);
+ computeAndCheckVelocity(VelocityTracker::Strategy::IMPULSE, motions, AMOTION_EVENT_AXIS_X, 0);
+ computeAndCheckVelocity(VelocityTracker::Strategy::LSQ2, motions, AMOTION_EVENT_AXIS_X, 0);
}
TEST_F(VelocityTrackerTest, ThreePointsLinearVelocityTest) {
@@ -266,8 +268,8 @@
{ 20ms, {{10, NAN}} },
{ 20ms, {{10, NAN}} }, // ACTION_UP
};
- computeAndCheckVelocity("impulse", motions, AMOTION_EVENT_AXIS_X, 500);
- computeAndCheckVelocity("lsq2", motions, AMOTION_EVENT_AXIS_X, 500);
+ computeAndCheckVelocity(VelocityTracker::Strategy::IMPULSE, motions, AMOTION_EVENT_AXIS_X, 500);
+ computeAndCheckVelocity(VelocityTracker::Strategy::LSQ2, motions, AMOTION_EVENT_AXIS_X, 500);
}
@@ -297,8 +299,10 @@
{ 96948871ns, {{274.79245, 428.113159}} },
{ 96948871ns, {{274.79245, 428.113159}} }, // ACTION_UP
};
- computeAndCheckVelocity("impulse", motions, AMOTION_EVENT_AXIS_X, 623.577637);
- computeAndCheckVelocity("impulse", motions, AMOTION_EVENT_AXIS_Y, 5970.7309);
+ computeAndCheckVelocity(VelocityTracker::Strategy::IMPULSE, motions, AMOTION_EVENT_AXIS_X,
+ 623.577637);
+ computeAndCheckVelocity(VelocityTracker::Strategy::IMPULSE, motions, AMOTION_EVENT_AXIS_Y,
+ 5970.7309);
}
// --------------- Recorded by hand on sailfish, generated by a script -----------------------------
@@ -339,10 +343,14 @@
{ 235089162955851ns, {{560.66, 843.82}} },
{ 235089162955851ns, {{560.66, 843.82}} }, // ACTION_UP
};
- computeAndCheckVelocity("impulse", motions, AMOTION_EVENT_AXIS_X, 872.794617);
- computeAndCheckVelocity("lsq2", motions, AMOTION_EVENT_AXIS_X, 951.698181);
- computeAndCheckVelocity("impulse",motions, AMOTION_EVENT_AXIS_Y, -3604.819336);
- computeAndCheckVelocity("lsq2", motions, AMOTION_EVENT_AXIS_Y, -3044.966064);
+ computeAndCheckVelocity(VelocityTracker::Strategy::IMPULSE, motions, AMOTION_EVENT_AXIS_X,
+ 872.794617);
+ computeAndCheckVelocity(VelocityTracker::Strategy::LSQ2, motions, AMOTION_EVENT_AXIS_X,
+ 951.698181);
+ computeAndCheckVelocity(VelocityTracker::Strategy::IMPULSE, motions, AMOTION_EVENT_AXIS_Y,
+ -3604.819336);
+ computeAndCheckVelocity(VelocityTracker::Strategy::LSQ2, motions, AMOTION_EVENT_AXIS_Y,
+ -3044.966064);
}
@@ -368,8 +376,10 @@
{ 235110660368000ns, {{530.00, 980.00}} },
{ 235110660368000ns, {{530.00, 980.00}} }, // ACTION_UP
};
- computeAndCheckVelocity("impulse", motions, AMOTION_EVENT_AXIS_Y, -4096.583008);
- computeAndCheckVelocity("lsq2", motions, AMOTION_EVENT_AXIS_Y, -3455.094238);
+ computeAndCheckVelocity(VelocityTracker::Strategy::IMPULSE, motions, AMOTION_EVENT_AXIS_Y,
+ -4096.583008);
+ computeAndCheckVelocity(VelocityTracker::Strategy::LSQ2, motions, AMOTION_EVENT_AXIS_Y,
+ -3455.094238);
}
@@ -396,10 +406,14 @@
{ 792629200000ns, {{619.00, 1115.00}} },
{ 792629200000ns, {{619.00, 1115.00}} }, // ACTION_UP
};
- computeAndCheckVelocity("impulse", motions, AMOTION_EVENT_AXIS_X, 574.33429);
- computeAndCheckVelocity("lsq2", motions, AMOTION_EVENT_AXIS_X, 617.40564);
- computeAndCheckVelocity("impulse", motions, AMOTION_EVENT_AXIS_Y, -2361.982666);
- computeAndCheckVelocity("lsq2", motions, AMOTION_EVENT_AXIS_Y, -2500.055664);
+ computeAndCheckVelocity(VelocityTracker::Strategy::IMPULSE, motions, AMOTION_EVENT_AXIS_X,
+ 574.33429);
+ computeAndCheckVelocity(VelocityTracker::Strategy::LSQ2, motions, AMOTION_EVENT_AXIS_X,
+ 617.40564);
+ computeAndCheckVelocity(VelocityTracker::Strategy::IMPULSE, motions, AMOTION_EVENT_AXIS_Y,
+ -2361.982666);
+ computeAndCheckVelocity(VelocityTracker::Strategy::LSQ2, motions, AMOTION_EVENT_AXIS_Y,
+ -2500.055664);
}
@@ -426,10 +440,14 @@
{ 235160520366000ns, {{679.00, 814.00}} },
{ 235160520366000ns, {{679.00, 814.00}} }, // ACTION_UP
};
- computeAndCheckVelocity("impulse", motions, AMOTION_EVENT_AXIS_X, 1274.141724);
- computeAndCheckVelocity("lsq2", motions, AMOTION_EVENT_AXIS_X, 1438.53186);
- computeAndCheckVelocity("impulse", motions, AMOTION_EVENT_AXIS_Y, -3001.4348);
- computeAndCheckVelocity("lsq2", motions, AMOTION_EVENT_AXIS_Y, -3695.859619);
+ computeAndCheckVelocity(VelocityTracker::Strategy::IMPULSE, motions, AMOTION_EVENT_AXIS_X,
+ 1274.141724);
+ computeAndCheckVelocity(VelocityTracker::Strategy::LSQ2, motions, AMOTION_EVENT_AXIS_X,
+ 1438.53186);
+ computeAndCheckVelocity(VelocityTracker::Strategy::IMPULSE, motions, AMOTION_EVENT_AXIS_Y,
+ -3001.4348);
+ computeAndCheckVelocity(VelocityTracker::Strategy::LSQ2, motions, AMOTION_EVENT_AXIS_Y,
+ -3695.859619);
}
@@ -452,8 +470,10 @@
{ 847237986000ns, {{610.00, 1095.00}} },
{ 847237986000ns, {{610.00, 1095.00}} }, // ACTION_UP
};
- computeAndCheckVelocity("impulse", motions, AMOTION_EVENT_AXIS_Y, -4280.07959);
- computeAndCheckVelocity("lsq2", motions, AMOTION_EVENT_AXIS_Y, -4241.004395);
+ computeAndCheckVelocity(VelocityTracker::Strategy::IMPULSE, motions, AMOTION_EVENT_AXIS_Y,
+ -4280.07959);
+ computeAndCheckVelocity(VelocityTracker::Strategy::LSQ2, motions, AMOTION_EVENT_AXIS_Y,
+ -4241.004395);
}
@@ -476,8 +496,10 @@
{ 235200616933000ns, {{590.00, 844.00}} },
{ 235200616933000ns, {{590.00, 844.00}} }, // ACTION_UP
};
- computeAndCheckVelocity("impulse", motions, AMOTION_EVENT_AXIS_Y, -8715.686523);
- computeAndCheckVelocity("lsq2", motions, AMOTION_EVENT_AXIS_Y, -7639.026367);
+ computeAndCheckVelocity(VelocityTracker::Strategy::IMPULSE, motions, AMOTION_EVENT_AXIS_Y,
+ -8715.686523);
+ computeAndCheckVelocity(VelocityTracker::Strategy::LSQ2, motions, AMOTION_EVENT_AXIS_Y,
+ -7639.026367);
}
@@ -499,10 +521,14 @@
{ 920989261000ns, {{715.00, 903.00}} },
{ 920989261000ns, {{715.00, 903.00}} }, // ACTION_UP
};
- computeAndCheckVelocity("impulse", motions, AMOTION_EVENT_AXIS_X, 5670.329102);
- computeAndCheckVelocity("lsq2", motions, AMOTION_EVENT_AXIS_X, 5991.866699);
- computeAndCheckVelocity("impulse", motions, AMOTION_EVENT_AXIS_Y, -13021.101562);
- computeAndCheckVelocity("lsq2", motions, AMOTION_EVENT_AXIS_Y, -15093.995117);
+ computeAndCheckVelocity(VelocityTracker::Strategy::IMPULSE, motions, AMOTION_EVENT_AXIS_X,
+ 5670.329102);
+ computeAndCheckVelocity(VelocityTracker::Strategy::LSQ2, motions, AMOTION_EVENT_AXIS_X,
+ 5991.866699);
+ computeAndCheckVelocity(VelocityTracker::Strategy::IMPULSE, motions, AMOTION_EVENT_AXIS_Y,
+ -13021.101562);
+ computeAndCheckVelocity(VelocityTracker::Strategy::LSQ2, motions, AMOTION_EVENT_AXIS_Y,
+ -15093.995117);
}
@@ -522,8 +548,10 @@
{ 235247220736000ns, {{620.00, 641.00}} },
{ 235247220736000ns, {{620.00, 641.00}} }, // ACTION_UP
};
- computeAndCheckVelocity("impulse", motions, AMOTION_EVENT_AXIS_Y, -20286.958984);
- computeAndCheckVelocity("lsq2", motions, AMOTION_EVENT_AXIS_Y, -20494.587891);
+ computeAndCheckVelocity(VelocityTracker::Strategy::IMPULSE, motions, AMOTION_EVENT_AXIS_Y,
+ -20286.958984);
+ computeAndCheckVelocity(VelocityTracker::Strategy::LSQ2, motions, AMOTION_EVENT_AXIS_Y,
+ -20494.587891);
}
@@ -541,8 +569,10 @@
{ 235302613019881ns, {{679.26, 526.73}} },
{ 235302613019881ns, {{679.26, 526.73}} }, // ACTION_UP
};
- computeAndCheckVelocity("impulse", motions, AMOTION_EVENT_AXIS_Y, -39295.941406);
- computeAndCheckVelocity("lsq2", motions, AMOTION_EVENT_AXIS_Y, -36461.421875);
+ computeAndCheckVelocity(VelocityTracker::Strategy::IMPULSE, motions, AMOTION_EVENT_AXIS_Y,
+ -39295.941406);
+ computeAndCheckVelocity(VelocityTracker::Strategy::LSQ2, motions, AMOTION_EVENT_AXIS_Y,
+ -36461.421875);
}
@@ -569,10 +599,14 @@
{ 235655842893000ns, {{563.00, 649.00}} },
{ 235655842893000ns, {{563.00, 649.00}} }, // ACTION_UP
};
- computeAndCheckVelocity("impulse", motions, AMOTION_EVENT_AXIS_X, -419.749695);
- computeAndCheckVelocity("lsq2", motions, AMOTION_EVENT_AXIS_X, -398.303894);
- computeAndCheckVelocity("impulse", motions, AMOTION_EVENT_AXIS_Y, 3309.016357);
- computeAndCheckVelocity("lsq2", motions, AMOTION_EVENT_AXIS_Y, 3969.099854);
+ computeAndCheckVelocity(VelocityTracker::Strategy::IMPULSE, motions, AMOTION_EVENT_AXIS_X,
+ -419.749695);
+ computeAndCheckVelocity(VelocityTracker::Strategy::LSQ2, motions, AMOTION_EVENT_AXIS_X,
+ -398.303894);
+ computeAndCheckVelocity(VelocityTracker::Strategy::IMPULSE, motions, AMOTION_EVENT_AXIS_Y,
+ 3309.016357);
+ computeAndCheckVelocity(VelocityTracker::Strategy::LSQ2, motions, AMOTION_EVENT_AXIS_Y,
+ 3969.099854);
}
@@ -599,10 +633,14 @@
{ 235671246532000ns, {{470.00, 799.00}} },
{ 235671246532000ns, {{470.00, 799.00}} }, // ACTION_UP
};
- computeAndCheckVelocity("impulse", motions, AMOTION_EVENT_AXIS_X, -262.80426);
- computeAndCheckVelocity("lsq2", motions, AMOTION_EVENT_AXIS_X, -243.665344);
- computeAndCheckVelocity("impulse", motions, AMOTION_EVENT_AXIS_Y, 4215.682129);
- computeAndCheckVelocity("lsq2", motions, AMOTION_EVENT_AXIS_Y, 4587.986816);
+ computeAndCheckVelocity(VelocityTracker::Strategy::IMPULSE, motions, AMOTION_EVENT_AXIS_X,
+ -262.80426);
+ computeAndCheckVelocity(VelocityTracker::Strategy::LSQ2, motions, AMOTION_EVENT_AXIS_X,
+ -243.665344);
+ computeAndCheckVelocity(VelocityTracker::Strategy::IMPULSE, motions, AMOTION_EVENT_AXIS_Y,
+ 4215.682129);
+ computeAndCheckVelocity(VelocityTracker::Strategy::LSQ2, motions, AMOTION_EVENT_AXIS_Y,
+ 4587.986816);
}
@@ -622,10 +660,14 @@
{ 171051052000ns, {{536.00, 586.00}} },
{ 171051052000ns, {{536.00, 586.00}} }, // ACTION_UP
};
- computeAndCheckVelocity("impulse", motions, AMOTION_EVENT_AXIS_X, -723.413513);
- computeAndCheckVelocity("lsq2", motions, AMOTION_EVENT_AXIS_X, -651.038452);
- computeAndCheckVelocity("impulse", motions, AMOTION_EVENT_AXIS_Y, 2091.502441);
- computeAndCheckVelocity("lsq2", motions, AMOTION_EVENT_AXIS_Y, 1934.517456);
+ computeAndCheckVelocity(VelocityTracker::Strategy::IMPULSE, motions, AMOTION_EVENT_AXIS_X,
+ -723.413513);
+ computeAndCheckVelocity(VelocityTracker::Strategy::LSQ2, motions, AMOTION_EVENT_AXIS_X,
+ -651.038452);
+ computeAndCheckVelocity(VelocityTracker::Strategy::IMPULSE, motions, AMOTION_EVENT_AXIS_Y,
+ 2091.502441);
+ computeAndCheckVelocity(VelocityTracker::Strategy::LSQ2, motions, AMOTION_EVENT_AXIS_Y,
+ 1934.517456);
}
@@ -652,8 +694,10 @@
{ 235695373403000ns, {{564.00, 744.00}} },
{ 235695373403000ns, {{564.00, 744.00}} }, // ACTION_UP
};
- computeAndCheckVelocity("impulse", motions, AMOTION_EVENT_AXIS_Y, 4254.639648);
- computeAndCheckVelocity("lsq2", motions, AMOTION_EVENT_AXIS_Y, 4698.415039);
+ computeAndCheckVelocity(VelocityTracker::Strategy::IMPULSE, motions, AMOTION_EVENT_AXIS_Y,
+ 4254.639648);
+ computeAndCheckVelocity(VelocityTracker::Strategy::LSQ2, motions, AMOTION_EVENT_AXIS_Y,
+ 4698.415039);
}
@@ -677,10 +721,14 @@
{ 235709710626776ns, {{511.72, 741.85}} },
{ 235709710626776ns, {{511.72, 741.85}} }, // ACTION_UP
};
- computeAndCheckVelocity("impulse", motions, AMOTION_EVENT_AXIS_X, -430.440247);
- computeAndCheckVelocity("lsq2", motions, AMOTION_EVENT_AXIS_X, -447.600311);
- computeAndCheckVelocity("impulse", motions, AMOTION_EVENT_AXIS_Y, 3953.859375);
- computeAndCheckVelocity("lsq2", motions, AMOTION_EVENT_AXIS_Y, 4316.155273);
+ computeAndCheckVelocity(VelocityTracker::Strategy::IMPULSE, motions, AMOTION_EVENT_AXIS_X,
+ -430.440247);
+ computeAndCheckVelocity(VelocityTracker::Strategy::LSQ2, motions, AMOTION_EVENT_AXIS_X,
+ -447.600311);
+ computeAndCheckVelocity(VelocityTracker::Strategy::IMPULSE, motions, AMOTION_EVENT_AXIS_Y,
+ 3953.859375);
+ computeAndCheckVelocity(VelocityTracker::Strategy::LSQ2, motions, AMOTION_EVENT_AXIS_Y,
+ 4316.155273);
}
@@ -706,8 +754,10 @@
{ 235727721580000ns, {{516.00, 658.00}} },
{ 235727721580000ns, {{516.00, 658.00}} }, // ACTION_UP
};
- computeAndCheckVelocity("impulse", motions, AMOTION_EVENT_AXIS_Y, 4484.617676);
- computeAndCheckVelocity("lsq2", motions, AMOTION_EVENT_AXIS_Y, 4927.92627);
+ computeAndCheckVelocity(VelocityTracker::Strategy::IMPULSE, motions, AMOTION_EVENT_AXIS_Y,
+ 4484.617676);
+ computeAndCheckVelocity(VelocityTracker::Strategy::LSQ2, motions, AMOTION_EVENT_AXIS_Y,
+ 4927.92627);
}
@@ -725,8 +775,10 @@
{ 235762396429369ns, {{404.37, 680.67}} },
{ 235762396429369ns, {{404.37, 680.67}} }, //ACTION_UP
};
- computeAndCheckVelocity("impulse", motions, AMOTION_EVENT_AXIS_Y, 14227.0224);
- computeAndCheckVelocity("lsq2", motions, AMOTION_EVENT_AXIS_Y, 16064.685547);
+ computeAndCheckVelocity(VelocityTracker::Strategy::IMPULSE, motions, AMOTION_EVENT_AXIS_Y,
+ 14227.0224);
+ computeAndCheckVelocity(VelocityTracker::Strategy::LSQ2, motions, AMOTION_EVENT_AXIS_Y,
+ 16064.685547);
}
@@ -744,8 +796,10 @@
{ 235772537635000ns, {{484.00, 589.00}} },
{ 235772537635000ns, {{484.00, 589.00}} }, // ACTION_UP
};
- computeAndCheckVelocity("impulse", motions, AMOTION_EVENT_AXIS_Y, 18660.048828);
- computeAndCheckVelocity("lsq2", motions, AMOTION_EVENT_AXIS_Y, 16918.439453);
+ computeAndCheckVelocity(VelocityTracker::Strategy::IMPULSE, motions, AMOTION_EVENT_AXIS_Y,
+ 18660.048828);
+ computeAndCheckVelocity(VelocityTracker::Strategy::LSQ2, motions, AMOTION_EVENT_AXIS_Y,
+ 16918.439453);
}
@@ -764,10 +818,14 @@
{ 507703352649ns, {{443.71, 857.77}} },
{ 507703352649ns, {{443.71, 857.77}} }, // ACTION_UP
};
- computeAndCheckVelocity("impulse", motions, AMOTION_EVENT_AXIS_X, -4111.8173);
- computeAndCheckVelocity("lsq2", motions, AMOTION_EVENT_AXIS_X, -6388.48877);
- computeAndCheckVelocity("impulse", motions, AMOTION_EVENT_AXIS_Y, 29765.908203);
- computeAndCheckVelocity("lsq2", motions, AMOTION_EVENT_AXIS_Y, 28354.796875);
+ computeAndCheckVelocity(VelocityTracker::Strategy::IMPULSE, motions, AMOTION_EVENT_AXIS_X,
+ -4111.8173);
+ computeAndCheckVelocity(VelocityTracker::Strategy::LSQ2, motions, AMOTION_EVENT_AXIS_X,
+ -6388.48877);
+ computeAndCheckVelocity(VelocityTracker::Strategy::IMPULSE, motions, AMOTION_EVENT_AXIS_Y,
+ 29765.908203);
+ computeAndCheckVelocity(VelocityTracker::Strategy::LSQ2, motions, AMOTION_EVENT_AXIS_Y,
+ 28354.796875);
}
/**
@@ -789,10 +847,10 @@
// Velocity should actually be zero, but we expect 0.016 here instead.
// This is close enough to zero, and is likely caused by division by a very small number.
- computeAndCheckVelocity("lsq2", motions, AMOTION_EVENT_AXIS_X, -0.016);
- computeAndCheckVelocity("lsq2", motions, AMOTION_EVENT_AXIS_Y, -0.016);
- computeAndCheckVelocity("impulse", motions, AMOTION_EVENT_AXIS_X, 0);
- computeAndCheckVelocity("impulse", motions, AMOTION_EVENT_AXIS_Y, 0);
+ computeAndCheckVelocity(VelocityTracker::Strategy::LSQ2, motions, AMOTION_EVENT_AXIS_X, -0.016);
+ computeAndCheckVelocity(VelocityTracker::Strategy::LSQ2, motions, AMOTION_EVENT_AXIS_Y, -0.016);
+ computeAndCheckVelocity(VelocityTracker::Strategy::IMPULSE, motions, AMOTION_EVENT_AXIS_X, 0);
+ computeAndCheckVelocity(VelocityTracker::Strategy::IMPULSE, motions, AMOTION_EVENT_AXIS_Y, 0);
}
/**
diff --git a/libs/math/Android.bp b/libs/math/Android.bp
index 3b1edcb..22d4712 100644
--- a/libs/math/Android.bp
+++ b/libs/math/Android.bp
@@ -25,6 +25,11 @@
min_sdk_version: "29",
export_include_dirs: ["include"],
+ target: {
+ windows: {
+ enabled: true,
+ }
+ }
}
subdirs = ["tests"]
diff --git a/libs/math/include/math/half.h b/libs/math/include/math/half.h
index 7682973..617a0ab 100644
--- a/libs/math/include/math/half.h
+++ b/libs/math/include/math/half.h
@@ -82,6 +82,7 @@
};
public:
+ CONSTEXPR half() noexcept { }
CONSTEXPR half(float v) noexcept : mBits(ftoh(v)) { }
CONSTEXPR operator float() const noexcept { return htof(mBits); }
diff --git a/libs/math/tests/half_test.cpp b/libs/math/tests/half_test.cpp
index 496a7ef..604072e 100644
--- a/libs/math/tests/half_test.cpp
+++ b/libs/math/tests/half_test.cpp
@@ -35,6 +35,7 @@
EXPECT_EQ(2UL, sizeof(half));
// test +/- zero
+ EXPECT_EQ(0x0000, half().getBits());
EXPECT_EQ(0x0000, half( 0.0f).getBits());
EXPECT_EQ(0x8000, half(-0.0f).getBits());
diff --git a/libs/renderengine/Android.bp b/libs/renderengine/Android.bp
index eb6080f..3dcb498 100644
--- a/libs/renderengine/Android.bp
+++ b/libs/renderengine/Android.bp
@@ -64,6 +64,13 @@
],
}
+filegroup {
+ name: "librenderengine_threaded_sources",
+ srcs: [
+ "threaded/RenderEngineThreaded.cpp",
+ ],
+}
+
cc_library_static {
name: "librenderengine",
defaults: ["librenderengine_defaults"],
@@ -80,6 +87,7 @@
srcs: [
":librenderengine_sources",
":librenderengine_gl_sources",
+ ":librenderengine_threaded_sources",
],
lto: {
thin: true,
diff --git a/libs/renderengine/RenderEngine.cpp b/libs/renderengine/RenderEngine.cpp
index 0fdf093..c3fbb60 100644
--- a/libs/renderengine/RenderEngine.cpp
+++ b/libs/renderengine/RenderEngine.cpp
@@ -20,19 +20,34 @@
#include <log/log.h>
#include <private/gui/SyncFeatures.h>
#include "gl/GLESRenderEngine.h"
+#include "threaded/RenderEngineThreaded.h"
namespace android {
namespace renderengine {
-std::unique_ptr<impl::RenderEngine> RenderEngine::create(const RenderEngineCreationArgs& args) {
+std::unique_ptr<RenderEngine> RenderEngine::create(const RenderEngineCreationArgs& args) {
+ RenderEngineType renderEngineType = args.renderEngineType;
+
+ // Keep the ability to override by PROPERTIES:
char prop[PROPERTY_VALUE_MAX];
- property_get(PROPERTY_DEBUG_RENDERENGINE_BACKEND, prop, "gles");
+ property_get(PROPERTY_DEBUG_RENDERENGINE_BACKEND, prop, "");
if (strcmp(prop, "gles") == 0) {
- ALOGD("RenderEngine GLES Backend");
- return renderengine::gl::GLESRenderEngine::create(args);
+ renderEngineType = RenderEngineType::GLES;
}
- ALOGE("UNKNOWN BackendType: %s, create GLES RenderEngine.", prop);
- return renderengine::gl::GLESRenderEngine::create(args);
+ if (strcmp(prop, "threaded") == 0) {
+ renderEngineType = RenderEngineType::THREADED;
+ }
+
+ switch (renderEngineType) {
+ case RenderEngineType::THREADED:
+ ALOGD("Threaded RenderEngine with GLES Backend");
+ return renderengine::threaded::RenderEngineThreaded::create(
+ [args]() { return android::renderengine::gl::GLESRenderEngine::create(args); });
+ case RenderEngineType::GLES:
+ default:
+ ALOGD("RenderEngine with GLES Backend");
+ return renderengine::gl::GLESRenderEngine::create(args);
+ }
}
RenderEngine::~RenderEngine() = default;
diff --git a/libs/renderengine/gl/GLESRenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp
index 92e7e71..d102696 100644
--- a/libs/renderengine/gl/GLESRenderEngine.cpp
+++ b/libs/renderengine/gl/GLESRenderEngine.cpp
@@ -982,7 +982,7 @@
status_t GLESRenderEngine::drawLayers(const DisplaySettings& display,
const std::vector<const LayerSettings*>& layers,
- ANativeWindowBuffer* const buffer,
+ const sp<GraphicBuffer>& buffer,
const bool useFramebufferCache, base::unique_fd&& bufferFence,
base::unique_fd* drawFence) {
ATRACE_CALL();
@@ -1019,7 +1019,9 @@
const auto blurLayersSize = blurLayers.size();
if (blurLayersSize == 0) {
- fbo = std::make_unique<BindNativeBufferAsFramebuffer>(*this, buffer, useFramebufferCache);
+ fbo = std::make_unique<BindNativeBufferAsFramebuffer>(*this,
+ buffer.get()->getNativeBuffer(),
+ useFramebufferCache);
if (fbo->getStatus() != NO_ERROR) {
ALOGE("Failed to bind framebuffer! Aborting GPU composition for buffer (%p).",
buffer->handle);
@@ -1076,7 +1078,9 @@
if (blurLayers.size() == 0) {
// Done blurring, time to bind the native FBO and render our blur onto it.
- fbo = std::make_unique<BindNativeBufferAsFramebuffer>(*this, buffer,
+ fbo = std::make_unique<BindNativeBufferAsFramebuffer>(*this,
+ buffer.get()
+ ->getNativeBuffer(),
useFramebufferCache);
status = fbo->getStatus();
setViewportAndProjection(display.physicalDisplay, display.clip);
diff --git a/libs/renderengine/gl/GLESRenderEngine.h b/libs/renderengine/gl/GLESRenderEngine.h
index 42b8537..9ab5ee6 100644
--- a/libs/renderengine/gl/GLESRenderEngine.h
+++ b/libs/renderengine/gl/GLESRenderEngine.h
@@ -73,7 +73,7 @@
bool useProtectedContext(bool useProtectedContext) override;
status_t drawLayers(const DisplaySettings& display,
const std::vector<const LayerSettings*>& layers,
- ANativeWindowBuffer* buffer, const bool useFramebufferCache,
+ const sp<GraphicBuffer>& buffer, const bool useFramebufferCache,
base::unique_fd&& bufferFence, base::unique_fd* drawFence) override;
bool cleanupPostRender() override;
diff --git a/libs/renderengine/include/renderengine/RenderEngine.h b/libs/renderengine/include/renderengine/RenderEngine.h
index e06e128..b137023 100644
--- a/libs/renderengine/include/renderengine/RenderEngine.h
+++ b/libs/renderengine/include/renderengine/RenderEngine.h
@@ -50,6 +50,10 @@
class Texture;
struct RenderEngineCreationArgs;
+namespace threaded {
+class RenderEngineThreaded;
+}
+
namespace impl {
class RenderEngine;
}
@@ -67,7 +71,12 @@
HIGH = 3,
};
- static std::unique_ptr<impl::RenderEngine> create(const RenderEngineCreationArgs& args);
+ enum class RenderEngineType {
+ GLES = 1,
+ THREADED = 2,
+ };
+
+ static std::unique_ptr<RenderEngine> create(const RenderEngineCreationArgs& args);
virtual ~RenderEngine() = 0;
@@ -163,7 +172,7 @@
// now, this always returns NO_ERROR.
virtual status_t drawLayers(const DisplaySettings& display,
const std::vector<const LayerSettings*>& layers,
- ANativeWindowBuffer* buffer, const bool useFramebufferCache,
+ const sp<GraphicBuffer>& buffer, const bool useFramebufferCache,
base::unique_fd&& bufferFence, base::unique_fd* drawFence) = 0;
protected:
@@ -174,6 +183,7 @@
// live longer than RenderEngine.
virtual Framebuffer* getFramebufferForDrawing() = 0;
friend class BindNativeBufferAsFramebuffer;
+ friend class threaded::RenderEngineThreaded;
};
struct RenderEngineCreationArgs {
@@ -184,26 +194,25 @@
bool precacheToneMapperShaderOnly;
bool supportsBackgroundBlur;
RenderEngine::ContextPriority contextPriority;
+ RenderEngine::RenderEngineType renderEngineType;
struct Builder;
private:
// must be created by Builder via constructor with full argument list
- RenderEngineCreationArgs(
- int _pixelFormat,
- uint32_t _imageCacheSize,
- bool _useColorManagement,
- bool _enableProtectedContext,
- bool _precacheToneMapperShaderOnly,
- bool _supportsBackgroundBlur,
- RenderEngine::ContextPriority _contextPriority)
- : pixelFormat(_pixelFormat)
- , imageCacheSize(_imageCacheSize)
- , useColorManagement(_useColorManagement)
- , enableProtectedContext(_enableProtectedContext)
- , precacheToneMapperShaderOnly(_precacheToneMapperShaderOnly)
- , supportsBackgroundBlur(_supportsBackgroundBlur)
- , contextPriority(_contextPriority) {}
+ RenderEngineCreationArgs(int _pixelFormat, uint32_t _imageCacheSize, bool _useColorManagement,
+ bool _enableProtectedContext, bool _precacheToneMapperShaderOnly,
+ bool _supportsBackgroundBlur,
+ RenderEngine::ContextPriority _contextPriority,
+ RenderEngine::RenderEngineType _renderEngineType)
+ : pixelFormat(_pixelFormat),
+ imageCacheSize(_imageCacheSize),
+ useColorManagement(_useColorManagement),
+ enableProtectedContext(_enableProtectedContext),
+ precacheToneMapperShaderOnly(_precacheToneMapperShaderOnly),
+ supportsBackgroundBlur(_supportsBackgroundBlur),
+ contextPriority(_contextPriority),
+ renderEngineType(_renderEngineType) {}
RenderEngineCreationArgs() = delete;
};
@@ -238,10 +247,14 @@
this->contextPriority = contextPriority;
return *this;
}
+ Builder& setRenderEngineType(RenderEngine::RenderEngineType renderEngineType) {
+ this->renderEngineType = renderEngineType;
+ return *this;
+ }
RenderEngineCreationArgs build() const {
return RenderEngineCreationArgs(pixelFormat, imageCacheSize, useColorManagement,
enableProtectedContext, precacheToneMapperShaderOnly,
- supportsBackgroundBlur, contextPriority);
+ supportsBackgroundBlur, contextPriority, renderEngineType);
}
private:
@@ -253,6 +266,7 @@
bool precacheToneMapperShaderOnly = false;
bool supportsBackgroundBlur = false;
RenderEngine::ContextPriority contextPriority = RenderEngine::ContextPriority::MEDIUM;
+ RenderEngine::RenderEngineType renderEngineType = RenderEngine::RenderEngineType::GLES;
};
class BindNativeBufferAsFramebuffer {
diff --git a/libs/renderengine/include/renderengine/mock/RenderEngine.h b/libs/renderengine/include/renderengine/mock/RenderEngine.h
index df0f17a..d0343ba 100644
--- a/libs/renderengine/include/renderengine/mock/RenderEngine.h
+++ b/libs/renderengine/include/renderengine/mock/RenderEngine.h
@@ -59,7 +59,8 @@
MOCK_METHOD0(cleanupPostRender, bool());
MOCK_METHOD6(drawLayers,
status_t(const DisplaySettings&, const std::vector<const LayerSettings*>&,
- ANativeWindowBuffer*, const bool, base::unique_fd&&, base::unique_fd*));
+ const sp<GraphicBuffer>&, const bool, base::unique_fd&&,
+ base::unique_fd*));
};
} // namespace mock
diff --git a/libs/renderengine/tests/Android.bp b/libs/renderengine/tests/Android.bp
index e98babc..bcf389b 100644
--- a/libs/renderengine/tests/Android.bp
+++ b/libs/renderengine/tests/Android.bp
@@ -18,10 +18,12 @@
test_suites: ["device-tests"],
srcs: [
"RenderEngineTest.cpp",
+ "RenderEngineThreadedTest.cpp",
],
static_libs: [
"libgmock",
"librenderengine",
+ "librenderengine_mocks",
],
shared_libs: [
"libbase",
diff --git a/libs/renderengine/tests/RenderEngineTest.cpp b/libs/renderengine/tests/RenderEngineTest.cpp
index 16a8a0d..77b6c0f 100644
--- a/libs/renderengine/tests/RenderEngineTest.cpp
+++ b/libs/renderengine/tests/RenderEngineTest.cpp
@@ -22,12 +22,13 @@
#include <condition_variable>
#include <fstream>
-#include <gtest/gtest.h>
#include <cutils/properties.h>
+#include <gtest/gtest.h>
#include <renderengine/RenderEngine.h>
#include <sync/sync.h>
#include <ui/PixelFormat.h>
#include "../gl/GLESRenderEngine.h"
+#include "../threaded/RenderEngineThreaded.h"
constexpr int DEFAULT_DISPLAY_WIDTH = 128;
constexpr int DEFAULT_DISPLAY_HEIGHT = 256;
@@ -40,14 +41,15 @@
static void SetUpTestSuite() {
sRE = renderengine::gl::GLESRenderEngine::create(
renderengine::RenderEngineCreationArgs::Builder()
- .setPixelFormat(static_cast<int>(ui::PixelFormat::RGBA_8888))
- .setImageCacheSize(1)
- .setUseColorManagerment(false)
- .setEnableProtectedContext(false)
- .setPrecacheToneMapperShaderOnly(false)
- .setSupportsBackgroundBlur(true)
- .setContextPriority(renderengine::RenderEngine::ContextPriority::MEDIUM)
- .build());
+ .setPixelFormat(static_cast<int>(ui::PixelFormat::RGBA_8888))
+ .setImageCacheSize(1)
+ .setUseColorManagerment(false)
+ .setEnableProtectedContext(false)
+ .setPrecacheToneMapperShaderOnly(false)
+ .setSupportsBackgroundBlur(true)
+ .setContextPriority(renderengine::RenderEngine::ContextPriority::MEDIUM)
+ .setRenderEngineType(renderengine::RenderEngine::RenderEngineType::GLES)
+ .build());
}
static void TearDownTestSuite() {
@@ -252,8 +254,8 @@
std::vector<const renderengine::LayerSettings*> layers,
sp<GraphicBuffer> buffer) {
base::unique_fd fence;
- status_t status = sRE->drawLayers(settings, layers, buffer->getNativeBuffer(), true,
- base::unique_fd(), &fence);
+ status_t status =
+ sRE->drawLayers(settings, layers, buffer, true, base::unique_fd(), &fence);
sCurrentBuffer = buffer;
int fd = fence.release();
@@ -1004,8 +1006,7 @@
layer.alpha = 1.0;
layers.push_back(&layer);
- status_t status = sRE->drawLayers(settings, layers, mBuffer->getNativeBuffer(), true,
- base::unique_fd(), nullptr);
+ status_t status = sRE->drawLayers(settings, layers, mBuffer, true, base::unique_fd(), nullptr);
sCurrentBuffer = mBuffer;
ASSERT_EQ(NO_ERROR, status);
expectBufferColor(fullscreenRect(), 255, 0, 0, 255);
@@ -1023,8 +1024,7 @@
layer.alpha = 1.0;
layers.push_back(&layer);
- status_t status = sRE->drawLayers(settings, layers, mBuffer->getNativeBuffer(), false,
- base::unique_fd(), nullptr);
+ status_t status = sRE->drawLayers(settings, layers, mBuffer, false, base::unique_fd(), nullptr);
sCurrentBuffer = mBuffer;
ASSERT_EQ(NO_ERROR, status);
ASSERT_FALSE(sRE->isFramebufferImageCachedForTesting(mBuffer->getId()));
@@ -1414,11 +1414,9 @@
layers.push_back(&layer);
base::unique_fd fenceOne;
- sRE->drawLayers(settings, layers, mBuffer->getNativeBuffer(), true, base::unique_fd(),
- &fenceOne);
+ sRE->drawLayers(settings, layers, mBuffer, true, base::unique_fd(), &fenceOne);
base::unique_fd fenceTwo;
- sRE->drawLayers(settings, layers, mBuffer->getNativeBuffer(), true, std::move(fenceOne),
- &fenceTwo);
+ sRE->drawLayers(settings, layers, mBuffer, true, std::move(fenceOne), &fenceTwo);
const int fd = fenceTwo.get();
if (fd >= 0) {
diff --git a/libs/renderengine/tests/RenderEngineThreadedTest.cpp b/libs/renderengine/tests/RenderEngineThreadedTest.cpp
new file mode 100644
index 0000000..69a0e19
--- /dev/null
+++ b/libs/renderengine/tests/RenderEngineThreadedTest.cpp
@@ -0,0 +1,210 @@
+/*
+ * 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.
+ */
+
+#include <cutils/properties.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <renderengine/mock/RenderEngine.h>
+#include "../threaded/RenderEngineThreaded.h"
+
+namespace android {
+
+using testing::_;
+using testing::Eq;
+using testing::Mock;
+using testing::Return;
+
+struct RenderEngineThreadedTest : public ::testing::Test {
+ ~RenderEngineThreadedTest() {}
+
+ void SetUp() override {
+ mThreadedRE = renderengine::threaded::RenderEngineThreaded::create(
+ [this]() { return std::unique_ptr<renderengine::RenderEngine>(mRenderEngine); });
+ }
+
+ std::unique_ptr<renderengine::threaded::RenderEngineThreaded> mThreadedRE;
+ renderengine::mock::RenderEngine* mRenderEngine = new renderengine::mock::RenderEngine();
+};
+
+TEST_F(RenderEngineThreadedTest, dump) {
+ std::string testString = "XYZ";
+ EXPECT_CALL(*mRenderEngine, dump(_));
+ mThreadedRE->dump(testString);
+}
+
+TEST_F(RenderEngineThreadedTest, primeCache) {
+ EXPECT_CALL(*mRenderEngine, primeCache());
+ mThreadedRE->primeCache();
+}
+
+TEST_F(RenderEngineThreadedTest, genTextures) {
+ uint32_t texName;
+ EXPECT_CALL(*mRenderEngine, genTextures(1, &texName));
+ mThreadedRE->genTextures(1, &texName);
+}
+
+TEST_F(RenderEngineThreadedTest, deleteTextures) {
+ uint32_t texName;
+ EXPECT_CALL(*mRenderEngine, deleteTextures(1, &texName));
+ mThreadedRE->deleteTextures(1, &texName);
+}
+
+TEST_F(RenderEngineThreadedTest, bindExternalBuffer_nullptrBuffer) {
+ EXPECT_CALL(*mRenderEngine, bindExternalTextureBuffer(0, Eq(nullptr), Eq(nullptr)))
+ .WillOnce(Return(BAD_VALUE));
+ status_t result = mThreadedRE->bindExternalTextureBuffer(0, nullptr, nullptr);
+ ASSERT_EQ(BAD_VALUE, result);
+}
+
+TEST_F(RenderEngineThreadedTest, bindExternalBuffer_withBuffer) {
+ sp<GraphicBuffer> buf = new GraphicBuffer();
+ EXPECT_CALL(*mRenderEngine, bindExternalTextureBuffer(0, buf, Eq(nullptr)))
+ .WillOnce(Return(NO_ERROR));
+ status_t result = mThreadedRE->bindExternalTextureBuffer(0, buf, nullptr);
+ ASSERT_EQ(NO_ERROR, result);
+}
+
+TEST_F(RenderEngineThreadedTest, cacheExternalTextureBuffer_nullptr) {
+ EXPECT_CALL(*mRenderEngine, cacheExternalTextureBuffer(Eq(nullptr)));
+ mThreadedRE->cacheExternalTextureBuffer(nullptr);
+}
+
+TEST_F(RenderEngineThreadedTest, cacheExternalTextureBuffer_withBuffer) {
+ sp<GraphicBuffer> buf = new GraphicBuffer();
+ EXPECT_CALL(*mRenderEngine, cacheExternalTextureBuffer(buf));
+ mThreadedRE->cacheExternalTextureBuffer(buf);
+}
+
+TEST_F(RenderEngineThreadedTest, unbindExternalTextureBuffer) {
+ EXPECT_CALL(*mRenderEngine, unbindExternalTextureBuffer(0x0));
+ mThreadedRE->unbindExternalTextureBuffer(0x0);
+}
+
+TEST_F(RenderEngineThreadedTest, bindFrameBuffer_returnsBadValue) {
+ std::unique_ptr<renderengine::Framebuffer> framebuffer;
+ EXPECT_CALL(*mRenderEngine, bindFrameBuffer(framebuffer.get())).WillOnce(Return(BAD_VALUE));
+ status_t result = mThreadedRE->bindFrameBuffer(framebuffer.get());
+ ASSERT_EQ(BAD_VALUE, result);
+}
+
+TEST_F(RenderEngineThreadedTest, bindFrameBuffer_returnsNoError) {
+ std::unique_ptr<renderengine::Framebuffer> framebuffer;
+ EXPECT_CALL(*mRenderEngine, bindFrameBuffer(framebuffer.get())).WillOnce(Return(NO_ERROR));
+ status_t result = mThreadedRE->bindFrameBuffer(framebuffer.get());
+ ASSERT_EQ(NO_ERROR, result);
+}
+
+TEST_F(RenderEngineThreadedTest, unbindFrameBuffer) {
+ std::unique_ptr<renderengine::Framebuffer> framebuffer;
+ EXPECT_CALL(*mRenderEngine, unbindFrameBuffer(framebuffer.get()));
+ mThreadedRE->unbindFrameBuffer(framebuffer.get());
+}
+
+TEST_F(RenderEngineThreadedTest, getMaxTextureSize_returns20) {
+ size_t size = 20;
+ EXPECT_CALL(*mRenderEngine, getMaxTextureSize()).WillOnce(Return(size));
+ size_t result = mThreadedRE->getMaxTextureSize();
+ ASSERT_EQ(size, result);
+}
+
+TEST_F(RenderEngineThreadedTest, getMaxTextureSize_returns0) {
+ size_t size = 0;
+ EXPECT_CALL(*mRenderEngine, getMaxTextureSize()).WillOnce(Return(size));
+ size_t result = mThreadedRE->getMaxTextureSize();
+ ASSERT_EQ(size, result);
+}
+
+TEST_F(RenderEngineThreadedTest, getMaxViewportDims_returns20) {
+ size_t dims = 20;
+ EXPECT_CALL(*mRenderEngine, getMaxViewportDims()).WillOnce(Return(dims));
+ size_t result = mThreadedRE->getMaxViewportDims();
+ ASSERT_EQ(dims, result);
+}
+
+TEST_F(RenderEngineThreadedTest, getMaxViewportDims_returns0) {
+ size_t dims = 0;
+ EXPECT_CALL(*mRenderEngine, getMaxViewportDims()).WillOnce(Return(dims));
+ size_t result = mThreadedRE->getMaxViewportDims();
+ ASSERT_EQ(dims, result);
+}
+
+TEST_F(RenderEngineThreadedTest, isProtected_returnsFalse) {
+ EXPECT_CALL(*mRenderEngine, isProtected()).WillOnce(Return(false));
+ status_t result = mThreadedRE->isProtected();
+ ASSERT_EQ(false, result);
+}
+
+TEST_F(RenderEngineThreadedTest, isProtected_returnsTrue) {
+ EXPECT_CALL(*mRenderEngine, isProtected()).WillOnce(Return(true));
+ size_t result = mThreadedRE->isProtected();
+ ASSERT_EQ(true, result);
+}
+
+TEST_F(RenderEngineThreadedTest, supportsProtectedContent_returnsFalse) {
+ EXPECT_CALL(*mRenderEngine, supportsProtectedContent()).WillOnce(Return(false));
+ status_t result = mThreadedRE->supportsProtectedContent();
+ ASSERT_EQ(false, result);
+}
+
+TEST_F(RenderEngineThreadedTest, supportsProtectedContent_returnsTrue) {
+ EXPECT_CALL(*mRenderEngine, supportsProtectedContent()).WillOnce(Return(true));
+ status_t result = mThreadedRE->supportsProtectedContent();
+ ASSERT_EQ(true, result);
+}
+
+TEST_F(RenderEngineThreadedTest, useProtectedContext_returnsFalse) {
+ EXPECT_CALL(*mRenderEngine, useProtectedContext(false)).WillOnce(Return(false));
+ status_t result = mThreadedRE->useProtectedContext(false);
+ ASSERT_EQ(false, result);
+}
+
+TEST_F(RenderEngineThreadedTest, useProtectedContext_returnsTrue) {
+ EXPECT_CALL(*mRenderEngine, useProtectedContext(false)).WillOnce(Return(true));
+ status_t result = mThreadedRE->useProtectedContext(false);
+ ASSERT_EQ(true, result);
+}
+
+TEST_F(RenderEngineThreadedTest, cleanupPostRender_returnsFalse) {
+ EXPECT_CALL(*mRenderEngine, cleanupPostRender()).WillOnce(Return(false));
+ status_t result = mThreadedRE->cleanupPostRender();
+ ASSERT_EQ(false, result);
+}
+
+TEST_F(RenderEngineThreadedTest, cleanupPostRender_returnsTrue) {
+ EXPECT_CALL(*mRenderEngine, cleanupPostRender()).WillOnce(Return(true));
+ status_t result = mThreadedRE->cleanupPostRender();
+ ASSERT_EQ(true, result);
+}
+
+TEST_F(RenderEngineThreadedTest, drawLayers) {
+ renderengine::DisplaySettings settings;
+ std::vector<const renderengine::LayerSettings*> layers;
+ sp<GraphicBuffer> buffer = new GraphicBuffer();
+ base::unique_fd bufferFence;
+ base::unique_fd drawFence;
+
+ EXPECT_CALL(*mRenderEngine, drawLayers)
+ .WillOnce([](const renderengine::DisplaySettings&,
+ const std::vector<const renderengine::LayerSettings*>&,
+ const sp<GraphicBuffer>&, const bool, base::unique_fd&&,
+ base::unique_fd*) -> status_t { return NO_ERROR; });
+
+ status_t result = mThreadedRE->drawLayers(settings, layers, buffer, false,
+ std::move(bufferFence), &drawFence);
+ ASSERT_EQ(NO_ERROR, result);
+}
+
+} // namespace android
diff --git a/libs/renderengine/threaded/RenderEngineThreaded.cpp b/libs/renderengine/threaded/RenderEngineThreaded.cpp
new file mode 100644
index 0000000..ad61718
--- /dev/null
+++ b/libs/renderengine/threaded/RenderEngineThreaded.cpp
@@ -0,0 +1,403 @@
+/*
+ * 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.
+ */
+
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
+#include "RenderEngineThreaded.h"
+
+#include <sched.h>
+#include <chrono>
+#include <future>
+
+#include <android-base/stringprintf.h>
+#include <private/gui/SyncFeatures.h>
+#include <utils/Trace.h>
+
+#include "gl/GLESRenderEngine.h"
+
+using namespace std::chrono_literals;
+
+namespace android {
+namespace renderengine {
+namespace threaded {
+
+std::unique_ptr<RenderEngineThreaded> RenderEngineThreaded::create(CreateInstanceFactory factory) {
+ return std::make_unique<RenderEngineThreaded>(std::move(factory));
+}
+
+RenderEngineThreaded::RenderEngineThreaded(CreateInstanceFactory factory) {
+ ATRACE_CALL();
+
+ std::lock_guard lockThread(mThreadMutex);
+ mThread = std::thread(&RenderEngineThreaded::threadMain, this, factory);
+}
+
+RenderEngineThreaded::~RenderEngineThreaded() {
+ {
+ std::lock_guard lock(mThreadMutex);
+ mRunning = false;
+ mCondition.notify_one();
+ }
+
+ if (mThread.joinable()) {
+ mThread.join();
+ }
+}
+
+// NO_THREAD_SAFETY_ANALYSIS is because std::unique_lock presently lacks thread safety annotations.
+void RenderEngineThreaded::threadMain(CreateInstanceFactory factory) NO_THREAD_SAFETY_ANALYSIS {
+ ATRACE_CALL();
+
+ struct sched_param param = {0};
+ param.sched_priority = 2;
+ if (sched_setscheduler(0, SCHED_FIFO, ¶m) != 0) {
+ ALOGE("Couldn't set SCHED_FIFO");
+ }
+
+ mRenderEngine = factory();
+
+ std::unique_lock<std::mutex> lock(mThreadMutex);
+ pthread_setname_np(pthread_self(), mThreadName);
+
+ while (mRunning) {
+ if (!mFunctionCalls.empty()) {
+ auto task = mFunctionCalls.front();
+ mFunctionCalls.pop();
+ task(*mRenderEngine);
+ }
+ mCondition.wait(lock, [this]() REQUIRES(mThreadMutex) {
+ return !mRunning || !mFunctionCalls.empty();
+ });
+ }
+}
+
+void RenderEngineThreaded::primeCache() const {
+ std::promise<void> resultPromise;
+ std::future<void> resultFuture = resultPromise.get_future();
+ {
+ std::lock_guard lock(mThreadMutex);
+ mFunctionCalls.push([&resultPromise](renderengine::RenderEngine& instance) {
+ ATRACE_NAME("REThreaded::primeCache");
+ instance.primeCache();
+ resultPromise.set_value();
+ });
+ }
+ mCondition.notify_one();
+ resultFuture.wait();
+}
+
+void RenderEngineThreaded::dump(std::string& result) {
+ std::promise<std::string> resultPromise;
+ std::future<std::string> resultFuture = resultPromise.get_future();
+ {
+ std::lock_guard lock(mThreadMutex);
+ mFunctionCalls.push([&resultPromise, &result](renderengine::RenderEngine& instance) {
+ ATRACE_NAME("REThreaded::dump");
+ std::string localResult = result;
+ instance.dump(localResult);
+ resultPromise.set_value(std::move(localResult));
+ });
+ }
+ mCondition.notify_one();
+ // Note: This is an rvalue.
+ result.assign(resultFuture.get());
+}
+
+bool RenderEngineThreaded::useNativeFenceSync() const {
+ std::promise<bool> resultPromise;
+ std::future<bool> resultFuture = resultPromise.get_future();
+ {
+ std::lock_guard lock(mThreadMutex);
+ mFunctionCalls.push([&resultPromise](renderengine::RenderEngine& /*instance*/) {
+ ATRACE_NAME("REThreaded::useNativeFenceSync");
+ bool returnValue = SyncFeatures::getInstance().useNativeFenceSync();
+ resultPromise.set_value(returnValue);
+ });
+ }
+ mCondition.notify_one();
+ return resultFuture.get();
+}
+
+bool RenderEngineThreaded::useWaitSync() const {
+ std::promise<bool> resultPromise;
+ std::future<bool> resultFuture = resultPromise.get_future();
+ {
+ std::lock_guard lock(mThreadMutex);
+ mFunctionCalls.push([&resultPromise](renderengine::RenderEngine& /*instance*/) {
+ ATRACE_NAME("REThreaded::useWaitSync");
+ bool returnValue = SyncFeatures::getInstance().useWaitSync();
+ resultPromise.set_value(returnValue);
+ });
+ }
+ mCondition.notify_one();
+ return resultFuture.get();
+}
+
+void RenderEngineThreaded::genTextures(size_t count, uint32_t* names) {
+ std::promise<void> resultPromise;
+ std::future<void> resultFuture = resultPromise.get_future();
+ {
+ std::lock_guard lock(mThreadMutex);
+ mFunctionCalls.push([&resultPromise, count, names](renderengine::RenderEngine& instance) {
+ ATRACE_NAME("REThreaded::genTextures");
+ instance.genTextures(count, names);
+ resultPromise.set_value();
+ });
+ }
+ mCondition.notify_one();
+ resultFuture.wait();
+}
+
+void RenderEngineThreaded::deleteTextures(size_t count, uint32_t const* names) {
+ std::promise<void> resultPromise;
+ std::future<void> resultFuture = resultPromise.get_future();
+ {
+ std::lock_guard lock(mThreadMutex);
+ mFunctionCalls.push([&resultPromise, count, &names](renderengine::RenderEngine& instance) {
+ ATRACE_NAME("REThreaded::deleteTextures");
+ instance.deleteTextures(count, names);
+ resultPromise.set_value();
+ });
+ }
+ mCondition.notify_one();
+ resultFuture.wait();
+}
+
+void RenderEngineThreaded::bindExternalTextureImage(uint32_t texName, const Image& image) {
+ std::promise<void> resultPromise;
+ std::future<void> resultFuture = resultPromise.get_future();
+ {
+ std::lock_guard lock(mThreadMutex);
+ mFunctionCalls.push(
+ [&resultPromise, texName, &image](renderengine::RenderEngine& instance) {
+ ATRACE_NAME("REThreaded::bindExternalTextureImage");
+ instance.bindExternalTextureImage(texName, image);
+ resultPromise.set_value();
+ });
+ }
+ mCondition.notify_one();
+ resultFuture.wait();
+}
+
+status_t RenderEngineThreaded::bindExternalTextureBuffer(uint32_t texName,
+ const sp<GraphicBuffer>& buffer,
+ const sp<Fence>& fence) {
+ std::promise<status_t> resultPromise;
+ std::future<status_t> resultFuture = resultPromise.get_future();
+ {
+ std::lock_guard lock(mThreadMutex);
+ mFunctionCalls.push(
+ [&resultPromise, texName, &buffer, &fence](renderengine::RenderEngine& instance) {
+ ATRACE_NAME("REThreaded::bindExternalTextureBuffer");
+ status_t status = instance.bindExternalTextureBuffer(texName, buffer, fence);
+ resultPromise.set_value(status);
+ });
+ }
+ mCondition.notify_one();
+ return resultFuture.get();
+}
+
+void RenderEngineThreaded::cacheExternalTextureBuffer(const sp<GraphicBuffer>& buffer) {
+ std::promise<void> resultPromise;
+ std::future<void> resultFuture = resultPromise.get_future();
+ {
+ std::lock_guard lock(mThreadMutex);
+ mFunctionCalls.push([&resultPromise, &buffer](renderengine::RenderEngine& instance) {
+ ATRACE_NAME("REThreaded::cacheExternalTextureBuffer");
+ instance.cacheExternalTextureBuffer(buffer);
+ resultPromise.set_value();
+ });
+ }
+ mCondition.notify_one();
+ resultFuture.wait();
+}
+
+void RenderEngineThreaded::unbindExternalTextureBuffer(uint64_t bufferId) {
+ std::promise<void> resultPromise;
+ std::future<void> resultFuture = resultPromise.get_future();
+ {
+ std::lock_guard lock(mThreadMutex);
+ mFunctionCalls.push([&resultPromise, &bufferId](renderengine::RenderEngine& instance) {
+ ATRACE_NAME("REThreaded::unbindExternalTextureBuffer");
+ instance.unbindExternalTextureBuffer(bufferId);
+ resultPromise.set_value();
+ });
+ }
+ mCondition.notify_one();
+ resultFuture.wait();
+}
+
+status_t RenderEngineThreaded::bindFrameBuffer(Framebuffer* framebuffer) {
+ std::promise<status_t> resultPromise;
+ std::future<status_t> resultFuture = resultPromise.get_future();
+ {
+ std::lock_guard lock(mThreadMutex);
+ mFunctionCalls.push([&resultPromise, &framebuffer](renderengine::RenderEngine& instance) {
+ ATRACE_NAME("REThreaded::bindFrameBuffer");
+ status_t status = instance.bindFrameBuffer(framebuffer);
+ resultPromise.set_value(status);
+ });
+ }
+ mCondition.notify_one();
+ return resultFuture.get();
+}
+
+void RenderEngineThreaded::unbindFrameBuffer(Framebuffer* framebuffer) {
+ std::promise<void> resultPromise;
+ std::future<void> resultFuture = resultPromise.get_future();
+ {
+ std::lock_guard lock(mThreadMutex);
+ mFunctionCalls.push([&resultPromise, &framebuffer](renderengine::RenderEngine& instance) {
+ ATRACE_NAME("REThreaded::unbindFrameBuffer");
+ instance.unbindFrameBuffer(framebuffer);
+ resultPromise.set_value();
+ });
+ }
+ mCondition.notify_one();
+ resultFuture.wait();
+}
+
+size_t RenderEngineThreaded::getMaxTextureSize() const {
+ std::promise<size_t> resultPromise;
+ std::future<size_t> resultFuture = resultPromise.get_future();
+ {
+ std::lock_guard lock(mThreadMutex);
+ mFunctionCalls.push([&resultPromise](renderengine::RenderEngine& instance) {
+ ATRACE_NAME("REThreaded::getMaxTextureSize");
+ size_t size = instance.getMaxTextureSize();
+ resultPromise.set_value(size);
+ });
+ }
+ mCondition.notify_one();
+ return resultFuture.get();
+}
+
+size_t RenderEngineThreaded::getMaxViewportDims() const {
+ std::promise<size_t> resultPromise;
+ std::future<size_t> resultFuture = resultPromise.get_future();
+ {
+ std::lock_guard lock(mThreadMutex);
+ mFunctionCalls.push([&resultPromise](renderengine::RenderEngine& instance) {
+ ATRACE_NAME("REThreaded::getMaxViewportDims");
+ size_t size = instance.getMaxViewportDims();
+ resultPromise.set_value(size);
+ });
+ }
+ mCondition.notify_one();
+ return resultFuture.get();
+}
+
+bool RenderEngineThreaded::isProtected() const {
+ std::promise<bool> resultPromise;
+ std::future<bool> resultFuture = resultPromise.get_future();
+ {
+ std::lock_guard lock(mThreadMutex);
+ mFunctionCalls.push([&resultPromise](renderengine::RenderEngine& instance) {
+ ATRACE_NAME("REThreaded::isProtected");
+ bool returnValue = instance.isProtected();
+ resultPromise.set_value(returnValue);
+ });
+ }
+ mCondition.notify_one();
+ return resultFuture.get();
+}
+
+bool RenderEngineThreaded::supportsProtectedContent() const {
+ std::promise<bool> resultPromise;
+ std::future<bool> resultFuture = resultPromise.get_future();
+ {
+ std::lock_guard lock(mThreadMutex);
+ mFunctionCalls.push([&resultPromise](renderengine::RenderEngine& instance) {
+ ATRACE_NAME("REThreaded::supportsProtectedContent");
+ bool returnValue = instance.supportsProtectedContent();
+ resultPromise.set_value(returnValue);
+ });
+ }
+ mCondition.notify_one();
+ return resultFuture.get();
+}
+
+bool RenderEngineThreaded::useProtectedContext(bool useProtectedContext) {
+ std::promise<bool> resultPromise;
+ std::future<bool> resultFuture = resultPromise.get_future();
+ {
+ std::lock_guard lock(mThreadMutex);
+ mFunctionCalls.push(
+ [&resultPromise, useProtectedContext](renderengine::RenderEngine& instance) {
+ ATRACE_NAME("REThreaded::useProtectedContext");
+ bool returnValue = instance.useProtectedContext(useProtectedContext);
+ resultPromise.set_value(returnValue);
+ });
+ }
+ mCondition.notify_one();
+ return resultFuture.get();
+}
+
+Framebuffer* RenderEngineThreaded::getFramebufferForDrawing() {
+ std::promise<Framebuffer*> resultPromise;
+ std::future<Framebuffer*> resultFuture = resultPromise.get_future();
+ {
+ std::lock_guard lock(mThreadMutex);
+ mFunctionCalls.push([&resultPromise](renderengine::RenderEngine& instance) {
+ ATRACE_NAME("REThreaded::getFramebufferForDrawing");
+ Framebuffer* framebuffer = instance.getFramebufferForDrawing();
+ resultPromise.set_value(framebuffer);
+ });
+ }
+ mCondition.notify_one();
+ return resultFuture.get();
+}
+
+bool RenderEngineThreaded::cleanupPostRender() {
+ std::promise<bool> resultPromise;
+ std::future<bool> resultFuture = resultPromise.get_future();
+ {
+ std::lock_guard lock(mThreadMutex);
+ mFunctionCalls.push([&resultPromise](renderengine::RenderEngine& instance) {
+ ATRACE_NAME("REThreaded::cleanupPostRender");
+ bool returnValue = instance.cleanupPostRender();
+ resultPromise.set_value(returnValue);
+ });
+ }
+ mCondition.notify_one();
+ return resultFuture.get();
+}
+
+status_t RenderEngineThreaded::drawLayers(const DisplaySettings& display,
+ const std::vector<const LayerSettings*>& layers,
+ const sp<GraphicBuffer>& buffer,
+ const bool useFramebufferCache,
+ base::unique_fd&& bufferFence,
+ base::unique_fd* drawFence) {
+ std::promise<status_t> resultPromise;
+ std::future<status_t> resultFuture = resultPromise.get_future();
+ {
+ std::lock_guard lock(mThreadMutex);
+ mFunctionCalls.push([&resultPromise, &display, &layers, &buffer, useFramebufferCache,
+ &bufferFence, &drawFence](renderengine::RenderEngine& instance) {
+ ATRACE_NAME("REThreaded::drawLayers");
+ status_t status = instance.drawLayers(display, layers, buffer, useFramebufferCache,
+ std::move(bufferFence), drawFence);
+ resultPromise.set_value(status);
+ });
+ }
+ mCondition.notify_one();
+ return resultFuture.get();
+}
+
+} // namespace threaded
+} // namespace renderengine
+} // namespace android
\ No newline at end of file
diff --git a/libs/renderengine/threaded/RenderEngineThreaded.h b/libs/renderengine/threaded/RenderEngineThreaded.h
new file mode 100644
index 0000000..ec18e1f
--- /dev/null
+++ b/libs/renderengine/threaded/RenderEngineThreaded.h
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android-base/thread_annotations.h>
+#include <condition_variable>
+#include <mutex>
+#include <queue>
+#include <thread>
+
+#include "renderengine/RenderEngine.h"
+
+namespace android {
+namespace renderengine {
+namespace threaded {
+
+using CreateInstanceFactory = std::function<std::unique_ptr<renderengine::RenderEngine>()>;
+
+/**
+ * This class extends a basic RenderEngine class. It contains a thread. Each time a function of
+ * this class is called, we create a lambda function that is put on a queue. The main thread then
+ * executes the functions in order.
+ */
+class RenderEngineThreaded : public RenderEngine {
+public:
+ static std::unique_ptr<RenderEngineThreaded> create(CreateInstanceFactory factory);
+
+ RenderEngineThreaded(CreateInstanceFactory factory);
+ ~RenderEngineThreaded() override;
+ void primeCache() const override;
+
+ void dump(std::string& result) override;
+
+ bool useNativeFenceSync() const override;
+ bool useWaitSync() const override;
+ void genTextures(size_t count, uint32_t* names) override;
+ void deleteTextures(size_t count, uint32_t const* names) override;
+ void bindExternalTextureImage(uint32_t texName, const Image& image) override;
+ status_t bindExternalTextureBuffer(uint32_t texName, const sp<GraphicBuffer>& buffer,
+ const sp<Fence>& fence) override;
+ void cacheExternalTextureBuffer(const sp<GraphicBuffer>& buffer) override;
+ void unbindExternalTextureBuffer(uint64_t bufferId) override;
+ status_t bindFrameBuffer(Framebuffer* framebuffer) override;
+ void unbindFrameBuffer(Framebuffer* framebuffer) override;
+ size_t getMaxTextureSize() const override;
+ size_t getMaxViewportDims() const override;
+
+ bool isProtected() const override;
+ bool supportsProtectedContent() const override;
+ bool useProtectedContext(bool useProtectedContext) override;
+ bool cleanupPostRender() override;
+
+ status_t drawLayers(const DisplaySettings& display,
+ const std::vector<const LayerSettings*>& layers,
+ const sp<GraphicBuffer>& buffer, const bool useFramebufferCache,
+ base::unique_fd&& bufferFence, base::unique_fd* drawFence) override;
+
+protected:
+ Framebuffer* getFramebufferForDrawing() override;
+
+private:
+ void threadMain(CreateInstanceFactory factory);
+
+ /* ------------------------------------------------------------------------
+ * Threading
+ */
+ const char* const mThreadName = "RenderEngineThread";
+ // Protects the creation and destruction of mThread.
+ mutable std::mutex mThreadMutex;
+ std::thread mThread GUARDED_BY(mThreadMutex);
+ bool mRunning GUARDED_BY(mThreadMutex) = true;
+ mutable std::queue<std::function<void(renderengine::RenderEngine& instance)>> mFunctionCalls
+ GUARDED_BY(mThreadMutex);
+ mutable std::condition_variable mCondition;
+
+ /* ------------------------------------------------------------------------
+ * Render Engine
+ */
+ std::unique_ptr<renderengine::RenderEngine> mRenderEngine;
+};
+} // namespace threaded
+} // namespace renderengine
+} // namespace android
\ No newline at end of file
diff --git a/libs/sensor/ISensorServer.cpp b/libs/sensor/ISensorServer.cpp
index 8ed09f8..a6b0aaf 100644
--- a/libs/sensor/ISensorServer.cpp
+++ b/libs/sensor/ISensorServer.cpp
@@ -216,14 +216,25 @@
int32_t type;
Vector<float> floats;
Vector<int32_t> ints;
+ uint32_t count;
handle = data.readInt32();
type = data.readInt32();
- floats.resize(data.readUint32());
+
+ count = data.readUint32();
+ if (count > (data.dataAvail() / sizeof(float))) {
+ return BAD_VALUE;
+ }
+ floats.resize(count);
for (auto &i : floats) {
i = data.readFloat();
}
- ints.resize(data.readUint32());
+
+ count = data.readUint32();
+ if (count > (data.dataAvail() / sizeof(int32_t))) {
+ return BAD_VALUE;
+ }
+ ints.resize(count);
for (auto &i : ints) {
i = data.readInt32();
}
diff --git a/libs/ui/Android.bp b/libs/ui/Android.bp
index 1ee8c71..f3edd3c 100644
--- a/libs/ui/Android.bp
+++ b/libs/ui/Android.bp
@@ -12,6 +12,66 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+cc_defaults {
+ name: "libui-defaults",
+ clang: true,
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
+ cppflags: [
+ "-Wextra",
+ ],
+
+ sanitize: {
+ integer_overflow: true,
+ misc_undefined: ["bounds"],
+ },
+
+}
+
+cc_library_static {
+ name: "libui-types",
+ vendor_available: true,
+ host_supported: true,
+ target: {
+ windows: {
+ enabled: true,
+ }
+ },
+
+ defaults: [
+ "libui-defaults",
+ ],
+
+ apex_available: [
+ "//apex_available:anyapex",
+ "//apex_available:platform",
+ ],
+ min_sdk_version: "apex_inherit",
+
+ shared_libs: [
+ "libutils",
+ ],
+
+ static_libs: [
+ "libmath",
+ ],
+
+ srcs: [
+ "ColorSpace.cpp",
+ ],
+
+ export_include_dirs: [
+ "include_types",
+ ],
+
+ export_static_lib_headers: [
+ "libmath",
+ ],
+
+}
+
cc_library_shared {
name: "libui",
vendor_available: true,
@@ -35,8 +95,9 @@
},
srcs: [
- "ColorSpace.cpp",
"DebugUtils.cpp",
+ "DeviceProductInfo.cpp",
+ "DisplayInfo.cpp",
"Fence.cpp",
"FenceTime.cpp",
"FrameStats.cpp",
@@ -65,8 +126,11 @@
"include_private",
],
- // Uncomment the following line to enable VALIDATE_REGIONS traces
- //defaults: ["libui-validate-regions-defaults"],
+ defaults: [
+ "libui-defaults",
+ // Uncomment the following line to enable VALIDATE_REGIONS traces
+ //defaults: ["libui-validate-regions-defaults"],
+ ],
shared_libs: [
"android.hardware.graphics.allocator@2.0",
@@ -100,6 +164,10 @@
"libmath",
],
+ whole_static_libs: [
+ "libui-types",
+ ],
+
// bufferhub is not used when building libgui for vendors
target: {
vendor: {
diff --git a/libs/ui/DeviceProductInfo.cpp b/libs/ui/DeviceProductInfo.cpp
new file mode 100644
index 0000000..4d6ce43
--- /dev/null
+++ b/libs/ui/DeviceProductInfo.cpp
@@ -0,0 +1,87 @@
+/*
+ * 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.
+ */
+
+#include <ui/DeviceProductInfo.h>
+
+#include <android-base/stringprintf.h>
+#include <ui/FlattenableHelpers.h>
+#include <utils/Log.h>
+
+#define RETURN_IF_ERROR(op) \
+ if (const status_t status = (op); status != OK) return status;
+
+namespace android {
+
+using base::StringAppendF;
+
+size_t DeviceProductInfo::getFlattenedSize() const {
+ return FlattenableHelpers::getFlattenedSize(name) +
+ FlattenableHelpers::getFlattenedSize(manufacturerPnpId) +
+ FlattenableHelpers::getFlattenedSize(productId) +
+ FlattenableHelpers::getFlattenedSize(manufactureOrModelDate) +
+ FlattenableHelpers::getFlattenedSize(relativeAddress);
+}
+
+status_t DeviceProductInfo::flatten(void* buffer, size_t size) const {
+ if (size < getFlattenedSize()) {
+ return NO_MEMORY;
+ }
+ RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, name));
+ RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, manufacturerPnpId));
+ RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, productId));
+ RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, manufactureOrModelDate));
+ RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, relativeAddress));
+ return OK;
+}
+
+status_t DeviceProductInfo::unflatten(void const* buffer, size_t size) {
+ RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &name));
+ RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &manufacturerPnpId));
+ RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &productId));
+ RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &manufactureOrModelDate));
+ RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &relativeAddress));
+ return OK;
+}
+
+void DeviceProductInfo::dump(std::string& result) const {
+ StringAppendF(&result, "{name=%s, ", name.c_str());
+ StringAppendF(&result, "manufacturerPnpId=%s, ", manufacturerPnpId.data());
+ StringAppendF(&result, "productId=%s, ", productId.c_str());
+
+ if (const auto* model = std::get_if<ModelYear>(&manufactureOrModelDate)) {
+ StringAppendF(&result, "modelYear=%u, ", model->year);
+ } else if (const auto* manufactureWeekAndYear =
+ std::get_if<ManufactureWeekAndYear>(&manufactureOrModelDate)) {
+ StringAppendF(&result, "manufactureWeek=%u, ", manufactureWeekAndYear->week);
+ StringAppendF(&result, "manufactureYear=%d, ", manufactureWeekAndYear->year);
+ } else if (const auto* manufactureYear =
+ std::get_if<ManufactureYear>(&manufactureOrModelDate)) {
+ StringAppendF(&result, "manufactureYear=%d, ", manufactureYear->year);
+ } else {
+ ALOGE("Unknown alternative for variant DeviceProductInfo::ManufactureOrModelDate");
+ }
+
+ result.append("relativeAddress=[");
+ for (size_t i = 0; i < relativeAddress.size(); i++) {
+ if (i != 0) {
+ result.append(", ");
+ }
+ StringAppendF(&result, "%u", relativeAddress[i]);
+ }
+ result.append("]}");
+}
+
+} // namespace android
diff --git a/libs/ui/DisplayInfo.cpp b/libs/ui/DisplayInfo.cpp
new file mode 100644
index 0000000..73a78af
--- /dev/null
+++ b/libs/ui/DisplayInfo.cpp
@@ -0,0 +1,54 @@
+/*
+ * 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.
+ */
+
+#include <ui/DisplayInfo.h>
+
+#include <cstdint>
+
+#include <ui/FlattenableHelpers.h>
+
+#define RETURN_IF_ERROR(op) \
+ if (const status_t status = (op); status != OK) return status;
+
+namespace android {
+
+size_t DisplayInfo::getFlattenedSize() const {
+ return FlattenableHelpers::getFlattenedSize(connectionType) +
+ FlattenableHelpers::getFlattenedSize(density) +
+ FlattenableHelpers::getFlattenedSize(secure) +
+ FlattenableHelpers::getFlattenedSize(deviceProductInfo);
+}
+
+status_t DisplayInfo::flatten(void* buffer, size_t size) const {
+ if (size < getFlattenedSize()) {
+ return NO_MEMORY;
+ }
+ RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, connectionType));
+ RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, density));
+ RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, secure));
+ RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, deviceProductInfo));
+ return OK;
+}
+
+status_t DisplayInfo::unflatten(void const* buffer, size_t size) {
+ RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &connectionType));
+ RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &density));
+ RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &secure));
+ RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &deviceProductInfo));
+ return OK;
+}
+
+} // namespace android
diff --git a/libs/ui/include/ui/DeviceProductInfo.h b/libs/ui/include/ui/DeviceProductInfo.h
index af00342..807a5d9 100644
--- a/libs/ui/include/ui/DeviceProductInfo.h
+++ b/libs/ui/include/ui/DeviceProductInfo.h
@@ -19,7 +19,12 @@
#include <array>
#include <cstdint>
#include <optional>
+#include <string>
+#include <type_traits>
#include <variant>
+#include <vector>
+
+#include <utils/Flattenable.h>
namespace android {
@@ -29,13 +34,7 @@
// Product-specific information about the display or the directly connected device on the
// display chain. For example, if the display is transitively connected, this field may contain
// product information about the intermediate device.
-struct DeviceProductInfo {
- static constexpr size_t TEXT_BUFFER_SIZE = 20;
- static constexpr size_t RELATIVE_ADDRESS_SIZE = 4;
-
- using RelativeAddress = std::array<uint8_t, RELATIVE_ADDRESS_SIZE>;
- static constexpr RelativeAddress NO_RELATIVE_ADDRESS = {0xff, 0xff, 0xff, 0xff};
-
+struct DeviceProductInfo : LightFlattenable<DeviceProductInfo> {
struct ModelYear {
uint32_t year;
};
@@ -48,21 +47,29 @@
};
// Display name.
- std::array<char, TEXT_BUFFER_SIZE> name;
+ std::string name;
// Manufacturer Plug and Play ID.
PnpId manufacturerPnpId;
// Manufacturer product ID.
- std::array<char, TEXT_BUFFER_SIZE> productId;
+ std::string productId;
using ManufactureOrModelDate = std::variant<ModelYear, ManufactureYear, ManufactureWeekAndYear>;
+ static_assert(std::is_trivially_copyable_v<ManufactureOrModelDate>);
ManufactureOrModelDate manufactureOrModelDate;
- // Relative address in the display network. Unavailable address is indicated
- // by all elements equal to 255.
+ // Relative address in the display network. Empty vector indicates that the
+ // address is unavailable.
// For example, for HDMI connected device this will be the physical address.
- RelativeAddress relativeAddress;
+ std::vector<uint8_t> relativeAddress;
+
+ bool isFixedSize() const { return false; }
+ size_t getFlattenedSize() const;
+ status_t flatten(void* buffer, size_t size) const;
+ status_t unflatten(void const* buffer, size_t size);
+
+ void dump(std::string& result) const;
};
} // namespace android
diff --git a/libs/ui/include/ui/DisplayInfo.h b/libs/ui/include/ui/DisplayInfo.h
index 897060c..03e0a38 100644
--- a/libs/ui/include/ui/DisplayInfo.h
+++ b/libs/ui/include/ui/DisplayInfo.h
@@ -20,19 +20,23 @@
#include <type_traits>
#include <ui/DeviceProductInfo.h>
+#include <utils/Flattenable.h>
namespace android {
enum class DisplayConnectionType { Internal, External };
// Immutable information about physical display.
-struct DisplayInfo {
+struct DisplayInfo : LightFlattenable<DisplayInfo> {
DisplayConnectionType connectionType = DisplayConnectionType::Internal;
float density = 0.f;
bool secure = false;
std::optional<DeviceProductInfo> deviceProductInfo;
-};
-static_assert(std::is_trivially_copyable_v<DisplayInfo>);
+ bool isFixedSize() const { return false; }
+ size_t getFlattenedSize() const;
+ status_t flatten(void* buffer, size_t size) const;
+ status_t unflatten(void const* buffer, size_t size);
+};
} // namespace android
diff --git a/libs/ui/include_private/ui/FlattenableHelpers.h b/libs/ui/include_private/ui/FlattenableHelpers.h
new file mode 100644
index 0000000..8e316d8
--- /dev/null
+++ b/libs/ui/include_private/ui/FlattenableHelpers.h
@@ -0,0 +1,160 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <numeric>
+#include <optional>
+#include <type_traits>
+#include <vector>
+
+#include <utils/Flattenable.h>
+
+#define RETURN_IF_ERROR(op) \
+ if (const status_t status = (op); status != OK) return status;
+
+namespace android {
+
+struct FlattenableHelpers {
+ // Helpers for reading and writing POD structures
+ template <class T, typename = std::enable_if_t<std::is_trivially_copyable_v<T>>>
+ static constexpr size_t getFlattenedSize(const T&) {
+ return sizeof(T);
+ }
+
+ template <class T, typename = std::enable_if_t<std::is_trivially_copyable_v<T>>>
+ static status_t flatten(void** buffer, size_t* size, const T& value) {
+ if (*size < sizeof(T)) return NO_MEMORY;
+ FlattenableUtils::write(*buffer, *size, value);
+ return OK;
+ }
+
+ template <class T, typename = std::enable_if_t<std::is_trivially_copyable_v<T>>>
+ static status_t unflatten(const void** buffer, size_t* size, T* value) {
+ if (*size < sizeof(T)) return NO_MEMORY;
+ FlattenableUtils::read(*buffer, *size, *value);
+ return OK;
+ }
+
+ // Helpers for reading and writing std::string
+ static size_t getFlattenedSize(const std::string& str) {
+ return sizeof(uint64_t) + str.length();
+ }
+
+ static status_t flatten(void** buffer, size_t* size, const std::string& str) {
+ if (*size < getFlattenedSize(str)) return NO_MEMORY;
+ flatten(buffer, size, (uint64_t)str.length());
+ memcpy(reinterpret_cast<char*>(*buffer), str.c_str(), str.length());
+ FlattenableUtils::advance(*buffer, *size, str.length());
+ return OK;
+ }
+
+ static status_t unflatten(const void** buffer, size_t* size, std::string* str) {
+ uint64_t length;
+ RETURN_IF_ERROR(unflatten(buffer, size, &length));
+ if (*size < length) return NO_MEMORY;
+ str->assign(reinterpret_cast<const char*>(*buffer), length);
+ FlattenableUtils::advance(*buffer, *size, length);
+ return OK;
+ }
+
+ // Helpers for reading and writing LightFlattenable
+ template <class T>
+ static size_t getFlattenedSize(const LightFlattenable<T>& value) {
+ return value.getFlattenedSize();
+ }
+
+ template <class T>
+ static status_t flatten(void** buffer, size_t* size, const LightFlattenable<T>& value) {
+ RETURN_IF_ERROR(value.flatten(*buffer, *size));
+ FlattenableUtils::advance(*buffer, *size, value.getFlattenedSize());
+ return OK;
+ }
+
+ template <class T>
+ static status_t unflatten(const void** buffer, size_t* size, LightFlattenable<T>* value) {
+ RETURN_IF_ERROR(value->unflatten(*buffer, *size));
+ FlattenableUtils::advance(*buffer, *size, value->getFlattenedSize());
+ return OK;
+ }
+
+ // Helpers for reading and writing std::optional
+ template <class T, typename = std::enable_if_t<std::negation_v<std::is_trivially_copyable<T>>>>
+ static size_t getFlattenedSize(const std::optional<T>& value) {
+ return sizeof(bool) + (value ? getFlattenedSize(*value) : 0);
+ }
+
+ template <class T, typename = std::enable_if_t<std::negation_v<std::is_trivially_copyable<T>>>>
+ static status_t flatten(void** buffer, size_t* size, const std::optional<T>& value) {
+ if (value) {
+ RETURN_IF_ERROR(flatten(buffer, size, true));
+ RETURN_IF_ERROR(flatten(buffer, size, *value));
+ } else {
+ RETURN_IF_ERROR(flatten(buffer, size, false));
+ }
+ return OK;
+ }
+
+ template <class T, typename = std::enable_if_t<std::negation_v<std::is_trivially_copyable<T>>>>
+ static status_t unflatten(const void** buffer, size_t* size, std::optional<T>* value) {
+ bool isPresent;
+ RETURN_IF_ERROR(unflatten(buffer, size, &isPresent));
+ if (isPresent) {
+ *value = T();
+ RETURN_IF_ERROR(unflatten(buffer, size, &(**value)));
+ } else {
+ value->reset();
+ }
+ return OK;
+ }
+
+ // Helpers for reading and writing std::vector
+ template <class T>
+ static size_t getFlattenedSize(const std::vector<T>& value) {
+ return std::accumulate(value.begin(), value.end(), sizeof(uint64_t),
+ [](size_t sum, const T& element) {
+ return sum + getFlattenedSize(element);
+ });
+ }
+
+ template <class T>
+ static status_t flatten(void** buffer, size_t* size, const std::vector<T>& value) {
+ RETURN_IF_ERROR(flatten(buffer, size, (uint64_t)value.size()));
+ for (const auto& element : value) {
+ RETURN_IF_ERROR(flatten(buffer, size, element));
+ }
+ return OK;
+ }
+
+ template <class T>
+ static status_t unflatten(const void** buffer, size_t* size, std::vector<T>* value) {
+ uint64_t numElements;
+ RETURN_IF_ERROR(unflatten(buffer, size, &numElements));
+ // We don't need an extra size check since each iteration of the loop does that
+ std::vector<T> elements;
+ for (size_t i = 0; i < numElements; i++) {
+ T element;
+ RETURN_IF_ERROR(unflatten(buffer, size, &element));
+ elements.push_back(element);
+ }
+ *value = std::move(elements);
+ return OK;
+ }
+};
+
+} // namespace android
+
+#undef RETURN_IF_ERROR
\ No newline at end of file
diff --git a/libs/ui/include/ui/ColorSpace.h b/libs/ui/include_types/ui/ColorSpace.h
similarity index 100%
rename from libs/ui/include/ui/ColorSpace.h
rename to libs/ui/include_types/ui/ColorSpace.h
diff --git a/libs/ui/include_vndk/ui/ColorSpace.h b/libs/ui/include_vndk/ui/ColorSpace.h
index ddf70d5..7d2a6d3 120000
--- a/libs/ui/include_vndk/ui/ColorSpace.h
+++ b/libs/ui/include_vndk/ui/ColorSpace.h
@@ -1 +1 @@
-../../include/ui/ColorSpace.h
\ No newline at end of file
+../../include_types/ui/ColorSpace.h
\ No newline at end of file
diff --git a/libs/ui/tests/Android.bp b/libs/ui/tests/Android.bp
index b53342c..28ef77a 100644
--- a/libs/ui/tests/Android.bp
+++ b/libs/ui/tests/Android.bp
@@ -29,6 +29,13 @@
}
cc_test {
+ name: "FlattenableHelpers_test",
+ shared_libs: ["libui"],
+ srcs: ["FlattenableHelpers_test.cpp"],
+ cflags: ["-Wall", "-Werror"],
+}
+
+cc_test {
name: "GraphicBufferAllocator_test",
header_libs: [
"libnativewindow_headers",
diff --git a/libs/ui/tests/FlattenableHelpers_test.cpp b/libs/ui/tests/FlattenableHelpers_test.cpp
new file mode 100644
index 0000000..db32bc7
--- /dev/null
+++ b/libs/ui/tests/FlattenableHelpers_test.cpp
@@ -0,0 +1,136 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "FlattenableHelpersTest"
+
+#include <ui/FlattenableHelpers.h>
+
+#include <gtest/gtest.h>
+#include <utils/Flattenable.h>
+#include <cstdint>
+#include <memory>
+#include <optional>
+#include <string>
+#include <vector>
+
+namespace android {
+
+namespace {
+
+struct TestLightFlattenable : LightFlattenable<TestLightFlattenable> {
+ std::unique_ptr<int32_t> ptr;
+
+ bool isFixedSize() const { return true; }
+ size_t getFlattenedSize() const { return sizeof(int32_t); }
+
+ status_t flatten(void* buffer, size_t size) const {
+ FlattenableUtils::write(buffer, size, *ptr);
+ return OK;
+ }
+
+ status_t unflatten(void const* buffer, size_t size) {
+ int value;
+ FlattenableUtils::read(buffer, size, value);
+ ptr = std::make_unique<int32_t>(value);
+ return OK;
+ }
+};
+
+class FlattenableHelpersTest : public testing::Test {
+public:
+ template <class T>
+ void testWriteThenRead(const T& value, size_t bufferSize) {
+ std::vector<int8_t> buffer(bufferSize);
+ auto rawBuffer = reinterpret_cast<void*>(buffer.data());
+ size_t size = buffer.size();
+ ASSERT_EQ(OK, FlattenableHelpers::flatten(&rawBuffer, &size, value));
+
+ auto rawReadBuffer = reinterpret_cast<const void*>(buffer.data());
+ size = buffer.size();
+ T valueRead;
+ ASSERT_EQ(OK, FlattenableHelpers::unflatten(&rawReadBuffer, &size, &valueRead));
+ EXPECT_EQ(value, valueRead);
+ }
+
+ template <class T>
+ void testTriviallyCopyable(const T& value) {
+ testWriteThenRead(value, sizeof(T));
+ }
+
+ template <class T>
+ void testWriteThenRead(const T& value) {
+ testWriteThenRead(value, FlattenableHelpers::getFlattenedSize(value));
+ }
+};
+
+TEST_F(FlattenableHelpersTest, TriviallyCopyable) {
+ testTriviallyCopyable(42);
+ testTriviallyCopyable(1LL << 63);
+ testTriviallyCopyable(false);
+ testTriviallyCopyable(true);
+ testTriviallyCopyable(std::optional<int>());
+ testTriviallyCopyable(std::optional<int>(4));
+}
+
+TEST_F(FlattenableHelpersTest, String) {
+ testWriteThenRead(std::string("Android"));
+ testWriteThenRead(std::string());
+}
+
+TEST_F(FlattenableHelpersTest, Vector) {
+ testWriteThenRead(std::vector<int>({1, 2, 3}));
+ testWriteThenRead(std::vector<int>());
+}
+
+TEST_F(FlattenableHelpersTest, OptionalOfLightFlattenable) {
+ std::vector<size_t> buffer;
+ constexpr int kInternalValue = 16;
+ {
+ std::optional<TestLightFlattenable> value =
+ TestLightFlattenable{.ptr = std::make_unique<int32_t>(kInternalValue)};
+ buffer.assign(FlattenableHelpers::getFlattenedSize(value), 0);
+ void* rawBuffer = reinterpret_cast<void*>(buffer.data());
+ size_t size = buffer.size();
+ ASSERT_EQ(OK, FlattenableHelpers::flatten(&rawBuffer, &size, value));
+ }
+
+ const void* rawReadBuffer = reinterpret_cast<const void*>(buffer.data());
+ size_t size = buffer.size();
+ std::optional<TestLightFlattenable> valueRead;
+ ASSERT_EQ(OK, FlattenableHelpers::unflatten(&rawReadBuffer, &size, &valueRead));
+ ASSERT_TRUE(valueRead.has_value());
+ EXPECT_EQ(kInternalValue, *valueRead->ptr);
+}
+
+TEST_F(FlattenableHelpersTest, NullOptionalOfLightFlattenable) {
+ std::vector<size_t> buffer;
+ {
+ std::optional<TestLightFlattenable> value;
+ buffer.assign(FlattenableHelpers::getFlattenedSize(value), 0);
+ void* rawBuffer = reinterpret_cast<void*>(buffer.data());
+ size_t size = buffer.size();
+ ASSERT_EQ(OK, FlattenableHelpers::flatten(&rawBuffer, &size, value));
+ }
+
+ const void* rawReadBuffer = reinterpret_cast<const void*>(buffer.data());
+ size_t size = buffer.size();
+ std::optional<TestLightFlattenable> valueRead;
+ ASSERT_EQ(OK, FlattenableHelpers::unflatten(&rawReadBuffer, &size, &valueRead));
+ ASSERT_FALSE(valueRead.has_value());
+}
+
+} // namespace
+} // namespace android
diff --git a/opengl/include/EGL/eglext_angle.h b/opengl/include/EGL/eglext_angle.h
index 0556ea1..1f1bcb3 100644
--- a/opengl/include/EGL/eglext_angle.h
+++ b/opengl/include/EGL/eglext_angle.h
@@ -4,12 +4,12 @@
// found in the LICENSE file.
//
// eglext_angle.h: ANGLE modifications to the eglext.h header file.
-// Currently we don't include this file directly, we patch eglext.h
-// to include it implicitly so it is visible throughout our code.
#ifndef INCLUDE_EGL_EGLEXT_ANGLE_
#define INCLUDE_EGL_EGLEXT_ANGLE_
+#include <EGL/eglext.h>
+
// clang-format off
#ifndef EGL_ANGLE_robust_resource_initialization
diff --git a/opengl/libs/Android.bp b/opengl/libs/Android.bp
index e8d3684..3c76c62 100644
--- a/opengl/libs/Android.bp
+++ b/opengl/libs/Android.bp
@@ -102,11 +102,6 @@
"libbacktrace",
"libbase",
],
- target: {
- vendor: {
- exclude_shared_libs: ["libgraphicsenv"],
- },
- },
}
cc_library_static {
diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp
index d66ef2b..1afc693 100644
--- a/opengl/libs/EGL/Loader.cpp
+++ b/opengl/libs/EGL/Loader.cpp
@@ -17,27 +17,23 @@
//#define LOG_NDEBUG 0
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
-#include <EGL/Loader.h>
-
-#include <string>
-
-#include <dirent.h>
-#include <dlfcn.h>
+#include "EGL/Loader.h"
#include <android-base/properties.h>
#include <android/dlext.h>
+#include <dirent.h>
+#include <dlfcn.h>
+#include <graphicsenv/GraphicsEnv.h>
#include <log/log.h>
#include <utils/Timers.h>
-
-#ifndef __ANDROID_VNDK__
-#include <graphicsenv/GraphicsEnv.h>
-#endif
#include <vndksupport/linker.h>
+#include <string>
+
+#include "EGL/eglext_angle.h"
#include "egl_platform_entries.h"
#include "egl_trace.h"
#include "egldefs.h"
-#include <EGL/eglext_angle.h>
namespace android {
@@ -159,13 +155,11 @@
return true;
}
-#ifndef __ANDROID_VNDK__
// Return true if updated driver namespace is set.
ns = android::GraphicsEnv::getInstance().getDriverNamespace();
if (ns) {
return true;
}
-#endif
return false;
}
@@ -276,7 +270,7 @@
// will set cnx->useAngle appropriately.
// Do this here so that we use ANGLE path when driver is ANGLE (e.g. loaded as native),
// not just loading ANGLE as option.
- init_angle_backend(hnd->dso[0], cnx);
+ init_angle_backend(hnd->dso[2], cnx);
}
LOG_ALWAYS_FATAL_IF(!hnd,
@@ -370,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.
*/
@@ -557,12 +551,8 @@
}
void Loader::init_angle_backend(void* dso, egl_connection_t* cnx) {
- void* eglCreateDeviceANGLE = nullptr;
-
- ALOGV("dso: %p", dso);
- eglCreateDeviceANGLE = dlsym(dso, "eglCreateDeviceANGLE");
- ALOGV("eglCreateDeviceANGLE: %p", eglCreateDeviceANGLE);
- if (eglCreateDeviceANGLE) {
+ void* pANGLEGetDisplayPlatform = dlsym(dso, "ANGLEGetDisplayPlatform");
+ if (pANGLEGetDisplayPlatform) {
ALOGV("ANGLE GLES library in use");
cnx->useAngle = true;
} else {
@@ -573,7 +563,7 @@
Loader::driver_t* Loader::attempt_to_load_updated_driver(egl_connection_t* cnx) {
ATRACE_CALL();
-#ifndef __ANDROID_VNDK__
+
android_namespace_t* ns = android::GraphicsEnv::getInstance().getDriverNamespace();
if (!ns) {
return nullptr;
@@ -603,9 +593,6 @@
hnd->set(dso, GLESv2);
}
return hnd;
-#else
- return nullptr;
-#endif
}
Loader::driver_t* Loader::attempt_to_load_system_driver(egl_connection_t* cnx, const char* suffix,
diff --git a/opengl/libs/EGL/egl_display.cpp b/opengl/libs/EGL/egl_display.cpp
index 3b1cf71..8c6f284 100644
--- a/opengl/libs/EGL/egl_display.cpp
+++ b/opengl/libs/EGL/egl_display.cpp
@@ -19,25 +19,22 @@
#include "egl_display.h"
+#include <SurfaceFlingerProperties.h>
+#include <android-base/properties.h>
+#include <android/dlext.h>
+#include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
+#include <configstore/Utils.h>
+#include <dlfcn.h>
+#include <graphicsenv/GraphicsEnv.h>
+
#include "../egl_impl.h"
-
-#include <EGL/eglext_angle.h>
-#include <private/EGL/display.h>
-
+#include "EGL/eglext_angle.h"
#include "Loader.h"
#include "egl_angle_platform.h"
#include "egl_cache.h"
#include "egl_object.h"
#include "egl_tls.h"
-
-#include <SurfaceFlingerProperties.h>
-#include <android-base/properties.h>
-#include <android/dlext.h>
-#include <dlfcn.h>
-#include <graphicsenv/GraphicsEnv.h>
-
-#include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
-#include <configstore/Utils.h>
+#include "private/EGL/display.h"
using namespace android::hardware::configstore;
using namespace android::hardware::configstore::V1_0;
diff --git a/opengl/libs/EGL/egl_object.cpp b/opengl/libs/EGL/egl_object.cpp
index ff4fe2d..fd426c2 100644
--- a/opengl/libs/EGL/egl_object.cpp
+++ b/opengl/libs/EGL/egl_object.cpp
@@ -309,6 +309,18 @@
gl_extensions = exts;
if (gl_extensions.find("GL_EXT_debug_marker") == std::string::npos) {
gl_extensions.insert(0, "GL_EXT_debug_marker ");
+ // eglGetProcAddress could return function pointers to these
+ // functions while they actually don't work. Fix them now.
+ __eglMustCastToProperFunctionPointerType* f;
+ f = (__eglMustCastToProperFunctionPointerType*)&gEGLImpl.hooks[version]
+ ->gl.glInsertEventMarkerEXT;
+ if (*f != gl_noop) *f = gl_noop;
+ f = (__eglMustCastToProperFunctionPointerType*)&gEGLImpl.hooks[version]
+ ->gl.glPushGroupMarkerEXT;
+ if (*f != gl_noop) *f = gl_noop;
+ f = (__eglMustCastToProperFunctionPointerType*)&gEGLImpl.hooks[version]
+ ->gl.glPopGroupMarkerEXT;
+ if (*f != gl_noop) *f = gl_noop;
}
// tokenize the supported extensions for the glGetStringi() wrapper
diff --git a/opengl/libs/EGL/egl_platform_entries.cpp b/opengl/libs/EGL/egl_platform_entries.cpp
index aa24e8e..1119e4a 100644
--- a/opengl/libs/EGL/egl_platform_entries.cpp
+++ b/opengl/libs/EGL/egl_platform_entries.cpp
@@ -18,36 +18,32 @@
#include "egl_platform_entries.h"
-#include <ctype.h>
-#include <dlfcn.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <EGL/egl.h>
-#include <EGL/eglext.h>
-#include <EGL/eglext_angle.h>
-
#include <android-base/properties.h>
#include <android-base/strings.h>
#include <android/hardware_buffer.h>
-#include <graphicsenv/GraphicsEnv.h>
-#include <private/android/AHardwareBufferHelpers.h>
-
+#include <ctype.h>
#include <cutils/compiler.h>
+#include <dlfcn.h>
+#include <graphicsenv/GraphicsEnv.h>
#include <log/log.h>
+#include <private/android/AHardwareBufferHelpers.h>
+#include <stdlib.h>
+#include <string.h>
#include <condition_variable>
#include <deque>
#include <mutex>
-#include <unordered_map>
#include <string>
#include <thread>
+#include <unordered_map>
#include "../egl_impl.h"
-
+#include "EGL/egl.h"
+#include "EGL/eglext.h"
+#include "EGL/eglext_angle.h"
#include "egl_display.h"
-#include "egl_object.h"
#include "egl_layers.h"
+#include "egl_object.h"
#include "egl_tls.h"
#include "egl_trace.h"
@@ -2248,15 +2244,8 @@
}
EGLClientBuffer eglGetNativeClientBufferANDROIDImpl(const AHardwareBuffer *buffer) {
- // AHardwareBuffer_to_ANativeWindowBuffer is a platform-only symbol and thus
- // this function cannot be implemented when this libEGL is built for
- // vendors.
-#ifndef __ANDROID_VNDK__
if (!buffer) return setError(EGL_BAD_PARAMETER, (EGLClientBuffer) nullptr);
return const_cast<ANativeWindowBuffer *>(AHardwareBuffer_to_ANativeWindowBuffer(buffer));
-#else
- return setError(EGL_BAD_PARAMETER, (EGLClientBuffer) nullptr);
-#endif
}
// ----------------------------------------------------------------------------
diff --git a/services/gpuservice/Android.bp b/services/gpuservice/Android.bp
index 6eed24a..1bcaab4 100644
--- a/services/gpuservice/Android.bp
+++ b/services/gpuservice/Android.bp
@@ -21,6 +21,8 @@
"libbinder",
"libcutils",
"libgfxstats",
+ "libgpumem",
+ "libgpumemtracer",
"libgraphicsenv",
"liblog",
"libutils",
@@ -85,6 +87,10 @@
name: "gpuservice",
defaults: ["libgpuservice_binary"],
init_rc: ["gpuservice.rc"],
+ required: [
+ "bpfloader",
+ "gpu_mem.o",
+ ],
srcs: [":gpuservice_binary_sources"],
shared_libs: [
"libgpuservice",
diff --git a/services/gpuservice/CleanSpec.mk b/services/gpuservice/CleanSpec.mk
new file mode 100644
index 0000000..482fc6d
--- /dev/null
+++ b/services/gpuservice/CleanSpec.mk
@@ -0,0 +1,52 @@
+# 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.
+#
+
+# If you don't need to do a full clean build but would like to touch
+# a file or delete some intermediate files, add a clean step to the end
+# of the list. These steps will only be run once, if they haven't been
+# run before.
+#
+# E.g.:
+# $(call add-clean-step, touch -c external/sqlite/sqlite3.h)
+# $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libz_intermediates)
+#
+# Always use "touch -c" and "rm -f" or "rm -rf" to gracefully deal with
+# files that are missing or have been moved.
+#
+# Use $(PRODUCT_OUT) to get to the "out/target/product/blah/" directory.
+# Use $(OUT_DIR) to refer to the "out" directory.
+#
+# If you need to re-do something that's already mentioned, just copy
+# the command and add it to the bottom of the list. E.g., if a change
+# that you made last week required touching a file and a change you
+# made today requires touching the same file, just copy the old
+# touch step and add it to the end of the list.
+#
+# ************************************************
+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
+# ************************************************
+
+# For example:
+#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/AndroidTests_intermediates)
+#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/core_intermediates)
+#$(call add-clean-step, find $(OUT_DIR) -type f -name "IGTalkSession*" -print0 | xargs -0 rm -f)
+#$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/*)
+
+# Remove gpu_mem.o
+$(call add-clean-step, rm -rf $(OUT_DIR)/soong/.intermediates/frameworks/native/services/gpuservice/bpf)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/FAKE/gpu_mem.o_intermediates)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/ETC/gpu_mem.o_gpu_mem.o_intermediates)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/etc/bpf/gpu_mem.o)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/fake_packages/gpu_mem.o-timestamp)
diff --git a/services/gpuservice/GpuService.cpp b/services/gpuservice/GpuService.cpp
index 304f1d0..18c819f 100644
--- a/services/gpuservice/GpuService.cpp
+++ b/services/gpuservice/GpuService.cpp
@@ -24,13 +24,16 @@
#include <binder/Parcel.h>
#include <binder/PermissionCache.h>
#include <cutils/properties.h>
+#include <gpumem/GpuMem.h>
#include <gpustats/GpuStats.h>
#include <private/android_filesystem_config.h>
+#include <tracing/GpuMemTracer.h>
#include <utils/String8.h>
#include <utils/Trace.h>
-
#include <vkjson.h>
+#include <thread>
+
namespace android {
using base::StringAppendF;
@@ -45,7 +48,16 @@
const char* const GpuService::SERVICE_NAME = "gpu";
-GpuService::GpuService() : mGpuStats(std::make_unique<GpuStats>()){};
+GpuService::GpuService()
+ : mGpuMem(std::make_shared<GpuMem>()),
+ mGpuStats(std::make_unique<GpuStats>()),
+ mGpuMemTracer(std::make_unique<GpuMemTracer>()) {
+ std::thread asyncInitThread([this]() {
+ mGpuMem->initialize();
+ mGpuMemTracer->initialize(mGpuMem);
+ });
+ asyncInitThread.detach();
+};
void GpuService::setGpuStats(const std::string& driverPackageName,
const std::string& driverVersionName, uint64_t driverVersionCode,
@@ -98,6 +110,7 @@
} else {
bool dumpAll = true;
bool dumpDriverInfo = false;
+ bool dumpMem = false;
bool dumpStats = false;
size_t numArgs = args.size();
@@ -107,15 +120,21 @@
dumpStats = true;
} else if (args[index] == String16("--gpudriverinfo")) {
dumpDriverInfo = true;
+ } else if (args[index] == String16("--gpumem")) {
+ dumpMem = true;
}
}
- dumpAll = !(dumpDriverInfo || dumpStats);
+ dumpAll = !(dumpDriverInfo || dumpMem || dumpStats);
}
if (dumpAll || dumpDriverInfo) {
dumpGameDriverInfo(&result);
result.append("\n");
}
+ if (dumpAll || dumpMem) {
+ mGpuMem->dump(args, &result);
+ result.append("\n");
+ }
if (dumpAll || dumpStats) {
mGpuStats->dump(args, &result);
result.append("\n");
diff --git a/services/gpuservice/GpuService.h b/services/gpuservice/GpuService.h
index ba44fe0..43faa3e 100644
--- a/services/gpuservice/GpuService.h
+++ b/services/gpuservice/GpuService.h
@@ -28,7 +28,9 @@
namespace android {
+class GpuMem;
class GpuStats;
+class GpuMemTracer;
class GpuService : public BnGpuService, public PriorityDumper {
public:
@@ -74,7 +76,9 @@
/*
* Attributes
*/
+ std::shared_ptr<GpuMem> mGpuMem;
std::unique_ptr<GpuStats> mGpuStats;
+ std::unique_ptr<GpuMemTracer> mGpuMemTracer;
std::string developerDriverPath;
};
diff --git a/services/gpuservice/bpfprogs/Android.bp b/services/gpuservice/bpfprogs/Android.bp
new file mode 100644
index 0000000..b875814
--- /dev/null
+++ b/services/gpuservice/bpfprogs/Android.bp
@@ -0,0 +1,22 @@
+// 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.
+
+bpf {
+ name: "gpu_mem.o",
+ srcs: ["gpu_mem.c"],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
+}
diff --git a/services/gpuservice/bpfprogs/gpu_mem.c b/services/gpuservice/bpfprogs/gpu_mem.c
new file mode 100644
index 0000000..c75213b
--- /dev/null
+++ b/services/gpuservice/bpfprogs/gpu_mem.c
@@ -0,0 +1,75 @@
+/*
+ * 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.
+ */
+
+#include <bpf_helpers.h>
+
+/*
+ * On Android the number of active processes using gpu is limited.
+ * So this is assumed to be true: SUM(num_procs_using_gpu[i]) <= 1024
+ */
+#define GPU_MEM_TOTAL_MAP_SIZE 1024
+
+/*
+ * This map maintains the global and per process gpu memory total counters.
+ *
+ * The KEY is ((gpu_id << 32) | pid) while VAL is the size in bytes.
+ * Use HASH type here since key is not int.
+ * Pass AID_GRAPHICS as gid since gpuservice is in the graphics group.
+ */
+DEFINE_BPF_MAP_GRO(gpu_mem_total_map, HASH, uint64_t, uint64_t, GPU_MEM_TOTAL_MAP_SIZE,
+ AID_GRAPHICS);
+
+/* This struct aligns with the fields offsets of the raw tracepoint format */
+struct gpu_mem_total_args {
+ uint64_t ignore;
+ /* Actual fields start at offset 8 */
+ uint32_t gpu_id;
+ uint32_t pid;
+ uint64_t size;
+};
+
+/*
+ * This program parses the gpu_mem/gpu_mem_total tracepoint's data into
+ * {KEY, VAL} pair used to update the corresponding bpf map.
+ *
+ * Pass AID_GRAPHICS as gid since gpuservice is in the graphics group.
+ * Upon seeing size 0, the corresponding KEY needs to be cleaned up.
+ */
+DEFINE_BPF_PROG("tracepoint/gpu_mem/gpu_mem_total", AID_ROOT, AID_GRAPHICS, tp_gpu_mem_total)
+(struct gpu_mem_total_args* args) {
+ uint64_t key = 0;
+ uint64_t cur_val = 0;
+ uint64_t* prev_val = NULL;
+
+ /* The upper 32 bits are for gpu_id while the lower is the pid */
+ key = ((uint64_t)args->gpu_id << 32) | args->pid;
+ cur_val = args->size;
+
+ if (!cur_val) {
+ bpf_gpu_mem_total_map_delete_elem(&key);
+ return 0;
+ }
+
+ prev_val = bpf_gpu_mem_total_map_lookup_elem(&key);
+ if (prev_val) {
+ *prev_val = cur_val;
+ } else {
+ bpf_gpu_mem_total_map_update_elem(&key, &cur_val, BPF_NOEXIST);
+ }
+ return 0;
+}
+
+char _license[] SEC("license") = "Apache 2.0";
diff --git a/services/gpuservice/gpumem/Android.bp b/services/gpuservice/gpumem/Android.bp
new file mode 100644
index 0000000..b2230b6
--- /dev/null
+++ b/services/gpuservice/gpumem/Android.bp
@@ -0,0 +1,41 @@
+// Copyright 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_library_shared {
+ name: "libgpumem",
+ srcs: [
+ "GpuMem.cpp",
+ ],
+ shared_libs: [
+ "libbase",
+ "libbpf",
+ "libbpf_android",
+ "libcutils",
+ "liblog",
+ "libutils",
+ ],
+ export_include_dirs: ["include"],
+ export_shared_lib_headers: [
+ "libbase",
+ "libbpf_android",
+ ],
+ cppflags: [
+ "-Wall",
+ "-Werror",
+ "-Wformat",
+ "-Wthread-safety",
+ "-Wunused",
+ "-Wunreachable-code",
+ ],
+}
diff --git a/services/gpuservice/gpumem/GpuMem.cpp b/services/gpuservice/gpumem/GpuMem.cpp
new file mode 100644
index 0000000..9b4053b
--- /dev/null
+++ b/services/gpuservice/gpumem/GpuMem.cpp
@@ -0,0 +1,132 @@
+/*
+ * 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 "GpuMem"
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
+#include "gpumem/GpuMem.h"
+
+#include <android-base/stringprintf.h>
+#include <libbpf.h>
+#include <libbpf_android.h>
+#include <log/log.h>
+#include <unistd.h>
+#include <utils/Trace.h>
+
+#include <unordered_map>
+#include <vector>
+
+namespace android {
+
+using base::StringAppendF;
+
+GpuMem::~GpuMem() {
+ bpf_detach_tracepoint(kGpuMemTraceGroup, kGpuMemTotalTracepoint);
+}
+
+void GpuMem::initialize() {
+ // Make sure bpf programs are loaded
+ bpf::waitForProgsLoaded();
+
+ int fd = bpf::bpfFdGet(kGpuMemTotalProgPath, BPF_F_RDONLY);
+ if (fd < 0) {
+ ALOGE("Failed to retrieve pinned program from %s", kGpuMemTotalProgPath);
+ return;
+ }
+
+ // TODO(http://b/159963505): Figure out a nicer way to wait until GPU driver loaded.
+ // Attach the program to the tracepoint, and the tracepoint is automatically enabled here.
+ int count = 0;
+ while (bpf_attach_tracepoint(fd, kGpuMemTraceGroup, kGpuMemTotalTracepoint) < 0) {
+ if (++count > kGpuWaitTimeout) {
+ ALOGE("Failed to attach bpf program to %s/%s tracepoint", kGpuMemTraceGroup,
+ kGpuMemTotalTracepoint);
+ return;
+ }
+ // Retry until GPU driver loaded or timeout.
+ sleep(1);
+ }
+
+ // Use the read-only wrapper BpfMapRO to properly retrieve the read-only map.
+ auto map = bpf::BpfMapRO<uint64_t, uint64_t>(kGpuMemTotalMapPath);
+ if (!map.isValid()) {
+ ALOGE("Failed to create bpf map from %s", kGpuMemTotalMapPath);
+ return;
+ }
+ setGpuMemTotalMap(map);
+
+ mInitialized.store(true);
+}
+
+void GpuMem::setGpuMemTotalMap(bpf::BpfMap<uint64_t, uint64_t>& map) {
+ mGpuMemTotalMap = std::move(map);
+}
+
+// Dump the snapshots of global and per process memory usage on all gpus
+void GpuMem::dump(const Vector<String16>& /* args */, std::string* result) {
+ ATRACE_CALL();
+
+ if (!mInitialized.load() || !mGpuMemTotalMap.isValid()) {
+ result->append("Failed to initialize GPU memory eBPF\n");
+ return;
+ }
+
+ auto res = mGpuMemTotalMap.getFirstKey();
+ if (!res.ok()) {
+ result->append("GPU memory total usage map is empty\n");
+ return;
+ }
+ uint64_t key = res.value();
+ // unordered_map<gpu_id, vector<pair<pid, size>>>
+ std::unordered_map<uint32_t, std::vector<std::pair<uint32_t, uint64_t>>> dumpMap;
+ while (true) {
+ uint32_t gpu_id = key >> 32;
+ uint32_t pid = key;
+
+ res = mGpuMemTotalMap.readValue(key);
+ if (!res.ok()) break;
+ uint64_t size = res.value();
+
+ dumpMap[gpu_id].emplace_back(pid, size);
+
+ res = mGpuMemTotalMap.getNextKey(key);
+ if (!res.ok()) break;
+ key = res.value();
+ }
+
+ for (auto& gpu : dumpMap) {
+ if (gpu.second.empty()) continue;
+ StringAppendF(result, "Memory snapshot for GPU %u:\n", gpu.first);
+
+ std::sort(gpu.second.begin(), gpu.second.end(),
+ [](auto& l, auto& r) { return l.first < r.first; });
+
+ int i = 0;
+ if (gpu.second[0].first != 0) {
+ StringAppendF(result, "Global total: N/A\n");
+ } else {
+ StringAppendF(result, "Global total: %" PRIu64 "\n", gpu.second[0].second);
+ i++;
+ }
+ for (; i < gpu.second.size(); i++) {
+ StringAppendF(result, "Proc %u total: %" PRIu64 "\n", gpu.second[i].first,
+ gpu.second[i].second);
+ }
+ }
+}
+
+} // namespace android
diff --git a/services/gpuservice/gpumem/include/gpumem/GpuMem.h b/services/gpuservice/gpumem/include/gpumem/GpuMem.h
new file mode 100644
index 0000000..49a9f95
--- /dev/null
+++ b/services/gpuservice/gpumem/include/gpumem/GpuMem.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <bpf/BpfMap.h>
+#include <utils/String16.h>
+#include <utils/Vector.h>
+
+namespace android {
+
+class GpuMem {
+public:
+ GpuMem() = default;
+ ~GpuMem();
+
+ // initialize eBPF program and map
+ void initialize();
+ // dumpsys interface
+ void dump(const Vector<String16>& args, std::string* result);
+ bool isInitialized() { return mInitialized.load(); }
+
+ // Traverse the map and send each value read back to the callback function.
+ // Used for tracing.
+ template <typename lambda>
+ void traceGpuMemTotals(lambda tracerCallback) {
+ auto res = mGpuMemTotalMap.getFirstKey();
+ if (!res.ok()) return;
+ uint64_t key = res.value();
+ while (true) {
+ uint32_t gpu_id = key >> 32;
+ uint32_t pid = key;
+
+ res = mGpuMemTotalMap.readValue(key);
+ if (!res.ok()) break;
+ uint64_t size = res.value();
+
+ tracerCallback(gpu_id, pid, size);
+ res = mGpuMemTotalMap.getNextKey(key);
+ if (!res.ok()) break;
+ key = res.value();
+ }
+ }
+
+private:
+ // Friend class for testing.
+ friend class TestableGpuMem;
+
+ // set gpu memory total map
+ void setGpuMemTotalMap(bpf::BpfMap<uint64_t, uint64_t>& map);
+
+ // indicate whether ebpf has been initialized
+ std::atomic<bool> mInitialized = false;
+ // bpf map for GPU memory total data
+ android::bpf::BpfMap<uint64_t, uint64_t> mGpuMemTotalMap;
+
+ // gpu memory tracepoint event category
+ static constexpr char kGpuMemTraceGroup[] = "gpu_mem";
+ // gpu memory total tracepoint
+ static constexpr char kGpuMemTotalTracepoint[] = "gpu_mem_total";
+ // pinned gpu memory total bpf c program path in bpf sysfs
+ static constexpr char kGpuMemTotalProgPath[] =
+ "/sys/fs/bpf/prog_gpu_mem_tracepoint_gpu_mem_gpu_mem_total";
+ // pinned gpu memory total bpf map path in bpf sysfs
+ static constexpr char kGpuMemTotalMapPath[] = "/sys/fs/bpf/map_gpu_mem_gpu_mem_total_map";
+ // 30 seconds timeout for trying to attach bpf program to tracepoint
+ static constexpr int kGpuWaitTimeout = 30;
+};
+
+} // namespace android
diff --git a/services/gpuservice/tests/unittests/Android.bp b/services/gpuservice/tests/unittests/Android.bp
index 538506d..db81f5d 100644
--- a/services/gpuservice/tests/unittests/Android.bp
+++ b/services/gpuservice/tests/unittests/Android.bp
@@ -19,11 +19,16 @@
address: true,
},
srcs: [
+ "GpuMemTest.cpp",
"GpuStatsTest.cpp",
],
shared_libs: [
+ "libbase",
+ "libbpf",
+ "libbpf_android",
"libcutils",
"libgfxstats",
+ "libgpumem",
"libgraphicsenv",
"liblog",
"libstatslog",
diff --git a/services/gpuservice/tests/unittests/GpuMemTest.cpp b/services/gpuservice/tests/unittests/GpuMemTest.cpp
new file mode 100644
index 0000000..abaf30a
--- /dev/null
+++ b/services/gpuservice/tests/unittests/GpuMemTest.cpp
@@ -0,0 +1,147 @@
+/*
+ * 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 "gpuservice_unittest"
+
+#include <android-base/stringprintf.h>
+#include <bpf/BpfMap.h>
+#include <gmock/gmock.h>
+#include <gpumem/GpuMem.h>
+#include <gtest/gtest.h>
+#include <inttypes.h>
+#include <utils/String16.h>
+#include <utils/Vector.h>
+
+#include "TestableGpuMem.h"
+
+namespace android {
+namespace {
+
+using base::StringPrintf;
+using testing::HasSubstr;
+
+constexpr uint32_t TEST_MAP_SIZE = 10;
+constexpr uint64_t TEST_GLOBAL_KEY = 0;
+constexpr uint64_t TEST_GLOBAL_VAL = 123;
+constexpr uint64_t TEST_PROC_KEY_1 = 1;
+constexpr uint64_t TEST_PROC_VAL_1 = 234;
+constexpr uint64_t TEST_PROC_KEY_2 = 4294967298; // (1 << 32) + 2
+constexpr uint64_t TEST_PROC_VAL_2 = 345;
+
+class GpuMemTest : public testing::Test {
+public:
+ GpuMemTest() {
+ const ::testing::TestInfo* const test_info =
+ ::testing::UnitTest::GetInstance()->current_test_info();
+ ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name());
+ }
+
+ ~GpuMemTest() {
+ const ::testing::TestInfo* const test_info =
+ ::testing::UnitTest::GetInstance()->current_test_info();
+ ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name());
+ }
+
+ void SetUp() override {
+ SKIP_IF_BPF_NOT_SUPPORTED;
+ ASSERT_EQ(0, bpf::setrlimitForTest());
+
+ mGpuMem = std::make_unique<GpuMem>();
+ mTestableGpuMem = TestableGpuMem(mGpuMem.get());
+ mTestableGpuMem.setInitialized();
+ 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());
+ }
+
+ std::string dumpsys() {
+ std::string result;
+ Vector<String16> args;
+ mGpuMem->dump(args, &result);
+ return result;
+ }
+
+ std::unique_ptr<GpuMem> mGpuMem;
+ TestableGpuMem mTestableGpuMem;
+ bpf::BpfMap<uint64_t, uint64_t> mTestMap;
+};
+
+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(),
+ "/sys/fs/bpf/prog_gpu_mem_tracepoint_gpu_mem_gpu_mem_total");
+ EXPECT_EQ(mTestableGpuMem.getGpuMemTotalMapPath(), "/sys/fs/bpf/map_gpu_mem_gpu_mem_total_map");
+}
+
+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);
+
+ EXPECT_THAT(dumpsys(), HasSubstr(StringPrintf("Global total: %" PRIu64 "\n", TEST_GLOBAL_VAL)));
+}
+
+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);
+
+ EXPECT_THAT(dumpsys(), HasSubstr("Global total: N/A"));
+}
+
+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);
+
+ EXPECT_THAT(dumpsys(),
+ HasSubstr(StringPrintf("Memory snapshot for GPU %u:\n",
+ (uint32_t)(TEST_PROC_KEY_1 >> 32))));
+ EXPECT_THAT(dumpsys(),
+ HasSubstr(StringPrintf("Proc %u total: %" PRIu64 "\n", (uint32_t)TEST_PROC_KEY_1,
+ TEST_PROC_VAL_1)));
+ EXPECT_THAT(dumpsys(),
+ HasSubstr(StringPrintf("Memory snapshot for GPU %u:\n",
+ (uint32_t)(TEST_PROC_KEY_2 >> 32))));
+ EXPECT_THAT(dumpsys(),
+ HasSubstr(StringPrintf("Proc %u total: %" PRIu64 "\n", (uint32_t)TEST_PROC_KEY_2,
+ TEST_PROC_VAL_2)));
+}
+
+} // namespace
+} // namespace android
diff --git a/services/gpuservice/tests/unittests/TestableGpuMem.h b/services/gpuservice/tests/unittests/TestableGpuMem.h
new file mode 100644
index 0000000..6c8becb
--- /dev/null
+++ b/services/gpuservice/tests/unittests/TestableGpuMem.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <bpf/BpfMap.h>
+#include <gpumem/GpuMem.h>
+
+namespace android {
+
+class TestableGpuMem {
+public:
+ TestableGpuMem() = default;
+ explicit TestableGpuMem(GpuMem *gpuMem) : mGpuMem(gpuMem) {}
+
+ void setInitialized() { mGpuMem->mInitialized.store(true); }
+
+ void setGpuMemTotalMap(bpf::BpfMap<uint64_t, uint64_t>& map) {
+ mGpuMem->setGpuMemTotalMap(map);
+ }
+
+ std::string getGpuMemTraceGroup() { return mGpuMem->kGpuMemTraceGroup; }
+
+ std::string getGpuMemTotalTracepoint() { return mGpuMem->kGpuMemTotalTracepoint; }
+
+ std::string getGpuMemTotalProgPath() { return mGpuMem->kGpuMemTotalProgPath; }
+
+ std::string getGpuMemTotalMapPath() { return mGpuMem->kGpuMemTotalMapPath; }
+
+private:
+ GpuMem *mGpuMem;
+};
+
+} // namespace android
diff --git a/services/gpuservice/tracing/Android.bp b/services/gpuservice/tracing/Android.bp
new file mode 100644
index 0000000..919fed3
--- /dev/null
+++ b/services/gpuservice/tracing/Android.bp
@@ -0,0 +1,41 @@
+// Copyright 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_library_shared {
+ name: "libgpumemtracer",
+ srcs: [
+ "GpuMemTracer.cpp",
+ ],
+ shared_libs: [
+ "libgpumem",
+ "libbase",
+ "liblog",
+ "libutils",
+ ],
+ static_libs: [
+ "libperfetto_client_experimental",
+ ],
+ export_include_dirs: ["include"],
+ export_static_lib_headers: [
+ "libperfetto_client_experimental",
+ ],
+ cppflags: [
+ "-Wall",
+ "-Werror",
+ "-Wformat",
+ "-Wthread-safety",
+ "-Wunused",
+ "-Wunreachable-code",
+ ],
+}
diff --git a/services/gpuservice/tracing/GpuMemTracer.cpp b/services/gpuservice/tracing/GpuMemTracer.cpp
new file mode 100644
index 0000000..c9bfa57
--- /dev/null
+++ b/services/gpuservice/tracing/GpuMemTracer.cpp
@@ -0,0 +1,101 @@
+/*
+ * 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 "GpuMemTracer"
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
+#include "tracing/GpuMemTracer.h"
+
+#include <gpumem/GpuMem.h>
+#include <perfetto/trace/android/gpu_mem_event.pbzero.h>
+#include <unistd.h>
+#include <utils/Timers.h>
+
+#include <algorithm>
+#include <thread>
+
+PERFETTO_DEFINE_DATA_SOURCE_STATIC_MEMBERS(android::GpuMemTracer::GpuMemDataSource);
+
+namespace android {
+
+std::mutex GpuMemTracer::sTraceMutex;
+std::condition_variable GpuMemTracer::sCondition;
+bool GpuMemTracer::sTraceStarted;
+
+void GpuMemTracer::initialize(std::shared_ptr<GpuMem> gpuMem) {
+ if (!gpuMem->isInitialized()) {
+ ALOGE("Cannot initialize GpuMemTracer before GpuMem");
+ return;
+ }
+ mGpuMem = gpuMem;
+ perfetto::TracingInitArgs args;
+ args.backends = perfetto::kSystemBackend;
+ // TODO(b/160016498): Find a better way to wait for traced
+ // Sleep for 30 seconds to make sure the data source is registered only
+ // after traced starts.
+ sleep(30);
+ perfetto::Tracing::Initialize(args);
+ registerDataSource();
+ std::thread tracerThread(&GpuMemTracer::threadLoop, this);
+ pthread_setname_np(tracerThread.native_handle(), "GpuMemTracerThread");
+ tracerThread.detach();
+}
+
+void GpuMemTracer::registerDataSource() {
+ perfetto::DataSourceDescriptor dsd;
+ dsd.set_name(kGpuMemDataSource);
+ GpuMemDataSource::Register(dsd);
+}
+
+void GpuMemTracer::threadLoop() {
+ while (true) {
+ {
+ std::unique_lock<std::mutex> lock(GpuMemTracer::sTraceMutex);
+ while (!sTraceStarted) {
+ sCondition.wait(lock);
+ }
+ }
+ traceInitialCounters();
+ {
+ std::lock_guard<std::mutex> lock(GpuMemTracer::sTraceMutex);
+ sTraceStarted = false;
+ }
+ }
+}
+
+void GpuMemTracer::traceInitialCounters() {
+ if (!mGpuMem->isInitialized()) {
+ // This should never happen.
+ ALOGE("Cannot trace without GpuMem initialization");
+ return;
+ }
+ mGpuMem->traceGpuMemTotals([](uint32_t gpuId, uint32_t pid, uint64_t size) {
+ GpuMemDataSource::Trace([&](GpuMemDataSource::TraceContext ctx) {
+ auto packet = ctx.NewTracePacket();
+ packet->set_timestamp(systemTime());
+ auto* event = packet->set_gpu_mem_total_event();
+ event->set_gpu_id(gpuId);
+ event->set_pid(pid);
+ event->set_size(size);
+ });
+ });
+ // Flush the TraceContext. The last packet in the above loop will go
+ // missing without this flush.
+ GpuMemDataSource::Trace([](GpuMemDataSource::TraceContext ctx) { ctx.Flush(); });
+}
+
+} // namespace android
diff --git a/services/gpuservice/tracing/include/tracing/GpuMemTracer.h b/services/gpuservice/tracing/include/tracing/GpuMemTracer.h
new file mode 100644
index 0000000..40deb4c
--- /dev/null
+++ b/services/gpuservice/tracing/include/tracing/GpuMemTracer.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <perfetto/tracing.h>
+
+#include <mutex>
+
+namespace android {
+
+class GpuMem;
+
+class GpuMemTracer {
+public:
+ class GpuMemDataSource : public perfetto::DataSource<GpuMemDataSource> {
+ virtual void OnSetup(const SetupArgs&) override{};
+ virtual void OnStart(const StartArgs&) override {
+ std::unique_lock<std::mutex> lock(GpuMemTracer::sTraceMutex);
+ sTraceStarted = true;
+ sCondition.notify_all();
+ }
+ virtual void OnStop(const StopArgs&) override{};
+ };
+
+ ~GpuMemTracer() = default;
+
+ // Sets up the perfetto tracing backend and data source.
+ void initialize(std::shared_ptr<GpuMem>);
+ // Registers the data source with the perfetto backend. Called as part of initialize()
+ // and should not be called manually outside of tests. Public to allow for substituting a
+ // perfetto::kInProcessBackend in tests.
+ void registerDataSource();
+
+ static constexpr char kGpuMemDataSource[] = "android.gpu.memory";
+ static std::condition_variable sCondition;
+ static std::mutex sTraceMutex;
+ static bool sTraceStarted;
+
+private:
+ void traceInitialCounters();
+ void threadLoop();
+
+ std::shared_ptr<GpuMem> mGpuMem;
+};
+
+} // namespace android
diff --git a/services/inputflinger/Android.bp b/services/inputflinger/Android.bp
index f67c9d0..f685628 100644
--- a/services/inputflinger/Android.bp
+++ b/services/inputflinger/Android.bp
@@ -21,6 +21,7 @@
"-Werror",
"-Wno-unused-parameter",
"-Wthread-safety",
+ "-Wshadow",
],
}
diff --git a/services/inputflinger/InputManager.cpp b/services/inputflinger/InputManager.cpp
index e68946d..c5f60ad 100644
--- a/services/inputflinger/InputManager.cpp
+++ b/services/inputflinger/InputManager.cpp
@@ -93,16 +93,15 @@
class BinderWindowHandle : public InputWindowHandle {
public:
- BinderWindowHandle(const InputWindowInfo& info) {
- mInfo = info;
- }
+ BinderWindowHandle(const InputWindowInfo& info) { mInfo = info; }
bool updateInfo() override {
return true;
}
};
-void InputManager::setInputWindows(const std::vector<InputWindowInfo>& infos,
+binder::Status InputManager::setInputWindows(
+ const std::vector<InputWindowInfo>& infos,
const sp<ISetInputWindowsListener>& setInputWindowsListener) {
std::unordered_map<int32_t, std::vector<sp<InputWindowHandle>>> handlesPerDisplay;
@@ -116,26 +115,38 @@
if (setInputWindowsListener) {
setInputWindowsListener->onSetInputWindowsFinished();
}
+ return binder::Status::ok();
}
// Used by tests only.
-void InputManager::registerInputChannel(const sp<InputChannel>& channel) {
+binder::Status InputManager::registerInputChannel(const InputChannelInfo& info) {
IPCThreadState* ipc = IPCThreadState::self();
const int uid = ipc->getCallingUid();
if (uid != AID_SHELL && uid != AID_ROOT) {
ALOGE("Invalid attempt to register input channel over IPC"
"from non shell/root entity (PID: %d)", ipc->getCallingPid());
- return;
+ return binder::Status::ok();
}
+ android::base::unique_fd newFd(::dup(info.mFd));
+ sp<InputChannel> channel = InputChannel::create(info.mName, std::move(newFd), info.mToken);
mDispatcher->registerInputChannel(channel);
+ return binder::Status::ok();
}
-void InputManager::unregisterInputChannel(const sp<InputChannel>& channel) {
+binder::Status InputManager::unregisterInputChannel(const InputChannelInfo& info) {
+ android::base::unique_fd newFd(::dup(info.mFd));
+ sp<InputChannel> channel = InputChannel::create(info.mName, std::move(newFd), info.mToken);
mDispatcher->unregisterInputChannel(channel);
+ return binder::Status::ok();
}
-void InputManager::setMotionClassifierEnabled(bool enabled) {
- mClassifier->setMotionClassifierEnabled(enabled);
+status_t InputManager::dump(int fd, const Vector<String16>& args) {
+ std::string dump;
+
+ dump += " InputFlinger dump\n";
+
+ ::write(fd, dump.c_str(), dump.size());
+ return NO_ERROR;
}
} // namespace android
diff --git a/services/inputflinger/InputManager.h b/services/inputflinger/InputManager.h
index 0158441..4993b54 100644
--- a/services/inputflinger/InputManager.h
+++ b/services/inputflinger/InputManager.h
@@ -26,15 +26,19 @@
#include <InputDispatcherInterface.h>
#include <InputDispatcherPolicyInterface.h>
-#include <input/ISetInputWindowsListener.h>
+#include <android/os/ISetInputWindowsListener.h>
#include <input/Input.h>
#include <input/InputTransport.h>
-#include <input/IInputFlinger.h>
+#include <android/os/BnInputFlinger.h>
+#include <android/os/IInputFlinger.h>
#include <utils/Errors.h>
-#include <utils/Vector.h>
-#include <utils/Timers.h>
#include <utils/RefBase.h>
+#include <utils/Timers.h>
+#include <utils/Vector.h>
+
+using android::os::BnInputFlinger;
+using android::os::ISetInputWindowsListener;
namespace android {
class InputChannel;
@@ -43,17 +47,19 @@
/*
* The input manager is the core of the system event processing.
*
- * The input manager has two components.
+ * The input manager has three components.
*
* 1. The InputReader class starts a thread that reads and preprocesses raw input events, applies
- * policy, and posts messages to a queue managed by the InputDispatcherThread.
- * 2. The InputDispatcher class starts a thread that waits for new events on the
- * queue and asynchronously dispatches them to applications.
+ * policy, and posts messages to a queue managed by the InputClassifier.
+ * 2. The InputClassifier class starts a thread to communicate with the device-specific
+ * classifiers. It then waits on the queue of events from InputReader, applies a classification
+ * to them, and queues them for the InputDispatcher.
+ * 3. The InputDispatcher class starts a thread that waits for new events on the
+ * previous queue and asynchronously dispatches them to applications.
*
- * By design, the InputReader class and InputDispatcher class do not share any
- * internal state. Moreover, all communication is done one way from the InputReader
- * into the InputDispatcherThread and never the reverse. Both classes may interact with the
- * InputDispatchPolicy, however.
+ * By design, none of these classes share any internal state. Moreover, all communication is
+ * done one way from the InputReader to the InputDispatcher and never the reverse. All
+ * classes may interact with the InputDispatchPolicy, however.
*
* The InputManager class never makes any calls into Java itself. Instead, the
* InputDispatchPolicy is responsible for performing all external interactions with the
@@ -74,33 +80,36 @@
/* Gets the input reader. */
virtual sp<InputReaderInterface> getReader() = 0;
+ /* Gets the input classifier */
+ virtual sp<InputClassifierInterface> getClassifier() = 0;
+
/* Gets the input dispatcher. */
virtual sp<InputDispatcherInterface> getDispatcher() = 0;
};
class InputManager : public InputManagerInterface, public BnInputFlinger {
protected:
- virtual ~InputManager();
+ ~InputManager() override;
public:
InputManager(
const sp<InputReaderPolicyInterface>& readerPolicy,
const sp<InputDispatcherPolicyInterface>& dispatcherPolicy);
- virtual status_t start();
- virtual status_t stop();
+ status_t start() override;
+ status_t stop() override;
- virtual sp<InputReaderInterface> getReader();
- virtual sp<InputClassifierInterface> getClassifier();
- virtual sp<InputDispatcherInterface> getDispatcher();
+ sp<InputReaderInterface> getReader() override;
+ sp<InputClassifierInterface> getClassifier() override;
+ sp<InputDispatcherInterface> getDispatcher() override;
- virtual void setInputWindows(const std::vector<InputWindowInfo>& handles,
- const sp<ISetInputWindowsListener>& setInputWindowsListener);
+ status_t dump(int fd, const Vector<String16>& args) override;
+ binder::Status setInputWindows(
+ const std::vector<InputWindowInfo>& handles,
+ const sp<ISetInputWindowsListener>& setInputWindowsListener) override;
- virtual void registerInputChannel(const sp<InputChannel>& channel);
- virtual void unregisterInputChannel(const sp<InputChannel>& channel);
-
- void setMotionClassifierEnabled(bool enabled);
+ binder::Status registerInputChannel(const InputChannelInfo& info) override;
+ binder::Status unregisterInputChannel(const InputChannelInfo& info) override;
private:
sp<InputReaderInterface> mReader;
diff --git a/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp b/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp
index 5a14133..7d8ab75 100644
--- a/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp
+++ b/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp
@@ -45,49 +45,45 @@
virtual ~FakeInputDispatcherPolicy() {}
private:
- virtual void notifyConfigurationChanged(nsecs_t) override {}
+ void notifyConfigurationChanged(nsecs_t) override {}
- virtual nsecs_t notifyAnr(const sp<InputApplicationHandle>&, const sp<IBinder>&,
- const std::string& name) override {
+ std::chrono::nanoseconds notifyAnr(const sp<InputApplicationHandle>&, const sp<IBinder>&,
+ const std::string& name) override {
ALOGE("The window is not responding : %s", name.c_str());
- return 0;
+ return 0s;
}
- virtual void notifyInputChannelBroken(const sp<IBinder>&) override {}
+ void notifyInputChannelBroken(const sp<IBinder>&) override {}
- virtual void notifyFocusChanged(const sp<IBinder>&, const sp<IBinder>&) override {}
+ void notifyFocusChanged(const sp<IBinder>&, const sp<IBinder>&) override {}
- virtual void getDispatcherConfiguration(InputDispatcherConfiguration* outConfig) override {
+ void getDispatcherConfiguration(InputDispatcherConfiguration* outConfig) override {
*outConfig = mConfig;
}
- virtual bool filterInputEvent(const InputEvent* inputEvent, uint32_t policyFlags) override {
+ bool filterInputEvent(const InputEvent* inputEvent, uint32_t policyFlags) override {
return true;
}
- virtual void interceptKeyBeforeQueueing(const KeyEvent*, uint32_t&) override {}
+ void interceptKeyBeforeQueueing(const KeyEvent*, uint32_t&) override {}
- virtual void interceptMotionBeforeQueueing(int32_t, nsecs_t, uint32_t&) override {}
+ void interceptMotionBeforeQueueing(int32_t, nsecs_t, uint32_t&) override {}
- virtual nsecs_t interceptKeyBeforeDispatching(const sp<IBinder>&, const KeyEvent*,
- uint32_t) override {
+ nsecs_t interceptKeyBeforeDispatching(const sp<IBinder>&, const KeyEvent*, uint32_t) override {
return 0;
}
- virtual bool dispatchUnhandledKey(const sp<IBinder>&, const KeyEvent*, uint32_t,
- KeyEvent*) override {
+ bool dispatchUnhandledKey(const sp<IBinder>&, const KeyEvent*, uint32_t, KeyEvent*) override {
return false;
}
- virtual void notifySwitch(nsecs_t, uint32_t, uint32_t, uint32_t) override {}
+ void notifySwitch(nsecs_t, uint32_t, uint32_t, uint32_t) override {}
- virtual void pokeUserActivity(nsecs_t, int32_t) override {}
+ void pokeUserActivity(nsecs_t, int32_t) override {}
- virtual bool checkInjectEventsPermissionNonReentrant(int32_t, int32_t) override {
- return false;
- }
+ bool checkInjectEventsPermissionNonReentrant(int32_t, int32_t) override { return false; }
- virtual void onPointerDownOutsideFocus(const sp<IBinder>& newToken) override {}
+ void onPointerDownOutsideFocus(const sp<IBinder>& newToken) override {}
InputDispatcherConfiguration mConfig;
};
@@ -98,7 +94,7 @@
virtual ~FakeApplicationHandle() {}
virtual bool updateInfo() {
- mInfo.dispatchingTimeout = DISPATCHING_TIMEOUT.count();
+ mInfo.dispatchingTimeout = DISPATCHING_TIMEOUT;
return true;
}
};
@@ -163,7 +159,7 @@
mInfo.name = "FakeWindowHandle";
mInfo.layoutParamsFlags = 0;
mInfo.layoutParamsType = InputWindowInfo::TYPE_APPLICATION;
- mInfo.dispatchingTimeout = DISPATCHING_TIMEOUT.count();
+ mInfo.dispatchingTimeout = DISPATCHING_TIMEOUT;
mInfo.frameLeft = mFrame.left;
mInfo.frameTop = mFrame.top;
mInfo.frameRight = mFrame.right;
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index fe016af..0fa2332 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -159,6 +159,10 @@
}
}
+static int64_t millis(std::chrono::nanoseconds t) {
+ return std::chrono::duration_cast<std::chrono::milliseconds>(t).count();
+}
+
static bool validateMotionEvent(int32_t action, int32_t actionButton, size_t pointerCount,
const PointerProperties* pointerProperties) {
if (!isValidMotionAction(action, actionButton, pointerCount)) {
@@ -1473,13 +1477,13 @@
if (focusedWindowHandle == nullptr && focusedApplicationHandle != nullptr) {
if (!mNoFocusedWindowTimeoutTime.has_value()) {
// We just discovered that there's no focused window. Start the ANR timer
- const nsecs_t timeout = focusedApplicationHandle->getDispatchingTimeout(
- DEFAULT_INPUT_DISPATCHING_TIMEOUT.count());
- mNoFocusedWindowTimeoutTime = currentTime + timeout;
+ std::chrono::nanoseconds timeout = focusedApplicationHandle->getDispatchingTimeout(
+ DEFAULT_INPUT_DISPATCHING_TIMEOUT);
+ mNoFocusedWindowTimeoutTime = currentTime + timeout.count();
mAwaitedFocusedApplication = focusedApplicationHandle;
ALOGW("Waiting because no window has focus but %s may eventually add a "
"window when it finishes starting up. Will wait for %" PRId64 "ms",
- mAwaitedFocusedApplication->getName().c_str(), ns2ms(timeout));
+ mAwaitedFocusedApplication->getName().c_str(), millis(timeout));
*nextWakeupTime = *mNoFocusedWindowTimeoutTime;
return INPUT_EVENT_INJECTION_PENDING;
} else if (currentTime > *mNoFocusedWindowTimeoutTime) {
@@ -2092,7 +2096,7 @@
// If ownerPid is the same we don't generate occlusion events as there
// is no in-process security boundary.
return false;
- } else if (otherInfo->isTrustedOverlay()) {
+ } else if (otherInfo->trustedOverlay) {
return false;
} else if (otherInfo->displayId != info->displayId) {
return false;
@@ -2109,7 +2113,7 @@
break; // All future windows are below us. Exit early.
}
const InputWindowInfo* otherInfo = otherHandle->getInfo();
- if (canBeObscuredBy(windowHandle, otherHandle) &&
+ if (canBeObscuredBy(windowHandle, otherHandle) &&
otherInfo->frameContainsPoint(x, y)) {
return true;
}
@@ -2125,7 +2129,6 @@
if (windowHandle == otherHandle) {
break; // All future windows are below us. Exit early.
}
-
const InputWindowInfo* otherInfo = otherHandle->getInfo();
if (canBeObscuredBy(windowHandle, otherHandle) &&
otherInfo->overlaps(windowInfo)) {
@@ -3865,9 +3868,8 @@
if (!mFocusedWindowHandlesByDisplay.empty()) {
ALOGE("But another display has a focused window:");
for (auto& it : mFocusedWindowHandlesByDisplay) {
- const int32_t displayId = it.first;
const sp<InputWindowHandle>& windowHandle = it.second;
- ALOGE("Display #%" PRId32 " has focused window: '%s'\n", displayId,
+ ALOGE("Display #%" PRId32 " has focused window: '%s'\n", it.first,
windowHandle->getName().c_str());
}
}
@@ -4065,13 +4067,11 @@
for (auto& it : mFocusedApplicationHandlesByDisplay) {
const int32_t displayId = it.first;
const sp<InputApplicationHandle>& applicationHandle = it.second;
+ const int64_t timeoutMillis = millis(
+ applicationHandle->getDispatchingTimeout(DEFAULT_INPUT_DISPATCHING_TIMEOUT));
dump += StringPrintf(INDENT2 "displayId=%" PRId32
", name='%s', dispatchingTimeout=%" PRId64 "ms\n",
- displayId, applicationHandle->getName().c_str(),
- ns2ms(applicationHandle
- ->getDispatchingTimeout(
- DEFAULT_INPUT_DISPATCHING_TIMEOUT)
- .count()));
+ displayId, applicationHandle->getName().c_str(), timeoutMillis);
}
} else {
dump += StringPrintf(INDENT "FocusedApplications: <none>\n");
@@ -4154,7 +4154,10 @@
dump += StringPrintf(", ownerPid=%d, ownerUid=%d, dispatchingTimeout=%" PRId64
"ms\n",
windowInfo->ownerPid, windowInfo->ownerUid,
- ns2ms(windowInfo->dispatchingTimeout));
+ millis(windowInfo->dispatchingTimeout));
+ dump += StringPrintf(INDENT4 " flags: %s\n",
+ inputWindowFlagsToString(windowInfo->layoutParamsFlags)
+ .c_str());
}
} else {
dump += INDENT2 "Windows: <none>\n";
@@ -4652,12 +4655,12 @@
commandEntry->inputChannel ? commandEntry->inputChannel->getConnectionToken() : nullptr;
mLock.unlock();
- const nsecs_t timeoutExtension =
+ const std::chrono::nanoseconds timeoutExtension =
mPolicy->notifyAnr(commandEntry->inputApplicationHandle, token, commandEntry->reason);
mLock.lock();
- if (timeoutExtension > 0) {
+ if (timeoutExtension > 0s) {
extendAnrTimeoutsLocked(commandEntry->inputApplicationHandle, token, timeoutExtension);
} else {
// stop waking up for events in this connection, it is already not responding
@@ -4671,12 +4674,12 @@
void InputDispatcher::extendAnrTimeoutsLocked(const sp<InputApplicationHandle>& application,
const sp<IBinder>& connectionToken,
- nsecs_t timeoutExtension) {
+ std::chrono::nanoseconds timeoutExtension) {
sp<Connection> connection = getConnectionLocked(connectionToken);
if (connection == nullptr) {
if (mNoFocusedWindowTimeoutTime.has_value() && application != nullptr) {
// Maybe ANR happened because there's no focused window?
- mNoFocusedWindowTimeoutTime = now() + timeoutExtension;
+ mNoFocusedWindowTimeoutTime = now() + timeoutExtension.count();
mAwaitedFocusedApplication = application;
} else {
// It's also possible that the connection already disappeared. No action necessary.
@@ -4685,10 +4688,10 @@
}
ALOGI("Raised ANR, but the policy wants to keep waiting on %s for %" PRId64 "ms longer",
- connection->inputChannel->getName().c_str(), ns2ms(timeoutExtension));
+ connection->inputChannel->getName().c_str(), millis(timeoutExtension));
connection->responsive = true;
- const nsecs_t newTimeout = now() + timeoutExtension;
+ const nsecs_t newTimeout = now() + timeoutExtension.count();
for (DispatchEntry* entry : connection->waitQueue) {
if (newTimeout >= entry->timeoutTime) {
// Already removed old entries when connection was marked unresponsive
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index e679c6b..42583bc 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -374,8 +374,8 @@
// prevent unneeded wakeups.
AnrTracker mAnrTracker GUARDED_BY(mLock);
void extendAnrTimeoutsLocked(const sp<InputApplicationHandle>& application,
- const sp<IBinder>& connectionToken, nsecs_t timeoutExtension)
- REQUIRES(mLock);
+ const sp<IBinder>& connectionToken,
+ std::chrono::nanoseconds timeoutExtension) REQUIRES(mLock);
// Contains the last window which received a hover event.
sp<InputWindowHandle> mLastHoverWindowHandle GUARDED_BY(mLock);
diff --git a/services/inputflinger/dispatcher/include/InputDispatcherInterface.h b/services/inputflinger/dispatcher/include/InputDispatcherInterface.h
index 9b002f4..f25131c 100644
--- a/services/inputflinger/dispatcher/include/InputDispatcherInterface.h
+++ b/services/inputflinger/dispatcher/include/InputDispatcherInterface.h
@@ -18,15 +18,14 @@
#define _UI_INPUT_INPUTDISPATCHER_INPUTDISPATCHERINTERFACE_H
#include <InputListener.h>
-#include <input/ISetInputWindowsListener.h>
+#include <android/os/ISetInputWindowsListener.h>
+#include <input/InputApplication.h>
+#include <input/InputTransport.h>
+#include <input/InputWindow.h>
#include <unordered_map>
namespace android {
-class InputApplicationHandle;
-class InputChannel;
-class InputWindowHandle;
-
/*
* Constants used to report the outcome of input event injection.
*/
diff --git a/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h b/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h
index 667af9b..c886bee 100644
--- a/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h
+++ b/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h
@@ -21,11 +21,11 @@
#include <binder/IBinder.h>
#include <input/Input.h>
+#include <input/InputApplication.h>
#include <utils/RefBase.h>
namespace android {
-class InputApplicationHandle;
/*
* Input dispatcher policy interface.
@@ -47,8 +47,9 @@
/* Notifies the system that an application is not responding.
* Returns a new timeout to continue waiting, or 0 to abort dispatch. */
- virtual nsecs_t notifyAnr(const sp<InputApplicationHandle>& inputApplicationHandle,
- const sp<IBinder>& token, const std::string& reason) = 0;
+ virtual std::chrono::nanoseconds notifyAnr(
+ const sp<InputApplicationHandle>& inputApplicationHandle, const sp<IBinder>& token,
+ const std::string& reason) = 0;
/* Notifies the system that an input channel is unrecoverably broken. */
virtual void notifyInputChannelBroken(const sp<IBinder>& token) = 0;
diff --git a/services/inputflinger/host/Android.bp b/services/inputflinger/host/Android.bp
index b56f356..2643c22 100644
--- a/services/inputflinger/host/Android.bp
+++ b/services/inputflinger/host/Android.bp
@@ -59,7 +59,8 @@
shared_libs: [
"libbinder",
"libinputflingerhost",
- "libutils"
+ "libutils",
+ "libinput"
],
static_libs: [
"libarect",
diff --git a/services/inputflinger/host/InputDriver.cpp b/services/inputflinger/host/InputDriver.cpp
index 683c05d..ff69800 100644
--- a/services/inputflinger/host/InputDriver.cpp
+++ b/services/inputflinger/host/InputDriver.cpp
@@ -217,8 +217,10 @@
idi.product = id->productId;
idi.version = id->version;
- std::string configFile = getInputDeviceConfigurationFilePathByDeviceIdentifier(
- idi, INPUT_DEVICE_CONFIGURATION_FILE_TYPE_CONFIGURATION);
+ std::string configFile =
+ getInputDeviceConfigurationFilePathByDeviceIdentifier(idi,
+ InputDeviceConfigurationFileType::
+ CONFIGURATION);
if (configFile.empty()) {
ALOGD("No input device configuration file found for device '%s'.",
idi.name.c_str());
diff --git a/services/inputflinger/host/InputFlinger.h b/services/inputflinger/host/InputFlinger.h
index 973b4f9..9364a2a 100644
--- a/services/inputflinger/host/InputFlinger.h
+++ b/services/inputflinger/host/InputFlinger.h
@@ -22,13 +22,17 @@
#include "InputHost.h"
+#include <android/os/BnInputFlinger.h>
+#include <android/os/ISetInputWindowsListener.h>
+#include <binder/Binder.h>
#include <cutils/compiler.h>
-#include <input/IInputFlinger.h>
-#include <input/ISetInputWindowsListener.h>
-#include <utils/String8.h>
#include <utils/String16.h>
+#include <utils/String8.h>
#include <utils/StrongPointer.h>
+using android::os::BnInputFlinger;
+using android::os::ISetInputWindowsListener;
+
namespace android {
class InputFlinger : public BnInputFlinger {
@@ -40,10 +44,12 @@
InputFlinger() ANDROID_API;
virtual status_t dump(int fd, const Vector<String16>& args);
- void setInputWindows(const std::vector<InputWindowInfo>&,
- const sp<ISetInputWindowsListener>&) {}
- void registerInputChannel(const sp<InputChannel>&) {}
- void unregisterInputChannel(const sp<InputChannel>&) {}
+ binder::Status setInputWindows(const std::vector<InputWindowInfo>&,
+ const sp<ISetInputWindowsListener>&) {
+ return binder::Status::ok();
+ }
+ binder::Status registerInputChannel(const InputChannelInfo&) { return binder::Status::ok(); }
+ binder::Status unregisterInputChannel(const InputChannelInfo&) { return binder::Status::ok(); }
private:
virtual ~InputFlinger();
diff --git a/services/inputflinger/reader/EventHub.cpp b/services/inputflinger/reader/EventHub.cpp
index a1514af..5f1d475 100644
--- a/services/inputflinger/reader/EventHub.cpp
+++ b/services/inputflinger/reader/EventHub.cpp
@@ -933,11 +933,11 @@
if (eventItem.events & EPOLLIN) {
ALOGV("awoken after wake()");
awoken = true;
- char buffer[16];
+ char wakeReadBuffer[16];
ssize_t nRead;
do {
- nRead = read(mWakeReadPipeFd, buffer, sizeof(buffer));
- } while ((nRead == -1 && errno == EINTR) || nRead == sizeof(buffer));
+ nRead = read(mWakeReadPipeFd, wakeReadBuffer, sizeof(wakeReadBuffer));
+ } while ((nRead == -1 && errno == EINTR) || nRead == sizeof(wakeReadBuffer));
} else {
ALOGW("Received unexpected epoll event 0x%08x for wake read pipe.",
eventItem.events);
@@ -1613,8 +1613,10 @@
}
void EventHub::loadConfigurationLocked(Device* device) {
- device->configurationFile = getInputDeviceConfigurationFilePathByDeviceIdentifier(
- device->identifier, INPUT_DEVICE_CONFIGURATION_FILE_TYPE_CONFIGURATION);
+ device->configurationFile =
+ getInputDeviceConfigurationFilePathByDeviceIdentifier(device->identifier,
+ InputDeviceConfigurationFileType::
+ CONFIGURATION);
if (device->configurationFile.empty()) {
ALOGD("No input device configuration file found for device '%s'.",
device->identifier.name.c_str());
diff --git a/services/inputflinger/reader/mapper/CursorInputMapper.cpp b/services/inputflinger/reader/mapper/CursorInputMapper.cpp
index 1a4d551..d1f20c7 100644
--- a/services/inputflinger/reader/mapper/CursorInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/CursorInputMapper.cpp
@@ -14,7 +14,9 @@
* limitations under the License.
*/
+// clang-format off
#include "../Macros.h"
+// clang-format on
#include "CursorInputMapper.h"
@@ -184,7 +186,7 @@
mOrientation = DISPLAY_ORIENTATION_0;
if (mParameters.orientationAware && mParameters.hasAssociatedDisplay) {
std::optional<DisplayViewport> internalViewport =
- config->getDisplayViewportByType(ViewportType::VIEWPORT_INTERNAL);
+ config->getDisplayViewportByType(ViewportType::INTERNAL);
if (internalViewport) {
mOrientation = internalViewport->orientation;
}
diff --git a/services/inputflinger/reader/mapper/JoystickInputMapper.cpp b/services/inputflinger/reader/mapper/JoystickInputMapper.cpp
index 030a846..bf81496 100644
--- a/services/inputflinger/reader/mapper/JoystickInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/JoystickInputMapper.cpp
@@ -32,8 +32,8 @@
void JoystickInputMapper::populateDeviceInfo(InputDeviceInfo* info) {
InputMapper::populateDeviceInfo(info);
- for (size_t i = 0; i < mAxes.size(); i++) {
- const Axis& axis = mAxes.valueAt(i);
+ for (std::pair<const int32_t, Axis>& pair : mAxes) {
+ const Axis& axis = pair.second;
addMotionRange(axis.axisInfo.axis, axis, info);
if (axis.axisInfo.mode == AxisInfo::MODE_SPLIT) {
@@ -72,9 +72,7 @@
dump += INDENT2 "Joystick Input Mapper:\n";
dump += INDENT3 "Axes:\n";
- size_t numAxes = mAxes.size();
- for (size_t i = 0; i < numAxes; i++) {
- const Axis& axis = mAxes.valueAt(i);
+ for (const auto& [rawAxis, axis] : mAxes) {
const char* label = getAxisLabel(axis.axisInfo.axis);
if (label) {
dump += StringPrintf(INDENT4 "%s", label);
@@ -100,7 +98,7 @@
axis.scale, axis.offset, axis.highScale, axis.highOffset);
dump += StringPrintf(INDENT4 " rawAxis=%d, rawMin=%d, rawMax=%d, "
"rawFlat=%d, rawFuzz=%d, rawResolution=%d\n",
- mAxes.keyAt(i), axis.rawAxisInfo.minValue, axis.rawAxisInfo.maxValue,
+ rawAxis, axis.rawAxisInfo.minValue, axis.rawAxisInfo.maxValue,
axis.rawAxisInfo.flat, axis.rawAxisInfo.fuzz,
axis.rawAxisInfo.resolution);
}
@@ -123,43 +121,14 @@
if (rawAxisInfo.valid) {
// Map axis.
AxisInfo axisInfo;
- bool explicitlyMapped = !getDeviceContext().mapAxis(abs, &axisInfo);
+ const bool explicitlyMapped = !getDeviceContext().mapAxis(abs, &axisInfo);
+
if (!explicitlyMapped) {
// Axis is not explicitly mapped, will choose a generic axis later.
axisInfo.mode = AxisInfo::MODE_NORMAL;
axisInfo.axis = -1;
}
-
- // Apply flat override.
- int32_t rawFlat =
- axisInfo.flatOverride < 0 ? rawAxisInfo.flat : axisInfo.flatOverride;
-
- // Calculate scaling factors and limits.
- Axis axis;
- if (axisInfo.mode == AxisInfo::MODE_SPLIT) {
- float scale = 1.0f / (axisInfo.splitValue - rawAxisInfo.minValue);
- float highScale = 1.0f / (rawAxisInfo.maxValue - axisInfo.splitValue);
- axis.initialize(rawAxisInfo, axisInfo, explicitlyMapped, scale, 0.0f, highScale,
- 0.0f, 0.0f, 1.0f, rawFlat * scale, rawAxisInfo.fuzz * scale,
- rawAxisInfo.resolution * scale);
- } else if (isCenteredAxis(axisInfo.axis)) {
- float scale = 2.0f / (rawAxisInfo.maxValue - rawAxisInfo.minValue);
- float offset = avg(rawAxisInfo.minValue, rawAxisInfo.maxValue) * -scale;
- axis.initialize(rawAxisInfo, axisInfo, explicitlyMapped, scale, offset, scale,
- offset, -1.0f, 1.0f, rawFlat * scale, rawAxisInfo.fuzz * scale,
- rawAxisInfo.resolution * scale);
- } else {
- float scale = 1.0f / (rawAxisInfo.maxValue - rawAxisInfo.minValue);
- axis.initialize(rawAxisInfo, axisInfo, explicitlyMapped, scale, 0.0f, scale,
- 0.0f, 0.0f, 1.0f, rawFlat * scale, rawAxisInfo.fuzz * scale,
- rawAxisInfo.resolution * scale);
- }
-
- // To eliminate noise while the joystick is at rest, filter out small variations
- // in axis values up front.
- axis.filter = axis.fuzz ? axis.fuzz : axis.flat * 0.25f;
-
- mAxes.add(abs, axis);
+ mAxes.insert({abs, createAxis(axisInfo, rawAxisInfo, explicitlyMapped)});
}
}
@@ -174,9 +143,8 @@
// Assign generic axis ids to remaining axes.
int32_t nextGenericAxisId = AMOTION_EVENT_AXIS_GENERIC_1;
- size_t numAxes = mAxes.size();
- for (size_t i = 0; i < numAxes; i++) {
- Axis& axis = mAxes.editValueAt(i);
+ for (auto it = mAxes.begin(); it != mAxes.end(); /*increment it inside loop*/) {
+ Axis& axis = it->second;
if (axis.axisInfo.axis < 0) {
while (nextGenericAxisId <= AMOTION_EVENT_AXIS_GENERIC_16 &&
haveAxis(nextGenericAxisId)) {
@@ -189,19 +157,57 @@
} else {
ALOGI("Ignoring joystick '%s' axis %d because all of the generic axis ids "
"have already been assigned to other axes.",
- getDeviceName().c_str(), mAxes.keyAt(i));
- mAxes.removeItemsAt(i--);
- numAxes -= 1;
+ getDeviceName().c_str(), it->first);
+ it = mAxes.erase(it);
+ continue;
}
}
+ it++;
}
}
}
+JoystickInputMapper::Axis JoystickInputMapper::createAxis(const AxisInfo& axisInfo,
+ const RawAbsoluteAxisInfo& rawAxisInfo,
+ bool explicitlyMapped) {
+ // Apply flat override.
+ int32_t rawFlat = axisInfo.flatOverride < 0 ? rawAxisInfo.flat : axisInfo.flatOverride;
+
+ float scale = std::numeric_limits<float>::signaling_NaN();
+ float highScale = std::numeric_limits<float>::signaling_NaN();
+ float highOffset = 0;
+ float offset = 0;
+ float min = 0;
+ // Calculate scaling factors and limits.
+ if (axisInfo.mode == AxisInfo::MODE_SPLIT) {
+ scale = 1.0f / (axisInfo.splitValue - rawAxisInfo.minValue);
+ highScale = 1.0f / (rawAxisInfo.maxValue - axisInfo.splitValue);
+ } else if (isCenteredAxis(axisInfo.axis)) {
+ scale = 2.0f / (rawAxisInfo.maxValue - rawAxisInfo.minValue);
+ offset = avg(rawAxisInfo.minValue, rawAxisInfo.maxValue) * -scale;
+ highOffset = offset;
+ highScale = scale;
+ min = -1.0f;
+ } else {
+ scale = 1.0f / (rawAxisInfo.maxValue - rawAxisInfo.minValue);
+ highScale = scale;
+ }
+
+ constexpr float max = 1.0;
+ const float flat = rawFlat * scale;
+ const float fuzz = rawAxisInfo.fuzz * scale;
+ const float resolution = rawAxisInfo.resolution * scale;
+
+ // To eliminate noise while the joystick is at rest, filter out small variations
+ // in axis values up front.
+ const float filter = fuzz ? fuzz : flat * 0.25f;
+ return Axis(rawAxisInfo, axisInfo, explicitlyMapped, scale, offset, highScale, highOffset, min,
+ max, flat, fuzz, resolution, filter);
+}
+
bool JoystickInputMapper::haveAxis(int32_t axisId) {
- size_t numAxes = mAxes.size();
- for (size_t i = 0; i < numAxes; i++) {
- const Axis& axis = mAxes.valueAt(i);
+ for (const std::pair<int32_t, Axis>& pair : mAxes) {
+ const Axis& axis = pair.second;
if (axis.axisInfo.axis == axisId ||
(axis.axisInfo.mode == AxisInfo::MODE_SPLIT && axis.axisInfo.highAxis == axisId)) {
return true;
@@ -211,14 +217,14 @@
}
void JoystickInputMapper::pruneAxes(bool ignoreExplicitlyMappedAxes) {
- size_t i = mAxes.size();
- while (mAxes.size() > PointerCoords::MAX_AXES && i-- > 0) {
- if (ignoreExplicitlyMappedAxes && mAxes.valueAt(i).explicitlyMapped) {
+ while (mAxes.size() > PointerCoords::MAX_AXES) {
+ auto it = mAxes.begin();
+ if (ignoreExplicitlyMappedAxes && it->second.explicitlyMapped) {
continue;
}
ALOGI("Discarding joystick '%s' axis %d because there are too many axes.",
- getDeviceName().c_str(), mAxes.keyAt(i));
- mAxes.removeItemsAt(i);
+ getDeviceName().c_str(), it->first);
+ mAxes.erase(it);
}
}
@@ -243,9 +249,8 @@
void JoystickInputMapper::reset(nsecs_t when) {
// Recenter all axes.
- size_t numAxes = mAxes.size();
- for (size_t i = 0; i < numAxes; i++) {
- Axis& axis = mAxes.editValueAt(i);
+ for (std::pair<const int32_t, Axis>& pair : mAxes) {
+ Axis& axis = pair.second;
axis.resetValue();
}
@@ -255,9 +260,9 @@
void JoystickInputMapper::process(const RawEvent* rawEvent) {
switch (rawEvent->type) {
case EV_ABS: {
- ssize_t index = mAxes.indexOfKey(rawEvent->code);
- if (index >= 0) {
- Axis& axis = mAxes.editValueAt(index);
+ auto it = mAxes.find(rawEvent->code);
+ if (it != mAxes.end()) {
+ Axis& axis = it->second;
float newValue, highNewValue;
switch (axis.axisInfo.mode) {
case AxisInfo::MODE_INVERT:
@@ -317,9 +322,8 @@
PointerCoords pointerCoords;
pointerCoords.clear();
- size_t numAxes = mAxes.size();
- for (size_t i = 0; i < numAxes; i++) {
- const Axis& axis = mAxes.valueAt(i);
+ for (std::pair<const int32_t, Axis>& pair : mAxes) {
+ const Axis& axis = pair.second;
setPointerCoordsAxisValue(&pointerCoords, axis.axisInfo.axis, axis.currentValue);
if (axis.axisInfo.mode == AxisInfo::MODE_SPLIT) {
setPointerCoordsAxisValue(&pointerCoords, axis.axisInfo.highAxis,
@@ -357,9 +361,8 @@
bool JoystickInputMapper::filterAxes(bool force) {
bool atLeastOneSignificantChange = force;
- size_t numAxes = mAxes.size();
- for (size_t i = 0; i < numAxes; i++) {
- Axis& axis = mAxes.editValueAt(i);
+ for (std::pair<const int32_t, Axis>& pair : mAxes) {
+ Axis& axis = pair.second;
if (force ||
hasValueChangedSignificantly(axis.filter, axis.newValue, axis.currentValue, axis.min,
axis.max)) {
diff --git a/services/inputflinger/reader/mapper/JoystickInputMapper.h b/services/inputflinger/reader/mapper/JoystickInputMapper.h
index 823a096..0cf60a2 100644
--- a/services/inputflinger/reader/mapper/JoystickInputMapper.h
+++ b/services/inputflinger/reader/mapper/JoystickInputMapper.h
@@ -36,6 +36,26 @@
private:
struct Axis {
+ explicit Axis(const RawAbsoluteAxisInfo& rawAxisInfo, const AxisInfo& axisInfo,
+ bool explicitlyMapped, float scale, float offset, float highScale,
+ float highOffset, float min, float max, float flat, float fuzz,
+ float resolution, float filter)
+ : rawAxisInfo(rawAxisInfo),
+ axisInfo(axisInfo),
+ explicitlyMapped(explicitlyMapped),
+ scale(scale),
+ offset(offset),
+ highScale(highScale),
+ highOffset(highOffset),
+ min(min),
+ max(max),
+ flat(flat),
+ fuzz(fuzz),
+ resolution(resolution),
+ filter(filter) {
+ resetValue();
+ }
+
RawAbsoluteAxisInfo rawAxisInfo;
AxisInfo axisInfo;
@@ -58,26 +78,6 @@
float highCurrentValue; // current value of high split
float highNewValue; // most recent value of high split
- void initialize(const RawAbsoluteAxisInfo& rawAxisInfo, const AxisInfo& axisInfo,
- bool explicitlyMapped, float scale, float offset, float highScale,
- float highOffset, float min, float max, float flat, float fuzz,
- float resolution) {
- this->rawAxisInfo = rawAxisInfo;
- this->axisInfo = axisInfo;
- this->explicitlyMapped = explicitlyMapped;
- this->scale = scale;
- this->offset = offset;
- this->highScale = highScale;
- this->highOffset = highOffset;
- this->min = min;
- this->max = max;
- this->flat = flat;
- this->fuzz = fuzz;
- this->resolution = resolution;
- this->filter = 0;
- resetValue();
- }
-
void resetValue() {
this->currentValue = 0;
this->newValue = 0;
@@ -86,8 +86,11 @@
}
};
+ static Axis createAxis(const AxisInfo& AxisInfo, const RawAbsoluteAxisInfo& rawAxisInfo,
+ bool explicitlyMapped);
+
// Axes indexed by raw ABS_* axis index.
- KeyedVector<int32_t, Axis> mAxes;
+ std::unordered_map<int32_t, Axis> mAxes;
void sync(nsecs_t when, bool force);
diff --git a/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp b/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp
index e009221..bd4232d 100644
--- a/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp
@@ -14,7 +14,9 @@
* limitations under the License.
*/
+// clang-format off
#include "../Macros.h"
+// clang-format on
#include "KeyboardInputMapper.h"
@@ -138,7 +140,7 @@
// No associated display defined, try to find default display if orientationAware.
if (mParameters.orientationAware) {
- return config->getDisplayViewportByType(ViewportType::VIEWPORT_INTERNAL);
+ return config->getDisplayViewportByType(ViewportType::INTERNAL);
}
return std::nullopt;
diff --git a/services/inputflinger/reader/mapper/MultiTouchInputMapper.h b/services/inputflinger/reader/mapper/MultiTouchInputMapper.h
index 89ef41d..190282f 100644
--- a/services/inputflinger/reader/mapper/MultiTouchInputMapper.h
+++ b/services/inputflinger/reader/mapper/MultiTouchInputMapper.h
@@ -92,15 +92,15 @@
class MultiTouchInputMapper : public TouchInputMapper {
public:
explicit MultiTouchInputMapper(InputDeviceContext& deviceContext);
- virtual ~MultiTouchInputMapper();
+ ~MultiTouchInputMapper() override;
- virtual void reset(nsecs_t when) override;
- virtual void process(const RawEvent* rawEvent) override;
+ void reset(nsecs_t when) override;
+ void process(const RawEvent* rawEvent) override;
protected:
- virtual void syncTouch(nsecs_t when, RawState* outState);
- virtual void configureRawPointerAxes();
- virtual bool hasStylus() const;
+ void syncTouch(nsecs_t when, RawState* outState) override;
+ void configureRawPointerAxes() override;
+ bool hasStylus() const override;
private:
MultiTouchMotionAccumulator mMultiTouchMotionAccumulator;
diff --git a/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.cpp b/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.cpp
index 9885889..594ff42 100644
--- a/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.cpp
@@ -14,7 +14,9 @@
* limitations under the License.
*/
+// clang-format off
#include "../Macros.h"
+// clang-format on
#include "RotaryEncoderInputMapper.h"
@@ -66,7 +68,7 @@
}
if (!changes || (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO)) {
std::optional<DisplayViewport> internalViewport =
- config->getDisplayViewportByType(ViewportType::VIEWPORT_INTERNAL);
+ config->getDisplayViewportByType(ViewportType::INTERNAL);
if (internalViewport) {
mOrientation = internalViewport->orientation;
} else {
diff --git a/services/inputflinger/reader/mapper/SingleTouchInputMapper.h b/services/inputflinger/reader/mapper/SingleTouchInputMapper.h
index f5befb3..9cb3f67 100644
--- a/services/inputflinger/reader/mapper/SingleTouchInputMapper.h
+++ b/services/inputflinger/reader/mapper/SingleTouchInputMapper.h
@@ -25,15 +25,15 @@
class SingleTouchInputMapper : public TouchInputMapper {
public:
explicit SingleTouchInputMapper(InputDeviceContext& deviceContext);
- virtual ~SingleTouchInputMapper();
+ ~SingleTouchInputMapper() override;
- virtual void reset(nsecs_t when) override;
- virtual void process(const RawEvent* rawEvent) override;
+ void reset(nsecs_t when) override;
+ void process(const RawEvent* rawEvent) override;
protected:
- virtual void syncTouch(nsecs_t when, RawState* outState);
- virtual void configureRawPointerAxes();
- virtual bool hasStylus() const;
+ void syncTouch(nsecs_t when, RawState* outState) override;
+ void configureRawPointerAxes() override;
+ bool hasStylus() const override;
private:
SingleTouchMotionAccumulator mSingleTouchMotionAccumulator;
diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.cpp b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
index efdc84f..4274ca8 100644
--- a/services/inputflinger/reader/mapper/TouchInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
@@ -14,7 +14,9 @@
* limitations under the License.
*/
+// clang-format off
#include "../Macros.h"
+// clang-format on
#include "TouchInputMapper.h"
@@ -159,7 +161,7 @@
TouchInputMapper::TouchInputMapper(InputDeviceContext& deviceContext)
: InputMapper(deviceContext),
mSource(0),
- mDeviceMode(DEVICE_MODE_DISABLED),
+ mDeviceMode(DeviceMode::DISABLED),
mRawSurfaceWidth(-1),
mRawSurfaceHeight(-1),
mSurfaceLeft(0),
@@ -179,7 +181,7 @@
void TouchInputMapper::populateDeviceInfo(InputDeviceInfo* info) {
InputMapper::populateDeviceInfo(info);
- if (mDeviceMode != DEVICE_MODE_DISABLED) {
+ if (mDeviceMode != DeviceMode::DISABLED) {
info->addMotionRange(mOrientedRanges.x);
info->addMotionRange(mOrientedRanges.y);
info->addMotionRange(mOrientedRanges.pressure);
@@ -218,7 +220,7 @@
info->addMotionRange(AMOTION_EVENT_AXIS_HSCROLL, mSource, -1.0f, 1.0f, 0.0f, 0.0f,
0.0f);
}
- if (mCalibration.coverageCalibration == Calibration::COVERAGE_CALIBRATION_BOX) {
+ if (mCalibration.coverageCalibration == Calibration::CoverageCalibration::BOX) {
const InputDeviceInfo::MotionRange& x = mOrientedRanges.x;
const InputDeviceInfo::MotionRange& y = mOrientedRanges.y;
info->addMotionRange(AMOTION_EVENT_AXIS_GENERIC_1, mSource, x.min, x.max, x.flat,
@@ -311,7 +313,7 @@
dump += INDENT3 "External Stylus State:\n";
dumpStylusState(dump, mExternalStylusState);
- if (mDeviceMode == DEVICE_MODE_POINTER) {
+ if (mDeviceMode == DeviceMode::POINTER) {
dump += StringPrintf(INDENT3 "Pointer Gesture Detector:\n");
dump += StringPrintf(INDENT4 "XMovementScale: %0.3f\n", mPointerXMovementScale);
dump += StringPrintf(INDENT4 "YMovementScale: %0.3f\n", mPointerYMovementScale);
@@ -323,15 +325,15 @@
const char* TouchInputMapper::modeToString(DeviceMode deviceMode) {
switch (deviceMode) {
- case DEVICE_MODE_DISABLED:
+ case DeviceMode::DISABLED:
return "disabled";
- case DEVICE_MODE_DIRECT:
+ case DeviceMode::DIRECT:
return "direct";
- case DEVICE_MODE_UNSCALED:
+ case DeviceMode::UNSCALED:
return "unscaled";
- case DEVICE_MODE_NAVIGATION:
+ case DeviceMode::NAVIGATION:
return "navigation";
- case DEVICE_MODE_POINTER:
+ case DeviceMode::POINTER:
return "pointer";
}
return "unknown";
@@ -406,16 +408,16 @@
// multitouch. The spot-based presentation relies on being able to accurately
// locate two or more fingers on the touch pad.
mParameters.gestureMode = getDeviceContext().hasInputProperty(INPUT_PROP_SEMI_MT)
- ? Parameters::GESTURE_MODE_SINGLE_TOUCH
- : Parameters::GESTURE_MODE_MULTI_TOUCH;
+ ? Parameters::GestureMode::SINGLE_TOUCH
+ : Parameters::GestureMode::MULTI_TOUCH;
String8 gestureModeString;
if (getDeviceContext().getConfiguration().tryGetProperty(String8("touch.gestureMode"),
gestureModeString)) {
if (gestureModeString == "single-touch") {
- mParameters.gestureMode = Parameters::GESTURE_MODE_SINGLE_TOUCH;
+ mParameters.gestureMode = Parameters::GestureMode::SINGLE_TOUCH;
} else if (gestureModeString == "multi-touch") {
- mParameters.gestureMode = Parameters::GESTURE_MODE_MULTI_TOUCH;
+ mParameters.gestureMode = Parameters::GestureMode::MULTI_TOUCH;
} else if (gestureModeString != "default") {
ALOGW("Invalid value for touch.gestureMode: '%s'", gestureModeString.string());
}
@@ -423,18 +425,18 @@
if (getDeviceContext().hasInputProperty(INPUT_PROP_DIRECT)) {
// The device is a touch screen.
- mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_SCREEN;
+ mParameters.deviceType = Parameters::DeviceType::TOUCH_SCREEN;
} else if (getDeviceContext().hasInputProperty(INPUT_PROP_POINTER)) {
// The device is a pointing device like a track pad.
- mParameters.deviceType = Parameters::DEVICE_TYPE_POINTER;
+ mParameters.deviceType = Parameters::DeviceType::POINTER;
} else if (getDeviceContext().hasRelativeAxis(REL_X) ||
getDeviceContext().hasRelativeAxis(REL_Y)) {
// The device is a cursor device with a touch pad attached.
// By default don't use the touch pad to move the pointer.
- mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_PAD;
+ mParameters.deviceType = Parameters::DeviceType::TOUCH_PAD;
} else {
// The device is a touch pad of unknown purpose.
- mParameters.deviceType = Parameters::DEVICE_TYPE_POINTER;
+ mParameters.deviceType = Parameters::DeviceType::POINTER;
}
mParameters.hasButtonUnderPad = getDeviceContext().hasInputProperty(INPUT_PROP_BUTTONPAD);
@@ -443,29 +445,29 @@
if (getDeviceContext().getConfiguration().tryGetProperty(String8("touch.deviceType"),
deviceTypeString)) {
if (deviceTypeString == "touchScreen") {
- mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_SCREEN;
+ mParameters.deviceType = Parameters::DeviceType::TOUCH_SCREEN;
} else if (deviceTypeString == "touchPad") {
- mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_PAD;
+ mParameters.deviceType = Parameters::DeviceType::TOUCH_PAD;
} else if (deviceTypeString == "touchNavigation") {
- mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_NAVIGATION;
+ mParameters.deviceType = Parameters::DeviceType::TOUCH_NAVIGATION;
} else if (deviceTypeString == "pointer") {
- mParameters.deviceType = Parameters::DEVICE_TYPE_POINTER;
+ mParameters.deviceType = Parameters::DeviceType::POINTER;
} else if (deviceTypeString != "default") {
ALOGW("Invalid value for touch.deviceType: '%s'", deviceTypeString.string());
}
}
- mParameters.orientationAware = mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN;
+ mParameters.orientationAware = mParameters.deviceType == Parameters::DeviceType::TOUCH_SCREEN;
getDeviceContext().getConfiguration().tryGetProperty(String8("touch.orientationAware"),
mParameters.orientationAware);
mParameters.hasAssociatedDisplay = false;
mParameters.associatedDisplayIsExternal = false;
if (mParameters.orientationAware ||
- mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN ||
- mParameters.deviceType == Parameters::DEVICE_TYPE_POINTER) {
+ mParameters.deviceType == Parameters::DeviceType::TOUCH_SCREEN ||
+ mParameters.deviceType == Parameters::DeviceType::POINTER) {
mParameters.hasAssociatedDisplay = true;
- if (mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN) {
+ if (mParameters.deviceType == Parameters::DeviceType::TOUCH_SCREEN) {
mParameters.associatedDisplayIsExternal = getDeviceContext().isExternal();
String8 uniqueDisplayId;
getDeviceContext().getConfiguration().tryGetProperty(String8("touch.displayId"),
@@ -488,10 +490,10 @@
dump += INDENT3 "Parameters:\n";
switch (mParameters.gestureMode) {
- case Parameters::GESTURE_MODE_SINGLE_TOUCH:
+ case Parameters::GestureMode::SINGLE_TOUCH:
dump += INDENT4 "GestureMode: single-touch\n";
break;
- case Parameters::GESTURE_MODE_MULTI_TOUCH:
+ case Parameters::GestureMode::MULTI_TOUCH:
dump += INDENT4 "GestureMode: multi-touch\n";
break;
default:
@@ -499,16 +501,16 @@
}
switch (mParameters.deviceType) {
- case Parameters::DEVICE_TYPE_TOUCH_SCREEN:
+ case Parameters::DeviceType::TOUCH_SCREEN:
dump += INDENT4 "DeviceType: touchScreen\n";
break;
- case Parameters::DEVICE_TYPE_TOUCH_PAD:
+ case Parameters::DeviceType::TOUCH_PAD:
dump += INDENT4 "DeviceType: touchPad\n";
break;
- case Parameters::DEVICE_TYPE_TOUCH_NAVIGATION:
+ case Parameters::DeviceType::TOUCH_NAVIGATION:
dump += INDENT4 "DeviceType: touchNavigation\n";
break;
- case Parameters::DEVICE_TYPE_POINTER:
+ case Parameters::DeviceType::POINTER:
dump += INDENT4 "DeviceType: pointer\n";
break;
default:
@@ -565,7 +567,7 @@
return getDeviceContext().getAssociatedViewport();
}
- if (mDeviceMode == DEVICE_MODE_POINTER) {
+ if (mDeviceMode == DeviceMode::POINTER) {
std::optional<DisplayViewport> viewport =
mConfig.getDisplayViewportById(mConfig.defaultPointerDisplayId);
if (viewport) {
@@ -583,18 +585,18 @@
ViewportType viewportTypeToUse;
if (mParameters.associatedDisplayIsExternal) {
- viewportTypeToUse = ViewportType::VIEWPORT_EXTERNAL;
+ viewportTypeToUse = ViewportType::EXTERNAL;
} else {
- viewportTypeToUse = ViewportType::VIEWPORT_INTERNAL;
+ viewportTypeToUse = ViewportType::INTERNAL;
}
std::optional<DisplayViewport> viewport =
mConfig.getDisplayViewportByType(viewportTypeToUse);
- if (!viewport && viewportTypeToUse == ViewportType::VIEWPORT_EXTERNAL) {
+ if (!viewport && viewportTypeToUse == ViewportType::EXTERNAL) {
ALOGW("Input device %s should be associated with external display, "
"fallback to internal one for the external viewport is not found.",
getDeviceName().c_str());
- viewport = mConfig.getDisplayViewportByType(ViewportType::VIEWPORT_INTERNAL);
+ viewport = mConfig.getDisplayViewportByType(ViewportType::INTERNAL);
}
return viewport;
@@ -610,34 +612,34 @@
}
void TouchInputMapper::configureSurface(nsecs_t when, bool* outResetNeeded) {
- int32_t oldDeviceMode = mDeviceMode;
+ DeviceMode oldDeviceMode = mDeviceMode;
resolveExternalStylusPresence();
// Determine device mode.
- if (mParameters.deviceType == Parameters::DEVICE_TYPE_POINTER &&
+ if (mParameters.deviceType == Parameters::DeviceType::POINTER &&
mConfig.pointerGesturesEnabled) {
mSource = AINPUT_SOURCE_MOUSE;
- mDeviceMode = DEVICE_MODE_POINTER;
+ mDeviceMode = DeviceMode::POINTER;
if (hasStylus()) {
mSource |= AINPUT_SOURCE_STYLUS;
}
- } else if (mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN &&
+ } else if (mParameters.deviceType == Parameters::DeviceType::TOUCH_SCREEN &&
mParameters.hasAssociatedDisplay) {
mSource = AINPUT_SOURCE_TOUCHSCREEN;
- mDeviceMode = DEVICE_MODE_DIRECT;
+ mDeviceMode = DeviceMode::DIRECT;
if (hasStylus()) {
mSource |= AINPUT_SOURCE_STYLUS;
}
if (hasExternalStylus()) {
mSource |= AINPUT_SOURCE_BLUETOOTH_STYLUS;
}
- } else if (mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_NAVIGATION) {
+ } else if (mParameters.deviceType == Parameters::DeviceType::TOUCH_NAVIGATION) {
mSource = AINPUT_SOURCE_TOUCH_NAVIGATION;
- mDeviceMode = DEVICE_MODE_NAVIGATION;
+ mDeviceMode = DeviceMode::NAVIGATION;
} else {
mSource = AINPUT_SOURCE_TOUCHPAD;
- mDeviceMode = DEVICE_MODE_UNSCALED;
+ mDeviceMode = DeviceMode::UNSCALED;
}
// Ensure we have valid X and Y axes.
@@ -645,7 +647,7 @@
ALOGW("Touch device '%s' did not report support for X or Y axis! "
"The device will be inoperable.",
getDeviceName().c_str());
- mDeviceMode = DEVICE_MODE_DISABLED;
+ mDeviceMode = DeviceMode::DISABLED;
return;
}
@@ -656,7 +658,7 @@
"display. The device will be inoperable until the display size "
"becomes available.",
getDeviceName().c_str());
- mDeviceMode = DEVICE_MODE_DISABLED;
+ mDeviceMode = DeviceMode::DISABLED;
return;
}
@@ -668,7 +670,7 @@
if (viewportChanged) {
mViewport = *newViewport;
- if (mDeviceMode == DEVICE_MODE_DIRECT || mDeviceMode == DEVICE_MODE_POINTER) {
+ if (mDeviceMode == DeviceMode::DIRECT || mDeviceMode == DeviceMode::POINTER) {
// Convert rotated viewport to natural surface coordinates.
int32_t naturalLogicalWidth, naturalLogicalHeight;
int32_t naturalPhysicalWidth, naturalPhysicalHeight;
@@ -759,8 +761,8 @@
}
// Create pointer controller if needed.
- if (mDeviceMode == DEVICE_MODE_POINTER ||
- (mDeviceMode == DEVICE_MODE_DIRECT && mConfig.showTouches)) {
+ if (mDeviceMode == DeviceMode::POINTER ||
+ (mDeviceMode == DeviceMode::DIRECT && mConfig.showTouches)) {
if (mPointerController == nullptr) {
mPointerController = getContext()->getPointerController(getDeviceId());
}
@@ -798,7 +800,7 @@
float diagonalSize = hypotf(mRawSurfaceWidth, mRawSurfaceHeight);
// Size factors.
- if (mCalibration.sizeCalibration != Calibration::SIZE_CALIBRATION_NONE) {
+ if (mCalibration.sizeCalibration != Calibration::SizeCalibration::NONE) {
if (mRawPointerAxes.touchMajor.valid && mRawPointerAxes.touchMajor.maxValue != 0) {
mSizeScale = 1.0f / mRawPointerAxes.touchMajor.maxValue;
} else if (mRawPointerAxes.toolMajor.valid && mRawPointerAxes.toolMajor.maxValue != 0) {
@@ -847,8 +849,8 @@
// Pressure factors.
mPressureScale = 0;
float pressureMax = 1.0;
- if (mCalibration.pressureCalibration == Calibration::PRESSURE_CALIBRATION_PHYSICAL ||
- mCalibration.pressureCalibration == Calibration::PRESSURE_CALIBRATION_AMPLITUDE) {
+ if (mCalibration.pressureCalibration == Calibration::PressureCalibration::PHYSICAL ||
+ mCalibration.pressureCalibration == Calibration::PressureCalibration::AMPLITUDE) {
if (mCalibration.havePressureScale) {
mPressureScale = mCalibration.pressureScale;
pressureMax = mPressureScale * mRawPointerAxes.pressure.maxValue;
@@ -901,9 +903,9 @@
mOrientedRanges.orientation.fuzz = 0;
mOrientedRanges.orientation.resolution = 0;
} else if (mCalibration.orientationCalibration !=
- Calibration::ORIENTATION_CALIBRATION_NONE) {
+ Calibration::OrientationCalibration::NONE) {
if (mCalibration.orientationCalibration ==
- Calibration::ORIENTATION_CALIBRATION_INTERPOLATED) {
+ Calibration::OrientationCalibration::INTERPOLATED) {
if (mRawPointerAxes.orientation.valid) {
if (mRawPointerAxes.orientation.maxValue > 0) {
mOrientationScale = M_PI_2 / mRawPointerAxes.orientation.maxValue;
@@ -928,8 +930,8 @@
// Distance
mDistanceScale = 0;
- if (mCalibration.distanceCalibration != Calibration::DISTANCE_CALIBRATION_NONE) {
- if (mCalibration.distanceCalibration == Calibration::DISTANCE_CALIBRATION_SCALED) {
+ if (mCalibration.distanceCalibration != Calibration::DistanceCalibration::NONE) {
+ if (mCalibration.distanceCalibration == Calibration::DistanceCalibration::SCALED) {
if (mCalibration.haveDistanceScale) {
mDistanceScale = mCalibration.distanceScale;
} else {
@@ -991,7 +993,7 @@
// Location
updateAffineTransformation();
- if (mDeviceMode == DEVICE_MODE_POINTER) {
+ if (mDeviceMode == DeviceMode::POINTER) {
// Compute pointer gesture detection parameters.
float rawDiagonal = hypotf(rawWidth, rawHeight);
float displayDiagonal = hypotf(mRawSurfaceWidth, mRawSurfaceHeight);
@@ -1112,19 +1114,19 @@
Calibration& out = mCalibration;
// Size
- out.sizeCalibration = Calibration::SIZE_CALIBRATION_DEFAULT;
+ out.sizeCalibration = Calibration::SizeCalibration::DEFAULT;
String8 sizeCalibrationString;
if (in.tryGetProperty(String8("touch.size.calibration"), sizeCalibrationString)) {
if (sizeCalibrationString == "none") {
- out.sizeCalibration = Calibration::SIZE_CALIBRATION_NONE;
+ out.sizeCalibration = Calibration::SizeCalibration::NONE;
} else if (sizeCalibrationString == "geometric") {
- out.sizeCalibration = Calibration::SIZE_CALIBRATION_GEOMETRIC;
+ out.sizeCalibration = Calibration::SizeCalibration::GEOMETRIC;
} else if (sizeCalibrationString == "diameter") {
- out.sizeCalibration = Calibration::SIZE_CALIBRATION_DIAMETER;
+ out.sizeCalibration = Calibration::SizeCalibration::DIAMETER;
} else if (sizeCalibrationString == "box") {
- out.sizeCalibration = Calibration::SIZE_CALIBRATION_BOX;
+ out.sizeCalibration = Calibration::SizeCalibration::BOX;
} else if (sizeCalibrationString == "area") {
- out.sizeCalibration = Calibration::SIZE_CALIBRATION_AREA;
+ out.sizeCalibration = Calibration::SizeCalibration::AREA;
} else if (sizeCalibrationString != "default") {
ALOGW("Invalid value for touch.size.calibration: '%s'", sizeCalibrationString.string());
}
@@ -1135,15 +1137,15 @@
out.haveSizeIsSummed = in.tryGetProperty(String8("touch.size.isSummed"), out.sizeIsSummed);
// Pressure
- out.pressureCalibration = Calibration::PRESSURE_CALIBRATION_DEFAULT;
+ out.pressureCalibration = Calibration::PressureCalibration::DEFAULT;
String8 pressureCalibrationString;
if (in.tryGetProperty(String8("touch.pressure.calibration"), pressureCalibrationString)) {
if (pressureCalibrationString == "none") {
- out.pressureCalibration = Calibration::PRESSURE_CALIBRATION_NONE;
+ out.pressureCalibration = Calibration::PressureCalibration::NONE;
} else if (pressureCalibrationString == "physical") {
- out.pressureCalibration = Calibration::PRESSURE_CALIBRATION_PHYSICAL;
+ out.pressureCalibration = Calibration::PressureCalibration::PHYSICAL;
} else if (pressureCalibrationString == "amplitude") {
- out.pressureCalibration = Calibration::PRESSURE_CALIBRATION_AMPLITUDE;
+ out.pressureCalibration = Calibration::PressureCalibration::AMPLITUDE;
} else if (pressureCalibrationString != "default") {
ALOGW("Invalid value for touch.pressure.calibration: '%s'",
pressureCalibrationString.string());
@@ -1153,15 +1155,15 @@
out.havePressureScale = in.tryGetProperty(String8("touch.pressure.scale"), out.pressureScale);
// Orientation
- out.orientationCalibration = Calibration::ORIENTATION_CALIBRATION_DEFAULT;
+ out.orientationCalibration = Calibration::OrientationCalibration::DEFAULT;
String8 orientationCalibrationString;
if (in.tryGetProperty(String8("touch.orientation.calibration"), orientationCalibrationString)) {
if (orientationCalibrationString == "none") {
- out.orientationCalibration = Calibration::ORIENTATION_CALIBRATION_NONE;
+ out.orientationCalibration = Calibration::OrientationCalibration::NONE;
} else if (orientationCalibrationString == "interpolated") {
- out.orientationCalibration = Calibration::ORIENTATION_CALIBRATION_INTERPOLATED;
+ out.orientationCalibration = Calibration::OrientationCalibration::INTERPOLATED;
} else if (orientationCalibrationString == "vector") {
- out.orientationCalibration = Calibration::ORIENTATION_CALIBRATION_VECTOR;
+ out.orientationCalibration = Calibration::OrientationCalibration::VECTOR;
} else if (orientationCalibrationString != "default") {
ALOGW("Invalid value for touch.orientation.calibration: '%s'",
orientationCalibrationString.string());
@@ -1169,13 +1171,13 @@
}
// Distance
- out.distanceCalibration = Calibration::DISTANCE_CALIBRATION_DEFAULT;
+ out.distanceCalibration = Calibration::DistanceCalibration::DEFAULT;
String8 distanceCalibrationString;
if (in.tryGetProperty(String8("touch.distance.calibration"), distanceCalibrationString)) {
if (distanceCalibrationString == "none") {
- out.distanceCalibration = Calibration::DISTANCE_CALIBRATION_NONE;
+ out.distanceCalibration = Calibration::DistanceCalibration::NONE;
} else if (distanceCalibrationString == "scaled") {
- out.distanceCalibration = Calibration::DISTANCE_CALIBRATION_SCALED;
+ out.distanceCalibration = Calibration::DistanceCalibration::SCALED;
} else if (distanceCalibrationString != "default") {
ALOGW("Invalid value for touch.distance.calibration: '%s'",
distanceCalibrationString.string());
@@ -1184,13 +1186,13 @@
out.haveDistanceScale = in.tryGetProperty(String8("touch.distance.scale"), out.distanceScale);
- out.coverageCalibration = Calibration::COVERAGE_CALIBRATION_DEFAULT;
+ out.coverageCalibration = Calibration::CoverageCalibration::DEFAULT;
String8 coverageCalibrationString;
if (in.tryGetProperty(String8("touch.coverage.calibration"), coverageCalibrationString)) {
if (coverageCalibrationString == "none") {
- out.coverageCalibration = Calibration::COVERAGE_CALIBRATION_NONE;
+ out.coverageCalibration = Calibration::CoverageCalibration::NONE;
} else if (coverageCalibrationString == "box") {
- out.coverageCalibration = Calibration::COVERAGE_CALIBRATION_BOX;
+ out.coverageCalibration = Calibration::CoverageCalibration::BOX;
} else if (coverageCalibrationString != "default") {
ALOGW("Invalid value for touch.coverage.calibration: '%s'",
coverageCalibrationString.string());
@@ -1201,43 +1203,43 @@
void TouchInputMapper::resolveCalibration() {
// Size
if (mRawPointerAxes.touchMajor.valid || mRawPointerAxes.toolMajor.valid) {
- if (mCalibration.sizeCalibration == Calibration::SIZE_CALIBRATION_DEFAULT) {
- mCalibration.sizeCalibration = Calibration::SIZE_CALIBRATION_GEOMETRIC;
+ if (mCalibration.sizeCalibration == Calibration::SizeCalibration::DEFAULT) {
+ mCalibration.sizeCalibration = Calibration::SizeCalibration::GEOMETRIC;
}
} else {
- mCalibration.sizeCalibration = Calibration::SIZE_CALIBRATION_NONE;
+ mCalibration.sizeCalibration = Calibration::SizeCalibration::NONE;
}
// Pressure
if (mRawPointerAxes.pressure.valid) {
- if (mCalibration.pressureCalibration == Calibration::PRESSURE_CALIBRATION_DEFAULT) {
- mCalibration.pressureCalibration = Calibration::PRESSURE_CALIBRATION_PHYSICAL;
+ if (mCalibration.pressureCalibration == Calibration::PressureCalibration::DEFAULT) {
+ mCalibration.pressureCalibration = Calibration::PressureCalibration::PHYSICAL;
}
} else {
- mCalibration.pressureCalibration = Calibration::PRESSURE_CALIBRATION_NONE;
+ mCalibration.pressureCalibration = Calibration::PressureCalibration::NONE;
}
// Orientation
if (mRawPointerAxes.orientation.valid) {
- if (mCalibration.orientationCalibration == Calibration::ORIENTATION_CALIBRATION_DEFAULT) {
- mCalibration.orientationCalibration = Calibration::ORIENTATION_CALIBRATION_INTERPOLATED;
+ if (mCalibration.orientationCalibration == Calibration::OrientationCalibration::DEFAULT) {
+ mCalibration.orientationCalibration = Calibration::OrientationCalibration::INTERPOLATED;
}
} else {
- mCalibration.orientationCalibration = Calibration::ORIENTATION_CALIBRATION_NONE;
+ mCalibration.orientationCalibration = Calibration::OrientationCalibration::NONE;
}
// Distance
if (mRawPointerAxes.distance.valid) {
- if (mCalibration.distanceCalibration == Calibration::DISTANCE_CALIBRATION_DEFAULT) {
- mCalibration.distanceCalibration = Calibration::DISTANCE_CALIBRATION_SCALED;
+ if (mCalibration.distanceCalibration == Calibration::DistanceCalibration::DEFAULT) {
+ mCalibration.distanceCalibration = Calibration::DistanceCalibration::SCALED;
}
} else {
- mCalibration.distanceCalibration = Calibration::DISTANCE_CALIBRATION_NONE;
+ mCalibration.distanceCalibration = Calibration::DistanceCalibration::NONE;
}
// Coverage
- if (mCalibration.coverageCalibration == Calibration::COVERAGE_CALIBRATION_DEFAULT) {
- mCalibration.coverageCalibration = Calibration::COVERAGE_CALIBRATION_NONE;
+ if (mCalibration.coverageCalibration == Calibration::CoverageCalibration::DEFAULT) {
+ mCalibration.coverageCalibration = Calibration::CoverageCalibration::NONE;
}
}
@@ -1246,19 +1248,19 @@
// Size
switch (mCalibration.sizeCalibration) {
- case Calibration::SIZE_CALIBRATION_NONE:
+ case Calibration::SizeCalibration::NONE:
dump += INDENT4 "touch.size.calibration: none\n";
break;
- case Calibration::SIZE_CALIBRATION_GEOMETRIC:
+ case Calibration::SizeCalibration::GEOMETRIC:
dump += INDENT4 "touch.size.calibration: geometric\n";
break;
- case Calibration::SIZE_CALIBRATION_DIAMETER:
+ case Calibration::SizeCalibration::DIAMETER:
dump += INDENT4 "touch.size.calibration: diameter\n";
break;
- case Calibration::SIZE_CALIBRATION_BOX:
+ case Calibration::SizeCalibration::BOX:
dump += INDENT4 "touch.size.calibration: box\n";
break;
- case Calibration::SIZE_CALIBRATION_AREA:
+ case Calibration::SizeCalibration::AREA:
dump += INDENT4 "touch.size.calibration: area\n";
break;
default:
@@ -1280,13 +1282,13 @@
// Pressure
switch (mCalibration.pressureCalibration) {
- case Calibration::PRESSURE_CALIBRATION_NONE:
+ case Calibration::PressureCalibration::NONE:
dump += INDENT4 "touch.pressure.calibration: none\n";
break;
- case Calibration::PRESSURE_CALIBRATION_PHYSICAL:
+ case Calibration::PressureCalibration::PHYSICAL:
dump += INDENT4 "touch.pressure.calibration: physical\n";
break;
- case Calibration::PRESSURE_CALIBRATION_AMPLITUDE:
+ case Calibration::PressureCalibration::AMPLITUDE:
dump += INDENT4 "touch.pressure.calibration: amplitude\n";
break;
default:
@@ -1299,13 +1301,13 @@
// Orientation
switch (mCalibration.orientationCalibration) {
- case Calibration::ORIENTATION_CALIBRATION_NONE:
+ case Calibration::OrientationCalibration::NONE:
dump += INDENT4 "touch.orientation.calibration: none\n";
break;
- case Calibration::ORIENTATION_CALIBRATION_INTERPOLATED:
+ case Calibration::OrientationCalibration::INTERPOLATED:
dump += INDENT4 "touch.orientation.calibration: interpolated\n";
break;
- case Calibration::ORIENTATION_CALIBRATION_VECTOR:
+ case Calibration::OrientationCalibration::VECTOR:
dump += INDENT4 "touch.orientation.calibration: vector\n";
break;
default:
@@ -1314,10 +1316,10 @@
// Distance
switch (mCalibration.distanceCalibration) {
- case Calibration::DISTANCE_CALIBRATION_NONE:
+ case Calibration::DistanceCalibration::NONE:
dump += INDENT4 "touch.distance.calibration: none\n";
break;
- case Calibration::DISTANCE_CALIBRATION_SCALED:
+ case Calibration::DistanceCalibration::SCALED:
dump += INDENT4 "touch.distance.calibration: scaled\n";
break;
default:
@@ -1329,10 +1331,10 @@
}
switch (mCalibration.coverageCalibration) {
- case Calibration::COVERAGE_CALIBRATION_NONE:
+ case Calibration::CoverageCalibration::NONE:
dump += INDENT4 "touch.coverage.calibration: none\n";
break;
- case Calibration::COVERAGE_CALIBRATION_BOX:
+ case Calibration::CoverageCalibration::BOX:
dump += INDENT4 "touch.coverage.calibration: box\n";
break;
default:
@@ -1370,7 +1372,7 @@
mCurrentCookedState.clear();
mLastRawState.clear();
mLastCookedState.clear();
- mPointerUsage = POINTER_USAGE_NONE;
+ mPointerUsage = PointerUsage::NONE;
mSentHoverEnter = false;
mHavePointerIds = false;
mCurrentMotionAborted = false;
@@ -1452,7 +1454,7 @@
}
void TouchInputMapper::processRawTouches(bool timeout) {
- if (mDeviceMode == DEVICE_MODE_DISABLED) {
+ if (mDeviceMode == DeviceMode::DISABLED) {
// Drop all input if the device is disabled.
mCurrentRawState.clear();
mRawStatesPending.clear();
@@ -1517,7 +1519,7 @@
bool buttonsPressed = mCurrentRawState.buttonState & ~mLastRawState.buttonState;
if (initialDown || buttonsPressed) {
// If this is a touch screen, hide the pointer on an initial down.
- if (mDeviceMode == DEVICE_MODE_DIRECT) {
+ if (mDeviceMode == DeviceMode::DIRECT) {
getContext()->fadePointer();
}
@@ -1546,7 +1548,7 @@
mCurrentCookedState.buttonState);
// Dispatch the touches either directly or by translation through a pointer on screen.
- if (mDeviceMode == DEVICE_MODE_POINTER) {
+ if (mDeviceMode == DeviceMode::POINTER) {
for (BitSet32 idBits(mCurrentRawState.rawPointerData.touchingIdBits); !idBits.isEmpty();) {
uint32_t id = idBits.clearFirstMarkedBit();
const RawPointerData::Pointer& pointer =
@@ -1576,18 +1578,18 @@
if (!mCurrentCookedState.stylusIdBits.isEmpty()) {
mCurrentCookedState.mouseIdBits.clear();
mCurrentCookedState.fingerIdBits.clear();
- pointerUsage = POINTER_USAGE_STYLUS;
+ pointerUsage = PointerUsage::STYLUS;
} else if (!mCurrentCookedState.mouseIdBits.isEmpty()) {
mCurrentCookedState.fingerIdBits.clear();
- pointerUsage = POINTER_USAGE_MOUSE;
+ pointerUsage = PointerUsage::MOUSE;
} else if (!mCurrentCookedState.fingerIdBits.isEmpty() ||
isPointerDown(mCurrentRawState.buttonState)) {
- pointerUsage = POINTER_USAGE_GESTURES;
+ pointerUsage = PointerUsage::GESTURES;
}
dispatchPointerUsage(when, policyFlags, pointerUsage);
} else {
- if (mDeviceMode == DEVICE_MODE_DIRECT && mConfig.showTouches &&
+ if (mDeviceMode == DeviceMode::DIRECT && mConfig.showTouches &&
mPointerController != nullptr) {
mPointerController->setPresentation(PointerControllerInterface::Presentation::SPOT);
mPointerController->fade(PointerControllerInterface::Transition::GRADUAL);
@@ -1627,7 +1629,7 @@
}
void TouchInputMapper::applyExternalStylusButtonState(nsecs_t when) {
- if (mDeviceMode == DEVICE_MODE_DIRECT && hasExternalStylus() && mExternalStylusId != -1) {
+ if (mDeviceMode == DeviceMode::DIRECT && hasExternalStylus() && mExternalStylusId != -1) {
mCurrentRawState.buttonState |= mExternalStylusState.buttons;
}
}
@@ -1654,7 +1656,7 @@
}
bool TouchInputMapper::assignExternalStylusId(const RawState& state, bool timeout) {
- if (mDeviceMode != DEVICE_MODE_DIRECT || !hasExternalStylus()) {
+ if (mDeviceMode != DeviceMode::DIRECT || !hasExternalStylus()) {
return false;
}
@@ -1697,11 +1699,11 @@
}
void TouchInputMapper::timeoutExpired(nsecs_t when) {
- if (mDeviceMode == DEVICE_MODE_POINTER) {
- if (mPointerUsage == POINTER_USAGE_GESTURES) {
+ if (mDeviceMode == DeviceMode::POINTER) {
+ if (mPointerUsage == PointerUsage::GESTURES) {
dispatchPointerGestures(when, 0 /*policyFlags*/, true /*isTimeout*/);
}
- } else if (mDeviceMode == DEVICE_MODE_DIRECT) {
+ } else if (mDeviceMode == DeviceMode::DIRECT) {
if (mExternalStylusFusionTimeout < when) {
processRawTouches(true /*timeout*/);
} else if (mExternalStylusFusionTimeout != LLONG_MAX) {
@@ -2038,10 +2040,10 @@
// Size
float touchMajor, touchMinor, toolMajor, toolMinor, size;
switch (mCalibration.sizeCalibration) {
- case Calibration::SIZE_CALIBRATION_GEOMETRIC:
- case Calibration::SIZE_CALIBRATION_DIAMETER:
- case Calibration::SIZE_CALIBRATION_BOX:
- case Calibration::SIZE_CALIBRATION_AREA:
+ case Calibration::SizeCalibration::GEOMETRIC:
+ case Calibration::SizeCalibration::DIAMETER:
+ case Calibration::SizeCalibration::BOX:
+ case Calibration::SizeCalibration::AREA:
if (mRawPointerAxes.touchMajor.valid && mRawPointerAxes.toolMajor.valid) {
touchMajor = in.touchMajor;
touchMinor = mRawPointerAxes.touchMinor.valid ? in.touchMinor : in.touchMajor;
@@ -2083,17 +2085,17 @@
}
}
- if (mCalibration.sizeCalibration == Calibration::SIZE_CALIBRATION_GEOMETRIC) {
+ if (mCalibration.sizeCalibration == Calibration::SizeCalibration::GEOMETRIC) {
touchMajor *= mGeometricScale;
touchMinor *= mGeometricScale;
toolMajor *= mGeometricScale;
toolMinor *= mGeometricScale;
- } else if (mCalibration.sizeCalibration == Calibration::SIZE_CALIBRATION_AREA) {
+ } else if (mCalibration.sizeCalibration == Calibration::SizeCalibration::AREA) {
touchMajor = touchMajor > 0 ? sqrtf(touchMajor) : 0;
touchMinor = touchMajor;
toolMajor = toolMajor > 0 ? sqrtf(toolMajor) : 0;
toolMinor = toolMajor;
- } else if (mCalibration.sizeCalibration == Calibration::SIZE_CALIBRATION_DIAMETER) {
+ } else if (mCalibration.sizeCalibration == Calibration::SizeCalibration::DIAMETER) {
touchMinor = touchMajor;
toolMinor = toolMajor;
}
@@ -2116,8 +2118,8 @@
// Pressure
float pressure;
switch (mCalibration.pressureCalibration) {
- case Calibration::PRESSURE_CALIBRATION_PHYSICAL:
- case Calibration::PRESSURE_CALIBRATION_AMPLITUDE:
+ case Calibration::PressureCalibration::PHYSICAL:
+ case Calibration::PressureCalibration::AMPLITUDE:
pressure = in.pressure * mPressureScale;
break;
default:
@@ -2137,10 +2139,10 @@
tilt = 0;
switch (mCalibration.orientationCalibration) {
- case Calibration::ORIENTATION_CALIBRATION_INTERPOLATED:
+ case Calibration::OrientationCalibration::INTERPOLATED:
orientation = in.orientation * mOrientationScale;
break;
- case Calibration::ORIENTATION_CALIBRATION_VECTOR: {
+ case Calibration::OrientationCalibration::VECTOR: {
int32_t c1 = signExtendNybble((in.orientation & 0xf0) >> 4);
int32_t c2 = signExtendNybble(in.orientation & 0x0f);
if (c1 != 0 || c2 != 0) {
@@ -2164,7 +2166,7 @@
// Distance
float distance;
switch (mCalibration.distanceCalibration) {
- case Calibration::DISTANCE_CALIBRATION_SCALED:
+ case Calibration::DistanceCalibration::SCALED:
distance = in.distance * mDistanceScale;
break;
default:
@@ -2174,7 +2176,7 @@
// Coverage
int32_t rawLeft, rawTop, rawRight, rawBottom;
switch (mCalibration.coverageCalibration) {
- case Calibration::COVERAGE_CALIBRATION_BOX:
+ case Calibration::CoverageCalibration::BOX:
rawLeft = (in.toolMinor & 0xffff0000) >> 16;
rawRight = in.toolMinor & 0x0000ffff;
rawBottom = in.toolMajor & 0x0000ffff;
@@ -2251,7 +2253,7 @@
out.setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, orientation);
out.setAxisValue(AMOTION_EVENT_AXIS_TILT, tilt);
out.setAxisValue(AMOTION_EVENT_AXIS_DISTANCE, distance);
- if (mCalibration.coverageCalibration == Calibration::COVERAGE_CALIBRATION_BOX) {
+ if (mCalibration.coverageCalibration == Calibration::CoverageCalibration::BOX) {
out.setAxisValue(AMOTION_EVENT_AXIS_GENERIC_1, left);
out.setAxisValue(AMOTION_EVENT_AXIS_GENERIC_2, top);
out.setAxisValue(AMOTION_EVENT_AXIS_GENERIC_3, right);
@@ -2281,36 +2283,36 @@
}
switch (mPointerUsage) {
- case POINTER_USAGE_GESTURES:
+ case PointerUsage::GESTURES:
dispatchPointerGestures(when, policyFlags, false /*isTimeout*/);
break;
- case POINTER_USAGE_STYLUS:
+ case PointerUsage::STYLUS:
dispatchPointerStylus(when, policyFlags);
break;
- case POINTER_USAGE_MOUSE:
+ case PointerUsage::MOUSE:
dispatchPointerMouse(when, policyFlags);
break;
- default:
+ case PointerUsage::NONE:
break;
}
}
void TouchInputMapper::abortPointerUsage(nsecs_t when, uint32_t policyFlags) {
switch (mPointerUsage) {
- case POINTER_USAGE_GESTURES:
+ case PointerUsage::GESTURES:
abortPointerGestures(when, policyFlags);
break;
- case POINTER_USAGE_STYLUS:
+ case PointerUsage::STYLUS:
abortPointerStylus(when, policyFlags);
break;
- case POINTER_USAGE_MOUSE:
+ case PointerUsage::MOUSE:
abortPointerMouse(when, policyFlags);
break;
- default:
+ case PointerUsage::NONE:
break;
}
- mPointerUsage = POINTER_USAGE_NONE;
+ mPointerUsage = PointerUsage::NONE;
}
void TouchInputMapper::dispatchPointerGestures(nsecs_t when, uint32_t policyFlags, bool isTimeout) {
@@ -2326,13 +2328,13 @@
}
// Update the pointer presentation and spots.
- if (mParameters.gestureMode == Parameters::GESTURE_MODE_MULTI_TOUCH) {
+ if (mParameters.gestureMode == Parameters::GestureMode::MULTI_TOUCH) {
mPointerController->setPresentation(PointerControllerInterface::Presentation::POINTER);
if (finishPreviousGesture || cancelPreviousGesture) {
mPointerController->clearSpots();
}
- if (mPointerGesture.currentGestureMode == PointerGesture::FREEFORM) {
+ if (mPointerGesture.currentGestureMode == PointerGesture::Mode::FREEFORM) {
mPointerController->setSpots(mPointerGesture.currentGestureCoords,
mPointerGesture.currentGestureIdToIndex,
mPointerGesture.currentGestureIdBits,
@@ -2344,28 +2346,28 @@
// Show or hide the pointer if needed.
switch (mPointerGesture.currentGestureMode) {
- case PointerGesture::NEUTRAL:
- case PointerGesture::QUIET:
- if (mParameters.gestureMode == Parameters::GESTURE_MODE_MULTI_TOUCH &&
- mPointerGesture.lastGestureMode == PointerGesture::FREEFORM) {
+ case PointerGesture::Mode::NEUTRAL:
+ case PointerGesture::Mode::QUIET:
+ if (mParameters.gestureMode == Parameters::GestureMode::MULTI_TOUCH &&
+ mPointerGesture.lastGestureMode == PointerGesture::Mode::FREEFORM) {
// Remind the user of where the pointer is after finishing a gesture with spots.
mPointerController->unfade(PointerControllerInterface::Transition::GRADUAL);
}
break;
- case PointerGesture::TAP:
- case PointerGesture::TAP_DRAG:
- case PointerGesture::BUTTON_CLICK_OR_DRAG:
- case PointerGesture::HOVER:
- case PointerGesture::PRESS:
- case PointerGesture::SWIPE:
+ case PointerGesture::Mode::TAP:
+ case PointerGesture::Mode::TAP_DRAG:
+ case PointerGesture::Mode::BUTTON_CLICK_OR_DRAG:
+ case PointerGesture::Mode::HOVER:
+ case PointerGesture::Mode::PRESS:
+ case PointerGesture::Mode::SWIPE:
// Unfade the pointer when the current gesture manipulates the
// area directly under the pointer.
mPointerController->unfade(PointerControllerInterface::Transition::IMMEDIATE);
break;
- case PointerGesture::FREEFORM:
+ case PointerGesture::Mode::FREEFORM:
// Fade the pointer when the current gesture manipulates a different
// area and there are spots to guide the user experience.
- if (mParameters.gestureMode == Parameters::GESTURE_MODE_MULTI_TOUCH) {
+ if (mParameters.gestureMode == Parameters::GestureMode::MULTI_TOUCH) {
mPointerController->fade(PointerControllerInterface::Transition::GRADUAL);
} else {
mPointerController->unfade(PointerControllerInterface::Transition::IMMEDIATE);
@@ -2379,12 +2381,12 @@
// Update last coordinates of pointers that have moved so that we observe the new
// pointer positions at the same time as other pointers that have just gone up.
- bool down = mPointerGesture.currentGestureMode == PointerGesture::TAP ||
- mPointerGesture.currentGestureMode == PointerGesture::TAP_DRAG ||
- mPointerGesture.currentGestureMode == PointerGesture::BUTTON_CLICK_OR_DRAG ||
- mPointerGesture.currentGestureMode == PointerGesture::PRESS ||
- mPointerGesture.currentGestureMode == PointerGesture::SWIPE ||
- mPointerGesture.currentGestureMode == PointerGesture::FREEFORM;
+ bool down = mPointerGesture.currentGestureMode == PointerGesture::Mode::TAP ||
+ mPointerGesture.currentGestureMode == PointerGesture::Mode::TAP_DRAG ||
+ mPointerGesture.currentGestureMode == PointerGesture::Mode::BUTTON_CLICK_OR_DRAG ||
+ mPointerGesture.currentGestureMode == PointerGesture::Mode::PRESS ||
+ mPointerGesture.currentGestureMode == PointerGesture::Mode::SWIPE ||
+ mPointerGesture.currentGestureMode == PointerGesture::Mode::FREEFORM;
bool moveNeeded = false;
if (down && !cancelPreviousGesture && !finishPreviousGesture &&
!mPointerGesture.lastGestureIdBits.isEmpty() &&
@@ -2467,7 +2469,7 @@
}
// Send motion events for hover.
- if (mPointerGesture.currentGestureMode == PointerGesture::HOVER) {
+ if (mPointerGesture.currentGestureMode == PointerGesture::Mode::HOVER) {
dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, metaState,
buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
mPointerGesture.currentGestureProperties,
@@ -2553,7 +2555,7 @@
ALOGD("Gestures: Processing timeout");
#endif
- if (mPointerGesture.lastGestureMode == PointerGesture::TAP) {
+ if (mPointerGesture.lastGestureMode == PointerGesture::Mode::TAP) {
if (when <= mPointerGesture.tapUpTime + mConfig.pointerGestureTapDragInterval) {
// The tap/drag timeout has not yet expired.
getContext()->requestTimeoutAtTime(mPointerGesture.tapUpTime +
@@ -2566,7 +2568,7 @@
*outFinishPreviousGesture = true;
mPointerGesture.activeGestureId = -1;
- mPointerGesture.currentGestureMode = PointerGesture::NEUTRAL;
+ mPointerGesture.currentGestureMode = PointerGesture::Mode::NEUTRAL;
mPointerGesture.currentGestureIdBits.clear();
mPointerVelocityControl.reset();
@@ -2598,9 +2600,9 @@
// If the gesture ever enters a mode other than TAP, HOVER or TAP_DRAG, without first returning
// to NEUTRAL, then we should not generate tap event.
- if (mPointerGesture.lastGestureMode != PointerGesture::HOVER &&
- mPointerGesture.lastGestureMode != PointerGesture::TAP &&
- mPointerGesture.lastGestureMode != PointerGesture::TAP_DRAG) {
+ if (mPointerGesture.lastGestureMode != PointerGesture::Mode::HOVER &&
+ mPointerGesture.lastGestureMode != PointerGesture::Mode::TAP &&
+ mPointerGesture.lastGestureMode != PointerGesture::Mode::TAP_DRAG) {
mPointerGesture.resetTap();
}
@@ -2633,15 +2635,16 @@
} else {
isQuietTime = when < mPointerGesture.quietTime + mConfig.pointerGestureQuietInterval;
if (!isQuietTime) {
- if ((mPointerGesture.lastGestureMode == PointerGesture::PRESS ||
- mPointerGesture.lastGestureMode == PointerGesture::SWIPE ||
- mPointerGesture.lastGestureMode == PointerGesture::FREEFORM) &&
+ if ((mPointerGesture.lastGestureMode == PointerGesture::Mode::PRESS ||
+ mPointerGesture.lastGestureMode == PointerGesture::Mode::SWIPE ||
+ mPointerGesture.lastGestureMode == PointerGesture::Mode::FREEFORM) &&
currentFingerCount < 2) {
// Enter quiet time when exiting swipe or freeform state.
// This is to prevent accidentally entering the hover state and flinging the
// pointer when finishing a swipe and there is still one pointer left onscreen.
isQuietTime = true;
- } else if (mPointerGesture.lastGestureMode == PointerGesture::BUTTON_CLICK_OR_DRAG &&
+ } else if (mPointerGesture.lastGestureMode ==
+ PointerGesture::Mode::BUTTON_CLICK_OR_DRAG &&
currentFingerCount >= 2 && !isPointerDown(mCurrentRawState.buttonState)) {
// Enter quiet time when releasing the button and there are still two or more
// fingers down. This may indicate that one finger was used to press the button
@@ -2661,12 +2664,12 @@
ALOGD("Gestures: QUIET for next %0.3fms",
(mPointerGesture.quietTime + mConfig.pointerGestureQuietInterval - when) * 0.000001f);
#endif
- if (mPointerGesture.lastGestureMode != PointerGesture::QUIET) {
+ if (mPointerGesture.lastGestureMode != PointerGesture::Mode::QUIET) {
*outFinishPreviousGesture = true;
}
mPointerGesture.activeGestureId = -1;
- mPointerGesture.currentGestureMode = PointerGesture::QUIET;
+ mPointerGesture.currentGestureMode = PointerGesture::Mode::QUIET;
mPointerGesture.currentGestureIdBits.clear();
mPointerVelocityControl.reset();
@@ -2690,7 +2693,7 @@
activeTouchId, currentFingerCount);
#endif
// Reset state when just starting.
- if (mPointerGesture.lastGestureMode != PointerGesture::BUTTON_CLICK_OR_DRAG) {
+ if (mPointerGesture.lastGestureMode != PointerGesture::Mode::BUTTON_CLICK_OR_DRAG) {
*outFinishPreviousGesture = true;
mPointerGesture.activeGestureId = 0;
}
@@ -2744,7 +2747,7 @@
float x, y;
mPointerController->getPosition(&x, &y);
- mPointerGesture.currentGestureMode = PointerGesture::BUTTON_CLICK_OR_DRAG;
+ mPointerGesture.currentGestureMode = PointerGesture::Mode::BUTTON_CLICK_OR_DRAG;
mPointerGesture.currentGestureIdBits.clear();
mPointerGesture.currentGestureIdBits.markBit(mPointerGesture.activeGestureId);
mPointerGesture.currentGestureIdToIndex[mPointerGesture.activeGestureId] = 0;
@@ -2757,15 +2760,15 @@
mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 1.0f);
} else if (currentFingerCount == 0) {
// Case 3. No fingers down and button is not pressed. (NEUTRAL)
- if (mPointerGesture.lastGestureMode != PointerGesture::NEUTRAL) {
+ if (mPointerGesture.lastGestureMode != PointerGesture::Mode::NEUTRAL) {
*outFinishPreviousGesture = true;
}
// Watch for taps coming out of HOVER or TAP_DRAG mode.
// Checking for taps after TAP_DRAG allows us to detect double-taps.
bool tapped = false;
- if ((mPointerGesture.lastGestureMode == PointerGesture::HOVER ||
- mPointerGesture.lastGestureMode == PointerGesture::TAP_DRAG) &&
+ if ((mPointerGesture.lastGestureMode == PointerGesture::Mode::HOVER ||
+ mPointerGesture.lastGestureMode == PointerGesture::Mode::TAP_DRAG) &&
lastFingerCount == 1) {
if (when <= mPointerGesture.tapDownTime + mConfig.pointerGestureTapInterval) {
float x, y;
@@ -2781,7 +2784,7 @@
mConfig.pointerGestureTapDragInterval);
mPointerGesture.activeGestureId = 0;
- mPointerGesture.currentGestureMode = PointerGesture::TAP;
+ mPointerGesture.currentGestureMode = PointerGesture::Mode::TAP;
mPointerGesture.currentGestureIdBits.clear();
mPointerGesture.currentGestureIdBits.markBit(mPointerGesture.activeGestureId);
mPointerGesture.currentGestureIdToIndex[mPointerGesture.activeGestureId] = 0;
@@ -2824,7 +2827,7 @@
ALOGD("Gestures: NEUTRAL");
#endif
mPointerGesture.activeGestureId = -1;
- mPointerGesture.currentGestureMode = PointerGesture::NEUTRAL;
+ mPointerGesture.currentGestureMode = PointerGesture::Mode::NEUTRAL;
mPointerGesture.currentGestureIdBits.clear();
}
} else if (currentFingerCount == 1) {
@@ -2834,14 +2837,14 @@
// When in TAP_DRAG, emit MOVE events at the pointer location.
ALOG_ASSERT(activeTouchId >= 0);
- mPointerGesture.currentGestureMode = PointerGesture::HOVER;
- if (mPointerGesture.lastGestureMode == PointerGesture::TAP) {
+ mPointerGesture.currentGestureMode = PointerGesture::Mode::HOVER;
+ if (mPointerGesture.lastGestureMode == PointerGesture::Mode::TAP) {
if (when <= mPointerGesture.tapUpTime + mConfig.pointerGestureTapDragInterval) {
float x, y;
mPointerController->getPosition(&x, &y);
if (fabs(x - mPointerGesture.tapX) <= mConfig.pointerGestureTapSlop &&
fabs(y - mPointerGesture.tapY) <= mConfig.pointerGestureTapSlop) {
- mPointerGesture.currentGestureMode = PointerGesture::TAP_DRAG;
+ mPointerGesture.currentGestureMode = PointerGesture::Mode::TAP_DRAG;
} else {
#if DEBUG_GESTURES
ALOGD("Gestures: Not a TAP_DRAG, deltaX=%f, deltaY=%f",
@@ -2854,8 +2857,8 @@
(when - mPointerGesture.tapUpTime) * 0.000001f);
#endif
}
- } else if (mPointerGesture.lastGestureMode == PointerGesture::TAP_DRAG) {
- mPointerGesture.currentGestureMode = PointerGesture::TAP_DRAG;
+ } else if (mPointerGesture.lastGestureMode == PointerGesture::Mode::TAP_DRAG) {
+ mPointerGesture.currentGestureMode = PointerGesture::Mode::TAP_DRAG;
}
float deltaX = 0, deltaY = 0;
@@ -2878,7 +2881,7 @@
}
bool down;
- if (mPointerGesture.currentGestureMode == PointerGesture::TAP_DRAG) {
+ if (mPointerGesture.currentGestureMode == PointerGesture::Mode::TAP_DRAG) {
#if DEBUG_GESTURES
ALOGD("Gestures: TAP_DRAG");
#endif
@@ -2887,7 +2890,7 @@
#if DEBUG_GESTURES
ALOGD("Gestures: HOVER");
#endif
- if (mPointerGesture.lastGestureMode != PointerGesture::HOVER) {
+ if (mPointerGesture.lastGestureMode != PointerGesture::Mode::HOVER) {
*outFinishPreviousGesture = true;
}
mPointerGesture.activeGestureId = 0;
@@ -2933,9 +2936,9 @@
bool settled = when >=
mPointerGesture.firstTouchTime + mConfig.pointerGestureMultitouchSettleInterval;
- if (mPointerGesture.lastGestureMode != PointerGesture::PRESS &&
- mPointerGesture.lastGestureMode != PointerGesture::SWIPE &&
- mPointerGesture.lastGestureMode != PointerGesture::FREEFORM) {
+ if (mPointerGesture.lastGestureMode != PointerGesture::Mode::PRESS &&
+ mPointerGesture.lastGestureMode != PointerGesture::Mode::SWIPE &&
+ mPointerGesture.lastGestureMode != PointerGesture::Mode::FREEFORM) {
*outFinishPreviousGesture = true;
} else if (!settled && currentFingerCount > lastFingerCount) {
// Additional pointers have gone down but not yet settled.
@@ -2953,7 +2956,7 @@
}
if (*outFinishPreviousGesture || *outCancelPreviousGesture) {
- mPointerGesture.currentGestureMode = PointerGesture::PRESS;
+ mPointerGesture.currentGestureMode = PointerGesture::Mode::PRESS;
mPointerGesture.activeGestureId = 0;
mPointerGesture.referenceIdBits.clear();
mPointerVelocityControl.reset();
@@ -3005,7 +3008,7 @@
}
// Consider transitions from PRESS to SWIPE or MULTITOUCH.
- if (mPointerGesture.currentGestureMode == PointerGesture::PRESS) {
+ if (mPointerGesture.currentGestureMode == PointerGesture::Mode::PRESS) {
float dist[MAX_POINTER_ID + 1];
int32_t distOverThreshold = 0;
for (BitSet32 idBits(mPointerGesture.referenceIdBits); !idBits.isEmpty();) {
@@ -3027,7 +3030,7 @@
currentFingerCount);
#endif
*outCancelPreviousGesture = true;
- mPointerGesture.currentGestureMode = PointerGesture::FREEFORM;
+ mPointerGesture.currentGestureMode = PointerGesture::Mode::FREEFORM;
} else {
// There are exactly two pointers.
BitSet32 idBits(mCurrentCookedState.fingerIdBits);
@@ -3046,7 +3049,7 @@
mutualDistance, mPointerGestureMaxSwipeWidth);
#endif
*outCancelPreviousGesture = true;
- mPointerGesture.currentGestureMode = PointerGesture::FREEFORM;
+ mPointerGesture.currentGestureMode = PointerGesture::Mode::FREEFORM;
} else {
// There are two pointers. Wait for both pointers to start moving
// before deciding whether this is a SWIPE or FREEFORM gesture.
@@ -3077,7 +3080,7 @@
mConfig.pointerGestureMultitouchMinDistance, cosine,
mConfig.pointerGestureSwipeTransitionAngleCosine);
#endif
- mPointerGesture.currentGestureMode = PointerGesture::SWIPE;
+ mPointerGesture.currentGestureMode = PointerGesture::Mode::SWIPE;
} else {
// Pointers are moving in different directions. Switch to FREEFORM.
#if DEBUG_GESTURES
@@ -3089,13 +3092,13 @@
mConfig.pointerGestureSwipeTransitionAngleCosine);
#endif
*outCancelPreviousGesture = true;
- mPointerGesture.currentGestureMode = PointerGesture::FREEFORM;
+ mPointerGesture.currentGestureMode = PointerGesture::Mode::FREEFORM;
}
}
}
}
}
- } else if (mPointerGesture.currentGestureMode == PointerGesture::SWIPE) {
+ } else if (mPointerGesture.currentGestureMode == PointerGesture::Mode::SWIPE) {
// Switch from SWIPE to FREEFORM if additional pointers go down.
// Cancel previous gesture.
if (currentFingerCount > 2) {
@@ -3104,13 +3107,13 @@
currentFingerCount);
#endif
*outCancelPreviousGesture = true;
- mPointerGesture.currentGestureMode = PointerGesture::FREEFORM;
+ mPointerGesture.currentGestureMode = PointerGesture::Mode::FREEFORM;
}
}
// Move the reference points based on the overall group motion of the fingers
// except in PRESS mode while waiting for a transition to occur.
- if (mPointerGesture.currentGestureMode != PointerGesture::PRESS &&
+ if (mPointerGesture.currentGestureMode != PointerGesture::Mode::PRESS &&
(commonDeltaX || commonDeltaY)) {
for (BitSet32 idBits(mPointerGesture.referenceIdBits); !idBits.isEmpty();) {
uint32_t id = idBits.clearFirstMarkedBit();
@@ -3133,8 +3136,8 @@
}
// Report gestures.
- if (mPointerGesture.currentGestureMode == PointerGesture::PRESS ||
- mPointerGesture.currentGestureMode == PointerGesture::SWIPE) {
+ if (mPointerGesture.currentGestureMode == PointerGesture::Mode::PRESS ||
+ mPointerGesture.currentGestureMode == PointerGesture::Mode::SWIPE) {
// PRESS or SWIPE mode.
#if DEBUG_GESTURES
ALOGD("Gestures: PRESS or SWIPE activeTouchId=%d,"
@@ -3155,7 +3158,7 @@
mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y,
mPointerGesture.referenceGestureY);
mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 1.0f);
- } else if (mPointerGesture.currentGestureMode == PointerGesture::FREEFORM) {
+ } else if (mPointerGesture.currentGestureMode == PointerGesture::Mode::FREEFORM) {
// FREEFORM mode.
#if DEBUG_GESTURES
ALOGD("Gestures: FREEFORM activeTouchId=%d,"
@@ -3168,7 +3171,7 @@
BitSet32 mappedTouchIdBits;
BitSet32 usedGestureIdBits;
- if (mPointerGesture.lastGestureMode != PointerGesture::FREEFORM) {
+ if (mPointerGesture.lastGestureMode != PointerGesture::Mode::FREEFORM) {
// Initially, assign the active gesture id to the active touch point
// if there is one. No other touch id bits are mapped yet.
if (!*outCancelPreviousGesture) {
@@ -3568,7 +3571,7 @@
}
float xCursorPosition = AMOTION_EVENT_INVALID_CURSOR_POSITION;
float yCursorPosition = AMOTION_EVENT_INVALID_CURSOR_POSITION;
- if (mDeviceMode == DEVICE_MODE_POINTER) {
+ if (mDeviceMode == DeviceMode::POINTER) {
mPointerController->getPosition(&xCursorPosition, &yCursorPosition);
}
const int32_t displayId = getAssociatedDisplayId().value_or(ADISPLAY_ID_NONE);
@@ -3907,7 +3910,7 @@
std::optional<int32_t> TouchInputMapper::getAssociatedDisplayId() {
if (mParameters.hasAssociatedDisplay) {
- if (mDeviceMode == DEVICE_MODE_POINTER) {
+ if (mDeviceMode == DeviceMode::POINTER) {
return std::make_optional(mPointerController->getDisplayId());
} else {
return std::make_optional(mViewport.displayId);
diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.h b/services/inputflinger/reader/mapper/TouchInputMapper.h
index 7f811a0..d437e01 100644
--- a/services/inputflinger/reader/mapper/TouchInputMapper.h
+++ b/services/inputflinger/reader/mapper/TouchInputMapper.h
@@ -17,6 +17,8 @@
#ifndef _UI_INPUTREADER_TOUCH_INPUT_MAPPER_H
#define _UI_INPUTREADER_TOUCH_INPUT_MAPPER_H
+#include <stdint.h>
+
#include "CursorButtonAccumulator.h"
#include "CursorScrollAccumulator.h"
#include "EventHub.h"
@@ -24,8 +26,6 @@
#include "InputReaderBase.h"
#include "TouchButtonAccumulator.h"
-#include <stdint.h>
-
namespace android {
/* Raw axis information from the driver. */
@@ -133,25 +133,24 @@
class TouchInputMapper : public InputMapper {
public:
explicit TouchInputMapper(InputDeviceContext& deviceContext);
- virtual ~TouchInputMapper();
+ ~TouchInputMapper() override;
- virtual uint32_t getSources() override;
- virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo) override;
- virtual void dump(std::string& dump) override;
- virtual void configure(nsecs_t when, const InputReaderConfiguration* config,
- uint32_t changes) override;
- virtual void reset(nsecs_t when) override;
- virtual void process(const RawEvent* rawEvent) override;
+ uint32_t getSources() override;
+ void populateDeviceInfo(InputDeviceInfo* deviceInfo) override;
+ void dump(std::string& dump) override;
+ void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes) override;
+ void reset(nsecs_t when) override;
+ void process(const RawEvent* rawEvent) override;
- virtual int32_t getKeyCodeState(uint32_t sourceMask, int32_t keyCode) override;
- virtual int32_t getScanCodeState(uint32_t sourceMask, int32_t scanCode) override;
- virtual bool markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes,
- const int32_t* keyCodes, uint8_t* outFlags) override;
+ int32_t getKeyCodeState(uint32_t sourceMask, int32_t keyCode) override;
+ int32_t getScanCodeState(uint32_t sourceMask, int32_t scanCode) override;
+ bool markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes, const int32_t* keyCodes,
+ uint8_t* outFlags) override;
- virtual void cancelTouch(nsecs_t when) override;
- virtual void timeoutExpired(nsecs_t when) override;
- virtual void updateExternalStylusState(const StylusState& state) override;
- virtual std::optional<int32_t> getAssociatedDisplayId() override;
+ void cancelTouch(nsecs_t when) override;
+ void timeoutExpired(nsecs_t when) override;
+ void updateExternalStylusState(const StylusState& state) override;
+ std::optional<int32_t> getAssociatedDisplayId() override;
protected:
CursorButtonAccumulator mCursorButtonAccumulator;
@@ -177,12 +176,12 @@
// Input sources and device mode.
uint32_t mSource;
- enum DeviceMode {
- DEVICE_MODE_DISABLED, // input is disabled
- DEVICE_MODE_DIRECT, // direct mapping (touchscreen)
- DEVICE_MODE_UNSCALED, // unscaled mapping (touchpad)
- DEVICE_MODE_NAVIGATION, // unscaled mapping with assist gesture (touch navigation)
- DEVICE_MODE_POINTER, // pointer mapping (pointer)
+ enum class DeviceMode {
+ DISABLED, // input is disabled
+ DIRECT, // direct mapping (touchscreen)
+ UNSCALED, // unscaled mapping (touchpad)
+ NAVIGATION, // unscaled mapping with assist gesture (touch navigation)
+ POINTER, // pointer mapping (pointer)
};
DeviceMode mDeviceMode;
@@ -191,11 +190,11 @@
// Immutable configuration parameters.
struct Parameters {
- enum DeviceType {
- DEVICE_TYPE_TOUCH_SCREEN,
- DEVICE_TYPE_TOUCH_PAD,
- DEVICE_TYPE_TOUCH_NAVIGATION,
- DEVICE_TYPE_POINTER,
+ enum class DeviceType {
+ TOUCH_SCREEN,
+ TOUCH_PAD,
+ TOUCH_NAVIGATION,
+ POINTER,
};
DeviceType deviceType;
@@ -205,9 +204,9 @@
bool hasButtonUnderPad;
std::string uniqueDisplayId;
- enum GestureMode {
- GESTURE_MODE_SINGLE_TOUCH,
- GESTURE_MODE_MULTI_TOUCH,
+ enum class GestureMode {
+ SINGLE_TOUCH,
+ MULTI_TOUCH,
};
GestureMode gestureMode;
@@ -217,13 +216,13 @@
// Immutable calibration parameters in parsed form.
struct Calibration {
// Size
- enum SizeCalibration {
- SIZE_CALIBRATION_DEFAULT,
- SIZE_CALIBRATION_NONE,
- SIZE_CALIBRATION_GEOMETRIC,
- SIZE_CALIBRATION_DIAMETER,
- SIZE_CALIBRATION_BOX,
- SIZE_CALIBRATION_AREA,
+ enum class SizeCalibration {
+ DEFAULT,
+ NONE,
+ GEOMETRIC,
+ DIAMETER,
+ BOX,
+ AREA,
};
SizeCalibration sizeCalibration;
@@ -236,11 +235,11 @@
bool sizeIsSummed;
// Pressure
- enum PressureCalibration {
- PRESSURE_CALIBRATION_DEFAULT,
- PRESSURE_CALIBRATION_NONE,
- PRESSURE_CALIBRATION_PHYSICAL,
- PRESSURE_CALIBRATION_AMPLITUDE,
+ enum class PressureCalibration {
+ DEFAULT,
+ NONE,
+ PHYSICAL,
+ AMPLITUDE,
};
PressureCalibration pressureCalibration;
@@ -248,30 +247,30 @@
float pressureScale;
// Orientation
- enum OrientationCalibration {
- ORIENTATION_CALIBRATION_DEFAULT,
- ORIENTATION_CALIBRATION_NONE,
- ORIENTATION_CALIBRATION_INTERPOLATED,
- ORIENTATION_CALIBRATION_VECTOR,
+ enum class OrientationCalibration {
+ DEFAULT,
+ NONE,
+ INTERPOLATED,
+ VECTOR,
};
OrientationCalibration orientationCalibration;
// Distance
- enum DistanceCalibration {
- DISTANCE_CALIBRATION_DEFAULT,
- DISTANCE_CALIBRATION_NONE,
- DISTANCE_CALIBRATION_SCALED,
+ enum class DistanceCalibration {
+ DEFAULT,
+ NONE,
+ SCALED,
};
DistanceCalibration distanceCalibration;
bool haveDistanceScale;
float distanceScale;
- enum CoverageCalibration {
- COVERAGE_CALIBRATION_DEFAULT,
- COVERAGE_CALIBRATION_NONE,
- COVERAGE_CALIBRATION_BOX,
+ enum class CoverageCalibration {
+ DEFAULT,
+ NONE,
+ BOX,
};
CoverageCalibration coverageCalibration;
@@ -524,16 +523,16 @@
uint64_t distance : 48; // squared distance
};
- enum PointerUsage {
- POINTER_USAGE_NONE,
- POINTER_USAGE_GESTURES,
- POINTER_USAGE_STYLUS,
- POINTER_USAGE_MOUSE,
+ enum class PointerUsage {
+ NONE,
+ GESTURES,
+ STYLUS,
+ MOUSE,
};
PointerUsage mPointerUsage;
struct PointerGesture {
- enum Mode {
+ enum class Mode {
// No fingers, button is not pressed.
// Nothing happening.
NEUTRAL,
@@ -646,9 +645,9 @@
firstTouchTime = LLONG_MIN;
activeTouchId = -1;
activeGestureId = -1;
- currentGestureMode = NEUTRAL;
+ currentGestureMode = Mode::NEUTRAL;
currentGestureIdBits.clear();
- lastGestureMode = NEUTRAL;
+ lastGestureMode = Mode::NEUTRAL;
lastGestureIdBits.clear();
downTime = 0;
velocityTracker.clear();
diff --git a/services/inputflinger/tests/Android.bp b/services/inputflinger/tests/Android.bp
index a0d2f4f..eae0963 100644
--- a/services/inputflinger/tests/Android.bp
+++ b/services/inputflinger/tests/Android.bp
@@ -35,7 +35,14 @@
"InputClassifierConverter_test.cpp",
"InputDispatcher_test.cpp",
"InputReader_test.cpp",
+ "InputFlingerService_test.cpp",
"UinputDevice.cpp",
+ "IInputFlingerQuery.aidl"
],
+ aidl: {
+ include_dirs: [
+ "frameworks/native/libs/input",
+ ],
+ },
require_root: true,
}
diff --git a/services/inputflinger/tests/IInputFlingerQuery.aidl b/services/inputflinger/tests/IInputFlingerQuery.aidl
new file mode 100644
index 0000000..1edc089
--- /dev/null
+++ b/services/inputflinger/tests/IInputFlingerQuery.aidl
@@ -0,0 +1,27 @@
+/**
+ * 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.
+ */
+
+import android.InputChannelInfo;
+import android.InputWindowInfo;
+import android.os.ISetInputWindowsListener;
+
+/** @hide */
+interface IInputFlingerQuery
+{
+ /* Test interfaces */
+ void getInputWindows(out InputWindowInfo[] inputHandles);
+ void getInputChannels(out InputChannelInfo[] infos);
+}
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index 1a133dc..cf5a3ab 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -198,13 +198,14 @@
mConfigurationChangedTime = when;
}
- virtual nsecs_t notifyAnr(const sp<InputApplicationHandle>& application,
- const sp<IBinder>& windowToken, const std::string&) override {
+ std::chrono::nanoseconds notifyAnr(const sp<InputApplicationHandle>& application,
+ const sp<IBinder>& windowToken,
+ const std::string&) override {
std::scoped_lock lock(mLock);
mAnrApplications.push(application);
mAnrWindowTokens.push(windowToken);
mNotifyAnr.notify_all();
- return mAnrTimeout.count();
+ return mAnrTimeout;
}
virtual void notifyInputChannelBroken(const sp<IBinder>&) override {}
@@ -585,7 +586,7 @@
FakeApplicationHandle() {
mInfo.name = "Fake Application";
mInfo.token = new BBinder();
- mInfo.dispatchingTimeout = DISPATCHING_TIMEOUT.count();
+ mInfo.dispatchingTimeout = DISPATCHING_TIMEOUT;
}
virtual ~FakeApplicationHandle() {}
@@ -594,7 +595,7 @@
}
void setDispatchingTimeout(std::chrono::nanoseconds timeout) {
- mInfo.dispatchingTimeout = timeout.count();
+ mInfo.dispatchingTimeout = timeout;
}
};
@@ -767,7 +768,7 @@
mInfo.name = name;
mInfo.layoutParamsFlags = 0;
mInfo.layoutParamsType = InputWindowInfo::TYPE_APPLICATION;
- mInfo.dispatchingTimeout = DISPATCHING_TIMEOUT.count();
+ mInfo.dispatchingTimeout = DISPATCHING_TIMEOUT;
mInfo.frameLeft = 0;
mInfo.frameTop = 0;
mInfo.frameRight = WIDTH;
@@ -791,7 +792,7 @@
void setFocus(bool hasFocus) { mInfo.hasFocus = hasFocus; }
void setDispatchingTimeout(std::chrono::nanoseconds timeout) {
- mInfo.dispatchingTimeout = timeout.count();
+ mInfo.dispatchingTimeout = timeout;
}
void setPaused(bool paused) { mInfo.paused = paused; }
@@ -2368,7 +2369,7 @@
mWindow =
new FakeWindowHandle(mApplication, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT);
mWindow->setFrame(Rect(0, 0, 30, 30));
- mWindow->setDispatchingTimeout(10ms);
+ mWindow->setDispatchingTimeout(30ms);
mWindow->setFocus(true);
// Adding FLAG_NOT_TOUCH_MODAL to ensure taps outside this window are not sent to this
// window.
@@ -2760,7 +2761,7 @@
mFocusedWindow =
new FakeWindowHandle(mApplication, mDispatcher, "Focused", ADISPLAY_ID_DEFAULT);
- mFocusedWindow->setDispatchingTimeout(10ms);
+ mFocusedWindow->setDispatchingTimeout(30ms);
mFocusedWindow->setFrame(Rect(50, 50, 100, 100));
mFocusedWindow->setLayoutParamFlags(InputWindowInfo::FLAG_NOT_TOUCH_MODAL |
InputWindowInfo::FLAG_SPLIT_TOUCH);
diff --git a/services/inputflinger/tests/InputFlingerService_test.cpp b/services/inputflinger/tests/InputFlingerService_test.cpp
new file mode 100644
index 0000000..fd3f562
--- /dev/null
+++ b/services/inputflinger/tests/InputFlingerService_test.cpp
@@ -0,0 +1,408 @@
+/*
+ * 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 <BnInputFlingerQuery.h>
+#include <IInputFlingerQuery.h>
+
+#include <android/os/BnInputFlinger.h>
+#include <android/os/BnSetInputWindowsListener.h>
+#include <android/os/IInputFlinger.h>
+#include <android/os/ISetInputWindowsListener.h>
+
+#include <binder/Binder.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/Parcel.h>
+#include <binder/ProcessState.h>
+
+#include <input/Input.h>
+#include <input/InputTransport.h>
+#include <input/InputWindow.h>
+
+#include <gtest/gtest.h>
+#include <inttypes.h>
+#include <linux/uinput.h>
+#include <log/log.h>
+#include <ui/Rect.h>
+#include <ui/Region.h>
+#include <chrono>
+#include <thread>
+#include <unordered_map>
+
+#define TAG "InputFlingerServiceTest"
+
+using android::os::BnInputFlinger;
+using android::os::BnSetInputWindowsListener;
+using android::os::IInputFlinger;
+using android::os::ISetInputWindowsListener;
+
+using std::chrono_literals::operator""ms;
+using std::chrono_literals::operator""s;
+
+namespace android {
+
+static const sp<IBinder> TestInfoToken = new BBinder();
+static constexpr int32_t TestInfoId = 1;
+static const std::string TestInfoName = "InputFlingerServiceTestInputWindowInfo";
+static constexpr int32_t TestInfoLayoutParamsFlags = 0xABCD;
+static constexpr int32_t TestInfoLayoutParamsType = 39;
+static constexpr std::chrono::duration TestInfoDispatchingTimeout = 2532ms;
+static constexpr int32_t TestInfoFrameLeft = 93;
+static constexpr int32_t TestInfoFrameTop = 34;
+static constexpr int32_t TestInfoFrameRight = 16;
+static constexpr int32_t TestInfoFrameBottom = 19;
+static constexpr int32_t TestInfoSurfaceInset = 17;
+static constexpr float TestInfoGlobalScaleFactor = 0.3;
+static constexpr float TestInfoWindowXScale = 0.4;
+static constexpr float TestInfoWindowYScale = 0.5;
+static const Rect TestInfoTouchableRegionRect = {100 /* left */, 150 /* top */, 400 /* right */,
+ 450 /* bottom */};
+static const Region TestInfoTouchableRegion(TestInfoTouchableRegionRect);
+static constexpr bool TestInfoVisible = false;
+static constexpr bool TestInfoCanReceiveKeys = false;
+static constexpr bool TestInfoTrustedOverlay = true;
+static constexpr bool TestInfoHasFocus = false;
+static constexpr bool TestInfoHasWallpaper = false;
+static constexpr bool TestInfoPaused = false;
+static constexpr int32_t TestInfoOwnerPid = 19;
+static constexpr int32_t TestInfoOwnerUid = 24;
+static constexpr int32_t TestInfoInputFeatures = 29;
+static constexpr int32_t TestInfoDisplayId = 34;
+static constexpr int32_t TestInfoPortalToDisplayId = 2;
+static constexpr bool TestInfoReplaceTouchableRegionWithCrop = true;
+static const sp<IBinder> TestInfoTouchableRegionCropHandle = new BBinder();
+
+static const std::string TestAppInfoName = "InputFlingerServiceTestInputApplicationInfo";
+static const sp<IBinder> TestAppInfoToken = new BBinder();
+static constexpr std::chrono::duration TestAppInfoDispatchingTimeout = 12345678ms;
+
+static const String16 kTestServiceName = String16("InputFlingerService");
+static const String16 kQueryServiceName = String16("InputFlingerQueryService");
+
+struct SetInputWindowsListener;
+// --- InputFlingerServiceTest ---
+class InputFlingerServiceTest : public testing::Test {
+public:
+ void SetUp() override;
+ void TearDown() override;
+
+protected:
+ void InitializeInputFlinger();
+ void setInputWindowsByInfos(std::vector<InputWindowInfo>& infos);
+
+ void setInputWindowsFinished();
+ void verifyInputWindowInfo(const InputWindowInfo& info) const;
+ InputWindowInfo& getInfo() const { return const_cast<InputWindowInfo&>(mInfo); }
+
+ sp<IInputFlinger> mService;
+ sp<IInputFlingerQuery> mQuery;
+
+private:
+ sp<SetInputWindowsListener> mSetInputWindowsListener;
+ sp<InputChannel> mServerChannel, mClientChannel;
+ InputWindowInfo mInfo;
+ std::mutex mLock;
+ std::condition_variable mSetInputWindowsFinishedCondition;
+};
+
+struct SetInputWindowsListener : BnSetInputWindowsListener {
+ explicit SetInputWindowsListener(std::function<void()> cbFunc) : mCbFunc(cbFunc) {}
+
+ binder::Status onSetInputWindowsFinished() override;
+
+ std::function<void()> mCbFunc;
+};
+
+class TestInputManager : public BnInputFlinger {
+protected:
+ virtual ~TestInputManager(){};
+
+public:
+ TestInputManager(){};
+ void checkFdFlags(const android::base::unique_fd& fd);
+
+ binder::Status getInputWindows(std::vector<::android::InputWindowInfo>* inputHandles);
+ binder::Status getInputChannels(std::vector<::android::InputChannelInfo>* infos);
+
+ status_t dump(int fd, const Vector<String16>& args) override;
+
+ binder::Status setInputWindows(
+ const std::vector<InputWindowInfo>& handles,
+ const sp<ISetInputWindowsListener>& setInputWindowsListener) override;
+
+ binder::Status registerInputChannel(const InputChannelInfo& channel) override;
+ binder::Status unregisterInputChannel(const InputChannelInfo& channel) override;
+
+private:
+ mutable Mutex mLock;
+ std::unordered_map<int32_t, std::vector<sp<InputWindowHandle>>> mHandlesPerDisplay;
+ std::vector<sp<InputChannel>> mInputChannels;
+};
+
+class TestInputQuery : public BnInputFlingerQuery {
+public:
+ TestInputQuery(sp<android::TestInputManager> manager) : mManager(manager){};
+ binder::Status getInputWindows(std::vector<::android::InputWindowInfo>* inputHandles) override;
+ binder::Status getInputChannels(std::vector<::android::InputChannelInfo>* infos) override;
+
+private:
+ sp<android::TestInputManager> mManager;
+};
+
+binder::Status TestInputQuery::getInputWindows(
+ std::vector<::android::InputWindowInfo>* inputHandles) {
+ return mManager->getInputWindows(inputHandles);
+}
+
+binder::Status TestInputQuery::getInputChannels(std::vector<::android::InputChannelInfo>* infos) {
+ return mManager->getInputChannels(infos);
+}
+
+binder::Status SetInputWindowsListener::onSetInputWindowsFinished() {
+ if (mCbFunc != nullptr) {
+ mCbFunc();
+ }
+ return binder::Status::ok();
+}
+
+binder::Status TestInputManager::setInputWindows(
+ const std::vector<InputWindowInfo>& infos,
+ const sp<ISetInputWindowsListener>& setInputWindowsListener) {
+ AutoMutex _l(mLock);
+
+ for (const auto& info : infos) {
+ mHandlesPerDisplay.emplace(info.displayId, std::vector<sp<InputWindowHandle>>());
+ mHandlesPerDisplay[info.displayId].push_back(new InputWindowHandle(info));
+ }
+ if (setInputWindowsListener) {
+ setInputWindowsListener->onSetInputWindowsFinished();
+ }
+ return binder::Status::ok();
+}
+
+void TestInputManager::checkFdFlags(const android::base::unique_fd& fd) {
+ const int result = fcntl(fd, F_GETFL);
+ EXPECT_NE(result, -1);
+ EXPECT_EQ(result & O_NONBLOCK, O_NONBLOCK);
+}
+
+binder::Status TestInputManager::registerInputChannel(const InputChannelInfo& info) {
+ AutoMutex _l(mLock);
+ // check Fd flags
+ checkFdFlags(info.mFd);
+
+ android::base::unique_fd newFd(::dup(info.mFd));
+ sp<InputChannel> channel = InputChannel::create(info.mName, std::move(newFd), info.mToken);
+ mInputChannels.push_back(channel);
+
+ return binder::Status::ok();
+}
+
+binder::Status TestInputManager::unregisterInputChannel(const InputChannelInfo& info) {
+ AutoMutex _l(mLock);
+ // check Fd flags
+ checkFdFlags(info.mFd);
+ android::base::unique_fd newFd(::dup(info.mFd));
+ sp<InputChannel> channel = InputChannel::create(info.mName, std::move(newFd), info.mToken);
+
+ auto it = std::find_if(mInputChannels.begin(), mInputChannels.end(),
+ [&](sp<InputChannel>& it) { return *it == *channel; });
+ if (it != mInputChannels.end()) {
+ mInputChannels.erase(it);
+ }
+
+ return binder::Status::ok();
+}
+
+status_t TestInputManager::dump(int fd, const Vector<String16>& args) {
+ std::string dump;
+
+ dump += " InputFlinger dump\n";
+
+ ::write(fd, dump.c_str(), dump.size());
+ return NO_ERROR;
+}
+
+binder::Status TestInputManager::getInputWindows(
+ std::vector<::android::InputWindowInfo>* inputInfos) {
+ for (auto& [displayId, inputHandles] : mHandlesPerDisplay) {
+ for (auto& inputHandle : inputHandles) {
+ inputInfos->push_back(*inputHandle->getInfo());
+ }
+ }
+ return binder::Status::ok();
+}
+
+binder::Status TestInputManager::getInputChannels(std::vector<::android::InputChannelInfo>* infos) {
+ infos->clear();
+ for (auto& channel : mInputChannels) {
+ auto chanDup = channel->dup();
+ infos->push_back(std::move(chanDup->getInfo()));
+ }
+ return binder::Status::ok();
+}
+
+void InputFlingerServiceTest::SetUp() {
+ mSetInputWindowsListener = new SetInputWindowsListener([&]() {
+ std::unique_lock<std::mutex> lock(mLock);
+ mSetInputWindowsFinishedCondition.notify_all();
+ });
+ InputChannel::openInputChannelPair("testchannels", mServerChannel, mClientChannel);
+
+ mInfo.token = TestInfoToken;
+ mInfo.id = TestInfoId;
+ mInfo.name = TestInfoName;
+ mInfo.layoutParamsFlags = TestInfoLayoutParamsFlags;
+ mInfo.layoutParamsType = TestInfoLayoutParamsType;
+ mInfo.dispatchingTimeout = TestInfoDispatchingTimeout;
+ mInfo.frameLeft = TestInfoFrameLeft;
+ mInfo.frameTop = TestInfoFrameTop;
+ mInfo.frameRight = TestInfoFrameRight;
+ mInfo.frameBottom = TestInfoFrameBottom;
+ mInfo.surfaceInset = TestInfoSurfaceInset;
+ mInfo.globalScaleFactor = TestInfoGlobalScaleFactor;
+ mInfo.windowXScale = TestInfoWindowXScale;
+ mInfo.windowYScale = TestInfoWindowYScale;
+ mInfo.touchableRegion = TestInfoTouchableRegion;
+ mInfo.visible = TestInfoVisible;
+ mInfo.canReceiveKeys = TestInfoCanReceiveKeys;
+ mInfo.trustedOverlay = TestInfoTrustedOverlay;
+ mInfo.hasFocus = TestInfoHasFocus;
+ mInfo.hasWallpaper = TestInfoHasWallpaper;
+ mInfo.paused = TestInfoPaused;
+ mInfo.ownerPid = TestInfoOwnerPid;
+ mInfo.ownerUid = TestInfoOwnerUid;
+ mInfo.inputFeatures = TestInfoInputFeatures;
+ mInfo.displayId = TestInfoDisplayId;
+ mInfo.portalToDisplayId = TestInfoPortalToDisplayId;
+ mInfo.replaceTouchableRegionWithCrop = TestInfoReplaceTouchableRegionWithCrop;
+ mInfo.touchableRegionCropHandle = TestInfoTouchableRegionCropHandle;
+
+ mInfo.applicationInfo.name = TestAppInfoName;
+ mInfo.applicationInfo.token = TestAppInfoToken;
+ mInfo.applicationInfo.dispatchingTimeout = TestAppInfoDispatchingTimeout;
+
+ InitializeInputFlinger();
+}
+
+void InputFlingerServiceTest::TearDown() {}
+
+void InputFlingerServiceTest::verifyInputWindowInfo(const InputWindowInfo& info) const {
+ EXPECT_EQ(mInfo, info);
+}
+
+void InputFlingerServiceTest::InitializeInputFlinger() {
+ sp<IBinder> input(defaultServiceManager()->waitForService(kTestServiceName));
+ ASSERT_TRUE(input != nullptr);
+ mService = interface_cast<IInputFlinger>(input);
+
+ input = defaultServiceManager()->waitForService(kQueryServiceName);
+ ASSERT_TRUE(input != nullptr);
+ mQuery = interface_cast<IInputFlingerQuery>(input);
+}
+
+void InputFlingerServiceTest::setInputWindowsByInfos(std::vector<InputWindowInfo>& infos) {
+ std::unique_lock<std::mutex> lock(mLock);
+ mService->setInputWindows(infos, mSetInputWindowsListener);
+ // Verify listener call
+ EXPECT_NE(mSetInputWindowsFinishedCondition.wait_for(lock, 1s), std::cv_status::timeout);
+ // Verify input windows from service
+ std::vector<::android::InputWindowInfo> inputHandles;
+ mQuery->getInputWindows(&inputHandles);
+ for (auto& inputInfo : inputHandles) {
+ verifyInputWindowInfo(inputInfo);
+ }
+}
+
+/**
+ * Test InputFlinger service interface SetInputWindows
+ */
+TEST_F(InputFlingerServiceTest, InputWindow_SetInputWindows) {
+ std::vector<InputWindowInfo> infos = {getInfo()};
+ setInputWindowsByInfos(infos);
+}
+
+/**
+ * Test InputFlinger service interface registerInputChannel
+ */
+TEST_F(InputFlingerServiceTest, InputWindow_RegisterInputChannel) {
+ sp<InputChannel> serverChannel, clientChannel;
+
+ InputChannel::openInputChannelPair("testchannels", serverChannel, clientChannel);
+ mService->registerInputChannel(serverChannel->getInfo());
+
+ std::vector<::android::InputChannelInfo> infos(2);
+ mQuery->getInputChannels(&infos);
+ EXPECT_EQ(infos.size(), 1UL);
+
+ auto& info = infos[0];
+ android::base::unique_fd newFd(::dup(info.mFd));
+ sp<InputChannel> channel = InputChannel::create(info.mName, std::move(newFd), info.mToken);
+ EXPECT_EQ(*channel, *serverChannel);
+
+ mService->unregisterInputChannel(serverChannel->getInfo());
+ mQuery->getInputChannels(&infos);
+ EXPECT_EQ(infos.size(), 0UL);
+}
+
+/**
+ * Test InputFlinger service interface registerInputChannel with invalid cases
+ */
+TEST_F(InputFlingerServiceTest, InputWindow_RegisterInputChannelInvalid) {
+ sp<InputChannel> serverChannel, clientChannel;
+ InputChannel::openInputChannelPair("testchannels", serverChannel, clientChannel);
+
+ std::vector<::android::InputChannelInfo> infos(2);
+ mQuery->getInputChannels(&infos);
+ EXPECT_EQ(infos.size(), 0UL);
+
+ mService->registerInputChannel(InputChannelInfo());
+ mService->unregisterInputChannel(clientChannel->getInfo());
+
+ mService->registerInputChannel(serverChannel->getInfo());
+ mService->registerInputChannel(clientChannel->getInfo());
+ mQuery->getInputChannels(&infos);
+ EXPECT_EQ(infos.size(), 2UL);
+
+ mService->unregisterInputChannel(clientChannel->getInfo());
+ mService->unregisterInputChannel(serverChannel->getInfo());
+ mQuery->getInputChannels(&infos);
+ EXPECT_EQ(infos.size(), 0UL);
+}
+
+} // namespace android
+
+int main(int argc, char** argv) {
+ pid_t forkPid = fork();
+
+ if (forkPid == 0) {
+ // Server process
+ android::sp<android::TestInputManager> manager = new android::TestInputManager();
+ android::sp<android::TestInputQuery> query = new android::TestInputQuery(manager);
+
+ android::defaultServiceManager()->addService(android::kTestServiceName, manager,
+ false /*allowIsolated*/);
+ android::defaultServiceManager()->addService(android::kQueryServiceName, query,
+ false /*allowIsolated*/);
+ android::ProcessState::self()->startThreadPool();
+ android::IPCThreadState::self()->joinThreadPool();
+ } else {
+ android::ProcessState::self()->startThreadPool();
+ ::testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+ }
+ return 0;
+}
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index 18bd3d0..fae7e64 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -1188,20 +1188,21 @@
// We didn't add any viewports yet, so there shouldn't be any.
std::optional<DisplayViewport> internalViewport =
- mFakePolicy->getDisplayViewportByType(ViewportType::VIEWPORT_INTERNAL);
+ mFakePolicy->getDisplayViewportByType(ViewportType::INTERNAL);
ASSERT_FALSE(internalViewport);
// Add an internal viewport, then clear it
mFakePolicy->addDisplayViewport(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT,
- DISPLAY_ORIENTATION_0, uniqueId, NO_PORT, ViewportType::VIEWPORT_INTERNAL);
+ DISPLAY_ORIENTATION_0, uniqueId, NO_PORT,
+ ViewportType::INTERNAL);
// Check matching by uniqueId
internalViewport = mFakePolicy->getDisplayViewportByUniqueId(uniqueId);
ASSERT_TRUE(internalViewport);
- ASSERT_EQ(ViewportType::VIEWPORT_INTERNAL, internalViewport->type);
+ ASSERT_EQ(ViewportType::INTERNAL, internalViewport->type);
// Check matching by viewport type
- internalViewport = mFakePolicy->getDisplayViewportByType(ViewportType::VIEWPORT_INTERNAL);
+ internalViewport = mFakePolicy->getDisplayViewportByType(ViewportType::INTERNAL);
ASSERT_TRUE(internalViewport);
ASSERT_EQ(uniqueId, internalViewport->uniqueId);
@@ -1209,7 +1210,7 @@
// Make sure nothing is found after clear
internalViewport = mFakePolicy->getDisplayViewportByUniqueId(uniqueId);
ASSERT_FALSE(internalViewport);
- internalViewport = mFakePolicy->getDisplayViewportByType(ViewportType::VIEWPORT_INTERNAL);
+ internalViewport = mFakePolicy->getDisplayViewportByType(ViewportType::INTERNAL);
ASSERT_FALSE(internalViewport);
}
@@ -1223,26 +1224,30 @@
// Add an internal viewport
mFakePolicy->addDisplayViewport(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT,
- DISPLAY_ORIENTATION_0, internalUniqueId, NO_PORT, ViewportType::VIEWPORT_INTERNAL);
+ DISPLAY_ORIENTATION_0, internalUniqueId, NO_PORT,
+ ViewportType::INTERNAL);
// Add an external viewport
mFakePolicy->addDisplayViewport(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT,
- DISPLAY_ORIENTATION_0, externalUniqueId, NO_PORT, ViewportType::VIEWPORT_EXTERNAL);
+ DISPLAY_ORIENTATION_0, externalUniqueId, NO_PORT,
+ ViewportType::EXTERNAL);
// Add an virtual viewport
mFakePolicy->addDisplayViewport(virtualDisplayId1, DISPLAY_WIDTH, DISPLAY_HEIGHT,
- DISPLAY_ORIENTATION_0, virtualUniqueId1, NO_PORT, ViewportType::VIEWPORT_VIRTUAL);
+ DISPLAY_ORIENTATION_0, virtualUniqueId1, NO_PORT,
+ ViewportType::VIRTUAL);
// Add another virtual viewport
mFakePolicy->addDisplayViewport(virtualDisplayId2, DISPLAY_WIDTH, DISPLAY_HEIGHT,
- DISPLAY_ORIENTATION_0, virtualUniqueId2, NO_PORT, ViewportType::VIEWPORT_VIRTUAL);
+ DISPLAY_ORIENTATION_0, virtualUniqueId2, NO_PORT,
+ ViewportType::VIRTUAL);
// Check matching by type for internal
std::optional<DisplayViewport> internalViewport =
- mFakePolicy->getDisplayViewportByType(ViewportType::VIEWPORT_INTERNAL);
+ mFakePolicy->getDisplayViewportByType(ViewportType::INTERNAL);
ASSERT_TRUE(internalViewport);
ASSERT_EQ(internalUniqueId, internalViewport->uniqueId);
// Check matching by type for external
std::optional<DisplayViewport> externalViewport =
- mFakePolicy->getDisplayViewportByType(ViewportType::VIEWPORT_EXTERNAL);
+ mFakePolicy->getDisplayViewportByType(ViewportType::EXTERNAL);
ASSERT_TRUE(externalViewport);
ASSERT_EQ(externalUniqueId, externalViewport->uniqueId);
@@ -1250,7 +1255,7 @@
std::optional<DisplayViewport> virtualViewport1 =
mFakePolicy->getDisplayViewportByUniqueId(virtualUniqueId1);
ASSERT_TRUE(virtualViewport1);
- ASSERT_EQ(ViewportType::VIEWPORT_VIRTUAL, virtualViewport1->type);
+ ASSERT_EQ(ViewportType::VIRTUAL, virtualViewport1->type);
ASSERT_EQ(virtualUniqueId1, virtualViewport1->uniqueId);
ASSERT_EQ(virtualDisplayId1, virtualViewport1->displayId);
@@ -1258,7 +1263,7 @@
std::optional<DisplayViewport> virtualViewport2 =
mFakePolicy->getDisplayViewportByUniqueId(virtualUniqueId2);
ASSERT_TRUE(virtualViewport2);
- ASSERT_EQ(ViewportType::VIEWPORT_VIRTUAL, virtualViewport2->type);
+ ASSERT_EQ(ViewportType::VIRTUAL, virtualViewport2->type);
ASSERT_EQ(virtualUniqueId2, virtualViewport2->uniqueId);
ASSERT_EQ(virtualDisplayId2, virtualViewport2->displayId);
}
@@ -1275,8 +1280,8 @@
constexpr int32_t displayId1 = 2;
constexpr int32_t displayId2 = 3;
- std::vector<ViewportType> types = {ViewportType::VIEWPORT_INTERNAL,
- ViewportType::VIEWPORT_EXTERNAL, ViewportType::VIEWPORT_VIRTUAL};
+ std::vector<ViewportType> types = {ViewportType::INTERNAL, ViewportType::EXTERNAL,
+ ViewportType::VIRTUAL};
for (const ViewportType& type : types) {
mFakePolicy->clearViewports();
// Add a viewport
@@ -1314,7 +1319,7 @@
* Check getDisplayViewportByPort
*/
TEST_F(InputReaderPolicyTest, Viewports_GetByPort) {
- constexpr ViewportType type = ViewportType::VIEWPORT_EXTERNAL;
+ constexpr ViewportType type = ViewportType::EXTERNAL;
const std::string uniqueId1 = "uniqueId1";
const std::string uniqueId2 = "uniqueId2";
constexpr int32_t displayId1 = 1;
@@ -1708,9 +1713,11 @@
// Add default and second display.
mFakePolicy->clearViewports();
mFakePolicy->addDisplayViewport(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT,
- DISPLAY_ORIENTATION_0, "local:0", NO_PORT, ViewportType::VIEWPORT_INTERNAL);
+ DISPLAY_ORIENTATION_0, "local:0", NO_PORT,
+ ViewportType::INTERNAL);
mFakePolicy->addDisplayViewport(SECONDARY_DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT,
- DISPLAY_ORIENTATION_0, "local:1", hdmi1, ViewportType::VIEWPORT_EXTERNAL);
+ DISPLAY_ORIENTATION_0, "local:1", hdmi1,
+ ViewportType::EXTERNAL);
mReader->requestRefreshConfiguration(InputReaderConfiguration::CHANGE_DISPLAY_INFO);
mReader->loopOnce();
@@ -1884,7 +1891,7 @@
// At least add an internal display.
setDisplayInfoAndReconfigure(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT,
DISPLAY_ORIENTATION_0, UNIQUE_ID, NO_PORT,
- ViewportType::VIEWPORT_INTERNAL);
+ ViewportType::INTERNAL);
mDevice = createUinputDevice<UinputTouchScreen>(Rect(0, 0, DISPLAY_WIDTH, DISPLAY_HEIGHT));
ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertInputDevicesChanged());
@@ -2220,8 +2227,7 @@
// Prepare displays.
mFakePolicy->addDisplayViewport(SECONDARY_DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT,
- DISPLAY_ORIENTATION_0, UNIQUE_ID, hdmi,
- ViewportType::VIEWPORT_INTERNAL);
+ DISPLAY_ORIENTATION_0, UNIQUE_ID, hdmi, ViewportType::INTERNAL);
mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(),
InputReaderConfiguration::CHANGE_DISPLAY_INFO);
ASSERT_TRUE(mDevice->isEnabled());
@@ -2421,8 +2427,8 @@
* orientation.
*/
void KeyboardInputMapperTest::prepareDisplay(int32_t orientation) {
- setDisplayInfoAndReconfigure(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT,
- orientation, UNIQUE_ID, NO_PORT, ViewportType::VIEWPORT_INTERNAL);
+ setDisplayInfoAndReconfigure(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, orientation, UNIQUE_ID,
+ NO_PORT, ViewportType::INTERNAL);
}
void KeyboardInputMapperTest::testDPadKeyRotation(KeyboardInputMapper& mapper,
@@ -2727,7 +2733,7 @@
// ^--- already checked by the previous test
setDisplayInfoAndReconfigure(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_ORIENTATION_0,
- UNIQUE_ID, NO_PORT, ViewportType::VIEWPORT_INTERNAL);
+ UNIQUE_ID, NO_PORT, ViewportType::INTERNAL);
process(mapper, ARBITRARY_TIME, EV_KEY, KEY_UP, 1);
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
process(mapper, ARBITRARY_TIME, EV_KEY, KEY_UP, 0);
@@ -2737,7 +2743,7 @@
constexpr int32_t newDisplayId = 2;
clearViewports();
setDisplayInfoAndReconfigure(newDisplayId, DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_ORIENTATION_0,
- UNIQUE_ID, NO_PORT, ViewportType::VIEWPORT_INTERNAL);
+ UNIQUE_ID, NO_PORT, ViewportType::INTERNAL);
process(mapper, ARBITRARY_TIME, EV_KEY, KEY_UP, 1);
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
process(mapper, ARBITRARY_TIME, EV_KEY, KEY_UP, 0);
@@ -2898,9 +2904,9 @@
// Prepare second display.
constexpr int32_t newDisplayId = 2;
setDisplayInfoAndReconfigure(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_ORIENTATION_0,
- UNIQUE_ID, hdmi1, ViewportType::VIEWPORT_INTERNAL);
+ UNIQUE_ID, hdmi1, ViewportType::INTERNAL);
setDisplayInfoAndReconfigure(newDisplayId, DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_ORIENTATION_0,
- SECONDARY_UNIQUE_ID, hdmi2, ViewportType::VIEWPORT_EXTERNAL);
+ SECONDARY_UNIQUE_ID, hdmi2, ViewportType::EXTERNAL);
// Default device will reconfigure above, need additional reconfiguration for another device.
device2->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(),
InputReaderConfiguration::CHANGE_DISPLAY_INFO);
@@ -3035,7 +3041,7 @@
void prepareDisplay(int32_t orientation) {
const std::string uniqueId = "local:0";
- const ViewportType viewportType = ViewportType::VIEWPORT_INTERNAL;
+ const ViewportType viewportType = ViewportType::INTERNAL;
setDisplayInfoAndReconfigure(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT,
orientation, uniqueId, NO_PORT, viewportType);
}
@@ -3780,8 +3786,7 @@
constexpr int32_t SECOND_DISPLAY_ID = 1;
const std::string SECOND_DISPLAY_UNIQUE_ID = "local:1";
mFakePolicy->addDisplayViewport(SECOND_DISPLAY_ID, 800, 480, DISPLAY_ORIENTATION_0,
- SECOND_DISPLAY_UNIQUE_ID, NO_PORT,
- ViewportType::VIEWPORT_EXTERNAL);
+ SECOND_DISPLAY_UNIQUE_ID, NO_PORT, ViewportType::EXTERNAL);
mFakePolicy->setDefaultPointerDisplayId(SECOND_DISPLAY_ID);
configureDevice(InputReaderConfiguration::CHANGE_DISPLAY_INFO);
@@ -3908,8 +3913,8 @@
};
void TouchInputMapperTest::prepareDisplay(int32_t orientation, std::optional<uint8_t> port) {
- setDisplayInfoAndReconfigure(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, orientation,
- UNIQUE_ID, port, ViewportType::VIEWPORT_INTERNAL);
+ setDisplayInfoAndReconfigure(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, orientation, UNIQUE_ID,
+ port, ViewportType::INTERNAL);
}
void TouchInputMapperTest::prepareSecondaryDisplay(ViewportType type, std::optional<uint8_t> port) {
@@ -3918,9 +3923,9 @@
}
void TouchInputMapperTest::prepareVirtualDisplay(int32_t orientation) {
- setDisplayInfoAndReconfigure(VIRTUAL_DISPLAY_ID, VIRTUAL_DISPLAY_WIDTH,
- VIRTUAL_DISPLAY_HEIGHT, orientation,
- VIRTUAL_DISPLAY_UNIQUE_ID, NO_PORT, ViewportType::VIEWPORT_VIRTUAL);
+ setDisplayInfoAndReconfigure(VIRTUAL_DISPLAY_ID, VIRTUAL_DISPLAY_WIDTH, VIRTUAL_DISPLAY_HEIGHT,
+ orientation, VIRTUAL_DISPLAY_UNIQUE_ID, NO_PORT,
+ ViewportType::VIRTUAL);
}
void TouchInputMapperTest::prepareVirtualKeys() {
@@ -6773,7 +6778,7 @@
const uint8_t hdmi1 = 0;
const uint8_t hdmi2 = 1;
const std::string secondaryUniqueId = "uniqueId2";
- constexpr ViewportType type = ViewportType::VIEWPORT_EXTERNAL;
+ constexpr ViewportType type = ViewportType::EXTERNAL;
addConfigurationProperty("touch.deviceType", "touchScreen");
prepareAxes(POSITION);
@@ -6814,7 +6819,7 @@
mFakePolicy->setPointerController(mDevice->getId(), fakePointerController);
mFakePolicy->setDefaultPointerDisplayId(SECONDARY_DISPLAY_ID);
- prepareSecondaryDisplay(ViewportType::VIEWPORT_EXTERNAL);
+ prepareSecondaryDisplay(ViewportType::EXTERNAL);
prepareDisplay(DISPLAY_ORIENTATION_0);
prepareAxes(POSITION);
@@ -6881,11 +6886,11 @@
// Create displays.
prepareDisplay(DISPLAY_ORIENTATION_0, hdmi1);
- prepareSecondaryDisplay(ViewportType::VIEWPORT_EXTERNAL, hdmi2);
+ prepareSecondaryDisplay(ViewportType::EXTERNAL, hdmi2);
// Default device will reconfigure above, need additional reconfiguration for another device.
device2->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(),
- InputReaderConfiguration::CHANGE_DISPLAY_INFO);
+ InputReaderConfiguration::CHANGE_DISPLAY_INFO);
// Two fingers down at default display.
int32_t x1 = 100, y1 = 125, x2 = 300, y2 = 500;
@@ -6992,7 +6997,7 @@
TEST_F(MultiTouchInputMapperTest, Configure_EnabledForAssociatedDisplay) {
constexpr uint8_t hdmi2 = 1;
const std::string secondaryUniqueId = "uniqueId2";
- constexpr ViewportType type = ViewportType::VIEWPORT_EXTERNAL;
+ constexpr ViewportType type = ViewportType::EXTERNAL;
mFakePolicy->addInputPortAssociation(DEVICE_LOCATION, hdmi2);
@@ -7206,7 +7211,7 @@
ASSERT_EQ(ADISPLAY_ID_DEFAULT, motionArgs.displayId);
// Expect the event to be sent to the external viewport if it is present.
- prepareSecondaryDisplay(ViewportType::VIEWPORT_EXTERNAL);
+ prepareSecondaryDisplay(ViewportType::EXTERNAL);
processPosition(mapper, 100, 100);
processSync(mapper);
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
@@ -7220,7 +7225,7 @@
protected:
void halfDisplayToCenterHorizontal(int32_t orientation) {
std::optional<DisplayViewport> internalViewport =
- mFakePolicy->getDisplayViewportByType(ViewportType::VIEWPORT_INTERNAL);
+ mFakePolicy->getDisplayViewportByType(ViewportType::INTERNAL);
// Half display to (width/4, 0, width * 3/4, height) to make display has offset.
internalViewport->orientation = orientation;
diff --git a/services/powermanager/Android.bp b/services/powermanager/Android.bp
index b0d3e3b..ec3dfc8 100644
--- a/services/powermanager/Android.bp
+++ b/services/powermanager/Android.bp
@@ -2,9 +2,14 @@
name: "libpowermanager",
srcs: [
- "IPowerManager.cpp",
- "Temperature.cpp",
+ "BatterySaverPolicyConfig.cpp",
"CoolingDevice.cpp",
+ "PowerHalController.cpp",
+ "PowerHalLoader.cpp",
+ "PowerHalWrapper.cpp",
+ "PowerSaveState.cpp",
+ "Temperature.cpp",
+ "WorkSource.cpp",
":libpowermanager_aidl",
],
@@ -17,9 +22,13 @@
},
shared_libs: [
- "libutils",
"libbinder",
- "liblog"
+ "libhidlbase",
+ "liblog",
+ "libutils",
+ "android.hardware.power@1.0",
+ "android.hardware.power@1.1",
+ "android.hardware.power-cpp",
],
cflags: [
@@ -34,22 +43,3 @@
"include",
],
}
-
-cc_test {
- name: "thermalmanager-test",
- srcs: ["IThermalManagerTest.cpp",
- ],
- cflags: [
- "-Wall",
- "-Werror",
- "-Wextra",
- ],
- shared_libs: [
- "libbase",
- "libhidlbase",
- "liblog",
- "libpowermanager",
- "libbinder",
- "libutils",
- ],
-}
diff --git a/services/powermanager/BatterySaverPolicyConfig.cpp b/services/powermanager/BatterySaverPolicyConfig.cpp
new file mode 100644
index 0000000..ee55b6b
--- /dev/null
+++ b/services/powermanager/BatterySaverPolicyConfig.cpp
@@ -0,0 +1,112 @@
+/*
+ * 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 "BatterySaverPolicyConfig"
+
+#include <android/BatterySaverPolicyConfig.h>
+#include <binder/Parcel.h>
+#include <utils/Log.h>
+
+namespace android::os {
+
+status_t BatterySaverPolicyConfig::readDeviceSpecificSettings(const android::Parcel *parcel) {
+ int32_t num = 0;
+ status_t ret = parcel->readInt32(&num);
+ if (ret != OK) {
+ return ret;
+ }
+ for (int i = 0; i < num; i++) {
+ String16 key, val;
+ ret = parcel->readString16(&key) ?:
+ parcel->readString16(&val);
+ if (ret != OK) {
+ return ret;
+ }
+ mDeviceSpecificSettings.emplace_back(key, val);
+ }
+ return ret;
+}
+
+status_t BatterySaverPolicyConfig::readFromParcel(const android::Parcel *parcel) {
+ if (parcel == nullptr) {
+ ALOGE("%s: Null parcel", __func__);
+ return BAD_VALUE;
+ }
+
+ return parcel->readFloat(&mAdjustBrightnessFactor)
+ ?: parcel->readBool(&mAdvertiseIsEnabled)
+ ?: parcel->readBool(&mDeferFullBackup)
+ ?: parcel->readBool(&mDeferKeyValueBackup)
+ ?: readDeviceSpecificSettings(parcel)
+ ?: parcel->readBool(&mDisableAnimation)
+ ?: parcel->readBool(&mDisableAod)
+ ?: parcel->readBool(&mDisableLaunchBoost)
+ ?: parcel->readBool(&mDisableOptionalSensors)
+ ?: parcel->readBool(&mDisableSoundTrigger)
+ ?: parcel->readBool(&mDisableVibration)
+ ?: parcel->readBool(&mEnableAdjustBrightness)
+ ?: parcel->readBool(&mEnableDataSaver)
+ ?: parcel->readBool(&mEnableFirewall)
+ ?: parcel->readBool(&mEnableNightMode)
+ ?: parcel->readBool(&mEnableQuickDoze)
+ ?: parcel->readBool(&mForceAllAppsStandby)
+ ?: parcel->readBool(&mForceBackgroundCheck)
+ ?: parcel->readInt32(reinterpret_cast<int32_t *>(&mLocationMode));
+}
+
+status_t BatterySaverPolicyConfig::writeDeviceSpecificSettings(android::Parcel *parcel) const {
+ status_t ret = parcel->writeInt32(mDeviceSpecificSettings.size());
+ if (ret != OK) {
+ return ret;
+ }
+ for (auto& settings : mDeviceSpecificSettings) {
+ ret = parcel->writeString16(settings.first) ?:
+ parcel->writeString16(settings.second);
+ if (ret != OK) {
+ return ret;
+ }
+ }
+ return ret;
+}
+
+status_t BatterySaverPolicyConfig::writeToParcel(android::Parcel *parcel) const {
+ if (parcel == nullptr) {
+ ALOGE("%s: Null parcel", __func__);
+ return BAD_VALUE;
+ }
+
+ return parcel->writeFloat(mAdjustBrightnessFactor)
+ ?: parcel->writeBool(mAdvertiseIsEnabled)
+ ?: parcel->writeBool(mDeferFullBackup)
+ ?: parcel->writeBool(mDeferKeyValueBackup)
+ ?: writeDeviceSpecificSettings(parcel)
+ ?: parcel->writeBool(mDisableAnimation)
+ ?: parcel->writeBool(mDisableAod)
+ ?: parcel->writeBool(mDisableLaunchBoost)
+ ?: parcel->writeBool(mDisableOptionalSensors)
+ ?: parcel->writeBool(mDisableSoundTrigger)
+ ?: parcel->writeBool(mDisableVibration)
+ ?: parcel->writeBool(mEnableAdjustBrightness)
+ ?: parcel->writeBool(mEnableDataSaver)
+ ?: parcel->writeBool(mEnableFirewall)
+ ?: parcel->writeBool(mEnableNightMode)
+ ?: parcel->writeBool(mEnableQuickDoze)
+ ?: parcel->writeBool(mForceAllAppsStandby)
+ ?: parcel->writeBool(mForceBackgroundCheck)
+ ?: parcel->writeInt32(static_cast<int32_t>(mLocationMode));
+}
+
+} // namespace android::os
diff --git a/services/powermanager/IPowerManager.cpp b/services/powermanager/IPowerManager.cpp
deleted file mode 100644
index ea3a831..0000000
--- a/services/powermanager/IPowerManager.cpp
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * Copyright (C) 2011 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 "IPowerManager"
-//#define LOG_NDEBUG 0
-#include <utils/Log.h>
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <binder/Parcel.h>
-
-#include <powermanager/IPowerManager.h>
-
-namespace android {
-
-class BpPowerManager : public BpInterface<IPowerManager>
-{
-public:
- explicit BpPowerManager(const sp<IBinder>& impl)
- : BpInterface<IPowerManager>(impl)
- {
- }
-
- virtual status_t acquireWakeLock(int flags, const sp<IBinder>& lock, const String16& tag,
- const String16& packageName, bool isOneWay)
- {
- Parcel data, reply;
- data.writeInterfaceToken(IPowerManager::getInterfaceDescriptor());
-
- data.writeStrongBinder(lock);
- data.writeInt32(flags);
- data.writeString16(tag);
- data.writeString16(packageName);
- data.writeInt32(0); // no WorkSource
- data.writeString16(NULL, 0); // no history tag
- return remote()->transact(ACQUIRE_WAKE_LOCK, data, &reply,
- isOneWay ? IBinder::FLAG_ONEWAY : 0);
- }
-
- virtual status_t acquireWakeLockWithUid(int flags, const sp<IBinder>& lock, const String16& tag,
- const String16& packageName, int uid, bool isOneWay)
- {
- Parcel data, reply;
- data.writeInterfaceToken(IPowerManager::getInterfaceDescriptor());
-
- data.writeStrongBinder(lock);
- data.writeInt32(flags);
- data.writeString16(tag);
- data.writeString16(packageName);
- data.writeInt32(uid); // uid to blame for the work
- return remote()->transact(ACQUIRE_WAKE_LOCK_UID, data, &reply,
- isOneWay ? IBinder::FLAG_ONEWAY : 0);
- }
-
- virtual status_t releaseWakeLock(const sp<IBinder>& lock, int flags, bool isOneWay)
- {
- Parcel data, reply;
- data.writeInterfaceToken(IPowerManager::getInterfaceDescriptor());
- data.writeStrongBinder(lock);
- data.writeInt32(flags);
- return remote()->transact(RELEASE_WAKE_LOCK, data, &reply,
- isOneWay ? IBinder::FLAG_ONEWAY : 0);
- }
-
- virtual status_t updateWakeLockUids(const sp<IBinder>& lock, int len, const int *uids,
- bool isOneWay) {
- Parcel data, reply;
- data.writeInterfaceToken(IPowerManager::getInterfaceDescriptor());
- data.writeStrongBinder(lock);
- data.writeInt32Array(len, uids);
- return remote()->transact(UPDATE_WAKE_LOCK_UIDS, data, &reply,
- isOneWay ? IBinder::FLAG_ONEWAY : 0);
- }
-
- virtual status_t powerHint(int hintId, int param)
- {
- Parcel data, reply;
- data.writeInterfaceToken(IPowerManager::getInterfaceDescriptor());
- data.writeInt32(hintId);
- data.writeInt32(param);
- // This FLAG_ONEWAY is in the .aidl, so there is no way to disable it
- return remote()->transact(POWER_HINT, data, &reply, IBinder::FLAG_ONEWAY);
- }
-
- virtual status_t goToSleep(int64_t event_time_ms, int reason, int flags)
- {
- Parcel data, reply;
- data.writeInterfaceToken(IPowerManager::getInterfaceDescriptor());
- data.writeInt64(event_time_ms);
- data.writeInt32(reason);
- data.writeInt32(flags);
- return remote()->transact(GO_TO_SLEEP, data, &reply, 0);
- }
-
- virtual status_t reboot(bool confirm, const String16& reason, bool wait)
- {
- Parcel data, reply;
- data.writeInterfaceToken(IPowerManager::getInterfaceDescriptor());
- data.writeInt32(confirm);
- data.writeString16(reason);
- data.writeInt32(wait);
- return remote()->transact(REBOOT, data, &reply, 0);
- }
-
- virtual status_t shutdown(bool confirm, const String16& reason, bool wait)
- {
- Parcel data, reply;
- data.writeInterfaceToken(IPowerManager::getInterfaceDescriptor());
- data.writeInt32(confirm);
- data.writeString16(reason);
- data.writeInt32(wait);
- return remote()->transact(SHUTDOWN, data, &reply, 0);
- }
-
- virtual status_t crash(const String16& message)
- {
- Parcel data, reply;
- data.writeInterfaceToken(IPowerManager::getInterfaceDescriptor());
- data.writeString16(message);
- return remote()->transact(CRASH, data, &reply, 0);
- }
-};
-
-IMPLEMENT_META_INTERFACE(PowerManager, "android.os.IPowerManager");
-
-// ----------------------------------------------------------------------------
-
-}; // namespace android
diff --git a/services/powermanager/PowerHalController.cpp b/services/powermanager/PowerHalController.cpp
new file mode 100644
index 0000000..178f545
--- /dev/null
+++ b/services/powermanager/PowerHalController.cpp
@@ -0,0 +1,101 @@
+/*
+ * 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 "PowerHalController"
+#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 namespace android::hardware::power;
+
+namespace android {
+
+namespace power {
+
+// -------------------------------------------------------------------------------------------------
+
+std::unique_ptr<HalWrapper> HalConnector::connect() {
+ sp<IPower> halAidl = PowerHalLoader::loadAidl();
+ if (halAidl) {
+ return std::make_unique<AidlHalWrapper>(halAidl);
+ }
+ 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<HidlHalWrapperV1_1>(halHidlV1_0, halHidlV1_1);
+ }
+ if (halHidlV1_0) {
+ return std::make_unique<HidlHalWrapperV1_0>(halHidlV1_0);
+ }
+ return nullptr;
+}
+
+void HalConnector::reset() {
+ PowerHalLoader::unloadAll();
+}
+
+// -------------------------------------------------------------------------------------------------
+
+void PowerHalController::init() {
+ 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();
+ if (mConnectedHal == nullptr) {
+ // Unable to connect to Power HAL service. Fallback to default.
+ return mDefaultHal;
+ }
+ }
+ return mConnectedHal;
+}
+
+// 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.
+ mConnectedHal = nullptr;
+ mHalConnector->reset();
+ }
+ return result;
+}
+
+HalResult PowerHalController::setBoost(Boost boost, int32_t durationMs) {
+ std::shared_ptr<HalWrapper> handle = initHal();
+ auto result = handle->setBoost(boost, durationMs);
+ return processHalResult(result, "setBoost");
+}
+
+HalResult PowerHalController::setMode(Mode mode, bool enabled) {
+ std::shared_ptr<HalWrapper> handle = initHal();
+ auto result = handle->setMode(mode, enabled);
+ return processHalResult(result, "setMode");
+}
+
+} // namespace power
+
+} // namespace android
diff --git a/services/powermanager/PowerHalLoader.cpp b/services/powermanager/PowerHalLoader.cpp
new file mode 100644
index 0000000..1f1b43a
--- /dev/null
+++ b/services/powermanager/PowerHalLoader.cpp
@@ -0,0 +1,95 @@
+/*
+ * 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 "PowerHalLoader"
+
+#include <android/hardware/power/1.1/IPower.h>
+#include <android/hardware/power/IPower.h>
+#include <binder/IServiceManager.h>
+#include <hardware/power.h>
+#include <hardware_legacy/power.h>
+#include <powermanager/PowerHalLoader.h>
+
+using namespace android::hardware::power;
+
+namespace android {
+
+namespace power {
+
+// -------------------------------------------------------------------------------------------------
+
+template <typename T, typename F>
+sp<T> loadHal(bool& exists, sp<T>& hal, F& loadFn, const char* halName) {
+ if (!exists) {
+ return nullptr;
+ }
+ if (hal) {
+ return hal;
+ }
+ hal = loadFn();
+ if (hal) {
+ ALOGV("Successfully connected to Power HAL %s service.", halName);
+ } else {
+ ALOGV("Power HAL %s service not available.", halName);
+ exists = false;
+ }
+ return hal;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+std::mutex PowerHalLoader::gHalMutex;
+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);
+ gHalAidl = nullptr;
+ gHalHidlV1_0 = nullptr;
+ gHalHidlV1_1 = nullptr;
+}
+
+sp<IPower> PowerHalLoader::loadAidl() {
+ std::lock_guard<std::mutex> lock(gHalMutex);
+ static bool gHalExists = true;
+ static auto loadFn = []() { return waitForVintfService<IPower>(); };
+ return loadHal<IPower>(gHalExists, gHalAidl, loadFn, "AIDL");
+}
+
+sp<V1_0::IPower> PowerHalLoader::loadHidlV1_0() {
+ std::lock_guard<std::mutex> lock(gHalMutex);
+ return loadHidlV1_0Locked();
+}
+
+sp<V1_1::IPower> PowerHalLoader::loadHidlV1_1() {
+ std::lock_guard<std::mutex> lock(gHalMutex);
+ static bool gHalExists = true;
+ static auto loadFn = []() { return V1_1::IPower::castFrom(loadHidlV1_0Locked()); };
+ return loadHal<V1_1::IPower>(gHalExists, gHalHidlV1_1, loadFn, "HIDL v1.1");
+}
+
+sp<V1_0::IPower> PowerHalLoader::loadHidlV1_0Locked() {
+ static bool gHalExists = true;
+ 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
new file mode 100644
index 0000000..95f8623
--- /dev/null
+++ b/services/powermanager/PowerHalWrapper.cpp
@@ -0,0 +1,173 @@
+/*
+ * 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 "HalWrapper"
+#include <android/hardware/power/Boost.h>
+#include <android/hardware/power/Mode.h>
+#include <powermanager/PowerHalWrapper.h>
+#include <utils/Log.h>
+
+using namespace android::hardware::power;
+
+namespace android {
+
+namespace power {
+
+// -------------------------------------------------------------------------------------------------
+
+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 HalResult::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;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+HalResult HidlHalWrapperV1_0::setBoost(Boost boost, int32_t durationMs) {
+ if (boost == Boost::INTERACTION) {
+ return sendPowerHint(V1_0::PowerHint::INTERACTION, durationMs);
+ } else {
+ ALOGV("Skipped setBoost %s because Power HAL AIDL not available", toString(boost).c_str());
+ return HalResult::UNSUPPORTED;
+ }
+}
+
+HalResult HidlHalWrapperV1_0::setMode(Mode mode, bool enabled) {
+ uint32_t data = enabled ? 1 : 0;
+ switch (mode) {
+ case Mode::LAUNCH:
+ return sendPowerHint(V1_0::PowerHint::LAUNCH, data);
+ case Mode::LOW_POWER:
+ return sendPowerHint(V1_0::PowerHint::LOW_POWER, data);
+ case Mode::SUSTAINED_PERFORMANCE:
+ return sendPowerHint(V1_0::PowerHint::SUSTAINED_PERFORMANCE, data);
+ case Mode::VR:
+ return sendPowerHint(V1_0::PowerHint::VR_MODE, data);
+ case Mode::INTERACTIVE:
+ return setInteractive(enabled);
+ case Mode::DOUBLE_TAP_TO_WAKE:
+ 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 HalResult::UNSUPPORTED;
+ }
+}
+
+HalResult HidlHalWrapperV1_0::sendPowerHint(V1_0::PowerHint hintId, uint32_t data) {
+ return toHalResult(mHandleV1_0->powerHint(hintId, data));
+}
+
+HalResult HidlHalWrapperV1_0::setInteractive(bool enabled) {
+ return toHalResult(mHandleV1_0->setInteractive(enabled));
+}
+
+HalResult HidlHalWrapperV1_0::setFeature(V1_0::Feature feature, bool enabled) {
+ return toHalResult(mHandleV1_0->setFeature(feature, enabled));
+}
+
+// -------------------------------------------------------------------------------------------------
+
+HalResult HidlHalWrapperV1_1::sendPowerHint(V1_0::PowerHint hintId, uint32_t data) {
+ return toHalResult(mHandleV1_1->powerHintAsync(hintId, data));
+}
+
+// -------------------------------------------------------------------------------------------------
+
+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 ||
+ 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 (mBoostSupportedArray[static_cast<int32_t>(boost)] == HalSupport::UNKNOWN) {
+ bool isSupported = false;
+ 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 HalResult::FAILED;
+ }
+
+ 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 HalResult::UNSUPPORTED;
+ }
+ }
+ lock.unlock();
+
+ return toHalResult(mHandle->setBoost(boost, durationMs));
+}
+
+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 ||
+ 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 (mModeSupportedArray[static_cast<int32_t>(mode)] == HalSupport::UNKNOWN) {
+ bool isSupported = false;
+ 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 HalResult::FAILED;
+ }
+
+ 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 HalResult::UNSUPPORTED;
+ }
+ }
+ lock.unlock();
+
+ return toHalResult(mHandle->setMode(mode, enabled));
+}
+
+// -------------------------------------------------------------------------------------------------
+
+} // namespace power
+
+} // namespace android
diff --git a/services/powermanager/PowerSaveState.cpp b/services/powermanager/PowerSaveState.cpp
new file mode 100644
index 0000000..6d1830a
--- /dev/null
+++ b/services/powermanager/PowerSaveState.cpp
@@ -0,0 +1,49 @@
+/*
+ * 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 "PowerSaveState"
+
+#include <android/PowerSaveState.h>
+#include <binder/Parcel.h>
+#include <utils/Log.h>
+
+namespace android::os {
+
+status_t PowerSaveState::readFromParcel(const android::Parcel *parcel) {
+ if (parcel == nullptr) {
+ ALOGE("%s: Null parcel", __func__);
+ return BAD_VALUE;
+ }
+
+ return parcel->readBool(&mBatterySaverEnabled)
+ ?: parcel->readBool(&mGlobalBatterySaverEnabled)
+ ?: parcel->readInt32(reinterpret_cast<int32_t *>(&mLocationMode))
+ ?: parcel->readFloat(&mBrightnessFactor);
+}
+
+status_t PowerSaveState::writeToParcel(android::Parcel *parcel) const {
+ if (parcel == nullptr) {
+ ALOGE("%s: Null parcel", __func__);
+ return BAD_VALUE;
+ }
+
+ return parcel->writeBool(mBatterySaverEnabled)
+ ?: parcel->writeBool(mGlobalBatterySaverEnabled)
+ ?: parcel->writeInt32(static_cast<int32_t>(mLocationMode))
+ ?: parcel->writeFloat(mBrightnessFactor);
+}
+
+} // namespace android::os
diff --git a/services/powermanager/TEST_MAPPING b/services/powermanager/TEST_MAPPING
new file mode 100644
index 0000000..caaec55
--- /dev/null
+++ b/services/powermanager/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "presubmit": [
+ {
+ "name": "libpowermanager_test"
+ }
+ ]
+}
diff --git a/services/powermanager/WorkSource.cpp b/services/powermanager/WorkSource.cpp
new file mode 100644
index 0000000..1006a06
--- /dev/null
+++ b/services/powermanager/WorkSource.cpp
@@ -0,0 +1,49 @@
+/*
+ * 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 "WorkSource"
+
+#include <android/WorkSource.h>
+#include <binder/Parcel.h>
+#include <utils/Log.h>
+
+namespace android::os {
+
+status_t WorkSource::readFromParcel(const android::Parcel *parcel) {
+ if (parcel == nullptr) {
+ ALOGE("%s: Null parcel", __func__);
+ return BAD_VALUE;
+ }
+ int32_t num;
+ status_t ret = parcel->readInt32(&num)
+ ?: parcel->readInt32Vector(&mUids)
+ ?: parcel->readString16Vector(&mNames);
+
+ return ret;
+}
+
+status_t WorkSource::writeToParcel(android::Parcel *parcel) const {
+ if (parcel == nullptr) {
+ ALOGE("%s: Null parcel", __func__);
+ return BAD_VALUE;
+ }
+
+ return parcel->writeInt32(mUids.size())
+ ?: parcel->writeInt32Vector(mUids)
+ ?: parcel->writeString16Vector(mNames);
+}
+
+} // namespace android::os
diff --git a/services/powermanager/benchmarks/Android.bp b/services/powermanager/benchmarks/Android.bp
new file mode 100644
index 0000000..5975269
--- /dev/null
+++ b/services/powermanager/benchmarks/Android.bp
@@ -0,0 +1,39 @@
+// 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.
+
+cc_benchmark {
+ name: "libpowermanager_benchmarks",
+ srcs: [
+ "main.cpp",
+ "PowerHalAidlBenchmarks.cpp",
+ "PowerHalControllerBenchmarks.cpp",
+ "PowerHalHidlBenchmarks.cpp",
+ ],
+ shared_libs: [
+ "libbase",
+ "libbinder",
+ "libhidlbase",
+ "liblog",
+ "libpowermanager",
+ "libutils",
+ "android.hardware.power@1.0",
+ "android.hardware.power@1.1",
+ "android.hardware.power-cpp",
+ ],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-Wextra",
+ ],
+}
diff --git a/services/powermanager/benchmarks/AndroidTest.xml b/services/powermanager/benchmarks/AndroidTest.xml
new file mode 100644
index 0000000..40f4872
--- /dev/null
+++ b/services/powermanager/benchmarks/AndroidTest.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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.
+ -->
+<configuration description="Config for libpowermanager benchmarks">
+ <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+ <option name="cleanup" value="true" />
+ <option name="push" value="libpowermanager_benchmarks->/data/benchmarktest/benchmark" />
+ </target_preparer>
+ <option name="test-suite-tag" value="apct" />
+ <option name="test-suite-tag" value="apct-metric-instrumentation" />
+ <test class="com.android.tradefed.testtype.GoogleBenchmarkTest" >
+ <option name="native-benchmark-device-path" value="/data/benchmarktest" />
+ <option name="benchmark-module-name" value="benchmark" />
+ </test>
+</configuration>
diff --git a/services/powermanager/benchmarks/PowerHalAidlBenchmarks.cpp b/services/powermanager/benchmarks/PowerHalAidlBenchmarks.cpp
new file mode 100644
index 0000000..a6dad51
--- /dev/null
+++ b/services/powermanager/benchmarks/PowerHalAidlBenchmarks.cpp
@@ -0,0 +1,68 @@
+/*
+ * 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 "PowerHalAidlBenchmarks"
+
+#include <android/hardware/power/Boost.h>
+#include <android/hardware/power/IPower.h>
+#include <android/hardware/power/Mode.h>
+
+#include <benchmark/benchmark.h>
+
+#include <binder/IServiceManager.h>
+
+using android::hardware::power::Boost;
+using android::hardware::power::IPower;
+using android::hardware::power::Mode;
+
+using namespace android;
+
+template <class R, class... Args0, class... Args1>
+static void runBenchmark(benchmark::State& state, R (IPower::*fn)(Args0...), Args1&&... args1) {
+ sp<IPower> hal = waitForVintfService<IPower>();
+
+ if (hal == nullptr) {
+ ALOGI("Power HAL AIDL not available, skipping test...");
+ return;
+ }
+
+ while (state.KeepRunning()) {
+ (*hal.*fn)(std::forward<Args1>(args1)...);
+ }
+}
+
+static void BM_PowerHalAidlBenchmarks_isBoostSupported(benchmark::State& state) {
+ bool isSupported;
+ runBenchmark(state, &IPower::isBoostSupported, Boost::INTERACTION, &isSupported);
+}
+
+static void BM_PowerHalAidlBenchmarks_isModeSupported(benchmark::State& state) {
+ bool isSupported;
+ runBenchmark(state, &IPower::isModeSupported, Mode::INTERACTIVE, &isSupported);
+}
+
+static void BM_PowerHalAidlBenchmarks_setBoost(benchmark::State& state) {
+ runBenchmark(state, &IPower::setBoost, Boost::INTERACTION, 0);
+}
+
+static void BM_PowerHalAidlBenchmarks_setMode(benchmark::State& state) {
+ runBenchmark(state, &IPower::setMode, Mode::INTERACTIVE, false);
+}
+
+BENCHMARK(BM_PowerHalAidlBenchmarks_isBoostSupported);
+BENCHMARK(BM_PowerHalAidlBenchmarks_isModeSupported);
+BENCHMARK(BM_PowerHalAidlBenchmarks_setBoost);
+BENCHMARK(BM_PowerHalAidlBenchmarks_setMode);
diff --git a/services/powermanager/benchmarks/PowerHalControllerBenchmarks.cpp b/services/powermanager/benchmarks/PowerHalControllerBenchmarks.cpp
new file mode 100644
index 0000000..a3a1f4e
--- /dev/null
+++ b/services/powermanager/benchmarks/PowerHalControllerBenchmarks.cpp
@@ -0,0 +1,88 @@
+/*
+ * 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 "PowerHalControllerBenchmarks"
+
+#include <android/hardware/power/Boost.h>
+#include <android/hardware/power/Mode.h>
+
+#include <benchmark/benchmark.h>
+
+#include <powermanager/PowerHalController.h>
+
+using android::hardware::power::Boost;
+using android::hardware::power::Mode;
+using android::power::PowerHalController;
+
+using namespace android;
+
+static void BM_PowerHalControllerBenchmarks_init(benchmark::State& state) {
+ while (state.KeepRunning()) {
+ PowerHalController controller;
+ controller.init();
+ }
+}
+
+static void BM_PowerHalControllerBenchmarks_initCached(benchmark::State& state) {
+ PowerHalController controller;
+ // First connection out of test.
+ controller.init();
+
+ while (state.KeepRunning()) {
+ controller.init();
+ }
+}
+
+static void BM_PowerHalControllerBenchmarks_setBoost(benchmark::State& state) {
+ while (state.KeepRunning()) {
+ PowerHalController controller;
+ controller.setBoost(Boost::INTERACTION, 0);
+ }
+}
+
+static void BM_PowerHalControllerBenchmarks_setBoostCached(benchmark::State& state) {
+ PowerHalController controller;
+ // First call out of test, to cache supported boost.
+ controller.setBoost(Boost::INTERACTION, 0);
+
+ while (state.KeepRunning()) {
+ controller.setBoost(Boost::INTERACTION, 0);
+ }
+}
+
+static void BM_PowerHalControllerBenchmarks_setMode(benchmark::State& state) {
+ while (state.KeepRunning()) {
+ PowerHalController controller;
+ controller.setMode(Mode::INTERACTIVE, false);
+ }
+}
+
+static void BM_PowerHalControllerBenchmarks_setModeCached(benchmark::State& state) {
+ PowerHalController controller;
+ // First call out of test, to cache supported mode.
+ controller.setMode(Mode::INTERACTIVE, false);
+
+ while (state.KeepRunning()) {
+ controller.setMode(Mode::INTERACTIVE, false);
+ }
+}
+
+BENCHMARK(BM_PowerHalControllerBenchmarks_init);
+BENCHMARK(BM_PowerHalControllerBenchmarks_initCached);
+BENCHMARK(BM_PowerHalControllerBenchmarks_setBoost);
+BENCHMARK(BM_PowerHalControllerBenchmarks_setBoostCached);
+BENCHMARK(BM_PowerHalControllerBenchmarks_setMode);
+BENCHMARK(BM_PowerHalControllerBenchmarks_setModeCached);
diff --git a/services/powermanager/benchmarks/PowerHalHidlBenchmarks.cpp b/services/powermanager/benchmarks/PowerHalHidlBenchmarks.cpp
new file mode 100644
index 0000000..5542ac4
--- /dev/null
+++ b/services/powermanager/benchmarks/PowerHalHidlBenchmarks.cpp
@@ -0,0 +1,71 @@
+/*
+ * 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 "PowerHalHidlBenchmarks"
+
+#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 <benchmark/benchmark.h>
+
+#include <hardware/power.h>
+#include <hardware_legacy/power.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 IPower1_0 = android::hardware::power::V1_0::IPower;
+using IPower1_1 = android::hardware::power::V1_1::IPower;
+
+using namespace android;
+
+template <class R, class I, class... Args0, class... Args1>
+static void runBenchmark(benchmark::State& state, R (I::*fn)(Args0...), Args1&&... args1) {
+ sp<I> hal = I::getService();
+
+ if (hal == nullptr) {
+ ALOGI("Power HAL HIDL not available, skipping test...");
+ return;
+ }
+
+ while (state.KeepRunning()) {
+ (*hal.*fn)(std::forward<Args1>(args1)...);
+ }
+}
+
+static void BM_PowerHalHidlBenchmarks_setFeature(benchmark::State& state) {
+ runBenchmark(state, &IPower1_0::setFeature, Feature::POWER_FEATURE_DOUBLE_TAP_TO_WAKE, false);
+}
+
+static void BM_PowerHalHidlBenchmarks_setInteractive(benchmark::State& state) {
+ runBenchmark(state, &IPower1_0::setInteractive, false);
+}
+
+static void BM_PowerHalHidlBenchmarks_powerHint(benchmark::State& state) {
+ runBenchmark(state, &IPower1_0::powerHint, PowerHint::INTERACTION, 0);
+}
+
+static void BM_PowerHalHidlBenchmarks_powerHintAsync(benchmark::State& state) {
+ runBenchmark(state, &IPower1_1::powerHintAsync, PowerHint::INTERACTION, 0);
+}
+
+BENCHMARK(BM_PowerHalHidlBenchmarks_setFeature);
+BENCHMARK(BM_PowerHalHidlBenchmarks_setInteractive);
+BENCHMARK(BM_PowerHalHidlBenchmarks_powerHint);
+BENCHMARK(BM_PowerHalHidlBenchmarks_powerHintAsync);
diff --git a/services/powermanager/benchmarks/main.cpp b/services/powermanager/benchmarks/main.cpp
new file mode 100644
index 0000000..15c57bf
--- /dev/null
+++ b/services/powermanager/benchmarks/main.cpp
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <benchmark/benchmark.h>
+
+BENCHMARK_MAIN();
diff --git a/services/powermanager/include/android/BatterySaverPolicyConfig.h b/services/powermanager/include/android/BatterySaverPolicyConfig.h
new file mode 100644
index 0000000..728c8a0
--- /dev/null
+++ b/services/powermanager/include/android/BatterySaverPolicyConfig.h
@@ -0,0 +1,143 @@
+/*
+ * 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_OS_BATTERY_SAVER_POLICY_CONFIG_H
+#define ANDROID_OS_BATTERY_SAVER_POLICY_CONFIG_H
+
+#include <math.h>
+#include <binder/Parcelable.h>
+#include <utils/RefBase.h>
+
+namespace android::os {
+
+enum class LocationMode : int32_t;
+/**
+ * BatterySaverPolicyConfig is a structure of configs to set Battery Saver policy flags.
+ * This file needs to be kept in sync with
+ * frameworks/base/core/java/android/os/BatterySaverPolicyConfig.java
+ */
+struct BatterySaverPolicyConfig : public android::Parcelable {
+
+ BatterySaverPolicyConfig(float adjustBrightnessFactor = 1.0f,
+ bool advertiseIsEnabled = false,
+ bool deferFullBackup = false,
+ bool deferKeyValueBackup = false,
+ std::vector<std::pair<String16, String16>> deviceSpecificSettings = {},
+ bool disableAnimation = false,
+ bool disableAod = false,
+ bool disableLaunchBoost = false,
+ bool disableOptionalSensors = false,
+ bool disableSoundTrigger = false,
+ bool disableVibration = false,
+ bool enableAdjustBrightness = false,
+ bool enableDataSaver = false,
+ bool enableFirewall = false,
+ bool enableNightMode = false,
+ bool enableQuickDoze = false,
+ bool forceAllAppsStandby = false,
+ bool forceBackgroundCheck = false,
+ LocationMode locationMode = static_cast<LocationMode>(0))
+ : mAdjustBrightnessFactor(adjustBrightnessFactor),
+ mAdvertiseIsEnabled(advertiseIsEnabled),
+ mDeferFullBackup(deferFullBackup),
+ mDeferKeyValueBackup(deferKeyValueBackup),
+ mDeviceSpecificSettings(deviceSpecificSettings),
+ mDisableAnimation(disableAnimation),
+ mDisableAod(disableAod),
+ mDisableLaunchBoost(disableLaunchBoost),
+ mDisableOptionalSensors(disableOptionalSensors),
+ mDisableSoundTrigger(disableSoundTrigger),
+ mDisableVibration(disableVibration),
+ mEnableAdjustBrightness(enableAdjustBrightness),
+ mEnableDataSaver(enableDataSaver),
+ mEnableFirewall(enableFirewall),
+ mEnableNightMode(enableNightMode),
+ mEnableQuickDoze(enableQuickDoze),
+ mForceAllAppsStandby(forceAllAppsStandby),
+ mForceBackgroundCheck(forceBackgroundCheck),
+ mLocationMode(locationMode) {
+ }
+
+ status_t readFromParcel(const android::Parcel* parcel) override;
+ status_t writeToParcel(android::Parcel* parcel) const override;
+ bool operator == (const BatterySaverPolicyConfig &bsp) const {
+ return fabs(mAdjustBrightnessFactor - bsp.mAdjustBrightnessFactor) == 0.0f &&
+ mAdvertiseIsEnabled == bsp.mAdvertiseIsEnabled &&
+ mDeferFullBackup == bsp.mDeferFullBackup &&
+ mDeferKeyValueBackup == bsp.mDeferKeyValueBackup &&
+ mDeviceSpecificSettings == bsp.mDeviceSpecificSettings &&
+ mDisableAnimation == bsp.mDisableAnimation &&
+ mDisableAod == bsp.mDisableAod &&
+ mDisableLaunchBoost == bsp.mDisableLaunchBoost &&
+ mDisableOptionalSensors == bsp.mDisableOptionalSensors &&
+ mDisableSoundTrigger == bsp.mDisableSoundTrigger &&
+ mDisableVibration == bsp.mDisableVibration &&
+ mEnableAdjustBrightness == bsp.mEnableAdjustBrightness &&
+ mEnableDataSaver == bsp.mEnableDataSaver &&
+ mEnableFirewall == bsp.mEnableFirewall &&
+ mEnableNightMode == bsp.mEnableNightMode &&
+ mEnableQuickDoze == bsp.mEnableQuickDoze &&
+ mForceAllAppsStandby == bsp.mForceAllAppsStandby &&
+ mForceBackgroundCheck == bsp.mForceBackgroundCheck &&
+ mLocationMode == bsp.mLocationMode;
+ }
+
+private:
+ status_t readDeviceSpecificSettings(const android::Parcel *parcel);
+ status_t writeDeviceSpecificSettings(android::Parcel *parcel) const;
+ /** Adjust screen brightness factor */
+ float mAdjustBrightnessFactor;
+ /** Is advertise enabled */
+ bool mAdvertiseIsEnabled;
+ /** Defer full backup */
+ bool mDeferFullBackup;
+ /** Defer key value backup */
+ bool mDeferKeyValueBackup;
+ /** Device specific settings */
+ std::vector<std::pair<String16, String16>> mDeviceSpecificSettings;
+ /** Disable animation */
+ bool mDisableAnimation;
+ /** Disable Aod */
+ bool mDisableAod;
+ /** Disable launch boost */
+ bool mDisableLaunchBoost;
+ /** Disable optional sensors */
+ bool mDisableOptionalSensors;
+ /** Disable sound trigger */
+ bool mDisableSoundTrigger;
+ /** Disable vibration */
+ bool mDisableVibration;
+ /** Enable adjust brightness */
+ bool mEnableAdjustBrightness;
+ /** Enable data saver */
+ bool mEnableDataSaver;
+ /** Enable firewall */
+ bool mEnableFirewall;
+ /** Enable night mode */
+ bool mEnableNightMode;
+ /** Enable quick doze */
+ bool mEnableQuickDoze;
+ /** Force all Apps standby */
+ bool mForceAllAppsStandby;
+ /** Force Background check */
+ bool mForceBackgroundCheck;
+ /** Location mode */
+ LocationMode mLocationMode;
+};
+
+} // namespace android::os
+
+#endif /* ANDROID_OS_BATTERY_SAVER_POLICY_CONFIG_H */
diff --git a/services/powermanager/include/android/LocationMode.h b/services/powermanager/include/android/LocationMode.h
new file mode 100644
index 0000000..42933d4
--- /dev/null
+++ b/services/powermanager/include/android/LocationMode.h
@@ -0,0 +1,35 @@
+/*
+ * 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_OS_LOCATION_MODE_H
+#define ANDROID_OS_LOCATION_MODE_H
+
+namespace android::os {
+
+enum class LocationMode : int32_t {
+ NO_CHANGE = IPowerManager::LOCATION_MODE_NO_CHANGE,
+ GPS_DISABLED_WHEN_SCREEN_OFF = IPowerManager::LOCATION_MODE_GPS_DISABLED_WHEN_SCREEN_OFF,
+ ALL_DISABLED_WHEN_SCREEN_OFF = IPowerManager::LOCATION_MODE_ALL_DISABLED_WHEN_SCREEN_OFF,
+ FOREGROUND_ONLY = IPowerManager::LOCATION_MODE_FOREGROUND_ONLY,
+ THROTTLE_REQUESTS_WHEN_SCREEN_OFF =
+ IPowerManager::LOCATION_MODE_THROTTLE_REQUESTS_WHEN_SCREEN_OFF,
+ MIN = IPowerManager::LOCATION_MODE_NO_CHANGE,
+ MAX = IPowerManager::LOCATION_MODE_THROTTLE_REQUESTS_WHEN_SCREEN_OFF,
+};
+
+} // namespace android::os
+
+#endif /* ANDROID_OS_LOCATION_MODE_H */
diff --git a/services/powermanager/include/android/PowerSaveState.h b/services/powermanager/include/android/PowerSaveState.h
new file mode 100644
index 0000000..b421f6a
--- /dev/null
+++ b/services/powermanager/include/android/PowerSaveState.h
@@ -0,0 +1,70 @@
+/*
+ * 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_OS_POWER_SAVE_STATE_H
+#define ANDROID_OS_POWER_SAVE_STATE_H
+
+#include <math.h>
+#include <binder/Parcelable.h>
+#include <utils/RefBase.h>
+
+namespace android::os {
+
+enum class LocationMode : int32_t;
+/**
+ * PowerSaveState is a structure to encapsulate PowerSaveState status.
+ * This file needs to be kept in sync with frameworks/base/core/java/android/os/PowerSaveState.java
+ */
+struct PowerSaveState : public android::Parcelable {
+
+ PowerSaveState(bool batterySaverEnabled = false,
+ bool globalBatterySaverEnabled = false,
+ LocationMode locationMode = static_cast<LocationMode>(0),
+ float brightnessFactor = 0.5f)
+ : mBatterySaverEnabled(batterySaverEnabled),
+ mGlobalBatterySaverEnabled(globalBatterySaverEnabled),
+ mLocationMode(locationMode),
+ mBrightnessFactor(brightnessFactor) {
+ }
+
+ bool getBatterySaverEnabled() const { return mBatterySaverEnabled; }
+ bool getGlobalBatterySaverEnabled() const { return mGlobalBatterySaverEnabled; }
+ LocationMode getLocationMode() const { return mLocationMode; }
+ float getBrightnessFactor() const { return mBrightnessFactor; }
+ bool operator == (const PowerSaveState &ps) const {
+ return mBatterySaverEnabled == ps.mBatterySaverEnabled &&
+ mGlobalBatterySaverEnabled == ps.mGlobalBatterySaverEnabled &&
+ mLocationMode == ps.mLocationMode &&
+ fabs(mBrightnessFactor - ps.mBrightnessFactor) == 0.0f;
+ }
+
+ status_t readFromParcel(const android::Parcel* parcel) override;
+ status_t writeToParcel(android::Parcel* parcel) const override;
+
+private:
+ /** Whether we should enable battery saver for this service. */
+ bool mBatterySaverEnabled;
+ /** Whether battery saver mode is enabled. */
+ bool mGlobalBatterySaverEnabled;
+ /** Location mode */
+ LocationMode mLocationMode;
+ /** Screen brightness factor. */
+ float mBrightnessFactor;
+};
+
+} // namespace android::os
+
+#endif /* ANDROID_OS_POWER_SAVE_STATE_H */
diff --git a/services/powermanager/include/android/WorkSource.h b/services/powermanager/include/android/WorkSource.h
new file mode 100644
index 0000000..f12847d
--- /dev/null
+++ b/services/powermanager/include/android/WorkSource.h
@@ -0,0 +1,54 @@
+/*
+ * 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_OS_WORKSOURCE_H
+#define ANDROID_OS_WORKSOURCE_H
+
+#include <optional>
+#include <binder/Parcelable.h>
+#include <utils/RefBase.h>
+
+namespace android::os {
+
+/**
+ * WorkSource is a structure to describes the source of some work that may be done by someone else.
+ * This file needs to be kept in sync with frameworks/base/core/java/android/os/WorkSource.java
+ */
+struct WorkSource : public android::Parcelable {
+ WorkSource(
+ std::vector<int32_t> uids = {},
+ std::optional<std::vector<std::optional<String16>>> names = std::nullopt)
+ : mUids(uids),
+ mNames(names) {
+ }
+ std::vector<int32_t> getUids() const { return mUids; }
+ std::optional<std::vector<std::optional<String16>>> getNames() const { return mNames; }
+ bool operator == (const WorkSource &ws) const {
+ return mUids == ws.mUids && mNames == ws.mNames;
+ }
+ status_t readFromParcel(const android::Parcel* parcel) override;
+ status_t writeToParcel(android::Parcel* parcel) const override;
+
+private:
+ /** WorkSource UID array */
+ std::vector<int32_t> mUids = {};
+ /** WorkSource Tag array */
+ std::optional<std::vector<std::optional<String16>>> mNames = {};
+};
+
+} // namespace android::os
+
+#endif /* ANDROID_OS_WORKSOURCE_H */
diff --git a/services/powermanager/tests/Android.bp b/services/powermanager/tests/Android.bp
new file mode 100644
index 0000000..49abc11
--- /dev/null
+++ b/services/powermanager/tests/Android.bp
@@ -0,0 +1,45 @@
+// 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.
+
+cc_test {
+ name: "libpowermanager_test",
+ test_suites: ["device-tests"],
+ srcs: [
+ "IThermalManagerTest.cpp",
+ "PowerHalControllerTest.cpp",
+ "PowerHalLoaderTest.cpp",
+ "PowerHalWrapperAidlTest.cpp",
+ "PowerHalWrapperHidlV1_0Test.cpp",
+ "PowerHalWrapperHidlV1_1Test.cpp",
+ ],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-Wextra",
+ ],
+ shared_libs: [
+ "libbase",
+ "libbinder",
+ "libhidlbase",
+ "liblog",
+ "libpowermanager",
+ "libutils",
+ "android.hardware.power@1.0",
+ "android.hardware.power@1.1",
+ "android.hardware.power-cpp",
+ ],
+ static_libs: [
+ "libgmock",
+ ],
+}
diff --git a/services/powermanager/IThermalManagerTest.cpp b/services/powermanager/tests/IThermalManagerTest.cpp
similarity index 100%
rename from services/powermanager/IThermalManagerTest.cpp
rename to services/powermanager/tests/IThermalManagerTest.cpp
diff --git a/services/powermanager/tests/PowerHalControllerTest.cpp b/services/powermanager/tests/PowerHalControllerTest.cpp
new file mode 100644
index 0000000..141b244
--- /dev/null
+++ b/services/powermanager/tests/PowerHalControllerTest.cpp
@@ -0,0 +1,280 @@
+/*
+ * 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 "PowerHalControllerTest"
+
+#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/PowerHalController.h>
+#include <utils/Log.h>
+
+#include <thread>
+
+using android::hardware::power::Boost;
+using android::hardware::power::Mode;
+using android::hardware::power::V1_0::Feature;
+using android::hardware::power::V1_0::IPower;
+using android::hardware::power::V1_0::PowerHint;
+
+using namespace android;
+using namespace android::power;
+using namespace std::chrono_literals;
+using namespace testing;
+
+// -------------------------------------------------------------------------------------------------
+
+class MockIPowerV1_0 : public IPower {
+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));
+};
+
+class TestPowerHalConnector : public HalConnector {
+public:
+ TestPowerHalConnector(sp<IPower> powerHal) : mHal(std::move(powerHal)) {}
+ virtual ~TestPowerHalConnector() = default;
+
+ virtual std::unique_ptr<HalWrapper> connect() override {
+ mCountMutex.lock();
+ ++mConnectedCount;
+ mCountMutex.unlock();
+ return std::make_unique<HidlHalWrapperV1_0>(mHal);
+ }
+
+ void reset() override {
+ mCountMutex.lock();
+ ++mResetCount;
+ mCountMutex.unlock();
+ }
+
+ int getConnectCount() { return mConnectedCount; }
+
+ int getResetCount() { return mResetCount; }
+
+private:
+ sp<IPower> mHal = nullptr;
+ std::mutex mCountMutex;
+ int mConnectedCount = 0;
+ int mResetCount = 0;
+};
+
+class AlwaysFailingTestPowerHalConnector : public TestPowerHalConnector {
+public:
+ AlwaysFailingTestPowerHalConnector() : TestPowerHalConnector(nullptr) {}
+
+ std::unique_ptr<HalWrapper> connect() override {
+ // Call parent to update counter, but ignore connected HalWrapper.
+ TestPowerHalConnector::connect();
+ return nullptr;
+ }
+};
+
+// -------------------------------------------------------------------------------------------------
+
+class PowerHalControllerTest : public Test {
+public:
+ void SetUp() override {
+ mMockHal = new StrictMock<MockIPowerV1_0>();
+ std::unique_ptr<TestPowerHalConnector> halConnector =
+ std::make_unique<TestPowerHalConnector>(mMockHal);
+ mHalConnector = halConnector.get();
+ mHalController = std::make_unique<PowerHalController>(std::move(halConnector));
+ }
+
+protected:
+ sp<StrictMock<MockIPowerV1_0>> mMockHal = nullptr;
+ TestPowerHalConnector* mHalConnector = nullptr;
+ std::unique_ptr<PowerHalController> mHalController = nullptr;
+};
+
+// -------------------------------------------------------------------------------------------------
+
+TEST_F(PowerHalControllerTest, TestInitConnectsToPowerHalOnlyOnce) {
+ int powerHalConnectCount = mHalConnector->getConnectCount();
+ EXPECT_EQ(powerHalConnectCount, 0);
+
+ mHalController->init();
+ mHalController->init();
+
+ // PowerHalConnector was called only once and never reset.
+ powerHalConnectCount = mHalConnector->getConnectCount();
+ EXPECT_EQ(powerHalConnectCount, 1);
+ int powerHalResetCount = mHalConnector->getResetCount();
+ EXPECT_EQ(powerHalResetCount, 0);
+}
+
+TEST_F(PowerHalControllerTest, TestUnableToConnectToPowerHalIgnoresAllApiCalls) {
+ std::unique_ptr<AlwaysFailingTestPowerHalConnector> halConnector =
+ 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.
+ auto result = halController.setBoost(Boost::INTERACTION, 1000);
+ ASSERT_EQ(HalResult::UNSUPPORTED, result);
+ result = halController.setMode(Mode::LAUNCH, true);
+ ASSERT_EQ(HalResult::UNSUPPORTED, result);
+
+ // PowerHalConnector was called every time to attempt to reconnect with
+ // underlying service.
+ powerHalConnectCount = failingHalConnector->getConnectCount();
+ EXPECT_EQ(powerHalConnectCount, 2);
+ // PowerHalConnector was never reset.
+ int powerHalResetCount = mHalConnector->getResetCount();
+ EXPECT_EQ(powerHalResetCount, 0);
+}
+
+TEST_F(PowerHalControllerTest, TestAllApiCallsDelegatedToConnectedPowerHal) {
+ int powerHalConnectCount = mHalConnector->getConnectCount();
+ EXPECT_EQ(powerHalConnectCount, 0);
+
+ {
+ 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));
+ }
+
+ auto result = mHalController->setBoost(Boost::INTERACTION, 100);
+ ASSERT_EQ(HalResult::SUCCESSFUL, result);
+ result = mHalController->setMode(Mode::LAUNCH, true);
+ ASSERT_EQ(HalResult::SUCCESSFUL, result);
+
+ // PowerHalConnector was called only once and never reset.
+ powerHalConnectCount = mHalConnector->getConnectCount();
+ EXPECT_EQ(powerHalConnectCount, 1);
+ int powerHalResetCount = mHalConnector->getResetCount();
+ EXPECT_EQ(powerHalResetCount, 0);
+}
+
+TEST_F(PowerHalControllerTest, TestPowerHalRecoversFromFailureByRecreatingPowerHal) {
+ int powerHalConnectCount = mHalConnector->getConnectCount();
+ EXPECT_EQ(powerHalConnectCount, 0);
+
+ ON_CALL(*mMockHal.get(), powerHint(Eq(PowerHint::LAUNCH), _))
+ .WillByDefault([](PowerHint, int32_t) {
+ return hardware::Return<void>(hardware::Status::fromExceptionCode(-1));
+ });
+
+ EXPECT_CALL(*mMockHal.get(), powerHint(_, _)).Times(Exactly(4));
+
+ auto result = mHalController->setBoost(Boost::INTERACTION, 1000);
+ ASSERT_EQ(HalResult::SUCCESSFUL, result);
+ result = mHalController->setMode(Mode::LAUNCH, true);
+ ASSERT_EQ(HalResult::FAILED, result);
+ result = mHalController->setMode(Mode::VR, false);
+ ASSERT_EQ(HalResult::SUCCESSFUL, result);
+ result = mHalController->setMode(Mode::LOW_POWER, true);
+ ASSERT_EQ(HalResult::SUCCESSFUL, result);
+
+ // 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.
+ int powerHalResetCount = mHalConnector->getResetCount();
+ EXPECT_EQ(powerHalResetCount, 1);
+}
+
+TEST_F(PowerHalControllerTest, TestPowerHalDoesNotTryToRecoverFromFailureOnUnsupportedCalls) {
+ int powerHalConnectCount = mHalConnector->getConnectCount();
+ EXPECT_EQ(powerHalConnectCount, 0);
+
+ auto result = mHalController->setBoost(Boost::CAMERA_LAUNCH, 1000);
+ ASSERT_EQ(HalResult::UNSUPPORTED, result);
+ result = mHalController->setMode(Mode::CAMERA_STREAMING_HIGH, true);
+ ASSERT_EQ(HalResult::UNSUPPORTED, result);
+
+ // PowerHalConnector was called only once and never reset.
+ powerHalConnectCount = mHalConnector->getConnectCount();
+ EXPECT_EQ(powerHalConnectCount, 1);
+ int powerHalResetCount = mHalConnector->getResetCount();
+ EXPECT_EQ(powerHalResetCount, 0);
+}
+
+TEST_F(PowerHalControllerTest, TestMultiThreadConnectsOnlyOnce) {
+ int powerHalConnectCount = mHalConnector->getConnectCount();
+ EXPECT_EQ(powerHalConnectCount, 0);
+
+ 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(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.
+ powerHalConnectCount = mHalConnector->getConnectCount();
+ EXPECT_EQ(powerHalConnectCount, 1);
+ int powerHalResetCount = mHalConnector->getResetCount();
+ EXPECT_EQ(powerHalResetCount, 0);
+}
+
+TEST_F(PowerHalControllerTest, TestMultiThreadWithFailureReconnectIsThreadSafe) {
+ int powerHalConnectCount = mHalConnector->getConnectCount();
+ EXPECT_EQ(powerHalConnectCount, 0);
+
+ ON_CALL(*mMockHal.get(), powerHint(Eq(PowerHint::LAUNCH), _))
+ .WillByDefault([](PowerHint, int32_t) {
+ return hardware::Return<void>(hardware::Status::fromExceptionCode(-1));
+ });
+
+ 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(HalResult::SUCCESSFUL, result);
+ }));
+ threads.push_back(std::thread([&]() {
+ auto result = mHalController->setMode(Mode::LAUNCH, true);
+ ASSERT_EQ(HalResult::FAILED, result);
+ }));
+ threads.push_back(std::thread([&]() {
+ auto result = mHalController->setMode(Mode::LOW_POWER, false);
+ ASSERT_EQ(HalResult::SUCCESSFUL, result);
+ }));
+ threads.push_back(std::thread([&]() {
+ auto result = mHalController->setMode(Mode::VR, true);
+ 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.
+ powerHalConnectCount = mHalConnector->getConnectCount();
+ EXPECT_THAT(powerHalConnectCount, AllOf(Ge(1), Le(11)));
+ int powerHalResetCount = mHalConnector->getResetCount();
+ EXPECT_THAT(powerHalResetCount, Le(10));
+}
diff --git a/services/powermanager/tests/PowerHalLoaderTest.cpp b/services/powermanager/tests/PowerHalLoaderTest.cpp
new file mode 100644
index 0000000..058e1b5
--- /dev/null
+++ b/services/powermanager/tests/PowerHalLoaderTest.cpp
@@ -0,0 +1,110 @@
+/*
+ * 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 "PowerHalLoaderTest"
+
+#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>
+
+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;
+
+// -------------------------------------------------------------------------------------------------
+
+template <typename T>
+sp<T> loadHal();
+
+template <>
+sp<IPowerAidl> loadHal<IPowerAidl>() {
+ return PowerHalLoader::loadAidl();
+}
+
+template <>
+sp<IPowerV1_0> loadHal<IPowerV1_0>() {
+ return PowerHalLoader::loadHidlV1_0();
+}
+
+template <>
+sp<IPowerV1_1> loadHal<IPowerV1_1>() {
+ return PowerHalLoader::loadHidlV1_1();
+}
+
+// -------------------------------------------------------------------------------------------------
+
+template <typename T>
+class PowerHalLoaderTest : public Test {
+public:
+ sp<T> load() { return ::loadHal<T>(); }
+ void unload() { PowerHalLoader::unloadAll(); }
+};
+
+// -------------------------------------------------------------------------------------------------
+
+typedef ::testing::Types<IPowerAidl, IPowerV1_0, IPowerV1_1> PowerHalTypes;
+TYPED_TEST_SUITE(PowerHalLoaderTest, PowerHalTypes);
+
+TYPED_TEST(PowerHalLoaderTest, TestLoadsOnlyOnce) {
+ sp<TypeParam> firstHal = this->load();
+ if (firstHal == nullptr) {
+ ALOGE("Power HAL not available. Skipping test.");
+ return;
+ }
+ sp<TypeParam> secondHal = this->load();
+ ASSERT_EQ(firstHal, secondHal);
+}
+
+TYPED_TEST(PowerHalLoaderTest, TestUnload) {
+ sp<TypeParam> firstHal = this->load();
+ if (firstHal == nullptr) {
+ ALOGE("Power HAL not available. Skipping test.");
+ return;
+ }
+ this->unload();
+ sp<TypeParam> secondHal = this->load();
+ ASSERT_NE(secondHal, nullptr);
+ ASSERT_NE(firstHal, secondHal);
+}
+
+TYPED_TEST(PowerHalLoaderTest, TestLoadMultiThreadLoadsOnlyOnce) {
+ 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));
+ }
+
+ futures[0].wait();
+ sp<TypeParam> firstHal = futures[0].get();
+ if (firstHal == nullptr) {
+ ALOGE("Power HAL not available. Skipping test.");
+ return;
+ }
+
+ for (int i = 1; i < 10; i++) {
+ futures[i].wait();
+ sp<TypeParam> currentHal = futures[i].get();
+ ASSERT_EQ(firstHal, currentHal);
+ }
+}
diff --git a/services/powermanager/tests/PowerHalWrapperAidlTest.cpp b/services/powermanager/tests/PowerHalWrapperAidlTest.cpp
new file mode 100644
index 0000000..a765659
--- /dev/null
+++ b/services/powermanager/tests/PowerHalWrapperAidlTest.cpp
@@ -0,0 +1,199 @@
+/*
+ * 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 "PowerHalWrapperAidlTest"
+
+#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>
+
+using android::binder::Status;
+using android::hardware::power::Boost;
+using android::hardware::power::IPower;
+using android::hardware::power::Mode;
+
+using namespace android;
+using namespace android::power;
+using namespace std::chrono_literals;
+using namespace testing;
+
+// -------------------------------------------------------------------------------------------------
+
+class MockIPower : public IPower {
+public:
+ MOCK_METHOD(Status, isBoostSupported, (Boost boost, bool* ret), (override));
+ MOCK_METHOD(Status, setBoost, (Boost boost, int32_t durationMs), (override));
+ MOCK_METHOD(Status, isModeSupported, (Mode mode, bool* ret), (override));
+ MOCK_METHOD(Status, setMode, (Mode mode, bool enabled), (override));
+ MOCK_METHOD(int32_t, getInterfaceVersion, (), (override));
+ MOCK_METHOD(std::string, getInterfaceHash, (), (override));
+ MOCK_METHOD(IBinder*, onAsBinder, (), (override));
+};
+
+// -------------------------------------------------------------------------------------------------
+
+class PowerHalWrapperAidlTest : public Test {
+public:
+ void SetUp() override;
+
+protected:
+ std::unique_ptr<HalWrapper> mWrapper = nullptr;
+ sp<StrictMock<MockIPower>> mMockHal = nullptr;
+};
+
+// -------------------------------------------------------------------------------------------------
+
+void PowerHalWrapperAidlTest::SetUp() {
+ mMockHal = new StrictMock<MockIPower>();
+ mWrapper = std::make_unique<AidlHalWrapper>(mMockHal);
+ ASSERT_NE(mWrapper, nullptr);
+}
+
+// -------------------------------------------------------------------------------------------------
+
+TEST_F(PowerHalWrapperAidlTest, TestSetBoostSuccessful) {
+ {
+ InSequence seq;
+ EXPECT_CALL(*mMockHal.get(), isBoostSupported(Eq(Boost::DISPLAY_UPDATE_IMMINENT), _))
+ .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));
+ }
+
+ auto result = mWrapper->setBoost(Boost::DISPLAY_UPDATE_IMMINENT, 100);
+ 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())));
+ EXPECT_CALL(*mMockHal.get(), setBoost(Eq(Boost::INTERACTION), Eq(100)))
+ .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)));
+ }
+
+ auto result = mWrapper->setBoost(Boost::INTERACTION, 100);
+ ASSERT_EQ(HalResult::FAILED, result);
+ result = mWrapper->setBoost(Boost::DISPLAY_UPDATE_IMMINENT, 1000);
+ 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())));
+
+ auto result = mWrapper->setBoost(Boost::INTERACTION, 1000);
+ ASSERT_EQ(HalResult::UNSUPPORTED, result);
+ result = mWrapper->setBoost(Boost::CAMERA_SHOT, 10);
+ 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));
+ }
+
+ 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(HalResult::SUCCESSFUL, result);
+ }));
+ }
+ std::for_each(threads.begin(), threads.end(), [](std::thread& t) { t.join(); });
+}
+
+TEST_F(PowerHalWrapperAidlTest, TestSetModeSuccessful) {
+ {
+ InSequence seq;
+ EXPECT_CALL(*mMockHal.get(), isModeSupported(Eq(Mode::DISPLAY_INACTIVE), _))
+ .Times(Exactly(1))
+ .WillRepeatedly(DoAll(SetArgPointee<1>(true), Return(Status())));
+ EXPECT_CALL(*mMockHal.get(), setMode(Eq(Mode::DISPLAY_INACTIVE), Eq(false)))
+ .Times(Exactly(1));
+ }
+
+ auto result = mWrapper->setMode(Mode::DISPLAY_INACTIVE, false);
+ 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())));
+ EXPECT_CALL(*mMockHal.get(), setMode(Eq(Mode::LAUNCH), Eq(true)))
+ .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)));
+ }
+
+ auto result = mWrapper->setMode(Mode::LAUNCH, true);
+ ASSERT_EQ(HalResult::FAILED, result);
+ result = mWrapper->setMode(Mode::DISPLAY_INACTIVE, false);
+ 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())));
+
+ auto result = mWrapper->setMode(Mode::LAUNCH, true);
+ ASSERT_EQ(HalResult::UNSUPPORTED, result);
+ result = mWrapper->setMode(Mode::CAMERA_STREAMING_HIGH, true);
+ 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));
+ }
+
+ 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(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
new file mode 100644
index 0000000..6693d0b
--- /dev/null
+++ b/services/powermanager/tests/PowerHalWrapperHidlV1_0Test.cpp
@@ -0,0 +1,136 @@
+/*
+ * 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 "PowerHalWrapperHidlV1_0Test"
+
+#include <android/hardware/power/Boost.h>
+#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;
+using android::hardware::power::Mode;
+using android::hardware::power::V1_0::Feature;
+using android::hardware::power::V1_0::IPower;
+using android::hardware::power::V1_0::PowerHint;
+
+using namespace android;
+using namespace android::power;
+using namespace std::chrono_literals;
+using namespace testing;
+
+// -------------------------------------------------------------------------------------------------
+
+class MockIPowerV1_0 : public IPower {
+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));
+};
+
+// -------------------------------------------------------------------------------------------------
+
+class PowerHalWrapperHidlV1_0Test : public Test {
+public:
+ void SetUp() override;
+
+protected:
+ std::unique_ptr<HalWrapper> mWrapper = nullptr;
+ sp<StrictMock<MockIPowerV1_0>> mMockHal = nullptr;
+};
+
+// -------------------------------------------------------------------------------------------------
+
+void PowerHalWrapperHidlV1_0Test::SetUp() {
+ mMockHal = new StrictMock<MockIPowerV1_0>();
+ 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));
+
+ auto result = mWrapper->setBoost(Boost::INTERACTION, 1000);
+ 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));
+ });
+
+ auto result = mWrapper->setBoost(Boost::INTERACTION, 1000);
+ ASSERT_EQ(HalResult::FAILED, result);
+}
+
+TEST_F(PowerHalWrapperHidlV1_0Test, TestSetBoostUnsupported) {
+ auto result = mWrapper->setBoost(Boost::CAMERA_LAUNCH, 10);
+ 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::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));
+ EXPECT_CALL(*mMockHal.get(),
+ setFeature(Eq(Feature::POWER_FEATURE_DOUBLE_TAP_TO_WAKE), Eq(false)))
+ .Times(Exactly(1));
+ }
+
+ auto result = mWrapper->setMode(Mode::LAUNCH, true);
+ ASSERT_EQ(HalResult::SUCCESSFUL, result);
+ result = mWrapper->setMode(Mode::LOW_POWER, false);
+ ASSERT_EQ(HalResult::SUCCESSFUL, result);
+ result = mWrapper->setMode(Mode::SUSTAINED_PERFORMANCE, true);
+ ASSERT_EQ(HalResult::SUCCESSFUL, result);
+ result = mWrapper->setMode(Mode::VR, false);
+ ASSERT_EQ(HalResult::SUCCESSFUL, result);
+ result = mWrapper->setMode(Mode::INTERACTIVE, true);
+ ASSERT_EQ(HalResult::SUCCESSFUL, result);
+ result = mWrapper->setMode(Mode::DOUBLE_TAP_TO_WAKE, false);
+ 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));
+ });
+
+ auto result = mWrapper->setMode(Mode::LAUNCH, 1);
+ ASSERT_EQ(HalResult::FAILED, result);
+}
+
+TEST_F(PowerHalWrapperHidlV1_0Test, TestSetModeIgnored) {
+ auto result = mWrapper->setMode(Mode::CAMERA_STREAMING_HIGH, true);
+ ASSERT_EQ(HalResult::UNSUPPORTED, result);
+}
diff --git a/services/powermanager/tests/PowerHalWrapperHidlV1_1Test.cpp b/services/powermanager/tests/PowerHalWrapperHidlV1_1Test.cpp
new file mode 100644
index 0000000..55bbd6d
--- /dev/null
+++ b/services/powermanager/tests/PowerHalWrapperHidlV1_1Test.cpp
@@ -0,0 +1,157 @@
+/*
+ * 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 "PowerHalWrapperHidlV1_1Test"
+
+#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 <binder/IServiceManager.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.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 IPowerV1_1 = android::hardware::power::V1_1::IPower;
+using IPowerV1_0 = android::hardware::power::V1_0::IPower;
+
+using namespace android;
+using namespace android::power;
+using namespace std::chrono_literals;
+using namespace testing;
+
+// -------------------------------------------------------------------------------------------------
+
+class MockIPowerV1_0 : public IPowerV1_0 {
+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));
+};
+
+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));
+};
+
+// -------------------------------------------------------------------------------------------------
+
+class PowerHalWrapperHidlV1_1Test : public Test {
+public:
+ void SetUp() override;
+
+protected:
+ std::unique_ptr<HalWrapper> mWrapper = nullptr;
+ sp<StrictMock<MockIPowerV1_0>> mMockHalV1_0 = nullptr;
+ sp<StrictMock<MockIPowerV1_1>> mMockHalV1_1 = nullptr;
+};
+
+// -------------------------------------------------------------------------------------------------
+
+void PowerHalWrapperHidlV1_1Test::SetUp() {
+ mMockHalV1_0 = new StrictMock<MockIPowerV1_0>();
+ mMockHalV1_1 = new StrictMock<MockIPowerV1_1>();
+ mWrapper = std::make_unique<HidlHalWrapperV1_1>(mMockHalV1_0, mMockHalV1_1);
+ ASSERT_NE(mWrapper, nullptr);
+}
+
+// -------------------------------------------------------------------------------------------------
+
+TEST_F(PowerHalWrapperHidlV1_1Test, TestSetBoostSuccessful) {
+ EXPECT_CALL(*mMockHalV1_1.get(), powerHintAsync(Eq(PowerHint::INTERACTION), Eq(1000)))
+ .Times(Exactly(1));
+
+ auto result = mWrapper->setBoost(Boost::INTERACTION, 1000);
+ 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));
+ });
+
+ auto result = mWrapper->setBoost(Boost::INTERACTION, 1000);
+ ASSERT_EQ(HalResult::FAILED, result);
+}
+
+TEST_F(PowerHalWrapperHidlV1_1Test, TestSetBoostUnsupported) {
+ auto result = mWrapper->setBoost(Boost::CAMERA_LAUNCH, 10);
+ 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));
+ 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));
+ 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));
+ EXPECT_CALL(*mMockHalV1_0.get(),
+ setFeature(Eq(Feature::POWER_FEATURE_DOUBLE_TAP_TO_WAKE), Eq(false)))
+ .Times(Exactly(1));
+ }
+
+ auto result = mWrapper->setMode(Mode::LAUNCH, true);
+ ASSERT_EQ(HalResult::SUCCESSFUL, result);
+ result = mWrapper->setMode(Mode::LOW_POWER, false);
+ ASSERT_EQ(HalResult::SUCCESSFUL, result);
+ result = mWrapper->setMode(Mode::SUSTAINED_PERFORMANCE, true);
+ ASSERT_EQ(HalResult::SUCCESSFUL, result);
+ result = mWrapper->setMode(Mode::VR, false);
+ ASSERT_EQ(HalResult::SUCCESSFUL, result);
+ result = mWrapper->setMode(Mode::INTERACTIVE, true);
+ ASSERT_EQ(HalResult::SUCCESSFUL, result);
+ result = mWrapper->setMode(Mode::DOUBLE_TAP_TO_WAKE, false);
+ 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));
+ });
+
+ auto result = mWrapper->setMode(Mode::LAUNCH, 1);
+ ASSERT_EQ(HalResult::FAILED, result);
+}
+
+TEST_F(PowerHalWrapperHidlV1_1Test, TestSetModeIgnored) {
+ auto result = mWrapper->setMode(Mode::CAMERA_STREAMING_HIGH, true);
+ ASSERT_EQ(HalResult::UNSUPPORTED, result);
+}
diff --git a/services/sensorservice/SensorDevice.cpp b/services/sensorservice/SensorDevice.cpp
index 8a282e2..e355594 100644
--- a/services/sensorservice/SensorDevice.cpp
+++ b/services/sensorservice/SensorDevice.cpp
@@ -153,12 +153,18 @@
SensorDeviceUtils::defaultResolutionForType(sensor.type);
}
- double promotedResolution = sensor.resolution;
- double promotedMaxRange = sensor.maxRange;
- if (fmod(promotedMaxRange, promotedResolution) != 0) {
- ALOGW("%s's max range %f is not a multiple of the resolution %f",
- sensor.name, sensor.maxRange, sensor.resolution);
- SensorDeviceUtils::quantizeValue(&sensor.maxRange, promotedResolution);
+ // Some sensors don't have a default resolution and will be left at 0.
+ // Don't crash in this case since CTS will verify that devices don't go to
+ // production with a resolution of 0.
+ if (sensor.resolution != 0) {
+ double promotedResolution = sensor.resolution;
+ double promotedMaxRange = sensor.maxRange;
+ if (fmod(promotedMaxRange, promotedResolution) != 0) {
+ ALOGW("%s's max range %f is not a multiple of the resolution %f",
+ sensor.name, sensor.maxRange, sensor.resolution);
+ SensorDeviceUtils::quantizeValue(
+ &sensor.maxRange, promotedResolution);
+ }
}
}
diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
index 60f9cd9..aa0dc92 100644
--- a/services/sensorservice/SensorService.cpp
+++ b/services/sensorservice/SensorService.cpp
@@ -699,6 +699,9 @@
if (!checkCallingPermission(sManageSensorsPermission, nullptr, nullptr)) {
return PERMISSION_DENIED;
}
+ if (args.size() == 0) {
+ return BAD_INDEX;
+ }
if (in == BAD_TYPE || out == BAD_TYPE || err == BAD_TYPE) {
return BAD_VALUE;
}
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index a790d0b..804a3c3 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -145,6 +145,7 @@
"DisplayHardware/HWComposer.cpp",
"DisplayHardware/PowerAdvisor.cpp",
"DisplayHardware/VirtualDisplaySurface.cpp",
+ "DisplayRenderArea.cpp",
"Effects/Daltonizer.cpp",
"EventLog/EventLog.cpp",
"FrameTracer/FrameTracer.cpp",
@@ -152,6 +153,7 @@
"Layer.cpp",
"LayerProtoHelper.cpp",
"LayerRejecter.cpp",
+ "LayerRenderArea.cpp",
"LayerVector.cpp",
"MonitoredProducer.cpp",
"NativeWindowSurface.cpp",
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index f0b0200..cf60b71 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -539,20 +539,6 @@
return (buffer != 0) && (buffer->getUsage() & GRALLOC_USAGE_PROTECTED);
}
-bool BufferLayer::latchUnsignaledBuffers() {
- static bool propertyLoaded = false;
- static bool latch = false;
- static std::mutex mutex;
- std::lock_guard<std::mutex> lock(mutex);
- if (!propertyLoaded) {
- char value[PROPERTY_VALUE_MAX] = {};
- property_get("debug.sf.latch_unsignaled", value, "0");
- latch = atoi(value);
- propertyLoaded = true;
- }
- return latch;
-}
-
// h/w composer set-up
bool BufferLayer::allTransactionsSignaled(nsecs_t expectedPresentTime) {
const auto headFrameNumber = getHeadFrameNumber(expectedPresentTime);
diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h
index 26bfb49..2483abb 100644
--- a/services/surfaceflinger/BufferLayer.h
+++ b/services/surfaceflinger/BufferLayer.h
@@ -187,9 +187,6 @@
bool onPreComposition(nsecs_t) override;
void preparePerFrameCompositionState() override;
- // Loads the corresponding system property once per process
- static bool latchUnsignaledBuffers();
-
// Check all of the local sync points to ensure that all transactions
// which need to have been applied prior to the frame which is about to
// be latched have signaled
diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp
index 07be791..1156f55 100644
--- a/services/surfaceflinger/BufferQueueLayer.cpp
+++ b/services/surfaceflinger/BufferQueueLayer.cpp
@@ -131,10 +131,6 @@
// -----------------------------------------------------------------------
bool BufferQueueLayer::fenceHasSignaled() const {
- if (latchUnsignaledBuffers()) {
- return true;
- }
-
if (!hasFrameUpdate()) {
return true;
}
@@ -208,8 +204,12 @@
}
bool BufferQueueLayer::latchSidebandStream(bool& recomputeVisibleRegions) {
+ // We need to update the sideband stream if the layer has both a buffer and a sideband stream.
+ const bool updateSidebandStream = hasFrameUpdate() && mSidebandStream.get();
+
bool sidebandStreamChanged = true;
- if (mSidebandStreamChanged.compare_exchange_strong(sidebandStreamChanged, false)) {
+ if (mSidebandStreamChanged.compare_exchange_strong(sidebandStreamChanged, false) ||
+ updateSidebandStream) {
// mSidebandStreamChanged was changed to false
mSidebandStream = mConsumer->getSidebandStream();
auto* layerCompositionState = editCompositionState();
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index 790f2ec..884cc0c 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -422,10 +422,6 @@
// Interface implementation for BufferLayer
// -----------------------------------------------------------------------
bool BufferStateLayer::fenceHasSignaled() const {
- if (latchUnsignaledBuffers()) {
- return true;
- }
-
const bool fenceSignaled =
getDrawingState().acquireFence->getStatus() == Fence::Status::Signaled;
if (!fenceSignaled) {
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index e8f54f5..b07c904 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -921,9 +921,8 @@
const nsecs_t renderEngineStart = systemTime();
status_t status =
- renderEngine.drawLayers(clientCompositionDisplay, clientCompositionLayerPointers,
- buf->getNativeBuffer(), /*useFramebufferCache=*/true,
- std::move(fd), &readyFence);
+ renderEngine.drawLayers(clientCompositionDisplay, clientCompositionLayerPointers, buf,
+ /*useFramebufferCache=*/true, std::move(fd), &readyFence);
if (status != NO_ERROR && mClientCompositionRequestCache) {
// If rendering was not successful, remove the request from the cache.
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index 730f297..9aa274b 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -116,6 +116,10 @@
}
}
+void DisplayDevice::setDeviceProductInfo(std::optional<DeviceProductInfo> info) {
+ mDeviceProductInfo = std::move(info);
+}
+
uint32_t DisplayDevice::getPageFlipCount() const {
return mCompositionDisplay->getRenderSurface()->getPageFlipCount();
}
@@ -269,6 +273,12 @@
StringAppendF(&result, "powerMode=%s (%d), ", to_string(mPowerMode).c_str(),
static_cast<int32_t>(mPowerMode));
StringAppendF(&result, "activeConfig=%d, ", mActiveConfig.value());
+ StringAppendF(&result, "deviceProductInfo=");
+ if (mDeviceProductInfo) {
+ mDeviceProductInfo->dump(result);
+ } else {
+ result.append("{}");
+ }
getCompositionDisplay()->dump(result);
}
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index cb467ea..576488c 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -40,7 +40,6 @@
#include "DisplayHardware/DisplayIdentification.h"
#include "DisplayHardware/Hal.h"
#include "DisplayHardware/PowerAdvisor.h"
-#include "RenderArea.h"
#include "Scheduler/HwcStrongTypes.h"
namespace android {
@@ -59,12 +58,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 {
@@ -136,6 +137,11 @@
void setDisplayName(const std::string& displayName);
const std::string& getDisplayName() const { return mDisplayName; }
+ void setDeviceProductInfo(std::optional<DeviceProductInfo> info);
+ const std::optional<DeviceProductInfo>& getDeviceProductInfo() const {
+ return mDeviceProductInfo;
+ }
+
/* ------------------------------------------------------------------------
* Display power mode management.
*/
@@ -182,6 +188,8 @@
// TODO(b/74619554): Remove special cases for primary display.
const bool mIsPrimary;
+
+ std::optional<DeviceProductInfo> mDeviceProductInfo;
};
struct DisplayDeviceState {
@@ -189,7 +197,7 @@
DisplayId id;
DisplayConnectionType type;
hardware::graphics::composer::hal::HWDisplayId hwcDisplayId;
-
+ std::optional<DeviceProductInfo> deviceProductInfo;
bool operator==(const Physical& other) const {
return id == other.id && type == other.type && hwcDisplayId == other.hwcDisplayId;
}
@@ -237,118 +245,4 @@
bool isPrimary{false};
};
-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) {}
-
- const ui::Transform& getTransform() const override { return mTransform; }
- Rect getBounds() const override { return mDisplay->getBounds(); }
- int getHeight() const override { return mDisplay->getHeight(); }
- int getWidth() const override { return mDisplay->getWidth(); }
- bool isSecure() const override { return mAllowSecureLayers && mDisplay->isSecure(); }
- sp<const DisplayDevice> getDisplayDevice() const override { return mDisplay; }
-
- bool needsFiltering() const override {
- // check if the projection from the logical render area
- // to the physical render area requires filtering
- const Rect& sourceCrop = getSourceCrop();
- int width = sourceCrop.width();
- int height = sourceCrop.height();
- if (getRotationFlags() & ui::Transform::ROT_90) {
- std::swap(width, height);
- }
- return width != getReqWidth() || height != getReqHeight();
- }
-
- Rect getSourceCrop() const override {
- // use the projected display viewport by default.
- if (mSourceCrop.isEmpty()) {
- return mDisplay->getSourceClip();
- }
-
- // If there is a source crop provided then it is assumed that the device
- // was in portrait orientation. This may not logically be true, so
- // correct for the orientation error by undoing the rotation
-
- ui::Rotation logicalOrientation = mDisplay->getOrientation();
- if (logicalOrientation == ui::Rotation::Rotation90) {
- logicalOrientation = ui::Rotation::Rotation270;
- } else if (logicalOrientation == ui::Rotation::Rotation270) {
- logicalOrientation = ui::Rotation::Rotation90;
- }
-
- const auto flags = ui::Transform::toRotationFlags(logicalOrientation);
- int width = mDisplay->getSourceClip().getWidth();
- int height = mDisplay->getSourceClip().getHeight();
- ui::Transform rotation;
- rotation.set(flags, width, height);
- return rotation.transform(mSourceCrop);
- }
-
-private:
- static RotationFlags applyDeviceOrientation(RotationFlags orientationFlag,
- const sp<const DisplayDevice>& device) {
- uint32_t inverseRotate90 = 0;
- uint32_t inverseReflect = 0;
-
- // Reverse the logical orientation.
- ui::Rotation logicalOrientation = device->getOrientation();
- if (logicalOrientation == ui::Rotation::Rotation90) {
- logicalOrientation = ui::Rotation::Rotation270;
- } else if (logicalOrientation == ui::Rotation::Rotation270) {
- logicalOrientation = ui::Rotation::Rotation90;
- }
-
- const ui::Rotation orientation = device->getPhysicalOrientation() + logicalOrientation;
-
- switch (orientation) {
- case ui::ROTATION_0:
- return orientationFlag;
-
- case ui::ROTATION_90:
- inverseRotate90 = ui::Transform::ROT_90;
- inverseReflect = ui::Transform::ROT_180;
- break;
-
- case ui::ROTATION_180:
- inverseReflect = ui::Transform::ROT_180;
- break;
-
- case ui::ROTATION_270:
- inverseRotate90 = ui::Transform::ROT_90;
- break;
- }
-
- const uint32_t rotate90 = orientationFlag & ui::Transform::ROT_90;
- uint32_t reflect = orientationFlag & ui::Transform::ROT_180;
-
- // Apply reflection for double rotation.
- if (rotate90 & inverseRotate90) {
- reflect = ~reflect & ui::Transform::ROT_180;
- }
-
- return static_cast<RotationFlags>((rotate90 ^ inverseRotate90) |
- (reflect ^ inverseReflect));
- }
-
- const sp<const DisplayDevice> mDisplay;
- const Rect mSourceCrop;
- const bool mAllowSecureLayers;
- const ui::Transform mTransform = ui::Transform();
-};
-
} // namespace android
diff --git a/services/surfaceflinger/DisplayHardware/DisplayIdentification.cpp b/services/surfaceflinger/DisplayHardware/DisplayIdentification.cpp
index 4dfc743..52a6380 100644
--- a/services/surfaceflinger/DisplayHardware/DisplayIdentification.cpp
+++ b/services/surfaceflinger/DisplayHardware/DisplayIdentification.cpp
@@ -71,12 +71,8 @@
DeviceProductInfo buildDeviceProductInfo(const Edid& edid) {
DeviceProductInfo info;
- std::copy(edid.displayName.begin(), edid.displayName.end(), info.name.begin());
- info.name[edid.displayName.size()] = '\0';
-
- const auto productId = std::to_string(edid.productId);
- std::copy(productId.begin(), productId.end(), info.productId.begin());
- info.productId[productId.size()] = '\0';
+ info.name.assign(edid.displayName);
+ info.productId = std::to_string(edid.productId);
info.manufacturerPnpId = edid.pnpId;
constexpr uint8_t kModelYearFlag = 0xff;
@@ -99,8 +95,6 @@
if (edid.cea861Block && edid.cea861Block->hdmiVendorDataBlock) {
const auto& address = edid.cea861Block->hdmiVendorDataBlock->physicalAddress;
info.relativeAddress = {address.a, address.b, address.c, address.d};
- } else {
- info.relativeAddress = DeviceProductInfo::NO_RELATIVE_ADDRESS;
}
return info;
}
@@ -238,7 +232,6 @@
constexpr size_t kDescriptorCount = 4;
constexpr size_t kDescriptorLength = 18;
- static_assert(kDescriptorLength - kEdidHeaderLength < DeviceProductInfo::TEXT_BUFFER_SIZE);
for (size_t i = 0; i < kDescriptorCount; i++) {
if (view.size() < kDescriptorLength) {
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/DisplayRenderArea.cpp b/services/surfaceflinger/DisplayRenderArea.cpp
new file mode 100644
index 0000000..7cd283d
--- /dev/null
+++ b/services/surfaceflinger/DisplayRenderArea.cpp
@@ -0,0 +1,154 @@
+/*
+ * 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.
+ */
+
+#include "DisplayRenderArea.h"
+#include "DisplayDevice.h"
+
+namespace android {
+namespace {
+
+RenderArea::RotationFlags applyDeviceOrientation(RenderArea::RotationFlags rotation,
+ const DisplayDevice& display) {
+ uint32_t inverseRotate90 = 0;
+ uint32_t inverseReflect = 0;
+
+ // Reverse the logical orientation.
+ ui::Rotation logicalOrientation = display.getOrientation();
+ if (logicalOrientation == ui::Rotation::Rotation90) {
+ logicalOrientation = ui::Rotation::Rotation270;
+ } else if (logicalOrientation == ui::Rotation::Rotation270) {
+ logicalOrientation = ui::Rotation::Rotation90;
+ }
+
+ const ui::Rotation orientation = display.getPhysicalOrientation() + logicalOrientation;
+
+ switch (orientation) {
+ case ui::ROTATION_0:
+ return rotation;
+
+ case ui::ROTATION_90:
+ inverseRotate90 = ui::Transform::ROT_90;
+ inverseReflect = ui::Transform::ROT_180;
+ break;
+
+ case ui::ROTATION_180:
+ inverseReflect = ui::Transform::ROT_180;
+ break;
+
+ case ui::ROTATION_270:
+ inverseRotate90 = ui::Transform::ROT_90;
+ break;
+ }
+
+ const uint32_t rotate90 = rotation & ui::Transform::ROT_90;
+ uint32_t reflect = rotation & ui::Transform::ROT_180;
+
+ // Apply reflection for double rotation.
+ if (rotate90 & inverseRotate90) {
+ reflect = ~reflect & ui::Transform::ROT_180;
+ }
+
+ return static_cast<RenderArea::RotationFlags>((rotate90 ^ inverseRotate90) |
+ (reflect ^ inverseReflect));
+}
+
+} // namespace
+
+std::unique_ptr<RenderArea> DisplayRenderArea::create(wp<const DisplayDevice> displayWeak,
+ const Rect& sourceCrop, ui::Size reqSize,
+ ui::Dataspace reqDataSpace,
+ RotationFlags rotation,
+ bool allowSecureLayers) {
+ 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;
+}
+
+DisplayRenderArea::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) {}
+
+const ui::Transform& DisplayRenderArea::getTransform() const {
+ return mTransform;
+}
+
+Rect DisplayRenderArea::getBounds() const {
+ return mDisplay->getBounds();
+}
+
+int DisplayRenderArea::getHeight() const {
+ return mDisplay->getHeight();
+}
+
+int DisplayRenderArea::getWidth() const {
+ return mDisplay->getWidth();
+}
+
+bool DisplayRenderArea::isSecure() const {
+ return mAllowSecureLayers && mDisplay->isSecure();
+}
+
+sp<const DisplayDevice> DisplayRenderArea::getDisplayDevice() const {
+ return mDisplay;
+}
+
+bool DisplayRenderArea::needsFiltering() const {
+ // check if the projection from the logical render area
+ // to the physical render area requires filtering
+ const Rect& sourceCrop = getSourceCrop();
+ int width = sourceCrop.width();
+ int height = sourceCrop.height();
+ if (getRotationFlags() & ui::Transform::ROT_90) {
+ std::swap(width, height);
+ }
+ return width != getReqWidth() || height != getReqHeight();
+}
+
+Rect DisplayRenderArea::getSourceCrop() const {
+ // use the projected display viewport by default.
+ if (mSourceCrop.isEmpty()) {
+ return mDisplay->getSourceClip();
+ }
+
+ // If there is a source crop provided then it is assumed that the device
+ // was in portrait orientation. This may not logically be true, so
+ // correct for the orientation error by undoing the rotation
+
+ ui::Rotation logicalOrientation = mDisplay->getOrientation();
+ if (logicalOrientation == ui::Rotation::Rotation90) {
+ logicalOrientation = ui::Rotation::Rotation270;
+ } else if (logicalOrientation == ui::Rotation::Rotation270) {
+ logicalOrientation = ui::Rotation::Rotation90;
+ }
+
+ const auto flags = ui::Transform::toRotationFlags(logicalOrientation);
+ int width = mDisplay->getSourceClip().getWidth();
+ int height = mDisplay->getSourceClip().getHeight();
+ ui::Transform rotation;
+ rotation.set(flags, width, height);
+ return rotation.transform(mSourceCrop);
+}
+
+} // namespace android
\ No newline at end of file
diff --git a/services/surfaceflinger/DisplayRenderArea.h b/services/surfaceflinger/DisplayRenderArea.h
new file mode 100644
index 0000000..340efb5
--- /dev/null
+++ b/services/surfaceflinger/DisplayRenderArea.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <ui/GraphicTypes.h>
+#include <ui/Transform.h>
+
+#include "RenderArea.h"
+
+namespace android {
+
+class DisplayDevice;
+
+class DisplayRenderArea : public RenderArea {
+public:
+ static std::unique_ptr<RenderArea> create(wp<const DisplayDevice>, const Rect& sourceCrop,
+ ui::Size reqSize, ui::Dataspace,
+ RotationFlags rotation,
+ bool allowSecureLayers = true);
+
+ const ui::Transform& getTransform() const override;
+ Rect getBounds() const override;
+ int getHeight() const override;
+ int getWidth() const override;
+ bool isSecure() const override;
+ sp<const DisplayDevice> getDisplayDevice() const override;
+ bool needsFiltering() const override;
+ Rect getSourceCrop() const override;
+
+private:
+ DisplayRenderArea(sp<const DisplayDevice>, const Rect& sourceCrop, ui::Size reqSize,
+ ui::Dataspace, RotationFlags rotation, bool allowSecureLayers = true);
+
+ const sp<const DisplayDevice> mDisplay;
+ const Rect mSourceCrop;
+ const bool mAllowSecureLayers;
+ const ui::Transform mTransform;
+};
+
+} // namespace android
\ No newline at end of file
diff --git a/services/surfaceflinger/FrameTracer/FrameTracer.cpp b/services/surfaceflinger/FrameTracer/FrameTracer.cpp
index b986f38..2dfb9a9 100644
--- a/services/surfaceflinger/FrameTracer/FrameTracer.cpp
+++ b/services/surfaceflinger/FrameTracer/FrameTracer.cpp
@@ -25,7 +25,7 @@
#include "FrameTracer.h"
#include <android-base/stringprintf.h>
-#include <perfetto/trace/clock_snapshot.pbzero.h>
+#include <perfetto/common/builtin_clock.pbzero.h>
#include <algorithm>
#include <mutex>
@@ -34,7 +34,6 @@
namespace android {
-using Clock = perfetto::protos::pbzero::ClockSnapshot::Clock;
void FrameTracer::initialize() {
std::call_once(mInitializationFlag, [this]() {
perfetto::TracingInitArgs args;
@@ -136,7 +135,7 @@
uint64_t bufferID, uint64_t frameNumber, nsecs_t timestamp,
FrameEvent::BufferEventType type, nsecs_t duration) {
auto packet = ctx.NewTracePacket();
- packet->set_timestamp_clock_id(Clock::MONOTONIC);
+ packet->set_timestamp_clock_id(perfetto::protos::pbzero::BUILTIN_CLOCK_MONOTONIC);
packet->set_timestamp(timestamp);
auto* event = packet->set_graphics_frame_event()->set_buffer_event();
event->set_buffer_id(static_cast<uint32_t>(bufferID));
diff --git a/services/surfaceflinger/FrameTracer/OWNERS b/services/surfaceflinger/FrameTracer/OWNERS
new file mode 100644
index 0000000..e4f5d45
--- /dev/null
+++ b/services/surfaceflinger/FrameTracer/OWNERS
@@ -0,0 +1 @@
+adsrini@google.com
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 03903f6..2ed363a 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -1820,7 +1820,7 @@
onRemovedFromCurrentState();
}
- if (callSetTransactionFlags || attachChildren()) {
+ if (attachChildren() || callSetTransactionFlags) {
setTransactionFlags(eTransactionNeeded);
}
return true;
@@ -1848,9 +1848,9 @@
if (client != nullptr && parentClient != client) {
if (child->mLayerDetached) {
child->mLayerDetached = false;
+ child->attachChildren();
changed = true;
}
- changed |= child->attachChildren();
}
}
@@ -2245,6 +2245,7 @@
layerInfo->set_effective_scaling_mode(getEffectiveScalingMode());
layerInfo->set_corner_radius(getRoundedCornerState().radius);
+ layerInfo->set_background_blur_radius(getBackgroundBlurRadius());
LayerProtoHelper::writeToProto(transform, layerInfo->mutable_transform());
LayerProtoHelper::writePositionToProto(transform.tx(), transform.ty(),
[&]() { return layerInfo->mutable_position(); });
diff --git a/services/surfaceflinger/LayerRenderArea.cpp b/services/surfaceflinger/LayerRenderArea.cpp
new file mode 100644
index 0000000..c4f8666
--- /dev/null
+++ b/services/surfaceflinger/LayerRenderArea.cpp
@@ -0,0 +1,113 @@
+/*
+ * 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.
+ */
+
+#include <ui/GraphicTypes.h>
+#include <ui/Transform.h>
+
+#include "ContainerLayer.h"
+#include "DisplayDevice.h"
+#include "Layer.h"
+#include "LayerRenderArea.h"
+#include "SurfaceFlinger.h"
+
+namespace android {
+namespace {
+
+struct ReparentForDrawing {
+ const sp<Layer>& oldParent;
+
+ ReparentForDrawing(const sp<Layer>& oldParent, const sp<Layer>& newParent,
+ const Rect& drawingBounds)
+ : oldParent(oldParent) {
+ // Compute and cache the bounds for the new parent layer.
+ newParent->computeBounds(drawingBounds.toFloatRect(), ui::Transform(),
+ 0.f /* shadowRadius */);
+ oldParent->setChildrenDrawingParent(newParent);
+ }
+ ~ReparentForDrawing() { oldParent->setChildrenDrawingParent(oldParent); }
+};
+
+} // namespace
+
+LayerRenderArea::LayerRenderArea(SurfaceFlinger& flinger, sp<Layer> layer, const Rect& crop,
+ ui::Size reqSize, ui::Dataspace reqDataSpace, bool childrenOnly,
+ const Rect& displayViewport)
+ : RenderArea(reqSize, CaptureFill::CLEAR, reqDataSpace, displayViewport),
+ mLayer(std::move(layer)),
+ mCrop(crop),
+ mFlinger(flinger),
+ mChildrenOnly(childrenOnly) {}
+
+const ui::Transform& LayerRenderArea::getTransform() const {
+ return mTransform;
+}
+
+Rect LayerRenderArea::getBounds() const {
+ return mLayer->getBufferSize(mLayer->getDrawingState());
+}
+
+int LayerRenderArea::getHeight() const {
+ return mLayer->getBufferSize(mLayer->getDrawingState()).getHeight();
+}
+
+int LayerRenderArea::getWidth() const {
+ return mLayer->getBufferSize(mLayer->getDrawingState()).getWidth();
+}
+
+bool LayerRenderArea::isSecure() const {
+ return false;
+}
+
+bool LayerRenderArea::needsFiltering() const {
+ return mNeedsFiltering;
+}
+
+sp<const DisplayDevice> LayerRenderArea::getDisplayDevice() const {
+ return nullptr;
+}
+
+Rect LayerRenderArea::getSourceCrop() const {
+ if (mCrop.isEmpty()) {
+ return getBounds();
+ } else {
+ return mCrop;
+ }
+}
+
+void LayerRenderArea::render(std::function<void()> drawLayers) {
+ using namespace std::string_literals;
+
+ const Rect sourceCrop = getSourceCrop();
+ // no need to check rotation because there is none
+ mNeedsFiltering = sourceCrop.width() != getReqWidth() || sourceCrop.height() != getReqHeight();
+
+ if (!mChildrenOnly) {
+ mTransform = mLayer->getTransform().inverse();
+ drawLayers();
+ } else {
+ uint32_t w = static_cast<uint32_t>(getWidth());
+ uint32_t h = static_cast<uint32_t>(getHeight());
+ // In the "childrenOnly" case we reparent the children to a screenshot
+ // layer which has no properties set and which does not draw.
+ sp<ContainerLayer> screenshotParentLayer = mFlinger.getFactory().createContainerLayer(
+ {&mFlinger, nullptr, "Screenshot Parent"s, w, h, 0, LayerMetadata()});
+
+ ReparentForDrawing reparent(mLayer, screenshotParentLayer, sourceCrop);
+ drawLayers();
+ }
+}
+
+} // namespace android
diff --git a/services/surfaceflinger/LayerRenderArea.h b/services/surfaceflinger/LayerRenderArea.h
new file mode 100644
index 0000000..81690b9
--- /dev/null
+++ b/services/surfaceflinger/LayerRenderArea.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <string>
+
+#include <ui/GraphicTypes.h>
+#include <ui/Transform.h>
+#include <utils/StrongPointer.h>
+
+#include "RenderArea.h"
+
+namespace android {
+
+class DisplayDevice;
+class Layer;
+class SurfaceFlinger;
+
+class LayerRenderArea : public RenderArea {
+public:
+ LayerRenderArea(SurfaceFlinger& flinger, sp<Layer> layer, const Rect& crop, ui::Size reqSize,
+ ui::Dataspace reqDataSpace, bool childrenOnly, const Rect& displayViewport);
+
+ const ui::Transform& getTransform() const override;
+ Rect getBounds() const override;
+ int getHeight() const override;
+ int getWidth() const override;
+ bool isSecure() const override;
+ bool needsFiltering() const override;
+ sp<const DisplayDevice> getDisplayDevice() const override;
+ Rect getSourceCrop() const override;
+
+ void render(std::function<void()> drawLayers) override;
+
+private:
+ const sp<Layer> mLayer;
+ const Rect mCrop;
+
+ ui::Transform mTransform;
+ bool mNeedsFiltering = false;
+
+ SurfaceFlinger& mFlinger;
+ const bool mChildrenOnly;
+};
+
+} // namespace android
\ No newline at end of file
diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp
index 27353d8..899d1fa 100644
--- a/services/surfaceflinger/RegionSamplingThread.cpp
+++ b/services/surfaceflinger/RegionSamplingThread.cpp
@@ -35,7 +35,9 @@
#include <string>
#include "DisplayDevice.h"
+#include "DisplayRenderArea.h"
#include "Layer.h"
+#include "Promise.h"
#include "Scheduler/DispSync.h"
#include "SurfaceFlinger.h"
@@ -336,8 +338,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 +360,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 +380,14 @@
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, screencapRegion.bounds(),
+ sampledBounds.getSize(), ui::Dataspace::V0_SRGB,
+ orientation);
+ });
std::unordered_set<sp<IRegionSamplingListener>, SpHash<IRegionSamplingListener>> listeners;
@@ -393,9 +411,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 +429,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 +455,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/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 9d65f2f..aa7b903 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -28,8 +28,10 @@
#include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
#include <android/hardware/configstore/1.1/ISurfaceFlingerConfigs.h>
#include <android/hardware/configstore/1.1/types.h>
-#include <android/hardware/power/1.0/IPower.h>
+#include <android/hardware/power/Boost.h>
#include <android/native_window.h>
+#include <android/os/BnSetInputWindowsListener.h>
+#include <android/os/IInputFlinger.h>
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
#include <binder/PermissionCache.h>
@@ -58,7 +60,6 @@
#include <gui/LayerState.h>
#include <gui/Surface.h>
#include <hidl/ServiceManagement.h>
-#include <input/IInputFlinger.h>
#include <layerproto/LayerProtoParser.h>
#include <log/log.h>
#include <private/android_filesystem_config.h>
@@ -103,10 +104,12 @@
#include "DisplayHardware/FramebufferSurface.h"
#include "DisplayHardware/HWComposer.h"
#include "DisplayHardware/VirtualDisplaySurface.h"
+#include "DisplayRenderArea.h"
#include "EffectLayer.h"
#include "Effects/Daltonizer.h"
#include "FrameTracer/FrameTracer.h"
#include "Layer.h"
+#include "LayerRenderArea.h"
#include "LayerVector.h"
#include "MonitoredProducer.h"
#include "NativeWindowSurface.h"
@@ -149,7 +152,7 @@
using namespace android::hardware::configstore::V1_0;
using namespace android::sysprop;
-using android::hardware::power::V1_0::PowerHint;
+using android::hardware::power::Boost;
using base::StringAppendF;
using ui::ColorMode;
using ui::Dataspace;
@@ -254,6 +257,21 @@
} // namespace anonymous
+struct SetInputWindowsListener : os::BnSetInputWindowsListener {
+ explicit SetInputWindowsListener(std::function<void()> listenerCb) : mListenerCb(listenerCb) {}
+
+ binder::Status onSetInputWindowsFinished() override;
+
+ std::function<void()> mListenerCb;
+};
+
+binder::Status SetInputWindowsListener::onSetInputWindowsFinished() {
+ if (mListenerCb != nullptr) {
+ mListenerCb();
+ }
+ return binder::Status::ok();
+}
+
// ---------------------------------------------------------------------------
const String16 sHardwareTest("android.permission.HARDWARE_TEST");
@@ -319,7 +337,9 @@
mEventQueue(mFactory.createMessageQueue()),
mCompositionEngine(mFactory.createCompositionEngine()),
mInternalDisplayDensity(getDensityFromProperty("ro.sf.lcd_density", true)),
- mEmulatedDisplayDensity(getDensityFromProperty("qemu.sf.lcd_density", false)) {}
+ mEmulatedDisplayDensity(getDensityFromProperty("qemu.sf.lcd_density", false)) {
+ mSetInputWindowsListener = new SetInputWindowsListener([&]() { setInputWindowsFinished(); });
+}
SurfaceFlinger::SurfaceFlinger(Factory& factory) : SurfaceFlinger(factory, SkipInitialization) {
ALOGI("SurfaceFlinger is starting");
@@ -397,10 +417,6 @@
int debugDdms = atoi(value);
ALOGI_IF(debugDdms, "DDMS debugging not supported");
- property_get("debug.sf.disable_backpressure", value, "0");
- mPropagateBackpressure = !atoi(value);
- ALOGI_IF(!mPropagateBackpressure, "Disabling backpressure propagation");
-
property_get("debug.sf.enable_gl_backpressure", value, "0");
mPropagateBackpressureClientComposition = atoi(value);
ALOGI_IF(mPropagateBackpressureClientComposition,
@@ -424,6 +440,10 @@
const size_t defaultListSize = ISurfaceComposer::MAX_LAYERS;
auto listSize = property_get_int32("debug.sf.max_igbp_list_size", int32_t(defaultListSize));
mMaxGraphicBufferProducerListSize = (listSize > 0) ? size_t(listSize) : defaultListSize;
+ mGraphicBufferProducerListSizeLogThreshold =
+ std::max(static_cast<int>(0.95 *
+ static_cast<double>(mMaxGraphicBufferProducerListSize)),
+ 1);
property_get("debug.sf.luma_sampling", value, "1");
mLumaSampling = atoi(value);
@@ -601,13 +621,6 @@
if (mWindowManager != 0) {
mWindowManager->linkToDeath(static_cast<IBinder::DeathRecipient*>(this));
}
- sp<IBinder> input(defaultServiceManager()->getService(
- String16("inputflinger")));
- if (input == nullptr) {
- ALOGE("Failed to link to input service");
- } else {
- mInputFlinger = interface_cast<IInputFlinger>(input);
- }
if (mVrFlinger) {
mVrFlinger->OnBootFinished();
@@ -622,7 +635,15 @@
LOG_EVENT_LONG(LOGTAG_SF_STOP_BOOTANIM,
ns2ms(systemTime(SYSTEM_TIME_MONOTONIC)));
- static_cast<void>(schedule([this] {
+ sp<IBinder> input(defaultServiceManager()->getService(String16("inputflinger")));
+
+ static_cast<void>(schedule([=] {
+ if (input == nullptr) {
+ ALOGE("Failed to link to input service");
+ } else {
+ mInputFlinger = interface_cast<os::IInputFlinger>(input);
+ }
+
readPersistentProperties();
mPowerAdvisor.onBootFinished();
mBootStage = BootStage::FINISHED;
@@ -872,7 +893,7 @@
info->density /= ACONFIGURATION_DENSITY_MEDIUM;
info->secure = display->isSecure();
- info->deviceProductInfo = getDeviceProductInfoLocked(*display);
+ info->deviceProductInfo = display->getDeviceProductInfo();
return NO_ERROR;
}
@@ -1339,30 +1360,6 @@
return NO_ERROR;
}
-std::optional<DeviceProductInfo> SurfaceFlinger::getDeviceProductInfoLocked(
- const DisplayDevice& display) const {
- // TODO(b/149075047): Populate DeviceProductInfo on hotplug and store it in DisplayDevice to
- // avoid repetitive HAL IPC and EDID parsing.
- const auto displayId = display.getId();
- LOG_FATAL_IF(!displayId);
-
- const auto hwcDisplayId = getHwComposer().fromPhysicalDisplayId(*displayId);
- LOG_FATAL_IF(!hwcDisplayId);
-
- uint8_t port;
- DisplayIdentificationData data;
- if (!getHwComposer().getDisplayIdentificationData(*hwcDisplayId, &port, &data)) {
- ALOGV("%s: No identification data.", __FUNCTION__);
- return {};
- }
-
- const auto info = parseDisplayIdentificationData(port, data);
- if (!info) {
- return {};
- }
- return info->deviceProductInfo;
-}
-
status_t SurfaceFlinger::getDisplayedContentSamplingAttributes(const sp<IBinder>& displayToken,
ui::PixelFormat* outFormat,
ui::Dataspace* outDataspace,
@@ -1530,10 +1527,10 @@
.get();
}
-status_t SurfaceFlinger::notifyPowerHint(int32_t hintId) {
- PowerHint powerHint = static_cast<PowerHint>(hintId);
+status_t SurfaceFlinger::notifyPowerBoost(int32_t boostId) {
+ Boost powerBoost = static_cast<Boost>(boostId);
- if (powerHint == PowerHint::INTERACTION) {
+ if (powerBoost == Boost::INTERACTION) {
mScheduler->notifyTouchEvent();
}
@@ -1860,10 +1857,7 @@
// for the present fence to fire instead of just giving up on this frame to handle cases
// where present fence is just about to get signaled.
const int graceTimeForPresentFenceMs =
- (mPropagateBackpressure &&
- (mPropagateBackpressureClientComposition || !mHadClientComposition))
- ? 1
- : 0;
+ (mPropagateBackpressureClientComposition || !mHadClientComposition) ? 1 : 0;
// Pending frames may trigger backpressure propagation.
const TracedOrdinal<bool> framePending = {"PrevFramePending",
@@ -1922,7 +1916,7 @@
ON_MAIN_THREAD(setActiveConfigInternal());
}
- if (framePending && mPropagateBackpressure) {
+ if (framePending) {
if ((hwcFrameMissed && !gpuFrameMissed) || mPropagateBackpressureClientComposition) {
signalLayerUpdate();
return;
@@ -2449,8 +2443,10 @@
}
DisplayDeviceState state;
- state.physical = {displayId, getHwComposer().getDisplayConnectionType(displayId),
- event.hwcDisplayId};
+ state.physical = {.id = displayId,
+ .type = getHwComposer().getDisplayConnectionType(displayId),
+ .hwcDisplayId = event.hwcDisplayId,
+ .deviceProductInfo = info->deviceProductInfo};
state.isSecure = true; // All physical displays are currently considered secure.
state.displayName = info->name;
@@ -2566,6 +2562,7 @@
LOG_ALWAYS_FATAL_IF(!displayId);
auto activeConfigId = HwcConfigIndexType(getHwComposer().getActiveConfigIndex(*displayId));
display->setActiveConfig(activeConfigId);
+ display->setDeviceProductInfo(state.physical->deviceProductInfo);
}
display->setLayerStack(state.layerStack);
@@ -2913,19 +2910,19 @@
}
void SurfaceFlinger::updateInputWindowInfo() {
- std::vector<InputWindowInfo> inputHandles;
+ std::vector<InputWindowInfo> inputInfos;
mDrawingState.traverseInReverseZOrder([&](Layer* layer) {
if (layer->needsInputInfo()) {
// When calculating the screen bounds we ignore the transparent region since it may
// result in an unwanted offset.
- inputHandles.push_back(layer->fillInputInfo());
+ inputInfos.push_back(layer->fillInputInfo());
}
});
- mInputFlinger->setInputWindows(inputHandles,
- mInputWindowCommands.syncInputWindows ? mSetInputWindowsListener
- : nullptr);
+ mInputFlinger->setInputWindows(inputInfos,
+ mInputWindowCommands.syncInputWindows ? mSetInputWindowsListener
+ : nullptr);
}
void SurfaceFlinger::commitInputWindowCommands() {
@@ -3209,6 +3206,11 @@
"Suspected IGBP leak: %zu IGBPs (%zu max), %zu Layers",
mGraphicBufferProducerList.size(),
mMaxGraphicBufferProducerListSize, mNumLayers.load());
+ if (mGraphicBufferProducerList.size() > mGraphicBufferProducerListSizeLogThreshold) {
+ ALOGW("Suspected IGBP leak: %zu IGBPs (%zu max), %zu Layers",
+ mGraphicBufferProducerList.size(), mMaxGraphicBufferProducerListSize,
+ mNumLayers.load());
+ }
}
if (const auto display = getDefaultDisplayDeviceLocked()) {
@@ -3823,7 +3825,7 @@
}
if (what & layer_state_t::eInputInfoChanged) {
if (privileged) {
- layer->setInputInfo(s.inputInfo);
+ layer->setInputInfo(*s.inputHandle->getInfo());
flags |= eTraversalNeeded;
} else {
ALOGE("Attempt to update InputWindowInfo without permission ACCESS_SURFACE_FLINGER");
@@ -4734,7 +4736,7 @@
StringAppendF(&result, "Composition layers\n");
mDrawingState.traverseInZOrder([&](Layer* layer) {
auto* compositionState = layer->getCompositionState();
- if (!compositionState) return;
+ if (!compositionState || !compositionState->isVisible) return;
android::base::StringAppendF(&result, "* Layer %p (%s)\n", layer,
layer->getDebugName() ? layer->getDebugName()
@@ -4898,7 +4900,7 @@
case GET_DISPLAYED_CONTENT_SAMPLING_ATTRIBUTES:
case SET_DISPLAY_CONTENT_SAMPLING_ENABLED:
case GET_DISPLAYED_CONTENT_SAMPLE:
- case NOTIFY_POWER_HINT:
+ case NOTIFY_POWER_BOOST:
case SET_GLOBAL_SHADOW_SETTINGS:
case ACQUIRE_FRAME_RATE_FLEXIBILITY_TOKEN: {
// ACQUIRE_FRAME_RATE_FLEXIBILITY_TOKEN is used by CTS tests, which acquire the
@@ -5430,27 +5432,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) {
@@ -5506,19 +5514,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);
@@ -5544,14 +5553,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 */);
}
@@ -5562,88 +5576,7 @@
float frameScale, bool childrenOnly) {
ATRACE_CALL();
- 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),
- mLayer(layer),
- mCrop(crop),
- mNeedsFiltering(false),
- mFlinger(flinger),
- mChildrenOnly(childrenOnly) {}
- const ui::Transform& getTransform() const override { return mTransform; }
- Rect getBounds() const override { return mLayer->getBufferSize(mLayer->getDrawingState()); }
- int getHeight() const override {
- return mLayer->getBufferSize(mLayer->getDrawingState()).getHeight();
- }
- int getWidth() const override {
- return mLayer->getBufferSize(mLayer->getDrawingState()).getWidth();
- }
- bool isSecure() const override { return false; }
- bool needsFiltering() const override { return mNeedsFiltering; }
- sp<const DisplayDevice> getDisplayDevice() const override { return nullptr; }
- Rect getSourceCrop() const override {
- if (mCrop.isEmpty()) {
- return getBounds();
- } else {
- return mCrop;
- }
- }
- class ReparentForDrawing {
- public:
- const sp<Layer>& oldParent;
- const sp<Layer>& newParent;
-
- ReparentForDrawing(const sp<Layer>& oldParent, const sp<Layer>& newParent,
- const Rect& drawingBounds)
- : oldParent(oldParent), newParent(newParent) {
- // Compute and cache the bounds for the new parent layer.
- newParent->computeBounds(drawingBounds.toFloatRect(), ui::Transform(),
- 0.f /* shadowRadius */);
- oldParent->setChildrenDrawingParent(newParent);
- }
- ~ReparentForDrawing() { oldParent->setChildrenDrawingParent(oldParent); }
- };
-
- void render(std::function<void()> drawLayers) override {
- const Rect sourceCrop = getSourceCrop();
- // no need to check rotation because there is none
- mNeedsFiltering = sourceCrop.width() != getReqWidth() ||
- sourceCrop.height() != getReqHeight();
-
- if (!mChildrenOnly) {
- mTransform = mLayer->getTransform().inverse();
- drawLayers();
- } else {
- uint32_t w = static_cast<uint32_t>(getWidth());
- uint32_t h = static_cast<uint32_t>(getHeight());
- // In the "childrenOnly" case we reparent the children to a screenshot
- // layer which has no properties set and which does not draw.
- sp<ContainerLayer> screenshotParentLayer =
- mFlinger->getFactory().createContainerLayer({mFlinger, nullptr,
- "Screenshot Parent"s, w, h, 0,
- LayerMetadata()});
-
- ReparentForDrawing reparent(mLayer, screenshotParentLayer, sourceCrop);
- drawLayers();
- }
- }
-
- private:
- const sp<Layer> mLayer;
- const Rect mCrop;
-
- ui::Transform mTransform;
- bool mNeedsFiltering;
-
- SurfaceFlinger* mFlinger;
- 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;
@@ -5680,8 +5613,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();
@@ -5702,15 +5634,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) {
@@ -5733,14 +5668,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();
@@ -5748,16 +5683,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,
@@ -5770,23 +5705,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);
@@ -5800,8 +5740,9 @@
void SurfaceFlinger::renderScreenImplLocked(const RenderArea& renderArea,
TraverseLayersFunction traverseLayers,
- ANativeWindowBuffer* buffer, bool useIdentityTransform,
- bool regionSampling, int* outSyncFd) {
+ const sp<GraphicBuffer>& buffer,
+ bool useIdentityTransform, bool regionSampling,
+ int* outSyncFd) {
ATRACE_CALL();
const auto reqWidth = renderArea.getReqWidth();
@@ -5899,7 +5840,7 @@
status_t SurfaceFlinger::captureScreenImplLocked(const RenderArea& renderArea,
TraverseLayersFunction traverseLayers,
- ANativeWindowBuffer* buffer,
+ const sp<GraphicBuffer>& buffer,
bool useIdentityTransform, bool forSystem,
int* outSyncFd, bool regionSampling,
bool& outCapturedSecureLayers) {
@@ -5944,17 +5885,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()) {
@@ -6136,10 +6077,6 @@
}
}
-void SurfaceFlinger::SetInputWindowsListener::onSetInputWindowsFinished() {
- mFlinger->setInputWindowsFinished();
-}
-
wp<Layer> SurfaceFlinger::fromHandle(const sp<IBinder>& handle) {
Mutex::Autolock _l(mStateLock);
return fromHandleLocked(handle);
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index ccaeb2d..7ab0729 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -33,7 +33,6 @@
#include <gui/ITransactionCompletedListener.h>
#include <gui/LayerState.h>
#include <gui/OccupancyTracker.h>
-#include <input/ISetInputWindowsListener.h>
#include <layerproto/LayerProtoHeader.h>
#include <math/mat4.h>
#include <renderengine/LayerSettings.h>
@@ -89,15 +88,20 @@
class Client;
class EventThread;
class HWComposer;
+struct SetInputWindowsListener;
class IGraphicBufferProducer;
-class IInputFlinger;
class Layer;
class MessageBase;
class RefreshRateOverlay;
class RegionSamplingThread;
+class RenderArea;
class TimeStats;
class FrameTracer;
+namespace os {
+ class IInputFlinger;
+}
+
namespace compositionengine {
class DisplaySurface;
class OutputLayer;
@@ -335,6 +339,7 @@
// If set, disables reusing client composition buffers. This can be set by
// debug.sf.disable_client_composition_cache
bool mDisableClientCompositionCache = false;
+ void setInputWindowsFinished();
private:
friend class BufferLayer;
@@ -498,7 +503,7 @@
status_t getDisplayBrightnessSupport(const sp<IBinder>& displayToken,
bool* outSupport) const override;
status_t setDisplayBrightness(const sp<IBinder>& displayToken, float brightness) override;
- status_t notifyPowerHint(int32_t hintId) override;
+ status_t notifyPowerBoost(int32_t boostId) override;
status_t setGlobalShadowSettings(const half4& ambientColor, const half4& spotColor,
float lightPosY, float lightPosZ, float lightRadius) override;
status_t setFrameRate(const sp<IGraphicBufferProducer>& surface, float frameRate,
@@ -605,7 +610,6 @@
void updateInputFlinger();
void updateInputWindowInfo();
void commitInputWindowCommands() REQUIRES(mStateLock);
- void setInputWindowsFinished();
void updateCursorAsync();
void initScheduler(DisplayId primaryDisplayId);
@@ -718,25 +722,25 @@
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,
- ANativeWindowBuffer* buffer, bool useIdentityTransform,
+ 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,
TraverseLayersFunction traverseLayers,
- ANativeWindowBuffer* buffer, bool useIdentityTransform,
+ 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;
@@ -783,8 +787,6 @@
return getDefaultDisplayDeviceLocked();
}
- std::optional<DeviceProductInfo> getDeviceProductInfoLocked(const DisplayDevice&) const;
-
// mark a region of a layer stack dirty. this updates the dirty
// region of all screens presenting this layer stack.
void invalidateLayerStack(const sp<const Layer>& layer, const Region& dirty);
@@ -1017,6 +1019,10 @@
// Can't be unordered_set because wp<> isn't hashable
std::set<wp<IBinder>> mGraphicBufferProducerList;
size_t mMaxGraphicBufferProducerListSize = ISurfaceComposer::MAX_LAYERS;
+ // If there are more GraphicBufferProducers tracked by SurfaceFlinger than
+ // this threshold, then begin logging.
+ size_t mGraphicBufferProducerListSizeLogThreshold =
+ static_cast<size_t>(0.95 * static_cast<double>(MAX_LAYERS));
void removeGraphicBufferProducerAsync(const wp<IBinder>&);
@@ -1080,7 +1086,6 @@
bool mDebugDisableTransformHint = false;
volatile nsecs_t mDebugInTransaction = 0;
bool mForceFullDamage = false;
- bool mPropagateBackpressure = true;
bool mPropagateBackpressureClientComposition = false;
std::unique_ptr<SurfaceInterceptor> mInterceptor;
@@ -1252,21 +1257,12 @@
const float mInternalDisplayDensity;
const float mEmulatedDisplayDensity;
- sp<IInputFlinger> mInputFlinger;
+ sp<os::IInputFlinger> mInputFlinger;
InputWindowCommands mPendingInputWindowCommands GUARDED_BY(mStateLock);
// Should only be accessed by the main thread.
InputWindowCommands mInputWindowCommands;
- struct SetInputWindowsListener : BnSetInputWindowsListener {
- explicit SetInputWindowsListener(sp<SurfaceFlinger> flinger)
- : mFlinger(std::move(flinger)) {}
-
- void onSetInputWindowsFinished() override;
-
- const sp<SurfaceFlinger> mFlinger;
- };
-
- const sp<SetInputWindowsListener> mSetInputWindowsListener = new SetInputWindowsListener(this);
+ sp<SetInputWindowsListener> mSetInputWindowsListener;
bool mPendingSyncInputWindows GUARDED_BY(mStateLock) = false;
Hwc2::impl::PowerAdvisor mPowerAdvisor;
diff --git a/services/surfaceflinger/tests/Android.bp b/services/surfaceflinger/tests/Android.bp
index fe2af80..c96dfc7 100644
--- a/services/surfaceflinger/tests/Android.bp
+++ b/services/surfaceflinger/tests/Android.bp
@@ -21,6 +21,7 @@
"CommonTypes_test.cpp",
"Credentials_test.cpp",
"DereferenceSurfaceControl_test.cpp",
+ "DetachChildren_test.cpp",
"DisplayConfigs_test.cpp",
"EffectLayer_test.cpp",
"InvalidHandles_test.cpp",
diff --git a/services/surfaceflinger/tests/DetachChildren_test.cpp b/services/surfaceflinger/tests/DetachChildren_test.cpp
new file mode 100644
index 0000000..b6c2fe2
--- /dev/null
+++ b/services/surfaceflinger/tests/DetachChildren_test.cpp
@@ -0,0 +1,322 @@
+/*
+ * 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.
+ */
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
+#include "LayerTransactionTest.h"
+
+namespace android {
+
+class DetachChildren : public LayerTransactionTest {
+protected:
+ virtual void SetUp() {
+ LayerTransactionTest::SetUp();
+
+ mMainSurface = createLayer(String8("Main Test Surface"), mMainSurfaceBounds.width(),
+ mMainSurfaceBounds.height(), 0, mBlackBgSurface.get());
+
+ ASSERT_TRUE(mMainSurface != nullptr);
+ ASSERT_TRUE(mMainSurface->isValid());
+
+ TransactionUtils::fillSurfaceRGBA8(mMainSurface, mMainSurfaceColor);
+
+ asTransaction([&](Transaction& t) {
+ t.setLayer(mMainSurface, INT32_MAX - 1)
+ .setPosition(mMainSurface, mMainSurfaceBounds.left, mMainSurfaceBounds.top)
+ .show(mMainSurface);
+ });
+ }
+
+ virtual void TearDown() {
+ LayerTransactionTest::TearDown();
+ mMainSurface = 0;
+ }
+
+ sp<SurfaceControl> mMainSurface;
+ Color mMainSurfaceColor = {195, 63, 63, 255};
+ Rect mMainSurfaceBounds = Rect(64, 64, 128, 128);
+ std::unique_ptr<ScreenCapture> mCapture;
+};
+
+TEST_F(DetachChildren, RelativesAreNotDetached) {
+ Color relativeColor = {10, 10, 10, 255};
+ Rect relBounds = Rect(64, 64, 74, 74);
+
+ sp<SurfaceControl> relative =
+ createLayer(String8("relativeTestSurface"), relBounds.width(), relBounds.height(), 0);
+ TransactionUtils::fillSurfaceRGBA8(relative, relativeColor);
+
+ Transaction{}
+ .setRelativeLayer(relative, mMainSurface->getHandle(), 1)
+ .setPosition(relative, relBounds.left, relBounds.top)
+ .apply();
+
+ {
+ // The relative should be on top of the FG control.
+ mCapture = screenshot();
+ mCapture->expectColor(relBounds, relativeColor);
+ }
+ Transaction{}.detachChildren(mMainSurface).apply();
+
+ {
+ // Nothing should change at this point.
+ mCapture = screenshot();
+ mCapture->expectColor(relBounds, relativeColor);
+ }
+
+ Transaction{}.hide(relative).apply();
+
+ {
+ // Ensure that the relative was actually hidden, rather than
+ // being left in the detached but visible state.
+ mCapture = screenshot();
+ mCapture->expectColor(mMainSurfaceBounds, mMainSurfaceColor);
+ }
+}
+
+TEST_F(DetachChildren, DetachChildrenSameClient) {
+ Color childColor = {200, 200, 200, 255};
+ Rect childBounds = Rect(74, 74, 84, 84);
+ sp<SurfaceControl> child = createLayer(String8("Child surface"), childBounds.width(),
+ childBounds.height(), 0, mMainSurface.get());
+ ASSERT_TRUE(child->isValid());
+
+ TransactionUtils::fillSurfaceRGBA8(child, childColor);
+
+ asTransaction([&](Transaction& t) {
+ t.show(child);
+ t.setPosition(child, childBounds.left - mMainSurfaceBounds.left,
+ childBounds.top - mMainSurfaceBounds.top);
+ });
+
+ {
+ mCapture = screenshot();
+ // Expect main color around the child surface
+ mCapture->expectBorder(childBounds, mMainSurfaceColor);
+ mCapture->expectColor(childBounds, childColor);
+ }
+
+ asTransaction([&](Transaction& t) { t.detachChildren(mMainSurface); });
+
+ asTransaction([&](Transaction& t) { t.hide(child); });
+
+ // Since the child has the same client as the parent, it will not get
+ // detached and will be hidden.
+ {
+ mCapture = screenshot();
+ mCapture->expectColor(mMainSurfaceBounds, mMainSurfaceColor);
+ }
+}
+
+TEST_F(DetachChildren, DetachChildrenDifferentClient) {
+ Color childColor = {200, 200, 200, 255};
+ Rect childBounds = Rect(74, 74, 84, 84);
+
+ sp<SurfaceComposerClient> newComposerClient = new SurfaceComposerClient;
+ sp<SurfaceControl> childNewClient =
+ createSurface(newComposerClient, "New Child Test Surface", childBounds.width(),
+ childBounds.height(), PIXEL_FORMAT_RGBA_8888, 0, mMainSurface.get());
+ ASSERT_TRUE(childNewClient->isValid());
+
+ TransactionUtils::fillSurfaceRGBA8(childNewClient, childColor);
+
+ asTransaction([&](Transaction& t) {
+ t.show(childNewClient);
+ t.setPosition(childNewClient, childBounds.left - mMainSurfaceBounds.left,
+ childBounds.top - mMainSurfaceBounds.top);
+ });
+
+ {
+ mCapture = screenshot();
+ // Expect main color around the child surface
+ mCapture->expectBorder(childBounds, mMainSurfaceColor);
+ mCapture->expectColor(childBounds, childColor);
+ }
+
+ asTransaction([&](Transaction& t) { t.detachChildren(mMainSurface); });
+
+ asTransaction([&](Transaction& t) { t.hide(childNewClient); });
+
+ // Nothing should have changed.
+ {
+ mCapture = screenshot();
+ mCapture->expectBorder(childBounds, mMainSurfaceColor);
+ mCapture->expectColor(childBounds, childColor);
+ }
+}
+
+TEST_F(DetachChildren, DetachChildrenThenAttach) {
+ Color childColor = {200, 200, 200, 255};
+ Rect childBounds = Rect(74, 74, 84, 84);
+
+ sp<SurfaceComposerClient> newComposerClient = new SurfaceComposerClient;
+ sp<SurfaceControl> childNewClient =
+ createSurface(newComposerClient, "New Child Test Surface", childBounds.width(),
+ childBounds.height(), PIXEL_FORMAT_RGBA_8888, 0, mMainSurface.get());
+ ASSERT_TRUE(childNewClient->isValid());
+
+ TransactionUtils::fillSurfaceRGBA8(childNewClient, childColor);
+
+ Transaction()
+ .show(childNewClient)
+ .setPosition(childNewClient, childBounds.left - mMainSurfaceBounds.left,
+ childBounds.top - mMainSurfaceBounds.top)
+ .apply();
+
+ {
+ mCapture = screenshot();
+ // Expect main color around the child surface
+ mCapture->expectBorder(childBounds, mMainSurfaceColor);
+ mCapture->expectColor(childBounds, childColor);
+ }
+
+ Transaction().detachChildren(mMainSurface).apply();
+ Transaction().hide(childNewClient).apply();
+
+ // Nothing should have changed.
+ {
+ mCapture = screenshot();
+ mCapture->expectBorder(childBounds, mMainSurfaceColor);
+ mCapture->expectColor(childBounds, childColor);
+ }
+
+ Color newParentColor = Color::RED;
+ Rect newParentBounds = Rect(20, 20, 52, 52);
+ sp<SurfaceControl> newParentSurface =
+ createLayer(String8("New Parent Surface"), newParentBounds.width(),
+ newParentBounds.height(), 0);
+ TransactionUtils::fillSurfaceRGBA8(newParentSurface, newParentColor);
+ Transaction()
+ .setLayer(newParentSurface, INT32_MAX - 1)
+ .show(newParentSurface)
+ .setPosition(newParentSurface, newParentBounds.left, newParentBounds.top)
+ .reparent(childNewClient, newParentSurface->getHandle())
+ .apply();
+ {
+ mCapture = screenshot();
+ // Child is now hidden.
+ mCapture->expectColor(newParentBounds, newParentColor);
+ }
+}
+
+TEST_F(DetachChildren, DetachChildrenWithDeferredTransaction) {
+ Color childColor = {200, 200, 200, 255};
+ Rect childBounds = Rect(74, 74, 84, 84);
+
+ sp<SurfaceComposerClient> newComposerClient = new SurfaceComposerClient;
+ sp<SurfaceControl> childNewClient =
+ createSurface(newComposerClient, "New Child Test Surface", childBounds.width(),
+ childBounds.height(), PIXEL_FORMAT_RGBA_8888, 0, mMainSurface.get());
+ ASSERT_TRUE(childNewClient->isValid());
+
+ TransactionUtils::fillSurfaceRGBA8(childNewClient, childColor);
+
+ Transaction()
+ .show(childNewClient)
+ .setPosition(childNewClient, childBounds.left - mMainSurfaceBounds.left,
+ childBounds.top - mMainSurfaceBounds.top)
+ .apply();
+
+ {
+ mCapture = screenshot();
+ mCapture->expectBorder(childBounds, mMainSurfaceColor);
+ mCapture->expectColor(childBounds, childColor);
+ }
+
+ Transaction()
+ .deferTransactionUntil_legacy(childNewClient, mMainSurface->getHandle(),
+ mMainSurface->getSurface()->getNextFrameNumber())
+ .apply();
+ Transaction().detachChildren(mMainSurface).apply();
+ ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(mMainSurface, Color::RED,
+ mMainSurfaceBounds.width(),
+ mMainSurfaceBounds.height()));
+
+ // BufferLayer can still dequeue buffers even though there's a detached layer with a
+ // deferred transaction.
+ {
+ SCOPED_TRACE("new buffer");
+ mCapture = screenshot();
+ mCapture->expectBorder(childBounds, Color::RED);
+ mCapture->expectColor(childBounds, childColor);
+ }
+}
+
+TEST_F(DetachChildren, ReparentParentLayerOfDetachedChildren) {
+ Color childColor = {200, 200, 200, 255};
+ Rect childBounds = Rect(74, 74, 94, 94);
+ Color grandchildColor = Color::RED;
+ Rect grandchildBounds = Rect(80, 80, 90, 90);
+
+ sp<SurfaceComposerClient> newClient1 = new SurfaceComposerClient;
+ sp<SurfaceComposerClient> newClient2 = new SurfaceComposerClient;
+
+ sp<SurfaceControl> childSurface =
+ createSurface(newClient1, "Child surface", childBounds.width(), childBounds.height(),
+ PIXEL_FORMAT_RGBA_8888, 0, mMainSurface.get());
+ sp<SurfaceControl> grandchildSurface =
+ createSurface(newClient2, "Grandchild Surface", grandchildBounds.width(),
+ grandchildBounds.height(), PIXEL_FORMAT_RGBA_8888, 0, childSurface.get());
+
+ TransactionUtils::fillSurfaceRGBA8(childSurface, childColor);
+ TransactionUtils::fillSurfaceRGBA8(grandchildSurface, grandchildColor);
+
+ Transaction()
+ .show(childSurface)
+ .show(grandchildSurface)
+ .setPosition(childSurface, childBounds.left - mMainSurfaceBounds.left,
+ childBounds.top - mMainSurfaceBounds.top)
+ .setPosition(grandchildSurface, grandchildBounds.left - childBounds.left,
+ grandchildBounds.top - childBounds.top)
+ .apply();
+
+ {
+ mCapture = screenshot();
+ mCapture->expectBorder(childBounds, mMainSurfaceColor);
+ mCapture->expectBorder(grandchildBounds, childColor);
+ mCapture->expectColor(grandchildBounds, grandchildColor);
+ }
+
+ Transaction().detachChildren(childSurface).apply();
+
+ // Remove main surface offscreen
+ Transaction().reparent(mMainSurface, nullptr).apply();
+ {
+ mCapture = screenshot();
+ mCapture->expectColor(mMainSurfaceBounds, Color::BLACK);
+ }
+
+ Transaction().reparent(mMainSurface, mBlackBgSurface->getHandle()).apply();
+ {
+ mCapture = screenshot();
+ mCapture->expectBorder(childBounds, mMainSurfaceColor);
+ mCapture->expectBorder(grandchildBounds, childColor);
+ mCapture->expectColor(grandchildBounds, grandchildColor);
+ }
+
+ Transaction().hide(grandchildSurface).apply();
+
+ // grandchild is still detached so it will not hide
+ {
+ mCapture = screenshot();
+ mCapture->expectBorder(childBounds, mMainSurfaceColor);
+ mCapture->expectBorder(grandchildBounds, childColor);
+ mCapture->expectColor(grandchildBounds, grandchildColor);
+ }
+}
+
+} // namespace android
\ No newline at end of file
diff --git a/services/surfaceflinger/tests/LayerUpdate_test.cpp b/services/surfaceflinger/tests/LayerUpdate_test.cpp
index cdd9d92..84823f5 100644
--- a/services/surfaceflinger/tests/LayerUpdate_test.cpp
+++ b/services/surfaceflinger/tests/LayerUpdate_test.cpp
@@ -103,41 +103,6 @@
sp<SurfaceControl> mSyncSurfaceControl;
};
-TEST_F(LayerUpdateTest, RelativesAreNotDetached) {
- std::unique_ptr<ScreenCapture> sc;
-
- sp<SurfaceControl> relative = createLayer(String8("relativeTestSurface"), 10, 10, 0);
- TransactionUtils::fillSurfaceRGBA8(relative, 10, 10, 10);
- waitForPostedBuffers();
-
- Transaction{}
- .setRelativeLayer(relative, mFGSurfaceControl->getHandle(), 1)
- .setPosition(relative, 64, 64)
- .apply();
-
- {
- // The relative should be on top of the FG control.
- ScreenCapture::captureScreen(&sc);
- sc->checkPixel(64, 64, 10, 10, 10);
- }
- Transaction{}.detachChildren(mFGSurfaceControl).apply();
-
- {
- // Nothing should change at this point.
- ScreenCapture::captureScreen(&sc);
- sc->checkPixel(64, 64, 10, 10, 10);
- }
-
- Transaction{}.hide(relative).apply();
-
- {
- // Ensure that the relative was actually hidden, rather than
- // being left in the detached but visible state.
- ScreenCapture::captureScreen(&sc);
- sc->expectFGColor(64, 64);
- }
-}
-
class GeometryLatchingTest : public LayerUpdateTest {
protected:
void EXPECT_INITIAL_STATE(const char* trace) {
@@ -588,174 +553,6 @@
}
}
-TEST_F(ChildLayerTest, DetachChildrenSameClient) {
- asTransaction([&](Transaction& t) {
- t.show(mChild);
- t.setPosition(mChild, 10, 10);
- t.setPosition(mFGSurfaceControl, 64, 64);
- });
-
- {
- mCapture = screenshot();
- // Top left of foreground must now be visible
- mCapture->expectFGColor(64, 64);
- // But 10 pixels in we should see the child surface
- mCapture->expectChildColor(74, 74);
- // And 10 more pixels we should be back to the foreground surface
- mCapture->expectFGColor(84, 84);
- }
-
- asTransaction([&](Transaction& t) { t.detachChildren(mFGSurfaceControl); });
-
- asTransaction([&](Transaction& t) { t.hide(mChild); });
-
- // Since the child has the same client as the parent, it will not get
- // detached and will be hidden.
- {
- mCapture = screenshot();
- mCapture->expectFGColor(64, 64);
- mCapture->expectFGColor(74, 74);
- mCapture->expectFGColor(84, 84);
- }
-}
-
-TEST_F(ChildLayerTest, DetachChildrenDifferentClient) {
- sp<SurfaceComposerClient> mNewComposerClient = new SurfaceComposerClient;
- sp<SurfaceControl> mChildNewClient =
- createSurface(mNewComposerClient, "New Child Test Surface", 10, 10,
- PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
-
- ASSERT_TRUE(mChildNewClient->isValid());
-
- TransactionUtils::fillSurfaceRGBA8(mChildNewClient, 200, 200, 200);
-
- asTransaction([&](Transaction& t) {
- t.hide(mChild);
- t.show(mChildNewClient);
- t.setPosition(mChildNewClient, 10, 10);
- t.setPosition(mFGSurfaceControl, 64, 64);
- });
-
- {
- mCapture = screenshot();
- // Top left of foreground must now be visible
- mCapture->expectFGColor(64, 64);
- // But 10 pixels in we should see the child surface
- mCapture->expectChildColor(74, 74);
- // And 10 more pixels we should be back to the foreground surface
- mCapture->expectFGColor(84, 84);
- }
-
- asTransaction([&](Transaction& t) { t.detachChildren(mFGSurfaceControl); });
-
- asTransaction([&](Transaction& t) { t.hide(mChildNewClient); });
-
- // Nothing should have changed.
- {
- mCapture = screenshot();
- mCapture->expectFGColor(64, 64);
- mCapture->expectChildColor(74, 74);
- mCapture->expectFGColor(84, 84);
- }
-}
-
-TEST_F(ChildLayerTest, DetachChildrenThenAttach) {
- sp<SurfaceComposerClient> newComposerClient = new SurfaceComposerClient;
- sp<SurfaceControl> childNewClient =
- newComposerClient->createSurface(String8("New Child Test Surface"), 10, 10,
- PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
-
- ASSERT_TRUE(childNewClient != nullptr);
- ASSERT_TRUE(childNewClient->isValid());
-
- TransactionUtils::fillSurfaceRGBA8(childNewClient, 200, 200, 200);
-
- Transaction()
- .hide(mChild)
- .show(childNewClient)
- .setPosition(childNewClient, 10, 10)
- .setPosition(mFGSurfaceControl, 64, 64)
- .apply();
-
- {
- mCapture = screenshot();
- // Top left of foreground must now be visible
- mCapture->expectFGColor(64, 64);
- // But 10 pixels in we should see the child surface
- mCapture->expectChildColor(74, 74);
- // And 10 more pixels we should be back to the foreground surface
- mCapture->expectFGColor(84, 84);
- }
-
- Transaction().detachChildren(mFGSurfaceControl).apply();
- Transaction().hide(childNewClient).apply();
-
- // Nothing should have changed.
- {
- mCapture = screenshot();
- mCapture->expectFGColor(64, 64);
- mCapture->expectChildColor(74, 74);
- mCapture->expectFGColor(84, 84);
- }
-
- sp<SurfaceControl> newParentSurface = createLayer(String8("New Parent Surface"), 32, 32, 0);
- fillLayerColor(ISurfaceComposerClient::eFXSurfaceBufferQueue, newParentSurface, Color::RED, 32,
- 32);
- Transaction()
- .setLayer(newParentSurface, INT32_MAX - 1)
- .show(newParentSurface)
- .setPosition(newParentSurface, 20, 20)
- .reparent(childNewClient, newParentSurface->getHandle())
- .apply();
- {
- mCapture = screenshot();
- // Child is now hidden.
- mCapture->expectColor(Rect(20, 20, 52, 52), Color::RED);
- }
-}
-TEST_F(ChildLayerTest, DetachChildrenWithDeferredTransaction) {
- sp<SurfaceComposerClient> newComposerClient = new SurfaceComposerClient;
- sp<SurfaceControl> childNewClient =
- newComposerClient->createSurface(String8("New Child Test Surface"), 10, 10,
- PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
-
- ASSERT_TRUE(childNewClient != nullptr);
- ASSERT_TRUE(childNewClient->isValid());
-
- TransactionUtils::fillSurfaceRGBA8(childNewClient, 200, 200, 200);
-
- Transaction()
- .hide(mChild)
- .show(childNewClient)
- .setPosition(childNewClient, 10, 10)
- .setPosition(mFGSurfaceControl, 64, 64)
- .apply();
-
- {
- mCapture = screenshot();
- Rect rect = Rect(74, 74, 84, 84);
- mCapture->expectBorder(rect, Color{195, 63, 63, 255});
- mCapture->expectColor(rect, Color{200, 200, 200, 255});
- }
-
- Transaction()
- .deferTransactionUntil_legacy(childNewClient, mFGSurfaceControl->getHandle(),
- mFGSurfaceControl->getSurface()->getNextFrameNumber())
- .apply();
- Transaction().detachChildren(mFGSurfaceControl).apply();
- ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(mFGSurfaceControl, Color::RED, 32, 32));
-
- // BufferLayer can still dequeue buffers even though there's a detached layer with a
- // deferred transaction.
- {
- SCOPED_TRACE("new buffer");
- mCapture = screenshot();
- Rect rect = Rect(74, 74, 84, 84);
- mCapture->expectBorder(rect, Color::RED);
- mCapture->expectColor(rect, Color{200, 200, 200, 255});
- }
-}
-
TEST_F(ChildLayerTest, ChildrenInheritNonTransformScalingFromParent) {
asTransaction([&](Transaction& t) {
t.show(mChild);
diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
index 32d722e..9355e61 100644
--- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
@@ -35,6 +35,7 @@
#include <utils/String8.h>
#include "BufferQueueLayer.h"
+#include "DisplayRenderArea.h"
#include "EffectLayer.h"
#include "Layer.h"
#include "TestableSurfaceFlinger.h"
@@ -233,24 +234,24 @@
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(),
- useIdentityTransform, forSystem, &fd, regionSampling);
+ mFlinger.captureScreenImplLocked(*renderArea, traverseLayers,
+ mCaptureScreenBuffer.get(), useIdentityTransform,
+ forSystem, &fd, regionSampling);
if (fd >= 0) {
close(fd);
}
@@ -348,7 +349,7 @@
EXPECT_CALL(*test->mRenderEngine, drawLayers)
.WillRepeatedly([](const renderengine::DisplaySettings& displaySettings,
const std::vector<const renderengine::LayerSettings*>&,
- ANativeWindowBuffer*, const bool, base::unique_fd&&,
+ const sp<GraphicBuffer>&, const bool, base::unique_fd&&,
base::unique_fd*) -> status_t {
EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance);
EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
@@ -397,7 +398,7 @@
EXPECT_CALL(*test->mRenderEngine, drawLayers)
.WillRepeatedly([](const renderengine::DisplaySettings& displaySettings,
const std::vector<const renderengine::LayerSettings*>&,
- ANativeWindowBuffer*, const bool, base::unique_fd&&,
+ const sp<GraphicBuffer>&, const bool, base::unique_fd&&,
base::unique_fd*) -> status_t {
EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance);
EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
@@ -648,7 +649,7 @@
EXPECT_CALL(*test->mRenderEngine, drawLayers)
.WillOnce([](const renderengine::DisplaySettings& displaySettings,
const std::vector<const renderengine::LayerSettings*>& layerSettings,
- ANativeWindowBuffer*, const bool, base::unique_fd&&,
+ const sp<GraphicBuffer>&, const bool, base::unique_fd&&,
base::unique_fd*) -> status_t {
EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance);
EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
@@ -697,7 +698,7 @@
EXPECT_CALL(*test->mRenderEngine, drawLayers)
.WillOnce([](const renderengine::DisplaySettings& displaySettings,
const std::vector<const renderengine::LayerSettings*>& layerSettings,
- ANativeWindowBuffer*, const bool, base::unique_fd&&,
+ const sp<GraphicBuffer>&, const bool, base::unique_fd&&,
base::unique_fd*) -> status_t {
EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance);
EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
@@ -775,7 +776,7 @@
EXPECT_CALL(*test->mRenderEngine, drawLayers)
.WillOnce([](const renderengine::DisplaySettings& displaySettings,
const std::vector<const renderengine::LayerSettings*>& layerSettings,
- ANativeWindowBuffer*, const bool, base::unique_fd&&,
+ const sp<GraphicBuffer>&, const bool, base::unique_fd&&,
base::unique_fd*) -> status_t {
EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance);
EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
diff --git a/services/surfaceflinger/tests/unittests/DisplayIdentificationTest.cpp b/services/surfaceflinger/tests/unittests/DisplayIdentificationTest.cpp
index 2a0e913..cc6a60c 100644
--- a/services/surfaceflinger/tests/unittests/DisplayIdentificationTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DisplayIdentificationTest.cpp
@@ -22,6 +22,8 @@
#include "DisplayHardware/DisplayIdentification.h"
+using ::testing::ElementsAre;
+
namespace android {
namespace {
@@ -312,86 +314,85 @@
using ManufactureYear = DeviceProductInfo::ManufactureYear;
using ManufactureWeekAndYear = DeviceProductInfo::ManufactureWeekAndYear;
using ModelYear = DeviceProductInfo::ModelYear;
- using RelativeAddress = DeviceProductInfo::RelativeAddress;
{
const auto displayIdInfo = parseDisplayIdentificationData(0, getInternalEdid());
ASSERT_TRUE(displayIdInfo);
ASSERT_TRUE(displayIdInfo->deviceProductInfo);
const auto& info = *displayIdInfo->deviceProductInfo;
- EXPECT_STREQ("", info.name.data());
+ EXPECT_EQ("", info.name);
EXPECT_STREQ("SEC", info.manufacturerPnpId.data());
- EXPECT_STREQ("12610", info.productId.data());
+ EXPECT_EQ("12610", info.productId);
ASSERT_TRUE(std::holds_alternative<ManufactureYear>(info.manufactureOrModelDate));
EXPECT_EQ(2011, std::get<ManufactureYear>(info.manufactureOrModelDate).year);
- EXPECT_EQ(DeviceProductInfo::NO_RELATIVE_ADDRESS, info.relativeAddress);
+ EXPECT_TRUE(info.relativeAddress.empty());
}
{
const auto displayIdInfo = parseDisplayIdentificationData(0, getExternalEdid());
ASSERT_TRUE(displayIdInfo);
ASSERT_TRUE(displayIdInfo->deviceProductInfo);
const auto& info = *displayIdInfo->deviceProductInfo;
- EXPECT_STREQ("HP ZR30w", info.name.data());
+ EXPECT_EQ("HP ZR30w", info.name);
EXPECT_STREQ("HWP", info.manufacturerPnpId.data());
- EXPECT_STREQ("10348", info.productId.data());
+ EXPECT_EQ("10348", info.productId);
ASSERT_TRUE(std::holds_alternative<ManufactureWeekAndYear>(info.manufactureOrModelDate));
const auto& date = std::get<ManufactureWeekAndYear>(info.manufactureOrModelDate);
EXPECT_EQ(2012, date.year);
EXPECT_EQ(2, date.week);
- EXPECT_EQ(DeviceProductInfo::NO_RELATIVE_ADDRESS, info.relativeAddress);
+ EXPECT_TRUE(info.relativeAddress.empty());
}
{
const auto displayIdInfo = parseDisplayIdentificationData(0, getExternalEedid());
ASSERT_TRUE(displayIdInfo);
ASSERT_TRUE(displayIdInfo->deviceProductInfo);
const auto& info = *displayIdInfo->deviceProductInfo;
- EXPECT_STREQ("SAMSUNG", info.name.data());
+ EXPECT_EQ("SAMSUNG", info.name);
EXPECT_STREQ("SAM", info.manufacturerPnpId.data());
- EXPECT_STREQ("2302", info.productId.data());
+ EXPECT_EQ("2302", info.productId);
ASSERT_TRUE(std::holds_alternative<ManufactureWeekAndYear>(info.manufactureOrModelDate));
const auto& date = std::get<ManufactureWeekAndYear>(info.manufactureOrModelDate);
EXPECT_EQ(2011, date.year);
EXPECT_EQ(41, date.week);
- EXPECT_EQ((RelativeAddress{{2, 0, 0, 0}}), info.relativeAddress);
+ EXPECT_THAT(info.relativeAddress, ElementsAre(2, 0, 0, 0));
}
{
const auto displayIdInfo = parseDisplayIdentificationData(0, getPanasonicTvEdid());
ASSERT_TRUE(displayIdInfo);
ASSERT_TRUE(displayIdInfo->deviceProductInfo);
const auto& info = *displayIdInfo->deviceProductInfo;
- EXPECT_STREQ("Panasonic-TV", info.name.data());
+ EXPECT_EQ("Panasonic-TV", info.name);
EXPECT_STREQ("MEI", info.manufacturerPnpId.data());
- EXPECT_STREQ("41622", info.productId.data());
+ EXPECT_EQ("41622", info.productId);
ASSERT_TRUE(std::holds_alternative<ManufactureYear>(info.manufactureOrModelDate));
const auto& date = std::get<ManufactureYear>(info.manufactureOrModelDate);
EXPECT_EQ(2019, date.year);
- EXPECT_EQ((RelativeAddress{{2, 0, 0, 0}}), info.relativeAddress);
+ EXPECT_THAT(info.relativeAddress, ElementsAre(2, 0, 0, 0));
}
{
const auto displayIdInfo = parseDisplayIdentificationData(0, getHisenseTvEdid());
ASSERT_TRUE(displayIdInfo);
ASSERT_TRUE(displayIdInfo->deviceProductInfo);
const auto& info = *displayIdInfo->deviceProductInfo;
- EXPECT_STREQ("Hisense", info.name.data());
+ EXPECT_EQ("Hisense", info.name);
EXPECT_STREQ("HEC", info.manufacturerPnpId.data());
- EXPECT_STREQ("0", info.productId.data());
+ EXPECT_EQ("0", info.productId);
ASSERT_TRUE(std::holds_alternative<ManufactureWeekAndYear>(info.manufactureOrModelDate));
const auto& date = std::get<ManufactureWeekAndYear>(info.manufactureOrModelDate);
EXPECT_EQ(2019, date.year);
EXPECT_EQ(18, date.week);
- EXPECT_EQ((RelativeAddress{{1, 2, 3, 4}}), info.relativeAddress);
+ EXPECT_THAT(info.relativeAddress, ElementsAre(1, 2, 3, 4));
}
{
const auto displayIdInfo = parseDisplayIdentificationData(0, getCtlDisplayEdid());
ASSERT_TRUE(displayIdInfo);
ASSERT_TRUE(displayIdInfo->deviceProductInfo);
const auto& info = *displayIdInfo->deviceProductInfo;
- EXPECT_STREQ("LP2361", info.name.data());
+ EXPECT_EQ("LP2361", info.name);
EXPECT_STREQ("CTL", info.manufacturerPnpId.data());
- EXPECT_STREQ("9373", info.productId.data());
+ EXPECT_EQ("9373", info.productId);
ASSERT_TRUE(std::holds_alternative<ModelYear>(info.manufactureOrModelDate));
EXPECT_EQ(2013, std::get<ModelYear>(info.manufactureOrModelDate).year);
- EXPECT_EQ(DeviceProductInfo::NO_RELATIVE_ADDRESS, info.relativeAddress);
+ EXPECT_TRUE(info.relativeAddress.empty());
}
}
diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
index ce5f35c..9130b04 100644
--- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
@@ -23,6 +23,7 @@
#include <type_traits>
+#include <android/hardware/power/Boost.h>
#include <compositionengine/Display.h>
#include <compositionengine/DisplayColorProfile.h>
#include <compositionengine/impl/Display.h>
@@ -57,6 +58,8 @@
namespace hal = android::hardware::graphics::composer::hal;
+using android::hardware::power::Boost;
+
using testing::_;
using testing::AnyNumber;
using testing::DoAll;
@@ -1347,6 +1350,30 @@
}
/* ------------------------------------------------------------------------
+ * SurfaceFlinger::notifyPowerBoost
+ */
+
+TEST_F(DisplayTransactionTest, notifyPowerBoostNotifiesTouchEvent) {
+ mFlinger.scheduler()->replaceTouchTimer(100);
+ std::this_thread::sleep_for(10ms); // wait for callback to be triggered
+ EXPECT_TRUE(mFlinger.scheduler()->isTouchActive()); // Starting timer activates touch
+
+ std::this_thread::sleep_for(110ms); // wait for reset touch timer to expire and trigger callback
+ EXPECT_FALSE(mFlinger.scheduler()->isTouchActive());
+
+ EXPECT_EQ(NO_ERROR, mFlinger.notifyPowerBoost(static_cast<int32_t>(Boost::CAMERA_SHOT)));
+ std::this_thread::sleep_for(10ms); // wait for callback to maybe be triggered
+ EXPECT_FALSE(mFlinger.scheduler()->isTouchActive());
+
+ std::this_thread::sleep_for(110ms); // wait for reset touch timer to expire and trigger callback
+ EXPECT_FALSE(mFlinger.scheduler()->isTouchActive());
+
+ EXPECT_EQ(NO_ERROR, mFlinger.notifyPowerBoost(static_cast<int32_t>(Boost::INTERACTION)));
+ std::this_thread::sleep_for(10ms); // wait for callback to be triggered.
+ EXPECT_TRUE(mFlinger.scheduler()->isTouchActive());
+}
+
+/* ------------------------------------------------------------------------
* DisplayDevice::GetBestColorMode
*/
class GetBestColorModeTest : public DisplayTransactionTest {
@@ -1794,7 +1821,7 @@
ASSERT_TRUE(displayId);
const auto hwcDisplayId = Case::Display::HWC_DISPLAY_ID_OPT::value;
ASSERT_TRUE(hwcDisplayId);
- state.physical = {*displayId, *connectionType, *hwcDisplayId};
+ state.physical = {.id = *displayId, .type = *connectionType, .hwcDisplayId = *hwcDisplayId};
}
state.isSecure = static_cast<bool>(Case::Display::SECURE);
@@ -1970,7 +1997,9 @@
ASSERT_TRUE(displayId);
const auto hwcDisplayId = Case::Display::HWC_DISPLAY_ID_OPT::value;
ASSERT_TRUE(hwcDisplayId);
- expectedPhysical = {*displayId, *connectionType, *hwcDisplayId};
+ expectedPhysical = {.id = *displayId,
+ .type = *connectionType,
+ .hwcDisplayId = *hwcDisplayId};
}
// The display should have been set up in the current display state
diff --git a/services/surfaceflinger/tests/unittests/TestableScheduler.h b/services/surfaceflinger/tests/unittests/TestableScheduler.h
index d5ecae8..b7067a6 100644
--- a/services/surfaceflinger/tests/unittests/TestableScheduler.h
+++ b/services/surfaceflinger/tests/unittests/TestableScheduler.h
@@ -72,13 +72,31 @@
auto& mutableEventControlThread() { return mEventControlThread; }
auto& mutablePrimaryDispSync() { return mPrimaryDispSync; }
auto& mutableHWVsyncAvailable() { return mHWVsyncAvailable; }
+
auto mutableLayerHistory() {
return static_cast<scheduler::impl::LayerHistory*>(mLayerHistory.get());
}
+
auto mutableLayerHistoryV2() {
return static_cast<scheduler::impl::LayerHistoryV2*>(mLayerHistory.get());
}
+ void replaceTouchTimer(int64_t millis) {
+ if (mTouchTimer) {
+ mTouchTimer.reset();
+ }
+ mTouchTimer.emplace(
+ std::chrono::milliseconds(millis),
+ [this] { touchTimerCallback(TimerState::Reset); },
+ [this] { touchTimerCallback(TimerState::Expired); });
+ mTouchTimer->start();
+ }
+
+ bool isTouchActive() {
+ std::lock_guard<std::mutex> lock(mFeatureStateLock);
+ return mFeatures.touch == Scheduler::TouchState::Active;
+ }
+
~TestableScheduler() {
// All these pointer and container clears help ensure that GMock does
// not report a leaked object, since the Scheduler instance may
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index 38bc8a1..f630103 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -321,6 +321,8 @@
return mFlinger->onInitializeDisplays();
}
+ auto notifyPowerBoost(int32_t boostId) { return mFlinger->notifyPowerBoost(boostId); }
+
// Allow reading display state without locking, as if called on the SF main thread.
auto setPowerModeInternal(const sp<DisplayDevice>& display,
hal::PowerMode mode) NO_THREAD_SAFETY_ANALYSIS {
@@ -331,7 +333,7 @@
auto captureScreenImplLocked(const RenderArea& renderArea,
SurfaceFlinger::TraverseLayersFunction traverseLayers,
- ANativeWindowBuffer* buffer, bool useIdentityTransform,
+ const sp<GraphicBuffer>& buffer, bool useIdentityTransform,
bool forSystem, int* outSyncFd, bool regionSampling) {
bool ignored;
return mFlinger->captureScreenImplLocked(renderArea, traverseLayers, buffer,
@@ -339,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,
@@ -633,7 +635,7 @@
if (const auto type = mCreationArgs.connectionType) {
LOG_ALWAYS_FATAL_IF(!displayId);
LOG_ALWAYS_FATAL_IF(!mHwcDisplayId);
- state.physical = {*displayId, *type, *mHwcDisplayId};
+ state.physical = {.id = *displayId, .type = *type, .hwcDisplayId = *mHwcDisplayId};
}
state.isSecure = mCreationArgs.isSecure;
diff --git a/services/vibratorservice/Android.bp b/services/vibratorservice/Android.bp
new file mode 100644
index 0000000..c45a1a1
--- /dev/null
+++ b/services/vibratorservice/Android.bp
@@ -0,0 +1,54 @@
+// 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.
+
+cc_library_shared {
+ name: "libvibratorservice",
+
+ srcs: [
+ "VibratorCallbackScheduler.cpp",
+ "VibratorHalController.cpp",
+ "VibratorHalWrapper.cpp",
+ ],
+
+ aidl: {
+ local_include_dirs: ["include"],
+ include_dirs: [
+ "hardware/interfaces/vibrator/aidl/android/hardware/vibrator",
+ ],
+ export_aidl_headers: true
+ },
+
+ shared_libs: [
+ "libbinder",
+ "libhidlbase",
+ "liblog",
+ "libutils",
+ "android.hardware.vibrator-cpp",
+ "android.hardware.vibrator@1.0",
+ "android.hardware.vibrator@1.1",
+ "android.hardware.vibrator@1.2",
+ "android.hardware.vibrator@1.3",
+ ],
+
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-Wunused",
+ "-Wunreachable-code",
+ ],
+
+ local_include_dirs: ["include"],
+
+ export_include_dirs: ["include"],
+}
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/VibratorHalController.cpp b/services/vibratorservice/VibratorHalController.cpp
new file mode 100644
index 0000000..896c162
--- /dev/null
+++ b/services/vibratorservice/VibratorHalController.cpp
@@ -0,0 +1,235 @@
+/*
+ * 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 "VibratorHalController"
+
+#include <android/hardware/vibrator/1.3/IVibrator.h>
+#include <android/hardware/vibrator/IVibrator.h>
+#include <binder/IServiceManager.h>
+#include <hardware/vibrator.h>
+
+#include <utils/Log.h>
+
+#include <vibratorservice/VibratorCallbackScheduler.h>
+#include <vibratorservice/VibratorHalController.h>
+#include <vibratorservice/VibratorHalWrapper.h>
+
+using android::hardware::vibrator::CompositeEffect;
+using android::hardware::vibrator::Effect;
+using android::hardware::vibrator::EffectStrength;
+
+using std::chrono::milliseconds;
+
+namespace V1_0 = android::hardware::vibrator::V1_0;
+namespace V1_1 = android::hardware::vibrator::V1_1;
+namespace V1_2 = android::hardware::vibrator::V1_2;
+namespace V1_3 = android::hardware::vibrator::V1_3;
+namespace Aidl = android::hardware::vibrator;
+
+namespace android {
+
+namespace vibrator {
+
+// -------------------------------------------------------------------------------------------------
+
+static constexpr int MAX_RETRIES = 1;
+
+template <typename T>
+using hal_connect_fn = std::function<sp<T>()>;
+
+template <typename T>
+sp<T> connectToHal(bool* halExists, const hal_connect_fn<T>& connectFn, const char* halName) {
+ if (!*halExists) {
+ return nullptr;
+ }
+ sp<T> hal = connectFn();
+ if (hal) {
+ ALOGV("Successfully connected to Vibrator HAL %s service.", halName);
+ } else {
+ ALOGV("Vibrator HAL %s service not available.", halName);
+ *halExists = false;
+ }
+ return hal;
+}
+
+sp<Aidl::IVibrator> connectToAidl() {
+ static bool gHalExists = true;
+ static hal_connect_fn<Aidl::IVibrator> connectFn = []() {
+ return waitForVintfService<Aidl::IVibrator>();
+ };
+ return connectToHal(&gHalExists, connectFn, "AIDL");
+}
+
+sp<V1_0::IVibrator> connectToHidl() {
+ static bool gHalExists = true;
+ static hal_connect_fn<V1_0::IVibrator> connectFn = []() {
+ return V1_0::IVibrator::getService();
+ };
+ return connectToHal(&gHalExists, connectFn, "v1.0");
+}
+
+// -------------------------------------------------------------------------------------------------
+
+std::shared_ptr<HalWrapper> HalConnector::connect(std::shared_ptr<CallbackScheduler> scheduler) {
+ sp<Aidl::IVibrator> aidlHal = connectToAidl();
+ if (aidlHal) {
+ return std::make_shared<AidlHalWrapper>(std::move(scheduler), aidlHal);
+ }
+ sp<V1_0::IVibrator> halV1_0 = connectToHidl();
+ if (halV1_0 == nullptr) {
+ // No Vibrator HAL service available.
+ return nullptr;
+ }
+ sp<V1_3::IVibrator> halV1_3 = V1_3::IVibrator::castFrom(halV1_0);
+ if (halV1_3) {
+ ALOGV("Successfully converted to Vibrator HAL v1.3 service.");
+ return std::make_shared<HidlHalWrapperV1_3>(std::move(scheduler), halV1_3);
+ }
+ sp<V1_2::IVibrator> halV1_2 = V1_2::IVibrator::castFrom(halV1_0);
+ if (halV1_2) {
+ ALOGV("Successfully converted to Vibrator HAL v1.2 service.");
+ return std::make_shared<HidlHalWrapperV1_2>(std::move(scheduler), halV1_2);
+ }
+ sp<V1_1::IVibrator> halV1_1 = V1_1::IVibrator::castFrom(halV1_0);
+ if (halV1_1) {
+ ALOGV("Successfully converted to Vibrator HAL v1.1 service.");
+ return std::make_shared<HidlHalWrapperV1_1>(std::move(scheduler), halV1_1);
+ }
+ return std::make_shared<HidlHalWrapperV1_0>(std::move(scheduler), halV1_0);
+}
+
+// -------------------------------------------------------------------------------------------------
+
+std::shared_ptr<HalWrapper> HalController::initHal() {
+ std::lock_guard<std::mutex> lock(mConnectedHalMutex);
+ if (mConnectedHal == nullptr) {
+ mConnectedHal = mHalConnector->connect(mCallbackScheduler);
+ }
+ return mConnectedHal;
+}
+
+template <typename T>
+HalResult<T> HalController::processHalResult(HalResult<T> result, const char* functionName) {
+ if (result.isFailed()) {
+ ALOGE("%s failed: Vibrator HAL not available", functionName);
+ std::lock_guard<std::mutex> lock(mConnectedHalMutex);
+ // Drop HAL handle. This will force future api calls to reconnect.
+ mConnectedHal = nullptr;
+ }
+ return result;
+}
+
+template <typename T>
+HalResult<T> HalController::apply(HalController::hal_fn<T>& halFn, const char* functionName) {
+ std::shared_ptr<HalWrapper> hal = initHal();
+ if (hal == nullptr) {
+ ALOGV("Skipped %s because Vibrator HAL is not available", functionName);
+ return HalResult<T>::unsupported();
+ }
+
+ HalResult<T> ret = processHalResult(halFn(hal), functionName);
+ for (int i = 0; i < MAX_RETRIES && ret.isFailed(); i++) {
+ hal = initHal();
+ if (hal) {
+ ret = processHalResult(halFn(hal), functionName);
+ }
+ }
+
+ return ret;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+HalResult<void> HalController::ping() {
+ hal_fn<void> pingFn = [](std::shared_ptr<HalWrapper> hal) { return hal->ping(); };
+ return apply(pingFn, "ping");
+}
+
+HalResult<void> HalController::on(milliseconds timeout,
+ const std::function<void()>& completionCallback) {
+ hal_fn<void> onFn = [&](std::shared_ptr<HalWrapper> hal) {
+ return hal->on(timeout, completionCallback);
+ };
+ return apply(onFn, "on");
+}
+
+HalResult<void> HalController::off() {
+ hal_fn<void> offFn = [](std::shared_ptr<HalWrapper> hal) { return hal->off(); };
+ return apply(offFn, "off");
+}
+
+HalResult<void> HalController::setAmplitude(int32_t amplitude) {
+ hal_fn<void> setAmplitudeFn = [&](std::shared_ptr<HalWrapper> hal) {
+ return hal->setAmplitude(amplitude);
+ };
+ return apply(setAmplitudeFn, "setAmplitude");
+}
+
+HalResult<void> HalController::setExternalControl(bool enabled) {
+ hal_fn<void> setExternalControlFn = [&](std::shared_ptr<HalWrapper> hal) {
+ return hal->setExternalControl(enabled);
+ };
+ return apply(setExternalControlFn, "setExternalControl");
+}
+
+HalResult<void> HalController::alwaysOnEnable(int32_t id, Effect effect, EffectStrength strength) {
+ hal_fn<void> alwaysOnEnableFn = [&](std::shared_ptr<HalWrapper> hal) {
+ return hal->alwaysOnEnable(id, effect, strength);
+ };
+ return apply(alwaysOnEnableFn, "alwaysOnEnable");
+}
+
+HalResult<void> HalController::alwaysOnDisable(int32_t id) {
+ hal_fn<void> alwaysOnDisableFn = [&](std::shared_ptr<HalWrapper> hal) {
+ return hal->alwaysOnDisable(id);
+ };
+ return apply(alwaysOnDisableFn, "alwaysOnDisable");
+}
+
+HalResult<Capabilities> HalController::getCapabilities() {
+ hal_fn<Capabilities> getCapabilitiesFn = [](std::shared_ptr<HalWrapper> hal) {
+ return hal->getCapabilities();
+ };
+ return apply(getCapabilitiesFn, "getCapabilities");
+}
+
+HalResult<std::vector<Effect>> HalController::getSupportedEffects() {
+ hal_fn<std::vector<Effect>> getSupportedEffectsFn = [](std::shared_ptr<HalWrapper> hal) {
+ return hal->getSupportedEffects();
+ };
+ return apply(getSupportedEffectsFn, "getSupportedEffects");
+}
+
+HalResult<milliseconds> HalController::performEffect(
+ Effect effect, EffectStrength strength, const std::function<void()>& completionCallback) {
+ hal_fn<milliseconds> performEffectFn = [&](std::shared_ptr<HalWrapper> hal) {
+ return hal->performEffect(effect, strength, completionCallback);
+ };
+ return apply(performEffectFn, "performEffect");
+}
+
+HalResult<void> HalController::performComposedEffect(
+ const std::vector<CompositeEffect>& primitiveEffects,
+ const std::function<void()>& completionCallback) {
+ hal_fn<void> performComposedEffectFn = [&](std::shared_ptr<HalWrapper> hal) {
+ return hal->performComposedEffect(primitiveEffects, completionCallback);
+ };
+ return apply(performComposedEffectFn, "performComposedEffect");
+}
+
+}; // namespace vibrator
+
+}; // namespace android
diff --git a/services/vibratorservice/VibratorHalWrapper.cpp b/services/vibratorservice/VibratorHalWrapper.cpp
new file mode 100644
index 0000000..94db538
--- /dev/null
+++ b/services/vibratorservice/VibratorHalWrapper.cpp
@@ -0,0 +1,450 @@
+/*
+ * 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 "VibratorHalWrapper"
+
+#include <android/hardware/vibrator/1.3/IVibrator.h>
+#include <android/hardware/vibrator/BnVibratorCallback.h>
+#include <android/hardware/vibrator/IVibrator.h>
+#include <hardware/vibrator.h>
+
+#include <utils/Log.h>
+
+#include <vibratorservice/VibratorCallbackScheduler.h>
+#include <vibratorservice/VibratorHalWrapper.h>
+
+using android::hardware::vibrator::CompositeEffect;
+using android::hardware::vibrator::Effect;
+using android::hardware::vibrator::EffectStrength;
+
+using std::chrono::milliseconds;
+
+namespace V1_0 = android::hardware::vibrator::V1_0;
+namespace V1_1 = android::hardware::vibrator::V1_1;
+namespace V1_2 = android::hardware::vibrator::V1_2;
+namespace V1_3 = android::hardware::vibrator::V1_3;
+namespace Aidl = android::hardware::vibrator;
+
+namespace android {
+
+namespace vibrator {
+
+// -------------------------------------------------------------------------------------------------
+
+template <class T>
+HalResult<T> loadCached(const std::function<HalResult<T>()>& loadFn, std::optional<T>& cache) {
+ if (cache.has_value()) {
+ // Return copy of cached value.
+ return HalResult<T>::ok(*cache);
+ }
+ HalResult<T> ret = loadFn();
+ if (ret.isOk()) {
+ // Cache copy of returned value.
+ cache.emplace(ret.value());
+ }
+ return ret;
+}
+
+template <class T>
+bool isStaticCastValid(Effect effect) {
+ T castEffect = static_cast<T>(effect);
+ auto iter = hardware::hidl_enum_range<T>();
+ return castEffect >= *iter.begin() && castEffect <= *std::prev(iter.end());
+}
+
+// -------------------------------------------------------------------------------------------------
+
+template <typename T>
+HalResult<T> HalResult<T>::fromStatus(binder::Status status, T data) {
+ if (status.exceptionCode() == binder::Status::EX_UNSUPPORTED_OPERATION) {
+ return HalResult<T>::unsupported();
+ }
+ if (status.isOk()) {
+ return HalResult<T>::ok(data);
+ }
+ return HalResult<T>::failed();
+}
+
+template <typename T>
+HalResult<T> HalResult<T>::fromStatus(V1_0::Status status, T data) {
+ switch (status) {
+ case V1_0::Status::OK:
+ return HalResult<T>::ok(data);
+ case V1_0::Status::UNSUPPORTED_OPERATION:
+ return HalResult<T>::unsupported();
+ default:
+ return HalResult<T>::failed();
+ }
+}
+
+template <typename T>
+template <typename R>
+HalResult<T> HalResult<T>::fromReturn(hardware::Return<R>& ret, T data) {
+ return ret.isOk() ? HalResult<T>::ok(data) : HalResult<T>::failed();
+}
+
+template <typename T>
+template <typename R>
+HalResult<T> HalResult<T>::fromReturn(hardware::Return<R>& ret, V1_0::Status status, T data) {
+ return ret.isOk() ? HalResult<T>::fromStatus(status, data) : HalResult<T>::failed();
+}
+
+// -------------------------------------------------------------------------------------------------
+
+HalResult<void> HalResult<void>::fromStatus(binder::Status status) {
+ if (status.exceptionCode() == binder::Status::EX_UNSUPPORTED_OPERATION) {
+ return HalResult<void>::unsupported();
+ }
+ if (status.isOk()) {
+ return HalResult<void>::ok();
+ }
+ return HalResult<void>::failed();
+}
+
+HalResult<void> HalResult<void>::fromStatus(V1_0::Status status) {
+ switch (status) {
+ case V1_0::Status::OK:
+ return HalResult<void>::ok();
+ case V1_0::Status::UNSUPPORTED_OPERATION:
+ return HalResult<void>::unsupported();
+ default:
+ return HalResult<void>::failed();
+ }
+}
+
+template <typename R>
+HalResult<void> HalResult<void>::fromReturn(hardware::Return<R>& ret) {
+ return ret.isOk() ? HalResult<void>::ok() : HalResult<void>::failed();
+}
+
+// -------------------------------------------------------------------------------------------------
+
+class HalCallbackWrapper : public Aidl::BnVibratorCallback {
+public:
+ HalCallbackWrapper(std::function<void()> completionCallback)
+ : mCompletionCallback(completionCallback) {}
+
+ binder::Status onComplete() override {
+ mCompletionCallback();
+ return binder::Status::ok();
+ }
+
+private:
+ const std::function<void()> mCompletionCallback;
+};
+
+// -------------------------------------------------------------------------------------------------
+
+HalResult<void> AidlHalWrapper::ping() {
+ return IInterface::asBinder(mHandle)->pingBinder() ? HalResult<void>::ok()
+ : HalResult<void>::failed();
+}
+
+HalResult<void> AidlHalWrapper::on(milliseconds timeout,
+ const std::function<void()>& completionCallback) {
+ 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() {
+ return HalResult<void>::fromStatus(mHandle->off());
+}
+
+HalResult<void> AidlHalWrapper::setAmplitude(int32_t amplitude) {
+ float convertedAmplitude = static_cast<float>(amplitude) / std::numeric_limits<uint8_t>::max();
+ return HalResult<void>::fromStatus(mHandle->setAmplitude(convertedAmplitude));
+}
+
+HalResult<void> AidlHalWrapper::setExternalControl(bool enabled) {
+ return HalResult<void>::fromStatus(mHandle->setExternalControl(enabled));
+}
+
+HalResult<void> AidlHalWrapper::alwaysOnEnable(int32_t id, Effect effect, EffectStrength strength) {
+ return HalResult<void>::fromStatus(mHandle->alwaysOnEnable(id, effect, strength));
+}
+
+HalResult<void> AidlHalWrapper::alwaysOnDisable(int32_t id) {
+ return HalResult<void>::fromStatus(mHandle->alwaysOnDisable(id));
+}
+
+HalResult<Capabilities> AidlHalWrapper::getCapabilities() {
+ std::lock_guard<std::mutex> lock(mCapabilitiesMutex);
+ return loadCached<Capabilities>(std::bind(&AidlHalWrapper::getCapabilitiesInternal, this),
+ mCapabilities);
+}
+
+HalResult<std::vector<Effect>> AidlHalWrapper::getSupportedEffects() {
+ std::lock_guard<std::mutex> lock(mSupportedEffectsMutex);
+ return loadCached<std::vector<Effect>>(std::bind(&AidlHalWrapper::getSupportedEffectsInternal,
+ this),
+ mSupportedEffects);
+}
+
+HalResult<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 result = mHandle->perform(effect, strength, cb, &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() {
+ auto result = mHandleV1_0->ping();
+ return HalResult<void>::fromReturn(result);
+}
+
+HalResult<void> HidlHalWrapperV1_0::on(milliseconds timeout,
+ const std::function<void()>& completionCallback) {
+ auto result = mHandleV1_0->on(timeout.count());
+ 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() {
+ auto result = mHandleV1_0->off();
+ return HalResult<void>::fromStatus(result.withDefault(V1_0::Status::UNKNOWN_ERROR));
+}
+
+HalResult<void> HidlHalWrapperV1_0::setAmplitude(int32_t amplitude) {
+ auto result = mHandleV1_0->setAmplitude(static_cast<uint8_t>(amplitude));
+ return HalResult<void>::fromStatus(result.withDefault(V1_0::Status::UNKNOWN_ERROR));
+}
+
+HalResult<void> HidlHalWrapperV1_0::setExternalControl(bool) {
+ ALOGV("Skipped setExternalControl because Vibrator HAL does not support it");
+ return HalResult<void>::unsupported();
+}
+
+HalResult<void> HidlHalWrapperV1_0::alwaysOnEnable(int32_t, Effect, EffectStrength) {
+ ALOGV("Skipped alwaysOnEnable because Vibrator HAL AIDL is not available");
+ return HalResult<void>::unsupported();
+}
+
+HalResult<void> HidlHalWrapperV1_0::alwaysOnDisable(int32_t) {
+ ALOGV("Skipped alwaysOnDisable because Vibrator HAL AIDL is not available");
+ return HalResult<void>::unsupported();
+}
+
+HalResult<Capabilities> HidlHalWrapperV1_0::getCapabilities() {
+ std::lock_guard<std::mutex> lock(mCapabilitiesMutex);
+ return loadCached<Capabilities>(std::bind(&HidlHalWrapperV1_0::getCapabilitiesInternal, this),
+ mCapabilities);
+}
+
+HalResult<std::vector<Effect>> HidlHalWrapperV1_0::getSupportedEffects() {
+ ALOGV("Skipped getSupportedEffects because Vibrator HAL AIDL is not available");
+ return HalResult<std::vector<Effect>>::unsupported();
+}
+
+HalResult<milliseconds> HidlHalWrapperV1_0::performEffect(
+ Effect effect, EffectStrength strength, const std::function<void()>& completionCallback) {
+ if (isStaticCastValid<V1_0::Effect>(effect)) {
+ return performInternalV1_0(effect, strength, completionCallback);
+ }
+
+ ALOGV("Skipped performEffect because Vibrator HAL does not support effect %s",
+ Aidl::toString(effect).c_str());
+ return HalResult<milliseconds>::unsupported();
+}
+
+HalResult<void> HidlHalWrapperV1_0::performComposedEffect(const std::vector<CompositeEffect>&,
+ const std::function<void()>&) {
+ ALOGV("Skipped composed effect because Vibrator HAL AIDL is not available");
+ return HalResult<void>::unsupported();
+}
+
+HalResult<Capabilities> HidlHalWrapperV1_0::getCapabilitiesInternal() {
+ hardware::Return<bool> result = mHandleV1_0->supportsAmplitudeControl();
+ Capabilities capabilities =
+ result.withDefault(false) ? Capabilities::AMPLITUDE_CONTROL : Capabilities::NONE;
+ 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()>& completionCallback) {
+ if (isStaticCastValid<V1_0::Effect>(effect)) {
+ return performInternalV1_0(effect, strength, completionCallback);
+ }
+ if (isStaticCastValid<V1_1::Effect_1_1>(effect)) {
+ return performInternalV1_1(effect, strength, completionCallback);
+ }
+
+ ALOGV("Skipped performEffect because Vibrator HAL does not support effect %s",
+ Aidl::toString(effect).c_str());
+ 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()>& completionCallback) {
+ if (isStaticCastValid<V1_0::Effect>(effect)) {
+ return performInternalV1_0(effect, strength, completionCallback);
+ }
+ if (isStaticCastValid<V1_1::Effect_1_1>(effect)) {
+ return performInternalV1_1(effect, strength, completionCallback);
+ }
+ if (isStaticCastValid<V1_2::Effect>(effect)) {
+ return performInternalV1_2(effect, strength, completionCallback);
+ }
+
+ ALOGV("Skipped performEffect because Vibrator HAL does not support effect %s",
+ Aidl::toString(effect).c_str());
+ 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) {
+ auto result = mHandleV1_3->setExternalControl(static_cast<uint32_t>(enabled));
+ return HalResult<void>::fromStatus(result.withDefault(V1_0::Status::UNKNOWN_ERROR));
+}
+
+HalResult<milliseconds> HidlHalWrapperV1_3::performEffect(
+ Effect effect, EffectStrength strength, const std::function<void()>& completionCallback) {
+ if (isStaticCastValid<V1_0::Effect>(effect)) {
+ return performInternalV1_0(effect, strength, completionCallback);
+ }
+ if (isStaticCastValid<V1_1::Effect_1_1>(effect)) {
+ return performInternalV1_1(effect, strength, completionCallback);
+ }
+ if (isStaticCastValid<V1_2::Effect>(effect)) {
+ return performInternalV1_2(effect, strength, completionCallback);
+ }
+ if (isStaticCastValid<V1_3::Effect>(effect)) {
+ return performInternalV1_3(effect, strength, completionCallback);
+ }
+
+ ALOGV("Skipped performEffect because Vibrator HAL does not support effect %s",
+ Aidl::toString(effect).c_str());
+ return HalResult<milliseconds>::unsupported();
+}
+
+HalResult<Capabilities> HidlHalWrapperV1_3::getCapabilitiesInternal() {
+ HalResult<Capabilities> parentResult = HidlHalWrapperV1_2::getCapabilitiesInternal();
+ if (!parentResult.isOk()) {
+ // Loading for previous HAL versions already failed, so propagate failure.
+ return parentResult;
+ }
+
+ Capabilities capabilities = parentResult.value();
+ auto result = mHandleV1_3->supportsExternalControl();
+ capabilities |= result.withDefault(false) ? Capabilities::EXTERNAL_CONTROL : Capabilities::NONE;
+ 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
+
+}; // namespace android
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/VibratorHalController.h b/services/vibratorservice/include/vibratorservice/VibratorHalController.h
new file mode 100644
index 0000000..1fb7d05
--- /dev/null
+++ b/services/vibratorservice/include/vibratorservice/VibratorHalController.h
@@ -0,0 +1,100 @@
+/*
+ * 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_OS_VIBRATORHALCONTROLLER_H
+#define ANDROID_OS_VIBRATORHALCONTROLLER_H
+
+#include <android-base/thread_annotations.h>
+#include <android/hardware/vibrator/IVibrator.h>
+
+#include <vibratorservice/VibratorCallbackScheduler.h>
+#include <vibratorservice/VibratorHalWrapper.h>
+
+namespace android {
+
+namespace vibrator {
+
+// Handles the connection to he underlying HAL implementation available.
+class HalConnector {
+public:
+ HalConnector() = default;
+ virtual ~HalConnector() = default;
+
+ virtual std::shared_ptr<HalWrapper> connect(std::shared_ptr<CallbackScheduler> scheduler);
+};
+
+// Controller for Vibrator HAL handle.
+// This relies on HalConnector to connect to the underlying Vibrator HAL service and reconnects to
+// it after each failed api call. This also ensures connecting to the service is thread-safe.
+class HalController : public HalWrapper {
+public:
+ HalController()
+ : HalController(std::make_unique<HalConnector>(), std::make_shared<CallbackScheduler>()) {
+ }
+ HalController(std::unique_ptr<HalConnector> halConnector,
+ std::shared_ptr<CallbackScheduler> callbackScheduler)
+ : HalWrapper(std::move(callbackScheduler)),
+ mHalConnector(std::move(halConnector)),
+ mConnectedHal(nullptr) {}
+ virtual ~HalController() = default;
+
+ HalResult<void> ping() final override;
+
+ HalResult<void> on(std::chrono::milliseconds timeout,
+ const std::function<void()>& completionCallback) final override;
+ HalResult<void> off() final override;
+
+ HalResult<void> setAmplitude(int32_t amplitude) final override;
+ HalResult<void> setExternalControl(bool enabled) final override;
+
+ HalResult<void> alwaysOnEnable(int32_t id, hardware::vibrator::Effect effect,
+ hardware::vibrator::EffectStrength strength) final override;
+ HalResult<void> alwaysOnDisable(int32_t id) final override;
+
+ HalResult<Capabilities> getCapabilities() final override;
+ HalResult<std::vector<hardware::vibrator::Effect>> getSupportedEffects() final override;
+
+ HalResult<std::chrono::milliseconds> performEffect(
+ hardware::vibrator::Effect effect, hardware::vibrator::EffectStrength strength,
+ const std::function<void()>& completionCallback) final override;
+
+ HalResult<void> performComposedEffect(
+ const std::vector<hardware::vibrator::CompositeEffect>& primitiveEffects,
+ const std::function<void()>& completionCallback) final override;
+
+private:
+ std::unique_ptr<HalConnector> mHalConnector;
+ std::mutex mConnectedHalMutex;
+ // Shared pointer to allow local copies to be used by different threads.
+ std::shared_ptr<HalWrapper> mConnectedHal GUARDED_BY(mConnectedHalMutex);
+
+ std::shared_ptr<HalWrapper> initHal();
+
+ template <typename T>
+ HalResult<T> processHalResult(HalResult<T> result, const char* functionName);
+
+ template <typename T>
+ using hal_fn = std::function<HalResult<T>(std::shared_ptr<HalWrapper>)>;
+
+ template <typename T>
+ HalResult<T> apply(hal_fn<T>& halFn, const char* functionName);
+};
+
+}; // namespace vibrator
+
+}; // namespace android
+
+#endif // ANDROID_OS_VIBRATORHALCONTROLLER_H
diff --git a/services/vibratorservice/include/vibratorservice/VibratorHalWrapper.h b/services/vibratorservice/include/vibratorservice/VibratorHalWrapper.h
new file mode 100644
index 0000000..5e3c275
--- /dev/null
+++ b/services/vibratorservice/include/vibratorservice/VibratorHalWrapper.h
@@ -0,0 +1,332 @@
+/*
+ * 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_OS_VIBRATORHALWRAPPER_H
+#define ANDROID_OS_VIBRATORHALWRAPPER_H
+
+#include <android-base/thread_annotations.h>
+#include <android/hardware/vibrator/1.3/IVibrator.h>
+#include <android/hardware/vibrator/IVibrator.h>
+
+#include <vibratorservice/VibratorCallbackScheduler.h>
+
+namespace android {
+
+namespace vibrator {
+
+// -------------------------------------------------------------------------------------------------
+
+// Result of a call to the Vibrator HAL wrapper, holding data if successful.
+template <typename T>
+class HalResult {
+public:
+ static HalResult<T> ok(T value) { return HalResult(value); }
+ static HalResult<T> failed() { return HalResult(/* unsupported= */ false); }
+ static HalResult<T> unsupported() { return HalResult(/* unsupported= */ true); }
+
+ static HalResult<T> fromStatus(binder::Status status, T data);
+ static HalResult<T> fromStatus(hardware::vibrator::V1_0::Status status, T data);
+
+ template <typename R>
+ static HalResult<T> fromReturn(hardware::Return<R>& ret, T data);
+
+ template <typename R>
+ static HalResult<T> fromReturn(hardware::Return<R>& ret,
+ hardware::vibrator::V1_0::Status status, T data);
+
+ // This will throw std::bad_optional_access if this result is not ok.
+ 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; }
+
+private:
+ std::optional<T> mValue;
+ bool mUnsupported;
+
+ explicit HalResult(T value) : mValue(std::make_optional(value)), mUnsupported(false) {}
+ explicit HalResult(bool unsupported) : mValue(), mUnsupported(unsupported) {}
+};
+
+// Empty result of a call to the Vibrator HAL wrapper.
+template <>
+class HalResult<void> {
+public:
+ static HalResult<void> ok() { return HalResult(); }
+ static HalResult<void> failed() { return HalResult(/* failed= */ true); }
+ static HalResult<void> unsupported() {
+ return HalResult(/* failed= */ false, /* unsupported= */ true);
+ }
+
+ static HalResult<void> fromStatus(binder::Status status);
+ static HalResult<void> fromStatus(hardware::vibrator::V1_0::Status status);
+
+ template <typename R>
+ static HalResult<void> fromReturn(hardware::Return<R>& ret);
+
+ bool isOk() const { return !mUnsupported && !mFailed; }
+ bool isFailed() const { return !mUnsupported && mFailed; }
+ bool isUnsupported() const { return mUnsupported; }
+
+private:
+ bool mFailed;
+ bool mUnsupported;
+
+ explicit HalResult(bool failed = false, bool unsupported = false)
+ : mFailed(failed), mUnsupported(unsupported) {}
+};
+
+// -------------------------------------------------------------------------------------------------
+
+// Vibrator HAL capabilities.
+enum class Capabilities : int32_t {
+ NONE = 0,
+ ON_CALLBACK = hardware::vibrator::IVibrator::CAP_ON_CALLBACK,
+ PERFORM_CALLBACK = hardware::vibrator::IVibrator::CAP_PERFORM_CALLBACK,
+ AMPLITUDE_CONTROL = hardware::vibrator::IVibrator::CAP_AMPLITUDE_CONTROL,
+ EXTERNAL_CONTROL = hardware::vibrator::IVibrator::CAP_EXTERNAL_CONTROL,
+ EXTERNAL_AMPLITUDE_CONTROL = hardware::vibrator::IVibrator::CAP_EXTERNAL_AMPLITUDE_CONTROL,
+ COMPOSE_EFFECTS = hardware::vibrator::IVibrator::CAP_COMPOSE_EFFECTS,
+ ALWAYS_ON_CONTROL = hardware::vibrator::IVibrator::CAP_ALWAYS_ON_CONTROL
+};
+
+inline Capabilities operator|(Capabilities lhs, Capabilities rhs) {
+ using underlying = typename std::underlying_type<Capabilities>::type;
+ return static_cast<Capabilities>(static_cast<underlying>(lhs) | static_cast<underlying>(rhs));
+}
+
+inline Capabilities& operator|=(Capabilities& lhs, Capabilities rhs) {
+ return lhs = lhs | rhs;
+}
+
+inline Capabilities operator&(Capabilities lhs, Capabilities rhs) {
+ using underlying = typename std::underlying_type<Capabilities>::type;
+ return static_cast<Capabilities>(static_cast<underlying>(lhs) & static_cast<underlying>(rhs));
+}
+
+inline Capabilities& operator&=(Capabilities& lhs, Capabilities rhs) {
+ return lhs = lhs & rhs;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+// 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;
+
+ virtual HalResult<void> on(std::chrono::milliseconds timeout,
+ const std::function<void()>& completionCallback) = 0;
+ virtual HalResult<void> off() = 0;
+
+ virtual HalResult<void> setAmplitude(int32_t amplitude) = 0;
+ virtual HalResult<void> setExternalControl(bool enabled) = 0;
+
+ virtual HalResult<void> alwaysOnEnable(int32_t id, hardware::vibrator::Effect effect,
+ hardware::vibrator::EffectStrength strength) = 0;
+ virtual HalResult<void> alwaysOnDisable(int32_t id) = 0;
+
+ virtual HalResult<Capabilities> getCapabilities() = 0;
+ virtual HalResult<std::vector<hardware::vibrator::Effect>> getSupportedEffects() = 0;
+
+ virtual HalResult<std::chrono::milliseconds> performEffect(
+ hardware::vibrator::Effect effect, hardware::vibrator::EffectStrength strength,
+ const std::function<void()>& completionCallback) = 0;
+
+ 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:
+ 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;
+
+ virtual HalResult<void> on(std::chrono::milliseconds timeout,
+ const std::function<void()>& completionCallback) override;
+ virtual HalResult<void> off() override;
+
+ virtual HalResult<void> setAmplitude(int32_t amplitude) override;
+ virtual HalResult<void> setExternalControl(bool enabled) override;
+
+ virtual HalResult<void> alwaysOnEnable(int32_t id, hardware::vibrator::Effect effect,
+ hardware::vibrator::EffectStrength strength) override;
+ virtual HalResult<void> alwaysOnDisable(int32_t id) override;
+
+ virtual HalResult<Capabilities> getCapabilities() override;
+ virtual HalResult<std::vector<hardware::vibrator::Effect>> getSupportedEffects() override;
+
+ virtual HalResult<std::chrono::milliseconds> performEffect(
+ hardware::vibrator::Effect effect, hardware::vibrator::EffectStrength strength,
+ const std::function<void()>& completionCallback) override;
+
+ virtual HalResult<void> performComposedEffect(
+ const std::vector<hardware::vibrator::CompositeEffect>& primitiveEffects,
+ const std::function<void()>& completionCallback) override;
+
+private:
+ const sp<hardware::vibrator::IVibrator> mHandle;
+ std::mutex mCapabilitiesMutex;
+ std::mutex mSupportedEffectsMutex;
+ 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:
+ 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;
+
+ virtual HalResult<void> on(std::chrono::milliseconds timeout,
+ const std::function<void()>& completionCallback) override;
+ virtual HalResult<void> off() override;
+
+ virtual HalResult<void> setAmplitude(int32_t amplitude) override;
+ virtual HalResult<void> setExternalControl(bool enabled) override;
+
+ virtual HalResult<void> alwaysOnEnable(int32_t id, hardware::vibrator::Effect effect,
+ hardware::vibrator::EffectStrength strength) override;
+ virtual HalResult<void> alwaysOnDisable(int32_t id) override;
+
+ virtual HalResult<Capabilities> getCapabilities() override;
+ virtual HalResult<std::vector<hardware::vibrator::Effect>> getSupportedEffects() override;
+
+ virtual HalResult<std::chrono::milliseconds> performEffect(
+ hardware::vibrator::Effect effect, hardware::vibrator::EffectStrength strength,
+ const std::function<void()>& completionCallback) override;
+
+ virtual HalResult<void> performComposedEffect(
+ const std::vector<hardware::vibrator::CompositeEffect>& primitiveEffects,
+ const std::function<void()>& completionCallback) override;
+
+protected:
+ const sp<hardware::vibrator::V1_0::IVibrator> mHandleV1_0;
+ std::mutex mCapabilitiesMutex;
+ std::optional<Capabilities> mCapabilities GUARDED_BY(mCapabilitiesMutex);
+
+ // 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:
+ HidlHalWrapperV1_1(std::shared_ptr<CallbackScheduler> scheduler,
+ sp<hardware::vibrator::V1_1::IVibrator> handle)
+ : HidlHalWrapperV1_0(std::move(scheduler), handle), mHandleV1_1(handle) {}
+ virtual ~HidlHalWrapperV1_1() = default;
+
+ virtual HalResult<std::chrono::milliseconds> performEffect(
+ hardware::vibrator::Effect effect, hardware::vibrator::EffectStrength strength,
+ const std::function<void()>& completionCallback) override;
+
+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:
+ HidlHalWrapperV1_2(std::shared_ptr<CallbackScheduler> scheduler,
+ sp<hardware::vibrator::V1_2::IVibrator> handle)
+ : HidlHalWrapperV1_1(std::move(scheduler), handle), mHandleV1_2(handle) {}
+ virtual ~HidlHalWrapperV1_2() = default;
+
+ virtual HalResult<std::chrono::milliseconds> performEffect(
+ hardware::vibrator::Effect effect, hardware::vibrator::EffectStrength strength,
+ const std::function<void()>& completionCallback) override;
+
+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:
+ HidlHalWrapperV1_3(std::shared_ptr<CallbackScheduler> scheduler,
+ sp<hardware::vibrator::V1_3::IVibrator> handle)
+ : HidlHalWrapperV1_2(std::move(scheduler), handle), mHandleV1_3(handle) {}
+ virtual ~HidlHalWrapperV1_3() = default;
+
+ virtual HalResult<void> setExternalControl(bool enabled) override;
+
+ virtual HalResult<std::chrono::milliseconds> performEffect(
+ hardware::vibrator::Effect effect, hardware::vibrator::EffectStrength strength,
+ const std::function<void()>& completionCallback) override;
+
+protected:
+ 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);
+};
+
+// -------------------------------------------------------------------------------------------------
+
+}; // namespace vibrator
+
+}; // namespace android
+
+#endif // ANDROID_OS_VIBRATORHALWRAPPER_H
diff --git a/services/vibratorservice/test/Android.bp b/services/vibratorservice/test/Android.bp
new file mode 100644
index 0000000..9033124
--- /dev/null
+++ b/services/vibratorservice/test/Android.bp
@@ -0,0 +1,48 @@
+// 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.
+
+cc_test {
+ name: "libvibratorservice_test",
+ test_suites: ["device-tests"],
+ srcs: [
+ "VibratorCallbackSchedulerTest.cpp",
+ "VibratorHalControllerTest.cpp",
+ "VibratorHalWrapperAidlTest.cpp",
+ "VibratorHalWrapperHidlV1_0Test.cpp",
+ "VibratorHalWrapperHidlV1_1Test.cpp",
+ "VibratorHalWrapperHidlV1_2Test.cpp",
+ "VibratorHalWrapperHidlV1_3Test.cpp",
+ ],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-Wextra",
+ ],
+ shared_libs: [
+ "libbase",
+ "libbinder",
+ "libhidlbase",
+ "liblog",
+ "libvibratorservice",
+ "libutils",
+ "android.hardware.vibrator-cpp",
+ "android.hardware.vibrator@1.0",
+ "android.hardware.vibrator@1.1",
+ "android.hardware.vibrator@1.2",
+ "android.hardware.vibrator@1.3",
+ ],
+ static_libs: [
+ "libgmock",
+ ],
+}
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/VibratorHalControllerTest.cpp b/services/vibratorservice/test/VibratorHalControllerTest.cpp
new file mode 100644
index 0000000..24e6a1e
--- /dev/null
+++ b/services/vibratorservice/test/VibratorHalControllerTest.cpp
@@ -0,0 +1,355 @@
+/*
+ * 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 "VibratorHalControllerTest"
+
+#include <android/hardware/vibrator/IVibrator.h>
+#include <cutils/atomic.h>
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include <utils/Log.h>
+#include <thread>
+
+#include <vibratorservice/VibratorCallbackScheduler.h>
+#include <vibratorservice/VibratorHalController.h>
+#include <vibratorservice/VibratorHalWrapper.h>
+
+#include "test_utils.h"
+
+using android::hardware::vibrator::CompositeEffect;
+using android::hardware::vibrator::CompositePrimitive;
+using android::hardware::vibrator::Effect;
+using android::hardware::vibrator::EffectStrength;
+
+using std::chrono::milliseconds;
+
+using namespace android;
+using namespace std::chrono_literals;
+using namespace testing;
+
+static constexpr int MAX_ATTEMPTS = 2;
+
+// -------------------------------------------------------------------------------------------------
+
+class MockHalWrapper : public vibrator::HalWrapper {
+public:
+ MockHalWrapper(std::shared_ptr<vibrator::CallbackScheduler> scheduler)
+ : HalWrapper(scheduler) {}
+ virtual ~MockHalWrapper() = default;
+
+ MOCK_METHOD(vibrator::HalResult<void>, ping, (), (override));
+ MOCK_METHOD(vibrator::HalResult<void>, on,
+ (milliseconds timeout, const std::function<void()>& completionCallback),
+ (override));
+ MOCK_METHOD(vibrator::HalResult<void>, off, (), (override));
+ MOCK_METHOD(vibrator::HalResult<void>, setAmplitude, (int32_t amplitude), (override));
+ MOCK_METHOD(vibrator::HalResult<void>, setExternalControl, (bool enabled), (override));
+ MOCK_METHOD(vibrator::HalResult<void>, alwaysOnEnable,
+ (int32_t id, Effect effect, EffectStrength strength), (override));
+ MOCK_METHOD(vibrator::HalResult<void>, alwaysOnDisable, (int32_t id), (override));
+ MOCK_METHOD(vibrator::HalResult<vibrator::Capabilities>, getCapabilities, (), (override));
+ MOCK_METHOD(vibrator::HalResult<std::vector<Effect>>, getSupportedEffects, (), (override));
+ MOCK_METHOD(vibrator::HalResult<milliseconds>, performEffect,
+ (Effect effect, EffectStrength strength,
+ const std::function<void()>& completionCallback),
+ (override));
+ MOCK_METHOD(vibrator::HalResult<void>, performComposedEffect,
+ (const std::vector<CompositeEffect>& primitiveEffects,
+ const std::function<void()>& completionCallback),
+ (override));
+
+ vibrator::CallbackScheduler* getCallbackScheduler() { return mCallbackScheduler.get(); }
+};
+
+class TestHalConnector : public vibrator::HalConnector {
+public:
+ TestHalConnector(int32_t* connectCounter, std::shared_ptr<MockHalWrapper> mockHal)
+ : mConnectCounter(connectCounter), mMockHal(std::move(mockHal)) {}
+ ~TestHalConnector() = default;
+
+ std::shared_ptr<vibrator::HalWrapper> connect(
+ std::shared_ptr<vibrator::CallbackScheduler>) override final {
+ android_atomic_inc(mConnectCounter);
+ return mMockHal;
+ }
+
+private:
+ int32_t* mConnectCounter;
+ std::shared_ptr<MockHalWrapper> mMockHal;
+};
+
+class FailingHalConnector : public vibrator::HalConnector {
+public:
+ FailingHalConnector(int32_t* connectCounter) : mConnectCounter(connectCounter) {}
+ ~FailingHalConnector() = default;
+
+ std::shared_ptr<vibrator::HalWrapper> connect(
+ std::shared_ptr<vibrator::CallbackScheduler>) override final {
+ android_atomic_inc(mConnectCounter);
+ return nullptr;
+ }
+
+private:
+ int32_t* mConnectCounter;
+};
+
+// -------------------------------------------------------------------------------------------------
+
+class VibratorHalControllerTest : public Test {
+public:
+ void SetUp() override {
+ mConnectCounter = 0;
+ auto callbackScheduler = std::make_shared<vibrator::CallbackScheduler>();
+ mMockHal = std::make_shared<StrictMock<MockHalWrapper>>(callbackScheduler);
+ auto halConnector = std::make_unique<TestHalConnector>(&mConnectCounter, mMockHal);
+ mController = std::make_unique<vibrator::HalController>(std::move(halConnector),
+ std::move(callbackScheduler));
+ ASSERT_NE(mController, nullptr);
+ }
+
+protected:
+ int32_t mConnectCounter;
+ std::shared_ptr<MockHalWrapper> mMockHal;
+ std::unique_ptr<vibrator::HalController> mController;
+
+ void setHalExpectations(int32_t cardinality, std::vector<CompositeEffect> compositeEffects,
+ vibrator::HalResult<void> voidResult,
+ vibrator::HalResult<vibrator::Capabilities> capabilitiesResult,
+ vibrator::HalResult<std::vector<Effect>> effectsResult,
+ vibrator::HalResult<milliseconds> durationResult) {
+ InSequence seq;
+ EXPECT_CALL(*mMockHal.get(), ping())
+ .Times(Exactly(cardinality))
+ .WillRepeatedly(Return(voidResult));
+ EXPECT_CALL(*mMockHal.get(), on(Eq(10ms), _))
+ .Times(Exactly(cardinality))
+ .WillRepeatedly(Return(voidResult));
+ EXPECT_CALL(*mMockHal.get(), off())
+ .Times(Exactly(cardinality))
+ .WillRepeatedly(Return(voidResult));
+ EXPECT_CALL(*mMockHal.get(), setAmplitude(Eq(255)))
+ .Times(Exactly(cardinality))
+ .WillRepeatedly(Return(voidResult));
+ EXPECT_CALL(*mMockHal.get(), setExternalControl(Eq(true)))
+ .Times(Exactly(cardinality))
+ .WillRepeatedly(Return(voidResult));
+ EXPECT_CALL(*mMockHal.get(),
+ alwaysOnEnable(Eq(1), Eq(Effect::CLICK), Eq(EffectStrength::LIGHT)))
+ .Times(Exactly(cardinality))
+ .WillRepeatedly(Return(voidResult));
+ EXPECT_CALL(*mMockHal.get(), alwaysOnDisable(Eq(1)))
+ .Times(Exactly(cardinality))
+ .WillRepeatedly(Return(voidResult));
+ EXPECT_CALL(*mMockHal.get(), getCapabilities())
+ .Times(Exactly(cardinality))
+ .WillRepeatedly(Return(capabilitiesResult));
+ EXPECT_CALL(*mMockHal.get(), getSupportedEffects())
+ .Times(Exactly(cardinality))
+ .WillRepeatedly(Return(effectsResult));
+ EXPECT_CALL(*mMockHal.get(), performEffect(Eq(Effect::CLICK), Eq(EffectStrength::LIGHT), _))
+ .Times(Exactly(cardinality))
+ .WillRepeatedly(Return(durationResult));
+ EXPECT_CALL(*mMockHal.get(), performComposedEffect(Eq(compositeEffects), _))
+ .Times(Exactly(cardinality))
+ .WillRepeatedly(Return(voidResult));
+ }
+};
+
+// -------------------------------------------------------------------------------------------------
+
+TEST_F(VibratorHalControllerTest, TestApiCallsAreForwardedToHal) {
+ std::vector<Effect> supportedEffects;
+ supportedEffects.push_back(Effect::CLICK);
+ supportedEffects.push_back(Effect::TICK);
+ std::vector<CompositeEffect> compositeEffects;
+ compositeEffects.push_back(
+ vibrator::TestFactory::createCompositeEffect(CompositePrimitive::SPIN, 100ms, 0.5f));
+ compositeEffects.push_back(
+ vibrator::TestFactory::createCompositeEffect(CompositePrimitive::THUD, 1000ms, 1.0f));
+
+ setHalExpectations(/* cardinality= */ 1, compositeEffects, vibrator::HalResult<void>::ok(),
+ vibrator::HalResult<vibrator::Capabilities>::ok(
+ vibrator::Capabilities::ON_CALLBACK),
+ vibrator::HalResult<std::vector<Effect>>::ok(supportedEffects),
+ vibrator::HalResult<milliseconds>::ok(100ms));
+
+ ASSERT_TRUE(mController->ping().isOk());
+ ASSERT_TRUE(mController->on(10ms, []() {}).isOk());
+ ASSERT_TRUE(mController->off().isOk());
+ ASSERT_TRUE(mController->setAmplitude(255).isOk());
+ ASSERT_TRUE(mController->setExternalControl(true).isOk());
+ ASSERT_TRUE(mController->alwaysOnEnable(1, Effect::CLICK, EffectStrength::LIGHT).isOk());
+ ASSERT_TRUE(mController->alwaysOnDisable(1).isOk());
+
+ auto getCapabilitiesResult = mController->getCapabilities();
+ ASSERT_TRUE(getCapabilitiesResult.isOk());
+ ASSERT_EQ(vibrator::Capabilities::ON_CALLBACK, getCapabilitiesResult.value());
+
+ auto getSupportedEffectsResult = mController->getSupportedEffects();
+ ASSERT_TRUE(getSupportedEffectsResult.isOk());
+ ASSERT_EQ(supportedEffects, getSupportedEffectsResult.value());
+
+ auto performEffectResult =
+ mController->performEffect(Effect::CLICK, EffectStrength::LIGHT, []() {});
+ ASSERT_TRUE(performEffectResult.isOk());
+ ASSERT_EQ(100ms, performEffectResult.value());
+
+ ASSERT_TRUE(mController->performComposedEffect(compositeEffects, []() {}).isOk());
+
+ // No reconnection attempt was made after the first one.
+ ASSERT_EQ(1, mConnectCounter);
+}
+
+TEST_F(VibratorHalControllerTest, TestUnsupportedApiResultDoNotResetHalConnection) {
+ setHalExpectations(/* cardinality= */ 1, std::vector<CompositeEffect>(),
+ vibrator::HalResult<void>::unsupported(),
+ vibrator::HalResult<vibrator::Capabilities>::unsupported(),
+ vibrator::HalResult<std::vector<Effect>>::unsupported(),
+ vibrator::HalResult<milliseconds>::unsupported());
+
+ ASSERT_EQ(0, mConnectCounter);
+
+ ASSERT_TRUE(mController->ping().isUnsupported());
+ ASSERT_TRUE(mController->on(10ms, []() {}).isUnsupported());
+ ASSERT_TRUE(mController->off().isUnsupported());
+ ASSERT_TRUE(mController->setAmplitude(255).isUnsupported());
+ ASSERT_TRUE(mController->setExternalControl(true).isUnsupported());
+ ASSERT_TRUE(
+ mController->alwaysOnEnable(1, Effect::CLICK, EffectStrength::LIGHT).isUnsupported());
+ ASSERT_TRUE(mController->alwaysOnDisable(1).isUnsupported());
+ ASSERT_TRUE(mController->getCapabilities().isUnsupported());
+ ASSERT_TRUE(mController->getSupportedEffects().isUnsupported());
+ ASSERT_TRUE(mController->performEffect(Effect::CLICK, EffectStrength::LIGHT, []() {})
+ .isUnsupported());
+ ASSERT_TRUE(mController->performComposedEffect(std::vector<CompositeEffect>(), []() {})
+ .isUnsupported());
+
+ // No reconnection attempt was made after the first one.
+ ASSERT_EQ(1, mConnectCounter);
+}
+
+TEST_F(VibratorHalControllerTest, TestFailedApiResultResetsHalConnection) {
+ setHalExpectations(MAX_ATTEMPTS, std::vector<CompositeEffect>(),
+ vibrator::HalResult<void>::failed(),
+ vibrator::HalResult<vibrator::Capabilities>::failed(),
+ vibrator::HalResult<std::vector<Effect>>::failed(),
+ vibrator::HalResult<milliseconds>::failed());
+
+ ASSERT_EQ(0, mConnectCounter);
+
+ ASSERT_TRUE(mController->ping().isFailed());
+ ASSERT_TRUE(mController->on(10ms, []() {}).isFailed());
+ ASSERT_TRUE(mController->off().isFailed());
+ ASSERT_TRUE(mController->setAmplitude(255).isFailed());
+ ASSERT_TRUE(mController->setExternalControl(true).isFailed());
+ ASSERT_TRUE(mController->alwaysOnEnable(1, Effect::CLICK, EffectStrength::LIGHT).isFailed());
+ ASSERT_TRUE(mController->alwaysOnDisable(1).isFailed());
+ ASSERT_TRUE(mController->getCapabilities().isFailed());
+ ASSERT_TRUE(mController->getSupportedEffects().isFailed());
+ ASSERT_TRUE(
+ mController->performEffect(Effect::CLICK, EffectStrength::LIGHT, []() {}).isFailed());
+ ASSERT_TRUE(
+ mController->performComposedEffect(std::vector<CompositeEffect>(), []() {}).isFailed());
+
+ // One reconnection attempt + retry attempts per api call.
+ ASSERT_EQ(11 * MAX_ATTEMPTS, mConnectCounter);
+}
+
+TEST_F(VibratorHalControllerTest, TestFailedApiResultReturnsSuccessAfterRetries) {
+ {
+ InSequence seq;
+ EXPECT_CALL(*mMockHal.get(), ping())
+ .Times(Exactly(2))
+ .WillOnce(Return(vibrator::HalResult<void>::failed()))
+ .WillRepeatedly(Return(vibrator::HalResult<void>::ok()));
+ }
+
+ ASSERT_EQ(0, mConnectCounter);
+ ASSERT_TRUE(mController->ping().isOk());
+ // One connect + one retry.
+ ASSERT_EQ(2, mConnectCounter);
+}
+
+TEST_F(VibratorHalControllerTest, TestMultiThreadConnectsOnlyOnce) {
+ ASSERT_EQ(0, mConnectCounter);
+
+ EXPECT_CALL(*mMockHal.get(), ping())
+ .Times(Exactly(10))
+ .WillRepeatedly(Return(vibrator::HalResult<void>::ok()));
+
+ std::vector<std::thread> threads;
+ for (int i = 0; i < 10; i++) {
+ threads.push_back(std::thread([&]() { ASSERT_TRUE(mController->ping().isOk()); }));
+ }
+ std::for_each(threads.begin(), threads.end(), [](std::thread& t) { t.join(); });
+
+ // Connector was called only by the first thread to use the api.
+ ASSERT_EQ(1, mConnectCounter);
+}
+
+TEST_F(VibratorHalControllerTest, TestNoVibratorReturnsUnsupportedAndAttemptsToReconnect) {
+ auto failingHalConnector = std::make_unique<FailingHalConnector>(&mConnectCounter);
+ mController =
+ std::make_unique<vibrator::HalController>(std::move(failingHalConnector), nullptr);
+ ASSERT_EQ(0, mConnectCounter);
+
+ ASSERT_TRUE(mController->ping().isUnsupported());
+ ASSERT_TRUE(mController->on(10ms, []() {}).isUnsupported());
+ ASSERT_TRUE(mController->off().isUnsupported());
+ ASSERT_TRUE(mController->setAmplitude(255).isUnsupported());
+ ASSERT_TRUE(mController->setExternalControl(true).isUnsupported());
+ ASSERT_TRUE(
+ mController->alwaysOnEnable(1, Effect::CLICK, EffectStrength::LIGHT).isUnsupported());
+ ASSERT_TRUE(mController->alwaysOnDisable(1).isUnsupported());
+ ASSERT_TRUE(mController->getCapabilities().isUnsupported());
+ ASSERT_TRUE(mController->getSupportedEffects().isUnsupported());
+ ASSERT_TRUE(mController->performEffect(Effect::CLICK, EffectStrength::LIGHT, []() {})
+ .isUnsupported());
+ ASSERT_TRUE(mController->performComposedEffect(std::vector<CompositeEffect>(), []() {})
+ .isUnsupported());
+
+ // One reconnection attempt per api call, no retry.
+ ASSERT_EQ(11, mConnectCounter);
+}
+
+TEST_F(VibratorHalControllerTest, TestScheduledCallbackSurvivesReconnection) {
+ {
+ InSequence seq;
+ EXPECT_CALL(*mMockHal.get(), on(Eq(10ms), _))
+ .Times(Exactly(1))
+ .WillRepeatedly([&](milliseconds timeout, std::function<void()> callback) {
+ mMockHal.get()->getCallbackScheduler()->schedule(callback, timeout);
+ return vibrator::HalResult<void>::ok();
+ });
+ EXPECT_CALL(*mMockHal.get(), ping())
+ .Times(Exactly(MAX_ATTEMPTS))
+ .WillRepeatedly(Return(vibrator::HalResult<void>::failed()));
+ }
+
+ std::unique_ptr<int32_t> callbackCounter = std::make_unique<int32_t>();
+ auto callback = vibrator::TestFactory::createCountingCallback(callbackCounter.get());
+
+ ASSERT_TRUE(mController->on(10ms, callback).isOk());
+ ASSERT_TRUE(mController->ping().isFailed()); // Delete connected HAL pointer from controller.
+ mMockHal.reset(); // Delete mock HAL pointer from test class.
+ ASSERT_EQ(0, *callbackCounter.get());
+
+ // Callback triggered even after HalWrapper was completely destroyed.
+ std::this_thread::sleep_for(15ms);
+ ASSERT_EQ(1, *callbackCounter.get());
+}
diff --git a/services/vibratorservice/test/VibratorHalWrapperAidlTest.cpp b/services/vibratorservice/test/VibratorHalWrapperAidlTest.cpp
new file mode 100644
index 0000000..0f2d7bc
--- /dev/null
+++ b/services/vibratorservice/test/VibratorHalWrapperAidlTest.cpp
@@ -0,0 +1,487 @@
+/*
+ * 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/hardware/vibrator/IVibrator.h>
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include <utils/Log.h>
+#include <thread>
+
+#include <vibratorservice/VibratorCallbackScheduler.h>
+#include <vibratorservice/VibratorHalWrapper.h>
+
+#include "test_utils.h"
+
+using android::binder::Status;
+
+using android::hardware::vibrator::CompositeEffect;
+using android::hardware::vibrator::CompositePrimitive;
+using android::hardware::vibrator::Effect;
+using android::hardware::vibrator::EffectStrength;
+using android::hardware::vibrator::IVibrator;
+using android::hardware::vibrator::IVibratorCallback;
+
+using namespace android;
+using namespace std::chrono_literals;
+using namespace testing;
+
+// -------------------------------------------------------------------------------------------------
+
+class MockBinder : public BBinder {
+public:
+ MOCK_METHOD(status_t, linkToDeath,
+ (const sp<DeathRecipient>& recipient, void* cookie, uint32_t flags), (override));
+ MOCK_METHOD(status_t, unlinkToDeath,
+ (const wp<DeathRecipient>& recipient, void* cookie, uint32_t flags,
+ wp<DeathRecipient>* outRecipient),
+ (override));
+ MOCK_METHOD(status_t, pingBinder, (), (override));
+};
+
+class MockIVibrator : public IVibrator {
+public:
+ MOCK_METHOD(Status, getCapabilities, (int32_t * ret), (override));
+ MOCK_METHOD(Status, off, (), (override));
+ MOCK_METHOD(Status, on, (int32_t timeout, const sp<IVibratorCallback>& cb), (override));
+ MOCK_METHOD(Status, perform,
+ (Effect e, EffectStrength s, const sp<IVibratorCallback>& cb, int32_t* ret),
+ (override));
+ MOCK_METHOD(Status, getSupportedEffects, (std::vector<Effect> * ret), (override));
+ MOCK_METHOD(Status, setAmplitude, (float amplitude), (override));
+ MOCK_METHOD(Status, setExternalControl, (bool enabled), (override));
+ MOCK_METHOD(Status, getCompositionDelayMax, (int32_t * ret), (override));
+ MOCK_METHOD(Status, getCompositionSizeMax, (int32_t * ret), (override));
+ MOCK_METHOD(Status, getSupportedPrimitives, (std::vector<CompositePrimitive> * ret),
+ (override));
+ MOCK_METHOD(Status, getPrimitiveDuration, (CompositePrimitive p, int32_t* ret), (override));
+ MOCK_METHOD(Status, compose,
+ (const std::vector<CompositeEffect>& e, const sp<IVibratorCallback>& cb),
+ (override));
+ MOCK_METHOD(Status, getSupportedAlwaysOnEffects, (std::vector<Effect> * ret), (override));
+ MOCK_METHOD(Status, alwaysOnEnable, (int32_t id, Effect e, EffectStrength s), (override));
+ MOCK_METHOD(Status, alwaysOnDisable, (int32_t id), (override));
+ MOCK_METHOD(int32_t, getInterfaceVersion, (), (override));
+ MOCK_METHOD(std::string, getInterfaceHash, (), (override));
+ MOCK_METHOD(IBinder*, onAsBinder, (), (override));
+};
+
+// -------------------------------------------------------------------------------------------------
+
+class VibratorHalWrapperAidlTest : public Test {
+public:
+ void SetUp() override {
+ mMockBinder = new StrictMock<MockBinder>();
+ mMockHal = new StrictMock<MockIVibrator>();
+ 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;
+};
+
+// -------------------------------------------------------------------------------------------------
+
+ACTION(TriggerCallbackInArg1) {
+ if (arg1 != nullptr) {
+ arg1->onComplete();
+ }
+}
+
+ACTION(TriggerCallbackInArg2) {
+ if (arg2 != nullptr) {
+ arg2->onComplete();
+ }
+}
+
+TEST_F(VibratorHalWrapperAidlTest, TestPing) {
+ {
+ InSequence seq;
+ EXPECT_CALL(*mMockHal.get(), onAsBinder())
+ .Times(Exactly(1))
+ .WillRepeatedly(Return(mMockBinder.get()));
+ EXPECT_CALL(*mMockBinder.get(), pingBinder()).Times(Exactly(1));
+ }
+
+ ASSERT_TRUE(mWrapper->ping().isFailed());
+}
+
+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())));
+ EXPECT_CALL(*mMockHal.get(), on(Eq(100), _))
+ .Times(Exactly(1))
+ .WillRepeatedly(Return(
+ Status::fromExceptionCode(Status::Exception::EX_UNSUPPORTED_OPERATION)));
+ EXPECT_CALL(*mMockHal.get(), on(Eq(1000), _))
+ .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(100ms, callback).isUnsupported());
+ // Callback not triggered for unsupported
+ ASSERT_EQ(1, *callbackCounter.get());
+
+ ASSERT_TRUE(mWrapper->on(1000ms, callback).isFailed());
+ // 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());
+}
+
+TEST_F(VibratorHalWrapperAidlTest, TestOff) {
+ EXPECT_CALL(*mMockHal.get(), off())
+ .Times(Exactly(3))
+ .WillOnce(Return(Status()))
+ .WillOnce(
+ Return(Status::fromExceptionCode(Status::Exception::EX_UNSUPPORTED_OPERATION)))
+ .WillRepeatedly(Return(Status::fromExceptionCode(Status::Exception::EX_SECURITY)));
+
+ ASSERT_TRUE(mWrapper->off().isOk());
+ ASSERT_TRUE(mWrapper->off().isUnsupported());
+ ASSERT_TRUE(mWrapper->off().isFailed());
+}
+
+TEST_F(VibratorHalWrapperAidlTest, TestSetAmplitude) {
+ {
+ InSequence seq;
+ EXPECT_CALL(*mMockHal.get(), setAmplitude(FloatNear(0.1, 1e-2))).Times(Exactly(1));
+ EXPECT_CALL(*mMockHal.get(), setAmplitude(FloatNear(0.2, 1e-2)))
+ .Times(Exactly(1))
+ .WillRepeatedly(Return(
+ Status::fromExceptionCode(Status::Exception::EX_UNSUPPORTED_OPERATION)));
+ EXPECT_CALL(*mMockHal.get(), setAmplitude(FloatNear(0.5, 1e-2)))
+ .Times(Exactly(1))
+ .WillRepeatedly(Return(Status::fromExceptionCode(Status::Exception::EX_SECURITY)));
+ }
+
+ ASSERT_TRUE(mWrapper->setAmplitude(std::numeric_limits<uint8_t>::max() / 10).isOk());
+ ASSERT_TRUE(mWrapper->setAmplitude(std::numeric_limits<uint8_t>::max() / 5).isUnsupported());
+ ASSERT_TRUE(mWrapper->setAmplitude(std::numeric_limits<uint8_t>::max() / 2).isFailed());
+}
+
+TEST_F(VibratorHalWrapperAidlTest, TestSetExternalControl) {
+ {
+ InSequence seq;
+ EXPECT_CALL(*mMockHal.get(), setExternalControl(Eq(true))).Times(Exactly(1));
+ EXPECT_CALL(*mMockHal.get(), setExternalControl(Eq(false)))
+ .Times(Exactly(2))
+ .WillOnce(Return(
+ Status::fromExceptionCode(Status::Exception::EX_UNSUPPORTED_OPERATION)))
+ .WillRepeatedly(Return(Status::fromExceptionCode(Status::Exception::EX_SECURITY)));
+ }
+
+ ASSERT_TRUE(mWrapper->setExternalControl(true).isOk());
+ ASSERT_TRUE(mWrapper->setExternalControl(false).isUnsupported());
+ ASSERT_TRUE(mWrapper->setExternalControl(false).isFailed());
+}
+
+TEST_F(VibratorHalWrapperAidlTest, TestAlwaysOnEnable) {
+ {
+ InSequence seq;
+ EXPECT_CALL(*mMockHal.get(),
+ alwaysOnEnable(Eq(1), Eq(Effect::CLICK), Eq(EffectStrength::LIGHT)))
+ .Times(Exactly(1));
+ EXPECT_CALL(*mMockHal.get(),
+ alwaysOnEnable(Eq(2), Eq(Effect::TICK), Eq(EffectStrength::MEDIUM)))
+ .Times(Exactly(1))
+ .WillRepeatedly(Return(
+ Status::fromExceptionCode(Status::Exception::EX_UNSUPPORTED_OPERATION)));
+ EXPECT_CALL(*mMockHal.get(),
+ alwaysOnEnable(Eq(3), Eq(Effect::POP), Eq(EffectStrength::STRONG)))
+ .Times(Exactly(1))
+ .WillRepeatedly(Return(Status::fromExceptionCode(Status::Exception::EX_SECURITY)));
+ }
+
+ auto result = mWrapper->alwaysOnEnable(1, Effect::CLICK, EffectStrength::LIGHT);
+ ASSERT_TRUE(result.isOk());
+ result = mWrapper->alwaysOnEnable(2, Effect::TICK, EffectStrength::MEDIUM);
+ ASSERT_TRUE(result.isUnsupported());
+ result = mWrapper->alwaysOnEnable(3, Effect::POP, EffectStrength::STRONG);
+ ASSERT_TRUE(result.isFailed());
+}
+
+TEST_F(VibratorHalWrapperAidlTest, TestAlwaysOnDisable) {
+ {
+ InSequence seq;
+ EXPECT_CALL(*mMockHal.get(), alwaysOnDisable(Eq(1))).Times(Exactly(1));
+ EXPECT_CALL(*mMockHal.get(), alwaysOnDisable(Eq(2)))
+ .Times(Exactly(1))
+ .WillRepeatedly(Return(
+ Status::fromExceptionCode(Status::Exception::EX_UNSUPPORTED_OPERATION)));
+ EXPECT_CALL(*mMockHal.get(), alwaysOnDisable(Eq(3)))
+ .Times(Exactly(1))
+ .WillRepeatedly(Return(Status::fromExceptionCode(Status::Exception::EX_SECURITY)));
+ }
+
+ ASSERT_TRUE(mWrapper->alwaysOnDisable(1).isOk());
+ ASSERT_TRUE(mWrapper->alwaysOnDisable(2).isUnsupported());
+ ASSERT_TRUE(mWrapper->alwaysOnDisable(3).isFailed());
+}
+
+TEST_F(VibratorHalWrapperAidlTest, TestGetCapabilitiesDoesNotCacheFailedResult) {
+ EXPECT_CALL(*mMockHal.get(), getCapabilities(_))
+ .Times(Exactly(3))
+ .WillOnce(
+ Return(Status::fromExceptionCode(Status::Exception::EX_UNSUPPORTED_OPERATION)))
+ .WillOnce(Return(Status::fromExceptionCode(Status::Exception::EX_SECURITY)))
+ .WillRepeatedly(DoAll(SetArgPointee<0>(IVibrator::CAP_ON_CALLBACK), Return(Status())));
+
+ ASSERT_TRUE(mWrapper->getCapabilities().isUnsupported());
+ ASSERT_TRUE(mWrapper->getCapabilities().isFailed());
+
+ auto result = mWrapper->getCapabilities();
+ ASSERT_TRUE(result.isOk());
+ ASSERT_EQ(vibrator::Capabilities::ON_CALLBACK, result.value());
+}
+
+TEST_F(VibratorHalWrapperAidlTest, TestGetCapabilitiesCachesResult) {
+ EXPECT_CALL(*mMockHal.get(), getCapabilities(_))
+ .Times(Exactly(1))
+ .WillRepeatedly(DoAll(SetArgPointee<0>(IVibrator::CAP_ON_CALLBACK), Return(Status())));
+
+ std::vector<std::thread> threads;
+ for (int i = 0; i < 10; i++) {
+ threads.push_back(std::thread([&]() {
+ auto result = mWrapper->getCapabilities();
+ ASSERT_TRUE(result.isOk());
+ ASSERT_EQ(vibrator::Capabilities::ON_CALLBACK, result.value());
+ }));
+ }
+ std::for_each(threads.begin(), threads.end(), [](std::thread& t) { t.join(); });
+
+ auto result = mWrapper->getCapabilities();
+ ASSERT_TRUE(result.isOk());
+ ASSERT_EQ(vibrator::Capabilities::ON_CALLBACK, result.value());
+}
+
+TEST_F(VibratorHalWrapperAidlTest, TestGetSupportedEffectsDoesNotCacheFailedResult) {
+ std::vector<Effect> supportedEffects;
+ supportedEffects.push_back(Effect::CLICK);
+ supportedEffects.push_back(Effect::TICK);
+
+ EXPECT_CALL(*mMockHal.get(), getSupportedEffects(_))
+ .Times(Exactly(3))
+ .WillOnce(
+ Return(Status::fromExceptionCode(Status::Exception::EX_UNSUPPORTED_OPERATION)))
+ .WillOnce(Return(Status::fromExceptionCode(Status::Exception::EX_SECURITY)))
+ .WillRepeatedly(DoAll(SetArgPointee<0>(supportedEffects), Return(Status())));
+
+ ASSERT_TRUE(mWrapper->getSupportedEffects().isUnsupported());
+ ASSERT_TRUE(mWrapper->getSupportedEffects().isFailed());
+
+ auto result = mWrapper->getSupportedEffects();
+ ASSERT_TRUE(result.isOk());
+ ASSERT_EQ(supportedEffects, result.value());
+}
+
+TEST_F(VibratorHalWrapperAidlTest, TestGetSupportedEffectsCachesResult) {
+ std::vector<Effect> supportedEffects;
+ supportedEffects.push_back(Effect::CLICK);
+ supportedEffects.push_back(Effect::TICK);
+
+ EXPECT_CALL(*mMockHal.get(), getSupportedEffects(_))
+ .Times(Exactly(1))
+ .WillRepeatedly(DoAll(SetArgPointee<0>(supportedEffects), Return(Status())));
+
+ std::vector<std::thread> threads;
+ for (int i = 0; i < 10; i++) {
+ threads.push_back(std::thread([&]() {
+ auto result = mWrapper->getSupportedEffects();
+ ASSERT_TRUE(result.isOk());
+ ASSERT_EQ(supportedEffects, result.value());
+ }));
+ }
+ std::for_each(threads.begin(), threads.end(), [](std::thread& t) { t.join(); });
+
+ auto result = mWrapper->getSupportedEffects();
+ ASSERT_TRUE(result.isOk());
+ ASSERT_EQ(supportedEffects, result.value());
+}
+
+TEST_F(VibratorHalWrapperAidlTest, 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(
+ DoAll(SetArgPointee<3>(1000), TriggerCallbackInArg2(), Return(Status())));
+ 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(1000ms, result.value());
+ ASSERT_EQ(1, *callbackCounter.get());
+
+ result = mWrapper->performEffect(Effect::POP, EffectStrength::MEDIUM, callback);
+ ASSERT_TRUE(result.isUnsupported());
+ // 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 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());
+}
+
+TEST_F(VibratorHalWrapperAidlTest, TestPerformComposedEffect) {
+ std::vector<CompositeEffect> emptyEffects, singleEffect, multipleEffects;
+ singleEffect.push_back(
+ vibrator::TestFactory::createCompositeEffect(CompositePrimitive::CLICK, 10ms, 0.0f));
+ multipleEffects.push_back(
+ vibrator::TestFactory::createCompositeEffect(CompositePrimitive::SPIN, 100ms, 0.5f));
+ multipleEffects.push_back(
+ vibrator::TestFactory::createCompositeEffect(CompositePrimitive::THUD, 1000ms, 1.0f));
+
+ {
+ InSequence seq;
+ EXPECT_CALL(*mMockHal.get(), compose(Eq(emptyEffects), _))
+ .Times(Exactly(1))
+ .WillRepeatedly(DoAll(TriggerCallbackInArg1(), Return(Status())));
+ EXPECT_CALL(*mMockHal.get(), compose(Eq(singleEffect), _))
+ .Times(Exactly(1))
+ .WillRepeatedly(Return(
+ Status::fromExceptionCode(Status::Exception::EX_UNSUPPORTED_OPERATION)));
+ EXPECT_CALL(*mMockHal.get(), compose(Eq(multipleEffects), _))
+ .Times(Exactly(1))
+ .WillRepeatedly(Return(Status::fromExceptionCode(Status::Exception::EX_SECURITY)));
+ }
+
+ std::unique_ptr<int32_t> callbackCounter = std::make_unique<int32_t>();
+ auto callback = vibrator::TestFactory::createCountingCallback(callbackCounter.get());
+
+ auto result = mWrapper->performComposedEffect(emptyEffects, callback);
+ ASSERT_TRUE(result.isOk());
+ ASSERT_EQ(1, *callbackCounter.get());
+
+ result = mWrapper->performComposedEffect(singleEffect, callback);
+ ASSERT_TRUE(result.isUnsupported());
+ // Callback not triggered for unsupported
+ ASSERT_EQ(1, *callbackCounter.get());
+
+ result = mWrapper->performComposedEffect(multipleEffects, callback);
+ ASSERT_TRUE(result.isFailed());
+ // 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
new file mode 100644
index 0000000..7eb4059
--- /dev/null
+++ b/services/vibratorservice/test/VibratorHalWrapperHidlV1_0Test.cpp
@@ -0,0 +1,322 @@
+/*
+ * 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 "VibratorHalWrapperHidlV1_0Test"
+
+#include <android/hardware/vibrator/IVibrator.h>
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include <utils/Log.h>
+#include <thread>
+
+#include <vibratorservice/VibratorCallbackScheduler.h>
+#include <vibratorservice/VibratorHalWrapper.h>
+
+#include "test_utils.h"
+
+namespace V1_0 = android::hardware::vibrator::V1_0;
+
+using android::hardware::vibrator::CompositeEffect;
+using android::hardware::vibrator::CompositePrimitive;
+using android::hardware::vibrator::Effect;
+using android::hardware::vibrator::EffectStrength;
+using android::hardware::vibrator::IVibrator;
+
+using namespace android;
+using namespace std::chrono_literals;
+using namespace testing;
+
+// -------------------------------------------------------------------------------------------------
+
+class MockIVibratorV1_0 : public V1_0::IVibrator {
+public:
+ MOCK_METHOD(hardware::Return<void>, ping, (), (override));
+ MOCK_METHOD(hardware::Return<V1_0::Status>, on, (uint32_t timeoutMs), (override));
+ MOCK_METHOD(hardware::Return<V1_0::Status>, off, (), (override));
+ MOCK_METHOD(hardware::Return<bool>, supportsAmplitudeControl, (), (override));
+ MOCK_METHOD(hardware::Return<V1_0::Status>, setAmplitude, (uint8_t amplitude), (override));
+ MOCK_METHOD(hardware::Return<void>, perform,
+ (V1_0::Effect effect, V1_0::EffectStrength strength, perform_cb cb), (override));
+};
+
+// -------------------------------------------------------------------------------------------------
+
+class VibratorHalWrapperHidlV1_0Test : public Test {
+public:
+ void SetUp() override {
+ mMockHal = new StrictMock<MockIVibratorV1_0>();
+ 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;
+};
+
+// -------------------------------------------------------------------------------------------------
+
+TEST_F(VibratorHalWrapperHidlV1_0Test, TestPing) {
+ EXPECT_CALL(*mMockHal.get(), ping())
+ .Times(Exactly(2))
+ .WillOnce([]() { return hardware::Return<void>(); })
+ .WillRepeatedly([]() {
+ return hardware::Return<void>(hardware::Status::fromExceptionCode(-1));
+ });
+
+ ASSERT_TRUE(mWrapper->ping().isOk());
+ ASSERT_TRUE(mWrapper->ping().isFailed());
+}
+
+TEST_F(VibratorHalWrapperHidlV1_0Test, TestOn) {
+ {
+ InSequence seq;
+ EXPECT_CALL(*mMockHal.get(), on(Eq(static_cast<uint32_t>(1))))
+ .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>(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>(12))))
+ .Times(Exactly(1))
+ .WillRepeatedly([](uint32_t) {
+ return hardware::Return<V1_0::Status>(hardware::Status::fromExceptionCode(-1));
+ });
+ }
+
+ std::unique_ptr<int32_t> callbackCounter = std::make_unique<int32_t>();
+ auto callback = vibrator::TestFactory::createCountingCallback(callbackCounter.get());
+
+ ASSERT_TRUE(mWrapper->on(1ms, callback).isOk());
+ ASSERT_EQ(1, *callbackCounter.get());
+
+ ASSERT_TRUE(mWrapper->on(10ms, callback).isUnsupported());
+ ASSERT_TRUE(mWrapper->on(11ms, callback).isFailed());
+ ASSERT_TRUE(mWrapper->on(12ms, callback).isFailed());
+
+ // Callback not triggered for unsupported and on failure
+ ASSERT_EQ(1, *callbackCounter.get());
+}
+
+TEST_F(VibratorHalWrapperHidlV1_0Test, TestOff) {
+ EXPECT_CALL(*mMockHal.get(), off())
+ .Times(Exactly(4))
+ .WillOnce([]() { return hardware::Return<V1_0::Status>(V1_0::Status::OK); })
+ .WillOnce([]() {
+ return hardware::Return<V1_0::Status>(V1_0::Status::UNSUPPORTED_OPERATION);
+ })
+ .WillOnce([]() { return hardware::Return<V1_0::Status>(V1_0::Status::BAD_VALUE); })
+ .WillRepeatedly([]() {
+ return hardware::Return<V1_0::Status>(hardware::Status::fromExceptionCode(-1));
+ });
+
+ ASSERT_TRUE(mWrapper->off().isOk());
+ ASSERT_TRUE(mWrapper->off().isUnsupported());
+ ASSERT_TRUE(mWrapper->off().isFailed());
+ ASSERT_TRUE(mWrapper->off().isFailed());
+}
+
+TEST_F(VibratorHalWrapperHidlV1_0Test, TestSetAmplitude) {
+ {
+ InSequence seq;
+ EXPECT_CALL(*mMockHal.get(), setAmplitude(static_cast<uint8_t>(1)))
+ .Times(Exactly(1))
+ .WillRepeatedly(
+ [](uint8_t) { return hardware::Return<V1_0::Status>(V1_0::Status::OK); });
+ EXPECT_CALL(*mMockHal.get(), setAmplitude(Eq(static_cast<uint8_t>(2))))
+ .Times(Exactly(1))
+ .WillRepeatedly([](uint8_t) {
+ return hardware::Return<V1_0::Status>(V1_0::Status::UNSUPPORTED_OPERATION);
+ });
+ EXPECT_CALL(*mMockHal.get(), setAmplitude(Eq(static_cast<uint8_t>(3))))
+ .Times(Exactly(1))
+ .WillRepeatedly([](uint8_t) {
+ return hardware::Return<V1_0::Status>(V1_0::Status::BAD_VALUE);
+ });
+ EXPECT_CALL(*mMockHal.get(), setAmplitude(Eq(static_cast<uint8_t>(4))))
+ .Times(Exactly(1))
+ .WillRepeatedly([](uint8_t) {
+ return hardware::Return<V1_0::Status>(hardware::Status::fromExceptionCode(-1));
+ });
+ }
+
+ ASSERT_TRUE(mWrapper->setAmplitude(1).isOk());
+ ASSERT_TRUE(mWrapper->setAmplitude(2).isUnsupported());
+ ASSERT_TRUE(mWrapper->setAmplitude(3).isFailed());
+ ASSERT_TRUE(mWrapper->setAmplitude(4).isFailed());
+}
+
+TEST_F(VibratorHalWrapperHidlV1_0Test, TestSetExternalControlUnsupported) {
+ ASSERT_TRUE(mWrapper->setExternalControl(true).isUnsupported());
+ ASSERT_TRUE(mWrapper->setExternalControl(false).isUnsupported());
+}
+
+TEST_F(VibratorHalWrapperHidlV1_0Test, TestAlwaysOnEnableUnsupported) {
+ ASSERT_TRUE(mWrapper->alwaysOnEnable(1, Effect::CLICK, EffectStrength::LIGHT).isUnsupported());
+}
+
+TEST_F(VibratorHalWrapperHidlV1_0Test, TestAlwaysOnDisableUnsupported) {
+ ASSERT_TRUE(mWrapper->alwaysOnDisable(1).isUnsupported());
+}
+
+TEST_F(VibratorHalWrapperHidlV1_0Test, TestGetCapabilitiesDoesNotCacheFailedResult) {
+ EXPECT_CALL(*mMockHal.get(), supportsAmplitudeControl())
+ .Times(Exactly(2))
+ .WillOnce([]() {
+ return hardware::Return<bool>(hardware::Status::fromExceptionCode(-1));
+ })
+ .WillRepeatedly([]() { return hardware::Return<bool>(true); });
+
+ ASSERT_TRUE(mWrapper->getCapabilities().isFailed());
+
+ auto result = mWrapper->getCapabilities();
+ ASSERT_TRUE(result.isOk());
+ ASSERT_EQ(vibrator::Capabilities::AMPLITUDE_CONTROL, result.value());
+}
+
+TEST_F(VibratorHalWrapperHidlV1_0Test, TestGetCapabilitiesWithoutAmplitudeControl) {
+ EXPECT_CALL(*mMockHal.get(), supportsAmplitudeControl()).Times(Exactly(1)).WillRepeatedly([]() {
+ return hardware::Return<bool>(false);
+ });
+
+ auto result = mWrapper->getCapabilities();
+ ASSERT_TRUE(result.isOk());
+ ASSERT_EQ(vibrator::Capabilities::NONE, result.value());
+}
+
+TEST_F(VibratorHalWrapperHidlV1_0Test, TestGetCapabilitiesCachesResult) {
+ EXPECT_CALL(*mMockHal.get(), supportsAmplitudeControl()).Times(Exactly(1)).WillRepeatedly([]() {
+ return hardware::Return<bool>(true);
+ });
+
+ std::vector<std::thread> threads;
+ for (int i = 0; i < 10; i++) {
+ threads.push_back(std::thread([&]() {
+ auto result = mWrapper->getCapabilities();
+ ASSERT_TRUE(result.isOk());
+ ASSERT_EQ(vibrator::Capabilities::AMPLITUDE_CONTROL, result.value());
+ }));
+ }
+ std::for_each(threads.begin(), threads.end(), [](std::thread& t) { t.join(); });
+
+ auto result = mWrapper->getCapabilities();
+ ASSERT_TRUE(result.isOk());
+ ASSERT_EQ(vibrator::Capabilities::AMPLITUDE_CONTROL, result.value());
+}
+
+TEST_F(VibratorHalWrapperHidlV1_0Test, TestGetSupportedEffectsUnsupported) {
+ ASSERT_TRUE(mWrapper->getSupportedEffects().isUnsupported());
+}
+
+TEST_F(VibratorHalWrapperHidlV1_0Test, TestPerformEffect) {
+ {
+ 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_0::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());
+ EXPECT_CALL(*mMockHal.get(),
+ perform(Eq(V1_0::Effect::CLICK), Eq(V1_0::EffectStrength::MEDIUM), _))
+ .Times(Exactly(1))
+ .WillRepeatedly(
+ [](V1_0::Effect, V1_0::EffectStrength, MockIVibratorV1_0::perform_cb cb) {
+ cb(V1_0::Status::UNSUPPORTED_OPERATION, 10);
+ return hardware::Return<void>();
+ });
+ EXPECT_CALL(*mMockHal.get(),
+ perform(Eq(V1_0::Effect::CLICK), Eq(V1_0::EffectStrength::STRONG), _))
+ .Times(Exactly(2))
+ .WillOnce([](V1_0::Effect, V1_0::EffectStrength, MockIVibratorV1_0::perform_cb cb) {
+ cb(V1_0::Status::BAD_VALUE, 10);
+ return hardware::Return<void>();
+ })
+ .WillRepeatedly(
+ [](V1_0::Effect, V1_0::EffectStrength, MockIVibratorV1_0::perform_cb) {
+ return hardware::Return<void>(hardware::Status::fromExceptionCode(-1));
+ });
+ }
+
+ 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::CLICK, EffectStrength::MEDIUM, callback);
+ ASSERT_TRUE(result.isUnsupported());
+
+ result = mWrapper->performEffect(Effect::CLICK, EffectStrength::STRONG, callback);
+ ASSERT_TRUE(result.isFailed());
+
+ result = mWrapper->performEffect(Effect::CLICK, EffectStrength::STRONG, callback);
+ ASSERT_TRUE(result.isFailed());
+
+ // Callback not triggered for unsupported and on failure
+ ASSERT_EQ(1, *callbackCounter.get());
+}
+
+TEST_F(VibratorHalWrapperHidlV1_0Test, TestPerformEffectUnsupported) {
+ std::unique_ptr<int32_t> callbackCounter = std::make_unique<int32_t>();
+ auto callback = vibrator::TestFactory::createCountingCallback(callbackCounter.get());
+ // 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());
+}
+
+TEST_F(VibratorHalWrapperHidlV1_0Test, TestPerformComposedEffectUnsupported) {
+ std::vector<CompositeEffect> emptyEffects, singleEffect, multipleEffects;
+ singleEffect.push_back(
+ vibrator::TestFactory::createCompositeEffect(CompositePrimitive::CLICK, 10ms, 0.0f));
+ multipleEffects.push_back(
+ vibrator::TestFactory::createCompositeEffect(CompositePrimitive::SPIN, 100ms, 0.5f));
+ multipleEffects.push_back(
+ vibrator::TestFactory::createCompositeEffect(CompositePrimitive::THUD, 1000ms, 1.0f));
+
+ std::unique_ptr<int32_t> callbackCounter = std::make_unique<int32_t>();
+ auto callback = vibrator::TestFactory::createCountingCallback(callbackCounter.get());
+
+ ASSERT_TRUE(mWrapper->performComposedEffect(singleEffect, callback).isUnsupported());
+ ASSERT_TRUE(mWrapper->performComposedEffect(multipleEffects, callback).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
new file mode 100644
index 0000000..d887efc
--- /dev/null
+++ b/services/vibratorservice/test/VibratorHalWrapperHidlV1_1Test.cpp
@@ -0,0 +1,165 @@
+/*
+ * 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 "VibratorHalWrapperHidlV1_1Test"
+
+#include <android/hardware/vibrator/IVibrator.h>
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include <utils/Log.h>
+
+#include <vibratorservice/VibratorCallbackScheduler.h>
+#include <vibratorservice/VibratorHalWrapper.h>
+
+#include "test_utils.h"
+
+namespace V1_0 = android::hardware::vibrator::V1_0;
+namespace V1_1 = android::hardware::vibrator::V1_1;
+
+using android::hardware::vibrator::Effect;
+using android::hardware::vibrator::EffectStrength;
+
+using namespace android;
+using namespace std::chrono_literals;
+using namespace testing;
+
+// -------------------------------------------------------------------------------------------------
+
+class MockIVibratorV1_1 : public V1_1::IVibrator {
+public:
+ MOCK_METHOD(hardware::Return<V1_0::Status>, on, (uint32_t timeoutMs), (override));
+ MOCK_METHOD(hardware::Return<V1_0::Status>, off, (), (override));
+ MOCK_METHOD(hardware::Return<bool>, supportsAmplitudeControl, (), (override));
+ MOCK_METHOD(hardware::Return<V1_0::Status>, setAmplitude, (uint8_t amplitude), (override));
+ MOCK_METHOD(hardware::Return<void>, perform,
+ (V1_0::Effect effect, V1_0::EffectStrength strength, perform_cb cb), (override));
+ MOCK_METHOD(hardware::Return<void>, perform_1_1,
+ (V1_1::Effect_1_1 effect, V1_0::EffectStrength strength, perform_cb cb),
+ (override));
+};
+
+// -------------------------------------------------------------------------------------------------
+
+class VibratorHalWrapperHidlV1_1Test : public Test {
+public:
+ void SetUp() override {
+ mMockHal = new StrictMock<MockIVibratorV1_1>();
+ 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;
+};
+
+// -------------------------------------------------------------------------------------------------
+
+TEST_F(VibratorHalWrapperHidlV1_1Test, TestPerformEffectV1_0) {
+ {
+ 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(10ms, result.value());
+ ASSERT_EQ(1, *callbackCounter.get());
+}
+
+TEST_F(VibratorHalWrapperHidlV1_1Test, TestPerformEffectV1_1) {
+ {
+ 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_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());
+ EXPECT_CALL(*mMockHal.get(),
+ perform_1_1(Eq(V1_1::Effect_1_1::TICK), Eq(V1_0::EffectStrength::MEDIUM), _))
+ .Times(Exactly(1))
+ .WillRepeatedly([](V1_1::Effect_1_1, V1_0::EffectStrength,
+ MockIVibratorV1_1::perform_cb cb) {
+ cb(V1_0::Status::UNSUPPORTED_OPERATION, 0);
+ return hardware::Return<void>();
+ });
+ EXPECT_CALL(*mMockHal.get(),
+ perform_1_1(Eq(V1_1::Effect_1_1::TICK), Eq(V1_0::EffectStrength::STRONG), _))
+ .Times(Exactly(2))
+ .WillOnce([](V1_1::Effect_1_1, V1_0::EffectStrength,
+ MockIVibratorV1_1::perform_cb cb) {
+ cb(V1_0::Status::BAD_VALUE, 0);
+ return hardware::Return<void>();
+ })
+ .WillRepeatedly(
+ [](V1_1::Effect_1_1, V1_0::EffectStrength, MockIVibratorV1_1::perform_cb) {
+ return hardware::Return<void>(hardware::Status::fromExceptionCode(-1));
+ });
+ }
+
+ 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(10ms, result.value());
+ ASSERT_EQ(1, *callbackCounter.get());
+
+ result = mWrapper->performEffect(Effect::TICK, EffectStrength::MEDIUM, callback);
+ ASSERT_TRUE(result.isUnsupported());
+
+ result = mWrapper->performEffect(Effect::TICK, EffectStrength::STRONG, callback);
+ ASSERT_TRUE(result.isFailed());
+
+ result = mWrapper->performEffect(Effect::TICK, EffectStrength::STRONG, callback);
+ ASSERT_TRUE(result.isFailed());
+
+ // Callback not triggered for unsupported and on failure
+ ASSERT_EQ(1, *callbackCounter.get());
+}
+
+TEST_F(VibratorHalWrapperHidlV1_1Test, TestPerformEffectUnsupported) {
+ std::unique_ptr<int32_t> callbackCounter = std::make_unique<int32_t>();
+ auto callback = vibrator::TestFactory::createCountingCallback(callbackCounter.get());
+ // 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
new file mode 100644
index 0000000..26d9350
--- /dev/null
+++ b/services/vibratorservice/test/VibratorHalWrapperHidlV1_2Test.cpp
@@ -0,0 +1,192 @@
+/*
+ * 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 "VibratorHalWrapperHidlV1_2Test"
+
+#include <android/hardware/vibrator/IVibrator.h>
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include <utils/Log.h>
+
+#include <vibratorservice/VibratorCallbackScheduler.h>
+#include <vibratorservice/VibratorHalWrapper.h>
+
+#include "test_utils.h"
+
+namespace V1_0 = android::hardware::vibrator::V1_0;
+namespace V1_1 = android::hardware::vibrator::V1_1;
+namespace V1_2 = android::hardware::vibrator::V1_2;
+
+using android::hardware::vibrator::Effect;
+using android::hardware::vibrator::EffectStrength;
+
+using namespace android;
+using namespace std::chrono_literals;
+using namespace testing;
+
+// -------------------------------------------------------------------------------------------------
+
+class MockIVibratorV1_2 : public V1_2::IVibrator {
+public:
+ MOCK_METHOD(hardware::Return<V1_0::Status>, on, (uint32_t timeoutMs), (override));
+ MOCK_METHOD(hardware::Return<V1_0::Status>, off, (), (override));
+ MOCK_METHOD(hardware::Return<bool>, supportsAmplitudeControl, (), (override));
+ MOCK_METHOD(hardware::Return<V1_0::Status>, setAmplitude, (uint8_t amplitude), (override));
+ MOCK_METHOD(hardware::Return<void>, perform,
+ (V1_0::Effect effect, V1_0::EffectStrength strength, perform_cb cb), (override));
+ MOCK_METHOD(hardware::Return<void>, perform_1_1,
+ (V1_1::Effect_1_1 effect, V1_0::EffectStrength strength, perform_cb cb),
+ (override));
+ MOCK_METHOD(hardware::Return<void>, perform_1_2,
+ (V1_2::Effect effect, V1_0::EffectStrength strength, perform_cb cb), (override));
+};
+
+// -------------------------------------------------------------------------------------------------
+
+class VibratorHalWrapperHidlV1_2Test : public Test {
+public:
+ void SetUp() override {
+ mMockHal = new StrictMock<MockIVibratorV1_2>();
+ 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;
+};
+
+// -------------------------------------------------------------------------------------------------
+
+TEST_F(VibratorHalWrapperHidlV1_2Test, TestPerformEffectV1_0) {
+ {
+ 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(10ms, result.value());
+ ASSERT_EQ(1, *callbackCounter.get());
+}
+
+TEST_F(VibratorHalWrapperHidlV1_2Test, TestPerformEffectV1_1) {
+ {
+ 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(10ms, result.value());
+ ASSERT_EQ(1, *callbackCounter.get());
+}
+
+TEST_F(VibratorHalWrapperHidlV1_2Test, TestPerformEffectV1_2) {
+ {
+ 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_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());
+ EXPECT_CALL(*mMockHal.get(),
+ perform_1_2(Eq(V1_2::Effect::THUD), Eq(V1_0::EffectStrength::MEDIUM), _))
+ .Times(Exactly(1))
+ .WillRepeatedly(
+ [](V1_2::Effect, V1_0::EffectStrength, MockIVibratorV1_2::perform_cb cb) {
+ cb(V1_0::Status::UNSUPPORTED_OPERATION, 10);
+ return hardware::Return<void>();
+ });
+ EXPECT_CALL(*mMockHal.get(),
+ perform_1_2(Eq(V1_2::Effect::THUD), Eq(V1_0::EffectStrength::STRONG), _))
+ .Times(Exactly(2))
+ .WillOnce([](V1_2::Effect, V1_0::EffectStrength, MockIVibratorV1_2::perform_cb cb) {
+ cb(V1_0::Status::BAD_VALUE, 10);
+ return hardware::Return<void>();
+ })
+ .WillRepeatedly(
+ [](V1_2::Effect, V1_0::EffectStrength, MockIVibratorV1_2::perform_cb) {
+ return hardware::Return<void>(hardware::Status::fromExceptionCode(-1));
+ });
+ }
+
+ 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(10ms, result.value());
+ ASSERT_EQ(1, *callbackCounter.get());
+
+ result = mWrapper->performEffect(Effect::THUD, EffectStrength::MEDIUM, callback);
+ ASSERT_TRUE(result.isUnsupported());
+
+ result = mWrapper->performEffect(Effect::THUD, EffectStrength::STRONG, callback);
+ ASSERT_TRUE(result.isFailed());
+
+ 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());
+}
+
+TEST_F(VibratorHalWrapperHidlV1_2Test, TestPerformEffectUnsupported) {
+ std::unique_ptr<int32_t> callbackCounter = std::make_unique<int32_t>();
+ auto callback = vibrator::TestFactory::createCountingCallback(callbackCounter.get());
+ // 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
new file mode 100644
index 0000000..5de6257
--- /dev/null
+++ b/services/vibratorservice/test/VibratorHalWrapperHidlV1_3Test.cpp
@@ -0,0 +1,398 @@
+/*
+ * 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 "VibratorHalWrapperHidlV1_3Test"
+
+#include <android/hardware/vibrator/IVibrator.h>
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include <utils/Log.h>
+#include <thread>
+
+#include <vibratorservice/VibratorCallbackScheduler.h>
+#include <vibratorservice/VibratorHalWrapper.h>
+
+#include "test_utils.h"
+
+namespace V1_0 = android::hardware::vibrator::V1_0;
+namespace V1_1 = android::hardware::vibrator::V1_1;
+namespace V1_2 = android::hardware::vibrator::V1_2;
+namespace V1_3 = android::hardware::vibrator::V1_3;
+
+using android::hardware::vibrator::Effect;
+using android::hardware::vibrator::EffectStrength;
+using android::hardware::vibrator::IVibrator;
+
+using namespace android;
+using namespace std::chrono_literals;
+using namespace testing;
+
+// -------------------------------------------------------------------------------------------------
+
+class MockIVibratorV1_3 : public V1_3::IVibrator {
+public:
+ MOCK_METHOD(hardware::Return<V1_0::Status>, on, (uint32_t timeoutMs), (override));
+ MOCK_METHOD(hardware::Return<V1_0::Status>, off, (), (override));
+ MOCK_METHOD(hardware::Return<bool>, supportsAmplitudeControl, (), (override));
+ MOCK_METHOD(hardware::Return<bool>, supportsExternalControl, (), (override));
+ MOCK_METHOD(hardware::Return<V1_0::Status>, setAmplitude, (uint8_t amplitude), (override));
+ MOCK_METHOD(hardware::Return<V1_0::Status>, setExternalControl, (bool enabled), (override));
+ MOCK_METHOD(hardware::Return<void>, perform,
+ (V1_0::Effect effect, V1_0::EffectStrength strength, perform_cb cb), (override));
+ MOCK_METHOD(hardware::Return<void>, perform_1_1,
+ (V1_1::Effect_1_1 effect, V1_0::EffectStrength strength, perform_cb cb),
+ (override));
+ MOCK_METHOD(hardware::Return<void>, perform_1_2,
+ (V1_2::Effect effect, V1_0::EffectStrength strength, perform_cb cb), (override));
+ MOCK_METHOD(hardware::Return<void>, perform_1_3,
+ (V1_3::Effect effect, V1_0::EffectStrength strength, perform_cb cb), (override));
+};
+
+// -------------------------------------------------------------------------------------------------
+
+class VibratorHalWrapperHidlV1_3Test : public Test {
+public:
+ void SetUp() override {
+ mMockHal = new StrictMock<MockIVibratorV1_3>();
+ 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;
+};
+
+// -------------------------------------------------------------------------------------------------
+
+TEST_F(VibratorHalWrapperHidlV1_3Test, TestSetExternalControl) {
+ {
+ InSequence seq;
+ EXPECT_CALL(*mMockHal.get(), setExternalControl(Eq(true)))
+ .Times(Exactly(2))
+ .WillOnce([]() { return hardware::Return<V1_0::Status>(V1_0::Status::OK); })
+ .WillRepeatedly([]() {
+ return hardware::Return<V1_0::Status>(V1_0::Status::UNSUPPORTED_OPERATION);
+ });
+ EXPECT_CALL(*mMockHal.get(), setExternalControl(Eq(false)))
+ .Times(Exactly(2))
+ .WillOnce([]() { return hardware::Return<V1_0::Status>(V1_0::Status::BAD_VALUE); })
+ .WillRepeatedly([]() {
+ return hardware::Return<V1_0::Status>(hardware::Status::fromExceptionCode(-1));
+ });
+ }
+
+ ASSERT_TRUE(mWrapper->setExternalControl(true).isOk());
+ ASSERT_TRUE(mWrapper->setExternalControl(true).isUnsupported());
+ ASSERT_TRUE(mWrapper->setExternalControl(false).isFailed());
+ ASSERT_TRUE(mWrapper->setExternalControl(false).isFailed());
+}
+
+TEST_F(VibratorHalWrapperHidlV1_3Test, TestGetCapabilitiesSuccessful) {
+ {
+ InSequence seq;
+ EXPECT_CALL(*mMockHal.get(), supportsAmplitudeControl())
+ .Times(Exactly(1))
+ .WillRepeatedly([]() { return hardware::Return<bool>(true); });
+ EXPECT_CALL(*mMockHal.get(), supportsExternalControl()).Times(Exactly(1)).WillOnce([]() {
+ return hardware::Return<bool>(true);
+ });
+ }
+
+ auto result = mWrapper->getCapabilities();
+ ASSERT_TRUE(result.isOk());
+ ASSERT_EQ(vibrator::Capabilities::AMPLITUDE_CONTROL | vibrator::Capabilities::EXTERNAL_CONTROL,
+ result.value());
+}
+
+TEST_F(VibratorHalWrapperHidlV1_3Test, TestGetCapabilitiesOnlyAmplitudeControl) {
+ {
+ InSequence seq;
+ EXPECT_CALL(*mMockHal.get(), supportsAmplitudeControl()).Times(Exactly(1)).WillOnce([]() {
+ return hardware::Return<bool>(true);
+ });
+ EXPECT_CALL(*mMockHal.get(), supportsExternalControl()).Times(Exactly(1)).WillOnce([]() {
+ return hardware::Return<bool>(false);
+ });
+ }
+
+ auto result = mWrapper->getCapabilities();
+ ASSERT_TRUE(result.isOk());
+ ASSERT_EQ(vibrator::Capabilities::AMPLITUDE_CONTROL, result.value());
+}
+
+TEST_F(VibratorHalWrapperHidlV1_3Test, TestGetCapabilitiesOnlyExternalControl) {
+ {
+ InSequence seq;
+ EXPECT_CALL(*mMockHal.get(), supportsAmplitudeControl()).Times(Exactly(1)).WillOnce([]() {
+ return hardware::Return<bool>(false);
+ });
+ EXPECT_CALL(*mMockHal.get(), supportsExternalControl()).Times(Exactly(1)).WillOnce([]() {
+ return hardware::Return<bool>(true);
+ });
+ }
+
+ auto result = mWrapper->getCapabilities();
+ ASSERT_TRUE(result.isOk());
+ ASSERT_EQ(vibrator::Capabilities::EXTERNAL_CONTROL, result.value());
+}
+
+TEST_F(VibratorHalWrapperHidlV1_3Test, TestGetCapabilitiesNone) {
+ {
+ InSequence seq;
+ EXPECT_CALL(*mMockHal.get(), supportsAmplitudeControl())
+ .Times(Exactly(1))
+ .WillRepeatedly([]() { return hardware::Return<bool>(false); });
+ EXPECT_CALL(*mMockHal.get(), supportsExternalControl()).Times(Exactly(1)).WillOnce([]() {
+ return hardware::Return<bool>(false);
+ });
+ }
+
+ auto result = mWrapper->getCapabilities();
+ ASSERT_TRUE(result.isOk());
+ ASSERT_EQ(vibrator::Capabilities::NONE, result.value());
+}
+
+TEST_F(VibratorHalWrapperHidlV1_3Test, TestGetCapabilitiesFailed) {
+ {
+ InSequence seq;
+ EXPECT_CALL(*mMockHal.get(), supportsAmplitudeControl())
+ .Times(Exactly(1))
+ .WillRepeatedly([]() {
+ return hardware::Return<bool>(hardware::Status::fromExceptionCode(-1));
+ });
+
+ EXPECT_CALL(*mMockHal.get(), supportsAmplitudeControl())
+ .Times(Exactly(1))
+ .WillRepeatedly([]() { return hardware::Return<bool>(true); });
+ EXPECT_CALL(*mMockHal.get(), supportsExternalControl())
+ .Times(Exactly(1))
+ .WillRepeatedly([]() {
+ return hardware::Return<bool>(hardware::Status::fromExceptionCode(-1));
+ });
+ }
+
+ ASSERT_TRUE(mWrapper->getCapabilities().isFailed());
+ ASSERT_TRUE(mWrapper->getCapabilities().isFailed());
+}
+
+TEST_F(VibratorHalWrapperHidlV1_3Test, TestGetCapabilitiesCachesResult) {
+ {
+ InSequence seq;
+ EXPECT_CALL(*mMockHal.get(), supportsAmplitudeControl())
+ .Times(Exactly(1))
+ .WillRepeatedly([]() { return hardware::Return<bool>(true); });
+ EXPECT_CALL(*mMockHal.get(), supportsExternalControl()).Times(Exactly(1)).WillOnce([]() {
+ return hardware::Return<bool>(false);
+ });
+ }
+
+ std::vector<std::thread> threads;
+ for (int i = 0; i < 10; i++) {
+ threads.push_back(std::thread([&]() {
+ auto result = mWrapper->getCapabilities();
+ ASSERT_TRUE(result.isOk());
+ ASSERT_EQ(vibrator::Capabilities::AMPLITUDE_CONTROL, result.value());
+ }));
+ }
+ 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) {
+ {
+ InSequence seq;
+ EXPECT_CALL(*mMockHal.get(), supportsAmplitudeControl())
+ .Times(Exactly(1))
+ .WillRepeatedly([]() {
+ return hardware::Return<bool>(hardware::Status::fromExceptionCode(-1));
+ });
+
+ EXPECT_CALL(*mMockHal.get(), supportsAmplitudeControl())
+ .Times(Exactly(1))
+ .WillRepeatedly([]() { return hardware::Return<bool>(true); });
+ EXPECT_CALL(*mMockHal.get(), supportsExternalControl())
+ .Times(Exactly(1))
+ .WillRepeatedly([]() {
+ return hardware::Return<bool>(hardware::Status::fromExceptionCode(-1));
+ });
+
+ EXPECT_CALL(*mMockHal.get(), supportsAmplitudeControl())
+ .Times(Exactly(1))
+ .WillRepeatedly([]() { return hardware::Return<bool>(true); });
+ EXPECT_CALL(*mMockHal.get(), supportsExternalControl())
+ .Times(Exactly(1))
+ .WillRepeatedly([]() { return hardware::Return<bool>(false); });
+ }
+
+ // Call to supportsAmplitudeControl failed.
+ auto result = mWrapper->getCapabilities();
+ ASSERT_TRUE(result.isFailed());
+
+ // Call to supportsExternalControl failed.
+ result = mWrapper->getCapabilities();
+ ASSERT_TRUE(result.isFailed());
+
+ // Returns successful result from third call.
+ result = mWrapper->getCapabilities();
+ ASSERT_TRUE(result.isOk());
+ ASSERT_EQ(vibrator::Capabilities::AMPLITUDE_CONTROL, result.value());
+
+ // Returns cached successful result.
+ result = mWrapper->getCapabilities();
+ ASSERT_TRUE(result.isOk());
+ ASSERT_EQ(vibrator::Capabilities::AMPLITUDE_CONTROL, result.value());
+}
+
+TEST_F(VibratorHalWrapperHidlV1_3Test, TestPerformEffectV1_0) {
+ {
+ 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(10ms, result.value());
+ ASSERT_EQ(1, *callbackCounter.get());
+}
+
+TEST_F(VibratorHalWrapperHidlV1_3Test, TestPerformEffectV1_1) {
+ {
+ 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(10ms, result.value());
+ ASSERT_EQ(1, *callbackCounter.get());
+}
+
+TEST_F(VibratorHalWrapperHidlV1_3Test, TestPerformEffectV1_2) {
+ {
+ 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(10ms, result.value());
+ ASSERT_EQ(1, *callbackCounter.get());
+}
+
+TEST_F(VibratorHalWrapperHidlV1_3Test, TestPerformEffectV1_3) {
+ {
+ InSequence seq;
+ EXPECT_CALL(*mMockHal.get(),
+ perform_1_3(Eq(V1_3::Effect::TEXTURE_TICK), Eq(V1_0::EffectStrength::LIGHT), _))
+ .Times(Exactly(1))
+ .WillRepeatedly(
+ [](V1_3::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());
+ EXPECT_CALL(*mMockHal.get(),
+ perform_1_3(Eq(V1_3::Effect::TEXTURE_TICK), Eq(V1_0::EffectStrength::MEDIUM),
+ _))
+ .Times(Exactly(1))
+ .WillRepeatedly(
+ [](V1_3::Effect, V1_0::EffectStrength, MockIVibratorV1_3::perform_cb cb) {
+ cb(V1_0::Status::UNSUPPORTED_OPERATION, 0);
+ return hardware::Return<void>();
+ });
+ EXPECT_CALL(*mMockHal.get(),
+ perform_1_3(Eq(V1_3::Effect::TEXTURE_TICK), Eq(V1_0::EffectStrength::STRONG),
+ _))
+ .Times(Exactly(2))
+ .WillOnce([](V1_3::Effect, V1_0::EffectStrength, MockIVibratorV1_3::perform_cb cb) {
+ cb(V1_0::Status::BAD_VALUE, 0);
+ return hardware::Return<void>();
+ })
+ .WillRepeatedly(
+ [](V1_3::Effect, V1_0::EffectStrength, MockIVibratorV1_3::perform_cb) {
+ return hardware::Return<void>(hardware::Status::fromExceptionCode(-1));
+ });
+ }
+
+ std::unique_ptr<int32_t> callbackCounter = std::make_unique<int32_t>();
+ auto callback = vibrator::TestFactory::createCountingCallback(callbackCounter.get());
+
+ auto result = mWrapper->performEffect(Effect::TEXTURE_TICK, EffectStrength::LIGHT, callback);
+ ASSERT_TRUE(result.isOk());
+ ASSERT_EQ(10ms, result.value());
+ ASSERT_EQ(1, *callbackCounter.get());
+
+ result = mWrapper->performEffect(Effect::TEXTURE_TICK, EffectStrength::MEDIUM, callback);
+ ASSERT_TRUE(result.isUnsupported());
+
+ result = mWrapper->performEffect(Effect::TEXTURE_TICK, EffectStrength::STRONG, callback);
+ ASSERT_TRUE(result.isFailed());
+
+ result = mWrapper->performEffect(Effect::TEXTURE_TICK, EffectStrength::STRONG, callback);
+ ASSERT_TRUE(result.isFailed());
+
+ // 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
new file mode 100644
index 0000000..8d0b22e
--- /dev/null
+++ b/services/vibratorservice/test/test_utils.h
@@ -0,0 +1,71 @@
+/*
+ * 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 VIBRATORSERVICE_UNITTEST_UTIL_H_
+#define VIBRATORSERVICE_UNITTEST_UTIL_H_
+
+#include <android/hardware/vibrator/IVibrator.h>
+
+#include <vibratorservice/VibratorHalWrapper.h>
+
+namespace android {
+
+namespace vibrator {
+
+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,
+ std::chrono::milliseconds delay, float scale) {
+ CompositeEffect effect;
+ effect.primitive = primitive;
+ effect.delayMs = delay.count();
+ effect.scale = scale;
+ return effect;
+ }
+
+ static std::function<void()> createCountingCallback(int32_t* counter) {
+ return [counter]() { *counter += 1; };
+ }
+
+private:
+ TestFactory() = delete;
+ ~TestFactory() = delete;
+};
+
+// -------------------------------------------------------------------------------------------------
+
+} // namespace vibrator
+
+} // namespace android
+
+#endif // VIBRATORSERVICE_UNITTEST_UTIL_H_
\ No newline at end of file
diff --git a/vulkan/libvulkan/driver.cpp b/vulkan/libvulkan/driver.cpp
index 74ef0e7..535e190 100644
--- a/vulkan/libvulkan/driver.cpp
+++ b/vulkan/libvulkan/driver.cpp
@@ -102,8 +102,6 @@
~CreateInfoWrapper();
VkResult Validate();
- void DowngradeApiVersion();
- void UpgradeDeviceCoreApiVersion(uint32_t api_version);
const std::bitset<ProcHook::EXTENSION_COUNT>& GetHookExtensions() const;
const std::bitset<ProcHook::EXTENSION_COUNT>& GetHalExtensions() const;
@@ -120,8 +118,8 @@
uint32_t name_count;
};
+ VkResult SanitizeApiVersion();
VkResult SanitizePNext();
-
VkResult SanitizeLayers();
VkResult SanitizeExtensions();
@@ -133,6 +131,7 @@
const bool is_instance_;
const VkAllocationCallbacks& allocator_;
+ const uint32_t loader_api_version_;
VkPhysicalDevice physical_dev_;
@@ -142,6 +141,7 @@
};
VkApplicationInfo application_info_;
+ uint32_t sanitized_api_version_;
ExtensionFilter extension_filter_;
@@ -327,29 +327,21 @@
const VkAllocationCallbacks& allocator)
: is_instance_(true),
allocator_(allocator),
+ loader_api_version_(VK_API_VERSION_1_1),
physical_dev_(VK_NULL_HANDLE),
instance_info_(create_info),
- extension_filter_() {
- // instance core versions need to match the loader api version
- for (uint32_t i = ProcHook::EXTENSION_CORE_1_0;
- i != ProcHook::EXTENSION_COUNT; ++i) {
- hook_extensions_.set(i);
- hal_extensions_.set(i);
- }
-}
+ sanitized_api_version_(loader_api_version_),
+ extension_filter_() {}
CreateInfoWrapper::CreateInfoWrapper(VkPhysicalDevice physical_dev,
const VkDeviceCreateInfo& create_info,
const VkAllocationCallbacks& allocator)
: is_instance_(false),
allocator_(allocator),
+ loader_api_version_(VK_API_VERSION_1_1),
physical_dev_(physical_dev),
dev_info_(create_info),
- extension_filter_() {
- // initialize with baseline core API version
- hook_extensions_.set(ProcHook::EXTENSION_CORE_1_0);
- hal_extensions_.set(ProcHook::EXTENSION_CORE_1_0);
-}
+ extension_filter_() {}
CreateInfoWrapper::~CreateInfoWrapper() {
allocator_.pfnFree(allocator_.pUserData, extension_filter_.exts);
@@ -357,7 +349,9 @@
}
VkResult CreateInfoWrapper::Validate() {
- VkResult result = SanitizePNext();
+ VkResult result = SanitizeApiVersion();
+ if (result == VK_SUCCESS)
+ result = SanitizePNext();
if (result == VK_SUCCESS)
result = SanitizeLayers();
if (result == VK_SUCCESS)
@@ -384,6 +378,82 @@
return &dev_info_;
}
+VkResult CreateInfoWrapper::SanitizeApiVersion() {
+ if (is_instance_) {
+ // instance core versions need to match the loader api version
+ for (uint32_t i = ProcHook::EXTENSION_CORE_1_0;
+ i != ProcHook::EXTENSION_COUNT; i++) {
+ hook_extensions_.set(i);
+ hal_extensions_.set(i);
+ }
+
+ uint32_t icd_api_version = VK_API_VERSION_1_0;
+ PFN_vkEnumerateInstanceVersion pfn_enumerate_instance_version =
+ reinterpret_cast<PFN_vkEnumerateInstanceVersion>(
+ Hal::Device().GetInstanceProcAddr(
+ nullptr, "vkEnumerateInstanceVersion"));
+ if (pfn_enumerate_instance_version) {
+ ATRACE_BEGIN("pfn_enumerate_instance_version");
+ VkResult result =
+ (*pfn_enumerate_instance_version)(&icd_api_version);
+ ATRACE_END();
+ if (result != VK_SUCCESS)
+ return result;
+
+ icd_api_version ^= VK_VERSION_PATCH(icd_api_version);
+ }
+
+ if (icd_api_version < VK_API_VERSION_1_0)
+ return VK_SUCCESS;
+
+ if (icd_api_version < loader_api_version_) {
+ sanitized_api_version_ = icd_api_version;
+
+ if (!instance_info_.pApplicationInfo)
+ return VK_SUCCESS;
+
+ application_info_ = *instance_info_.pApplicationInfo;
+ application_info_.apiVersion = sanitized_api_version_;
+ instance_info_.pApplicationInfo = &application_info_;
+ }
+ } else {
+ const auto& driver = GetData(physical_dev_).driver;
+
+ VkPhysicalDeviceProperties properties;
+ ATRACE_BEGIN("driver.GetPhysicalDeviceProperties");
+ driver.GetPhysicalDeviceProperties(physical_dev_, &properties);
+ ATRACE_END();
+
+ if (properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_CPU) {
+ // Log that the app is hitting software Vulkan implementation
+ android::GraphicsEnv::getInstance().setTargetStats(
+ android::GpuStatsInfo::Stats::CPU_VULKAN_IN_USE);
+ }
+
+ uint32_t api_version = properties.apiVersion;
+ api_version ^= VK_VERSION_PATCH(api_version);
+
+ if (api_version > loader_api_version_)
+ api_version = loader_api_version_;
+
+ switch (api_version) {
+ case VK_API_VERSION_1_1:
+ hook_extensions_.set(ProcHook::EXTENSION_CORE_1_1);
+ hal_extensions_.set(ProcHook::EXTENSION_CORE_1_1);
+ [[clang::fallthrough]];
+ case VK_API_VERSION_1_0:
+ hook_extensions_.set(ProcHook::EXTENSION_CORE_1_0);
+ hal_extensions_.set(ProcHook::EXTENSION_CORE_1_0);
+ break;
+ default:
+ ALOGE("Unknown API version[%u]", api_version);
+ break;
+ }
+ }
+
+ return VK_SUCCESS;
+}
+
VkResult CreateInfoWrapper::SanitizePNext() {
const struct StructHeader {
VkStructureType type;
@@ -431,15 +501,33 @@
: dev_info_.ppEnabledExtensionNames;
auto& ext_count = (is_instance_) ? instance_info_.enabledExtensionCount
: dev_info_.enabledExtensionCount;
- if (!ext_count)
- return VK_SUCCESS;
VkResult result = InitExtensionFilter();
if (result != VK_SUCCESS)
return result;
- for (uint32_t i = 0; i < ext_count; i++)
- FilterExtension(ext_names[i]);
+ if (is_instance_ && sanitized_api_version_ < loader_api_version_) {
+ for (uint32_t i = 0; i < ext_count; i++) {
+ // Upon api downgrade, skip the promoted instance extensions in the
+ // first pass to avoid duplicate extensions.
+ const std::optional<uint32_t> version =
+ GetInstanceExtensionPromotedVersion(ext_names[i]);
+ if (version && *version > sanitized_api_version_ &&
+ *version <= loader_api_version_)
+ continue;
+
+ FilterExtension(ext_names[i]);
+ }
+
+ // Enable the required extensions to support core functionalities.
+ const auto promoted_extensions = GetPromotedInstanceExtensions(
+ sanitized_api_version_, loader_api_version_);
+ for (const auto& promoted_extension : promoted_extensions)
+ FilterExtension(promoted_extension);
+ } else {
+ for (uint32_t i = 0; i < ext_count; i++)
+ FilterExtension(ext_names[i]);
+ }
// Enable device extensions that contain physical-device commands, so that
// vkGetInstanceProcAddr will return those physical-device commands.
@@ -504,10 +592,20 @@
filter.ext_count = count;
// allocate name array
- uint32_t enabled_ext_count = (is_instance_)
- ? instance_info_.enabledExtensionCount
- : dev_info_.enabledExtensionCount;
- count = std::min(filter.ext_count, enabled_ext_count);
+ if (is_instance_) {
+ uint32_t enabled_ext_count = instance_info_.enabledExtensionCount;
+
+ // It requires enabling additional promoted extensions to downgrade api,
+ // so we reserve enough space here.
+ if (sanitized_api_version_ < loader_api_version_) {
+ enabled_ext_count += CountPromotedInstanceExtensions(
+ sanitized_api_version_, loader_api_version_);
+ }
+
+ count = std::min(filter.ext_count, enabled_ext_count);
+ } else {
+ count = std::min(filter.ext_count, dev_info_.enabledExtensionCount);
+ }
filter.names = reinterpret_cast<const char**>(allocator_.pfnAllocation(
allocator_.pUserData, sizeof(const char*) * count, alignof(const char*),
VK_SYSTEM_ALLOCATION_SCOPE_COMMAND));
@@ -535,6 +633,10 @@
hook_extensions_.set(ext_bit);
break;
case ProcHook::KHR_get_physical_device_properties2:
+ case ProcHook::KHR_device_group_creation:
+ case ProcHook::KHR_external_memory_capabilities:
+ case ProcHook::KHR_external_semaphore_capabilities:
+ case ProcHook::KHR_external_fence_capabilities:
case ProcHook::EXTENSION_UNKNOWN:
// Extensions we don't need to do anything about at this level
break;
@@ -591,6 +693,10 @@
case ProcHook::KHR_android_surface:
case ProcHook::KHR_get_physical_device_properties2:
+ case ProcHook::KHR_device_group_creation:
+ case ProcHook::KHR_external_memory_capabilities:
+ case ProcHook::KHR_external_semaphore_capabilities:
+ case ProcHook::KHR_external_fence_capabilities:
case ProcHook::KHR_get_surface_capabilities2:
case ProcHook::KHR_surface:
case ProcHook::EXT_debug_report:
@@ -636,40 +742,6 @@
}
}
-void CreateInfoWrapper::DowngradeApiVersion() {
- // If pApplicationInfo is NULL, apiVersion is assumed to be 1.0:
- if (instance_info_.pApplicationInfo) {
- application_info_ = *instance_info_.pApplicationInfo;
- instance_info_.pApplicationInfo = &application_info_;
- application_info_.apiVersion = VK_API_VERSION_1_0;
- }
-}
-
-void CreateInfoWrapper::UpgradeDeviceCoreApiVersion(uint32_t api_version) {
- ALOG_ASSERT(!is_instance_, "Device only API called by instance wrapper.");
-
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wold-style-cast"
- api_version ^= VK_VERSION_PATCH(api_version);
-#pragma clang diagnostic pop
-
- // cap the API version to the loader supported highest version
- if (api_version > VK_API_VERSION_1_1)
- api_version = VK_API_VERSION_1_1;
-
- switch (api_version) {
- case VK_API_VERSION_1_1:
- hook_extensions_.set(ProcHook::EXTENSION_CORE_1_1);
- hal_extensions_.set(ProcHook::EXTENSION_CORE_1_1);
- [[clang::fallthrough]];
- case VK_API_VERSION_1_0:
- break;
- default:
- ALOGD("Unknown upgrade API version[%u]", api_version);
- break;
- }
-}
-
VKAPI_ATTR void* DefaultAllocate(void*,
size_t size,
size_t alignment,
@@ -904,13 +976,6 @@
bool QueryPresentationProperties(
VkPhysicalDevice physicalDevice,
VkPhysicalDevicePresentationPropertiesANDROID *presentation_properties) {
- const InstanceData& data = GetData(physicalDevice);
-
- // GPDP2 must be present and enabled on the instance.
- if (!data.driver.GetPhysicalDeviceProperties2KHR &&
- !data.driver.GetPhysicalDeviceProperties2)
- return false;
-
// Request the android-specific presentation properties via GPDP2
VkPhysicalDeviceProperties2KHR properties = {
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2_KHR,
@@ -926,12 +991,7 @@
presentation_properties->pNext = nullptr;
presentation_properties->sharedImage = VK_FALSE;
- if (data.driver.GetPhysicalDeviceProperties2KHR) {
- data.driver.GetPhysicalDeviceProperties2KHR(physicalDevice,
- &properties);
- } else {
- data.driver.GetPhysicalDeviceProperties2(physicalDevice, &properties);
- }
+ GetPhysicalDeviceProperties2(physicalDevice, &properties);
return true;
}
@@ -1032,45 +1092,12 @@
if (result != VK_SUCCESS)
return result;
- ATRACE_BEGIN("AllocateInstanceData");
InstanceData* data = AllocateInstanceData(data_allocator);
- ATRACE_END();
if (!data)
return VK_ERROR_OUT_OF_HOST_MEMORY;
data->hook_extensions |= wrapper.GetHookExtensions();
- ATRACE_BEGIN("autoDowngradeApiVersion");
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wold-style-cast"
- uint32_t api_version = ((pCreateInfo->pApplicationInfo)
- ? pCreateInfo->pApplicationInfo->apiVersion
- : VK_API_VERSION_1_0);
- uint32_t api_major_version = VK_VERSION_MAJOR(api_version);
- uint32_t api_minor_version = VK_VERSION_MINOR(api_version);
- uint32_t icd_api_version;
- PFN_vkEnumerateInstanceVersion pfn_enumerate_instance_version =
- reinterpret_cast<PFN_vkEnumerateInstanceVersion>(
- Hal::Device().GetInstanceProcAddr(nullptr,
- "vkEnumerateInstanceVersion"));
- if (!pfn_enumerate_instance_version) {
- icd_api_version = VK_API_VERSION_1_0;
- } else {
- ATRACE_BEGIN("pfn_enumerate_instance_version");
- result = (*pfn_enumerate_instance_version)(&icd_api_version);
- ATRACE_END();
- }
- uint32_t icd_api_major_version = VK_VERSION_MAJOR(icd_api_version);
- uint32_t icd_api_minor_version = VK_VERSION_MINOR(icd_api_version);
-
- if ((icd_api_major_version == 1) && (icd_api_minor_version == 0) &&
- ((api_major_version > 1) || (api_minor_version > 0))) {
- api_version = VK_API_VERSION_1_0;
- wrapper.DowngradeApiVersion();
- }
-#pragma clang diagnostic pop
- ATRACE_END();
-
// call into the driver
VkInstance instance;
ATRACE_BEGIN("driver.CreateInstance");
@@ -1145,13 +1172,6 @@
if (!data)
return VK_ERROR_OUT_OF_HOST_MEMORY;
- VkPhysicalDeviceProperties properties;
- ATRACE_BEGIN("driver.GetPhysicalDeviceProperties");
- instance_data.driver.GetPhysicalDeviceProperties(physicalDevice,
- &properties);
- ATRACE_END();
-
- wrapper.UpgradeDeviceCoreApiVersion(properties.apiVersion);
data->hook_extensions |= wrapper.GetHookExtensions();
// call into the driver
@@ -1196,12 +1216,6 @@
return VK_ERROR_INCOMPATIBLE_DRIVER;
}
- if (properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_CPU) {
- // Log that the app is hitting software Vulkan implementation
- android::GraphicsEnv::getInstance().setTargetStats(
- android::GpuStatsInfo::Stats::CPU_VULKAN_IN_USE);
- }
-
data->driver_device = dev;
*pDevice = dev;
@@ -1248,7 +1262,8 @@
VkResult result = VK_SUCCESS;
const auto& data = GetData(instance);
- if (!data.driver.EnumeratePhysicalDeviceGroups) {
+ if (!data.driver.EnumeratePhysicalDeviceGroups &&
+ !data.driver.EnumeratePhysicalDeviceGroupsKHR) {
uint32_t device_count = 0;
result = EnumeratePhysicalDevices(instance, &device_count, nullptr);
if (result < 0)
@@ -1280,9 +1295,15 @@
pPhysicalDeviceGroupProperties[i].subsetAllocation = 0;
}
} else {
- result = data.driver.EnumeratePhysicalDeviceGroups(
- instance, pPhysicalDeviceGroupCount,
- pPhysicalDeviceGroupProperties);
+ if (data.driver.EnumeratePhysicalDeviceGroups) {
+ result = data.driver.EnumeratePhysicalDeviceGroups(
+ instance, pPhysicalDeviceGroupCount,
+ pPhysicalDeviceGroupProperties);
+ } else {
+ result = data.driver.EnumeratePhysicalDeviceGroupsKHR(
+ instance, pPhysicalDeviceGroupCount,
+ pPhysicalDeviceGroupProperties);
+ }
if ((result == VK_SUCCESS || result == VK_INCOMPLETE) &&
*pPhysicalDeviceGroupCount && pPhysicalDeviceGroupProperties) {
for (uint32_t i = 0; i < *pPhysicalDeviceGroupCount; i++) {
@@ -1352,5 +1373,198 @@
return data.driver.QueueSubmit(queue, submitCount, pSubmits, fence);
}
+void GetPhysicalDeviceFeatures2(VkPhysicalDevice physicalDevice,
+ VkPhysicalDeviceFeatures2* pFeatures) {
+ ATRACE_CALL();
+
+ const auto& driver = GetData(physicalDevice).driver;
+
+ if (driver.GetPhysicalDeviceFeatures2) {
+ driver.GetPhysicalDeviceFeatures2(physicalDevice, pFeatures);
+ return;
+ }
+
+ driver.GetPhysicalDeviceFeatures2KHR(physicalDevice, pFeatures);
+}
+
+void GetPhysicalDeviceProperties2(VkPhysicalDevice physicalDevice,
+ VkPhysicalDeviceProperties2* pProperties) {
+ ATRACE_CALL();
+
+ const auto& driver = GetData(physicalDevice).driver;
+
+ if (driver.GetPhysicalDeviceProperties2) {
+ driver.GetPhysicalDeviceProperties2(physicalDevice, pProperties);
+ return;
+ }
+
+ driver.GetPhysicalDeviceProperties2KHR(physicalDevice, pProperties);
+}
+
+void GetPhysicalDeviceFormatProperties2(
+ VkPhysicalDevice physicalDevice,
+ VkFormat format,
+ VkFormatProperties2* pFormatProperties) {
+ ATRACE_CALL();
+
+ const auto& driver = GetData(physicalDevice).driver;
+
+ if (driver.GetPhysicalDeviceFormatProperties2) {
+ driver.GetPhysicalDeviceFormatProperties2(physicalDevice, format,
+ pFormatProperties);
+ return;
+ }
+
+ driver.GetPhysicalDeviceFormatProperties2KHR(physicalDevice, format,
+ pFormatProperties);
+}
+
+VkResult GetPhysicalDeviceImageFormatProperties2(
+ VkPhysicalDevice physicalDevice,
+ const VkPhysicalDeviceImageFormatInfo2* pImageFormatInfo,
+ VkImageFormatProperties2* pImageFormatProperties) {
+ ATRACE_CALL();
+
+ const auto& driver = GetData(physicalDevice).driver;
+
+ if (driver.GetPhysicalDeviceImageFormatProperties2) {
+ return driver.GetPhysicalDeviceImageFormatProperties2(
+ physicalDevice, pImageFormatInfo, pImageFormatProperties);
+ }
+
+ return driver.GetPhysicalDeviceImageFormatProperties2KHR(
+ physicalDevice, pImageFormatInfo, pImageFormatProperties);
+}
+
+void GetPhysicalDeviceQueueFamilyProperties2(
+ VkPhysicalDevice physicalDevice,
+ uint32_t* pQueueFamilyPropertyCount,
+ VkQueueFamilyProperties2* pQueueFamilyProperties) {
+ ATRACE_CALL();
+
+ const auto& driver = GetData(physicalDevice).driver;
+
+ if (driver.GetPhysicalDeviceQueueFamilyProperties2) {
+ driver.GetPhysicalDeviceQueueFamilyProperties2(
+ physicalDevice, pQueueFamilyPropertyCount, pQueueFamilyProperties);
+ return;
+ }
+
+ driver.GetPhysicalDeviceQueueFamilyProperties2KHR(
+ physicalDevice, pQueueFamilyPropertyCount, pQueueFamilyProperties);
+}
+
+void GetPhysicalDeviceMemoryProperties2(
+ VkPhysicalDevice physicalDevice,
+ VkPhysicalDeviceMemoryProperties2* pMemoryProperties) {
+ ATRACE_CALL();
+
+ const auto& driver = GetData(physicalDevice).driver;
+
+ if (driver.GetPhysicalDeviceMemoryProperties2) {
+ driver.GetPhysicalDeviceMemoryProperties2(physicalDevice,
+ pMemoryProperties);
+ return;
+ }
+
+ driver.GetPhysicalDeviceMemoryProperties2KHR(physicalDevice,
+ pMemoryProperties);
+}
+
+void GetPhysicalDeviceSparseImageFormatProperties2(
+ VkPhysicalDevice physicalDevice,
+ const VkPhysicalDeviceSparseImageFormatInfo2* pFormatInfo,
+ uint32_t* pPropertyCount,
+ VkSparseImageFormatProperties2* pProperties) {
+ ATRACE_CALL();
+
+ const auto& driver = GetData(physicalDevice).driver;
+
+ if (driver.GetPhysicalDeviceSparseImageFormatProperties2) {
+ driver.GetPhysicalDeviceSparseImageFormatProperties2(
+ physicalDevice, pFormatInfo, pPropertyCount, pProperties);
+ return;
+ }
+
+ driver.GetPhysicalDeviceSparseImageFormatProperties2KHR(
+ physicalDevice, pFormatInfo, pPropertyCount, pProperties);
+}
+
+void GetPhysicalDeviceExternalBufferProperties(
+ VkPhysicalDevice physicalDevice,
+ const VkPhysicalDeviceExternalBufferInfo* pExternalBufferInfo,
+ VkExternalBufferProperties* pExternalBufferProperties) {
+ ATRACE_CALL();
+
+ const auto& driver = GetData(physicalDevice).driver;
+
+ if (driver.GetPhysicalDeviceExternalBufferProperties) {
+ driver.GetPhysicalDeviceExternalBufferProperties(
+ physicalDevice, pExternalBufferInfo, pExternalBufferProperties);
+ return;
+ }
+
+ if (driver.GetPhysicalDeviceExternalBufferPropertiesKHR) {
+ driver.GetPhysicalDeviceExternalBufferPropertiesKHR(
+ physicalDevice, pExternalBufferInfo, pExternalBufferProperties);
+ return;
+ }
+
+ memset(&pExternalBufferProperties->externalMemoryProperties, 0,
+ sizeof(VkExternalMemoryProperties));
+}
+
+void GetPhysicalDeviceExternalSemaphoreProperties(
+ VkPhysicalDevice physicalDevice,
+ const VkPhysicalDeviceExternalSemaphoreInfo* pExternalSemaphoreInfo,
+ VkExternalSemaphoreProperties* pExternalSemaphoreProperties) {
+ ATRACE_CALL();
+
+ const auto& driver = GetData(physicalDevice).driver;
+
+ if (driver.GetPhysicalDeviceExternalSemaphoreProperties) {
+ driver.GetPhysicalDeviceExternalSemaphoreProperties(
+ physicalDevice, pExternalSemaphoreInfo,
+ pExternalSemaphoreProperties);
+ return;
+ }
+
+ if (driver.GetPhysicalDeviceExternalSemaphorePropertiesKHR) {
+ driver.GetPhysicalDeviceExternalSemaphorePropertiesKHR(
+ physicalDevice, pExternalSemaphoreInfo,
+ pExternalSemaphoreProperties);
+ return;
+ }
+
+ pExternalSemaphoreProperties->exportFromImportedHandleTypes = 0;
+ pExternalSemaphoreProperties->compatibleHandleTypes = 0;
+ pExternalSemaphoreProperties->externalSemaphoreFeatures = 0;
+}
+
+void GetPhysicalDeviceExternalFenceProperties(
+ VkPhysicalDevice physicalDevice,
+ const VkPhysicalDeviceExternalFenceInfo* pExternalFenceInfo,
+ VkExternalFenceProperties* pExternalFenceProperties) {
+ ATRACE_CALL();
+
+ const auto& driver = GetData(physicalDevice).driver;
+
+ if (driver.GetPhysicalDeviceExternalFenceProperties) {
+ driver.GetPhysicalDeviceExternalFenceProperties(
+ physicalDevice, pExternalFenceInfo, pExternalFenceProperties);
+ return;
+ }
+
+ if (driver.GetPhysicalDeviceExternalFencePropertiesKHR) {
+ driver.GetPhysicalDeviceExternalFencePropertiesKHR(
+ physicalDevice, pExternalFenceInfo, pExternalFenceProperties);
+ return;
+ }
+
+ pExternalFenceProperties->exportFromImportedHandleTypes = 0;
+ pExternalFenceProperties->compatibleHandleTypes = 0;
+ pExternalFenceProperties->externalFenceFeatures = 0;
+}
+
} // namespace driver
} // namespace vulkan
diff --git a/vulkan/libvulkan/driver.h b/vulkan/libvulkan/driver.h
index 23c717c..e7b4bb2 100644
--- a/vulkan/libvulkan/driver.h
+++ b/vulkan/libvulkan/driver.h
@@ -126,6 +126,18 @@
VKAPI_ATTR void GetDeviceQueue2(VkDevice device, const VkDeviceQueueInfo2* pQueueInfo, VkQueue* pQueue);
VKAPI_ATTR VkResult AllocateCommandBuffers(VkDevice device, const VkCommandBufferAllocateInfo* pAllocateInfo, VkCommandBuffer* pCommandBuffers);
VKAPI_ATTR VkResult QueueSubmit(VkQueue queue, uint32_t submitCount, const VkSubmitInfo* pSubmits, VkFence fence);
+
+VKAPI_ATTR void GetPhysicalDeviceFeatures2(VkPhysicalDevice physicalDevice, VkPhysicalDeviceFeatures2* pFeatures);
+VKAPI_ATTR void GetPhysicalDeviceProperties2(VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties2* pProperties);
+VKAPI_ATTR void GetPhysicalDeviceFormatProperties2(VkPhysicalDevice physicalDevice, VkFormat format, VkFormatProperties2* pFormatProperties);
+VKAPI_ATTR VkResult GetPhysicalDeviceImageFormatProperties2(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceImageFormatInfo2* pImageFormatInfo, VkImageFormatProperties2* pImageFormatProperties);
+VKAPI_ATTR void GetPhysicalDeviceQueueFamilyProperties2(VkPhysicalDevice physicalDevice, uint32_t* pQueueFamilyPropertyCount, VkQueueFamilyProperties2* pQueueFamilyProperties);
+VKAPI_ATTR void GetPhysicalDeviceMemoryProperties2(VkPhysicalDevice physicalDevice, VkPhysicalDeviceMemoryProperties2* pMemoryProperties);
+VKAPI_ATTR void GetPhysicalDeviceSparseImageFormatProperties2(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSparseImageFormatInfo2* pFormatInfo, uint32_t* pPropertyCount, VkSparseImageFormatProperties2* pProperties);
+
+VKAPI_ATTR void GetPhysicalDeviceExternalBufferProperties(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalBufferInfo* pExternalBufferInfo, VkExternalBufferProperties* pExternalBufferProperties);
+VKAPI_ATTR void GetPhysicalDeviceExternalSemaphoreProperties(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalSemaphoreInfo* pExternalSemaphoreInfo, VkExternalSemaphoreProperties* pExternalSemaphoreProperties);
+VKAPI_ATTR void GetPhysicalDeviceExternalFenceProperties(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalFenceInfo* pExternalFenceInfo, VkExternalFenceProperties* pExternalFenceProperties);
// clang-format on
template <typename DispatchableType>
diff --git a/vulkan/libvulkan/driver_gen.cpp b/vulkan/libvulkan/driver_gen.cpp
index 52205e9..6549c37 100644
--- a/vulkan/libvulkan/driver_gen.cpp
+++ b/vulkan/libvulkan/driver_gen.cpp
@@ -363,6 +363,55 @@
reinterpret_cast<PFN_vkVoidFunction>(checkedGetPastPresentationTimingGOOGLE),
},
{
+ "vkGetPhysicalDeviceExternalBufferProperties",
+ ProcHook::INSTANCE,
+ ProcHook::EXTENSION_CORE_1_1,
+ reinterpret_cast<PFN_vkVoidFunction>(GetPhysicalDeviceExternalBufferProperties),
+ nullptr,
+ },
+ {
+ "vkGetPhysicalDeviceExternalFenceProperties",
+ ProcHook::INSTANCE,
+ ProcHook::EXTENSION_CORE_1_1,
+ reinterpret_cast<PFN_vkVoidFunction>(GetPhysicalDeviceExternalFenceProperties),
+ nullptr,
+ },
+ {
+ "vkGetPhysicalDeviceExternalSemaphoreProperties",
+ ProcHook::INSTANCE,
+ ProcHook::EXTENSION_CORE_1_1,
+ reinterpret_cast<PFN_vkVoidFunction>(GetPhysicalDeviceExternalSemaphoreProperties),
+ nullptr,
+ },
+ {
+ "vkGetPhysicalDeviceFeatures2",
+ ProcHook::INSTANCE,
+ ProcHook::EXTENSION_CORE_1_1,
+ reinterpret_cast<PFN_vkVoidFunction>(GetPhysicalDeviceFeatures2),
+ nullptr,
+ },
+ {
+ "vkGetPhysicalDeviceFormatProperties2",
+ ProcHook::INSTANCE,
+ ProcHook::EXTENSION_CORE_1_1,
+ reinterpret_cast<PFN_vkVoidFunction>(GetPhysicalDeviceFormatProperties2),
+ nullptr,
+ },
+ {
+ "vkGetPhysicalDeviceImageFormatProperties2",
+ ProcHook::INSTANCE,
+ ProcHook::EXTENSION_CORE_1_1,
+ reinterpret_cast<PFN_vkVoidFunction>(GetPhysicalDeviceImageFormatProperties2),
+ nullptr,
+ },
+ {
+ "vkGetPhysicalDeviceMemoryProperties2",
+ ProcHook::INSTANCE,
+ ProcHook::EXTENSION_CORE_1_1,
+ reinterpret_cast<PFN_vkVoidFunction>(GetPhysicalDeviceMemoryProperties2),
+ nullptr,
+ },
+ {
"vkGetPhysicalDevicePresentRectanglesKHR",
ProcHook::INSTANCE,
ProcHook::KHR_swapchain,
@@ -370,6 +419,27 @@
nullptr,
},
{
+ "vkGetPhysicalDeviceProperties2",
+ ProcHook::INSTANCE,
+ ProcHook::EXTENSION_CORE_1_1,
+ reinterpret_cast<PFN_vkVoidFunction>(GetPhysicalDeviceProperties2),
+ nullptr,
+ },
+ {
+ "vkGetPhysicalDeviceQueueFamilyProperties2",
+ ProcHook::INSTANCE,
+ ProcHook::EXTENSION_CORE_1_1,
+ reinterpret_cast<PFN_vkVoidFunction>(GetPhysicalDeviceQueueFamilyProperties2),
+ nullptr,
+ },
+ {
+ "vkGetPhysicalDeviceSparseImageFormatProperties2",
+ ProcHook::INSTANCE,
+ ProcHook::EXTENSION_CORE_1_1,
+ reinterpret_cast<PFN_vkVoidFunction>(GetPhysicalDeviceSparseImageFormatProperties2),
+ nullptr,
+ },
+ {
"vkGetPhysicalDeviceSurfaceCapabilities2KHR",
ProcHook::INSTANCE,
ProcHook::KHR_get_surface_capabilities2,
@@ -505,6 +575,10 @@
if (strcmp(name, "VK_ANDROID_external_memory_android_hardware_buffer") == 0) return ProcHook::ANDROID_external_memory_android_hardware_buffer;
if (strcmp(name, "VK_KHR_bind_memory2") == 0) return ProcHook::KHR_bind_memory2;
if (strcmp(name, "VK_KHR_get_physical_device_properties2") == 0) return ProcHook::KHR_get_physical_device_properties2;
+ if (strcmp(name, "VK_KHR_device_group_creation") == 0) return ProcHook::KHR_device_group_creation;
+ if (strcmp(name, "VK_KHR_external_memory_capabilities") == 0) return ProcHook::KHR_external_memory_capabilities;
+ if (strcmp(name, "VK_KHR_external_semaphore_capabilities") == 0) return ProcHook::KHR_external_semaphore_capabilities;
+ if (strcmp(name, "VK_KHR_external_fence_capabilities") == 0) return ProcHook::KHR_external_fence_capabilities;
// clang-format on
return ProcHook::EXTENSION_UNKNOWN;
}
@@ -543,9 +617,28 @@
INIT_PROC_EXT(EXT_debug_report, true, instance, CreateDebugReportCallbackEXT);
INIT_PROC_EXT(EXT_debug_report, true, instance, DestroyDebugReportCallbackEXT);
INIT_PROC_EXT(EXT_debug_report, true, instance, DebugReportMessageEXT);
+ INIT_PROC(false, instance, GetPhysicalDeviceFeatures2);
+ INIT_PROC_EXT(KHR_get_physical_device_properties2, true, instance, GetPhysicalDeviceFeatures2KHR);
INIT_PROC(false, instance, GetPhysicalDeviceProperties2);
INIT_PROC_EXT(KHR_get_physical_device_properties2, true, instance, GetPhysicalDeviceProperties2KHR);
+ INIT_PROC(false, instance, GetPhysicalDeviceFormatProperties2);
+ INIT_PROC_EXT(KHR_get_physical_device_properties2, true, instance, GetPhysicalDeviceFormatProperties2KHR);
+ INIT_PROC(false, instance, GetPhysicalDeviceImageFormatProperties2);
+ INIT_PROC_EXT(KHR_get_physical_device_properties2, true, instance, GetPhysicalDeviceImageFormatProperties2KHR);
+ INIT_PROC(false, instance, GetPhysicalDeviceQueueFamilyProperties2);
+ INIT_PROC_EXT(KHR_get_physical_device_properties2, true, instance, GetPhysicalDeviceQueueFamilyProperties2KHR);
+ INIT_PROC(false, instance, GetPhysicalDeviceMemoryProperties2);
+ INIT_PROC_EXT(KHR_get_physical_device_properties2, true, instance, GetPhysicalDeviceMemoryProperties2KHR);
+ INIT_PROC(false, instance, GetPhysicalDeviceSparseImageFormatProperties2);
+ INIT_PROC_EXT(KHR_get_physical_device_properties2, true, instance, GetPhysicalDeviceSparseImageFormatProperties2KHR);
+ INIT_PROC(false, instance, GetPhysicalDeviceExternalBufferProperties);
+ INIT_PROC_EXT(KHR_external_memory_capabilities, true, instance, GetPhysicalDeviceExternalBufferPropertiesKHR);
+ INIT_PROC(false, instance, GetPhysicalDeviceExternalSemaphoreProperties);
+ INIT_PROC_EXT(KHR_external_semaphore_capabilities, true, instance, GetPhysicalDeviceExternalSemaphorePropertiesKHR);
+ INIT_PROC(false, instance, GetPhysicalDeviceExternalFenceProperties);
+ INIT_PROC_EXT(KHR_external_fence_capabilities, true, instance, GetPhysicalDeviceExternalFencePropertiesKHR);
INIT_PROC(false, instance, EnumeratePhysicalDeviceGroups);
+ INIT_PROC_EXT(KHR_device_group_creation, true, instance, EnumeratePhysicalDeviceGroupsKHR);
// clang-format on
return success;
@@ -577,5 +670,53 @@
return success;
}
+const std::pair<const char*, uint32_t> g_promoted_instance_extensions[] = {
+ // clang-format off
+ std::make_pair("VK_KHR_device_group_creation", VK_API_VERSION_1_1),
+ std::make_pair("VK_KHR_external_fence_capabilities", VK_API_VERSION_1_1),
+ std::make_pair("VK_KHR_external_memory_capabilities", VK_API_VERSION_1_1),
+ std::make_pair("VK_KHR_external_semaphore_capabilities", VK_API_VERSION_1_1),
+ std::make_pair("VK_KHR_get_physical_device_properties2", VK_API_VERSION_1_1),
+ // clang-format on
+};
+
+std::optional<uint32_t> GetInstanceExtensionPromotedVersion(const char* name) {
+ auto begin = std::cbegin(g_promoted_instance_extensions);
+ auto end = std::cend(g_promoted_instance_extensions);
+ auto iter =
+ std::lower_bound(begin, end, name,
+ [](const std::pair<const char*, uint32_t>& e,
+ const char* n) { return strcmp(e.first, n) < 0; });
+ return (iter < end && strcmp(iter->first, name) == 0)
+ ? std::optional<uint32_t>(iter->second)
+ : std::nullopt;
+}
+
+uint32_t CountPromotedInstanceExtensions(uint32_t begin_version,
+ uint32_t end_version) {
+ auto begin = std::cbegin(g_promoted_instance_extensions);
+ auto end = std::cend(g_promoted_instance_extensions);
+ uint32_t count = 0;
+
+ for (auto iter = begin; iter != end; iter++)
+ if (iter->second > begin_version && iter->second <= end_version)
+ count++;
+
+ return count;
+}
+
+std::vector<const char*> GetPromotedInstanceExtensions(uint32_t begin_version,
+ uint32_t end_version) {
+ auto begin = std::cbegin(g_promoted_instance_extensions);
+ auto end = std::cend(g_promoted_instance_extensions);
+ std::vector<const char*> extensions;
+
+ for (auto iter = begin; iter != end; iter++)
+ if (iter->second > begin_version && iter->second <= end_version)
+ extensions.emplace_back(iter->first);
+
+ return extensions;
+}
+
} // namespace driver
} // namespace vulkan
diff --git a/vulkan/libvulkan/driver_gen.h b/vulkan/libvulkan/driver_gen.h
index 43c4d14..1aba674 100644
--- a/vulkan/libvulkan/driver_gen.h
+++ b/vulkan/libvulkan/driver_gen.h
@@ -23,6 +23,8 @@
#include <vulkan/vulkan.h>
#include <bitset>
+#include <optional>
+#include <vector>
namespace vulkan {
namespace driver {
@@ -48,6 +50,10 @@
ANDROID_external_memory_android_hardware_buffer,
KHR_bind_memory2,
KHR_get_physical_device_properties2,
+ KHR_device_group_creation,
+ KHR_external_memory_capabilities,
+ KHR_external_semaphore_capabilities,
+ KHR_external_fence_capabilities,
EXTENSION_CORE_1_0,
EXTENSION_CORE_1_1,
@@ -74,9 +80,28 @@
PFN_vkCreateDebugReportCallbackEXT CreateDebugReportCallbackEXT;
PFN_vkDestroyDebugReportCallbackEXT DestroyDebugReportCallbackEXT;
PFN_vkDebugReportMessageEXT DebugReportMessageEXT;
+ PFN_vkGetPhysicalDeviceFeatures2 GetPhysicalDeviceFeatures2;
+ PFN_vkGetPhysicalDeviceFeatures2KHR GetPhysicalDeviceFeatures2KHR;
PFN_vkGetPhysicalDeviceProperties2 GetPhysicalDeviceProperties2;
PFN_vkGetPhysicalDeviceProperties2KHR GetPhysicalDeviceProperties2KHR;
+ PFN_vkGetPhysicalDeviceFormatProperties2 GetPhysicalDeviceFormatProperties2;
+ PFN_vkGetPhysicalDeviceFormatProperties2KHR GetPhysicalDeviceFormatProperties2KHR;
+ PFN_vkGetPhysicalDeviceImageFormatProperties2 GetPhysicalDeviceImageFormatProperties2;
+ PFN_vkGetPhysicalDeviceImageFormatProperties2KHR GetPhysicalDeviceImageFormatProperties2KHR;
+ PFN_vkGetPhysicalDeviceQueueFamilyProperties2 GetPhysicalDeviceQueueFamilyProperties2;
+ PFN_vkGetPhysicalDeviceQueueFamilyProperties2KHR GetPhysicalDeviceQueueFamilyProperties2KHR;
+ PFN_vkGetPhysicalDeviceMemoryProperties2 GetPhysicalDeviceMemoryProperties2;
+ PFN_vkGetPhysicalDeviceMemoryProperties2KHR GetPhysicalDeviceMemoryProperties2KHR;
+ PFN_vkGetPhysicalDeviceSparseImageFormatProperties2 GetPhysicalDeviceSparseImageFormatProperties2;
+ PFN_vkGetPhysicalDeviceSparseImageFormatProperties2KHR GetPhysicalDeviceSparseImageFormatProperties2KHR;
+ PFN_vkGetPhysicalDeviceExternalBufferProperties GetPhysicalDeviceExternalBufferProperties;
+ PFN_vkGetPhysicalDeviceExternalBufferPropertiesKHR GetPhysicalDeviceExternalBufferPropertiesKHR;
+ PFN_vkGetPhysicalDeviceExternalSemaphoreProperties GetPhysicalDeviceExternalSemaphoreProperties;
+ PFN_vkGetPhysicalDeviceExternalSemaphorePropertiesKHR GetPhysicalDeviceExternalSemaphorePropertiesKHR;
+ PFN_vkGetPhysicalDeviceExternalFenceProperties GetPhysicalDeviceExternalFenceProperties;
+ PFN_vkGetPhysicalDeviceExternalFencePropertiesKHR GetPhysicalDeviceExternalFencePropertiesKHR;
PFN_vkEnumeratePhysicalDeviceGroups EnumeratePhysicalDeviceGroups;
+ PFN_vkEnumeratePhysicalDeviceGroupsKHR EnumeratePhysicalDeviceGroupsKHR;
// clang-format on
};
@@ -109,6 +134,12 @@
PFN_vkGetDeviceProcAddr get_proc,
const std::bitset<ProcHook::EXTENSION_COUNT>& extensions);
+std::optional<uint32_t> GetInstanceExtensionPromotedVersion(const char* name);
+uint32_t CountPromotedInstanceExtensions(uint32_t begin_version,
+ uint32_t end_version);
+std::vector<const char*> GetPromotedInstanceExtensions(uint32_t begin_version,
+ uint32_t end_version);
+
} // namespace driver
} // namespace vulkan
diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp
index d3ed88d..c7ff640 100644
--- a/vulkan/libvulkan/swapchain.cpp
+++ b/vulkan/libvulkan/swapchain.cpp
@@ -970,7 +970,6 @@
strerror(-err), err);
}
- // TODO(b/143294545): Return something better than "whole window"
pRects[0].offset.x = 0;
pRects[0].offset.y = 0;
pRects[0].extent = VkExtent2D{static_cast<uint32_t>(width),
diff --git a/vulkan/scripts/driver_generator.py b/vulkan/scripts/driver_generator.py
index a64a702..566e063 100644
--- a/vulkan/scripts/driver_generator.py
+++ b/vulkan/scripts/driver_generator.py
@@ -40,6 +40,10 @@
'VK_ANDROID_external_memory_android_hardware_buffer',
'VK_KHR_bind_memory2',
'VK_KHR_get_physical_device_properties2',
+ 'VK_KHR_device_group_creation',
+ 'VK_KHR_external_memory_capabilities',
+ 'VK_KHR_external_semaphore_capabilities',
+ 'VK_KHR_external_fence_capabilities',
]
# Functions needed at vulkan::driver level.
@@ -71,12 +75,41 @@
'vkDestroyImage',
'vkGetPhysicalDeviceProperties',
- 'vkGetPhysicalDeviceProperties2',
- 'vkGetPhysicalDeviceProperties2KHR',
# VK_KHR_swapchain v69 requirement
'vkBindImageMemory2',
'vkBindImageMemory2KHR',
+
+ # For promoted VK_KHR_device_group_creation
+ 'vkEnumeratePhysicalDeviceGroupsKHR',
+
+ # For promoted VK_KHR_get_physical_device_properties2
+ 'vkGetPhysicalDeviceFeatures2',
+ 'vkGetPhysicalDeviceFeatures2KHR',
+ 'vkGetPhysicalDeviceProperties2',
+ 'vkGetPhysicalDeviceProperties2KHR',
+ 'vkGetPhysicalDeviceFormatProperties2',
+ 'vkGetPhysicalDeviceFormatProperties2KHR',
+ 'vkGetPhysicalDeviceImageFormatProperties2',
+ 'vkGetPhysicalDeviceImageFormatProperties2KHR',
+ 'vkGetPhysicalDeviceQueueFamilyProperties2',
+ 'vkGetPhysicalDeviceQueueFamilyProperties2KHR',
+ 'vkGetPhysicalDeviceMemoryProperties2',
+ 'vkGetPhysicalDeviceMemoryProperties2KHR',
+ 'vkGetPhysicalDeviceSparseImageFormatProperties2',
+ 'vkGetPhysicalDeviceSparseImageFormatProperties2KHR',
+
+ # For promoted VK_KHR_external_memory_capabilities
+ 'vkGetPhysicalDeviceExternalBufferProperties',
+ 'vkGetPhysicalDeviceExternalBufferPropertiesKHR',
+
+ # For promoted VK_KHR_external_semaphore_capabilities
+ 'vkGetPhysicalDeviceExternalSemaphoreProperties',
+ 'vkGetPhysicalDeviceExternalSemaphorePropertiesKHR',
+
+ # For promoted VK_KHR_external_fence_capabilities
+ 'vkGetPhysicalDeviceExternalFenceProperties',
+ 'vkGetPhysicalDeviceExternalFencePropertiesKHR',
]
# Functions intercepted at vulkan::driver level.
@@ -106,6 +139,24 @@
# VK_KHR_swapchain v69 requirement
'vkBindImageMemory2',
'vkBindImageMemory2KHR',
+
+ # For promoted VK_KHR_get_physical_device_properties2
+ 'vkGetPhysicalDeviceFeatures2',
+ 'vkGetPhysicalDeviceProperties2',
+ 'vkGetPhysicalDeviceFormatProperties2',
+ 'vkGetPhysicalDeviceImageFormatProperties2',
+ 'vkGetPhysicalDeviceQueueFamilyProperties2',
+ 'vkGetPhysicalDeviceMemoryProperties2',
+ 'vkGetPhysicalDeviceSparseImageFormatProperties2',
+
+ # For promoted VK_KHR_external_memory_capabilities
+ 'vkGetPhysicalDeviceExternalBufferProperties',
+
+ # For promoted VK_KHR_external_semaphore_capabilities
+ 'vkGetPhysicalDeviceExternalSemaphoreProperties',
+
+ # For promoted VK_KHR_external_fence_capabilities
+ 'vkGetPhysicalDeviceExternalFenceProperties',
]
@@ -162,6 +213,8 @@
#include <vulkan/vulkan.h>
#include <bitset>
+#include <optional>
+#include <vector>
namespace vulkan {
namespace driver {
@@ -229,6 +282,12 @@
PFN_vkGetDeviceProcAddr get_proc,
const std::bitset<ProcHook::EXTENSION_COUNT>& extensions);
+std::optional<uint32_t> GetInstanceExtensionPromotedVersion(const char* name);
+uint32_t CountPromotedInstanceExtensions(uint32_t begin_version,
+ uint32_t end_version);
+std::vector<const char*> GetPromotedInstanceExtensions(uint32_t begin_version,
+ uint32_t end_version);
+
} // namespace driver
} // namespace vulkan
@@ -539,6 +598,54 @@
return success;
}
+const std::pair<const char*, uint32_t> g_promoted_instance_extensions[] = {
+ // clang-format off\n""")
+
+ for key, value in sorted(gencom.promoted_inst_ext_dict.items()):
+ f.write(gencom.indent(1) + 'std::make_pair("' + key + '", ' + value + '),\n')
+
+ f.write("""\
+ // clang-format on
+};
+
+std::optional<uint32_t> GetInstanceExtensionPromotedVersion(const char* name) {
+ auto begin = std::cbegin(g_promoted_instance_extensions);
+ auto end = std::cend(g_promoted_instance_extensions);
+ auto iter =
+ std::lower_bound(begin, end, name,
+ [](const std::pair<const char*, uint32_t>& e,
+ const char* n) { return strcmp(e.first, n) < 0; });
+ return (iter < end && strcmp(iter->first, name) == 0)
+ ? std::optional<uint32_t>(iter->second)
+ : std::nullopt;
+}
+
+uint32_t CountPromotedInstanceExtensions(uint32_t begin_version,
+ uint32_t end_version) {
+ auto begin = std::cbegin(g_promoted_instance_extensions);
+ auto end = std::cend(g_promoted_instance_extensions);
+ uint32_t count = 0;
+
+ for (auto iter = begin; iter != end; iter++)
+ if (iter->second > begin_version && iter->second <= end_version)
+ count++;
+
+ return count;
+}
+
+std::vector<const char*> GetPromotedInstanceExtensions(uint32_t begin_version,
+ uint32_t end_version) {
+ auto begin = std::cbegin(g_promoted_instance_extensions);
+ auto end = std::cend(g_promoted_instance_extensions);
+ std::vector<const char*> extensions;
+
+ for (auto iter = begin; iter != end; iter++)
+ if (iter->second > begin_version && iter->second <= end_version)
+ extensions.emplace_back(iter->first);
+
+ return extensions;
+}
+
} // namespace driver
} // namespace vulkan\n""")
diff --git a/vulkan/scripts/generator_common.py b/vulkan/scripts/generator_common.py
index ef0719d..ef021f2 100644
--- a/vulkan/scripts/generator_common.py
+++ b/vulkan/scripts/generator_common.py
@@ -97,6 +97,9 @@
# Dict for mapping a function to the core Vulkan API version.
version_dict = {}
+# Dict for mapping a promoted instance extension to the core Vulkan API version.
+promoted_inst_ext_dict = {}
+
def indent(num):
"""Returns the requested indents.
@@ -183,6 +186,15 @@
return version[11:]
+def version_2_api_version(version):
+ """Returns the api version from a version string.
+
+ Args:
+ version: Vulkan version string.
+ """
+ return 'VK_API' + version[2:]
+
+
def is_function_supported(cmd):
"""Returns true if a function is core or from a supportable extension.
@@ -327,6 +339,7 @@
return_type_dict
version_code_list
version_dict
+ promoted_inst_ext_dict
"""
registry = os.path.join(os.path.dirname(__file__), '..', '..', '..', '..',
'external', 'vulkan-headers', 'registry', 'vk.xml')
@@ -379,6 +392,10 @@
apiversion = ''
if extension.tag == 'extension':
extname = extension.get('name')
+ if (extension.get('type') == 'instance' and
+ extension.get('promotedto') is not None):
+ promoted_inst_ext_dict[extname] = \
+ version_2_api_version(extension.get('promotedto'))
for req in extension:
if req.get('feature') is not None:
apiversion = req.get('feature')
diff --git a/vulkan/vkjson/vkjson.h b/vulkan/vkjson/vkjson.h
index a283b83..52e7bee 100644
--- a/vulkan/vkjson/vkjson.h
+++ b/vulkan/vkjson/vkjson.h
@@ -158,10 +158,7 @@
VkJsonInstance* instance,
std::string* errors);
-VkJsonDevice VkJsonGetDevice(VkInstance instance,
- VkPhysicalDevice device,
- uint32_t instanceExtensionCount,
- const char* const* instanceExtensions);
+VkJsonDevice VkJsonGetDevice(VkPhysicalDevice device);
std::string VkJsonDeviceToJson(const VkJsonDevice& device);
bool VkJsonDeviceFromJson(const std::string& json,
VkJsonDevice* device,
@@ -177,7 +174,7 @@
typedef VkJsonDevice VkJsonAllProperties;
inline VkJsonAllProperties VkJsonGetAllProperties(
VkPhysicalDevice physicalDevice) {
- return VkJsonGetDevice(VK_NULL_HANDLE, physicalDevice, 0, nullptr);
+ return VkJsonGetDevice(physicalDevice);
}
inline std::string VkJsonAllPropertiesToJson(
const VkJsonAllProperties& properties) {
diff --git a/vulkan/vkjson/vkjson_instance.cc b/vulkan/vkjson/vkjson_instance.cc
index 84cfe5e..ace713b 100644
--- a/vulkan/vkjson/vkjson_instance.cc
+++ b/vulkan/vkjson/vkjson_instance.cc
@@ -28,8 +28,6 @@
#include <utility>
namespace {
-const char* kSupportedInstanceExtensions[] = {
- "VK_KHR_get_physical_device_properties2"};
bool EnumerateExtensions(const char* layer_name,
std::vector<VkExtensionProperties>* extensions) {
@@ -47,15 +45,6 @@
}
bool HasExtension(const char* extension_name,
- uint32_t count,
- const char* const* extensions) {
- return std::find_if(extensions, extensions + count,
- [extension_name](const char* extension) {
- return strcmp(extension, extension_name) == 0;
- }) != extensions + count;
-}
-
-bool HasExtension(const char* extension_name,
const std::vector<VkExtensionProperties>& extensions) {
return std::find_if(extensions.cbegin(), extensions.cend(),
[extension_name](const VkExtensionProperties& extension) {
@@ -65,27 +54,9 @@
}
} // anonymous namespace
-VkJsonDevice VkJsonGetDevice(VkInstance instance,
- VkPhysicalDevice physical_device,
- uint32_t instance_extension_count,
- const char* const* instance_extensions) {
+VkJsonDevice VkJsonGetDevice(VkPhysicalDevice physical_device) {
VkJsonDevice device;
- PFN_vkGetPhysicalDeviceProperties2KHR vkpGetPhysicalDeviceProperties2KHR =
- nullptr;
- PFN_vkGetPhysicalDeviceFeatures2KHR vkpGetPhysicalDeviceFeatures2KHR =
- nullptr;
- if (instance != VK_NULL_HANDLE &&
- HasExtension("VK_KHR_get_physical_device_properties2",
- instance_extension_count, instance_extensions)) {
- vkpGetPhysicalDeviceProperties2KHR =
- reinterpret_cast<PFN_vkGetPhysicalDeviceProperties2KHR>(
- vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceProperties2KHR"));
- vkpGetPhysicalDeviceFeatures2KHR =
- reinterpret_cast<PFN_vkGetPhysicalDeviceFeatures2KHR>(
- vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceFeatures2KHR"));
- }
-
uint32_t extension_count = 0;
vkEnumerateDeviceExtensionProperties(physical_device, nullptr,
&extension_count, nullptr);
@@ -103,55 +74,48 @@
device.layers.data());
}
- if (HasExtension("VK_KHR_get_physical_device_properties2",
- instance_extension_count, instance_extensions)) {
- VkPhysicalDeviceProperties2KHR properties = {
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2_KHR,
- nullptr,
- {} // properties
- };
- if (HasExtension("VK_KHR_driver_properties", device.extensions)) {
- device.ext_driver_properties.reported = true;
- device.ext_driver_properties.driver_properties_khr.sType =
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES_KHR;
- device.ext_driver_properties.driver_properties_khr.pNext =
- properties.pNext;
- properties.pNext =
- &device.ext_driver_properties.driver_properties_khr;
- }
- vkpGetPhysicalDeviceProperties2KHR(physical_device, &properties);
- device.properties = properties.properties;
-
- VkPhysicalDeviceFeatures2KHR features = {
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2_KHR,
- nullptr,
- {} // features
- };
- if (HasExtension("VK_KHR_variable_pointers", device.extensions)) {
- device.ext_variable_pointer_features.reported = true;
- device.ext_variable_pointer_features.variable_pointer_features_khr.sType =
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTER_FEATURES_KHR;
- device.ext_variable_pointer_features.variable_pointer_features_khr.pNext =
- features.pNext;
- features.pNext =
- &device.ext_variable_pointer_features.variable_pointer_features_khr;
- }
- if (HasExtension("VK_KHR_shader_float16_int8", device.extensions)) {
- device.ext_shader_float16_int8_features.reported = true;
- device.ext_shader_float16_int8_features.shader_float16_int8_features_khr
- .sType =
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT16_INT8_FEATURES_KHR;
- device.ext_shader_float16_int8_features.shader_float16_int8_features_khr
- .pNext = features.pNext;
- features.pNext = &device.ext_shader_float16_int8_features
- .shader_float16_int8_features_khr;
- }
- vkpGetPhysicalDeviceFeatures2KHR(physical_device, &features);
- device.features = features.features;
- } else {
- vkGetPhysicalDeviceProperties(physical_device, &device.properties);
- vkGetPhysicalDeviceFeatures(physical_device, &device.features);
+ VkPhysicalDeviceProperties2 properties = {
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2,
+ nullptr,
+ {},
+ };
+ if (HasExtension("VK_KHR_driver_properties", device.extensions)) {
+ device.ext_driver_properties.reported = true;
+ device.ext_driver_properties.driver_properties_khr.sType =
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES_KHR;
+ device.ext_driver_properties.driver_properties_khr.pNext = properties.pNext;
+ properties.pNext = &device.ext_driver_properties.driver_properties_khr;
}
+ vkGetPhysicalDeviceProperties2(physical_device, &properties);
+ device.properties = properties.properties;
+
+ VkPhysicalDeviceFeatures2 features = {
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2,
+ nullptr,
+ {},
+ };
+ if (HasExtension("VK_KHR_variable_pointers", device.extensions)) {
+ device.ext_variable_pointer_features.reported = true;
+ device.ext_variable_pointer_features.variable_pointer_features_khr.sType =
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTER_FEATURES_KHR;
+ device.ext_variable_pointer_features.variable_pointer_features_khr.pNext =
+ features.pNext;
+ features.pNext =
+ &device.ext_variable_pointer_features.variable_pointer_features_khr;
+ }
+ if (HasExtension("VK_KHR_shader_float16_int8", device.extensions)) {
+ device.ext_shader_float16_int8_features.reported = true;
+ device.ext_shader_float16_int8_features.shader_float16_int8_features_khr
+ .sType =
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT16_INT8_FEATURES_KHR;
+ device.ext_shader_float16_int8_features.shader_float16_int8_features_khr
+ .pNext = features.pNext;
+ features.pNext = &device.ext_shader_float16_int8_features
+ .shader_float16_int8_features_khr;
+ }
+ vkGetPhysicalDeviceFeatures2(physical_device, &features);
+ device.features = features.features;
+
vkGetPhysicalDeviceMemoryProperties(physical_device, &device.memory);
uint32_t queue_family_count = 0;
@@ -189,135 +153,117 @@
}
}
- PFN_vkGetPhysicalDeviceProperties2 vkpGetPhysicalDeviceProperties2 =
- reinterpret_cast<PFN_vkGetPhysicalDeviceProperties2>(
- vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceProperties2"));
- if (vkpGetPhysicalDeviceProperties2) {
- VkPhysicalDeviceProperties2 properties2 = {
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2, nullptr, {}};
+ VkPhysicalDeviceProperties2 properties2 = {
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2,
+ nullptr,
+ {},
+ };
- device.subgroup_properties.sType =
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_PROPERTIES;
- device.subgroup_properties.pNext = properties2.pNext;
- properties2.pNext = &device.subgroup_properties;
+ device.subgroup_properties.sType =
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_PROPERTIES;
+ device.subgroup_properties.pNext = properties2.pNext;
+ properties2.pNext = &device.subgroup_properties;
- device.point_clipping_properties.sType =
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_POINT_CLIPPING_PROPERTIES;
- device.point_clipping_properties.pNext = properties2.pNext;
- properties2.pNext = &device.point_clipping_properties;
+ device.point_clipping_properties.sType =
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_POINT_CLIPPING_PROPERTIES;
+ device.point_clipping_properties.pNext = properties2.pNext;
+ properties2.pNext = &device.point_clipping_properties;
- device.multiview_properties.sType =
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PROPERTIES;
- device.multiview_properties.pNext = properties2.pNext;
- properties2.pNext = &device.multiview_properties;
+ device.multiview_properties.sType =
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PROPERTIES;
+ device.multiview_properties.pNext = properties2.pNext;
+ properties2.pNext = &device.multiview_properties;
- device.id_properties.sType =
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES;
- device.id_properties.pNext = properties2.pNext;
- properties2.pNext = &device.id_properties;
+ device.id_properties.sType =
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES;
+ device.id_properties.pNext = properties2.pNext;
+ properties2.pNext = &device.id_properties;
- device.maintenance3_properties.sType =
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_3_PROPERTIES;
- device.maintenance3_properties.pNext = properties2.pNext;
- properties2.pNext = &device.maintenance3_properties;
+ device.maintenance3_properties.sType =
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_3_PROPERTIES;
+ device.maintenance3_properties.pNext = properties2.pNext;
+ properties2.pNext = &device.maintenance3_properties;
- (*vkpGetPhysicalDeviceProperties2)(physical_device, &properties2);
- }
+ vkGetPhysicalDeviceProperties2(physical_device, &properties2);
- PFN_vkGetPhysicalDeviceFeatures2 vkpGetPhysicalDeviceFeatures2 =
- reinterpret_cast<PFN_vkGetPhysicalDeviceFeatures2>(
- vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceFeatures2"));
- if (vkpGetPhysicalDeviceFeatures2) {
- VkPhysicalDeviceFeatures2 features2 = {
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2, nullptr, {}};
+ VkPhysicalDeviceFeatures2 features2 = {
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2,
+ nullptr,
+ {},
+ };
- device.bit16_storage_features.sType =
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES;
- device.bit16_storage_features.pNext = features2.pNext;
- features2.pNext = &device.bit16_storage_features;
+ device.bit16_storage_features.sType =
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES;
+ device.bit16_storage_features.pNext = features2.pNext;
+ features2.pNext = &device.bit16_storage_features;
- device.multiview_features.sType =
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES;
- device.multiview_features.pNext = features2.pNext;
- features2.pNext = &device.multiview_features;
+ device.multiview_features.sType =
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES;
+ device.multiview_features.pNext = features2.pNext;
+ features2.pNext = &device.multiview_features;
- device.variable_pointer_features.sType =
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTER_FEATURES;
- device.variable_pointer_features.pNext = features2.pNext;
- features2.pNext = &device.variable_pointer_features;
+ device.variable_pointer_features.sType =
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTER_FEATURES;
+ device.variable_pointer_features.pNext = features2.pNext;
+ features2.pNext = &device.variable_pointer_features;
- device.protected_memory_features.sType =
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_FEATURES;
- device.protected_memory_features.pNext = features2.pNext;
- features2.pNext = &device.protected_memory_features;
+ device.protected_memory_features.sType =
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_FEATURES;
+ device.protected_memory_features.pNext = features2.pNext;
+ features2.pNext = &device.protected_memory_features;
- device.sampler_ycbcr_conversion_features.sType =
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES;
- device.sampler_ycbcr_conversion_features.pNext = features2.pNext;
- features2.pNext = &device.sampler_ycbcr_conversion_features;
+ device.sampler_ycbcr_conversion_features.sType =
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES;
+ device.sampler_ycbcr_conversion_features.pNext = features2.pNext;
+ features2.pNext = &device.sampler_ycbcr_conversion_features;
- device.shader_draw_parameter_features.sType =
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DRAW_PARAMETER_FEATURES;
- device.shader_draw_parameter_features.pNext = features2.pNext;
- features2.pNext = &device.shader_draw_parameter_features;
+ device.shader_draw_parameter_features.sType =
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DRAW_PARAMETER_FEATURES;
+ device.shader_draw_parameter_features.pNext = features2.pNext;
+ features2.pNext = &device.shader_draw_parameter_features;
- (*vkpGetPhysicalDeviceFeatures2)(physical_device, &features2);
- }
+ vkGetPhysicalDeviceFeatures2(physical_device, &features2);
- PFN_vkGetPhysicalDeviceExternalFenceProperties
- vkpGetPhysicalDeviceExternalFenceProperties =
- reinterpret_cast<PFN_vkGetPhysicalDeviceExternalFenceProperties>(
- vkGetInstanceProcAddr(
- instance, "vkGetPhysicalDeviceExternalFenceProperties"));
- if (vkpGetPhysicalDeviceExternalFenceProperties) {
- VkPhysicalDeviceExternalFenceInfo external_fence_info = {
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_FENCE_INFO, nullptr,
- VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT};
- VkExternalFenceProperties external_fence_properties = {};
+ VkPhysicalDeviceExternalFenceInfo external_fence_info = {
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_FENCE_INFO, nullptr,
+ VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT};
+ VkExternalFenceProperties external_fence_properties = {};
- for (VkExternalFenceHandleTypeFlagBits handle_type =
- VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT;
- handle_type <= VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT;
- handle_type = static_cast<VkExternalFenceHandleTypeFlagBits>(
- handle_type << 1)) {
- external_fence_info.handleType = handle_type;
- (*vkpGetPhysicalDeviceExternalFenceProperties)(
- physical_device, &external_fence_info, &external_fence_properties);
- if (external_fence_properties.exportFromImportedHandleTypes ||
- external_fence_properties.compatibleHandleTypes ||
- external_fence_properties.externalFenceFeatures) {
- device.external_fence_properties.insert(
- std::make_pair(handle_type, external_fence_properties));
- }
+ for (VkExternalFenceHandleTypeFlagBits handle_type =
+ VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT;
+ handle_type <= VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT;
+ handle_type =
+ static_cast<VkExternalFenceHandleTypeFlagBits>(handle_type << 1)) {
+ external_fence_info.handleType = handle_type;
+ vkGetPhysicalDeviceExternalFenceProperties(
+ physical_device, &external_fence_info, &external_fence_properties);
+ if (external_fence_properties.exportFromImportedHandleTypes ||
+ external_fence_properties.compatibleHandleTypes ||
+ external_fence_properties.externalFenceFeatures) {
+ device.external_fence_properties.insert(
+ std::make_pair(handle_type, external_fence_properties));
}
}
- PFN_vkGetPhysicalDeviceExternalSemaphoreProperties
- vkpGetPhysicalDeviceExternalSemaphoreProperties = reinterpret_cast<
- PFN_vkGetPhysicalDeviceExternalSemaphoreProperties>(
- vkGetInstanceProcAddr(
- instance, "vkGetPhysicalDeviceExternalSemaphoreProperties"));
- if (vkpGetPhysicalDeviceExternalSemaphoreProperties) {
- VkPhysicalDeviceExternalSemaphoreInfo external_semaphore_info = {
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_SEMAPHORE_INFO, nullptr,
- VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT};
- VkExternalSemaphoreProperties external_semaphore_properties = {};
+ VkPhysicalDeviceExternalSemaphoreInfo external_semaphore_info = {
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_SEMAPHORE_INFO, nullptr,
+ VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT};
+ VkExternalSemaphoreProperties external_semaphore_properties = {};
- for (VkExternalSemaphoreHandleTypeFlagBits handle_type =
- VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT;
- handle_type <= VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT;
- handle_type = static_cast<VkExternalSemaphoreHandleTypeFlagBits>(
- handle_type << 1)) {
- external_semaphore_info.handleType = handle_type;
- (*vkpGetPhysicalDeviceExternalSemaphoreProperties)(
- physical_device, &external_semaphore_info,
- &external_semaphore_properties);
- if (external_semaphore_properties.exportFromImportedHandleTypes ||
- external_semaphore_properties.compatibleHandleTypes ||
- external_semaphore_properties.externalSemaphoreFeatures) {
- device.external_semaphore_properties.insert(
- std::make_pair(handle_type, external_semaphore_properties));
- }
+ for (VkExternalSemaphoreHandleTypeFlagBits handle_type =
+ VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT;
+ handle_type <= VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT;
+ handle_type = static_cast<VkExternalSemaphoreHandleTypeFlagBits>(
+ handle_type << 1)) {
+ external_semaphore_info.handleType = handle_type;
+ vkGetPhysicalDeviceExternalSemaphoreProperties(
+ physical_device, &external_semaphore_info,
+ &external_semaphore_properties);
+ if (external_semaphore_properties.exportFromImportedHandleTypes ||
+ external_semaphore_properties.compatibleHandleTypes ||
+ external_semaphore_properties.externalSemaphoreFeatures) {
+ device.external_semaphore_properties.insert(
+ std::make_pair(handle_type, external_semaphore_properties));
}
}
}
@@ -351,19 +297,15 @@
if (!EnumerateExtensions(nullptr, &instance.extensions))
return VkJsonInstance();
- std::vector<const char*> instance_extensions;
- for (const auto extension : kSupportedInstanceExtensions) {
- if (HasExtension(extension, instance.extensions))
- instance_extensions.push_back(extension);
- }
-
- const VkApplicationInfo app_info = {VK_STRUCTURE_TYPE_APPLICATION_INFO,
- nullptr,
- "vkjson_info",
- 1,
- "",
- 0,
- VK_API_VERSION_1_1};
+ const VkApplicationInfo app_info = {
+ VK_STRUCTURE_TYPE_APPLICATION_INFO,
+ nullptr,
+ "vkjson_info",
+ 1,
+ "",
+ 0,
+ VK_API_VERSION_1_1,
+ };
VkInstanceCreateInfo instance_info = {
VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
nullptr,
@@ -371,8 +313,9 @@
&app_info,
0,
nullptr,
- static_cast<uint32_t>(instance_extensions.size()),
- instance_extensions.data()};
+ 0,
+ nullptr,
+ };
VkInstance vkinstance;
result = vkCreateInstance(&instance_info, nullptr, &vkinstance);
if (result != VK_SUCCESS)
@@ -397,52 +340,38 @@
instance.devices.reserve(sz);
for (uint32_t i = 0; i < sz; ++i) {
device_map.insert(std::make_pair(devices[i], i));
- instance.devices.emplace_back(VkJsonGetDevice(vkinstance, devices[i],
- instance_extensions.size(),
- instance_extensions.data()));
+ instance.devices.emplace_back(VkJsonGetDevice(devices[i]));
}
- PFN_vkEnumerateInstanceVersion vkpEnumerateInstanceVersion =
- reinterpret_cast<PFN_vkEnumerateInstanceVersion>(
- vkGetInstanceProcAddr(nullptr, "vkEnumerateInstanceVersion"));
- if (!vkpEnumerateInstanceVersion) {
- instance.api_version = VK_API_VERSION_1_0;
- } else {
- result = (*vkpEnumerateInstanceVersion)(&instance.api_version);
- if (result != VK_SUCCESS) {
- vkDestroyInstance(vkinstance, nullptr);
- return VkJsonInstance();
- }
+ result = vkEnumerateInstanceVersion(&instance.api_version);
+ if (result != VK_SUCCESS) {
+ vkDestroyInstance(vkinstance, nullptr);
+ return VkJsonInstance();
}
- PFN_vkEnumeratePhysicalDeviceGroups vkpEnumeratePhysicalDeviceGroups =
- reinterpret_cast<PFN_vkEnumeratePhysicalDeviceGroups>(
- vkGetInstanceProcAddr(vkinstance, "vkEnumeratePhysicalDeviceGroups"));
- if (vkpEnumeratePhysicalDeviceGroups) {
- count = 0;
- result = (*vkpEnumeratePhysicalDeviceGroups)(vkinstance, &count, nullptr);
- if (result != VK_SUCCESS) {
- vkDestroyInstance(vkinstance, nullptr);
- return VkJsonInstance();
- }
+ count = 0;
+ result = vkEnumeratePhysicalDeviceGroups(vkinstance, &count, nullptr);
+ if (result != VK_SUCCESS) {
+ vkDestroyInstance(vkinstance, nullptr);
+ return VkJsonInstance();
+ }
- VkJsonDeviceGroup device_group;
- std::vector<VkPhysicalDeviceGroupProperties> group_properties;
- group_properties.resize(count);
- result = (*vkpEnumeratePhysicalDeviceGroups)(vkinstance, &count,
- group_properties.data());
- if (result != VK_SUCCESS) {
- vkDestroyInstance(vkinstance, nullptr);
- return VkJsonInstance();
+ VkJsonDeviceGroup device_group;
+ std::vector<VkPhysicalDeviceGroupProperties> group_properties;
+ group_properties.resize(count);
+ result = vkEnumeratePhysicalDeviceGroups(vkinstance, &count,
+ group_properties.data());
+ if (result != VK_SUCCESS) {
+ vkDestroyInstance(vkinstance, nullptr);
+ return VkJsonInstance();
+ }
+ for (auto properties : group_properties) {
+ device_group.properties = properties;
+ for (uint32_t i = 0; i < properties.physicalDeviceCount; ++i) {
+ device_group.device_inds.push_back(
+ device_map[properties.physicalDevices[i]]);
}
- for (auto properties : group_properties) {
- device_group.properties = properties;
- for (uint32_t i = 0; i < properties.physicalDeviceCount; ++i) {
- device_group.device_inds.push_back(
- device_map[properties.physicalDevices[i]]);
- }
- instance.device_groups.push_back(device_group);
- }
+ instance.device_groups.push_back(device_group);
}
vkDestroyInstance(vkinstance, nullptr);