Merge changes Ic50dd34b,Ib8f5fbef,I058200ca into main
* changes:
ultrahdr: update jpegencoderhelper to accept uncompressed struct fields
ultrahdr: correct offset used during look ups
ultrahdr: minor fixes in encoder and decoder fuzzer
diff --git a/cmds/installd/otapreopt.cpp b/cmds/installd/otapreopt.cpp
index 7cabdb0..407cb24 100644
--- a/cmds/installd/otapreopt.cpp
+++ b/cmds/installd/otapreopt.cpp
@@ -471,13 +471,18 @@
// TODO(calin): embed the profile name in the parameters.
int Dexopt() {
std::string error;
+
+ int dexopt_flags = parameters_.dexopt_flags;
+ // Make sure dex2oat is run with background priority.
+ dexopt_flags |= DEXOPT_BOOTCOMPLETE | DEXOPT_IDLE_BACKGROUND_JOB;
+
int res = dexopt(parameters_.apk_path,
parameters_.uid,
parameters_.pkgName,
parameters_.instruction_set,
parameters_.dexopt_needed,
parameters_.oat_dir,
- parameters_.dexopt_flags,
+ dexopt_flags,
parameters_.compiler_filter,
parameters_.volume_uuid,
parameters_.shared_libraries,
diff --git a/cmds/installd/otapreopt_script.sh b/cmds/installd/otapreopt_script.sh
index db5c34e..e483d54 100644
--- a/cmds/installd/otapreopt_script.sh
+++ b/cmds/installd/otapreopt_script.sh
@@ -72,7 +72,6 @@
PROGRESS=$(cmd otadexopt progress)
print -u${STATUS_FD} "global_progress $PROGRESS"
- sleep 1
i=$((i+1))
done
diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp
index 41856f9..cd3e7c0 100644
--- a/libs/binder/tests/Android.bp
+++ b/libs/binder/tests/Android.bp
@@ -77,6 +77,8 @@
static_libs: [
"binderRecordReplayTestIface-cpp",
"binderReadParcelIface-cpp",
+ "libbinder_random_parcel_seeds",
+ "libbinder_random_parcel",
],
test_suites: ["general-tests"],
require_root: true,
diff --git a/libs/binder/tests/binderRecordReplayTest.cpp b/libs/binder/tests/binderRecordReplayTest.cpp
index 17d5c8a..6773c95 100644
--- a/libs/binder/tests/binderRecordReplayTest.cpp
+++ b/libs/binder/tests/binderRecordReplayTest.cpp
@@ -15,6 +15,7 @@
*/
#include <BnBinderRecordReplayTest.h>
+#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/unique_fd.h>
#include <binder/Binder.h>
@@ -23,6 +24,11 @@
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
#include <binder/RecordedTransaction.h>
+
+#include <fuzzbinder/libbinder_driver.h>
+#include <fuzzer/FuzzedDataProvider.h>
+#include <fuzzseeds/random_parcel_seeds.h>
+
#include <gtest/gtest.h>
#include <sys/prctl.h>
@@ -30,6 +36,7 @@
#include "parcelables/SingleDataParcelable.h"
using namespace android;
+using android::generateSeedsFromRecording;
using android::binder::Status;
using android::binder::debug::RecordedTransaction;
using parcelables::SingleDataParcelable;
@@ -84,6 +91,44 @@
GENERATE_GETTER_SETTER(SingleDataParcelableArray, std::vector<SingleDataParcelable>);
};
+std::vector<uint8_t> retrieveData(base::borrowed_fd fd) {
+ struct stat fdStat;
+ EXPECT_TRUE(fstat(fd.get(), &fdStat) != -1);
+ EXPECT_TRUE(fdStat.st_size != 0);
+
+ std::vector<uint8_t> buffer(fdStat.st_size);
+ auto readResult = android::base::ReadFully(fd, buffer.data(), fdStat.st_size);
+ EXPECT_TRUE(readResult != 0);
+ return std::move(buffer);
+}
+
+void replayFuzzService(const sp<BpBinder>& binder, const RecordedTransaction& transaction) {
+ base::unique_fd seedFd(open("/data/local/tmp/replayFuzzService",
+ O_RDWR | O_CREAT | O_CLOEXEC | O_TRUNC, 0666));
+ ASSERT_TRUE(seedFd.ok());
+
+ // generate corpus from this transaction.
+ generateSeedsFromRecording(seedFd, transaction);
+
+ // Read the data which has been written to seed corpus
+ ASSERT_EQ(0, lseek(seedFd.get(), 0, SEEK_SET));
+ std::vector<uint8_t> seedData = retrieveData(seedFd);
+
+ // use fuzzService to replay the corpus
+ FuzzedDataProvider provider(seedData.data(), seedData.size());
+ fuzzService(binder, std::move(provider));
+}
+
+void replayBinder(const sp<BpBinder>& binder, const RecordedTransaction& transaction) {
+ // TODO: move logic to replay RecordedTransaction into RecordedTransaction
+ Parcel data;
+ data.setData(transaction.getDataParcel().data(), transaction.getDataParcel().dataSize());
+ auto result = binder->transact(transaction.getCode(), data, nullptr, transaction.getFlags());
+
+ // make sure recording does the thing we expect it to do
+ EXPECT_EQ(OK, result);
+}
+
class BinderRecordReplayTest : public ::testing::Test {
public:
void SetUp() override {
@@ -98,48 +143,46 @@
template <typename T, typename U>
void recordReplay(Status (IBinderRecordReplayTest::*set)(T), U recordedValue,
Status (IBinderRecordReplayTest::*get)(U*), U changedValue) {
- base::unique_fd fd(open("/data/local/tmp/binderRecordReplayTest.rec",
- O_RDWR | O_CREAT | O_CLOEXEC, 0666));
- ASSERT_TRUE(fd.ok());
+ auto replayFunctions = {&replayBinder, &replayFuzzService};
+ for (auto replayFunc : replayFunctions) {
+ base::unique_fd fd(open("/data/local/tmp/binderRecordReplayTest.rec",
+ O_RDWR | O_CREAT | O_CLOEXEC, 0666));
+ ASSERT_TRUE(fd.ok());
- // record a transaction
- mBpBinder->startRecordingBinder(fd);
- auto status = (*mInterface.*set)(recordedValue);
- EXPECT_TRUE(status.isOk());
- mBpBinder->stopRecordingBinder();
+ // record a transaction
+ mBpBinder->startRecordingBinder(fd);
+ auto status = (*mInterface.*set)(recordedValue);
+ EXPECT_TRUE(status.isOk());
+ mBpBinder->stopRecordingBinder();
- // test transaction does the thing we expect it to do
- U output;
- status = (*mInterface.*get)(&output);
- EXPECT_TRUE(status.isOk());
- EXPECT_EQ(output, recordedValue);
+ // test transaction does the thing we expect it to do
+ U output;
+ status = (*mInterface.*get)(&output);
+ EXPECT_TRUE(status.isOk());
+ EXPECT_EQ(output, recordedValue);
- // write over the existing state
- status = (*mInterface.*set)(changedValue);
- EXPECT_TRUE(status.isOk());
+ // write over the existing state
+ status = (*mInterface.*set)(changedValue);
+ EXPECT_TRUE(status.isOk());
- status = (*mInterface.*get)(&output);
- EXPECT_TRUE(status.isOk());
+ status = (*mInterface.*get)(&output);
+ EXPECT_TRUE(status.isOk());
- EXPECT_EQ(output, changedValue);
+ EXPECT_EQ(output, changedValue);
- // replay transaction
- ASSERT_EQ(0, lseek(fd.get(), 0, SEEK_SET));
- std::optional<RecordedTransaction> transaction = RecordedTransaction::fromFile(fd);
- ASSERT_NE(transaction, std::nullopt);
+ // replay transaction
+ ASSERT_EQ(0, lseek(fd.get(), 0, SEEK_SET));
+ std::optional<RecordedTransaction> transaction = RecordedTransaction::fromFile(fd);
+ ASSERT_NE(transaction, std::nullopt);
- // TODO: move logic to replay RecordedTransaction into RecordedTransaction
- Parcel data;
- data.setData(transaction->getDataParcel().data(), transaction->getDataParcel().dataSize());
- auto result =
- mBpBinder->transact(transaction->getCode(), data, nullptr, transaction->getFlags());
+ const RecordedTransaction& recordedTransaction = *transaction;
+ // call replay function with recorded transaction
+ (*replayFunc)(mBpBinder, recordedTransaction);
- // make sure recording does the thing we expect it to do
- EXPECT_EQ(OK, result);
-
- status = (*mInterface.*get)(&output);
- EXPECT_TRUE(status.isOk());
- EXPECT_EQ(output, recordedValue);
+ status = (*mInterface.*get)(&output);
+ EXPECT_TRUE(status.isOk());
+ EXPECT_EQ(output, recordedValue);
+ }
}
private:
diff --git a/libs/binder/tests/parcel_fuzzer/Android.bp b/libs/binder/tests/parcel_fuzzer/Android.bp
index 35866ad..0d1503e 100644
--- a/libs/binder/tests/parcel_fuzzer/Android.bp
+++ b/libs/binder/tests/parcel_fuzzer/Android.bp
@@ -104,3 +104,28 @@
local_include_dirs: ["include_random_parcel"],
export_include_dirs: ["include_random_parcel"],
}
+
+cc_library {
+ name: "libbinder_random_parcel_seeds",
+ host_supported: true,
+ vendor_available: true,
+ target: {
+ darwin: {
+ enabled: false,
+ },
+ },
+ srcs: [
+ "random_parcel_seeds.cpp",
+ ],
+ shared_libs: [
+ "libbase",
+ "libbinder",
+ "libbinder_ndk",
+ "libcutils",
+ "libutils",
+ ],
+ local_include_dirs: [
+ "include_random_parcel_seeds",
+ ],
+ export_include_dirs: ["include_random_parcel_seeds"],
+}
diff --git a/libs/binder/tests/parcel_fuzzer/include_random_parcel_seeds/fuzzseeds/random_parcel_seeds.h b/libs/binder/tests/parcel_fuzzer/include_random_parcel_seeds/fuzzseeds/random_parcel_seeds.h
new file mode 100644
index 0000000..5755239
--- /dev/null
+++ b/libs/binder/tests/parcel_fuzzer/include_random_parcel_seeds/fuzzseeds/random_parcel_seeds.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/file.h>
+#include <android-base/hex.h>
+#include <android-base/logging.h>
+
+#include <binder/Binder.h>
+#include <binder/Parcel.h>
+#include <binder/RecordedTransaction.h>
+
+#include <private/android_filesystem_config.h>
+
+#include <vector>
+
+using android::Parcel;
+using android::base::HexString;
+using std::vector;
+
+namespace android {
+namespace impl {
+// computes the bytes so that if they are passed to FuzzedDataProvider and
+// provider.ConsumeIntegralInRange<T>(min, max) is called, it will return val
+template <typename T>
+void writeReversedBuffer(std::vector<std::byte>& integralBuffer, T min, T max, T val);
+
+// Calls writeInBuffer method with min and max numeric limits of type T. This method
+// is reversal of ConsumeIntegral<T>() in FuzzedDataProvider
+template <typename T>
+void writeReversedBuffer(std::vector<std::byte>& integralBuffer, T val);
+} // namespace impl
+void generateSeedsFromRecording(base::borrowed_fd fd,
+ const binder::debug::RecordedTransaction& transaction);
+} // namespace android
diff --git a/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp b/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp
index b268c5d..47d2a0a 100644
--- a/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp
+++ b/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp
@@ -35,6 +35,11 @@
.extraFds = {},
};
+ // Reserved bytes so that we don't have to change fuzzers and seed corpus if
+ // we introduce anything new in fuzzService.
+ std::vector<uint8_t> reservedBytes = provider.ConsumeBytes<uint8_t>(8);
+ (void)reservedBytes;
+
// always refresh the calling identity, because we sometimes set it below, but also,
// the code we're fuzzing might reset it
IPCThreadState::self()->clearCallingIdentity();
diff --git a/libs/binder/tests/parcel_fuzzer/random_parcel_seeds.cpp b/libs/binder/tests/parcel_fuzzer/random_parcel_seeds.cpp
new file mode 100644
index 0000000..9e3e2ab
--- /dev/null
+++ b/libs/binder/tests/parcel_fuzzer/random_parcel_seeds.cpp
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/file.h>
+#include <android-base/logging.h>
+
+#include <binder/RecordedTransaction.h>
+
+#include <fuzzseeds/random_parcel_seeds.h>
+
+using android::base::WriteFully;
+
+namespace android {
+namespace impl {
+template <typename T>
+std::vector<uint8_t> reverseBytes(T min, T max, T val) {
+ uint64_t range = static_cast<uint64_t>(max) - min;
+ uint64_t result = val - min;
+ size_t offset = 0;
+
+ std::vector<uint8_t> reverseData;
+ uint8_t reversed = 0;
+ reversed |= result;
+
+ while (offset < sizeof(T) * CHAR_BIT && (range >> offset) > 0) {
+ reverseData.push_back(reversed);
+ reversed = 0;
+ reversed |= (result >> CHAR_BIT);
+ result = result >> CHAR_BIT;
+ offset += CHAR_BIT;
+ }
+
+ return std::move(reverseData);
+}
+
+template <typename T>
+void writeReversedBuffer(std::vector<uint8_t>& integralBuffer, T min, T max, T val) {
+ std::vector<uint8_t> reversedData = reverseBytes(min, max, val);
+ // ConsumeIntegral Calls read buffer from the end. Keep inserting at the front of the buffer
+ // so that we can align fuzzService operations with seed generation for readability.
+ integralBuffer.insert(integralBuffer.begin(), reversedData.begin(), reversedData.end());
+}
+
+template <typename T>
+void writeReversedBuffer(std::vector<uint8_t>& integralBuffer, T val) {
+ // For ConsumeIntegral<T>() calls, FuzzedDataProvider uses numeric limits min and max
+ // as range
+ writeReversedBuffer(integralBuffer, std::numeric_limits<T>::min(),
+ std::numeric_limits<T>::max(), val);
+}
+
+} // namespace impl
+
+void generateSeedsFromRecording(base::borrowed_fd fd,
+ const binder::debug::RecordedTransaction& transaction) {
+ // Write Reserved bytes for future use
+ std::vector<uint8_t> reservedBytes(8);
+ CHECK(WriteFully(fd, reservedBytes.data(), reservedBytes.size())) << fd.get();
+
+ std::vector<uint8_t> integralBuffer;
+
+ // Write UID array : Array elements are initialized in the order that they are declared
+ // UID array index 2 element
+ // int64_t aidRoot = 0;
+ impl::writeReversedBuffer(integralBuffer, static_cast<int64_t>(AID_ROOT) << 32,
+ static_cast<int64_t>(AID_USER) << 32,
+ static_cast<int64_t>(AID_ROOT) << 32);
+
+ // UID array index 3 element
+ impl::writeReversedBuffer(integralBuffer, static_cast<int64_t>(AID_ROOT) << 32);
+
+ // always pick AID_ROOT -> index 0
+ size_t uidIndex = 0;
+ impl::writeReversedBuffer(integralBuffer, static_cast<size_t>(0), static_cast<size_t>(3),
+ uidIndex);
+
+ // Never set uid in seed corpus
+ uint8_t writeUid = 0;
+ impl::writeReversedBuffer(integralBuffer, writeUid);
+
+ // Read random code. this will be from recorded transaction
+ uint8_t selectCode = 1;
+ impl::writeReversedBuffer(integralBuffer, selectCode);
+
+ // Get from recorded transaction
+ uint32_t code = transaction.getCode();
+ impl::writeReversedBuffer(integralBuffer, code);
+
+ // Get from recorded transaction
+ uint32_t flags = transaction.getFlags();
+ impl::writeReversedBuffer(integralBuffer, flags);
+
+ // always fuzz primary binder
+ size_t extraBindersIndex = 0;
+ impl::writeReversedBuffer(integralBuffer, static_cast<size_t>(0), static_cast<size_t>(0),
+ extraBindersIndex);
+
+ const Parcel& dataParcel = transaction.getDataParcel();
+
+ // This buffer holds the bytes which will be used for fillRandomParcel API
+ std::vector<uint8_t> fillParcelBuffer;
+
+ // Don't take rpc path
+ uint8_t rpcBranch = 0;
+ impl::writeReversedBuffer(fillParcelBuffer, rpcBranch);
+
+ // Implicit branch on this path -> options->writeHeader(p, provider)
+ uint8_t writeHeaderInternal = 0;
+ impl::writeReversedBuffer(fillParcelBuffer, writeHeaderInternal);
+
+ // Choose to write data in parcel
+ size_t fillFuncIndex = 0;
+ impl::writeReversedBuffer(fillParcelBuffer, static_cast<size_t>(0), static_cast<size_t>(2),
+ fillFuncIndex);
+
+ // Write parcel data size from recorded transaction
+ size_t toWrite = transaction.getDataParcel().dataBufferSize();
+ impl::writeReversedBuffer(fillParcelBuffer, static_cast<size_t>(0), toWrite, toWrite);
+
+ // Write parcel data with size towrite from recorded transaction
+ CHECK(WriteFully(fd, dataParcel.data(), toWrite)) << fd.get();
+
+ // Write Fill Parcel buffer size in integralBuffer so that fuzzService knows size of data
+ size_t subDataSize = toWrite + fillParcelBuffer.size();
+ impl::writeReversedBuffer(integralBuffer, static_cast<size_t>(0), subDataSize, subDataSize);
+
+ // Write fill parcel buffer
+ CHECK(WriteFully(fd, fillParcelBuffer.data(), fillParcelBuffer.size())) << fd.get();
+
+ // Write the integralBuffer to data
+ CHECK(WriteFully(fd, integralBuffer.data(), integralBuffer.size())) << fd.get();
+}
+} // namespace android
diff --git a/libs/graphicsenv/GraphicsEnv.cpp b/libs/graphicsenv/GraphicsEnv.cpp
index 715822b..732ca36 100644
--- a/libs/graphicsenv/GraphicsEnv.cpp
+++ b/libs/graphicsenv/GraphicsEnv.cpp
@@ -512,7 +512,11 @@
return mShouldUseAngle;
}
-void GraphicsEnv::setAngleInfo(const std::string& path, const bool shouldUseSystemAngle,
+// Set ANGLE information.
+// If path is "system", it means system ANGLE must be used for the process.
+// If shouldUseNativeDriver is true, it means native GLES drivers must be used for the process.
+// If path is set to nonempty and shouldUseNativeDriver is true, ANGLE will be used regardless.
+void GraphicsEnv::setAngleInfo(const std::string& path, const bool shouldUseNativeDriver,
const std::string& packageName,
const std::vector<std::string> eglFeatures) {
if (mShouldUseAngle) {
@@ -529,8 +533,13 @@
mAnglePath = std::move(path);
ALOGV("setting app package name to '%s'", packageName.c_str());
mPackageName = std::move(packageName);
- mShouldUseAngle = true;
- mShouldUseSystemAngle = shouldUseSystemAngle;
+ if (mAnglePath == "system") {
+ mShouldUseSystemAngle = true;
+ }
+ if (!mAnglePath.empty()) {
+ mShouldUseAngle = true;
+ }
+ mShouldUseNativeDriver = shouldUseNativeDriver;
}
std::string& GraphicsEnv::getPackageName() {
@@ -607,6 +616,10 @@
return mShouldUseSystemAngle;
}
+bool GraphicsEnv::shouldUseNativeDriver() {
+ return mShouldUseNativeDriver;
+}
+
/**
* APIs for debuggable layers
*/
diff --git a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
index fbf2902..6cce3f6 100644
--- a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
+++ b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
@@ -108,7 +108,10 @@
// (libraries must be stored uncompressed and page aligned); such elements
// in the search path must have a '!' after the zip filename, e.g.
// /system/app/ANGLEPrebuilt/ANGLEPrebuilt.apk!/lib/arm64-v8a
- void setAngleInfo(const std::string& path, const bool useSystemAngle,
+ // If the search patch is "system", then it means the system ANGLE should be used.
+ // If shouldUseNativeDriver is true, it means native GLES drivers must be used for the process.
+ // If path is set to nonempty and shouldUseNativeDriver is true, ANGLE will be used regardless.
+ void setAngleInfo(const std::string& path, const bool shouldUseNativeDriver,
const std::string& packageName, const std::vector<std::string> eglFeatures);
// Get the ANGLE driver namespace.
android_namespace_t* getAngleNamespace();
@@ -118,6 +121,7 @@
// Set the persist.graphics.egl system property value.
void nativeToggleAngleAsSystemDriver(bool enabled);
bool shouldUseSystemAngle();
+ bool shouldUseNativeDriver();
/*
* Apis for debug layer
@@ -175,6 +179,8 @@
bool mShouldUseAngle = false;
// Whether loader should load system ANGLE.
bool mShouldUseSystemAngle = false;
+ // Whether loader should load native GLES driver.
+ bool mShouldUseNativeDriver = false;
// ANGLE namespace.
android_namespace_t* mAngleNamespace = nullptr;
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index db99726..3c508c7 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -2513,38 +2513,41 @@
outInfo->secure = ginfo.secure;
outInfo->installOrientation = static_cast<ui::Rotation>(ginfo.installOrientation);
- DeviceProductInfo info;
- std::optional<gui::DeviceProductInfo> dpi = ginfo.deviceProductInfo;
- gui::DeviceProductInfo::ManufactureOrModelDate& date = dpi->manufactureOrModelDate;
- info.name = dpi->name;
- if (dpi->manufacturerPnpId.size() > 0) {
- // copid from PnpId = std::array<char, 4> in ui/DeviceProductInfo.h
- constexpr int kMaxPnpIdSize = 4;
- size_t count = std::max<size_t>(kMaxPnpIdSize, dpi->manufacturerPnpId.size());
- std::copy_n(dpi->manufacturerPnpId.begin(), count, info.manufacturerPnpId.begin());
- }
- if (dpi->relativeAddress.size() > 0) {
- std::copy(dpi->relativeAddress.begin(), dpi->relativeAddress.end(),
- std::back_inserter(info.relativeAddress));
- }
- info.productId = dpi->productId;
- if (date.getTag() == Tag::modelYear) {
- DeviceProductInfo::ModelYear modelYear;
- modelYear.year = static_cast<uint32_t>(date.get<Tag::modelYear>().year);
- info.manufactureOrModelDate = modelYear;
- } else if (date.getTag() == Tag::manufactureYear) {
- DeviceProductInfo::ManufactureYear manufactureYear;
- manufactureYear.year = date.get<Tag::manufactureYear>().modelYear.year;
- info.manufactureOrModelDate = manufactureYear;
- } else if (date.getTag() == Tag::manufactureWeekAndYear) {
- DeviceProductInfo::ManufactureWeekAndYear weekAndYear;
- weekAndYear.year =
- date.get<Tag::manufactureWeekAndYear>().manufactureYear.modelYear.year;
- weekAndYear.week = date.get<Tag::manufactureWeekAndYear>().week;
- info.manufactureOrModelDate = weekAndYear;
- }
+ if (const std::optional<gui::DeviceProductInfo> dpi = ginfo.deviceProductInfo) {
+ DeviceProductInfo info;
+ info.name = dpi->name;
+ if (dpi->manufacturerPnpId.size() > 0) {
+ // copid from PnpId = std::array<char, 4> in ui/DeviceProductInfo.h
+ constexpr int kMaxPnpIdSize = 4;
+ size_t count = std::max<size_t>(kMaxPnpIdSize, dpi->manufacturerPnpId.size());
+ std::copy_n(dpi->manufacturerPnpId.begin(), count, info.manufacturerPnpId.begin());
+ }
+ if (dpi->relativeAddress.size() > 0) {
+ std::copy(dpi->relativeAddress.begin(), dpi->relativeAddress.end(),
+ std::back_inserter(info.relativeAddress));
+ }
+ info.productId = dpi->productId;
- outInfo->deviceProductInfo = info;
+ const gui::DeviceProductInfo::ManufactureOrModelDate& date =
+ dpi->manufactureOrModelDate;
+ if (date.getTag() == Tag::modelYear) {
+ DeviceProductInfo::ModelYear modelYear;
+ modelYear.year = static_cast<uint32_t>(date.get<Tag::modelYear>().year);
+ info.manufactureOrModelDate = modelYear;
+ } else if (date.getTag() == Tag::manufactureYear) {
+ DeviceProductInfo::ManufactureYear manufactureYear;
+ manufactureYear.year = date.get<Tag::manufactureYear>().modelYear.year;
+ info.manufactureOrModelDate = manufactureYear;
+ } else if (date.getTag() == Tag::manufactureWeekAndYear) {
+ DeviceProductInfo::ManufactureWeekAndYear weekAndYear;
+ weekAndYear.year =
+ date.get<Tag::manufactureWeekAndYear>().manufactureYear.modelYear.year;
+ weekAndYear.week = date.get<Tag::manufactureWeekAndYear>().week;
+ info.manufactureOrModelDate = weekAndYear;
+ }
+
+ outInfo->deviceProductInfo = info;
+ }
}
return statusTFromBinderStatus(status);
}
diff --git a/libs/gui/aidl/android/gui/ISurfaceComposer.aidl b/libs/gui/aidl/android/gui/ISurfaceComposer.aidl
index 539a1c1..5e8e904 100644
--- a/libs/gui/aidl/android/gui/ISurfaceComposer.aidl
+++ b/libs/gui/aidl/android/gui/ISurfaceComposer.aidl
@@ -230,20 +230,20 @@
* The subregion can be optionally rotated. It will also be scaled to
* match the size of the output buffer.
*/
- void captureDisplay(in DisplayCaptureArgs args, IScreenCaptureListener listener);
+ oneway void captureDisplay(in DisplayCaptureArgs args, IScreenCaptureListener listener);
/**
* Capture the specified screen. This requires the READ_FRAME_BUFFER
* permission.
*/
- void captureDisplayById(long displayId, IScreenCaptureListener listener);
+ oneway void captureDisplayById(long displayId, IScreenCaptureListener listener);
/**
* Capture a subtree of the layer hierarchy, potentially ignoring the root node.
* This requires READ_FRAME_BUFFER permission. This function will fail if there
* is a secure window on screen
*/
- void captureLayers(in LayerCaptureArgs args, IScreenCaptureListener listener);
+ oneway void captureLayers(in LayerCaptureArgs args, IScreenCaptureListener listener);
/**
* Clears the frame statistics for animations.
diff --git a/libs/renderengine/skia/SkiaRenderEngine.cpp b/libs/renderengine/skia/SkiaRenderEngine.cpp
index 29d8ba7..1f4c989 100644
--- a/libs/renderengine/skia/SkiaRenderEngine.cpp
+++ b/libs/renderengine/skia/SkiaRenderEngine.cpp
@@ -511,7 +511,8 @@
auto effect =
shaders::LinearEffect{.inputDataspace = parameters.layer.sourceDataspace,
.outputDataspace = parameters.outputDataSpace,
- .undoPremultipliedAlpha = parameters.undoPremultipliedAlpha};
+ .undoPremultipliedAlpha = parameters.undoPremultipliedAlpha,
+ .fakeOutputDataspace = parameters.fakeOutputDataspace};
auto effectIter = mRuntimeEffects.find(effect);
sk_sp<SkRuntimeEffect> runtimeEffect = nullptr;
@@ -907,12 +908,14 @@
(display.outputDataspace & ui::Dataspace::TRANSFER_MASK) ==
static_cast<int32_t>(ui::Dataspace::TRANSFER_SRGB);
- const ui::Dataspace runtimeEffectDataspace = !dimInLinearSpace && isExtendedHdr
+ const bool useFakeOutputDataspaceForRuntimeEffect = !dimInLinearSpace && isExtendedHdr;
+
+ const ui::Dataspace fakeDataspace = useFakeOutputDataspaceForRuntimeEffect
? static_cast<ui::Dataspace>(
(display.outputDataspace & ui::Dataspace::STANDARD_MASK) |
ui::Dataspace::TRANSFER_GAMMA2_2 |
(display.outputDataspace & ui::Dataspace::RANGE_MASK))
- : display.outputDataspace;
+ : ui::Dataspace::UNKNOWN;
// If the input dataspace is range extended, the output dataspace transfer is sRGB
// and dimmingStage is GAMMA_OETF, dim in linear space instead, and
@@ -1019,7 +1022,8 @@
.layerDimmingRatio = dimInLinearSpace
? layerDimmingRatio
: 1.f,
- .outputDataSpace = runtimeEffectDataspace}));
+ .outputDataSpace = display.outputDataspace,
+ .fakeOutputDataspace = fakeDataspace}));
// Turn on dithering when dimming beyond this (arbitrary) threshold...
static constexpr float kDimmingThreshold = 0.2f;
@@ -1083,7 +1087,8 @@
.undoPremultipliedAlpha = false,
.requiresLinearEffect = requiresLinearEffect,
.layerDimmingRatio = layerDimmingRatio,
- .outputDataSpace = runtimeEffectDataspace}));
+ .outputDataSpace = display.outputDataspace,
+ .fakeOutputDataspace = fakeDataspace}));
}
if (layer.disableBlending) {
diff --git a/libs/renderengine/skia/SkiaRenderEngine.h b/libs/renderengine/skia/SkiaRenderEngine.h
index 6457bfa..723e73c 100644
--- a/libs/renderengine/skia/SkiaRenderEngine.h
+++ b/libs/renderengine/skia/SkiaRenderEngine.h
@@ -157,6 +157,7 @@
bool requiresLinearEffect;
float layerDimmingRatio;
const ui::Dataspace outputDataSpace;
+ const ui::Dataspace fakeOutputDataspace;
};
sk_sp<SkShader> createRuntimeEffectShader(const RuntimeEffectShaderParameters&);
diff --git a/libs/shaders/shaders.cpp b/libs/shaders/shaders.cpp
index c85517a..ef039e5 100644
--- a/libs/shaders/shaders.cpp
+++ b/libs/shaders/shaders.cpp
@@ -168,8 +168,8 @@
void generateOETF(std::string& shader) {
// Only support gamma 2.2 for now
shader.append(R"(
- float OETF(float3 linear) {
- return sign(linear) * pow(abs(linear), (1.0 / 2.2));
+ float3 OETF(float3 linear) {
+ return sign(linear) * pow(abs(linear), float3(1.0 / 2.2));
}
)");
}
diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp
index 8d0eb59..04e2fff 100644
--- a/opengl/libs/EGL/Loader.cpp
+++ b/opengl/libs/EGL/Loader.cpp
@@ -41,24 +41,44 @@
/*
* EGL userspace drivers must be provided either:
* - as a single library:
- * /vendor/lib/egl/libGLES.so
+ * /vendor/${LIB}/egl/libGLES.so
*
* - as separate libraries:
- * /vendor/lib/egl/libEGL.so
- * /vendor/lib/egl/libGLESv1_CM.so
- * /vendor/lib/egl/libGLESv2.so
+ * /vendor/${LIB}/egl/libEGL.so
+ * /vendor/${LIB}/egl/libGLESv1_CM.so
+ * /vendor/${LIB}/egl/libGLESv2.so
*
* For backward compatibility and to facilitate the transition to
* this new naming scheme, the loader will additionally look for:
*
- * /{vendor|system}/lib/egl/lib{GLES | [EGL|GLESv1_CM|GLESv2]}_*.so
+ * /vendor/${LIB}/egl/lib{GLES | [EGL|GLESv1_CM|GLESv2]}_${SUFFIX}.so
*
*/
-Loader& Loader::getInstance() {
- static Loader loader;
- return loader;
-}
+#ifndef SYSTEM_LIB_PATH
+#if defined(__LP64__)
+#define SYSTEM_LIB_PATH "/system/lib64"
+#else
+#define SYSTEM_LIB_PATH "/system/lib"
+#endif
+#endif
+
+static const char* PERSIST_DRIVER_SUFFIX_PROPERTY = "persist.graphics.egl";
+static const char* RO_DRIVER_SUFFIX_PROPERTY = "ro.hardware.egl";
+static const char* RO_BOARD_PLATFORM_PROPERTY = "ro.board.platform";
+
+static const char* HAL_SUBNAME_KEY_PROPERTIES[3] = {
+ PERSIST_DRIVER_SUFFIX_PROPERTY,
+ RO_DRIVER_SUFFIX_PROPERTY,
+ RO_BOARD_PLATFORM_PROPERTY,
+};
+
+static const char* const VENDOR_LIB_EGL_DIR =
+#if defined(__LP64__)
+ "/vendor/lib64/egl";
+#else
+ "/vendor/lib/egl";
+#endif
static void* do_dlopen(const char* path, int mode) {
ATRACE_CALL();
@@ -80,6 +100,17 @@
return android_unload_sphal_library(dso);
}
+static void* load_wrapper(const char* path) {
+ void* so = do_dlopen(path, RTLD_NOW | RTLD_LOCAL);
+ ALOGE_IF(!so, "dlopen(\"%s\") failed: %s", path, dlerror());
+ return so;
+}
+
+Loader& Loader::getInstance() {
+ static Loader loader;
+ return loader;
+}
+
Loader::driver_t::driver_t(void* gles)
{
dso[0] = gles;
@@ -123,30 +154,6 @@
Loader::~Loader() {
}
-static void* load_wrapper(const char* path) {
- void* so = do_dlopen(path, RTLD_NOW | RTLD_LOCAL);
- ALOGE_IF(!so, "dlopen(\"%s\") failed: %s", path, dlerror());
- return so;
-}
-
-#ifndef EGL_WRAPPER_DIR
-#if defined(__LP64__)
-#define EGL_WRAPPER_DIR "/system/lib64"
-#else
-#define EGL_WRAPPER_DIR "/system/lib"
-#endif
-#endif
-
-static const char* PERSIST_DRIVER_SUFFIX_PROPERTY = "persist.graphics.egl";
-static const char* RO_DRIVER_SUFFIX_PROPERTY = "ro.hardware.egl";
-static const char* RO_BOARD_PLATFORM_PROPERTY = "ro.board.platform";
-
-static const char* HAL_SUBNAME_KEY_PROPERTIES[3] = {
- PERSIST_DRIVER_SUFFIX_PROPERTY,
- RO_DRIVER_SUFFIX_PROPERTY,
- RO_BOARD_PLATFORM_PROPERTY,
-};
-
// Check whether the loaded system drivers should be unloaded in order to
// load ANGLE or the updatable graphics drivers.
// If ANGLE namespace is set, it means the application is identified to run on top of ANGLE.
@@ -169,6 +176,11 @@
}
}
+ // Return true if native GLES drivers should be used and ANGLE is already loaded.
+ if (android::GraphicsEnv::getInstance().shouldUseNativeDriver() && cnx->angleLoaded) {
+ return true;
+ }
+
// Return true if updated driver namespace is set.
ns = android::GraphicsEnv::getInstance().getDriverNamespace();
if (ns) {
@@ -240,16 +252,28 @@
if (!hnd) {
// Secondly, try to load from driver apk.
hnd = attempt_to_load_updated_driver(cnx);
+
+ // If updated driver apk is set but fail to load, abort here.
+ LOG_ALWAYS_FATAL_IF(android::GraphicsEnv::getInstance().getDriverNamespace(),
+ "couldn't find an OpenGL ES implementation from %s",
+ android::GraphicsEnv::getInstance().getDriverPath().c_str());
}
+ // Attempt to load native GLES drivers specified by ro.hardware.egl if native is selected.
+ // If native is selected but fail to load, abort.
+ if (!hnd && android::GraphicsEnv::getInstance().shouldUseNativeDriver()) {
+ auto driverSuffix = base::GetProperty(RO_DRIVER_SUFFIX_PROPERTY, "");
+ LOG_ALWAYS_FATAL_IF(driverSuffix.empty(),
+ "Native GLES driver is selected but not specified in %s",
+ RO_DRIVER_SUFFIX_PROPERTY);
+ hnd = attempt_to_load_system_driver(cnx, driverSuffix.c_str(), true);
+ LOG_ALWAYS_FATAL_IF(!hnd, "Native GLES driver is selected but failed to load. %s=%s",
+ RO_DRIVER_SUFFIX_PROPERTY, driverSuffix.c_str());
+ }
+
+ // Finally, try to load default driver.
bool failToLoadFromDriverSuffixProperty = false;
if (!hnd) {
- // If updated driver apk is set but fail to load, abort here.
- if (android::GraphicsEnv::getInstance().getDriverNamespace()) {
- LOG_ALWAYS_FATAL("couldn't find an OpenGL ES implementation from %s",
- android::GraphicsEnv::getInstance().getDriverPath().c_str());
- }
- // Finally, try to load system driver.
// Start by searching for the library name appended by the system
// properties of the GLES userspace driver in both locations.
// i.e.:
@@ -306,13 +330,13 @@
HAL_SUBNAME_KEY_PROPERTIES[2]);
if (!cnx->libEgl) {
- cnx->libEgl = load_wrapper(EGL_WRAPPER_DIR "/libEGL.so");
+ cnx->libEgl = load_wrapper(SYSTEM_LIB_PATH "/libEGL.so");
}
if (!cnx->libGles1) {
- cnx->libGles1 = load_wrapper(EGL_WRAPPER_DIR "/libGLESv1_CM.so");
+ cnx->libGles1 = load_wrapper(SYSTEM_LIB_PATH "/libGLESv1_CM.so");
}
if (!cnx->libGles2) {
- cnx->libGles2 = load_wrapper(EGL_WRAPPER_DIR "/libGLESv2.so");
+ cnx->libGles2 = load_wrapper(SYSTEM_LIB_PATH "/libGLESv2.so");
}
if (!cnx->libEgl || !cnx->libGles2 || !cnx->libGles1) {
@@ -415,31 +439,19 @@
class MatchFile {
public:
static std::string find(const char* libraryName, const bool exact) {
- const char* const searchPaths[] = {
-#if defined(__LP64__)
- "/vendor/lib64/egl",
- "/system/lib64/egl"
-#else
- "/vendor/lib/egl",
- "/system/lib/egl"
-#endif
- };
-
- for (auto dir : searchPaths) {
- std::string absolutePath;
- if (find(absolutePath, libraryName, dir, exact)) {
- return absolutePath;
- }
+ std::string absolutePath;
+ if (findLibPath(absolutePath, libraryName, exact)) {
+ return absolutePath;
}
// Driver not found. gah.
return std::string();
}
private:
- static bool find(std::string& result,
- const std::string& pattern, const char* const search, bool exact) {
+ static bool findLibPath(std::string& result, const std::string& pattern, bool exact) {
+ const std::string vendorLibEglDirString = std::string(VENDOR_LIB_EGL_DIR);
if (exact) {
- std::string absolutePath = std::string(search) + "/" + pattern + ".so";
+ std::string absolutePath = vendorLibEglDirString + "/" + pattern + ".so";
if (!access(absolutePath.c_str(), R_OK)) {
result = absolutePath;
return true;
@@ -447,7 +459,7 @@
return false;
}
- DIR* d = opendir(search);
+ DIR* d = opendir(VENDOR_LIB_EGL_DIR);
if (d != nullptr) {
struct dirent* e;
while ((e = readdir(d)) != nullptr) {
@@ -460,7 +472,7 @@
}
if (strstr(e->d_name, pattern.c_str()) == e->d_name) {
if (!strcmp(e->d_name + strlen(e->d_name) - 3, ".so")) {
- result = std::string(search) + "/" + e->d_name;
+ result = vendorLibEglDirString + "/" + e->d_name;
closedir(d);
return true;
}
diff --git a/services/sensorservice/tests/sensorservicetest.cpp b/services/sensorservice/tests/sensorservicetest.cpp
index e939d51..1baf397 100644
--- a/services/sensorservice/tests/sensorservicetest.cpp
+++ b/services/sensorservice/tests/sensorservicetest.cpp
@@ -87,7 +87,7 @@
int ret = mgr.createDirectChannel(
kMemSize, ASENSOR_DIRECT_CHANNEL_TYPE_SHARED_MEMORY, resourceHandle);
- // Should print -22 (BAD_VALUE) and the device runtime shouldn't restart
+ // Should not succeed (ret != OK) and the device runtime shouldn't restart
printf("createInvalidDirectChannel=%d\n", ret);
// Secondary test: correct channel creation & destruction (should print 0)
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index 32bd890..3c7cbe6 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -38,7 +38,6 @@
#include <log/log.h>
#include <system/window.h>
-#include "Display/DisplaySnapshot.h"
#include "DisplayDevice.h"
#include "FrontEnd/DisplayInfo.h"
#include "HdrSdrRatioOverlay.h"
@@ -231,10 +230,18 @@
return BAD_VALUE;
}
mUpcomingActiveMode = info;
- ATRACE_INT(mActiveModeFPSHwcTrace.c_str(), info.modeOpt->modePtr->getFps().getIntValue());
- return mHwComposer.setActiveModeWithConstraints(getPhysicalId(),
- info.modeOpt->modePtr->getHwcId(), constraints,
- outTimeline);
+ mIsModeSetPending = true;
+
+ const auto& pendingMode = *info.modeOpt->modePtr;
+ ATRACE_INT(mActiveModeFPSHwcTrace.c_str(), pendingMode.getFps().getIntValue());
+
+ return mHwComposer.setActiveModeWithConstraints(getPhysicalId(), pendingMode.getHwcId(),
+ constraints, outTimeline);
+}
+
+void DisplayDevice::finalizeModeChange(DisplayModeId modeId, Fps displayFps, Fps renderFps) {
+ setActiveMode(modeId, displayFps, renderFps);
+ mIsModeSetPending = false;
}
nsecs_t DisplayDevice::getVsyncPeriodFromHWC() const {
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index e92125a..a3fa701 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -218,6 +218,8 @@
return mUpcomingActiveMode;
}
+ bool isModeSetPending() const REQUIRES(kMainThreadContext) { return mIsModeSetPending; }
+
scheduler::FrameRateMode getActiveMode() const REQUIRES(kMainThreadContext) {
return mRefreshRateSelector->getActiveMode();
}
@@ -229,6 +231,9 @@
hal::VsyncPeriodChangeTimeline* outTimeline)
REQUIRES(kMainThreadContext);
+ void finalizeModeChange(DisplayModeId, Fps displayFps, Fps renderFps)
+ REQUIRES(kMainThreadContext);
+
scheduler::RefreshRateSelector& refreshRateSelector() const { return *mRefreshRateSelector; }
// Extends the lifetime of the RefreshRateSelector, so it can outlive this DisplayDevice.
@@ -313,7 +318,9 @@
ActiveModeInfo mDesiredActiveMode GUARDED_BY(mActiveModeLock);
TracedOrdinal<bool> mDesiredActiveModeChanged GUARDED_BY(mActiveModeLock) =
{ftl::Concat("DesiredActiveModeChanged-", getId().value).c_str(), false};
+
ActiveModeInfo mUpcomingActiveMode GUARDED_BY(kMainThreadContext);
+ bool mIsModeSetPending GUARDED_BY(kMainThreadContext) = false;
};
struct DisplayDeviceState {
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp
index aaf2523..0c2b77d 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp
@@ -311,6 +311,14 @@
}
Error Display::supportsDoze(bool* outSupport) const {
+ {
+ std::scoped_lock lock(mDisplayCapabilitiesMutex);
+ if (!mDisplayCapabilities) {
+ // The display has not turned on since boot, so DOZE support is unknown.
+ ALOGW("%s: haven't queried capabilities yet!", __func__);
+ return Error::NO_RESOURCES;
+ }
+ }
*outSupport = hasCapability(DisplayCapability::DOZE);
return Error::NONE;
}
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 3177b33..a9bb928 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -616,19 +616,29 @@
ALOGV("setPowerMode: Calling HWC %s", to_string(mode).c_str());
{
bool supportsDoze = false;
- auto error = hwcDisplay->supportsDoze(&supportsDoze);
- if (error != hal::Error::NONE) {
- LOG_HWC_ERROR("supportsDoze", error, displayId);
- }
+ const auto queryDozeError = hwcDisplay->supportsDoze(&supportsDoze);
- if (!supportsDoze) {
+ // queryDozeError might be NO_RESOURCES, in the case of a display that has never
+ // been turned on. In that case, attempt to set to DOZE anyway.
+ if (!supportsDoze && queryDozeError == hal::Error::NONE) {
mode = hal::PowerMode::ON;
}
- error = hwcDisplay->setPowerMode(mode);
+ auto error = hwcDisplay->setPowerMode(mode);
if (error != hal::Error::NONE) {
LOG_HWC_ERROR(("setPowerMode(" + to_string(mode) + ")").c_str(), error,
displayId);
+ // If the display had never been turned on, so its doze
+ // support was unknown, it may truly not support doze. Try
+ // switching it to ON instead.
+ if (queryDozeError == hal::Error::NO_RESOURCES) {
+ ALOGD("%s: failed to set %s to %s. Trying again with ON", __func__,
+ to_string(displayId).c_str(), to_string(mode).c_str());
+ error = hwcDisplay->setPowerMode(hal::PowerMode::ON);
+ if (error != hal::Error::NONE) {
+ LOG_HWC_ERROR("setPowerMode(ON)", error, displayId);
+ }
+ }
}
}
break;
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 3a41f15..1a0517a 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -594,8 +594,8 @@
snapshot->localTransformInverse = snapshot->localTransform.inverse();
snapshot->blendMode = static_cast<Hwc2::IComposerClient::BlendMode>(blendMode);
snapshot->alpha = alpha;
- snapshot->backgroundBlurRadius = drawingState.backgroundBlurRadius;
- snapshot->blurRegions = drawingState.blurRegions;
+ snapshot->backgroundBlurRadius = getBackgroundBlurRadius();
+ snapshot->blurRegions = getBlurRegions();
snapshot->stretchEffect = getStretchEffect();
}
@@ -664,8 +664,8 @@
snapshot->forceClientComposition = true;
}
// If there are no visible region changes, we still need to update blur parameters.
- snapshot->blurRegions = drawingState.blurRegions;
- snapshot->backgroundBlurRadius = drawingState.backgroundBlurRadius;
+ snapshot->blurRegions = getBlurRegions();
+ snapshot->backgroundBlurRadius = getBackgroundBlurRadius();
// Layer framerate is used in caching decisions.
// Retrieve it from the scheduler which maintains an instance of LayerHistory, and store it in
diff --git a/services/surfaceflinger/LayerFE.cpp b/services/surfaceflinger/LayerFE.cpp
index f855f27..4d3e048 100644
--- a/services/surfaceflinger/LayerFE.cpp
+++ b/services/surfaceflinger/LayerFE.cpp
@@ -16,7 +16,7 @@
// #define LOG_NDEBUG 0
#undef LOG_TAG
-#define LOG_TAG "LayerFE"
+#define LOG_TAG "SurfaceFlinger"
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
#include <gui/GLConsumer.h>
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index d6d7725..5a19ec5 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -186,7 +186,17 @@
FrameTargeter& pacesetterTargeter = *pacesetterOpt->get().targeterPtr;
pacesetterTargeter.beginFrame(beginFrameArgs, *pacesetterOpt->get().schedulePtr);
- if (!compositor.commit(pacesetterTargeter.target())) return;
+ FrameTargets targets;
+ targets.try_emplace(pacesetterId, &pacesetterTargeter.target());
+
+ for (const auto& [id, display] : mDisplays) {
+ if (id == pacesetterId) continue;
+
+ const FrameTargeter& targeter = *display.targeterPtr;
+ targets.try_emplace(id, &targeter.target());
+ }
+
+ if (!compositor.commit(pacesetterId, targets)) return;
// TODO(b/256196556): Choose the frontrunner display.
FrameTargeters targeters;
diff --git a/services/surfaceflinger/Scheduler/include/scheduler/interface/ICompositor.h b/services/surfaceflinger/Scheduler/include/scheduler/interface/ICompositor.h
index 6fe813a..12ee36e 100644
--- a/services/surfaceflinger/Scheduler/include/scheduler/interface/ICompositor.h
+++ b/services/surfaceflinger/Scheduler/include/scheduler/interface/ICompositor.h
@@ -29,6 +29,7 @@
class FrameTarget;
class FrameTargeter;
+using FrameTargets = ui::PhysicalDisplayMap<PhysicalDisplayId, const scheduler::FrameTarget*>;
using FrameTargeters = ui::PhysicalDisplayMap<PhysicalDisplayId, scheduler::FrameTargeter*>;
} // namespace scheduler
@@ -39,7 +40,7 @@
// Commits transactions for layers and displays. Returns whether any state has been invalidated,
// i.e. whether a frame should be composited for each display.
- virtual bool commit(const scheduler::FrameTarget&) = 0;
+ virtual bool commit(PhysicalDisplayId pacesetterId, const scheduler::FrameTargets&) = 0;
// Composites a frame for each display. CompositionEngine performs GPU and/or HAL composition
// via RenderEngine and the Composer HAL, respectively.
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 9f24dd6..f114b28 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -1195,9 +1195,9 @@
}
void SurfaceFlinger::setDesiredActiveMode(display::DisplayModeRequest&& request, bool force) {
- ATRACE_CALL();
-
const auto displayId = request.mode.modePtr->getPhysicalDisplayId();
+ ATRACE_NAME(ftl::Concat(__func__, ' ', displayId.value).c_str());
+
const auto display = getDisplayDeviceLocked(displayId);
if (!display) {
ALOGW("%s: display is no longer valid", __func__);
@@ -1225,17 +1225,24 @@
// As we called to set period, we will call to onRefreshRateChangeCompleted once
// VsyncController model is locked.
mScheduler->modulateVsync(displayId, &VsyncModulator::onRefreshRateChangeInitiated);
- updatePhaseConfiguration(mode.fps);
+
+ if (displayId == mActiveDisplayId) {
+ updatePhaseConfiguration(mode.fps);
+ }
+
mScheduler->setModeChangePending(true);
break;
case DisplayDevice::DesiredActiveModeAction::InitiateRenderRateSwitch:
mScheduler->setRenderRate(displayId, mode.fps);
- updatePhaseConfiguration(mode.fps);
- mRefreshRateStats->setRefreshRate(mode.fps);
- if (display->getPhysicalId() == mActiveDisplayId && emitEvent) {
- mScheduler->onPrimaryDisplayModeChanged(mAppConnectionHandle, mode);
+
+ if (displayId == mActiveDisplayId) {
+ updatePhaseConfiguration(mode.fps);
+ mRefreshRateStats->setRefreshRate(mode.fps);
}
+ if (emitEvent) {
+ dispatchDisplayModeChangeEvent(displayId, mode);
+ }
break;
case DisplayDevice::DesiredActiveModeAction::None:
break;
@@ -1291,24 +1298,20 @@
return future.get();
}
-void SurfaceFlinger::updateInternalStateWithChangedMode() {
- ATRACE_CALL();
+void SurfaceFlinger::finalizeDisplayModeChange(DisplayDevice& display) {
+ const auto displayId = display.getPhysicalId();
+ ATRACE_NAME(ftl::Concat(__func__, ' ', displayId.value).c_str());
- const auto display = getDefaultDisplayDeviceLocked();
- if (!display) {
- return;
- }
-
- const auto upcomingModeInfo = display->getUpcomingActiveMode();
+ const auto upcomingModeInfo = display.getUpcomingActiveMode();
if (!upcomingModeInfo.modeOpt) {
// There is no pending mode change. This can happen if the active
// display changed and the mode change happened on a different display.
return;
}
- if (display->getActiveMode().modePtr->getResolution() !=
+ if (display.getActiveMode().modePtr->getResolution() !=
upcomingModeInfo.modeOpt->modePtr->getResolution()) {
- auto& state = mCurrentState.displays.editValueFor(display->getDisplayToken());
+ auto& state = mCurrentState.displays.editValueFor(display.getDisplayToken());
// We need to generate new sequenceId in order to recreate the display (and this
// way the framebuffer).
state.sequenceId = DisplayDeviceState{}.sequenceId;
@@ -1319,27 +1322,24 @@
return;
}
- mPhysicalDisplays.get(display->getPhysicalId())
- .transform(&PhysicalDisplay::snapshotRef)
- .transform(ftl::unit_fn([&](const display::DisplaySnapshot& snapshot) {
- FTL_FAKE_GUARD(kMainThreadContext,
- display->setActiveMode(upcomingModeInfo.modeOpt->modePtr->getId(),
- upcomingModeInfo.modeOpt->modePtr->getFps(),
- upcomingModeInfo.modeOpt->fps));
- }));
+ const auto& activeMode = *upcomingModeInfo.modeOpt;
+ display.finalizeModeChange(activeMode.modePtr->getId(), activeMode.modePtr->getFps(),
+ activeMode.fps);
- const Fps refreshRate = upcomingModeInfo.modeOpt->fps;
- mRefreshRateStats->setRefreshRate(refreshRate);
- updatePhaseConfiguration(refreshRate);
+ if (displayId == mActiveDisplayId) {
+ mRefreshRateStats->setRefreshRate(activeMode.fps);
+ updatePhaseConfiguration(activeMode.fps);
+ }
if (upcomingModeInfo.event != scheduler::DisplayModeEvent::None) {
- mScheduler->onPrimaryDisplayModeChanged(mAppConnectionHandle, *upcomingModeInfo.modeOpt);
+ dispatchDisplayModeChangeEvent(displayId, activeMode);
}
}
void SurfaceFlinger::clearDesiredActiveModeState(const sp<DisplayDevice>& display) {
display->clearDesiredActiveModeState();
if (display->getPhysicalId() == mActiveDisplayId) {
+ // TODO(b/255635711): Check for pending mode changes on other displays.
mScheduler->setModeChangePending(false);
}
}
@@ -1353,21 +1353,18 @@
clearDesiredActiveModeState(display);
mScheduler->resyncToHardwareVsync(displayId, true /* allowToEnable */, displayFps);
mScheduler->setRenderRate(displayId, renderFps);
- updatePhaseConfiguration(renderFps);
+
+ if (displayId == mActiveDisplayId) {
+ updatePhaseConfiguration(renderFps);
+ }
}
-void SurfaceFlinger::setActiveModeInHwcIfNeeded() {
+void SurfaceFlinger::initiateDisplayModeChanges() {
ATRACE_CALL();
std::optional<PhysicalDisplayId> displayToUpdateImmediately;
for (const auto& [id, physical] : mPhysicalDisplays) {
- const auto& snapshot = physical.snapshot();
-
- if (snapshot.connectionType() != ui::DisplayConnectionType::Internal) {
- continue;
- }
-
const auto display = getDisplayDeviceLocked(id);
if (!display) continue;
@@ -1378,14 +1375,14 @@
continue;
}
- if (id != mActiveDisplayId) {
- // Display is no longer the active display, so abort the mode change.
+ if (!display->isPoweredOn()) {
+ // Display is no longer powered on, so abort the mode change.
clearDesiredActiveModeState(display);
continue;
}
const auto desiredModeId = desiredActiveMode->modeOpt->modePtr->getId();
- const auto displayModePtrOpt = snapshot.displayModes().get(desiredModeId);
+ const auto displayModePtrOpt = physical.snapshot().displayModes().get(desiredModeId);
if (!displayModePtrOpt) {
ALOGW("Desired display mode is no longer supported. Mode ID = %d",
@@ -1435,19 +1432,18 @@
if (outTimeline.refreshRequired) {
scheduleComposite(FrameHint::kNone);
- mSetActiveModePending = true;
} else {
- // Updating the internal state should be done outside the loop,
- // because it can recreate a DisplayDevice and modify mDisplays
- // which will invalidate the iterator.
+ // TODO(b/255635711): Remove `displayToUpdateImmediately` to `finalizeDisplayModeChange`
+ // for all displays. This was only needed when the loop iterated over `mDisplays` rather
+ // than `mPhysicalDisplays`.
displayToUpdateImmediately = display->getPhysicalId();
}
}
if (displayToUpdateImmediately) {
- updateInternalStateWithChangedMode();
-
const auto display = getDisplayDeviceLocked(*displayToUpdateImmediately);
+ finalizeDisplayModeChange(*display);
+
const auto desiredActiveMode = display->getDesiredActiveMode();
if (desiredActiveMode && display->getActiveMode() == desiredActiveMode->modeOpt) {
desiredActiveModeChangeDone(display);
@@ -2398,7 +2394,10 @@
return mustComposite;
}
-bool SurfaceFlinger::commit(const scheduler::FrameTarget& pacesetterFrameTarget) {
+bool SurfaceFlinger::commit(PhysicalDisplayId pacesetterId,
+ const scheduler::FrameTargets& frameTargets) {
+ const scheduler::FrameTarget& pacesetterFrameTarget = *frameTargets.get(pacesetterId)->get();
+
const VsyncId vsyncId = pacesetterFrameTarget.vsyncId();
ATRACE_NAME(ftl::Concat(__func__, ' ', ftl::to_underlying(vsyncId)).c_str());
@@ -2411,20 +2410,35 @@
mTracingEnabledChanged = false;
}
- // If we are in the middle of a mode change and the fence hasn't
- // fired yet just wait for the next commit.
- if (mSetActiveModePending) {
- if (pacesetterFrameTarget.isFramePending()) {
- mScheduler->scheduleFrame();
- return false;
- }
+ // If a mode set is pending and the fence hasn't fired yet, wait for the next commit.
+ if (std::any_of(frameTargets.begin(), frameTargets.end(),
+ [this](const auto& pair) FTL_FAKE_GUARD(mStateLock)
+ FTL_FAKE_GUARD(kMainThreadContext) {
+ if (!pair.second->isFramePending()) return false;
- // We received the present fence from the HWC, so we assume it successfully updated
- // the mode, hence we update SF.
- mSetActiveModePending = false;
- {
- Mutex::Autolock lock(mStateLock);
- updateInternalStateWithChangedMode();
+ if (const auto display = getDisplayDeviceLocked(pair.first)) {
+ return display->isModeSetPending();
+ }
+
+ return false;
+ })) {
+ mScheduler->scheduleFrame();
+ return false;
+ }
+
+ {
+ Mutex::Autolock lock(mStateLock);
+
+ for (const auto [id, target] : frameTargets) {
+ // TODO(b/241285876): This is `nullptr` when the DisplayDevice is about to be removed in
+ // this commit, since the PhysicalDisplay has already been removed. Rather than checking
+ // for `nullptr` below, change Scheduler::onFrameSignal to filter out the FrameTarget of
+ // the removed display.
+ const auto display = getDisplayDeviceLocked(id);
+
+ if (display && display->isModeSetPending()) {
+ finalizeDisplayModeChange(*display);
+ }
}
}
@@ -2515,7 +2529,7 @@
? &mLayerHierarchyBuilder.getHierarchy()
: nullptr,
updateAttachedChoreographer);
- setActiveModeInHwcIfNeeded();
+ initiateDisplayModeChanges();
}
updateCursorAsync();
@@ -3322,6 +3336,16 @@
mScheduler->onHotplugReceived(mSfConnectionHandle, displayId, connected);
}
+void SurfaceFlinger::dispatchDisplayModeChangeEvent(PhysicalDisplayId displayId,
+ const scheduler::FrameRateMode& mode) {
+ // TODO(b/255635821): Merge code paths and move to Scheduler.
+ const auto onDisplayModeChanged = displayId == mActiveDisplayId
+ ? &scheduler::Scheduler::onPrimaryDisplayModeChanged
+ : &scheduler::Scheduler::onNonPrimaryDisplayModeChanged;
+
+ ((*mScheduler).*onDisplayModeChanged)(mAppConnectionHandle, mode);
+}
+
sp<DisplayDevice> SurfaceFlinger::setupNewDisplayDeviceInternal(
const wp<IBinder>& displayToken,
std::shared_ptr<compositionengine::Display> compositionDisplay,
@@ -3420,14 +3444,8 @@
RenderIntent::COLORIMETRIC});
if (const auto& physical = state.physical) {
- mPhysicalDisplays.get(physical->id)
- .transform(&PhysicalDisplay::snapshotRef)
- .transform(ftl::unit_fn([&](const display::DisplaySnapshot& snapshot) {
- FTL_FAKE_GUARD(kMainThreadContext,
- display->setActiveMode(physical->activeMode->getId(),
- physical->activeMode->getFps(),
- physical->activeMode->getFps()));
- }));
+ const auto& mode = *physical->activeMode;
+ display->setActiveMode(mode.getId(), mode.getFps(), mode.getFps());
}
display->setLayerFilter(makeLayerFilterForDisplay(display->getId(), state.layerStack));
@@ -3946,12 +3964,8 @@
if (!display) continue;
- const bool isInternalDisplay = mPhysicalDisplays.get(displayId)
- .transform(&PhysicalDisplay::isInternal)
- .value_or(false);
-
- if (isInternalDisplay && displayId != mActiveDisplayId) {
- ALOGV("%s(%s): Inactive display", __func__, to_string(displayId).c_str());
+ if (!display->isPoweredOn()) {
+ ALOGV("%s(%s): Display is powered off", __func__, to_string(displayId).c_str());
continue;
}
@@ -3959,7 +3973,7 @@
setDesiredActiveMode(std::move(request));
} else {
ALOGV("%s: Mode %d is disallowed for display %s", __func__, modePtr->getId().value(),
- to_string(display->getId()).c_str());
+ to_string(displayId).c_str());
}
}
}
@@ -6127,6 +6141,13 @@
displayProto->set_id(display->getId().value);
displayProto->set_name(display->getDisplayName());
displayProto->set_layer_stack(display->getLayerStack().id);
+
+ if (!display->isVirtual()) {
+ const auto dpi = display->refreshRateSelector().getActiveMode().modePtr->getDpi();
+ displayProto->set_dpi_x(dpi.x);
+ displayProto->set_dpi_y(dpi.y);
+ }
+
LayerProtoHelper::writeSizeToProto(display->getWidth(), display->getHeight(),
[&]() { return displayProto->mutable_size(); });
LayerProtoHelper::writeToProto(display->getLayerStackSpaceRect(), [&]() {
@@ -7311,16 +7332,27 @@
} // namespace
-status_t SurfaceFlinger::captureDisplay(const DisplayCaptureArgs& args,
- const sp<IScreenCaptureListener>& captureListener) {
+static void invokeScreenCaptureError(const status_t status,
+ const sp<IScreenCaptureListener>& captureListener) {
+ ScreenCaptureResults captureResults;
+ captureResults.fenceResult = base::unexpected(status);
+ captureListener->onScreenCaptureCompleted(captureResults);
+}
+
+void SurfaceFlinger::captureDisplay(const DisplayCaptureArgs& args,
+ const sp<IScreenCaptureListener>& captureListener) {
ATRACE_CALL();
status_t validate = validateScreenshotPermissions(args);
if (validate != OK) {
- return validate;
+ invokeScreenCaptureError(validate, captureListener);
+ return;
}
- if (!args.displayToken) return BAD_VALUE;
+ if (!args.displayToken) {
+ invokeScreenCaptureError(BAD_VALUE, captureListener);
+ return;
+ }
wp<const DisplayDevice> displayWeak;
ui::LayerStack layerStack;
@@ -7329,7 +7361,10 @@
{
Mutex::Autolock lock(mStateLock);
sp<DisplayDevice> display = getDisplayDeviceLocked(args.displayToken);
- if (!display) return NAME_NOT_FOUND;
+ if (!display) {
+ invokeScreenCaptureError(NAME_NOT_FOUND, captureListener);
+ return;
+ }
displayWeak = display;
layerStack = display->getLayerStack();
@@ -7344,7 +7379,8 @@
excludeLayerIds.emplace(excludeLayer);
} else {
ALOGW("Invalid layer handle passed as excludeLayer to captureDisplay");
- return NAME_NOT_FOUND;
+ invokeScreenCaptureError(NAME_NOT_FOUND, captureListener);
+ return;
}
}
}
@@ -7367,14 +7403,12 @@
getLayerSnapshots = RenderArea::fromTraverseLayersLambda(traverseLayers);
}
- auto future = captureScreenCommon(std::move(renderAreaFuture), getLayerSnapshots, reqSize,
- args.pixelFormat, args.allowProtected, args.grayscale,
- captureListener);
- return fenceStatus(future.get());
+ captureScreenCommon(std::move(renderAreaFuture), getLayerSnapshots, reqSize, args.pixelFormat,
+ args.allowProtected, args.grayscale, captureListener);
}
-status_t SurfaceFlinger::captureDisplay(DisplayId displayId,
- const sp<IScreenCaptureListener>& captureListener) {
+void SurfaceFlinger::captureDisplay(DisplayId displayId,
+ const sp<IScreenCaptureListener>& captureListener) {
ui::LayerStack layerStack;
wp<const DisplayDevice> displayWeak;
ui::Size size;
@@ -7383,7 +7417,8 @@
const auto display = getDisplayDeviceLocked(displayId);
if (!display) {
- return NAME_NOT_FOUND;
+ invokeScreenCaptureError(NAME_NOT_FOUND, captureListener);
+ return;
}
displayWeak = display;
@@ -7411,25 +7446,25 @@
if (captureListener == nullptr) {
ALOGE("capture screen must provide a capture listener callback");
- return BAD_VALUE;
+ invokeScreenCaptureError(BAD_VALUE, captureListener);
+ return;
}
constexpr bool kAllowProtected = false;
constexpr bool kGrayscale = false;
- auto future = captureScreenCommon(std::move(renderAreaFuture), getLayerSnapshots, size,
- ui::PixelFormat::RGBA_8888, kAllowProtected, kGrayscale,
- captureListener);
- return fenceStatus(future.get());
+ captureScreenCommon(std::move(renderAreaFuture), getLayerSnapshots, size,
+ ui::PixelFormat::RGBA_8888, kAllowProtected, kGrayscale, captureListener);
}
-status_t SurfaceFlinger::captureLayers(const LayerCaptureArgs& args,
- const sp<IScreenCaptureListener>& captureListener) {
+void SurfaceFlinger::captureLayers(const LayerCaptureArgs& args,
+ const sp<IScreenCaptureListener>& captureListener) {
ATRACE_CALL();
status_t validate = validateScreenshotPermissions(args);
if (validate != OK) {
- return validate;
+ invokeScreenCaptureError(validate, captureListener);
+ return;
}
ui::Size reqSize;
@@ -7447,13 +7482,15 @@
parent = LayerHandle::getLayer(args.layerHandle);
if (parent == nullptr) {
ALOGE("captureLayers called with an invalid or removed parent");
- return NAME_NOT_FOUND;
+ invokeScreenCaptureError(NAME_NOT_FOUND, captureListener);
+ return;
}
if (!canCaptureBlackoutContent &&
parent->getDrawingState().flags & layer_state_t::eLayerSecure) {
ALOGW("Attempting to capture secure layer: PERMISSION_DENIED");
- return PERMISSION_DENIED;
+ invokeScreenCaptureError(PERMISSION_DENIED, captureListener);
+ return;
}
Rect parentSourceBounds = parent->getCroppedBufferSize(parent->getDrawingState());
@@ -7470,7 +7507,8 @@
if (crop.isEmpty() || args.frameScaleX <= 0.0f || args.frameScaleY <= 0.0f) {
// Error out if the layer has no source bounds (i.e. they are boundless) and a source
// crop was not specified, or an invalid frame scale was provided.
- return BAD_VALUE;
+ invokeScreenCaptureError(BAD_VALUE, captureListener);
+ return;
}
reqSize = ui::Size(crop.width() * args.frameScaleX, crop.height() * args.frameScaleY);
@@ -7480,7 +7518,8 @@
excludeLayerIds.emplace(excludeLayer);
} else {
ALOGW("Invalid layer handle passed as excludeLayer to captureLayers");
- return NAME_NOT_FOUND;
+ invokeScreenCaptureError(NAME_NOT_FOUND, captureListener);
+ return;
}
}
} // mStateLock
@@ -7488,7 +7527,8 @@
// really small crop or frameScale
if (reqSize.width <= 0 || reqSize.height <= 0) {
ALOGW("Failed to captureLayes: crop or scale too small");
- return BAD_VALUE;
+ invokeScreenCaptureError(BAD_VALUE, captureListener);
+ return;
}
bool childrenOnly = args.childrenOnly;
@@ -7552,26 +7592,27 @@
if (captureListener == nullptr) {
ALOGE("capture screen must provide a capture listener callback");
- return BAD_VALUE;
+ invokeScreenCaptureError(BAD_VALUE, captureListener);
+ return;
}
- auto future = captureScreenCommon(std::move(renderAreaFuture), getLayerSnapshots, reqSize,
- args.pixelFormat, args.allowProtected, args.grayscale,
- captureListener);
- return fenceStatus(future.get());
+ captureScreenCommon(std::move(renderAreaFuture), getLayerSnapshots, reqSize, args.pixelFormat,
+ args.allowProtected, args.grayscale, captureListener);
}
-ftl::SharedFuture<FenceResult> SurfaceFlinger::captureScreenCommon(
- RenderAreaFuture renderAreaFuture, GetLayerSnapshotsFunction getLayerSnapshots,
- ui::Size bufferSize, ui::PixelFormat reqPixelFormat, bool allowProtected, bool grayscale,
- const sp<IScreenCaptureListener>& captureListener) {
+void SurfaceFlinger::captureScreenCommon(RenderAreaFuture renderAreaFuture,
+ GetLayerSnapshotsFunction getLayerSnapshots,
+ ui::Size bufferSize, ui::PixelFormat reqPixelFormat,
+ bool allowProtected, bool grayscale,
+ const sp<IScreenCaptureListener>& captureListener) {
ATRACE_CALL();
if (exceedsMaxRenderTargetSize(bufferSize.getWidth(), bufferSize.getHeight())) {
ALOGE("Attempted to capture screen with size (%" PRId32 ", %" PRId32
") that exceeds render target size limit.",
bufferSize.getWidth(), bufferSize.getHeight());
- return ftl::yield<FenceResult>(base::unexpected(BAD_VALUE)).share();
+ invokeScreenCaptureError(BAD_VALUE, captureListener);
+ return;
}
// Loop over all visible layers to see whether there's any protected layer. A protected layer is
@@ -7611,14 +7652,16 @@
// Otherwise an irreponsible process may cause an SF crash by allocating
// too much.
ALOGE("%s: Buffer failed to allocate: %d", __func__, bufferStatus);
- return ftl::yield<FenceResult>(base::unexpected(bufferStatus)).share();
+ invokeScreenCaptureError(bufferStatus, captureListener);
+ return;
}
const std::shared_ptr<renderengine::ExternalTexture> texture = std::make_shared<
renderengine::impl::ExternalTexture>(buffer, getRenderEngine(),
renderengine::impl::ExternalTexture::Usage::
WRITEABLE);
- return captureScreenCommon(std::move(renderAreaFuture), getLayerSnapshots, texture,
- false /* regionSampling */, grayscale, captureListener);
+ auto fence = captureScreenCommon(std::move(renderAreaFuture), getLayerSnapshots, texture,
+ false /* regionSampling */, grayscale, captureListener);
+ fence.get();
}
ftl::SharedFuture<FenceResult> SurfaceFlinger::captureScreenCommon(
@@ -7922,6 +7965,7 @@
const sp<DisplayDevice>& display,
const scheduler::RefreshRateSelector::PolicyVariant& policy) {
const auto displayId = display->getPhysicalId();
+ ATRACE_NAME(ftl::Concat(__func__, ' ', displayId.value).c_str());
Mutex::Autolock lock(mStateLock);
@@ -7942,13 +7986,11 @@
break;
}
- const bool isInternalDisplay = mPhysicalDisplays.get(displayId)
- .transform(&PhysicalDisplay::isInternal)
- .value_or(false);
-
- if (isInternalDisplay && displayId != mActiveDisplayId) {
- // The policy will be be applied when the display becomes active.
- ALOGV("%s(%s): Inactive display", __func__, to_string(displayId).c_str());
+ // TODO(b/255635711): Apply the policy once the display is powered on, which is currently only
+ // done for the internal display that becomes active on fold/unfold. For now, assume that DM
+ // always powers on the secondary (internal or external) display before setting its policy.
+ if (!display->isPoweredOn()) {
+ ALOGV("%s(%s): Display is powered off", __func__, to_string(displayId).c_str());
return NO_ERROR;
}
@@ -8311,7 +8353,9 @@
resetPhaseConfiguration(activeDisplay.getActiveMode().fps);
+ // TODO(b/255635711): Check for pending mode changes on other displays.
mScheduler->setModeChangePending(false);
+
mScheduler->setPacesetterDisplay(mActiveDisplayId);
onActiveDisplaySizeChanged(activeDisplay);
@@ -8842,33 +8886,35 @@
outInfo->secure = info.secure;
outInfo->installOrientation = static_cast<gui::Rotation>(info.installOrientation);
- gui::DeviceProductInfo dinfo;
- std::optional<DeviceProductInfo> dpi = info.deviceProductInfo;
- dinfo.name = std::move(dpi->name);
- dinfo.manufacturerPnpId =
- std::vector<uint8_t>(dpi->manufacturerPnpId.begin(), dpi->manufacturerPnpId.end());
- dinfo.productId = dpi->productId;
- dinfo.relativeAddress =
- std::vector<uint8_t>(dpi->relativeAddress.begin(), dpi->relativeAddress.end());
- if (const auto* model =
- std::get_if<DeviceProductInfo::ModelYear>(&dpi->manufactureOrModelDate)) {
- gui::DeviceProductInfo::ModelYear modelYear;
- modelYear.year = model->year;
- dinfo.manufactureOrModelDate.set<Tag::modelYear>(modelYear);
- } else if (const auto* manufacture = std::get_if<DeviceProductInfo::ManufactureYear>(
- &dpi->manufactureOrModelDate)) {
- gui::DeviceProductInfo::ManufactureYear date;
- date.modelYear.year = manufacture->year;
- dinfo.manufactureOrModelDate.set<Tag::manufactureYear>(date);
- } else if (const auto* manufacture = std::get_if<DeviceProductInfo::ManufactureWeekAndYear>(
- &dpi->manufactureOrModelDate)) {
- gui::DeviceProductInfo::ManufactureWeekAndYear date;
- date.manufactureYear.modelYear.year = manufacture->year;
- date.week = manufacture->week;
- dinfo.manufactureOrModelDate.set<Tag::manufactureWeekAndYear>(date);
- }
+ if (const std::optional<DeviceProductInfo> dpi = info.deviceProductInfo) {
+ gui::DeviceProductInfo dinfo;
+ dinfo.name = std::move(dpi->name);
+ dinfo.manufacturerPnpId = std::vector<uint8_t>(dpi->manufacturerPnpId.begin(),
+ dpi->manufacturerPnpId.end());
+ dinfo.productId = dpi->productId;
+ dinfo.relativeAddress =
+ std::vector<uint8_t>(dpi->relativeAddress.begin(), dpi->relativeAddress.end());
+ if (const auto* model =
+ std::get_if<DeviceProductInfo::ModelYear>(&dpi->manufactureOrModelDate)) {
+ gui::DeviceProductInfo::ModelYear modelYear;
+ modelYear.year = model->year;
+ dinfo.manufactureOrModelDate.set<Tag::modelYear>(modelYear);
+ } else if (const auto* manufacture = std::get_if<DeviceProductInfo::ManufactureYear>(
+ &dpi->manufactureOrModelDate)) {
+ gui::DeviceProductInfo::ManufactureYear date;
+ date.modelYear.year = manufacture->year;
+ dinfo.manufactureOrModelDate.set<Tag::manufactureYear>(date);
+ } else if (const auto* manufacture =
+ std::get_if<DeviceProductInfo::ManufactureWeekAndYear>(
+ &dpi->manufactureOrModelDate)) {
+ gui::DeviceProductInfo::ManufactureWeekAndYear date;
+ date.manufactureYear.modelYear.year = manufacture->year;
+ date.week = manufacture->week;
+ dinfo.manufactureOrModelDate.set<Tag::manufactureWeekAndYear>(date);
+ }
- outInfo->deviceProductInfo = dinfo;
+ outInfo->deviceProductInfo = dinfo;
+ }
}
return binderStatusFromStatusT(status);
}
@@ -9055,28 +9101,28 @@
binder::Status SurfaceComposerAIDL::captureDisplay(
const DisplayCaptureArgs& args, const sp<IScreenCaptureListener>& captureListener) {
- status_t status = mFlinger->captureDisplay(args, captureListener);
- return binderStatusFromStatusT(status);
+ mFlinger->captureDisplay(args, captureListener);
+ return binderStatusFromStatusT(NO_ERROR);
}
binder::Status SurfaceComposerAIDL::captureDisplayById(
int64_t displayId, const sp<IScreenCaptureListener>& captureListener) {
- status_t status;
+ // status_t status;
IPCThreadState* ipc = IPCThreadState::self();
const int uid = ipc->getCallingUid();
if (uid == AID_ROOT || uid == AID_GRAPHICS || uid == AID_SYSTEM || uid == AID_SHELL) {
std::optional<DisplayId> id = DisplayId::fromValue(static_cast<uint64_t>(displayId));
- status = mFlinger->captureDisplay(*id, captureListener);
+ mFlinger->captureDisplay(*id, captureListener);
} else {
- status = PERMISSION_DENIED;
+ invokeScreenCaptureError(PERMISSION_DENIED, captureListener);
}
- return binderStatusFromStatusT(status);
+ return binderStatusFromStatusT(NO_ERROR);
}
binder::Status SurfaceComposerAIDL::captureLayers(
const LayerCaptureArgs& args, const sp<IScreenCaptureListener>& captureListener) {
- status_t status = mFlinger->captureLayers(args, captureListener);
- return binderStatusFromStatusT(status);
+ mFlinger->captureLayers(args, captureListener);
+ return binderStatusFromStatusT(NO_ERROR);
}
binder::Status SurfaceComposerAIDL::overrideHdrTypes(const sp<IBinder>& display,
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index b07910d..93560bd 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -535,9 +535,9 @@
EventRegistrationFlags eventRegistration = {},
const sp<IBinder>& layerHandle = nullptr);
- status_t captureDisplay(const DisplayCaptureArgs&, const sp<IScreenCaptureListener>&);
- status_t captureDisplay(DisplayId, const sp<IScreenCaptureListener>&);
- status_t captureLayers(const LayerCaptureArgs&, const sp<IScreenCaptureListener>&);
+ void captureDisplay(const DisplayCaptureArgs&, const sp<IScreenCaptureListener>&);
+ void captureDisplay(DisplayId, const sp<IScreenCaptureListener>&);
+ void captureLayers(const LayerCaptureArgs&, const sp<IScreenCaptureListener>&);
status_t getDisplayStats(const sp<IBinder>& displayToken, DisplayStatInfo* stats);
status_t getDisplayState(const sp<IBinder>& displayToken, ui::DisplayState*)
@@ -638,7 +638,8 @@
// ICompositor overrides:
void configure() override REQUIRES(kMainThreadContext);
- bool commit(const scheduler::FrameTarget&) override REQUIRES(kMainThreadContext);
+ bool commit(PhysicalDisplayId pacesetterId, const scheduler::FrameTargets&) override
+ REQUIRES(kMainThreadContext);
CompositeResultsPerDisplay composite(PhysicalDisplayId pacesetterId,
const scheduler::FrameTargeters&) override
REQUIRES(kMainThreadContext);
@@ -684,11 +685,10 @@
REQUIRES(mStateLock);
status_t setActiveModeFromBackdoor(const sp<display::DisplayToken>&, DisplayModeId);
- // Sets the active mode and a new refresh rate in SF.
- void updateInternalStateWithChangedMode() REQUIRES(mStateLock, kMainThreadContext);
- // Calls to setActiveMode on the main thread if there is a pending mode change
- // that needs to be applied.
- void setActiveModeInHwcIfNeeded() REQUIRES(mStateLock, kMainThreadContext);
+
+ void initiateDisplayModeChanges() REQUIRES(mStateLock, kMainThreadContext);
+ void finalizeDisplayModeChange(DisplayDevice&) REQUIRES(mStateLock, kMainThreadContext);
+
void clearDesiredActiveModeState(const sp<DisplayDevice>&) REQUIRES(mStateLock);
// Called when active mode is no longer is progress
void desiredActiveModeChangeDone(const sp<DisplayDevice>&) REQUIRES(mStateLock);
@@ -836,10 +836,9 @@
// Boot animation, on/off animations and screen capture
void startBootAnim();
- ftl::SharedFuture<FenceResult> captureScreenCommon(RenderAreaFuture, GetLayerSnapshotsFunction,
- ui::Size bufferSize, ui::PixelFormat,
- bool allowProtected, bool grayscale,
- const sp<IScreenCaptureListener>&);
+ void captureScreenCommon(RenderAreaFuture, GetLayerSnapshotsFunction, ui::Size bufferSize,
+ ui::PixelFormat, bool allowProtected, bool grayscale,
+ const sp<IScreenCaptureListener>&);
ftl::SharedFuture<FenceResult> captureScreenCommon(
RenderAreaFuture, GetLayerSnapshotsFunction,
const std::shared_ptr<renderengine::ExternalTexture>&, bool regionSampling,
@@ -1011,7 +1010,9 @@
const DisplayDeviceState& drawingState)
REQUIRES(mStateLock, kMainThreadContext);
- void dispatchDisplayHotplugEvent(PhysicalDisplayId displayId, bool connected);
+ void dispatchDisplayHotplugEvent(PhysicalDisplayId, bool connected);
+ void dispatchDisplayModeChangeEvent(PhysicalDisplayId, const scheduler::FrameRateMode&)
+ REQUIRES(mStateLock);
/*
* VSYNC
@@ -1330,9 +1331,6 @@
std::unique_ptr<scheduler::RefreshRateStats> mRefreshRateStats;
scheduler::PresentLatencyTracker mPresentLatencyTracker GUARDED_BY(kMainThreadContext);
- // below flags are set by main thread only
- bool mSetActiveModePending = false;
-
bool mLumaSampling = true;
sp<RegionSamplingThread> mRegionSamplingThread;
sp<FpsReporter> mFpsReporter;
diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h
index 28ac664..ca1af6e 100644
--- a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h
@@ -286,7 +286,7 @@
private:
// ICompositor overrides:
void configure() override {}
- bool commit(const scheduler::FrameTarget&) override { return false; }
+ bool commit(PhysicalDisplayId, const scheduler::FrameTargets&) override { return false; }
CompositeResultsPerDisplay composite(PhysicalDisplayId,
const scheduler::FrameTargeters&) override {
return {};
diff --git a/services/surfaceflinger/layerproto/display.proto b/services/surfaceflinger/layerproto/display.proto
index c8cd926..64de775 100644
--- a/services/surfaceflinger/layerproto/display.proto
+++ b/services/surfaceflinger/layerproto/display.proto
@@ -35,4 +35,8 @@
TransformProto transform = 6;
bool is_virtual = 7;
+
+ double dpi_x = 8;
+
+ double dpi_y = 9;
}
diff --git a/services/surfaceflinger/tests/unittests/MessageQueueTest.cpp b/services/surfaceflinger/tests/unittests/MessageQueueTest.cpp
index 1dcf222..9aa089f 100644
--- a/services/surfaceflinger/tests/unittests/MessageQueueTest.cpp
+++ b/services/surfaceflinger/tests/unittests/MessageQueueTest.cpp
@@ -35,7 +35,7 @@
struct NoOpCompositor final : ICompositor {
void configure() override {}
- bool commit(const scheduler::FrameTarget&) override { return false; }
+ bool commit(PhysicalDisplayId, const scheduler::FrameTargets&) override { return false; }
CompositeResultsPerDisplay composite(PhysicalDisplayId,
const scheduler::FrameTargeters&) override {
return {};
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp
index 703bdda..24eb318 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp
@@ -67,10 +67,36 @@
.WillByDefault(Return(true));
}
+ static constexpr HWDisplayId kInnerDisplayHwcId = PrimaryDisplayVariant::HWC_DISPLAY_ID;
+ static constexpr HWDisplayId kOuterDisplayHwcId = kInnerDisplayHwcId + 1;
+
+ auto injectOuterDisplay() {
+ constexpr PhysicalDisplayId kOuterDisplayId = PhysicalDisplayId::fromPort(254u);
+
+ constexpr bool kIsPrimary = false;
+ TestableSurfaceFlinger::FakeHwcDisplayInjector(kOuterDisplayId, hal::DisplayType::PHYSICAL,
+ kIsPrimary)
+ .setHwcDisplayId(kOuterDisplayHwcId)
+ .setPowerMode(hal::PowerMode::OFF)
+ .inject(&mFlinger, mComposer);
+
+ mOuterDisplay = mFakeDisplayInjector.injectInternalDisplay(
+ [&](FakeDisplayDeviceInjector& injector) {
+ injector.setPowerMode(hal::PowerMode::OFF);
+ injector.setDisplayModes(mock::cloneForDisplay(kOuterDisplayId, kModes),
+ kModeId120);
+ },
+ {.displayId = kOuterDisplayId,
+ .hwcDisplayId = kOuterDisplayHwcId,
+ .isPrimary = kIsPrimary});
+
+ return std::forward_as_tuple(mDisplay, mOuterDisplay);
+ }
+
protected:
void setupScheduler(std::shared_ptr<scheduler::RefreshRateSelector>);
- sp<DisplayDevice> mDisplay;
+ sp<DisplayDevice> mDisplay, mOuterDisplay;
mock::EventThread* mAppEventThread;
static constexpr DisplayModeId kModeId60{0};
@@ -328,32 +354,16 @@
return true;
}
-TEST_F(DisplayModeSwitchingTest, multiDisplay) {
- constexpr HWDisplayId kInnerDisplayHwcId = PrimaryDisplayVariant::HWC_DISPLAY_ID;
- constexpr HWDisplayId kOuterDisplayHwcId = kInnerDisplayHwcId + 1;
+TEST_F(DisplayModeSwitchingTest, innerXorOuterDisplay) {
+ const auto [innerDisplay, outerDisplay] = injectOuterDisplay();
- constexpr PhysicalDisplayId kOuterDisplayId = PhysicalDisplayId::fromPort(254u);
-
- constexpr bool kIsPrimary = false;
- TestableSurfaceFlinger::FakeHwcDisplayInjector(kOuterDisplayId, hal::DisplayType::PHYSICAL,
- kIsPrimary)
- .setHwcDisplayId(kOuterDisplayHwcId)
- .inject(&mFlinger, mComposer);
-
- const auto outerDisplay = mFakeDisplayInjector.injectInternalDisplay(
- [&](FakeDisplayDeviceInjector& injector) {
- injector.setDisplayModes(mock::cloneForDisplay(kOuterDisplayId, kModes),
- kModeId120);
- },
- {.displayId = kOuterDisplayId,
- .hwcDisplayId = kOuterDisplayHwcId,
- .isPrimary = kIsPrimary});
-
- const auto& innerDisplay = mDisplay;
+ EXPECT_TRUE(innerDisplay->isPoweredOn());
+ EXPECT_FALSE(outerDisplay->isPoweredOn());
EXPECT_THAT(innerDisplay, ModeSettledTo(kModeId60));
EXPECT_THAT(outerDisplay, ModeSettledTo(kModeId120));
+ // Only the inner display is powered on.
mFlinger.onActiveDisplayChanged(nullptr, *innerDisplay);
EXPECT_THAT(innerDisplay, ModeSettledTo(kModeId60));
@@ -388,6 +398,10 @@
EXPECT_THAT(innerDisplay, ModeSettledTo(kModeId90));
EXPECT_THAT(outerDisplay, ModeSettledTo(kModeId120));
+ innerDisplay->setPowerMode(hal::PowerMode::OFF);
+ outerDisplay->setPowerMode(hal::PowerMode::ON);
+
+ // Only the outer display is powered on.
mFlinger.onActiveDisplayChanged(innerDisplay.get(), *outerDisplay);
EXPECT_THAT(innerDisplay, ModeSettledTo(kModeId90));
@@ -409,5 +423,107 @@
EXPECT_THAT(outerDisplay, ModeSettledTo(kModeId60));
}
+TEST_F(DisplayModeSwitchingTest, innerAndOuterDisplay) {
+ const auto [innerDisplay, outerDisplay] = injectOuterDisplay();
+
+ EXPECT_TRUE(innerDisplay->isPoweredOn());
+ EXPECT_FALSE(outerDisplay->isPoweredOn());
+
+ EXPECT_THAT(innerDisplay, ModeSettledTo(kModeId60));
+ EXPECT_THAT(outerDisplay, ModeSettledTo(kModeId120));
+
+ outerDisplay->setPowerMode(hal::PowerMode::ON);
+
+ // Both displays are powered on.
+ mFlinger.onActiveDisplayChanged(nullptr, *innerDisplay);
+
+ EXPECT_THAT(innerDisplay, ModeSettledTo(kModeId60));
+ EXPECT_THAT(outerDisplay, ModeSettledTo(kModeId120));
+
+ EXPECT_EQ(NO_ERROR,
+ mFlinger.setDesiredDisplayModeSpecs(innerDisplay->getDisplayToken().promote(),
+ mock::createDisplayModeSpecs(kModeId90.value(),
+ false, 0.f, 120.f)));
+
+ EXPECT_EQ(NO_ERROR,
+ mFlinger.setDesiredDisplayModeSpecs(outerDisplay->getDisplayToken().promote(),
+ mock::createDisplayModeSpecs(kModeId60.value(),
+ false, 0.f, 120.f)));
+
+ EXPECT_THAT(innerDisplay, ModeSwitchingTo(&mFlinger, kModeId90));
+ EXPECT_THAT(outerDisplay, ModeSwitchingTo(&mFlinger, kModeId60));
+
+ const VsyncPeriodChangeTimeline timeline{.refreshRequired = true};
+ EXPECT_CALL(*mComposer,
+ setActiveConfigWithConstraints(kInnerDisplayHwcId,
+ hal::HWConfigId(kModeId90.value()), _, _))
+ .WillOnce(DoAll(SetArgPointee<3>(timeline), Return(Error::NONE)));
+
+ EXPECT_CALL(*mComposer,
+ setActiveConfigWithConstraints(kOuterDisplayHwcId,
+ hal::HWConfigId(kModeId60.value()), _, _))
+ .WillOnce(DoAll(SetArgPointee<3>(timeline), Return(Error::NONE)));
+
+ mFlinger.commit();
+
+ EXPECT_THAT(innerDisplay, ModeSwitchingTo(&mFlinger, kModeId90));
+ EXPECT_THAT(outerDisplay, ModeSwitchingTo(&mFlinger, kModeId60));
+
+ mFlinger.commit();
+
+ EXPECT_THAT(innerDisplay, ModeSettledTo(kModeId90));
+ EXPECT_THAT(outerDisplay, ModeSettledTo(kModeId60));
+}
+
+TEST_F(DisplayModeSwitchingTest, powerOffDuringModeSet) {
+ const auto [innerDisplay, outerDisplay] = injectOuterDisplay();
+
+ EXPECT_TRUE(innerDisplay->isPoweredOn());
+ EXPECT_FALSE(outerDisplay->isPoweredOn());
+
+ EXPECT_THAT(innerDisplay, ModeSettledTo(kModeId60));
+ EXPECT_THAT(outerDisplay, ModeSettledTo(kModeId120));
+
+ outerDisplay->setPowerMode(hal::PowerMode::ON);
+
+ // Both displays are powered on.
+ mFlinger.onActiveDisplayChanged(nullptr, *innerDisplay);
+
+ EXPECT_THAT(innerDisplay, ModeSettledTo(kModeId60));
+ EXPECT_THAT(outerDisplay, ModeSettledTo(kModeId120));
+
+ EXPECT_EQ(NO_ERROR,
+ mFlinger.setDesiredDisplayModeSpecs(innerDisplay->getDisplayToken().promote(),
+ mock::createDisplayModeSpecs(kModeId90.value(),
+ false, 0.f, 120.f)));
+
+ EXPECT_EQ(NO_ERROR,
+ mFlinger.setDesiredDisplayModeSpecs(outerDisplay->getDisplayToken().promote(),
+ mock::createDisplayModeSpecs(kModeId60.value(),
+ false, 0.f, 120.f)));
+
+ EXPECT_THAT(innerDisplay, ModeSwitchingTo(&mFlinger, kModeId90));
+ EXPECT_THAT(outerDisplay, ModeSwitchingTo(&mFlinger, kModeId60));
+
+ // Power off the outer display before the mode has been set.
+ outerDisplay->setPowerMode(hal::PowerMode::OFF);
+
+ const VsyncPeriodChangeTimeline timeline{.refreshRequired = true};
+ EXPECT_CALL(*mComposer,
+ setActiveConfigWithConstraints(kInnerDisplayHwcId,
+ hal::HWConfigId(kModeId90.value()), _, _))
+ .WillOnce(DoAll(SetArgPointee<3>(timeline), Return(Error::NONE)));
+
+ mFlinger.commit();
+
+ EXPECT_THAT(innerDisplay, ModeSwitchingTo(&mFlinger, kModeId90));
+ EXPECT_THAT(outerDisplay, ModeSettledTo(kModeId120));
+
+ mFlinger.commit();
+
+ EXPECT_THAT(innerDisplay, ModeSettledTo(kModeId90));
+ EXPECT_THAT(outerDisplay, ModeSettledTo(kModeId120));
+}
+
} // namespace
} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/TestableScheduler.h b/services/surfaceflinger/tests/unittests/TestableScheduler.h
index f3c9d0d..151b178 100644
--- a/services/surfaceflinger/tests/unittests/TestableScheduler.h
+++ b/services/surfaceflinger/tests/unittests/TestableScheduler.h
@@ -180,7 +180,7 @@
private:
// ICompositor overrides:
void configure() override {}
- bool commit(const scheduler::FrameTarget&) override { return false; }
+ bool commit(PhysicalDisplayId, const scheduler::FrameTargets&) override { return false; }
CompositeResultsPerDisplay composite(PhysicalDisplayId,
const scheduler::FrameTargeters&) override {
return {};
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index 9b3a893..e59d44d 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -386,10 +386,19 @@
.sfWorkDuration = 10ms},
*mScheduler->getVsyncSchedule());
- mFlinger->commit(frameTargeter.target());
+ scheduler::FrameTargets targets;
+ scheduler::FrameTargeters targeters;
+
+ for (const auto& [id, display] :
+ FTL_FAKE_GUARD(mFlinger->mStateLock, mFlinger->mPhysicalDisplays)) {
+ targets.try_emplace(id, &frameTargeter.target());
+ targeters.try_emplace(id, &frameTargeter);
+ }
+
+ mFlinger->commit(displayId, targets);
if (composite) {
- mFlinger->composite(displayId, ftl::init::map(displayId, &frameTargeter));
+ mFlinger->composite(displayId, targeters);
}
}