Merge "Moved desiredPresentTime for BLAST into State"
diff --git a/cmds/atrace/atrace.cpp b/cmds/atrace/atrace.cpp
index 587d25f..5186ad3 100644
--- a/cmds/atrace/atrace.cpp
+++ b/cmds/atrace/atrace.cpp
@@ -171,6 +171,7 @@
{ OPT, "events/clk/clk_disable/enable" },
{ OPT, "events/clk/clk_enable/enable" },
{ OPT, "events/power/cpu_frequency_limits/enable" },
+ { OPT, "events/power/suspend_resume/enable" },
} },
{ "membus", "Memory Bus Utilization", 0, {
{ REQ, "events/memory_bus/enable" },
diff --git a/cmds/atrace/atrace.rc b/cmds/atrace/atrace.rc
index f1426b6..6e460a0 100644
--- a/cmds/atrace/atrace.rc
+++ b/cmds/atrace/atrace.rc
@@ -49,6 +49,8 @@
chmod 0666 /sys/kernel/tracing/events/power/cpu_frequency_limits/enable
chmod 0666 /sys/kernel/debug/tracing/events/power/gpu_frequency/enable
chmod 0666 /sys/kernel/tracing/events/power/gpu_frequency/enable
+ chmod 0666 /sys/kernel/debug/tracing/events/power/suspend_resume/enable
+ chmod 0666 /sys/kernel/tracing/events/power/suspend_resume/enable
chmod 0666 /sys/kernel/debug/tracing/events/cpufreq_interactive/enable
chmod 0666 /sys/kernel/tracing/events/cpufreq_interactive/enable
chmod 0666 /sys/kernel/debug/tracing/events/vmscan/mm_vmscan_direct_reclaim_begin/enable
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 3a0aa95..2044943 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -44,10 +44,12 @@
#include <unistd.h>
#include <chrono>
+#include <cmath>
#include <fstream>
#include <functional>
#include <future>
#include <memory>
+#include <numeric>
#include <regex>
#include <set>
#include <string>
@@ -116,8 +118,9 @@
// TODO: temporary variables and functions used during C++ refactoring
static Dumpstate& ds = Dumpstate::GetInstance();
static int RunCommand(const std::string& title, const std::vector<std::string>& full_command,
- const CommandOptions& options = CommandOptions::DEFAULT) {
- return ds.RunCommand(title, full_command, options);
+ const CommandOptions& options = CommandOptions::DEFAULT,
+ bool verbose_duration = false) {
+ return ds.RunCommand(title, full_command, options, verbose_duration);
}
// Reasonable value for max stats.
@@ -896,17 +899,17 @@
RunCommand(
"EVENT LOG",
{"logcat", "-b", "events", "-v", "threadtime", "-v", "printable", "-v", "uid", "-d", "*:v"},
- CommandOptions::WithTimeoutInMs(timeout_ms).Build());
+ CommandOptions::WithTimeoutInMs(timeout_ms).Build(), true /* verbose_duration */);
timeout_ms = logcat_timeout({"stats"});
RunCommand(
"STATS LOG",
{"logcat", "-b", "stats", "-v", "threadtime", "-v", "printable", "-v", "uid", "-d", "*:v"},
- CommandOptions::WithTimeoutInMs(timeout_ms).Build());
+ CommandOptions::WithTimeoutInMs(timeout_ms).Build(), true /* verbose_duration */);
timeout_ms = logcat_timeout({"radio"});
RunCommand(
"RADIO LOG",
{"logcat", "-b", "radio", "-v", "threadtime", "-v", "printable", "-v", "uid", "-d", "*:v"},
- CommandOptions::WithTimeoutInMs(timeout_ms).Build());
+ CommandOptions::WithTimeoutInMs(timeout_ms).Build(), true /* verbose_duration */);
RunCommand("LOG STATISTICS", {"logcat", "-b", "all", "-S"});
@@ -1232,6 +1235,45 @@
}
}
+static void DumpExternalFragmentationInfo() {
+ struct stat st;
+ if (stat("/proc/buddyinfo", &st) != 0) {
+ MYLOGE("Unable to dump external fragmentation info\n");
+ return;
+ }
+
+ printf("------ EXTERNAL FRAGMENTATION INFO ------\n");
+ std::ifstream ifs("/proc/buddyinfo");
+ auto unusable_index_regex = std::regex{"Node\\s+([0-9]+),\\s+zone\\s+(\\S+)\\s+(.*)"};
+ for (std::string line; std::getline(ifs, line);) {
+ std::smatch match_results;
+ if (std::regex_match(line, match_results, unusable_index_regex)) {
+ std::stringstream free_pages(std::string{match_results[3]});
+ std::vector<int> free_pages_per_order(std::istream_iterator<int>{free_pages},
+ std::istream_iterator<int>());
+
+ int total_free_pages = 0;
+ for (size_t i = 0; i < free_pages_per_order.size(); i++) {
+ total_free_pages += (free_pages_per_order[i] * std::pow(2, i));
+ }
+
+ printf("Node %s, zone %8s", match_results[1].str().c_str(),
+ match_results[2].str().c_str());
+
+ int usable_free_pages = total_free_pages;
+ for (size_t i = 0; i < free_pages_per_order.size(); i++) {
+ auto unusable_index = (total_free_pages - usable_free_pages) /
+ static_cast<double>(total_free_pages);
+ printf(" %5.3f", unusable_index);
+ usable_free_pages -= (free_pages_per_order[i] * std::pow(2, i));
+ }
+
+ printf("\n");
+ }
+ }
+ printf("\n");
+}
+
// Dumps various things. Returns early with status USER_CONSENT_DENIED if user denies consent
// via the consent they are shown. Ignores other errors that occur while running various
// commands. The consent checking is currently done around long running tasks, which happen to
@@ -1258,7 +1300,7 @@
DumpFile("ZONEINFO", "/proc/zoneinfo");
DumpFile("PAGETYPEINFO", "/proc/pagetypeinfo");
DumpFile("BUDDYINFO", "/proc/buddyinfo");
- DumpFile("FRAGMENTATION INFO", "/d/extfrag/unusable_index");
+ DumpExternalFragmentationInfo();
DumpFile("KERNEL WAKE SOURCES", "/d/wakeup_sources");
DumpFile("KERNEL CPUFREQ", "/sys/devices/system/cpu/cpu0/cpufreq/stats/time_in_state");
@@ -1505,6 +1547,8 @@
static void DumpstateRadioCommon() {
DumpIpTablesAsRoot();
+ ds.AddDir(LOGPERSIST_DATA_DIR, false);
+
if (!DropRootUser()) {
return;
}
@@ -1515,6 +1559,7 @@
DoKmsg();
DumpIpAddrAndRules();
dump_route_tables();
+ DumpHals();
RunDumpsys("NETWORK DIAGNOSTICS", {"connectivity", "--diag"},
CommandOptions::WithTimeout(10).Build());
@@ -1584,8 +1629,6 @@
RunDumpsys("DUMPSYS", {"wifi"}, CommandOptions::WithTimeout(90).Build(),
SEC_TO_MSEC(10));
- DumpHals();
-
printf("========================================================\n");
printf("== dumpstate: done (id %d)\n", ds.id_);
printf("========================================================\n");
@@ -2814,8 +2857,8 @@
return singleton_;
}
-DurationReporter::DurationReporter(const std::string& title, bool logcat_only)
- : title_(title), logcat_only_(logcat_only) {
+DurationReporter::DurationReporter(const std::string& title, bool logcat_only, bool verbose)
+ : title_(title), logcat_only_(logcat_only), verbose_(verbose) {
if (!title_.empty()) {
started_ = Nanotime();
}
@@ -2824,7 +2867,7 @@
DurationReporter::~DurationReporter() {
if (!title_.empty()) {
float elapsed = (float)(Nanotime() - started_) / NANOS_PER_SEC;
- if (elapsed < .5f) {
+ if (elapsed < .5f && !verbose_) {
return;
}
MYLOGD("Duration of '%s': %.2fs\n", title_.c_str(), elapsed);
@@ -3417,8 +3460,8 @@
}
int Dumpstate::RunCommand(const std::string& title, const std::vector<std::string>& full_command,
- const CommandOptions& options) {
- DurationReporter duration_reporter(title);
+ const CommandOptions& options, bool verbose_duration) {
+ DurationReporter duration_reporter(title, false /* logcat_only */, verbose_duration);
int status = RunCommandToFd(STDOUT_FILENO, title, full_command, options);
diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h
index 77b5e8a..ccc9f42 100644
--- a/cmds/dumpstate/dumpstate.h
+++ b/cmds/dumpstate/dumpstate.h
@@ -73,13 +73,15 @@
*/
class DurationReporter {
public:
- explicit DurationReporter(const std::string& title, bool logcat_only = false);
+ explicit DurationReporter(const std::string& title, bool logcat_only = false,
+ bool verbose = false);
~DurationReporter();
private:
std::string title_;
bool logcat_only_;
+ bool verbose_;
uint64_t started_;
DISALLOW_COPY_AND_ASSIGN(DurationReporter);
@@ -224,7 +226,8 @@
*/
int RunCommand(const std::string& title, const std::vector<std::string>& fullCommand,
const android::os::dumpstate::CommandOptions& options =
- android::os::dumpstate::CommandOptions::DEFAULT);
+ android::os::dumpstate::CommandOptions::DEFAULT,
+ bool verbose_duration = false);
/*
* Runs `dumpsys` with the given arguments, automatically setting its timeout
diff --git a/cmds/installd/tests/installd_dexopt_test.cpp b/cmds/installd/tests/installd_dexopt_test.cpp
index 73780ec..0212bc5 100644
--- a/cmds/installd/tests/installd_dexopt_test.cpp
+++ b/cmds/installd/tests/installd_dexopt_test.cpp
@@ -275,7 +275,7 @@
writer.StartEntry("primary.prof", ZipWriter::kCompress);
writer.FinishEntry();
writer.Finish();
- close(fd);
+ fclose(file);
}
// Create the app user data.
diff --git a/cmds/servicemanager/ServiceManager.cpp b/cmds/servicemanager/ServiceManager.cpp
index 5f7dc25..f35f360 100644
--- a/cmds/servicemanager/ServiceManager.cpp
+++ b/cmds/servicemanager/ServiceManager.cpp
@@ -98,18 +98,12 @@
return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT);
}
+ // implicitly unlinked when the binder is removed
if (OK != binder->linkToDeath(this)) {
LOG(ERROR) << "Could not linkToDeath when adding " << name;
return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE);
}
- auto it = mNameToService.find(name);
- if (it != mNameToService.end()) {
- if (OK != it->second.binder->unlinkToDeath(this)) {
- LOG(WARNING) << "Could not unlinkToDeath when adding " << name;
- }
- }
-
mNameToService[name] = Service {
.binder = binder,
.allowIsolated = allowIsolated,
diff --git a/data/etc/car_core_hardware.xml b/data/etc/car_core_hardware.xml
index ad7791e..50f117d 100644
--- a/data/etc/car_core_hardware.xml
+++ b/data/etc/car_core_hardware.xml
@@ -40,7 +40,6 @@
<feature name="android.software.voice_recognizers" notLowRam="true" />
<feature name="android.software.backup" />
<feature name="android.software.home_screen" />
- <feature name="android.software.print" />
<feature name="android.software.companion_device_setup" />
<feature name="android.software.autofill" />
<feature name="android.software.cant_save_state" />
diff --git a/include/android/bitmap.h b/include/android/bitmap.h
index 2def64d..6fba0ac 100644
--- a/include/android/bitmap.h
+++ b/include/android/bitmap.h
@@ -60,6 +60,8 @@
ANDROID_BITMAP_FORMAT_RGBA_4444 = 7,
/** Alpha: 8 bits. */
ANDROID_BITMAP_FORMAT_A_8 = 8,
+ /** Each component is stored as a half float. **/
+ ANDROID_BITMAP_FORMAT_RGBA_F16 = 9,
};
/** Bitmap info, see AndroidBitmap_getInfo(). */
diff --git a/libs/binder/Binder.cpp b/libs/binder/Binder.cpp
index 268c85e..f3483ca 100644
--- a/libs/binder/Binder.cpp
+++ b/libs/binder/Binder.cpp
@@ -124,7 +124,6 @@
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
data.setDataPosition(0);
- data.setTransactingBinder(this);
status_t err = NO_ERROR;
switch (code) {
@@ -139,7 +138,6 @@
// In case this is being transacted on in the same process.
if (reply != nullptr) {
reply->setDataPosition(0);
- reply->setTransactingBinder(this);
}
return err;
diff --git a/libs/binder/BpBinder.cpp b/libs/binder/BpBinder.cpp
index 57440d5..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,14 +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;
- if (reply != nullptr) {
- reply->setTransactingBinder(this);
- }
-
return status;
}
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index 4487778..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>
@@ -170,11 +171,10 @@
status_t Parcel::finishFlattenBinder(
const sp<IBinder>& binder, const flat_binder_object& flat)
{
- internal::Stability::tryMarkCompilationUnit(binder.get());
-
status_t status = writeObject(flat, false);
if (status != OK) return status;
+ internal::Stability::tryMarkCompilationUnit(binder.get());
return writeInt32(internal::Stability::get(binder.get()));
}
@@ -185,10 +185,6 @@
status_t status = readInt32(&stability);
if (status != OK) return status;
- if (binder != nullptr && !internal::Stability::check(stability, mRequiredStability)) {
- return BAD_TYPE;
- }
-
status = internal::Stability::set(binder.get(), stability, true /*log*/);
if (status != OK) return status;
@@ -356,10 +352,6 @@
return NO_ERROR;
}
-void Parcel::setTransactingBinder(const sp<IBinder>& binder) const {
- mRequiredStability = internal::Stability::get(binder.get());
-}
-
status_t Parcel::setData(const uint8_t* buffer, size_t len)
{
if (len > INT32_MAX) {
@@ -2705,10 +2697,9 @@
mObjectsCapacity = 0;
mNextObjectHint = 0;
mObjectsSorted = false;
- mAllowFds = true;
mHasFds = false;
mFdsKnown = true;
- mRequiredStability = internal::Stability::UNDECLARED;
+ mAllowFds = true;
mOwner = nullptr;
mOpenAshmemSize = 0;
mWorkSourceRequestHeaderPosition = 0;
diff --git a/libs/binder/ProcessState.cpp b/libs/binder/ProcessState.cpp
index 1e1bc3a..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()
diff --git a/libs/binder/Stability.cpp b/libs/binder/Stability.cpp
index 0a10a1d..b6f10c8 100644
--- a/libs/binder/Stability.cpp
+++ b/libs/binder/Stability.cpp
@@ -32,6 +32,11 @@
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*/);
}
@@ -95,9 +100,9 @@
}
if (!stable) {
- ALOGE("Interface with %s cannot accept interface with %s.",
- stabilityString(required).c_str(),
- stabilityString(provided).c_str());
+ ALOGE("Cannot do a user transaction on a %s binder in a %s context.",
+ stabilityString(provided).c_str(),
+ stabilityString(required).c_str());
}
return stable;
diff --git a/libs/binder/include/binder/Binder.h b/libs/binder/include/binder/Binder.h
index 1537e69..dec75f5 100644
--- a/libs/binder/include/binder/Binder.h
+++ b/libs/binder/include/binder/Binder.h
@@ -38,7 +38,7 @@
virtual status_t transact( uint32_t code,
const Parcel& data,
Parcel* reply,
- uint32_t flags = 0);
+ uint32_t flags = 0) final;
// NOLINTNEXTLINE(google-default-arguments)
virtual status_t linkToDeath(const sp<DeathRecipient>& recipient,
diff --git a/libs/binder/include/binder/BpBinder.h b/libs/binder/include/binder/BpBinder.h
index e71541b..28599f4 100644
--- a/libs/binder/include/binder/BpBinder.h
+++ b/libs/binder/include/binder/BpBinder.h
@@ -45,7 +45,7 @@
virtual status_t transact( uint32_t code,
const Parcel& data,
Parcel* reply,
- uint32_t flags = 0);
+ uint32_t flags = 0) final;
// NOLINTNEXTLINE(google-default-arguments)
virtual status_t linkToDeath(const sp<DeathRecipient>& recipient,
diff --git a/libs/binder/include/binder/Parcel.h b/libs/binder/include/binder/Parcel.h
index 698fc07..f5aafc7 100644
--- a/libs/binder/include/binder/Parcel.h
+++ b/libs/binder/include/binder/Parcel.h
@@ -33,7 +33,6 @@
#include <binder/IInterface.h>
#include <binder/Parcelable.h>
-#include <binder/Stability.h>
// ---------------------------------------------------------------------------
namespace android {
@@ -69,8 +68,6 @@
void setDataPosition(size_t pos) const;
status_t setDataCapacity(size_t size);
- void setTransactingBinder(const sp<IBinder>& binder) const;
-
status_t setData(const uint8_t* buffer, size_t len);
status_t appendFrom(const Parcel *parcel,
@@ -475,15 +472,13 @@
size_t mObjectsCapacity;
mutable size_t mNextObjectHint;
mutable bool mObjectsSorted;
- bool mAllowFds;
mutable bool mRequestHeaderPresent;
mutable size_t mWorkSourceRequestHeaderPosition;
mutable bool mFdsKnown;
mutable bool mHasFds;
-
- mutable internal::Stability::Level mRequiredStability;
+ bool mAllowFds;
release_func mOwner;
void* mOwnerCookie;
diff --git a/libs/binder/include/binder/Stability.h b/libs/binder/include/binder/Stability.h
index 9d98c7f..f8240e4 100644
--- a/libs/binder/include/binder/Stability.h
+++ b/libs/binder/include/binder/Stability.h
@@ -20,6 +20,10 @@
#include <string>
namespace android {
+
+class BpBinder;
+class ProcessState;
+
namespace internal {
// WARNING: These APIs are only ever expected to be called by auto-generated code.
@@ -43,14 +47,30 @@
// 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 store stability level since this is more efficient than storing and looking
- // up the efficiency level of a binder object. So, we expose the underlying type.
+ // 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 : int16_t {
+ enum Level : int32_t {
UNDECLARED = 0,
VENDOR = 0b000011,
diff --git a/libs/binder/ndk/Android.bp b/libs/binder/ndk/Android.bp
index 6da3086..734a928 100644
--- a/libs/binder/ndk/Android.bp
+++ b/libs/binder/ndk/Android.bp
@@ -14,12 +14,12 @@
* limitations under the License.
*/
-cc_library {
+cc_library_shared {
name: "libbinder_ndk",
export_include_dirs: [
"include_ndk",
- "include_apex",
+ "include_platform",
],
cflags: [
@@ -33,6 +33,7 @@
"ibinder_jni.cpp",
"parcel.cpp",
"process.cpp",
+ "stability.cpp",
"status.cpp",
"service_manager.cpp",
],
@@ -54,7 +55,7 @@
version_script: "libbinder_ndk.map.txt",
stubs: {
symbol_file: "libbinder_ndk.map.txt",
- versions: ["29"],
+ versions: ["29", "30"],
},
}
@@ -79,6 +80,6 @@
symbol_file: "libbinder_ndk.map.txt",
export_include_dirs: [
"include_ndk",
- "include_apex",
+ "include_platform",
],
}
diff --git a/libs/binder/ndk/include_apex/android/binder_manager.h b/libs/binder/ndk/include_platform/android/binder_manager.h
similarity index 100%
rename from libs/binder/ndk/include_apex/android/binder_manager.h
rename to libs/binder/ndk/include_platform/android/binder_manager.h
diff --git a/libs/binder/ndk/include_apex/android/binder_process.h b/libs/binder/ndk/include_platform/android/binder_process.h
similarity index 100%
rename from libs/binder/ndk/include_apex/android/binder_process.h
rename to libs/binder/ndk/include_platform/android/binder_process.h
diff --git a/libs/binder/ndk/include_platform/android/binder_stability.h b/libs/binder/ndk/include_platform/android/binder_stability.h
new file mode 100644
index 0000000..e6aeb04
--- /dev/null
+++ b/libs/binder/ndk/include_platform/android/binder_stability.h
@@ -0,0 +1,52 @@
+/*
+ * 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 <android/binder_ibinder.h>
+
+__BEGIN_DECLS
+
+#ifdef __ANDROID_VNDK__
+
+/**
+ * This interface has the stability of the vendor image.
+ */
+void AIBinder_markVendorStability(AIBinder* binder);
+
+static inline void AIBinder_markCompilationUnitStability(AIBinder* binder) {
+ AIBinder_markVendorStability(binder);
+}
+
+#else // ndef defined __ANDROID_VNDK__
+
+/**
+ * This interface has the stability of the system image.
+ */
+void AIBinder_markSystemStability(AIBinder* binder);
+
+static inline void AIBinder_markCompilationUnitStability(AIBinder* binder) {
+ AIBinder_markSystemStability(binder);
+}
+
+#endif // ifdef __ANDROID_VNDK__
+
+/**
+ * This interface has system<->vendor stability
+ */
+void AIBinder_markVintfStability(AIBinder* binder);
+
+__END_DECLS
diff --git a/libs/binder/ndk/libbinder_ndk.map.txt b/libs/binder/ndk/libbinder_ndk.map.txt
index 4f685d1..feedde6 100644
--- a/libs/binder/ndk/libbinder_ndk.map.txt
+++ b/libs/binder/ndk/libbinder_ndk.map.txt
@@ -98,3 +98,12 @@
local:
*;
};
+
+LIBBINDER_NDK30 { # introduced=30
+ global:
+ AIBinder_markSystemStability; # apex
+ AIBinder_markVendorStability; # vndk
+ AIBinder_markVintfStability; # apex vndk
+ local:
+ *;
+};
diff --git a/libs/binder/ndk/stability.cpp b/libs/binder/ndk/stability.cpp
new file mode 100644
index 0000000..a5b3ece
--- /dev/null
+++ b/libs/binder/ndk/stability.cpp
@@ -0,0 +1,45 @@
+/*
+ * 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 <android/binder_stability.h>
+
+#include <binder/Stability.h>
+#include "ibinder_internal.h"
+
+#include <log/log.h>
+
+using ::android::internal::Stability;
+
+#ifdef __ANDROID_VNDK__
+#error libbinder_ndk should only be built in a system context
+#endif
+
+#ifdef __ANDROID_NDK__
+#error libbinder_ndk should only be built in a system context
+#endif
+
+// explicit extern because symbol is only declared in header when __ANDROID_VNDK__
+extern "C" void AIBinder_markVendorStability(AIBinder* binder) {
+ Stability::markVndk(binder->getBinder().get());
+}
+
+void AIBinder_markSystemStability(AIBinder* binder) {
+ Stability::markCompilationUnit(binder->getBinder().get());
+}
+
+void AIBinder_markVintfStability(AIBinder* binder) {
+ Stability::markVintf(binder->getBinder().get());
+}
diff --git a/libs/binder/ndk/test/Android.bp b/libs/binder/ndk/test/Android.bp
index 8cd4e03..bb1fe2f 100644
--- a/libs/binder/ndk/test/Android.bp
+++ b/libs/binder/ndk/test/Android.bp
@@ -44,10 +44,10 @@
"libandroid_runtime_lazy",
"libbase",
"libbinder",
+ "libbinder_ndk",
"libutils",
],
static_libs: [
- "libbinder_ndk",
"test_libbinder_ndk_library",
],
}
diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp
index 05db81e..bc457ce 100644
--- a/libs/binder/tests/Android.bp
+++ b/libs/binder/tests/Android.bp
@@ -138,17 +138,30 @@
test_suites: ["device-tests"],
}
+aidl_interface {
+ name: "binderStabilityTestIface",
+ srcs: [
+ "IBinderStabilityTest.aidl",
+ ],
+}
+
cc_test {
name: "binderStabilityTest",
defaults: ["binder_test_defaults"],
srcs: [
"binderStabilityTest.cpp",
- "IBinderStabilityTest.aidl",
],
shared_libs: [
+ "libbinder_ndk",
"libbinder",
+ "liblog",
"libutils",
],
+ static_libs: [
+ "binderStabilityTestIface-cpp",
+ "binderStabilityTestIface-ndk_platform",
+ ],
+
test_suites: ["device-tests"],
}
diff --git a/libs/binder/tests/IBinderStabilityTest.aidl b/libs/binder/tests/IBinderStabilityTest.aidl
index 7540ec9..36e1c2c 100644
--- a/libs/binder/tests/IBinderStabilityTest.aidl
+++ b/libs/binder/tests/IBinderStabilityTest.aidl
@@ -23,6 +23,10 @@
// DO NOT EVER IN A MILLION YEARS WRITE AN INTERFACE LIKE THIS!
// THIS IS ONLY FOR TESTING!
+ void sendAndCallBinder(IBinder binder);
+
+ // DO NOT EVER IN A MILLION YEARS WRITE AN INTERFACE LIKE THIS!
+ // THIS IS ONLY FOR TESTING!
IBinder returnNoStabilityBinder();
// DO NOT EVER IN A MILLION YEARS WRITE AN INTERFACE LIKE THIS!
@@ -32,6 +36,10 @@
// DO NOT EVER IN A MILLION YEARS WRITE AN INTERFACE LIKE THIS!
// THIS IS ONLY FOR TESTING!
IBinder returnVintfStabilityBinder();
+
+ // DO NOT EVER IN A MILLION YEARS WRITE AN INTERFACE LIKE THIS!
+ // THIS IS ONLY FOR TESTING!
+ IBinder returnVendorStabilityBinder();
}
// DO NOT EVER IN A MILLION YEARS WRITE AN INTERFACE LIKE THIS!
// THIS IS ONLY FOR TESTING!
diff --git a/libs/binder/tests/binderStabilityTest.cpp b/libs/binder/tests/binderStabilityTest.cpp
index 0218b94..0336b9e 100644
--- a/libs/binder/tests/binderStabilityTest.cpp
+++ b/libs/binder/tests/binderStabilityTest.cpp
@@ -14,7 +14,8 @@
* limitations under the License.
*/
-#include <android/os/IServiceManager.h>
+#include <android/binder_manager.h>
+#include <android/binder_stability.h>
#include <binder/Binder.h>
#include <binder/IBinder.h>
#include <binder/IPCThreadState.h>
@@ -25,155 +26,225 @@
#include <sys/prctl.h>
+#include "aidl/BnBinderStabilityTest.h"
#include "BnBinderStabilityTest.h"
-#include "BpBinderStabilityTest.h"
using namespace android;
+using namespace ndk;
using android::binder::Status;
-using android::os::IServiceManager;
+using android::internal::Stability; // for testing only!
-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");
+const String16 kSystemStabilityServer = String16("binder_stability_test_service_system");
-sp<IBinder> getCompilationUnitStability() {
- sp<IBinder> binder = new BBinder();
- // NO! NO! NO! NO! DO NOT EVERY DO SOMETHING LIKE THIS?
- // WHAT ARE YOU CRAZY? IT'S VERY DANGEROUS
- internal::Stability::markCompilationUnit(binder.get()); // <- BAD, NO! DO NOT COPY
- return binder;
-}
+// This is handwritten so that we can test different stability levels w/o having the AIDL
+// compiler assign them. Hand-writing binder interfaces is considered a bad practice
+// sanity reasons. YOU SHOULD DEFINE AN AIDL INTERFACE INSTEAD!
+class BadStableBinder : public BBinder {
+public:
+ static constexpr uint32_t USER_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION;
+ static String16 kDescriptor;
-sp<IBinder> getVintfStability() {
- sp<IBinder> binder = new BBinder();
- // NO! NO! NO! NO! DO NOT EVERY DO SOMETHING LIKE THIS?
- // WHAT ARE YOU CRAZY? IT'S VERY DANGEROUS
- internal::Stability::markVintf(binder.get()); // <- BAD, NO! DO NOT COPY
- return binder;
-}
+ bool gotUserTransaction = false;
+
+ static status_t doUserTransaction(const sp<IBinder>& binder) {
+ Parcel data, reply;
+ data.writeInterfaceToken(kDescriptor);
+ return binder->transact(USER_TRANSACTION, data, &reply, 0/*flags*/);
+ }
+
+ status_t onTransact(uint32_t code,
+ const Parcel& data, Parcel* reply, uint32_t flags) override {
+ if (code == USER_TRANSACTION) {
+ // not interested in this kind of stability. Make sure
+ // we have a test failure
+ LOG_ALWAYS_FATAL_IF(!data.enforceInterface(kDescriptor));
+
+ gotUserTransaction = true;
+
+ ALOGE("binder stability: Got user transaction");
+ return OK;
+ }
+ return BBinder::onTransact(code, data, reply, flags);
+ }
+
+ static sp<BadStableBinder> undef() {
+ sp<BadStableBinder> iface = new BadStableBinder();
+ return iface;
+ }
+
+ static sp<BadStableBinder> system() {
+ sp<BadStableBinder> iface = new BadStableBinder();
+ Stability::markCompilationUnit(iface.get()); // <- for test only
+ return iface;
+ }
+
+ static sp<BadStableBinder> vintf() {
+ sp<BadStableBinder> iface = new BadStableBinder();
+ Stability::markVintf(iface.get()); // <- for test only
+ return iface;
+ }
+
+ static sp<BadStableBinder> vendor() {
+ sp<BadStableBinder> iface = new BadStableBinder();
+ Stability::markVndk(iface.get()); // <- for test only
+ return iface;
+ }
+};
+String16 BadStableBinder::kDescriptor = String16("BadStableBinder.test");
// 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 {
+class MyBinderStabilityTest : public BnBinderStabilityTest {
public:
Status sendBinder(const sp<IBinder>& /*binder*/) override {
return Status::ok();
}
+ Status sendAndCallBinder(const sp<IBinder>& binder) override {
+ Stability::debugLogStability("sendAndCallBinder got binder", binder);
+ return Status::fromExceptionCode(BadStableBinder::doUserTransaction(binder));
+ }
Status returnNoStabilityBinder(sp<IBinder>* _aidl_return) override {
- *_aidl_return = new BBinder();
+ *_aidl_return = BadStableBinder::undef();
return Status::ok();
}
Status returnLocalStabilityBinder(sp<IBinder>* _aidl_return) override {
- *_aidl_return = getCompilationUnitStability();
+ *_aidl_return = BadStableBinder::system();
return Status::ok();
}
Status returnVintfStabilityBinder(sp<IBinder>* _aidl_return) override {
- *_aidl_return = getVintfStability();
+ *_aidl_return = BadStableBinder::vintf();
return Status::ok();
}
-
- static sp<IBinderStabilityTest> getNoStabilityServer() {
- sp<IBinder> remote = new BadStabilityTester;
- return new BpBinderStabilityTest(remote);
- }
- static sp<IBinderStabilityTest> getCompilationUnitStabilityServer() {
- sp<IBinder> remote = new BadStabilityTester;
- internal::Stability::markCompilationUnit(remote.get());
- return new BpBinderStabilityTest(remote);
- }
- static sp<IBinderStabilityTest> getVintfStabilityServer() {
- sp<IBinder> remote = new BadStabilityTester;
- internal::Stability::markVintf(remote.get()); // <- BAD, NO! DO NOT COPY
- return new BpBinderStabilityTest(remote);
+ Status returnVendorStabilityBinder(sp<IBinder>* _aidl_return) override {
+ *_aidl_return = BadStableBinder::vendor();
+ return Status::ok();
}
};
-void checkLocalStabilityBinder(const sp<IBinderStabilityTest>& complServer) {
- // this binder should automatically be set to local stability
- EXPECT_TRUE(complServer->sendBinder(new BBinder()).isOk());
- EXPECT_TRUE(complServer->sendBinder(getCompilationUnitStability()).isOk());
- EXPECT_TRUE(complServer->sendBinder(getVintfStability()).isOk());
+TEST(BinderStability, CantCallVendorBinderInSystemContext) {
+ sp<IBinder> serverBinder = android::defaultServiceManager()->getService(kSystemStabilityServer);
+ auto server = interface_cast<IBinderStabilityTest>(serverBinder);
+
+ ASSERT_NE(nullptr, server.get());
+ ASSERT_NE(nullptr, IInterface::asBinder(server)->remoteBinder());
+
+ EXPECT_TRUE(server->sendBinder(BadStableBinder::undef()).isOk());
+ EXPECT_TRUE(server->sendBinder(BadStableBinder::system()).isOk());
+ EXPECT_TRUE(server->sendBinder(BadStableBinder::vintf()).isOk());
+ EXPECT_TRUE(server->sendBinder(BadStableBinder::vendor()).isOk());
+
+ {
+ sp<BadStableBinder> binder = BadStableBinder::undef();
+ EXPECT_TRUE(server->sendAndCallBinder(binder).isOk());
+ EXPECT_TRUE(binder->gotUserTransaction);
+ }
+ {
+ sp<BadStableBinder> binder = BadStableBinder::system();
+ EXPECT_TRUE(server->sendAndCallBinder(binder).isOk());
+ EXPECT_TRUE(binder->gotUserTransaction);
+ }
+ {
+ sp<BadStableBinder> binder = BadStableBinder::vintf();
+ EXPECT_TRUE(server->sendAndCallBinder(binder).isOk());
+ EXPECT_TRUE(binder->gotUserTransaction);
+ }
+ {
+ // !!! user-defined transaction may not be stable for remote server !!!
+ // !!! so, it does not work !!!
+ sp<BadStableBinder> binder = BadStableBinder::vendor();
+ EXPECT_EQ(BAD_TYPE, server->sendAndCallBinder(binder).exceptionCode());
+ EXPECT_FALSE(binder->gotUserTransaction);
+ }
sp<IBinder> out;
- // should automatically be set to local stability
- EXPECT_TRUE(complServer->returnNoStabilityBinder(&out).isOk());
- EXPECT_NE(nullptr, out.get());
+ EXPECT_TRUE(server->returnNoStabilityBinder(&out).isOk());
+ ASSERT_NE(nullptr, out.get());
+ EXPECT_EQ(OK, out->pingBinder());
+ EXPECT_EQ(OK, BadStableBinder::doUserTransaction(out));
- EXPECT_TRUE(complServer->returnLocalStabilityBinder(&out).isOk());
- EXPECT_NE(nullptr, out.get());
+ EXPECT_TRUE(server->returnLocalStabilityBinder(&out).isOk());
+ ASSERT_NE(nullptr, out.get());
+ EXPECT_EQ(OK, out->pingBinder());
+ EXPECT_EQ(OK, BadStableBinder::doUserTransaction(out));
- EXPECT_TRUE(complServer->returnVintfStabilityBinder(&out).isOk());
- EXPECT_NE(nullptr, out.get());
+ EXPECT_TRUE(server->returnVintfStabilityBinder(&out).isOk());
+ ASSERT_NE(nullptr, out.get());
+ EXPECT_EQ(OK, out->pingBinder());
+ EXPECT_EQ(OK, BadStableBinder::doUserTransaction(out));
+
+ EXPECT_TRUE(server->returnVendorStabilityBinder(&out).isOk());
+ ASSERT_NE(nullptr, out.get());
+
+ // !!! libbinder-defined transaction works !!!
+ EXPECT_EQ(OK, out->pingBinder());
+
+ // !!! user-defined transaction may not be stable !!!
+ // !!! so, it does not work !!!
+ EXPECT_EQ(BAD_TYPE, BadStableBinder::doUserTransaction(out));
}
-void checkHighStabilityServer(const sp<IBinderStabilityTest>& highStability) {
- EXPECT_FALSE(highStability->sendBinder(new BBinder()).isOk());
- EXPECT_FALSE(highStability->sendBinder(getCompilationUnitStability()).isOk());
- EXPECT_TRUE(highStability->sendBinder(getVintfStability()).isOk());
+// This is handwritten so that we can test different stability levels w/o having the AIDL
+// compiler assign them. Hand-writing binder interfaces is considered a bad practice
+// sanity reasons. YOU SHOULD DEFINE AN AIDL INTERFACE INSTEAD!
- sp<IBinder> out;
- EXPECT_FALSE(highStability->returnNoStabilityBinder(&out).isOk());
- EXPECT_EQ(nullptr, out.get());
+struct NdkBinderStable_DataClass {
+ bool gotUserTransaction = false;
+};
+void* NdkBadStableBinder_Class_onCreate(void* args) {
+ LOG_ALWAYS_FATAL_IF(args != nullptr, "Takes no args");
+ return static_cast<void*>(new NdkBinderStable_DataClass);
+}
+void NdkBadStableBinder_Class_onDestroy(void* userData) {
+ delete static_cast<NdkBinderStable_DataClass*>(userData);
+}
+NdkBinderStable_DataClass* NdkBadStableBinder_getUserData(AIBinder* binder) {
+ LOG_ALWAYS_FATAL_IF(binder == nullptr);
+ void* userData = AIBinder_getUserData(binder);
+ LOG_ALWAYS_FATAL_IF(userData == nullptr, "null data - binder is remote?");
- EXPECT_FALSE(highStability->returnLocalStabilityBinder(&out).isOk());
- EXPECT_EQ(nullptr, out.get());
+ return static_cast<NdkBinderStable_DataClass*>(userData);
+}
+binder_status_t NdkBadStableBinder_Class_onTransact(
+ AIBinder* binder, transaction_code_t code, const AParcel* /*in*/, AParcel* /*out*/) {
- EXPECT_TRUE(highStability->returnVintfStabilityBinder(&out).isOk());
- EXPECT_NE(nullptr, out.get());
+ if (code == BadStableBinder::USER_TRANSACTION) {
+ ALOGE("ndk binder stability: Got user transaction");
+ NdkBadStableBinder_getUserData(binder)->gotUserTransaction = true;
+ return STATUS_OK;
+ }
+
+ return STATUS_UNKNOWN_TRANSACTION;
}
-TEST(BinderStability, LocalNoStabilityServer) {
- // in practice, a low stability server is probably one that hasn't been rebuilt
- // or was written by hand.
- auto server = BadStabilityTester::getNoStabilityServer();
- ASSERT_NE(nullptr, IInterface::asBinder(server)->localBinder());
+static AIBinder_Class* kNdkBadStableBinder =
+ AIBinder_Class_define(String8(BadStableBinder::kDescriptor).c_str(),
+ NdkBadStableBinder_Class_onCreate,
+ NdkBadStableBinder_Class_onDestroy,
+ NdkBadStableBinder_Class_onTransact);
- // it should be considered to have local stability
- checkLocalStabilityBinder(server);
-}
+// for testing only to get around __ANDROID_VNDK__ guard.
+extern "C" void AIBinder_markVendorStability(AIBinder* binder); // <- BAD DO NOT COPY
-TEST(BinderStability, LocalLowStabilityServer) {
- auto server = BadStabilityTester::getCompilationUnitStabilityServer();
- ASSERT_NE(nullptr, IInterface::asBinder(server)->localBinder());
- checkLocalStabilityBinder(server);
-}
+TEST(BinderStability, NdkCantCallVendorBinderInSystemContext) {
+ SpAIBinder binder = SpAIBinder(AServiceManager_getService(
+ String8(kSystemStabilityServer).c_str()));
-TEST(BinderStability, LocalHighStabilityServer) {
- auto server = BadStabilityTester::getVintfStabilityServer();
- ASSERT_NE(nullptr, IInterface::asBinder(server)->localBinder());
- checkHighStabilityServer(server);
-}
-
-TEST(BinderStability, RemoteNoStabilityServer) {
- sp<IBinder> remoteBinder = android::defaultServiceManager()->getService(kNoStabilityServer);
- auto remoteServer = interface_cast<IBinderStabilityTest>(remoteBinder);
+ std::shared_ptr<aidl::IBinderStabilityTest> remoteServer =
+ aidl::IBinderStabilityTest::fromBinder(binder);
ASSERT_NE(nullptr, remoteServer.get());
- ASSERT_NE(nullptr, IInterface::asBinder(remoteServer)->remoteBinder());
- // it should be considered to have local stability
- checkLocalStabilityBinder(remoteServer);
-}
+ SpAIBinder comp = SpAIBinder(AIBinder_new(kNdkBadStableBinder, nullptr /*args*/));
+ EXPECT_TRUE(remoteServer->sendBinder(comp).isOk());
+ EXPECT_TRUE(remoteServer->sendAndCallBinder(comp).isOk());
+ EXPECT_TRUE(NdkBadStableBinder_getUserData(comp.get())->gotUserTransaction);
-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());
-
- checkLocalStabilityBinder(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());
-
- checkHighStabilityServer(remoteServer);
+ SpAIBinder vendor = SpAIBinder(AIBinder_new(kNdkBadStableBinder, nullptr /*args*/));
+ AIBinder_markVendorStability(vendor.get());
+ EXPECT_TRUE(remoteServer->sendBinder(vendor).isOk());
+ EXPECT_FALSE(remoteServer->sendAndCallBinder(vendor).isOk());
+ EXPECT_FALSE(NdkBadStableBinder_getUserData(vendor.get())->gotUserTransaction);
}
class MarksStabilityInConstructor : public BBinder {
@@ -181,7 +252,7 @@
static bool gDestructed;
MarksStabilityInConstructor() {
- internal::Stability::markCompilationUnit(this);
+ Stability::markCompilationUnit(this);
}
~MarksStabilityInConstructor() {
gDestructed = true;
@@ -204,6 +275,14 @@
ASSERT_TRUE(MarksStabilityInConstructor::gDestructed);
}
+TEST(BinderStability, RemarkDies) {
+ ASSERT_DEATH({
+ sp<IBinder> binder = new BBinder();
+ Stability::markCompilationUnit(binder.get()); // <-- only called for tests
+ Stability::markVndk(binder.get()); // <-- only called for tests
+ }, "Should only mark known object.");
+}
+
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
@@ -211,16 +290,8 @@
// 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);
+ sp<IBinder> server = new MyBinderStabilityTest;
+ android::defaultServiceManager()->addService(kSystemStabilityServer, server);
IPCThreadState::self()->joinThreadPool(true);
exit(1); // should not reach
diff --git a/libs/cputimeinstate/cputimeinstate.cpp b/libs/cputimeinstate/cputimeinstate.cpp
index 0e68e62..4c8d52e 100644
--- a/libs/cputimeinstate/cputimeinstate.cpp
+++ b/libs/cputimeinstate/cputimeinstate.cpp
@@ -22,6 +22,7 @@
#include <dirent.h>
#include <errno.h>
#include <inttypes.h>
+#include <sys/sysinfo.h>
#include <mutex>
#include <optional>
@@ -48,6 +49,7 @@
static std::mutex gInitializedMutex;
static bool gInitialized = false;
static uint32_t gNPolicies = 0;
+static uint32_t gNCpus = 0;
static std::vector<std::vector<uint32_t>> gPolicyFreqs;
static std::vector<std::vector<uint32_t>> gPolicyCpus;
static std::set<uint32_t> gAllFreqs;
@@ -85,6 +87,8 @@
std::lock_guard<std::mutex> guard(gInitializedMutex);
if (gInitialized) return true;
+ gNCpus = get_nprocs_conf();
+
struct dirent **dirlist;
const char basepath[] = "/sys/devices/system/cpu/cpufreq";
int ret = scandir(basepath, &dirlist, isPolicyFile, comparePolicyFiles);
@@ -140,6 +144,32 @@
// This function should *not* be called while tracking is already active; doing so is unnecessary
// and can lead to accounting errors.
bool startTrackingUidCpuFreqTimes() {
+ if (!initGlobals()) return false;
+
+ unique_fd fd(bpf_obj_get(BPF_FS_PATH "map_time_in_state_cpu_policy_map"));
+ if (fd < 0) return false;
+
+ for (uint32_t i = 0; i < gPolicyCpus.size(); ++i) {
+ for (auto &cpu : gPolicyCpus[i]) {
+ if (writeToMapEntry(fd, &cpu, &i, BPF_ANY)) return false;
+ }
+ }
+
+ unique_fd fd2(bpf_obj_get(BPF_FS_PATH "map_time_in_state_freq_to_idx_map"));
+ if (fd2 < 0) return false;
+ freq_idx_key_t key;
+ for (uint32_t i = 0; i < gNPolicies; ++i) {
+ key.policy = i;
+ for (uint32_t j = 0; j < gPolicyFreqs[i].size(); ++j) {
+ key.freq = gPolicyFreqs[i][j];
+ // Start indexes at 1 so that uninitialized state is distinguishable from lowest freq.
+ // The uid_times map still uses 0-based indexes, and the sched_switch program handles
+ // conversion between them, so this does not affect our map reading code.
+ uint32_t idx = j + 1;
+ if (writeToMapEntry(fd2, &key, &idx, BPF_ANY)) return false;
+ }
+ }
+
return attachTracepointProgram("sched", "sched_switch") &&
attachTracepointProgram("power", "cpu_frequency");
}
@@ -151,27 +181,33 @@
// where ti_j is the ns that uid spent running on the ith cluster at that cluster's jth lowest freq.
std::optional<std::vector<std::vector<uint64_t>>> getUidCpuFreqTimes(uint32_t uid) {
if (!gInitialized && !initGlobals()) return {};
- time_key_t key = {.uid = uid, .freq = 0};
- std::vector<std::vector<uint64_t>> out(gNPolicies);
- std::vector<uint32_t> idxs(gNPolicies, 0);
+ std::vector<std::vector<uint64_t>> out;
+ uint32_t maxFreqCount = 0;
+ for (const auto &freqList : gPolicyFreqs) {
+ if (freqList.size() > maxFreqCount) maxFreqCount = freqList.size();
+ out.emplace_back(freqList.size(), 0);
+ }
- val_t value;
- for (uint32_t freq : gAllFreqs) {
- key.freq = freq;
- int ret = findMapEntry(gMapFd, &key, &value);
- if (ret) {
- if (errno == ENOENT)
- memset(&value.ar, 0, sizeof(value.ar));
- else
- return {};
+ std::vector<val_t> vals(gNCpus);
+ time_key_t key = {.uid = uid};
+ for (uint32_t i = 0; i <= (maxFreqCount - 1) / FREQS_PER_ENTRY; ++i) {
+ key.bucket = i;
+ if (findMapEntry(gMapFd, &key, vals.data())) {
+ if (errno != ENOENT) return {};
+ continue;
}
- for (uint32_t i = 0; i < gNPolicies; ++i) {
- if (idxs[i] == gPolicyFreqs[i].size() || freq != gPolicyFreqs[i][idxs[i]]) continue;
- uint64_t time = 0;
- for (uint32_t cpu : gPolicyCpus[i]) time += value.ar[cpu];
- idxs[i] += 1;
- out[i].emplace_back(time);
+
+ auto offset = i * FREQS_PER_ENTRY;
+ auto nextOffset = (i + 1) * FREQS_PER_ENTRY;
+ for (uint32_t j = 0; j < gNPolicies; ++j) {
+ if (offset >= gPolicyFreqs[j].size()) continue;
+ auto begin = out[j].begin() + offset;
+ auto end = nextOffset < gPolicyFreqs[j].size() ? begin + FREQS_PER_ENTRY : out[j].end();
+
+ for (const auto &cpu : gPolicyCpus[j]) {
+ std::transform(begin, end, std::begin(vals[cpu].ar), begin, std::plus<uint64_t>());
+ }
}
}
@@ -187,47 +223,53 @@
std::optional<std::unordered_map<uint32_t, std::vector<std::vector<uint64_t>>>>
getUidsCpuFreqTimes() {
if (!gInitialized && !initGlobals()) return {};
-
- int fd = bpf_obj_get(BPF_FS_PATH "map_time_in_state_uid_times_map");
- if (fd < 0) return {};
- BpfMap<time_key_t, val_t> m(fd);
-
- std::vector<std::unordered_map<uint32_t, uint32_t>> policyFreqIdxs;
- for (uint32_t i = 0; i < gNPolicies; ++i) {
- std::unordered_map<uint32_t, uint32_t> freqIdxs;
- for (size_t j = 0; j < gPolicyFreqs[i].size(); ++j) freqIdxs[gPolicyFreqs[i][j]] = j;
- policyFreqIdxs.emplace_back(freqIdxs);
- }
+ time_key_t key, prevKey;
std::unordered_map<uint32_t, std::vector<std::vector<uint64_t>>> map;
- auto fn = [&map, &policyFreqIdxs](const time_key_t &key, const val_t &val,
- const BpfMap<time_key_t, val_t> &) {
- if (map.find(key.uid) == map.end()) {
- map[key.uid].resize(gNPolicies);
- for (uint32_t i = 0; i < gNPolicies; ++i) {
- map[key.uid][i].resize(gPolicyFreqs[i].size(), 0);
- }
- }
+ if (getFirstMapKey(gMapFd, &key)) {
+ if (errno == ENOENT) return map;
+ return std::nullopt;
+ }
- for (size_t policy = 0; policy < gNPolicies; ++policy) {
- for (const auto &cpu : gPolicyCpus[policy]) {
- auto freqIdx = policyFreqIdxs[policy][key.freq];
- map[key.uid][policy][freqIdx] += val.ar[cpu];
+ std::vector<std::vector<uint64_t>> mapFormat;
+ for (const auto &freqList : gPolicyFreqs) mapFormat.emplace_back(freqList.size(), 0);
+
+ std::vector<val_t> vals(gNCpus);
+ do {
+ if (findMapEntry(gMapFd, &key, vals.data())) return {};
+ if (map.find(key.uid) == map.end()) map.emplace(key.uid, mapFormat);
+
+ auto offset = key.bucket * FREQS_PER_ENTRY;
+ auto nextOffset = (key.bucket + 1) * FREQS_PER_ENTRY;
+ for (uint32_t i = 0; i < gNPolicies; ++i) {
+ if (offset >= gPolicyFreqs[i].size()) continue;
+ auto begin = map[key.uid][i].begin() + offset;
+ auto end = nextOffset < gPolicyFreqs[i].size() ? begin + FREQS_PER_ENTRY :
+ map[key.uid][i].end();
+ for (const auto &cpu : gPolicyCpus[i]) {
+ std::transform(begin, end, std::begin(vals[cpu].ar), begin, std::plus<uint64_t>());
}
}
- return android::netdutils::status::ok;
- };
- if (isOk(m.iterateWithValue(fn))) return map;
- return {};
+ prevKey = key;
+ } while (!getNextMapKey(gMapFd, &prevKey, &key));
+ if (errno != ENOENT) return {};
+ return map;
}
// Clear all time in state data for a given uid. Returns false on error, true otherwise.
bool clearUidCpuFreqTimes(uint32_t uid) {
if (!gInitialized && !initGlobals()) return false;
- time_key_t key = {.uid = uid, .freq = 0};
- std::vector<uint32_t> idxs(gNPolicies, 0);
- for (auto freq : gAllFreqs) {
- key.freq = freq;
+ time_key_t key = {.uid = uid};
+
+ uint32_t maxFreqCount = 0;
+ for (const auto &freqList : gPolicyFreqs) {
+ if (freqList.size() > maxFreqCount) maxFreqCount = freqList.size();
+ }
+
+ val_t zeros = {0};
+ std::vector<val_t> vals(gNCpus, zeros);
+ for (key.bucket = 0; key.bucket <= (maxFreqCount - 1) / FREQS_PER_ENTRY; ++key.bucket) {
+ if (writeToMapEntry(gMapFd, &key, vals.data(), BPF_EXIST) && errno != ENOENT) return false;
if (deleteMapEntry(gMapFd, &key) && errno != ENOENT) return false;
}
return true;
diff --git a/libs/cputimeinstate/testtimeinstate.cpp b/libs/cputimeinstate/testtimeinstate.cpp
index 6347de1..39007e4 100644
--- a/libs/cputimeinstate/testtimeinstate.cpp
+++ b/libs/cputimeinstate/testtimeinstate.cpp
@@ -126,10 +126,10 @@
ASSERT_GE(fd, 0);
time_key_t k;
ASSERT_FALSE(getFirstMapKey(fd, &k));
- val_t val;
- ASSERT_FALSE(findMapEntry(fd, &k, &val));
+ std::vector<val_t> vals(get_nprocs_conf());
+ ASSERT_FALSE(findMapEntry(fd, &k, vals.data()));
k.uid = uid;
- ASSERT_FALSE(writeToMapEntry(fd, &k, &val, BPF_NOEXIST));
+ ASSERT_FALSE(writeToMapEntry(fd, &k, vals.data(), BPF_NOEXIST));
}
auto times = getUidCpuFreqTimes(uid);
ASSERT_TRUE(times.has_value());
diff --git a/libs/cputimeinstate/timeinstate.h b/libs/cputimeinstate/timeinstate.h
index cf66ae7..41d0af0 100644
--- a/libs/cputimeinstate/timeinstate.h
+++ b/libs/cputimeinstate/timeinstate.h
@@ -18,11 +18,18 @@
#define BPF_FS_PATH "/sys/fs/bpf/"
+#define FREQS_PER_ENTRY 32
+
struct time_key_t {
uint32_t uid;
- uint32_t freq;
+ uint32_t bucket;
};
struct val_t {
- uint64_t ar[100];
+ uint64_t ar[FREQS_PER_ENTRY];
+};
+
+struct freq_idx_key_t {
+ uint32_t policy;
+ uint32_t freq;
};
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index e6b1beb..40621e3 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -795,14 +795,15 @@
}
SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setMetadata(
- const sp<SurfaceControl>& sc, uint32_t key, std::vector<uint8_t> data) {
+ const sp<SurfaceControl>& sc, uint32_t key, const Parcel& p) {
layer_state_t* s = getLayerState(sc);
if (!s) {
mStatus = BAD_INDEX;
return *this;
}
s->what |= layer_state_t::eMetadataChanged;
- s->metadata.mMap[key] = std::move(data);
+
+ s->metadata.mMap[key] = {p.data(), p.data() + p.dataSize()};
registerSurfaceControlForCallback(sc);
return *this;
diff --git a/libs/gui/include/gui/LayerMetadata.h b/libs/gui/include/gui/LayerMetadata.h
index 47f0ced..d58e019 100644
--- a/libs/gui/include/gui/LayerMetadata.h
+++ b/libs/gui/include/gui/LayerMetadata.h
@@ -22,7 +22,12 @@
namespace android {
-enum { METADATA_OWNER_UID = 1, METADATA_WINDOW_TYPE = 2, METADATA_TASK_ID = 3 };
+enum {
+ METADATA_OWNER_UID = 1,
+ METADATA_WINDOW_TYPE = 2,
+ METADATA_TASK_ID = 3,
+ METADATA_MOUSE_CURSOR = 4,
+};
struct LayerMetadata : public Parcelable {
std::unordered_map<uint32_t, std::vector<uint8_t>> mMap;
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 22ab62d..f303a03 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -379,8 +379,7 @@
Transaction& setCrop_legacy(const sp<SurfaceControl>& sc, const Rect& crop);
Transaction& setCornerRadius(const sp<SurfaceControl>& sc, float cornerRadius);
Transaction& setLayerStack(const sp<SurfaceControl>& sc, uint32_t layerStack);
- Transaction& setMetadata(const sp<SurfaceControl>& sc, uint32_t key,
- std::vector<uint8_t> data);
+ Transaction& setMetadata(const sp<SurfaceControl>& sc, uint32_t key, const Parcel& p);
// Defers applying any changes made in this transaction until the Layer
// identified by handle reaches the given frameNumber. If the Layer identified
// by handle is removed, then we will apply this transaction regardless of
diff --git a/libs/gui/tests/EndToEndNativeInputTest.cpp b/libs/gui/tests/EndToEndNativeInputTest.cpp
index ff1ba0a..386f731 100644
--- a/libs/gui/tests/EndToEndNativeInputTest.cpp
+++ b/libs/gui/tests/EndToEndNativeInputTest.cpp
@@ -410,6 +410,19 @@
bgSurface->expectTap(1, 1);
}
+TEST_F(InputSurfacesTest, input_respects_scaled_surface_insets_overflow) {
+ std::unique_ptr<InputSurface> fgSurface = makeSurface(100, 100);
+ // In case we pass the very big inset without any checking.
+ fgSurface->mInputInfo.surfaceInset = INT32_MAX;
+ fgSurface->showAt(100, 100);
+
+ fgSurface->doTransaction([&](auto &t, auto &sc) { t.setMatrix(sc, 2.0, 0, 0, 2.0); });
+
+ // expect no crash for overflow, and inset size to be clamped to surface size
+ injectTap(202, 202);
+ fgSurface->expectTap(1, 1);
+}
+
// Ensure we ignore transparent region when getting screen bounds when positioning input frame.
TEST_F(InputSurfacesTest, input_ignores_transparent_region) {
std::unique_ptr<InputSurface> surface = makeSurface(100, 100);
diff --git a/libs/input/tests/LatencyStatistics_test.cpp b/libs/input/tests/LatencyStatistics_test.cpp
index 6d1cab4..eb12d4e 100644
--- a/libs/input/tests/LatencyStatistics_test.cpp
+++ b/libs/input/tests/LatencyStatistics_test.cpp
@@ -18,6 +18,7 @@
#include <input/LatencyStatistics.h>
#include <cmath>
#include <limits>
+#include <thread>
namespace android {
namespace test {
@@ -65,6 +66,8 @@
LatencyStatistics stats{0min};
stats.addValue(5.0);
+ std::this_thread::sleep_for(1us);
+
ASSERT_EQ(stats.shouldReport(), true);
}
diff --git a/services/inputflinger/InputDispatcher.cpp b/services/inputflinger/InputDispatcher.cpp
index 019815c..1eb979e 100644
--- a/services/inputflinger/InputDispatcher.cpp
+++ b/services/inputflinger/InputDispatcher.cpp
@@ -48,10 +48,11 @@
#include <errno.h>
#include <inttypes.h>
#include <limits.h>
-#include <sstream>
#include <stddef.h>
#include <time.h>
#include <unistd.h>
+#include <queue>
+#include <sstream>
#include <android-base/chrono_utils.h>
#include <android-base/stringprintf.h>
@@ -358,7 +359,7 @@
// Ready to start a new event.
// If we don't already have a pending event, go grab one.
if (! mPendingEvent) {
- if (mInboundQueue.isEmpty()) {
+ if (mInboundQueue.empty()) {
if (isAppSwitchDue) {
// The inbound queue is empty so the app switch key we were waiting
// for will never arrive. Stop waiting for it.
@@ -383,7 +384,8 @@
}
} else {
// Inbound queue has at least one entry.
- mPendingEvent = mInboundQueue.dequeueAtHead();
+ mPendingEvent = mInboundQueue.front();
+ mInboundQueue.pop_front();
traceInboundQueueLengthLocked();
}
@@ -483,8 +485,8 @@
}
bool InputDispatcher::enqueueInboundEventLocked(EventEntry* entry) {
- bool needWake = mInboundQueue.isEmpty();
- mInboundQueue.enqueueAtTail(entry);
+ bool needWake = mInboundQueue.empty();
+ mInboundQueue.push_back(entry);
traceInboundQueueLengthLocked();
switch (entry->type) {
@@ -544,9 +546,10 @@
void InputDispatcher::addRecentEventLocked(EventEntry* entry) {
entry->refCount += 1;
- mRecentQueue.enqueueAtTail(entry);
- if (mRecentQueue.count() > RECENT_QUEUE_MAX_SIZE) {
- mRecentQueue.dequeueAtHead()->release();
+ mRecentQueue.push_back(entry);
+ if (mRecentQueue.size() > RECENT_QUEUE_MAX_SIZE) {
+ mRecentQueue.front()->release();
+ mRecentQueue.pop_front();
}
}
@@ -703,35 +706,33 @@
}
bool InputDispatcher::haveCommandsLocked() const {
- return !mCommandQueue.isEmpty();
+ return !mCommandQueue.empty();
}
bool InputDispatcher::runCommandsLockedInterruptible() {
- if (mCommandQueue.isEmpty()) {
+ if (mCommandQueue.empty()) {
return false;
}
do {
- CommandEntry* commandEntry = mCommandQueue.dequeueAtHead();
-
+ std::unique_ptr<CommandEntry> commandEntry = std::move(mCommandQueue.front());
+ mCommandQueue.pop_front();
Command command = commandEntry->command;
- command(*this, commandEntry); // commands are implicitly 'LockedInterruptible'
+ command(*this, commandEntry.get()); // commands are implicitly 'LockedInterruptible'
commandEntry->connection.clear();
- delete commandEntry;
- } while (! mCommandQueue.isEmpty());
+ } while (!mCommandQueue.empty());
return true;
}
-InputDispatcher::CommandEntry* InputDispatcher::postCommandLocked(Command command) {
- CommandEntry* commandEntry = new CommandEntry(command);
- mCommandQueue.enqueueAtTail(commandEntry);
- return commandEntry;
+void InputDispatcher::postCommandLocked(std::unique_ptr<CommandEntry> commandEntry) {
+ mCommandQueue.push_back(std::move(commandEntry));
}
void InputDispatcher::drainInboundQueueLocked() {
- while (! mInboundQueue.isEmpty()) {
- EventEntry* entry = mInboundQueue.dequeueAtHead();
+ while (!mInboundQueue.empty()) {
+ EventEntry* entry = mInboundQueue.front();
+ mInboundQueue.pop_front();
releaseInboundEventLocked(entry);
}
traceInboundQueueLengthLocked();
@@ -809,9 +810,10 @@
resetKeyRepeatLocked();
// Enqueue a command to run outside the lock to tell the policy that the configuration changed.
- CommandEntry* commandEntry =
- postCommandLocked(&InputDispatcher::doNotifyConfigurationChangedLockedInterruptible);
+ std::unique_ptr<CommandEntry> commandEntry = std::make_unique<CommandEntry>(
+ &InputDispatcher::doNotifyConfigurationChangedLockedInterruptible);
commandEntry->eventTime = entry->eventTime;
+ postCommandLocked(std::move(commandEntry));
return true;
}
@@ -883,7 +885,7 @@
// Give the policy a chance to intercept the key.
if (entry->interceptKeyResult == KeyEntry::INTERCEPT_KEY_RESULT_UNKNOWN) {
if (entry->policyFlags & POLICY_FLAG_PASS_TO_USER) {
- CommandEntry* commandEntry = postCommandLocked(
+ std::unique_ptr<CommandEntry> commandEntry = std::make_unique<CommandEntry>(
&InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible);
sp<InputWindowHandle> focusedWindowHandle =
getValueByKey(mFocusedWindowHandlesByDisplay, getTargetDisplayId(entry));
@@ -892,6 +894,7 @@
getInputChannelLocked(focusedWindowHandle->getToken());
}
commandEntry->keyEntry = entry;
+ postCommandLocked(std::move(commandEntry));
entry->refCount += 1;
return false; // wait for the command to run
} else {
@@ -1873,8 +1876,9 @@
// If the connection is backed up then keep waiting.
if (connection->inputPublisherBlocked) {
return StringPrintf("Waiting because the %s window's input channel is full. "
- "Outbound queue length: %d. Wait queue length: %d.",
- targetType, connection->outboundQueue.count(), connection->waitQueue.count());
+ "Outbound queue length: %zu. Wait queue length: %zu.",
+ targetType, connection->outboundQueue.size(),
+ connection->waitQueue.size());
}
// Ensure that the dispatch queues aren't too far backed up for this event.
@@ -1890,11 +1894,13 @@
// often anticipate pending UI changes when typing on a keyboard.
// To obtain this behavior, we must serialize key events with respect to all
// prior input events.
- if (!connection->outboundQueue.isEmpty() || !connection->waitQueue.isEmpty()) {
+ if (!connection->outboundQueue.empty() || !connection->waitQueue.empty()) {
return StringPrintf("Waiting to send key event because the %s window has not "
- "finished processing all of the input events that were previously "
- "delivered to it. Outbound queue length: %d. Wait queue length: %d.",
- targetType, connection->outboundQueue.count(), connection->waitQueue.count());
+ "finished processing all of the input events that were previously "
+ "delivered to it. Outbound queue length: %zu. Wait queue length: "
+ "%zu.",
+ targetType, connection->outboundQueue.size(),
+ connection->waitQueue.size());
}
} else {
// Touch events can always be sent to a window immediately because the user intended
@@ -1912,15 +1918,18 @@
// The one case where we pause input event delivery is when the wait queue is piling
// up with lots of events because the application is not responding.
// This condition ensures that ANRs are detected reliably.
- if (!connection->waitQueue.isEmpty()
- && currentTime >= connection->waitQueue.head->deliveryTime
- + STREAM_AHEAD_EVENT_TIMEOUT) {
+ if (!connection->waitQueue.empty() &&
+ currentTime >=
+ connection->waitQueue.front()->deliveryTime + STREAM_AHEAD_EVENT_TIMEOUT) {
return StringPrintf("Waiting to send non-key event because the %s window has not "
- "finished processing certain input events that were delivered to it over "
- "%0.1fms ago. Wait queue length: %d. Wait queue head age: %0.1fms.",
- targetType, STREAM_AHEAD_EVENT_TIMEOUT * 0.000001f,
- connection->waitQueue.count(),
- (currentTime - connection->waitQueue.head->deliveryTime) * 0.000001f);
+ "finished processing certain input events that were delivered to "
+ "it over "
+ "%0.1fms ago. Wait queue length: %zu. Wait queue head age: "
+ "%0.1fms.",
+ targetType, STREAM_AHEAD_EVENT_TIMEOUT * 0.000001f,
+ connection->waitQueue.size(),
+ (currentTime - connection->waitQueue.front()->deliveryTime) *
+ 0.000001f);
}
}
return "";
@@ -1982,10 +1991,11 @@
}
}
- CommandEntry* commandEntry =
- postCommandLocked(&InputDispatcher::doPokeUserActivityLockedInterruptible);
+ std::unique_ptr<CommandEntry> commandEntry =
+ std::make_unique<CommandEntry>(&InputDispatcher::doPokeUserActivityLockedInterruptible);
commandEntry->eventTime = eventEntry->eventTime;
commandEntry->userActivityEventType = eventType;
+ postCommandLocked(std::move(commandEntry));
}
void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime,
@@ -2053,7 +2063,7 @@
ATRACE_NAME(message.c_str());
}
- bool wasEmpty = connection->outboundQueue.isEmpty();
+ bool wasEmpty = connection->outboundQueue.empty();
// Enqueue dispatch entries for the requested modes.
enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
@@ -2070,7 +2080,7 @@
InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER);
// If the outbound queue was previously empty, start the dispatch cycle going.
- if (wasEmpty && !connection->outboundQueue.isEmpty()) {
+ if (wasEmpty && !connection->outboundQueue.empty()) {
startDispatchCycleLocked(currentTime, connection);
}
}
@@ -2173,7 +2183,7 @@
}
// Enqueue the dispatch entry.
- connection->outboundQueue.enqueueAtTail(dispatchEntry);
+ connection->outboundQueue.push_back(dispatchEntry);
traceOutboundQueueLength(connection);
}
@@ -2200,9 +2210,10 @@
return;
}
- CommandEntry* commandEntry =
- postCommandLocked(&InputDispatcher::doOnPointerDownOutsideFocusLockedInterruptible);
+ std::unique_ptr<CommandEntry> commandEntry = std::make_unique<CommandEntry>(
+ &InputDispatcher::doOnPointerDownOutsideFocusLockedInterruptible);
commandEntry->newToken = newToken;
+ postCommandLocked(std::move(commandEntry));
}
void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,
@@ -2217,9 +2228,8 @@
connection->getInputChannelName().c_str());
#endif
- while (connection->status == Connection::STATUS_NORMAL
- && !connection->outboundQueue.isEmpty()) {
- DispatchEntry* dispatchEntry = connection->outboundQueue.head;
+ while (connection->status == Connection::STATUS_NORMAL && !connection->outboundQueue.empty()) {
+ DispatchEntry* dispatchEntry = connection->outboundQueue.front();
dispatchEntry->deliveryTime = currentTime;
// Publish the event.
@@ -2301,7 +2311,7 @@
// Check the result.
if (status) {
if (status == WOULD_BLOCK) {
- if (connection->waitQueue.isEmpty()) {
+ if (connection->waitQueue.empty()) {
ALOGE("channel '%s' ~ Could not publish event because the pipe is full. "
"This is unexpected because the wait queue is empty, so the pipe "
"should be empty and we shouldn't have any problems writing an "
@@ -2327,9 +2337,11 @@
}
// Re-enqueue the event on the wait queue.
- connection->outboundQueue.dequeue(dispatchEntry);
+ connection->outboundQueue.erase(std::remove(connection->outboundQueue.begin(),
+ connection->outboundQueue.end(),
+ dispatchEntry));
traceOutboundQueueLength(connection);
- connection->waitQueue.enqueueAtTail(dispatchEntry);
+ connection->waitQueue.push_back(dispatchEntry);
traceWaitQueueLength(connection);
}
}
@@ -2360,9 +2372,9 @@
#endif
// Clear the dispatch queues.
- drainDispatchQueue(&connection->outboundQueue);
+ drainDispatchQueue(connection->outboundQueue);
traceOutboundQueueLength(connection);
- drainDispatchQueue(&connection->waitQueue);
+ drainDispatchQueue(connection->waitQueue);
traceWaitQueueLength(connection);
// The connection appears to be unrecoverably broken.
@@ -2377,9 +2389,10 @@
}
}
-void InputDispatcher::drainDispatchQueue(Queue<DispatchEntry>* queue) {
- while (!queue->isEmpty()) {
- DispatchEntry* dispatchEntry = queue->dequeueAtHead();
+void InputDispatcher::drainDispatchQueue(std::deque<DispatchEntry*>& queue) {
+ while (!queue.empty()) {
+ DispatchEntry* dispatchEntry = queue.front();
+ queue.pop_front();
releaseDispatchEntry(dispatchEntry);
}
}
@@ -2907,8 +2920,7 @@
policyFlags |= POLICY_FLAG_TRUSTED;
}
- EventEntry* firstInjectedEntry;
- EventEntry* lastInjectedEntry;
+ std::queue<EventEntry*> injectedEntries;
switch (event->getType()) {
case AINPUT_EVENT_TYPE_KEY: {
KeyEvent keyEvent;
@@ -2941,12 +2953,13 @@
}
mLock.lock();
- firstInjectedEntry = new KeyEntry(SYNTHESIZED_EVENT_SEQUENCE_NUM, keyEvent.getEventTime(),
- keyEvent.getDeviceId(), keyEvent.getSource(), keyEvent.getDisplayId(),
- policyFlags, action, flags,
- keyEvent.getKeyCode(), keyEvent.getScanCode(), keyEvent.getMetaState(),
- keyEvent.getRepeatCount(), keyEvent.getDownTime());
- lastInjectedEntry = firstInjectedEntry;
+ KeyEntry* injectedEntry =
+ new KeyEntry(SYNTHESIZED_EVENT_SEQUENCE_NUM, keyEvent.getEventTime(),
+ keyEvent.getDeviceId(), keyEvent.getSource(), keyEvent.getDisplayId(),
+ policyFlags, action, flags, keyEvent.getKeyCode(),
+ keyEvent.getScanCode(), keyEvent.getMetaState(),
+ keyEvent.getRepeatCount(), keyEvent.getDownTime());
+ injectedEntries.push(injectedEntry);
break;
}
@@ -2974,7 +2987,7 @@
mLock.lock();
const nsecs_t* sampleEventTimes = motionEvent->getSampleEventTimes();
const PointerCoords* samplePointerCoords = motionEvent->getSamplePointerCoords();
- firstInjectedEntry =
+ MotionEntry* injectedEntry =
new MotionEntry(SYNTHESIZED_EVENT_SEQUENCE_NUM, *sampleEventTimes,
motionEvent->getDeviceId(), motionEvent->getSource(),
motionEvent->getDisplayId(), policyFlags, action, actionButton,
@@ -2985,7 +2998,7 @@
motionEvent->getRawYCursorPosition(), motionEvent->getDownTime(),
uint32_t(pointerCount), pointerProperties, samplePointerCoords,
motionEvent->getXOffset(), motionEvent->getYOffset());
- lastInjectedEntry = firstInjectedEntry;
+ injectedEntries.push(injectedEntry);
for (size_t i = motionEvent->getHistorySize(); i > 0; i--) {
sampleEventTimes += 1;
samplePointerCoords += pointerCount;
@@ -3002,8 +3015,7 @@
motionEvent->getDownTime(), uint32_t(pointerCount),
pointerProperties, samplePointerCoords,
motionEvent->getXOffset(), motionEvent->getYOffset());
- lastInjectedEntry->next = nextInjectedEntry;
- lastInjectedEntry = nextInjectedEntry;
+ injectedEntries.push(nextInjectedEntry);
}
break;
}
@@ -3019,13 +3031,12 @@
}
injectionState->refCount += 1;
- lastInjectedEntry->injectionState = injectionState;
+ injectedEntries.back()->injectionState = injectionState;
bool needWake = false;
- for (EventEntry* entry = firstInjectedEntry; entry != nullptr; ) {
- EventEntry* nextEntry = entry->next;
- needWake |= enqueueInboundEventLocked(entry);
- entry = nextEntry;
+ while (!injectedEntries.empty()) {
+ needWake |= enqueueInboundEventLocked(injectedEntries.front());
+ injectedEntries.pop();
}
mLock.unlock();
@@ -3756,9 +3767,9 @@
nsecs_t currentTime = now();
// Dump recently dispatched or dropped events from oldest to newest.
- if (!mRecentQueue.isEmpty()) {
- dump += StringPrintf(INDENT "RecentQueue: length=%u\n", mRecentQueue.count());
- for (EventEntry* entry = mRecentQueue.head; entry; entry = entry->next) {
+ if (!mRecentQueue.empty()) {
+ dump += StringPrintf(INDENT "RecentQueue: length=%zu\n", mRecentQueue.size());
+ for (EventEntry* entry : mRecentQueue) {
dump += INDENT2;
entry->appendDescription(dump);
dump += StringPrintf(", age=%0.1fms\n",
@@ -3780,9 +3791,9 @@
}
// Dump inbound events from oldest to newest.
- if (!mInboundQueue.isEmpty()) {
- dump += StringPrintf(INDENT "InboundQueue: length=%u\n", mInboundQueue.count());
- for (EventEntry* entry = mInboundQueue.head; entry; entry = entry->next) {
+ if (!mInboundQueue.empty()) {
+ dump += StringPrintf(INDENT "InboundQueue: length=%zu\n", mInboundQueue.size());
+ for (EventEntry* entry : mInboundQueue) {
dump += INDENT2;
entry->appendDescription(dump);
dump += StringPrintf(", age=%0.1fms\n",
@@ -3815,11 +3826,10 @@
connection->getStatusLabel(), toString(connection->monitor),
toString(connection->inputPublisherBlocked));
- if (!connection->outboundQueue.isEmpty()) {
- dump += StringPrintf(INDENT3 "OutboundQueue: length=%u\n",
- connection->outboundQueue.count());
- for (DispatchEntry* entry = connection->outboundQueue.head; entry;
- entry = entry->next) {
+ if (!connection->outboundQueue.empty()) {
+ dump += StringPrintf(INDENT3 "OutboundQueue: length=%zu\n",
+ connection->outboundQueue.size());
+ for (DispatchEntry* entry : connection->outboundQueue) {
dump.append(INDENT4);
entry->eventEntry->appendDescription(dump);
dump += StringPrintf(", targetFlags=0x%08x, resolvedAction=%d, age=%0.1fms\n",
@@ -3830,11 +3840,10 @@
dump += INDENT3 "OutboundQueue: <empty>\n";
}
- if (!connection->waitQueue.isEmpty()) {
- dump += StringPrintf(INDENT3 "WaitQueue: length=%u\n",
- connection->waitQueue.count());
- for (DispatchEntry* entry = connection->waitQueue.head; entry;
- entry = entry->next) {
+ if (!connection->waitQueue.empty()) {
+ dump += StringPrintf(INDENT3 "WaitQueue: length=%zu\n",
+ connection->waitQueue.size());
+ for (DispatchEntry* entry : connection->waitQueue) {
dump += INDENT4;
entry->eventEntry->appendDescription(dump);
dump += StringPrintf(", targetFlags=0x%08x, resolvedAction=%d, "
@@ -4087,12 +4096,13 @@
void InputDispatcher::onDispatchCycleFinishedLocked(
nsecs_t currentTime, const sp<Connection>& connection, uint32_t seq, bool handled) {
- CommandEntry* commandEntry =
- postCommandLocked(&InputDispatcher::doDispatchCycleFinishedLockedInterruptible);
+ std::unique_ptr<CommandEntry> commandEntry = std::make_unique<CommandEntry>(
+ &InputDispatcher::doDispatchCycleFinishedLockedInterruptible);
commandEntry->connection = connection;
commandEntry->eventTime = currentTime;
commandEntry->seq = seq;
commandEntry->handled = handled;
+ postCommandLocked(std::move(commandEntry));
}
void InputDispatcher::onDispatchCycleBrokenLocked(
@@ -4100,19 +4110,21 @@
ALOGE("channel '%s' ~ Channel is unrecoverably broken and will be disposed!",
connection->getInputChannelName().c_str());
- CommandEntry* commandEntry =
- postCommandLocked(&InputDispatcher::doNotifyInputChannelBrokenLockedInterruptible);
+ std::unique_ptr<CommandEntry> commandEntry = std::make_unique<CommandEntry>(
+ &InputDispatcher::doNotifyInputChannelBrokenLockedInterruptible);
commandEntry->connection = connection;
+ postCommandLocked(std::move(commandEntry));
}
void InputDispatcher::onFocusChangedLocked(const sp<InputWindowHandle>& oldFocus,
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);
+ std::unique_ptr<CommandEntry> commandEntry = std::make_unique<CommandEntry>(
+ &InputDispatcher::doNotifyFocusChangedLockedInterruptible);
commandEntry->oldToken = oldToken;
commandEntry->newToken = newToken;
+ postCommandLocked(std::move(commandEntry));
}
void InputDispatcher::onANRLocked(
@@ -4142,12 +4154,13 @@
mLastANRState += StringPrintf(INDENT2 "Reason: %s\n", reason);
dumpDispatchStateLocked(mLastANRState);
- CommandEntry* commandEntry =
- postCommandLocked(&InputDispatcher::doNotifyANRLockedInterruptible);
+ std::unique_ptr<CommandEntry> commandEntry =
+ std::make_unique<CommandEntry>(&InputDispatcher::doNotifyANRLockedInterruptible);
commandEntry->inputApplicationHandle = applicationHandle;
commandEntry->inputChannel = windowHandle != nullptr ?
getInputChannelLocked(windowHandle->getToken()) : nullptr;
commandEntry->reason = reason;
+ postCommandLocked(std::move(commandEntry));
}
void InputDispatcher::doNotifyConfigurationChangedLockedInterruptible (
@@ -4242,10 +4255,12 @@
const bool handled = commandEntry->handled;
// Handle post-event policy actions.
- DispatchEntry* dispatchEntry = connection->findWaitQueueEntry(seq);
- if (!dispatchEntry) {
+ std::deque<InputDispatcher::DispatchEntry*>::iterator dispatchEntryIt =
+ connection->findWaitQueueEntry(seq);
+ if (dispatchEntryIt == connection->waitQueue.end()) {
return;
}
+ DispatchEntry* dispatchEntry = *dispatchEntryIt;
nsecs_t eventDuration = finishTime - dispatchEntry->deliveryTime;
if (eventDuration > SLOW_EVENT_PROCESSING_WARNING_TIMEOUT) {
@@ -4273,11 +4288,13 @@
// 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);
+ dispatchEntryIt = connection->findWaitQueueEntry(seq);
+ if (dispatchEntryIt != connection->waitQueue.end()) {
+ dispatchEntry = *dispatchEntryIt;
+ connection->waitQueue.erase(dispatchEntryIt);
traceWaitQueueLength(connection);
if (restartEvent && connection->status == Connection::STATUS_NORMAL) {
- connection->outboundQueue.enqueueAtHead(dispatchEntry);
+ connection->outboundQueue.push_front(dispatchEntry);
traceOutboundQueueLength(connection);
} else {
releaseDispatchEntry(dispatchEntry);
@@ -4496,7 +4513,7 @@
void InputDispatcher::traceInboundQueueLengthLocked() {
if (ATRACE_ENABLED()) {
- ATRACE_INT("iq", mInboundQueue.count());
+ ATRACE_INT("iq", mInboundQueue.size());
}
}
@@ -4504,7 +4521,7 @@
if (ATRACE_ENABLED()) {
char counterName[40];
snprintf(counterName, sizeof(counterName), "oq:%s", connection->getWindowName().c_str());
- ATRACE_INT(counterName, connection->outboundQueue.count());
+ ATRACE_INT(counterName, connection->outboundQueue.size());
}
}
@@ -4512,7 +4529,7 @@
if (ATRACE_ENABLED()) {
char counterName[40];
snprintf(counterName, sizeof(counterName), "wq:%s", connection->getWindowName().c_str());
- ATRACE_INT(counterName, connection->waitQueue.count());
+ ATRACE_INT(counterName, connection->waitQueue.size());
}
}
@@ -5148,13 +5165,14 @@
}
}
-InputDispatcher::DispatchEntry* InputDispatcher::Connection::findWaitQueueEntry(uint32_t seq) {
- for (DispatchEntry* entry = waitQueue.head; entry != nullptr; entry = entry->next) {
- if (entry->seq == seq) {
- return entry;
+std::deque<InputDispatcher::DispatchEntry*>::iterator
+InputDispatcher::Connection::findWaitQueueEntry(uint32_t seq) {
+ for (std::deque<DispatchEntry*>::iterator it = waitQueue.begin(); it != waitQueue.end(); it++) {
+ if ((*it)->seq == seq) {
+ return it;
}
}
- return nullptr;
+ return waitQueue.end();
}
// --- InputDispatcher::Monitor
diff --git a/services/inputflinger/InputDispatcher.h b/services/inputflinger/InputDispatcher.h
index 147437c..92e1e5f 100644
--- a/services/inputflinger/InputDispatcher.h
+++ b/services/inputflinger/InputDispatcher.h
@@ -33,9 +33,10 @@
#include <cutils/atomic.h>
#include <unordered_map>
+#include <limits.h>
#include <stddef.h>
#include <unistd.h>
-#include <limits.h>
+#include <deque>
#include <unordered_map>
#include "InputListener.h"
@@ -450,14 +451,6 @@
virtual status_t pilferPointers(const sp<IBinder>& token) override;
private:
- template <typename T>
- struct Link {
- T* next;
- T* prev;
-
- protected:
- inline Link() : next(nullptr), prev(nullptr) { }
- };
struct InjectionState {
mutable int32_t refCount;
@@ -475,7 +468,7 @@
~InjectionState();
};
- struct EventEntry : Link<EventEntry> {
+ struct EventEntry {
enum {
TYPE_CONFIGURATION_CHANGED,
TYPE_DEVICE_RESET,
@@ -592,7 +585,7 @@
};
// Tracks the progress of dispatching a particular event to a particular connection.
- struct DispatchEntry : Link<DispatchEntry> {
+ struct DispatchEntry {
const uint32_t seq; // unique sequence number, never 0
EventEntry* eventEntry; // the event to dispatch
@@ -647,7 +640,7 @@
typedef std::function<void(InputDispatcher&, CommandEntry*)> Command;
class Connection;
- struct CommandEntry : Link<CommandEntry> {
+ struct CommandEntry {
explicit CommandEntry(Command command);
~CommandEntry();
@@ -667,75 +660,6 @@
sp<IBinder> newToken;
};
- // Generic queue implementation.
- template <typename T>
- struct Queue {
- T* head;
- T* tail;
- uint32_t entryCount;
-
- inline Queue() : head(nullptr), tail(nullptr), entryCount(0) {
- }
-
- inline bool isEmpty() const {
- return !head;
- }
-
- inline void enqueueAtTail(T* entry) {
- entryCount++;
- entry->prev = tail;
- if (tail) {
- tail->next = entry;
- } else {
- head = entry;
- }
- entry->next = nullptr;
- tail = entry;
- }
-
- inline void enqueueAtHead(T* entry) {
- entryCount++;
- entry->next = head;
- if (head) {
- head->prev = entry;
- } else {
- tail = entry;
- }
- entry->prev = nullptr;
- head = entry;
- }
-
- inline void dequeue(T* entry) {
- entryCount--;
- if (entry->prev) {
- entry->prev->next = entry->next;
- } else {
- head = entry->next;
- }
- if (entry->next) {
- entry->next->prev = entry->prev;
- } else {
- tail = entry->prev;
- }
- }
-
- inline T* dequeueAtHead() {
- entryCount--;
- T* entry = head;
- head = entry->next;
- if (head) {
- head->prev = nullptr;
- } else {
- tail = nullptr;
- }
- return entry;
- }
-
- uint32_t count() const {
- return entryCount;
- }
- };
-
/* Specifies which events are to be canceled and why. */
struct CancelationOptions {
enum Mode {
@@ -886,11 +810,11 @@
bool inputPublisherBlocked;
// Queue of events that need to be published to the connection.
- Queue<DispatchEntry> outboundQueue;
+ std::deque<DispatchEntry*> outboundQueue;
// Queue of events that have been published to the connection but that have not
// yet received a "finished" response from the application.
- Queue<DispatchEntry> waitQueue;
+ std::deque<DispatchEntry*> waitQueue;
explicit Connection(const sp<InputChannel>& inputChannel, bool monitor);
@@ -899,7 +823,7 @@
const std::string getWindowName() const;
const char* getStatusLabel() const;
- DispatchEntry* findWaitQueueEntry(uint32_t seq);
+ std::deque<DispatchEntry*>::iterator findWaitQueueEntry(uint32_t seq);
};
struct Monitor {
@@ -927,9 +851,9 @@
sp<Looper> mLooper;
EventEntry* mPendingEvent GUARDED_BY(mLock);
- Queue<EventEntry> mInboundQueue GUARDED_BY(mLock);
- Queue<EventEntry> mRecentQueue GUARDED_BY(mLock);
- Queue<CommandEntry> mCommandQueue GUARDED_BY(mLock);
+ std::deque<EventEntry*> mInboundQueue GUARDED_BY(mLock);
+ std::deque<EventEntry*> mRecentQueue GUARDED_BY(mLock);
+ std::deque<std::unique_ptr<CommandEntry>> mCommandQueue GUARDED_BY(mLock);
DropReason mLastDropReason GUARDED_BY(mLock);
@@ -1029,7 +953,7 @@
// Deferred command processing.
bool haveCommandsLocked() const REQUIRES(mLock);
bool runCommandsLockedInterruptible() REQUIRES(mLock);
- CommandEntry* postCommandLocked(Command command) REQUIRES(mLock);
+ void postCommandLocked(std::unique_ptr<CommandEntry> commandEntry) REQUIRES(mLock);
// Input filter processing.
bool shouldSendKeyToInputFilterLocked(const NotifyKeyArgs* args) REQUIRES(mLock);
@@ -1221,7 +1145,7 @@
uint32_t seq, bool handled) REQUIRES(mLock);
void abortBrokenDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection,
bool notify) REQUIRES(mLock);
- void drainDispatchQueue(Queue<DispatchEntry>* queue);
+ void drainDispatchQueue(std::deque<DispatchEntry*>& queue);
void releaseDispatchEntry(DispatchEntry* dispatchEntry);
static int handleReceiveCallback(int fd, int events, void* data);
// The action sent should only be of type AMOTION_EVENT_*
diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
index c11b88e..14ed73d 100644
--- a/services/sensorservice/SensorService.cpp
+++ b/services/sensorservice/SensorService.cpp
@@ -299,14 +299,10 @@
}
void SensorService::setSensorAccess(uid_t uid, bool hasAccess) {
- SortedVector< sp<SensorEventConnection> > activeConnections;
- populateActiveConnections(&activeConnections);
- {
- Mutex::Autolock _l(mLock);
- for (size_t i = 0 ; i < activeConnections.size(); i++) {
- if (activeConnections[i] != nullptr && activeConnections[i]->getUid() == uid) {
- activeConnections[i]->setSensorAccess(hasAccess);
- }
+ ConnectionSafeAutolock connLock = mConnectionHolder.lock(mLock);
+ for (const sp<SensorEventConnection>& conn : connLock.getActiveConnections()) {
+ if (conn->getUid() == uid) {
+ conn->setSensorAccess(hasAccess);
}
}
}
@@ -360,7 +356,7 @@
if (args.size() > 2) {
return INVALID_OPERATION;
}
- Mutex::Autolock _l(mLock);
+ ConnectionSafeAutolock connLock = mConnectionHolder.lock(mLock);
SensorDevice& dev(SensorDevice::getInstance());
if (args.size() == 2 && args[0] == String16("restrict")) {
// If already in restricted mode. Ignore.
@@ -374,7 +370,7 @@
mCurrentOperatingMode = RESTRICTED;
// temporarily stop all sensor direct report and disable sensors
- disableAllSensorsLocked();
+ disableAllSensorsLocked(&connLock);
mWhiteListedPackage.setTo(String8(args[1]));
return status_t(NO_ERROR);
} else if (args.size() == 1 && args[0] == String16("enable")) {
@@ -382,7 +378,7 @@
if (mCurrentOperatingMode == RESTRICTED) {
mCurrentOperatingMode = NORMAL;
// enable sensors and recover all sensor direct report
- enableAllSensorsLocked();
+ enableAllSensorsLocked(&connLock);
}
if (mCurrentOperatingMode == DATA_INJECTION) {
resetToNormalModeLocked();
@@ -473,22 +469,18 @@
result.appendFormat("Sensor Privacy: %s\n",
mSensorPrivacyPolicy->isSensorPrivacyEnabled() ? "enabled" : "disabled");
- result.appendFormat("%zd active connections\n", mActiveConnections.size());
- for (size_t i=0 ; i < mActiveConnections.size() ; i++) {
- sp<SensorEventConnection> connection(mActiveConnections[i].promote());
- if (connection != nullptr) {
- result.appendFormat("Connection Number: %zu \n", i);
- connection->dump(result);
- }
+ const auto& activeConnections = connLock.getActiveConnections();
+ result.appendFormat("%zd active connections\n", activeConnections.size());
+ for (size_t i=0 ; i < activeConnections.size() ; i++) {
+ result.appendFormat("Connection Number: %zu \n", i);
+ activeConnections[i]->dump(result);
}
- result.appendFormat("%zd direct connections\n", mDirectConnections.size());
- for (size_t i = 0 ; i < mDirectConnections.size() ; i++) {
- sp<SensorDirectConnection> connection(mDirectConnections[i].promote());
- if (connection != nullptr) {
- result.appendFormat("Direct connection %zu:\n", i);
- connection->dump(result);
- }
+ const auto& directConnections = connLock.getDirectConnections();
+ result.appendFormat("%zd direct connections\n", directConnections.size());
+ for (size_t i = 0 ; i < directConnections.size() ; i++) {
+ result.appendFormat("Direct connection %zu:\n", i);
+ directConnections[i]->dump(result);
}
result.appendFormat("Previous Registrations:\n");
@@ -515,17 +507,14 @@
}
void SensorService::disableAllSensors() {
- Mutex::Autolock _l(mLock);
- disableAllSensorsLocked();
+ ConnectionSafeAutolock connLock = mConnectionHolder.lock(mLock);
+ disableAllSensorsLocked(&connLock);
}
-void SensorService::disableAllSensorsLocked() {
+void SensorService::disableAllSensorsLocked(ConnectionSafeAutolock* connLock) {
SensorDevice& dev(SensorDevice::getInstance());
- for (auto &i : mDirectConnections) {
- sp<SensorDirectConnection> connection(i.promote());
- if (connection != nullptr) {
- connection->stopAll(true /* backupRecord */);
- }
+ for (const sp<SensorDirectConnection>& connection : connLock->getDirectConnections()) {
+ connection->stopAll(true /* backupRecord */);
}
dev.disableAllSensors();
// Clear all pending flush connections for all active sensors. If one of the active
@@ -537,11 +526,11 @@
}
void SensorService::enableAllSensors() {
- Mutex::Autolock _l(mLock);
- enableAllSensorsLocked();
+ ConnectionSafeAutolock connLock = mConnectionHolder.lock(mLock);
+ enableAllSensorsLocked(&connLock);
}
-void SensorService::enableAllSensorsLocked() {
+void SensorService::enableAllSensorsLocked(ConnectionSafeAutolock* connLock) {
// sensors should only be enabled if the operating state is not restricted and sensor
// privacy is not enabled.
if (mCurrentOperatingMode == RESTRICTED || mSensorPrivacyPolicy->isSensorPrivacyEnabled()) {
@@ -552,14 +541,12 @@
}
SensorDevice& dev(SensorDevice::getInstance());
dev.enableAllSensors();
- for (auto &i : mDirectConnections) {
- sp<SensorDirectConnection> connection(i.promote());
- if (connection != nullptr) {
- connection->recoverAll();
- }
+ for (const sp<SensorDirectConnection>& connection : connLock->getDirectConnections()) {
+ connection->recoverAll();
}
}
+
// NOTE: This is a remote API - make sure all args are validated
status_t SensorService::shellCommand(int in, int out, int err, Vector<String16>& args) {
if (!checkCallingPermission(sManageSensorsPermission, nullptr, nullptr)) {
@@ -734,17 +721,8 @@
for (int i = 0; i < count; i++) {
mSensorEventBuffer[i].flags = 0;
}
+ ConnectionSafeAutolock connLock = mConnectionHolder.lock(mLock);
- // Make a copy of the connection vector as some connections may be removed during the course
- // of this loop (especially when one-shot sensor events are present in the sensor_event
- // buffer). Promote all connections to StrongPointers before the lock is acquired. If the
- // destructor of the sp gets called when the lock is acquired, it may result in a deadlock
- // as ~SensorEventConnection() needs to acquire mLock again for cleanup. So copy all the
- // strongPointers to a vector before the lock is acquired.
- SortedVector< sp<SensorEventConnection> > activeConnections;
- populateActiveConnections(&activeConnections);
-
- Mutex::Autolock _l(mLock);
// Poll has returned. Hold a wakelock if one of the events is from a wake up sensor. The
// rest of this loop is under a critical section protected by mLock. Acquiring a wakeLock,
// sending events to clients (incrementing SensorEventConnection::mWakeLockRefCount) should
@@ -818,6 +796,10 @@
}
}
+ // Cache the list of active connections, since we use it in multiple places below but won't
+ // modify it here
+ const std::vector<sp<SensorEventConnection>> activeConnections = connLock.getActiveConnections();
+
for (int i = 0; i < count; ++i) {
// Map flush_complete_events in the buffer to SensorEventConnections which called flush
// on the hardware sensor. mapFlushEventsToConnections[i] will be the
@@ -869,11 +851,8 @@
ALOGE("Dynamic sensor release error.");
}
- size_t numConnections = activeConnections.size();
- for (size_t i=0 ; i < numConnections; ++i) {
- if (activeConnections[i] != nullptr) {
- activeConnections[i]->removeSensor(handle);
- }
+ for (const sp<SensorEventConnection>& connection : activeConnections) {
+ connection->removeSensor(handle);
}
}
}
@@ -882,18 +861,14 @@
// Send our events to clients. Check the state of wake lock for each client and release the
// lock if none of the clients need it.
bool needsWakeLock = false;
- size_t numConnections = activeConnections.size();
- for (size_t i=0 ; i < numConnections; ++i) {
- if (activeConnections[i] != nullptr) {
- activeConnections[i]->sendEvents(mSensorEventBuffer, count, mSensorEventScratch,
- mMapFlushEventsToConnections);
- needsWakeLock |= activeConnections[i]->needsWakeLock();
- // If the connection has one-shot sensors, it may be cleaned up after first trigger.
- // Early check for one-shot sensors.
- if (activeConnections[i]->hasOneShotSensors()) {
- cleanupAutoDisabledSensorLocked(activeConnections[i], mSensorEventBuffer,
- count);
- }
+ for (const sp<SensorEventConnection>& connection : activeConnections) {
+ connection->sendEvents(mSensorEventBuffer, count, mSensorEventScratch,
+ mMapFlushEventsToConnections);
+ needsWakeLock |= connection->needsWakeLock();
+ // If the connection has one-shot sensors, it may be cleaned up after first trigger.
+ // Early check for one-shot sensors.
+ if (connection->hasOneShotSensors()) {
+ cleanupAutoDisabledSensorLocked(connection, mSensorEventBuffer, count);
}
}
@@ -912,17 +887,11 @@
}
void SensorService::resetAllWakeLockRefCounts() {
- SortedVector< sp<SensorEventConnection> > activeConnections;
- populateActiveConnections(&activeConnections);
- {
- Mutex::Autolock _l(mLock);
- for (size_t i=0 ; i < activeConnections.size(); ++i) {
- if (activeConnections[i] != nullptr) {
- activeConnections[i]->resetWakeLockRefCount();
- }
- }
- setWakeLockAcquiredLocked(false);
+ ConnectionSafeAutolock connLock = mConnectionHolder.lock(mLock);
+ for (const sp<SensorEventConnection>& connection : connLock.getActiveConnections()) {
+ connection->resetWakeLockRefCount();
}
+ setWakeLockAcquiredLocked(false);
}
void SensorService::setWakeLockAcquiredLocked(bool acquire) {
@@ -1144,9 +1113,7 @@
sp<SensorEventConnection> result(new SensorEventConnection(this, uid, connPackageName,
requestedMode == DATA_INJECTION, connOpPackageName, hasSensorAccess));
if (requestedMode == DATA_INJECTION) {
- if (mActiveConnections.indexOf(result) < 0) {
- mActiveConnections.add(result);
- }
+ mConnectionHolder.addEventConnectionIfNotPresent(result);
// Add the associated file descriptor to the Looper for polling whenever there is data to
// be injected.
result->updateLooperRegistration(mLooper);
@@ -1162,7 +1129,7 @@
sp<ISensorEventConnection> SensorService::createSensorDirectConnection(
const String16& opPackageName, uint32_t size, int32_t type, int32_t format,
const native_handle *resource) {
- Mutex::Autolock _l(mLock);
+ ConnectionSafeAutolock connLock = mConnectionHolder.lock(mLock);
// No new direct connections are allowed when sensor privacy is enabled
if (mSensorPrivacyPolicy->isSensorPrivacyEnabled()) {
@@ -1190,9 +1157,8 @@
}
// check for duplication
- for (auto &i : mDirectConnections) {
- sp<SensorDirectConnection> connection(i.promote());
- if (connection != nullptr && connection->isEquivalent(&mem)) {
+ for (const sp<SensorDirectConnection>& connection : connLock.getDirectConnections()) {
+ if (connection->isEquivalent(&mem)) {
ALOGE("Duplicate create channel request for the same share memory");
return nullptr;
}
@@ -1229,7 +1195,7 @@
return nullptr;
}
- SensorDirectConnection* conn = nullptr;
+ sp<SensorDirectConnection> conn;
SensorDevice& dev(SensorDevice::getInstance());
int channelHandle = dev.registerDirectChannel(&mem);
@@ -1246,7 +1212,7 @@
} else {
// add to list of direct connections
// sensor service should never hold pointer or sp of SensorDirectConnection object.
- mDirectConnections.add(wp<SensorDirectConnection>(conn));
+ mConnectionHolder.addDirectConnection(conn);
}
return conn;
}
@@ -1358,7 +1324,7 @@
}
void SensorService::cleanupConnection(SensorEventConnection* c) {
- Mutex::Autolock _l(mLock);
+ ConnectionSafeAutolock connLock = mConnectionHolder.lock(mLock);
const wp<SensorEventConnection> connection(c);
size_t size = mActiveSensors.size();
ALOGD_IF(DEBUG_CONNECTIONS, "%zu active sensors", size);
@@ -1391,10 +1357,10 @@
}
}
c->updateLooperRegistration(mLooper);
- mActiveConnections.remove(connection);
+ mConnectionHolder.removeEventConnection(connection);
BatteryService::cleanup(c->getUid());
if (c->needsWakeLock()) {
- checkWakeLockStateLocked();
+ checkWakeLockStateLocked(&connLock);
}
{
@@ -1414,7 +1380,7 @@
SensorDevice& dev(SensorDevice::getInstance());
dev.unregisterDirectChannel(c->getHalChannelHandle());
- mDirectConnections.remove(c);
+ mConnectionHolder.removeDirectConnection(c);
}
sp<SensorInterface> SensorService::getSensorInterfaceFromHandle(int handle) const {
@@ -1433,7 +1399,7 @@
return BAD_VALUE;
}
- Mutex::Autolock _l(mLock);
+ ConnectionSafeAutolock connLock = mConnectionHolder.lock(mLock);
if (mCurrentOperatingMode != NORMAL
&& !isWhiteListedPackage(connection->getPackageName())) {
return INVALID_OPERATION;
@@ -1484,7 +1450,7 @@
}
connection->sendEvents(&event, 1, nullptr);
if (!connection->needsWakeLock() && mWakeLockAcquired) {
- checkWakeLockStateLocked();
+ checkWakeLockStateLocked(&connLock);
}
}
}
@@ -1497,9 +1463,7 @@
BatteryService::enableSensor(connection->getUid(), handle);
// the sensor was added (which means it wasn't already there)
// so, see if this connection becomes active
- if (mActiveConnections.indexOf(connection) < 0) {
- mActiveConnections.add(connection);
- }
+ mConnectionHolder.addEventConnectionIfNotPresent(connection);
} else {
ALOGW("sensor %08x already enabled in connection %p (ignoring)",
handle, connection.get());
@@ -1603,7 +1567,7 @@
}
if (connection->hasAnySensor() == false) {
connection->updateLooperRegistration(mLooper);
- mActiveConnections.remove(connection);
+ mConnectionHolder.removeEventConnection(connection);
}
// see if this sensor becomes inactive
if (rec->removeConnection(connection)) {
@@ -1762,22 +1726,19 @@
}
void SensorService::checkWakeLockState() {
- Mutex::Autolock _l(mLock);
- checkWakeLockStateLocked();
+ ConnectionSafeAutolock connLock = mConnectionHolder.lock(mLock);
+ checkWakeLockStateLocked(&connLock);
}
-void SensorService::checkWakeLockStateLocked() {
+void SensorService::checkWakeLockStateLocked(ConnectionSafeAutolock* connLock) {
if (!mWakeLockAcquired) {
return;
}
bool releaseLock = true;
- for (size_t i=0 ; i<mActiveConnections.size() ; i++) {
- sp<SensorEventConnection> connection(mActiveConnections[i].promote());
- if (connection != nullptr) {
- if (connection->needsWakeLock()) {
- releaseLock = false;
- break;
- }
+ for (const sp<SensorEventConnection>& connection : connLock->getActiveConnections()) {
+ if (connection->needsWakeLock()) {
+ releaseLock = false;
+ break;
}
}
if (releaseLock) {
@@ -1793,17 +1754,6 @@
}
}
-void SensorService::populateActiveConnections(
- SortedVector< sp<SensorEventConnection> >* activeConnections) {
- Mutex::Autolock _l(mLock);
- for (size_t i=0 ; i < mActiveConnections.size(); ++i) {
- sp<SensorEventConnection> connection(mActiveConnections[i].promote());
- if (connection != nullptr) {
- activeConnections->add(connection);
- }
- }
-}
-
bool SensorService::isWhiteListedPackage(const String8& packageName) {
return (packageName.contains(mWhiteListedPackage.string()));
}
@@ -1938,4 +1888,62 @@
}
return binder::Status::ok();
}
-}; // namespace android
+
+SensorService::ConnectionSafeAutolock::ConnectionSafeAutolock(
+ SensorService::SensorConnectionHolder& holder, Mutex& mutex)
+ : mConnectionHolder(holder), mAutolock(mutex) {}
+
+template<typename ConnectionType>
+const std::vector<sp<ConnectionType>>& SensorService::ConnectionSafeAutolock::getConnectionsHelper(
+ const SortedVector<wp<ConnectionType>>& connectionList,
+ std::vector<std::vector<sp<ConnectionType>>>* referenceHolder) {
+ referenceHolder->emplace_back();
+ std::vector<sp<ConnectionType>>& connections = referenceHolder->back();
+ for (const wp<ConnectionType>& weakConnection : connectionList){
+ sp<ConnectionType> connection = weakConnection.promote();
+ if (connection != nullptr) {
+ connections.push_back(std::move(connection));
+ }
+ }
+ return connections;
+}
+
+const std::vector<sp<SensorService::SensorEventConnection>>&
+ SensorService::ConnectionSafeAutolock::getActiveConnections() {
+ return getConnectionsHelper(mConnectionHolder.mActiveConnections,
+ &mReferencedActiveConnections);
+}
+
+const std::vector<sp<SensorService::SensorDirectConnection>>&
+ SensorService::ConnectionSafeAutolock::getDirectConnections() {
+ return getConnectionsHelper(mConnectionHolder.mDirectConnections,
+ &mReferencedDirectConnections);
+}
+
+void SensorService::SensorConnectionHolder::addEventConnectionIfNotPresent(
+ const sp<SensorService::SensorEventConnection>& connection) {
+ if (mActiveConnections.indexOf(connection) < 0) {
+ mActiveConnections.add(connection);
+ }
+}
+
+void SensorService::SensorConnectionHolder::removeEventConnection(
+ const wp<SensorService::SensorEventConnection>& connection) {
+ mActiveConnections.remove(connection);
+}
+
+void SensorService::SensorConnectionHolder::addDirectConnection(
+ const sp<SensorService::SensorDirectConnection>& connection) {
+ mDirectConnections.add(connection);
+}
+
+void SensorService::SensorConnectionHolder::removeDirectConnection(
+ const wp<SensorService::SensorDirectConnection>& connection) {
+ mDirectConnections.remove(connection);
+}
+
+SensorService::ConnectionSafeAutolock SensorService::SensorConnectionHolder::lock(Mutex& mutex) {
+ return ConnectionSafeAutolock(*this, mutex);
+}
+
+} // namespace android
diff --git a/services/sensorservice/SensorService.h b/services/sensorservice/SensorService.h
index e6ec96d..060b5eb 100644
--- a/services/sensorservice/SensorService.h
+++ b/services/sensorservice/SensorService.h
@@ -20,6 +20,7 @@
#include "SensorList.h"
#include "RecentEventLogger.h"
+#include <android-base/macros.h>
#include <binder/AppOpsManager.h>
#include <binder/BinderService.h>
#include <binder/IUidObserver.h>
@@ -42,6 +43,7 @@
#include <sys/types.h>
#include <unordered_map>
#include <unordered_set>
+#include <vector>
#if __clang__
// Clang warns about SensorEventConnection::dump hiding BBinder::dump. The cause isn't fixable
@@ -95,10 +97,67 @@
friend class BinderService<SensorService>;
// nested class/struct for internal use
- class SensorRecord;
+ class ConnectionSafeAutolock;
+ class SensorConnectionHolder;
class SensorEventAckReceiver;
+ class SensorRecord;
class SensorRegistrationInfo;
+ // Promoting a SensorEventConnection or SensorDirectConnection from wp to sp must be done with
+ // mLock held, but destroying that sp must be done unlocked to avoid a race condition that
+ // causes a deadlock (remote dies while we hold a local sp, then our decStrong() call invokes
+ // the dtor -> cleanupConnection() tries to re-lock the mutex). This class ensures safe usage
+ // by wrapping a Mutex::Autolock on SensorService's mLock, plus vectors that hold promoted sp<>
+ // references until the lock is released, when they are safely destroyed.
+ // All read accesses to the connection lists in mConnectionHolder must be done via this class.
+ class ConnectionSafeAutolock final {
+ public:
+ // Returns a list of non-null promoted connection references
+ const std::vector<sp<SensorEventConnection>>& getActiveConnections();
+ const std::vector<sp<SensorDirectConnection>>& getDirectConnections();
+
+ private:
+ // Constructed via SensorConnectionHolder::lock()
+ friend class SensorConnectionHolder;
+ explicit ConnectionSafeAutolock(SensorConnectionHolder& holder, Mutex& mutex);
+ DISALLOW_IMPLICIT_CONSTRUCTORS(ConnectionSafeAutolock);
+
+ // NOTE: Order of these members is important, as the destructor for non-static members
+ // get invoked in the reverse order of their declaration. Here we are relying on the
+ // Autolock to be destroyed *before* the vectors, so the sp<> objects are destroyed without
+ // the lock held, which avoids the deadlock.
+ SensorConnectionHolder& mConnectionHolder;
+ std::vector<std::vector<sp<SensorEventConnection>>> mReferencedActiveConnections;
+ std::vector<std::vector<sp<SensorDirectConnection>>> mReferencedDirectConnections;
+ Mutex::Autolock mAutolock;
+
+ template<typename ConnectionType>
+ const std::vector<sp<ConnectionType>>& getConnectionsHelper(
+ const SortedVector<wp<ConnectionType>>& connectionList,
+ std::vector<std::vector<sp<ConnectionType>>>* referenceHolder);
+ };
+
+ // Encapsulates the collection of active SensorEventConection and SensorDirectConnection
+ // references. Write access is done through this class with mLock held, but all read access
+ // must be routed through ConnectionSafeAutolock.
+ class SensorConnectionHolder {
+ public:
+ void addEventConnectionIfNotPresent(const sp<SensorEventConnection>& connection);
+ void removeEventConnection(const wp<SensorEventConnection>& connection);
+
+ void addDirectConnection(const sp<SensorDirectConnection>& connection);
+ void removeDirectConnection(const wp<SensorDirectConnection>& connection);
+
+ // Pass in the mutex that protects this connection holder; acquires the lock and returns an
+ // object that can be used to safely read the lists of connections
+ ConnectionSafeAutolock lock(Mutex& mutex);
+
+ private:
+ friend class ConnectionSafeAutolock;
+ SortedVector< wp<SensorEventConnection> > mActiveConnections;
+ SortedVector< wp<SensorDirectConnection> > mDirectConnections;
+ };
+
// If accessing a sensor we need to make sure the UID has access to it. If
// the app UID is idle then it cannot access sensors and gets no trigger
// events, no on-change events, flush event behavior does not change, and
@@ -250,7 +309,7 @@
// method checks whether all the events from these wake up sensors have been delivered to the
// corresponding applications, if yes the wakelock is released.
void checkWakeLockState();
- void checkWakeLockStateLocked();
+ void checkWakeLockStateLocked(ConnectionSafeAutolock* connLock);
bool isWakeLockAcquired();
bool isWakeUpSensorEvent(const sensors_event_t& event) const;
@@ -268,10 +327,6 @@
// Send events from the event cache for this particular connection.
void sendEventsFromCache(const sp<SensorEventConnection>& connection);
- // Promote all weak referecences in mActiveConnections vector to strong references and add them
- // to the output vector.
- void populateActiveConnections( SortedVector< sp<SensorEventConnection> >* activeConnections);
-
// If SensorService is operating in RESTRICTED mode, only select whitelisted packages are
// allowed to register for or call flush on sensors. Typically only cts test packages are
// allowed.
@@ -306,10 +361,10 @@
// temporarily stops all active direct connections and disables all sensors
void disableAllSensors();
- void disableAllSensorsLocked();
+ void disableAllSensorsLocked(ConnectionSafeAutolock* connLock);
// restarts the previously stopped direct connections and enables all sensors
void enableAllSensors();
- void enableAllSensorsLocked();
+ void enableAllSensorsLocked(ConnectionSafeAutolock* connLock);
static uint8_t sHmacGlobalKey[128];
static bool sHmacGlobalKeyIsValid;
@@ -327,12 +382,13 @@
mutable Mutex mLock;
DefaultKeyedVector<int, SensorRecord*> mActiveSensors;
std::unordered_set<int> mActiveVirtualSensors;
- SortedVector< wp<SensorEventConnection> > mActiveConnections;
+ SensorConnectionHolder mConnectionHolder;
bool mWakeLockAcquired;
sensors_event_t *mSensorEventBuffer, *mSensorEventScratch;
+ // WARNING: these SensorEventConnection instances must not be promoted to sp, except via
+ // modification to add support for them in ConnectionSafeAutolock
wp<const SensorEventConnection> * mMapFlushEventsToConnections;
std::unordered_map<int, SensorServiceUtil::RecentEventLogger*> mRecentEvent;
- SortedVector< wp<SensorDirectConnection> > mDirectConnections;
Mode mCurrentOperatingMode;
// This packagaName is set when SensorService is in RESTRICTED or DATA_INJECTION mode. Only
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index 965d8f4..afb9cec 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -138,7 +138,6 @@
"Layer.cpp",
"LayerProtoHelper.cpp",
"LayerRejecter.cpp",
- "LayerStats.cpp",
"LayerVector.cpp",
"MonitoredProducer.cpp",
"NativeWindowSurface.cpp",
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index 87bec11..e9af9e2 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -167,7 +167,7 @@
}
return std::nullopt;
}
- bool blackOutLayer = (isProtected() && !targetSettings.supportProtectedContent) ||
+ bool blackOutLayer = (isProtected() && !targetSettings.supportsProtectedContent) ||
(isSecure() && !targetSettings.isSecure);
const State& s(getDrawingState());
auto& layer = *result;
@@ -668,6 +668,15 @@
return FloatRect(0, 0, bufWidth, bufHeight);
}
+void BufferLayer::latchAndReleaseBuffer() {
+ mRefreshPending = false;
+ if (hasReadyFrame()) {
+ bool ignored = false;
+ latchBuffer(ignored, systemTime(), 0 /* expectedPresentTime */);
+ }
+ releasePendingBuffer(systemTime());
+}
+
} // namespace android
#if defined(__gl_h_)
diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h
index c86acf0..fb8d7d0 100644
--- a/services/surfaceflinger/BufferLayer.h
+++ b/services/surfaceflinger/BufferLayer.h
@@ -48,7 +48,7 @@
class BufferLayer : public Layer {
public:
explicit BufferLayer(const LayerCreationArgs& args);
- ~BufferLayer() override;
+ virtual ~BufferLayer() override;
// -----------------------------------------------------------------------
// Overriden from Layer
@@ -103,6 +103,13 @@
// Returns the current scaling mode, unless mOverrideScalingMode
// is set, in which case, it returns mOverrideScalingMode
uint32_t getEffectiveScalingMode() const override;
+
+ // Calls latchBuffer if the buffer has a frame queued and then releases the buffer.
+ // This is used if the buffer is just latched and releases to free up the buffer
+ // and will not be shown on screen.
+ // Should only be called on the main thread.
+ void latchAndReleaseBuffer() override;
+
// -----------------------------------------------------------------------
// -----------------------------------------------------------------------
diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp
index 12be00f..5f494ff 100644
--- a/services/surfaceflinger/BufferQueueLayer.cpp
+++ b/services/surfaceflinger/BufferQueueLayer.cpp
@@ -412,14 +412,6 @@
// Interface implementation for BufferLayerConsumer::ContentsChangedListener
// -----------------------------------------------------------------------
-void BufferQueueLayer::fakeVsync() {
- mRefreshPending = false;
- bool ignored = false;
- latchBuffer(ignored, systemTime(), 0 /* expectedPresentTime */);
- usleep(16000);
- releasePendingBuffer(systemTime());
-}
-
void BufferQueueLayer::onFrameAvailable(const BufferItem& item) {
ATRACE_CALL();
// Add this buffer from our internal queue tracker
@@ -456,13 +448,7 @@
mFlinger->mInterceptor->saveBufferUpdate(this, item.mGraphicBuffer->getWidth(),
item.mGraphicBuffer->getHeight(), item.mFrameNumber);
- // If this layer is orphaned, then we run a fake vsync pulse so that
- // dequeueBuffer doesn't block indefinitely.
- if (isRemovedFromCurrentState()) {
- fakeVsync();
- } else {
- mFlinger->signalLayerUpdate();
- }
+ mFlinger->signalLayerUpdate();
mConsumer->onBufferAvailable(item);
}
diff --git a/services/surfaceflinger/BufferQueueLayer.h b/services/surfaceflinger/BufferQueueLayer.h
index 231a531..392b706 100644
--- a/services/surfaceflinger/BufferQueueLayer.h
+++ b/services/surfaceflinger/BufferQueueLayer.h
@@ -138,8 +138,6 @@
// thread-safe
std::atomic<int32_t> mQueuedFrames{0};
std::atomic<bool> mSidebandStreamChanged{false};
-
- void fakeVsync();
};
} // namespace android
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index c2ec9bf..e0804ff 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -51,6 +51,16 @@
mCurrentState.dataspace = ui::Dataspace::V0_SRGB;
}
+BufferStateLayer::~BufferStateLayer() {
+ if (mActiveBuffer != nullptr) {
+ // Ensure that mActiveBuffer is uncached from RenderEngine here, as
+ // RenderEngine may have been using the buffer as an external texture
+ // after the client uncached the buffer.
+ auto& engine(mFlinger->getRenderEngine());
+ engine.unbindExternalTextureBuffer(mActiveBuffer->getId());
+ }
+}
+
// -----------------------------------------------------------------------
// Interface implementation for Layer
// -----------------------------------------------------------------------
@@ -604,10 +614,6 @@
}
}
-void BufferStateLayer::bufferErased(const client_cache_t& clientCacheId) {
- mFlinger->getRenderEngine().unbindExternalTextureBuffer(clientCacheId.id);
-}
-
void BufferStateLayer::HwcSlotGenerator::bufferErased(const client_cache_t& clientCacheId) {
std::lock_guard lock(mMutex);
if (!clientCacheId.isValid()) {
diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h
index a17fcfd..0ee941e 100644
--- a/services/surfaceflinger/BufferStateLayer.h
+++ b/services/surfaceflinger/BufferStateLayer.h
@@ -35,6 +35,8 @@
public:
explicit BufferStateLayer(const LayerCreationArgs&);
+ ~BufferStateLayer() override;
+
// -----------------------------------------------------------------------
// Interface implementation for Layer
// -----------------------------------------------------------------------
@@ -102,9 +104,6 @@
bool fenceHasSignaled() const override;
bool framePresentTimeIsCurrent(nsecs_t expectedPresentTime) const override;
- // Inherit from ClientCache::ErasedRecipient
- void bufferErased(const client_cache_t& clientCacheId) override;
-
private:
nsecs_t getDesiredPresentTime() override;
std::shared_ptr<FenceTime> getCurrentFenceTime() const override;
diff --git a/services/surfaceflinger/ClientCache.cpp b/services/surfaceflinger/ClientCache.cpp
index 77f2f57..16fe27c 100644
--- a/services/surfaceflinger/ClientCache.cpp
+++ b/services/surfaceflinger/ClientCache.cpp
@@ -55,16 +55,16 @@
return true;
}
-void ClientCache::add(const client_cache_t& cacheId, const sp<GraphicBuffer>& buffer) {
+bool ClientCache::add(const client_cache_t& cacheId, const sp<GraphicBuffer>& buffer) {
auto& [processToken, id] = cacheId;
if (processToken == nullptr) {
ALOGE("failed to cache buffer: invalid process token");
- return;
+ return false;
}
if (!buffer) {
ALOGE("failed to cache buffer: invalid buffer");
- return;
+ return false;
}
std::lock_guard lock(mMutex);
@@ -77,13 +77,13 @@
token = processToken.promote();
if (!token) {
ALOGE("failed to cache buffer: invalid token");
- return;
+ return false;
}
status_t err = token->linkToDeath(mDeathRecipient);
if (err != NO_ERROR) {
ALOGE("failed to cache buffer: could not link to death");
- return;
+ return false;
}
auto [itr, success] =
mBuffers.emplace(processToken, std::unordered_map<uint64_t, ClientCacheBuffer>());
@@ -95,10 +95,11 @@
if (processBuffers.size() > BUFFER_CACHE_MAX_SIZE) {
ALOGE("failed to cache buffer: cache is full");
- return;
+ return false;
}
processBuffers[id].buffer = buffer;
+ return true;
}
void ClientCache::erase(const client_cache_t& cacheId) {
@@ -139,16 +140,17 @@
return buf->buffer;
}
-void ClientCache::registerErasedRecipient(const client_cache_t& cacheId,
+bool ClientCache::registerErasedRecipient(const client_cache_t& cacheId,
const wp<ErasedRecipient>& recipient) {
std::lock_guard lock(mMutex);
ClientCacheBuffer* buf = nullptr;
if (!getBuffer(cacheId, &buf)) {
ALOGE("failed to register erased recipient, could not retrieve buffer");
- return;
+ return false;
}
buf->recipients.insert(recipient);
+ return true;
}
void ClientCache::unregisterErasedRecipient(const client_cache_t& cacheId,
diff --git a/services/surfaceflinger/ClientCache.h b/services/surfaceflinger/ClientCache.h
index 9f057c4..aa6c80d 100644
--- a/services/surfaceflinger/ClientCache.h
+++ b/services/surfaceflinger/ClientCache.h
@@ -36,7 +36,7 @@
public:
ClientCache();
- void add(const client_cache_t& cacheId, const sp<GraphicBuffer>& buffer);
+ bool add(const client_cache_t& cacheId, const sp<GraphicBuffer>& buffer);
void erase(const client_cache_t& cacheId);
sp<GraphicBuffer> get(const client_cache_t& cacheId);
@@ -48,7 +48,7 @@
virtual void bufferErased(const client_cache_t& clientCacheId) = 0;
};
- void registerErasedRecipient(const client_cache_t& cacheId,
+ bool registerErasedRecipient(const client_cache_t& cacheId,
const wp<ErasedRecipient>& recipient);
void unregisterErasedRecipient(const client_cache_t& cacheId,
const wp<ErasedRecipient>& recipient);
diff --git a/services/surfaceflinger/ColorLayer.cpp b/services/surfaceflinger/ColorLayer.cpp
index b65d351..2ad7591 100644
--- a/services/surfaceflinger/ColorLayer.cpp
+++ b/services/surfaceflinger/ColorLayer.cpp
@@ -108,6 +108,10 @@
return mCompositionLayer;
}
+bool ColorLayer::isOpaque(const Layer::State& s) const {
+ return (s.flags & layer_state_t::eLayerOpaque) != 0;
+}
+
// ---------------------------------------------------------------------------
}; // namespace android
diff --git a/services/surfaceflinger/ColorLayer.h b/services/surfaceflinger/ColorLayer.h
index 015b939..c793142 100644
--- a/services/surfaceflinger/ColorLayer.h
+++ b/services/surfaceflinger/ColorLayer.h
@@ -39,6 +39,8 @@
void commitTransaction(const State& stateToCommit) override;
+ bool isOpaque(const Layer::State& s) const override;
+
protected:
/*
* compositionengine::LayerFE overrides
diff --git a/services/surfaceflinger/CompositionEngine/Android.bp b/services/surfaceflinger/CompositionEngine/Android.bp
index 6f076ad..ae6bdbc 100644
--- a/services/surfaceflinger/CompositionEngine/Android.bp
+++ b/services/surfaceflinger/CompositionEngine/Android.bp
@@ -94,6 +94,7 @@
"tests/LayerTest.cpp",
"tests/MockHWC2.cpp",
"tests/MockHWComposer.cpp",
+ "tests/MockPowerAdvisor.cpp",
"tests/OutputTest.cpp",
"tests/OutputLayerTest.cpp",
"tests/RenderSurfaceTest.cpp",
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayCreationArgs.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayCreationArgs.h
index 0b6b4e4..0778936 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayCreationArgs.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayCreationArgs.h
@@ -20,6 +20,7 @@
#include <optional>
#include "DisplayHardware/DisplayIdentification.h"
+#include "DisplayHardware/PowerAdvisor.h"
namespace android::compositionengine {
@@ -37,6 +38,10 @@
// Identifies the display to the HWC, if composition is supported by it
std::optional<DisplayId> displayId;
+
+ // Optional pointer to the power advisor interface, if one is needed for
+ // this display.
+ Hwc2::PowerAdvisor* powerAdvisor = nullptr;
};
/**
@@ -68,6 +73,10 @@
mArgs.displayId = displayId;
return *this;
}
+ DisplayCreationArgsBuilder& setPowerAdvisor(Hwc2::PowerAdvisor* powerAdvisor) {
+ mArgs.powerAdvisor = powerAdvisor;
+ return *this;
+ }
private:
DisplayCreationArgs mArgs;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
index 94fab1f..2a901ae 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
@@ -59,7 +59,7 @@
const bool isSecure;
// If set to true, the target buffer has protected content support.
- const bool supportProtectedContent;
+ const bool supportsProtectedContent;
// Modified by each call to prepareClientComposition to indicate the
// region of the target buffer that should be cleared.
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h
index d96d58c..d5763d5 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h
@@ -116,6 +116,12 @@
// The color transform
mat4 colorTransform;
bool colorTransformIsIdentity{true};
+
+ // True if the layer is completely opaque
+ bool isOpaque{true};
+
+ // True if the layer has protected content
+ bool hasProtectedContent{false};
};
} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
index 4dfcfa4..f73304d 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
@@ -22,6 +22,7 @@
#include <unordered_map>
#include <math/mat4.h>
+#include <renderengine/LayerSettings.h>
#include <ui/Fence.h>
#include <ui/GraphicTypes.h>
#include <ui/Region.h>
@@ -156,6 +157,12 @@
// Prepares a frame for display
virtual void prepareFrame() = 0;
+ // Performs client composition as needed for layers on the output. The
+ // output fence is set to a fence to signal when client composition is
+ // finished.
+ // Returns false if client composition cannot be performed.
+ virtual bool composeSurfaces(const Region& debugFence, base::unique_fd* outReadyFence) = 0;
+
// Posts the new frame, and sets release fences.
virtual void postFramebuffer() = 0;
@@ -163,7 +170,14 @@
virtual void setDisplayColorProfile(std::unique_ptr<DisplayColorProfile>) = 0;
virtual void setRenderSurface(std::unique_ptr<RenderSurface>) = 0;
virtual void chooseCompositionStrategy() = 0;
+ virtual bool getSkipColorTransform() const = 0;
virtual FrameFences presentAndGetFrameFences() = 0;
+ virtual std::vector<renderengine::LayerSettings> generateClientCompositionRequests(
+ bool supportsProtectedContent, Region& clearRegion) = 0;
+ virtual void appendRegionFlashRequests(
+ const Region& flashRegion,
+ std::vector<renderengine::LayerSettings>& clientCompositionLayers) = 0;
+ virtual void setExpensiveRenderingExpected(bool enabled) = 0;
};
} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h
index d7f00a9..5f62b32c 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h
@@ -93,6 +93,9 @@
// Applies a HWC device layer request
virtual void applyDeviceLayerRequest(Hwc2::IComposerClient::LayerRequest request) = 0;
+ // Returns true if the composition settings scale pixels
+ virtual bool needsFiltering() const = 0;
+
// Debugging
virtual void dump(std::string& result) const = 0;
};
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h
index 795061a..36e4aac 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h
@@ -23,6 +23,7 @@
#include "DisplayHardware/DisplayIdentification.h"
#include "DisplayHardware/HWComposer.h"
+#include "DisplayHardware/PowerAdvisor.h"
namespace android::compositionengine {
@@ -42,7 +43,9 @@
void setColorTransform(const mat4&) override;
void setColorMode(ui::ColorMode, ui::Dataspace, ui::RenderIntent, ui::Dataspace) override;
void chooseCompositionStrategy() override;
+ bool getSkipColorTransform() const override;
compositionengine::Output::FrameFences presentAndGetFrameFences() override;
+ void setExpensiveRenderingExpected(bool) override;
// compositionengine::Display overrides
const std::optional<DisplayId>& getId() const override;
@@ -65,9 +68,11 @@
private:
const bool mIsVirtual;
std::optional<DisplayId> mId;
+ Hwc2::PowerAdvisor* const mPowerAdvisor{nullptr};
};
std::shared_ptr<Display> createDisplay(const compositionengine::CompositionEngine&,
compositionengine::DisplayCreationArgs&&);
+
} // namespace impl
} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
index 5f4a764..3972f2b 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
@@ -77,6 +77,7 @@
void beginFrame() override;
void prepareFrame() override;
+ bool composeSurfaces(const Region&, base::unique_fd*) override;
void postFramebuffer() override;
// Testing
@@ -86,7 +87,13 @@
protected:
const CompositionEngine& getCompositionEngine() const;
void chooseCompositionStrategy() override;
+ bool getSkipColorTransform() const override;
compositionengine::Output::FrameFences presentAndGetFrameFences() override;
+ std::vector<renderengine::LayerSettings> generateClientCompositionRequests(
+ bool supportsProtectedContent, Region& clearRegion) override;
+ void appendRegionFlashRequests(const Region&,
+ std::vector<renderengine::LayerSettings>&) override;
+ void setExpensiveRenderingExpected(bool enabled) override;
void dumpBase(std::string&) const;
private:
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h
index d8ad02a..4c3f935 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h
@@ -55,6 +55,7 @@
void applyDeviceCompositionTypeChange(Hwc2::IComposerClient::Composition) override;
void prepareForDeviceLayerRequests() override;
void applyDeviceLayerRequest(Hwc2::IComposerClient::LayerRequest request) override;
+ bool needsFiltering() const override;
void dump(std::string& result) const override;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
index d494413..c944bec 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
@@ -77,8 +77,17 @@
MOCK_METHOD0(prepareFrame, void());
MOCK_METHOD0(chooseCompositionStrategy, void());
+ MOCK_METHOD2(composeSurfaces, bool(const Region&, base::unique_fd*));
+ MOCK_CONST_METHOD0(getSkipColorTransform, bool());
+
MOCK_METHOD0(postFramebuffer, void());
MOCK_METHOD0(presentAndGetFrameFences, compositionengine::Output::FrameFences());
+
+ MOCK_METHOD2(generateClientCompositionRequests,
+ std::vector<renderengine::LayerSettings>(bool, Region&));
+ MOCK_METHOD2(appendRegionFlashRequests,
+ void(const Region&, std::vector<renderengine::LayerSettings>&));
+ MOCK_METHOD1(setExpensiveRenderingExpected, void(bool));
};
} // 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 195648f..d8d637d 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h
@@ -46,6 +46,7 @@
MOCK_METHOD1(applyDeviceCompositionTypeChange, void(Hwc2::IComposerClient::Composition));
MOCK_METHOD0(prepareForDeviceLayerRequests, void());
MOCK_METHOD1(applyDeviceLayerRequest, void(Hwc2::IComposerClient::LayerRequest request));
+ MOCK_CONST_METHOD0(needsFiltering, bool());
MOCK_CONST_METHOD1(dump, void(std::string&));
};
diff --git a/services/surfaceflinger/CompositionEngine/src/Display.cpp b/services/surfaceflinger/CompositionEngine/src/Display.cpp
index 6831901..6cd392e 100644
--- a/services/surfaceflinger/CompositionEngine/src/Display.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Display.cpp
@@ -26,6 +26,7 @@
#include <utils/Trace.h>
#include "DisplayHardware/HWComposer.h"
+#include "DisplayHardware/PowerAdvisor.h"
namespace android::compositionengine::impl {
@@ -38,7 +39,8 @@
Display::Display(const CompositionEngine& compositionEngine, DisplayCreationArgs&& args)
: compositionengine::impl::Output(compositionEngine),
mIsVirtual(args.isVirtual),
- mId(args.displayId) {
+ mId(args.displayId),
+ mPowerAdvisor(args.powerAdvisor) {
editState().isSecure = args.isSecure;
}
@@ -160,6 +162,15 @@
state.usesDeviceComposition = !allLayersRequireClientComposition();
}
+bool Display::getSkipColorTransform() const {
+ if (!mId) {
+ return false;
+ }
+
+ auto& hwc = getCompositionEngine().getHwComposer();
+ return hwc.hasDisplayCapability(*mId, HWC2::DisplayCapability::SkipClientColorTransform);
+}
+
bool Display::anyLayersRequireClientComposition() const {
const auto& layers = getOutputLayersOrderedByZ();
return std::any_of(layers.cbegin(), layers.cend(),
@@ -240,4 +251,12 @@
return result;
}
+void Display::setExpensiveRenderingExpected(bool enabled) {
+ Output::setExpensiveRenderingExpected(enabled);
+
+ if (mPowerAdvisor && mId) {
+ mPowerAdvisor->setExpensiveRenderingExpected(*mId, enabled);
+ }
+}
+
} // namespace android::compositionengine::impl
diff --git a/services/surfaceflinger/CompositionEngine/src/LayerCompositionState.cpp b/services/surfaceflinger/CompositionEngine/src/LayerCompositionState.cpp
index 37d6eaa..0dc4bf1 100644
--- a/services/surfaceflinger/CompositionEngine/src/LayerCompositionState.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/LayerCompositionState.cpp
@@ -71,6 +71,8 @@
dumpVal(out, "color", state.color);
out.append("\n ");
+ dumpVal(out, "isOpaque", state.isOpaque);
+ dumpVal(out, "hasProtectedContent", state.hasProtectedContent);
dumpVal(out, "isColorspaceAgnostic", state.isColorspaceAgnostic);
dumpVal(out, "dataspace", toString(state.dataspace), state.dataspace);
dumpVal(out, "hdr metadata types", state.hdrMetadata.validTypes);
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index b411e0a..55fdacd 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -17,13 +17,20 @@
#include <android-base/stringprintf.h>
#include <compositionengine/CompositionEngine.h>
#include <compositionengine/DisplayColorProfile.h>
+#include <compositionengine/Layer.h>
#include <compositionengine/LayerFE.h>
#include <compositionengine/RenderSurface.h>
+#include <compositionengine/impl/LayerCompositionState.h>
#include <compositionengine/impl/Output.h>
#include <compositionengine/impl/OutputLayer.h>
+#include <renderengine/DisplaySettings.h>
+#include <renderengine/RenderEngine.h>
#include <ui/DebugUtils.h>
+#include <ui/HdrCapabilities.h>
#include <utils/Trace.h>
+#include "TracedOrdinal.h"
+
namespace android::compositionengine {
Output::~Output() = default;
@@ -73,10 +80,10 @@
dirtyEntireOutput();
}
-// TODO(lpique): Rename setSize() once more is moved.
+// TODO(b/121291683): Rename setSize() once more is moved.
void Output::setBounds(const ui::Size& size) {
mRenderSurface->setDisplaySize(size);
- // TODO(lpique): Rename mState.size once more is moved.
+ // TODO(b/121291683): Rename mState.size once more is moved.
mState.bounds = Rect(mRenderSurface->getSize());
dirtyEntireOutput();
@@ -292,6 +299,179 @@
mRenderSurface->prepareFrame(mState.usesClientComposition, mState.usesDeviceComposition);
}
+bool Output::composeSurfaces(const Region& debugRegion, base::unique_fd* readyFence) {
+ ATRACE_CALL();
+ ALOGV(__FUNCTION__);
+
+ const TracedOrdinal<bool> hasClientComposition = {"hasClientComposition",
+ mState.usesClientComposition};
+ if (!hasClientComposition) {
+ return true;
+ }
+
+ ALOGV("hasClientComposition");
+
+ auto& renderEngine = mCompositionEngine.getRenderEngine();
+ const bool supportsProtectedContent = renderEngine.supportsProtectedContent();
+
+ renderengine::DisplaySettings clientCompositionDisplay;
+ clientCompositionDisplay.physicalDisplay = mState.scissor;
+ clientCompositionDisplay.clip = mState.scissor;
+ clientCompositionDisplay.globalTransform = mState.transform.asMatrix4();
+ clientCompositionDisplay.orientation = mState.orientation;
+ clientCompositionDisplay.outputDataspace =
+ mDisplayColorProfile->hasWideColorGamut() ? mState.dataspace : ui::Dataspace::UNKNOWN;
+ clientCompositionDisplay.maxLuminance =
+ mDisplayColorProfile->getHdrCapabilities().getDesiredMaxLuminance();
+
+ // Compute the global color transform matrix.
+ if (!mState.usesDeviceComposition && !getSkipColorTransform()) {
+ clientCompositionDisplay.colorTransform = mState.colorTransformMat;
+ }
+
+ // Note: Updated by generateClientCompositionRequests
+ clientCompositionDisplay.clearRegion = Region::INVALID_REGION;
+
+ // Generate the client composition requests for the layers on this output.
+ std::vector<renderengine::LayerSettings> clientCompositionLayers =
+ generateClientCompositionRequests(supportsProtectedContent,
+ clientCompositionDisplay.clearRegion);
+ appendRegionFlashRequests(debugRegion, clientCompositionLayers);
+
+ // If we the display is secure, protected content support is enabled, and at
+ // least one layer has protected content, we need to use a secure back
+ // buffer.
+ if (mState.isSecure && supportsProtectedContent) {
+ bool needsProtected =
+ std::any_of(mOutputLayersOrderedByZ.begin(), mOutputLayersOrderedByZ.end(),
+ [](auto& layer) {
+ return layer->getLayer().getState().frontEnd.hasProtectedContent;
+ });
+ if (needsProtected != renderEngine.isProtected()) {
+ renderEngine.useProtectedContext(needsProtected);
+ }
+ if (needsProtected != mRenderSurface->isProtected() &&
+ needsProtected == renderEngine.isProtected()) {
+ mRenderSurface->setProtected(needsProtected);
+ }
+ }
+
+ base::unique_fd fd;
+ sp<GraphicBuffer> buf = mRenderSurface->dequeueBuffer(&fd);
+ if (buf == nullptr) {
+ ALOGW("Dequeuing buffer for display [%s] failed, bailing out of "
+ "client composition for this frame",
+ mName.c_str());
+ return false;
+ }
+
+ // We boost GPU frequency here because there will be color spaces conversion
+ // and it's expensive. We boost the GPU frequency so that GPU composition can
+ // finish in time. We must reset GPU frequency afterwards, because high frequency
+ // consumes extra battery.
+ const bool expensiveRenderingExpected =
+ clientCompositionDisplay.outputDataspace == ui::Dataspace::DISPLAY_P3;
+ if (expensiveRenderingExpected) {
+ setExpensiveRenderingExpected(true);
+ }
+
+ renderEngine.drawLayers(clientCompositionDisplay, clientCompositionLayers,
+ buf->getNativeBuffer(), /*useFramebufferCache=*/true, std::move(fd),
+ readyFence);
+
+ if (expensiveRenderingExpected) {
+ setExpensiveRenderingExpected(false);
+ }
+
+ return true;
+}
+
+std::vector<renderengine::LayerSettings> Output::generateClientCompositionRequests(
+ bool supportsProtectedContent, Region& clearRegion) {
+ std::vector<renderengine::LayerSettings> clientCompositionLayers;
+ ALOGV("Rendering client layers");
+
+ const Region viewportRegion(mState.viewport);
+ const bool useIdentityTransform = false;
+ bool firstLayer = true;
+ // Used when a layer clears part of the buffer.
+ Region dummyRegion;
+
+ for (auto& layer : mOutputLayersOrderedByZ) {
+ const auto& layerState = layer->getState();
+ const auto& layerFEState = layer->getLayer().getState().frontEnd;
+ auto& layerFE = layer->getLayerFE();
+
+ const Region clip(viewportRegion.intersect(layer->getState().visibleRegion));
+ ALOGV("Layer: %s", layerFE.getDebugName());
+ if (clip.isEmpty()) {
+ ALOGV(" Skipping for empty clip");
+ firstLayer = false;
+ continue;
+ }
+
+ bool clientComposition = layer->requiresClientComposition();
+
+ // We clear the client target for non-client composed layers if
+ // requested by the HWC. We skip this if the layer is not an opaque
+ // rectangle, as by definition the layer must blend with whatever is
+ // underneath. We also skip the first layer as the buffer target is
+ // guaranteed to start out cleared.
+ bool clearClientComposition =
+ layerState.clearClientTarget && layerFEState.isOpaque && !firstLayer;
+
+ ALOGV(" Composition type: client %d clear %d", clientComposition, clearClientComposition);
+
+ if (clientComposition || clearClientComposition) {
+ compositionengine::LayerFE::ClientCompositionTargetSettings targetSettings{
+ clip,
+ useIdentityTransform,
+ layer->needsFiltering() || mState.needsFiltering,
+ mState.isSecure,
+ supportsProtectedContent,
+ clientComposition ? clearRegion : dummyRegion,
+ };
+ if (auto result = layerFE.prepareClientComposition(targetSettings)) {
+ if (clearClientComposition) {
+ auto& layerSettings = *result;
+ layerSettings.source.buffer.buffer = nullptr;
+ layerSettings.source.solidColor = half3(0.0, 0.0, 0.0);
+ layerSettings.alpha = half(0.0);
+ layerSettings.disableBlending = true;
+ }
+
+ clientCompositionLayers.push_back(*result);
+ }
+ }
+
+ firstLayer = false;
+ }
+
+ return clientCompositionLayers;
+}
+
+void Output::appendRegionFlashRequests(
+ const Region& flashRegion,
+ std::vector<renderengine::LayerSettings>& clientCompositionLayers) {
+ if (flashRegion.isEmpty()) {
+ return;
+ }
+
+ renderengine::LayerSettings layerSettings;
+ layerSettings.source.buffer.buffer = nullptr;
+ layerSettings.source.solidColor = half3(1.0, 0.0, 1.0);
+ layerSettings.alpha = half(1.0);
+
+ for (const auto& rect : flashRegion) {
+ layerSettings.geometry.boundaries = rect.toFloatRect();
+ clientCompositionLayers.push_back(layerSettings);
+ }
+}
+
+void Output::setExpensiveRenderingExpected(bool) {
+ // The base class does nothing with this call.
+}
+
void Output::postFramebuffer() {
ATRACE_CALL();
ALOGV(__FUNCTION__);
@@ -300,10 +480,10 @@
return;
}
- mRenderSurface->onPresentDisplayCompleted();
-
auto frame = presentAndGetFrameFences();
+ mRenderSurface->onPresentDisplayCompleted();
+
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
@@ -353,6 +533,10 @@
mState.usesDeviceComposition = false;
}
+bool Output::getSkipColorTransform() const {
+ return true;
+}
+
compositionengine::Output::FrameFences Output::presentAndGetFrameFences() {
compositionengine::Output::FrameFences result;
if (mState.usesClientComposition) {
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
index 6e744b9..e721cf5 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
@@ -614,6 +614,13 @@
}
}
+bool OutputLayer::needsFiltering() const {
+ const auto& displayFrame = mState.displayFrame;
+ const auto& sourceCrop = mState.sourceCrop;
+ return sourceCrop.getHeight() != displayFrame.getHeight() ||
+ sourceCrop.getWidth() != displayFrame.getWidth();
+}
+
void OutputLayer::dump(std::string& out) const {
using android::base::StringAppendF;
diff --git a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
index e3be0d7..743da82 100644
--- a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
@@ -30,6 +30,7 @@
#include "MockHWC2.h"
#include "MockHWComposer.h"
+#include "MockPowerAdvisor.h"
namespace android::compositionengine {
namespace {
@@ -59,6 +60,7 @@
}
StrictMock<android::mock::HWComposer> mHwComposer;
+ StrictMock<Hwc2::mock::PowerAdvisor> mPowerAdvisor;
StrictMock<mock::CompositionEngine> mCompositionEngine;
sp<mock::NativeWindow> mNativeWindow = new StrictMock<mock::NativeWindow>();
StrictMock<HWC2::mock::Layer> mHWC2Layer1;
@@ -68,7 +70,10 @@
mock::OutputLayer* mLayer2 = new StrictMock<mock::OutputLayer>();
mock::OutputLayer* mLayer3 = new StrictMock<mock::OutputLayer>();
impl::Display mDisplay{mCompositionEngine,
- DisplayCreationArgsBuilder().setDisplayId(DEFAULT_DISPLAY_ID).build()};
+ DisplayCreationArgsBuilder()
+ .setDisplayId(DEFAULT_DISPLAY_ID)
+ .setPowerAdvisor(&mPowerAdvisor)
+ .build()};
};
/*
@@ -344,6 +349,24 @@
}
/*
+ * Display::getSkipColorTransform()
+ */
+
+TEST_F(DisplayTest, getSkipColorTransformDoesNothingIfNonHwcDisplay) {
+ auto nonHwcDisplay{
+ impl::createDisplay(mCompositionEngine, DisplayCreationArgsBuilder().build())};
+ EXPECT_FALSE(nonHwcDisplay->getSkipColorTransform());
+}
+
+TEST_F(DisplayTest, getSkipColorTransformChecksHwcCapability) {
+ EXPECT_CALL(mHwComposer,
+ hasDisplayCapability(std::make_optional(DEFAULT_DISPLAY_ID),
+ HWC2::DisplayCapability::SkipClientColorTransform))
+ .WillOnce(Return(true));
+ EXPECT_TRUE(mDisplay.getSkipColorTransform());
+}
+
+/*
* Display::anyLayersRequireClientComposition()
*/
@@ -502,5 +525,17 @@
EXPECT_EQ(layer2Fence, result.layerFences[&mHWC2Layer2]);
}
+/*
+ * Display::setExpensiveRenderingExpected()
+ */
+
+TEST_F(DisplayTest, setExpensiveRenderingExpectedForwardsToPowerAdvisor) {
+ EXPECT_CALL(mPowerAdvisor, setExpensiveRenderingExpected(DEFAULT_DISPLAY_ID, true)).Times(1);
+ mDisplay.setExpensiveRenderingExpected(true);
+
+ EXPECT_CALL(mPowerAdvisor, setExpensiveRenderingExpected(DEFAULT_DISPLAY_ID, false)).Times(1);
+ mDisplay.setExpensiveRenderingExpected(false);
+}
+
} // namespace
} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.cpp b/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.cpp
new file mode 100644
index 0000000..85b9403
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.cpp
@@ -0,0 +1,34 @@
+/*
+ * 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 "MockPowerAdvisor.h"
+
+namespace android {
+namespace Hwc2 {
+
+// This will go away once PowerAdvisor is moved into the "backend" library
+PowerAdvisor::~PowerAdvisor() = default;
+
+namespace mock {
+
+// The Google Mock documentation recommends explicit non-header instantiations
+// for better compile time performance.
+PowerAdvisor::PowerAdvisor() = default;
+PowerAdvisor::~PowerAdvisor() = default;
+
+} // namespace mock
+} // namespace Hwc2
+} // namespace android
diff --git a/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.h b/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.h
new file mode 100644
index 0000000..c5a73f2
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.h
@@ -0,0 +1,37 @@
+/*
+ * 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 <gmock/gmock.h>
+
+#include "DisplayHardware/PowerAdvisor.h"
+
+namespace android {
+namespace Hwc2 {
+namespace mock {
+
+class PowerAdvisor : public android::Hwc2::PowerAdvisor {
+public:
+ PowerAdvisor();
+ ~PowerAdvisor() override;
+
+ MOCK_METHOD2(setExpensiveRenderingExpected, void(DisplayId displayId, bool expected));
+};
+
+} // namespace mock
+} // namespace Hwc2
+} // namespace android
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
index a5428ad..c83cae6 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
@@ -875,5 +875,23 @@
EXPECT_FALSE(mOutputLayer.getState().clearClientTarget);
}
+/*
+ * OutputLayer::needsFiltering()
+ */
+
+TEST_F(OutputLayerTest, needsFilteringReturnsFalseIfDisplaySizeSameAsSourceSize) {
+ mOutputLayer.editState().displayFrame = Rect(100, 100, 200, 200);
+ mOutputLayer.editState().sourceCrop = FloatRect{0.f, 0.f, 100.f, 100.f};
+
+ EXPECT_FALSE(mOutputLayer.needsFiltering());
+}
+
+TEST_F(OutputLayerTest, needsFilteringReturnsTrueIfDisplaySizeDifferentFromSourceSize) {
+ mOutputLayer.editState().displayFrame = Rect(100, 100, 200, 200);
+ mOutputLayer.editState().sourceCrop = FloatRect{0.f, 0.f, 100.1f, 100.1f};
+
+ EXPECT_TRUE(mOutputLayer.needsFiltering());
+}
+
} // namespace
} // namespace android::compositionengine
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index d136562..b6d79d4 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -60,7 +60,7 @@
mDisplayInstallOrientation(args.displayInstallOrientation),
mCompositionDisplay{mFlinger->getCompositionEngine().createDisplay(
compositionengine::DisplayCreationArgs{args.isSecure, args.isVirtual,
- args.displayId})},
+ args.displayId, args.powerAdvisor})},
mIsVirtual(args.isVirtual),
mOrientation(),
mActiveConfig(0),
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index 8bc19d4..4321e3d 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -40,6 +40,7 @@
#include <utils/Timers.h>
#include "DisplayHardware/DisplayIdentification.h"
+#include "DisplayHardware/PowerAdvisor.h"
#include "RenderArea.h"
namespace android {
@@ -241,6 +242,7 @@
std::unordered_map<ui::ColorMode, std::vector<ui::RenderIntent>> hwcColorModes;
int initialPowerMode{HWC_POWER_MODE_NORMAL};
bool isPrimary{false};
+ Hwc2::PowerAdvisor* powerAdvisor{nullptr};
};
class DisplayRenderArea : public RenderArea {
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index a2eeea5..db4ae41 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -105,7 +105,7 @@
mCurrentState.acquireFence = new Fence(-1);
mCurrentState.dataspace = ui::Dataspace::UNKNOWN;
mCurrentState.hdrMetadata.validTypes = 0;
- mCurrentState.surfaceDamageRegion.clear();
+ mCurrentState.surfaceDamageRegion = Region::INVALID_REGION;
mCurrentState.cornerRadius = 0.0f;
mCurrentState.api = -1;
mCurrentState.hasColorTransform = false;
@@ -440,6 +440,7 @@
}
void Layer::latchPerFrameState(compositionengine::LayerFECompositionState& compositionState) const {
+ const auto& drawingState{getDrawingState()};
compositionState.forceClientComposition = false;
// TODO(lpique): b/121291683 Remove this one we are sure we don't need the
@@ -451,9 +452,14 @@
compositionState.colorTransform = getColorTransform();
compositionState.colorTransformIsIdentity = !hasColorTransform();
compositionState.surfaceDamage = surfaceDamageRegion;
+ compositionState.hasProtectedContent = isProtected();
+
+ const bool usesRoundedCorners = getRoundedCornerState().radius != 0.f;
+ compositionState.isOpaque =
+ isOpaque(drawingState) && !usesRoundedCorners && getAlpha() == 1.0_hf;
// Force client composition for special cases known only to the front-end.
- if (isHdrY410() || getRoundedCornerState().radius > 0.0f) {
+ if (isHdrY410() || usesRoundedCorners) {
compositionState.forceClientComposition = true;
}
}
@@ -1932,46 +1938,10 @@
}
}
-void Layer::writeToProtoCompositionState(LayerProto* layerInfo,
- const sp<DisplayDevice>& displayDevice,
- uint32_t traceFlags) const {
- auto outputLayer = findOutputLayerForDisplay(displayDevice);
- if (!outputLayer) {
- return;
- }
-
- writeToProtoDrawingState(layerInfo, traceFlags);
- writeToProtoCommonState(layerInfo, LayerVector::StateSet::Drawing, traceFlags);
-
- const auto& compositionState = outputLayer->getState();
-
- const Rect& frame = compositionState.displayFrame;
- LayerProtoHelper::writeToProto(frame, [&]() { return layerInfo->mutable_hwc_frame(); });
-
- const FloatRect& crop = compositionState.sourceCrop;
- LayerProtoHelper::writeToProto(crop, [&]() { return layerInfo->mutable_hwc_crop(); });
-
- const int32_t transform =
- getCompositionLayer() ? static_cast<int32_t>(compositionState.bufferTransform) : 0;
- layerInfo->set_hwc_transform(transform);
-
- const int32_t compositionType =
- static_cast<int32_t>(compositionState.hwc ? (*compositionState.hwc).hwcCompositionType
- : Hwc2::IComposerClient::Composition::CLIENT);
- layerInfo->set_hwc_composition_type(compositionType);
-}
-
bool Layer::isRemovedFromCurrentState() const {
return mRemovedFromCurrentState;
}
-// Debug helper for b/137560795
-#define INT32_MIGHT_OVERFLOW(n) (((n) >= INT32_MAX / 2) || ((n) <= INT32_MIN / 2))
-
-#define RECT_BOUNDS_INVALID(rect) \
- (INT32_MIGHT_OVERFLOW((rect).left) || INT32_MIGHT_OVERFLOW((rect).right) || \
- INT32_MIGHT_OVERFLOW((rect).bottom) || INT32_MIGHT_OVERFLOW((rect).top))
-
InputWindowInfo Layer::fillInputInfo() {
InputWindowInfo info = mDrawingState.inputInfo;
@@ -1982,14 +1952,14 @@
ui::Transform t = getTransform();
const float xScale = t.sx();
const float yScale = t.sy();
- float xSurfaceInset = info.surfaceInset;
- float ySurfaceInset = info.surfaceInset;
+ int32_t xSurfaceInset = info.surfaceInset;
+ int32_t ySurfaceInset = info.surfaceInset;
if (xScale != 1.0f || yScale != 1.0f) {
- info.windowXScale *= 1.0f / xScale;
- info.windowYScale *= 1.0f / yScale;
+ info.windowXScale *= (xScale != 0.0f) ? 1.0f / xScale : 0.0f;
+ info.windowYScale *= (yScale != 0.0f) ? 1.0f / yScale : 0.0f;
info.touchableRegion.scaleSelf(xScale, yScale);
- xSurfaceInset *= xScale;
- ySurfaceInset *= yScale;
+ xSurfaceInset = std::round(xSurfaceInset * xScale);
+ ySurfaceInset = std::round(ySurfaceInset * yScale);
}
// Transform layer size to screen space and inset it by surface insets.
@@ -2002,25 +1972,10 @@
}
layerBounds = t.transform(layerBounds);
- // debug check for b/137560795
- {
- if (RECT_BOUNDS_INVALID(layerBounds)) {
- ALOGE("layer %s bounds are invalid (%" PRIi32 ", %" PRIi32 ", %" PRIi32 ", %" PRIi32
- ")",
- mName.c_str(), layerBounds.left, layerBounds.top, layerBounds.right,
- layerBounds.bottom);
- std::string out;
- getTransform().dump(out, "Transform");
- ALOGE("%s", out.c_str());
- layerBounds.left = layerBounds.top = layerBounds.right = layerBounds.bottom = 0;
- }
+ // clamp inset to layer bounds
+ xSurfaceInset = (xSurfaceInset >= 0) ? std::min(xSurfaceInset, layerBounds.getWidth() / 2) : 0;
+ ySurfaceInset = (ySurfaceInset >= 0) ? std::min(ySurfaceInset, layerBounds.getHeight() / 2) : 0;
- if (INT32_MIGHT_OVERFLOW(xSurfaceInset) || INT32_MIGHT_OVERFLOW(ySurfaceInset)) {
- ALOGE("layer %s surface inset are invalid (%" PRIi32 ", %" PRIi32 ")", mName.c_str(),
- int32_t(xSurfaceInset), int32_t(ySurfaceInset));
- xSurfaceInset = ySurfaceInset = 0;
- }
- }
layerBounds.inset(xSurfaceInset, ySurfaceInset, xSurfaceInset, ySurfaceInset);
// Input coordinate should match the layer bounds.
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 220465a..53091a0 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -93,7 +93,7 @@
LayerMetadata metadata;
};
-class Layer : public virtual compositionengine::LayerFE, public ClientCache::ErasedRecipient {
+class Layer : public virtual compositionengine::LayerFE {
static std::atomic<int32_t> sSequence;
public:
@@ -441,11 +441,6 @@
// 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.
@@ -550,6 +545,8 @@
virtual bool isBufferLatched() const { return false; }
+ virtual void latchAndReleaseBuffer() {}
+
/*
* Remove relative z for the layer if its relative parent is not part of the
* provided layer tree.
@@ -677,9 +674,6 @@
compositionengine::OutputLayer* findOutputLayerForDisplay(
const sp<const DisplayDevice>& display) const;
- // Inherit from ClientCache::ErasedRecipient
- void bufferErased(const client_cache_t& /*clientCacheId*/) override {}
-
protected:
// constant
sp<SurfaceFlinger> mFlinger;
diff --git a/services/surfaceflinger/LayerStats.cpp b/services/surfaceflinger/LayerStats.cpp
deleted file mode 100644
index a2d1feb..0000000
--- a/services/surfaceflinger/LayerStats.cpp
+++ /dev/null
@@ -1,233 +0,0 @@
-/*
- * Copyright 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.
- */
-#undef LOG_TAG
-#define LOG_TAG "LayerStats"
-#define ATRACE_TAG ATRACE_TAG_GRAPHICS
-
-#include "LayerStats.h"
-#include "DisplayHardware/HWComposer.h"
-#include "ui/DebugUtils.h"
-
-#include <android-base/stringprintf.h>
-#include <log/log.h>
-#include <utils/Trace.h>
-
-namespace android {
-
-using base::StringAppendF;
-using base::StringPrintf;
-
-void LayerStats::enable() {
- ATRACE_CALL();
- std::lock_guard<std::mutex> lock(mMutex);
- if (mEnabled) return;
- mLayerShapeStatsMap.clear();
- mEnabled = true;
- ALOGD("Logging enabled");
-}
-
-void LayerStats::disable() {
- ATRACE_CALL();
- std::lock_guard<std::mutex> lock(mMutex);
- if (!mEnabled) return;
- mEnabled = false;
- ALOGD("Logging disabled");
-}
-
-void LayerStats::clear() {
- ATRACE_CALL();
- std::lock_guard<std::mutex> lock(mMutex);
- mLayerShapeStatsMap.clear();
- ALOGD("Cleared current layer stats");
-}
-
-bool LayerStats::isEnabled() {
- return mEnabled;
-}
-
-void LayerStats::traverseLayerTreeStatsLocked(
- const std::vector<LayerProtoParser::Layer*>& layerTree,
- const LayerProtoParser::LayerGlobal& layerGlobal,
- std::vector<std::string>* const outLayerShapeVec) {
- for (const auto& layer : layerTree) {
- if (!layer) continue;
- traverseLayerTreeStatsLocked(layer->children, layerGlobal, outLayerShapeVec);
- std::string key = "";
- StringAppendF(&key, ",%s", layer->type.c_str());
- StringAppendF(&key, ",%s", layerCompositionType(layer->hwcCompositionType));
- StringAppendF(&key, ",%d", layer->isProtected);
- StringAppendF(&key, ",%s", layerTransform(layer->hwcTransform));
- StringAppendF(&key, ",%s", layerPixelFormat(layer->activeBuffer.format).c_str());
- StringAppendF(&key, ",%s", layer->dataspace.c_str());
- StringAppendF(&key, ",%s",
- destinationLocation(layer->hwcFrame.left, layerGlobal.resolution[0], true));
- StringAppendF(&key, ",%s",
- destinationLocation(layer->hwcFrame.top, layerGlobal.resolution[1], false));
- StringAppendF(&key, ",%s",
- destinationSize(layer->hwcFrame.right - layer->hwcFrame.left,
- layerGlobal.resolution[0], true));
- StringAppendF(&key, ",%s",
- destinationSize(layer->hwcFrame.bottom - layer->hwcFrame.top,
- layerGlobal.resolution[1], false));
- StringAppendF(&key, ",%s", scaleRatioWH(layer).c_str());
- StringAppendF(&key, ",%s", alpha(static_cast<float>(layer->color.a)));
-
- outLayerShapeVec->push_back(key);
- ALOGV("%s", key.c_str());
- }
-}
-
-void LayerStats::logLayerStats(const LayersProto& layersProto) {
- ATRACE_CALL();
- ALOGV("Logging");
- auto layerGlobal = LayerProtoParser::generateLayerGlobalInfo(layersProto);
- auto layerTree = LayerProtoParser::generateLayerTree(layersProto);
- std::vector<std::string> layerShapeVec;
-
- std::lock_guard<std::mutex> lock(mMutex);
- traverseLayerTreeStatsLocked(layerTree.topLevelLayers, layerGlobal, &layerShapeVec);
-
- std::string layerShapeKey =
- StringPrintf("%d,%s,%s,%s", static_cast<int32_t>(layerShapeVec.size()),
- layerGlobal.colorMode.c_str(), layerGlobal.colorTransform.c_str(),
- layerTransform(layerGlobal.globalTransform));
- ALOGV("%s", layerShapeKey.c_str());
-
- std::sort(layerShapeVec.begin(), layerShapeVec.end(), std::greater<std::string>());
- for (auto const& s : layerShapeVec) {
- layerShapeKey += s;
- }
-
- mLayerShapeStatsMap[layerShapeKey]++;
-}
-
-void LayerStats::dump(std::string& result) {
- ATRACE_CALL();
- ALOGD("Dumping");
- std::lock_guard<std::mutex> lock(mMutex);
- result.append("Frequency,LayerCount,ColorMode,ColorTransform,Orientation\n");
- result.append("LayerType,CompositionType,IsProtected,Transform,PixelFormat,Dataspace,");
- result.append("DstX,DstY,DstWidth,DstHeight,WScale,HScale,Alpha\n");
- for (auto& u : mLayerShapeStatsMap) {
- StringAppendF(&result, "%u,%s\n", u.second, u.first.c_str());
- }
-}
-
-const char* LayerStats::destinationLocation(int32_t location, int32_t range, bool isHorizontal) {
- static const char* locationArray[8] = {"0", "1/8", "1/4", "3/8", "1/2", "5/8", "3/4", "7/8"};
- int32_t ratio = location * 8 / range;
- if (ratio < 0) return "N/A";
- if (isHorizontal) {
- // X location is divided into 4 buckets {"0", "1/4", "1/2", "3/4"}
- if (ratio > 6) return "3/4";
- // use index 0, 2, 4, 6
- return locationArray[ratio & ~1];
- }
- if (ratio > 7) return "7/8";
- return locationArray[ratio];
-}
-
-const char* LayerStats::destinationSize(int32_t size, int32_t range, bool isWidth) {
- static const char* sizeArray[8] = {"1/8", "1/4", "3/8", "1/2", "5/8", "3/4", "7/8", "1"};
- int32_t ratio = size * 8 / range;
- if (ratio < 0) return "N/A";
- if (isWidth) {
- // width is divided into 4 buckets {"1/4", "1/2", "3/4", "1"}
- if (ratio > 6) return "1";
- // use index 1, 3, 5, 7
- return sizeArray[ratio | 1];
- }
- if (ratio > 7) return "1";
- return sizeArray[ratio];
-}
-
-const char* LayerStats::layerTransform(int32_t transform) {
- return getTransformName(static_cast<hwc_transform_t>(transform));
-}
-
-const char* LayerStats::layerCompositionType(int32_t compositionType) {
- return getCompositionName(static_cast<hwc2_composition_t>(compositionType));
-}
-
-std::string LayerStats::layerPixelFormat(int32_t pixelFormat) {
- return decodePixelFormat(pixelFormat);
-}
-
-std::string LayerStats::scaleRatioWH(const LayerProtoParser::Layer* layer) {
- if (!layer->type.compare("ColorLayer")) return "N/A,N/A";
- std::string ret = "";
- if (isRotated(layer->hwcTransform)) {
- ret += scaleRatio(layer->hwcFrame.right - layer->hwcFrame.left,
- static_cast<int32_t>(layer->hwcCrop.bottom - layer->hwcCrop.top));
- ret += ",";
- ret += scaleRatio(layer->hwcFrame.bottom - layer->hwcFrame.top,
- static_cast<int32_t>(layer->hwcCrop.right - layer->hwcCrop.left));
- } else {
- ret += scaleRatio(layer->hwcFrame.right - layer->hwcFrame.left,
- static_cast<int32_t>(layer->hwcCrop.right - layer->hwcCrop.left));
- ret += ",";
- ret += scaleRatio(layer->hwcFrame.bottom - layer->hwcFrame.top,
- static_cast<int32_t>(layer->hwcCrop.bottom - layer->hwcCrop.top));
- }
- return ret;
-}
-
-const char* LayerStats::scaleRatio(int32_t destinationScale, int32_t sourceScale) {
- // Make scale buckets from <1/64 to >= 16, to avoid floating point
- // calculation, x64 on destinationScale first
- int32_t scale = destinationScale * 64 / sourceScale;
- if (!scale) return "<1/64";
- if (scale < 2) return "1/64";
- if (scale < 4) return "1/32";
- if (scale < 8) return "1/16";
- if (scale < 16) return "1/8";
- if (scale < 32) return "1/4";
- if (scale < 64) return "1/2";
- if (scale < 128) return "1";
- if (scale < 256) return "2";
- if (scale < 512) return "4";
- if (scale < 1024) return "8";
- return ">=16";
-}
-
-const char* LayerStats::alpha(float a) {
- if (a == 1.0f) return "1.0";
- if (a > 0.9f) return "0.99";
- if (a > 0.8f) return "0.9";
- if (a > 0.7f) return "0.8";
- if (a > 0.6f) return "0.7";
- if (a > 0.5f) return "0.6";
- if (a > 0.4f) return "0.5";
- if (a > 0.3f) return "0.4";
- if (a > 0.2f) return "0.3";
- if (a > 0.1f) return "0.2";
- if (a > 0.0f) return "0.1";
- return "0.0";
-}
-
-bool LayerStats::isRotated(int32_t transform) {
- return transform & HWC_TRANSFORM_ROT_90;
-}
-
-bool LayerStats::isVFlipped(int32_t transform) {
- return transform & HWC_TRANSFORM_FLIP_V;
-}
-
-bool LayerStats::isHFlipped(int32_t transform) {
- return transform & HWC_TRANSFORM_FLIP_H;
-}
-
-} // namespace android
diff --git a/services/surfaceflinger/LayerStats.h b/services/surfaceflinger/LayerStats.h
deleted file mode 100644
index 62b2688..0000000
--- a/services/surfaceflinger/LayerStats.h
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright 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.
- */
-
-#pragma once
-
-#include <layerproto/LayerProtoHeader.h>
-#include <layerproto/LayerProtoParser.h>
-#include <mutex>
-#include <unordered_map>
-
-using namespace android::surfaceflinger;
-
-namespace android {
-
-class LayerStats {
-public:
- void enable();
- void disable();
- void clear();
- bool isEnabled();
- void logLayerStats(const LayersProto& layersProto);
- void dump(std::string& result);
-
-private:
- // Traverse layer tree to get all visible layers' stats
- void traverseLayerTreeStatsLocked(
- const std::vector<LayerProtoParser::Layer*>& layerTree,
- const LayerProtoParser::LayerGlobal& layerGlobal,
- std::vector<std::string>* const outLayerShapeVec);
- // Convert layer's top-left position into 8x8 percentage of the display
- static const char* destinationLocation(int32_t location, int32_t range, bool isHorizontal);
- // Convert layer's size into 8x8 percentage of the display
- static const char* destinationSize(int32_t size, int32_t range, bool isWidth);
- // Return the name of the transform
- static const char* layerTransform(int32_t transform);
- // Return the name of the composition type
- static const char* layerCompositionType(int32_t compositionType);
- // Return the name of the pixel format
- static std::string layerPixelFormat(int32_t pixelFormat);
- // Calculate scale ratios of layer's width/height with rotation information
- static std::string scaleRatioWH(const LayerProtoParser::Layer* layer);
- // Calculate scale ratio from source to destination and convert to string
- static const char* scaleRatio(int32_t destinationScale, int32_t sourceScale);
- // Bucket the alpha into designed buckets
- static const char* alpha(float a);
- // Return whether the original buffer is rotated in final composition
- static bool isRotated(int32_t transform);
- // Return whether the original buffer is V-flipped in final composition
- static bool isVFlipped(int32_t transform);
- // Return whether the original buffer is H-flipped in final composition
- static bool isHFlipped(int32_t transform);
-
- bool mEnabled = false;
- // Protect mLayersStatsMap
- std::mutex mMutex;
- // Hashmap for tracking the frame(layer shape) stats
- // KEY is a concatenation of all layers' properties within a frame
- // VALUE is the number of times this particular set has been scanned out
- std::unordered_map<std::string, uint32_t> mLayerShapeStatsMap;
-};
-
-} // namespace android
diff --git a/services/surfaceflinger/Scheduler/LayerInfo.cpp b/services/surfaceflinger/Scheduler/LayerInfo.cpp
index e782dd5..723d71f 100644
--- a/services/surfaceflinger/Scheduler/LayerInfo.cpp
+++ b/services/surfaceflinger/Scheduler/LayerInfo.cpp
@@ -49,7 +49,7 @@
mLastPresentTime = lastPresentTime;
// Ignore time diff that are too high - those are stale values
if (timeDiff > OBSOLETE_TIME_EPSILON_NS.count()) return;
- const nsecs_t refreshDuration = (timeDiff > 0) ? timeDiff : mMinRefreshDuration;
+ const nsecs_t refreshDuration = std::max(timeDiff, mMinRefreshDuration);
const int fps = 1e9f / refreshDuration;
mRefreshRateHistory.insertRefreshRate(fps);
}
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 952643c..3883427 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -118,6 +118,14 @@
}
}
+Scheduler::Scheduler(std::unique_ptr<DispSync> primaryDispSync,
+ std::unique_ptr<EventControlThread> eventControlThread,
+ const scheduler::RefreshRateConfigs& configs)
+ : mHasSyncFramework(false),
+ mPrimaryDispSync(std::move(primaryDispSync)),
+ mEventControlThread(std::move(eventControlThread)),
+ mRefreshRateConfigs(configs) {}
+
Scheduler::~Scheduler() {
// Ensure the OneShotTimer threads are joined before we start destroying state.
mDisplayPowerTimer.reset();
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index 0d9d7aa..5905ff6 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -204,6 +204,10 @@
enum class TimerState { Reset, Expired };
enum class TouchState { Inactive, Active };
+ // Used by tests to inject mocks.
+ Scheduler(std::unique_ptr<DispSync>, std::unique_ptr<EventControlThread>,
+ const scheduler::RefreshRateConfigs&);
+
// Creates a connection on the given EventThread and forwards the given callbacks.
sp<EventThreadConnection> createConnectionInternal(EventThread*, ResyncCallback&&,
ISurfaceComposer::ConfigChanged);
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 488b9ef..7a8eb6b 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -1798,8 +1798,6 @@
doComposition(displayDevice, repaintEverything);
}
- logLayerStats();
-
postFrame();
postComposition();
@@ -1854,24 +1852,13 @@
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);
+ // Latch the frontend layer composition state for each layer being
+ // composed.
+ for (const auto& [token, displayDevice] : mDisplays) {
+ auto display = displayDevice->getCompositionDisplay();
+ for (auto& layer : display->getOutputLayersOrderedByZ()) {
+ layer->getLayerFE().latchCompositionState(layer->getLayer().editState().frontEnd,
+ updatingGeometryThisFrame);
}
}
@@ -1904,16 +1891,14 @@
auto display = displayDevice->getCompositionDisplay();
for (auto& layer : display->getOutputLayersOrderedByZ()) {
+ if (mDebugDisableHWC || mDebugRegion) {
+ layer->editState().forceClientComposition = true;
+ }
+
// 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);
}
@@ -1943,7 +1928,7 @@
if (!dirtyRegion.isEmpty()) {
base::unique_fd readyFence;
// redraw the whole screen
- doComposeSurfaces(displayDevice, dirtyRegion, &readyFence);
+ display->composeSurfaces(dirtyRegion, &readyFence);
display->getRenderSurface()->queueBuffer(std::move(readyFence));
}
@@ -1958,20 +1943,6 @@
displayDevice->getCompositionDisplay()->prepareFrame();
}
-void SurfaceFlinger::logLayerStats() {
- ATRACE_CALL();
- if (CC_UNLIKELY(mLayerStats.isEnabled())) {
- for (const auto& [token, display] : mDisplays) {
- if (display->isPrimary()) {
- mLayerStats.logLayerStats(dumpVisibleLayersProtoInfo(display));
- return;
- }
- }
-
- ALOGE("logLayerStats: no primary display");
- }
-}
-
void SurfaceFlinger::updateCompositorTiming(const DisplayStatInfo& stats, nsecs_t compositeTime,
std::shared_ptr<FenceTime>& presentFenceTime) {
// Update queue of past composite+present times and determine the
@@ -2488,6 +2459,7 @@
creationArgs.displaySurface = dispSurface;
creationArgs.hasWideColorGamut = false;
creationArgs.supportedPerFrameMetadata = 0;
+ creationArgs.powerAdvisor = displayId ? &mPowerAdvisor : nullptr;
const bool isInternalDisplay = displayId && displayId == getInternalDisplayIdLocked();
creationArgs.isPrimary = isInternalDisplay;
@@ -2898,14 +2870,6 @@
}
}
-void SurfaceFlinger::latchAndReleaseBuffer(const sp<Layer>& layer) {
- if (layer->hasReadyFrame()) {
- bool ignored = false;
- layer->latchBuffer(ignored, systemTime(), 0 /* expectedPresentTime */);
- }
- layer->releasePendingBuffer(systemTime());
-}
-
void SurfaceFlinger::commitTransaction()
{
if (!mLayersPendingRemoval.isEmpty()) {
@@ -2916,7 +2880,7 @@
// Ensure any buffers set to display on any children are released.
if (l->isRemovedFromCurrentState()) {
- latchAndReleaseBuffer(l);
+ l->latchAndReleaseBuffer();
}
// If the layer has been removed and has no parent, then it will not be reachable
@@ -3174,6 +3138,14 @@
}
});
+ // The client can continue submitting buffers for offscreen layers, but they will not
+ // be shown on screen. Therefore, we need to latch and release buffers of offscreen
+ // layers to ensure dequeueBuffer doesn't block indefinitely.
+ for (Layer* offscreenLayer : mOffscreenLayers) {
+ offscreenLayer->traverseInZOrder(LayerVector::StateSet::Drawing,
+ [&](Layer* l) { l->latchAndReleaseBuffer(); });
+ }
+
if (!mLayersWithQueuedFrames.empty()) {
// mStateLock is needed for latchBuffer as LayerRejecter::reject()
// writes to Layer current state. See also b/119481871
@@ -3228,201 +3200,12 @@
ALOGV("doDisplayComposition");
base::unique_fd readyFence;
- if (!doComposeSurfaces(displayDevice, Region::INVALID_REGION, &readyFence)) return;
+ if (!display->composeSurfaces(Region::INVALID_REGION, &readyFence)) return;
// swap buffers (presentation)
display->getRenderSurface()->queueBuffer(std::move(readyFence));
}
-bool SurfaceFlinger::doComposeSurfaces(const sp<DisplayDevice>& displayDevice,
- const Region& debugRegion, base::unique_fd* readyFence) {
- ATRACE_CALL();
- ALOGV("doComposeSurfaces");
-
- auto display = displayDevice->getCompositionDisplay();
- const auto& displayState = display->getState();
- const auto displayId = display->getId();
- auto& renderEngine = getRenderEngine();
- const bool supportProtectedContent = renderEngine.supportsProtectedContent();
-
- const Region bounds(displayState.bounds);
- const DisplayRenderArea renderArea(displayDevice);
- const TracedOrdinal<bool> hasClientComposition = {"hasClientComposition",
- displayState.usesClientComposition};
- bool applyColorMatrix = false;
-
- renderengine::DisplaySettings clientCompositionDisplay;
- std::vector<renderengine::LayerSettings> clientCompositionLayers;
- sp<GraphicBuffer> buf;
- base::unique_fd fd;
-
- if (hasClientComposition) {
- ALOGV("hasClientComposition");
-
- if (displayDevice->isPrimary() && supportProtectedContent) {
- bool needsProtected = false;
- for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) {
- // If the layer is a protected layer, mark protected context is needed.
- if (layer->isProtected()) {
- needsProtected = true;
- break;
- }
- }
- if (needsProtected != renderEngine.isProtected()) {
- renderEngine.useProtectedContext(needsProtected);
- }
- if (needsProtected != display->getRenderSurface()->isProtected() &&
- needsProtected == renderEngine.isProtected()) {
- display->getRenderSurface()->setProtected(needsProtected);
- }
- }
-
- buf = display->getRenderSurface()->dequeueBuffer(&fd);
-
- if (buf == nullptr) {
- ALOGW("Dequeuing buffer for display [%s] failed, bailing out of "
- "client composition for this frame",
- displayDevice->getDisplayName().c_str());
- return false;
- }
-
- clientCompositionDisplay.physicalDisplay = displayState.scissor;
- clientCompositionDisplay.clip = displayState.scissor;
- const ui::Transform& displayTransform = displayState.transform;
- clientCompositionDisplay.globalTransform = displayTransform.asMatrix4();
- clientCompositionDisplay.orientation = displayState.orientation;
-
- const auto* profile = display->getDisplayColorProfile();
- Dataspace outputDataspace = Dataspace::UNKNOWN;
- if (profile->hasWideColorGamut()) {
- outputDataspace = displayState.dataspace;
- }
- clientCompositionDisplay.outputDataspace = outputDataspace;
- clientCompositionDisplay.maxLuminance =
- profile->getHdrCapabilities().getDesiredMaxLuminance();
-
- const bool hasDeviceComposition = displayState.usesDeviceComposition;
- const bool skipClientColorTransform =
- getHwComposer()
- .hasDisplayCapability(displayId,
- HWC2::DisplayCapability::SkipClientColorTransform);
-
- // Compute the global color transform matrix.
- applyColorMatrix = !hasDeviceComposition && !skipClientColorTransform;
- if (applyColorMatrix) {
- clientCompositionDisplay.colorTransform = displayState.colorTransformMat;
- }
- }
-
- /*
- * and then, render the layers targeted at the framebuffer
- */
-
- ALOGV("Rendering client layers");
- const bool useIdentityTransform = false;
- bool firstLayer = true;
- Region clearRegion = Region::INVALID_REGION;
- for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) {
- const Region viewportRegion(displayState.viewport);
- const Region clip(viewportRegion.intersect(layer->visibleRegion));
- ALOGV("Layer: %s", layer->getName().string());
- ALOGV(" Composition type: %s", toString(layer->getCompositionType(displayDevice)).c_str());
- if (!clip.isEmpty()) {
- switch (layer->getCompositionType(displayDevice)) {
- case Hwc2::IComposerClient::Composition::CURSOR:
- case Hwc2::IComposerClient::Composition::DEVICE:
- case Hwc2::IComposerClient::Composition::SIDEBAND:
- case Hwc2::IComposerClient::Composition::SOLID_COLOR: {
- LOG_ALWAYS_FATAL_IF(!displayId);
- const Layer::State& state(layer->getDrawingState());
- if (layer->getClearClientTarget(displayDevice) && !firstLayer &&
- layer->isOpaque(state) && (layer->getAlpha() == 1.0f) &&
- layer->getRoundedCornerState().radius == 0.0f && hasClientComposition) {
- // never clear the very first layer since we're
- // guaranteed the FB is already cleared
- Region dummyRegion;
- compositionengine::LayerFE::ClientCompositionTargetSettings targetSettings{
- clip,
- useIdentityTransform,
- layer->needsFiltering(renderArea.getDisplayDevice()) ||
- renderArea.needsFiltering(),
- renderArea.isSecure(),
- supportProtectedContent,
- dummyRegion,
- };
- auto result = layer->prepareClientComposition(targetSettings);
-
- 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);
- layerSettings.disableBlending = true;
- clientCompositionLayers.push_back(layerSettings);
- }
- }
- break;
- }
- case Hwc2::IComposerClient::Composition::CLIENT: {
- 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;
- }
- default:
- break;
- }
- } else {
- ALOGV(" Skipping for empty clip");
- }
- firstLayer = false;
- }
-
- // Perform some cleanup steps if we used client composition.
- if (hasClientComposition) {
- clientCompositionDisplay.clearRegion = clearRegion;
-
- // We boost GPU frequency here because there will be color spaces conversion
- // and it's expensive. We boost the GPU frequency so that GPU composition can
- // finish in time. We must reset GPU frequency afterwards, because high frequency
- // consumes extra battery.
- const bool expensiveRenderingExpected =
- clientCompositionDisplay.outputDataspace == Dataspace::DISPLAY_P3;
- if (expensiveRenderingExpected && displayId) {
- mPowerAdvisor.setExpensiveRenderingExpected(*displayId, true);
- }
- if (!debugRegion.isEmpty()) {
- Region::const_iterator it = debugRegion.begin();
- Region::const_iterator end = debugRegion.end();
- while (it != end) {
- const Rect& rect = *it++;
- renderengine::LayerSettings layerSettings;
- layerSettings.source.buffer.buffer = nullptr;
- layerSettings.source.solidColor = half3(1.0, 0.0, 1.0);
- layerSettings.geometry.boundaries = rect.toFloatRect();
- layerSettings.alpha = half(1.0);
- clientCompositionLayers.push_back(layerSettings);
- }
- }
- renderEngine.drawLayers(clientCompositionDisplay, clientCompositionLayers,
- buf->getNativeBuffer(), /*useFramebufferCache=*/true, std::move(fd),
- readyFence);
- } else if (displayId) {
- mPowerAdvisor.setExpensiveRenderingExpected(*displayId, false);
- }
- return true;
-}
-
status_t SurfaceFlinger::addClientLayer(const sp<Client>& client, const sp<IBinder>& handle,
const sp<IGraphicBufferProducer>& gbc, const sp<Layer>& lbc,
const sp<IBinder>& parentHandle,
@@ -3441,7 +3224,7 @@
}
if (mNumLayers >= MAX_LAYERS) {
- ALOGE("AddClientLayer failed, mNumLayers (%zu) >= MAX_LAYERS (%zu)", mNumLayers,
+ ALOGE("AddClientLayer failed, mNumLayers (%zu) >= MAX_LAYERS (%zu)", mNumLayers.load(),
MAX_LAYERS);
return NO_MEMORY;
}
@@ -3465,7 +3248,7 @@
mMaxGraphicBufferProducerListSize,
"Suspected IGBP leak: %zu IGBPs (%zu max), %zu Layers",
mGraphicBufferProducerList.size(),
- mMaxGraphicBufferProducerListSize, mNumLayers);
+ mMaxGraphicBufferProducerListSize, mNumLayers.load());
}
mLayersAdded = true;
}
@@ -3677,6 +3460,7 @@
if (uncacheBuffer.isValid()) {
ClientCache::getInstance().erase(uncacheBuffer);
+ getRenderEngine().unbindExternalTextureBuffer(uncacheBuffer.id);
}
// If a synchronous transaction is explicitly requested without any changes, force a transaction
@@ -4039,12 +3823,18 @@
bool bufferChanged = what & layer_state_t::eBufferChanged;
bool cacheIdChanged = what & layer_state_t::eCachedBufferChanged;
sp<GraphicBuffer> buffer;
- if (bufferChanged && cacheIdChanged) {
- ClientCache::getInstance().add(s.cachedBuffer, s.buffer);
- ClientCache::getInstance().registerErasedRecipient(s.cachedBuffer,
- wp<ClientCache::ErasedRecipient>(layer));
- getRenderEngine().cacheExternalTextureBuffer(s.buffer);
+ if (bufferChanged && cacheIdChanged && s.buffer != nullptr) {
buffer = s.buffer;
+ bool success = ClientCache::getInstance().add(s.cachedBuffer, s.buffer);
+ if (success) {
+ getRenderEngine().cacheExternalTextureBuffer(s.buffer);
+ success = ClientCache::getInstance()
+ .registerErasedRecipient(s.cachedBuffer,
+ wp<ClientCache::ErasedRecipient>(this));
+ if (!success) {
+ getRenderEngine().unbindExternalTextureBuffer(s.buffer->getId());
+ }
+ }
} else if (cacheIdChanged) {
buffer = ClientCache::getInstance().get(s.cachedBuffer);
} else if (bufferChanged) {
@@ -4465,14 +4255,10 @@
using namespace std::string_literals;
static const std::unordered_map<std::string, Dumper> dumpers = {
- {"--clear-layer-stats"s, dumper([this](std::string&) { mLayerStats.clear(); })},
- {"--disable-layer-stats"s, dumper([this](std::string&) { mLayerStats.disable(); })},
{"--display-id"s, dumper(&SurfaceFlinger::dumpDisplayIdentificationData)},
{"--dispsync"s, dumper([this](std::string& s) {
mScheduler->dumpPrimaryDispSync(s);
})},
- {"--dump-layer-stats"s, dumper([this](std::string& s) { mLayerStats.dump(s); })},
- {"--enable-layer-stats"s, dumper([this](std::string&) { mLayerStats.enable(); })},
{"--frame-events"s, dumper(&SurfaceFlinger::dumpFrameEventsLocked)},
{"--latency"s, argsDumper(&SurfaceFlinger::dumpStatsLocked)},
{"--latency-clear"s, argsDumper(&SurfaceFlinger::clearStatsLocked)},
@@ -4485,7 +4271,8 @@
const auto flag = args.empty() ? ""s : std::string(String8(args[0]));
- if (const auto it = dumpers.find(flag); it != dumpers.end()) {
+ const auto it = dumpers.find(flag);
+ if (it != dumpers.end()) {
(it->second)(args, asProto, result);
} else if (!asProto) {
dumpAllLocked(args, result);
@@ -4495,13 +4282,15 @@
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");
+ if (it == dumpers.end()) {
+ const LayersProto layersProto = dumpProtoFromMainThread();
+ if (asProto) {
+ result.append(layersProto.SerializeAsString());
+ } else {
+ const auto layerTree = LayerProtoParser::generateLayerTree(layersProto);
+ result.append(LayerProtoParser::layerTreeToString(layerTree));
+ result.append("\n");
+ }
}
}
write(fd, result.c_str(), result.size());
@@ -4760,33 +4549,6 @@
return layersProto;
}
-LayersProto SurfaceFlinger::dumpVisibleLayersProtoInfo(
- const sp<DisplayDevice>& displayDevice) const {
- LayersProto layersProto;
-
- SizeProto* resolution = layersProto.mutable_resolution();
- resolution->set_w(displayDevice->getWidth());
- resolution->set_h(displayDevice->getHeight());
-
- auto display = displayDevice->getCompositionDisplay();
- const auto& displayState = display->getState();
-
- layersProto.set_color_mode(decodeColorMode(displayState.colorMode));
- layersProto.set_color_transform(decodeColorTransform(displayState.colorTransform));
- layersProto.set_global_transform(displayState.orientation);
-
- const auto displayId = displayDevice->getId();
- LOG_ALWAYS_FATAL_IF(!displayId);
- mDrawingState.traverseInZOrder([&](Layer* layer) {
- if (!layer->visibleRegion.isEmpty() && !display->getOutputLayersOrderedByZ().empty()) {
- LayerProto* layerProto = layersProto.add_layers();
- layer->writeToProtoCompositionState(layerProto, displayDevice);
- }
- });
-
- return layersProto;
-}
-
void SurfaceFlinger::dumpAllLocked(const DumpArgs& args, std::string& result) const {
const bool colorize = !args.empty() && args[0] == String16("--color");
Colorizer colorizer(colorize);
@@ -4839,7 +4601,7 @@
* Dump the visible layer list
*/
colorizer.bold(result);
- StringAppendF(&result, "Visible layers (count = %zu)\n", mNumLayers);
+ StringAppendF(&result, "Visible layers (count = %zu)\n", mNumLayers.load());
StringAppendF(&result, "GraphicBufferProducers: %zu, max %zu\n",
mGraphicBufferProducerList.size(), mMaxGraphicBufferProducerListSize);
colorizer.reset(result);
@@ -5645,10 +5407,13 @@
drawLayers();
} else {
Rect bounds = getBounds();
- screenshotParentLayer = mFlinger->getFactory().createContainerLayer(
- LayerCreationArgs(mFlinger, nullptr, String8("Screenshot Parent"),
- bounds.getWidth(), bounds.getHeight(), 0,
- LayerMetadata()));
+ // In the "childrenOnly" case we reparent the children to a screenshot
+ // layer which has no properties set and which does not draw.
+ sp<ContainerLayer> screenshotParentLayer =
+ mFlinger->getFactory().createContainerLayer(
+ LayerCreationArgs(mFlinger, nullptr, String8("Screenshot Parent"),
+ bounds.getWidth(), bounds.getHeight(), 0,
+ LayerMetadata()));
ReparentForDrawing reparent(mLayer, screenshotParentLayer, sourceCrop);
drawLayers();
@@ -5659,9 +5424,6 @@
const sp<Layer> mLayer;
const Rect mCrop;
- // In the "childrenOnly" case we reparent the children to a screenshot
- // layer which has no properties set and which does not draw.
- sp<ContainerLayer> screenshotParentLayer;
ui::Transform mTransform;
bool mNeedsFiltering;
@@ -6096,6 +5858,10 @@
return nullptr;
}
+void SurfaceFlinger::bufferErased(const client_cache_t& clientCacheId) {
+ getRenderEngine().unbindExternalTextureBuffer(clientCacheId.id);
+}
+
} // namespace android
#if defined(__gl_h_)
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 3974a8c..27a0f6b 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -52,7 +52,6 @@
#include "DisplayHardware/PowerAdvisor.h"
#include "Effects/Daltonizer.h"
#include "FrameTracker.h"
-#include "LayerStats.h"
#include "LayerVector.h"
#include "Scheduler/RefreshRateConfigs.h"
#include "Scheduler/RefreshRateStats.h"
@@ -172,9 +171,9 @@
class SurfaceFlinger : public BnSurfaceComposer,
public PriorityDumper,
+ public ClientCache::ErasedRecipient,
private IBinder::DeathRecipient,
- private HWC2::ComposerCallback
-{
+ private HWC2::ComposerCallback {
public:
SurfaceFlingerBE& getBE() { return mBE; }
const SurfaceFlingerBE& getBE() const { return mBE; }
@@ -322,6 +321,9 @@
sp<Layer> fromHandle(const sp<IBinder>& handle) REQUIRES(mStateLock);
+ // Inherit from ClientCache::ErasedRecipient
+ void bufferErased(const client_cache_t& clientCacheId) override;
+
private:
friend class BufferLayer;
friend class BufferQueueLayer;
@@ -574,7 +576,6 @@
// Can only be called from the main thread or with mStateLock held
uint32_t setTransactionFlags(uint32_t flags);
uint32_t setTransactionFlags(uint32_t flags, Scheduler::TransactionStart transactionStart);
- void latchAndReleaseBuffer(const sp<Layer>& layer);
void commitTransaction() REQUIRES(mStateLock);
void commitOffscreenLayers();
bool transactionIsReadyToBeApplied(int64_t desiredPresentTime,
@@ -762,15 +763,8 @@
void calculateWorkingSet();
void doComposition(const sp<DisplayDevice>& display, bool repainEverything);
void doDebugFlashRegions(const sp<DisplayDevice>& display, bool repaintEverything);
- void logLayerStats();
void doDisplayComposition(const sp<DisplayDevice>& display, const Region& dirtyRegion);
- // This fails if using GL and the surface has been destroyed. readyFence
- // will be populated if using GL and native fence sync is supported, to
- // signal when drawing has completed.
- bool doComposeSurfaces(const sp<DisplayDevice>& display, const Region& debugRegionm,
- base::unique_fd* readyFence);
-
void postFrame();
/* ------------------------------------------------------------------------
@@ -884,7 +878,6 @@
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;
bool isLayerTripleBufferingDisabled() const {
return this->mLayerTripleBufferingDisabled;
@@ -1001,7 +994,6 @@
SurfaceTracing mTracing{*this};
bool mTracingEnabled = false;
bool mTracingEnabledChanged GUARDED_BY(mStateLock) = false;
- LayerStats mLayerStats;
const std::shared_ptr<TimeStats> mTimeStats;
bool mUseHwcVirtualDisplays = false;
std::atomic<uint32_t> mFrameMissedCount = 0;
@@ -1072,7 +1064,7 @@
// Static screen stats
bool mHasPoweredOff = false;
- size_t mNumLayers = 0;
+ std::atomic<size_t> mNumLayers = 0;
// Verify that transaction is being called by an approved process:
// either AID_GRAPHICS or AID_SYSTEM.
diff --git a/services/surfaceflinger/TimeStats/TimeStats.cpp b/services/surfaceflinger/TimeStats/TimeStats.cpp
index c97a19b..3e3ab18 100644
--- a/services/surfaceflinger/TimeStats/TimeStats.cpp
+++ b/services/surfaceflinger/TimeStats/TimeStats.cpp
@@ -72,8 +72,10 @@
std::string result = "TimeStats miniDump:\n";
std::lock_guard<std::mutex> lock(mMutex);
- android::base::StringAppendF(&result, "Number of tracked layers is %zu\n",
+ android::base::StringAppendF(&result, "Number of layers currently being tracked is %zu\n",
mTimeStatsTracker.size());
+ android::base::StringAppendF(&result, "Number of layers in the stats pool is %zu\n",
+ mTimeStats.stats.size());
return result;
}
@@ -173,8 +175,8 @@
ALOGV("[%d]-[%" PRIu64 "]-presentFenceTime[%" PRId64 "]", layerID,
timeRecords[0].frameTime.frameNumber, timeRecords[0].frameTime.presentTime);
- const std::string& layerName = layerRecord.layerName;
if (prevTimeRecord.ready) {
+ const std::string& layerName = layerRecord.layerName;
if (!mTimeStats.stats.count(layerName)) {
mTimeStats.stats[layerName].layerName = layerName;
mTimeStats.stats[layerName].packageName = getPackageName(layerName);
@@ -220,18 +222,6 @@
timeRecords[0].frameTime.frameNumber, presentToPresentMs);
timeStatsLayer.deltas["present2present"].insert(presentToPresentMs);
}
-
- // Output additional trace points to track frame time.
- ATRACE_INT64(("TimeStats-Post - " + layerName).c_str(), timeRecords[0].frameTime.postTime);
- ATRACE_INT64(("TimeStats-Acquire - " + layerName).c_str(),
- timeRecords[0].frameTime.acquireTime);
- ATRACE_INT64(("TimeStats-Latch - " + layerName).c_str(),
- timeRecords[0].frameTime.latchTime);
- ATRACE_INT64(("TimeStats-Desired - " + layerName).c_str(),
- timeRecords[0].frameTime.desiredTime);
- ATRACE_INT64(("TimeStats-Present - " + layerName).c_str(),
- timeRecords[0].frameTime.presentTime);
-
prevTimeRecord = timeRecords[0];
timeRecords.pop_front();
layerRecord.waitData--;
@@ -262,6 +252,9 @@
postTime);
std::lock_guard<std::mutex> lock(mMutex);
+ if (!mTimeStats.stats.count(layerName) && mTimeStats.stats.size() >= MAX_NUM_LAYER_STATS) {
+ return;
+ }
if (!mTimeStatsTracker.count(layerID) && mTimeStatsTracker.size() < MAX_NUM_LAYER_RECORDS &&
layerNameIsValid(layerName)) {
mTimeStatsTracker[layerID].layerName = layerName;
@@ -613,7 +606,7 @@
if (asProto) {
ALOGD("Dumping TimeStats as proto");
SFTimeStatsGlobalProto timeStatsProto = mTimeStats.toProto(maxLayers);
- result.append(timeStatsProto.SerializeAsString().c_str(), timeStatsProto.ByteSize());
+ result.append(timeStatsProto.SerializeAsString());
} else {
ALOGD("Dumping TimeStats as text");
result.append(mTimeStats.toString(maxLayers));
diff --git a/services/surfaceflinger/TimeStats/TimeStats.h b/services/surfaceflinger/TimeStats/TimeStats.h
index 2bcb568..eed7111 100644
--- a/services/surfaceflinger/TimeStats/TimeStats.h
+++ b/services/surfaceflinger/TimeStats/TimeStats.h
@@ -161,6 +161,7 @@
GlobalRecord mGlobalRecord;
static const size_t MAX_NUM_LAYER_RECORDS = 200;
+ static const size_t MAX_NUM_LAYER_STATS = 200;
};
} // namespace impl
diff --git a/services/surfaceflinger/layerproto/LayerProtoParser.cpp b/services/surfaceflinger/layerproto/LayerProtoParser.cpp
index d3381e5..ef488bd 100644
--- a/services/surfaceflinger/layerproto/LayerProtoParser.cpp
+++ b/services/surfaceflinger/layerproto/LayerProtoParser.cpp
@@ -37,16 +37,6 @@
return lhs->id < rhs->id;
}
-const LayerProtoParser::LayerGlobal LayerProtoParser::generateLayerGlobalInfo(
- const LayersProto& layersProto) {
- LayerGlobal layerGlobal;
- layerGlobal.resolution = {layersProto.resolution().w(), layersProto.resolution().h()};
- layerGlobal.colorMode = layersProto.color_mode();
- layerGlobal.colorTransform = layersProto.color_transform();
- layerGlobal.globalTransform = layersProto.global_transform();
- return layerGlobal;
-}
-
LayerProtoParser::LayerTree LayerProtoParser::generateLayerTree(const LayersProto& layersProto) {
LayerTree layerTree;
layerTree.allLayers = generateLayerList(layersProto);
@@ -114,10 +104,6 @@
layer.bufferTransform = generateTransform(layerProto.buffer_transform());
layer.queuedFrames = layerProto.queued_frames();
layer.refreshPending = layerProto.refresh_pending();
- layer.hwcFrame = generateRect(layerProto.hwc_frame());
- layer.hwcCrop = generateFloatRect(layerProto.hwc_crop());
- layer.hwcTransform = layerProto.hwc_transform();
- layer.hwcCompositionType = layerProto.hwc_composition_type();
layer.isProtected = layerProto.is_protected();
layer.cornerRadius = layerProto.corner_radius();
for (const auto& entry : layerProto.metadata()) {
diff --git a/services/surfaceflinger/layerproto/include/layerproto/LayerProtoParser.h b/services/surfaceflinger/layerproto/include/layerproto/LayerProtoParser.h
index d1b2b1f..54e02ca 100644
--- a/services/surfaceflinger/layerproto/include/layerproto/LayerProtoParser.h
+++ b/services/surfaceflinger/layerproto/include/layerproto/LayerProtoParser.h
@@ -108,10 +108,6 @@
Transform bufferTransform;
int32_t queuedFrames;
bool refreshPending;
- LayerProtoParser::Rect hwcFrame;
- LayerProtoParser::FloatRect hwcCrop;
- int32_t hwcTransform;
- int32_t hwcCompositionType;
bool isProtected;
float cornerRadius;
LayerMetadata metadata;
@@ -119,14 +115,6 @@
std::string to_string() const;
};
- class LayerGlobal {
- public:
- int2 resolution;
- std::string colorMode;
- std::string colorTransform;
- int32_t globalTransform;
- };
-
class LayerTree {
public:
// all layers in LayersProto and in the original order
@@ -136,7 +124,6 @@
std::vector<Layer*> topLevelLayers;
};
- static const LayerGlobal generateLayerGlobalInfo(const LayersProto& layersProto);
static LayerTree generateLayerTree(const LayersProto& layersProto);
static std::string layerTreeToString(const LayerTree& layerTree);
diff --git a/services/surfaceflinger/layerproto/layers.proto b/services/surfaceflinger/layerproto/layers.proto
index b097505..c7fbff3 100644
--- a/services/surfaceflinger/layerproto/layers.proto
+++ b/services/surfaceflinger/layerproto/layers.proto
@@ -7,10 +7,6 @@
// Contains a list of all layers.
message LayersProto {
repeated LayerProto layers = 1;
- SizeProto resolution = 2;
- string color_mode = 3;
- string color_transform = 4;
- int32 global_transform = 5;
}
// Information about each layer.
diff --git a/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt b/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt
new file mode 100644
index 0000000..b66e56e
--- /dev/null
+++ b/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt
@@ -0,0 +1,138 @@
+props {
+ module: "android.sysprop.SurfaceFlingerProperties"
+ prop {
+ api_name: "color_space_agnostic_dataspace"
+ type: Long
+ prop_name: "ro.surface_flinger.color_space_agnostic_dataspace"
+ }
+ prop {
+ api_name: "default_composition_dataspace"
+ type: Long
+ prop_name: "ro.surface_flinger.default_composition_dataspace"
+ }
+ prop {
+ api_name: "default_composition_pixel_format"
+ type: Integer
+ prop_name: "ro.surface_flinger.default_composition_pixel_format"
+ }
+ prop {
+ api_name: "display_primary_blue"
+ type: DoubleList
+ prop_name: "ro.surface_flinger.display_primary_blue"
+ }
+ prop {
+ api_name: "display_primary_green"
+ type: DoubleList
+ prop_name: "ro.surface_flinger.display_primary_green"
+ }
+ prop {
+ api_name: "display_primary_red"
+ type: DoubleList
+ prop_name: "ro.surface_flinger.display_primary_red"
+ }
+ prop {
+ api_name: "display_primary_white"
+ type: DoubleList
+ prop_name: "ro.surface_flinger.display_primary_white"
+ }
+ prop {
+ api_name: "enable_protected_contents"
+ prop_name: "ro.surface_flinger.protected_contents"
+ }
+ prop {
+ api_name: "force_hwc_copy_for_virtual_displays"
+ prop_name: "ro.surface_flinger.force_hwc_copy_for_virtual_displays"
+ }
+ prop {
+ api_name: "has_HDR_display"
+ prop_name: "ro.surface_flinger.has_HDR_display"
+ }
+ prop {
+ api_name: "has_wide_color_display"
+ prop_name: "ro.surface_flinger.has_wide_color_display"
+ }
+ prop {
+ api_name: "max_frame_buffer_acquired_buffers"
+ type: Long
+ prop_name: "ro.surface_flinger.max_frame_buffer_acquired_buffers"
+ }
+ prop {
+ api_name: "max_virtual_display_dimension"
+ type: Long
+ prop_name: "ro.surface_flinger.max_virtual_display_dimension"
+ }
+ prop {
+ api_name: "present_time_offset_from_vsync_ns"
+ type: Long
+ prop_name: "ro.surface_flinger.present_time_offset_from_vsync_ns"
+ }
+ prop {
+ api_name: "primary_display_orientation"
+ type: Enum
+ prop_name: "ro.surface_flinger.primary_display_orientation"
+ enum_values: "ORIENTATION_0|ORIENTATION_90|ORIENTATION_180|ORIENTATION_270"
+ }
+ prop {
+ api_name: "running_without_sync_framework"
+ prop_name: "ro.surface_flinger.running_without_sync_framework"
+ }
+ prop {
+ api_name: "set_display_power_timer_ms"
+ type: Integer
+ prop_name: "ro.surface_flinger.set_display_power_timer_ms"
+ }
+ prop {
+ api_name: "set_idle_timer_ms"
+ type: Integer
+ prop_name: "ro.surface_flinger.set_idle_timer_ms"
+ }
+ prop {
+ api_name: "set_touch_timer_ms"
+ type: Integer
+ prop_name: "ro.surface_flinger.set_touch_timer_ms"
+ }
+ prop {
+ api_name: "start_graphics_allocator_service"
+ prop_name: "ro.surface_flinger.start_graphics_allocator_service"
+ }
+ prop {
+ api_name: "support_kernel_idle_timer"
+ prop_name: "ro.surface_flinger.support_kernel_idle_timer"
+ }
+ prop {
+ api_name: "use_color_management"
+ prop_name: "ro.surface_flinger.use_color_management"
+ }
+ prop {
+ api_name: "use_context_priority"
+ prop_name: "ro.surface_flinger.use_context_priority"
+ }
+ prop {
+ api_name: "use_smart_90_for_video"
+ prop_name: "ro.surface_flinger.use_smart_90_for_video"
+ }
+ prop {
+ api_name: "use_vr_flinger"
+ prop_name: "ro.surface_flinger.use_vr_flinger"
+ }
+ prop {
+ api_name: "vsync_event_phase_offset_ns"
+ type: Long
+ prop_name: "ro.surface_flinger.vsync_event_phase_offset_ns"
+ }
+ prop {
+ api_name: "vsync_sf_event_phase_offset_ns"
+ type: Long
+ prop_name: "ro.surface_flinger.vsync_sf_event_phase_offset_ns"
+ }
+ prop {
+ api_name: "wcg_composition_dataspace"
+ type: Long
+ prop_name: "ro.surface_flinger.wcg_composition_dataspace"
+ }
+ prop {
+ api_name: "wcg_composition_pixel_format"
+ type: Integer
+ prop_name: "ro.surface_flinger.wcg_composition_pixel_format"
+ }
+}
diff --git a/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-latest.txt b/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-latest.txt
new file mode 100644
index 0000000..b66e56e
--- /dev/null
+++ b/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-latest.txt
@@ -0,0 +1,138 @@
+props {
+ module: "android.sysprop.SurfaceFlingerProperties"
+ prop {
+ api_name: "color_space_agnostic_dataspace"
+ type: Long
+ prop_name: "ro.surface_flinger.color_space_agnostic_dataspace"
+ }
+ prop {
+ api_name: "default_composition_dataspace"
+ type: Long
+ prop_name: "ro.surface_flinger.default_composition_dataspace"
+ }
+ prop {
+ api_name: "default_composition_pixel_format"
+ type: Integer
+ prop_name: "ro.surface_flinger.default_composition_pixel_format"
+ }
+ prop {
+ api_name: "display_primary_blue"
+ type: DoubleList
+ prop_name: "ro.surface_flinger.display_primary_blue"
+ }
+ prop {
+ api_name: "display_primary_green"
+ type: DoubleList
+ prop_name: "ro.surface_flinger.display_primary_green"
+ }
+ prop {
+ api_name: "display_primary_red"
+ type: DoubleList
+ prop_name: "ro.surface_flinger.display_primary_red"
+ }
+ prop {
+ api_name: "display_primary_white"
+ type: DoubleList
+ prop_name: "ro.surface_flinger.display_primary_white"
+ }
+ prop {
+ api_name: "enable_protected_contents"
+ prop_name: "ro.surface_flinger.protected_contents"
+ }
+ prop {
+ api_name: "force_hwc_copy_for_virtual_displays"
+ prop_name: "ro.surface_flinger.force_hwc_copy_for_virtual_displays"
+ }
+ prop {
+ api_name: "has_HDR_display"
+ prop_name: "ro.surface_flinger.has_HDR_display"
+ }
+ prop {
+ api_name: "has_wide_color_display"
+ prop_name: "ro.surface_flinger.has_wide_color_display"
+ }
+ prop {
+ api_name: "max_frame_buffer_acquired_buffers"
+ type: Long
+ prop_name: "ro.surface_flinger.max_frame_buffer_acquired_buffers"
+ }
+ prop {
+ api_name: "max_virtual_display_dimension"
+ type: Long
+ prop_name: "ro.surface_flinger.max_virtual_display_dimension"
+ }
+ prop {
+ api_name: "present_time_offset_from_vsync_ns"
+ type: Long
+ prop_name: "ro.surface_flinger.present_time_offset_from_vsync_ns"
+ }
+ prop {
+ api_name: "primary_display_orientation"
+ type: Enum
+ prop_name: "ro.surface_flinger.primary_display_orientation"
+ enum_values: "ORIENTATION_0|ORIENTATION_90|ORIENTATION_180|ORIENTATION_270"
+ }
+ prop {
+ api_name: "running_without_sync_framework"
+ prop_name: "ro.surface_flinger.running_without_sync_framework"
+ }
+ prop {
+ api_name: "set_display_power_timer_ms"
+ type: Integer
+ prop_name: "ro.surface_flinger.set_display_power_timer_ms"
+ }
+ prop {
+ api_name: "set_idle_timer_ms"
+ type: Integer
+ prop_name: "ro.surface_flinger.set_idle_timer_ms"
+ }
+ prop {
+ api_name: "set_touch_timer_ms"
+ type: Integer
+ prop_name: "ro.surface_flinger.set_touch_timer_ms"
+ }
+ prop {
+ api_name: "start_graphics_allocator_service"
+ prop_name: "ro.surface_flinger.start_graphics_allocator_service"
+ }
+ prop {
+ api_name: "support_kernel_idle_timer"
+ prop_name: "ro.surface_flinger.support_kernel_idle_timer"
+ }
+ prop {
+ api_name: "use_color_management"
+ prop_name: "ro.surface_flinger.use_color_management"
+ }
+ prop {
+ api_name: "use_context_priority"
+ prop_name: "ro.surface_flinger.use_context_priority"
+ }
+ prop {
+ api_name: "use_smart_90_for_video"
+ prop_name: "ro.surface_flinger.use_smart_90_for_video"
+ }
+ prop {
+ api_name: "use_vr_flinger"
+ prop_name: "ro.surface_flinger.use_vr_flinger"
+ }
+ prop {
+ api_name: "vsync_event_phase_offset_ns"
+ type: Long
+ prop_name: "ro.surface_flinger.vsync_event_phase_offset_ns"
+ }
+ prop {
+ api_name: "vsync_sf_event_phase_offset_ns"
+ type: Long
+ prop_name: "ro.surface_flinger.vsync_sf_event_phase_offset_ns"
+ }
+ prop {
+ api_name: "wcg_composition_dataspace"
+ type: Long
+ prop_name: "ro.surface_flinger.wcg_composition_dataspace"
+ }
+ prop {
+ api_name: "wcg_composition_pixel_format"
+ type: Integer
+ prop_name: "ro.surface_flinger.wcg_composition_pixel_format"
+ }
+}
diff --git a/services/surfaceflinger/sysprop/api/current.txt b/services/surfaceflinger/sysprop/api/current.txt
deleted file mode 100644
index d802177..0000000
--- a/services/surfaceflinger/sysprop/api/current.txt
+++ /dev/null
@@ -1 +0,0 @@
-// Signature format: 2.0
diff --git a/services/surfaceflinger/sysprop/api/removed.txt b/services/surfaceflinger/sysprop/api/removed.txt
deleted file mode 100644
index d802177..0000000
--- a/services/surfaceflinger/sysprop/api/removed.txt
+++ /dev/null
@@ -1 +0,0 @@
-// Signature format: 2.0
diff --git a/services/surfaceflinger/sysprop/api/system-current.txt b/services/surfaceflinger/sysprop/api/system-current.txt
deleted file mode 100644
index 79854b3..0000000
--- a/services/surfaceflinger/sysprop/api/system-current.txt
+++ /dev/null
@@ -1,45 +0,0 @@
-// Signature format: 2.0
-package android.sysprop {
-
- public final class SurfaceFlingerProperties {
- method public static java.util.Optional<java.lang.Long> color_space_agnostic_dataspace();
- method public static java.util.Optional<java.lang.Long> default_composition_dataspace();
- method public static java.util.Optional<java.lang.Integer> default_composition_pixel_format();
- method public static java.util.List<java.lang.Double> display_primary_blue();
- method public static java.util.List<java.lang.Double> display_primary_green();
- method public static java.util.List<java.lang.Double> display_primary_red();
- method public static java.util.List<java.lang.Double> display_primary_white();
- method public static java.util.Optional<java.lang.Boolean> enable_protected_contents();
- method public static java.util.Optional<java.lang.Boolean> force_hwc_copy_for_virtual_displays();
- method public static java.util.Optional<java.lang.Boolean> has_HDR_display();
- method public static java.util.Optional<java.lang.Boolean> has_wide_color_display();
- method public static java.util.Optional<java.lang.Long> max_frame_buffer_acquired_buffers();
- method public static java.util.Optional<java.lang.Long> max_virtual_display_dimension();
- method public static java.util.Optional<java.lang.Long> present_time_offset_from_vsync_ns();
- method public static java.util.Optional<android.sysprop.SurfaceFlingerProperties.primary_display_orientation_values> primary_display_orientation();
- method public static java.util.Optional<java.lang.Boolean> running_without_sync_framework();
- method public static java.util.Optional<java.lang.Integer> set_display_power_timer_ms();
- method public static java.util.Optional<java.lang.Integer> set_idle_timer_ms();
- method public static java.util.Optional<java.lang.Integer> set_touch_timer_ms();
- method public static java.util.Optional<java.lang.Boolean> start_graphics_allocator_service();
- method public static java.util.Optional<java.lang.Boolean> support_kernel_idle_timer();
- method public static java.util.Optional<java.lang.Boolean> use_color_management();
- method public static java.util.Optional<java.lang.Boolean> use_context_priority();
- method public static java.util.Optional<java.lang.Boolean> use_smart_90_for_video();
- method public static java.util.Optional<java.lang.Boolean> use_vr_flinger();
- method public static java.util.Optional<java.lang.Long> vsync_event_phase_offset_ns();
- method public static java.util.Optional<java.lang.Long> vsync_sf_event_phase_offset_ns();
- method public static java.util.Optional<java.lang.Long> wcg_composition_dataspace();
- method public static java.util.Optional<java.lang.Integer> wcg_composition_pixel_format();
- }
-
- public enum SurfaceFlingerProperties.primary_display_orientation_values {
- method public String getPropValue();
- enum_constant public static final android.sysprop.SurfaceFlingerProperties.primary_display_orientation_values ORIENTATION_0;
- enum_constant public static final android.sysprop.SurfaceFlingerProperties.primary_display_orientation_values ORIENTATION_180;
- enum_constant public static final android.sysprop.SurfaceFlingerProperties.primary_display_orientation_values ORIENTATION_270;
- enum_constant public static final android.sysprop.SurfaceFlingerProperties.primary_display_orientation_values ORIENTATION_90;
- }
-
-}
-
diff --git a/services/surfaceflinger/sysprop/api/system-removed.txt b/services/surfaceflinger/sysprop/api/system-removed.txt
deleted file mode 100644
index d802177..0000000
--- a/services/surfaceflinger/sysprop/api/system-removed.txt
+++ /dev/null
@@ -1 +0,0 @@
-// Signature format: 2.0
diff --git a/services/surfaceflinger/sysprop/api/test-current.txt b/services/surfaceflinger/sysprop/api/test-current.txt
deleted file mode 100644
index d802177..0000000
--- a/services/surfaceflinger/sysprop/api/test-current.txt
+++ /dev/null
@@ -1 +0,0 @@
-// Signature format: 2.0
diff --git a/services/surfaceflinger/sysprop/api/test-removed.txt b/services/surfaceflinger/sysprop/api/test-removed.txt
deleted file mode 100644
index d802177..0000000
--- a/services/surfaceflinger/sysprop/api/test-removed.txt
+++ /dev/null
@@ -1 +0,0 @@
-// Signature format: 2.0
diff --git a/services/surfaceflinger/test.png b/services/surfaceflinger/test.png
deleted file mode 100644
index 773dcc3..0000000
--- a/services/surfaceflinger/test.png
+++ /dev/null
Binary files differ
diff --git a/services/surfaceflinger/tests/fakehwc/Android.bp b/services/surfaceflinger/tests/fakehwc/Android.bp
index a2c0611..f359550 100644
--- a/services/surfaceflinger/tests/fakehwc/Android.bp
+++ b/services/surfaceflinger/tests/fakehwc/Android.bp
@@ -10,6 +10,7 @@
],
shared_libs: [
"android.hardware.graphics.composer@2.1",
+ "android.hardware.graphics.composer@2.1-resources",
"android.hardware.graphics.mapper@2.0",
"android.hardware.graphics.mapper@3.0",
"android.hardware.power@1.3",
diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
index 47243a9..82dd3c7 100644
--- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
@@ -34,7 +34,6 @@
#include "ColorLayer.h"
#include "Layer.h"
-#include "TestableScheduler.h"
#include "TestableSurfaceFlinger.h"
#include "mock/DisplayHardware/MockComposer.h"
#include "mock/MockDispSync.h"
@@ -95,10 +94,6 @@
mFlinger.mutableEventQueue().reset(mMessageQueue);
setupScheduler();
- EXPECT_CALL(*mPrimaryDispSync, computeNextRefresh(0)).WillRepeatedly(Return(0));
- EXPECT_CALL(*mPrimaryDispSync, getPeriod())
- .WillRepeatedly(Return(FakeHwcDisplayInjector::DEFAULT_REFRESH_RATE));
- EXPECT_CALL(*mPrimaryDispSync, expectedPresentTime()).WillRepeatedly(Return(0));
EXPECT_CALL(*mNativeWindow, query(NATIVE_WINDOW_WIDTH, _))
.WillRepeatedly(DoAll(SetArgPointee<1>(DEFAULT_DISPLAY_WIDTH), Return(0)));
EXPECT_CALL(*mNativeWindow, query(NATIVE_WINDOW_HEIGHT, _))
@@ -125,15 +120,22 @@
}
void setupScheduler() {
- mScheduler = new TestableScheduler(mFlinger.mutableRefreshRateConfigs());
- mScheduler->mutableEventControlThread().reset(mEventControlThread);
- mScheduler->mutablePrimaryDispSync().reset(mPrimaryDispSync);
- EXPECT_CALL(*mEventThread.get(), registerDisplayEventConnection(_));
- sp<Scheduler::ConnectionHandle> connectionHandle =
- mScheduler->addConnection(std::move(mEventThread));
- mFlinger.mutableSfConnectionHandle() = std::move(connectionHandle);
+ auto eventThread = std::make_unique<mock::EventThread>();
+ auto sfEventThread = std::make_unique<mock::EventThread>();
- mFlinger.mutableScheduler().reset(mScheduler);
+ EXPECT_CALL(*eventThread, registerDisplayEventConnection(_));
+ EXPECT_CALL(*sfEventThread, registerDisplayEventConnection(_));
+
+ auto primaryDispSync = std::make_unique<mock::DispSync>();
+
+ EXPECT_CALL(*primaryDispSync, computeNextRefresh(0)).WillRepeatedly(Return(0));
+ EXPECT_CALL(*primaryDispSync, getPeriod())
+ .WillRepeatedly(Return(FakeHwcDisplayInjector::DEFAULT_REFRESH_RATE));
+ EXPECT_CALL(*primaryDispSync, expectedPresentTime()).WillRepeatedly(Return(0));
+
+ mFlinger.setupScheduler(std::move(primaryDispSync),
+ std::make_unique<mock::EventControlThread>(),
+ std::move(eventThread), std::move(sfEventThread));
}
void setupForceGeometryDirty() {
@@ -157,7 +159,6 @@
std::unordered_set<HWC2::Capability> mDefaultCapabilities = {HWC2::Capability::SidebandStream};
- TestableScheduler* mScheduler;
TestableSurfaceFlinger mFlinger;
sp<DisplayDevice> mDisplay;
sp<DisplayDevice> mExternalDisplay;
@@ -168,13 +169,9 @@
sp<GraphicBuffer> mBuffer = new GraphicBuffer();
ANativeWindowBuffer* mNativeWindowBuffer = mBuffer->getNativeBuffer();
- std::unique_ptr<mock::EventThread> mEventThread = std::make_unique<mock::EventThread>();
- mock::EventControlThread* mEventControlThread = new mock::EventControlThread();
-
Hwc2::mock::Composer* mComposer = nullptr;
renderengine::mock::RenderEngine* mRenderEngine = new renderengine::mock::RenderEngine();
mock::MessageQueue* mMessageQueue = new mock::MessageQueue();
- mock::DispSync* mPrimaryDispSync = new mock::DispSync();
sp<Fence> mClientTargetAcquireFence = Fence::NO_FENCE;
diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
index 5f58e7d..8f6f3ec 100644
--- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
@@ -95,11 +95,10 @@
DisplayTransactionTest();
~DisplayTransactionTest() override;
- void setupScheduler();
-
// --------------------------------------------------------------------
// Mock/Fake injection
+ void injectMockScheduler();
void injectMockComposer(int virtualDisplayCount);
void injectFakeBufferQueueFactory();
void injectFakeNativeWindowSurfaceFactory();
@@ -119,11 +118,7 @@
// --------------------------------------------------------------------
// Test instances
- TestableScheduler* mScheduler;
TestableSurfaceFlinger mFlinger;
- mock::EventThread* mEventThread = new mock::EventThread();
- mock::EventThread* mSFEventThread = new mock::EventThread();
- mock::EventControlThread* mEventControlThread = new mock::EventControlThread();
sp<mock::NativeWindow> mNativeWindow = new mock::NativeWindow();
sp<GraphicBuffer> mBuffer = new GraphicBuffer();
@@ -134,7 +129,11 @@
Hwc2::mock::Composer* mComposer = nullptr;
mock::MessageQueue* mMessageQueue = new mock::MessageQueue();
mock::SurfaceInterceptor* mSurfaceInterceptor = new mock::SurfaceInterceptor();
- mock::DispSync* mPrimaryDispSync = new mock::DispSync();
+
+ mock::DispSync* mPrimaryDispSync = new mock::DispSync;
+ mock::EventControlThread* mEventControlThread = new mock::EventControlThread;
+ mock::EventThread* mEventThread = new mock::EventThread;
+ mock::EventThread* mSFEventThread = new mock::EventThread;
// These mocks are created only when expected to be created via a factory.
sp<mock::GraphicBufferConsumer> mConsumer;
@@ -164,7 +163,7 @@
return nullptr;
});
- setupScheduler();
+ injectMockScheduler();
mFlinger.mutableEventQueue().reset(mMessageQueue);
mFlinger.setupRenderEngine(std::unique_ptr<renderengine::RenderEngine>(mRenderEngine));
mFlinger.mutableInterceptor().reset(mSurfaceInterceptor);
@@ -178,20 +177,14 @@
ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name());
}
-void DisplayTransactionTest::setupScheduler() {
- mScheduler = new TestableScheduler(mFlinger.mutableRefreshRateConfigs());
- mScheduler->mutableEventControlThread().reset(mEventControlThread);
- mScheduler->mutablePrimaryDispSync().reset(mPrimaryDispSync);
+void DisplayTransactionTest::injectMockScheduler() {
EXPECT_CALL(*mEventThread, registerDisplayEventConnection(_));
EXPECT_CALL(*mSFEventThread, registerDisplayEventConnection(_));
- sp<Scheduler::ConnectionHandle> sfConnectionHandle =
- mScheduler->addConnection(std::unique_ptr<EventThread>(mSFEventThread));
- mFlinger.mutableSfConnectionHandle() = std::move(sfConnectionHandle);
- sp<Scheduler::ConnectionHandle> appConnectionHandle =
- mScheduler->addConnection(std::unique_ptr<EventThread>(mEventThread));
- mFlinger.mutableAppConnectionHandle() = std::move(appConnectionHandle);
- mFlinger.mutableScheduler().reset(mScheduler);
+ mFlinger.setupScheduler(std::unique_ptr<DispSync>(mPrimaryDispSync),
+ std::unique_ptr<EventControlThread>(mEventControlThread),
+ std::unique_ptr<EventThread>(mEventThread),
+ std::unique_ptr<EventThread>(mSFEventThread));
}
void DisplayTransactionTest::injectMockComposer(int virtualDisplayCount) {
@@ -1131,8 +1124,8 @@
// Preconditions
// vsync is enabled and available
- mScheduler->mutablePrimaryHWVsyncEnabled() = true;
- mScheduler->mutableHWVsyncAvailable() = true;
+ mFlinger.scheduler()->mutablePrimaryHWVsyncEnabled() = true;
+ mFlinger.scheduler()->mutableHWVsyncAvailable() = true;
// A display exists
auto existing = Case::Display::makeFakeExistingDisplayInjector(this);
@@ -1156,8 +1149,8 @@
// Postconditions
// vsyncs should be off and not available.
- EXPECT_FALSE(mScheduler->mutablePrimaryHWVsyncEnabled());
- EXPECT_FALSE(mScheduler->mutableHWVsyncAvailable());
+ EXPECT_FALSE(mFlinger.scheduler()->mutablePrimaryHWVsyncEnabled());
+ EXPECT_FALSE(mFlinger.scheduler()->mutableHWVsyncAvailable());
// The display should have been removed from the display map.
EXPECT_FALSE(hasDisplayDevice(existing.token()));
@@ -3008,7 +3001,7 @@
}
static void setInitialPrimaryHWVsyncEnabled(DisplayTransactionTest* test, bool enabled) {
- test->mScheduler->mutablePrimaryHWVsyncEnabled() = enabled;
+ test->mFlinger.scheduler()->mutablePrimaryHWVsyncEnabled() = enabled;
}
static void setupRepaintEverythingCallExpectations(DisplayTransactionTest* test) {
diff --git a/services/surfaceflinger/tests/unittests/TestableScheduler.h b/services/surfaceflinger/tests/unittests/TestableScheduler.h
index cb6980e..5157cc4 100644
--- a/services/surfaceflinger/tests/unittests/TestableScheduler.h
+++ b/services/surfaceflinger/tests/unittests/TestableScheduler.h
@@ -20,15 +20,16 @@
#include <gui/ISurfaceComposer.h>
#include "Scheduler/EventThread.h"
-#include "Scheduler/RefreshRateConfigs.h"
#include "Scheduler/Scheduler.h"
namespace android {
class TestableScheduler : public Scheduler {
public:
- TestableScheduler(const scheduler::RefreshRateConfigs& refreshRateConfig)
- : Scheduler([](bool) {}, refreshRateConfig) {}
+ TestableScheduler(std::unique_ptr<DispSync> primaryDispSync,
+ std::unique_ptr<EventControlThread> eventControlThread,
+ const scheduler::RefreshRateConfigs& configs)
+ : Scheduler(std::move(primaryDispSync), std::move(eventControlThread), configs) {}
// Creates EventThreadConnection with the given eventThread. Creates Scheduler::Connection
// and adds it to the list of connectins. Returns the ConnectionHandle for the
@@ -62,7 +63,7 @@
mutableEventControlThread().reset();
mutablePrimaryDispSync().reset();
mConnections.clear();
- };
+ }
};
} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index 64d34ee..27a119b 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -36,7 +36,7 @@
#include "SurfaceFlinger.h"
#include "SurfaceFlingerFactory.h"
#include "SurfaceInterceptor.h"
-
+#include "TestableScheduler.h"
#include "TimeStats/TimeStats.h"
namespace android {
@@ -176,6 +176,8 @@
class TestableSurfaceFlinger {
public:
+ TestableScheduler* scheduler() { return mScheduler; }
+
// Extend this as needed for accessing SurfaceFlinger private (and public)
// functions.
@@ -188,6 +190,23 @@
std::make_unique<impl::HWComposer>(std::move(composer)));
}
+ void setupScheduler(std::unique_ptr<DispSync> primaryDispSync,
+ std::unique_ptr<EventControlThread> eventControlThread,
+ std::unique_ptr<EventThread> appEventThread,
+ std::unique_ptr<EventThread> sfEventThread) {
+ mScheduler =
+ new TestableScheduler(std::move(primaryDispSync), std::move(eventControlThread),
+ mFlinger->mRefreshRateConfigs);
+
+ mFlinger->mAppConnectionHandle = mScheduler->addConnection(std::move(appEventThread));
+ mFlinger->mSfConnectionHandle = mScheduler->addConnection(std::move(sfEventThread));
+
+ mFlinger->mScheduler.reset(mScheduler);
+ mFlinger->mVSyncModulator.emplace(*mScheduler, mFlinger->mAppConnectionHandle,
+ mFlinger->mSfConnectionHandle,
+ mFlinger->mPhaseOffsets->getCurrentOffsets());
+ }
+
using CreateBufferQueueFunction = surfaceflinger::test::Factory::CreateBufferQueueFunction;
void setCreateBufferQueueFunction(CreateBufferQueueFunction f) {
mFactory.mCreateBufferQueue = f;
@@ -338,10 +357,6 @@
auto& mutableHwcPhysicalDisplayIdMap() { return getHwComposer().mPhysicalDisplayIdMap; }
auto& mutableInternalHwcDisplayId() { return getHwComposer().mInternalHwcDisplayId; }
auto& mutableExternalHwcDisplayId() { return getHwComposer().mExternalHwcDisplayId; }
- auto& mutableScheduler() { return mFlinger->mScheduler; }
- auto& mutableAppConnectionHandle() { return mFlinger->mAppConnectionHandle; }
- auto& mutableSfConnectionHandle() { return mFlinger->mSfConnectionHandle; }
- auto& mutableRefreshRateConfigs() { return mFlinger->mRefreshRateConfigs; }
~TestableSurfaceFlinger() {
// All these pointer and container clears help ensure that GMock does
@@ -353,7 +368,7 @@
mutableDrawingState().displays.clear();
mutableEventQueue().reset();
mutableInterceptor().reset();
- mutableScheduler().reset();
+ mFlinger->mScheduler.reset();
mFlinger->mCompositionEngine->setHwComposer(std::unique_ptr<HWComposer>());
mFlinger->mCompositionEngine->setRenderEngine(
std::unique_ptr<renderengine::RenderEngine>());
@@ -573,6 +588,7 @@
surfaceflinger::test::Factory mFactory;
sp<SurfaceFlinger> mFlinger = new SurfaceFlinger(mFactory, SurfaceFlinger::SkipInitialization);
+ TestableScheduler* mScheduler = nullptr;
// We need to keep a reference to these so they are properly destroyed.
std::vector<std::unique_ptr<HWC2Display>> mFakeHwcDisplays;
diff --git a/services/vr/hardware_composer/Android.bp b/services/vr/hardware_composer/Android.bp
index 1604775..bc7cc1c 100644
--- a/services/vr/hardware_composer/Android.bp
+++ b/services/vr/hardware_composer/Android.bp
@@ -14,6 +14,7 @@
shared_libs: [
"android.frameworks.vr.composer@1.0",
"android.hardware.graphics.composer@2.1",
+ "android.hardware.graphics.composer@2.1-resources",
"android.hardware.graphics.mapper@2.0",
"android.hardware.graphics.mapper@3.0",
"libbase",
diff --git a/vulkan/Android.bp b/vulkan/Android.bp
index 7747734..4934970 100644
--- a/vulkan/Android.bp
+++ b/vulkan/Android.bp
@@ -31,6 +31,5 @@
subdirs = [
"nulldrv",
"libvulkan",
- "tools",
"vkjson",
]
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/api.cpp b/vulkan/libvulkan/api.cpp
index 368130d..48f26e7 100644
--- a/vulkan/libvulkan/api.cpp
+++ b/vulkan/libvulkan/api.cpp
@@ -1172,11 +1172,20 @@
std::call_once(once_flag, []() {
if (driver::OpenHAL()) {
- DiscoverLayers();
initialized = true;
}
});
+ {
+ static pid_t pid = getpid() + 1;
+ static std::mutex layer_lock;
+ std::lock_guard<std::mutex> lock(layer_lock);
+ if (pid != getpid()) {
+ pid = getpid();
+ DiscoverLayers();
+ }
+ }
+
return initialized;
}
diff --git a/vulkan/tools/Android.bp b/vulkan/tools/Android.bp
deleted file mode 100644
index 2514094..0000000
--- a/vulkan/tools/Android.bp
+++ /dev/null
@@ -1,43 +0,0 @@
-// Copyright 2015 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: "vkinfo",
-
- clang: true,
- cflags: [
- "-fvisibility=hidden",
- "-fstrict-aliasing",
-
- "-DLOG_TAG=\"vkinfo\"",
-
- "-Weverything",
- "-Werror",
- "-Wno-padded",
- "-Wno-undef",
- "-Wno-switch-enum",
- ],
- cppflags: [
- "-Wno-c++98-compat-pedantic",
- "-Wno-c99-extensions",
- "-Wno-old-style-cast",
- ],
-
- srcs: ["vkinfo.cpp"],
-
- shared_libs: [
- "libvulkan",
- "liblog",
- ],
-}
diff --git a/vulkan/tools/vkinfo.cpp b/vulkan/tools/vkinfo.cpp
deleted file mode 100644
index 89bc926..0000000
--- a/vulkan/tools/vkinfo.cpp
+++ /dev/null
@@ -1,634 +0,0 @@
-/*
- * Copyright 2015 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>
-#include <stdlib.h>
-#include <unistd.h>
-
-#include <algorithm>
-#include <array>
-#include <sstream>
-#include <vector>
-
-#include <vulkan/vulkan.h>
-
-namespace {
-
-struct Options {
- bool layer_description;
- bool layer_extensions;
- bool unsupported_features;
- bool validate;
-};
-
-struct GpuInfo {
- VkPhysicalDeviceProperties properties;
- VkPhysicalDeviceMemoryProperties memory;
- VkPhysicalDeviceFeatures features;
- std::vector<VkQueueFamilyProperties> queue_families;
- std::vector<VkExtensionProperties> extensions;
- std::vector<VkLayerProperties> layers;
- std::vector<std::vector<VkExtensionProperties>> layer_extensions;
-};
-struct VulkanInfo {
- std::vector<VkExtensionProperties> extensions;
- std::vector<VkLayerProperties> layers;
- std::vector<std::vector<VkExtensionProperties>> layer_extensions;
- std::vector<GpuInfo> gpus;
-};
-
-// ----------------------------------------------------------------------------
-
-[[noreturn]] void die(const char* proc, VkResult result) {
- const char* result_str;
- switch (result) {
- // clang-format off
- case VK_SUCCESS: result_str = "VK_SUCCESS"; break;
- case VK_NOT_READY: result_str = "VK_NOT_READY"; break;
- case VK_TIMEOUT: result_str = "VK_TIMEOUT"; break;
- case VK_EVENT_SET: result_str = "VK_EVENT_SET"; break;
- case VK_EVENT_RESET: result_str = "VK_EVENT_RESET"; break;
- case VK_INCOMPLETE: result_str = "VK_INCOMPLETE"; break;
- case VK_ERROR_OUT_OF_HOST_MEMORY: result_str = "VK_ERROR_OUT_OF_HOST_MEMORY"; break;
- case VK_ERROR_OUT_OF_DEVICE_MEMORY: result_str = "VK_ERROR_OUT_OF_DEVICE_MEMORY"; break;
- case VK_ERROR_INITIALIZATION_FAILED: result_str = "VK_ERROR_INITIALIZATION_FAILED"; break;
- case VK_ERROR_DEVICE_LOST: result_str = "VK_ERROR_DEVICE_LOST"; break;
- case VK_ERROR_MEMORY_MAP_FAILED: result_str = "VK_ERROR_MEMORY_MAP_FAILED"; break;
- case VK_ERROR_LAYER_NOT_PRESENT: result_str = "VK_ERROR_LAYER_NOT_PRESENT"; break;
- case VK_ERROR_EXTENSION_NOT_PRESENT: result_str = "VK_ERROR_EXTENSION_NOT_PRESENT"; break;
- case VK_ERROR_INCOMPATIBLE_DRIVER: result_str = "VK_ERROR_INCOMPATIBLE_DRIVER"; break;
- default: result_str = "<unknown VkResult>"; break;
- // clang-format on
- }
- fprintf(stderr, "%s failed: %s (%d)\n", proc, result_str, result);
- exit(1);
-}
-
-bool HasExtension(const std::vector<VkExtensionProperties>& extensions,
- const char* name) {
- return std::find_if(extensions.cbegin(), extensions.cend(),
- [=](const VkExtensionProperties& prop) {
- return strcmp(prop.extensionName, name) == 0;
- }) != extensions.end();
-}
-
-void EnumerateInstanceExtensions(
- const char* layer_name,
- std::vector<VkExtensionProperties>* extensions) {
- VkResult result;
- uint32_t count;
- result =
- vkEnumerateInstanceExtensionProperties(layer_name, &count, nullptr);
- if (result != VK_SUCCESS)
- die("vkEnumerateInstanceExtensionProperties (count)", result);
- do {
- extensions->resize(count);
- result = vkEnumerateInstanceExtensionProperties(layer_name, &count,
- extensions->data());
- } while (result == VK_INCOMPLETE);
- if (result != VK_SUCCESS)
- die("vkEnumerateInstanceExtensionProperties (data)", result);
-}
-
-void EnumerateDeviceExtensions(VkPhysicalDevice gpu,
- const char* layer_name,
- std::vector<VkExtensionProperties>* extensions) {
- VkResult result;
- uint32_t count;
- result =
- vkEnumerateDeviceExtensionProperties(gpu, layer_name, &count, nullptr);
- if (result != VK_SUCCESS)
- die("vkEnumerateDeviceExtensionProperties (count)", result);
- do {
- extensions->resize(count);
- result = vkEnumerateDeviceExtensionProperties(gpu, layer_name, &count,
- extensions->data());
- } while (result == VK_INCOMPLETE);
- if (result != VK_SUCCESS)
- die("vkEnumerateDeviceExtensionProperties (data)", result);
-}
-
-void GatherGpuInfo(VkPhysicalDevice gpu,
- const Options &options,
- GpuInfo& info) {
- VkResult result;
- uint32_t count;
-
- vkGetPhysicalDeviceProperties(gpu, &info.properties);
- vkGetPhysicalDeviceMemoryProperties(gpu, &info.memory);
- vkGetPhysicalDeviceFeatures(gpu, &info.features);
-
- vkGetPhysicalDeviceQueueFamilyProperties(gpu, &count, nullptr);
- info.queue_families.resize(count);
- vkGetPhysicalDeviceQueueFamilyProperties(gpu, &count,
- info.queue_families.data());
-
- result = vkEnumerateDeviceLayerProperties(gpu, &count, nullptr);
- if (result != VK_SUCCESS)
- die("vkEnumerateDeviceLayerProperties (count)", result);
- do {
- info.layers.resize(count);
- result =
- vkEnumerateDeviceLayerProperties(gpu, &count, info.layers.data());
- } while (result == VK_INCOMPLETE);
- if (result != VK_SUCCESS)
- die("vkEnumerateDeviceLayerProperties (data)", result);
- info.layer_extensions.resize(info.layers.size());
-
- EnumerateDeviceExtensions(gpu, nullptr, &info.extensions);
- for (size_t i = 0; i < info.layers.size(); i++) {
- EnumerateDeviceExtensions(gpu, info.layers[i].layerName,
- &info.layer_extensions[i]);
- }
-
- const std::array<const char*, 1> kDesiredExtensions = {
- {VK_KHR_SWAPCHAIN_EXTENSION_NAME},
- };
- const char* extensions[kDesiredExtensions.size()];
- uint32_t num_extensions = 0;
- for (const auto& desired_ext : kDesiredExtensions) {
- bool available = HasExtension(info.extensions, desired_ext);
- if (options.validate) {
- for (size_t i = 0; !available && i < info.layer_extensions.size();
- i++)
- available = HasExtension(info.layer_extensions[i], desired_ext);
- }
- if (available)
- extensions[num_extensions++] = desired_ext;
- }
-
- VkDevice device;
- float queue_priorities[] = {0.0};
- const VkDeviceQueueCreateInfo queue_create_info = {
- .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
- .queueFamilyIndex = 0,
- .queueCount = 1,
- .pQueuePriorities = queue_priorities
- };
- // clang-format off
- const char *kValidationLayers[] = {
- "VK_LAYER_GOOGLE_threading",
- "VK_LAYER_LUNARG_parameter_validation",
- "VK_LAYER_LUNARG_device_limits",
- "VK_LAYER_LUNARG_object_tracker",
- "VK_LAYER_LUNARG_image",
- "VK_LAYER_LUNARG_core_validation",
- "VK_LAYER_LUNARG_swapchain",
- "VK_LAYER_GOOGLE_unique_objects"
- };
- // clang-format on
- uint32_t num_layers = sizeof(kValidationLayers) / sizeof(char*);
- const VkDeviceCreateInfo create_info = {
- .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
- .queueCreateInfoCount = 1,
- .pQueueCreateInfos = &queue_create_info,
- .enabledExtensionCount = num_extensions,
- .ppEnabledExtensionNames = extensions,
- .enabledLayerCount = (options.validate) ? num_layers : 0,
- .ppEnabledLayerNames = kValidationLayers,
- .pEnabledFeatures = &info.features,
- };
- result = vkCreateDevice(gpu, &create_info, nullptr, &device);
- if (result != VK_SUCCESS)
- die("vkCreateDevice", result);
- vkDestroyDevice(device, nullptr);
-}
-
-void GatherInfo(VulkanInfo* info, const Options& options) {
- VkResult result;
- uint32_t count;
-
- result = vkEnumerateInstanceLayerProperties(&count, nullptr);
- if (result != VK_SUCCESS)
- die("vkEnumerateInstanceLayerProperties (count)", result);
- do {
- info->layers.resize(count);
- result =
- vkEnumerateInstanceLayerProperties(&count, info->layers.data());
- } while (result == VK_INCOMPLETE);
- if (result != VK_SUCCESS)
- die("vkEnumerateInstanceLayerProperties (data)", result);
- info->layer_extensions.resize(info->layers.size());
-
- EnumerateInstanceExtensions(nullptr, &info->extensions);
- for (size_t i = 0; i < info->layers.size(); i++) {
- EnumerateInstanceExtensions(info->layers[i].layerName,
- &info->layer_extensions[i]);
- }
-
- const char* kDesiredExtensions[] = {
- VK_EXT_DEBUG_REPORT_EXTENSION_NAME,
- };
- const char*
- extensions[sizeof(kDesiredExtensions) / sizeof(kDesiredExtensions[0])];
- uint32_t num_extensions = 0;
- for (const auto& desired_ext : kDesiredExtensions) {
- bool available = HasExtension(info->extensions, desired_ext);
- if (options.validate) {
- for (size_t i = 0; !available && i < info->layer_extensions.size();
- i++)
- available =
- HasExtension(info->layer_extensions[i], desired_ext);
- }
- if (available)
- extensions[num_extensions++] = desired_ext;
- }
-
- // clang-format off
- const char *kValidationLayers[] = {
- "VK_LAYER_GOOGLE_threading",
- "VK_LAYER_LUNARG_parameter_validation",
- "VK_LAYER_LUNARG_device_limits",
- "VK_LAYER_LUNARG_object_tracker",
- "VK_LAYER_LUNARG_image",
- "VK_LAYER_LUNARG_core_validation",
- "VK_LAYER_LUNARG_swapchain",
- "VK_LAYER_GOOGLE_unique_objects"
- };
- // clang-format on
- uint32_t num_layers = sizeof(kValidationLayers) / sizeof(char*);
-
- const VkApplicationInfo application_info = {
- .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
- .pApplicationName = "vkinfo",
- .applicationVersion = 0,
- .pEngineName = "vkinfo",
- .engineVersion = 0,
- .apiVersion = VK_API_VERSION_1_0,
- };
- const VkInstanceCreateInfo create_info = {
- .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
- .pApplicationInfo = &application_info,
- .enabledExtensionCount = num_extensions,
- .ppEnabledExtensionNames = extensions,
- .enabledLayerCount = (options.validate) ? num_layers : 0,
- .ppEnabledLayerNames = kValidationLayers,
- };
- VkInstance instance;
- result = vkCreateInstance(&create_info, nullptr, &instance);
- if (result != VK_SUCCESS)
- die("vkCreateInstance", result);
-
- uint32_t num_gpus;
- result = vkEnumeratePhysicalDevices(instance, &num_gpus, nullptr);
- if (result != VK_SUCCESS)
- die("vkEnumeratePhysicalDevices (count)", result);
- std::vector<VkPhysicalDevice> gpus(num_gpus, VK_NULL_HANDLE);
- do {
- gpus.resize(num_gpus, VK_NULL_HANDLE);
- result = vkEnumeratePhysicalDevices(instance, &num_gpus, gpus.data());
- } while (result == VK_INCOMPLETE);
- if (result != VK_SUCCESS)
- die("vkEnumeratePhysicalDevices (data)", result);
-
- info->gpus.resize(num_gpus);
- for (size_t i = 0; i < gpus.size(); i++)
- GatherGpuInfo(gpus[i], options, info->gpus.at(i));
-
- vkDestroyInstance(instance, nullptr);
-}
-
-// ----------------------------------------------------------------------------
-
-const size_t kMaxIndent = 8;
-const size_t kIndentSize = 3;
-std::array<char, kMaxIndent * kIndentSize + 1> kIndent;
-const char* Indent(size_t n) {
- static bool initialized = false;
- if (!initialized) {
- kIndent.fill(' ');
- kIndent.back() = '\0';
- initialized = true;
- }
- return kIndent.data() +
- (kIndent.size() - (kIndentSize * std::min(n, kMaxIndent) + 1));
-}
-
-const char* VkPhysicalDeviceTypeStr(VkPhysicalDeviceType type) {
- switch (type) {
- case VK_PHYSICAL_DEVICE_TYPE_OTHER:
- return "OTHER";
- case VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU:
- return "INTEGRATED_GPU";
- case VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU:
- return "DISCRETE_GPU";
- case VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU:
- return "VIRTUAL_GPU";
- case VK_PHYSICAL_DEVICE_TYPE_CPU:
- return "CPU";
- default:
- return "<UNKNOWN>";
- }
-}
-
-void PrintExtensions(const std::vector<VkExtensionProperties>& extensions,
- const Options& /*options*/,
- size_t indent) {
- for (const auto& e : extensions)
- printf("%s%s (v%u)\n", Indent(indent), e.extensionName, e.specVersion);
-}
-
-void PrintLayers(
- const std::vector<VkLayerProperties>& layers,
- const std::vector<std::vector<VkExtensionProperties>> extensions,
- const Options& options,
- size_t indent) {
- for (size_t i = 0; i < layers.size(); i++) {
- printf("%s%s %u.%u.%u/%u\n", Indent(indent), layers[i].layerName,
- VK_VERSION_MAJOR(layers[i].specVersion),
- VK_VERSION_MINOR(layers[i].specVersion),
- VK_VERSION_PATCH(layers[i].specVersion),
- layers[i].implementationVersion);
- if (options.layer_description)
- printf("%s%s\n", Indent(indent + 1), layers[i].description);
- if (options.layer_extensions && !extensions[i].empty()) {
- if (!extensions[i].empty()) {
- printf("%sExtensions [%zu]:\n", Indent(indent + 1),
- extensions[i].size());
- PrintExtensions(extensions[i], options, indent + 2);
- }
- }
- }
-}
-
-void PrintAllFeatures(const char* indent,
- const VkPhysicalDeviceFeatures& features) {
- // clang-format off
- printf("%srobustBufferAccess: %s\n", indent, features.robustBufferAccess ? "YES" : "NO");
- printf("%sfullDrawIndexUint32: %s\n", indent, features.fullDrawIndexUint32 ? "YES" : "NO");
- printf("%simageCubeArray: %s\n", indent, features.imageCubeArray ? "YES" : "NO");
- printf("%sindependentBlend: %s\n", indent, features.independentBlend ? "YES" : "NO");
- printf("%sgeometryShader: %s\n", indent, features.geometryShader ? "YES" : "NO");
- printf("%stessellationShader: %s\n", indent, features.tessellationShader ? "YES" : "NO");
- printf("%ssampleRateShading: %s\n", indent, features.sampleRateShading ? "YES" : "NO");
- printf("%sdualSrcBlend: %s\n", indent, features.dualSrcBlend ? "YES" : "NO");
- printf("%slogicOp: %s\n", indent, features.logicOp ? "YES" : "NO");
- printf("%smultiDrawIndirect: %s\n", indent, features.multiDrawIndirect ? "YES" : "NO");
- printf("%sdrawIndirectFirstInstance: %s\n", indent, features.drawIndirectFirstInstance ? "YES" : "NO");
- printf("%sdepthClamp: %s\n", indent, features.depthClamp ? "YES" : "NO");
- printf("%sdepthBiasClamp: %s\n", indent, features.depthBiasClamp ? "YES" : "NO");
- printf("%sfillModeNonSolid: %s\n", indent, features.fillModeNonSolid ? "YES" : "NO");
- printf("%sdepthBounds: %s\n", indent, features.depthBounds ? "YES" : "NO");
- printf("%swideLines: %s\n", indent, features.wideLines ? "YES" : "NO");
- printf("%slargePoints: %s\n", indent, features.largePoints ? "YES" : "NO");
- printf("%salphaToOne: %s\n", indent, features.alphaToOne ? "YES" : "NO");
- printf("%smultiViewport: %s\n", indent, features.multiViewport ? "YES" : "NO");
- printf("%ssamplerAnisotropy: %s\n", indent, features.samplerAnisotropy ? "YES" : "NO");
- printf("%stextureCompressionETC2: %s\n", indent, features.textureCompressionETC2 ? "YES" : "NO");
- printf("%stextureCompressionASTC_LDR: %s\n", indent, features.textureCompressionASTC_LDR ? "YES" : "NO");
- printf("%stextureCompressionBC: %s\n", indent, features.textureCompressionBC ? "YES" : "NO");
- printf("%socclusionQueryPrecise: %s\n", indent, features.occlusionQueryPrecise ? "YES" : "NO");
- printf("%spipelineStatisticsQuery: %s\n", indent, features.pipelineStatisticsQuery ? "YES" : "NO");
- printf("%svertexPipelineStoresAndAtomics: %s\n", indent, features.vertexPipelineStoresAndAtomics ? "YES" : "NO");
- printf("%sfragmentStoresAndAtomics: %s\n", indent, features.fragmentStoresAndAtomics ? "YES" : "NO");
- printf("%sshaderTessellationAndGeometryPointSize: %s\n", indent, features.shaderTessellationAndGeometryPointSize ? "YES" : "NO");
- printf("%sshaderImageGatherExtended: %s\n", indent, features.shaderImageGatherExtended ? "YES" : "NO");
- printf("%sshaderStorageImageExtendedFormats: %s\n", indent, features.shaderStorageImageExtendedFormats ? "YES" : "NO");
- printf("%sshaderStorageImageMultisample: %s\n", indent, features.shaderStorageImageMultisample ? "YES" : "NO");
- printf("%sshaderStorageImageReadWithoutFormat: %s\n", indent, features.shaderStorageImageReadWithoutFormat ? "YES" : "NO");
- printf("%sshaderStorageImageWriteWithoutFormat: %s\n", indent, features.shaderStorageImageWriteWithoutFormat ? "YES" : "NO");
- printf("%sshaderUniformBufferArrayDynamicIndexing: %s\n", indent, features.shaderUniformBufferArrayDynamicIndexing ? "YES" : "NO");
- printf("%sshaderSampledImageArrayDynamicIndexing: %s\n", indent, features.shaderSampledImageArrayDynamicIndexing ? "YES" : "NO");
- printf("%sshaderStorageBufferArrayDynamicIndexing: %s\n", indent, features.shaderStorageBufferArrayDynamicIndexing ? "YES" : "NO");
- printf("%sshaderStorageImageArrayDynamicIndexing: %s\n", indent, features.shaderStorageImageArrayDynamicIndexing ? "YES" : "NO");
- printf("%sshaderClipDistance: %s\n", indent, features.shaderClipDistance ? "YES" : "NO");
- printf("%sshaderCullDistance: %s\n", indent, features.shaderCullDistance ? "YES" : "NO");
- printf("%sshaderFloat64: %s\n", indent, features.shaderFloat64 ? "YES" : "NO");
- printf("%sshaderInt64: %s\n", indent, features.shaderInt64 ? "YES" : "NO");
- printf("%sshaderInt16: %s\n", indent, features.shaderInt16 ? "YES" : "NO");
- printf("%sshaderResourceResidency: %s\n", indent, features.shaderResourceResidency ? "YES" : "NO");
- printf("%sshaderResourceMinLod: %s\n", indent, features.shaderResourceMinLod ? "YES" : "NO");
- printf("%ssparseBinding: %s\n", indent, features.sparseBinding ? "YES" : "NO");
- printf("%ssparseResidencyBuffer: %s\n", indent, features.sparseResidencyBuffer ? "YES" : "NO");
- printf("%ssparseResidencyImage2D: %s\n", indent, features.sparseResidencyImage2D ? "YES" : "NO");
- printf("%ssparseResidencyImage3D: %s\n", indent, features.sparseResidencyImage3D ? "YES" : "NO");
- printf("%ssparseResidency2Samples: %s\n", indent, features.sparseResidency2Samples ? "YES" : "NO");
- printf("%ssparseResidency4Samples: %s\n", indent, features.sparseResidency4Samples ? "YES" : "NO");
- printf("%ssparseResidency8Samples: %s\n", indent, features.sparseResidency8Samples ? "YES" : "NO");
- printf("%ssparseResidency16Samples: %s\n", indent, features.sparseResidency16Samples ? "YES" : "NO");
- printf("%ssparseResidencyAliased: %s\n", indent, features.sparseResidencyAliased ? "YES" : "NO");
- printf("%svariableMultisampleRate: %s\n", indent, features.variableMultisampleRate ? "YES" : "NO");
- printf("%sinheritedQueries: %s\n", indent, features.inheritedQueries ? "YES" : "NO");
- // clang-format on
-}
-
-void PrintSupportedFeatures(const char* indent,
- const VkPhysicalDeviceFeatures& features) {
- // clang-format off
- if (features.robustBufferAccess) printf("%srobustBufferAccess\n", indent);
- if (features.fullDrawIndexUint32) printf("%sfullDrawIndexUint32\n", indent);
- if (features.imageCubeArray) printf("%simageCubeArray\n", indent);
- if (features.independentBlend) printf("%sindependentBlend\n", indent);
- if (features.geometryShader) printf("%sgeometryShader\n", indent);
- if (features.tessellationShader) printf("%stessellationShader\n", indent);
- if (features.sampleRateShading) printf("%ssampleRateShading\n", indent);
- if (features.dualSrcBlend) printf("%sdualSrcBlend\n", indent);
- if (features.logicOp) printf("%slogicOp\n", indent);
- if (features.multiDrawIndirect) printf("%smultiDrawIndirect\n", indent);
- if (features.drawIndirectFirstInstance) printf("%sdrawIndirectFirstInstance\n", indent);
- if (features.depthClamp) printf("%sdepthClamp\n", indent);
- if (features.depthBiasClamp) printf("%sdepthBiasClamp\n", indent);
- if (features.fillModeNonSolid) printf("%sfillModeNonSolid\n", indent);
- if (features.depthBounds) printf("%sdepthBounds\n", indent);
- if (features.wideLines) printf("%swideLines\n", indent);
- if (features.largePoints) printf("%slargePoints\n", indent);
- if (features.alphaToOne) printf("%salphaToOne\n", indent);
- if (features.multiViewport) printf("%smultiViewport\n", indent);
- if (features.samplerAnisotropy) printf("%ssamplerAnisotropy\n", indent);
- if (features.textureCompressionETC2) printf("%stextureCompressionETC2\n", indent);
- if (features.textureCompressionASTC_LDR) printf("%stextureCompressionASTC_LDR\n", indent);
- if (features.textureCompressionBC) printf("%stextureCompressionBC\n", indent);
- if (features.occlusionQueryPrecise) printf("%socclusionQueryPrecise\n", indent);
- if (features.pipelineStatisticsQuery) printf("%spipelineStatisticsQuery\n", indent);
- if (features.vertexPipelineStoresAndAtomics) printf("%svertexPipelineStoresAndAtomics\n", indent);
- if (features.fragmentStoresAndAtomics) printf("%sfragmentStoresAndAtomics\n", indent);
- if (features.shaderTessellationAndGeometryPointSize) printf("%sshaderTessellationAndGeometryPointSize\n", indent);
- if (features.shaderImageGatherExtended) printf("%sshaderImageGatherExtended\n", indent);
- if (features.shaderStorageImageExtendedFormats) printf("%sshaderStorageImageExtendedFormats\n", indent);
- if (features.shaderStorageImageMultisample) printf("%sshaderStorageImageMultisample\n", indent);
- if (features.shaderStorageImageReadWithoutFormat) printf("%sshaderStorageImageReadWithoutFormat\n", indent);
- if (features.shaderStorageImageWriteWithoutFormat) printf("%sshaderStorageImageWriteWithoutFormat\n", indent);
- if (features.shaderUniformBufferArrayDynamicIndexing) printf("%sshaderUniformBufferArrayDynamicIndexing\n", indent);
- if (features.shaderSampledImageArrayDynamicIndexing) printf("%sshaderSampledImageArrayDynamicIndexing\n", indent);
- if (features.shaderStorageBufferArrayDynamicIndexing) printf("%sshaderStorageBufferArrayDynamicIndexing\n", indent);
- if (features.shaderStorageImageArrayDynamicIndexing) printf("%sshaderStorageImageArrayDynamicIndexing\n", indent);
- if (features.shaderClipDistance) printf("%sshaderClipDistance\n", indent);
- if (features.shaderCullDistance) printf("%sshaderCullDistance\n", indent);
- if (features.shaderFloat64) printf("%sshaderFloat64\n", indent);
- if (features.shaderInt64) printf("%sshaderInt64\n", indent);
- if (features.shaderInt16) printf("%sshaderInt16\n", indent);
- if (features.shaderResourceResidency) printf("%sshaderResourceResidency\n", indent);
- if (features.shaderResourceMinLod) printf("%sshaderResourceMinLod\n", indent);
- if (features.sparseBinding) printf("%ssparseBinding\n", indent);
- if (features.sparseResidencyBuffer) printf("%ssparseResidencyBuffer\n", indent);
- if (features.sparseResidencyImage2D) printf("%ssparseResidencyImage2D\n", indent);
- if (features.sparseResidencyImage3D) printf("%ssparseResidencyImage3D\n", indent);
- if (features.sparseResidency2Samples) printf("%ssparseResidency2Samples\n", indent);
- if (features.sparseResidency4Samples) printf("%ssparseResidency4Samples\n", indent);
- if (features.sparseResidency8Samples) printf("%ssparseResidency8Samples\n", indent);
- if (features.sparseResidency16Samples) printf("%ssparseResidency16Samples\n", indent);
- if (features.sparseResidencyAliased) printf("%ssparseResidencyAliased\n", indent);
- if (features.variableMultisampleRate) printf("%svariableMultisampleRate\n", indent);
- if (features.inheritedQueries) printf("%sinheritedQueries\n", indent);
- // clang-format on
-}
-
-void PrintGpuInfo(const GpuInfo& info, const Options& options, size_t indent) {
- VkResult result;
- std::ostringstream strbuf;
-
- printf("%s\"%s\" (%s) %u.%u.%u/%#x [%04x:%04x]\n", Indent(indent),
- info.properties.deviceName,
- VkPhysicalDeviceTypeStr(info.properties.deviceType),
- VK_VERSION_MAJOR(info.properties.apiVersion),
- VK_VERSION_MINOR(info.properties.apiVersion),
- VK_VERSION_PATCH(info.properties.apiVersion),
- info.properties.driverVersion, info.properties.vendorID,
- info.properties.deviceID);
-
- for (uint32_t heap = 0; heap < info.memory.memoryHeapCount; heap++) {
- if ((info.memory.memoryHeaps[heap].flags &
- VK_MEMORY_HEAP_DEVICE_LOCAL_BIT) != 0)
- strbuf << "DEVICE_LOCAL";
- printf("%sHeap %u: %" PRIu64 " MiB (0x%" PRIx64 " B) %s\n",
- Indent(indent + 1), heap,
- info.memory.memoryHeaps[heap].size / 0x100000,
- info.memory.memoryHeaps[heap].size, strbuf.str().c_str());
- strbuf.str(std::string());
-
- for (uint32_t type = 0; type < info.memory.memoryTypeCount; type++) {
- if (info.memory.memoryTypes[type].heapIndex != heap)
- continue;
- VkMemoryPropertyFlags flags =
- info.memory.memoryTypes[type].propertyFlags;
- if ((flags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) != 0)
- strbuf << " DEVICE_LOCAL";
- if ((flags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) != 0)
- strbuf << " HOST_VISIBLE";
- if ((flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) != 0)
- strbuf << " COHERENT";
- if ((flags & VK_MEMORY_PROPERTY_HOST_CACHED_BIT) != 0)
- strbuf << " CACHED";
- if ((flags & VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT) != 0)
- strbuf << " LAZILY_ALLOCATED";
- printf("%sType %u:%s\n", Indent(indent + 2), type,
- strbuf.str().c_str());
- strbuf.str(std::string());
- }
- }
-
- for (uint32_t family = 0; family < info.queue_families.size(); family++) {
- const VkQueueFamilyProperties& qprops = info.queue_families[family];
- VkQueueFlags flags = qprops.queueFlags;
- char flags_str[5];
- flags_str[0] = (flags & VK_QUEUE_GRAPHICS_BIT) ? 'G' : '_';
- flags_str[1] = (flags & VK_QUEUE_COMPUTE_BIT) ? 'C' : '_';
- flags_str[2] = (flags & VK_QUEUE_TRANSFER_BIT) ? 'T' : '_';
- flags_str[3] = (flags & VK_QUEUE_SPARSE_BINDING_BIT) ? 'S' : '_';
- flags_str[4] = '\0';
- printf(
- "%sQueue Family %u: %ux %s\n"
- "%stimestampValidBits: %ub\n"
- "%sminImageTransferGranularity: (%u,%u,%u)\n",
- Indent(indent + 1), family, qprops.queueCount, flags_str,
- Indent(indent + 2), qprops.timestampValidBits, Indent(indent + 2),
- qprops.minImageTransferGranularity.width,
- qprops.minImageTransferGranularity.height,
- qprops.minImageTransferGranularity.depth);
- }
-
- printf("%sFeatures:\n", Indent(indent + 1));
- if (options.unsupported_features) {
- PrintAllFeatures(Indent(indent + 2), info.features);
- } else {
- PrintSupportedFeatures(Indent(indent + 2), info.features);
- }
-
- printf("%sExtensions [%zu]:\n", Indent(indent + 1), info.extensions.size());
- if (!info.extensions.empty())
- PrintExtensions(info.extensions, options, indent + 2);
- printf("%sLayers [%zu]:\n", Indent(indent + 1), info.layers.size());
- if (!info.layers.empty())
- PrintLayers(info.layers, info.layer_extensions, options, indent + 2);
-}
-
-void PrintInfo(const VulkanInfo& info, const Options& options) {
- std::ostringstream strbuf;
- size_t indent = 0;
-
- printf("%sInstance Extensions [%zu]:\n", Indent(indent),
- info.extensions.size());
- PrintExtensions(info.extensions, options, indent + 1);
- printf("%sInstance Layers [%zu]:\n", Indent(indent), info.layers.size());
- if (!info.layers.empty())
- PrintLayers(info.layers, info.layer_extensions, options, indent + 1);
-
- printf("%sPhysicalDevices [%zu]:\n", Indent(indent), info.gpus.size());
- for (const auto& gpu : info.gpus)
- PrintGpuInfo(gpu, options, indent + 1);
-}
-
-const char kUsageString[] =
- "usage: vkinfo [options]\n"
- " -v enable all the following verbose options\n"
- " -layer_description print layer description strings\n"
- " -layer_extensions print extensions supported by each layer\n"
- " -unsupported_features print all physical device features\n"
- " -validate enable validation layers if present\n"
- " -debug_pause pause at start until resumed via debugger\n";
-
-} // namespace
-
-// ----------------------------------------------------------------------------
-
-int main(int argc, char const* argv[]) {
- static volatile bool startup_pause = false;
- Options options = {
- .layer_description = false, .layer_extensions = false,
- .unsupported_features = false,
- .validate = false,
- };
- for (int argi = 1; argi < argc; argi++) {
- if (strcmp(argv[argi], "-h") == 0) {
- fputs(kUsageString, stdout);
- return 0;
- }
- if (strcmp(argv[argi], "-v") == 0) {
- options.layer_description = true;
- options.layer_extensions = true;
- options.unsupported_features = true;
- } else if (strcmp(argv[argi], "-layer_description") == 0) {
- options.layer_description = true;
- } else if (strcmp(argv[argi], "-layer_extensions") == 0) {
- options.layer_extensions = true;
- } else if (strcmp(argv[argi], "-unsupported_features") == 0) {
- options.unsupported_features = true;
- } else if (strcmp(argv[argi], "-validate") == 0) {
- options.validate = true;
- } else if (strcmp(argv[argi], "-debug_pause") == 0) {
- startup_pause = true;
- }
- }
-
- while (startup_pause) {
- sleep(0);
- }
-
- VulkanInfo info;
- GatherInfo(&info, options);
- PrintInfo(info, options);
- return 0;
-}
diff --git a/vulkan/vkjson/vkjson.cc b/vulkan/vkjson/vkjson.cc
index 6204779..8f714d8 100644
--- a/vulkan/vkjson/vkjson.cc
+++ b/vulkan/vkjson/vkjson.cc
@@ -53,7 +53,7 @@
// 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 = 0.99 * std::numeric_limits<double>::min();
+static const double SAFE_DOUBLE_MIN = -SAFE_DOUBLE_MAX;
template <typename T> struct EnumTraits;
template <> struct EnumTraits<VkPhysicalDeviceType> {