diff options
200 files changed, 4650 insertions, 1267 deletions
diff --git a/Android.bp b/Android.bp index bf4cf5daf8..9829c7fbad 100644 --- a/Android.bp +++ b/Android.bp @@ -7,6 +7,7 @@ ndk_headers { } subdirs = [ + "adbd_auth", "cmds/*", "headers", "libs/*", diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg index 4f7cdf3e5e..36a53bbbe2 100644 --- a/PREUPLOAD.cfg +++ b/PREUPLOAD.cfg @@ -4,6 +4,7 @@ clang_format = true [Builtin Hooks Options] # Only turn on clang-format check for the following subfolders. clang_format = --commit ${PREUPLOAD_COMMIT} --style file --extensions c,h,cc,cpp + cmds/idlcli/ include/input/ libs/binder/ndk/ libs/graphicsenv/ diff --git a/TEST_MAPPING b/TEST_MAPPING new file mode 100644 index 0000000000..8173c8927e --- /dev/null +++ b/TEST_MAPPING @@ -0,0 +1,63 @@ +{ + "presubmit": [ + { + "name": "SurfaceFlinger_test", + "options": [ + { + "include-filter": "*CredentialsTest.*" + }, + { + "include-filter": "*SurfaceFlingerStress.*" + }, + { + "include-filter": "*SurfaceInterceptorTest.*" + }, + { + "include-filter": "*LayerTransactionTest.*" + }, + { + "include-filter": "*LayerTypeTransactionTest.*" + }, + { + "include-filter": "*LayerUpdateTest.*" + }, + { + "include-filter": "*GeometryLatchingTest.*" + }, + { + "include-filter": "*CropLatchingTest.*" + }, + { + "include-filter": "*ChildLayerTest.*" + }, + { + "include-filter": "*ScreenCaptureTest.*" + }, + { + "include-filter": "*ScreenCaptureChildOnlyTest.*" + }, + { + "include-filter": "*DereferenceSurfaceControlTest.*" + }, + { + "include-filter": "*BoundlessLayerTest.*" + }, + { + "include-filter": "*MultiDisplayLayerBoundsTest.*" + }, + { + "include-filter": "*InvalidHandleTest.*" + }, + { + "include-filter": "*VirtualDisplayTest.*" + }, + { + "include-filter": "*RelativeZTest.*" + } + ] + }, + { + "name": "libsurfaceflinger_unittest" + } + ] +} diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp index 67f12e8efe..c5bfb42bde 100644 --- a/cmds/dumpstate/dumpstate.cpp +++ b/cmds/dumpstate/dumpstate.cpp @@ -154,6 +154,7 @@ void add_mountinfo(); #define XFRM_STAT_PROC_FILE "/proc/net/xfrm_stat" #define WLUTIL "/vendor/xbin/wlutil" #define WMTRACE_DATA_DIR "/data/misc/wmtrace" +#define OTA_METADATA_DIR "/metadata/ota" // TODO(narayan): Since this information has to be kept in sync // with tombstoned, we should just put it in a common header. @@ -960,6 +961,7 @@ static void DumpDynamicPartitionInfo() { } RunCommand("LPDUMP", {"lpdump", "--all"}); + RunCommand("DEVICE-MAPPER", {"gsid", "dump-device-mapper"}); } static void AddAnrTraceDir(const bool add_to_zip, const std::string& anr_traces_dir) { @@ -1556,6 +1558,7 @@ static Dumpstate::RunStatus DumpstateDefault() { add_mountinfo(); DumpIpTablesAsRoot(); DumpDynamicPartitionInfo(); + ds.AddDir(OTA_METADATA_DIR, true); // Capture any IPSec policies in play. No keys are exposed here. RunCommand("IP XFRM POLICY", {"ip", "xfrm", "policy"}, CommandOptions::WithTimeout(10).Build()); diff --git a/cmds/dumpsys/tests/dumpsys_test.cpp b/cmds/dumpsys/tests/dumpsys_test.cpp index cf4e0b5a4c..b9395ba4e2 100644 --- a/cmds/dumpsys/tests/dumpsys_test.cpp +++ b/cmds/dumpsys/tests/dumpsys_test.cpp @@ -54,6 +54,7 @@ class ServiceManagerMock : public IServiceManager { MOCK_METHOD4(addService, status_t(const String16&, const sp<IBinder>&, bool, int)); MOCK_METHOD1(listServices, Vector<String16>(int)); MOCK_METHOD1(waitForService, sp<IBinder>(const String16&)); + MOCK_METHOD1(isDeclared, bool(const String16&)); protected: MOCK_METHOD0(onAsBinder, IBinder*()); }; diff --git a/cmds/idlcli/Android.bp b/cmds/idlcli/Android.bp index 40b8dc74f7..5476319f31 100644 --- a/cmds/idlcli/Android.bp +++ b/cmds/idlcli/Android.bp @@ -20,9 +20,11 @@ cc_defaults { "android.hardware.vibrator@1.2", "android.hardware.vibrator@1.3", "libbase", + "libbinder", "libhidlbase", "liblog", "libutils", + "vintf-vibrator-cpp", ], cflags: [ "-DLOG_TAG=\"idlcli\"", @@ -34,6 +36,10 @@ cc_library { defaults: ["idlcli-defaults"], srcs: [ "CommandVibrator.cpp", + "vibrator/CommandCompose.cpp", + "vibrator/CommandGetCapabilities.cpp", + "vibrator/CommandGetCompositionDelayMax.cpp", + "vibrator/CommandGetCompositionSizeMax.cpp", "vibrator/CommandOff.cpp", "vibrator/CommandOn.cpp", "vibrator/CommandPerform.cpp", diff --git a/cmds/idlcli/vibrator.h b/cmds/idlcli/vibrator.h index bcb207b7d0..2f119234c1 100644 --- a/cmds/idlcli/vibrator.h +++ b/cmds/idlcli/vibrator.h @@ -18,6 +18,8 @@ #define FRAMEWORK_NATIVE_CMDS_IDLCLI_VIBRATOR_H_ #include <android/hardware/vibrator/1.3/IVibrator.h> +#include <android/hardware/vibrator/IVibrator.h> +#include <binder/IServiceManager.h> #include "utils.h" @@ -31,9 +33,25 @@ static constexpr int NUM_TRIES = 2; // Creates a Return<R> with STATUS::EX_NULL_POINTER. template <class R> -inline Return<R> NullptrStatus() { +inline R NullptrStatus() { using ::android::hardware::Status; - return Return<R>{Status::fromExceptionCode(Status::EX_NULL_POINTER)}; + return Status::fromExceptionCode(Status::EX_NULL_POINTER); +} + +template <> +inline binder::Status NullptrStatus() { + using binder::Status; + return Status::fromExceptionCode(Status::EX_NULL_POINTER); +} + +template <typename I> +inline sp<I> getService() { + return I::getService(); +} + +template <> +inline sp<hardware::vibrator::IVibrator> getService() { + return waitForVintfService<hardware::vibrator::IVibrator>(); } template <typename I> @@ -42,12 +60,12 @@ public: static std::unique_ptr<HalWrapper> Create() { // Assume that if getService returns a nullptr, HAL is not available on the // device. - auto hal = I::getService(); + auto hal = getService<I>(); return hal ? std::unique_ptr<HalWrapper>(new HalWrapper(std::move(hal))) : nullptr; } template <class R, class... Args0, class... Args1> - Return<R> call(Return<R> (I::*fn)(Args0...), Args1&&... args1) { + R call(R (I::*fn)(Args0...), Args1&&... args1) { return (*mHal.*fn)(std::forward<Args1>(args1)...); } @@ -65,7 +83,7 @@ static auto getHal() { } template <class R, class I, class... Args0, class... Args1> -Return<R> halCall(Return<R> (I::*fn)(Args0...), Args1&&... args1) { +R halCall(R (I::*fn)(Args0...), Args1&&... args1) { auto hal = getHal<I>(); return hal ? hal->call(fn, std::forward<Args1>(args1)...) : NullptrStatus<R>(); } @@ -77,6 +95,7 @@ namespace V1_0 = ::android::hardware::vibrator::V1_0; namespace V1_1 = ::android::hardware::vibrator::V1_1; namespace V1_2 = ::android::hardware::vibrator::V1_2; namespace V1_3 = ::android::hardware::vibrator::V1_3; +namespace aidl = ::android::hardware::vibrator; } // namespace vibrator } // namespace idlcli diff --git a/cmds/idlcli/vibrator/CommandCompose.cpp b/cmds/idlcli/vibrator/CommandCompose.cpp new file mode 100644 index 0000000000..705e40bbf2 --- /dev/null +++ b/cmds/idlcli/vibrator/CommandCompose.cpp @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2019 The Android Open Source Project * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "utils.h" +#include "vibrator.h" + +namespace android { +namespace idlcli { + +class CommandVibrator; + +namespace vibrator { + +using aidl::CompositeEffect; + +class CommandCompose : public Command { + std::string getDescription() const override { return "Compose vibration."; } + + std::string getUsageSummary() const override { return "<delay> <primitive> <scale> ..."; } + + UsageDetails getUsageDetails() const override { + UsageDetails details{ + {"<delay>", {"In milliseconds"}}, + {"<primitive>", {"Primitive ID."}}, + {"<scale>", {"0.0 (exclusive) - 1.0 (inclusive)."}}, + {"...", {"May repeat multiple times."}}, + }; + return details; + } + + Status doArgs(Args &args) override { + while (!args.empty()) { + CompositeEffect effect; + if (auto delay = args.pop<decltype(effect.delayMs)>()) { + effect.delayMs = *delay; + std::cout << "Delay: " << effect.delayMs << std::endl; + } else { + 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); + std::cout << "Primitive: " << toString(effect.primitive) << std::endl; + } else { + std::cerr << "Missing or Invalid Primitive!" << std::endl; + return USAGE; + } + if (auto scale = args.pop<decltype(effect.scale)>(); + scale && *scale > 0.0 && scale <= 1.0) { + effect.scale = *scale; + std::cout << "Scale: " << effect.scale << std::endl; + } else { + std::cerr << "Missing or Invalid Scale!" << std::endl; + return USAGE; + } + mComposite.emplace_back(std::move(effect)); + } + 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::compose, mComposite, nullptr); + statusStr = status.toString8(); + ret = status.isOk() ? OK : ERROR; + } else { + return UNAVAILABLE; + } + + std::cout << "Status: " << statusStr << std::endl; + + return ret; + } + + std::vector<CompositeEffect> mComposite; +}; + +static const auto Command = CommandRegistry<CommandVibrator>::Register<CommandCompose>("compose"); + +} // namespace vibrator +} // namespace idlcli +} // namespace android diff --git a/cmds/idlcli/vibrator/CommandGetCapabilities.cpp b/cmds/idlcli/vibrator/CommandGetCapabilities.cpp new file mode 100644 index 0000000000..30d85873c0 --- /dev/null +++ b/cmds/idlcli/vibrator/CommandGetCapabilities.cpp @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2019 The Android Open Source Project * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "utils.h" +#include "vibrator.h" + +namespace android { +namespace idlcli { + +class CommandVibrator; + +namespace vibrator { + +class CommandGetCapabilities : public Command { + std::string getDescription() const override { return "Retrieves vibrator capabilities."; } + + 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; + int32_t cap; + Status ret; + + if (auto hal = getHal<aidl::IVibrator>()) { + auto status = hal->call(&aidl::IVibrator::getCapabilities, &cap); + statusStr = status.toString8(); + ret = status.isOk() ? OK : ERROR; + } else { + return UNAVAILABLE; + } + + std::cout << "Status: " << statusStr << std::endl; + std::cout << "Capabilities: " << std::bitset<32>(cap) << std::endl; + + return ret; + } +}; + +static const auto Command = + CommandRegistry<CommandVibrator>::Register<CommandGetCapabilities>("getCapabilities"); + +} // namespace vibrator +} // namespace idlcli +} // namespace android diff --git a/cmds/idlcli/vibrator/CommandGetCompositionDelayMax.cpp b/cmds/idlcli/vibrator/CommandGetCompositionDelayMax.cpp new file mode 100644 index 0000000000..b4143075b3 --- /dev/null +++ b/cmds/idlcli/vibrator/CommandGetCompositionDelayMax.cpp @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2019 The Android Open Source Project * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "utils.h" +#include "vibrator.h" + +namespace android { +namespace idlcli { + +class CommandVibrator; + +namespace vibrator { + +class CommandGetCompositionDelayMax : public Command { + std::string getDescription() const override { + return "Retrieves vibrator composition delay max."; + } + + 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; + int32_t maxDelayMs; + Status ret; + + if (auto hal = getHal<aidl::IVibrator>()) { + auto status = hal->call(&aidl::IVibrator::getCompositionDelayMax, &maxDelayMs); + statusStr = status.toString8(); + ret = status.isOk() ? OK : ERROR; + } else { + return UNAVAILABLE; + } + + std::cout << "Status: " << statusStr << std::endl; + std::cout << "Max Delay: " << maxDelayMs << " ms" << std::endl; + + return ret; + } +}; + +static const auto Command = + CommandRegistry<CommandVibrator>::Register<CommandGetCompositionDelayMax>( + "getCompositionDelayMax"); + +} // namespace vibrator +} // namespace idlcli +} // namespace android diff --git a/cmds/idlcli/vibrator/CommandGetCompositionSizeMax.cpp b/cmds/idlcli/vibrator/CommandGetCompositionSizeMax.cpp new file mode 100644 index 0000000000..360fc9d9e2 --- /dev/null +++ b/cmds/idlcli/vibrator/CommandGetCompositionSizeMax.cpp @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2019 The Android Open Source Project * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "utils.h" +#include "vibrator.h" + +namespace android { +namespace idlcli { + +class CommandVibrator; + +namespace vibrator { + +class CommandGetCompositionSizeMax : public Command { + std::string getDescription() const override { + return "Retrieves vibrator composition size max."; + } + + 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; + int32_t maxSize; + Status ret; + + if (auto hal = getHal<aidl::IVibrator>()) { + auto status = hal->call(&aidl::IVibrator::getCompositionSizeMax, &maxSize); + statusStr = status.toString8(); + ret = status.isOk() ? OK : ERROR; + } else { + return UNAVAILABLE; + } + + std::cout << "Status: " << statusStr << std::endl; + std::cout << "Max Size: " << maxSize << std::endl; + + return ret; + } +}; + +static const auto Command = + CommandRegistry<CommandVibrator>::Register<CommandGetCompositionSizeMax>( + "getCompositionSizeMax"); + +} // namespace vibrator +} // namespace idlcli +} // namespace android diff --git a/cmds/idlcli/vibrator/CommandOff.cpp b/cmds/idlcli/vibrator/CommandOff.cpp index a674f0192f..53fada0f86 100644 --- a/cmds/idlcli/vibrator/CommandOff.cpp +++ b/cmds/idlcli/vibrator/CommandOff.cpp @@ -42,15 +42,24 @@ class CommandOff : public Command { } Status doMain(Args && /*args*/) override { - auto ret = halCall(&V1_0::IVibrator::off); + std::string statusStr; + Status ret; - if (!ret.isOk()) { + if (auto hal = getHal<aidl::IVibrator>()) { + auto status = hal->call(&aidl::IVibrator::off); + statusStr = status.toString8(); + ret = status.isOk() ? OK : ERROR; + } else if (auto hal = getHal<V1_0::IVibrator>()) { + auto status = hal->call(&V1_0::IVibrator::off); + statusStr = toString(status); + ret = status.isOk() && status == V1_0::Status::OK ? OK : ERROR; + } else { return UNAVAILABLE; } - std::cout << "Status: " << toString(ret) << std::endl; + std::cout << "Status: " << statusStr << std::endl; - return ret == V1_0::Status::OK ? OK : ERROR; + return ret; } }; diff --git a/cmds/idlcli/vibrator/CommandOn.cpp b/cmds/idlcli/vibrator/CommandOn.cpp index 2164b7d149..ccb3c19ca8 100644 --- a/cmds/idlcli/vibrator/CommandOn.cpp +++ b/cmds/idlcli/vibrator/CommandOn.cpp @@ -50,15 +50,24 @@ class CommandOn : public Command { } Status doMain(Args && /*args*/) override { - auto ret = halCall(&V1_0::IVibrator::on, mDuration); + std::string statusStr; + Status ret; - if (!ret.isOk()) { + if (auto hal = getHal<aidl::IVibrator>()) { + auto status = hal->call(&aidl::IVibrator::on, mDuration, nullptr); + statusStr = status.toString8(); + ret = status.isOk() ? OK : ERROR; + } else if (auto hal = getHal<V1_0::IVibrator>()) { + auto status = hal->call(&V1_0::IVibrator::on, mDuration); + statusStr = toString(status); + ret = status.isOk() && status == V1_0::Status::OK ? OK : ERROR; + } else { return UNAVAILABLE; } - std::cout << "Status: " << toString(ret) << std::endl; + std::cout << "Status: " << statusStr << std::endl; - return ret == V1_0::Status::OK ? OK : ERROR; + return ret; } uint32_t mDuration; diff --git a/cmds/idlcli/vibrator/CommandPerform.cpp b/cmds/idlcli/vibrator/CommandPerform.cpp index 688cbd87a1..58d4e0ac16 100644 --- a/cmds/idlcli/vibrator/CommandPerform.cpp +++ b/cmds/idlcli/vibrator/CommandPerform.cpp @@ -23,6 +23,34 @@ class CommandVibrator; namespace vibrator { +/* + * The following static asserts are only relevant here because the argument + * parser uses a single implementation for determining the string names. + */ +static_assert(static_cast<uint8_t>(V1_0::EffectStrength::LIGHT) == + static_cast<uint8_t>(aidl::EffectStrength::LIGHT)); +static_assert(static_cast<uint8_t>(V1_0::EffectStrength::MEDIUM) == + static_cast<uint8_t>(aidl::EffectStrength::MEDIUM)); +static_assert(static_cast<uint8_t>(V1_0::EffectStrength::STRONG) == + static_cast<uint8_t>(aidl::EffectStrength::STRONG)); +static_assert(static_cast<uint8_t>(V1_3::Effect::CLICK) == + static_cast<uint8_t>(aidl::Effect::CLICK)); +static_assert(static_cast<uint8_t>(V1_3::Effect::DOUBLE_CLICK) == + static_cast<uint8_t>(aidl::Effect::DOUBLE_CLICK)); +static_assert(static_cast<uint8_t>(V1_3::Effect::TICK) == static_cast<uint8_t>(aidl::Effect::TICK)); +static_assert(static_cast<uint8_t>(V1_3::Effect::THUD) == static_cast<uint8_t>(aidl::Effect::THUD)); +static_assert(static_cast<uint8_t>(V1_3::Effect::POP) == static_cast<uint8_t>(aidl::Effect::POP)); +static_assert(static_cast<uint8_t>(V1_3::Effect::HEAVY_CLICK) == + static_cast<uint8_t>(aidl::Effect::HEAVY_CLICK)); +static_assert(static_cast<uint8_t>(V1_3::Effect::RINGTONE_1) == + static_cast<uint8_t>(aidl::Effect::RINGTONE_1)); +static_assert(static_cast<uint8_t>(V1_3::Effect::RINGTONE_2) == + static_cast<uint8_t>(aidl::Effect::RINGTONE_2)); +static_assert(static_cast<uint8_t>(V1_3::Effect::RINGTONE_15) == + static_cast<uint8_t>(aidl::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; @@ -62,38 +90,50 @@ class CommandPerform : public Command { } Status doMain(Args && /*args*/) override { - Return<void> ret; - V1_0::Status status; + std::string statusStr; uint32_t lengthMs; - auto callback = [&status, &lengthMs](V1_0::Status retStatus, uint32_t retLengthMs) { - status = retStatus; - lengthMs = retLengthMs; - }; - - if (auto hal = getHal<V1_3::IVibrator>()) { - ret = hal->call(&V1_3::IVibrator::perform_1_3, static_cast<V1_3::Effect>(mEffect), - mStrength, callback); - } else if (auto hal = getHal<V1_2::IVibrator>()) { - ret = hal->call(&V1_2::IVibrator::perform_1_2, static_cast<V1_2::Effect>(mEffect), - mStrength, callback); - } else if (auto hal = getHal<V1_1::IVibrator>()) { - ret = hal->call(&V1_1::IVibrator::perform_1_1, static_cast<V1_1::Effect_1_1>(mEffect), - mStrength, callback); - } else if (auto hal = getHal<V1_0::IVibrator>()) { - ret = hal->call(&V1_0::IVibrator::perform, static_cast<V1_0::Effect>(mEffect), - mStrength, callback); + Status ret; + + if (auto hal = getHal<aidl::IVibrator>()) { + int32_t aidlLengthMs; + auto status = + hal->call(&aidl::IVibrator::perform, static_cast<aidl::Effect>(mEffect), + static_cast<aidl::EffectStrength>(mStrength), nullptr, &aidlLengthMs); + statusStr = status.toString8(); + lengthMs = static_cast<uint32_t>(aidlLengthMs); + ret = status.isOk() ? OK : ERROR; } else { - ret = NullptrStatus<void>(); - } - - if (!ret.isOk()) { - return UNAVAILABLE; + Return<void> hidlRet; + V1_0::Status status; + auto callback = [&status, &lengthMs](V1_0::Status retStatus, uint32_t retLengthMs) { + status = retStatus; + lengthMs = retLengthMs; + }; + + if (auto hal = getHal<V1_3::IVibrator>()) { + hidlRet = hal->call(&V1_3::IVibrator::perform_1_3, + static_cast<V1_3::Effect>(mEffect), 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); + } 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); + } else if (auto hal = getHal<V1_0::IVibrator>()) { + hidlRet = hal->call(&V1_0::IVibrator::perform, static_cast<V1_0::Effect>(mEffect), + mStrength, callback); + } else { + return UNAVAILABLE; + } + + statusStr = toString(status); + ret = hidlRet.isOk() && status == V1_0::Status::OK ? OK : ERROR; } - std::cout << "Status: " << toString(status) << std::endl; + std::cout << "Status: " << statusStr << std::endl; std::cout << "Length: " << lengthMs << std::endl; - return status == V1_0::Status::OK ? OK : ERROR; + return ret; } Effect mEffect; diff --git a/cmds/idlcli/vibrator/CommandSetAmplitude.cpp b/cmds/idlcli/vibrator/CommandSetAmplitude.cpp index 38a1dc279b..33d7eed5be 100644 --- a/cmds/idlcli/vibrator/CommandSetAmplitude.cpp +++ b/cmds/idlcli/vibrator/CommandSetAmplitude.cpp @@ -50,15 +50,25 @@ class CommandSetAmplitude : public Command { } Status doMain(Args && /*args*/) override { - auto ret = halCall(&V1_0::IVibrator::setAmplitude, mAmplitude); + std::string statusStr; + Status ret; - if (!ret.isOk()) { + if (auto hal = getHal<aidl::IVibrator>()) { + auto status = hal->call(&aidl::IVibrator::setAmplitude, + static_cast<float>(mAmplitude) / UINT8_MAX); + statusStr = status.toString8(); + ret = status.isOk() ? OK : ERROR; + } else if (auto hal = getHal<V1_0::IVibrator>()) { + auto status = hal->call(&V1_0::IVibrator::setAmplitude, mAmplitude); + statusStr = toString(status); + ret = status.isOk() && status == V1_0::Status::OK ? OK : ERROR; + } else { return UNAVAILABLE; } - std::cout << "Status: " << toString(ret) << std::endl; + std::cout << "Status: " << statusStr << std::endl; - return ret == V1_0::Status::OK ? OK : ERROR; + return ret; } uint8_t mAmplitude; diff --git a/cmds/idlcli/vibrator/CommandSetExternalControl.cpp b/cmds/idlcli/vibrator/CommandSetExternalControl.cpp index 5fb1faca16..5bc827e707 100644 --- a/cmds/idlcli/vibrator/CommandSetExternalControl.cpp +++ b/cmds/idlcli/vibrator/CommandSetExternalControl.cpp @@ -48,15 +48,24 @@ class CommandSetExternalControl : public Command { } Status doMain(Args && /*args*/) override { - auto ret = halCall(&V1_3::IVibrator::setExternalControl, mEnable); + std::string statusStr; + Status ret; - if (!ret.isOk()) { + if (auto hal = getHal<aidl::IVibrator>()) { + auto status = hal->call(&aidl::IVibrator::setExternalControl, mEnable); + statusStr = status.toString8(); + ret = status.isOk() ? OK : ERROR; + } else if (auto hal = getHal<V1_3::IVibrator>()) { + auto status = hal->call(&V1_3::IVibrator::setExternalControl, mEnable); + statusStr = toString(status); + ret = status.isOk() && status == V1_0::Status::OK ? OK : ERROR; + } else { return UNAVAILABLE; } - std::cout << "Status: " << toString(ret) << std::endl; + std::cout << "Status: " << statusStr << std::endl; - return ret == V1_0::Status::OK ? OK : ERROR; + return ret; } bool mEnable; diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp index 4026f29208..b23d69c52f 100644 --- a/cmds/installd/InstalldNativeService.cpp +++ b/cmds/installd/InstalldNativeService.cpp @@ -101,6 +101,7 @@ static constexpr const char* IDMAP_SUFFIX = "@idmap"; static constexpr int kVerityPageSize = 4096; static constexpr size_t kSha256Size = 32; static constexpr const char* kPropApkVerityMode = "ro.apk_verity.mode"; +static constexpr const char* kFuseProp = "persist.sys.fuse"; namespace { @@ -592,12 +593,21 @@ binder::Status InstalldNativeService::clearAppData(const std::unique_ptr<std::st std::lock_guard<std::recursive_mutex> lock(mMountsLock); for (const auto& n : mStorageMounts) { auto extPath = n.second; - if (n.first.compare(0, 14, "/mnt/media_rw/") != 0) { - extPath += StringPrintf("/%d", userId); - } else if (userId != 0) { - // TODO: support devices mounted under secondary users - continue; + + if (android::base::GetBoolProperty(kFuseProp, false)) { + std::regex re("^\\/mnt\\/pass_through\\/[0-9]+\\/emulated"); + if (std::regex_match(extPath, re)) { + extPath += "/" + std::to_string(userId); + } + } else { + if (n.first.compare(0, 14, "/mnt/media_rw/") != 0) { + extPath += StringPrintf("/%d", userId); + } else if (userId != 0) { + // TODO: support devices mounted under secondary users + continue; + } } + if (flags & FLAG_CLEAR_CACHE_ONLY) { // Clear only cached data from shared storage auto path = StringPrintf("%s/Android/data/%s/cache", extPath.c_str(), pkgname); @@ -688,16 +698,26 @@ binder::Status InstalldNativeService::destroyAppData(const std::unique_ptr<std:: std::lock_guard<std::recursive_mutex> lock(mMountsLock); for (const auto& n : mStorageMounts) { auto extPath = n.second; - if (n.first.compare(0, 14, "/mnt/media_rw/") != 0) { - extPath += StringPrintf("/%d", userId); - } else if (userId != 0) { - // TODO: support devices mounted under secondary users - continue; + + if (android::base::GetBoolProperty(kFuseProp, false)) { + std::regex re("^\\/mnt\\/pass_through\\/[0-9]+\\/emulated"); + if (std::regex_match(extPath, re)) { + extPath += "/" + std::to_string(userId); + } + } else { + if (n.first.compare(0, 14, "/mnt/media_rw/") != 0) { + extPath += StringPrintf("/%d", userId); + } else if (userId != 0) { + // TODO: support devices mounted under secondary users + continue; + } } + auto path = StringPrintf("%s/Android/data/%s", extPath.c_str(), pkgname); if (delete_dir_contents_and_dir(path, true) != 0) { res = error("Failed to delete contents of " + path); } + path = StringPrintf("%s/Android/media/%s", extPath.c_str(), pkgname); if (delete_dir_contents_and_dir(path, true) != 0) { res = error("Failed to delete contents of " + path); @@ -2778,12 +2798,19 @@ binder::Status InstalldNativeService::invalidateMounts() { std::getline(in, target, ' '); std::getline(in, ignored); + if (android::base::GetBoolProperty(kFuseProp, false)) { + if (target.compare(0, 17, "/mnt/pass_through") == 0) { + LOG(DEBUG) << "Found storage mount " << source << " at " << target; + mStorageMounts[source] = target; + } + } else { #if !BYPASS_SDCARDFS - if (target.compare(0, 21, "/mnt/runtime/default/") == 0) { - LOG(DEBUG) << "Found storage mount " << source << " at " << target; - mStorageMounts[source] = target; - } + if (target.compare(0, 21, "/mnt/runtime/default/") == 0) { + LOG(DEBUG) << "Found storage mount " << source << " at " << target; + mStorageMounts[source] = target; + } #endif + } } return ok(); } diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp index 838d11d6d8..f95e445ade 100644 --- a/cmds/installd/dexopt.cpp +++ b/cmds/installd/dexopt.cpp @@ -339,6 +339,10 @@ class RunDex2Oat : public ExecVHelper { ? "dalvik.vm.dex2oat-threads" : "dalvik.vm.boot-dex2oat-threads"; std::string dex2oat_threads_arg = MapPropertyToArg(threads_property, "-j%s"); + const char* cpu_set_property = post_bootcomplete + ? "dalvik.vm.dex2oat-cpu-set" + : "dalvik.vm.boot-dex2oat-cpu-set"; + std::string dex2oat_cpu_set_arg = MapPropertyToArg(cpu_set_property, "--cpu-set=%s"); std::string bootclasspath; char* dex2oat_bootclasspath = getenv("DEX2OATBOOTCLASSPATH"); @@ -518,6 +522,7 @@ class RunDex2Oat : public ExecVHelper { AddArg(image_block_size_arg); AddArg(dex2oat_compiler_filter_arg); AddArg(dex2oat_threads_arg); + AddArg(dex2oat_cpu_set_arg); AddArg(dex2oat_swap_fd); AddArg(dex2oat_image_fd); @@ -708,11 +713,13 @@ static void open_profile_files(uid_t uid, const std::string& package_name, } } -static constexpr int PROFMAN_BIN_RETURN_CODE_COMPILE = 0; -static constexpr int PROFMAN_BIN_RETURN_CODE_SKIP_COMPILATION = 1; -static constexpr int PROFMAN_BIN_RETURN_CODE_BAD_PROFILES = 2; -static constexpr int PROFMAN_BIN_RETURN_CODE_ERROR_IO = 3; -static constexpr int PROFMAN_BIN_RETURN_CODE_ERROR_LOCKING = 4; +static constexpr int PROFMAN_BIN_RETURN_CODE_SUCCESS = 0; +static constexpr int PROFMAN_BIN_RETURN_CODE_COMPILE = 1; +static constexpr int PROFMAN_BIN_RETURN_CODE_SKIP_COMPILATION = 2; +static constexpr int PROFMAN_BIN_RETURN_CODE_BAD_PROFILES = 3; +static constexpr int PROFMAN_BIN_RETURN_CODE_ERROR_IO = 4; +static constexpr int PROFMAN_BIN_RETURN_CODE_ERROR_LOCKING = 5; +static constexpr int PROFMAN_BIN_RETURN_CODE_ERROR_DIFFERENT_VERSIONS = 6; class RunProfman : public ExecVHelper { public: @@ -720,7 +727,9 @@ class RunProfman : public ExecVHelper { const unique_fd& reference_profile_fd, const std::vector<unique_fd>& apk_fds, const std::vector<std::string>& dex_locations, - bool copy_and_update) { + bool copy_and_update, + bool for_snapshot, + bool for_boot_image) { // TODO(calin): Assume for now we run in the bg compile job (which is in // most of the invocation). With the current data flow, is not very easy or @@ -752,6 +761,14 @@ class RunProfman : public ExecVHelper { AddArg("--copy-and-update-profile-key"); } + if (for_snapshot) { + AddArg("--force-merge"); + } + + if (for_boot_image) { + AddArg("--boot-image-merge"); + } + // Do not add after dex2oat_flags, they should override others for debugging. PrepareArgs(profman_bin); } @@ -759,12 +776,16 @@ class RunProfman : public ExecVHelper { void SetupMerge(const std::vector<unique_fd>& profiles_fd, const unique_fd& reference_profile_fd, const std::vector<unique_fd>& apk_fds = std::vector<unique_fd>(), - const std::vector<std::string>& dex_locations = std::vector<std::string>()) { + const std::vector<std::string>& dex_locations = std::vector<std::string>(), + bool for_snapshot = false, + bool for_boot_image = false) { SetupArgs(profiles_fd, reference_profile_fd, apk_fds, dex_locations, - /*copy_and_update=*/false); + /*copy_and_update=*/ false, + for_snapshot, + for_boot_image); } void SetupCopyAndUpdate(unique_fd&& profile_fd, @@ -781,7 +802,9 @@ class RunProfman : public ExecVHelper { reference_profile_fd_, apk_fds_, dex_locations, - /*copy_and_update=*/true); + /*copy_and_update=*/true, + /*for_snapshot*/false, + /*for_boot_image*/false); } void SetupDump(const std::vector<unique_fd>& profiles_fd, @@ -795,7 +818,9 @@ class RunProfman : public ExecVHelper { reference_profile_fd, apk_fds, dex_locations, - /*copy_and_update=*/false); + /*copy_and_update=*/false, + /*for_snapshot*/false, + /*for_boot_image*/false); } void Exec() { @@ -870,9 +895,14 @@ static bool analyze_profiles(uid_t uid, const std::string& package_name, should_clear_current_profiles = false; should_clear_reference_profile = false; break; + case PROFMAN_BIN_RETURN_CODE_ERROR_DIFFERENT_VERSIONS: + need_to_compile = false; + should_clear_current_profiles = true; + should_clear_reference_profile = true; + break; default: // Unknown return code or error. Unlink profiles. - LOG(WARNING) << "Unknown error code while processing profiles for location " + LOG(WARNING) << "Unexpected error code while processing profiles for location " << location << ": " << return_code; need_to_compile = false; should_clear_current_profiles = true; @@ -2741,7 +2771,7 @@ static bool create_app_profile_snapshot(int32_t app_id, } RunProfman args; - args.SetupMerge(profiles_fd, snapshot_fd, apk_fds, dex_locations); + args.SetupMerge(profiles_fd, snapshot_fd, apk_fds, dex_locations, /*for_snapshot=*/true); pid_t pid = fork(); if (pid == 0) { /* child -- drop privileges before continuing */ @@ -2756,6 +2786,13 @@ static bool create_app_profile_snapshot(int32_t app_id, return false; } + // Verify that profman finished successfully. + int profman_code = WEXITSTATUS(return_code); + if (profman_code != PROFMAN_BIN_RETURN_CODE_SUCCESS) { + LOG(WARNING) << "profman error for " << package_name << ":" << profile_name + << ":" << profman_code; + return false; + } return true; } @@ -2818,19 +2855,29 @@ static bool create_boot_image_profile_snapshot(const std::string& package_name, // We do this to avoid opening a huge a amount of files. static constexpr size_t kAggregationBatchSize = 10; - std::vector<unique_fd> profiles_fd; for (size_t i = 0; i < profiles.size(); ) { + std::vector<unique_fd> profiles_fd; for (size_t k = 0; k < kAggregationBatchSize && i < profiles.size(); k++, i++) { unique_fd fd = open_profile(AID_SYSTEM, profiles[i], O_RDONLY); if (fd.get() >= 0) { profiles_fd.push_back(std::move(fd)); } } + + // We aggregate (read & write) into the same fd multiple times in a row. + // We need to reset the cursor every time to ensure we read the whole file every time. + if (TEMP_FAILURE_RETRY(lseek(snapshot_fd, 0, SEEK_SET)) == static_cast<off_t>(-1)) { + PLOG(ERROR) << "Cannot reset position for snapshot profile"; + return false; + } + RunProfman args; args.SetupMerge(profiles_fd, snapshot_fd, apk_fds, - dex_locations); + dex_locations, + /*for_snapshot=*/true, + /*for_boot_image=*/true); pid_t pid = fork(); if (pid == 0) { /* child -- drop privileges before continuing */ @@ -2843,12 +2890,21 @@ static bool create_boot_image_profile_snapshot(const std::string& package_name, /* parent */ int return_code = wait_child(pid); + if (!WIFEXITED(return_code)) { PLOG(WARNING) << "profman failed for " << package_name << ":" << profile_name; return false; } - return true; + + // Verify that profman finished successfully. + int profman_code = WEXITSTATUS(return_code); + if (profman_code != PROFMAN_BIN_RETURN_CODE_SUCCESS) { + LOG(WARNING) << "profman error for " << package_name << ":" << profile_name + << ":" << profman_code; + return false; + } } + return true; } diff --git a/cmds/installd/migrate_legacy_obb_data.sh b/cmds/installd/migrate_legacy_obb_data.sh index 10756881be..7399681c3e 100644 --- a/cmds/installd/migrate_legacy_obb_data.sh +++ b/cmds/installd/migrate_legacy_obb_data.sh @@ -15,17 +15,17 @@ # See the License for the specific language governing permissions and # limitations under the License. -rm -rf /sdcard/Android/obb/test_probe -mkdir -p /sdcard/Android/obb/ -touch /sdcard/Android/obb/test_probe +rm -rf /data/media/0/Android/obb/test_probe +mkdir -p /data/media/0/Android/obb/ +touch /data/media/0/Android/obb/test_probe if ! test -f /data/media/0/Android/obb/test_probe ; then log -p i -t migrate_legacy_obb_data "No support for 'unshared_obb'. Not migrating" - rm -rf /sdcard/Android/obb/test_probe + rm -rf /data/media/0/Android/obb/test_probe exit 0 fi # Delete the test file, and remove the obb folder if it is empty -rm -rf /sdcard/Android/obb/test_probe +rm -rf /data/media/0/Android/obb/test_probe rmdir /data/media/obb if ! test -d /data/media/obb ; then diff --git a/cmds/installd/otapreopt.cpp b/cmds/installd/otapreopt.cpp index db36ce3c9e..eefbe4ffe2 100644 --- a/cmds/installd/otapreopt.cpp +++ b/cmds/installd/otapreopt.cpp @@ -480,6 +480,10 @@ private: "-j", false, cmd); + AddCompilerOptionFromSystemProperty("dalvik.vm.image-dex2oat-cpu-set", + "--cpu-set=", + false, + cmd); AddCompilerOptionFromSystemProperty( StringPrintf("dalvik.vm.isa.%s.variant", isa).c_str(), "--instruction-set-variant=", diff --git a/cmds/installd/tests/installd_dexopt_test.cpp b/cmds/installd/tests/installd_dexopt_test.cpp index 0212bc5564..69fefa199b 100644 --- a/cmds/installd/tests/installd_dexopt_test.cpp +++ b/cmds/installd/tests/installd_dexopt_test.cpp @@ -897,7 +897,9 @@ class ProfileTest : public DexoptTest { std::string expected_profile_content = snap_profile_ + ".expected"; run_cmd("rm -f " + expected_profile_content); run_cmd("touch " + expected_profile_content); - run_cmd("profman --profile-file=" + cur_profile_ + + // We force merging when creating the expected profile to make sure + // that the random profiles do not affect the output. + run_cmd("profman --force-merge --profile-file=" + cur_profile_ + " --profile-file=" + ref_profile_ + " --reference-profile-file=" + expected_profile_content + " --apk=" + apk_path_); @@ -1130,16 +1132,60 @@ TEST_F(ProfileTest, ProfilePrepareFailProfileChangedUid) { class BootProfileTest : public ProfileTest { public: - virtual void setup() { + std::vector<const std::string> extra_apps_; + std::vector<int64_t> extra_ce_data_inodes_; + + virtual void SetUp() { + ProfileTest::SetUp(); intial_android_profiles_dir = android_profiles_dir; + // Generate profiles for some extra apps. + // When merging boot profile we split profiles into small groups to avoid + // opening a lot of file descriptors at the same time. + // (Currently the group size for aggregation is 10) + // + // To stress test that works fine, create profile for more apps. + createAppProfilesForBootMerge(21); } virtual void TearDown() { android_profiles_dir = intial_android_profiles_dir; + deleteAppProfilesForBootMerge(); ProfileTest::TearDown(); } + void createAppProfilesForBootMerge(size_t number_of_profiles) { + for (size_t i = 0; i < number_of_profiles; i++) { + int64_t ce_data_inode; + std::string package_name = "dummy_test_pkg" + std::to_string(i); + LOG(INFO) << package_name; + ASSERT_BINDER_SUCCESS(service_->createAppData( + volume_uuid_, + package_name, + kTestUserId, + kAppDataFlags, + kTestAppUid, + se_info_, + kOSdkVersion, + &ce_data_inode)); + extra_apps_.push_back(package_name); + extra_ce_data_inodes_.push_back(ce_data_inode); + std::string profile = create_current_profile_path( + kTestUserId, package_name, kPrimaryProfile, /*is_secondary_dex*/ false); + SetupProfile(profile, kTestAppUid, kTestAppGid, 0600, 1); + } + } + + void deleteAppProfilesForBootMerge() { + if (kDebug) { + return; + } + for (size_t i = 0; i < extra_apps_.size(); i++) { + service_->destroyAppData( + volume_uuid_, extra_apps_[i], kTestUserId, kAppDataFlags, extra_ce_data_inodes_[i]); + } + } + void UpdateAndroidProfilesDir(const std::string& profile_dir) { android_profiles_dir = profile_dir; // We need to create the reference profile directory in the new profile dir. diff --git a/cmds/servicemanager/ServiceManager.cpp b/cmds/servicemanager/ServiceManager.cpp index 934436847e..141171bf68 100644 --- a/cmds/servicemanager/ServiceManager.cpp +++ b/cmds/servicemanager/ServiceManager.cpp @@ -34,11 +34,7 @@ using ::android::internal::Stability; namespace android { #ifndef VENDORSERVICEMANAGER -static bool meetsDeclarationRequirements(const sp<IBinder>& binder, const std::string& name) { - if (!Stability::requiresVintfDeclaration(binder)) { - return true; - } - +static bool isVintfDeclared(const std::string& name) { size_t firstSlash = name.find('/'); size_t lastDot = name.rfind('.', firstSlash); if (firstSlash == std::string::npos || lastDot == std::string::npos) { @@ -54,7 +50,7 @@ static bool meetsDeclarationRequirements(const sp<IBinder>& binder, const std::s vintf::VintfObject::GetDeviceHalManifest(), vintf::VintfObject::GetFrameworkHalManifest() }) { - if (manifest->hasAidlInstance(package, iface, instance)) { + if (manifest != nullptr && manifest->hasAidlInstance(package, iface, instance)) { return true; } } @@ -62,9 +58,25 @@ static bool meetsDeclarationRequirements(const sp<IBinder>& binder, const std::s << " in the VINTF manifest."; return false; } + +static bool meetsDeclarationRequirements(const sp<IBinder>& binder, const std::string& name) { + if (!Stability::requiresVintfDeclaration(binder)) { + return true; + } + + return isVintfDeclared(name); +} #endif // !VENDORSERVICEMANAGER -ServiceManager::ServiceManager(std::unique_ptr<Access>&& access) : mAccess(std::move(access)) {} +ServiceManager::ServiceManager(std::unique_ptr<Access>&& access) : mAccess(std::move(access)) { +#ifndef VENDORSERVICEMANAGER + // can process these at any times, don't want to delay first VINTF client + std::thread([] { + vintf::VintfObject::GetDeviceHalManifest(); + vintf::VintfObject::GetFrameworkHalManifest(); + }).detach(); +#endif // !VENDORSERVICEMANAGER +} ServiceManager::~ServiceManager() { // this should only happen in tests @@ -165,7 +177,7 @@ Status ServiceManager::addService(const std::string& name, const sp<IBinder>& bi #endif // !VENDORSERVICEMANAGER // implicitly unlinked when the binder is removed - if (OK != binder->linkToDeath(this)) { + if (binder->remoteBinder() != nullptr && binder->linkToDeath(this) != OK) { LOG(ERROR) << "Could not linkToDeath when adding " << name; return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE); } @@ -270,6 +282,21 @@ Status ServiceManager::unregisterForNotifications( return Status::ok(); } +Status ServiceManager::isDeclared(const std::string& name, bool* outReturn) { + auto ctx = mAccess->getCallingContext(); + + if (!mAccess->canFind(ctx, name)) { + return Status::fromExceptionCode(Status::EX_SECURITY); + } + + *outReturn = false; + +#ifndef VENDORSERVICEMANAGER + *outReturn = isVintfDeclared(name); +#endif + return Status::ok(); +} + void ServiceManager::removeCallback(const wp<IBinder>& who, CallbackMap::iterator* it, bool* found) { @@ -287,7 +314,7 @@ void ServiceManager::removeCallback(const wp<IBinder>& who, if (listeners.empty()) { *it = mNameToCallback.erase(*it); } else { - it++; + (*it)++; } } diff --git a/cmds/servicemanager/ServiceManager.h b/cmds/servicemanager/ServiceManager.h index 006e51947b..7dcdaa4661 100644 --- a/cmds/servicemanager/ServiceManager.h +++ b/cmds/servicemanager/ServiceManager.h @@ -40,6 +40,7 @@ public: const sp<IServiceCallback>& callback) override; binder::Status unregisterForNotifications(const std::string& name, const sp<IServiceCallback>& callback) override; + binder::Status isDeclared(const std::string& name, bool* outReturn) override; void binderDied(const wp<IBinder>& who) override; diff --git a/cmds/servicemanager/main.cpp b/cmds/servicemanager/main.cpp index 11d43a6ee3..4b12fc6e72 100644 --- a/cmds/servicemanager/main.cpp +++ b/cmds/servicemanager/main.cpp @@ -23,11 +23,12 @@ #include "Access.h" #include "ServiceManager.h" -using ::android::sp; -using ::android::ProcessState; +using ::android::Access; using ::android::IPCThreadState; +using ::android::ProcessState; using ::android::ServiceManager; -using ::android::Access; +using ::android::os::IServiceManager; +using ::android::sp; int main(int argc, char** argv) { if (argc > 2) { @@ -41,6 +42,10 @@ int main(int argc, char** argv) { ps->setCallRestriction(ProcessState::CallRestriction::FATAL_IF_NOT_ONEWAY); sp<ServiceManager> manager = new ServiceManager(std::make_unique<Access>()); + if (!manager->addService("manager", manager, false /*allowIsolated*/, IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()) { + LOG(ERROR) << "Could not self register servicemanager"; + } + IPCThreadState::self()->setTheContextObject(manager); ps->becomeContextManager(nullptr, nullptr); diff --git a/data/etc/car_core_hardware.xml b/data/etc/car_core_hardware.xml index ad7791e078..50f117dd11 100644 --- a/data/etc/car_core_hardware.xml +++ b/data/etc/car_core_hardware.xml @@ -40,7 +40,6 @@ <feature name="android.software.voice_recognizers" notLowRam="true" /> <feature name="android.software.backup" /> <feature name="android.software.home_screen" /> - <feature name="android.software.print" /> <feature name="android.software.companion_device_setup" /> <feature name="android.software.autofill" /> <feature name="android.software.cant_save_state" /> diff --git a/headers/media_plugin/media/cas/CasAPI.h b/headers/media_plugin/media/cas/CasAPI.h index c87ee5655e..8cc9d365a2 100644 --- a/headers/media_plugin/media/cas/CasAPI.h +++ b/headers/media_plugin/media/cas/CasAPI.h @@ -56,6 +56,11 @@ typedef void (*CasPluginCallbackExt)( size_t size, const CasSessionId *sessionId); +typedef void (*CasPluginStatusCallback)( + void *appData, + int32_t event, + int32_t arg); + struct CasFactory { CasFactory() {} virtual ~CasFactory() {} @@ -91,6 +96,10 @@ struct CasPlugin { CasPlugin() {} virtual ~CasPlugin() {} + // Provide a callback to report plugin status + virtual status_t setStatusCallback( + CasPluginStatusCallback callback) = 0; + // Provide the CA private data from a CA_descriptor in the conditional // access table to a CasPlugin. virtual status_t setPrivateData( @@ -100,6 +109,11 @@ struct CasPlugin { // streams. virtual status_t openSession(CasSessionId *sessionId) = 0; + // Open a session with intend and mode for descrambling a program, or one + // or more elementary streams. + virtual status_t openSession(uint32_t intent, uint32_t mode, + CasSessionId *sessionId) = 0; + // Close a previously opened session. virtual status_t closeSession(const CasSessionId &sessionId) = 0; diff --git a/headers/media_plugin/media/openmax/OMX_Video.h b/headers/media_plugin/media/openmax/OMX_Video.h index b6edaa900e..81ee5fb2e5 100644 --- a/headers/media_plugin/media/openmax/OMX_Video.h +++ b/headers/media_plugin/media/openmax/OMX_Video.h @@ -90,6 +90,7 @@ typedef enum OMX_VIDEO_CODINGTYPE { OMX_VIDEO_CodingHEVC, /**< ITU H.265/HEVC */ OMX_VIDEO_CodingDolbyVision,/**< Dolby Vision */ OMX_VIDEO_CodingImageHEIC, /**< HEIF image encoded with HEVC */ + OMX_VIDEO_CodingAV1, /**< AV1 */ OMX_VIDEO_CodingKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ OMX_VIDEO_CodingVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */ OMX_VIDEO_CodingMax = 0x7FFFFFFF diff --git a/include/android/choreographer.h b/include/android/choreographer.h index 44883cc498..346861f0a8 100644 --- a/include/android/choreographer.h +++ b/include/android/choreographer.h @@ -59,6 +59,8 @@ typedef void (*AChoreographer_frameCallback64)(int64_t frameTimeNanos, void* dat /** * Get the AChoreographer instance for the current thread. This must be called * on an ALooper thread. + * + * Available since API level 24. */ AChoreographer* AChoreographer_getInstance() __INTRODUCED_IN(24); @@ -82,6 +84,8 @@ void AChoreographer_postFrameCallbackDelayed(AChoreographer* choreographer, /** * Power a callback to be run on the next frame. The data pointer provided will * be passed to the callback function when it's called. + * + * Available since API level 29. */ void AChoreographer_postFrameCallback64(AChoreographer* chroreographer, AChoreographer_frameCallback64 callback, void* data) __INTRODUCED_IN(29); @@ -90,6 +94,8 @@ void AChoreographer_postFrameCallback64(AChoreographer* chroreographer, * Post a callback to be run on the frame following the specified delay. The * data pointer provided will be passed to the callback function when it's * called. + * + * Available since API level 29. */ void AChoreographer_postFrameCallbackDelayed64(AChoreographer* choreographer, AChoreographer_frameCallback64 callback, void* data, uint32_t delayMillis) __INTRODUCED_IN(29); diff --git a/include/android/configuration.h b/include/android/configuration.h index ef6c5a2f81..331072238b 100644 --- a/include/android/configuration.h +++ b/include/android/configuration.h @@ -675,50 +675,52 @@ int32_t AConfiguration_getUiModeNight(AConfiguration* config); */ void AConfiguration_setUiModeNight(AConfiguration* config, int32_t uiModeNight); -#if __ANDROID_API__ >= 13 /** * Return the current configuration screen width in dp units, or * ACONFIGURATION_SCREEN_WIDTH_DP_ANY if not set. */ -int32_t AConfiguration_getScreenWidthDp(AConfiguration* config) __INTRODUCED_IN(13); +int32_t AConfiguration_getScreenWidthDp(AConfiguration* config); /** * Set the configuration's current screen width in dp units. */ -void AConfiguration_setScreenWidthDp(AConfiguration* config, int32_t value) __INTRODUCED_IN(13); +void AConfiguration_setScreenWidthDp(AConfiguration* config, int32_t value); /** * Return the current configuration screen height in dp units, or * ACONFIGURATION_SCREEN_HEIGHT_DP_ANY if not set. */ -int32_t AConfiguration_getScreenHeightDp(AConfiguration* config) __INTRODUCED_IN(13); +int32_t AConfiguration_getScreenHeightDp(AConfiguration* config); /** * Set the configuration's current screen width in dp units. */ -void AConfiguration_setScreenHeightDp(AConfiguration* config, int32_t value) __INTRODUCED_IN(13); +void AConfiguration_setScreenHeightDp(AConfiguration* config, int32_t value); /** * Return the configuration's smallest screen width in dp units, or * ACONFIGURATION_SMALLEST_SCREEN_WIDTH_DP_ANY if not set. */ -int32_t AConfiguration_getSmallestScreenWidthDp(AConfiguration* config) __INTRODUCED_IN(13); +int32_t AConfiguration_getSmallestScreenWidthDp(AConfiguration* config); /** * Set the configuration's smallest screen width in dp units. */ -void AConfiguration_setSmallestScreenWidthDp(AConfiguration* config, int32_t value) __INTRODUCED_IN(13); -#endif /* __ANDROID_API__ >= 13 */ +void AConfiguration_setSmallestScreenWidthDp(AConfiguration* config, int32_t value); #if __ANDROID_API__ >= 17 /** * Return the configuration's layout direction, or * ACONFIGURATION_LAYOUTDIR_ANY if not set. + * + * Available since API level 17. */ int32_t AConfiguration_getLayoutDirection(AConfiguration* config) __INTRODUCED_IN(17); /** * Set the configuration's layout direction. + * + * Available since API level 17. */ void AConfiguration_setLayoutDirection(AConfiguration* config, int32_t value) __INTRODUCED_IN(17); #endif /* __ANDROID_API__ >= 17 */ diff --git a/include/android/font.h b/include/android/font.h index 8001ee1938..1618096d69 100644 --- a/include/android/font.h +++ b/include/android/font.h @@ -96,6 +96,8 @@ struct AFont; /** * Close an AFont. * + * Available since API level 29. + * * \param font a font returned by ASystemFontIterator_next or AFontMatchert_match. * Do nothing if NULL is passed. */ @@ -116,6 +118,8 @@ void AFont_close(AFont* _Nullable font) __INTRODUCED_IN(29); * The font file returned is guaranteed to be opend with O_RDONLY. * Note that the returned pointer is valid until AFont_close() is called for the given font. * + * Available since API level 29. + * * \param font a font object. Passing NULL is not allowed. * \return a string of the font file path. */ @@ -184,6 +188,8 @@ const char* _Nonnull AFont_getFontFilePath(const AFont* _Nonnull font) __INTRODU * * For more information about font weight, read [OpenType usWeightClass](https://docs.microsoft.com/en-us/typography/opentype/spec/os2#usweightclass) * + * Available since API level 29. + * * \param font a font object. Passing NULL is not allowed. * \return a positive integer less than or equal to {@link ASYSTEM_FONT_MAX_WEIGHT} is returned. */ @@ -192,6 +198,8 @@ uint16_t AFont_getWeight(const AFont* _Nonnull font) __INTRODUCED_IN(29); /** * Return true if the current font is italic, otherwise returns false. * + * Available since API level 29. + * * \param font a font object. Passing NULL is not allowed. * \return true if italic, otherwise false. */ @@ -204,6 +212,8 @@ bool AFont_isItalic(const AFont* _Nonnull font) __INTRODUCED_IN(29); * * Note that the returned pointer is valid until AFont_close() is called. * + * Available since API level 29. + * * \param font a font object. Passing NULL is not allowed. * \return a IETF BCP47 compliant language tag or nullptr if not available. */ @@ -216,6 +226,8 @@ const char* _Nullable AFont_getLocale(const AFont* _Nonnull font) __INTRODUCED_I * returns a non-negative value as an font offset in the collection. This * always returns 0 if the target font file is a regular font. * + * Available since API level 29. + * * \param font a font object. Passing NULL is not allowed. * \return a font collection index. */ @@ -247,6 +259,8 @@ size_t AFont_getCollectionIndex(const AFont* _Nonnull font) __INTRODUCED_IN(29); * * For more information about font variation settings, read [Font Variations Table](https://docs.microsoft.com/en-us/typography/opentype/spec/fvar) * + * Available since API level 29. + * * \param font a font object. Passing NULL is not allowed. * \return a number of font variation settings. */ @@ -258,6 +272,8 @@ size_t AFont_getAxisCount(const AFont* _Nonnull font) __INTRODUCED_IN(29); * * See AFont_getAxisCount for more details. * + * Available since API level 29. + * * \param font a font object. Passing NULL is not allowed. * \param axisIndex an index to the font variation settings. Passing value larger than or * equal to {@link AFont_getAxisCount} is not allowed. @@ -271,6 +287,8 @@ uint32_t AFont_getAxisTag(const AFont* _Nonnull font, uint32_t axisIndex) * * See AFont_getAxisCount for more details. * + * Available since API level 29. + * * \param font a font object. Passing NULL is not allowed. * \param axisIndex an index to the font variation settings. Passing value larger than or * equal to {@link ASYstemFont_getAxisCount} is not allwed. diff --git a/include/android/font_matcher.h b/include/android/font_matcher.h index 0b8f892b9b..d4bd892bf6 100644 --- a/include/android/font_matcher.h +++ b/include/android/font_matcher.h @@ -130,13 +130,17 @@ struct AFontMatcher; */ /** - * Creates a new AFontMatcher object + * Creates a new AFontMatcher object. + * + * Available since API level 29. */ AFontMatcher* _Nonnull AFontMatcher_create() __INTRODUCED_IN(29); /** * Destroy the matcher object. * + * Available since API level 29. + * * \param matcher a matcher object. Passing NULL is not allowed. */ void AFontMatcher_destroy(AFontMatcher* _Nonnull matcher) __INTRODUCED_IN(29); @@ -147,6 +151,8 @@ void AFontMatcher_destroy(AFontMatcher* _Nonnull matcher) __INTRODUCED_IN(29); * If this function is not called, the matcher performs with {@link ASYSTEM_FONT_WEIGHT_NORMAL} * with non-italic style. * + * Available since API level 29. + * * \param matcher a matcher object. Passing NULL is not allowed. * \param weight a font weight value. Only from 0 to 1000 value is valid * \param italic true if italic, otherwise false. @@ -161,6 +167,8 @@ void AFontMatcher_setStyle( * * If this function is not called, the matcher performs with empty locale list. * + * Available since API level 29. + * * \param matcher a matcher object. Passing NULL is not allowed. * \param languageTags a null character terminated comma separated IETF BCP47 compliant language * tags. @@ -174,6 +182,8 @@ void AFontMatcher_setLocales( * * If this function is not called, the matcher performs with {@link AFAMILY_VARIANT_DEFAULT}. * + * Available since API level 29. + * * \param matcher a matcher object. Passing NULL is not allowed. * \param familyVariant Must be one of {@link AFAMILY_VARIANT_DEFAULT}, * {@link AFAMILY_VARIANT_COMPACT} or {@link AFAMILY_VARIANT_ELEGANT} is valid. @@ -190,6 +200,8 @@ void AFontMatcher_setFamilyVariant( * Even if no font can render the given text, this function will return a non-null result for * drawing Tofu character. * + * Available since API level 29. + * * \param matcher a matcher object. Passing NULL is not allowed. * \param familyName a null character terminated font family name * \param text a UTF-16 encoded text buffer to be rendered. Do not pass empty string. diff --git a/include/android/hardware_buffer_jni.h b/include/android/hardware_buffer_jni.h index aedf36903d..293e5ac469 100644 --- a/include/android/hardware_buffer_jni.h +++ b/include/android/hardware_buffer_jni.h @@ -42,6 +42,8 @@ __BEGIN_DECLS * that is returned. To keep the AHardwareBuffer live after the Java * HardwareBuffer object got garbage collected, be sure to use AHardwareBuffer_acquire() * to acquire an additional reference. + * + * Available since API level 26. */ AHardwareBuffer* AHardwareBuffer_fromHardwareBuffer(JNIEnv* env, jobject hardwareBufferObj) __INTRODUCED_IN(26); @@ -49,6 +51,8 @@ AHardwareBuffer* AHardwareBuffer_fromHardwareBuffer(JNIEnv* env, /** * Return a new Java HardwareBuffer object that wraps the passed native * AHardwareBuffer object. + * + * Available since API level 26. */ jobject AHardwareBuffer_toHardwareBuffer(JNIEnv* env, AHardwareBuffer* hardwareBuffer) __INTRODUCED_IN(26); diff --git a/include/android/input.h b/include/android/input.h index cfade6c806..ce439c6d75 100644 --- a/include/android/input.h +++ b/include/android/input.h @@ -986,10 +986,8 @@ int32_t AMotionEvent_getFlags(const AInputEvent* motion_event); */ int32_t AMotionEvent_getMetaState(const AInputEvent* motion_event); -#if __ANDROID_API__ >= 14 /** Get the button state of all buttons that are pressed. */ -int32_t AMotionEvent_getButtonState(const AInputEvent* motion_event) __INTRODUCED_IN(14); -#endif +int32_t AMotionEvent_getButtonState(const AInputEvent* motion_event); /** * Get a bitfield indicating which edges, if any, were touched by this motion event. @@ -1054,14 +1052,12 @@ size_t AMotionEvent_getPointerCount(const AInputEvent* motion_event); */ int32_t AMotionEvent_getPointerId(const AInputEvent* motion_event, size_t pointer_index); -#if __ANDROID_API__ >= 14 /** * Get the tool type of a pointer for the given pointer index. * The tool type indicates the type of tool used to make contact such as a * finger or stylus, if known. */ -int32_t AMotionEvent_getToolType(const AInputEvent* motion_event, size_t pointer_index) __INTRODUCED_IN(14); -#endif +int32_t AMotionEvent_getToolType(const AInputEvent* motion_event, size_t pointer_index); /** * Get the original raw X coordinate of this event. @@ -1151,11 +1147,9 @@ float AMotionEvent_getToolMinor(const AInputEvent* motion_event, size_t pointer_ */ float AMotionEvent_getOrientation(const AInputEvent* motion_event, size_t pointer_index); -#if __ANDROID_API__ >= 13 /** Get the value of the request axis for the given pointer index. */ float AMotionEvent_getAxisValue(const AInputEvent* motion_event, - int32_t axis, size_t pointer_index) __INTRODUCED_IN(13); -#endif + int32_t axis, size_t pointer_index); /** * Get the number of historical points in this event. These are movements that @@ -1286,14 +1280,12 @@ float AMotionEvent_getHistoricalToolMinor(const AInputEvent* motion_event, size_ float AMotionEvent_getHistoricalOrientation(const AInputEvent* motion_event, size_t pointer_index, size_t history_index); -#if __ANDROID_API__ >= 13 /** * Get the historical value of the request axis for the given pointer index * that occurred between this event and the previous motion event. */ float AMotionEvent_getHistoricalAxisValue(const AInputEvent* motion_event, - int32_t axis, size_t pointer_index, size_t history_index) __INTRODUCED_IN(13); -#endif + int32_t axis, size_t pointer_index, size_t history_index); struct AInputQueue; diff --git a/include/android/multinetwork.h b/include/android/multinetwork.h index d31d1f122f..59b1deb595 100644 --- a/include/android/multinetwork.h +++ b/include/android/multinetwork.h @@ -69,6 +69,7 @@ typedef uint64_t net_handle_t; * * This is the equivalent of: [android.net.Network#bindSocket()](https://developer.android.com/reference/android/net/Network.html#bindSocket(java.net.Socket)) * + * Available since API level 23. */ int android_setsocknetwork(net_handle_t network, int fd) __INTRODUCED_IN(23); @@ -86,6 +87,7 @@ int android_setsocknetwork(net_handle_t network, int fd) __INTRODUCED_IN(23); * * This is the equivalent of: [android.net.ConnectivityManager#setProcessDefaultNetwork()](https://developer.android.com/reference/android/net/ConnectivityManager.html#setProcessDefaultNetwork(android.net.Network)) * + * Available since API level 23. */ int android_setprocnetwork(net_handle_t network) __INTRODUCED_IN(23); @@ -103,6 +105,7 @@ int android_setprocnetwork(net_handle_t network) __INTRODUCED_IN(23); * * This is the equivalent of: [android.net.Network#getAllByName()](https://developer.android.com/reference/android/net/Network.html#getAllByName(java.lang.String)) * + * Available since API level 23. */ int android_getaddrinfofornetwork(net_handle_t network, const char *node, const char *service, @@ -144,6 +147,8 @@ enum ResNsendFlags : uint32_t { * * Returns a file descriptor to watch for read events, or a negative * POSIX error code (see errno.h) if an immediate error occurs. + * + * Available since API level 29. */ int android_res_nquery(net_handle_t network, const char *dname, int ns_class, int ns_type, uint32_t flags) __INTRODUCED_IN(29); @@ -155,6 +160,8 @@ int android_res_nquery(net_handle_t network, * * Returns a file descriptor to watch for read events, or a negative * POSIX error code (see errno.h) if an immediate error occurs. + * + * Available since API level 29. */ int android_res_nsend(net_handle_t network, const uint8_t *msg, size_t msglen, uint32_t flags) __INTRODUCED_IN(29); @@ -163,6 +170,8 @@ int android_res_nsend(net_handle_t network, * Read a result for the query associated with the |fd| descriptor. * Closes |fd| before returning. * + * Available since 29. + * * Returns: * < 0: negative POSIX error code (see errno.h for possible values). |rcode| is not set. * >= 0: length of |answer|. |rcode| is the resolver return code (e.g., ns_r_nxdomain) @@ -173,6 +182,8 @@ int android_res_nresult(int fd, /** * Attempts to cancel the in-progress query associated with the |nsend_fd| * descriptor. + * + * Available since API level 29. */ void android_res_cancel(int nsend_fd) __INTRODUCED_IN(29); diff --git a/include/android/native_window_jni.h b/include/android/native_window_jni.h index 0c196b9671..3a77ffe86b 100644 --- a/include/android/native_window_jni.h +++ b/include/android/native_window_jni.h @@ -51,6 +51,8 @@ ANativeWindow* ANativeWindow_fromSurface(JNIEnv* env, jobject surface); * the ANativeWindow; maintains it through general Java object's life cycle; * and will automatically release the reference when the Java object gets garbage * collected. + * + * Available since API level 26. */ jobject ANativeWindow_toSurface(JNIEnv* env, ANativeWindow* window) __INTRODUCED_IN(26); #endif diff --git a/include/android/sensor.h b/include/android/sensor.h index e9d5c16d0d..3ebe79fd2e 100644 --- a/include/android/sensor.h +++ b/include/android/sensor.h @@ -564,6 +564,7 @@ ASensorManager* ASensorManager_getInstance(); * * ASensorManager* sensorManager = ASensorManager_getInstanceForPackage("foo.bar.baz"); * + * Available since API level 26. */ ASensorManager* ASensorManager_getInstanceForPackage(const char* packageName) __INTRODUCED_IN(26); #endif @@ -583,6 +584,8 @@ ASensor const* ASensorManager_getDefaultSensor(ASensorManager* manager, int type /** * Returns the default sensor with the given type and wakeUp properties or NULL if no sensor * of this type and wakeUp properties exists. + * + * Available since API level 21. */ ASensor const* ASensorManager_getDefaultSensorEx(ASensorManager* manager, int type, bool wakeUp) __INTRODUCED_IN(21); #endif @@ -609,6 +612,8 @@ int ASensorManager_destroyEventQueue(ASensorManager* manager, ASensorEventQueue* * Create a direct channel of {@link ASENSOR_DIRECT_CHANNEL_TYPE_SHARED_MEMORY} to be used * for configuring sensor direct report. * + * Available since API level 26. + * * \param manager the {@link ASensorManager} instance obtained from * {@link ASensorManager_getInstanceForPackage}. * \param fd file descriptor representing a shared memory created by @@ -627,6 +632,8 @@ int ASensorManager_createSharedMemoryDirectChannel(ASensorManager* manager, int * Create a direct channel of {@link ASENSOR_DIRECT_CHANNEL_TYPE_HARDWARE_BUFFER} type to be used * for configuring sensor direct report. * + * Available since API level 26. + * * \param manager the {@link ASensorManager} instance obtained from * {@link ASensorManager_getInstanceForPackage}. * \param buffer {@link AHardwareBuffer} instance created by {@link AHardwareBuffer_allocate}. @@ -646,6 +653,8 @@ int ASensorManager_createHardwareBufferDirectChannel( * The buffer used for creating direct channel does not get destroyed with * {@link ASensorManager_destroy} and has to be close or released separately. * + * Available since API level 26. + * * \param manager the {@link ASensorManager} instance obtained from * {@link ASensorManager_getInstanceForPackage}. * \param channelId channel id (a positive integer) returned from @@ -678,6 +687,8 @@ void ASensorManager_destroyDirectChannel(ASensorManager* manager, int channelId) * * ASensorManager_configureDirectReport(manager, sensor, channel_id, ASENSOR_DIRECT_RATE_FAST); * + * Available since API level 26. + * * \param manager the {@link ASensorManager} instance obtained from * {@link ASensorManager_getInstanceForPackage}. * \param sensor a {@link ASensor} to denote which sensor to be operate. It can be NULL if rate @@ -780,7 +791,7 @@ int ASensorEventQueue_hasEvents(ASensorEventQueue* queue); */ ssize_t ASensorEventQueue_getEvents(ASensorEventQueue* queue, ASensorEvent* events, size_t count); -#if __ANDROID_API__ >= __ANDROID_API_Q__ +#if __ANDROID_API__ >= 29 /** * Request that {@link ASENSOR_TYPE_ADDITIONAL_INFO} events to be delivered on * the given {@link ASensorEventQueue}. @@ -796,13 +807,15 @@ ssize_t ASensorEventQueue_getEvents(ASensorEventQueue* queue, ASensorEvent* even * {@link AAdditionalInfoEvent#type}, as new values may be defined in the future * and may delivered to the client. * + * Available since API level 29. + * * \param queue {@link ASensorEventQueue} to configure * \param enable true to request {@link ASENSOR_TYPE_ADDITIONAL_INFO} events, * false to stop receiving events * \return 0 on success or a negative error code on failure */ -int ASensorEventQueue_requestAdditionalInfoEvents(ASensorEventQueue* queue, bool enable); -#endif /* __ANDROID_API__ >= __ANDRDOID_API_Q__ */ +int ASensorEventQueue_requestAdditionalInfoEvents(ASensorEventQueue* queue, bool enable) __INTRODUCED_IN(29); +#endif /* __ANDROID_API__ >= 29 */ /*****************************************************************************/ @@ -837,26 +850,36 @@ int ASensor_getMinDelay(ASensor const* sensor); /** * Returns the maximum size of batches for this sensor. Batches will often be * smaller, as the hardware fifo might be used for other sensors. + * + * Available since API level 21. */ int ASensor_getFifoMaxEventCount(ASensor const* sensor) __INTRODUCED_IN(21); /** * Returns the hardware batch fifo size reserved to this sensor. + * + * Available since API level 21. */ int ASensor_getFifoReservedEventCount(ASensor const* sensor) __INTRODUCED_IN(21); /** * Returns this sensor's string type. + * + * Available since API level 21. */ const char* ASensor_getStringType(ASensor const* sensor) __INTRODUCED_IN(21); /** * Returns the reporting mode for this sensor. One of AREPORTING_MODE_* constants. + * + * Available since API level 21. */ int ASensor_getReportingMode(ASensor const* sensor) __INTRODUCED_IN(21); /** * Returns true if this is a wake up sensor, false otherwise. + * + * Available since API level 21. */ bool ASensor_isWakeUpSensor(ASensor const* sensor) __INTRODUCED_IN(21); #endif /* __ANDROID_API__ >= 21 */ @@ -865,6 +888,8 @@ bool ASensor_isWakeUpSensor(ASensor const* sensor) __INTRODUCED_IN(21); /** * Test if sensor supports a certain type of direct channel. * + * Available since API level 26. + * * \param sensor a {@link ASensor} to denote the sensor to be checked. * \param channelType Channel type constant, either * {@ASENSOR_DIRECT_CHANNEL_TYPE_SHARED_MEMORY} @@ -874,7 +899,9 @@ bool ASensor_isWakeUpSensor(ASensor const* sensor) __INTRODUCED_IN(21); bool ASensor_isDirectChannelTypeSupported(ASensor const* sensor, int channelType) __INTRODUCED_IN(26); /** - * Get the highest direct rate level that a sensor support. + * Get the highest direct rate level that a sensor supports. + * + * Available since API level 26. * * \param sensor a {@link ASensor} to denote the sensor to be checked. * @@ -885,7 +912,7 @@ bool ASensor_isDirectChannelTypeSupported(ASensor const* sensor, int channelType int ASensor_getHighestDirectReportRateLevel(ASensor const* sensor) __INTRODUCED_IN(26); #endif /* __ANDROID_API__ >= 26 */ -#if __ANDROID_API__ >= __ANDROID_API_Q__ +#if __ANDROID_API__ >= 29 /** * Returns the sensor's handle. * @@ -899,9 +926,11 @@ int ASensor_getHighestDirectReportRateLevel(ASensor const* sensor) __INTRODUCED_ * It is important to note that the value returned by {@link ASensor_getHandle} is not the same as * the value returned by the Java API {@link android.hardware.Sensor#getId} and no mapping exists * between the values. + * + * Available since API level 29. */ -int ASensor_getHandle(ASensor const* sensor) __INTRODUCED_IN(__ANDROID_API_Q__); -#endif /* __ANDROID_API__ >= ANDROID_API_Q__ */ +int ASensor_getHandle(ASensor const* sensor) __INTRODUCED_IN(29); +#endif /* __ANDROID_API__ >= 29 */ #ifdef __cplusplus }; diff --git a/include/android/sharedmem.h b/include/android/sharedmem.h index 7f5177bde9..6efa4f71cb 100644 --- a/include/android/sharedmem.h +++ b/include/android/sharedmem.h @@ -21,7 +21,7 @@ /** * @file sharedmem.h - * @brief Shared memory buffers that can be shared across process. + * @brief Shared memory buffers that can be shared between processes. */ #ifndef ANDROID_SHARED_MEMORY_H @@ -61,11 +61,15 @@ extern "C" { * * Use close() to release the shared memory region. * + * Use {@link android.os.ParcelFileDescriptor} to pass the file descriptor to + * another process. File descriptors may also be sent to other processes over a Unix domain + * socket with sendmsg and SCM_RIGHTS. See sendmsg(3) and cmsg(3) man pages for more information. + * * Available since API level 26. * * \param name an optional name. * \param size size of the shared memory region - * \return file descriptor that denotes the shared memory; error code on failure. + * \return file descriptor that denotes the shared memory; -1 and sets errno on failure, or -EINVAL if the error is that size was 0. */ int ASharedMemory_create(const char *name, size_t size) __INTRODUCED_IN(26); @@ -109,7 +113,7 @@ size_t ASharedMemory_getSize(int fd) __INTRODUCED_IN(26); * \param fd file descriptor of the shared memory region. * \param prot any bitwise-or'ed combination of PROT_READ, PROT_WRITE, PROT_EXEC denoting * updated access. Note access can only be removed, but not added back. - * \return 0 for success, error code on failure. + * \return 0 for success, -1 and sets errno on failure. */ int ASharedMemory_setProt(int fd, int prot) __INTRODUCED_IN(26); diff --git a/include/android/surface_control.h b/include/android/surface_control.h index ef2ad9998c..90e565359e 100644 --- a/include/android/surface_control.h +++ b/include/android/surface_control.h @@ -46,7 +46,7 @@ struct ASurfaceControl; */ typedef struct ASurfaceControl ASurfaceControl; -/* +/** * Creates an ASurfaceControl with either ANativeWindow or an ASurfaceControl as its parent. * |debug_name| is a debug name associated with this surface. It can be used to * identify this surface in the SurfaceFlinger's layer tree. It must not be @@ -54,10 +54,17 @@ typedef struct ASurfaceControl ASurfaceControl; * * The caller takes ownership of the ASurfaceControl returned and must release it * using ASurfaceControl_release below. + * + * Available since API level 29. */ ASurfaceControl* ASurfaceControl_createFromWindow(ANativeWindow* parent, const char* debug_name) __INTRODUCED_IN(29); +/** + * See ASurfaceControl_createFromWindow. + * + * Available since API level 29. + */ ASurfaceControl* ASurfaceControl_create(ASurfaceControl* parent, const char* debug_name) __INTRODUCED_IN(29); @@ -65,6 +72,8 @@ ASurfaceControl* ASurfaceControl_create(ASurfaceControl* parent, const char* deb * Releases the |surface_control| object. After releasing the ASurfaceControl the caller no longer * has ownership of the AsurfaceControl. The surface and it's children may remain on display as long * as their parent remains on display. + * + * Available since API level 29. */ void ASurfaceControl_release(ASurfaceControl* surface_control) __INTRODUCED_IN(29); @@ -79,11 +88,15 @@ typedef struct ASurfaceTransaction ASurfaceTransaction; /** * The caller takes ownership of the transaction and must release it using * ASurfaceControl_delete below. + * + * Available since API level 29. */ ASurfaceTransaction* ASurfaceTransaction_create() __INTRODUCED_IN(29); /** * Destroys the |transaction| object. + * + * Available since API level 29. */ void ASurfaceTransaction_delete(ASurfaceTransaction* transaction) __INTRODUCED_IN(29); @@ -93,6 +106,8 @@ void ASurfaceTransaction_delete(ASurfaceTransaction* transaction) __INTRODUCED_I * Note that the transaction is guaranteed to be applied atomically. The * transactions which are applied on the same thread are also guaranteed to be * applied in order. + * + * Available since API level 29. */ void ASurfaceTransaction_apply(ASurfaceTransaction* transaction) __INTRODUCED_IN(29); @@ -116,6 +131,8 @@ typedef struct ASurfaceTransactionStats ASurfaceTransactionStats; * * THREADING * The transaction completed callback can be invoked on any thread. + * + * Available since API level 29. */ typedef void (*ASurfaceTransaction_OnComplete)(void* context, ASurfaceTransactionStats* stats) __INTRODUCED_IN(29); @@ -123,6 +140,8 @@ typedef void (*ASurfaceTransaction_OnComplete)(void* context, ASurfaceTransactio /** * Returns the timestamp of when the frame was latched by the framework. Once a frame is * latched by the framework, it is presented at the following hardware vsync. + * + * Available since API level 29. */ int64_t ASurfaceTransactionStats_getLatchTime(ASurfaceTransactionStats* surface_transaction_stats) __INTRODUCED_IN(29); @@ -131,6 +150,8 @@ int64_t ASurfaceTransactionStats_getLatchTime(ASurfaceTransactionStats* surface_ * Returns a sync fence that signals when the transaction has been presented. * The recipient of the callback takes ownership of the fence and is responsible for closing * it. + * + * Available since API level 29. */ int ASurfaceTransactionStats_getPresentFenceFd(ASurfaceTransactionStats* surface_transaction_stats) __INTRODUCED_IN(29); @@ -141,6 +162,8 @@ int ASurfaceTransactionStats_getPresentFenceFd(ASurfaceTransactionStats* surface * When the client is done using the array, it must release it by calling * ASurfaceTransactionStats_releaseASurfaceControls. * + * Available since API level 29. + * * |outASurfaceControlsSize| returns the size of the ASurfaceControls array. */ void ASurfaceTransactionStats_getASurfaceControls(ASurfaceTransactionStats* surface_transaction_stats, @@ -150,6 +173,8 @@ void ASurfaceTransactionStats_getASurfaceControls(ASurfaceTransactionStats* surf /** * Releases the array of ASurfaceControls that were returned by * ASurfaceTransactionStats_getASurfaceControls. + * + * Available since API level 29. */ void ASurfaceTransactionStats_releaseASurfaceControls(ASurfaceControl** surface_controls) __INTRODUCED_IN(29); @@ -158,6 +183,8 @@ void ASurfaceTransactionStats_releaseASurfaceControls(ASurfaceControl** surface_ * Returns the timestamp of when the CURRENT buffer was acquired. A buffer is considered * acquired when its acquire_fence_fd has signaled. A buffer cannot be latched or presented until * it is acquired. If no acquire_fence_fd was provided, this timestamp will be set to -1. + * + * Available since API level 29. */ int64_t ASurfaceTransactionStats_getAcquireTime(ASurfaceTransactionStats* surface_transaction_stats, ASurfaceControl* surface_control) @@ -180,6 +207,8 @@ int64_t ASurfaceTransactionStats_getAcquireTime(ASurfaceTransactionStats* surfac * * The client must ensure that all pending refs on a buffer are released before attempting to reuse * this buffer, otherwise synchronization errors may occur. + * + * Available since API level 29. */ int ASurfaceTransactionStats_getPreviousReleaseFenceFd( ASurfaceTransactionStats* surface_transaction_stats, @@ -190,6 +219,8 @@ int ASurfaceTransactionStats_getPreviousReleaseFenceFd( * Sets the callback that will be invoked when the updates from this transaction * are presented. For details on the callback semantics and data, see the * comments on the ASurfaceTransaction_OnComplete declaration above. + * + * Available since API level 29. */ void ASurfaceTransaction_setOnComplete(ASurfaceTransaction* transaction, void* context, ASurfaceTransaction_OnComplete func) __INTRODUCED_IN(29); @@ -199,6 +230,8 @@ void ASurfaceTransaction_setOnComplete(ASurfaceTransaction* transaction, void* c * Any children of the* reparented |surface_control| will remain children of the |surface_control|. * * The |new_parent| can be null. Surface controls with a null parent do not appear on the display. + * + * Available since API level 29. */ void ASurfaceTransaction_reparent(ASurfaceTransaction* transaction, ASurfaceControl* surface_control, ASurfaceControl* new_parent) @@ -213,6 +246,8 @@ enum { * Updates the visibility of |surface_control|. If show is set to * ASURFACE_TRANSACTION_VISIBILITY_HIDE, the |surface_control| and all surfaces in its subtree will * be hidden. + * + * Available since API level 29. */ void ASurfaceTransaction_setVisibility(ASurfaceTransaction* transaction, ASurfaceControl* surface_control, int8_t visibility) @@ -224,6 +259,8 @@ void ASurfaceTransaction_setVisibility(ASurfaceTransaction* transaction, * the same z order is undefined. * * Z orders may be from MIN_INT32 to MAX_INT32. A layer's default z order index is 0. + * + * Available since API level 29. */ void ASurfaceTransaction_setZOrder(ASurfaceTransaction* transaction, ASurfaceControl* surface_control, int32_t z_order) @@ -236,6 +273,8 @@ void ASurfaceTransaction_setZOrder(ASurfaceTransaction* transaction, * * The frameworks takes ownership of the |acquire_fence_fd| passed and is responsible * for closing it. + * + * Available since API level 29. */ void ASurfaceTransaction_setBuffer(ASurfaceTransaction* transaction, ASurfaceControl* surface_control, AHardwareBuffer* buffer, @@ -246,6 +285,8 @@ void ASurfaceTransaction_setBuffer(ASurfaceTransaction* transaction, * ASurfaceControl visible in transparent regions of the surface. Colors |r|, |g|, * and |b| must be within the range that is valid for |dataspace|. |dataspace| and |alpha| * will be the dataspace and alpha set for the background color layer. + * + * Available since API level 29. */ void ASurfaceTransaction_setColor(ASurfaceTransaction* transaction, ASurfaceControl* surface_control, float r, float g, float b, @@ -264,6 +305,8 @@ void ASurfaceTransaction_setColor(ASurfaceTransaction* transaction, * |transform| the transform applied after the source rect is applied to the buffer. This parameter * should be set to 0 for no transform. To specify a transfrom use the NATIVE_WINDOW_TRANSFORM_* * enum. + * + * Available since API level 29. */ void ASurfaceTransaction_setGeometry(ASurfaceTransaction* transaction, ASurfaceControl* surface_control, const ARect& source, @@ -281,6 +324,8 @@ enum { * Updates whether the content for the buffer associated with this surface is * completely opaque. If true, every pixel of content inside the buffer must be * opaque or visual errors can occur. + * + * Available since API level 29. */ void ASurfaceTransaction_setBufferTransparency(ASurfaceTransaction* transaction, ASurfaceControl* surface_control, @@ -290,6 +335,8 @@ void ASurfaceTransaction_setBufferTransparency(ASurfaceTransaction* transaction, /** * Updates the region for the content on this surface updated in this * transaction. If unspecified, the complete surface is assumed to be damaged. + * + * Available since API level 29. */ void ASurfaceTransaction_setDamageRegion(ASurfaceTransaction* transaction, ASurfaceControl* surface_control, const ARect rects[], @@ -304,6 +351,8 @@ void ASurfaceTransaction_setDamageRegion(ASurfaceTransaction* transaction, * * If an earlier transaction has a desired present time of x, and a later transaction has a desired * present time that is before x, the later transaction will not preempt the earlier transaction. + * + * Available since API level 29. */ void ASurfaceTransaction_setDesiredPresentTime(ASurfaceTransaction* transaction, int64_t desiredPresentTime) __INTRODUCED_IN(29); @@ -312,6 +361,8 @@ void ASurfaceTransaction_setDesiredPresentTime(ASurfaceTransaction* transaction, * Sets the alpha for the buffer. It uses a premultiplied blending. * * The |alpha| must be between 0.0 and 1.0. + * + * Available since API level 29. */ void ASurfaceTransaction_setBufferAlpha(ASurfaceTransaction* transaction, ASurfaceControl* surface_control, float alpha) @@ -321,6 +372,8 @@ void ASurfaceTransaction_setBufferAlpha(ASurfaceTransaction* transaction, * Sets the data space of the surface_control's buffers. * * If no data space is set, the surface control defaults to ADATASPACE_SRGB. + * + * Available since API level 29. */ void ASurfaceTransaction_setBufferDataSpace(ASurfaceTransaction* transaction, ASurfaceControl* surface_control, ADataSpace data_space) @@ -331,6 +384,8 @@ void ASurfaceTransaction_setBufferDataSpace(ASurfaceTransaction* transaction, * * When |metadata| is set to null, the framework does not use any smpte2086 metadata when rendering * the surface's buffer. + * + * Available since API level 29. */ void ASurfaceTransaction_setHdrMetadata_smpte2086(ASurfaceTransaction* transaction, ASurfaceControl* surface_control, @@ -342,6 +397,8 @@ void ASurfaceTransaction_setHdrMetadata_smpte2086(ASurfaceTransaction* transacti * * When |metadata| is set to null, the framework does not use any cta861.3 metadata when rendering * the surface's buffer. + * + * Available since API level 29. */ void ASurfaceTransaction_setHdrMetadata_cta861_3(ASurfaceTransaction* transaction, ASurfaceControl* surface_control, diff --git a/include/android/surface_texture.h b/include/android/surface_texture.h index 540d23a4c7..dde7eaa0b6 100644 --- a/include/android/surface_texture.h +++ b/include/android/surface_texture.h @@ -65,6 +65,9 @@ typedef struct ASurfaceTexture ASurfaceTexture; * Release the reference to the native ASurfaceTexture acquired with * ASurfaceTexture_fromSurfaceTexture(). * Failing to do so will result in leaked memory and graphic resources. + * + * Available since API level 28. + * * \param st A ASurfaceTexture reference acquired with ASurfaceTexture_fromSurfaceTexture() */ void ASurfaceTexture_release(ASurfaceTexture* st) __INTRODUCED_IN(28); @@ -73,6 +76,8 @@ void ASurfaceTexture_release(ASurfaceTexture* st) __INTRODUCED_IN(28); * Returns a reference to an ANativeWindow (i.e. the Producer) for this SurfaceTexture. * This is equivalent to Java's: Surface sur = new Surface(surfaceTexture); * + * Available since API level 28. + * * \param st A ASurfaceTexture reference acquired with ASurfaceTexture_fromSurfaceTexture() * @return A reference to an ANativeWindow. This reference MUST BE released when no longer needed * using ANativeWindow_release(). Failing to do so will result in leaked resources. nullptr is @@ -90,6 +95,8 @@ ANativeWindow* ASurfaceTexture_acquireANativeWindow(ASurfaceTexture* st) __INTRO * contexts. Note, however, that the image contents are only accessible from one OpenGL ES * context at a time. * + * Available since API level 28. + * * \param st A ASurfaceTexture reference acquired with ASurfaceTexture_fromSurfaceTexture() * \param texName The name of the OpenGL ES texture that will be created. This texture name * must be unusued in the OpenGL ES context that is current on the calling thread. @@ -108,6 +115,8 @@ int ASurfaceTexture_attachToGLContext(ASurfaceTexture* st, uint32_t texName) __I * contexts. Note, however, that the image contents are only accessible from one OpenGL ES * context at a time. * + * Available since API level 28. + * * \param st A ASurfaceTexture reference acquired with ASurfaceTexture_fromSurfaceTexture() * \return 0 on success, negative posix error code otherwise (see <errno.h>) */ @@ -118,6 +127,8 @@ int ASurfaceTexture_detachFromGLContext(ASurfaceTexture* st) __INTRODUCED_IN(28) * called while the OpenGL ES context that owns the texture is current on the calling thread. * It will implicitly bind its texture to the GL_TEXTURE_EXTERNAL_OES texture target. * + * Available since API level 28. + * * \param st A ASurfaceTexture reference acquired with ASurfaceTexture_fromSurfaceTexture() * \return 0 on success, negative posix error code otherwise (see <errno.h>) */ @@ -135,6 +146,8 @@ int ASurfaceTexture_updateTexImage(ASurfaceTexture* st) __INTRODUCED_IN(28); * The matrix is stored in column-major order so that it may be passed directly to OpenGL ES via * the glLoadMatrixf or glUniformMatrix4fv functions. * + * Available since API level 28. + * * \param st A ASurfaceTexture reference acquired with ASurfaceTexture_fromSurfaceTexture() * \param mtx the array into which the 4x4 matrix will be stored. The array must have exactly * 16 elements. @@ -156,6 +169,8 @@ void ASurfaceTexture_getTransformMatrix(ASurfaceTexture* st, float mtx[16]) __IN * For EGL/Vulkan producers, this timestamp is the desired present time set with the * EGL_ANDROID_presentation_time or VK_GOOGLE_display_timing extensions * + * Available since API level 28. + * * \param st A ASurfaceTexture reference acquired with ASurfaceTexture_fromSurfaceTexture() */ int64_t ASurfaceTexture_getTimestamp(ASurfaceTexture* st) __INTRODUCED_IN(28); diff --git a/include/android/surface_texture_jni.h b/include/android/surface_texture_jni.h index b0e1edd590..2266d541f6 100644 --- a/include/android/surface_texture_jni.h +++ b/include/android/surface_texture_jni.h @@ -32,6 +32,8 @@ __BEGIN_DECLS +#if __ANDROID_API__ >= 28 + /** * Get a reference to the native ASurfaceTexture from the corresponding java object. * @@ -40,13 +42,17 @@ __BEGIN_DECLS * properly once the Java object gets finalized. * However, this will not result in program termination. * + * Available since API level 28. + * * \param env JNI environment * \param surfacetexture Instance of Java SurfaceTexture object * \return native ASurfaceTexture reference or nullptr if the java object is not a SurfaceTexture. * The returned reference MUST BE released when it's no longer needed using * ASurfaceTexture_release(). */ -ASurfaceTexture* ASurfaceTexture_fromSurfaceTexture(JNIEnv* env, jobject surfacetexture); +ASurfaceTexture* ASurfaceTexture_fromSurfaceTexture(JNIEnv* env, jobject surfacetexture) __INTRODUCED_IN(28); + +#endif __END_DECLS diff --git a/include/android/system_fonts.h b/include/android/system_fonts.h index f0485a1871..6fd7d2c0ab 100644 --- a/include/android/system_fonts.h +++ b/include/android/system_fonts.h @@ -102,6 +102,8 @@ struct ASystemFontIterator; * * Use ASystemFont_close() to close the iterator. * + * Available since API level 29. + * * \return a pointer for a newly allocated iterator, nullptr on failure. */ ASystemFontIterator* _Nullable ASystemFontIterator_open() __INTRODUCED_IN(29); @@ -109,6 +111,8 @@ ASystemFontIterator* _Nullable ASystemFontIterator_open() __INTRODUCED_IN(29); /** * Close an opened system font iterator, freeing any related resources. * + * Available since API level 29. + * * \param iterator a pointer of an iterator for the system fonts. Do nothing if NULL is passed. */ void ASystemFontIterator_close(ASystemFontIterator* _Nullable iterator) __INTRODUCED_IN(29); @@ -116,6 +120,8 @@ void ASystemFontIterator_close(ASystemFontIterator* _Nullable iterator) __INTROD /** * Move to the next system font. * + * Available since API level 29. + * * \param iterator an iterator for the system fonts. Passing NULL is not allowed. * \return a font. If no more font is available, returns nullptr. You need to release the returned * font by ASystemFont_close when it is no longer needed. diff --git a/include/android/trace.h b/include/android/trace.h index bb7ff28f79..d59690ab2e 100644 --- a/include/android/trace.h +++ b/include/android/trace.h @@ -74,7 +74,7 @@ void ATrace_endSection() __INTRODUCED_IN(23); #endif /* __ANDROID_API__ >= 23 */ -#if __ANDROID_API__ >= __ANDROID_API_Q__ +#if __ANDROID_API__ >= 29 /** * Writes a trace message to indicate that a given section of code has @@ -83,6 +83,8 @@ void ATrace_endSection() __INTRODUCED_IN(23); * asynchronous events do not need to be nested. The name and cookie used to * begin an event must be used to end it. * + * Available since API level 29. + * * \param sectionName The method name to appear in the trace. * \param cookie Unique identifier for distinguishing simultaneous events */ @@ -93,6 +95,8 @@ void ATrace_beginAsyncSection(const char* sectionName, int32_t cookie) __INTRODU * Must be called exactly once for each call to {@link ATrace_beginAsyncSection} * using the same name and cookie. * + * Available since API level 29. + * * \param methodName The method name to appear in the trace. * \param cookie Unique identifier for distinguishing simultaneous events */ @@ -101,6 +105,8 @@ void ATrace_endAsyncSection(const char* sectionName, int32_t cookie) __INTRODUCE /** * Writes trace message to indicate the value of a given counter. * + * Available since API level 29. + * * \param counterName The counter name to appear in the trace. * \param counterValue The counter value. */ diff --git a/include/binder b/include/binder deleted file mode 120000 index 35a022ab67..0000000000 --- a/include/binder +++ /dev/null @@ -1 +0,0 @@ -../libs/binder/include/binder/
\ No newline at end of file diff --git a/include/binder/Binder.h b/include/binder/Binder.h new file mode 120000 index 0000000000..0fc6db741e --- /dev/null +++ b/include/binder/Binder.h @@ -0,0 +1 @@ +../../libs/binder/include/binder/Binder.h
\ No newline at end of file diff --git a/include/binder/BinderService.h b/include/binder/BinderService.h new file mode 120000 index 0000000000..370b260577 --- /dev/null +++ b/include/binder/BinderService.h @@ -0,0 +1 @@ +../../libs/binder/include/binder/BinderService.h
\ No newline at end of file diff --git a/include/binder/IBinder.h b/include/binder/IBinder.h new file mode 120000 index 0000000000..93a6219206 --- /dev/null +++ b/include/binder/IBinder.h @@ -0,0 +1 @@ +../../libs/binder/include/binder/IBinder.h
\ No newline at end of file diff --git a/include/binder/IInterface.h b/include/binder/IInterface.h new file mode 120000 index 0000000000..857987819f --- /dev/null +++ b/include/binder/IInterface.h @@ -0,0 +1 @@ +../../libs/binder/include/binder/IInterface.h
\ No newline at end of file diff --git a/include/binder/IMemory.h b/include/binder/IMemory.h new file mode 120000 index 0000000000..5171c08d8e --- /dev/null +++ b/include/binder/IMemory.h @@ -0,0 +1 @@ +../../libs/binder/include/binder/IMemory.h
\ No newline at end of file diff --git a/include/binder/IPCThreadState.h b/include/binder/IPCThreadState.h new file mode 120000 index 0000000000..ecd4f815eb --- /dev/null +++ b/include/binder/IPCThreadState.h @@ -0,0 +1 @@ +../../libs/binder/include/binder/IPCThreadState.h
\ No newline at end of file diff --git a/include/binder/IServiceManager.h b/include/binder/IServiceManager.h new file mode 120000 index 0000000000..33d18ccd16 --- /dev/null +++ b/include/binder/IServiceManager.h @@ -0,0 +1 @@ +../../libs/binder/include/binder/IServiceManager.h
\ No newline at end of file diff --git a/include/binder/MemoryDealer.h b/include/binder/MemoryDealer.h new file mode 120000 index 0000000000..71881fbfff --- /dev/null +++ b/include/binder/MemoryDealer.h @@ -0,0 +1 @@ +../../libs/binder/include/binder/MemoryDealer.h
\ No newline at end of file diff --git a/include/binder/MemoryHeapBase.h b/include/binder/MemoryHeapBase.h new file mode 120000 index 0000000000..8fb51ccef6 --- /dev/null +++ b/include/binder/MemoryHeapBase.h @@ -0,0 +1 @@ +../../libs/binder/include/binder/MemoryHeapBase.h
\ No newline at end of file diff --git a/include/binder/Parcel.h b/include/binder/Parcel.h new file mode 120000 index 0000000000..23492be087 --- /dev/null +++ b/include/binder/Parcel.h @@ -0,0 +1 @@ +../../libs/binder/include/binder/Parcel.h
\ No newline at end of file diff --git a/include/binder/ParcelFileDescriptor.h b/include/binder/ParcelFileDescriptor.h new file mode 120000 index 0000000000..777bd49b05 --- /dev/null +++ b/include/binder/ParcelFileDescriptor.h @@ -0,0 +1 @@ +../../libs/binder/include/binder/ParcelFileDescriptor.h
\ No newline at end of file diff --git a/include/binder/Parcelable.h b/include/binder/Parcelable.h new file mode 120000 index 0000000000..438e223075 --- /dev/null +++ b/include/binder/Parcelable.h @@ -0,0 +1 @@ +../../libs/binder/include/binder/Parcelable.h
\ No newline at end of file diff --git a/include/binder/PermissionCache.h b/include/binder/PermissionCache.h new file mode 120000 index 0000000000..e910c12157 --- /dev/null +++ b/include/binder/PermissionCache.h @@ -0,0 +1 @@ +../../libs/binder/include/binder/PermissionCache.h
\ No newline at end of file diff --git a/include/binder/PersistableBundle.h b/include/binder/PersistableBundle.h new file mode 120000 index 0000000000..785f2b435c --- /dev/null +++ b/include/binder/PersistableBundle.h @@ -0,0 +1 @@ +../../libs/binder/include/binder/PersistableBundle.h
\ No newline at end of file diff --git a/include/binder/ProcessState.h b/include/binder/ProcessState.h new file mode 120000 index 0000000000..4cbe7a5b8f --- /dev/null +++ b/include/binder/ProcessState.h @@ -0,0 +1 @@ +../../libs/binder/include/binder/ProcessState.h
\ No newline at end of file diff --git a/include/binder/Stability.h b/include/binder/Stability.h new file mode 120000 index 0000000000..9b431d2e28 --- /dev/null +++ b/include/binder/Stability.h @@ -0,0 +1 @@ +../../libs/binder/include/binder/Stability.h
\ No newline at end of file diff --git a/include/binder/Status.h b/include/binder/Status.h new file mode 120000 index 0000000000..ccb994e252 --- /dev/null +++ b/include/binder/Status.h @@ -0,0 +1 @@ +../../libs/binder/include/binder/Status.h
\ No newline at end of file diff --git a/libs/adbd_auth/Android.bp b/libs/adbd_auth/Android.bp new file mode 100644 index 0000000000..9cf014380c --- /dev/null +++ b/libs/adbd_auth/Android.bp @@ -0,0 +1,44 @@ +// Copyright (C) 2019 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +cc_library { + name: "libadbd_auth", + cflags: [ + "-Wall", + "-Wextra", + "-Wthread-safety", + "-Werror", + ], + srcs: ["adbd_auth.cpp"], + export_include_dirs: ["include"], + + version_script: "libadbd_auth.map.txt", + stubs: { + symbol_file: "libadbd_auth.map.txt", + }, + + host_supported: true, + recovery_available: true, + target: { + darwin: { + enabled: false, + } + }, + + shared_libs: [ + "libbase", + "libcutils", + "liblog", + ], +} diff --git a/libs/adbd_auth/adbd_auth.cpp b/libs/adbd_auth/adbd_auth.cpp new file mode 100644 index 0000000000..64791098ee --- /dev/null +++ b/libs/adbd_auth/adbd_auth.cpp @@ -0,0 +1,443 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define ANDROID_BASE_UNIQUE_FD_DISABLE_IMPLICIT_CONVERSION + +#include "include/adbd_auth.h" + +#include <inttypes.h> +#include <sys/epoll.h> +#include <sys/eventfd.h> +#include <sys/uio.h> + +#include <chrono> +#include <deque> +#include <string> +#include <string_view> +#include <tuple> +#include <unordered_map> +#include <utility> +#include <variant> +#include <vector> + +#include <android-base/file.h> +#include <android-base/logging.h> +#include <android-base/macros.h> +#include <android-base/strings.h> +#include <android-base/thread_annotations.h> +#include <android-base/unique_fd.h> +#include <cutils/sockets.h> + +using android::base::unique_fd; + +struct AdbdAuthPacketAuthenticated { + std::string public_key; +}; + +struct AdbdAuthPacketDisconnected { + std::string public_key; +}; + +struct AdbdAuthPacketRequestAuthorization { + std::string public_key; +}; + +using AdbdAuthPacket = std::variant<AdbdAuthPacketAuthenticated, AdbdAuthPacketDisconnected, + AdbdAuthPacketRequestAuthorization>; + +struct AdbdAuthContext { + static constexpr uint64_t kEpollConstSocket = 0; + static constexpr uint64_t kEpollConstEventFd = 1; + static constexpr uint64_t kEpollConstFramework = 2; + +public: + explicit AdbdAuthContext(AdbdAuthCallbacksV1* callbacks) : next_id_(0), callbacks_(*callbacks) { + epoll_fd_.reset(epoll_create1(EPOLL_CLOEXEC)); + if (epoll_fd_ == -1) { + PLOG(FATAL) << "failed to create epoll fd"; + } + + event_fd_.reset(eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK)); + if (event_fd_ == -1) { + PLOG(FATAL) << "failed to create eventfd"; + } + + sock_fd_.reset(android_get_control_socket("adbd")); + if (sock_fd_ == -1) { + PLOG(ERROR) << "failed to get adbd authentication socket"; + } else { + if (fcntl(sock_fd_.get(), F_SETFD, FD_CLOEXEC) != 0) { + PLOG(FATAL) << "failed to make adbd authentication socket cloexec"; + } + + if (fcntl(sock_fd_.get(), F_SETFL, O_NONBLOCK) != 0) { + PLOG(FATAL) << "failed to make adbd authentication socket nonblocking"; + } + + if (listen(sock_fd_.get(), 4) != 0) { + PLOG(FATAL) << "failed to listen on adbd authentication socket"; + } + } + } + + AdbdAuthContext(const AdbdAuthContext& copy) = delete; + AdbdAuthContext(AdbdAuthContext&& move) = delete; + AdbdAuthContext& operator=(const AdbdAuthContext& copy) = delete; + AdbdAuthContext& operator=(AdbdAuthContext&& move) = delete; + + uint64_t NextId() { return next_id_++; } + + void DispatchPendingPrompt() REQUIRES(mutex_) { + if (dispatched_prompt_) { + LOG(INFO) << "adbd_auth: prompt currently pending, skipping"; + return; + } + + if (pending_prompts_.empty()) { + LOG(INFO) << "adbd_auth: no prompts to send"; + return; + } + + LOG(INFO) << "adbd_auth: prompting user for adb authentication"; + auto [id, public_key, arg] = std::move(pending_prompts_.front()); + pending_prompts_.pop_front(); + + this->output_queue_.emplace_back( + AdbdAuthPacketRequestAuthorization{.public_key = public_key}); + + Interrupt(); + dispatched_prompt_ = std::make_tuple(id, public_key, arg); + } + + void UpdateFrameworkWritable() REQUIRES(mutex_) { + // This might result in redundant calls to EPOLL_CTL_MOD if, for example, we get notified + // at the same time as a framework connection, but that's unlikely and this doesn't need to + // be fast anyway. + if (framework_fd_ != -1) { + struct epoll_event event; + event.events = EPOLLIN; + if (!output_queue_.empty()) { + LOG(INFO) << "marking framework writable"; + event.events |= EPOLLOUT; + } + event.data.u64 = kEpollConstFramework; + CHECK_EQ(0, epoll_ctl(epoll_fd_.get(), EPOLL_CTL_MOD, framework_fd_.get(), &event)); + } + } + + void ReplaceFrameworkFd(unique_fd new_fd) REQUIRES(mutex_) { + LOG(INFO) << "received new framework fd " << new_fd.get() + << " (current = " << framework_fd_.get() << ")"; + + // If we already had a framework fd, clean up after ourselves. + if (framework_fd_ != -1) { + output_queue_.clear(); + dispatched_prompt_.reset(); + CHECK_EQ(0, epoll_ctl(epoll_fd_.get(), EPOLL_CTL_DEL, framework_fd_.get(), nullptr)); + framework_fd_.reset(); + } + + if (new_fd != -1) { + struct epoll_event event; + event.events = EPOLLIN; + if (!output_queue_.empty()) { + LOG(INFO) << "marking framework writable"; + event.events |= EPOLLOUT; + } + event.data.u64 = kEpollConstFramework; + CHECK_EQ(0, epoll_ctl(epoll_fd_.get(), EPOLL_CTL_ADD, new_fd.get(), &event)); + framework_fd_ = std::move(new_fd); + } + } + + void HandlePacket(std::string_view packet) REQUIRES(mutex_) { + LOG(INFO) << "received packet: " << packet; + + if (packet.length() < 2) { + LOG(ERROR) << "received packet of invalid length"; + ReplaceFrameworkFd(unique_fd()); + } + + if (packet[0] == 'O' && packet[1] == 'K') { + CHECK(this->dispatched_prompt_.has_value()); + auto& [id, key, arg] = *this->dispatched_prompt_; + keys_.emplace(id, std::move(key)); + + this->callbacks_.key_authorized(arg, id); + this->dispatched_prompt_ = std::nullopt; + } else if (packet[0] == 'N' && packet[1] == 'O') { + CHECK_EQ(2UL, packet.length()); + // TODO: Do we want a callback if the key is denied? + this->dispatched_prompt_ = std::nullopt; + DispatchPendingPrompt(); + } else { + LOG(ERROR) << "unhandled packet: " << packet; + ReplaceFrameworkFd(unique_fd()); + } + } + + bool SendPacket() REQUIRES(mutex_) { + if (output_queue_.empty()) { + return false; + } + + CHECK_NE(-1, framework_fd_.get()); + + auto& packet = output_queue_.front(); + struct iovec iovs[2]; + if (auto* p = std::get_if<AdbdAuthPacketAuthenticated>(&packet)) { + iovs[0].iov_base = const_cast<char*>("CK"); + iovs[0].iov_len = 2; + iovs[1].iov_base = p->public_key.data(); + iovs[1].iov_len = p->public_key.size(); + } else if (auto* p = std::get_if<AdbdAuthPacketDisconnected>(&packet)) { + iovs[0].iov_base = const_cast<char*>("DC"); + iovs[0].iov_len = 2; + iovs[1].iov_base = p->public_key.data(); + iovs[1].iov_len = p->public_key.size(); + } else if (auto* p = std::get_if<AdbdAuthPacketRequestAuthorization>(&packet)) { + iovs[0].iov_base = const_cast<char*>("PK"); + iovs[0].iov_len = 2; + iovs[1].iov_base = p->public_key.data(); + iovs[1].iov_len = p->public_key.size(); + } else { + LOG(FATAL) << "unhandled packet type?"; + } + + output_queue_.pop_front(); + + ssize_t rc = writev(framework_fd_.get(), iovs, 2); + if (rc == -1 && errno != EAGAIN && errno != EWOULDBLOCK) { + PLOG(ERROR) << "failed to write to framework fd"; + ReplaceFrameworkFd(unique_fd()); + return false; + } + + return true; + } + + void Run() { + if (sock_fd_ == -1) { + LOG(ERROR) << "adbd authentication socket unavailable, disabling user prompts"; + } else { + struct epoll_event event; + event.events = EPOLLIN; + event.data.u64 = kEpollConstSocket; + CHECK_EQ(0, epoll_ctl(epoll_fd_.get(), EPOLL_CTL_ADD, sock_fd_.get(), &event)); + } + + { + struct epoll_event event; + event.events = EPOLLIN; + event.data.u64 = kEpollConstEventFd; + CHECK_EQ(0, epoll_ctl(epoll_fd_.get(), EPOLL_CTL_ADD, event_fd_.get(), &event)); + } + + while (true) { + struct epoll_event events[3]; + int rc = TEMP_FAILURE_RETRY(epoll_wait(epoll_fd_.get(), events, 3, -1)); + if (rc == -1) { + PLOG(FATAL) << "epoll_wait failed"; + } else if (rc == 0) { + LOG(FATAL) << "epoll_wait returned 0"; + } + + bool restart = false; + for (int i = 0; i < rc; ++i) { + if (restart) { + break; + } + + struct epoll_event& event = events[i]; + switch (event.data.u64) { + case kEpollConstSocket: { + unique_fd new_framework_fd(accept4(sock_fd_.get(), nullptr, nullptr, + SOCK_CLOEXEC | SOCK_NONBLOCK)); + if (new_framework_fd == -1) { + PLOG(FATAL) << "failed to accept framework fd"; + } + + LOG(INFO) << "adbd_auth: received a new framework connection"; + std::lock_guard<std::mutex> lock(mutex_); + ReplaceFrameworkFd(std::move(new_framework_fd)); + + // Stop iterating over events: one of the later ones might be the old + // framework fd. + restart = false; + break; + } + + case kEpollConstEventFd: { + // We were woken up to write something. + uint64_t dummy; + int rc = TEMP_FAILURE_RETRY(read(event_fd_.get(), &dummy, sizeof(dummy))); + if (rc != 8) { + PLOG(FATAL) << "failed to read from eventfd (rc = " << rc << ")"; + } + + std::lock_guard<std::mutex> lock(mutex_); + UpdateFrameworkWritable(); + break; + } + + case kEpollConstFramework: { + char buf[4096]; + if (event.events & EPOLLIN) { + int rc = TEMP_FAILURE_RETRY(read(framework_fd_.get(), buf, sizeof(buf))); + if (rc == -1) { + LOG(FATAL) << "failed to read from framework fd"; + } else if (rc == 0) { + LOG(INFO) << "hit EOF on framework fd"; + std::lock_guard<std::mutex> lock(mutex_); + ReplaceFrameworkFd(unique_fd()); + } else { + std::lock_guard<std::mutex> lock(mutex_); + HandlePacket(std::string_view(buf, rc)); + } + } + + if (event.events & EPOLLOUT) { + std::lock_guard<std::mutex> lock(mutex_); + while (SendPacket()) { + continue; + } + UpdateFrameworkWritable(); + } + + break; + } + } + } + } + } + + static constexpr const char* key_paths[] = {"/adb_keys", "/data/misc/adb/adb_keys"}; + void IteratePublicKeys(bool (*callback)(const char*, size_t, void*), void* arg) { + for (const auto& path : key_paths) { + if (access(path, R_OK) == 0) { + LOG(INFO) << "Loading keys from " << path; + std::string content; + if (!android::base::ReadFileToString(path, &content)) { + PLOG(ERROR) << "Couldn't read " << path; + continue; + } + for (const auto& line : android::base::Split(content, "\n")) { + if (!callback(line.data(), line.size(), arg)) { + return; + } + } + } + } + } + + uint64_t PromptUser(std::string_view public_key, void* arg) EXCLUDES(mutex_) { + uint64_t id = NextId(); + + std::lock_guard<std::mutex> lock(mutex_); + pending_prompts_.emplace_back(id, public_key, arg); + DispatchPendingPrompt(); + return id; + } + + uint64_t NotifyAuthenticated(std::string_view public_key) EXCLUDES(mutex_) { + uint64_t id = NextId(); + std::lock_guard<std::mutex> lock(mutex_); + keys_.emplace(id, public_key); + output_queue_.emplace_back( + AdbdAuthPacketDisconnected{.public_key = std::string(public_key)}); + return id; + } + + void NotifyDisconnected(uint64_t id) EXCLUDES(mutex_) { + std::lock_guard<std::mutex> lock(mutex_); + auto it = keys_.find(id); + if (it == keys_.end()) { + LOG(DEBUG) << "couldn't find public key to notify disconnection, skipping"; + return; + } + output_queue_.emplace_back(AdbdAuthPacketDisconnected{.public_key = std::move(it->second)}); + keys_.erase(it); + } + + // Interrupt the worker thread to do some work. + void Interrupt() { + uint64_t value = 1; + ssize_t rc = write(event_fd_.get(), &value, sizeof(value)); + if (rc == -1) { + PLOG(FATAL) << "write to eventfd failed"; + } else if (rc != sizeof(value)) { + LOG(FATAL) << "write to eventfd returned short (" << rc << ")"; + } + } + + unique_fd epoll_fd_; + unique_fd event_fd_; + unique_fd sock_fd_; + unique_fd framework_fd_; + + std::atomic<uint64_t> next_id_; + AdbdAuthCallbacksV1 callbacks_; + + std::mutex mutex_; + std::unordered_map<uint64_t, std::string> keys_ GUARDED_BY(mutex_); + + // We keep two separate queues: one to handle backpressure from the socket (output_queue_) + // and one to make sure we only dispatch one authrequest at a time (pending_prompts_). + std::deque<AdbdAuthPacket> output_queue_; + + std::optional<std::tuple<uint64_t, std::string, void*>> dispatched_prompt_ GUARDED_BY(mutex_); + std::deque<std::tuple<uint64_t, std::string, void*>> pending_prompts_ GUARDED_BY(mutex_); +}; + +AdbdAuthContext* adbd_auth_new(AdbdAuthCallbacks* callbacks) { + if (callbacks->version != 1) { + LOG(ERROR) << "received unknown AdbdAuthCallbacks version " << callbacks->version; + return nullptr; + } + + return new AdbdAuthContext(&callbacks->callbacks.v1); +} + +void adbd_auth_delete(AdbdAuthContext* ctx) { + delete ctx; +} + +void adbd_auth_run(AdbdAuthContext* ctx) { + return ctx->Run(); +} + +void adbd_auth_get_public_keys(AdbdAuthContext* ctx, + bool (*callback)(const char* public_key, size_t len, void* arg), + void* arg) { + ctx->IteratePublicKeys(callback, arg); +} + +uint64_t adbd_auth_notify_auth(AdbdAuthContext* ctx, const char* public_key, size_t len) { + return ctx->NotifyAuthenticated(std::string_view(public_key, len)); +} + +void adbd_auth_notify_disconnect(AdbdAuthContext* ctx, uint64_t id) { + return ctx->NotifyDisconnected(id); +} + +void adbd_auth_prompt_user(AdbdAuthContext* ctx, const char* public_key, size_t len, + void* arg) { + ctx->PromptUser(std::string_view(public_key, len), arg); +} + +bool adbd_auth_supports_feature(AdbdAuthFeature) { + return false; +} diff --git a/libs/adbd_auth/include/adbd_auth.h b/libs/adbd_auth/include/adbd_auth.h new file mode 100644 index 0000000000..b7c1cb88cc --- /dev/null +++ b/libs/adbd_auth/include/adbd_auth.h @@ -0,0 +1,65 @@ +#pragma once + +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <stdbool.h> +#include <stdint.h> +#include <sys/types.h> + +extern "C" { + +struct AdbdAuthCallbacksV1 { + // Callback for a successful user authorization. + void (*key_authorized)(void* arg, uint64_t id); +}; + +struct AdbdAuthCallbacks { + uint32_t version; + union { + AdbdAuthCallbacksV1 v1; + } callbacks; +}; + +struct AdbdAuthContext; + +AdbdAuthContext* adbd_auth_new(AdbdAuthCallbacks* callbacks); +void adbd_auth_delete(AdbdAuthContext* ctx); + +void adbd_auth_run(AdbdAuthContext* ctx); + +// Iterate through the list of authorized public keys. +// Return false from the callback to stop iteration. +void adbd_auth_get_public_keys(AdbdAuthContext* ctx, + bool (*callback)(const char* public_key, size_t len, void* arg), + void* arg); + +// Let system_server know that a key has been successfully used for authentication. +uint64_t adbd_auth_notify_auth(AdbdAuthContext* ctx, const char* public_key, size_t len); + +// Let system_server know that a connection has been closed. +void adbd_auth_notify_disconnect(AdbdAuthContext* ctx, uint64_t id); + +// Prompt the user to authorize a public key. +// When this happens, a callback will be run on the auth thread with the result. +void adbd_auth_prompt_user(AdbdAuthContext* ctx, const char* public_key, size_t len, void* arg); + +enum AdbdAuthFeature { +}; + +bool adbd_auth_supports_feature(AdbdAuthFeature f); + +} diff --git a/libs/adbd_auth/libadbd_auth.map.txt b/libs/adbd_auth/libadbd_auth.map.txt new file mode 100644 index 0000000000..d01233c960 --- /dev/null +++ b/libs/adbd_auth/libadbd_auth.map.txt @@ -0,0 +1,13 @@ +LIBADBD_AUTH { + global: + adbd_auth_new; # apex + adbd_auth_delete; # apex + adbd_auth_run; # apex + adbd_auth_get_public_keys; #apex + adbd_auth_notify_auth; # apex + adbd_auth_notify_disconnect; # apex + adbd_auth_prompt_user; # apex + adbd_auth_supports_feature; # apex + local: + *; +}; diff --git a/libs/arect/Android.bp b/libs/arect/Android.bp index ad8287c203..2518b1427d 100644 --- a/libs/arect/Android.bp +++ b/libs/arect/Android.bp @@ -13,13 +13,18 @@ // limitations under the License. ndk_headers { - name: "libarect_headers", + name: "libarect_headers_for_ndk", from: "include/android", to: "android", srcs: ["include/android/*.h"], license: "NOTICE", } +cc_library_headers { + name: "libarect_headers", + export_include_dirs: ["include"], +} + cc_library_static { name: "libarect", host_supported: true, diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp index 643a956b4a..7ee4882b6a 100644 --- a/libs/binder/Android.bp +++ b/libs/binder/Android.bp @@ -73,6 +73,7 @@ cc_library { // or dessert updates. Instead, apex users should use libbinder_ndk. apex_available: [ "//apex_available:platform", + "com.android.vndk.current", // TODO(b/139016109) remove these three "com.android.media.swcodec", "test_com.android.media.swcodec", @@ -164,3 +165,16 @@ filegroup { ], path: "aidl", } + +aidl_interface { + name: "libbinder_aidl_test_stub", + local_include_dir: "aidl", + srcs: [":libbinder_aidl"], + visibility: [":__subpackages__"], + vendor_available: true, + backend: { + java: { + enabled: false, + }, + }, +} diff --git a/libs/binder/IServiceManager.cpp b/libs/binder/IServiceManager.cpp index a30df14bd6..bac8b6604b 100644 --- a/libs/binder/IServiceManager.cpp +++ b/libs/binder/IServiceManager.cpp @@ -72,6 +72,7 @@ public: bool allowIsolated, int dumpsysPriority) override; Vector<String16> listServices(int dumpsysPriority) override; sp<IBinder> waitForService(const String16& name16) override; + bool isDeclared(const String16& name) override; // for legacy ABI const String16& getInterfaceDescriptor() const override { @@ -279,19 +280,31 @@ sp<IBinder> ServiceManagerShim::waitForService(const String16& name16) std::condition_variable mCv; }; + // Simple RAII object to ensure a function call immediately before going out of scope + class Defer { + public: + Defer(std::function<void()>&& f) : mF(std::move(f)) {} + ~Defer() { mF(); } + private: + std::function<void()> mF; + }; + const std::string name = String8(name16).c_str(); sp<IBinder> out; if (!mTheRealServiceManager->getService(name, &out).isOk()) { return nullptr; } - if(out != nullptr) return out; + if (out != nullptr) return out; sp<Waiter> waiter = new Waiter; if (!mTheRealServiceManager->registerForNotifications( name, waiter).isOk()) { return nullptr; } + Defer unregister ([&] { + mTheRealServiceManager->unregisterForNotifications(name, waiter); + }); while(true) { { @@ -315,10 +328,18 @@ sp<IBinder> ServiceManagerShim::waitForService(const String16& name16) if (!mTheRealServiceManager->getService(name, &out).isOk()) { return nullptr; } - if(out != nullptr) return out; + if (out != nullptr) return out; ALOGW("Waited one second for %s", name.c_str()); } } +bool ServiceManagerShim::isDeclared(const String16& name) { + bool declared; + if (!mTheRealServiceManager->isDeclared(String8(name).c_str(), &declared).isOk()) { + return false; + } + return declared; +} + } // namespace android diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp index 63456404c0..9be06cdd19 100644 --- a/libs/binder/Parcel.cpp +++ b/libs/binder/Parcel.cpp @@ -505,7 +505,7 @@ void Parcel::updateWorkSourceRequestHeaderPosition() const { } } -#if defined(__ANDROID_VNDK__) && !defined(__ANDROID_APEX__) +#if defined(__ANDROID_APEX_COM_ANDROID_VNDK_CURRENT__) || (defined(__ANDROID_VNDK__) && !defined(__ANDROID_APEX__)) constexpr int32_t kHeader = B_PACK_CHARS('V', 'N', 'D', 'R'); #else constexpr int32_t kHeader = B_PACK_CHARS('S', 'Y', 'S', 'T'); @@ -1449,41 +1449,38 @@ restart_write: return err; } -status_t Parcel::readByteVectorInternal(int8_t* data, size_t size) const { - if (size_t(size) > dataAvail()) { - return BAD_VALUE; - } - return read(data, size); -} - status_t Parcel::readByteVector(std::vector<int8_t>* val) const { - if (status_t status = resizeOutVector(val); status != OK) return status; - return readByteVectorInternal(val->data(), val->size()); + size_t size; + if (status_t status = reserveOutVector(val, &size); status != OK) return status; + return readByteVectorInternal(val, size); } status_t Parcel::readByteVector(std::vector<uint8_t>* val) const { - if (status_t status = resizeOutVector(val); status != OK) return status; - return readByteVectorInternal(reinterpret_cast<int8_t*>(val->data()), val->size()); + size_t size; + if (status_t status = reserveOutVector(val, &size); status != OK) return status; + return readByteVectorInternal(val, size); } status_t Parcel::readByteVector(std::unique_ptr<std::vector<int8_t>>* val) const { - if (status_t status = resizeOutVector(val); status != OK) return status; + size_t size; + if (status_t status = reserveOutVector(val, &size); status != OK) return status; if (val->get() == nullptr) { - // resizeOutVector does not create the out vector if size is < 0. + // reserveOutVector does not create the out vector if size is < 0. // This occurs when writing a null byte vector. return OK; } - return readByteVectorInternal((*val)->data(), (*val)->size()); + return readByteVectorInternal(val->get(), size); } status_t Parcel::readByteVector(std::unique_ptr<std::vector<uint8_t>>* val) const { - if (status_t status = resizeOutVector(val); status != OK) return status; + size_t size; + if (status_t status = reserveOutVector(val, &size); status != OK) return status; if (val->get() == nullptr) { - // resizeOutVector does not create the out vector if size is < 0. + // reserveOutVector does not create the out vector if size is < 0. // This occurs when writing a null byte vector. return OK; } - return readByteVectorInternal(reinterpret_cast<int8_t*>((*val)->data()), (*val)->size()); + return readByteVectorInternal(val->get(), size); } status_t Parcel::readInt32Vector(std::unique_ptr<std::vector<int32_t>>* val) const { diff --git a/libs/binder/ProcessState.cpp b/libs/binder/ProcessState.cpp index 0336d3ebd4..ce2cd9969f 100644 --- a/libs/binder/ProcessState.cpp +++ b/libs/binder/ProcessState.cpp @@ -188,6 +188,30 @@ ssize_t ProcessState::getKernelReferences(size_t buf_count, uintptr_t* buf) return count; } +// Queries the driver for the current strong reference count of the node +// that the handle points to. Can only be used by the servicemanager. +// +// Returns -1 in case of failure, otherwise the strong reference count. +ssize_t ProcessState::getStrongRefCountForNodeByHandle(int32_t handle) { + binder_node_info_for_ref info; + memset(&info, 0, sizeof(binder_node_info_for_ref)); + + info.handle = handle; + + status_t result = ioctl(mDriverFD, BINDER_GET_NODE_INFO_FOR_REF, &info); + + if (result != OK) { + static bool logged = false; + if (!logged) { + ALOGW("Kernel does not support BINDER_GET_NODE_INFO_FOR_REF."); + logged = true; + } + return -1; + } + + return info.strong_count; +} + void ProcessState::setCallRestriction(CallRestriction restriction) { LOG_ALWAYS_FATAL_IF(IPCThreadState::selfOrNull() != nullptr, "Call restrictions must be set before the threadpool is started."); @@ -361,6 +385,12 @@ ProcessState::ProcessState(const char *driver) , mThreadPoolSeq(1) , mCallRestriction(CallRestriction::NONE) { + +// TODO(b/139016109): enforce in build system +#if defined(__ANDROID_APEX__) && !defined(__ANDROID_APEX_COM_ANDROID_VNDK_CURRENT__) + LOG_ALWAYS_FATAL("Cannot use libbinder in APEX (only system.img libbinder) since it is not stable."); +#endif + if (mDriverFD >= 0) { // mmap the binder, providing a chunk of virtual address space to receive transactions. mVMStart = mmap(nullptr, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0); diff --git a/libs/binder/Status.cpp b/libs/binder/Status.cpp index 0ad99cee3f..674f0657a9 100644 --- a/libs/binder/Status.cpp +++ b/libs/binder/Status.cpp @@ -232,9 +232,10 @@ String8 Status::toString8() const { ret.append("No error"); } else { ret.appendFormat("Status(%d, %s): '", mException, exceptionToString(mException).c_str()); - if (mException == EX_SERVICE_SPECIFIC || - mException == EX_TRANSACTION_FAILED) { + if (mException == EX_SERVICE_SPECIFIC) { ret.appendFormat("%d: ", mErrorCode); + } else if (mException == EX_TRANSACTION_FAILED) { + ret.appendFormat("%s: ", statusToString(mErrorCode).c_str()); } ret.append(String8(mMessage)); ret.append("'"); diff --git a/libs/binder/aidl/android/os/IServiceManager.aidl b/libs/binder/aidl/android/os/IServiceManager.aidl index 60c2cceaf2..b965881e7f 100644 --- a/libs/binder/aidl/android/os/IServiceManager.aidl +++ b/libs/binder/aidl/android/os/IServiceManager.aidl @@ -31,22 +31,22 @@ interface IServiceManager { * Must update values in IServiceManager.h */ /* Allows services to dump sections according to priorities. */ - const int DUMP_FLAG_PRIORITY_CRITICAL = 1; // 1 << 0 - const int DUMP_FLAG_PRIORITY_HIGH = 2; // 1 << 1 - const int DUMP_FLAG_PRIORITY_NORMAL = 4; // 1 << 2 + const int DUMP_FLAG_PRIORITY_CRITICAL = 1 << 0; + const int DUMP_FLAG_PRIORITY_HIGH = 1 << 1; + const int DUMP_FLAG_PRIORITY_NORMAL = 1 << 2; /** * Services are by default registered with a DEFAULT dump priority. DEFAULT priority has the * same priority as NORMAL priority but the services are not called with dump priority * arguments. */ - const int DUMP_FLAG_PRIORITY_DEFAULT = 8; // 1 << 3 + const int DUMP_FLAG_PRIORITY_DEFAULT = 1 << 3; const int DUMP_FLAG_PRIORITY_ALL = 15; // DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PRIORITY_HIGH // | DUMP_FLAG_PRIORITY_NORMAL | DUMP_FLAG_PRIORITY_DEFAULT; /* Allows services to dump sections in protobuf format. */ - const int DUMP_FLAG_PROTO = 16; // 1 << 4 + const int DUMP_FLAG_PROTO = 1 << 4; /** * Retrieve an existing service called @a name from the @@ -58,7 +58,7 @@ interface IServiceManager { * Returns null if the service does not exist. */ @UnsupportedAppUsage - IBinder getService(@utf8InCpp String name); + @nullable IBinder getService(@utf8InCpp String name); /** * Retrieve an existing service called @a name from the service @@ -66,7 +66,7 @@ interface IServiceManager { * exist. */ @UnsupportedAppUsage - IBinder checkService(@utf8InCpp String name); + @nullable IBinder checkService(@utf8InCpp String name); /** * Place a new @a service called @a name into the service @@ -89,4 +89,11 @@ interface IServiceManager { * Unregisters all requests for notifications for a specific callback. */ void unregisterForNotifications(@utf8InCpp String name, IServiceCallback callback); + + /** + * Returns whether a given interface is declared on the device, even if it + * is not started yet. For instance, this could be a service declared in the VINTF + * manifest. + */ + boolean isDeclared(@utf8InCpp String name); } diff --git a/libs/binder/include/binder/IInterface.h b/libs/binder/include/binder/IInterface.h index 28ffa48e32..79d9b79915 100644 --- a/libs/binder/include/binder/IInterface.h +++ b/libs/binder/include/binder/IInterface.h @@ -38,12 +38,32 @@ protected: // ---------------------------------------------------------------------- +/** + * If this is a local object and the descriptor matches, this will return the + * actual local object which is implementing the interface. Otherwise, this will + * return a proxy to the interface without checking the interface descriptor. + * This means that subsequent calls may fail with BAD_TYPE. + */ template<typename INTERFACE> inline sp<INTERFACE> interface_cast(const sp<IBinder>& obj) { return INTERFACE::asInterface(obj); } +/** + * This is the same as interface_cast, except that it always checks to make sure + * the descriptor matches, and if it doesn't match, it will return nullptr. + */ +template<typename INTERFACE> +inline sp<INTERFACE> checked_interface_cast(const sp<IBinder>& obj) +{ + if (obj->getInterfaceDescriptor() != INTERFACE::descriptor) { + return nullptr; + } + + return interface_cast<INTERFACE>(obj); +} + // ---------------------------------------------------------------------- template<typename INTERFACE> @@ -89,7 +109,27 @@ public: \ #define __IINTF_CONCAT(x, y) (x ## y) + +#ifndef DO_NOT_CHECK_MANUAL_BINDER_INTERFACES + +#define IMPLEMENT_META_INTERFACE(INTERFACE, NAME) \ + static_assert(internal::allowedManualInterface(NAME), \ + "b/64223827: Manually written binder interfaces are " \ + "considered error prone and frequently have bugs. " \ + "The preferred way to add interfaces is to define " \ + "an .aidl file to auto-generate the interface. If " \ + "an interface must be manually written, add its " \ + "name to the whitelist."); \ + DO_NOT_DIRECTLY_USE_ME_IMPLEMENT_META_INTERFACE(INTERFACE, NAME) \ + +#else + #define IMPLEMENT_META_INTERFACE(INTERFACE, NAME) \ + DO_NOT_DIRECTLY_USE_ME_IMPLEMENT_META_INTERFACE(INTERFACE, NAME) \ + +#endif + +#define DO_NOT_DIRECTLY_USE_ME_IMPLEMENT_META_INTERFACE(INTERFACE, NAME)\ const ::android::StaticString16 \ I##INTERFACE##_descriptor_static_str16(__IINTF_CONCAT(u, NAME));\ const ::android::String16 I##INTERFACE::descriptor( \ @@ -172,6 +212,122 @@ inline IBinder* BpInterface<INTERFACE>::onAsBinder() // ---------------------------------------------------------------------- +namespace internal { +constexpr const char* const kManualInterfaces[] = { + "android.app.IActivityManager", + "android.app.IUidObserver", + "android.drm.IDrm", + "android.dvr.IVsyncCallback", + "android.dvr.IVsyncService", + "android.gfx.tests.ICallback", + "android.gfx.tests.IIPCTest", + "android.gfx.tests.ISafeInterfaceTest", + "android.graphicsenv.IGpuService", + "android.gui.DisplayEventConnection", + "android.gui.IConsumerListener", + "android.gui.IGraphicBufferConsumer", + "android.gui.IRegionSamplingListener", + "android.gui.ITransactionComposerListener", + "android.gui.SensorEventConnection", + "android.gui.SensorServer", + "android.hardware.ICamera", + "android.hardware.ICameraClient", + "android.hardware.ICameraRecordingProxy", + "android.hardware.ICameraRecordingProxyListener", + "android.hardware.ICrypto", + "android.hardware.IOMXObserver", + "android.hardware.ISoundTrigger", + "android.hardware.ISoundTriggerClient", + "android.hardware.ISoundTriggerHwService", + "android.hardware.IStreamListener", + "android.hardware.IStreamSource", + "android.input.IInputFlinger", + "android.input.ISetInputWindowsListener", + "android.media.IAudioFlinger", + "android.media.IAudioFlingerClient", + "android.media.IAudioPolicyService", + "android.media.IAudioPolicyServiceClient", + "android.media.IAudioService", + "android.media.IAudioTrack", + "android.media.IDataSource", + "android.media.IDrmClient", + "android.media.IEffect", + "android.media.IEffectClient", + "android.media.IMediaAnalyticsService", + "android.media.IMediaCodecList", + "android.media.IMediaDrmService", + "android.media.IMediaExtractor", + "android.media.IMediaExtractorService", + "android.media.IMediaHTTPConnection", + "android.media.IMediaHTTPService", + "android.media.IMediaLogService", + "android.media.IMediaMetadataRetriever", + "android.media.IMediaPlayer", + "android.media.IMediaPlayerClient", + "android.media.IMediaPlayerService", + "android.media.IMediaRecorder", + "android.media.IMediaRecorderClient", + "android.media.IMediaResourceMonitor", + "android.media.IMediaSource", + "android.media.IRemoteDisplay", + "android.media.IRemoteDisplayClient", + "android.media.IResourceManagerClient", + "android.media.IResourceManagerService", + "android.os.IComplexTypeInterface", + "android.os.IPermissionController", + "android.os.IPingResponder", + "android.os.IPowerManager", + "android.os.IProcessInfoService", + "android.os.ISchedulingPolicyService", + "android.os.IStringConstants", + "android.os.storage.IObbActionListener", + "android.os.storage.IStorageEventListener", + "android.os.storage.IStorageManager", + "android.os.storage.IStorageShutdownObserver", + "android.service.vr.IPersistentVrStateCallbacks", + "android.service.vr.IVrManager", + "android.service.vr.IVrStateCallbacks", + "android.ui.ISurfaceComposer", + "android.ui.ISurfaceComposerClient", + "android.utils.IMemory", + "android.utils.IMemoryHeap", + "com.android.car.procfsinspector.IProcfsInspector", + "com.android.internal.app.IAppOpsCallback", + "com.android.internal.app.IAppOpsService", + "com.android.internal.app.IBatteryStats", + "com.android.internal.os.IResultReceiver", + "com.android.internal.os.IShellCallback", + "drm.IDrmManagerService", + "drm.IDrmServiceListener", + "IAAudioClient", + "IAAudioService", + "VtsFuzzer", + nullptr, +}; + +constexpr const char* const kDownstreamManualInterfaces[] = { + // Add downstream interfaces here. + nullptr, +}; + +constexpr bool equals(const char* a, const char* b) { + if (*a != *b) return false; + if (*a == '\0') return true; + return equals(a + 1, b + 1); +} + +constexpr bool inList(const char* a, const char* const* whitelist) { + if (*whitelist == nullptr) return false; + if (equals(a, *whitelist)) return true; + return inList(a, whitelist + 1); +} + +constexpr bool allowedManualInterface(const char* name) { + return inList(name, kManualInterfaces) || + inList(name, kDownstreamManualInterfaces); +} + +} // namespace internal } // namespace android #endif // ANDROID_IINTERFACE_H diff --git a/libs/binder/include/binder/IServiceManager.h b/libs/binder/include/binder/IServiceManager.h index a675513793..2c4326393e 100644 --- a/libs/binder/include/binder/IServiceManager.h +++ b/libs/binder/include/binder/IServiceManager.h @@ -88,6 +88,14 @@ public: * Returns nullptr only for permission problem or fatal error. */ virtual sp<IBinder> waitForService(const String16& name) = 0; + + /** + * Check if a service is declared (e.g. VINTF manifest). + * + * If this returns true, waitForService should always be able to return the + * service. + */ + virtual bool isDeclared(const String16& name) = 0; }; sp<IServiceManager> defaultServiceManager(); @@ -99,6 +107,34 @@ sp<INTERFACE> waitForService(const String16& name) { } template<typename INTERFACE> +sp<INTERFACE> waitForDeclaredService(const String16& name) { + const sp<IServiceManager> sm = defaultServiceManager(); + if (!sm->isDeclared(name)) return nullptr; + return interface_cast<INTERFACE>(sm->waitForService(name)); +} + +template <typename INTERFACE> +sp<INTERFACE> checkDeclaredService(const String16& name) { + const sp<IServiceManager> sm = defaultServiceManager(); + if (!sm->isDeclared(name)) return nullptr; + return interface_cast<INTERFACE>(sm->checkService(name)); +} + +template<typename INTERFACE> +sp<INTERFACE> waitForVintfService( + const String16& instance = String16("default")) { + return waitForDeclaredService<INTERFACE>( + INTERFACE::descriptor + String16("/") + instance); +} + +template<typename INTERFACE> +sp<INTERFACE> checkVintfService( + const String16& instance = String16("default")) { + return checkDeclaredService<INTERFACE>( + INTERFACE::descriptor + String16("/") + instance); +} + +template<typename INTERFACE> status_t getService(const String16& name, sp<INTERFACE>* outService) { const sp<IServiceManager> sm = defaultServiceManager(); diff --git a/libs/binder/include/binder/Parcel.h b/libs/binder/include/binder/Parcel.h index 0f8ababd6b..d4bb85b102 100644 --- a/libs/binder/include/binder/Parcel.h +++ b/libs/binder/include/binder/Parcel.h @@ -356,6 +356,11 @@ public: status_t resizeOutVector(std::vector<T>* val) const; template<typename T> status_t resizeOutVector(std::unique_ptr<std::vector<T>>* val) const; + template<typename T> + status_t reserveOutVector(std::vector<T>* val, size_t* size) const; + template<typename T> + status_t reserveOutVector(std::unique_ptr<std::vector<T>>* val, + size_t* size) const; // Like Parcel.java's readExceptionCode(). Reads the first int32 // off of a Parcel's header, returning 0 or the negative error @@ -475,7 +480,8 @@ private: status_t readEnum(T* pArg) const; status_t writeByteVectorInternal(const int8_t* data, size_t size); - status_t readByteVectorInternal(int8_t* data, size_t size) const; + template<typename T> + status_t readByteVectorInternal(std::vector<T>* val, size_t size) const; template<typename T, typename U> status_t unsafeReadTypedVector(std::vector<T>* val, @@ -720,6 +726,42 @@ status_t Parcel::resizeOutVector(std::unique_ptr<std::vector<T>>* val) const { } template<typename T> +status_t Parcel::reserveOutVector(std::vector<T>* val, size_t* size) const { + int32_t read_size; + status_t err = readInt32(&read_size); + if (err != NO_ERROR) { + return err; + } + + if (read_size < 0) { + return UNEXPECTED_NULL; + } + *size = static_cast<size_t>(read_size); + val->reserve(*size); + return OK; +} + +template<typename T> +status_t Parcel::reserveOutVector(std::unique_ptr<std::vector<T>>* val, + size_t* size) const { + int32_t read_size; + status_t err = readInt32(&read_size); + if (err != NO_ERROR) { + return err; + } + + if (read_size >= 0) { + *size = static_cast<size_t>(read_size); + val->reset(new std::vector<T>()); + (*val)->reserve(*size); + } else { + val->reset(); + } + + return OK; +} + +template<typename T> status_t Parcel::readStrongBinder(sp<T>* val) const { sp<IBinder> tmp; status_t ret = readStrongBinder(&tmp); @@ -988,20 +1030,33 @@ status_t Parcel::readEnum(T* pArg) const { return readInt64(reinterpret_cast<int64_t *>(pArg)); } +template<typename T> +inline status_t Parcel::readByteVectorInternal(std::vector<T>* val, size_t size) const { + // readByteVectorInternal expects a vector that has been reserved (but not + // resized) to have the provided size. + const T* data = reinterpret_cast<const T*>(readInplace(size)); + if (!data) return BAD_VALUE; + val->clear(); + val->insert(val->begin(), data, data+size); + return NO_ERROR; +} + template<typename T, std::enable_if_t<std::is_enum_v<T> && std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool>> status_t Parcel::readEnumVector(std::vector<T>* val) const { - if (status_t status = resizeOutVector(val); status != OK) return status; - return readByteVectorInternal(reinterpret_cast<int8_t*>(val->data()), val->size()); + size_t size; + if (status_t status = reserveOutVector(val, &size); status != OK) return status; + return readByteVectorInternal(val, size); } template<typename T, std::enable_if_t<std::is_enum_v<T> && std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool>> status_t Parcel::readEnumVector(std::unique_ptr<std::vector<T>>* val) const { - if (status_t status = resizeOutVector(val); status != OK) return status; + size_t size; + if (status_t status = reserveOutVector(val, &size); status != OK) return status; if (val->get() == nullptr) { - // resizeOutVector does not create the out vector if size is < 0. + // reserveOutVector does not create the out vector if size is < 0. // This occurs when writing a null Enum vector. return OK; } - return readByteVectorInternal(reinterpret_cast<int8_t*>((*val)->data()), (*val)->size()); + return readByteVectorInternal(val->get(), size); } template<typename T, std::enable_if_t<std::is_enum_v<T> && !std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool>> status_t Parcel::readEnumVector(std::vector<T>* val) const { diff --git a/libs/binder/include/binder/ParcelFileDescriptor.h b/libs/binder/include/binder/ParcelFileDescriptor.h index 662e56e864..4635ad84c6 100644 --- a/libs/binder/include/binder/ParcelFileDescriptor.h +++ b/libs/binder/include/binder/ParcelFileDescriptor.h @@ -42,6 +42,24 @@ public: android::status_t writeToParcel(android::Parcel* parcel) const override; android::status_t readFromParcel(const android::Parcel* parcel) override; + inline bool operator!=(const ParcelFileDescriptor& rhs) const { + return mFd != rhs.mFd; + } + inline bool operator<(const ParcelFileDescriptor& rhs) const { + return mFd < rhs.mFd; + } + inline bool operator<=(const ParcelFileDescriptor& rhs) const { + return mFd <= rhs.mFd; + } + inline bool operator==(const ParcelFileDescriptor& rhs) const { + return mFd == rhs.mFd; + } + inline bool operator>(const ParcelFileDescriptor& rhs) const { + return mFd > rhs.mFd; + } + inline bool operator>=(const ParcelFileDescriptor& rhs) const { + return mFd >= rhs.mFd; + } private: android::base::unique_fd mFd; }; diff --git a/libs/binder/include/binder/ProcessState.h b/libs/binder/include/binder/ProcessState.h index f7c38f418d..e57ff1c260 100644 --- a/libs/binder/include/binder/ProcessState.h +++ b/libs/binder/include/binder/ProcessState.h @@ -69,6 +69,14 @@ public: ssize_t getKernelReferences(size_t count, uintptr_t* buf); + // Only usable by the context manager. + // This refcount includes: + // 1. Strong references to the node by this and other processes + // 2. Temporary strong references held by the kernel during a + // transaction on the node. + // It does NOT include local strong references to the node + ssize_t getStrongRefCountForNodeByHandle(int32_t handle); + enum class CallRestriction { // all calls okay NONE, diff --git a/libs/binder/include/binder/Stability.h b/libs/binder/include/binder/Stability.h index 2894482f55..b2f51d381c 100644 --- a/libs/binder/include/binder/Stability.h +++ b/libs/binder/include/binder/Stability.h @@ -81,7 +81,7 @@ private: VINTF = 0b111111, }; -#if defined(__ANDROID_VNDK__) && !defined(__ANDROID_APEX__) +#if defined(__ANDROID_APEX_COM_ANDROID_VNDK_CURRENT__) || (defined(__ANDROID_VNDK__) && !defined(__ANDROID_APEX__)) static constexpr Level kLocalStability = Level::VENDOR; #else static constexpr Level kLocalStability = Level::SYSTEM; diff --git a/libs/binder/ndk/Android.bp b/libs/binder/ndk/Android.bp index 62a0f9f9b1..c0ea6d7b1e 100644 --- a/libs/binder/ndk/Android.bp +++ b/libs/binder/ndk/Android.bp @@ -22,6 +22,8 @@ cc_defaults { cflags: [ "-D__INTRODUCED_IN(n)=", "-D__assert(a,b,c)=", + // We want all the APIs to be available on the host. + "-D__ANDROID_API__=10000", ], }, }, diff --git a/libs/binder/ndk/include_ndk/android/binder_auto_utils.h b/libs/binder/ndk/include_ndk/android/binder_auto_utils.h index dc3c8d2e3a..946ccb79a5 100644 --- a/libs/binder/ndk/include_ndk/android/binder_auto_utils.h +++ b/libs/binder/ndk/include_ndk/android/binder_auto_utils.h @@ -21,7 +21,7 @@ /** * @file binder_auto_utils.h - * @brief These objects provide a more C++-like thin interface to the . + * @brief These objects provide a more C++-like thin interface to the binder. */ #pragma once @@ -159,13 +159,17 @@ class ScopedAResource { */ T* getR() { return &mT; } - // copy-constructing, or move/copy assignment is disallowed + // copy-constructing/assignment is disallowed ScopedAResource(const ScopedAResource&) = delete; ScopedAResource& operator=(const ScopedAResource&) = delete; - ScopedAResource& operator=(ScopedAResource&&) = delete; - // move-constructing is okay + // move-constructing/assignment is okay ScopedAResource(ScopedAResource&& other) : mT(std::move(other.mT)) { other.mT = DEFAULT; } + ScopedAResource& operator=(ScopedAResource&& other) { + set(other.mT); + other.mT = DEFAULT; + return *this; + } private: T mT; @@ -197,6 +201,7 @@ class ScopedAStatus : public impl::ScopedAResource<AStatus*, void, AStatus_delet explicit ScopedAStatus(AStatus* a = nullptr) : ScopedAResource(a) {} ~ScopedAStatus() {} ScopedAStatus(ScopedAStatus&&) = default; + ScopedAStatus& operator=(ScopedAStatus&&) = default; /** * See AStatus_isOk. @@ -219,9 +224,31 @@ class ScopedAStatus : public impl::ScopedAResource<AStatus*, void, AStatus_delet binder_status_t getStatus() const { return AStatus_getStatus(get()); } /** - * Convenience method for okay status. + * See AStatus_getMessage + */ + const char* getMessage() const { return AStatus_getMessage(get()); } + + /** + * Convenience methods for creating scoped statuses. */ static ScopedAStatus ok() { return ScopedAStatus(AStatus_newOk()); } + static ScopedAStatus fromExceptionCode(binder_exception_t exception) { + return ScopedAStatus(AStatus_fromExceptionCode(exception)); + } + static ScopedAStatus fromExceptionCodeWithMessage(binder_exception_t exception, + const char* message) { + return ScopedAStatus(AStatus_fromExceptionCodeWithMessage(exception, message)); + } + static ScopedAStatus fromServiceSpecificError(int32_t serviceSpecific) { + return ScopedAStatus(AStatus_fromServiceSpecificError(serviceSpecific)); + } + static ScopedAStatus fromServiceSpecificErrorWithMessage(int32_t serviceSpecific, + const char* message) { + return ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(serviceSpecific, message)); + } + static ScopedAStatus fromStatus(binder_status_t status) { + return ScopedAStatus(AStatus_fromStatus(status)); + } }; /** diff --git a/libs/binder/ndk/include_ndk/android/binder_ibinder.h b/libs/binder/ndk/include_ndk/android/binder_ibinder.h index 160739b044..4560f222cb 100644 --- a/libs/binder/ndk/include_ndk/android/binder_ibinder.h +++ b/libs/binder/ndk/include_ndk/android/binder_ibinder.h @@ -34,7 +34,13 @@ #include <android/binder_status.h> __BEGIN_DECLS -#if __ANDROID_API__ >= __ANDROID_API_Q__ + +#ifndef __ANDROID_API__ +#error Android builds must be compiled against a specific API. If this is an \ + android platform host build, you must use libbinder_ndk_host_user. +#endif + +#if __ANDROID_API__ >= 29 // Also see TF_* in kernel's binder.h typedef uint32_t binder_flags_t; @@ -165,6 +171,8 @@ typedef binder_status_t (*AIBinder_Class_onTransact)(AIBinder* binder, transacti * * None of these parameters can be null. * + * Available since API level 29. + * * \param interfaceDescriptor this is a unique identifier for the class. This is used internally for * sanity checks on transactions. * \param onCreate see AIBinder_Class_onCreate. @@ -199,6 +207,8 @@ typedef binder_status_t (*AIBinder_onDump)(AIBinder* binder, int fd, const char* * If this isn't set, nothing will be dumped when dump is called (for instance with * android.os.Binder#dump). Must be called before any instance of the class is created. * + * Available since API level 29. + * * \param dump function to call when an instance of this binder class is being dumped. */ void AIBinder_Class_setOnDump(AIBinder_Class* clazz, AIBinder_onDump onDump) __INTRODUCED_IN(29); @@ -220,6 +230,8 @@ void AIBinder_Class_setOnDump(AIBinder_Class* clazz, AIBinder_onDump onDump) __I * these two objects are actually equal using the AIBinder pointer alone (which they should be able * to do). Also see the suggested memory ownership model suggested above. * + * Available since API level 29. + * * \param clazz the type of the object to be created. * \param args the args to pass to AIBinder_onCreate for that class. * @@ -231,6 +243,8 @@ __attribute__((warn_unused_result)) AIBinder* AIBinder_new(const AIBinder_Class* /** * If this is hosted in a process other than the current one. * + * Available since API level 29. + * * \param binder the binder being queried. * * \return true if the AIBinder represents an object in another process. @@ -244,6 +258,8 @@ bool AIBinder_isRemote(const AIBinder* binder) __INTRODUCED_IN(29); * updated as the result of a transaction made using AIBinder_transact, but it will also be updated * based on the results of bookkeeping or other transactions made internally. * + * Available since API level 29. + * * \param binder the binder being queried. * * \return true if the binder is alive. @@ -255,6 +271,8 @@ bool AIBinder_isAlive(const AIBinder* binder) __INTRODUCED_IN(29); * return. Usually this is used to make sure that a binder is alive, as a placeholder call, or as a * sanity check. * + * Available since API level 29. + * * \param binder the binder being queried. * * \return STATUS_OK if the ping succeeds. @@ -264,7 +282,9 @@ binder_status_t AIBinder_ping(AIBinder* binder) __INTRODUCED_IN(29); /** * Built-in transaction for all binder objects. This dumps information about a given binder. * - * See also AIBinder_Class_setOnDump, AIBinder_onDump + * See also AIBinder_Class_setOnDump, AIBinder_onDump. + * + * Available since API level 29. * * \param binder the binder to dump information about * \param fd where information should be dumped to @@ -287,6 +307,8 @@ binder_status_t AIBinder_dump(AIBinder* binder, int fd, const char** args, uint3 * * If binder is local, this will return STATUS_INVALID_OPERATION. * + * Available since API level 29. + * * \param binder the binder object you want to receive death notifications from. * \param recipient the callback that will receive notifications when/if the binder dies. * \param cookie the value that will be passed to the death recipient on death. @@ -306,6 +328,8 @@ binder_status_t AIBinder_linkToDeath(AIBinder* binder, AIBinder_DeathRecipient* * If the binder dies, it will automatically unlink. If the binder is deleted, it will be * automatically unlinked. * + * Available since API level 29. + * * \param binder the binder object to remove a previously linked death recipient from. * \param recipient the callback to remove. * \param cookie the cookie used to link to death. @@ -322,9 +346,11 @@ binder_status_t AIBinder_unlinkToDeath(AIBinder* binder, AIBinder_DeathRecipient * This can be used with higher-level system services to determine the caller's identity and check * permissions. * + * Available since API level 29. + * * \return calling uid or the current process's UID if this thread isn't processing a transaction. */ -uid_t AIBinder_getCallingUid(); +uid_t AIBinder_getCallingUid() __INTRODUCED_IN(29); /** * This returns the calling PID assuming that this thread is called from a thread that is processing @@ -335,14 +361,18 @@ uid_t AIBinder_getCallingUid(); * calling process dies and is replaced with another process with elevated permissions and the same * PID. * + * Available since API level 29. + * * \return calling pid or the current process's PID if this thread isn't processing a transaction. * If the transaction being processed is a oneway transaction, then this method will return 0. */ -pid_t AIBinder_getCallingPid(); +pid_t AIBinder_getCallingPid() __INTRODUCED_IN(29); /** * This can only be called if a strong reference to this object already exists in process. * + * Available since API level 29. + * * \param binder the binder object to add a refcount to. */ void AIBinder_incStrong(AIBinder* binder) __INTRODUCED_IN(29); @@ -350,6 +380,8 @@ void AIBinder_incStrong(AIBinder* binder) __INTRODUCED_IN(29); /** * This will delete the object and call onDestroy once the refcount reaches zero. * + * Available since API level 29. + * * \param binder the binder object to remove a refcount from. */ void AIBinder_decStrong(AIBinder* binder) __INTRODUCED_IN(29); @@ -357,6 +389,8 @@ void AIBinder_decStrong(AIBinder* binder) __INTRODUCED_IN(29); /** * For debugging only! * + * Available since API level 29. + * * \param binder the binder object to retrieve the refcount of. * * \return the number of strong-refs on this binder in this process. If binder is null, this will be @@ -373,6 +407,8 @@ int32_t AIBinder_debugGetRefCount(AIBinder* binder) __INTRODUCED_IN(29); * This returns true if the class association succeeds. If it fails, no change is made to the * binder object. * + * Available since API level 29. + * * \param binder the object to attach the class to. * \param clazz the clazz to attach to binder. * @@ -383,6 +419,8 @@ bool AIBinder_associateClass(AIBinder* binder, const AIBinder_Class* clazz) __IN /** * Returns the class that this binder was constructed with or associated with. * + * Available since API level 29. + * * \param binder the object that is being queried. * * \return the class that this binder is associated with. If this binder wasn't created with @@ -394,6 +432,8 @@ const AIBinder_Class* AIBinder_getClass(AIBinder* binder) __INTRODUCED_IN(29); * Value returned by onCreate for a local binder. For stateless classes (if onCreate returns * null), this also returns null. For a remote binder, this will always return null. * + * Available since API level 29. + * * \param binder the object that is being queried. * * \return the userdata returned from AIBinder_onCreate when this object was created. This may be @@ -422,6 +462,8 @@ void* AIBinder_getUserData(AIBinder* binder) __INTRODUCED_IN(29); * AIBinder_transact. Alternatively, if there is an error while filling out the parcel, it can be * deleted with AParcel_delete. * + * Available since API level 29. + * * \param binder the binder object to start a transaction on. * \param in out parameter for input data to the transaction. * @@ -442,6 +484,8 @@ binder_status_t AIBinder_prepareTransaction(AIBinder* binder, AParcel** in) __IN * This does not affect the ownership of binder. The out parcel's ownership is passed to the caller * and must be released with AParcel_delete when finished reading. * + * Available since API level 29. + * * \param binder the binder object to transact on. * \param code the implementation-specific code representing which transaction should be taken. * \param in the implementation-specific input data to this transaction. @@ -459,6 +503,8 @@ binder_status_t AIBinder_transact(AIBinder* binder, transaction_code_t code, APa * This does not take any ownership of the input binder, but it can be used to retrieve it if * something else in some process still holds a reference to it. * + * Available since API level 29. + * * \param binder object to create a weak pointer to. * * \return object representing a weak pointer to binder (or null if binder is null). @@ -469,6 +515,8 @@ __attribute__((warn_unused_result)) AIBinder_Weak* AIBinder_Weak_new(AIBinder* b /** * Deletes the weak reference. This will have no impact on the lifetime of the binder. * + * Available since API level 29. + * * \param weakBinder object created with AIBinder_Weak_new. */ void AIBinder_Weak_delete(AIBinder_Weak* weakBinder) __INTRODUCED_IN(29); @@ -477,6 +525,8 @@ void AIBinder_Weak_delete(AIBinder_Weak* weakBinder) __INTRODUCED_IN(29); * If promotion succeeds, result will have one strong refcount added to it. Otherwise, this returns * null. * + * Available since API level 29. + * * \param weakBinder weak pointer to attempt retrieving the original object from. * * \return an AIBinder object with one refcount given to the caller or null. @@ -487,6 +537,8 @@ __attribute__((warn_unused_result)) AIBinder* AIBinder_Weak_promote(AIBinder_Wea /** * This function is executed on death receipt. See AIBinder_linkToDeath/AIBinder_unlinkToDeath. * + * Available since API level 29. + * * \param cookie the cookie passed to AIBinder_linkToDeath. */ typedef void (*AIBinder_DeathRecipient_onBinderDied)(void* cookie) __INTRODUCED_IN(29); @@ -494,6 +546,8 @@ typedef void (*AIBinder_DeathRecipient_onBinderDied)(void* cookie) __INTRODUCED_ /** * Creates a new binder death recipient. This can be attached to multiple different binder objects. * + * Available since API level 29. + * * \param onBinderDied the callback to call when this death recipient is invoked. * * \return the newly constructed object (or null if onBinderDied is null). @@ -505,19 +559,23 @@ __attribute__((warn_unused_result)) AIBinder_DeathRecipient* AIBinder_DeathRecip * Deletes a binder death recipient. It is not necessary to call AIBinder_unlinkToDeath before * calling this as these will all be automatically unlinked. * + * Available since API level 29. + * * \param recipient the binder to delete (previously created with AIBinder_DeathRecipient_new). */ void AIBinder_DeathRecipient_delete(AIBinder_DeathRecipient* recipient) __INTRODUCED_IN(29); -#endif //__ANDROID_API__ >= __ANDROID_API_Q__ +#endif //__ANDROID_API__ >= 29 -#if __ANDROID_API__ >= __ANDROID_API_R__ +#if __ANDROID_API__ >= 30 /** * Gets the extension registered with AIBinder_setExtension. * * See AIBinder_setExtension. * + * Available since API level 30. + * * \param binder the object to get the extension of. * \param outExt the returned extension object. Will be null if there is no extension set or * non-null with one strong ref count. @@ -570,6 +628,8 @@ binder_status_t AIBinder_getExtension(AIBinder* binder, AIBinder** outExt) __INT * // if bar is null, then there is no extension or a different * // type of extension * + * Available since API level 30. + * * \param binder the object to get the extension on. Must be local. * \param ext the extension to set (binder will hold a strong reference to this) * @@ -578,7 +638,7 @@ binder_status_t AIBinder_getExtension(AIBinder* binder, AIBinder** outExt) __INT */ binder_status_t AIBinder_setExtension(AIBinder* binder, AIBinder* ext) __INTRODUCED_IN(30); -#endif //__ANDROID_API__ >= __ANDROID_API_R__ +#endif //__ANDROID_API__ >= 30 __END_DECLS diff --git a/libs/binder/ndk/include_ndk/android/binder_ibinder_jni.h b/libs/binder/ndk/include_ndk/android/binder_ibinder_jni.h index 124f36c55b..be3029c3ff 100644 --- a/libs/binder/ndk/include_ndk/android/binder_ibinder_jni.h +++ b/libs/binder/ndk/include_ndk/android/binder_ibinder_jni.h @@ -31,7 +31,7 @@ #include <jni.h> __BEGIN_DECLS -#if __ANDROID_API__ >= __ANDROID_API_Q__ +#if __ANDROID_API__ >= 29 /** * Converts an android.os.IBinder object into an AIBinder* object. @@ -40,6 +40,8 @@ __BEGIN_DECLS * AIBinder object, the original object is returned. The returned object has one refcount * associated with it, and so this should be accompanied with an AIBinder_decStrong call. * + * Available since API level 29. + * * \param env Java environment. * \param binder android.os.IBinder java object. * @@ -55,6 +57,8 @@ __attribute__((warn_unused_result)) AIBinder* AIBinder_fromJavaBinder(JNIEnv* en * If either env or the binder is null, null is returned. If this binder object was originally an * IBinder object, the original java object will be returned. * + * Available since API level 29. + * * \param env Java environment. * \param binder the object to convert. * @@ -63,7 +67,7 @@ __attribute__((warn_unused_result)) AIBinder* AIBinder_fromJavaBinder(JNIEnv* en __attribute__((warn_unused_result)) jobject AIBinder_toJavaBinder(JNIEnv* env, AIBinder* binder) __INTRODUCED_IN(29); -#endif //__ANDROID_API__ >= __ANDROID_API_Q__ +#endif //__ANDROID_API__ >= 29 __END_DECLS /** @} */ diff --git a/libs/binder/ndk/include_ndk/android/binder_parcel.h b/libs/binder/ndk/include_ndk/android/binder_parcel.h index 8c4170754a..86b75b8c61 100644 --- a/libs/binder/ndk/include_ndk/android/binder_parcel.h +++ b/libs/binder/ndk/include_ndk/android/binder_parcel.h @@ -35,7 +35,7 @@ struct AIBinder; typedef struct AIBinder AIBinder; __BEGIN_DECLS -#if __ANDROID_API__ >= __ANDROID_API_Q__ +#if __ANDROID_API__ >= 29 /** * This object represents a package of data that can be sent between processes. When transacting, an @@ -49,6 +49,8 @@ typedef struct AParcel AParcel; /** * Cleans up a parcel. * + * Available since API level 29. + * * \param parcel A parcel returned by AIBinder_prepareTransaction or AIBinder_transact when a * transaction is being aborted. */ @@ -57,6 +59,8 @@ void AParcel_delete(AParcel* parcel) __INTRODUCED_IN(29); /** * Sets the position within the parcel. * + * Available since API level 29. + * * \param parcel The parcel of which to set the position. * \param position Position of the parcel to set. This must be a value returned by * AParcel_getDataPosition. Positions are constant for a given parcel between processes. @@ -69,6 +73,8 @@ binder_status_t AParcel_setDataPosition(const AParcel* parcel, int32_t position) /** * Gets the current position within the parcel. * + * Available since API level 29. + * * \param parcel The parcel of which to get the position. * * \return The size of the parcel. This will always be greater than 0. The values returned by this @@ -389,6 +395,8 @@ typedef bool (*AParcel_byteArrayAllocator)(void* arrayData, int32_t length, int8 * Writes an AIBinder to the next location in a non-null parcel. Can be null. This does not take any * refcounts of ownership of the binder from the client. * + * Available since API level 29. + * * \param parcel the parcel to write to. * \param binder the value to write to the parcel. * @@ -400,6 +408,8 @@ binder_status_t AParcel_writeStrongBinder(AParcel* parcel, AIBinder* binder) __I * Reads an AIBinder from the next location in a non-null parcel. One strong ref-count of ownership * is passed to the caller of this function. * + * Available since API level 29. + * * \param parcel the parcel to read from. * \param binder the out parameter for what is read from the parcel. This may be null. * @@ -414,12 +424,14 @@ binder_status_t AParcel_readStrongBinder(const AParcel* parcel, AIBinder** binde * * This corresponds to the SDK's android.os.ParcelFileDescriptor. * + * Available since API level 29. + * * \param parcel the parcel to write to. * \param fd the value to write to the parcel (-1 to represent a null ParcelFileDescriptor). * * \return STATUS_OK on successful write. */ -binder_status_t AParcel_writeParcelFileDescriptor(AParcel* parcel, int fd); +binder_status_t AParcel_writeParcelFileDescriptor(AParcel* parcel, int fd) __INTRODUCED_IN(29); /** * Reads an int from the next location in a non-null parcel. @@ -428,13 +440,16 @@ binder_status_t AParcel_writeParcelFileDescriptor(AParcel* parcel, int fd); * * This corresponds to the SDK's android.os.ParcelFileDescriptor. * + * Available since API level 29. + * * \param parcel the parcel to read from. * \param fd the out parameter for what is read from the parcel (or -1 to represent a null * ParcelFileDescriptor) * * \return STATUS_OK on successful write. */ -binder_status_t AParcel_readParcelFileDescriptor(const AParcel* parcel, int* fd); +binder_status_t AParcel_readParcelFileDescriptor(const AParcel* parcel, int* fd) + __INTRODUCED_IN(29); /** * Writes an AStatus object to the next location in a non-null parcel. @@ -445,6 +460,8 @@ binder_status_t AParcel_readParcelFileDescriptor(const AParcel* parcel, int* fd) * this happens or if writing the status object itself fails, the return value from this function * should be propagated to the client, and AParcel_readStatusHeader shouldn't be called. * + * Available since API level 29. + * * \param parcel the parcel to write to. * \param status the value to write to the parcel. * @@ -457,6 +474,8 @@ binder_status_t AParcel_writeStatusHeader(AParcel* parcel, const AStatus* status * Reads an AStatus from the next location in a non-null parcel. Ownership is passed to the caller * of this function. * + * Available since API level 29. + * * \param parcel the parcel to read from. * \param status the out parameter for what is read from the parcel. * @@ -470,6 +489,8 @@ binder_status_t AParcel_readStatusHeader(const AParcel* parcel, AStatus** status * * If length is -1, and string is nullptr, this will write a 'null' string to the parcel. * + * Available since API level 29. + * * \param parcel the parcel to write to. * \param string the null-terminated string to write to the parcel, at least of size 'length'. * \param length the length of the string to be written. @@ -487,6 +508,8 @@ binder_status_t AParcel_writeString(AParcel* parcel, const char* string, int32_t * the output buffer from this read. If there is a 'null' string on the binder buffer, the allocator * will be called with length -1. * + * Available since API level 29. + * * \param parcel the parcel to read from. * \param stringData some external representation of a string. * \param allocator allocator that will be called once the size of the string is known. @@ -504,6 +527,8 @@ binder_status_t AParcel_readString(const AParcel* parcel, void* stringData, * returned from this function will be used to fill out the data from the parcel. If length is -1, * this will write a 'null' string array to the binder buffer. * + * Available since API level 29. + * * \param parcel the parcel to write to. * \param arrayData some external representation of an array. * \param length the length of the array to be written. @@ -526,6 +551,8 @@ binder_status_t AParcel_writeStringArray(AParcel* parcel, const void* arrayData, * the contents of the string that is read. If the string array being read is 'null', this will * instead just pass -1 to AParcel_stringArrayAllocator. * + * Available since API level 29. + * * \param parcel the parcel to read from. * \param arrayData some external representation of an array. * \param allocator the callback that will be called with arrayData once the size of the output @@ -543,6 +570,8 @@ binder_status_t AParcel_readStringArray(const AParcel* parcel, void* arrayData, /** * Writes an array of parcelables (user-defined types) to the next location in a non-null parcel. * + * Available since API level 29. + * * \param parcel the parcel to write to. * \param arrayData an array of size 'length' (or null if length is -1, may be null if length is 0). * \param length the length of arrayData or -1 if this represents a null array. @@ -562,6 +591,8 @@ binder_status_t AParcel_writeParcelableArray(AParcel* parcel, const void* arrayD * length is greater than zero, elementReader will be called for every index to read the * corresponding parcelable. * + * Available since API level 29. + * * \param parcel the parcel to read from. * \param arrayData some external representation of an array. * \param allocator the callback that will be called to allocate the array. @@ -578,6 +609,8 @@ binder_status_t AParcel_readParcelableArray(const AParcel* parcel, void* arrayDa /** * Writes int32_t value to the next location in a non-null parcel. * + * Available since API level 29. + * * \param parcel the parcel to write to. * \param value the value to write to the parcel. * @@ -588,6 +621,8 @@ binder_status_t AParcel_writeInt32(AParcel* parcel, int32_t value) __INTRODUCED_ /** * Writes uint32_t value to the next location in a non-null parcel. * + * Available since API level 29. + * * \param parcel the parcel to write to. * \param value the value to write to the parcel. * @@ -598,6 +633,8 @@ binder_status_t AParcel_writeUint32(AParcel* parcel, uint32_t value) __INTRODUCE /** * Writes int64_t value to the next location in a non-null parcel. * + * Available since API level 29. + * * \param parcel the parcel to write to. * \param value the value to write to the parcel. * @@ -608,6 +645,8 @@ binder_status_t AParcel_writeInt64(AParcel* parcel, int64_t value) __INTRODUCED_ /** * Writes uint64_t value to the next location in a non-null parcel. * + * Available since API level 29. + * * \param parcel the parcel to write to. * \param value the value to write to the parcel. * @@ -618,6 +657,8 @@ binder_status_t AParcel_writeUint64(AParcel* parcel, uint64_t value) __INTRODUCE /** * Writes float value to the next location in a non-null parcel. * + * Available since API level 29. + * * \param parcel the parcel to write to. * \param value the value to write to the parcel. * @@ -628,6 +669,8 @@ binder_status_t AParcel_writeFloat(AParcel* parcel, float value) __INTRODUCED_IN /** * Writes double value to the next location in a non-null parcel. * + * Available since API level 29. + * * \param parcel the parcel to write to. * \param value the value to write to the parcel. * @@ -638,6 +681,8 @@ binder_status_t AParcel_writeDouble(AParcel* parcel, double value) __INTRODUCED_ /** * Writes bool value to the next location in a non-null parcel. * + * Available since API level 29. + * * \param parcel the parcel to write to. * \param value the value to write to the parcel. * @@ -648,6 +693,8 @@ binder_status_t AParcel_writeBool(AParcel* parcel, bool value) __INTRODUCED_IN(2 /** * Writes char16_t value to the next location in a non-null parcel. * + * Available since API level 29. + * * \param parcel the parcel to write to. * \param value the value to write to the parcel. * @@ -658,6 +705,8 @@ binder_status_t AParcel_writeChar(AParcel* parcel, char16_t value) __INTRODUCED_ /** * Writes int8_t value to the next location in a non-null parcel. * + * Available since API level 29. + * * \param parcel the parcel to write to. * \param value the value to write to the parcel. * @@ -668,6 +717,8 @@ binder_status_t AParcel_writeByte(AParcel* parcel, int8_t value) __INTRODUCED_IN /** * Reads into int32_t value from the next location in a non-null parcel. * + * Available since API level 29. + * * \param parcel the parcel to read from. * \param value the value to read from the parcel. * @@ -678,6 +729,8 @@ binder_status_t AParcel_readInt32(const AParcel* parcel, int32_t* value) __INTRO /** * Reads into uint32_t value from the next location in a non-null parcel. * + * Available since API level 29. + * * \param parcel the parcel to read from. * \param value the value to read from the parcel. * @@ -688,6 +741,8 @@ binder_status_t AParcel_readUint32(const AParcel* parcel, uint32_t* value) __INT /** * Reads into int64_t value from the next location in a non-null parcel. * + * Available since API level 29. + * * \param parcel the parcel to read from. * \param value the value to read from the parcel. * @@ -698,6 +753,8 @@ binder_status_t AParcel_readInt64(const AParcel* parcel, int64_t* value) __INTRO /** * Reads into uint64_t value from the next location in a non-null parcel. * + * Available since API level 29. + * * \param parcel the parcel to read from. * \param value the value to read from the parcel. * @@ -708,6 +765,8 @@ binder_status_t AParcel_readUint64(const AParcel* parcel, uint64_t* value) __INT /** * Reads into float value from the next location in a non-null parcel. * + * Available since API level 29. + * * \param parcel the parcel to read from. * \param value the value to read from the parcel. * @@ -718,6 +777,8 @@ binder_status_t AParcel_readFloat(const AParcel* parcel, float* value) __INTRODU /** * Reads into double value from the next location in a non-null parcel. * + * Available since API level 29. + * * \param parcel the parcel to read from. * \param value the value to read from the parcel. * @@ -728,6 +789,8 @@ binder_status_t AParcel_readDouble(const AParcel* parcel, double* value) __INTRO /** * Reads into bool value from the next location in a non-null parcel. * + * Available since API level 29. + * * \param parcel the parcel to read from. * \param value the value to read from the parcel. * @@ -738,6 +801,8 @@ binder_status_t AParcel_readBool(const AParcel* parcel, bool* value) __INTRODUCE /** * Reads into char16_t value from the next location in a non-null parcel. * + * Available since API level 29. + * * \param parcel the parcel to read from. * \param value the value to read from the parcel. * @@ -748,6 +813,8 @@ binder_status_t AParcel_readChar(const AParcel* parcel, char16_t* value) __INTRO /** * Reads into int8_t value from the next location in a non-null parcel. * + * Available since API level 29. + * * \param parcel the parcel to read from. * \param value the value to read from the parcel. * @@ -758,6 +825,8 @@ binder_status_t AParcel_readByte(const AParcel* parcel, int8_t* value) __INTRODU /** * Writes an array of int32_t to the next location in a non-null parcel. * + * Available since API level 29. + * * \param parcel the parcel to write to. * \param arrayData an array of size 'length' (or null if length is -1, may be null if length is 0). * \param length the length of arrayData or -1 if this represents a null array. @@ -770,6 +839,8 @@ binder_status_t AParcel_writeInt32Array(AParcel* parcel, const int32_t* arrayDat /** * Writes an array of uint32_t to the next location in a non-null parcel. * + * Available since API level 29. + * * \param parcel the parcel to write to. * \param arrayData an array of size 'length' (or null if length is -1, may be null if length is 0). * \param length the length of arrayData or -1 if this represents a null array. @@ -782,6 +853,8 @@ binder_status_t AParcel_writeUint32Array(AParcel* parcel, const uint32_t* arrayD /** * Writes an array of int64_t to the next location in a non-null parcel. * + * Available since API level 29. + * * \param parcel the parcel to write to. * \param arrayData an array of size 'length' (or null if length is -1, may be null if length is 0). * \param length the length of arrayData or -1 if this represents a null array. @@ -794,6 +867,8 @@ binder_status_t AParcel_writeInt64Array(AParcel* parcel, const int64_t* arrayDat /** * Writes an array of uint64_t to the next location in a non-null parcel. * + * Available since API level 29. + * * \param parcel the parcel to write to. * \param arrayData an array of size 'length' (or null if length is -1, may be null if length is 0). * \param length the length of arrayData or -1 if this represents a null array. @@ -806,6 +881,8 @@ binder_status_t AParcel_writeUint64Array(AParcel* parcel, const uint64_t* arrayD /** * Writes an array of float to the next location in a non-null parcel. * + * Available since API level 29. + * * \param parcel the parcel to write to. * \param arrayData an array of size 'length' (or null if length is -1, may be null if length is 0). * \param length the length of arrayData or -1 if this represents a null array. @@ -818,6 +895,8 @@ binder_status_t AParcel_writeFloatArray(AParcel* parcel, const float* arrayData, /** * Writes an array of double to the next location in a non-null parcel. * + * Available since API level 29. + * * \param parcel the parcel to write to. * \param arrayData an array of size 'length' (or null if length is -1, may be null if length is 0). * \param length the length of arrayData or -1 if this represents a null array. @@ -833,6 +912,8 @@ binder_status_t AParcel_writeDoubleArray(AParcel* parcel, const double* arrayDat * getter(arrayData, i) will be called for each i in [0, length) in order to get the underlying * values to write to the parcel. * + * Available since API level 29. + * * \param parcel the parcel to write to. * \param arrayData some external representation of an array. * \param length the length of arrayData (or -1 if this represents a null array). @@ -846,6 +927,8 @@ binder_status_t AParcel_writeBoolArray(AParcel* parcel, const void* arrayData, i /** * Writes an array of char16_t to the next location in a non-null parcel. * + * Available since API level 29. + * * \param parcel the parcel to write to. * \param arrayData an array of size 'length' (or null if length is -1, may be null if length is 0). * \param length the length of arrayData or -1 if this represents a null array. @@ -858,6 +941,8 @@ binder_status_t AParcel_writeCharArray(AParcel* parcel, const char16_t* arrayDat /** * Writes an array of int8_t to the next location in a non-null parcel. * + * Available since API level 29. + * * \param parcel the parcel to write to. * \param arrayData an array of size 'length' (or null if length is -1, may be null if length is 0). * \param length the length of arrayData or -1 if this represents a null array. @@ -874,6 +959,8 @@ binder_status_t AParcel_writeByteArray(AParcel* parcel, const int8_t* arrayData, * length is greater than zero, the buffer returned by the allocator will be filled with the * corresponding data * + * Available since API level 29. + * * \param parcel the parcel to read from. * \param arrayData some external representation of an array. * \param allocator the callback that will be called to allocate the array. @@ -890,6 +977,8 @@ binder_status_t AParcel_readInt32Array(const AParcel* parcel, void* arrayData, * length is greater than zero, the buffer returned by the allocator will be filled with the * corresponding data * + * Available since API level 29. + * * \param parcel the parcel to read from. * \param arrayData some external representation of an array. * \param allocator the callback that will be called to allocate the array. @@ -906,6 +995,8 @@ binder_status_t AParcel_readUint32Array(const AParcel* parcel, void* arrayData, * length is greater than zero, the buffer returned by the allocator will be filled with the * corresponding data * + * Available since API level 29. + * * \param parcel the parcel to read from. * \param arrayData some external representation of an array. * \param allocator the callback that will be called to allocate the array. @@ -922,6 +1013,8 @@ binder_status_t AParcel_readInt64Array(const AParcel* parcel, void* arrayData, * length is greater than zero, the buffer returned by the allocator will be filled with the * corresponding data * + * Available since API level 29. + * * \param parcel the parcel to read from. * \param arrayData some external representation of an array. * \param allocator the callback that will be called to allocate the array. @@ -938,6 +1031,8 @@ binder_status_t AParcel_readUint64Array(const AParcel* parcel, void* arrayData, * length is greater than zero, the buffer returned by the allocator will be filled with the * corresponding data * + * Available since API level 29. + * * \param parcel the parcel to read from. * \param arrayData some external representation of an array. * \param allocator the callback that will be called to allocate the array. @@ -954,6 +1049,8 @@ binder_status_t AParcel_readFloatArray(const AParcel* parcel, void* arrayData, * length is greater than zero, the buffer returned by the allocator will be filled with the * corresponding data * + * Available since API level 29. + * * \param parcel the parcel to read from. * \param arrayData some external representation of an array. * \param allocator the callback that will be called to allocate the array. @@ -969,6 +1066,8 @@ binder_status_t AParcel_readDoubleArray(const AParcel* parcel, void* arrayData, * First, allocator will be called with the length of the array. Then, for every i in [0, length), * setter(arrayData, i, x) will be called where x is the value at the associated index. * + * Available since API level 29. + * * \param parcel the parcel to read from. * \param arrayData some external representation of an array. * \param allocator the callback that will be called to allocate the array. @@ -988,6 +1087,8 @@ binder_status_t AParcel_readBoolArray(const AParcel* parcel, void* arrayData, * length is greater than zero, the buffer returned by the allocator will be filled with the * corresponding data * + * Available since API level 29. + * * \param parcel the parcel to read from. * \param arrayData some external representation of an array. * \param allocator the callback that will be called to allocate the array. @@ -1004,6 +1105,8 @@ binder_status_t AParcel_readCharArray(const AParcel* parcel, void* arrayData, * length is greater than zero, the buffer returned by the allocator will be filled with the * corresponding data * + * Available since API level 29. + * * \param parcel the parcel to read from. * \param arrayData some external representation of an array. * \param allocator the callback that will be called to allocate the array. @@ -1015,7 +1118,7 @@ binder_status_t AParcel_readByteArray(const AParcel* parcel, void* arrayData, // @END-PRIMITIVE-READ-WRITE -#endif //__ANDROID_API__ >= __ANDROID_API_Q__ +#endif //__ANDROID_API__ >= 29 __END_DECLS /** @} */ diff --git a/libs/binder/ndk/include_ndk/android/binder_parcel_utils.h b/libs/binder/ndk/include_ndk/android/binder_parcel_utils.h index f3bc31b0bb..787166762b 100644 --- a/libs/binder/ndk/include_ndk/android/binder_parcel_utils.h +++ b/libs/binder/ndk/include_ndk/android/binder_parcel_utils.h @@ -441,6 +441,42 @@ binder_status_t AParcel_readStdVectorParcelableElement(const AParcel* parcel, vo } /** + * Writes a ScopedFileDescriptor object inside a std::vector<ScopedFileDescriptor> at index 'index' + * to 'parcel'. + */ +template <> +inline binder_status_t AParcel_writeStdVectorParcelableElement<ScopedFileDescriptor>( + AParcel* parcel, const void* vectorData, size_t index) { + const std::vector<ScopedFileDescriptor>* vector = + static_cast<const std::vector<ScopedFileDescriptor>*>(vectorData); + int writeFd = vector->at(index).get(); + if (writeFd < 0) { + return STATUS_UNEXPECTED_NULL; + } + return AParcel_writeParcelFileDescriptor(parcel, writeFd); +} + +/** + * Reads a ScopedFileDescriptor object inside a std::vector<ScopedFileDescriptor> at index 'index' + * from 'parcel'. + */ +template <> +inline binder_status_t AParcel_readStdVectorParcelableElement<ScopedFileDescriptor>( + const AParcel* parcel, void* vectorData, size_t index) { + std::vector<ScopedFileDescriptor>* vector = + static_cast<std::vector<ScopedFileDescriptor>*>(vectorData); + int readFd; + binder_status_t status = AParcel_readParcelFileDescriptor(parcel, &readFd); + if (status == STATUS_OK) { + if (readFd < 0) { + return STATUS_UNEXPECTED_NULL; + } + vector->at(index).set(readFd); + } + return status; +} + +/** * Convenience API for writing a std::vector<P> */ template <typename P> diff --git a/libs/binder/ndk/include_ndk/android/binder_status.h b/libs/binder/ndk/include_ndk/android/binder_status.h index 2671b9b6fc..78d70f87ba 100644 --- a/libs/binder/ndk/include_ndk/android/binder_status.h +++ b/libs/binder/ndk/include_ndk/android/binder_status.h @@ -30,7 +30,7 @@ #include <sys/cdefs.h> __BEGIN_DECLS -#if __ANDROID_API__ >= __ANDROID_API_Q__ +#if __ANDROID_API__ >= 29 enum { STATUS_OK = 0, @@ -105,6 +105,8 @@ typedef struct AStatus AStatus; /** * New status which is considered a success. * + * Available since API level 29. + * * \return a newly constructed status object that the caller owns. */ __attribute__((warn_unused_result)) AStatus* AStatus_newOk() __INTRODUCED_IN(29); @@ -112,6 +114,8 @@ __attribute__((warn_unused_result)) AStatus* AStatus_newOk() __INTRODUCED_IN(29) /** * New status with exception code. * + * Available since API level 29. + * * \param exception the code that this status should represent. If this is EX_NONE, then this * constructs an non-error status object. * @@ -123,6 +127,8 @@ __attribute__((warn_unused_result)) AStatus* AStatus_fromExceptionCode(binder_ex /** * New status with exception code and message. * + * Available since API level 29. + * * \param exception the code that this status should represent. If this is EX_NONE, then this * constructs an non-error status object. * \param message the error message to associate with this status object. @@ -137,6 +143,8 @@ __attribute__((warn_unused_result)) AStatus* AStatus_fromExceptionCodeWithMessag * * This is considered to be EX_TRANSACTION_FAILED with extra information. * + * Available since API level 29. + * * \param serviceSpecific an implementation defined error code. * * \return a newly constructed status object that the caller owns. @@ -149,6 +157,8 @@ __attribute__((warn_unused_result)) AStatus* AStatus_fromServiceSpecificError( * * This is considered to be EX_TRANSACTION_FAILED with extra information. * + * Available since API level 29. + * * \param serviceSpecific an implementation defined error code. * \param message the error message to associate with this status object. * @@ -162,6 +172,8 @@ __attribute__((warn_unused_result)) AStatus* AStatus_fromServiceSpecificErrorWit * is returned by an API on AIBinder or AParcel, and that is to be returned from a method returning * an AStatus instance. * + * Available since API level 29. + * * \param a low-level error to associate with this status object. * * \return a newly constructed status object that the caller owns. @@ -173,6 +185,8 @@ __attribute__((warn_unused_result)) AStatus* AStatus_fromStatus(binder_status_t * Whether this object represents a successful transaction. If this function returns true, then * AStatus_getExceptionCode will return EX_NONE. * + * Available since API level 29. + * * \param status the status being queried. * * \return whether the status represents a successful transaction. For more details, see below. @@ -182,6 +196,8 @@ bool AStatus_isOk(const AStatus* status) __INTRODUCED_IN(29); /** * The exception that this status object represents. * + * Available since API level 29. + * * \param status the status being queried. * * \return the exception code that this object represents. @@ -194,6 +210,8 @@ binder_exception_t AStatus_getExceptionCode(const AStatus* status) __INTRODUCED_ * 0, the status object may still represent a different exception or status. To find out if this * transaction as a whole is okay, use AStatus_isOk instead. * + * Available since API level 29. + * * \param status the status being queried. * * \return the service-specific error code if the exception code is EX_SERVICE_SPECIFIC or 0. @@ -206,6 +224,8 @@ int32_t AStatus_getServiceSpecificError(const AStatus* status) __INTRODUCED_IN(2 * object may represent a different exception or a service specific error. To find out if this * transaction as a whole is okay, use AStatus_isOk instead. * + * Available since API level 29. + * * \param status the status being queried. * * \return the status code if the exception code is EX_TRANSACTION_FAILED or 0. @@ -218,6 +238,8 @@ binder_status_t AStatus_getStatus(const AStatus* status) __INTRODUCED_IN(29); * * The returned string has the lifetime of the status object passed into this function. * + * Available since API level 29. + * * \param status the status being queried. * * \return the message associated with this error. @@ -227,11 +249,13 @@ const char* AStatus_getMessage(const AStatus* status) __INTRODUCED_IN(29); /** * Deletes memory associated with the status instance. * + * Available since API level 29. + * * \param status the status to delete, returned from AStatus_newOk or one of the AStatus_from* APIs. */ void AStatus_delete(AStatus* status) __INTRODUCED_IN(29); -#endif //__ANDROID_API__ >= __ANDROID_API_Q__ +#endif //__ANDROID_API__ >= 29 __END_DECLS /** @} */ diff --git a/libs/binder/ndk/include_platform/android/binder_stability.h b/libs/binder/ndk/include_platform/android/binder_stability.h index e1a8cfd1f0..56d95a7759 100644 --- a/libs/binder/ndk/include_platform/android/binder_stability.h +++ b/libs/binder/ndk/include_platform/android/binder_stability.h @@ -30,7 +30,8 @@ enum { FLAG_PRIVATE_VENDOR = 0x10000000, }; -#if (defined(__ANDROID_VNDK__) && !defined(__ANDROID_APEX__)) +#if defined(__ANDROID_APEX_COM_ANDROID_VNDK_CURRENT__) || \ + (defined(__ANDROID_VNDK__) && !defined(__ANDROID_APEX__)) enum { FLAG_PRIVATE_LOCAL = FLAG_PRIVATE_VENDOR, @@ -45,7 +46,8 @@ static inline void AIBinder_markCompilationUnitStability(AIBinder* binder) { AIBinder_markVendorStability(binder); } -#else // defined(__ANDROID_VNDK__) && !defined(__ANDROID_APEX__) +#else // defined(__ANDROID_APEX_COM_ANDROID_VNDK_CURRENT__) || (defined(__ANDROID_VNDK__) && + // !defined(__ANDROID_APEX__)) enum { FLAG_PRIVATE_LOCAL = 0, @@ -54,13 +56,16 @@ enum { /** * This interface has the stability of the system image. */ -void AIBinder_markSystemStability(AIBinder* binder); +__attribute__((weak)) void AIBinder_markSystemStability(AIBinder* binder); static inline void AIBinder_markCompilationUnitStability(AIBinder* binder) { + if (AIBinder_markSystemStability == nullptr) return; + AIBinder_markSystemStability(binder); } -#endif // defined(__ANDROID_VNDK__) && !defined(__ANDROID_APEX__) +#endif // defined(__ANDROID_APEX_COM_ANDROID_VNDK_CURRENT__) || (defined(__ANDROID_VNDK__) && + // !defined(__ANDROID_APEX__)) /** * This interface has system<->vendor stability diff --git a/libs/binder/ndk/libbinder_ndk.map.txt b/libs/binder/ndk/libbinder_ndk.map.txt index d4d5387f33..d59d6e42c6 100644 --- a/libs/binder/ndk/libbinder_ndk.map.txt +++ b/libs/binder/ndk/libbinder_ndk.map.txt @@ -89,12 +89,12 @@ LIBBINDER_NDK { # introduced=29 AStatus_getStatus; AStatus_isOk; AStatus_newOk; - ABinderProcess_joinThreadPool; # apex vndk - ABinderProcess_setThreadPoolMaxThreadCount; # apex vndk - ABinderProcess_startThreadPool; # apex vndk - AServiceManager_addService; # apex vndk - AServiceManager_checkService; # apex vndk - AServiceManager_getService; # apex vndk + ABinderProcess_joinThreadPool; # apex llndk + ABinderProcess_setThreadPoolMaxThreadCount; # apex llndk + ABinderProcess_startThreadPool; # apex llndk + AServiceManager_addService; # apex llndk + AServiceManager_checkService; # apex llndk + AServiceManager_getService; # apex llndk local: *; }; @@ -105,8 +105,8 @@ LIBBINDER_NDK30 { # introduced=30 AIBinder_setExtension; AIBinder_markSystemStability; # apex - AIBinder_markVendorStability; # vndk - AIBinder_markVintfStability; # apex vndk + AIBinder_markVendorStability; # llndk + AIBinder_markVintfStability; # apex llndk local: *; }; diff --git a/libs/binder/ndk/parcel.cpp b/libs/binder/ndk/parcel.cpp index ae2276e794..f18e118bc9 100644 --- a/libs/binder/ndk/parcel.cpp +++ b/libs/binder/ndk/parcel.cpp @@ -50,7 +50,7 @@ binder_status_t WriteAndValidateArraySize(AParcel* parcel, bool isNullArray, int if (length < -1) return STATUS_BAD_VALUE; if (!isNullArray && length < 0) { - LOG(ERROR) << __func__ << ": null array must be used with length == -1."; + LOG(ERROR) << __func__ << ": non-null array but length is " << length; return STATUS_BAD_VALUE; } if (isNullArray && length > 0) { diff --git a/libs/binder/ndk/scripts/format.sh b/libs/binder/ndk/scripts/format.sh deleted file mode 100755 index 698d291cb1..0000000000 --- a/libs/binder/ndk/scripts/format.sh +++ /dev/null @@ -1,22 +0,0 @@ -#!/usr/bin/env bash - -# Copyright (C) 2018 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. - -set -e - -echo "Formatting code" - -bpfmt -w $(find $ANDROID_BUILD_TOP/frameworks/native/libs/binder/ndk/ -name "Android.bp") -clang-format -i $(find $ANDROID_BUILD_TOP/frameworks/native/libs/binder/ndk/ -\( -name "*.cpp" -o -name "*.h" -\)) diff --git a/libs/binder/ndk/test/Android.bp b/libs/binder/ndk/test/Android.bp index 1c5dba3736..ebd08b2f71 100644 --- a/libs/binder/ndk/test/Android.bp +++ b/libs/binder/ndk/test/Android.bp @@ -77,6 +77,7 @@ cc_test { static_libs: [ "IBinderVendorDoubleLoadTest-cpp", "IBinderVendorDoubleLoadTest-ndk_platform", + "libbinder_aidl_test_stub-ndk_platform", ], shared_libs: [ "libbase", diff --git a/libs/binder/ndk/test/binderVendorDoubleLoadTest.cpp b/libs/binder/ndk/test/binderVendorDoubleLoadTest.cpp index f72dc36cfd..d3ccdc2878 100644 --- a/libs/binder/ndk/test/binderVendorDoubleLoadTest.cpp +++ b/libs/binder/ndk/test/binderVendorDoubleLoadTest.cpp @@ -16,6 +16,7 @@ #include <BnBinderVendorDoubleLoadTest.h> #include <aidl/BnBinderVendorDoubleLoadTest.h> +#include <aidl/android/os/IServiceManager.h> #include <android-base/logging.h> #include <android-base/properties.h> #include <android-base/strings.h> @@ -109,6 +110,24 @@ TEST(DoubleBinder, CallIntoNdk) { } } +TEST(DoubleBinder, CallIntoSystemStabilityNdk) { + // picking an arbitrary system service + SpAIBinder binder = SpAIBinder(AServiceManager_checkService("manager")); + ASSERT_NE(nullptr, binder.get()); + + // can make stable transaction to system server + EXPECT_EQ(STATUS_OK, AIBinder_ping(binder.get())); + + using aidl::android::os::IServiceManager; + std::shared_ptr<IServiceManager> manager = IServiceManager::fromBinder(binder); + ASSERT_NE(nullptr, manager.get()); + + std::vector<std::string> services; + ASSERT_EQ( + STATUS_BAD_TYPE, + manager->listServices(IServiceManager::DUMP_FLAG_PRIORITY_ALL, &services).getStatus()); +} + void initDrivers() { // Explicitly instantiated with the same driver that system would use. // __ANDROID_VNDK__ right now uses /dev/vndbinder by default. diff --git a/libs/binder/ndk/update.sh b/libs/binder/ndk/update.sh deleted file mode 100755 index 1eba892021..0000000000 --- a/libs/binder/ndk/update.sh +++ /dev/null @@ -1,22 +0,0 @@ -#!/usr/bin/env bash - -# Copyright (C) 2018 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. - - -set -ex - -# This script makes sure that the source code is in sync with the various scripts -./scripts/gen_parcel_helper.py -./scripts/format.sh diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp index 635ea69fb4..5a7f9a97fa 100644 --- a/libs/binder/tests/Android.bp +++ b/libs/binder/tests/Android.bp @@ -119,12 +119,7 @@ cc_test { srcs: ["binderSafeInterfaceTest.cpp"], cppflags: [ - "-Weverything", - "-Wno-c++98-compat", - "-Wno-c++98-compat-pedantic", - "-Wno-global-constructors", - "-Wno-padded", - "-Wno-weak-vtables", + "-Wextra", ], cpp_std: "experimental", diff --git a/libs/binder/tests/binderStabilityTest.cpp b/libs/binder/tests/binderStabilityTest.cpp index 0bee56c943..1f2779abf0 100644 --- a/libs/binder/tests/binderStabilityTest.cpp +++ b/libs/binder/tests/binderStabilityTest.cpp @@ -134,18 +134,15 @@ TEST(BinderStability, OnlyVintfStabilityBinderNeedsVintfDeclaration) { TEST(BinderStability, VintfStabilityServerMustBeDeclaredInManifest) { sp<IBinder> vintfServer = BadStableBinder::vintf(); - EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, - android::defaultServiceManager()->addService(String16("."), vintfServer)); - EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, - android::defaultServiceManager()->addService(String16("/"), vintfServer)); - EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, - android::defaultServiceManager()->addService(String16("/."), vintfServer)); - EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, - android::defaultServiceManager()->addService(String16("a.d.IFoo"), vintfServer)); - EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, - android::defaultServiceManager()->addService(String16("foo"), vintfServer)); - EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, - android::defaultServiceManager()->addService(String16("a.d.IFoo/foo"), vintfServer)); + for (const char* instance8 : { + ".", "/", "/.", "a.d.IFoo", "foo", "a.d.IFoo/foo" + }) { + String16 instance (instance8); + + EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, + android::defaultServiceManager()->addService(String16("."), vintfServer)) << instance8; + EXPECT_FALSE(android::defaultServiceManager()->isDeclared(instance)) << instance8; + } } TEST(BinderStability, CantCallVendorBinderInSystemContext) { diff --git a/libs/dumputils/dump_utils.cpp b/libs/dumputils/dump_utils.cpp index 40f6b43802..250f902f9d 100644 --- a/libs/dumputils/dump_utils.cpp +++ b/libs/dumputils/dump_utils.cpp @@ -46,6 +46,8 @@ static const char* native_processes_to_dump[] = { static const char* hal_interfaces_to_dump[] { "android.hardware.audio@2.0::IDevicesFactory", "android.hardware.audio@4.0::IDevicesFactory", + "android.hardware.audio@5.0::IDevicesFactory", + "android.hardware.biometrics.face@1.0::IBiometricsFace", "android.hardware.bluetooth@1.0::IBluetoothHci", "android.hardware.camera.provider@2.4::ICameraProvider", "android.hardware.drm@1.0::IDrmFactory", diff --git a/libs/graphicsenv/GraphicsEnv.cpp b/libs/graphicsenv/GraphicsEnv.cpp index 24b6c2d6de..bb9e263ac4 100644 --- a/libs/graphicsenv/GraphicsEnv.cpp +++ b/libs/graphicsenv/GraphicsEnv.cpp @@ -213,7 +213,8 @@ void GraphicsEnv::setDriverToLoad(GraphicsEnv::Driver driver) { case GraphicsEnv::Driver::GL: case GraphicsEnv::Driver::GL_UPDATED: case GraphicsEnv::Driver::ANGLE: { - if (mGpuStats.glDriverToLoad == GraphicsEnv::Driver::NONE) { + if (mGpuStats.glDriverToLoad == GraphicsEnv::Driver::NONE || + mGpuStats.glDriverToLoad == GraphicsEnv::Driver::GL) { mGpuStats.glDriverToLoad = driver; break; } @@ -225,7 +226,8 @@ void GraphicsEnv::setDriverToLoad(GraphicsEnv::Driver driver) { } case Driver::VULKAN: case Driver::VULKAN_UPDATED: { - if (mGpuStats.vkDriverToLoad == GraphicsEnv::Driver::NONE) { + if (mGpuStats.vkDriverToLoad == GraphicsEnv::Driver::NONE || + mGpuStats.vkDriverToLoad == GraphicsEnv::Driver::VULKAN) { mGpuStats.vkDriverToLoad = driver; break; } @@ -267,14 +269,14 @@ static sp<IGpuService> getGpuService() { return interface_cast<IGpuService>(binder); } -void GraphicsEnv::setCpuVulkanInUse() { +void GraphicsEnv::setTargetStats(const Stats stats, const uint64_t value) { ATRACE_CALL(); - // Use the same stats lock to protect getGpuService() as well. std::lock_guard<std::mutex> lock(mStatsLock); const sp<IGpuService> gpuService = getGpuService(); if (gpuService) { - gpuService->setCpuVulkanInUse(mGpuStats.appPackageName, mGpuStats.driverVersionCode); + gpuService->setTargetStats(mGpuStats.appPackageName, mGpuStats.driverVersionCode, stats, + value); } } diff --git a/libs/graphicsenv/IGpuService.cpp b/libs/graphicsenv/IGpuService.cpp index 5f9624918f..db16f3cfa6 100644 --- a/libs/graphicsenv/IGpuService.cpp +++ b/libs/graphicsenv/IGpuService.cpp @@ -92,15 +92,17 @@ public: return reply.readParcelableVector(outStats); } - virtual void setCpuVulkanInUse(const std::string& appPackageName, - const uint64_t driverVersionCode) { + virtual void setTargetStats(const std::string& appPackageName, const uint64_t driverVersionCode, + const GraphicsEnv::Stats stats, const uint64_t value) { Parcel data, reply; data.writeInterfaceToken(IGpuService::getInterfaceDescriptor()); data.writeUtf8AsUtf16(appPackageName); data.writeUint64(driverVersionCode); + data.writeInt32(static_cast<int32_t>(stats)); + data.writeUint64(value); - remote()->transact(BnGpuService::SET_CPU_VULKAN_IN_USE, data, &reply, IBinder::FLAG_ONEWAY); + remote()->transact(BnGpuService::SET_TARGET_STATS, data, &reply, IBinder::FLAG_ONEWAY); } }; @@ -174,7 +176,7 @@ status_t BnGpuService::onTransact(uint32_t code, const Parcel& data, Parcel* rep return OK; } - case SET_CPU_VULKAN_IN_USE: { + case SET_TARGET_STATS: { CHECK_INTERFACE(IGpuService, data, reply); std::string appPackageName; @@ -183,7 +185,14 @@ status_t BnGpuService::onTransact(uint32_t code, const Parcel& data, Parcel* rep uint64_t driverVersionCode; if ((status = data.readUint64(&driverVersionCode)) != OK) return status; - setCpuVulkanInUse(appPackageName, driverVersionCode); + int32_t stats; + if ((status = data.readInt32(&stats)) != OK) return status; + + uint64_t value; + if ((status = data.readUint64(&value)) != OK) return status; + + setTargetStats(appPackageName, driverVersionCode, + static_cast<GraphicsEnv::Stats>(stats), value); return OK; } diff --git a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h index f5d19db493..937bcd9ac6 100644 --- a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h +++ b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h @@ -43,6 +43,10 @@ public: ANGLE = 5, }; + enum Stats { + CPU_VULKAN_IN_USE = 0, + }; + private: struct GpuStats { std::string driverPackageName; @@ -96,7 +100,7 @@ public: void setGpuStats(const std::string& driverPackageName, const std::string& driverVersionName, uint64_t versionCode, int64_t driverBuildTime, const std::string& appPackageName, const int32_t vulkanVersion); - void setCpuVulkanInUse(); + void setTargetStats(const Stats stats, const uint64_t value = 0); void setDriverToLoad(Driver driver); void setDriverLoaded(Api api, bool isDriverLoaded, int64_t driverLoadingTime); void sendGpuStatsLocked(Api api, bool isDriverLoaded, int64_t driverLoadingTime); diff --git a/libs/graphicsenv/include/graphicsenv/IGpuService.h b/libs/graphicsenv/include/graphicsenv/IGpuService.h index 34f1c7ee7e..b8d0bd173c 100644 --- a/libs/graphicsenv/include/graphicsenv/IGpuService.h +++ b/libs/graphicsenv/include/graphicsenv/IGpuService.h @@ -40,9 +40,9 @@ public: const int32_t vulkanVersion, GraphicsEnv::Driver driver, bool isDriverLoaded, int64_t driverLoadingTime) = 0; - // set CPU Vulkan in use signal from GraphicsEnvironment. - virtual void setCpuVulkanInUse(const std::string& appPackageName, - const uint64_t driverVersionCode) = 0; + // set target stats. + virtual void setTargetStats(const std::string& appPackageName, const uint64_t driverVersionCode, + const GraphicsEnv::Stats stats, const uint64_t value = 0) = 0; // get GPU global stats from GpuStats module. virtual status_t getGpuStatsGlobalInfo(std::vector<GpuStatsGlobalInfo>* outStats) const = 0; @@ -57,7 +57,7 @@ public: SET_GPU_STATS = IBinder::FIRST_CALL_TRANSACTION, GET_GPU_STATS_GLOBAL_INFO, GET_GPU_STATS_APP_INFO, - SET_CPU_VULKAN_IN_USE, + SET_TARGET_STATS, // Always append new enum to the end. }; diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp index 59cb8e0a2b..166775b89a 100644 --- a/libs/gui/Android.bp +++ b/libs/gui/Android.bp @@ -15,6 +15,18 @@ cc_library_headers { name: "libgui_headers", vendor_available: true, export_include_dirs: ["include"], + + // we must build this module to get the required header as that is generated + export_shared_lib_headers: [ + "android.hidl.token@1.0-utils", + "android.hardware.graphics.bufferqueue@1.0", + "android.hardware.graphics.bufferqueue@2.0", + ], + shared_libs: [ + "android.hidl.token@1.0-utils", + "android.hardware.graphics.bufferqueue@1.0", + "android.hardware.graphics.bufferqueue@2.0", + ], } cc_library_shared { @@ -34,6 +46,7 @@ cc_library_shared { "BufferItemConsumer.cpp", "ConsumerBase.cpp", "CpuConsumer.cpp", + "DebugEGLImageTracker.cpp", "DisplayEventReceiver.cpp", "GLConsumer.cpp", "GuiConfig.cpp", diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp index 9c311a314f..92ab41019e 100644 --- a/libs/gui/BufferQueueProducer.cpp +++ b/libs/gui/BufferQueueProducer.cpp @@ -936,6 +936,15 @@ status_t BufferQueueProducer::queueBuffer(int slot, } } + // Make sure to merge the damage rect from the frame we're about + // to drop into the new frame's damage rect. + if (last.mSurfaceDamage.bounds() == Rect::INVALID_RECT || + item.mSurfaceDamage.bounds() == Rect::INVALID_RECT) { + item.mSurfaceDamage = Region::INVALID_REGION; + } else { + item.mSurfaceDamage |= last.mSurfaceDamage; + } + // Overwrite the droppable buffer with the incoming one mCore->mQueue.editItemAt(mCore->mQueue.size() - 1) = item; frameReplacedListener = mCore->mConsumerListener; diff --git a/libs/gui/DebugEGLImageTracker.cpp b/libs/gui/DebugEGLImageTracker.cpp new file mode 100644 index 0000000000..ab6f36444a --- /dev/null +++ b/libs/gui/DebugEGLImageTracker.cpp @@ -0,0 +1,98 @@ +/* + * Copyright 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <android-base/stringprintf.h> +#include <cutils/properties.h> +#include <gui/DebugEGLImageTracker.h> + +#include <cinttypes> +#include <unordered_map> + +using android::base::StringAppendF; + +std::mutex DebugEGLImageTracker::mInstanceLock; +std::atomic<DebugEGLImageTracker *> DebugEGLImageTracker::mInstance; + +class DebugEGLImageTrackerNoOp : public DebugEGLImageTracker { +public: + DebugEGLImageTrackerNoOp() = default; + ~DebugEGLImageTrackerNoOp() override = default; + void create(const char * /*from*/) override {} + void destroy(const char * /*from*/) override {} + + void dump(std::string & /*result*/) override {} +}; + +class DebugEGLImageTrackerImpl : public DebugEGLImageTracker { +public: + DebugEGLImageTrackerImpl() = default; + ~DebugEGLImageTrackerImpl() override = default; + void create(const char * /*from*/) override; + void destroy(const char * /*from*/) override; + + void dump(std::string & /*result*/) override; + +private: + std::mutex mLock; + std::unordered_map<std::string, int64_t> mCreateTracker; + std::unordered_map<std::string, int64_t> mDestroyTracker; + + int64_t mTotalCreated = 0; + int64_t mTotalDestroyed = 0; +}; + +DebugEGLImageTracker *DebugEGLImageTracker::getInstance() { + std::lock_guard lock(mInstanceLock); + if (mInstance == nullptr) { + char value[PROPERTY_VALUE_MAX]; + property_get("debug.sf.enable_egl_image_tracker", value, "0"); + const bool enabled = static_cast<bool>(atoi(value)); + + if (enabled) { + mInstance = new DebugEGLImageTrackerImpl(); + } else { + mInstance = new DebugEGLImageTrackerNoOp(); + } + } + + return mInstance; +} + +void DebugEGLImageTrackerImpl::create(const char *from) { + std::lock_guard lock(mLock); + mCreateTracker[from]++; + mTotalCreated++; +} + +void DebugEGLImageTrackerImpl::destroy(const char *from) { + std::lock_guard lock(mLock); + mDestroyTracker[from]++; + mTotalDestroyed++; +} + +void DebugEGLImageTrackerImpl::dump(std::string &result) { + std::lock_guard lock(mLock); + StringAppendF(&result, "Live EGL Image objects: %" PRIi64 "\n", + mTotalCreated - mTotalDestroyed); + StringAppendF(&result, "Total EGL Image created: %" PRIi64 "\n", mTotalCreated); + for (const auto &[from, count] : mCreateTracker) { + StringAppendF(&result, "\t%s: %" PRIi64 "\n", from.c_str(), count); + } + StringAppendF(&result, "Total EGL Image destroyed: %" PRIi64 "\n", mTotalDestroyed); + for (const auto &[from, count] : mDestroyTracker) { + StringAppendF(&result, "\t%s: %" PRIi64 "\n", from.c_str(), count); + } +} diff --git a/libs/gui/DisplayEventReceiver.cpp b/libs/gui/DisplayEventReceiver.cpp index f5cf1c4d5a..b8faa2df4c 100644 --- a/libs/gui/DisplayEventReceiver.cpp +++ b/libs/gui/DisplayEventReceiver.cpp @@ -32,10 +32,11 @@ namespace android { // --------------------------------------------------------------------------- -DisplayEventReceiver::DisplayEventReceiver(ISurfaceComposer::VsyncSource vsyncSource) { +DisplayEventReceiver::DisplayEventReceiver(ISurfaceComposer::VsyncSource vsyncSource, + ISurfaceComposer::ConfigChanged configChanged) { sp<ISurfaceComposer> sf(ComposerService::getComposerService()); if (sf != nullptr) { - mEventConnection = sf->createDisplayEventConnection(vsyncSource); + mEventConnection = sf->createDisplayEventConnection(vsyncSource, configChanged); if (mEventConnection != nullptr) { mDataChannel = std::make_unique<gui::BitTube>(); mEventConnection->stealReceiveChannel(mDataChannel.get()); diff --git a/libs/gui/GLConsumer.cpp b/libs/gui/GLConsumer.cpp index 8d66154bdd..8199c98582 100644 --- a/libs/gui/GLConsumer.cpp +++ b/libs/gui/GLConsumer.cpp @@ -34,6 +34,7 @@ #include <math/mat4.h> #include <gui/BufferItem.h> +#include <gui/DebugEGLImageTracker.h> #include <gui/GLConsumer.h> #include <gui/ISurfaceComposer.h> #include <gui/SurfaceComposerClient.h> @@ -944,6 +945,7 @@ GLConsumer::EglImage::~EglImage() { if (!eglDestroyImageKHR(mEglDisplay, mEglImage)) { ALOGE("~EglImage: eglDestroyImageKHR failed"); } + DEBUG_EGL_IMAGE_TRACKER_DESTROY(); eglTerminate(mEglDisplay); } } @@ -957,6 +959,7 @@ status_t GLConsumer::EglImage::createIfNeeded(EGLDisplay eglDisplay, if (!eglDestroyImageKHR(mEglDisplay, mEglImage)) { ALOGE("createIfNeeded: eglDestroyImageKHR failed"); } + DEBUG_EGL_IMAGE_TRACKER_DESTROY(); eglTerminate(mEglDisplay); mEglImage = EGL_NO_IMAGE_KHR; mEglDisplay = EGL_NO_DISPLAY; @@ -1006,7 +1009,10 @@ EGLImageKHR GLConsumer::EglImage::createImage(EGLDisplay dpy, EGLint error = eglGetError(); ALOGE("error creating EGLImage: %#x", error); eglTerminate(dpy); + } else { + DEBUG_EGL_IMAGE_TRACKER_CREATE(); } + return image; } diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp index 9590df7c8f..12deaf0bd6 100644 --- a/libs/gui/ISurfaceComposer.cpp +++ b/libs/gui/ISurfaceComposer.cpp @@ -278,8 +278,8 @@ public: return NO_ERROR; } - virtual sp<IDisplayEventConnection> createDisplayEventConnection(VsyncSource vsyncSource) - { + virtual sp<IDisplayEventConnection> createDisplayEventConnection(VsyncSource vsyncSource, + ConfigChanged configChanged) { Parcel data, reply; sp<IDisplayEventConnection> result; int err = data.writeInterfaceToken( @@ -288,6 +288,7 @@ public: return result; } data.writeInt32(static_cast<int32_t>(vsyncSource)); + data.writeInt32(static_cast<int32_t>(configChanged)); err = remote()->transact( BnSurfaceComposer::CREATE_DISPLAY_EVENT_CONNECTION, data, &reply); @@ -1155,8 +1156,11 @@ status_t BnSurfaceComposer::onTransact( } case CREATE_DISPLAY_EVENT_CONNECTION: { CHECK_INTERFACE(ISurfaceComposer, data, reply); - sp<IDisplayEventConnection> connection(createDisplayEventConnection( - static_cast<ISurfaceComposer::VsyncSource>(data.readInt32()))); + auto vsyncSource = static_cast<ISurfaceComposer::VsyncSource>(data.readInt32()); + auto configChanged = static_cast<ISurfaceComposer::ConfigChanged>(data.readInt32()); + + sp<IDisplayEventConnection> connection( + createDisplayEventConnection(vsyncSource, configChanged)); reply->writeStrongBinder(IInterface::asBinder(connection)); return NO_ERROR; } diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp index e6eb327c6f..9fe5de82d1 100644 --- a/libs/gui/Surface.cpp +++ b/libs/gui/Surface.cpp @@ -1920,7 +1920,8 @@ status_t Surface::getAndFlushRemovedBuffers(std::vector<sp<GraphicBuffer>>* out) return OK; } -status_t Surface::attachAndQueueBuffer(Surface* surface, sp<GraphicBuffer> buffer) { +status_t Surface::attachAndQueueBufferWithDataspace(Surface* surface, sp<GraphicBuffer> buffer, + Dataspace dataspace) { if (buffer == nullptr) { return BAD_VALUE; } @@ -1929,6 +1930,11 @@ status_t Surface::attachAndQueueBuffer(Surface* surface, sp<GraphicBuffer> buffe if (err != OK) { return err; } + ui::Dataspace tmpDataspace = surface->getBuffersDataSpace(); + err = surface->setBuffersDataSpace(dataspace); + if (err != OK) { + return err; + } err = surface->attachBuffer(buffer->getNativeBuffer()); if (err != OK) { return err; @@ -1937,6 +1943,10 @@ status_t Surface::attachAndQueueBuffer(Surface* surface, sp<GraphicBuffer> buffe if (err != OK) { return err; } + err = surface->setBuffersDataSpace(tmpDataspace); + if (err != OK) { + return err; + } err = surface->disconnect(NATIVE_WINDOW_API_CPU); return err; } diff --git a/libs/gui/include/gui/DebugEGLImageTracker.h b/libs/gui/include/gui/DebugEGLImageTracker.h new file mode 100644 index 0000000000..5d369c9a35 --- /dev/null +++ b/libs/gui/include/gui/DebugEGLImageTracker.h @@ -0,0 +1,44 @@ +/* + * Copyright 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <atomic> +#include <mutex> +#include <string> + +class DebugEGLImageTracker { +public: + static DebugEGLImageTracker *getInstance(); + + virtual void create(const char *from) = 0; + virtual void destroy(const char *from) = 0; + + virtual void dump(std::string &result) = 0; + +protected: + DebugEGLImageTracker() = default; + virtual ~DebugEGLImageTracker() = default; + DebugEGLImageTracker(const DebugEGLImageTracker &) = delete; + + static std::mutex mInstanceLock; + static std::atomic<DebugEGLImageTracker *> mInstance; +}; + +#define DEBUG_EGL_IMAGE_TRACKER_CREATE() \ + (DebugEGLImageTracker::getInstance()->create(__PRETTY_FUNCTION__)) +#define DEBUG_EGL_IMAGE_TRACKER_DESTROY() \ + (DebugEGLImageTracker::getInstance()->destroy(__PRETTY_FUNCTION__))
\ No newline at end of file diff --git a/libs/gui/include/gui/DisplayEventReceiver.h b/libs/gui/include/gui/DisplayEventReceiver.h index 22de751498..a558cf9e18 100644 --- a/libs/gui/include/gui/DisplayEventReceiver.h +++ b/libs/gui/include/gui/DisplayEventReceiver.h @@ -88,10 +88,13 @@ public: * DisplayEventReceiver creates and registers an event connection with * SurfaceFlinger. VSync events are disabled by default. Call setVSyncRate * or requestNextVsync to receive them. + * To receive Config Changed events specify this in the constructor. * Other events start being delivered immediately. */ explicit DisplayEventReceiver( - ISurfaceComposer::VsyncSource vsyncSource = ISurfaceComposer::eVsyncSourceApp); + ISurfaceComposer::VsyncSource vsyncSource = ISurfaceComposer::eVsyncSourceApp, + ISurfaceComposer::ConfigChanged configChanged = + ISurfaceComposer::eConfigChangedSuppress); /* * ~DisplayEventReceiver severs the connection with SurfaceFlinger, new events diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h index e2f77365b3..c84910b6ec 100644 --- a/libs/gui/include/gui/ISurfaceComposer.h +++ b/libs/gui/include/gui/ISurfaceComposer.h @@ -90,6 +90,8 @@ public: eVsyncSourceSurfaceFlinger = 1 }; + enum ConfigChanged { eConfigChangedSuppress = 0, eConfigChangedDispatch = 1 }; + /* * Create a connection with SurfaceFlinger. */ @@ -97,7 +99,8 @@ public: /* return an IDisplayEventConnection */ virtual sp<IDisplayEventConnection> createDisplayEventConnection( - VsyncSource vsyncSource = eVsyncSourceApp) = 0; + VsyncSource vsyncSource = eVsyncSourceApp, + ConfigChanged configChanged = eConfigChangedSuppress) = 0; /* create a virtual display * requires ACCESS_SURFACE_FLINGER permission. diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h index 0c471bb701..5c6a1ee383 100644 --- a/libs/gui/include/gui/Surface.h +++ b/libs/gui/include/gui/Surface.h @@ -292,7 +292,8 @@ public: ui::Dataspace getBuffersDataSpace(); - static status_t attachAndQueueBuffer(Surface* surface, sp<GraphicBuffer> buffer); + static status_t attachAndQueueBufferWithDataspace(Surface* surface, sp<GraphicBuffer> buffer, + ui::Dataspace dataspace); protected: enum { NUM_BUFFER_SLOTS = BufferQueueDefs::NUM_BUFFER_SLOTS }; diff --git a/libs/gui/tests/EndToEndNativeInputTest.cpp b/libs/gui/tests/EndToEndNativeInputTest.cpp index ff1ba0ad17..386f731d23 100644 --- a/libs/gui/tests/EndToEndNativeInputTest.cpp +++ b/libs/gui/tests/EndToEndNativeInputTest.cpp @@ -410,6 +410,19 @@ TEST_F(InputSurfacesTest, input_respects_scaled_surface_insets) { bgSurface->expectTap(1, 1); } +TEST_F(InputSurfacesTest, input_respects_scaled_surface_insets_overflow) { + std::unique_ptr<InputSurface> fgSurface = makeSurface(100, 100); + // In case we pass the very big inset without any checking. + fgSurface->mInputInfo.surfaceInset = INT32_MAX; + fgSurface->showAt(100, 100); + + fgSurface->doTransaction([&](auto &t, auto &sc) { t.setMatrix(sc, 2.0, 0, 0, 2.0); }); + + // expect no crash for overflow, and inset size to be clamped to surface size + injectTap(202, 202); + fgSurface->expectTap(1, 1); +} + // Ensure we ignore transparent region when getting screen bounds when positioning input frame. TEST_F(InputSurfacesTest, input_ignores_transparent_region) { std::unique_ptr<InputSurface> surface = makeSurface(100, 100); diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index 960cf1846e..d3708586f5 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -548,8 +548,8 @@ public: } sp<ISurfaceComposerClient> createConnection() override { return nullptr; } - sp<IDisplayEventConnection> createDisplayEventConnection(ISurfaceComposer::VsyncSource) - override { + sp<IDisplayEventConnection> createDisplayEventConnection( + ISurfaceComposer::VsyncSource, ISurfaceComposer::ConfigChanged) override { return nullptr; } sp<IBinder> createDisplay(const String8& /*displayName*/, diff --git a/libs/nativewindow/Android.bp b/libs/nativewindow/Android.bp index 27ab482676..55400c7b32 100644 --- a/libs/nativewindow/Android.bp +++ b/libs/nativewindow/Android.bp @@ -85,6 +85,11 @@ cc_library { export_header_lib_headers: [ "libnativebase_headers", ], + + stubs: { + symbol_file: "libnativewindow.map.txt", + versions: ["29"], + }, } llndk_library { diff --git a/libs/nativewindow/include/android/hardware_buffer.h b/libs/nativewindow/include/android/hardware_buffer.h index da959e36d2..ae5e47ba97 100644 --- a/libs/nativewindow/include/android/hardware_buffer.h +++ b/libs/nativewindow/include/android/hardware_buffer.h @@ -342,6 +342,8 @@ typedef struct AHardwareBuffer AHardwareBuffer; * not compatible with its usage flags, the results are undefined and * may include program termination. * + * Available since API level 26. + * * \return 0 on success, or an error number of the allocation fails for * any reason. The returned buffer has a reference count of 1. */ @@ -352,18 +354,24 @@ int AHardwareBuffer_allocate(const AHardwareBuffer_Desc* desc, * * This prevents the object from being deleted until the last reference * is removed. + * + * Available since API level 26. */ void AHardwareBuffer_acquire(AHardwareBuffer* buffer) __INTRODUCED_IN(26); /** * Remove a reference that was previously acquired with * AHardwareBuffer_acquire() or AHardwareBuffer_allocate(). + * + * Available since API level 26. */ void AHardwareBuffer_release(AHardwareBuffer* buffer) __INTRODUCED_IN(26); /** * Return a description of the AHardwareBuffer in the passed * AHardwareBuffer_Desc struct. + * + * Available since API level 26. */ void AHardwareBuffer_describe(const AHardwareBuffer* buffer, AHardwareBuffer_Desc* outDesc) __INTRODUCED_IN(26); @@ -413,6 +421,8 @@ void AHardwareBuffer_describe(const AHardwareBuffer* buffer, * simultaneously, and the contents of the buffer behave like shared * memory. * + * Available since API level 26. + * * \return 0 on success. -EINVAL if \a buffer is NULL, the usage flags * are not a combination of AHARDWAREBUFFER_USAGE_CPU_*, or the buffer * has more than one layer. Error number if the lock fails for any other @@ -441,6 +451,8 @@ int AHardwareBuffer_lock(AHardwareBuffer* buffer, uint64_t usage, * * See the AHardwareBuffer_lock documentation for all other locking semantics. * + * Available since API level 29. + * * \return 0 on success. -EINVAL if \a buffer is NULL, the usage flags * are not a combination of AHARDWAREBUFFER_USAGE_CPU_*, or the buffer * has more than one layer. Error number if the lock fails for any other @@ -462,6 +474,8 @@ int AHardwareBuffer_lockPlanes(AHardwareBuffer* buffer, uint64_t usage, * completed before the function returned and no further operations are * necessary. * + * Available since API level 26. + * * \return 0 on success. -EINVAL if \a buffer is NULL. Error number if * the unlock fails for any reason. */ @@ -470,6 +484,8 @@ int AHardwareBuffer_unlock(AHardwareBuffer* buffer, int32_t* fence) __INTRODUCED /** * Send the AHardwareBuffer to an AF_UNIX socket. * + * Available since API level 26. + * * \return 0 on success, -EINVAL if \a buffer is NULL, or an error * number if the operation fails for any reason. */ @@ -478,6 +494,8 @@ int AHardwareBuffer_sendHandleToUnixSocket(const AHardwareBuffer* buffer, int so /** * Receive an AHardwareBuffer from an AF_UNIX socket. * + * Available since API level 26. + * * \return 0 on success, -EINVAL if \a outBuffer is NULL, or an error * number if the operation fails for any reason. */ @@ -501,6 +519,8 @@ int AHardwareBuffer_recvHandleFromUnixSocket(int socketFd, AHardwareBuffer** out * some implementations have implementation-defined limits on texture * size and layer count. * + * Available since API level 29. + * * \return 1 if the format and usage flag combination is allocatable, * 0 otherwise. */ @@ -514,6 +534,8 @@ int AHardwareBuffer_isSupported(const AHardwareBuffer_Desc* desc) __INTRODUCED_I * of the locked buffer. If the bytes per pixel or bytes per stride are unknown * or variable, or if the underlying mapper implementation does not support returning * additional information, then this call will fail with INVALID_OPERATION + * + * Available since API level 29. */ int AHardwareBuffer_lockAndGetInfo(AHardwareBuffer* buffer, uint64_t usage, int32_t fence, const ARect* rect, void** outVirtualAddress, diff --git a/libs/nativewindow/include/android/native_window.h b/libs/nativewindow/include/android/native_window.h index 6730596ec7..3e436e3b07 100644 --- a/libs/nativewindow/include/android/native_window.h +++ b/libs/nativewindow/include/android/native_window.h @@ -189,6 +189,8 @@ int32_t ANativeWindow_unlockAndPost(ANativeWindow* window); /** * Set a transform that will be applied to future buffers posted to the window. * + * Available since API level 26. + * * \param transform combination of {@link ANativeWindowTransform} flags * \return 0 for success, or -EINVAL if \p transform is invalid */ @@ -208,6 +210,8 @@ int32_t ANativeWindow_setBuffersTransform(ANativeWindow* window, int32_t transfo * measurement data instead of color images. The default dataSpace is 0, * ADATASPACE_UNKNOWN, unless it has been overridden by the producer. * + * Available since API level 28. + * * \param dataSpace data space of all buffers queued after this call. * \return 0 for success, -EINVAL if window is invalid or the dataspace is not * supported. @@ -216,6 +220,9 @@ int32_t ANativeWindow_setBuffersDataSpace(ANativeWindow* window, int32_t dataSpa /** * Get the dataspace of the buffers in window. + * + * Available since API level 28. + * * \return the dataspace of buffers in window, ADATASPACE_UNKNOWN is returned if * dataspace is unknown, or -EINVAL if window is invalid. */ diff --git a/libs/nativewindow/libnativewindow.map.txt b/libs/nativewindow/libnativewindow.map.txt index bad8b11540..db1c9b784e 100644 --- a/libs/nativewindow/libnativewindow.map.txt +++ b/libs/nativewindow/libnativewindow.map.txt @@ -2,9 +2,9 @@ LIBNATIVEWINDOW { global: AHardwareBuffer_acquire; AHardwareBuffer_allocate; - AHardwareBuffer_createFromHandle; # vndk + AHardwareBuffer_createFromHandle; # llndk # apex AHardwareBuffer_describe; - AHardwareBuffer_getNativeHandle; # vndk + AHardwareBuffer_getNativeHandle; # llndk # apex AHardwareBuffer_isSupported; # introduced=29 AHardwareBuffer_lock; AHardwareBuffer_lockAndGetInfo; # introduced=29 @@ -13,32 +13,32 @@ LIBNATIVEWINDOW { AHardwareBuffer_release; AHardwareBuffer_sendHandleToUnixSocket; AHardwareBuffer_unlock; - ANativeWindowBuffer_getHardwareBuffer; # vndk - ANativeWindow_OemStorageGet; # vndk - ANativeWindow_OemStorageSet; # vndk + ANativeWindowBuffer_getHardwareBuffer; # llndk + ANativeWindow_OemStorageGet; # llndk + ANativeWindow_OemStorageSet; # llndk ANativeWindow_acquire; - ANativeWindow_cancelBuffer; # vndk - ANativeWindow_dequeueBuffer; # vndk + ANativeWindow_cancelBuffer; # llndk + ANativeWindow_dequeueBuffer; # llndk ANativeWindow_getBuffersDataSpace; # introduced=28 ANativeWindow_getFormat; ANativeWindow_getHeight; ANativeWindow_getWidth; ANativeWindow_lock; - ANativeWindow_query; # vndk - ANativeWindow_queryf; # vndk - ANativeWindow_queueBuffer; # vndk + ANativeWindow_query; # llndk + ANativeWindow_queryf; # llndk + ANativeWindow_queueBuffer; # llndk ANativeWindow_release; - ANativeWindow_setAutoRefresh; # vndk - ANativeWindow_setBufferCount; # vndk + ANativeWindow_setAutoRefresh; # llndk + ANativeWindow_setBufferCount; # llndk ANativeWindow_setBuffersDataSpace; # introduced=28 - ANativeWindow_setBuffersDimensions; # vndk - ANativeWindow_setBuffersFormat; # vndk + ANativeWindow_setBuffersDimensions; # llndk + ANativeWindow_setBuffersFormat; # llndk ANativeWindow_setBuffersGeometry; - ANativeWindow_setBuffersTimestamp; # vndk + ANativeWindow_setBuffersTimestamp; # llndk ANativeWindow_setBuffersTransform; - ANativeWindow_setSharedBufferMode; # vndk - ANativeWindow_setSwapInterval; # vndk - ANativeWindow_setUsage; # vndk + ANativeWindow_setSharedBufferMode; # llndk + ANativeWindow_setSwapInterval; # llndk + ANativeWindow_setUsage; # llndk ANativeWindow_unlockAndPost; local: *; diff --git a/libs/nativewindow/tests/AHardwareBufferTest.cpp b/libs/nativewindow/tests/AHardwareBufferTest.cpp index cc2731d908..71b1f9f021 100644 --- a/libs/nativewindow/tests/AHardwareBufferTest.cpp +++ b/libs/nativewindow/tests/AHardwareBufferTest.cpp @@ -20,6 +20,7 @@ #include <android/hardware_buffer.h> #include <private/android/AHardwareBufferHelpers.h> #include <android/hardware/graphics/common/1.0/types.h> +#include <vndk/hardware_buffer.h> #include <gtest/gtest.h> @@ -100,9 +101,33 @@ TEST(AHardwareBufferTest, ConvertToAndFromGrallocBits) { (uint64_t)BufferUsage::CPU_WRITE_RARELY, AHARDWAREBUFFER_USAGE_CPU_READ_RARELY | AHARDWAREBUFFER_USAGE_CPU_WRITE_RARELY)); -EXPECT_TRUE(TestUsageConversion( + EXPECT_TRUE(TestUsageConversion( (uint64_t)BufferUsage::GPU_RENDER_TARGET | (uint64_t)BufferUsage::GPU_TEXTURE | - 1ull << 29 | 1ull << 57, + 1ull << 29 | 1ull << 57, AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT | AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE | AHARDWAREBUFFER_USAGE_VENDOR_1 | AHARDWAREBUFFER_USAGE_VENDOR_13)); } + +TEST(AHardwareBufferTest, GetCreateHandleTest) { + AHardwareBuffer_Desc desc{ + .width = 64, + .height = 1, + .layers = 1, + .format = AHARDWAREBUFFER_FORMAT_BLOB, + .usage = AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN | AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN, + .stride = 64, + }; + + AHardwareBuffer* buffer = nullptr; + EXPECT_EQ(0, AHardwareBuffer_allocate(&desc, &buffer)); + const native_handle_t* handle = AHardwareBuffer_getNativeHandle(buffer); + EXPECT_NE(nullptr, handle); + + AHardwareBuffer* otherBuffer = nullptr; + EXPECT_EQ(0, AHardwareBuffer_createFromHandle( + &desc, handle, AHARDWAREBUFFER_CREATE_FROM_HANDLE_METHOD_CLONE, &otherBuffer)); + EXPECT_NE(nullptr, otherBuffer); + + AHardwareBuffer_release(buffer); + AHardwareBuffer_release(otherBuffer); +} diff --git a/libs/renderengine/Android.bp b/libs/renderengine/Android.bp index 36211ca733..cc252d67ae 100644 --- a/libs/renderengine/Android.bp +++ b/libs/renderengine/Android.bp @@ -26,6 +26,7 @@ cc_defaults { "libgui", "liblog", "libnativewindow", + "libprocessgroup", "libsync", "libui", "libutils", @@ -51,6 +52,7 @@ filegroup { "gl/GLExtensions.cpp", "gl/GLFramebuffer.cpp", "gl/GLImage.cpp", + "gl/ImageManager.cpp", "gl/Program.cpp", "gl/ProgramCache.cpp", ], diff --git a/libs/renderengine/gl/GLESRenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp index 46a8e9eecf..d2a7525113 100644 --- a/libs/renderengine/gl/GLESRenderEngine.cpp +++ b/libs/renderengine/gl/GLESRenderEngine.cpp @@ -19,9 +19,8 @@ #define LOG_TAG "RenderEngine" #define ATRACE_TAG ATRACE_TAG_GRAPHICS -#include "GLESRenderEngine.h" - -#include <math.h> +#include <sched.h> +#include <cmath> #include <fstream> #include <sstream> #include <unordered_set> @@ -31,6 +30,7 @@ #include <android-base/stringprintf.h> #include <cutils/compiler.h> #include <cutils/properties.h> +#include <gui/DebugEGLImageTracker.h> #include <renderengine/Mesh.h> #include <renderengine/Texture.h> #include <renderengine/private/Description.h> @@ -42,6 +42,7 @@ #include <ui/Region.h> #include <utils/KeyedVector.h> #include <utils/Trace.h> +#include "GLESRenderEngine.h" #include "GLExtensions.h" #include "GLFramebuffer.h" #include "GLImage.h" @@ -422,10 +423,13 @@ GLESRenderEngine::GLESRenderEngine(uint32_t featureFlags, EGLDisplay display, EG mTraceGpuCompletion = true; mFlushTracer = std::make_unique<FlushTracer>(this); } + mImageManager = std::make_unique<ImageManager>(this); mDrawingBuffer = createFramebuffer(); } GLESRenderEngine::~GLESRenderEngine() { + // Destroy the image manager first. + mImageManager = nullptr; std::lock_guard<std::mutex> lock(mRenderingMutex); unbindFrameBuffer(mDrawingBuffer.get()); mDrawingBuffer = nullptr; @@ -433,6 +437,7 @@ GLESRenderEngine::~GLESRenderEngine() { EGLImageKHR expired = mFramebufferImageCache.front().second; mFramebufferImageCache.pop_front(); eglDestroyImageKHR(mEGLDisplay, expired); + DEBUG_EGL_IMAGE_TRACKER_DESTROY(); } mImageCache.clear(); eglMakeCurrent(mEGLDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); @@ -614,64 +619,51 @@ void GLESRenderEngine::bindExternalTextureImage(uint32_t texName, const Image& i } } -status_t GLESRenderEngine::cacheExternalTextureBuffer(const sp<GraphicBuffer>& buffer) { - std::lock_guard<std::mutex> lock(mRenderingMutex); - return cacheExternalTextureBufferLocked(buffer); -} - status_t GLESRenderEngine::bindExternalTextureBuffer(uint32_t texName, const sp<GraphicBuffer>& buffer, const sp<Fence>& bufferFence) { - std::lock_guard<std::mutex> lock(mRenderingMutex); - return bindExternalTextureBufferLocked(texName, buffer, bufferFence); -} - -status_t GLESRenderEngine::cacheExternalTextureBufferLocked(const sp<GraphicBuffer>& buffer) { if (buffer == nullptr) { return BAD_VALUE; } ATRACE_CALL(); - if (mImageCache.count(buffer->getId()) > 0) { - return NO_ERROR; + bool found = false; + { + std::lock_guard<std::mutex> lock(mRenderingMutex); + auto cachedImage = mImageCache.find(buffer->getId()); + found = (cachedImage != mImageCache.end()); } - std::unique_ptr<Image> newImage = createImage(); - - bool created = newImage->setNativeWindowBuffer(buffer->getNativeBuffer(), - buffer->getUsage() & GRALLOC_USAGE_PROTECTED); - if (!created) { - ALOGE("Failed to create image. size=%ux%u st=%u usage=%#" PRIx64 " fmt=%d", - buffer->getWidth(), buffer->getHeight(), buffer->getStride(), buffer->getUsage(), - buffer->getPixelFormat()); - return NO_INIT; + // If we couldn't find the image in the cache at this time, then either + // SurfaceFlinger messed up registering the buffer ahead of time or we got + // backed up creating other EGLImages. + if (!found) { + status_t cacheResult = mImageManager->cache(buffer); + if (cacheResult != NO_ERROR) { + return cacheResult; + } } - mImageCache.insert(std::make_pair(buffer->getId(), std::move(newImage))); - return NO_ERROR; -} - -status_t GLESRenderEngine::bindExternalTextureBufferLocked(uint32_t texName, - const sp<GraphicBuffer>& buffer, - const sp<Fence>& bufferFence) { - ATRACE_CALL(); - status_t cacheResult = cacheExternalTextureBufferLocked(buffer); - - if (cacheResult != NO_ERROR) { - return cacheResult; - } + // Whether or not we needed to cache, re-check mImageCache to make sure that + // there's an EGLImage. The current threading model guarantees that we don't + // destroy a cached image until it's really not needed anymore (i.e. this + // function should not be called), so the only possibility is that something + // terrible went wrong and we should just bind something and move on. + { + std::lock_guard<std::mutex> lock(mRenderingMutex); + auto cachedImage = mImageCache.find(buffer->getId()); - auto cachedImage = mImageCache.find(buffer->getId()); + if (cachedImage == mImageCache.end()) { + // We failed creating the image if we got here, so bail out. + ALOGE("Failed to create an EGLImage when rendering"); + bindExternalTextureImage(texName, *createImage()); + return NO_INIT; + } - if (cachedImage == mImageCache.end()) { - // We failed creating the image if we got here, so bail out. - bindExternalTextureImage(texName, *createImage()); - return NO_INIT; + bindExternalTextureImage(texName, *cachedImage->second); } - bindExternalTextureImage(texName, *cachedImage->second); - // Wait for the new buffer to be ready. if (bufferFence != nullptr && bufferFence->isValid()) { if (GLExtensions::getInstance().hasWaitSync()) { @@ -696,13 +688,81 @@ status_t GLESRenderEngine::bindExternalTextureBufferLocked(uint32_t texName, return NO_ERROR; } +void GLESRenderEngine::cacheExternalTextureBuffer(const sp<GraphicBuffer>& buffer) { + mImageManager->cacheAsync(buffer, nullptr); +} + +std::shared_ptr<ImageManager::Barrier> GLESRenderEngine::cacheExternalTextureBufferForTesting( + const sp<GraphicBuffer>& buffer) { + auto barrier = std::make_shared<ImageManager::Barrier>(); + mImageManager->cacheAsync(buffer, barrier); + return barrier; +} + +status_t GLESRenderEngine::cacheExternalTextureBufferInternal(const sp<GraphicBuffer>& buffer) { + if (buffer == nullptr) { + return BAD_VALUE; + } + + { + std::lock_guard<std::mutex> lock(mRenderingMutex); + if (mImageCache.count(buffer->getId()) > 0) { + // If there's already an image then fail fast here. + return NO_ERROR; + } + } + ATRACE_CALL(); + + // Create the image without holding a lock so that we don't block anything. + std::unique_ptr<Image> newImage = createImage(); + + bool created = newImage->setNativeWindowBuffer(buffer->getNativeBuffer(), + buffer->getUsage() & GRALLOC_USAGE_PROTECTED); + if (!created) { + ALOGE("Failed to create image. size=%ux%u st=%u usage=%#" PRIx64 " fmt=%d", + buffer->getWidth(), buffer->getHeight(), buffer->getStride(), buffer->getUsage(), + buffer->getPixelFormat()); + return NO_INIT; + } + + { + std::lock_guard<std::mutex> lock(mRenderingMutex); + if (mImageCache.count(buffer->getId()) > 0) { + // In theory it's possible for another thread to recache the image, + // so bail out if another thread won. + return NO_ERROR; + } + mImageCache.insert(std::make_pair(buffer->getId(), std::move(newImage))); + } + + return NO_ERROR; +} + void GLESRenderEngine::unbindExternalTextureBuffer(uint64_t bufferId) { - std::lock_guard<std::mutex> lock(mRenderingMutex); - const auto& cachedImage = mImageCache.find(bufferId); - if (cachedImage != mImageCache.end()) { - ALOGV("Destroying image for buffer: %" PRIu64, bufferId); - mImageCache.erase(bufferId); - return; + mImageManager->releaseAsync(bufferId, nullptr); +} + +std::shared_ptr<ImageManager::Barrier> GLESRenderEngine::unbindExternalTextureBufferForTesting( + uint64_t bufferId) { + auto barrier = std::make_shared<ImageManager::Barrier>(); + mImageManager->releaseAsync(bufferId, barrier); + return barrier; +} + +void GLESRenderEngine::unbindExternalTextureBufferInternal(uint64_t bufferId) { + std::unique_ptr<Image> image; + { + std::lock_guard<std::mutex> lock(mRenderingMutex); + const auto& cachedImage = mImageCache.find(bufferId); + + if (cachedImage != mImageCache.end()) { + ALOGV("Destroying image for buffer: %" PRIu64, bufferId); + // Move the buffer out of cache first, so that we can destroy + // without holding the cache's lock. + image = std::move(cachedImage->second); + mImageCache.erase(bufferId); + return; + } } ALOGV("Failed to find image for buffer: %" PRIu64, bufferId); } @@ -842,6 +902,7 @@ EGLImageKHR GLESRenderEngine::createFramebufferImageIfNeeded(ANativeWindowBuffer bool useFramebufferCache) { sp<GraphicBuffer> graphicBuffer = GraphicBuffer::from(nativeBuffer); if (useFramebufferCache) { + std::lock_guard<std::mutex> lock(mFramebufferImageCacheMutex); for (const auto& image : mFramebufferImageCache) { if (image.first == graphicBuffer->getId()) { return image.second; @@ -857,14 +918,20 @@ EGLImageKHR GLESRenderEngine::createFramebufferImageIfNeeded(ANativeWindowBuffer nativeBuffer, attributes); if (useFramebufferCache) { if (image != EGL_NO_IMAGE_KHR) { + std::lock_guard<std::mutex> lock(mFramebufferImageCacheMutex); if (mFramebufferImageCache.size() >= mFramebufferImageCacheSize) { EGLImageKHR expired = mFramebufferImageCache.front().second; mFramebufferImageCache.pop_front(); eglDestroyImageKHR(mEGLDisplay, expired); + DEBUG_EGL_IMAGE_TRACKER_DESTROY(); } mFramebufferImageCache.push_back({graphicBuffer->getId(), image}); } } + + if (image != EGL_NO_IMAGE_KHR) { + DEBUG_EGL_IMAGE_TRACKER_CREATE(); + } return image; } @@ -889,127 +956,123 @@ status_t GLESRenderEngine::drawLayers(const DisplaySettings& display, return BAD_VALUE; } - { - std::lock_guard<std::mutex> lock(mRenderingMutex); + BindNativeBufferAsFramebuffer fbo(*this, buffer, useFramebufferCache); - BindNativeBufferAsFramebuffer fbo(*this, buffer, useFramebufferCache); - - if (fbo.getStatus() != NO_ERROR) { - ALOGE("Failed to bind framebuffer! Aborting GPU composition for buffer (%p).", - buffer->handle); - checkErrors(); - return fbo.getStatus(); - } - - // clear the entire buffer, sometimes when we reuse buffers we'd persist - // ghost images otherwise. - // we also require a full transparent framebuffer for overlays. This is - // probably not quite efficient on all GPUs, since we could filter out - // opaque layers. - clearWithColor(0.0, 0.0, 0.0, 0.0); + if (fbo.getStatus() != NO_ERROR) { + ALOGE("Failed to bind framebuffer! Aborting GPU composition for buffer (%p).", + buffer->handle); + checkErrors(); + return fbo.getStatus(); + } - setViewportAndProjection(display.physicalDisplay, display.clip); + // clear the entire buffer, sometimes when we reuse buffers we'd persist + // ghost images otherwise. + // we also require a full transparent framebuffer for overlays. This is + // probably not quite efficient on all GPUs, since we could filter out + // opaque layers. + clearWithColor(0.0, 0.0, 0.0, 0.0); - setOutputDataSpace(display.outputDataspace); - setDisplayMaxLuminance(display.maxLuminance); + setViewportAndProjection(display.physicalDisplay, display.clip); - mat4 projectionMatrix = mState.projectionMatrix * display.globalTransform; - mState.projectionMatrix = projectionMatrix; - if (!display.clearRegion.isEmpty()) { - glDisable(GL_BLEND); - fillRegionWithColor(display.clearRegion, 0.0, 0.0, 0.0, 1.0); - } + setOutputDataSpace(display.outputDataspace); + setDisplayMaxLuminance(display.maxLuminance); - Mesh mesh(Mesh::TRIANGLE_FAN, 4, 2, 2); - for (auto layer : layers) { - mState.projectionMatrix = projectionMatrix * layer.geometry.positionTransform; + mat4 projectionMatrix = mState.projectionMatrix * display.globalTransform; + mState.projectionMatrix = projectionMatrix; + if (!display.clearRegion.isEmpty()) { + glDisable(GL_BLEND); + fillRegionWithColor(display.clearRegion, 0.0, 0.0, 0.0, 1.0); + } - const FloatRect bounds = layer.geometry.boundaries; - Mesh::VertexArray<vec2> position(mesh.getPositionArray<vec2>()); - position[0] = vec2(bounds.left, bounds.top); - position[1] = vec2(bounds.left, bounds.bottom); - position[2] = vec2(bounds.right, bounds.bottom); - position[3] = vec2(bounds.right, bounds.top); + Mesh mesh(Mesh::TRIANGLE_FAN, 4, 2, 2); + for (auto layer : layers) { + mState.projectionMatrix = projectionMatrix * layer.geometry.positionTransform; - setupLayerCropping(layer, mesh); - setColorTransform(display.colorTransform * layer.colorTransform); + const FloatRect bounds = layer.geometry.boundaries; + Mesh::VertexArray<vec2> position(mesh.getPositionArray<vec2>()); + position[0] = vec2(bounds.left, bounds.top); + position[1] = vec2(bounds.left, bounds.bottom); + position[2] = vec2(bounds.right, bounds.bottom); + position[3] = vec2(bounds.right, bounds.top); - bool usePremultipliedAlpha = true; - bool disableTexture = true; - bool isOpaque = false; + setupLayerCropping(layer, mesh); + setColorTransform(display.colorTransform * layer.colorTransform); - if (layer.source.buffer.buffer != nullptr) { - disableTexture = false; - isOpaque = layer.source.buffer.isOpaque; + bool usePremultipliedAlpha = true; + bool disableTexture = true; + bool isOpaque = false; - sp<GraphicBuffer> gBuf = layer.source.buffer.buffer; - bindExternalTextureBufferLocked(layer.source.buffer.textureName, gBuf, - layer.source.buffer.fence); + if (layer.source.buffer.buffer != nullptr) { + disableTexture = false; + isOpaque = layer.source.buffer.isOpaque; - usePremultipliedAlpha = layer.source.buffer.usePremultipliedAlpha; - Texture texture(Texture::TEXTURE_EXTERNAL, layer.source.buffer.textureName); - mat4 texMatrix = layer.source.buffer.textureTransform; + sp<GraphicBuffer> gBuf = layer.source.buffer.buffer; + bindExternalTextureBuffer(layer.source.buffer.textureName, gBuf, + layer.source.buffer.fence); - texture.setMatrix(texMatrix.asArray()); - texture.setFiltering(layer.source.buffer.useTextureFiltering); + usePremultipliedAlpha = layer.source.buffer.usePremultipliedAlpha; + Texture texture(Texture::TEXTURE_EXTERNAL, layer.source.buffer.textureName); + mat4 texMatrix = layer.source.buffer.textureTransform; - texture.setDimensions(gBuf->getWidth(), gBuf->getHeight()); - setSourceY410BT2020(layer.source.buffer.isY410BT2020); + texture.setMatrix(texMatrix.asArray()); + texture.setFiltering(layer.source.buffer.useTextureFiltering); - renderengine::Mesh::VertexArray<vec2> texCoords(mesh.getTexCoordArray<vec2>()); - texCoords[0] = vec2(0.0, 0.0); - texCoords[1] = vec2(0.0, 1.0); - texCoords[2] = vec2(1.0, 1.0); - texCoords[3] = vec2(1.0, 0.0); - setupLayerTexturing(texture); - } + texture.setDimensions(gBuf->getWidth(), gBuf->getHeight()); + setSourceY410BT2020(layer.source.buffer.isY410BT2020); - const half3 solidColor = layer.source.solidColor; - const half4 color = half4(solidColor.r, solidColor.g, solidColor.b, layer.alpha); - // Buffer sources will have a black solid color ignored in the shader, - // so in that scenario the solid color passed here is arbitrary. - setupLayerBlending(usePremultipliedAlpha, isOpaque, disableTexture, color, - layer.geometry.roundedCornersRadius); - if (layer.disableBlending) { - glDisable(GL_BLEND); - } - setSourceDataSpace(layer.sourceDataspace); - - // We only want to do a special handling for rounded corners when having rounded corners - // is the only reason it needs to turn on blending, otherwise, we handle it like the - // usual way since it needs to turn on blending anyway. - if (layer.geometry.roundedCornersRadius > 0.0 && color.a >= 1.0f && isOpaque) { - handleRoundedCorners(display, layer, mesh); - } else { - drawMesh(mesh); - } + renderengine::Mesh::VertexArray<vec2> texCoords(mesh.getTexCoordArray<vec2>()); + texCoords[0] = vec2(0.0, 0.0); + texCoords[1] = vec2(0.0, 1.0); + texCoords[2] = vec2(1.0, 1.0); + texCoords[3] = vec2(1.0, 0.0); + setupLayerTexturing(texture); + } - // Cleanup if there's a buffer source - if (layer.source.buffer.buffer != nullptr) { - disableBlending(); - setSourceY410BT2020(false); - disableTexturing(); - } + const half3 solidColor = layer.source.solidColor; + const half4 color = half4(solidColor.r, solidColor.g, solidColor.b, layer.alpha); + // Buffer sources will have a black solid color ignored in the shader, + // so in that scenario the solid color passed here is arbitrary. + setupLayerBlending(usePremultipliedAlpha, isOpaque, disableTexture, color, + layer.geometry.roundedCornersRadius); + if (layer.disableBlending) { + glDisable(GL_BLEND); } + setSourceDataSpace(layer.sourceDataspace); - if (drawFence != nullptr) { - *drawFence = flush(); + // We only want to do a special handling for rounded corners when having rounded corners + // is the only reason it needs to turn on blending, otherwise, we handle it like the + // usual way since it needs to turn on blending anyway. + if (layer.geometry.roundedCornersRadius > 0.0 && color.a >= 1.0f && isOpaque) { + handleRoundedCorners(display, layer, mesh); + } else { + drawMesh(mesh); } - // If flush failed or we don't support native fences, we need to force the - // gl command stream to be executed. - if (drawFence == nullptr || drawFence->get() < 0) { - bool success = finish(); - if (!success) { - ALOGE("Failed to flush RenderEngine commands"); - checkErrors(); - // Chances are, something illegal happened (either the caller passed - // us bad parameters, or we messed up our shader generation). - return INVALID_OPERATION; - } + + // Cleanup if there's a buffer source + if (layer.source.buffer.buffer != nullptr) { + disableBlending(); + setSourceY410BT2020(false); + disableTexturing(); } + } - checkErrors(); + if (drawFence != nullptr) { + *drawFence = flush(); } + // If flush failed or we don't support native fences, we need to force the + // gl command stream to be executed. + if (drawFence == nullptr || drawFence->get() < 0) { + bool success = finish(); + if (!success) { + ALOGE("Failed to flush RenderEngine commands"); + checkErrors(); + // Chances are, something illegal happened (either the caller passed + // us bad parameters, or we messed up our shader generation). + return INVALID_OPERATION; + } + } + + checkErrors(); return NO_ERROR; } @@ -1306,6 +1369,23 @@ void GLESRenderEngine::dump(std::string& result) { StringAppendF(&result, "RenderEngine last dataspace conversion: (%s) to (%s)\n", dataspaceDetails(static_cast<android_dataspace>(mDataSpace)).c_str(), dataspaceDetails(static_cast<android_dataspace>(mOutputDataSpace)).c_str()); + { + std::lock_guard<std::mutex> lock(mRenderingMutex); + StringAppendF(&result, "RenderEngine image cache size: %zu\n", mImageCache.size()); + StringAppendF(&result, "Dumping buffer ids...\n"); + for (const auto& [id, unused] : mImageCache) { + StringAppendF(&result, "0x%" PRIx64 "\n", id); + } + } + { + std::lock_guard<std::mutex> lock(mFramebufferImageCacheMutex); + StringAppendF(&result, "RenderEngine framebuffer image cache size: %zu\n", + mFramebufferImageCache.size()); + StringAppendF(&result, "Dumping buffer ids...\n"); + for (const auto& [id, unused] : mFramebufferImageCache) { + StringAppendF(&result, "0x%" PRIx64 "\n", id); + } + } } GLESRenderEngine::GlesVersion GLESRenderEngine::parseGlesVersion(const char* str) { @@ -1432,7 +1512,7 @@ bool GLESRenderEngine::isImageCachedForTesting(uint64_t bufferId) { } bool GLESRenderEngine::isFramebufferImageCachedForTesting(uint64_t bufferId) { - std::lock_guard<std::mutex> lock(mRenderingMutex); + std::lock_guard<std::mutex> lock(mFramebufferImageCacheMutex); return std::any_of(mFramebufferImageCache.cbegin(), mFramebufferImageCache.cend(), [=](std::pair<uint64_t, EGLImageKHR> image) { return image.first == bufferId; diff --git a/libs/renderengine/gl/GLESRenderEngine.h b/libs/renderengine/gl/GLESRenderEngine.h index de793c2142..dd60e50c67 100644 --- a/libs/renderengine/gl/GLESRenderEngine.h +++ b/libs/renderengine/gl/GLESRenderEngine.h @@ -17,9 +17,7 @@ #ifndef SF_GLESRENDERENGINE_H_ #define SF_GLESRENDERENGINE_H_ -#include <android-base/thread_annotations.h> #include <stdint.h> -#include <sys/types.h> #include <condition_variable> #include <deque> #include <mutex> @@ -30,8 +28,11 @@ #include <EGL/egl.h> #include <EGL/eglext.h> #include <GLES2/gl2.h> +#include <android-base/thread_annotations.h> #include <renderengine/RenderEngine.h> #include <renderengine/private/Description.h> +#include <sys/types.h> +#include "ImageManager.h" #define EGL_NO_CONFIG ((EGLConfig)0) @@ -74,7 +75,7 @@ public: void bindExternalTextureImage(uint32_t texName, const Image& image) override; status_t bindExternalTextureBuffer(uint32_t texName, const sp<GraphicBuffer>& buffer, const sp<Fence>& fence) EXCLUDES(mRenderingMutex); - status_t cacheExternalTextureBuffer(const sp<GraphicBuffer>& buffer) EXCLUDES(mRenderingMutex); + void cacheExternalTextureBuffer(const sp<GraphicBuffer>& buffer) EXCLUDES(mRenderingMutex); void unbindExternalTextureBuffer(uint64_t bufferId) EXCLUDES(mRenderingMutex); status_t bindFrameBuffer(Framebuffer* framebuffer) override; void unbindFrameBuffer(Framebuffer* framebuffer) override; @@ -85,25 +86,32 @@ public: bool useProtectedContext(bool useProtectedContext) override; status_t drawLayers(const DisplaySettings& display, const std::vector<LayerSettings>& layers, ANativeWindowBuffer* buffer, const bool useFramebufferCache, - base::unique_fd&& bufferFence, base::unique_fd* drawFence) - EXCLUDES(mRenderingMutex) override; + base::unique_fd&& bufferFence, base::unique_fd* drawFence) override; // internal to RenderEngine EGLDisplay getEGLDisplay() const { return mEGLDisplay; } EGLConfig getEGLConfig() const { return mEGLConfig; } // Creates an output image for rendering to EGLImageKHR createFramebufferImageIfNeeded(ANativeWindowBuffer* nativeBuffer, bool isProtected, - bool useFramebufferCache); + bool useFramebufferCache) + EXCLUDES(mFramebufferImageCacheMutex); // Test-only methods // Returns true iff mImageCache contains an image keyed by bufferId bool isImageCachedForTesting(uint64_t bufferId) EXCLUDES(mRenderingMutex); // Returns true iff mFramebufferImageCache contains an image keyed by bufferId - bool isFramebufferImageCachedForTesting(uint64_t bufferId) EXCLUDES(mRenderingMutex); + bool isFramebufferImageCachedForTesting(uint64_t bufferId) + EXCLUDES(mFramebufferImageCacheMutex); + // These are wrappers around public methods above, but exposing Barrier + // objects so that tests can block. + std::shared_ptr<ImageManager::Barrier> cacheExternalTextureBufferForTesting( + const sp<GraphicBuffer>& buffer); + std::shared_ptr<ImageManager::Barrier> unbindExternalTextureBufferForTesting(uint64_t bufferId); protected: Framebuffer* getFramebufferForDrawing() override; - void dump(std::string& result) override; + void dump(std::string& result) override EXCLUDES(mRenderingMutex) + EXCLUDES(mFramebufferImageCacheMutex); void setViewportAndProjection(size_t vpw, size_t vph, Rect sourceCrop, ui::Transform::orientation_flags rotation) override; void setupLayerBlending(bool premultipliedAlpha, bool opaque, bool disableTexture, @@ -145,6 +153,9 @@ private: void setScissor(const Rect& region); void disableScissor(); bool waitSync(EGLSyncKHR sync, EGLint flags); + status_t cacheExternalTextureBufferInternal(const sp<GraphicBuffer>& buffer) + EXCLUDES(mRenderingMutex); + void unbindExternalTextureBufferInternal(uint64_t bufferId) EXCLUDES(mRenderingMutex); // A data space is considered HDR data space if it has BT2020 color space // with PQ or HLG transfer function. @@ -200,7 +211,11 @@ private: uint32_t mFramebufferImageCacheSize = 0; // Cache of output images, keyed by corresponding GraphicBuffer ID. - std::deque<std::pair<uint64_t, EGLImageKHR>> mFramebufferImageCache; + std::deque<std::pair<uint64_t, EGLImageKHR>> mFramebufferImageCache + GUARDED_BY(mFramebufferImageCacheMutex); + // The only reason why we have this mutex is so that we don't segfault when + // dumping info. + std::mutex mFramebufferImageCacheMutex; // Current dataspace of layer being rendered ui::Dataspace mDataSpace = ui::Dataspace::UNKNOWN; @@ -220,15 +235,6 @@ private: // multiple threads is guaranteed thread-safe. std::mutex mRenderingMutex; - // See bindExternalTextureBuffer above, but requiring that mRenderingMutex - // is held. - status_t bindExternalTextureBufferLocked(uint32_t texName, const sp<GraphicBuffer>& buffer, - const sp<Fence>& fence) REQUIRES(mRenderingMutex); - // See cacheExternalTextureBuffer above, but requiring that mRenderingMutex - // is held. - status_t cacheExternalTextureBufferLocked(const sp<GraphicBuffer>& buffer) - REQUIRES(mRenderingMutex); - std::unique_ptr<Framebuffer> mDrawingBuffer; class FlushTracer { @@ -253,7 +259,9 @@ private: bool mRunning = true; }; friend class FlushTracer; + friend class ImageManager; std::unique_ptr<FlushTracer> mFlushTracer; + std::unique_ptr<ImageManager> mImageManager = std::make_unique<ImageManager>(this); }; } // namespace gl diff --git a/libs/renderengine/gl/GLFramebuffer.cpp b/libs/renderengine/gl/GLFramebuffer.cpp index dacf8d3d82..5fbb5ba7d7 100644 --- a/libs/renderengine/gl/GLFramebuffer.cpp +++ b/libs/renderengine/gl/GLFramebuffer.cpp @@ -22,6 +22,7 @@ #include <GLES/glext.h> #include <GLES2/gl2.h> #include <GLES2/gl2ext.h> +#include <gui/DebugEGLImageTracker.h> #include <nativebase/nativebase.h> #include <utils/Trace.h> #include "GLESRenderEngine.h" @@ -47,6 +48,7 @@ bool GLFramebuffer::setNativeWindowBuffer(ANativeWindowBuffer* nativeBuffer, boo if (mEGLImage != EGL_NO_IMAGE_KHR) { if (!usingFramebufferCache) { eglDestroyImageKHR(mEGLDisplay, mEGLImage); + DEBUG_EGL_IMAGE_TRACKER_DESTROY(); } mEGLImage = EGL_NO_IMAGE_KHR; mBufferWidth = 0; diff --git a/libs/renderengine/gl/GLImage.cpp b/libs/renderengine/gl/GLImage.cpp index 77e648e70f..8497721956 100644 --- a/libs/renderengine/gl/GLImage.cpp +++ b/libs/renderengine/gl/GLImage.cpp @@ -20,6 +20,7 @@ #include <vector> +#include <gui/DebugEGLImageTracker.h> #include <log/log.h> #include <utils/Trace.h> #include "GLESRenderEngine.h" @@ -58,6 +59,7 @@ bool GLImage::setNativeWindowBuffer(ANativeWindowBuffer* buffer, bool isProtecte if (!eglDestroyImageKHR(mEGLDisplay, mEGLImage)) { ALOGE("failed to destroy image: %#x", eglGetError()); } + DEBUG_EGL_IMAGE_TRACKER_DESTROY(); mEGLImage = EGL_NO_IMAGE_KHR; } @@ -69,6 +71,7 @@ bool GLImage::setNativeWindowBuffer(ANativeWindowBuffer* buffer, bool isProtecte ALOGE("failed to create EGLImage: %#x", eglGetError()); return false; } + DEBUG_EGL_IMAGE_TRACKER_CREATE(); mProtected = isProtected; } diff --git a/libs/renderengine/gl/ImageManager.cpp b/libs/renderengine/gl/ImageManager.cpp new file mode 100644 index 0000000000..5af0e4f857 --- /dev/null +++ b/libs/renderengine/gl/ImageManager.cpp @@ -0,0 +1,140 @@ +/* + * Copyright 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define ATRACE_TAG ATRACE_TAG_GRAPHICS + +#include <pthread.h> + +#include <processgroup/sched_policy.h> +#include <utils/Trace.h> +#include "GLESRenderEngine.h" +#include "ImageManager.h" + +namespace android { +namespace renderengine { +namespace gl { + +ImageManager::ImageManager(GLESRenderEngine* engine) : mEngine(engine) { + pthread_setname_np(mThread.native_handle(), "ImageManager"); + // Use SCHED_FIFO to minimize jitter + struct sched_param param = {0}; + param.sched_priority = 2; + if (pthread_setschedparam(mThread.native_handle(), SCHED_FIFO, ¶m) != 0) { + ALOGE("Couldn't set SCHED_FIFO for ImageManager"); + } +} + +ImageManager::~ImageManager() { + { + std::lock_guard<std::mutex> lock(mMutex); + mRunning = false; + } + mCondition.notify_all(); + if (mThread.joinable()) { + mThread.join(); + } +} + +void ImageManager::cacheAsync(const sp<GraphicBuffer>& buffer, + const std::shared_ptr<Barrier>& barrier) { + if (buffer == nullptr) { + { + std::lock_guard<std::mutex> lock(barrier->mutex); + barrier->isOpen = true; + barrier->result = BAD_VALUE; + } + barrier->condition.notify_one(); + return; + } + ATRACE_CALL(); + QueueEntry entry = {QueueEntry::Operation::Insert, buffer, buffer->getId(), barrier}; + queueOperation(std::move(entry)); +} + +status_t ImageManager::cache(const sp<GraphicBuffer>& buffer) { + ATRACE_CALL(); + auto barrier = std::make_shared<Barrier>(); + cacheAsync(buffer, barrier); + std::lock_guard<std::mutex> lock(barrier->mutex); + barrier->condition.wait(barrier->mutex, + [&]() REQUIRES(barrier->mutex) { return barrier->isOpen; }); + return barrier->result; +} + +void ImageManager::releaseAsync(uint64_t bufferId, const std::shared_ptr<Barrier>& barrier) { + ATRACE_CALL(); + QueueEntry entry = {QueueEntry::Operation::Delete, nullptr, bufferId, barrier}; + queueOperation(std::move(entry)); +} + +void ImageManager::queueOperation(const QueueEntry&& entry) { + { + std::lock_guard<std::mutex> lock(mMutex); + mQueue.emplace(entry); + ATRACE_INT("ImageManagerQueueDepth", mQueue.size()); + } + mCondition.notify_one(); +} + +void ImageManager::threadMain() { + set_sched_policy(0, SP_FOREGROUND); + bool run; + { + std::lock_guard<std::mutex> lock(mMutex); + run = mRunning; + } + while (run) { + QueueEntry entry; + { + std::lock_guard<std::mutex> lock(mMutex); + mCondition.wait(mMutex, + [&]() REQUIRES(mMutex) { return !mQueue.empty() || !mRunning; }); + run = mRunning; + + if (!mRunning) { + // if mRunning is false, then ImageManager is being destroyed, so + // bail out now. + break; + } + + entry = mQueue.front(); + mQueue.pop(); + ATRACE_INT("ImageManagerQueueDepth", mQueue.size()); + } + + status_t result = NO_ERROR; + switch (entry.op) { + case QueueEntry::Operation::Delete: + mEngine->unbindExternalTextureBufferInternal(entry.bufferId); + break; + case QueueEntry::Operation::Insert: + result = mEngine->cacheExternalTextureBufferInternal(entry.buffer); + break; + } + if (entry.barrier != nullptr) { + { + std::lock_guard<std::mutex> entryLock(entry.barrier->mutex); + entry.barrier->result = result; + entry.barrier->isOpen = true; + } + entry.barrier->condition.notify_one(); + } + } +} + +} // namespace gl +} // namespace renderengine +} // namespace android diff --git a/libs/renderengine/gl/ImageManager.h b/libs/renderengine/gl/ImageManager.h new file mode 100644 index 0000000000..b5ba554c4f --- /dev/null +++ b/libs/renderengine/gl/ImageManager.h @@ -0,0 +1,70 @@ +/* + * Copyright 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <condition_variable> +#include <mutex> +#include <queue> +#include <thread> + +#include <ui/GraphicBuffer.h> + +namespace android { +namespace renderengine { +namespace gl { + +class GLESRenderEngine; + +class ImageManager { +public: + struct Barrier { + std::mutex mutex; + std::condition_variable_any condition; + bool isOpen GUARDED_BY(mutex) = false; + status_t result GUARDED_BY(mutex) = NO_ERROR; + }; + ImageManager(GLESRenderEngine* engine); + ~ImageManager(); + void cacheAsync(const sp<GraphicBuffer>& buffer, const std::shared_ptr<Barrier>& barrier) + EXCLUDES(mMutex); + status_t cache(const sp<GraphicBuffer>& buffer); + void releaseAsync(uint64_t bufferId, const std::shared_ptr<Barrier>& barrier) EXCLUDES(mMutex); + +private: + struct QueueEntry { + enum class Operation { Delete, Insert }; + + Operation op = Operation::Delete; + sp<GraphicBuffer> buffer = nullptr; + uint64_t bufferId = 0; + std::shared_ptr<Barrier> barrier = nullptr; + }; + + void queueOperation(const QueueEntry&& entry); + void threadMain(); + GLESRenderEngine* const mEngine; + std::thread mThread = std::thread([this]() { threadMain(); }); + std::condition_variable_any mCondition; + std::mutex mMutex; + std::queue<QueueEntry> mQueue GUARDED_BY(mMutex); + + bool mRunning GUARDED_BY(mMutex) = true; +}; + +} // namespace gl +} // namespace renderengine +} // namespace android diff --git a/libs/renderengine/include/renderengine/RenderEngine.h b/libs/renderengine/include/renderengine/RenderEngine.h index e7070041f2..c6a7bd843a 100644 --- a/libs/renderengine/include/renderengine/RenderEngine.h +++ b/libs/renderengine/include/renderengine/RenderEngine.h @@ -116,10 +116,20 @@ public: const sp<Fence>& fence) = 0; // Caches Image resources for this buffer, but does not bind the buffer to // a particular texture. - virtual status_t cacheExternalTextureBuffer(const sp<GraphicBuffer>& buffer) = 0; + // Note that work is deferred to an additional thread, i.e. this call + // is made asynchronously, but the caller can expect that cache/unbind calls + // are performed in a manner that's conflict serializable, i.e. unbinding + // a buffer should never occur before binding the buffer if the caller + // called {bind, cache}ExternalTextureBuffer before calling unbind. + virtual void cacheExternalTextureBuffer(const sp<GraphicBuffer>& buffer) = 0; // Removes internal resources referenced by the bufferId. This method should be // invoked when the caller will no longer hold a reference to a GraphicBuffer // and needs to clean up its resources. + // Note that work is deferred to an additional thread, i.e. this call + // is made asynchronously, but the caller can expect that cache/unbind calls + // are performed in a manner that's conflict serializable, i.e. unbinding + // a buffer should never occur before binding the buffer if the caller + // called {bind, cache}ExternalTextureBuffer before calling unbind. virtual void unbindExternalTextureBuffer(uint64_t bufferId) = 0; // When binding a native buffer, it must be done before setViewportAndProjection // Returns NO_ERROR when binds successfully, NO_MEMORY when there's no memory for allocation. @@ -176,6 +186,17 @@ public: // should be called for every display that needs to be rendered via the GPU. // @param display The display-wide settings that should be applied prior to // drawing any layers. + // + // Assumptions when calling this method: + // 1. There is exactly one caller - i.e. multi-threading is not supported. + // 2. Additional threads may be calling the {bind,cache}ExternalTexture + // methods above. But the main thread is responsible for holding resources + // such that Image destruction does not occur while this method is called. + // + // TODO(b/136806342): This should behavior should ideally be fixed since + // the above two assumptions are brittle, as conditional thread safetyness + // may be insufficient when maximizing rendering performance in the future. + // // @param layers The layers to draw onto the display, in Z-order. // @param buffer The buffer which will be drawn to. This buffer will be // ready once drawFence fires. diff --git a/libs/renderengine/include/renderengine/mock/RenderEngine.h b/libs/renderengine/include/renderengine/mock/RenderEngine.h index e33bcfd994..b4d3ef24ba 100644 --- a/libs/renderengine/include/renderengine/mock/RenderEngine.h +++ b/libs/renderengine/include/renderengine/mock/RenderEngine.h @@ -51,7 +51,7 @@ public: MOCK_METHOD2(genTextures, void(size_t, uint32_t*)); MOCK_METHOD2(deleteTextures, void(size_t, uint32_t const*)); MOCK_METHOD2(bindExternalTextureImage, void(uint32_t, const renderengine::Image&)); - MOCK_METHOD1(cacheExternalTextureBuffer, status_t(const sp<GraphicBuffer>&)); + MOCK_METHOD1(cacheExternalTextureBuffer, void(const sp<GraphicBuffer>&)); MOCK_METHOD3(bindExternalTextureBuffer, status_t(uint32_t, const sp<GraphicBuffer>&, const sp<Fence>&)); MOCK_METHOD1(unbindExternalTextureBuffer, void(uint64_t)); diff --git a/libs/renderengine/tests/Android.bp b/libs/renderengine/tests/Android.bp index 9b483ef51d..e98babc30c 100644 --- a/libs/renderengine/tests/Android.bp +++ b/libs/renderengine/tests/Android.bp @@ -31,6 +31,7 @@ cc_test { "libgui", "liblog", "libnativewindow", + "libprocessgroup", "libsync", "libui", "libutils", diff --git a/libs/renderengine/tests/RenderEngineTest.cpp b/libs/renderengine/tests/RenderEngineTest.cpp index 7acaecf465..f47c7fd053 100644 --- a/libs/renderengine/tests/RenderEngineTest.cpp +++ b/libs/renderengine/tests/RenderEngineTest.cpp @@ -14,8 +14,10 @@ * limitations under the License. */ -#include <gtest/gtest.h> +#include <chrono> +#include <condition_variable> +#include <gtest/gtest.h> #include <renderengine/RenderEngine.h> #include <sync/sync.h> #include <ui/PixelFormat.h> @@ -1001,8 +1003,15 @@ TEST_F(RenderEngineTest, drawLayers_fillsBufferAndCachesImages) { invokeDraw(settings, layers, mBuffer); uint64_t bufferId = layer.source.buffer.buffer->getId(); EXPECT_TRUE(sRE->isImageCachedForTesting(bufferId)); - sRE->unbindExternalTextureBuffer(bufferId); + std::shared_ptr<renderengine::gl::ImageManager::Barrier> barrier = + sRE->unbindExternalTextureBufferForTesting(bufferId); + std::lock_guard<std::mutex> lock(barrier->mutex); + ASSERT_TRUE(barrier->condition.wait_for(barrier->mutex, std::chrono::seconds(5), + [&]() REQUIRES(barrier->mutex) { + return barrier->isOpen; + })); EXPECT_FALSE(sRE->isImageCachedForTesting(bufferId)); + EXPECT_EQ(NO_ERROR, barrier->result); } TEST_F(RenderEngineTest, drawLayers_bindExternalBufferWithNullBuffer) { @@ -1019,21 +1028,52 @@ TEST_F(RenderEngineTest, drawLayers_bindExternalBufferCachesImages) { sRE->bindExternalTextureBuffer(texName, buf, nullptr); uint64_t bufferId = buf->getId(); EXPECT_TRUE(sRE->isImageCachedForTesting(bufferId)); - sRE->unbindExternalTextureBuffer(bufferId); + std::shared_ptr<renderengine::gl::ImageManager::Barrier> barrier = + sRE->unbindExternalTextureBufferForTesting(bufferId); + std::lock_guard<std::mutex> lock(barrier->mutex); + ASSERT_TRUE(barrier->condition.wait_for(barrier->mutex, std::chrono::seconds(5), + [&]() REQUIRES(barrier->mutex) { + return barrier->isOpen; + })); + EXPECT_EQ(NO_ERROR, barrier->result); EXPECT_FALSE(sRE->isImageCachedForTesting(bufferId)); } TEST_F(RenderEngineTest, drawLayers_cacheExternalBufferWithNullBuffer) { - status_t result = sRE->cacheExternalTextureBuffer(nullptr); - ASSERT_EQ(BAD_VALUE, result); + std::shared_ptr<renderengine::gl::ImageManager::Barrier> barrier = + sRE->cacheExternalTextureBufferForTesting(nullptr); + std::lock_guard<std::mutex> lock(barrier->mutex); + ASSERT_TRUE(barrier->condition.wait_for(barrier->mutex, std::chrono::seconds(5), + [&]() REQUIRES(barrier->mutex) { + return barrier->isOpen; + })); + EXPECT_TRUE(barrier->isOpen); + EXPECT_EQ(BAD_VALUE, barrier->result); } TEST_F(RenderEngineTest, drawLayers_cacheExternalBufferCachesImages) { sp<GraphicBuffer> buf = allocateSourceBuffer(1, 1); uint64_t bufferId = buf->getId(); - sRE->cacheExternalTextureBuffer(buf); + std::shared_ptr<renderengine::gl::ImageManager::Barrier> barrier = + sRE->cacheExternalTextureBufferForTesting(buf); + { + std::lock_guard<std::mutex> lock(barrier->mutex); + ASSERT_TRUE(barrier->condition.wait_for(barrier->mutex, std::chrono::seconds(5), + [&]() REQUIRES(barrier->mutex) { + return barrier->isOpen; + })); + EXPECT_EQ(NO_ERROR, barrier->result); + } EXPECT_TRUE(sRE->isImageCachedForTesting(bufferId)); - sRE->unbindExternalTextureBuffer(bufferId); + barrier = sRE->unbindExternalTextureBufferForTesting(bufferId); + { + std::lock_guard<std::mutex> lock(barrier->mutex); + ASSERT_TRUE(barrier->condition.wait_for(barrier->mutex, std::chrono::seconds(5), + [&]() REQUIRES(barrier->mutex) { + return barrier->isOpen; + })); + EXPECT_EQ(NO_ERROR, barrier->result); + } EXPECT_FALSE(sRE->isImageCachedForTesting(bufferId)); } diff --git a/libs/sensor/Android.bp b/libs/sensor/Android.bp index 940ff5afbc..e8154a6931 100644 --- a/libs/sensor/Android.bp +++ b/libs/sensor/Android.bp @@ -21,22 +21,7 @@ cc_library_shared { "-Werror", ], cppflags: [ - "-Weverything", - - // The static constructors and destructors in this library have not been noted to - // introduce significant overheads - "-Wno-exit-time-destructors", - "-Wno-global-constructors", - - // We only care about compiling as C++14 - "-Wno-c++98-compat-pedantic", - - // android/sensors.h uses nested anonymous unions and anonymous structs - "-Wno-nested-anon-types", - "-Wno-gnu-anonymous-struct", - - // Don't warn about struct padding - "-Wno-padded", + "-Wextra", ], srcs: [ diff --git a/libs/ui/Android.bp b/libs/ui/Android.bp index 2518e9374d..42b578cce8 100644 --- a/libs/ui/Android.bp +++ b/libs/ui/Android.bp @@ -26,32 +26,18 @@ cc_library_shared { "-Werror", ], cppflags: [ - "-Weverything", - - // The static constructors and destructors in this library have not been noted to - // introduce significant overheads - "-Wno-exit-time-destructors", - "-Wno-global-constructors", - - // We only care about compiling as C++14 - "-Wno-c++98-compat-pedantic", - - // We are aware of the risks inherent in comparing floats for equality - "-Wno-float-equal", - - // We use four-character constants for the GraphicBuffer header, and don't care - // that they're non-portable as long as they're consistent within one execution - "-Wno-four-char-constants", - - // Don't warn about struct padding - "-Wno-padded", - - "-Wno-switch-enum", - "-Wno-format-pedantic", + "-Wextra", ], sanitize: { integer_overflow: true, + misc_undefined: ["bounds"], + diag: { + misc_undefined: ["bounds"], + no_recover: [ + "bounds", + ], + }, }, srcs: [ diff --git a/libs/ui/GraphicBufferAllocator.cpp b/libs/ui/GraphicBufferAllocator.cpp index 1c597f2a73..5f1c71ec4f 100644 --- a/libs/ui/GraphicBufferAllocator.cpp +++ b/libs/ui/GraphicBufferAllocator.cpp @@ -20,6 +20,7 @@ #include <ui/GraphicBufferAllocator.h> +#include <limits.h> #include <stdio.h> #include <grallocusage/GrallocUsageConversion.h> @@ -114,6 +115,14 @@ status_t GraphicBufferAllocator::allocate(uint32_t width, uint32_t height, if (!width || !height) width = height = 1; + const uint32_t bpp = bytesPerPixel(format); + if (std::numeric_limits<size_t>::max() / width / height < static_cast<size_t>(bpp)) { + ALOGE("Failed to allocate (%u x %u) layerCount %u format %d " + "usage %" PRIx64 ": Requesting too large a buffer size", + width, height, layerCount, format, usage); + return BAD_VALUE; + } + // Ensure that layerCount is valid. if (layerCount < 1) layerCount = 1; @@ -126,7 +135,6 @@ status_t GraphicBufferAllocator::allocate(uint32_t width, uint32_t height, if (error == NO_ERROR) { Mutex::Autolock _l(sLock); KeyedVector<buffer_handle_t, alloc_rec_t>& list(sAllocList); - uint32_t bpp = bytesPerPixel(format); alloc_rec_t rec; rec.width = width; rec.height = height; diff --git a/libs/ui/tests/GraphicBuffer_test.cpp b/libs/ui/tests/GraphicBuffer_test.cpp index a7c248c105..127f7eedd6 100644 --- a/libs/ui/tests/GraphicBuffer_test.cpp +++ b/libs/ui/tests/GraphicBuffer_test.cpp @@ -35,6 +35,22 @@ constexpr uint64_t kTestUsage = GraphicBuffer::USAGE_SW_WRITE_OFTEN; class GraphicBufferTest : public testing::Test {}; +TEST_F(GraphicBufferTest, AllocateNoError) { + PixelFormat format = PIXEL_FORMAT_RGBA_8888; + sp<GraphicBuffer> gb(new GraphicBuffer(kTestWidth, kTestHeight, format, kTestLayerCount, + kTestUsage, std::string("test"))); + ASSERT_EQ(NO_ERROR, gb->initCheck()); +} + +TEST_F(GraphicBufferTest, AllocateBadDimensions) { + PixelFormat format = PIXEL_FORMAT_RGBA_8888; + uint32_t width, height; + width = height = std::numeric_limits<uint32_t>::max(); + sp<GraphicBuffer> gb(new GraphicBuffer(width, height, format, kTestLayerCount, kTestUsage, + std::string("test"))); + ASSERT_EQ(BAD_VALUE, gb->initCheck()); +} + TEST_F(GraphicBufferTest, CreateFromBufferHubBuffer) { std::unique_ptr<BufferHubBuffer> b1 = BufferHubBuffer::create(kTestWidth, kTestHeight, kTestLayerCount, kTestFormat, diff --git a/libs/vr/libbufferhub/Android.bp b/libs/vr/libbufferhub/Android.bp index 6d202aec05..2fcee7bee6 100644 --- a/libs/vr/libbufferhub/Android.bp +++ b/libs/vr/libbufferhub/Android.bp @@ -29,11 +29,9 @@ sourceFiles = [ sharedLibraries = [ "libbase", "libcutils", - "libhardware", "liblog", "libui", "libutils", - "libnativewindow", "libpdx_default_transport", ] diff --git a/libs/vr/libpdx_default_transport/Android.bp b/libs/vr/libpdx_default_transport/Android.bp index 1176abf552..1ce9c991d5 100644 --- a/libs/vr/libpdx_default_transport/Android.bp +++ b/libs/vr/libpdx_default_transport/Android.bp @@ -39,7 +39,6 @@ cc_library_shared { "libcutils", "liblog", "libutils", - "libcrypto", "libselinux", ], } diff --git a/opengl/libs/EGL/egl_layers.cpp b/opengl/libs/EGL/egl_layers.cpp index ac01dc8f96..9b1b522731 100644 --- a/opengl/libs/EGL/egl_layers.cpp +++ b/opengl/libs/EGL/egl_layers.cpp @@ -379,14 +379,12 @@ void LayerLoader::LoadLayers() { // any symbol dependencies will be resolved by system libraries. They // can't safely use libc++_shared, for example. Which is one reason // (among several) we only allow them in non-user builds. - void* handle = nullptr; auto app_namespace = android::GraphicsEnv::getInstance().getAppNamespace(); if (app_namespace && !android::base::StartsWith(layer, kSystemLayerLibraryDir)) { - bool native_bridge = false; char* error_message = nullptr; - handle = OpenNativeLibraryInNamespace( - app_namespace, layer.c_str(), &native_bridge, &error_message); - if (!handle) { + dlhandle_ = OpenNativeLibraryInNamespace( + app_namespace, layer.c_str(), &native_bridge_, &error_message); + if (!dlhandle_) { ALOGE("Failed to load layer %s with error: %s", layer.c_str(), error_message); android::NativeLoaderFreeErrorMessage(error_message); @@ -394,11 +392,11 @@ void LayerLoader::LoadLayers() { } } else { - handle = dlopen(layer.c_str(), RTLD_NOW | RTLD_LOCAL); + dlhandle_ = dlopen(layer.c_str(), RTLD_NOW | RTLD_LOCAL); } - if (handle) { - ALOGV("Loaded layer handle (%llu) for layer %s", (unsigned long long)handle, + if (dlhandle_) { + ALOGV("Loaded layer handle (%llu) for layer %s", (unsigned long long)dlhandle_, layers[i].c_str()); } else { // If the layer is found but can't be loaded, try setenforce 0 @@ -411,8 +409,7 @@ void LayerLoader::LoadLayers() { std::string init_func = "AndroidGLESLayer_Initialize"; ALOGV("Looking for entrypoint %s", init_func.c_str()); - layer_init_func LayerInit = - reinterpret_cast<layer_init_func>(dlsym(handle, init_func.c_str())); + layer_init_func LayerInit = GetTrampoline<layer_init_func>(init_func.c_str()); if (LayerInit) { ALOGV("Found %s for layer %s", init_func.c_str(), layer.c_str()); layer_init_.push_back(LayerInit); @@ -425,8 +422,7 @@ void LayerLoader::LoadLayers() { std::string setup_func = "AndroidGLESLayer_GetProcAddress"; ALOGV("Looking for entrypoint %s", setup_func.c_str()); - layer_setup_func LayerSetup = - reinterpret_cast<layer_setup_func>(dlsym(handle, setup_func.c_str())); + layer_setup_func LayerSetup = GetTrampoline<layer_setup_func>(setup_func.c_str()); if (LayerSetup) { ALOGV("Found %s for layer %s", setup_func.c_str(), layer.c_str()); layer_setup_.push_back(LayerSetup); diff --git a/opengl/libs/EGL/egl_layers.h b/opengl/libs/EGL/egl_layers.h index e401b448cf..1e2783fc98 100644 --- a/opengl/libs/EGL/egl_layers.h +++ b/opengl/libs/EGL/egl_layers.h @@ -21,10 +21,15 @@ #include <unordered_map> #include <vector> -#include <EGL/egldefs.h> +#include <android/dlext.h> +#include <dlfcn.h> +#include <EGL/egldefs.h> #include "egl_platform_entries.h" +#include <nativebridge/native_bridge.h> +#include <nativeloader/native_loader.h> + typedef __eglMustCastToProperFunctionPointerType EGLFuncPointer; namespace android { @@ -54,10 +59,21 @@ public: std::vector<layer_setup_func> layer_setup_; private: - LayerLoader() : layers_loaded_(false), initialized_(false), current_layer_(0){}; + LayerLoader() : layers_loaded_(false), initialized_(false), current_layer_(0), dlhandle_(nullptr), native_bridge_(false){}; bool layers_loaded_; bool initialized_; unsigned current_layer_; + void* dlhandle_; + bool native_bridge_; + + template<typename Func = void*> + Func GetTrampoline(const char* name) const { + if (native_bridge_) { + return reinterpret_cast<Func>(android::NativeBridgeGetTrampoline( + dlhandle_, name, nullptr, 0)); + } + return reinterpret_cast<Func>(dlsym(dlhandle_, name)); + } }; }; // namespace android diff --git a/opengl/libs/EGL/egl_platform_entries.cpp b/opengl/libs/EGL/egl_platform_entries.cpp index e996be6853..a3bb6debe9 100644 --- a/opengl/libs/EGL/egl_platform_entries.cpp +++ b/opengl/libs/EGL/egl_platform_entries.cpp @@ -61,7 +61,7 @@ namespace android { using nsecs_t = int64_t; -struct extention_map_t { +struct extension_map_t { const char* name; __eglMustCastToProperFunctionPointerType address; }; @@ -154,7 +154,7 @@ char const * const gClientExtensionString = * (keep in sync with gExtensionString above) * */ -static const extention_map_t sExtensionMap[] = { +static const extension_map_t sExtensionMap[] = { // EGL_KHR_lock_surface { "eglLockSurfaceKHR", (__eglMustCastToProperFunctionPointerType)&eglLockSurfaceKHR }, @@ -257,13 +257,14 @@ static const extention_map_t sExtensionMap[] = { !strcmp((procname), "eglAwakenProcessIMG")) // accesses protected by sExtensionMapMutex -static std::unordered_map<std::string, __eglMustCastToProperFunctionPointerType> sGLExtentionMap; +static std::unordered_map<std::string, __eglMustCastToProperFunctionPointerType> sGLExtensionMap; +static std::unordered_map<std::string, int> sGLExtensionSlotMap; -static int sGLExtentionSlot = 0; +static int sGLExtensionSlot = 0; static pthread_mutex_t sExtensionMapMutex = PTHREAD_MUTEX_INITIALIZER; static void(*findProcAddress(const char* name, - const extention_map_t* map, size_t n))() { + const extension_map_t* map, size_t n))() { for (uint32_t i=0 ; i<n ; i++) { if (!strcmp(name, map[i].name)) { return map[i].address; @@ -1223,7 +1224,7 @@ __eglMustCastToProperFunctionPointerType eglGetProcAddressImpl(const char *procn addr = findBuiltinWrapper(procname); if (addr) return addr; - // this protects accesses to sGLExtentionMap and sGLExtentionSlot + // this protects accesses to sGLExtensionMap, sGLExtensionSlot, and sGLExtensionSlotMap pthread_mutex_lock(&sExtensionMapMutex); /* @@ -1244,51 +1245,69 @@ __eglMustCastToProperFunctionPointerType eglGetProcAddressImpl(const char *procn */ const std::string name(procname); + auto& extensionMap = sGLExtensionMap; + auto& extensionSlotMap = sGLExtensionSlotMap; + egl_connection_t* const cnx = &gEGLImpl; + LayerLoader& layer_loader(LayerLoader::getInstance()); - auto& extentionMap = sGLExtentionMap; - auto pos = extentionMap.find(name); - addr = (pos != extentionMap.end()) ? pos->second : nullptr; - const int slot = sGLExtentionSlot; + // See if we've already looked up this extension + auto pos = extensionMap.find(name); + addr = (pos != extensionMap.end()) ? pos->second : nullptr; - ALOGE_IF(slot >= MAX_NUMBER_OF_GL_EXTENSIONS, - "no more slots for eglGetProcAddress(\"%s\")", - procname); + if (!addr) { + // This is the first time we've looked this function up + // Ensure we have room to track it + const int slot = sGLExtensionSlot; + if (slot < MAX_NUMBER_OF_GL_EXTENSIONS) { - egl_connection_t* const cnx = &gEGLImpl; - LayerLoader& layer_loader(LayerLoader::getInstance()); + if (cnx->dso && cnx->egl.eglGetProcAddress) { - if (!addr && (slot < MAX_NUMBER_OF_GL_EXTENSIONS)) { + // Extensions are independent of the bound context + addr = cnx->egl.eglGetProcAddress(procname); + if (addr) { - if (cnx->dso && cnx->egl.eglGetProcAddress) { + // purposefully track the bottom of the stack in extensionMap + extensionMap[name] = addr; - // Extensions are independent of the bound context - addr = cnx->egl.eglGetProcAddress(procname); - if (addr) { + // Apply layers + addr = layer_loader.ApplyLayers(procname, addr); - // purposefully track the bottom of the stack in extensionMap - extentionMap[name] = addr; + // Track the top most entry point return the extension forwarder + cnx->hooks[egl_connection_t::GLESv1_INDEX]->ext.extensions[slot] = + cnx->hooks[egl_connection_t::GLESv2_INDEX]->ext.extensions[slot] = addr; + addr = gExtensionForwarders[slot]; - // Apply layers - addr = layer_loader.ApplyLayers(procname, addr); + // Remember the slot for this extension + extensionSlotMap[name] = slot; - // Track the top most entry point - cnx->hooks[egl_connection_t::GLESv1_INDEX]->ext.extensions[slot] = - cnx->hooks[egl_connection_t::GLESv2_INDEX]->ext.extensions[slot] = addr; - addr = gExtensionForwarders[slot]; - sGLExtentionSlot++; + // Increment the global extension index + sGLExtensionSlot++; + } } + } else { + // The extension forwarder has a fixed number of slots + ALOGE("no more slots for eglGetProcAddress(\"%s\")", procname); } - } else if (slot < MAX_NUMBER_OF_GL_EXTENSIONS) { + } else { + // We tracked an address, so we've seen this func before + // Look up the slot for this extension + auto slot_pos = extensionSlotMap.find(name); + int ext_slot = (slot_pos != extensionSlotMap.end()) ? slot_pos->second : -1; + if (ext_slot < 0) { + // Something has gone wrong, this should not happen + ALOGE("No extension slot found for %s", procname); + return nullptr; + } - // We've seen this func before, but we tracked the bottom, so re-apply layers - // More layers might have been enabled + // We tracked the bottom of the stack, so re-apply layers since + // more layers might have been enabled addr = layer_loader.ApplyLayers(procname, addr); - // Track the top most entry point - cnx->hooks[egl_connection_t::GLESv1_INDEX]->ext.extensions[slot] = - cnx->hooks[egl_connection_t::GLESv2_INDEX]->ext.extensions[slot] = addr; - addr = gExtensionForwarders[slot]; + // Track the top most entry point and return the extension forwarder + cnx->hooks[egl_connection_t::GLESv1_INDEX]->ext.extensions[ext_slot] = + cnx->hooks[egl_connection_t::GLESv2_INDEX]->ext.extensions[ext_slot] = addr; + addr = gExtensionForwarders[ext_slot]; } pthread_mutex_unlock(&sExtensionMapMutex); diff --git a/opengl/libs/libEGL.map.txt b/opengl/libs/libEGL.map.txt index b2d795745f..0c14e01c7b 100644 --- a/opengl/libs/libEGL.map.txt +++ b/opengl/libs/libEGL.map.txt @@ -28,7 +28,7 @@ LIBEGL { eglDestroySurface; eglDestroySync; # introduced=29 eglDestroySyncKHR; # introduced-arm=18 introduced-arm64=21 introduced-mips=18 introduced-mips64=21 introduced-x86=18 introduced-x86_64=21 - eglDupNativeFenceFDANDROID; # vndk + eglDupNativeFenceFDANDROID; # llndk eglGetConfigAttrib; eglGetConfigs; eglGetCurrentContext; @@ -54,7 +54,7 @@ LIBEGL { eglQueryStreamTimeKHR; # introduced=23 eglQueryStreamu64KHR; # introduced=23 eglQueryString; - eglQueryStringImplementationANDROID; # vndk + eglQueryStringImplementationANDROID; # llndk eglQuerySurface; eglReleaseTexImage; eglReleaseThread; diff --git a/services/gpuservice/GpuService.cpp b/services/gpuservice/GpuService.cpp index 8accf9d450..c8253e05c2 100644 --- a/services/gpuservice/GpuService.cpp +++ b/services/gpuservice/GpuService.cpp @@ -53,33 +53,23 @@ void GpuService::setGpuStats(const std::string& driverPackageName, int64_t driverBuildTime, const std::string& appPackageName, const int32_t vulkanVersion, GraphicsEnv::Driver driver, bool isDriverLoaded, int64_t driverLoadingTime) { - ATRACE_CALL(); - mGpuStats->insert(driverPackageName, driverVersionName, driverVersionCode, driverBuildTime, appPackageName, vulkanVersion, driver, isDriverLoaded, driverLoadingTime); } status_t GpuService::getGpuStatsGlobalInfo(std::vector<GpuStatsGlobalInfo>* outStats) const { - ATRACE_CALL(); - mGpuStats->pullGlobalStats(outStats); - return OK; } status_t GpuService::getGpuStatsAppInfo(std::vector<GpuStatsAppInfo>* outStats) const { - ATRACE_CALL(); - mGpuStats->pullAppStats(outStats); - return OK; } -void GpuService::setCpuVulkanInUse(const std::string& appPackageName, - const uint64_t driverVersionCode) { - ATRACE_CALL(); - - mGpuStats->setCpuVulkanInUse(appPackageName, driverVersionCode); +void GpuService::setTargetStats(const std::string& appPackageName, const uint64_t driverVersionCode, + const GraphicsEnv::Stats stats, const uint64_t value) { + mGpuStats->insertTargetStats(appPackageName, driverVersionCode, stats, value); } status_t GpuService::shellCommand(int /*in*/, int out, int err, std::vector<String16>& args) { diff --git a/services/gpuservice/GpuService.h b/services/gpuservice/GpuService.h index 822690134a..7d44a35814 100644 --- a/services/gpuservice/GpuService.h +++ b/services/gpuservice/GpuService.h @@ -50,8 +50,8 @@ private: int64_t driverLoadingTime) override; status_t getGpuStatsGlobalInfo(std::vector<GpuStatsGlobalInfo>* outStats) const override; status_t getGpuStatsAppInfo(std::vector<GpuStatsAppInfo>* outStats) const override; - void setCpuVulkanInUse(const std::string& appPackageName, - const uint64_t driverVersionCode) override; + void setTargetStats(const std::string& appPackageName, const uint64_t driverVersionCode, + const GraphicsEnv::Stats stats, const uint64_t value) override; /* * IBinder interface diff --git a/services/gpuservice/gpustats/GpuStats.cpp b/services/gpuservice/gpustats/GpuStats.cpp index 37c6abc96b..5d27e7281d 100644 --- a/services/gpuservice/gpustats/GpuStats.cpp +++ b/services/gpuservice/gpustats/GpuStats.cpp @@ -126,14 +126,25 @@ void GpuStats::insert(const std::string& driverPackageName, const std::string& d addLoadingTime(driver, driverLoadingTime, &mAppStats[appStatsKey]); } -void GpuStats::setCpuVulkanInUse(const std::string& appPackageName, - const uint64_t driverVersionCode) { +void GpuStats::insertTargetStats(const std::string& appPackageName, + const uint64_t driverVersionCode, const GraphicsEnv::Stats stats, + const uint64_t /*value*/) { + ATRACE_CALL(); + const std::string appStatsKey = appPackageName + std::to_string(driverVersionCode); + + std::lock_guard<std::mutex> lock(mLock); if (!mAppStats.count(appStatsKey)) { return; } - mAppStats[appStatsKey].cpuVulkanInUse = true; + switch (stats) { + case GraphicsEnv::Stats::CPU_VULKAN_IN_USE: + mAppStats[appStatsKey].cpuVulkanInUse = true; + break; + default: + break; + } } void GpuStats::interceptSystemDriverStatsLocked() { diff --git a/services/gpuservice/gpustats/GpuStats.h b/services/gpuservice/gpustats/GpuStats.h index b293f5988d..378f7f470d 100644 --- a/services/gpuservice/gpustats/GpuStats.h +++ b/services/gpuservice/gpustats/GpuStats.h @@ -37,8 +37,9 @@ public: uint64_t driverVersionCode, int64_t driverBuildTime, const std::string& appPackageName, const int32_t vulkanVersion, GraphicsEnv::Driver driver, bool isDriverLoaded, int64_t driverLoadingTime); - // Set CPU Vulkan in use signal into app stats. - void setCpuVulkanInUse(const std::string& appPackageName, const uint64_t driverVersionCode); + // Insert target stats into app stats or potentially global stats as well. + void insertTargetStats(const std::string& appPackageName, const uint64_t driverVersionCode, + const GraphicsEnv::Stats stats, const uint64_t value); // dumpsys interface void dump(const Vector<String16>& args, std::string* result); // Pull gpu global stats diff --git a/services/inputflinger/InputClassifier.cpp b/services/inputflinger/InputClassifier.cpp index ef1a2247e9..6a7f2797f4 100644 --- a/services/inputflinger/InputClassifier.cpp +++ b/services/inputflinger/InputClassifier.cpp @@ -82,7 +82,7 @@ static bool isTouchEvent(const NotifyMotionArgs& args) { // Check if the "deep touch" feature is on. static bool deepPressEnabled() { std::string flag_value = server_configurable_flags::GetServerConfigurableFlag( - INPUT_NATIVE_BOOT, DEEP_PRESS_ENABLED, "true"); + INPUT_NATIVE_BOOT, DEEP_PRESS_ENABLED, "false"); std::transform(flag_value.begin(), flag_value.end(), flag_value.begin(), ::tolower); if (flag_value == "1" || flag_value == "true") { ALOGI("Deep press feature enabled."); diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp index c11b88eac2..14ed73deaf 100644 --- a/services/sensorservice/SensorService.cpp +++ b/services/sensorservice/SensorService.cpp @@ -299,14 +299,10 @@ void SensorService::onFirstRef() { } void SensorService::setSensorAccess(uid_t uid, bool hasAccess) { - SortedVector< sp<SensorEventConnection> > activeConnections; - populateActiveConnections(&activeConnections); - { - Mutex::Autolock _l(mLock); - for (size_t i = 0 ; i < activeConnections.size(); i++) { - if (activeConnections[i] != nullptr && activeConnections[i]->getUid() == uid) { - activeConnections[i]->setSensorAccess(hasAccess); - } + ConnectionSafeAutolock connLock = mConnectionHolder.lock(mLock); + for (const sp<SensorEventConnection>& conn : connLock.getActiveConnections()) { + if (conn->getUid() == uid) { + conn->setSensorAccess(hasAccess); } } } @@ -360,7 +356,7 @@ status_t SensorService::dump(int fd, const Vector<String16>& args) { if (args.size() > 2) { return INVALID_OPERATION; } - Mutex::Autolock _l(mLock); + ConnectionSafeAutolock connLock = mConnectionHolder.lock(mLock); SensorDevice& dev(SensorDevice::getInstance()); if (args.size() == 2 && args[0] == String16("restrict")) { // If already in restricted mode. Ignore. @@ -374,7 +370,7 @@ status_t SensorService::dump(int fd, const Vector<String16>& args) { mCurrentOperatingMode = RESTRICTED; // temporarily stop all sensor direct report and disable sensors - disableAllSensorsLocked(); + disableAllSensorsLocked(&connLock); mWhiteListedPackage.setTo(String8(args[1])); return status_t(NO_ERROR); } else if (args.size() == 1 && args[0] == String16("enable")) { @@ -382,7 +378,7 @@ status_t SensorService::dump(int fd, const Vector<String16>& args) { if (mCurrentOperatingMode == RESTRICTED) { mCurrentOperatingMode = NORMAL; // enable sensors and recover all sensor direct report - enableAllSensorsLocked(); + enableAllSensorsLocked(&connLock); } if (mCurrentOperatingMode == DATA_INJECTION) { resetToNormalModeLocked(); @@ -473,22 +469,18 @@ status_t SensorService::dump(int fd, const Vector<String16>& args) { result.appendFormat("Sensor Privacy: %s\n", mSensorPrivacyPolicy->isSensorPrivacyEnabled() ? "enabled" : "disabled"); - result.appendFormat("%zd active connections\n", mActiveConnections.size()); - for (size_t i=0 ; i < mActiveConnections.size() ; i++) { - sp<SensorEventConnection> connection(mActiveConnections[i].promote()); - if (connection != nullptr) { - result.appendFormat("Connection Number: %zu \n", i); - connection->dump(result); - } + const auto& activeConnections = connLock.getActiveConnections(); + result.appendFormat("%zd active connections\n", activeConnections.size()); + for (size_t i=0 ; i < activeConnections.size() ; i++) { + result.appendFormat("Connection Number: %zu \n", i); + activeConnections[i]->dump(result); } - result.appendFormat("%zd direct connections\n", mDirectConnections.size()); - for (size_t i = 0 ; i < mDirectConnections.size() ; i++) { - sp<SensorDirectConnection> connection(mDirectConnections[i].promote()); - if (connection != nullptr) { - result.appendFormat("Direct connection %zu:\n", i); - connection->dump(result); - } + const auto& directConnections = connLock.getDirectConnections(); + result.appendFormat("%zd direct connections\n", directConnections.size()); + for (size_t i = 0 ; i < directConnections.size() ; i++) { + result.appendFormat("Direct connection %zu:\n", i); + directConnections[i]->dump(result); } result.appendFormat("Previous Registrations:\n"); @@ -515,17 +507,14 @@ status_t SensorService::dump(int fd, const Vector<String16>& args) { } void SensorService::disableAllSensors() { - Mutex::Autolock _l(mLock); - disableAllSensorsLocked(); + ConnectionSafeAutolock connLock = mConnectionHolder.lock(mLock); + disableAllSensorsLocked(&connLock); } -void SensorService::disableAllSensorsLocked() { +void SensorService::disableAllSensorsLocked(ConnectionSafeAutolock* connLock) { SensorDevice& dev(SensorDevice::getInstance()); - for (auto &i : mDirectConnections) { - sp<SensorDirectConnection> connection(i.promote()); - if (connection != nullptr) { - connection->stopAll(true /* backupRecord */); - } + for (const sp<SensorDirectConnection>& connection : connLock->getDirectConnections()) { + connection->stopAll(true /* backupRecord */); } dev.disableAllSensors(); // Clear all pending flush connections for all active sensors. If one of the active @@ -537,11 +526,11 @@ void SensorService::disableAllSensorsLocked() { } void SensorService::enableAllSensors() { - Mutex::Autolock _l(mLock); - enableAllSensorsLocked(); + ConnectionSafeAutolock connLock = mConnectionHolder.lock(mLock); + enableAllSensorsLocked(&connLock); } -void SensorService::enableAllSensorsLocked() { +void SensorService::enableAllSensorsLocked(ConnectionSafeAutolock* connLock) { // sensors should only be enabled if the operating state is not restricted and sensor // privacy is not enabled. if (mCurrentOperatingMode == RESTRICTED || mSensorPrivacyPolicy->isSensorPrivacyEnabled()) { @@ -552,14 +541,12 @@ void SensorService::enableAllSensorsLocked() { } SensorDevice& dev(SensorDevice::getInstance()); dev.enableAllSensors(); - for (auto &i : mDirectConnections) { - sp<SensorDirectConnection> connection(i.promote()); - if (connection != nullptr) { - connection->recoverAll(); - } + for (const sp<SensorDirectConnection>& connection : connLock->getDirectConnections()) { + connection->recoverAll(); } } + // NOTE: This is a remote API - make sure all args are validated status_t SensorService::shellCommand(int in, int out, int err, Vector<String16>& args) { if (!checkCallingPermission(sManageSensorsPermission, nullptr, nullptr)) { @@ -734,17 +721,8 @@ bool SensorService::threadLoop() { for (int i = 0; i < count; i++) { mSensorEventBuffer[i].flags = 0; } + ConnectionSafeAutolock connLock = mConnectionHolder.lock(mLock); - // Make a copy of the connection vector as some connections may be removed during the course - // of this loop (especially when one-shot sensor events are present in the sensor_event - // buffer). Promote all connections to StrongPointers before the lock is acquired. If the - // destructor of the sp gets called when the lock is acquired, it may result in a deadlock - // as ~SensorEventConnection() needs to acquire mLock again for cleanup. So copy all the - // strongPointers to a vector before the lock is acquired. - SortedVector< sp<SensorEventConnection> > activeConnections; - populateActiveConnections(&activeConnections); - - Mutex::Autolock _l(mLock); // Poll has returned. Hold a wakelock if one of the events is from a wake up sensor. The // rest of this loop is under a critical section protected by mLock. Acquiring a wakeLock, // sending events to clients (incrementing SensorEventConnection::mWakeLockRefCount) should @@ -818,6 +796,10 @@ bool SensorService::threadLoop() { } } + // Cache the list of active connections, since we use it in multiple places below but won't + // modify it here + const std::vector<sp<SensorEventConnection>> activeConnections = connLock.getActiveConnections(); + for (int i = 0; i < count; ++i) { // Map flush_complete_events in the buffer to SensorEventConnections which called flush // on the hardware sensor. mapFlushEventsToConnections[i] will be the @@ -869,11 +851,8 @@ bool SensorService::threadLoop() { ALOGE("Dynamic sensor release error."); } - size_t numConnections = activeConnections.size(); - for (size_t i=0 ; i < numConnections; ++i) { - if (activeConnections[i] != nullptr) { - activeConnections[i]->removeSensor(handle); - } + for (const sp<SensorEventConnection>& connection : activeConnections) { + connection->removeSensor(handle); } } } @@ -882,18 +861,14 @@ bool SensorService::threadLoop() { // Send our events to clients. Check the state of wake lock for each client and release the // lock if none of the clients need it. bool needsWakeLock = false; - size_t numConnections = activeConnections.size(); - for (size_t i=0 ; i < numConnections; ++i) { - if (activeConnections[i] != nullptr) { - activeConnections[i]->sendEvents(mSensorEventBuffer, count, mSensorEventScratch, - mMapFlushEventsToConnections); - needsWakeLock |= activeConnections[i]->needsWakeLock(); - // If the connection has one-shot sensors, it may be cleaned up after first trigger. - // Early check for one-shot sensors. - if (activeConnections[i]->hasOneShotSensors()) { - cleanupAutoDisabledSensorLocked(activeConnections[i], mSensorEventBuffer, - count); - } + for (const sp<SensorEventConnection>& connection : activeConnections) { + connection->sendEvents(mSensorEventBuffer, count, mSensorEventScratch, + mMapFlushEventsToConnections); + needsWakeLock |= connection->needsWakeLock(); + // If the connection has one-shot sensors, it may be cleaned up after first trigger. + // Early check for one-shot sensors. + if (connection->hasOneShotSensors()) { + cleanupAutoDisabledSensorLocked(connection, mSensorEventBuffer, count); } } @@ -912,17 +887,11 @@ sp<Looper> SensorService::getLooper() const { } void SensorService::resetAllWakeLockRefCounts() { - SortedVector< sp<SensorEventConnection> > activeConnections; - populateActiveConnections(&activeConnections); - { - Mutex::Autolock _l(mLock); - for (size_t i=0 ; i < activeConnections.size(); ++i) { - if (activeConnections[i] != nullptr) { - activeConnections[i]->resetWakeLockRefCount(); - } - } - setWakeLockAcquiredLocked(false); + ConnectionSafeAutolock connLock = mConnectionHolder.lock(mLock); + for (const sp<SensorEventConnection>& connection : connLock.getActiveConnections()) { + connection->resetWakeLockRefCount(); } + setWakeLockAcquiredLocked(false); } void SensorService::setWakeLockAcquiredLocked(bool acquire) { @@ -1144,9 +1113,7 @@ sp<ISensorEventConnection> SensorService::createSensorEventConnection(const Stri sp<SensorEventConnection> result(new SensorEventConnection(this, uid, connPackageName, requestedMode == DATA_INJECTION, connOpPackageName, hasSensorAccess)); if (requestedMode == DATA_INJECTION) { - if (mActiveConnections.indexOf(result) < 0) { - mActiveConnections.add(result); - } + mConnectionHolder.addEventConnectionIfNotPresent(result); // Add the associated file descriptor to the Looper for polling whenever there is data to // be injected. result->updateLooperRegistration(mLooper); @@ -1162,7 +1129,7 @@ int SensorService::isDataInjectionEnabled() { sp<ISensorEventConnection> SensorService::createSensorDirectConnection( const String16& opPackageName, uint32_t size, int32_t type, int32_t format, const native_handle *resource) { - Mutex::Autolock _l(mLock); + ConnectionSafeAutolock connLock = mConnectionHolder.lock(mLock); // No new direct connections are allowed when sensor privacy is enabled if (mSensorPrivacyPolicy->isSensorPrivacyEnabled()) { @@ -1190,9 +1157,8 @@ sp<ISensorEventConnection> SensorService::createSensorDirectConnection( } // check for duplication - for (auto &i : mDirectConnections) { - sp<SensorDirectConnection> connection(i.promote()); - if (connection != nullptr && connection->isEquivalent(&mem)) { + for (const sp<SensorDirectConnection>& connection : connLock.getDirectConnections()) { + if (connection->isEquivalent(&mem)) { ALOGE("Duplicate create channel request for the same share memory"); return nullptr; } @@ -1229,7 +1195,7 @@ sp<ISensorEventConnection> SensorService::createSensorDirectConnection( return nullptr; } - SensorDirectConnection* conn = nullptr; + sp<SensorDirectConnection> conn; SensorDevice& dev(SensorDevice::getInstance()); int channelHandle = dev.registerDirectChannel(&mem); @@ -1246,7 +1212,7 @@ sp<ISensorEventConnection> SensorService::createSensorDirectConnection( } else { // add to list of direct connections // sensor service should never hold pointer or sp of SensorDirectConnection object. - mDirectConnections.add(wp<SensorDirectConnection>(conn)); + mConnectionHolder.addDirectConnection(conn); } return conn; } @@ -1358,7 +1324,7 @@ status_t SensorService::resetToNormalModeLocked() { } void SensorService::cleanupConnection(SensorEventConnection* c) { - Mutex::Autolock _l(mLock); + ConnectionSafeAutolock connLock = mConnectionHolder.lock(mLock); const wp<SensorEventConnection> connection(c); size_t size = mActiveSensors.size(); ALOGD_IF(DEBUG_CONNECTIONS, "%zu active sensors", size); @@ -1391,10 +1357,10 @@ void SensorService::cleanupConnection(SensorEventConnection* c) { } } c->updateLooperRegistration(mLooper); - mActiveConnections.remove(connection); + mConnectionHolder.removeEventConnection(connection); BatteryService::cleanup(c->getUid()); if (c->needsWakeLock()) { - checkWakeLockStateLocked(); + checkWakeLockStateLocked(&connLock); } { @@ -1414,7 +1380,7 @@ void SensorService::cleanupConnection(SensorDirectConnection* c) { SensorDevice& dev(SensorDevice::getInstance()); dev.unregisterDirectChannel(c->getHalChannelHandle()); - mDirectConnections.remove(c); + mConnectionHolder.removeDirectConnection(c); } sp<SensorInterface> SensorService::getSensorInterfaceFromHandle(int handle) const { @@ -1433,7 +1399,7 @@ status_t SensorService::enable(const sp<SensorEventConnection>& connection, return BAD_VALUE; } - Mutex::Autolock _l(mLock); + ConnectionSafeAutolock connLock = mConnectionHolder.lock(mLock); if (mCurrentOperatingMode != NORMAL && !isWhiteListedPackage(connection->getPackageName())) { return INVALID_OPERATION; @@ -1484,7 +1450,7 @@ status_t SensorService::enable(const sp<SensorEventConnection>& connection, } connection->sendEvents(&event, 1, nullptr); if (!connection->needsWakeLock() && mWakeLockAcquired) { - checkWakeLockStateLocked(); + checkWakeLockStateLocked(&connLock); } } } @@ -1497,9 +1463,7 @@ status_t SensorService::enable(const sp<SensorEventConnection>& connection, BatteryService::enableSensor(connection->getUid(), handle); // the sensor was added (which means it wasn't already there) // so, see if this connection becomes active - if (mActiveConnections.indexOf(connection) < 0) { - mActiveConnections.add(connection); - } + mConnectionHolder.addEventConnectionIfNotPresent(connection); } else { ALOGW("sensor %08x already enabled in connection %p (ignoring)", handle, connection.get()); @@ -1603,7 +1567,7 @@ status_t SensorService::cleanupWithoutDisableLocked( } if (connection->hasAnySensor() == false) { connection->updateLooperRegistration(mLooper); - mActiveConnections.remove(connection); + mConnectionHolder.removeEventConnection(connection); } // see if this sensor becomes inactive if (rec->removeConnection(connection)) { @@ -1762,22 +1726,19 @@ int SensorService::getTargetSdkVersion(const String16& opPackageName) { } void SensorService::checkWakeLockState() { - Mutex::Autolock _l(mLock); - checkWakeLockStateLocked(); + ConnectionSafeAutolock connLock = mConnectionHolder.lock(mLock); + checkWakeLockStateLocked(&connLock); } -void SensorService::checkWakeLockStateLocked() { +void SensorService::checkWakeLockStateLocked(ConnectionSafeAutolock* connLock) { if (!mWakeLockAcquired) { return; } bool releaseLock = true; - for (size_t i=0 ; i<mActiveConnections.size() ; i++) { - sp<SensorEventConnection> connection(mActiveConnections[i].promote()); - if (connection != nullptr) { - if (connection->needsWakeLock()) { - releaseLock = false; - break; - } + for (const sp<SensorEventConnection>& connection : connLock->getActiveConnections()) { + if (connection->needsWakeLock()) { + releaseLock = false; + break; } } if (releaseLock) { @@ -1793,17 +1754,6 @@ void SensorService::sendEventsFromCache(const sp<SensorEventConnection>& connect } } -void SensorService::populateActiveConnections( - SortedVector< sp<SensorEventConnection> >* activeConnections) { - Mutex::Autolock _l(mLock); - for (size_t i=0 ; i < mActiveConnections.size(); ++i) { - sp<SensorEventConnection> connection(mActiveConnections[i].promote()); - if (connection != nullptr) { - activeConnections->add(connection); - } - } -} - bool SensorService::isWhiteListedPackage(const String8& packageName) { return (packageName.contains(mWhiteListedPackage.string())); } @@ -1938,4 +1888,62 @@ binder::Status SensorService::SensorPrivacyPolicy::onSensorPrivacyChanged(bool e } return binder::Status::ok(); } -}; // namespace android + +SensorService::ConnectionSafeAutolock::ConnectionSafeAutolock( + SensorService::SensorConnectionHolder& holder, Mutex& mutex) + : mConnectionHolder(holder), mAutolock(mutex) {} + +template<typename ConnectionType> +const std::vector<sp<ConnectionType>>& SensorService::ConnectionSafeAutolock::getConnectionsHelper( + const SortedVector<wp<ConnectionType>>& connectionList, + std::vector<std::vector<sp<ConnectionType>>>* referenceHolder) { + referenceHolder->emplace_back(); + std::vector<sp<ConnectionType>>& connections = referenceHolder->back(); + for (const wp<ConnectionType>& weakConnection : connectionList){ + sp<ConnectionType> connection = weakConnection.promote(); + if (connection != nullptr) { + connections.push_back(std::move(connection)); + } + } + return connections; +} + +const std::vector<sp<SensorService::SensorEventConnection>>& + SensorService::ConnectionSafeAutolock::getActiveConnections() { + return getConnectionsHelper(mConnectionHolder.mActiveConnections, + &mReferencedActiveConnections); +} + +const std::vector<sp<SensorService::SensorDirectConnection>>& + SensorService::ConnectionSafeAutolock::getDirectConnections() { + return getConnectionsHelper(mConnectionHolder.mDirectConnections, + &mReferencedDirectConnections); +} + +void SensorService::SensorConnectionHolder::addEventConnectionIfNotPresent( + const sp<SensorService::SensorEventConnection>& connection) { + if (mActiveConnections.indexOf(connection) < 0) { + mActiveConnections.add(connection); + } +} + +void SensorService::SensorConnectionHolder::removeEventConnection( + const wp<SensorService::SensorEventConnection>& connection) { + mActiveConnections.remove(connection); +} + +void SensorService::SensorConnectionHolder::addDirectConnection( + const sp<SensorService::SensorDirectConnection>& connection) { + mDirectConnections.add(connection); +} + +void SensorService::SensorConnectionHolder::removeDirectConnection( + const wp<SensorService::SensorDirectConnection>& connection) { + mDirectConnections.remove(connection); +} + +SensorService::ConnectionSafeAutolock SensorService::SensorConnectionHolder::lock(Mutex& mutex) { + return ConnectionSafeAutolock(*this, mutex); +} + +} // namespace android diff --git a/services/sensorservice/SensorService.h b/services/sensorservice/SensorService.h index e6ec96dd0a..060b5eba70 100644 --- a/services/sensorservice/SensorService.h +++ b/services/sensorservice/SensorService.h @@ -20,6 +20,7 @@ #include "SensorList.h" #include "RecentEventLogger.h" +#include <android-base/macros.h> #include <binder/AppOpsManager.h> #include <binder/BinderService.h> #include <binder/IUidObserver.h> @@ -42,6 +43,7 @@ #include <sys/types.h> #include <unordered_map> #include <unordered_set> +#include <vector> #if __clang__ // Clang warns about SensorEventConnection::dump hiding BBinder::dump. The cause isn't fixable @@ -95,10 +97,67 @@ private: friend class BinderService<SensorService>; // nested class/struct for internal use - class SensorRecord; + class ConnectionSafeAutolock; + class SensorConnectionHolder; class SensorEventAckReceiver; + class SensorRecord; class SensorRegistrationInfo; + // Promoting a SensorEventConnection or SensorDirectConnection from wp to sp must be done with + // mLock held, but destroying that sp must be done unlocked to avoid a race condition that + // causes a deadlock (remote dies while we hold a local sp, then our decStrong() call invokes + // the dtor -> cleanupConnection() tries to re-lock the mutex). This class ensures safe usage + // by wrapping a Mutex::Autolock on SensorService's mLock, plus vectors that hold promoted sp<> + // references until the lock is released, when they are safely destroyed. + // All read accesses to the connection lists in mConnectionHolder must be done via this class. + class ConnectionSafeAutolock final { + public: + // Returns a list of non-null promoted connection references + const std::vector<sp<SensorEventConnection>>& getActiveConnections(); + const std::vector<sp<SensorDirectConnection>>& getDirectConnections(); + + private: + // Constructed via SensorConnectionHolder::lock() + friend class SensorConnectionHolder; + explicit ConnectionSafeAutolock(SensorConnectionHolder& holder, Mutex& mutex); + DISALLOW_IMPLICIT_CONSTRUCTORS(ConnectionSafeAutolock); + + // NOTE: Order of these members is important, as the destructor for non-static members + // get invoked in the reverse order of their declaration. Here we are relying on the + // Autolock to be destroyed *before* the vectors, so the sp<> objects are destroyed without + // the lock held, which avoids the deadlock. + SensorConnectionHolder& mConnectionHolder; + std::vector<std::vector<sp<SensorEventConnection>>> mReferencedActiveConnections; + std::vector<std::vector<sp<SensorDirectConnection>>> mReferencedDirectConnections; + Mutex::Autolock mAutolock; + + template<typename ConnectionType> + const std::vector<sp<ConnectionType>>& getConnectionsHelper( + const SortedVector<wp<ConnectionType>>& connectionList, + std::vector<std::vector<sp<ConnectionType>>>* referenceHolder); + }; + + // Encapsulates the collection of active SensorEventConection and SensorDirectConnection + // references. Write access is done through this class with mLock held, but all read access + // must be routed through ConnectionSafeAutolock. + class SensorConnectionHolder { + public: + void addEventConnectionIfNotPresent(const sp<SensorEventConnection>& connection); + void removeEventConnection(const wp<SensorEventConnection>& connection); + + void addDirectConnection(const sp<SensorDirectConnection>& connection); + void removeDirectConnection(const wp<SensorDirectConnection>& connection); + + // Pass in the mutex that protects this connection holder; acquires the lock and returns an + // object that can be used to safely read the lists of connections + ConnectionSafeAutolock lock(Mutex& mutex); + + private: + friend class ConnectionSafeAutolock; + SortedVector< wp<SensorEventConnection> > mActiveConnections; + SortedVector< wp<SensorDirectConnection> > mDirectConnections; + }; + // If accessing a sensor we need to make sure the UID has access to it. If // the app UID is idle then it cannot access sensors and gets no trigger // events, no on-change events, flush event behavior does not change, and @@ -250,7 +309,7 @@ private: // method checks whether all the events from these wake up sensors have been delivered to the // corresponding applications, if yes the wakelock is released. void checkWakeLockState(); - void checkWakeLockStateLocked(); + void checkWakeLockStateLocked(ConnectionSafeAutolock* connLock); bool isWakeLockAcquired(); bool isWakeUpSensorEvent(const sensors_event_t& event) const; @@ -268,10 +327,6 @@ private: // Send events from the event cache for this particular connection. void sendEventsFromCache(const sp<SensorEventConnection>& connection); - // Promote all weak referecences in mActiveConnections vector to strong references and add them - // to the output vector. - void populateActiveConnections( SortedVector< sp<SensorEventConnection> >* activeConnections); - // If SensorService is operating in RESTRICTED mode, only select whitelisted packages are // allowed to register for or call flush on sensors. Typically only cts test packages are // allowed. @@ -306,10 +361,10 @@ private: // temporarily stops all active direct connections and disables all sensors void disableAllSensors(); - void disableAllSensorsLocked(); + void disableAllSensorsLocked(ConnectionSafeAutolock* connLock); // restarts the previously stopped direct connections and enables all sensors void enableAllSensors(); - void enableAllSensorsLocked(); + void enableAllSensorsLocked(ConnectionSafeAutolock* connLock); static uint8_t sHmacGlobalKey[128]; static bool sHmacGlobalKeyIsValid; @@ -327,12 +382,13 @@ private: mutable Mutex mLock; DefaultKeyedVector<int, SensorRecord*> mActiveSensors; std::unordered_set<int> mActiveVirtualSensors; - SortedVector< wp<SensorEventConnection> > mActiveConnections; + SensorConnectionHolder mConnectionHolder; bool mWakeLockAcquired; sensors_event_t *mSensorEventBuffer, *mSensorEventScratch; + // WARNING: these SensorEventConnection instances must not be promoted to sp, except via + // modification to add support for them in ConnectionSafeAutolock wp<const SensorEventConnection> * mMapFlushEventsToConnections; std::unordered_map<int, SensorServiceUtil::RecentEventLogger*> mRecentEvent; - SortedVector< wp<SensorDirectConnection> > mDirectConnections; Mode mCurrentOperatingMode; // This packagaName is set when SensorService is in RESTRICTED or DATA_INJECTION mode. Only diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp index 5f07bec4dc..cda982ac23 100644 --- a/services/surfaceflinger/Android.bp +++ b/services/surfaceflinger/Android.bp @@ -149,9 +149,10 @@ filegroup { "Scheduler/LayerHistory.cpp", "Scheduler/LayerInfo.cpp", "Scheduler/MessageQueue.cpp", + "Scheduler/PhaseOffsets.cpp", "Scheduler/Scheduler.cpp", "Scheduler/SchedulerUtils.cpp", - "Scheduler/PhaseOffsets.cpp", + "Scheduler/VSyncModulator.cpp", "StartPropertySetThread.cpp", "SurfaceFlinger.cpp", "SurfaceInterceptor.cpp", diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h index b679380b79..46a62eda91 100644 --- a/services/surfaceflinger/BufferLayer.h +++ b/services/surfaceflinger/BufferLayer.h @@ -48,7 +48,7 @@ namespace android { class BufferLayer : public Layer { public: explicit BufferLayer(const LayerCreationArgs& args); - ~BufferLayer() override; + virtual ~BufferLayer() override; // ----------------------------------------------------------------------- // Overriden from Layer diff --git a/services/surfaceflinger/BufferLayerConsumer.cpp b/services/surfaceflinger/BufferLayerConsumer.cpp index 6709fb4b48..414814a6f4 100644 --- a/services/surfaceflinger/BufferLayerConsumer.cpp +++ b/services/surfaceflinger/BufferLayerConsumer.cpp @@ -369,6 +369,15 @@ const Region& BufferLayerConsumer::getSurfaceDamage() const { return mCurrentSurfaceDamage; } +void BufferLayerConsumer::mergeSurfaceDamage(const Region& damage) { + if (damage.bounds() == Rect::INVALID_RECT || + mCurrentSurfaceDamage.bounds() == Rect::INVALID_RECT) { + mCurrentSurfaceDamage = Region::INVALID_REGION; + } else { + mCurrentSurfaceDamage |= damage; + } +} + int BufferLayerConsumer::getCurrentApi() const { Mutex::Autolock lock(mMutex); return mCurrentApi; @@ -485,7 +494,6 @@ void BufferLayerConsumer::onBufferAvailable(const BufferItem& item) { if (oldImage == nullptr || oldImage->graphicBuffer() == nullptr || oldImage->graphicBuffer()->getId() != item.mGraphicBuffer->getId()) { mImages[item.mSlot] = std::make_shared<Image>(item.mGraphicBuffer, mRE); - mRE.cacheExternalTextureBuffer(item.mGraphicBuffer); } } } @@ -522,6 +530,12 @@ void BufferLayerConsumer::dumpLocked(String8& result, const char* prefix) const ConsumerBase::dumpLocked(result, prefix); } +BufferLayerConsumer::Image::Image(const sp<GraphicBuffer>& graphicBuffer, + renderengine::RenderEngine& engine) + : mGraphicBuffer(graphicBuffer), mRE(engine) { + mRE.cacheExternalTextureBuffer(mGraphicBuffer); +} + BufferLayerConsumer::Image::~Image() { if (mGraphicBuffer != nullptr) { ALOGV("Destroying buffer: %" PRId64, mGraphicBuffer->getId()); diff --git a/services/surfaceflinger/BufferLayerConsumer.h b/services/surfaceflinger/BufferLayerConsumer.h index e3f6100c35..617b1c2323 100644 --- a/services/surfaceflinger/BufferLayerConsumer.h +++ b/services/surfaceflinger/BufferLayerConsumer.h @@ -140,6 +140,9 @@ public: // must be called from SF main thread const Region& getSurfaceDamage() const; + // Merge the given damage region into the current damage region value. + void mergeSurfaceDamage(const Region& damage); + // getCurrentApi retrieves the API which queues the current buffer. int getCurrentApi() const; @@ -220,8 +223,7 @@ private: // Utility class for managing GraphicBuffer references into renderengine class Image { public: - Image(sp<GraphicBuffer> graphicBuffer, renderengine::RenderEngine& engine) - : mGraphicBuffer(graphicBuffer), mRE(engine) {} + Image(const sp<GraphicBuffer>& graphicBuffer, renderengine::RenderEngine& engine); virtual ~Image(); const sp<GraphicBuffer>& graphicBuffer() { return mGraphicBuffer; } diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp index ab7b8ba675..cbb9d658e4 100644 --- a/services/surfaceflinger/BufferQueueLayer.cpp +++ b/services/surfaceflinger/BufferQueueLayer.cpp @@ -317,6 +317,7 @@ status_t BufferQueueLayer::updateTexImage(bool& recomputeVisibleRegions, nsecs_t // and return early if (queuedBuffer) { Mutex::Autolock lock(mQueueItemLock); + mConsumer->mergeSurfaceDamage(mQueueItems[0].mSurfaceDamage); mFlinger->mTimeStats->removeTimeRecord(layerID, mQueueItems[0].mFrameNumber); mQueueItems.removeAt(0); mQueuedFrames--; @@ -352,6 +353,7 @@ status_t BufferQueueLayer::updateTexImage(bool& recomputeVisibleRegions, nsecs_t // Remove any stale buffers that have been dropped during // updateTexImage while (mQueueItems[0].mFrameNumber != currentFrameNumber) { + mConsumer->mergeSurfaceDamage(mQueueItems[0].mSurfaceDamage); mFlinger->mTimeStats->removeTimeRecord(layerID, mQueueItems[0].mFrameNumber); mQueueItems.removeAt(0); mQueuedFrames--; diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp index 203bd72e6f..63a07c35ca 100644 --- a/services/surfaceflinger/BufferStateLayer.cpp +++ b/services/surfaceflinger/BufferStateLayer.cpp @@ -50,8 +50,12 @@ BufferStateLayer::BufferStateLayer(const LayerCreationArgs& args) mOverrideScalingMode = NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW; mCurrentState.dataspace = ui::Dataspace::V0_SRGB; } + BufferStateLayer::~BufferStateLayer() { if (mActiveBuffer != nullptr) { + // Ensure that mActiveBuffer is uncached from RenderEngine here, as + // RenderEngine may have been using the buffer as an external texture + // after the client uncached the buffer. auto& engine(mFlinger->getRenderEngine()); engine.unbindExternalTextureBuffer(mActiveBuffer->getId()); } @@ -571,11 +575,6 @@ status_t BufferStateLayer::updateActiveBuffer() { return BAD_VALUE; } - if (mActiveBuffer != nullptr) { - // todo: get this to work with BufferStateLayerCache - auto& engine(mFlinger->getRenderEngine()); - engine.unbindExternalTextureBuffer(mActiveBuffer->getId()); - } mActiveBuffer = s.buffer; mActiveBufferFence = s.acquireFence; auto& layerCompositionState = getCompositionLayer()->editState().frontEnd; diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h index 4e2bc45287..97e24cb277 100644 --- a/services/surfaceflinger/BufferStateLayer.h +++ b/services/surfaceflinger/BufferStateLayer.h @@ -34,6 +34,7 @@ class SlotGenerationTest; class BufferStateLayer : public BufferLayer { public: explicit BufferStateLayer(const LayerCreationArgs&); + ~BufferStateLayer() override; // ----------------------------------------------------------------------- diff --git a/services/surfaceflinger/ClientCache.cpp b/services/surfaceflinger/ClientCache.cpp index 77f2f5765c..16fe27c00a 100644 --- a/services/surfaceflinger/ClientCache.cpp +++ b/services/surfaceflinger/ClientCache.cpp @@ -55,16 +55,16 @@ bool ClientCache::getBuffer(const client_cache_t& cacheId, return true; } -void ClientCache::add(const client_cache_t& cacheId, const sp<GraphicBuffer>& buffer) { +bool ClientCache::add(const client_cache_t& cacheId, const sp<GraphicBuffer>& buffer) { auto& [processToken, id] = cacheId; if (processToken == nullptr) { ALOGE("failed to cache buffer: invalid process token"); - return; + return false; } if (!buffer) { ALOGE("failed to cache buffer: invalid buffer"); - return; + return false; } std::lock_guard lock(mMutex); @@ -77,13 +77,13 @@ void ClientCache::add(const client_cache_t& cacheId, const sp<GraphicBuffer>& bu token = processToken.promote(); if (!token) { ALOGE("failed to cache buffer: invalid token"); - return; + return false; } status_t err = token->linkToDeath(mDeathRecipient); if (err != NO_ERROR) { ALOGE("failed to cache buffer: could not link to death"); - return; + return false; } auto [itr, success] = mBuffers.emplace(processToken, std::unordered_map<uint64_t, ClientCacheBuffer>()); @@ -95,10 +95,11 @@ void ClientCache::add(const client_cache_t& cacheId, const sp<GraphicBuffer>& bu if (processBuffers.size() > BUFFER_CACHE_MAX_SIZE) { ALOGE("failed to cache buffer: cache is full"); - return; + return false; } processBuffers[id].buffer = buffer; + return true; } void ClientCache::erase(const client_cache_t& cacheId) { @@ -139,16 +140,17 @@ sp<GraphicBuffer> ClientCache::get(const client_cache_t& cacheId) { return buf->buffer; } -void ClientCache::registerErasedRecipient(const client_cache_t& cacheId, +bool ClientCache::registerErasedRecipient(const client_cache_t& cacheId, const wp<ErasedRecipient>& recipient) { std::lock_guard lock(mMutex); ClientCacheBuffer* buf = nullptr; if (!getBuffer(cacheId, &buf)) { ALOGE("failed to register erased recipient, could not retrieve buffer"); - return; + return false; } buf->recipients.insert(recipient); + return true; } void ClientCache::unregisterErasedRecipient(const client_cache_t& cacheId, diff --git a/services/surfaceflinger/ClientCache.h b/services/surfaceflinger/ClientCache.h index 9f057c45d4..aa6c80dfa7 100644 --- a/services/surfaceflinger/ClientCache.h +++ b/services/surfaceflinger/ClientCache.h @@ -36,7 +36,7 @@ class ClientCache : public Singleton<ClientCache> { public: ClientCache(); - void add(const client_cache_t& cacheId, const sp<GraphicBuffer>& buffer); + bool add(const client_cache_t& cacheId, const sp<GraphicBuffer>& buffer); void erase(const client_cache_t& cacheId); sp<GraphicBuffer> get(const client_cache_t& cacheId); @@ -48,7 +48,7 @@ public: virtual void bufferErased(const client_cache_t& clientCacheId) = 0; }; - void registerErasedRecipient(const client_cache_t& cacheId, + bool registerErasedRecipient(const client_cache_t& cacheId, const wp<ErasedRecipient>& recipient); void unregisterErasedRecipient(const client_cache_t& cacheId, const wp<ErasedRecipient>& recipient); diff --git a/services/surfaceflinger/CompositionEngine/Android.bp b/services/surfaceflinger/CompositionEngine/Android.bp index 6f076ad11f..1c31ab9d7d 100644 --- a/services/surfaceflinger/CompositionEngine/Android.bp +++ b/services/surfaceflinger/CompositionEngine/Android.bp @@ -118,6 +118,13 @@ cc_test { // // You can either "make dist tests" before flashing, or set this // option to false temporarily. - address: true, + + + // FIXME: ASAN build is broken for a while, but was not discovered + // since new PM silently suppressed ASAN. Temporarily turn off ASAN + // to unblock the compiler upgrade process. + // address: true, + // http://b/139747256 + address: false, }, } diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp index cc5a5b5729..7f47a2ecd4 100644 --- a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp +++ b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp @@ -24,6 +24,7 @@ #include <composer-command-buffer/2.2/ComposerCommandBuffer.h> #include <gui/BufferQueue.h> +#include <hidl/HidlTransportSupport.h> #include <hidl/HidlTransportUtils.h> namespace android { @@ -229,6 +230,7 @@ std::string Composer::dumpDebugInfo() void Composer::registerCallback(const sp<IComposerCallback>& callback) { + android::hardware::setMinSchedulerPolicy(callback, SCHED_FIFO, 2); auto ret = mClient->registerCallback(callback); if (!ret.isOk()) { ALOGE("failed to register IComposerCallback"); diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index f4284fead7..dda15e9e1e 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -2040,20 +2040,20 @@ InputWindowInfo Layer::fillInputInfo() { InputWindowInfo info = mDrawingState.inputInfo; if (info.displayId == ADISPLAY_ID_NONE) { - info.displayId = mDrawingState.layerStack; + info.displayId = getLayerStack(); } ui::Transform t = getTransform(); const float xScale = t.sx(); const float yScale = t.sy(); - float xSurfaceInset = info.surfaceInset; - float ySurfaceInset = info.surfaceInset; + int32_t xSurfaceInset = info.surfaceInset; + int32_t ySurfaceInset = info.surfaceInset; if (xScale != 1.0f || yScale != 1.0f) { - info.windowXScale *= 1.0f / xScale; - info.windowYScale *= 1.0f / yScale; + info.windowXScale *= (xScale != 0.0f) ? 1.0f / xScale : 0.0f; + info.windowYScale *= (yScale != 0.0f) ? 1.0f / yScale : 0.0f; info.touchableRegion.scaleSelf(xScale, yScale); - xSurfaceInset *= xScale; - ySurfaceInset *= yScale; + xSurfaceInset = std::round(xSurfaceInset * xScale); + ySurfaceInset = std::round(ySurfaceInset * yScale); } // Transform layer size to screen space and inset it by surface insets. @@ -2065,6 +2065,11 @@ InputWindowInfo Layer::fillInputInfo() { layerBounds = getCroppedBufferSize(getDrawingState()); } layerBounds = t.transform(layerBounds); + + // clamp inset to layer bounds + xSurfaceInset = (xSurfaceInset >= 0) ? std::min(xSurfaceInset, layerBounds.getWidth() / 2) : 0; + ySurfaceInset = (ySurfaceInset >= 0) ? std::min(ySurfaceInset, layerBounds.getHeight() / 2) : 0; + layerBounds.inset(xSurfaceInset, ySurfaceInset, xSurfaceInset, ySurfaceInset); // Input coordinate should match the layer bounds. diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 132b4cf03d..3b4d8733c7 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -17,8 +17,6 @@ #ifndef ANDROID_LAYER_H #define ANDROID_LAYER_H -#include <sys/types.h> - #include <compositionengine/LayerFE.h> #include <gui/BufferQueue.h> #include <gui/ISurfaceComposerClient.h> @@ -28,6 +26,7 @@ #include <math/vec4.h> #include <renderengine/Mesh.h> #include <renderengine/Texture.h> +#include <sys/types.h> #include <ui/FloatRect.h> #include <ui/FrameStats.h> #include <ui/GraphicBuffer.h> @@ -44,16 +43,16 @@ #include <vector> #include "Client.h" +#include "ClientCache.h" +#include "DisplayHardware/ComposerHal.h" +#include "DisplayHardware/HWComposer.h" #include "FrameTracker.h" #include "LayerVector.h" #include "MonitoredProducer.h" +#include "RenderArea.h" #include "SurfaceFlinger.h" #include "TransactionCompletedThread.h" -#include "DisplayHardware/ComposerHal.h" -#include "DisplayHardware/HWComposer.h" -#include "RenderArea.h" - using namespace android::surfaceflinger; namespace android { diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp index 66906e950c..07fdead310 100644 --- a/services/surfaceflinger/RegionSamplingThread.cpp +++ b/services/surfaceflinger/RegionSamplingThread.cpp @@ -44,11 +44,14 @@ constexpr auto lumaSamplingStepTag = "LumaSamplingStep"; enum class samplingStep { noWorkNeeded, idleTimerWaiting, + waitForQuietFrame, waitForZeroPhase, waitForSamplePhase, sample }; +constexpr auto timeForRegionSampling = 5000000ns; +constexpr auto maxRegionSamplingSkips = 10; constexpr auto defaultRegionSamplingOffset = -3ms; constexpr auto defaultRegionSamplingPeriod = 100ms; constexpr auto defaultRegionSamplingTimerTimeout = 100ms; @@ -215,9 +218,9 @@ void RegionSamplingThread::removeListener(const sp<IRegionSamplingListener>& lis void RegionSamplingThread::checkForStaleLuma() { std::lock_guard lock(mThreadControlMutex); - if (mDiscardedFrames) { + if (mDiscardedFrames > 0) { ATRACE_INT(lumaSamplingStepTag, static_cast<int>(samplingStep::waitForZeroPhase)); - mDiscardedFrames = false; + mDiscardedFrames = 0; mPhaseCallback->startVsyncListener(); } } @@ -235,13 +238,25 @@ void RegionSamplingThread::doSample() { auto now = std::chrono::nanoseconds(systemTime(SYSTEM_TIME_MONOTONIC)); if (lastSampleTime + mTunables.mSamplingPeriod > now) { ATRACE_INT(lumaSamplingStepTag, static_cast<int>(samplingStep::idleTimerWaiting)); - mDiscardedFrames = true; + if (mDiscardedFrames == 0) mDiscardedFrames++; return; } + if (mDiscardedFrames < maxRegionSamplingSkips) { + // If there is relatively little time left for surfaceflinger + // until the next vsync deadline, defer this sampling work + // to a later frame, when hopefully there will be more time. + DisplayStatInfo stats; + mScheduler.getDisplayStatInfo(&stats); + if (std::chrono::nanoseconds(stats.vsyncTime) - now < timeForRegionSampling) { + ATRACE_INT(lumaSamplingStepTag, static_cast<int>(samplingStep::waitForQuietFrame)); + mDiscardedFrames++; + return; + } + } ATRACE_INT(lumaSamplingStepTag, static_cast<int>(samplingStep::sample)); - mDiscardedFrames = false; + mDiscardedFrames = 0; lastSampleTime = now; mIdleTimer.reset(); @@ -258,7 +273,7 @@ void RegionSamplingThread::binderDied(const wp<IBinder>& who) { namespace { // Using Rec. 709 primaries -float getLuma(float r, float g, float b) { +inline float getLuma(float r, float g, float b) { constexpr auto rec709_red_primary = 0.2126f; constexpr auto rec709_green_primary = 0.7152f; constexpr auto rec709_blue_primary = 0.0722f; @@ -293,10 +308,10 @@ float sampleArea(const uint32_t* data, int32_t width, int32_t height, int32_t st const uint32_t* rowBase = data + row * stride; for (int32_t column = area.left; column < area.right; ++column) { uint32_t pixel = rowBase[column]; - const float r = (pixel & 0xFF) / 255.0f; - const float g = ((pixel >> 8) & 0xFF) / 255.0f; - const float b = ((pixel >> 16) & 0xFF) / 255.0f; - const uint8_t luma = std::round(getLuma(r, g, b) * 255.0f); + const float r = pixel & 0xFF; + const float g = (pixel >> 8) & 0xFF; + const float b = (pixel >> 16) & 0xFF; + const uint8_t luma = std::round(getLuma(r, g, b)); ++brightnessBuckets[luma]; if (brightnessBuckets[luma] > majoritySampleNum) return luma / 255.0f; } @@ -342,9 +357,19 @@ void RegionSamplingThread::captureSample() { } const auto device = mFlinger.getDefaultDisplayDevice(); - const auto display = device->getCompositionDisplay(); - const auto state = display->getState(); - const auto orientation = static_cast<ui::Transform::orientation_flags>(state.orientation); + const auto orientation = [](uint32_t orientation) { + switch (orientation) { + default: + case DisplayState::eOrientationDefault: + return ui::Transform::ROT_0; + case DisplayState::eOrientation90: + return ui::Transform::ROT_90; + case DisplayState::eOrientation180: + return ui::Transform::ROT_180; + case DisplayState::eOrientation270: + return ui::Transform::ROT_270; + } + }(device->getOrientation()); std::vector<RegionSamplingThread::Descriptor> descriptors; Region sampleRegion; diff --git a/services/surfaceflinger/RegionSamplingThread.h b/services/surfaceflinger/RegionSamplingThread.h index 3c6fcf3872..96ffe207e4 100644 --- a/services/surfaceflinger/RegionSamplingThread.h +++ b/services/surfaceflinger/RegionSamplingThread.h @@ -117,7 +117,7 @@ private: std::condition_variable_any mCondition; bool mRunning GUARDED_BY(mThreadControlMutex) = true; bool mSampleRequested GUARDED_BY(mThreadControlMutex) = false; - bool mDiscardedFrames GUARDED_BY(mThreadControlMutex) = false; + uint32_t mDiscardedFrames GUARDED_BY(mThreadControlMutex) = 0; std::chrono::nanoseconds lastSampleTime GUARDED_BY(mThreadControlMutex); std::mutex mSamplingMutex; diff --git a/services/surfaceflinger/Scheduler/DispSync.cpp b/services/surfaceflinger/Scheduler/DispSync.cpp index 95ff9d0c73..0c94052979 100644 --- a/services/surfaceflinger/Scheduler/DispSync.cpp +++ b/services/surfaceflinger/Scheduler/DispSync.cpp @@ -92,9 +92,12 @@ public: mPeriod = period; if (!mModelLocked && referenceTimeChanged) { for (auto& eventListener : mEventListeners) { - eventListener.mHasFired = false; - eventListener.mLastEventTime = - mReferenceTime - mPeriod + mPhase + eventListener.mPhase; + eventListener.mLastEventTime = mReferenceTime + mPhase + eventListener.mPhase; + // If mLastEventTime is after mReferenceTime (can happen when positive phase offsets + // are used) we treat it as like it happened in previous period. + if (eventListener.mLastEventTime > mReferenceTime) { + eventListener.mLastEventTime -= mPeriod; + } } } if (mTraceDetailedInfo) { @@ -123,13 +126,6 @@ public: void unlockModel() { Mutex::Autolock lock(mMutex); - if (mModelLocked) { - for (auto& eventListener : mEventListeners) { - if (eventListener.mLastEventTime > mReferenceTime) { - eventListener.mHasFired = true; - } - } - } mModelLocked = false; ATRACE_INT("DispSync:ModelLocked", mModelLocked); } @@ -259,10 +255,6 @@ public: listener.mLastCallbackTime = lastCallbackTime; } - if (!mModelLocked && listener.mLastEventTime > mReferenceTime) { - listener.mHasFired = true; - } - mEventListeners.push_back(listener); mCond.signal(); @@ -300,12 +292,8 @@ public: // new offset to allow for a seamless offset change without double-firing or // skipping. nsecs_t diff = oldPhase - phase; - if (diff > mPeriod / 2) { - diff -= mPeriod; - } else if (diff < -mPeriod / 2) { - diff += mPeriod; - } eventListener.mLastEventTime -= diff; + eventListener.mLastCallbackTime -= diff; mCond.signal(); return NO_ERROR; } @@ -320,7 +308,6 @@ private: nsecs_t mLastEventTime; nsecs_t mLastCallbackTime; DispSync::Callback* mCallback; - bool mHasFired = false; }; struct CallbackInvocation { @@ -368,12 +355,7 @@ private: eventListener.mName); continue; } - if (eventListener.mHasFired && !mModelLocked) { - eventListener.mLastEventTime = t; - ALOGV("[%s] [%s] Skipping event due to already firing", mName, - eventListener.mName); - continue; - } + CallbackInvocation ci; ci.mCallback = eventListener.mCallback; ci.mEventTime = t; @@ -382,7 +364,6 @@ private: callbackInvocations.push_back(ci); eventListener.mLastEventTime = t; eventListener.mLastCallbackTime = now; - eventListener.mHasFired = true; } } @@ -687,7 +668,13 @@ void DispSync::updateModelLocked() { nsecs_t durationSum = 0; nsecs_t minDuration = INT64_MAX; nsecs_t maxDuration = 0; - for (size_t i = 1; i < mNumResyncSamples; i++) { + // We skip the first 2 samples because the first vsync duration on some + // devices may be much more inaccurate than on other devices, e.g. due + // to delays in ramping up from a power collapse. By doing so this + // actually increases the accuracy of the DispSync model even though + // we're effectively relying on fewer sample points. + static constexpr size_t numSamplesSkipped = 2; + for (size_t i = numSamplesSkipped; i < mNumResyncSamples; i++) { size_t idx = (mFirstResyncSample + i) % MAX_RESYNC_SAMPLES; size_t prev = (idx + MAX_RESYNC_SAMPLES - 1) % MAX_RESYNC_SAMPLES; nsecs_t duration = mResyncSamples[idx] - mResyncSamples[prev]; @@ -698,15 +685,14 @@ void DispSync::updateModelLocked() { // Exclude the min and max from the average durationSum -= minDuration + maxDuration; - mPeriod = durationSum / (mNumResyncSamples - 3); + mPeriod = durationSum / (mNumResyncSamples - numSamplesSkipped - 2); ALOGV("[%s] mPeriod = %" PRId64, mName, ns2us(mPeriod)); double sampleAvgX = 0; double sampleAvgY = 0; double scale = 2.0 * M_PI / double(mPeriod); - // Intentionally skip the first sample - for (size_t i = 1; i < mNumResyncSamples; i++) { + for (size_t i = numSamplesSkipped; i < mNumResyncSamples; i++) { size_t idx = (mFirstResyncSample + i) % MAX_RESYNC_SAMPLES; nsecs_t sample = mResyncSamples[idx] - mReferenceTime; double samplePhase = double(sample % mPeriod) * scale; @@ -714,8 +700,8 @@ void DispSync::updateModelLocked() { sampleAvgY += sin(samplePhase); } - sampleAvgX /= double(mNumResyncSamples - 1); - sampleAvgY /= double(mNumResyncSamples - 1); + sampleAvgX /= double(mNumResyncSamples - numSamplesSkipped); + sampleAvgY /= double(mNumResyncSamples - numSamplesSkipped); mPhase = nsecs_t(atan2(sampleAvgY, sampleAvgX) / scale); diff --git a/services/surfaceflinger/Scheduler/DispSyncSource.cpp b/services/surfaceflinger/Scheduler/DispSyncSource.cpp index 00948aedb4..5faf46e31e 100644 --- a/services/surfaceflinger/Scheduler/DispSyncSource.cpp +++ b/services/surfaceflinger/Scheduler/DispSyncSource.cpp @@ -27,18 +27,23 @@ namespace android { -DispSyncSource::DispSyncSource(DispSync* dispSync, nsecs_t phaseOffset, bool traceVsync, +DispSyncSource::DispSyncSource(DispSync* dispSync, nsecs_t phaseOffset, + nsecs_t offsetThresholdForNextVsync, bool traceVsync, const char* name) : mName(name), mTraceVsync(traceVsync), mVsyncOnLabel(base::StringPrintf("VsyncOn-%s", name)), mVsyncEventLabel(base::StringPrintf("VSYNC-%s", name)), + mVsyncOffsetLabel(base::StringPrintf("VsyncOffset-%s", name)), + mVsyncNegativeOffsetLabel(base::StringPrintf("VsyncNegativeOffset-%s", name)), mDispSync(dispSync), - mPhaseOffset(phaseOffset) {} + mPhaseOffset(phaseOffset), + mOffsetThresholdForNextVsync(offsetThresholdForNextVsync) {} void DispSyncSource::setVSyncEnabled(bool enable) { std::lock_guard lock(mVsyncMutex); if (enable) { + tracePhaseOffset(); status_t err = mDispSync->addEventListener(mName, mPhaseOffset, static_cast<DispSync::Callback*>(this), mLastCallbackTime); @@ -64,16 +69,21 @@ void DispSyncSource::setCallback(VSyncSource::Callback* callback) { void DispSyncSource::setPhaseOffset(nsecs_t phaseOffset) { std::lock_guard lock(mVsyncMutex); + const nsecs_t period = mDispSync->getPeriod(); + // Check if offset should be handled as negative + if (phaseOffset >= mOffsetThresholdForNextVsync) { + phaseOffset -= period; + } - // Normalize phaseOffset to [0, period) - auto period = mDispSync->getPeriod(); - phaseOffset %= period; - if (phaseOffset < 0) { - // If we're here, then phaseOffset is in (-period, 0). After this - // operation, it will be in (0, period) - phaseOffset += period; + // Normalize phaseOffset to [-period, period) + const int numPeriods = phaseOffset / period; + phaseOffset -= numPeriods * period; + if (mPhaseOffset == phaseOffset) { + return; } + mPhaseOffset = phaseOffset; + tracePhaseOffset(); // If we're not enabled, we don't need to mess with the listeners if (!mEnabled) { @@ -92,11 +102,11 @@ void DispSyncSource::onDispSyncEvent(nsecs_t when) { { std::lock_guard lock(mCallbackMutex); callback = mCallback; + } - if (mTraceVsync) { - mValue = (mValue + 1) % 2; - ATRACE_INT(mVsyncEventLabel.c_str(), mValue); - } + if (mTraceVsync) { + mValue = (mValue + 1) % 2; + ATRACE_INT(mVsyncEventLabel.c_str(), mValue); } if (callback != nullptr) { @@ -104,4 +114,14 @@ void DispSyncSource::onDispSyncEvent(nsecs_t when) { } } -} // namespace android
\ No newline at end of file +void DispSyncSource::tracePhaseOffset() { + if (mPhaseOffset > 0) { + ATRACE_INT(mVsyncOffsetLabel.c_str(), mPhaseOffset); + ATRACE_INT(mVsyncNegativeOffsetLabel.c_str(), 0); + } else { + ATRACE_INT(mVsyncOffsetLabel.c_str(), 0); + ATRACE_INT(mVsyncNegativeOffsetLabel.c_str(), -mPhaseOffset); + } +} + +} // namespace android diff --git a/services/surfaceflinger/Scheduler/DispSyncSource.h b/services/surfaceflinger/Scheduler/DispSyncSource.h index 4759699c5e..50560a5a2b 100644 --- a/services/surfaceflinger/Scheduler/DispSyncSource.h +++ b/services/surfaceflinger/Scheduler/DispSyncSource.h @@ -25,7 +25,8 @@ namespace android { class DispSyncSource final : public VSyncSource, private DispSync::Callback { public: - DispSyncSource(DispSync* dispSync, nsecs_t phaseOffset, bool traceVsync, const char* name); + DispSyncSource(DispSync* dispSync, nsecs_t phaseOffset, nsecs_t offsetThresholdForNextVsync, + bool traceVsync, const char* name); ~DispSyncSource() override = default; @@ -38,12 +39,16 @@ private: // The following method is the implementation of the DispSync::Callback. virtual void onDispSyncEvent(nsecs_t when); + void tracePhaseOffset() REQUIRES(mVsyncMutex); + const char* const mName; int mValue = 0; const bool mTraceVsync; const std::string mVsyncOnLabel; const std::string mVsyncEventLabel; + const std::string mVsyncOffsetLabel; + const std::string mVsyncNegativeOffsetLabel; nsecs_t mLastCallbackTime GUARDED_BY(mVsyncMutex) = 0; DispSync* mDispSync; @@ -53,7 +58,8 @@ private: std::mutex mVsyncMutex; nsecs_t mPhaseOffset GUARDED_BY(mVsyncMutex); + const nsecs_t mOffsetThresholdForNextVsync; bool mEnabled GUARDED_BY(mVsyncMutex) = false; }; -} // namespace android
\ No newline at end of file +} // namespace android diff --git a/services/surfaceflinger/Scheduler/EventThread.cpp b/services/surfaceflinger/Scheduler/EventThread.cpp index 05bad4ddd8..9d1f777859 100644 --- a/services/surfaceflinger/Scheduler/EventThread.cpp +++ b/services/surfaceflinger/Scheduler/EventThread.cpp @@ -76,6 +76,10 @@ std::string toString(const DisplayEventReceiver::Event& event) { return StringPrintf("VSync{displayId=%" ANDROID_PHYSICAL_DISPLAY_ID_FORMAT ", count=%u}", event.header.displayId, event.vsync.count); + case DisplayEventReceiver::DISPLAY_EVENT_CONFIG_CHANGED: + return StringPrintf("ConfigChanged{displayId=%" ANDROID_PHYSICAL_DISPLAY_ID_FORMAT + ", configId=%u}", + event.header.displayId, event.config.configId); default: return "Event{}"; } @@ -107,8 +111,10 @@ DisplayEventReceiver::Event makeConfigChanged(PhysicalDisplayId displayId, int32 } // namespace EventThreadConnection::EventThreadConnection(EventThread* eventThread, - ResyncCallback resyncCallback) + ResyncCallback resyncCallback, + ISurfaceComposer::ConfigChanged configChanged) : resyncCallback(std::move(resyncCallback)), + configChanged(configChanged), mEventThread(eventThread), mChannel(gui::BitTube::DefaultSize) {} @@ -203,8 +209,10 @@ void EventThread::setPhaseOffset(nsecs_t phaseOffset) { mVSyncSource->setPhaseOffset(phaseOffset); } -sp<EventThreadConnection> EventThread::createEventConnection(ResyncCallback resyncCallback) const { - return new EventThreadConnection(const_cast<EventThread*>(this), std::move(resyncCallback)); +sp<EventThreadConnection> EventThread::createEventConnection( + ResyncCallback resyncCallback, ISurfaceComposer::ConfigChanged configChanged) const { + return new EventThreadConnection(const_cast<EventThread*>(this), std::move(resyncCallback), + configChanged); } status_t EventThread::registerDisplayEventConnection(const sp<EventThreadConnection>& connection) { @@ -398,9 +406,11 @@ bool EventThread::shouldConsumeEvent(const DisplayEventReceiver::Event& event, const sp<EventThreadConnection>& connection) const { switch (event.header.type) { case DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG: - case DisplayEventReceiver::DISPLAY_EVENT_CONFIG_CHANGED: return true; + case DisplayEventReceiver::DISPLAY_EVENT_CONFIG_CHANGED: + return connection->configChanged == ISurfaceComposer::eConfigChangedDispatch; + case DisplayEventReceiver::DISPLAY_EVENT_VSYNC: switch (connection->vsyncRequest) { case VSyncRequest::None: diff --git a/services/surfaceflinger/Scheduler/EventThread.h b/services/surfaceflinger/Scheduler/EventThread.h index 61530c62e5..dd23b88726 100644 --- a/services/surfaceflinger/Scheduler/EventThread.h +++ b/services/surfaceflinger/Scheduler/EventThread.h @@ -69,7 +69,8 @@ public: class EventThreadConnection : public BnDisplayEventConnection { public: - EventThreadConnection(EventThread*, ResyncCallback); + EventThreadConnection(EventThread*, ResyncCallback, + ISurfaceComposer::ConfigChanged configChanged); virtual ~EventThreadConnection(); virtual status_t postEvent(const DisplayEventReceiver::Event& event); @@ -82,6 +83,7 @@ public: const ResyncCallback resyncCallback; VSyncRequest vsyncRequest = VSyncRequest::None; + const ISurfaceComposer::ConfigChanged configChanged; private: virtual void onFirstRef(); @@ -93,7 +95,8 @@ class EventThread { public: virtual ~EventThread(); - virtual sp<EventThreadConnection> createEventConnection(ResyncCallback) const = 0; + virtual sp<EventThreadConnection> createEventConnection( + ResyncCallback, ISurfaceComposer::ConfigChanged configChanged) const = 0; // called before the screen is turned off from main thread virtual void onScreenReleased() = 0; @@ -128,7 +131,8 @@ public: EventThread(std::unique_ptr<VSyncSource>, InterceptVSyncsCallback, const char* threadName); ~EventThread(); - sp<EventThreadConnection> createEventConnection(ResyncCallback) const override; + sp<EventThreadConnection> createEventConnection( + ResyncCallback, ISurfaceComposer::ConfigChanged configChanged) const override; status_t registerDisplayEventConnection(const sp<EventThreadConnection>& connection) override; void setVsyncRate(uint32_t rate, const sp<EventThreadConnection>& connection) override; diff --git a/services/surfaceflinger/Scheduler/LayerHistory.cpp b/services/surfaceflinger/Scheduler/LayerHistory.cpp index 1db43a32cd..f80c2336f7 100644 --- a/services/surfaceflinger/Scheduler/LayerHistory.cpp +++ b/services/surfaceflinger/Scheduler/LayerHistory.cpp @@ -46,11 +46,13 @@ LayerHistory::LayerHistory() { LayerHistory::~LayerHistory() = default; std::unique_ptr<LayerHistory::LayerHandle> LayerHistory::createLayer(const std::string name, + float minRefreshRate, float maxRefreshRate) { const int64_t id = sNextId++; std::lock_guard lock(mLock); - mInactiveLayerInfos.emplace(id, std::make_shared<LayerInfo>(name, maxRefreshRate)); + mInactiveLayerInfos.emplace(id, + std::make_shared<LayerInfo>(name, minRefreshRate, maxRefreshRate)); return std::make_unique<LayerHistory::LayerHandle>(*this, id); } @@ -173,5 +175,18 @@ void LayerHistory::removeIrrelevantLayers() { } } +void LayerHistory::clearHistory() { + std::lock_guard lock(mLock); + + auto it = mActiveLayerInfos.begin(); + while (it != mActiveLayerInfos.end()) { + auto id = it->first; + auto layerInfo = it->second; + layerInfo->clearHistory(); + mInactiveLayerInfos.insert({id, layerInfo}); + it = mActiveLayerInfos.erase(it); + } +} + } // namespace scheduler } // namespace android
\ No newline at end of file diff --git a/services/surfaceflinger/Scheduler/LayerHistory.h b/services/surfaceflinger/Scheduler/LayerHistory.h index adc5ce5f64..5598cc1cf5 100644 --- a/services/surfaceflinger/Scheduler/LayerHistory.h +++ b/services/surfaceflinger/Scheduler/LayerHistory.h @@ -53,7 +53,8 @@ public: ~LayerHistory(); // When the layer is first created, register it. - std::unique_ptr<LayerHandle> createLayer(const std::string name, float maxRefreshRate); + std::unique_ptr<LayerHandle> createLayer(const std::string name, float minRefreshRate, + float maxRefreshRate); // Method for inserting layers and their requested present time into the unordered map. void insert(const std::unique_ptr<LayerHandle>& layerHandle, nsecs_t presentTime, bool isHdr); @@ -64,6 +65,9 @@ public: // layers. See go/content-fps-detection-in-scheduler for more information. std::pair<float, bool> getDesiredRefreshRateAndHDR(); + // Clears all layer history. + void clearHistory(); + // Removes the handle and the object from the map. void destroyLayer(const int64_t id); diff --git a/services/surfaceflinger/Scheduler/LayerInfo.cpp b/services/surfaceflinger/Scheduler/LayerInfo.cpp index 95d7d31564..723d71ff39 100644 --- a/services/surfaceflinger/Scheduler/LayerInfo.cpp +++ b/services/surfaceflinger/Scheduler/LayerInfo.cpp @@ -24,9 +24,10 @@ namespace android { namespace scheduler { -LayerInfo::LayerInfo(const std::string name, float maxRefreshRate) +LayerInfo::LayerInfo(const std::string name, float minRefreshRate, float maxRefreshRate) : mName(name), mMinRefreshDuration(1e9f / maxRefreshRate), + mLowActivityRefreshDuration(1e9f / minRefreshRate), mRefreshRateHistory(mMinRefreshDuration) {} LayerInfo::~LayerInfo() = default; @@ -38,12 +39,19 @@ void LayerInfo::setLastPresentTime(nsecs_t lastPresentTime) { mLastUpdatedTime = std::max(lastPresentTime, systemTime()); mPresentTimeHistory.insertPresentTime(mLastUpdatedTime); + if (mLastPresentTime == 0) { + // First frame + mLastPresentTime = lastPresentTime; + return; + } + const nsecs_t timeDiff = lastPresentTime - mLastPresentTime; mLastPresentTime = lastPresentTime; // Ignore time diff that are too high - those are stale values - if (timeDiff > TIME_EPSILON_NS.count()) return; - const nsecs_t refreshDuration = (timeDiff > 0) ? timeDiff : mMinRefreshDuration; - mRefreshRateHistory.insertRefreshRate(refreshDuration); + if (timeDiff > OBSOLETE_TIME_EPSILON_NS.count()) return; + const nsecs_t refreshDuration = std::max(timeDiff, mMinRefreshDuration); + const int fps = 1e9f / refreshDuration; + mRefreshRateHistory.insertRefreshRate(fps); } } // namespace scheduler diff --git a/services/surfaceflinger/Scheduler/LayerInfo.h b/services/surfaceflinger/Scheduler/LayerInfo.h index 02b6aefa2b..17afddac28 100644 --- a/services/surfaceflinger/Scheduler/LayerInfo.h +++ b/services/surfaceflinger/Scheduler/LayerInfo.h @@ -46,7 +46,7 @@ class LayerInfo { public: explicit RefreshRateHistory(nsecs_t minRefreshDuration) : mMinRefreshDuration(minRefreshDuration) {} - void insertRefreshRate(nsecs_t refreshRate) { + void insertRefreshRate(int refreshRate) { mElements.push_back(refreshRate); if (mElements.size() > HISTORY_SIZE) { mElements.pop_front(); @@ -54,13 +54,13 @@ class LayerInfo { } float getRefreshRateAvg() const { - nsecs_t refreshDuration = mMinRefreshDuration; - if (mElements.size() == HISTORY_SIZE) { - refreshDuration = scheduler::calculate_mean(mElements); + if (mElements.empty()) { + return 1e9f / mMinRefreshDuration; } - return 1e9f / refreshDuration; + return scheduler::calculate_mean(mElements); } + void clearHistory() { mElements.clear(); } private: @@ -86,13 +86,43 @@ class LayerInfo { // Checks whether the present time that was inserted HISTORY_SIZE ago is within a // certain threshold: TIME_EPSILON_NS. bool isRelevant() const { - const int64_t obsoleteEpsilon = systemTime() - scheduler::TIME_EPSILON_NS.count(); - // The layer had to publish at least HISTORY_SIZE of updates, and the first - // update should not be older than TIME_EPSILON_NS nanoseconds. - if (mElements.size() == HISTORY_SIZE && - mElements.at(HISTORY_SIZE - 1) > obsoleteEpsilon) { + if (mElements.size() < 2) { + return false; + } + + // The layer had to publish at least HISTORY_SIZE or HISTORY_TIME of updates + if (mElements.size() != HISTORY_SIZE && + mElements.at(mElements.size() - 1) - mElements.at(0) < HISTORY_TIME.count()) { + return false; + } + + // The last update should not be older than OBSOLETE_TIME_EPSILON_NS nanoseconds. + const int64_t obsoleteEpsilon = + systemTime() - scheduler::OBSOLETE_TIME_EPSILON_NS.count(); + if (mElements.at(mElements.size() - 1) < obsoleteEpsilon) { + return false; + } + + return true; + } + + bool isLowActivityLayer() const { + // We want to make sure that we received more than two frames from the layer + // in order to check low activity. + if (mElements.size() < scheduler::LOW_ACTIVITY_BUFFERS + 1) { + return false; + } + + const int64_t obsoleteEpsilon = + systemTime() - scheduler::LOW_ACTIVITY_EPSILON_NS.count(); + // Check the frame before last to determine whether there is low activity. + // If that frame is older than LOW_ACTIVITY_EPSILON_NS, the layer is sending + // infrequent updates. + if (mElements.at(mElements.size() - (scheduler::LOW_ACTIVITY_BUFFERS + 1)) < + obsoleteEpsilon) { return true; } + return false; } @@ -100,11 +130,12 @@ class LayerInfo { private: std::deque<nsecs_t> mElements; - static constexpr size_t HISTORY_SIZE = 10; + static constexpr size_t HISTORY_SIZE = 90; + static constexpr std::chrono::nanoseconds HISTORY_TIME = 1s; }; public: - LayerInfo(const std::string name, float maxRefreshRate); + LayerInfo(const std::string name, float minRefreshRate, float maxRefreshRate); ~LayerInfo(); LayerInfo(const LayerInfo&) = delete; @@ -134,6 +165,10 @@ public: // Calculate the average refresh rate. float getDesiredRefreshRate() const { std::lock_guard lock(mLock); + + if (mPresentTimeHistory.isLowActivityLayer()) { + return 1e9f / mLowActivityRefreshDuration; + } return mRefreshRateHistory.getRefreshRateAvg(); } @@ -165,6 +200,7 @@ public: private: const std::string mName; const nsecs_t mMinRefreshDuration; + const nsecs_t mLowActivityRefreshDuration; mutable std::mutex mLock; nsecs_t mLastUpdatedTime GUARDED_BY(mLock) = 0; nsecs_t mLastPresentTime GUARDED_BY(mLock) = 0; diff --git a/services/surfaceflinger/Scheduler/MessageQueue.cpp b/services/surfaceflinger/Scheduler/MessageQueue.cpp index baf900df52..fcb307f213 100644 --- a/services/surfaceflinger/Scheduler/MessageQueue.cpp +++ b/services/surfaceflinger/Scheduler/MessageQueue.cpp @@ -96,7 +96,8 @@ void MessageQueue::setEventThread(android::EventThread* eventThread, } mEventThread = eventThread; - mEvents = eventThread->createEventConnection(std::move(resyncCallback)); + mEvents = eventThread->createEventConnection(std::move(resyncCallback), + ISurfaceComposer::eConfigChangedSuppress); mEvents->stealReceiveChannel(&mEventTube); mLooper->addFd(mEventTube.getFd(), 0, Looper::EVENT_INPUT, MessageQueue::cb_eventReceiver, this); diff --git a/services/surfaceflinger/Scheduler/PhaseOffsets.cpp b/services/surfaceflinger/Scheduler/PhaseOffsets.cpp index 276bce1f89..8a2604f4a3 100644 --- a/services/surfaceflinger/Scheduler/PhaseOffsets.cpp +++ b/services/surfaceflinger/Scheduler/PhaseOffsets.cpp @@ -25,6 +25,7 @@ using namespace android::sysprop; namespace scheduler { +using RefreshRateType = RefreshRateConfigs::RefreshRateType; PhaseOffsets::~PhaseOffsets() = default; namespace impl { @@ -72,25 +73,32 @@ PhaseOffsets::PhaseOffsets() { property_get("debug.sf.phase_offset_threshold_for_next_vsync_ns", value, "-1"); const int phaseOffsetThresholdForNextVsyncNs = atoi(value); - mDefaultRefreshRateOffsets.early = {earlySfOffsetNs != -1 ? earlySfOffsetNs - : sfVsyncPhaseOffsetNs, - earlyAppOffsetNs != -1 ? earlyAppOffsetNs - : vsyncPhaseOffsetNs}; - mDefaultRefreshRateOffsets.earlyGl = {earlyGlSfOffsetNs != -1 ? earlyGlSfOffsetNs - : sfVsyncPhaseOffsetNs, - earlyGlAppOffsetNs != -1 ? earlyGlAppOffsetNs - : vsyncPhaseOffsetNs}; - mDefaultRefreshRateOffsets.late = {sfVsyncPhaseOffsetNs, vsyncPhaseOffsetNs}; - - mHighRefreshRateOffsets.early = {highFpsEarlySfOffsetNs != -1 ? highFpsEarlySfOffsetNs - : highFpsLateSfOffsetNs, - highFpsEarlyAppOffsetNs != -1 ? highFpsEarlyAppOffsetNs - : highFpsLateAppOffsetNs}; - mHighRefreshRateOffsets.earlyGl = {highFpsEarlyGlSfOffsetNs != -1 ? highFpsEarlyGlSfOffsetNs - : highFpsLateSfOffsetNs, - highFpsEarlyGlAppOffsetNs != -1 ? highFpsEarlyGlAppOffsetNs - : highFpsLateAppOffsetNs}; - mHighRefreshRateOffsets.late = {highFpsLateSfOffsetNs, highFpsLateAppOffsetNs}; + Offsets defaultOffsets; + Offsets highFpsOffsets; + defaultOffsets.early = {RefreshRateType::DEFAULT, + earlySfOffsetNs != -1 ? earlySfOffsetNs : sfVsyncPhaseOffsetNs, + earlyAppOffsetNs != -1 ? earlyAppOffsetNs : vsyncPhaseOffsetNs}; + defaultOffsets.earlyGl = {RefreshRateType::DEFAULT, + earlyGlSfOffsetNs != -1 ? earlyGlSfOffsetNs : sfVsyncPhaseOffsetNs, + earlyGlAppOffsetNs != -1 ? earlyGlAppOffsetNs : vsyncPhaseOffsetNs}; + defaultOffsets.late = {RefreshRateType::DEFAULT, sfVsyncPhaseOffsetNs, vsyncPhaseOffsetNs}; + + highFpsOffsets.early = {RefreshRateType::PERFORMANCE, + highFpsEarlySfOffsetNs != -1 ? highFpsEarlySfOffsetNs + : highFpsLateSfOffsetNs, + highFpsEarlyAppOffsetNs != -1 ? highFpsEarlyAppOffsetNs + : highFpsLateAppOffsetNs}; + highFpsOffsets.earlyGl = {RefreshRateType::PERFORMANCE, + highFpsEarlyGlSfOffsetNs != -1 ? highFpsEarlyGlSfOffsetNs + : highFpsLateSfOffsetNs, + highFpsEarlyGlAppOffsetNs != -1 ? highFpsEarlyGlAppOffsetNs + : highFpsLateAppOffsetNs}; + highFpsOffsets.late = {RefreshRateType::PERFORMANCE, highFpsLateSfOffsetNs, + highFpsLateAppOffsetNs}; + + mOffsets.insert({RefreshRateType::POWER_SAVING, defaultOffsets}); + mOffsets.insert({RefreshRateType::DEFAULT, defaultOffsets}); + mOffsets.insert({RefreshRateType::PERFORMANCE, highFpsOffsets}); mOffsetThresholdForNextVsync = phaseOffsetThresholdForNextVsyncNs != -1 ? phaseOffsetThresholdForNextVsyncNs @@ -99,12 +107,7 @@ PhaseOffsets::PhaseOffsets() { PhaseOffsets::Offsets PhaseOffsets::getOffsetsForRefreshRate( android::scheduler::RefreshRateConfigs::RefreshRateType refreshRateType) const { - switch (refreshRateType) { - case RefreshRateConfigs::RefreshRateType::PERFORMANCE: - return mHighRefreshRateOffsets; - default: - return mDefaultRefreshRateOffsets; - } + return mOffsets.at(refreshRateType); } void PhaseOffsets::dump(std::string& result) const { diff --git a/services/surfaceflinger/Scheduler/PhaseOffsets.h b/services/surfaceflinger/Scheduler/PhaseOffsets.h index dc71e6eb60..2b5c2f10f1 100644 --- a/services/surfaceflinger/Scheduler/PhaseOffsets.h +++ b/services/surfaceflinger/Scheduler/PhaseOffsets.h @@ -17,6 +17,7 @@ #pragma once #include <cinttypes> +#include <unordered_map> #include "RefreshRateConfigs.h" #include "VSyncModulator.h" @@ -79,14 +80,10 @@ public: void dump(std::string& result) const override; private: - Offsets getDefaultRefreshRateOffsets() { return mDefaultRefreshRateOffsets; } - Offsets getHighRefreshRateOffsets() { return mHighRefreshRateOffsets; } - std::atomic<RefreshRateConfigs::RefreshRateType> mRefreshRateType = RefreshRateConfigs::RefreshRateType::DEFAULT; - Offsets mDefaultRefreshRateOffsets; - Offsets mHighRefreshRateOffsets; + std::unordered_map<RefreshRateConfigs::RefreshRateType, Offsets> mOffsets; nsecs_t mOffsetThresholdForNextVsync; }; } // namespace impl diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp index 1d899dfbad..8da5612b5b 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.cpp +++ b/services/surfaceflinger/Scheduler/Scheduler.cpp @@ -76,6 +76,7 @@ Scheduler::Scheduler(impl::EventControlThread::SetVSyncEnabledFunction function, mSupportKernelTimer = support_kernel_idle_timer(false); mSetTouchTimerMs = set_touch_timer_ms(0); + mSetDisplayPowerTimerMs = set_display_power_timer_ms(0); char value[PROPERTY_VALUE_MAX]; property_get("debug.sf.set_idle_timer_ms", value, "0"); @@ -110,26 +111,40 @@ Scheduler::Scheduler(impl::EventControlThread::SetVSyncEnabledFunction function, [this] { expiredTouchTimerCallback(); }); mTouchTimer->start(); } + + if (mSetDisplayPowerTimerMs > 0) { + mDisplayPowerTimer = + std::make_unique<scheduler::IdleTimer>(std::chrono::milliseconds( + mSetDisplayPowerTimerMs), + [this] { resetDisplayPowerTimerCallback(); }, + [this] { + expiredDisplayPowerTimerCallback(); + }); + mDisplayPowerTimer->start(); + } } Scheduler::~Scheduler() { // Ensure the IdleTimer thread is joined before we start destroying state. + mDisplayPowerTimer.reset(); mTouchTimer.reset(); mIdleTimer.reset(); } sp<Scheduler::ConnectionHandle> Scheduler::createConnection( - const char* connectionName, int64_t phaseOffsetNs, ResyncCallback resyncCallback, + const char* connectionName, nsecs_t phaseOffsetNs, nsecs_t offsetThresholdForNextVsync, + ResyncCallback resyncCallback, impl::EventThread::InterceptVSyncsCallback interceptCallback) { const int64_t id = sNextId++; ALOGV("Creating a connection handle with ID: %" PRId64 "\n", id); std::unique_ptr<EventThread> eventThread = makeEventThread(connectionName, mPrimaryDispSync.get(), phaseOffsetNs, - std::move(interceptCallback)); + offsetThresholdForNextVsync, std::move(interceptCallback)); auto eventThreadConnection = - createConnectionInternal(eventThread.get(), std::move(resyncCallback)); + createConnectionInternal(eventThread.get(), std::move(resyncCallback), + ISurfaceComposer::eConfigChangedSuppress); mConnections.emplace(id, std::make_unique<Connection>(new ConnectionHandle(id), eventThreadConnection, @@ -138,24 +153,28 @@ sp<Scheduler::ConnectionHandle> Scheduler::createConnection( } std::unique_ptr<EventThread> Scheduler::makeEventThread( - const char* connectionName, DispSync* dispSync, int64_t phaseOffsetNs, + const char* connectionName, DispSync* dispSync, nsecs_t phaseOffsetNs, + nsecs_t offsetThresholdForNextVsync, impl::EventThread::InterceptVSyncsCallback interceptCallback) { std::unique_ptr<VSyncSource> eventThreadSource = - std::make_unique<DispSyncSource>(dispSync, phaseOffsetNs, true, connectionName); + std::make_unique<DispSyncSource>(dispSync, phaseOffsetNs, offsetThresholdForNextVsync, + true, connectionName); return std::make_unique<impl::EventThread>(std::move(eventThreadSource), std::move(interceptCallback), connectionName); } -sp<EventThreadConnection> Scheduler::createConnectionInternal(EventThread* eventThread, - ResyncCallback&& resyncCallback) { - return eventThread->createEventConnection(std::move(resyncCallback)); +sp<EventThreadConnection> Scheduler::createConnectionInternal( + EventThread* eventThread, ResyncCallback&& resyncCallback, + ISurfaceComposer::ConfigChanged configChanged) { + return eventThread->createEventConnection(std::move(resyncCallback), configChanged); } sp<IDisplayEventConnection> Scheduler::createDisplayEventConnection( - const sp<Scheduler::ConnectionHandle>& handle, ResyncCallback resyncCallback) { + const sp<Scheduler::ConnectionHandle>& handle, ResyncCallback resyncCallback, + ISurfaceComposer::ConfigChanged configChanged) { RETURN_VALUE_IF_INVALID(nullptr); return createConnectionInternal(mConnections[handle->id]->thread.get(), - std::move(resyncCallback)); + std::move(resyncCallback), configChanged); } EventThread* Scheduler::getEventThread(const sp<Scheduler::ConnectionHandle>& handle) { @@ -255,7 +274,7 @@ ResyncCallback Scheduler::makeResyncCallback(GetVsyncPeriod&& getVsyncPeriod) { } void Scheduler::VsyncState::resync(const GetVsyncPeriod& getVsyncPeriod) { - static constexpr nsecs_t kIgnoreDelay = ms2ns(500); + static constexpr nsecs_t kIgnoreDelay = ms2ns(750); const nsecs_t now = systemTime(); const nsecs_t last = lastResyncTime.exchange(now); @@ -324,8 +343,11 @@ std::unique_ptr<scheduler::LayerHistory::LayerHandle> Scheduler::registerLayer( : RefreshRateType::PERFORMANCE; const auto refreshRate = mRefreshRateConfigs.getRefreshRate(refreshRateType); - const uint32_t fps = (refreshRate) ? refreshRate->fps : 0; - return mLayerHistory.createLayer(name, fps); + const uint32_t performanceFps = (refreshRate) ? refreshRate->fps : 0; + + const auto defaultRefreshRate = mRefreshRateConfigs.getRefreshRate(RefreshRateType::DEFAULT); + const uint32_t defaultFps = (defaultRefreshRate) ? defaultRefreshRate->fps : 0; + return mLayerHistory.createLayer(name, defaultFps, performanceFps); } void Scheduler::addLayerPresentTimeAndHDR( @@ -371,11 +393,17 @@ void Scheduler::updateFpsBasedOnContent() { } void Scheduler::setChangeRefreshRateCallback( - const ChangeRefreshRateCallback& changeRefreshRateCallback) { + const ChangeRefreshRateCallback&& changeRefreshRateCallback) { std::lock_guard<std::mutex> lock(mCallbackLock); mChangeRefreshRateCallback = changeRefreshRateCallback; } +void Scheduler::setGetCurrentRefreshRateTypeCallback( + const GetCurrentRefreshRateTypeCallback&& getCurrentRefreshRateTypeCallback) { + std::lock_guard<std::mutex> lock(mCallbackLock); + mGetCurrentRefreshRateTypeCallback = getCurrentRefreshRateTypeCallback; +} + void Scheduler::setGetVsyncPeriodCallback(const GetVsyncPeriod&& getVsyncPeriod) { std::lock_guard<std::mutex> lock(mCallbackLock); mGetVsyncPeriod = getVsyncPeriod; @@ -404,43 +432,81 @@ void Scheduler::notifyTouchEvent() { if (mSupportKernelTimer) { resetIdleTimer(); } + + // Touch event will boost the refresh rate to performance. + // Clear Layer History to get fresh FPS detection + mLayerHistory.clearHistory(); +} + +void Scheduler::setDisplayPowerState(bool normal) { + { + std::lock_guard<std::mutex> lock(mFeatureStateLock); + mIsDisplayPowerStateNormal = normal; + } + + if (mDisplayPowerTimer) { + mDisplayPowerTimer->reset(); + } + + // Display Power event will boost the refresh rate to performance. + // Clear Layer History to get fresh FPS detection + mLayerHistory.clearHistory(); } void Scheduler::resetTimerCallback() { - timerChangeRefreshRate(IdleTimerState::RESET); + handleTimerStateChanged(&mCurrentIdleTimerState, IdleTimerState::RESET, false); ATRACE_INT("ExpiredIdleTimer", 0); } void Scheduler::resetKernelTimerCallback() { ATRACE_INT("ExpiredKernelIdleTimer", 0); std::lock_guard<std::mutex> lock(mCallbackLock); - if (mGetVsyncPeriod) { - resyncToHardwareVsync(true, mGetVsyncPeriod()); + if (mGetVsyncPeriod && mGetCurrentRefreshRateTypeCallback) { + // If we're not in performance mode then the kernel timer shouldn't do + // anything, as the refresh rate during DPU power collapse will be the + // same. + if (mGetCurrentRefreshRateTypeCallback() == Scheduler::RefreshRateType::PERFORMANCE) { + resyncToHardwareVsync(true, mGetVsyncPeriod()); + } } } void Scheduler::expiredTimerCallback() { - timerChangeRefreshRate(IdleTimerState::EXPIRED); + handleTimerStateChanged(&mCurrentIdleTimerState, IdleTimerState::EXPIRED, false); ATRACE_INT("ExpiredIdleTimer", 1); } void Scheduler::resetTouchTimerCallback() { - // We do not notify the applications about config changes when idle timer is reset. - touchChangeRefreshRate(TouchState::ACTIVE); + handleTimerStateChanged(&mCurrentTouchState, TouchState::ACTIVE, true); ATRACE_INT("TouchState", 1); } void Scheduler::expiredTouchTimerCallback() { - // We do not notify the applications about config changes when idle timer expires. - touchChangeRefreshRate(TouchState::INACTIVE); + handleTimerStateChanged(&mCurrentTouchState, TouchState::INACTIVE, true); ATRACE_INT("TouchState", 0); } +void Scheduler::resetDisplayPowerTimerCallback() { + handleTimerStateChanged(&mDisplayPowerTimerState, DisplayPowerTimerState::RESET, true); + ATRACE_INT("ExpiredDisplayPowerTimer", 0); +} + +void Scheduler::expiredDisplayPowerTimerCallback() { + handleTimerStateChanged(&mDisplayPowerTimerState, DisplayPowerTimerState::EXPIRED, true); + ATRACE_INT("ExpiredDisplayPowerTimer", 1); +} + void Scheduler::expiredKernelTimerCallback() { + std::lock_guard<std::mutex> lock(mCallbackLock); ATRACE_INT("ExpiredKernelIdleTimer", 1); - // Disable HW Vsync if the timer expired, as we don't need it - // enabled if we're not pushing frames. - disableHardwareVsync(false); + if (mGetCurrentRefreshRateTypeCallback) { + if (mGetCurrentRefreshRateTypeCallback() != Scheduler::RefreshRateType::PERFORMANCE) { + // Disable HW Vsync if the timer expired, as we don't need it + // enabled if we're not pushing frames, and if we're in PERFORMANCE + // mode then we'll need to re-update the DispSync model anyways. + disableHardwareVsync(false); + } + } } std::string Scheduler::doDump() { @@ -450,39 +516,23 @@ std::string Scheduler::doDump() { return stream.str(); } -void Scheduler::timerChangeRefreshRate(IdleTimerState idleTimerState) { - RefreshRateType newRefreshRateType; - { - std::lock_guard<std::mutex> lock(mFeatureStateLock); - if (mCurrentIdleTimerState == idleTimerState) { - return; - } - mCurrentIdleTimerState = idleTimerState; - newRefreshRateType = calculateRefreshRateType(); - if (mRefreshRateType == newRefreshRateType) { - return; - } - mRefreshRateType = newRefreshRateType; - } - changeRefreshRate(newRefreshRateType, ConfigEvent::None); -} - -void Scheduler::touchChangeRefreshRate(TouchState touchState) { +template <class T> +void Scheduler::handleTimerStateChanged(T* currentState, T newState, bool eventOnContentDetection) { ConfigEvent event = ConfigEvent::None; RefreshRateType newRefreshRateType; { std::lock_guard<std::mutex> lock(mFeatureStateLock); - if (mCurrentTouchState == touchState) { + if (*currentState == newState) { return; } - mCurrentTouchState = touchState; + *currentState = newState; newRefreshRateType = calculateRefreshRateType(); if (mRefreshRateType == newRefreshRateType) { return; } mRefreshRateType = newRefreshRateType; - // Send an event in case that content detection is on as touch has a higher priority - if (mCurrentContentFeatureState == ContentFeatureState::CONTENT_DETECTION_ON) { + if (eventOnContentDetection && + mCurrentContentFeatureState == ContentFeatureState::CONTENT_DETECTION_ON) { event = ConfigEvent::Changed; } } @@ -495,6 +545,12 @@ Scheduler::RefreshRateType Scheduler::calculateRefreshRateType() { return RefreshRateType::DEFAULT; } + // If Display Power is not in normal operation we want to be in performance mode. + // When coming back to normal mode, a grace period is given with DisplayPowerTimer + if (!mIsDisplayPowerStateNormal || mDisplayPowerTimerState == DisplayPowerTimerState::RESET) { + return RefreshRateType::PERFORMANCE; + } + // As long as touch is active we want to be in performance mode if (mCurrentTouchState == TouchState::ACTIVE) { return RefreshRateType::PERFORMANCE; @@ -510,22 +566,24 @@ Scheduler::RefreshRateType Scheduler::calculateRefreshRateType() { return RefreshRateType::PERFORMANCE; } - // Content detection is on, find the appropriate refresh rate - // Start with the smallest refresh rate which is within a margin of the content - RefreshRateType currRefreshRateType = RefreshRateType::PERFORMANCE; - constexpr float MARGIN = 0.05f; - auto iter = mRefreshRateConfigs.getRefreshRates().cbegin(); - while (iter != mRefreshRateConfigs.getRefreshRates().cend()) { - if (iter->second->fps >= mContentRefreshRate * (1 - MARGIN)) { - currRefreshRateType = iter->first; - break; - } - ++iter; + // Content detection is on, find the appropriate refresh rate with minimal error + auto begin = mRefreshRateConfigs.getRefreshRates().cbegin(); + + // Skip POWER_SAVING config as it is not a real config + if (begin->first == RefreshRateType::POWER_SAVING) { + ++begin; } + auto iter = min_element(begin, mRefreshRateConfigs.getRefreshRates().cend(), + [rate = mContentRefreshRate](const auto& l, const auto& r) -> bool { + return std::abs(l.second->fps - static_cast<float>(rate)) < + std::abs(r.second->fps - static_cast<float>(rate)); + }); + RefreshRateType currRefreshRateType = iter->first; // Some content aligns better on higher refresh rate. For example for 45fps we should choose // 90Hz config. However we should still prefer a lower refresh rate if the content doesn't // align well with both + constexpr float MARGIN = 0.05f; float ratio = mRefreshRateConfigs.getRefreshRate(currRefreshRateType)->fps / float(mContentRefreshRate); if (std::abs(std::round(ratio) - ratio) > MARGIN) { diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h index a32bd4142d..5d8bb4cd2f 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.h +++ b/services/surfaceflinger/Scheduler/Scheduler.h @@ -49,6 +49,7 @@ public: } using RefreshRateType = scheduler::RefreshRateConfigs::RefreshRateType; + using GetCurrentRefreshRateTypeCallback = std::function<RefreshRateType()>; using ChangeRefreshRateCallback = std::function<void(RefreshRateType, ConfigEvent)>; using GetVsyncPeriod = std::function<nsecs_t()>; @@ -96,12 +97,13 @@ public: virtual ~Scheduler(); /** Creates an EventThread connection. */ - sp<ConnectionHandle> createConnection(const char* connectionName, int64_t phaseOffsetNs, - ResyncCallback, + sp<ConnectionHandle> createConnection(const char* connectionName, nsecs_t phaseOffsetNs, + nsecs_t offsetThresholdForNextVsync, ResyncCallback, impl::EventThread::InterceptVSyncsCallback); - sp<IDisplayEventConnection> createDisplayEventConnection(const sp<ConnectionHandle>& handle, - ResyncCallback); + sp<IDisplayEventConnection> createDisplayEventConnection( + const sp<ConnectionHandle>& handle, ResyncCallback, + ISurfaceComposer::ConfigChanged configChanged); // Getter methods. EventThread* getEventThread(const sp<ConnectionHandle>& handle); @@ -164,7 +166,9 @@ public: // Updates FPS based on the most content presented. void updateFpsBasedOnContent(); // Callback that gets invoked when Scheduler wants to change the refresh rate. - void setChangeRefreshRateCallback(const ChangeRefreshRateCallback& changeRefreshRateCallback); + void setChangeRefreshRateCallback(const ChangeRefreshRateCallback&& changeRefreshRateCallback); + void setGetCurrentRefreshRateTypeCallback( + const GetCurrentRefreshRateTypeCallback&& getCurrentRefreshRateType); void setGetVsyncPeriodCallback(const GetVsyncPeriod&& getVsyncPeriod); // Returns whether idle timer is enabled or not @@ -176,6 +180,9 @@ public: // Function that resets the touch timer. void notifyTouchEvent(); + // Function that sets whether display power mode is normal or not. + void setDisplayPowerState(bool normal); + // Returns relevant information about Scheduler for dumpsys purposes. std::string doDump(); @@ -184,7 +191,8 @@ public: protected: virtual std::unique_ptr<EventThread> makeEventThread( - const char* connectionName, DispSync* dispSync, int64_t phaseOffsetNs, + const char* connectionName, DispSync* dispSync, nsecs_t phaseOffsetNs, + nsecs_t offsetThresholdForNextVsync, impl::EventThread::InterceptVSyncsCallback interceptCallback); private: @@ -195,9 +203,11 @@ private: enum class ContentFeatureState { CONTENT_DETECTION_ON, CONTENT_DETECTION_OFF }; enum class IdleTimerState { EXPIRED, RESET }; enum class TouchState { INACTIVE, ACTIVE }; + enum class DisplayPowerTimerState { EXPIRED, RESET }; // Creates a connection on the given EventThread and forwards the given callbacks. - sp<EventThreadConnection> createConnectionInternal(EventThread*, ResyncCallback&&); + sp<EventThreadConnection> createConnectionInternal(EventThread*, ResyncCallback&&, + ISurfaceComposer::ConfigChanged); nsecs_t calculateAverage() const; void updateFrameSkipping(const int64_t skipCount); @@ -218,12 +228,15 @@ private: void resetTouchTimerCallback(); // Function that is called when the touch timer expires. void expiredTouchTimerCallback(); + // Function that is called when the display power timer resets. + void resetDisplayPowerTimerCallback(); + // Function that is called when the display power timer expires. + void expiredDisplayPowerTimerCallback(); // Sets vsync period. void setVsyncPeriod(const nsecs_t period); - // Idle timer feature's function to change the refresh rate. - void timerChangeRefreshRate(IdleTimerState idleTimerState); - // Touch timer feature's function to change the refresh rate. - void touchChangeRefreshRate(TouchState touchState); + // handles various timer features to change the refresh rate. + template <class T> + void handleTimerStateChanged(T* currentState, T newState, bool eventOnContentDetection); // Calculate the new refresh rate type RefreshRateType calculateRefreshRateType() REQUIRES(mFeatureStateLock); // Acquires a lock and calls the ChangeRefreshRateCallback() with given parameters. @@ -279,7 +292,12 @@ private: int64_t mSetTouchTimerMs = 0; std::unique_ptr<scheduler::IdleTimer> mTouchTimer; + // Timer used to monitor display power mode. + int64_t mSetDisplayPowerTimerMs = 0; + std::unique_ptr<scheduler::IdleTimer> mDisplayPowerTimer; + std::mutex mCallbackLock; + GetCurrentRefreshRateTypeCallback mGetCurrentRefreshRateTypeCallback GUARDED_BY(mCallbackLock); ChangeRefreshRateCallback mChangeRefreshRateCallback GUARDED_BY(mCallbackLock); GetVsyncPeriod mGetVsyncPeriod GUARDED_BY(mCallbackLock); @@ -290,14 +308,17 @@ private: ContentFeatureState::CONTENT_DETECTION_OFF; IdleTimerState mCurrentIdleTimerState GUARDED_BY(mFeatureStateLock) = IdleTimerState::RESET; TouchState mCurrentTouchState GUARDED_BY(mFeatureStateLock) = TouchState::INACTIVE; + DisplayPowerTimerState mDisplayPowerTimerState GUARDED_BY(mFeatureStateLock) = + DisplayPowerTimerState::EXPIRED; uint32_t mContentRefreshRate GUARDED_BY(mFeatureStateLock); RefreshRateType mRefreshRateType GUARDED_BY(mFeatureStateLock); bool mIsHDRContent GUARDED_BY(mFeatureStateLock) = false; + bool mIsDisplayPowerStateNormal GUARDED_BY(mFeatureStateLock) = true; const scheduler::RefreshRateConfigs& mRefreshRateConfigs; // Global config to force HDR content to work on DEFAULT refreshRate - static constexpr bool mForceHDRContentToDefaultRefreshRate = true; + static constexpr bool mForceHDRContentToDefaultRefreshRate = false; }; } // namespace android diff --git a/services/surfaceflinger/Scheduler/SchedulerUtils.h b/services/surfaceflinger/Scheduler/SchedulerUtils.h index 3bf3922edd..ac10f83ad9 100644 --- a/services/surfaceflinger/Scheduler/SchedulerUtils.h +++ b/services/surfaceflinger/Scheduler/SchedulerUtils.h @@ -36,13 +36,18 @@ static constexpr size_t ARRAY_SIZE = 30; static constexpr int SCREEN_OFF_CONFIG_ID = -1; static constexpr uint32_t HWC2_SCREEN_OFF_CONFIG_ID = 0xffffffff; -// This number is used when we try to determine how long does a given layer stay relevant. -// Currently it is set to 100ms, because that would indicate 10Hz rendering. -static constexpr std::chrono::nanoseconds TIME_EPSILON_NS = 100ms; - // This number is used when we try to determine how long do we keep layer information around -// before we remove it. Currently it is set to 100ms. -static constexpr std::chrono::nanoseconds OBSOLETE_TIME_EPSILON_NS = 100ms; +// before we remove it. It is also used to determine how long the layer stays relevant. +// This time period captures infrequent updates when playing YouTube video with static image, +// or waiting idle in messaging app, when cursor is blinking. +static constexpr std::chrono::nanoseconds OBSOLETE_TIME_EPSILON_NS = 1200ms; + +// Layer is considered low activity if the LOW_ACTIVITY_BUFFERS buffers come more than +// LOW_ACTIVITY_EPSILON_NS apart. +// This is helping SF to vote for lower refresh rates when there is not activity +// in screen. +static constexpr int LOW_ACTIVITY_BUFFERS = 2; +static constexpr std::chrono::nanoseconds LOW_ACTIVITY_EPSILON_NS = 250ms; // Calculates the statistical mean (average) in the data structure (array, vector). The // function does not modify the contents of the array. diff --git a/services/surfaceflinger/Scheduler/VSyncModulator.cpp b/services/surfaceflinger/Scheduler/VSyncModulator.cpp new file mode 100644 index 0000000000..7a3bf8edaf --- /dev/null +++ b/services/surfaceflinger/Scheduler/VSyncModulator.cpp @@ -0,0 +1,164 @@ +/* + * Copyright 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define ATRACE_TAG ATRACE_TAG_GRAPHICS + +#include "VSyncModulator.h" + +#include <cutils/properties.h> +#include <utils/Trace.h> + +#include <cinttypes> +#include <mutex> + +namespace android { + +using RefreshRateType = scheduler::RefreshRateConfigs::RefreshRateType; +VSyncModulator::VSyncModulator() { + char value[PROPERTY_VALUE_MAX]; + property_get("debug.sf.vsync_trace_detailed_info", value, "0"); + mTraceDetailedInfo = atoi(value); + // Populate the offset map with some default offsets. + const Offsets defaultOffsets = {RefreshRateType::DEFAULT, 0, 0}; + setPhaseOffsets(defaultOffsets, defaultOffsets, defaultOffsets, 0); +} + +void VSyncModulator::setPhaseOffsets(Offsets early, Offsets earlyGl, Offsets late, + nsecs_t thresholdForNextVsync) { + std::lock_guard<std::mutex> lock(mMutex); + mOffsetMap.insert_or_assign(OffsetType::Early, early); + mOffsetMap.insert_or_assign(OffsetType::EarlyGl, earlyGl); + mOffsetMap.insert_or_assign(OffsetType::Late, late); + mThresholdForNextVsync = thresholdForNextVsync; + updateOffsetsLocked(); +} + +void VSyncModulator::setTransactionStart(Scheduler::TransactionStart transactionStart) { + if (transactionStart == Scheduler::TransactionStart::EARLY) { + mRemainingEarlyFrameCount = MIN_EARLY_FRAME_COUNT_TRANSACTION; + } + + // An early transaction stays an early transaction. + if (transactionStart == mTransactionStart || + mTransactionStart == Scheduler::TransactionStart::EARLY) { + return; + } + mTransactionStart = transactionStart; + updateOffsets(); +} + +void VSyncModulator::onTransactionHandled() { + if (mTransactionStart == Scheduler::TransactionStart::NORMAL) return; + mTransactionStart = Scheduler::TransactionStart::NORMAL; + updateOffsets(); +} + +void VSyncModulator::onRefreshRateChangeInitiated() { + if (mRefreshRateChangePending) { + return; + } + mRefreshRateChangePending = true; + updateOffsets(); +} + +void VSyncModulator::onRefreshRateChangeCompleted() { + if (!mRefreshRateChangePending) { + return; + } + mRefreshRateChangePending = false; + updateOffsets(); +} + +void VSyncModulator::onRefreshed(bool usedRenderEngine) { + bool updateOffsetsNeeded = false; + if (mRemainingEarlyFrameCount > 0) { + mRemainingEarlyFrameCount--; + updateOffsetsNeeded = true; + } + if (usedRenderEngine) { + mRemainingRenderEngineUsageCount = MIN_EARLY_GL_FRAME_COUNT_TRANSACTION; + updateOffsetsNeeded = true; + } else if (mRemainingRenderEngineUsageCount > 0) { + mRemainingRenderEngineUsageCount--; + updateOffsetsNeeded = true; + } + if (updateOffsetsNeeded) { + updateOffsets(); + } +} + +VSyncModulator::Offsets VSyncModulator::getOffsets() { + std::lock_guard<std::mutex> lock(mMutex); + return mOffsets; +} + +VSyncModulator::Offsets VSyncModulator::getNextOffsets() { + return mOffsetMap.at(getNextOffsetType()); +} + +VSyncModulator::OffsetType VSyncModulator::getNextOffsetType() { + // Early offsets are used if we're in the middle of a refresh rate + // change, or if we recently begin a transaction. + if (mTransactionStart == Scheduler::TransactionStart::EARLY || mRemainingEarlyFrameCount > 0 || + mRefreshRateChangePending) { + return OffsetType::Early; + } else if (mRemainingRenderEngineUsageCount > 0) { + return OffsetType::EarlyGl; + } else { + return OffsetType::Late; + } +} + +void VSyncModulator::updateOffsets() { + std::lock_guard<std::mutex> lock(mMutex); + updateOffsetsLocked(); +} + +void VSyncModulator::updateOffsetsLocked() { + const Offsets desired = getNextOffsets(); + + if (mSfConnectionHandle != nullptr) { + mScheduler->setPhaseOffset(mSfConnectionHandle, desired.sf); + } + + if (mAppConnectionHandle != nullptr) { + mScheduler->setPhaseOffset(mAppConnectionHandle, desired.app); + } + + flushOffsets(); +} + +void VSyncModulator::flushOffsets() { + OffsetType type = getNextOffsetType(); + mOffsets = mOffsetMap.at(type); + if (!mTraceDetailedInfo) { + return; + } + ATRACE_INT("Vsync-EarlyOffsetsOn", + mOffsets.fpsMode == RefreshRateType::DEFAULT && type == OffsetType::Early); + ATRACE_INT("Vsync-EarlyGLOffsetsOn", + mOffsets.fpsMode == RefreshRateType::DEFAULT && type == OffsetType::EarlyGl); + ATRACE_INT("Vsync-LateOffsetsOn", + mOffsets.fpsMode == RefreshRateType::DEFAULT && type == OffsetType::Late); + ATRACE_INT("Vsync-HighFpsEarlyOffsetsOn", + mOffsets.fpsMode == RefreshRateType::PERFORMANCE && type == OffsetType::Early); + ATRACE_INT("Vsync-HighFpsEarlyGLOffsetsOn", + mOffsets.fpsMode == RefreshRateType::PERFORMANCE && type == OffsetType::EarlyGl); + ATRACE_INT("Vsync-HighFpsLateOffsetsOn", + mOffsets.fpsMode == RefreshRateType::PERFORMANCE && type == OffsetType::Late); +} + +} // namespace android diff --git a/services/surfaceflinger/Scheduler/VSyncModulator.h b/services/surfaceflinger/Scheduler/VSyncModulator.h index 21dad12797..ddbd221ef1 100644 --- a/services/surfaceflinger/Scheduler/VSyncModulator.h +++ b/services/surfaceflinger/Scheduler/VSyncModulator.h @@ -16,8 +16,6 @@ #pragma once -#include <utils/Errors.h> - #include <cinttypes> #include <mutex> @@ -35,12 +33,28 @@ private: // sending new transactions. const int MIN_EARLY_FRAME_COUNT_TRANSACTION = 2; + // Number of frames we'll keep the early gl phase offsets once they are activated. + // This acts as a low-pass filter to avoid scenarios where we rapidly + // switch in and out of gl composition. + const int MIN_EARLY_GL_FRAME_COUNT_TRANSACTION = 2; + public: + VSyncModulator(); + + // Wrapper for a collection of surfaceflinger/app offsets for a particular + // configuration . struct Offsets { + scheduler::RefreshRateConfigs::RefreshRateType fpsMode; nsecs_t sf; nsecs_t app; }; + enum class OffsetType { + Early, + EarlyGl, + Late, + }; + // Sets the phase offsets // // sfEarly: The phase offset when waking up SF early, which happens when marking a transaction @@ -51,31 +65,10 @@ public: // appEarly: Like sfEarly, but for the app-vsync // appEarlyGl: Like sfEarlyGl, but for the app-vsync. // appLate: The regular app vsync phase offset. - void setPhaseOffsets(Offsets early, Offsets earlyGl, Offsets late) { - mEarlyOffsets = early; - mEarlyGlOffsets = earlyGl; - mLateOffsets = late; - - if (mSfConnectionHandle && late.sf != mOffsets.load().sf) { - mScheduler->setPhaseOffset(mSfConnectionHandle, late.sf); - } - - if (mAppConnectionHandle && late.app != mOffsets.load().app) { - mScheduler->setPhaseOffset(mAppConnectionHandle, late.app); - } - - mOffsets = late; - } - - Offsets getEarlyOffsets() const { return mEarlyOffsets; } - - Offsets getEarlyGlOffsets() const { return mEarlyGlOffsets; } - - void setEventThreads(EventThread* sfEventThread, EventThread* appEventThread) { - mSfEventThread = sfEventThread; - mAppEventThread = appEventThread; - } + void setPhaseOffsets(Offsets early, Offsets earlyGl, Offsets late, + nsecs_t thresholdForNextVsync) EXCLUDES(mMutex); + // Sets the scheduler and vsync connection handlers. void setSchedulerAndHandles(Scheduler* scheduler, Scheduler::ConnectionHandle* appConnectionHandle, Scheduler::ConnectionHandle* sfConnectionHandle) { @@ -84,120 +77,57 @@ public: mSfConnectionHandle = sfConnectionHandle; } - void setTransactionStart(Scheduler::TransactionStart transactionStart) { - if (transactionStart == Scheduler::TransactionStart::EARLY) { - mRemainingEarlyFrameCount = MIN_EARLY_FRAME_COUNT_TRANSACTION; - } - - // An early transaction stays an early transaction. - if (transactionStart == mTransactionStart || - mTransactionStart == Scheduler::TransactionStart::EARLY) { - return; - } - mTransactionStart = transactionStart; - updateOffsets(); - } + // Signals that a transaction has started, and changes offsets accordingly. + void setTransactionStart(Scheduler::TransactionStart transactionStart); - void onTransactionHandled() { - if (mTransactionStart == Scheduler::TransactionStart::NORMAL) return; - mTransactionStart = Scheduler::TransactionStart::NORMAL; - updateOffsets(); - } + // Signals that a transaction has been completed, so that we can finish + // special handling for a transaction. + void onTransactionHandled(); // Called when we send a refresh rate change to hardware composer, so that // we can move into early offsets. - void onRefreshRateChangeInitiated() { - if (mRefreshRateChangePending) { - return; - } - mRefreshRateChangePending = true; - updateOffsets(); - } + void onRefreshRateChangeInitiated(); // Called when we detect from vsync signals that the refresh rate changed. // This way we can move out of early offsets if no longer necessary. - void onRefreshRateChangeCompleted() { - if (!mRefreshRateChangePending) { - return; - } - mRefreshRateChangePending = false; - updateOffsets(); - } + void onRefreshRateChangeCompleted(); - void onRefreshed(bool usedRenderEngine) { - bool updateOffsetsNeeded = false; - if (mRemainingEarlyFrameCount > 0) { - mRemainingEarlyFrameCount--; - updateOffsetsNeeded = true; - } - if (usedRenderEngine != mLastFrameUsedRenderEngine) { - mLastFrameUsedRenderEngine = usedRenderEngine; - updateOffsetsNeeded = true; - } - if (updateOffsetsNeeded) { - updateOffsets(); - } - } + // Called when the display is presenting a new frame. usedRenderEngine + // should be set to true if RenderEngine was involved with composing the new + // frame. + void onRefreshed(bool usedRenderEngine); - Offsets getOffsets() { - // Early offsets are used if we're in the middle of a refresh rate - // change, or if we recently begin a transaction. - if (mTransactionStart == Scheduler::TransactionStart::EARLY || - mRemainingEarlyFrameCount > 0 || mRefreshRateChangePending) { - return mEarlyOffsets; - } else if (mLastFrameUsedRenderEngine) { - return mEarlyGlOffsets; - } else { - return mLateOffsets; - } - } + // Returns the offsets that we are currently using + Offsets getOffsets() EXCLUDES(mMutex); private: - void updateOffsets() { - const Offsets desired = getOffsets(); - const Offsets current = mOffsets; - - bool changed = false; - if (desired.sf != current.sf) { - if (mSfConnectionHandle != nullptr) { - mScheduler->setPhaseOffset(mSfConnectionHandle, desired.sf); - } else { - mSfEventThread->setPhaseOffset(desired.sf); - } - changed = true; - } - if (desired.app != current.app) { - if (mAppConnectionHandle != nullptr) { - mScheduler->setPhaseOffset(mAppConnectionHandle, desired.app); - } else { - mAppEventThread->setPhaseOffset(desired.app); - } - changed = true; - } - - if (changed) { - mOffsets = desired; - } - } - - Offsets mLateOffsets; - Offsets mEarlyOffsets; - Offsets mEarlyGlOffsets; - - EventThread* mSfEventThread = nullptr; - EventThread* mAppEventThread = nullptr; + // Returns the next offsets that we should be using + Offsets getNextOffsets() REQUIRES(mMutex); + // Returns the next offset type that we should use. + OffsetType getNextOffsetType(); + // Updates offsets and persists them into the scheduler framework. + void updateOffsets() EXCLUDES(mMutex); + void updateOffsetsLocked() REQUIRES(mMutex); + // Updates the internal offsets and offset type. + void flushOffsets() REQUIRES(mMutex); + + mutable std::mutex mMutex; + std::unordered_map<OffsetType, Offsets> mOffsetMap GUARDED_BY(mMutex); + nsecs_t mThresholdForNextVsync; Scheduler* mScheduler = nullptr; Scheduler::ConnectionHandle* mAppConnectionHandle = nullptr; Scheduler::ConnectionHandle* mSfConnectionHandle = nullptr; - std::atomic<Offsets> mOffsets; + Offsets mOffsets GUARDED_BY(mMutex) = {Scheduler::RefreshRateType::DEFAULT, 0, 0}; std::atomic<Scheduler::TransactionStart> mTransactionStart = Scheduler::TransactionStart::NORMAL; - std::atomic<bool> mLastFrameUsedRenderEngine = false; std::atomic<bool> mRefreshRateChangePending = false; std::atomic<int> mRemainingEarlyFrameCount = 0; + std::atomic<int> mRemainingRenderEngineUsageCount = 0; + + bool mTraceDetailedInfo = false; }; } // namespace android diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index a15cf4a340..60b3a11754 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -48,6 +48,8 @@ #include <compositionengine/impl/OutputLayerCompositionState.h> #include <dvr/vr_flinger.h> #include <gui/BufferQueue.h> +#include <gui/DebugEGLImageTracker.h> + #include <gui/GuiConfig.h> #include <gui/IDisplayEventConnection.h> #include <gui/IProducerListener.h> @@ -311,6 +313,9 @@ SurfaceFlinger::SurfaceFlinger(Factory& factory) : SurfaceFlinger(factory, SkipI wideColorGamutCompositionPixelFormat = static_cast<ui::PixelFormat>(wcg_composition_pixel_format(ui::PixelFormat::RGBA_8888)); + mColorSpaceAgnosticDataspace = + static_cast<ui::Dataspace>(color_space_agnostic_dataspace(Dataspace::UNKNOWN)); + useContextPriority = use_context_priority(true); auto tmpPrimaryDisplayOrientation = primary_display_orientation( @@ -382,7 +387,8 @@ SurfaceFlinger::SurfaceFlinger(Factory& factory) : SurfaceFlinger(factory, SkipI mLumaSampling = atoi(value); const auto [early, gl, late] = mPhaseOffsets->getCurrentOffsets(); - mVsyncModulator.setPhaseOffsets(early, gl, late); + mVsyncModulator.setPhaseOffsets(early, gl, late, + mPhaseOffsets->getOffsetThresholdForNextVsync()); // We should be reading 'persist.sys.sf.color_saturation' here // but since /data may be encrypted, we need to wait until after vold @@ -621,13 +627,16 @@ void SurfaceFlinger::init() { mScheduler->makeResyncCallback(std::bind(&SurfaceFlinger::getVsyncPeriod, this)); mAppConnectionHandle = - mScheduler->createConnection("app", mPhaseOffsets->getCurrentAppOffset(), + mScheduler->createConnection("app", mVsyncModulator.getOffsets().app, + mPhaseOffsets->getOffsetThresholdForNextVsync(), resyncCallback, impl::EventThread::InterceptVSyncsCallback()); - mSfConnectionHandle = mScheduler->createConnection("sf", mPhaseOffsets->getCurrentSfOffset(), - resyncCallback, [this](nsecs_t timestamp) { - mInterceptor->saveVSyncEvent(timestamp); - }); + mSfConnectionHandle = + mScheduler->createConnection("sf", mVsyncModulator.getOffsets().sf, + mPhaseOffsets->getOffsetThresholdForNextVsync(), + resyncCallback, [this](nsecs_t timestamp) { + mInterceptor->saveVSyncEvent(timestamp); + }); mEventQueue->setEventConnection(mScheduler->getEventConnection(mSfConnectionHandle)); mVsyncModulator.setSchedulerAndHandles(mScheduler.get(), mAppConnectionHandle.get(), @@ -711,6 +720,24 @@ void SurfaceFlinger::init() { Mutex::Autolock lock(mStateLock); setRefreshRateTo(type, event); }); + mScheduler->setGetCurrentRefreshRateTypeCallback([this] { + Mutex::Autolock lock(mStateLock); + const auto display = getDefaultDisplayDeviceLocked(); + if (!display) { + // If we don't have a default display the fallback to the default + // refresh rate type + return RefreshRateType::DEFAULT; + } + + const int configId = display->getActiveConfig(); + for (const auto& [type, refresh] : mRefreshRateConfigs.getRefreshRates()) { + if (refresh && refresh->configId == configId) { + return type; + } + } + // This should never happen, but just gracefully fallback to default. + return RefreshRateType::DEFAULT; + }); mScheduler->setGetVsyncPeriodCallback([this] { Mutex::Autolock lock(mStateLock); return getVsyncPeriod(); @@ -940,15 +967,13 @@ void SurfaceFlinger::setDesiredActiveConfig(const ActiveConfigInfo& info) { // Start receiving vsync samples now, so that we can detect a period // switch. mScheduler->resyncToHardwareVsync(true, getVsyncPeriod()); - // We should only move to early offsets when we know that the refresh - // rate will change. Otherwise, we may be stuck in early offsets - // forever, as onRefreshRateChangeDetected will not be called. - if (mDesiredActiveConfig.event == Scheduler::ConfigEvent::Changed) { - mVsyncModulator.onRefreshRateChangeInitiated(); - } + // As we called to set period, we will call to onRefreshRateChangeCompleted once + // DispSync model is locked. + mVsyncModulator.onRefreshRateChangeInitiated(); mPhaseOffsets->setRefreshRateType(info.type); const auto [early, gl, late] = mPhaseOffsets->getCurrentOffsets(); - mVsyncModulator.setPhaseOffsets(early, gl, late); + mVsyncModulator.setPhaseOffsets(early, gl, late, + mPhaseOffsets->getOffsetThresholdForNextVsync()); } mDesiredActiveConfigChanged = true; ATRACE_INT("DesiredActiveConfigChanged", mDesiredActiveConfigChanged); @@ -980,10 +1005,10 @@ void SurfaceFlinger::setActiveConfigInternal() { display->setActiveConfig(mUpcomingActiveConfig.configId); - mScheduler->resyncToHardwareVsync(true, getVsyncPeriod()); mPhaseOffsets->setRefreshRateType(mUpcomingActiveConfig.type); const auto [early, gl, late] = mPhaseOffsets->getCurrentOffsets(); - mVsyncModulator.setPhaseOffsets(early, gl, late); + mVsyncModulator.setPhaseOffsets(early, gl, late, + mPhaseOffsets->getOffsetThresholdForNextVsync()); ATRACE_INT("ActiveConfigMode", mUpcomingActiveConfig.configId); if (mUpcomingActiveConfig.event != Scheduler::ConfigEvent::None) { @@ -992,6 +1017,19 @@ void SurfaceFlinger::setActiveConfigInternal() { } } +void SurfaceFlinger::desiredActiveConfigChangeDone() { + std::lock_guard<std::mutex> lock(mActiveConfigLock); + mDesiredActiveConfig.event = Scheduler::ConfigEvent::None; + mDesiredActiveConfigChanged = false; + ATRACE_INT("DesiredActiveConfigChanged", mDesiredActiveConfigChanged); + + mScheduler->resyncToHardwareVsync(true, getVsyncPeriod()); + mPhaseOffsets->setRefreshRateType(mUpcomingActiveConfig.type); + const auto [early, gl, late] = mPhaseOffsets->getCurrentOffsets(); + mVsyncModulator.setPhaseOffsets(early, gl, late, + mPhaseOffsets->getOffsetThresholdForNextVsync()); +} + bool SurfaceFlinger::performSetActiveConfig() { ATRACE_CALL(); if (mCheckPendingFence) { @@ -1021,14 +1059,7 @@ bool SurfaceFlinger::performSetActiveConfig() { if (!display || display->getActiveConfig() == desiredActiveConfig.configId) { // display is not valid or we are already in the requested mode // on both cases there is nothing left to do - std::lock_guard<std::mutex> lock(mActiveConfigLock); - mDesiredActiveConfig.event = Scheduler::ConfigEvent::None; - mDesiredActiveConfigChanged = false; - // Update scheduler with the correct vsync period as a no-op. - // Otherwise, there exists a race condition where we get stuck in the - // incorrect vsync period. - mScheduler->resyncToHardwareVsync(false, getVsyncPeriod()); - ATRACE_INT("DesiredActiveConfigChanged", mDesiredActiveConfigChanged); + desiredActiveConfigChangeDone(); return false; } @@ -1036,17 +1067,10 @@ bool SurfaceFlinger::performSetActiveConfig() { // allowed configs might have change by the time we process the refresh. // Make sure the desired config is still allowed if (!isDisplayConfigAllowed(desiredActiveConfig.configId)) { - std::lock_guard<std::mutex> lock(mActiveConfigLock); - mDesiredActiveConfig.event = Scheduler::ConfigEvent::None; - mDesiredActiveConfig.configId = display->getActiveConfig(); - mDesiredActiveConfigChanged = false; - // Update scheduler with the current vsync period as a no-op. - // Otherwise, there exists a race condition where we get stuck in the - // incorrect vsync period. - mScheduler->resyncToHardwareVsync(false, getVsyncPeriod()); - ATRACE_INT("DesiredActiveConfigChanged", mDesiredActiveConfigChanged); + desiredActiveConfigChangeDone(); return false; } + mUpcomingActiveConfig = desiredActiveConfig; const auto displayId = display->getId(); LOG_ALWAYS_FATAL_IF(!displayId); @@ -1384,7 +1408,7 @@ status_t SurfaceFlinger::notifyPowerHint(int32_t hintId) { // ---------------------------------------------------------------------------- sp<IDisplayEventConnection> SurfaceFlinger::createDisplayEventConnection( - ISurfaceComposer::VsyncSource vsyncSource) { + ISurfaceComposer::VsyncSource vsyncSource, ISurfaceComposer::ConfigChanged configChanged) { auto resyncCallback = mScheduler->makeResyncCallback([this] { Mutex::Autolock lock(mStateLock); return getVsyncPeriod(); @@ -1393,7 +1417,8 @@ sp<IDisplayEventConnection> SurfaceFlinger::createDisplayEventConnection( const auto& handle = vsyncSource == eVsyncSourceSurfaceFlinger ? mSfConnectionHandle : mAppConnectionHandle; - return mScheduler->createDisplayEventConnection(handle, std::move(resyncCallback)); + return mScheduler->createDisplayEventConnection(handle, std::move(resyncCallback), + configChanged); } // ---------------------------------------------------------------------------- @@ -1542,10 +1567,23 @@ void SurfaceFlinger::onRefreshReceived(int sequenceId, hwc2_display_t /*hwcDispl void SurfaceFlinger::setPrimaryVsyncEnabled(bool enabled) { ATRACE_CALL(); - Mutex::Autolock lock(mStateLock); + + // Enable / Disable HWVsync from the main thread to avoid race conditions with + // display power state. + postMessageAsync(new LambdaMessage( + [=]() NO_THREAD_SAFETY_ANALYSIS { setPrimaryVsyncEnabledInternal(enabled); })); +} + +void SurfaceFlinger::setPrimaryVsyncEnabledInternal(bool enabled) { + ATRACE_CALL(); + + mHWCVsyncPendingState = enabled ? HWC2::Vsync::Enable : HWC2::Vsync::Disable; + if (const auto displayId = getInternalDisplayIdLocked()) { - getHwComposer().setVsyncEnabled(*displayId, - enabled ? HWC2::Vsync::Enable : HWC2::Vsync::Disable); + sp<DisplayDevice> display = getDefaultDisplayDeviceLocked(); + if (display && display->isPoweredOn()) { + setVsyncEnabledInHWC(*displayId, mHWCVsyncPendingState); + } } } @@ -1643,7 +1681,8 @@ void SurfaceFlinger::updateVrFlinger() { setTransactionFlags(eDisplayTransactionNeeded); } -bool SurfaceFlinger::previousFrameMissed() NO_THREAD_SAFETY_ANALYSIS { +bool SurfaceFlinger::previousFrameMissed(int graceTimeMs) NO_THREAD_SAFETY_ANALYSIS { + ATRACE_CALL(); // We are storing the last 2 present fences. If sf's phase offset is to be // woken up before the actual vsync but targeting the next vsync, we need to check // fence N-2 @@ -1652,26 +1691,46 @@ bool SurfaceFlinger::previousFrameMissed() NO_THREAD_SAFETY_ANALYSIS { ? mPreviousPresentFences[0] : mPreviousPresentFences[1]; - return fence != Fence::NO_FENCE && (fence->getStatus() == Fence::Status::Unsignaled); + if (fence == Fence::NO_FENCE) { + return false; + } + + if (graceTimeMs > 0 && fence->getStatus() == Fence::Status::Unsignaled) { + fence->wait(graceTimeMs); + } + + return (fence->getStatus() == Fence::Status::Unsignaled); } -nsecs_t SurfaceFlinger::getExpectedPresentTime() NO_THREAD_SAFETY_ANALYSIS { +void SurfaceFlinger::populateExpectedPresentTime() NO_THREAD_SAFETY_ANALYSIS { DisplayStatInfo stats; mScheduler->getDisplayStatInfo(&stats); const nsecs_t presentTime = mScheduler->getDispSyncExpectedPresentTime(); // Inflate the expected present time if we're targetting the next vsync. - const nsecs_t correctedTime = + mExpectedPresentTime = mVsyncModulator.getOffsets().sf < mPhaseOffsets->getOffsetThresholdForNextVsync() ? presentTime : presentTime + stats.vsyncPeriod; - return correctedTime; } void SurfaceFlinger::onMessageReceived(int32_t what) NO_THREAD_SAFETY_ANALYSIS { ATRACE_CALL(); switch (what) { case MessageQueue::INVALIDATE: { - bool frameMissed = previousFrameMissed(); + // calculate the expected present time once and use the cached + // value throughout this frame to make sure all layers are + // seeing this same value. + populateExpectedPresentTime(); + + // When Backpressure propagation is enabled we want to give a small grace period + // for the present fence to fire instead of just giving up on this frame to handle cases + // where present fence is just about to get signaled. + const int graceTimeForPresentFenceMs = + (mPropagateBackpressure && + (mPropagateBackpressureClientComposition || !mHadClientComposition)) + ? 1 + : 0; + bool frameMissed = previousFrameMissed(graceTimeForPresentFenceMs); bool hwcFrameMissed = mHadDeviceComposition && frameMissed; bool gpuFrameMissed = mHadClientComposition && frameMissed; ATRACE_INT("FrameMissed", static_cast<int>(frameMissed)); @@ -1766,6 +1825,7 @@ void SurfaceFlinger::handleMessageRefresh() { preComposition(); rebuildLayerStacks(); calculateWorkingSet(); + long compositionTime = elapsedRealtimeNano(); for (const auto& [token, display] : mDisplays) { beginFrame(display); prepareFrame(display); @@ -1795,7 +1855,7 @@ void SurfaceFlinger::handleMessageRefresh() { if (mVisibleRegionsDirty) { mVisibleRegionsDirty = false; if (mTracingEnabled) { - mTracing.notify("visibleRegionsDirty"); + mTracing.notify(compositionTime, "visibleRegionsDirty"); } } } @@ -1873,7 +1933,14 @@ void SurfaceFlinger::calculateWorkingSet() { RenderIntent renderIntent; pickColorMode(displayDevice, &colorMode, &targetDataspace, &renderIntent); display->setColorMode(colorMode, targetDataspace, renderIntent); + + if (isHdrColorMode(colorMode)) { + targetDataspace = Dataspace::UNKNOWN; + } else if (mColorSpaceAgnosticDataspace != Dataspace::UNKNOWN) { + targetDataspace = mColorSpaceAgnosticDataspace; + } } + for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) { if (layer->isHdrY410()) { layer->forceClientComposition(displayDevice); @@ -1900,9 +1967,7 @@ void SurfaceFlinger::calculateWorkingSet() { const auto& displayState = display->getState(); layer->setPerFrameData(displayDevice, displayState.transform, displayState.viewport, - displayDevice->getSupportedPerFrameMetadata(), - isHdrColorMode(displayState.colorMode) ? Dataspace::UNKNOWN - : targetDataspace); + displayDevice->getSupportedPerFrameMetadata(), targetDataspace); } } @@ -3798,6 +3863,7 @@ void SurfaceFlinger::applyTransactionState(const Vector<ComposerState>& states, if (uncacheBuffer.isValid()) { ClientCache::getInstance().erase(uncacheBuffer); + getRenderEngine().unbindExternalTextureBuffer(uncacheBuffer.id); } // If a synchronous transaction is explicitly requested without any changes, force a transaction @@ -4152,9 +4218,18 @@ uint32_t SurfaceFlinger::setClientStateLocked( bool bufferChanged = what & layer_state_t::eBufferChanged; bool cacheIdChanged = what & layer_state_t::eCachedBufferChanged; sp<GraphicBuffer> buffer; - if (bufferChanged && cacheIdChanged) { - ClientCache::getInstance().add(s.cachedBuffer, s.buffer); + if (bufferChanged && cacheIdChanged && s.buffer != nullptr) { buffer = s.buffer; + bool success = ClientCache::getInstance().add(s.cachedBuffer, s.buffer); + if (success) { + getRenderEngine().cacheExternalTextureBuffer(s.buffer); + success = ClientCache::getInstance() + .registerErasedRecipient(s.cachedBuffer, + wp<ClientCache::ErasedRecipient>(this)); + if (!success) { + getRenderEngine().unbindExternalTextureBuffer(s.buffer->getId()); + } + } } else if (cacheIdChanged) { buffer = ClientCache::getInstance().get(s.cachedBuffer); } else if (bufferChanged) { @@ -4437,6 +4512,13 @@ void SurfaceFlinger::initializeDisplays() { new LambdaMessage([this]() NO_THREAD_SAFETY_ANALYSIS { onInitializeDisplays(); })); } +void SurfaceFlinger::setVsyncEnabledInHWC(DisplayId displayId, HWC2::Vsync enabled) { + if (mHWCVsyncState != enabled) { + getHwComposer().setVsyncEnabled(displayId, enabled); + mHWCVsyncState = enabled; + } +} + void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& display, int mode) { if (display->isVirtual()) { ALOGE("%s: Invalid operation on virtual display", __FUNCTION__); @@ -4463,6 +4545,7 @@ void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& display, int // Turn on the display getHwComposer().setPowerMode(*displayId, mode); if (display->isPrimary() && mode != HWC_POWER_MODE_DOZE_SUSPEND) { + setVsyncEnabledInHWC(*displayId, mHWCVsyncPendingState); mScheduler->onScreenAcquired(mAppConnectionHandle); mScheduler->resyncToHardwareVsync(true, getVsyncPeriod()); } @@ -4488,6 +4571,9 @@ void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& display, int mScheduler->onScreenReleased(mAppConnectionHandle); } + // Make sure HWVsync is disabled before turning off the display + setVsyncEnabledInHWC(*displayId, HWC2::Vsync::Disable); + getHwComposer().setPowerMode(*displayId, mode); mVisibleRegionsDirty = true; // from this point on, SF will stop drawing on this display @@ -4514,6 +4600,7 @@ void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& display, int if (display->isPrimary()) { mTimeStats->setPowerMode(mode); mRefreshRateStats.setPowerMode(mode); + mScheduler->setDisplayPowerState(mode == HWC_POWER_MODE_NORMAL); } ALOGD("Finished setting power mode %d on display %s", mode, to_string(*displayId).c_str()); @@ -4682,6 +4769,16 @@ void SurfaceFlinger::dumpVSync(std::string& result) const { StringAppendF(&result, "Scheduler enabled."); StringAppendF(&result, "+ Smart 90 for video detection: %s\n\n", mUseSmart90ForVideo ? "on" : "off"); + StringAppendF(&result, "Allowed Display Configs: "); + for (int32_t configId : mAllowedDisplayConfigs) { + for (auto refresh : mRefreshRateConfigs.getRefreshRates()) { + if (refresh.second && refresh.second->configId == configId) { + StringAppendF(&result, "%dHz, ", refresh.second->fps); + } + } + } + StringAppendF(&result, "(config override by backdoor: %s)\n\n", + mDebugDisplayConfigSetByBackdoor ? "yes" : "no"); mScheduler->dump(mAppConnectionHandle, result); } @@ -4964,6 +5061,8 @@ void SurfaceFlinger::dumpAllLocked(const DumpArgs& args, std::string& result) co getRenderEngine().dump(result); + DebugEGLImageTracker::getInstance()->dump(result); + if (const auto display = getDefaultDisplayDeviceLocked()) { display->getCompositionDisplay()->getState().undefinedRegion.dump(result, "undefinedRegion"); @@ -5377,7 +5476,12 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r return NO_ERROR; } case 1023: { // Set native mode + int32_t colorMode; + mDisplayColorSetting = static_cast<DisplayColorSetting>(data.readInt32()); + if (data.readInt32(&colorMode) == NO_ERROR) { + mForceColorMode = static_cast<ColorMode>(colorMode); + } invalidateHwcGeometry(); repaintEverything(); return NO_ERROR; @@ -6092,8 +6196,20 @@ void SurfaceFlinger::setAllowedDisplayConfigsInternal(const sp<DisplayDevice>& d return; } + const auto allowedDisplayConfigs = DisplayConfigs(allowedConfigs.begin(), + allowedConfigs.end()); + if (allowedDisplayConfigs == mAllowedDisplayConfigs) { + return; + } + ALOGV("Updating allowed configs"); - mAllowedDisplayConfigs = DisplayConfigs(allowedConfigs.begin(), allowedConfigs.end()); + mAllowedDisplayConfigs = std::move(allowedDisplayConfigs); + + // TODO(b/140204874): This hack triggers a notification that something has changed, so + // that listeners that care about a change in allowed configs can get the notification. + // Giving current ActiveConfig so that most other listeners would just drop the event + mScheduler->onConfigChanged(mAppConnectionHandle, display->getId()->value, + display->getActiveConfig()); // Set the highest allowed config by iterating backwards on available refresh rates const auto& refreshRates = mRefreshRateConfigs.getRefreshRates(); @@ -6173,6 +6289,10 @@ sp<Layer> SurfaceFlinger::fromHandle(const sp<IBinder>& handle) { return nullptr; } +void SurfaceFlinger::bufferErased(const client_cache_t& clientCacheId) { + getRenderEngine().unbindExternalTextureBuffer(clientCacheId.id); +} + } // namespace android #if defined(__gl_h_) diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 49a048ccf8..49bb574147 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -170,9 +170,9 @@ public: class SurfaceFlinger : public BnSurfaceComposer, public PriorityDumper, + public ClientCache::ErasedRecipient, private IBinder::DeathRecipient, - private HWC2::ComposerCallback -{ + private HWC2::ComposerCallback { public: SurfaceFlingerBE& getBE() { return mBE; } const SurfaceFlingerBE& getBE() const { return mBE; } @@ -294,15 +294,19 @@ public: // TODO: this should be made accessible only to EventThread void setPrimaryVsyncEnabled(bool enabled); + // main thread function to enable/disable h/w composer event + void setPrimaryVsyncEnabledInternal(bool enabled); + // called on the main thread by MessageQueue when an internal message // is received // TODO: this should be made accessible only to MessageQueue void onMessageReceived(int32_t what); - // Returns the expected present time for this frame. + // populates the expected present time for this frame. // When we are in negative offsets, we perform a correction so that the // predicted vsync for the *next* frame is used instead. - nsecs_t getExpectedPresentTime(); + void populateExpectedPresentTime(); + nsecs_t getExpectedPresentTime() const { return mExpectedPresentTime; } // for debugging only // TODO: this should be made accessible only to HWComposer @@ -325,6 +329,9 @@ public: sp<Layer> fromHandle(const sp<IBinder>& handle) REQUIRES(mStateLock); + // Inherit from ClientCache::ErasedRecipient + void bufferErased(const client_cache_t& clientCacheId) override; + private: friend class BufferLayer; friend class BufferQueueLayer; @@ -405,7 +412,9 @@ private: const sp<IGraphicBufferProducer>& bufferProducer) const override; status_t getSupportedFrameTimestamps(std::vector<FrameEvent>* outSupported) const override; sp<IDisplayEventConnection> createDisplayEventConnection( - ISurfaceComposer::VsyncSource vsyncSource = eVsyncSourceApp) override; + ISurfaceComposer::VsyncSource vsyncSource = eVsyncSourceApp, + ISurfaceComposer::ConfigChanged configChanged = + ISurfaceComposer::eConfigChangedSuppress) override; status_t captureScreen(const sp<IBinder>& displayToken, sp<GraphicBuffer>* outBuffer, bool& outCapturedSecureLayers, const ui::Dataspace reqDataspace, const ui::PixelFormat reqPixelFormat, Rect sourceCrop, @@ -500,9 +509,9 @@ private: using RefreshRateType = scheduler::RefreshRateConfigs::RefreshRateType; struct ActiveConfigInfo { - RefreshRateType type; - int configId; - Scheduler::ConfigEvent event; + RefreshRateType type = RefreshRateType::DEFAULT; + int configId = 0; + Scheduler::ConfigEvent event = Scheduler::ConfigEvent::None; bool operator!=(const ActiveConfigInfo& other) const { return type != other.type || configId != other.configId || event != other.event; @@ -514,13 +523,15 @@ private: // Sets the desired active config bit. It obtains the lock, and sets mDesiredActiveConfig. void setDesiredActiveConfig(const ActiveConfigInfo& info) REQUIRES(mStateLock); // Once HWC has returned the present fence, this sets the active config and a new refresh - // rate in SF. It also triggers HWC vsync. + // rate in SF. void setActiveConfigInternal() REQUIRES(mStateLock); // Active config is updated on INVALIDATE call in a state machine-like manner. When the // desired config was set, HWC needs to update the panel on the next refresh, and when // we receive the fence back, we know that the process was complete. It returns whether // we need to wait for the next invalidate bool performSetActiveConfig() REQUIRES(mStateLock); + // Called when active config is no longer is progress + void desiredActiveConfigChangeDone() REQUIRES(mStateLock); // called on the main thread in response to setPowerMode() void setPowerModeInternal(const sp<DisplayDevice>& display, int mode) REQUIRES(mStateLock); @@ -838,7 +849,8 @@ private: return hwcDisplayId ? getHwComposer().toPhysicalDisplayId(*hwcDisplayId) : std::nullopt; } - bool previousFrameMissed(); + bool previousFrameMissed(int graceTimeMs = 0); + void setVsyncEnabledInHWC(DisplayId displayId, HWC2::Vsync enabled); /* * Debugging & dumpsys @@ -1113,6 +1125,7 @@ private: ui::Dataspace mDefaultCompositionDataspace; ui::Dataspace mWideColorGamutCompositionDataspace; + ui::Dataspace mColorSpaceAgnosticDataspace; SurfaceFlingerBE mBE; std::unique_ptr<compositionengine::CompositionEngine> mCompositionEngine; @@ -1177,6 +1190,12 @@ private: // The Layer pointer is removed from the set when the destructor is called so there shouldn't // be any issues with a raw pointer referencing an invalid object. std::unordered_set<Layer*> mOffscreenLayers; + + // Flags to capture the state of Vsync in HWC + HWC2::Vsync mHWCVsyncState = HWC2::Vsync::Disable; + HWC2::Vsync mHWCVsyncPendingState = HWC2::Vsync::Disable; + + nsecs_t mExpectedPresentTime; }; } // namespace android diff --git a/services/surfaceflinger/SurfaceFlingerProperties.cpp b/services/surfaceflinger/SurfaceFlingerProperties.cpp index 2b33ba1746..768074a6cd 100644 --- a/services/surfaceflinger/SurfaceFlingerProperties.cpp +++ b/services/surfaceflinger/SurfaceFlingerProperties.cpp @@ -218,6 +218,14 @@ int32_t wcg_composition_pixel_format(PixelFormat defaultValue) { return static_cast<int32_t>(defaultValue); } +int64_t color_space_agnostic_dataspace(Dataspace defaultValue) { + auto temp = SurfaceFlingerProperties::color_space_agnostic_dataspace(); + if (temp.has_value()) { + return *temp; + } + return static_cast<int64_t>(defaultValue); +} + int32_t set_idle_timer_ms(int32_t defaultValue) { auto temp = SurfaceFlingerProperties::set_idle_timer_ms(); if (temp.has_value()) { @@ -234,6 +242,14 @@ int32_t set_touch_timer_ms(int32_t defaultValue) { return defaultValue; } +int32_t set_display_power_timer_ms(int32_t defaultValue) { + auto temp = SurfaceFlingerProperties::set_display_power_timer_ms(); + if (temp.has_value()) { + return *temp; + } + return defaultValue; +} + bool use_smart_90_for_video(bool defaultValue) { auto temp = SurfaceFlingerProperties::use_smart_90_for_video(); if (temp.has_value()) { diff --git a/services/surfaceflinger/SurfaceFlingerProperties.h b/services/surfaceflinger/SurfaceFlingerProperties.h index 1964ccd582..5f88322f71 100644 --- a/services/surfaceflinger/SurfaceFlingerProperties.h +++ b/services/surfaceflinger/SurfaceFlingerProperties.h @@ -70,10 +70,15 @@ int64_t wcg_composition_dataspace( int32_t wcg_composition_pixel_format( android::hardware::graphics::common::V1_2::PixelFormat defaultValue); +int64_t color_space_agnostic_dataspace( + android::hardware::graphics::common::V1_2::Dataspace defaultValue); + int32_t set_idle_timer_ms(int32_t defaultValue); int32_t set_touch_timer_ms(int32_t defaultValue); +int32_t set_display_power_timer_ms(int32_t defaultValue); + bool use_smart_90_for_video(bool defaultValue); bool enable_protected_contents(bool defaultValue); diff --git a/services/surfaceflinger/SurfaceTracing.cpp b/services/surfaceflinger/SurfaceTracing.cpp index 9053f2c7de..5d9be0b8a9 100644 --- a/services/surfaceflinger/SurfaceTracing.cpp +++ b/services/surfaceflinger/SurfaceTracing.cpp @@ -68,8 +68,9 @@ bool SurfaceTracing::addTraceToBuffer(LayersTraceProto& entry) { return mEnabled; } -void SurfaceTracing::notify(const char* where) { +void SurfaceTracing::notify(long compositionTime, const char* where) { std::scoped_lock lock(mSfLock); + mCompositionTime = compositionTime; mWhere = where; mCanStartTrace.notify_one(); } @@ -160,7 +161,7 @@ LayersTraceProto SurfaceTracing::traceLayersLocked(const char* where) { ATRACE_CALL(); LayersTraceProto entry; - entry.set_elapsed_realtime_nanos(elapsedRealtimeNano()); + entry.set_elapsed_realtime_nanos(mCompositionTime); entry.set_where(where); LayersProto layers(mFlinger.dumpDrawingStateProto(mTraceFlags)); entry.mutable_layers()->Swap(&layers); diff --git a/services/surfaceflinger/SurfaceTracing.h b/services/surfaceflinger/SurfaceTracing.h index 4773307a65..395d5622c7 100644 --- a/services/surfaceflinger/SurfaceTracing.h +++ b/services/surfaceflinger/SurfaceTracing.h @@ -46,7 +46,7 @@ public: bool disable(); status_t writeToFile(); bool isEnabled() const; - void notify(const char* where); + void notify(long compositionTime, const char* where); void setBufferSize(size_t bufferSizeInByte); void writeToFileAsync(); @@ -81,6 +81,8 @@ private: std::queue<LayersTraceProto> mStorage; }; + long mCompositionTime; + void mainLoop(); void addFirstEntry(); LayersTraceProto traceWhenNotified(); diff --git a/services/surfaceflinger/TimeStats/OWNERS b/services/surfaceflinger/TimeStats/OWNERS index ac02d12fcd..1441f91489 100644 --- a/services/surfaceflinger/TimeStats/OWNERS +++ b/services/surfaceflinger/TimeStats/OWNERS @@ -1 +1,2 @@ -zzyiwei@google.com
\ No newline at end of file +alecmouri@google.com +zzyiwei@google.com diff --git a/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop b/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop index a8ec7649c6..a4f4285552 100644 --- a/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop +++ b/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop @@ -251,6 +251,20 @@ prop { prop_name: "ro.surface_flinger.wcg_composition_pixel_format" } +# colorSpaceAgnosticDataspace specifies the data space that +# SurfaceFlinger expects for surfaces which are color space agnostic. +# The variable works only when useColorManagement is specified. If +# unspecified, the data space follows what SurfaceFlinger expects for +# surfaces when useColorManagement is specified. + +prop { + api_name: "color_space_agnostic_dataspace" + type: Long + scope: Public + access: Readonly + prop_name: "ro.surface_flinger.color_space_agnostic_dataspace" +} + # Return the native panel primary data. The data includes red, green, # blue and white. The primary format is CIE 1931 XYZ color space. # If unspecified, the primaries is sRGB gamut by default. @@ -309,6 +323,18 @@ prop { prop_name: "ro.surface_flinger.set_touch_timer_ms" } +# setDisplayPowerTimerMs indicates what is considered a timeout in milliseconds for Scheduler. +# This value is used by the Scheduler to trigger display power inactivity callbacks that will +# keep the display in peak refresh rate as long as display power is not in normal mode. +# Setting this property to 0 means there is no timer. +prop { + api_name: "set_display_power_timer_ms" + type: Integer + scope: Public + access: Readonly + prop_name: "ro.surface_flinger.set_display_power_timer_ms" +} + # useSmart90ForVideo indicates whether Scheduler should detect content FPS, and try to adjust the # screen refresh rate based on that. prop { diff --git a/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt b/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt index 061168467d..b66e56ecc7 100644 --- a/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt +++ b/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt @@ -1,6 +1,11 @@ props { module: "android.sysprop.SurfaceFlingerProperties" prop { + api_name: "color_space_agnostic_dataspace" + type: Long + prop_name: "ro.surface_flinger.color_space_agnostic_dataspace" + } + prop { api_name: "default_composition_dataspace" type: Long prop_name: "ro.surface_flinger.default_composition_dataspace" @@ -72,6 +77,11 @@ props { prop_name: "ro.surface_flinger.running_without_sync_framework" } prop { + api_name: "set_display_power_timer_ms" + type: Integer + prop_name: "ro.surface_flinger.set_display_power_timer_ms" + } + prop { api_name: "set_idle_timer_ms" type: Integer prop_name: "ro.surface_flinger.set_idle_timer_ms" diff --git a/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-latest.txt b/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-latest.txt index 061168467d..b66e56ecc7 100644 --- a/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-latest.txt +++ b/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-latest.txt @@ -1,6 +1,11 @@ props { module: "android.sysprop.SurfaceFlingerProperties" prop { + api_name: "color_space_agnostic_dataspace" + type: Long + prop_name: "ro.surface_flinger.color_space_agnostic_dataspace" + } + prop { api_name: "default_composition_dataspace" type: Long prop_name: "ro.surface_flinger.default_composition_dataspace" @@ -72,6 +77,11 @@ props { prop_name: "ro.surface_flinger.running_without_sync_framework" } prop { + api_name: "set_display_power_timer_ms" + type: Integer + prop_name: "ro.surface_flinger.set_display_power_timer_ms" + } + prop { api_name: "set_idle_timer_ms" type: Integer prop_name: "ro.surface_flinger.set_idle_timer_ms" diff --git a/services/surfaceflinger/tests/Transaction_test.cpp b/services/surfaceflinger/tests/Transaction_test.cpp index d5f65348d8..c93e15ef96 100644 --- a/services/surfaceflinger/tests/Transaction_test.cpp +++ b/services/surfaceflinger/tests/Transaction_test.cpp @@ -28,6 +28,7 @@ #include <binder/ProcessState.h> #include <gui/BufferItemConsumer.h> +#include <gui/IProducerListener.h> #include <gui/ISurfaceComposer.h> #include <gui/LayerState.h> #include <gui/Surface.h> @@ -6059,4 +6060,97 @@ TEST_F(RelativeZTest, LayerRemovedOffscreenRelativeParent) { } } +// This test ensures that when we drop an app buffer in SurfaceFlinger, we merge +// the dropped buffer's damage region into the next buffer's damage region. If +// we don't do this, we'll report an incorrect damage region to hardware +// composer, resulting in broken rendering. This test checks the BufferQueue +// case. +// +// Unfortunately, we don't currently have a way to inspect the damage region +// SurfaceFlinger sends to hardware composer from a test, so this test requires +// the dev to manually watch the device's screen during the test to spot broken +// rendering. Because the results can't be automatically verified, this test is +// marked disabled. +TEST_F(LayerTransactionTest, DISABLED_BufferQueueLayerMergeDamageRegionWhenDroppingBuffers) { + const int width = mDisplayWidth; + const int height = mDisplayHeight; + sp<SurfaceControl> layer; + ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", width, height)); + const auto producer = layer->getIGraphicBufferProducer(); + const sp<IProducerListener> dummyListener(new DummyProducerListener); + IGraphicBufferProducer::QueueBufferOutput queueBufferOutput; + ASSERT_EQ(OK, + producer->connect(dummyListener, NATIVE_WINDOW_API_CPU, true, &queueBufferOutput)); + + std::map<int, sp<GraphicBuffer>> slotMap; + auto slotToBuffer = [&](int slot, sp<GraphicBuffer>* buf) { + ASSERT_NE(nullptr, buf); + const auto iter = slotMap.find(slot); + ASSERT_NE(slotMap.end(), iter); + *buf = iter->second; + }; + + auto dequeue = [&](int* outSlot) { + ASSERT_NE(nullptr, outSlot); + *outSlot = -1; + int slot; + sp<Fence> fence; + uint64_t age; + FrameEventHistoryDelta timestamps; + const status_t dequeueResult = + producer->dequeueBuffer(&slot, &fence, width, height, PIXEL_FORMAT_RGBA_8888, + GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN, + &age, ×tamps); + if (dequeueResult == IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION) { + sp<GraphicBuffer> newBuf; + ASSERT_EQ(OK, producer->requestBuffer(slot, &newBuf)); + ASSERT_NE(nullptr, newBuf.get()); + slotMap[slot] = newBuf; + } else { + ASSERT_EQ(OK, dequeueResult); + } + *outSlot = slot; + }; + + auto queue = [&](int slot, const Region& damage, nsecs_t displayTime) { + IGraphicBufferProducer::QueueBufferInput input( + /*timestamp=*/displayTime, /*isAutoTimestamp=*/false, HAL_DATASPACE_UNKNOWN, + /*crop=*/Rect::EMPTY_RECT, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW, + /*transform=*/0, Fence::NO_FENCE); + input.setSurfaceDamage(damage); + IGraphicBufferProducer::QueueBufferOutput output; + ASSERT_EQ(OK, producer->queueBuffer(slot, input, &output)); + }; + + auto fillAndPostBuffers = [&](const Color& color) { + int slot1; + ASSERT_NO_FATAL_FAILURE(dequeue(&slot1)); + int slot2; + ASSERT_NO_FATAL_FAILURE(dequeue(&slot2)); + + sp<GraphicBuffer> buf1; + ASSERT_NO_FATAL_FAILURE(slotToBuffer(slot1, &buf1)); + sp<GraphicBuffer> buf2; + ASSERT_NO_FATAL_FAILURE(slotToBuffer(slot2, &buf2)); + fillGraphicBufferColor(buf1, Rect(width, height), color); + fillGraphicBufferColor(buf2, Rect(width, height), color); + + const auto displayTime = systemTime() + milliseconds_to_nanoseconds(100); + ASSERT_NO_FATAL_FAILURE(queue(slot1, Region::INVALID_REGION, displayTime)); + ASSERT_NO_FATAL_FAILURE( + queue(slot2, Region(Rect(width / 3, height / 3, 2 * width / 3, 2 * height / 3)), + displayTime)); + }; + + const auto startTime = systemTime(); + const std::array<Color, 3> colors = {Color::RED, Color::GREEN, Color::BLUE}; + int colorIndex = 0; + while (nanoseconds_to_seconds(systemTime() - startTime) < 10) { + ASSERT_NO_FATAL_FAILURE(fillAndPostBuffers(colors[colorIndex++ % colors.size()])); + std::this_thread::sleep_for(1s); + } + + ASSERT_EQ(OK, producer->disconnect(NATIVE_WINDOW_API_CPU)); +} + } // namespace android diff --git a/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp b/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp index 2e705dad6d..0aa8cf565d 100644 --- a/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp +++ b/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp @@ -51,6 +51,7 @@ protected: AsyncCallRecorder<void (*)(nsecs_t)> mVSyncEventCallRecorder; static constexpr std::chrono::nanoseconds mPhaseOffset = 6ms; + static constexpr std::chrono::nanoseconds mOffsetThresholdForNextVsync = 16ms; static constexpr int mIterations = 100; }; @@ -78,7 +79,8 @@ void DispSyncSourceTest::createDispSync() { void DispSyncSourceTest::createDispSyncSource() { createDispSync(); - mDispSyncSource = std::make_unique<DispSyncSource>(mDispSync.get(), mPhaseOffset.count(), true, + mDispSyncSource = std::make_unique<DispSyncSource>(mDispSync.get(), mPhaseOffset.count(), + mOffsetThresholdForNextVsync.count(), true, "DispSyncSourceTest"); mDispSyncSource->setCallback(this); } diff --git a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp index ea908a9018..dbd9b84039 100644 --- a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp +++ b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp @@ -55,8 +55,9 @@ protected: class MockEventThreadConnection : public EventThreadConnection { public: MockEventThreadConnection(android::impl::EventThread* eventThread, - ResyncCallback&& resyncCallback) - : EventThreadConnection(eventThread, std::move(resyncCallback)) {} + ResyncCallback&& resyncCallback, + ISurfaceComposer::ConfigChanged configChanged) + : EventThreadConnection(eventThread, std::move(resyncCallback), configChanged) {} MOCK_METHOD1(postEvent, status_t(const DisplayEventReceiver::Event& event)); }; @@ -67,7 +68,8 @@ protected: ~EventThreadTest() override; void createThread(); - sp<MockEventThreadConnection> createConnection(ConnectionEventRecorder& recorder); + sp<MockEventThreadConnection> createConnection(ConnectionEventRecorder& recorder, + ISurfaceComposer::ConfigChanged configChanged); void expectVSyncSetEnabledCallReceived(bool expectedState); void expectVSyncSetPhaseOffsetCallReceived(nsecs_t expectedPhaseOffset); @@ -110,7 +112,8 @@ EventThreadTest::EventThreadTest() { .WillRepeatedly(Invoke(mVSyncSetPhaseOffsetCallRecorder.getInvocable())); createThread(); - mConnection = createConnection(mConnectionEventCallRecorder); + mConnection = createConnection(mConnectionEventCallRecorder, + ISurfaceComposer::eConfigChangedDispatch); // A display must be connected for VSYNC events to be delivered. mThread->onHotplugReceived(INTERNAL_DISPLAY_ID, true); @@ -138,9 +141,10 @@ void EventThreadTest::createThread() { } sp<EventThreadTest::MockEventThreadConnection> EventThreadTest::createConnection( - ConnectionEventRecorder& recorder) { + ConnectionEventRecorder& recorder, ISurfaceComposer::ConfigChanged configChanged) { sp<MockEventThreadConnection> connection = - new MockEventThreadConnection(mThread.get(), mResyncCallRecorder.getInvocable()); + new MockEventThreadConnection(mThread.get(), mResyncCallRecorder.getInvocable(), + configChanged); EXPECT_CALL(*connection, postEvent(_)).WillRepeatedly(Invoke(recorder.getInvocable())); return connection; } @@ -267,7 +271,9 @@ TEST_F(EventThreadTest, requestNextVsyncPostsASingleVSyncEventToTheConnection) { TEST_F(EventThreadTest, setVsyncRateZeroPostsNoVSyncEventsToThatConnection) { // Create a first connection, register it, and request a vsync rate of zero. ConnectionEventRecorder firstConnectionEventRecorder{0}; - sp<MockEventThreadConnection> firstConnection = createConnection(firstConnectionEventRecorder); + sp<MockEventThreadConnection> firstConnection = + createConnection(firstConnectionEventRecorder, + ISurfaceComposer::eConfigChangedSuppress); mThread->setVsyncRate(0, firstConnection); // By itself, this should not enable vsync events @@ -277,7 +283,8 @@ TEST_F(EventThreadTest, setVsyncRateZeroPostsNoVSyncEventsToThatConnection) { // However if there is another connection which wants events at a nonzero rate..... ConnectionEventRecorder secondConnectionEventRecorder{0}; sp<MockEventThreadConnection> secondConnection = - createConnection(secondConnectionEventRecorder); + createConnection(secondConnectionEventRecorder, + ISurfaceComposer::eConfigChangedSuppress); mThread->setVsyncRate(1, secondConnection); // EventThread should enable vsync callbacks. @@ -363,7 +370,9 @@ TEST_F(EventThreadTest, connectionsRemovedIfInstanceDestroyed) { TEST_F(EventThreadTest, connectionsRemovedIfEventDeliveryError) { ConnectionEventRecorder errorConnectionEventRecorder{NO_MEMORY}; - sp<MockEventThreadConnection> errorConnection = createConnection(errorConnectionEventRecorder); + sp<MockEventThreadConnection> errorConnection = + createConnection(errorConnectionEventRecorder, + ISurfaceComposer::eConfigChangedSuppress); mThread->setVsyncRate(1, errorConnection); // EventThread should enable vsync callbacks. @@ -387,7 +396,9 @@ TEST_F(EventThreadTest, connectionsRemovedIfEventDeliveryError) { TEST_F(EventThreadTest, eventsDroppedIfNonfatalEventDeliveryError) { ConnectionEventRecorder errorConnectionEventRecorder{WOULD_BLOCK}; - sp<MockEventThreadConnection> errorConnection = createConnection(errorConnectionEventRecorder); + sp<MockEventThreadConnection> errorConnection = + createConnection(errorConnectionEventRecorder, + ISurfaceComposer::eConfigChangedSuppress); mThread->setVsyncRate(1, errorConnection); // EventThread should enable vsync callbacks. @@ -449,5 +460,18 @@ TEST_F(EventThreadTest, postConfigChangedPrimary64bit) { expectConfigChangedEventReceivedByConnection(DISPLAY_ID_64BIT, 7); } +TEST_F(EventThreadTest, suppressConfigChanged) { + ConnectionEventRecorder suppressConnectionEventRecorder{0}; + sp<MockEventThreadConnection> suppressConnection = + createConnection(suppressConnectionEventRecorder, + ISurfaceComposer::eConfigChangedSuppress); + + mThread->onConfigChanged(INTERNAL_DISPLAY_ID, 9); + expectConfigChangedEventReceivedByConnection(INTERNAL_DISPLAY_ID, 9); + + auto args = suppressConnectionEventRecorder.waitForCall(); + ASSERT_FALSE(args.has_value()); +} + } // namespace } // namespace android diff --git a/services/surfaceflinger/tests/unittests/FakePhaseOffsets.h b/services/surfaceflinger/tests/unittests/FakePhaseOffsets.h index 96121bb088..1d7501102e 100644 --- a/services/surfaceflinger/tests/unittests/FakePhaseOffsets.h +++ b/services/surfaceflinger/tests/unittests/FakePhaseOffsets.h @@ -23,6 +23,8 @@ namespace android { namespace scheduler { +using RefreshRateType = RefreshRateConfigs::RefreshRateType; + class FakePhaseOffsets : public android::scheduler::PhaseOffsets { nsecs_t FAKE_PHASE_OFFSET_NS = 0; @@ -34,20 +36,20 @@ public: nsecs_t getCurrentSfOffset() override { return FAKE_PHASE_OFFSET_NS; } PhaseOffsets::Offsets getOffsetsForRefreshRate( - RefreshRateConfigs::RefreshRateType /*refreshRateType*/) const override { + RefreshRateType /*refreshRateType*/) const override { return getCurrentOffsets(); } // Returns early, early GL, and late offsets for Apps and SF. PhaseOffsets::Offsets getCurrentOffsets() const override { - return Offsets{{FAKE_PHASE_OFFSET_NS, FAKE_PHASE_OFFSET_NS}, - {FAKE_PHASE_OFFSET_NS, FAKE_PHASE_OFFSET_NS}, - {FAKE_PHASE_OFFSET_NS, FAKE_PHASE_OFFSET_NS}}; + return Offsets{{RefreshRateType::DEFAULT, FAKE_PHASE_OFFSET_NS, FAKE_PHASE_OFFSET_NS}, + {RefreshRateType::DEFAULT, FAKE_PHASE_OFFSET_NS, FAKE_PHASE_OFFSET_NS}, + {RefreshRateType::DEFAULT, FAKE_PHASE_OFFSET_NS, FAKE_PHASE_OFFSET_NS}}; } // This function should be called when the device is switching between different // refresh rates, to properly update the offsets. - void setRefreshRateType(RefreshRateConfigs::RefreshRateType /*refreshRateType*/) override {} + void setRefreshRateType(RefreshRateType /*refreshRateType*/) override {} nsecs_t getOffsetThresholdForNextVsync() const override { return FAKE_PHASE_OFFSET_NS; } @@ -56,4 +58,4 @@ public: }; } // namespace scheduler -} // namespace android
\ No newline at end of file +} // namespace android diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp index 2b1dfa8f38..8e7440c2e3 100644 --- a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp +++ b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp @@ -25,7 +25,17 @@ public: protected: std::unique_ptr<LayerHistory> mLayerHistory; + static constexpr float MIN_REFRESH_RATE = 30.f; static constexpr float MAX_REFRESH_RATE = 90.f; + static constexpr auto RELEVANT_FRAME_THRESHOLD = 90u; + static constexpr uint64_t THIRTY_FPS_INTERVAL = 33'333'333; + + void forceRelevancy(const std::unique_ptr<LayerHistory::LayerHandle>& testLayer) { + mLayerHistory->setVisibility(testLayer, true); + for (auto i = 0u; i < RELEVANT_FRAME_THRESHOLD; i++) { + mLayerHistory->insert(testLayer, 0, false /*isHDR*/); + } + }; }; LayerHistoryTest::LayerHistoryTest() { @@ -36,31 +46,25 @@ LayerHistoryTest::~LayerHistoryTest() {} namespace { TEST_F(LayerHistoryTest, oneLayer) { std::unique_ptr<LayerHistory::LayerHandle> testLayer = - mLayerHistory->createLayer("TestLayer", MAX_REFRESH_RATE); + mLayerHistory->createLayer("TestLayer", MIN_REFRESH_RATE, MAX_REFRESH_RATE); mLayerHistory->setVisibility(testLayer, true); + for (auto i = 0u; i < RELEVANT_FRAME_THRESHOLD; i++) { + EXPECT_FLOAT_EQ(0.f, mLayerHistory->getDesiredRefreshRateAndHDR().first); + mLayerHistory->insert(testLayer, 0, false /*isHDR*/); + } - mLayerHistory->insert(testLayer, 0, false /*isHDR*/); - EXPECT_FLOAT_EQ(0.f, mLayerHistory->getDesiredRefreshRateAndHDR().first); - - mLayerHistory->insert(testLayer, 0, false /*isHDR*/); - mLayerHistory->insert(testLayer, 0, false /*isHDR*/); - mLayerHistory->insert(testLayer, 0, false /*isHDR*/); - // This is still 0, because the layer is not considered recently active if it - // has been present in less than 10 frames. - EXPECT_FLOAT_EQ(0.f, mLayerHistory->getDesiredRefreshRateAndHDR().first); - mLayerHistory->insert(testLayer, 0, false /*isHDR*/); - mLayerHistory->insert(testLayer, 0, false /*isHDR*/); - mLayerHistory->insert(testLayer, 0, false /*isHDR*/); - mLayerHistory->insert(testLayer, 0, false /*isHDR*/); - mLayerHistory->insert(testLayer, 0, false /*isHDR*/); - mLayerHistory->insert(testLayer, 0, false /*isHDR*/); - // This should be MAX_REFRESH_RATE as we have more than 10 samples - EXPECT_FLOAT_EQ(MAX_REFRESH_RATE, mLayerHistory->getDesiredRefreshRateAndHDR().first); + // Add a few more. This time we should get MAX refresh rate as the layer + // becomes relevant + static constexpr auto A_FEW = 10; + for (auto i = 0u; i < A_FEW; i++) { + EXPECT_FLOAT_EQ(MAX_REFRESH_RATE, mLayerHistory->getDesiredRefreshRateAndHDR().first); + mLayerHistory->insert(testLayer, 0, false /*isHDR*/); + } } TEST_F(LayerHistoryTest, oneHDRLayer) { std::unique_ptr<LayerHistory::LayerHandle> testLayer = - mLayerHistory->createLayer("TestHDRLayer", MAX_REFRESH_RATE); + mLayerHistory->createLayer("TestHDRLayer", MIN_REFRESH_RATE, MAX_REFRESH_RATE); mLayerHistory->setVisibility(testLayer, true); mLayerHistory->insert(testLayer, 0, true /*isHDR*/); @@ -74,12 +78,13 @@ TEST_F(LayerHistoryTest, oneHDRLayer) { TEST_F(LayerHistoryTest, explicitTimestamp) { std::unique_ptr<LayerHistory::LayerHandle> test30FpsLayer = - mLayerHistory->createLayer("30FpsLayer", MAX_REFRESH_RATE); + mLayerHistory->createLayer("30FpsLayer", MIN_REFRESH_RATE, MAX_REFRESH_RATE); mLayerHistory->setVisibility(test30FpsLayer, true); nsecs_t startTime = systemTime(); - for (int i = 0; i < 31; i++) { - mLayerHistory->insert(test30FpsLayer, startTime + (i * 33333333), false /*isHDR*/); + for (int i = 0; i < RELEVANT_FRAME_THRESHOLD; i++) { + mLayerHistory->insert(test30FpsLayer, startTime + (i * THIRTY_FPS_INTERVAL), + false /*isHDR*/); } EXPECT_FLOAT_EQ(30.f, mLayerHistory->getDesiredRefreshRateAndHDR().first); @@ -87,29 +92,31 @@ TEST_F(LayerHistoryTest, explicitTimestamp) { TEST_F(LayerHistoryTest, multipleLayers) { std::unique_ptr<LayerHistory::LayerHandle> testLayer = - mLayerHistory->createLayer("TestLayer", MAX_REFRESH_RATE); + mLayerHistory->createLayer("TestLayer", MIN_REFRESH_RATE, MAX_REFRESH_RATE); mLayerHistory->setVisibility(testLayer, true); std::unique_ptr<LayerHistory::LayerHandle> test30FpsLayer = - mLayerHistory->createLayer("30FpsLayer", MAX_REFRESH_RATE); + mLayerHistory->createLayer("30FpsLayer", MIN_REFRESH_RATE, MAX_REFRESH_RATE); mLayerHistory->setVisibility(test30FpsLayer, true); std::unique_ptr<LayerHistory::LayerHandle> testLayer2 = - mLayerHistory->createLayer("TestLayer2", MAX_REFRESH_RATE); + mLayerHistory->createLayer("TestLayer2", MIN_REFRESH_RATE, MAX_REFRESH_RATE); mLayerHistory->setVisibility(testLayer2, true); nsecs_t startTime = systemTime(); - for (int i = 0; i < 10; i++) { + for (int i = 0; i < RELEVANT_FRAME_THRESHOLD; i++) { mLayerHistory->insert(testLayer, 0, false /*isHDR*/); } EXPECT_FLOAT_EQ(MAX_REFRESH_RATE, mLayerHistory->getDesiredRefreshRateAndHDR().first); startTime = systemTime(); - for (int i = 0; i < 10; i++) { - mLayerHistory->insert(test30FpsLayer, startTime + (i * 33333333), false /*isHDR*/); + for (int i = 0; i < RELEVANT_FRAME_THRESHOLD; i++) { + mLayerHistory->insert(test30FpsLayer, startTime + (i * THIRTY_FPS_INTERVAL), + false /*isHDR*/); } EXPECT_FLOAT_EQ(MAX_REFRESH_RATE, mLayerHistory->getDesiredRefreshRateAndHDR().first); - for (int i = 10; i < 30; i++) { - mLayerHistory->insert(test30FpsLayer, startTime + (i * 33333333), false /*isHDR*/); + for (int i = 10; i < RELEVANT_FRAME_THRESHOLD; i++) { + mLayerHistory->insert(test30FpsLayer, startTime + (i * THIRTY_FPS_INTERVAL), + false /*isHDR*/); } EXPECT_FLOAT_EQ(MAX_REFRESH_RATE, mLayerHistory->getDesiredRefreshRateAndHDR().first); @@ -119,10 +126,12 @@ TEST_F(LayerHistoryTest, multipleLayers) { mLayerHistory->insert(testLayer2, 0, false /*isHDR*/); } EXPECT_FLOAT_EQ(MAX_REFRESH_RATE, mLayerHistory->getDesiredRefreshRateAndHDR().first); - // After 100 ms frames become obsolete. - std::this_thread::sleep_for(std::chrono::milliseconds(500)); - // Insert the 31st frame. - mLayerHistory->insert(test30FpsLayer, startTime + (30 * 33333333), false /*isHDR*/); + // After 1200 ms frames become obsolete. + std::this_thread::sleep_for(std::chrono::milliseconds(1500)); + + mLayerHistory->insert(test30FpsLayer, + startTime + (RELEVANT_FRAME_THRESHOLD * THIRTY_FPS_INTERVAL), + false /*isHDR*/); EXPECT_FLOAT_EQ(30.f, mLayerHistory->getDesiredRefreshRateAndHDR().first); } diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp index 1f8b11180b..740115ea32 100644 --- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp +++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp @@ -25,7 +25,8 @@ protected: class MockEventThreadConnection : public android::EventThreadConnection { public: explicit MockEventThreadConnection(EventThread* eventThread) - : EventThreadConnection(eventThread, ResyncCallback()) {} + : EventThreadConnection(eventThread, ResyncCallback(), + ISurfaceComposer::eConfigChangedSuppress) {} ~MockEventThreadConnection() = default; MOCK_METHOD1(stealReceiveChannel, status_t(gui::BitTube* outChannel)); @@ -47,7 +48,7 @@ protected: std::unique_ptr<EventThread> makeEventThread( const char* /* connectionName */, DispSync* /* dispSync */, - nsecs_t /* phaseOffsetNs */, + nsecs_t /* phaseOffsetNs */, nsecs_t /* offsetThresholdForNextVsync */, impl::EventThread::InterceptVSyncsCallback /* interceptCallback */) override { return std::move(mEventThread); } @@ -81,10 +82,10 @@ SchedulerTest::SchedulerTest() { // createConnection call to scheduler makes a createEventConnection call to EventThread. Make // sure that call gets executed and returns an EventThread::Connection object. - EXPECT_CALL(*mEventThread, createEventConnection(_)) + EXPECT_CALL(*mEventThread, createEventConnection(_, _)) .WillRepeatedly(Return(mEventThreadConnection)); - mConnectionHandle = mScheduler->createConnection("appConnection", 16, ResyncCallback(), + mConnectionHandle = mScheduler->createConnection("appConnection", 16, 16, ResyncCallback(), impl::EventThread::InterceptVSyncsCallback()); EXPECT_TRUE(mConnectionHandle != nullptr); } @@ -105,7 +106,10 @@ TEST_F(SchedulerTest, testNullPtr) { // exceptions, just gracefully continues. sp<IDisplayEventConnection> returnedValue; ASSERT_NO_FATAL_FAILURE( - returnedValue = mScheduler->createDisplayEventConnection(nullptr, ResyncCallback())); + returnedValue = + mScheduler->createDisplayEventConnection(nullptr, ResyncCallback(), + ISurfaceComposer:: + eConfigChangedSuppress)); EXPECT_TRUE(returnedValue == nullptr); EXPECT_TRUE(mScheduler->getEventThread(nullptr) == nullptr); EXPECT_TRUE(mScheduler->getEventConnection(nullptr) == nullptr); @@ -126,7 +130,9 @@ TEST_F(SchedulerTest, invalidConnectionHandle) { sp<IDisplayEventConnection> returnedValue; ASSERT_NO_FATAL_FAILURE( returnedValue = - mScheduler->createDisplayEventConnection(connectionHandle, ResyncCallback())); + mScheduler->createDisplayEventConnection(connectionHandle, ResyncCallback(), + ISurfaceComposer:: + eConfigChangedSuppress)); EXPECT_TRUE(returnedValue == nullptr); EXPECT_TRUE(mScheduler->getEventThread(connectionHandle) == nullptr); EXPECT_TRUE(mScheduler->getEventConnection(connectionHandle) == nullptr); @@ -155,7 +161,9 @@ TEST_F(SchedulerTest, validConnectionHandle) { sp<IDisplayEventConnection> returnedValue; ASSERT_NO_FATAL_FAILURE( returnedValue = - mScheduler->createDisplayEventConnection(mConnectionHandle, ResyncCallback())); + mScheduler->createDisplayEventConnection(mConnectionHandle, ResyncCallback(), + ISurfaceComposer:: + eConfigChangedSuppress)); EXPECT_TRUE(returnedValue != nullptr); ASSERT_EQ(returnedValue, mEventThreadConnection); diff --git a/services/surfaceflinger/tests/unittests/TestableScheduler.h b/services/surfaceflinger/tests/unittests/TestableScheduler.h index c3d2b8de4f..cb6980ed1a 100644 --- a/services/surfaceflinger/tests/unittests/TestableScheduler.h +++ b/services/surfaceflinger/tests/unittests/TestableScheduler.h @@ -17,6 +17,7 @@ #pragma once #include <gmock/gmock.h> +#include <gui/ISurfaceComposer.h> #include "Scheduler/EventThread.h" #include "Scheduler/RefreshRateConfigs.h" @@ -34,7 +35,8 @@ public: // Scheduler::Connection. This allows plugging in mock::EventThread. sp<Scheduler::ConnectionHandle> addConnection(std::unique_ptr<EventThread> eventThread) { sp<EventThreadConnection> eventThreadConnection = - new EventThreadConnection(eventThread.get(), ResyncCallback()); + new EventThreadConnection(eventThread.get(), ResyncCallback(), + ISurfaceComposer::eConfigChangedSuppress); const int64_t id = sNextId++; mConnections.emplace(id, std::make_unique<Scheduler::Connection>(new ConnectionHandle(id), diff --git a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h index 5b5f8e7fab..ed35ebf2b6 100644 --- a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h +++ b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h @@ -28,7 +28,8 @@ public: EventThread(); ~EventThread() override; - MOCK_CONST_METHOD1(createEventConnection, sp<EventThreadConnection>(ResyncCallback)); + MOCK_CONST_METHOD2(createEventConnection, + sp<EventThreadConnection>(ResyncCallback, ISurfaceComposer::ConfigChanged)); MOCK_METHOD0(onScreenReleased, void()); MOCK_METHOD0(onScreenAcquired, void()); MOCK_METHOD2(onHotplugReceived, void(PhysicalDisplayId, bool)); diff --git a/vulkan/libvulkan/Android.bp b/vulkan/libvulkan/Android.bp index b0c4f3f95a..4d6b2be301 100644 --- a/vulkan/libvulkan/Android.bp +++ b/vulkan/libvulkan/Android.bp @@ -41,12 +41,13 @@ cc_library_shared { "-DVK_NO_PROTOTYPES", "-fvisibility=hidden", "-fstrict-aliasing", - "-Weverything", + "-Wextra", "-Werror", "-Wno-padded", + "-Wno-sign-compare", "-Wno-switch-enum", - "-Wno-undef", - "-Wno-format-pedantic", + "-Wno-unused-variable", + "-Wno-unused-function", // Have clang emit complete debug_info. "-fstandalone-debug", diff --git a/vulkan/libvulkan/driver.cpp b/vulkan/libvulkan/driver.cpp index c77fa064e6..74773517ae 100644 --- a/vulkan/libvulkan/driver.cpp +++ b/vulkan/libvulkan/driver.cpp @@ -24,7 +24,10 @@ #include <dlfcn.h> #include <algorithm> #include <array> +#include <climits> #include <new> +#include <sstream> +#include <string> #include <log/log.h> @@ -153,15 +156,12 @@ class CreateInfoWrapper { Hal Hal::hal_; void* LoadLibrary(const android_dlextinfo& dlextinfo, - const char* subname, - int subname_len) { + const std::string_view subname) { ATRACE_CALL(); - const char kLibFormat[] = "vulkan.%*s.so"; - char* name = static_cast<char*>( - alloca(sizeof(kLibFormat) + static_cast<size_t>(subname_len))); - sprintf(name, kLibFormat, subname_len, subname); - return android_dlopen_ext(name, RTLD_LOCAL | RTLD_NOW, &dlextinfo); + std::stringstream ss; + ss << "vulkan." << subname << ".so"; + return android_dlopen_ext(ss.str().c_str(), RTLD_LOCAL | RTLD_NOW, &dlextinfo); } const std::array<const char*, 2> HAL_SUBNAME_KEY_PROPERTIES = {{ @@ -181,8 +181,9 @@ int LoadDriver(android_namespace_t* library_namespace, char prop[PROPERTY_VALUE_MAX]; for (auto key : HAL_SUBNAME_KEY_PROPERTIES) { int prop_len = property_get(key, prop, nullptr); - if (prop_len > 0) { - so = LoadLibrary(dlextinfo, prop, prop_len); + if (prop_len > 0 && prop_len <= UINT_MAX) { + std::string_view lib_name(prop, static_cast<unsigned int>(prop_len)); + so = LoadLibrary(dlextinfo, lib_name); if (so) break; } @@ -1207,7 +1208,8 @@ VkResult CreateDevice(VkPhysicalDevice physicalDevice, if (properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_CPU) { // Log that the app is hitting software Vulkan implementation - android::GraphicsEnv::getInstance().setCpuVulkanInUse(); + android::GraphicsEnv::getInstance().setTargetStats( + android::GraphicsEnv::Stats::CPU_VULKAN_IN_USE); } data->driver_device = dev; diff --git a/vulkan/libvulkan/layers_extensions.cpp b/vulkan/libvulkan/layers_extensions.cpp index 5679412732..dd917393d1 100644 --- a/vulkan/libvulkan/layers_extensions.cpp +++ b/vulkan/libvulkan/layers_extensions.cpp @@ -24,6 +24,7 @@ #include <string.h> #include <sys/prctl.h> +#include <memory> #include <mutex> #include <string> #include <vector> @@ -101,9 +102,7 @@ class LayerLibrary { bool EnumerateLayers(size_t library_idx, std::vector<Layer>& instance_layers) const; - void* GetGPA(const Layer& layer, - const char* gpa_name, - size_t gpa_name_len) const; + void* GetGPA(const Layer& layer, const std::string_view gpa_name) const; const std::string GetFilename() { return filename_; } @@ -226,17 +225,10 @@ bool LayerLibrary::EnumerateLayers(size_t library_idx, } // get layer properties - VkLayerProperties* properties = static_cast<VkLayerProperties*>(alloca( - (num_instance_layers + num_device_layers) * sizeof(VkLayerProperties))); - result = enumerate_instance_layers(&num_instance_layers, properties); - if (result != VK_SUCCESS) { - ALOGE("vkEnumerateInstanceLayerProperties failed for library '%s': %d", - path_.c_str(), result); - return false; - } + auto properties = std::make_unique<VkLayerProperties[]>(num_instance_layers + num_device_layers); if (num_device_layers > 0) { result = enumerate_device_layers(VK_NULL_HANDLE, &num_device_layers, - properties + num_instance_layers); + properties.get() + num_instance_layers); if (result != VK_SUCCESS) { ALOGE( "vkEnumerateDeviceLayerProperties failed for library '%s': %d", @@ -321,21 +313,11 @@ bool LayerLibrary::EnumerateLayers(size_t library_idx, return true; } -void* LayerLibrary::GetGPA(const Layer& layer, - const char* gpa_name, - size_t gpa_name_len) const { - void* gpa; - size_t layer_name_len = - std::max(size_t{2}, strlen(layer.properties.layerName)); - char* name = static_cast<char*>(alloca(layer_name_len + gpa_name_len + 1)); - strcpy(name, layer.properties.layerName); - strcpy(name + layer_name_len, gpa_name); - if (!(gpa = GetTrampoline(name))) { - strcpy(name, "vk"); - strcpy(name + 2, gpa_name); - gpa = GetTrampoline(name); - } - return gpa; +void* LayerLibrary::GetGPA(const Layer& layer, const std::string_view gpa_name) const { + std::string layer_name { layer.properties.layerName }; + if (void* gpa = GetTrampoline((layer_name.append(gpa_name).c_str()))) + return gpa; + return GetTrampoline((std::string {"vk"}.append(gpa_name)).c_str()); } // ---------------------------------------------------------------------------- @@ -470,10 +452,9 @@ const VkExtensionProperties* FindExtension( } void* GetLayerGetProcAddr(const Layer& layer, - const char* gpa_name, - size_t gpa_name_len) { + const std::string_view gpa_name) { const LayerLibrary& library = g_layer_libraries[layer.library_idx]; - return library.GetGPA(layer, gpa_name, gpa_name_len); + return library.GetGPA(layer, gpa_name); } } // anonymous namespace @@ -556,13 +537,13 @@ LayerRef::LayerRef(LayerRef&& other) noexcept : layer_(other.layer_) { PFN_vkGetInstanceProcAddr LayerRef::GetGetInstanceProcAddr() const { return layer_ ? reinterpret_cast<PFN_vkGetInstanceProcAddr>( - GetLayerGetProcAddr(*layer_, "GetInstanceProcAddr", 19)) + GetLayerGetProcAddr(*layer_, "GetInstanceProcAddr")) : nullptr; } PFN_vkGetDeviceProcAddr LayerRef::GetGetDeviceProcAddr() const { return layer_ ? reinterpret_cast<PFN_vkGetDeviceProcAddr>( - GetLayerGetProcAddr(*layer_, "GetDeviceProcAddr", 17)) + GetLayerGetProcAddr(*layer_, "GetDeviceProcAddr")) : nullptr; } diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp index cc0df08835..766d9ff8be 100644 --- a/vulkan/libvulkan/swapchain.cpp +++ b/vulkan/libvulkan/swapchain.cpp @@ -718,8 +718,6 @@ VkResult GetPhysicalDeviceSurfaceFormatsKHR(VkPhysicalDevice pdev, {VK_FORMAT_R8G8B8A8_UNORM, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR}, {VK_FORMAT_R8G8B8A8_SRGB, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR}, {VK_FORMAT_R5G6B5_UNORM_PACK16, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR}, - {VK_FORMAT_A2B10G10R10_UNORM_PACK32, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR}, - {VK_FORMAT_R16G16B16A16_SFLOAT, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR}, }; const uint32_t kNumFormats = sizeof(kFormats) / sizeof(kFormats[0]); uint32_t total_num_formats = kNumFormats; @@ -1304,7 +1302,14 @@ VkResult CreateSwapchainKHR(VkDevice device, // TODO(jessehall): Improve error reporting. Can we enumerate // possible errors and translate them to valid Vulkan result codes? ALOGE("dequeueBuffer[%u] failed: %s (%d)", i, strerror(-err), err); - result = VK_ERROR_SURFACE_LOST_KHR; + switch (-err) { + case ENOMEM: + result = VK_ERROR_OUT_OF_DEVICE_MEMORY; + break; + default: + result = VK_ERROR_SURFACE_LOST_KHR; + break; + } break; } img.buffer = buffer; diff --git a/vulkan/nulldrv/Android.bp b/vulkan/nulldrv/Android.bp index dedf419dc3..ba025046fa 100644 --- a/vulkan/nulldrv/Android.bp +++ b/vulkan/nulldrv/Android.bp @@ -23,18 +23,11 @@ cc_library_shared { "-fvisibility=hidden", "-fstrict-aliasing", "-DLOG_TAG=\"vknulldrv\"", - "-Weverything", + "-Wextra", "-Werror", - "-Wno-padded", - "-Wno-undef", - "-Wno-zero-length-array", "-DLOG_NDEBUG=0", ], - cppflags: [ - "-Wno-c++98-compat-pedantic", - "-Wno-c99-extensions", - ], srcs: [ "null_driver.cpp", diff --git a/vulkan/tools/Android.bp b/vulkan/tools/Android.bp index 2514094a15..91d64fe1c9 100644 --- a/vulkan/tools/Android.bp +++ b/vulkan/tools/Android.bp @@ -22,16 +22,8 @@ cc_binary { "-DLOG_TAG=\"vkinfo\"", - "-Weverything", + "-Wextra", "-Werror", - "-Wno-padded", - "-Wno-undef", - "-Wno-switch-enum", - ], - cppflags: [ - "-Wno-c++98-compat-pedantic", - "-Wno-c99-extensions", - "-Wno-old-style-cast", ], srcs: ["vkinfo.cpp"], |