Merge "Add sleep to ShouldReportStats Test in libinput_tests"
diff --git a/cmds/dumpstate/Android.bp b/cmds/dumpstate/Android.bp
index 8d383f5..93bbe90 100644
--- a/cmds/dumpstate/Android.bp
+++ b/cmds/dumpstate/Android.bp
@@ -93,7 +93,6 @@
"libutils",
],
srcs: [
- "DumpstateSectionReporter.cpp",
"DumpstateService.cpp",
],
static_libs: [
diff --git a/cmds/dumpstate/DumpstateSectionReporter.cpp b/cmds/dumpstate/DumpstateSectionReporter.cpp
deleted file mode 100644
index f814bde..0000000
--- a/cmds/dumpstate/DumpstateSectionReporter.cpp
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "dumpstate"
-
-#include "DumpstateSectionReporter.h"
-
-namespace android {
-namespace os {
-namespace dumpstate {
-
-DumpstateSectionReporter::DumpstateSectionReporter(const std::string& title,
- sp<android::os::IDumpstateListener> listener,
- bool sendReport)
- : title_(title), listener_(listener), sendReport_(sendReport), status_(OK), size_(-1) {
- started_ = std::chrono::steady_clock::now();
-}
-
-DumpstateSectionReporter::~DumpstateSectionReporter() {
- if ((listener_ != nullptr) && (sendReport_)) {
- auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(
- std::chrono::steady_clock::now() - started_);
- listener_->onSectionComplete(title_, status_, size_, (int32_t)elapsed.count());
- }
-}
-
-} // namespace dumpstate
-} // namespace os
-} // namespace android
diff --git a/cmds/dumpstate/DumpstateSectionReporter.h b/cmds/dumpstate/DumpstateSectionReporter.h
deleted file mode 100644
index e971de8..0000000
--- a/cmds/dumpstate/DumpstateSectionReporter.h
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_OS_DUMPSTATESECTIONREPORTER_H_
-#define ANDROID_OS_DUMPSTATESECTIONREPORTER_H_
-
-#include <android/os/IDumpstateListener.h>
-#include <utils/StrongPointer.h>
-
-namespace android {
-namespace os {
-namespace dumpstate {
-
-
-/*
- * Helper class used to report per section details to a listener.
- *
- * Typical usage:
- *
- * DumpstateSectionReporter sectionReporter(title, listener, sendReport);
- * sectionReporter.setSize(5000);
- *
- */
-class DumpstateSectionReporter {
- public:
- DumpstateSectionReporter(const std::string& title, sp<android::os::IDumpstateListener> listener,
- bool sendReport);
-
- ~DumpstateSectionReporter();
-
- void setStatus(status_t status) {
- status_ = status;
- }
-
- void setSize(int size) {
- size_ = size;
- }
-
- private:
- std::string title_;
- android::sp<android::os::IDumpstateListener> listener_;
- bool sendReport_;
- status_t status_;
- int size_;
- std::chrono::time_point<std::chrono::steady_clock> started_;
-};
-
-} // namespace dumpstate
-} // namespace os
-} // namespace android
-
-#endif // ANDROID_OS_DUMPSTATESECTIONREPORTER_H_
diff --git a/cmds/dumpstate/DumpstateService.cpp b/cmds/dumpstate/DumpstateService.cpp
index 37ba4f9..f98df99 100644
--- a/cmds/dumpstate/DumpstateService.cpp
+++ b/cmds/dumpstate/DumpstateService.cpp
@@ -200,8 +200,7 @@
dprintf(fd, "id: %d\n", ds_->id_);
dprintf(fd, "pid: %d\n", ds_->pid_);
dprintf(fd, "update_progress: %s\n", ds_->options_->do_progress_updates ? "true" : "false");
- dprintf(fd, "update_progress_threshold: %d\n", ds_->update_progress_threshold_);
- dprintf(fd, "last_updated_progress: %d\n", ds_->last_updated_progress_);
+ dprintf(fd, "last_percent_progress: %d\n", ds_->last_reported_percent_progress_);
dprintf(fd, "progress:\n");
ds_->progress_->Dump(fd, " ");
dprintf(fd, "args: %s\n", ds_->options_->args.c_str());
diff --git a/cmds/dumpstate/binder/android/os/IDumpstateListener.aidl b/cmds/dumpstate/binder/android/os/IDumpstateListener.aidl
index ea1e467..e486460 100644
--- a/cmds/dumpstate/binder/android/os/IDumpstateListener.aidl
+++ b/cmds/dumpstate/binder/android/os/IDumpstateListener.aidl
@@ -61,21 +61,4 @@
* Called when taking bugreport finishes successfully.
*/
void onFinished();
-
- // TODO(b/111441001): Remove old methods when not used anymore.
- void onProgressUpdated(int progress);
- void onMaxProgressUpdated(int maxProgress);
-
- /**
- * Called after every section is complete.
- *
- * @param name section name
- * @param status values from status_t
- * {@code OK} section completed successfully
- * {@code TIMEOUT} dump timed out
- * {@code != OK} error
- * @param size size in bytes, may be invalid if status != OK
- * @param durationMs duration in ms
- */
- void onSectionComplete(@utf8InCpp String name, int status, int size, int durationMs);
}
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 1416629..3a0aa95 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -80,7 +80,6 @@
#include <serviceutils/PriorityDumper.h>
#include <utils/StrongPointer.h>
#include "DumpstateInternal.h"
-#include "DumpstateSectionReporter.h"
#include "DumpstateService.h"
#include "dumpstate.h"
@@ -105,7 +104,6 @@
using android::os::IDumpstateListener;
using android::os::dumpstate::CommandOptions;
using android::os::dumpstate::DumpFileToFd;
-using android::os::dumpstate::DumpstateSectionReporter;
using android::os::dumpstate::PropertiesHelper;
// Keep in sync with
@@ -1047,7 +1045,6 @@
RETURN_IF_USER_DENIED_CONSENT();
std::string path(title);
path.append(" - ").append(String8(service).c_str());
- DumpstateSectionReporter section_reporter(path, ds.listener_, ds.report_section_);
size_t bytes_written = 0;
status_t status = dumpsys.startDumpThread(service, args);
if (status == OK) {
@@ -1055,12 +1052,10 @@
std::chrono::duration<double> elapsed_seconds;
status = dumpsys.writeDump(STDOUT_FILENO, service, service_timeout,
/* as_proto = */ false, elapsed_seconds, bytes_written);
- section_reporter.setSize(bytes_written);
dumpsys.writeDumpFooter(STDOUT_FILENO, service, elapsed_seconds);
bool dump_complete = (status == OK);
dumpsys.stopDumpThread(dump_complete);
}
- section_reporter.setStatus(status);
auto elapsed_duration = std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::steady_clock::now() - start);
@@ -1123,7 +1118,6 @@
path.append("_HIGH");
}
path.append(kProtoExt);
- DumpstateSectionReporter section_reporter(path, ds.listener_, ds.report_section_);
status_t status = dumpsys.startDumpThread(service, args);
if (status == OK) {
status = ds.AddZipEntryFromFd(path, dumpsys.getDumpFd(), service_timeout);
@@ -1132,8 +1126,6 @@
}
ZipWriter::FileEntry file_entry;
ds.zip_writer_->GetLastEntry(&file_entry);
- section_reporter.setSize(file_entry.compressed_size);
- section_reporter.setStatus(status);
auto elapsed_duration = std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::steady_clock::now() - start);
@@ -1270,7 +1262,6 @@
DumpFile("KERNEL WAKE SOURCES", "/d/wakeup_sources");
DumpFile("KERNEL CPUFREQ", "/sys/devices/system/cpu/cpu0/cpufreq/stats/time_in_state");
- DumpFile("KERNEL SYNC", "/d/sync");
RunCommand("PROCESSES AND THREADS",
{"ps", "-A", "-T", "-Z", "-O", "pri,nice,rtprio,sched,pcy,time"});
@@ -1989,12 +1980,12 @@
}
if (ds.options_->do_fb) {
- ds.screenshot_path_ = ds.GetPath(".png");
+ ds.screenshot_path_ = ds.GetPath(ds.CalledByApi() ? "-tmp.png" : ".png");
}
ds.tmp_path_ = ds.GetPath(".tmp");
ds.log_path_ = ds.GetPath("-dumpstate_log-" + std::to_string(ds.pid_) + ".txt");
- std::string destination = ds.options_->bugreport_fd.get() != -1
+ std::string destination = ds.CalledByApi()
? StringPrintf("[fd:%d]", ds.options_->bugreport_fd.get())
: ds.bugreport_internal_dir_.c_str();
MYLOGD(
@@ -2008,7 +1999,7 @@
ds.tmp_path_.c_str(), ds.screenshot_path_.c_str());
if (ds.options_->do_zip_file) {
- ds.path_ = ds.GetPath(".zip");
+ ds.path_ = ds.GetPath(ds.CalledByApi() ? "-tmp.zip" : ".zip");
MYLOGD("Creating initial .zip file (%s)\n", ds.path_.c_str());
create_parent_dirs(ds.path_.c_str());
ds.zip_file.reset(fopen(ds.path_.c_str(), "wb"));
@@ -2043,7 +2034,7 @@
MYLOGI("changing suffix from %s to %s\n", ds.name_.c_str(), name.c_str());
ds.name_ = name;
if (!ds.screenshot_path_.empty()) {
- std::string new_screenshot_path = ds.GetPath(".png");
+ std::string new_screenshot_path = ds.GetPath(ds.CalledByApi() ? "-tmp.png" : ".png");
if (rename(ds.screenshot_path_.c_str(), new_screenshot_path.c_str())) {
MYLOGE("rename(%s, %s): %s\n", ds.screenshot_path_.c_str(),
new_screenshot_path.c_str(), strerror(errno));
@@ -2061,7 +2052,7 @@
} else {
do_text_file = false;
// If the user has changed the suffix, we need to change the zip file name.
- std::string new_path = ds.GetPath(".zip");
+ std::string new_path = ds.GetPath(ds.CalledByApi() ? "-tmp.zip" : ".zip");
if (ds.path_ != new_path) {
MYLOGD("Renaming zip file from %s to %s\n", ds.path_.c_str(), new_path.c_str());
if (rename(ds.path_.c_str(), new_path.c_str())) {
@@ -2608,7 +2599,7 @@
// Dump state for the default case. This also drops root.
RunStatus s = DumpstateDefault();
if (s != RunStatus::OK) {
- if (s == RunStatus::USER_CONSENT_TIMED_OUT) {
+ if (s == RunStatus::USER_CONSENT_DENIED) {
HandleUserConsentDenied();
}
return s;
@@ -2716,6 +2707,10 @@
ds.consent_callback_->getResult() == UserConsentResult::DENIED;
}
+bool Dumpstate::CalledByApi() const {
+ return ds.options_->bugreport_fd.get() != -1 ? true : false;
+}
+
void Dumpstate::CleanupFiles() {
android::os::UnlinkAndLogOnError(tmp_path_);
android::os::UnlinkAndLogOnError(screenshot_path_);
@@ -2809,6 +2804,7 @@
Dumpstate::Dumpstate(const std::string& version)
: pid_(getpid()),
options_(new Dumpstate::DumpOptions()),
+ last_reported_percent_progress_(0),
version_(version),
now_(time(nullptr)) {
}
@@ -3571,31 +3567,25 @@
}
// Always update progess so stats can be tuned...
- bool max_changed = progress_->Inc(delta_sec);
+ progress_->Inc(delta_sec);
// ...but only notifiy listeners when necessary.
if (!options_->do_progress_updates) return;
int progress = progress_->Get();
int max = progress_->GetMax();
+ int percent = 100 * progress / max;
- // adjusts max on the fly
- if (max_changed && listener_ != nullptr) {
- listener_->onMaxProgressUpdated(max);
- }
-
- int32_t last_update_delta = progress - last_updated_progress_;
- if (last_updated_progress_ > 0 && last_update_delta < update_progress_threshold_) {
+ if (last_reported_percent_progress_ > 0 && percent <= last_reported_percent_progress_) {
return;
}
- last_updated_progress_ = progress;
+ last_reported_percent_progress_ = percent;
if (control_socket_fd_ >= 0) {
dprintf(control_socket_fd_, "PROGRESS:%d/%d\n", progress, max);
fsync(control_socket_fd_);
}
- int percent = 100 * progress / max;
if (listener_ != nullptr) {
if (percent % 5 == 0) {
// We don't want to spam logcat, so only log multiples of 5.
@@ -3607,8 +3597,6 @@
fprintf(stderr, "Setting progress (%s): %d/%d (%d%%)\n", listener_name_.c_str(),
progress, max, percent);
}
- // TODO(b/111441001): Remove in favor of onProgress
- listener_->onProgressUpdated(progress);
listener_->onProgress(percent);
}
diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h
index ae6a721..77b5e8a 100644
--- a/cmds/dumpstate/dumpstate.h
+++ b/cmds/dumpstate/dumpstate.h
@@ -341,6 +341,11 @@
bool IsUserConsentDenied() const;
/*
+ * Returns true if dumpstate is called by bugreporting API
+ */
+ bool CalledByApi() const;
+
+ /*
* Structure to hold options that determine the behavior of dumpstate.
*/
struct DumpOptions {
@@ -400,12 +405,8 @@
// Runtime options.
std::unique_ptr<DumpOptions> options_;
- // How frequently the progess should be updated;the listener will only be notificated when the
- // delta from the previous update is more than the threshold.
- int32_t update_progress_threshold_ = 100;
-
- // Last progress that triggered a listener updated
- int32_t last_updated_progress_;
+ // Last progress that was sent to the listener [0-100].
+ int last_reported_percent_progress_ = 0;
// Whether it should take an screenshot earlier in the process.
bool do_early_screenshot_ = false;
diff --git a/cmds/dumpstate/tests/dumpstate_smoke_test.cpp b/cmds/dumpstate/tests/dumpstate_smoke_test.cpp
index 5bde7db..181046a 100644
--- a/cmds/dumpstate/tests/dumpstate_smoke_test.cpp
+++ b/cmds/dumpstate/tests/dumpstate_smoke_test.cpp
@@ -14,20 +14,21 @@
* limitations under the License.
*/
-#include <gmock/gmock.h>
-#include <gtest/gtest.h>
-
-#include <fcntl.h>
-#include <libgen.h>
-
#include <android-base/file.h>
#include <android/os/BnDumpstate.h>
#include <android/os/BnDumpstateListener.h>
#include <binder/IServiceManager.h>
#include <binder/ProcessState.h>
#include <cutils/properties.h>
+#include <fcntl.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <libgen.h>
#include <ziparchive/zip_archive.h>
+#include <fstream>
+#include <regex>
+
#include "dumpstate.h"
#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
@@ -44,6 +45,11 @@
namespace {
+struct SectionInfo {
+ std::string name;
+ int32_t size_bytes;
+};
+
sp<IDumpstate> GetDumpstateService() {
return android::interface_cast<IDumpstate>(
android::defaultServiceManager()->getService(String16("dumpstate")));
@@ -55,14 +61,79 @@
S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH));
}
-} // namespace
+void GetEntry(const ZipArchiveHandle archive, const std::string_view entry_name, ZipEntry* data) {
+ int32_t e = FindEntry(archive, entry_name, data);
+ EXPECT_EQ(e, 0) << ErrorCodeString(e) << " entry name: " << entry_name;
+}
-struct SectionInfo {
- std::string name;
- status_t status;
- int32_t size_bytes;
- int32_t duration_ms;
-};
+// Extracts the main bugreport txt from the given archive and writes into output_fd.
+void ExtractBugreport(const ZipArchiveHandle* handle, int output_fd) {
+ // Read contents of main_entry.txt which is a single line indicating the name of the zip entry
+ // that contains the main bugreport txt.
+ ZipEntry main_entry;
+ GetEntry(*handle, "main_entry.txt", &main_entry);
+ std::string bugreport_txt_name;
+ bugreport_txt_name.resize(main_entry.uncompressed_length);
+ ExtractToMemory(*handle, &main_entry, reinterpret_cast<uint8_t*>(bugreport_txt_name.data()),
+ main_entry.uncompressed_length);
+
+ // Read the main bugreport txt and extract to output_fd.
+ ZipEntry entry;
+ GetEntry(*handle, bugreport_txt_name, &entry);
+ ExtractEntryToFile(*handle, &entry, output_fd);
+}
+
+bool IsSectionStart(const std::string& line, std::string* section_name) {
+ static const std::regex kSectionStart = std::regex{"DUMP OF SERVICE (.*):"};
+ std::smatch match;
+ if (std::regex_match(line, match, kSectionStart)) {
+ *section_name = match.str(1);
+ return true;
+ }
+ return false;
+}
+
+bool IsSectionEnd(const std::string& line) {
+ // Not all lines that contain "was the duration of" is a section end, but all section ends do
+ // contain "was the duration of". The disambiguation can be done by the caller.
+ return (line.find("was the duration of") != std::string::npos);
+}
+
+// Extracts the zipped bugreport and identifies the sections.
+void ParseSections(const std::string& zip_path, std::vector<SectionInfo>* sections) {
+ // Open the archive
+ ZipArchiveHandle handle;
+ ASSERT_EQ(OpenArchive(zip_path.c_str(), &handle), 0);
+
+ // Extract the main entry to a temp file
+ TemporaryFile tmp_binary;
+ ASSERT_NE(-1, tmp_binary.fd);
+ ExtractBugreport(&handle, tmp_binary.fd);
+
+ // Read line by line and identify sections
+ std::ifstream ifs(tmp_binary.path, std::ifstream::in);
+ std::string line;
+ int section_bytes = 0;
+ std::string current_section_name;
+ while (std::getline(ifs, line)) {
+ std::string section_name;
+ if (IsSectionStart(line, §ion_name)) {
+ section_bytes = 0;
+ current_section_name = section_name;
+ } else if (IsSectionEnd(line)) {
+ if (!current_section_name.empty()) {
+ sections->push_back({current_section_name, section_bytes});
+ }
+ current_section_name = "";
+ } else if (!current_section_name.empty()) {
+ section_bytes += line.length();
+ }
+ }
+
+ CloseArchive(handle);
+}
+
+} // namespace
/**
* Listens to bugreport progress and updates the user by writing the progress to STDOUT. All the
@@ -96,26 +167,6 @@
return binder::Status::ok();
}
- binder::Status onProgressUpdated(int32_t progress) override {
- dprintf(out_fd_, "\rIn progress %d/%d", progress, max_progress_);
- return binder::Status::ok();
- }
-
- binder::Status onMaxProgressUpdated(int32_t max_progress) override {
- std::lock_guard<std::mutex> lock(lock_);
- max_progress_ = max_progress;
- return binder::Status::ok();
- }
-
- binder::Status onSectionComplete(const ::std::string& name, int32_t status, int32_t size_bytes,
- int32_t duration_ms) override {
- std::lock_guard<std::mutex> lock(lock_);
- if (sections_.get() != nullptr) {
- sections_->push_back({name, status, size_bytes, duration_ms});
- }
- return binder::Status::ok();
- }
-
bool getIsFinished() {
std::lock_guard<std::mutex> lock(lock_);
return is_finished_;
@@ -128,7 +179,6 @@
private:
int out_fd_;
- int max_progress_ = 5000;
int error_code_ = -1;
bool is_finished_ = false;
std::shared_ptr<std::vector<SectionInfo>> sections_;
@@ -208,29 +258,30 @@
void FileExists(const char* filename, uint32_t minsize, uint32_t maxsize) {
ZipEntry entry;
- EXPECT_EQ(FindEntry(handle, filename, &entry), 0);
+ GetEntry(handle, filename, &entry);
EXPECT_GT(entry.uncompressed_length, minsize);
EXPECT_LT(entry.uncompressed_length, maxsize);
}
};
TEST_F(ZippedBugReportContentsTest, ContainsMainEntry) {
- ZipEntry mainEntryLoc;
+ ZipEntry main_entry;
// contains main entry name file
- EXPECT_EQ(FindEntry(handle, "main_entry.txt", &mainEntryLoc), 0);
+ GetEntry(handle, "main_entry.txt", &main_entry);
- char* buf = new char[mainEntryLoc.uncompressed_length];
- ExtractToMemory(handle, &mainEntryLoc, (uint8_t*)buf, mainEntryLoc.uncompressed_length);
- delete[] buf;
+ std::string bugreport_txt_name;
+ bugreport_txt_name.resize(main_entry.uncompressed_length);
+ ExtractToMemory(handle, &main_entry, reinterpret_cast<uint8_t*>(bugreport_txt_name.data()),
+ main_entry.uncompressed_length);
// contains main entry file
- FileExists(buf, 1000000U, 50000000U);
+ FileExists(bugreport_txt_name.c_str(), 1000000U, 50000000U);
}
TEST_F(ZippedBugReportContentsTest, ContainsVersion) {
ZipEntry entry;
// contains main entry name file
- EXPECT_EQ(FindEntry(handle, "version.txt", &entry), 0);
+ GetEntry(handle, "version.txt", &entry);
char* buf = new char[entry.uncompressed_length + 1];
ExtractToMemory(handle, &entry, (uint8_t*)buf, entry.uncompressed_length);
@@ -244,6 +295,10 @@
FileExists("dumpstate_board.txt", 100000U, 1000000U);
}
+TEST_F(ZippedBugReportContentsTest, ContainsProtoFile) {
+ FileExists("proto/activity.proto", 100000U, 1000000U);
+}
+
// Spot check on some files pulled from the file system
TEST_F(ZippedBugReportContentsTest, ContainsSomeFileSystemFiles) {
// FS/proc/*/mountinfo size > 0
@@ -258,6 +313,11 @@
*/
class BugreportSectionTest : public Test {
public:
+ static void SetUpTestCase() {
+ ParseSections(ZippedBugreportGenerationTest::getZipFilePath(),
+ ZippedBugreportGenerationTest::sections.get());
+ }
+
int numMatches(const std::string& substring) {
int matches = 0;
for (auto const& section : *ZippedBugreportGenerationTest::sections) {
@@ -267,10 +327,11 @@
}
return matches;
}
+
void SectionExists(const std::string& sectionName, int minsize) {
for (auto const& section : *ZippedBugreportGenerationTest::sections) {
if (sectionName == section.name) {
- EXPECT_GE(section.size_bytes, minsize);
+ EXPECT_GE(section.size_bytes, minsize) << " for section:" << sectionName;
return;
}
}
@@ -278,71 +339,59 @@
}
};
-// Test all sections are generated without timeouts or errors
-TEST_F(BugreportSectionTest, GeneratedWithoutErrors) {
- for (auto const& section : *ZippedBugreportGenerationTest::sections) {
- EXPECT_EQ(section.status, 0) << section.name << " failed with status " << section.status;
- }
-}
-
TEST_F(BugreportSectionTest, Atleast3CriticalDumpsysSectionsGenerated) {
- int numSections = numMatches("DUMPSYS CRITICAL");
+ int numSections = numMatches("CRITICAL");
EXPECT_GE(numSections, 3);
}
TEST_F(BugreportSectionTest, Atleast2HighDumpsysSectionsGenerated) {
- int numSections = numMatches("DUMPSYS HIGH");
+ int numSections = numMatches("HIGH");
EXPECT_GE(numSections, 2);
}
TEST_F(BugreportSectionTest, Atleast50NormalDumpsysSectionsGenerated) {
- int allSections = numMatches("DUMPSYS");
- int criticalSections = numMatches("DUMPSYS CRITICAL");
- int highSections = numMatches("DUMPSYS HIGH");
+ int allSections = ZippedBugreportGenerationTest::sections->size();
+ int criticalSections = numMatches("CRITICAL");
+ int highSections = numMatches("HIGH");
int normalSections = allSections - criticalSections - highSections;
EXPECT_GE(normalSections, 50) << "Total sections less than 50 (Critical:" << criticalSections
<< "High:" << highSections << "Normal:" << normalSections << ")";
}
-TEST_F(BugreportSectionTest, Atleast1ProtoDumpsysSectionGenerated) {
- int numSections = numMatches("proto/");
- EXPECT_GE(numSections, 1);
-}
-
// Test if some critical sections are being generated.
TEST_F(BugreportSectionTest, CriticalSurfaceFlingerSectionGenerated) {
- SectionExists("DUMPSYS CRITICAL - SurfaceFlinger", /* bytes= */ 10000);
+ SectionExists("CRITICAL SurfaceFlinger", /* bytes= */ 10000);
}
TEST_F(BugreportSectionTest, ActivitySectionsGenerated) {
- SectionExists("DUMPSYS CRITICAL - activity", /* bytes= */ 5000);
- SectionExists("DUMPSYS - activity", /* bytes= */ 10000);
+ SectionExists("CRITICAL activity", /* bytes= */ 5000);
+ SectionExists("activity", /* bytes= */ 10000);
}
TEST_F(BugreportSectionTest, CpuinfoSectionGenerated) {
- SectionExists("DUMPSYS CRITICAL - cpuinfo", /* bytes= */ 1000);
+ SectionExists("CRITICAL cpuinfo", /* bytes= */ 1000);
}
TEST_F(BugreportSectionTest, WindowSectionGenerated) {
- SectionExists("DUMPSYS CRITICAL - window", /* bytes= */ 20000);
+ SectionExists("CRITICAL window", /* bytes= */ 20000);
}
TEST_F(BugreportSectionTest, ConnectivitySectionsGenerated) {
- SectionExists("DUMPSYS HIGH - connectivity", /* bytes= */ 5000);
- SectionExists("DUMPSYS - connectivity", /* bytes= */ 5000);
+ SectionExists("HIGH connectivity", /* bytes= */ 3000);
+ SectionExists("connectivity", /* bytes= */ 5000);
}
TEST_F(BugreportSectionTest, MeminfoSectionGenerated) {
- SectionExists("DUMPSYS HIGH - meminfo", /* bytes= */ 100000);
+ SectionExists("HIGH meminfo", /* bytes= */ 100000);
}
TEST_F(BugreportSectionTest, BatteryStatsSectionGenerated) {
- SectionExists("DUMPSYS - batterystats", /* bytes= */ 1000);
+ SectionExists("batterystats", /* bytes= */ 1000);
}
TEST_F(BugreportSectionTest, WifiSectionGenerated) {
- SectionExists("DUMPSYS - wifi", /* bytes= */ 100000);
+ SectionExists("wifi", /* bytes= */ 100000);
}
class DumpstateBinderTest : public Test {
diff --git a/cmds/dumpstate/tests/dumpstate_test.cpp b/cmds/dumpstate/tests/dumpstate_test.cpp
index 4e6b084..cff1d43 100644
--- a/cmds/dumpstate/tests/dumpstate_test.cpp
+++ b/cmds/dumpstate/tests/dumpstate_test.cpp
@@ -62,10 +62,6 @@
MOCK_METHOD1(onProgress, binder::Status(int32_t progress));
MOCK_METHOD1(onError, binder::Status(int32_t error_code));
MOCK_METHOD0(onFinished, binder::Status());
- MOCK_METHOD1(onProgressUpdated, binder::Status(int32_t progress));
- MOCK_METHOD1(onMaxProgressUpdated, binder::Status(int32_t max_progress));
- MOCK_METHOD4(onSectionComplete, binder::Status(const ::std::string& name, int32_t status,
- int32_t size, int32_t durationMs));
protected:
MOCK_METHOD0(onAsBinder, IBinder*());
@@ -590,7 +586,6 @@
SetDryRun(false);
SetBuildType(android::base::GetProperty("ro.build.type", "(unknown)"));
ds.progress_.reset(new Progress());
- ds.update_progress_threshold_ = 0;
ds.options_.reset(new Dumpstate::DumpOptions());
}
@@ -615,10 +610,9 @@
return status;
}
- void SetProgress(long progress, long initial_max, long threshold = 0) {
+ void SetProgress(long progress, long initial_max) {
+ ds.last_reported_percent_progress_ = 0;
ds.options_->do_progress_updates = true;
- ds.update_progress_threshold_ = threshold;
- ds.last_updated_progress_ = 0;
ds.progress_.reset(new Progress(initial_max, progress, 1.2));
}
@@ -796,73 +790,36 @@
ds.listener_name_ = "FoxMulder";
SetProgress(0, 30);
- EXPECT_CALL(*listener, onProgressUpdated(20));
EXPECT_CALL(*listener, onProgress(66)); // 20/30 %
EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(20).Build()));
std::string progress_message = GetProgressMessage(ds.listener_name_, 20, 30);
EXPECT_THAT(out, StrEq("stdout\n"));
EXPECT_THAT(err, StrEq("stderr\n" + progress_message));
- EXPECT_CALL(*listener, onProgressUpdated(30));
- EXPECT_CALL(*listener, onProgress(100)); // 35/35 %
- EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(10).Build()));
- progress_message = GetProgressMessage(ds.listener_name_, 30, 30);
- EXPECT_THAT(out, StrEq("stdout\n"));
- EXPECT_THAT(err, StrEq("stderr\n" + progress_message));
-
- // Run a command that will increase maximum timeout.
- EXPECT_CALL(*listener, onProgressUpdated(31));
- EXPECT_CALL(*listener, onMaxProgressUpdated(37));
- EXPECT_CALL(*listener, onProgress(83)); // 31/37 %
- EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(1).Build()));
- progress_message = GetProgressMessage(ds.listener_name_, 31, 37, 30); // 20% increase
+ EXPECT_CALL(*listener, onProgress(80)); // 24/30 %
+ EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(4).Build()));
+ progress_message = GetProgressMessage(ds.listener_name_, 24, 30);
EXPECT_THAT(out, StrEq("stdout\n"));
EXPECT_THAT(err, StrEq("stderr\n" + progress_message));
// Make sure command ran while in dry_run is counted.
SetDryRun(true);
- EXPECT_CALL(*listener, onProgressUpdated(35));
- EXPECT_CALL(*listener, onProgress(94)); // 35/37 %
- EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(4).Build()));
- progress_message = GetProgressMessage(ds.listener_name_, 35, 37);
+ EXPECT_CALL(*listener, onProgress(90)); // 27/30 %
+ EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(3).Build()));
+ progress_message = GetProgressMessage(ds.listener_name_, 27, 30);
EXPECT_THAT(out, IsEmpty());
EXPECT_THAT(err, StrEq(progress_message));
- ds.listener_.clear();
-}
-
-TEST_F(DumpstateTest, RunCommandProgressIgnoreThreshold) {
- sp<DumpstateListenerMock> listener(new DumpstateListenerMock());
- ds.listener_ = listener;
- ds.listener_name_ = "FoxMulder";
- SetProgress(0, 8, 5); // 8 max, 5 threshold
-
- // First update should always be sent.
- EXPECT_CALL(*listener, onProgressUpdated(1));
- EXPECT_CALL(*listener, onProgress(12)); // 1/12 %
- EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(1).Build()));
- std::string progress_message = GetProgressMessage(ds.listener_name_, 1, 8);
+ SetDryRun(false);
+ EXPECT_CALL(*listener, onProgress(96)); // 29/30 %
+ EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(2).Build()));
+ progress_message = GetProgressMessage(ds.listener_name_, 29, 30);
EXPECT_THAT(out, StrEq("stdout\n"));
EXPECT_THAT(err, StrEq("stderr\n" + progress_message));
- // Fourth update should be ignored because it's between the threshold (5 -1 = 4 < 5).
- EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(4).Build()));
- EXPECT_THAT(out, StrEq("stdout\n"));
- EXPECT_THAT(err, StrEq("stderr\n"));
-
- // Third update should be sent because it reaches threshold (6 - 1 = 5).
- EXPECT_CALL(*listener, onProgressUpdated(6));
- EXPECT_CALL(*listener, onProgress(75)); // 6/8 %
+ EXPECT_CALL(*listener, onProgress(100)); // 30/30 %
EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(1).Build()));
- progress_message = GetProgressMessage(ds.listener_name_, 6, 8);
- EXPECT_THAT(out, StrEq("stdout\n"));
- EXPECT_THAT(err, StrEq("stderr\n" + progress_message));
-
- // Fourth update should be ignored because it's between the threshold (9 - 6 = 3 < 5).
- // But max update should be sent.
- EXPECT_CALL(*listener, onMaxProgressUpdated(10)); // 9 * 120% = 10.8 = 10
- EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(3).Build()));
- progress_message = GetProgressMessage(ds.listener_name_, 9, 10, 8, false);
+ progress_message = GetProgressMessage(ds.listener_name_, 30, 30);
EXPECT_THAT(out, StrEq("stdout\n"));
EXPECT_THAT(err, StrEq("stderr\n" + progress_message));
@@ -1090,7 +1047,6 @@
ds.listener_name_ = "FoxMulder";
SetProgress(0, 30);
- EXPECT_CALL(*listener, onProgressUpdated(5));
EXPECT_CALL(*listener, onProgress(16)); // 5/30 %
EXPECT_EQ(0, DumpFile("", kTestDataPath + "single-line.txt"));
diff --git a/cmds/service/Android.bp b/cmds/service/Android.bp
index 9513ec1..a5b1ac5 100644
--- a/cmds/service/Android.bp
+++ b/cmds/service/Android.bp
@@ -4,6 +4,7 @@
srcs: ["service.cpp"],
shared_libs: [
+ "libcutils",
"libutils",
"libbinder",
],
@@ -22,6 +23,7 @@
srcs: ["service.cpp"],
shared_libs: [
+ "libcutils",
"libutils",
"libbinder",
],
diff --git a/cmds/service/service.cpp b/cmds/service/service.cpp
index 543357c..18b6b58 100644
--- a/cmds/service/service.cpp
+++ b/cmds/service/service.cpp
@@ -18,13 +18,18 @@
#include <binder/ProcessState.h>
#include <binder/IServiceManager.h>
#include <binder/TextOutput.h>
+#include <cutils/ashmem.h>
#include <getopt.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
+#include <sys/mman.h>
#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
using namespace android;
@@ -187,6 +192,57 @@
} else if (strcmp(argv[optind], "null") == 0) {
optind++;
data.writeStrongBinder(nullptr);
+ } else if (strcmp(argv[optind], "fd") == 0) {
+ optind++;
+ if (optind >= argc) {
+ aerr << "service: no path supplied for 'fd'" << endl;
+ wantsUsage = true;
+ result = 10;
+ break;
+ }
+ const char *path = argv[optind++];
+ int fd = open(path, O_RDONLY);
+ if (fd < 0) {
+ aerr << "service: could not open '" << path << "'" << endl;
+ wantsUsage = true;
+ result = 10;
+ break;
+ }
+ data.writeFileDescriptor(fd, true /* take ownership */);
+ } else if (strcmp(argv[optind], "afd") == 0) {
+ optind++;
+ if (optind >= argc) {
+ aerr << "service: no path supplied for 'afd'" << endl;
+ wantsUsage = true;
+ result = 10;
+ break;
+ }
+ const char *path = argv[optind++];
+ int fd = open(path, O_RDONLY);
+ struct stat statbuf;
+ if (fd < 0 || fstat(fd, &statbuf) != 0) {
+ aerr << "service: could not open or stat '" << path << "'" << endl;
+ wantsUsage = true;
+ result = 10;
+ break;
+ }
+ int afd = ashmem_create_region("test", statbuf.st_size);
+ void* ptr = mmap(NULL, statbuf.st_size,
+ PROT_READ | PROT_WRITE, MAP_SHARED, afd, 0);
+ read(fd, ptr, statbuf.st_size);
+ close(fd);
+ data.writeFileDescriptor(afd, true /* take ownership */);
+ } else if (strcmp(argv[optind], "nfd") == 0) {
+ optind++;
+ if (optind >= argc) {
+ aerr << "service: no file descriptor supplied for 'nfd'" << endl;
+ wantsUsage = true;
+ result = 10;
+ break;
+ }
+ data.writeFileDescriptor(
+ atoi(argv[optind++]), true /* take ownership */);
+
} else if (strcmp(argv[optind], "intent") == 0) {
char* action = nullptr;
@@ -300,13 +356,19 @@
aout << "Usage: service [-h|-?]\n"
" service list\n"
" service check SERVICE\n"
- " service call SERVICE CODE [i32 N | i64 N | f N | d N | s16 STR ] ...\n"
+ " service call SERVICE CODE [i32 N | i64 N | f N | d N | s16 STR | null"
+ " | fd f | nfd n | afd f ] ...\n"
"Options:\n"
" i32: Write the 32-bit integer N into the send parcel.\n"
" i64: Write the 64-bit integer N into the send parcel.\n"
" f: Write the 32-bit single-precision number N into the send parcel.\n"
" d: Write the 64-bit double-precision number N into the send parcel.\n"
- " s16: Write the UTF-16 string STR into the send parcel.\n";
+ " s16: Write the UTF-16 string STR into the send parcel.\n"
+ " null: Write a null binder into the send parcel.\n"
+ " fd: Write a file descriptor for the file f to the send parcel.\n"
+ " nfd: Write file descriptor n to the send parcel.\n"
+ " afd: Write an ashmem file descriptor for a region containing the data from"
+ " file f to the send parcel.\n";
// " intent: Write and Intent int the send parcel. ARGS can be\n"
// " action=STR data=STR type=STR launchFlags=INT component=STR categories=STR[,STR,...]\n";
return result;
diff --git a/cmds/servicemanager/Access.cpp b/cmds/servicemanager/Access.cpp
index d936dbe..606477f 100644
--- a/cmds/servicemanager/Access.cpp
+++ b/cmds/servicemanager/Access.cpp
@@ -61,15 +61,21 @@
return gSehandle;
}
+struct AuditCallbackData {
+ const Access::CallingContext* context;
+ const std::string* tname;
+};
+
static int auditCallback(void *data, security_class_t /*cls*/, char *buf, size_t len) {
- const Access::CallingContext* ad = reinterpret_cast<Access::CallingContext*>(data);
+ const AuditCallbackData* ad = reinterpret_cast<AuditCallbackData*>(data);
if (!ad) {
LOG(ERROR) << "No service manager audit data";
return 0;
}
- snprintf(buf, len, "pid=%d uid=%d", ad->debugPid, ad->uid);
+ snprintf(buf, len, "pid=%d uid=%d name=%s", ad->context->debugPid, ad->context->uid,
+ ad->tname->c_str());
return 0;
}
@@ -113,13 +119,20 @@
}
bool Access::canList(const CallingContext& ctx) {
- return actionAllowed(ctx, mThisProcessContext, "list");
+ return actionAllowed(ctx, mThisProcessContext, "list", "service_manager");
}
-bool Access::actionAllowed(const CallingContext& sctx, const char* tctx, const char* perm) {
+bool Access::actionAllowed(const CallingContext& sctx, const char* tctx, const char* perm,
+ const std::string& tname) {
const char* tclass = "service_manager";
- return 0 == selinux_check_access(sctx.sid.c_str(), tctx, tclass, perm, reinterpret_cast<void*>(const_cast<CallingContext*>((&sctx))));
+ AuditCallbackData data = {
+ .context = &sctx,
+ .tname = &tname,
+ };
+
+ return 0 == selinux_check_access(sctx.sid.c_str(), tctx, tclass, perm,
+ reinterpret_cast<void*>(&data));
}
bool Access::actionAllowedFromLookup(const CallingContext& sctx, const std::string& name, const char *perm) {
@@ -129,7 +142,7 @@
return false;
}
- bool allowed = actionAllowed(sctx, tctx, perm);
+ bool allowed = actionAllowed(sctx, tctx, perm, name);
freecon(tctx);
return allowed;
}
diff --git a/cmds/servicemanager/Access.h b/cmds/servicemanager/Access.h
index 05a60d3..77c2cd4 100644
--- a/cmds/servicemanager/Access.h
+++ b/cmds/servicemanager/Access.h
@@ -45,7 +45,8 @@
virtual bool canList(const CallingContext& ctx);
private:
- bool actionAllowed(const CallingContext& sctx, const char* tctx, const char* perm);
+ bool actionAllowed(const CallingContext& sctx, const char* tctx, const char* perm,
+ const std::string& tname);
bool actionAllowedFromLookup(const CallingContext& sctx, const std::string& name,
const char *perm);
diff --git a/cmds/servicemanager/ServiceManager.cpp b/cmds/servicemanager/ServiceManager.cpp
index c2c71e0..5f7dc25 100644
--- a/cmds/servicemanager/ServiceManager.cpp
+++ b/cmds/servicemanager/ServiceManager.cpp
@@ -52,7 +52,6 @@
}
}
- // TODO(b/136023468): move this check to be first
if (!mAccess->canFind(ctx, name)) {
// returns ok and null for legacy reasons
*outBinder = nullptr;
diff --git a/cmds/surfacereplayer/proto/src/trace.proto b/cmds/surfacereplayer/proto/src/trace.proto
index a738527..792ff91 100644
--- a/cmds/surfacereplayer/proto/src/trace.proto
+++ b/cmds/surfacereplayer/proto/src/trace.proto
@@ -1,5 +1,6 @@
syntax = "proto2";
option optimize_for = LITE_RUNTIME;
+package android.surfaceflinger;
message Trace {
repeated Increment increment = 1;
diff --git a/cmds/surfacereplayer/replayer/Event.cpp b/cmds/surfacereplayer/replayer/Event.cpp
index 390d398..64db5f0 100644
--- a/cmds/surfacereplayer/replayer/Event.cpp
+++ b/cmds/surfacereplayer/replayer/Event.cpp
@@ -17,6 +17,7 @@
#include "Event.h"
using namespace android;
+using Increment = surfaceflinger::Increment;
Event::Event(Increment::IncrementCase type) : mIncrementType(type) {}
diff --git a/cmds/surfacereplayer/replayer/Event.h b/cmds/surfacereplayer/replayer/Event.h
index 44b60f5..09a7c24 100644
--- a/cmds/surfacereplayer/replayer/Event.h
+++ b/cmds/surfacereplayer/replayer/Event.h
@@ -24,6 +24,8 @@
namespace android {
+using Increment = surfaceflinger::Increment;
+
class Event {
public:
Event(Increment::IncrementCase);
diff --git a/cmds/surfacereplayer/replayer/Replayer.h b/cmds/surfacereplayer/replayer/Replayer.h
index d7709cc..3b94618 100644
--- a/cmds/surfacereplayer/replayer/Replayer.h
+++ b/cmds/surfacereplayer/replayer/Replayer.h
@@ -38,6 +38,8 @@
#include <unordered_map>
#include <utility>
+using namespace android::surfaceflinger;
+
namespace android {
const auto DEFAULT_PATH = "/data/local/tmp/SurfaceTrace.dat";
diff --git a/data/etc/android.hardware.se.omapi.ese.xml b/data/etc/android.hardware.se.omapi.ese.xml
new file mode 100644
index 0000000..3b1d81c
--- /dev/null
+++ b/data/etc/android.hardware.se.omapi.ese.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<!-- This feature indicates that the device supports The device supports
+ Open Mobile API capable ESE-based secure elements-->
+<permissions>
+ <feature name="android.hardware.se.omapi.ese" />
+</permissions>
diff --git a/data/etc/android.hardware.se.omapi.sd.xml b/data/etc/android.hardware.se.omapi.sd.xml
new file mode 100644
index 0000000..8fc2869
--- /dev/null
+++ b/data/etc/android.hardware.se.omapi.sd.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<!-- This feature indicates that the device supports The device supports
+ Open Mobile API capable SD-based secure elements-->
+<permissions>
+ <feature name="android.hardware.se.omapi.sd" />
+</permissions>
diff --git a/data/etc/android.hardware.se.omapi.uicc.xml b/data/etc/android.hardware.se.omapi.uicc.xml
new file mode 100644
index 0000000..9c6f143
--- /dev/null
+++ b/data/etc/android.hardware.se.omapi.uicc.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<!-- This feature indicates that the device supports The device supports
+ Open Mobile API capable UICC-based secure elements-->
+<permissions>
+ <feature name="android.hardware.se.omapi.uicc" />
+</permissions>
diff --git a/include/android/choreographer.h b/include/android/choreographer.h
index 44883cc..1b589bc 100644
--- a/include/android/choreographer.h
+++ b/include/android/choreographer.h
@@ -83,7 +83,7 @@
* Power a callback to be run on the next frame. The data pointer provided will
* be passed to the callback function when it's called.
*/
-void AChoreographer_postFrameCallback64(AChoreographer* chroreographer,
+void AChoreographer_postFrameCallback64(AChoreographer* choreographer,
AChoreographer_frameCallback64 callback, void* data) __INTRODUCED_IN(29);
/**
diff --git a/include/input/Input.h b/include/input/Input.h
index a976246..cbd1a41 100644
--- a/include/input/Input.h
+++ b/include/input/Input.h
@@ -24,6 +24,7 @@
*/
#include <android/input.h>
+#include <math.h>
#include <stdint.h>
#include <utils/BitSet.h>
#include <utils/KeyedVector.h>
@@ -468,14 +469,18 @@
inline float getYPrecision() const { return mYPrecision; }
- inline float getRawXCursorPosition() const { return mXCursorPosition; }
+ inline float getRawXCursorPosition() const { return mRawXCursorPosition; }
float getXCursorPosition() const;
- inline float getRawYCursorPosition() const { return mYCursorPosition; }
+ inline float getRawYCursorPosition() const { return mRawYCursorPosition; }
float getYCursorPosition() const;
+ void setCursorPosition(float x, float y);
+
+ static inline bool isValidCursorPosition(float x, float y) { return !isnan(x) && !isnan(y); }
+
inline nsecs_t getDownTime() const { return mDownTime; }
inline void setDownTime(nsecs_t downTime) { mDownTime = downTime; }
@@ -620,8 +625,8 @@
void initialize(int32_t deviceId, int32_t source, int32_t displayId, int32_t action,
int32_t actionButton, int32_t flags, int32_t edgeFlags, int32_t metaState,
int32_t buttonState, MotionClassification classification, float xOffset,
- float yOffset, float xPrecision, float yPrecision, float mXCursorPosition,
- float mYCursorPosition, nsecs_t downTime, nsecs_t eventTime,
+ float yOffset, float xPrecision, float yPrecision, float rawXCursorPosition,
+ float rawYCursorPosition, nsecs_t downTime, nsecs_t eventTime,
size_t pointerCount, const PointerProperties* pointerProperties,
const PointerCoords* pointerCoords);
@@ -673,8 +678,8 @@
float mYOffset;
float mXPrecision;
float mYPrecision;
- float mXCursorPosition;
- float mYCursorPosition;
+ float mRawXCursorPosition;
+ float mRawYCursorPosition;
nsecs_t mDownTime;
Vector<PointerProperties> mPointerProperties;
Vector<nsecs_t> mSampleEventTimes;
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
index b230943..c6ce576 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -70,6 +70,7 @@
"ProcessInfoService.cpp",
"ProcessState.cpp",
"Static.cpp",
+ "Stability.cpp",
"Status.cpp",
"TextOutput.cpp",
"IpPrefix.cpp",
diff --git a/libs/binder/Binder.cpp b/libs/binder/Binder.cpp
index c1d916c..f3483ca 100644
--- a/libs/binder/Binder.cpp
+++ b/libs/binder/Binder.cpp
@@ -17,15 +17,12 @@
#include <binder/Binder.h>
#include <atomic>
+#include <utils/misc.h>
#include <binder/BpBinder.h>
#include <binder/IInterface.h>
-#include <binder/IPCThreadState.h>
#include <binder/IResultReceiver.h>
#include <binder/IShellCallback.h>
#include <binder/Parcel.h>
-#include <cutils/android_filesystem_config.h>
-#include <cutils/compiler.h>
-#include <utils/misc.h>
#include <stdio.h>
@@ -128,19 +125,6 @@
{
data.setDataPosition(0);
- // Shell command transaction is conventionally implemented by
- // overriding onTransact by copy/pasting the parceling code from
- // this file. So, we must check permissions for it before we call
- // onTransact. This check is here because shell APIs aren't
- // guaranteed to be stable, and so they should only be used by
- // developers.
- if (CC_UNLIKELY(code == SHELL_COMMAND_TRANSACTION)) {
- uid_t uid = IPCThreadState::self()->getCallingUid();
- if (uid != AID_SHELL && uid != AID_ROOT) {
- return PERMISSION_DENIED;
- }
- }
-
status_t err = NO_ERROR;
switch (code) {
case PING_TRANSACTION:
@@ -151,6 +135,7 @@
break;
}
+ // In case this is being transacted on in the same process.
if (reply != nullptr) {
reply->setDataPosition(0);
}
diff --git a/libs/binder/BpBinder.cpp b/libs/binder/BpBinder.cpp
index 5ceb218..74ffde2 100644
--- a/libs/binder/BpBinder.cpp
+++ b/libs/binder/BpBinder.cpp
@@ -21,6 +21,7 @@
#include <binder/IPCThreadState.h>
#include <binder/IResultReceiver.h>
+#include <binder/Stability.h>
#include <cutils/compiler.h>
#include <utils/Log.h>
@@ -213,9 +214,21 @@
{
// Once a binder has died, it will never come back to life.
if (mAlive) {
+ // user transactions require a given stability level
+ if (code >= FIRST_CALL_TRANSACTION && code <= LAST_CALL_TRANSACTION) {
+ using android::internal::Stability;
+
+ auto stability = Stability::get(this);
+
+ if (CC_UNLIKELY(!Stability::check(stability, Stability::kLocalStability))) {
+ return BAD_TYPE;
+ }
+ }
+
status_t status = IPCThreadState::self()->transact(
mHandle, code, data, reply, flags);
if (status == DEAD_OBJECT) mAlive = 0;
+
return status;
}
diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp
index cfb86f0..7c45c77 100644
--- a/libs/binder/IPCThreadState.cpp
+++ b/libs/binder/IPCThreadState.cpp
@@ -465,7 +465,7 @@
void IPCThreadState::flushCommands()
{
- if (mProcess->mDriverFD <= 0)
+ if (mProcess->mDriverFD < 0)
return;
talkWithDriver(false);
// The flush could have caused post-write refcount decrements to have
@@ -618,7 +618,7 @@
int IPCThreadState::setupPolling(int* fd)
{
- if (mProcess->mDriverFD <= 0) {
+ if (mProcess->mDriverFD < 0) {
return -EBADF;
}
@@ -924,7 +924,7 @@
status_t IPCThreadState::talkWithDriver(bool doReceive)
{
- if (mProcess->mDriverFD <= 0) {
+ if (mProcess->mDriverFD < 0) {
return -EBADF;
}
@@ -982,7 +982,7 @@
#else
err = INVALID_OPERATION;
#endif
- if (mProcess->mDriverFD <= 0) {
+ if (mProcess->mDriverFD < 0) {
err = -EBADF;
}
IF_LOG_COMMANDS() {
@@ -1301,7 +1301,7 @@
if (self) {
self->flushCommands();
#if defined(__ANDROID__)
- if (self->mProcess->mDriverFD > 0) {
+ if (self->mProcess->mDriverFD >= 0) {
ioctl(self->mProcess->mDriverFD, BINDER_THREAD_EXIT, 0);
}
#endif
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index b5fbf42..ed6c834 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -35,6 +35,7 @@
#include <binder/IPCThreadState.h>
#include <binder/Parcel.h>
#include <binder/ProcessState.h>
+#include <binder/Stability.h>
#include <binder/Status.h>
#include <binder/TextOutput.h>
@@ -77,6 +78,9 @@
namespace android {
+// many things compile this into prebuilts on the stack
+static_assert(sizeof(Parcel) == 60 || sizeof(Parcel) == 120);
+
static pthread_mutex_t gParcelGlobalAllocSizeLock = PTHREAD_MUTEX_INITIALIZER;
static size_t gParcelGlobalAllocSize = 0;
static size_t gParcelGlobalAllocCount = 0;
@@ -102,10 +106,6 @@
reinterpret_cast<IBinder*>(obj.cookie)->incStrong(who);
}
return;
- case BINDER_TYPE_WEAK_BINDER:
- if (obj.binder)
- reinterpret_cast<RefBase::weakref_type*>(obj.binder)->incWeak(who);
- return;
case BINDER_TYPE_HANDLE: {
const sp<IBinder> b = proc->getStrongProxyForHandle(obj.handle);
if (b != nullptr) {
@@ -114,11 +114,6 @@
}
return;
}
- case BINDER_TYPE_WEAK_HANDLE: {
- const wp<IBinder> b = proc->getWeakProxyForHandle(obj.handle);
- if (b != nullptr) b.get_refs()->incWeak(who);
- return;
- }
case BINDER_TYPE_FD: {
if ((obj.cookie != 0) && (outAshmemSize != nullptr) && ashmem_valid(obj.handle)) {
// If we own an ashmem fd, keep track of how much memory it refers to.
@@ -144,10 +139,6 @@
reinterpret_cast<IBinder*>(obj.cookie)->decStrong(who);
}
return;
- case BINDER_TYPE_WEAK_BINDER:
- if (obj.binder)
- reinterpret_cast<RefBase::weakref_type*>(obj.binder)->decWeak(who);
- return;
case BINDER_TYPE_HANDLE: {
const sp<IBinder> b = proc->getStrongProxyForHandle(obj.handle);
if (b != nullptr) {
@@ -156,11 +147,6 @@
}
return;
}
- case BINDER_TYPE_WEAK_HANDLE: {
- const wp<IBinder> b = proc->getWeakProxyForHandle(obj.handle);
- if (b != nullptr) b.get_refs()->decWeak(who);
- return;
- }
case BINDER_TYPE_FD: {
if (obj.cookie != 0) { // owned
if ((outAshmemSize != nullptr) && ashmem_valid(obj.handle)) {
@@ -182,14 +168,31 @@
ALOGE("Invalid object type 0x%08x", obj.hdr.type);
}
-inline static status_t finish_flatten_binder(
- const sp<IBinder>& /*binder*/, const flat_binder_object& flat, Parcel* out)
+status_t Parcel::finishFlattenBinder(
+ const sp<IBinder>& binder, const flat_binder_object& flat)
{
- return out->writeObject(flat, false);
+ status_t status = writeObject(flat, false);
+ if (status != OK) return status;
+
+ internal::Stability::tryMarkCompilationUnit(binder.get());
+ return writeInt32(internal::Stability::get(binder.get()));
}
-static status_t flatten_binder(const sp<ProcessState>& /*proc*/,
- const sp<IBinder>& binder, Parcel* out)
+status_t Parcel::finishUnflattenBinder(
+ const sp<IBinder>& binder, sp<IBinder>* out) const
+{
+ int32_t stability;
+ status_t status = readInt32(&stability);
+ if (status != OK) return status;
+
+ status = internal::Stability::set(binder.get(), stability, true /*log*/);
+ if (status != OK) return status;
+
+ *out = binder;
+ return OK;
+}
+
+status_t Parcel::flattenBinder(const sp<IBinder>& binder)
{
flat_binder_object obj;
@@ -227,108 +230,24 @@
obj.cookie = 0;
}
- return finish_flatten_binder(binder, obj, out);
+ return finishFlattenBinder(binder, obj);
}
-static status_t flatten_binder(const sp<ProcessState>& /*proc*/,
- const wp<IBinder>& binder, Parcel* out)
+status_t Parcel::unflattenBinder(sp<IBinder>* out) const
{
- flat_binder_object obj;
+ const flat_binder_object* flat = readObject(false);
- obj.flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;
- if (binder != nullptr) {
- sp<IBinder> real = binder.promote();
- if (real != nullptr) {
- IBinder *local = real->localBinder();
- if (!local) {
- BpBinder *proxy = real->remoteBinder();
- if (proxy == nullptr) {
- ALOGE("null proxy");
- }
- const int32_t handle = proxy ? proxy->handle() : 0;
- obj.hdr.type = BINDER_TYPE_WEAK_HANDLE;
- obj.binder = 0; /* Don't pass uninitialized stack data to a remote process */
- obj.handle = handle;
- obj.cookie = 0;
- } else {
- obj.hdr.type = BINDER_TYPE_WEAK_BINDER;
- obj.binder = reinterpret_cast<uintptr_t>(binder.get_refs());
- obj.cookie = reinterpret_cast<uintptr_t>(binder.unsafe_get());
+ if (flat) {
+ switch (flat->hdr.type) {
+ case BINDER_TYPE_BINDER: {
+ sp<IBinder> binder = reinterpret_cast<IBinder*>(flat->cookie);
+ return finishUnflattenBinder(binder, out);
}
- return finish_flatten_binder(real, obj, out);
- }
-
- // XXX How to deal? In order to flatten the given binder,
- // we need to probe it for information, which requires a primary
- // reference... but we don't have one.
- //
- // The OpenBinder implementation uses a dynamic_cast<> here,
- // but we can't do that with the different reference counting
- // implementation we are using.
- ALOGE("Unable to unflatten Binder weak reference!");
- obj.hdr.type = BINDER_TYPE_BINDER;
- obj.binder = 0;
- obj.cookie = 0;
- return finish_flatten_binder(nullptr, obj, out);
-
- } else {
- obj.hdr.type = BINDER_TYPE_BINDER;
- obj.binder = 0;
- obj.cookie = 0;
- return finish_flatten_binder(nullptr, obj, out);
- }
-}
-
-inline static status_t finish_unflatten_binder(
- BpBinder* /*proxy*/, const flat_binder_object& /*flat*/,
- const Parcel& /*in*/)
-{
- return NO_ERROR;
-}
-
-static status_t unflatten_binder(const sp<ProcessState>& proc,
- const Parcel& in, sp<IBinder>* out)
-{
- const flat_binder_object* flat = in.readObject(false);
-
- if (flat) {
- switch (flat->hdr.type) {
- case BINDER_TYPE_BINDER:
- *out = reinterpret_cast<IBinder*>(flat->cookie);
- return finish_unflatten_binder(nullptr, *flat, in);
- case BINDER_TYPE_HANDLE:
- *out = proc->getStrongProxyForHandle(flat->handle);
- return finish_unflatten_binder(
- static_cast<BpBinder*>(out->get()), *flat, in);
- }
- }
- return BAD_TYPE;
-}
-
-static status_t unflatten_binder(const sp<ProcessState>& proc,
- const Parcel& in, wp<IBinder>* out)
-{
- const flat_binder_object* flat = in.readObject(false);
-
- if (flat) {
- switch (flat->hdr.type) {
- case BINDER_TYPE_BINDER:
- *out = reinterpret_cast<IBinder*>(flat->cookie);
- return finish_unflatten_binder(nullptr, *flat, in);
- case BINDER_TYPE_WEAK_BINDER:
- if (flat->binder != 0) {
- out->set_object_and_refs(
- reinterpret_cast<IBinder*>(flat->cookie),
- reinterpret_cast<RefBase::weakref_type*>(flat->binder));
- } else {
- *out = nullptr;
- }
- return finish_unflatten_binder(nullptr, *flat, in);
- case BINDER_TYPE_HANDLE:
- case BINDER_TYPE_WEAK_HANDLE:
- *out = proc->getWeakProxyForHandle(flat->handle);
- return finish_unflatten_binder(
- static_cast<BpBinder*>(out->unsafe_get()), *flat, in);
+ case BINDER_TYPE_HANDLE: {
+ sp<IBinder> binder =
+ ProcessState::self()->getStrongProxyForHandle(flat->handle);
+ return finishUnflattenBinder(binder, out);
+ }
}
}
return BAD_TYPE;
@@ -590,6 +509,12 @@
}
}
+#ifdef __ANDROID_VNDK__
+constexpr int32_t kHeader = B_PACK_CHARS('V', 'N', 'D', 'R');
+#else
+constexpr int32_t kHeader = B_PACK_CHARS('S', 'Y', 'S', 'T');
+#endif
+
// Write RPC headers. (previously just the interface token)
status_t Parcel::writeInterfaceToken(const String16& interface)
{
@@ -598,6 +523,7 @@
updateWorkSourceRequestHeaderPosition();
writeInt32(threadState->shouldPropagateWorkSource() ?
threadState->getCallingWorkSourceUid() : IPCThreadState::kUnsetWorkSource);
+ writeInt32(kHeader);
// currently the interface identification token is just its name as a string
return writeString16(interface);
}
@@ -655,6 +581,12 @@
updateWorkSourceRequestHeaderPosition();
int32_t workSource = readInt32();
threadState->setCallingWorkSourceUidWithoutPropagation(workSource);
+ // vendor header
+ int32_t header = readInt32();
+ if (header != kHeader) {
+ ALOGE("Expecting header 0x%x but found 0x%x. Mixing copies of libbinder?", kHeader, header);
+ return false;
+ }
// Interface descriptor.
const String16 str(readString16());
if (str == interface) {
@@ -1115,7 +1047,7 @@
status_t Parcel::writeStrongBinder(const sp<IBinder>& val)
{
- return flatten_binder(ProcessState::self(), val, this);
+ return flattenBinder(val);
}
status_t Parcel::writeStrongBinderVector(const std::vector<sp<IBinder>>& val)
@@ -1136,11 +1068,6 @@
return readTypedVector(val, &Parcel::readStrongBinder);
}
-status_t Parcel::writeWeakBinder(const wp<IBinder>& val)
-{
- return flatten_binder(ProcessState::self(), val, this);
-}
-
status_t Parcel::writeRawNullableParcelable(const Parcelable* parcelable) {
if (!parcelable) {
return writeInt32(0);
@@ -2066,7 +1993,7 @@
status_t Parcel::readNullableStrongBinder(sp<IBinder>* val) const
{
- return unflatten_binder(ProcessState::self(), *this, val);
+ return unflattenBinder(val);
}
sp<IBinder> Parcel::readStrongBinder() const
@@ -2079,13 +2006,6 @@
return val;
}
-wp<IBinder> Parcel::readWeakBinder() const
-{
- wp<IBinder> val;
- unflatten_binder(ProcessState::self(), *this, &val);
- return val;
-}
-
status_t Parcel::readParcelable(Parcelable* parcelable) const {
int32_t have_parcelable = 0;
status_t status = readInt32(&have_parcelable);
diff --git a/libs/binder/ProcessState.cpp b/libs/binder/ProcessState.cpp
index a07b3a0..07db50f 100644
--- a/libs/binder/ProcessState.cpp
+++ b/libs/binder/ProcessState.cpp
@@ -21,6 +21,7 @@
#include <binder/BpBinder.h>
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
+#include <binder/Stability.h>
#include <cutils/atomic.h>
#include <utils/Log.h>
#include <utils/String8.h>
@@ -109,7 +110,13 @@
sp<IBinder> ProcessState::getContextObject(const sp<IBinder>& /*caller*/)
{
- return getStrongProxyForHandle(0);
+ sp<IBinder> context = getStrongProxyForHandle(0);
+
+ // The root object is special since we get it directly from the driver, it is never
+ // written by Parcell::writeStrongBinder.
+ internal::Stability::tryMarkCompilationUnit(context.get());
+
+ return context;
}
void ProcessState::startThreadPool()
@@ -210,8 +217,12 @@
if (e != nullptr) {
// We need to create a new BpBinder if there isn't currently one, OR we
- // are unable to acquire a weak reference on this current one. See comment
- // in getWeakProxyForHandle() for more info about this.
+ // are unable to acquire a weak reference on this current one. The
+ // attemptIncWeak() is safe because we know the BpBinder destructor will always
+ // call expungeHandle(), which acquires the same lock we are holding now.
+ // We need to do this because there is a race condition between someone
+ // releasing a reference on this BpBinder, and a new reference on its handle
+ // arriving from the driver.
IBinder* b = e->binder;
if (b == nullptr || !e->refs->attemptIncWeak(this)) {
if (handle == 0) {
@@ -257,37 +268,6 @@
return result;
}
-wp<IBinder> ProcessState::getWeakProxyForHandle(int32_t handle)
-{
- wp<IBinder> result;
-
- AutoMutex _l(mLock);
-
- handle_entry* e = lookupHandleLocked(handle);
-
- if (e != nullptr) {
- // We need to create a new BpBinder if there isn't currently one, OR we
- // are unable to acquire a weak reference on this current one. The
- // attemptIncWeak() is safe because we know the BpBinder destructor will always
- // call expungeHandle(), which acquires the same lock we are holding now.
- // We need to do this because there is a race condition between someone
- // releasing a reference on this BpBinder, and a new reference on its handle
- // arriving from the driver.
- IBinder* b = e->binder;
- if (b == nullptr || !e->refs->attemptIncWeak(this)) {
- b = BpBinder::create(handle);
- result = b;
- e->binder = b;
- if (b) e->refs = b->getWeakRefs();
- } else {
- result = b;
- e->refs->decWeak(this);
- }
- }
-
- return result;
-}
-
void ProcessState::expungeHandle(int32_t handle, IBinder* binder)
{
AutoMutex _l(mLock);
diff --git a/libs/binder/Stability.cpp b/libs/binder/Stability.cpp
new file mode 100644
index 0000000..b6f10c8
--- /dev/null
+++ b/libs/binder/Stability.cpp
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <binder/Stability.h>
+
+namespace android {
+namespace internal {
+
+void Stability::markCompilationUnit(IBinder* binder) {
+ status_t result = set(binder, kLocalStability, true /*log*/);
+ LOG_ALWAYS_FATAL_IF(result != OK, "Should only mark known object.");
+}
+
+void Stability::markVintf(IBinder* binder) {
+ status_t result = set(binder, Level::VINTF, true /*log*/);
+ LOG_ALWAYS_FATAL_IF(result != OK, "Should only mark known object.");
+}
+
+void Stability::debugLogStability(const std::string& tag, const sp<IBinder>& binder) {
+ ALOGE("%s: stability is %s", tag.c_str(), stabilityString(get(binder.get())).c_str());
+}
+
+void Stability::markVndk(IBinder* binder) {
+ status_t result = set(binder, Level::VENDOR, true /*log*/);
+ LOG_ALWAYS_FATAL_IF(result != OK, "Should only mark known object.");
+}
+
+void Stability::tryMarkCompilationUnit(IBinder* binder) {
+ (void) set(binder, kLocalStability, false /*log*/);
+}
+
+status_t Stability::set(IBinder* binder, int32_t stability, bool log) {
+ Level currentStability = get(binder);
+
+ // null binder is always written w/ 'UNDECLARED' stability
+ if (binder == nullptr) {
+ if (stability == UNDECLARED) {
+ return OK;
+ } else {
+ if (log) {
+ ALOGE("Null binder written with stability %s.",
+ stabilityString(stability).c_str());
+ }
+ return BAD_TYPE;
+ }
+ }
+
+ if (!isDeclaredStability(stability)) {
+ if (log) {
+ ALOGE("Can only set known stability, not %d.", stability);
+ }
+ return BAD_TYPE;
+ }
+
+ if (currentStability != Level::UNDECLARED && currentStability != stability) {
+ if (log) {
+ ALOGE("Interface being set with %s but it is already marked as %s.",
+ stabilityString(stability).c_str(), stabilityString(currentStability).c_str());
+ }
+ return BAD_TYPE;
+ }
+
+ if (currentStability == stability) return OK;
+
+ binder->attachObject(
+ reinterpret_cast<void*>(&Stability::get),
+ reinterpret_cast<void*>(stability),
+ nullptr /*cleanupCookie*/,
+ nullptr /*cleanup function*/);
+
+ return OK;
+}
+
+Stability::Level Stability::get(IBinder* binder) {
+ if (binder == nullptr) return UNDECLARED;
+
+ return static_cast<Level>(reinterpret_cast<intptr_t>(
+ binder->findObject(reinterpret_cast<void*>(&Stability::get))));
+}
+
+bool Stability::check(int32_t provided, Level required) {
+ bool stable = (provided & required) == required;
+
+ if (!isDeclaredStability(provided) && provided != UNDECLARED) {
+ ALOGE("Unknown stability when checking interface stability %d.", provided);
+
+ stable = false;
+ }
+
+ if (!stable) {
+ ALOGE("Cannot do a user transaction on a %s binder in a %s context.",
+ stabilityString(provided).c_str(),
+ stabilityString(required).c_str());
+ }
+
+ return stable;
+}
+
+bool Stability::isDeclaredStability(int32_t stability) {
+ return stability == VENDOR || stability == SYSTEM || stability == VINTF;
+}
+
+std::string Stability::stabilityString(int32_t stability) {
+ switch (stability) {
+ case Level::UNDECLARED: return "undeclared stability";
+ case Level::VENDOR: return "vendor stability";
+ case Level::SYSTEM: return "system stability";
+ case Level::VINTF: return "vintf stability";
+ }
+ return "unknown stability " + std::to_string(stability);
+}
+
+} // namespace internal
+} // namespace stability
\ No newline at end of file
diff --git a/libs/binder/TEST_MAPPING b/libs/binder/TEST_MAPPING
index 01e57d3..136bdb0 100644
--- a/libs/binder/TEST_MAPPING
+++ b/libs/binder/TEST_MAPPING
@@ -11,6 +11,9 @@
},
{
"name": "binderLibTest"
+ },
+ {
+ "name": "binderStabilityTest"
}
]
}
diff --git a/libs/binder/include/binder/Binder.h b/libs/binder/include/binder/Binder.h
index cf3ef84..1537e69 100644
--- a/libs/binder/include/binder/Binder.h
+++ b/libs/binder/include/binder/Binder.h
@@ -54,9 +54,9 @@
virtual void attachObject( const void* objectID,
void* object,
void* cleanupCookie,
- object_cleanup_func func);
- virtual void* findObject(const void* objectID) const;
- virtual void detachObject(const void* objectID);
+ object_cleanup_func func) final;
+ virtual void* findObject(const void* objectID) const final;
+ virtual void detachObject(const void* objectID) final;
virtual BBinder* localBinder();
diff --git a/libs/binder/include/binder/BpBinder.h b/libs/binder/include/binder/BpBinder.h
index b3a1d0b..e71541b 100644
--- a/libs/binder/include/binder/BpBinder.h
+++ b/libs/binder/include/binder/BpBinder.h
@@ -61,9 +61,9 @@
virtual void attachObject( const void* objectID,
void* object,
void* cleanupCookie,
- object_cleanup_func func);
- virtual void* findObject(const void* objectID) const;
- virtual void detachObject(const void* objectID);
+ object_cleanup_func func) final;
+ virtual void* findObject(const void* objectID) const final;
+ virtual void detachObject(const void* objectID) final;
virtual BpBinder* remoteBinder();
diff --git a/libs/binder/include/binder/IServiceManager.h b/libs/binder/include/binder/IServiceManager.h
index aeea1a2..30786fa 100644
--- a/libs/binder/include/binder/IServiceManager.h
+++ b/libs/binder/include/binder/IServiceManager.h
@@ -71,13 +71,6 @@
*/
// NOLINTNEXTLINE(google-default-arguments)
virtual Vector<String16> listServices(int dumpsysFlags = DUMP_FLAG_PRIORITY_ALL) = 0;
-
- enum {
- GET_SERVICE_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION,
- CHECK_SERVICE_TRANSACTION,
- ADD_SERVICE_TRANSACTION,
- LIST_SERVICES_TRANSACTION,
- };
};
sp<IServiceManager> defaultServiceManager();
diff --git a/libs/binder/include/binder/Parcel.h b/libs/binder/include/binder/Parcel.h
index b65d456..f5aafc7 100644
--- a/libs/binder/include/binder/Parcel.h
+++ b/libs/binder/include/binder/Parcel.h
@@ -67,7 +67,7 @@
status_t setDataSize(size_t size);
void setDataPosition(size_t pos) const;
status_t setDataCapacity(size_t size);
-
+
status_t setData(const uint8_t* buffer, size_t len);
status_t appendFrom(const Parcel *parcel,
@@ -117,7 +117,6 @@
status_t writeString16(const std::unique_ptr<String16>& str);
status_t writeString16(const char16_t* str, size_t len);
status_t writeStrongBinder(const sp<IBinder>& val);
- status_t writeWeakBinder(const wp<IBinder>& val);
status_t writeInt32Array(size_t len, const int32_t *val);
status_t writeByteArray(size_t len, const uint8_t *val);
status_t writeBool(bool val);
@@ -273,7 +272,6 @@
sp<IBinder> readStrongBinder() const;
status_t readStrongBinder(sp<IBinder>* val) const;
status_t readNullableStrongBinder(sp<IBinder>* val) const;
- wp<IBinder> readWeakBinder() const;
template<typename T>
status_t readParcelableVector(
@@ -421,7 +419,13 @@
void scanForFds() const;
status_t validateReadData(size_t len) const;
void updateWorkSourceRequestHeaderPosition() const;
-
+
+ status_t finishFlattenBinder(const sp<IBinder>& binder,
+ const flat_binder_object& flat);
+ status_t finishUnflattenBinder(const sp<IBinder>& binder, sp<IBinder>* out) const;
+ status_t flattenBinder(const sp<IBinder>& binder);
+ status_t unflattenBinder(sp<IBinder>* out) const;
+
template<class T>
status_t readAligned(T *pArg) const;
diff --git a/libs/binder/include/binder/ProcessState.h b/libs/binder/include/binder/ProcessState.h
index 3af9eed..8339976 100644
--- a/libs/binder/include/binder/ProcessState.h
+++ b/libs/binder/include/binder/ProcessState.h
@@ -58,7 +58,6 @@
void* userData);
sp<IBinder> getStrongProxyForHandle(int32_t handle);
- wp<IBinder> getWeakProxyForHandle(int32_t handle);
void expungeHandle(int32_t handle, IBinder* binder);
void spawnPooledThread(bool isMain);
diff --git a/libs/binder/include/binder/Stability.h b/libs/binder/include/binder/Stability.h
new file mode 100644
index 0000000..f8240e4
--- /dev/null
+++ b/libs/binder/include/binder/Stability.h
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <binder/IBinder.h>
+#include <string>
+
+namespace android {
+
+class BpBinder;
+class ProcessState;
+
+namespace internal {
+
+// WARNING: These APIs are only ever expected to be called by auto-generated code.
+// Instead of calling them, you should set the stability of a .aidl interface
+class Stability final {
+public:
+ // WARNING: This is only ever expected to be called by auto-generated code. You likely want to
+ // change or modify the stability class of the interface you are using.
+ // This must be called as soon as the binder in question is constructed. No thread safety
+ // is provided.
+ // E.g. stability is according to libbinder compilation unit
+ static void markCompilationUnit(IBinder* binder);
+ // WARNING: This is only ever expected to be called by auto-generated code. You likely want to
+ // change or modify the stability class of the interface you are using.
+ // This must be called as soon as the binder in question is constructed. No thread safety
+ // is provided.
+ // E.g. stability is according to libbinder_ndk or Java SDK AND the interface
+ // expressed here is guaranteed to be stable for multiple years (Stable AIDL)
+ static void markVintf(IBinder* binder);
+
+ // WARNING: for debugging only
+ static void debugLogStability(const std::string& tag, const sp<IBinder>& binder);
+
+ // WARNING: This is only ever expected to be called by auto-generated code or tests.
+ // You likely want to change or modify the stability of the interface you are using.
+ // This must be called as soon as the binder in question is constructed. No thread safety
+ // is provided.
+ // E.g. stability is according to libbinder_ndk or Java SDK AND the interface
+ // expressed here is guaranteed to be stable for multiple years (Stable AIDL)
+ // If this is called when __ANDROID_VNDK__ is not defined, then it is UB and will likely
+ // break the device during GSI or other tests.
+ static void markVndk(IBinder* binder);
+
+private:
+ // Parcel needs to read/write stability level in an unstable format.
+ friend ::android::Parcel;
+
+ // only expose internal APIs inside of libbinder, for checking stability
+ friend ::android::BpBinder;
+
+ // so that it can mark the context object (only the root object doesn't go
+ // through Parcel)
+ friend ::android::ProcessState;
+
+ static void tryMarkCompilationUnit(IBinder* binder);
+
+ enum Level : int32_t {
+ UNDECLARED = 0,
+
+ VENDOR = 0b000011,
+ SYSTEM = 0b001100,
+ VINTF = 0b111111,
+ };
+
+#ifdef __ANDROID_VNDK__
+ static constexpr Level kLocalStability = Level::VENDOR;
+#else
+ static constexpr Level kLocalStability = Level::SYSTEM;
+#endif
+
+ // applies stability to binder if stability level is known
+ __attribute__((warn_unused_result))
+ static status_t set(IBinder* binder, int32_t stability, bool log);
+
+ static Level get(IBinder* binder);
+
+ static bool check(int32_t provided, Level required);
+
+ static bool isDeclaredStability(int32_t stability);
+ static std::string stabilityString(int32_t stability);
+
+ Stability();
+};
+
+} // namespace internal
+} // namespace android
diff --git a/libs/binder/ndk/Android.bp b/libs/binder/ndk/Android.bp
index 21bef2e..6da3086 100644
--- a/libs/binder/ndk/Android.bp
+++ b/libs/binder/ndk/Android.bp
@@ -16,7 +16,6 @@
cc_library {
name: "libbinder_ndk",
- vendor_available: true,
export_include_dirs: [
"include_ndk",
@@ -74,3 +73,12 @@
symbol_file: "libbinder_ndk.map.txt",
first_version: "29",
}
+
+llndk_library {
+ name: "libbinder_ndk",
+ symbol_file: "libbinder_ndk.map.txt",
+ export_include_dirs: [
+ "include_ndk",
+ "include_apex",
+ ],
+}
diff --git a/libs/binder/ndk/include_apex/android/binder_process.h b/libs/binder/ndk/include_apex/android/binder_process.h
index 69e6387..fdefbb4 100644
--- a/libs/binder/ndk/include_apex/android/binder_process.h
+++ b/libs/binder/ndk/include_apex/android/binder_process.h
@@ -27,7 +27,7 @@
void ABinderProcess_startThreadPool();
/**
* This sets the maximum number of threads that can be started in the threadpool. By default, after
- * startThreadPool is called, this is one. If it is called additional times, it will only prevent
+ * startThreadPool is called, this is 15. If it is called additional times, it will only prevent
* the kernel from starting new threads and will not delete already existing threads.
*/
bool ABinderProcess_setThreadPoolMaxThreadCount(uint32_t numThreads);
diff --git a/libs/binder/ndk/libbinder_ndk.map.txt b/libs/binder/ndk/libbinder_ndk.map.txt
index 7e65817..4f685d1 100644
--- a/libs/binder/ndk/libbinder_ndk.map.txt
+++ b/libs/binder/ndk/libbinder_ndk.map.txt
@@ -89,12 +89,12 @@
AStatus_getStatus;
AStatus_isOk;
AStatus_newOk;
- ABinderProcess_joinThreadPool; # apex
- ABinderProcess_setThreadPoolMaxThreadCount; # apex
- ABinderProcess_startThreadPool; # apex
- AServiceManager_addService; # apex
- AServiceManager_checkService; # apex
- AServiceManager_getService; # apex
+ ABinderProcess_joinThreadPool; # apex vndk
+ ABinderProcess_setThreadPoolMaxThreadCount; # apex vndk
+ ABinderProcess_startThreadPool; # apex vndk
+ AServiceManager_addService; # apex vndk
+ AServiceManager_checkService; # apex vndk
+ AServiceManager_getService; # apex vndk
local:
*;
};
diff --git a/libs/binder/ndk/scripts/init_map.sh b/libs/binder/ndk/scripts/init_map.sh
deleted file mode 100755
index 3529b72..0000000
--- a/libs/binder/ndk/scripts/init_map.sh
+++ /dev/null
@@ -1,19 +0,0 @@
-#!/usr/bin/env bash
-
-# Simple helper for ease of development until this API is frozen.
-
-echo "LIBBINDER_NDK { # introduced=29"
-echo " global:"
-{
- grep -oP "AIBinder_[a-zA-Z0-9_]+(?=\()" include_ndk/android/binder_ibinder.h;
- grep -oP "AIBinder_[a-zA-Z0-9_]+(?=\()" include_ndk/android/binder_ibinder_jni.h;
- grep -oP "AParcel_[a-zA-Z0-9_]+(?=\()" include_ndk/android/binder_parcel.h;
- grep -oP "AStatus_[a-zA-Z0-9_]+(?=\()" include_ndk/android/binder_status.h;
-} | sort | uniq | awk '{ print " " $0 ";"; }'
-{
- grep -oP "AServiceManager_[a-zA-Z0-9_]+(?=\()" include_apex/android/binder_manager.h;
- grep -oP "ABinderProcess_[a-zA-Z0-9_]+(?=\()" include_apex/android/binder_process.h;
-} | sort | uniq | awk '{ print " " $0 "; # apex"; }'
-echo " local:"
-echo " *;"
-echo "};"
diff --git a/libs/binder/ndk/update.sh b/libs/binder/ndk/update.sh
index 9a4577f..1eba892 100755
--- a/libs/binder/ndk/update.sh
+++ b/libs/binder/ndk/update.sh
@@ -20,4 +20,3 @@
# This script makes sure that the source code is in sync with the various scripts
./scripts/gen_parcel_helper.py
./scripts/format.sh
-./scripts/init_map.sh > libbinder_ndk.map.txt
diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp
index 44a691d..724cb15 100644
--- a/libs/binder/tests/Android.bp
+++ b/libs/binder/tests/Android.bp
@@ -137,3 +137,19 @@
],
test_suites: ["device-tests"],
}
+
+cc_test {
+ name: "binderStabilityTest",
+ defaults: ["binder_test_defaults"],
+ srcs: [
+ "binderStabilityTest.cpp",
+ "IBinderStabilityTest.aidl",
+ "IBinderStabilityTestSub.aidl",
+ ],
+
+ shared_libs: [
+ "libbinder",
+ "libutils",
+ ],
+ test_suites: ["device-tests"],
+}
diff --git a/libs/binder/tests/IBinderStabilityTest.aidl b/libs/binder/tests/IBinderStabilityTest.aidl
new file mode 100644
index 0000000..9559196
--- /dev/null
+++ b/libs/binder/tests/IBinderStabilityTest.aidl
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import IBinderStabilityTestSub;
+
+// DO NOT EVER IN A MILLION YEARS WRITE AN INTERFACE LIKE THIS!
+// THIS IS ONLY FOR TESTING!
+interface IBinderStabilityTest {
+ // DO NOT EVER IN A MILLION YEARS WRITE AN INTERFACE LIKE THIS!
+ // THIS IS ONLY FOR TESTING!
+ void sendBinder(IBinderStabilityTestSub binder);
+
+ // DO NOT EVER IN A MILLION YEARS WRITE AN INTERFACE LIKE THIS!
+ // THIS IS ONLY FOR TESTING!
+ void sendAndCallBinder(IBinderStabilityTestSub binder);
+
+ // DO NOT EVER IN A MILLION YEARS WRITE AN INTERFACE LIKE THIS!
+ // THIS IS ONLY FOR TESTING!
+ IBinderStabilityTestSub returnNoStabilityBinder();
+
+ // DO NOT EVER IN A MILLION YEARS WRITE AN INTERFACE LIKE THIS!
+ // THIS IS ONLY FOR TESTING!
+ IBinderStabilityTestSub returnLocalStabilityBinder();
+
+ // DO NOT EVER IN A MILLION YEARS WRITE AN INTERFACE LIKE THIS!
+ // THIS IS ONLY FOR TESTING!
+ IBinderStabilityTestSub returnVintfStabilityBinder();
+
+ // DO NOT EVER IN A MILLION YEARS WRITE AN INTERFACE LIKE THIS!
+ // THIS IS ONLY FOR TESTING!
+ IBinderStabilityTestSub returnVendorStabilityBinder();
+}
+// DO NOT EVER IN A MILLION YEARS WRITE AN INTERFACE LIKE THIS!
+// THIS IS ONLY FOR TESTING!
+// Construct and return a binder with a specific stability
diff --git a/libs/binder/tests/IBinderStabilityTestSub.aidl b/libs/binder/tests/IBinderStabilityTestSub.aidl
new file mode 100644
index 0000000..a81ebf9
--- /dev/null
+++ b/libs/binder/tests/IBinderStabilityTestSub.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+interface IBinderStabilityTestSub {
+ void userDefinedTransaction();
+}
diff --git a/libs/binder/tests/binderLibTest.cpp b/libs/binder/tests/binderLibTest.cpp
index e51bceb..9de3460 100644
--- a/libs/binder/tests/binderLibTest.cpp
+++ b/libs/binder/tests/binderLibTest.cpp
@@ -66,7 +66,6 @@
BINDER_LIB_TEST_LINK_DEATH_TRANSACTION,
BINDER_LIB_TEST_WRITE_FILE_TRANSACTION,
BINDER_LIB_TEST_WRITE_PARCEL_FILE_DESCRIPTOR_TRANSACTION,
- BINDER_LIB_TEST_PROMOTE_WEAK_REF_TRANSACTION,
BINDER_LIB_TEST_EXIT_TRANSACTION,
BINDER_LIB_TEST_DELAYED_EXIT_TRANSACTION,
BINDER_LIB_TEST_GET_PTR_SIZE_TRANSACTION,
@@ -770,22 +769,6 @@
EXPECT_TRUE(strong_from_weak == nullptr);
}
-TEST_F(BinderLibTest, PromoteRemote) {
- int ret;
- Parcel data, reply;
- sp<IBinder> strong = new BBinder();
- sp<IBinder> server = addServer();
-
- ASSERT_TRUE(server != nullptr);
- ASSERT_TRUE(strong != nullptr);
-
- ret = data.writeWeakBinder(strong);
- EXPECT_EQ(NO_ERROR, ret);
-
- ret = server->transact(BINDER_LIB_TEST_PROMOTE_WEAK_REF_TRANSACTION, data, &reply);
- EXPECT_GE(ret, 0);
-}
-
TEST_F(BinderLibTest, CheckHandleZeroBinderHighBitsZeroCookie) {
status_t ret;
Parcel data, reply;
@@ -811,7 +794,6 @@
wp<IBinder> keepFreedBinder;
{
Parcel data, reply;
- data.writeBool(false); /* request weak reference */
ret = server->transact(BINDER_LIB_TEST_CREATE_BINDER_TRANSACTION, data, &reply);
ASSERT_EQ(NO_ERROR, ret);
struct flat_binder_object *freed = (struct flat_binder_object *)(reply.data());
@@ -820,8 +802,9 @@
* delete its reference to it - otherwise the transaction
* fails regardless of whether the driver is fixed.
*/
- keepFreedBinder = reply.readWeakBinder();
+ keepFreedBinder = reply.readStrongBinder();
}
+ IPCThreadState::self()->flushCommands();
{
Parcel data, reply;
data.writeStrongBinder(server);
@@ -1280,29 +1263,6 @@
if (ret != size) return UNKNOWN_ERROR;
return NO_ERROR;
}
- case BINDER_LIB_TEST_PROMOTE_WEAK_REF_TRANSACTION: {
- int ret;
- wp<IBinder> weak;
- sp<IBinder> strong;
- Parcel data2, reply2;
- sp<IServiceManager> sm = defaultServiceManager();
- sp<IBinder> server = sm->getService(binderLibTestServiceName);
-
- weak = data.readWeakBinder();
- if (weak == nullptr) {
- return BAD_VALUE;
- }
- strong = weak.promote();
-
- ret = server->transact(BINDER_LIB_TEST_NOP_TRANSACTION, data2, &reply2);
- if (ret != NO_ERROR)
- exit(EXIT_FAILURE);
-
- if (strong == nullptr) {
- reply->setError(1);
- }
- return NO_ERROR;
- }
case BINDER_LIB_TEST_DELAYED_EXIT_TRANSACTION:
alarm(10);
return NO_ERROR;
@@ -1311,13 +1271,8 @@
;
exit(EXIT_SUCCESS);
case BINDER_LIB_TEST_CREATE_BINDER_TRANSACTION: {
- bool strongRef = data.readBool();
sp<IBinder> binder = new BBinder();
- if (strongRef) {
- reply->writeStrongBinder(binder);
- } else {
- reply->writeWeakBinder(binder);
- }
+ reply->writeStrongBinder(binder);
return NO_ERROR;
}
case BINDER_LIB_TEST_GET_WORK_SOURCE_TRANSACTION: {
diff --git a/libs/binder/tests/binderStabilityTest.cpp b/libs/binder/tests/binderStabilityTest.cpp
new file mode 100644
index 0000000..52595e0
--- /dev/null
+++ b/libs/binder/tests/binderStabilityTest.cpp
@@ -0,0 +1,221 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <binder/Binder.h>
+#include <binder/IBinder.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/Parcel.h>
+#include <binder/Stability.h>
+#include <gtest/gtest.h>
+
+#include <sys/prctl.h>
+
+#include "BnBinderStabilityTestSub.h"
+#include "BnBinderStabilityTest.h"
+#include "BpBinderStabilityTest.h"
+
+using namespace android;
+using android::binder::Status;
+
+const String16 kNoStabilityServer = String16("binder_stability_test_service_low");
+const String16 kCompilationUnitServer = String16("binder_stability_test_service_compl");
+const String16 kVintfServer = String16("binder_stability_test_service_vintf");
+
+class BadStabilityTestSub : public BnBinderStabilityTestSub {
+ Status userDefinedTransaction() {
+ return Status::ok();
+ }
+};
+
+sp<IBinderStabilityTestSub> getCompilationUnitStability() {
+ sp<BnBinderStabilityTestSub> iface = new BadStabilityTestSub();
+ // NO! NO! NO! NO! DO NOT EVERY DO SOMETHING LIKE THIS?
+ // WHAT ARE YOU CRAZY? IT'S VERY DANGEROUS
+ internal::Stability::markCompilationUnit(iface.get()); // <- BAD, NO! DO NOT COPY
+ return iface;
+}
+
+sp<IBinderStabilityTestSub> getVintfStability() {
+ sp<BnBinderStabilityTestSub> iface = new BadStabilityTestSub();
+ // NO! NO! NO! NO! DO NOT EVERY DO SOMETHING LIKE THIS?
+ // WHAT ARE YOU CRAZY? IT'S VERY DANGEROUS
+ internal::Stability::markVintf(iface.get()); // <- BAD, NO! DO NOT COPY
+ return iface;
+}
+
+sp<IBinderStabilityTestSub> getVendorStability() {
+ sp<BnBinderStabilityTestSub> iface = new BadStabilityTestSub();
+ // NO! NO! NO! NO! DO NOT EVERY DO SOMETHING LIKE THIS?
+ // WHAT ARE YOU CRAZY? IT'S VERY DANGEROUS
+ internal::Stability::markVndk(iface.get()); // <- BAD, NO! DO NOT COPY
+ return iface;
+}
+
+// NO! NO! NO! Do not even think of doing something like this!
+// This is for testing! If a class like this was actually used in production,
+// it would ruin everything!
+class BadStabilityTester : public BnBinderStabilityTest {
+public:
+ Status sendBinder(const sp<IBinderStabilityTestSub>& /*binder*/) override {
+ return Status::ok();
+ }
+ Status sendAndCallBinder(const sp<IBinderStabilityTestSub>& binder) override {
+ return binder->userDefinedTransaction();
+ }
+ Status returnNoStabilityBinder(sp<IBinderStabilityTestSub>* _aidl_return) override {
+ *_aidl_return = new BadStabilityTestSub();
+ return Status::ok();
+ }
+ Status returnLocalStabilityBinder(sp<IBinderStabilityTestSub>* _aidl_return) override {
+ *_aidl_return = getCompilationUnitStability();
+ return Status::ok();
+ }
+ Status returnVintfStabilityBinder(sp<IBinderStabilityTestSub>* _aidl_return) override {
+ *_aidl_return = getVintfStability();
+ return Status::ok();
+ }
+ Status returnVendorStabilityBinder(sp<IBinderStabilityTestSub>* _aidl_return) override {
+ *_aidl_return = getVendorStability();
+ return Status::ok();
+ }
+};
+
+void checkSystemStabilityBinder(const sp<IBinderStabilityTest>& complServer) {
+ EXPECT_TRUE(complServer->sendBinder(new BadStabilityTestSub()).isOk());
+ EXPECT_TRUE(complServer->sendBinder(getCompilationUnitStability()).isOk());
+ EXPECT_TRUE(complServer->sendBinder(getVintfStability()).isOk());
+ EXPECT_TRUE(complServer->sendBinder(getVendorStability()).isOk());
+
+ EXPECT_TRUE(complServer->sendAndCallBinder(new BadStabilityTestSub()).isOk());
+ EXPECT_TRUE(complServer->sendAndCallBinder(getCompilationUnitStability()).isOk());
+ EXPECT_TRUE(complServer->sendAndCallBinder(getVintfStability()).isOk());
+
+ // !!! user-defined transaction may not be stable for remote server !!!
+ EXPECT_FALSE(complServer->sendAndCallBinder(getVendorStability()).isOk());
+
+ sp<IBinderStabilityTestSub> out;
+ EXPECT_TRUE(complServer->returnNoStabilityBinder(&out).isOk());
+ ASSERT_NE(nullptr, out.get());
+ EXPECT_EQ(OK, IInterface::asBinder(out)->pingBinder());
+ EXPECT_TRUE(out->userDefinedTransaction().isOk());
+
+ EXPECT_TRUE(complServer->returnLocalStabilityBinder(&out).isOk());
+ ASSERT_NE(nullptr, out.get());
+ EXPECT_EQ(OK, IInterface::asBinder(out)->pingBinder());
+ EXPECT_TRUE(out->userDefinedTransaction().isOk());
+
+ EXPECT_TRUE(complServer->returnVintfStabilityBinder(&out).isOk());
+ ASSERT_NE(nullptr, out.get());
+ EXPECT_EQ(OK, IInterface::asBinder(out)->pingBinder());
+ EXPECT_TRUE(out->userDefinedTransaction().isOk());
+
+ EXPECT_TRUE(complServer->returnVendorStabilityBinder(&out).isOk());
+ ASSERT_NE(nullptr, out.get());
+
+ // !!! libbinder-defined transaction works !!!
+ EXPECT_EQ(OK, IInterface::asBinder(out)->pingBinder());
+
+ // !!! user-defined transaction may not be stable !!!
+ EXPECT_FALSE(out->userDefinedTransaction().isOk());
+}
+
+TEST(BinderStability, RemoteNoStabilityServer) {
+ sp<IBinder> remoteBinder = android::defaultServiceManager()->getService(kNoStabilityServer);
+ auto remoteServer = interface_cast<IBinderStabilityTest>(remoteBinder);
+
+ ASSERT_NE(nullptr, remoteServer.get());
+ ASSERT_NE(nullptr, IInterface::asBinder(remoteServer)->remoteBinder());
+
+ checkSystemStabilityBinder(remoteServer);
+}
+
+TEST(BinderStability, RemoteLowStabilityServer) {
+ sp<IBinder> remoteBinder = android::defaultServiceManager()->getService(kCompilationUnitServer);
+ auto remoteServer = interface_cast<IBinderStabilityTest>(remoteBinder);
+
+ ASSERT_NE(nullptr, remoteServer.get());
+ ASSERT_NE(nullptr, IInterface::asBinder(remoteServer)->remoteBinder());
+
+ checkSystemStabilityBinder(remoteServer);
+}
+
+TEST(BinderStability, RemoteVintfServer) {
+ sp<IBinder> remoteBinder = android::defaultServiceManager()->getService(kVintfServer);
+ auto remoteServer = interface_cast<IBinderStabilityTest>(remoteBinder);
+
+ ASSERT_NE(nullptr, remoteServer.get());
+ ASSERT_NE(nullptr, IInterface::asBinder(remoteServer)->remoteBinder());
+
+ checkSystemStabilityBinder(remoteServer);
+}
+
+class MarksStabilityInConstructor : public BBinder {
+public:
+ static bool gDestructed;
+
+ MarksStabilityInConstructor() {
+ internal::Stability::markCompilationUnit(this);
+ }
+ ~MarksStabilityInConstructor() {
+ gDestructed = true;
+ }
+};
+bool MarksStabilityInConstructor::gDestructed = false;
+
+TEST(BinderStability, MarkingObjectNoDestructTest) {
+ ASSERT_FALSE(MarksStabilityInConstructor::gDestructed);
+
+ // best practice is to put this directly in an sp, but for this test, we
+ // want to explicitly check what happens before that happens
+ MarksStabilityInConstructor* binder = new MarksStabilityInConstructor();
+ ASSERT_FALSE(MarksStabilityInConstructor::gDestructed);
+
+ sp<MarksStabilityInConstructor> binderSp = binder;
+ ASSERT_FALSE(MarksStabilityInConstructor::gDestructed);
+
+ binderSp = nullptr;
+ ASSERT_TRUE(MarksStabilityInConstructor::gDestructed);
+}
+
+int main(int argc, char** argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+
+ if (fork() == 0) {
+ // child process
+ prctl(PR_SET_PDEATHSIG, SIGHUP);
+
+ sp<IBinder> noStability = new BadStabilityTester;
+ android::defaultServiceManager()->addService(kNoStabilityServer, noStability);
+
+ sp<IBinder> compil = new BadStabilityTester;
+ internal::Stability::markCompilationUnit(compil.get());
+ android::defaultServiceManager()->addService(kCompilationUnitServer, compil);
+
+ sp<IBinder> vintf = new BadStabilityTester;
+ internal::Stability::markVintf(vintf.get());
+ android::defaultServiceManager()->addService(kVintfServer, vintf);
+
+ IPCThreadState::self()->joinThreadPool(true);
+ exit(1); // should not reach
+ }
+
+ // This is not racey. Just giving these services some time to register before we call
+ // getService which sleeps for much longer...
+ usleep(10000);
+
+ return RUN_ALL_TESTS();
+}
diff --git a/libs/cputimeinstate/Android.bp b/libs/cputimeinstate/Android.bp
index 28cb138..9080ce1 100644
--- a/libs/cputimeinstate/Android.bp
+++ b/libs/cputimeinstate/Android.bp
@@ -19,7 +19,11 @@
name: "libtimeinstate_test",
srcs: ["testtimeinstate.cpp"],
shared_libs: [
+ "libbase",
+ "libbpf",
+ "libbpf_android",
"libtimeinstate",
+ "libnetdutils",
],
cflags: [
"-Werror",
diff --git a/libs/cputimeinstate/cputimeinstate.cpp b/libs/cputimeinstate/cputimeinstate.cpp
index 41cbde1..0e68e62 100644
--- a/libs/cputimeinstate/cputimeinstate.cpp
+++ b/libs/cputimeinstate/cputimeinstate.cpp
@@ -17,6 +17,7 @@
#define LOG_TAG "libtimeinstate"
#include "cputimeinstate.h"
+#include "timeinstate.h"
#include <dirent.h>
#include <errno.h>
@@ -38,23 +39,12 @@
#include <libbpf.h>
#include <log/log.h>
-#define BPF_FS_PATH "/sys/fs/bpf/"
-
using android::base::StringPrintf;
using android::base::unique_fd;
namespace android {
namespace bpf {
-struct time_key_t {
- uint32_t uid;
- uint32_t freq;
-};
-
-struct val_t {
- uint64_t ar[100];
-};
-
static std::mutex gInitializedMutex;
static bool gInitialized = false;
static uint32_t gNPolicies = 0;
diff --git a/libs/cputimeinstate/testtimeinstate.cpp b/libs/cputimeinstate/testtimeinstate.cpp
index d4b8738..6347de1 100644
--- a/libs/cputimeinstate/testtimeinstate.cpp
+++ b/libs/cputimeinstate/testtimeinstate.cpp
@@ -1,14 +1,24 @@
+#include "timeinstate.h"
+
+#include <sys/sysinfo.h>
+
#include <unordered_map>
#include <vector>
#include <gtest/gtest.h>
+#include <android-base/unique_fd.h>
+#include <bpf/BpfMap.h>
#include <cputimeinstate.h>
+#include <libbpf.h>
namespace android {
namespace bpf {
+static constexpr uint64_t NSEC_PER_SEC = 1000000000;
+static constexpr uint64_t NSEC_PER_YEAR = NSEC_PER_SEC * 60 * 60 * 24 * 365;
+
using std::vector;
TEST(TimeInStateTest, SingleUid) {
@@ -33,8 +43,95 @@
}
}
+TEST(TimeInStateTest, SingleAndAllUidConsistent) {
+ auto map = getUidsCpuFreqTimes();
+ ASSERT_TRUE(map.has_value());
+ ASSERT_FALSE(map->empty());
+
+ for (const auto &kv : *map) {
+ uint32_t uid = kv.first;
+ auto times1 = kv.second;
+ auto times2 = getUidCpuFreqTimes(uid);
+ ASSERT_TRUE(times2.has_value());
+
+ ASSERT_EQ(times1.size(), times2->size());
+ for (uint32_t i = 0; i < times1.size(); ++i) {
+ ASSERT_EQ(times1[i].size(), (*times2)[i].size());
+ for (uint32_t j = 0; j < times1[i].size(); ++j) {
+ ASSERT_LE((*times2)[i][j] - times1[i][j], NSEC_PER_SEC);
+ }
+ }
+ }
+}
+
+void TestCheckDelta(uint64_t before, uint64_t after) {
+ // Times should never decrease
+ ASSERT_LE(before, after);
+ // UID can't have run for more than ~1s on each CPU
+ ASSERT_LE(after - before, NSEC_PER_SEC * 2 * get_nprocs_conf());
+}
+
+TEST(TimeInStateTest, AllUidMonotonic) {
+ auto map1 = getUidsCpuFreqTimes();
+ ASSERT_TRUE(map1.has_value());
+ sleep(1);
+ auto map2 = getUidsCpuFreqTimes();
+ ASSERT_TRUE(map2.has_value());
+
+ for (const auto &kv : *map1) {
+ uint32_t uid = kv.first;
+ auto times = kv.second;
+ ASSERT_NE(map2->find(uid), map2->end());
+ for (uint32_t policy = 0; policy < times.size(); ++policy) {
+ for (uint32_t freqIdx = 0; freqIdx < times[policy].size(); ++freqIdx) {
+ auto before = times[policy][freqIdx];
+ auto after = (*map2)[uid][policy][freqIdx];
+ ASSERT_NO_FATAL_FAILURE(TestCheckDelta(before, after));
+ }
+ }
+ }
+}
+
+TEST(TimeInStateTest, AllUidSanityCheck) {
+ auto map = getUidsCpuFreqTimes();
+ ASSERT_TRUE(map.has_value());
+
+ bool foundLargeValue = false;
+ for (const auto &kv : *map) {
+ for (const auto &timeVec : kv.second) {
+ for (const auto &time : timeVec) {
+ ASSERT_LE(time, NSEC_PER_YEAR);
+ if (time > UINT32_MAX) foundLargeValue = true;
+ }
+ }
+ }
+ // UINT32_MAX nanoseconds is less than 5 seconds, so if every part of our pipeline is using
+ // uint64_t as expected, we should have some times higher than that.
+ ASSERT_TRUE(foundLargeValue);
+}
+
TEST(TimeInStateTest, RemoveUid) {
- auto times = getUidCpuFreqTimes(0);
+ uint32_t uid = 0;
+ {
+ // Find an unused UID
+ auto times = getUidsCpuFreqTimes();
+ ASSERT_TRUE(times.has_value());
+ ASSERT_FALSE(times->empty());
+ for (const auto &kv : *times) uid = std::max(uid, kv.first);
+ ++uid;
+ }
+ {
+ // Add a map entry for our fake UID by copying a real map entry
+ android::base::unique_fd fd{bpf_obj_get(BPF_FS_PATH "map_time_in_state_uid_times_map")};
+ ASSERT_GE(fd, 0);
+ time_key_t k;
+ ASSERT_FALSE(getFirstMapKey(fd, &k));
+ val_t val;
+ ASSERT_FALSE(findMapEntry(fd, &k, &val));
+ k.uid = uid;
+ ASSERT_FALSE(writeToMapEntry(fd, &k, &val, BPF_NOEXIST));
+ }
+ auto times = getUidCpuFreqTimes(uid);
ASSERT_TRUE(times.has_value());
ASSERT_FALSE(times->empty());
@@ -44,15 +141,12 @@
}
ASSERT_GT(sum, (uint64_t)0);
- ASSERT_TRUE(clearUidCpuFreqTimes(0));
+ ASSERT_TRUE(clearUidCpuFreqTimes(uid));
- auto times2 = getUidCpuFreqTimes(0);
- ASSERT_TRUE(times2.has_value());
- ASSERT_EQ(times2->size(), times->size());
- for (size_t i = 0; i < times->size(); ++i) {
- ASSERT_EQ((*times2)[i].size(), (*times)[i].size());
- for (size_t j = 0; j < (*times)[i].size(); ++j) ASSERT_LE((*times2)[i][j], (*times)[i][j]);
- }
+ auto allTimes = getUidsCpuFreqTimes();
+ ASSERT_TRUE(allTimes.has_value());
+ ASSERT_FALSE(allTimes->empty());
+ ASSERT_EQ(allTimes->find(uid), allTimes->end());
}
} // namespace bpf
diff --git a/libs/cputimeinstate/timeinstate.h b/libs/cputimeinstate/timeinstate.h
new file mode 100644
index 0000000..cf66ae7
--- /dev/null
+++ b/libs/cputimeinstate/timeinstate.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <inttypes.h>
+
+#define BPF_FS_PATH "/sys/fs/bpf/"
+
+struct time_key_t {
+ uint32_t uid;
+ uint32_t freq;
+};
+
+struct val_t {
+ uint64_t ar[100];
+};
diff --git a/libs/graphicsenv/Android.bp b/libs/graphicsenv/Android.bp
index 56521bf..f11cf62 100644
--- a/libs/graphicsenv/Android.bp
+++ b/libs/graphicsenv/Android.bp
@@ -32,5 +32,9 @@
"libutils",
],
+ header_libs: [
+ "libnativeloader-dummy-headers",
+ ],
+
export_include_dirs: ["include"],
}
diff --git a/libs/graphicsenv/GraphicsEnv.cpp b/libs/graphicsenv/GraphicsEnv.cpp
index 3e29e88..30f5f73 100644
--- a/libs/graphicsenv/GraphicsEnv.cpp
+++ b/libs/graphicsenv/GraphicsEnv.cpp
@@ -32,6 +32,7 @@
#include <cutils/properties.h>
#include <graphicsenv/IGpuService.h>
#include <log/log.h>
+#include <nativeloader/dlext_namespaces.h>
#include <sys/prctl.h>
#include <utils/Trace.h>
@@ -39,22 +40,6 @@
#include <string>
#include <thread>
-// TODO(b/37049319) Get this from a header once one exists
-extern "C" {
-android_namespace_t* android_get_exported_namespace(const char*);
-android_namespace_t* android_create_namespace(const char* name, const char* ld_library_path,
- const char* default_library_path, uint64_t type,
- const char* permitted_when_isolated_path,
- android_namespace_t* parent);
-bool android_link_namespaces(android_namespace_t* from, android_namespace_t* to,
- const char* shared_libs_sonames);
-
-enum {
- ANDROID_NAMESPACE_TYPE_ISOLATED = 1,
- ANDROID_NAMESPACE_TYPE_SHARED = 2,
-};
-}
-
// TODO(ianelliott@): Get the following from an ANGLE header:
#define CURRENT_ANGLE_API_VERSION 2 // Current API verion we are targetting
// Version-2 API:
@@ -213,7 +198,8 @@
case GpuStatsInfo::Driver::GL:
case GpuStatsInfo::Driver::GL_UPDATED:
case GpuStatsInfo::Driver::ANGLE: {
- if (mGpuStats.glDriverToLoad == GpuStatsInfo::Driver::NONE) {
+ if (mGpuStats.glDriverToLoad == GpuStatsInfo::Driver::NONE ||
+ mGpuStats.glDriverToLoad == GpuStatsInfo::Driver::GL) {
mGpuStats.glDriverToLoad = driver;
break;
}
@@ -225,7 +211,8 @@
}
case GpuStatsInfo::Driver::VULKAN:
case GpuStatsInfo::Driver::VULKAN_UPDATED: {
- if (mGpuStats.vkDriverToLoad == GpuStatsInfo::Driver::NONE) {
+ if (mGpuStats.vkDriverToLoad == GpuStatsInfo::Driver::NONE ||
+ mGpuStats.vkDriverToLoad == GpuStatsInfo::Driver::VULKAN) {
mGpuStats.vkDriverToLoad = driver;
break;
}
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp
index b2a7557..beb13ad 100644
--- a/libs/gui/Android.bp
+++ b/libs/gui/Android.bp
@@ -38,6 +38,7 @@
"BufferItemConsumer.cpp",
"ConsumerBase.cpp",
"CpuConsumer.cpp",
+ "DebugEGLImageTracker.cpp",
"DisplayEventReceiver.cpp",
"GLConsumer.cpp",
"GuiConfig.cpp",
diff --git a/libs/gui/DebugEGLImageTracker.cpp b/libs/gui/DebugEGLImageTracker.cpp
new file mode 100644
index 0000000..ab6f364
--- /dev/null
+++ b/libs/gui/DebugEGLImageTracker.cpp
@@ -0,0 +1,98 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/stringprintf.h>
+#include <cutils/properties.h>
+#include <gui/DebugEGLImageTracker.h>
+
+#include <cinttypes>
+#include <unordered_map>
+
+using android::base::StringAppendF;
+
+std::mutex DebugEGLImageTracker::mInstanceLock;
+std::atomic<DebugEGLImageTracker *> DebugEGLImageTracker::mInstance;
+
+class DebugEGLImageTrackerNoOp : public DebugEGLImageTracker {
+public:
+ DebugEGLImageTrackerNoOp() = default;
+ ~DebugEGLImageTrackerNoOp() override = default;
+ void create(const char * /*from*/) override {}
+ void destroy(const char * /*from*/) override {}
+
+ void dump(std::string & /*result*/) override {}
+};
+
+class DebugEGLImageTrackerImpl : public DebugEGLImageTracker {
+public:
+ DebugEGLImageTrackerImpl() = default;
+ ~DebugEGLImageTrackerImpl() override = default;
+ void create(const char * /*from*/) override;
+ void destroy(const char * /*from*/) override;
+
+ void dump(std::string & /*result*/) override;
+
+private:
+ std::mutex mLock;
+ std::unordered_map<std::string, int64_t> mCreateTracker;
+ std::unordered_map<std::string, int64_t> mDestroyTracker;
+
+ int64_t mTotalCreated = 0;
+ int64_t mTotalDestroyed = 0;
+};
+
+DebugEGLImageTracker *DebugEGLImageTracker::getInstance() {
+ std::lock_guard lock(mInstanceLock);
+ if (mInstance == nullptr) {
+ char value[PROPERTY_VALUE_MAX];
+ property_get("debug.sf.enable_egl_image_tracker", value, "0");
+ const bool enabled = static_cast<bool>(atoi(value));
+
+ if (enabled) {
+ mInstance = new DebugEGLImageTrackerImpl();
+ } else {
+ mInstance = new DebugEGLImageTrackerNoOp();
+ }
+ }
+
+ return mInstance;
+}
+
+void DebugEGLImageTrackerImpl::create(const char *from) {
+ std::lock_guard lock(mLock);
+ mCreateTracker[from]++;
+ mTotalCreated++;
+}
+
+void DebugEGLImageTrackerImpl::destroy(const char *from) {
+ std::lock_guard lock(mLock);
+ mDestroyTracker[from]++;
+ mTotalDestroyed++;
+}
+
+void DebugEGLImageTrackerImpl::dump(std::string &result) {
+ std::lock_guard lock(mLock);
+ StringAppendF(&result, "Live EGL Image objects: %" PRIi64 "\n",
+ mTotalCreated - mTotalDestroyed);
+ StringAppendF(&result, "Total EGL Image created: %" PRIi64 "\n", mTotalCreated);
+ for (const auto &[from, count] : mCreateTracker) {
+ StringAppendF(&result, "\t%s: %" PRIi64 "\n", from.c_str(), count);
+ }
+ StringAppendF(&result, "Total EGL Image destroyed: %" PRIi64 "\n", mTotalDestroyed);
+ for (const auto &[from, count] : mDestroyTracker) {
+ StringAppendF(&result, "\t%s: %" PRIi64 "\n", from.c_str(), count);
+ }
+}
diff --git a/libs/gui/GLConsumer.cpp b/libs/gui/GLConsumer.cpp
index 8d66154..59f1bcd 100644
--- a/libs/gui/GLConsumer.cpp
+++ b/libs/gui/GLConsumer.cpp
@@ -34,6 +34,7 @@
#include <math/mat4.h>
#include <gui/BufferItem.h>
+#include <gui/DebugEGLImageTracker.h>
#include <gui/GLConsumer.h>
#include <gui/ISurfaceComposer.h>
#include <gui/SurfaceComposerClient.h>
@@ -45,7 +46,6 @@
#include <utils/String8.h>
#include <utils/Trace.h>
-extern "C" EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name);
#define PROT_CONTENT_EXT_STR "EGL_EXT_protected_content"
#define EGL_PROTECTED_CONTENT_EXT 0x32C0
@@ -944,6 +944,7 @@
if (!eglDestroyImageKHR(mEglDisplay, mEglImage)) {
ALOGE("~EglImage: eglDestroyImageKHR failed");
}
+ DEBUG_EGL_IMAGE_TRACKER_DESTROY();
eglTerminate(mEglDisplay);
}
}
@@ -957,6 +958,7 @@
if (!eglDestroyImageKHR(mEglDisplay, mEglImage)) {
ALOGE("createIfNeeded: eglDestroyImageKHR failed");
}
+ DEBUG_EGL_IMAGE_TRACKER_DESTROY();
eglTerminate(mEglDisplay);
mEglImage = EGL_NO_IMAGE_KHR;
mEglDisplay = EGL_NO_DISPLAY;
@@ -1006,7 +1008,10 @@
EGLint error = eglGetError();
ALOGE("error creating EGLImage: %#x", error);
eglTerminate(dpy);
+ } else {
+ DEBUG_EGL_IMAGE_TRACKER_CREATE();
}
+
return image;
}
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index bf7991a..be58b85 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -169,12 +169,10 @@
}
status_t ComposerState::write(Parcel& output) const {
- output.writeStrongBinder(IInterface::asBinder(client));
return state.write(output);
}
status_t ComposerState::read(const Parcel& input) {
- client = interface_cast<ISurfaceComposerClient>(input.readStrongBinder());
return state.read(input);
}
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index c59fddf..e6b1beb 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -202,7 +202,8 @@
* callbackIds to generate one super map that contains all the sp<IBinder> to sp<SurfaceControl>
* that could possibly exist for the callbacks.
*/
- std::unordered_map<sp<IBinder>, sp<SurfaceControl>, IBinderHash> surfaceControls;
+ std::unordered_map<sp<IBinder>, sp<SurfaceControl>, SurfaceComposerClient::IBinderHash>
+ surfaceControls;
for (const auto& transactionStats : listenerStats.transactionStats) {
for (auto callbackId : transactionStats.callbackIds) {
auto& [callbackFunction, callbackSurfaceControls] = mCallbacks[callbackId];
@@ -365,16 +366,16 @@
if (count > parcel->dataSize()) {
return BAD_VALUE;
}
- std::unordered_map<sp<SurfaceControl>, ComposerState, SCHash> composerStates;
+ std::unordered_map<sp<IBinder>, ComposerState, IBinderHash> composerStates;
composerStates.reserve(count);
for (size_t i = 0; i < count; i++) {
- sp<SurfaceControl> surfaceControl = SurfaceControl::readFromParcel(parcel);
+ sp<IBinder> surfaceControlHandle = parcel->readStrongBinder();
ComposerState composerState;
if (composerState.read(*parcel) == BAD_VALUE) {
return BAD_VALUE;
}
- composerStates[surfaceControl] = composerState;
+ composerStates[surfaceControlHandle] = composerState;
}
InputWindowCommands inputWindowCommands;
@@ -408,8 +409,8 @@
}
parcel->writeUint32(static_cast<uint32_t>(mComposerStates.size()));
- for (auto const& [surfaceControl, composerState] : mComposerStates) {
- surfaceControl->writeToParcel(parcel);
+ for (auto const& [surfaceHandle, composerState] : mComposerStates) {
+ parcel->writeStrongBinder(surfaceHandle);
composerState.write(*parcel);
}
@@ -418,11 +419,11 @@
}
SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::merge(Transaction&& other) {
- for (auto const& kv : other.mComposerStates) {
- if (mComposerStates.count(kv.first) == 0) {
- mComposerStates[kv.first] = kv.second;
+ for (auto const& [surfaceHandle, composerState] : other.mComposerStates) {
+ if (mComposerStates.count(surfaceHandle) == 0) {
+ mComposerStates[surfaceHandle] = composerState;
} else {
- mComposerStates[kv.first].state.merge(kv.second.state);
+ mComposerStates[surfaceHandle].state.merge(composerState.state);
}
}
@@ -448,6 +449,7 @@
mInputWindowCommands.merge(other.mInputWindowCommands);
mContainsBuffer = other.mContainsBuffer;
+ mEarlyWakeup = mEarlyWakeup || other.mEarlyWakeup;
other.clear();
return *this;
}
@@ -465,14 +467,12 @@
mDesiredPresentTime = -1;
}
-void SurfaceComposerClient::doDropReferenceTransaction(const sp<IBinder>& handle,
- const sp<ISurfaceComposerClient>& client) {
+void SurfaceComposerClient::doDropReferenceTransaction(const sp<IBinder>& handle) {
sp<ISurfaceComposer> sf(ComposerService::getComposerService());
Vector<ComposerState> composerStates;
Vector<DisplayState> displayStates;
ComposerState s;
- s.client = client;
s.state.surface = handle;
s.state.what |= layer_state_t::eReparent;
s.state.parentHandleForChild = nullptr;
@@ -499,8 +499,8 @@
}
size_t count = 0;
- for (auto& [sc, cs] : mComposerStates) {
- layer_state_t* s = getLayerState(sc);
+ for (auto& [handle, cs] : mComposerStates) {
+ layer_state_t* s = getLayerState(handle);
if (!(s->what & layer_state_t::eBufferChanged)) {
continue;
}
@@ -639,16 +639,15 @@
mEarlyWakeup = true;
}
-layer_state_t* SurfaceComposerClient::Transaction::getLayerState(const sp<SurfaceControl>& sc) {
- if (mComposerStates.count(sc) == 0) {
+layer_state_t* SurfaceComposerClient::Transaction::getLayerState(const sp<IBinder>& handle) {
+ if (mComposerStates.count(handle) == 0) {
// we don't have it, add an initialized layer_state to our list
ComposerState s;
- s.client = sc->getClient()->mClient;
- s.state.surface = sc->getHandle();
- mComposerStates[sc] = s;
+ s.state.surface = handle;
+ mComposerStates[handle] = s;
}
- return &(mComposerStates[sc].state);
+ return &(mComposerStates[handle].state);
}
void SurfaceComposerClient::Transaction::registerSurfaceControlForCallback(
diff --git a/libs/gui/SurfaceControl.cpp b/libs/gui/SurfaceControl.cpp
index b9defdd..071314f 100644
--- a/libs/gui/SurfaceControl.cpp
+++ b/libs/gui/SurfaceControl.cpp
@@ -65,8 +65,8 @@
{
// Avoid reparenting the server-side surface to null if we are not the owner of it,
// meaning that we retrieved it from another process.
- if (mClient != nullptr && mHandle != nullptr && mOwned) {
- SurfaceComposerClient::doDropReferenceTransaction(mHandle, mClient->getClient());
+ if (mHandle != nullptr && mOwned) {
+ SurfaceComposerClient::doDropReferenceTransaction(mHandle);
}
release();
}
diff --git a/libs/gui/include/gui/DebugEGLImageTracker.h b/libs/gui/include/gui/DebugEGLImageTracker.h
new file mode 100644
index 0000000..5d369c9
--- /dev/null
+++ b/libs/gui/include/gui/DebugEGLImageTracker.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <atomic>
+#include <mutex>
+#include <string>
+
+class DebugEGLImageTracker {
+public:
+ static DebugEGLImageTracker *getInstance();
+
+ virtual void create(const char *from) = 0;
+ virtual void destroy(const char *from) = 0;
+
+ virtual void dump(std::string &result) = 0;
+
+protected:
+ DebugEGLImageTracker() = default;
+ virtual ~DebugEGLImageTracker() = default;
+ DebugEGLImageTracker(const DebugEGLImageTracker &) = delete;
+
+ static std::mutex mInstanceLock;
+ static std::atomic<DebugEGLImageTracker *> mInstance;
+};
+
+#define DEBUG_EGL_IMAGE_TRACKER_CREATE() \
+ (DebugEGLImageTracker::getInstance()->create(__PRETTY_FUNCTION__))
+#define DEBUG_EGL_IMAGE_TRACKER_DESTROY() \
+ (DebugEGLImageTracker::getInstance()->destroy(__PRETTY_FUNCTION__))
\ No newline at end of file
diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h
index f438eb3..cbd1c85 100644
--- a/libs/gui/include/gui/LayerState.h
+++ b/libs/gui/include/gui/LayerState.h
@@ -206,7 +206,6 @@
};
struct ComposerState {
- sp<ISurfaceComposerClient> client;
layer_state_t state;
status_t write(Parcel& output) const;
status_t read(const Parcel& input);
@@ -274,8 +273,6 @@
};
static inline int compare_type(const ComposerState& lhs, const ComposerState& rhs) {
- if (lhs.client < rhs.client) return -1;
- if (lhs.client > rhs.client) return 1;
if (lhs.state.surface < rhs.state.surface) return -1;
if (lhs.state.surface > rhs.state.surface) return 1;
return 0;
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 4dda97f..22ab62d 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -163,8 +163,7 @@
* Called from SurfaceControl d'tor to 'destroy' the surface (or rather, reparent it
* to null), but without needing an sp<SurfaceControl> to avoid infinite ressurection.
*/
- static void doDropReferenceTransaction(const sp<IBinder>& handle,
- const sp<ISurfaceComposerClient>& client);
+ static void doDropReferenceTransaction(const sp<IBinder>& handle);
/**
* Uncaches a buffer in ISurfaceComposer. It must be uncached via a transaction so that it is
@@ -270,6 +269,12 @@
}
};
+ struct IBinderHash {
+ std::size_t operator()(const sp<IBinder>& iBinder) const {
+ return std::hash<IBinder*>{}(iBinder.get());
+ }
+ };
+
struct TCLHash {
std::size_t operator()(const sp<ITransactionCompletedListener>& tcl) const {
return std::hash<IBinder*>{}((tcl) ? IInterface::asBinder(tcl).get() : nullptr);
@@ -286,7 +291,7 @@
};
class Transaction : Parcelable {
- std::unordered_map<sp<SurfaceControl>, ComposerState, SCHash> mComposerStates;
+ std::unordered_map<sp<IBinder>, ComposerState, IBinderHash> mComposerStates;
SortedVector<DisplayState > mDisplayStates;
std::unordered_map<sp<ITransactionCompletedListener>, CallbackInfo, TCLHash>
mListenerCallbacks;
@@ -314,7 +319,10 @@
InputWindowCommands mInputWindowCommands;
int mStatus = NO_ERROR;
- layer_state_t* getLayerState(const sp<SurfaceControl>& sc);
+ layer_state_t* getLayerState(const sp<IBinder>& surfaceHandle);
+ layer_state_t* getLayerState(const sp<SurfaceControl>& sc) {
+ return getLayerState(sc->getHandle());
+ }
DisplayState& getDisplayState(const sp<IBinder>& token);
void cacheBuffers();
@@ -560,15 +568,10 @@
CallbackId mCallbackIdCounter GUARDED_BY(mMutex) = 1;
- struct IBinderHash {
- std::size_t operator()(const sp<IBinder>& iBinder) const {
- return std::hash<IBinder*>{}(iBinder.get());
- }
- };
-
struct CallbackTranslation {
TransactionCompletedCallback callbackFunction;
- std::unordered_map<sp<IBinder>, sp<SurfaceControl>, IBinderHash> surfaceControls;
+ std::unordered_map<sp<IBinder>, sp<SurfaceControl>, SurfaceComposerClient::IBinderHash>
+ surfaceControls;
};
std::unordered_map<CallbackId, CallbackTranslation> mCallbacks GUARDED_BY(mMutex);
diff --git a/libs/gui/tests/SurfaceTextureClient_test.cpp b/libs/gui/tests/SurfaceTextureClient_test.cpp
index 65e09f2..c85e844 100644
--- a/libs/gui/tests/SurfaceTextureClient_test.cpp
+++ b/libs/gui/tests/SurfaceTextureClient_test.cpp
@@ -28,8 +28,6 @@
#include <utils/Log.h>
#include <utils/Thread.h>
-extern "C" EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name);
-
namespace android {
class SurfaceTextureClientTest : public ::testing::Test {
diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp
index 3266b07..34b305e 100644
--- a/libs/input/Input.cpp
+++ b/libs/input/Input.cpp
@@ -17,7 +17,6 @@
#define LOG_TAG "Input"
//#define LOG_NDEBUG 0
-#include <math.h>
#include <limits.h>
#include <input/Input.h>
@@ -239,8 +238,8 @@
int32_t actionButton, int32_t flags, int32_t edgeFlags,
int32_t metaState, int32_t buttonState,
MotionClassification classification, float xOffset, float yOffset,
- float xPrecision, float yPrecision, float xCursorPosition,
- float yCursorPosition, nsecs_t downTime, nsecs_t eventTime,
+ float xPrecision, float yPrecision, float rawXCursorPosition,
+ float rawYCursorPosition, nsecs_t downTime, nsecs_t eventTime,
size_t pointerCount, const PointerProperties* pointerProperties,
const PointerCoords* pointerCoords) {
InputEvent::initialize(deviceId, source, displayId);
@@ -255,8 +254,8 @@
mYOffset = yOffset;
mXPrecision = xPrecision;
mYPrecision = yPrecision;
- mXCursorPosition = xCursorPosition;
- mYCursorPosition = yCursorPosition;
+ mRawXCursorPosition = rawXCursorPosition;
+ mRawYCursorPosition = rawYCursorPosition;
mDownTime = downTime;
mPointerProperties.clear();
mPointerProperties.appendArray(pointerProperties, pointerCount);
@@ -278,8 +277,8 @@
mYOffset = other->mYOffset;
mXPrecision = other->mXPrecision;
mYPrecision = other->mYPrecision;
- mXCursorPosition = other->mXCursorPosition;
- mYCursorPosition = other->mYCursorPosition;
+ mRawXCursorPosition = other->mRawXCursorPosition;
+ mRawYCursorPosition = other->mRawYCursorPosition;
mDownTime = other->mDownTime;
mPointerProperties = other->mPointerProperties;
@@ -314,6 +313,11 @@
return rawY + mYOffset;
}
+void MotionEvent::setCursorPosition(float x, float y) {
+ mRawXCursorPosition = x - mXOffset;
+ mRawYCursorPosition = y - mYOffset;
+}
+
const PointerCoords* MotionEvent::getRawPointerCoords(size_t pointerIndex) const {
return &mSamplePointerCoords[getHistorySize() * getPointerCount() + pointerIndex];
}
@@ -434,12 +438,12 @@
transformPoint(matrix, 0, 0, &originX, &originY);
// Apply the transformation to cursor position.
- if (!isnan(mXCursorPosition) && !isnan(mYCursorPosition)) {
- float x = mXCursorPosition + oldXOffset;
- float y = mYCursorPosition + oldYOffset;
+ if (isValidCursorPosition(mRawXCursorPosition, mRawYCursorPosition)) {
+ float x = mRawXCursorPosition + oldXOffset;
+ float y = mRawYCursorPosition + oldYOffset;
transformPoint(matrix, x, y, &x, &y);
- mXCursorPosition = x - mXOffset;
- mYCursorPosition = y - mYOffset;
+ mRawXCursorPosition = x - mXOffset;
+ mRawYCursorPosition = y - mYOffset;
}
// Apply the transformation to all samples.
@@ -481,8 +485,8 @@
mYOffset = parcel->readFloat();
mXPrecision = parcel->readFloat();
mYPrecision = parcel->readFloat();
- mXCursorPosition = parcel->readFloat();
- mYCursorPosition = parcel->readFloat();
+ mRawXCursorPosition = parcel->readFloat();
+ mRawYCursorPosition = parcel->readFloat();
mDownTime = parcel->readInt64();
mPointerProperties.clear();
@@ -534,8 +538,8 @@
parcel->writeFloat(mYOffset);
parcel->writeFloat(mXPrecision);
parcel->writeFloat(mYPrecision);
- parcel->writeFloat(mXCursorPosition);
- parcel->writeFloat(mYCursorPosition);
+ parcel->writeFloat(mRawXCursorPosition);
+ parcel->writeFloat(mRawYCursorPosition);
parcel->writeInt64(mDownTime);
for (size_t i = 0; i < pointerCount; i++) {
diff --git a/libs/input/InputWindow.cpp b/libs/input/InputWindow.cpp
index 5a60347..ec28757 100644
--- a/libs/input/InputWindow.cpp
+++ b/libs/input/InputWindow.cpp
@@ -99,7 +99,7 @@
applicationInfo.write(output);
output.write(touchableRegion);
output.writeBool(replaceTouchableRegionWithCrop);
- output.writeWeakBinder(touchableRegionCropHandle);
+ output.writeStrongBinder(touchableRegionCropHandle.promote());
return OK;
}
@@ -142,7 +142,7 @@
ret.applicationInfo = InputApplicationInfo::read(from);
from.read(ret.touchableRegion);
ret.replaceTouchableRegionWithCrop = from.readBool();
- ret.touchableRegionCropHandle = from.readWeakBinder();
+ ret.touchableRegionCropHandle = from.readStrongBinder();
return ret;
}
diff --git a/libs/input/tests/InputEvent_test.cpp b/libs/input/tests/InputEvent_test.cpp
index ec34f3e..b90857c 100644
--- a/libs/input/tests/InputEvent_test.cpp
+++ b/libs/input/tests/InputEvent_test.cpp
@@ -603,9 +603,13 @@
ASSERT_NEAR(tanf(angle), tanf(event.getOrientation(i)), 0.1);
}
- // Check cursor positions.
- ASSERT_NEAR(sinf(PI_180 * (90 + ROTATION)) * RADIUS, event.getXCursorPosition(), 0.001);
- ASSERT_NEAR(-cosf(PI_180 * (90 + ROTATION)) * RADIUS, event.getYCursorPosition(), 0.001);
+ // Check cursor positions. The original cursor position is at (3 + RADIUS, 2), where the center
+ // of the circle is (3, 2), so the cursor position is to the right of the center of the circle.
+ // The choice of triangular functions in this test defines the angle of rotation clockwise
+ // relative to the y-axis. Therefore the cursor position's angle is 90 degrees. Here we swap the
+ // triangular function so that we don't have to add the 90 degrees.
+ ASSERT_NEAR(cosf(PI_180 * ROTATION) * RADIUS, event.getXCursorPosition(), 0.001);
+ ASSERT_NEAR(sinf(PI_180 * ROTATION) * RADIUS, event.getYCursorPosition(), 0.001);
// Applying the transformation should preserve the raw X and Y of the first point.
ASSERT_NEAR(originalRawX, event.getRawX(0), 0.001);
@@ -661,4 +665,14 @@
ASSERT_EQ(600, event.getYCursorPosition());
}
+TEST_F(MotionEventTest, SetCursorPosition) {
+ MotionEvent event;
+ initializeEventWithHistory(&event);
+ event.setSource(AINPUT_SOURCE_MOUSE);
+
+ event.setCursorPosition(3, 4);
+ ASSERT_EQ(3, event.getXCursorPosition());
+ ASSERT_EQ(4, event.getYCursorPosition());
+}
+
} // namespace android
diff --git a/libs/renderengine/Android.bp b/libs/renderengine/Android.bp
index 36211ca..cc252d6 100644
--- a/libs/renderengine/Android.bp
+++ b/libs/renderengine/Android.bp
@@ -26,6 +26,7 @@
"libgui",
"liblog",
"libnativewindow",
+ "libprocessgroup",
"libsync",
"libui",
"libutils",
@@ -51,6 +52,7 @@
"gl/GLExtensions.cpp",
"gl/GLFramebuffer.cpp",
"gl/GLImage.cpp",
+ "gl/ImageManager.cpp",
"gl/Program.cpp",
"gl/ProgramCache.cpp",
],
diff --git a/libs/renderengine/gl/GLESRenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp
index efad745..dd4c55d 100644
--- a/libs/renderengine/gl/GLESRenderEngine.cpp
+++ b/libs/renderengine/gl/GLESRenderEngine.cpp
@@ -19,9 +19,8 @@
#define LOG_TAG "RenderEngine"
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
-#include "GLESRenderEngine.h"
-
-#include <math.h>
+#include <sched.h>
+#include <cmath>
#include <fstream>
#include <sstream>
#include <unordered_set>
@@ -31,6 +30,7 @@
#include <android-base/stringprintf.h>
#include <cutils/compiler.h>
#include <cutils/properties.h>
+#include <gui/DebugEGLImageTracker.h>
#include <renderengine/Mesh.h>
#include <renderengine/Texture.h>
#include <renderengine/private/Description.h>
@@ -42,6 +42,7 @@
#include <ui/Region.h>
#include <utils/KeyedVector.h>
#include <utils/Trace.h>
+#include "GLESRenderEngine.h"
#include "GLExtensions.h"
#include "GLFramebuffer.h"
#include "GLImage.h"
@@ -422,10 +423,13 @@
mTraceGpuCompletion = true;
mFlushTracer = std::make_unique<FlushTracer>(this);
}
+ mImageManager = std::make_unique<ImageManager>(this);
mDrawingBuffer = createFramebuffer();
}
GLESRenderEngine::~GLESRenderEngine() {
+ // Destroy the image manager first.
+ mImageManager = nullptr;
std::lock_guard<std::mutex> lock(mRenderingMutex);
unbindFrameBuffer(mDrawingBuffer.get());
mDrawingBuffer = nullptr;
@@ -433,6 +437,7 @@
EGLImageKHR expired = mFramebufferImageCache.front().second;
mFramebufferImageCache.pop_front();
eglDestroyImageKHR(mEGLDisplay, expired);
+ DEBUG_EGL_IMAGE_TRACKER_DESTROY();
}
mImageCache.clear();
eglMakeCurrent(mEGLDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
@@ -613,19 +618,41 @@
status_t GLESRenderEngine::bindExternalTextureBuffer(uint32_t texName,
const sp<GraphicBuffer>& buffer,
const sp<Fence>& bufferFence) {
- ATRACE_CALL();
- status_t cacheResult = cacheExternalTextureBuffer(buffer);
-
- if (cacheResult != NO_ERROR) {
- return cacheResult;
+ if (buffer == nullptr) {
+ return BAD_VALUE;
}
+ ATRACE_CALL();
+
+ bool found = false;
+ {
+ std::lock_guard<std::mutex> lock(mRenderingMutex);
+ auto cachedImage = mImageCache.find(buffer->getId());
+ found = (cachedImage != mImageCache.end());
+ }
+
+ // If we couldn't find the image in the cache at this time, then either
+ // SurfaceFlinger messed up registering the buffer ahead of time or we got
+ // backed up creating other EGLImages.
+ if (!found) {
+ status_t cacheResult = mImageManager->cache(buffer);
+ if (cacheResult != NO_ERROR) {
+ return cacheResult;
+ }
+ }
+
+ // Whether or not we needed to cache, re-check mImageCache to make sure that
+ // there's an EGLImage. The current threading model guarantees that we don't
+ // destroy a cached image until it's really not needed anymore (i.e. this
+ // function should not be called), so the only possibility is that something
+ // terrible went wrong and we should just bind something and move on.
{
std::lock_guard<std::mutex> lock(mRenderingMutex);
auto cachedImage = mImageCache.find(buffer->getId());
if (cachedImage == mImageCache.end()) {
// We failed creating the image if we got here, so bail out.
+ ALOGE("Failed to create an EGLImage when rendering");
bindExternalTextureImage(texName, *createImage());
return NO_INIT;
}
@@ -657,7 +684,18 @@
return NO_ERROR;
}
-status_t GLESRenderEngine::cacheExternalTextureBuffer(const sp<GraphicBuffer>& buffer) {
+void GLESRenderEngine::cacheExternalTextureBuffer(const sp<GraphicBuffer>& buffer) {
+ mImageManager->cacheAsync(buffer, nullptr);
+}
+
+std::shared_ptr<ImageManager::Barrier> GLESRenderEngine::cacheExternalTextureBufferForTesting(
+ const sp<GraphicBuffer>& buffer) {
+ auto barrier = std::make_shared<ImageManager::Barrier>();
+ mImageManager->cacheAsync(buffer, barrier);
+ return barrier;
+}
+
+status_t GLESRenderEngine::cacheExternalTextureBufferInternal(const sp<GraphicBuffer>& buffer) {
if (buffer == nullptr) {
return BAD_VALUE;
}
@@ -697,12 +735,30 @@
}
void GLESRenderEngine::unbindExternalTextureBuffer(uint64_t bufferId) {
- std::lock_guard<std::mutex> lock(mRenderingMutex);
- const auto& cachedImage = mImageCache.find(bufferId);
- if (cachedImage != mImageCache.end()) {
- ALOGV("Destroying image for buffer: %" PRIu64, bufferId);
- mImageCache.erase(bufferId);
- return;
+ mImageManager->releaseAsync(bufferId, nullptr);
+}
+
+std::shared_ptr<ImageManager::Barrier> GLESRenderEngine::unbindExternalTextureBufferForTesting(
+ uint64_t bufferId) {
+ auto barrier = std::make_shared<ImageManager::Barrier>();
+ mImageManager->releaseAsync(bufferId, barrier);
+ return barrier;
+}
+
+void GLESRenderEngine::unbindExternalTextureBufferInternal(uint64_t bufferId) {
+ std::unique_ptr<Image> image;
+ {
+ std::lock_guard<std::mutex> lock(mRenderingMutex);
+ const auto& cachedImage = mImageCache.find(bufferId);
+
+ if (cachedImage != mImageCache.end()) {
+ ALOGV("Destroying image for buffer: %" PRIu64, bufferId);
+ // Move the buffer out of cache first, so that we can destroy
+ // without holding the cache's lock.
+ image = std::move(cachedImage->second);
+ mImageCache.erase(bufferId);
+ return;
+ }
}
ALOGV("Failed to find image for buffer: %" PRIu64, bufferId);
}
@@ -862,10 +918,15 @@
EGLImageKHR expired = mFramebufferImageCache.front().second;
mFramebufferImageCache.pop_front();
eglDestroyImageKHR(mEGLDisplay, expired);
+ DEBUG_EGL_IMAGE_TRACKER_DESTROY();
}
mFramebufferImageCache.push_back({graphicBuffer->getId(), image});
}
}
+
+ if (image != EGL_NO_IMAGE_KHR) {
+ DEBUG_EGL_IMAGE_TRACKER_CREATE();
+ }
return image;
}
diff --git a/libs/renderengine/gl/GLESRenderEngine.h b/libs/renderengine/gl/GLESRenderEngine.h
index c8b45d2..501b044 100644
--- a/libs/renderengine/gl/GLESRenderEngine.h
+++ b/libs/renderengine/gl/GLESRenderEngine.h
@@ -17,9 +17,7 @@
#ifndef SF_GLESRENDERENGINE_H_
#define SF_GLESRENDERENGINE_H_
-#include <android-base/thread_annotations.h>
#include <stdint.h>
-#include <sys/types.h>
#include <condition_variable>
#include <deque>
#include <mutex>
@@ -30,8 +28,11 @@
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <GLES2/gl2.h>
+#include <android-base/thread_annotations.h>
#include <renderengine/RenderEngine.h>
#include <renderengine/private/Description.h>
+#include <sys/types.h>
+#include "ImageManager.h"
#define EGL_NO_CONFIG ((EGLConfig)0)
@@ -63,7 +64,7 @@
void bindExternalTextureImage(uint32_t texName, const Image& image) override;
status_t bindExternalTextureBuffer(uint32_t texName, const sp<GraphicBuffer>& buffer,
const sp<Fence>& fence) EXCLUDES(mRenderingMutex);
- status_t cacheExternalTextureBuffer(const sp<GraphicBuffer>& buffer) EXCLUDES(mRenderingMutex);
+ void cacheExternalTextureBuffer(const sp<GraphicBuffer>& buffer) EXCLUDES(mRenderingMutex);
void unbindExternalTextureBuffer(uint64_t bufferId) EXCLUDES(mRenderingMutex);
status_t bindFrameBuffer(Framebuffer* framebuffer) override;
void unbindFrameBuffer(Framebuffer* framebuffer) override;
@@ -87,6 +88,11 @@
// Returns true iff mFramebufferImageCache contains an image keyed by bufferId
bool isFramebufferImageCachedForTesting(uint64_t bufferId)
EXCLUDES(mFramebufferImageCacheMutex);
+ // These are wrappers around public methods above, but exposing Barrier
+ // objects so that tests can block.
+ std::shared_ptr<ImageManager::Barrier> cacheExternalTextureBufferForTesting(
+ const sp<GraphicBuffer>& buffer);
+ std::shared_ptr<ImageManager::Barrier> unbindExternalTextureBufferForTesting(uint64_t bufferId);
protected:
Framebuffer* getFramebufferForDrawing() override;
@@ -116,6 +122,9 @@
void setScissor(const Rect& region);
void disableScissor();
bool waitSync(EGLSyncKHR sync, EGLint flags);
+ status_t cacheExternalTextureBufferInternal(const sp<GraphicBuffer>& buffer)
+ EXCLUDES(mRenderingMutex);
+ void unbindExternalTextureBufferInternal(uint64_t bufferId) EXCLUDES(mRenderingMutex);
// A data space is considered HDR data space if it has BT2020 color space
// with PQ or HLG transfer function.
@@ -241,7 +250,9 @@
bool mRunning = true;
};
friend class FlushTracer;
+ friend class ImageManager;
std::unique_ptr<FlushTracer> mFlushTracer;
+ std::unique_ptr<ImageManager> mImageManager = std::make_unique<ImageManager>(this);
};
} // namespace gl
diff --git a/libs/renderengine/gl/GLFramebuffer.cpp b/libs/renderengine/gl/GLFramebuffer.cpp
index dacf8d3..5fbb5ba 100644
--- a/libs/renderengine/gl/GLFramebuffer.cpp
+++ b/libs/renderengine/gl/GLFramebuffer.cpp
@@ -22,6 +22,7 @@
#include <GLES/glext.h>
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
+#include <gui/DebugEGLImageTracker.h>
#include <nativebase/nativebase.h>
#include <utils/Trace.h>
#include "GLESRenderEngine.h"
@@ -47,6 +48,7 @@
if (mEGLImage != EGL_NO_IMAGE_KHR) {
if (!usingFramebufferCache) {
eglDestroyImageKHR(mEGLDisplay, mEGLImage);
+ DEBUG_EGL_IMAGE_TRACKER_DESTROY();
}
mEGLImage = EGL_NO_IMAGE_KHR;
mBufferWidth = 0;
diff --git a/libs/renderengine/gl/GLImage.cpp b/libs/renderengine/gl/GLImage.cpp
index 77e648e..8497721 100644
--- a/libs/renderengine/gl/GLImage.cpp
+++ b/libs/renderengine/gl/GLImage.cpp
@@ -20,6 +20,7 @@
#include <vector>
+#include <gui/DebugEGLImageTracker.h>
#include <log/log.h>
#include <utils/Trace.h>
#include "GLESRenderEngine.h"
@@ -58,6 +59,7 @@
if (!eglDestroyImageKHR(mEGLDisplay, mEGLImage)) {
ALOGE("failed to destroy image: %#x", eglGetError());
}
+ DEBUG_EGL_IMAGE_TRACKER_DESTROY();
mEGLImage = EGL_NO_IMAGE_KHR;
}
@@ -69,6 +71,7 @@
ALOGE("failed to create EGLImage: %#x", eglGetError());
return false;
}
+ DEBUG_EGL_IMAGE_TRACKER_CREATE();
mProtected = isProtected;
}
diff --git a/libs/renderengine/gl/ImageManager.cpp b/libs/renderengine/gl/ImageManager.cpp
new file mode 100644
index 0000000..5af0e4f
--- /dev/null
+++ b/libs/renderengine/gl/ImageManager.cpp
@@ -0,0 +1,140 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
+#include <pthread.h>
+
+#include <processgroup/sched_policy.h>
+#include <utils/Trace.h>
+#include "GLESRenderEngine.h"
+#include "ImageManager.h"
+
+namespace android {
+namespace renderengine {
+namespace gl {
+
+ImageManager::ImageManager(GLESRenderEngine* engine) : mEngine(engine) {
+ pthread_setname_np(mThread.native_handle(), "ImageManager");
+ // Use SCHED_FIFO to minimize jitter
+ struct sched_param param = {0};
+ param.sched_priority = 2;
+ if (pthread_setschedparam(mThread.native_handle(), SCHED_FIFO, ¶m) != 0) {
+ ALOGE("Couldn't set SCHED_FIFO for ImageManager");
+ }
+}
+
+ImageManager::~ImageManager() {
+ {
+ std::lock_guard<std::mutex> lock(mMutex);
+ mRunning = false;
+ }
+ mCondition.notify_all();
+ if (mThread.joinable()) {
+ mThread.join();
+ }
+}
+
+void ImageManager::cacheAsync(const sp<GraphicBuffer>& buffer,
+ const std::shared_ptr<Barrier>& barrier) {
+ if (buffer == nullptr) {
+ {
+ std::lock_guard<std::mutex> lock(barrier->mutex);
+ barrier->isOpen = true;
+ barrier->result = BAD_VALUE;
+ }
+ barrier->condition.notify_one();
+ return;
+ }
+ ATRACE_CALL();
+ QueueEntry entry = {QueueEntry::Operation::Insert, buffer, buffer->getId(), barrier};
+ queueOperation(std::move(entry));
+}
+
+status_t ImageManager::cache(const sp<GraphicBuffer>& buffer) {
+ ATRACE_CALL();
+ auto barrier = std::make_shared<Barrier>();
+ cacheAsync(buffer, barrier);
+ std::lock_guard<std::mutex> lock(barrier->mutex);
+ barrier->condition.wait(barrier->mutex,
+ [&]() REQUIRES(barrier->mutex) { return barrier->isOpen; });
+ return barrier->result;
+}
+
+void ImageManager::releaseAsync(uint64_t bufferId, const std::shared_ptr<Barrier>& barrier) {
+ ATRACE_CALL();
+ QueueEntry entry = {QueueEntry::Operation::Delete, nullptr, bufferId, barrier};
+ queueOperation(std::move(entry));
+}
+
+void ImageManager::queueOperation(const QueueEntry&& entry) {
+ {
+ std::lock_guard<std::mutex> lock(mMutex);
+ mQueue.emplace(entry);
+ ATRACE_INT("ImageManagerQueueDepth", mQueue.size());
+ }
+ mCondition.notify_one();
+}
+
+void ImageManager::threadMain() {
+ set_sched_policy(0, SP_FOREGROUND);
+ bool run;
+ {
+ std::lock_guard<std::mutex> lock(mMutex);
+ run = mRunning;
+ }
+ while (run) {
+ QueueEntry entry;
+ {
+ std::lock_guard<std::mutex> lock(mMutex);
+ mCondition.wait(mMutex,
+ [&]() REQUIRES(mMutex) { return !mQueue.empty() || !mRunning; });
+ run = mRunning;
+
+ if (!mRunning) {
+ // if mRunning is false, then ImageManager is being destroyed, so
+ // bail out now.
+ break;
+ }
+
+ entry = mQueue.front();
+ mQueue.pop();
+ ATRACE_INT("ImageManagerQueueDepth", mQueue.size());
+ }
+
+ status_t result = NO_ERROR;
+ switch (entry.op) {
+ case QueueEntry::Operation::Delete:
+ mEngine->unbindExternalTextureBufferInternal(entry.bufferId);
+ break;
+ case QueueEntry::Operation::Insert:
+ result = mEngine->cacheExternalTextureBufferInternal(entry.buffer);
+ break;
+ }
+ if (entry.barrier != nullptr) {
+ {
+ std::lock_guard<std::mutex> entryLock(entry.barrier->mutex);
+ entry.barrier->result = result;
+ entry.barrier->isOpen = true;
+ }
+ entry.barrier->condition.notify_one();
+ }
+ }
+}
+
+} // namespace gl
+} // namespace renderengine
+} // namespace android
diff --git a/libs/renderengine/gl/ImageManager.h b/libs/renderengine/gl/ImageManager.h
new file mode 100644
index 0000000..b5ba554
--- /dev/null
+++ b/libs/renderengine/gl/ImageManager.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <condition_variable>
+#include <mutex>
+#include <queue>
+#include <thread>
+
+#include <ui/GraphicBuffer.h>
+
+namespace android {
+namespace renderengine {
+namespace gl {
+
+class GLESRenderEngine;
+
+class ImageManager {
+public:
+ struct Barrier {
+ std::mutex mutex;
+ std::condition_variable_any condition;
+ bool isOpen GUARDED_BY(mutex) = false;
+ status_t result GUARDED_BY(mutex) = NO_ERROR;
+ };
+ ImageManager(GLESRenderEngine* engine);
+ ~ImageManager();
+ void cacheAsync(const sp<GraphicBuffer>& buffer, const std::shared_ptr<Barrier>& barrier)
+ EXCLUDES(mMutex);
+ status_t cache(const sp<GraphicBuffer>& buffer);
+ void releaseAsync(uint64_t bufferId, const std::shared_ptr<Barrier>& barrier) EXCLUDES(mMutex);
+
+private:
+ struct QueueEntry {
+ enum class Operation { Delete, Insert };
+
+ Operation op = Operation::Delete;
+ sp<GraphicBuffer> buffer = nullptr;
+ uint64_t bufferId = 0;
+ std::shared_ptr<Barrier> barrier = nullptr;
+ };
+
+ void queueOperation(const QueueEntry&& entry);
+ void threadMain();
+ GLESRenderEngine* const mEngine;
+ std::thread mThread = std::thread([this]() { threadMain(); });
+ std::condition_variable_any mCondition;
+ std::mutex mMutex;
+ std::queue<QueueEntry> mQueue GUARDED_BY(mMutex);
+
+ bool mRunning GUARDED_BY(mMutex) = true;
+};
+
+} // namespace gl
+} // namespace renderengine
+} // namespace android
diff --git a/libs/renderengine/gl/ProgramCache.cpp b/libs/renderengine/gl/ProgramCache.cpp
index 086a324..d242677 100644
--- a/libs/renderengine/gl/ProgramCache.cpp
+++ b/libs/renderengine/gl/ProgramCache.cpp
@@ -575,10 +575,11 @@
float applyCornerRadius(vec2 cropCoords)
{
vec2 position = cropCoords - cropCenter;
- // Increase precision here so that a large corner radius doesn't
- // cause floating point error
- highp vec2 dist = abs(position) + vec2(cornerRadius) - cropCenter;
- float plane = length(max(dist, vec2(0.0)));
+ // Scale down the dist vector here, as otherwise large corner
+ // radii can cause floating point issues when computing the norm
+ vec2 dist = (abs(position) - cropCenter + vec2(cornerRadius)) / 16.0;
+ // Once we've found the norm, then scale back up.
+ float plane = length(max(dist, vec2(0.0))) * 16.0;
return 1.0 - clamp(plane - cornerRadius, 0.0, 1.0);
}
)__SHADER__";
diff --git a/libs/renderengine/include/renderengine/RenderEngine.h b/libs/renderengine/include/renderengine/RenderEngine.h
index 1c480a7..205782b 100644
--- a/libs/renderengine/include/renderengine/RenderEngine.h
+++ b/libs/renderengine/include/renderengine/RenderEngine.h
@@ -94,10 +94,20 @@
const sp<Fence>& fence) = 0;
// Caches Image resources for this buffer, but does not bind the buffer to
// a particular texture.
- virtual status_t cacheExternalTextureBuffer(const sp<GraphicBuffer>& buffer) = 0;
+ // Note that work is deferred to an additional thread, i.e. this call
+ // is made asynchronously, but the caller can expect that cache/unbind calls
+ // are performed in a manner that's conflict serializable, i.e. unbinding
+ // a buffer should never occur before binding the buffer if the caller
+ // called {bind, cache}ExternalTextureBuffer before calling unbind.
+ virtual void cacheExternalTextureBuffer(const sp<GraphicBuffer>& buffer) = 0;
// Removes internal resources referenced by the bufferId. This method should be
// invoked when the caller will no longer hold a reference to a GraphicBuffer
// and needs to clean up its resources.
+ // Note that work is deferred to an additional thread, i.e. this call
+ // is made asynchronously, but the caller can expect that cache/unbind calls
+ // are performed in a manner that's conflict serializable, i.e. unbinding
+ // a buffer should never occur before binding the buffer if the caller
+ // called {bind, cache}ExternalTextureBuffer before calling unbind.
virtual void unbindExternalTextureBuffer(uint64_t bufferId) = 0;
// When binding a native buffer, it must be done before setViewportAndProjection
// Returns NO_ERROR when binds successfully, NO_MEMORY when there's no memory for allocation.
diff --git a/libs/renderengine/include/renderengine/mock/RenderEngine.h b/libs/renderengine/include/renderengine/mock/RenderEngine.h
index f099cd2..0750e86 100644
--- a/libs/renderengine/include/renderengine/mock/RenderEngine.h
+++ b/libs/renderengine/include/renderengine/mock/RenderEngine.h
@@ -43,7 +43,7 @@
MOCK_METHOD2(genTextures, void(size_t, uint32_t*));
MOCK_METHOD2(deleteTextures, void(size_t, uint32_t const*));
MOCK_METHOD2(bindExternalTextureImage, void(uint32_t, const renderengine::Image&));
- MOCK_METHOD1(cacheExternalTextureBuffer, status_t(const sp<GraphicBuffer>&));
+ MOCK_METHOD1(cacheExternalTextureBuffer, void(const sp<GraphicBuffer>&));
MOCK_METHOD3(bindExternalTextureBuffer,
status_t(uint32_t, const sp<GraphicBuffer>&, const sp<Fence>&));
MOCK_METHOD1(unbindExternalTextureBuffer, void(uint64_t));
diff --git a/libs/renderengine/tests/Android.bp b/libs/renderengine/tests/Android.bp
index 9b483ef..e98babc 100644
--- a/libs/renderengine/tests/Android.bp
+++ b/libs/renderengine/tests/Android.bp
@@ -31,6 +31,7 @@
"libgui",
"liblog",
"libnativewindow",
+ "libprocessgroup",
"libsync",
"libui",
"libutils",
diff --git a/libs/renderengine/tests/RenderEngineTest.cpp b/libs/renderengine/tests/RenderEngineTest.cpp
index 7acaecf..f47c7fd 100644
--- a/libs/renderengine/tests/RenderEngineTest.cpp
+++ b/libs/renderengine/tests/RenderEngineTest.cpp
@@ -14,8 +14,10 @@
* limitations under the License.
*/
-#include <gtest/gtest.h>
+#include <chrono>
+#include <condition_variable>
+#include <gtest/gtest.h>
#include <renderengine/RenderEngine.h>
#include <sync/sync.h>
#include <ui/PixelFormat.h>
@@ -1001,8 +1003,15 @@
invokeDraw(settings, layers, mBuffer);
uint64_t bufferId = layer.source.buffer.buffer->getId();
EXPECT_TRUE(sRE->isImageCachedForTesting(bufferId));
- sRE->unbindExternalTextureBuffer(bufferId);
+ std::shared_ptr<renderengine::gl::ImageManager::Barrier> barrier =
+ sRE->unbindExternalTextureBufferForTesting(bufferId);
+ std::lock_guard<std::mutex> lock(barrier->mutex);
+ ASSERT_TRUE(barrier->condition.wait_for(barrier->mutex, std::chrono::seconds(5),
+ [&]() REQUIRES(barrier->mutex) {
+ return barrier->isOpen;
+ }));
EXPECT_FALSE(sRE->isImageCachedForTesting(bufferId));
+ EXPECT_EQ(NO_ERROR, barrier->result);
}
TEST_F(RenderEngineTest, drawLayers_bindExternalBufferWithNullBuffer) {
@@ -1019,21 +1028,52 @@
sRE->bindExternalTextureBuffer(texName, buf, nullptr);
uint64_t bufferId = buf->getId();
EXPECT_TRUE(sRE->isImageCachedForTesting(bufferId));
- sRE->unbindExternalTextureBuffer(bufferId);
+ std::shared_ptr<renderengine::gl::ImageManager::Barrier> barrier =
+ sRE->unbindExternalTextureBufferForTesting(bufferId);
+ std::lock_guard<std::mutex> lock(barrier->mutex);
+ ASSERT_TRUE(barrier->condition.wait_for(barrier->mutex, std::chrono::seconds(5),
+ [&]() REQUIRES(barrier->mutex) {
+ return barrier->isOpen;
+ }));
+ EXPECT_EQ(NO_ERROR, barrier->result);
EXPECT_FALSE(sRE->isImageCachedForTesting(bufferId));
}
TEST_F(RenderEngineTest, drawLayers_cacheExternalBufferWithNullBuffer) {
- status_t result = sRE->cacheExternalTextureBuffer(nullptr);
- ASSERT_EQ(BAD_VALUE, result);
+ std::shared_ptr<renderengine::gl::ImageManager::Barrier> barrier =
+ sRE->cacheExternalTextureBufferForTesting(nullptr);
+ std::lock_guard<std::mutex> lock(barrier->mutex);
+ ASSERT_TRUE(barrier->condition.wait_for(barrier->mutex, std::chrono::seconds(5),
+ [&]() REQUIRES(barrier->mutex) {
+ return barrier->isOpen;
+ }));
+ EXPECT_TRUE(barrier->isOpen);
+ EXPECT_EQ(BAD_VALUE, barrier->result);
}
TEST_F(RenderEngineTest, drawLayers_cacheExternalBufferCachesImages) {
sp<GraphicBuffer> buf = allocateSourceBuffer(1, 1);
uint64_t bufferId = buf->getId();
- sRE->cacheExternalTextureBuffer(buf);
+ std::shared_ptr<renderengine::gl::ImageManager::Barrier> barrier =
+ sRE->cacheExternalTextureBufferForTesting(buf);
+ {
+ std::lock_guard<std::mutex> lock(barrier->mutex);
+ ASSERT_TRUE(barrier->condition.wait_for(barrier->mutex, std::chrono::seconds(5),
+ [&]() REQUIRES(barrier->mutex) {
+ return barrier->isOpen;
+ }));
+ EXPECT_EQ(NO_ERROR, barrier->result);
+ }
EXPECT_TRUE(sRE->isImageCachedForTesting(bufferId));
- sRE->unbindExternalTextureBuffer(bufferId);
+ barrier = sRE->unbindExternalTextureBufferForTesting(bufferId);
+ {
+ std::lock_guard<std::mutex> lock(barrier->mutex);
+ ASSERT_TRUE(barrier->condition.wait_for(barrier->mutex, std::chrono::seconds(5),
+ [&]() REQUIRES(barrier->mutex) {
+ return barrier->isOpen;
+ }));
+ EXPECT_EQ(NO_ERROR, barrier->result);
+ }
EXPECT_FALSE(sRE->isImageCachedForTesting(bufferId));
}
diff --git a/libs/sensor/ISensorServer.cpp b/libs/sensor/ISensorServer.cpp
index 5200545..8ed09f8 100644
--- a/libs/sensor/ISensorServer.cpp
+++ b/libs/sensor/ISensorServer.cpp
@@ -199,6 +199,10 @@
int32_t type = data.readInt32();
int32_t format = data.readInt32();
native_handle_t *resource = data.readNativeHandle();
+ // Avoid a crash in native_handle_close if resource is nullptr
+ if (resource == nullptr) {
+ return BAD_VALUE;
+ }
sp<ISensorEventConnection> ch =
createSensorDirectConnection(opPackageName, size, type, format, resource);
native_handle_close(resource);
diff --git a/libs/ui/Android.bp b/libs/ui/Android.bp
index 2cc6857..2bbb0ee 100644
--- a/libs/ui/Android.bp
+++ b/libs/ui/Android.bp
@@ -187,3 +187,11 @@
"tests",
"tools",
]
+
+filegroup {
+ name: "libui_host_common",
+ srcs: [
+ "Rect.cpp",
+ "PixelFormat.cpp"
+ ],
+}
diff --git a/libs/ui/GraphicBufferAllocator.cpp b/libs/ui/GraphicBufferAllocator.cpp
index 0861a1f..9c7d1fd 100644
--- a/libs/ui/GraphicBufferAllocator.cpp
+++ b/libs/ui/GraphicBufferAllocator.cpp
@@ -20,6 +20,7 @@
#include <ui/GraphicBufferAllocator.h>
+#include <limits.h>
#include <stdio.h>
#include <grallocusage/GrallocUsageConversion.h>
@@ -114,6 +115,14 @@
if (!width || !height)
width = height = 1;
+ const uint32_t bpp = bytesPerPixel(format);
+ if (std::numeric_limits<size_t>::max() / width / height < static_cast<size_t>(bpp)) {
+ ALOGE("Failed to allocate (%u x %u) layerCount %u format %d "
+ "usage %" PRIx64 ": Requesting too large a buffer size",
+ width, height, layerCount, format, usage);
+ return BAD_VALUE;
+ }
+
// Ensure that layerCount is valid.
if (layerCount < 1)
layerCount = 1;
@@ -126,7 +135,6 @@
if (error == NO_ERROR) {
Mutex::Autolock _l(sLock);
KeyedVector<buffer_handle_t, alloc_rec_t>& list(sAllocList);
- uint32_t bpp = bytesPerPixel(format);
alloc_rec_t rec;
rec.width = width;
rec.height = height;
diff --git a/libs/ui/tests/GraphicBuffer_test.cpp b/libs/ui/tests/GraphicBuffer_test.cpp
index a7c248c..5e0b094 100644
--- a/libs/ui/tests/GraphicBuffer_test.cpp
+++ b/libs/ui/tests/GraphicBuffer_test.cpp
@@ -35,6 +35,39 @@
class GraphicBufferTest : public testing::Test {};
+TEST_F(GraphicBufferTest, AllocateNoError) {
+ PixelFormat format = PIXEL_FORMAT_RGBA_8888;
+ sp<GraphicBuffer> gb(new GraphicBuffer(kTestWidth, kTestHeight, format, kTestLayerCount,
+ kTestUsage, std::string("test")));
+ ASSERT_EQ(NO_ERROR, gb->initCheck());
+}
+
+TEST_F(GraphicBufferTest, AllocateBadDimensions) {
+ PixelFormat format = PIXEL_FORMAT_RGBA_8888;
+ if (std::numeric_limits<size_t>::max() / std::numeric_limits<uint32_t>::max() /
+ bytesPerPixel(format) >=
+ std::numeric_limits<uint32_t>::max()) {
+ GTEST_SUCCEED() << "Cannot overflow with this format";
+ }
+ uint32_t width, height;
+ width = height = std::numeric_limits<uint32_t>::max();
+ sp<GraphicBuffer> gb(new GraphicBuffer(width, height, format, kTestLayerCount, kTestUsage,
+ std::string("test")));
+ ASSERT_EQ(BAD_VALUE, gb->initCheck());
+
+ const size_t targetArea = std::numeric_limits<size_t>::max() / bytesPerPixel(format);
+ const size_t widthCandidate = targetArea / std::numeric_limits<uint32_t>::max();
+ if (widthCandidate == 0) {
+ width = 1;
+ } else {
+ width = std::numeric_limits<uint32_t>::max();
+ }
+ height = (targetArea / width) + 1;
+ sp<GraphicBuffer> gb2(new GraphicBuffer(width, height, format, kTestLayerCount, kTestUsage,
+ std::string("test")));
+ ASSERT_EQ(BAD_VALUE, gb2->initCheck());
+}
+
TEST_F(GraphicBufferTest, CreateFromBufferHubBuffer) {
std::unique_ptr<BufferHubBuffer> b1 =
BufferHubBuffer::create(kTestWidth, kTestHeight, kTestLayerCount, kTestFormat,
diff --git a/libs/vr/libdisplay/include/private/dvr/display_protocol.h b/libs/vr/libdisplay/include/private/dvr/display_protocol.h
index 3786d1d..861dc6c 100644
--- a/libs/vr/libdisplay/include/private/dvr/display_protocol.h
+++ b/libs/vr/libdisplay/include/private/dvr/display_protocol.h
@@ -191,7 +191,8 @@
enum class ConfigFileType : uint32_t {
kLensMetrics,
kDeviceMetrics,
- kDeviceConfiguration
+ kDeviceConfiguration,
+ kDeviceEdid
};
struct DisplayProtocol {
diff --git a/libs/vr/libdvr/include/dvr/dvr_api.h b/libs/vr/libdvr/include/dvr/dvr_api.h
index e383bb2..b7abb99 100644
--- a/libs/vr/libdvr/include/dvr/dvr_api.h
+++ b/libs/vr/libdvr/include/dvr/dvr_api.h
@@ -85,6 +85,8 @@
DVR_CONFIGURATION_DATA_DEVICE_METRICS = 1,
// Request the per device configuration data file.
DVR_CONFIGURATION_DATA_DEVICE_CONFIG = 2,
+ // Request the edid data for the display.
+ DVR_CONFIGURATION_DATA_DEVICE_EDID = 3,
};
// dvr_display_manager.h
diff --git a/libs/vr/libvrflinger/display_service.cpp b/libs/vr/libvrflinger/display_service.cpp
index 87162c0..8980a92 100644
--- a/libs/vr/libvrflinger/display_service.cpp
+++ b/libs/vr/libvrflinger/display_service.cpp
@@ -44,6 +44,18 @@
Endpoint::Create(display::DisplayProtocol::kClientPath)) {
hardware_composer_.Initialize(
hidl, primary_display_id, request_display_callback);
+
+ uint8_t port;
+ const auto error = hidl->getDisplayIdentificationData(
+ primary_display_id, &port, &display_identification_data_);
+ if (error != android::hardware::graphics::composer::V2_1::Error::NONE) {
+ if (error !=
+ android::hardware::graphics::composer::V2_1::Error::UNSUPPORTED) {
+ ALOGI("DisplayService: identification data error\n");
+ } else {
+ ALOGI("DisplayService: identification data unsupported\n");
+ }
+ }
}
bool DisplayService::IsInitialized() const {
@@ -204,6 +216,12 @@
case display::ConfigFileType::kDeviceConfiguration:
property_name = kDvrDeviceConfigProperty;
break;
+ case display::ConfigFileType::kDeviceEdid:
+ if (display_identification_data_.size() == 0) {
+ return ErrorStatus(ENOENT);
+ }
+ return std::string(display_identification_data_.begin(),
+ display_identification_data_.end());
default:
return ErrorStatus(EINVAL);
}
diff --git a/libs/vr/libvrflinger/display_service.h b/libs/vr/libvrflinger/display_service.h
index e0f2edd..d45a61f 100644
--- a/libs/vr/libvrflinger/display_service.h
+++ b/libs/vr/libvrflinger/display_service.h
@@ -18,6 +18,8 @@
#include "epoll_event_dispatcher.h"
#include "hardware_composer.h"
+#include "DisplayHardware/DisplayIdentification.h"
+
namespace android {
namespace dvr {
@@ -117,6 +119,8 @@
DisplayService(const DisplayService&) = delete;
void operator=(const DisplayService&) = delete;
+
+ DisplayIdentificationData display_identification_data_;
};
} // namespace dvr
diff --git a/services/gpuservice/Android.bp b/services/gpuservice/Android.bp
index dbb6ba6..7b8e0f8 100644
--- a/services/gpuservice/Android.bp
+++ b/services/gpuservice/Android.bp
@@ -59,9 +59,6 @@
cc_defaults {
name: "gpuservice_binary",
defaults: ["gpuservice_defaults"],
- whole_static_libs: [
- "libsigchain",
- ],
shared_libs: [
"libbinder",
"libcutils",
diff --git a/services/gpuservice/GpuService.cpp b/services/gpuservice/GpuService.cpp
index c81ab50..e50dfca 100644
--- a/services/gpuservice/GpuService.cpp
+++ b/services/gpuservice/GpuService.cpp
@@ -28,7 +28,12 @@
#include <utils/String8.h>
#include <utils/Trace.h>
+#include <array>
+#include <fstream>
+#include <sstream>
+#include <sys/types.h>
#include <vkjson.h>
+#include <unistd.h>
#include "gpustats/GpuStats.h"
@@ -40,6 +45,7 @@
status_t cmdHelp(int out);
status_t cmdVkjson(int out, int err);
void dumpGameDriverInfo(std::string* result);
+void dumpMemoryInfo(std::string* result, const GpuMemoryMap& memories, uint32_t pid);
} // namespace
const String16 sDump("android.permission.DUMP");
@@ -72,6 +78,147 @@
mGpuStats->insertTargetStats(appPackageName, driverVersionCode, stats, value);
}
+bool isExpectedFormat(const char* str) {
+ // Should match in order:
+ // gpuaddr useraddr size id flags type usage sglen mapsize eglsrf eglimg
+ std::istringstream iss;
+ iss.str(str);
+
+ std::string word;
+ iss >> word;
+ if (word != "gpuaddr") { return false; }
+ iss >> word;
+ if (word != "useraddr") { return false; }
+ iss >> word;
+ if (word != "size") { return false; }
+ iss >> word;
+ if (word != "id") { return false; }
+ iss >> word;
+ if (word != "flags") { return false; }
+ iss >> word;
+ if (word != "type") { return false; }
+ iss >> word;
+ if (word != "usage") { return false; }
+ iss >> word;
+ if (word != "sglen") { return false; }
+ iss >> word;
+ if (word != "mapsize") { return false; }
+ iss >> word;
+ if (word != "eglsrf") { return false; }
+ iss >> word;
+ if (word != "eglimg") { return false; }
+ return true;
+}
+
+
+// Queries gpu memory via Qualcomm's /d/kgsl/proc/*/mem interface.
+status_t GpuService::getQCommGpuMemoryInfo(GpuMemoryMap* memories, std::string* result, int32_t dumpPid) const {
+ const std::string kDirectoryPath = "/d/kgsl/proc";
+ DIR* directory = opendir(kDirectoryPath.c_str());
+ if (!directory) { return PERMISSION_DENIED; }
+
+ // File Format:
+ // gpuaddr useraddr size id flags type usage sglen mapsize eglsrf eglimg
+ // 0000000000000000 0000000000000000 8359936 23 --w--pY-- gpumem VK/others( 38) 0 0 0 0
+ // 0000000000000000 0000000000000000 16293888 24 --wL--N-- ion surface 41 0 0 1
+
+ const bool dumpAll = dumpPid == 0;
+ static constexpr size_t kMaxLineLength = 1024;
+ static char line[kMaxLineLength];
+ while(dirent* subdir = readdir(directory)) {
+ // Skip "." and ".." in directory.
+ if (strcmp(subdir->d_name, ".") == 0 || strcmp(subdir->d_name, "..") == 0 ) { continue; }
+
+ std::string pid_str(subdir->d_name);
+ const uint32_t pid(stoi(pid_str));
+
+ if (!dumpAll && dumpPid != pid) {
+ continue;
+ }
+
+ std::string filepath(kDirectoryPath + "/" + pid_str + "/mem");
+ std::ifstream file(filepath);
+
+ // Check first line
+ file.getline(line, kMaxLineLength);
+ if (!isExpectedFormat(line)) {
+ continue;
+ }
+
+ if (result) {
+ StringAppendF(result, "%d:\n%s\n", pid, line);
+ }
+
+ while( file.getline(line, kMaxLineLength) ) {
+ if (result) {
+ StringAppendF(result, "%s\n", line);
+ }
+
+ std::istringstream iss;
+ iss.str(line);
+
+ // Skip gpuaddr, useraddr.
+ const char delimiter = ' ';
+ iss >> std::ws;
+ iss.ignore(kMaxLineLength, delimiter);
+ iss >> std::ws;
+ iss.ignore(kMaxLineLength, delimiter);
+
+ // Get size.
+ int64_t memsize;
+ iss >> memsize;
+
+ // Skip id, flags.
+ iss >> std::ws;
+ iss.ignore(kMaxLineLength, delimiter);
+ iss >> std::ws;
+ iss.ignore(kMaxLineLength, delimiter);
+
+ // Get type, usage.
+ std::string memtype;
+ std::string usage;
+ iss >> memtype >> usage;
+
+ // Adjust for the space in VK/others( #)
+ if (usage == "VK/others(") {
+ std::string vkTypeEnd;
+ iss >> vkTypeEnd;
+ usage.append(vkTypeEnd);
+ }
+
+ // Skip sglen.
+ iss >> std::ws;
+ iss.ignore(kMaxLineLength, delimiter);
+
+ // Get mapsize.
+ int64_t mapsize;
+ iss >> mapsize;
+
+ if (memsize == 0 && mapsize == 0) {
+ continue;
+ }
+
+ if (memtype == "gpumem") {
+ (*memories)[pid][usage].gpuMemory += memsize;
+ } else {
+ (*memories)[pid][usage].ionMemory += memsize;
+ }
+
+ if (mapsize > 0) {
+ (*memories)[pid][usage].mappedMemory += mapsize;
+ }
+ }
+
+ if (result) {
+ StringAppendF(result, "\n");
+ }
+ }
+
+ closedir(directory);
+
+ return OK;
+}
+
status_t GpuService::shellCommand(int /*in*/, int out, int err, std::vector<String16>& args) {
ATRACE_CALL();
@@ -99,24 +246,44 @@
StringAppendF(&result, "Permission Denial: can't dump gpu from pid=%d, uid=%d\n", pid, uid);
} else {
bool dumpAll = true;
- size_t index = 0;
+ bool dumpDriverInfo = false;
+ bool dumpStats = false;
+ bool dumpMemory = false;
size_t numArgs = args.size();
+ int32_t pid = 0;
if (numArgs) {
- if ((index < numArgs) && (args[index] == String16("--gpustats"))) {
- index++;
- mGpuStats->dump(args, &result);
- dumpAll = false;
+ dumpAll = false;
+ for (size_t index = 0; index < numArgs; ++index) {
+ if (args[index] == String16("--gpustats")) {
+ dumpStats = true;
+ } else if (args[index] == String16("--gpudriverinfo")) {
+ dumpDriverInfo = true;
+ } else if (args[index] == String16("--gpumem")) {
+ dumpMemory = true;
+ } else if (args[index].compare(String16("--gpumem=")) > 0) {
+ dumpMemory = true;
+ pid = atoi(String8(&args[index][9]));
+ }
}
}
- if (dumpAll) {
+ if (dumpAll || dumpDriverInfo) {
dumpGameDriverInfo(&result);
result.append("\n");
-
+ }
+ if (dumpAll || dumpStats) {
mGpuStats->dump(Vector<String16>(), &result);
result.append("\n");
}
+ if (dumpAll || dumpMemory) {
+ GpuMemoryMap memories;
+ // Currently only queries Qualcomm gpu memory. More will be added later.
+ if (getQCommGpuMemoryInfo(&memories, &result, pid) == OK) {
+ dumpMemoryInfo(&result, memories, pid);
+ result.append("\n");
+ }
+ }
}
write(fd, result.c_str(), result.size());
@@ -168,6 +335,34 @@
StringAppendF(result, "Pre-release Game Driver: %s\n", preReleaseGameDriver);
}
+// Read and print all memory info for each process from /d/kgsl/proc/<pid>/mem.
+void dumpMemoryInfo(std::string* result, const GpuMemoryMap& memories, uint32_t pid) {
+ if (!result) return;
+
+ // Write results.
+ StringAppendF(result, "GPU Memory Summary:\n");
+ for(auto& mem : memories) {
+ uint32_t process = mem.first;
+ if (pid != 0 && pid != process) {
+ continue;
+ }
+
+ StringAppendF(result, "%d:\n", process);
+ for(auto& memStruct : mem.second) {
+ StringAppendF(result, " %s", memStruct.first.c_str());
+
+ if(memStruct.second.gpuMemory > 0)
+ StringAppendF(result, ", GPU memory = %" PRId64, memStruct.second.gpuMemory);
+ if(memStruct.second.mappedMemory > 0)
+ StringAppendF(result, ", Mapped memory = %" PRId64, memStruct.second.mappedMemory);
+ if(memStruct.second.ionMemory > 0)
+ StringAppendF(result, ", Ion memory = %" PRId64, memStruct.second.ionMemory);
+
+ StringAppendF(result, "\n");
+ }
+ }
+}
+
} // anonymous namespace
} // namespace android
diff --git a/services/gpuservice/GpuService.h b/services/gpuservice/GpuService.h
index 525fb4f..b3dc2e2 100644
--- a/services/gpuservice/GpuService.h
+++ b/services/gpuservice/GpuService.h
@@ -25,11 +25,22 @@
#include <mutex>
#include <vector>
+#include <unordered_map>
namespace android {
class GpuStats;
+struct MemoryStruct {
+ int64_t gpuMemory;
+ int64_t mappedMemory;
+ int64_t ionMemory;
+};
+
+// A map that keeps track of how much memory of each type is allocated by every process.
+// Format: map[pid][memoryType] = MemoryStruct()'
+using GpuMemoryMap = std::unordered_map<int32_t, std::unordered_map<std::string, MemoryStruct>>;
+
class GpuService : public BnGpuService, public PriorityDumper {
public:
static const char* const SERVICE_NAME ANDROID_API;
@@ -71,6 +82,8 @@
status_t doDump(int fd, const Vector<String16>& args, bool asProto);
+ status_t getQCommGpuMemoryInfo(GpuMemoryMap* memories, std::string* result, int32_t dumpPid) const;
+
/*
* Attributes
*/
diff --git a/services/inputflinger/EventHub.h b/services/inputflinger/EventHub.h
index eb4e8f2..6c3a4a2 100644
--- a/services/inputflinger/EventHub.h
+++ b/services/inputflinger/EventHub.h
@@ -146,12 +146,11 @@
* which keys are currently down. Finally, the event hub keeps track of the capabilities of
* individual input devices, such as their class and the set of key codes that they support.
*/
-class EventHubInterface : public virtual RefBase {
-protected:
+class EventHubInterface {
+public:
EventHubInterface() { }
virtual ~EventHubInterface() { }
-public:
// Synthetic raw event type codes produced when devices are added or removed.
enum {
// Sent when a device is added.
@@ -319,7 +318,6 @@
virtual void dump(std::string& dump);
virtual void monitor();
-protected:
virtual ~EventHub();
private:
diff --git a/services/inputflinger/InputDispatcher.cpp b/services/inputflinger/InputDispatcher.cpp
index be13707..019815c 100644
--- a/services/inputflinger/InputDispatcher.cpp
+++ b/services/inputflinger/InputDispatcher.cpp
@@ -253,9 +253,17 @@
}
}
-template<typename T, typename U>
-static T getValueByKey(std::unordered_map<U, T>& map, U key) {
- typename std::unordered_map<U, T>::const_iterator it = map.find(key);
+/**
+ * Find the entry in std::unordered_map by key, and return it.
+ * If the entry is not found, return a default constructed entry.
+ *
+ * Useful when the entries are vectors, since an empty vector will be returned
+ * if the entry is not found.
+ * Also useful when the entries are sp<>. If an entry is not found, nullptr is returned.
+ */
+template <typename T, typename U>
+static T getValueByKey(const std::unordered_map<U, T>& map, U key) {
+ auto it = map.find(key);
return it != map.end() ? it->second : T{};
}
@@ -707,7 +715,7 @@
CommandEntry* commandEntry = mCommandQueue.dequeueAtHead();
Command command = commandEntry->command;
- (this->*command)(commandEntry); // commands are implicitly 'LockedInterruptible'
+ command(*this, commandEntry); // commands are implicitly 'LockedInterruptible'
commandEntry->connection.clear();
delete commandEntry;
@@ -801,8 +809,8 @@
resetKeyRepeatLocked();
// Enqueue a command to run outside the lock to tell the policy that the configuration changed.
- CommandEntry* commandEntry = postCommandLocked(
- & InputDispatcher::doNotifyConfigurationChangedLockedInterruptible);
+ CommandEntry* commandEntry =
+ postCommandLocked(&InputDispatcher::doNotifyConfigurationChangedLockedInterruptible);
commandEntry->eventTime = entry->eventTime;
return true;
}
@@ -876,7 +884,7 @@
if (entry->interceptKeyResult == KeyEntry::INTERCEPT_KEY_RESULT_UNKNOWN) {
if (entry->policyFlags & POLICY_FLAG_PASS_TO_USER) {
CommandEntry* commandEntry = postCommandLocked(
- & InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible);
+ &InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible);
sp<InputWindowHandle> focusedWindowHandle =
getValueByKey(mFocusedWindowHandlesByDisplay, getTargetDisplayId(entry));
if (focusedWindowHandle != nullptr) {
@@ -1974,8 +1982,8 @@
}
}
- CommandEntry* commandEntry = postCommandLocked(
- & InputDispatcher::doPokeUserActivityLockedInterruptible);
+ CommandEntry* commandEntry =
+ postCommandLocked(&InputDispatcher::doPokeUserActivityLockedInterruptible);
commandEntry->eventTime = eventEntry->eventTime;
commandEntry->userActivityEventType = eventType;
}
@@ -2192,8 +2200,8 @@
return;
}
- CommandEntry* commandEntry = postCommandLocked(
- & InputDispatcher::doOnPointerDownOutsideFocusLockedInterruptible);
+ CommandEntry* commandEntry =
+ postCommandLocked(&InputDispatcher::doOnPointerDownOutsideFocusLockedInterruptible);
commandEntry->newToken = newToken;
}
@@ -2766,7 +2774,7 @@
", policyFlags=0x%x, "
"action=0x%x, actionButton=0x%x, flags=0x%x, metaState=0x%x, buttonState=0x%x, "
"edgeFlags=0x%x, xPrecision=%f, yPrecision=%f, xCursorPosition=%f, "
- "mYCursorPosition=%f, downTime=%" PRId64,
+ "yCursorPosition=%f, downTime=%" PRId64,
args->eventTime, args->deviceId, args->source, args->displayId, args->policyFlags,
args->action, args->actionButton, args->flags, args->metaState, args->buttonState,
args->edgeFlags, args->xPrecision, args->yPrecision, arg->xCursorPosition,
@@ -3144,14 +3152,7 @@
std::vector<sp<InputWindowHandle>> InputDispatcher::getWindowHandlesLocked(
int32_t displayId) const {
- std::unordered_map<int32_t, std::vector<sp<InputWindowHandle>>>::const_iterator it =
- mWindowHandlesByDisplay.find(displayId);
- if(it != mWindowHandlesByDisplay.end()) {
- return it->second;
- }
-
- // Return an empty one if nothing found.
- return std::vector<sp<InputWindowHandle>>();
+ return getValueByKey(mWindowHandlesByDisplay, displayId);
}
sp<InputWindowHandle> InputDispatcher::getWindowHandleLocked(
@@ -3193,6 +3194,63 @@
return mInputChannelsByToken.at(token);
}
+void InputDispatcher::updateWindowHandlesForDisplayLocked(
+ const std::vector<sp<InputWindowHandle>>& inputWindowHandles, int32_t displayId) {
+ if (inputWindowHandles.empty()) {
+ // Remove all handles on a display if there are no windows left.
+ mWindowHandlesByDisplay.erase(displayId);
+ return;
+ }
+
+ // Since we compare the pointer of input window handles across window updates, we need
+ // to make sure the handle object for the same window stays unchanged across updates.
+ const std::vector<sp<InputWindowHandle>>& oldHandles = getWindowHandlesLocked(displayId);
+ std::unordered_map<sp<IBinder>, sp<InputWindowHandle>, IBinderHash> oldHandlesByTokens;
+ for (const sp<InputWindowHandle>& handle : oldHandles) {
+ oldHandlesByTokens[handle->getToken()] = handle;
+ }
+
+ std::vector<sp<InputWindowHandle>> newHandles;
+ for (const sp<InputWindowHandle>& handle : inputWindowHandles) {
+ if (!handle->updateInfo()) {
+ // handle no longer valid
+ continue;
+ }
+
+ const InputWindowInfo* info = handle->getInfo();
+ if ((getInputChannelLocked(handle->getToken()) == nullptr &&
+ info->portalToDisplayId == ADISPLAY_ID_NONE)) {
+ const bool noInputChannel =
+ info->inputFeatures & InputWindowInfo::INPUT_FEATURE_NO_INPUT_CHANNEL;
+ const bool canReceiveInput =
+ !(info->layoutParamsFlags & InputWindowInfo::FLAG_NOT_TOUCHABLE) ||
+ !(info->layoutParamsFlags & InputWindowInfo::FLAG_NOT_FOCUSABLE);
+ if (canReceiveInput && !noInputChannel) {
+ ALOGE("Window handle %s has no registered input channel",
+ handle->getName().c_str());
+ }
+ continue;
+ }
+
+ if (info->displayId != displayId) {
+ ALOGE("Window %s updated by wrong display %d, should belong to display %d",
+ handle->getName().c_str(), displayId, info->displayId);
+ continue;
+ }
+
+ if (oldHandlesByTokens.find(handle->getToken()) != oldHandlesByTokens.end()) {
+ const sp<InputWindowHandle> oldHandle = oldHandlesByTokens.at(handle->getToken());
+ oldHandle->updateFrom(handle);
+ newHandles.push_back(oldHandle);
+ } else {
+ newHandles.push_back(handle);
+ }
+ }
+
+ // Insert or replace
+ mWindowHandlesByDisplay[displayId] = newHandles;
+}
+
/**
* Called from InputManagerService, update window handle list by displayId that can receive input.
* A window handle contains information about InputChannel, Touch Region, Types, Focused,...
@@ -3212,73 +3270,19 @@
const std::vector<sp<InputWindowHandle>> oldWindowHandles =
getWindowHandlesLocked(displayId);
+ updateWindowHandlesForDisplayLocked(inputWindowHandles, displayId);
+
sp<InputWindowHandle> newFocusedWindowHandle = nullptr;
bool foundHoveredWindow = false;
-
- if (inputWindowHandles.empty()) {
- // Remove all handles on a display if there are no windows left.
- mWindowHandlesByDisplay.erase(displayId);
- } else {
- // Since we compare the pointer of input window handles across window updates, we need
- // to make sure the handle object for the same window stays unchanged across updates.
- const std::vector<sp<InputWindowHandle>>& oldHandles =
- mWindowHandlesByDisplay[displayId];
- std::unordered_map<sp<IBinder>, sp<InputWindowHandle>, IBinderHash> oldHandlesByTokens;
- for (const sp<InputWindowHandle>& handle : oldHandles) {
- oldHandlesByTokens[handle->getToken()] = handle;
+ for (const sp<InputWindowHandle>& windowHandle : getWindowHandlesLocked(displayId)) {
+ // Set newFocusedWindowHandle to the top most focused window instead of the last one
+ if (!newFocusedWindowHandle && windowHandle->getInfo()->hasFocus &&
+ windowHandle->getInfo()->visible) {
+ newFocusedWindowHandle = windowHandle;
}
-
- std::vector<sp<InputWindowHandle>> newHandles;
- for (const sp<InputWindowHandle>& handle : inputWindowHandles) {
- if (!handle->updateInfo()) {
- // handle no longer valid
- continue;
- }
- const InputWindowInfo* info = handle->getInfo();
-
- if ((getInputChannelLocked(handle->getToken()) == nullptr &&
- info->portalToDisplayId == ADISPLAY_ID_NONE)) {
- const bool noInputChannel =
- info->inputFeatures & InputWindowInfo::INPUT_FEATURE_NO_INPUT_CHANNEL;
- const bool canReceiveInput =
- !(info->layoutParamsFlags & InputWindowInfo::FLAG_NOT_TOUCHABLE) ||
- !(info->layoutParamsFlags & InputWindowInfo::FLAG_NOT_FOCUSABLE);
- if (canReceiveInput && !noInputChannel) {
- ALOGE("Window handle %s has no registered input channel",
- handle->getName().c_str());
- }
- continue;
- }
-
- if (info->displayId != displayId) {
- ALOGE("Window %s updated by wrong display %d, should belong to display %d",
- handle->getName().c_str(), displayId, info->displayId);
- continue;
- }
-
- if (oldHandlesByTokens.find(handle->getToken()) != oldHandlesByTokens.end()) {
- const sp<InputWindowHandle> oldHandle =
- oldHandlesByTokens.at(handle->getToken());
- oldHandle->updateFrom(handle);
- newHandles.push_back(oldHandle);
- } else {
- newHandles.push_back(handle);
- }
+ if (windowHandle == mLastHoverWindowHandle) {
+ foundHoveredWindow = true;
}
-
- for (const sp<InputWindowHandle>& windowHandle : newHandles) {
- // Set newFocusedWindowHandle to the top most focused window instead of the last one
- if (!newFocusedWindowHandle && windowHandle->getInfo()->hasFocus
- && windowHandle->getInfo()->visible) {
- newFocusedWindowHandle = windowHandle;
- }
- if (windowHandle == mLastHoverWindowHandle) {
- foundHoveredWindow = true;
- }
- }
-
- // Insert or replace
- mWindowHandlesByDisplay[displayId] = newHandles;
}
if (!foundHoveredWindow) {
@@ -4083,8 +4087,8 @@
void InputDispatcher::onDispatchCycleFinishedLocked(
nsecs_t currentTime, const sp<Connection>& connection, uint32_t seq, bool handled) {
- CommandEntry* commandEntry = postCommandLocked(
- & InputDispatcher::doDispatchCycleFinishedLockedInterruptible);
+ CommandEntry* commandEntry =
+ postCommandLocked(&InputDispatcher::doDispatchCycleFinishedLockedInterruptible);
commandEntry->connection = connection;
commandEntry->eventTime = currentTime;
commandEntry->seq = seq;
@@ -4096,8 +4100,8 @@
ALOGE("channel '%s' ~ Channel is unrecoverably broken and will be disposed!",
connection->getInputChannelName().c_str());
- CommandEntry* commandEntry = postCommandLocked(
- & InputDispatcher::doNotifyInputChannelBrokenLockedInterruptible);
+ CommandEntry* commandEntry =
+ postCommandLocked(&InputDispatcher::doNotifyInputChannelBrokenLockedInterruptible);
commandEntry->connection = connection;
}
@@ -4105,8 +4109,8 @@
const sp<InputWindowHandle>& newFocus) {
sp<IBinder> oldToken = oldFocus != nullptr ? oldFocus->getToken() : nullptr;
sp<IBinder> newToken = newFocus != nullptr ? newFocus->getToken() : nullptr;
- CommandEntry* commandEntry = postCommandLocked(
- & InputDispatcher::doNotifyFocusChangedLockedInterruptible);
+ CommandEntry* commandEntry =
+ postCommandLocked(&InputDispatcher::doNotifyFocusChangedLockedInterruptible);
commandEntry->oldToken = oldToken;
commandEntry->newToken = newToken;
}
@@ -4138,8 +4142,8 @@
mLastANRState += StringPrintf(INDENT2 "Reason: %s\n", reason);
dumpDispatchStateLocked(mLastANRState);
- CommandEntry* commandEntry = postCommandLocked(
- & InputDispatcher::doNotifyANRLockedInterruptible);
+ CommandEntry* commandEntry =
+ postCommandLocked(&InputDispatcher::doNotifyANRLockedInterruptible);
commandEntry->inputApplicationHandle = applicationHandle;
commandEntry->inputChannel = windowHandle != nullptr ?
getInputChannelLocked(windowHandle->getToken()) : nullptr;
@@ -4233,53 +4237,55 @@
void InputDispatcher::doDispatchCycleFinishedLockedInterruptible(
CommandEntry* commandEntry) {
sp<Connection> connection = commandEntry->connection;
- nsecs_t finishTime = commandEntry->eventTime;
+ const nsecs_t finishTime = commandEntry->eventTime;
uint32_t seq = commandEntry->seq;
- bool handled = commandEntry->handled;
+ const bool handled = commandEntry->handled;
// Handle post-event policy actions.
DispatchEntry* dispatchEntry = connection->findWaitQueueEntry(seq);
- if (dispatchEntry) {
- nsecs_t eventDuration = finishTime - dispatchEntry->deliveryTime;
- if (eventDuration > SLOW_EVENT_PROCESSING_WARNING_TIMEOUT) {
- std::string msg =
- StringPrintf("Window '%s' spent %0.1fms processing the last input event: ",
- connection->getWindowName().c_str(), eventDuration * 0.000001f);
- dispatchEntry->eventEntry->appendDescription(msg);
- ALOGI("%s", msg.c_str());
- }
-
- bool restartEvent;
- if (dispatchEntry->eventEntry->type == EventEntry::TYPE_KEY) {
- KeyEntry* keyEntry = static_cast<KeyEntry*>(dispatchEntry->eventEntry);
- restartEvent = afterKeyEventLockedInterruptible(connection,
- dispatchEntry, keyEntry, handled);
- } else if (dispatchEntry->eventEntry->type == EventEntry::TYPE_MOTION) {
- MotionEntry* motionEntry = static_cast<MotionEntry*>(dispatchEntry->eventEntry);
- restartEvent = afterMotionEventLockedInterruptible(connection,
- dispatchEntry, motionEntry, handled);
- } else {
- restartEvent = false;
- }
-
- // Dequeue the event and start the next cycle.
- // Note that because the lock might have been released, it is possible that the
- // contents of the wait queue to have been drained, so we need to double-check
- // a few things.
- if (dispatchEntry == connection->findWaitQueueEntry(seq)) {
- connection->waitQueue.dequeue(dispatchEntry);
- traceWaitQueueLength(connection);
- if (restartEvent && connection->status == Connection::STATUS_NORMAL) {
- connection->outboundQueue.enqueueAtHead(dispatchEntry);
- traceOutboundQueueLength(connection);
- } else {
- releaseDispatchEntry(dispatchEntry);
- }
- }
-
- // Start the next dispatch cycle for this connection.
- startDispatchCycleLocked(now(), connection);
+ if (!dispatchEntry) {
+ return;
}
+
+ nsecs_t eventDuration = finishTime - dispatchEntry->deliveryTime;
+ if (eventDuration > SLOW_EVENT_PROCESSING_WARNING_TIMEOUT) {
+ std::string msg =
+ StringPrintf("Window '%s' spent %0.1fms processing the last input event: ",
+ connection->getWindowName().c_str(), eventDuration * 0.000001f);
+ dispatchEntry->eventEntry->appendDescription(msg);
+ ALOGI("%s", msg.c_str());
+ }
+
+ bool restartEvent;
+ if (dispatchEntry->eventEntry->type == EventEntry::TYPE_KEY) {
+ KeyEntry* keyEntry = static_cast<KeyEntry*>(dispatchEntry->eventEntry);
+ restartEvent =
+ afterKeyEventLockedInterruptible(connection, dispatchEntry, keyEntry, handled);
+ } else if (dispatchEntry->eventEntry->type == EventEntry::TYPE_MOTION) {
+ MotionEntry* motionEntry = static_cast<MotionEntry*>(dispatchEntry->eventEntry);
+ restartEvent = afterMotionEventLockedInterruptible(connection, dispatchEntry, motionEntry,
+ handled);
+ } else {
+ restartEvent = false;
+ }
+
+ // Dequeue the event and start the next cycle.
+ // Note that because the lock might have been released, it is possible that the
+ // contents of the wait queue to have been drained, so we need to double-check
+ // a few things.
+ if (dispatchEntry == connection->findWaitQueueEntry(seq)) {
+ connection->waitQueue.dequeue(dispatchEntry);
+ traceWaitQueueLength(connection);
+ if (restartEvent && connection->status == Connection::STATUS_NORMAL) {
+ connection->outboundQueue.enqueueAtHead(dispatchEntry);
+ traceOutboundQueueLength(connection);
+ } else {
+ releaseDispatchEntry(dispatchEntry);
+ }
+ }
+
+ // Start the next dispatch cycle for this connection.
+ startDispatchCycleLocked(now(), connection);
}
bool InputDispatcher::afterKeyEventLockedInterruptible(const sp<Connection>& connection,
diff --git a/services/inputflinger/InputDispatcher.h b/services/inputflinger/InputDispatcher.h
index 46dd9bd..147437c 100644
--- a/services/inputflinger/InputDispatcher.h
+++ b/services/inputflinger/InputDispatcher.h
@@ -644,7 +644,7 @@
//
// Commands are implicitly 'LockedInterruptible'.
struct CommandEntry;
- typedef void (InputDispatcher::*Command)(CommandEntry* commandEntry);
+ typedef std::function<void(InputDispatcher&, CommandEntry*)> Command;
class Connection;
struct CommandEntry : Link<CommandEntry> {
@@ -1055,6 +1055,13 @@
sp<InputChannel> getInputChannelLocked(const sp<IBinder>& windowToken) const REQUIRES(mLock);
bool hasWindowHandleLocked(const sp<InputWindowHandle>& windowHandle) const REQUIRES(mLock);
+ /*
+ * Validate and update InputWindowHandles for a given display.
+ */
+ void updateWindowHandlesForDisplayLocked(
+ const std::vector<sp<InputWindowHandle>>& inputWindowHandles, int32_t displayId)
+ REQUIRES(mLock);
+
// Focus tracking for keys, trackball, etc.
std::unordered_map<int32_t, sp<InputWindowHandle>> mFocusedWindowHandlesByDisplay
GUARDED_BY(mLock);
diff --git a/services/inputflinger/InputReader.cpp b/services/inputflinger/InputReader.cpp
index d565e3a..4631bec 100644
--- a/services/inputflinger/InputReader.cpp
+++ b/services/inputflinger/InputReader.cpp
@@ -256,12 +256,17 @@
// --- InputReader ---
-InputReader::InputReader(const sp<EventHubInterface>& eventHub,
- const sp<InputReaderPolicyInterface>& policy,
- const sp<InputListenerInterface>& listener) :
- mContext(this), mEventHub(eventHub), mPolicy(policy),
- mNextSequenceNum(1), mGlobalMetaState(0), mGeneration(1),
- mDisableVirtualKeysTimeout(LLONG_MIN), mNextTimeout(LLONG_MAX),
+InputReader::InputReader(std::shared_ptr<EventHubInterface> eventHub,
+ const sp<InputReaderPolicyInterface>& policy,
+ const sp<InputListenerInterface>& listener)
+ : mContext(this),
+ mEventHub(eventHub),
+ mPolicy(policy),
+ mNextSequenceNum(1),
+ mGlobalMetaState(0),
+ mGeneration(1),
+ mDisableVirtualKeysTimeout(LLONG_MIN),
+ mNextTimeout(LLONG_MAX),
mConfigurationChangesToRefresh(0) {
mQueuedListener = new QueuedInputListener(listener);
@@ -1090,8 +1095,8 @@
}
if (!changes || (changes & InputReaderConfiguration::CHANGE_ENABLED_STATE)) {
- ssize_t index = config->disabledDevices.indexOf(mId);
- bool enabled = index < 0;
+ auto it = config->disabledDevices.find(mId);
+ bool enabled = it == config->disabledDevices.end();
setEnabled(enabled, when);
}
diff --git a/services/inputflinger/InputReader.h b/services/inputflinger/InputReader.h
index e434869..b7f94c1 100644
--- a/services/inputflinger/InputReader.h
+++ b/services/inputflinger/InputReader.h
@@ -114,9 +114,9 @@
*/
class InputReader : public InputReaderInterface {
public:
- InputReader(const sp<EventHubInterface>& eventHub,
- const sp<InputReaderPolicyInterface>& policy,
- const sp<InputListenerInterface>& listener);
+ InputReader(std::shared_ptr<EventHubInterface> eventHub,
+ const sp<InputReaderPolicyInterface>& policy,
+ const sp<InputListenerInterface>& listener);
virtual ~InputReader();
virtual void dump(std::string& dump);
@@ -181,7 +181,10 @@
Condition mReaderIsAliveCondition;
- sp<EventHubInterface> mEventHub;
+ // This could be unique_ptr, but due to the way InputReader tests are written,
+ // it is made shared_ptr here. In the tests, an EventHub reference is retained by the test
+ // in parallel to passing it to the InputReader.
+ std::shared_ptr<EventHubInterface> mEventHub;
sp<InputReaderPolicyInterface> mPolicy;
sp<QueuedInputListener> mQueuedListener;
diff --git a/services/inputflinger/InputReaderFactory.cpp b/services/inputflinger/InputReaderFactory.cpp
index 3534f6b..072499b 100644
--- a/services/inputflinger/InputReaderFactory.cpp
+++ b/services/inputflinger/InputReaderFactory.cpp
@@ -22,7 +22,7 @@
sp<InputReaderInterface> createInputReader(
const sp<InputReaderPolicyInterface>& policy,
const sp<InputListenerInterface>& listener) {
- return new InputReader(new EventHub(), policy, listener);
+ return new InputReader(std::make_unique<EventHub>(), policy, listener);
}
} // namespace android
\ No newline at end of file
diff --git a/services/inputflinger/include/InputReaderBase.h b/services/inputflinger/include/InputReaderBase.h
index 64c5257..5d576b9 100644
--- a/services/inputflinger/include/InputReaderBase.h
+++ b/services/inputflinger/include/InputReaderBase.h
@@ -26,11 +26,11 @@
#include <input/VelocityTracker.h>
#include <utils/Thread.h>
#include <utils/RefBase.h>
-#include <utils/SortedVector.h>
-#include <optional>
#include <stddef.h>
#include <unistd.h>
+#include <optional>
+#include <set>
#include <unordered_map>
#include <vector>
@@ -249,7 +249,7 @@
bool pointerCapture;
// The set of currently disabled input devices.
- SortedVector<int32_t> disabledDevices;
+ std::set<int32_t> disabledDevices;
InputReaderConfiguration() :
virtualKeyQuietTime(0),
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index e108834..d95ac96 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -202,21 +202,9 @@
mConfig.portAssociations.insert({inputPort, displayPort});
}
- void addDisabledDevice(int32_t deviceId) {
- ssize_t index = mConfig.disabledDevices.indexOf(deviceId);
- bool currentlyEnabled = index < 0;
- if (currentlyEnabled) {
- mConfig.disabledDevices.add(deviceId);
- }
- }
+ void addDisabledDevice(int32_t deviceId) { mConfig.disabledDevices.insert(deviceId); }
- void removeDisabledDevice(int32_t deviceId) {
- ssize_t index = mConfig.disabledDevices.indexOf(deviceId);
- bool currentlyEnabled = index < 0;
- if (!currentlyEnabled) {
- mConfig.disabledDevices.remove(deviceId);
- }
- }
+ void removeDisabledDevice(int32_t deviceId) { mConfig.disabledDevices.erase(deviceId); }
void setPointerController(int32_t deviceId, const sp<FakePointerController>& controller) {
mPointerControllers.add(deviceId, controller);
@@ -337,14 +325,13 @@
List<RawEvent> mEvents;
std::unordered_map<int32_t /*deviceId*/, std::vector<TouchVideoFrame>> mVideoFrames;
-protected:
+public:
virtual ~FakeEventHub() {
for (size_t i = 0; i < mDevices.size(); i++) {
delete mDevices.valueAt(i);
}
}
-public:
FakeEventHub() { }
void addDevice(int32_t deviceId, const std::string& name, uint32_t classes) {
@@ -772,7 +759,7 @@
// --- FakeInputReaderContext ---
class FakeInputReaderContext : public InputReaderContext {
- sp<EventHubInterface> mEventHub;
+ std::shared_ptr<EventHubInterface> mEventHub;
sp<InputReaderPolicyInterface> mPolicy;
sp<InputListenerInterface> mListener;
int32_t mGlobalMetaState;
@@ -781,12 +768,14 @@
uint32_t mNextSequenceNum;
public:
- FakeInputReaderContext(const sp<EventHubInterface>& eventHub,
- const sp<InputReaderPolicyInterface>& policy,
- const sp<InputListenerInterface>& listener) :
- mEventHub(eventHub), mPolicy(policy), mListener(listener),
- mGlobalMetaState(0), mNextSequenceNum(1) {
- }
+ FakeInputReaderContext(std::shared_ptr<EventHubInterface> eventHub,
+ const sp<InputReaderPolicyInterface>& policy,
+ const sp<InputListenerInterface>& listener)
+ : mEventHub(eventHub),
+ mPolicy(policy),
+ mListener(listener),
+ mGlobalMetaState(0),
+ mNextSequenceNum(1) {}
virtual ~FakeInputReaderContext() { }
@@ -1011,12 +1000,10 @@
InputDevice* mNextDevice;
public:
- InstrumentedInputReader(const sp<EventHubInterface>& eventHub,
- const sp<InputReaderPolicyInterface>& policy,
- const sp<InputListenerInterface>& listener) :
- InputReader(eventHub, policy, listener),
- mNextDevice(nullptr) {
- }
+ InstrumentedInputReader(std::shared_ptr<EventHubInterface> eventHub,
+ const sp<InputReaderPolicyInterface>& policy,
+ const sp<InputListenerInterface>& listener)
+ : InputReader(eventHub, policy, listener), mNextDevice(nullptr) {}
virtual ~InstrumentedInputReader() {
if (mNextDevice) {
@@ -1244,11 +1231,11 @@
protected:
sp<TestInputListener> mFakeListener;
sp<FakeInputReaderPolicy> mFakePolicy;
- sp<FakeEventHub> mFakeEventHub;
+ std::shared_ptr<FakeEventHub> mFakeEventHub;
sp<InstrumentedInputReader> mReader;
virtual void SetUp() {
- mFakeEventHub = new FakeEventHub();
+ mFakeEventHub = std::make_unique<FakeEventHub>();
mFakePolicy = new FakeInputReaderPolicy();
mFakeListener = new TestInputListener();
@@ -1260,7 +1247,6 @@
mFakeListener.clear();
mFakePolicy.clear();
- mFakeEventHub.clear();
}
void addDevice(int32_t deviceId, const std::string& name, uint32_t classes,
@@ -1587,7 +1573,7 @@
static const int32_t DEVICE_CONTROLLER_NUMBER;
static const uint32_t DEVICE_CLASSES;
- sp<FakeEventHub> mFakeEventHub;
+ std::shared_ptr<FakeEventHub> mFakeEventHub;
sp<FakeInputReaderPolicy> mFakePolicy;
sp<TestInputListener> mFakeListener;
FakeInputReaderContext* mFakeContext;
@@ -1595,7 +1581,7 @@
InputDevice* mDevice;
virtual void SetUp() {
- mFakeEventHub = new FakeEventHub();
+ mFakeEventHub = std::make_unique<FakeEventHub>();
mFakePolicy = new FakeInputReaderPolicy();
mFakeListener = new TestInputListener();
mFakeContext = new FakeInputReaderContext(mFakeEventHub, mFakePolicy, mFakeListener);
@@ -1613,7 +1599,6 @@
delete mFakeContext;
mFakeListener.clear();
mFakePolicy.clear();
- mFakeEventHub.clear();
}
};
@@ -1782,14 +1767,14 @@
static const int32_t DEVICE_CONTROLLER_NUMBER;
static const uint32_t DEVICE_CLASSES;
- sp<FakeEventHub> mFakeEventHub;
+ std::shared_ptr<FakeEventHub> mFakeEventHub;
sp<FakeInputReaderPolicy> mFakePolicy;
sp<TestInputListener> mFakeListener;
FakeInputReaderContext* mFakeContext;
InputDevice* mDevice;
virtual void SetUp() {
- mFakeEventHub = new FakeEventHub();
+ mFakeEventHub = std::make_unique<FakeEventHub>();
mFakePolicy = new FakeInputReaderPolicy();
mFakeListener = new TestInputListener();
mFakeContext = new FakeInputReaderContext(mFakeEventHub, mFakePolicy, mFakeListener);
@@ -1807,7 +1792,6 @@
delete mFakeContext;
mFakeListener.clear();
mFakePolicy.clear();
- mFakeEventHub.clear();
}
void addConfigurationProperty(const char* key, const char* value) {
diff --git a/services/nativeperms/.clang-format b/services/nativeperms/.clang-format
deleted file mode 100644
index 6006e6f..0000000
--- a/services/nativeperms/.clang-format
+++ /dev/null
@@ -1,13 +0,0 @@
-BasedOnStyle: Google
-AllowShortFunctionsOnASingleLine: Inline
-AllowShortIfStatementsOnASingleLine: true
-AllowShortLoopsOnASingleLine: true
-BinPackArguments: true
-BinPackParameters: true
-ColumnLimit: 80
-CommentPragmas: NOLINT:.*
-ContinuationIndentWidth: 8
-DerivePointerAlignment: false
-IndentWidth: 4
-PointerAlignment: Left
-TabWidth: 4
diff --git a/services/nativeperms/Android.bp b/services/nativeperms/Android.bp
deleted file mode 100644
index cbc7d66..0000000
--- a/services/nativeperms/Android.bp
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright 2016 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-
-cc_binary {
- name: "nativeperms",
- srcs: [
- "nativeperms.cpp",
- "android/os/IPermissionController.aidl",
- ],
- cflags: [
- "-Wall",
- "-Werror",
- ],
- shared_libs: [
- "libbinder",
- "libbrillo",
- "libbrillo-binder",
- "libchrome",
- "libutils",
- ],
- init_rc: ["nativeperms.rc"],
-}
diff --git a/services/nativeperms/android/os/IPermissionController.aidl b/services/nativeperms/android/os/IPermissionController.aidl
deleted file mode 100644
index 89db85c..0000000
--- a/services/nativeperms/android/os/IPermissionController.aidl
+++ /dev/null
@@ -1,25 +0,0 @@
-/* //device/java/android/android/os/IPowerManager.aidl
-**
-** Copyright 2007, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-package android.os;
-
-/** @hide */
-interface IPermissionController {
- boolean checkPermission(String permission, int pid, int uid);
- String[] getPackagesForUid(int uid);
- boolean isRuntimePermission(String permission);
-}
diff --git a/services/nativeperms/android/os/README b/services/nativeperms/android/os/README
deleted file mode 100644
index e414499..0000000
--- a/services/nativeperms/android/os/README
+++ /dev/null
@@ -1,4 +0,0 @@
-IPermissionController.aidl in this directory is a verbatim copy of
-https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/os/IPermissionController.aidl,
-because some Brillo manifests do not currently include the frameworks/base repo.
-TODO(jorgelo): Figure out a way to use the .aidl file in frameworks/base.
diff --git a/services/nativeperms/nativeperms.cpp b/services/nativeperms/nativeperms.cpp
deleted file mode 100644
index 7f03bed..0000000
--- a/services/nativeperms/nativeperms.cpp
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Copyright 2016 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 <base/at_exit.h>
-#include <base/logging.h>
-#include <base/message_loop/message_loop.h>
-#include <binder/IServiceManager.h>
-#include <binder/Status.h>
-#include <brillo/binder_watcher.h>
-#include <brillo/message_loops/base_message_loop.h>
-#include <brillo/syslog_logging.h>
-#include <utils/String16.h>
-
-#include "android/os/BnPermissionController.h"
-
-namespace {
-static android::String16 serviceName("permission");
-}
-
-namespace android {
-
-class PermissionService : public android::os::BnPermissionController {
- public:
- ::android::binder::Status checkPermission(
- const ::android::String16& permission, int32_t pid, int32_t uid,
- bool* _aidl_return) {
- (void)permission;
- (void)pid;
- (void)uid;
- *_aidl_return = true;
- return binder::Status::ok();
- }
-
- ::android::binder::Status getPackagesForUid(
- int32_t uid, ::std::vector<::android::String16>* _aidl_return) {
- (void)uid;
- // Brillo doesn't currently have installable packages.
- if (_aidl_return) {
- _aidl_return->clear();
- }
- return binder::Status::ok();
- }
-
- ::android::binder::Status isRuntimePermission(
- const ::android::String16& permission, bool* _aidl_return) {
- (void)permission;
- // Brillo doesn't currently have runtime permissions.
- *_aidl_return = false;
- return binder::Status::ok();
- }
-};
-
-} // namespace android
-
-int main() {
- base::AtExitManager atExitManager;
- brillo::InitLog(brillo::kLogToSyslog);
- // Register the service with servicemanager.
- android::status_t status = android::defaultServiceManager()->addService(
- serviceName, new android::PermissionService());
- CHECK(status == android::OK) << "Failed to get IPermissionController "
- "binder from servicemanager.";
-
- // Create a message loop.
- base::MessageLoopForIO messageLoopForIo;
- brillo::BaseMessageLoop messageLoop{&messageLoopForIo};
-
- // Initialize a binder watcher.
- brillo::BinderWatcher watcher(&messageLoop);
- watcher.Init();
-
- // Run the message loop.
- messageLoop.Run();
-}
diff --git a/services/nativeperms/nativeperms.rc b/services/nativeperms/nativeperms.rc
deleted file mode 100644
index 704c0a2..0000000
--- a/services/nativeperms/nativeperms.rc
+++ /dev/null
@@ -1,4 +0,0 @@
-service nativeperms /system/bin/nativeperms
- class main
- user system
- group system
diff --git a/services/sensorservice/SensorDevice.cpp b/services/sensorservice/SensorDevice.cpp
index 717f317..c7a8f5b 100644
--- a/services/sensorservice/SensorDevice.cpp
+++ b/services/sensorservice/SensorDevice.cpp
@@ -134,7 +134,12 @@
mActivationCount.add(list[i].sensorHandle, model);
- checkReturn(mSensors->activate(list[i].sensorHandle, 0 /* enabled */));
+ // Only disable all sensors on HAL 1.0 since HAL 2.0
+ // handles this in its initialize method
+ if (!mSensors->supportsMessageQueues()) {
+ checkReturn(mSensors->activate(list[i].sensorHandle,
+ 0 /* enabled */));
+ }
}
}));
}
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index 6e953f4..965d8f4 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -187,9 +187,6 @@
cflags: [
"-DLOG_TAG=\"SurfaceFlinger\"",
],
- whole_static_libs: [
- "libsigchain",
- ],
shared_libs: [
"android.frameworks.displayservice@1.0",
"android.hardware.configstore-utils",
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index f51fbb4..87bec11 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -25,6 +25,7 @@
#include <compositionengine/Display.h>
#include <compositionengine/Layer.h>
#include <compositionengine/LayerCreationArgs.h>
+#include <compositionengine/LayerFECompositionState.h>
#include <compositionengine/OutputLayer.h>
#include <compositionengine/impl/LayerCompositionState.h>
#include <compositionengine/impl/OutputLayerCompositionState.h>
@@ -131,13 +132,15 @@
return inverse(tr);
}
-bool BufferLayer::prepareClientLayer(const RenderArea& renderArea, const Region& clip,
- bool useIdentityTransform, Region& clearRegion,
- const bool supportProtectedContent,
- renderengine::LayerSettings& layer) {
+std::optional<renderengine::LayerSettings> BufferLayer::prepareClientComposition(
+ compositionengine::LayerFE::ClientCompositionTargetSettings& targetSettings) {
ATRACE_CALL();
- Layer::prepareClientLayer(renderArea, clip, useIdentityTransform, clearRegion,
- supportProtectedContent, layer);
+
+ auto result = Layer::prepareClientComposition(targetSettings);
+ if (!result) {
+ return result;
+ }
+
if (CC_UNLIKELY(mActiveBuffer == 0)) {
// the texture has not been created yet, this Layer has
// in fact never been drawn into. This happens frequently with
@@ -158,15 +161,16 @@
under.orSelf(layer->visibleRegion);
});
// if not everything below us is covered, we plug the holes!
- Region holes(clip.subtract(under));
+ Region holes(targetSettings.clip.subtract(under));
if (!holes.isEmpty()) {
- clearRegion.orSelf(holes);
+ targetSettings.clearRegion.orSelf(holes);
}
- return false;
+ return std::nullopt;
}
- bool blackOutLayer =
- (isProtected() && !supportProtectedContent) || (isSecure() && !renderArea.isSecure());
+ bool blackOutLayer = (isProtected() && !targetSettings.supportProtectedContent) ||
+ (isSecure() && !targetSettings.isSecure);
const State& s(getDrawingState());
+ auto& layer = *result;
if (!blackOutLayer) {
layer.source.buffer.buffer = mActiveBuffer;
layer.source.buffer.isOpaque = isOpaque(s);
@@ -175,8 +179,7 @@
layer.source.buffer.usePremultipliedAlpha = getPremultipledAlpha();
layer.source.buffer.isY410BT2020 = isHdrY410();
// TODO: we could be more subtle with isFixedSize()
- const bool useFiltering = needsFiltering(renderArea.getDisplayDevice()) ||
- renderArea.needsFiltering() || isFixedSize();
+ const bool useFiltering = targetSettings.needsFiltering || mNeedsFiltering || isFixedSize();
// Query the texture matrix given our current filtering mode.
float textureMatrix[16];
@@ -243,7 +246,7 @@
layer.alpha = 1.0;
}
- return true;
+ return result;
}
bool BufferLayer::isHdrY410() const {
@@ -253,90 +256,20 @@
mActiveBuffer->getPixelFormat() == HAL_PIXEL_FORMAT_RGBA_1010102);
}
-void BufferLayer::setPerFrameData(const sp<const DisplayDevice>& displayDevice,
- const ui::Transform& transform, const Rect& viewport,
- int32_t supportedPerFrameMetadata,
- const ui::Dataspace targetDataspace) {
- RETURN_IF_NO_HWC_LAYER(displayDevice);
-
- // Apply this display's projection's viewport to the visible region
- // before giving it to the HWC HAL.
- Region visible = transform.transform(visibleRegion.intersect(viewport));
-
- const auto outputLayer = findOutputLayerForDisplay(displayDevice);
- LOG_FATAL_IF(!outputLayer || !outputLayer->getState().hwc);
-
- auto& hwcLayer = (*outputLayer->getState().hwc).hwcLayer;
- auto error = hwcLayer->setVisibleRegion(visible);
- if (error != HWC2::Error::None) {
- ALOGE("[%s] Failed to set visible region: %s (%d)", mName.string(),
- to_string(error).c_str(), static_cast<int32_t>(error));
- visible.dump(LOG_TAG);
- }
- outputLayer->editState().visibleRegion = visible;
-
- auto& layerCompositionState = getCompositionLayer()->editState().frontEnd;
-
- error = hwcLayer->setSurfaceDamage(surfaceDamageRegion);
- if (error != HWC2::Error::None) {
- ALOGE("[%s] Failed to set surface damage: %s (%d)", mName.string(),
- to_string(error).c_str(), static_cast<int32_t>(error));
- surfaceDamageRegion.dump(LOG_TAG);
- }
- layerCompositionState.surfaceDamage = surfaceDamageRegion;
+void BufferLayer::latchPerFrameState(
+ compositionengine::LayerFECompositionState& compositionState) const {
+ Layer::latchPerFrameState(compositionState);
// Sideband layers
- if (layerCompositionState.sidebandStream.get()) {
- setCompositionType(displayDevice, Hwc2::IComposerClient::Composition::SIDEBAND);
- ALOGV("[%s] Requesting Sideband composition", mName.string());
- error = hwcLayer->setSidebandStream(layerCompositionState.sidebandStream->handle());
- if (error != HWC2::Error::None) {
- ALOGE("[%s] Failed to set sideband stream %p: %s (%d)", mName.string(),
- layerCompositionState.sidebandStream->handle(), to_string(error).c_str(),
- static_cast<int32_t>(error));
- }
- layerCompositionState.compositionType = Hwc2::IComposerClient::Composition::SIDEBAND;
- return;
- }
-
- // Device or Cursor layers
- if (mPotentialCursor) {
- ALOGV("[%s] Requesting Cursor composition", mName.string());
- setCompositionType(displayDevice, Hwc2::IComposerClient::Composition::CURSOR);
+ if (compositionState.sidebandStream.get()) {
+ compositionState.compositionType = Hwc2::IComposerClient::Composition::SIDEBAND;
} else {
- ALOGV("[%s] Requesting Device composition", mName.string());
- setCompositionType(displayDevice, Hwc2::IComposerClient::Composition::DEVICE);
+ // Normal buffer layers
+ compositionState.hdrMetadata = getDrawingHdrMetadata();
+ compositionState.compositionType = mPotentialCursor
+ ? Hwc2::IComposerClient::Composition::CURSOR
+ : Hwc2::IComposerClient::Composition::DEVICE;
}
-
- ui::Dataspace dataspace = isColorSpaceAgnostic() && targetDataspace != ui::Dataspace::UNKNOWN
- ? targetDataspace
- : mCurrentDataSpace;
- error = hwcLayer->setDataspace(dataspace);
- if (error != HWC2::Error::None) {
- ALOGE("[%s] Failed to set dataspace %d: %s (%d)", mName.string(), dataspace,
- to_string(error).c_str(), static_cast<int32_t>(error));
- }
-
- const HdrMetadata& metadata = getDrawingHdrMetadata();
- error = hwcLayer->setPerFrameMetadata(supportedPerFrameMetadata, metadata);
- if (error != HWC2::Error::None && error != HWC2::Error::Unsupported) {
- ALOGE("[%s] Failed to set hdrMetadata: %s (%d)", mName.string(),
- to_string(error).c_str(), static_cast<int32_t>(error));
- }
-
- error = hwcLayer->setColorTransform(getColorTransform());
- if (error == HWC2::Error::Unsupported) {
- // If per layer color transform is not supported, we use GPU composition.
- setCompositionType(displayDevice, Hwc2::IComposerClient::Composition::CLIENT);
- } else if (error != HWC2::Error::None) {
- ALOGE("[%s] Failed to setColorTransform: %s (%d)", mName.string(),
- to_string(error).c_str(), static_cast<int32_t>(error));
- }
- layerCompositionState.dataspace = mCurrentDataSpace;
- layerCompositionState.colorTransform = getColorTransform();
- layerCompositionState.hdrMetadata = metadata;
-
- setHwcLayerBuffer(displayDevice);
}
bool BufferLayer::onPreComposition(nsecs_t refreshStartTime) {
@@ -395,7 +328,8 @@
return true;
}
-bool BufferLayer::latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime) {
+bool BufferLayer::latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime,
+ nsecs_t expectedPresentTime) {
ATRACE_CALL();
bool refreshRequired = latchSidebandStream(recomputeVisibleRegions);
@@ -430,12 +364,12 @@
const bool oldOpacity = isOpaque(s);
sp<GraphicBuffer> oldBuffer = mActiveBuffer;
- if (!allTransactionsSignaled()) {
+ if (!allTransactionsSignaled(expectedPresentTime)) {
mFlinger->setTransactionFlags(eTraversalNeeded);
return false;
}
- status_t err = updateTexImage(recomputeVisibleRegions, latchTime);
+ status_t err = updateTexImage(recomputeVisibleRegions, latchTime, expectedPresentTime);
if (err != NO_ERROR) {
return false;
}
@@ -540,10 +474,10 @@
}
// transaction
-void BufferLayer::notifyAvailableFrames() {
- const auto headFrameNumber = getHeadFrameNumber();
+void BufferLayer::notifyAvailableFrames(nsecs_t expectedPresentTime) {
+ const auto headFrameNumber = getHeadFrameNumber(expectedPresentTime);
const bool headFenceSignaled = fenceHasSignaled();
- const bool presentTimeIsCurrent = framePresentTimeIsCurrent();
+ const bool presentTimeIsCurrent = framePresentTimeIsCurrent(expectedPresentTime);
Mutex::Autolock lock(mLocalSyncPointMutex);
for (auto& point : mLocalSyncPoints) {
if (headFrameNumber >= point->getFrameNumber() && headFenceSignaled &&
@@ -591,8 +525,8 @@
}
// h/w composer set-up
-bool BufferLayer::allTransactionsSignaled() {
- auto headFrameNumber = getHeadFrameNumber();
+bool BufferLayer::allTransactionsSignaled(nsecs_t expectedPresentTime) {
+ const auto headFrameNumber = getHeadFrameNumber(expectedPresentTime);
bool matchingFramesFound = false;
bool allTransactionsApplied = true;
Mutex::Autolock lock(mLocalSyncPointMutex);
@@ -640,27 +574,29 @@
}
bool BufferLayer::needsFiltering(const sp<const DisplayDevice>& displayDevice) const {
- // If we are not capturing based on the state of a known display device, we
- // only return mNeedsFiltering
+ // If we are not capturing based on the state of a known display device,
+ // just return false.
if (displayDevice == nullptr) {
- return mNeedsFiltering;
+ return false;
}
const auto outputLayer = findOutputLayerForDisplay(displayDevice);
if (outputLayer == nullptr) {
- return mNeedsFiltering;
+ return false;
}
+ // We need filtering if the sourceCrop rectangle size does not match the
+ // displayframe rectangle size (not a 1:1 render)
const auto& compositionState = outputLayer->getState();
const auto displayFrame = compositionState.displayFrame;
const auto sourceCrop = compositionState.sourceCrop;
- return mNeedsFiltering || sourceCrop.getHeight() != displayFrame.getHeight() ||
+ return sourceCrop.getHeight() != displayFrame.getHeight() ||
sourceCrop.getWidth() != displayFrame.getWidth();
}
-uint64_t BufferLayer::getHeadFrameNumber() const {
+uint64_t BufferLayer::getHeadFrameNumber(nsecs_t expectedPresentTime) const {
if (hasFrameUpdate()) {
- return getFrameNumber();
+ return getFrameNumber(expectedPresentTime);
} else {
return mCurrentFrameNumber;
}
diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h
index b679380..c86acf0 100644
--- a/services/surfaceflinger/BufferLayer.h
+++ b/services/surfaceflinger/BufferLayer.h
@@ -82,11 +82,6 @@
bool isHdrY410() const override;
- void setPerFrameData(const sp<const DisplayDevice>& display, const ui::Transform& transform,
- const Rect& viewport, int32_t supportedPerFrameMetadata,
- const ui::Dataspace targetDataspace) override;
-
- bool onPreComposition(nsecs_t refreshStartTime) override;
bool onPostComposition(const std::optional<DisplayId>& displayId,
const std::shared_ptr<FenceTime>& glDoneFence,
const std::shared_ptr<FenceTime>& presentFence,
@@ -96,11 +91,12 @@
// the visible regions need to be recomputed (this is a fairly heavy
// operation, so this should be set only if needed). Typically this is used
// to figure out if the content or size of a surface has changed.
- bool latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime) override;
+ bool latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime,
+ nsecs_t expectedPresentTime) override;
bool isBufferLatched() const override { return mRefreshPending; }
- void notifyAvailableFrames() override;
+ void notifyAvailableFrames(nsecs_t expectedPresentTime) override;
bool hasReadyFrame() const override;
@@ -114,7 +110,7 @@
// -----------------------------------------------------------------------
private:
virtual bool fenceHasSignaled() const = 0;
- virtual bool framePresentTimeIsCurrent() const = 0;
+ virtual bool framePresentTimeIsCurrent(nsecs_t expectedPresentTime) const = 0;
virtual nsecs_t getDesiredPresentTime() = 0;
virtual std::shared_ptr<FenceTime> getCurrentFenceTime() const = 0;
@@ -129,7 +125,7 @@
virtual int getDrawingApi() const = 0;
virtual PixelFormat getPixelFormat() const = 0;
- virtual uint64_t getFrameNumber() const = 0;
+ virtual uint64_t getFrameNumber(nsecs_t expectedPresentTime) const = 0;
virtual bool getAutoRefresh() const = 0;
virtual bool getSidebandStreamChanged() const = 0;
@@ -142,21 +138,28 @@
virtual void setFilteringEnabled(bool enabled) = 0;
virtual status_t bindTextureImage() = 0;
- virtual status_t updateTexImage(bool& recomputeVisibleRegions, nsecs_t latchTime) = 0;
+ virtual status_t updateTexImage(bool& recomputeVisibleRegions, nsecs_t latchTime,
+ nsecs_t expectedPresentTime) = 0;
virtual status_t updateActiveBuffer() = 0;
virtual status_t updateFrameNumber(nsecs_t latchTime) = 0;
- virtual void setHwcLayerBuffer(const sp<const DisplayDevice>& displayDevice) = 0;
-
protected:
+ /*
+ * compositionengine::LayerFE overrides
+ */
+ bool onPreComposition(nsecs_t) override;
+ void latchPerFrameState(compositionengine::LayerFECompositionState&) const override;
+ std::optional<renderengine::LayerSettings> prepareClientComposition(
+ compositionengine::LayerFE::ClientCompositionTargetSettings&) override;
+
// Loads the corresponding system property once per process
static bool latchUnsignaledBuffers();
// Check all of the local sync points to ensure that all transactions
// which need to have been applied prior to the frame which is about to
// be latched have signaled
- bool allTransactionsSignaled();
+ bool allTransactionsSignaled(nsecs_t expectedPresentTime);
static bool getOpacityForFormat(uint32_t format);
@@ -165,17 +168,11 @@
bool mRefreshPending{false};
- // prepareClientLayer - constructs a RenderEngine layer for GPU composition.
- bool prepareClientLayer(const RenderArea& renderArea, const Region& clip,
- bool useIdentityTransform, Region& clearRegion,
- const bool supportProtectedContent,
- renderengine::LayerSettings& layer) override;
-
private:
// Returns true if this layer requires filtering
- bool needsFiltering(const sp<const DisplayDevice>& displayDevice) const;
+ bool needsFiltering(const sp<const DisplayDevice>& displayDevice) const override;
- uint64_t getHeadFrameNumber() const;
+ uint64_t getHeadFrameNumber(nsecs_t expectedPresentTime) const;
uint32_t mCurrentScalingMode{NATIVE_WINDOW_SCALING_MODE_FREEZE};
diff --git a/services/surfaceflinger/BufferLayerConsumer.cpp b/services/surfaceflinger/BufferLayerConsumer.cpp
index 096cd1a..ea55795 100644
--- a/services/surfaceflinger/BufferLayerConsumer.cpp
+++ b/services/surfaceflinger/BufferLayerConsumer.cpp
@@ -369,6 +369,15 @@
return mCurrentSurfaceDamage;
}
+void BufferLayerConsumer::mergeSurfaceDamage(const Region& damage) {
+ if (damage.bounds() == Rect::INVALID_RECT ||
+ mCurrentSurfaceDamage.bounds() == Rect::INVALID_RECT) {
+ mCurrentSurfaceDamage = Region::INVALID_REGION;
+ } else {
+ mCurrentSurfaceDamage |= damage;
+ }
+}
+
int BufferLayerConsumer::getCurrentApi() const {
Mutex::Autolock lock(mMutex);
return mCurrentApi;
@@ -461,7 +470,6 @@
if (oldImage == nullptr || oldImage->graphicBuffer() == nullptr ||
oldImage->graphicBuffer()->getId() != item.mGraphicBuffer->getId()) {
mImages[item.mSlot] = std::make_shared<Image>(item.mGraphicBuffer, mRE);
- mRE.cacheExternalTextureBuffer(item.mGraphicBuffer);
}
}
}
@@ -498,6 +506,12 @@
ConsumerBase::dumpLocked(result, prefix);
}
+BufferLayerConsumer::Image::Image(const sp<GraphicBuffer>& graphicBuffer,
+ renderengine::RenderEngine& engine)
+ : mGraphicBuffer(graphicBuffer), mRE(engine) {
+ mRE.cacheExternalTextureBuffer(mGraphicBuffer);
+}
+
BufferLayerConsumer::Image::~Image() {
if (mGraphicBuffer != nullptr) {
ALOGV("Destroying buffer: %" PRId64, mGraphicBuffer->getId());
diff --git a/services/surfaceflinger/BufferLayerConsumer.h b/services/surfaceflinger/BufferLayerConsumer.h
index 144686c..39ed370 100644
--- a/services/surfaceflinger/BufferLayerConsumer.h
+++ b/services/surfaceflinger/BufferLayerConsumer.h
@@ -140,6 +140,9 @@
// must be called from SF main thread
const Region& getSurfaceDamage() const;
+ // Merge the given damage region into the current damage region value.
+ void mergeSurfaceDamage(const Region& damage);
+
// getCurrentApi retrieves the API which queues the current buffer.
int getCurrentApi() const;
@@ -220,8 +223,7 @@
// Utility class for managing GraphicBuffer references into renderengine
class Image {
public:
- Image(sp<GraphicBuffer> graphicBuffer, renderengine::RenderEngine& engine)
- : mGraphicBuffer(graphicBuffer), mRE(engine) {}
+ Image(const sp<GraphicBuffer>& graphicBuffer, renderengine::RenderEngine& engine);
virtual ~Image();
const sp<GraphicBuffer>& graphicBuffer() { return mGraphicBuffer; }
diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp
index d685366..12be00f 100644
--- a/services/surfaceflinger/BufferQueueLayer.cpp
+++ b/services/surfaceflinger/BufferQueueLayer.cpp
@@ -137,13 +137,13 @@
return mQueueItems[0].mFenceTime->getSignalTime() != Fence::SIGNAL_TIME_PENDING;
}
-bool BufferQueueLayer::framePresentTimeIsCurrent() const {
+bool BufferQueueLayer::framePresentTimeIsCurrent(nsecs_t expectedPresentTime) const {
if (!hasFrameUpdate() || isRemovedFromCurrentState()) {
return true;
}
Mutex::Autolock lock(mQueueItemLock);
- return mQueueItems[0].mTimestamp <= mFlinger->getExpectedPresentTime();
+ return mQueueItems[0].mTimestamp <= expectedPresentTime;
}
nsecs_t BufferQueueLayer::getDesiredPresentTime() {
@@ -196,13 +196,11 @@
return mFormat;
}
-uint64_t BufferQueueLayer::getFrameNumber() const {
+uint64_t BufferQueueLayer::getFrameNumber(nsecs_t expectedPresentTime) const {
Mutex::Autolock lock(mQueueItemLock);
uint64_t frameNumber = mQueueItems[0].mFrameNumber;
// The head of the queue will be dropped if there are signaled and timely frames behind it
- nsecs_t expectedPresentTime = mFlinger->getExpectedPresentTime();
-
if (isRemovedFromCurrentState()) {
expectedPresentTime = 0;
}
@@ -268,7 +266,8 @@
return mConsumer->bindTextureImage();
}
-status_t BufferQueueLayer::updateTexImage(bool& recomputeVisibleRegions, nsecs_t latchTime) {
+status_t BufferQueueLayer::updateTexImage(bool& recomputeVisibleRegions, nsecs_t latchTime,
+ nsecs_t expectedPresentTime) {
// This boolean is used to make sure that SurfaceFlinger's shadow copy
// of the buffer queue isn't modified when the buffer queue is returning
// BufferItem's that weren't actually queued. This can happen in shared
@@ -279,8 +278,6 @@
getProducerStickyTransform() != 0, mName.string(), mOverrideScalingMode,
getTransformToDisplayInverse(), mFreezeGeometryUpdates);
- nsecs_t expectedPresentTime = mFlinger->getExpectedPresentTime();
-
if (isRemovedFromCurrentState()) {
expectedPresentTime = 0;
}
@@ -316,6 +313,7 @@
// and return early
if (queuedBuffer) {
Mutex::Autolock lock(mQueueItemLock);
+ mConsumer->mergeSurfaceDamage(mQueueItems[0].mSurfaceDamage);
mFlinger->mTimeStats->removeTimeRecord(layerID, mQueueItems[0].mFrameNumber);
mQueueItems.removeAt(0);
mQueuedFrames--;
@@ -351,6 +349,7 @@
// Remove any stale buffers that have been dropped during
// updateTexImage
while (mQueueItems[0].mFrameNumber != currentFrameNumber) {
+ mConsumer->mergeSurfaceDamage(mQueueItems[0].mSurfaceDamage);
mFlinger->mTimeStats->removeTimeRecord(layerID, mQueueItems[0].mFrameNumber);
mQueueItems.removeAt(0);
mQueuedFrames--;
@@ -377,7 +376,6 @@
mActiveBuffer = mConsumer->getCurrentBuffer(&mActiveBufferSlot, &mActiveBufferFence);
auto& layerCompositionState = getCompositionLayer()->editState().frontEnd;
layerCompositionState.buffer = mActiveBuffer;
- layerCompositionState.bufferSlot = mActiveBufferSlot;
if (mActiveBuffer == nullptr) {
// this can only happen if the very first buffer was rejected.
@@ -397,32 +395,17 @@
return NO_ERROR;
}
-void BufferQueueLayer::setHwcLayerBuffer(const sp<const DisplayDevice>& display) {
- const auto outputLayer = findOutputLayerForDisplay(display);
- LOG_FATAL_IF(!outputLayer);
- LOG_FATAL_IF(!outputLayer->getState.hwc);
- auto& hwcLayer = (*outputLayer->getState().hwc).hwcLayer;
-
- uint32_t hwcSlot = 0;
- sp<GraphicBuffer> hwcBuffer;
-
- // INVALID_BUFFER_SLOT is used to identify BufferStateLayers. Default to 0
- // for BufferQueueLayers
- int slot = (mActiveBufferSlot == BufferQueue::INVALID_BUFFER_SLOT) ? 0 : mActiveBufferSlot;
- (*outputLayer->editState().hwc)
- .hwcBufferCache.getHwcBuffer(slot, mActiveBuffer, &hwcSlot, &hwcBuffer);
-
- auto acquireFence = mConsumer->getCurrentFence();
- auto error = hwcLayer->setBuffer(hwcSlot, hwcBuffer, acquireFence);
- if (error != HWC2::Error::None) {
- ALOGE("[%s] Failed to set buffer %p: %s (%d)", mName.string(), mActiveBuffer->handle,
- to_string(error).c_str(), static_cast<int32_t>(error));
+void BufferQueueLayer::latchPerFrameState(
+ compositionengine::LayerFECompositionState& compositionState) const {
+ BufferLayer::latchPerFrameState(compositionState);
+ if (compositionState.compositionType == Hwc2::IComposerClient::Composition::SIDEBAND) {
+ return;
}
- auto& layerCompositionState = getCompositionLayer()->editState().frontEnd;
- layerCompositionState.bufferSlot = mActiveBufferSlot;
- layerCompositionState.buffer = mActiveBuffer;
- layerCompositionState.acquireFence = acquireFence;
+ compositionState.buffer = mActiveBuffer;
+ compositionState.bufferSlot =
+ (mActiveBufferSlot == BufferQueue::INVALID_BUFFER_SLOT) ? 0 : mActiveBufferSlot;
+ compositionState.acquireFence = mConsumer->getCurrentFence();
}
// -----------------------------------------------------------------------
@@ -432,7 +415,7 @@
void BufferQueueLayer::fakeVsync() {
mRefreshPending = false;
bool ignored = false;
- latchBuffer(ignored, systemTime());
+ latchBuffer(ignored, systemTime(), 0 /* expectedPresentTime */);
usleep(16000);
releasePendingBuffer(systemTime());
}
diff --git a/services/surfaceflinger/BufferQueueLayer.h b/services/surfaceflinger/BufferQueueLayer.h
index 7def33a..231a531 100644
--- a/services/surfaceflinger/BufferQueueLayer.h
+++ b/services/surfaceflinger/BufferQueueLayer.h
@@ -61,7 +61,7 @@
// -----------------------------------------------------------------------
public:
bool fenceHasSignaled() const override;
- bool framePresentTimeIsCurrent() const override;
+ bool framePresentTimeIsCurrent(nsecs_t expectedPresentTime) const override;
private:
nsecs_t getDesiredPresentTime() override;
@@ -77,7 +77,7 @@
int getDrawingApi() const override;
PixelFormat getPixelFormat() const override;
- uint64_t getFrameNumber() const override;
+ uint64_t getFrameNumber(nsecs_t expectedPresentTime) const override;
bool getAutoRefresh() const override;
bool getSidebandStreamChanged() const override;
@@ -89,12 +89,13 @@
void setFilteringEnabled(bool enabled) override;
status_t bindTextureImage() override;
- status_t updateTexImage(bool& recomputeVisibleRegions, nsecs_t latchTime) override;
+ status_t updateTexImage(bool& recomputeVisibleRegions, nsecs_t latchTime,
+ nsecs_t expectedPresentTime) override;
status_t updateActiveBuffer() override;
status_t updateFrameNumber(nsecs_t latchTime) override;
- void setHwcLayerBuffer(const sp<const DisplayDevice>& displayDevice) override;
+ void latchPerFrameState(compositionengine::LayerFECompositionState&) const override;
// -----------------------------------------------------------------------
// Interface implementation for BufferLayerConsumer::ContentsChangedListener
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index 4b01301..0f26211 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -216,7 +216,7 @@
mCurrentState.modified = true;
setTransactionFlags(eTransactionNeeded);
- mFlinger->mTimeStats->setPostTime(getSequence(), getFrameNumber(), getName().c_str(), postTime);
+ mFlinger->mTimeStats->setPostTime(getSequence(), mFrameNumber, getName().c_str(), postTime);
mDesiredPresentTime = desiredPresentTime;
if (mFlinger->mUseSmart90ForVideo) {
@@ -369,12 +369,12 @@
return getDrawingState().acquireFence->getStatus() == Fence::Status::Signaled;
}
-bool BufferStateLayer::framePresentTimeIsCurrent() const {
+bool BufferStateLayer::framePresentTimeIsCurrent(nsecs_t expectedPresentTime) const {
if (!hasFrameUpdate() || isRemovedFromCurrentState()) {
return true;
}
- return mDesiredPresentTime <= mFlinger->getExpectedPresentTime();
+ return mDesiredPresentTime <= expectedPresentTime;
}
nsecs_t BufferStateLayer::getDesiredPresentTime() {
@@ -446,7 +446,7 @@
return mActiveBuffer->format;
}
-uint64_t BufferStateLayer::getFrameNumber() const {
+uint64_t BufferStateLayer::getFrameNumber(nsecs_t /*expectedPresentTime*/) const {
return mFrameNumber;
}
@@ -494,7 +494,8 @@
return engine.bindExternalTextureBuffer(mTextureName, s.buffer, s.acquireFence);
}
-status_t BufferStateLayer::updateTexImage(bool& /*recomputeVisibleRegions*/, nsecs_t latchTime) {
+status_t BufferStateLayer::updateTexImage(bool& /*recomputeVisibleRegions*/, nsecs_t latchTime,
+ nsecs_t /*expectedPresentTime*/) {
const State& s(getDrawingState());
if (!s.buffer) {
@@ -528,7 +529,7 @@
ALOGE("[%s] rejecting buffer: "
"bufferWidth=%d, bufferHeight=%d, front.active.{w=%d, h=%d}",
mName.string(), bufferWidth, bufferHeight, s.active.w, s.active.h);
- mFlinger->mTimeStats->removeTimeRecord(layerID, getFrameNumber());
+ mFlinger->mTimeStats->removeTimeRecord(layerID, mFrameNumber);
return BAD_VALUE;
}
@@ -550,8 +551,8 @@
}
}
- mFlinger->mTimeStats->setAcquireFence(layerID, getFrameNumber(), getCurrentFenceTime());
- mFlinger->mTimeStats->setLatchTime(layerID, getFrameNumber(), latchTime);
+ mFlinger->mTimeStats->setAcquireFence(layerID, mFrameNumber, getCurrentFenceTime());
+ mFlinger->mTimeStats->setLatchTime(layerID, mFrameNumber, latchTime);
mCurrentStateModified = false;
@@ -569,7 +570,6 @@
mActiveBufferFence = s.acquireFence;
auto& layerCompositionState = getCompositionLayer()->editState().frontEnd;
layerCompositionState.buffer = mActiveBuffer;
- layerCompositionState.bufferSlot = 0;
return NO_ERROR;
}
@@ -580,24 +580,18 @@
return NO_ERROR;
}
-void BufferStateLayer::setHwcLayerBuffer(const sp<const DisplayDevice>& display) {
- const auto outputLayer = findOutputLayerForDisplay(display);
- LOG_FATAL_IF(!outputLayer || !outputLayer->getState().hwc);
- auto& hwcInfo = *outputLayer->editState().hwc;
- auto& hwcLayer = hwcInfo.hwcLayer;
+void BufferStateLayer::latchPerFrameState(
+ compositionengine::LayerFECompositionState& compositionState) const {
+ BufferLayer::latchPerFrameState(compositionState);
+ if (compositionState.compositionType == Hwc2::IComposerClient::Composition::SIDEBAND) {
+ return;
+ }
const State& s(getDrawingState());
- uint32_t hwcSlot;
- sp<GraphicBuffer> buffer;
- hwcInfo.hwcBufferCache.getHwcBuffer(mHwcSlotGenerator->getHwcCacheSlot(s.clientCacheId),
- s.buffer, &hwcSlot, &buffer);
-
- auto error = hwcLayer->setBuffer(hwcSlot, buffer, s.acquireFence);
- if (error != HWC2::Error::None) {
- ALOGE("[%s] Failed to set buffer %p: %s (%d)", mName.string(),
- s.buffer->handle, to_string(error).c_str(), static_cast<int32_t>(error));
- }
+ compositionState.buffer = s.buffer;
+ compositionState.bufferSlot = mHwcSlotGenerator->getHwcCacheSlot(s.clientCacheId);
+ compositionState.acquireFence = s.acquireFence;
mFrameNumber++;
}
diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h
index db8ae0d..5e5b9b0 100644
--- a/services/surfaceflinger/BufferStateLayer.h
+++ b/services/surfaceflinger/BufferStateLayer.h
@@ -100,7 +100,7 @@
// Interface implementation for BufferLayer
// -----------------------------------------------------------------------
bool fenceHasSignaled() const override;
- bool framePresentTimeIsCurrent() const override;
+ bool framePresentTimeIsCurrent(nsecs_t expectedPresentTime) const override;
// Inherit from ClientCache::ErasedRecipient
void bufferErased(const client_cache_t& clientCacheId) override;
@@ -119,7 +119,7 @@
int getDrawingApi() const override;
PixelFormat getPixelFormat() const override;
- uint64_t getFrameNumber() const override;
+ uint64_t getFrameNumber(nsecs_t expectedPresentTime) const override;
bool getAutoRefresh() const override;
bool getSidebandStreamChanged() const override;
@@ -131,12 +131,13 @@
void setFilteringEnabled(bool enabled) override;
status_t bindTextureImage() override;
- status_t updateTexImage(bool& recomputeVisibleRegions, nsecs_t latchTime) override;
+ status_t updateTexImage(bool& recomputeVisibleRegions, nsecs_t latchTime,
+ nsecs_t expectedPresentTime) override;
status_t updateActiveBuffer() override;
status_t updateFrameNumber(nsecs_t latchTime) override;
- void setHwcLayerBuffer(const sp<const DisplayDevice>& display) override;
+ void latchPerFrameState(compositionengine::LayerFECompositionState&) const override;
private:
friend class SlotGenerationTest;
@@ -151,11 +152,11 @@
std::atomic<bool> mSidebandStreamChanged{false};
- uint32_t mFrameNumber{0};
+ mutable uint32_t mFrameNumber{0};
sp<Fence> mPreviousReleaseFence;
- bool mCurrentStateModified = false;
+ mutable bool mCurrentStateModified = false;
bool mReleasePreviousBuffer = false;
nsecs_t mCallbackHandleAcquireTime = -1;
diff --git a/services/surfaceflinger/ColorLayer.cpp b/services/surfaceflinger/ColorLayer.cpp
index fcc2d97..b65d351 100644
--- a/services/surfaceflinger/ColorLayer.cpp
+++ b/services/surfaceflinger/ColorLayer.cpp
@@ -18,6 +18,8 @@
#undef LOG_TAG
#define LOG_TAG "ColorLayer"
+#include "ColorLayer.h"
+
#include <stdint.h>
#include <stdlib.h>
#include <sys/types.h>
@@ -26,6 +28,7 @@
#include <compositionengine/Display.h>
#include <compositionengine/Layer.h>
#include <compositionengine/LayerCreationArgs.h>
+#include <compositionengine/LayerFECompositionState.h>
#include <compositionengine/OutputLayer.h>
#include <compositionengine/impl/LayerCompositionState.h>
#include <compositionengine/impl/OutputLayerCompositionState.h>
@@ -34,7 +37,6 @@
#include <utils/Errors.h>
#include <utils/Log.h>
-#include "ColorLayer.h"
#include "DisplayDevice.h"
#include "SurfaceFlinger.h"
@@ -48,16 +50,14 @@
ColorLayer::~ColorLayer() = default;
-bool ColorLayer::prepareClientLayer(const RenderArea& renderArea, const Region& clip,
- bool useIdentityTransform, Region& clearRegion,
- const bool supportProtectedContent,
- renderengine::LayerSettings& layer) {
- Layer::prepareClientLayer(renderArea, clip, useIdentityTransform, clearRegion,
- supportProtectedContent, layer);
- half4 color(getColor());
- half3 solidColor(color.r, color.g, color.b);
- layer.source.solidColor = solidColor;
- return true;
+std::optional<renderengine::LayerSettings> ColorLayer::prepareClientComposition(
+ compositionengine::LayerFE::ClientCompositionTargetSettings& targetSettings) {
+ auto result = Layer::prepareClientComposition(targetSettings);
+ if (!result) {
+ return result;
+ }
+ result->source.solidColor = getColor().rgb;
+ return result;
}
bool ColorLayer::isVisible() const {
@@ -91,75 +91,12 @@
return true;
}
-void ColorLayer::setPerFrameData(const sp<const DisplayDevice>& display,
- const ui::Transform& transform, const Rect& viewport,
- int32_t /* supportedPerFrameMetadata */,
- const ui::Dataspace targetDataspace) {
- RETURN_IF_NO_HWC_LAYER(display);
+void ColorLayer::latchPerFrameState(
+ compositionengine::LayerFECompositionState& compositionState) const {
+ Layer::latchPerFrameState(compositionState);
- Region visible = transform.transform(visibleRegion.intersect(viewport));
-
- const auto outputLayer = findOutputLayerForDisplay(display);
- LOG_FATAL_IF(!outputLayer || !outputLayer->getState().hwc);
-
- auto& hwcLayer = (*outputLayer->getState().hwc).hwcLayer;
-
- auto error = hwcLayer->setVisibleRegion(visible);
- if (error != HWC2::Error::None) {
- ALOGE("[%s] Failed to set visible region: %s (%d)", mName.string(),
- to_string(error).c_str(), static_cast<int32_t>(error));
- visible.dump(LOG_TAG);
- }
- outputLayer->editState().visibleRegion = visible;
-
- setCompositionType(display, Hwc2::IComposerClient::Composition::SOLID_COLOR);
-
- const ui::Dataspace dataspace =
- isColorSpaceAgnostic() && targetDataspace != ui::Dataspace::UNKNOWN ? targetDataspace
- : mCurrentDataSpace;
- error = hwcLayer->setDataspace(dataspace);
- if (error != HWC2::Error::None) {
- ALOGE("[%s] Failed to set dataspace %d: %s (%d)", mName.string(), dataspace,
- to_string(error).c_str(), static_cast<int32_t>(error));
- }
-
- auto& layerCompositionState = getCompositionLayer()->editState().frontEnd;
- layerCompositionState.dataspace = mCurrentDataSpace;
-
- half4 color = getColor();
- error = hwcLayer->setColor({static_cast<uint8_t>(std::round(255.0f * color.r)),
- static_cast<uint8_t>(std::round(255.0f * color.g)),
- static_cast<uint8_t>(std::round(255.0f * color.b)), 255});
- if (error != HWC2::Error::None) {
- ALOGE("[%s] Failed to set color: %s (%d)", mName.string(), to_string(error).c_str(),
- static_cast<int32_t>(error));
- }
- layerCompositionState.color = {static_cast<uint8_t>(std::round(255.0f * color.r)),
- static_cast<uint8_t>(std::round(255.0f * color.g)),
- static_cast<uint8_t>(std::round(255.0f * color.b)), 255};
-
- // Clear out the transform, because it doesn't make sense absent a source buffer
- error = hwcLayer->setTransform(HWC2::Transform::None);
- if (error != HWC2::Error::None) {
- ALOGE("[%s] Failed to clear transform: %s (%d)", mName.string(), to_string(error).c_str(),
- static_cast<int32_t>(error));
- }
- outputLayer->editState().bufferTransform = static_cast<Hwc2::Transform>(0);
-
- error = hwcLayer->setColorTransform(getColorTransform());
- if (error != HWC2::Error::None) {
- ALOGE("[%s] Failed to setColorTransform: %s (%d)", mName.string(),
- to_string(error).c_str(), static_cast<int32_t>(error));
- }
- layerCompositionState.colorTransform = getColorTransform();
-
- error = hwcLayer->setSurfaceDamage(surfaceDamageRegion);
- if (error != HWC2::Error::None) {
- ALOGE("[%s] Failed to set surface damage: %s (%d)", mName.string(),
- to_string(error).c_str(), static_cast<int32_t>(error));
- surfaceDamageRegion.dump(LOG_TAG);
- }
- layerCompositionState.surfaceDamage = surfaceDamageRegion;
+ compositionState.color = getColor();
+ compositionState.compositionType = Hwc2::IComposerClient::Composition::SOLID_COLOR;
}
void ColorLayer::commitTransaction(const State& stateToCommit) {
diff --git a/services/surfaceflinger/ColorLayer.h b/services/surfaceflinger/ColorLayer.h
index 53d5b5b..015b939 100644
--- a/services/surfaceflinger/ColorLayer.h
+++ b/services/surfaceflinger/ColorLayer.h
@@ -37,21 +37,16 @@
bool setDataspace(ui::Dataspace dataspace) override;
- void setPerFrameData(const sp<const DisplayDevice>& display, const ui::Transform& transform,
- const Rect& viewport, int32_t supportedPerFrameMetadata,
- const ui::Dataspace targetDataspace) override;
-
void commitTransaction(const State& stateToCommit) override;
- bool onPreComposition(nsecs_t /*refreshStartTime*/) override { return false; }
-
protected:
- virtual bool prepareClientLayer(const RenderArea& renderArea, const Region& clip,
- bool useIdentityTransform, Region& clearRegion,
- const bool supportProtectedContent,
- renderengine::LayerSettings& layer);
+ /*
+ * compositionengine::LayerFE overrides
+ */
+ void latchPerFrameState(compositionengine::LayerFECompositionState&) const override;
+ std::optional<renderengine::LayerSettings> prepareClientComposition(
+ compositionengine::LayerFE::ClientCompositionTargetSettings&) override;
-private:
std::shared_ptr<compositionengine::Layer> mCompositionLayer;
};
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionEngine.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionEngine.h
index 896f8aa..31d6365 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionEngine.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionEngine.h
@@ -18,6 +18,8 @@
#include <memory>
+#include <utils/Timers.h>
+
namespace android {
class HWComposer;
@@ -31,6 +33,7 @@
class Display;
class Layer;
+struct CompositionRefreshArgs;
struct DisplayCreationArgs;
struct LayerCreationArgs;
@@ -51,6 +54,12 @@
virtual renderengine::RenderEngine& getRenderEngine() const = 0;
virtual void setRenderEngine(std::unique_ptr<renderengine::RenderEngine>) = 0;
+
+ virtual bool needsAnotherUpdate() const = 0;
+ virtual nsecs_t getLastFrameRefreshTimestamp() const = 0;
+
+ // TODO(b/121291683): These will become private/internal
+ virtual void preComposition(CompositionRefreshArgs&) = 0;
};
} // namespace compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionRefreshArgs.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionRefreshArgs.h
new file mode 100644
index 0000000..20f131e
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionRefreshArgs.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <compositionengine/Display.h>
+#include <compositionengine/Layer.h>
+
+namespace android::compositionengine {
+
+using Layers = std::vector<std::shared_ptr<compositionengine::Layer>>;
+using Outputs = std::vector<std::shared_ptr<compositionengine::Output>>;
+
+/**
+ * A parameter object for refreshing a set of outputs
+ */
+struct CompositionRefreshArgs {
+ // All the outputs being refreshed
+ Outputs outputs;
+
+ // All the layers that are potentially visible in the outputs. The order of
+ // the layers is important, and should be in traversal order from back to
+ // front.
+ Layers layers;
+};
+
+} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayColorProfile.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayColorProfile.h
index e2a0d42..d93bfa3 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayColorProfile.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayColorProfile.h
@@ -17,6 +17,7 @@
#pragma once
#include <cstdint>
+#include <string>
#include <ui/GraphicTypes.h>
@@ -75,6 +76,13 @@
// Gets the supported HDR capabilities for the profile
virtual const HdrCapabilities& getHdrCapabilities() const = 0;
+ // Returns true if HWC for this profile supports the dataspace
+ virtual bool isDataspaceSupported(ui::Dataspace) const = 0;
+
+ // Returns the target dataspace for picked color mode and dataspace
+ virtual ui::Dataspace getTargetDataspace(ui::ColorMode, ui::Dataspace,
+ ui::Dataspace colorSpaceAgnosticDataspace) const = 0;
+
// Debugging
virtual void dump(std::string&) const = 0;
};
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Layer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Layer.h
index 8cb9203..451608b 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Layer.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Layer.h
@@ -21,11 +21,7 @@
#include <utils/StrongPointer.h>
-namespace android {
-
-typedef int64_t nsecs_t;
-
-namespace compositionengine {
+namespace android::compositionengine {
class Display;
class LayerFE;
@@ -62,5 +58,4 @@
virtual void dump(std::string& result) const = 0;
};
-} // namespace compositionengine
-} // namespace android
+} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
index 9f635b9..94fab1f 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
@@ -16,7 +16,11 @@
#pragma once
+#include <optional>
+
+#include <renderengine/LayerSettings.h>
#include <utils/RefBase.h>
+#include <utils/Timers.h>
namespace android {
@@ -30,10 +34,43 @@
// of the front-end layer
class LayerFE : public virtual RefBase {
public:
+ // Called before composition starts. Should return true if this layer has
+ // pending updates which would require an extra display refresh cycle to
+ // process.
+ virtual bool onPreComposition(nsecs_t refreshStartTime) = 0;
+
// Latches the output-independent state. If includeGeometry is false, the
// geometry state can be skipped.
virtual void latchCompositionState(LayerFECompositionState&, bool includeGeometry) const = 0;
+ struct ClientCompositionTargetSettings {
+ // The clip region, or visible region that is being rendered to
+ const Region& clip;
+
+ // If true, the layer should use an identity transform for its position
+ // transform. Used only by the captureScreen API call.
+ const bool useIdentityTransform;
+
+ // If set to true, the layer should enable filtering when rendering.
+ const bool needsFiltering;
+
+ // If set to true, the buffer is being sent to a destination that is
+ // expected to treat the buffer contents as secure.
+ const bool isSecure;
+
+ // If set to true, the target buffer has protected content support.
+ const bool supportProtectedContent;
+
+ // Modified by each call to prepareClientComposition to indicate the
+ // region of the target buffer that should be cleared.
+ Region& clearRegion;
+ };
+
+ // Returns the LayerSettings to pass to RenderEngine::drawLayers, or
+ // nullopt_t if the layer does not render
+ virtual std::optional<renderengine::LayerSettings> prepareClientComposition(
+ ClientCompositionTargetSettings&) = 0;
+
// Called after the layer is displayed to update the presentation fence
virtual void onLayerDisplayed(const sp<Fence>&) = 0;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h
index e6ee078..d96d58c 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h
@@ -36,9 +36,9 @@
* Used by LayerFE::getCompositionState
*/
struct LayerFECompositionState {
- // TODO(lpique): b/121291683 Remove this one we are sure we don't need the
- // value recomputed / set every frame.
- Region geomVisibleRegion;
+ // If set to true, forces client composition on all output layers until
+ // the next geometry change.
+ bool forceClientComposition{false};
/*
* Geometry state
@@ -56,6 +56,10 @@
Region geomActiveTransparentRegion;
FloatRect geomLayerBounds;
+ // TODO(lpique): b/121291683 Remove this one we are sure we don't need the
+ // value recomputed / set every frame.
+ Region geomVisibleRegion;
+
/*
* Presentation
*/
@@ -93,12 +97,16 @@
sp<NativeHandle> sidebandStream;
// The color for this layer
- Hwc2::IComposerClient::Color color;
+ half4 color;
/*
* Per-frame presentation state
*/
+ // If true, this layer will use the dataspace chosen for the output and
+ // ignore the dataspace value just below
+ bool isColorspaceAgnostic{false};
+
// The dataspace for this layer
ui::Dataspace dataspace{ui::Dataspace::UNKNOWN};
@@ -107,6 +115,7 @@
// The color transform
mat4 colorTransform;
+ bool colorTransformIsIdentity{true};
};
} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
index 54e6bd6..4dfcfa4 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
@@ -19,8 +19,10 @@
#include <cstdint>
#include <optional>
#include <string>
+#include <unordered_map>
#include <math/mat4.h>
+#include <ui/Fence.h>
#include <ui/GraphicTypes.h>
#include <ui/Region.h>
#include <ui/Transform.h>
@@ -28,6 +30,10 @@
#include "DisplayHardware/DisplayIdentification.h"
+namespace HWC2 {
+class Layer;
+} // namespace HWC2
+
namespace android::compositionengine {
class DisplayColorProfile;
@@ -46,6 +52,13 @@
class Output {
public:
using OutputLayers = std::vector<std::unique_ptr<compositionengine::OutputLayer>>;
+ using ReleasedLayers = std::vector<wp<LayerFE>>;
+
+ struct FrameFences {
+ sp<Fence> presentFence{Fence::NO_FENCE};
+ sp<Fence> clientTargetAcquireFence{Fence::NO_FENCE};
+ std::unordered_map<HWC2::Layer*, sp<Fence>> layerFences;
+ };
virtual ~Output();
@@ -71,7 +84,8 @@
virtual void setColorTransform(const mat4&) = 0;
// Sets the output color mode
- virtual void setColorMode(ui::ColorMode, ui::Dataspace, ui::RenderIntent) = 0;
+ virtual void setColorMode(ui::ColorMode, ui::Dataspace, ui::RenderIntent,
+ ui::Dataspace colorSpaceAgnosticDataspace) = 0;
// Outputs a string with a state dump
virtual void dump(std::string&) const = 0;
@@ -130,9 +144,26 @@
// Gets the ordered set of output layers for this output
virtual const OutputLayers& getOutputLayersOrderedByZ() const = 0;
+ // Sets the new set of layers being released this frame
+ virtual void setReleasedLayers(ReleasedLayers&&) = 0;
+
+ // Takes (moves) the set of layers being released this frame.
+ virtual ReleasedLayers takeReleasedLayers() = 0;
+
+ // Signals that a frame is beginning on the output
+ virtual void beginFrame() = 0;
+
+ // Prepares a frame for display
+ virtual void prepareFrame() = 0;
+
+ // Posts the new frame, and sets release fences.
+ virtual void postFramebuffer() = 0;
+
protected:
virtual void setDisplayColorProfile(std::unique_ptr<DisplayColorProfile>) = 0;
virtual void setRenderSurface(std::unique_ptr<RenderSurface>) = 0;
+ virtual void chooseCompositionStrategy() = 0;
+ virtual FrameFences presentAndGetFrameFences() = 0;
};
} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h
index cd63b57..d7f00a9 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h
@@ -21,8 +21,13 @@
#include <utils/StrongPointer.h>
+#include "DisplayHardware/ComposerHal.h"
#include "DisplayHardware/DisplayIdentification.h"
+namespace HWC2 {
+class Layer;
+} // namespace HWC2
+
namespace android {
namespace compositionengine {
@@ -71,7 +76,22 @@
// Writes the geometry state to the HWC, or does nothing if this layer does
// not use the HWC. If includeGeometry is false, the geometry state can be
// skipped.
- virtual void writeStateToHWC(bool includeGeometry) const = 0;
+ virtual void writeStateToHWC(bool includeGeometry) = 0;
+
+ // Returns the HWC2::Layer associated with this layer, if it exists
+ virtual HWC2::Layer* getHwcLayer() const = 0;
+
+ // Returns true if the current layer state requires client composition
+ virtual bool requiresClientComposition() const = 0;
+
+ // Applies a HWC device requested composition type change
+ virtual void applyDeviceCompositionTypeChange(Hwc2::IComposerClient::Composition) = 0;
+
+ // Prepares to apply any HWC device layer requests
+ virtual void prepareForDeviceLayerRequests() = 0;
+
+ // Applies a HWC device layer request
+ virtual void applyDeviceLayerRequest(Hwc2::IComposerClient::LayerRequest request) = 0;
// Debugging
virtual void dump(std::string& result) const = 0;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h
index 9bff73e..6859846 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h
@@ -71,7 +71,7 @@
virtual status_t beginFrame(bool mustRecompose) = 0;
// Prepares the frame for rendering
- virtual status_t prepareFrame() = 0;
+ virtual void prepareFrame(bool usesClientComposition, bool usesDeviceComposition) = 0;
// Allocates a buffer as scratch space for GPU composition
virtual sp<GraphicBuffer> dequeueBuffer(base::unique_fd* bufferFence) = 0;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/CompositionEngine.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/CompositionEngine.h
index b01eb64..96e609d 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/CompositionEngine.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/CompositionEngine.h
@@ -36,9 +36,19 @@
renderengine::RenderEngine& getRenderEngine() const override;
void setRenderEngine(std::unique_ptr<renderengine::RenderEngine>) override;
+ bool needsAnotherUpdate() const override;
+ nsecs_t getLastFrameRefreshTimestamp() const override;
+
+ void preComposition(CompositionRefreshArgs&) override;
+
+ // Testing
+ void setNeedsAnotherUpdateForTest(bool);
+
private:
std::unique_ptr<HWComposer> mHwComposer;
std::unique_ptr<renderengine::RenderEngine> mRenderEngine;
+ bool mNeedsAnotherUpdate = false;
+ nsecs_t mRefreshStartTime = 0;
};
std::unique_ptr<compositionengine::CompositionEngine> createCompositionEngine();
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h
index 0e20c43..795061a 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h
@@ -16,12 +16,13 @@
#pragma once
-#include <memory>
-
#include <compositionengine/Display.h>
#include <compositionengine/impl/Output.h>
+#include <memory>
+
#include "DisplayHardware/DisplayIdentification.h"
+#include "DisplayHardware/HWComposer.h"
namespace android::compositionengine {
@@ -39,7 +40,9 @@
// compositionengine::Output overrides
void dump(std::string&) const override;
void setColorTransform(const mat4&) override;
- void setColorMode(ui::ColorMode, ui::Dataspace, ui::RenderIntent) override;
+ void setColorMode(ui::ColorMode, ui::Dataspace, ui::RenderIntent, ui::Dataspace) override;
+ void chooseCompositionStrategy() override;
+ compositionengine::Output::FrameFences presentAndGetFrameFences() override;
// compositionengine::Display overrides
const std::optional<DisplayId>& getId() const override;
@@ -49,12 +52,22 @@
void createDisplayColorProfile(compositionengine::DisplayColorProfileCreationArgs&&) override;
void createRenderSurface(compositionengine::RenderSurfaceCreationArgs&&) override;
+ // Internal helpers used by chooseCompositionStrategy()
+ using ChangedTypes = android::HWComposer::DeviceRequestedChanges::ChangedTypes;
+ using DisplayRequests = android::HWComposer::DeviceRequestedChanges::DisplayRequests;
+ using LayerRequests = android::HWComposer::DeviceRequestedChanges::LayerRequests;
+ virtual bool anyLayersRequireClientComposition() const;
+ virtual bool allLayersRequireClientComposition() const;
+ virtual void applyChangedTypesToLayers(const ChangedTypes&);
+ virtual void applyDisplayRequests(const DisplayRequests&);
+ virtual void applyLayerRequestsToLayers(const LayerRequests&);
+
private:
const bool mIsVirtual;
std::optional<DisplayId> mId;
};
-std::shared_ptr<compositionengine::Display> createDisplay(
- const compositionengine::CompositionEngine&, compositionengine::DisplayCreationArgs&&);
+std::shared_ptr<Display> createDisplay(const compositionengine::CompositionEngine&,
+ compositionengine::DisplayCreationArgs&&);
} // namespace impl
} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/DisplayColorProfile.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/DisplayColorProfile.h
index 49c2d2c..e84a36e 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/DisplayColorProfile.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/DisplayColorProfile.h
@@ -54,6 +54,8 @@
bool hasDolbyVisionSupport() const override;
const HdrCapabilities& getHdrCapabilities() const override;
+ bool isDataspaceSupported(ui::Dataspace) const override;
+ ui::Dataspace getTargetDataspace(ui::ColorMode, ui::Dataspace, ui::Dataspace) const override;
void dump(std::string&) const override;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
index b1d1f42..5f4a764 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
@@ -45,7 +45,7 @@
void setLayerStackFilter(uint32_t layerStackId, bool isInternal) override;
void setColorTransform(const mat4&) override;
- void setColorMode(ui::ColorMode, ui::Dataspace, ui::RenderIntent) override;
+ void setColorMode(ui::ColorMode, ui::Dataspace, ui::RenderIntent, ui::Dataspace) override;
void dump(std::string&) const override;
@@ -72,12 +72,21 @@
void setOutputLayersOrderedByZ(OutputLayers&&) override;
const OutputLayers& getOutputLayersOrderedByZ() const override;
+ void setReleasedLayers(ReleasedLayers&&) override;
+ ReleasedLayers takeReleasedLayers() override;
+
+ void beginFrame() override;
+ void prepareFrame() override;
+ void postFramebuffer() override;
+
// Testing
void setDisplayColorProfileForTest(std::unique_ptr<compositionengine::DisplayColorProfile>);
void setRenderSurfaceForTest(std::unique_ptr<compositionengine::RenderSurface>);
protected:
const CompositionEngine& getCompositionEngine() const;
+ void chooseCompositionStrategy() override;
+ compositionengine::Output::FrameFences presentAndGetFrameFences() override;
void dumpBase(std::string&) const;
private:
@@ -93,6 +102,7 @@
std::unique_ptr<compositionengine::RenderSurface> mRenderSurface;
OutputLayers mOutputLayersOrderedByZ;
+ ReleasedLayers mReleasedLayers;
};
} // namespace impl
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
index 0c47eb5..1078f11 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
@@ -35,6 +35,16 @@
// If false, this output is not considered secure
bool isSecure{false};
+ // If true, the current frame on this output uses client composition
+ bool usesClientComposition{false};
+
+ // If true, the current frame on this output uses device composition
+ bool usesDeviceComposition{false};
+
+ // If true, the client target should be flipped when performing client
+ // composition
+ bool flipClientTarget{false};
+
// If true, this output displays layers that are internal-only
bool layerStackInternal{false};
@@ -88,9 +98,12 @@
// Current active render intent
ui::RenderIntent renderIntent{ui::RenderIntent::COLORIMETRIC};
- // Current active dstaspace
+ // Current active dataspace
ui::Dataspace dataspace{ui::Dataspace::UNKNOWN};
+ // Current target dataspace
+ ui::Dataspace targetDataspace{ui::Dataspace::UNKNOWN};
+
// Debugging
void dump(std::string& result) const;
};
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h
index 6a4818f..d8ad02a 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h
@@ -26,7 +26,11 @@
#include "DisplayHardware/DisplayIdentification.h"
-namespace android::compositionengine::impl {
+namespace android::compositionengine {
+
+struct LayerFECompositionState;
+
+namespace impl {
class OutputLayer : public compositionengine::OutputLayer {
public:
@@ -44,7 +48,13 @@
OutputLayerCompositionState& editState() override;
void updateCompositionState(bool) override;
- void writeStateToHWC(bool) const override;
+ void writeStateToHWC(bool) override;
+
+ HWC2::Layer* getHwcLayer() const override;
+ bool requiresClientComposition() const override;
+ void applyDeviceCompositionTypeChange(Hwc2::IComposerClient::Composition) override;
+ void prepareForDeviceLayerRequests() override;
+ void applyDeviceLayerRequest(Hwc2::IComposerClient::LayerRequest request) override;
void dump(std::string& result) const override;
@@ -54,6 +64,16 @@
private:
Rect calculateInitialCrop() const;
+ void writeOutputDependentGeometryStateToHWC(HWC2::Layer*, Hwc2::IComposerClient::Composition);
+ void writeOutputIndependentGeometryStateToHWC(HWC2::Layer*, const LayerFECompositionState&);
+ void writeOutputDependentPerFrameStateToHWC(HWC2::Layer*);
+ void writeOutputIndependentPerFrameStateToHWC(HWC2::Layer*, const LayerFECompositionState&);
+ void writeSolidColorStateToHWC(HWC2::Layer*, const LayerFECompositionState&);
+ void writeSidebandStateToHWC(HWC2::Layer*, const LayerFECompositionState&);
+ void writeBufferStateToHWC(HWC2::Layer*, const LayerFECompositionState&);
+ void writeCompositionTypeToHWC(HWC2::Layer*, Hwc2::IComposerClient::Composition);
+ void detectDisallowedCompositionTypeChange(Hwc2::IComposerClient::Composition from,
+ Hwc2::IComposerClient::Composition to) const;
const compositionengine::Output& mOutput;
std::shared_ptr<compositionengine::Layer> mLayer;
@@ -66,4 +86,5 @@
const CompositionEngine&, std::optional<DisplayId>, const compositionengine::Output&,
std::shared_ptr<compositionengine::Layer>, sp<compositionengine::LayerFE>);
-} // namespace android::compositionengine::impl
+} // namespace impl
+} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h
index b78e9e0..de0f08a 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h
@@ -23,6 +23,7 @@
#include <compositionengine/impl/HwcBufferCache.h>
#include <renderengine/Mesh.h>
#include <ui/FloatRect.h>
+#include <ui/GraphicTypes.h>
#include <ui/Rect.h>
#include <ui/Region.h>
@@ -57,6 +58,9 @@
// The buffer transform to use for this layer o on this output.
Hwc2::Transform bufferTransform{static_cast<Hwc2::Transform>(0)};
+ // The dataspace for this layer
+ ui::Dataspace dataspace{ui::Dataspace::UNKNOWN};
+
// The Z order index of this layer on this output
uint32_t z;
@@ -70,7 +74,7 @@
// The HWC Layer backing this layer
std::shared_ptr<HWC2::Layer> hwcLayer;
- // The HWC composition type for this layer
+ // The most recently set HWC composition type for this layer
Hwc2::IComposerClient::Composition hwcCompositionType{
Hwc2::IComposerClient::Composition::INVALID};
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h
index e4c9c80..0a04462 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h
@@ -52,7 +52,7 @@
void setDisplaySize(const ui::Size&) override;
void setProtected(bool useProtected) override;
status_t beginFrame(bool mustRecompose) override;
- status_t prepareFrame() override;
+ void prepareFrame(bool usesClientComposition, bool usesDeviceComposition) override;
sp<GraphicBuffer> dequeueBuffer(base::unique_fd* bufferFence) override;
void queueBuffer(base::unique_fd&& readyFence) override;
void onPresentDisplayCompleted() override;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/CompositionEngine.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/CompositionEngine.h
index 0f57685..82ecec5 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/CompositionEngine.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/CompositionEngine.h
@@ -17,6 +17,7 @@
#pragma once
#include <compositionengine/CompositionEngine.h>
+#include <compositionengine/CompositionRefreshArgs.h>
#include <compositionengine/DisplayCreationArgs.h>
#include <compositionengine/LayerCreationArgs.h>
#include <gmock/gmock.h>
@@ -39,6 +40,11 @@
MOCK_CONST_METHOD0(getRenderEngine, renderengine::RenderEngine&());
MOCK_METHOD1(setRenderEngine, void(std::unique_ptr<renderengine::RenderEngine>));
+
+ MOCK_CONST_METHOD0(needsAnotherUpdate, bool());
+ MOCK_CONST_METHOD0(getLastFrameRefreshTimestamp, nsecs_t());
+
+ MOCK_METHOD1(preComposition, void(CompositionRefreshArgs&));
};
} // namespace android::compositionengine::mock
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/DisplayColorProfile.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/DisplayColorProfile.h
index 8056c9d..1aaebea 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/DisplayColorProfile.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/DisplayColorProfile.h
@@ -42,6 +42,9 @@
MOCK_CONST_METHOD0(hasDolbyVisionSupport, bool());
MOCK_CONST_METHOD0(getHdrCapabilities, const HdrCapabilities&());
+ MOCK_CONST_METHOD1(isDataspaceSupported, bool(ui::Dataspace));
+ MOCK_CONST_METHOD3(getTargetDataspace,
+ ui::Dataspace(ui::ColorMode, ui::Dataspace, ui::Dataspace));
MOCK_CONST_METHOD1(dump, void(std::string&));
};
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h
index aab18db..48c2dbf 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h
@@ -30,7 +30,12 @@
LayerFE();
virtual ~LayerFE();
+ MOCK_METHOD1(onPreComposition, bool(nsecs_t));
+
MOCK_CONST_METHOD2(latchCompositionState, void(LayerFECompositionState&, bool));
+ MOCK_METHOD1(prepareClientComposition,
+ std::optional<renderengine::LayerSettings>(
+ compositionengine::LayerFE::ClientCompositionTargetSettings&));
MOCK_METHOD1(onLayerDisplayed, void(const sp<Fence>&));
MOCK_CONST_METHOD0(getDebugName, const char*());
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
index d0e7b19..d494413 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
@@ -41,17 +41,18 @@
MOCK_METHOD2(setLayerStackFilter, void(uint32_t, bool));
MOCK_METHOD1(setColorTransform, void(const mat4&));
- MOCK_METHOD3(setColorMode, void(ui::ColorMode, ui::Dataspace, ui::RenderIntent));
+ MOCK_METHOD4(setColorMode, void(ui::ColorMode, ui::Dataspace, ui::RenderIntent, ui::Dataspace));
MOCK_CONST_METHOD1(dump, void(std::string&));
MOCK_CONST_METHOD0(getName, const std::string&());
MOCK_METHOD1(setName, void(const std::string&));
- MOCK_CONST_METHOD0(getDisplayColorProfile, DisplayColorProfile*());
- MOCK_METHOD1(setDisplayColorProfile, void(std::unique_ptr<DisplayColorProfile>));
+ MOCK_CONST_METHOD0(getDisplayColorProfile, compositionengine::DisplayColorProfile*());
+ MOCK_METHOD1(setDisplayColorProfile,
+ void(std::unique_ptr<compositionengine::DisplayColorProfile>));
- MOCK_CONST_METHOD0(getRenderSurface, RenderSurface*());
- MOCK_METHOD1(setRenderSurface, void(std::unique_ptr<RenderSurface>));
+ MOCK_CONST_METHOD0(getRenderSurface, compositionengine::RenderSurface*());
+ MOCK_METHOD1(setRenderSurface, void(std::unique_ptr<compositionengine::RenderSurface>));
MOCK_CONST_METHOD0(getState, const OutputCompositionState&());
MOCK_METHOD0(editState, OutputCompositionState&());
@@ -65,8 +66,19 @@
std::unique_ptr<compositionengine::OutputLayer>(
std::optional<DisplayId>, std::shared_ptr<compositionengine::Layer>,
sp<compositionengine::LayerFE>));
+
MOCK_METHOD1(setOutputLayersOrderedByZ, void(OutputLayers&&));
MOCK_CONST_METHOD0(getOutputLayersOrderedByZ, OutputLayers&());
+
+ MOCK_METHOD1(setReleasedLayers, void(ReleasedLayers&&));
+ MOCK_METHOD0(takeReleasedLayers, ReleasedLayers());
+
+ MOCK_METHOD0(beginFrame, void());
+ MOCK_METHOD0(prepareFrame, void());
+ MOCK_METHOD0(chooseCompositionStrategy, void());
+
+ MOCK_METHOD0(postFramebuffer, void());
+ MOCK_METHOD0(presentAndGetFrameFences, compositionengine::Output::FrameFences());
};
} // namespace android::compositionengine::mock
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h
index 29cd08a..195648f 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h
@@ -39,7 +39,13 @@
MOCK_METHOD0(editState, impl::OutputLayerCompositionState&());
MOCK_METHOD1(updateCompositionState, void(bool));
- MOCK_CONST_METHOD1(writeStateToHWC, void(bool));
+ MOCK_METHOD1(writeStateToHWC, void(bool));
+
+ MOCK_CONST_METHOD0(getHwcLayer, HWC2::Layer*());
+ MOCK_CONST_METHOD0(requiresClientComposition, bool());
+ MOCK_METHOD1(applyDeviceCompositionTypeChange, void(Hwc2::IComposerClient::Composition));
+ MOCK_METHOD0(prepareForDeviceLayerRequests, void());
+ MOCK_METHOD1(applyDeviceLayerRequest, void(Hwc2::IComposerClient::LayerRequest request));
MOCK_CONST_METHOD1(dump, void(std::string&));
};
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h
index 146a2ea..ba6746a 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h
@@ -37,7 +37,7 @@
MOCK_METHOD1(setProtected, void(bool));
MOCK_METHOD1(setBufferDataspace, void(ui::Dataspace));
MOCK_METHOD1(beginFrame, status_t(bool mustRecompose));
- MOCK_METHOD0(prepareFrame, status_t());
+ MOCK_METHOD2(prepareFrame, void(bool, bool));
MOCK_METHOD1(dequeueBuffer, sp<GraphicBuffer>(base::unique_fd*));
MOCK_METHOD1(queueBuffer, void(base::unique_fd&&));
MOCK_METHOD0(onPresentDisplayCompleted, void());
diff --git a/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp b/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp
index cb08b81..9558266 100644
--- a/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp
@@ -14,10 +14,13 @@
* limitations under the License.
*/
+#include <compositionengine/CompositionRefreshArgs.h>
+#include <compositionengine/LayerFE.h>
#include <compositionengine/impl/CompositionEngine.h>
#include <compositionengine/impl/Display.h>
#include <compositionengine/impl/Layer.h>
#include <renderengine/RenderEngine.h>
+#include <utils/Trace.h>
#include "DisplayHardware/HWComposer.h"
@@ -59,5 +62,35 @@
mRenderEngine = std::move(renderEngine);
}
+bool CompositionEngine::needsAnotherUpdate() const {
+ return mNeedsAnotherUpdate;
+}
+
+nsecs_t CompositionEngine::getLastFrameRefreshTimestamp() const {
+ return mRefreshStartTime;
+}
+
+void CompositionEngine::preComposition(CompositionRefreshArgs& args) {
+ ATRACE_CALL();
+ ALOGV(__FUNCTION__);
+
+ bool needsAnotherUpdate = false;
+
+ mRefreshStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+
+ for (auto& layer : args.layers) {
+ sp<compositionengine::LayerFE> layerFE = layer->getLayerFE();
+ if (layerFE && layerFE->onPreComposition(mRefreshStartTime)) {
+ needsAnotherUpdate = true;
+ }
+ }
+
+ mNeedsAnotherUpdate = needsAnotherUpdate;
+}
+
+void CompositionEngine::setNeedsAnotherUpdateForTest(bool value) {
+ mNeedsAnotherUpdate = value;
+}
+
} // namespace impl
} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/src/Display.cpp b/services/surfaceflinger/CompositionEngine/src/Display.cpp
index f9d70e3..6831901 100644
--- a/services/surfaceflinger/CompositionEngine/src/Display.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Display.cpp
@@ -21,13 +21,15 @@
#include <compositionengine/impl/Display.h>
#include <compositionengine/impl/DisplayColorProfile.h>
#include <compositionengine/impl/DumpHelpers.h>
+#include <compositionengine/impl/OutputLayer.h>
#include <compositionengine/impl/RenderSurface.h>
+#include <utils/Trace.h>
#include "DisplayHardware/HWComposer.h"
namespace android::compositionengine::impl {
-std::shared_ptr<compositionengine::Display> createDisplay(
+std::shared_ptr<Display> createDisplay(
const compositionengine::CompositionEngine& compositionEngine,
compositionengine::DisplayCreationArgs&& args) {
return std::make_shared<Display>(compositionEngine, std::move(args));
@@ -74,9 +76,14 @@
}
void Display::setColorMode(ui::ColorMode mode, ui::Dataspace dataspace,
- ui::RenderIntent renderIntent) {
+ ui::RenderIntent renderIntent,
+ ui::Dataspace colorSpaceAgnosticDataspace) {
+ ui::Dataspace targetDataspace =
+ getDisplayColorProfile()->getTargetDataspace(mode, dataspace,
+ colorSpaceAgnosticDataspace);
+
if (mode == getState().colorMode && dataspace == getState().dataspace &&
- renderIntent == getState().renderIntent) {
+ renderIntent == getState().renderIntent && targetDataspace == getState().targetDataspace) {
return;
}
@@ -85,7 +92,7 @@
return;
}
- Output::setColorMode(mode, dataspace, renderIntent);
+ Output::setColorMode(mode, dataspace, renderIntent, colorSpaceAgnosticDataspace);
auto& hwc = getCompositionEngine().getHwComposer();
hwc.setActiveColorMode(*mId, mode, renderIntent);
@@ -119,4 +126,118 @@
std::move(args)));
}
+void Display::chooseCompositionStrategy() {
+ ATRACE_CALL();
+ ALOGV(__FUNCTION__);
+
+ // Default to the base settings -- client composition only.
+ Output::chooseCompositionStrategy();
+
+ // If we don't have a HWC display, then we are done
+ if (!mId) {
+ return;
+ }
+
+ // Get any composition changes requested by the HWC device, and apply them.
+ std::optional<android::HWComposer::DeviceRequestedChanges> changes;
+ auto& hwc = getCompositionEngine().getHwComposer();
+ if (status_t result = hwc.getDeviceCompositionChanges(*mId, anyLayersRequireClientComposition(),
+ &changes);
+ result != NO_ERROR) {
+ ALOGE("chooseCompositionStrategy failed for %s: %d (%s)", getName().c_str(), result,
+ strerror(-result));
+ return;
+ }
+ if (changes) {
+ applyChangedTypesToLayers(changes->changedTypes);
+ applyDisplayRequests(changes->displayRequests);
+ applyLayerRequestsToLayers(changes->layerRequests);
+ }
+
+ // Determine what type of composition we are doing from the final state
+ auto& state = editState();
+ state.usesClientComposition = anyLayersRequireClientComposition();
+ state.usesDeviceComposition = !allLayersRequireClientComposition();
+}
+
+bool Display::anyLayersRequireClientComposition() const {
+ const auto& layers = getOutputLayersOrderedByZ();
+ return std::any_of(layers.cbegin(), layers.cend(),
+ [](const auto& layer) { return layer->requiresClientComposition(); });
+}
+
+bool Display::allLayersRequireClientComposition() const {
+ const auto& layers = getOutputLayersOrderedByZ();
+ return std::all_of(layers.cbegin(), layers.cend(),
+ [](const auto& layer) { return layer->requiresClientComposition(); });
+}
+
+void Display::applyChangedTypesToLayers(const ChangedTypes& changedTypes) {
+ if (changedTypes.empty()) {
+ return;
+ }
+
+ for (auto& layer : getOutputLayersOrderedByZ()) {
+ auto hwcLayer = layer->getHwcLayer();
+ if (!hwcLayer) {
+ continue;
+ }
+
+ if (auto it = changedTypes.find(hwcLayer); it != changedTypes.end()) {
+ layer->applyDeviceCompositionTypeChange(
+ static_cast<Hwc2::IComposerClient::Composition>(it->second));
+ }
+ }
+}
+
+void Display::applyDisplayRequests(const DisplayRequests& displayRequests) {
+ auto& state = editState();
+ state.flipClientTarget = (static_cast<uint32_t>(displayRequests) &
+ static_cast<uint32_t>(HWC2::DisplayRequest::FlipClientTarget)) != 0;
+ // Note: HWC2::DisplayRequest::WriteClientTargetToOutput is currently ignored.
+}
+
+void Display::applyLayerRequestsToLayers(const LayerRequests& layerRequests) {
+ for (auto& layer : getOutputLayersOrderedByZ()) {
+ layer->prepareForDeviceLayerRequests();
+
+ auto hwcLayer = layer->getHwcLayer();
+ if (!hwcLayer) {
+ continue;
+ }
+
+ if (auto it = layerRequests.find(hwcLayer); it != layerRequests.end()) {
+ layer->applyDeviceLayerRequest(
+ static_cast<Hwc2::IComposerClient::LayerRequest>(it->second));
+ }
+ }
+}
+
+compositionengine::Output::FrameFences Display::presentAndGetFrameFences() {
+ auto result = impl::Output::presentAndGetFrameFences();
+
+ if (!mId) {
+ return result;
+ }
+
+ auto& hwc = getCompositionEngine().getHwComposer();
+ hwc.presentAndGetReleaseFences(*mId);
+
+ result.presentFence = hwc.getPresentFence(*mId);
+
+ // TODO(b/121291683): Change HWComposer call to return entire map
+ for (const auto& layer : getOutputLayersOrderedByZ()) {
+ auto hwcLayer = layer->getHwcLayer();
+ if (!hwcLayer) {
+ continue;
+ }
+
+ result.layerFences.emplace(hwcLayer, hwc.getLayerReleaseFence(*mId, hwcLayer));
+ }
+
+ hwc.clearReleaseFences(*mId);
+
+ return result;
+}
+
} // namespace android::compositionengine::impl
diff --git a/services/surfaceflinger/CompositionEngine/src/DisplayColorProfile.cpp b/services/surfaceflinger/CompositionEngine/src/DisplayColorProfile.cpp
index 130ab1d..5ef9097 100644
--- a/services/surfaceflinger/CompositionEngine/src/DisplayColorProfile.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/DisplayColorProfile.cpp
@@ -64,6 +64,12 @@
RenderIntent::TONE_MAP_COLORIMETRIC,
};
+// Returns true if the given colorMode is considered an HDR color mode
+bool isHdrColorMode(const ColorMode colorMode) {
+ return std::any_of(std::begin(sHdrColorModes), std::end(sHdrColorModes),
+ [colorMode](ColorMode hdrColorMode) { return hdrColorMode == colorMode; });
+}
+
// map known color mode to dataspace
Dataspace colorModeToDataspace(ColorMode mode) {
switch (mode) {
@@ -90,13 +96,7 @@
candidates.push_back(mode);
// check if mode is HDR
- bool isHdr = false;
- for (auto hdrMode : sHdrColorModes) {
- if (hdrMode == mode) {
- isHdr = true;
- break;
- }
- }
+ bool isHdr = isHdrColorMode(mode);
// add other HDR candidates when mode is HDR
if (isHdr) {
@@ -376,6 +376,32 @@
}
}
+bool DisplayColorProfile::isDataspaceSupported(Dataspace dataspace) const {
+ switch (dataspace) {
+ case Dataspace::BT2020_PQ:
+ case Dataspace::BT2020_ITU_PQ:
+ return hasHDR10Support();
+
+ case Dataspace::BT2020_HLG:
+ case Dataspace::BT2020_ITU_HLG:
+ return hasHLGSupport();
+
+ default:
+ return true;
+ }
+}
+
+ui::Dataspace DisplayColorProfile::getTargetDataspace(ColorMode mode, Dataspace dataspace,
+ Dataspace colorSpaceAgnosticDataspace) const {
+ if (isHdrColorMode(mode)) {
+ return Dataspace::UNKNOWN;
+ }
+ if (colorSpaceAgnosticDataspace != ui::Dataspace::UNKNOWN) {
+ return colorSpaceAgnosticDataspace;
+ }
+ return dataspace;
+}
+
void DisplayColorProfile::dump(std::string& out) const {
out.append(" Composition Display Color State:");
diff --git a/services/surfaceflinger/CompositionEngine/src/LayerCompositionState.cpp b/services/surfaceflinger/CompositionEngine/src/LayerCompositionState.cpp
index 40c4da9..37d6eaa 100644
--- a/services/surfaceflinger/CompositionEngine/src/LayerCompositionState.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/LayerCompositionState.cpp
@@ -24,9 +24,10 @@
using android::compositionengine::impl::dumpVal;
-void dumpVal(std::string& out, const char* name, Hwc2::IComposerClient::Color value) {
+void dumpVal(std::string& out, const char* name, half4 value) {
using android::base::StringAppendF;
- StringAppendF(&out, "%s=[%d %d %d] ", name, value.r, value.g, value.b);
+ StringAppendF(&out, "%s=[%f %f %f] ", name, static_cast<float>(value.r),
+ static_cast<float>(value.g), static_cast<float>(value.b));
}
void dumpFrontEnd(std::string& out, const LayerFECompositionState& state) {
@@ -60,8 +61,8 @@
dumpVal(out, "composition type", toString(state.compositionType), state.compositionType);
out.append("\n buffer: ");
+ dumpVal(out, "bufferSlot", state.bufferSlot);
dumpVal(out, "buffer", state.buffer.get());
- dumpVal(out, "slot", state.bufferSlot);
out.append("\n ");
dumpVal(out, "sideband stream", state.sidebandStream.get());
@@ -70,6 +71,7 @@
dumpVal(out, "color", state.color);
out.append("\n ");
+ dumpVal(out, "isColorspaceAgnostic", state.isColorspaceAgnostic);
dumpVal(out, "dataspace", toString(state.dataspace), state.dataspace);
dumpVal(out, "hdr metadata types", state.hdrMetadata.validTypes);
dumpVal(out, "colorTransform", state.colorTransform);
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index 01b5781..b411e0a 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -22,6 +22,7 @@
#include <compositionengine/impl/Output.h>
#include <compositionengine/impl/OutputLayer.h>
#include <ui/DebugUtils.h>
+#include <utils/Trace.h>
namespace android::compositionengine {
@@ -104,15 +105,21 @@
}
void Output::setColorMode(ui::ColorMode mode, ui::Dataspace dataspace,
- ui::RenderIntent renderIntent) {
+ ui::RenderIntent renderIntent,
+ ui::Dataspace colorSpaceAgnosticDataspace) {
+ ui::Dataspace targetDataspace =
+ getDisplayColorProfile()->getTargetDataspace(mode, dataspace,
+ colorSpaceAgnosticDataspace);
+
if (mState.colorMode == mode && mState.dataspace == dataspace &&
- mState.renderIntent == renderIntent) {
+ mState.renderIntent == renderIntent && mState.targetDataspace == targetDataspace) {
return;
}
mState.colorMode = mode;
mState.dataspace = dataspace;
mState.renderIntent = renderIntent;
+ mState.targetDataspace = targetDataspace;
mRenderSurface->setBufferDataspace(dataspace);
@@ -236,9 +243,123 @@
return mOutputLayersOrderedByZ;
}
+void Output::setReleasedLayers(Output::ReleasedLayers&& layers) {
+ mReleasedLayers = std::move(layers);
+}
+
+Output::ReleasedLayers Output::takeReleasedLayers() {
+ return std::move(mReleasedLayers);
+}
+
+void Output::beginFrame() {
+ const bool dirty = !getDirtyRegion(false).isEmpty();
+ const bool empty = mOutputLayersOrderedByZ.empty();
+ const bool wasEmpty = !mState.lastCompositionHadVisibleLayers;
+
+ // If nothing has changed (!dirty), don't recompose.
+ // If something changed, but we don't currently have any visible layers,
+ // and didn't when we last did a composition, then skip it this time.
+ // The second rule does two things:
+ // - When all layers are removed from a display, we'll emit one black
+ // frame, then nothing more until we get new layers.
+ // - When a display is created with a private layer stack, we won't
+ // emit any black frames until a layer is added to the layer stack.
+ const bool mustRecompose = dirty && !(empty && wasEmpty);
+
+ const char flagPrefix[] = {'-', '+'};
+ static_cast<void>(flagPrefix);
+ ALOGV_IF("%s: %s composition for %s (%cdirty %cempty %cwasEmpty)", __FUNCTION__,
+ mustRecompose ? "doing" : "skipping", getName().c_str(), flagPrefix[dirty],
+ flagPrefix[empty], flagPrefix[wasEmpty]);
+
+ mRenderSurface->beginFrame(mustRecompose);
+
+ if (mustRecompose) {
+ mState.lastCompositionHadVisibleLayers = !empty;
+ }
+}
+
+void Output::prepareFrame() {
+ ATRACE_CALL();
+ ALOGV(__FUNCTION__);
+
+ if (!mState.isEnabled) {
+ return;
+ }
+
+ chooseCompositionStrategy();
+
+ mRenderSurface->prepareFrame(mState.usesClientComposition, mState.usesDeviceComposition);
+}
+
+void Output::postFramebuffer() {
+ ATRACE_CALL();
+ ALOGV(__FUNCTION__);
+
+ if (!getState().isEnabled) {
+ return;
+ }
+
+ mRenderSurface->onPresentDisplayCompleted();
+
+ auto frame = presentAndGetFrameFences();
+
+ for (auto& layer : getOutputLayersOrderedByZ()) {
+ // The layer buffer from the previous frame (if any) is released
+ // by HWC only when the release fence from this frame (if any) is
+ // signaled. Always get the release fence from HWC first.
+ sp<Fence> releaseFence = Fence::NO_FENCE;
+
+ if (auto hwcLayer = layer->getHwcLayer()) {
+ if (auto f = frame.layerFences.find(hwcLayer); f != frame.layerFences.end()) {
+ releaseFence = f->second;
+ }
+ }
+
+ // If the layer was client composited in the previous frame, we
+ // need to merge with the previous client target acquire fence.
+ // Since we do not track that, always merge with the current
+ // client target acquire fence when it is available, even though
+ // this is suboptimal.
+ // TODO(b/121291683): Track previous frame client target acquire fence.
+ if (mState.usesClientComposition) {
+ releaseFence =
+ Fence::merge("LayerRelease", releaseFence, frame.clientTargetAcquireFence);
+ }
+
+ layer->getLayerFE().onLayerDisplayed(releaseFence);
+ }
+
+ // We've got a list of layers needing fences, that are disjoint with
+ // getOutputLayersOrderedByZ. The best we can do is to
+ // supply them with the present fence.
+ for (auto& weakLayer : mReleasedLayers) {
+ if (auto layer = weakLayer.promote(); layer != nullptr) {
+ layer->onLayerDisplayed(frame.presentFence);
+ }
+ }
+
+ // Clear out the released layers now that we're done with them.
+ mReleasedLayers.clear();
+}
+
void Output::dirtyEntireOutput() {
mState.dirtyRegion.set(mState.bounds);
}
+void Output::chooseCompositionStrategy() {
+ // The base output implementation can only do client composition
+ mState.usesClientComposition = true;
+ mState.usesDeviceComposition = false;
+}
+
+compositionengine::Output::FrameFences Output::presentAndGetFrameFences() {
+ compositionengine::Output::FrameFences result;
+ if (mState.usesClientComposition) {
+ result.clientTargetAcquireFence = mRenderSurface->getClientTargetAcquireFence();
+ }
+ return result;
+}
+
} // namespace impl
} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp b/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp
index 9549054..3e47fe2 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp
@@ -24,6 +24,10 @@
dumpVal(out, "isEnabled", isEnabled);
dumpVal(out, "isSecure", isSecure);
+ dumpVal(out, "usesClientComposition", usesClientComposition);
+ dumpVal(out, "usesDeviceComposition", usesDeviceComposition);
+ dumpVal(out, "flipClientTarget", flipClientTarget);
+
dumpVal(out, "layerStack", layerStackId);
dumpVal(out, "layerStackInternal", layerStackInternal);
@@ -44,6 +48,7 @@
dumpVal(out, "renderIntent", toString(renderIntent), renderIntent);
dumpVal(out, "dataspace", toString(dataspace), dataspace);
dumpVal(out, "colorTransform", colorTransform);
+ dumpVal(out, "target dataspace", toString(targetDataspace), targetDataspace);
out.append("\n");
}
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
index 5ce72b0..6e744b9 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
@@ -16,6 +16,7 @@
#include <android-base/stringprintf.h>
#include <compositionengine/CompositionEngine.h>
+#include <compositionengine/DisplayColorProfile.h>
#include <compositionengine/Layer.h>
#include <compositionengine/LayerFE.h>
#include <compositionengine/Output.h>
@@ -290,20 +291,43 @@
} // namespace impl
void OutputLayer::updateCompositionState(bool includeGeometry) {
+ const auto& layerFEState = mLayer->getState().frontEnd;
+ const auto& outputState = mOutput.getState();
+ const auto& profile = *mOutput.getDisplayColorProfile();
+
if (includeGeometry) {
mState.displayFrame = calculateOutputDisplayFrame();
mState.sourceCrop = calculateOutputSourceCrop();
mState.bufferTransform =
static_cast<Hwc2::Transform>(calculateOutputRelativeBufferTransform());
- if ((mLayer->getState().frontEnd.isSecure && !mOutput.getState().isSecure) ||
+ if ((layerFEState.isSecure && !outputState.isSecure) ||
(mState.bufferTransform & ui::Transform::ROT_INVALID)) {
mState.forceClientComposition = true;
}
}
+
+ // Determine the output dependent dataspace for this layer. If it is
+ // colorspace agnostic, it just uses the dataspace chosen for the output to
+ // avoid the need for color conversion.
+ mState.dataspace = layerFEState.isColorspaceAgnostic &&
+ outputState.targetDataspace != ui::Dataspace::UNKNOWN
+ ? outputState.targetDataspace
+ : layerFEState.dataspace;
+
+ // TODO(lpique): b/121291683 Remove this one we are sure we don't need the
+ // value recomputed / set every frame.
+ mState.visibleRegion = outputState.transform.transform(
+ layerFEState.geomVisibleRegion.intersect(outputState.viewport));
+
+ // These are evaluated every frame as they can potentially change at any
+ // time.
+ if (layerFEState.forceClientComposition || !profile.isDataspaceSupported(mState.dataspace)) {
+ mState.forceClientComposition = true;
+ }
}
-void OutputLayer::writeStateToHWC(bool includeGeometry) const {
+void OutputLayer::writeStateToHWC(bool includeGeometry) {
// Skip doing this if there is no HWC interface
if (!mState.hwc) {
return;
@@ -316,63 +340,277 @@
return;
}
+ const auto& outputIndependentState = mLayer->getState().frontEnd;
+ auto requestedCompositionType = outputIndependentState.compositionType;
+
if (includeGeometry) {
- // Output dependent state
+ writeOutputDependentGeometryStateToHWC(hwcLayer.get(), requestedCompositionType);
+ writeOutputIndependentGeometryStateToHWC(hwcLayer.get(), outputIndependentState);
+ }
- if (auto error = hwcLayer->setDisplayFrame(mState.displayFrame);
- error != HWC2::Error::None) {
- ALOGE("[%s] Failed to set display frame [%d, %d, %d, %d]: %s (%d)",
- mLayerFE->getDebugName(), mState.displayFrame.left, mState.displayFrame.top,
- mState.displayFrame.right, mState.displayFrame.bottom, to_string(error).c_str(),
- static_cast<int32_t>(error));
- }
+ writeOutputDependentPerFrameStateToHWC(hwcLayer.get());
+ writeOutputIndependentPerFrameStateToHWC(hwcLayer.get(), outputIndependentState);
- if (auto error = hwcLayer->setSourceCrop(mState.sourceCrop); error != HWC2::Error::None) {
- ALOGE("[%s] Failed to set source crop [%.3f, %.3f, %.3f, %.3f]: "
- "%s (%d)",
- mLayerFE->getDebugName(), mState.sourceCrop.left, mState.sourceCrop.top,
- mState.sourceCrop.right, mState.sourceCrop.bottom, to_string(error).c_str(),
- static_cast<int32_t>(error));
- }
+ writeCompositionTypeToHWC(hwcLayer.get(), requestedCompositionType);
+}
- if (auto error = hwcLayer->setZOrder(mState.z); error != HWC2::Error::None) {
- ALOGE("[%s] Failed to set Z %u: %s (%d)", mLayerFE->getDebugName(), mState.z,
+void OutputLayer::writeOutputDependentGeometryStateToHWC(
+ HWC2::Layer* hwcLayer, Hwc2::IComposerClient::Composition requestedCompositionType) {
+ const auto& outputDependentState = getState();
+
+ if (auto error = hwcLayer->setDisplayFrame(outputDependentState.displayFrame);
+ error != HWC2::Error::None) {
+ ALOGE("[%s] Failed to set display frame [%d, %d, %d, %d]: %s (%d)",
+ mLayerFE->getDebugName(), outputDependentState.displayFrame.left,
+ outputDependentState.displayFrame.top, outputDependentState.displayFrame.right,
+ outputDependentState.displayFrame.bottom, to_string(error).c_str(),
+ static_cast<int32_t>(error));
+ }
+
+ if (auto error = hwcLayer->setSourceCrop(outputDependentState.sourceCrop);
+ error != HWC2::Error::None) {
+ ALOGE("[%s] Failed to set source crop [%.3f, %.3f, %.3f, %.3f]: "
+ "%s (%d)",
+ mLayerFE->getDebugName(), outputDependentState.sourceCrop.left,
+ outputDependentState.sourceCrop.top, outputDependentState.sourceCrop.right,
+ outputDependentState.sourceCrop.bottom, to_string(error).c_str(),
+ static_cast<int32_t>(error));
+ }
+
+ if (auto error = hwcLayer->setZOrder(outputDependentState.z); error != HWC2::Error::None) {
+ ALOGE("[%s] Failed to set Z %u: %s (%d)", mLayerFE->getDebugName(), outputDependentState.z,
+ to_string(error).c_str(), static_cast<int32_t>(error));
+ }
+
+ // Solid-color layers should always use an identity transform.
+ const auto bufferTransform =
+ requestedCompositionType != Hwc2::IComposerClient::Composition::SOLID_COLOR
+ ? outputDependentState.bufferTransform
+ : static_cast<Hwc2::Transform>(0);
+ if (auto error = hwcLayer->setTransform(static_cast<HWC2::Transform>(bufferTransform));
+ error != HWC2::Error::None) {
+ ALOGE("[%s] Failed to set transform %s: %s (%d)", mLayerFE->getDebugName(),
+ toString(outputDependentState.bufferTransform).c_str(), to_string(error).c_str(),
+ static_cast<int32_t>(error));
+ }
+}
+
+void OutputLayer::writeOutputIndependentGeometryStateToHWC(
+ HWC2::Layer* hwcLayer, const LayerFECompositionState& outputIndependentState) {
+ if (auto error = hwcLayer->setBlendMode(
+ static_cast<HWC2::BlendMode>(outputIndependentState.blendMode));
+ error != HWC2::Error::None) {
+ ALOGE("[%s] Failed to set blend mode %s: %s (%d)", mLayerFE->getDebugName(),
+ toString(outputIndependentState.blendMode).c_str(), to_string(error).c_str(),
+ static_cast<int32_t>(error));
+ }
+
+ if (auto error = hwcLayer->setPlaneAlpha(outputIndependentState.alpha);
+ error != HWC2::Error::None) {
+ ALOGE("[%s] Failed to set plane alpha %.3f: %s (%d)", mLayerFE->getDebugName(),
+ outputIndependentState.alpha, to_string(error).c_str(), static_cast<int32_t>(error));
+ }
+
+ if (auto error = hwcLayer->setInfo(outputIndependentState.type, outputIndependentState.appId);
+ error != HWC2::Error::None) {
+ ALOGE("[%s] Failed to set info %s (%d)", mLayerFE->getDebugName(), to_string(error).c_str(),
+ static_cast<int32_t>(error));
+ }
+}
+
+void OutputLayer::writeOutputDependentPerFrameStateToHWC(HWC2::Layer* hwcLayer) {
+ const auto& outputDependentState = getState();
+
+ // TODO(lpique): b/121291683 visibleRegion is output-dependent geometry
+ // state and should not change every frame.
+ if (auto error = hwcLayer->setVisibleRegion(outputDependentState.visibleRegion);
+ error != HWC2::Error::None) {
+ ALOGE("[%s] Failed to set visible region: %s (%d)", mLayerFE->getDebugName(),
+ to_string(error).c_str(), static_cast<int32_t>(error));
+ outputDependentState.visibleRegion.dump(LOG_TAG);
+ }
+
+ if (auto error = hwcLayer->setDataspace(outputDependentState.dataspace);
+ error != HWC2::Error::None) {
+ ALOGE("[%s] Failed to set dataspace %d: %s (%d)", mLayerFE->getDebugName(),
+ outputDependentState.dataspace, to_string(error).c_str(),
+ static_cast<int32_t>(error));
+ }
+}
+
+void OutputLayer::writeOutputIndependentPerFrameStateToHWC(
+ HWC2::Layer* hwcLayer, const LayerFECompositionState& outputIndependentState) {
+ switch (auto error = hwcLayer->setColorTransform(outputIndependentState.colorTransform)) {
+ case HWC2::Error::None:
+ break;
+ case HWC2::Error::Unsupported:
+ editState().forceClientComposition = true;
+ break;
+ default:
+ ALOGE("[%s] Failed to set color transform: %s (%d)", mLayerFE->getDebugName(),
to_string(error).c_str(), static_cast<int32_t>(error));
- }
+ }
- if (auto error =
- hwcLayer->setTransform(static_cast<HWC2::Transform>(mState.bufferTransform));
+ if (auto error = hwcLayer->setSurfaceDamage(outputIndependentState.surfaceDamage);
+ error != HWC2::Error::None) {
+ ALOGE("[%s] Failed to set surface damage: %s (%d)", mLayerFE->getDebugName(),
+ to_string(error).c_str(), static_cast<int32_t>(error));
+ outputIndependentState.surfaceDamage.dump(LOG_TAG);
+ }
+
+ // Content-specific per-frame state
+ switch (outputIndependentState.compositionType) {
+ case Hwc2::IComposerClient::Composition::SOLID_COLOR:
+ writeSolidColorStateToHWC(hwcLayer, outputIndependentState);
+ break;
+ case Hwc2::IComposerClient::Composition::SIDEBAND:
+ writeSidebandStateToHWC(hwcLayer, outputIndependentState);
+ break;
+ case Hwc2::IComposerClient::Composition::CURSOR:
+ case Hwc2::IComposerClient::Composition::DEVICE:
+ writeBufferStateToHWC(hwcLayer, outputIndependentState);
+ break;
+ case Hwc2::IComposerClient::Composition::INVALID:
+ case Hwc2::IComposerClient::Composition::CLIENT:
+ // Ignored
+ break;
+ }
+}
+
+void OutputLayer::writeSolidColorStateToHWC(HWC2::Layer* hwcLayer,
+ const LayerFECompositionState& outputIndependentState) {
+ hwc_color_t color = {static_cast<uint8_t>(std::round(255.0f * outputIndependentState.color.r)),
+ static_cast<uint8_t>(std::round(255.0f * outputIndependentState.color.g)),
+ static_cast<uint8_t>(std::round(255.0f * outputIndependentState.color.b)),
+ 255};
+
+ if (auto error = hwcLayer->setColor(color); error != HWC2::Error::None) {
+ ALOGE("[%s] Failed to set color: %s (%d)", mLayerFE->getDebugName(),
+ to_string(error).c_str(), static_cast<int32_t>(error));
+ }
+}
+
+void OutputLayer::writeSidebandStateToHWC(HWC2::Layer* hwcLayer,
+ const LayerFECompositionState& outputIndependentState) {
+ if (auto error = hwcLayer->setSidebandStream(outputIndependentState.sidebandStream->handle());
+ error != HWC2::Error::None) {
+ ALOGE("[%s] Failed to set sideband stream %p: %s (%d)", mLayerFE->getDebugName(),
+ outputIndependentState.sidebandStream->handle(), to_string(error).c_str(),
+ static_cast<int32_t>(error));
+ }
+}
+
+void OutputLayer::writeBufferStateToHWC(HWC2::Layer* hwcLayer,
+ const LayerFECompositionState& outputIndependentState) {
+ auto supportedPerFrameMetadata =
+ mOutput.getDisplayColorProfile()->getSupportedPerFrameMetadata();
+ if (auto error = hwcLayer->setPerFrameMetadata(supportedPerFrameMetadata,
+ outputIndependentState.hdrMetadata);
+ error != HWC2::Error::None && error != HWC2::Error::Unsupported) {
+ ALOGE("[%s] Failed to set hdrMetadata: %s (%d)", mLayerFE->getDebugName(),
+ to_string(error).c_str(), static_cast<int32_t>(error));
+ }
+
+ uint32_t hwcSlot = 0;
+ sp<GraphicBuffer> hwcBuffer;
+ // We need access to the output-dependent state for the buffer cache there,
+ // though otherwise the buffer is not output-dependent.
+ editState().hwc->hwcBufferCache.getHwcBuffer(outputIndependentState.bufferSlot,
+ outputIndependentState.buffer, &hwcSlot,
+ &hwcBuffer);
+
+ if (auto error = hwcLayer->setBuffer(hwcSlot, hwcBuffer, outputIndependentState.acquireFence);
+ error != HWC2::Error::None) {
+ ALOGE("[%s] Failed to set buffer %p: %s (%d)", mLayerFE->getDebugName(),
+ outputIndependentState.buffer->handle, to_string(error).c_str(),
+ static_cast<int32_t>(error));
+ }
+}
+
+void OutputLayer::writeCompositionTypeToHWC(
+ HWC2::Layer* hwcLayer, Hwc2::IComposerClient::Composition requestedCompositionType) {
+ auto& outputDependentState = editState();
+
+ // If we are forcing client composition, we need to tell the HWC
+ if (outputDependentState.forceClientComposition) {
+ requestedCompositionType = Hwc2::IComposerClient::Composition::CLIENT;
+ }
+
+ // Set the requested composition type with the HWC whenever it changes
+ if (outputDependentState.hwc->hwcCompositionType != requestedCompositionType) {
+ outputDependentState.hwc->hwcCompositionType = requestedCompositionType;
+
+ if (auto error = hwcLayer->setCompositionType(
+ static_cast<HWC2::Composition>(requestedCompositionType));
error != HWC2::Error::None) {
- ALOGE("[%s] Failed to set transform %s: %s (%d)", mLayerFE->getDebugName(),
- toString(mState.bufferTransform).c_str(), to_string(error).c_str(),
+ ALOGE("[%s] Failed to set composition type %s: %s (%d)", mLayerFE->getDebugName(),
+ toString(requestedCompositionType).c_str(), to_string(error).c_str(),
static_cast<int32_t>(error));
}
+ }
+}
- // Output independent state
+HWC2::Layer* OutputLayer::getHwcLayer() const {
+ return mState.hwc ? mState.hwc->hwcLayer.get() : nullptr;
+}
- const auto& outputIndependentState = mLayer->getState().frontEnd;
+bool OutputLayer::requiresClientComposition() const {
+ return !mState.hwc ||
+ mState.hwc->hwcCompositionType == Hwc2::IComposerClient::Composition::CLIENT;
+}
- if (auto error = hwcLayer->setBlendMode(
- static_cast<HWC2::BlendMode>(outputIndependentState.blendMode));
- error != HWC2::Error::None) {
- ALOGE("[%s] Failed to set blend mode %s: %s (%d)", mLayerFE->getDebugName(),
- toString(outputIndependentState.blendMode).c_str(), to_string(error).c_str(),
- static_cast<int32_t>(error));
- }
+void OutputLayer::detectDisallowedCompositionTypeChange(
+ Hwc2::IComposerClient::Composition from, Hwc2::IComposerClient::Composition to) const {
+ bool result = false;
+ switch (from) {
+ case Hwc2::IComposerClient::Composition::INVALID:
+ case Hwc2::IComposerClient::Composition::CLIENT:
+ result = false;
+ break;
- if (auto error = hwcLayer->setPlaneAlpha(outputIndependentState.alpha);
- error != HWC2::Error::None) {
- ALOGE("[%s] Failed to set plane alpha %.3f: %s (%d)", mLayerFE->getDebugName(),
- outputIndependentState.alpha, to_string(error).c_str(),
- static_cast<int32_t>(error));
- }
+ case Hwc2::IComposerClient::Composition::DEVICE:
+ case Hwc2::IComposerClient::Composition::SOLID_COLOR:
+ result = (to == Hwc2::IComposerClient::Composition::CLIENT);
+ break;
- if (auto error =
- hwcLayer->setInfo(outputIndependentState.type, outputIndependentState.appId);
- error != HWC2::Error::None) {
- ALOGE("[%s] Failed to set info %s (%d)", mLayerFE->getDebugName(),
- to_string(error).c_str(), static_cast<int32_t>(error));
- }
+ case Hwc2::IComposerClient::Composition::CURSOR:
+ case Hwc2::IComposerClient::Composition::SIDEBAND:
+ result = (to == Hwc2::IComposerClient::Composition::CLIENT ||
+ to == Hwc2::IComposerClient::Composition::DEVICE);
+ break;
+ }
+
+ if (!result) {
+ ALOGE("[%s] Invalid device requested composition type change: %s (%d) --> %s (%d)",
+ mLayerFE->getDebugName(), toString(from).c_str(), static_cast<int>(from),
+ toString(to).c_str(), static_cast<int>(to));
+ }
+}
+
+void OutputLayer::applyDeviceCompositionTypeChange(
+ Hwc2::IComposerClient::Composition compositionType) {
+ LOG_FATAL_IF(!mState.hwc);
+ auto& hwcState = *mState.hwc;
+
+ detectDisallowedCompositionTypeChange(hwcState.hwcCompositionType, compositionType);
+
+ hwcState.hwcCompositionType = compositionType;
+}
+
+void OutputLayer::prepareForDeviceLayerRequests() {
+ mState.clearClientTarget = false;
+}
+
+void OutputLayer::applyDeviceLayerRequest(Hwc2::IComposerClient::LayerRequest request) {
+ switch (request) {
+ case Hwc2::IComposerClient::LayerRequest::CLEAR_CLIENT_TARGET:
+ mState.clearClientTarget = true;
+ break;
+
+ default:
+ ALOGE("[%s] Unknown device layer request %s (%d)", mLayerFE->getDebugName(),
+ toString(request).c_str(), static_cast<int>(request));
+ break;
}
}
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayerCompositionState.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayerCompositionState.cpp
index 861ea57..e320bee 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputLayerCompositionState.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputLayerCompositionState.cpp
@@ -47,6 +47,7 @@
dumpVal(out, "displayFrame", displayFrame);
dumpVal(out, "sourceCrop", sourceCrop);
dumpVal(out, "bufferTransform", toString(bufferTransform), bufferTransform);
+ dumpVal(out, "dataspace", toString(dataspace), dataspace);
dumpVal(out, "z-index", z);
if (hwc) {
diff --git a/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp b/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp
index 8a91316..1ce6b4c 100644
--- a/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp
@@ -23,6 +23,7 @@
#include <compositionengine/DisplaySurface.h>
#include <compositionengine/RenderSurfaceCreationArgs.h>
#include <compositionengine/impl/DumpHelpers.h>
+#include <compositionengine/impl/OutputCompositionState.h>
#include <compositionengine/impl/RenderSurface.h>
#include <log/log.h>
#include <renderengine/RenderEngine.h>
@@ -110,24 +111,13 @@
return mDisplaySurface->beginFrame(mustRecompose);
}
-status_t RenderSurface::prepareFrame() {
- auto& hwc = mCompositionEngine.getHwComposer();
- const auto id = mDisplay.getId();
- if (id) {
- status_t error = hwc.prepare(*id, mDisplay);
- if (error != NO_ERROR) {
- return error;
- }
- }
-
+void RenderSurface::prepareFrame(bool usesClientComposition, bool usesDeviceComposition) {
DisplaySurface::CompositionType compositionType;
- const bool hasClient = hwc.hasClientComposition(id);
- const bool hasDevice = hwc.hasDeviceComposition(id);
- if (hasClient && hasDevice) {
+ if (usesClientComposition && usesDeviceComposition) {
compositionType = DisplaySurface::COMPOSITION_MIXED;
- } else if (hasClient) {
+ } else if (usesClientComposition) {
compositionType = DisplaySurface::COMPOSITION_GLES;
- } else if (hasDevice) {
+ } else if (usesDeviceComposition) {
compositionType = DisplaySurface::COMPOSITION_HWC;
} else {
// Nothing to do -- when turning the screen off we get a frame like
@@ -135,7 +125,11 @@
// will do a prepare/set cycle.
compositionType = DisplaySurface::COMPOSITION_HWC;
}
- return mDisplaySurface->prepareFrame(compositionType);
+
+ if (status_t result = mDisplaySurface->prepareFrame(compositionType); result != NO_ERROR) {
+ ALOGE("updateCompositionType failed for %s: %d (%s)", mDisplay.getName().c_str(), result,
+ strerror(-result));
+ }
}
sp<GraphicBuffer> RenderSurface::dequeueBuffer(base::unique_fd* bufferFence) {
@@ -163,10 +157,9 @@
}
void RenderSurface::queueBuffer(base::unique_fd&& readyFence) {
- auto& hwc = mCompositionEngine.getHwComposer();
- const auto id = mDisplay.getId();
+ auto& state = mDisplay.getState();
- if (hwc.hasClientComposition(id) || hwc.hasFlipClientTargetRequest(id)) {
+ if (state.usesClientComposition || state.flipClientTarget) {
// hasFlipClientTargetRequest could return true even if we haven't
// dequeued a buffer before. Try dequeueing one if we don't have a
// buffer ready.
diff --git a/services/surfaceflinger/CompositionEngine/tests/CompositionEngineTest.cpp b/services/surfaceflinger/CompositionEngine/tests/CompositionEngineTest.cpp
index 3766f27..0dbf8f0 100644
--- a/services/surfaceflinger/CompositionEngine/tests/CompositionEngineTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/CompositionEngineTest.cpp
@@ -14,7 +14,11 @@
* limitations under the License.
*/
+#include <compositionengine/CompositionRefreshArgs.h>
#include <compositionengine/impl/CompositionEngine.h>
+#include <compositionengine/mock/Layer.h>
+#include <compositionengine/mock/LayerFE.h>
+#include <compositionengine/mock/Output.h>
#include <gtest/gtest.h>
#include <renderengine/mock/RenderEngine.h>
@@ -23,19 +27,19 @@
namespace android::compositionengine {
namespace {
+using ::testing::_;
+using ::testing::Return;
+using ::testing::SaveArg;
using ::testing::StrictMock;
class CompositionEngineTest : public testing::Test {
public:
- ~CompositionEngineTest() override;
- mock::HWComposer* mHwc = new StrictMock<mock::HWComposer>();
+ android::mock::HWComposer* mHwc = new StrictMock<android::mock::HWComposer>();
renderengine::mock::RenderEngine* mRenderEngine =
new StrictMock<renderengine::mock::RenderEngine>();
impl::CompositionEngine mEngine;
};
-CompositionEngineTest::~CompositionEngineTest() = default;
-
TEST_F(CompositionEngineTest, canInstantiateCompositionEngine) {
auto engine = impl::createCompositionEngine();
EXPECT_TRUE(engine.get() != nullptr);
@@ -53,5 +57,84 @@
EXPECT_EQ(mRenderEngine, &mEngine.getRenderEngine());
}
+/*
+ * CompositionEngine::preComposition
+ */
+
+class PreCompositionTest : public CompositionEngineTest {
+public:
+ PreCompositionTest() {
+ EXPECT_CALL(*mLayer1, getLayerFE()).WillRepeatedly(Return(mLayer1FE));
+ EXPECT_CALL(*mLayer2, getLayerFE()).WillRepeatedly(Return(mLayer2FE));
+ EXPECT_CALL(*mLayer3, getLayerFE()).WillRepeatedly(Return(mLayer3FE));
+ // getLayerFE() can return nullptr. Ensure that this is handled.
+ EXPECT_CALL(*mLayer4, getLayerFE()).WillRepeatedly(Return(nullptr));
+
+ mRefreshArgs.outputs = {mOutput};
+ mRefreshArgs.layers = {mLayer1, mLayer2, mLayer3, mLayer4};
+ }
+
+ std::shared_ptr<mock::Output> mOutput{std::make_shared<StrictMock<mock::Output>>()};
+ std::shared_ptr<mock::Layer> mLayer1{std::make_shared<StrictMock<mock::Layer>>()};
+ std::shared_ptr<mock::Layer> mLayer2{std::make_shared<StrictMock<mock::Layer>>()};
+ std::shared_ptr<mock::Layer> mLayer3{std::make_shared<StrictMock<mock::Layer>>()};
+ std::shared_ptr<mock::Layer> mLayer4{std::make_shared<StrictMock<mock::Layer>>()};
+ sp<StrictMock<mock::LayerFE>> mLayer1FE{new StrictMock<mock::LayerFE>()};
+ sp<StrictMock<mock::LayerFE>> mLayer2FE{new StrictMock<mock::LayerFE>()};
+ sp<StrictMock<mock::LayerFE>> mLayer3FE{new StrictMock<mock::LayerFE>()};
+
+ CompositionRefreshArgs mRefreshArgs;
+};
+
+TEST_F(PreCompositionTest, preCompositionSetsFrameTimestamp) {
+ const nsecs_t before = systemTime(SYSTEM_TIME_MONOTONIC);
+ CompositionRefreshArgs emptyArgs;
+ mEngine.preComposition(emptyArgs);
+ const nsecs_t after = systemTime(SYSTEM_TIME_MONOTONIC);
+
+ // The frame timestamp should be between the before and after timestamps
+ EXPECT_GE(mEngine.getLastFrameRefreshTimestamp(), before);
+ EXPECT_LE(mEngine.getLastFrameRefreshTimestamp(), after);
+}
+
+TEST_F(PreCompositionTest, preCompositionInvokesLayerPreCompositionWithFrameTimestamp) {
+ nsecs_t ts1 = 0;
+ nsecs_t ts2 = 0;
+ nsecs_t ts3 = 0;
+ EXPECT_CALL(*mLayer1FE, onPreComposition(_)).WillOnce(DoAll(SaveArg<0>(&ts1), Return(false)));
+ EXPECT_CALL(*mLayer2FE, onPreComposition(_)).WillOnce(DoAll(SaveArg<0>(&ts2), Return(false)));
+ EXPECT_CALL(*mLayer3FE, onPreComposition(_)).WillOnce(DoAll(SaveArg<0>(&ts3), Return(false)));
+
+ mEngine.preComposition(mRefreshArgs);
+
+ // Each of the onPreComposition calls should used the same refresh timestamp
+ EXPECT_EQ(ts1, mEngine.getLastFrameRefreshTimestamp());
+ EXPECT_EQ(ts2, mEngine.getLastFrameRefreshTimestamp());
+ EXPECT_EQ(ts3, mEngine.getLastFrameRefreshTimestamp());
+}
+
+TEST_F(PreCompositionTest, preCompositionDefaultsToNoUpdateNeeded) {
+ EXPECT_CALL(*mLayer1FE, onPreComposition(_)).WillOnce(Return(false));
+ EXPECT_CALL(*mLayer2FE, onPreComposition(_)).WillOnce(Return(false));
+ EXPECT_CALL(*mLayer3FE, onPreComposition(_)).WillOnce(Return(false));
+
+ mEngine.setNeedsAnotherUpdateForTest(true);
+
+ mEngine.preComposition(mRefreshArgs);
+
+ // The call should have cleared the needsAnotherUpdate flag
+ EXPECT_FALSE(mEngine.needsAnotherUpdate());
+}
+
+TEST_F(PreCompositionTest, preCompositionSetsNeedsAnotherUpdateIfAtLeastOneLayerRequestsIt) {
+ EXPECT_CALL(*mLayer1FE, onPreComposition(_)).WillOnce(Return(true));
+ EXPECT_CALL(*mLayer2FE, onPreComposition(_)).WillOnce(Return(false));
+ EXPECT_CALL(*mLayer3FE, onPreComposition(_)).WillOnce(Return(false));
+
+ mEngine.preComposition(mRefreshArgs);
+
+ EXPECT_TRUE(mEngine.needsAnotherUpdate());
+}
+
} // namespace
} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/tests/DisplayColorProfileTest.cpp b/services/surfaceflinger/CompositionEngine/tests/DisplayColorProfileTest.cpp
index 9215884..c07dfbb 100644
--- a/services/surfaceflinger/CompositionEngine/tests/DisplayColorProfileTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/DisplayColorProfileTest.cpp
@@ -638,5 +638,66 @@
checkGetBestColorMode(profile, expectedResults);
}
+/*
+ * RenderSurface::isDataspaceSupported()
+ */
+
+TEST_F(DisplayColorProfileTest, isDataspaceSupportedWorksForProfileWithNoHdrSupport) {
+ auto profile = ProfileFactory::createProfileWithNoColorModeSupport();
+
+ EXPECT_TRUE(profile.isDataspaceSupported(Dataspace::UNKNOWN));
+ EXPECT_TRUE(profile.isDataspaceSupported(Dataspace::V0_SRGB));
+ EXPECT_FALSE(profile.isDataspaceSupported(Dataspace::BT2020_PQ));
+ EXPECT_FALSE(profile.isDataspaceSupported(Dataspace::BT2020_ITU_PQ));
+ EXPECT_FALSE(profile.isDataspaceSupported(Dataspace::BT2020_HLG));
+ EXPECT_FALSE(profile.isDataspaceSupported(Dataspace::BT2020_ITU_HLG));
+}
+
+TEST_F(DisplayColorProfileTest, isDataspaceSupportedWorksForProfileWithHdr10Support) {
+ auto profile = ProfileFactory::createProfileWithSRGBColorModeSupport();
+
+ EXPECT_TRUE(profile.isDataspaceSupported(Dataspace::UNKNOWN));
+ EXPECT_TRUE(profile.isDataspaceSupported(Dataspace::V0_SRGB));
+ EXPECT_TRUE(profile.isDataspaceSupported(Dataspace::BT2020_PQ));
+ EXPECT_TRUE(profile.isDataspaceSupported(Dataspace::BT2020_ITU_PQ));
+ EXPECT_FALSE(profile.isDataspaceSupported(Dataspace::BT2020_HLG));
+ EXPECT_FALSE(profile.isDataspaceSupported(Dataspace::BT2020_ITU_HLG));
+}
+
+TEST_F(DisplayColorProfileTest, isDataspaceSupportedWorksForProfileWithHlgSupport) {
+ auto profile = ProfileFactory::createProfileWithBT2100PQSupport();
+
+ EXPECT_TRUE(profile.isDataspaceSupported(Dataspace::UNKNOWN));
+ EXPECT_TRUE(profile.isDataspaceSupported(Dataspace::V0_SRGB));
+ EXPECT_FALSE(profile.isDataspaceSupported(Dataspace::BT2020_PQ));
+ EXPECT_FALSE(profile.isDataspaceSupported(Dataspace::BT2020_ITU_PQ));
+ EXPECT_TRUE(profile.isDataspaceSupported(Dataspace::BT2020_HLG));
+ EXPECT_TRUE(profile.isDataspaceSupported(Dataspace::BT2020_ITU_HLG));
+}
+
+/*
+ * RenderSurface::getTargetDataspace()
+ */
+
+TEST_F(DisplayColorProfileTest, getTargetDataspaceWorks) {
+ auto profile = ProfileFactory::createProfileWithNoColorModeSupport();
+
+ // For a non-HDR colorspace with no colorSpaceAgnosticDataspace override,
+ // the input dataspace should be returned.
+ EXPECT_EQ(Dataspace::DISPLAY_P3,
+ profile.getTargetDataspace(ColorMode::DISPLAY_P3, Dataspace::DISPLAY_P3,
+ Dataspace::UNKNOWN));
+
+ // If colorSpaceAgnosticDataspace is set, its value should be returned
+ EXPECT_EQ(Dataspace::V0_SRGB,
+ profile.getTargetDataspace(ColorMode::DISPLAY_P3, Dataspace::DISPLAY_P3,
+ Dataspace::V0_SRGB));
+
+ // For an HDR colorspace, Dataspace::UNKNOWN should be returned.
+ EXPECT_EQ(Dataspace::UNKNOWN,
+ profile.getTargetDataspace(ColorMode::BT2100_PQ, Dataspace::BT2020_PQ,
+ Dataspace::UNKNOWN));
+}
+
} // namespace
} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
index 33444a5..e3be0d7 100644
--- a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
@@ -22,33 +22,56 @@
#include <compositionengine/RenderSurfaceCreationArgs.h>
#include <compositionengine/impl/Display.h>
#include <compositionengine/mock/CompositionEngine.h>
+#include <compositionengine/mock/DisplayColorProfile.h>
#include <compositionengine/mock/NativeWindow.h>
+#include <compositionengine/mock/OutputLayer.h>
#include <compositionengine/mock/RenderSurface.h>
#include <gtest/gtest.h>
+#include "MockHWC2.h"
#include "MockHWComposer.h"
namespace android::compositionengine {
namespace {
+using testing::_;
+using testing::DoAll;
using testing::Return;
using testing::ReturnRef;
+using testing::Sequence;
+using testing::SetArgPointee;
using testing::StrictMock;
constexpr DisplayId DEFAULT_DISPLAY_ID = DisplayId{42};
-class DisplayTest : public testing::Test {
-public:
- ~DisplayTest() override = default;
+struct DisplayTest : public testing::Test {
+ DisplayTest() {
+ EXPECT_CALL(mCompositionEngine, getHwComposer()).WillRepeatedly(ReturnRef(mHwComposer));
+ EXPECT_CALL(*mLayer1, getHwcLayer()).WillRepeatedly(Return(&mHWC2Layer1));
+ EXPECT_CALL(*mLayer2, getHwcLayer()).WillRepeatedly(Return(&mHWC2Layer2));
+ EXPECT_CALL(*mLayer3, getHwcLayer()).WillRepeatedly(Return(nullptr));
+
+ std::vector<std::unique_ptr<OutputLayer>> layers;
+ layers.emplace_back(mLayer1);
+ layers.emplace_back(mLayer2);
+ layers.emplace_back(mLayer3);
+ mDisplay.setOutputLayersOrderedByZ(std::move(layers));
+ }
StrictMock<android::mock::HWComposer> mHwComposer;
StrictMock<mock::CompositionEngine> mCompositionEngine;
sp<mock::NativeWindow> mNativeWindow = new StrictMock<mock::NativeWindow>();
+ StrictMock<HWC2::mock::Layer> mHWC2Layer1;
+ StrictMock<HWC2::mock::Layer> mHWC2Layer2;
+ StrictMock<HWC2::mock::Layer> mHWC2LayerUnknown;
+ mock::OutputLayer* mLayer1 = new StrictMock<mock::OutputLayer>();
+ mock::OutputLayer* mLayer2 = new StrictMock<mock::OutputLayer>();
+ mock::OutputLayer* mLayer3 = new StrictMock<mock::OutputLayer>();
impl::Display mDisplay{mCompositionEngine,
DisplayCreationArgsBuilder().setDisplayId(DEFAULT_DISPLAY_ID).build()};
};
-/* ------------------------------------------------------------------------
+/*
* Basic construction
*/
@@ -88,13 +111,11 @@
}
}
-/* ------------------------------------------------------------------------
+/*
* Display::disconnect()
*/
TEST_F(DisplayTest, disconnectDisconnectsDisplay) {
- EXPECT_CALL(mCompositionEngine, getHwComposer()).WillRepeatedly(ReturnRef(mHwComposer));
-
// The first call to disconnect will disconnect the display with the HWC and
// set mHwcId to -1.
EXPECT_CALL(mHwComposer, disconnectDisplay(DEFAULT_DISPLAY_ID)).Times(1);
@@ -107,7 +128,7 @@
EXPECT_FALSE(mDisplay.getId());
}
-/* ------------------------------------------------------------------------
+/*
* Display::setColorTransform()
*/
@@ -115,8 +136,6 @@
// Identity matrix sets an identity state value
const mat4 identity;
- EXPECT_CALL(mCompositionEngine, getHwComposer()).WillRepeatedly(ReturnRef(mHwComposer));
-
EXPECT_CALL(mHwComposer, setColorTransform(DEFAULT_DISPLAY_ID, identity)).Times(1);
mDisplay.setColorTransform(identity);
@@ -133,28 +152,33 @@
EXPECT_EQ(HAL_COLOR_TRANSFORM_ARBITRARY_MATRIX, mDisplay.getState().colorTransform);
}
-/* ------------------------------------------------------------------------
+/*
* Display::setColorMode()
*/
TEST_F(DisplayTest, setColorModeSetsModeUnlessNoChange) {
mock::RenderSurface* renderSurface = new StrictMock<mock::RenderSurface>();
mDisplay.setRenderSurfaceForTest(std::unique_ptr<RenderSurface>(renderSurface));
+ mock::DisplayColorProfile* colorProfile = new StrictMock<mock::DisplayColorProfile>();
+ mDisplay.setDisplayColorProfileForTest(std::unique_ptr<DisplayColorProfile>(colorProfile));
- EXPECT_CALL(mCompositionEngine, getHwComposer()).WillRepeatedly(ReturnRef(mHwComposer));
+ EXPECT_CALL(*colorProfile, getTargetDataspace(_, _, _))
+ .WillRepeatedly(Return(ui::Dataspace::UNKNOWN));
// These values are expected to be the initial state.
ASSERT_EQ(ui::ColorMode::NATIVE, mDisplay.getState().colorMode);
ASSERT_EQ(ui::Dataspace::UNKNOWN, mDisplay.getState().dataspace);
ASSERT_EQ(ui::RenderIntent::COLORIMETRIC, mDisplay.getState().renderIntent);
+ ASSERT_EQ(ui::Dataspace::UNKNOWN, mDisplay.getState().targetDataspace);
- // Otherwise if the values are unchanged, nothing happens
+ // If the set values are unchanged, nothing happens
mDisplay.setColorMode(ui::ColorMode::NATIVE, ui::Dataspace::UNKNOWN,
- ui::RenderIntent::COLORIMETRIC);
+ ui::RenderIntent::COLORIMETRIC, ui::Dataspace::UNKNOWN);
EXPECT_EQ(ui::ColorMode::NATIVE, mDisplay.getState().colorMode);
EXPECT_EQ(ui::Dataspace::UNKNOWN, mDisplay.getState().dataspace);
EXPECT_EQ(ui::RenderIntent::COLORIMETRIC, mDisplay.getState().renderIntent);
+ EXPECT_EQ(ui::Dataspace::UNKNOWN, mDisplay.getState().targetDataspace);
// Otherwise if the values are different, updates happen
EXPECT_CALL(*renderSurface, setBufferDataspace(ui::Dataspace::DISPLAY_P3)).Times(1);
@@ -164,26 +188,37 @@
.Times(1);
mDisplay.setColorMode(ui::ColorMode::DISPLAY_P3, ui::Dataspace::DISPLAY_P3,
- ui::RenderIntent::TONE_MAP_COLORIMETRIC);
+ ui::RenderIntent::TONE_MAP_COLORIMETRIC, ui::Dataspace::UNKNOWN);
EXPECT_EQ(ui::ColorMode::DISPLAY_P3, mDisplay.getState().colorMode);
EXPECT_EQ(ui::Dataspace::DISPLAY_P3, mDisplay.getState().dataspace);
EXPECT_EQ(ui::RenderIntent::TONE_MAP_COLORIMETRIC, mDisplay.getState().renderIntent);
+ EXPECT_EQ(ui::Dataspace::UNKNOWN, mDisplay.getState().targetDataspace);
}
TEST_F(DisplayTest, setColorModeDoesNothingForVirtualDisplay) {
impl::Display virtualDisplay{mCompositionEngine,
DisplayCreationArgs{false, true, DEFAULT_DISPLAY_ID}};
+ mock::DisplayColorProfile* colorProfile = new StrictMock<mock::DisplayColorProfile>();
+ virtualDisplay.setDisplayColorProfileForTest(
+ std::unique_ptr<DisplayColorProfile>(colorProfile));
+
+ EXPECT_CALL(*colorProfile,
+ getTargetDataspace(ui::ColorMode::DISPLAY_P3, ui::Dataspace::DISPLAY_P3,
+ ui::Dataspace::UNKNOWN))
+ .WillOnce(Return(ui::Dataspace::UNKNOWN));
+
virtualDisplay.setColorMode(ui::ColorMode::DISPLAY_P3, ui::Dataspace::DISPLAY_P3,
- ui::RenderIntent::TONE_MAP_COLORIMETRIC);
+ ui::RenderIntent::TONE_MAP_COLORIMETRIC, ui::Dataspace::UNKNOWN);
EXPECT_EQ(ui::ColorMode::NATIVE, virtualDisplay.getState().colorMode);
EXPECT_EQ(ui::Dataspace::UNKNOWN, virtualDisplay.getState().dataspace);
EXPECT_EQ(ui::RenderIntent::COLORIMETRIC, virtualDisplay.getState().renderIntent);
+ EXPECT_EQ(ui::Dataspace::UNKNOWN, mDisplay.getState().targetDataspace);
}
-/* ------------------------------------------------------------------------
+/*
* Display::createDisplayColorProfile()
*/
@@ -195,7 +230,7 @@
EXPECT_TRUE(mDisplay.getDisplayColorProfile() != nullptr);
}
-/* ------------------------------------------------------------------------
+/*
* Display::createRenderSurface()
*/
@@ -206,5 +241,266 @@
EXPECT_TRUE(mDisplay.getRenderSurface() != nullptr);
}
+/*
+ * Display::chooseCompositionStrategy()
+ */
+
+struct DisplayChooseCompositionStrategyTest : public testing::Test {
+ struct DisplayPartialMock : public impl::Display {
+ DisplayPartialMock(const compositionengine::CompositionEngine& compositionEngine,
+ compositionengine::DisplayCreationArgs&& args)
+ : impl::Display(compositionEngine, std::move(args)) {}
+
+ // Sets up the helper functions called by chooseCompositionStrategy to
+ // use a mock implementations.
+ MOCK_CONST_METHOD0(anyLayersRequireClientComposition, bool());
+ MOCK_CONST_METHOD0(allLayersRequireClientComposition, bool());
+ MOCK_METHOD1(applyChangedTypesToLayers, void(const impl::Display::ChangedTypes&));
+ MOCK_METHOD1(applyDisplayRequests, void(const impl::Display::DisplayRequests&));
+ MOCK_METHOD1(applyLayerRequestsToLayers, void(const impl::Display::LayerRequests&));
+ };
+
+ DisplayChooseCompositionStrategyTest() {
+ EXPECT_CALL(mCompositionEngine, getHwComposer()).WillRepeatedly(ReturnRef(mHwComposer));
+ }
+
+ StrictMock<android::mock::HWComposer> mHwComposer;
+ StrictMock<mock::CompositionEngine> mCompositionEngine;
+ StrictMock<DisplayPartialMock>
+ mDisplay{mCompositionEngine,
+ DisplayCreationArgsBuilder().setDisplayId(DEFAULT_DISPLAY_ID).build()};
+};
+
+TEST_F(DisplayChooseCompositionStrategyTest, takesEarlyOutIfNotAHwcDisplay) {
+ impl::Display nonHwcDisplay{mCompositionEngine, DisplayCreationArgsBuilder().build()};
+ EXPECT_FALSE(nonHwcDisplay.getId());
+
+ nonHwcDisplay.chooseCompositionStrategy();
+
+ auto& state = nonHwcDisplay.getState();
+ EXPECT_TRUE(state.usesClientComposition);
+ EXPECT_FALSE(state.usesDeviceComposition);
+}
+
+TEST_F(DisplayChooseCompositionStrategyTest, takesEarlyOutOnHwcError) {
+ EXPECT_CALL(mDisplay, anyLayersRequireClientComposition()).WillOnce(Return(false));
+ EXPECT_CALL(mHwComposer, getDeviceCompositionChanges(DEFAULT_DISPLAY_ID, false, _))
+ .WillOnce(Return(INVALID_OPERATION));
+
+ mDisplay.chooseCompositionStrategy();
+
+ auto& state = mDisplay.getState();
+ EXPECT_TRUE(state.usesClientComposition);
+ EXPECT_FALSE(state.usesDeviceComposition);
+}
+
+TEST_F(DisplayChooseCompositionStrategyTest, normalOperation) {
+ // Since two calls are made to anyLayersRequireClientComposition with different return values,
+ // use a Sequence to control the matching so the values are returned in a known order.
+ Sequence s;
+ EXPECT_CALL(mDisplay, anyLayersRequireClientComposition()).InSequence(s).WillOnce(Return(true));
+ EXPECT_CALL(mDisplay, anyLayersRequireClientComposition())
+ .InSequence(s)
+ .WillOnce(Return(false));
+
+ EXPECT_CALL(mHwComposer, getDeviceCompositionChanges(DEFAULT_DISPLAY_ID, true, _))
+ .WillOnce(Return(NO_ERROR));
+ EXPECT_CALL(mDisplay, allLayersRequireClientComposition()).WillOnce(Return(false));
+
+ mDisplay.chooseCompositionStrategy();
+
+ auto& state = mDisplay.getState();
+ EXPECT_FALSE(state.usesClientComposition);
+ EXPECT_TRUE(state.usesDeviceComposition);
+}
+
+TEST_F(DisplayChooseCompositionStrategyTest, normalOperationWithChanges) {
+ android::HWComposer::DeviceRequestedChanges changes{
+ {{nullptr, HWC2::Composition::Client}},
+ HWC2::DisplayRequest::FlipClientTarget,
+ {{nullptr, HWC2::LayerRequest::ClearClientTarget}},
+ };
+
+ // Since two calls are made to anyLayersRequireClientComposition with different return values,
+ // use a Sequence to control the matching so the values are returned in a known order.
+ Sequence s;
+ EXPECT_CALL(mDisplay, anyLayersRequireClientComposition()).InSequence(s).WillOnce(Return(true));
+ EXPECT_CALL(mDisplay, anyLayersRequireClientComposition())
+ .InSequence(s)
+ .WillOnce(Return(false));
+
+ EXPECT_CALL(mHwComposer, getDeviceCompositionChanges(DEFAULT_DISPLAY_ID, true, _))
+ .WillOnce(DoAll(SetArgPointee<2>(changes), Return(NO_ERROR)));
+ EXPECT_CALL(mDisplay, applyChangedTypesToLayers(changes.changedTypes)).Times(1);
+ EXPECT_CALL(mDisplay, applyDisplayRequests(changes.displayRequests)).Times(1);
+ EXPECT_CALL(mDisplay, applyLayerRequestsToLayers(changes.layerRequests)).Times(1);
+ EXPECT_CALL(mDisplay, allLayersRequireClientComposition()).WillOnce(Return(false));
+
+ mDisplay.chooseCompositionStrategy();
+
+ auto& state = mDisplay.getState();
+ EXPECT_FALSE(state.usesClientComposition);
+ EXPECT_TRUE(state.usesDeviceComposition);
+}
+
+/*
+ * Display::anyLayersRequireClientComposition()
+ */
+
+TEST_F(DisplayTest, anyLayersRequireClientCompositionReturnsFalse) {
+ EXPECT_CALL(*mLayer1, requiresClientComposition()).WillOnce(Return(false));
+ EXPECT_CALL(*mLayer2, requiresClientComposition()).WillOnce(Return(false));
+ EXPECT_CALL(*mLayer3, requiresClientComposition()).WillOnce(Return(false));
+
+ EXPECT_FALSE(mDisplay.anyLayersRequireClientComposition());
+}
+
+TEST_F(DisplayTest, anyLayersRequireClientCompositionReturnsTrue) {
+ EXPECT_CALL(*mLayer1, requiresClientComposition()).WillOnce(Return(false));
+ EXPECT_CALL(*mLayer2, requiresClientComposition()).WillOnce(Return(true));
+
+ EXPECT_TRUE(mDisplay.anyLayersRequireClientComposition());
+}
+
+/*
+ * Display::allLayersRequireClientComposition()
+ */
+
+TEST_F(DisplayTest, allLayersRequireClientCompositionReturnsTrue) {
+ EXPECT_CALL(*mLayer1, requiresClientComposition()).WillOnce(Return(true));
+ EXPECT_CALL(*mLayer2, requiresClientComposition()).WillOnce(Return(true));
+ EXPECT_CALL(*mLayer3, requiresClientComposition()).WillOnce(Return(true));
+
+ EXPECT_TRUE(mDisplay.allLayersRequireClientComposition());
+}
+
+TEST_F(DisplayTest, allLayersRequireClientCompositionReturnsFalse) {
+ EXPECT_CALL(*mLayer1, requiresClientComposition()).WillOnce(Return(true));
+ EXPECT_CALL(*mLayer2, requiresClientComposition()).WillOnce(Return(false));
+
+ EXPECT_FALSE(mDisplay.allLayersRequireClientComposition());
+}
+
+/*
+ * Display::applyChangedTypesToLayers()
+ */
+
+TEST_F(DisplayTest, applyChangedTypesToLayersTakesEarlyOutIfNoChangedLayers) {
+ mDisplay.applyChangedTypesToLayers(impl::Display::ChangedTypes());
+}
+
+TEST_F(DisplayTest, applyChangedTypesToLayersAppliesChanges) {
+ EXPECT_CALL(*mLayer1,
+ applyDeviceCompositionTypeChange(Hwc2::IComposerClient::Composition::CLIENT))
+ .Times(1);
+ EXPECT_CALL(*mLayer2,
+ applyDeviceCompositionTypeChange(Hwc2::IComposerClient::Composition::DEVICE))
+ .Times(1);
+
+ mDisplay.applyChangedTypesToLayers(impl::Display::ChangedTypes{
+ {&mHWC2Layer1, HWC2::Composition::Client},
+ {&mHWC2Layer2, HWC2::Composition::Device},
+ {&mHWC2LayerUnknown, HWC2::Composition::SolidColor},
+ });
+}
+
+/*
+ * Display::applyDisplayRequests()
+ */
+
+TEST_F(DisplayTest, applyDisplayRequestsToLayersHandlesNoRequests) {
+ mDisplay.applyDisplayRequests(static_cast<HWC2::DisplayRequest>(0));
+
+ auto& state = mDisplay.getState();
+ EXPECT_FALSE(state.flipClientTarget);
+}
+
+TEST_F(DisplayTest, applyDisplayRequestsToLayersHandlesFlipClientTarget) {
+ mDisplay.applyDisplayRequests(HWC2::DisplayRequest::FlipClientTarget);
+
+ auto& state = mDisplay.getState();
+ EXPECT_TRUE(state.flipClientTarget);
+}
+
+TEST_F(DisplayTest, applyDisplayRequestsToLayersHandlesWriteClientTargetToOutput) {
+ mDisplay.applyDisplayRequests(HWC2::DisplayRequest::WriteClientTargetToOutput);
+
+ auto& state = mDisplay.getState();
+ EXPECT_FALSE(state.flipClientTarget);
+}
+
+TEST_F(DisplayTest, applyDisplayRequestsToLayersHandlesAllRequestFlagsSet) {
+ mDisplay.applyDisplayRequests(static_cast<HWC2::DisplayRequest>(~0));
+
+ auto& state = mDisplay.getState();
+ EXPECT_TRUE(state.flipClientTarget);
+}
+
+/*
+ * Display::applyLayerRequestsToLayers()
+ */
+
+TEST_F(DisplayTest, applyLayerRequestsToLayersPreparesAllLayers) {
+ EXPECT_CALL(*mLayer1, prepareForDeviceLayerRequests()).Times(1);
+ EXPECT_CALL(*mLayer2, prepareForDeviceLayerRequests()).Times(1);
+ EXPECT_CALL(*mLayer3, prepareForDeviceLayerRequests()).Times(1);
+
+ mDisplay.applyLayerRequestsToLayers(impl::Display::LayerRequests());
+}
+
+TEST_F(DisplayTest, applyLayerRequestsToLayers2) {
+ EXPECT_CALL(*mLayer1, prepareForDeviceLayerRequests()).Times(1);
+ EXPECT_CALL(*mLayer2, prepareForDeviceLayerRequests()).Times(1);
+ EXPECT_CALL(*mLayer3, prepareForDeviceLayerRequests()).Times(1);
+
+ EXPECT_CALL(*mLayer1,
+ applyDeviceLayerRequest(Hwc2::IComposerClient::LayerRequest::CLEAR_CLIENT_TARGET))
+ .Times(1);
+
+ mDisplay.applyLayerRequestsToLayers(impl::Display::LayerRequests{
+ {&mHWC2Layer1, HWC2::LayerRequest::ClearClientTarget},
+ {&mHWC2LayerUnknown, HWC2::LayerRequest::ClearClientTarget},
+ });
+}
+
+/*
+ * Display::presentAndGetFrameFences()
+ */
+
+TEST_F(DisplayTest, presentAndGetFrameFencesReturnsNoFencesOnNonHwcDisplay) {
+ auto nonHwcDisplay{
+ impl::createDisplay(mCompositionEngine, DisplayCreationArgsBuilder().build())};
+
+ auto result = nonHwcDisplay->presentAndGetFrameFences();
+
+ ASSERT_TRUE(result.presentFence.get());
+ EXPECT_FALSE(result.presentFence->isValid());
+ EXPECT_EQ(0u, result.layerFences.size());
+}
+
+TEST_F(DisplayTest, presentAndGetFrameFencesReturnsPresentAndLayerFences) {
+ sp<Fence> presentFence = new Fence();
+ sp<Fence> layer1Fence = new Fence();
+ sp<Fence> layer2Fence = new Fence();
+
+ EXPECT_CALL(mHwComposer, presentAndGetReleaseFences(DEFAULT_DISPLAY_ID)).Times(1);
+ EXPECT_CALL(mHwComposer, getPresentFence(DEFAULT_DISPLAY_ID)).WillOnce(Return(presentFence));
+ EXPECT_CALL(mHwComposer, getLayerReleaseFence(DEFAULT_DISPLAY_ID, &mHWC2Layer1))
+ .WillOnce(Return(layer1Fence));
+ EXPECT_CALL(mHwComposer, getLayerReleaseFence(DEFAULT_DISPLAY_ID, &mHWC2Layer2))
+ .WillOnce(Return(layer2Fence));
+ EXPECT_CALL(mHwComposer, clearReleaseFences(DEFAULT_DISPLAY_ID)).Times(1);
+
+ auto result = mDisplay.presentAndGetFrameFences();
+
+ EXPECT_EQ(presentFence, result.presentFence);
+
+ EXPECT_EQ(2u, result.layerFences.size());
+ ASSERT_EQ(1, result.layerFences.count(&mHWC2Layer1));
+ EXPECT_EQ(layer1Fence, result.layerFences[&mHWC2Layer1]);
+ ASSERT_EQ(1, result.layerFences.count(&mHWC2Layer2));
+ EXPECT_EQ(layer2Fence, result.layerFences[&mHWC2Layer2]);
+}
+
} // namespace
} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
index 94349de..5cfec77 100644
--- a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
+++ b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
@@ -40,7 +40,9 @@
std::optional<DisplayId>(uint32_t, uint32_t, ui::PixelFormat*));
MOCK_METHOD1(createLayer, HWC2::Layer*(DisplayId));
MOCK_METHOD2(destroyLayer, void(DisplayId, HWC2::Layer*));
- MOCK_METHOD2(prepare, status_t(DisplayId, const compositionengine::Output&));
+ MOCK_METHOD3(getDeviceCompositionChanges,
+ status_t(DisplayId, bool,
+ std::optional<android::HWComposer::DeviceRequestedChanges>*));
MOCK_METHOD5(setClientTarget,
status_t(DisplayId, uint32_t, const sp<Fence>&, const sp<GraphicBuffer>&,
ui::Dataspace));
@@ -50,8 +52,6 @@
MOCK_METHOD2(setColorTransform, status_t(DisplayId, const mat4&));
MOCK_METHOD1(disconnectDisplay, void(DisplayId));
MOCK_CONST_METHOD1(hasDeviceComposition, bool(const std::optional<DisplayId>&));
- MOCK_CONST_METHOD1(hasFlipClientTargetRequest, bool(const std::optional<DisplayId>&));
- MOCK_CONST_METHOD1(hasClientComposition, bool(const std::optional<DisplayId>&));
MOCK_CONST_METHOD1(getPresentFence, sp<Fence>(DisplayId));
MOCK_CONST_METHOD2(getLayerReleaseFence, sp<Fence>(DisplayId, HWC2::Layer*));
MOCK_METHOD3(setOutputBuffer, status_t(DisplayId, const sp<Fence>&, const sp<GraphicBuffer>&));
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
index ae906cd..a5428ad 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
@@ -16,6 +16,7 @@
#include <compositionengine/impl/OutputLayer.h>
#include <compositionengine/mock/CompositionEngine.h>
+#include <compositionengine/mock/DisplayColorProfile.h>
#include <compositionengine/mock/Layer.h>
#include <compositionengine/mock/LayerFE.h>
#include <compositionengine/mock/Output.h>
@@ -25,6 +26,7 @@
#include "MockHWC2.h"
#include "MockHWComposer.h"
#include "RectMatcher.h"
+#include "RegionMatcher.h"
namespace android::compositionengine {
namespace {
@@ -45,8 +47,16 @@
const std::string kOutputName{"Test Output"};
-class OutputLayerTest : public testing::Test {
-public:
+MATCHER_P(ColorEq, expected, "") {
+ *result_listener << "Colors are not equal\n";
+ *result_listener << "expected " << expected.r << " " << expected.g << " " << expected.b << " "
+ << expected.a << "\n";
+ *result_listener << "actual " << arg.r << " " << arg.g << " " << arg.b << " " << arg.a << "\n";
+
+ return expected.r == arg.r && expected.g == arg.g && expected.b == arg.b && expected.a == arg.a;
+}
+
+struct OutputLayerTest : public testing::Test {
OutputLayerTest() {
EXPECT_CALL(*mLayerFE, getDebugName()).WillRepeatedly(Return("Test LayerFE"));
EXPECT_CALL(mOutput, getName()).WillRepeatedly(ReturnRef(kOutputName));
@@ -55,8 +65,6 @@
EXPECT_CALL(mOutput, getState()).WillRepeatedly(ReturnRef(mOutputState));
}
- ~OutputLayerTest() override = default;
-
compositionengine::mock::Output mOutput;
std::shared_ptr<compositionengine::mock::Layer> mLayer{
new StrictMock<compositionengine::mock::Layer>()};
@@ -429,6 +437,9 @@
OutputLayerUpdateCompositionStateTest() {
EXPECT_CALL(*mLayer, getState()).WillRepeatedly(ReturnRef(mLayerState));
EXPECT_CALL(mOutput, getState()).WillRepeatedly(ReturnRef(mOutputState));
+ EXPECT_CALL(mOutput, getDisplayColorProfile())
+ .WillRepeatedly(Return(&mDisplayColorProfile));
+ EXPECT_CALL(mDisplayColorProfile, isDataspaceSupported(_)).WillRepeatedly(Return(true));
}
~OutputLayerUpdateCompositionStateTest() = default;
@@ -453,6 +464,7 @@
using OutputLayer = OutputLayerPartialMockForUpdateCompositionState;
StrictMock<OutputLayer> mOutputLayer{mOutput, mLayer, mLayerFE};
+ StrictMock<mock::DisplayColorProfile> mDisplayColorProfile;
};
TEST_F(OutputLayerUpdateCompositionStateTest, setsStateNormally) {
@@ -498,12 +510,50 @@
EXPECT_EQ(true, mOutputLayer.getState().forceClientComposition);
}
+TEST_F(OutputLayerUpdateCompositionStateTest, setsOutputLayerColorspaceCorrectly) {
+ mLayerState.frontEnd.dataspace = ui::Dataspace::DISPLAY_P3;
+ mOutputState.targetDataspace = ui::Dataspace::V0_SCRGB;
+
+ // If the layer is not colorspace agnostic, the output layer dataspace
+ // should use the layers requested colorspace.
+ mLayerState.frontEnd.isColorspaceAgnostic = false;
+
+ mOutputLayer.updateCompositionState(false);
+
+ EXPECT_EQ(ui::Dataspace::DISPLAY_P3, mOutputLayer.getState().dataspace);
+
+ // If the layer is colorspace agnostic, the output layer dataspace
+ // should use the colorspace chosen for the whole output.
+ mLayerState.frontEnd.isColorspaceAgnostic = true;
+
+ mOutputLayer.updateCompositionState(false);
+
+ EXPECT_EQ(ui::Dataspace::V0_SCRGB, mOutputLayer.getState().dataspace);
+}
+
TEST_F(OutputLayerUpdateCompositionStateTest, doesNotRecomputeGeometryIfNotRequested) {
mOutputLayer.updateCompositionState(false);
EXPECT_EQ(false, mOutputLayer.getState().forceClientComposition);
}
+TEST_F(OutputLayerUpdateCompositionStateTest, clientCompositionForcedFromFrontEndFlagAtAnyTime) {
+ mLayerState.frontEnd.forceClientComposition = true;
+
+ mOutputLayer.updateCompositionState(false);
+
+ EXPECT_EQ(true, mOutputLayer.getState().forceClientComposition);
+}
+
+TEST_F(OutputLayerUpdateCompositionStateTest,
+ clientCompositionForcedFromUnsupportedDataspaceAtAnyTime) {
+ EXPECT_CALL(mDisplayColorProfile, isDataspaceSupported(_)).WillRepeatedly(Return(false));
+
+ mOutputLayer.updateCompositionState(false);
+
+ EXPECT_EQ(true, mOutputLayer.getState().forceClientComposition);
+}
+
/*
* OutputLayer::writeStateToHWC()
*/
@@ -518,8 +568,19 @@
static constexpr float kAlpha = 51.f;
static constexpr uint32_t kType = 61u;
static constexpr uint32_t kAppId = 62u;
+ static constexpr ui::Dataspace kDataspace = static_cast<ui::Dataspace>(71);
+ static constexpr int kSupportedPerFrameMetadata = 101;
+ static constexpr int kExpectedHwcSlot = 0;
+ static const half4 kColor;
static const Rect kDisplayFrame;
+ static const Region kVisibleRegion;
+ static const mat4 kColorTransform;
+ static const Region kSurfaceDamage;
+ static const HdrMetadata kHdrMetadata;
+ static native_handle_t* kSidebandStreamHandle;
+ static const sp<GraphicBuffer> kBuffer;
+ static const sp<Fence> kFence;
OutputLayerWriteStateToHWCTest() {
auto& outputLayerState = mOutputLayer.editState();
@@ -529,13 +590,31 @@
outputLayerState.sourceCrop = kSourceCrop;
outputLayerState.z = kZOrder;
outputLayerState.bufferTransform = static_cast<Hwc2::Transform>(kBufferTransform);
+ outputLayerState.visibleRegion = kVisibleRegion;
+ outputLayerState.dataspace = kDataspace;
mLayerState.frontEnd.blendMode = kBlendMode;
mLayerState.frontEnd.alpha = kAlpha;
mLayerState.frontEnd.type = kType;
mLayerState.frontEnd.appId = kAppId;
+ mLayerState.frontEnd.colorTransform = kColorTransform;
+ mLayerState.frontEnd.color = kColor;
+ mLayerState.frontEnd.surfaceDamage = kSurfaceDamage;
+ mLayerState.frontEnd.hdrMetadata = kHdrMetadata;
+ mLayerState.frontEnd.sidebandStream = NativeHandle::create(kSidebandStreamHandle, false);
+ mLayerState.frontEnd.buffer = kBuffer;
+ mLayerState.frontEnd.bufferSlot = BufferQueue::INVALID_BUFFER_SLOT;
+ mLayerState.frontEnd.acquireFence = kFence;
+
+ EXPECT_CALL(mOutput, getDisplayColorProfile())
+ .WillRepeatedly(Return(&mDisplayColorProfile));
+ EXPECT_CALL(mDisplayColorProfile, getSupportedPerFrameMetadata())
+ .WillRepeatedly(Return(kSupportedPerFrameMetadata));
}
+ // Some tests may need to simulate unsupported HWC calls
+ enum class SimulateUnsupported { None, ColorTransform };
+
void expectGeometryCommonCalls() {
EXPECT_CALL(*mHwcLayer, setDisplayFrame(kDisplayFrame)).WillOnce(Return(kError));
EXPECT_CALL(*mHwcLayer, setSourceCrop(kSourceCrop)).WillOnce(Return(kError));
@@ -549,10 +628,62 @@
EXPECT_CALL(*mHwcLayer, setInfo(kType, kAppId)).WillOnce(Return(kError));
}
+ void expectPerFrameCommonCalls(SimulateUnsupported unsupported = SimulateUnsupported::None) {
+ EXPECT_CALL(*mHwcLayer, setVisibleRegion(RegionEq(kVisibleRegion)))
+ .WillOnce(Return(kError));
+ EXPECT_CALL(*mHwcLayer, setDataspace(kDataspace)).WillOnce(Return(kError));
+ EXPECT_CALL(*mHwcLayer, setColorTransform(kColorTransform))
+ .WillOnce(Return(unsupported == SimulateUnsupported::ColorTransform
+ ? HWC2::Error::Unsupported
+ : HWC2::Error::None));
+ EXPECT_CALL(*mHwcLayer, setSurfaceDamage(RegionEq(kSurfaceDamage)))
+ .WillOnce(Return(kError));
+ }
+
+ void expectSetCompositionTypeCall(Hwc2::IComposerClient::Composition compositionType) {
+ EXPECT_CALL(*mHwcLayer, setCompositionType(static_cast<HWC2::Composition>(compositionType)))
+ .WillOnce(Return(kError));
+ }
+
+ void expectNoSetCompositionTypeCall() {
+ EXPECT_CALL(*mHwcLayer, setCompositionType(_)).Times(0);
+ }
+
+ void expectSetColorCall() {
+ hwc_color_t color = {static_cast<uint8_t>(std::round(kColor.r * 255)),
+ static_cast<uint8_t>(std::round(kColor.g * 255)),
+ static_cast<uint8_t>(std::round(kColor.b * 255)), 255};
+
+ EXPECT_CALL(*mHwcLayer, setColor(ColorEq(color))).WillOnce(Return(kError));
+ }
+
+ void expectSetSidebandHandleCall() {
+ EXPECT_CALL(*mHwcLayer, setSidebandStream(kSidebandStreamHandle));
+ }
+
+ void expectSetHdrMetadataAndBufferCalls() {
+ EXPECT_CALL(*mHwcLayer, setPerFrameMetadata(kSupportedPerFrameMetadata, kHdrMetadata));
+ EXPECT_CALL(*mHwcLayer, setBuffer(kExpectedHwcSlot, kBuffer, kFence));
+ }
+
std::shared_ptr<HWC2::mock::Layer> mHwcLayer{std::make_shared<StrictMock<HWC2::mock::Layer>>()};
+ StrictMock<mock::DisplayColorProfile> mDisplayColorProfile;
};
+const half4 OutputLayerWriteStateToHWCTest::kColor{81.f / 255.f, 82.f / 255.f, 83.f / 255.f,
+ 84.f / 255.f};
const Rect OutputLayerWriteStateToHWCTest::kDisplayFrame{1001, 1002, 1003, 10044};
+const Region OutputLayerWriteStateToHWCTest::kVisibleRegion{Rect{1005, 1006, 1007, 1008}};
+const mat4 OutputLayerWriteStateToHWCTest::kColorTransform{
+ 1009, 1010, 1011, 1012, 1013, 1014, 1015, 1016,
+ 1017, 1018, 1019, 1020, 1021, 1022, 1023, 1024,
+};
+const Region OutputLayerWriteStateToHWCTest::kSurfaceDamage{Rect{1025, 1026, 1027, 1028}};
+const HdrMetadata OutputLayerWriteStateToHWCTest::kHdrMetadata{{/* LightFlattenable */}, 1029};
+native_handle_t* OutputLayerWriteStateToHWCTest::kSidebandStreamHandle =
+ reinterpret_cast<native_handle_t*>(1031);
+const sp<GraphicBuffer> OutputLayerWriteStateToHWCTest::kBuffer;
+const sp<Fence> OutputLayerWriteStateToHWCTest::kFence;
TEST_F(OutputLayerWriteStateToHWCTest, doesNothingIfNoHWCState) {
mOutputLayer.editState().hwc.reset();
@@ -566,11 +697,183 @@
mOutputLayer.writeStateToHWC(true);
}
-TEST_F(OutputLayerWriteStateToHWCTest, canSetsAllState) {
+TEST_F(OutputLayerWriteStateToHWCTest, canSetAllState) {
expectGeometryCommonCalls();
+ expectPerFrameCommonCalls();
+
+ expectNoSetCompositionTypeCall();
mOutputLayer.writeStateToHWC(true);
}
+TEST_F(OutputLayerWriteStateToHWCTest, canSetPerFrameStateForSolidColor) {
+ mLayerState.frontEnd.compositionType = Hwc2::IComposerClient::Composition::SOLID_COLOR;
+
+ expectPerFrameCommonCalls();
+ expectSetColorCall();
+ expectSetCompositionTypeCall(Hwc2::IComposerClient::Composition::SOLID_COLOR);
+
+ mOutputLayer.writeStateToHWC(false);
+}
+
+TEST_F(OutputLayerWriteStateToHWCTest, canSetPerFrameStateForSideband) {
+ mLayerState.frontEnd.compositionType = Hwc2::IComposerClient::Composition::SIDEBAND;
+
+ expectPerFrameCommonCalls();
+ expectSetSidebandHandleCall();
+ expectSetCompositionTypeCall(Hwc2::IComposerClient::Composition::SIDEBAND);
+
+ mOutputLayer.writeStateToHWC(false);
+}
+
+TEST_F(OutputLayerWriteStateToHWCTest, canSetPerFrameStateForCursor) {
+ mLayerState.frontEnd.compositionType = Hwc2::IComposerClient::Composition::CURSOR;
+
+ expectPerFrameCommonCalls();
+ expectSetHdrMetadataAndBufferCalls();
+ expectSetCompositionTypeCall(Hwc2::IComposerClient::Composition::CURSOR);
+
+ mOutputLayer.writeStateToHWC(false);
+}
+
+TEST_F(OutputLayerWriteStateToHWCTest, canSetPerFrameStateForDevice) {
+ mLayerState.frontEnd.compositionType = Hwc2::IComposerClient::Composition::DEVICE;
+
+ expectPerFrameCommonCalls();
+ expectSetHdrMetadataAndBufferCalls();
+ expectSetCompositionTypeCall(Hwc2::IComposerClient::Composition::DEVICE);
+
+ mOutputLayer.writeStateToHWC(false);
+}
+
+TEST_F(OutputLayerWriteStateToHWCTest, compositionTypeIsNotSetIfUnchanged) {
+ (*mOutputLayer.editState().hwc).hwcCompositionType =
+ Hwc2::IComposerClient::Composition::SOLID_COLOR;
+
+ mLayerState.frontEnd.compositionType = Hwc2::IComposerClient::Composition::SOLID_COLOR;
+
+ expectPerFrameCommonCalls();
+ expectSetColorCall();
+ expectNoSetCompositionTypeCall();
+
+ mOutputLayer.writeStateToHWC(false);
+}
+
+TEST_F(OutputLayerWriteStateToHWCTest, compositionTypeIsSetToClientIfColorTransformNotSupported) {
+ mLayerState.frontEnd.compositionType = Hwc2::IComposerClient::Composition::SOLID_COLOR;
+
+ expectPerFrameCommonCalls(SimulateUnsupported::ColorTransform);
+ expectSetColorCall();
+ expectSetCompositionTypeCall(Hwc2::IComposerClient::Composition::CLIENT);
+
+ mOutputLayer.writeStateToHWC(false);
+}
+
+TEST_F(OutputLayerWriteStateToHWCTest, compositionTypeIsSetToClientIfClientCompositionForced) {
+ mOutputLayer.editState().forceClientComposition = true;
+
+ mLayerState.frontEnd.compositionType = Hwc2::IComposerClient::Composition::SOLID_COLOR;
+
+ expectPerFrameCommonCalls();
+ expectSetColorCall();
+ expectSetCompositionTypeCall(Hwc2::IComposerClient::Composition::CLIENT);
+
+ mOutputLayer.writeStateToHWC(false);
+}
+
+/*
+ * OutputLayer::getHwcLayer()
+ */
+
+TEST_F(OutputLayerTest, getHwcLayerHandlesNoHwcState) {
+ mOutputLayer.editState().hwc.reset();
+
+ EXPECT_TRUE(mOutputLayer.getHwcLayer() == nullptr);
+}
+
+TEST_F(OutputLayerTest, getHwcLayerHandlesNoHwcLayer) {
+ mOutputLayer.editState().hwc = impl::OutputLayerCompositionState::Hwc{nullptr};
+
+ EXPECT_TRUE(mOutputLayer.getHwcLayer() == nullptr);
+}
+
+TEST_F(OutputLayerTest, getHwcLayerReturnsHwcLayer) {
+ auto hwcLayer = std::make_shared<StrictMock<HWC2::mock::Layer>>();
+ mOutputLayer.editState().hwc = impl::OutputLayerCompositionState::Hwc{hwcLayer};
+
+ EXPECT_EQ(hwcLayer.get(), mOutputLayer.getHwcLayer());
+}
+
+/*
+ * OutputLayer::requiresClientComposition()
+ */
+
+TEST_F(OutputLayerTest, requiresClientCompositionReturnsTrueIfNoHWC2State) {
+ mOutputLayer.editState().hwc.reset();
+
+ EXPECT_TRUE(mOutputLayer.requiresClientComposition());
+}
+
+TEST_F(OutputLayerTest, requiresClientCompositionReturnsTrueIfSetToClientComposition) {
+ mOutputLayer.editState().hwc = impl::OutputLayerCompositionState::Hwc{nullptr};
+ mOutputLayer.editState().hwc->hwcCompositionType = Hwc2::IComposerClient::Composition::CLIENT;
+
+ EXPECT_TRUE(mOutputLayer.requiresClientComposition());
+}
+
+TEST_F(OutputLayerTest, requiresClientCompositionReturnsFalseIfSetToDeviceComposition) {
+ mOutputLayer.editState().hwc = impl::OutputLayerCompositionState::Hwc{nullptr};
+ mOutputLayer.editState().hwc->hwcCompositionType = Hwc2::IComposerClient::Composition::DEVICE;
+
+ EXPECT_FALSE(mOutputLayer.requiresClientComposition());
+}
+
+/*
+ * OutputLayer::applyDeviceCompositionTypeChange()
+ */
+
+TEST_F(OutputLayerTest, applyDeviceCompositionTypeChangeSetsNewType) {
+ mOutputLayer.editState().hwc = impl::OutputLayerCompositionState::Hwc{nullptr};
+ mOutputLayer.editState().hwc->hwcCompositionType = Hwc2::IComposerClient::Composition::DEVICE;
+
+ mOutputLayer.applyDeviceCompositionTypeChange(Hwc2::IComposerClient::Composition::CLIENT);
+
+ ASSERT_TRUE(mOutputLayer.getState().hwc);
+ EXPECT_EQ(Hwc2::IComposerClient::Composition::CLIENT,
+ mOutputLayer.getState().hwc->hwcCompositionType);
+}
+
+/*
+ * OutputLayer::prepareForDeviceLayerRequests()
+ */
+
+TEST_F(OutputLayerTest, prepareForDeviceLayerRequestsResetsRequestState) {
+ mOutputLayer.editState().clearClientTarget = true;
+
+ mOutputLayer.prepareForDeviceLayerRequests();
+
+ EXPECT_FALSE(mOutputLayer.getState().clearClientTarget);
+}
+
+/*
+ * OutputLayer::applyDeviceLayerRequest()
+ */
+
+TEST_F(OutputLayerTest, applyDeviceLayerRequestHandlesClearClientTarget) {
+ mOutputLayer.editState().clearClientTarget = false;
+
+ mOutputLayer.applyDeviceLayerRequest(Hwc2::IComposerClient::LayerRequest::CLEAR_CLIENT_TARGET);
+
+ EXPECT_TRUE(mOutputLayer.getState().clearClientTarget);
+}
+
+TEST_F(OutputLayerTest, applyDeviceLayerRequestHandlesUnknownRequest) {
+ mOutputLayer.editState().clearClientTarget = false;
+
+ mOutputLayer.applyDeviceLayerRequest(static_cast<Hwc2::IComposerClient::LayerRequest>(0));
+
+ EXPECT_FALSE(mOutputLayer.getState().clearClientTarget);
+}
+
} // namespace
} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
index fee0c11..aa35d25 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
@@ -17,6 +17,7 @@
#include <cmath>
#include <compositionengine/impl/Output.h>
+#include <compositionengine/impl/OutputCompositionState.h>
#include <compositionengine/mock/CompositionEngine.h>
#include <compositionengine/mock/DisplayColorProfile.h>
#include <compositionengine/mock/Layer.h>
@@ -37,8 +38,7 @@
using testing::ReturnRef;
using testing::StrictMock;
-class OutputTest : public testing::Test {
-public:
+struct OutputTest : public testing::Test {
OutputTest() {
mOutput.setDisplayColorProfileForTest(
std::unique_ptr<DisplayColorProfile>(mDisplayColorProfile));
@@ -46,7 +46,6 @@
mOutput.editState().bounds = kDefaultDisplaySize;
}
- ~OutputTest() override = default;
static const Rect kDefaultDisplaySize;
@@ -58,7 +57,7 @@
const Rect OutputTest::kDefaultDisplaySize{100, 200};
-/* ------------------------------------------------------------------------
+/*
* Basic construction
*/
@@ -77,7 +76,7 @@
EXPECT_FALSE(mOutput.isValid());
}
-/* ------------------------------------------------------------------------
+/*
* Output::setCompositionEnabled()
*/
@@ -108,7 +107,7 @@
EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region(kDefaultDisplaySize)));
}
-/* ------------------------------------------------------------------------
+/*
* Output::setProjection()
*/
@@ -130,7 +129,7 @@
EXPECT_EQ(needsFiltering, mOutput.getState().needsFiltering);
}
-/* ------------------------------------------------------------------------
+/*
* Output::setBounds()
*/
@@ -147,7 +146,7 @@
EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region(Rect(displaySize))));
}
-/* ------------------------------------------------------------------------
+/*
* Output::setLayerStackFilter()
*/
@@ -161,7 +160,7 @@
EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region(kDefaultDisplaySize)));
}
-/* ------------------------------------------------------------------------
+/*
* Output::setColorTransform
*/
@@ -200,34 +199,46 @@
EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region(kDefaultDisplaySize)));
}
-/* ------------------------------------------------------------------------
+/*
* Output::setColorMode
*/
TEST_F(OutputTest, setColorModeSetsStateAndDirtiesOutputIfChanged) {
+ EXPECT_CALL(*mDisplayColorProfile,
+ getTargetDataspace(ui::ColorMode::DISPLAY_P3, ui::Dataspace::DISPLAY_P3,
+ ui::Dataspace::UNKNOWN))
+ .WillOnce(Return(ui::Dataspace::UNKNOWN));
EXPECT_CALL(*mRenderSurface, setBufferDataspace(ui::Dataspace::DISPLAY_P3)).Times(1);
mOutput.setColorMode(ui::ColorMode::DISPLAY_P3, ui::Dataspace::DISPLAY_P3,
- ui::RenderIntent::TONE_MAP_COLORIMETRIC);
+ ui::RenderIntent::TONE_MAP_COLORIMETRIC, ui::Dataspace::UNKNOWN);
EXPECT_EQ(ui::ColorMode::DISPLAY_P3, mOutput.getState().colorMode);
EXPECT_EQ(ui::Dataspace::DISPLAY_P3, mOutput.getState().dataspace);
EXPECT_EQ(ui::RenderIntent::TONE_MAP_COLORIMETRIC, mOutput.getState().renderIntent);
+ EXPECT_EQ(ui::Dataspace::UNKNOWN, mOutput.getState().targetDataspace);
+
EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region(kDefaultDisplaySize)));
}
TEST_F(OutputTest, setColorModeDoesNothingIfNoChange) {
+ EXPECT_CALL(*mDisplayColorProfile,
+ getTargetDataspace(ui::ColorMode::DISPLAY_P3, ui::Dataspace::DISPLAY_P3,
+ ui::Dataspace::UNKNOWN))
+ .WillOnce(Return(ui::Dataspace::UNKNOWN));
+
mOutput.editState().colorMode = ui::ColorMode::DISPLAY_P3;
mOutput.editState().dataspace = ui::Dataspace::DISPLAY_P3;
mOutput.editState().renderIntent = ui::RenderIntent::TONE_MAP_COLORIMETRIC;
+ mOutput.editState().targetDataspace = ui::Dataspace::UNKNOWN;
mOutput.setColorMode(ui::ColorMode::DISPLAY_P3, ui::Dataspace::DISPLAY_P3,
- ui::RenderIntent::TONE_MAP_COLORIMETRIC);
+ ui::RenderIntent::TONE_MAP_COLORIMETRIC, ui::Dataspace::UNKNOWN);
EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region()));
}
-/* ------------------------------------------------------------------------
+/*
* Output::setRenderSurface()
*/
@@ -242,7 +253,7 @@
EXPECT_EQ(Rect(newDisplaySize), mOutput.getState().bounds);
}
-/* ------------------------------------------------------------------------
+/*
* Output::getDirtyRegion()
*/
@@ -271,7 +282,7 @@
}
}
-/* ------------------------------------------------------------------------
+/*
* Output::belongsInOutput()
*/
@@ -298,7 +309,7 @@
EXPECT_FALSE(mOutput.belongsInOutput(layerStack2, false));
}
-/* ------------------------------------------------------------------------
+/*
* Output::getOutputLayerForLayer()
*/
@@ -330,7 +341,7 @@
EXPECT_EQ(nullptr, mOutput.getOutputLayerForLayer(&layer));
}
-/* ------------------------------------------------------------------------
+/*
* Output::getOrCreateOutputLayer()
*/
@@ -377,5 +388,63 @@
}
}
+/*
+ * Output::prepareFrame()
+ */
+
+struct OutputPrepareFrameTest : public testing::Test {
+ struct OutputPartialMock : public impl::Output {
+ OutputPartialMock(const compositionengine::CompositionEngine& compositionEngine)
+ : impl::Output(compositionEngine) {}
+
+ // Sets up the helper functions called by prepareFrame to use a mock
+ // implementations.
+ MOCK_METHOD0(chooseCompositionStrategy, void());
+ };
+
+ OutputPrepareFrameTest() {
+ mOutput.setDisplayColorProfileForTest(
+ std::unique_ptr<DisplayColorProfile>(mDisplayColorProfile));
+ mOutput.setRenderSurfaceForTest(std::unique_ptr<RenderSurface>(mRenderSurface));
+ }
+
+ StrictMock<mock::CompositionEngine> mCompositionEngine;
+ mock::DisplayColorProfile* mDisplayColorProfile = new StrictMock<mock::DisplayColorProfile>();
+ mock::RenderSurface* mRenderSurface = new StrictMock<mock::RenderSurface>();
+ StrictMock<OutputPartialMock> mOutput{mCompositionEngine};
+};
+
+TEST_F(OutputPrepareFrameTest, takesEarlyOutIfNotEnabled) {
+ mOutput.editState().isEnabled = false;
+
+ mOutput.prepareFrame();
+}
+
+TEST_F(OutputPrepareFrameTest, delegatesToChooseCompositionStrategyAndRenderSurface) {
+ mOutput.editState().isEnabled = true;
+ mOutput.editState().usesClientComposition = false;
+ mOutput.editState().usesDeviceComposition = true;
+
+ EXPECT_CALL(mOutput, chooseCompositionStrategy()).Times(1);
+ EXPECT_CALL(*mRenderSurface, prepareFrame(false, true));
+
+ mOutput.prepareFrame();
+}
+
+// Note: Use OutputTest and not OutputPrepareFrameTest, so the real
+// base chooseCompositionStrategy() is invoked.
+TEST_F(OutputTest, prepareFrameSetsClientCompositionOnlyByDefault) {
+ mOutput.editState().isEnabled = true;
+ mOutput.editState().usesClientComposition = false;
+ mOutput.editState().usesDeviceComposition = true;
+
+ EXPECT_CALL(*mRenderSurface, prepareFrame(true, false));
+
+ mOutput.prepareFrame();
+
+ EXPECT_TRUE(mOutput.getState().usesClientComposition);
+ EXPECT_FALSE(mOutput.getState().usesDeviceComposition);
+}
+
} // namespace
} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp b/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp
index 87419ea..da3f4fb 100644
--- a/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp
@@ -18,6 +18,7 @@
#include <cstdint>
#include <compositionengine/RenderSurfaceCreationArgs.h>
+#include <compositionengine/impl/OutputCompositionState.h>
#include <compositionengine/impl/RenderSurface.h>
#include <compositionengine/mock/CompositionEngine.h>
#include <compositionengine/mock/Display.h>
@@ -27,15 +28,9 @@
#include <gtest/gtest.h>
#include <renderengine/mock/RenderEngine.h>
-#include "MockHWComposer.h"
-
namespace android::compositionengine {
namespace {
-/* ------------------------------------------------------------------------
- * RenderSurfaceTest
- */
-
constexpr int32_t DEFAULT_DISPLAY_WIDTH = 1920;
constexpr int32_t DEFAULT_DISPLAY_HEIGHT = 1080;
constexpr std::optional<DisplayId> DEFAULT_DISPLAY_ID = std::make_optional(DisplayId{123u});
@@ -55,14 +50,11 @@
RenderSurfaceTest() {
EXPECT_CALL(mDisplay, getId()).WillRepeatedly(ReturnRef(DEFAULT_DISPLAY_ID));
EXPECT_CALL(mDisplay, getName()).WillRepeatedly(ReturnRef(DEFAULT_DISPLAY_NAME));
- EXPECT_CALL(mCompositionEngine, getHwComposer).WillRepeatedly(ReturnRef(mHwComposer));
EXPECT_CALL(mCompositionEngine, getRenderEngine).WillRepeatedly(ReturnRef(mRenderEngine));
EXPECT_CALL(*mNativeWindow, disconnect(NATIVE_WINDOW_API_EGL))
.WillRepeatedly(Return(NO_ERROR));
}
- ~RenderSurfaceTest() override = default;
- StrictMock<android::mock::HWComposer> mHwComposer;
StrictMock<renderengine::mock::RenderEngine> mRenderEngine;
StrictMock<mock::CompositionEngine> mCompositionEngine;
StrictMock<mock::Display> mDisplay;
@@ -74,7 +66,7 @@
mDisplaySurface}};
};
-/* ------------------------------------------------------------------------
+/*
* Basic construction
*/
@@ -82,7 +74,7 @@
EXPECT_TRUE(mSurface.isValid());
}
-/* ------------------------------------------------------------------------
+/*
* RenderSurface::initialize()
*/
@@ -95,7 +87,7 @@
mSurface.initialize();
}
-/* ------------------------------------------------------------------------
+/*
* RenderSurface::getSize()
*/
@@ -105,7 +97,7 @@
EXPECT_EQ(expected, mSurface.getSize());
}
-/* ------------------------------------------------------------------------
+/*
* RenderSurface::getClientTargetAcquireFence()
*/
@@ -117,7 +109,7 @@
EXPECT_EQ(fence.get(), mSurface.getClientTargetAcquireFence().get());
}
-/* ------------------------------------------------------------------------
+/*
* RenderSurface::setDisplaySize()
*/
@@ -127,7 +119,7 @@
mSurface.setDisplaySize(ui::Size(640, 480));
}
-/* ------------------------------------------------------------------------
+/*
* RenderSurface::setBufferDataspace()
*/
@@ -138,7 +130,7 @@
mSurface.setBufferDataspace(ui::Dataspace::DISPLAY_P3);
}
-/* ------------------------------------------------------------------------
+/*
* RenderSurface::setProtected()
*/
@@ -179,7 +171,7 @@
EXPECT_FALSE(mSurface.isProtected());
}
-/* ------------------------------------------------------------------------
+/*
* RenderSurface::beginFrame()
*/
@@ -189,73 +181,39 @@
EXPECT_EQ(NO_ERROR, mSurface.beginFrame(true));
}
-/* ------------------------------------------------------------------------
+/*
* RenderSurface::prepareFrame()
*/
-TEST_F(RenderSurfaceTest, prepareFramePassesOutputLayersToHwc) {
- EXPECT_CALL(mHwComposer, prepare(*DEFAULT_DISPLAY_ID, Ref(mDisplay)))
- .WillOnce(Return(INVALID_OPERATION));
-
- EXPECT_EQ(INVALID_OPERATION, mSurface.prepareFrame());
-}
-
-TEST_F(RenderSurfaceTest, prepareFrameTakesEarlyOutOnHwcError) {
- EXPECT_CALL(mHwComposer, prepare(*DEFAULT_DISPLAY_ID, Ref(mDisplay)))
- .WillOnce(Return(INVALID_OPERATION));
-
- EXPECT_EQ(INVALID_OPERATION, mSurface.prepareFrame());
-}
-
TEST_F(RenderSurfaceTest, prepareFrameHandlesMixedComposition) {
- EXPECT_CALL(mHwComposer, prepare(*DEFAULT_DISPLAY_ID, Ref(mDisplay)))
- .WillOnce(Return(NO_ERROR));
- EXPECT_CALL(mHwComposer, hasClientComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(true));
- EXPECT_CALL(mHwComposer, hasDeviceComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(true));
-
EXPECT_CALL(*mDisplaySurface, prepareFrame(DisplaySurface::COMPOSITION_MIXED))
- .WillOnce(Return(INVALID_OPERATION));
+ .WillOnce(Return(NO_ERROR));
- EXPECT_EQ(INVALID_OPERATION, mSurface.prepareFrame());
+ mSurface.prepareFrame(true, true);
}
TEST_F(RenderSurfaceTest, prepareFrameHandlesOnlyGlesComposition) {
- EXPECT_CALL(mHwComposer, prepare(*DEFAULT_DISPLAY_ID, Ref(mDisplay)))
- .WillOnce(Return(NO_ERROR));
- EXPECT_CALL(mHwComposer, hasClientComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(true));
- EXPECT_CALL(mHwComposer, hasDeviceComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(false));
-
EXPECT_CALL(*mDisplaySurface, prepareFrame(DisplaySurface::COMPOSITION_GLES))
.WillOnce(Return(NO_ERROR));
- EXPECT_EQ(NO_ERROR, mSurface.prepareFrame());
+ mSurface.prepareFrame(true, false);
}
TEST_F(RenderSurfaceTest, prepareFrameHandlesOnlyHwcComposition) {
- EXPECT_CALL(mHwComposer, prepare(*DEFAULT_DISPLAY_ID, Ref(mDisplay)))
- .WillOnce(Return(NO_ERROR));
- EXPECT_CALL(mHwComposer, hasClientComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(false));
- EXPECT_CALL(mHwComposer, hasDeviceComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(true));
-
EXPECT_CALL(*mDisplaySurface, prepareFrame(DisplaySurface::COMPOSITION_HWC))
.WillOnce(Return(NO_ERROR));
- EXPECT_EQ(NO_ERROR, mSurface.prepareFrame());
+ mSurface.prepareFrame(false, true);
}
TEST_F(RenderSurfaceTest, prepareFrameHandlesNoComposition) {
- EXPECT_CALL(mHwComposer, prepare(*DEFAULT_DISPLAY_ID, Ref(mDisplay)))
- .WillOnce(Return(NO_ERROR));
- EXPECT_CALL(mHwComposer, hasClientComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(false));
- EXPECT_CALL(mHwComposer, hasDeviceComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(false));
-
EXPECT_CALL(*mDisplaySurface, prepareFrame(DisplaySurface::COMPOSITION_HWC))
.WillOnce(Return(NO_ERROR));
- EXPECT_EQ(NO_ERROR, mSurface.prepareFrame());
+ mSurface.prepareFrame(false, false);
}
-/* ------------------------------------------------------------------------
+/*
* RenderSurface::dequeueBuffer()
*/
@@ -272,7 +230,7 @@
EXPECT_EQ(buffer.get(), mSurface.mutableGraphicBufferForTest().get());
}
-/* ------------------------------------------------------------------------
+/*
* RenderSurface::queueBuffer()
*/
@@ -280,9 +238,11 @@
sp<GraphicBuffer> buffer = new GraphicBuffer();
mSurface.mutableGraphicBufferForTest() = buffer;
- EXPECT_CALL(mHwComposer, hasClientComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(false));
- EXPECT_CALL(mHwComposer, hasFlipClientTargetRequest(DEFAULT_DISPLAY_ID))
- .WillOnce(Return(false));
+ impl::OutputCompositionState state;
+ state.usesClientComposition = false;
+ state.flipClientTarget = false;
+
+ EXPECT_CALL(mDisplay, getState()).WillOnce(ReturnRef(state));
EXPECT_CALL(*mDisplaySurface, advanceFrame()).Times(1);
mSurface.queueBuffer(base::unique_fd());
@@ -294,7 +254,11 @@
sp<GraphicBuffer> buffer = new GraphicBuffer();
mSurface.mutableGraphicBufferForTest() = buffer;
- EXPECT_CALL(mHwComposer, hasClientComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(true));
+ impl::OutputCompositionState state;
+ state.usesClientComposition = true;
+ state.flipClientTarget = false;
+
+ EXPECT_CALL(mDisplay, getState()).WillOnce(ReturnRef(state));
EXPECT_CALL(*mNativeWindow, queueBuffer(buffer->getNativeBuffer(), -1))
.WillOnce(Return(NO_ERROR));
EXPECT_CALL(*mDisplaySurface, advanceFrame()).Times(1);
@@ -308,8 +272,11 @@
sp<GraphicBuffer> buffer = new GraphicBuffer();
mSurface.mutableGraphicBufferForTest() = buffer;
- EXPECT_CALL(mHwComposer, hasClientComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(false));
- EXPECT_CALL(mHwComposer, hasFlipClientTargetRequest(DEFAULT_DISPLAY_ID)).WillOnce(Return(true));
+ impl::OutputCompositionState state;
+ state.usesClientComposition = false;
+ state.flipClientTarget = true;
+
+ EXPECT_CALL(mDisplay, getState()).WillOnce(ReturnRef(state));
EXPECT_CALL(*mNativeWindow, queueBuffer(buffer->getNativeBuffer(), -1))
.WillOnce(Return(NO_ERROR));
EXPECT_CALL(*mDisplaySurface, advanceFrame()).Times(1);
@@ -322,8 +289,11 @@
TEST_F(RenderSurfaceTest, queueBufferHandlesFlipClientTargetRequestWithNoBufferYetDequeued) {
sp<GraphicBuffer> buffer = new GraphicBuffer();
- EXPECT_CALL(mHwComposer, hasClientComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(false));
- EXPECT_CALL(mHwComposer, hasFlipClientTargetRequest(DEFAULT_DISPLAY_ID)).WillOnce(Return(true));
+ impl::OutputCompositionState state;
+ state.usesClientComposition = false;
+ state.flipClientTarget = true;
+
+ EXPECT_CALL(mDisplay, getState()).WillOnce(ReturnRef(state));
EXPECT_CALL(*mNativeWindow, dequeueBuffer(_, _))
.WillOnce(
DoAll(SetArgPointee<0>(buffer.get()), SetArgPointee<1>(-1), Return(NO_ERROR)));
@@ -340,7 +310,10 @@
sp<GraphicBuffer> buffer = new GraphicBuffer();
mSurface.mutableGraphicBufferForTest() = buffer;
- EXPECT_CALL(mHwComposer, hasClientComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(true));
+ impl::OutputCompositionState state;
+ state.usesClientComposition = true;
+
+ EXPECT_CALL(mDisplay, getState()).WillOnce(ReturnRef(state));
EXPECT_CALL(*mNativeWindow, queueBuffer(buffer->getNativeBuffer(), -1))
.WillOnce(Return(INVALID_OPERATION));
EXPECT_CALL(mDisplay, isVirtual()).WillOnce(Return(true));
@@ -353,7 +326,7 @@
EXPECT_EQ(nullptr, mSurface.mutableGraphicBufferForTest().get());
}
-/* ------------------------------------------------------------------------
+/*
* RenderSurface::onPresentDisplayCompleted()
*/
@@ -363,7 +336,7 @@
mSurface.onPresentDisplayCompleted();
}
-/* ------------------------------------------------------------------------
+/*
* RenderSurface::flip()
*/
diff --git a/services/surfaceflinger/ContainerLayer.cpp b/services/surfaceflinger/ContainerLayer.cpp
index 7927fa9..d40a38c 100644
--- a/services/surfaceflinger/ContainerLayer.cpp
+++ b/services/surfaceflinger/ContainerLayer.cpp
@@ -26,11 +26,6 @@
ContainerLayer::~ContainerLayer() = default;
-bool ContainerLayer::prepareClientLayer(const RenderArea&, const Region&, bool, Region&, const bool,
- renderengine::LayerSettings&) {
- return false;
-}
-
bool ContainerLayer::isVisible() const {
return false;
}
@@ -39,7 +34,4 @@
return !isHiddenByPolicy();
}
-void ContainerLayer::setPerFrameData(const sp<const DisplayDevice>&, const ui::Transform&,
- const Rect&, int32_t, const ui::Dataspace) {}
-
} // namespace android
diff --git a/services/surfaceflinger/ContainerLayer.h b/services/surfaceflinger/ContainerLayer.h
index 7222a3e..a1607ff 100644
--- a/services/surfaceflinger/ContainerLayer.h
+++ b/services/surfaceflinger/ContainerLayer.h
@@ -33,19 +33,7 @@
bool canReceiveInput() const override;
- void setPerFrameData(const sp<const DisplayDevice>& display, const ui::Transform& transform,
- const Rect& viewport, int32_t supportedPerFrameMetadata,
- const ui::Dataspace targetDataspace) override;
-
bool isCreatedFromMainThread() const override { return true; }
-
- bool onPreComposition(nsecs_t /*refreshStartTime*/) override { return false; }
-
-protected:
- bool prepareClientLayer(const RenderArea& renderArea, const Region& clip,
- bool useIdentityTransform, Region& clearRegion,
- const bool supportProtectedContent,
- renderengine::LayerSettings& layer) override;
};
} // namespace android
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index 4a13bfb..d136562 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -126,14 +126,6 @@
return mVisibleLayersSortedByZ;
}
-void DisplayDevice::setLayersNeedingFences(const Vector< sp<Layer> >& layers) {
- mLayersNeedingFences = layers;
-}
-
-const Vector< sp<Layer> >& DisplayDevice::getLayersNeedingFences() const {
- return mLayersNeedingFences;
-}
-
// ----------------------------------------------------------------------------
void DisplayDevice::setPowerMode(int mode) {
mPowerMode = mode;
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index 0067b50..8bc19d4 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -88,8 +88,6 @@
void setVisibleLayersSortedByZ(const Vector< sp<Layer> >& layers);
const Vector< sp<Layer> >& getVisibleLayersSortedByZ() const;
- void setLayersNeedingFences(const Vector< sp<Layer> >& layers);
- const Vector< sp<Layer> >& getLayersNeedingFences() const;
void setLayerStack(uint32_t stack);
void setDisplaySize(const int newWidth, const int newHeight);
@@ -182,8 +180,6 @@
// list of visible layers on that display
Vector< sp<Layer> > mVisibleLayersSortedByZ;
- // list of layers needing fences
- Vector< sp<Layer> > mLayersNeedingFences;
/*
* Transaction state
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 1099041..d480f7c 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -20,6 +20,8 @@
#define LOG_TAG "HWComposer"
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+#include "HWComposer.h"
+
#include <compositionengine/Output.h>
#include <compositionengine/OutputLayer.h>
#include <compositionengine/impl/OutputLayerCompositionState.h>
@@ -29,12 +31,10 @@
#include <utils/Errors.h>
#include <utils/Trace.h>
-#include "HWComposer.h"
-#include "HWC2.h"
-#include "ComposerHal.h"
-
-#include "../Layer.h" // needed only for debugging
+#include "../Layer.h" // needed only for debugging
#include "../SurfaceFlinger.h"
+#include "ComposerHal.h"
+#include "HWC2.h"
#define LOG_HWC_DISPLAY_ERROR(hwcDisplayId, msg) \
ALOGE("%s failed for HWC display %" PRIu64 ": %s", __FUNCTION__, hwcDisplayId, msg)
@@ -113,31 +113,6 @@
return mDisplayData.at(*displayId).hwcDisplay->getCapabilities().count(capability) > 0;
}
-void HWComposer::validateChange(HWC2::Composition from, HWC2::Composition to) {
- bool valid = true;
- switch (from) {
- case HWC2::Composition::Client:
- valid = false;
- break;
- case HWC2::Composition::Device:
- case HWC2::Composition::SolidColor:
- valid = (to == HWC2::Composition::Client);
- break;
- case HWC2::Composition::Cursor:
- case HWC2::Composition::Sideband:
- valid = (to == HWC2::Composition::Client ||
- to == HWC2::Composition::Device);
- break;
- default:
- break;
- }
-
- if (!valid) {
- ALOGE("Invalid layer type change: %s --> %s", to_string(from).c_str(),
- to_string(to).c_str());
- }
-}
-
std::optional<DisplayIdentificationInfo> HWComposer::onHotplug(hwc2_display_t hwcDisplayId,
HWC2::Connection connection) {
std::optional<DisplayIdentificationInfo> info;
@@ -399,7 +374,9 @@
return NO_ERROR;
}
-status_t HWComposer::prepare(DisplayId displayId, const compositionengine::Output& output) {
+status_t HWComposer::getDeviceCompositionChanges(
+ DisplayId displayId, bool frameUsesClientComposition,
+ std::optional<android::HWComposer::DeviceRequestedChanges>* outChanges) {
ATRACE_CALL();
RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX);
@@ -419,12 +396,8 @@
// composition. When there is client composition, since we haven't
// rendered to the client target yet, we should not attempt to skip
// validate.
- //
- // displayData.hasClientComposition hasn't been updated for this frame.
- // The check below is incorrect. We actually rely on HWC here to fall
- // back to validate when there is any client layer.
displayData.validateWasSkipped = false;
- if (!displayData.hasClientComposition) {
+ if (!frameUsesClientComposition) {
sp<Fence> outPresentFence;
uint32_t state = UINT32_MAX;
error = hwcDisplay->presentOrValidate(&numTypes, &numRequests, &outPresentFence , &state);
@@ -449,58 +422,19 @@
RETURN_IF_HWC_ERROR_FOR("validate", error, displayId, BAD_INDEX);
}
- std::unordered_map<HWC2::Layer*, HWC2::Composition> changedTypes;
+ android::HWComposer::DeviceRequestedChanges::ChangedTypes changedTypes;
changedTypes.reserve(numTypes);
error = hwcDisplay->getChangedCompositionTypes(&changedTypes);
RETURN_IF_HWC_ERROR_FOR("getChangedCompositionTypes", error, displayId, BAD_INDEX);
- displayData.displayRequests = static_cast<HWC2::DisplayRequest>(0);
- std::unordered_map<HWC2::Layer*, HWC2::LayerRequest> layerRequests;
+ auto displayRequests = static_cast<HWC2::DisplayRequest>(0);
+ android::HWComposer::DeviceRequestedChanges::LayerRequests layerRequests;
layerRequests.reserve(numRequests);
- error = hwcDisplay->getRequests(&displayData.displayRequests,
- &layerRequests);
+ error = hwcDisplay->getRequests(&displayRequests, &layerRequests);
RETURN_IF_HWC_ERROR_FOR("getRequests", error, displayId, BAD_INDEX);
- displayData.hasClientComposition = false;
- displayData.hasDeviceComposition = false;
- for (auto& outputLayer : output.getOutputLayersOrderedByZ()) {
- auto& state = outputLayer->editState();
- LOG_FATAL_IF(!state.hwc.);
- auto hwcLayer = (*state.hwc).hwcLayer;
-
- if (auto it = changedTypes.find(hwcLayer.get()); it != changedTypes.end()) {
- auto newCompositionType = it->second;
- validateChange(static_cast<HWC2::Composition>((*state.hwc).hwcCompositionType),
- newCompositionType);
- (*state.hwc).hwcCompositionType =
- static_cast<Hwc2::IComposerClient::Composition>(newCompositionType);
- }
-
- switch ((*state.hwc).hwcCompositionType) {
- case Hwc2::IComposerClient::Composition::CLIENT:
- displayData.hasClientComposition = true;
- break;
- case Hwc2::IComposerClient::Composition::DEVICE:
- case Hwc2::IComposerClient::Composition::SOLID_COLOR:
- case Hwc2::IComposerClient::Composition::CURSOR:
- case Hwc2::IComposerClient::Composition::SIDEBAND:
- displayData.hasDeviceComposition = true;
- break;
- default:
- break;
- }
-
- state.clearClientTarget = false;
- if (auto it = layerRequests.find(hwcLayer.get()); it != layerRequests.end()) {
- auto request = it->second;
- if (request == HWC2::LayerRequest::ClearClientTarget) {
- state.clearClientTarget = true;
- } else {
- LOG_DISPLAY_ERROR(displayId,
- ("Unknown layer request " + to_string(request)).c_str());
- }
- }
- }
+ outChanges->emplace(DeviceRequestedChanges{std::move(changedTypes), std::move(displayRequests),
+ std::move(layerRequests)});
error = hwcDisplay->acceptChanges();
RETURN_IF_HWC_ERROR_FOR("acceptChanges", error, displayId, BAD_INDEX);
@@ -508,40 +442,6 @@
return NO_ERROR;
}
-bool HWComposer::hasDeviceComposition(const std::optional<DisplayId>& displayId) const {
- if (!displayId) {
- // Displays without a corresponding HWC display are never composed by
- // the device
- return false;
- }
-
- RETURN_IF_INVALID_DISPLAY(*displayId, false);
- return mDisplayData.at(*displayId).hasDeviceComposition;
-}
-
-bool HWComposer::hasFlipClientTargetRequest(const std::optional<DisplayId>& displayId) const {
- if (!displayId) {
- // Displays without a corresponding HWC display are never composed by
- // the device
- return false;
- }
-
- RETURN_IF_INVALID_DISPLAY(*displayId, false);
- return ((static_cast<uint32_t>(mDisplayData.at(*displayId).displayRequests) &
- static_cast<uint32_t>(HWC2::DisplayRequest::FlipClientTarget)) != 0);
-}
-
-bool HWComposer::hasClientComposition(const std::optional<DisplayId>& displayId) const {
- if (!displayId) {
- // Displays without a corresponding HWC display are always composed by
- // the client
- return true;
- }
-
- RETURN_IF_INVALID_DISPLAY(*displayId, true);
- return mDisplayData.at(*displayId).hasClientComposition;
-}
-
sp<Fence> HWComposer::getPresentFence(DisplayId displayId) const {
RETURN_IF_INVALID_DISPLAY(displayId, Fence::NO_FENCE);
return mDisplayData.at(displayId).lastPresentFence;
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index de863b8..e87c5c3 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -71,8 +71,26 @@
// Destroy a previously created layer
virtual void destroyLayer(DisplayId displayId, HWC2::Layer* layer) = 0;
- // Asks the HAL what it can do
- virtual status_t prepare(DisplayId displayId, const compositionengine::Output&) = 0;
+ struct DeviceRequestedChanges {
+ using ChangedTypes = std::unordered_map<HWC2::Layer*, HWC2::Composition>;
+ using DisplayRequests = HWC2::DisplayRequest;
+ using LayerRequests = std::unordered_map<HWC2::Layer*, HWC2::LayerRequest>;
+
+ ChangedTypes changedTypes;
+ DisplayRequests displayRequests;
+ LayerRequests layerRequests;
+ };
+
+ // Gets any required composition change requests from the HWC device.
+ //
+ // Note that frameUsesClientComposition must be set correctly based on
+ // whether the current frame appears to use client composition. If it is
+ // false some internal optimizations are allowed to present the display
+ // with fewer handshakes, but this does not work if client composition is
+ // expected.
+ virtual status_t getDeviceCompositionChanges(
+ DisplayId, bool frameUsesClientComposition,
+ std::optional<DeviceRequestedChanges>* outChanges) = 0;
virtual status_t setClientTarget(DisplayId displayId, uint32_t slot,
const sp<Fence>& acquireFence, const sp<GraphicBuffer>& target,
@@ -93,15 +111,6 @@
// reset state when an external, non-virtual display is disconnected
virtual void disconnectDisplay(DisplayId displayId) = 0;
- // does this display have layers handled by HWC
- virtual bool hasDeviceComposition(const std::optional<DisplayId>& displayId) const = 0;
-
- // does this display have pending request to flip client target
- virtual bool hasFlipClientTargetRequest(const std::optional<DisplayId>& displayId) const = 0;
-
- // does this display have layers handled by GLES
- virtual bool hasClientComposition(const std::optional<DisplayId>& displayId) const = 0;
-
// get the present fence received from the last call to present.
virtual sp<Fence> getPresentFence(DisplayId displayId) const = 0;
@@ -210,8 +219,9 @@
// Destroy a previously created layer
void destroyLayer(DisplayId displayId, HWC2::Layer* layer) override;
- // Asks the HAL what it can do
- status_t prepare(DisplayId displayId, const compositionengine::Output&) override;
+ status_t getDeviceCompositionChanges(
+ DisplayId, bool frameUsesClientComposition,
+ std::optional<DeviceRequestedChanges>* outChanges) override;
status_t setClientTarget(DisplayId displayId, uint32_t slot, const sp<Fence>& acquireFence,
const sp<GraphicBuffer>& target, ui::Dataspace dataspace) override;
@@ -231,15 +241,6 @@
// reset state when an external, non-virtual display is disconnected
void disconnectDisplay(DisplayId displayId) override;
- // does this display have layers handled by HWC
- bool hasDeviceComposition(const std::optional<DisplayId>& displayId) const override;
-
- // does this display have pending request to flip client target
- bool hasFlipClientTargetRequest(const std::optional<DisplayId>& displayId) const override;
-
- // does this display have layers handled by GLES
- bool hasClientComposition(const std::optional<DisplayId>& displayId) const override;
-
// get the present fence received from the last call to present.
sp<Fence> getPresentFence(DisplayId displayId) const override;
@@ -326,14 +327,10 @@
std::optional<DisplayIdentificationInfo> onHotplugConnect(hwc2_display_t hwcDisplayId);
- static void validateChange(HWC2::Composition from, HWC2::Composition to);
-
struct DisplayData {
bool isVirtual = false;
- bool hasClientComposition = false;
- bool hasDeviceComposition = false;
+
HWC2::Display* hwcDisplay = nullptr;
- HWC2::DisplayRequest displayRequests;
sp<Fence> lastPresentFence = Fence::NO_FENCE; // signals when the last set op retires
std::unordered_map<HWC2::Layer*, sp<Fence>> releaseFences;
buffer_handle_t outbufHandle = nullptr;
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 26c61ba..a2eeea5 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -153,7 +153,6 @@
mRemoteSyncPoints.clear();
{
- Mutex::Autolock pendingStateLock(mPendingStateMutex);
for (State pendingState : mPendingStates) {
pendingState.barrierLayer_legacy = nullptr;
}
@@ -242,20 +241,6 @@
// h/w composer set-up
// ---------------------------------------------------------------------------
-bool Layer::hasHwcLayer(const sp<const DisplayDevice>& displayDevice) {
- auto outputLayer = findOutputLayerForDisplay(displayDevice);
- LOG_FATAL_IF(!outputLayer);
- return outputLayer->getState().hwc && (*outputLayer->getState().hwc).hwcLayer != nullptr;
-}
-
-HWC2::Layer* Layer::getHwcLayer(const sp<const DisplayDevice>& displayDevice) {
- auto outputLayer = findOutputLayerForDisplay(displayDevice);
- if (!outputLayer || !outputLayer->getState().hwc) {
- return nullptr;
- }
- return (*outputLayer->getState().hwc).hwcLayer.get();
-}
-
Rect Layer::getContentCrop() const {
// this is the crop rectangle that applies to the buffer
// itself (as opposed to the window)
@@ -454,29 +439,42 @@
compositionState.appId = appId;
}
+void Layer::latchPerFrameState(compositionengine::LayerFECompositionState& compositionState) const {
+ compositionState.forceClientComposition = false;
+
+ // TODO(lpique): b/121291683 Remove this one we are sure we don't need the
+ // value recomputed / set every frame.
+ compositionState.geomVisibleRegion = visibleRegion;
+
+ compositionState.isColorspaceAgnostic = isColorSpaceAgnostic();
+ compositionState.dataspace = mCurrentDataSpace;
+ compositionState.colorTransform = getColorTransform();
+ compositionState.colorTransformIsIdentity = !hasColorTransform();
+ compositionState.surfaceDamage = surfaceDamageRegion;
+
+ // Force client composition for special cases known only to the front-end.
+ if (isHdrY410() || getRoundedCornerState().radius > 0.0f) {
+ compositionState.forceClientComposition = true;
+ }
+}
+
+bool Layer::onPreComposition(nsecs_t) {
+ return false;
+}
+
void Layer::latchCompositionState(compositionengine::LayerFECompositionState& compositionState,
bool includeGeometry) const {
if (includeGeometry) {
latchGeometry(compositionState);
}
+
+ latchPerFrameState(compositionState);
}
const char* Layer::getDebugName() const {
return mName.string();
}
-void Layer::forceClientComposition(const sp<DisplayDevice>& display) {
- const auto outputLayer = findOutputLayerForDisplay(display);
- LOG_FATAL_IF(!outputLayer);
- outputLayer->editState().forceClientComposition = true;
-}
-
-bool Layer::getForceClientComposition(const sp<DisplayDevice>& display) {
- const auto outputLayer = findOutputLayerForDisplay(display);
- LOG_FATAL_IF(!outputLayer);
- return outputLayer->getState().forceClientComposition;
-}
-
void Layer::updateCursorPosition(const sp<const DisplayDevice>& display) {
const auto outputLayer = findOutputLayerForDisplay(display);
LOG_FATAL_IF(!outputLayer);
@@ -513,77 +511,33 @@
// drawing...
// ---------------------------------------------------------------------------
-bool Layer::prepareClientLayer(const RenderArea& renderArea, const Region& clip,
- Region& clearRegion, const bool supportProtectedContent,
- renderengine::LayerSettings& layer) {
- return prepareClientLayer(renderArea, clip, false, clearRegion, supportProtectedContent, layer);
-}
+std::optional<renderengine::LayerSettings> Layer::prepareClientComposition(
+ compositionengine::LayerFE::ClientCompositionTargetSettings& targetSettings) {
+ if (!getCompositionLayer()) {
+ return {};
+ }
-bool Layer::prepareClientLayer(const RenderArea& renderArea, bool useIdentityTransform,
- Region& clearRegion, const bool supportProtectedContent,
- renderengine::LayerSettings& layer) {
- return prepareClientLayer(renderArea, Region(renderArea.getBounds()), useIdentityTransform,
- clearRegion, supportProtectedContent, layer);
-}
-
-bool Layer::prepareClientLayer(const RenderArea& /*renderArea*/, const Region& /*clip*/,
- bool useIdentityTransform, Region& /*clearRegion*/,
- const bool /*supportProtectedContent*/,
- renderengine::LayerSettings& layer) {
FloatRect bounds = getBounds();
half alpha = getAlpha();
- layer.geometry.boundaries = bounds;
- if (useIdentityTransform) {
- layer.geometry.positionTransform = mat4();
+ renderengine::LayerSettings layerSettings;
+ layerSettings.geometry.boundaries = bounds;
+ if (targetSettings.useIdentityTransform) {
+ layerSettings.geometry.positionTransform = mat4();
} else {
- const ui::Transform transform = getTransform();
- mat4 m;
- m[0][0] = transform[0][0];
- m[0][1] = transform[0][1];
- m[0][3] = transform[0][2];
- m[1][0] = transform[1][0];
- m[1][1] = transform[1][1];
- m[1][3] = transform[1][2];
- m[3][0] = transform[2][0];
- m[3][1] = transform[2][1];
- m[3][3] = transform[2][2];
- layer.geometry.positionTransform = m;
+ layerSettings.geometry.positionTransform = getTransform().asMatrix4();
}
if (hasColorTransform()) {
- layer.colorTransform = getColorTransform();
+ layerSettings.colorTransform = getColorTransform();
}
const auto roundedCornerState = getRoundedCornerState();
- layer.geometry.roundedCornersRadius = roundedCornerState.radius;
- layer.geometry.roundedCornersCrop = roundedCornerState.cropRect;
+ layerSettings.geometry.roundedCornersRadius = roundedCornerState.radius;
+ layerSettings.geometry.roundedCornersCrop = roundedCornerState.cropRect;
- layer.alpha = alpha;
- layer.sourceDataspace = mCurrentDataSpace;
- return true;
-}
-
-void Layer::setCompositionType(const sp<const DisplayDevice>& display,
- Hwc2::IComposerClient::Composition type) {
- const auto outputLayer = findOutputLayerForDisplay(display);
- LOG_FATAL_IF(!outputLayer);
- LOG_FATAL_IF(!outputLayer->getState().hwc);
- auto& compositionState = outputLayer->editState();
-
- ALOGV("setCompositionType(%" PRIx64 ", %s, %d)", ((*compositionState.hwc).hwcLayer)->getId(),
- toString(type).c_str(), 1);
- if ((*compositionState.hwc).hwcCompositionType != type) {
- ALOGV(" actually setting");
- (*compositionState.hwc).hwcCompositionType = type;
-
- auto error = (*compositionState.hwc)
- .hwcLayer->setCompositionType(static_cast<HWC2::Composition>(type));
- ALOGE_IF(error != HWC2::Error::None,
- "[%s] Failed to set "
- "composition type %s: %s (%d)",
- mName.string(), toString(type).c_str(), to_string(error).c_str(),
- static_cast<int32_t>(error));
- }
+ layerSettings.alpha = alpha;
+ layerSettings.sourceDataspace = mCurrentDataSpace;
+ return layerSettings;
}
Hwc2::IComposerClient::Composition Layer::getCompositionType(
@@ -881,6 +835,7 @@
// Commit the transaction
commitTransaction(c);
+ mPendingStatesSnapshot = mPendingStates;
mCurrentState.callbackHandles = {};
return flags;
}
@@ -1848,14 +1803,61 @@
setTransactionFlags(eTransactionNeeded);
}
-void Layer::writeToProto(LayerProto* layerInfo, LayerVector::StateSet stateSet,
- uint32_t traceFlags) {
+void Layer::writeToProtoDrawingState(LayerProto* layerInfo, uint32_t traceFlags) const {
+ ui::Transform transform = getTransform();
+
+ if (traceFlags & SurfaceTracing::TRACE_CRITICAL) {
+ for (const auto& pendingState : mPendingStatesSnapshot) {
+ auto barrierLayer = pendingState.barrierLayer_legacy.promote();
+ if (barrierLayer != nullptr) {
+ BarrierLayerProto* barrierLayerProto = layerInfo->add_barrier_layer();
+ barrierLayerProto->set_id(barrierLayer->sequence);
+ barrierLayerProto->set_frame_number(pendingState.frameNumber_legacy);
+ }
+ }
+
+ auto buffer = mActiveBuffer;
+ if (buffer != nullptr) {
+ LayerProtoHelper::writeToProto(buffer,
+ [&]() { return layerInfo->mutable_active_buffer(); });
+ LayerProtoHelper::writeToProto(ui::Transform(mCurrentTransform),
+ layerInfo->mutable_buffer_transform());
+ }
+ layerInfo->set_invalidate(contentDirty);
+ layerInfo->set_is_protected(isProtected());
+ layerInfo->set_dataspace(
+ dataspaceDetails(static_cast<android_dataspace>(mCurrentDataSpace)));
+ layerInfo->set_queued_frames(getQueuedFrameCount());
+ layerInfo->set_refresh_pending(isBufferLatched());
+ layerInfo->set_curr_frame(mCurrentFrameNumber);
+ layerInfo->set_effective_scaling_mode(getEffectiveScalingMode());
+
+ layerInfo->set_corner_radius(getRoundedCornerState().radius);
+ LayerProtoHelper::writeToProto(transform, layerInfo->mutable_transform());
+ LayerProtoHelper::writePositionToProto(transform.tx(), transform.ty(),
+ [&]() { return layerInfo->mutable_position(); });
+ LayerProtoHelper::writeToProto(mBounds, [&]() { return layerInfo->mutable_bounds(); });
+ LayerProtoHelper::writeToProto(visibleRegion,
+ [&]() { return layerInfo->mutable_visible_region(); });
+ LayerProtoHelper::writeToProto(surfaceDamageRegion,
+ [&]() { return layerInfo->mutable_damage_region(); });
+ }
+
+ if (traceFlags & SurfaceTracing::TRACE_EXTRA) {
+ LayerProtoHelper::writeToProto(mSourceBounds,
+ [&]() { return layerInfo->mutable_source_bounds(); });
+ LayerProtoHelper::writeToProto(mScreenBounds,
+ [&]() { return layerInfo->mutable_screen_bounds(); });
+ }
+}
+
+void Layer::writeToProtoCommonState(LayerProto* layerInfo, LayerVector::StateSet stateSet,
+ uint32_t traceFlags) const {
const bool useDrawing = stateSet == LayerVector::StateSet::Drawing;
const LayerVector& children = useDrawing ? mDrawingChildren : mCurrentChildren;
const State& state = useDrawing ? mDrawingState : mCurrentState;
ui::Transform requestedTransform = state.active_legacy.transform;
- ui::Transform transform = getTransform();
if (traceFlags & SurfaceTracing::TRACE_CRITICAL) {
layerInfo->set_id(sequence);
@@ -1875,17 +1877,10 @@
LayerProtoHelper::writeToProto(state.activeTransparentRegion_legacy,
[&]() { return layerInfo->mutable_transparent_region(); });
- LayerProtoHelper::writeToProto(visibleRegion,
- [&]() { return layerInfo->mutable_visible_region(); });
- LayerProtoHelper::writeToProto(surfaceDamageRegion,
- [&]() { return layerInfo->mutable_damage_region(); });
layerInfo->set_layer_stack(getLayerStack());
layerInfo->set_z(state.z);
- LayerProtoHelper::writePositionToProto(transform.tx(), transform.ty(),
- [&]() { return layerInfo->mutable_position(); });
-
LayerProtoHelper::writePositionToProto(requestedTransform.tx(), requestedTransform.ty(),
[&]() {
return layerInfo->mutable_requested_position();
@@ -1896,15 +1891,9 @@
LayerProtoHelper::writeToProto(state.crop_legacy,
[&]() { return layerInfo->mutable_crop(); });
- layerInfo->set_corner_radius(getRoundedCornerState().radius);
layerInfo->set_is_opaque(isOpaque(state));
- layerInfo->set_invalidate(contentDirty);
- layerInfo->set_is_protected(isProtected());
- // XXX (b/79210409) mCurrentDataSpace is not protected
- layerInfo->set_dataspace(
- dataspaceDetails(static_cast<android_dataspace>(mCurrentDataSpace)));
layerInfo->set_pixel_format(decodePixelFormat(getPixelFormat()));
LayerProtoHelper::writeToProto(getColor(), [&]() { return layerInfo->mutable_color(); });
@@ -1912,7 +1901,6 @@
[&]() { return layerInfo->mutable_requested_color(); });
layerInfo->set_flags(state.flags);
- LayerProtoHelper::writeToProto(transform, layerInfo->mutable_transform());
LayerProtoHelper::writeToProto(requestedTransform,
layerInfo->mutable_requested_transform());
@@ -1929,29 +1917,6 @@
} else {
layerInfo->set_z_order_relative_of(-1);
}
-
- auto buffer = mActiveBuffer;
- if (buffer != nullptr) {
- LayerProtoHelper::writeToProto(buffer,
- [&]() { return layerInfo->mutable_active_buffer(); });
- LayerProtoHelper::writeToProto(ui::Transform(mCurrentTransform),
- layerInfo->mutable_buffer_transform());
- }
-
- layerInfo->set_queued_frames(getQueuedFrameCount());
- layerInfo->set_refresh_pending(isBufferLatched());
- layerInfo->set_curr_frame(mCurrentFrameNumber);
- layerInfo->set_effective_scaling_mode(getEffectiveScalingMode());
-
- for (const auto& pendingState : mPendingStates) {
- auto barrierLayer = pendingState.barrierLayer_legacy.promote();
- if (barrierLayer != nullptr) {
- BarrierLayerProto* barrierLayerProto = layerInfo->add_barrier_layer();
- barrierLayerProto->set_id(barrierLayer->sequence);
- barrierLayerProto->set_frame_number(pendingState.frameNumber_legacy);
- }
- }
- LayerProtoHelper::writeToProto(mBounds, [&]() { return layerInfo->mutable_bounds(); });
}
if (traceFlags & SurfaceTracing::TRACE_INPUT) {
@@ -1964,23 +1929,19 @@
for (const auto& entry : state.metadata.mMap) {
(*protoMap)[entry.first] = std::string(entry.second.cbegin(), entry.second.cend());
}
- LayerProtoHelper::writeToProto(mEffectiveTransform,
- layerInfo->mutable_effective_transform());
- LayerProtoHelper::writeToProto(mSourceBounds,
- [&]() { return layerInfo->mutable_source_bounds(); });
- LayerProtoHelper::writeToProto(mScreenBounds,
- [&]() { return layerInfo->mutable_screen_bounds(); });
}
}
-void Layer::writeToProto(LayerProto* layerInfo, const sp<DisplayDevice>& displayDevice,
- uint32_t traceFlags) {
+void Layer::writeToProtoCompositionState(LayerProto* layerInfo,
+ const sp<DisplayDevice>& displayDevice,
+ uint32_t traceFlags) const {
auto outputLayer = findOutputLayerForDisplay(displayDevice);
if (!outputLayer) {
return;
}
- writeToProto(layerInfo, LayerVector::StateSet::Drawing, traceFlags);
+ writeToProtoDrawingState(layerInfo, traceFlags);
+ writeToProtoCommonState(layerInfo, LayerVector::StateSet::Drawing, traceFlags);
const auto& compositionState = outputLayer->getState();
@@ -1998,13 +1959,6 @@
static_cast<int32_t>(compositionState.hwc ? (*compositionState.hwc).hwcCompositionType
: Hwc2::IComposerClient::Composition::CLIENT);
layerInfo->set_hwc_composition_type(compositionType);
-
- if (std::strcmp(getTypeId(), "BufferLayer") == 0 &&
- static_cast<BufferLayer*>(this)->isProtected()) {
- layerInfo->set_is_protected(true);
- } else {
- layerInfo->set_is_protected(false);
- }
}
bool Layer::isRemovedFromCurrentState() const {
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index b693a47..953f25d 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -435,11 +435,21 @@
bool isRemovedFromCurrentState() const;
- void writeToProto(LayerProto* layerInfo, LayerVector::StateSet stateSet,
- uint32_t traceFlags = SurfaceTracing::TRACE_ALL);
-
- void writeToProto(LayerProto* layerInfo, const sp<DisplayDevice>& displayDevice,
- uint32_t traceFlags = SurfaceTracing::TRACE_ALL);
+ // Write states that are modified by the main thread. This includes drawing
+ // state as well as buffer data. This should be called in the main or tracing
+ // thread.
+ void writeToProtoDrawingState(LayerProto* layerInfo,
+ uint32_t traceFlags = SurfaceTracing::TRACE_ALL) const;
+ // Write states that are modified by the main thread. This includes drawing
+ // state as well as buffer data and composition data for layers on the specified
+ // display. This should be called in the main or tracing thread.
+ void writeToProtoCompositionState(LayerProto* layerInfo, const sp<DisplayDevice>& displayDevice,
+ uint32_t traceFlags = SurfaceTracing::TRACE_ALL) const;
+ // Write drawing or current state. If writing current state, the caller should hold the
+ // external mStateLock. If writing drawing state, this function should be called on the
+ // main or tracing thread.
+ void writeToProtoCommonState(LayerProto* layerInfo, LayerVector::StateSet stateSet,
+ uint32_t traceFlags = SurfaceTracing::TRACE_ALL) const;
virtual Geometry getActiveGeometry(const Layer::State& s) const { return s.active_legacy; }
virtual uint32_t getActiveWidth(const Layer::State& s) const { return s.active_legacy.w; }
@@ -451,41 +461,29 @@
return s.activeTransparentRegion_legacy;
}
virtual Rect getCrop(const Layer::State& s) const { return s.crop_legacy; }
-
-protected:
- virtual bool prepareClientLayer(const RenderArea& renderArea, const Region& clip,
- bool useIdentityTransform, Region& clearRegion,
- const bool supportProtectedContent,
- renderengine::LayerSettings& layer);
+ virtual bool needsFiltering(const sp<const DisplayDevice>&) const { return false; }
public:
/*
* compositionengine::LayerFE overrides
*/
+ bool onPreComposition(nsecs_t) override;
void latchCompositionState(compositionengine::LayerFECompositionState&,
bool includeGeometry) const override;
+ std::optional<renderengine::LayerSettings> prepareClientComposition(
+ compositionengine::LayerFE::ClientCompositionTargetSettings&) override;
void onLayerDisplayed(const sp<Fence>& releaseFence) override;
const char* getDebugName() const override;
protected:
void latchGeometry(compositionengine::LayerFECompositionState& outState) const;
+ virtual void latchPerFrameState(compositionengine::LayerFECompositionState& outState) const;
public:
virtual void setDefaultBufferSize(uint32_t /*w*/, uint32_t /*h*/) {}
virtual bool isHdrY410() const { return false; }
- void forceClientComposition(const sp<DisplayDevice>& display);
- bool getForceClientComposition(const sp<DisplayDevice>& display);
- virtual void setPerFrameData(const sp<const DisplayDevice>& display,
- const ui::Transform& transform, const Rect& viewport,
- int32_t supportedPerFrameMetadata,
- const ui::Dataspace targetDataspace) = 0;
-
- // callIntoHwc exists so we can update our local state and call
- // acceptDisplayChanges without unnecessarily updating the device's state
- void setCompositionType(const sp<const DisplayDevice>& display,
- Hwc2::IComposerClient::Composition type);
Hwc2::IComposerClient::Composition getCompositionType(
const sp<const DisplayDevice>& display) const;
bool getClearClientTarget(const sp<const DisplayDevice>& display) const;
@@ -495,12 +493,6 @@
virtual void setTransformHint(uint32_t /*orientation*/) const { }
/*
- * called before composition.
- * returns true if the layer has pending updates.
- */
- virtual bool onPreComposition(nsecs_t refreshStartTime) = 0;
-
- /*
* called after composition.
* returns true if the layer latched a new buffer this frame.
*/
@@ -515,17 +507,6 @@
virtual void releasePendingBuffer(nsecs_t /*dequeueReadyTime*/) { }
/*
- * prepareClientLayer - populates a renderengine::LayerSettings to passed to
- * RenderEngine::drawLayers. Returns true if the layer can be used, and
- * false otherwise.
- */
- bool prepareClientLayer(const RenderArea& renderArea, const Region& clip, Region& clearRegion,
- const bool supportProtectedContent, renderengine::LayerSettings& layer);
- bool prepareClientLayer(const RenderArea& renderArea, bool useIdentityTransform,
- Region& clearRegion, const bool supportProtectedContent,
- renderengine::LayerSettings& layer);
-
- /*
* doTransaction - process the transaction. This is a good place to figure
* out which attributes of the surface have changed.
*/
@@ -561,8 +542,9 @@
* operation, so this should be set only if needed). Typically this is used
* to figure out if the content or size of a surface has changed.
*/
- virtual bool latchBuffer(bool& /*recomputeVisibleRegions*/, nsecs_t /*latchTime*/) {
- return {};
+ virtual bool latchBuffer(bool& /*recomputeVisibleRegions*/, nsecs_t /*latchTime*/,
+ nsecs_t /*expectedPresentTime*/) {
+ return false;
}
virtual bool isBufferLatched() const { return false; }
@@ -607,10 +589,6 @@
virtual int32_t getQueuedFrameCount() const { return 0; }
// -----------------------------------------------------------------------
-
- bool hasHwcLayer(const sp<const DisplayDevice>& displayDevice);
- HWC2::Layer* getHwcLayer(const sp<const DisplayDevice>& displayDevice);
-
inline const State& getDrawingState() const { return mDrawingState; }
inline const State& getCurrentState() const { return mCurrentState; }
inline State& getCurrentState() { return mCurrentState; }
@@ -812,7 +790,7 @@
// this to be called once.
sp<IBinder> getHandle();
const String8& getName() const;
- virtual void notifyAvailableFrames() {}
+ virtual void notifyAvailableFrames(nsecs_t /*expectedPresentTime*/) {}
virtual PixelFormat getPixelFormat() const { return PIXEL_FORMAT_NONE; }
bool getPremultipledAlpha() const;
@@ -832,13 +810,15 @@
bool mPrimaryDisplayOnly = false;
- // these are protected by an external lock
- State mCurrentState;
+ // These are only accessed by the main thread or the tracing thread.
State mDrawingState;
- std::atomic<uint32_t> mTransactionFlags{0};
+ // Store a copy of the pending state so that the drawing thread can access the
+ // states without a lock.
+ Vector<State> mPendingStatesSnapshot;
- // Accessed from main thread and binder threads
- Mutex mPendingStateMutex;
+ // these are protected by an external lock (mStateLock)
+ State mCurrentState;
+ std::atomic<uint32_t> mTransactionFlags{0};
Vector<State> mPendingStates;
// Timestamp history for UIAutomation. Thread safe.
diff --git a/services/surfaceflinger/Scheduler/DispSync.cpp b/services/surfaceflinger/Scheduler/DispSync.cpp
index 83fd42b..ad5eb33 100644
--- a/services/surfaceflinger/Scheduler/DispSync.cpp
+++ b/services/surfaceflinger/Scheduler/DispSync.cpp
@@ -64,7 +64,7 @@
DispSyncThread(const char* name, bool showTraceDetailedInfo)
: mName(name),
mStop(false),
- mModelLocked(false),
+ mModelLocked("DispSync:ModelLocked", false),
mPeriod(0),
mPhase(0),
mReferenceTime(0),
@@ -121,13 +121,11 @@
void lockModel() {
Mutex::Autolock lock(mMutex);
mModelLocked = true;
- ATRACE_INT("DispSync:ModelLocked", mModelLocked);
}
void unlockModel() {
Mutex::Autolock lock(mMutex);
mModelLocked = false;
- ATRACE_INT("DispSync:ModelLocked", mModelLocked);
}
virtual bool threadLoop() {
@@ -431,7 +429,7 @@
const char* const mName;
bool mStop;
- bool mModelLocked;
+ TracedOrdinal<bool> mModelLocked;
nsecs_t mPeriod;
nsecs_t mPhase;
@@ -454,15 +452,14 @@
class ZeroPhaseTracer : public DispSync::Callback {
public:
- ZeroPhaseTracer() : mParity(false) {}
+ ZeroPhaseTracer() : mParity("ZERO_PHASE_VSYNC", false) {}
virtual void onDispSyncEvent(nsecs_t /*when*/) {
mParity = !mParity;
- ATRACE_INT("ZERO_PHASE_VSYNC", mParity ? 1 : 0);
}
private:
- bool mParity;
+ TracedOrdinal<bool> mParity;
};
DispSync::DispSync(const char* name) : mName(name), mRefreshSkipCount(0) {
@@ -668,7 +665,13 @@
nsecs_t durationSum = 0;
nsecs_t minDuration = INT64_MAX;
nsecs_t maxDuration = 0;
- for (size_t i = 1; i < mNumResyncSamples; i++) {
+ // We skip the first 2 samples because the first vsync duration on some
+ // devices may be much more inaccurate than on other devices, e.g. due
+ // to delays in ramping up from a power collapse. By doing so this
+ // actually increases the accuracy of the DispSync model even though
+ // we're effectively relying on fewer sample points.
+ static constexpr size_t numSamplesSkipped = 2;
+ for (size_t i = numSamplesSkipped; i < mNumResyncSamples; i++) {
size_t idx = (mFirstResyncSample + i) % MAX_RESYNC_SAMPLES;
size_t prev = (idx + MAX_RESYNC_SAMPLES - 1) % MAX_RESYNC_SAMPLES;
nsecs_t duration = mResyncSamples[idx] - mResyncSamples[prev];
@@ -679,15 +682,14 @@
// Exclude the min and max from the average
durationSum -= minDuration + maxDuration;
- mPeriod = durationSum / (mNumResyncSamples - 3);
+ mPeriod = durationSum / (mNumResyncSamples - numSamplesSkipped - 2);
ALOGV("[%s] mPeriod = %" PRId64, mName, ns2us(mPeriod));
double sampleAvgX = 0;
double sampleAvgY = 0;
double scale = 2.0 * M_PI / double(mPeriod);
- // Intentionally skip the first sample
- for (size_t i = 1; i < mNumResyncSamples; i++) {
+ for (size_t i = numSamplesSkipped; i < mNumResyncSamples; i++) {
size_t idx = (mFirstResyncSample + i) % MAX_RESYNC_SAMPLES;
nsecs_t sample = mResyncSamples[idx] - mReferenceTime;
double samplePhase = double(sample % mPeriod) * scale;
@@ -695,8 +697,8 @@
sampleAvgY += sin(samplePhase);
}
- sampleAvgX /= double(mNumResyncSamples - 1);
- sampleAvgY /= double(mNumResyncSamples - 1);
+ sampleAvgX /= double(mNumResyncSamples - numSamplesSkipped);
+ sampleAvgY /= double(mNumResyncSamples - numSamplesSkipped);
mPhase = nsecs_t(atan2(sampleAvgY, sampleAvgX) / scale);
diff --git a/services/surfaceflinger/Scheduler/DispSyncSource.cpp b/services/surfaceflinger/Scheduler/DispSyncSource.cpp
index 5faf46e..571c9ca 100644
--- a/services/surfaceflinger/Scheduler/DispSyncSource.cpp
+++ b/services/surfaceflinger/Scheduler/DispSyncSource.cpp
@@ -31,19 +31,16 @@
nsecs_t offsetThresholdForNextVsync, bool traceVsync,
const char* name)
: mName(name),
+ mValue(base::StringPrintf("VSYNC-%s", name), 0),
mTraceVsync(traceVsync),
mVsyncOnLabel(base::StringPrintf("VsyncOn-%s", name)),
- mVsyncEventLabel(base::StringPrintf("VSYNC-%s", name)),
- mVsyncOffsetLabel(base::StringPrintf("VsyncOffset-%s", name)),
- mVsyncNegativeOffsetLabel(base::StringPrintf("VsyncNegativeOffset-%s", name)),
mDispSync(dispSync),
- mPhaseOffset(phaseOffset),
+ mPhaseOffset(base::StringPrintf("VsyncOffset-%s", name), phaseOffset),
mOffsetThresholdForNextVsync(offsetThresholdForNextVsync) {}
void DispSyncSource::setVSyncEnabled(bool enable) {
std::lock_guard lock(mVsyncMutex);
if (enable) {
- tracePhaseOffset();
status_t err = mDispSync->addEventListener(mName, mPhaseOffset,
static_cast<DispSync::Callback*>(this),
mLastCallbackTime);
@@ -83,7 +80,6 @@
}
mPhaseOffset = phaseOffset;
- tracePhaseOffset();
// If we're not enabled, we don't need to mess with the listeners
if (!mEnabled) {
@@ -106,7 +102,6 @@
if (mTraceVsync) {
mValue = (mValue + 1) % 2;
- ATRACE_INT(mVsyncEventLabel.c_str(), mValue);
}
if (callback != nullptr) {
@@ -114,14 +109,4 @@
}
}
-void DispSyncSource::tracePhaseOffset() {
- if (mPhaseOffset > 0) {
- ATRACE_INT(mVsyncOffsetLabel.c_str(), mPhaseOffset);
- ATRACE_INT(mVsyncNegativeOffsetLabel.c_str(), 0);
- } else {
- ATRACE_INT(mVsyncOffsetLabel.c_str(), 0);
- ATRACE_INT(mVsyncNegativeOffsetLabel.c_str(), -mPhaseOffset);
- }
-}
-
} // namespace android
diff --git a/services/surfaceflinger/Scheduler/DispSyncSource.h b/services/surfaceflinger/Scheduler/DispSyncSource.h
index 50560a5..740c8c4 100644
--- a/services/surfaceflinger/Scheduler/DispSyncSource.h
+++ b/services/surfaceflinger/Scheduler/DispSyncSource.h
@@ -20,6 +20,7 @@
#include "DispSync.h"
#include "EventThread.h"
+#include "TracedOrdinal.h"
namespace android {
@@ -39,16 +40,11 @@
// The following method is the implementation of the DispSync::Callback.
virtual void onDispSyncEvent(nsecs_t when);
- void tracePhaseOffset() REQUIRES(mVsyncMutex);
-
const char* const mName;
- int mValue = 0;
+ TracedOrdinal<int> mValue;
const bool mTraceVsync;
const std::string mVsyncOnLabel;
- const std::string mVsyncEventLabel;
- const std::string mVsyncOffsetLabel;
- const std::string mVsyncNegativeOffsetLabel;
nsecs_t mLastCallbackTime GUARDED_BY(mVsyncMutex) = 0;
DispSync* mDispSync;
@@ -57,7 +53,7 @@
VSyncSource::Callback* mCallback GUARDED_BY(mCallbackMutex) = nullptr;
std::mutex mVsyncMutex;
- nsecs_t mPhaseOffset GUARDED_BY(mVsyncMutex);
+ TracedOrdinal<nsecs_t> mPhaseOffset GUARDED_BY(mVsyncMutex);
const nsecs_t mOffsetThresholdForNextVsync;
bool mEnabled GUARDED_BY(mVsyncMutex) = false;
};
diff --git a/services/surfaceflinger/Scheduler/PhaseOffsets.cpp b/services/surfaceflinger/Scheduler/PhaseOffsets.cpp
index 8a2604f..9f8567d 100644
--- a/services/surfaceflinger/Scheduler/PhaseOffsets.cpp
+++ b/services/surfaceflinger/Scheduler/PhaseOffsets.cpp
@@ -18,115 +18,102 @@
#include <cutils/properties.h>
+#include <optional>
+
#include "SurfaceFlingerProperties.h"
-namespace android {
-using namespace android::sysprop;
+namespace {
-namespace scheduler {
+std::optional<int> getProperty(const char* name) {
+ char value[PROPERTY_VALUE_MAX];
+ property_get(name, value, "-1");
+ if (const int i = atoi(value); i != -1) return i;
+ return std::nullopt;
+}
-using RefreshRateType = RefreshRateConfigs::RefreshRateType;
+} // namespace
+
+namespace android::scheduler {
+
PhaseOffsets::~PhaseOffsets() = default;
namespace impl {
+
PhaseOffsets::PhaseOffsets() {
- int64_t vsyncPhaseOffsetNs = vsync_event_phase_offset_ns(1000000);
-
- int64_t sfVsyncPhaseOffsetNs = vsync_sf_event_phase_offset_ns(1000000);
-
- char value[PROPERTY_VALUE_MAX];
- property_get("debug.sf.early_phase_offset_ns", value, "-1");
- const int earlySfOffsetNs = atoi(value);
-
- property_get("debug.sf.early_gl_phase_offset_ns", value, "-1");
- const int earlyGlSfOffsetNs = atoi(value);
-
- property_get("debug.sf.early_app_phase_offset_ns", value, "-1");
- const int earlyAppOffsetNs = atoi(value);
-
- property_get("debug.sf.early_gl_app_phase_offset_ns", value, "-1");
- const int earlyGlAppOffsetNs = atoi(value);
-
- property_get("debug.sf.high_fps_early_phase_offset_ns", value, "-1");
- const int highFpsEarlySfOffsetNs = atoi(value);
-
- property_get("debug.sf.high_fps_early_gl_phase_offset_ns", value, "-1");
- const int highFpsEarlyGlSfOffsetNs = atoi(value);
-
- property_get("debug.sf.high_fps_early_app_phase_offset_ns", value, "-1");
- const int highFpsEarlyAppOffsetNs = atoi(value);
-
- property_get("debug.sf.high_fps_early_gl_app_phase_offset_ns", value, "-1");
- const int highFpsEarlyGlAppOffsetNs = atoi(value);
-
- // TODO(b/122905996): Define these in device.mk.
- property_get("debug.sf.high_fps_late_app_phase_offset_ns", value, "2000000");
- const int highFpsLateAppOffsetNs = atoi(value);
-
- property_get("debug.sf.high_fps_late_sf_phase_offset_ns", value, "1000000");
- const int highFpsLateSfOffsetNs = atoi(value);
-
// Below defines the threshold when an offset is considered to be negative, i.e. targeting
// for the N+2 vsync instead of N+1. This means that:
// For offset < threshold, SF wake up (vsync_duration - offset) before HW vsync.
// For offset >= threshold, SF wake up (2 * vsync_duration - offset) before HW vsync.
- property_get("debug.sf.phase_offset_threshold_for_next_vsync_ns", value, "-1");
- const int phaseOffsetThresholdForNextVsyncNs = atoi(value);
+ const nsecs_t thresholdForNextVsync =
+ getProperty("debug.sf.phase_offset_threshold_for_next_vsync_ns")
+ .value_or(std::numeric_limits<nsecs_t>::max());
- Offsets defaultOffsets;
- Offsets highFpsOffsets;
- defaultOffsets.early = {RefreshRateType::DEFAULT,
- earlySfOffsetNs != -1 ? earlySfOffsetNs : sfVsyncPhaseOffsetNs,
- earlyAppOffsetNs != -1 ? earlyAppOffsetNs : vsyncPhaseOffsetNs};
- defaultOffsets.earlyGl = {RefreshRateType::DEFAULT,
- earlyGlSfOffsetNs != -1 ? earlyGlSfOffsetNs : sfVsyncPhaseOffsetNs,
- earlyGlAppOffsetNs != -1 ? earlyGlAppOffsetNs : vsyncPhaseOffsetNs};
- defaultOffsets.late = {RefreshRateType::DEFAULT, sfVsyncPhaseOffsetNs, vsyncPhaseOffsetNs};
-
- highFpsOffsets.early = {RefreshRateType::PERFORMANCE,
- highFpsEarlySfOffsetNs != -1 ? highFpsEarlySfOffsetNs
- : highFpsLateSfOffsetNs,
- highFpsEarlyAppOffsetNs != -1 ? highFpsEarlyAppOffsetNs
- : highFpsLateAppOffsetNs};
- highFpsOffsets.earlyGl = {RefreshRateType::PERFORMANCE,
- highFpsEarlyGlSfOffsetNs != -1 ? highFpsEarlyGlSfOffsetNs
- : highFpsLateSfOffsetNs,
- highFpsEarlyGlAppOffsetNs != -1 ? highFpsEarlyGlAppOffsetNs
- : highFpsLateAppOffsetNs};
- highFpsOffsets.late = {RefreshRateType::PERFORMANCE, highFpsLateSfOffsetNs,
- highFpsLateAppOffsetNs};
+ const Offsets defaultOffsets = getDefaultOffsets(thresholdForNextVsync);
+ const Offsets highFpsOffsets = getHighFpsOffsets(thresholdForNextVsync);
mOffsets.insert({RefreshRateType::POWER_SAVING, defaultOffsets});
mOffsets.insert({RefreshRateType::DEFAULT, defaultOffsets});
mOffsets.insert({RefreshRateType::PERFORMANCE, highFpsOffsets});
-
- mOffsetThresholdForNextVsync = phaseOffsetThresholdForNextVsyncNs != -1
- ? phaseOffsetThresholdForNextVsyncNs
- : std::numeric_limits<nsecs_t>::max();
}
PhaseOffsets::Offsets PhaseOffsets::getOffsetsForRefreshRate(
- android::scheduler::RefreshRateConfigs::RefreshRateType refreshRateType) const {
+ RefreshRateType refreshRateType) const {
return mOffsets.at(refreshRateType);
}
void PhaseOffsets::dump(std::string& result) const {
- const auto [early, earlyGl, late] = getCurrentOffsets();
+ const auto [early, earlyGl, late, threshold] = getCurrentOffsets();
base::StringAppendF(&result,
" app phase: %9" PRId64 " ns\t SF phase: %9" PRId64 " ns\n"
" early app phase: %9" PRId64 " ns\t early SF phase: %9" PRId64 " ns\n"
- "GL early app phase: %9" PRId64 " ns\tGL early SF phase: %9" PRId64 " ns\n",
- late.app, late.sf, early.app, early.sf, earlyGl.app, earlyGl.sf);
+ "GL early app phase: %9" PRId64 " ns\tGL early SF phase: %9" PRId64 " ns\n"
+ "threshold for next VSYNC: %" PRId64 " ns\n",
+ late.app, late.sf, early.app, early.sf, earlyGl.app, earlyGl.sf, threshold);
}
-nsecs_t PhaseOffsets::getCurrentAppOffset() {
- return getCurrentOffsets().late.app;
+PhaseOffsets::Offsets PhaseOffsets::getDefaultOffsets(nsecs_t thresholdForNextVsync) {
+ const int64_t vsyncPhaseOffsetNs = sysprop::vsync_event_phase_offset_ns(1000000);
+ const int64_t sfVsyncPhaseOffsetNs = sysprop::vsync_sf_event_phase_offset_ns(1000000);
+
+ const auto earlySfOffsetNs = getProperty("debug.sf.early_phase_offset_ns");
+ const auto earlyGlSfOffsetNs = getProperty("debug.sf.early_gl_phase_offset_ns");
+ const auto earlyAppOffsetNs = getProperty("debug.sf.early_app_phase_offset_ns");
+ const auto earlyGlAppOffsetNs = getProperty("debug.sf.early_gl_app_phase_offset_ns");
+
+ return {{RefreshRateType::DEFAULT, earlySfOffsetNs.value_or(sfVsyncPhaseOffsetNs),
+ earlyAppOffsetNs.value_or(vsyncPhaseOffsetNs)},
+
+ {RefreshRateType::DEFAULT, earlyGlSfOffsetNs.value_or(sfVsyncPhaseOffsetNs),
+ earlyGlAppOffsetNs.value_or(vsyncPhaseOffsetNs)},
+
+ {RefreshRateType::DEFAULT, sfVsyncPhaseOffsetNs, vsyncPhaseOffsetNs},
+
+ thresholdForNextVsync};
}
-nsecs_t PhaseOffsets::getCurrentSfOffset() {
- return getCurrentOffsets().late.sf;
+PhaseOffsets::Offsets PhaseOffsets::getHighFpsOffsets(nsecs_t thresholdForNextVsync) {
+ // TODO(b/122905996): Define these in device.mk.
+ const int highFpsLateAppOffsetNs =
+ getProperty("debug.sf.high_fps_late_app_phase_offset_ns").value_or(2000000);
+ const int highFpsLateSfOffsetNs =
+ getProperty("debug.sf.high_fps_late_sf_phase_offset_ns").value_or(1000000);
+
+ const auto highFpsEarlySfOffsetNs = getProperty("debug.sf.high_fps_early_phase_offset_ns");
+ const auto highFpsEarlyGlSfOffsetNs = getProperty("debug.sf.high_fps_early_gl_phase_offset_ns");
+ const auto highFpsEarlyAppOffsetNs = getProperty("debug.sf.high_fps_early_app_phase_offset_ns");
+ const auto highFpsEarlyGlAppOffsetNs =
+ getProperty("debug.sf.high_fps_early_gl_app_phase_offset_ns");
+
+ return {{RefreshRateType::PERFORMANCE, highFpsEarlySfOffsetNs.value_or(highFpsLateSfOffsetNs),
+ highFpsEarlyAppOffsetNs.value_or(highFpsLateAppOffsetNs)},
+
+ {RefreshRateType::PERFORMANCE, highFpsEarlyGlSfOffsetNs.value_or(highFpsLateSfOffsetNs),
+ highFpsEarlyGlAppOffsetNs.value_or(highFpsLateAppOffsetNs)},
+
+ {RefreshRateType::PERFORMANCE, highFpsLateSfOffsetNs, highFpsLateAppOffsetNs},
+
+ thresholdForNextVsync};
}
} // namespace impl
-} // namespace scheduler
-} // namespace android
+} // namespace android::scheduler
diff --git a/services/surfaceflinger/Scheduler/PhaseOffsets.h b/services/surfaceflinger/Scheduler/PhaseOffsets.h
index 2b5c2f1..2c52432 100644
--- a/services/surfaceflinger/Scheduler/PhaseOffsets.h
+++ b/services/surfaceflinger/Scheduler/PhaseOffsets.h
@@ -16,14 +16,12 @@
#pragma once
-#include <cinttypes>
#include <unordered_map>
#include "RefreshRateConfigs.h"
#include "VSyncModulator.h"
-namespace android {
-namespace scheduler {
+namespace android::scheduler {
/*
* This class encapsulates offsets for different refresh rates. Depending
@@ -33,35 +31,33 @@
*/
class PhaseOffsets {
public:
- struct Offsets {
- VSyncModulator::Offsets early;
- VSyncModulator::Offsets earlyGl;
- VSyncModulator::Offsets late;
- };
+ using Offsets = VSyncModulator::OffsetsConfig;
+ using RefreshRateType = RefreshRateConfigs::RefreshRateType;
virtual ~PhaseOffsets();
- virtual nsecs_t getCurrentAppOffset() = 0;
- virtual nsecs_t getCurrentSfOffset() = 0;
- virtual Offsets getOffsetsForRefreshRate(
- RefreshRateConfigs::RefreshRateType refreshRateType) const = 0;
+ nsecs_t getCurrentAppOffset() const { return getCurrentOffsets().late.app; }
+ nsecs_t getCurrentSfOffset() const { return getCurrentOffsets().late.sf; }
+ nsecs_t getOffsetThresholdForNextVsync() const {
+ return getCurrentOffsets().thresholdForNextVsync;
+ }
+
virtual Offsets getCurrentOffsets() const = 0;
- virtual void setRefreshRateType(RefreshRateConfigs::RefreshRateType refreshRateType) = 0;
- virtual nsecs_t getOffsetThresholdForNextVsync() const = 0;
+ virtual Offsets getOffsetsForRefreshRate(RefreshRateType) const = 0;
+
+ virtual void setRefreshRateType(RefreshRateType) = 0;
+
virtual void dump(std::string& result) const = 0;
};
namespace impl {
+
class PhaseOffsets : public scheduler::PhaseOffsets {
public:
PhaseOffsets();
- nsecs_t getCurrentAppOffset() override;
- nsecs_t getCurrentSfOffset() override;
-
// Returns early, early GL, and late offsets for Apps and SF for a given refresh rate.
- Offsets getOffsetsForRefreshRate(
- RefreshRateConfigs::RefreshRateType refreshRateType) const override;
+ Offsets getOffsetsForRefreshRate(RefreshRateType) const override;
// Returns early, early GL, and late offsets for Apps and SF.
Offsets getCurrentOffsets() const override {
@@ -70,23 +66,21 @@
// This function should be called when the device is switching between different
// refresh rates, to properly update the offsets.
- void setRefreshRateType(RefreshRateConfigs::RefreshRateType refreshRateType) override {
+ void setRefreshRateType(RefreshRateType refreshRateType) override {
mRefreshRateType = refreshRateType;
}
- nsecs_t getOffsetThresholdForNextVsync() const override { return mOffsetThresholdForNextVsync; }
-
// Returns current offsets in human friendly format.
void dump(std::string& result) const override;
private:
- std::atomic<RefreshRateConfigs::RefreshRateType> mRefreshRateType =
- RefreshRateConfigs::RefreshRateType::DEFAULT;
+ static Offsets getDefaultOffsets(nsecs_t thresholdForNextVsync);
+ static Offsets getHighFpsOffsets(nsecs_t thresholdForNextVsync);
- std::unordered_map<RefreshRateConfigs::RefreshRateType, Offsets> mOffsets;
- nsecs_t mOffsetThresholdForNextVsync;
+ std::atomic<RefreshRateType> mRefreshRateType = RefreshRateType::DEFAULT;
+
+ std::unordered_map<RefreshRateType, Offsets> mOffsets;
};
-} // namespace impl
-} // namespace scheduler
-} // namespace android
+} // namespace impl
+} // namespace android::scheduler
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 7acb470..952643c 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -89,12 +89,13 @@
if (mSupportKernelTimer) {
mIdleTimer = std::make_unique<scheduler::OneShotTimer>(
std::chrono::milliseconds(mSetIdleTimerMs),
- [this] { resetKernelTimerCallback(); },
- [this] { expiredKernelTimerCallback(); });
+ [this] { kernelIdleTimerCallback(TimerState::Reset); },
+ [this] { kernelIdleTimerCallback(TimerState::Expired); });
} else {
mIdleTimer = std::make_unique<scheduler::OneShotTimer>(
- std::chrono::milliseconds(mSetIdleTimerMs), [this] { resetTimerCallback(); },
- [this] { expiredTimerCallback(); });
+ std::chrono::milliseconds(mSetIdleTimerMs),
+ [this] { idleTimerCallback(TimerState::Reset); },
+ [this] { idleTimerCallback(TimerState::Expired); });
}
mIdleTimer->start();
}
@@ -102,16 +103,17 @@
if (mSetTouchTimerMs > 0) {
// Touch events are coming to SF every 100ms, so the timer needs to be higher than that
mTouchTimer = std::make_unique<scheduler::OneShotTimer>(
- std::chrono::milliseconds(mSetTouchTimerMs), [this] { resetTouchTimerCallback(); },
- [this] { expiredTouchTimerCallback(); });
+ std::chrono::milliseconds(mSetTouchTimerMs),
+ [this] { touchTimerCallback(TimerState::Reset); },
+ [this] { touchTimerCallback(TimerState::Expired); });
mTouchTimer->start();
}
if (mSetDisplayPowerTimerMs > 0) {
mDisplayPowerTimer = std::make_unique<scheduler::OneShotTimer>(
std::chrono::milliseconds(mSetDisplayPowerTimerMs),
- [this] { resetDisplayPowerTimerCallback(); },
- [this] { expiredDisplayPowerTimerCallback(); });
+ [this] { displayPowerTimerCallback(TimerState::Reset); },
+ [this] { displayPowerTimerCallback(TimerState::Expired); });
mDisplayPowerTimer->start();
}
}
@@ -363,23 +365,22 @@
RefreshRateType newRefreshRateType;
{
std::lock_guard<std::mutex> lock(mFeatureStateLock);
- if (mContentRefreshRate == refreshRateRound && mIsHDRContent == isHDR) {
+ if (mFeatures.contentRefreshRate == refreshRateRound && mFeatures.isHDRContent == isHDR) {
return;
}
- mContentRefreshRate = refreshRateRound;
- ATRACE_INT("ContentFPS", mContentRefreshRate);
+ mFeatures.contentRefreshRate = refreshRateRound;
+ ATRACE_INT("ContentFPS", refreshRateRound);
- mIsHDRContent = isHDR;
- ATRACE_INT("ContentHDR", mIsHDRContent);
+ mFeatures.isHDRContent = isHDR;
+ ATRACE_INT("ContentHDR", isHDR);
- mCurrentContentFeatureState = refreshRateRound > 0
- ? ContentFeatureState::CONTENT_DETECTION_ON
- : ContentFeatureState::CONTENT_DETECTION_OFF;
+ mFeatures.contentDetection =
+ refreshRateRound > 0 ? ContentDetectionState::On : ContentDetectionState::Off;
newRefreshRateType = calculateRefreshRateType();
- if (mRefreshRateType == newRefreshRateType) {
+ if (mFeatures.refreshRateType == newRefreshRateType) {
return;
}
- mRefreshRateType = newRefreshRateType;
+ mFeatures.refreshRateType = newRefreshRateType;
}
changeRefreshRate(newRefreshRateType, ConfigEvent::Changed);
}
@@ -433,7 +434,7 @@
void Scheduler::setDisplayPowerState(bool normal) {
{
std::lock_guard<std::mutex> lock(mFeatureStateLock);
- mIsDisplayPowerStateNormal = normal;
+ mFeatures.isDisplayPowerStateNormal = normal;
}
if (mDisplayPowerTimer) {
@@ -445,60 +446,41 @@
mLayerHistory.clearHistory();
}
-void Scheduler::resetTimerCallback() {
- handleTimerStateChanged(&mCurrentIdleTimerState, IdleTimerState::RESET, false);
- ATRACE_INT("ExpiredIdleTimer", 0);
-}
+void Scheduler::kernelIdleTimerCallback(TimerState state) {
+ ATRACE_INT("ExpiredKernelIdleTimer", static_cast<int>(state));
-void Scheduler::resetKernelTimerCallback() {
- ATRACE_INT("ExpiredKernelIdleTimer", 0);
std::lock_guard<std::mutex> lock(mCallbackLock);
- if (mGetVsyncPeriod && mGetCurrentRefreshRateTypeCallback) {
+ if (!mGetCurrentRefreshRateTypeCallback || !mGetVsyncPeriod) return;
+
+ const auto type = mGetCurrentRefreshRateTypeCallback();
+ if (state == TimerState::Reset && type == RefreshRateType::PERFORMANCE) {
// If we're not in performance mode then the kernel timer shouldn't do
// anything, as the refresh rate during DPU power collapse will be the
// same.
- if (mGetCurrentRefreshRateTypeCallback() == Scheduler::RefreshRateType::PERFORMANCE) {
- resyncToHardwareVsync(true, mGetVsyncPeriod());
- }
+ resyncToHardwareVsync(true /* makeAvailable */, mGetVsyncPeriod());
+ } else if (state == TimerState::Expired && type != RefreshRateType::PERFORMANCE) {
+ // Disable HW VSYNC if the timer expired, as we don't need it enabled if
+ // we're not pushing frames, and if we're in PERFORMANCE mode then we'll
+ // need to update the DispSync model anyway.
+ disableHardwareVsync(false /* makeUnavailable */);
}
}
-void Scheduler::expiredTimerCallback() {
- handleTimerStateChanged(&mCurrentIdleTimerState, IdleTimerState::EXPIRED, false);
- ATRACE_INT("ExpiredIdleTimer", 1);
+void Scheduler::idleTimerCallback(TimerState state) {
+ handleTimerStateChanged(&mFeatures.idleTimer, state, false /* eventOnContentDetection */);
+ ATRACE_INT("ExpiredIdleTimer", static_cast<int>(state));
}
-void Scheduler::resetTouchTimerCallback() {
- handleTimerStateChanged(&mCurrentTouchState, TouchState::ACTIVE, true);
- ATRACE_INT("TouchState", 1);
+void Scheduler::touchTimerCallback(TimerState state) {
+ const TouchState touch = state == TimerState::Reset ? TouchState::Active : TouchState::Inactive;
+ handleTimerStateChanged(&mFeatures.touch, touch, true /* eventOnContentDetection */);
+ ATRACE_INT("TouchState", static_cast<int>(touch));
}
-void Scheduler::expiredTouchTimerCallback() {
- handleTimerStateChanged(&mCurrentTouchState, TouchState::INACTIVE, true);
- ATRACE_INT("TouchState", 0);
-}
-
-void Scheduler::resetDisplayPowerTimerCallback() {
- handleTimerStateChanged(&mDisplayPowerTimerState, DisplayPowerTimerState::RESET, true);
- ATRACE_INT("ExpiredDisplayPowerTimer", 0);
-}
-
-void Scheduler::expiredDisplayPowerTimerCallback() {
- handleTimerStateChanged(&mDisplayPowerTimerState, DisplayPowerTimerState::EXPIRED, true);
- ATRACE_INT("ExpiredDisplayPowerTimer", 1);
-}
-
-void Scheduler::expiredKernelTimerCallback() {
- std::lock_guard<std::mutex> lock(mCallbackLock);
- ATRACE_INT("ExpiredKernelIdleTimer", 1);
- if (mGetCurrentRefreshRateTypeCallback) {
- if (mGetCurrentRefreshRateTypeCallback() != Scheduler::RefreshRateType::PERFORMANCE) {
- // Disable HW Vsync if the timer expired, as we don't need it
- // enabled if we're not pushing frames, and if we're in PERFORMANCE
- // mode then we'll need to re-update the DispSync model anyways.
- disableHardwareVsync(false);
- }
- }
+void Scheduler::displayPowerTimerCallback(TimerState state) {
+ handleTimerStateChanged(&mFeatures.displayPowerTimer, state,
+ true /* eventOnContentDetection */);
+ ATRACE_INT("ExpiredDisplayPowerTimer", static_cast<int>(state));
}
std::string Scheduler::doDump() {
@@ -519,12 +501,11 @@
}
*currentState = newState;
newRefreshRateType = calculateRefreshRateType();
- if (mRefreshRateType == newRefreshRateType) {
+ if (mFeatures.refreshRateType == newRefreshRateType) {
return;
}
- mRefreshRateType = newRefreshRateType;
- if (eventOnContentDetection &&
- mCurrentContentFeatureState == ContentFeatureState::CONTENT_DETECTION_ON) {
+ mFeatures.refreshRateType = newRefreshRateType;
+ if (eventOnContentDetection && mFeatures.contentDetection == ContentDetectionState::On) {
event = ConfigEvent::Changed;
}
}
@@ -533,37 +514,38 @@
Scheduler::RefreshRateType Scheduler::calculateRefreshRateType() {
// HDR content is not supported on PERFORMANCE mode
- if (mForceHDRContentToDefaultRefreshRate && mIsHDRContent) {
+ if (mForceHDRContentToDefaultRefreshRate && mFeatures.isHDRContent) {
return RefreshRateType::DEFAULT;
}
// If Display Power is not in normal operation we want to be in performance mode.
// When coming back to normal mode, a grace period is given with DisplayPowerTimer
- if (!mIsDisplayPowerStateNormal || mDisplayPowerTimerState == DisplayPowerTimerState::RESET) {
+ if (!mFeatures.isDisplayPowerStateNormal || mFeatures.displayPowerTimer == TimerState::Reset) {
return RefreshRateType::PERFORMANCE;
}
// As long as touch is active we want to be in performance mode
- if (mCurrentTouchState == TouchState::ACTIVE) {
+ if (mFeatures.touch == TouchState::Active) {
return RefreshRateType::PERFORMANCE;
}
// If timer has expired as it means there is no new content on the screen
- if (mCurrentIdleTimerState == IdleTimerState::EXPIRED) {
+ if (mFeatures.idleTimer == TimerState::Expired) {
return RefreshRateType::DEFAULT;
}
// If content detection is off we choose performance as we don't know the content fps
- if (mCurrentContentFeatureState == ContentFeatureState::CONTENT_DETECTION_OFF) {
+ if (mFeatures.contentDetection == ContentDetectionState::Off) {
return RefreshRateType::PERFORMANCE;
}
// Content detection is on, find the appropriate refresh rate with minimal error
+ const float rate = static_cast<float>(mFeatures.contentRefreshRate);
auto iter = min_element(mRefreshRateConfigs.getRefreshRates().cbegin(),
mRefreshRateConfigs.getRefreshRates().cend(),
- [rate = mContentRefreshRate](const auto& l, const auto& r) -> bool {
- return std::abs(l.second->fps - static_cast<float>(rate)) <
- std::abs(r.second->fps - static_cast<float>(rate));
+ [rate](const auto& lhs, const auto& rhs) -> bool {
+ return std::abs(lhs.second->fps - rate) <
+ std::abs(rhs.second->fps - rate);
});
RefreshRateType currRefreshRateType = iter->first;
@@ -571,11 +553,10 @@
// 90Hz config. However we should still prefer a lower refresh rate if the content doesn't
// align well with both
constexpr float MARGIN = 0.05f;
- float ratio = mRefreshRateConfigs.getRefreshRate(currRefreshRateType)->fps /
- float(mContentRefreshRate);
+ float ratio = mRefreshRateConfigs.getRefreshRate(currRefreshRateType)->fps / rate;
if (std::abs(std::round(ratio) - ratio) > MARGIN) {
while (iter != mRefreshRateConfigs.getRefreshRates().cend()) {
- ratio = iter->second->fps / float(mContentRefreshRate);
+ ratio = iter->second->fps / rate;
if (std::abs(std::round(ratio) - ratio) <= MARGIN) {
currRefreshRateType = iter->first;
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index 123036e..0d9d7aa 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -200,10 +200,9 @@
// In order to make sure that the features don't override themselves, we need a state machine
// to keep track which feature requested the config change.
- enum class ContentFeatureState { CONTENT_DETECTION_ON, CONTENT_DETECTION_OFF };
- enum class IdleTimerState { EXPIRED, RESET };
- enum class TouchState { INACTIVE, ACTIVE };
- enum class DisplayPowerTimerState { EXPIRED, RESET };
+ enum class ContentDetectionState { Off, On };
+ enum class TimerState { Reset, Expired };
+ enum class TouchState { Inactive, Active };
// Creates a connection on the given EventThread and forwards the given callbacks.
sp<EventThreadConnection> createConnectionInternal(EventThread*, ResyncCallback&&,
@@ -212,26 +211,12 @@
nsecs_t calculateAverage() const;
void updateFrameSkipping(const int64_t skipCount);
- // Function that is called when the timer resets.
- void resetTimerCallback();
- // Function that is called when the timer expires.
- void expiredTimerCallback();
- // Function that is called when the timer resets when paired with a display
- // driver timeout in the kernel. This enables hardware vsync when we move
- // out from idle.
- void resetKernelTimerCallback();
- // Function that is called when the timer expires when paired with a display
- // driver timeout in the kernel. This disables hardware vsync when we move
- // into idle.
- void expiredKernelTimerCallback();
- // Function that is called when the touch timer resets.
- void resetTouchTimerCallback();
- // Function that is called when the touch timer expires.
- void expiredTouchTimerCallback();
- // Function that is called when the display power timer resets.
- void resetDisplayPowerTimerCallback();
- // Function that is called when the display power timer expires.
- void expiredDisplayPowerTimerCallback();
+ // Update feature state machine to given state when corresponding timer resets or expires.
+ void kernelIdleTimerCallback(TimerState);
+ void idleTimerCallback(TimerState);
+ void touchTimerCallback(TimerState);
+ void displayPowerTimerCallback(TimerState);
+
// Sets vsync period.
void setVsyncPeriod(const nsecs_t period);
// handles various timer features to change the refresh rate.
@@ -304,16 +289,19 @@
// In order to make sure that the features don't override themselves, we need a state machine
// to keep track which feature requested the config change.
std::mutex mFeatureStateLock;
- ContentFeatureState mCurrentContentFeatureState GUARDED_BY(mFeatureStateLock) =
- ContentFeatureState::CONTENT_DETECTION_OFF;
- IdleTimerState mCurrentIdleTimerState GUARDED_BY(mFeatureStateLock) = IdleTimerState::RESET;
- TouchState mCurrentTouchState GUARDED_BY(mFeatureStateLock) = TouchState::INACTIVE;
- DisplayPowerTimerState mDisplayPowerTimerState GUARDED_BY(mFeatureStateLock) =
- DisplayPowerTimerState::EXPIRED;
- uint32_t mContentRefreshRate GUARDED_BY(mFeatureStateLock);
- RefreshRateType mRefreshRateType GUARDED_BY(mFeatureStateLock);
- bool mIsHDRContent GUARDED_BY(mFeatureStateLock) = false;
- bool mIsDisplayPowerStateNormal GUARDED_BY(mFeatureStateLock) = true;
+
+ struct {
+ ContentDetectionState contentDetection = ContentDetectionState::Off;
+ TimerState idleTimer = TimerState::Reset;
+ TouchState touch = TouchState::Inactive;
+ TimerState displayPowerTimer = TimerState::Expired;
+
+ RefreshRateType refreshRateType = RefreshRateType::DEFAULT;
+ uint32_t contentRefreshRate = 0;
+
+ bool isHDRContent = false;
+ bool isDisplayPowerStateNormal = true;
+ } mFeatures GUARDED_BY(mFeatureStateLock);
const scheduler::RefreshRateConfigs& mRefreshRateConfigs;
diff --git a/services/surfaceflinger/Scheduler/VSyncModulator.cpp b/services/surfaceflinger/Scheduler/VSyncModulator.cpp
index 7a3bf8e..f267c99 100644
--- a/services/surfaceflinger/Scheduler/VSyncModulator.cpp
+++ b/services/surfaceflinger/Scheduler/VSyncModulator.cpp
@@ -24,25 +24,24 @@
#include <cinttypes>
#include <mutex>
-namespace android {
+namespace android::scheduler {
-using RefreshRateType = scheduler::RefreshRateConfigs::RefreshRateType;
-VSyncModulator::VSyncModulator() {
+VSyncModulator::VSyncModulator(Scheduler& scheduler,
+ const sp<Scheduler::ConnectionHandle>& appConnectionHandle,
+ const sp<Scheduler::ConnectionHandle>& sfConnectionHandle,
+ const OffsetsConfig& config)
+ : mScheduler(scheduler),
+ mAppConnectionHandle(appConnectionHandle),
+ mSfConnectionHandle(sfConnectionHandle),
+ mOffsetsConfig(config) {
char value[PROPERTY_VALUE_MAX];
property_get("debug.sf.vsync_trace_detailed_info", value, "0");
mTraceDetailedInfo = atoi(value);
- // Populate the offset map with some default offsets.
- const Offsets defaultOffsets = {RefreshRateType::DEFAULT, 0, 0};
- setPhaseOffsets(defaultOffsets, defaultOffsets, defaultOffsets, 0);
}
-void VSyncModulator::setPhaseOffsets(Offsets early, Offsets earlyGl, Offsets late,
- nsecs_t thresholdForNextVsync) {
+void VSyncModulator::setPhaseOffsets(const OffsetsConfig& config) {
std::lock_guard<std::mutex> lock(mMutex);
- mOffsetMap.insert_or_assign(OffsetType::Early, early);
- mOffsetMap.insert_or_assign(OffsetType::EarlyGl, earlyGl);
- mOffsetMap.insert_or_assign(OffsetType::Late, late);
- mThresholdForNextVsync = thresholdForNextVsync;
+ mOffsetsConfig = config;
updateOffsetsLocked();
}
@@ -100,25 +99,21 @@
}
}
-VSyncModulator::Offsets VSyncModulator::getOffsets() {
+VSyncModulator::Offsets VSyncModulator::getOffsets() const {
std::lock_guard<std::mutex> lock(mMutex);
return mOffsets;
}
-VSyncModulator::Offsets VSyncModulator::getNextOffsets() {
- return mOffsetMap.at(getNextOffsetType());
-}
-
-VSyncModulator::OffsetType VSyncModulator::getNextOffsetType() {
+const VSyncModulator::Offsets& VSyncModulator::getNextOffsets() const {
// Early offsets are used if we're in the middle of a refresh rate
// change, or if we recently begin a transaction.
if (mTransactionStart == Scheduler::TransactionStart::EARLY || mRemainingEarlyFrameCount > 0 ||
mRefreshRateChangePending) {
- return OffsetType::Early;
+ return mOffsetsConfig.early;
} else if (mRemainingRenderEngineUsageCount > 0) {
- return OffsetType::EarlyGl;
+ return mOffsetsConfig.earlyGl;
} else {
- return OffsetType::Late;
+ return mOffsetsConfig.late;
}
}
@@ -128,37 +123,29 @@
}
void VSyncModulator::updateOffsetsLocked() {
- const Offsets desired = getNextOffsets();
+ const Offsets& offsets = getNextOffsets();
- if (mSfConnectionHandle != nullptr) {
- mScheduler->setPhaseOffset(mSfConnectionHandle, desired.sf);
- }
+ mScheduler.setPhaseOffset(mSfConnectionHandle, offsets.sf);
+ mScheduler.setPhaseOffset(mAppConnectionHandle, offsets.app);
- if (mAppConnectionHandle != nullptr) {
- mScheduler->setPhaseOffset(mAppConnectionHandle, desired.app);
- }
+ mOffsets = offsets;
- flushOffsets();
-}
-
-void VSyncModulator::flushOffsets() {
- OffsetType type = getNextOffsetType();
- mOffsets = mOffsetMap.at(type);
if (!mTraceDetailedInfo) {
return;
}
- ATRACE_INT("Vsync-EarlyOffsetsOn",
- mOffsets.fpsMode == RefreshRateType::DEFAULT && type == OffsetType::Early);
- ATRACE_INT("Vsync-EarlyGLOffsetsOn",
- mOffsets.fpsMode == RefreshRateType::DEFAULT && type == OffsetType::EarlyGl);
- ATRACE_INT("Vsync-LateOffsetsOn",
- mOffsets.fpsMode == RefreshRateType::DEFAULT && type == OffsetType::Late);
- ATRACE_INT("Vsync-HighFpsEarlyOffsetsOn",
- mOffsets.fpsMode == RefreshRateType::PERFORMANCE && type == OffsetType::Early);
- ATRACE_INT("Vsync-HighFpsEarlyGLOffsetsOn",
- mOffsets.fpsMode == RefreshRateType::PERFORMANCE && type == OffsetType::EarlyGl);
- ATRACE_INT("Vsync-HighFpsLateOffsetsOn",
- mOffsets.fpsMode == RefreshRateType::PERFORMANCE && type == OffsetType::Late);
+
+ const bool isDefault = mOffsets.fpsMode == RefreshRateType::DEFAULT;
+ const bool isPerformance = mOffsets.fpsMode == RefreshRateType::PERFORMANCE;
+ const bool isEarly = &offsets == &mOffsetsConfig.early;
+ const bool isEarlyGl = &offsets == &mOffsetsConfig.earlyGl;
+ const bool isLate = &offsets == &mOffsetsConfig.late;
+
+ ATRACE_INT("Vsync-EarlyOffsetsOn", isDefault && isEarly);
+ ATRACE_INT("Vsync-EarlyGLOffsetsOn", isDefault && isEarlyGl);
+ ATRACE_INT("Vsync-LateOffsetsOn", isDefault && isLate);
+ ATRACE_INT("Vsync-HighFpsEarlyOffsetsOn", isPerformance && isEarly);
+ ATRACE_INT("Vsync-HighFpsEarlyGLOffsetsOn", isPerformance && isEarlyGl);
+ ATRACE_INT("Vsync-HighFpsLateOffsetsOn", isPerformance && isLate);
}
-} // namespace android
+} // namespace android::scheduler
diff --git a/services/surfaceflinger/Scheduler/VSyncModulator.h b/services/surfaceflinger/Scheduler/VSyncModulator.h
index ddbd221..636c8c8 100644
--- a/services/surfaceflinger/Scheduler/VSyncModulator.h
+++ b/services/surfaceflinger/Scheduler/VSyncModulator.h
@@ -16,12 +16,11 @@
#pragma once
-#include <cinttypes>
#include <mutex>
#include "Scheduler.h"
-namespace android {
+namespace android::scheduler {
/*
* Modulates the vsync-offsets depending on current SurfaceFlinger state.
@@ -31,51 +30,36 @@
// Number of frames we'll keep the early phase offsets once they are activated for a
// transaction. This acts as a low-pass filter in case the client isn't quick enough in
// sending new transactions.
- const int MIN_EARLY_FRAME_COUNT_TRANSACTION = 2;
+ static constexpr int MIN_EARLY_FRAME_COUNT_TRANSACTION = 2;
// Number of frames we'll keep the early gl phase offsets once they are activated.
// This acts as a low-pass filter to avoid scenarios where we rapidly
// switch in and out of gl composition.
- const int MIN_EARLY_GL_FRAME_COUNT_TRANSACTION = 2;
+ static constexpr int MIN_EARLY_GL_FRAME_COUNT_TRANSACTION = 2;
+
+ using RefreshRateType = RefreshRateConfigs::RefreshRateType;
public:
- VSyncModulator();
-
// Wrapper for a collection of surfaceflinger/app offsets for a particular
- // configuration .
+ // configuration.
struct Offsets {
- scheduler::RefreshRateConfigs::RefreshRateType fpsMode;
+ RefreshRateType fpsMode;
nsecs_t sf;
nsecs_t app;
};
- enum class OffsetType {
- Early,
- EarlyGl,
- Late,
+ struct OffsetsConfig {
+ Offsets early; // For transactions with the eEarlyWakeup flag.
+ Offsets earlyGl; // As above but while compositing with GL.
+ Offsets late; // Default.
+
+ nsecs_t thresholdForNextVsync;
};
- // Sets the phase offsets
- //
- // sfEarly: The phase offset when waking up SF early, which happens when marking a transaction
- // as early. May be the same as late, in which case we don't shift offsets.
- // sfEarlyGl: Like sfEarly, but only if we used GL composition. If we use both GL composition
- // and the transaction was marked as early, we'll use sfEarly.
- // sfLate: The regular SF vsync phase offset.
- // appEarly: Like sfEarly, but for the app-vsync
- // appEarlyGl: Like sfEarlyGl, but for the app-vsync.
- // appLate: The regular app vsync phase offset.
- void setPhaseOffsets(Offsets early, Offsets earlyGl, Offsets late,
- nsecs_t thresholdForNextVsync) EXCLUDES(mMutex);
+ VSyncModulator(Scheduler&, const sp<Scheduler::ConnectionHandle>& appConnectionHandle,
+ const sp<Scheduler::ConnectionHandle>& sfConnectionHandle, const OffsetsConfig&);
- // Sets the scheduler and vsync connection handlers.
- void setSchedulerAndHandles(Scheduler* scheduler,
- Scheduler::ConnectionHandle* appConnectionHandle,
- Scheduler::ConnectionHandle* sfConnectionHandle) {
- mScheduler = scheduler;
- mAppConnectionHandle = appConnectionHandle;
- mSfConnectionHandle = sfConnectionHandle;
- }
+ void setPhaseOffsets(const OffsetsConfig&) EXCLUDES(mMutex);
// Signals that a transaction has started, and changes offsets accordingly.
void setTransactionStart(Scheduler::TransactionStart transactionStart);
@@ -98,28 +82,23 @@
void onRefreshed(bool usedRenderEngine);
// Returns the offsets that we are currently using
- Offsets getOffsets() EXCLUDES(mMutex);
+ Offsets getOffsets() const EXCLUDES(mMutex);
private:
// Returns the next offsets that we should be using
- Offsets getNextOffsets() REQUIRES(mMutex);
- // Returns the next offset type that we should use.
- OffsetType getNextOffsetType();
+ const Offsets& getNextOffsets() const REQUIRES(mMutex);
// Updates offsets and persists them into the scheduler framework.
void updateOffsets() EXCLUDES(mMutex);
void updateOffsetsLocked() REQUIRES(mMutex);
- // Updates the internal offsets and offset type.
- void flushOffsets() REQUIRES(mMutex);
+
+ Scheduler& mScheduler;
+ const sp<Scheduler::ConnectionHandle> mAppConnectionHandle;
+ const sp<Scheduler::ConnectionHandle> mSfConnectionHandle;
mutable std::mutex mMutex;
- std::unordered_map<OffsetType, Offsets> mOffsetMap GUARDED_BY(mMutex);
- nsecs_t mThresholdForNextVsync;
+ OffsetsConfig mOffsetsConfig GUARDED_BY(mMutex);
- Scheduler* mScheduler = nullptr;
- Scheduler::ConnectionHandle* mAppConnectionHandle = nullptr;
- Scheduler::ConnectionHandle* mSfConnectionHandle = nullptr;
-
- Offsets mOffsets GUARDED_BY(mMutex) = {Scheduler::RefreshRateType::DEFAULT, 0, 0};
+ Offsets mOffsets GUARDED_BY(mMutex){mOffsetsConfig.late};
std::atomic<Scheduler::TransactionStart> mTransactionStart =
Scheduler::TransactionStart::NORMAL;
@@ -130,4 +109,4 @@
bool mTraceDetailedInfo = false;
};
-} // namespace android
+} // namespace android::scheduler
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 5b82556..488b9ef 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -38,6 +38,7 @@
#include <binder/PermissionCache.h>
#include <compositionengine/CompositionEngine.h>
+#include <compositionengine/CompositionRefreshArgs.h>
#include <compositionengine/Display.h>
#include <compositionengine/DisplayColorProfile.h>
#include <compositionengine/Layer.h>
@@ -48,6 +49,8 @@
#include <compositionengine/impl/OutputLayerCompositionState.h>
#include <dvr/vr_flinger.h>
#include <gui/BufferQueue.h>
+#include <gui/DebugEGLImageTracker.h>
+
#include <gui/GuiConfig.h>
#include <gui/IDisplayEventConnection.h>
#include <gui/IProducerListener.h>
@@ -160,28 +163,6 @@
return false;
}
-bool isHdrColorMode(const ColorMode colorMode) {
- switch (colorMode) {
- case ColorMode::BT2100_PQ:
- case ColorMode::BT2100_HLG:
- return true;
- case ColorMode::DISPLAY_P3:
- case ColorMode::ADOBE_RGB:
- case ColorMode::DCI_P3:
- case ColorMode::BT2020:
- case ColorMode::DISPLAY_BT2020:
- case ColorMode::NATIVE:
- case ColorMode::STANDARD_BT601_625:
- case ColorMode::STANDARD_BT601_625_UNADJUSTED:
- case ColorMode::STANDARD_BT601_525:
- case ColorMode::STANDARD_BT601_525_UNADJUSTED:
- case ColorMode::STANDARD_BT709:
- case ColorMode::SRGB:
- return false;
- }
- return false;
-}
-
ui::Transform::orientation_flags fromSurfaceComposerRotation(ISurfaceComposer::Rotation rotation) {
switch (rotation) {
case ISurfaceComposer::eRotateNone:
@@ -274,11 +255,11 @@
SurfaceFlinger::SurfaceFlinger(Factory& factory, SkipInitializationTag)
: mFactory(factory),
- mPhaseOffsets(mFactory.createPhaseOffsets()),
mInterceptor(mFactory.createSurfaceInterceptor(this)),
mTimeStats(mFactory.createTimeStats()),
mEventQueue(mFactory.createMessageQueue()),
- mCompositionEngine(mFactory.createCompositionEngine()) {}
+ mCompositionEngine(mFactory.createCompositionEngine()),
+ mPhaseOffsets(mFactory.createPhaseOffsets()) {}
SurfaceFlinger::SurfaceFlinger(Factory& factory) : SurfaceFlinger(factory, SkipInitialization) {
ALOGI("SurfaceFlinger is starting");
@@ -356,6 +337,11 @@
mPropagateBackpressure = !atoi(value);
ALOGI_IF(!mPropagateBackpressure, "Disabling backpressure propagation");
+ property_get("debug.sf.enable_gl_backpressure", value, "0");
+ mPropagateBackpressureClientComposition = atoi(value);
+ ALOGI_IF(mPropagateBackpressureClientComposition,
+ "Enabling backpressure propagation for Client Composition");
+
property_get("debug.sf.enable_hwc_vds", value, "0");
mUseHwcVirtualDisplays = atoi(value);
ALOGI_IF(mUseHwcVirtualDisplays, "Enabling HWC virtual displays");
@@ -379,10 +365,6 @@
property_get("debug.sf.luma_sampling", value, "1");
mLumaSampling = atoi(value);
- const auto [early, gl, late] = mPhaseOffsets->getCurrentOffsets();
- mVsyncModulator.setPhaseOffsets(early, gl, late,
- mPhaseOffsets->getOffsetThresholdForNextVsync());
-
// We should be reading 'persist.sys.sf.color_saturation' here
// but since /data may be encrypted, we need to wait until after vold
// comes online to attempt to read the property. The property is
@@ -609,7 +591,7 @@
ALOGI( "SurfaceFlinger's main thread ready to run. "
"Initializing graphics H/W...");
- ALOGI("Phase offset NS: %" PRId64 "", mPhaseOffsets->getCurrentAppOffset());
+ ALOGI("Phase offset: %" PRId64 " ns", mPhaseOffsets->getCurrentAppOffset());
Mutex::Autolock _l(mStateLock);
// start the EventThread
@@ -620,20 +602,21 @@
mScheduler->makeResyncCallback(std::bind(&SurfaceFlinger::getVsyncPeriod, this));
mAppConnectionHandle =
- mScheduler->createConnection("app", mVsyncModulator.getOffsets().app,
+ mScheduler->createConnection("app", mPhaseOffsets->getCurrentAppOffset(),
mPhaseOffsets->getOffsetThresholdForNextVsync(),
resyncCallback,
impl::EventThread::InterceptVSyncsCallback());
mSfConnectionHandle =
- mScheduler->createConnection("sf", mVsyncModulator.getOffsets().sf,
+ mScheduler->createConnection("sf", mPhaseOffsets->getCurrentSfOffset(),
mPhaseOffsets->getOffsetThresholdForNextVsync(),
resyncCallback, [this](nsecs_t timestamp) {
mInterceptor->saveVSyncEvent(timestamp);
});
mEventQueue->setEventConnection(mScheduler->getEventConnection(mSfConnectionHandle));
- mVsyncModulator.setSchedulerAndHandles(mScheduler.get(), mAppConnectionHandle.get(),
- mSfConnectionHandle.get());
+
+ mVSyncModulator.emplace(*mScheduler, mAppConnectionHandle, mSfConnectionHandle,
+ mPhaseOffsets->getCurrentOffsets());
mRegionSamplingThread =
new RegionSamplingThread(*this, *mScheduler,
@@ -696,7 +679,11 @@
// set initial conditions (e.g. unblank default device)
initializeDisplays();
- getRenderEngine().primeCache();
+ char primeShaderCache[PROPERTY_VALUE_MAX];
+ property_get("service.sf.prime_shader_cache", primeShaderCache, "1");
+ if (atoi(primeShaderCache)) {
+ getRenderEngine().primeCache();
+ }
// Inform native graphics APIs whether the present timestamp is supported:
@@ -962,14 +949,11 @@
mScheduler->resyncToHardwareVsync(true, getVsyncPeriod());
// As we called to set period, we will call to onRefreshRateChangeCompleted once
// DispSync model is locked.
- mVsyncModulator.onRefreshRateChangeInitiated();
+ mVSyncModulator->onRefreshRateChangeInitiated();
mPhaseOffsets->setRefreshRateType(info.type);
- const auto [early, gl, late] = mPhaseOffsets->getCurrentOffsets();
- mVsyncModulator.setPhaseOffsets(early, gl, late,
- mPhaseOffsets->getOffsetThresholdForNextVsync());
+ mVSyncModulator->setPhaseOffsets(mPhaseOffsets->getCurrentOffsets());
}
mDesiredActiveConfigChanged = true;
- ATRACE_INT("DesiredActiveConfigChanged", mDesiredActiveConfigChanged);
if (mRefreshRateOverlay) {
mRefreshRateOverlay->changeRefreshRate(mDesiredActiveConfig.type);
@@ -999,9 +983,7 @@
display->setActiveConfig(mUpcomingActiveConfig.configId);
mPhaseOffsets->setRefreshRateType(mUpcomingActiveConfig.type);
- const auto [early, gl, late] = mPhaseOffsets->getCurrentOffsets();
- mVsyncModulator.setPhaseOffsets(early, gl, late,
- mPhaseOffsets->getOffsetThresholdForNextVsync());
+ mVSyncModulator->setPhaseOffsets(mPhaseOffsets->getCurrentOffsets());
ATRACE_INT("ActiveConfigMode", mUpcomingActiveConfig.configId);
if (mUpcomingActiveConfig.event != Scheduler::ConfigEvent::None) {
@@ -1014,13 +996,10 @@
std::lock_guard<std::mutex> lock(mActiveConfigLock);
mDesiredActiveConfig.event = Scheduler::ConfigEvent::None;
mDesiredActiveConfigChanged = false;
- ATRACE_INT("DesiredActiveConfigChanged", mDesiredActiveConfigChanged);
mScheduler->resyncToHardwareVsync(true, getVsyncPeriod());
mPhaseOffsets->setRefreshRateType(mUpcomingActiveConfig.type);
- const auto [early, gl, late] = mPhaseOffsets->getCurrentOffsets();
- mVsyncModulator.setPhaseOffsets(early, gl, late,
- mPhaseOffsets->getOffsetThresholdForNextVsync());
+ mVSyncModulator->setPhaseOffsets(mPhaseOffsets->getCurrentOffsets());
}
bool SurfaceFlinger::performSetActiveConfig() {
@@ -1153,7 +1132,8 @@
decodeColorMode(mode).c_str(), mode);
} else {
display->getCompositionDisplay()->setColorMode(mode, Dataspace::UNKNOWN,
- RenderIntent::COLORIMETRIC);
+ RenderIntent::COLORIMETRIC,
+ Dataspace::UNKNOWN);
}
}));
@@ -1487,7 +1467,7 @@
bool periodFlushed = false;
mScheduler->addResyncSample(timestamp, &periodFlushed);
if (periodFlushed) {
- mVsyncModulator.onRefreshRateChangeCompleted();
+ mVSyncModulator->onRefreshRateChangeCompleted();
}
}
@@ -1679,35 +1659,39 @@
// woken up before the actual vsync but targeting the next vsync, we need to check
// fence N-2
const sp<Fence>& fence =
- mVsyncModulator.getOffsets().sf < mPhaseOffsets->getOffsetThresholdForNextVsync()
+ mVSyncModulator->getOffsets().sf < mPhaseOffsets->getOffsetThresholdForNextVsync()
? mPreviousPresentFences[0]
: mPreviousPresentFences[1];
return fence != Fence::NO_FENCE && (fence->getStatus() == Fence::Status::Unsignaled);
}
-nsecs_t SurfaceFlinger::getExpectedPresentTime() NO_THREAD_SAFETY_ANALYSIS {
+void SurfaceFlinger::populateExpectedPresentTime() {
DisplayStatInfo stats;
mScheduler->getDisplayStatInfo(&stats);
const nsecs_t presentTime = mScheduler->getDispSyncExpectedPresentTime();
// Inflate the expected present time if we're targetting the next vsync.
- const nsecs_t correctedTime =
- mVsyncModulator.getOffsets().sf < mPhaseOffsets->getOffsetThresholdForNextVsync()
- ? presentTime
- : presentTime + stats.vsyncPeriod;
- return correctedTime;
+ mExpectedPresentTime.store(mVSyncModulator->getOffsets().sf <
+ mPhaseOffsets->getOffsetThresholdForNextVsync()
+ ? presentTime
+ : presentTime + stats.vsyncPeriod);
}
void SurfaceFlinger::onMessageReceived(int32_t what) NO_THREAD_SAFETY_ANALYSIS {
ATRACE_CALL();
switch (what) {
case MessageQueue::INVALIDATE: {
- bool frameMissed = previousFrameMissed();
- bool hwcFrameMissed = mHadDeviceComposition && frameMissed;
- bool gpuFrameMissed = mHadClientComposition && frameMissed;
- ATRACE_INT("FrameMissed", static_cast<int>(frameMissed));
- ATRACE_INT("HwcFrameMissed", static_cast<int>(hwcFrameMissed));
- ATRACE_INT("GpuFrameMissed", static_cast<int>(gpuFrameMissed));
+ // calculate the expected present time once and use the cached
+ // value throughout this frame to make sure all layers are
+ // seeing this same value.
+ populateExpectedPresentTime();
+
+ const TracedOrdinal<bool> frameMissed = {"FrameMissed", previousFrameMissed()};
+ const TracedOrdinal<bool> hwcFrameMissed = {"HwcFrameMissed",
+ mHadDeviceComposition && frameMissed};
+ const TracedOrdinal<bool> gpuFrameMissed = {"GpuFrameMissed",
+ mHadClientComposition && frameMissed};
+
if (frameMissed) {
mFrameMissedCount++;
mTimeStats->incrementMissedFrames();
@@ -1731,9 +1715,9 @@
break;
}
- // For now, only propagate backpressure when missing a hwc frame.
- if (hwcFrameMissed && !gpuFrameMissed) {
- if (mPropagateBackpressure) {
+ if (frameMissed && mPropagateBackpressure) {
+ if ((hwcFrameMissed && !gpuFrameMissed) ||
+ mPropagateBackpressureClientComposition) {
signalLayerUpdate();
break;
}
@@ -1793,15 +1777,25 @@
mRefreshPending = false;
+ compositionengine::CompositionRefreshArgs refreshArgs;
+ for (const auto& [_, display] : mDisplays) {
+ refreshArgs.outputs.push_back(display->getCompositionDisplay());
+ }
+ mDrawingState.traverseInZOrder([&refreshArgs](Layer* layer) {
+ auto compositionLayer = layer->getCompositionLayer();
+ if (compositionLayer) refreshArgs.layers.push_back(compositionLayer);
+ });
+
const bool repaintEverything = mRepaintEverything.exchange(false);
- preComposition();
+ mCompositionEngine->preComposition(refreshArgs);
rebuildLayerStacks();
calculateWorkingSet();
- for (const auto& [token, display] : mDisplays) {
- beginFrame(display);
- prepareFrame(display);
- doDebugFlashRegions(display, repaintEverything);
- doComposition(display, repaintEverything);
+ for (const auto& [token, displayDevice] : mDisplays) {
+ auto display = displayDevice->getCompositionDisplay();
+ display->beginFrame();
+ display->prepareFrame();
+ doDebugFlashRegions(displayDevice, repaintEverything);
+ doComposition(displayDevice, repaintEverything);
}
logLayerStats();
@@ -1809,18 +1803,18 @@
postFrame();
postComposition();
- mHadClientComposition = false;
- mHadDeviceComposition = false;
- for (const auto& [token, displayDevice] : mDisplays) {
- auto display = displayDevice->getCompositionDisplay();
- const auto displayId = display->getId();
- mHadClientComposition =
- mHadClientComposition || getHwComposer().hasClientComposition(displayId);
- mHadDeviceComposition =
- mHadDeviceComposition || getHwComposer().hasDeviceComposition(displayId);
- }
+ mHadClientComposition =
+ std::any_of(mDisplays.cbegin(), mDisplays.cend(), [](const auto& tokenDisplayPair) {
+ auto& displayDevice = tokenDisplayPair.second;
+ return displayDevice->getCompositionDisplay()->getState().usesClientComposition;
+ });
+ mHadDeviceComposition =
+ std::any_of(mDisplays.cbegin(), mDisplays.cend(), [](const auto& tokenDisplayPair) {
+ auto& displayDevice = tokenDisplayPair.second;
+ return displayDevice->getCompositionDisplay()->getState().usesDeviceComposition;
+ });
- mVsyncModulator.onRefreshed(mHadClientComposition);
+ mVSyncModulator->onRefreshed(mHadClientComposition);
mLayersWithQueuedFrames.clear();
if (mVisibleRegionsDirty) {
@@ -1829,6 +1823,10 @@
mTracing.notify("visibleRegionsDirty");
}
}
+
+ if (mCompositionEngine->needsAnotherUpdate()) {
+ signalLayerUpdate();
+ }
}
@@ -1853,104 +1851,80 @@
ATRACE_CALL();
ALOGV(__FUNCTION__);
- // build the h/w work list
- if (CC_UNLIKELY(mGeometryInvalid)) {
- mGeometryInvalid = false;
+ const bool updatingGeometryThisFrame = mGeometryInvalid;
+ mGeometryInvalid = false;
+
+ {
+ // Use a map so that we latch the state of each front-end layer once.
+ std::unordered_map<compositionengine::LayerFE*, compositionengine::LayerFECompositionState*>
+ uniqueVisibleLayers;
+
+ // Figure out which frontend layers are being composed, and build the unique
+ // set of them (and the corresponding composition layer)
for (const auto& [token, displayDevice] : mDisplays) {
auto display = displayDevice->getCompositionDisplay();
+ for (auto& layer : display->getOutputLayersOrderedByZ()) {
+ uniqueVisibleLayers.insert(std::make_pair(&layer->getLayerFE(),
+ &layer->getLayer().editState().frontEnd));
+ }
+ }
+ // Update the composition state from each front-end layer.
+ for (auto& [layerFE, state] : uniqueVisibleLayers) {
+ layerFE->latchCompositionState(*state, updatingGeometryThisFrame);
+ }
+ }
+
+ if (CC_UNLIKELY(updatingGeometryThisFrame)) {
+ for (const auto& [token, displayDevice] : mDisplays) {
+ auto display = displayDevice->getCompositionDisplay();
uint32_t zOrder = 0;
for (auto& layer : display->getOutputLayersOrderedByZ()) {
- auto& compositionState = layer->editState();
- compositionState.forceClientComposition = false;
- if (!compositionState.hwc || mDebugDisableHWC || mDebugRegion) {
- compositionState.forceClientComposition = true;
- }
-
- // The output Z order is set here based on a simple counter.
- compositionState.z = zOrder++;
-
- // Update the display independent composition state. This goes
- // to the general composition layer state structure.
- // TODO: Do this once per compositionengine::CompositionLayer.
- layer->getLayerFE().latchCompositionState(layer->getLayer().editState().frontEnd,
- true);
-
- // Recalculate the geometry state of the output layer.
- layer->updateCompositionState(true);
-
- // Write the updated geometry state to the HWC
- layer->writeStateToHWC(true);
+ // Assign a simple Z order sequence to each visible layer.
+ layer->editState().z = zOrder++;
}
}
}
- // Set the per-frame data
+ // Determine the color configuration of each output
for (const auto& [token, displayDevice] : mDisplays) {
auto display = displayDevice->getCompositionDisplay();
- const auto displayId = display->getId();
- if (!displayId) {
- continue;
- }
- auto* profile = display->getDisplayColorProfile();
- if (mDrawingState.colorMatrixChanged) {
+ ColorMode colorMode = ColorMode::NATIVE;
+ Dataspace dataspace = Dataspace::UNKNOWN;
+ RenderIntent renderIntent = RenderIntent::COLORIMETRIC;
+ if (useColorManagement) {
+ pickColorMode(displayDevice, &colorMode, &dataspace, &renderIntent);
+ }
+ display->setColorMode(colorMode, dataspace, renderIntent, mColorSpaceAgnosticDataspace);
+ }
+
+ for (const auto& [token, displayDevice] : mDisplays) {
+ auto display = displayDevice->getCompositionDisplay();
+
+ for (auto& layer : display->getOutputLayersOrderedByZ()) {
+ // Update the composition state of the output layer, as needed
+ // recomputing it from the state given by the front-end layer.
+ layer->updateCompositionState(updatingGeometryThisFrame);
+ }
+ }
+
+ for (const auto& [token, displayDevice] : mDisplays) {
+ auto display = displayDevice->getCompositionDisplay();
+
+ for (auto& layer : display->getOutputLayersOrderedByZ()) {
+ // Send the updated state to the HWC, if appropriate.
+ layer->writeStateToHWC(updatingGeometryThisFrame);
+ }
+ }
+
+ if (CC_UNLIKELY(mDrawingState.colorMatrixChanged)) {
+ for (const auto& [token, displayDevice] : mDisplays) {
+ auto display = displayDevice->getCompositionDisplay();
display->setColorTransform(mDrawingState.colorMatrix);
}
- Dataspace targetDataspace = Dataspace::UNKNOWN;
- if (useColorManagement) {
- ColorMode colorMode;
- RenderIntent renderIntent;
- pickColorMode(displayDevice, &colorMode, &targetDataspace, &renderIntent);
- display->setColorMode(colorMode, targetDataspace, renderIntent);
-
- if (isHdrColorMode(colorMode)) {
- targetDataspace = Dataspace::UNKNOWN;
- } else if (mColorSpaceAgnosticDataspace != Dataspace::UNKNOWN) {
- targetDataspace = mColorSpaceAgnosticDataspace;
- }
- }
-
- for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) {
- if (layer->isHdrY410()) {
- layer->forceClientComposition(displayDevice);
- } else if ((layer->getDataSpace() == Dataspace::BT2020_PQ ||
- layer->getDataSpace() == Dataspace::BT2020_ITU_PQ) &&
- !profile->hasHDR10Support()) {
- layer->forceClientComposition(displayDevice);
- } else if ((layer->getDataSpace() == Dataspace::BT2020_HLG ||
- layer->getDataSpace() == Dataspace::BT2020_ITU_HLG) &&
- !profile->hasHLGSupport()) {
- layer->forceClientComposition(displayDevice);
- }
-
- if (layer->getRoundedCornerState().radius > 0.0f) {
- layer->forceClientComposition(displayDevice);
- }
-
- if (layer->getForceClientComposition(displayDevice)) {
- ALOGV("[%s] Requesting Client composition", layer->getName().string());
- layer->setCompositionType(displayDevice,
- Hwc2::IComposerClient::Composition::CLIENT);
- continue;
- }
-
- const auto& displayState = display->getState();
- layer->setPerFrameData(displayDevice, displayState.transform, displayState.viewport,
- displayDevice->getSupportedPerFrameMetadata(), targetDataspace);
- }
- }
-
- mDrawingState.colorMatrixChanged = false;
-
- for (const auto& [token, displayDevice] : mDisplays) {
- auto display = displayDevice->getCompositionDisplay();
- for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) {
- auto& layerState = layer->getCompositionLayer()->editState().frontEnd;
- layerState.compositionType = static_cast<Hwc2::IComposerClient::Composition>(
- layer->getCompositionType(displayDevice));
- }
+ mDrawingState.colorMatrixChanged = false;
}
}
@@ -1975,13 +1949,13 @@
}
}
- postFramebuffer(displayDevice);
+ displayDevice->getCompositionDisplay()->postFramebuffer();
if (mDebugRegion > 1) {
usleep(mDebugRegion * 1000);
}
- prepareFrame(displayDevice);
+ displayDevice->getCompositionDisplay()->prepareFrame();
}
void SurfaceFlinger::logLayerStats() {
@@ -1998,25 +1972,6 @@
}
}
-void SurfaceFlinger::preComposition()
-{
- ATRACE_CALL();
- ALOGV("preComposition");
-
- mRefreshStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
-
- bool needExtraInvalidate = false;
- mDrawingState.traverseInZOrder([&](Layer* layer) {
- if (layer->onPreComposition(mRefreshStartTime)) {
- needExtraInvalidate = true;
- }
- });
-
- if (needExtraInvalidate) {
- signalLayerUpdate();
- }
-}
-
void SurfaceFlinger::updateCompositorTiming(const DisplayStatInfo& stats, nsecs_t compositeTime,
std::shared_ptr<FenceTime>& presentFenceTime) {
// Update queue of past composite+present times and determine the
@@ -2089,7 +2044,7 @@
getBE().mGlCompositionDoneTimeline.updateSignalTimes();
std::shared_ptr<FenceTime> glCompositionDoneFenceTime;
- if (displayDevice && getHwComposer().hasClientComposition(displayDevice->getId())) {
+ if (displayDevice && displayDevice->getCompositionDisplay()->getState().usesClientComposition) {
glCompositionDoneFenceTime =
std::make_shared<FenceTime>(displayDevice->getCompositionDisplay()
->getRenderSurface()
@@ -2110,10 +2065,11 @@
DisplayStatInfo stats;
mScheduler->getDisplayStatInfo(&stats);
- // We use the mRefreshStartTime which might be sampled a little later than
- // when we started doing work for this frame, but that should be okay
- // since updateCompositorTiming has snapping logic.
- updateCompositorTiming(stats, mRefreshStartTime, presentFenceTime);
+ // We use the CompositionEngine::getLastFrameRefreshTimestamp() which might
+ // be sampled a little later than when we started doing work for this frame,
+ // but that should be okay since updateCompositorTiming has snapping logic.
+ updateCompositorTiming(stats, mCompositionEngine->getLastFrameRefreshTimestamp(),
+ presentFenceTime);
CompositorTiming compositorTiming;
{
std::lock_guard<std::mutex> lock(getBE().mCompositorTimingLock);
@@ -2246,8 +2202,8 @@
Region opaqueRegion;
Region dirtyRegion;
compositionengine::Output::OutputLayers layersSortedByZ;
+ compositionengine::Output::ReleasedLayers releasedLayers;
Vector<sp<Layer>> deprecated_layersSortedByZ;
- Vector<sp<Layer>> layersNeedingFences;
const ui::Transform& tr = displayState.transform;
const Rect bounds = displayState.bounds;
if (displayState.isEnabled) {
@@ -2295,16 +2251,16 @@
layer) != mLayersWithQueuedFrames.cend();
if (hasExistingOutputLayer && hasQueuedFrames) {
- layersNeedingFences.add(layer);
+ releasedLayers.push_back(layer);
}
}
});
}
display->setOutputLayersOrderedByZ(std::move(layersSortedByZ));
+ display->setReleasedLayers(std::move(releasedLayers));
displayDevice->setVisibleLayersSortedByZ(deprecated_layersSortedByZ);
- displayDevice->setLayersNeedingFences(layersNeedingFences);
Region undefinedRegion{bounds};
undefinedRegion.subtractSelf(tr.transform(opaqueRegion));
@@ -2347,7 +2303,8 @@
case Dataspace::BT2020_ITU_PQ:
bestDataSpace = Dataspace::DISPLAY_P3;
*outHdrDataSpace = Dataspace::BT2020_PQ;
- *outIsHdrClientComposition = layer->getForceClientComposition(display);
+ *outIsHdrClientComposition =
+ layer->getCompositionLayer()->getState().frontEnd.forceClientComposition;
break;
case Dataspace::BT2020_HLG:
case Dataspace::BT2020_ITU_HLG:
@@ -2417,51 +2374,6 @@
profile->getBestColorMode(bestDataSpace, intent, outDataSpace, outMode, outRenderIntent);
}
-void SurfaceFlinger::beginFrame(const sp<DisplayDevice>& displayDevice) {
- auto display = displayDevice->getCompositionDisplay();
- const auto& displayState = display->getState();
-
- bool dirty = !display->getDirtyRegion(false).isEmpty();
- bool empty = displayDevice->getVisibleLayersSortedByZ().size() == 0;
- bool wasEmpty = !displayState.lastCompositionHadVisibleLayers;
-
- // If nothing has changed (!dirty), don't recompose.
- // If something changed, but we don't currently have any visible layers,
- // and didn't when we last did a composition, then skip it this time.
- // The second rule does two things:
- // - When all layers are removed from a display, we'll emit one black
- // frame, then nothing more until we get new layers.
- // - When a display is created with a private layer stack, we won't
- // emit any black frames until a layer is added to the layer stack.
- bool mustRecompose = dirty && !(empty && wasEmpty);
-
- const char flagPrefix[] = {'-', '+'};
- static_cast<void>(flagPrefix);
- ALOGV_IF(displayDevice->isVirtual(), "%s: %s composition for %s (%cdirty %cempty %cwasEmpty)",
- __FUNCTION__, mustRecompose ? "doing" : "skipping",
- displayDevice->getDebugName().c_str(), flagPrefix[dirty], flagPrefix[empty],
- flagPrefix[wasEmpty]);
-
- display->getRenderSurface()->beginFrame(mustRecompose);
-
- if (mustRecompose) {
- display->editState().lastCompositionHadVisibleLayers = !empty;
- }
-}
-
-void SurfaceFlinger::prepareFrame(const sp<DisplayDevice>& displayDevice) {
- auto display = displayDevice->getCompositionDisplay();
- const auto& displayState = display->getState();
-
- if (!displayState.isEnabled) {
- return;
- }
-
- status_t result = display->getRenderSurface()->prepareFrame();
- ALOGE_IF(result != NO_ERROR, "prepareFrame failed for %s: %d (%s)",
- displayDevice->getDebugName().c_str(), result, strerror(-result));
-}
-
void SurfaceFlinger::doComposition(const sp<DisplayDevice>& displayDevice, bool repaintEverything) {
ATRACE_CALL();
ALOGV("doComposition");
@@ -2479,7 +2391,7 @@
display->editState().dirtyRegion.clear();
display->getRenderSurface()->flip();
}
- postFramebuffer(displayDevice);
+ displayDevice->getCompositionDisplay()->postFramebuffer();
}
void SurfaceFlinger::postFrame()
@@ -2494,65 +2406,6 @@
}
}
-void SurfaceFlinger::postFramebuffer(const sp<DisplayDevice>& displayDevice) {
- ATRACE_CALL();
- ALOGV("postFramebuffer");
-
- auto display = displayDevice->getCompositionDisplay();
- const auto& displayState = display->getState();
- const auto displayId = display->getId();
-
- if (displayState.isEnabled) {
- if (displayId) {
- getHwComposer().presentAndGetReleaseFences(*displayId);
- }
- display->getRenderSurface()->onPresentDisplayCompleted();
- for (auto& layer : display->getOutputLayersOrderedByZ()) {
- sp<Fence> releaseFence = Fence::NO_FENCE;
- bool usedClientComposition = true;
-
- // The layer buffer from the previous frame (if any) is released
- // by HWC only when the release fence from this frame (if any) is
- // signaled. Always get the release fence from HWC first.
- if (layer->getState().hwc) {
- const auto& hwcState = *layer->getState().hwc;
- releaseFence =
- getHwComposer().getLayerReleaseFence(*displayId, hwcState.hwcLayer.get());
- usedClientComposition =
- hwcState.hwcCompositionType == Hwc2::IComposerClient::Composition::CLIENT;
- }
-
- // If the layer was client composited in the previous frame, we
- // need to merge with the previous client target acquire fence.
- // Since we do not track that, always merge with the current
- // client target acquire fence when it is available, even though
- // this is suboptimal.
- if (usedClientComposition) {
- releaseFence =
- Fence::merge("LayerRelease", releaseFence,
- display->getRenderSurface()->getClientTargetAcquireFence());
- }
-
- layer->getLayerFE().onLayerDisplayed(releaseFence);
- }
-
- // We've got a list of layers needing fences, that are disjoint with
- // display->getVisibleLayersSortedByZ. The best we can do is to
- // supply them with the present fence.
- if (!displayDevice->getLayersNeedingFences().isEmpty()) {
- sp<Fence> presentFence =
- displayId ? getHwComposer().getPresentFence(*displayId) : Fence::NO_FENCE;
- for (auto& layer : displayDevice->getLayersNeedingFences()) {
- layer->getCompositionLayer()->getLayerFE()->onLayerDisplayed(presentFence);
- }
- }
-
- if (displayId) {
- getHwComposer().clearReleaseFences(*displayId);
- }
- }
-}
-
void SurfaceFlinger::handleTransaction(uint32_t transactionFlags)
{
ATRACE_CALL();
@@ -2572,7 +2425,7 @@
// with mStateLock held to guarantee that mCurrentState won't change
// until the transaction is committed.
- mVsyncModulator.onTransactionHandled();
+ mVSyncModulator->onTransactionHandled();
transactionFlags = getTransactionFlags(eTransactionMask);
handleTransactionLocked(transactionFlags);
@@ -2688,7 +2541,7 @@
defaultDataSpace = Dataspace::V0_SRGB;
}
display->getCompositionDisplay()->setColorMode(defaultColorMode, defaultDataSpace,
- RenderIntent::COLORIMETRIC);
+ RenderIntent::COLORIMETRIC, Dataspace::UNKNOWN);
if (!state.isVirtual()) {
LOG_ALWAYS_FATAL_IF(!displayId);
display->setActiveConfig(getHwComposer().getActiveConfigIndex(*displayId));
@@ -2845,9 +2698,11 @@
void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags)
{
+ const nsecs_t expectedPresentTime = mExpectedPresentTime.load();
+
// Notify all layers of available frames
- mCurrentState.traverseInZOrder([](Layer* layer) {
- layer->notifyAvailableFrames();
+ mCurrentState.traverseInZOrder([expectedPresentTime](Layer* layer) {
+ layer->notifyAvailableFrames(expectedPresentTime);
});
/*
@@ -3046,7 +2901,7 @@
void SurfaceFlinger::latchAndReleaseBuffer(const sp<Layer>& layer) {
if (layer->hasReadyFrame()) {
bool ignored = false;
- layer->latchBuffer(ignored, systemTime());
+ layer->latchBuffer(ignored, systemTime(), 0 /* expectedPresentTime */);
}
layer->releasePendingBuffer(systemTime());
}
@@ -3294,6 +3149,8 @@
bool frameQueued = false;
bool newDataLatched = false;
+ const nsecs_t expectedPresentTime = mExpectedPresentTime.load();
+
// Store the set of layers that need updates. This set must not change as
// buffers are being latched, as this could result in a deadlock.
// Example: Two producers share the same command stream and:
@@ -3306,7 +3163,6 @@
mDrawingState.traverseInZOrder([&](Layer* layer) {
if (layer->hasReadyFrame()) {
frameQueued = true;
- const nsecs_t expectedPresentTime = getExpectedPresentTime();
if (layer->shouldPresentNow(expectedPresentTime)) {
mLayersWithQueuedFrames.push_back(layer);
} else {
@@ -3324,7 +3180,7 @@
Mutex::Autolock lock(mStateLock);
for (auto& layer : mLayersWithQueuedFrames) {
- if (layer->latchBuffer(visibleRegions, latchTime)) {
+ if (layer->latchBuffer(visibleRegions, latchTime, expectedPresentTime)) {
mLayersPendingRefresh.push_back(layer);
}
layer->useSurfaceDamage();
@@ -3391,9 +3247,8 @@
const Region bounds(displayState.bounds);
const DisplayRenderArea renderArea(displayDevice);
- const bool hasClientComposition = getHwComposer().hasClientComposition(displayId);
- ATRACE_INT("hasClientComposition", hasClientComposition);
-
+ const TracedOrdinal<bool> hasClientComposition = {"hasClientComposition",
+ displayState.usesClientComposition};
bool applyColorMatrix = false;
renderengine::DisplaySettings clientCompositionDisplay;
@@ -3446,7 +3301,7 @@
clientCompositionDisplay.maxLuminance =
profile->getHdrCapabilities().getDesiredMaxLuminance();
- const bool hasDeviceComposition = getHwComposer().hasDeviceComposition(displayId);
+ const bool hasDeviceComposition = displayState.usesDeviceComposition;
const bool skipClientColorTransform =
getHwComposer()
.hasDisplayCapability(displayId,
@@ -3464,6 +3319,7 @@
*/
ALOGV("Rendering client layers");
+ const bool useIdentityTransform = false;
bool firstLayer = true;
Region clearRegion = Region::INVALID_REGION;
for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) {
@@ -3484,13 +3340,20 @@
layer->getRoundedCornerState().radius == 0.0f && hasClientComposition) {
// never clear the very first layer since we're
// guaranteed the FB is already cleared
- renderengine::LayerSettings layerSettings;
Region dummyRegion;
- bool prepared =
- layer->prepareClientLayer(renderArea, clip, dummyRegion,
- supportProtectedContent, layerSettings);
+ compositionengine::LayerFE::ClientCompositionTargetSettings targetSettings{
+ clip,
+ useIdentityTransform,
+ layer->needsFiltering(renderArea.getDisplayDevice()) ||
+ renderArea.needsFiltering(),
+ renderArea.isSecure(),
+ supportProtectedContent,
+ dummyRegion,
+ };
+ auto result = layer->prepareClientComposition(targetSettings);
- if (prepared) {
+ if (result) {
+ auto& layerSettings = *result;
layerSettings.source.buffer.buffer = nullptr;
layerSettings.source.solidColor = half3(0.0, 0.0, 0.0);
layerSettings.alpha = half(0.0);
@@ -3501,12 +3364,18 @@
break;
}
case Hwc2::IComposerClient::Composition::CLIENT: {
- renderengine::LayerSettings layerSettings;
- bool prepared =
- layer->prepareClientLayer(renderArea, clip, clearRegion,
- supportProtectedContent, layerSettings);
- if (prepared) {
- clientCompositionLayers.push_back(layerSettings);
+ compositionengine::LayerFE::ClientCompositionTargetSettings targetSettings{
+ clip,
+ useIdentityTransform,
+ layer->needsFiltering(renderArea.getDisplayDevice()) ||
+ renderArea.needsFiltering(),
+ renderArea.isSecure(),
+ supportProtectedContent,
+ clearRegion,
+ };
+ auto result = layer->prepareClientComposition(targetSettings);
+ if (result) {
+ clientCompositionLayers.push_back(*result);
}
break;
}
@@ -3622,7 +3491,7 @@
uint32_t SurfaceFlinger::setTransactionFlags(uint32_t flags,
Scheduler::TransactionStart transactionStart) {
uint32_t old = mTransactionFlags.fetch_or(flags);
- mVsyncModulator.setTransactionStart(transactionStart);
+ mVSyncModulator->setTransactionStart(transactionStart);
if ((old & flags)==0) { // wake the server up
signalTransaction();
}
@@ -3645,6 +3514,7 @@
while (!transactionQueue.empty()) {
const auto& transaction = transactionQueue.front();
if (!transactionIsReadyToBeApplied(transaction.desiredPresentTime,
+ true /* useCachedExpectedPresentTime */,
transaction.states)) {
setTransactionFlags(eTransactionFlushNeeded);
break;
@@ -3674,31 +3544,14 @@
return !mTransactionQueues.empty();
}
-bool SurfaceFlinger::containsAnyInvalidClientState(const Vector<ComposerState>& states) {
- for (const ComposerState& state : states) {
- // Here we need to check that the interface we're given is indeed
- // one of our own. A malicious client could give us a nullptr
- // IInterface, or one of its own or even one of our own but a
- // different type. All these situations would cause us to crash.
- if (state.client == nullptr) {
- return true;
- }
-
- sp<IBinder> binder = IInterface::asBinder(state.client);
- if (binder == nullptr) {
- return true;
- }
-
- if (binder->queryLocalInterface(ISurfaceComposerClient::descriptor) == nullptr) {
- return true;
- }
- }
- return false;
-}
bool SurfaceFlinger::transactionIsReadyToBeApplied(int64_t desiredPresentTime,
+ bool useCachedExpectedPresentTime,
const Vector<ComposerState>& states) {
- nsecs_t expectedPresentTime = getExpectedPresentTime();
+ if (!useCachedExpectedPresentTime)
+ populateExpectedPresentTime();
+
+ const nsecs_t expectedPresentTime = mExpectedPresentTime.load();
// Do not present if the desiredPresentTime has not passed unless it is more than one second
// in the future. We ignore timestamps more than 1 second in the future for stability reasons.
if (desiredPresentTime >= 0 && desiredPresentTime >= expectedPresentTime &&
@@ -3733,10 +3586,6 @@
Mutex::Autolock _l(mStateLock);
- if (containsAnyInvalidClientState(states)) {
- return;
- }
-
// If its TransactionQueue already has a pending TransactionState or if it is pending
auto itr = mTransactionQueues.find(applyToken);
// if this is an animation frame, wait until prior animation frame has
@@ -3753,8 +3602,10 @@
itr = mTransactionQueues.find(applyToken);
}
}
- if (itr != mTransactionQueues.end() ||
- !transactionIsReadyToBeApplied(desiredPresentTime, states)) {
+
+ // Expected present time is computed and cached on invalidate, so it may be stale.
+ if (itr != mTransactionQueues.end() || !transactionIsReadyToBeApplied(
+ desiredPresentTime, false /* useCachedExpectedPresentTime */, states)) {
mTransactionQueues[applyToken].emplace(states, displays, flags, desiredPresentTime,
uncacheBuffer, listenerCallbacks, postTime,
privileged);
@@ -3948,9 +3799,8 @@
const std::vector<ListenerCallbacks>& listenerCallbacks, int64_t postTime,
bool privileged) {
const layer_state_t& s = composerState.state;
- sp<Client> client(static_cast<Client*>(composerState.client.get()));
- sp<Layer> layer(client->getLayerUser(s.surface));
+ sp<Layer> layer(fromHandle(s.surface));
if (layer == nullptr) {
for (auto& listenerCallback : listenerCallbacks) {
mTransactionCompletedThread.registerUnpresentedCallbackHandle(
@@ -4107,15 +3957,6 @@
// We don't trigger a traversal here because if no other state is
// changed, we don't want this to cause any more work
}
- if (what & layer_state_t::eReparent) {
- bool hadParent = layer->hasParent();
- if (layer->reparent(s.parentHandleForChild)) {
- if (!hadParent) {
- mCurrentState.layersSortedByZ.remove(layer);
- }
- flags |= eTransactionNeeded|eTraversalNeeded;
- }
- }
if (what & layer_state_t::eReparentChildren) {
if (layer->reparentChildren(s.reparentHandle)) {
flags |= eTransactionNeeded|eTraversalNeeded;
@@ -4176,6 +4017,19 @@
flags |= eTraversalNeeded;
}
}
+ // This has to happen after we reparent children because when we reparent to null we remove
+ // child layers from current state and remove its relative z. If the children are reparented in
+ // the same transaction, then we have to make sure we reparent the children first so we do not
+ // lose its relative z order.
+ if (what & layer_state_t::eReparent) {
+ bool hadParent = layer->hasParent();
+ if (layer->reparent(s.parentHandleForChild)) {
+ if (!hadParent) {
+ mCurrentState.layersSortedByZ.remove(layer);
+ }
+ flags |= eTransactionNeeded | eTraversalNeeded;
+ }
+ }
std::vector<sp<CallbackHandle>> callbackHandles;
if ((what & layer_state_t::eHasListenerCallbacksChanged) && (!listenerCallbacks.empty())) {
for (const auto& [listener, callbackIds] : listenerCallbacks) {
@@ -4633,18 +4487,22 @@
if (const auto it = dumpers.find(flag); it != dumpers.end()) {
(it->second)(args, asProto, result);
- } else {
- if (asProto) {
- LayersProto layersProto = dumpProtoInfo(LayerVector::StateSet::Current);
- result.append(layersProto.SerializeAsString().c_str(), layersProto.ByteSize());
- } else {
- dumpAllLocked(args, result);
- }
+ } else if (!asProto) {
+ dumpAllLocked(args, result);
}
if (locked) {
mStateLock.unlock();
}
+
+ LayersProto layersProto = dumpProtoFromMainThread();
+ if (asProto) {
+ result.append(layersProto.SerializeAsString().c_str(), layersProto.ByteSize());
+ } else {
+ auto layerTree = LayerProtoParser::generateLayerTree(layersProto);
+ result.append(LayerProtoParser::layerTreeToString(layerTree));
+ result.append("\n");
+ }
}
write(fd, result.c_str(), result.size());
return NO_ERROR;
@@ -4885,19 +4743,23 @@
result.append("\n");
}
-LayersProto SurfaceFlinger::dumpProtoInfo(LayerVector::StateSet stateSet,
- uint32_t traceFlags) const {
+LayersProto SurfaceFlinger::dumpDrawingStateProto(uint32_t traceFlags) const {
LayersProto layersProto;
- const bool useDrawing = stateSet == LayerVector::StateSet::Drawing;
- const State& state = useDrawing ? mDrawingState : mCurrentState;
- state.traverseInZOrder([&](Layer* layer) {
+ mDrawingState.traverseInZOrder([&](Layer* layer) {
LayerProto* layerProto = layersProto.add_layers();
- layer->writeToProto(layerProto, stateSet, traceFlags);
+ layer->writeToProtoDrawingState(layerProto, traceFlags);
+ layer->writeToProtoCommonState(layerProto, LayerVector::StateSet::Drawing, traceFlags);
});
return layersProto;
}
+LayersProto SurfaceFlinger::dumpProtoFromMainThread(uint32_t traceFlags) {
+ LayersProto layersProto;
+ postMessageSync(new LambdaMessage([&]() { layersProto = dumpDrawingStateProto(traceFlags); }));
+ return layersProto;
+}
+
LayersProto SurfaceFlinger::dumpVisibleLayersProtoInfo(
const sp<DisplayDevice>& displayDevice) const {
LayersProto layersProto;
@@ -4918,7 +4780,7 @@
mDrawingState.traverseInZOrder([&](Layer* layer) {
if (!layer->visibleRegion.isEmpty() && !display->getOutputLayersOrderedByZ().empty()) {
LayerProto* layerProto = layersProto.add_layers();
- layer->writeToProto(layerProto, displayDevice);
+ layer->writeToProtoCompositionState(layerProto, displayDevice);
}
});
@@ -4983,13 +4845,6 @@
colorizer.reset(result);
{
- LayersProto layersProto = dumpProtoInfo(LayerVector::StateSet::Current);
- auto layerTree = LayerProtoParser::generateLayerTree(layersProto);
- result.append(LayerProtoParser::layerTreeToString(layerTree));
- result.append("\n");
- }
-
- {
StringAppendF(&result, "Composition layers\n");
mDrawingState.traverseInZOrder([&](Layer* layer) {
auto compositionLayer = layer->getCompositionLayer();
@@ -5019,6 +4874,8 @@
getRenderEngine().dump(result);
+ DebugEGLImageTracker::getInstance()->dump(result);
+
if (const auto display = getDefaultDisplayDeviceLocked()) {
display->getCompositionDisplay()->getState().undefinedRegion.dump(result,
"undefinedRegion");
@@ -5103,19 +4960,6 @@
result.append("\n");
}
-const Vector<sp<Layer>>& SurfaceFlinger::getLayerSortedByZForHwcDisplay(DisplayId displayId) {
- // Note: mStateLock is held here
- for (const auto& [token, display] : mDisplays) {
- if (display->getId() == displayId) {
- return getDisplayDeviceLocked(token)->getVisibleLayersSortedByZ();
- }
- }
-
- ALOGE("%s: Invalid display %s", __FUNCTION__, to_string(displayId).c_str());
- static const Vector<sp<Layer>> empty;
- return empty;
-}
-
void SurfaceFlinger::updateColorMatrixLocked() {
mat4 colorMatrix;
if (mGlobalSaturationFactor != 1.0f) {
@@ -6076,11 +5920,19 @@
Region clearRegion = Region::INVALID_REGION;
traverseLayers([&](Layer* layer) {
- renderengine::LayerSettings layerSettings;
- bool prepared = layer->prepareClientLayer(renderArea, useIdentityTransform, clearRegion,
- false, layerSettings);
- if (prepared) {
- clientCompositionLayers.push_back(layerSettings);
+ const bool supportProtectedContent = false;
+ Region clip(renderArea.getBounds());
+ compositionengine::LayerFE::ClientCompositionTargetSettings targetSettings{
+ clip,
+ useIdentityTransform,
+ layer->needsFiltering(renderArea.getDisplayDevice()) || renderArea.needsFiltering(),
+ renderArea.isSecure(),
+ supportProtectedContent,
+ clearRegion,
+ };
+ auto result = layer->prepareClientComposition(targetSettings);
+ if (result) {
+ clientCompositionLayers.push_back(*result);
}
});
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index fa801af..3974a8c 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -60,6 +60,7 @@
#include "Scheduler/VSyncModulator.h"
#include "SurfaceFlingerFactory.h"
#include "SurfaceTracing.h"
+#include "TracedOrdinal.h"
#include "TransactionCompletedThread.h"
#include <atomic>
@@ -68,6 +69,7 @@
#include <map>
#include <memory>
#include <mutex>
+#include <optional>
#include <queue>
#include <set>
#include <string>
@@ -263,7 +265,8 @@
status_t postMessageAsync(const sp<MessageBase>& msg, nsecs_t reltime = 0, uint32_t flags = 0);
// post a synchronous message to the main thread
- status_t postMessageSync(const sp<MessageBase>& msg, nsecs_t reltime = 0, uint32_t flags = 0);
+ status_t postMessageSync(const sp<MessageBase>& msg, nsecs_t reltime = 0, uint32_t flags = 0)
+ EXCLUDES(mStateLock);
// force full composition on all displays
void repaintEverything();
@@ -295,21 +298,13 @@
// main thread function to enable/disable h/w composer event
void setPrimaryVsyncEnabledInternal(bool enabled);
+ void setVsyncEnabledInHWC(DisplayId displayId, HWC2::Vsync enabled);
// called on the main thread by MessageQueue when an internal message
// is received
// TODO: this should be made accessible only to MessageQueue
void onMessageReceived(int32_t what);
- // Returns the expected present time for this frame.
- // When we are in negative offsets, we perform a correction so that the
- // predicted vsync for the *next* frame is used instead.
- nsecs_t getExpectedPresentTime();
-
- // for debugging only
- // TODO: this should be made accessible only to HWComposer
- const Vector<sp<Layer>>& getLayerSortedByZForHwcDisplay(DisplayId displayId);
-
renderengine::RenderEngine& getRenderEngine() const;
bool authenticateSurfaceTextureLocked(
@@ -582,8 +577,8 @@
void latchAndReleaseBuffer(const sp<Layer>& layer);
void commitTransaction() REQUIRES(mStateLock);
void commitOffscreenLayers();
- bool containsAnyInvalidClientState(const Vector<ComposerState>& states);
bool transactionIsReadyToBeApplied(int64_t desiredPresentTime,
+ bool useCachedExpectedPresentTime,
const Vector<ComposerState>& states);
uint32_t setClientStateLocked(const ComposerState& composerState, int64_t desiredPresentTime,
const std::vector<ListenerCallbacks>& listenerCallbacks,
@@ -747,7 +742,6 @@
void computeVisibleRegions(const sp<const DisplayDevice>& display, Region& dirtyRegion,
Region& opaqueRegion);
- void preComposition();
void postComposition();
void getCompositorTiming(CompositorTiming* compositorTiming);
void updateCompositorTiming(const DisplayStatInfo& stats, nsecs_t compositeTime,
@@ -766,17 +760,6 @@
ui::Dataspace* outDataSpace, ui::RenderIntent* outRenderIntent) const;
void calculateWorkingSet();
- /*
- * beginFrame - This function handles any pre-frame processing that needs to be
- * prior to any CompositionInfo handling and is not dependent on data in
- * CompositionInfo
- */
- void beginFrame(const sp<DisplayDevice>& display);
- /* prepareFrame - This function will call into the DisplayDevice to prepare a
- * frame after CompositionInfo has been programmed. This provides a mechanism
- * to prepare the hardware composer
- */
- void prepareFrame(const sp<DisplayDevice>& display);
void doComposition(const sp<DisplayDevice>& display, bool repainEverything);
void doDebugFlashRegions(const sp<DisplayDevice>& display, bool repaintEverything);
void logLayerStats();
@@ -788,7 +771,6 @@
bool doComposeSurfaces(const sp<DisplayDevice>& display, const Region& debugRegionm,
base::unique_fd* readyFence);
- void postFramebuffer(const sp<DisplayDevice>& display);
void postFrame();
/* ------------------------------------------------------------------------
@@ -815,6 +797,12 @@
bool isDisplayConfigAllowed(int32_t configId) const REQUIRES(mStateLock);
+ bool previousFrameMissed();
+
+ // Populates the expected present time for this frame. For negative offsets, performs a
+ // correction using the predicted vsync for the next frame instead.
+ void populateExpectedPresentTime();
+
/*
* Display identification
*/
@@ -843,9 +831,6 @@
return hwcDisplayId ? getHwComposer().toPhysicalDisplayId(*hwcDisplayId) : std::nullopt;
}
- bool previousFrameMissed();
- void setVsyncEnabledInHWC(DisplayId displayId, HWC2::Vsync enabled);
-
/*
* Debugging & dumpsys
*/
@@ -895,8 +880,9 @@
void dumpBufferingStats(std::string& result) const;
void dumpDisplayIdentificationData(std::string& result) const;
void dumpWideColorInfo(std::string& result) const;
- LayersProto dumpProtoInfo(LayerVector::StateSet stateSet,
- uint32_t traceFlags = SurfaceTracing::TRACE_ALL) const;
+ LayersProto dumpDrawingStateProto(uint32_t traceFlags = SurfaceTracing::TRACE_ALL) const;
+ LayersProto dumpProtoFromMainThread(uint32_t traceFlags = SurfaceTracing::TRACE_ALL)
+ EXCLUDES(mStateLock);
void withTracingLock(std::function<void()> operation) REQUIRES(mStateLock);
LayersProto dumpVisibleLayersProtoInfo(const sp<DisplayDevice>& display) const;
@@ -962,11 +948,6 @@
std::unique_ptr<EventThread> mInjectorEventThread;
std::unique_ptr<InjectVSyncSource> mVSyncInjector;
- // Calculates correct offsets.
- VSyncModulator mVsyncModulator;
- // Keeps track of all available phase offsets for different refresh types.
- const std::unique_ptr<scheduler::PhaseOffsets> mPhaseOffsets;
-
// Can only accessed from the main thread, these members
// don't need synchronization
State mDrawingState{LayerVector::StateSet::Drawing};
@@ -1015,6 +996,7 @@
volatile nsecs_t mDebugInTransaction = 0;
bool mForceFullDamage = false;
bool mPropagateBackpressure = true;
+ bool mPropagateBackpressureClientComposition = false;
std::unique_ptr<SurfaceInterceptor> mInterceptor;
SurfaceTracing mTracing{*this};
bool mTracingEnabled = false;
@@ -1130,9 +1112,17 @@
sp<Scheduler::ConnectionHandle> mAppConnectionHandle;
sp<Scheduler::ConnectionHandle> mSfConnectionHandle;
+ // Stores phase offsets configured per refresh rate.
+ const std::unique_ptr<scheduler::PhaseOffsets> mPhaseOffsets;
+
+ // Optional to defer construction until scheduler connections are created.
+ std::optional<scheduler::VSyncModulator> mVSyncModulator;
+
scheduler::RefreshRateConfigs mRefreshRateConfigs;
scheduler::RefreshRateStats mRefreshRateStats{mRefreshRateConfigs, *mTimeStats};
+ std::atomic<nsecs_t> mExpectedPresentTime = 0;
+
// All configs are allowed if the set is empty.
using DisplayConfigs = std::set<int32_t>;
DisplayConfigs mAllowedDisplayConfigs GUARDED_BY(mStateLock);
@@ -1146,7 +1136,8 @@
ActiveConfigInfo mDesiredActiveConfig GUARDED_BY(mActiveConfigLock);
// below flags are set by main thread only
- bool mDesiredActiveConfigChanged GUARDED_BY(mActiveConfigLock) = false;
+ TracedOrdinal<bool> mDesiredActiveConfigChanged
+ GUARDED_BY(mActiveConfigLock) = {"DesiredActiveConfigChanged", false};
bool mCheckPendingFence = false;
bool mLumaSampling = true;
diff --git a/services/surfaceflinger/SurfaceInterceptor.h b/services/surfaceflinger/SurfaceInterceptor.h
index 7f86c14..6858c4d 100644
--- a/services/surfaceflinger/SurfaceInterceptor.h
+++ b/services/surfaceflinger/SurfaceInterceptor.h
@@ -39,8 +39,14 @@
struct DisplayDeviceState;
struct DisplayState;
struct layer_state_t;
+using Transaction = surfaceflinger::Transaction;
+using Trace = surfaceflinger::Trace;
+using Rectangle = surfaceflinger::Rectangle;
+using SurfaceChange = surfaceflinger::SurfaceChange;
+using Increment = surfaceflinger::Increment;
+using DisplayChange = surfaceflinger::DisplayChange;
-constexpr auto DEFAULT_FILENAME = "/data/SurfaceTrace.dat";
+constexpr auto DEFAULT_FILENAME = "/data/misc/wmtrace/transaction_trace.pb";
class SurfaceInterceptor {
public:
@@ -183,6 +189,7 @@
};
} // namespace impl
+
} // namespace android
#endif // ANDROID_SURFACEINTERCEPTOR_H
diff --git a/services/surfaceflinger/SurfaceTracing.cpp b/services/surfaceflinger/SurfaceTracing.cpp
index c4ab066..9053f2c 100644
--- a/services/surfaceflinger/SurfaceTracing.cpp
+++ b/services/surfaceflinger/SurfaceTracing.cpp
@@ -162,7 +162,7 @@
LayersTraceProto entry;
entry.set_elapsed_realtime_nanos(elapsedRealtimeNano());
entry.set_where(where);
- LayersProto layers(mFlinger.dumpProtoInfo(LayerVector::StateSet::Drawing, mTraceFlags));
+ LayersProto layers(mFlinger.dumpDrawingStateProto(mTraceFlags));
entry.mutable_layers()->Swap(&layers);
return entry;
diff --git a/services/surfaceflinger/TracedOrdinal.h b/services/surfaceflinger/TracedOrdinal.h
new file mode 100644
index 0000000..c145a39
--- /dev/null
+++ b/services/surfaceflinger/TracedOrdinal.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+#include <android-base/stringprintf.h>
+#include <utils/Trace.h>
+#include <cmath>
+#include <string>
+
+template <typename T>
+class TracedOrdinal {
+public:
+ static_assert(std::is_same<bool, T>() || (std::is_signed<T>() && std::is_integral<T>()),
+ "Type is not supported. Please test it with systrace before adding "
+ "it to the list.");
+
+ TracedOrdinal(const std::string& name, T initialValue)
+ : mName(name),
+ mNameNegative(android::base::StringPrintf("%sNegative", name.c_str())),
+ mHasGoneNegative(std::signbit(initialValue)),
+ mData(initialValue) {
+ trace();
+ }
+
+ operator T() const { return mData; }
+
+ TracedOrdinal& operator=(T other) {
+ mData = other;
+ mHasGoneNegative = mHasGoneNegative || std::signbit(mData);
+ trace();
+ return *this;
+ }
+
+private:
+ void trace() {
+ if (!std::signbit(mData)) {
+ ATRACE_INT64(mName.c_str(), int64_t(mData));
+ if (mHasGoneNegative) {
+ ATRACE_INT64(mNameNegative.c_str(), 0);
+ }
+ } else {
+ ATRACE_INT64(mNameNegative.c_str(), -int64_t(mData));
+ ATRACE_INT64(mName.c_str(), 0);
+ }
+ }
+
+ const std::string mName;
+ const std::string mNameNegative;
+ bool mHasGoneNegative;
+ T mData;
+};
diff --git a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
index 26c6da9..59e9c00 100644
--- a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
+++ b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
@@ -36,6 +36,9 @@
namespace android {
using Transaction = SurfaceComposerClient::Transaction;
+using SurfaceChange = surfaceflinger::SurfaceChange;
+using Trace = surfaceflinger::Trace;
+using Increment = surfaceflinger::Increment;
constexpr int32_t SCALING_UPDATE = 1;
constexpr uint32_t BUFFER_UPDATES = 18;
@@ -57,7 +60,7 @@
constexpr auto LAYER_NAME = "Layer Create and Delete Test";
constexpr auto UNIQUE_LAYER_NAME = "Layer Create and Delete Test#0";
-constexpr auto DEFAULT_FILENAME = "/data/SurfaceTrace.dat";
+constexpr auto DEFAULT_FILENAME = "/data/misc/wmtrace/transaction_trace.pb";
// Fill an RGBA_8888 formatted surface with a single color.
static void fillSurfaceRGBA8(const sp<SurfaceControl>& sc, uint8_t r, uint8_t g, uint8_t b) {
@@ -980,5 +983,4 @@
ASSERT_TRUE(bufferUpdatesFound(capturedTrace));
ASSERT_TRUE(singleIncrementFound(capturedTrace, Increment::IncrementCase::kSurfaceCreation));
}
-
}
diff --git a/services/surfaceflinger/tests/Transaction_test.cpp b/services/surfaceflinger/tests/Transaction_test.cpp
index aed7b40..b1fde22 100644
--- a/services/surfaceflinger/tests/Transaction_test.cpp
+++ b/services/surfaceflinger/tests/Transaction_test.cpp
@@ -28,6 +28,7 @@
#include <binder/ProcessState.h>
#include <gui/BufferItemConsumer.h>
+#include <gui/IProducerListener.h>
#include <gui/ISurfaceComposer.h>
#include <gui/LayerState.h>
#include <gui/Surface.h>
@@ -4685,6 +4686,34 @@
}
}
+TEST_F(ChildLayerTest, ChildrenRelativeZSurvivesParentDestruction) {
+ sp<SurfaceControl> mGrandChild =
+ createSurface(mClient, "Grand Child", 10, 10, PIXEL_FORMAT_RGBA_8888, 0, mChild.get());
+ fillSurfaceRGBA8(mGrandChild, 111, 111, 111);
+
+ // draw grand child behind the foreground surface
+ asTransaction([&](Transaction& t) {
+ t.setRelativeLayer(mGrandChild, mFGSurfaceControl->getHandle(), -1);
+ });
+
+ {
+ SCOPED_TRACE("Child visible");
+ ScreenCapture::captureScreen(&mCapture);
+ mCapture->checkPixel(64, 64, 200, 200, 200);
+ }
+
+ asTransaction([&](Transaction& t) {
+ t.reparent(mChild, nullptr);
+ t.reparentChildren(mChild, mFGSurfaceControl->getHandle());
+ });
+
+ {
+ SCOPED_TRACE("foreground visible reparenting grandchild");
+ ScreenCapture::captureScreen(&mCapture);
+ mCapture->checkPixel(64, 64, 195, 63, 63);
+ }
+}
+
TEST_F(ChildLayerTest, DetachChildrenSameClient) {
asTransaction([&](Transaction& t) {
t.show(mChild);
@@ -6083,4 +6112,97 @@
}
}
+// This test ensures that when we drop an app buffer in SurfaceFlinger, we merge
+// the dropped buffer's damage region into the next buffer's damage region. If
+// we don't do this, we'll report an incorrect damage region to hardware
+// composer, resulting in broken rendering. This test checks the BufferQueue
+// case.
+//
+// Unfortunately, we don't currently have a way to inspect the damage region
+// SurfaceFlinger sends to hardware composer from a test, so this test requires
+// the dev to manually watch the device's screen during the test to spot broken
+// rendering. Because the results can't be automatically verified, this test is
+// marked disabled.
+TEST_F(LayerTransactionTest, DISABLED_BufferQueueLayerMergeDamageRegionWhenDroppingBuffers) {
+ const int width = mDisplayWidth;
+ const int height = mDisplayHeight;
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", width, height));
+ const auto producer = layer->getIGraphicBufferProducer();
+ const sp<IProducerListener> dummyListener(new DummyProducerListener);
+ IGraphicBufferProducer::QueueBufferOutput queueBufferOutput;
+ ASSERT_EQ(OK,
+ producer->connect(dummyListener, NATIVE_WINDOW_API_CPU, true, &queueBufferOutput));
+
+ std::map<int, sp<GraphicBuffer>> slotMap;
+ auto slotToBuffer = [&](int slot, sp<GraphicBuffer>* buf) {
+ ASSERT_NE(nullptr, buf);
+ const auto iter = slotMap.find(slot);
+ ASSERT_NE(slotMap.end(), iter);
+ *buf = iter->second;
+ };
+
+ auto dequeue = [&](int* outSlot) {
+ ASSERT_NE(nullptr, outSlot);
+ *outSlot = -1;
+ int slot;
+ sp<Fence> fence;
+ uint64_t age;
+ FrameEventHistoryDelta timestamps;
+ const status_t dequeueResult =
+ producer->dequeueBuffer(&slot, &fence, width, height, PIXEL_FORMAT_RGBA_8888,
+ GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
+ &age, ×tamps);
+ if (dequeueResult == IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION) {
+ sp<GraphicBuffer> newBuf;
+ ASSERT_EQ(OK, producer->requestBuffer(slot, &newBuf));
+ ASSERT_NE(nullptr, newBuf.get());
+ slotMap[slot] = newBuf;
+ } else {
+ ASSERT_EQ(OK, dequeueResult);
+ }
+ *outSlot = slot;
+ };
+
+ auto queue = [&](int slot, const Region& damage, nsecs_t displayTime) {
+ IGraphicBufferProducer::QueueBufferInput input(
+ /*timestamp=*/displayTime, /*isAutoTimestamp=*/false, HAL_DATASPACE_UNKNOWN,
+ /*crop=*/Rect::EMPTY_RECT, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW,
+ /*transform=*/0, Fence::NO_FENCE);
+ input.setSurfaceDamage(damage);
+ IGraphicBufferProducer::QueueBufferOutput output;
+ ASSERT_EQ(OK, producer->queueBuffer(slot, input, &output));
+ };
+
+ auto fillAndPostBuffers = [&](const Color& color) {
+ int slot1;
+ ASSERT_NO_FATAL_FAILURE(dequeue(&slot1));
+ int slot2;
+ ASSERT_NO_FATAL_FAILURE(dequeue(&slot2));
+
+ sp<GraphicBuffer> buf1;
+ ASSERT_NO_FATAL_FAILURE(slotToBuffer(slot1, &buf1));
+ sp<GraphicBuffer> buf2;
+ ASSERT_NO_FATAL_FAILURE(slotToBuffer(slot2, &buf2));
+ fillGraphicBufferColor(buf1, Rect(width, height), color);
+ fillGraphicBufferColor(buf2, Rect(width, height), color);
+
+ const auto displayTime = systemTime() + milliseconds_to_nanoseconds(100);
+ ASSERT_NO_FATAL_FAILURE(queue(slot1, Region::INVALID_REGION, displayTime));
+ ASSERT_NO_FATAL_FAILURE(
+ queue(slot2, Region(Rect(width / 3, height / 3, 2 * width / 3, 2 * height / 3)),
+ displayTime));
+ };
+
+ const auto startTime = systemTime();
+ const std::array<Color, 3> colors = {Color::RED, Color::GREEN, Color::BLUE};
+ int colorIndex = 0;
+ while (nanoseconds_to_seconds(systemTime() - startTime) < 10) {
+ ASSERT_NO_FATAL_FAILURE(fillAndPostBuffers(colors[colorIndex++ % colors.size()]));
+ std::this_thread::sleep_for(1s);
+ }
+
+ ASSERT_EQ(OK, producer->disconnect(NATIVE_WINDOW_API_CPU));
+}
+
} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
index e6211c4..47243a9 100644
--- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
@@ -296,7 +296,6 @@
EXPECT_CALL(*test->mComposer,
setColorTransform(HWC_DISPLAY, _, Hwc2::ColorTransform::IDENTITY))
.Times(1);
- EXPECT_CALL(*test->mComposer, presentOrValidateDisplay(HWC_DISPLAY, _, _, _, _)).Times(1);
EXPECT_CALL(*test->mComposer, getDisplayRequests(HWC_DISPLAY, _, _, _)).Times(1);
EXPECT_CALL(*test->mComposer, acceptDisplayChanges(HWC_DISPLAY)).Times(1);
EXPECT_CALL(*test->mComposer, presentDisplay(HWC_DISPLAY, _)).Times(1);
@@ -336,11 +335,21 @@
}
static void setupHwcCompositionCallExpectations(CompositionTest* test) {
+ EXPECT_CALL(*test->mComposer, presentOrValidateDisplay(HWC_DISPLAY, _, _, _, _)).Times(1);
+
EXPECT_CALL(*test->mDisplaySurface,
prepareFrame(compositionengine::DisplaySurface::COMPOSITION_HWC))
.Times(1);
}
+ static void setupHwcClientCompositionCallExpectations(CompositionTest* test) {
+ EXPECT_CALL(*test->mComposer, presentOrValidateDisplay(HWC_DISPLAY, _, _, _, _)).Times(1);
+ }
+
+ static void setupHwcForcedClientCompositionCallExpectations(CompositionTest* test) {
+ EXPECT_CALL(*test->mComposer, validateDisplay(HWC_DISPLAY, _, _)).Times(1);
+ }
+
static void setupRECompositionCallExpectations(CompositionTest* test) {
EXPECT_CALL(*test->mDisplaySurface,
prepareFrame(compositionengine::DisplaySurface::COMPOSITION_GLES))
@@ -414,6 +423,8 @@
}
static void setupHwcCompositionCallExpectations(CompositionTest*) {}
+ static void setupHwcClientCompositionCallExpectations(CompositionTest*) {}
+ static void setupHwcForcedClientCompositionCallExpectations(CompositionTest*) {}
static void setupRECompositionCallExpectations(CompositionTest* test) {
EXPECT_CALL(*test->mRenderEngine, useNativeFenceSync()).WillRepeatedly(Return(true));
@@ -502,7 +513,7 @@
EXPECT_CALL(*test->mRenderEngine, useNativeFenceSync()).WillRepeatedly(Return(true));
bool ignoredRecomputeVisibleRegions;
- layer->latchBuffer(ignoredRecomputeVisibleRegions, 0);
+ layer->latchBuffer(ignoredRecomputeVisibleRegions, 0, 0);
Mock::VerifyAndClear(test->mRenderEngine);
}
@@ -981,14 +992,25 @@
template <typename Case>
static void setupCallExpectations(CompositionTest* test) {
Case::Display::setupNonEmptyFrameCompositionCallExpectations(test);
+ Case::Display::setupHwcClientCompositionCallExpectations(test);
Case::Display::setupRECompositionCallExpectations(test);
Case::Display::template setupRELayerCompositionCallExpectations<Case>(test);
}
};
-struct ForcedClientCompositionResultVariant : public RECompositionResultVariant {
+struct ForcedClientCompositionResultVariant : public CompositionResultBaseVariant {
static void setupLayerState(CompositionTest* test, sp<Layer> layer) {
- layer->forceClientComposition(test->mDisplay);
+ const auto outputLayer = layer->findOutputLayerForDisplay(test->mDisplay);
+ LOG_FATAL_IF(!outputLayer);
+ outputLayer->editState().forceClientComposition = true;
+ }
+
+ template <typename Case>
+ static void setupCallExpectations(CompositionTest* test) {
+ Case::Display::setupNonEmptyFrameCompositionCallExpectations(test);
+ Case::Display::setupHwcForcedClientCompositionCallExpectations(test);
+ Case::Display::setupRECompositionCallExpectations(test);
+ Case::Display::template setupRELayerCompositionCallExpectations<Case>(test);
}
template <typename Case>
diff --git a/services/surfaceflinger/tests/unittests/FakePhaseOffsets.h b/services/surfaceflinger/tests/unittests/FakePhaseOffsets.h
index 1d75011..66c7f6b 100644
--- a/services/surfaceflinger/tests/unittests/FakePhaseOffsets.h
+++ b/services/surfaceflinger/tests/unittests/FakePhaseOffsets.h
@@ -20,42 +20,22 @@
#include "Scheduler/PhaseOffsets.h"
-namespace android {
-namespace scheduler {
+namespace android::scheduler {
-using RefreshRateType = RefreshRateConfigs::RefreshRateType;
+struct FakePhaseOffsets : PhaseOffsets {
+ static constexpr nsecs_t FAKE_PHASE_OFFSET_NS = 0;
-class FakePhaseOffsets : public android::scheduler::PhaseOffsets {
- nsecs_t FAKE_PHASE_OFFSET_NS = 0;
+ Offsets getOffsetsForRefreshRate(RefreshRateType) const override { return getCurrentOffsets(); }
-public:
- FakePhaseOffsets() = default;
- ~FakePhaseOffsets() = default;
-
- nsecs_t getCurrentAppOffset() override { return FAKE_PHASE_OFFSET_NS; }
- nsecs_t getCurrentSfOffset() override { return FAKE_PHASE_OFFSET_NS; }
-
- PhaseOffsets::Offsets getOffsetsForRefreshRate(
- RefreshRateType /*refreshRateType*/) const override {
- return getCurrentOffsets();
+ Offsets getCurrentOffsets() const override {
+ return {{RefreshRateType::DEFAULT, FAKE_PHASE_OFFSET_NS, FAKE_PHASE_OFFSET_NS},
+ {RefreshRateType::DEFAULT, FAKE_PHASE_OFFSET_NS, FAKE_PHASE_OFFSET_NS},
+ {RefreshRateType::DEFAULT, FAKE_PHASE_OFFSET_NS, FAKE_PHASE_OFFSET_NS},
+ FAKE_PHASE_OFFSET_NS};
}
- // Returns early, early GL, and late offsets for Apps and SF.
- PhaseOffsets::Offsets getCurrentOffsets() const override {
- return Offsets{{RefreshRateType::DEFAULT, FAKE_PHASE_OFFSET_NS, FAKE_PHASE_OFFSET_NS},
- {RefreshRateType::DEFAULT, FAKE_PHASE_OFFSET_NS, FAKE_PHASE_OFFSET_NS},
- {RefreshRateType::DEFAULT, FAKE_PHASE_OFFSET_NS, FAKE_PHASE_OFFSET_NS}};
- }
-
- // This function should be called when the device is switching between different
- // refresh rates, to properly update the offsets.
- void setRefreshRateType(RefreshRateType /*refreshRateType*/) override {}
-
- nsecs_t getOffsetThresholdForNextVsync() const override { return FAKE_PHASE_OFFSET_NS; }
-
- // Returns current offsets in human friendly format.
- void dump(std::string& /*result*/) const override {}
+ void setRefreshRateType(RefreshRateType) override {}
+ void dump(std::string&) const override {}
};
-} // namespace scheduler
-} // namespace android
+} // namespace android::scheduler
diff --git a/services/surfaceflinger/version-script32.txt b/services/surfaceflinger/version-script32.txt
deleted file mode 100644
index 2340785..0000000
--- a/services/surfaceflinger/version-script32.txt
+++ /dev/null
@@ -1,12 +0,0 @@
-{
-global:
- EnsureFrontOfChain;
- AddSpecialSignalHandlerFn;
- RemoveSpecialSignalHandlerFn;
- bsd_signal;
- sigaction;
- signal;
- sigprocmask;
-local:
- *;
-};
diff --git a/services/surfaceflinger/version-script64.txt b/services/surfaceflinger/version-script64.txt
deleted file mode 100644
index acf3630..0000000
--- a/services/surfaceflinger/version-script64.txt
+++ /dev/null
@@ -1,11 +0,0 @@
-{
-global:
- EnsureFrontOfChain;
- AddSpecialSignalHandlerFn;
- RemoveSpecialSignalHandlerFn;
- sigaction;
- signal;
- sigprocmask;
-local:
- *;
-};
diff --git a/vulkan/README.md b/vulkan/README.md
index 0f66097..185aa39 100644
--- a/vulkan/README.md
+++ b/vulkan/README.md
@@ -2,6 +2,10 @@
This subdirectory contains Android's Vulkan loader, as well as some Vulkan-related tools useful to platform developers.
+## Documentation
+
+The former contents of doc/implementors_guide/ are now at https://source.android.com/devices/graphics/implement-vulkan.
+
## Coding Style
We follow the [Chromium coding style](https://www.chromium.org/developers/coding-style) for naming and formatting, except with four-space indentation instead of two spaces. In general, any C++ features supported by the prebuilt platform toolchain are allowed.
@@ -12,6 +16,7 @@
We generate several parts of the loader and tools driectly from the Vulkan Registry (external/vulkan-headers/registry/vk.xml). Code generation must be done manually because the generator is not part of the platform toolchain (yet?). Files named `foo_gen.*` are generated by the code generator.
- To run the generator:
-- Install Python3 (if not already installed)
-- `$ ./<path to>/frameworks/native/vulkan/scripts/code_generator.py`
+### Run The Code Generator
+
+Install Python3 (if not already installed) and execute below:
+`$ ./scripts/code_generator.py`
diff --git a/vulkan/doc/README b/vulkan/doc/README
deleted file mode 100644
index d1dc2e1..0000000
--- a/vulkan/doc/README
+++ /dev/null
@@ -1,2 +0,0 @@
-The former contents of implementors_guide/ are now at
-https://source.android.com/devices/graphics/implement-vulkan
diff --git a/vulkan/libvulkan/Android.bp b/vulkan/libvulkan/Android.bp
index 993b751..85ef475 100644
--- a/vulkan/libvulkan/Android.bp
+++ b/vulkan/libvulkan/Android.bp
@@ -75,6 +75,7 @@
header_libs: [
"hwvulkan_headers",
+ "libnativeloader-dummy-headers",
"vulkan_headers",
],
export_header_lib_headers: ["vulkan_headers"],
diff --git a/vulkan/libvulkan/driver.cpp b/vulkan/libvulkan/driver.cpp
index f596086..9a670f6 100644
--- a/vulkan/libvulkan/driver.cpp
+++ b/vulkan/libvulkan/driver.cpp
@@ -30,6 +30,7 @@
#include <cutils/properties.h>
#include <graphicsenv/GraphicsEnv.h>
#include <log/log.h>
+#include <nativeloader/dlext_namespaces.h>
#include <sys/prctl.h>
#include <utils/Timers.h>
#include <utils/Trace.h>
@@ -44,11 +45,6 @@
using namespace android::hardware::configstore;
using namespace android::hardware::configstore::V1_0;
-// TODO(b/37049319) Get this from a header once one exists
-extern "C" {
-android_namespace_t* android_get_exported_namespace(const char*);
-}
-
// #define ENABLE_ALLOC_CALLSTACKS 1
#if ENABLE_ALLOC_CALLSTACKS
#include <utils/CallStack.h>
diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp
index e5ac2de..d60eaa7 100644
--- a/vulkan/libvulkan/swapchain.cpp
+++ b/vulkan/libvulkan/swapchain.cpp
@@ -370,9 +370,6 @@
nullptr, //&first_composition_start_time,
nullptr, //&last_composition_start_time,
nullptr, //&composition_finish_time,
- // TODO(ianelliott): Maybe ask if this one is
- // supported, at startup time (since it may not be
- // supported):
&actual_present_time,
nullptr, //&dequeue_ready_time,
nullptr /*&reads_done_time*/);
@@ -399,7 +396,6 @@
return num_ready;
}
-// TODO(ianelliott): DEAL WITH RETURN VALUE (e.g. VK_INCOMPLETE)!!!
void copy_ready_timings(Swapchain& swapchain,
uint32_t* count,
VkPastPresentationTimingGOOGLE* timings) {
@@ -1773,6 +1769,10 @@
ATRACE_CALL();
Swapchain& swapchain = *SwapchainFromHandle(swapchain_handle);
+ if (swapchain.surface.swapchain_handle != swapchain_handle) {
+ return VK_ERROR_OUT_OF_DATE_KHR;
+ }
+
ANativeWindow* window = swapchain.surface.window.get();
VkResult result = VK_SUCCESS;
@@ -1783,8 +1783,15 @@
}
if (timings) {
- // TODO(ianelliott): plumb return value (e.g. VK_INCOMPLETE)
+ // Get the latest ready timing count before copying, since the copied
+ // timing info will be erased in copy_ready_timings function.
+ uint32_t n = get_num_ready_timings(swapchain);
copy_ready_timings(swapchain, count, timings);
+ // Check the *count here against the recorded ready timing count, since
+ // *count can be overwritten per spec describes.
+ if (*count < n) {
+ result = VK_INCOMPLETE;
+ }
} else {
*count = get_num_ready_timings(swapchain);
}
diff --git a/vulkan/vkjson/vkjson.cc b/vulkan/vkjson/vkjson.cc
index 3da4336..8f714d8 100644
--- a/vulkan/vkjson/vkjson.cc
+++ b/vulkan/vkjson/vkjson.cc
@@ -21,11 +21,14 @@
#include "vkjson.h"
#include <assert.h>
-#include <string.h>
#include <stdlib.h>
+#include <string.h>
-#include <cmath>
+#include <json/json.h>
+
+#include <algorithm>
#include <cinttypes>
+#include <cmath>
#include <cstdio>
#include <limits>
#include <memory>
@@ -33,8 +36,6 @@
#include <type_traits>
#include <utility>
-#include <json/json.h>
-
namespace {
inline bool IsIntegral(double value) {
@@ -46,6 +47,14 @@
#endif
}
+// Floating point fields of Vulkan structure use single precision. The string
+// output of max double value in c++ will be larger than Java double's infinity
+// value. Below fake double max/min values are only to serve the safe json text
+// parsing in between C++ and Java, becasue Java json library simply cannot
+// handle infinity.
+static const double SAFE_DOUBLE_MAX = 0.99 * std::numeric_limits<double>::max();
+static const double SAFE_DOUBLE_MIN = -SAFE_DOUBLE_MAX;
+
template <typename T> struct EnumTraits;
template <> struct EnumTraits<VkPhysicalDeviceType> {
static uint32_t min() { return VK_PHYSICAL_DEVICE_TYPE_BEGIN_RANGE; }
@@ -851,7 +860,8 @@
template <typename T, typename = EnableForArithmetic<T>>
inline Json::Value ToJsonValue(const T& value) {
- return Json::Value(static_cast<double>(value));
+ return Json::Value(
+ std::clamp(static_cast<double>(value), SAFE_DOUBLE_MIN, SAFE_DOUBLE_MAX));
}
inline Json::Value ToJsonValue(const uint64_t& value) {