diff options
85 files changed, 4105 insertions, 570 deletions
diff --git a/cmds/idlcli/Android.bp b/cmds/idlcli/Android.bp index 402767a426..64bfdf9289 100644 --- a/cmds/idlcli/Android.bp +++ b/cmds/idlcli/Android.bp @@ -37,10 +37,16 @@ cc_library { 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 a8e595470d..b8744555e2 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 @@ inline std::istream &operator>>(std::istream &stream, uint8_t &out) { } // 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 ca5142dee9..6c30a9e2ca 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_2 = ::android::hardware::vibrator::V1_2; 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 0000000000..9afa300c2b --- /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 0000000000..bb7f9f284a --- /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 4721a5f9ae..97c057fa0c 100644 --- a/cmds/idlcli/vibrator/CommandCompose.cpp +++ b/cmds/idlcli/vibrator/CommandCompose.cpp @@ -28,10 +28,13 @@ using aidl::CompositeEffect; 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 @@ class CommandCompose : public Command { } 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 @@ class CommandCompose : public Command { 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 @@ class CommandCompose : public Command { } 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(); + + 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 ret; + 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 0000000000..460d39e64f --- /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 0000000000..edfcd9195a --- /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 0000000000..7658f22def --- /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 0000000000..d101681914 --- /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 4e7e493d6d..8212fc14a7 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 @@ namespace vibrator { 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 @@ class CommandOn : public Command { 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 @@ class CommandOn : public Command { 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 69c7e37744..c897686cbe 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::RINGTONE_15) == 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 @@ class CommandPerform : public Command { } 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 @@ class CommandPerform : public Command { 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 @@ class CommandPerform : public Command { }; 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 @@ class CommandPerform : public Command { 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 a956efc263..6cc66ecf6a 100644 --- a/cmds/installd/InstalldNativeService.cpp +++ b/cmds/installd/InstalldNativeService.cpp @@ -2244,7 +2244,7 @@ binder::Status InstalldNativeService::getAppCrates( #if CRATE_DEBUG LOG(WARNING) << "retVector.size() =" << retVector.size(); for (auto& item : retVector) { - CrateManager::dump(item); + CrateManager::dump(*item); } #endif @@ -2276,7 +2276,7 @@ binder::Status InstalldNativeService::getUserCrates( if (cratedFolder == nullptr) { return; } - retVector->push_back(std::move(crateMetadata)); + retVector.push_back(std::move(crateMetadata)); }; std::function<void(FTSENT*)> onHandingPackage = [&](FTSENT* packageDir) -> void { @@ -2288,7 +2288,7 @@ binder::Status InstalldNativeService::getUserCrates( #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 4ac70a4857..eeda6c5855 100644 --- a/cmds/installd/binder/android/os/IInstalld.aidl +++ b/cmds/installd/binder/android/os/IInstalld.aidl @@ -117,10 +117,11 @@ interface IInstalld { 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 dbfd61eb05..7c392348b7 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 @@ int32_t AInputEvent_getDeviceId(const AInputEvent* event); /** 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_getDownTime(const AInputEvent* key_event); */ 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_getHistoricalOrientation(const AInputEvent* motion_event, siz 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/InputWindow.h b/include/input/InputWindow.h index 856c54d89e..98518e0fe8 100644 --- a/include/input/InputWindow.h +++ b/include/input/InputWindow.h @@ -37,23 +37,23 @@ struct InputWindowInfo { 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 @@ struct InputWindowInfo { 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,6 +114,7 @@ struct InputWindowInfo { 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, LAST_SYSTEM_WINDOW = 2999, }; @@ -191,6 +199,7 @@ struct InputWindowInfo { static InputWindowInfo read(const Parcel& from); }; +std::string inputWindowFlagsToString(uint32_t flags); /* * Handle for a window that can receive input. diff --git a/include/powermanager/IPowerManager.h b/include/powermanager/IPowerManager.h deleted file mode 100644 index 964e318584..0000000000 --- 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 0000000000..44b8915875 --- /dev/null +++ b/include/powermanager/PowerHalController.h @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#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> + +using android::hardware::power::Boost; +using android::hardware::power::Mode; +using android::hardware::power::V1_0::Feature; +using android::hardware::power::V1_0::PowerHint; + +namespace android { + +// ------------------------------------------------------------------------------------------------- + +// Connects to underlying Power HAL handles. +class PowerHalConnector { +public: + PowerHalConnector() = default; + virtual ~PowerHalConnector() = default; + + virtual std::unique_ptr<PowerHalWrapper> connect(); + virtual void reset(); +}; + +// ------------------------------------------------------------------------------------------------- + +// Controller for Power HAL handle. +// This relies on PowerHalConnector to connect to the underlying Power HAL service and reconnects to +// it after each failed api call. This also ensures connecting to the service is thread-safe. +class PowerHalController : public PowerHalWrapper { +public: + PowerHalController() : PowerHalController(std::make_unique<PowerHalConnector>()) {} + explicit PowerHalController(std::unique_ptr<PowerHalConnector> connector) + : mHalConnector(std::move(connector)) {} + + void init(); + + PowerHalResult setBoost(Boost boost, int32_t durationMs) override; + PowerHalResult setMode(Mode mode, bool enabled) override; + +private: + std::mutex mConnectedHalMutex; + std::unique_ptr<PowerHalConnector> mHalConnector; + + // Shared pointers to keep global pointer and allow local copies to be used in different threads + std::shared_ptr<PowerHalWrapper> mConnectedHal GUARDED_BY(mConnectedHalMutex) = nullptr; + const std::shared_ptr<PowerHalWrapper> mDefaultHal = std::make_shared<EmptyPowerHalWrapper>(); + + std::shared_ptr<PowerHalWrapper> initHal(); + PowerHalResult processHalResult(PowerHalResult result, const char* functionName); +}; + +// ------------------------------------------------------------------------------------------------- + +}; // namespace android + +#endif // ANDROID_POWERHALCONTROLLER_H diff --git a/include/powermanager/PowerHalLoader.h b/include/powermanager/PowerHalLoader.h new file mode 100644 index 0000000000..487b95b298 --- /dev/null +++ b/include/powermanager/PowerHalLoader.h @@ -0,0 +1,52 @@ +/* + * 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> + +using IPowerV1_0 = android::hardware::power::V1_0::IPower; +using IPowerV1_1 = android::hardware::power::V1_1::IPower; +using IPowerAidl = android::hardware::power::IPower; + +namespace android { + +// Loads available Power HAL services. +class PowerHalLoader { +public: + static void unloadAll(); + static sp<IPowerAidl> loadAidl(); + static sp<IPowerV1_0> loadHidlV1_0(); + static sp<IPowerV1_1> loadHidlV1_1(); + +private: + static std::mutex gHalMutex; + static sp<IPowerAidl> gHalAidl GUARDED_BY(gHalMutex); + static sp<IPowerV1_0> gHalHidlV1_0 GUARDED_BY(gHalMutex); + static sp<IPowerV1_1> gHalHidlV1_1 GUARDED_BY(gHalMutex); + + static sp<IPowerV1_0> loadHidlV1_0Locked() EXCLUSIVE_LOCKS_REQUIRED(gHalMutex); + + PowerHalLoader() = default; +}; + +} // namespace android + +#endif // ANDROID_POWERHALLOADER_H diff --git a/include/powermanager/PowerHalWrapper.h b/include/powermanager/PowerHalWrapper.h new file mode 100644 index 0000000000..6d8a6eb0f6 --- /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> + +using android::hardware::power::Boost; +using android::hardware::power::Mode; +using android::hardware::power::V1_0::Feature; +using android::hardware::power::V1_0::PowerHint; +using IPowerV1_1 = android::hardware::power::V1_1::IPower; +using IPowerV1_0 = android::hardware::power::V1_0::IPower; +using IPowerAidl = android::hardware::power::IPower; + +namespace android { + +// State of Power HAL support for individual apis. +enum class PowerHalSupport { + UNKNOWN = 0, + ON = 1, + OFF = 2, +}; + +// State of the Power HAL api call result. +enum class PowerHalResult { + SUCCESSFUL = 0, + FAILED = 1, + UNSUPPORTED = 2, +}; + +// Wrapper for Power HAL handlers. +class PowerHalWrapper { +public: + virtual ~PowerHalWrapper() = default; + + virtual PowerHalResult setBoost(Boost boost, int32_t durationMs) = 0; + virtual PowerHalResult setMode(Mode mode, bool enabled) = 0; +}; + +// Empty Power HAL wrapper that ignores all api calls. +class EmptyPowerHalWrapper : public PowerHalWrapper { +public: + EmptyPowerHalWrapper() = default; + ~EmptyPowerHalWrapper() = default; + + PowerHalResult setBoost(Boost boost, int32_t durationMs) override; + PowerHalResult setMode(Mode mode, bool enabled) override; +}; + +// Wrapper for the HIDL Power HAL v1.0. +class HidlPowerHalWrapperV1_0 : public PowerHalWrapper { +public: + explicit HidlPowerHalWrapperV1_0(sp<IPowerV1_0> powerHal) : handleV1_0(std::move(powerHal)) {} + virtual ~HidlPowerHalWrapperV1_0() = default; + + PowerHalResult setBoost(Boost boost, int32_t durationMs) override; + PowerHalResult setMode(Mode mode, bool enabled) override; + +protected: + virtual PowerHalResult sendPowerHint(PowerHint hintId, uint32_t data); + +private: + sp<IPowerV1_0> handleV1_0; + PowerHalResult setInteractive(bool enabled); + PowerHalResult setFeature(Feature feature, bool enabled); +}; + +// Wrapper for the HIDL Power HAL v1.1. +class HidlPowerHalWrapperV1_1 : public HidlPowerHalWrapperV1_0 { +public: + HidlPowerHalWrapperV1_1(sp<IPowerV1_0> powerHalV1_0, sp<IPowerV1_1> powerHalV1_1) + : HidlPowerHalWrapperV1_0(powerHalV1_0), handleV1_1(std::move(powerHalV1_1)) {} + ~HidlPowerHalWrapperV1_1() = default; + +protected: + virtual PowerHalResult sendPowerHint(PowerHint hintId, uint32_t data) override; + +private: + sp<IPowerV1_1> handleV1_1; +}; + +// Wrapper for the AIDL Power HAL. +class AidlPowerHalWrapper : public PowerHalWrapper { +public: + explicit AidlPowerHalWrapper(sp<IPowerAidl> powerHal) : handle(std::move(powerHal)) {} + ~AidlPowerHalWrapper() = default; + + PowerHalResult setBoost(Boost boost, int32_t durationMs) override; + PowerHalResult setMode(Mode mode, bool enabled) override; + +private: + // Control access to the boost and mode supported arrays. + std::mutex mBoostMutex; + std::mutex mModeMutex; + sp<IPowerAidl> handle; + // Android framework only sends boost upto DISPLAY_UPDATE_IMMINENT. + // Need to increase the array size if more boost supported. + std::array<std::atomic<PowerHalSupport>, static_cast<int32_t>(Boost::DISPLAY_UPDATE_IMMINENT)+1> + boostSupportedArray GUARDED_BY(mBoostMutex) = {PowerHalSupport::UNKNOWN}; + // Android framework only sends mode upto DISPLAY_INACTIVE. + // Need to increase the array if more mode supported. + std::array<std::atomic<PowerHalSupport>, static_cast<int32_t>(Mode::DISPLAY_INACTIVE)+1> + modeSupportedArray GUARDED_BY(mModeMutex) = {PowerHalSupport::UNKNOWN}; +}; + +}; // namespace android + +#endif // ANDROID_POWERHALWRAPPER_H diff --git a/libs/binder/fuzzer/binder.cpp b/libs/binder/fuzzer/binder.cpp index 52c730cfb8..8c0495cf54 100644 --- a/libs/binder/fuzzer/binder.cpp +++ b/libs/binder/fuzzer/binder.cpp @@ -135,6 +135,7 @@ std::vector<ParcelRead<::android::Parcel>> BINDER_PARCEL_READ_FUNCTIONS { 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 @@ std::vector<ParcelRead<::android::Parcel>> BINDER_PARCEL_READ_FUNCTIONS { 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 @@ std::vector<ParcelRead<::android::Parcel>> BINDER_PARCEL_READ_FUNCTIONS { // 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 @@ std::vector<ParcelRead<::android::Parcel>> BINDER_PARCEL_READ_FUNCTIONS { // 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 @@ std::vector<ParcelRead<::android::Parcel>> BINDER_PARCEL_READ_FUNCTIONS { // 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/graphicsenv/GraphicsEnv.cpp b/libs/graphicsenv/GraphicsEnv.cpp index 4809c1f0d8..e49fb0859e 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> @@ -67,7 +66,7 @@ static constexpr const char* kNativeLibrariesSystemConfigPath[] = static std::string vndkVersionStr() { #ifdef __BIONIC__ - return android::base::GetProperty("ro.vndk.version", ""); + return base::GetProperty("ro.vndk.version", ""); #endif return ""; } @@ -338,10 +337,8 @@ void* GraphicsEnv::loadLibrary(std::string name) { } 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, @@ -394,7 +391,8 @@ bool GraphicsEnv::checkAngleRules(void* so) { 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; } diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp index 2a27a9a278..6c9fd07449 100644 --- a/libs/gui/ISurfaceComposer.cpp +++ b/libs/gui/ISurfaceComposer.cpp @@ -371,10 +371,8 @@ public: 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) { @@ -1094,22 +1092,22 @@ public: 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; @@ -1443,10 +1441,8 @@ status_t BnSurfaceComposer::onTransact( 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); @@ -1990,15 +1986,15 @@ status_t BnSurfaceComposer::onTransact( } 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/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index a52f298e77..e864327c0c 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -1846,8 +1846,8 @@ status_t SurfaceComposerClient::setDisplayBrightness(const sp<IBinder>& displayT 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/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h index 0d33b3f695..21ad2b274d 100644 --- a/libs/gui/include/gui/ISurfaceComposer.h +++ b/libs/gui/include/gui/ISurfaceComposer.h @@ -488,14 +488,14 @@ public: 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 @@ -583,7 +583,7 @@ public: 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/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index 531aed7ac4..fe1094c3ed 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -217,14 +217,14 @@ public: 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/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index a1d12a5ca6..3b809452b9 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -849,7 +849,7 @@ public: 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 8efaf3d90b..7037680935 100644 --- a/libs/input/Android.bp +++ b/libs/input/Android.bp @@ -34,6 +34,9 @@ cc_library { clang: true, + header_libs: ["jni_headers"], + export_header_lib_headers: ["jni_headers"], + shared_libs: [ "libbase", "liblog", diff --git a/libs/input/InputWindow.cpp b/libs/input/InputWindow.cpp index b27b050d28..d7f8ae5d12 100644 --- a/libs/input/InputWindow.cpp +++ b/libs/input/InputWindow.cpp @@ -17,9 +17,10 @@ #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> @@ -28,6 +29,118 @@ 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); @@ -43,7 +156,8 @@ bool InputWindowInfo::frameContainsPoint(int32_t x, int32_t y) const { } bool InputWindowInfo::isTrustedOverlay() const { - return layoutParamsType == TYPE_INPUT_METHOD || layoutParamsType == TYPE_INPUT_METHOD_DIALOG || + return layoutParamsType == TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY || + 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 || diff --git a/libs/math/Android.bp b/libs/math/Android.bp index 693bace1f4..8e903e3d85 100644 --- a/libs/math/Android.bp +++ b/libs/math/Android.bp @@ -17,6 +17,11 @@ cc_library_static { host_supported: true, vendor_available: true, export_include_dirs: ["include"], + target: { + windows: { + enabled: true, + } + } } subdirs = ["tests"] diff --git a/libs/renderengine/gl/GLESRenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp index 92e7e715ea..d102696382 100644 --- a/libs/renderengine/gl/GLESRenderEngine.cpp +++ b/libs/renderengine/gl/GLESRenderEngine.cpp @@ -982,7 +982,7 @@ EGLImageKHR GLESRenderEngine::createFramebufferImageIfNeeded(ANativeWindowBuffer 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 @@ status_t GLESRenderEngine::drawLayers(const DisplaySettings& display, 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 @@ status_t GLESRenderEngine::drawLayers(const DisplaySettings& display, 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 42b8537b94..9ab5ee6dba 100644 --- a/libs/renderengine/gl/GLESRenderEngine.h +++ b/libs/renderengine/gl/GLESRenderEngine.h @@ -73,7 +73,7 @@ public: 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 e06e1287c1..5349a30121 100644 --- a/libs/renderengine/include/renderengine/RenderEngine.h +++ b/libs/renderengine/include/renderengine/RenderEngine.h @@ -163,7 +163,7 @@ public: // 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: diff --git a/libs/renderengine/include/renderengine/mock/RenderEngine.h b/libs/renderengine/include/renderengine/mock/RenderEngine.h index df0f17a6d5..d0343ba5a4 100644 --- a/libs/renderengine/include/renderengine/mock/RenderEngine.h +++ b/libs/renderengine/include/renderengine/mock/RenderEngine.h @@ -59,7 +59,8 @@ public: 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/RenderEngineTest.cpp b/libs/renderengine/tests/RenderEngineTest.cpp index 16a8a0decb..31f0966598 100644 --- a/libs/renderengine/tests/RenderEngineTest.cpp +++ b/libs/renderengine/tests/RenderEngineTest.cpp @@ -252,8 +252,8 @@ struct RenderEngineTest : public ::testing::Test { 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 +1004,7 @@ TEST_F(RenderEngineTest, drawLayers_nullOutputFence) { 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 +1022,7 @@ TEST_F(RenderEngineTest, drawLayers_doesNotCacheFramebuffer) { 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 +1412,9 @@ TEST_F(RenderEngineTest, cleanupPostRender_cleansUpOnce) { 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/ui/Android.bp b/libs/ui/Android.bp index 1ee8c7105c..bb7889510d 100644 --- a/libs/ui/Android.bp +++ b/libs/ui/Android.bp @@ -12,6 +12,64 @@ // 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", + ], + 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 +93,9 @@ cc_library_shared { }, srcs: [ - "ColorSpace.cpp", "DebugUtils.cpp", + "DeviceProductInfo.cpp", + "DisplayInfo.cpp", "Fence.cpp", "FenceTime.cpp", "FrameStats.cpp", @@ -65,8 +124,11 @@ cc_library_shared { "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 +162,10 @@ cc_library_shared { "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 0000000000..7bced9b76a --- /dev/null +++ b/libs/ui/DeviceProductInfo.cpp @@ -0,0 +1,55 @@ +/* + * 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 <ui/FlattenableHelpers.h> + +#define RETURN_IF_ERROR(op) \ + if (const status_t status = (op); status != OK) return status; + +namespace android { + +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; +} + +} // namespace android diff --git a/libs/ui/DisplayInfo.cpp b/libs/ui/DisplayInfo.cpp new file mode 100644 index 0000000000..73a78af186 --- /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 af00342c0c..0bc1e5c4f3 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 @@ using PnpId = std::array<char, 4>; // 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,27 @@ struct DeviceProductInfo { }; // 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); }; } // namespace android diff --git a/libs/ui/include/ui/DisplayInfo.h b/libs/ui/include/ui/DisplayInfo.h index 897060c2ed..03e0a3886e 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 0000000000..8e316d8ae0 --- /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 index 241ec106c0..241ec106c0 100644 --- a/libs/ui/include/ui/ColorSpace.h +++ b/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 ddf70d5bdf..7d2a6d307e 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 b53342cb79..28ef77a496 100644 --- a/libs/ui/tests/Android.bp +++ b/libs/ui/tests/Android.bp @@ -29,6 +29,13 @@ cc_test { } 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 0000000000..db32bc7596 --- /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/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp index d664e4db97..391a4101ae 100644 --- a/opengl/libs/EGL/Loader.cpp +++ b/opengl/libs/EGL/Loader.cpp @@ -276,7 +276,7 @@ void* Loader::open(egl_connection_t* cnx) // 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, @@ -557,12 +557,8 @@ Loader::driver_t* Loader::attempt_to_load_angle(egl_connection_t* cnx) { } 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 { diff --git a/services/gpuservice/bpfprogs/Android.bp b/services/gpuservice/bpfprogs/Android.bp new file mode 100644 index 0000000000..b8758146cc --- /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 0000000000..c75213bbd4 --- /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 0000000000..b2230b6c01 --- /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 0000000000..1d4b524a7d --- /dev/null +++ b/services/gpuservice/gpumem/GpuMem.cpp @@ -0,0 +1,123 @@ +/* + * 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 <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; + } + + // Attach the program to the tracepoint, and the tracepoint is automatically enabled here. + if (bpf_attach_tracepoint(fd, kGpuMemTraceGroup, kGpuMemTotalTracepoint) < 0) { + ALOGE("Failed to attach bpf program to %s/%s tracepoint", kGpuMemTraceGroup, + kGpuMemTotalTracepoint); + return; + } + + // 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); +} + +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 (!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 0000000000..6d0322ad1f --- /dev/null +++ b/services/gpuservice/gpumem/include/gpumem/GpuMem.h @@ -0,0 +1,56 @@ +/* + * 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); + +private: + // Friend class for testing. + friend class TestableGpuMem; + + // set gpu memory total map + void setGpuMemTotalMap(bpf::BpfMap<uint64_t, uint64_t>& map); + + // 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"; +}; + +} // namespace android diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index baf2f2b917..dda04f24a7 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -328,6 +328,18 @@ static std::unique_ptr<DispatchEntry> createDispatchEntry(const InputTarget& inp return dispatchEntry; } +static void addGestureMonitors(const std::vector<Monitor>& monitors, + std::vector<TouchedMonitor>& outTouchedMonitors, float xOffset = 0, + float yOffset = 0) { + if (monitors.empty()) { + return; + } + outTouchedMonitors.reserve(monitors.size() + outTouchedMonitors.size()); + for (const Monitor& monitor : monitors) { + outTouchedMonitors.emplace_back(monitor, xOffset, yOffset); + } +} + static std::array<uint8_t, 128> getRandomKey() { std::array<uint8_t, 128> key; if (RAND_bytes(key.data(), key.size()) != 1) { @@ -664,7 +676,7 @@ bool InputDispatcher::enqueueInboundEventLocked(EventEntry* entry) { int32_t y = int32_t(motionEntry->pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y)); sp<InputWindowHandle> touchedWindowHandle = - findTouchedWindowAtLocked(displayId, x, y); + findTouchedWindowAtLocked(displayId, x, y, nullptr); if (touchedWindowHandle != nullptr && touchedWindowHandle->getApplicationToken() != mInputTargetWaitApplicationToken) { @@ -697,8 +709,13 @@ void InputDispatcher::addRecentEventLocked(EventEntry* entry) { } sp<InputWindowHandle> InputDispatcher::findTouchedWindowAtLocked(int32_t displayId, int32_t x, - int32_t y, bool addOutsideTargets, + int32_t y, TouchState* touchState, + bool addOutsideTargets, bool addPortalWindows) { + if ((addPortalWindows || addOutsideTargets) && touchState == nullptr) { + LOG_ALWAYS_FATAL( + "Must provide a valid touch state if adding portal windows or outside targets"); + } // Traverse windows from front to back to find touched window. const std::vector<sp<InputWindowHandle>> windowHandles = getWindowHandlesLocked(displayId); for (const sp<InputWindowHandle>& windowHandle : windowHandles) { @@ -717,9 +734,9 @@ sp<InputWindowHandle> InputDispatcher::findTouchedWindowAtLocked(int32_t display portalToDisplayId != displayId) { if (addPortalWindows) { // For the monitoring channels of the display. - mTempTouchState.addPortalWindow(windowHandle); + touchState->addPortalWindow(windowHandle); } - return findTouchedWindowAtLocked(portalToDisplayId, x, y, + return findTouchedWindowAtLocked(portalToDisplayId, x, y, touchState, addOutsideTargets, addPortalWindows); } // Found window. @@ -728,9 +745,9 @@ sp<InputWindowHandle> InputDispatcher::findTouchedWindowAtLocked(int32_t display } if (addOutsideTargets && (flags & InputWindowInfo::FLAG_WATCH_OUTSIDE_TOUCH)) { - mTempTouchState.addOrUpdateWindow(windowHandle, - InputTarget::FLAG_DISPATCH_AS_OUTSIDE, - BitSet32(0)); + touchState->addOrUpdateWindow(windowHandle, + InputTarget::FLAG_DISPATCH_AS_OUTSIDE, + BitSet32(0)); } } } @@ -739,7 +756,7 @@ sp<InputWindowHandle> InputDispatcher::findTouchedWindowAtLocked(int32_t display } std::vector<TouchedMonitor> InputDispatcher::findTouchedGestureMonitorsLocked( - int32_t displayId, const std::vector<sp<InputWindowHandle>>& portalWindows) { + int32_t displayId, const std::vector<sp<InputWindowHandle>>& portalWindows) const { std::vector<TouchedMonitor> touchedMonitors; std::vector<Monitor> monitors = getValueByKey(mGestureMonitorsByDisplay, displayId); @@ -753,18 +770,6 @@ std::vector<TouchedMonitor> InputDispatcher::findTouchedGestureMonitorsLocked( return touchedMonitors; } -void InputDispatcher::addGestureMonitors(const std::vector<Monitor>& monitors, - std::vector<TouchedMonitor>& outTouchedMonitors, - float xOffset, float yOffset) { - if (monitors.empty()) { - return; - } - outTouchedMonitors.reserve(monitors.size() + outTouchedMonitors.size()); - for (const Monitor& monitor : monitors) { - outTouchedMonitors.emplace_back(monitor, xOffset, yOffset); - } -} - void InputDispatcher::dropInboundEventLocked(const EventEntry& entry, DropReason dropReason) { const char* reason; switch (dropReason) { @@ -1167,9 +1172,10 @@ bool InputDispatcher::dispatchMotionLocked(nsecs_t currentTime, MotionEntry* ent addGlobalMonitoringTargetsLocked(inputTargets, getTargetDisplayId(*entry)); if (isPointerEvent) { - ssize_t stateIndex = mTouchStatesByDisplay.indexOfKey(entry->displayId); - if (stateIndex >= 0) { - const TouchState& state = mTouchStatesByDisplay.valueAt(stateIndex); + std::unordered_map<int32_t, TouchState>::iterator it = + mTouchStatesByDisplay.find(entry->displayId); + if (it != mTouchStatesByDisplay.end()) { + const TouchState& state = it->second; if (!state.portalWindows.empty()) { // The event has gone through these portal windows, so we add monitoring targets of // the corresponding displays as well. @@ -1265,10 +1271,8 @@ int32_t InputDispatcher::handleTargetsNotReadyLocked( } } else { if (mInputTargetWaitCause != INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY) { - if (DEBUG_FOCUS) { - ALOGD("Waiting for application to become ready for input: %s. Reason: %s", - getApplicationWindowLabel(applicationHandle, windowHandle).c_str(), reason); - } + ALOGI("Waiting for application to become ready for input: %s. Reason: %s", + getApplicationWindowLabel(applicationHandle, windowHandle).c_str(), reason); nsecs_t timeout; if (windowHandle != nullptr) { timeout = windowHandle->getDispatchingTimeout(DEFAULT_INPUT_DISPATCHING_TIMEOUT); @@ -1316,8 +1320,8 @@ int32_t InputDispatcher::handleTargetsNotReadyLocked( } void InputDispatcher::removeWindowByTokenLocked(const sp<IBinder>& token) { - for (size_t d = 0; d < mTouchStatesByDisplay.size(); d++) { - TouchState& state = mTouchStatesByDisplay.editValueAt(d); + for (std::pair<const int32_t, TouchState>& pair : mTouchStatesByDisplay) { + TouchState& state = pair.second; state.removeWindowByToken(token); } } @@ -1480,20 +1484,22 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, InjectionPermission injectionPermission = INJECTION_PERMISSION_UNKNOWN; sp<InputWindowHandle> newHoverWindowHandle; - // Copy current touch state into mTempTouchState. - // This state is always reset at the end of this function, so if we don't find state - // for the specified display then our initial state will be empty. + // Copy current touch state into tempTouchState. + // This state will be used to update mTouchStatesByDisplay at the end of this function. + // If no state for the specified display exists, then our initial state will be empty. const TouchState* oldState = nullptr; - ssize_t oldStateIndex = mTouchStatesByDisplay.indexOfKey(displayId); - if (oldStateIndex >= 0) { - oldState = &mTouchStatesByDisplay.valueAt(oldStateIndex); - mTempTouchState.copyFrom(*oldState); - } - - bool isSplit = mTempTouchState.split; - bool switchedDevice = mTempTouchState.deviceId >= 0 && mTempTouchState.displayId >= 0 && - (mTempTouchState.deviceId != entry.deviceId || mTempTouchState.source != entry.source || - mTempTouchState.displayId != displayId); + TouchState tempTouchState; + std::unordered_map<int32_t, TouchState>::iterator oldStateIt = + mTouchStatesByDisplay.find(displayId); + if (oldStateIt != mTouchStatesByDisplay.end()) { + oldState = &(oldStateIt->second); + tempTouchState.copyFrom(*oldState); + } + + bool isSplit = tempTouchState.split; + bool switchedDevice = tempTouchState.deviceId >= 0 && tempTouchState.displayId >= 0 && + (tempTouchState.deviceId != entry.deviceId || tempTouchState.source != entry.source || + tempTouchState.displayId != displayId); bool isHoverAction = (maskedAction == AMOTION_EVENT_ACTION_HOVER_MOVE || maskedAction == AMOTION_EVENT_ACTION_HOVER_ENTER || maskedAction == AMOTION_EVENT_ACTION_HOVER_EXIT); @@ -1503,30 +1509,26 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, bool wrongDevice = false; if (newGesture) { bool down = maskedAction == AMOTION_EVENT_ACTION_DOWN; - if (switchedDevice && mTempTouchState.down && !down && !isHoverAction) { - if (DEBUG_FOCUS) { - ALOGD("Dropping event because a pointer for a different device is already down " - "in display %" PRId32, - displayId); - } + if (switchedDevice && tempTouchState.down && !down && !isHoverAction) { + ALOGI("Dropping event because a pointer for a different device is already down " + "in display %" PRId32, + displayId); // TODO: test multiple simultaneous input streams. injectionResult = INPUT_EVENT_INJECTION_FAILED; switchedDevice = false; wrongDevice = true; goto Failed; } - mTempTouchState.reset(); - mTempTouchState.down = down; - mTempTouchState.deviceId = entry.deviceId; - mTempTouchState.source = entry.source; - mTempTouchState.displayId = displayId; + tempTouchState.reset(); + tempTouchState.down = down; + tempTouchState.deviceId = entry.deviceId; + tempTouchState.source = entry.source; + tempTouchState.displayId = displayId; isSplit = false; } else if (switchedDevice && maskedAction == AMOTION_EVENT_ACTION_MOVE) { - if (DEBUG_FOCUS) { - ALOGI("Dropping move event because a pointer for a different device is already active " - "in display %" PRId32, - displayId); - } + ALOGI("Dropping move event because a pointer for a different device is already active " + "in display %" PRId32, + displayId); // TODO: test multiple simultaneous input streams. injectionResult = INPUT_EVENT_INJECTION_PERMISSION_DENIED; switchedDevice = false; @@ -1550,11 +1552,11 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, } bool isDown = maskedAction == AMOTION_EVENT_ACTION_DOWN; sp<InputWindowHandle> newTouchedWindowHandle = - findTouchedWindowAtLocked(displayId, x, y, isDown /*addOutsideTargets*/, - true /*addPortalWindows*/); + findTouchedWindowAtLocked(displayId, x, y, &tempTouchState, + isDown /*addOutsideTargets*/, true /*addPortalWindows*/); std::vector<TouchedMonitor> newGestureMonitors = isDown - ? findTouchedGestureMonitorsLocked(displayId, mTempTouchState.portalWindows) + ? findTouchedGestureMonitorsLocked(displayId, tempTouchState.portalWindows) : std::vector<TouchedMonitor>{}; // Figure out whether splitting will be allowed for this window. @@ -1571,7 +1573,7 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, // Handle the case where we did not find a window. if (newTouchedWindowHandle == nullptr) { // Try to assign the pointer to the first foreground window we find, if there is one. - newTouchedWindowHandle = mTempTouchState.getFirstForegroundWindowHandle(); + newTouchedWindowHandle = tempTouchState.getFirstForegroundWindowHandle(); } if (newTouchedWindowHandle == nullptr && newGestureMonitors.empty()) { @@ -1607,15 +1609,15 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, uint32_t pointerId = entry.pointerProperties[pointerIndex].id; pointerIds.markBit(pointerId); } - mTempTouchState.addOrUpdateWindow(newTouchedWindowHandle, targetFlags, pointerIds); + tempTouchState.addOrUpdateWindow(newTouchedWindowHandle, targetFlags, pointerIds); } - mTempTouchState.addGestureMonitors(newGestureMonitors); + tempTouchState.addGestureMonitors(newGestureMonitors); } else { /* Case 2: Pointer move, up, cancel or non-splittable pointer down. */ // If the pointer is not currently down, then ignore the event. - if (!mTempTouchState.down) { + if (!tempTouchState.down) { if (DEBUG_FOCUS) { ALOGD("Dropping event because the pointer is not down or we previously " "dropped the pointer down event in display %" PRId32, @@ -1627,14 +1629,14 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, // Check whether touches should slip outside of the current foreground window. if (maskedAction == AMOTION_EVENT_ACTION_MOVE && entry.pointerCount == 1 && - mTempTouchState.isSlippery()) { + tempTouchState.isSlippery()) { int32_t x = int32_t(entry.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X)); int32_t y = int32_t(entry.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y)); sp<InputWindowHandle> oldTouchedWindowHandle = - mTempTouchState.getFirstForegroundWindowHandle(); + tempTouchState.getFirstForegroundWindowHandle(); sp<InputWindowHandle> newTouchedWindowHandle = - findTouchedWindowAtLocked(displayId, x, y); + findTouchedWindowAtLocked(displayId, x, y, &tempTouchState); if (oldTouchedWindowHandle != newTouchedWindowHandle && oldTouchedWindowHandle != nullptr && newTouchedWindowHandle != nullptr) { if (DEBUG_FOCUS) { @@ -1643,9 +1645,9 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, newTouchedWindowHandle->getName().c_str(), displayId); } // Make a slippery exit from the old window. - mTempTouchState.addOrUpdateWindow(oldTouchedWindowHandle, - InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT, - BitSet32(0)); + tempTouchState.addOrUpdateWindow(oldTouchedWindowHandle, + InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT, + BitSet32(0)); // Make a slippery entrance into the new window. if (newTouchedWindowHandle->getInfo()->supportsSplitTouch()) { @@ -1665,7 +1667,7 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, if (isSplit) { pointerIds.markBit(entry.pointerProperties[0].id); } - mTempTouchState.addOrUpdateWindow(newTouchedWindowHandle, targetFlags, pointerIds); + tempTouchState.addOrUpdateWindow(newTouchedWindowHandle, targetFlags, pointerIds); } } } @@ -1677,9 +1679,8 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, ALOGD("Sending hover exit event to window %s.", mLastHoverWindowHandle->getName().c_str()); #endif - mTempTouchState.addOrUpdateWindow(mLastHoverWindowHandle, - InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT, - BitSet32(0)); + tempTouchState.addOrUpdateWindow(mLastHoverWindowHandle, + InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT, BitSet32(0)); } // Let the new window know that the hover sequence is starting. @@ -1688,9 +1689,9 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, ALOGD("Sending hover enter event to window %s.", newHoverWindowHandle->getName().c_str()); #endif - mTempTouchState.addOrUpdateWindow(newHoverWindowHandle, - InputTarget::FLAG_DISPATCH_AS_HOVER_ENTER, - BitSet32(0)); + tempTouchState.addOrUpdateWindow(newHoverWindowHandle, + InputTarget::FLAG_DISPATCH_AS_HOVER_ENTER, + BitSet32(0)); } } @@ -1698,7 +1699,7 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, // is at least one touched foreground window. { bool haveForegroundWindow = false; - for (const TouchedWindow& touchedWindow : mTempTouchState.windows) { + for (const TouchedWindow& touchedWindow : tempTouchState.windows) { if (touchedWindow.targetFlags & InputTarget::FLAG_FOREGROUND) { haveForegroundWindow = true; if (!checkInjectionPermission(touchedWindow.windowHandle, entry.injectionState)) { @@ -1708,13 +1709,11 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, } } } - bool hasGestureMonitor = !mTempTouchState.gestureMonitors.empty(); + bool hasGestureMonitor = !tempTouchState.gestureMonitors.empty(); if (!haveForegroundWindow && !hasGestureMonitor) { - if (DEBUG_FOCUS) { - ALOGD("Dropping event because there is no touched foreground window in display " - "%" PRId32 " or gesture monitor to receive it.", - displayId); - } + ALOGI("Dropping event because there is no touched foreground window in display " + "%" PRId32 " or gesture monitor to receive it.", + displayId); injectionResult = INPUT_EVENT_INJECTION_FAILED; goto Failed; } @@ -1727,16 +1726,16 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, // set the policy flag that we will not reveal coordinate information to this window. if (maskedAction == AMOTION_EVENT_ACTION_DOWN) { sp<InputWindowHandle> foregroundWindowHandle = - mTempTouchState.getFirstForegroundWindowHandle(); + tempTouchState.getFirstForegroundWindowHandle(); if (foregroundWindowHandle) { const int32_t foregroundWindowUid = foregroundWindowHandle->getInfo()->ownerUid; - for (const TouchedWindow& touchedWindow : mTempTouchState.windows) { + for (const TouchedWindow& touchedWindow : tempTouchState.windows) { if (touchedWindow.targetFlags & InputTarget::FLAG_DISPATCH_AS_OUTSIDE) { sp<InputWindowHandle> inputWindowHandle = touchedWindow.windowHandle; if (inputWindowHandle->getInfo()->ownerUid != foregroundWindowUid) { - mTempTouchState.addOrUpdateWindow(inputWindowHandle, - InputTarget::FLAG_ZERO_COORDS, - BitSet32(0)); + tempTouchState.addOrUpdateWindow(inputWindowHandle, + InputTarget::FLAG_ZERO_COORDS, + BitSet32(0)); } } } @@ -1744,7 +1743,7 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, } // Ensure all touched foreground windows are ready for new input. - for (const TouchedWindow& touchedWindow : mTempTouchState.windows) { + for (const TouchedWindow& touchedWindow : tempTouchState.windows) { if (touchedWindow.targetFlags & InputTarget::FLAG_FOREGROUND) { // Check whether the window is ready for more input. std::string reason = @@ -1767,7 +1766,7 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, // to View.onGenericMotionEvent to enable wallpapers to handle these events. if (maskedAction == AMOTION_EVENT_ACTION_DOWN) { sp<InputWindowHandle> foregroundWindowHandle = - mTempTouchState.getFirstForegroundWindowHandle(); + tempTouchState.getFirstForegroundWindowHandle(); if (foregroundWindowHandle && foregroundWindowHandle->getInfo()->hasWallpaper) { const std::vector<sp<InputWindowHandle>> windowHandles = getWindowHandlesLocked(displayId); @@ -1775,7 +1774,7 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, const InputWindowInfo* info = windowHandle->getInfo(); if (info->displayId == displayId && windowHandle->getInfo()->layoutParamsType == InputWindowInfo::TYPE_WALLPAPER) { - mTempTouchState + tempTouchState .addOrUpdateWindow(windowHandle, InputTarget::FLAG_WINDOW_IS_OBSCURED | InputTarget:: @@ -1790,19 +1789,19 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, // Success! Output targets. injectionResult = INPUT_EVENT_INJECTION_SUCCEEDED; - for (const TouchedWindow& touchedWindow : mTempTouchState.windows) { + for (const TouchedWindow& touchedWindow : tempTouchState.windows) { addWindowTargetLocked(touchedWindow.windowHandle, touchedWindow.targetFlags, touchedWindow.pointerIds, inputTargets); } - for (const TouchedMonitor& touchedMonitor : mTempTouchState.gestureMonitors) { + for (const TouchedMonitor& touchedMonitor : tempTouchState.gestureMonitors) { addMonitoringTargetLocked(touchedMonitor.monitor, touchedMonitor.xOffset, touchedMonitor.yOffset, inputTargets); } // Drop the outside or hover touch windows since we will not care about them // in the next iteration. - mTempTouchState.filterNonAsIsTouchWindows(); + tempTouchState.filterNonAsIsTouchWindows(); Failed: // Check injection permission once and for all. @@ -1833,17 +1832,17 @@ Failed: } *outConflictingPointerActions = true; } - mTempTouchState.reset(); + tempTouchState.reset(); if (maskedAction == AMOTION_EVENT_ACTION_HOVER_ENTER || maskedAction == AMOTION_EVENT_ACTION_HOVER_MOVE) { - mTempTouchState.deviceId = entry.deviceId; - mTempTouchState.source = entry.source; - mTempTouchState.displayId = displayId; + tempTouchState.deviceId = entry.deviceId; + tempTouchState.source = entry.source; + tempTouchState.displayId = displayId; } } else if (maskedAction == AMOTION_EVENT_ACTION_UP || maskedAction == AMOTION_EVENT_ACTION_CANCEL) { // All pointers up or canceled. - mTempTouchState.reset(); + tempTouchState.reset(); } else if (maskedAction == AMOTION_EVENT_ACTION_DOWN) { // First pointer went down. if (oldState && oldState->down) { @@ -1858,12 +1857,12 @@ Failed: int32_t pointerIndex = getMotionEventActionPointerIndex(action); uint32_t pointerId = entry.pointerProperties[pointerIndex].id; - for (size_t i = 0; i < mTempTouchState.windows.size();) { - TouchedWindow& touchedWindow = mTempTouchState.windows[i]; + for (size_t i = 0; i < tempTouchState.windows.size();) { + TouchedWindow& touchedWindow = tempTouchState.windows[i]; if (touchedWindow.targetFlags & InputTarget::FLAG_SPLIT) { touchedWindow.pointerIds.clearBit(pointerId); if (touchedWindow.pointerIds.isEmpty()) { - mTempTouchState.windows.erase(mTempTouchState.windows.begin() + i); + tempTouchState.windows.erase(tempTouchState.windows.begin() + i); continue; } } @@ -1875,14 +1874,10 @@ Failed: // Save changes unless the action was scroll in which case the temporary touch // state was only valid for this one action. if (maskedAction != AMOTION_EVENT_ACTION_SCROLL) { - if (mTempTouchState.displayId >= 0) { - if (oldStateIndex >= 0) { - mTouchStatesByDisplay.editValueAt(oldStateIndex).copyFrom(mTempTouchState); - } else { - mTouchStatesByDisplay.add(displayId, mTempTouchState); - } - } else if (oldStateIndex >= 0) { - mTouchStatesByDisplay.removeItemsAt(oldStateIndex); + if (tempTouchState.displayId >= 0) { + mTouchStatesByDisplay[displayId] = tempTouchState; + } else { + mTouchStatesByDisplay.erase(displayId); } } @@ -1896,8 +1891,6 @@ Failed: } Unresponsive: - // Reset temporary touch state to ensure we release unnecessary references to input channels. - mTempTouchState.reset(); nsecs_t timeSpentWaitingForApplication = getTimeSpentWaitingForApplicationLocked(currentTime); updateDispatchStatistics(currentTime, entry, injectionResult, timeSpentWaitingForApplication); @@ -2027,7 +2020,7 @@ bool InputDispatcher::isWindowObscuredAtPointLocked(const sp<InputWindowHandle>& 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; } @@ -2043,7 +2036,6 @@ bool InputDispatcher::isWindowObscuredLocked(const sp<InputWindowHandle>& window if (windowHandle == otherHandle) { break; // All future windows are below us. Exit early. } - const InputWindowInfo* otherInfo = otherHandle->getInfo(); if (canBeObscuredBy(windowHandle, otherHandle) && otherInfo->overlaps(windowInfo)) { @@ -3053,7 +3045,7 @@ void InputDispatcher::accelerateMetaShortcuts(const int32_t deviceId, const int3 if (newKeyCode != AKEYCODE_UNKNOWN) { std::scoped_lock _l(mLock); struct KeyReplacement replacement = {keyCode, deviceId}; - mReplacedKeys.add(replacement, newKeyCode); + mReplacedKeys[replacement] = newKeyCode; keyCode = newKeyCode; metaState &= ~(AMETA_META_ON | AMETA_META_LEFT_ON | AMETA_META_RIGHT_ON); } @@ -3063,10 +3055,10 @@ void InputDispatcher::accelerateMetaShortcuts(const int32_t deviceId, const int3 // even if the modifier was released between the down and the up events. std::scoped_lock _l(mLock); struct KeyReplacement replacement = {keyCode, deviceId}; - ssize_t index = mReplacedKeys.indexOfKey(replacement); - if (index >= 0) { - keyCode = mReplacedKeys.valueAt(index); - mReplacedKeys.removeItemsAt(index); + auto replacementIt = mReplacedKeys.find(replacement); + if (replacementIt != mReplacedKeys.end()) { + keyCode = replacementIt->second; + mReplacedKeys.erase(replacementIt); metaState &= ~(AMETA_META_ON | AMETA_META_LEFT_ON | AMETA_META_RIGHT_ON); } } @@ -3748,9 +3740,10 @@ void InputDispatcher::setInputWindowsLocked( } } - ssize_t stateIndex = mTouchStatesByDisplay.indexOfKey(displayId); - if (stateIndex >= 0) { - TouchState& state = mTouchStatesByDisplay.editValueAt(stateIndex); + std::unordered_map<int32_t, TouchState>::iterator stateIt = + mTouchStatesByDisplay.find(displayId); + if (stateIt != mTouchStatesByDisplay.end()) { + TouchState& state = stateIt->second; for (size_t i = 0; i < state.windows.size();) { TouchedWindow& touchedWindow = state.windows[i]; if (!hasWindowHandleLocked(touchedWindow.windowHandle)) { @@ -3965,8 +3958,8 @@ bool InputDispatcher::transferTouchFocus(const sp<IBinder>& fromToken, const sp< } bool found = false; - for (size_t d = 0; d < mTouchStatesByDisplay.size(); d++) { - TouchState& state = mTouchStatesByDisplay.editValueAt(d); + for (std::pair<const int32_t, TouchState>& pair : mTouchStatesByDisplay) { + TouchState& state = pair.second; for (size_t i = 0; i < state.windows.size(); i++) { const TouchedWindow& touchedWindow = state.windows[i]; if (touchedWindow.windowHandle == fromWindowHandle) { @@ -4079,10 +4072,10 @@ void InputDispatcher::dumpDispatchStateLocked(std::string& dump) { dump += StringPrintf(INDENT "FocusedWindows: <none>\n"); } - if (!mTouchStatesByDisplay.isEmpty()) { + if (!mTouchStatesByDisplay.empty()) { dump += StringPrintf(INDENT "TouchStatesByDisplay:\n"); - for (size_t i = 0; i < mTouchStatesByDisplay.size(); i++) { - const TouchState& state = mTouchStatesByDisplay.valueAt(i); + for (const std::pair<int32_t, TouchState>& pair : mTouchStatesByDisplay) { + const TouchState& state = pair.second; dump += StringPrintf(INDENT2 "%d: down=%s, split=%s, deviceId=%d, source=0x%08x\n", state.displayId, toString(state.down), toString(state.split), state.deviceId, state.source); @@ -4144,6 +4137,9 @@ void InputDispatcher::dumpDispatchStateLocked(std::string& dump) { dump += StringPrintf(", ownerPid=%d, ownerUid=%d, dispatchingTimeout=%0.3fms\n", windowInfo->ownerPid, windowInfo->ownerUid, windowInfo->dispatchingTimeout / 1000000.0); + dump += StringPrintf(INDENT4 " flags: %s\n", + inputWindowFlagsToString(windowInfo->layoutParamsFlags) + .c_str()); } } else { dump += INDENT2 "Windows: <none>\n"; @@ -4205,12 +4201,12 @@ void InputDispatcher::dumpDispatchStateLocked(std::string& dump) { dump += INDENT "InboundQueue: <empty>\n"; } - if (!mReplacedKeys.isEmpty()) { + if (!mReplacedKeys.empty()) { dump += INDENT "ReplacedKeys:\n"; - for (size_t i = 0; i < mReplacedKeys.size(); i++) { - const KeyReplacement& replacement = mReplacedKeys.keyAt(i); - int32_t newKeyCode = mReplacedKeys.valueAt(i); - dump += StringPrintf(INDENT2 "%zu: originalKeyCode=%d, deviceId=%d, newKeyCode=%d\n", i, + for (const std::pair<KeyReplacement, int32_t>& pair : mReplacedKeys) { + const KeyReplacement& replacement = pair.first; + int32_t newKeyCode = pair.second; + dump += StringPrintf(INDENT2 "originalKeyCode=%d, deviceId=%d -> newKeyCode=%d\n", replacement.keyCode, replacement.deviceId, newKeyCode); } } else { @@ -4427,13 +4423,14 @@ status_t InputDispatcher::pilferPointers(const sp<IBinder>& token) { } int32_t displayId = foundDisplayId.value(); - ssize_t stateIndex = mTouchStatesByDisplay.indexOfKey(displayId); - if (stateIndex < 0) { + std::unordered_map<int32_t, TouchState>::iterator stateIt = + mTouchStatesByDisplay.find(displayId); + if (stateIt == mTouchStatesByDisplay.end()) { ALOGW("Failed to pilfer pointers: no pointers on display %" PRId32 ".", displayId); return BAD_VALUE; } - TouchState& state = mTouchStatesByDisplay.editValueAt(stateIndex); + TouchState& state = stateIt->second; std::optional<int32_t> foundDeviceId; for (const TouchedMonitor& touchedMonitor : state.gestureMonitors) { if (touchedMonitor.monitor.inputChannel->getConnectionToken() == token) { diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h index 2b9cbcec2e..a3afe1ecf6 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.h +++ b/services/inputflinger/dispatcher/InputDispatcher.h @@ -190,6 +190,7 @@ private: EventEntry* mNextUnblockedEvent GUARDED_BY(mLock); sp<InputWindowHandle> findTouchedWindowAtLocked(int32_t displayId, int32_t x, int32_t y, + TouchState* touchState, bool addOutsideTargets = false, bool addPortalWindows = false) REQUIRES(mLock); @@ -250,12 +251,14 @@ private: bool operator==(const KeyReplacement& rhs) const { return keyCode == rhs.keyCode && deviceId == rhs.deviceId; } - bool operator<(const KeyReplacement& rhs) const { - return keyCode != rhs.keyCode ? keyCode < rhs.keyCode : deviceId < rhs.deviceId; + }; + struct KeyReplacementHash { + size_t operator()(const KeyReplacement& key) const { + return std::hash<int32_t>()(key.keyCode) ^ (std::hash<int32_t>()(key.deviceId) << 1); } }; // Maps the key code replaced, device id tuple to the key code it was replaced with - KeyedVector<KeyReplacement, int32_t> mReplacedKeys GUARDED_BY(mLock); + std::unordered_map<KeyReplacement, int32_t, KeyReplacementHash> mReplacedKeys GUARDED_BY(mLock); // Process certain Meta + Key combinations void accelerateMetaShortcuts(const int32_t deviceId, const int32_t action, int32_t& keyCode, int32_t& metaState); @@ -303,8 +306,7 @@ private: std::unordered_map<int32_t, sp<InputWindowHandle>> mFocusedWindowHandlesByDisplay GUARDED_BY(mLock); - KeyedVector<int32_t, TouchState> mTouchStatesByDisplay GUARDED_BY(mLock); - TouchState mTempTouchState GUARDED_BY(mLock); + std::unordered_map<int32_t, TouchState> mTouchStatesByDisplay GUARDED_BY(mLock); // Focused applications. std::unordered_map<int32_t, sp<InputApplicationHandle>> mFocusedApplicationHandlesByDisplay @@ -371,11 +373,8 @@ private: nsecs_t* nextWakeupTime, bool* outConflictingPointerActions) REQUIRES(mLock); std::vector<TouchedMonitor> findTouchedGestureMonitorsLocked( - int32_t displayId, const std::vector<sp<InputWindowHandle>>& portalWindows) + int32_t displayId, const std::vector<sp<InputWindowHandle>>& portalWindows) const REQUIRES(mLock); - void addGestureMonitors(const std::vector<Monitor>& monitors, - std::vector<TouchedMonitor>& outTouchedMonitors, float xOffset = 0, - float yOffset = 0); void addWindowTargetLocked(const sp<InputWindowHandle>& windowHandle, int32_t targetFlags, BitSet32 pointerIds, std::vector<InputTarget>& inputTargets) diff --git a/services/inputflinger/host/Android.bp b/services/inputflinger/host/Android.bp index cbe0190dfa..b56f356dfd 100644 --- a/services/inputflinger/host/Android.bp +++ b/services/inputflinger/host/Android.bp @@ -21,6 +21,7 @@ cc_library_shared { "InputHost.cpp", ], + header_libs: ["jni_headers"], shared_libs: [ "libbinder", "libcrypto", @@ -42,6 +43,7 @@ cc_library_shared { //-fvisibility=hidden ], + export_header_lib_headers: ["jni_headers"], export_include_dirs: ["."], } diff --git a/services/powermanager/Android.bp b/services/powermanager/Android.bp index b0d3e3bde0..ec3dfc8faa 100644 --- a/services/powermanager/Android.bp +++ b/services/powermanager/Android.bp @@ -2,9 +2,14 @@ cc_library_shared { 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 @@ cc_library_shared { }, 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 @@ cc_library_shared { "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 0000000000..ee55b6b439 --- /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 ea3a831c13..0000000000 --- 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 0000000000..d26d582c43 --- /dev/null +++ b/services/powermanager/PowerHalController.cpp @@ -0,0 +1,99 @@ +/* + * 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 <utils/Log.h> + +#include <android/hardware/power/1.1/IPower.h> +#include <android/hardware/power/Boost.h> +#include <android/hardware/power/IPower.h> +#include <android/hardware/power/Mode.h> + +#include <powermanager/PowerHalController.h> +#include <powermanager/PowerHalLoader.h> + +using android::hardware::power::Boost; +using android::hardware::power::Mode; + +namespace android { + +// ------------------------------------------------------------------------------------------------- + +std::unique_ptr<PowerHalWrapper> PowerHalConnector::connect() { + sp<IPowerAidl> halAidl = PowerHalLoader::loadAidl(); + if (halAidl) { + return std::make_unique<AidlPowerHalWrapper>(halAidl); + } + sp<IPowerV1_0> halHidlV1_0 = PowerHalLoader::loadHidlV1_0(); + sp<IPowerV1_1> halHidlV1_1 = PowerHalLoader::loadHidlV1_1(); + if (halHidlV1_1) { + return std::make_unique<HidlPowerHalWrapperV1_1>(halHidlV1_0, halHidlV1_1); + } + if (halHidlV1_0) { + return std::make_unique<HidlPowerHalWrapperV1_0>(halHidlV1_0); + } + return nullptr; +} + +void PowerHalConnector::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<PowerHalWrapper> 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. +PowerHalResult PowerHalController::processHalResult(PowerHalResult result, const char* fnName) { + if (result == PowerHalResult::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; +} + +PowerHalResult PowerHalController::setBoost(Boost boost, int32_t durationMs) { + std::shared_ptr<PowerHalWrapper> handle = initHal(); + auto result = handle->setBoost(boost, durationMs); + return processHalResult(result, "setBoost"); +} + +PowerHalResult PowerHalController::setMode(Mode mode, bool enabled) { + std::shared_ptr<PowerHalWrapper> handle = initHal(); + auto result = handle->setMode(mode, enabled); + return processHalResult(result, "setMode"); +} + +}; // namespace android diff --git a/services/powermanager/PowerHalLoader.cpp b/services/powermanager/PowerHalLoader.cpp new file mode 100644 index 0000000000..3ae538447b --- /dev/null +++ b/services/powermanager/PowerHalLoader.cpp @@ -0,0 +1,94 @@ +/* + * 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 IPowerV1_1 = android::hardware::power::V1_1::IPower; +using IPowerV1_0 = android::hardware::power::V1_0::IPower; +using IPowerAidl = android::hardware::power::IPower; + +namespace android { + +// ------------------------------------------------------------------------------------------------- + +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<IPowerAidl> PowerHalLoader::gHalAidl = nullptr; +sp<IPowerV1_0> PowerHalLoader::gHalHidlV1_0 = nullptr; +sp<IPowerV1_1> PowerHalLoader::gHalHidlV1_1 = nullptr; + +void PowerHalLoader::unloadAll() { + std::lock_guard<std::mutex> lock(gHalMutex); + gHalAidl = nullptr; + gHalHidlV1_0 = nullptr; + gHalHidlV1_1 = nullptr; +} + +sp<IPowerAidl> PowerHalLoader::loadAidl() { + std::lock_guard<std::mutex> lock(gHalMutex); + static bool gHalExists = true; + static auto loadFn = []() { return waitForVintfService<IPowerAidl>(); }; + return loadHal<IPowerAidl>(gHalExists, gHalAidl, loadFn, "AIDL"); +} + +sp<IPowerV1_0> PowerHalLoader::loadHidlV1_0() { + std::lock_guard<std::mutex> lock(gHalMutex); + return loadHidlV1_0Locked(); +} + +sp<IPowerV1_1> PowerHalLoader::loadHidlV1_1() { + std::lock_guard<std::mutex> lock(gHalMutex); + static bool gHalExists = true; + static auto loadFn = []() { return IPowerV1_1::castFrom(loadHidlV1_0Locked()); }; + return loadHal<IPowerV1_1>(gHalExists, gHalHidlV1_1, loadFn, "HIDL v1.1"); +} + +sp<IPowerV1_0> PowerHalLoader::loadHidlV1_0Locked() { + static bool gHalExists = true; + static auto loadFn = []() { return IPowerV1_0::getService(); }; + return loadHal<IPowerV1_0>(gHalExists, gHalHidlV1_0, loadFn, "HIDL v1.0"); +} + +// ------------------------------------------------------------------------------------------------- + +} // namespace android diff --git a/services/powermanager/PowerHalWrapper.cpp b/services/powermanager/PowerHalWrapper.cpp new file mode 100644 index 0000000000..d959a2cc96 --- /dev/null +++ b/services/powermanager/PowerHalWrapper.cpp @@ -0,0 +1,172 @@ +/* + * 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 "PowerHalWrapper" +#include <utils/Log.h> + +#include <android/hardware/power/Boost.h> +#include <android/hardware/power/Mode.h> + +#include <powermanager/PowerHalWrapper.h> + +using android::hardware::power::Boost; +using android::hardware::power::Mode; +using android::hardware::power::V1_0::Feature; +using android::hardware::power::V1_0::PowerHint; + +namespace android { + +// ------------------------------------------------------------------------------------------------- + +PowerHalResult EmptyPowerHalWrapper::setBoost(Boost boost, int32_t durationMs) { + ALOGV("Skipped setBoost %s with duration %dms because Power HAL not available", + toString(boost).c_str(), durationMs); + return PowerHalResult::UNSUPPORTED; +} + +PowerHalResult EmptyPowerHalWrapper::setMode(Mode mode, bool enabled) { + ALOGV("Skipped setMode %s to %s because Power HAL not available", + toString(mode).c_str(), enabled ? "true" : "false"); + return PowerHalResult::UNSUPPORTED; +} + +// ------------------------------------------------------------------------------------------------- + +PowerHalResult HidlPowerHalWrapperV1_0::setBoost(Boost boost, int32_t durationMs) { + if (boost == Boost::INTERACTION) { + return sendPowerHint(PowerHint::INTERACTION, durationMs); + } else { + ALOGV("Skipped setBoost %s because Power HAL AIDL not available", + toString(boost).c_str()); + return PowerHalResult::UNSUPPORTED; + } +} + +PowerHalResult HidlPowerHalWrapperV1_0::setMode(Mode mode, bool enabled) { + uint32_t data = enabled ? 1 : 0; + switch (mode) { + case Mode::LAUNCH: + return sendPowerHint(PowerHint::LAUNCH, data); + case Mode::LOW_POWER: + return sendPowerHint(PowerHint::LOW_POWER, data); + case Mode::SUSTAINED_PERFORMANCE: + return sendPowerHint(PowerHint::SUSTAINED_PERFORMANCE, data); + case Mode::VR: + return sendPowerHint(PowerHint::VR_MODE, data); + case Mode::INTERACTIVE: + return setInteractive(enabled); + case Mode::DOUBLE_TAP_TO_WAKE: + return setFeature(Feature::POWER_FEATURE_DOUBLE_TAP_TO_WAKE, enabled); + default: + ALOGV("Skipped setMode %s because Power HAL AIDL not available", + toString(mode).c_str()); + return PowerHalResult::UNSUPPORTED; + } +} + +PowerHalResult HidlPowerHalWrapperV1_0::sendPowerHint(PowerHint hintId, uint32_t data) { + auto ret = handleV1_0->powerHint(hintId, data); + return ret.isOk() ? PowerHalResult::SUCCESSFUL : PowerHalResult::FAILED; +} + +PowerHalResult HidlPowerHalWrapperV1_0::setInteractive(bool enabled) { + auto ret = handleV1_0->setInteractive(enabled); + return ret.isOk() ? PowerHalResult::SUCCESSFUL : PowerHalResult::FAILED; +} + +PowerHalResult HidlPowerHalWrapperV1_0::setFeature(Feature feature, bool enabled) { + auto ret = handleV1_0->setFeature(feature, enabled); + return ret.isOk() ? PowerHalResult::SUCCESSFUL : PowerHalResult::FAILED; +} + +// ------------------------------------------------------------------------------------------------- + +PowerHalResult HidlPowerHalWrapperV1_1::sendPowerHint(PowerHint hintId, uint32_t data) { + auto ret = handleV1_1->powerHintAsync(hintId, data); + return ret.isOk() ? PowerHalResult::SUCCESSFUL : PowerHalResult::FAILED; +} + +// ------------------------------------------------------------------------------------------------- + +PowerHalResult AidlPowerHalWrapper::setBoost(Boost boost, int32_t durationMs) { + std::unique_lock<std::mutex> lock(mBoostMutex); + // Quick return if boost is not supported by HAL + if (boost > Boost::DISPLAY_UPDATE_IMMINENT || + boostSupportedArray[static_cast<int32_t>(boost)] == PowerHalSupport::OFF) { + ALOGV("Skipped setBoost %s because Power HAL doesn't support it", + toString(boost).c_str()); + return PowerHalResult::UNSUPPORTED; + } + + if (boostSupportedArray[static_cast<int32_t>(boost)] == PowerHalSupport::UNKNOWN) { + bool isSupported = false; + auto isSupportedRet = handle->isBoostSupported(boost, &isSupported); + if (!isSupportedRet.isOk()) { + ALOGV("Skipped setBoost %s because Power HAL is not available to check support", + toString(boost).c_str()); + return PowerHalResult::FAILED; + } + + boostSupportedArray[static_cast<int32_t>(boost)] = + isSupported ? PowerHalSupport::ON : PowerHalSupport::OFF; + if (!isSupported) { + ALOGV("Skipped setBoost %s because Power HAL doesn't support it", + toString(boost).c_str()); + return PowerHalResult::UNSUPPORTED; + } + } + lock.unlock(); + + auto ret = handle->setBoost(boost, durationMs); + return ret.isOk() ? PowerHalResult::SUCCESSFUL : PowerHalResult::FAILED; +} + +PowerHalResult AidlPowerHalWrapper::setMode(Mode mode, bool enabled) { + std::unique_lock<std::mutex> lock(mModeMutex); + // Quick return if mode is not supported by HAL + if (mode > Mode::DISPLAY_INACTIVE || + modeSupportedArray[static_cast<int32_t>(mode)] == PowerHalSupport::OFF) { + ALOGV("Skipped setMode %s because Power HAL doesn't support it", + toString(mode).c_str()); + return PowerHalResult::UNSUPPORTED; + } + + if (modeSupportedArray[static_cast<int32_t>(mode)] == PowerHalSupport::UNKNOWN) { + bool isSupported = false; + auto isSupportedRet = handle->isModeSupported(mode, &isSupported); + if (!isSupportedRet.isOk()) { + ALOGV("Skipped setMode %s because Power HAL is not available to check support", + toString(mode).c_str()); + return PowerHalResult::FAILED; + } + + modeSupportedArray[static_cast<int32_t>(mode)] = + isSupported ? PowerHalSupport::ON : PowerHalSupport::OFF; + if (!isSupported) { + ALOGV("Skipped setMode %s because Power HAL doesn't support it", + toString(mode).c_str()); + return PowerHalResult::UNSUPPORTED; + } + } + lock.unlock(); + + auto ret = handle->setMode(mode, enabled); + return ret.isOk() ? PowerHalResult::SUCCESSFUL : PowerHalResult::FAILED; +} + +// ------------------------------------------------------------------------------------------------- + +}; // namespace android diff --git a/services/powermanager/PowerSaveState.cpp b/services/powermanager/PowerSaveState.cpp new file mode 100644 index 0000000000..6d1830a887 --- /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 0000000000..9a67901c5f --- /dev/null +++ b/services/powermanager/TEST_MAPPING @@ -0,0 +1,10 @@ +{ + "presubmit": [ + { + "name": "powermanager_test" + }, + { + "name": "thermalmanager_test" + } + ] +} diff --git a/services/powermanager/WorkSource.cpp b/services/powermanager/WorkSource.cpp new file mode 100644 index 0000000000..1006a0666f --- /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/include/android/BatterySaverPolicyConfig.h b/services/powermanager/include/android/BatterySaverPolicyConfig.h new file mode 100644 index 0000000000..728c8a02a0 --- /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 0000000000..42933d438b --- /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 0000000000..b421f6aaa8 --- /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 0000000000..f12847d040 --- /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 0000000000..70837cfda5 --- /dev/null +++ b/services/powermanager/tests/Android.bp @@ -0,0 +1,63 @@ +// 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: "powermanager_test", + test_suites: ["device-tests"], + srcs: [ + "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", + ], +} + +cc_test { + name: "thermalmanager_test", + test_suites: ["device-tests"], + srcs: ["IThermalManagerTest.cpp",], + cflags: [ + "-Wall", + "-Werror", + "-Wextra", + ], + shared_libs: [ + "libbase", + "libhidlbase", + "liblog", + "libpowermanager", + "libbinder", + "libutils", + ], +} diff --git a/services/powermanager/IThermalManagerTest.cpp b/services/powermanager/tests/IThermalManagerTest.cpp index 575b9ee1c4..575b9ee1c4 100644 --- a/services/powermanager/IThermalManagerTest.cpp +++ b/services/powermanager/tests/IThermalManagerTest.cpp diff --git a/services/powermanager/tests/PowerHalControllerTest.cpp b/services/powermanager/tests/PowerHalControllerTest.cpp new file mode 100644 index 0000000000..ac1e19a242 --- /dev/null +++ b/services/powermanager/tests/PowerHalControllerTest.cpp @@ -0,0 +1,287 @@ +/* + * 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/PowerHalWrapper.h> +#include <powermanager/PowerHalController.h> + +#include <thread> +#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 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 PowerHalConnector { +public: + TestPowerHalConnector(sp<IPower> powerHal) : mHal(std::move(powerHal)) {} + virtual ~TestPowerHalConnector() = default; + + virtual std::unique_ptr<PowerHalWrapper> connect() override { + mCountMutex.lock(); + ++mConnectedCount; + mCountMutex.unlock(); + return std::make_unique<HidlPowerHalWrapperV1_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<PowerHalWrapper> connect() override { + // Call parent to update counter, but ignore connected PowerHalWrapper. + 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(PowerHalResult::UNSUPPORTED, result); + result = halController.setMode(Mode::LAUNCH, true); + ASSERT_EQ(PowerHalResult::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(PowerHalResult::SUCCESSFUL, result); + result = mHalController->setMode(Mode::LAUNCH, true); + ASSERT_EQ(PowerHalResult::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(PowerHalResult::SUCCESSFUL, result); + result = mHalController->setMode(Mode::LAUNCH, true); + ASSERT_EQ(PowerHalResult::FAILED, result); + result = mHalController->setMode(Mode::VR, false); + ASSERT_EQ(PowerHalResult::SUCCESSFUL, result); + result = mHalController->setMode(Mode::LOW_POWER, true); + ASSERT_EQ(PowerHalResult::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(PowerHalResult::UNSUPPORTED, result); + result = mHalController->setMode(Mode::CAMERA_STREAMING_HIGH, true); + ASSERT_EQ(PowerHalResult::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(PowerHalResult::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(PowerHalResult::SUCCESSFUL, result); + })); + threads.push_back(std::thread([&]() { + auto result = mHalController->setMode(Mode::LAUNCH, true); + ASSERT_EQ(PowerHalResult::FAILED, result); + })); + threads.push_back(std::thread([&]() { + auto result = mHalController->setMode(Mode::LOW_POWER, false); + ASSERT_EQ(PowerHalResult::SUCCESSFUL, result); + })); + threads.push_back(std::thread([&]() { + auto result = mHalController->setMode(Mode::VR, true); + ASSERT_EQ(PowerHalResult::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 0000000000..2310a72318 --- /dev/null +++ b/services/powermanager/tests/PowerHalLoaderTest.cpp @@ -0,0 +1,113 @@ +/* + * 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 <future> +#include <gtest/gtest.h> + +#include <powermanager/PowerHalLoader.h> + +using IPowerV1_0 = android::hardware::power::V1_0::IPower; +using IPowerV1_1 = android::hardware::power::V1_1::IPower; +using IPowerAidl = android::hardware::power::IPower; + +using namespace android; + +// ------------------------------------------------------------------------------------------------- + +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 testing::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 0000000000..73b7466670 --- /dev/null +++ b/services/powermanager/tests/PowerHalWrapperAidlTest.cpp @@ -0,0 +1,202 @@ +/* + * 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 <thread> +#include <utils/Log.h> + +using android::binder::Status; +using android::hardware::power::Boost; +using android::hardware::power::IPower; +using android::hardware::power::Mode; + +using namespace android; +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<PowerHalWrapper> mWrapper = nullptr; + sp<StrictMock<MockIPower>> mMockHal = nullptr; +}; + +// ------------------------------------------------------------------------------------------------- + +void PowerHalWrapperAidlTest::SetUp() { + mMockHal = new StrictMock<MockIPower>(); + mWrapper = std::make_unique<AidlPowerHalWrapper>(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(PowerHalResult::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(PowerHalResult::FAILED, result); + result = mWrapper->setBoost(Boost::DISPLAY_UPDATE_IMMINENT, 1000); + ASSERT_EQ(PowerHalResult::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(PowerHalResult::UNSUPPORTED, result); + result = mWrapper->setBoost(Boost::CAMERA_SHOT, 10); + ASSERT_EQ(PowerHalResult::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(PowerHalResult::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(PowerHalResult::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(PowerHalResult::FAILED, result); + result = mWrapper->setMode(Mode::DISPLAY_INACTIVE, false); + ASSERT_EQ(PowerHalResult::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(PowerHalResult::UNSUPPORTED, result); + result = mWrapper->setMode(Mode::CAMERA_STREAMING_HIGH, true); + ASSERT_EQ(PowerHalResult::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(PowerHalResult::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 0000000000..5379054493 --- /dev/null +++ b/services/powermanager/tests/PowerHalWrapperHidlV1_0Test.cpp @@ -0,0 +1,145 @@ +/* + * 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 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<PowerHalWrapper> mWrapper = nullptr; + sp<StrictMock<MockIPowerV1_0>> mMockHal = nullptr; +}; + +// ------------------------------------------------------------------------------------------------- + +void PowerHalWrapperHidlV1_0Test::SetUp() { + mMockHal = new StrictMock<MockIPowerV1_0>(); + mWrapper = std::make_unique<HidlPowerHalWrapperV1_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(PowerHalResult::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(PowerHalResult::FAILED, result); +} + +TEST_F(PowerHalWrapperHidlV1_0Test, TestSetBoostUnsupported) { + auto result = mWrapper->setBoost(Boost::CAMERA_LAUNCH, 10); + ASSERT_EQ(PowerHalResult::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(PowerHalResult::SUCCESSFUL, result); + result = mWrapper->setMode(Mode::LOW_POWER, false); + ASSERT_EQ(PowerHalResult::SUCCESSFUL, result); + result = mWrapper->setMode(Mode::SUSTAINED_PERFORMANCE, true); + ASSERT_EQ(PowerHalResult::SUCCESSFUL, result); + result = mWrapper->setMode(Mode::VR, false); + ASSERT_EQ(PowerHalResult::SUCCESSFUL, result); + result = mWrapper->setMode(Mode::INTERACTIVE, true); + ASSERT_EQ(PowerHalResult::SUCCESSFUL, result); + result = mWrapper->setMode(Mode::DOUBLE_TAP_TO_WAKE, false); + ASSERT_EQ(PowerHalResult::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(PowerHalResult::FAILED, result); +} + +TEST_F(PowerHalWrapperHidlV1_0Test, TestSetModeIgnored) { + auto result = mWrapper->setMode(Mode::CAMERA_STREAMING_HIGH, true); + ASSERT_EQ(PowerHalResult::UNSUPPORTED, result); +} diff --git a/services/powermanager/tests/PowerHalWrapperHidlV1_1Test.cpp b/services/powermanager/tests/PowerHalWrapperHidlV1_1Test.cpp new file mode 100644 index 0000000000..931c0d5011 --- /dev/null +++ b/services/powermanager/tests/PowerHalWrapperHidlV1_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 "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 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<PowerHalWrapper> 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<HidlPowerHalWrapperV1_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(PowerHalResult::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(PowerHalResult::FAILED, result); +} + +TEST_F(PowerHalWrapperHidlV1_1Test, TestSetBoostUnsupported) { + auto result = mWrapper->setBoost(Boost::CAMERA_LAUNCH, 10); + ASSERT_EQ(PowerHalResult::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(PowerHalResult::SUCCESSFUL, result); + result = mWrapper->setMode(Mode::LOW_POWER, false); + ASSERT_EQ(PowerHalResult::SUCCESSFUL, result); + result = mWrapper->setMode(Mode::SUSTAINED_PERFORMANCE, true); + ASSERT_EQ(PowerHalResult::SUCCESSFUL, result); + result = mWrapper->setMode(Mode::VR, false); + ASSERT_EQ(PowerHalResult::SUCCESSFUL, result); + result = mWrapper->setMode(Mode::INTERACTIVE, true); + ASSERT_EQ(PowerHalResult::SUCCESSFUL, result); + result = mWrapper->setMode(Mode::DOUBLE_TAP_TO_WAKE, false); + ASSERT_EQ(PowerHalResult::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(PowerHalResult::FAILED, result); +} + +TEST_F(PowerHalWrapperHidlV1_1Test, TestSetModeIgnored) { + auto result = mWrapper->setMode(Mode::CAMERA_STREAMING_HIGH, true); + ASSERT_EQ(PowerHalResult::UNSUPPORTED, result); +} diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp index e8f54f57b1..b07c904917 100644 --- a/services/surfaceflinger/CompositionEngine/src/Output.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp @@ -921,9 +921,8 @@ std::optional<base::unique_fd> Output::composeSurfaces( 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/DisplayHardware/DisplayIdentification.cpp b/services/surfaceflinger/DisplayHardware/DisplayIdentification.cpp index 4dfc7431de..52a6380ebd 100644 --- a/services/surfaceflinger/DisplayHardware/DisplayIdentification.cpp +++ b/services/surfaceflinger/DisplayHardware/DisplayIdentification.cpp @@ -71,12 +71,8 @@ char getPnpLetter(uint16_t id) { 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 @@ DeviceProductInfo buildDeviceProductInfo(const Edid& edid) { 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 @@ std::optional<Edid> parseEdid(const DisplayIdentificationData& edid) { 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/Layer.cpp b/services/surfaceflinger/Layer.cpp index 752407aedc..fe59d73043 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -2201,6 +2201,7 @@ void Layer::writeToProtoDrawingState(LayerProto* layerInfo, uint32_t traceFlags) 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/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 87e73a0e7a..1b9ddb1886 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -27,7 +27,7 @@ #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 <binder/IPCThreadState.h> #include <binder/IServiceManager.h> @@ -133,7 +133,7 @@ using namespace android::hardware::configstore; 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; @@ -387,6 +387,10 @@ SurfaceFlinger::SurfaceFlinger(Factory& factory) : SurfaceFlinger(factory, SkipI 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); @@ -1504,10 +1508,10 @@ status_t SurfaceFlinger::setDisplayBrightness(const sp<IBinder>& displayToken, f .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(); } @@ -3178,6 +3182,11 @@ status_t SurfaceFlinger::addClientLayer(const sp<Client>& client, const sp<IBind "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()); + } } mLayersAdded = true; } @@ -4670,7 +4679,7 @@ void SurfaceFlinger::dumpAllLocked(const DumpArgs& args, std::string& result) co 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() @@ -4834,7 +4843,7 @@ status_t SurfaceFlinger::CheckTransactCodeCredentials(uint32_t code) { 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 @@ -5711,8 +5720,9 @@ status_t SurfaceFlinger::captureScreenCommon(RenderArea& renderArea, 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(); @@ -5809,7 +5819,7 @@ void SurfaceFlinger::renderScreenImplLocked(const RenderArea& renderArea, 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) { diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index f3984ed8d4..4b5a843589 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -505,7 +505,7 @@ private: 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, @@ -715,7 +715,7 @@ private: using TraverseLayersFunction = std::function<void(const LayerVector::Visitor&)>; 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, @@ -727,7 +727,7 @@ private: const sp<DisplayDevice> getDisplayByLayerStack(uint64_t layerStack); 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, @@ -1006,6 +1006,10 @@ private: // 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>&); diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp index 8713b2bd49..27853979eb 100644 --- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp +++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp @@ -348,7 +348,7 @@ struct BaseDisplayVariant { 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 +397,7 @@ struct BaseDisplayVariant { 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 +648,7 @@ struct BaseLayerProperties { 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 +697,7 @@ struct BaseLayerProperties { 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 +775,7 @@ struct SecureLayerProperties : public BaseLayerProperties<SecureLayerProperties> 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 2a0e913e7a..cc6a60ce27 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 @@ TEST(DisplayIdentificationTest, deviceProductInfo) { 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 ce5f35cdf3..f41b10e67c 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 { namespace hal = android::hardware::graphics::composer::hal; +using android::hardware::power::Boost; + using testing::_; using testing::AnyNumber; using testing::DoAll; @@ -1347,6 +1350,30 @@ TEST_F(DisplayTransactionTest, resetDisplayStateClearsState) { } /* ------------------------------------------------------------------------ + * 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 { diff --git a/services/surfaceflinger/tests/unittests/TestableScheduler.h b/services/surfaceflinger/tests/unittests/TestableScheduler.h index 41b5d49bf8..806f95ce0e 100644 --- a/services/surfaceflinger/tests/unittests/TestableScheduler.h +++ b/services/surfaceflinger/tests/unittests/TestableScheduler.h @@ -72,13 +72,31 @@ public: 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 add33270f9..445f04a46f 100644 --- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h +++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h @@ -315,6 +315,8 @@ public: 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 { @@ -325,7 +327,7 @@ public: 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, diff --git a/services/vr/virtual_touchpad/Android.bp b/services/vr/virtual_touchpad/Android.bp index dcaa663160..9cf4905b68 100644 --- a/services/vr/virtual_touchpad/Android.bp +++ b/services/vr/virtual_touchpad/Android.bp @@ -14,6 +14,7 @@ shared_libs = [ ] header_libraries = [ + "jni_headers", "libdvr_headers", ] |