Merge "Only process passback transactions during onFrameAvailable"
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 312db67..8e0f8a3 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -135,6 +135,11 @@
static char cmdline_buf[16384] = "(unknown)";
static const char *dump_traces_path = nullptr;
static const uint64_t USER_CONSENT_TIMEOUT_MS = 30 * 1000;
+// Because telephony reports are significantly faster to collect (< 10 seconds vs. > 2 minutes),
+// it's often the case that they time out far too quickly for consent with such a hefty dialog for
+// the user to read. For telephony reports only, we increase the default timeout to 2 minutes to
+// roughly match full reports' durations.
+static const uint64_t TELEPHONY_REPORT_USER_CONSENT_TIMEOUT_MS = 2 * 60 * 1000;
// TODO: variables and functions below should be part of dumpstate object
@@ -149,6 +154,7 @@
#define RECOVERY_DATA_DIR "/data/misc/recovery"
#define UPDATE_ENGINE_LOG_DIR "/data/misc/update_engine_log"
#define LOGPERSIST_DATA_DIR "/data/misc/logd"
+#define PREREBOOT_DATA_DIR "/data/misc/prereboot"
#define PROFILE_DATA_DIR_CUR "/data/misc/profiles/cur"
#define PROFILE_DATA_DIR_REF "/data/misc/profiles/ref"
#define XFRM_STAT_PROC_FILE "/proc/net/xfrm_stat"
@@ -879,6 +885,14 @@
CommandOptions::WithTimeoutInMs(timeout_ms).Build());
}
+static void DoRadioLogcat() {
+ unsigned long timeout_ms = logcat_timeout({"radio"});
+ RunCommand(
+ "RADIO LOG",
+ {"logcat", "-b", "radio", "-v", "threadtime", "-v", "printable", "-v", "uid", "-d", "*:v"},
+ CommandOptions::WithTimeoutInMs(timeout_ms).Build(), true /* verbose_duration */);
+}
+
static void DoLogcat() {
unsigned long timeout_ms;
// DumpFile("EVENT LOG TAGS", "/etc/event-log-tags");
@@ -897,11 +911,7 @@
"STATS LOG",
{"logcat", "-b", "stats", "-v", "threadtime", "-v", "printable", "-v", "uid", "-d", "*:v"},
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(), true /* verbose_duration */);
+ DoRadioLogcat();
RunCommand("LOG STATISTICS", {"logcat", "-b", "all", "-S"});
@@ -1429,11 +1439,14 @@
RunCommand("FILESYSTEMS & FREE SPACE", {"df"});
/* Binder state is expensive to look at as it uses a lot of memory. */
- DumpFile("BINDER FAILED TRANSACTION LOG", "/sys/kernel/debug/binder/failed_transaction_log");
- DumpFile("BINDER TRANSACTION LOG", "/sys/kernel/debug/binder/transaction_log");
- DumpFile("BINDER TRANSACTIONS", "/sys/kernel/debug/binder/transactions");
- DumpFile("BINDER STATS", "/sys/kernel/debug/binder/stats");
- DumpFile("BINDER STATE", "/sys/kernel/debug/binder/state");
+ std::string binder_logs_dir = access("/dev/binderfs/binder_logs", R_OK) ?
+ "/sys/kernel/debug/binder" : "/dev/binderfs/binder_logs";
+
+ DumpFile("BINDER FAILED TRANSACTION LOG", binder_logs_dir + "/failed_transaction_log");
+ DumpFile("BINDER TRANSACTION LOG", binder_logs_dir + "/transaction_log");
+ DumpFile("BINDER TRANSACTIONS", binder_logs_dir + "/transactions");
+ DumpFile("BINDER STATS", binder_logs_dir + "/stats");
+ DumpFile("BINDER STATE", binder_logs_dir + "/state");
/* Add window and surface trace files. */
if (!PropertiesHelper::IsUserBuild()) {
@@ -1573,6 +1586,7 @@
ds.AddDir(PROFILE_DATA_DIR_CUR, true);
ds.AddDir(PROFILE_DATA_DIR_REF, true);
}
+ ds.AddDir(PREREBOOT_DATA_DIR, false);
add_mountinfo();
DumpIpTablesAsRoot();
DumpDynamicPartitionInfo();
@@ -1611,8 +1625,10 @@
return status;
}
-// This method collects common dumpsys for telephony and wifi
-static void DumpstateRadioCommon() {
+// This method collects common dumpsys for telephony and wifi. Typically, wifi
+// reports are fine to include all information, but telephony reports on user
+// builds need to strip some content (see DumpstateTelephonyOnly).
+static void DumpstateRadioCommon(bool include_sensitive_info = true) {
DumpIpTablesAsRoot();
ds.AddDir(LOGPERSIST_DATA_DIR, false);
@@ -1621,27 +1637,51 @@
return;
}
- do_dmesg();
- DoLogcat();
+ // We need to be picky about some stuff for telephony reports on user builds.
+ if (!include_sensitive_info) {
+ // Only dump the radio log buffer (other buffers and dumps contain too much unrelated info).
+ DoRadioLogcat();
+ } else {
+ // Contains various system properties and process startup info.
+ do_dmesg();
+ // Logs other than the radio buffer may contain package/component names and potential PII.
+ DoLogcat();
+ // Too broad for connectivity problems.
+ DoKmsg();
+ // Contains unrelated hardware info (camera, NFC, biometrics, ...).
+ DumpHals();
+ }
+
DumpPacketStats();
- DoKmsg();
DumpIpAddrAndRules();
dump_route_tables();
- DumpHals();
-
RunDumpsys("NETWORK DIAGNOSTICS", {"connectivity", "--diag"},
CommandOptions::WithTimeout(10).Build());
}
-// This method collects dumpsys for telephony debugging only
+// We use "telephony" here for legacy reasons, though this now really means "connectivity" (cellular
+// + wifi + networking). This method collects dumpsys for connectivity debugging only. General rules
+// for what can be included on user builds: all reported information MUST directly relate to
+// connectivity debugging or customer support and MUST NOT contain unrelated personally identifiable
+// information. This information MUST NOT identify user-installed packages (UIDs are OK, package
+// names are not), and MUST NOT contain logs of user application traffic.
+// TODO(b/148168577) rename this and other related fields/methods to "connectivity" instead.
static void DumpstateTelephonyOnly() {
DurationReporter duration_reporter("DUMPSTATE");
const CommandOptions DUMPSYS_COMPONENTS_OPTIONS = CommandOptions::WithTimeout(60).Build();
- DumpstateRadioCommon();
+ const bool include_sensitive_info = !PropertiesHelper::IsUserBuild();
- RunCommand("SYSTEM PROPERTIES", {"getprop"});
+ DumpstateRadioCommon(include_sensitive_info);
+
+ if (include_sensitive_info) {
+ // Contains too much unrelated PII, and given the unstructured nature of sysprops, we can't
+ // really cherrypick all of the connectivity-related ones. Apps generally have no business
+ // reading these anyway, and there should be APIs to supply the info in a more app-friendly
+ // way.
+ RunCommand("SYSTEM PROPERTIES", {"getprop"});
+ }
printf("========================================================\n");
printf("== Android Framework Services\n");
@@ -1649,15 +1689,28 @@
RunDumpsys("DUMPSYS", {"connectivity"}, CommandOptions::WithTimeout(90).Build(),
SEC_TO_MSEC(10));
- RunDumpsys("DUMPSYS", {"connmetrics"}, CommandOptions::WithTimeout(90).Build(),
- SEC_TO_MSEC(10));
- RunDumpsys("DUMPSYS", {"netd"}, CommandOptions::WithTimeout(90).Build(), SEC_TO_MSEC(10));
+ // TODO(b/146521742) build out an argument to include bound services here for user builds
RunDumpsys("DUMPSYS", {"carrier_config"}, CommandOptions::WithTimeout(90).Build(),
SEC_TO_MSEC(10));
RunDumpsys("DUMPSYS", {"wifi"}, CommandOptions::WithTimeout(90).Build(),
SEC_TO_MSEC(10));
- RunDumpsys("BATTERYSTATS", {"batterystats"}, CommandOptions::WithTimeout(90).Build(),
+ RunDumpsys("DUMPSYS", {"netpolicy"}, CommandOptions::WithTimeout(90).Build(), SEC_TO_MSEC(10));
+ RunDumpsys("DUMPSYS", {"network_management"}, CommandOptions::WithTimeout(90).Build(),
SEC_TO_MSEC(10));
+ if (include_sensitive_info) {
+ // Contains raw IP addresses, omit from reports on user builds.
+ RunDumpsys("DUMPSYS", {"netd"}, CommandOptions::WithTimeout(90).Build(), SEC_TO_MSEC(10));
+ // Contains raw destination IP/MAC addresses, omit from reports on user builds.
+ RunDumpsys("DUMPSYS", {"connmetrics"}, CommandOptions::WithTimeout(90).Build(),
+ SEC_TO_MSEC(10));
+ // Contains package/component names, omit from reports on user builds.
+ RunDumpsys("BATTERYSTATS", {"batterystats"}, CommandOptions::WithTimeout(90).Build(),
+ SEC_TO_MSEC(10));
+ // Contains package names, but should be relatively simple to remove them (also contains
+ // UIDs already), omit from reports on user builds.
+ RunDumpsys("BATTERYSTATS", {"deviceidle"}, CommandOptions::WithTimeout(90).Build(),
+ SEC_TO_MSEC(10));
+ }
printf("========================================================\n");
printf("== Running Application Services\n");
@@ -1665,18 +1718,24 @@
RunDumpsys("TELEPHONY SERVICES", {"activity", "service", "TelephonyDebugService"});
- printf("========================================================\n");
- printf("== Running Application Services (non-platform)\n");
- printf("========================================================\n");
+ if (include_sensitive_info) {
+ printf("========================================================\n");
+ printf("== Running Application Services (non-platform)\n");
+ printf("========================================================\n");
- RunDumpsys("APP SERVICES NON-PLATFORM", {"activity", "service", "all-non-platform"},
- DUMPSYS_COMPONENTS_OPTIONS);
+ // Contains package/component names and potential PII, omit from reports on user builds.
+ // To get dumps of the active CarrierService(s) on user builds, we supply an argument to the
+ // carrier_config dumpsys instead.
+ RunDumpsys("APP SERVICES NON-PLATFORM", {"activity", "service", "all-non-platform"},
+ DUMPSYS_COMPONENTS_OPTIONS);
- printf("========================================================\n");
- printf("== Checkins\n");
- printf("========================================================\n");
+ printf("========================================================\n");
+ printf("== Checkins\n");
+ printf("========================================================\n");
- RunDumpsys("CHECKIN BATTERYSTATS", {"batterystats", "-c"});
+ // Contains package/component names, omit from reports on user builds.
+ RunDumpsys("CHECKIN BATTERYSTATS", {"batterystats", "-c"});
+ }
printf("========================================================\n");
printf("== dumpstate: done (id %d)\n", ds.id_);
@@ -2157,6 +2216,7 @@
break;
case Dumpstate::BugreportMode::BUGREPORT_TELEPHONY:
options->telephony_only = true;
+ options->do_progress_updates = true;
options->do_fb = false;
break;
case Dumpstate::BugreportMode::BUGREPORT_WIFI:
@@ -2641,8 +2701,13 @@
if (consent_result == UserConsentResult::UNAVAILABLE) {
// User has not responded yet.
uint64_t elapsed_ms = consent_callback_->getElapsedTimeMs();
- if (elapsed_ms < USER_CONSENT_TIMEOUT_MS) {
- uint delay_seconds = (USER_CONSENT_TIMEOUT_MS - elapsed_ms) / 1000;
+ // Telephony is a fast report type, particularly on user builds where information may be
+ // more aggressively limited. To give the user time to read the consent dialog, increase the
+ // timeout.
+ uint64_t timeout_ms = options_->telephony_only ? TELEPHONY_REPORT_USER_CONSENT_TIMEOUT_MS
+ : USER_CONSENT_TIMEOUT_MS;
+ if (elapsed_ms < timeout_ms) {
+ uint delay_seconds = (timeout_ms - elapsed_ms) / 1000;
MYLOGD("Did not receive user consent yet; going to wait for %d seconds", delay_seconds);
sleep(delay_seconds);
}
diff --git a/cmds/dumpstate/tests/dumpstate_test.cpp b/cmds/dumpstate/tests/dumpstate_test.cpp
index 1ae073c..718f459 100644
--- a/cmds/dumpstate/tests/dumpstate_test.cpp
+++ b/cmds/dumpstate/tests/dumpstate_test.cpp
@@ -295,12 +295,12 @@
EXPECT_FALSE(options_.do_fb);
EXPECT_TRUE(options_.do_zip_file);
EXPECT_TRUE(options_.telephony_only);
+ EXPECT_TRUE(options_.do_progress_updates);
// Other options retain default values
EXPECT_TRUE(options_.do_vibrate);
EXPECT_FALSE(options_.use_control_socket);
EXPECT_FALSE(options_.show_header_only);
- EXPECT_FALSE(options_.do_progress_updates);
EXPECT_FALSE(options_.is_remote_mode);
EXPECT_FALSE(options_.use_socket);
}
diff --git a/cmds/dumpsys/dumpsys.cpp b/cmds/dumpsys/dumpsys.cpp
index 5597bcd..a427c8d 100644
--- a/cmds/dumpsys/dumpsys.cpp
+++ b/cmds/dumpsys/dumpsys.cpp
@@ -29,6 +29,7 @@
#include <utils/Log.h>
#include <utils/Vector.h>
+#include <iostream>
#include <fcntl.h>
#include <getopt.h>
#include <stdio.h>
@@ -231,14 +232,14 @@
const size_t N = services.size();
if (N > 1) {
// first print a list of the current services
- aout << "Currently running services:" << endl;
+ std::cout << "Currently running services:" << std::endl;
for (size_t i=0; i<N; i++) {
sp<IBinder> service = sm_->checkService(services[i]);
if (service != nullptr) {
bool skipped = IsSkipped(skippedServices, services[i]);
- aout << " " << services[i] << (skipped ? " (skipped)" : "") << endl;
+ std::cout << " " << services[i] << (skipped ? " (skipped)" : "") << std::endl;
}
}
}
@@ -263,10 +264,10 @@
asProto, elapsedDuration, bytesWritten);
if (status == TIMED_OUT) {
- aout << endl
+ std::cout << std::endl
<< "*** SERVICE '" << serviceName << "' DUMP TIMEOUT (" << timeoutArgMs
- << "ms) EXPIRED ***" << endl
- << endl;
+ << "ms) EXPIRED ***" << std::endl
+ << std::endl;
}
if (addSeparator) {
@@ -332,14 +333,14 @@
const Vector<String16>& args) {
sp<IBinder> service = sm_->checkService(serviceName);
if (service == nullptr) {
- aerr << "Can't find service: " << serviceName << endl;
+ std::cerr << "Can't find service: " << serviceName << std::endl;
return NAME_NOT_FOUND;
}
int sfd[2];
if (pipe(sfd) != 0) {
- aerr << "Failed to create pipe to dump service info for " << serviceName << ": "
- << strerror(errno) << endl;
+ std::cerr << "Failed to create pipe to dump service info for " << serviceName << ": "
+ << strerror(errno) << std::endl;
return -errno;
}
@@ -359,13 +360,13 @@
err = dumpPidToFd(service, remote_end);
break;
default:
- aerr << "Unknown dump type" << static_cast<int>(type) << endl;
+ std::cerr << "Unknown dump type" << static_cast<int>(type) << std::endl;
return;
}
if (err != OK) {
- aerr << "Error dumping service info status_t: " << statusToString(err) << " "
- << serviceName << endl;
+ std::cerr << "Error dumping service info status_t: " << statusToString(err) << " "
+ << serviceName << std::endl;
}
});
return OK;
@@ -422,8 +423,8 @@
int rc = TEMP_FAILURE_RETRY(poll(&pfd, 1, time_left_ms()));
if (rc < 0) {
- aerr << "Error in poll while dumping service " << serviceName << " : "
- << strerror(errno) << endl;
+ std::cerr << "Error in poll while dumping service " << serviceName << " : "
+ << strerror(errno) << std::endl;
status = -errno;
break;
} else if (rc == 0) {
@@ -434,8 +435,8 @@
char buf[4096];
rc = TEMP_FAILURE_RETRY(read(redirectFd_.get(), buf, sizeof(buf)));
if (rc < 0) {
- aerr << "Failed to read while dumping service " << serviceName << ": "
- << strerror(errno) << endl;
+ std::cerr << "Failed to read while dumping service " << serviceName << ": "
+ << strerror(errno) << std::endl;
status = -errno;
break;
} else if (rc == 0) {
@@ -444,8 +445,8 @@
}
if (!WriteFully(fd, buf, rc)) {
- aerr << "Failed to write while dumping service " << serviceName << ": "
- << strerror(errno) << endl;
+ std::cerr << "Failed to write while dumping service " << serviceName << ": "
+ << strerror(errno) << std::endl;
status = -errno;
break;
}
diff --git a/cmds/dumpsys/main.cpp b/cmds/dumpsys/main.cpp
index 8ba0eba..fa4cc97 100644
--- a/cmds/dumpsys/main.cpp
+++ b/cmds/dumpsys/main.cpp
@@ -21,10 +21,9 @@
#include "dumpsys.h"
#include <binder/IServiceManager.h>
-#include <binder/TextOutput.h>
+#include <iostream>
#include <signal.h>
-#include <stdio.h>
using namespace android;
@@ -34,7 +33,7 @@
fflush(stdout);
if (sm == nullptr) {
ALOGE("Unable to get default service manager!");
- aerr << "dumpsys: Unable to get default service manager!" << endl;
+ std::cerr << "dumpsys: Unable to get default service manager!" << std::endl;
return 20;
}
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index 08d4657..4288735 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -2684,7 +2684,7 @@
}
// Mount volume's CE and DE storage to mirror
-binder::Status InstalldNativeService::onPrivateVolumeMounted(
+binder::Status InstalldNativeService::tryMountDataMirror(
const std::unique_ptr<std::string>& uuid) {
ENFORCE_UID(AID_SYSTEM);
CHECK_ARGUMENT_UUID(uuid);
@@ -2696,24 +2696,50 @@
}
const char* uuid_ = uuid->c_str();
- // Mount CE mirror
+
std::string mirrorVolCePath(StringPrintf("%s/%s", kDataMirrorCePath, uuid_));
std::lock_guard<std::recursive_mutex> lock(mLock);
- if (fs_prepare_dir(mirrorVolCePath.c_str(), 0700, AID_ROOT, AID_ROOT) != 0) {
+ if (fs_prepare_dir(mirrorVolCePath.c_str(), 0711, AID_SYSTEM, AID_SYSTEM) != 0) {
return error("Failed to create CE mirror");
}
- auto cePath = StringPrintf("%s/user_ce", create_data_path(uuid_).c_str());
+
+ std::string mirrorVolDePath(StringPrintf("%s/%s", kDataMirrorDePath, uuid_));
+ if (fs_prepare_dir(mirrorVolDePath.c_str(), 0711, AID_SYSTEM, AID_SYSTEM) != 0) {
+ return error("Failed to create DE mirror");
+ }
+
+ auto cePath = StringPrintf("%s/user", create_data_path(uuid_).c_str());
+ auto dePath = StringPrintf("%s/user_de", create_data_path(uuid_).c_str());
+
+ if (access(cePath.c_str(), F_OK) != 0) {
+ return error("Cannot access CE path: " + cePath);
+ }
+ if (access(dePath.c_str(), F_OK) != 0) {
+ return error("Cannot access DE path: " + dePath);
+ }
+
+ struct stat ceStat, mirrorCeStat;
+ if (stat(cePath.c_str(), &ceStat) != 0) {
+ return error("Failed to stat " + cePath);
+ }
+ if (stat(mirrorVolCePath.c_str(), &mirrorCeStat) != 0) {
+ return error("Failed to stat " + mirrorVolCePath);
+ }
+
+ if (mirrorCeStat.st_ino == ceStat.st_ino) {
+ // As it's being called by prepareUserStorage, it can be called multiple times.
+ // Hence, we if we mount it already, we should skip it.
+ LOG(WARNING) << "CE dir is mounted already: " + cePath;
+ return ok();
+ }
+
+ // Mount CE mirror
if (TEMP_FAILURE_RETRY(mount(cePath.c_str(), mirrorVolCePath.c_str(), NULL,
MS_NOSUID | MS_NODEV | MS_NOATIME | MS_BIND | MS_NOEXEC, nullptr)) == -1) {
return error("Failed to mount " + mirrorVolCePath);
}
// Mount DE mirror
- std::string mirrorVolDePath(StringPrintf("%s/%s", kDataMirrorDePath, uuid_));
- if (fs_prepare_dir(mirrorVolDePath.c_str(), 0700, AID_ROOT, AID_ROOT) != 0) {
- return error("Failed to create DE mirror");
- }
- auto dePath = StringPrintf("%s/user_de", create_data_path(uuid_).c_str());
if (TEMP_FAILURE_RETRY(mount(dePath.c_str(), mirrorVolDePath.c_str(), NULL,
MS_NOSUID | MS_NODEV | MS_NOATIME | MS_BIND | MS_NOEXEC, nullptr)) == -1) {
return error("Failed to mount " + mirrorVolDePath);
diff --git a/cmds/installd/InstalldNativeService.h b/cmds/installd/InstalldNativeService.h
index eb35fd3..27c59b0 100644
--- a/cmds/installd/InstalldNativeService.h
+++ b/cmds/installd/InstalldNativeService.h
@@ -155,7 +155,7 @@
binder::Status invalidateMounts();
binder::Status isQuotaSupported(const std::unique_ptr<std::string>& volumeUuid,
bool* _aidl_return);
- binder::Status onPrivateVolumeMounted(const std::unique_ptr<std::string>& volumeUuid);
+ binder::Status tryMountDataMirror(const std::unique_ptr<std::string>& volumeUuid);
binder::Status onPrivateVolumeRemoved(const std::unique_ptr<std::string>& volumeUuid);
binder::Status prepareAppProfile(const std::string& packageName,
diff --git a/cmds/installd/binder/android/os/IInstalld.aidl b/cmds/installd/binder/android/os/IInstalld.aidl
index 80d9703..f2e86ba 100644
--- a/cmds/installd/binder/android/os/IInstalld.aidl
+++ b/cmds/installd/binder/android/os/IInstalld.aidl
@@ -116,7 +116,7 @@
int appId, @utf8InCpp String seInfo, int user, int snapshotId, int storageflags);
void destroyAppDataSnapshot(@nullable @utf8InCpp String uuid, @utf8InCpp String packageName,
int userId, long ceSnapshotInode, int snapshotId, int storageFlags);
- void onPrivateVolumeMounted(@nullable @utf8InCpp String volumeUuid);
+ void tryMountDataMirror(@nullable @utf8InCpp String volumeUuid);
void onPrivateVolumeRemoved(@nullable @utf8InCpp String volumeUuid);
void migrateLegacyObbData();
diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp
index f95e445..70bbc33 100644
--- a/cmds/installd/dexopt.cpp
+++ b/cmds/installd/dexopt.cpp
@@ -299,9 +299,10 @@
// Namespace for Android Runtime flags applied during boot time.
static const char* RUNTIME_NATIVE_BOOT_NAMESPACE = "runtime_native_boot";
// Feature flag name for running the JIT in Zygote experiment, b/119800099.
-static const char* ENABLE_APEX_IMAGE = "enable_apex_image";
-// Location of the apex image.
-static const char* kApexImage = "/system/framework/apex.art";
+static const char* ENABLE_JITZYGOTE_IMAGE = "enable_apex_image";
+// Location of the JIT Zygote image.
+static const char* kJitZygoteImage =
+ "boot.art:/nonx/boot-framework.art!/system/etc/boot-image.prof";
// Phenotype property name for enabling profiling the boot class path.
static const char* PROFILE_BOOT_CLASS_PATH = "profilebootclasspath";
@@ -405,9 +406,9 @@
GetBoolProperty(kMinidebugInfoSystemProperty, kMinidebugInfoSystemPropertyDefault);
std::string boot_image;
- std::string use_apex_image =
+ std::string use_jitzygote_image =
server_configurable_flags::GetServerConfigurableFlag(RUNTIME_NATIVE_BOOT_NAMESPACE,
- ENABLE_APEX_IMAGE,
+ ENABLE_JITZYGOTE_IMAGE,
/*default_value=*/ "");
std::string profile_boot_class_path = GetProperty("dalvik.vm.profilebootclasspath", "");
@@ -417,10 +418,10 @@
PROFILE_BOOT_CLASS_PATH,
/*default_value=*/ profile_boot_class_path);
- if (use_apex_image == "true" || profile_boot_class_path == "true") {
- boot_image = StringPrintf("-Ximage:%s", kApexImage);
+ if (use_jitzygote_image == "true" || profile_boot_class_path == "true") {
+ boot_image = StringPrintf("--boot-image=%s", kJitZygoteImage);
} else {
- boot_image = MapPropertyToArg("dalvik.vm.boot-image", "-Ximage:%s");
+ boot_image = MapPropertyToArg("dalvik.vm.boot-image", "--boot-image=%s");
}
// clang FORTIFY doesn't let us use strlen in constant array bounds, so we
@@ -513,7 +514,8 @@
AddArg(instruction_set_variant_arg);
AddArg(instruction_set_features_arg);
- AddRuntimeArg(boot_image);
+ AddArg(boot_image);
+
AddRuntimeArg(bootclasspath);
AddRuntimeArg(dex2oat_Xms_arg);
AddRuntimeArg(dex2oat_Xmx_arg);
diff --git a/include/android/bitmap.h b/include/android/bitmap.h
index 412fc6b..727a4af 100644
--- a/include/android/bitmap.h
+++ b/include/android/bitmap.h
@@ -81,8 +81,8 @@
enum {
/** If this bit is set in AndroidBitmapInfo.flags, the Bitmap uses the
- * HARDWARE Config, and its AHardwareBuffer can be retrieved via
- * AndroidBitmap_getHardwareBuffer.
+ * HARDWARE Config, and its {@link AHardwareBuffer} can be retrieved via
+ * {@link AndroidBitmap_getHardwareBuffer}.
*/
ANDROID_BITMAP_FLAGS_IS_HARDWARE = 1 << 31,
};
@@ -120,10 +120,10 @@
#if __ANDROID_API__ >= 30
/**
- * Given a java bitmap object, return its ADataSpace.
+ * Given a java bitmap object, return its {@link ADataSpace}.
*
- * Note that ADataSpace only exposes a few values. This may return
- * ADATASPACE_UNKNOWN, even for Named ColorSpaces, if they have no
+ * Note that {@link ADataSpace} only exposes a few values. This may return
+ * {@link ADATASPACE_UNKNOWN}, even for Named ColorSpaces, if they have no
* corresponding ADataSpace.
*/
int32_t AndroidBitmap_getDataSpace(JNIEnv* env, jobject jbitmap) __INTRODUCED_IN(30);
@@ -206,17 +206,17 @@
* @param dataspace {@link ADataSpace} describing the color space of the
* pixels.
* @param pixels Pointer to pixels to compress.
- * @param format (@link AndroidBitmapCompressFormat} to compress to.
+ * @param format {@link AndroidBitmapCompressFormat} to compress to.
* @param quality Hint to the compressor, 0-100. The value is interpreted
* differently depending on the
* {@link AndroidBitmapCompressFormat}.
* @param userContext User-defined data which will be passed to the supplied
* {@link AndroidBitmap_CompressWriteFunc} each time it is
* called. May be null.
- * @parm fn Function that writes the compressed data. Will be called each time
- * the compressor has compressed more data that is ready to be
- * written. May be called more than once for each call to this method.
- * May not be null.
+ * @param fn Function that writes the compressed data. Will be called each time
+ * the compressor has compressed more data that is ready to be
+ * written. May be called more than once for each call to this method.
+ * May not be null.
* @return AndroidBitmap functions result code.
*/
int AndroidBitmap_compress(const AndroidBitmapInfo* info,
@@ -235,11 +235,11 @@
*
* @param bitmap Handle to an android.graphics.Bitmap.
* @param outBuffer On success, is set to a pointer to the
- * AHardwareBuffer associated with bitmap. This acquires
+ * {@link AHardwareBuffer} associated with bitmap. This acquires
* a reference on the buffer, and the client must call
- * AHardwareBuffer_release when finished with it.
+ * {@link AHardwareBuffer_release} when finished with it.
* @return AndroidBitmap functions result code.
- * ANDROID_BITMAP_RESULT_BAD_PARAMETER if bitmap is not a
+ * {@link ANDROID_BITMAP_RESULT_BAD_PARAMETER} if bitmap is not a
* HARDWARE Bitmap.
*/
int AndroidBitmap_getHardwareBuffer(JNIEnv* env, jobject bitmap,
diff --git a/include/android/sensor.h b/include/android/sensor.h
index 12c00ad..e63ac4b 100644
--- a/include/android/sensor.h
+++ b/include/android/sensor.h
@@ -15,6 +15,9 @@
*/
/**
+ * Structures and functions to receive and process sensor events in
+ * native code.
+ *
* @addtogroup Sensor
* @{
*/
@@ -42,12 +45,6 @@
* - DO NOT CHANGE THE LAYOUT OR SIZE OF STRUCTURES
*/
-/**
- * Structures and functions to receive and process sensor events in
- * native code.
- *
- */
-
#include <android/looper.h>
#include <stdbool.h>
diff --git a/include/input/Input.h b/include/input/Input.h
index cf0814c..14a7288 100644
--- a/include/input/Input.h
+++ b/include/input/Input.h
@@ -73,6 +73,19 @@
AMOTION_EVENT_FLAG_TAINTED = 0x80000000,
};
+/**
+ * Allowed VerifiedKeyEvent flags. All other flags from KeyEvent do not get verified.
+ * These values must be kept in sync with VerifiedKeyEvent.java
+ */
+constexpr int32_t VERIFIED_KEY_EVENT_FLAGS = AKEY_EVENT_FLAG_CANCELED;
+
+/**
+ * Allowed VerifiedMotionEventFlags. All other flags from MotionEvent do not get verified.
+ * These values must be kept in sync with VerifiedMotionEvent.java
+ */
+constexpr int32_t VERIFIED_MOTION_EVENT_FLAGS =
+ AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED | AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED;
+
enum {
/* Used when a motion event is not associated with any display.
* Typically used for non-pointer events. */
@@ -718,6 +731,55 @@
bool mInTouchMode;
};
+/**
+ * Base class for verified events.
+ * Do not create a VerifiedInputEvent explicitly.
+ * Use helper functions to create them from InputEvents.
+ */
+struct __attribute__((__packed__)) VerifiedInputEvent {
+ enum class Type : int32_t {
+ KEY = AINPUT_EVENT_TYPE_KEY,
+ MOTION = AINPUT_EVENT_TYPE_MOTION,
+ };
+
+ Type type;
+ int32_t deviceId;
+ nsecs_t eventTimeNanos;
+ uint32_t source;
+ int32_t displayId;
+};
+
+/**
+ * Same as KeyEvent, but only contains the data that can be verified.
+ * If you update this class, you must also update VerifiedKeyEvent.java
+ */
+struct __attribute__((__packed__)) VerifiedKeyEvent : public VerifiedInputEvent {
+ int32_t action;
+ nsecs_t downTimeNanos;
+ int32_t flags;
+ int32_t keyCode;
+ int32_t scanCode;
+ int32_t metaState;
+ int32_t repeatCount;
+};
+
+/**
+ * Same as MotionEvent, but only contains the data that can be verified.
+ * If you update this class, you must also update VerifiedMotionEvent.java
+ */
+struct __attribute__((__packed__)) VerifiedMotionEvent : public VerifiedInputEvent {
+ float rawX;
+ float rawY;
+ int32_t actionMasked;
+ nsecs_t downTimeNanos;
+ int32_t flags;
+ int32_t metaState;
+ int32_t buttonState;
+};
+
+VerifiedKeyEvent verifiedKeyEventFromKeyEvent(const KeyEvent& event);
+VerifiedMotionEvent verifiedMotionEventFromMotionEvent(const MotionEvent& event);
+
/*
* Input event factory.
*/
diff --git a/include/ui/FatVector.h b/include/ui/FatVector.h
new file mode 120000
index 0000000..c2047c0
--- /dev/null
+++ b/include/ui/FatVector.h
@@ -0,0 +1 @@
+../../libs/ui/include/ui/FatVector.h
\ No newline at end of file
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
index 5f9d400..bc541f4 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -170,7 +170,6 @@
name: "libbinder_aidl_test_stub",
local_include_dir: "aidl",
srcs: [":libbinder_aidl"],
- visibility: [":__subpackages__"],
vendor_available: true,
backend: {
java: {
diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp
index 4dcd07a..9e89c57 100644
--- a/libs/binder/IPCThreadState.cpp
+++ b/libs/binder/IPCThreadState.cpp
@@ -1230,6 +1230,11 @@
if (error < NO_ERROR) reply.setError(error);
sendReply(reply, 0);
} else {
+ if (error != OK || reply.dataSize() != 0) {
+ alog << "oneway function results will be dropped but finished with status "
+ << statusToString(error)
+ << " and parcel size " << reply.dataSize() << endl;
+ }
LOG_ONEWAY("NOT sending reply to %d!", mCallingPid);
}
diff --git a/libs/binder/fuzzer/Android.bp b/libs/binder/fuzzer/Android.bp
index 521d36f..d2b4d52 100644
--- a/libs/binder/fuzzer/Android.bp
+++ b/libs/binder/fuzzer/Android.bp
@@ -16,7 +16,6 @@
],
static_libs: [
"libbase",
- "libbinderthreadstate",
"libcgrouprc",
"libcgrouprc_format",
"libcutils",
diff --git a/libs/binder/ndk/ibinder.cpp b/libs/binder/ndk/ibinder.cpp
index e752c45..75dcdc8 100644
--- a/libs/binder/ndk/ibinder.cpp
+++ b/libs/binder/ndk/ibinder.cpp
@@ -24,10 +24,13 @@
#include <android-base/logging.h>
#include <binder/IPCThreadState.h>
+#include <binder/IResultReceiver.h>
+#include <private/android_filesystem_config.h>
using DeathRecipient = ::android::IBinder::DeathRecipient;
using ::android::IBinder;
+using ::android::IResultReceiver;
using ::android::Parcel;
using ::android::sp;
using ::android::status_t;
@@ -158,6 +161,45 @@
binder_status_t status = getClass()->onTransact(this, code, &in, &out);
return PruneStatusT(status);
+ } else if (code == SHELL_COMMAND_TRANSACTION) {
+ int in = data.readFileDescriptor();
+ int out = data.readFileDescriptor();
+ int err = data.readFileDescriptor();
+
+ int argc = data.readInt32();
+ std::vector<String8> utf8Args; // owns memory of utf8s
+ std::vector<const char*> utf8Pointers; // what can be passed over NDK API
+ for (int i = 0; i < argc && data.dataAvail() > 0; i++) {
+ utf8Args.push_back(String8(data.readString16()));
+ utf8Pointers.push_back(utf8Args[i].c_str());
+ }
+
+ data.readStrongBinder(); // skip over the IShellCallback
+ sp<IResultReceiver> resultReceiver = IResultReceiver::asInterface(data.readStrongBinder());
+
+ // Shell commands should only be callable by ADB.
+ uid_t uid = AIBinder_getCallingUid();
+ if (uid != AID_ROOT && uid != AID_SHELL) {
+ if (resultReceiver != nullptr) {
+ resultReceiver->send(-1);
+ }
+ return STATUS_PERMISSION_DENIED;
+ }
+
+ // Check that the file descriptors are valid.
+ if (in == STATUS_BAD_TYPE || out == STATUS_BAD_TYPE || err == STATUS_BAD_TYPE) {
+ if (resultReceiver != nullptr) {
+ resultReceiver->send(-1);
+ }
+ return STATUS_BAD_VALUE;
+ }
+
+ binder_status_t status = getClass()->handleShellCommand(
+ this, in, out, err, utf8Pointers.data(), utf8Pointers.size());
+ if (resultReceiver != nullptr) {
+ resultReceiver->send(status);
+ }
+ return status;
} else {
return BBinder::onTransact(code, data, reply, flags);
}
@@ -266,6 +308,13 @@
clazz->onDump = onDump;
}
+void AIBinder_Class_setHandleShellCommand(AIBinder_Class* clazz,
+ AIBinder_handleShellCommand handleShellCommand) {
+ CHECK(clazz != nullptr) << "setHandleShellCommand requires non-null clazz";
+
+ clazz->handleShellCommand = handleShellCommand;
+}
+
void AIBinder_DeathRecipient::TransferDeathRecipient::binderDied(const wp<IBinder>& who) {
CHECK(who == mWho);
diff --git a/libs/binder/ndk/ibinder_internal.h b/libs/binder/ndk/ibinder_internal.h
index 5cb68c2..5779427 100644
--- a/libs/binder/ndk/ibinder_internal.h
+++ b/libs/binder/ndk/ibinder_internal.h
@@ -17,6 +17,7 @@
#pragma once
#include <android/binder_ibinder.h>
+#include <android/binder_shell.h>
#include "ibinder_internal.h"
#include <atomic>
@@ -115,6 +116,7 @@
// optional methods for a class
AIBinder_onDump onDump;
+ AIBinder_handleShellCommand handleShellCommand;
private:
// This must be a String16 since BBinder virtual getInterfaceDescriptor returns a reference to
diff --git a/libs/binder/ndk/include_ndk/android/binder_interface_utils.h b/libs/binder/ndk/include_ndk/android/binder_interface_utils.h
index 83a1048..7331ba2 100644
--- a/libs/binder/ndk/include_ndk/android/binder_interface_utils.h
+++ b/libs/binder/ndk/include_ndk/android/binder_interface_utils.h
@@ -30,6 +30,11 @@
#include <android/binder_auto_utils.h>
#include <android/binder_ibinder.h>
+#if __has_include(<android/binder_shell.h>)
+#include <android/binder_shell.h>
+#define HAS_BINDER_SHELL_COMMAND
+#endif //_has_include
+
#include <assert.h>
#include <memory>
@@ -108,7 +113,15 @@
/**
* Dumps information about the interface. By default, dumps nothing.
*/
- virtual inline binder_status_t dump(int /*fd*/, const char** /*args*/, uint32_t /*numArgs*/);
+ virtual inline binder_status_t dump(int fd, const char** args, uint32_t numArgs);
+
+#ifdef HAS_BINDER_SHELL_COMMAND
+ /**
+ * Process shell commands. By default, does nothing.
+ */
+ virtual inline binder_status_t handleShellCommand(int in, int out, int err, const char** argv,
+ uint32_t argc);
+#endif
/**
* Interprets this binder as this underlying interface if this has stored an ICInterface in the
@@ -136,6 +149,11 @@
static inline void onDestroy(void* userData);
static inline binder_status_t onDump(AIBinder* binder, int fd, const char** args,
uint32_t numArgs);
+
+#ifdef HAS_BINDER_SHELL_COMMAND
+ static inline binder_status_t handleShellCommand(AIBinder* binder, int in, int out, int err,
+ const char** argv, uint32_t argc);
+#endif
};
};
@@ -191,6 +209,13 @@
return STATUS_OK;
}
+#ifdef HAS_BINDER_SHELL_COMMAND
+binder_status_t ICInterface::handleShellCommand(int /*in*/, int /*out*/, int /*err*/,
+ const char** /*argv*/, uint32_t /*argc*/) {
+ return STATUS_OK;
+}
+#endif
+
std::shared_ptr<ICInterface> ICInterface::asInterface(AIBinder* binder) {
return ICInterfaceData::getInterface(binder);
}
@@ -203,9 +228,12 @@
return nullptr;
}
- // We can't know if this method is overriden by a subclass interface, so we must register
- // ourselves. The default (nothing to dump) is harmless.
+ // We can't know if these methods are overridden by a subclass interface, so we must register
+ // ourselves. The defaults are harmless.
AIBinder_Class_setOnDump(clazz, ICInterfaceData::onDump);
+#ifdef HAS_BINDER_SHELL_COMMAND
+ AIBinder_Class_setHandleShellCommand(clazz, ICInterfaceData::handleShellCommand);
+#endif
return clazz;
}
@@ -234,6 +262,15 @@
return interface->dump(fd, args, numArgs);
}
+#ifdef HAS_BINDER_SHELL_COMMAND
+binder_status_t ICInterface::ICInterfaceData::handleShellCommand(AIBinder* binder, int in, int out,
+ int err, const char** argv,
+ uint32_t argc) {
+ std::shared_ptr<ICInterface> interface = getInterface(binder);
+ return interface->handleShellCommand(in, out, err, argv, argc);
+}
+#endif
+
template <typename INTERFACE>
SpAIBinder BnCInterface<INTERFACE>::asBinder() {
std::lock_guard<std::mutex> l(mMutex);
diff --git a/libs/binder/ndk/include_platform/android/binder_shell.h b/libs/binder/ndk/include_platform/android/binder_shell.h
new file mode 100644
index 0000000..17b38b0
--- /dev/null
+++ b/libs/binder/ndk/include_platform/android/binder_shell.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2020 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
+
+/**
+ * Function to execute a shell command.
+ *
+ * Available since API level 30.
+ *
+ * \param binder the binder executing the command
+ * \param in input file descriptor, should be flushed, ownership is not passed
+ * \param out output file descriptor, should be flushed, ownership is not passed
+ * \param err error file descriptor, should be flushed, ownership is not passed
+ * \param argv array of null-terminated strings for command (may be null if argc
+ * is 0)
+ * \param argc length of argv array
+ *
+ * \return binder_status_t result of transaction
+ */
+typedef binder_status_t (*AIBinder_handleShellCommand)(AIBinder* binder, int in, int out, int err,
+ const char** argv, uint32_t argc);
+
+/**
+ * This sets the implementation of handleShellCommand for a class.
+ *
+ * If this isn't set, nothing will be executed when handleShellCommand is called.
+ *
+ * Available since API level 30.
+ *
+ * \param handleShellCommand function to call when a shell transaction is
+ * received
+ */
+void AIBinder_Class_setHandleShellCommand(AIBinder_Class* clazz,
+ AIBinder_handleShellCommand handleShellCommand)
+ __INTRODUCED_IN(30);
+
+__END_DECLS
diff --git a/libs/binder/ndk/libbinder_ndk.map.txt b/libs/binder/ndk/libbinder_ndk.map.txt
index f3158d7..7e72f22 100644
--- a/libs/binder/ndk/libbinder_ndk.map.txt
+++ b/libs/binder/ndk/libbinder_ndk.map.txt
@@ -110,6 +110,7 @@
AIBinder_markSystemStability; # apex
AIBinder_markVendorStability; # llndk
AIBinder_markVintfStability; # apex llndk
+ AIBinder_Class_setHandleShellCommand; # apex llndk
local:
*;
};
diff --git a/libs/binder/ndk/test/Android.bp b/libs/binder/ndk/test/Android.bp
index 513d8c2..cb4b20f 100644
--- a/libs/binder/ndk/test/Android.bp
+++ b/libs/binder/ndk/test/Android.bp
@@ -60,6 +60,7 @@
defaults: ["test_libbinder_ndk_test_defaults"],
srcs: ["libbinder_ndk_unit_test.cpp"],
static_libs: [
+ "IBinderNdkUnitTest-cpp",
"IBinderNdkUnitTest-ndk_platform",
],
test_suites: ["general-tests"],
diff --git a/libs/binder/ndk/test/libbinder_ndk_unit_test.cpp b/libs/binder/ndk/test/libbinder_ndk_unit_test.cpp
index 51dd169..fd30d87 100644
--- a/libs/binder/ndk/test/libbinder_ndk_unit_test.cpp
+++ b/libs/binder/ndk/test/libbinder_ndk_unit_test.cpp
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#include <IBinderNdkUnitTest.h>
#include <aidl/BnBinderNdkUnitTest.h>
#include <aidl/BnEmpty.h>
#include <android-base/logging.h>
@@ -26,13 +27,16 @@
// warning: this is assuming that libbinder_ndk is using the same copy
// of libbinder that we are.
#include <binder/IPCThreadState.h>
+#include <binder/IResultReceiver.h>
+#include <binder/IServiceManager.h>
+#include <binder/IShellCallback.h>
#include <sys/prctl.h>
#include <chrono>
#include <condition_variable>
#include <mutex>
-using ::android::sp;
+using namespace android;
constexpr char kExistingNonNdkService[] = "SurfaceFlinger";
constexpr char kBinderNdkUnitTestService[] = "BinderNdkUnitTest";
@@ -48,6 +52,14 @@
android::IPCThreadState::self()->flushCommands();
return ndk::ScopedAStatus::ok();
}
+ binder_status_t handleShellCommand(int /*in*/, int out, int /*err*/, const char** args,
+ uint32_t numArgs) override {
+ for (uint32_t i = 0; i < numArgs; i++) {
+ dprintf(out, "%s", args[i]);
+ }
+ fsync(out);
+ return STATUS_OK;
+ }
};
int generatedService() {
@@ -296,6 +308,92 @@
EXPECT_TRUE(destroyed);
}
+class MyResultReceiver : public BnResultReceiver {
+ public:
+ Mutex mMutex;
+ Condition mCondition;
+ bool mHaveResult = false;
+ int32_t mResult = 0;
+
+ virtual void send(int32_t resultCode) {
+ AutoMutex _l(mMutex);
+ mResult = resultCode;
+ mHaveResult = true;
+ mCondition.signal();
+ }
+
+ int32_t waitForResult() {
+ AutoMutex _l(mMutex);
+ while (!mHaveResult) {
+ mCondition.wait(mMutex);
+ }
+ return mResult;
+ }
+};
+
+class MyShellCallback : public BnShellCallback {
+ public:
+ virtual int openFile(const String16& /*path*/, const String16& /*seLinuxContext*/,
+ const String16& /*mode*/) {
+ // Empty implementation.
+ return 0;
+ }
+};
+
+bool ReadFdToString(int fd, std::string* content) {
+ char buf[64];
+ ssize_t n;
+ while ((n = TEMP_FAILURE_RETRY(read(fd, &buf[0], sizeof(buf)))) > 0) {
+ content->append(buf, n);
+ }
+ return (n == 0) ? true : false;
+}
+
+std::string shellCmdToString(sp<IBinder> unitTestService, const std::vector<const char*>& args) {
+ int inFd[2] = {-1, -1};
+ int outFd[2] = {-1, -1};
+ int errFd[2] = {-1, -1};
+
+ EXPECT_EQ(0, socketpair(AF_UNIX, SOCK_STREAM, 0, inFd));
+ EXPECT_EQ(0, socketpair(AF_UNIX, SOCK_STREAM, 0, outFd));
+ EXPECT_EQ(0, socketpair(AF_UNIX, SOCK_STREAM, 0, errFd));
+
+ sp<MyShellCallback> cb = new MyShellCallback();
+ sp<MyResultReceiver> resultReceiver = new MyResultReceiver();
+
+ Vector<String16> argsVec;
+ for (int i = 0; i < args.size(); i++) {
+ argsVec.add(String16(args[i]));
+ }
+ status_t error = IBinder::shellCommand(unitTestService, inFd[0], outFd[0], errFd[0], argsVec,
+ cb, resultReceiver);
+ EXPECT_EQ(error, android::OK);
+
+ status_t res = resultReceiver->waitForResult();
+ EXPECT_EQ(res, android::OK);
+
+ close(inFd[0]);
+ close(inFd[1]);
+ close(outFd[0]);
+ close(errFd[0]);
+ close(errFd[1]);
+
+ std::string ret;
+ EXPECT_TRUE(ReadFdToString(outFd[1], &ret));
+ close(outFd[1]);
+ return ret;
+}
+
+TEST(NdkBinder, UseHandleShellCommand) {
+ static const sp<android::IServiceManager> sm(android::defaultServiceManager());
+ sp<IBinder> testService = sm->getService(String16(kBinderNdkUnitTestService));
+
+ EXPECT_EQ("", shellCmdToString(testService, {}));
+ EXPECT_EQ("", shellCmdToString(testService, {"", ""}));
+ EXPECT_EQ("Hello world!", shellCmdToString(testService, {"Hello ", "world!"}));
+ EXPECT_EQ("CMD", shellCmdToString(testService, {"C", "M", "D"}));
+}
+
int main(int argc, char* argv[]) {
::testing::InitGoogleTest(&argc, argv);
diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp
index 5a7f9a9..3ee8187 100644
--- a/libs/binder/tests/Android.bp
+++ b/libs/binder/tests/Android.bp
@@ -40,7 +40,7 @@
},
srcs: ["binderDriverInterfaceTest.cpp"],
- test_suites: ["device-tests"],
+ test_suites: ["device-tests", "vts-core"],
}
cc_test {
@@ -69,7 +69,7 @@
"libbinder",
"libutils",
],
- test_suites: ["device-tests"],
+ test_suites: ["device-tests", "vts-core"],
require_root: true,
}
@@ -131,7 +131,7 @@
"liblog",
"libutils",
],
- test_suites: ["device-tests"],
+ test_suites: ["device-tests", "vts-core"],
require_root: true,
}
diff --git a/libs/binderthreadstate/Android.bp b/libs/binderthreadstate/Android.bp
index 4655e1d..c186110 100644
--- a/libs/binderthreadstate/Android.bp
+++ b/libs/binderthreadstate/Android.bp
@@ -63,15 +63,3 @@
],
require_root: true,
}
-
-// TODO(b/148692216): remove empty lib
-cc_library {
- name: "libbinderthreadstate",
- recovery_available: true,
- vendor_available: false,
- vndk: {
- enabled: true,
- support_system_process: true,
- },
- host_supported: true,
-}
diff --git a/libs/cputimeinstate/cputimeinstate.cpp b/libs/cputimeinstate/cputimeinstate.cpp
index 31a399b..b6b81bb 100644
--- a/libs/cputimeinstate/cputimeinstate.cpp
+++ b/libs/cputimeinstate/cputimeinstate.cpp
@@ -58,6 +58,7 @@
static std::set<uint32_t> gAllFreqs;
static unique_fd gTisMapFd;
static unique_fd gConcurrentMapFd;
+static unique_fd gUidLastUpdateMapFd;
static std::optional<std::vector<uint32_t>> readNumbersFromFile(const std::string &path) {
std::string data;
@@ -144,6 +145,10 @@
unique_fd{bpf_obj_get(BPF_FS_PATH "map_time_in_state_uid_concurrent_times_map")};
if (gConcurrentMapFd < 0) return false;
+ gUidLastUpdateMapFd =
+ unique_fd{bpf_obj_get(BPF_FS_PATH "map_time_in_state_uid_last_update_map")};
+ if (gUidLastUpdateMapFd < 0) return false;
+
gInitialized = true;
return true;
}
@@ -263,6 +268,18 @@
return out;
}
+static std::optional<bool> uidUpdatedSince(uint32_t uid, uint64_t lastUpdate,
+ uint64_t *newLastUpdate) {
+ uint64_t uidLastUpdate;
+ if (findMapEntry(gUidLastUpdateMapFd, &uid, &uidLastUpdate)) return {};
+ // Updates that occurred during the previous read may have been missed. To mitigate
+ // this, don't ignore entries updated up to 1s before *lastUpdate
+ constexpr uint64_t NSEC_PER_SEC = 1000000000;
+ if (uidLastUpdate + NSEC_PER_SEC < lastUpdate) return false;
+ if (uidLastUpdate > *newLastUpdate) *newLastUpdate = uidLastUpdate;
+ return true;
+}
+
// Retrieve the times in ns that each uid spent running at each CPU freq.
// Return contains no value on error, otherwise it contains a map from uids to vectors of vectors
// using the format:
@@ -271,6 +288,14 @@
// where ti_j_k is the ns uid i spent running on the jth cluster at the cluster's kth lowest freq.
std::optional<std::unordered_map<uint32_t, std::vector<std::vector<uint64_t>>>>
getUidsCpuFreqTimes() {
+ return getUidsUpdatedCpuFreqTimes(nullptr);
+}
+
+// Retrieve the times in ns that each uid spent running at each CPU freq, excluding UIDs that have
+// not run since before lastUpdate.
+// Return format is the same as getUidsCpuFreqTimes()
+std::optional<std::unordered_map<uint32_t, std::vector<std::vector<uint64_t>>>>
+getUidsUpdatedCpuFreqTimes(uint64_t *lastUpdate) {
if (!gInitialized && !initGlobals()) return {};
time_key_t key, prevKey;
std::unordered_map<uint32_t, std::vector<std::vector<uint64_t>>> map;
@@ -282,8 +307,14 @@
std::vector<std::vector<uint64_t>> mapFormat;
for (const auto &freqList : gPolicyFreqs) mapFormat.emplace_back(freqList.size(), 0);
+ uint64_t newLastUpdate = lastUpdate ? *lastUpdate : 0;
std::vector<tis_val_t> vals(gNCpus);
do {
+ if (lastUpdate) {
+ auto uidUpdated = uidUpdatedSince(key.uid, *lastUpdate, &newLastUpdate);
+ if (!uidUpdated.has_value()) return {};
+ if (!*uidUpdated) continue;
+ }
if (findMapEntry(gTisMapFd, &key, vals.data())) return {};
if (map.find(key.uid) == map.end()) map.emplace(key.uid, mapFormat);
@@ -299,8 +330,9 @@
}
}
prevKey = key;
- } while (!getNextMapKey(gTisMapFd, &prevKey, &key));
+ } while (prevKey = key, !getNextMapKey(gTisMapFd, &prevKey, &key));
if (errno != ENOENT) return {};
+ if (lastUpdate && newLastUpdate > *lastUpdate) *lastUpdate = newLastUpdate;
return map;
}
@@ -365,6 +397,15 @@
// where ai is the ns spent running concurrently with tasks on i other cpus and pi_j is the ns spent
// running on the ith cluster, concurrently with tasks on j other cpus in the same cluster.
std::optional<std::unordered_map<uint32_t, concurrent_time_t>> getUidsConcurrentTimes() {
+ return getUidsUpdatedConcurrentTimes(nullptr);
+}
+
+// Retrieve the times in ns that each uid spent running concurrently with each possible number of
+// other tasks on each cluster (policy times) and overall (active times), excluding UIDs that have
+// not run since before lastUpdate.
+// Return format is the same as getUidsConcurrentTimes()
+std::optional<std::unordered_map<uint32_t, concurrent_time_t>> getUidsUpdatedConcurrentTimes(
+ uint64_t *lastUpdate) {
if (!gInitialized && !initGlobals()) return {};
time_key_t key, prevKey;
std::unordered_map<uint32_t, concurrent_time_t> ret;
@@ -379,7 +420,13 @@
std::vector<concurrent_val_t> vals(gNCpus);
std::vector<uint64_t>::iterator activeBegin, activeEnd, policyBegin, policyEnd;
+ uint64_t newLastUpdate = lastUpdate ? *lastUpdate : 0;
do {
+ if (lastUpdate) {
+ auto uidUpdated = uidUpdatedSince(key.uid, *lastUpdate, &newLastUpdate);
+ if (!uidUpdated.has_value()) return {};
+ if (!*uidUpdated) continue;
+ }
if (findMapEntry(gConcurrentMapFd, &key, vals.data())) return {};
if (ret.find(key.uid) == ret.end()) ret.emplace(key.uid, retFormat);
@@ -405,8 +452,7 @@
std::plus<uint64_t>());
}
}
- prevKey = key;
- } while (!getNextMapKey(gConcurrentMapFd, &prevKey, &key));
+ } while (prevKey = key, !getNextMapKey(gConcurrentMapFd, &prevKey, &key));
if (errno != ENOENT) return {};
for (const auto &[key, value] : ret) {
if (!verifyConcurrentTimes(value)) {
@@ -414,6 +460,7 @@
if (val.has_value()) ret[key] = val.value();
}
}
+ if (lastUpdate && newLastUpdate > *lastUpdate) *lastUpdate = newLastUpdate;
return ret;
}
@@ -446,6 +493,8 @@
return false;
if (deleteMapEntry(gConcurrentMapFd, &key) && errno != ENOENT) return false;
}
+
+ if (deleteMapEntry(gUidLastUpdateMapFd, &uid) && errno != ENOENT) return false;
return true;
}
diff --git a/libs/cputimeinstate/cputimeinstate.h b/libs/cputimeinstate/cputimeinstate.h
index 49469d8..b7600f5 100644
--- a/libs/cputimeinstate/cputimeinstate.h
+++ b/libs/cputimeinstate/cputimeinstate.h
@@ -26,6 +26,8 @@
std::optional<std::vector<std::vector<uint64_t>>> getUidCpuFreqTimes(uint32_t uid);
std::optional<std::unordered_map<uint32_t, std::vector<std::vector<uint64_t>>>>
getUidsCpuFreqTimes();
+std::optional<std::unordered_map<uint32_t, std::vector<std::vector<uint64_t>>>>
+ getUidsUpdatedCpuFreqTimes(uint64_t *lastUpdate);
std::optional<std::vector<std::vector<uint32_t>>> getCpuFreqs();
struct concurrent_time_t {
@@ -35,6 +37,8 @@
std::optional<concurrent_time_t> getUidConcurrentTimes(uint32_t uid, bool retry = true);
std::optional<std::unordered_map<uint32_t, concurrent_time_t>> getUidsConcurrentTimes();
+std::optional<std::unordered_map<uint32_t, concurrent_time_t>>
+ getUidsUpdatedConcurrentTimes(uint64_t *lastUpdate);
bool clearUidTimes(unsigned int uid);
} // namespace bpf
diff --git a/libs/cputimeinstate/testtimeinstate.cpp b/libs/cputimeinstate/testtimeinstate.cpp
index 23d87fd..ea2a200 100644
--- a/libs/cputimeinstate/testtimeinstate.cpp
+++ b/libs/cputimeinstate/testtimeinstate.cpp
@@ -115,71 +115,169 @@
}
TEST(TimeInStateTest, AllUidTimeInState) {
- vector<size_t> sizes;
- auto map = getUidsCpuFreqTimes();
- ASSERT_TRUE(map.has_value());
+ uint64_t zero = 0;
+ auto maps = {getUidsCpuFreqTimes(), getUidsUpdatedCpuFreqTimes(&zero)};
+ for (const auto &map : maps) {
+ ASSERT_TRUE(map.has_value());
- ASSERT_FALSE(map->empty());
+ ASSERT_FALSE(map->empty());
- auto firstEntry = map->begin()->second;
- for (const auto &subEntry : firstEntry) sizes.emplace_back(subEntry.size());
+ vector<size_t> sizes;
+ auto firstEntry = map->begin()->second;
+ for (const auto &subEntry : firstEntry) sizes.emplace_back(subEntry.size());
- for (const auto &vec : *map) {
- ASSERT_EQ(vec.second.size(), sizes.size());
- for (size_t i = 0; i < vec.second.size(); ++i) ASSERT_EQ(vec.second[i].size(), sizes[i]);
+ for (const auto &vec : *map) {
+ ASSERT_EQ(vec.second.size(), sizes.size());
+ for (size_t i = 0; i < vec.second.size(); ++i) ASSERT_EQ(vec.second[i].size(), sizes[i]);
+ }
+ }
+}
+
+void TestCheckUpdate(const std::vector<std::vector<uint64_t>> &before,
+ const std::vector<std::vector<uint64_t>> &after) {
+ ASSERT_EQ(before.size(), after.size());
+ uint64_t sumBefore = 0, sumAfter = 0;
+ for (size_t i = 0; i < before.size(); ++i) {
+ ASSERT_EQ(before[i].size(), after[i].size());
+ for (size_t j = 0; j < before[i].size(); ++j) {
+ // Times should never decrease
+ ASSERT_LE(before[i][j], after[i][j]);
+ }
+ sumBefore += std::accumulate(before[i].begin(), before[i].end(), (uint64_t)0);
+ sumAfter += std::accumulate(after[i].begin(), after[i].end(), (uint64_t)0);
+ }
+ ASSERT_LE(sumBefore, sumAfter);
+ ASSERT_LE(sumAfter - sumBefore, NSEC_PER_SEC);
+}
+
+TEST(TimeInStateTest, AllUidUpdatedTimeInState) {
+ uint64_t lastUpdate = 0;
+ auto map1 = getUidsUpdatedCpuFreqTimes(&lastUpdate);
+ ASSERT_TRUE(map1.has_value());
+ ASSERT_FALSE(map1->empty());
+ ASSERT_NE(lastUpdate, (uint64_t)0);
+ uint64_t oldLastUpdate = lastUpdate;
+
+ // Sleep briefly to trigger a context switch, ensuring we see at least one update.
+ struct timespec ts;
+ ts.tv_sec = 0;
+ ts.tv_nsec = 1000000;
+ nanosleep (&ts, NULL);
+
+ auto map2 = getUidsUpdatedCpuFreqTimes(&lastUpdate);
+ ASSERT_TRUE(map2.has_value());
+ ASSERT_FALSE(map2->empty());
+ ASSERT_NE(lastUpdate, oldLastUpdate);
+
+ bool someUidsExcluded = false;
+ for (const auto &[uid, v] : *map1) {
+ if (map2->find(uid) == map2->end()) {
+ someUidsExcluded = true;
+ break;
+ }
+ }
+ ASSERT_TRUE(someUidsExcluded);
+
+ for (const auto &[uid, newTimes] : *map2) {
+ ASSERT_NE(map1->find(uid), map1->end());
+ ASSERT_NO_FATAL_FAILURE(TestCheckUpdate((*map1)[uid], newTimes));
}
}
TEST(TimeInStateTest, SingleAndAllUidTimeInStateConsistent) {
- auto map = getUidsCpuFreqTimes();
- ASSERT_TRUE(map.has_value());
- ASSERT_FALSE(map->empty());
+ uint64_t zero = 0;
+ auto maps = {getUidsCpuFreqTimes(), getUidsUpdatedCpuFreqTimes(&zero)};
+ for (const auto &map : maps) {
+ ASSERT_TRUE(map.has_value());
+ ASSERT_FALSE(map->empty());
- for (const auto &kv : *map) {
- uint32_t uid = kv.first;
- auto times1 = kv.second;
- auto times2 = getUidCpuFreqTimes(uid);
- ASSERT_TRUE(times2.has_value());
+ for (const auto &kv : *map) {
+ uint32_t uid = kv.first;
+ auto times1 = kv.second;
+ auto times2 = getUidCpuFreqTimes(uid);
+ ASSERT_TRUE(times2.has_value());
- ASSERT_EQ(times1.size(), times2->size());
- for (uint32_t i = 0; i < times1.size(); ++i) {
- ASSERT_EQ(times1[i].size(), (*times2)[i].size());
- for (uint32_t j = 0; j < times1[i].size(); ++j) {
- ASSERT_LE((*times2)[i][j] - times1[i][j], NSEC_PER_SEC);
+ ASSERT_EQ(times1.size(), times2->size());
+ for (uint32_t i = 0; i < times1.size(); ++i) {
+ ASSERT_EQ(times1[i].size(), (*times2)[i].size());
+ for (uint32_t j = 0; j < times1[i].size(); ++j) {
+ ASSERT_LE((*times2)[i][j] - times1[i][j], NSEC_PER_SEC);
+ }
}
}
}
}
TEST(TimeInStateTest, AllUidConcurrentTimes) {
- auto map = getUidsConcurrentTimes();
- ASSERT_TRUE(map.has_value());
- ASSERT_FALSE(map->empty());
+ uint64_t zero = 0;
+ auto maps = {getUidsConcurrentTimes(), getUidsUpdatedConcurrentTimes(&zero)};
+ for (const auto &map : maps) {
+ ASSERT_TRUE(map.has_value());
+ ASSERT_FALSE(map->empty());
- auto firstEntry = map->begin()->second;
- for (const auto &kv : *map) {
- ASSERT_EQ(kv.second.active.size(), firstEntry.active.size());
- ASSERT_EQ(kv.second.policy.size(), firstEntry.policy.size());
- for (size_t i = 0; i < kv.second.policy.size(); ++i) {
- ASSERT_EQ(kv.second.policy[i].size(), firstEntry.policy[i].size());
+ auto firstEntry = map->begin()->second;
+ for (const auto &kv : *map) {
+ ASSERT_EQ(kv.second.active.size(), firstEntry.active.size());
+ ASSERT_EQ(kv.second.policy.size(), firstEntry.policy.size());
+ for (size_t i = 0; i < kv.second.policy.size(); ++i) {
+ ASSERT_EQ(kv.second.policy[i].size(), firstEntry.policy[i].size());
+ }
}
}
}
-TEST(TimeInStateTest, SingleAndAllUidConcurrentTimesConsistent) {
- auto map = getUidsConcurrentTimes();
- ASSERT_TRUE(map.has_value());
- for (const auto &kv : *map) {
- uint32_t uid = kv.first;
- auto times1 = kv.second;
- auto times2 = getUidConcurrentTimes(uid);
- ASSERT_TRUE(times2.has_value());
- for (uint32_t i = 0; i < times1.active.size(); ++i) {
- ASSERT_LE(times2->active[i] - times1.active[i], NSEC_PER_SEC);
+TEST(TimeInStateTest, AllUidUpdatedConcurrentTimes) {
+ uint64_t lastUpdate = 0;
+ auto map1 = getUidsUpdatedConcurrentTimes(&lastUpdate);
+ ASSERT_TRUE(map1.has_value());
+ ASSERT_FALSE(map1->empty());
+ ASSERT_NE(lastUpdate, (uint64_t)0);
+
+ // Sleep briefly to trigger a context switch, ensuring we see at least one update.
+ struct timespec ts;
+ ts.tv_sec = 0;
+ ts.tv_nsec = 1000000;
+ nanosleep (&ts, NULL);
+
+ uint64_t oldLastUpdate = lastUpdate;
+ auto map2 = getUidsUpdatedConcurrentTimes(&lastUpdate);
+ ASSERT_TRUE(map2.has_value());
+ ASSERT_FALSE(map2->empty());
+ ASSERT_NE(lastUpdate, oldLastUpdate);
+
+ bool someUidsExcluded = false;
+ for (const auto &[uid, v] : *map1) {
+ if (map2->find(uid) == map2->end()) {
+ someUidsExcluded = true;
+ break;
}
- for (uint32_t i = 0; i < times1.policy.size(); ++i) {
- for (uint32_t j = 0; j < times1.policy[i].size(); ++j) {
- ASSERT_LE(times2->policy[i][j] - times1.policy[i][j], NSEC_PER_SEC);
+ }
+ ASSERT_TRUE(someUidsExcluded);
+
+ for (const auto &[uid, newTimes] : *map2) {
+ ASSERT_NE(map1->find(uid), map1->end());
+ ASSERT_NO_FATAL_FAILURE(TestCheckUpdate({(*map1)[uid].active},{newTimes.active}));
+ ASSERT_NO_FATAL_FAILURE(TestCheckUpdate((*map1)[uid].policy, newTimes.policy));
+ }
+}
+
+TEST(TimeInStateTest, SingleAndAllUidConcurrentTimesConsistent) {
+ uint64_t zero = 0;
+ auto maps = {getUidsConcurrentTimes(), getUidsUpdatedConcurrentTimes(&zero)};
+ for (const auto &map : maps) {
+ ASSERT_TRUE(map.has_value());
+ for (const auto &kv : *map) {
+ uint32_t uid = kv.first;
+ auto times1 = kv.second;
+ auto times2 = getUidConcurrentTimes(uid);
+ ASSERT_TRUE(times2.has_value());
+ for (uint32_t i = 0; i < times1.active.size(); ++i) {
+ ASSERT_LE(times2->active[i] - times1.active[i], NSEC_PER_SEC);
+ }
+ for (uint32_t i = 0; i < times1.policy.size(); ++i) {
+ for (uint32_t j = 0; j < times1.policy[i].size(); ++j) {
+ ASSERT_LE(times2->policy[i][j] - times1.policy[i][j], NSEC_PER_SEC);
+ }
}
}
}
@@ -242,45 +340,51 @@
}
TEST(TimeInStateTest, AllUidTimeInStateSanityCheck) {
- auto map = getUidsCpuFreqTimes();
- ASSERT_TRUE(map.has_value());
+ uint64_t zero = 0;
+ auto maps = {getUidsCpuFreqTimes(), getUidsUpdatedCpuFreqTimes(&zero)};
+ for (const auto &map : maps) {
+ ASSERT_TRUE(map.has_value());
- bool foundLargeValue = false;
- for (const auto &kv : *map) {
- for (const auto &timeVec : kv.second) {
- for (const auto &time : timeVec) {
- ASSERT_LE(time, NSEC_PER_YEAR);
- if (time > UINT32_MAX) foundLargeValue = true;
+ bool foundLargeValue = false;
+ for (const auto &kv : *map) {
+ for (const auto &timeVec : kv.second) {
+ for (const auto &time : timeVec) {
+ ASSERT_LE(time, NSEC_PER_YEAR);
+ if (time > UINT32_MAX) foundLargeValue = true;
+ }
}
}
+ // UINT32_MAX nanoseconds is less than 5 seconds, so if every part of our pipeline is using
+ // uint64_t as expected, we should have some times higher than that.
+ ASSERT_TRUE(foundLargeValue);
}
- // UINT32_MAX nanoseconds is less than 5 seconds, so if every part of our pipeline is using
- // uint64_t as expected, we should have some times higher than that.
- ASSERT_TRUE(foundLargeValue);
}
TEST(TimeInStateTest, AllUidConcurrentTimesSanityCheck) {
- auto concurrentMap = getUidsConcurrentTimes();
- ASSERT_TRUE(concurrentMap);
+ uint64_t zero = 0;
+ auto maps = {getUidsConcurrentTimes(), getUidsUpdatedConcurrentTimes(&zero)};
+ for (const auto &concurrentMap : maps) {
+ ASSERT_TRUE(concurrentMap);
- bool activeFoundLargeValue = false;
- bool policyFoundLargeValue = false;
- for (const auto &kv : *concurrentMap) {
- for (const auto &time : kv.second.active) {
- ASSERT_LE(time, NSEC_PER_YEAR);
- if (time > UINT32_MAX) activeFoundLargeValue = true;
- }
- for (const auto &policyTimeVec : kv.second.policy) {
- for (const auto &time : policyTimeVec) {
+ bool activeFoundLargeValue = false;
+ bool policyFoundLargeValue = false;
+ for (const auto &kv : *concurrentMap) {
+ for (const auto &time : kv.second.active) {
ASSERT_LE(time, NSEC_PER_YEAR);
- if (time > UINT32_MAX) policyFoundLargeValue = true;
+ if (time > UINT32_MAX) activeFoundLargeValue = true;
+ }
+ for (const auto &policyTimeVec : kv.second.policy) {
+ for (const auto &time : policyTimeVec) {
+ ASSERT_LE(time, NSEC_PER_YEAR);
+ if (time > UINT32_MAX) policyFoundLargeValue = true;
+ }
}
}
+ // UINT32_MAX nanoseconds is less than 5 seconds, so if every part of our pipeline is using
+ // uint64_t as expected, we should have some times higher than that.
+ ASSERT_TRUE(activeFoundLargeValue);
+ ASSERT_TRUE(policyFoundLargeValue);
}
- // UINT32_MAX nanoseconds is less than 5 seconds, so if every part of our pipeline is using
- // uint64_t as expected, we should have some times higher than that.
- ASSERT_TRUE(activeFoundLargeValue);
- ASSERT_TRUE(policyFoundLargeValue);
}
TEST(TimeInStateTest, AllUidTimesConsistent) {
diff --git a/libs/gralloc/types/Gralloc4.cpp b/libs/gralloc/types/Gralloc4.cpp
index 4e8569f..603e7e5 100644
--- a/libs/gralloc/types/Gralloc4.cpp
+++ b/libs/gralloc/types/Gralloc4.cpp
@@ -734,12 +734,7 @@
if (err) {
return err;
}
- err = encodeInteger<int64_t>(static_cast<int32_t>(input.verticalSubsampling), output);
- if (err) {
- return err;
- }
-
- return encodeRect(input.crop, output);
+ return encodeInteger<int64_t>(static_cast<int32_t>(input.verticalSubsampling), output);
}
status_t decodePlaneLayout(InputHidlVec* input, PlaneLayout* output) {
@@ -780,12 +775,7 @@
if (err) {
return err;
}
- err = decodeInteger<int64_t>(input, &output->verticalSubsampling);
- if (err) {
- return err;
- }
-
- return decodeRect(input, &output->crop);
+ return decodeInteger<int64_t>(input, &output->verticalSubsampling);
}
status_t encodePlaneLayoutsHelper(const std::vector<PlaneLayout>& planeLayouts, OutputHidlVec* outOutputHidlVec) {
@@ -831,6 +821,49 @@
output->clear();
}
+status_t encodeCropHelper(const std::vector<Rect>& crops, OutputHidlVec* outOutputHidlVec) {
+ status_t err = encodeInteger<int64_t>(static_cast<int64_t>(crops.size()), outOutputHidlVec);
+ if (err) {
+ return err;
+ }
+
+ for (const auto& crop : crops) {
+ err = encodeRect(crop, outOutputHidlVec);
+ if (err) {
+ return err;
+ }
+ }
+
+ return NO_ERROR;
+}
+
+status_t decodeCropHelper(InputHidlVec* inputHidlVec, std::vector<Rect>* outCrops) {
+ int64_t size = 0;
+ status_t err = decodeInteger<int64_t>(inputHidlVec, &size);
+ if (err) {
+ return err;
+ }
+ if (size < 0) {
+ return BAD_VALUE;
+ }
+
+ for (size_t i = 0; i < size; i++) {
+ outCrops->emplace_back();
+ err = decodeRect(inputHidlVec, &outCrops->back());
+ if (err) {
+ return err;
+ }
+ }
+ return NO_ERROR;
+}
+
+void clearCrop(std::vector<Rect>* output) {
+ if (!output) {
+ return;
+ }
+ output->clear();
+}
+
status_t encodeSmpte2086Helper(const Smpte2086& smpte2086, OutputHidlVec* outOutputHidlVec) {
status_t err = encodeXyColor(smpte2086.primaryRed, outOutputHidlVec);
if (err) {
@@ -1043,6 +1076,14 @@
decodePlaneLayoutsHelper, clearPlaneLayouts);
}
+status_t encodeCrop(const std::vector<Rect>& crop, hidl_vec<uint8_t>* outCrop) {
+ return encodeMetadata(MetadataType_Crop, crop, outCrop, encodeCropHelper);
+}
+
+status_t decodeCrop(const hidl_vec<uint8_t>& crop, std::vector<Rect>* outCrop) {
+ return decodeMetadata(MetadataType_Crop, crop, outCrop, decodeCropHelper, clearCrop);
+}
+
status_t encodeDataspace(const Dataspace& dataspace, hidl_vec<uint8_t>* outDataspace) {
return encodeMetadata(MetadataType_Dataspace, static_cast<int32_t>(dataspace), outDataspace,
encodeInteger);
diff --git a/libs/gralloc/types/fuzzer/gralloctypes.cpp b/libs/gralloc/types/fuzzer/gralloctypes.cpp
index b5644be..dc22385 100644
--- a/libs/gralloc/types/fuzzer/gralloctypes.cpp
+++ b/libs/gralloc/types/fuzzer/gralloctypes.cpp
@@ -70,6 +70,7 @@
GRALLOCTYPES_DECODE(aidl::android::hardware::graphics::common::ExtendableType, ::android::gralloc4::decodeInterlaced),
GRALLOCTYPES_DECODE(aidl::android::hardware::graphics::common::ExtendableType, ::android::gralloc4::decodeChromaSiting),
GRALLOCTYPES_DECODE(std::vector<aidl::android::hardware::graphics::common::PlaneLayout>, ::android::gralloc4::decodePlaneLayouts),
+ GRALLOCTYPES_DECODE(std::vector<aidl::android::hardware::graphics::common::Rect>, ::android::gralloc4::decodeCrop),
GRALLOCTYPES_DECODE(aidl::android::hardware::graphics::common::Dataspace, ::android::gralloc4::decodeDataspace),
GRALLOCTYPES_DECODE(aidl::android::hardware::graphics::common::BlendMode, ::android::gralloc4::decodeBlendMode),
GRALLOCTYPES_DECODE(std::optional<aidl::android::hardware::graphics::common::Smpte2086>, ::android::gralloc4::decodeSmpte2086),
diff --git a/libs/gralloc/types/include/gralloctypes/Gralloc4.h b/libs/gralloc/types/include/gralloctypes/Gralloc4.h
index d855439..5ec4d0d 100644
--- a/libs/gralloc/types/include/gralloctypes/Gralloc4.h
+++ b/libs/gralloc/types/include/gralloctypes/Gralloc4.h
@@ -89,6 +89,24 @@
return !(lhs == rhs);
}
+inline bool operator==(const std::vector<aidl::android::hardware::graphics::common::Rect>& lhs,
+ const std::vector<aidl::android::hardware::graphics::common::Rect>& rhs) {
+ if (lhs.size() != rhs.size()) {
+ return false;
+ }
+ for (size_t i = 0; i < lhs.size(); i++) {
+ if (lhs[i] != rhs[i]) {
+ return false;
+ }
+ }
+ return true;
+}
+
+inline bool operator!=(const std::vector<aidl::android::hardware::graphics::common::Rect>& lhs,
+ const std::vector<aidl::android::hardware::graphics::common::Rect>& rhs) {
+ return !(lhs == rhs);
+}
+
inline bool operator==(const aidl::android::hardware::graphics::common::PlaneLayout& lhs,
const aidl::android::hardware::graphics::common::PlaneLayout& rhs) {
if (lhs.offsetInBytes != rhs.offsetInBytes) {
@@ -115,9 +133,6 @@
if (lhs.verticalSubsampling != rhs.verticalSubsampling) {
return false;
}
- if (lhs.crop != rhs.crop) {
- return false;
- }
if (lhs.components.size() != rhs.components.size()) {
return false;
}
@@ -286,6 +301,10 @@
GRALLOC4_STANDARD_METADATA_TYPE, static_cast<int64_t>(aidl::android::hardware::graphics::common::StandardMetadataType::PLANE_LAYOUTS)
};
+static const android::hardware::graphics::mapper::V4_0::IMapper::MetadataType MetadataType_Crop = {
+ GRALLOC4_STANDARD_METADATA_TYPE, static_cast<int64_t>(aidl::android::hardware::graphics::common::StandardMetadataType::CROP)
+};
+
static const android::hardware::graphics::mapper::V4_0::IMapper::MetadataType MetadataType_Dataspace = {
GRALLOC4_STANDARD_METADATA_TYPE, static_cast<int64_t>(aidl::android::hardware::graphics::common::StandardMetadataType::DATASPACE)
};
@@ -469,6 +488,9 @@
status_t encodePlaneLayouts(const std::vector<aidl::android::hardware::graphics::common::PlaneLayout>& planeLayouts, android::hardware::hidl_vec<uint8_t>* outPlaneLayouts);
status_t decodePlaneLayouts(const android::hardware::hidl_vec<uint8_t>& planeLayouts, std::vector<aidl::android::hardware::graphics::common::PlaneLayout>* outPlaneLayouts);
+status_t encodeCrop(const std::vector<aidl::android::hardware::graphics::common::Rect>& crop, android::hardware::hidl_vec<uint8_t>* outCrop);
+status_t decodeCrop(const android::hardware::hidl_vec<uint8_t>& crop, std::vector<aidl::android::hardware::graphics::common::Rect>* outCrop);
+
status_t encodeDataspace(const aidl::android::hardware::graphics::common::Dataspace& dataspace, android::hardware::hidl_vec<uint8_t>* outDataspace);
status_t decodeDataspace(const android::hardware::hidl_vec<uint8_t>& dataspace, aidl::android::hardware::graphics::common::Dataspace* outDataspace);
diff --git a/libs/gralloc/types/tests/Gralloc4_test.cpp b/libs/gralloc/types/tests/Gralloc4_test.cpp
index dbe41f1..89cbf4a 100644
--- a/libs/gralloc/types/tests/Gralloc4_test.cpp
+++ b/libs/gralloc/types/tests/Gralloc4_test.cpp
@@ -321,10 +321,6 @@
planeLayoutA.totalSizeInBytes = planeLayoutA.strideInBytes * height;
planeLayoutA.horizontalSubsampling = 1;
planeLayoutA.verticalSubsampling = 1;
- planeLayoutA.crop.left = 0;
- planeLayoutA.crop.top = 0;
- planeLayoutA.crop.right = width;
- planeLayoutA.crop.bottom = height;
component.type = gralloc4::PlaneLayoutComponentType_A;
component.offsetInBits = 0;
@@ -341,11 +337,6 @@
planeLayoutRGB.totalSizeInBytes = planeLayoutRGB.strideInBytes * height;
planeLayoutRGB.horizontalSubsampling = 1;
planeLayoutRGB.verticalSubsampling = 1;
- planeLayoutRGB.crop.left = 0;
- planeLayoutRGB.crop.top = 0;
- planeLayoutRGB.crop.right = width;
- planeLayoutRGB.crop.bottom = height;
-
component.type = gralloc4::PlaneLayoutComponentType_R;
planeLayoutRGB.components.push_back(component);
component.type = gralloc4::PlaneLayoutComponentType_G;
@@ -358,6 +349,33 @@
ASSERT_NO_FATAL_FAILURE(testHelperStableAidlType(planeLayouts, gralloc4::encodePlaneLayouts, gralloc4::decodePlaneLayouts));
}
+class Gralloc4TestCrop : public testing::Test { };
+
+TEST_F(Gralloc4TestCrop, Crop) {
+ std::vector<Rect> crops;
+ Rect crop1, crop2, crop3;
+
+ crop1.left = 0;
+ crop1.top = 0;
+ crop1.right = 64;
+ crop1.bottom = 64;
+ crops.push_back(crop1);
+
+ crop2.left = std::numeric_limits<int32_t>::min();
+ crop2.top = 0xFF;
+ crop2.right = std::numeric_limits<int32_t>::max();
+ crop2.bottom = 0xFFFF;
+ crops.push_back(crop2);
+
+ crop3.left = 0;
+ crop3.top = 0;
+ crop3.right = -1;
+ crop3.bottom = -1;
+ crops.push_back(crop3);
+
+ ASSERT_NO_FATAL_FAILURE(testHelperStableAidlType(crops, gralloc4::encodeCrop, gralloc4::decodeCrop));
+}
+
class Gralloc4TestDataspace : public testing::TestWithParam<Dataspace> { };
INSTANTIATE_TEST_CASE_P(
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp
index 40c044d..99d3856 100644
--- a/libs/gui/Android.bp
+++ b/libs/gui/Android.bp
@@ -55,7 +55,11 @@
"DisplayEventReceiver.cpp",
"GLConsumer.cpp",
"GuiConfig.cpp",
+ "IConsumerListener.cpp",
"IDisplayEventConnection.cpp",
+ "IGraphicBufferConsumer.cpp",
+ "IGraphicBufferProducer.cpp",
+ "IProducerListener.cpp",
"IRegionSamplingListener.cpp",
"ISurfaceComposer.cpp",
"ISurfaceComposerClient.cpp",
@@ -63,22 +67,32 @@
"LayerDebugInfo.cpp",
"LayerMetadata.cpp",
"LayerState.cpp",
+ "OccupancyTracker.cpp",
"StreamSplitter.cpp",
"Surface.cpp",
"SurfaceControl.cpp",
"SurfaceComposerClient.cpp",
"SyncFeatures.cpp",
"view/Surface.cpp",
+ "bufferqueue/1.0/B2HProducerListener.cpp",
+ "bufferqueue/1.0/H2BGraphicBufferProducer.cpp",
+ "bufferqueue/2.0/B2HProducerListener.cpp",
+ "bufferqueue/2.0/H2BGraphicBufferProducer.cpp",
],
shared_libs: [
"android.frameworks.bufferhub@1.0",
+ "libbinder",
"libbufferhub",
"libbufferhubqueue", // TODO(b/70046255): Remove this once BufferHub is integrated into libgui.
"libinput",
"libpdx_default_transport",
],
+ export_shared_lib_headers: [
+ "libbinder",
+ ],
+
// bufferhub is not used when building libgui for vendors
target: {
vendor: {
@@ -118,6 +132,7 @@
cflags: [
"-DNO_BUFFERHUB",
+ "-DNO_BINDER",
],
defaults: ["libgui_bufferqueue-defaults"],
@@ -140,19 +155,11 @@
"FrameTimestamps.cpp",
"GLConsumerUtils.cpp",
"HdrMetadata.cpp",
- "IConsumerListener.cpp",
- "IGraphicBufferConsumer.cpp",
- "IGraphicBufferProducer.cpp",
- "IProducerListener.cpp",
- "OccupancyTracker.cpp",
- "bufferqueue/1.0/B2HProducerListener.cpp",
+ "QueueBufferInputOutput.cpp",
"bufferqueue/1.0/Conversion.cpp",
- "bufferqueue/1.0/H2BGraphicBufferProducer.cpp",
"bufferqueue/1.0/H2BProducerListener.cpp",
"bufferqueue/1.0/WProducerListener.cpp",
"bufferqueue/2.0/B2HGraphicBufferProducer.cpp",
- "bufferqueue/2.0/B2HProducerListener.cpp",
- "bufferqueue/2.0/H2BGraphicBufferProducer.cpp",
"bufferqueue/2.0/H2BProducerListener.cpp",
"bufferqueue/2.0/types.cpp",
],
@@ -189,7 +196,6 @@
"android.hardware.graphics.common@1.2",
"android.hidl.token@1.0-utils",
"libbase",
- "libbinder",
"libcutils",
"libEGL",
"libGLESv2",
@@ -212,7 +218,6 @@
],
export_shared_lib_headers: [
- "libbinder",
"libEGL",
"libnativewindow",
"libui",
diff --git a/libs/gui/BufferQueueConsumer.cpp b/libs/gui/BufferQueueConsumer.cpp
index 9b74fef..4435265 100644
--- a/libs/gui/BufferQueueConsumer.cpp
+++ b/libs/gui/BufferQueueConsumer.cpp
@@ -66,6 +66,8 @@
mCore->mUniqueId, mCore->mConnectedApi, mCore->mConnectedPid, (mCore->mUniqueId) >> 32, \
##__VA_ARGS__)
+ConsumerListener::~ConsumerListener() = default;
+
BufferQueueConsumer::BufferQueueConsumer(const sp<BufferQueueCore>& core) :
mCore(core),
mSlots(core->mSlots),
@@ -291,8 +293,9 @@
ATRACE_INT(mCore->mConsumerName.string(),
static_cast<int32_t>(mCore->mQueue.size()));
+#ifndef NO_BINDER
mCore->mOccupancyTracker.registerOccupancyChange(mCore->mQueue.size());
-
+#endif
VALIDATE_CONSISTENCY();
}
@@ -765,7 +768,12 @@
status_t BufferQueueConsumer::getOccupancyHistory(bool forceFlush,
std::vector<OccupancyTracker::Segment>* outHistory) {
std::lock_guard<std::mutex> lock(mCore->mMutex);
+#ifndef NO_BINDER
*outHistory = mCore->mOccupancyTracker.getSegmentHistory(forceFlush);
+#else
+ (void)forceFlush;
+ outHistory->clear();
+#endif
return NO_ERROR;
}
@@ -798,7 +806,7 @@
bool denied = false;
const uid_t uid = BufferQueueThreadState::getCallingUid();
-#ifndef __ANDROID_VNDK__
+#if !defined(__ANDROID_VNDK__) && !defined(NO_BINDER)
// permission check can't be done for vendors as vendors have no access to
// the PermissionController. We need to do a runtime check as well, since
// the system variant of libgui can be loaded in a vendor process. For eg:
diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp
index 6b11a54..9e86838 100644
--- a/libs/gui/BufferQueueProducer.cpp
+++ b/libs/gui/BufferQueueProducer.cpp
@@ -67,6 +67,7 @@
##__VA_ARGS__)
static constexpr uint32_t BQ_LAYER_COUNT = 1;
+ProducerListener::~ProducerListener() = default;
BufferQueueProducer::BufferQueueProducer(const sp<BufferQueueCore>& core,
bool consumerIsSurfaceFlinger) :
@@ -1005,8 +1006,9 @@
ATRACE_INT(mCore->mConsumerName.string(),
static_cast<int32_t>(mCore->mQueue.size()));
+#ifndef NO_BINDER
mCore->mOccupancyTracker.registerOccupancyChange(mCore->mQueue.size());
-
+#endif
// Take a ticket for the callback functions
callbackTicket = mNextCallbackTicket++;
@@ -1252,6 +1254,7 @@
if (listener != nullptr) {
// Set up a death notification so that we can disconnect
// automatically if the remote producer dies
+#ifndef NO_BINDER
if (IInterface::asBinder(listener)->remoteBinder() != nullptr) {
status = IInterface::asBinder(listener)->linkToDeath(
static_cast<IBinder::DeathRecipient*>(this));
@@ -1261,6 +1264,7 @@
}
mCore->mLinkedToDeath = listener;
}
+#endif
mCore->mConnectedProducerListener = listener;
mCore->mBufferReleasedCbEnabled = listener->needsReleaseNotify();
}
@@ -1329,6 +1333,7 @@
if (mCore->mConnectedApi == api) {
mCore->freeAllBuffersLocked();
+#ifndef NO_BINDER
// Remove our death notification callback if we have one
if (mCore->mLinkedToDeath != nullptr) {
sp<IBinder> token =
@@ -1338,6 +1343,7 @@
token->unlinkToDeath(
static_cast<IBinder::DeathRecipient*>(this));
}
+#endif
mCore->mSharedBufferSlot =
BufferQueueCore::INVALID_BUFFER_SLOT;
mCore->mLinkedToDeath = nullptr;
diff --git a/libs/gui/BufferQueueThreadState.cpp b/libs/gui/BufferQueueThreadState.cpp
index c13030b..976c9b9 100644
--- a/libs/gui/BufferQueueThreadState.cpp
+++ b/libs/gui/BufferQueueThreadState.cpp
@@ -14,8 +14,10 @@
* limitations under the License.
*/
+#ifndef NO_BINDER
#include <binder/IPCThreadState.h>
#include <binderthreadstate/CallerUtils.h>
+#endif // NO_BINDER
#include <hwbinder/IPCThreadState.h>
#include <private/gui/BufferQueueThreadState.h>
#include <unistd.h>
@@ -23,17 +25,25 @@
namespace android {
uid_t BufferQueueThreadState::getCallingUid() {
+#ifndef NO_BINDER
if (getCurrentServingCall() == BinderCallType::HWBINDER) {
return hardware::IPCThreadState::self()->getCallingUid();
}
return IPCThreadState::self()->getCallingUid();
+#else // NO_BINDER
+ return hardware::IPCThreadState::self()->getCallingUid();
+#endif // NO_BINDER
}
pid_t BufferQueueThreadState::getCallingPid() {
+#ifndef NO_BINDER
if (getCurrentServingCall() == BinderCallType::HWBINDER) {
return hardware::IPCThreadState::self()->getCallingPid();
}
return IPCThreadState::self()->getCallingPid();
+#else // NO_BINDER
+ return hardware::IPCThreadState::self()->getCallingPid();
+#endif // NO_BINDER
}
} // namespace android
diff --git a/libs/gui/IConsumerListener.cpp b/libs/gui/IConsumerListener.cpp
index 48cb4b9..f3bd90c 100644
--- a/libs/gui/IConsumerListener.cpp
+++ b/libs/gui/IConsumerListener.cpp
@@ -90,7 +90,6 @@
// Out-of-line virtual method definitions to trigger vtable emission in this translation unit (see
// clang warning -Wweak-vtables)
BpConsumerListener::~BpConsumerListener() = default;
-ConsumerListener::~ConsumerListener() = default;
IMPLEMENT_META_INTERFACE(ConsumerListener, "android.gui.IConsumerListener");
diff --git a/libs/gui/IGraphicBufferProducer.cpp b/libs/gui/IGraphicBufferProducer.cpp
index 75876f2..7b5596e 100644
--- a/libs/gui/IGraphicBufferProducer.cpp
+++ b/libs/gui/IGraphicBufferProducer.cpp
@@ -1113,133 +1113,5 @@
parcel.read(*this);
}
-constexpr size_t IGraphicBufferProducer::QueueBufferInput::minFlattenedSize() {
- return sizeof(timestamp) +
- sizeof(isAutoTimestamp) +
- sizeof(dataSpace) +
- sizeof(crop) +
- sizeof(scalingMode) +
- sizeof(transform) +
- sizeof(stickyTransform) +
- sizeof(getFrameTimestamps);
-}
-
-size_t IGraphicBufferProducer::QueueBufferInput::getFlattenedSize() const {
- return minFlattenedSize() +
- fence->getFlattenedSize() +
- surfaceDamage.getFlattenedSize() +
- hdrMetadata.getFlattenedSize();
-}
-
-size_t IGraphicBufferProducer::QueueBufferInput::getFdCount() const {
- return fence->getFdCount();
-}
-
-status_t IGraphicBufferProducer::QueueBufferInput::flatten(
- void*& buffer, size_t& size, int*& fds, size_t& count) const
-{
- if (size < getFlattenedSize()) {
- return NO_MEMORY;
- }
-
- FlattenableUtils::write(buffer, size, timestamp);
- FlattenableUtils::write(buffer, size, isAutoTimestamp);
- FlattenableUtils::write(buffer, size, dataSpace);
- FlattenableUtils::write(buffer, size, crop);
- FlattenableUtils::write(buffer, size, scalingMode);
- FlattenableUtils::write(buffer, size, transform);
- FlattenableUtils::write(buffer, size, stickyTransform);
- FlattenableUtils::write(buffer, size, getFrameTimestamps);
-
- status_t result = fence->flatten(buffer, size, fds, count);
- if (result != NO_ERROR) {
- return result;
- }
- result = surfaceDamage.flatten(buffer, size);
- if (result != NO_ERROR) {
- return result;
- }
- FlattenableUtils::advance(buffer, size, surfaceDamage.getFlattenedSize());
- return hdrMetadata.flatten(buffer, size);
-}
-
-status_t IGraphicBufferProducer::QueueBufferInput::unflatten(
- void const*& buffer, size_t& size, int const*& fds, size_t& count)
-{
- if (size < minFlattenedSize()) {
- return NO_MEMORY;
- }
-
- FlattenableUtils::read(buffer, size, timestamp);
- FlattenableUtils::read(buffer, size, isAutoTimestamp);
- FlattenableUtils::read(buffer, size, dataSpace);
- FlattenableUtils::read(buffer, size, crop);
- FlattenableUtils::read(buffer, size, scalingMode);
- FlattenableUtils::read(buffer, size, transform);
- FlattenableUtils::read(buffer, size, stickyTransform);
- FlattenableUtils::read(buffer, size, getFrameTimestamps);
-
- fence = new Fence();
- status_t result = fence->unflatten(buffer, size, fds, count);
- if (result != NO_ERROR) {
- return result;
- }
- result = surfaceDamage.unflatten(buffer, size);
- if (result != NO_ERROR) {
- return result;
- }
- FlattenableUtils::advance(buffer, size, surfaceDamage.getFlattenedSize());
- return hdrMetadata.unflatten(buffer, size);
-}
-
-// ----------------------------------------------------------------------------
-constexpr size_t IGraphicBufferProducer::QueueBufferOutput::minFlattenedSize() {
- return sizeof(width) + sizeof(height) + sizeof(transformHint) + sizeof(numPendingBuffers) +
- sizeof(nextFrameNumber) + sizeof(bufferReplaced) + sizeof(maxBufferCount);
-}
-
-size_t IGraphicBufferProducer::QueueBufferOutput::getFlattenedSize() const {
- return minFlattenedSize() + frameTimestamps.getFlattenedSize();
-}
-
-size_t IGraphicBufferProducer::QueueBufferOutput::getFdCount() const {
- return frameTimestamps.getFdCount();
-}
-
-status_t IGraphicBufferProducer::QueueBufferOutput::flatten(
- void*& buffer, size_t& size, int*& fds, size_t& count) const
-{
- if (size < getFlattenedSize()) {
- return NO_MEMORY;
- }
-
- FlattenableUtils::write(buffer, size, width);
- FlattenableUtils::write(buffer, size, height);
- FlattenableUtils::write(buffer, size, transformHint);
- FlattenableUtils::write(buffer, size, numPendingBuffers);
- FlattenableUtils::write(buffer, size, nextFrameNumber);
- FlattenableUtils::write(buffer, size, bufferReplaced);
- FlattenableUtils::write(buffer, size, maxBufferCount);
-
- return frameTimestamps.flatten(buffer, size, fds, count);
-}
-
-status_t IGraphicBufferProducer::QueueBufferOutput::unflatten(
- void const*& buffer, size_t& size, int const*& fds, size_t& count)
-{
- if (size < minFlattenedSize()) {
- return NO_MEMORY;
- }
-
- FlattenableUtils::read(buffer, size, width);
- FlattenableUtils::read(buffer, size, height);
- FlattenableUtils::read(buffer, size, transformHint);
- FlattenableUtils::read(buffer, size, numPendingBuffers);
- FlattenableUtils::read(buffer, size, nextFrameNumber);
- FlattenableUtils::read(buffer, size, bufferReplaced);
- FlattenableUtils::read(buffer, size, maxBufferCount);
-
- return frameTimestamps.unflatten(buffer, size, fds, count);
-}
}; // namespace android
diff --git a/libs/gui/IProducerListener.cpp b/libs/gui/IProducerListener.cpp
index 808e336..5c81b9d 100644
--- a/libs/gui/IProducerListener.cpp
+++ b/libs/gui/IProducerListener.cpp
@@ -119,8 +119,6 @@
return BBinder::onTransact(code, data, reply, flags);
}
-ProducerListener::~ProducerListener() = default;
-
DummyProducerListener::~DummyProducerListener() = default;
bool BnProducerListener::needsReleaseNotify() {
diff --git a/libs/gui/QueueBufferInputOutput.cpp b/libs/gui/QueueBufferInputOutput.cpp
new file mode 100644
index 0000000..30f0ef6
--- /dev/null
+++ b/libs/gui/QueueBufferInputOutput.cpp
@@ -0,0 +1,159 @@
+/*
+ * Copyright 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <inttypes.h>
+
+#define LOG_TAG "QueueBufferInputOutput"
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+//#define LOG_NDEBUG 0
+
+#include <gui/IGraphicBufferProducer.h>
+
+namespace android {
+
+constexpr size_t IGraphicBufferProducer::QueueBufferInput::minFlattenedSize() {
+ return sizeof(timestamp) +
+ sizeof(isAutoTimestamp) +
+ sizeof(dataSpace) +
+ sizeof(crop) +
+ sizeof(scalingMode) +
+ sizeof(transform) +
+ sizeof(stickyTransform) +
+ sizeof(getFrameTimestamps);
+}
+
+IGraphicBufferProducer::QueueBufferInput::QueueBufferInput(const Parcel& parcel) {
+ parcel.read(*this);
+}
+
+size_t IGraphicBufferProducer::QueueBufferInput::getFlattenedSize() const {
+ return minFlattenedSize() +
+ fence->getFlattenedSize() +
+ surfaceDamage.getFlattenedSize() +
+ hdrMetadata.getFlattenedSize();
+}
+
+size_t IGraphicBufferProducer::QueueBufferInput::getFdCount() const {
+ return fence->getFdCount();
+}
+
+status_t IGraphicBufferProducer::QueueBufferInput::flatten(
+ void*& buffer, size_t& size, int*& fds, size_t& count) const
+{
+ if (size < getFlattenedSize()) {
+ return NO_MEMORY;
+ }
+
+ FlattenableUtils::write(buffer, size, timestamp);
+ FlattenableUtils::write(buffer, size, isAutoTimestamp);
+ FlattenableUtils::write(buffer, size, dataSpace);
+ FlattenableUtils::write(buffer, size, crop);
+ FlattenableUtils::write(buffer, size, scalingMode);
+ FlattenableUtils::write(buffer, size, transform);
+ FlattenableUtils::write(buffer, size, stickyTransform);
+ FlattenableUtils::write(buffer, size, getFrameTimestamps);
+
+ status_t result = fence->flatten(buffer, size, fds, count);
+ if (result != NO_ERROR) {
+ return result;
+ }
+ result = surfaceDamage.flatten(buffer, size);
+ if (result != NO_ERROR) {
+ return result;
+ }
+ FlattenableUtils::advance(buffer, size, surfaceDamage.getFlattenedSize());
+ return hdrMetadata.flatten(buffer, size);
+}
+
+status_t IGraphicBufferProducer::QueueBufferInput::unflatten(
+ void const*& buffer, size_t& size, int const*& fds, size_t& count)
+{
+ if (size < minFlattenedSize()) {
+ return NO_MEMORY;
+ }
+
+ FlattenableUtils::read(buffer, size, timestamp);
+ FlattenableUtils::read(buffer, size, isAutoTimestamp);
+ FlattenableUtils::read(buffer, size, dataSpace);
+ FlattenableUtils::read(buffer, size, crop);
+ FlattenableUtils::read(buffer, size, scalingMode);
+ FlattenableUtils::read(buffer, size, transform);
+ FlattenableUtils::read(buffer, size, stickyTransform);
+ FlattenableUtils::read(buffer, size, getFrameTimestamps);
+
+ fence = new Fence();
+ status_t result = fence->unflatten(buffer, size, fds, count);
+ if (result != NO_ERROR) {
+ return result;
+ }
+ result = surfaceDamage.unflatten(buffer, size);
+ if (result != NO_ERROR) {
+ return result;
+ }
+ FlattenableUtils::advance(buffer, size, surfaceDamage.getFlattenedSize());
+ return hdrMetadata.unflatten(buffer, size);
+}
+
+////////////////////////////////////////////////////////////////////////
+constexpr size_t IGraphicBufferProducer::QueueBufferOutput::minFlattenedSize() {
+ return sizeof(width) + sizeof(height) + sizeof(transformHint) + sizeof(numPendingBuffers) +
+ sizeof(nextFrameNumber) + sizeof(bufferReplaced) + sizeof(maxBufferCount);
+}
+size_t IGraphicBufferProducer::QueueBufferOutput::getFlattenedSize() const {
+ return minFlattenedSize() + frameTimestamps.getFlattenedSize();
+}
+
+size_t IGraphicBufferProducer::QueueBufferOutput::getFdCount() const {
+ return frameTimestamps.getFdCount();
+}
+
+status_t IGraphicBufferProducer::QueueBufferOutput::flatten(
+ void*& buffer, size_t& size, int*& fds, size_t& count) const
+{
+ if (size < getFlattenedSize()) {
+ return NO_MEMORY;
+ }
+
+ FlattenableUtils::write(buffer, size, width);
+ FlattenableUtils::write(buffer, size, height);
+ FlattenableUtils::write(buffer, size, transformHint);
+ FlattenableUtils::write(buffer, size, numPendingBuffers);
+ FlattenableUtils::write(buffer, size, nextFrameNumber);
+ FlattenableUtils::write(buffer, size, bufferReplaced);
+ FlattenableUtils::write(buffer, size, maxBufferCount);
+
+ return frameTimestamps.flatten(buffer, size, fds, count);
+}
+
+status_t IGraphicBufferProducer::QueueBufferOutput::unflatten(
+ void const*& buffer, size_t& size, int const*& fds, size_t& count)
+{
+ if (size < minFlattenedSize()) {
+ return NO_MEMORY;
+ }
+
+ FlattenableUtils::read(buffer, size, width);
+ FlattenableUtils::read(buffer, size, height);
+ FlattenableUtils::read(buffer, size, transformHint);
+ FlattenableUtils::read(buffer, size, numPendingBuffers);
+ FlattenableUtils::read(buffer, size, nextFrameNumber);
+ FlattenableUtils::read(buffer, size, bufferReplaced);
+ FlattenableUtils::read(buffer, size, maxBufferCount);
+
+ return frameTimestamps.unflatten(buffer, size, fds, count);
+}
+
+} // namespace android
diff --git a/libs/gui/bufferqueue/1.0/Conversion.cpp b/libs/gui/bufferqueue/1.0/Conversion.cpp
index 5cb3593..3e20a37 100644
--- a/libs/gui/bufferqueue/1.0/Conversion.cpp
+++ b/libs/gui/bufferqueue/1.0/Conversion.cpp
@@ -109,20 +109,6 @@
}
/**
- * \brief Convert `Return<void>` to `binder::Status`.
- *
- * \param[in] t The source `Return<void>`.
- * \return The corresponding `binder::Status`.
- */
-// convert: Return<void> -> ::android::binder::Status
-::android::binder::Status toBinderStatus(
- Return<void> const& t) {
- return ::android::binder::Status::fromExceptionCode(
- toStatusT(t),
- t.description().c_str());
-}
-
-/**
* \brief Wrap `native_handle_t*` in `hidl_handle`.
*
* \param[in] nh The source `native_handle_t*`.
@@ -1337,57 +1323,6 @@
return unflatten(&(t->surfaceDamage), buffer, size);
}
-/**
- * \brief Wrap `BGraphicBufferProducer::QueueBufferInput` in
- * `HGraphicBufferProducer::QueueBufferInput`.
- *
- * \param[out] t The wrapper of type
- * `HGraphicBufferProducer::QueueBufferInput`.
- * \param[out] nh The underlying native handle for `t->fence`.
- * \param[in] l The source `BGraphicBufferProducer::QueueBufferInput`.
- *
- * If the return value is `true` and `t->fence` contains a valid file
- * descriptor, \p nh will be a newly created native handle holding that file
- * descriptor. \p nh needs to be deleted with `native_handle_delete()`
- * afterwards.
- */
-bool wrapAs(
- HGraphicBufferProducer::QueueBufferInput* t,
- native_handle_t** nh,
- BGraphicBufferProducer::QueueBufferInput const& l) {
-
- size_t const baseSize = l.getFlattenedSize();
- std::unique_ptr<uint8_t[]> baseBuffer(
- new (std::nothrow) uint8_t[baseSize]);
- if (!baseBuffer) {
- return false;
- }
-
- size_t const baseNumFds = l.getFdCount();
- std::unique_ptr<int[]> baseFds(
- new (std::nothrow) int[baseNumFds]);
- if (!baseFds) {
- return false;
- }
-
- void* buffer = static_cast<void*>(baseBuffer.get());
- size_t size = baseSize;
- int* fds = baseFds.get();
- size_t numFds = baseNumFds;
- if (l.flatten(buffer, size, fds, numFds) != NO_ERROR) {
- return false;
- }
-
- void const* constBuffer = static_cast<void const*>(baseBuffer.get());
- size = baseSize;
- int const* constFds = static_cast<int const*>(baseFds.get());
- numFds = baseNumFds;
- if (unflatten(t, nh, constBuffer, size, constFds, numFds) != NO_ERROR) {
- return false;
- }
-
- return true;
-}
/**
* \brief Convert `HGraphicBufferProducer::QueueBufferInput` to
diff --git a/libs/gui/bufferqueue/1.0/H2BProducerListener.cpp b/libs/gui/bufferqueue/1.0/H2BProducerListener.cpp
index 2712f42..598c8de 100644
--- a/libs/gui/bufferqueue/1.0/H2BProducerListener.cpp
+++ b/libs/gui/bufferqueue/1.0/H2BProducerListener.cpp
@@ -32,7 +32,11 @@
using ::android::hardware::Return;
H2BProducerListener::H2BProducerListener(sp<HProducerListener> const& base)
+#ifndef NO_BINDER
: CBase{base} {
+#else
+ : mBase(base) {
+#endif
}
void H2BProducerListener::onBufferReleased() {
diff --git a/libs/gui/bufferqueue/1.0/WProducerListener.cpp b/libs/gui/bufferqueue/1.0/WProducerListener.cpp
index 78dc4e8..56b64b9 100644
--- a/libs/gui/bufferqueue/1.0/WProducerListener.cpp
+++ b/libs/gui/bufferqueue/1.0/WProducerListener.cpp
@@ -46,5 +46,7 @@
bool LWProducerListener::needsReleaseNotify() {
return static_cast<bool>(mBase->needsReleaseNotify());
}
+void LWProducerListener::onBuffersDiscarded(const std::vector<int32_t>& /*slots*/) {
+}
} // namespace android
diff --git a/libs/gui/bufferqueue/2.0/B2HGraphicBufferProducer.cpp b/libs/gui/bufferqueue/2.0/B2HGraphicBufferProducer.cpp
index e891ec5..c76d771 100644
--- a/libs/gui/bufferqueue/2.0/B2HGraphicBufferProducer.cpp
+++ b/libs/gui/bufferqueue/2.0/B2HGraphicBufferProducer.cpp
@@ -249,6 +249,24 @@
return {};
}
+struct Obituary : public hardware::hidl_death_recipient {
+ wp<B2HGraphicBufferProducer> producer;
+ sp<HProducerListener> listener;
+ HConnectionType apiType;
+ Obituary(const wp<B2HGraphicBufferProducer>& p,
+ const sp<HProducerListener>& l,
+ HConnectionType t)
+ : producer(p), listener(l), apiType(t) {}
+
+ void serviceDied(uint64_t /* cookie */,
+ const wp<::android::hidl::base::V1_0::IBase>& /* who */) override {
+ sp<B2HGraphicBufferProducer> dr = producer.promote();
+ if (dr != nullptr) {
+ (void)dr->disconnect(apiType);
+ }
+ }
+};
+
Return<void> B2HGraphicBufferProducer::connect(
sp<HProducerListener> const& hListener,
HConnectionType hConnectionType,
@@ -270,6 +288,12 @@
&bOutput),
&hStatus) &&
b2h(bOutput, &hOutput);
+#ifdef NO_BINDER
+ if (converted && hListener != nullptr) {
+ mObituary = new Obituary(this, hListener, hConnectionType);
+ hListener->linkToDeath(mObituary, 0);
+ }
+#endif // NO_BINDER
_hidl_cb(converted ? hStatus : HStatus::UNKNOWN_ERROR, hOutput);
return {};
}
@@ -282,6 +306,12 @@
}
HStatus hStatus{};
bool converted = b2h(mBase->disconnect(bConnectionType), &hStatus);
+#ifdef NO_BINDER
+ if (mObituary != nullptr) {
+ mObituary->listener->unlinkToDeath(mObituary);
+ mObituary.clear();
+ }
+#endif // NO_BINDER
return {converted ? hStatus : HStatus::UNKNOWN_ERROR};
}
diff --git a/libs/gui/bufferqueue/2.0/H2BProducerListener.cpp b/libs/gui/bufferqueue/2.0/H2BProducerListener.cpp
index b81a357..b2bd117 100644
--- a/libs/gui/bufferqueue/2.0/H2BProducerListener.cpp
+++ b/libs/gui/bufferqueue/2.0/H2BProducerListener.cpp
@@ -32,7 +32,11 @@
using ::android::hardware::Return;
H2BProducerListener::H2BProducerListener(sp<HProducerListener> const& base)
+#ifndef NO_BINDER
: CBase{base} {
+#else
+ : mBase(base) {
+#endif
}
void H2BProducerListener::onBufferReleased() {
@@ -48,6 +52,9 @@
return static_cast<bool>(mBase);
}
+void H2BProducerListener::onBuffersDiscarded(const std::vector<int32_t>& /*slots*/) {
+}
+
} // namespace utils
} // namespace V2_0
} // namespace bufferqueue
diff --git a/libs/gui/include/gui/BufferQueueProducer.h b/libs/gui/include/gui/BufferQueueProducer.h
index 2dec663..cbace5b 100644
--- a/libs/gui/include/gui/BufferQueueProducer.h
+++ b/libs/gui/include/gui/BufferQueueProducer.h
@@ -22,10 +22,15 @@
namespace android {
+class IBinder;
struct BufferSlot;
+#ifndef NO_BINDER
class BufferQueueProducer : public BnGraphicBufferProducer,
private IBinder::DeathRecipient {
+#else
+class BufferQueueProducer : public BnGraphicBufferProducer {
+#endif
public:
friend class BufferQueue; // Needed to access binderDied
diff --git a/libs/gui/include/gui/IConsumerListener.h b/libs/gui/include/gui/IConsumerListener.h
index 046f6e1..0ab2399 100644
--- a/libs/gui/include/gui/IConsumerListener.h
+++ b/libs/gui/include/gui/IConsumerListener.h
@@ -92,6 +92,7 @@
FrameEventHistoryDelta* /*outDelta*/) {}
};
+#ifndef NO_BINDER
class IConsumerListener : public ConsumerListener, public IInterface {
public:
DECLARE_META_INTERFACE(ConsumerListener)
@@ -105,4 +106,11 @@
uint32_t flags = 0) override;
};
+#else
+class IConsumerListener : public ConsumerListener {
+};
+class BnConsumerListener : public IConsumerListener {
+};
+#endif
+
} // namespace android
diff --git a/libs/gui/include/gui/IGraphicBufferConsumer.h b/libs/gui/include/gui/IGraphicBufferConsumer.h
index 54f77b4..56fe949 100644
--- a/libs/gui/include/gui/IGraphicBufferConsumer.h
+++ b/libs/gui/include/gui/IGraphicBufferConsumer.h
@@ -35,10 +35,14 @@
class GraphicBuffer;
class IConsumerListener;
class NativeHandle;
-
+#ifndef NO_BINDER
class IGraphicBufferConsumer : public IInterface {
public:
DECLARE_META_INTERFACE(GraphicBufferConsumer)
+#else
+class IGraphicBufferConsumer : public RefBase {
+public:
+#endif
enum {
// Returned by releaseBuffer, after which the consumer must free any references to the
@@ -292,6 +296,7 @@
}
};
+#ifndef NO_BINDER
class BnGraphicBufferConsumer : public SafeBnInterface<IGraphicBufferConsumer> {
public:
BnGraphicBufferConsumer()
@@ -300,5 +305,9 @@
status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply,
uint32_t flags = 0) override;
};
+#else
+class BnGraphicBufferConsumer : public IGraphicBufferConsumer {
+};
+#endif
} // namespace android
diff --git a/libs/gui/include/gui/IGraphicBufferProducer.h b/libs/gui/include/gui/IGraphicBufferProducer.h
index 680d64e..87989da 100644
--- a/libs/gui/include/gui/IGraphicBufferProducer.h
+++ b/libs/gui/include/gui/IGraphicBufferProducer.h
@@ -45,6 +45,13 @@
class NativeHandle;
class Surface;
+using HGraphicBufferProducerV1_0 =
+ ::android::hardware::graphics::bufferqueue::V1_0::
+ IGraphicBufferProducer;
+using HGraphicBufferProducerV2_0 =
+ ::android::hardware::graphics::bufferqueue::V2_0::
+ IGraphicBufferProducer;
+
/*
* This class defines the Binder IPC interface for the producer side of
* a queue of graphics buffers. It's used to send graphics data from one
@@ -59,20 +66,15 @@
*
* This class was previously called ISurfaceTexture.
*/
-class IGraphicBufferProducer : public IInterface
-{
-public:
- using HGraphicBufferProducerV1_0 =
- ::android::hardware::graphics::bufferqueue::V1_0::
- IGraphicBufferProducer;
- using HGraphicBufferProducerV2_0 =
- ::android::hardware::graphics::bufferqueue::V2_0::
- IGraphicBufferProducer;
-
+#ifndef NO_BINDER
+class IGraphicBufferProducer : public IInterface {
DECLARE_HYBRID_META_INTERFACE(GraphicBufferProducer,
HGraphicBufferProducerV1_0,
HGraphicBufferProducerV2_0)
-
+#else
+class IGraphicBufferProducer : public RefBase {
+#endif
+public:
enum {
// A flag returned by dequeueBuffer when the client needs to call
// requestBuffer immediately thereafter.
@@ -640,6 +642,7 @@
// Sets the apps intended frame rate.
virtual status_t setFrameRate(float frameRate);
+#ifndef NO_BINDER
// Static method exports any IGraphicBufferProducer object to a parcel. It
// handles null producer as well.
static status_t exportToParcel(const sp<IGraphicBufferProducer>& producer,
@@ -657,10 +660,11 @@
// it writes a strong binder object; for BufferHub, it writes a
// ProducerQueueParcelable object.
virtual status_t exportToParcel(Parcel* parcel);
+#endif
};
// ----------------------------------------------------------------------------
-
+#ifndef NO_BINDER
class BnGraphicBufferProducer : public BnInterface<IGraphicBufferProducer>
{
public:
@@ -669,6 +673,10 @@
Parcel* reply,
uint32_t flags = 0);
};
+#else
+class BnGraphicBufferProducer : public IGraphicBufferProducer {
+};
+#endif
// ----------------------------------------------------------------------------
}; // namespace android
diff --git a/libs/gui/include/gui/IProducerListener.h b/libs/gui/include/gui/IProducerListener.h
index 32a3690..0b1f4b5 100644
--- a/libs/gui/include/gui/IProducerListener.h
+++ b/libs/gui/include/gui/IProducerListener.h
@@ -51,6 +51,7 @@
virtual void onBuffersDiscarded(const std::vector<int32_t>& slots) = 0; // Asynchronous
};
+#ifndef NO_BINDER
class IProducerListener : public ProducerListener, public IInterface
{
public:
@@ -73,6 +74,12 @@
virtual void onBuffersDiscarded(const std::vector<int32_t>& slots);
};
+#else
+class IProducerListener : public ProducerListener {
+};
+class BnProducerListener : public IProducerListener {
+};
+#endif
class DummyProducerListener : public BnProducerListener
{
public:
diff --git a/libs/gui/include/gui/ISurfaceComposerClient.h b/libs/gui/include/gui/ISurfaceComposerClient.h
index 2b65d2f..6366529 100644
--- a/libs/gui/include/gui/ISurfaceComposerClient.h
+++ b/libs/gui/include/gui/ISurfaceComposerClient.h
@@ -44,7 +44,7 @@
eCursorWindow = 0x00002000,
eFXSurfaceBufferQueue = 0x00000000,
- eFXSurfaceColor = 0x00020000,
+ eFXSurfaceEffect = 0x00020000,
eFXSurfaceBufferState = 0x00040000,
eFXSurfaceContainer = 0x00080000,
eFXSurfaceMask = 0x000F0000,
diff --git a/libs/gui/include/gui/bufferqueue/1.0/Conversion.h b/libs/gui/include/gui/bufferqueue/1.0/Conversion.h
index 627845c..811dcbe 100644
--- a/libs/gui/include/gui/bufferqueue/1.0/Conversion.h
+++ b/libs/gui/include/gui/bufferqueue/1.0/Conversion.h
@@ -25,8 +25,6 @@
#include <hidl/MQDescriptor.h>
#include <hidl/Status.h>
-#include <binder/Binder.h>
-#include <binder/Status.h>
#include <ui/FenceTime.h>
#include <cutils/native_handle.h>
#include <gui/IGraphicBufferProducer.h>
@@ -127,15 +125,6 @@
*/
/**
- * \brief Convert `Return<void>` to `binder::Status`.
- *
- * \param[in] t The source `Return<void>`.
- * \return The corresponding `binder::Status`.
- */
-// convert: Return<void> -> ::android::binder::Status
-::android::binder::Status toBinderStatus(Return<void> const& t);
-
-/**
* \brief Convert `Return<void>` to `status_t`. This is for legacy binder calls.
*
* \param[in] t The source `Return<void>`.
diff --git a/libs/gui/include/gui/bufferqueue/1.0/H2BProducerListener.h b/libs/gui/include/gui/bufferqueue/1.0/H2BProducerListener.h
index 211fdd5..cda5103 100644
--- a/libs/gui/include/gui/bufferqueue/1.0/H2BProducerListener.h
+++ b/libs/gui/include/gui/bufferqueue/1.0/H2BProducerListener.h
@@ -34,7 +34,12 @@
using BProducerListener = ::android::IProducerListener;
class H2BProducerListener
+#ifndef NO_BINDER
: public H2BConverter<HProducerListener, BnProducerListener> {
+#else
+ : public BProducerListener {
+ sp<HProducerListener> mBase;
+#endif
public:
H2BProducerListener(sp<HProducerListener> const& base);
virtual void onBufferReleased() override;
diff --git a/libs/gui/include/gui/bufferqueue/1.0/WGraphicBufferProducer.h b/libs/gui/include/gui/bufferqueue/1.0/WGraphicBufferProducer.h
index 029dcc0..99ab085 100644
--- a/libs/gui/include/gui/bufferqueue/1.0/WGraphicBufferProducer.h
+++ b/libs/gui/include/gui/bufferqueue/1.0/WGraphicBufferProducer.h
@@ -49,7 +49,6 @@
typedef ::android::IGraphicBufferProducer BGraphicBufferProducer;
typedef ::android::IProducerListener BProducerListener;
-using ::android::BnGraphicBufferProducer;
#ifndef LOG
struct LOG_dummy {
diff --git a/libs/gui/include/gui/bufferqueue/1.0/WProducerListener.h b/libs/gui/include/gui/bufferqueue/1.0/WProducerListener.h
index 51dff5b..197db26 100644
--- a/libs/gui/include/gui/bufferqueue/1.0/WProducerListener.h
+++ b/libs/gui/include/gui/bufferqueue/1.0/WProducerListener.h
@@ -20,7 +20,6 @@
#include <hidl/MQDescriptor.h>
#include <hidl/Status.h>
-#include <binder/IBinder.h>
#include <gui/IProducerListener.h>
#include <android/hardware/graphics/bufferqueue/1.0/IProducerListener.h>
@@ -55,6 +54,7 @@
LWProducerListener(sp<HProducerListener> const& base);
void onBufferReleased() override;
bool needsReleaseNotify() override;
+ void onBuffersDiscarded(const std::vector<int32_t>& slots) override;
};
} // namespace android
diff --git a/libs/gui/include/gui/bufferqueue/2.0/B2HGraphicBufferProducer.h b/libs/gui/include/gui/bufferqueue/2.0/B2HGraphicBufferProducer.h
index 1c58167..16d054b 100644
--- a/libs/gui/include/gui/bufferqueue/2.0/B2HGraphicBufferProducer.h
+++ b/libs/gui/include/gui/bufferqueue/2.0/B2HGraphicBufferProducer.h
@@ -45,6 +45,7 @@
using ::android::hardware::hidl_vec;
using ::android::hardware::graphics::common::V1_2::HardwareBuffer;
+struct Obituary;
class B2HGraphicBufferProducer : public HGraphicBufferProducer {
public:
@@ -108,6 +109,7 @@
protected:
sp<BGraphicBufferProducer> mBase;
+ sp<Obituary> mObituary;
};
diff --git a/libs/gui/include/gui/bufferqueue/2.0/H2BProducerListener.h b/libs/gui/include/gui/bufferqueue/2.0/H2BProducerListener.h
index 898920b..92650b7 100644
--- a/libs/gui/include/gui/bufferqueue/2.0/H2BProducerListener.h
+++ b/libs/gui/include/gui/bufferqueue/2.0/H2BProducerListener.h
@@ -33,12 +33,20 @@
using BProducerListener = ::android::IProducerListener;
+#ifndef NO_BINDER
class H2BProducerListener
: public H2BConverter<HProducerListener, BnProducerListener> {
+#else
+class H2BProducerListener
+ : public BProducerListener {
+ sp<HProducerListener> mBase;
+
+#endif
public:
H2BProducerListener(sp<HProducerListener> const& base);
virtual void onBufferReleased() override;
virtual bool needsReleaseNotify() override;
+ virtual void onBuffersDiscarded(const std::vector<int32_t>& slots) override;
};
} // namespace utils
diff --git a/libs/gui/tests/BLASTBufferQueue_test.cpp b/libs/gui/tests/BLASTBufferQueue_test.cpp
index b40eb14..a87ccd6 100644
--- a/libs/gui/tests/BLASTBufferQueue_test.cpp
+++ b/libs/gui/tests/BLASTBufferQueue_test.cpp
@@ -239,7 +239,7 @@
ASSERT_EQ(&next, adapter.getNextTransaction());
}
-TEST_F(BLASTBufferQueueTest, onFrameAvailable_ApplyDesiredPresentTime) {
+TEST_F(BLASTBufferQueueTest, DISABLED_onFrameAvailable_ApplyDesiredPresentTime) {
BLASTBufferQueueHelper adapter(mSurfaceControl, mDisplayWidth, mDisplayHeight);
sp<IGraphicBufferProducer> igbProducer;
setUpProducer(adapter, igbProducer);
@@ -403,7 +403,7 @@
int32_t finalCropSideLength = bufferSideLength / 2;
auto bg = mClient->createSurface(String8("BGTest"), 0, 0, PIXEL_FORMAT_RGBA_8888,
- ISurfaceComposerClient::eFXSurfaceColor);
+ ISurfaceComposerClient::eFXSurfaceEffect);
ASSERT_NE(nullptr, bg.get());
Transaction t;
t.setLayerStack(bg, 0)
diff --git a/libs/gui/tests/EndToEndNativeInputTest.cpp b/libs/gui/tests/EndToEndNativeInputTest.cpp
index 1a623e2..c59afba 100644
--- a/libs/gui/tests/EndToEndNativeInputTest.cpp
+++ b/libs/gui/tests/EndToEndNativeInputTest.cpp
@@ -82,7 +82,8 @@
int width, int height) {
sp<SurfaceControl> surfaceControl =
scc->createSurface(String8("Test Surface"), 0 /* bufHeight */, 0 /* bufWidth */,
- PIXEL_FORMAT_RGBA_8888, ISurfaceComposerClient::eFXSurfaceColor);
+ PIXEL_FORMAT_RGBA_8888,
+ ISurfaceComposerClient::eFXSurfaceEffect);
return std::make_unique<InputSurface>(surfaceControl, width, height);
}
diff --git a/libs/gui/tests/RegionSampling_test.cpp b/libs/gui/tests/RegionSampling_test.cpp
index c9de37d..dbd4ef9 100644
--- a/libs/gui/tests/RegionSampling_test.cpp
+++ b/libs/gui/tests/RegionSampling_test.cpp
@@ -183,7 +183,7 @@
mBackgroundLayer =
mSurfaceComposerClient->createSurface(String8("Background RegionSamplingTest"), 0,
0, PIXEL_FORMAT_RGBA_8888,
- ISurfaceComposerClient::eFXSurfaceColor);
+ ISurfaceComposerClient::eFXSurfaceEffect);
uint32_t layerPositionBottom = 0x7E000000;
SurfaceComposerClient::Transaction{}
.setLayer(mBackgroundLayer, layerPositionBottom)
diff --git a/libs/gui/tests/SamplingDemo.cpp b/libs/gui/tests/SamplingDemo.cpp
index 9891587..5c1bebb 100644
--- a/libs/gui/tests/SamplingDemo.cpp
+++ b/libs/gui/tests/SamplingDemo.cpp
@@ -39,7 +39,7 @@
sp<SurfaceComposerClient> client = new SurfaceComposerClient;
mButton = client->createSurface(String8(name), 0, 0, PIXEL_FORMAT_RGBA_8888,
- ISurfaceComposerClient::eFXSurfaceColor);
+ ISurfaceComposerClient::eFXSurfaceEffect);
const int32_t width = samplingArea.getWidth();
const int32_t height = samplingArea.getHeight();
@@ -55,7 +55,7 @@
.apply();
mButtonBlend = client->createSurface(String8(name) + "Blend", 0, 0, PIXEL_FORMAT_RGBA_8888,
- ISurfaceComposerClient::eFXSurfaceColor);
+ ISurfaceComposerClient::eFXSurfaceEffect);
SurfaceComposerClient::Transaction{}
.setLayer(mButtonBlend, 0x7ffffffe)
@@ -73,7 +73,7 @@
if (HIGHLIGHT_SAMPLING_AREA) {
mSamplingArea =
client->createSurface(String8("SamplingArea"), 0, 0, PIXEL_FORMAT_RGBA_8888,
- ISurfaceComposerClient::eFXSurfaceColor);
+ ISurfaceComposerClient::eFXSurfaceEffect);
SurfaceComposerClient::Transaction{}
.setLayer(mSamplingArea, 0x7ffffffd)
diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp
index 85b0fd0..2a73dc0 100644
--- a/libs/input/Input.cpp
+++ b/libs/input/Input.cpp
@@ -57,6 +57,30 @@
return "UNKNOWN";
}
+VerifiedKeyEvent verifiedKeyEventFromKeyEvent(const KeyEvent& event) {
+ return {{VerifiedInputEvent::Type::KEY, event.getDeviceId(), event.getEventTime(),
+ event.getSource(), event.getDisplayId()},
+ event.getAction(),
+ event.getDownTime(),
+ event.getFlags() & VERIFIED_KEY_EVENT_FLAGS,
+ event.getKeyCode(),
+ event.getScanCode(),
+ event.getMetaState(),
+ event.getRepeatCount()};
+}
+
+VerifiedMotionEvent verifiedMotionEventFromMotionEvent(const MotionEvent& event) {
+ return {{VerifiedInputEvent::Type::MOTION, event.getDeviceId(), event.getEventTime(),
+ event.getSource(), event.getDisplayId()},
+ event.getRawX(0),
+ event.getRawY(0),
+ event.getActionMasked(),
+ event.getDownTime(),
+ event.getFlags() & VERIFIED_MOTION_EVENT_FLAGS,
+ event.getMetaState(),
+ event.getButtonState()};
+}
+
void InputEvent::initialize(int32_t deviceId, uint32_t source, int32_t displayId,
std::array<uint8_t, 32> hmac) {
mDeviceId = deviceId;
diff --git a/libs/input/tests/Android.bp b/libs/input/tests/Android.bp
index c1c35e1..fb21d5e 100644
--- a/libs/input/tests/Android.bp
+++ b/libs/input/tests/Android.bp
@@ -10,12 +10,12 @@
"LatencyStatistics_test.cpp",
"TouchVideoFrame_test.cpp",
"VelocityTracker_test.cpp",
+ "VerifiedInputEvent_test.cpp",
],
cflags: [
"-Wall",
"-Wextra",
"-Werror",
- "-Wno-unused-variable",
],
shared_libs: [
"libinput",
diff --git a/libs/input/tests/InputEvent_test.cpp b/libs/input/tests/InputEvent_test.cpp
index dce1f29..d0f7618 100644
--- a/libs/input/tests/InputEvent_test.cpp
+++ b/libs/input/tests/InputEvent_test.cpp
@@ -46,7 +46,6 @@
}
TEST_F(PointerCoordsTest, AxisValues) {
- float* valuePtr;
PointerCoords coords;
coords.clear();
diff --git a/libs/input/tests/InputPublisherAndConsumer_test.cpp b/libs/input/tests/InputPublisherAndConsumer_test.cpp
index d4bbf6c..885196f 100644
--- a/libs/input/tests/InputPublisherAndConsumer_test.cpp
+++ b/libs/input/tests/InputPublisherAndConsumer_test.cpp
@@ -38,6 +38,7 @@
virtual void SetUp() {
status_t result = InputChannel::openInputChannelPair("channel name",
serverChannel, clientChannel);
+ ASSERT_EQ(OK, result);
mPublisher = new InputPublisher(serverChannel);
mConsumer = new InputConsumer(clientChannel);
diff --git a/libs/input/tests/StructLayout_test.cpp b/libs/input/tests/StructLayout_test.cpp
index aa8a2d4..dd127fc 100644
--- a/libs/input/tests/StructLayout_test.cpp
+++ b/libs/input/tests/StructLayout_test.cpp
@@ -98,4 +98,34 @@
static_assert(sizeof(InputMessage::Body::Focus) == 8);
}
+// --- VerifiedInputEvent ---
+// Ensure that VerifiedInputEvent, VerifiedKeyEvent, VerifiedMotionEvent are packed.
+// We will treat them as byte collections when signing them. There should not be any uninitialized
+// data in-between fields. Otherwise, the padded data will affect the hmac value and verifications
+// will fail.
+
+void TestVerifiedEventSize() {
+ // VerifiedInputEvent
+ constexpr size_t VERIFIED_INPUT_EVENT_SIZE = sizeof(VerifiedInputEvent::type) +
+ sizeof(VerifiedInputEvent::deviceId) + sizeof(VerifiedInputEvent::eventTimeNanos) +
+ sizeof(VerifiedInputEvent::source) + sizeof(VerifiedInputEvent::displayId);
+ static_assert(sizeof(VerifiedInputEvent) == VERIFIED_INPUT_EVENT_SIZE);
+
+ // VerifiedKeyEvent
+ constexpr size_t VERIFIED_KEY_EVENT_SIZE = VERIFIED_INPUT_EVENT_SIZE +
+ sizeof(VerifiedKeyEvent::action) + sizeof(VerifiedKeyEvent::downTimeNanos) +
+ sizeof(VerifiedKeyEvent::flags) + sizeof(VerifiedKeyEvent::keyCode) +
+ sizeof(VerifiedKeyEvent::scanCode) + sizeof(VerifiedKeyEvent::metaState) +
+ sizeof(VerifiedKeyEvent::repeatCount);
+ static_assert(sizeof(VerifiedKeyEvent) == VERIFIED_KEY_EVENT_SIZE);
+
+ // VerifiedMotionEvent
+ constexpr size_t VERIFIED_MOTION_EVENT_SIZE = VERIFIED_INPUT_EVENT_SIZE +
+ sizeof(VerifiedMotionEvent::rawX) + sizeof(VerifiedMotionEvent::rawY) +
+ sizeof(VerifiedMotionEvent::actionMasked) + sizeof(VerifiedMotionEvent::downTimeNanos) +
+ sizeof(VerifiedMotionEvent::flags) + sizeof(VerifiedMotionEvent::metaState) +
+ sizeof(VerifiedMotionEvent::buttonState);
+ static_assert(sizeof(VerifiedMotionEvent) == VERIFIED_MOTION_EVENT_SIZE);
+}
+
} // namespace android
diff --git a/libs/input/tests/VerifiedInputEvent_test.cpp b/libs/input/tests/VerifiedInputEvent_test.cpp
new file mode 100644
index 0000000..a59dbe5
--- /dev/null
+++ b/libs/input/tests/VerifiedInputEvent_test.cpp
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2020 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 <gtest/gtest.h>
+#include <input/Input.h>
+
+namespace android {
+
+static KeyEvent getKeyEventWithFlags(int32_t flags) {
+ KeyEvent event;
+ event.initialize(2 /*deviceId*/, AINPUT_SOURCE_GAMEPAD, ADISPLAY_ID_DEFAULT, INVALID_HMAC,
+ AKEY_EVENT_ACTION_DOWN, flags, AKEYCODE_BUTTON_X, 121 /*scanCode*/,
+ AMETA_ALT_ON, 1 /*repeatCount*/, 1000 /*downTime*/, 2000 /*eventTime*/);
+ return event;
+}
+
+static MotionEvent getMotionEventWithFlags(int32_t flags) {
+ MotionEvent event;
+ constexpr size_t pointerCount = 1;
+ PointerProperties pointerProperties[pointerCount];
+ PointerCoords pointerCoords[pointerCount];
+ for (size_t i = 0; i < pointerCount; i++) {
+ pointerProperties[i].clear();
+ pointerProperties[i].id = i;
+ pointerCoords[i].clear();
+ }
+
+ event.initialize(0 /*deviceId*/, AINPUT_SOURCE_MOUSE, ADISPLAY_ID_DEFAULT, INVALID_HMAC,
+ AMOTION_EVENT_ACTION_DOWN, 0 /*actionButton*/, flags,
+ AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE, 0 /*buttonState*/,
+ MotionClassification::NONE, 2 /*xScale*/, 3 /*yScale*/, 4 /*xOffset*/,
+ 5 /*yOffset*/, 0.1 /*xPrecision*/, 0.2 /*yPrecision*/, 280 /*xCursorPosition*/,
+ 540 /*yCursorPosition*/, 100 /*downTime*/, 200 /*eventTime*/, pointerCount,
+ pointerProperties, pointerCoords);
+ return event;
+}
+
+TEST(VerifiedKeyEventTest, ConvertKeyEventToVerifiedKeyEvent) {
+ KeyEvent event = getKeyEventWithFlags(0);
+ VerifiedKeyEvent verified = verifiedKeyEventFromKeyEvent(event);
+
+ ASSERT_EQ(VerifiedInputEvent::Type::KEY, verified.type);
+
+ ASSERT_EQ(event.getDeviceId(), verified.deviceId);
+ ASSERT_EQ(event.getEventTime(), verified.eventTimeNanos);
+ ASSERT_EQ(event.getSource(), verified.source);
+ ASSERT_EQ(event.getDisplayId(), verified.displayId);
+
+ ASSERT_EQ(event.getAction(), verified.action);
+ ASSERT_EQ(event.getDownTime(), verified.downTimeNanos);
+ ASSERT_EQ(event.getFlags() & VERIFIED_KEY_EVENT_FLAGS, verified.flags);
+ ASSERT_EQ(event.getKeyCode(), verified.keyCode);
+ ASSERT_EQ(event.getScanCode(), verified.scanCode);
+ ASSERT_EQ(event.getMetaState(), verified.metaState);
+ ASSERT_EQ(event.getRepeatCount(), verified.repeatCount);
+}
+
+TEST(VerifiedKeyEventTest, VerifiedKeyEventContainsOnlyVerifiedFlags) {
+ KeyEvent event = getKeyEventWithFlags(AKEY_EVENT_FLAG_CANCELED | AKEY_EVENT_FLAG_FALLBACK);
+ VerifiedKeyEvent verified = verifiedKeyEventFromKeyEvent(event);
+ ASSERT_EQ(AKEY_EVENT_FLAG_CANCELED, verified.flags);
+}
+
+TEST(VerifiedKeyEventTest, VerifiedKeyEventDoesNotContainUnverifiedFlags) {
+ KeyEvent event = getKeyEventWithFlags(AKEY_EVENT_FLAG_EDITOR_ACTION);
+ VerifiedKeyEvent verified = verifiedKeyEventFromKeyEvent(event);
+ ASSERT_EQ(0, verified.flags);
+}
+
+TEST(VerifiedMotionEventTest, ConvertMotionEventToVerifiedMotionEvent) {
+ MotionEvent event = getMotionEventWithFlags(0);
+ VerifiedMotionEvent verified = verifiedMotionEventFromMotionEvent(event);
+
+ ASSERT_EQ(VerifiedInputEvent::Type::MOTION, verified.type);
+
+ ASSERT_EQ(event.getDeviceId(), verified.deviceId);
+ ASSERT_EQ(event.getEventTime(), verified.eventTimeNanos);
+ ASSERT_EQ(event.getSource(), verified.source);
+ ASSERT_EQ(event.getDisplayId(), verified.displayId);
+
+ ASSERT_EQ(event.getRawX(0), verified.rawX);
+ ASSERT_EQ(event.getRawY(0), verified.rawY);
+ ASSERT_EQ(event.getAction(), verified.actionMasked);
+ ASSERT_EQ(event.getDownTime(), verified.downTimeNanos);
+ ASSERT_EQ(event.getFlags() & VERIFIED_MOTION_EVENT_FLAGS, verified.flags);
+ ASSERT_EQ(event.getMetaState(), verified.metaState);
+ ASSERT_EQ(event.getButtonState(), verified.buttonState);
+}
+
+TEST(VerifiedMotionEventTest, VerifiedMotionEventContainsOnlyVerifiedFlags) {
+ MotionEvent event = getMotionEventWithFlags(AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED |
+ AMOTION_EVENT_FLAG_IS_GENERATED_GESTURE);
+ VerifiedMotionEvent verified = verifiedMotionEventFromMotionEvent(event);
+ ASSERT_EQ(AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED, verified.flags);
+}
+
+TEST(VerifiedMotionEventTest, VerifiedMotionEventDoesNotContainUnverifiedFlags) {
+ MotionEvent event = getMotionEventWithFlags(AMOTION_EVENT_FLAG_TAINTED);
+ VerifiedMotionEvent verified = verifiedMotionEventFromMotionEvent(event);
+ ASSERT_EQ(0, verified.flags);
+}
+
+} // namespace android
diff --git a/libs/renderengine/gl/GLESRenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp
index e523836..e11b59f 100644
--- a/libs/renderengine/gl/GLESRenderEngine.cpp
+++ b/libs/renderengine/gl/GLESRenderEngine.cpp
@@ -984,18 +984,19 @@
}
std::unique_ptr<BindNativeBufferAsFramebuffer> fbo;
- // Let's find the topmost layer requesting background blur (if any.)
- // Blurs in multiple layers are not supported, given the cost of the shader.
- const LayerSettings* blurLayer = nullptr;
+ // Gathering layers that requested blur, we'll need them to decide when to render to an
+ // offscreen buffer, and when to render to the native buffer.
+ std::deque<const LayerSettings*> blurLayers;
if (CC_LIKELY(mBlurFilter != nullptr)) {
- for (auto const layer : layers) {
+ for (auto layer : layers) {
if (layer->backgroundBlurRadius > 0) {
- blurLayer = layer;
+ blurLayers.push_back(layer);
}
}
}
+ const auto blurLayersSize = blurLayers.size();
- if (blurLayer == nullptr) {
+ if (blurLayersSize == 0) {
fbo = std::make_unique<BindNativeBufferAsFramebuffer>(*this, buffer, useFramebufferCache);
if (fbo->getStatus() != NO_ERROR) {
ALOGE("Failed to bind framebuffer! Aborting GPU composition for buffer (%p).",
@@ -1006,7 +1007,8 @@
setViewportAndProjection(display.physicalDisplay, display.clip);
} else {
setViewportAndProjection(display.physicalDisplay, display.clip);
- auto status = mBlurFilter->setAsDrawTarget(display, blurLayer->backgroundBlurRadius);
+ auto status =
+ mBlurFilter->setAsDrawTarget(display, blurLayers.front()->backgroundBlurRadius);
if (status != NO_ERROR) {
ALOGE("Failed to prepare blur filter! Aborting GPU composition for buffer (%p).",
buffer->handle);
@@ -1039,7 +1041,9 @@
.setCropCoords(2 /* size */)
.build();
for (auto const layer : layers) {
- if (blurLayer == layer) {
+ if (blurLayers.size() > 0 && blurLayers.front() == layer) {
+ blurLayers.pop_front();
+
auto status = mBlurFilter->prepare();
if (status != NO_ERROR) {
ALOGE("Failed to render blur effect! Aborting GPU composition for buffer (%p).",
@@ -1048,18 +1052,26 @@
return status;
}
- fbo = std::make_unique<BindNativeBufferAsFramebuffer>(*this, buffer,
- useFramebufferCache);
- status = fbo->getStatus();
+ if (blurLayers.size() == 0) {
+ // Done blurring, time to bind the native FBO and render our blur onto it.
+ fbo = std::make_unique<BindNativeBufferAsFramebuffer>(*this, buffer,
+ useFramebufferCache);
+ status = fbo->getStatus();
+ setViewportAndProjection(display.physicalDisplay, display.clip);
+ } else {
+ // There's still something else to blur, so let's keep rendering to our FBO
+ // instead of to the display.
+ status = mBlurFilter->setAsDrawTarget(display,
+ blurLayers.front()->backgroundBlurRadius);
+ }
if (status != NO_ERROR) {
ALOGE("Failed to bind framebuffer! Aborting GPU composition for buffer (%p).",
buffer->handle);
checkErrors("Can't bind native framebuffer");
return status;
}
- setViewportAndProjection(display.physicalDisplay, display.clip);
- status = mBlurFilter->render();
+ status = mBlurFilter->render(blurLayersSize > 1);
if (status != NO_ERROR) {
ALOGE("Failed to render blur effect! Aborting GPU composition for buffer (%p).",
buffer->handle);
diff --git a/libs/renderengine/gl/filters/BlurFilter.cpp b/libs/renderengine/gl/filters/BlurFilter.cpp
index f8b0a7a..b1a84bd 100644
--- a/libs/renderengine/gl/filters/BlurFilter.cpp
+++ b/libs/renderengine/gl/filters/BlurFilter.cpp
@@ -96,13 +96,17 @@
mEngine.checkErrors("Drawing blur mesh");
}
-status_t BlurFilter::render() {
+status_t BlurFilter::render(bool multiPass) {
ATRACE_NAME("BlurFilter::render");
// Now let's scale our blur up. It will be interpolated with the larger composited
// texture for the first frames, to hide downscaling artifacts.
GLfloat mix = fmin(1.0, mRadius / kMaxCrossFadeRadius);
- if (mix >= 1) {
+
+ // When doing multiple passes, we cannot try to read mCompositionFbo, given that we'll
+ // be writing onto it. Let's disable the crossfade, otherwise we'd need 1 extra frame buffer,
+ // as large as the screen size.
+ if (mix >= 1 || multiPass) {
mBlurredFbo.bindAsReadBuffer();
glBlitFramebuffer(0, 0, mBlurredFbo.getBufferWidth(), mBlurredFbo.getBufferHeight(), 0, 0,
mDisplayWidth, mDisplayHeight, GL_COLOR_BUFFER_BIT, GL_LINEAR);
diff --git a/libs/renderengine/gl/filters/BlurFilter.h b/libs/renderengine/gl/filters/BlurFilter.h
index 67b3895..52dc8aa 100644
--- a/libs/renderengine/gl/filters/BlurFilter.h
+++ b/libs/renderengine/gl/filters/BlurFilter.h
@@ -45,7 +45,7 @@
// Execute blur passes, rendering to offscreen texture.
virtual status_t prepare() = 0;
// Render blur to the bound framebuffer (screen).
- status_t render();
+ status_t render(bool multiPass);
protected:
uint32_t mRadius;
diff --git a/libs/ui/Region.cpp b/libs/ui/Region.cpp
index bf487c4..cd2a448 100644
--- a/libs/ui/Region.cpp
+++ b/libs/ui/Region.cpp
@@ -67,19 +67,20 @@
// ----------------------------------------------------------------------------
Region::Region() {
- mStorage.add(Rect(0,0));
+ mStorage.push_back(Rect(0, 0));
}
Region::Region(const Region& rhs)
- : mStorage(rhs.mStorage)
{
+ mStorage.clear();
+ mStorage.insert(mStorage.begin(), rhs.mStorage.begin(), rhs.mStorage.end());
#if defined(VALIDATE_REGIONS)
validate(rhs, "rhs copy-ctor");
#endif
}
Region::Region(const Rect& rhs) {
- mStorage.add(rhs);
+ mStorage.push_back(rhs);
}
Region::~Region()
@@ -100,8 +101,8 @@
* final, correctly ordered region buffer. Each rectangle will be compared with the span directly
* above it, and subdivided to resolve any remaining T-junctions.
*/
-static void reverseRectsResolvingJunctions(const Rect* begin, const Rect* end,
- Vector<Rect>& dst, int spanDirection) {
+static void reverseRectsResolvingJunctions(const Rect* begin, const Rect* end, FatVector<Rect>& dst,
+ int spanDirection) {
dst.clear();
const Rect* current = end - 1;
@@ -109,7 +110,7 @@
// add first span immediately
do {
- dst.add(*current);
+ dst.push_back(*current);
current--;
} while (current->top == lastTop && current >= begin);
@@ -147,12 +148,12 @@
if (prev.right <= left) break;
if (prev.right > left && prev.right < right) {
- dst.add(Rect(prev.right, top, right, bottom));
+ dst.push_back(Rect(prev.right, top, right, bottom));
right = prev.right;
}
if (prev.left > left && prev.left < right) {
- dst.add(Rect(prev.left, top, right, bottom));
+ dst.push_back(Rect(prev.left, top, right, bottom));
right = prev.left;
}
@@ -166,12 +167,12 @@
if (prev.left >= right) break;
if (prev.left > left && prev.left < right) {
- dst.add(Rect(left, top, prev.left, bottom));
+ dst.push_back(Rect(left, top, prev.left, bottom));
left = prev.left;
}
if (prev.right > left && prev.right < right) {
- dst.add(Rect(left, top, prev.right, bottom));
+ dst.push_back(Rect(left, top, prev.right, bottom));
left = prev.right;
}
// if an entry in the previous span is too far left, nothing further right in the
@@ -183,7 +184,7 @@
}
if (left < right) {
- dst.add(Rect(left, top, right, bottom));
+ dst.push_back(Rect(left, top, right, bottom));
}
current--;
@@ -201,13 +202,14 @@
if (r.isEmpty()) return r;
if (r.isRect()) return r;
- Vector<Rect> reversed;
+ FatVector<Rect> reversed;
reverseRectsResolvingJunctions(r.begin(), r.end(), reversed, direction_RTL);
Region outputRegion;
- reverseRectsResolvingJunctions(reversed.begin(), reversed.end(),
- outputRegion.mStorage, direction_LTR);
- outputRegion.mStorage.add(r.getBounds()); // to make region valid, mStorage must end with bounds
+ reverseRectsResolvingJunctions(reversed.data(), reversed.data() + reversed.size(),
+ outputRegion.mStorage, direction_LTR);
+ outputRegion.mStorage.push_back(
+ r.getBounds()); // to make region valid, mStorage must end with bounds
#if defined(VALIDATE_REGIONS)
validate(outputRegion, "T-Junction free region");
@@ -222,7 +224,8 @@
validate(*this, "this->operator=");
validate(rhs, "rhs.operator=");
#endif
- mStorage = rhs.mStorage;
+ mStorage.clear();
+ mStorage.insert(mStorage.begin(), rhs.mStorage.begin(), rhs.mStorage.end());
return *this;
}
@@ -231,7 +234,7 @@
if (mStorage.size() >= 2) {
const Rect bounds(getBounds());
mStorage.clear();
- mStorage.add(bounds);
+ mStorage.push_back(bounds);
}
return *this;
}
@@ -255,25 +258,25 @@
void Region::clear()
{
mStorage.clear();
- mStorage.add(Rect(0,0));
+ mStorage.push_back(Rect(0, 0));
}
void Region::set(const Rect& r)
{
mStorage.clear();
- mStorage.add(r);
+ mStorage.push_back(r);
}
void Region::set(int32_t w, int32_t h)
{
mStorage.clear();
- mStorage.add(Rect(w, h));
+ mStorage.push_back(Rect(w, h));
}
void Region::set(uint32_t w, uint32_t h)
{
mStorage.clear();
- mStorage.add(Rect(w, h));
+ mStorage.push_back(Rect(w, h));
}
bool Region::isTriviallyEqual(const Region& region) const {
@@ -299,8 +302,7 @@
void Region::addRectUnchecked(int l, int t, int r, int b)
{
Rect rect(l,t,r,b);
- size_t where = mStorage.size() - 1;
- mStorage.insertAt(rect, where, 1);
+ mStorage.insert(mStorage.end() - 1, rect);
}
// ----------------------------------------------------------------------------
@@ -350,7 +352,7 @@
Region& Region::scaleSelf(float sx, float sy) {
size_t count = mStorage.size();
- Rect* rects = mStorage.editArray();
+ Rect* rects = mStorage.data();
while (count) {
rects->left = static_cast<int32_t>(static_cast<float>(rects->left) * sx + 0.5f);
rects->right = static_cast<int32_t>(static_cast<float>(rects->right) * sx + 0.5f);
@@ -455,10 +457,10 @@
class Region::rasterizer : public region_operator<Rect>::region_rasterizer
{
Rect bounds;
- Vector<Rect>& storage;
+ FatVector<Rect>& storage;
Rect* head;
Rect* tail;
- Vector<Rect> span;
+ FatVector<Rect> span;
Rect* cur;
public:
explicit rasterizer(Region& reg)
@@ -485,8 +487,8 @@
flushSpan();
}
if (storage.size()) {
- bounds.top = storage.itemAt(0).top;
- bounds.bottom = storage.top().bottom;
+ bounds.top = storage.front().top;
+ bounds.bottom = storage.back().bottom;
if (storage.size() == 1) {
storage.clear();
}
@@ -494,7 +496,7 @@
bounds.left = 0;
bounds.right = 0;
}
- storage.add(bounds);
+ storage.push_back(bounds);
}
void Region::rasterizer::operator()(const Rect& rect)
@@ -509,15 +511,15 @@
return;
}
}
- span.add(rect);
- cur = span.editArray() + (span.size() - 1);
+ span.push_back(rect);
+ cur = span.data() + (span.size() - 1);
}
void Region::rasterizer::flushSpan()
{
bool merge = false;
if (tail-head == ssize_t(span.size())) {
- Rect const* p = span.editArray();
+ Rect const* p = span.data();
Rect const* q = head;
if (p->top == q->bottom) {
merge = true;
@@ -532,17 +534,17 @@
}
}
if (merge) {
- const int bottom = span[0].bottom;
+ const int bottom = span.front().bottom;
Rect* r = head;
while (r != tail) {
r->bottom = bottom;
r++;
}
} else {
- bounds.left = min(span.itemAt(0).left, bounds.left);
- bounds.right = max(span.top().right, bounds.right);
- storage.appendVector(span);
- tail = storage.editArray() + storage.size();
+ bounds.left = min(span.front().left, bounds.left);
+ bounds.right = max(span.back().right, bounds.right);
+ storage.insert(storage.end(), span.begin(), span.end());
+ tail = storage.data() + storage.size();
head = tail - span.size();
}
span.clear();
@@ -550,7 +552,7 @@
bool Region::validate(const Region& reg, const char* name, bool silent)
{
- if (reg.mStorage.isEmpty()) {
+ if (reg.mStorage.empty()) {
ALOGE_IF(!silent, "%s: mStorage is empty, which is never valid", name);
// return immediately as the code below assumes mStorage is non-empty
return false;
@@ -689,9 +691,8 @@
}
sk_dst.op(sk_lhs, sk_rhs, sk_op);
- if (sk_dst.isEmpty() && dst.isEmpty())
- return;
-
+ if (sk_dst.empty() && dst.empty()) return;
+
bool same = true;
Region::const_iterator head = dst.begin();
Region::const_iterator const tail = dst.end();
@@ -786,7 +787,7 @@
validate(reg, "translate (before)");
#endif
size_t count = reg.mStorage.size();
- Rect* rects = reg.mStorage.editArray();
+ Rect* rects = reg.mStorage.data();
while (count) {
rects->offsetBy(dx, dy);
rects++;
@@ -866,24 +867,25 @@
ALOGE("Region::unflatten() failed, invalid region");
return BAD_VALUE;
}
- mStorage = result.mStorage;
+ mStorage.clear();
+ mStorage.insert(mStorage.begin(), result.mStorage.begin(), result.mStorage.end());
return NO_ERROR;
}
// ----------------------------------------------------------------------------
Region::const_iterator Region::begin() const {
- return mStorage.array();
+ return mStorage.data();
}
Region::const_iterator Region::end() const {
// Workaround for b/77643177
// mStorage should never be empty, but somehow it is and it's causing
// an abort in ubsan
- if (mStorage.isEmpty()) return mStorage.array();
+ if (mStorage.empty()) return mStorage.data();
size_t numRects = isRect() ? 1 : mStorage.size() - 1;
- return mStorage.array() + numRects;
+ return mStorage.data() + numRects;
}
Rect const* Region::getArray(size_t* count) const {
diff --git a/libs/ui/include/ui/FatVector.h b/libs/ui/include/ui/FatVector.h
new file mode 100644
index 0000000..25fe3a0
--- /dev/null
+++ b/libs/ui/include/ui/FatVector.h
@@ -0,0 +1,93 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_REGION_FAT_VECTOR_H
+#define ANDROID_REGION_FAT_VECTOR_H
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <utils/Log.h>
+#include <type_traits>
+
+#include <vector>
+
+namespace android {
+
+template <typename T, size_t SIZE = 4>
+class InlineStdAllocator {
+public:
+ struct Allocation {
+ private:
+ Allocation(const Allocation&) = delete;
+ void operator=(const Allocation&) = delete;
+
+ public:
+ Allocation() {}
+ // char array instead of T array, so memory is uninitialized, with no destructors run
+ char array[sizeof(T) * SIZE];
+ bool inUse = false;
+ };
+
+ typedef T value_type; // needed to implement std::allocator
+ typedef T* pointer; // needed to implement std::allocator
+
+ explicit InlineStdAllocator(Allocation& allocation) : mAllocation(allocation) {}
+ InlineStdAllocator(const InlineStdAllocator& other) : mAllocation(other.mAllocation) {}
+ ~InlineStdAllocator() {}
+
+ T* allocate(size_t num, const void* = 0) {
+ if (!mAllocation.inUse && num <= SIZE) {
+ mAllocation.inUse = true;
+ return static_cast<T*>(static_cast<void*>(mAllocation.array));
+ } else {
+ return static_cast<T*>(static_cast<void*>(malloc(num * sizeof(T))));
+ }
+ }
+
+ void deallocate(pointer p, size_t) {
+ if (p == static_cast<T*>(static_cast<void*>(mAllocation.array))) {
+ mAllocation.inUse = false;
+ } else {
+ // 'free' instead of delete here - destruction handled separately
+ free(p);
+ }
+ }
+ Allocation& mAllocation;
+};
+
+/**
+ * std::vector with SIZE elements preallocated into an internal buffer.
+ *
+ * Useful for avoiding the cost of malloc in cases where only SIZE or
+ * fewer elements are needed in the common case.
+ */
+template <typename T, size_t SIZE = 4>
+class FatVector : public std::vector<T, InlineStdAllocator<T, SIZE>> {
+public:
+ FatVector()
+ : std::vector<T, InlineStdAllocator<T, SIZE>>(InlineStdAllocator<T, SIZE>(mAllocation)) {
+ this->reserve(SIZE);
+ }
+
+ explicit FatVector(size_t capacity) : FatVector() { this->resize(capacity); }
+
+private:
+ typename InlineStdAllocator<T, SIZE>::Allocation mAllocation;
+};
+
+} // namespace android
+
+#endif // ANDROID_REGION_FAT_VECTOR_H
diff --git a/libs/ui/include/ui/Region.h b/libs/ui/include/ui/Region.h
index 2db3b10..6bb7b8d 100644
--- a/libs/ui/include/ui/Region.h
+++ b/libs/ui/include/ui/Region.h
@@ -21,13 +21,13 @@
#include <sys/types.h>
#include <ostream>
-#include <utils/Vector.h>
-
#include <ui/Rect.h>
#include <utils/Flattenable.h>
#include <android-base/macros.h>
+#include "FatVector.h"
+
#include <string>
namespace android {
@@ -180,7 +180,7 @@
// with an extra Rect as the last element which is set to the
// bounds of the region. However, if the region is
// a simple Rect then mStorage contains only that rect.
- Vector<Rect> mStorage;
+ FatVector<Rect> mStorage;
};
@@ -235,4 +235,3 @@
}; // namespace android
#endif // ANDROID_UI_REGION_H
-
diff --git a/libs/ui/include_vndk/ui/FatVector.h b/libs/ui/include_vndk/ui/FatVector.h
new file mode 120000
index 0000000..bf30166
--- /dev/null
+++ b/libs/ui/include_vndk/ui/FatVector.h
@@ -0,0 +1 @@
+../../include/ui/FatVector.h
\ No newline at end of file
diff --git a/services/inputflinger/Android.bp b/services/inputflinger/Android.bp
index 308e93a..5c80d55 100644
--- a/services/inputflinger/Android.bp
+++ b/services/inputflinger/Android.bp
@@ -40,6 +40,7 @@
"libinputreporter",
"libinputreader",
"libbinder",
+ "libcrypto",
"libcutils",
"libhidlbase",
"libinput",
diff --git a/services/inputflinger/dispatcher/Android.bp b/services/inputflinger/dispatcher/Android.bp
index a556aad..3f956a8 100644
--- a/services/inputflinger/dispatcher/Android.bp
+++ b/services/inputflinger/dispatcher/Android.bp
@@ -28,6 +28,7 @@
],
shared_libs: [
"libbase",
+ "libcrypto",
"libcutils",
"libinput",
"libinputreporter",
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index f2b95e7..75bc0aa 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -60,7 +60,10 @@
#include <android-base/chrono_utils.h>
#include <android-base/stringprintf.h>
#include <binder/Binder.h>
+#include <input/InputDevice.h>
#include <log/log.h>
+#include <openssl/hmac.h>
+#include <openssl/rand.h>
#include <powermanager/PowerManager.h>
#include <utils/Trace.h>
@@ -325,6 +328,55 @@
return dispatchEntry;
}
+static std::array<uint8_t, 128> getRandomKey() {
+ std::array<uint8_t, 128> key;
+ if (RAND_bytes(key.data(), key.size()) != 1) {
+ LOG_ALWAYS_FATAL("Can't generate HMAC key");
+ }
+ return key;
+}
+
+// --- HmacKeyManager ---
+
+HmacKeyManager::HmacKeyManager() : mHmacKey(getRandomKey()) {}
+
+std::array<uint8_t, 32> HmacKeyManager::sign(const VerifiedInputEvent& event) const {
+ size_t size;
+ switch (event.type) {
+ case VerifiedInputEvent::Type::KEY: {
+ size = sizeof(VerifiedKeyEvent);
+ break;
+ }
+ case VerifiedInputEvent::Type::MOTION: {
+ size = sizeof(VerifiedMotionEvent);
+ break;
+ }
+ }
+ std::vector<uint8_t> data;
+ const uint8_t* start = reinterpret_cast<const uint8_t*>(&event);
+ data.assign(start, start + size);
+ return sign(data);
+}
+
+std::array<uint8_t, 32> HmacKeyManager::sign(const std::vector<uint8_t>& data) const {
+ // SHA256 always generates 32-bytes result
+ std::array<uint8_t, 32> hash;
+ unsigned int hashLen = 0;
+ uint8_t* result = HMAC(EVP_sha256(), mHmacKey.data(), mHmacKey.size(), data.data(), data.size(),
+ hash.data(), &hashLen);
+ if (result == nullptr) {
+ ALOGE("Could not sign the data using HMAC");
+ return INVALID_HMAC;
+ }
+
+ if (hashLen != hash.size()) {
+ ALOGE("HMAC-SHA256 has unexpected length");
+ return INVALID_HMAC;
+ }
+
+ return hash;
+}
+
// --- InputDispatcher ---
InputDispatcher::InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy)
@@ -3153,22 +3205,22 @@
std::queue<EventEntry*> injectedEntries;
switch (event->getType()) {
case AINPUT_EVENT_TYPE_KEY: {
- KeyEvent keyEvent;
- keyEvent.initialize(*static_cast<const KeyEvent*>(event));
- int32_t action = keyEvent.getAction();
+ const KeyEvent& incomingKey = static_cast<const KeyEvent&>(*event);
+ int32_t action = incomingKey.getAction();
if (!validateKeyEvent(action)) {
return INPUT_EVENT_INJECTION_FAILED;
}
- int32_t flags = keyEvent.getFlags();
- int32_t keyCode = keyEvent.getKeyCode();
- int32_t metaState = keyEvent.getMetaState();
- accelerateMetaShortcuts(keyEvent.getDeviceId(), action,
+ int32_t flags = incomingKey.getFlags();
+ int32_t keyCode = incomingKey.getKeyCode();
+ int32_t metaState = incomingKey.getMetaState();
+ accelerateMetaShortcuts(VIRTUAL_KEYBOARD_ID, action,
/*byref*/ keyCode, /*byref*/ metaState);
- keyEvent.initialize(keyEvent.getDeviceId(), keyEvent.getSource(),
- keyEvent.getDisplayId(), INVALID_HMAC, action, flags, keyCode,
- keyEvent.getScanCode(), metaState, keyEvent.getRepeatCount(),
- keyEvent.getDownTime(), keyEvent.getEventTime());
+ KeyEvent keyEvent;
+ keyEvent.initialize(VIRTUAL_KEYBOARD_ID, incomingKey.getSource(),
+ incomingKey.getDisplayId(), INVALID_HMAC, action, flags, keyCode,
+ incomingKey.getScanCode(), metaState, incomingKey.getRepeatCount(),
+ incomingKey.getDownTime(), incomingKey.getEventTime());
if (flags & AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY) {
policyFlags |= POLICY_FLAG_VIRTUAL;
@@ -3186,11 +3238,10 @@
mLock.lock();
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());
+ VIRTUAL_KEYBOARD_ID, keyEvent.getSource(), keyEvent.getDisplayId(),
+ policyFlags, action, flags, keyEvent.getKeyCode(),
+ keyEvent.getScanCode(), keyEvent.getMetaState(),
+ keyEvent.getRepeatCount(), keyEvent.getDownTime());
injectedEntries.push(injectedEntry);
break;
}
@@ -3221,7 +3272,7 @@
const PointerCoords* samplePointerCoords = motionEvent->getSamplePointerCoords();
MotionEntry* injectedEntry =
new MotionEntry(SYNTHESIZED_EVENT_SEQUENCE_NUM, *sampleEventTimes,
- motionEvent->getDeviceId(), motionEvent->getSource(),
+ VIRTUAL_KEYBOARD_ID, motionEvent->getSource(),
motionEvent->getDisplayId(), policyFlags, action, actionButton,
motionEvent->getFlags(), motionEvent->getMetaState(),
motionEvent->getButtonState(), motionEvent->getClassification(),
@@ -3238,7 +3289,7 @@
samplePointerCoords += pointerCount;
MotionEntry* nextInjectedEntry =
new MotionEntry(SYNTHESIZED_EVENT_SEQUENCE_NUM, *sampleEventTimes,
- motionEvent->getDeviceId(), motionEvent->getSource(),
+ VIRTUAL_KEYBOARD_ID, motionEvent->getSource(),
motionEvent->getDisplayId(), policyFlags, action,
actionButton, motionEvent->getFlags(),
motionEvent->getMetaState(), motionEvent->getButtonState(),
@@ -3340,6 +3391,10 @@
return injectionResult;
}
+std::unique_ptr<VerifiedInputEvent> InputDispatcher::verifyInputEvent(const InputEvent& event) {
+ return nullptr;
+}
+
bool InputDispatcher::hasInjectionPermission(int32_t injectorPid, int32_t injectorUid) {
return injectorUid == 0 ||
mPolicy->checkInjectEventsPermissionNonReentrant(injectorPid, injectorUid);
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index d2aea80..ded59a5 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -56,6 +56,16 @@
class Connection;
+class HmacKeyManager {
+public:
+ HmacKeyManager();
+ std::array<uint8_t, 32> sign(const VerifiedInputEvent& event) const;
+
+private:
+ std::array<uint8_t, 32> sign(const std::vector<uint8_t>& data) const;
+ const std::array<uint8_t, 128> mHmacKey;
+};
+
/* Dispatches events to input targets. Some functions of the input dispatcher, such as
* identifying input targets, are controlled by a separate policy object.
*
@@ -96,6 +106,8 @@
int32_t injectorUid, int32_t syncMode, int32_t timeoutMillis,
uint32_t policyFlags) override;
+ virtual std::unique_ptr<VerifiedInputEvent> verifyInputEvent(const InputEvent& event) override;
+
virtual void setInputWindows(
const std::vector<sp<InputWindowHandle>>& inputWindowHandles, int32_t displayId,
const sp<ISetInputWindowsListener>& setInputWindowsListener = nullptr) override;
diff --git a/services/inputflinger/dispatcher/include/InputDispatcherInterface.h b/services/inputflinger/dispatcher/include/InputDispatcherInterface.h
index 3424f4c..6e98676 100644
--- a/services/inputflinger/dispatcher/include/InputDispatcherInterface.h
+++ b/services/inputflinger/dispatcher/include/InputDispatcherInterface.h
@@ -92,6 +92,13 @@
int32_t injectorUid, int32_t syncMode, int32_t timeoutMillis,
uint32_t policyFlags) = 0;
+ /*
+ * Check whether InputEvent actually happened by checking the signature of the event.
+ *
+ * Return nullptr if the event cannot be verified.
+ */
+ virtual std::unique_ptr<VerifiedInputEvent> verifyInputEvent(const InputEvent& event) = 0;
+
/* Sets the list of input windows.
*
* This method may be called on any thread (usually by the input manager).
diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.cpp b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
index b66caca..3b20173 100644
--- a/services/inputflinger/reader/mapper/TouchInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
@@ -761,7 +761,11 @@
(mDeviceMode == DEVICE_MODE_DIRECT && mConfig.showTouches)) {
if (mPointerController == nullptr || viewportChanged) {
mPointerController = getPolicy()->obtainPointerController(getDeviceId());
- mPointerController->setDisplayViewport(mViewport);
+ // Set the DisplayViewport for the PointerController to the default pointer display
+ // that is recommended by the configuration before using it.
+ std::optional<DisplayViewport> defaultViewport =
+ mConfig.getDisplayViewportById(mConfig.defaultPointerDisplayId);
+ mPointerController->setDisplayViewport(defaultViewport.value_or(mViewport));
}
} else {
mPointerController.clear();
diff --git a/services/inputflinger/tests/Android.bp b/services/inputflinger/tests/Android.bp
index 09ecb13..f913d82 100644
--- a/services/inputflinger/tests/Android.bp
+++ b/services/inputflinger/tests/Android.bp
@@ -10,6 +10,7 @@
"InputClassifierConverter_test.cpp",
"InputDispatcher_test.cpp",
"InputReader_test.cpp",
+ "UinputDevice.cpp",
],
cflags: [
"-Wall",
diff --git a/services/inputflinger/tests/EventHub_test.cpp b/services/inputflinger/tests/EventHub_test.cpp
index 6504738..be2e19e 100644
--- a/services/inputflinger/tests/EventHub_test.cpp
+++ b/services/inputflinger/tests/EventHub_test.cpp
@@ -16,7 +16,8 @@
#include "EventHub.h"
-#include <android-base/stringprintf.h>
+#include "UinputDevice.h"
+
#include <gtest/gtest.h>
#include <inttypes.h>
#include <linux/uinput.h>
@@ -25,16 +26,16 @@
#define TAG "EventHub_test"
+using android::createUinputDevice;
using android::EventHub;
using android::EventHubInterface;
using android::InputDeviceIdentifier;
using android::RawEvent;
using android::sp;
-using android::base::StringPrintf;
+using android::UinputHomeKey;
using std::chrono_literals::operator""ms;
static constexpr bool DEBUG = false;
-static const char* DEVICE_NAME = "EventHub Test Device";
static void dumpEvents(const std::vector<RawEvent>& events) {
for (const RawEvent& event : events) {
@@ -62,27 +63,26 @@
protected:
std::unique_ptr<EventHubInterface> mEventHub;
// We are only going to emulate a single input device currently.
- android::base::unique_fd mDeviceFd;
+ std::unique_ptr<UinputHomeKey> mKeyboard;
int32_t mDeviceId;
+
virtual void SetUp() override {
mEventHub = std::make_unique<EventHub>();
consumeInitialDeviceAddedEvents();
- createDevice();
+ mKeyboard = createUinputDevice<UinputHomeKey>();
mDeviceId = waitForDeviceCreation();
}
virtual void TearDown() override {
- mDeviceFd.reset();
+ mKeyboard.reset();
waitForDeviceClose(mDeviceId);
}
- void createDevice();
/**
* Return the device id of the created device.
*/
int32_t waitForDeviceCreation();
void waitForDeviceClose(int32_t deviceId);
void consumeInitialDeviceAddedEvents();
- void sendEvent(uint16_t type, uint16_t code, int32_t value);
std::vector<RawEvent> getEvents(std::chrono::milliseconds timeout = 5ms);
};
@@ -105,48 +105,6 @@
return events;
}
-void EventHubTest::createDevice() {
- mDeviceFd = android::base::unique_fd(open("/dev/uinput", O_WRONLY | O_NONBLOCK));
- if (mDeviceFd < 0) {
- FAIL() << "Can't open /dev/uinput :" << strerror(errno);
- }
-
- /**
- * Signal which type of events this input device supports.
- * We will emulate a keyboard here.
- */
- // enable key press/release event
- if (ioctl(mDeviceFd, UI_SET_EVBIT, EV_KEY)) {
- ADD_FAILURE() << "Error in ioctl : UI_SET_EVBIT : EV_KEY: " << strerror(errno);
- }
-
- // enable set of KEY events
- if (ioctl(mDeviceFd, UI_SET_KEYBIT, KEY_HOME)) {
- ADD_FAILURE() << "Error in ioctl : UI_SET_KEYBIT : KEY_HOME: " << strerror(errno);
- }
-
- // enable synchronization event
- if (ioctl(mDeviceFd, UI_SET_EVBIT, EV_SYN)) {
- ADD_FAILURE() << "Error in ioctl : UI_SET_EVBIT : EV_SYN: " << strerror(errno);
- }
-
- struct uinput_user_dev keyboard = {};
- strlcpy(keyboard.name, DEVICE_NAME, UINPUT_MAX_NAME_SIZE);
- keyboard.id.bustype = BUS_USB;
- keyboard.id.vendor = 0x01;
- keyboard.id.product = 0x01;
- keyboard.id.version = 1;
-
- if (write(mDeviceFd, &keyboard, sizeof(keyboard)) < 0) {
- FAIL() << "Could not write uinput_user_dev struct into uinput file descriptor: "
- << strerror(errno);
- }
-
- if (ioctl(mDeviceFd, UI_DEV_CREATE)) {
- FAIL() << "Error in ioctl : UI_DEV_CREATE: " << strerror(errno);
- }
-}
-
/**
* Since the test runs on a real platform, there will be existing devices
* in addition to the test devices being added. Therefore, when EventHub is first created,
@@ -176,7 +134,7 @@
EXPECT_EQ(static_cast<int32_t>(EventHubInterface::DEVICE_ADDED), deviceAddedEvent.type);
InputDeviceIdentifier identifier = mEventHub->getDeviceIdentifier(deviceAddedEvent.deviceId);
const int32_t deviceId = deviceAddedEvent.deviceId;
- EXPECT_EQ(identifier.name, DEVICE_NAME);
+ EXPECT_EQ(identifier.name, mKeyboard->getName());
const RawEvent& finishedDeviceScanEvent = events[1];
EXPECT_EQ(static_cast<int32_t>(EventHubInterface::FINISHED_DEVICE_SCAN),
finishedDeviceScanEvent.type);
@@ -194,22 +152,6 @@
finishedDeviceScanEvent.type);
}
-void EventHubTest::sendEvent(uint16_t type, uint16_t code, int32_t value) {
- struct input_event event = {};
- event.type = type;
- event.code = code;
- event.value = value;
- event.time = {}; // uinput ignores the timestamp
-
- if (write(mDeviceFd, &event, sizeof(input_event)) < 0) {
- std::string msg = StringPrintf("Could not write event %" PRIu16 " %" PRIu16
- " with value %" PRId32 " : %s",
- type, code, value, strerror(errno));
- ALOGE("%s", msg.c_str());
- ADD_FAILURE() << msg.c_str();
- }
-}
-
/**
* Ensure that input_events are generated with monotonic clock.
* That means input_event should receive a timestamp that is in the future of the time
@@ -218,13 +160,7 @@
*/
TEST_F(EventHubTest, InputEvent_TimestampIsMonotonic) {
nsecs_t lastEventTime = systemTime(SYSTEM_TIME_MONOTONIC);
- // key press
- sendEvent(EV_KEY, KEY_HOME, 1);
- sendEvent(EV_SYN, SYN_REPORT, 0);
-
- // key release
- sendEvent(EV_KEY, KEY_HOME, 0);
- sendEvent(EV_SYN, SYN_REPORT, 0);
+ ASSERT_NO_FATAL_FAILURE(mKeyboard->pressAndReleaseHomeKey());
std::vector<RawEvent> events = getEvents();
ASSERT_EQ(4U, events.size()) << "Expected to receive 2 keys and 2 syncs, total of 4 events";
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index 27db8f5..c4092cd 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -43,6 +43,18 @@
float y;
};
+/**
+ * Return a DOWN key event with KEYCODE_A.
+ */
+static KeyEvent getTestKeyEvent() {
+ KeyEvent event;
+
+ event.initialize(DEVICE_ID, AINPUT_SOURCE_KEYBOARD, ADISPLAY_ID_NONE, INVALID_HMAC,
+ AKEY_EVENT_ACTION_DOWN, 0, AKEYCODE_A, KEY_A, AMETA_NONE, 0, ARBITRARY_TIME,
+ ARBITRARY_TIME);
+ return event;
+}
+
// --- FakeInputDispatcherPolicy ---
class FakeInputDispatcherPolicy : public InputDispatcherPolicyInterface {
@@ -197,6 +209,69 @@
}
};
+// --- HmacKeyManagerTest ---
+
+class HmacKeyManagerTest : public testing::Test {
+protected:
+ HmacKeyManager mHmacKeyManager;
+};
+
+/**
+ * Ensure that separate calls to sign the same data are generating the same key.
+ * We avoid asserting against INVALID_HMAC. Since the key is random, there is a non-zero chance
+ * that a specific key and data combination would produce INVALID_HMAC, which would cause flaky
+ * tests.
+ */
+TEST_F(HmacKeyManagerTest, GeneratedHmac_IsConsistent) {
+ KeyEvent event = getTestKeyEvent();
+ VerifiedKeyEvent verifiedEvent = verifiedKeyEventFromKeyEvent(event);
+
+ std::array<uint8_t, 32> hmac1 = mHmacKeyManager.sign(verifiedEvent);
+ std::array<uint8_t, 32> hmac2 = mHmacKeyManager.sign(verifiedEvent);
+ ASSERT_EQ(hmac1, hmac2);
+}
+
+/**
+ * Ensure that changes in VerifiedKeyEvent produce a different hmac.
+ */
+TEST_F(HmacKeyManagerTest, GeneratedHmac_ChangesWhenFieldsChange) {
+ KeyEvent event = getTestKeyEvent();
+ VerifiedKeyEvent verifiedEvent = verifiedKeyEventFromKeyEvent(event);
+ std::array<uint8_t, 32> initialHmac = mHmacKeyManager.sign(verifiedEvent);
+
+ verifiedEvent.deviceId += 1;
+ ASSERT_NE(initialHmac, mHmacKeyManager.sign(verifiedEvent));
+
+ verifiedEvent.source += 1;
+ ASSERT_NE(initialHmac, mHmacKeyManager.sign(verifiedEvent));
+
+ verifiedEvent.eventTimeNanos += 1;
+ ASSERT_NE(initialHmac, mHmacKeyManager.sign(verifiedEvent));
+
+ verifiedEvent.displayId += 1;
+ ASSERT_NE(initialHmac, mHmacKeyManager.sign(verifiedEvent));
+
+ verifiedEvent.action += 1;
+ ASSERT_NE(initialHmac, mHmacKeyManager.sign(verifiedEvent));
+
+ verifiedEvent.downTimeNanos += 1;
+ ASSERT_NE(initialHmac, mHmacKeyManager.sign(verifiedEvent));
+
+ verifiedEvent.flags += 1;
+ ASSERT_NE(initialHmac, mHmacKeyManager.sign(verifiedEvent));
+
+ verifiedEvent.keyCode += 1;
+ ASSERT_NE(initialHmac, mHmacKeyManager.sign(verifiedEvent));
+
+ verifiedEvent.scanCode += 1;
+ ASSERT_NE(initialHmac, mHmacKeyManager.sign(verifiedEvent));
+
+ verifiedEvent.metaState += 1;
+ ASSERT_NE(initialHmac, mHmacKeyManager.sign(verifiedEvent));
+
+ verifiedEvent.repeatCount += 1;
+ ASSERT_NE(initialHmac, mHmacKeyManager.sign(verifiedEvent));
+}
// --- InputDispatcherTest ---
diff --git a/services/inputflinger/tests/UinputDevice.cpp b/services/inputflinger/tests/UinputDevice.cpp
new file mode 100644
index 0000000..2775d21
--- /dev/null
+++ b/services/inputflinger/tests/UinputDevice.cpp
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2020 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 "UinputDevice.h"
+
+#include <android-base/stringprintf.h>
+
+namespace android {
+
+// --- UinputDevice ---
+
+UinputDevice::UinputDevice(const char* name) : mName(name) {}
+
+UinputDevice::~UinputDevice() {
+ if (ioctl(mDeviceFd, UI_DEV_DESTROY)) {
+ ALOGE("Error while destroying uinput device: %s", strerror(errno));
+ }
+ mDeviceFd.reset();
+}
+
+void UinputDevice::init() {
+ mDeviceFd = android::base::unique_fd(open("/dev/uinput", O_WRONLY | O_NONBLOCK));
+ if (mDeviceFd < 0) {
+ FAIL() << "Can't open /dev/uinput :" << strerror(errno);
+ }
+
+ struct uinput_user_dev device = {};
+ strlcpy(device.name, mName, UINPUT_MAX_NAME_SIZE);
+ device.id.bustype = BUS_USB;
+ device.id.vendor = 0x01;
+ device.id.product = 0x01;
+ device.id.version = 1;
+
+ // Using EXPECT instead of ASSERT to allow the device creation to continue even when
+ // some failures are reported when configuring the device.
+ EXPECT_NO_FATAL_FAILURE(configureDevice(mDeviceFd, &device));
+
+ if (write(mDeviceFd, &device, sizeof(device)) < 0) {
+ FAIL() << "Could not write uinput_user_dev struct into uinput file descriptor: "
+ << strerror(errno);
+ }
+
+ if (ioctl(mDeviceFd, UI_DEV_CREATE)) {
+ FAIL() << "Error in ioctl : UI_DEV_CREATE: " << strerror(errno);
+ }
+}
+
+void UinputDevice::injectEvent(uint16_t type, uint16_t code, int32_t value) {
+ struct input_event event = {};
+ event.type = type;
+ event.code = code;
+ event.value = value;
+ event.time = {}; // uinput ignores the timestamp
+
+ if (write(mDeviceFd, &event, sizeof(input_event)) < 0) {
+ std::string msg = base::StringPrintf("Could not write event %" PRIu16 " %" PRIu16
+ " with value %" PRId32 " : %s",
+ type, code, value, strerror(errno));
+ ALOGE("%s", msg.c_str());
+ ADD_FAILURE() << msg.c_str();
+ }
+}
+
+// --- UinputKeyboard ---
+
+UinputKeyboard::UinputKeyboard(std::initializer_list<int> keys)
+ : UinputDevice(UinputKeyboard::KEYBOARD_NAME), mKeys(keys.begin(), keys.end()) {}
+
+void UinputKeyboard::configureDevice(int fd, uinput_user_dev* device) {
+ // enable key press/release event
+ if (ioctl(fd, UI_SET_EVBIT, EV_KEY)) {
+ ADD_FAILURE() << "Error in ioctl : UI_SET_EVBIT : EV_KEY: " << strerror(errno);
+ }
+
+ // enable set of KEY events
+ std::for_each(mKeys.begin(), mKeys.end(), [fd](int key) {
+ if (ioctl(fd, UI_SET_KEYBIT, key)) {
+ ADD_FAILURE() << "Error in ioctl : UI_SET_KEYBIT : " << key << " : " << strerror(errno);
+ }
+ });
+
+ // enable synchronization event
+ if (ioctl(fd, UI_SET_EVBIT, EV_SYN)) {
+ ADD_FAILURE() << "Error in ioctl : UI_SET_EVBIT : EV_SYN: " << strerror(errno);
+ }
+}
+
+void UinputKeyboard::pressKey(int key) {
+ if (mKeys.find(key) == mKeys.end()) {
+ ADD_FAILURE() << mName << ": Cannot inject key press: Key not found: " << key;
+ }
+ EXPECT_NO_FATAL_FAILURE(injectEvent(EV_KEY, key, 1));
+ EXPECT_NO_FATAL_FAILURE(injectEvent(EV_SYN, SYN_REPORT, 0));
+}
+
+void UinputKeyboard::releaseKey(int key) {
+ if (mKeys.find(key) == mKeys.end()) {
+ ADD_FAILURE() << mName << ": Cannot inject key release: Key not found: " << key;
+ }
+ EXPECT_NO_FATAL_FAILURE(injectEvent(EV_KEY, key, 0));
+ EXPECT_NO_FATAL_FAILURE(injectEvent(EV_SYN, SYN_REPORT, 0));
+}
+
+void UinputKeyboard::pressAndReleaseKey(int key) {
+ EXPECT_NO_FATAL_FAILURE(pressKey(key));
+ EXPECT_NO_FATAL_FAILURE(releaseKey(key));
+}
+
+// --- UinputHomeKey---
+
+UinputHomeKey::UinputHomeKey() : UinputKeyboard({KEY_HOME}) {}
+
+void UinputHomeKey::pressAndReleaseHomeKey() {
+ EXPECT_NO_FATAL_FAILURE(pressAndReleaseKey(KEY_HOME));
+}
+
+} // namespace android
diff --git a/services/inputflinger/tests/UinputDevice.h b/services/inputflinger/tests/UinputDevice.h
new file mode 100644
index 0000000..57d9011
--- /dev/null
+++ b/services/inputflinger/tests/UinputDevice.h
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _UI_TEST_INPUT_UINPUT_INJECTOR_H
+#define _UI_TEST_INPUT_UINPUT_INJECTOR_H
+
+#include <android-base/unique_fd.h>
+#include <gtest/gtest.h>
+#include <inttypes.h>
+#include <linux/uinput.h>
+#include <log/log.h>
+
+#include <memory>
+
+namespace android {
+
+// This is the factory method that must be used to create a UinputDevice.
+template <class D, class... Ts>
+std::unique_ptr<D> createUinputDevice(Ts... args) {
+ // Using `new` to access non-public constructors.
+ std::unique_ptr<D> dev(new D(&args...));
+ EXPECT_NO_FATAL_FAILURE(dev->init());
+ return dev;
+}
+
+// --- UinputDevice ---
+
+class UinputDevice {
+public:
+ virtual ~UinputDevice();
+
+ inline const char* getName() const { return mName; }
+
+ // Subclasses must either provide a public constructor or must be-friend the factory method.
+ template <class D, class... Ts>
+ friend std::unique_ptr<D> createUinputDevice(Ts... args);
+
+protected:
+ const char* mName;
+
+ UinputDevice(const char* name);
+
+ // Signals which types of events this device supports before it is created.
+ // This must be overridden by subclasses.
+ virtual void configureDevice(int fd, uinput_user_dev* device) = 0;
+
+ void injectEvent(uint16_t type, uint16_t code, int32_t value);
+
+private:
+ base::unique_fd mDeviceFd;
+
+ // This is called once by the factory method createUinputDevice().
+ void init();
+};
+
+// --- UinputKeyboard ---
+
+class UinputKeyboard : public UinputDevice {
+public:
+ static constexpr const char* KEYBOARD_NAME = "Test Keyboard Device";
+
+ // Injects key press and sync.
+ void pressKey(int key);
+ // Injects key release and sync.
+ void releaseKey(int key);
+ // Injects 4 events: key press, sync, key release, and sync.
+ void pressAndReleaseKey(int key);
+
+ template <class D, class... Ts>
+ friend std::unique_ptr<D> createUinputDevice(Ts... args);
+
+protected:
+ UinputKeyboard(std::initializer_list<int> keys = {});
+
+private:
+ void configureDevice(int fd, uinput_user_dev* device) override;
+
+ std::set<int> mKeys;
+};
+
+// --- UinputHomeKey---
+
+// A keyboard device that has a single HOME key.
+class UinputHomeKey : public UinputKeyboard {
+public:
+ // Injects 4 events: key press, sync, key release, and sync.
+ void pressAndReleaseHomeKey();
+
+ template <class D, class... Ts>
+ friend std::unique_ptr<D> createUinputDevice(Ts... args);
+
+private:
+ UinputHomeKey();
+};
+
+} // namespace android
+
+#endif // _UI_TEST_INPUT_UINPUT_INJECTOR_H
diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
index e803c9a..914a4cb 100644
--- a/services/sensorservice/SensorService.cpp
+++ b/services/sensorservice/SensorService.cpp
@@ -520,6 +520,10 @@
status_t SensorService::dumpProtoLocked(int fd, ConnectionSafeAutolock* connLock) const {
using namespace service::SensorServiceProto;
util::ProtoOutputStream proto;
+ proto.write(INIT_STATUS, int(SensorDevice::getInstance().initCheck()));
+ if (!mSensors.hasAnySensor()) {
+ return proto.flush(fd) ? OK : UNKNOWN_ERROR;
+ }
const bool privileged = IPCThreadState::self()->getCallingUid() == 0;
timespec curTime;
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index 1b1e889..4ffdf97 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -136,7 +136,7 @@
"BufferStateLayer.cpp",
"ClientCache.cpp",
"Client.cpp",
- "ColorLayer.cpp",
+ "EffectLayer.cpp",
"ContainerLayer.cpp",
"DisplayDevice.cpp",
"DisplayHardware/ComposerHal.cpp",
diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp
index 3cc803e..e65064b 100644
--- a/services/surfaceflinger/BufferQueueLayer.cpp
+++ b/services/surfaceflinger/BufferQueueLayer.cpp
@@ -441,6 +441,7 @@
status_t result = mQueueItemCondition.waitRelative(mQueueItemLock, ms2ns(500));
if (result != NO_ERROR) {
ALOGE("[%s] Timed out waiting on callback", getDebugName());
+ break;
}
}
@@ -469,6 +470,7 @@
status_t result = mQueueItemCondition.waitRelative(mQueueItemLock, ms2ns(500));
if (result != NO_ERROR) {
ALOGE("[%s] Timed out waiting on callback", getDebugName());
+ break;
}
}
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index 923a81c..1188dfe 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -32,7 +32,7 @@
#include <private/gui/SyncFeatures.h>
#include <renderengine/Image.h>
-#include "ColorLayer.h"
+#include "EffectLayer.h"
#include "FrameTracer/FrameTracer.h"
#include "TimeStats/TimeStats.h"
@@ -742,6 +742,33 @@
layer->setInitialValuesForClone(this);
return layer;
}
+
+Layer::RoundedCornerState BufferStateLayer::getRoundedCornerState() const {
+ const auto& p = mDrawingParent.promote();
+ if (p != nullptr) {
+ RoundedCornerState parentState = p->getRoundedCornerState();
+ if (parentState.radius > 0) {
+ ui::Transform t = getActiveTransform(getDrawingState());
+ t = t.inverse();
+ parentState.cropRect = t.transform(parentState.cropRect);
+ // The rounded corners shader only accepts 1 corner radius for performance reasons,
+ // but a transform matrix can define horizontal and vertical scales.
+ // Let's take the average between both of them and pass into the shader, practically we
+ // never do this type of transformation on windows anyway.
+ parentState.radius *= (t[0][0] + t[1][1]) / 2.0f;
+ return parentState;
+ }
+ }
+ const float radius = getDrawingState().cornerRadius;
+ const State& s(getDrawingState());
+ if (radius <= 0 || (getActiveWidth(s) == UINT32_MAX && getActiveHeight(s) == UINT32_MAX))
+ return RoundedCornerState();
+ return RoundedCornerState(FloatRect(static_cast<float>(s.active.transform.tx()),
+ static_cast<float>(s.active.transform.ty()),
+ static_cast<float>(s.active.transform.tx() + s.active.w),
+ static_cast<float>(s.active.transform.ty() + s.active.h)),
+ radius);
+}
} // namespace android
// TODO(b/129481165): remove the #pragma below and fix conversion issues
diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h
index 6ee5802..539442a 100644
--- a/services/surfaceflinger/BufferStateLayer.h
+++ b/services/surfaceflinger/BufferStateLayer.h
@@ -103,6 +103,7 @@
Rect getBufferSize(const State& s) const override;
FloatRect computeSourceBounds(const FloatRect& parentBounds) const override;
+ Layer::RoundedCornerState getRoundedCornerState() const override;
// -----------------------------------------------------------------------
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 153cfe7..f8d45c0 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -109,7 +109,6 @@
android::Hwc2::Display display, int64_t timestamp,
android::Hwc2::VsyncPeriodNanos vsyncPeriodNanos) override {
if (mVsyncSwitchingSupported) {
- // TODO(b/140201379): use vsyncPeriodNanos in the new DispSync
mCallback->onVsyncReceived(mSequenceId, display, timestamp,
std::make_optional(vsyncPeriodNanos));
} else {
@@ -579,12 +578,13 @@
sp<Fence> HWComposer::getLayerReleaseFence(DisplayId displayId, HWC2::Layer* layer) const {
RETURN_IF_INVALID_DISPLAY(displayId, Fence::NO_FENCE);
- auto displayFences = mDisplayData.at(displayId).releaseFences;
- if (displayFences.count(layer) == 0) {
+ const auto& displayFences = mDisplayData.at(displayId).releaseFences;
+ auto fence = displayFences.find(layer);
+ if (fence == displayFences.end()) {
ALOGV("getLayerReleaseFence: Release fence not found");
return Fence::NO_FENCE;
}
- return displayFences[layer];
+ return fence->second;
}
status_t HWComposer::presentAndGetReleaseFences(DisplayId displayId) {
diff --git a/services/surfaceflinger/ColorLayer.cpp b/services/surfaceflinger/EffectLayer.cpp
similarity index 78%
rename from services/surfaceflinger/ColorLayer.cpp
rename to services/surfaceflinger/EffectLayer.cpp
index 83050c4..e928c57 100644
--- a/services/surfaceflinger/ColorLayer.cpp
+++ b/services/surfaceflinger/EffectLayer.cpp
@@ -20,9 +20,9 @@
// #define LOG_NDEBUG 0
#undef LOG_TAG
-#define LOG_TAG "ColorLayer"
+#define LOG_TAG "EffectLayer"
-#include "ColorLayer.h"
+#include "EffectLayer.h"
#include <stdint.h>
#include <stdlib.h>
@@ -41,13 +41,13 @@
namespace android {
// ---------------------------------------------------------------------------
-ColorLayer::ColorLayer(const LayerCreationArgs& args)
+EffectLayer::EffectLayer(const LayerCreationArgs& args)
: Layer(args),
mCompositionState{mFlinger->getCompositionEngine().createLayerFECompositionState()} {}
-ColorLayer::~ColorLayer() = default;
+EffectLayer::~EffectLayer() = default;
-std::optional<compositionengine::LayerFE::LayerSettings> ColorLayer::prepareClientComposition(
+std::optional<compositionengine::LayerFE::LayerSettings> EffectLayer::prepareClientComposition(
compositionengine::LayerFE::ClientCompositionTargetSettings& targetSettings) {
auto result = Layer::prepareClientComposition(targetSettings);
if (!result) {
@@ -57,11 +57,11 @@
return result;
}
-bool ColorLayer::isVisible() const {
+bool EffectLayer::isVisible() const {
return !isHiddenByPolicy() && getAlpha() > 0.0_hf;
}
-bool ColorLayer::setColor(const half3& color) {
+bool EffectLayer::setColor(const half3& color) {
if (mCurrentState.color.r == color.r && mCurrentState.color.g == color.g &&
mCurrentState.color.b == color.b) {
return false;
@@ -76,7 +76,7 @@
return true;
}
-bool ColorLayer::setDataspace(ui::Dataspace dataspace) {
+bool EffectLayer::setDataspace(ui::Dataspace dataspace) {
if (mCurrentState.dataspace == dataspace) {
return false;
}
@@ -88,7 +88,7 @@
return true;
}
-void ColorLayer::preparePerFrameCompositionState() {
+void EffectLayer::preparePerFrameCompositionState() {
Layer::preparePerFrameCompositionState();
auto* compositionState = editCompositionState();
@@ -96,30 +96,30 @@
compositionState->compositionType = Hwc2::IComposerClient::Composition::SOLID_COLOR;
}
-sp<compositionengine::LayerFE> ColorLayer::getCompositionEngineLayerFE() const {
+sp<compositionengine::LayerFE> EffectLayer::getCompositionEngineLayerFE() const {
return asLayerFE();
}
-compositionengine::LayerFECompositionState* ColorLayer::editCompositionState() {
+compositionengine::LayerFECompositionState* EffectLayer::editCompositionState() {
return mCompositionState.get();
}
-const compositionengine::LayerFECompositionState* ColorLayer::getCompositionState() const {
+const compositionengine::LayerFECompositionState* EffectLayer::getCompositionState() const {
return mCompositionState.get();
}
-bool ColorLayer::isOpaque(const Layer::State& s) const {
+bool EffectLayer::isOpaque(const Layer::State& s) const {
// Consider the layer to be opaque if its opaque flag is set or its effective
// alpha (considering the alpha of its parents as well) is 1.0;
return (s.flags & layer_state_t::eLayerOpaque) != 0 || getAlpha() == 1.0_hf;
}
-ui::Dataspace ColorLayer::getDataSpace() const {
+ui::Dataspace EffectLayer::getDataSpace() const {
return mDrawingState.dataspace;
}
-sp<Layer> ColorLayer::createClone() {
- sp<ColorLayer> layer = mFlinger->getFactory().createColorLayer(
+sp<Layer> EffectLayer::createClone() {
+ sp<EffectLayer> layer = mFlinger->getFactory().createEffectLayer(
LayerCreationArgs(mFlinger.get(), nullptr, mName + " (Mirror)", 0, 0, 0,
LayerMetadata()));
layer->setInitialValuesForClone(this);
diff --git a/services/surfaceflinger/ColorLayer.h b/services/surfaceflinger/EffectLayer.h
similarity index 79%
rename from services/surfaceflinger/ColorLayer.h
rename to services/surfaceflinger/EffectLayer.h
index 4deb162..8694283 100644
--- a/services/surfaceflinger/ColorLayer.h
+++ b/services/surfaceflinger/EffectLayer.h
@@ -23,15 +23,19 @@
namespace android {
-class ColorLayer : public Layer {
+// A layer that can render a combination of the following effects.
+// * fill the bounds of the layer with a color
+// * render a shadow cast by the bounds of the layer
+// If no effects are enabled, the layer is considered to be invisible.
+class EffectLayer : public Layer {
public:
- explicit ColorLayer(const LayerCreationArgs&);
- ~ColorLayer() override;
+ explicit EffectLayer(const LayerCreationArgs&);
+ ~EffectLayer() override;
sp<compositionengine::LayerFE> getCompositionEngineLayerFE() const override;
compositionengine::LayerFECompositionState* editCompositionState() override;
- const char* getType() const override { return "ColorLayer"; }
+ const char* getType() const override { return "EffectLayer"; }
bool isVisible() const override;
bool setColor(const half3& color) override;
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index effbed6..fd86da8 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -56,10 +56,10 @@
#include <sstream>
#include "BufferLayer.h"
-#include "ColorLayer.h"
#include "Colorizer.h"
#include "DisplayDevice.h"
#include "DisplayHardware/HWComposer.h"
+#include "EffectLayer.h"
#include "FrameTracer/FrameTracer.h"
#include "LayerProtoHelper.h"
#include "LayerRejecter.h"
@@ -80,7 +80,6 @@
mName(args.name),
mClientRef(args.client),
mWindowType(args.metadata.getInt32(METADATA_WINDOW_TYPE, 0)) {
-
uint32_t layerFlags = 0;
if (args.flags & ISurfaceComposerClient::eHidden) layerFlags |= layer_state_t::eLayerHidden;
if (args.flags & ISurfaceComposerClient::eOpaque) layerFlags |= layer_state_t::eLayerOpaque;
@@ -165,7 +164,7 @@
/*
* onLayerDisplayed is only meaningful for BufferLayer, but, is called through
* Layer. So, the implementation is done in BufferLayer. When called on a
- * ColorLayer object, it's essentially a NOP.
+ * EffectLayer object, it's essentially a NOP.
*/
void Layer::onLayerDisplayed(const sp<Fence>& /*releaseFence*/) {}
@@ -1092,9 +1091,9 @@
if (!mCurrentState.bgColorLayer && alpha != 0) {
// create background color layer if one does not yet exist
- uint32_t flags = ISurfaceComposerClient::eFXSurfaceColor;
+ uint32_t flags = ISurfaceComposerClient::eFXSurfaceEffect;
std::string name = mName + "BackgroundColorLayer";
- mCurrentState.bgColorLayer = mFlinger->getFactory().createColorLayer(
+ mCurrentState.bgColorLayer = mFlinger->getFactory().createEffectLayer(
LayerCreationArgs(mFlinger.get(), nullptr, std::move(name), 0, 0, flags,
LayerMetadata()));
@@ -1264,6 +1263,9 @@
}
bool Layer::setFrameRate(FrameRate frameRate) {
+ if (!mFlinger->useFrameRateApi) {
+ return false;
+ }
if (mCurrentState.frameRate == frameRate) {
return false;
}
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index de4a080..c2dbd14 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -212,7 +212,7 @@
InputWindowInfo inputInfo;
wp<Layer> touchableRegionCrop;
- // dataspace is only used by BufferStateLayer and ColorLayer
+ // dataspace is only used by BufferStateLayer and EffectLayer
ui::Dataspace dataspace;
// The fields below this point are only used by BufferStateLayer
@@ -710,7 +710,7 @@
// corner definition and converting it into current layer's coordinates.
// As of now, only 1 corner radius per display list is supported. Subsequent ones will be
// ignored.
- RoundedCornerState getRoundedCornerState() const;
+ virtual RoundedCornerState getRoundedCornerState() const;
renderengine::ShadowSettings getShadowSettings(const Rect& viewport) const;
diff --git a/services/surfaceflinger/Scheduler/DispSync.cpp b/services/surfaceflinger/Scheduler/DispSync.cpp
index ca41608..809a0e5 100644
--- a/services/surfaceflinger/Scheduler/DispSync.cpp
+++ b/services/surfaceflinger/Scheduler/DispSync.cpp
@@ -542,7 +542,8 @@
resetLocked();
}
-bool DispSync::addResyncSample(nsecs_t timestamp, bool* periodFlushed) {
+bool DispSync::addResyncSample(nsecs_t timestamp, std::optional<nsecs_t> /*hwcVsyncPeriod*/,
+ bool* periodFlushed) {
Mutex::Autolock lock(mMutex);
ALOGV("[%s] addResyncSample(%" PRId64 ")", mName, ns2us(timestamp));
diff --git a/services/surfaceflinger/Scheduler/DispSync.h b/services/surfaceflinger/Scheduler/DispSync.h
index c6aadbb..2d9afc9 100644
--- a/services/surfaceflinger/Scheduler/DispSync.h
+++ b/services/surfaceflinger/Scheduler/DispSync.h
@@ -49,7 +49,8 @@
virtual void reset() = 0;
virtual bool addPresentFence(const std::shared_ptr<FenceTime>&) = 0;
virtual void beginResync() = 0;
- virtual bool addResyncSample(nsecs_t timestamp, bool* periodFlushed) = 0;
+ virtual bool addResyncSample(nsecs_t timestamp, std::optional<nsecs_t> hwcVsyncPeriod,
+ bool* periodFlushed) = 0;
virtual void endResync() = 0;
virtual void setPeriod(nsecs_t period) = 0;
virtual nsecs_t getPeriod() = 0;
@@ -125,7 +126,8 @@
// down the DispSync model, and false otherwise.
// periodFlushed will be set to true if mPendingPeriod is flushed to
// mIntendedPeriod, and false otherwise.
- bool addResyncSample(nsecs_t timestamp, bool* periodFlushed) override;
+ bool addResyncSample(nsecs_t timestamp, std::optional<nsecs_t> hwcVsyncPeriod,
+ bool* periodFlushed) override;
void endResync() override;
// The setPeriod method sets the vsync event model's period to a specific
diff --git a/services/surfaceflinger/Scheduler/EventThread.cpp b/services/surfaceflinger/Scheduler/EventThread.cpp
index 14e3ec6..acab5a6 100644
--- a/services/surfaceflinger/Scheduler/EventThread.cpp
+++ b/services/surfaceflinger/Scheduler/EventThread.cpp
@@ -335,6 +335,11 @@
mCondition.notify_all();
}
+size_t EventThread::getEventThreadConnectionCount() {
+ std::lock_guard<std::mutex> lock(mMutex);
+ return mDisplayEventConnections.size();
+}
+
void EventThread::threadMain(std::unique_lock<std::mutex>& lock) {
DisplayEventConsumers consumers;
diff --git a/services/surfaceflinger/Scheduler/EventThread.h b/services/surfaceflinger/Scheduler/EventThread.h
index 641b2a5..466234d 100644
--- a/services/surfaceflinger/Scheduler/EventThread.h
+++ b/services/surfaceflinger/Scheduler/EventThread.h
@@ -16,7 +16,12 @@
#pragma once
+#include <android-base/thread_annotations.h>
+#include <gui/DisplayEventReceiver.h>
+#include <gui/IDisplayEventConnection.h>
+#include <private/gui/BitTube.h>
#include <sys/types.h>
+#include <utils/Errors.h>
#include <condition_variable>
#include <cstdint>
@@ -26,13 +31,6 @@
#include <thread>
#include <vector>
-#include <android-base/thread_annotations.h>
-
-#include <gui/DisplayEventReceiver.h>
-#include <gui/IDisplayEventConnection.h>
-#include <private/gui/BitTube.h>
-
-#include <utils/Errors.h>
#include "HwcStrongTypes.h"
// ---------------------------------------------------------------------------
@@ -134,6 +132,9 @@
// Usage of this method assumes that only the primary internal display
// supports multiple display configurations.
virtual void requestLatestConfig() = 0;
+
+ // Retrieves the number of event connections tracked by this EventThread.
+ virtual size_t getEventThreadConnectionCount() = 0;
};
namespace impl {
@@ -168,6 +169,8 @@
void setPhaseOffset(nsecs_t phaseOffset) override;
+ size_t getEventThreadConnectionCount() override;
+
private:
friend EventThreadTest;
diff --git a/services/surfaceflinger/Scheduler/LayerHistory.cpp b/services/surfaceflinger/Scheduler/LayerHistory.cpp
index 9aada11..b313777 100644
--- a/services/surfaceflinger/Scheduler/LayerHistory.cpp
+++ b/services/surfaceflinger/Scheduler/LayerHistory.cpp
@@ -66,7 +66,6 @@
ATRACE_INT(tag.c_str(), fps);
ALOGD("%s: %s @ %d Hz", __FUNCTION__, name.c_str(), fps);
}
-
} // namespace
LayerHistory::LayerHistory()
@@ -102,23 +101,6 @@
partitionLayers(now);
- // Find the maximum refresh rate among recently active layers.
- for (const auto& [activeLayer, info] : activeLayers()) {
- const bool recent = info->isRecentlyActive(now);
-
- if (recent || CC_UNLIKELY(mTraceEnabled)) {
- const float refreshRate = info->getRefreshRate(now);
- if (recent && refreshRate > 0.0f) {
- if (const auto layer = activeLayer.promote(); layer) {
- const int32_t priority = layer->getFrameRateSelectionPriority();
- // TODO(b/142507166): This is where the scoring algorithm should live.
- // Layers should be organized by priority
- ALOGD("Layer has priority: %d", priority);
- }
- }
- }
- }
-
LayerHistory::Summary summary;
for (const auto& [weakLayer, info] : activeLayers()) {
const bool recent = info->isRecentlyActive(now);
@@ -196,6 +178,5 @@
mActiveLayersEnd = 0;
}
-
} // namespace android::scheduler::impl
diff --git a/services/surfaceflinger/Scheduler/LayerHistoryV2.cpp b/services/surfaceflinger/Scheduler/LayerHistoryV2.cpp
index ce085f4..6ef6ce4 100644
--- a/services/surfaceflinger/Scheduler/LayerHistoryV2.cpp
+++ b/services/surfaceflinger/Scheduler/LayerHistoryV2.cpp
@@ -79,7 +79,6 @@
ALOGD("%s: %s @ %d Hz", __FUNCTION__, name.c_str(), fps);
}
-
} // namespace
LayerHistoryV2::LayerHistoryV2()
@@ -124,6 +123,10 @@
continue;
}
+ // TODO(b/144307188): This needs to be plugged into layer summary as
+ // an additional parameter.
+ ALOGV("Layer has priority: %d", strong->getFrameRateSelectionPriority());
+
const bool recent = info->isRecentlyActive(now);
if (recent) {
const auto [type, refreshRate] = info->getRefreshRate(now);
@@ -212,5 +215,4 @@
mActiveLayersEnd = 0;
}
-
} // namespace android::scheduler::impl
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
index c73e825..d1de737 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
@@ -194,9 +194,22 @@
}
}
- float max = 0;
+ // Now that we scored all the refresh rates we need to pick the one that got the highest score.
+ // In case of a tie we will pick the higher refresh rate if any of the layers wanted Max,
+ // or the lower otherwise.
+ const RefreshRate* bestRefreshRate = maxVoteLayers > 0
+ ? getBestRefreshRate(scores.rbegin(), scores.rend())
+ : getBestRefreshRate(scores.begin(), scores.end());
+
+ return bestRefreshRate == nullptr ? *mCurrentRefreshRate : *bestRefreshRate;
+}
+
+template <typename Iter>
+const RefreshRate* RefreshRateConfigs::getBestRefreshRate(Iter begin, Iter end) const {
const RefreshRate* bestRefreshRate = nullptr;
- for (const auto [refreshRate, score] : scores) {
+ float max = 0;
+ for (auto i = begin; i != end; ++i) {
+ const auto [refreshRate, score] = *i;
ALOGV("%s scores %.2f", refreshRate->name.c_str(), score);
ATRACE_INT(refreshRate->name.c_str(), round<int>(score * 100));
@@ -207,7 +220,7 @@
}
}
- return bestRefreshRate == nullptr ? *mCurrentRefreshRate : *bestRefreshRate;
+ return bestRefreshRate;
}
const AllRefreshRatesMapType& RefreshRateConfigs::getAllRefreshRates() const {
@@ -229,6 +242,15 @@
return *mCurrentRefreshRate;
}
+const RefreshRate& RefreshRateConfigs::getCurrentRefreshRateByPolicy() const {
+ std::lock_guard lock(mLock);
+ if (std::find(mAvailableRefreshRates.begin(), mAvailableRefreshRates.end(),
+ mCurrentRefreshRate) != mAvailableRefreshRates.end()) {
+ return *mCurrentRefreshRate;
+ }
+ return mRefreshRates.at(mDefaultConfig);
+}
+
void RefreshRateConfigs::setCurrentConfigId(HwcConfigIndexType configId) {
std::lock_guard lock(mLock);
mCurrentRefreshRate = &mRefreshRates.at(configId);
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
index fc95959..1132a8c 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
@@ -149,6 +149,10 @@
// Returns the current refresh rate
const RefreshRate& getCurrentRefreshRate() const EXCLUDES(mLock);
+ // Returns the current refresh rate, if allowed. Otherwise the default that is allowed by
+ // the policy.
+ const RefreshRate& getCurrentRefreshRateByPolicy() const;
+
// Returns the refresh rate that corresponds to a HwcConfigIndexType. This won't change at
// runtime.
const RefreshRate& getRefreshRateFromConfigId(HwcConfigIndexType configId) const {
@@ -178,6 +182,12 @@
const std::function<bool(const RefreshRate&)>& shouldAddRefreshRate,
std::vector<const RefreshRate*>* outRefreshRates);
+ // Returns the refresh rate with the highest score in the collection specified from begin
+ // to end. If there are more than one with the same highest refresh rate, the first one is
+ // returned.
+ template <typename Iter>
+ const RefreshRate* getBestRefreshRate(Iter begin, Iter end) const;
+
// The list of refresh rates, indexed by display config ID. This must not change after this
// object is initialized.
AllRefreshRatesMapType mRefreshRates;
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 49a269f..71ac90e 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -108,12 +108,10 @@
mUseContentDetectionV2(useContentDetectionV2) {
using namespace sysprop;
- if (property_get_bool("debug.sf.use_smart_90_for_video", 0) || use_smart_90_for_video(false)) {
- if (mUseContentDetectionV2) {
- mLayerHistory = std::make_unique<scheduler::impl::LayerHistoryV2>();
- } else {
- mLayerHistory = std::make_unique<scheduler::impl::LayerHistory>();
- }
+ if (mUseContentDetectionV2) {
+ mLayerHistory = std::make_unique<scheduler::impl::LayerHistoryV2>();
+ } else {
+ mLayerHistory = std::make_unique<scheduler::impl::LayerHistory>();
}
const int setIdleTimerMs = property_get_int32("debug.sf.set_idle_timer_ms", 0);
@@ -232,6 +230,11 @@
mConnections[handle].thread->onConfigChanged(displayId, configId, vsyncPeriod);
}
+size_t Scheduler::getEventThreadConnectionCount(ConnectionHandle handle) {
+ RETURN_IF_INVALID_HANDLE(handle, 0);
+ return mConnections[handle].thread->getEventThreadConnectionCount();
+}
+
void Scheduler::dump(ConnectionHandle handle, std::string& result) const {
RETURN_IF_INVALID_HANDLE(handle);
mConnections.at(handle).thread->dump(result);
@@ -340,13 +343,15 @@
}
}
-void Scheduler::addResyncSample(nsecs_t timestamp, bool* periodFlushed) {
+void Scheduler::addResyncSample(nsecs_t timestamp, std::optional<nsecs_t> hwcVsyncPeriod,
+ bool* periodFlushed) {
bool needsHwVsync = false;
*periodFlushed = false;
{ // Scope for the lock
std::lock_guard<std::mutex> lock(mHWVsyncLock);
if (mPrimaryHWVsyncEnabled) {
- needsHwVsync = mPrimaryDispSync->addResyncSample(timestamp, periodFlushed);
+ needsHwVsync =
+ mPrimaryDispSync->addResyncSample(timestamp, hwcVsyncPeriod, periodFlushed);
}
}
@@ -437,7 +442,7 @@
mFeatures.contentDetection =
!summary.empty() ? ContentDetectionState::On : ContentDetectionState::Off;
- newConfigId = calculateRefreshRateType();
+ newConfigId = calculateRefreshRateConfigIndexType();
if (mFeatures.configId == newConfigId) {
return;
}
@@ -530,8 +535,6 @@
using base::StringAppendF;
const char* const states[] = {"off", "on"};
- StringAppendF(&result, "+ Content detection: %s\n", states[mLayerHistory != nullptr]);
-
StringAppendF(&result, "+ Idle timer: %s\n",
mIdleTimer ? mIdleTimer->dump().c_str() : states[0]);
StringAppendF(&result, "+ Touch timer: %s\n\n",
@@ -548,7 +551,7 @@
return;
}
*currentState = newState;
- newConfigId = calculateRefreshRateType();
+ newConfigId = calculateRefreshRateConfigIndexType();
if (mFeatures.configId == newConfigId) {
return;
}
@@ -562,6 +565,7 @@
}
bool Scheduler::layerHistoryHasClientSpecifiedFrameRate() {
+ // Traverse all the layers to see if any of them requested frame rate.
for (const auto& layer : mFeatures.contentRequirements) {
if (layer.vote == scheduler::RefreshRateConfigs::LayerVoteType::ExplicitDefault ||
layer.vote == scheduler::RefreshRateConfigs::LayerVoteType::ExplicitExactOrMultiple) {
@@ -572,10 +576,9 @@
return false;
}
-HwcConfigIndexType Scheduler::calculateRefreshRateType() {
+HwcConfigIndexType Scheduler::calculateRefreshRateConfigIndexType() {
// This block of the code checks whether any layers used the SetFrameRate API. If they have,
- // their request should be honored regardless of whether the device has refresh rate switching
- // turned off.
+ // their request should be honored depending on other active layers.
if (layerHistoryHasClientSpecifiedFrameRate()) {
if (!mUseContentDetectionV2) {
return mRefreshRateConfigs.getRefreshRateForContent(mFeatures.contentRequirements)
@@ -586,23 +589,23 @@
}
}
- // If the layer history doesn't have the frame rate specified, use the old path. NOTE:
- // if we remove the kernel idle timer, and use our internal idle timer, this code will have to
- // be refactored.
- // If Display Power is not in normal operation we want to be in performance mode.
- // When coming back to normal mode, a grace period is given with DisplayPowerTimer
+ // If the layer history doesn't have the frame rate specified, check for other features and
+ // honor them. NOTE: If we remove the kernel idle timer, and use our internal idle timer, this
+ // code will have to be refactored. If Display Power is not in normal operation we want to be in
+ // performance mode. When coming back to normal mode, a grace period is given with
+ // DisplayPowerTimer.
if (mDisplayPowerTimer &&
(!mFeatures.isDisplayPowerStateNormal ||
mFeatures.displayPowerTimer == TimerState::Reset)) {
return mRefreshRateConfigs.getMaxRefreshRateByPolicy().configId;
}
- // As long as touch is active we want to be in performance mode
+ // As long as touch is active we want to be in performance mode.
if (mTouchTimer && mFeatures.touch == TouchState::Active) {
return mRefreshRateConfigs.getMaxRefreshRateByPolicy().configId;
}
- // If timer has expired as it means there is no new content on the screen
+ // If timer has expired as it means there is no new content on the screen.
if (mIdleTimer && mFeatures.idleTimer == TimerState::Expired) {
return mRefreshRateConfigs.getMinRefreshRateByPolicy().configId;
}
@@ -610,7 +613,7 @@
if (!mUseContentDetectionV2) {
// If content detection is off we choose performance as we don't know the content fps.
if (mFeatures.contentDetection == ContentDetectionState::Off) {
- // TODO(b/148428554): Be careful to not always call this.
+ // NOTE: V1 always calls this, but this is not a default behavior for V2.
return mRefreshRateConfigs.getMaxRefreshRateByPolicy().configId;
}
@@ -624,15 +627,15 @@
.configId;
}
- // There are no signals for refresh rate, just leave it as is
- return mRefreshRateConfigs.getCurrentRefreshRate().configId;
+ // There are no signals for refresh rate, just leave it as is.
+ return mRefreshRateConfigs.getCurrentRefreshRateByPolicy().configId;
}
std::optional<HwcConfigIndexType> Scheduler::getPreferredConfigId() {
std::lock_guard<std::mutex> lock(mFeatureStateLock);
// Make sure that the default config ID is first updated, before returned.
if (mFeatures.configId.has_value()) {
- mFeatures.configId = calculateRefreshRateType();
+ mFeatures.configId = calculateRefreshRateConfigIndexType();
}
return mFeatures.configId;
}
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index 01062f8..81051be 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -109,7 +109,8 @@
// Passes a vsync sample to DispSync. periodFlushed will be true if
// DispSync detected that the vsync period changed, and false otherwise.
- void addResyncSample(nsecs_t timestamp, bool* periodFlushed);
+ void addResyncSample(nsecs_t timestamp, std::optional<nsecs_t> hwcVsyncPeriod,
+ bool* periodFlushed);
void addPresentFence(const std::shared_ptr<FenceTime>&);
void setIgnorePresentFences(bool ignore);
nsecs_t getDispSyncExpectedPresentTime();
@@ -144,6 +145,8 @@
// Notifies the scheduler when the display size has changed. Called from SF's main thread
void onPrimaryDisplayAreaChanged(uint32_t displayArea);
+ size_t getEventThreadConnectionCount(ConnectionHandle handle);
+
private:
friend class TestableScheduler;
@@ -177,7 +180,10 @@
void setVsyncPeriod(nsecs_t period);
- HwcConfigIndexType calculateRefreshRateType() REQUIRES(mFeatureStateLock);
+ // This function checks whether individual features that are affecting the refresh rate
+ // selection were initialized, prioritizes them, and calculates the HwcConfigIndexType
+ // for the suggested refresh rate.
+ HwcConfigIndexType calculateRefreshRateConfigIndexType() REQUIRES(mFeatureStateLock);
bool layerHistoryHasClientSpecifiedFrameRate() REQUIRES(mFeatureStateLock);
diff --git a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp b/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
index b467f24..399da19 100644
--- a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
+++ b/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
@@ -53,15 +53,15 @@
}
inline size_t VSyncPredictor::next(int i) const {
- return (i + 1) % timestamps.size();
+ return (i + 1) % mTimestamps.size();
}
bool VSyncPredictor::validate(nsecs_t timestamp) const {
- if (lastTimestampIndex < 0 || timestamps.empty()) {
+ if (mLastTimestampIndex < 0 || mTimestamps.empty()) {
return true;
}
- auto const aValidTimestamp = timestamps[lastTimestampIndex];
+ auto const aValidTimestamp = mTimestamps[mLastTimestampIndex];
auto const percent = (timestamp - aValidTimestamp) % mIdealPeriod * kMaxPercent / mIdealPeriod;
return percent < kOutlierTolerancePercent || percent > (kMaxPercent - kOutlierTolerancePercent);
}
@@ -79,15 +79,15 @@
return false;
}
- if (timestamps.size() != kHistorySize) {
- timestamps.push_back(timestamp);
- lastTimestampIndex = next(lastTimestampIndex);
+ if (mTimestamps.size() != kHistorySize) {
+ mTimestamps.push_back(timestamp);
+ mLastTimestampIndex = next(mLastTimestampIndex);
} else {
- lastTimestampIndex = next(lastTimestampIndex);
- timestamps[lastTimestampIndex] = timestamp;
+ mLastTimestampIndex = next(mLastTimestampIndex);
+ mTimestamps[mLastTimestampIndex] = timestamp;
}
- if (timestamps.size() < kMinimumSamplesForPrediction) {
+ if (mTimestamps.size() < kMinimumSamplesForPrediction) {
mRateMap[mIdealPeriod] = {mIdealPeriod, 0};
return true;
}
@@ -107,11 +107,11 @@
//
// intercept = mean(Y) - slope * mean(X)
//
- std::vector<nsecs_t> vsyncTS(timestamps.size());
- std::vector<nsecs_t> ordinals(timestamps.size());
+ std::vector<nsecs_t> vsyncTS(mTimestamps.size());
+ std::vector<nsecs_t> ordinals(mTimestamps.size());
// normalizing to the oldest timestamp cuts down on error in calculating the intercept.
- auto const oldest_ts = *std::min_element(timestamps.begin(), timestamps.end());
+ auto const oldest_ts = *std::min_element(mTimestamps.begin(), mTimestamps.end());
auto it = mRateMap.find(mIdealPeriod);
auto const currentPeriod = std::get<0>(it->second);
// TODO (b/144707443): its important that there's some precision in the mean of the ordinals
@@ -120,10 +120,10 @@
// scheduler::utils::calculate_mean to have a fixed point fractional part.
static constexpr int kScalingFactor = 10;
- for (auto i = 0u; i < timestamps.size(); i++) {
- traceInt64If("VSP-ts", timestamps[i]);
+ for (auto i = 0u; i < mTimestamps.size(); i++) {
+ traceInt64If("VSP-ts", mTimestamps[i]);
- vsyncTS[i] = timestamps[i] - oldest_ts;
+ vsyncTS[i] = mTimestamps[i] - oldest_ts;
ordinals[i] = ((vsyncTS[i] + (currentPeriod / 2)) / currentPeriod) * kScalingFactor;
}
@@ -143,12 +143,20 @@
if (CC_UNLIKELY(bottom == 0)) {
it->second = {mIdealPeriod, 0};
+ clearTimestamps();
return false;
}
nsecs_t const anticipatedPeriod = top / bottom * kScalingFactor;
nsecs_t const intercept = meanTS - (anticipatedPeriod * meanOrdinal / kScalingFactor);
+ auto const percent = std::abs(anticipatedPeriod - mIdealPeriod) * kMaxPercent / mIdealPeriod;
+ if (percent >= kOutlierTolerancePercent) {
+ it->second = {mIdealPeriod, 0};
+ clearTimestamps();
+ return false;
+ }
+
traceInt64If("VSP-period", anticipatedPeriod);
traceInt64If("VSP-intercept", intercept);
@@ -164,14 +172,14 @@
auto const [slope, intercept] = getVSyncPredictionModel(lk);
- if (timestamps.empty()) {
+ if (mTimestamps.empty()) {
traceInt64If("VSP-mode", 1);
auto const knownTimestamp = mKnownTimestamp ? *mKnownTimestamp : timePoint;
auto const numPeriodsOut = ((timePoint - knownTimestamp) / mIdealPeriod) + 1;
return knownTimestamp + numPeriodsOut * mIdealPeriod;
}
- auto const oldest = *std::min_element(timestamps.begin(), timestamps.end());
+ auto const oldest = *std::min_element(mTimestamps.begin(), mTimestamps.end());
// See b/145667109, the ordinal calculation must take into account the intercept.
auto const zeroPoint = oldest + intercept;
@@ -225,10 +233,10 @@
}
void VSyncPredictor::clearTimestamps() {
- if (!timestamps.empty()) {
- mKnownTimestamp = *std::max_element(timestamps.begin(), timestamps.end());
- timestamps.clear();
- lastTimestampIndex = 0;
+ if (!mTimestamps.empty()) {
+ mKnownTimestamp = *std::max_element(mTimestamps.begin(), mTimestamps.end());
+ mTimestamps.clear();
+ mLastTimestampIndex = 0;
}
}
@@ -236,11 +244,11 @@
using namespace std::literals::chrono_literals;
std::lock_guard<std::mutex> lk(mMutex);
bool needsMoreSamples = true;
- if (timestamps.size() >= kMinimumSamplesForPrediction) {
+ if (mTimestamps.size() >= kMinimumSamplesForPrediction) {
nsecs_t constexpr aLongTime =
std::chrono::duration_cast<std::chrono::nanoseconds>(500ms).count();
- if (!(lastTimestampIndex < 0 || timestamps.empty())) {
- auto const lastTimestamp = timestamps[lastTimestampIndex];
+ if (!(mLastTimestampIndex < 0 || mTimestamps.empty())) {
+ auto const lastTimestamp = mTimestamps[mLastTimestampIndex];
needsMoreSamples = !((lastTimestamp + aLongTime) > now);
}
}
diff --git a/services/surfaceflinger/Scheduler/VSyncPredictor.h b/services/surfaceflinger/Scheduler/VSyncPredictor.h
index 532fe9e..ef1d88a 100644
--- a/services/surfaceflinger/Scheduler/VSyncPredictor.h
+++ b/services/surfaceflinger/Scheduler/VSyncPredictor.h
@@ -83,8 +83,8 @@
std::unordered_map<nsecs_t, std::tuple<nsecs_t, nsecs_t>> mutable mRateMap GUARDED_BY(mMutex);
- int lastTimestampIndex GUARDED_BY(mMutex) = 0;
- std::vector<nsecs_t> timestamps GUARDED_BY(mMutex);
+ int mLastTimestampIndex GUARDED_BY(mMutex) = 0;
+ std::vector<nsecs_t> mTimestamps GUARDED_BY(mMutex);
};
} // namespace android::scheduler
diff --git a/services/surfaceflinger/Scheduler/VSyncReactor.cpp b/services/surfaceflinger/Scheduler/VSyncReactor.cpp
index 70e4760..da73e4e 100644
--- a/services/surfaceflinger/Scheduler/VSyncReactor.cpp
+++ b/services/surfaceflinger/Scheduler/VSyncReactor.cpp
@@ -229,24 +229,33 @@
void VSyncReactor::endResync() {}
-bool VSyncReactor::periodConfirmed(nsecs_t vsync_timestamp) {
- if (!mLastHwVsync || !mPeriodConfirmationInProgress) {
+bool VSyncReactor::periodConfirmed(nsecs_t vsync_timestamp, std::optional<nsecs_t> HwcVsyncPeriod) {
+ if (!mPeriodConfirmationInProgress) {
return false;
}
- auto const period = mPeriodTransitioningTo ? *mPeriodTransitioningTo : getPeriod();
+ if (!mLastHwVsync && !HwcVsyncPeriod) {
+ return false;
+ }
+
+ auto const period = mPeriodTransitioningTo ? *mPeriodTransitioningTo : getPeriod();
static constexpr int allowancePercent = 10;
static constexpr std::ratio<allowancePercent, 100> allowancePercentRatio;
auto const allowance = period * allowancePercentRatio.num / allowancePercentRatio.den;
+ if (HwcVsyncPeriod) {
+ return std::abs(*HwcVsyncPeriod - period) < allowance;
+ }
+
auto const distance = vsync_timestamp - *mLastHwVsync;
return std::abs(distance - period) < allowance;
}
-bool VSyncReactor::addResyncSample(nsecs_t timestamp, bool* periodFlushed) {
+bool VSyncReactor::addResyncSample(nsecs_t timestamp, std::optional<nsecs_t> hwcVsyncPeriod,
+ bool* periodFlushed) {
assert(periodFlushed);
std::lock_guard<std::mutex> lk(mMutex);
- if (periodConfirmed(timestamp)) {
+ if (periodConfirmed(timestamp, hwcVsyncPeriod)) {
if (mPeriodTransitioningTo) {
mTracker->setPeriod(*mPeriodTransitioningTo);
for (auto& entry : mCallbacks) {
diff --git a/services/surfaceflinger/Scheduler/VSyncReactor.h b/services/surfaceflinger/Scheduler/VSyncReactor.h
index 5b79f35..aa8a38d 100644
--- a/services/surfaceflinger/Scheduler/VSyncReactor.h
+++ b/services/surfaceflinger/Scheduler/VSyncReactor.h
@@ -49,7 +49,8 @@
// TODO: (b/145626181) remove begin,endResync functions from DispSync i/f when possible.
void beginResync() final;
- bool addResyncSample(nsecs_t timestamp, bool* periodFlushed) final;
+ bool addResyncSample(nsecs_t timestamp, std::optional<nsecs_t> hwcVsyncPeriod,
+ bool* periodFlushed) final;
void endResync() final;
status_t addEventListener(const char* name, nsecs_t phase, DispSync::Callback* callback,
@@ -65,7 +66,8 @@
void updateIgnorePresentFencesInternal() REQUIRES(mMutex);
void startPeriodTransition(nsecs_t newPeriod) REQUIRES(mMutex);
void endPeriodTransition() REQUIRES(mMutex);
- bool periodConfirmed(nsecs_t vsync_timestamp) REQUIRES(mMutex);
+ bool periodConfirmed(nsecs_t vsync_timestamp, std::optional<nsecs_t> hwcVsyncPeriod)
+ REQUIRES(mMutex);
std::unique_ptr<Clock> const mClock;
std::unique_ptr<VSyncTracker> const mTracker;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index e8c7a55..67c3d52 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -83,10 +83,10 @@
#include "BufferQueueLayer.h"
#include "BufferStateLayer.h"
#include "Client.h"
-#include "ColorLayer.h"
#include "Colorizer.h"
#include "ContainerLayer.h"
#include "DisplayDevice.h"
+#include "EffectLayer.h"
#include "Layer.h"
#include "LayerVector.h"
#include "MonitoredProducer.h"
@@ -228,6 +228,7 @@
ui::PixelFormat SurfaceFlinger::defaultCompositionPixelFormat = ui::PixelFormat::RGBA_8888;
Dataspace SurfaceFlinger::wideColorGamutCompositionDataspace = Dataspace::V0_SRGB;
ui::PixelFormat SurfaceFlinger::wideColorGamutCompositionPixelFormat = ui::PixelFormat::RGBA_8888;
+bool SurfaceFlinger::useFrameRateApi;
std::string getHwcServiceName() {
char value[PROPERTY_VALUE_MAX] = {};
@@ -387,6 +388,8 @@
// for production purposes later on.
setenv("TREBLE_TESTING_OVERRIDE", "true", true);
}
+
+ useFrameRateApi = use_frame_rate_api(true);
}
void SurfaceFlinger::onFirstRef()
@@ -1499,11 +1502,9 @@
void SurfaceFlinger::onVsyncReceived(int32_t sequenceId, hwc2_display_t hwcDisplayId,
int64_t timestamp,
- std::optional<hwc2_vsync_period_t> /*vsyncPeriod*/) {
+ std::optional<hwc2_vsync_period_t> vsyncPeriod) {
ATRACE_NAME("SF onVsync");
- // TODO(b/140201379): use vsyncPeriod in the new DispSync
-
Mutex::Autolock lock(mStateLock);
// Ignore any vsyncs from a previous hardware composer.
if (sequenceId != getBE().mComposerSequenceId) {
@@ -1520,7 +1521,7 @@
}
bool periodFlushed = false;
- mScheduler->addResyncSample(timestamp, &periodFlushed);
+ mScheduler->addResyncSample(timestamp, vsyncPeriod, &periodFlushed);
if (periodFlushed) {
mVSyncModulator->onRefreshRateChangeCompleted();
}
@@ -2080,7 +2081,8 @@
}
});
- if (presentFenceTime->isValid()) {
+ if (displayDevice && displayDevice->isPrimary() &&
+ displayDevice->getPowerMode() == HWC_POWER_MODE_NORMAL && presentFenceTime->isValid()) {
mScheduler->addPresentFence(presentFenceTime);
}
@@ -2118,6 +2120,10 @@
mTimeStats->setPresentFenceGlobal(presentFenceTime);
+ const size_t sfConnections = mScheduler->getEventThreadConnectionCount(mSfConnectionHandle);
+ const size_t appConnections = mScheduler->getEventThreadConnectionCount(mAppConnectionHandle);
+ mTimeStats->recordDisplayEventConnectionCount(sfConnections + appConnections);
+
if (displayDevice && getHwComposer().isConnected(*displayDevice->getId()) &&
!displayDevice->isPoweredOn()) {
return;
@@ -3694,7 +3700,7 @@
result = createBufferStateLayer(client, std::move(uniqueName), w, h, flags,
std::move(metadata), handle, outTransformHint, &layer);
break;
- case ISurfaceComposerClient::eFXSurfaceColor:
+ case ISurfaceComposerClient::eFXSurfaceEffect:
// check if buffer size is set for color layer.
if (w > 0 || h > 0) {
ALOGE("createLayer() failed, w or h cannot be set for color layer (w=%d, h=%d)",
@@ -3702,8 +3708,8 @@
return BAD_VALUE;
}
- result = createColorLayer(client, std::move(uniqueName), w, h, flags,
- std::move(metadata), handle, &layer);
+ result = createEffectLayer(client, std::move(uniqueName), w, h, flags,
+ std::move(metadata), handle, &layer);
break;
case ISurfaceComposerClient::eFXSurfaceContainer:
// check if buffer size is set for container layer.
@@ -3821,10 +3827,10 @@
return NO_ERROR;
}
-status_t SurfaceFlinger::createColorLayer(const sp<Client>& client, std::string name, uint32_t w,
- uint32_t h, uint32_t flags, LayerMetadata metadata,
- sp<IBinder>* handle, sp<Layer>* outLayer) {
- *outLayer = getFactory().createColorLayer(
+status_t SurfaceFlinger::createEffectLayer(const sp<Client>& client, std::string name, uint32_t w,
+ uint32_t h, uint32_t flags, LayerMetadata metadata,
+ sp<IBinder>* handle, sp<Layer>* outLayer) {
+ *outLayer = getFactory().createEffectLayer(
{this, client, std::move(name), w, h, flags, std::move(metadata)});
*handle = (*outLayer)->getHandle();
return NO_ERROR;
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index ccf5794..0d43215 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -248,6 +248,11 @@
static ui::Dataspace wideColorGamutCompositionDataspace;
static ui::PixelFormat wideColorGamutCompositionPixelFormat;
+ // Whether to use frame rate API when deciding about the refresh rate of the display. This
+ // variable is caches in SF, so that we can check it with each layer creation, and a void the
+ // overhead that is caused by reading from sysprop.
+ static bool useFrameRateApi;
+
static char const* getServiceName() ANDROID_API {
return "SurfaceFlinger";
}
@@ -648,9 +653,9 @@
sp<IBinder>* outHandle, uint32_t* outTransformHint,
sp<Layer>* outLayer);
- status_t createColorLayer(const sp<Client>& client, std::string name, uint32_t w, uint32_t h,
- uint32_t flags, LayerMetadata metadata, sp<IBinder>* outHandle,
- sp<Layer>* outLayer);
+ status_t createEffectLayer(const sp<Client>& client, std::string name, uint32_t w, uint32_t h,
+ uint32_t flags, LayerMetadata metadata, sp<IBinder>* outHandle,
+ sp<Layer>* outLayer);
status_t createContainerLayer(const sp<Client>& client, std::string name, uint32_t w,
uint32_t h, uint32_t flags, LayerMetadata metadata,
diff --git a/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp b/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp
index f9658a7..d49133d 100644
--- a/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp
+++ b/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp
@@ -25,9 +25,9 @@
#include "BufferLayerConsumer.h"
#include "BufferQueueLayer.h"
#include "BufferStateLayer.h"
-#include "ColorLayer.h"
#include "ContainerLayer.h"
#include "DisplayDevice.h"
+#include "EffectLayer.h"
#include "Layer.h"
#include "MonitoredProducer.h"
#include "NativeWindowSurface.h"
@@ -139,8 +139,8 @@
return new BufferStateLayer(args);
}
-sp<ColorLayer> DefaultFactory::createColorLayer(const LayerCreationArgs& args) {
- return new ColorLayer(args);
+sp<EffectLayer> DefaultFactory::createEffectLayer(const LayerCreationArgs& args) {
+ return new EffectLayer(args);
}
} // namespace android::surfaceflinger
diff --git a/services/surfaceflinger/SurfaceFlingerDefaultFactory.h b/services/surfaceflinger/SurfaceFlingerDefaultFactory.h
index 36fae21..89194c7 100644
--- a/services/surfaceflinger/SurfaceFlingerDefaultFactory.h
+++ b/services/surfaceflinger/SurfaceFlingerDefaultFactory.h
@@ -55,7 +55,7 @@
std::unique_ptr<compositionengine::CompositionEngine> createCompositionEngine() override;
sp<BufferQueueLayer> createBufferQueueLayer(const LayerCreationArgs& args) override;
sp<BufferStateLayer> createBufferStateLayer(const LayerCreationArgs& args) override;
- sp<ColorLayer> createColorLayer(const LayerCreationArgs& args) override;
+ sp<EffectLayer> createEffectLayer(const LayerCreationArgs& args) override;
sp<ContainerLayer> createContainerLayer(const LayerCreationArgs& args) override;
};
diff --git a/services/surfaceflinger/SurfaceFlingerFactory.h b/services/surfaceflinger/SurfaceFlingerFactory.h
index 951bd09..209bd0c 100644
--- a/services/surfaceflinger/SurfaceFlingerFactory.h
+++ b/services/surfaceflinger/SurfaceFlingerFactory.h
@@ -16,14 +16,14 @@
#pragma once
+#include <cutils/compiler.h>
+#include <utils/StrongPointer.h>
+
#include <cinttypes>
#include <functional>
#include <memory>
#include <string>
-#include <cutils/compiler.h>
-#include <utils/StrongPointer.h>
-
namespace android {
typedef int32_t PixelFormat;
@@ -31,7 +31,7 @@
class BufferQueueLayer;
class BufferStateLayer;
class BufferLayerConsumer;
-class ColorLayer;
+class EffectLayer;
class ContainerLayer;
class DisplayDevice;
class DispSync;
@@ -104,7 +104,7 @@
virtual sp<BufferQueueLayer> createBufferQueueLayer(const LayerCreationArgs& args) = 0;
virtual sp<BufferStateLayer> createBufferStateLayer(const LayerCreationArgs& args) = 0;
- virtual sp<ColorLayer> createColorLayer(const LayerCreationArgs& args) = 0;
+ virtual sp<EffectLayer> createEffectLayer(const LayerCreationArgs& args) = 0;
virtual sp<ContainerLayer> createContainerLayer(const LayerCreationArgs& args) = 0;
protected:
diff --git a/services/surfaceflinger/SurfaceFlingerProperties.cpp b/services/surfaceflinger/SurfaceFlingerProperties.cpp
index e199b53..1a611f5 100644
--- a/services/surfaceflinger/SurfaceFlingerProperties.cpp
+++ b/services/surfaceflinger/SurfaceFlingerProperties.cpp
@@ -18,6 +18,7 @@
#include <android/hardware/configstore/1.1/ISurfaceFlingerConfigs.h>
#include <android/hardware/configstore/1.1/types.h>
#include <configstore/Utils.h>
+#include <utils/Log.h>
#include <log/log.h>
#include <cstdlib>
@@ -263,8 +264,17 @@
return defaultValue;
}
-bool use_smart_90_for_video(bool defaultValue) {
- auto temp = SurfaceFlingerProperties::use_smart_90_for_video();
+bool use_content_detection_for_refresh_rate(bool defaultValue) {
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+ auto smart_90_deprecated = SurfaceFlingerProperties::use_smart_90_for_video();
+#pragma clang diagnostic pop
+ if (smart_90_deprecated.has_value()) {
+ ALOGW("Using deprecated use_smart_90_for_video sysprop. Value: %d", *smart_90_deprecated);
+ return *smart_90_deprecated;
+ }
+
+ auto temp = SurfaceFlingerProperties::use_content_detection_for_refresh_rate();
if (temp.has_value()) {
return *temp;
}
@@ -287,6 +297,14 @@
return defaultValue;
}
+bool use_frame_rate_api(bool defaultValue) {
+ auto temp = SurfaceFlingerProperties::use_frame_rate_api();
+ if (temp.has_value()) {
+ return *temp;
+ }
+ return defaultValue;
+}
+
#define DISPLAY_PRIMARY_SIZE 3
constexpr float kSrgbRedX = 0.4123f;
diff --git a/services/surfaceflinger/SurfaceFlingerProperties.h b/services/surfaceflinger/SurfaceFlingerProperties.h
index e394cca..4c6e191 100644
--- a/services/surfaceflinger/SurfaceFlingerProperties.h
+++ b/services/surfaceflinger/SurfaceFlingerProperties.h
@@ -81,12 +81,14 @@
int32_t set_display_power_timer_ms(int32_t defaultValue);
-bool use_smart_90_for_video(bool defaultValue);
+bool use_content_detection_for_refresh_rate(bool defaultValue);
bool enable_protected_contents(bool defaultValue);
bool support_kernel_idle_timer(bool defaultValue);
+bool use_frame_rate_api(bool defaultValue);
+
android::ui::DisplayPrimaries getDisplayNativePrimaries();
} // namespace sysprop
} // namespace android
diff --git a/services/surfaceflinger/TimeStats/TimeStats.cpp b/services/surfaceflinger/TimeStats/TimeStats.cpp
index 493a709..7c8c28e 100644
--- a/services/surfaceflinger/TimeStats/TimeStats.cpp
+++ b/services/surfaceflinger/TimeStats/TimeStats.cpp
@@ -70,6 +70,7 @@
mStatsDelegate->statsEventWriteInt64(event, mTimeStats.clientCompositionFrames);
mStatsDelegate->statsEventWriteInt64(event, mTimeStats.displayOnTime);
mStatsDelegate->statsEventWriteInt64(event, mTimeStats.presentToPresent.totalTime());
+ mStatsDelegate->statsEventWriteInt32(event, mTimeStats.displayEventConnectionsCount);
mStatsDelegate->statsEventBuild(event);
clearGlobalLocked();
@@ -148,6 +149,9 @@
}
}
+ mStatsDelegate->statsEventWriteInt64(event, layer->lateAcquireFrames);
+ mStatsDelegate->statsEventWriteInt64(event, layer->badDesiredPresentFrames);
+
mStatsDelegate->statsEventBuild(event);
}
clearLayersLocked();
@@ -269,6 +273,16 @@
mTimeStats.clientCompositionReusedFrames++;
}
+void TimeStats::recordDisplayEventConnectionCount(int32_t count) {
+ if (!mEnabled.load()) return;
+
+ ATRACE_CALL();
+
+ std::lock_guard<std::mutex> lock(mMutex);
+ mTimeStats.displayEventConnectionsCount =
+ std::max(mTimeStats.displayEventConnectionsCount, count);
+}
+
static int32_t msBetween(nsecs_t start, nsecs_t end) {
int64_t delta = std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::nanoseconds(end - start))
@@ -812,6 +826,7 @@
mTimeStats.missedFrames = 0;
mTimeStats.clientCompositionFrames = 0;
mTimeStats.clientCompositionReusedFrames = 0;
+ mTimeStats.displayEventConnectionsCount = 0;
mTimeStats.displayOnTime = 0;
mTimeStats.presentToPresent.hist.clear();
mTimeStats.frameDuration.hist.clear();
diff --git a/services/surfaceflinger/TimeStats/TimeStats.h b/services/surfaceflinger/TimeStats/TimeStats.h
index a428ef4..ddebeb1 100644
--- a/services/surfaceflinger/TimeStats/TimeStats.h
+++ b/services/surfaceflinger/TimeStats/TimeStats.h
@@ -52,6 +52,9 @@
virtual void incrementMissedFrames() = 0;
virtual void incrementClientCompositionFrames() = 0;
virtual void incrementClientCompositionReusedFrames() = 0;
+ // Records the most up-to-date count of display event connections.
+ // The stored count will be the maximum ever recoded.
+ virtual void recordDisplayEventConnectionCount(int32_t count) = 0;
// Records the start and end times for a frame.
// The start time is the same as the beginning of a SurfaceFlinger
@@ -177,6 +180,10 @@
return AStatsEvent_setAtomId(event, atom_id);
}
+ virtual void statsEventWriteInt32(AStatsEvent* event, int32_t field) {
+ return AStatsEvent_writeInt32(event, field);
+ }
+
virtual void statsEventWriteInt64(AStatsEvent* event, int64_t field) {
return AStatsEvent_writeInt64(event, field);
}
@@ -208,6 +215,7 @@
void incrementMissedFrames() override;
void incrementClientCompositionFrames() override;
void incrementClientCompositionReusedFrames() override;
+ void recordDisplayEventConnectionCount(int32_t count) override;
void recordFrameDuration(nsecs_t startTime, nsecs_t endTime) override;
void recordRenderEngineDuration(nsecs_t startTime, nsecs_t endTime) override;
diff --git a/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h b/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h
index e374b73..5e7c449 100644
--- a/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h
+++ b/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h
@@ -62,6 +62,7 @@
int32_t missedFrames = 0;
int32_t clientCompositionFrames = 0;
int32_t clientCompositionReusedFrames = 0;
+ int32_t displayEventConnectionsCount = 0;
int64_t displayOnTime = 0;
Histogram presentToPresent;
Histogram frameDuration;
diff --git a/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop b/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop
index 764181a..b19eae6 100644
--- a/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop
+++ b/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop
@@ -345,14 +345,26 @@
prop_name: "ro.surface_flinger.set_display_power_timer_ms"
}
+# useContentDetectionForRefreshRate indicates whether Scheduler should detect content FPS, and try
+# to adjust the screen refresh rate based on that.
+prop {
+ api_name: "use_content_detection_for_refresh_rate"
+ type: Boolean
+ scope: Public
+ access: Readonly
+ prop_name: "ro.surface_flinger.use_content_detection_for_refresh_rate"
+}
+
# useSmart90ForVideo indicates whether Scheduler should detect content FPS, and try to adjust the
# screen refresh rate based on that.
+# Replaced by useContentDetectionForRefreshRate
prop {
api_name: "use_smart_90_for_video"
type: Boolean
scope: Public
access: Readonly
prop_name: "ro.surface_flinger.use_smart_90_for_video"
+ deprecated: true
}
prop {
@@ -381,3 +393,13 @@
access: Readonly
prop_name: "ro.surface_flinger.supports_background_blur"
}
+
+# Indicates whether Scheduler should use frame rate API when adjusting the
+# display refresh rate.
+prop {
+ api_name: "use_frame_rate_api"
+ type: Boolean
+ scope: Public
+ access: Readonly
+ prop_name: "ro.surface_flinger.use_frame_rate_api"
+}
diff --git a/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt b/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt
index bee99f4..c66523a 100644
--- a/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt
+++ b/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt
@@ -113,12 +113,21 @@
prop_name: "ro.surface_flinger.use_color_management"
}
prop {
+ api_name: "use_content_detection_for_refresh_rate"
+ prop_name: "ro.surface_flinger.use_content_detection_for_refresh_rate"
+ }
+ prop {
api_name: "use_context_priority"
prop_name: "ro.surface_flinger.use_context_priority"
}
prop {
+ api_name: "use_frame_rate_api"
+ prop_name: "ro.surface_flinger.use_frame_rate_api"
+ }
+ prop {
api_name: "use_smart_90_for_video"
prop_name: "ro.surface_flinger.use_smart_90_for_video"
+ deprecated: true
}
prop {
api_name: "use_vr_flinger"
diff --git a/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp b/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp
index 24874b0..6c8eb27 100644
--- a/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp
+++ b/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp
@@ -531,7 +531,7 @@
ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(bufferLayer, Color::RED, 32, 32));
ASSERT_NO_FATAL_FAILURE(colorLayer =
createLayer("test", 0 /* buffer width */, 0 /* buffer height */,
- ISurfaceComposerClient::eFXSurfaceColor));
+ ISurfaceComposerClient::eFXSurfaceEffect));
Transaction()
.setCrop_legacy(colorLayer, Rect(0, 0, 32, 32))
@@ -570,7 +570,7 @@
Color priorBgColor = Color::BLUE;
Color expectedColor = Color::BLACK;
switch (layerType) {
- case ISurfaceComposerClient::eFXSurfaceColor:
+ case ISurfaceComposerClient::eFXSurfaceEffect:
ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 0, 0, layerType));
Transaction()
.setCrop_legacy(layer, Rect(0, 0, width, height))
@@ -599,7 +599,7 @@
return;
}
- if (priorColor && layerType != ISurfaceComposerClient::eFXSurfaceColor) {
+ if (priorColor && layerType != ISurfaceComposerClient::eFXSurfaceEffect) {
Transaction()
.setBackgroundColor(layer, half3(0, 0, 1.0f), 1.0f, ui::Dataspace::UNKNOWN)
.apply();
@@ -628,7 +628,7 @@
bool bufferFill = false;
float alpha = 1.0f;
Color finalColor = Color::RED;
- ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceColor,
+ ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceEffect,
priorColor, bufferFill, alpha, finalColor));
}
@@ -744,7 +744,7 @@
sp<SurfaceControl> colorLayer;
ASSERT_NO_FATAL_FAILURE(colorLayer =
createLayer("test", 0 /* buffer width */, 0 /* buffer height */,
- ISurfaceComposerClient::eFXSurfaceColor));
+ ISurfaceComposerClient::eFXSurfaceEffect));
Transaction()
.setCrop_legacy(colorLayer, Rect(0, 0, 32, 32))
.setColor(colorLayer, half3(2.0f, -1.0f, 0.0f))
@@ -760,7 +760,7 @@
ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(bufferLayer, Color::RED, 32, 32));
ASSERT_NO_FATAL_FAILURE(colorLayer =
createLayer("test", 0 /* buffer width */, 0 /* buffer height */,
- ISurfaceComposerClient::eFXSurfaceColor));
+ ISurfaceComposerClient::eFXSurfaceEffect));
Transaction().setCrop_legacy(colorLayer, Rect(0, 0, 32, 32)).apply();
const half3 color(15.0f / 255.0f, 51.0f / 255.0f, 85.0f / 255.0f);
@@ -787,7 +787,7 @@
ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(bufferLayer, Color::RED, 32, 32));
ASSERT_NO_FATAL_FAILURE(colorLayer = createLayer("childWithColor", 0 /* buffer width */,
0 /* buffer height */,
- ISurfaceComposerClient::eFXSurfaceColor));
+ ISurfaceComposerClient::eFXSurfaceEffect));
Transaction().setCrop_legacy(colorLayer, Rect(0, 0, 32, 32)).apply();
const half3 color(15.0f / 255.0f, 51.0f / 255.0f, 85.0f / 255.0f);
const float alpha = 0.25f;
@@ -1663,7 +1663,7 @@
sp<SurfaceControl> colorLayer;
ASSERT_NO_FATAL_FAILURE(colorLayer =
createLayer("test", 0 /* buffer width */, 0 /* buffer height */,
- ISurfaceComposerClient::eFXSurfaceColor));
+ ISurfaceComposerClient::eFXSurfaceEffect));
Transaction()
.setCrop_legacy(colorLayer, Rect(0, 0, 32, 32))
.setLayer(colorLayer, mLayerZBase + 1)
@@ -1719,7 +1719,7 @@
ISurfaceComposerClient::eFXSurfaceContainer));
ASSERT_NO_FATAL_FAILURE(
colorLayer = createLayer("test", 0 /* buffer width */, 0 /* buffer height */,
- ISurfaceComposerClient::eFXSurfaceColor, parentLayer.get()));
+ ISurfaceComposerClient::eFXSurfaceEffect, parentLayer.get()));
Transaction()
.setCrop_legacy(parentLayer, Rect(0, 0, 100, 100))
@@ -1780,7 +1780,7 @@
ISurfaceComposerClient::eFXSurfaceContainer));
ASSERT_NO_FATAL_FAILURE(
colorLayer = createLayer("test", 0 /* buffer width */, 0 /* buffer height */,
- ISurfaceComposerClient::eFXSurfaceColor, parentLayer.get()));
+ ISurfaceComposerClient::eFXSurfaceEffect, parentLayer.get()));
Transaction()
.setCrop_legacy(parentLayer, Rect(0, 0, 100, 100))
diff --git a/services/surfaceflinger/tests/LayerTransactionTest.h b/services/surfaceflinger/tests/LayerTransactionTest.h
index 5eb1739..932c7c8 100644
--- a/services/surfaceflinger/tests/LayerTransactionTest.h
+++ b/services/surfaceflinger/tests/LayerTransactionTest.h
@@ -89,7 +89,7 @@
SurfaceControl* parent = nullptr) {
auto colorLayer = createSurface(mClient, name, 0 /* buffer width */, 0 /* buffer height */,
PIXEL_FORMAT_RGBA_8888,
- ISurfaceComposerClient::eFXSurfaceColor, parent);
+ ISurfaceComposerClient::eFXSurfaceEffect, parent);
asTransaction([&](Transaction& t) {
t.setColor(colorLayer, half3{color.r / 255.0f, color.g / 255.0f, color.b / 255.0f});
t.setAlpha(colorLayer, color.a / 255.0f);
@@ -268,7 +268,7 @@
mBlackBgSurface =
createSurface(mClient, "BaseSurface", 0 /* buffer width */, 0 /* buffer height */,
- PIXEL_FORMAT_RGBA_8888, ISurfaceComposerClient::eFXSurfaceColor);
+ PIXEL_FORMAT_RGBA_8888, ISurfaceComposerClient::eFXSurfaceEffect);
// set layer stack (b/68888219)
Transaction t;
diff --git a/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp b/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp
index 3bbd12a..dbace11 100644
--- a/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp
+++ b/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp
@@ -199,10 +199,17 @@
ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", size, size));
ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED, size, size));
- Transaction()
- .setCornerRadius(layer, cornerRadius)
- .setCrop_legacy(layer, Rect(0, 0, size, size))
- .apply();
+ if (mLayerType == ISurfaceComposerClient::eFXSurfaceBufferQueue) {
+ Transaction()
+ .setCornerRadius(layer, cornerRadius)
+ .setCrop_legacy(layer, Rect(0, 0, size, size))
+ .apply();
+ } else {
+ Transaction()
+ .setCornerRadius(layer, cornerRadius)
+ .setFrame(layer, Rect(0, 0, size, size))
+ .apply();
+ }
{
const uint8_t bottom = size - 1;
const uint8_t right = size - 1;
@@ -226,12 +233,21 @@
ASSERT_NO_FATAL_FAILURE(child = createLayer("child", size, size / 2));
ASSERT_NO_FATAL_FAILURE(fillLayerColor(child, Color::GREEN, size, size / 2));
- Transaction()
- .setCornerRadius(parent, cornerRadius)
- .setCrop_legacy(parent, Rect(0, 0, size, size))
- .reparent(child, parent->getHandle())
- .setPosition(child, 0, size / 2)
- .apply();
+ if (mLayerType == ISurfaceComposerClient::eFXSurfaceBufferQueue) {
+ Transaction()
+ .setCornerRadius(parent, cornerRadius)
+ .setCrop_legacy(parent, Rect(0, 0, size, size))
+ .reparent(child, parent->getHandle())
+ .setPosition(child, 0, size / 2)
+ .apply();
+ } else {
+ Transaction()
+ .setCornerRadius(parent, cornerRadius)
+ .setFrame(parent, Rect(0, 0, size, size))
+ .reparent(child, parent->getHandle())
+ .setFrame(child, Rect(0, size / 2, size, size))
+ .apply();
+ }
{
const uint8_t bottom = size - 1;
const uint8_t right = size - 1;
@@ -279,6 +295,48 @@
50 /* tolerance */);
}
+TEST_P(LayerTypeAndRenderTypeTransactionTest, SetBackgroundBlurRadiusOnMultipleLayers) {
+ char value[PROPERTY_VALUE_MAX];
+ property_get("ro.surface_flinger.supports_background_blur", value, "0");
+ if (!atoi(value)) {
+ // This device doesn't support blurs, no-op.
+ return;
+ }
+
+ auto size = 256;
+ auto center = size / 2;
+ auto blurRadius = 50;
+
+ sp<SurfaceControl> backgroundLayer;
+ ASSERT_NO_FATAL_FAILURE(backgroundLayer = createLayer("background", size, size));
+ ASSERT_NO_FATAL_FAILURE(fillLayerColor(backgroundLayer, Color::GREEN, size, size));
+
+ sp<SurfaceControl> leftLayer;
+ ASSERT_NO_FATAL_FAILURE(leftLayer = createLayer("left", size / 2, size));
+ ASSERT_NO_FATAL_FAILURE(fillLayerColor(leftLayer, Color::RED, size / 2, size));
+
+ sp<SurfaceControl> blurLayer1;
+ auto centralSquareSize = size / 2;
+ ASSERT_NO_FATAL_FAILURE(blurLayer1 =
+ createLayer("blur1", centralSquareSize, centralSquareSize));
+ ASSERT_NO_FATAL_FAILURE(
+ fillLayerColor(blurLayer1, Color::BLUE, centralSquareSize, centralSquareSize));
+
+ sp<SurfaceControl> blurLayer2;
+ ASSERT_NO_FATAL_FAILURE(blurLayer2 = createLayer("blur2", size, size));
+ ASSERT_NO_FATAL_FAILURE(
+ fillLayerColor(blurLayer2, Color::TRANSPARENT, centralSquareSize, centralSquareSize));
+
+ Transaction()
+ .setBackgroundBlurRadius(blurLayer1, blurRadius)
+ .setBackgroundBlurRadius(blurLayer2, blurRadius)
+ .apply();
+
+ auto shot = getScreenCapture();
+ shot->expectColor(Rect(center - 5, center - 5, center, center), Color{100, 100, 100, 255},
+ 40 /* tolerance */);
+}
+
TEST_P(LayerTypeAndRenderTypeTransactionTest, SetColorWithBuffer) {
sp<SurfaceControl> bufferLayer;
ASSERT_NO_FATAL_FAILURE(bufferLayer = createLayer("test", 32, 32));
diff --git a/services/surfaceflinger/tests/LayerTypeTransaction_test.cpp b/services/surfaceflinger/tests/LayerTypeTransaction_test.cpp
index 7e9202b..84780ba 100644
--- a/services/surfaceflinger/tests/LayerTypeTransaction_test.cpp
+++ b/services/surfaceflinger/tests/LayerTypeTransaction_test.cpp
@@ -69,13 +69,13 @@
TEST_P(LayerTypeTransactionTest, SetLayerAndRelative) {
sp<SurfaceControl> parent =
LayerTransactionTest::createLayer("Parent", 0 /* buffer width */, 0 /* buffer height */,
- ISurfaceComposerClient::eFXSurfaceColor);
+ ISurfaceComposerClient::eFXSurfaceEffect);
sp<SurfaceControl> childLayer;
ASSERT_NO_FATAL_FAILURE(
childLayer = LayerTransactionTest::createLayer("childLayer", 0 /* buffer width */,
0 /* buffer height */,
- ISurfaceComposerClient::eFXSurfaceColor,
+ ISurfaceComposerClient::eFXSurfaceEffect,
parent.get()));
Transaction()
.setColor(childLayer, half3{1.0f, 0.0f, 0.0f})
@@ -116,17 +116,17 @@
TEST_P(LayerTypeTransactionTest, HideRelativeParentHidesLayer) {
sp<SurfaceControl> parent =
LayerTransactionTest::createLayer("Parent", 0 /* buffer width */, 0 /* buffer height */,
- ISurfaceComposerClient::eFXSurfaceColor);
+ ISurfaceComposerClient::eFXSurfaceEffect);
sp<SurfaceControl> relativeParent =
LayerTransactionTest::createLayer("RelativeParent", 0 /* buffer width */,
0 /* buffer height */,
- ISurfaceComposerClient::eFXSurfaceColor);
+ ISurfaceComposerClient::eFXSurfaceEffect);
sp<SurfaceControl> childLayer;
ASSERT_NO_FATAL_FAILURE(
childLayer = LayerTransactionTest::createLayer("childLayer", 0 /* buffer width */,
0 /* buffer height */,
- ISurfaceComposerClient::eFXSurfaceColor,
+ ISurfaceComposerClient::eFXSurfaceEffect,
parent.get()));
Transaction()
.setColor(childLayer, half3{1.0f, 0.0f, 0.0f})
diff --git a/services/surfaceflinger/tests/LayerUpdate_test.cpp b/services/surfaceflinger/tests/LayerUpdate_test.cpp
index a1c4128..cf3f8e8 100644
--- a/services/surfaceflinger/tests/LayerUpdate_test.cpp
+++ b/services/surfaceflinger/tests/LayerUpdate_test.cpp
@@ -1114,7 +1114,7 @@
TEST_F(BoundlessLayerTest, BoundlessColorLayerFillsParentBufferBounds) {
sp<SurfaceControl> colorLayer =
createSurface(mClient, "ColorLayer", 0, 0, PIXEL_FORMAT_RGBA_8888,
- ISurfaceComposerClient::eFXSurfaceColor, mFGSurfaceControl.get());
+ ISurfaceComposerClient::eFXSurfaceEffect, mFGSurfaceControl.get());
ASSERT_TRUE(colorLayer->isValid());
asTransaction([&](Transaction& t) {
t.setColor(colorLayer, half3{0, 0, 0});
@@ -1139,7 +1139,7 @@
ASSERT_TRUE(cropLayer->isValid());
sp<SurfaceControl> colorLayer =
createSurface(mClient, "ColorLayer", 0, 0, PIXEL_FORMAT_RGBA_8888,
- ISurfaceComposerClient::eFXSurfaceColor, cropLayer.get());
+ ISurfaceComposerClient::eFXSurfaceEffect, cropLayer.get());
ASSERT_TRUE(colorLayer->isValid());
asTransaction([&](Transaction& t) {
t.setCrop_legacy(cropLayer, Rect(5, 5, 10, 10));
@@ -1164,7 +1164,7 @@
TEST_F(BoundlessLayerTest, BoundlessColorLayerTransformHasNoEffect) {
sp<SurfaceControl> colorLayer =
createSurface(mClient, "ColorLayer", 0, 0, PIXEL_FORMAT_RGBA_8888,
- ISurfaceComposerClient::eFXSurfaceColor, mFGSurfaceControl.get());
+ ISurfaceComposerClient::eFXSurfaceEffect, mFGSurfaceControl.get());
ASSERT_TRUE(colorLayer->isValid());
asTransaction([&](Transaction& t) {
t.setPosition(colorLayer, 320, 320);
@@ -1195,7 +1195,7 @@
ASSERT_TRUE(boundlessLayerDownShift->isValid());
sp<SurfaceControl> colorLayer =
createSurface(mClient, "ColorLayer", 0, 0, PIXEL_FORMAT_RGBA_8888,
- ISurfaceComposerClient::eFXSurfaceColor, boundlessLayerDownShift.get());
+ ISurfaceComposerClient::eFXSurfaceEffect, boundlessLayerDownShift.get());
ASSERT_TRUE(colorLayer->isValid());
asTransaction([&](Transaction& t) {
t.setPosition(boundlessLayerRightShift, 32, 0);
@@ -1229,7 +1229,7 @@
ASSERT_TRUE(boundlessLayer->isValid());
sp<SurfaceControl> colorLayer =
mClient->createSurface(String8("ColorLayer"), 0, 0, PIXEL_FORMAT_RGBA_8888,
- ISurfaceComposerClient::eFXSurfaceColor, boundlessLayer.get());
+ ISurfaceComposerClient::eFXSurfaceEffect, boundlessLayer.get());
ASSERT_TRUE(colorLayer != nullptr);
ASSERT_TRUE(colorLayer->isValid());
asTransaction([&](Transaction& t) {
@@ -1261,7 +1261,7 @@
ASSERT_TRUE(rootBoundlessLayer->isValid());
sp<SurfaceControl> colorLayer =
createSurface(mClient, "ColorLayer", 0, 0, PIXEL_FORMAT_RGBA_8888,
- ISurfaceComposerClient::eFXSurfaceColor, rootBoundlessLayer.get());
+ ISurfaceComposerClient::eFXSurfaceEffect, rootBoundlessLayer.get());
ASSERT_TRUE(colorLayer->isValid());
asTransaction([&](Transaction& t) {
diff --git a/services/surfaceflinger/tests/MultiDisplayLayerBounds_test.cpp b/services/surfaceflinger/tests/MultiDisplayLayerBounds_test.cpp
index c9fdc3b..f8a5b40 100644
--- a/services/surfaceflinger/tests/MultiDisplayLayerBounds_test.cpp
+++ b/services/surfaceflinger/tests/MultiDisplayLayerBounds_test.cpp
@@ -66,7 +66,7 @@
void createColorLayer(uint32_t layerStack) {
mColorLayer =
createSurface(mClient, "ColorLayer", 0 /* buffer width */, 0 /* buffer height */,
- PIXEL_FORMAT_RGBA_8888, ISurfaceComposerClient::eFXSurfaceColor);
+ PIXEL_FORMAT_RGBA_8888, ISurfaceComposerClient::eFXSurfaceEffect);
ASSERT_TRUE(mColorLayer != nullptr);
ASSERT_TRUE(mColorLayer->isValid());
asTransaction([&](Transaction& t) {
diff --git a/services/surfaceflinger/tests/SurfaceFlinger_test.filter b/services/surfaceflinger/tests/SurfaceFlinger_test.filter
index 2bedd7d..cf7d570 100644
--- a/services/surfaceflinger/tests/SurfaceFlinger_test.filter
+++ b/services/surfaceflinger/tests/SurfaceFlinger_test.filter
@@ -1,5 +1,5 @@
{
"presubmit": {
- "filter": "*:-LayerTypeAndRenderTypeTransactionTests/LayerTypeAndRenderTypeTransactionTest.SetCornerRadius/2:LayerTypeAndRenderTypeTransactionTests/LayerTypeAndRenderTypeTransactionTest.SetCornerRadius/3:LayerTypeAndRenderTypeTransactionTests/LayerTypeAndRenderTypeTransactionTest.SetCornerRadiusChildCrop/2:LayerTypeAndRenderTypeTransactionTests/LayerTypeAndRenderTypeTransactionTest.SetCornerRadiusChildCrop/3"
+ "filter": ""
}
}
diff --git a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
index e751496..32c58ad 100644
--- a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
+++ b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
@@ -1827,10 +1827,11 @@
protected:
void SetUp() override {
Base::SetUp();
- Base::mChild = Base::mComposerClient->createSurface(String8("Child surface"), 0, 0,
- PIXEL_FORMAT_RGBA_8888,
- ISurfaceComposerClient::eFXSurfaceColor,
- Base::mFGSurfaceControl.get());
+ Base::mChild =
+ Base::mComposerClient->createSurface(String8("Child surface"), 0, 0,
+ PIXEL_FORMAT_RGBA_8888,
+ ISurfaceComposerClient::eFXSurfaceEffect,
+ Base::mFGSurfaceControl.get());
{
TransactionScope ts(*Base::sFakeComposer);
ts.setColor(Base::mChild,
diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
index 888e009..6e83166 100644
--- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
@@ -35,7 +35,7 @@
#include <utils/String8.h>
#include "BufferQueueLayer.h"
-#include "ColorLayer.h"
+#include "EffectLayer.h"
#include "Layer.h"
#include "TestableSurfaceFlinger.h"
#include "mock/DisplayHardware/MockComposer.h"
@@ -713,7 +713,7 @@
struct DefaultLayerProperties : public BaseLayerProperties<DefaultLayerProperties> {};
-struct ColorLayerProperties : public BaseLayerProperties<ColorLayerProperties> {
+struct EffectLayerProperties : public BaseLayerProperties<EffectLayerProperties> {
static constexpr IComposerClient::BlendMode BLENDMODE = IComposerClient::BlendMode::NONE;
};
@@ -866,16 +866,16 @@
};
template <typename LayerProperties>
-struct ColorLayerVariant : public BaseLayerVariant<LayerProperties> {
+struct EffectLayerVariant : public BaseLayerVariant<LayerProperties> {
using Base = BaseLayerVariant<LayerProperties>;
- using FlingerLayerType = sp<ColorLayer>;
+ using FlingerLayerType = sp<EffectLayer>;
static FlingerLayerType createLayer(CompositionTest* test) {
- FlingerLayerType layer = Base::template createLayerWithFactory<ColorLayer>(test, [test]() {
- return new ColorLayer(LayerCreationArgs(test->mFlinger.mFlinger.get(), sp<Client>(),
- "test-layer", LayerProperties::WIDTH,
- LayerProperties::HEIGHT,
- LayerProperties::LAYER_FLAGS, LayerMetadata()));
+ FlingerLayerType layer = Base::template createLayerWithFactory<EffectLayer>(test, [test]() {
+ return new EffectLayer(
+ LayerCreationArgs(test->mFlinger.mFlinger.get(), sp<Client>(), "test-layer",
+ LayerProperties::WIDTH, LayerProperties::HEIGHT,
+ LayerProperties::LAYER_FLAGS, LayerMetadata()));
});
auto& layerDrawingState = test->mFlinger.mutableLayerDrawingState(layer);
@@ -1228,31 +1228,31 @@
* Single-color layers
*/
-TEST_F(CompositionTest, HWCComposedColorLayerWithDirtyGeometry) {
+TEST_F(CompositionTest, HWCComposedEffectLayerWithDirtyGeometry) {
displayRefreshCompositionDirtyGeometry<
- CompositionCase<DefaultDisplaySetupVariant, ColorLayerVariant<ColorLayerProperties>,
+ CompositionCase<DefaultDisplaySetupVariant, EffectLayerVariant<EffectLayerProperties>,
KeepCompositionTypeVariant<IComposerClient::Composition::SOLID_COLOR>,
HwcCompositionResultVariant>>();
}
-TEST_F(CompositionTest, HWCComposedColorLayerWithDirtyFrame) {
+TEST_F(CompositionTest, HWCComposedEffectLayerWithDirtyFrame) {
displayRefreshCompositionDirtyFrame<
- CompositionCase<DefaultDisplaySetupVariant, ColorLayerVariant<ColorLayerProperties>,
+ CompositionCase<DefaultDisplaySetupVariant, EffectLayerVariant<EffectLayerProperties>,
KeepCompositionTypeVariant<IComposerClient::Composition::SOLID_COLOR>,
HwcCompositionResultVariant>>();
}
-TEST_F(CompositionTest, REComposedColorLayer) {
+TEST_F(CompositionTest, REComposedEffectLayer) {
displayRefreshCompositionDirtyFrame<
- CompositionCase<DefaultDisplaySetupVariant, ColorLayerVariant<ColorLayerProperties>,
+ CompositionCase<DefaultDisplaySetupVariant, EffectLayerVariant<EffectLayerProperties>,
ChangeCompositionTypeVariant<IComposerClient::Composition::SOLID_COLOR,
IComposerClient::Composition::CLIENT>,
RECompositionResultVariant>>();
}
-TEST_F(CompositionTest, captureScreenColorLayer) {
+TEST_F(CompositionTest, captureScreenEffectLayer) {
captureScreenComposition<
- CompositionCase<DefaultDisplaySetupVariant, ColorLayerVariant<ColorLayerProperties>,
+ CompositionCase<DefaultDisplaySetupVariant, EffectLayerVariant<EffectLayerProperties>,
NoCompositionTypeVariant, REScreenshotResultVariant>>();
}
diff --git a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
index 61d4f47..65b3e35 100644
--- a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
+++ b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
@@ -19,9 +19,7 @@
#include <gmock/gmock.h>
#include <gtest/gtest.h>
-
#include <log/log.h>
-
#include <utils/Errors.h>
#include "AsyncCallRecorder.h"
@@ -401,6 +399,34 @@
expectVSyncSetEnabledCallReceived(false);
}
+TEST_F(EventThreadTest, tracksEventConnections) {
+ EXPECT_EQ(1, mThread->getEventThreadConnectionCount());
+ ConnectionEventRecorder errorConnectionEventRecorder{NO_MEMORY};
+ sp<MockEventThreadConnection> errorConnection =
+ createConnection(errorConnectionEventRecorder,
+ ISurfaceComposer::eConfigChangedSuppress);
+ mThread->setVsyncRate(1, errorConnection);
+ EXPECT_EQ(2, mThread->getEventThreadConnectionCount());
+ ConnectionEventRecorder secondConnectionEventRecorder{0};
+ sp<MockEventThreadConnection> secondConnection =
+ createConnection(secondConnectionEventRecorder,
+ ISurfaceComposer::eConfigChangedSuppress);
+ mThread->setVsyncRate(1, secondConnection);
+ EXPECT_EQ(3, mThread->getEventThreadConnectionCount());
+
+ // EventThread should enable vsync callbacks.
+ expectVSyncSetEnabledCallReceived(true);
+
+ // The first event will be seen by the interceptor, and by the connection,
+ // which then returns an error.
+ mCallback->onVSyncEvent(123);
+ expectInterceptCallReceived(123);
+ expectVsyncEventReceivedByConnection("errorConnection", errorConnectionEventRecorder, 123, 1u);
+ expectVsyncEventReceivedByConnection("successConnection", secondConnectionEventRecorder, 123,
+ 1u);
+ EXPECT_EQ(2, mThread->getEventThreadConnectionCount());
+}
+
TEST_F(EventThreadTest, eventsDroppedIfNonfatalEventDeliveryError) {
ConnectionEventRecorder errorConnectionEventRecorder{WOULD_BLOCK};
sp<MockEventThreadConnection> errorConnection =
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
index 841c624..99c5f3d 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
@@ -745,6 +745,44 @@
}
}
+TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_getRefreshRateForContentV2_Multiples) {
+ std::vector<RefreshRateConfigs::InputConfig> configs{
+ {{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60},
+ {HWC_CONFIG_ID_90, HWC_GROUP_ID_0, VSYNC_90}}};
+ auto refreshRateConfigs =
+ std::make_unique<RefreshRateConfigs>(configs, /*currentConfigId=*/HWC_CONFIG_ID_60);
+
+ RefreshRate expected60Config = {HWC_CONFIG_ID_60, VSYNC_60, HWC_GROUP_ID_0, "60fps", 60};
+ RefreshRate expected90Config = {HWC_CONFIG_ID_90, VSYNC_90, HWC_GROUP_ID_0, "90fps", 90};
+
+ auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f},
+ LayerRequirement{.weight = 1.0f}};
+ auto& lr1 = layers[0];
+ auto& lr2 = layers[1];
+
+ lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
+ lr1.desiredRefreshRate = 60.0f;
+ lr2.vote = LayerVoteType::Heuristic;
+ lr2.desiredRefreshRate = 90.0f;
+ EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+
+ lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
+ lr1.desiredRefreshRate = 60.0f;
+ lr2.vote = LayerVoteType::Max;
+ EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+
+ lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
+ lr1.desiredRefreshRate = 30.0f;
+ lr2.vote = LayerVoteType::Heuristic;
+ lr2.desiredRefreshRate = 90.0f;
+ EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+
+ lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
+ lr1.desiredRefreshRate = 30.0f;
+ lr2.vote = LayerVoteType::Max;
+ EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+}
+
} // namespace
} // namespace scheduler
} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateSelectionTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateSelectionTest.cpp
index cffdc14..edd9de4 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateSelectionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateSelectionTest.cpp
@@ -27,7 +27,7 @@
#include "BufferQueueLayer.h"
#include "BufferStateLayer.h"
-#include "ColorLayer.h"
+#include "EffectLayer.h"
#include "Layer.h"
#include "TestableSurfaceFlinger.h"
#include "mock/DisplayHardware/MockComposer.h"
@@ -68,7 +68,7 @@
void setupComposer(int virtualDisplayCount);
sp<BufferQueueLayer> createBufferQueueLayer();
sp<BufferStateLayer> createBufferStateLayer();
- sp<ColorLayer> createColorLayer();
+ sp<EffectLayer> createEffectLayer();
void setParent(Layer* child, Layer* parent);
void commitTransaction(Layer* layer);
@@ -111,11 +111,11 @@
return new BufferStateLayer(args);
}
-sp<ColorLayer> RefreshRateSelectionTest::createColorLayer() {
+sp<EffectLayer> RefreshRateSelectionTest::createEffectLayer() {
sp<Client> client;
LayerCreationArgs args(mFlinger.flinger(), client, "color-layer", WIDTH, HEIGHT, LAYER_FLAGS,
LayerMetadata());
- return new ColorLayer(args);
+ return new EffectLayer(args);
}
void RefreshRateSelectionTest::setParent(Layer* child, Layer* parent) {
@@ -244,11 +244,11 @@
ASSERT_EQ(1, mGrandChild->getFrameRateSelectionPriority());
}
-TEST_F(RefreshRateSelectionTest, testPriorityOnColorLayers) {
- mParent = createColorLayer();
- mChild = createColorLayer();
+TEST_F(RefreshRateSelectionTest, testPriorityOnEffectLayers) {
+ mParent = createEffectLayer();
+ mChild = createEffectLayer();
setParent(mChild.get(), mParent.get());
- mGrandChild = createColorLayer();
+ mGrandChild = createEffectLayer();
setParent(mGrandChild.get(), mChild.get());
ASSERT_EQ(PRIORITY_UNSET, mParent->getFrameRateSelectionPriority());
diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
index 89002a8..5db11ec 100644
--- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
@@ -159,6 +159,11 @@
EXPECT_CALL(*mEventThread, setPhaseOffset(10)).Times(1);
ASSERT_NO_FATAL_FAILURE(mScheduler->setPhaseOffset(mConnectionHandle, 10));
+
+ static constexpr size_t kEventConnections = 5;
+ ON_CALL(*mEventThread, getEventThreadConnectionCount())
+ .WillByDefault(Return(kEventConnections));
+ EXPECT_EQ(kEventConnections, mScheduler->getEventThreadConnectionCount(mConnectionHandle));
}
} // namespace
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index 798ba76..685cfaf 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -25,9 +25,9 @@
#include "BufferQueueLayer.h"
#include "BufferStateLayer.h"
-#include "ColorLayer.h"
#include "ContainerLayer.h"
#include "DisplayDevice.h"
+#include "EffectLayer.h"
#include "FakePhaseOffsets.h"
#include "Layer.h"
#include "NativeWindowSurface.h"
@@ -147,9 +147,7 @@
return nullptr;
}
- sp<ColorLayer> createColorLayer(const LayerCreationArgs&) override {
- return nullptr;
- }
+ sp<EffectLayer> createEffectLayer(const LayerCreationArgs&) override { return nullptr; }
sp<ContainerLayer> createContainerLayer(const LayerCreationArgs&) override {
return nullptr;
diff --git a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
index 91a40d0..685dfba 100644
--- a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
@@ -166,6 +166,7 @@
MOCK_METHOD1(unregisterStatsPullAtomCallback, void(int32_t));
MOCK_METHOD2(statsEventSetAtomId, void(AStatsEvent*, uint32_t));
+ MOCK_METHOD2(statsEventWriteInt32, void(AStatsEvent*, int32_t));
MOCK_METHOD2(statsEventWriteInt64, void(AStatsEvent*, int64_t));
MOCK_METHOD2(statsEventWriteString8, void(AStatsEvent*, const char*));
MOCK_METHOD3(statsEventWriteByteArray, void(AStatsEvent*, const uint8_t*, size_t));
@@ -800,6 +801,7 @@
constexpr size_t TOTAL_FRAMES = 5;
constexpr size_t MISSED_FRAMES = 4;
constexpr size_t CLIENT_COMPOSITION_FRAMES = 3;
+ constexpr size_t DISPLAY_EVENT_CONNECTIONS = 14;
mTimeStats->onBootFinished();
EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
@@ -814,6 +816,8 @@
mTimeStats->incrementClientCompositionFrames();
}
+ mTimeStats->recordDisplayEventConnectionCount(DISPLAY_EVENT_CONNECTIONS);
+
mTimeStats->setPowerMode(HWC_POWER_MODE_NORMAL);
mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(3000000));
mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(5000000));
@@ -834,6 +838,7 @@
EXPECT_CALL(*mDelegate, statsEventWriteInt64(mDelegate->mEvent, CLIENT_COMPOSITION_FRAMES));
EXPECT_CALL(*mDelegate, statsEventWriteInt64(mDelegate->mEvent, _));
EXPECT_CALL(*mDelegate, statsEventWriteInt64(mDelegate->mEvent, 2));
+ EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, DISPLAY_EVENT_CONNECTIONS));
EXPECT_CALL(*mDelegate, statsEventBuild(mDelegate->mEvent));
}
EXPECT_EQ(AStatsManager_PULL_SUCCESS,
@@ -892,12 +897,20 @@
return expected == actual;
}
-TEST_F(TimeStatsTest, layerStatsCallback_pullsAllHistogramsAndClears) {
+TEST_F(TimeStatsTest, layerStatsCallback_pullsAllAndClears) {
+ constexpr size_t LATE_ACQUIRE_FRAMES = 2;
+ constexpr size_t BAD_DESIRED_PRESENT_FRAMES = 3;
EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
mTimeStats->onBootFinished();
insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000);
+ for (size_t i = 0; i < LATE_ACQUIRE_FRAMES; i++) {
+ mTimeStats->incrementLatchSkipped(LAYER_ID_0, TimeStats::LatchSkipReason::LateAcquire);
+ }
+ for (size_t i = 0; i < BAD_DESIRED_PRESENT_FRAMES; i++) {
+ mTimeStats->incrementBadDesiredPresent(LAYER_ID_0);
+ }
insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 2, 2000000);
EXPECT_THAT(mDelegate->mAtomTags,
@@ -955,6 +968,9 @@
BytesEq((const uint8_t*)expectedPostToAcquire.c_str(),
expectedPostToAcquire.size()),
expectedPostToAcquire.size()));
+ EXPECT_CALL(*mDelegate, statsEventWriteInt64(mDelegate->mEvent, LATE_ACQUIRE_FRAMES));
+ EXPECT_CALL(*mDelegate,
+ statsEventWriteInt64(mDelegate->mEvent, BAD_DESIRED_PRESENT_FRAMES));
EXPECT_CALL(*mDelegate, statsEventBuild(mDelegate->mEvent));
}
EXPECT_EQ(AStatsManager_PULL_SUCCESS,
diff --git a/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp b/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp
index 6ec3844..f834af8 100644
--- a/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp
+++ b/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp
@@ -36,7 +36,7 @@
namespace android::scheduler {
MATCHER_P2(IsCloseTo, value, tolerance, "is within tolerance") {
- return arg <= value + tolerance && value >= value - tolerance;
+ return arg <= value + tolerance && arg >= value - tolerance;
}
std::vector<nsecs_t> generateVsyncTimestamps(size_t count, nsecs_t period, nsecs_t bias) {
@@ -370,6 +370,26 @@
IsCloseTo(idealPeriod, mMaxRoundingError));
}
+TEST_F(VSyncPredictorTest, slopeAlwaysValid) {
+ constexpr auto kNumVsyncs = 100;
+ auto invalidPeriod = mPeriod;
+ auto now = 0;
+ for (int i = 0; i < kNumVsyncs; i++) {
+ tracker.addVsyncTimestamp(now);
+ now += invalidPeriod;
+ invalidPeriod *= 0.9f;
+
+ auto [slope, intercept] = tracker.getVSyncPredictionModel();
+ EXPECT_THAT(slope, IsCloseTo(mPeriod, mPeriod * kOutlierTolerancePercent / 100.f));
+
+ // When VsyncPredictor returns the period it means that it doesn't know how to predict and
+ // it needs to get more samples
+ if (slope == mPeriod && intercept == 0) {
+ EXPECT_TRUE(tracker.needsMoreSamples(now));
+ }
+ }
+}
+
} // namespace android::scheduler
// TODO(b/129481165): remove the #pragma below and fix conversion issues
diff --git a/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp b/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp
index 1de72b9..2f36bb2 100644
--- a/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp
+++ b/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp
@@ -250,9 +250,9 @@
nsecs_t const newPeriod = 5000;
mReactor.setPeriod(newPeriod);
- EXPECT_TRUE(mReactor.addResyncSample(0, &periodFlushed));
+ EXPECT_TRUE(mReactor.addResyncSample(0, std::nullopt, &periodFlushed));
EXPECT_FALSE(periodFlushed);
- EXPECT_FALSE(mReactor.addResyncSample(newPeriod, &periodFlushed));
+ EXPECT_FALSE(mReactor.addResyncSample(newPeriod, std::nullopt, &periodFlushed));
EXPECT_TRUE(periodFlushed);
EXPECT_TRUE(mReactor.addPresentFence(generateSignalledFenceWithTime(0)));
@@ -302,16 +302,16 @@
mReactor.setPeriod(newPeriod);
bool periodFlushed = true;
- EXPECT_TRUE(mReactor.addResyncSample(10000, &periodFlushed));
+ EXPECT_TRUE(mReactor.addResyncSample(10000, std::nullopt, &periodFlushed));
EXPECT_FALSE(periodFlushed);
- EXPECT_TRUE(mReactor.addResyncSample(20000, &periodFlushed));
+ EXPECT_TRUE(mReactor.addResyncSample(20000, std::nullopt, &periodFlushed));
EXPECT_FALSE(periodFlushed);
Mock::VerifyAndClearExpectations(mMockTracker.get());
EXPECT_CALL(*mMockTracker, setPeriod(newPeriod)).Times(1);
- EXPECT_FALSE(mReactor.addResyncSample(25000, &periodFlushed));
+ EXPECT_FALSE(mReactor.addResyncSample(25000, std::nullopt, &periodFlushed));
EXPECT_TRUE(periodFlushed);
}
@@ -320,14 +320,14 @@
nsecs_t const newPeriod = 5000;
mReactor.setPeriod(newPeriod);
bool periodFlushed = true;
- EXPECT_TRUE(mReactor.addResyncSample(sampleTime += period, &periodFlushed));
+ EXPECT_TRUE(mReactor.addResyncSample(sampleTime += period, std::nullopt, &periodFlushed));
EXPECT_FALSE(periodFlushed);
- EXPECT_TRUE(mReactor.addResyncSample(sampleTime += period, &periodFlushed));
+ EXPECT_TRUE(mReactor.addResyncSample(sampleTime += period, std::nullopt, &periodFlushed));
EXPECT_FALSE(periodFlushed);
mReactor.setPeriod(period);
- EXPECT_FALSE(mReactor.addResyncSample(sampleTime += period, &periodFlushed));
+ EXPECT_FALSE(mReactor.addResyncSample(sampleTime += period, std::nullopt, &periodFlushed));
EXPECT_FALSE(periodFlushed);
}
@@ -338,14 +338,14 @@
mReactor.setPeriod(secondPeriod);
bool periodFlushed = true;
- EXPECT_TRUE(mReactor.addResyncSample(sampleTime += period, &periodFlushed));
+ EXPECT_TRUE(mReactor.addResyncSample(sampleTime += period, std::nullopt, &periodFlushed));
EXPECT_FALSE(periodFlushed);
- EXPECT_TRUE(mReactor.addResyncSample(sampleTime += period, &periodFlushed));
+ EXPECT_TRUE(mReactor.addResyncSample(sampleTime += period, std::nullopt, &periodFlushed));
EXPECT_FALSE(periodFlushed);
mReactor.setPeriod(thirdPeriod);
- EXPECT_TRUE(mReactor.addResyncSample(sampleTime += secondPeriod, &periodFlushed));
+ EXPECT_TRUE(mReactor.addResyncSample(sampleTime += secondPeriod, std::nullopt, &periodFlushed));
EXPECT_FALSE(periodFlushed);
- EXPECT_FALSE(mReactor.addResyncSample(sampleTime += thirdPeriod, &periodFlushed));
+ EXPECT_FALSE(mReactor.addResyncSample(sampleTime += thirdPeriod, std::nullopt, &periodFlushed));
EXPECT_TRUE(periodFlushed);
}
@@ -360,9 +360,9 @@
nsecs_t skewyPeriod = period >> 1;
bool periodFlushed = false;
nsecs_t sampleTime = 0;
- EXPECT_TRUE(mReactor.addResyncSample(sampleTime += skewyPeriod, &periodFlushed));
+ EXPECT_TRUE(mReactor.addResyncSample(sampleTime += skewyPeriod, std::nullopt, &periodFlushed));
EXPECT_FALSE(periodFlushed);
- EXPECT_FALSE(mReactor.addResyncSample(sampleTime += period, &periodFlushed));
+ EXPECT_FALSE(mReactor.addResyncSample(sampleTime += period, std::nullopt, &periodFlushed));
EXPECT_FALSE(periodFlushed);
}
@@ -390,12 +390,12 @@
mReactor.setPeriod(newPeriod);
bool periodFlushed = true;
- EXPECT_TRUE(mReactor.addResyncSample(5000, &periodFlushed));
+ EXPECT_TRUE(mReactor.addResyncSample(5000, std::nullopt, &periodFlushed));
EXPECT_FALSE(periodFlushed);
Mock::VerifyAndClearExpectations(mMockTracker.get());
EXPECT_CALL(*mMockTracker, setPeriod(newPeriod)).Times(1);
- EXPECT_FALSE(mReactor.addResyncSample(10000, &periodFlushed));
+ EXPECT_FALSE(mReactor.addResyncSample(10000, std::nullopt, &periodFlushed));
EXPECT_TRUE(periodFlushed);
}
@@ -404,7 +404,7 @@
bool periodFlushed = false;
EXPECT_CALL(*mMockTracker, addVsyncTimestamp(fakeTimestamp));
- EXPECT_FALSE(mReactor.addResyncSample(fakeTimestamp, &periodFlushed));
+ EXPECT_FALSE(mReactor.addResyncSample(fakeTimestamp, std::nullopt, &periodFlushed));
EXPECT_FALSE(periodFlushed);
}
@@ -418,17 +418,17 @@
auto constexpr numTimestampSubmissions = 10;
for (auto i = 0; i < numTimestampSubmissions; i++) {
time += period;
- EXPECT_TRUE(mReactor.addResyncSample(time, &periodFlushed));
+ EXPECT_TRUE(mReactor.addResyncSample(time, std::nullopt, &periodFlushed));
EXPECT_FALSE(periodFlushed);
}
time += newPeriod;
- EXPECT_FALSE(mReactor.addResyncSample(time, &periodFlushed));
+ EXPECT_FALSE(mReactor.addResyncSample(time, std::nullopt, &periodFlushed));
EXPECT_TRUE(periodFlushed);
for (auto i = 0; i < numTimestampSubmissions; i++) {
time += newPeriod;
- EXPECT_FALSE(mReactor.addResyncSample(time, &periodFlushed));
+ EXPECT_FALSE(mReactor.addResyncSample(time, std::nullopt, &periodFlushed));
EXPECT_FALSE(periodFlushed);
}
}
@@ -440,11 +440,11 @@
mReactor.setPeriod(newPeriod);
time += period;
- mReactor.addResyncSample(time, &periodFlushed);
+ mReactor.addResyncSample(time, std::nullopt, &periodFlushed);
EXPECT_TRUE(mReactor.addPresentFence(generateSignalledFenceWithTime(0)));
time += newPeriod;
- mReactor.addResyncSample(time, &periodFlushed);
+ mReactor.addResyncSample(time, std::nullopt, &periodFlushed);
EXPECT_FALSE(mReactor.addPresentFence(generateSignalledFenceWithTime(0)));
}
@@ -568,8 +568,8 @@
bool periodFlushed = false;
mReactor.setPeriod(anotherPeriod);
- EXPECT_TRUE(mReactor.addResyncSample(anotherPeriod, &periodFlushed));
- EXPECT_FALSE(mReactor.addResyncSample(anotherPeriod * 2, &periodFlushed));
+ EXPECT_TRUE(mReactor.addResyncSample(anotherPeriod, std::nullopt, &periodFlushed));
+ EXPECT_FALSE(mReactor.addResyncSample(anotherPeriod * 2, std::nullopt, &periodFlushed));
mReactor.addEventListener(mName, mPhase, &outerCb, lastCallbackTime);
}
@@ -614,6 +614,24 @@
mReactor.beginResync();
}
+TEST_F(VSyncReactorTest, periodChangeWithGivenVsyncPeriod) {
+ bool periodFlushed = true;
+ EXPECT_CALL(*mMockTracker, addVsyncTimestamp(_)).Times(3);
+ mReactor.setIgnorePresentFences(true);
+
+ nsecs_t const newPeriod = 5000;
+ mReactor.setPeriod(newPeriod);
+
+ EXPECT_TRUE(mReactor.addResyncSample(0, 0, &periodFlushed));
+ EXPECT_FALSE(periodFlushed);
+ EXPECT_TRUE(mReactor.addResyncSample(newPeriod, 0, &periodFlushed));
+ EXPECT_FALSE(periodFlushed);
+ EXPECT_FALSE(mReactor.addResyncSample(newPeriod, newPeriod, &periodFlushed));
+ EXPECT_TRUE(periodFlushed);
+
+ EXPECT_TRUE(mReactor.addPresentFence(generateSignalledFenceWithTime(0)));
+}
+
using VSyncReactorDeathTest = VSyncReactorTest;
TEST_F(VSyncReactorDeathTest, invalidRemoval) {
mReactor.addEventListener(mName, mPhase, &outerCb, lastCallbackTime);
diff --git a/services/surfaceflinger/tests/unittests/mock/MockDispSync.h b/services/surfaceflinger/tests/unittests/mock/MockDispSync.h
index 9ca116d..a2ae6c9 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockDispSync.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockDispSync.h
@@ -31,7 +31,7 @@
MOCK_METHOD0(reset, void());
MOCK_METHOD1(addPresentFence, bool(const std::shared_ptr<FenceTime>&));
MOCK_METHOD0(beginResync, void());
- MOCK_METHOD2(addResyncSample, bool(nsecs_t, bool*));
+ MOCK_METHOD3(addResyncSample, bool(nsecs_t, std::optional<nsecs_t>, bool*));
MOCK_METHOD0(endResync, void());
MOCK_METHOD1(setPeriod, void(nsecs_t));
MOCK_METHOD0(getPeriod, nsecs_t());
diff --git a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
index 9bda095..50eb390 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
@@ -42,6 +42,7 @@
MOCK_METHOD1(requestNextVsync, void(const sp<android::EventThreadConnection> &));
MOCK_METHOD0(requestLatestConfig, void());
MOCK_METHOD1(pauseVsyncCallback, void(bool));
+ MOCK_METHOD0(getEventThreadConnectionCount, size_t());
};
} // namespace mock
diff --git a/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h b/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h
index 2720537..c45d584 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h
@@ -36,6 +36,7 @@
MOCK_METHOD0(incrementMissedFrames, void());
MOCK_METHOD0(incrementClientCompositionFrames, void());
MOCK_METHOD0(incrementClientCompositionReusedFrames, void());
+ MOCK_METHOD1(recordDisplayEventConnectionCount, void(int32_t));
MOCK_METHOD2(recordFrameDuration, void(nsecs_t, nsecs_t));
MOCK_METHOD2(recordRenderEngineDuration, void(nsecs_t, nsecs_t));
MOCK_METHOD2(recordRenderEngineDuration, void(nsecs_t, const std::shared_ptr<FenceTime>&));