Merge "Create SessionManager in ADPF PowerAdvisor" into main
diff --git a/cmds/idlcli/Android.bp b/cmds/idlcli/Android.bp
index 50c2cd8..36dcbca 100644
--- a/cmds/idlcli/Android.bp
+++ b/cmds/idlcli/Android.bp
@@ -50,6 +50,7 @@
"vibrator/CommandAlwaysOnEnable.cpp",
"vibrator/CommandCompose.cpp",
"vibrator/CommandComposePwle.cpp",
+ "vibrator/CommandGetFrequencyToOutputAccelerationMap.cpp",
"vibrator/CommandGetBandwidthAmplitudeMap.cpp",
"vibrator/CommandGetCapabilities.cpp",
"vibrator/CommandGetCompositionDelayMax.cpp",
@@ -72,6 +73,11 @@
"vibrator/CommandSetExternalControl.cpp",
"vibrator/CommandSupportsAmplitudeControl.cpp",
"vibrator/CommandSupportsExternalControl.cpp",
+ "vibrator/CommandGetPwleV2PrimitiveDurationMaxMillis.cpp",
+ "vibrator/CommandGetPwleV2CompositionSizeMax.cpp",
+ "vibrator/CommandGetPwleV2PrimitiveDurationMinMillis.cpp",
+ "vibrator/CommandComposePwleV2.cpp",
+ "vibrator/CommandPerformVendorEffect.cpp",
],
visibility: [":__subpackages__"],
}
diff --git a/cmds/idlcli/vibrator/CommandComposePwleV2.cpp b/cmds/idlcli/vibrator/CommandComposePwleV2.cpp
new file mode 100644
index 0000000..6d3cf84
--- /dev/null
+++ b/cmds/idlcli/vibrator/CommandComposePwleV2.cpp
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2024 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 <stdlib.h>
+
+#include <charconv>
+
+#include "utils.h"
+#include "vibrator.h"
+
+namespace android {
+namespace idlcli {
+
+class CommandVibrator;
+
+namespace vibrator {
+
+using aidl::CompositePwleV2;
+using aidl::PwleV2Primitive;
+
+class CommandComposePwleV2 : public Command {
+ std::string getDescription() const override { return "Compose normalized PWLE vibration."; }
+
+ std::string getUsageSummary() const override {
+ return "[options] <time> <frequency> <amplitude> ...";
+ }
+
+ UsageDetails getUsageDetails() const override {
+ UsageDetails details{
+ {"-b", {"Block for duration of vibration."}},
+ {"<time>", {"Segment duration in milliseconds"}},
+ {"<frequency>", {"Target frequency in Hz"}},
+ {"<amplitude>", {"Target amplitude in [0.0, 1.0]"}},
+ {"...", {"May repeat multiple times."}},
+ };
+ return details;
+ }
+
+ Status doArgs(Args& args) override {
+ while (args.get<std::string>().value_or("").find("-") == 0) {
+ auto opt = *args.pop<std::string>();
+ if (opt == "--") {
+ break;
+ } else if (opt == "-b") {
+ mBlocking = true;
+ } else {
+ std::cerr << "Invalid Option '" << opt << "'!" << std::endl;
+ return USAGE;
+ }
+ }
+
+ if (args.empty()) {
+ std::cerr << "Missing arguments! Please see usage" << std::endl;
+ return USAGE;
+ }
+
+ while (!args.empty()) {
+ PwleV2Primitive segment;
+
+ if (auto timeMs = args.pop<decltype(segment.timeMillis)>();
+ timeMs && *timeMs >= 0 && *timeMs <= 0x7ffff) {
+ segment.timeMillis = *timeMs;
+ std::cout << "Time: " << segment.timeMillis << std::endl;
+ } else {
+ std::cerr << "Missing or Invalid Time!" << std::endl;
+ return USAGE;
+ }
+
+ if (auto frequencyHz = args.pop<decltype(segment.frequencyHz)>();
+ frequencyHz && *frequencyHz >= 30 && *frequencyHz <= 300) {
+ segment.frequencyHz = *frequencyHz;
+ std::cout << "Frequency: " << segment.frequencyHz << std::endl;
+ } else {
+ std::cerr << "Missing or Invalid Frequency!" << std::endl;
+ return USAGE;
+ }
+
+ if (auto amplitude = args.pop<decltype(segment.amplitude)>();
+ amplitude && *amplitude >= 0 && *amplitude <= 1.0) {
+ segment.amplitude = *amplitude;
+ std::cout << "Amplitude: " << segment.amplitude << std::endl;
+ } else {
+ std::cerr << "Missing or Invalid Amplitude!" << std::endl;
+ return USAGE;
+ }
+
+ mCompositePwle.pwlePrimitives.emplace_back(std::move(segment));
+ }
+
+ if (!args.empty()) {
+ std::cerr << "Unexpected Arguments!" << std::endl;
+ return USAGE;
+ }
+
+ return OK;
+ }
+
+ Status doMain(Args&& /*args*/) override {
+ auto hal = getHal<aidl::IVibrator>();
+
+ if (!hal) {
+ return UNAVAILABLE;
+ }
+
+ ABinderProcess_setThreadPoolMaxThreadCount(1);
+ ABinderProcess_startThreadPool();
+
+ std::shared_ptr<VibratorCallback> callback;
+
+ if (mBlocking) {
+ callback = ndk::SharedRefBase::make<VibratorCallback>();
+ }
+
+ auto status = hal->call(&aidl::IVibrator::composePwleV2, mCompositePwle, callback);
+
+ if (status.isOk() && callback) {
+ callback->waitForComplete();
+ }
+
+ std::cout << "Status: " << status.getDescription() << std::endl;
+
+ return status.isOk() ? OK : ERROR;
+ }
+
+ bool mBlocking;
+ CompositePwleV2 mCompositePwle;
+};
+
+static const auto Command =
+ CommandRegistry<CommandVibrator>::Register<CommandComposePwleV2>("composePwleV2");
+
+} // namespace vibrator
+} // namespace idlcli
+} // namespace android
diff --git a/cmds/idlcli/vibrator/CommandGetFrequencyToOutputAccelerationMap.cpp b/cmds/idlcli/vibrator/CommandGetFrequencyToOutputAccelerationMap.cpp
new file mode 100644
index 0000000..2edd0ca
--- /dev/null
+++ b/cmds/idlcli/vibrator/CommandGetFrequencyToOutputAccelerationMap.cpp
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2024 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::FrequencyAccelerationMapEntry;
+
+class CommandGetFrequencyToOutputAccelerationMap : public Command {
+ std::string getDescription() const override {
+ return "Retrieves vibrator frequency to output acceleration map.";
+ }
+
+ std::string getUsageSummary() const override { return ""; }
+
+ UsageDetails getUsageDetails() const override {
+ UsageDetails details{};
+ return details;
+ }
+
+ Status doArgs(Args& args) override {
+ if (!args.empty()) {
+ std::cerr << "Unexpected Arguments!" << std::endl;
+ return USAGE;
+ }
+ return OK;
+ }
+
+ Status doMain(Args&& /*args*/) override {
+ std::string statusStr;
+ std::vector<FrequencyAccelerationMapEntry> frequencyToOutputAccelerationMap;
+ Status ret;
+
+ if (auto hal = getHal<aidl::IVibrator>()) {
+ auto status = hal->call(&aidl::IVibrator::getFrequencyToOutputAccelerationMap,
+ &frequencyToOutputAccelerationMap);
+ statusStr = status.getDescription();
+ ret = (status.isOk() ? OK : ERROR);
+ } else {
+ return UNAVAILABLE;
+ }
+
+ std::cout << "Status: " << statusStr << std::endl;
+ std::cout << "Frequency to Output Amplitude Map: " << std::endl;
+ for (auto& entry : frequencyToOutputAccelerationMap) {
+ std::cout << entry.frequencyHz << " " << entry.maxOutputAccelerationGs << std::endl;
+ }
+
+ return ret;
+ }
+};
+
+static const auto Command =
+ CommandRegistry<CommandVibrator>::Register<CommandGetFrequencyToOutputAccelerationMap>(
+ "getFrequencyToOutputAccelerationMap");
+
+} // namespace vibrator
+} // namespace idlcli
+} // namespace android
diff --git a/cmds/idlcli/vibrator/CommandGetPwleV2CompositionSizeMax.cpp b/cmds/idlcli/vibrator/CommandGetPwleV2CompositionSizeMax.cpp
new file mode 100644
index 0000000..cca072c
--- /dev/null
+++ b/cmds/idlcli/vibrator/CommandGetPwleV2CompositionSizeMax.cpp
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2024 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 CommandGetPwleV2CompositionSizeMax : public Command {
+ std::string getDescription() const override {
+ return "Retrieves vibrator PwleV2 max composition size.";
+ }
+
+ 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::getPwleV2CompositionSizeMax, &maxSize);
+ statusStr = status.getDescription();
+ 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<CommandGetPwleV2CompositionSizeMax>(
+ "getPwleV2CompositionSizeMax");
+
+} // namespace vibrator
+} // namespace idlcli
+} // namespace android
diff --git a/cmds/idlcli/vibrator/CommandGetPwleV2PrimitiveDurationMaxMillis.cpp b/cmds/idlcli/vibrator/CommandGetPwleV2PrimitiveDurationMaxMillis.cpp
new file mode 100644
index 0000000..dbbfe1a
--- /dev/null
+++ b/cmds/idlcli/vibrator/CommandGetPwleV2PrimitiveDurationMaxMillis.cpp
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2024 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 CommandGetPwleV2PrimitiveDurationMaxMillis : public Command {
+ std::string getDescription() const override {
+ return "Retrieves vibrator PwleV2 max primitive duration in milliseconds.";
+ }
+
+ 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 maxDurationMs;
+ Status ret;
+
+ if (auto hal = getHal<aidl::IVibrator>()) {
+ auto status = hal->call(&aidl::IVibrator::getPwleV2PrimitiveDurationMaxMillis,
+ &maxDurationMs);
+ statusStr = status.getDescription();
+ ret = status.isOk() ? OK : ERROR;
+ } else {
+ return UNAVAILABLE;
+ }
+
+ std::cout << "Status: " << statusStr << std::endl;
+ std::cout << "Primitive duration max: " << maxDurationMs << " ms" << std::endl;
+
+ return ret;
+ }
+};
+
+static const auto Command =
+ CommandRegistry<CommandVibrator>::Register<CommandGetPwleV2PrimitiveDurationMaxMillis>(
+ "getPwleV2PrimitiveDurationMaxMillis");
+
+} // namespace vibrator
+} // namespace idlcli
+} // namespace android
diff --git a/cmds/idlcli/vibrator/CommandGetPwleV2PrimitiveDurationMinMillis.cpp b/cmds/idlcli/vibrator/CommandGetPwleV2PrimitiveDurationMinMillis.cpp
new file mode 100644
index 0000000..09225c4
--- /dev/null
+++ b/cmds/idlcli/vibrator/CommandGetPwleV2PrimitiveDurationMinMillis.cpp
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2024 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 CommandGetPwleV2PrimitiveDurationMinMillis : public Command {
+ std::string getDescription() const override {
+ return "Retrieves vibrator PwleV2 minimum primitive duration in milliseconds.";
+ }
+
+ 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 minDurationMs;
+ Status ret;
+
+ if (auto hal = getHal<aidl::IVibrator>()) {
+ auto status = hal->call(&aidl::IVibrator::getPwleV2PrimitiveDurationMinMillis,
+ &minDurationMs);
+ statusStr = status.getDescription();
+ ret = status.isOk() ? OK : ERROR;
+ } else {
+ return UNAVAILABLE;
+ }
+
+ std::cout << "Status: " << statusStr << std::endl;
+ std::cout << "Primitive duration min: " << minDurationMs << " ms" << std::endl;
+
+ return ret;
+ }
+};
+
+static const auto Command =
+ CommandRegistry<CommandVibrator>::Register<CommandGetPwleV2PrimitiveDurationMinMillis>(
+ "getPwleV2PrimitiveDurationMinMillis");
+
+} // namespace vibrator
+} // namespace idlcli
+} // namespace android
diff --git a/cmds/idlcli/vibrator/CommandPerformVendorEffect.cpp b/cmds/idlcli/vibrator/CommandPerformVendorEffect.cpp
new file mode 100644
index 0000000..9c25bd2
--- /dev/null
+++ b/cmds/idlcli/vibrator/CommandPerformVendorEffect.cpp
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2024 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 <thread>
+
+#include "utils.h"
+#include "vibrator.h"
+
+using std::chrono::milliseconds;
+using std::this_thread::sleep_for;
+
+namespace android {
+namespace idlcli {
+
+class CommandVibrator;
+
+namespace vibrator {
+
+using aidl::VendorEffect;
+
+class CommandPerformVendorEffect : public Command {
+ std::string getDescription() const override { return "Perform vendor vibration effect."; }
+
+ std::string getUsageSummary() const override { return "[options] <none>"; }
+
+ UsageDetails getUsageDetails() const override {
+ UsageDetails details{
+ {"-b", {"Block for duration of vibration."}},
+ {"<none>", {"No valid input."}},
+ };
+ return details;
+ }
+
+ Status doArgs(Args& args) override {
+ while (args.get<std::string>().value_or("").find("-") == 0) {
+ auto opt = *args.pop<std::string>();
+ if (opt == "--") {
+ break;
+ } else if (opt == "-b") {
+ mBlocking = true;
+ } else {
+ std::cerr << "Invalid Option '" << opt << "'!" << std::endl;
+ return USAGE;
+ }
+ }
+
+ return OK;
+ }
+
+ Status doMain(Args&& /*args*/) override { return UNAVAILABLE; }
+
+ bool mBlocking;
+ VendorEffect mEffect;
+};
+
+static const auto Command = CommandRegistry<CommandVibrator>::Register<CommandPerformVendorEffect>(
+ "performVendorEffect");
+
+} // namespace vibrator
+} // namespace idlcli
+} // namespace android
diff --git a/cmds/installd/tests/fuzzers/InstalldServiceFuzzer.cpp b/cmds/installd/tests/fuzzers/InstalldServiceFuzzer.cpp
index b1c6940..50ea0c7 100644
--- a/cmds/installd/tests/fuzzers/InstalldServiceFuzzer.cpp
+++ b/cmds/installd/tests/fuzzers/InstalldServiceFuzzer.cpp
@@ -47,6 +47,8 @@
} // namespace android
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ // TODO(b/183141167): need to rewrite 'dump' to avoid SIGPIPE.
+ signal(SIGPIPE, SIG_IGN);
auto service = sp<InstalldNativeService>::make();
fuzzService(service, FuzzedDataProvider(data, size));
return 0;
diff --git a/cmds/servicemanager/ServiceManager.cpp b/cmds/servicemanager/ServiceManager.cpp
index fa7cb64..38a125b 100644
--- a/cmds/servicemanager/ServiceManager.cpp
+++ b/cmds/servicemanager/ServiceManager.cpp
@@ -396,7 +396,7 @@
SM_PERFETTO_TRACE_FUNC(PERFETTO_TE_PROTO_FIELDS(
PERFETTO_TE_PROTO_FIELD_CSTR(kProtoServiceName, name.c_str())));
- *outBinder = tryGetBinder(name, true);
+ *outBinder = tryGetBinder(name, true).service;
// returns ok regardless of result for legacy reasons
return Status::ok();
}
@@ -430,13 +430,15 @@
return os::Service::make<os::Service::Tag::accessor>(nullptr);
}
return os::Service::make<os::Service::Tag::accessor>(
- tryGetBinder(*accessorName, startIfNotFound));
+ tryGetBinder(*accessorName, startIfNotFound).service);
} else {
- return os::Service::make<os::Service::Tag::binder>(tryGetBinder(name, startIfNotFound));
+ return os::Service::make<os::Service::Tag::serviceWithMetadata>(
+ tryGetBinder(name, startIfNotFound));
}
}
-sp<IBinder> ServiceManager::tryGetBinder(const std::string& name, bool startIfNotFound) {
+os::ServiceWithMetadata ServiceManager::tryGetBinder(const std::string& name,
+ bool startIfNotFound) {
SM_PERFETTO_TRACE_FUNC(PERFETTO_TE_PROTO_FIELDS(
PERFETTO_TE_PROTO_FIELD_CSTR(kProtoServiceName, name.c_str())));
@@ -450,13 +452,13 @@
if (!service->allowIsolated && is_multiuser_uid_isolated(ctx.uid)) {
LOG(WARNING) << "Isolated app with UID " << ctx.uid << " requested '" << name
<< "', but the service is not allowed for isolated apps.";
- return nullptr;
+ return os::ServiceWithMetadata();
}
out = service->binder;
}
if (!mAccess->canFind(ctx, name)) {
- return nullptr;
+ return os::ServiceWithMetadata();
}
if (!out && startIfNotFound) {
@@ -473,8 +475,11 @@
CHECK(handleServiceClientCallback(2 /* sm + transaction */, name, false));
service->guaranteeClient = true;
}
-
- return out;
+ os::ServiceWithMetadata serviceWithMetadata = os::ServiceWithMetadata();
+ serviceWithMetadata.service = out;
+ serviceWithMetadata.isLazyService =
+ service ? service->dumpPriority & FLAG_IS_LAZY_SERVICE : false;
+ return serviceWithMetadata;
}
bool isValidServiceName(const std::string& name) {
diff --git a/cmds/servicemanager/ServiceManager.h b/cmds/servicemanager/ServiceManager.h
index c92141b..964abee 100644
--- a/cmds/servicemanager/ServiceManager.h
+++ b/cmds/servicemanager/ServiceManager.h
@@ -114,7 +114,7 @@
void removeClientCallback(const wp<IBinder>& who, ClientCallbackMap::iterator* it);
os::Service tryGetService(const std::string& name, bool startIfNotFound);
- sp<IBinder> tryGetBinder(const std::string& name, bool startIfNotFound);
+ os::ServiceWithMetadata tryGetBinder(const std::string& name, bool startIfNotFound);
binder::Status canAddService(const Access::CallingContext& ctx, const std::string& name,
std::optional<std::string>* accessor);
binder::Status canFindService(const Access::CallingContext& ctx, const std::string& name,
diff --git a/cmds/servicemanager/main.cpp b/cmds/servicemanager/main.cpp
index c126e91..df5a8ed 100644
--- a/cmds/servicemanager/main.cpp
+++ b/cmds/servicemanager/main.cpp
@@ -165,6 +165,7 @@
IPCThreadState::self()->disableBackgroundScheduling(true);
sp<ServiceManager> manager = sp<ServiceManager>::make(std::make_unique<Access>());
+ manager->setRequestingSid(true);
if (!manager->addService("manager", manager, false /*allowIsolated*/, IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()) {
LOG(ERROR) << "Could not self register servicemanager";
}
diff --git a/cmds/servicemanager/test_sm.cpp b/cmds/servicemanager/test_sm.cpp
index 95f459f..e620770 100644
--- a/cmds/servicemanager/test_sm.cpp
+++ b/cmds/servicemanager/test_sm.cpp
@@ -92,6 +92,11 @@
auto sm = getPermissiveServiceManager();
EXPECT_TRUE(sm->addService("foo", getBinder(), false /*allowIsolated*/,
IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk());
+
+ EXPECT_TRUE(sm->addService("lazyfoo", getBinder(), false /*allowIsolated*/,
+ IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT |
+ IServiceManager::FLAG_IS_LAZY_SERVICE)
+ .isOk());
}
TEST(AddService, EmptyNameDisallowed) {
@@ -156,7 +161,7 @@
Service outA;
EXPECT_TRUE(sm->getService2("foo", &outA).isOk());
- EXPECT_EQ(serviceA, outA.get<Service::Tag::binder>());
+ EXPECT_EQ(serviceA, outA.get<Service::Tag::serviceWithMetadata>().service);
sp<IBinder> outBinderA;
EXPECT_TRUE(sm->getService("foo", &outBinderA).isOk());
EXPECT_EQ(serviceA, outBinderA);
@@ -168,7 +173,7 @@
Service outB;
EXPECT_TRUE(sm->getService2("foo", &outB).isOk());
- EXPECT_EQ(serviceB, outB.get<Service::Tag::binder>());
+ EXPECT_EQ(serviceB, outB.get<Service::Tag::serviceWithMetadata>().service);
sp<IBinder> outBinderB;
EXPECT_TRUE(sm->getService("foo", &outBinderB).isOk());
EXPECT_EQ(serviceB, outBinderB);
@@ -195,7 +200,7 @@
Service out;
EXPECT_TRUE(sm->getService2("foo", &out).isOk());
- EXPECT_EQ(service, out.get<Service::Tag::binder>());
+ EXPECT_EQ(service, out.get<Service::Tag::serviceWithMetadata>().service);
sp<IBinder> outBinder;
EXPECT_TRUE(sm->getService("foo", &outBinder).isOk());
EXPECT_EQ(service, outBinder);
@@ -206,7 +211,7 @@
Service out;
EXPECT_TRUE(sm->getService2("foo", &out).isOk());
- EXPECT_EQ(nullptr, out.get<Service::Tag::binder>());
+ EXPECT_EQ(nullptr, out.get<Service::Tag::serviceWithMetadata>().service);
sp<IBinder> outBinder;
EXPECT_TRUE(sm->getService("foo", &outBinder).isOk());
EXPECT_EQ(nullptr, outBinder);
@@ -227,7 +232,7 @@
Service out;
// returns nullptr but has OK status for legacy compatibility
EXPECT_TRUE(sm->getService2("foo", &out).isOk());
- EXPECT_EQ(nullptr, out.get<Service::Tag::binder>());
+ EXPECT_EQ(nullptr, out.get<Service::Tag::serviceWithMetadata>().service);
sp<IBinder> outBinder;
EXPECT_TRUE(sm->getService("foo", &outBinder).isOk());
EXPECT_EQ(nullptr, outBinder);
@@ -257,7 +262,7 @@
Service out;
EXPECT_TRUE(sm->getService2("foo", &out).isOk());
- EXPECT_EQ(service, out.get<Service::Tag::binder>());
+ EXPECT_EQ(service, out.get<Service::Tag::serviceWithMetadata>().service);
sp<IBinder> outBinder;
EXPECT_TRUE(sm->getService("foo", &outBinder).isOk());
EXPECT_EQ(service, outBinder);
@@ -289,7 +294,7 @@
Service out;
// returns nullptr but has OK status for legacy compatibility
EXPECT_TRUE(sm->getService2("foo", &out).isOk());
- EXPECT_EQ(nullptr, out.get<Service::Tag::binder>());
+ EXPECT_EQ(nullptr, out.get<Service::Tag::serviceWithMetadata>().service);
sp<IBinder> outBinder;
EXPECT_TRUE(sm->getService("foo", &outBinder).isOk());
EXPECT_EQ(nullptr, outBinder);
diff --git a/include/android/OWNERS b/include/android/OWNERS
index 5b014d0..9dfa279 100644
--- a/include/android/OWNERS
+++ b/include/android/OWNERS
@@ -9,4 +9,5 @@
# ADPF
per-file performance_hint.h = file:platform/frameworks/base:/ADPF_OWNERS
+per-file system_health.h = file:platform/frameworks/base:/ADPF_OWNERS
per-file thermal.h = file:platform/frameworks/base:/ADPF_OWNERS
diff --git a/include/android/performance_hint.h b/include/android/performance_hint.h
index ca86c27..2b4a5f5 100644
--- a/include/android/performance_hint.h
+++ b/include/android/performance_hint.h
@@ -359,6 +359,31 @@
bool cpu, bool gpu, const char* _Nonnull debugName) __INTRODUCED_IN(36);
/**
+ * Informs the framework of an upcoming one-off expensive frame for a graphics pipeline
+ * bound to this session. This frame will be treated as not representative of the workload as a
+ * whole, and it will be discarded the purposes of load tracking. The user can specify
+ * whether the workload spike is expected to be on the CPU, GPU, or both.
+ *
+ * Sending hints for both CPU and GPU counts as two separate hints for the purposes of the
+ * rate limiter.
+ *
+ * @param cpu Indicates if the workload spike is expected to affect the CPU.
+ * @param gpu Indicates if the workload spike is expected to affect the GPU.
+ * @param debugName A required string used to identify this specific hint during
+ * tracing. This debug string will only be held for the duration of the
+ * method, and can be safely discarded after.
+ *
+ * @return 0 on success.
+ * EINVAL if no hints were requested.
+ * EBUSY if the hint was rate limited.
+ * EPIPE if communication with the system service has failed.
+ * ENOTSUP if the hint is not supported.
+ */
+int APerformanceHint_notifyWorkloadSpike(
+ APerformanceHintSession* _Nonnull session,
+ bool cpu, bool gpu, const char* _Nonnull debugName) __INTRODUCED_IN(36);
+
+/**
* Associates a session with any {@link ASurfaceControl} or {@link ANativeWindow}
* instances managed by this session.
*
diff --git a/include/android/system_health.h b/include/android/system_health.h
new file mode 100644
index 0000000..69620df
--- /dev/null
+++ b/include/android/system_health.h
@@ -0,0 +1,351 @@
+/*
+ * Copyright (C) 2024 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.
+ */
+
+/**
+* @defgroup SystemHealth
+* @{
+*/
+
+/**
+ * @file system_health.h
+ */
+
+#ifndef _ANDROID_SYSTEM_HEALTH_H
+#define _ANDROID_SYSTEM_HEALTH_H
+
+#include <sys/cdefs.h>
+
+/******************************************************************
+ *
+ * IMPORTANT NOTICE:
+ *
+ * This file is part of Android's set of stable system headers
+ * exposed by the Android NDK (Native Development Kit).
+ *
+ * Third-party source AND binary code relies on the definitions
+ * here to be FROZEN ON ALL UPCOMING PLATFORM RELEASES.
+ *
+ * - DO NOT MODIFY ENUMS (EXCEPT IF YOU ADD NEW 32-BIT VALUES)
+ * - DO NOT MODIFY CONSTANTS OR FUNCTIONAL MACROS
+ * - DO NOT CHANGE THE SIGNATURE OF FUNCTIONS IN ANY WAY
+ * - DO NOT CHANGE THE LAYOUT OR SIZE OF STRUCTURES
+ */
+
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#if !defined(__INTRODUCED_IN)
+#define __INTRODUCED_IN(__api_level) /* nothing */
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Params used to customize the calculation of CPU headroom.
+ *
+ * Also see {@link ASystemHealth_getCpuHeadroom}.
+ */
+typedef struct ACpuHeadroomParams ACpuHeadroomParams;
+
+/**
+ * Params used to customize the calculation of GPU headroom.
+ *
+ * Also see {@link ASystemHealth_getGpuHeadroom}.
+ */
+typedef struct AGpuHeadroomParams AGpuHeadroomParams;
+
+/**
+ * Creates a new instance of ACpuHeadroomParams.
+ *
+ * When the client finishes using {@link ACpuHeadroomParams},
+ * {@link ACpuHeadroomParams_destroy()} must be called to destroy
+ * and free up the resources associated with {@link ACpuHeadroomParams}.
+ *
+ * Available since API level 36.
+ *
+ * @return A new instance of ACpuHeadroomParams.
+ */
+ACpuHeadroomParams *_Nonnull ACpuHeadroomParams_create()
+__INTRODUCED_IN(36);
+
+enum ACpuHeadroomCalculationType {
+ /**
+ * Use the minimum headroom value within the calculation window.
+ * Introduced in API level 36.
+ */
+ ACPU_HEADROOM_CALCULATION_TYPE_MIN = 0,
+ /**
+ * Use the average headroom value within the calculation window.
+ * Introduced in API level 36.
+ */
+ ACPU_HEADROOM_CALCULATION_TYPE_AVERAGE = 1,
+};
+typedef enum ACpuHeadroomCalculationType ACpuHeadroomCalculationType;
+
+enum AGpuHeadroomCalculationType {
+ /**
+ * Use the minimum headroom value within the calculation window.
+ * Introduced in API level 36.
+ */
+ AGPU_HEADROOM_CALCULATION_TYPE_MIN = 0,
+ /**
+ * Use the average headroom value within the calculation window.
+ * Introduced in API level 36.
+ */
+ AGPU_HEADROOM_CALCULATION_TYPE_AVERAGE = 1,
+};
+typedef enum AGpuHeadroomCalculationType AGpuHeadroomCalculationType;
+
+/**
+ * Sets the headroom calculation window size in ACpuHeadroomParams.
+ *
+ * Available since API level 36.
+ *
+ * @param params The params to be set.
+ * @param windowMillis The window size in milliseconds ranged from [50, 10000]. The smaller the
+ * window size, the larger fluctuation in the headroom value should be expected.
+ * The default value can be retrieved from the
+ * {@link #ACpuHeadroomParams_getCalculationWindowMillis} if not set. The device
+ * will try to use the closest feasible window size to this param.
+ */
+void ACpuHeadroomParams_setCalculationWindowMillis(ACpuHeadroomParams *_Nonnull params,
+ int windowMillis)
+__INTRODUCED_IN(36);
+
+/**
+ * Gets the headroom calculation window size in ACpuHeadroomParams.
+ *
+ * Available since API level 36.
+ *
+ * @param params The params to be set.
+ * @return This will return the default value chosen by the device if the params is not set.
+ */
+int ACpuHeadroomParams_getCalculationWindowMillis(ACpuHeadroomParams *_Nonnull params)
+__INTRODUCED_IN(36);
+
+/**
+ * Sets the headroom calculation window size in AGpuHeadroomParams.
+ *
+ * Available since API level 36.
+ *
+ * @param params The params to be set.
+ * @param windowMillis The window size in milliseconds ranged from [50, 10000]. The smaller the
+ * window size, the larger fluctuation in the headroom value should be expected.
+ * The default value can be retrieved from the
+ * {@link #AGpuHeadroomParams_getCalculationWindowMillis} if not set. The device
+ * will try to use the closest feasible window size to this param.
+ */
+void AGpuHeadroomParams_setCalculationWindowMillis(AGpuHeadroomParams *_Nonnull params,
+ int windowMillis)
+__INTRODUCED_IN(36);
+
+/**
+ * Gets the headroom calculation window size in AGpuHeadroomParams.
+ *
+ * Available since API level 36.
+ *
+ * @param params The params to be set.
+ * @return This will return the default value chosen by the device if the params is not set.
+ */
+int AGpuHeadroomParams_getCalculationWindowMillis(AGpuHeadroomParams *_Nonnull params)
+__INTRODUCED_IN(36);
+
+/**
+ * Sets the headroom calculation type in ACpuHeadroomParams.
+ *
+ * Available since API level 36.
+ *
+ * @param params The params to be set.
+ * @param calculationType The headroom calculation type.
+ */
+void ACpuHeadroomParams_setCalculationType(ACpuHeadroomParams *_Nonnull params,
+ ACpuHeadroomCalculationType calculationType)
+__INTRODUCED_IN(36);
+
+/**
+ * Gets the headroom calculation type in ACpuHeadroomParams.
+ *
+ * Available since API level 36.
+ *
+ * @param params The params to be set.
+ * @return The headroom calculation type.
+ */
+ACpuHeadroomCalculationType
+ACpuHeadroomParams_getCalculationType(ACpuHeadroomParams *_Nonnull params)
+__INTRODUCED_IN(36);
+
+/**
+ * Sets the headroom calculation type in AGpuHeadroomParams.
+ *
+ * Available since API level 36.
+ *
+ * @param params The params to be set.
+ * @param calculationType The headroom calculation type.
+ */
+void AGpuHeadroomParams_setCalculationType(AGpuHeadroomParams *_Nonnull params,
+ AGpuHeadroomCalculationType calculationType)
+__INTRODUCED_IN(36);
+
+/**
+ * Gets the headroom calculation type in AGpuHeadroomParams.
+ *
+ * Available since API level 36.
+ *
+ * @param params The params to be set.
+ * @return The headroom calculation type.
+ */
+AGpuHeadroomCalculationType
+AGpuHeadroomParams_getCalculationType(AGpuHeadroomParams *_Nonnull params)
+__INTRODUCED_IN(36);
+
+/**
+ * Sets the thread TIDs to track in ACpuHeadroomParams.
+ *
+ * Available since API level 36.
+ *
+ * @param params The params to be set.
+ * @param tids Non-null array of TIDs, maximum 5.
+ * @param tidsSize The size of the tids array.
+ */
+void ACpuHeadroomParams_setTids(ACpuHeadroomParams *_Nonnull params, const int *_Nonnull tids,
+ int tidsSize)
+__INTRODUCED_IN(36);
+
+/**
+ * Creates a new instance of AGpuHeadroomParams.
+ *
+ * When the client finishes using {@link AGpuHeadroomParams},
+ * {@link AGpuHeadroomParams_destroy()} must be called to destroy
+ * and free up the resources associated with {@link AGpuHeadroomParams}.
+ *
+ * Available since API level 36.
+ *
+ * @return A new instance of AGpuHeadroomParams.
+ */
+AGpuHeadroomParams *_Nonnull AGpuHeadroomParams_create()
+__INTRODUCED_IN(36);
+
+/**
+ * Deletes the ACpuHeadroomParams instance.
+ *
+ * Available since API level 36.
+ *
+ * @param params The params to be deleted.
+ */
+void ACpuHeadroomParams_destroy(ACpuHeadroomParams *_Nonnull params)
+__INTRODUCED_IN(36);
+
+/**
+ * Deletes the AGpuHeadroomParams instance.
+ *
+ * Available since API level 36.
+ *
+ * @param params The params to be deleted.
+ */
+void AGpuHeadroomParams_destroy(AGpuHeadroomParams *_Nonnull params)
+__INTRODUCED_IN(36);
+
+/**
+ * Provides an estimate of available CPU capacity headroom of the device.
+ *
+ * The value can be used by the calling application to determine if the workload was CPU bound and
+ * then take action accordingly to ensure that the workload can be completed smoothly. It can also
+ * be used with the thermal status and headroom to determine if reducing the CPU bound workload can
+ * help reduce the device temperature to avoid thermal throttling.
+ *
+ * Available since API level 36.
+ *
+ * @param params The params to customize the CPU headroom calculation, or nullptr to use the default
+ * @param outHeadroom Non-null output pointer to a single float, which will be set to the CPU
+ * headroom value. The value will be a single value or `Float.NaN` if it's
+ * temporarily unavailable.
+ * Each valid value ranges from [0, 100], where 0 indicates no more cpu resources
+ * can be granted.
+ * @return 0 on success
+ * EPIPE if failed to get the CPU headroom.
+ * EPERM if the TIDs do not belong to the same process.
+ * ENOTSUP if API or requested params is unsupported.
+ */
+int ASystemHealth_getCpuHeadroom(const ACpuHeadroomParams *_Nullable params,
+ float *_Nonnull outHeadroom)
+__INTRODUCED_IN(36);
+
+/**
+ * Provides an estimate of available GPU capacity headroom of the device.
+ *
+ * The value can be used by the calling application to determine if the workload was GPU bound and
+ * then take action accordingly to ensure that the workload can be completed smoothly. It can also
+ * be used with the thermal status and headroom to determine if reducing the GPU bound workload can
+ * help reduce the device temperature to avoid thermal throttling.
+ *
+ * Available since API level 36
+ *
+ * @param params The params to customize the GPU headroom calculation, or nullptr to use the default
+ * @param outHeadroom Non-null output pointer to a single float, which will be set to the GPU
+ * headroom value. The value will be a single value or `Float.NaN` if it's
+ * temporarily unavailable.
+ * Each valid value ranges from [0, 100], where 0 indicates no more gpu resources
+ * can be granted.
+ * @return 0 on success
+ * EPIPE if failed to get the GPU headroom.
+ * ENOTSUP if API or requested params is unsupported.
+ */
+int ASystemHealth_getGpuHeadroom(const AGpuHeadroomParams *_Nullable params,
+ float *_Nonnull outHeadroom)
+__INTRODUCED_IN(36);
+
+/**
+ * Gets minimum polling interval for calling {@link ASystemHealth_getCpuHeadroom} in milliseconds.
+ *
+ * The getCpuHeadroom API may return cached result if called more frequently than the interval.
+ *
+ * Available since API level 36.
+ *
+ * @param outMinIntervalMillis Non-null output pointer to a int64_t, which
+ * will be set to the minimum polling interval in milliseconds.
+ * @return 0 on success
+ * EPIPE if failed to get the minimum polling interval.
+ * ENOTSUP if API is unsupported.
+ */
+int ASystemHealth_getCpuHeadroomMinIntervalMillis(int64_t *_Nonnull outMinIntervalMillis)
+__INTRODUCED_IN(36);
+
+/**
+ * Gets minimum polling interval for calling {@link ASystemHealth_getGpuHeadroom} in milliseconds.
+ *
+ * The getGpuHeadroom API may return cached result if called more frequent than the interval.
+ *
+ * Available since API level 36.
+ *
+ * @param outMinIntervalMillis Non-null output pointer to a int64_t, which
+ * will be set to the minimum polling interval in milliseconds.
+ * @return 0 on success
+ * EPIPE if failed to get the minimum polling interval.
+ * ENOTSUP if API is unsupported.
+ */
+int ASystemHealth_getGpuHeadroomMinIntervalMillis(int64_t *_Nonnull outMinIntervalMillis)
+__INTRODUCED_IN(36);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // _ANDROID_SYSTEM_HEALTH_H
+
+/** @} */
diff --git a/include/input/DisplayTopologyGraph.h b/include/input/DisplayTopologyGraph.h
new file mode 100644
index 0000000..90427bd
--- /dev/null
+++ b/include/input/DisplayTopologyGraph.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2024 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 <ftl/enum.h>
+#include <ui/LogicalDisplayId.h>
+
+#include <cinttypes>
+#include <unordered_map>
+#include <vector>
+
+namespace android {
+
+/**
+ * The edge of the current display, where adjacent display is attached to.
+ */
+enum class DisplayTopologyPosition : int32_t {
+ LEFT = 0,
+ TOP = 1,
+ RIGHT = 2,
+ BOTTOM = 3,
+
+ ftl_last = BOTTOM
+};
+
+/**
+ * Directed edge in the graph of adjacent displays.
+ */
+struct DisplayTopologyAdjacentDisplay {
+ ui::LogicalDisplayId displayId = ui::LogicalDisplayId::INVALID;
+ DisplayTopologyPosition position;
+ float offsetPx;
+};
+
+/**
+ * Directed Graph representation of Display Topology.
+ */
+struct DisplayTopologyGraph {
+ ui::LogicalDisplayId primaryDisplayId = ui::LogicalDisplayId::INVALID;
+ std::unordered_map<ui::LogicalDisplayId, std::vector<DisplayTopologyAdjacentDisplay>> graph;
+};
+
+} // namespace android
diff --git a/include/private/performance_hint_private.h b/include/private/performance_hint_private.h
index f150fb1..e3f98ba 100644
--- a/include/private/performance_hint_private.h
+++ b/include/private/performance_hint_private.h
@@ -74,6 +74,20 @@
* baseline to prepare for an arbitrary load, and must wake up if inactive.
*/
GPU_LOAD_RESET = 7,
+
+ /**
+ * This hint indicates an upcoming CPU workload that is abnormally large and
+ * not representative of the workload. This should be used for rare, one-time
+ * operations and should be ignored by any load tracking or session hysteresis.
+ */
+ CPU_LOAD_SPIKE = 8,
+
+ /**
+ * This hint indicates an upcoming GPU workload that is abnormally large and
+ * not representative of the workload. This should be used for rare, one-time
+ * operations and should be ignored by any load tracking or session hysteresis.
+ */
+ GPU_LOAD_SPIKE = 9,
};
// Allows access to PowerHAL's SessionTags without needing to import its AIDL
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
index e10e4dd..aac369d 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -456,6 +456,28 @@
}
soong_config_module_type {
+ name: "libbinder_remove_cache_static_list_config",
+ module_type: "cc_defaults",
+ config_namespace: "libbinder",
+ bool_variables: ["release_libbinder_remove_cache_static_list"],
+ properties: [
+ "cflags",
+ ],
+}
+
+libbinder_remove_cache_static_list_config {
+ name: "libbinder_remove_cache_static_list_flag",
+ soong_config_variables: {
+ release_libbinder_remove_cache_static_list: {
+ cflags: ["-DLIBBINDER_REMOVE_CACHE_STATIC_LIST"],
+ conditions_default: {
+ cflags: ["-DNO_LIBBINDER_REMOVE_CACHE_STATIC_LIST"],
+ },
+ },
+ },
+}
+
+soong_config_module_type {
name: "libbinder_client_cache_config",
module_type: "cc_defaults",
config_namespace: "libbinder",
@@ -504,6 +526,7 @@
defaults: [
"libbinder_client_cache_flag",
"libbinder_addservice_cache_flag",
+ "libbinder_remove_cache_static_list_flag",
],
srcs: [
"BufferedTextOutput.cpp",
@@ -826,6 +849,7 @@
"aidl/android/os/IServiceCallback.aidl",
"aidl/android/os/IServiceManager.aidl",
"aidl/android/os/Service.aidl",
+ "aidl/android/os/ServiceWithMetadata.aidl",
"aidl/android/os/ServiceDebugInfo.aidl",
],
path: "aidl",
diff --git a/libs/binder/BackendUnifiedServiceManager.cpp b/libs/binder/BackendUnifiedServiceManager.cpp
index 123dfd2..34d5a09 100644
--- a/libs/binder/BackendUnifiedServiceManager.cpp
+++ b/libs/binder/BackendUnifiedServiceManager.cpp
@@ -16,6 +16,7 @@
#include "BackendUnifiedServiceManager.h"
#include <android/os/IAccessor.h>
+#include <android/os/IServiceManager.h>
#include <binder/RpcSession.h>
#if defined(__BIONIC__) && !defined(__ANDROID_VNDK__)
@@ -36,6 +37,12 @@
constexpr bool kUseCacheInAddService = false;
#endif
+#ifdef LIBBINDER_REMOVE_CACHE_STATIC_LIST
+constexpr bool kRemoveStaticList = true;
+#else
+constexpr bool kRemoveStaticList = false;
+#endif
+
using AidlServiceManager = android::os::IServiceManager;
using android::os::IAccessor;
using binder::Status;
@@ -110,6 +117,13 @@
// go/keep-sorted end
};
+os::ServiceWithMetadata createServiceWithMetadata(const sp<IBinder>& service, bool isLazyService) {
+ os::ServiceWithMetadata out = os::ServiceWithMetadata();
+ out.service = service;
+ out.isLazyService = isLazyService;
+ return out;
+}
+
bool BinderCacheWithInvalidation::isClientSideCachingEnabled(const std::string& serviceName) {
sp<ProcessState> self = ProcessState::selfOrNull();
if (!self || self->getThreadPoolMaxTotalThreadCount() <= 0) {
@@ -118,6 +132,7 @@
serviceName.c_str());
return false;
}
+ if (kRemoveStaticList) return true;
for (const char* name : kStaticCachableList) {
if (name == serviceName) {
return true;
@@ -132,15 +147,21 @@
return Status::ok();
}
- if (service.getTag() == os::Service::Tag::binder) {
- return updateCache(serviceName, service.get<os::Service::Tag::binder>());
+ if (service.getTag() == os::Service::Tag::serviceWithMetadata) {
+ auto serviceWithMetadata = service.get<os::Service::Tag::serviceWithMetadata>();
+ return updateCache(serviceName, serviceWithMetadata.service,
+ serviceWithMetadata.isLazyService);
}
return Status::ok();
}
Status BackendUnifiedServiceManager::updateCache(const std::string& serviceName,
- const sp<IBinder>& binder) {
+ const sp<IBinder>& binder, bool isServiceLazy) {
std::string traceStr;
+ // Don't cache if service is lazy
+ if (kRemoveStaticList && isServiceLazy) {
+ return Status::ok();
+ }
if (atrace_is_tag_enabled(ATRACE_TAG_AIDL)) {
traceStr = "BinderCacheWithInvalidation::updateCache : " + serviceName;
}
@@ -153,7 +174,9 @@
binder::ScopedTrace aidlTrace(ATRACE_TAG_AIDL,
"BinderCacheWithInvalidation::updateCache failed: "
"isBinderAlive_false");
- } else if (mCacheForGetService->isClientSideCachingEnabled(serviceName)) {
+ }
+ // If we reach here with kRemoveStaticList=true then we know service isn't lazy
+ else if (mCacheForGetService->isClientSideCachingEnabled(serviceName)) {
binder::ScopedTrace aidlTrace(ATRACE_TAG_AIDL,
"BinderCacheWithInvalidation::updateCache successful");
return mCacheForGetService->setItem(serviceName, binder);
@@ -173,7 +196,7 @@
sp<IBinder> item = mCacheForGetService->getItem(serviceName);
// TODO(b/363177618): Enable caching for binders which are always null.
if (item != nullptr && item->isBinderAlive()) {
- *_out = os::Service::make<os::Service::Tag::binder>(item);
+ *_out = createServiceWithMetadata(item, false);
return true;
}
return false;
@@ -188,7 +211,7 @@
sp<IBinder>* _aidl_return) {
os::Service service;
Status status = getService2(name, &service);
- *_aidl_return = service.get<os::Service::Tag::binder>();
+ *_aidl_return = service.get<os::Service::Tag::serviceWithMetadata>().service;
return status;
}
@@ -227,14 +250,16 @@
Status BackendUnifiedServiceManager::toBinderService(const ::std::string& name,
const os::Service& in, os::Service* _out) {
switch (in.getTag()) {
- case os::Service::Tag::binder: {
- if (in.get<os::Service::Tag::binder>() == nullptr) {
+ case os::Service::Tag::serviceWithMetadata: {
+ auto serviceWithMetadata = in.get<os::Service::Tag::serviceWithMetadata>();
+ if (serviceWithMetadata.service == nullptr) {
// failed to find a service. Check to see if we have any local
// injected Accessors for this service.
os::Service accessor;
Status status = getInjectedAccessor(name, &accessor);
if (!status.isOk()) {
- *_out = os::Service::make<os::Service::Tag::binder>(nullptr);
+ *_out = os::Service::make<os::Service::Tag::serviceWithMetadata>(
+ createServiceWithMetadata(nullptr, false));
return status;
}
if (accessor.getTag() == os::Service::Tag::accessor &&
@@ -255,7 +280,8 @@
sp<IAccessor> accessor = interface_cast<IAccessor>(accessorBinder);
if (accessor == nullptr) {
ALOGE("Service#accessor doesn't have accessor. VM is maybe starting...");
- *_out = os::Service::make<os::Service::Tag::binder>(nullptr);
+ *_out = os::Service::make<os::Service::Tag::serviceWithMetadata>(
+ createServiceWithMetadata(nullptr, false));
return Status::ok();
}
auto request = [=] {
@@ -276,7 +302,8 @@
return Status::fromStatusT(status);
}
session->setSessionSpecificRoot(accessorBinder);
- *_out = os::Service::make<os::Service::Tag::binder>(session->getRootObject());
+ *_out = os::Service::make<os::Service::Tag::serviceWithMetadata>(
+ createServiceWithMetadata(session->getRootObject(), false));
return Status::ok();
}
default: {
@@ -291,7 +318,8 @@
Status status = mTheRealServiceManager->addService(name, service, allowIsolated, dumpPriority);
// mEnableAddServiceCache is true by default.
if (kUseCacheInAddService && mEnableAddServiceCache && status.isOk()) {
- return updateCache(name, service);
+ return updateCache(name, service,
+ dumpPriority & android::os::IServiceManager::FLAG_IS_LAZY_SERVICE);
}
return status;
}
diff --git a/libs/binder/BackendUnifiedServiceManager.h b/libs/binder/BackendUnifiedServiceManager.h
index b46bf19..6a0d06a 100644
--- a/libs/binder/BackendUnifiedServiceManager.h
+++ b/libs/binder/BackendUnifiedServiceManager.h
@@ -159,7 +159,8 @@
binder::Status toBinderService(const ::std::string& name, const os::Service& in,
os::Service* _out);
binder::Status updateCache(const std::string& serviceName, const os::Service& service);
- binder::Status updateCache(const std::string& serviceName, const sp<IBinder>& binder);
+ binder::Status updateCache(const std::string& serviceName, const sp<IBinder>& binder,
+ bool isLazyService);
bool returnIfCached(const std::string& serviceName, os::Service* _out);
};
diff --git a/libs/binder/IServiceManager.cpp b/libs/binder/IServiceManager.cpp
index 61866d7..53435c3 100644
--- a/libs/binder/IServiceManager.cpp
+++ b/libs/binder/IServiceManager.cpp
@@ -152,7 +152,8 @@
virtual Status realGetService(const std::string& name, sp<IBinder>* _aidl_return) {
Service service;
Status status = mUnifiedServiceManager->getService2(name, &service);
- *_aidl_return = service.get<Service::Tag::binder>();
+ auto serviceWithMetadata = service.get<Service::Tag::serviceWithMetadata>();
+ *_aidl_return = serviceWithMetadata.service;
return status;
}
};
@@ -607,7 +608,7 @@
if (!mUnifiedServiceManager->checkService(String8(name).c_str(), &ret).isOk()) {
return nullptr;
}
- return ret.get<Service::Tag::binder>();
+ return ret.get<Service::Tag::serviceWithMetadata>().service;
}
status_t CppBackendShim::addService(const String16& name, const sp<IBinder>& service,
diff --git a/libs/binder/LazyServiceRegistrar.cpp b/libs/binder/LazyServiceRegistrar.cpp
index 0f0af0b..27cfe0c 100644
--- a/libs/binder/LazyServiceRegistrar.cpp
+++ b/libs/binder/LazyServiceRegistrar.cpp
@@ -19,7 +19,6 @@
#include <android/os/BnClientCallback.h>
#include <android/os/IServiceManager.h>
#include <binder/IPCThreadState.h>
-#include <binder/IServiceManager.h>
#include <binder/LazyServiceRegistrar.h>
namespace android {
@@ -134,6 +133,12 @@
std::string regStr = (reRegister) ? "Re-registering" : "Registering";
ALOGI("%s service %s", regStr.c_str(), name.c_str());
+ if (dumpFlags & android::os::IServiceManager::FLAG_IS_LAZY_SERVICE) {
+ ALOGW("FLAG_IS_LAZY_SERVICE flag already set. This should only be set by "
+ "ClientCounterCallbackImpl in LazyServiceRegistrar");
+ }
+ dumpFlags |= android::os::IServiceManager::FLAG_IS_LAZY_SERVICE;
+
if (Status status = manager->addService(name.c_str(), service, allowIsolated, dumpFlags);
!status.isOk()) {
ALOGE("Failed to register service %s (%s)", name.c_str(), status.toString8().c_str());
diff --git a/libs/binder/aidl/android/os/IServiceManager.aidl b/libs/binder/aidl/android/os/IServiceManager.aidl
index 1d1f84f..69edef8 100644
--- a/libs/binder/aidl/android/os/IServiceManager.aidl
+++ b/libs/binder/aidl/android/os/IServiceManager.aidl
@@ -49,6 +49,8 @@
DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PRIORITY_HIGH
| DUMP_FLAG_PRIORITY_NORMAL | DUMP_FLAG_PRIORITY_DEFAULT;
+ const int FLAG_IS_LAZY_SERVICE = 1 << 30;
+
/* Allows services to dump sections in protobuf format. */
const int DUMP_FLAG_PROTO = 1 << 4;
@@ -61,7 +63,8 @@
*
* Returns null if the service does not exist.
*
- * @deprecated TODO(b/355394904): Use getService2 instead.
+ * @deprecated TODO(b/355394904): Use getService2 instead. This does not return metadata
+ * that is included in ServiceWithMetadata
*/
@UnsupportedAppUsage
@nullable IBinder getService(@utf8InCpp String name);
diff --git a/libs/binder/aidl/android/os/Service.aidl b/libs/binder/aidl/android/os/Service.aidl
index 4c52109..3bc6588 100644
--- a/libs/binder/aidl/android/os/Service.aidl
+++ b/libs/binder/aidl/android/os/Service.aidl
@@ -16,6 +16,8 @@
package android.os;
+import android.os.ServiceWithMetadata;
+
/**
* Service is a union of different service types that can be returned
* by the internal {@link ServiceManager#getService(name)} API.
@@ -23,6 +25,6 @@
* @hide
*/
union Service {
- @nullable IBinder binder;
+ ServiceWithMetadata serviceWithMetadata;
@nullable IBinder accessor;
}
\ No newline at end of file
diff --git a/libs/binder/aidl/android/os/ServiceWithMetadata.aidl b/libs/binder/aidl/android/os/ServiceWithMetadata.aidl
new file mode 100644
index 0000000..96f76ff
--- /dev/null
+++ b/libs/binder/aidl/android/os/ServiceWithMetadata.aidl
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os;
+
+/**
+ * Service binder with metadata.
+ * @hide
+ */
+parcelable ServiceWithMetadata {
+ /**
+ * IBinder to service
+ */
+ @nullable IBinder service;
+ /**
+ * boolean if the IBinder can be cached by client.
+ */
+ boolean isLazyService;
+}
diff --git a/libs/binder/include/binder/IInterface.h b/libs/binder/include/binder/IInterface.h
index 30e005c..5924a2d 100644
--- a/libs/binder/include/binder/IInterface.h
+++ b/libs/binder/include/binder/IInterface.h
@@ -220,8 +220,6 @@
"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",
@@ -264,17 +262,12 @@
"android.media.IResourceManagerService",
"android.os.IComplexTypeInterface",
"android.os.IPermissionController",
- "android.os.IPingResponder",
"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.utils.IMemory",
"android.utils.IMemoryHeap",
@@ -286,9 +279,6 @@
"com.android.internal.os.IShellCallback",
"drm.IDrmManagerService",
"drm.IDrmServiceListener",
- "IAAudioClient",
- "IAAudioService",
- "VtsFuzzer",
nullptr,
};
diff --git a/libs/binder/include/binder/IServiceManager.h b/libs/binder/include/binder/IServiceManager.h
index ca26a57..7d79baa 100644
--- a/libs/binder/include/binder/IServiceManager.h
+++ b/libs/binder/include/binder/IServiceManager.h
@@ -153,7 +153,7 @@
/**
* Directly enable or disable caching binder during addService calls.
- * Only used for testing.
+ * Only used for testing. This is enabled by default.
*/
virtual void enableAddServiceCache(bool value) = 0;
};
diff --git a/libs/binder/ndk/include_platform/android/binder_manager.h b/libs/binder/ndk/include_platform/android/binder_manager.h
index cc4943b..f5df8d5 100644
--- a/libs/binder/ndk/include_platform/android/binder_manager.h
+++ b/libs/binder/ndk/include_platform/android/binder_manager.h
@@ -34,6 +34,7 @@
ADD_SERVICE_DUMP_FLAG_PRIORITY_HIGH = 1 << 2,
ADD_SERVICE_DUMP_FLAG_PRIORITY_NORMAL = 1 << 3,
ADD_SERVICE_DUMP_FLAG_PRIORITY_DEFAULT = 1 << 4,
+ // All other bits are reserved for internal usage
};
/**
diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp
index 642fbf3..c21d7c6 100644
--- a/libs/binder/tests/Android.bp
+++ b/libs/binder/tests/Android.bp
@@ -73,6 +73,7 @@
defaults: [
"libbinder_client_cache_flag",
"libbinder_addservice_cache_flag",
+ "libbinder_remove_cache_static_list_flag",
],
test_suites: ["general-tests"],
require_root: true,
diff --git a/libs/binder/tests/binderCacheUnitTest.cpp b/libs/binder/tests/binderCacheUnitTest.cpp
index 3195c55..19395c2 100644
--- a/libs/binder/tests/binderCacheUnitTest.cpp
+++ b/libs/binder/tests/binderCacheUnitTest.cpp
@@ -40,6 +40,12 @@
constexpr bool kUseCacheInAddService = false;
#endif
+#ifdef LIBBINDER_REMOVE_CACHE_STATIC_LIST
+constexpr bool kRemoveStaticList = true;
+#else
+constexpr bool kRemoveStaticList = false;
+#endif
+
// A service name which is in the static list of cachable services
const String16 kCachedServiceName = String16("isub");
@@ -69,8 +75,10 @@
MockAidlServiceManager() : innerSm() {}
binder::Status checkService(const ::std::string& name, os::Service* _out) override {
- sp<IBinder> binder = innerSm.getService(String16(name.c_str()));
- *_out = os::Service::make<os::Service::Tag::binder>(binder);
+ os::ServiceWithMetadata serviceWithMetadata = os::ServiceWithMetadata();
+ serviceWithMetadata.service = innerSm.getService(String16(name.c_str()));
+ serviceWithMetadata.isLazyService = false;
+ *_out = os::Service::make<os::Service::Tag::serviceWithMetadata>(serviceWithMetadata);
return binder::Status::ok();
}
@@ -85,6 +93,75 @@
FakeServiceManager innerSm;
};
+// Returns services with isLazyService flag as true.
+class MockAidlServiceManager2 : public os::IServiceManagerDefault {
+public:
+ MockAidlServiceManager2() : innerSm() {}
+
+ binder::Status checkService(const ::std::string& name, os::Service* _out) override {
+ os::ServiceWithMetadata serviceWithMetadata = os::ServiceWithMetadata();
+ serviceWithMetadata.service = innerSm.getService(String16(name.c_str()));
+ serviceWithMetadata.isLazyService = true;
+ *_out = os::Service::make<os::Service::Tag::serviceWithMetadata>(serviceWithMetadata);
+ return binder::Status::ok();
+ }
+
+ binder::Status addService(const std::string& name, const sp<IBinder>& service,
+ bool allowIsolated, int32_t dumpPriority) override {
+ return binder::Status::fromStatusT(
+ innerSm.addService(String16(name.c_str()), service, allowIsolated, dumpPriority));
+ }
+
+ void clearServices() { innerSm.clear(); }
+
+ FakeServiceManager innerSm;
+};
+
+class LibbinderCacheRemoveStaticList : public ::testing::Test {
+protected:
+ void SetUp() override {
+ fakeServiceManager = sp<MockAidlServiceManager2>::make();
+ mServiceManager = getServiceManagerShimFromAidlServiceManagerForTests(fakeServiceManager);
+ mServiceManager->enableAddServiceCache(true);
+ }
+ void TearDown() override {}
+
+public:
+ void cacheAddServiceAndConfirmCacheMiss(const sp<IBinder>& binder1) {
+ // Add a service. This shouldn't cache it.
+ EXPECT_EQ(OK,
+ mServiceManager->addService(kCachedServiceName, binder1,
+ /*allowIsolated = */ false,
+ android::os::IServiceManager::FLAG_IS_LAZY_SERVICE));
+ // Try to populate cache. Cache shouldn't be updated.
+ EXPECT_EQ(binder1, mServiceManager->checkService(kCachedServiceName));
+ fakeServiceManager->clearServices();
+ EXPECT_EQ(nullptr, mServiceManager->checkService(kCachedServiceName));
+ }
+
+ sp<MockAidlServiceManager2> fakeServiceManager;
+ sp<android::IServiceManager> mServiceManager;
+};
+
+TEST_F(LibbinderCacheRemoveStaticList, AddLocalServiceAndConfirmCacheMiss) {
+ if (!kRemoveStaticList) {
+ GTEST_SKIP() << "Skipping as feature is not enabled";
+ return;
+ }
+ sp<IBinder> binder1 = sp<BBinder>::make();
+ cacheAddServiceAndConfirmCacheMiss(binder1);
+}
+
+TEST_F(LibbinderCacheRemoveStaticList, AddRemoteServiceAndConfirmCacheMiss) {
+ if (!kRemoveStaticList) {
+ GTEST_SKIP() << "Skipping as feature is not enabled";
+ return;
+ }
+ sp<IBinder> binder1 = defaultServiceManager()->checkService(kServerName);
+ ASSERT_NE(binder1, nullptr);
+ cacheAddServiceAndConfirmCacheMiss(binder1);
+}
+
class LibbinderCacheAddServiceTest : public ::testing::Test {
protected:
void SetUp() override {
@@ -231,7 +308,13 @@
EXPECT_EQ(binder2, result);
}
+// TODO(b/333854840): Remove this test removing the static list
TEST_F(LibbinderCacheTest, DoNotCacheServiceNotInList) {
+ if (kRemoveStaticList) {
+ GTEST_SKIP() << "Skipping test as static list is disabled";
+ return;
+ }
+
sp<IBinder> binder1 = sp<BBinder>::make();
sp<IBinder> binder2 = sp<BBinder>::make();
String16 serviceName = String16("NewLibbinderCacheTest");
diff --git a/libs/binder/tests/binderLibTest.cpp b/libs/binder/tests/binderLibTest.cpp
index 9e92f95..c038c95 100644
--- a/libs/binder/tests/binderLibTest.cpp
+++ b/libs/binder/tests/binderLibTest.cpp
@@ -43,6 +43,7 @@
#include <input/BlockingQueue.h>
#include <processgroup/processgroup.h>
#include <utils/Flattenable.h>
+#include <utils/SystemClock.h>
#include <linux/sched.h>
#include <sys/epoll.h>
@@ -343,7 +344,12 @@
}
bool checkFreezeSupport() {
- std::ifstream freezer_file("/sys/fs/cgroup/uid_0/cgroup.freeze");
+ std::string path;
+ if (!CgroupGetAttributePathForTask("FreezerState", getpid(), &path)) {
+ return false;
+ }
+
+ std::ifstream freezer_file(path);
// Pass test on devices where the cgroup v2 freezer is not supported
if (freezer_file.fail()) {
return false;
@@ -1837,14 +1843,6 @@
EXPECT_TRUE(reply.readBool());
}
-size_t epochMillis() {
- using std::chrono::duration_cast;
- using std::chrono::milliseconds;
- using std::chrono::seconds;
- using std::chrono::system_clock;
- return duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count();
-}
-
TEST_F(BinderLibTest, HangingServices) {
Parcel data, reply;
sp<IBinder> server = addServer();
@@ -1853,7 +1851,7 @@
data.writeInt32(delay);
// b/266537959 - must take before taking lock, since countdown is started in the remote
// process there.
- size_t epochMsBefore = epochMillis();
+ int64_t timeBefore = uptimeMillis();
EXPECT_THAT(server->transact(BINDER_LIB_TEST_PROCESS_TEMPORARY_LOCK, data, &reply), NO_ERROR);
std::vector<std::thread> ts;
for (size_t i = 0; i < kKernelThreads + 1; i++) {
@@ -1867,10 +1865,10 @@
for (auto &t : ts) {
t.join();
}
- size_t epochMsAfter = epochMillis();
+ int64_t timeAfter = uptimeMillis();
// deadlock occurred and threads only finished after 1s passed.
- EXPECT_GE(epochMsAfter, epochMsBefore + delay);
+ EXPECT_GE(timeAfter, timeBefore + delay);
}
TEST_F(BinderLibTest, BinderProxyCount) {
diff --git a/libs/gui/tests/EndToEndNativeInputTest.cpp b/libs/gui/tests/EndToEndNativeInputTest.cpp
index dcda1ee..06f00a4 100644
--- a/libs/gui/tests/EndToEndNativeInputTest.cpp
+++ b/libs/gui/tests/EndToEndNativeInputTest.cpp
@@ -34,6 +34,8 @@
#include <binder/Parcel.h>
#include <binder/ProcessState.h>
+#include <gui/IConsumerListener.h>
+#include <gui/IGraphicBufferConsumer.h>
#include <gui/ISurfaceComposer.h>
#include <gui/Surface.h>
#include <gui/SurfaceComposerClient.h>
@@ -116,7 +118,7 @@
} else {
android::os::InputChannelCore tempChannel;
android::binder::Status result =
- mInputFlinger->createInputChannel("testchannels", &tempChannel);
+ mInputFlinger->createInputChannel(sc->getName() + " channel", &tempChannel);
if (!result.isOk()) {
ADD_FAILURE() << "binder call to createInputChannel failed";
}
@@ -139,47 +141,51 @@
}
static std::unique_ptr<InputSurface> makeColorInputSurface(const sp<SurfaceComposerClient>& scc,
- int width, int height) {
+ int width, int height,
+ const std::string& name) {
sp<SurfaceControl> surfaceControl =
- scc->createSurface(String8("Test Surface"), 0 /* bufHeight */, 0 /* bufWidth */,
+ scc->createSurface(String8(name.c_str()), 0 /* bufHeight */, 0 /* bufWidth */,
PIXEL_FORMAT_RGBA_8888,
ISurfaceComposerClient::eFXSurfaceEffect);
return std::make_unique<InputSurface>(surfaceControl, width, height);
}
static std::unique_ptr<InputSurface> makeBufferInputSurface(
- const sp<SurfaceComposerClient>& scc, int width, int height) {
+ const sp<SurfaceComposerClient>& scc, int width, int height,
+ const std::string& name = "Test Buffer Surface") {
sp<SurfaceControl> surfaceControl =
- scc->createSurface(String8("Test Buffer Surface"), width, height,
- PIXEL_FORMAT_RGBA_8888, 0 /* flags */);
+ scc->createSurface(String8(name.c_str()), width, height, PIXEL_FORMAT_RGBA_8888,
+ 0 /* flags */);
return std::make_unique<InputSurface>(surfaceControl, width, height);
}
static std::unique_ptr<InputSurface> makeContainerInputSurface(
- const sp<SurfaceComposerClient>& scc, int width, int height) {
+ const sp<SurfaceComposerClient>& scc, int width, int height,
+ const std::string& name = "Test Container Surface") {
sp<SurfaceControl> surfaceControl =
- scc->createSurface(String8("Test Container Surface"), 0 /* bufHeight */,
- 0 /* bufWidth */, PIXEL_FORMAT_RGBA_8888,
+ scc->createSurface(String8(name.c_str()), 0 /* bufHeight */, 0 /* bufWidth */,
+ PIXEL_FORMAT_RGBA_8888,
ISurfaceComposerClient::eFXSurfaceContainer);
return std::make_unique<InputSurface>(surfaceControl, width, height);
}
static std::unique_ptr<InputSurface> makeContainerInputSurfaceNoInputChannel(
- const sp<SurfaceComposerClient>& scc, int width, int height) {
+ const sp<SurfaceComposerClient>& scc, int width, int height,
+ const std::string& name = "Test Container Surface") {
sp<SurfaceControl> surfaceControl =
- scc->createSurface(String8("Test Container Surface"), 100 /* height */,
- 100 /* width */, PIXEL_FORMAT_RGBA_8888,
+ scc->createSurface(String8(name.c_str()), 100 /* height */, 100 /* width */,
+ PIXEL_FORMAT_RGBA_8888,
ISurfaceComposerClient::eFXSurfaceContainer);
return std::make_unique<InputSurface>(surfaceControl, width, height,
true /* noInputChannel */);
}
static std::unique_ptr<InputSurface> makeCursorInputSurface(
- const sp<SurfaceComposerClient>& scc, int width, int height) {
+ const sp<SurfaceComposerClient>& scc, int width, int height,
+ const std::string& name = "Test Cursor Surface") {
sp<SurfaceControl> surfaceControl =
- scc->createSurface(String8("Test Cursor Surface"), 0 /* bufHeight */,
- 0 /* bufWidth */, PIXEL_FORMAT_RGBA_8888,
- ISurfaceComposerClient::eCursorWindow);
+ scc->createSurface(String8(name.c_str()), 0 /* bufHeight */, 0 /* bufWidth */,
+ PIXEL_FORMAT_RGBA_8888, ISurfaceComposerClient::eCursorWindow);
return std::make_unique<InputSurface>(surfaceControl, width, height);
}
@@ -410,8 +416,9 @@
void TearDown() { mComposerClient->dispose(); }
- std::unique_ptr<InputSurface> makeSurface(int width, int height) {
- return InputSurface::makeColorInputSurface(mComposerClient, width, height);
+ std::unique_ptr<InputSurface> makeSurface(int width, int height,
+ const std::string& name = "Test Surface") const {
+ return InputSurface::makeColorInputSurface(mComposerClient, width, height, name);
}
void postBuffer(const sp<SurfaceControl>& layer, int32_t w, int32_t h) {
@@ -470,10 +477,10 @@
* reverse order.
*/
TEST_F(InputSurfacesTest, input_respects_positioning) {
- std::unique_ptr<InputSurface> surface = makeSurface(100, 100);
+ std::unique_ptr<InputSurface> surface = makeSurface(100, 100, "Left Surface");
surface->showAt(100, 100);
- std::unique_ptr<InputSurface> surface2 = makeSurface(100, 100);
+ std::unique_ptr<InputSurface> surface2 = makeSurface(100, 100, "Right Surface");
surface2->showAt(200, 200);
injectTap(201, 201);
@@ -493,8 +500,8 @@
}
TEST_F(InputSurfacesTest, input_respects_layering) {
- std::unique_ptr<InputSurface> surface = makeSurface(100, 100);
- std::unique_ptr<InputSurface> surface2 = makeSurface(100, 100);
+ std::unique_ptr<InputSurface> surface = makeSurface(100, 100, "Test Surface 1");
+ std::unique_ptr<InputSurface> surface2 = makeSurface(100, 100, "Test Surface 2");
surface->showAt(10, 10);
surface2->showAt(10, 10);
@@ -519,8 +526,8 @@
// (such as shadows in dialogs). Inputs sent to the client are offset such that 0,0 is the start
// of the client content.
TEST_F(InputSurfacesTest, input_respects_surface_insets) {
- std::unique_ptr<InputSurface> bgSurface = makeSurface(100, 100);
- std::unique_ptr<InputSurface> fgSurface = makeSurface(100, 100);
+ std::unique_ptr<InputSurface> bgSurface = makeSurface(100, 100, "Background Surface");
+ std::unique_ptr<InputSurface> fgSurface = makeSurface(100, 100, "Foreground Surface");
bgSurface->showAt(100, 100);
fgSurface->mInputInfo->editInfo()->surfaceInset = 5;
@@ -534,8 +541,8 @@
}
TEST_F(InputSurfacesTest, input_respects_surface_insets_with_replaceTouchableRegionWithCrop) {
- std::unique_ptr<InputSurface> bgSurface = makeSurface(100, 100);
- std::unique_ptr<InputSurface> fgSurface = makeSurface(100, 100);
+ std::unique_ptr<InputSurface> bgSurface = makeSurface(100, 100, "Background Surface");
+ std::unique_ptr<InputSurface> fgSurface = makeSurface(100, 100, "Foreground Surface");
bgSurface->showAt(100, 100);
fgSurface->mInputInfo->editInfo()->surfaceInset = 5;
@@ -551,8 +558,8 @@
// Ensure a surface whose insets are cropped, handles the touch offset correctly. ref:b/120413463
TEST_F(InputSurfacesTest, input_respects_cropped_surface_insets) {
- std::unique_ptr<InputSurface> parentSurface = makeSurface(100, 100);
- std::unique_ptr<InputSurface> childSurface = makeSurface(100, 100);
+ std::unique_ptr<InputSurface> parentSurface = makeSurface(100, 100, "Parent Surface");
+ std::unique_ptr<InputSurface> childSurface = makeSurface(100, 100, "Child Surface");
parentSurface->showAt(100, 100);
childSurface->mInputInfo->editInfo()->surfaceInset = 10;
@@ -572,8 +579,8 @@
// Ensure a surface whose insets are scaled, handles the touch offset correctly.
TEST_F(InputSurfacesTest, input_respects_scaled_surface_insets) {
- std::unique_ptr<InputSurface> bgSurface = makeSurface(100, 100);
- std::unique_ptr<InputSurface> fgSurface = makeSurface(100, 100);
+ std::unique_ptr<InputSurface> bgSurface = makeSurface(100, 100, "Background Surface");
+ std::unique_ptr<InputSurface> fgSurface = makeSurface(100, 100, "Foreground Surface");
bgSurface->showAt(100, 100);
fgSurface->mInputInfo->editInfo()->surfaceInset = 5;
@@ -590,8 +597,8 @@
}
TEST_F(InputSurfacesTest, input_respects_scaled_surface_insets_overflow) {
- std::unique_ptr<InputSurface> bgSurface = makeSurface(100, 100);
- std::unique_ptr<InputSurface> fgSurface = makeSurface(100, 100);
+ std::unique_ptr<InputSurface> bgSurface = makeSurface(100, 100, "Background Surface");
+ std::unique_ptr<InputSurface> fgSurface = makeSurface(100, 100, "Foreground Surface");
bgSurface->showAt(100, 100);
// In case we pass the very big inset without any checking.
@@ -621,8 +628,8 @@
}
TEST_F(InputSurfacesTest, input_respects_touchable_region_offset_overflow) {
- std::unique_ptr<InputSurface> bgSurface = makeSurface(100, 100);
- std::unique_ptr<InputSurface> fgSurface = makeSurface(100, 100);
+ std::unique_ptr<InputSurface> bgSurface = makeSurface(100, 100, "Background Surface");
+ std::unique_ptr<InputSurface> fgSurface = makeSurface(100, 100, "Foreground Surface");
bgSurface->showAt(100, 100);
// Set the touchable region to the values at the limit of its corresponding type.
@@ -641,8 +648,8 @@
}
TEST_F(InputSurfacesTest, input_respects_scaled_touchable_region_overflow) {
- std::unique_ptr<InputSurface> bgSurface = makeSurface(100, 100);
- std::unique_ptr<InputSurface> fgSurface = makeSurface(100, 100);
+ std::unique_ptr<InputSurface> bgSurface = makeSurface(100, 100, "Background Surface");
+ std::unique_ptr<InputSurface> fgSurface = makeSurface(100, 100, "Foreground Surface");
bgSurface->showAt(0, 0);
fgSurface->mInputInfo->editInfo()->touchableRegion.orSelf(
@@ -707,8 +714,8 @@
}
TEST_F(InputSurfacesTest, input_ignores_color_layer_alpha) {
- std::unique_ptr<InputSurface> bgSurface = makeSurface(100, 100);
- std::unique_ptr<InputSurface> fgSurface = makeSurface(100, 100);
+ std::unique_ptr<InputSurface> bgSurface = makeSurface(100, 100, "Background Surface");
+ std::unique_ptr<InputSurface> fgSurface = makeSurface(100, 100, "Foreground Surface");
bgSurface->showAt(10, 10);
fgSurface->showAt(10, 10);
@@ -839,12 +846,13 @@
}
TEST_F(InputSurfacesTest, touch_flag_obscured) {
- std::unique_ptr<InputSurface> surface = makeSurface(100, 100);
+ std::unique_ptr<InputSurface> surface = makeSurface(100, 100, "Touchable Surface");
surface->showAt(100, 100);
// Add non touchable window to fully cover touchable window. Window behind gets touch, but
// with flag AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED
- std::unique_ptr<InputSurface> nonTouchableSurface = makeSurface(100, 100);
+ std::unique_ptr<InputSurface> nonTouchableSurface =
+ makeSurface(100, 100, "Non-Touchable Surface");
nonTouchableSurface->mInputInfo->editInfo()
->setInputConfig(WindowInfo::InputConfig::NOT_TOUCHABLE, true);
nonTouchableSurface->mInputInfo->editInfo()->ownerUid = gui::Uid{22222};
@@ -858,14 +866,15 @@
}
TEST_F(InputSurfacesTest, touch_flag_partially_obscured_with_crop) {
- std::unique_ptr<InputSurface> surface = makeSurface(100, 100);
+ std::unique_ptr<InputSurface> surface = makeSurface(100, 100, "Test Surface");
surface->showAt(100, 100);
// Add non touchable window to cover touchable window, but parent is cropped to not cover area
// that will be tapped. Window behind gets touch, but with flag
// AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED
- std::unique_ptr<InputSurface> parentSurface = makeSurface(100, 100);
- std::unique_ptr<InputSurface> nonTouchableSurface = makeSurface(100, 100);
+ std::unique_ptr<InputSurface> parentSurface = makeSurface(100, 100, "Parent Surface");
+ std::unique_ptr<InputSurface> nonTouchableSurface =
+ makeSurface(100, 100, "Non-Touchable Surface");
nonTouchableSurface->mInputInfo->editInfo()
->setInputConfig(WindowInfo::InputConfig::NOT_TOUCHABLE, true);
parentSurface->mInputInfo->editInfo()->setInputConfig(WindowInfo::InputConfig::NOT_TOUCHABLE,
@@ -885,13 +894,14 @@
}
TEST_F(InputSurfacesTest, touch_not_obscured_with_crop) {
- std::unique_ptr<InputSurface> surface = makeSurface(100, 100);
+ std::unique_ptr<InputSurface> surface = makeSurface(100, 100, "Test Surface");
surface->showAt(100, 100);
// Add non touchable window to cover touchable window, but parent is cropped to avoid covering
// the touchable window. Window behind gets touch with no obscured flags.
- std::unique_ptr<InputSurface> parentSurface = makeSurface(100, 100);
- std::unique_ptr<InputSurface> nonTouchableSurface = makeSurface(100, 100);
+ std::unique_ptr<InputSurface> parentSurface = makeSurface(100, 100, "Parent Surface");
+ std::unique_ptr<InputSurface> nonTouchableSurface =
+ makeSurface(100, 100, "Non-Touchable Surface");
nonTouchableSurface->mInputInfo->editInfo()
->setInputConfig(WindowInfo::InputConfig::NOT_TOUCHABLE, true);
parentSurface->mInputInfo->editInfo()->setInputConfig(WindowInfo::InputConfig::NOT_TOUCHABLE,
@@ -975,12 +985,12 @@
}
TEST_F(InputSurfacesTest, strict_unobscured_input_obscured_window) {
- std::unique_ptr<InputSurface> surface = makeSurface(100, 100);
+ std::unique_ptr<InputSurface> surface = makeSurface(100, 100, "Test Surface");
surface->mInputInfo->editInfo()->ownerUid = gui::Uid{11111};
surface->doTransaction(
[&](auto& t, auto& sc) { t.setDropInputMode(sc, gui::DropInputMode::OBSCURED); });
surface->showAt(100, 100);
- std::unique_ptr<InputSurface> obscuringSurface = makeSurface(100, 100);
+ std::unique_ptr<InputSurface> obscuringSurface = makeSurface(100, 100, "Obscuring Surface");
obscuringSurface->mInputInfo->editInfo()->setInputConfig(WindowInfo::InputConfig::NOT_TOUCHABLE,
true);
obscuringSurface->mInputInfo->editInfo()->ownerUid = gui::Uid{22222};
@@ -995,12 +1005,12 @@
}
TEST_F(InputSurfacesTest, strict_unobscured_input_partially_obscured_window) {
- std::unique_ptr<InputSurface> surface = makeSurface(100, 100);
+ std::unique_ptr<InputSurface> surface = makeSurface(100, 100, "Test Surface");
surface->mInputInfo->editInfo()->ownerUid = gui::Uid{11111};
surface->doTransaction(
[&](auto& t, auto& sc) { t.setDropInputMode(sc, gui::DropInputMode::OBSCURED); });
surface->showAt(100, 100);
- std::unique_ptr<InputSurface> obscuringSurface = makeSurface(100, 100);
+ std::unique_ptr<InputSurface> obscuringSurface = makeSurface(100, 100, "Obscuring Surface");
obscuringSurface->mInputInfo->editInfo()->setInputConfig(WindowInfo::InputConfig::NOT_TOUCHABLE,
true);
obscuringSurface->mInputInfo->editInfo()->ownerUid = gui::Uid{22222};
@@ -1017,10 +1027,10 @@
}
TEST_F(InputSurfacesTest, strict_unobscured_input_alpha_window) {
- std::unique_ptr<InputSurface> parentSurface = makeSurface(300, 300);
+ std::unique_ptr<InputSurface> parentSurface = makeSurface(300, 300, "Parent Surface");
parentSurface->showAt(0, 0, Rect(0, 0, 300, 300));
- std::unique_ptr<InputSurface> surface = makeSurface(100, 100);
+ std::unique_ptr<InputSurface> surface = makeSurface(100, 100, "Test Surface");
surface->showAt(100, 100);
surface->doTransaction([&](auto& t, auto& sc) {
t.setDropInputMode(sc, gui::DropInputMode::OBSCURED);
@@ -1039,10 +1049,10 @@
}
TEST_F(InputSurfacesTest, strict_unobscured_input_cropped_window) {
- std::unique_ptr<InputSurface> parentSurface = makeSurface(300, 300);
+ std::unique_ptr<InputSurface> parentSurface = makeSurface(300, 300, "Parent Surface");
parentSurface->showAt(0, 0, Rect(0, 0, 300, 300));
- std::unique_ptr<InputSurface> surface = makeSurface(100, 100);
+ std::unique_ptr<InputSurface> surface = makeSurface(100, 100, "Test Surface");
surface->doTransaction([&](auto& t, auto& sc) {
t.setDropInputMode(sc, gui::DropInputMode::OBSCURED);
t.reparent(sc, parentSurface->mSurfaceControl);
@@ -1105,9 +1115,11 @@
*/
TEST_F(InputSurfacesTest, cropped_container_replaces_touchable_region_with_null_crop) {
std::unique_ptr<InputSurface> parentContainer =
- InputSurface::makeContainerInputSurface(mComposerClient, 0, 0);
+ InputSurface::makeContainerInputSurface(mComposerClient, 0, 0,
+ "Parent Container Surface");
std::unique_ptr<InputSurface> containerSurface =
- InputSurface::makeContainerInputSurface(mComposerClient, 100, 100);
+ InputSurface::makeContainerInputSurface(mComposerClient, 100, 100,
+ "Test Container Surface");
containerSurface->doTransaction(
[&](auto& t, auto& sc) { t.reparent(sc, parentContainer->mSurfaceControl); });
containerSurface->mInputInfo->editInfo()->replaceTouchableRegionWithCrop = true;
@@ -1130,11 +1142,14 @@
*/
TEST_F(InputSurfacesTest, uncropped_container_replaces_touchable_region_with_null_crop) {
std::unique_ptr<InputSurface> bgContainer =
- InputSurface::makeContainerInputSurface(mComposerClient, 0, 0);
+ InputSurface::makeContainerInputSurface(mComposerClient, 0, 0,
+ "Background Container Surface");
std::unique_ptr<InputSurface> parentContainer =
- InputSurface::makeContainerInputSurface(mComposerClient, 0, 0);
+ InputSurface::makeContainerInputSurface(mComposerClient, 0, 0,
+ "Parent Container Surface");
std::unique_ptr<InputSurface> containerSurface =
- InputSurface::makeContainerInputSurface(mComposerClient, 100, 100);
+ InputSurface::makeContainerInputSurface(mComposerClient, 100, 100,
+ "Test Container Surface");
containerSurface->doTransaction(
[&](auto& t, auto& sc) { t.reparent(sc, parentContainer->mSurfaceControl); });
containerSurface->mInputInfo->editInfo()->replaceTouchableRegionWithCrop = true;
@@ -1160,11 +1175,11 @@
*/
TEST_F(InputSurfacesTest, replace_touchable_region_with_crop) {
std::unique_ptr<InputSurface> cropLayer =
- InputSurface::makeContainerInputSurface(mComposerClient, 0, 0);
+ InputSurface::makeContainerInputSurface(mComposerClient, 0, 0, "Crop Layer Surface");
cropLayer->showAt(50, 50, Rect(0, 0, 20, 20));
std::unique_ptr<InputSurface> containerSurface =
- InputSurface::makeContainerInputSurface(mComposerClient, 100, 100);
+ InputSurface::makeContainerInputSurface(mComposerClient, 100, 100, "Container Surface");
containerSurface->mInputInfo->editInfo()->replaceTouchableRegionWithCrop = true;
containerSurface->mInputInfo->editInfo()->touchableRegionCropHandle =
cropLayer->mSurfaceControl->getHandle();
@@ -1212,9 +1227,17 @@
sp<IGraphicBufferConsumer> consumer;
sp<IGraphicBufferProducer> producer;
BufferQueue::createBufferQueue(&producer, &consumer);
- consumer->setConsumerName(String8("Virtual disp consumer"));
+ consumer->setConsumerName(String8("Virtual disp consumer (MultiDisplayTests)"));
consumer->setDefaultBufferSize(width, height);
- mProducers.push_back(producer);
+
+ class StubConsumerListener : public BnConsumerListener {
+ virtual void onFrameAvailable(const BufferItem&) override {}
+ virtual void onBuffersReleased() override {}
+ virtual void onSidebandStreamChanged() override {}
+ };
+
+ consumer->consumerConnect(sp<StubConsumerListener>::make(), true);
+ mBufferQueues.push_back({consumer, producer});
std::string name = "VirtualDisplay";
name += std::to_string(mVirtualDisplays.size());
@@ -1231,7 +1254,7 @@
}
std::vector<sp<IBinder>> mVirtualDisplays;
- std::vector<sp<IGraphicBufferProducer>> mProducers;
+ std::vector<std::tuple<sp<IGraphicBufferConsumer>, sp<IGraphicBufferProducer>>> mBufferQueues;
};
TEST_F(MultiDisplayTests, drop_touch_if_layer_on_invalid_display) {
diff --git a/libs/gui/tests/FrameRateUtilsTest.cpp b/libs/gui/tests/FrameRateUtilsTest.cpp
index 5d3287d..9ffe91f 100644
--- a/libs/gui/tests/FrameRateUtilsTest.cpp
+++ b/libs/gui/tests/FrameRateUtilsTest.cpp
@@ -62,7 +62,7 @@
// Invalid compatibility.
EXPECT_FALSE(
ValidateFrameRate(60.0f, -1, ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, ""));
- EXPECT_FALSE(ValidateFrameRate(60.0f, 2, ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, ""));
+ EXPECT_FALSE(ValidateFrameRate(60.0f, 3, ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, ""));
// Invalid change frame rate strategy.
if (flags::bq_setframerate()) {
diff --git a/libs/nativewindow/AHardwareBuffer.cpp b/libs/nativewindow/AHardwareBuffer.cpp
index ca41346..3205c32 100644
--- a/libs/nativewindow/AHardwareBuffer.cpp
+++ b/libs/nativewindow/AHardwareBuffer.cpp
@@ -112,6 +112,10 @@
static_cast<int>(aidl::android::hardware::graphics::common::PixelFormat::RGBA_10101010) ==
AHARDWAREBUFFER_FORMAT_R10G10B10A10_UNORM,
"HAL and AHardwareBuffer pixel format don't match");
+static_assert(
+ static_cast<int>(aidl::android::hardware::graphics::common::PixelFormat::YCBCR_P210) ==
+ AHARDWAREBUFFER_FORMAT_YCbCr_P210,
+ "HAL and AHardwareBuffer pixel format don't match");
static enum AHardwareBufferStatus filterStatus(status_t status) {
switch (status) {
@@ -300,8 +304,10 @@
if (result == 0) {
outPlanes->planeCount = 3;
outPlanes->planes[0].data = yuvData.y;
- // P010 is word-aligned 10-bit semiplaner, and YCbCr_422_I is a single interleaved plane
+ // P010 & P210 are word-aligned 10-bit semiplaner, and YCbCr_422_I is a single interleaved
+ // plane
if (format == AHARDWAREBUFFER_FORMAT_YCbCr_P010 ||
+ format == AHARDWAREBUFFER_FORMAT_YCbCr_P210 ||
format == AHARDWAREBUFFER_FORMAT_YCbCr_422_I) {
outPlanes->planes[0].pixelStride = 2;
} else {
@@ -724,6 +730,7 @@
case AHARDWAREBUFFER_FORMAT_YCrCb_420_SP:
case AHARDWAREBUFFER_FORMAT_YCbCr_422_I:
case AHARDWAREBUFFER_FORMAT_YCbCr_P010:
+ case AHARDWAREBUFFER_FORMAT_YCbCr_P210:
return true;
default:
return false;
diff --git a/libs/renderengine/skia/SkiaRenderEngine.cpp b/libs/renderengine/skia/SkiaRenderEngine.cpp
index b3284e4..b986967 100644
--- a/libs/renderengine/skia/SkiaRenderEngine.cpp
+++ b/libs/renderengine/skia/SkiaRenderEngine.cpp
@@ -1009,7 +1009,7 @@
const auto& item = layer.source.buffer;
auto imageTextureRef = getOrCreateBackendTexture(item.buffer->getBuffer(), false);
- // if the layer's buffer has a fence, then we must must respect the fence prior to using
+ // if the layer's buffer has a fence, then we must respect the fence prior to using
// the buffer.
if (layer.source.buffer.fence != nullptr) {
waitFence(context, layer.source.buffer.fence->get());
diff --git a/libs/ui/DisplayIdentification.cpp b/libs/ui/DisplayIdentification.cpp
index 8d6f74b..c9f0761 100644
--- a/libs/ui/DisplayIdentification.cpp
+++ b/libs/ui/DisplayIdentification.cpp
@@ -417,6 +417,7 @@
return DisplayIdentificationInfo{
.id = displayId,
.name = std::string(edid->displayName),
+ .port = port,
.deviceProductInfo = buildDeviceProductInfo(*edid),
.preferredDetailedTimingDescriptor = edid->preferredDetailedTimingDescriptor,
};
diff --git a/libs/ui/GraphicBuffer.cpp b/libs/ui/GraphicBuffer.cpp
index b0c6e44..18c9a6b 100644
--- a/libs/ui/GraphicBuffer.cpp
+++ b/libs/ui/GraphicBuffer.cpp
@@ -596,6 +596,8 @@
width = height = stride = format = usage_deprecated = 0;
layerCount = 0;
usage = 0;
+ native_handle_close(handle);
+ native_handle_delete(const_cast<native_handle_t*>(handle));
handle = nullptr;
ALOGE("unflatten: registerBuffer failed: %s (%d)", strerror(-err), err);
return err;
diff --git a/libs/ui/include/ui/DisplayIdentification.h b/libs/ui/include/ui/DisplayIdentification.h
index cf67d7b..cdac269 100644
--- a/libs/ui/include/ui/DisplayIdentification.h
+++ b/libs/ui/include/ui/DisplayIdentification.h
@@ -42,6 +42,7 @@
struct DisplayIdentificationInfo {
PhysicalDisplayId id;
std::string name;
+ uint8_t port;
std::optional<DeviceProductInfo> deviceProductInfo;
std::optional<DetailedTimingDescriptor> preferredDetailedTimingDescriptor;
};
diff --git a/libs/ui/include/ui/PublicFormat.h b/libs/ui/include/ui/PublicFormat.h
index e87931e..7c17763 100644
--- a/libs/ui/include/ui/PublicFormat.h
+++ b/libs/ui/include/ui/PublicFormat.h
@@ -60,6 +60,7 @@
JPEG_R = 0x1005,
HEIC = 0x48454946,
HEIC_ULTRAHDR = 0x1006,
+ YCBCR_P210 = 0x3c,
};
/* Convert from android.graphics.ImageFormat/PixelFormat enums to graphics.h HAL
diff --git a/services/sensorservice/Android.bp b/services/sensorservice/Android.bp
index 7b2596a..8c80dd8 100644
--- a/services/sensorservice/Android.bp
+++ b/services/sensorservice/Android.bp
@@ -92,7 +92,7 @@
"libaidlcommonsupport",
"android.hardware.sensors@1.0-convert",
"android.hardware.sensors-V1-convert",
- "android.hardware.sensors-V2-ndk",
+ "android.hardware.sensors-V3-ndk",
"sensorservice_flags_c_lib",
],
diff --git a/services/sensorservice/aidl/Android.bp b/services/sensorservice/aidl/Android.bp
index 542fcae..b9a3491 100644
--- a/services/sensorservice/aidl/Android.bp
+++ b/services/sensorservice/aidl/Android.bp
@@ -28,7 +28,7 @@
"libbinder_ndk",
"libsensor",
"android.frameworks.sensorservice-V1-ndk",
- "android.hardware.sensors-V2-ndk",
+ "android.hardware.sensors-V3-ndk",
],
export_include_dirs: [
"include/",
diff --git a/services/sensorservice/aidl/fuzzer/Android.bp b/services/sensorservice/aidl/fuzzer/Android.bp
index b2dc89b..880df08 100644
--- a/services/sensorservice/aidl/fuzzer/Android.bp
+++ b/services/sensorservice/aidl/fuzzer/Android.bp
@@ -20,7 +20,7 @@
"android.companion.virtual.virtualdevice_aidl-cpp",
"android.frameworks.sensorservice-V1-ndk",
"android.hardware.sensors-V1-convert",
- "android.hardware.sensors-V2-ndk",
+ "android.hardware.sensors-V3-ndk",
"android.hardware.common-V2-ndk",
"libsensor",
"libfakeservicemanager",
diff --git a/services/surfaceflinger/Display/DisplaySnapshot.cpp b/services/surfaceflinger/Display/DisplaySnapshot.cpp
index 0c7a58e..3960740 100644
--- a/services/surfaceflinger/Display/DisplaySnapshot.cpp
+++ b/services/surfaceflinger/Display/DisplaySnapshot.cpp
@@ -26,11 +26,12 @@
namespace android::display {
-DisplaySnapshot::DisplaySnapshot(PhysicalDisplayId displayId,
+DisplaySnapshot::DisplaySnapshot(PhysicalDisplayId displayId, uint8_t port,
ui::DisplayConnectionType connectionType,
DisplayModes&& displayModes, ui::ColorModes&& colorModes,
std::optional<DeviceProductInfo>&& deviceProductInfo)
: mDisplayId(displayId),
+ mPort(port),
mConnectionType(connectionType),
mDisplayModes(std::move(displayModes)),
mColorModes(std::move(colorModes)),
@@ -62,6 +63,8 @@
void DisplaySnapshot::dump(utils::Dumper& dumper) const {
using namespace std::string_view_literals;
+ dumper.dump("port"sv, mPort);
+
dumper.dump("connectionType"sv, ftl::enum_string(mConnectionType));
dumper.dump("colorModes"sv);
diff --git a/services/surfaceflinger/Display/DisplaySnapshot.h b/services/surfaceflinger/Display/DisplaySnapshot.h
index 23471f5..0030aad 100644
--- a/services/surfaceflinger/Display/DisplaySnapshot.h
+++ b/services/surfaceflinger/Display/DisplaySnapshot.h
@@ -16,6 +16,7 @@
#pragma once
+#include <cstdint>
#include <optional>
#include <ui/ColorMode.h>
@@ -30,13 +31,14 @@
// Immutable state of a physical display, captured on hotplug.
class DisplaySnapshot {
public:
- DisplaySnapshot(PhysicalDisplayId, ui::DisplayConnectionType, DisplayModes&&, ui::ColorModes&&,
- std::optional<DeviceProductInfo>&&);
+ DisplaySnapshot(PhysicalDisplayId, uint8_t, ui::DisplayConnectionType, DisplayModes&&,
+ ui::ColorModes&&, std::optional<DeviceProductInfo>&&);
DisplaySnapshot(const DisplaySnapshot&) = delete;
DisplaySnapshot(DisplaySnapshot&&) = default;
PhysicalDisplayId displayId() const { return mDisplayId; }
+ uint8_t port() const { return mPort; }
ui::DisplayConnectionType connectionType() const { return mConnectionType; }
std::optional<DisplayModeId> translateModeId(hal::HWConfigId) const;
@@ -51,6 +53,7 @@
private:
const PhysicalDisplayId mDisplayId;
+ const uint8_t mPort;
const ui::DisplayConnectionType mConnectionType;
// Effectively const except in move constructor.
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 55ccdef..721cfd3 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -1180,6 +1180,7 @@
return DisplayIdentificationInfo{.id = PhysicalDisplayId::fromPort(port),
.name = isPrimary ? "Primary display"
: "Secondary display",
+ .port = port,
.deviceProductInfo = std::nullopt};
}();
diff --git a/services/surfaceflinger/Scheduler/LayerHistory.cpp b/services/surfaceflinger/Scheduler/LayerHistory.cpp
index 171342d..630beb0 100644
--- a/services/surfaceflinger/Scheduler/LayerHistory.cpp
+++ b/services/surfaceflinger/Scheduler/LayerHistory.cpp
@@ -280,6 +280,9 @@
case Layer::FrameRateCompatibility::Exact:
return LayerVoteType::ExplicitExact;
case Layer::FrameRateCompatibility::Gte:
+ if (frameRate.isNoVote()) {
+ return LayerVoteType::NoVote;
+ }
if (isVrrDevice) {
return LayerVoteType::ExplicitGte;
} else {
diff --git a/services/surfaceflinger/Scheduler/LayerInfo.cpp b/services/surfaceflinger/Scheduler/LayerInfo.cpp
index 356c30e..6e2b943 100644
--- a/services/surfaceflinger/Scheduler/LayerInfo.cpp
+++ b/services/surfaceflinger/Scheduler/LayerInfo.cpp
@@ -562,7 +562,10 @@
}
bool LayerInfo::FrameRate::isNoVote() const {
- return vote.type == FrameRateCompatibility::NoVote;
+ // A desired frame rate greater than or equal to 0 is treated as NoVote.
+ bool isNoVoteGte = FlagManager::getInstance().arr_setframerate_gte_enum() &&
+ vote.type == FrameRateCompatibility::Gte && !vote.rate.isValid();
+ return vote.type == FrameRateCompatibility::NoVote || isNoVoteGte;
}
bool LayerInfo::FrameRate::isValuelessType() const {
@@ -577,7 +580,12 @@
case FrameRateCompatibility::Default:
case FrameRateCompatibility::ExactOrMultiple:
case FrameRateCompatibility::Exact:
+ return false;
case FrameRateCompatibility::Gte:
+ if (isNoVote()) {
+ // Special case: GTE 0 is same as NoVote.
+ return true;
+ }
return false;
}
}
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index 3fdddac..a2cdd46 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -209,6 +209,7 @@
ftl::FakeGuard guard(kMainThreadContext);
resyncToHardwareVsyncLocked(id, allowToEnable, modePtr);
}
+ void resync() override EXCLUDES(mDisplayLock);
void forceNextResync() { mLastResyncTime = 0; }
// Passes a vsync sample to VsyncController. Returns true if
@@ -470,7 +471,6 @@
bool throttleVsync(TimePoint, uid_t) override;
// Get frame interval
Period getVsyncPeriod(uid_t) override EXCLUDES(mDisplayLock);
- void resync() override EXCLUDES(mDisplayLock);
void onExpectedPresentTimePosted(TimePoint expectedPresentTime) override EXCLUDES(mDisplayLock);
std::unique_ptr<EventThread> mRenderEventThread;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 59b1917..e6b6f4e 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -877,6 +877,9 @@
} else if (algorithm == "kawase2") {
return renderengine::RenderEngine::BlurAlgorithm::KAWASE_DUAL_FILTER;
} else {
+ if (FlagManager::getInstance().window_blur_kawase2()) {
+ return renderengine::RenderEngine::BlurAlgorithm::KAWASE_DUAL_FILTER;
+ }
return renderengine::RenderEngine::BlurAlgorithm::KAWASE;
}
}
@@ -3631,10 +3634,13 @@
deviceProductInfo = snapshot.deviceProductInfo();
}
+ // Use the cached port via snapshot because we are updating an existing
+ // display on reconnect.
const auto it =
mPhysicalDisplays.try_replace(displayId, display.token(), displayId,
- snapshot.connectionType(), std::move(displayModes),
- std::move(colorModes), std::move(deviceProductInfo));
+ snapshot.port(), snapshot.connectionType(),
+ std::move(displayModes), std::move(colorModes),
+ std::move(deviceProductInfo));
auto& state = mCurrentState.displays.editValueFor(it->second.token());
state.sequenceId = DisplayDeviceState{}.sequenceId; // Generate new sequenceId.
@@ -3647,7 +3653,7 @@
const ui::DisplayConnectionType connectionType =
getHwComposer().getDisplayConnectionType(displayId);
- mPhysicalDisplays.try_emplace(displayId, token, displayId, connectionType,
+ mPhysicalDisplays.try_emplace(displayId, token, displayId, info.port, connectionType,
std::move(displayModes), std::move(colorModes),
std::move(info.deviceProductInfo));
@@ -4563,6 +4569,7 @@
SFTRACE_INT("mTransactionFlags", transactionFlags);
if (const bool scheduled = transactionFlags & mask; !scheduled) {
+ mScheduler->resync();
scheduleCommit(frameHint);
} else if (frameHint == FrameHint::kActive) {
// Even if the next frame is already scheduled, we should reset the idle timer
diff --git a/services/surfaceflinger/common/Android.bp b/services/surfaceflinger/common/Android.bp
index f9c99bf..8786f6e 100644
--- a/services/surfaceflinger/common/Android.bp
+++ b/services/surfaceflinger/common/Android.bp
@@ -38,6 +38,7 @@
],
static_libs: [
"libsurfaceflingerflags",
+ "aconfig_hardware_flags_c_lib",
"android.os.flags-aconfig-cc",
"android.server.display.flags-aconfig-cc",
"libguiflags_no_apex",
@@ -51,6 +52,7 @@
],
static_libs: [
"libsurfaceflingerflags_test",
+ "aconfig_hardware_flags_c_lib",
"android.os.flags-aconfig-cc-test",
"android.server.display.flags-aconfig-cc",
"libguiflags_no_apex",
@@ -67,6 +69,7 @@
static_libs: [
"libsurfaceflinger_common",
"libsurfaceflingerflags",
+ "aconfig_hardware_flags_c_lib",
"android.os.flags-aconfig-cc",
"android.server.display.flags-aconfig-cc",
"libguiflags_no_apex",
@@ -83,6 +86,7 @@
static_libs: [
"libsurfaceflinger_common_test",
"libsurfaceflingerflags_test",
+ "aconfig_hardware_flags_c_lib",
"android.os.flags-aconfig-cc-test",
"android.server.display.flags-aconfig-cc",
"libguiflags_no_apex",
diff --git a/services/surfaceflinger/common/FlagManager.cpp b/services/surfaceflinger/common/FlagManager.cpp
index e28a0c1..5e78426 100644
--- a/services/surfaceflinger/common/FlagManager.cpp
+++ b/services/surfaceflinger/common/FlagManager.cpp
@@ -27,6 +27,7 @@
#include <cinttypes>
#include <android_os.h>
+#include <android_hardware_flags.h>
#include <com_android_graphics_libgui_flags.h>
#include <com_android_graphics_surfaceflinger_flags.h>
#include <com_android_server_display_feature_flags.h>
@@ -164,6 +165,7 @@
DUMP_ACONFIG_FLAG(deprecate_frame_tracker);
DUMP_ACONFIG_FLAG(skip_invisible_windows_in_input);
DUMP_ACONFIG_FLAG(begone_bright_hlg);
+ DUMP_ACONFIG_FLAG(window_blur_kawase2);
#undef DUMP_ACONFIG_FLAG
#undef DUMP_LEGACY_SERVER_FLAG
@@ -263,6 +265,7 @@
FLAG_MANAGER_ACONFIG_FLAG(deprecate_frame_tracker, "");
FLAG_MANAGER_ACONFIG_FLAG(skip_invisible_windows_in_input, "");
FLAG_MANAGER_ACONFIG_FLAG(begone_bright_hlg, "debug.sf.begone_bright_hlg");
+FLAG_MANAGER_ACONFIG_FLAG(window_blur_kawase2, "");
/// Trunk stable server (R/W) flags ///
FLAG_MANAGER_ACONFIG_FLAG(refresh_rate_overlay_on_external_display, "")
@@ -279,5 +282,6 @@
FLAG_MANAGER_ACONFIG_FLAG_IMPORTED(adpf_use_fmq_channel_fixed, "", android::os)
FLAG_MANAGER_ACONFIG_FLAG_IMPORTED(trace_frame_rate_override, "",
com::android::graphics::libgui::flags);
-
+FLAG_MANAGER_ACONFIG_FLAG_IMPORTED(luts_api, "",
+ android::hardware::flags);
} // namespace android
diff --git a/services/surfaceflinger/common/include/common/FlagManager.h b/services/surfaceflinger/common/include/common/FlagManager.h
index 1a857c8..d8887f5 100644
--- a/services/surfaceflinger/common/include/common/FlagManager.h
+++ b/services/surfaceflinger/common/include/common/FlagManager.h
@@ -102,6 +102,8 @@
bool deprecate_frame_tracker() const;
bool skip_invisible_windows_in_input() const;
bool begone_bright_hlg() const;
+ bool luts_api() const;
+ bool window_blur_kawase2() const;
protected:
// overridden for unit tests
diff --git a/services/surfaceflinger/surfaceflinger_flags_new.aconfig b/services/surfaceflinger/surfaceflinger_flags_new.aconfig
index d6a1ad4..bdd826d 100644
--- a/services/surfaceflinger/surfaceflinger_flags_new.aconfig
+++ b/services/surfaceflinger/surfaceflinger_flags_new.aconfig
@@ -31,6 +31,7 @@
description: "New SDK Surface#setFrameRate API and Surface.FrameRateParams for Android 16"
bug: "356987016"
is_fixed_read_only: true
+ is_exported: true
} # arr_setframerate_api
flag {
@@ -47,6 +48,7 @@
description: "New SDK SurfaceControl.Transaction#setFrameRate API for Android 16"
bug: "356987016"
is_fixed_read_only: true
+ is_exported: true
} # arr_surfacecontrol_setframerate_api
flag {
@@ -293,4 +295,11 @@
}
} # vrr_bugfix_dropped_frame
+flag {
+ name: "window_blur_kawase2"
+ namespace: "core_graphics"
+ description: "Flag for using Kawase2 algorithm for window blur"
+ bug: "353826438"
+} # window_blur_kawase2
+
# IMPORTANT - please keep alphabetize to reduce merge conflicts
diff --git a/services/surfaceflinger/tests/MultiDisplayLayerBounds_test.cpp b/services/surfaceflinger/tests/MultiDisplayLayerBounds_test.cpp
index 56cf13d..65add63 100644
--- a/services/surfaceflinger/tests/MultiDisplayLayerBounds_test.cpp
+++ b/services/surfaceflinger/tests/MultiDisplayLayerBounds_test.cpp
@@ -19,6 +19,7 @@
#pragma clang diagnostic ignored "-Wconversion"
#include <common/FlagManager.h>
+#include <gui/IConsumerListener.h>
#include <ui/DisplayState.h>
#include "LayerTransactionTest.h"
@@ -45,11 +46,17 @@
SurfaceComposerClient::getDisplayState(mMainDisplay, &mMainDisplayState);
SurfaceComposerClient::getActiveDisplayMode(mMainDisplay, &mMainDisplayMode);
- sp<IGraphicBufferConsumer> consumer;
- BufferQueue::createBufferQueue(&mProducer, &consumer);
- consumer->setConsumerName(String8("Virtual disp consumer"));
- consumer->setDefaultBufferSize(mMainDisplayMode.resolution.getWidth(),
- mMainDisplayMode.resolution.getHeight());
+ BufferQueue::createBufferQueue(&mProducer, &mConsumer);
+ mConsumer->setConsumerName(String8("Virtual disp consumer (MultiDisplayLayerBounds)"));
+ mConsumer->setDefaultBufferSize(mMainDisplayMode.resolution.getWidth(),
+ mMainDisplayMode.resolution.getHeight());
+
+ class StubConsumerListener : public BnConsumerListener {
+ virtual void onFrameAvailable(const BufferItem&) override {}
+ virtual void onBuffersReleased() override {}
+ virtual void onSidebandStreamChanged() override {}
+ };
+ mConsumer->consumerConnect(sp<StubConsumerListener>::make(), true);
}
virtual void TearDown() {
@@ -92,6 +99,7 @@
sp<IBinder> mMainDisplay;
PhysicalDisplayId mMainDisplayId;
sp<IBinder> mVirtualDisplay;
+ sp<IGraphicBufferConsumer> mConsumer;
sp<IGraphicBufferProducer> mProducer;
sp<SurfaceControl> mColorLayer;
Color mExpectedColor = {63, 63, 195, 255};
diff --git a/services/surfaceflinger/tests/TransactionTestHarnesses.h b/services/surfaceflinger/tests/TransactionTestHarnesses.h
index bf5957a..c95c875 100644
--- a/services/surfaceflinger/tests/TransactionTestHarnesses.h
+++ b/services/surfaceflinger/tests/TransactionTestHarnesses.h
@@ -58,7 +58,7 @@
GRALLOC_USAGE_HW_VIDEO_ENCODER | GRALLOC_USAGE_SW_READ_OFTEN);
sp<BufferListener> listener = sp<BufferListener>::make(this);
itemConsumer->setFrameAvailableListener(listener);
- itemConsumer->setName(String8("Virtual disp consumer"));
+ itemConsumer->setName(String8("Virtual disp consumer (TransactionTest)"));
itemConsumer->setDefaultBufferSize(resolution.getWidth(), resolution.getHeight());
#else
sp<IGraphicBufferProducer> producer;
@@ -66,7 +66,7 @@
sp<BufferItemConsumer> itemConsumer;
BufferQueue::createBufferQueue(&producer, &consumer);
- consumer->setConsumerName(String8("Virtual disp consumer"));
+ consumer->setConsumerName(String8("Virtual disp consumer (TransactionTest)"));
consumer->setDefaultBufferSize(resolution.getWidth(), resolution.getHeight());
itemConsumer = sp<BufferItemConsumer>::make(consumer,
diff --git a/services/surfaceflinger/tests/VirtualDisplay_test.cpp b/services/surfaceflinger/tests/VirtualDisplay_test.cpp
index d69378c..1108c7f 100644
--- a/services/surfaceflinger/tests/VirtualDisplay_test.cpp
+++ b/services/surfaceflinger/tests/VirtualDisplay_test.cpp
@@ -29,14 +29,14 @@
void SetUp() override {
#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ)
mGLConsumer = sp<GLConsumer>::make(GLConsumer::TEXTURE_EXTERNAL, true, false, false);
- mGLConsumer->setName(String8("Virtual disp consumer"));
+ mGLConsumer->setName(String8("Virtual disp consumer (VirtualDisplayTest)"));
mGLConsumer->setDefaultBufferSize(100, 100);
mProducer = mGLConsumer->getSurface()->getIGraphicBufferProducer();
#else
sp<IGraphicBufferConsumer> consumer;
BufferQueue::createBufferQueue(&mProducer, &consumer);
- consumer->setConsumerName(String8("Virtual disp consumer"));
+ consumer->setConsumerName(String8("Virtual disp consumer (VirtualDisplayTest)"));
consumer->setDefaultBufferSize(100, 100);
mGLConsumer = sp<GLConsumer>::make(consumer, GLConsumer::TEXTURE_EXTERNAL, true, false);
diff --git a/services/surfaceflinger/tests/unittests/CommitAndCompositeTest.h b/services/surfaceflinger/tests/unittests/CommitAndCompositeTest.h
index b517ff0..c858d9a 100644
--- a/services/surfaceflinger/tests/unittests/CommitAndCompositeTest.h
+++ b/services/surfaceflinger/tests/unittests/CommitAndCompositeTest.h
@@ -54,8 +54,8 @@
compositionengine::impl::createDisplay(mFlinger.getCompositionEngine(),
std::move(compostionEngineDisplayArgs));
mDisplay = FakeDisplayDeviceInjector(mFlinger, compositionDisplay,
- ui::DisplayConnectionType::Internal, HWC_DISPLAY,
- kIsPrimary)
+ ui::DisplayConnectionType::Internal,
+ DEFAULT_DISPLAY_PORT, HWC_DISPLAY, kIsPrimary)
.setDisplaySurface(mDisplaySurface)
.setNativeWindow(mNativeWindow)
.setPowerMode(hal::PowerMode::ON)
@@ -68,7 +68,9 @@
using FakeDisplayDeviceInjector = TestableSurfaceFlinger::FakeDisplayDeviceInjector;
static constexpr hal::HWDisplayId HWC_DISPLAY = FakeHwcDisplayInjector::DEFAULT_HWC_DISPLAY_ID;
- static constexpr PhysicalDisplayId DEFAULT_DISPLAY_ID = PhysicalDisplayId::fromPort(42u);
+ static constexpr uint8_t DEFAULT_DISPLAY_PORT = 42u;
+ static constexpr PhysicalDisplayId DEFAULT_DISPLAY_ID =
+ PhysicalDisplayId::fromPort(DEFAULT_DISPLAY_PORT);
static constexpr int DEFAULT_DISPLAY_WIDTH = 1920;
static constexpr int DEFAULT_DISPLAY_HEIGHT = 1024;
diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
index 860ad2e..71cafbf 100644
--- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
@@ -76,7 +76,8 @@
constexpr hal::HWLayerId HWC_LAYER = 5000;
constexpr Transform DEFAULT_TRANSFORM = static_cast<Transform>(0);
-constexpr PhysicalDisplayId DEFAULT_DISPLAY_ID = PhysicalDisplayId::fromPort(42u);
+constexpr uint8_t DEFAULT_DISPLAY_PORT = 42u;
+constexpr PhysicalDisplayId DEFAULT_DISPLAY_ID = PhysicalDisplayId::fromPort(DEFAULT_DISPLAY_PORT);
constexpr int DEFAULT_DISPLAY_WIDTH = 1920;
constexpr int DEFAULT_DISPLAY_HEIGHT = 1024;
@@ -276,7 +277,8 @@
test->mDisplay =
FakeDisplayDeviceInjector(test->mFlinger, compositionDisplay,
- kDisplayConnectionType, HWC_DISPLAY, kIsPrimary)
+ kDisplayConnectionType, DEFAULT_DISPLAY_PORT, HWC_DISPLAY,
+ kIsPrimary)
.setDisplaySurface(test->mDisplaySurface)
.setNativeWindow(test->mNativeWindow)
.setSecure(Derived::IS_SECURE)
diff --git a/services/surfaceflinger/tests/unittests/DisplayModeControllerTest.cpp b/services/surfaceflinger/tests/unittests/DisplayModeControllerTest.cpp
index 29a1fab..c6cbe52 100644
--- a/services/surfaceflinger/tests/unittests/DisplayModeControllerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DisplayModeControllerTest.cpp
@@ -71,7 +71,7 @@
ASSERT_TRUE(infoOpt);
mDisplayId = infoOpt->id;
- mDisplaySnapshotOpt.emplace(mDisplayId, ui::DisplayConnectionType::Internal,
+ mDisplaySnapshotOpt.emplace(mDisplayId, infoOpt->port, ui::DisplayConnectionType::Internal,
makeModes(kMode60, kMode90, kMode120), ui::ColorModes{},
std::nullopt);
diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h b/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h
index fa976c8..6e231aa 100644
--- a/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h
@@ -231,6 +231,16 @@
static constexpr std::optional<HWDisplayId> value = PhysicalDisplay::HWC_DISPLAY_ID;
};
+template <typename>
+struct PortGetter {
+ static constexpr std::optional<uint8_t> value;
+};
+
+template <typename PhysicalDisplay>
+struct PortGetter<PhysicalDisplayIdType<PhysicalDisplay>> {
+ static constexpr std::optional<uint8_t> value = PhysicalDisplay::PORT;
+};
+
// DisplayIdType can be:
// 1) PhysicalDisplayIdType<...> for generated ID of physical display backed by HWC.
// 2) HalVirtualDisplayIdType<...> for hard-coded ID of virtual display backed by HWC.
@@ -241,6 +251,7 @@
using DISPLAY_ID = DisplayIdGetter<DisplayIdType>;
using CONNECTION_TYPE = DisplayConnectionTypeGetter<DisplayIdType>;
using HWC_DISPLAY_ID_OPT = HwcDisplayIdGetter<DisplayIdType>;
+ using PORT = PortGetter<DisplayIdType>;
static constexpr int WIDTH = width;
static constexpr int HEIGHT = height;
@@ -277,6 +288,7 @@
TestableSurfaceFlinger::FakeDisplayDeviceInjector(test->mFlinger,
compositionDisplay,
CONNECTION_TYPE::value,
+ PORT::value,
HWC_DISPLAY_ID_OPT::value,
static_cast<bool>(PRIMARY));
@@ -558,6 +570,10 @@
/*hasIdentificationData=*/true, kNonSecure>,
1080, 2092>;
+using ExternalDisplayWithIdentificationVariant =
+ PhysicalDisplayVariant<SecondaryDisplay<ui::DisplayConnectionType::External,
+ /*hasIdentificationData=*/true, kNonSecure>,
+ 1920, 1280>;
using ExternalDisplayVariant =
PhysicalDisplayVariant<SecondaryDisplay<ui::DisplayConnectionType::External,
/*hasIdentificationData=*/false, kSecure>,
diff --git a/services/surfaceflinger/tests/unittests/FakeDisplayInjector.h b/services/surfaceflinger/tests/unittests/FakeDisplayInjector.h
index 744c536..5f7a9f2 100644
--- a/services/surfaceflinger/tests/unittests/FakeDisplayInjector.h
+++ b/services/surfaceflinger/tests/unittests/FakeDisplayInjector.h
@@ -24,12 +24,15 @@
namespace android {
+static constexpr uint8_t kDefaultPort = 255u;
+
using FakeDisplayDeviceInjector = TestableSurfaceFlinger::FakeDisplayDeviceInjector;
using android::adpf::mock::PowerAdvisor;
using android::hardware::graphics::composer::hal::HWDisplayId;
struct FakeDisplayInjectorArgs {
- PhysicalDisplayId displayId = PhysicalDisplayId::fromPort(255u);
+ PhysicalDisplayId displayId = PhysicalDisplayId::fromPort(kDefaultPort);
+ uint8_t port = kDefaultPort;
HWDisplayId hwcDisplayId = 0;
bool isPrimary = true;
};
@@ -73,7 +76,7 @@
.build());
auto injector = FakeDisplayDeviceInjector(mFlinger, compositionDisplay,
- ui::DisplayConnectionType::Internal,
+ ui::DisplayConnectionType::Internal, args.port,
args.hwcDisplayId, args.isPrimary);
injector.setNativeWindow(mNativeWindow);
diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryIntegrationTest.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryIntegrationTest.cpp
index f9bfe97..53a9062 100644
--- a/services/surfaceflinger/tests/unittests/LayerHistoryIntegrationTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerHistoryIntegrationTest.cpp
@@ -654,6 +654,72 @@
EXPECT_EQ(FrameRateCategory::Default, summarizeLayerHistory(time)[0].frameRateCategory);
}
+TEST_F(LayerHistoryIntegrationTest, oneLayerGteNoVote_arr) {
+ SET_FLAG_FOR_TEST(flags::arr_setframerate_gte_enum, true);
+ // Set the test to be on a vrr mode.
+ SET_FLAG_FOR_TEST(flags::vrr_config, true);
+ mSelector->setActiveMode(kVrrModeId, HI_FPS);
+
+ auto layer = createLegacyAndFrontedEndLayer(1);
+ showLayer(1);
+ setFrameRate(1, (0_Hz).getValue(), ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_GTE,
+ ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS);
+
+ EXPECT_EQ(1u, layerCount());
+ EXPECT_EQ(0u, activeLayerCount());
+
+ nsecs_t time = systemTime();
+ for (size_t i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
+ setBufferWithPresentTime(layer, time);
+ time += HI_FPS_PERIOD;
+ }
+
+ // Layer is active but GTE with 0 should be considered NoVote, thus nothing from summarize.
+ ASSERT_EQ(0u, summarizeLayerHistory(time).size());
+ EXPECT_EQ(1u, activeLayerCount());
+ EXPECT_EQ(1, frequentLayerCount(time));
+
+ // layer became inactive.
+ setDefaultLayerVote(layer.get(), LayerHistory::LayerVoteType::Heuristic);
+ time += MAX_ACTIVE_LAYER_PERIOD_NS.count();
+ ASSERT_EQ(0u, summarizeLayerHistory(time).size());
+ EXPECT_EQ(0u, activeLayerCount());
+ EXPECT_EQ(0, frequentLayerCount(time));
+}
+
+TEST_F(LayerHistoryIntegrationTest, oneLayerGteNoVote_mrr) {
+ SET_FLAG_FOR_TEST(flags::arr_setframerate_gte_enum, true);
+ // True by default on MRR devices as well, but the device is not set to VRR mode.
+ SET_FLAG_FOR_TEST(flags::vrr_config, true);
+
+ auto layer = createLegacyAndFrontedEndLayer(1);
+ showLayer(1);
+ setFrameRate(1, (0_Hz).getValue(), ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_GTE,
+ ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS);
+ setFrameRateCategory(1, 0);
+
+ EXPECT_EQ(1u, layerCount());
+ EXPECT_EQ(0u, activeLayerCount());
+
+ nsecs_t time = systemTime();
+ for (size_t i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
+ setBufferWithPresentTime(layer, time);
+ time += HI_FPS_PERIOD;
+ }
+
+ // Layer is active but GTE with 0 should be considered NoVote, thus nothing from summarize.
+ ASSERT_EQ(0u, summarizeLayerHistory(time).size());
+ EXPECT_EQ(1u, activeLayerCount());
+ EXPECT_EQ(1, frequentLayerCount(time));
+
+ // layer became inactive.
+ setDefaultLayerVote(layer.get(), LayerHistory::LayerVoteType::Heuristic);
+ time += MAX_ACTIVE_LAYER_PERIOD_NS.count();
+ ASSERT_EQ(0u, summarizeLayerHistory(time).size());
+ EXPECT_EQ(0u, activeLayerCount());
+ EXPECT_EQ(0, frequentLayerCount(time));
+}
+
TEST_F(LayerHistoryIntegrationTest, oneLayerExplicitVoteWithCategory_vrrFeatureOff) {
SET_FLAG_FOR_TEST(flags::frame_rate_category_mrr, false);
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp
index b0dd5c2..a506873 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp
@@ -126,8 +126,9 @@
static constexpr HWDisplayId kInnerDisplayHwcId = PrimaryDisplayVariant::HWC_DISPLAY_ID;
static constexpr HWDisplayId kOuterDisplayHwcId = kInnerDisplayHwcId + 1;
-
- static constexpr PhysicalDisplayId kOuterDisplayId = PhysicalDisplayId::fromPort(254u);
+ static constexpr uint8_t kOuterDisplayPort = 254u;
+ static constexpr PhysicalDisplayId kOuterDisplayId =
+ PhysicalDisplayId::fromPort(kOuterDisplayPort);
auto injectOuterDisplay() {
// For the inner display, this is handled by setupHwcHotplugCallExpectations.
@@ -149,6 +150,7 @@
kModeId120);
},
{.displayId = kOuterDisplayId,
+ .port = kOuterDisplayPort,
.hwcDisplayId = kOuterDisplayHwcId,
.isPrimary = kIsPrimary});
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_HotplugTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_HotplugTest.cpp
index aef467a..4e7a174 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_HotplugTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_HotplugTest.cpp
@@ -59,6 +59,137 @@
EXPECT_TRUE(hasTransactionFlagSet(eDisplayTransactionNeeded));
}
+TEST_F(HotplugTest, createsDisplaySnapshotsForDisplaysWithIdentificationData) {
+ // Configure a primary display with identification data.
+ using PrimaryDisplay = InnerDisplayVariant;
+ PrimaryDisplay::setupHwcHotplugCallExpectations(this);
+ PrimaryDisplay::setupHwcGetActiveConfigCallExpectations(this);
+ PrimaryDisplay::injectPendingHotplugEvent(this, Connection::CONNECTED);
+
+ // TODO(b/241286146): Remove this unnecessary call.
+ EXPECT_CALL(*mComposer,
+ setVsyncEnabled(PrimaryDisplay::HWC_DISPLAY_ID, IComposerClient::Vsync::DISABLE))
+ .WillOnce(Return(Error::NONE));
+
+ // A single commit should be scheduled.
+ EXPECT_CALL(*mFlinger.scheduler(), scheduleFrame(_)).Times(1);
+
+ mFlinger.configure();
+
+ // Configure an external display with identification info.
+ using ExternalDisplay = ExternalDisplayWithIdentificationVariant;
+ ExternalDisplay::setupHwcHotplugCallExpectations(this);
+ ExternalDisplay::setupHwcGetActiveConfigCallExpectations(this);
+ ExternalDisplay::injectPendingHotplugEvent(this, Connection::CONNECTED);
+
+ // TODO(b/241286146): Remove this unnecessary call.
+ EXPECT_CALL(*mComposer,
+ setVsyncEnabled(ExternalDisplay::HWC_DISPLAY_ID, IComposerClient::Vsync::DISABLE))
+ .WillOnce(Return(Error::NONE));
+
+ mFlinger.configure();
+
+ EXPECT_TRUE(hasPhysicalHwcDisplay(PrimaryDisplay::HWC_DISPLAY_ID));
+ EXPECT_TRUE(mFlinger.getHwComposer().isConnected(PrimaryDisplay::DISPLAY_ID::get()));
+ const auto primaryDisplayIdOpt =
+ mFlinger.getHwComposer().toPhysicalDisplayId(PrimaryDisplay::HWC_DISPLAY_ID);
+ ASSERT_TRUE(primaryDisplayIdOpt.has_value());
+ const auto primaryPhysicalDisplayOpt =
+ mFlinger.physicalDisplays().get(primaryDisplayIdOpt.value());
+ ASSERT_TRUE(primaryPhysicalDisplayOpt.has_value());
+ const auto primaryDisplaySnapshotRef = primaryPhysicalDisplayOpt->get().snapshotRef();
+ EXPECT_EQ(PrimaryDisplay::DISPLAY_ID::get(), primaryDisplaySnapshotRef.get().displayId());
+ EXPECT_EQ(PrimaryDisplay::PORT::value, primaryDisplaySnapshotRef.get().port());
+ EXPECT_EQ(PrimaryDisplay::CONNECTION_TYPE::value,
+ primaryDisplaySnapshotRef.get().connectionType());
+
+ EXPECT_TRUE(hasPhysicalHwcDisplay(ExternalDisplay::HWC_DISPLAY_ID));
+ EXPECT_TRUE(mFlinger.getHwComposer().isConnected(ExternalDisplay::DISPLAY_ID::get()));
+ const auto externalDisplayIdOpt =
+ mFlinger.getHwComposer().toPhysicalDisplayId(ExternalDisplay::HWC_DISPLAY_ID);
+ ASSERT_TRUE(externalDisplayIdOpt.has_value());
+ const auto externalPhysicalDisplayOpt =
+ mFlinger.physicalDisplays().get(externalDisplayIdOpt.value());
+ ASSERT_TRUE(externalPhysicalDisplayOpt.has_value());
+ const auto externalDisplaySnapshotRef = externalPhysicalDisplayOpt->get().snapshotRef();
+ EXPECT_EQ(ExternalDisplay::DISPLAY_ID::get(), externalDisplaySnapshotRef.get().displayId());
+ EXPECT_EQ(ExternalDisplay::PORT::value, externalDisplaySnapshotRef.get().port());
+ EXPECT_EQ(ExternalDisplay::CONNECTION_TYPE::value,
+ externalDisplaySnapshotRef.get().connectionType());
+}
+
+TEST_F(HotplugTest, createsDisplaySnapshotsForDisplaysWithoutIdentificationData) {
+ // Configure a primary display without identification data.
+ using PrimaryDisplay = PrimaryDisplayVariant;
+ PrimaryDisplay::setupHwcHotplugCallExpectations(this);
+ PrimaryDisplay::setupHwcGetActiveConfigCallExpectations(this);
+ PrimaryDisplay::injectPendingHotplugEvent(this, Connection::CONNECTED);
+
+ // TODO(b/241286146): Remove this unnecessary call.
+ EXPECT_CALL(*mComposer,
+ setVsyncEnabled(PrimaryDisplay::HWC_DISPLAY_ID, IComposerClient::Vsync::DISABLE))
+ .WillOnce(Return(Error::NONE));
+
+ // A single commit should be scheduled.
+ EXPECT_CALL(*mFlinger.scheduler(), scheduleFrame(_)).Times(1);
+
+ mFlinger.configure();
+
+ // Configure an external display with identification info.
+ using ExternalDisplay = ExternalDisplayWithIdentificationVariant;
+ ExternalDisplay::setupHwcHotplugCallExpectations(this);
+ ExternalDisplay::setupHwcGetActiveConfigCallExpectations(this);
+ ExternalDisplay::injectPendingHotplugEvent(this, Connection::CONNECTED);
+
+ // TODO(b/241286146): Remove this unnecessary call.
+ EXPECT_CALL(*mComposer,
+ setVsyncEnabled(ExternalDisplay::HWC_DISPLAY_ID, IComposerClient::Vsync::DISABLE))
+ .WillOnce(Return(Error::NONE));
+
+ mFlinger.configure();
+
+ // Both ID and port are expected to be equal to 0 for primary internal display due to no
+ // identification data.
+ constexpr uint8_t primaryInternalDisplayPort = 0u;
+ constexpr PhysicalDisplayId primaryInternalDisplayId =
+ PhysicalDisplayId::fromPort(primaryInternalDisplayPort);
+ EXPECT_TRUE(hasPhysicalHwcDisplay(PrimaryDisplay::HWC_DISPLAY_ID));
+ ASSERT_EQ(primaryInternalDisplayId, PrimaryDisplay::DISPLAY_ID::get());
+ EXPECT_TRUE(mFlinger.getHwComposer().isConnected(PrimaryDisplay::DISPLAY_ID::get()));
+ const auto primaryDisplayIdOpt =
+ mFlinger.getHwComposer().toPhysicalDisplayId(PrimaryDisplay::HWC_DISPLAY_ID);
+ ASSERT_TRUE(primaryDisplayIdOpt.has_value());
+ const auto primaryPhysicalDisplayOpt =
+ mFlinger.physicalDisplays().get(primaryDisplayIdOpt.value());
+ ASSERT_TRUE(primaryPhysicalDisplayOpt.has_value());
+ const auto primaryDisplaySnapshotRef = primaryPhysicalDisplayOpt->get().snapshotRef();
+ EXPECT_EQ(primaryInternalDisplayId, primaryDisplaySnapshotRef.get().displayId());
+ EXPECT_EQ(primaryInternalDisplayPort, primaryDisplaySnapshotRef.get().port());
+ EXPECT_EQ(PrimaryDisplay::CONNECTION_TYPE::value,
+ primaryDisplaySnapshotRef.get().connectionType());
+
+ // Even though the external display has identification data available, the lack of data for the
+ // internal display has set of the legacy multi-display mode in SF and therefore the external
+ // display's identification data will be ignored.
+ // Both ID and port are expected to be equal to 1 for external internal display.
+ constexpr uint8_t externalDisplayPort = 1u;
+ constexpr PhysicalDisplayId externalDisplayId =
+ PhysicalDisplayId::fromPort(externalDisplayPort);
+ EXPECT_TRUE(hasPhysicalHwcDisplay(ExternalDisplay::HWC_DISPLAY_ID));
+ EXPECT_TRUE(mFlinger.getHwComposer().isConnected(externalDisplayId));
+ const auto externalDisplayIdOpt =
+ mFlinger.getHwComposer().toPhysicalDisplayId(ExternalDisplay::HWC_DISPLAY_ID);
+ ASSERT_TRUE(externalDisplayIdOpt.has_value());
+ const auto externalPhysicalDisplayOpt =
+ mFlinger.physicalDisplays().get(externalDisplayIdOpt.value());
+ ASSERT_TRUE(externalPhysicalDisplayOpt.has_value());
+ const auto externalDisplaySnapshotRef = externalPhysicalDisplayOpt->get().snapshotRef();
+ EXPECT_EQ(externalDisplayId, externalDisplaySnapshotRef.get().displayId());
+ EXPECT_EQ(externalDisplayPort, externalDisplaySnapshotRef.get().port());
+ EXPECT_EQ(ExternalDisplay::CONNECTION_TYPE::value,
+ externalDisplaySnapshotRef.get().connectionType());
+}
+
TEST_F(HotplugTest, ignoresDuplicateDisconnection) {
// Inject a primary display.
PrimaryDisplayVariant::injectHwcDisplay(this);
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp
index 352000e..6951eaf 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp
@@ -239,6 +239,8 @@
ASSERT_TRUE(displayId);
const auto hwcDisplayId = Case::Display::HWC_DISPLAY_ID_OPT::value;
ASSERT_TRUE(hwcDisplayId);
+ const auto port = Case::Display::PORT::value;
+ ASSERT_TRUE(port);
mFlinger.getHwComposer().allocatePhysicalDisplay(*hwcDisplayId, *displayId, std::nullopt);
DisplayModePtr activeMode = DisplayMode::Builder(Case::Display::HWC_ACTIVE_CONFIG_ID)
.setResolution(Case::Display::RESOLUTION)
@@ -258,7 +260,7 @@
}
const auto it = mFlinger.mutablePhysicalDisplays()
- .emplace_or_replace(*displayId, displayToken, *displayId,
+ .emplace_or_replace(*displayId, displayToken, *displayId, *port,
*kConnectionTypeOpt, makeModes(activeMode),
std::move(colorModes), std::nullopt)
.first;
@@ -299,6 +301,13 @@
mFlinger.mutableDisplayModeController()
.getActiveMode(device->getPhysicalId())
.modePtr->getHwcId());
+
+ EXPECT_EQ(Case::Display::PORT::value,
+ mFlinger.physicalDisplays()
+ .get(device->getPhysicalId())
+ .transform([](const display::PhysicalDisplay& display) {
+ return display.snapshot().port();
+ }));
}
}
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index 7f0b7a6..bd1382e 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -947,11 +947,13 @@
FakeDisplayDeviceInjector(TestableSurfaceFlinger& flinger,
std::shared_ptr<compositionengine::Display> display,
std::optional<ui::DisplayConnectionType> connectionType,
+ std::optional<uint8_t> port,
std::optional<hal::HWDisplayId> hwcDisplayId, bool isPrimary)
: mFlinger(flinger),
mCreationArgs(flinger.mFlinger, flinger.mFlinger->getHwComposer(), mDisplayToken,
display),
mConnectionType(connectionType),
+ mPort(port),
mHwcDisplayId(hwcDisplayId) {
mCreationArgs.isPrimary = isPrimary;
mCreationArgs.initialPowerMode = hal::PowerMode::ON;
@@ -1100,11 +1102,12 @@
.hwcDisplayId = *mHwcDisplayId,
.activeMode = activeModeOpt->get()};
- const auto it = mFlinger.mutablePhysicalDisplays()
- .emplace_or_replace(*physicalId, mDisplayToken, *physicalId,
- *mConnectionType, std::move(modes),
- ui::ColorModes(), std::nullopt)
- .first;
+ const auto it =
+ mFlinger.mutablePhysicalDisplays()
+ .emplace_or_replace(*physicalId, mDisplayToken, *physicalId, *mPort,
+ *mConnectionType, std::move(modes),
+ ui::ColorModes(), std::nullopt)
+ .first;
mFlinger.mutableDisplayModeController()
.registerDisplay(*physicalId, it->second.snapshot(),
@@ -1138,6 +1141,7 @@
DisplayModeId mActiveModeId;
bool mSchedulerRegistration = true;
const std::optional<ui::DisplayConnectionType> mConnectionType;
+ const std::optional<uint8_t> mPort;
const std::optional<hal::HWDisplayId> mHwcDisplayId;
};
diff --git a/vulkan/vkjson/vkjson.cc b/vulkan/vkjson/vkjson.cc
index 9b508aa..3cb9405 100644
--- a/vulkan/vkjson/vkjson.cc
+++ b/vulkan/vkjson/vkjson.cc
@@ -400,6 +400,78 @@
}
};
+template <>
+struct EnumTraits<VkPipelineRobustnessBufferBehavior> {
+ static bool exist(uint32_t e) {
+ switch (e) {
+ case VK_PIPELINE_ROBUSTNESS_BUFFER_BEHAVIOR_DEVICE_DEFAULT:
+ case VK_PIPELINE_ROBUSTNESS_BUFFER_BEHAVIOR_DISABLED:
+ case VK_PIPELINE_ROBUSTNESS_BUFFER_BEHAVIOR_ROBUST_BUFFER_ACCESS:
+ case VK_PIPELINE_ROBUSTNESS_BUFFER_BEHAVIOR_ROBUST_BUFFER_ACCESS_2:
+ return true;
+ }
+ return false;
+ }
+};
+
+template <>
+struct EnumTraits<VkPipelineRobustnessImageBehavior> {
+ static bool exist(uint32_t e) {
+ switch (e) {
+ case VK_PIPELINE_ROBUSTNESS_IMAGE_BEHAVIOR_DEVICE_DEFAULT:
+ case VK_PIPELINE_ROBUSTNESS_IMAGE_BEHAVIOR_DISABLED:
+ case VK_PIPELINE_ROBUSTNESS_IMAGE_BEHAVIOR_ROBUST_IMAGE_ACCESS:
+ case VK_PIPELINE_ROBUSTNESS_IMAGE_BEHAVIOR_ROBUST_IMAGE_ACCESS_2:
+ return true;
+ }
+ return false;
+ }
+};
+
+template <>
+struct EnumTraits<VkImageLayout> {
+ static bool exist(uint32_t e) {
+ switch (e) {
+ case VK_IMAGE_LAYOUT_UNDEFINED:
+ case VK_IMAGE_LAYOUT_GENERAL:
+ case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:
+ case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL:
+ case VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL:
+ case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
+ case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL:
+ case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:
+ case VK_IMAGE_LAYOUT_PREINITIALIZED:
+ case VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL:
+ case VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL:
+ case VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL:
+ case VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_OPTIMAL:
+ case VK_IMAGE_LAYOUT_STENCIL_ATTACHMENT_OPTIMAL:
+ case VK_IMAGE_LAYOUT_STENCIL_READ_ONLY_OPTIMAL:
+ case VK_IMAGE_LAYOUT_READ_ONLY_OPTIMAL:
+ case VK_IMAGE_LAYOUT_ATTACHMENT_OPTIMAL:
+ case VK_IMAGE_LAYOUT_PRESENT_SRC_KHR:
+ case VK_IMAGE_LAYOUT_VIDEO_DECODE_DST_KHR:
+ case VK_IMAGE_LAYOUT_VIDEO_DECODE_SRC_KHR:
+ case VK_IMAGE_LAYOUT_VIDEO_DECODE_DPB_KHR:
+ case VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR:
+ case VK_IMAGE_LAYOUT_FRAGMENT_DENSITY_MAP_OPTIMAL_EXT:
+ case VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR:
+#ifdef VK_ENABLE_BETA_EXTENSIONS
+ case VK_IMAGE_LAYOUT_VIDEO_ENCODE_DST_KHR:
+#endif
+#ifdef VK_ENABLE_BETA_EXTENSIONS
+ case VK_IMAGE_LAYOUT_VIDEO_ENCODE_SRC_KHR:
+#endif
+#ifdef VK_ENABLE_BETA_EXTENSIONS
+ case VK_IMAGE_LAYOUT_VIDEO_ENCODE_DPB_KHR:
+#endif
+ case VK_IMAGE_LAYOUT_ATTACHMENT_FEEDBACK_LOOP_OPTIMAL_EXT:
+ return true;
+ }
+ return false;
+ }
+};
+
// VkSparseImageFormatProperties
template <typename Visitor>
@@ -810,6 +882,68 @@
visitor->Visit("shaderIntegerDotProduct", &features->shaderIntegerDotProduct) &&
visitor->Visit("maintenance4", &features->maintenance4);
}
+
+template <typename Visitor>
+inline bool Iterate(Visitor* visitor, VkJsonCore14* core) {
+ return
+ visitor->Visit("features", &core->features) &&
+ visitor->Visit("properties", &core->properties);
+}
+
+template <typename Visitor>
+inline bool Iterate(Visitor* visitor, VkPhysicalDeviceVulkan14Properties* properties) {
+ return
+ visitor->Visit("lineSubPixelPrecisionBits", &properties->lineSubPixelPrecisionBits) &&
+ visitor->Visit("maxVertexAttribDivisor", &properties->maxVertexAttribDivisor) &&
+ visitor->Visit("supportsNonZeroFirstInstance", &properties->supportsNonZeroFirstInstance) &&
+ visitor->Visit("maxPushDescriptors", &properties->maxPushDescriptors) &&
+ visitor->Visit("dynamicRenderingLocalReadDepthStencilAttachments", &properties->dynamicRenderingLocalReadDepthStencilAttachments) &&
+ visitor->Visit("dynamicRenderingLocalReadMultisampledAttachments", &properties->dynamicRenderingLocalReadMultisampledAttachments) &&
+ visitor->Visit("earlyFragmentMultisampleCoverageAfterSampleCounting", &properties->earlyFragmentMultisampleCoverageAfterSampleCounting) &&
+ visitor->Visit("earlyFragmentSampleMaskTestBeforeSampleCounting", &properties->earlyFragmentSampleMaskTestBeforeSampleCounting) &&
+ visitor->Visit("depthStencilSwizzleOneSupport", &properties->depthStencilSwizzleOneSupport) &&
+ visitor->Visit("polygonModePointSize", &properties->polygonModePointSize) &&
+ visitor->Visit("nonStrictSinglePixelWideLinesUseParallelogram", &properties->nonStrictSinglePixelWideLinesUseParallelogram) &&
+ visitor->Visit("nonStrictWideLinesUseParallelogram", &properties->nonStrictWideLinesUseParallelogram) &&
+ visitor->Visit("blockTexelViewCompatibleMultipleLayers", &properties->blockTexelViewCompatibleMultipleLayers) &&
+ visitor->Visit("maxCombinedImageSamplerDescriptorCount", &properties->maxCombinedImageSamplerDescriptorCount) &&
+ visitor->Visit("fragmentShadingRateClampCombinerInputs", &properties->fragmentShadingRateClampCombinerInputs) &&
+ visitor->Visit("defaultRobustnessStorageBuffers", &properties->defaultRobustnessStorageBuffers) &&
+ visitor->Visit("defaultRobustnessUniformBuffers", &properties->defaultRobustnessUniformBuffers) &&
+ visitor->Visit("defaultRobustnessVertexInputs", &properties->defaultRobustnessVertexInputs) &&
+ visitor->Visit("defaultRobustnessImages", &properties->defaultRobustnessImages) &&
+ visitor->Visit("copySrcLayoutCount", &properties->copySrcLayoutCount) &&
+ visitor->VisitArray("pCopySrcLayouts", properties->copySrcLayoutCount, &properties->pCopySrcLayouts) &&
+ visitor->Visit("copyDstLayoutCount", &properties->copyDstLayoutCount) &&
+ visitor->VisitArray("pCopyDstLayouts", properties->copyDstLayoutCount, &properties->pCopyDstLayouts) &&
+ visitor->Visit("optimalTilingLayoutUUID", &properties->optimalTilingLayoutUUID) &&
+ visitor->Visit("identicalMemoryTypeRequirements", &properties->identicalMemoryTypeRequirements);
+}
+
+template <typename Visitor>
+inline bool Iterate(Visitor* visitor, VkPhysicalDeviceVulkan14Features* features) {
+ return
+ visitor->Visit("globalPriorityQuery", &features->globalPriorityQuery) &&
+ visitor->Visit("shaderSubgroupRotate", &features->shaderSubgroupRotate) &&
+ visitor->Visit("shaderSubgroupRotateClustered", &features->shaderSubgroupRotateClustered) &&
+ visitor->Visit("shaderFloatControls2", &features->shaderFloatControls2) &&
+ visitor->Visit("shaderExpectAssume", &features->shaderExpectAssume) &&
+ visitor->Visit("rectangularLines", &features->rectangularLines) &&
+ visitor->Visit("bresenhamLines", &features->bresenhamLines) &&
+ visitor->Visit("smoothLines", &features->smoothLines) &&
+ visitor->Visit("stippledRectangularLines", &features->stippledRectangularLines) &&
+ visitor->Visit("stippledBresenhamLines", &features->stippledBresenhamLines) &&
+ visitor->Visit("stippledSmoothLines", &features->stippledSmoothLines) &&
+ visitor->Visit("vertexAttributeInstanceRateDivisor", &features->vertexAttributeInstanceRateDivisor) &&
+ visitor->Visit("vertexAttributeInstanceRateZeroDivisor", &features->vertexAttributeInstanceRateZeroDivisor) &&
+ visitor->Visit("indexTypeUint8", &features->indexTypeUint8) &&
+ visitor->Visit("dynamicRenderingLocalRead", &features->dynamicRenderingLocalRead) &&
+ visitor->Visit("maintenance5", &features->maintenance5) &&
+ visitor->Visit("maintenance6", &features->maintenance6) &&
+ visitor->Visit("pipelineProtectedAccess", &features->pipelineProtectedAccess) &&
+ visitor->Visit("pipelineRobustness", &features->pipelineRobustness) &&
+ visitor->Visit("hostImageCopy", &features->hostImageCopy);
+}
// clang-format on
template <typename Visitor>
@@ -1051,7 +1185,7 @@
switch (device->properties.apiVersion ^
VK_API_VERSION_PATCH(device->properties.apiVersion)) {
case VK_API_VERSION_1_4:
- // TODO: real 1.4 support here
+ ret &= visitor->Visit("core14", &device->core14);
FALLTHROUGH_INTENDED;
case VK_API_VERSION_1_3:
ret &= visitor->Visit("core13", &device->core13);
@@ -1224,6 +1358,12 @@
return true;
}
+ template <typename T>
+ bool VisitArray(const char* key, uint32_t count, const T *value) {
+ object_[key] = ArrayToJsonValue(count, *value);
+ return true;
+ }
+
Json::Value get_object() const { return object_; }
private:
@@ -1288,6 +1428,15 @@
return true;
}
+inline bool AsValue(Json::Value* json_value, VkImageLayout* t) {
+ uint32_t value = 0;
+ if (!AsValue(json_value, &value))
+ return false;
+ if (!EnumTraits<VkImageLayout>::exist(value)) return false;
+ *t = static_cast<VkImageLayout>(value);
+ return true;
+}
+
template <typename T>
inline bool AsArray(Json::Value* json_value, uint32_t count, T* values) {
if (json_value->type() != Json::arrayValue || json_value->size() != count)
@@ -1398,6 +1547,20 @@
return false;
}
+ template <typename T>
+ bool VisitArray(const char* key, uint32_t count, T *value) {
+ Json::Value json_value = (*object_)[key];
+ if (!json_value) {
+ if (errors_)
+ *errors_ = std::string(key) + " missing.";
+ return false;
+ }
+ if (AsArray(&json_value, count, *value)) return true;
+ if (errors_)
+ *errors_ = std::string("Wrong type for ") + std::string(key) + ".";
+ return false;
+ }
+
private:
Json::Value* object_;
diff --git a/vulkan/vkjson/vkjson.h b/vulkan/vkjson/vkjson.h
index 88f6e7d..28de680 100644
--- a/vulkan/vkjson/vkjson.h
+++ b/vulkan/vkjson/vkjson.h
@@ -84,6 +84,11 @@
VkPhysicalDeviceVulkan13Features features;
};
+struct VkJsonCore14 {
+ VkPhysicalDeviceVulkan14Properties properties;
+ VkPhysicalDeviceVulkan14Features features;
+};
+
struct VkJsonDevice {
VkJsonDevice() {
memset(&properties, 0, sizeof(VkPhysicalDeviceProperties));
@@ -110,6 +115,7 @@
sizeof(VkPhysicalDeviceShaderDrawParameterFeatures));
memset(&core12, 0, sizeof(VkJsonCore12));
memset(&core13, 0, sizeof(VkJsonCore13));
+ memset(&core14, 0, sizeof(VkJsonCore14));
}
VkPhysicalDeviceProperties properties;
VkPhysicalDeviceFeatures features;
@@ -139,6 +145,7 @@
external_semaphore_properties;
VkJsonCore12 core12;
VkJsonCore13 core13;
+ VkJsonCore14 core14;
};
struct VkJsonDeviceGroup {
diff --git a/vulkan/vkjson/vkjson_instance.cc b/vulkan/vkjson/vkjson_instance.cc
index 0ffe7e0..32bc50b 100644
--- a/vulkan/vkjson/vkjson_instance.cc
+++ b/vulkan/vkjson/vkjson_instance.cc
@@ -292,6 +292,22 @@
vkGetPhysicalDeviceFeatures2(physical_device, &features);
}
+ if (device.properties.apiVersion >= VK_API_VERSION_1_4) {
+ device.core14.properties.sType =
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_4_PROPERTIES;
+ device.core14.properties.pNext = properties.pNext;
+ properties.pNext = &device.core14.properties;
+
+ vkGetPhysicalDeviceProperties2(physical_device, &properties);
+
+ device.core14.features.sType =
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_4_FEATURES;
+ device.core14.features.pNext = features.pNext;
+ features.pNext = &device.core14.features;
+
+ vkGetPhysicalDeviceFeatures2(physical_device, &features);
+ }
+
return device;
}