Merge "Add TEST_MAPPING for atrace"
diff --git a/cmds/atrace/atrace.cpp b/cmds/atrace/atrace.cpp
index bd3d2d8..5836f11 100644
--- a/cmds/atrace/atrace.cpp
+++ b/cmds/atrace/atrace.cpp
@@ -193,10 +193,12 @@
{ REQ, "events/cpufreq_interactive/enable" },
} },
{ "sync", "Synchronization", 0, {
- // before linux kernel 4.9
+ // linux kernel < 4.9
{ OPT, "events/sync/enable" },
- // starting in linux kernel 4.9
+ // linux kernel == 4.9.x
{ OPT, "events/fence/enable" },
+ // linux kernel > 4.9
+ { OPT, "events/dma_fence/enable" },
} },
{ "workq", "Kernel Workqueues", 0, {
{ REQ, "events/workqueue/enable" },
diff --git a/cmds/atrace/atrace.rc b/cmds/atrace/atrace.rc
index a282424..66c9cc6 100644
--- a/cmds/atrace/atrace.rc
+++ b/cmds/atrace/atrace.rc
@@ -91,6 +91,8 @@
chmod 0666 /sys/kernel/tracing/events/sync/enable
chmod 0666 /sys/kernel/debug/tracing/events/fence/enable
chmod 0666 /sys/kernel/tracing/events/fence/enable
+ chmod 0666 /sys/kernel/debug/tracing/events/dma_fence/enable
+ chmod 0666 /sys/kernel/tracing/events/dma_fence/enable
chmod 0666 /sys/kernel/debug/tracing/events/kmem/rss_stat/enable
chmod 0666 /sys/kernel/tracing/events/kmem/rss_stat/enable
chmod 0666 /sys/kernel/debug/tracing/events/kmem/ion_heap_grow/enable
diff --git a/cmds/dumpstate/DumpstateService.cpp b/cmds/dumpstate/DumpstateService.cpp
index 768cb4f..ddae9ea 100644
--- a/cmds/dumpstate/DumpstateService.cpp
+++ b/cmds/dumpstate/DumpstateService.cpp
@@ -127,7 +127,7 @@
if (ds_ != nullptr) {
MYLOGE("Error! There is already a bugreport in progress. Returning.");
if (listener != nullptr) {
- listener->onError(IDumpstateListener::BUGREPORT_ERROR_CONCURRENT_BUGREPORTS_FORBIDDEN);
+ listener->onError(IDumpstateListener::BUGREPORT_ERROR_ANOTHER_REPORT_IN_PROGRESS);
}
return exception(binder::Status::EX_SERVICE_SPECIFIC,
"There is already a bugreport in progress");
diff --git a/cmds/dumpstate/binder/android/os/IDumpstateListener.aidl b/cmds/dumpstate/binder/android/os/IDumpstateListener.aidl
index 42858e0..ea1e467 100644
--- a/cmds/dumpstate/binder/android/os/IDumpstateListener.aidl
+++ b/cmds/dumpstate/binder/android/os/IDumpstateListener.aidl
@@ -50,7 +50,7 @@
const int BUGREPORT_ERROR_USER_CONSENT_TIMED_OUT = 4;
/* There is currently a bugreport running. The caller should try again later. */
- const int BUGREPORT_ERROR_CONCURRENT_BUGREPORTS_FORBIDDEN = 5;
+ const int BUGREPORT_ERROR_ANOTHER_REPORT_IN_PROGRESS = 5;
/**
* Called on an error condition with one of the error codes listed above.
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 60a7de2..21de4db 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -766,6 +766,17 @@
ZipWriter::ErrorCodeString(err));
return UNKNOWN_ERROR;
}
+ bool finished_entry = false;
+ auto finish_entry = [this, &finished_entry] {
+ if (!finished_entry) {
+ // This should only be called when we're going to return an earlier error,
+ // which would've been logged. This may imply the file is already corrupt
+ // and any further logging from FinishEntry is more likely to mislead than
+ // not.
+ this->zip_writer_->FinishEntry();
+ }
+ };
+ auto scope_guard = android::base::make_scope_guard(finish_entry);
auto start = std::chrono::steady_clock::now();
auto end = start + timeout;
struct pollfd pfd = {fd, POLLIN};
@@ -782,11 +793,11 @@
int rc = TEMP_FAILURE_RETRY(poll(&pfd, 1, time_left_ms()));
if (rc < 0) {
- MYLOGE("Error in poll while adding from fd to zip entry %s:%s", entry_name.c_str(),
- strerror(errno));
+ MYLOGE("Error in poll while adding from fd to zip entry %s:%s\n",
+ entry_name.c_str(), strerror(errno));
return -errno;
} else if (rc == 0) {
- MYLOGE("Timed out adding from fd to zip entry %s:%s Timeout:%lldms",
+ MYLOGE("Timed out adding from fd to zip entry %s:%s Timeout:%lldms\n",
entry_name.c_str(), strerror(errno), timeout.count());
return TIMED_OUT;
}
@@ -807,6 +818,7 @@
}
err = zip_writer_->FinishEntry();
+ finished_entry = true;
if (err != 0) {
MYLOGE("zip_writer_->FinishEntry(): %s\n", ZipWriter::ErrorCodeString(err));
return UNKNOWN_ERROR;
@@ -1740,7 +1752,9 @@
}
// TODO: Should truncate the existing file.
// ... and re-open it for further logging.
- redirect_to_existing_file(stderr, const_cast<char*>(ds.log_path_.c_str()));
+ if (!redirect_to_existing_file(stderr, const_cast<char*>(ds.log_path_.c_str()))) {
+ return false;
+ }
fprintf(stderr, "\n");
int32_t err = zip_writer_->Finish();
@@ -2360,12 +2374,17 @@
// If we are going to use a socket, do it as early as possible
// to avoid timeouts from bugreport.
if (options_->use_socket) {
- redirect_to_socket(stdout, "dumpstate");
+ if (!redirect_to_socket(stdout, "dumpstate")) {
+ return ERROR;
+ }
}
if (options_->use_control_socket) {
MYLOGD("Opening control socket\n");
control_socket_fd_ = open_socket("dumpstate");
+ if (control_socket_fd_ == -1) {
+ return ERROR;
+ }
options_->do_progress_updates = 1;
}
@@ -2424,7 +2443,9 @@
if (is_redirecting) {
// Redirect stderr to log_path_ for debugging.
TEMP_FAILURE_RETRY(dup_stderr_fd = dup(fileno(stderr)));
- redirect_to_file(stderr, const_cast<char*>(log_path_.c_str()));
+ if (!redirect_to_file(stderr, const_cast<char*>(log_path_.c_str()))) {
+ return ERROR;
+ }
if (chown(log_path_.c_str(), AID_SHELL, AID_SHELL)) {
MYLOGE("Unable to change ownership of dumpstate log file %s: %s\n", log_path_.c_str(),
strerror(errno));
@@ -2437,7 +2458,9 @@
/* TODO: rather than generating a text file now and zipping it later,
it would be more efficient to redirect stdout to the zip entry
directly, but the libziparchive doesn't support that option yet. */
- redirect_to_file(stdout, const_cast<char*>(tmp_path_.c_str()));
+ if (!redirect_to_file(stdout, const_cast<char*>(tmp_path_.c_str()))) {
+ return ERROR;
+ }
if (chown(tmp_path_.c_str(), AID_SHELL, AID_SHELL)) {
MYLOGE("Unable to change ownership of temporary bugreport file %s: %s\n",
tmp_path_.c_str(), strerror(errno));
diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h
index 9803f00..c326bb6 100644
--- a/cmds/dumpstate/dumpstate.h
+++ b/cmds/dumpstate/dumpstate.h
@@ -519,14 +519,26 @@
/** opens a socket and returns its file descriptor */
int open_socket(const char *service);
-/* redirect output to a service control socket */
-void redirect_to_socket(FILE *redirect, const char *service);
+/*
+ * Redirects 'redirect' to a service control socket.
+ *
+ * Returns true if redirect succeeds.
+ */
+bool redirect_to_socket(FILE* redirect, const char* service);
-/* redirect output to a new file */
-void redirect_to_file(FILE *redirect, char *path);
+/*
+ * Redirects 'redirect' to a file indicated by 'path', truncating it.
+ *
+ * Returns true if redirect succeeds.
+ */
+bool redirect_to_file(FILE* redirect, char* path);
-/* redirect output to an existing file */
-void redirect_to_existing_file(FILE *redirect, char *path);
+/*
+ * Redirects 'redirect' to an existing file indicated by 'path', appending it.
+ *
+ * Returns true if redirect succeeds.
+ */
+bool redirect_to_existing_file(FILE* redirect, char* path);
/* create leading directories, if necessary */
void create_parent_dirs(const char *path);
diff --git a/cmds/dumpstate/tests/dumpstate_smoke_test.cpp b/cmds/dumpstate/tests/dumpstate_smoke_test.cpp
index 555badd..fc3642c 100644
--- a/cmds/dumpstate/tests/dumpstate_smoke_test.cpp
+++ b/cmds/dumpstate/tests/dumpstate_smoke_test.cpp
@@ -475,7 +475,7 @@
EXPECT_FALSE(status.isOk());
WaitTillExecutionComplete(listener2.get());
EXPECT_EQ(listener2->getErrorCode(),
- IDumpstateListener::BUGREPORT_ERROR_CONCURRENT_BUGREPORTS_FORBIDDEN);
+ IDumpstateListener::BUGREPORT_ERROR_ANOTHER_REPORT_IN_PROGRESS);
// Meanwhile the first call works as expected. Service should not die in this case.
WaitTillExecutionComplete(listener1.get());
diff --git a/cmds/dumpstate/utils.cpp b/cmds/dumpstate/utils.cpp
index 528e43d..2a5516d 100644
--- a/cmds/dumpstate/utils.cpp
+++ b/cmds/dumpstate/utils.cpp
@@ -108,6 +108,8 @@
if (log_only_) {
MYLOGD("Duration of '%s': %.3fs\n", title_.c_str(), (float)elapsed / NANOS_PER_SEC);
} else {
+ // TODO(124089395): Remove or rewrite when bugreport latency is fixed.
+ MYLOGD("Duration of '%s': %.3fs\n", title_.c_str(), (float)elapsed / NANOS_PER_SEC);
// Use "Yoda grammar" to make it easier to grep|sort sections.
printf("------ %.3fs was the duration of '%s' ------\n", (float)elapsed / NANOS_PER_SEC,
title_.c_str());
@@ -710,12 +712,12 @@
int s = android_get_control_socket(service);
if (s < 0) {
MYLOGE("android_get_control_socket(%s): %s\n", service, strerror(errno));
- exit(1);
+ return -1;
}
fcntl(s, F_SETFD, FD_CLOEXEC);
if (listen(s, 4) < 0) {
MYLOGE("listen(control socket): %s\n", strerror(errno));
- exit(1);
+ return -1;
}
struct sockaddr addr;
@@ -723,18 +725,23 @@
int fd = accept(s, &addr, &alen);
if (fd < 0) {
MYLOGE("accept(control socket): %s\n", strerror(errno));
- exit(1);
+ return -1;
}
return fd;
}
/* redirect output to a service control socket */
-void redirect_to_socket(FILE *redirect, const char *service) {
+bool redirect_to_socket(FILE* redirect, const char* service) {
int fd = open_socket(service);
+ if (fd == -1) {
+ return false;
+ }
fflush(redirect);
- dup2(fd, fileno(redirect));
+ // TODO: handle dup2 failure
+ TEMP_FAILURE_RETRY(dup2(fd, fileno(redirect)));
close(fd);
+ return true;
}
// TODO: should call is_valid_output_file and/or be merged into it.
@@ -764,7 +771,7 @@
}
}
-void _redirect_to_file(FILE *redirect, char *path, int truncate_flag) {
+bool _redirect_to_file(FILE* redirect, char* path, int truncate_flag) {
create_parent_dirs(path);
int fd = TEMP_FAILURE_RETRY(open(path,
@@ -772,19 +779,20 @@
S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH));
if (fd < 0) {
MYLOGE("%s: %s\n", path, strerror(errno));
- exit(1);
+ return false;
}
TEMP_FAILURE_RETRY(dup2(fd, fileno(redirect)));
close(fd);
+ return true;
}
-void redirect_to_file(FILE *redirect, char *path) {
- _redirect_to_file(redirect, path, O_TRUNC);
+bool redirect_to_file(FILE* redirect, char* path) {
+ return _redirect_to_file(redirect, path, O_TRUNC);
}
-void redirect_to_existing_file(FILE *redirect, char *path) {
- _redirect_to_file(redirect, path, O_APPEND);
+bool redirect_to_existing_file(FILE* redirect, char* path) {
+ return _redirect_to_file(redirect, path, O_APPEND);
}
// Dump Dalvik and native stack traces, return the trace file location (nullptr if none).
diff --git a/cmds/installd/Android.bp b/cmds/installd/Android.bp
index e33b2a8..b60bbc0 100644
--- a/cmds/installd/Android.bp
+++ b/cmds/installd/Android.bp
@@ -35,6 +35,7 @@
"libprocessgroup",
"libselinux",
"libutils",
+ "server_configurable_flags",
],
product_variables: {
@@ -227,6 +228,7 @@
"libprocessgroup",
"libselinux",
"libutils",
+ "server_configurable_flags",
],
}
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index 49383e5..2efcf11 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -39,6 +39,7 @@
#include <sys/xattr.h>
#include <unistd.h>
+#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/properties.h>
#include <android-base/scopeguard.h>
@@ -80,6 +81,8 @@
// An uuid used in unit tests.
static constexpr const char* kTestUuid = "TEST";
+static constexpr const mode_t kRollbackFolderMode = 0700;
+
static constexpr const char* kCpPath = "/system/bin/cp";
static constexpr const char* kXattrDefault = "user.default";
@@ -822,8 +825,8 @@
binder::Status InstalldNativeService::snapshotAppData(
const std::unique_ptr<std::string>& volumeUuid,
- const std::string& packageName, int32_t user, int32_t storageFlags,
- int64_t* _aidl_return) {
+ const std::string& packageName, int32_t user, int32_t snapshotId,
+ int32_t storageFlags, int64_t* _aidl_return) {
ENFORCE_UID(AID_SYSTEM);
CHECK_ARGUMENT_UUID_IS_TEST_OR_NULL(volumeUuid);
CHECK_ARGUMENT_PACKAGE_NAME(packageName);
@@ -840,16 +843,19 @@
bool clear_ce_on_exit = false;
bool clear_de_on_exit = false;
- auto deleter = [&clear_ce_on_exit, &clear_de_on_exit, &volume_uuid, &user, &package_name] {
+ auto deleter = [&clear_ce_on_exit, &clear_de_on_exit, &volume_uuid, &user, &package_name,
+ &snapshotId] {
if (clear_de_on_exit) {
- auto to = create_data_misc_de_rollback_package_path(volume_uuid, user, package_name);
+ auto to = create_data_misc_de_rollback_package_path(volume_uuid, user, snapshotId,
+ package_name);
if (delete_dir_contents(to.c_str(), 1, nullptr) != 0) {
LOG(WARNING) << "Failed to delete app data snapshot: " << to;
}
}
if (clear_ce_on_exit) {
- auto to = create_data_misc_ce_rollback_package_path(volume_uuid, user, package_name);
+ auto to = create_data_misc_ce_rollback_package_path(volume_uuid, user, snapshotId,
+ package_name);
if (delete_dir_contents(to.c_str(), 1, nullptr) != 0) {
LOG(WARNING) << "Failed to delete app data snapshot: " << to;
}
@@ -885,15 +891,21 @@
if (storageFlags & FLAG_STORAGE_DE) {
auto from = create_data_user_de_package_path(volume_uuid, user, package_name);
- auto to = create_data_misc_de_rollback_path(volume_uuid, user);
+ auto to = create_data_misc_de_rollback_path(volume_uuid, user, snapshotId);
+ auto rollback_package_path = create_data_misc_de_rollback_package_path(volume_uuid, user,
+ snapshotId, package_name);
- int rd = delete_dir_contents(to, true /* ignore_if_missing */);
- if (rd != 0) {
- res = error(rd, "Failed clearing existing snapshot " + to);
- return res;
+ int rc = create_dir_if_needed(to.c_str(), kRollbackFolderMode);
+ if (rc != 0) {
+ return error(rc, "Failed to create folder " + to);
}
- int rc = copy_directory_recursive(from.c_str(), to.c_str());
+ rc = delete_dir_contents(rollback_package_path, true /* ignore_if_missing */);
+ if (rc != 0) {
+ return error(rc, "Failed clearing existing snapshot " + rollback_package_path);
+ }
+
+ rc = copy_directory_recursive(from.c_str(), to.c_str());
if (rc != 0) {
res = error(rc, "Failed copying " + from + " to " + to);
clear_de_on_exit = true;
@@ -903,15 +915,21 @@
if (storageFlags & FLAG_STORAGE_CE) {
auto from = create_data_user_ce_package_path(volume_uuid, user, package_name);
- auto to = create_data_misc_ce_rollback_path(volume_uuid, user);
+ auto to = create_data_misc_ce_rollback_path(volume_uuid, user, snapshotId);
+ auto rollback_package_path = create_data_misc_ce_rollback_package_path(volume_uuid, user,
+ snapshotId, package_name);
- int rd = delete_dir_contents(to, true /* ignore_if_missing */);
- if (rd != 0) {
- res = error(rd, "Failed clearing existing snapshot " + to);
- return res;
+ int rc = create_dir_if_needed(to.c_str(), kRollbackFolderMode);
+ if (rc != 0) {
+ return error(rc, "Failed to create folder " + to);
}
- int rc = copy_directory_recursive(from.c_str(), to.c_str());
+ rc = delete_dir_contents(rollback_package_path, true /* ignore_if_missing */);
+ if (rc != 0) {
+ return error(rc, "Failed clearing existing snapshot " + rollback_package_path);
+ }
+
+ rc = copy_directory_recursive(from.c_str(), to.c_str());
if (rc != 0) {
res = error(rc, "Failed copying " + from + " to " + to);
clear_ce_on_exit = true;
@@ -919,7 +937,7 @@
}
if (_aidl_return != nullptr) {
auto ce_snapshot_path = create_data_misc_ce_rollback_package_path(volume_uuid, user,
- package_name);
+ snapshotId, package_name);
rc = get_path_inode(ce_snapshot_path, reinterpret_cast<ino_t*>(_aidl_return));
if (rc != 0) {
res = error(rc, "Failed to get_path_inode for " + ce_snapshot_path);
@@ -934,8 +952,8 @@
binder::Status InstalldNativeService::restoreAppDataSnapshot(
const std::unique_ptr<std::string>& volumeUuid, const std::string& packageName,
- const int32_t appId, const int64_t ceDataInode, const std::string& seInfo,
- const int32_t user, int32_t storageFlags) {
+ const int32_t appId, const std::string& seInfo, const int32_t user,
+ const int32_t snapshotId, int32_t storageFlags) {
ENFORCE_UID(AID_SYSTEM);
CHECK_ARGUMENT_UUID_IS_TEST_OR_NULL(volumeUuid);
CHECK_ARGUMENT_PACKAGE_NAME(packageName);
@@ -945,9 +963,9 @@
const char* package_name = packageName.c_str();
auto from_ce = create_data_misc_ce_rollback_package_path(volume_uuid,
- user, package_name);
+ user, snapshotId, package_name);
auto from_de = create_data_misc_de_rollback_package_path(volume_uuid,
- user, package_name);
+ user, snapshotId, package_name);
const bool needs_ce_rollback = (storageFlags & FLAG_STORAGE_CE) &&
(access(from_ce.c_str(), F_OK) == 0);
@@ -964,7 +982,11 @@
// app with no data in those cases is arguably better than leaving the app
// with mismatched / stale data.
LOG(INFO) << "Clearing app data for " << packageName << " to restore snapshot.";
- binder::Status res = clearAppData(volumeUuid, packageName, user, storageFlags, ceDataInode);
+ // It's fine to pass 0 as ceDataInode here, because restoreAppDataSnapshot
+ // can only be called when user unlocks the phone, meaning that CE user data
+ // is decrypted.
+ binder::Status res = clearAppData(volumeUuid, packageName, user, storageFlags,
+ 0 /* ceDataInode */);
if (!res.isOk()) {
return res;
}
@@ -1000,7 +1022,8 @@
binder::Status InstalldNativeService::destroyAppDataSnapshot(
const std::unique_ptr<std::string> &volumeUuid, const std::string& packageName,
- const int32_t user, const int64_t ceSnapshotInode, int32_t storageFlags) {
+ const int32_t user, const int64_t ceSnapshotInode, const int32_t snapshotId,
+ int32_t storageFlags) {
ENFORCE_UID(AID_SYSTEM);
CHECK_ARGUMENT_UUID_IS_TEST_OR_NULL(volumeUuid);
CHECK_ARGUMENT_PACKAGE_NAME(packageName);
@@ -1011,7 +1034,7 @@
if (storageFlags & FLAG_STORAGE_DE) {
auto de_snapshot_path = create_data_misc_de_rollback_package_path(volume_uuid,
- user, package_name);
+ user, snapshotId, package_name);
int res = delete_dir_contents_and_dir(de_snapshot_path, true /* ignore_if_missing */);
if (res != 0) {
@@ -1021,7 +1044,7 @@
if (storageFlags & FLAG_STORAGE_CE) {
auto ce_snapshot_path = create_data_misc_ce_rollback_package_path(volume_uuid,
- user, package_name, ceSnapshotInode);
+ user, snapshotId, package_name, ceSnapshotInode);
int res = delete_dir_contents_and_dir(ce_snapshot_path, true /* ignore_if_missing */);
if (res != 0) {
return error(res, "Failed clearing snapshot " + ce_snapshot_path);
diff --git a/cmds/installd/InstalldNativeService.h b/cmds/installd/InstalldNativeService.h
index 578132d..0e91cb2 100644
--- a/cmds/installd/InstalldNativeService.h
+++ b/cmds/installd/InstalldNativeService.h
@@ -61,14 +61,14 @@
binder::Status fixupAppData(const std::unique_ptr<std::string>& uuid, int32_t flags);
binder::Status snapshotAppData(const std::unique_ptr<std::string>& volumeUuid,
- const std::string& packageName, const int32_t user, int32_t storageFlags,
- int64_t* _aidl_return);
+ const std::string& packageName, const int32_t user, const int32_t snapshotId,
+ int32_t storageFlags, int64_t* _aidl_return);
binder::Status restoreAppDataSnapshot(const std::unique_ptr<std::string>& volumeUuid,
- const std::string& packageName, const int32_t appId, const int64_t ceDataInode,
- const std::string& seInfo, const int32_t user, int32_t storageFlags);
+ const std::string& packageName, const int32_t appId, const std::string& seInfo,
+ const int32_t user, const int32_t snapshotId, int32_t storageFlags);
binder::Status destroyAppDataSnapshot(const std::unique_ptr<std::string> &volumeUuid,
const std::string& packageName, const int32_t user, const int64_t ceSnapshotInode,
- int32_t storageFlags);
+ const int32_t snapshotId, int32_t storageFlags);
binder::Status getAppSize(const std::unique_ptr<std::string>& uuid,
const std::vector<std::string>& packageNames, int32_t userId, int32_t flags,
diff --git a/cmds/installd/binder/android/os/IInstalld.aidl b/cmds/installd/binder/android/os/IInstalld.aidl
index b345210..63c9765 100644
--- a/cmds/installd/binder/android/os/IInstalld.aidl
+++ b/cmds/installd/binder/android/os/IInstalld.aidl
@@ -106,11 +106,11 @@
@nullable @utf8InCpp String dexMetadata);
long snapshotAppData(@nullable @utf8InCpp String uuid, in @utf8InCpp String packageName,
- int userId, int storageFlags);
+ int userId, int snapshotId, int storageFlags);
void restoreAppDataSnapshot(@nullable @utf8InCpp String uuid, in @utf8InCpp String packageName,
- int appId, long ceDataInode, @utf8InCpp String seInfo, int user, int storageflags);
+ 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 storageFlags);
+ int userId, long ceSnapshotInode, int snapshotId, int storageFlags);
const int FLAG_STORAGE_DE = 0x1;
const int FLAG_STORAGE_CE = 0x2;
diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp
index acc0647..ffd1191 100644
--- a/cmds/installd/dexopt.cpp
+++ b/cmds/installd/dexopt.cpp
@@ -45,6 +45,7 @@
#include <private/android_filesystem_config.h>
#include <processgroup/sched_policy.h>
#include <selinux/android.h>
+#include <server_configurable_flags/get_flags.h>
#include <system/thread_defs.h>
#include "dexopt.h"
@@ -260,6 +261,47 @@
return "";
}
+// Determines which binary we should use for execution (the debug or non-debug version).
+// e.g. dex2oatd vs dex2oat
+static const char* select_execution_binary(const char* binary, const char* debug_binary,
+ bool background_job_compile) {
+ return select_execution_binary(
+ binary,
+ debug_binary,
+ background_job_compile,
+ is_debug_runtime(),
+ (android::base::GetProperty("ro.build.version.codename", "") == "REL"),
+ is_debuggable_build());
+}
+
+// Determines which binary we should use for execution (the debug or non-debug version).
+// e.g. dex2oatd vs dex2oat
+// This is convenient method which is much easier to test because it doesn't read
+// system properties.
+const char* select_execution_binary(
+ const char* binary,
+ const char* debug_binary,
+ bool background_job_compile,
+ bool is_debug_runtime,
+ bool is_release,
+ bool is_debuggable_build) {
+ // Do not use debug binaries for release candidates (to give more soak time).
+ bool is_debug_bg_job = background_job_compile && is_debuggable_build && !is_release;
+
+ // If the runtime was requested to use libartd.so, we'll run the debug version - assuming
+ // the file is present (it may not be on images with very little space available).
+ bool useDebug = (is_debug_runtime || is_debug_bg_job) && (access(debug_binary, X_OK) == 0);
+
+ return useDebug ? debug_binary : binary;
+}
+
+// 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";
+
class RunDex2Oat : public ExecVHelper {
public:
RunDex2Oat(int zip_fd,
@@ -293,6 +335,14 @@
: "dalvik.vm.boot-dex2oat-threads";
std::string dex2oat_threads_arg = MapPropertyToArg(threads_property, "-j%s");
+ std::string bootclasspath;
+ char* dex2oat_bootclasspath = getenv("DEX2OATBOOTCLASSPATH");
+ if (dex2oat_bootclasspath != nullptr) {
+ bootclasspath = StringPrintf("-Xbootclasspath:%s", dex2oat_bootclasspath);
+ }
+ // If DEX2OATBOOTCLASSPATH is not in the environment, dex2oat is going to query
+ // BOOTCLASSPATH.
+
const std::string dex2oat_isa_features_key =
StringPrintf("dalvik.vm.isa.%s.features", instruction_set);
std::string instruction_set_features_arg =
@@ -338,21 +388,23 @@
std::string dex2oat_large_app_threshold_arg =
MapPropertyToArg("dalvik.vm.dex2oat-very-large", "--very-large-app-threshold=%s");
- // If the runtime was requested to use libartd.so, we'll run dex2oatd, otherwise dex2oat.
- const char* dex2oat_bin = kDex2oatPath;
- // Do not use dex2oatd for release candidates (give dex2oat more soak time).
- bool is_release = android::base::GetProperty("ro.build.version.codename", "") == "REL";
- if (is_debug_runtime() ||
- (background_job_compile && is_debuggable_build() && !is_release)) {
- if (access(kDex2oatDebugPath, X_OK) == 0) {
- dex2oat_bin = kDex2oatDebugPath;
- }
- }
+
+ const char* dex2oat_bin = select_execution_binary(
+ kDex2oatPath, kDex2oatDebugPath, background_job_compile);
bool generate_minidebug_info = kEnableMinidebugInfo &&
GetBoolProperty(kMinidebugInfoSystemProperty, kMinidebugInfoSystemPropertyDefault);
- std::string boot_image = MapPropertyToArg("dalvik.vm.boot-image", "-Ximage:%s");
+ std::string boot_image;
+ std::string use_apex_image =
+ server_configurable_flags::GetServerConfigurableFlag(RUNTIME_NATIVE_BOOT_NAMESPACE,
+ ENABLE_APEX_IMAGE,
+ /*default_value=*/ "");
+ if (use_apex_image == "true") {
+ boot_image = StringPrintf("-Ximage:%s", kApexImage);
+ } else {
+ boot_image = MapPropertyToArg("dalvik.vm.boot-image", "-Ximage:%s");
+ }
// clang FORTIFY doesn't let us use strlen in constant array bounds, so we
// use arraysize instead.
@@ -440,6 +492,7 @@
AddArg(instruction_set_features_arg);
AddRuntimeArg(boot_image);
+ AddRuntimeArg(bootclasspath);
AddRuntimeArg(dex2oat_Xms_arg);
AddRuntimeArg(dex2oat_Xmx_arg);
@@ -650,7 +703,12 @@
const std::vector<std::string>& dex_locations,
bool copy_and_update,
bool store_aggregation_counters) {
- const char* profman_bin = is_debug_runtime() ? kProfmanDebugPath: kProfmanPath;
+
+ // TODO(calin): Assume for now we run in the bg compile job (which is in
+ // most of the invocation). With the current data flow, is not very easy or
+ // clean to discover this in RunProfman (it will require quite a messy refactoring).
+ const char* profman_bin = select_execution_binary(
+ kProfmanPath, kProfmanDebugPath, /*background_job_compile=*/ true);
if (copy_and_update) {
CHECK_EQ(1u, profile_fds.size());
@@ -1465,8 +1523,10 @@
bool downgrade,
const char* class_loader_context) {
CHECK_GE(zip_fd, 0);
- const char* dexoptanalyzer_bin =
- is_debug_runtime() ? kDexoptanalyzerDebugPath : kDexoptanalyzerPath;
+
+ // We always run the analyzer in the background job.
+ const char* dexoptanalyzer_bin = select_execution_binary(
+ kDexoptanalyzerPath, kDexoptanalyzerDebugPath, /*background_job_compile=*/ true);
std::string dex_file_arg = "--dex-file=" + dex_file;
std::string oat_fd_arg = "--oat-fd=" + std::to_string(oat_fd);
@@ -1961,11 +2021,6 @@
/* child -- drop privileges before continuing */
drop_capabilities(uid);
- // Clear BOOTCLASSPATH.
- // Let dex2oat use the BCP from boot image, excluding updatable BCP
- // modules for AOT to avoid app recompilation after their upgrades.
- unsetenv("BOOTCLASSPATH");
-
SetDex2OatScheduling(boot_complete);
if (flock(out_oat_fd.get(), LOCK_EX | LOCK_NB) != 0) {
PLOG(ERROR) << "flock(" << out_oat_path << ") failed";
diff --git a/cmds/installd/dexopt.h b/cmds/installd/dexopt.h
index 5902659..a8c48c5 100644
--- a/cmds/installd/dexopt.h
+++ b/cmds/installd/dexopt.h
@@ -36,7 +36,7 @@
// Location of binaries in the Android Runtime APEX.
static constexpr const char* kDex2oatPath = ANDROID_RUNTIME_APEX_BIN "/dex2oat";
static constexpr const char* kDex2oatDebugPath = ANDROID_RUNTIME_APEX_BIN "/dex2oatd";
-static constexpr const char* kProfmanPath = ANDROID_RUNTIME_APEX_BIN "/profmand";
+static constexpr const char* kProfmanPath = ANDROID_RUNTIME_APEX_BIN "/profman";
static constexpr const char* kProfmanDebugPath = ANDROID_RUNTIME_APEX_BIN "/profmand";
static constexpr const char* kDexoptanalyzerPath = ANDROID_RUNTIME_APEX_BIN "/dexoptanalyzer";
static constexpr const char* kDexoptanalyzerDebugPath = ANDROID_RUNTIME_APEX_BIN "/dexoptanalyzerd";
@@ -128,6 +128,14 @@
bool move_ab(const char* apk_path, const char* instruction_set, const char* output_path);
+const char* select_execution_binary(
+ const char* binary,
+ const char* debug_binary,
+ bool background_job_compile,
+ bool is_debug_runtime,
+ bool is_release,
+ bool is_debuggable_build);
+
} // namespace installd
} // namespace android
diff --git a/cmds/installd/globals.cpp b/cmds/installd/globals.cpp
index b3a6daf..f52c2e7 100644
--- a/cmds/installd/globals.cpp
+++ b/cmds/installd/globals.cpp
@@ -44,6 +44,8 @@
static constexpr const char* PRIVATE_APP_SUBDIR = "app-private/"; // sub-directory under
// ANDROID_DATA
+static constexpr const char* STAGING_SUBDIR = "pkg_staging/"; // sub-directory under ANDROID_DATA
+
std::string android_app_dir;
std::string android_app_ephemeral_dir;
std::string android_app_lib_dir;
@@ -54,6 +56,7 @@
std::string android_mnt_expand_dir;
std::string android_profiles_dir;
std::string android_root_dir;
+std::string android_staging_dir;
std::vector<std::string> android_system_dirs;
@@ -110,6 +113,9 @@
// Get the android profiles directory.
android_profiles_dir = android_data_dir + PROFILES_SUBDIR;
+ // Get the android session staging directory.
+ android_staging_dir = android_data_dir + STAGING_SUBDIR;
+
// Take note of the system and vendor directories.
android_system_dirs.clear();
android_system_dirs.push_back(android_root_dir + APP_SUBDIR);
diff --git a/cmds/installd/globals.h b/cmds/installd/globals.h
index 633e33b..a88a86e 100644
--- a/cmds/installd/globals.h
+++ b/cmds/installd/globals.h
@@ -38,6 +38,7 @@
extern std::string android_mnt_expand_dir;
extern std::string android_profiles_dir;
extern std::string android_root_dir;
+extern std::string android_staging_dir;
extern std::vector<std::string> android_system_dirs;
diff --git a/cmds/installd/tests/Android.bp b/cmds/installd/tests/Android.bp
index 9c9db0f..1ed49a0 100644
--- a/cmds/installd/tests/Android.bp
+++ b/cmds/installd/tests/Android.bp
@@ -31,6 +31,7 @@
"libprocessgroup",
"libselinux",
"libutils",
+ "server_configurable_flags",
],
static_libs: [
"libdiskusage",
@@ -54,6 +55,7 @@
"libprocessgroup",
"libselinux",
"libutils",
+ "server_configurable_flags",
],
static_libs: [
"libdiskusage",
@@ -77,6 +79,7 @@
"libprocessgroup",
"libselinux",
"libutils",
+ "server_configurable_flags",
],
static_libs: [
"libdiskusage",
@@ -96,6 +99,7 @@
"libbase",
"libcutils",
"libutils",
+ "server_configurable_flags",
],
static_libs: [
"liblog",
diff --git a/cmds/installd/tests/installd_dexopt_test.cpp b/cmds/installd/tests/installd_dexopt_test.cpp
index 78edce0..71b710b 100644
--- a/cmds/installd/tests/installd_dexopt_test.cpp
+++ b/cmds/installd/tests/installd_dexopt_test.cpp
@@ -1175,5 +1175,64 @@
ASSERT_TRUE(std::find(profiles.begin(), profiles.end(), ref_prof) != profiles.end());
}
+TEST_F(DexoptTest, select_execution_binary) {
+ LOG(INFO) << "DexoptTestselect_execution_binary";
+
+ std::string release_str = app_private_dir_ce_ + "/release";
+ std::string debug_str = app_private_dir_ce_ + "/debug";
+
+ // Setup the binaries. Note that we only need executable files to actually
+ // test the execution binary selection
+ run_cmd("touch " + release_str);
+ run_cmd("touch " + debug_str);
+ run_cmd("chmod 777 " + release_str);
+ run_cmd("chmod 777 " + debug_str);
+
+ const char* release = release_str.c_str();
+ const char* debug = debug_str.c_str();
+
+ ASSERT_STREQ(release, select_execution_binary(
+ release,
+ debug,
+ /*background_job_compile=*/ false,
+ /*is_debug_runtime=*/ false,
+ /*is_release=*/ false,
+ /*is_debuggable_build=*/ false));
+
+ ASSERT_STREQ(release, select_execution_binary(
+ release,
+ debug,
+ /*background_job_compile=*/ true,
+ /*is_debug_runtime=*/ false,
+ /*is_release=*/ true,
+ /*is_debuggable_build=*/ true));
+
+ ASSERT_STREQ(debug, select_execution_binary(
+ release,
+ debug,
+ /*background_job_compile=*/ false,
+ /*is_debug_runtime=*/ true,
+ /*is_release=*/ false,
+ /*is_debuggable_build=*/ false));
+
+ ASSERT_STREQ(debug, select_execution_binary(
+ release,
+ debug,
+ /*background_job_compile=*/ true,
+ /*is_debug_runtime=*/ false,
+ /*is_release=*/ false,
+ /*is_debuggable_build=*/ true));
+
+
+ // Select the release when the debug file is not there.
+ ASSERT_STREQ(release, select_execution_binary(
+ release,
+ "does_not_exist",
+ /*background_job_compile=*/ false,
+ /*is_debug_runtime=*/ true,
+ /*is_release=*/ false,
+ /*is_debuggable_build=*/ false));
+}
+
} // namespace installd
} // namespace android
diff --git a/cmds/installd/tests/installd_service_test.cpp b/cmds/installd/tests/installd_service_test.cpp
index 48b07c4..a31d510 100644
--- a/cmds/installd/tests/installd_service_test.cpp
+++ b/cmds/installd/tests/installd_service_test.cpp
@@ -259,32 +259,59 @@
return false;
}
- return (::mkdir(path.c_str(), mode) != -1);
+ if (::mkdir(path.c_str(), mode) != 0) {
+ PLOG(DEBUG) << "Failed to create folder " << path;
+ return false;
+ }
+ return true;
}
-TEST_F(ServiceTest, CreateAppDataSnapshot) {
- auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0);
- auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0);
+class AppDataSnapshotTest : public testing::Test {
+private:
+ std::string rollback_ce_base_dir;
+ std::string rollback_de_base_dir;
- ASSERT_TRUE(mkdirs(rollback_ce_dir, 700));
- ASSERT_TRUE(mkdirs(rollback_de_dir, 700));
+protected:
+ InstalldNativeService* service;
- auto fake_package_ce_path = create_data_user_ce_package_path("TEST", 0, "com.foo");
- auto fake_package_de_path = create_data_user_de_package_path("TEST", 0, "com.foo");
+ std::string fake_package_ce_path;
+ std::string fake_package_de_path;
- ASSERT_TRUE(mkdirs(fake_package_ce_path, 700));
- ASSERT_TRUE(mkdirs(fake_package_de_path, 700));
+ virtual void SetUp() {
+ setenv("ANDROID_LOG_TAGS", "*:v", 1);
+ android::base::InitLogging(nullptr);
- auto deleter = [&rollback_ce_dir, &rollback_de_dir,
- &fake_package_ce_path, &fake_package_de_path]() {
- delete_dir_contents(rollback_ce_dir, true);
- delete_dir_contents(rollback_de_dir, true);
- delete_dir_contents(fake_package_ce_path, true);
- delete_dir_contents(fake_package_de_path, true);
- rmdir(rollback_ce_dir.c_str());
- rmdir(rollback_de_dir.c_str());
- };
- auto scope_guard = android::base::make_scope_guard(deleter);
+ service = new InstalldNativeService();
+ ASSERT_TRUE(mkdirs("/data/local/tmp/user/0", 0700));
+
+ init_globals_from_data_and_root();
+
+ rollback_ce_base_dir = create_data_misc_ce_rollback_base_path("TEST", 0);
+ rollback_de_base_dir = create_data_misc_de_rollback_base_path("TEST", 0);
+
+ fake_package_ce_path = create_data_user_ce_package_path("TEST", 0, "com.foo");
+ fake_package_de_path = create_data_user_de_package_path("TEST", 0, "com.foo");
+
+ ASSERT_TRUE(mkdirs(rollback_ce_base_dir, 0700));
+ ASSERT_TRUE(mkdirs(rollback_de_base_dir, 0700));
+ ASSERT_TRUE(mkdirs(fake_package_ce_path, 0700));
+ ASSERT_TRUE(mkdirs(fake_package_de_path, 0700));
+ }
+
+ virtual void TearDown() {
+ ASSERT_EQ(0, delete_dir_contents_and_dir(rollback_ce_base_dir, true));
+ ASSERT_EQ(0, delete_dir_contents_and_dir(rollback_de_base_dir, true));
+ ASSERT_EQ(0, delete_dir_contents(fake_package_ce_path, true));
+ ASSERT_EQ(0, delete_dir_contents(fake_package_de_path, true));
+
+ delete service;
+ ASSERT_EQ(0, delete_dir_contents_and_dir("/data/local/tmp/user/0", true));
+ }
+};
+
+TEST_F(AppDataSnapshotTest, CreateAppDataSnapshot) {
+ auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0, 37);
+ auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0, 37);
ASSERT_TRUE(android::base::WriteStringToFile(
"TEST_CONTENT_CE", fake_package_ce_path + "/file1",
@@ -296,7 +323,7 @@
// Request a snapshot of the CE content but not the DE content.
int64_t ce_snapshot_inode;
ASSERT_BINDER_SUCCESS(service->snapshotAppData(std::make_unique<std::string>("TEST"),
- "com.foo", 0, FLAG_STORAGE_CE, &ce_snapshot_inode));
+ "com.foo", 0, 37, FLAG_STORAGE_CE, &ce_snapshot_inode));
struct stat buf;
memset(&buf, 0, sizeof(buf));
ASSERT_EQ(0, stat((rollback_ce_dir + "/com.foo").c_str(), &buf));
@@ -318,7 +345,7 @@
// Request a snapshot of the DE content but not the CE content.
ASSERT_BINDER_SUCCESS(service->snapshotAppData(std::make_unique<std::string>("TEST"),
- "com.foo", 0, FLAG_STORAGE_DE, &ce_snapshot_inode));
+ "com.foo", 0, 37, FLAG_STORAGE_DE, &ce_snapshot_inode));
// Only DE content snapshot was requested.
ASSERT_EQ(ce_snapshot_inode, 0);
@@ -339,7 +366,7 @@
// Request a snapshot of both the CE as well as the DE content.
ASSERT_BINDER_SUCCESS(service->snapshotAppData(std::make_unique<std::string>("TEST"),
- "com.foo", 0, FLAG_STORAGE_DE | FLAG_STORAGE_CE, nullptr));
+ "com.foo", 0, 37, FLAG_STORAGE_DE | FLAG_STORAGE_CE, nullptr));
ASSERT_TRUE(android::base::ReadFileToString(
rollback_ce_dir + "/com.foo/file1", &ce_content, false /* follow_symlinks */));
@@ -349,27 +376,73 @@
ASSERT_EQ("TEST_CONTENT_DE_MODIFIED", de_content);
}
-TEST_F(ServiceTest, CreateAppDataSnapshot_AppDataAbsent) {
- auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0);
- auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0);
+TEST_F(AppDataSnapshotTest, CreateAppDataSnapshot_TwoSnapshotsWithTheSameId) {
+ auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0, 67);
+ auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0, 67);
- ASSERT_TRUE(mkdirs(rollback_ce_dir, 700));
- ASSERT_TRUE(mkdirs(rollback_de_dir, 700));
+ auto another_fake_package_ce_path = create_data_user_ce_package_path("TEST", 0, "com.bar");
+ auto another_fake_package_de_path = create_data_user_de_package_path("TEST", 0, "com.bar");
- auto deleter = [&rollback_ce_dir, &rollback_de_dir]() {
- delete_dir_contents(rollback_ce_dir, true);
- delete_dir_contents(rollback_de_dir, true);
- rmdir(rollback_ce_dir.c_str());
- rmdir(rollback_de_dir.c_str());
+ // Since this test sets up data for another package, some bookkeeping is required.
+ auto deleter = [&]() {
+ ASSERT_EQ(0, delete_dir_contents_and_dir(another_fake_package_ce_path, true));
+ ASSERT_EQ(0, delete_dir_contents_and_dir(another_fake_package_de_path, true));
};
-
auto scope_guard = android::base::make_scope_guard(deleter);
+ ASSERT_TRUE(mkdirs(another_fake_package_ce_path, 0700));
+ ASSERT_TRUE(mkdirs(another_fake_package_de_path, 0700));
+
+ ASSERT_TRUE(android::base::WriteStringToFile(
+ "TEST_CONTENT_CE", fake_package_ce_path + "/file1",
+ 0700, 10000, 20000, false /* follow_symlinks */));
+ ASSERT_TRUE(android::base::WriteStringToFile(
+ "TEST_CONTENT_DE", fake_package_de_path + "/file1",
+ 0700, 10000, 20000, false /* follow_symlinks */));
+ ASSERT_TRUE(android::base::WriteStringToFile(
+ "ANOTHER_TEST_CONTENT_CE", another_fake_package_ce_path + "/file1",
+ 0700, 10000, 20000, false /* follow_symlinks */));
+ ASSERT_TRUE(android::base::WriteStringToFile(
+ "ANOTHER_TEST_CONTENT_DE", another_fake_package_de_path + "/file1",
+ 0700, 10000, 20000, false /* follow_symlinks */));
+
+ // Request snapshot for the package com.foo.
+ ASSERT_BINDER_SUCCESS(service->snapshotAppData(std::make_unique<std::string>("TEST"),
+ "com.foo", 0, 67, FLAG_STORAGE_DE | FLAG_STORAGE_CE, nullptr));
+ // Now request snapshot with the same id for the package com.bar
+ ASSERT_BINDER_SUCCESS(service->snapshotAppData(std::make_unique<std::string>("TEST"),
+ "com.bar", 0, 67, FLAG_STORAGE_DE | FLAG_STORAGE_CE, nullptr));
+
+ // Check that both snapshots have correct data in them.
+ std::string com_foo_ce_content, com_foo_de_content;
+ std::string com_bar_ce_content, com_bar_de_content;
+ ASSERT_TRUE(android::base::ReadFileToString(
+ rollback_ce_dir + "/com.foo/file1", &com_foo_ce_content, false /* follow_symlinks */));
+ ASSERT_TRUE(android::base::ReadFileToString(
+ rollback_de_dir + "/com.foo/file1", &com_foo_de_content, false /* follow_symlinks */));
+ ASSERT_TRUE(android::base::ReadFileToString(
+ rollback_ce_dir + "/com.bar/file1", &com_bar_ce_content, false /* follow_symlinks */));
+ ASSERT_TRUE(android::base::ReadFileToString(
+ rollback_de_dir + "/com.bar/file1", &com_bar_de_content, false /* follow_symlinks */));
+ ASSERT_EQ("TEST_CONTENT_CE", com_foo_ce_content);
+ ASSERT_EQ("TEST_CONTENT_DE", com_foo_de_content);
+ ASSERT_EQ("ANOTHER_TEST_CONTENT_CE", com_bar_ce_content);
+ ASSERT_EQ("ANOTHER_TEST_CONTENT_DE", com_bar_de_content);
+}
+
+TEST_F(AppDataSnapshotTest, CreateAppDataSnapshot_AppDataAbsent) {
+ auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0, 73);
+ auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0, 73);
+
+ // Similuating app data absence.
+ ASSERT_EQ(0, delete_dir_contents_and_dir(fake_package_ce_path, true));
+ ASSERT_EQ(0, delete_dir_contents_and_dir(fake_package_de_path, true));
+
int64_t ce_snapshot_inode;
ASSERT_BINDER_SUCCESS(service->snapshotAppData(std::make_unique<std::string>("TEST"),
- "com.foo", 0, FLAG_STORAGE_CE, &ce_snapshot_inode));
+ "com.foo", 0, 73, FLAG_STORAGE_CE, &ce_snapshot_inode));
ASSERT_BINDER_SUCCESS(service->snapshotAppData(std::make_unique<std::string>("TEST"),
- "com.foo", 0, FLAG_STORAGE_DE, nullptr));
+ "com.foo", 0, 73, FLAG_STORAGE_DE, nullptr));
// No CE content snapshot was performed.
ASSERT_EQ(ce_snapshot_inode, 0);
@@ -380,29 +453,12 @@
ASSERT_EQ(-1, stat((rollback_de_dir + "/com.foo").c_str(), &sb));
}
-TEST_F(ServiceTest, CreateAppDataSnapshot_ClearsExistingSnapshot) {
- auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0);
- auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0);
+TEST_F(AppDataSnapshotTest, CreateAppDataSnapshot_ClearsExistingSnapshot) {
+ auto rollback_ce_dir = create_data_misc_ce_rollback_package_path("TEST", 0, 13, "com.foo");
+ auto rollback_de_dir = create_data_misc_de_rollback_package_path("TEST", 0, 13, "com.foo");
- ASSERT_TRUE(mkdirs(rollback_ce_dir, 700));
- ASSERT_TRUE(mkdirs(rollback_de_dir, 700));
-
- auto fake_package_ce_path = create_data_user_ce_package_path("TEST", 0, "com.foo");
- auto fake_package_de_path = create_data_user_de_package_path("TEST", 0, "com.foo");
-
- ASSERT_TRUE(mkdirs(fake_package_ce_path, 700));
- ASSERT_TRUE(mkdirs(fake_package_de_path, 700));
-
- auto deleter = [&rollback_ce_dir, &rollback_de_dir,
- &fake_package_ce_path, &fake_package_de_path]() {
- delete_dir_contents(rollback_ce_dir, true);
- delete_dir_contents(rollback_de_dir, true);
- delete_dir_contents(fake_package_ce_path, true);
- delete_dir_contents(fake_package_de_path, true);
- rmdir(rollback_ce_dir.c_str());
- rmdir(rollback_de_dir.c_str());
- };
- auto scope_guard = android::base::make_scope_guard(deleter);
+ ASSERT_TRUE(mkdirs(rollback_ce_dir, 0700));
+ ASSERT_TRUE(mkdirs(rollback_de_dir, 0700));
// Simulate presence of an existing snapshot
ASSERT_TRUE(android::base::WriteStringToFile(
@@ -421,62 +477,40 @@
0700, 10000, 20000, false /* follow_symlinks */));
ASSERT_BINDER_SUCCESS(service->snapshotAppData(std::make_unique<std::string>("TEST"),
- "com.foo", 0, FLAG_STORAGE_DE | FLAG_STORAGE_CE, nullptr));
+ "com.foo", 0, 13, FLAG_STORAGE_DE | FLAG_STORAGE_CE, nullptr));
// Previous snapshot (with data for file1) must be cleared.
struct stat sb;
- ASSERT_EQ(-1, stat((rollback_ce_dir + "/com.foo/file1").c_str(), &sb));
- ASSERT_EQ(-1, stat((rollback_de_dir + "/com.foo/file1").c_str(), &sb));
+ ASSERT_EQ(-1, stat((rollback_ce_dir + "/file1").c_str(), &sb));
+ ASSERT_EQ(-1, stat((rollback_de_dir + "/file1").c_str(), &sb));
+ // New snapshot (with data for file2) must be present.
+ ASSERT_NE(-1, stat((rollback_ce_dir + "/file2").c_str(), &sb));
+ ASSERT_NE(-1, stat((rollback_de_dir + "/file2").c_str(), &sb));
}
-TEST_F(ServiceTest, SnapshotAppData_WrongVolumeUuid) {
- // Setup app data to make sure that fails due to wrong volumeUuid being
+TEST_F(AppDataSnapshotTest, SnapshotAppData_WrongVolumeUuid) {
+ // Setup rollback folders to make sure that fails due to wrong volumeUuid being
// passed, not because of some other reason.
- auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0);
- auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0);
+ auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0, 17);
+ auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0, 17);
- ASSERT_TRUE(mkdirs(rollback_ce_dir, 700));
- ASSERT_TRUE(mkdirs(rollback_de_dir, 700));
-
- auto deleter = [&rollback_ce_dir, &rollback_de_dir]() {
- delete_dir_contents(rollback_ce_dir, true);
- delete_dir_contents(rollback_de_dir, true);
- rmdir(rollback_ce_dir.c_str());
- rmdir(rollback_de_dir.c_str());
- };
- auto scope_guard = android::base::make_scope_guard(deleter);
+ ASSERT_TRUE(mkdirs(rollback_ce_dir, 0700));
+ ASSERT_TRUE(mkdirs(rollback_de_dir, 0700));
EXPECT_BINDER_FAIL(service->snapshotAppData(std::make_unique<std::string>("FOO"),
- "com.foo", 0, FLAG_STORAGE_DE, nullptr));
+ "com.foo", 0, 17, FLAG_STORAGE_DE, nullptr));
}
-TEST_F(ServiceTest, CreateAppDataSnapshot_ClearsCache) {
- auto fake_package_ce_path = create_data_user_ce_package_path("TEST", 0, "com.foo");
- auto fake_package_de_path = create_data_user_de_package_path("TEST", 0, "com.foo");
+TEST_F(AppDataSnapshotTest, CreateAppDataSnapshot_ClearsCache) {
auto fake_package_ce_cache_path = fake_package_ce_path + "/cache";
auto fake_package_ce_code_cache_path = fake_package_ce_path + "/code_cache";
auto fake_package_de_cache_path = fake_package_de_path + "/cache";
auto fake_package_de_code_cache_path = fake_package_de_path + "/code_cache";
- auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0);
- auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0);
- ASSERT_TRUE(mkdirs(fake_package_ce_path, 700));
- ASSERT_TRUE(mkdirs(fake_package_de_path, 700));
- ASSERT_TRUE(mkdirs(fake_package_ce_cache_path, 700));
- ASSERT_TRUE(mkdirs(fake_package_ce_code_cache_path, 700));
- ASSERT_TRUE(mkdirs(fake_package_de_cache_path, 700));
- ASSERT_TRUE(mkdirs(fake_package_de_code_cache_path, 700));
- ASSERT_TRUE(mkdirs(rollback_ce_dir, 700));
- ASSERT_TRUE(mkdirs(rollback_de_dir, 700));
-
- auto deleter = [&fake_package_ce_path, &fake_package_de_path,
- &rollback_ce_dir, &rollback_de_dir]() {
- delete_dir_contents(fake_package_ce_path, true);
- delete_dir_contents(fake_package_de_path, true);
- delete_dir_contents_and_dir(rollback_ce_dir, true);
- delete_dir_contents_and_dir(rollback_de_dir, true);
- };
- auto scope_guard = android::base::make_scope_guard(deleter);
+ ASSERT_TRUE(mkdirs(fake_package_ce_cache_path, 0700));
+ ASSERT_TRUE(mkdirs(fake_package_ce_code_cache_path, 0700));
+ ASSERT_TRUE(mkdirs(fake_package_de_cache_path, 0700));
+ ASSERT_TRUE(mkdirs(fake_package_de_code_cache_path, 0700));
ASSERT_TRUE(android::base::WriteStringToFile(
"TEST_CONTENT_CE", fake_package_ce_cache_path + "/file1",
@@ -491,7 +525,7 @@
"TEST_CONTENT_DE", fake_package_de_code_cache_path + "/file1",
0700, 10000, 20000, false /* follow_symlinks */));
ASSERT_BINDER_SUCCESS(service->snapshotAppData(std::make_unique<std::string>("TEST"),
- "com.foo", 0, FLAG_STORAGE_CE | FLAG_STORAGE_DE, nullptr));
+ "com.foo", 0, 23, FLAG_STORAGE_CE | FLAG_STORAGE_DE, nullptr));
// The snapshot call must clear cache.
struct stat sb;
ASSERT_EQ(-1, stat((fake_package_ce_cache_path + "/file1").c_str(), &sb));
@@ -500,34 +534,17 @@
ASSERT_EQ(-1, stat((fake_package_de_code_cache_path + "/file1").c_str(), &sb));
}
-TEST_F(ServiceTest, RestoreAppDataSnapshot) {
- auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0);
- auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0);
+TEST_F(AppDataSnapshotTest, RestoreAppDataSnapshot) {
+ auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0, 239);
+ auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0, 239);
- ASSERT_TRUE(mkdirs(rollback_ce_dir, 700));
- ASSERT_TRUE(mkdirs(rollback_de_dir, 700));
-
- auto fake_package_ce_path = create_data_user_ce_package_path("TEST", 0, "com.foo");
- auto fake_package_de_path = create_data_user_de_package_path("TEST", 0, "com.foo");
-
- ASSERT_TRUE(mkdirs(fake_package_ce_path, 700));
- ASSERT_TRUE(mkdirs(fake_package_de_path, 700));
-
- auto deleter = [&rollback_ce_dir, &rollback_de_dir,
- &fake_package_ce_path, &fake_package_de_path]() {
- delete_dir_contents(rollback_ce_dir, true);
- delete_dir_contents(rollback_de_dir, true);
- delete_dir_contents(fake_package_ce_path, true);
- delete_dir_contents(fake_package_de_path, true);
- rmdir(rollback_ce_dir.c_str());
- rmdir(rollback_de_dir.c_str());
- };
- auto scope_guard = android::base::make_scope_guard(deleter);
+ ASSERT_TRUE(mkdirs(rollback_ce_dir, 0700));
+ ASSERT_TRUE(mkdirs(rollback_de_dir, 0700));
// Write contents to the rollback location. We'll write the same files to the
// app data location and make sure the restore has overwritten them.
- ASSERT_TRUE(mkdirs(rollback_ce_dir + "/com.foo/", 700));
- ASSERT_TRUE(mkdirs(rollback_de_dir + "/com.foo/", 700));
+ ASSERT_TRUE(mkdirs(rollback_ce_dir + "/com.foo/", 0700));
+ ASSERT_TRUE(mkdirs(rollback_de_dir + "/com.foo/", 0700));
ASSERT_TRUE(android::base::WriteStringToFile(
"CE_RESTORE_CONTENT", rollback_ce_dir + "/com.foo/file1",
0700, 10000, 20000, false /* follow_symlinks */));
@@ -542,7 +559,7 @@
0700, 10000, 20000, false /* follow_symlinks */));
ASSERT_BINDER_SUCCESS(service->restoreAppDataSnapshot(std::make_unique<std::string>("TEST"),
- "com.foo", 10000, -1, "", 0, FLAG_STORAGE_DE | FLAG_STORAGE_CE));
+ "com.foo", 10000, "", 0, 239, FLAG_STORAGE_DE | FLAG_STORAGE_CE));
std::string ce_content, de_content;
ASSERT_TRUE(android::base::ReadFileToString(
@@ -553,29 +570,9 @@
ASSERT_EQ("DE_RESTORE_CONTENT", de_content);
}
-TEST_F(ServiceTest, CreateSnapshotThenDestroyIt) {
- auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0);
- auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0);
-
- ASSERT_TRUE(mkdirs(rollback_ce_dir, 700));
- ASSERT_TRUE(mkdirs(rollback_de_dir, 700));
-
- auto fake_package_ce_path = create_data_user_ce_package_path("TEST", 0, "com.foo");
- auto fake_package_de_path = create_data_user_de_package_path("TEST", 0, "com.foo");
-
- ASSERT_TRUE(mkdirs(fake_package_ce_path, 700));
- ASSERT_TRUE(mkdirs(fake_package_de_path, 700));
-
- auto deleter = [&rollback_ce_dir, &rollback_de_dir,
- &fake_package_ce_path, &fake_package_de_path]() {
- delete_dir_contents(rollback_ce_dir, true);
- delete_dir_contents(rollback_de_dir, true);
- delete_dir_contents(fake_package_ce_path, true);
- delete_dir_contents(fake_package_de_path, true);
- rmdir(rollback_ce_dir.c_str());
- rmdir(rollback_de_dir.c_str());
- };
- auto scope_guard = android::base::make_scope_guard(deleter);
+TEST_F(AppDataSnapshotTest, CreateSnapshotThenDestroyIt) {
+ auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0, 57);
+ auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0, 57);
// Prepare data for snapshot.
ASSERT_TRUE(android::base::WriteStringToFile(
@@ -588,7 +585,7 @@
int64_t ce_snapshot_inode;
// Request a snapshot of both the CE as well as the DE content.
ASSERT_TRUE(service->snapshotAppData(std::make_unique<std::string>("TEST"),
- "com.foo", 0, FLAG_STORAGE_DE | FLAG_STORAGE_CE, &ce_snapshot_inode).isOk());
+ "com.foo", 0, 57, FLAG_STORAGE_DE | FLAG_STORAGE_CE, &ce_snapshot_inode).isOk());
// Because CE data snapshot was requested, ce_snapshot_inode can't be null.
ASSERT_NE(0, ce_snapshot_inode);
// Check snapshot is there.
@@ -598,39 +595,19 @@
ASSERT_TRUE(service->destroyAppDataSnapshot(std::make_unique<std::string>("TEST"),
- "com.foo", 0, ce_snapshot_inode, FLAG_STORAGE_DE | FLAG_STORAGE_CE).isOk());
+ "com.foo", 0, ce_snapshot_inode, 57, FLAG_STORAGE_DE | FLAG_STORAGE_CE).isOk());
// Check snapshot is deleted.
ASSERT_EQ(-1, stat((rollback_ce_dir + "/com.foo").c_str(), &sb));
ASSERT_EQ(-1, stat((rollback_de_dir + "/com.foo").c_str(), &sb));
}
-TEST_F(ServiceTest, DestroyAppDataSnapshot_CeSnapshotInodeIsZero) {
- auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0);
- auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0);
-
- ASSERT_TRUE(mkdirs(rollback_ce_dir, 700));
- ASSERT_TRUE(mkdirs(rollback_de_dir, 700));
-
- auto fake_package_ce_path = create_data_user_ce_package_path("TEST", 0, "com.foo");
- auto fake_package_de_path = create_data_user_de_package_path("TEST", 0, "com.foo");
-
- ASSERT_TRUE(mkdirs(fake_package_ce_path, 700));
- ASSERT_TRUE(mkdirs(fake_package_de_path, 700));
-
- auto deleter = [&rollback_ce_dir, &rollback_de_dir,
- &fake_package_ce_path, &fake_package_de_path]() {
- delete_dir_contents(rollback_ce_dir, true);
- delete_dir_contents(rollback_de_dir, true);
- delete_dir_contents(fake_package_ce_path, true);
- delete_dir_contents(fake_package_de_path, true);
- rmdir(rollback_ce_dir.c_str());
- rmdir(rollback_de_dir.c_str());
- };
- auto scope_guard = android::base::make_scope_guard(deleter);
+TEST_F(AppDataSnapshotTest, DestroyAppDataSnapshot_CeSnapshotInodeIsZero) {
+ auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0, 1543);
+ auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0, 1543);
// Create a snapshot
- ASSERT_TRUE(mkdirs(rollback_ce_dir + "/com.foo/", 700));
- ASSERT_TRUE(mkdirs(rollback_de_dir + "/com.foo/", 700));
+ ASSERT_TRUE(mkdirs(rollback_ce_dir + "/com.foo/", 0700));
+ ASSERT_TRUE(mkdirs(rollback_de_dir + "/com.foo/", 0700));
ASSERT_TRUE(android::base::WriteStringToFile(
"CE_RESTORE_CONTENT", rollback_ce_dir + "/com.foo/file1",
0700, 10000, 20000, false /* follow_symlinks */));
@@ -639,7 +616,7 @@
0700, 10000, 20000, false /* follow_symlinks */));
ASSERT_TRUE(service->destroyAppDataSnapshot(std::make_unique<std::string>("TEST"),
- "com.foo", 0, 0, FLAG_STORAGE_DE | FLAG_STORAGE_CE).isOk());
+ "com.foo", 0, 0, 1543, FLAG_STORAGE_DE | FLAG_STORAGE_CE).isOk());
// Check snapshot is deleted.
struct stat sb;
@@ -648,67 +625,33 @@
// Check that deleting already deleted snapshot is no-op.
ASSERT_TRUE(service->destroyAppDataSnapshot(std::make_unique<std::string>("TEST"),
- "com.foo", 0, 0, FLAG_STORAGE_DE | FLAG_STORAGE_CE).isOk());
+ "com.foo", 0, 0, 1543, FLAG_STORAGE_DE | FLAG_STORAGE_CE).isOk());
}
-TEST_F(ServiceTest, DestroyAppDataSnapshot_WrongVolumeUuid) {
+TEST_F(AppDataSnapshotTest, DestroyAppDataSnapshot_WrongVolumeUuid) {
// Setup rollback data to make sure that test fails due to wrong volumeUuid
// being passed, not because of some other reason.
- auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0);
- auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0);
+ auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0, 43);
+ auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0, 43);
- ASSERT_TRUE(mkdirs(rollback_ce_dir, 700));
- ASSERT_TRUE(mkdirs(rollback_de_dir, 700));
-
- auto fake_package_ce_path = create_data_user_ce_package_path("TEST", 0, "com.foo");
- auto fake_package_de_path = create_data_user_de_package_path("TEST", 0, "com.foo");
-
- ASSERT_TRUE(mkdirs(fake_package_ce_path, 700));
- ASSERT_TRUE(mkdirs(fake_package_de_path, 700));
-
- auto deleter = [&rollback_ce_dir, &rollback_de_dir,
- &fake_package_ce_path, &fake_package_de_path]() {
- delete_dir_contents(rollback_ce_dir, true);
- delete_dir_contents(rollback_de_dir, true);
- delete_dir_contents(fake_package_ce_path, true);
- delete_dir_contents(fake_package_de_path, true);
- rmdir(rollback_ce_dir.c_str());
- rmdir(rollback_de_dir.c_str());
- };
- auto scope_guard = android::base::make_scope_guard(deleter);
+ ASSERT_TRUE(mkdirs(rollback_ce_dir, 0700));
+ ASSERT_TRUE(mkdirs(rollback_de_dir, 0700));
ASSERT_FALSE(service->destroyAppDataSnapshot(std::make_unique<std::string>("BAR"),
- "com.foo", 0, 0, FLAG_STORAGE_DE).isOk());
+ "com.foo", 0, 0, 43, FLAG_STORAGE_DE).isOk());
}
-TEST_F(ServiceTest, RestoreAppDataSnapshot_WrongVolumeUuid) {
+TEST_F(AppDataSnapshotTest, RestoreAppDataSnapshot_WrongVolumeUuid) {
// Setup rollback data to make sure that fails due to wrong volumeUuid being
// passed, not because of some other reason.
- auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0);
- auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0);
+ auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0, 41);
+ auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0, 41);
- ASSERT_TRUE(mkdirs(rollback_ce_dir, 700));
- ASSERT_TRUE(mkdirs(rollback_de_dir, 700));
-
- auto fake_package_ce_path = create_data_user_ce_package_path("TEST", 0, "com.foo");
- auto fake_package_de_path = create_data_user_de_package_path("TEST", 0, "com.foo");
-
- ASSERT_TRUE(mkdirs(fake_package_ce_path, 700));
- ASSERT_TRUE(mkdirs(fake_package_de_path, 700));
-
- auto deleter = [&rollback_ce_dir, &rollback_de_dir,
- &fake_package_ce_path, &fake_package_de_path]() {
- delete_dir_contents(rollback_ce_dir, true);
- delete_dir_contents(rollback_de_dir, true);
- delete_dir_contents(fake_package_ce_path, true);
- delete_dir_contents(fake_package_de_path, true);
- rmdir(rollback_ce_dir.c_str());
- rmdir(rollback_de_dir.c_str());
- };
- auto scope_guard = android::base::make_scope_guard(deleter);
+ ASSERT_TRUE(mkdirs(rollback_ce_dir, 0700));
+ ASSERT_TRUE(mkdirs(rollback_de_dir, 0700));
EXPECT_BINDER_FAIL(service->restoreAppDataSnapshot(std::make_unique<std::string>("BAR"),
- "com.foo", 10000, -1, "", 0, FLAG_STORAGE_DE));
+ "com.foo", 10000, "", 0, 41, FLAG_STORAGE_DE));
}
} // namespace installd
diff --git a/cmds/installd/tests/installd_utils_test.cpp b/cmds/installd/tests/installd_utils_test.cpp
index 1782aa2..e61eb6e 100644
--- a/cmds/installd/tests/installd_utils_test.cpp
+++ b/cmds/installd/tests/installd_utils_test.cpp
@@ -546,56 +546,86 @@
}
TEST_F(UtilsTest, TestRollbackPaths) {
- EXPECT_EQ("/data/misc_ce/0/rollback/com.foo",
- create_data_misc_ce_rollback_package_path(nullptr, 0, "com.foo"));
- EXPECT_EQ("/data/misc_ce/10/rollback/com.foo",
- create_data_misc_ce_rollback_package_path(nullptr, 10, "com.foo"));
+ EXPECT_EQ("/data/misc_ce/0/rollback/239/com.foo",
+ create_data_misc_ce_rollback_package_path(nullptr, 0, 239, "com.foo"));
+ EXPECT_EQ("/data/misc_ce/10/rollback/37/com.foo",
+ create_data_misc_ce_rollback_package_path(nullptr, 10, 37, "com.foo"));
- EXPECT_EQ("/data/misc_de/0/rollback/com.foo",
- create_data_misc_de_rollback_package_path(nullptr, 0, "com.foo"));
- EXPECT_EQ("/data/misc_de/10/rollback/com.foo",
- create_data_misc_de_rollback_package_path(nullptr, 10, "com.foo"));
+ EXPECT_EQ("/data/misc_de/0/rollback/73/com.foo",
+ create_data_misc_de_rollback_package_path(nullptr, 0, 73, "com.foo"));
+ EXPECT_EQ("/data/misc_de/10/rollback/13/com.foo",
+ create_data_misc_de_rollback_package_path(nullptr, 10, 13, "com.foo"));
- EXPECT_EQ("/data/misc_ce/0/rollback",
- create_data_misc_ce_rollback_path(nullptr, 0));
- EXPECT_EQ("/data/misc_ce/10/rollback",
- create_data_misc_ce_rollback_path(nullptr, 10));
+ EXPECT_EQ("/data/misc_ce/0/rollback/57",
+ create_data_misc_ce_rollback_path(nullptr, 0, 57));
+ EXPECT_EQ("/data/misc_ce/10/rollback/1543",
+ create_data_misc_ce_rollback_path(nullptr, 10, 1543));
- EXPECT_EQ("/data/misc_de/0/rollback",
- create_data_misc_de_rollback_path(nullptr, 0));
- EXPECT_EQ("/data/misc_de/10/rollback",
- create_data_misc_de_rollback_path(nullptr, 10));
+ EXPECT_EQ("/data/misc_de/0/rollback/43",
+ create_data_misc_de_rollback_path(nullptr, 0, 43));
+ EXPECT_EQ("/data/misc_de/10/rollback/41",
+ create_data_misc_de_rollback_path(nullptr, 10, 41));
- EXPECT_EQ("/data/misc_ce/0/rollback/com.foo",
- create_data_misc_ce_rollback_package_path(nullptr, 0, "com.foo", 0));
- EXPECT_EQ("/data/misc_ce/0/rollback/com.foo",
- create_data_misc_ce_rollback_package_path(nullptr, 0, "com.foo", 239));
+ EXPECT_EQ("/data/misc_ce/0/rollback/17/com.foo",
+ create_data_misc_ce_rollback_package_path(nullptr, 0, 17, "com.foo", 0));
+ EXPECT_EQ("/data/misc_ce/0/rollback/19/com.foo",
+ create_data_misc_ce_rollback_package_path(nullptr, 0, 19, "com.foo", 239));
- auto rollback_ce_package_path = create_data_misc_ce_rollback_package_path(nullptr, 0, "com.foo");
- auto deleter = [&rollback_ce_package_path]() {
- delete_dir_contents_and_dir(rollback_ce_package_path, true /* ignore_if_missing */);
+ auto rollback_ce_path = create_data_misc_ce_rollback_path(nullptr, 0, 53);
+ auto rollback_ce_package_path = create_data_misc_ce_rollback_package_path(nullptr, 0, 53,
+ "com.foo");
+ auto deleter = [&rollback_ce_path]() {
+ delete_dir_contents_and_dir(rollback_ce_path, true /* ignore_if_missing */);
};
auto scope_guard = android::base::make_scope_guard(deleter);
- ASSERT_NE(-1, mkdir(rollback_ce_package_path.c_str(), 700));
+ EXPECT_NE(-1, mkdir(rollback_ce_path.c_str(), 700));
+ EXPECT_NE(-1, mkdir(rollback_ce_package_path.c_str(), 700));
ino_t ce_data_inode;
- ASSERT_EQ(0, get_path_inode(rollback_ce_package_path, &ce_data_inode));
+ EXPECT_EQ(0, get_path_inode(rollback_ce_package_path, &ce_data_inode));
- EXPECT_EQ("/data/misc_ce/0/rollback/com.foo",
- create_data_misc_ce_rollback_package_path(nullptr, 0, "com.foo", ce_data_inode));
+ EXPECT_EQ("/data/misc_ce/0/rollback/53/com.foo",
+ create_data_misc_ce_rollback_package_path(nullptr, 0, 53, "com.foo", ce_data_inode));
// Check that path defined by inode is picked even if it's not the same as
// the fallback one.
- EXPECT_EQ("/data/misc_ce/0/rollback/com.foo",
- create_data_misc_ce_rollback_package_path(nullptr, 0, "com.bar", ce_data_inode));
+ EXPECT_EQ("/data/misc_ce/0/rollback/53/com.foo",
+ create_data_misc_ce_rollback_package_path(nullptr, 0, 53, "com.bar", ce_data_inode));
// These last couple of cases are never exercised in production because we
// only snapshot apps in the primary data partition. Exercise them here for
// the sake of completeness.
- EXPECT_EQ("/mnt/expand/57f8f4bc-abf4-655f-bf67-946fc0f9f25b/misc_ce/0/rollback/com.example",
- create_data_misc_ce_rollback_package_path("57f8f4bc-abf4-655f-bf67-946fc0f9f25b", 0, "com.example"));
- EXPECT_EQ("/mnt/expand/57f8f4bc-abf4-655f-bf67-946fc0f9f25b/misc_de/0/rollback/com.example",
- create_data_misc_de_rollback_package_path("57f8f4bc-abf4-655f-bf67-946fc0f9f25b", 0, "com.example"));
+ EXPECT_EQ("/mnt/expand/57f8f4bc-abf4-655f-bf67-946fc0f9f25b/misc_ce/0/rollback/7/com.example",
+ create_data_misc_ce_rollback_package_path("57f8f4bc-abf4-655f-bf67-946fc0f9f25b", 0, 7,
+ "com.example"));
+ EXPECT_EQ("/mnt/expand/57f8f4bc-abf4-655f-bf67-946fc0f9f25b/misc_de/0/rollback/11/com.example",
+ create_data_misc_de_rollback_package_path("57f8f4bc-abf4-655f-bf67-946fc0f9f25b", 0, 11,
+ "com.example"));
+}
+
+TEST_F(UtilsTest, TestCreateDirIfNeeded) {
+ system("mkdir -p /data/local/tmp/user/0");
+
+ auto deleter = [&]() {
+ delete_dir_contents_and_dir("/data/local/tmp/user/0", true /* ignore_if_missing */);
+ };
+ auto scope_guard = android::base::make_scope_guard(deleter);
+
+ // Create folder and check it's permissions.
+ ASSERT_EQ(0, create_dir_if_needed("/data/local/tmp/user/0/foo", 0700));
+ struct stat st;
+ ASSERT_EQ(0, stat("/data/local/tmp/user/0/foo", &st));
+ ASSERT_EQ(0700, st.st_mode & ALLPERMS);
+
+ // Check that create_dir_if_needed is no-op if folder already exists with
+ // correct permissions.
+ ASSERT_EQ(0, create_dir_if_needed("/data/local/tmp/user/0/foo", 0700));
+
+ // Check -1 is returned if folder exists but with different permissions.
+ ASSERT_EQ(-1, create_dir_if_needed("/data/local/tmp/user/0/foo", 0750));
+
+ // Check that call fails if parent doesn't exist.
+ ASSERT_NE(0, create_dir_if_needed("/data/local/tmp/user/0/bar/baz", 0700));
}
} // namespace installd
diff --git a/cmds/installd/utils.cpp b/cmds/installd/utils.cpp
index 5b487bb..da097db 100644
--- a/cmds/installd/utils.cpp
+++ b/cmds/installd/utils.cpp
@@ -197,32 +197,44 @@
return StringPrintf("%s/user_de/%u", data.c_str(), userid);
}
-
-std::string create_data_misc_ce_rollback_path(const char* volume_uuid, userid_t user) {
+std::string create_data_misc_ce_rollback_base_path(const char* volume_uuid, userid_t user) {
return StringPrintf("%s/misc_ce/%u/rollback", create_data_path(volume_uuid).c_str(), user);
}
-std::string create_data_misc_de_rollback_path(const char* volume_uuid, userid_t user) {
+std::string create_data_misc_de_rollback_base_path(const char* volume_uuid, userid_t user) {
return StringPrintf("%s/misc_de/%u/rollback", create_data_path(volume_uuid).c_str(), user);
}
-std::string create_data_misc_ce_rollback_package_path(const char* volume_uuid,
- userid_t user, const char* package_name) {
- return StringPrintf("%s/%s",
- create_data_misc_ce_rollback_path(volume_uuid, user).c_str(), package_name);
+std::string create_data_misc_ce_rollback_path(const char* volume_uuid, userid_t user,
+ int32_t snapshot_id) {
+ return StringPrintf("%s/%d", create_data_misc_ce_rollback_base_path(volume_uuid, user).c_str(),
+ snapshot_id);
+}
+
+std::string create_data_misc_de_rollback_path(const char* volume_uuid, userid_t user,
+ int32_t snapshot_id) {
+ return StringPrintf("%s/%d", create_data_misc_de_rollback_base_path(volume_uuid, user).c_str(),
+ snapshot_id);
}
std::string create_data_misc_ce_rollback_package_path(const char* volume_uuid,
- userid_t user, const char* package_name, ino_t ce_rollback_inode) {
- auto fallback = create_data_misc_ce_rollback_package_path(volume_uuid, user, package_name);
- auto user_path = create_data_misc_ce_rollback_path(volume_uuid, user);
+ userid_t user, int32_t snapshot_id, const char* package_name) {
+ return StringPrintf("%s/%s",
+ create_data_misc_ce_rollback_path(volume_uuid, user, snapshot_id).c_str(), package_name);
+}
+
+std::string create_data_misc_ce_rollback_package_path(const char* volume_uuid,
+ userid_t user, int32_t snapshot_id, const char* package_name, ino_t ce_rollback_inode) {
+ auto fallback = create_data_misc_ce_rollback_package_path(volume_uuid, user, snapshot_id,
+ package_name);
+ auto user_path = create_data_misc_ce_rollback_path(volume_uuid, user, snapshot_id);
return resolve_ce_path_by_inode_or_fallback(user_path, ce_rollback_inode, fallback);
}
std::string create_data_misc_de_rollback_package_path(const char* volume_uuid,
- userid_t user, const char* package_name) {
+ userid_t user, int32_t snapshot_id, const char* package_name) {
return StringPrintf("%s/%s",
- create_data_misc_de_rollback_path(volume_uuid, user).c_str(), package_name);
+ create_data_misc_de_rollback_path(volume_uuid, user, snapshot_id).c_str(), package_name);
}
/**
@@ -528,6 +540,30 @@
return result;
}
+int create_dir_if_needed(const std::string& pathname, mode_t perms) {
+ struct stat st;
+
+ int rc;
+ if ((rc = stat(pathname.c_str(), &st)) != 0) {
+ if (errno == ENOENT) {
+ return mkdir(pathname.c_str(), perms);
+ } else {
+ return rc;
+ }
+ } else if (!S_ISDIR(st.st_mode)) {
+ LOG(DEBUG) << pathname << " is not a folder";
+ return -1;
+ }
+
+ mode_t actual_perms = st.st_mode & ALLPERMS;
+ if (actual_perms != perms) {
+ LOG(WARNING) << pathname << " permissions " << actual_perms << " expected " << perms;
+ return -1;
+ }
+
+ return 0;
+}
+
int delete_dir_contents(const std::string& pathname, bool ignore_if_missing) {
return delete_dir_contents(pathname.c_str(), 0, nullptr, ignore_if_missing);
}
@@ -892,6 +928,8 @@
static int validate_apk_path_internal(const std::string& path, int maxSubdirs) {
if (validate_path(android_app_dir, path, maxSubdirs) == 0) {
return 0;
+ } else if (validate_path(android_staging_dir, path, maxSubdirs) == 0) {
+ return 0;
} else if (validate_path(android_app_private_dir, path, maxSubdirs) == 0) {
return 0;
} else if (validate_path(android_app_ephemeral_dir, path, maxSubdirs) == 0) {
diff --git a/cmds/installd/utils.h b/cmds/installd/utils.h
index 0711b34..955d524 100644
--- a/cmds/installd/utils.h
+++ b/cmds/installd/utils.h
@@ -61,14 +61,18 @@
std::string create_data_user_ce_package_path_as_user_link(
const char* volume_uuid, userid_t userid, const char* package_name);
-std::string create_data_misc_ce_rollback_path(const char* volume_uuid, userid_t user);
-std::string create_data_misc_de_rollback_path(const char* volume_uuid, userid_t user);
+std::string create_data_misc_ce_rollback_base_path(const char* volume_uuid, userid_t user);
+std::string create_data_misc_de_rollback_base_path(const char* volume_uuid, userid_t user);
+std::string create_data_misc_ce_rollback_path(const char* volume_uuid, userid_t user,
+ int32_t snapshot_id);
+std::string create_data_misc_de_rollback_path(const char* volume_uuid, userid_t user,
+ int32_t snapshot_id);
std::string create_data_misc_ce_rollback_package_path(const char* volume_uuid,
- userid_t user, const char* package_name);
+ userid_t user, int32_t snapshot_id, const char* package_name);
std::string create_data_misc_ce_rollback_package_path(const char* volume_uuid,
- userid_t user, const char* package_name, ino_t ce_rollback_inode);
+ userid_t user, int32_t snapshot_id, const char* package_name, ino_t ce_rollback_inode);
std::string create_data_misc_de_rollback_package_path(const char* volume_uuid,
- userid_t user, const char* package_name);
+ userid_t user, int32_t snapshot_id, const char* package_name);
std::string create_data_media_path(const char* volume_uuid, userid_t userid);
std::string create_data_media_obb_path(const char* volume_uuid, const char* package_name);
@@ -109,6 +113,8 @@
bool is_valid_filename(const std::string& name);
bool is_valid_package_name(const std::string& packageName);
+int create_dir_if_needed(const std::string& pathname, mode_t mode);
+
int delete_dir_contents(const std::string& pathname, bool ignore_if_missing = false);
int delete_dir_contents_and_dir(const std::string& pathname, bool ignore_if_missing = false);
diff --git a/include/input/IInputFlinger.h b/include/input/IInputFlinger.h
index ff443c6..cd12fcd 100644
--- a/include/input/IInputFlinger.h
+++ b/include/input/IInputFlinger.h
@@ -24,6 +24,7 @@
#include <utils/Vector.h>
#include <input/InputWindow.h>
+#include <input/ISetInputWindowsListener.h>
namespace android {
@@ -35,7 +36,8 @@
public:
DECLARE_META_INTERFACE(InputFlinger)
- virtual void setInputWindows(const Vector<InputWindowInfo>& inputHandles) = 0;
+ virtual void setInputWindows(const Vector<InputWindowInfo>& inputHandles,
+ const sp<ISetInputWindowsListener>& setInputWindowsListener) = 0;
virtual void transferTouchFocus(const sp<IBinder>& fromToken, const sp<IBinder>& toToken) = 0;
virtual void registerInputChannel(const sp<InputChannel>& channel) = 0;
virtual void unregisterInputChannel(const sp<InputChannel>& channel) = 0;
diff --git a/include/input/ISetInputWindowsListener.h b/include/input/ISetInputWindowsListener.h
new file mode 100644
index 0000000..15d31b2
--- /dev/null
+++ b/include/input/ISetInputWindowsListener.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <binder/IInterface.h>
+#include <binder/Parcel.h>
+
+namespace android {
+
+class ISetInputWindowsListener : public IInterface {
+public:
+ DECLARE_META_INTERFACE(SetInputWindowsListener)
+ virtual void onSetInputWindowsFinished() = 0;
+};
+
+class BnSetInputWindowsListener: public BnInterface<ISetInputWindowsListener> {
+public:
+ enum SetInputWindowsTag : uint32_t {
+ ON_SET_INPUT_WINDOWS_FINISHED
+ };
+
+ virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply,
+ uint32_t flags = 0) override;
+};
+
+}; // namespace android
diff --git a/include/input/InputDevice.h b/include/input/InputDevice.h
index ce8db91..48ac88d 100644
--- a/include/input/InputDevice.h
+++ b/include/input/InputDevice.h
@@ -51,6 +51,15 @@
// is intended to be a minimum way to distinguish from other active devices and may
// reuse values that are not associated with an input anymore.
uint16_t nonce;
+
+ /**
+ * Return InputDeviceIdentifier.name that has been adjusted as follows:
+ * - all characters besides alphanumerics, dash,
+ * and underscore have been replaced with underscores.
+ * This helps in situations where a file that matches the device name is needed,
+ * while conforming to the filename limitations.
+ */
+ std::string getCanonicalName() const;
};
/*
diff --git a/include/input/Keyboard.h b/include/input/Keyboard.h
index 8b66f69..92da10c 100644
--- a/include/input/Keyboard.h
+++ b/include/input/Keyboard.h
@@ -25,15 +25,6 @@
namespace android {
-enum {
- /* Device id of the built in keyboard. */
- DEVICE_ID_BUILT_IN_KEYBOARD = 0,
-
- /* Device id of a generic virtual keyboard with a full layout that can be used
- * to synthesize key events. */
- DEVICE_ID_VIRTUAL_KEYBOARD = -1,
-};
-
class KeyLayoutMap;
class KeyCharacterMap;
diff --git a/include/input/VirtualKeyMap.h b/include/input/VirtualKeyMap.h
index 24e0e0e..4f7cfb6 100644
--- a/include/input/VirtualKeyMap.h
+++ b/include/input/VirtualKeyMap.h
@@ -49,7 +49,7 @@
public:
~VirtualKeyMap();
- static status_t load(const std::string& filename, VirtualKeyMap** outMap);
+ static std::unique_ptr<VirtualKeyMap> load(const std::string& filename);
inline const Vector<VirtualKeyDefinition>& getVirtualKeys() const {
return mVirtualKeys;
diff --git a/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl b/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl
index 5b66b92..ccde12a 100644
--- a/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl
+++ b/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl
@@ -54,4 +54,9 @@
long getVersionCodeForPackage(in String packageName);
+ /**
+ * Return if each app, identified by its package name allows its audio to be recorded.
+ * Unknown packages are mapped to false.
+ */
+ boolean[] isAudioPlaybackCaptureAllowed(in @utf8InCpp String[] packageNames);
}
diff --git a/libs/graphicsenv/Android.bp b/libs/graphicsenv/Android.bp
index d940752..0571dcc 100644
--- a/libs/graphicsenv/Android.bp
+++ b/libs/graphicsenv/Android.bp
@@ -16,6 +16,7 @@
name: "libgraphicsenv",
srcs: [
+ "GpuStatsInfo.cpp",
"GraphicsEnv.cpp",
"IGpuService.cpp"
],
diff --git a/libs/graphicsenv/GpuStatsInfo.cpp b/libs/graphicsenv/GpuStatsInfo.cpp
new file mode 100644
index 0000000..0fa0d9e
--- /dev/null
+++ b/libs/graphicsenv/GpuStatsInfo.cpp
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <inttypes.h>
+
+#include <android-base/stringprintf.h>
+#include <binder/Parcel.h>
+#include <graphicsenv/GpuStatsInfo.h>
+
+namespace android {
+
+using base::StringAppendF;
+
+status_t GpuStatsGlobalInfo::writeToParcel(Parcel* parcel) const {
+ status_t status;
+ if ((status = parcel->writeUtf8AsUtf16(driverPackageName)) != OK) return status;
+ if ((status = parcel->writeUtf8AsUtf16(driverVersionName)) != OK) return status;
+ if ((status = parcel->writeUint64(driverVersionCode)) != OK) return status;
+ if ((status = parcel->writeInt64(driverBuildTime)) != OK) return status;
+ if ((status = parcel->writeInt32(glLoadingCount)) != OK) return status;
+ if ((status = parcel->writeInt32(glLoadingFailureCount)) != OK) return status;
+ if ((status = parcel->writeInt32(vkLoadingCount)) != OK) return status;
+ if ((status = parcel->writeInt32(vkLoadingFailureCount)) != OK) return status;
+ return OK;
+}
+
+status_t GpuStatsGlobalInfo::readFromParcel(const Parcel* parcel) {
+ status_t status;
+ if ((status = parcel->readUtf8FromUtf16(&driverPackageName)) != OK) return status;
+ if ((status = parcel->readUtf8FromUtf16(&driverVersionName)) != OK) return status;
+ if ((status = parcel->readUint64(&driverVersionCode)) != OK) return status;
+ if ((status = parcel->readInt64(&driverBuildTime)) != OK) return status;
+ if ((status = parcel->readInt32(&glLoadingCount)) != OK) return status;
+ if ((status = parcel->readInt32(&glLoadingFailureCount)) != OK) return status;
+ if ((status = parcel->readInt32(&vkLoadingCount)) != OK) return status;
+ if ((status = parcel->readInt32(&vkLoadingFailureCount)) != OK) return status;
+ return OK;
+}
+
+std::string GpuStatsGlobalInfo::toString() const {
+ std::string result;
+ StringAppendF(&result, "driverPackageName = %s\n", driverPackageName.c_str());
+ StringAppendF(&result, "driverVersionName = %s\n", driverVersionName.c_str());
+ StringAppendF(&result, "driverVersionCode = %" PRIu64 "\n", driverVersionCode);
+ StringAppendF(&result, "driverBuildTime = %" PRId64 "\n", driverBuildTime);
+ StringAppendF(&result, "glLoadingCount = %d\n", glLoadingCount);
+ StringAppendF(&result, "glLoadingFailureCount = %d\n", glLoadingFailureCount);
+ StringAppendF(&result, "vkLoadingCount = %d\n", vkLoadingCount);
+ StringAppendF(&result, "vkLoadingFailureCount = %d\n", vkLoadingFailureCount);
+ return result;
+}
+
+status_t GpuStatsAppInfo::writeToParcel(Parcel* parcel) const {
+ status_t status;
+ if ((status = parcel->writeUtf8AsUtf16(appPackageName)) != OK) return status;
+ if ((status = parcel->writeUint64(driverVersionCode)) != OK) return status;
+ if ((status = parcel->writeInt64Vector(glDriverLoadingTime)) != OK) return status;
+ if ((status = parcel->writeInt64Vector(vkDriverLoadingTime)) != OK) return status;
+ return OK;
+}
+
+status_t GpuStatsAppInfo::readFromParcel(const Parcel* parcel) {
+ status_t status;
+ if ((status = parcel->readUtf8FromUtf16(&appPackageName)) != OK) return status;
+ if ((status = parcel->readUint64(&driverVersionCode)) != OK) return status;
+ if ((status = parcel->readInt64Vector(&glDriverLoadingTime)) != OK) return status;
+ if ((status = parcel->readInt64Vector(&vkDriverLoadingTime)) != OK) return status;
+ return OK;
+}
+
+std::string GpuStatsAppInfo::toString() const {
+ std::string result;
+ StringAppendF(&result, "appPackageName = %s\n", appPackageName.c_str());
+ StringAppendF(&result, "driverVersionCode = %" PRIu64 "\n", driverVersionCode);
+ result.append("glDriverLoadingTime:");
+ for (int32_t loadingTime : glDriverLoadingTime) {
+ StringAppendF(&result, " %d", loadingTime);
+ }
+ result.append("\n");
+ result.append("vkDriverLoadingTime:");
+ for (int32_t loadingTime : vkDriverLoadingTime) {
+ StringAppendF(&result, " %d", loadingTime);
+ }
+ result.append("\n");
+ return result;
+}
+
+} // namespace android
diff --git a/libs/graphicsenv/GraphicsEnv.cpp b/libs/graphicsenv/GraphicsEnv.cpp
index 386f9f0..13c0d87 100644
--- a/libs/graphicsenv/GraphicsEnv.cpp
+++ b/libs/graphicsenv/GraphicsEnv.cpp
@@ -146,36 +146,39 @@
return 0;
}
-void GraphicsEnv::setDriverPath(const std::string path) {
- if (!mDriverPath.empty()) {
- ALOGV("ignoring attempt to change driver path from '%s' to '%s'", mDriverPath.c_str(),
- path.c_str());
+void GraphicsEnv::setDriverPathAndSphalLibraries(const std::string path,
+ const std::string sphalLibraries) {
+ if (!mDriverPath.empty() || !mSphalLibraries.empty()) {
+ ALOGV("ignoring attempt to change driver path from '%s' to '%s' or change sphal libraries "
+ "from '%s' to '%s'",
+ mDriverPath.c_str(), path.c_str(), mSphalLibraries.c_str(), sphalLibraries.c_str());
return;
}
- ALOGV("setting driver path to '%s'", path.c_str());
+ ALOGV("setting driver path to '%s' and sphal libraries to '%s'", path.c_str(),
+ sphalLibraries.c_str());
mDriverPath = path;
+ mSphalLibraries = sphalLibraries;
}
void GraphicsEnv::setGpuStats(const std::string& driverPackageName,
const std::string& driverVersionName, uint64_t driverVersionCode,
- const std::string& driverBuildDate,
- const std::string& appPackageName) {
+ int64_t driverBuildTime, const std::string& appPackageName) {
ATRACE_CALL();
std::lock_guard<std::mutex> lock(mStatsLock);
ALOGV("setGpuStats:\n"
"\tdriverPackageName[%s]\n"
"\tdriverVersionName[%s]\n"
- "\tdriverVersionCode[%llu]\n"
- "\tdriverBuildDate[%s]\n"
+ "\tdriverVersionCode[%" PRIu64 "]\n"
+ "\tdriverBuildTime[%" PRId64 "]\n"
"\tappPackageName[%s]\n",
- driverPackageName.c_str(), driverVersionName.c_str(),
- (unsigned long long)driverVersionCode, driverBuildDate.c_str(), appPackageName.c_str());
+ driverPackageName.c_str(), driverVersionName.c_str(), driverVersionCode, driverBuildTime,
+ appPackageName.c_str());
mGpuStats.driverPackageName = driverPackageName;
mGpuStats.driverVersionName = driverVersionName;
mGpuStats.driverVersionCode = driverVersionCode;
- mGpuStats.driverBuildDate = driverBuildDate;
+ mGpuStats.driverBuildTime = driverBuildTime;
mGpuStats.appPackageName = appPackageName;
}
@@ -264,21 +267,20 @@
ALOGV("sendGpuStats:\n"
"\tdriverPackageName[%s]\n"
"\tdriverVersionName[%s]\n"
- "\tdriverVersionCode[%llu]\n"
- "\tdriverBuildDate[%s]\n"
+ "\tdriverVersionCode[%" PRIu64 "]\n"
+ "\tdriverBuildTime[%" PRId64 "]\n"
"\tappPackageName[%s]\n"
"\tdriver[%d]\n"
"\tisDriverLoaded[%d]\n"
- "\tdriverLoadingTime[%lld]",
+ "\tdriverLoadingTime[%" PRId64 "]",
mGpuStats.driverPackageName.c_str(), mGpuStats.driverVersionName.c_str(),
- (unsigned long long)mGpuStats.driverVersionCode, mGpuStats.driverBuildDate.c_str(),
- mGpuStats.appPackageName.c_str(), static_cast<int32_t>(driver), isDriverLoaded,
- (long long)driverLoadingTime);
+ mGpuStats.driverVersionCode, mGpuStats.driverBuildTime, mGpuStats.appPackageName.c_str(),
+ static_cast<int32_t>(driver), isDriverLoaded, driverLoadingTime);
const sp<IGpuService> gpuService = getGpuService();
if (gpuService) {
gpuService->setGpuStats(mGpuStats.driverPackageName, mGpuStats.driverVersionName,
- mGpuStats.driverVersionCode, mGpuStats.driverBuildDate,
+ mGpuStats.driverVersionCode, mGpuStats.driverBuildTime,
mGpuStats.appPackageName, driver, isDriverLoaded,
driverLoadingTime);
}
@@ -538,6 +540,23 @@
mDriverNamespace = nullptr;
return;
}
+
+ if (mSphalLibraries.empty()) return;
+
+ // Make additional libraries in sphal to be accessible
+ auto sphalNamespace = android_get_exported_namespace("sphal");
+ if (!sphalNamespace) {
+ ALOGE("Depend on these libraries[%s] in sphal, but failed to get sphal namespace",
+ mSphalLibraries.c_str());
+ mDriverNamespace = nullptr;
+ return;
+ }
+
+ if (!android_link_namespaces(mDriverNamespace, sphalNamespace, mSphalLibraries.c_str())) {
+ ALOGE("Failed to link sphal namespace[%s]", dlerror());
+ mDriverNamespace = nullptr;
+ return;
+ }
});
return mDriverNamespace;
diff --git a/libs/graphicsenv/IGpuService.cpp b/libs/graphicsenv/IGpuService.cpp
index a8a07c2..0b0bf44 100644
--- a/libs/graphicsenv/IGpuService.cpp
+++ b/libs/graphicsenv/IGpuService.cpp
@@ -29,7 +29,7 @@
virtual void setGpuStats(const std::string& driverPackageName,
const std::string& driverVersionName, uint64_t driverVersionCode,
- const std::string& driverBuildDate, const std::string& appPackageName,
+ int64_t driverBuildTime, const std::string& appPackageName,
GraphicsEnv::Driver driver, bool isDriverLoaded,
int64_t driverLoadingTime) {
Parcel data, reply;
@@ -38,7 +38,7 @@
data.writeUtf8AsUtf16(driverPackageName);
data.writeUtf8AsUtf16(driverVersionName);
data.writeUint64(driverVersionCode);
- data.writeUtf8AsUtf16(driverBuildDate);
+ data.writeInt64(driverBuildTime);
data.writeUtf8AsUtf16(appPackageName);
data.writeInt32(static_cast<int32_t>(driver));
data.writeBool(isDriverLoaded);
@@ -46,6 +46,27 @@
remote()->transact(BnGpuService::SET_GPU_STATS, data, &reply, IBinder::FLAG_ONEWAY);
}
+
+ virtual status_t getGpuStatsGlobalInfo(std::vector<GpuStatsGlobalInfo>* outStats) const {
+ if (!outStats) return UNEXPECTED_NULL;
+
+ Parcel data, reply;
+ status_t status;
+
+ if ((status = data.writeInterfaceToken(IGpuService::getInterfaceDescriptor())) != OK)
+ return status;
+
+ if ((status = remote()->transact(BnGpuService::GET_GPU_STATS_GLOBAL_INFO, data, &reply)) !=
+ OK)
+ return status;
+
+ int32_t result = 0;
+ if ((status = reply.readInt32(&result)) != OK) return status;
+ if (result != OK) return result;
+
+ outStats->clear();
+ return reply.readParcelableVector(outStats);
+ }
};
IMPLEMENT_META_INTERFACE(GpuService, "android.graphicsenv.IGpuService");
@@ -68,8 +89,8 @@
uint64_t driverVersionCode;
if ((status = data.readUint64(&driverVersionCode)) != OK) return status;
- std::string driverBuildDate;
- if ((status = data.readUtf8FromUtf16(&driverBuildDate)) != OK) return status;
+ int64_t driverBuildTime;
+ if ((status = data.readInt64(&driverBuildTime)) != OK) return status;
std::string appPackageName;
if ((status = data.readUtf8FromUtf16(&appPackageName)) != OK) return status;
@@ -83,12 +104,25 @@
int64_t driverLoadingTime;
if ((status = data.readInt64(&driverLoadingTime)) != OK) return status;
- setGpuStats(driverPackageName, driverVersionName, driverVersionCode, driverBuildDate,
+ setGpuStats(driverPackageName, driverVersionName, driverVersionCode, driverBuildTime,
appPackageName, static_cast<GraphicsEnv::Driver>(driver), isDriverLoaded,
driverLoadingTime);
return OK;
}
+ case GET_GPU_STATS_GLOBAL_INFO: {
+ CHECK_INTERFACE(IGpuService, data, reply);
+
+ std::vector<GpuStatsGlobalInfo> stats;
+ const status_t result = getGpuStatsGlobalInfo(&stats);
+
+ if ((status = reply->writeInt32(result)) != OK) return status;
+ if (result != OK) return result;
+
+ if ((status = reply->writeParcelableVector(stats)) != OK) return status;
+
+ return OK;
+ }
case SHELL_COMMAND_TRANSACTION: {
int in = data.readFileDescriptor();
int out = data.readFileDescriptor();
diff --git a/libs/graphicsenv/include/graphicsenv/GpuStatsInfo.h b/libs/graphicsenv/include/graphicsenv/GpuStatsInfo.h
new file mode 100644
index 0000000..a92ca70
--- /dev/null
+++ b/libs/graphicsenv/include/graphicsenv/GpuStatsInfo.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <string>
+#include <vector>
+
+#include <binder/Parcelable.h>
+
+namespace android {
+
+/*
+ * class for transporting gpu global stats from GpuService to authorized
+ * recipents. This class is intended to be a data container.
+ */
+class GpuStatsGlobalInfo : public Parcelable {
+public:
+ GpuStatsGlobalInfo() = default;
+ GpuStatsGlobalInfo(const GpuStatsGlobalInfo&) = default;
+ virtual ~GpuStatsGlobalInfo() = default;
+ virtual status_t writeToParcel(Parcel* parcel) const;
+ virtual status_t readFromParcel(const Parcel* parcel);
+ std::string toString() const;
+
+ std::string driverPackageName = "";
+ std::string driverVersionName = "";
+ uint64_t driverVersionCode = 0;
+ int64_t driverBuildTime = 0;
+ int32_t glLoadingCount = 0;
+ int32_t glLoadingFailureCount = 0;
+ int32_t vkLoadingCount = 0;
+ int32_t vkLoadingFailureCount = 0;
+};
+
+/*
+ * class for transporting gpu app stats from GpuService to authorized recipents.
+ * This class is intended to be a data container.
+ */
+class GpuStatsAppInfo : public Parcelable {
+public:
+ GpuStatsAppInfo() = default;
+ GpuStatsAppInfo(const GpuStatsAppInfo&) = default;
+ virtual ~GpuStatsAppInfo() = default;
+ virtual status_t writeToParcel(Parcel* parcel) const;
+ virtual status_t readFromParcel(const Parcel* parcel);
+ std::string toString() const;
+
+ std::string appPackageName = "";
+ uint64_t driverVersionCode = 0;
+ std::vector<int64_t> glDriverLoadingTime = {};
+ std::vector<int64_t> vkDriverLoadingTime = {};
+};
+
+} // namespace android
diff --git a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
index 20b0205..cb4239f 100644
--- a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
+++ b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
@@ -48,7 +48,7 @@
std::string driverPackageName;
std::string driverVersionName;
uint64_t driverVersionCode;
- std::string driverBuildDate;
+ int64_t driverBuildTime;
std::string appPackageName;
Driver glDriverToLoad;
Driver glDriverFallback;
@@ -59,7 +59,7 @@
: driverPackageName(""),
driverVersionName(""),
driverVersionCode(0),
- driverBuildDate(""),
+ driverBuildTime(0),
appPackageName(""),
glDriverToLoad(Driver::NONE),
glDriverFallback(Driver::NONE),
@@ -77,10 +77,13 @@
// (drivers must be stored uncompressed and page aligned); such elements
// in the search path must have a '!' after the zip filename, e.g.
// /data/app/com.example.driver/base.apk!/lib/arm64-v8a
- void setDriverPath(const std::string path);
+ // Also set additional required sphal libraries to the linker for loading
+ // graphics drivers. The string is a list of libraries separated by ':',
+ // which is required by android_link_namespaces.
+ void setDriverPathAndSphalLibraries(const std::string path, const std::string sphalLibraries);
android_namespace_t* getDriverNamespace();
void setGpuStats(const std::string& driverPackageName, const std::string& driverVersionName,
- uint64_t versionCode, const std::string& driverBuildDate,
+ uint64_t versionCode, int64_t driverBuildTime,
const std::string& appPackageName);
void setDriverToLoad(Driver driver);
void setDriverLoaded(Api api, bool isDriverLoaded, int64_t driverLoadingTime);
@@ -118,6 +121,7 @@
GraphicsEnv() = default;
std::string mDriverPath;
+ std::string mSphalLibraries;
std::mutex mStatsLock;
GpuStats mGpuStats;
std::string mAnglePath;
diff --git a/libs/graphicsenv/include/graphicsenv/IGpuService.h b/libs/graphicsenv/include/graphicsenv/IGpuService.h
index 105a903..e7cdb38 100644
--- a/libs/graphicsenv/include/graphicsenv/IGpuService.h
+++ b/libs/graphicsenv/include/graphicsenv/IGpuService.h
@@ -16,12 +16,13 @@
#pragma once
+#include <vector>
+
#include <binder/IInterface.h>
#include <cutils/compiler.h>
+#include <graphicsenv/GpuStatsInfo.h>
#include <graphicsenv/GraphicsEnv.h>
-#include <vector>
-
namespace android {
/*
@@ -35,15 +36,19 @@
// set GPU stats from GraphicsEnvironment.
virtual void setGpuStats(const std::string& driverPackageName,
const std::string& driverVersionName, uint64_t driverVersionCode,
- const std::string& driverBuildDate, const std::string& appPackageName,
+ int64_t driverBuildTime, const std::string& appPackageName,
GraphicsEnv::Driver driver, bool isDriverLoaded,
int64_t driverLoadingTime) = 0;
+
+ // get GPU global stats from GpuStats module.
+ virtual status_t getGpuStatsGlobalInfo(std::vector<GpuStatsGlobalInfo>* outStats) const = 0;
};
class BnGpuService : public BnInterface<IGpuService> {
public:
enum IGpuServiceTag {
SET_GPU_STATS = IBinder::FIRST_CALL_TRANSACTION,
+ GET_GPU_STATS_GLOBAL_INFO,
// Always append new enum to the end.
};
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index 9197262..400daf0 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -100,7 +100,7 @@
const ui::Dataspace reqDataspace,
const ui::PixelFormat reqPixelFormat, Rect sourceCrop,
uint32_t reqWidth, uint32_t reqHeight, bool useIdentityTransform,
- ISurfaceComposer::Rotation rotation) {
+ ISurfaceComposer::Rotation rotation, bool captureSecureLayers) {
Parcel data, reply;
data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
data.writeStrongBinder(display);
@@ -111,6 +111,7 @@
data.writeUint32(reqHeight);
data.writeInt32(static_cast<int32_t>(useIdentityTransform));
data.writeInt32(static_cast<int32_t>(rotation));
+ data.writeInt32(static_cast<int32_t>(captureSecureLayers));
status_t result = remote()->transact(BnSurfaceComposer::CAPTURE_SCREEN, data, &reply);
if (result != NO_ERROR) {
ALOGE("captureScreen failed to transact: %d", result);
@@ -791,26 +792,73 @@
Parcel data, reply;
status_t error = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
if (error != NO_ERROR) {
- ALOGE("addRegionSamplingListener: Failed to write interface token");
+ ALOGE("removeRegionSamplingListener: Failed to write interface token");
return error;
}
error = data.writeStrongBinder(IInterface::asBinder(listener));
if (error != NO_ERROR) {
- ALOGE("addRegionSamplingListener: Failed to write listener");
+ ALOGE("removeRegionSamplingListener: Failed to write listener");
return error;
}
error = remote()->transact(BnSurfaceComposer::REMOVE_REGION_SAMPLING_LISTENER, data,
&reply);
if (error != NO_ERROR) {
- ALOGE("addRegionSamplingListener: Failed to transact");
+ ALOGE("removeRegionSamplingListener: Failed to transact");
}
return error;
}
- virtual void setInputWindowsFinished() {
+ virtual status_t setAllowedDisplayConfigs(const sp<IBinder>& displayToken,
+ const std::vector<int32_t>& allowedConfigs) {
Parcel data, reply;
- data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
- remote()->transact(BnSurfaceComposer::SET_INPUT_WINDOWS_FINISHED, data, &reply);
+ status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+ if (result != NO_ERROR) {
+ ALOGE("setAllowedDisplayConfigs failed to writeInterfaceToken: %d", result);
+ return result;
+ }
+ result = data.writeStrongBinder(displayToken);
+ if (result != NO_ERROR) {
+ ALOGE("setAllowedDisplayConfigs failed to writeStrongBinder: %d", result);
+ return result;
+ }
+ result = data.writeInt32Vector(allowedConfigs);
+ if (result != NO_ERROR) {
+ ALOGE("setAllowedDisplayConfigs failed to writeInt32Vector: %d", result);
+ return result;
+ }
+ result = remote()->transact(BnSurfaceComposer::SET_ALLOWED_DISPLAY_CONFIGS, data, &reply);
+ if (result != NO_ERROR) {
+ ALOGE("setAllowedDisplayConfigs failed to transact: %d", result);
+ return result;
+ }
+ return reply.readInt32();
+ }
+
+ virtual status_t getAllowedDisplayConfigs(const sp<IBinder>& displayToken,
+ std::vector<int32_t>* outAllowedConfigs) {
+ if (!outAllowedConfigs) return BAD_VALUE;
+ Parcel data, reply;
+ status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+ if (result != NO_ERROR) {
+ ALOGE("getAllowedDisplayConfigs failed to writeInterfaceToken: %d", result);
+ return result;
+ }
+ result = data.writeStrongBinder(displayToken);
+ if (result != NO_ERROR) {
+ ALOGE("getAllowedDisplayConfigs failed to writeStrongBinder: %d", result);
+ return result;
+ }
+ result = remote()->transact(BnSurfaceComposer::GET_ALLOWED_DISPLAY_CONFIGS, data, &reply);
+ if (result != NO_ERROR) {
+ ALOGE("getAllowedDisplayConfigs failed to transact: %d", result);
+ return result;
+ }
+ result = reply.readInt32Vector(outAllowedConfigs);
+ if (result != NO_ERROR) {
+ ALOGE("getAllowedDisplayConfigs failed to readInt32Vector: %d", result);
+ return result;
+ }
+ return reply.readInt32();
}
};
@@ -890,10 +938,11 @@
uint32_t reqHeight = data.readUint32();
bool useIdentityTransform = static_cast<bool>(data.readInt32());
int32_t rotation = data.readInt32();
+ bool captureSecureLayers = static_cast<bool>(data.readInt32());
status_t res = captureScreen(display, &outBuffer, reqDataspace, reqPixelFormat,
sourceCrop, reqWidth, reqHeight, useIdentityTransform,
- static_cast<ISurfaceComposer::Rotation>(rotation));
+ static_cast<ISurfaceComposer::Rotation>(rotation), captureSecureLayers);
reply->writeInt32(res);
if (res == NO_ERROR) {
reply->write(*outBuffer);
@@ -1323,10 +1372,23 @@
}
return removeRegionSamplingListener(listener);
}
- case SET_INPUT_WINDOWS_FINISHED: {
+ case SET_ALLOWED_DISPLAY_CONFIGS: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
- setInputWindowsFinished();
- return NO_ERROR;
+ sp<IBinder> displayToken = data.readStrongBinder();
+ std::vector<int32_t> allowedConfigs;
+ data.readInt32Vector(&allowedConfigs);
+ status_t result = setAllowedDisplayConfigs(displayToken, allowedConfigs);
+ reply->writeInt32(result);
+ return result;
+ }
+ case GET_ALLOWED_DISPLAY_CONFIGS: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
+ sp<IBinder> displayToken = data.readStrongBinder();
+ std::vector<int32_t> allowedConfigs;
+ status_t result = getAllowedDisplayConfigs(displayToken, &allowedConfigs);
+ reply->writeInt32Vector(allowedConfigs);
+ reply->writeInt32(result);
+ return result;
}
default: {
return BBinder::onTransact(code, data, reply, flags);
diff --git a/libs/gui/LayerMetadata.cpp b/libs/gui/LayerMetadata.cpp
index 745433a..04d2871 100644
--- a/libs/gui/LayerMetadata.cpp
+++ b/libs/gui/LayerMetadata.cpp
@@ -31,10 +31,23 @@
LayerMetadata::LayerMetadata(LayerMetadata&& other) = default;
-void LayerMetadata::merge(const LayerMetadata& other) {
+bool LayerMetadata::merge(const LayerMetadata& other, bool eraseEmpty) {
+ bool changed = false;
for (const auto& entry : other.mMap) {
- mMap[entry.first] = entry.second;
+ auto it = mMap.find(entry.first);
+ if (it != mMap.cend() && it->second != entry.second) {
+ if (eraseEmpty && entry.second.empty()) {
+ mMap.erase(it);
+ } else {
+ it->second = entry.second;
+ }
+ changed = true;
+ } else if (it == mMap.cend() && !entry.second.empty()) {
+ mMap[entry.first] = entry.second;
+ changed = true;
+ }
}
+ return changed;
}
status_t LayerMetadata::writeToParcel(Parcel* parcel) const {
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 8c2538c..050ba87 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -189,7 +189,7 @@
}
void TransactionCompletedListener::onTransactionCompleted(ListenerStats listenerStats) {
- std::lock_guard lock(mMutex);
+ std::lock_guard<std::mutex> lock(mMutex);
/* This listener knows all the sp<IBinder> to sp<SurfaceControl> for all its registered
* callbackIds, except for when Transactions are merged together. This probably cannot be
@@ -242,7 +242,7 @@
}
int32_t getId(const sp<GraphicBuffer>& buffer) {
- std::lock_guard lock(mMutex);
+ std::lock_guard<std::mutex> lock(mMutex);
auto itr = mBuffers.find(buffer);
if (itr == mBuffers.end()) {
@@ -253,7 +253,7 @@
}
int32_t cache(const sp<GraphicBuffer>& buffer) {
- std::lock_guard lock(mMutex);
+ std::lock_guard<std::mutex> lock(mMutex);
int32_t bufferId = getNextAvailableId();
@@ -1382,6 +1382,18 @@
return ComposerService::getComposerService()->setActiveConfig(display, id);
}
+status_t SurfaceComposerClient::setAllowedDisplayConfigs(
+ const sp<IBinder>& displayToken, const std::vector<int32_t>& allowedConfigs) {
+ return ComposerService::getComposerService()->setAllowedDisplayConfigs(displayToken,
+ allowedConfigs);
+}
+
+status_t SurfaceComposerClient::getAllowedDisplayConfigs(const sp<IBinder>& displayToken,
+ std::vector<int32_t>* outAllowedConfigs) {
+ return ComposerService::getComposerService()->getAllowedDisplayConfigs(displayToken,
+ outAllowedConfigs);
+}
+
status_t SurfaceComposerClient::getDisplayColorModes(const sp<IBinder>& display,
Vector<ColorMode>* outColorModes) {
return ComposerService::getComposerService()->getDisplayColorModes(display, outColorModes);
@@ -1469,18 +1481,27 @@
status_t ScreenshotClient::capture(const sp<IBinder>& display, const ui::Dataspace reqDataSpace,
const ui::PixelFormat reqPixelFormat, Rect sourceCrop,
uint32_t reqWidth, uint32_t reqHeight, bool useIdentityTransform,
- uint32_t rotation, sp<GraphicBuffer>* outBuffer) {
+ uint32_t rotation, bool captureSecureLayers, sp<GraphicBuffer>* outBuffer) {
sp<ISurfaceComposer> s(ComposerService::getComposerService());
if (s == nullptr) return NO_INIT;
status_t ret = s->captureScreen(display, outBuffer, reqDataSpace, reqPixelFormat, sourceCrop,
- reqWidth, reqHeight, useIdentityTransform,
- static_cast<ISurfaceComposer::Rotation>(rotation));
+ reqWidth, reqHeight, useIdentityTransform,
+ static_cast<ISurfaceComposer::Rotation>(rotation),
+ captureSecureLayers);
if (ret != NO_ERROR) {
return ret;
}
return ret;
}
+status_t ScreenshotClient::capture(const sp<IBinder>& display, const ui::Dataspace reqDataSpace,
+ const ui::PixelFormat reqPixelFormat, Rect sourceCrop,
+ uint32_t reqWidth, uint32_t reqHeight, bool useIdentityTransform,
+ uint32_t rotation, sp<GraphicBuffer>* outBuffer) {
+ return capture(display, reqDataSpace, reqPixelFormat, sourceCrop, reqWidth,
+ reqHeight, useIdentityTransform, rotation, false, outBuffer);
+}
+
status_t ScreenshotClient::captureLayers(const sp<IBinder>& layerHandle,
const ui::Dataspace reqDataSpace,
const ui::PixelFormat reqPixelFormat, Rect sourceCrop,
diff --git a/libs/gui/include/gui/DisplayEventReceiver.h b/libs/gui/include/gui/DisplayEventReceiver.h
index 8c3f463..22de751 100644
--- a/libs/gui/include/gui/DisplayEventReceiver.h
+++ b/libs/gui/include/gui/DisplayEventReceiver.h
@@ -52,6 +52,7 @@
enum {
DISPLAY_EVENT_VSYNC = fourcc('v', 's', 'y', 'n'),
DISPLAY_EVENT_HOTPLUG = fourcc('p', 'l', 'u', 'g'),
+ DISPLAY_EVENT_CONFIG_CHANGED = fourcc('c', 'o', 'n', 'f'),
};
struct Event {
@@ -70,10 +71,15 @@
bool connected;
};
+ struct Config {
+ int32_t configId;
+ };
+
Header header;
union {
VSync vsync;
Hotplug hotplug;
+ Config config;
};
};
diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
index c2d7d28..0e576ca 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -209,7 +209,8 @@
const ui::Dataspace reqDataspace,
const ui::PixelFormat reqPixelFormat, Rect sourceCrop,
uint32_t reqWidth, uint32_t reqHeight, bool useIdentityTransform,
- Rotation rotation = eRotateNone) = 0;
+ Rotation rotation = eRotateNone,
+ bool captureSecureLayers = false) = 0;
/**
* Capture the specified screen. This requires READ_FRAME_BUFFER
* permission. This function will fail if there is a secure window on
@@ -360,7 +361,21 @@
*/
virtual status_t removeRegionSamplingListener(const sp<IRegionSamplingListener>& listener) = 0;
- virtual void setInputWindowsFinished() = 0;
+ /*
+ * Sets the allowed display configurations to be used.
+ * The allowedConfigs in a vector of indexes corresponding to the configurations
+ * returned from getDisplayConfigs().
+ */
+ virtual status_t setAllowedDisplayConfigs(const sp<IBinder>& displayToken,
+ const std::vector<int32_t>& allowedConfigs) = 0;
+
+ /*
+ * Returns the allowed display configurations currently set.
+ * The allowedConfigs in a vector of indexes corresponding to the configurations
+ * returned from getDisplayConfigs().
+ */
+ virtual status_t getAllowedDisplayConfigs(const sp<IBinder>& displayToken,
+ std::vector<int32_t>* outAllowedConfigs) = 0;
};
// ----------------------------------------------------------------------------
@@ -408,8 +423,8 @@
GET_PHYSICAL_DISPLAY_IDS,
ADD_REGION_SAMPLING_LISTENER,
REMOVE_REGION_SAMPLING_LISTENER,
- SET_INPUT_WINDOWS_FINISHED,
-
+ SET_ALLOWED_DISPLAY_CONFIGS,
+ GET_ALLOWED_DISPLAY_CONFIGS,
// Always append new enum to the end.
};
diff --git a/libs/gui/include/gui/LayerMetadata.h b/libs/gui/include/gui/LayerMetadata.h
index 3ae10e4..47f0ced 100644
--- a/libs/gui/include/gui/LayerMetadata.h
+++ b/libs/gui/include/gui/LayerMetadata.h
@@ -34,7 +34,9 @@
LayerMetadata& operator=(const LayerMetadata& other);
LayerMetadata& operator=(LayerMetadata&& other);
- void merge(const LayerMetadata& other);
+ // Merges other into this LayerMetadata. If eraseEmpty is true, any entries in
+ // in this whose keys are paired with empty values in other will be erased.
+ bool merge(const LayerMetadata& other, bool eraseEmpty = false);
status_t writeToParcel(Parcel* parcel) const override;
status_t readFromParcel(const Parcel* parcel) override;
diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h
index 8430874..32d7391 100644
--- a/libs/gui/include/gui/LayerState.h
+++ b/libs/gui/include/gui/LayerState.h
@@ -254,7 +254,7 @@
};
std::vector<TransferTouchFocusCommand> transferTouchFocusCommands;
- bool syncInputWindows;
+ bool syncInputWindows{false};
void merge(const InputWindowCommands& other);
void clear();
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index cb38209..e062339 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -111,6 +111,18 @@
// returned by getDisplayInfo
static status_t setActiveConfig(const sp<IBinder>& display, int id);
+ // Sets the allowed display configurations to be used.
+ // The allowedConfigs in a vector of indexes corresponding to the configurations
+ // returned from getDisplayConfigs().
+ static status_t setAllowedDisplayConfigs(const sp<IBinder>& displayToken,
+ const std::vector<int32_t>& allowedConfigs);
+
+ // Returns the allowed display configurations currently set.
+ // The allowedConfigs in a vector of indexes corresponding to the configurations
+ // returned from getDisplayConfigs().
+ static status_t getAllowedDisplayConfigs(const sp<IBinder>& displayToken,
+ std::vector<int32_t>* outAllowedConfigs);
+
// Gets the list of supported color modes for the given display
static status_t getDisplayColorModes(const sp<IBinder>& display,
Vector<ui::ColorMode>* outColorModes);
@@ -454,6 +466,10 @@
static status_t capture(const sp<IBinder>& display, const ui::Dataspace reqDataSpace,
const ui::PixelFormat reqPixelFormat, Rect sourceCrop,
uint32_t reqWidth, uint32_t reqHeight, bool useIdentityTransform,
+ uint32_t rotation, bool captureSecureLayers, sp<GraphicBuffer>* outBuffer);
+ static status_t capture(const sp<IBinder>& display, const ui::Dataspace reqDataSpace,
+ const ui::PixelFormat reqPixelFormat, Rect sourceCrop,
+ uint32_t reqWidth, uint32_t reqHeight, bool useIdentityTransform,
uint32_t rotation, sp<GraphicBuffer>* outBuffer);
static status_t captureLayers(const sp<IBinder>& layerHandle, const ui::Dataspace reqDataSpace,
const ui::PixelFormat reqPixelFormat, Rect sourceCrop,
diff --git a/libs/gui/tests/Android.bp b/libs/gui/tests/Android.bp
index f020a40..ab6dcaa 100644
--- a/libs/gui/tests/Android.bp
+++ b/libs/gui/tests/Android.bp
@@ -23,6 +23,7 @@
"IGraphicBufferProducer_test.cpp",
"Malicious.cpp",
"MultiTextureConsumer_test.cpp",
+ "RegionSampling_test.cpp",
"StreamSplitter_test.cpp",
"SurfaceTextureClient_test.cpp",
"SurfaceTextureFBO_test.cpp",
@@ -87,3 +88,26 @@
"libdvr_headers",
],
}
+
+cc_test {
+ name: "SamplingDemo",
+
+ clang: true,
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
+
+ srcs: [
+ "SamplingDemo.cpp",
+ ],
+
+ shared_libs: [
+ "libbinder",
+ "libcutils",
+ "libgui",
+ "liblog",
+ "libui",
+ "libutils",
+ ]
+}
diff --git a/libs/gui/tests/RegionSampling_test.cpp b/libs/gui/tests/RegionSampling_test.cpp
new file mode 100644
index 0000000..5652c0c
--- /dev/null
+++ b/libs/gui/tests/RegionSampling_test.cpp
@@ -0,0 +1,300 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+#include <thread>
+
+#include <binder/ProcessState.h>
+#include <gui/DisplayEventReceiver.h>
+#include <gui/IRegionSamplingListener.h>
+#include <gui/ISurfaceComposer.h>
+#include <gui/Surface.h>
+#include <gui/SurfaceComposerClient.h>
+#include <private/gui/ComposerService.h>
+#include <utils/Looper.h>
+
+using namespace std::chrono_literals;
+
+namespace android::test {
+
+struct ChoreographerSync {
+ ChoreographerSync(DisplayEventReceiver& receiver) : receiver_(receiver) {}
+ ~ChoreographerSync() = default;
+
+ void notify() const {
+ std::unique_lock<decltype(mutex_)> lk(mutex_);
+
+ auto check_event = [](auto const& ev) -> bool {
+ return ev.header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC;
+ };
+ DisplayEventReceiver::Event ev_;
+ int evs = receiver_.getEvents(&ev_, 1);
+ auto vsync_event_found = check_event(ev_);
+ while (evs) {
+ evs = receiver_.getEvents(&ev_, 1);
+ vsync_event_found |= check_event(ev_);
+ }
+
+ if (vsync_event_found) {
+ notification_arrived_ = true;
+ cv_.notify_all();
+ }
+ }
+
+ void wait_vsync_notify() const {
+ std::unique_lock<decltype(mutex_)> lk(mutex_);
+ cv_.wait(lk, [this] { return notification_arrived_; });
+ notification_arrived_ = false;
+ }
+
+private:
+ ChoreographerSync(ChoreographerSync const&) = delete;
+ ChoreographerSync& operator=(ChoreographerSync const&) = delete;
+
+ std::mutex mutable mutex_;
+ std::condition_variable mutable cv_;
+ bool mutable notification_arrived_ = false;
+ DisplayEventReceiver& receiver_;
+};
+
+struct ChoreographerSim {
+ static std::unique_ptr<ChoreographerSim> make() {
+ auto receiver = std::make_unique<DisplayEventReceiver>();
+ if (!receiver || receiver->initCheck() == NO_INIT) {
+ ALOGE("No display reciever");
+ return nullptr;
+ }
+ return std::unique_ptr<ChoreographerSim>(new ChoreographerSim(std::move(receiver)));
+ }
+
+ ~ChoreographerSim() {
+ poll_ = false;
+ looper->wake();
+ choreographer_thread_.join();
+ }
+
+ void request_render_wait(std::function<void()> const& render_fn) {
+ display_event_receiver_->requestNextVsync();
+ choreographer_.wait_vsync_notify();
+ render_fn();
+
+ // Purpose is to make sure that the content is latched by the time we sample.
+ // Waiting one vsync after queueing could still race with vsync, so wait for two, after
+ // which the content is pretty reliably on screen.
+ display_event_receiver_->requestNextVsync();
+ choreographer_.wait_vsync_notify();
+ display_event_receiver_->requestNextVsync();
+ choreographer_.wait_vsync_notify();
+ }
+
+private:
+ ChoreographerSim(std::unique_ptr<DisplayEventReceiver> receiver)
+ : display_event_receiver_{std::move(receiver)},
+ choreographer_{*display_event_receiver_},
+ looper{new Looper(false)} {
+ choreographer_thread_ = std::thread([this] {
+ auto vsync_notify_fd = display_event_receiver_->getFd();
+ looper->addFd(vsync_notify_fd, 0, Looper::EVENT_INPUT,
+ [](int /*fd*/, int /*events*/, void* data) -> int {
+ if (!data) return 0;
+ reinterpret_cast<ChoreographerSync*>(data)->notify();
+ return 1;
+ },
+ const_cast<void*>(reinterpret_cast<void const*>(&choreographer_)));
+
+ while (poll_) {
+ auto const poll_interval =
+ std::chrono::duration_cast<std::chrono::milliseconds>(1s).count();
+ auto rc = looper->pollOnce(poll_interval);
+ if ((rc != Looper::POLL_CALLBACK) && (rc != Looper::POLL_WAKE))
+ ALOGW("Vsync Looper returned: %i\n", rc);
+ }
+ });
+ }
+
+ ChoreographerSim(ChoreographerSim const&) = delete;
+ ChoreographerSim& operator=(ChoreographerSim const&) = delete;
+
+ std::unique_ptr<DisplayEventReceiver> const display_event_receiver_;
+ ChoreographerSync const choreographer_;
+ sp<Looper> looper;
+ std::thread choreographer_thread_;
+ std::atomic<bool> poll_{true};
+};
+
+struct Listener : BnRegionSamplingListener {
+ void onSampleCollected(float medianLuma) override {
+ std::unique_lock<decltype(mutex)> lk(mutex);
+ received = true;
+ mLuma = medianLuma;
+ cv.notify_all();
+ };
+ bool wait_event(std::chrono::milliseconds timeout) {
+ std::unique_lock<decltype(mutex)> lk(mutex);
+ return cv.wait_for(lk, timeout, [this] { return received; });
+ }
+
+ float luma() {
+ std::unique_lock<decltype(mutex)> lk(mutex);
+ return mLuma;
+ }
+
+ void reset() {
+ std::unique_lock<decltype(mutex)> lk(mutex);
+ received = false;
+ }
+
+private:
+ std::condition_variable cv;
+ std::mutex mutex;
+ bool received = false;
+ float mLuma = -0.0f;
+};
+
+// Hoisted to TestSuite setup to avoid flake in test (b/124675919)
+std::unique_ptr<ChoreographerSim> gChoreographerSim = nullptr;
+
+struct RegionSamplingTest : ::testing::Test {
+protected:
+ RegionSamplingTest() { ProcessState::self()->startThreadPool(); }
+
+ static void SetUpTestSuite() {
+ gChoreographerSim = ChoreographerSim::make();
+ ASSERT_NE(gChoreographerSim, nullptr);
+ }
+
+ void SetUp() override {
+ mSurfaceComposerClient = new SurfaceComposerClient;
+ ASSERT_EQ(NO_ERROR, mSurfaceComposerClient->initCheck());
+
+ mBackgroundLayer =
+ mSurfaceComposerClient->createSurface(String8("Background RegionSamplingTest"), 0,
+ 0, PIXEL_FORMAT_RGBA_8888,
+ ISurfaceComposerClient::eFXSurfaceColor);
+ uint32_t layerPositionBottom = 0x7E000000;
+ SurfaceComposerClient::Transaction{}
+ .setLayer(mBackgroundLayer, layerPositionBottom)
+ .setPosition(mBackgroundLayer, 100, 100)
+ .setColor(mBackgroundLayer, half3{0.5, 0.5, 0.5})
+ .show(mBackgroundLayer)
+ .apply();
+
+ mContentLayer = mSurfaceComposerClient->createSurface(String8("Content RegionSamplingTest"),
+ 300, 300, PIXEL_FORMAT_RGBA_8888, 0);
+
+ SurfaceComposerClient::Transaction{}
+ .setLayer(mContentLayer, layerPositionBottom + 1)
+ .setPosition(mContentLayer, 100, 100)
+ .setColor(mContentLayer, half3{0.5, 0.5, 0.5})
+ .show(mContentLayer)
+ .apply();
+
+ mTopLayer = mSurfaceComposerClient->createSurface(String8("TopLayer RegionSamplingTest"), 0,
+ 0, PIXEL_FORMAT_RGBA_8888, 0);
+ SurfaceComposerClient::Transaction{}
+ .setLayer(mTopLayer, layerPositionBottom + 2)
+ .setPosition(mTopLayer, 0, 0)
+ .show(mBackgroundLayer)
+ .apply();
+ }
+
+ void fill_render(uint32_t rgba_value) {
+ auto surface = mContentLayer->getSurface();
+ ANativeWindow_Buffer outBuffer;
+ status_t status = surface->lock(&outBuffer, NULL);
+ ASSERT_EQ(status, android::OK);
+ auto b = reinterpret_cast<uint32_t*>(outBuffer.bits);
+ for (auto i = 0; i < outBuffer.height; i++) {
+ for (auto j = 0; j < outBuffer.width; j++) {
+ b[j] = rgba_value;
+ }
+ b += outBuffer.stride;
+ }
+
+ gChoreographerSim->request_render_wait([&surface] { surface->unlockAndPost(); });
+ }
+
+ sp<SurfaceComposerClient> mSurfaceComposerClient;
+ sp<SurfaceControl> mBackgroundLayer;
+ sp<SurfaceControl> mContentLayer;
+ sp<SurfaceControl> mTopLayer;
+
+ uint32_t const rgba_green = 0xFF00FF00;
+ float const luma_green = 0.7152;
+ uint32_t const rgba_blue = 0xFFFF0000;
+ float const luma_blue = 0.0722;
+ float const error_margin = 0.01;
+ float const luma_gray = 0.50;
+};
+
+TEST_F(RegionSamplingTest, CollectsLuma) {
+ fill_render(rgba_green);
+
+ sp<ISurfaceComposer> composer = ComposerService::getComposerService();
+ sp<Listener> listener = new Listener();
+ const Rect sampleArea{100, 100, 200, 200};
+ composer->addRegionSamplingListener(sampleArea, mTopLayer->getHandle(), listener);
+
+ EXPECT_TRUE(listener->wait_event(300ms)) << "timed out waiting for luma event to be received";
+ EXPECT_NEAR(listener->luma(), luma_green, error_margin);
+
+ composer->removeRegionSamplingListener(listener);
+}
+
+TEST_F(RegionSamplingTest, CollectsChangingLuma) {
+ fill_render(rgba_green);
+
+ sp<ISurfaceComposer> composer = ComposerService::getComposerService();
+ sp<Listener> listener = new Listener();
+ const Rect sampleArea{100, 100, 200, 200};
+ composer->addRegionSamplingListener(sampleArea, mTopLayer->getHandle(), listener);
+
+ EXPECT_TRUE(listener->wait_event(300ms)) << "timed out waiting for luma event to be received";
+ EXPECT_NEAR(listener->luma(), luma_green, error_margin);
+
+ listener->reset();
+
+ fill_render(rgba_blue);
+ EXPECT_TRUE(listener->wait_event(300ms))
+ << "timed out waiting for 2nd luma event to be received";
+ EXPECT_NEAR(listener->luma(), luma_blue, error_margin);
+
+ composer->removeRegionSamplingListener(listener);
+}
+
+TEST_F(RegionSamplingTest, CollectsLumaFromTwoRegions) {
+ fill_render(rgba_green);
+ sp<ISurfaceComposer> composer = ComposerService::getComposerService();
+ sp<Listener> greenListener = new Listener();
+ const Rect greenSampleArea{100, 100, 200, 200};
+ composer->addRegionSamplingListener(greenSampleArea, mTopLayer->getHandle(), greenListener);
+
+ sp<Listener> grayListener = new Listener();
+ const Rect graySampleArea{500, 100, 600, 200};
+ composer->addRegionSamplingListener(graySampleArea, mTopLayer->getHandle(), grayListener);
+
+ EXPECT_TRUE(grayListener->wait_event(300ms))
+ << "timed out waiting for luma event to be received";
+ EXPECT_NEAR(grayListener->luma(), luma_gray, error_margin);
+ EXPECT_TRUE(greenListener->wait_event(300ms))
+ << "timed out waiting for luma event to be received";
+ EXPECT_NEAR(greenListener->luma(), luma_green, error_margin);
+
+ composer->removeRegionSamplingListener(greenListener);
+ composer->removeRegionSamplingListener(grayListener);
+}
+
+} // namespace android::test
diff --git a/libs/gui/tests/SamplingDemo.cpp b/libs/gui/tests/SamplingDemo.cpp
new file mode 100644
index 0000000..9891587
--- /dev/null
+++ b/libs/gui/tests/SamplingDemo.cpp
@@ -0,0 +1,135 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+#define LOG_TAG "SamplingTest"
+
+#include <chrono>
+#include <thread>
+
+#include <binder/IPCThreadState.h>
+#include <binder/ProcessState.h>
+#include <gui/IRegionSamplingListener.h>
+#include <gui/ISurfaceComposer.h>
+#include <gui/SurfaceComposerClient.h>
+#include <gui/SurfaceControl.h>
+#include <private/gui/ComposerService.h>
+#include <utils/Trace.h>
+
+using namespace std::chrono_literals;
+
+namespace android {
+
+class Button : public BnRegionSamplingListener {
+public:
+ Button(const char* name, const Rect& samplingArea) {
+ sp<SurfaceComposerClient> client = new SurfaceComposerClient;
+
+ mButton = client->createSurface(String8(name), 0, 0, PIXEL_FORMAT_RGBA_8888,
+ ISurfaceComposerClient::eFXSurfaceColor);
+
+ const int32_t width = samplingArea.getWidth();
+ const int32_t height = samplingArea.getHeight();
+
+ SurfaceComposerClient::Transaction{}
+ .setLayer(mButton, 0x7fffffff)
+ .setCrop_legacy(mButton,
+ {0, 0, width - 2 * BUTTON_PADDING, height - 2 * BUTTON_PADDING})
+ .setPosition(mButton, samplingArea.left + BUTTON_PADDING,
+ samplingArea.top + BUTTON_PADDING)
+ .setColor(mButton, half3{1, 1, 1})
+ .show(mButton)
+ .apply();
+
+ mButtonBlend = client->createSurface(String8(name) + "Blend", 0, 0, PIXEL_FORMAT_RGBA_8888,
+ ISurfaceComposerClient::eFXSurfaceColor);
+
+ SurfaceComposerClient::Transaction{}
+ .setLayer(mButtonBlend, 0x7ffffffe)
+ .setCrop_legacy(mButtonBlend,
+ {0, 0, width - 2 * SAMPLE_AREA_PADDING,
+ height - 2 * SAMPLE_AREA_PADDING})
+ .setPosition(mButtonBlend, samplingArea.left + SAMPLE_AREA_PADDING,
+ samplingArea.top + SAMPLE_AREA_PADDING)
+ .setColor(mButtonBlend, half3{1, 1, 1})
+ .setAlpha(mButtonBlend, 0.2)
+ .show(mButtonBlend)
+ .apply(true);
+
+ const bool HIGHLIGHT_SAMPLING_AREA = false;
+ if (HIGHLIGHT_SAMPLING_AREA) {
+ mSamplingArea =
+ client->createSurface(String8("SamplingArea"), 0, 0, PIXEL_FORMAT_RGBA_8888,
+ ISurfaceComposerClient::eFXSurfaceColor);
+
+ SurfaceComposerClient::Transaction{}
+ .setLayer(mSamplingArea, 0x7ffffffd)
+ .setCrop_legacy(mSamplingArea, {0, 0, 100, 32})
+ .setPosition(mSamplingArea, 490, 1606)
+ .setColor(mSamplingArea, half3{0, 1, 0})
+ .setAlpha(mSamplingArea, 0.1)
+ .show(mSamplingArea)
+ .apply();
+ }
+ }
+
+ sp<IBinder> getStopLayerHandle() { return mButtonBlend->getHandle(); }
+
+private:
+ static const int32_t BLEND_WIDTH = 2;
+ static const int32_t SAMPLE_AREA_PADDING = 8;
+ static const int32_t BUTTON_PADDING = BLEND_WIDTH + SAMPLE_AREA_PADDING;
+
+ void setColor(float color) {
+ const float complement = std::fmod(color + 0.5f, 1.0f);
+ SurfaceComposerClient::Transaction{}
+ .setColor(mButton, half3{complement, complement, complement})
+ .setColor(mButtonBlend, half3{color, color, color})
+ .apply();
+ }
+
+ void onSampleCollected(float medianLuma) override {
+ ATRACE_CALL();
+ setColor(medianLuma);
+ }
+
+ sp<SurfaceComposerClient> mClient;
+ sp<SurfaceControl> mButton;
+ sp<SurfaceControl> mButtonBlend;
+ sp<SurfaceControl> mSamplingArea;
+};
+
+} // namespace android
+
+using namespace android;
+
+int main(int, const char**) {
+ const Rect homeButtonArea{490, 1606, 590, 1654};
+ sp<android::Button> homeButton = new android::Button("HomeButton", homeButtonArea);
+ const Rect backButtonArea{200, 1606, 248, 1654};
+ sp<android::Button> backButton = new android::Button("BackButton", backButtonArea);
+
+ sp<ISurfaceComposer> composer = ComposerService::getComposerService();
+ composer->addRegionSamplingListener(homeButtonArea, homeButton->getStopLayerHandle(),
+ homeButton);
+ composer->addRegionSamplingListener(backButtonArea, backButton->getStopLayerHandle(),
+ backButton);
+
+ ProcessState::self()->startThreadPool();
+ IPCThreadState::self()->joinThreadPool();
+
+ return 0;
+}
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index 8225647..a7599e0 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -615,7 +615,8 @@
const ui::Dataspace /*reqDataspace*/,
const ui::PixelFormat /*reqPixelFormat*/, Rect /*sourceCrop*/,
uint32_t /*reqWidth*/, uint32_t /*reqHeight*/,
- bool /*useIdentityTransform*/, Rotation /*rotation*/) override {
+ bool /*useIdentityTransform*/, Rotation /*rotation*/,
+ bool /*captureSecureLayers*/) override {
return NO_ERROR;
}
virtual status_t captureLayers(const sp<IBinder>& /*parentHandle*/,
@@ -678,8 +679,14 @@
const sp<IRegionSamplingListener>& /*listener*/) override {
return NO_ERROR;
}
-
- void setInputWindowsFinished() override {}
+ status_t setAllowedDisplayConfigs(const sp<IBinder>& /*displayToken*/,
+ const std::vector<int32_t>& /*allowedConfigs*/) override {
+ return NO_ERROR;
+ }
+ status_t getAllowedDisplayConfigs(const sp<IBinder>& /*displayToken*/,
+ std::vector<int32_t>* /*outAllowedConfigs*/) override {
+ return NO_ERROR;
+ }
protected:
IBinder* onAsBinder() override { return nullptr; }
diff --git a/libs/input/Android.bp b/libs/input/Android.bp
index 6aedb00..2d78811 100644
--- a/libs/input/Android.bp
+++ b/libs/input/Android.bp
@@ -47,6 +47,7 @@
"InputApplication.cpp",
"InputTransport.cpp",
"InputWindow.cpp",
+ "ISetInputWindowsListener.cpp",
"VelocityControl.cpp",
"VelocityTracker.cpp",
],
diff --git a/libs/input/IInputFlinger.cpp b/libs/input/IInputFlinger.cpp
index acf40bc..4ce5a10 100644
--- a/libs/input/IInputFlinger.cpp
+++ b/libs/input/IInputFlinger.cpp
@@ -30,7 +30,8 @@
explicit BpInputFlinger(const sp<IBinder>& impl) :
BpInterface<IInputFlinger>(impl) { }
- virtual void setInputWindows(const Vector<InputWindowInfo>& inputInfo) {
+ virtual void setInputWindows(const Vector<InputWindowInfo>& inputInfo,
+ const sp<ISetInputWindowsListener>& setInputWindowsListener) {
Parcel data, reply;
data.writeInterfaceToken(IInputFlinger::getInterfaceDescriptor());
@@ -38,6 +39,8 @@
for (const auto& info : inputInfo) {
info.write(data);
}
+ data.writeStrongBinder(IInterface::asBinder(setInputWindowsListener));
+
remote()->transact(BnInputFlinger::SET_INPUT_WINDOWS_TRANSACTION, data, &reply,
IBinder::FLAG_ONEWAY);
}
@@ -83,7 +86,9 @@
for (size_t i = 0; i < count; i++) {
handles.add(InputWindowInfo(data));
}
- setInputWindows(handles);
+ const sp<ISetInputWindowsListener> setInputWindowsListener =
+ ISetInputWindowsListener::asInterface(data.readStrongBinder());
+ setInputWindows(handles, setInputWindowsListener);
break;
}
case REGISTER_INPUT_CHANNEL_TRANSACTION: {
diff --git a/libs/input/ISetInputWindowsListener.cpp b/libs/input/ISetInputWindowsListener.cpp
new file mode 100644
index 0000000..a0330da
--- /dev/null
+++ b/libs/input/ISetInputWindowsListener.cpp
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <input/ISetInputWindowsListener.h>
+
+namespace android {
+
+class BpSetInputWindowsListener : public BpInterface<ISetInputWindowsListener> {
+public:
+ explicit BpSetInputWindowsListener(const sp<IBinder>& impl)
+ : BpInterface<ISetInputWindowsListener>(impl) {
+ }
+
+ virtual ~BpSetInputWindowsListener() = default;
+
+ virtual void onSetInputWindowsFinished() {
+ Parcel data, reply;
+ data.writeInterfaceToken(ISetInputWindowsListener::getInterfaceDescriptor());
+ remote()->transact(BnSetInputWindowsListener::ON_SET_INPUT_WINDOWS_FINISHED, data, &reply,
+ IBinder::FLAG_ONEWAY);
+ }
+};
+
+IMPLEMENT_META_INTERFACE(SetInputWindowsListener, "android.input.ISetInputWindowsListener");
+
+status_t BnSetInputWindowsListener::onTransact(uint32_t code, const Parcel& data, Parcel* reply,
+ uint32_t flags) {
+ switch(code) {
+ case ON_SET_INPUT_WINDOWS_FINISHED: {
+ CHECK_INTERFACE(ISetInputWindowsListener, data, reply);
+ onSetInputWindowsFinished();
+ return NO_ERROR;
+ }
+ default: {
+ return BBinder::onTransact(code, data, reply, flags);
+ }
+ }
+}
+
+} // namespace android
diff --git a/libs/input/InputDevice.cpp b/libs/input/InputDevice.cpp
index 778c453..dab6eac 100644
--- a/libs/input/InputDevice.cpp
+++ b/libs/input/InputDevice.cpp
@@ -46,15 +46,9 @@
static void appendInputDeviceConfigurationFileRelativePath(std::string& path,
const std::string& name, InputDeviceConfigurationFileType type) {
- path.append(CONFIGURATION_FILE_DIR[type]);
- for (size_t i = 0; i < name.length(); i++) {
- char ch = name[i];
- if (!isValidNameChar(ch)) {
- ch = '_';
- }
- path.append(&ch, 1);
- }
- path.append(CONFIGURATION_FILE_EXTENSION[type]);
+ path += CONFIGURATION_FILE_DIR[type];
+ path += name;
+ path += CONFIGURATION_FILE_EXTENSION[type];
}
std::string getInputDeviceConfigurationFilePathByDeviceIdentifier(
@@ -84,7 +78,7 @@
}
// Try device name.
- return getInputDeviceConfigurationFilePathByName(deviceIdentifier.name, type);
+ return getInputDeviceConfigurationFilePathByName(deviceIdentifier.getCanonicalName(), type);
}
std::string getInputDeviceConfigurationFilePathByName(
@@ -140,6 +134,18 @@
return "";
}
+// --- InputDeviceIdentifier
+
+std::string InputDeviceIdentifier::getCanonicalName() const {
+ std::string replacedName = name;
+ for (char& ch : replacedName) {
+ if (!isValidNameChar(ch)) {
+ ch = '_';
+ }
+ }
+ return replacedName;
+}
+
// --- InputDeviceInfo ---
diff --git a/libs/input/InputTransport.cpp b/libs/input/InputTransport.cpp
index 0f7a1f0..e13b40e 100644
--- a/libs/input/InputTransport.cpp
+++ b/libs/input/InputTransport.cpp
@@ -59,6 +59,18 @@
// far into the future. This time is further bounded by 50% of the last time delta.
static const nsecs_t RESAMPLE_MAX_PREDICTION = 8 * NANOS_PER_MS;
+/**
+ * System property for enabling / disabling touch resampling.
+ * Resampling extrapolates / interpolates the reported touch event coordinates to better
+ * align them to the VSYNC signal, thus resulting in smoother scrolling performance.
+ * Resampling is not needed (and should be disabled) on hardware that already
+ * has touch events triggered by VSYNC.
+ * Set to "1" to enable resampling (default).
+ * Set to "0" to disable resampling.
+ * Resampling is enabled by default.
+ */
+static const char* PROPERTY_RESAMPLING_ENABLED = "ro.input.resampling";
+
template<typename T>
inline static T min(const T& a, const T& b) {
return a < b ? a : b;
@@ -545,18 +557,7 @@
}
bool InputConsumer::isTouchResamplingEnabled() {
- char value[PROPERTY_VALUE_MAX];
- int length = property_get("ro.input.noresample", value, nullptr);
- if (length > 0) {
- if (!strcmp("1", value)) {
- return false;
- }
- if (strcmp("0", value)) {
- ALOGD("Unrecognized property value for 'ro.input.noresample'. "
- "Use '1' or '0'.");
- }
- }
- return true;
+ return property_get_bool(PROPERTY_RESAMPLING_ENABLED, true);
}
status_t InputConsumer::consume(InputEventFactoryInterface* factory,
diff --git a/libs/input/VirtualKeyMap.cpp b/libs/input/VirtualKeyMap.cpp
index 3ec53bf..624f152 100644
--- a/libs/input/VirtualKeyMap.cpp
+++ b/libs/input/VirtualKeyMap.cpp
@@ -28,10 +28,6 @@
// Enables debug output for the parser.
#define DEBUG_PARSER 0
-// Enables debug output for parser performance.
-#define DEBUG_PARSER_PERFORMANCE 0
-
-
namespace android {
static const char* WHITESPACE = " \t\r";
@@ -46,39 +42,28 @@
VirtualKeyMap::~VirtualKeyMap() {
}
-status_t VirtualKeyMap::load(const std::string& filename, VirtualKeyMap** outMap) {
- *outMap = nullptr;
-
- Tokenizer* tokenizer;
- status_t status = Tokenizer::open(String8(filename.c_str()), &tokenizer);
- if (status) {
+std::unique_ptr<VirtualKeyMap> VirtualKeyMap::load(const std::string& filename) {
+ Tokenizer* t;
+ status_t status = Tokenizer::open(String8(filename.c_str()), &t);
+ if (status != OK) {
ALOGE("Error %d opening virtual key map file %s.", status, filename.c_str());
- } else {
- VirtualKeyMap* map = new VirtualKeyMap();
- if (!map) {
- ALOGE("Error allocating virtual key map.");
- status = NO_MEMORY;
- } else {
-#if DEBUG_PARSER_PERFORMANCE
- nsecs_t startTime = systemTime(SYSTEM_TIME_MONOTONIC);
-#endif
- Parser parser(map, tokenizer);
- status = parser.parse();
-#if DEBUG_PARSER_PERFORMANCE
- nsecs_t elapsedTime = systemTime(SYSTEM_TIME_MONOTONIC) - startTime;
- ALOGD("Parsed key character map file '%s' %d lines in %0.3fms.",
- tokenizer->getFilename().string(), tokenizer->getLineNumber(),
- elapsedTime / 1000000.0);
-#endif
- if (status) {
- delete map;
- } else {
- *outMap = map;
- }
- }
- delete tokenizer;
+ return nullptr;
}
- return status;
+ std::unique_ptr<Tokenizer> tokenizer(t);
+ // Using 'new' to access a non-public constructor
+ std::unique_ptr<VirtualKeyMap> map(new VirtualKeyMap());
+ if (!map) {
+ ALOGE("Error allocating virtual key map.");
+ return nullptr;
+ }
+
+ Parser parser(map.get(), tokenizer.get());
+ status = parser.parse();
+ if (status != OK) {
+ return nullptr;
+ }
+
+ return map;
}
diff --git a/libs/input/tests/Android.bp b/libs/input/tests/Android.bp
index 57ba2a2..ade931e 100644
--- a/libs/input/tests/Android.bp
+++ b/libs/input/tests/Android.bp
@@ -3,6 +3,7 @@
name: "libinput_tests",
srcs: [
"InputChannel_test.cpp",
+ "InputDevice_test.cpp",
"InputEvent_test.cpp",
"InputPublisherAndConsumer_test.cpp",
"InputWindow_test.cpp",
@@ -35,6 +36,7 @@
"-O0",
"-Wall",
"-Werror",
+ "-Wextra",
],
shared_libs: [
"libinput",
diff --git a/libs/input/tests/InputDevice_test.cpp b/libs/input/tests/InputDevice_test.cpp
new file mode 100644
index 0000000..c174ae9
--- /dev/null
+++ b/libs/input/tests/InputDevice_test.cpp
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#include <gtest/gtest.h>
+#include <input/InputDevice.h>
+
+namespace android {
+
+// --- InputDeviceIdentifierTest ---
+
+TEST(InputDeviceIdentifierTest, getCanonicalName) {
+ InputDeviceIdentifier identifier;
+ identifier.name = "test device";
+ ASSERT_EQ(std::string("test_device"), identifier.getCanonicalName());
+
+ identifier.name = "deviceName-123 version_C!";
+ ASSERT_EQ(std::string("deviceName-123_version_C_"), identifier.getCanonicalName());
+}
+
+} // namespace android
\ No newline at end of file
diff --git a/libs/nativewindow/include/android/hdr_metadata.h b/libs/nativewindow/include/android/hdr_metadata.h
index 7e1313b..88772a9 100644
--- a/libs/nativewindow/include/android/hdr_metadata.h
+++ b/libs/nativewindow/include/android/hdr_metadata.h
@@ -33,6 +33,15 @@
*/
/**
+ * HDR metadata standards that are supported by Android.
+ */
+enum AHdrMetadataType : uint32_t {
+ HDR10_SMPTE2086 = 1,
+ HDR10_CTA861_3 = 2,
+ HDR10PLUS_SEI = 3,
+};
+
+/**
* Color is defined in CIE XYZ coordinates.
*/
struct AColor_xy {
diff --git a/libs/renderengine/OWNERS b/libs/renderengine/OWNERS
new file mode 100644
index 0000000..c00fbba
--- /dev/null
+++ b/libs/renderengine/OWNERS
@@ -0,0 +1,2 @@
+lpy@google.com
+stoza@google.com
diff --git a/libs/renderengine/RenderEngine.cpp b/libs/renderengine/RenderEngine.cpp
index 6dd7283..166c267 100644
--- a/libs/renderengine/RenderEngine.cpp
+++ b/libs/renderengine/RenderEngine.cpp
@@ -24,15 +24,16 @@
namespace android {
namespace renderengine {
-std::unique_ptr<impl::RenderEngine> RenderEngine::create(int hwcFormat, uint32_t featureFlags) {
+std::unique_ptr<impl::RenderEngine> RenderEngine::create(int hwcFormat, uint32_t featureFlags,
+ uint32_t imageCacheSize) {
char prop[PROPERTY_VALUE_MAX];
property_get(PROPERTY_DEBUG_RENDERENGINE_BACKEND, prop, "gles");
if (strcmp(prop, "gles") == 0) {
ALOGD("RenderEngine GLES Backend");
- return renderengine::gl::GLESRenderEngine::create(hwcFormat, featureFlags);
+ return renderengine::gl::GLESRenderEngine::create(hwcFormat, featureFlags, imageCacheSize);
}
ALOGE("UNKNOWN BackendType: %s, create GLES RenderEngine.", prop);
- return renderengine::gl::GLESRenderEngine::create(hwcFormat, featureFlags);
+ return renderengine::gl::GLESRenderEngine::create(hwcFormat, featureFlags, imageCacheSize);
}
RenderEngine::~RenderEngine() = default;
diff --git a/libs/renderengine/gl/GLESRenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp
index 8f9071e..8069a1a 100644
--- a/libs/renderengine/gl/GLESRenderEngine.cpp
+++ b/libs/renderengine/gl/GLESRenderEngine.cpp
@@ -37,6 +37,7 @@
#include <sync/sync.h>
#include <ui/ColorSpace.h>
#include <ui/DebugUtils.h>
+#include <ui/GraphicBuffer.h>
#include <ui/Rect.h>
#include <ui/Region.h>
#include <utils/KeyedVector.h>
@@ -225,7 +226,8 @@
return err;
}
-std::unique_ptr<GLESRenderEngine> GLESRenderEngine::create(int hwcFormat, uint32_t featureFlags) {
+std::unique_ptr<GLESRenderEngine> GLESRenderEngine::create(int hwcFormat, uint32_t featureFlags,
+ uint32_t imageCacheSize) {
// initialize EGL for the default display
EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
if (!eglInitialize(display, nullptr, nullptr)) {
@@ -295,7 +297,8 @@
case GLES_VERSION_2_0:
case GLES_VERSION_3_0:
engine = std::make_unique<GLESRenderEngine>(featureFlags, display, config, ctxt, dummy,
- protectedContext, protectedDummy);
+ protectedContext, protectedDummy,
+ imageCacheSize);
break;
}
@@ -351,7 +354,7 @@
GLESRenderEngine::GLESRenderEngine(uint32_t featureFlags, EGLDisplay display, EGLConfig config,
EGLContext ctxt, EGLSurface dummy, EGLContext protectedContext,
- EGLSurface protectedDummy)
+ EGLSurface protectedDummy, uint32_t imageCacheSize)
: renderengine::impl::RenderEngine(featureFlags),
mEGLDisplay(display),
mEGLConfig(config),
@@ -361,6 +364,7 @@
mProtectedDummySurface(protectedDummy),
mVpWidth(0),
mVpHeight(0),
+ mFramebufferImageCacheSize(imageCacheSize),
mUseColorManagement(featureFlags & USE_COLOR_MANAGEMENT) {
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTextureSize);
glGetIntegerv(GL_MAX_VIEWPORT_DIMS, mMaxViewportDims);
@@ -428,6 +432,10 @@
}
GLESRenderEngine::~GLESRenderEngine() {
+ for (const auto& image : mFramebufferImageCache) {
+ eglDestroyImageKHR(mEGLDisplay, image.second);
+ }
+ mFramebufferImageCache.clear();
eglMakeCurrent(mEGLDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
eglTerminate(mEGLDisplay);
}
@@ -618,22 +626,13 @@
}
status_t GLESRenderEngine::bindExternalTextureBuffer(uint32_t texName, sp<GraphicBuffer> buffer,
- sp<Fence> bufferFence, bool readCache) {
- return bindExternalTextureBuffer(texName, buffer, bufferFence, readCache,
- /*persistCache=*/false);
-}
-
-status_t GLESRenderEngine::bindExternalTextureBuffer(uint32_t texName, sp<GraphicBuffer> buffer,
- sp<Fence> bufferFence, bool readCache,
- bool persistCache) {
+ sp<Fence> bufferFence) {
ATRACE_CALL();
- if (readCache) {
- auto cachedImage = mImageCache.find(buffer->getId());
+ auto cachedImage = mImageCache.find(buffer->getId());
- if (cachedImage != mImageCache.end()) {
- bindExternalTextureImage(texName, *cachedImage->second);
- return NO_ERROR;
- }
+ if (cachedImage != mImageCache.end()) {
+ bindExternalTextureImage(texName, *cachedImage->second);
+ return NO_ERROR;
}
std::unique_ptr<Image> newImage = createImage();
@@ -670,35 +669,19 @@
}
}
}
-
- // We don't always want to persist to the cache, e.g. on older devices we
- // might bind for synchronization purposes, but that might leak if we never
- // call drawLayers again, so it's just better to recreate the image again
- // if needed when we draw.
- if (persistCache) {
- mImageCache.insert(std::make_pair(buffer->getId(), std::move(newImage)));
- }
+ mImageCache.insert(std::make_pair(buffer->getId(), std::move(newImage)));
return NO_ERROR;
}
-void GLESRenderEngine::evictImages(const std::vector<LayerSettings>& layers) {
- ATRACE_CALL();
- // destroy old image references that we're not going to draw with.
- std::unordered_set<uint64_t> bufIds;
- for (auto layer : layers) {
- if (layer.source.buffer.buffer != nullptr) {
- bufIds.emplace(layer.source.buffer.buffer->getId());
- }
+void GLESRenderEngine::unbindExternalTextureBuffer(uint64_t bufferId) {
+ const auto& cachedImage = mImageCache.find(bufferId);
+ if (cachedImage != mImageCache.end()) {
+ ALOGV("Destroying image for buffer: %" PRIu64, bufferId);
+ mImageCache.erase(bufferId);
+ return;
}
-
- for (auto it = mImageCache.begin(); it != mImageCache.end();) {
- if (bufIds.count(it->first) == 0) {
- it = mImageCache.erase(it);
- } else {
- it++;
- }
- }
+ ALOGV("Failed to find image for buffer: %" PRIu64, bufferId);
}
FloatRect GLESRenderEngine::setupLayerCropping(const LayerSettings& layer, Mesh& mesh) {
@@ -785,17 +768,48 @@
}
return success;
}
+EGLImageKHR GLESRenderEngine::createFramebufferImageIfNeeded(ANativeWindowBuffer* nativeBuffer,
+ bool isProtected) {
+ sp<GraphicBuffer> graphicBuffer = GraphicBuffer::from(nativeBuffer);
+ uint32_t bufferId = graphicBuffer->getId();
+ for (const auto& image : mFramebufferImageCache) {
+ if (image.first == bufferId) {
+ return image.second;
+ }
+ }
+ EGLint attributes[] = {
+ isProtected ? EGL_PROTECTED_CONTENT_EXT : EGL_NONE,
+ isProtected ? EGL_TRUE : EGL_NONE,
+ EGL_NONE,
+ };
+ EGLImageKHR image = eglCreateImageKHR(mEGLDisplay, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID,
+ nativeBuffer, attributes);
+ if (image != EGL_NO_IMAGE_KHR) {
+ if (mFramebufferImageCache.size() >= mFramebufferImageCacheSize) {
+ EGLImageKHR expired = mFramebufferImageCache.front().second;
+ mFramebufferImageCache.pop_front();
+ eglDestroyImageKHR(mEGLDisplay, expired);
+ }
+ mFramebufferImageCache.push_back({bufferId, image});
+ }
+ return image;
+}
status_t GLESRenderEngine::drawLayers(const DisplaySettings& display,
const std::vector<LayerSettings>& layers,
ANativeWindowBuffer* const buffer,
- base::unique_fd* drawFence) {
+ base::unique_fd&& bufferFence, base::unique_fd* drawFence) {
ATRACE_CALL();
if (layers.empty()) {
ALOGV("Drawing empty layer stack");
return NO_ERROR;
}
+ if (bufferFence.get() >= 0 && !waitFence(std::move(bufferFence))) {
+ ATRACE_NAME("Waiting before draw");
+ sync_wait(bufferFence.get(), -1);
+ }
+
BindNativeBufferAsFramebuffer fbo(*this, buffer);
if (fbo.getStatus() != NO_ERROR) {
@@ -805,8 +819,6 @@
return fbo.getStatus();
}
- evictImages(layers);
-
// clear the entire buffer, sometimes when we reuse buffers we'd persist
// ghost images otherwise.
// we also require a full transparent framebuffer for overlays. This is
@@ -849,10 +861,8 @@
isOpaque = layer.source.buffer.isOpaque;
sp<GraphicBuffer> gBuf = layer.source.buffer.buffer;
-
- bool readCache = layer.source.buffer.cacheHint == Buffer::CachingHint::USE_CACHE;
bindExternalTextureBuffer(layer.source.buffer.textureName, gBuf,
- layer.source.buffer.fence, readCache, /*persistCache=*/true);
+ layer.source.buffer.fence);
usePremultipliedAlpha = layer.source.buffer.usePremultipliedAlpha;
Texture texture(Texture::TEXTURE_EXTERNAL, layer.source.buffer.textureName);
diff --git a/libs/renderengine/gl/GLESRenderEngine.h b/libs/renderengine/gl/GLESRenderEngine.h
index 7b72666..728882a 100644
--- a/libs/renderengine/gl/GLESRenderEngine.h
+++ b/libs/renderengine/gl/GLESRenderEngine.h
@@ -21,16 +21,17 @@
#include <stdint.h>
#include <sys/types.h>
#include <condition_variable>
+#include <deque>
#include <mutex>
#include <queue>
#include <thread>
+#include <unordered_map>
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <GLES2/gl2.h>
#include <renderengine/RenderEngine.h>
#include <renderengine/private/Description.h>
-#include <unordered_map>
#define EGL_NO_CONFIG ((EGLConfig)0)
@@ -47,12 +48,14 @@
class GLESRenderEngine : public impl::RenderEngine {
public:
- static std::unique_ptr<GLESRenderEngine> create(int hwcFormat, uint32_t featureFlags);
+ static std::unique_ptr<GLESRenderEngine> create(int hwcFormat, uint32_t featureFlags,
+ uint32_t imageCacheSize);
static EGLConfig chooseEglConfig(EGLDisplay display, int format, bool logConfig);
GLESRenderEngine(uint32_t featureFlags, // See RenderEngine::FeatureFlag
EGLDisplay display, EGLConfig config, EGLContext ctxt, EGLSurface dummy,
- EGLContext protectedContext, EGLSurface protectedDummy);
+ EGLContext protectedContext, EGLSurface protectedDummy,
+ uint32_t imageCacheSize);
~GLESRenderEngine() override;
std::unique_ptr<Framebuffer> createFramebuffer() override;
@@ -71,8 +74,8 @@
void genTextures(size_t count, uint32_t* names) override;
void deleteTextures(size_t count, uint32_t const* names) override;
void bindExternalTextureImage(uint32_t texName, const Image& image) override;
- status_t bindExternalTextureBuffer(uint32_t texName, sp<GraphicBuffer> buffer, sp<Fence> fence,
- bool readCache);
+ status_t bindExternalTextureBuffer(uint32_t texName, sp<GraphicBuffer> buffer, sp<Fence> fence);
+ void unbindExternalTextureBuffer(uint64_t bufferId);
status_t bindFrameBuffer(Framebuffer* framebuffer) override;
void unbindFrameBuffer(Framebuffer* framebuffer) override;
void checkErrors() const override;
@@ -81,11 +84,14 @@
bool supportsProtectedContent() const override;
bool useProtectedContext(bool useProtectedContext) override;
status_t drawLayers(const DisplaySettings& display, const std::vector<LayerSettings>& layers,
- ANativeWindowBuffer* buffer, base::unique_fd* drawFence) override;
+ ANativeWindowBuffer* buffer, base::unique_fd&& bufferFence,
+ base::unique_fd* drawFence) override;
// internal to RenderEngine
EGLDisplay getEGLDisplay() const { return mEGLDisplay; }
EGLConfig getEGLConfig() const { return mEGLConfig; }
+ // Creates an output image for rendering to
+ EGLImageKHR createFramebufferImageIfNeeded(ANativeWindowBuffer* nativeBuffer, bool isProtected);
protected:
Framebuffer* getFramebufferForDrawing() override;
@@ -137,8 +143,6 @@
// Defines the viewport, and sets the projection matrix to the projection
// defined by the clip.
void setViewportAndProjection(Rect viewport, Rect clip);
- status_t bindExternalTextureBuffer(uint32_t texName, sp<GraphicBuffer> buffer, sp<Fence> fence,
- bool readCache, bool persistCache);
// Evicts stale images from the buffer cache.
void evictImages(const std::vector<LayerSettings>& layers);
// Computes the cropping window for the layer and sets up cropping
@@ -175,6 +179,12 @@
// If set to true, then enables tracing flush() and finish() to systrace.
bool mTraceGpuCompletion = false;
int32_t mFboHeight = 0;
+ // Maximum size of mFramebufferImageCache. If more images would be cached, then (approximately)
+ // the last recently used buffer should be kicked out.
+ uint32_t mFramebufferImageCacheSize = 0;
+
+ // Cache of output images, keyed by corresponding GraphicBuffer ID.
+ std::deque<std::pair<uint64_t, EGLImageKHR>> mFramebufferImageCache;
// Current dataspace of layer being rendered
ui::Dataspace mDataSpace = ui::Dataspace::UNKNOWN;
diff --git a/libs/renderengine/gl/GLFramebuffer.cpp b/libs/renderengine/gl/GLFramebuffer.cpp
index 0e3b405..c45598c 100644
--- a/libs/renderengine/gl/GLFramebuffer.cpp
+++ b/libs/renderengine/gl/GLFramebuffer.cpp
@@ -30,8 +30,8 @@
namespace renderengine {
namespace gl {
-GLFramebuffer::GLFramebuffer(const GLESRenderEngine& engine)
- : mEGLDisplay(engine.getEGLDisplay()), mEGLImage(EGL_NO_IMAGE_KHR) {
+GLFramebuffer::GLFramebuffer(GLESRenderEngine& engine)
+ : mEngine(engine), mEGLDisplay(engine.getEGLDisplay()), mEGLImage(EGL_NO_IMAGE_KHR) {
glGenTextures(1, &mTextureName);
glGenFramebuffers(1, &mFramebufferName);
}
@@ -39,26 +39,18 @@
GLFramebuffer::~GLFramebuffer() {
glDeleteFramebuffers(1, &mFramebufferName);
glDeleteTextures(1, &mTextureName);
- eglDestroyImageKHR(mEGLDisplay, mEGLImage);
}
bool GLFramebuffer::setNativeWindowBuffer(ANativeWindowBuffer* nativeBuffer, bool isProtected) {
ATRACE_CALL();
if (mEGLImage != EGL_NO_IMAGE_KHR) {
- eglDestroyImageKHR(mEGLDisplay, mEGLImage);
mEGLImage = EGL_NO_IMAGE_KHR;
mBufferWidth = 0;
mBufferHeight = 0;
}
if (nativeBuffer) {
- EGLint attributes[] = {
- isProtected ? EGL_PROTECTED_CONTENT_EXT : EGL_NONE,
- isProtected ? EGL_TRUE : EGL_NONE,
- EGL_NONE,
- };
- mEGLImage = eglCreateImageKHR(mEGLDisplay, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID,
- nativeBuffer, attributes);
+ mEGLImage = mEngine.createFramebufferImageIfNeeded(nativeBuffer, isProtected);
if (mEGLImage == EGL_NO_IMAGE_KHR) {
return false;
}
diff --git a/libs/renderengine/gl/GLFramebuffer.h b/libs/renderengine/gl/GLFramebuffer.h
index 5043c59..1289fbf 100644
--- a/libs/renderengine/gl/GLFramebuffer.h
+++ b/libs/renderengine/gl/GLFramebuffer.h
@@ -32,7 +32,7 @@
class GLFramebuffer : public renderengine::Framebuffer {
public:
- explicit GLFramebuffer(const GLESRenderEngine& engine);
+ explicit GLFramebuffer(GLESRenderEngine& engine);
~GLFramebuffer() override;
bool setNativeWindowBuffer(ANativeWindowBuffer* nativeBuffer, bool isProtected) override;
@@ -43,6 +43,7 @@
int32_t getBufferWidth() const { return mBufferWidth; }
private:
+ GLESRenderEngine& mEngine;
EGLDisplay mEGLDisplay;
EGLImageKHR mEGLImage;
uint32_t mTextureName, mFramebufferName;
diff --git a/libs/renderengine/include/renderengine/LayerSettings.h b/libs/renderengine/include/renderengine/LayerSettings.h
index aa45ed8..b8bf801 100644
--- a/libs/renderengine/include/renderengine/LayerSettings.h
+++ b/libs/renderengine/include/renderengine/LayerSettings.h
@@ -32,16 +32,6 @@
// Metadata describing the input buffer to render from.
struct Buffer {
- // Hint for whether to use the Image cache or not.
- // If NO_CACHE is specified, then upload the contents of the GraphicBuffer
- // to the GPU, without checking against any implementation defined cache.
- // If USE_CACHE is specified, then check against an implementation defined
- // cache first. If there is an Image cached for the given GraphicBuffer id,
- // then use that instead of the provided buffer contents. If there is no
- // cached image or the RenderEngine implementation does not support caching,
- // then use the GraphicBuffer contents.
- enum class CachingHint { NO_CACHE, USE_CACHE };
-
// Buffer containing the image that we will render.
// If buffer == nullptr, then the rest of the fields in this struct will be
// ignored.
@@ -50,9 +40,6 @@
// Fence that will fire when the buffer is ready to be bound.
sp<Fence> fence = nullptr;
- // Caching hint to use when uploading buffer contents.
- CachingHint cacheHint = CachingHint::NO_CACHE;
-
// Texture identifier to bind the external texture to.
// TODO(alecmouri): This is GL-specific...make the type backend-agnostic.
uint32_t textureName = 0;
diff --git a/libs/renderengine/include/renderengine/RenderEngine.h b/libs/renderengine/include/renderengine/RenderEngine.h
index b51ed22..ab34274 100644
--- a/libs/renderengine/include/renderengine/RenderEngine.h
+++ b/libs/renderengine/include/renderengine/RenderEngine.h
@@ -65,7 +65,8 @@
USE_HIGH_PRIORITY_CONTEXT = 1 << 1, // Use high priority context
};
- static std::unique_ptr<impl::RenderEngine> create(int hwcFormat, uint32_t featureFlags);
+ static std::unique_ptr<impl::RenderEngine> create(int hwcFormat, uint32_t featureFlags,
+ uint32_t imageCacheSize);
virtual ~RenderEngine() = 0;
@@ -109,7 +110,11 @@
virtual void deleteTextures(size_t count, uint32_t const* names) = 0;
virtual void bindExternalTextureImage(uint32_t texName, const Image& image) = 0;
virtual status_t bindExternalTextureBuffer(uint32_t texName, sp<GraphicBuffer> buffer,
- sp<Fence> fence, bool cleanCache) = 0;
+ sp<Fence> fence) = 0;
+ // Removes internal resources referenced by the bufferId. This method should be
+ // invoked when the caller will no longer hold a reference to a GraphicBuffer
+ // and needs to clean up its resources.
+ virtual void unbindExternalTextureBuffer(uint64_t bufferId) = 0;
// When binding a native buffer, it must be done before setViewportAndProjection
// Returns NO_ERROR when binds successfully, NO_MEMORY when there's no memory for allocation.
virtual status_t bindFrameBuffer(Framebuffer* framebuffer) = 0;
@@ -167,7 +172,9 @@
// drawing any layers.
// @param layers The layers to draw onto the display, in Z-order.
// @param buffer The buffer which will be drawn to. This buffer will be
- // ready once displayFence fires.
+ // ready once drawFence fires.
+ // @param bufferFence Fence signalling that the buffer is ready to be drawn
+ // to.
// @param drawFence A pointer to a fence, which will fire when the buffer
// has been drawn to and is ready to be examined. The fence will be
// initialized by this method. The caller will be responsible for owning the
@@ -176,7 +183,8 @@
// now, this always returns NO_ERROR.
virtual status_t drawLayers(const DisplaySettings& display,
const std::vector<LayerSettings>& layers,
- ANativeWindowBuffer* buffer, base::unique_fd* drawFence) = 0;
+ ANativeWindowBuffer* buffer, base::unique_fd&& bufferFence,
+ base::unique_fd* drawFence) = 0;
protected:
// Gets a framebuffer to render to. This framebuffer may or may not be
diff --git a/libs/renderengine/include/renderengine/mock/RenderEngine.h b/libs/renderengine/include/renderengine/mock/RenderEngine.h
index 800eac3..ddf7420 100644
--- a/libs/renderengine/include/renderengine/mock/RenderEngine.h
+++ b/libs/renderengine/include/renderengine/mock/RenderEngine.h
@@ -53,7 +53,8 @@
MOCK_METHOD2(genTextures, void(size_t, uint32_t*));
MOCK_METHOD2(deleteTextures, void(size_t, uint32_t const*));
MOCK_METHOD2(bindExternalTextureImage, void(uint32_t, const renderengine::Image&));
- MOCK_METHOD4(bindExternalTextureBuffer, status_t(uint32_t, sp<GraphicBuffer>, sp<Fence>, bool));
+ MOCK_METHOD3(bindExternalTextureBuffer, status_t(uint32_t, sp<GraphicBuffer>, sp<Fence>));
+ MOCK_METHOD1(unbindExternalTextureBuffer, void(uint64_t));
MOCK_CONST_METHOD0(checkErrors, void());
MOCK_METHOD4(setViewportAndProjection,
void(size_t, size_t, Rect, ui::Transform::orientation_flags));
@@ -78,9 +79,9 @@
MOCK_CONST_METHOD0(isProtected, bool());
MOCK_CONST_METHOD0(supportsProtectedContent, bool());
MOCK_METHOD1(useProtectedContext, bool(bool));
- MOCK_METHOD4(drawLayers,
+ MOCK_METHOD5(drawLayers,
status_t(const DisplaySettings&, const std::vector<LayerSettings>&,
- ANativeWindowBuffer*, base::unique_fd*));
+ ANativeWindowBuffer*, base::unique_fd&&, base::unique_fd*));
};
} // namespace mock
diff --git a/libs/renderengine/tests/RenderEngineTest.cpp b/libs/renderengine/tests/RenderEngineTest.cpp
index f82beeb..a2bbaff 100644
--- a/libs/renderengine/tests/RenderEngineTest.cpp
+++ b/libs/renderengine/tests/RenderEngineTest.cpp
@@ -105,7 +105,8 @@
std::vector<renderengine::LayerSettings> layers,
sp<GraphicBuffer> buffer) {
base::unique_fd fence;
- status_t status = sRE->drawLayers(settings, layers, buffer->getNativeBuffer(), &fence);
+ status_t status = sRE->drawLayers(settings, layers, buffer->getNativeBuffer(),
+ base::unique_fd(), &fence);
int fd = fence.release();
if (fd >= 0) {
@@ -209,7 +210,7 @@
};
std::unique_ptr<renderengine::RenderEngine> RenderEngineTest::sRE =
- renderengine::RenderEngine::create(static_cast<int32_t>(ui::PixelFormat::RGBA_8888), 0);
+ renderengine::RenderEngine::create(static_cast<int32_t>(ui::PixelFormat::RGBA_8888), 0, 1);
struct ColorSourceVariant {
static void fillColor(renderengine::LayerSettings& layer, half r, half g, half b,
diff --git a/libs/ui/Android.bp b/libs/ui/Android.bp
index 00e227f..4ca1781 100644
--- a/libs/ui/Android.bp
+++ b/libs/ui/Android.bp
@@ -45,6 +45,8 @@
// Don't warn about struct padding
"-Wno-padded",
+
+ "-Wno-switch-enum",
],
sanitize: {
@@ -68,6 +70,7 @@
"GraphicBufferMapper.cpp",
"HdrCapabilities.cpp",
"PixelFormat.cpp",
+ "PublicFormat.cpp",
"Rect.cpp",
"Region.cpp",
"Size.cpp",
@@ -87,8 +90,6 @@
"android.hardware.graphics.mapper@2.0",
"android.hardware.graphics.mapper@2.1",
"android.hardware.graphics.mapper@3.0",
- "android.hardware.configstore@1.2",
- "android.hardware.configstore-utils",
"libbase",
"libcutils",
"libhardware",
@@ -102,7 +103,6 @@
],
export_shared_lib_headers: [
- "android.hardware.configstore@1.2",
"android.hardware.graphics.common@1.2",
],
diff --git a/libs/ui/GraphicBuffer.cpp b/libs/ui/GraphicBuffer.cpp
index f487dfa..79958ec 100644
--- a/libs/ui/GraphicBuffer.cpp
+++ b/libs/ui/GraphicBuffer.cpp
@@ -15,6 +15,7 @@
*/
#define LOG_TAG "GraphicBuffer"
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
#include <ui/GraphicBuffer.h>
@@ -29,6 +30,7 @@
#include <ui/Gralloc2.h>
#include <ui/GraphicBufferAllocator.h>
#include <ui/GraphicBufferMapper.h>
+#include <utils/Trace.h>
namespace android {
@@ -111,6 +113,7 @@
GraphicBuffer::~GraphicBuffer()
{
+ ATRACE_CALL();
if (handle) {
free_handle();
}
diff --git a/libs/ui/PublicFormat.cpp b/libs/ui/PublicFormat.cpp
new file mode 100644
index 0000000..70e3ce7
--- /dev/null
+++ b/libs/ui/PublicFormat.cpp
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <ui/GraphicTypes.h> // ui::Dataspace
+#include <ui/PublicFormat.h>
+
+// ----------------------------------------------------------------------------
+namespace android {
+// ----------------------------------------------------------------------------
+
+using ui::Dataspace;
+
+int mapPublicFormatToHalFormat(PublicFormat f) {
+ switch (f) {
+ case PublicFormat::JPEG:
+ case PublicFormat::DEPTH_POINT_CLOUD:
+ case PublicFormat::DEPTH_JPEG:
+ case PublicFormat::HEIC:
+ return HAL_PIXEL_FORMAT_BLOB;
+ case PublicFormat::DEPTH16:
+ return HAL_PIXEL_FORMAT_Y16;
+ case PublicFormat::RAW_SENSOR:
+ case PublicFormat::RAW_DEPTH:
+ return HAL_PIXEL_FORMAT_RAW16;
+ default:
+ // Most formats map 1:1
+ return static_cast<int>(f);
+ }
+}
+
+android_dataspace mapPublicFormatToHalDataspace(PublicFormat f) {
+ Dataspace dataspace;
+ switch (f) {
+ case PublicFormat::JPEG:
+ dataspace = Dataspace::V0_JFIF;
+ break;
+ case PublicFormat::DEPTH_POINT_CLOUD:
+ case PublicFormat::DEPTH16:
+ case PublicFormat::RAW_DEPTH:
+ dataspace = Dataspace::DEPTH;
+ break;
+ case PublicFormat::RAW_SENSOR:
+ case PublicFormat::RAW_PRIVATE:
+ case PublicFormat::RAW10:
+ case PublicFormat::RAW12:
+ dataspace = Dataspace::ARBITRARY;
+ break;
+ case PublicFormat::YUV_420_888:
+ case PublicFormat::NV21:
+ case PublicFormat::YV12:
+ dataspace = Dataspace::V0_JFIF;
+ break;
+ case PublicFormat::DEPTH_JPEG:
+ dataspace = Dataspace::DYNAMIC_DEPTH;
+ break;
+ case PublicFormat::HEIC:
+ dataspace = Dataspace::HEIF;
+ break;
+ default:
+ // Most formats map to UNKNOWN
+ dataspace = Dataspace::UNKNOWN;
+ break;
+ }
+ return static_cast<android_dataspace>(dataspace);
+}
+
+PublicFormat mapHalFormatDataspaceToPublicFormat(int format, android_dataspace dataSpace) {
+ Dataspace ds = static_cast<Dataspace>(dataSpace);
+ switch (format) {
+ case HAL_PIXEL_FORMAT_RGBA_8888:
+ case HAL_PIXEL_FORMAT_RGBX_8888:
+ case HAL_PIXEL_FORMAT_RGBA_FP16:
+ case HAL_PIXEL_FORMAT_RGBA_1010102:
+ case HAL_PIXEL_FORMAT_RGB_888:
+ case HAL_PIXEL_FORMAT_RGB_565:
+ case HAL_PIXEL_FORMAT_Y8:
+ case HAL_PIXEL_FORMAT_RAW10:
+ case HAL_PIXEL_FORMAT_RAW12:
+ case HAL_PIXEL_FORMAT_YCbCr_420_888:
+ case HAL_PIXEL_FORMAT_YV12:
+ // Enums overlap in both name and value
+ return static_cast<PublicFormat>(format);
+ case HAL_PIXEL_FORMAT_RAW16:
+ switch (ds) {
+ case Dataspace::DEPTH:
+ return PublicFormat::RAW_DEPTH;
+ default:
+ return PublicFormat::RAW_SENSOR;
+ }
+ case HAL_PIXEL_FORMAT_RAW_OPAQUE:
+ // Name differs, though value is the same
+ return PublicFormat::RAW_PRIVATE;
+ case HAL_PIXEL_FORMAT_YCbCr_422_SP:
+ // Name differs, though the value is the same
+ return PublicFormat::NV16;
+ case HAL_PIXEL_FORMAT_YCrCb_420_SP:
+ // Name differs, though the value is the same
+ return PublicFormat::NV21;
+ case HAL_PIXEL_FORMAT_YCbCr_422_I:
+ // Name differs, though the value is the same
+ return PublicFormat::YUY2;
+ case HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED:
+ // Name differs, though the value is the same
+ return PublicFormat::PRIVATE;
+ case HAL_PIXEL_FORMAT_Y16:
+ // Dataspace-dependent
+ switch (ds) {
+ case Dataspace::DEPTH:
+ return PublicFormat::DEPTH16;
+ default:
+ // Assume non-depth Y16 is just Y16.
+ return PublicFormat::Y16;
+ }
+ case HAL_PIXEL_FORMAT_BLOB:
+ // Dataspace-dependent
+ switch (ds) {
+ case Dataspace::DEPTH:
+ return PublicFormat::DEPTH_POINT_CLOUD;
+ case Dataspace::V0_JFIF:
+ return PublicFormat::JPEG;
+ case Dataspace::HEIF:
+ return PublicFormat::HEIC;
+ default:
+ if (dataSpace == static_cast<android_dataspace>(HAL_DATASPACE_DYNAMIC_DEPTH)) {
+ return PublicFormat::DEPTH_JPEG;
+ } else {
+ // Assume otherwise-marked blobs are also JPEG
+ return PublicFormat::JPEG;
+ }
+ }
+ case HAL_PIXEL_FORMAT_BGRA_8888:
+ // Not defined in public API
+ return PublicFormat::UNKNOWN;
+
+ default:
+ return PublicFormat::UNKNOWN;
+ }
+}
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+// ----------------------------------------------------------------------------
diff --git a/libs/ui/include/ui/ConfigStoreTypes.h b/libs/ui/include/ui/ConfigStoreTypes.h
index 37a2bd5..4445ae9 100644
--- a/libs/ui/include/ui/ConfigStoreTypes.h
+++ b/libs/ui/include/ui/ConfigStoreTypes.h
@@ -16,14 +16,22 @@
#pragma once
-#include <android/hardware/configstore/1.2/types.h>
-
// android::ui::* in this header file will alias different types as
// the HIDL interface is updated.
namespace android {
namespace ui {
-using android::hardware::configstore::V1_2::DisplayPrimaries;
+struct CieXyz {
+ float X;
+ float Y;
+ float Z;
+};
+struct DisplayPrimaries {
+ CieXyz red;
+ CieXyz green;
+ CieXyz blue;
+ CieXyz white;
+};
} // namespace ui
} // namespace android
diff --git a/libs/ui/include/ui/PublicFormat.h b/libs/ui/include/ui/PublicFormat.h
new file mode 100644
index 0000000..1152cc5
--- /dev/null
+++ b/libs/ui/include/ui/PublicFormat.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef UI_PUBLICFORMAT_H
+#define UI_PUBLICFORMAT_H
+
+#include <system/graphics.h>
+
+namespace android {
+
+/**
+ * Enum mirroring the public API definitions for image and pixel formats.
+ * Some of these are hidden in the public API
+ *
+ * Keep up to date with android.graphics.ImageFormat and
+ * android.graphics.PixelFormat
+ *
+ * TODO: PublicFormat is going to be deprecated(b/126594675)
+ */
+enum class PublicFormat {
+ UNKNOWN = 0x0,
+ RGBA_8888 = 0x1,
+ RGBX_8888 = 0x2,
+ RGB_888 = 0x3,
+ RGB_565 = 0x4,
+ NV16 = 0x10,
+ NV21 = 0x11,
+ YUY2 = 0x14,
+ RGBA_FP16 = 0x16,
+ RAW_SENSOR = 0x20,
+ PRIVATE = 0x22,
+ YUV_420_888 = 0x23,
+ RAW_PRIVATE = 0x24,
+ RAW10 = 0x25,
+ RAW12 = 0x26,
+ RGBA_1010102 = 0x2b,
+ JPEG = 0x100,
+ DEPTH_POINT_CLOUD = 0x101,
+ RAW_DEPTH = 0x1002, // @hide
+ YV12 = 0x32315659,
+ Y8 = 0x20203859,
+ Y16 = 0x20363159, // @hide
+ DEPTH16 = 0x44363159,
+ DEPTH_JPEG = 0x69656963,
+ HEIC = 0x48454946,
+};
+
+/* Convert from android.graphics.ImageFormat/PixelFormat enums to graphics.h HAL
+ * format */
+extern int mapPublicFormatToHalFormat(PublicFormat f);
+
+/* Convert from android.graphics.ImageFormat/PixelFormat enums to graphics.h HAL
+ * dataspace */
+extern android_dataspace mapPublicFormatToHalDataspace(PublicFormat f);
+
+/* Convert from HAL format, dataspace pair to
+ * android.graphics.ImageFormat/PixelFormat.
+ * For unknown/unspecified pairs, returns PublicFormat::UNKNOWN */
+extern PublicFormat mapHalFormatDataspaceToPublicFormat(int format, android_dataspace dataSpace);
+
+}; // namespace android
+
+#endif // UI_PUBLICFORMAT_H
diff --git a/libs/ui/include_vndk/ui/ConfigStoreTypes.h b/libs/ui/include_vndk/ui/ConfigStoreTypes.h
index 37a2bd5..4445ae9 100644
--- a/libs/ui/include_vndk/ui/ConfigStoreTypes.h
+++ b/libs/ui/include_vndk/ui/ConfigStoreTypes.h
@@ -16,14 +16,22 @@
#pragma once
-#include <android/hardware/configstore/1.2/types.h>
-
// android::ui::* in this header file will alias different types as
// the HIDL interface is updated.
namespace android {
namespace ui {
-using android::hardware::configstore::V1_2::DisplayPrimaries;
+struct CieXyz {
+ float X;
+ float Y;
+ float Z;
+};
+struct DisplayPrimaries {
+ CieXyz red;
+ CieXyz green;
+ CieXyz blue;
+ CieXyz white;
+};
} // namespace ui
} // namespace android
diff --git a/opengl/tools/glgen/gen b/opengl/tools/glgen/gen
index 9fa58e2..da9bb49 100755
--- a/opengl/tools/glgen/gen
+++ b/opengl/tools/glgen/gen
@@ -90,6 +90,10 @@
rm src/*.class
+# Add UnsupportedAppUsage.java to known sources.
+mkdir -p out/android/annotation
+cp ../../../../base/core/java/android/annotation/UnsupportedAppUsage.java out/android/annotation
+
pushd out > /dev/null
mkdir classes
javac -d classes android/opengl/EGL14.java \
@@ -109,7 +113,8 @@
android/opengl/GLES30.java \
android/opengl/GLES31.java \
android/opengl/GLES31Ext.java \
- android/opengl/GLES32.java
+ android/opengl/GLES32.java \
+ android/annotation/UnsupportedAppUsage.java
popd > /dev/null
JAVA_RESULT=$?
if [ $JAVA_RESULT -ne 0 ]; then
@@ -142,7 +147,7 @@
echo
SAID_PLEASE=1
fi
- echo " cp $2/$3 $1"
+ echo " cp $2/$3 $1/$3"
echo " (cd $1; git add $3)"
KEEP_GENERATED=1
fi
diff --git a/opengl/tools/glgen/src/JniCodeEmitter.java b/opengl/tools/glgen/src/JniCodeEmitter.java
index 6697189..9c80212 100644
--- a/opengl/tools/glgen/src/JniCodeEmitter.java
+++ b/opengl/tools/glgen/src/JniCodeEmitter.java
@@ -775,6 +775,19 @@
}
}
+ String getJniDefaultReturn(JType jType) {
+ if (jType.isPrimitive()) {
+ String baseType = jType.getBaseType();
+ if (baseType.equals("boolean")) {
+ return "JNI_FALSE";
+ } else {
+ return "(" + getJniType(jType) + ")0";
+ }
+ } else {
+ return "nullptr";
+ }
+ }
+
String getJniMangledName(String name) {
name = name.replaceAll("_", "_1");
name = name.replaceAll(";", "_2");
@@ -943,15 +956,15 @@
"jniThrowException(_env, \"java/lang/UnsupportedOperationException\",");
out.println(indent +
" \"" + cfunc.getName() + "\");");
- if (!isVoid) {
- String retval = getErrorReturnValue(cfunc);
+ if (isVoid) {
+ out.println(indent + "return;");
+ } else {
if (cfunc.getType().isEGLHandle()) {
String baseType = cfunc.getType().getBaseType().toLowerCase();
- out.println(indent +
- "return toEGLHandle(_env, " + baseType + "Class, " +
- baseType + "Constructor, " + retval + ");");
+ out.println(indent + indent + "return nullptr;");
} else {
- out.println(indent + "return " + retval + ";");
+ out.println(indent + indent + "return " +
+ getJniDefaultReturn(jfunc.getType()) + ";");
}
}
out.println("}");
@@ -1595,8 +1608,17 @@
out.println(indent + "if (_exception) {");
out.println(indent + indent +
"jniThrowException(_env, _exceptionType, _exceptionMessage);");
- out.println(indent + "}");
+ if (!isVoid) {
+ if (cfunc.getType().isEGLHandle()) {
+ String baseType = cfunc.getType().getBaseType().toLowerCase();
+ out.println(indent + indent + "return nullptr;");
+ } else {
+ out.println(indent + indent + "return " +
+ getJniDefaultReturn(jfunc.getType()) + ";");
+ }
+ }
+ out.println(indent + "}");
}
diff --git a/opengl/tools/glgen/stubs/egl/EGL14Header.java-if b/opengl/tools/glgen/stubs/egl/EGL14Header.java-if
index f3bf220..12728f5 100644
--- a/opengl/tools/glgen/stubs/egl/EGL14Header.java-if
+++ b/opengl/tools/glgen/stubs/egl/EGL14Header.java-if
@@ -18,6 +18,7 @@
package android.opengl;
+import android.annotation.UnsupportedAppUsage;
import android.graphics.SurfaceTexture;
import android.view.Surface;
import android.view.SurfaceView;
diff --git a/opengl/tools/glgen/stubs/egl/EGL14cHeader.cpp b/opengl/tools/glgen/stubs/egl/EGL14cHeader.cpp
index f90e3ec..93203fd 100644
--- a/opengl/tools/glgen/stubs/egl/EGL14cHeader.cpp
+++ b/opengl/tools/glgen/stubs/egl/EGL14cHeader.cpp
@@ -35,8 +35,6 @@
#include <ui/ANativeObjectBase.h>
-static int initialized = 0;
-
static jclass egldisplayClass;
static jclass eglcontextClass;
static jclass eglsurfaceClass;
@@ -107,6 +105,7 @@
if (obj == NULL){
jniThrowException(_env, "java/lang/IllegalArgumentException",
"Object is set to null.");
+ return nullptr;
}
jlong handle = _env->CallLongMethod(obj, mid);
diff --git a/opengl/tools/glgen/stubs/egl/EGL15cHeader.cpp b/opengl/tools/glgen/stubs/egl/EGL15cHeader.cpp
index 70b46f7..1c53c9e 100644
--- a/opengl/tools/glgen/stubs/egl/EGL15cHeader.cpp
+++ b/opengl/tools/glgen/stubs/egl/EGL15cHeader.cpp
@@ -14,21 +14,21 @@
** limitations under the License.
*/
+// This source file is automatically generated
+
#pragma GCC diagnostic ignored "-Wunused-variable"
#pragma GCC diagnostic ignored "-Wunused-function"
-#include <android_runtime/AndroidRuntime.h>
-#include <nativehelper/JNIHelp.h>
-#include <utils/misc.h>
#include "jni.h"
+#include <nativehelper/JNIHelp.h>
+#include <android_runtime/AndroidRuntime.h>
+#include <utils/misc.h>
-#include <EGL/egl.h>
#include <assert.h>
+#include <EGL/egl.h>
#include <ui/ANativeObjectBase.h>
-static int initialized = 0;
-
// classes from EGL 1.4
static jclass egldisplayClass;
static jclass eglsurfaceClass;
@@ -74,16 +74,18 @@
/* Cache method IDs each time the class is loaded. */
-static void nativeClassInit(JNIEnv *_env, jclass glImplClass) {
+static void
+nativeClassInit(JNIEnv *_env, jclass glImplClass)
+{
// EGL 1.4 Init
jclass eglconfigClassLocal = _env->FindClass("android/opengl/EGLConfig");
- eglconfigClass = (jclass)_env->NewGlobalRef(eglconfigClassLocal);
+ eglconfigClass = (jclass) _env->NewGlobalRef(eglconfigClassLocal);
jclass eglcontextClassLocal = _env->FindClass("android/opengl/EGLContext");
- eglcontextClass = (jclass)_env->NewGlobalRef(eglcontextClassLocal);
+ eglcontextClass = (jclass) _env->NewGlobalRef(eglcontextClassLocal);
jclass egldisplayClassLocal = _env->FindClass("android/opengl/EGLDisplay");
- egldisplayClass = (jclass)_env->NewGlobalRef(egldisplayClassLocal);
+ egldisplayClass = (jclass) _env->NewGlobalRef(egldisplayClassLocal);
jclass eglsurfaceClassLocal = _env->FindClass("android/opengl/EGLSurface");
- eglsurfaceClass = (jclass)_env->NewGlobalRef(eglsurfaceClassLocal);
+ eglsurfaceClass = (jclass) _env->NewGlobalRef(eglsurfaceClassLocal);
eglconfigGetHandleID = _env->GetMethodID(eglconfigClass, "getNativeHandle", "()J");
eglcontextGetHandleID = _env->GetMethodID(eglcontextClass, "getNativeHandle", "()J");
@@ -95,51 +97,46 @@
egldisplayConstructor = _env->GetMethodID(egldisplayClass, "<init>", "(J)V");
eglsurfaceConstructor = _env->GetMethodID(eglsurfaceClass, "<init>", "(J)V");
- jobject localeglNoContextObject = _env->NewObject(eglcontextClass, eglcontextConstructor,
- reinterpret_cast<jlong>(EGL_NO_CONTEXT));
+ jobject localeglNoContextObject = _env->NewObject(eglcontextClass, eglcontextConstructor, reinterpret_cast<jlong>(EGL_NO_CONTEXT));
eglNoContextObject = _env->NewGlobalRef(localeglNoContextObject);
- jobject localeglNoDisplayObject = _env->NewObject(egldisplayClass, egldisplayConstructor,
- reinterpret_cast<jlong>(EGL_NO_DISPLAY));
+ jobject localeglNoDisplayObject = _env->NewObject(egldisplayClass, egldisplayConstructor, reinterpret_cast<jlong>(EGL_NO_DISPLAY));
eglNoDisplayObject = _env->NewGlobalRef(localeglNoDisplayObject);
- jobject localeglNoSurfaceObject = _env->NewObject(eglsurfaceClass, eglsurfaceConstructor,
- reinterpret_cast<jlong>(EGL_NO_SURFACE));
+ jobject localeglNoSurfaceObject = _env->NewObject(eglsurfaceClass, eglsurfaceConstructor, reinterpret_cast<jlong>(EGL_NO_SURFACE));
eglNoSurfaceObject = _env->NewGlobalRef(localeglNoSurfaceObject);
jclass eglClass = _env->FindClass("android/opengl/EGL15");
- jfieldID noContextFieldID =
- _env->GetStaticFieldID(eglClass, "EGL_NO_CONTEXT", "Landroid/opengl/EGLContext;");
+ jfieldID noContextFieldID = _env->GetStaticFieldID(eglClass, "EGL_NO_CONTEXT", "Landroid/opengl/EGLContext;");
_env->SetStaticObjectField(eglClass, noContextFieldID, eglNoContextObject);
- jfieldID noDisplayFieldID =
- _env->GetStaticFieldID(eglClass, "EGL_NO_DISPLAY", "Landroid/opengl/EGLDisplay;");
+ jfieldID noDisplayFieldID = _env->GetStaticFieldID(eglClass, "EGL_NO_DISPLAY", "Landroid/opengl/EGLDisplay;");
_env->SetStaticObjectField(eglClass, noDisplayFieldID, eglNoDisplayObject);
- jfieldID noSurfaceFieldID =
- _env->GetStaticFieldID(eglClass, "EGL_NO_SURFACE", "Landroid/opengl/EGLSurface;");
+ jfieldID noSurfaceFieldID = _env->GetStaticFieldID(eglClass, "EGL_NO_SURFACE", "Landroid/opengl/EGLSurface;");
_env->SetStaticObjectField(eglClass, noSurfaceFieldID, eglNoSurfaceObject);
// EGL 1.5 init
jclass nioAccessClassLocal = _env->FindClass("java/nio/NIOAccess");
- nioAccessClass = (jclass)_env->NewGlobalRef(nioAccessClassLocal);
+ nioAccessClass = (jclass) _env->NewGlobalRef(nioAccessClassLocal);
jclass bufferClassLocal = _env->FindClass("java/nio/Buffer");
- bufferClass = (jclass)_env->NewGlobalRef(bufferClassLocal);
+ bufferClass = (jclass) _env->NewGlobalRef(bufferClassLocal);
- getBasePointerID =
- _env->GetStaticMethodID(nioAccessClass, "getBasePointer", "(Ljava/nio/Buffer;)J");
- getBaseArrayID = _env->GetStaticMethodID(nioAccessClass, "getBaseArray",
- "(Ljava/nio/Buffer;)Ljava/lang/Object;");
- getBaseArrayOffsetID =
- _env->GetStaticMethodID(nioAccessClass, "getBaseArrayOffset", "(Ljava/nio/Buffer;)I");
+ getBasePointerID = _env->GetStaticMethodID(nioAccessClass,
+ "getBasePointer", "(Ljava/nio/Buffer;)J");
+ getBaseArrayID = _env->GetStaticMethodID(nioAccessClass,
+ "getBaseArray", "(Ljava/nio/Buffer;)Ljava/lang/Object;");
+ getBaseArrayOffsetID = _env->GetStaticMethodID(nioAccessClass,
+ "getBaseArrayOffset", "(Ljava/nio/Buffer;)I");
positionID = _env->GetFieldID(bufferClass, "position", "I");
limitID = _env->GetFieldID(bufferClass, "limit", "I");
- elementSizeShiftID = _env->GetFieldID(bufferClass, "_elementSizeShift", "I");
+ elementSizeShiftID =
+ _env->GetFieldID(bufferClass, "_elementSizeShift", "I");
jclass eglimageClassLocal = _env->FindClass("android/opengl/EGLImage");
- eglimageClass = (jclass)_env->NewGlobalRef(eglimageClassLocal);
+ eglimageClass = (jclass) _env->NewGlobalRef(eglimageClassLocal);
jclass eglsyncClassLocal = _env->FindClass("android/opengl/EGLSync");
- eglsyncClass = (jclass)_env->NewGlobalRef(eglsyncClassLocal);
+ eglsyncClass = (jclass) _env->NewGlobalRef(eglsyncClassLocal);
eglimageGetHandleID = _env->GetMethodID(eglimageClass, "getNativeHandle", "()J");
eglsyncGetHandleID = _env->GetMethodID(eglsyncClass, "getNativeHandle", "()J");
@@ -147,17 +144,16 @@
eglimageConstructor = _env->GetMethodID(eglimageClass, "<init>", "(J)V");
eglsyncConstructor = _env->GetMethodID(eglsyncClass, "<init>", "(J)V");
- jfieldID noImageFieldID =
- _env->GetStaticFieldID(eglClass, "EGL_NO_IMAGE", "Landroid/opengl/EGLImage;");
+ jfieldID noImageFieldID = _env->GetStaticFieldID(eglClass, "EGL_NO_IMAGE", "Landroid/opengl/EGLImage;");
_env->SetStaticObjectField(eglClass, noImageFieldID, eglNoImageObject);
- jfieldID noSyncFieldID =
- _env->GetStaticFieldID(eglClass, "EGL_NO_SYNC", "Landroid/opengl/EGLSync;");
+ jfieldID noSyncFieldID = _env->GetStaticFieldID(eglClass, "EGL_NO_SYNC", "Landroid/opengl/EGLSync;");
_env->SetStaticObjectField(eglClass, noSyncFieldID, eglNoSyncObject);
}
-static void *getPointer(JNIEnv *_env, jobject buffer, jarray *array, jint *remaining,
- jint *offset) {
+static void *
+getPointer(JNIEnv *_env, jobject buffer, jarray *array, jint *remaining, jint *offset)
+{
jint position;
jint limit;
jint elementSizeShift;
@@ -167,34 +163,42 @@
limit = _env->GetIntField(buffer, limitID);
elementSizeShift = _env->GetIntField(buffer, elementSizeShiftID);
*remaining = (limit - position) << elementSizeShift;
- pointer = _env->CallStaticLongMethod(nioAccessClass, getBasePointerID, buffer);
+ pointer = _env->CallStaticLongMethod(nioAccessClass,
+ getBasePointerID, buffer);
if (pointer != 0L) {
*array = NULL;
- return reinterpret_cast<void *>(pointer);
+ return reinterpret_cast<void*>(pointer);
}
- eglimageGetHandleID = _env->GetMethodID(eglimageClass, "getNativeHandle", "()J");
- eglsyncGetHandleID = _env->GetMethodID(eglsyncClass, "getNativeHandle", "()J");
- *array = (jarray)_env->CallStaticObjectMethod(nioAccessClass, getBaseArrayID, buffer);
- *offset = _env->CallStaticIntMethod(nioAccessClass, getBaseArrayOffsetID, buffer);
+ *array = (jarray) _env->CallStaticObjectMethod(nioAccessClass,
+ getBaseArrayID, buffer);
+ *offset = _env->CallStaticIntMethod(nioAccessClass,
+ getBaseArrayOffsetID, buffer);
return NULL;
}
-static void releasePointer(JNIEnv *_env, jarray array, void *data, jboolean commit) {
- _env->ReleasePrimitiveArrayCritical(array, data, commit ? 0 : JNI_ABORT);
+static void
+releasePointer(JNIEnv *_env, jarray array, void *data, jboolean commit)
+{
+ _env->ReleasePrimitiveArrayCritical(array, data,
+ commit ? 0 : JNI_ABORT);
}
-static void *fromEGLHandle(JNIEnv *_env, jmethodID mid, jobject obj) {
+static void *
+fromEGLHandle(JNIEnv *_env, jmethodID mid, jobject obj) {
if (obj == NULL) {
- jniThrowException(_env, "java/lang/IllegalArgumentException", "Object is set to null.");
+ jniThrowException(_env, "java/lang/IllegalArgumentException",
+ "Object is set to null.");
+ return nullptr;
}
jlong handle = _env->CallLongMethod(obj, mid);
- return reinterpret_cast<void *>(handle);
+ return reinterpret_cast<void*>(handle);
}
-static jobject toEGLHandle(JNIEnv *_env, jclass cls, jmethodID con, void *handle) {
+static jobject
+toEGLHandle(JNIEnv *_env, jclass cls, jmethodID con, void *handle) {
if (cls == eglimageClass && (EGLImage)handle == EGL_NO_IMAGE) {
return eglNoImageObject;
}
diff --git a/opengl/tools/glgen/stubs/egl/EGLExtcHeader.cpp b/opengl/tools/glgen/stubs/egl/EGLExtcHeader.cpp
index 12b96f4..b3b0690 100644
--- a/opengl/tools/glgen/stubs/egl/EGLExtcHeader.cpp
+++ b/opengl/tools/glgen/stubs/egl/EGLExtcHeader.cpp
@@ -36,8 +36,6 @@
#include <ui/ANativeObjectBase.h>
-static int initialized = 0;
-
static jclass egldisplayClass;
static jclass eglcontextClass;
static jclass eglsurfaceClass;
@@ -104,6 +102,7 @@
if (obj == NULL){
jniThrowException(_env, "java/lang/IllegalArgumentException",
"Object is set to null.");
+ return nullptr;
}
return reinterpret_cast<void*>(_env->CallLongMethod(obj, mid));
diff --git a/opengl/tools/glgen/stubs/egl/eglCreatePbufferFromClientBuffer.cpp b/opengl/tools/glgen/stubs/egl/eglCreatePbufferFromClientBuffer.cpp
index 497d284..f229860 100755
--- a/opengl/tools/glgen/stubs/egl/eglCreatePbufferFromClientBuffer.cpp
+++ b/opengl/tools/glgen/stubs/egl/eglCreatePbufferFromClientBuffer.cpp
@@ -54,6 +54,7 @@
}
if (_exception) {
jniThrowException(_env, _exceptionType, _exceptionMessage);
+ return nullptr;
}
return toEGLHandle(_env, eglsurfaceClass, eglsurfaceConstructor, _returnValue);
}
diff --git a/opengl/tools/glgen/stubs/egl/eglCreatePixmapSurface.cpp b/opengl/tools/glgen/stubs/egl/eglCreatePixmapSurface.cpp
index 3eacf3c..2e146a8 100644
--- a/opengl/tools/glgen/stubs/egl/eglCreatePixmapSurface.cpp
+++ b/opengl/tools/glgen/stubs/egl/eglCreatePixmapSurface.cpp
@@ -4,6 +4,6 @@
(JNIEnv *_env, jobject _this, jobject dpy, jobject config, jint pixmap, jintArray attrib_list_ref, jint offset) {
jniThrowException(_env, "java/lang/UnsupportedOperationException",
"eglCreatePixmapSurface");
- return toEGLHandle(_env, eglsurfaceClass, eglsurfaceConstructor, (EGLSurface) 0);
+ return nullptr;
}
diff --git a/opengl/tools/glgen/stubs/egl/eglCreateWindowSurface.cpp b/opengl/tools/glgen/stubs/egl/eglCreateWindowSurface.cpp
index 355c4b0..7c255ed 100644
--- a/opengl/tools/glgen/stubs/egl/eglCreateWindowSurface.cpp
+++ b/opengl/tools/glgen/stubs/egl/eglCreateWindowSurface.cpp
@@ -67,6 +67,7 @@
}
if (_exception) {
jniThrowException(_env, _exceptionType, _exceptionMessage);
+ return nullptr;
}
return toEGLHandle(_env, eglsurfaceClass, eglsurfaceConstructor, _returnValue);
}
@@ -149,6 +150,7 @@
}
if (_exception) {
jniThrowException(_env, _exceptionType, _exceptionMessage);
+ return nullptr;
}
return toEGLHandle(_env, eglsurfaceClass, eglsurfaceConstructor, _returnValue);
}
diff --git a/opengl/tools/glgen/stubs/egl/eglGetDisplay.java b/opengl/tools/glgen/stubs/egl/eglGetDisplay.java
index 7532abf..85f743d 100755
--- a/opengl/tools/glgen/stubs/egl/eglGetDisplay.java
+++ b/opengl/tools/glgen/stubs/egl/eglGetDisplay.java
@@ -7,6 +7,7 @@
/**
* {@hide}
*/
+ @UnsupportedAppUsage
public static native EGLDisplay eglGetDisplay(
long display_id
);
diff --git a/opengl/tools/glgen/stubs/egl/eglGetPlatformDisplay.cpp b/opengl/tools/glgen/stubs/egl/eglGetPlatformDisplay.cpp
index fd44498..3a6176f 100644
--- a/opengl/tools/glgen/stubs/egl/eglGetPlatformDisplay.cpp
+++ b/opengl/tools/glgen/stubs/egl/eglGetPlatformDisplay.cpp
@@ -40,6 +40,7 @@
}
if (_exception) {
jniThrowException(_env, _exceptionType, _exceptionMessage);
+ return nullptr;
}
return toEGLHandle(_env, egldisplayClass, egldisplayConstructor, _returnValue);
}
diff --git a/opengl/tools/glgen/stubs/gles11/GLES20Header.java-if b/opengl/tools/glgen/stubs/gles11/GLES20Header.java-if
index 9ce6728..c2711aa 100644
--- a/opengl/tools/glgen/stubs/gles11/GLES20Header.java-if
+++ b/opengl/tools/glgen/stubs/gles11/GLES20Header.java-if
@@ -19,6 +19,8 @@
package android.opengl;
+import android.annotation.UnsupportedAppUsage;
+
/** OpenGL ES 2.0
*/
public class GLES20 {
diff --git a/opengl/tools/glgen/stubs/gles11/common.cpp b/opengl/tools/glgen/stubs/gles11/common.cpp
index 2163d76..51e62ed 100644
--- a/opengl/tools/glgen/stubs/gles11/common.cpp
+++ b/opengl/tools/glgen/stubs/gles11/common.cpp
@@ -4,8 +4,6 @@
#include <utils/misc.h>
#include <assert.h>
-static int initialized = 0;
-
static jclass nioAccessClass;
static jclass bufferClass;
static jmethodID getBasePointerID;
diff --git a/opengl/tools/glgen/stubs/gles11/glGetActiveAttrib.java b/opengl/tools/glgen/stubs/gles11/glGetActiveAttrib.java
index d66200f..b297b7a 100644
--- a/opengl/tools/glgen/stubs/gles11/glGetActiveAttrib.java
+++ b/opengl/tools/glgen/stubs/gles11/glGetActiveAttrib.java
@@ -17,6 +17,7 @@
// C function void glGetActiveAttrib ( GLuint program, GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, char *name )
/** @hide Method is broken, but used to be public (b/6006380) */
+ @UnsupportedAppUsage
public static native void glGetActiveAttrib(
int program,
int index,
diff --git a/opengl/tools/glgen/stubs/gles11/glGetActiveUniform.java b/opengl/tools/glgen/stubs/gles11/glGetActiveUniform.java
index 8c8d5a2..f211440 100644
--- a/opengl/tools/glgen/stubs/gles11/glGetActiveUniform.java
+++ b/opengl/tools/glgen/stubs/gles11/glGetActiveUniform.java
@@ -17,6 +17,7 @@
// C function void glGetActiveUniform ( GLuint program, GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, char *name )
/** @hide Method is broken, but used to be public (b/6006380) */
+ @UnsupportedAppUsage
public static native void glGetActiveUniform(
int program,
int index,
diff --git a/opengl/tools/glgen/stubs/jsr239/GLCHeader.cpp b/opengl/tools/glgen/stubs/jsr239/GLCHeader.cpp
index 29296ff..c808fe9 100644
--- a/opengl/tools/glgen/stubs/jsr239/GLCHeader.cpp
+++ b/opengl/tools/glgen/stubs/jsr239/GLCHeader.cpp
@@ -64,8 +64,6 @@
GLsizei stride, const GLvoid *pointer, GLsizei count);
}
-static int initialized = 0;
-
static jclass nioAccessClass;
static jclass bufferClass;
static jclass G11ImplClass;
diff --git a/services/gpuservice/Android.bp b/services/gpuservice/Android.bp
index e21d8e7..dbb6ba6 100644
--- a/services/gpuservice/Android.bp
+++ b/services/gpuservice/Android.bp
@@ -2,6 +2,7 @@
name: "gpuservice_sources",
srcs: [
"GpuService.cpp",
+ "gpustats/GpuStats.cpp"
],
}
@@ -29,6 +30,7 @@
"frameworks/native/vulkan/include",
],
shared_libs: [
+ "libbase",
"libbinder",
"libcutils",
"libgraphicsenv",
@@ -37,6 +39,7 @@
"libvulkan",
],
static_libs: [
+ "libserviceutils",
"libvkjson",
],
}
diff --git a/services/gpuservice/GpuService.cpp b/services/gpuservice/GpuService.cpp
index 81b70c0..5e5cf35 100644
--- a/services/gpuservice/GpuService.cpp
+++ b/services/gpuservice/GpuService.cpp
@@ -18,45 +18,53 @@
#include "GpuService.h"
+#include <android-base/stringprintf.h>
+#include <binder/IPCThreadState.h>
#include <binder/IResultReceiver.h>
#include <binder/Parcel.h>
+#include <binder/PermissionCache.h>
+#include <cutils/properties.h>
+#include <private/android_filesystem_config.h>
#include <utils/String8.h>
#include <utils/Trace.h>
#include <vkjson.h>
+#include "gpustats/GpuStats.h"
+
namespace android {
+using base::StringAppendF;
namespace {
- status_t cmd_help(int out);
- status_t cmd_vkjson(int out, int err);
-}
+status_t cmdHelp(int out);
+status_t cmdVkjson(int out, int err);
+void dumpGameDriverInfo(std::string* result);
+} // namespace
+
+const String16 sDump("android.permission.DUMP");
const char* const GpuService::SERVICE_NAME = "gpu";
-GpuService::GpuService() = default;
+GpuService::GpuService() : mGpuStats(std::make_unique<GpuStats>()){};
void GpuService::setGpuStats(const std::string& driverPackageName,
const std::string& driverVersionName, uint64_t driverVersionCode,
- const std::string& driverBuildDate, const std::string& appPackageName,
+ int64_t driverBuildTime, const std::string& appPackageName,
GraphicsEnv::Driver driver, bool isDriverLoaded,
int64_t driverLoadingTime) {
ATRACE_CALL();
- std::lock_guard<std::mutex> lock(mStateLock);
- ALOGV("Received:\n"
- "\tdriverPackageName[%s]\n"
- "\tdriverVersionName[%s]\n"
- "\tdriverVersionCode[%llu]\n"
- "\tdriverBuildDate[%s]\n"
- "\tappPackageName[%s]\n"
- "\tdriver[%d]\n"
- "\tisDriverLoaded[%d]\n"
- "\tdriverLoadingTime[%lld]",
- driverPackageName.c_str(), driverVersionName.c_str(),
- (unsigned long long)driverVersionCode, driverBuildDate.c_str(), appPackageName.c_str(),
- static_cast<int32_t>(driver), isDriverLoaded, (long long)driverLoadingTime);
+ mGpuStats->insert(driverPackageName, driverVersionName, driverVersionCode, driverBuildTime,
+ appPackageName, driver, isDriverLoaded, driverLoadingTime);
+}
+
+status_t GpuService::getGpuStatsGlobalInfo(std::vector<GpuStatsGlobalInfo>* outStats) const {
+ ATRACE_CALL();
+
+ mGpuStats->pullGlobalStats(outStats);
+
+ return OK;
}
status_t GpuService::shellCommand(int /*in*/, int out, int err, std::vector<String16>& args) {
@@ -67,28 +75,60 @@
ALOGV(" arg[%zu]: '%s'", i, String8(args[i]).string());
if (args.size() >= 1) {
- if (args[0] == String16("vkjson"))
- return cmd_vkjson(out, err);
- if (args[0] == String16("help"))
- return cmd_help(out);
+ if (args[0] == String16("vkjson")) return cmdVkjson(out, err);
+ if (args[0] == String16("help")) return cmdHelp(out);
}
// no command, or unrecognized command
- cmd_help(err);
+ cmdHelp(err);
return BAD_VALUE;
}
+status_t GpuService::doDump(int fd, const Vector<String16>& args, bool /*asProto*/) {
+ std::string result;
+
+ IPCThreadState* ipc = IPCThreadState::self();
+ const int pid = ipc->getCallingPid();
+ const int uid = ipc->getCallingUid();
+
+ if ((uid != AID_SHELL) && !PermissionCache::checkPermission(sDump, pid, uid)) {
+ StringAppendF(&result, "Permission Denial: can't dump gpu from pid=%d, uid=%d\n", pid, uid);
+ } else {
+ bool dumpAll = true;
+ size_t index = 0;
+ size_t numArgs = args.size();
+
+ if (numArgs) {
+ if ((index < numArgs) && (args[index] == String16("--gpustats"))) {
+ index++;
+ mGpuStats->dump(args, &result);
+ dumpAll = false;
+ }
+ }
+
+ if (dumpAll) {
+ dumpGameDriverInfo(&result);
+ result.append("\n");
+
+ mGpuStats->dump(Vector<String16>(), &result);
+ result.append("\n");
+ }
+ }
+
+ write(fd, result.c_str(), result.size());
+ return NO_ERROR;
+}
+
namespace {
-status_t cmd_help(int out) {
+status_t cmdHelp(int out) {
FILE* outs = fdopen(out, "w");
if (!outs) {
- ALOGE("vkjson: failed to create out stream: %s (%d)", strerror(errno),
- errno);
+ ALOGE("vkjson: failed to create out stream: %s (%d)", strerror(errno), errno);
return BAD_VALUE;
}
fprintf(outs,
- "GPU Service commands:\n"
- " vkjson dump Vulkan properties as JSON\n");
+ "GPU Service commands:\n"
+ " vkjson dump Vulkan properties as JSON\n");
fclose(outs);
return NO_ERROR;
}
@@ -99,7 +139,7 @@
fputc('\n', out);
}
-status_t cmd_vkjson(int out, int /*err*/) {
+status_t cmdVkjson(int out, int /*err*/) {
FILE* outs = fdopen(out, "w");
if (!outs) {
int errnum = errno;
@@ -111,6 +151,18 @@
return NO_ERROR;
}
+void dumpGameDriverInfo(std::string* result) {
+ if (!result) return;
+
+ char stableGameDriver[PROPERTY_VALUE_MAX] = {};
+ property_get("ro.gfx.driver.0", stableGameDriver, "unsupported");
+ StringAppendF(result, "Stable Game Driver: %s\n", stableGameDriver);
+
+ char preReleaseGameDriver[PROPERTY_VALUE_MAX] = {};
+ property_get("ro.gfx.driver.1", preReleaseGameDriver, "unsupported");
+ StringAppendF(result, "Pre-release Game Driver: %s\n", preReleaseGameDriver);
+}
+
} // anonymous namespace
} // namespace android
diff --git a/services/gpuservice/GpuService.h b/services/gpuservice/GpuService.h
index 76234a3..b984e0f 100644
--- a/services/gpuservice/GpuService.h
+++ b/services/gpuservice/GpuService.h
@@ -19,14 +19,18 @@
#include <binder/IInterface.h>
#include <cutils/compiler.h>
+#include <graphicsenv/GpuStatsInfo.h>
#include <graphicsenv/IGpuService.h>
+#include <serviceutils/PriorityDumper.h>
#include <mutex>
#include <vector>
namespace android {
-class GpuService : public BnGpuService {
+class GpuStats;
+
+class GpuService : public BnGpuService, public PriorityDumper {
public:
static const char* const SERVICE_NAME ANDROID_API;
@@ -36,14 +40,37 @@
status_t shellCommand(int in, int out, int err, std::vector<String16>& args) override;
private:
- // IGpuService interface
+ /*
+ * IGpuService interface
+ */
void setGpuStats(const std::string& driverPackageName, const std::string& driverVersionName,
- uint64_t driverVersionCode, const std::string& driverBuildDate,
+ uint64_t driverVersionCode, int64_t driverBuildTime,
const std::string& appPackageName, GraphicsEnv::Driver driver,
- bool isDriverLoaded, int64_t driverLoadingTime);
+ bool isDriverLoaded, int64_t driverLoadingTime) override;
+ status_t getGpuStatsGlobalInfo(std::vector<GpuStatsGlobalInfo>* outStats) const override;
- // GpuStats access must be protected by mStateLock
- std::mutex mStateLock;
+ /*
+ * IBinder interface
+ */
+ status_t dump(int fd, const Vector<String16>& args) override { return priorityDump(fd, args); }
+
+ /*
+ * Debugging & dumpsys
+ */
+ status_t dumpCritical(int fd, const Vector<String16>& /*args*/, bool asProto) override {
+ return doDump(fd, Vector<String16>(), asProto);
+ }
+
+ status_t dumpAll(int fd, const Vector<String16>& args, bool asProto) override {
+ return doDump(fd, args, asProto);
+ }
+
+ status_t doDump(int fd, const Vector<String16>& args, bool asProto);
+
+ /*
+ * Attributes
+ */
+ std::unique_ptr<GpuStats> mGpuStats;
};
} // namespace android
diff --git a/services/gpuservice/gpustats/GpuStats.cpp b/services/gpuservice/gpustats/GpuStats.cpp
new file mode 100644
index 0000000..146e2c2
--- /dev/null
+++ b/services/gpuservice/gpustats/GpuStats.cpp
@@ -0,0 +1,201 @@
+/*
+ * 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.
+ */
+#undef LOG_TAG
+#define LOG_TAG "GpuStats"
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
+#include "GpuStats.h"
+
+#include <unordered_set>
+
+#include <log/log.h>
+#include <utils/Trace.h>
+
+namespace android {
+
+static bool addLoadingCount(GraphicsEnv::Driver driver, bool isDriverLoaded,
+ GpuStatsGlobalInfo* const outGlobalInfo) {
+ switch (driver) {
+ case GraphicsEnv::Driver::GL:
+ case GraphicsEnv::Driver::GL_UPDATED:
+ outGlobalInfo->glLoadingCount++;
+ if (!isDriverLoaded) outGlobalInfo->glLoadingFailureCount++;
+ break;
+ case GraphicsEnv::Driver::VULKAN:
+ case GraphicsEnv::Driver::VULKAN_UPDATED:
+ outGlobalInfo->vkLoadingCount++;
+ if (!isDriverLoaded) outGlobalInfo->vkLoadingFailureCount++;
+ break;
+ default:
+ // Currently we don't support GraphicsEnv::Driver::ANGLE because the
+ // basic driver package info only belongs to system or updated driver.
+ return false;
+ }
+
+ return true;
+}
+
+static void addLoadingTime(GraphicsEnv::Driver driver, int64_t driverLoadingTime,
+ GpuStatsAppInfo* const outAppInfo) {
+ switch (driver) {
+ case GraphicsEnv::Driver::GL:
+ case GraphicsEnv::Driver::GL_UPDATED:
+ outAppInfo->glDriverLoadingTime.emplace_back(driverLoadingTime);
+ break;
+ case GraphicsEnv::Driver::VULKAN:
+ case GraphicsEnv::Driver::VULKAN_UPDATED:
+ outAppInfo->vkDriverLoadingTime.emplace_back(driverLoadingTime);
+ break;
+ default:
+ break;
+ }
+}
+
+void GpuStats::insert(const std::string& driverPackageName, const std::string& driverVersionName,
+ uint64_t driverVersionCode, int64_t driverBuildTime,
+ const std::string& appPackageName, GraphicsEnv::Driver driver,
+ bool isDriverLoaded, int64_t driverLoadingTime) {
+ ATRACE_CALL();
+
+ std::lock_guard<std::mutex> lock(mLock);
+ ALOGV("Received:\n"
+ "\tdriverPackageName[%s]\n"
+ "\tdriverVersionName[%s]\n"
+ "\tdriverVersionCode[%" PRIu64 "]\n"
+ "\tdriverBuildTime[%" PRId64 "]\n"
+ "\tappPackageName[%s]\n"
+ "\tdriver[%d]\n"
+ "\tisDriverLoaded[%d]\n"
+ "\tdriverLoadingTime[%" PRId64 "]",
+ driverPackageName.c_str(), driverVersionName.c_str(), driverVersionCode, driverBuildTime,
+ appPackageName.c_str(), static_cast<int32_t>(driver), isDriverLoaded, driverLoadingTime);
+
+ if (!mGlobalStats.count(driverVersionCode)) {
+ GpuStatsGlobalInfo globalInfo;
+ if (!addLoadingCount(driver, isDriverLoaded, &globalInfo)) {
+ return;
+ }
+ globalInfo.driverPackageName = driverPackageName;
+ globalInfo.driverVersionName = driverVersionName;
+ globalInfo.driverVersionCode = driverVersionCode;
+ globalInfo.driverBuildTime = driverBuildTime;
+ mGlobalStats.insert({driverVersionCode, globalInfo});
+ } else if (!addLoadingCount(driver, isDriverLoaded, &mGlobalStats[driverVersionCode])) {
+ return;
+ }
+
+ if (mAppStats.size() >= MAX_NUM_APP_RECORDS) {
+ ALOGV("GpuStatsAppInfo has reached maximum size. Ignore new stats.");
+ return;
+ }
+
+ const std::string appStatsKey = appPackageName + std::to_string(driverVersionCode);
+ if (!mAppStats.count(appStatsKey)) {
+ GpuStatsAppInfo appInfo;
+ addLoadingTime(driver, driverLoadingTime, &appInfo);
+ appInfo.appPackageName = appPackageName;
+ appInfo.driverVersionCode = driverVersionCode;
+ mAppStats.insert({appStatsKey, appInfo});
+ return;
+ }
+
+ addLoadingTime(driver, driverLoadingTime, &mAppStats[appStatsKey]);
+}
+
+void GpuStats::dump(const Vector<String16>& args, std::string* result) {
+ ATRACE_CALL();
+
+ if (!result) {
+ ALOGE("Dump result shouldn't be nullptr.");
+ return;
+ }
+
+ std::lock_guard<std::mutex> lock(mLock);
+ bool dumpAll = true;
+
+ std::unordered_set<std::string> argsSet;
+ for (size_t i = 0; i < args.size(); i++) {
+ argsSet.insert(String8(args[i]).c_str());
+ }
+
+ const bool dumpGlobal = argsSet.count("--global") != 0;
+ if (dumpGlobal) {
+ dumpGlobalLocked(result);
+ dumpAll = false;
+ }
+
+ const bool dumpApp = argsSet.count("--app") != 0;
+ if (dumpApp) {
+ dumpAppLocked(result);
+ dumpAll = false;
+ }
+
+ if (argsSet.count("--clear")) {
+ bool clearAll = true;
+
+ if (dumpGlobal) {
+ mGlobalStats.clear();
+ clearAll = false;
+ }
+
+ if (dumpApp) {
+ mAppStats.clear();
+ clearAll = false;
+ }
+
+ if (clearAll) {
+ mGlobalStats.clear();
+ mAppStats.clear();
+ }
+
+ dumpAll = false;
+ }
+
+ if (dumpAll) {
+ dumpGlobalLocked(result);
+ dumpAppLocked(result);
+ }
+}
+
+void GpuStats::dumpGlobalLocked(std::string* result) {
+ for (const auto& ele : mGlobalStats) {
+ result->append(ele.second.toString());
+ result->append("\n");
+ }
+}
+
+void GpuStats::dumpAppLocked(std::string* result) {
+ for (const auto& ele : mAppStats) {
+ result->append(ele.second.toString());
+ result->append("\n");
+ }
+}
+
+void GpuStats::pullGlobalStats(std::vector<GpuStatsGlobalInfo>* outStats) {
+ ATRACE_CALL();
+
+ std::lock_guard<std::mutex> lock(mLock);
+ outStats->clear();
+ outStats->reserve(mGlobalStats.size());
+
+ for (const auto& ele : mGlobalStats) {
+ outStats->emplace_back(ele.second);
+ }
+
+ mGlobalStats.clear();
+}
+
+} // namespace android
diff --git a/services/gpuservice/gpustats/GpuStats.h b/services/gpuservice/gpustats/GpuStats.h
new file mode 100644
index 0000000..9cdcd95
--- /dev/null
+++ b/services/gpuservice/gpustats/GpuStats.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <mutex>
+#include <unordered_map>
+#include <vector>
+
+#include <graphicsenv/GpuStatsInfo.h>
+#include <graphicsenv/GraphicsEnv.h>
+#include <utils/String16.h>
+#include <utils/Vector.h>
+
+namespace android {
+
+class GpuStats {
+public:
+ GpuStats() = default;
+ ~GpuStats() = default;
+
+ // Insert new gpu stats into global stats and app stats.
+ void insert(const std::string& driverPackageName, const std::string& driverVersionName,
+ uint64_t driverVersionCode, int64_t driverBuildTime,
+ const std::string& appPackageName, GraphicsEnv::Driver driver, bool isDriverLoaded,
+ int64_t driverLoadingTime);
+ // dumpsys interface
+ void dump(const Vector<String16>& args, std::string* result);
+ // Pull gpu global stats
+ void pullGlobalStats(std::vector<GpuStatsGlobalInfo>* outStats);
+
+private:
+ // Dump global stats
+ void dumpGlobalLocked(std::string* result);
+ // Dump app stats
+ void dumpAppLocked(std::string* result);
+
+ // This limits the memory usage of GpuStats to be less than 30KB. This is
+ // the maximum atom size statsd could afford.
+ static const size_t MAX_NUM_APP_RECORDS = 300;
+ // GpuStats access should be guarded by mLock.
+ std::mutex mLock;
+ // Key is driver version code.
+ std::unordered_map<uint64_t, GpuStatsGlobalInfo> mGlobalStats;
+ // Key is <app package name>+<driver version code>.
+ std::unordered_map<std::string, GpuStatsAppInfo> mAppStats;
+};
+
+} // namespace android
diff --git a/services/inputflinger/EventHub.cpp b/services/inputflinger/EventHub.cpp
index c13bac6..4da1473 100644
--- a/services/inputflinger/EventHub.cpp
+++ b/services/inputflinger/EventHub.cpp
@@ -202,7 +202,6 @@
EventHub::Device::~Device() {
close();
delete configuration;
- delete virtualKeyMap;
}
void EventHub::Device::close() {
@@ -1364,8 +1363,8 @@
if ((device->classes & INPUT_DEVICE_CLASS_TOUCH)) {
// Load the virtual keys for the touch screen, if any.
// We do this now so that we can make sure to load the keymap if necessary.
- status_t status = loadVirtualKeyMapLocked(device);
- if (!status) {
+ bool success = loadVirtualKeyMapLocked(device);
+ if (success) {
device->classes |= INPUT_DEVICE_CLASS_KEYBOARD;
}
}
@@ -1614,15 +1613,16 @@
}
}
-status_t EventHub::loadVirtualKeyMapLocked(Device* device) {
+bool EventHub::loadVirtualKeyMapLocked(Device* device) {
// The virtual key map is supplied by the kernel as a system board property file.
std::string path;
path += "/sys/board_properties/virtualkeys.";
- path += device->identifier.name;
+ path += device->identifier.getCanonicalName();
if (access(path.c_str(), R_OK)) {
- return NAME_NOT_FOUND;
+ return false;
}
- return VirtualKeyMap::load(path, &device->virtualKeyMap);
+ device->virtualKeyMap = VirtualKeyMap::load(path);
+ return device->virtualKeyMap != nullptr;
}
status_t EventHub::loadKeyMapLocked(Device* device) {
diff --git a/services/inputflinger/EventHub.h b/services/inputflinger/EventHub.h
index d176648..44f7b37 100644
--- a/services/inputflinger/EventHub.h
+++ b/services/inputflinger/EventHub.h
@@ -345,7 +345,7 @@
std::string configurationFile;
PropertyMap* configuration;
- VirtualKeyMap* virtualKeyMap;
+ std::unique_ptr<VirtualKeyMap> virtualKeyMap;
KeyMap keyMap;
sp<KeyCharacterMap> overlayKeyMap;
@@ -416,7 +416,7 @@
bool hasKeycodeLocked(Device* device, int keycode) const;
void loadConfigurationLocked(Device* device);
- status_t loadVirtualKeyMapLocked(Device* device);
+ bool loadVirtualKeyMapLocked(Device* device);
status_t loadKeyMapLocked(Device* device);
bool isExternalDeviceLocked(Device* device);
diff --git a/services/inputflinger/InputDispatcher.cpp b/services/inputflinger/InputDispatcher.cpp
index 2ffd0a8..d288736 100644
--- a/services/inputflinger/InputDispatcher.cpp
+++ b/services/inputflinger/InputDispatcher.cpp
@@ -3072,7 +3072,7 @@
* For removed handle, check if need to send a cancel event if already in touch.
*/
void InputDispatcher::setInputWindows(const Vector<sp<InputWindowHandle>>& inputWindowHandles,
- int32_t displayId) {
+ int32_t displayId, const sp<ISetInputWindowsListener>& setInputWindowsListener) {
#if DEBUG_FOCUS
ALOGD("setInputWindows displayId=%" PRId32, displayId);
#endif
@@ -3222,6 +3222,10 @@
// Wake up poll loop since it may need to make new input dispatching choices.
mLooper->wake();
+
+ if (setInputWindowsListener) {
+ setInputWindowsListener->onSetInputWindowsFinished();
+ }
}
void InputDispatcher::setFocusedApplication(
diff --git a/services/inputflinger/InputDispatcher.h b/services/inputflinger/InputDispatcher.h
index ecfeb6c..9d8919b 100644
--- a/services/inputflinger/InputDispatcher.h
+++ b/services/inputflinger/InputDispatcher.h
@@ -21,6 +21,7 @@
#include <input/InputApplication.h>
#include <input/InputTransport.h>
#include <input/InputWindow.h>
+#include <input/ISetInputWindowsListener.h>
#include <utils/KeyedVector.h>
#include <utils/Vector.h>
#include <utils/threads.h>
@@ -39,7 +40,6 @@
#include "InputListener.h"
#include "InputReporterInterface.h"
-
namespace android {
/*
@@ -315,7 +315,8 @@
* This method may be called on any thread (usually by the input manager).
*/
virtual void setInputWindows(const Vector<sp<InputWindowHandle> >& inputWindowHandles,
- int32_t displayId) = 0;
+ int32_t displayId,
+ const sp<ISetInputWindowsListener>& setInputWindowsListener = nullptr) = 0;
/* Sets the focused application on the given display.
*
@@ -406,7 +407,8 @@
uint32_t policyFlags);
virtual void setInputWindows(const Vector<sp<InputWindowHandle> >& inputWindowHandles,
- int32_t displayId);
+ int32_t displayId,
+ const sp<ISetInputWindowsListener>& setInputWindowsListener = nullptr);
virtual void setFocusedApplication(int32_t displayId,
const sp<InputApplicationHandle>& inputApplicationHandle);
virtual void setFocusedDisplay(int32_t displayId);
diff --git a/services/inputflinger/InputManager.cpp b/services/inputflinger/InputManager.cpp
index a7fd9ba..b0157a1 100644
--- a/services/inputflinger/InputManager.cpp
+++ b/services/inputflinger/InputManager.cpp
@@ -103,7 +103,8 @@
}
};
-void InputManager::setInputWindows(const Vector<InputWindowInfo>& infos) {
+void InputManager::setInputWindows(const Vector<InputWindowInfo>& infos,
+ const sp<ISetInputWindowsListener>& setInputWindowsListener) {
std::unordered_map<int32_t, Vector<sp<InputWindowHandle>>> handlesPerDisplay;
Vector<sp<InputWindowHandle>> handles;
@@ -112,7 +113,7 @@
handlesPerDisplay[info.displayId].add(new BinderWindowHandle(info));
}
for (auto const& i : handlesPerDisplay) {
- mDispatcher->setInputWindows(i.second, i.first);
+ mDispatcher->setInputWindows(i.second, i.first, setInputWindowsListener);
}
}
diff --git a/services/inputflinger/InputManager.h b/services/inputflinger/InputManager.h
index e632da3..ff9a080 100644
--- a/services/inputflinger/InputManager.h
+++ b/services/inputflinger/InputManager.h
@@ -29,6 +29,7 @@
#include <input/Input.h>
#include <input/InputTransport.h>
+#include <input/ISetInputWindowsListener.h>
#include <input/IInputFlinger.h>
#include <utils/Errors.h>
@@ -93,7 +94,8 @@
virtual sp<InputClassifierInterface> getClassifier();
virtual sp<InputDispatcherInterface> getDispatcher();
- virtual void setInputWindows(const Vector<InputWindowInfo>& handles);
+ virtual void setInputWindows(const Vector<InputWindowInfo>& handles,
+ const sp<ISetInputWindowsListener>& setInputWindowsListener);
virtual void transferTouchFocus(const sp<IBinder>& fromToken, const sp<IBinder>& toToken);
virtual void registerInputChannel(const sp<InputChannel>& channel);
diff --git a/services/inputflinger/host/InputFlinger.h b/services/inputflinger/host/InputFlinger.h
index 9d0be95..a00b5fb 100644
--- a/services/inputflinger/host/InputFlinger.h
+++ b/services/inputflinger/host/InputFlinger.h
@@ -24,6 +24,7 @@
#include <cutils/compiler.h>
#include <input/IInputFlinger.h>
+#include <input/ISetInputWindowsListener.h>
#include <utils/String8.h>
#include <utils/String16.h>
#include <utils/StrongPointer.h>
@@ -39,7 +40,7 @@
InputFlinger() ANDROID_API;
virtual status_t dump(int fd, const Vector<String16>& args);
- void setInputWindows(const Vector<InputWindowInfo>&) {}
+ void setInputWindows(const Vector<InputWindowInfo>&, const sp<ISetInputWindowsListener>&) {}
void transferTouchFocus(const sp<IBinder>&, const sp<IBinder>&) {}
void registerInputChannel(const sp<InputChannel>&) {}
void unregisterInputChannel(const sp<InputChannel>&) {}
diff --git a/services/surfaceflinger/AllowedDisplayConfigs.h b/services/surfaceflinger/AllowedDisplayConfigs.h
new file mode 100644
index 0000000..7ca62ea
--- /dev/null
+++ b/services/surfaceflinger/AllowedDisplayConfigs.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <log/log.h>
+#include <vector>
+
+/*
+ * Used to represent the Display Configurations allowed to be set by SurfaceFlinger
+ */
+class AllowedDisplayConfigs {
+private:
+ // Defining ConstructorTag as private to prevent instantiating this class from outside
+ // while still allowing it to be constructed by std::make_unique
+ struct ConstructorTag {};
+
+public:
+ AllowedDisplayConfigs(ConstructorTag) {}
+
+ class Builder {
+ public:
+ Builder()
+ : mAllowedDisplayConfigs(std::make_unique<AllowedDisplayConfigs>(ConstructorTag{})) {}
+
+ std::unique_ptr<const AllowedDisplayConfigs> build() {
+ return std::move(mAllowedDisplayConfigs);
+ }
+
+ // add a config to the allowed config set
+ Builder& addConfig(int32_t config) {
+ mAllowedDisplayConfigs->addConfig(config);
+ return *this;
+ }
+
+ private:
+ std::unique_ptr<AllowedDisplayConfigs> mAllowedDisplayConfigs;
+ };
+
+ bool isConfigAllowed(int32_t config) const {
+ return (std::find(mConfigs.begin(), mConfigs.end(), config) != mConfigs.end());
+ }
+
+ void getAllowedConfigs(std::vector<int32_t>* outConfigs) const {
+ if (outConfigs) {
+ *outConfigs = mConfigs;
+ }
+ }
+
+private:
+ // add a config to the allowed config set
+ void addConfig(int32_t config) { mConfigs.push_back(config); }
+
+ std::vector<int32_t> mConfigs;
+};
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index 734ed6c..ac1d492 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -23,7 +23,6 @@
"android.hardware.configstore-utils",
"android.hardware.configstore@1.0",
"android.hardware.configstore@1.1",
- "android.hardware.configstore@1.2",
"android.hardware.graphics.allocator@2.0",
"android.hardware.graphics.allocator@3.0",
"android.hardware.graphics.common@1.2",
@@ -57,7 +56,6 @@
"libui",
"libinput",
"libutils",
- "libutilscallstack",
"libSurfaceFlingerProperties",
],
static_libs: [
@@ -134,7 +132,6 @@
"EventLog/EventLog.cpp",
"FrameTracker.cpp",
"Layer.cpp",
- "LayerBE.cpp",
"LayerProtoHelper.cpp",
"LayerRejecter.cpp",
"LayerStats.cpp",
@@ -142,6 +139,7 @@
"MonitoredProducer.cpp",
"NativeWindowSurface.cpp",
"RenderArea.cpp",
+ "RegionSamplingThread.cpp",
"Scheduler/DispSync.cpp",
"Scheduler/DispSyncSource.cpp",
"Scheduler/EventControlThread.cpp",
@@ -189,7 +187,6 @@
"android.frameworks.displayservice@1.0",
"android.hardware.configstore-utils",
"android.hardware.configstore@1.0",
- "android.hardware.configstore@1.2",
"android.hardware.graphics.allocator@2.0",
"android.hardware.graphics.allocator@3.0",
"libbinder",
@@ -244,13 +241,15 @@
"android.hardware.configstore-utils",
"android.hardware.configstore@1.0",
"android.hardware.configstore@1.1",
- "android.hardware.configstore@1.2",
+ "android.hardware.graphics.common@1.2",
"libhidlbase",
"libhidltransport",
"libhwbinder",
+ "libui",
"libutils",
],
export_shared_lib_headers: [
+ "android.hardware.graphics.common@1.2",
"libhidlbase",
"libhidltransport",
"libhwbinder",
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index 2501fae..756ca42 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -125,9 +125,11 @@
bool BufferLayer::prepareClientLayer(const RenderArea& renderArea, const Region& clip,
bool useIdentityTransform, Region& clearRegion,
+ const bool supportProtectedContent,
renderengine::LayerSettings& layer) {
ATRACE_CALL();
- Layer::prepareClientLayer(renderArea, clip, useIdentityTransform, clearRegion, layer);
+ Layer::prepareClientLayer(renderArea, clip, useIdentityTransform, clearRegion,
+ supportProtectedContent, layer);
if (CC_UNLIKELY(mActiveBuffer == 0)) {
// the texture has not been created yet, this Layer has
// in fact never been drawn into. This happens frequently with
@@ -154,15 +156,13 @@
}
return false;
}
- bool blackOutLayer = isProtected() || (isSecure() && !renderArea.isSecure());
+ bool blackOutLayer =
+ (isProtected() && !supportProtectedContent) || (isSecure() && !renderArea.isSecure());
const State& s(getDrawingState());
if (!blackOutLayer) {
layer.source.buffer.buffer = mActiveBuffer;
layer.source.buffer.isOpaque = isOpaque(s);
layer.source.buffer.fence = mActiveBufferFence;
- layer.source.buffer.cacheHint = useCachedBufferForClientComposition()
- ? renderengine::Buffer::CachingHint::USE_CACHE
- : renderengine::Buffer::CachingHint::NO_CACHE;
layer.source.buffer.textureName = mTextureName;
layer.source.buffer.usePremultipliedAlpha = getPremultipledAlpha();
layer.source.buffer.isY410BT2020 = isHdrY410();
diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h
index e3b10fc..e9dbdea 100644
--- a/services/surfaceflinger/BufferLayer.h
+++ b/services/surfaceflinger/BufferLayer.h
@@ -161,14 +161,11 @@
bool mRefreshPending{false};
- // Returns true if, when drawing the active buffer during gpu compositon, we
- // should use a cached buffer or not.
- virtual bool useCachedBufferForClientComposition() const = 0;
-
// prepareClientLayer - constructs a RenderEngine layer for GPU composition.
bool prepareClientLayer(const RenderArea& renderArea, const Region& clip,
bool useIdentityTransform, Region& clearRegion,
- renderengine::LayerSettings& layer);
+ const bool supportProtectedContent,
+ renderengine::LayerSettings& layer) override;
private:
// Returns true if this layer requires filtering
diff --git a/services/surfaceflinger/BufferLayerConsumer.cpp b/services/surfaceflinger/BufferLayerConsumer.cpp
index 6866e5c..7d2dcba 100644
--- a/services/surfaceflinger/BufferLayerConsumer.cpp
+++ b/services/surfaceflinger/BufferLayerConsumer.cpp
@@ -178,7 +178,8 @@
return;
}
- auto buffer = mPendingRelease.isPending ? mPendingRelease.graphicBuffer : mCurrentTextureBuffer;
+ auto buffer = mPendingRelease.isPending ? mPendingRelease.graphicBuffer
+ : mCurrentTextureBuffer->graphicBuffer();
auto err = addReleaseFence(slot, buffer, fence);
if (err != OK) {
BLC_LOGE("setReleaseFence: failed to add the fence: %s (%d)", strerror(-err), err);
@@ -214,9 +215,9 @@
}
// If item->mGraphicBuffer is not null, this buffer has not been acquired
- // before.
+ // before, so we need to clean up old references.
if (item->mGraphicBuffer != nullptr) {
- mImages[item->mSlot] = nullptr;
+ mImages[item->mSlot] = std::make_shared<Image>(item->mGraphicBuffer, mRE);
}
return NO_ERROR;
@@ -229,18 +230,21 @@
int slot = item.mSlot;
BLC_LOGV("updateAndRelease: (slot=%d buf=%p) -> (slot=%d buf=%p)", mCurrentTexture,
- mCurrentTextureBuffer != nullptr ? mCurrentTextureBuffer->handle : 0, slot,
- mSlots[slot].mGraphicBuffer->handle);
+ (mCurrentTextureBuffer != nullptr && mCurrentTextureBuffer->graphicBuffer() != nullptr)
+ ? mCurrentTextureBuffer->graphicBuffer()->handle
+ : 0,
+ slot, mSlots[slot].mGraphicBuffer->handle);
// Hang onto the pointer so that it isn't freed in the call to
// releaseBufferLocked() if we're in shared buffer mode and both buffers are
// the same.
- sp<GraphicBuffer> nextTextureBuffer = mSlots[slot].mGraphicBuffer;
+ std::shared_ptr<Image> nextTextureBuffer = mImages[slot];
// release old buffer
if (mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) {
if (pendingRelease == nullptr) {
- status_t status = releaseBufferLocked(mCurrentTexture, mCurrentTextureBuffer);
+ status_t status =
+ releaseBufferLocked(mCurrentTexture, mCurrentTextureBuffer->graphicBuffer());
if (status < NO_ERROR) {
BLC_LOGE("updateAndRelease: failed to release buffer: %s (%d)", strerror(-status),
status);
@@ -249,7 +253,7 @@
}
} else {
pendingRelease->currentTexture = mCurrentTexture;
- pendingRelease->graphicBuffer = mCurrentTextureBuffer;
+ pendingRelease->graphicBuffer = mCurrentTextureBuffer->graphicBuffer();
pendingRelease->isPending = true;
}
}
@@ -257,8 +261,6 @@
// Update the BufferLayerConsumer state.
mCurrentTexture = slot;
mCurrentTextureBuffer = nextTextureBuffer;
- mCurrentTextureBufferStaleForGpu = false;
- mCurrentTextureImageFreed = nullptr;
mCurrentCrop = item.mCrop;
mCurrentTransform = item.mTransform;
mCurrentScalingMode = item.mScalingMode;
@@ -280,7 +282,12 @@
status_t BufferLayerConsumer::bindTextureImageLocked() {
ATRACE_CALL();
- return mRE.bindExternalTextureBuffer(mTexName, mCurrentTextureBuffer, mCurrentFence, false);
+ if (mCurrentTextureBuffer != nullptr && mCurrentTextureBuffer->graphicBuffer() != nullptr) {
+ return mRE.bindExternalTextureBuffer(mTexName, mCurrentTextureBuffer->graphicBuffer(),
+ mCurrentFence);
+ }
+
+ return NO_INIT;
}
void BufferLayerConsumer::getTransformMatrix(float mtx[16]) {
@@ -308,12 +315,15 @@
void BufferLayerConsumer::computeCurrentTransformMatrixLocked() {
BLC_LOGV("computeCurrentTransformMatrixLocked");
- if (mCurrentTextureBuffer == nullptr) {
+ if (mCurrentTextureBuffer == nullptr || mCurrentTextureBuffer->graphicBuffer() == nullptr) {
BLC_LOGD("computeCurrentTransformMatrixLocked: "
"mCurrentTextureBuffer is nullptr");
}
- GLConsumer::computeTransformMatrix(mCurrentTransformMatrix, mCurrentTextureBuffer, mCurrentCrop,
- mCurrentTransform, mFilteringEnabled);
+ GLConsumer::computeTransformMatrix(mCurrentTransformMatrix,
+ mCurrentTextureBuffer == nullptr
+ ? nullptr
+ : mCurrentTextureBuffer->graphicBuffer(),
+ mCurrentCrop, mCurrentTransform, mFilteringEnabled);
}
nsecs_t BufferLayerConsumer::getTimestamp() {
@@ -365,16 +375,7 @@
*outFence = mCurrentFence;
}
- return mCurrentTextureBuffer;
-}
-
-bool BufferLayerConsumer::getAndSetCurrentBufferCacheHint() {
- Mutex::Autolock lock(mMutex);
- bool useCache = mCurrentTextureBufferStaleForGpu;
- // Set the staleness bit here, as this function is only called during a
- // client composition path.
- mCurrentTextureBufferStaleForGpu = true;
- return useCache;
+ return mCurrentTextureBuffer == nullptr ? nullptr : mCurrentTextureBuffer->graphicBuffer();
}
Rect BufferLayerConsumer::getCurrentCrop() const {
@@ -432,10 +433,8 @@
BLC_LOGV("freeBufferLocked: slotIndex=%d", slotIndex);
if (slotIndex == mCurrentTexture) {
mCurrentTexture = BufferQueue::INVALID_BUFFER_SLOT;
- mCurrentTextureImageFreed = std::move(mImages[slotIndex]);
- } else {
- mImages[slotIndex] = nullptr;
}
+ mImages[slotIndex] = nullptr;
ConsumerBase::freeBufferLocked(slotIndex);
}
@@ -474,7 +473,10 @@
void BufferLayerConsumer::abandonLocked() {
BLC_LOGV("abandonLocked");
- mCurrentTextureBuffer.clear();
+ mCurrentTextureBuffer = nullptr;
+ for (int i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) {
+ mImages[i] = nullptr;
+ }
ConsumerBase::abandonLocked();
}
@@ -492,4 +494,11 @@
ConsumerBase::dumpLocked(result, prefix);
}
+BufferLayerConsumer::Image::~Image() {
+ if (mGraphicBuffer != nullptr) {
+ ALOGE("Destroying buffer: %" PRId64, mGraphicBuffer->getId());
+ mRE.unbindExternalTextureBuffer(mGraphicBuffer->getId());
+ }
+}
+
}; // namespace android
diff --git a/services/surfaceflinger/BufferLayerConsumer.h b/services/surfaceflinger/BufferLayerConsumer.h
index e2a6d2e..32ccfbb 100644
--- a/services/surfaceflinger/BufferLayerConsumer.h
+++ b/services/surfaceflinger/BufferLayerConsumer.h
@@ -149,11 +149,6 @@
// for use with bilinear filtering.
void setFilteringEnabled(bool enabled);
- // Sets mCurrentTextureBufferStaleForGpu to true to indicate that the
- // buffer is now "stale" for GPU composition, and returns the old staleness
- // bit as a caching hint.
- bool getAndSetCurrentBufferCacheHint();
-
// getCurrentBuffer returns the buffer associated with the current image.
// When outSlot is not nullptr, the current buffer slot index is also
// returned. Simiarly, when outFence is not nullptr, the current output
@@ -218,6 +213,22 @@
status_t bindTextureImageLocked();
private:
+ // Utility class for managing GraphicBuffer references into renderengine
+ class Image {
+ public:
+ Image(sp<GraphicBuffer> graphicBuffer, renderengine::RenderEngine& engine)
+ : mGraphicBuffer(graphicBuffer), mRE(engine) {}
+ virtual ~Image();
+ const sp<GraphicBuffer>& graphicBuffer() { return mGraphicBuffer; }
+
+ private:
+ // mGraphicBuffer is the buffer that was used to create this image.
+ sp<GraphicBuffer> mGraphicBuffer;
+ // Back-reference into renderengine to initiate cleanup.
+ renderengine::RenderEngine& mRE;
+ DISALLOW_COPY_AND_ASSIGN(Image);
+ };
+
// freeBufferLocked frees up the given buffer slot. If the slot has been
// initialized this will release the reference to the GraphicBuffer in
// that slot. Otherwise it has no effect.
@@ -248,14 +259,10 @@
// consume buffers as hardware textures.
static const uint64_t DEFAULT_USAGE_FLAGS = GraphicBuffer::USAGE_HW_TEXTURE;
- // mCurrentTextureImage is the buffer containing the current texture. It's
+ // mCurrentTextureBuffer is the buffer containing the current texture. It's
// possible that this buffer is not associated with any buffer slot, so we
// must track it separately in order to support the getCurrentBuffer method.
- sp<GraphicBuffer> mCurrentTextureBuffer;
-
- // True if the buffer was used for the previous client composition frame,
- // and false otherwise.
- bool mCurrentTextureBufferStaleForGpu;
+ std::shared_ptr<Image> mCurrentTextureBuffer;
// mCurrentCrop is the crop rectangle that applies to the current texture.
// It gets set each time updateTexImage is called.
@@ -333,16 +340,8 @@
// reset mCurrentTexture to INVALID_BUFFER_SLOT.
int mCurrentTexture;
- // Cached image used for rendering the current texture through GPU
- // composition, which contains the cached image after freeBufferLocked is
- // called on the current buffer. Whenever latchBuffer is called, this is
- // expected to be cleared. Then, if bindTexImage is called before the next
- // buffer is acquired, then this image is bound.
- std::unique_ptr<renderengine::Image> mCurrentTextureImageFreed;
-
- // Cached images used for rendering the current texture through GPU
- // composition.
- std::unique_ptr<renderengine::Image> mImages[BufferQueueDefs::NUM_BUFFER_SLOTS];
+ // Shadow buffer cache for cleaning up renderengine references.
+ std::shared_ptr<Image> mImages[BufferQueueDefs::NUM_BUFFER_SLOTS];
// A release that is pending on the receipt of a new release fence from
// presentDisplay
diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp
index b3e2a4b..7cd9e49 100644
--- a/services/surfaceflinger/BufferQueueLayer.cpp
+++ b/services/surfaceflinger/BufferQueueLayer.cpp
@@ -199,7 +199,6 @@
bool sidebandStreamChanged = true;
if (mSidebandStreamChanged.compare_exchange_strong(sidebandStreamChanged, false)) {
// mSidebandStreamChanged was changed to false
- // replicated in LayerBE until FE/BE is ready to be synchronized
auto& layerCompositionState = getCompositionLayer()->editState().frontEnd;
layerCompositionState.sidebandStream = mConsumer->getSidebandStream();
if (layerCompositionState.sidebandStream != nullptr) {
@@ -343,10 +342,6 @@
return NO_ERROR;
}
-bool BufferQueueLayer::useCachedBufferForClientComposition() const {
- return mConsumer->getAndSetCurrentBufferCacheHint();
-}
-
status_t BufferQueueLayer::updateFrameNumber(nsecs_t latchTime) {
mPreviousFrameNumber = mCurrentFrameNumber;
mCurrentFrameNumber = mConsumer->getFrameNumber();
@@ -367,7 +362,7 @@
uint32_t hwcSlot = 0;
sp<GraphicBuffer> hwcBuffer;
(*outputLayer->editState().hwc)
- .hwcBufferCache.getHwcBuffer(mActiveBufferSlot, mActiveBuffer, &hwcSlot, &hwcBuffer);
+ .hwcBufferCache.getHwcBuffer(mActiveBuffer, &hwcSlot, &hwcBuffer);
auto acquireFence = mConsumer->getCurrentFence();
auto error = hwcLayer->setBuffer(hwcSlot, hwcBuffer, acquireFence);
@@ -397,9 +392,11 @@
void BufferQueueLayer::onFrameAvailable(const BufferItem& item) {
// Add this buffer from our internal queue tracker
{ // Autolock scope
- // Report the requested present time to the Scheduler.
- mFlinger->mScheduler->addFramePresentTimeForLayer(item.mTimestamp, item.mIsAutoTimestamp,
- mName.c_str());
+ if (mFlinger->mUse90Hz && mFlinger->mUseSmart90ForVideo) {
+ // Report the requested present time to the Scheduler, if the feature is turned on.
+ mFlinger->mScheduler->addFramePresentTimeForLayer(item.mTimestamp,
+ item.mIsAutoTimestamp, mName.c_str());
+ }
Mutex::Autolock lock(mQueueItemLock);
// Reset the frame number tracker when we receive the first buffer after
diff --git a/services/surfaceflinger/BufferQueueLayer.h b/services/surfaceflinger/BufferQueueLayer.h
index fbb8c14..a2aad17 100644
--- a/services/surfaceflinger/BufferQueueLayer.h
+++ b/services/surfaceflinger/BufferQueueLayer.h
@@ -62,9 +62,6 @@
public:
bool fenceHasSignaled() const override;
-protected:
- bool useCachedBufferForClientComposition() const override;
-
private:
nsecs_t getDesiredPresentTime() override;
std::shared_ptr<FenceTime> getCurrentFenceTime() const override;
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index e48c41e..b2383ad 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -48,7 +48,12 @@
mOverrideScalingMode = NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW;
mCurrentState.dataspace = ui::Dataspace::V0_SRGB;
}
-BufferStateLayer::~BufferStateLayer() = default;
+BufferStateLayer::~BufferStateLayer() {
+ if (mActiveBuffer != nullptr) {
+ auto& engine(mFlinger->getRenderEngine());
+ engine.unbindExternalTextureBuffer(mActiveBuffer->getId());
+ }
+}
// -----------------------------------------------------------------------
// Interface implementation for Layer
@@ -198,7 +203,6 @@
mReleasePreviousBuffer = true;
}
- mCurrentState.sequence++;
mCurrentState.buffer = buffer;
mCurrentState.modified = true;
setTransactionFlags(eTransactionNeeded);
@@ -217,7 +221,6 @@
bool BufferStateLayer::setDataspace(ui::Dataspace dataspace) {
if (mCurrentState.dataspace == dataspace) return false;
- mCurrentState.sequence++;
mCurrentState.dataspace = dataspace;
mCurrentState.modified = true;
setTransactionFlags(eTransactionNeeded);
@@ -470,7 +473,7 @@
const State& s(getDrawingState());
auto& engine(mFlinger->getRenderEngine());
- return engine.bindExternalTextureBuffer(mTextureName, s.buffer, s.acquireFence, false);
+ return engine.bindExternalTextureBuffer(mTextureName, s.buffer, s.acquireFence);
}
status_t BufferStateLayer::updateTexImage(bool& /*recomputeVisibleRegions*/, nsecs_t latchTime) {
@@ -544,6 +547,11 @@
return BAD_VALUE;
}
+ if (mActiveBuffer != nullptr) {
+ // todo: get this to work with BufferStateLayerCache
+ auto& engine(mFlinger->getRenderEngine());
+ engine.unbindExternalTextureBuffer(mActiveBuffer->getId());
+ }
mActiveBuffer = s.buffer;
mActiveBufferFence = s.acquireFence;
auto& layerCompositionState = getCompositionLayer()->editState().frontEnd;
@@ -553,11 +561,6 @@
return NO_ERROR;
}
-bool BufferStateLayer::useCachedBufferForClientComposition() const {
- // TODO: Store a proper staleness bit to support EGLImage caching.
- return false;
-}
-
status_t BufferStateLayer::updateFrameNumber(nsecs_t /*latchTime*/) {
// TODO(marissaw): support frame history events
mCurrentFrameNumber = mFrameNumber;
@@ -567,14 +570,17 @@
void BufferStateLayer::setHwcLayerBuffer(const sp<const DisplayDevice>& display) {
const auto outputLayer = findOutputLayerForDisplay(display);
LOG_FATAL_IF(!outputLayer || !outputLayer->getState().hwc);
- auto& hwcLayer = (*outputLayer->getState().hwc).hwcLayer;
+ auto& hwcInfo = *outputLayer->editState().hwc;
+ auto& hwcLayer = hwcInfo.hwcLayer;
const State& s(getDrawingState());
- // TODO(marissaw): support more than one slot
+ // obtain slot
uint32_t hwcSlot = 0;
+ sp<GraphicBuffer> buffer;
+ hwcInfo.hwcBufferCache.getHwcBuffer(s.buffer, &hwcSlot, &buffer);
- auto error = hwcLayer->setBuffer(hwcSlot, s.buffer, s.acquireFence);
+ auto error = hwcLayer->setBuffer(hwcSlot, buffer, s.acquireFence);
if (error != HWC2::Error::None) {
ALOGE("[%s] Failed to set buffer %p: %s (%d)", mName.string(),
s.buffer->handle, to_string(error).c_str(), static_cast<int32_t>(error));
diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h
index 0b03f49..97662e8 100644
--- a/services/surfaceflinger/BufferStateLayer.h
+++ b/services/surfaceflinger/BufferStateLayer.h
@@ -96,9 +96,6 @@
// -----------------------------------------------------------------------
bool fenceHasSignaled() const override;
-protected:
- bool useCachedBufferForClientComposition() const override;
-
private:
nsecs_t getDesiredPresentTime() override;
std::shared_ptr<FenceTime> getCurrentFenceTime() const override;
diff --git a/services/surfaceflinger/ColorLayer.cpp b/services/surfaceflinger/ColorLayer.cpp
index 9ea0a46..2aeece7 100644
--- a/services/surfaceflinger/ColorLayer.cpp
+++ b/services/surfaceflinger/ColorLayer.cpp
@@ -50,8 +50,10 @@
bool ColorLayer::prepareClientLayer(const RenderArea& renderArea, const Region& clip,
bool useIdentityTransform, Region& clearRegion,
+ const bool supportProtectedContent,
renderengine::LayerSettings& layer) {
- Layer::prepareClientLayer(renderArea, clip, useIdentityTransform, clearRegion, layer);
+ Layer::prepareClientLayer(renderArea, clip, useIdentityTransform, clearRegion,
+ supportProtectedContent, layer);
half4 color(getColor());
half3 solidColor(color.r, color.g, color.b);
layer.source.solidColor = solidColor;
diff --git a/services/surfaceflinger/ColorLayer.h b/services/surfaceflinger/ColorLayer.h
index df0adac..9786419 100644
--- a/services/surfaceflinger/ColorLayer.h
+++ b/services/surfaceflinger/ColorLayer.h
@@ -42,9 +42,10 @@
protected:
FloatRect computeCrop(const sp<const DisplayDevice>& /*display*/) const override { return {}; }
- virtual bool prepareClientLayer(const RenderArea& renderArea, const Region& clip,
- bool useIdentityTransform, Region& clearRegion,
- renderengine::LayerSettings& layer);
+ bool prepareClientLayer(const RenderArea& renderArea, const Region& clip,
+ bool useIdentityTransform, Region& clearRegion,
+ const bool supportProtectedContent,
+ renderengine::LayerSettings& layer) override;
private:
std::shared_ptr<compositionengine::Layer> mCompositionLayer;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
index f9a3624..6cc87ba 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
@@ -18,10 +18,19 @@
#include <utils/RefBase.h>
-namespace android::compositionengine {
+namespace android {
+
+class Fence;
+
+namespace compositionengine {
// Defines the interface used by the CompositionEngine to make requests
// of the front-end layer
-class LayerFE : public virtual RefBase {};
+class LayerFE : public virtual RefBase {
+public:
+ // Called after the layer is displayed to update the presentation fence
+ virtual void onLayerDisplayed(const sp<Fence>&) = 0;
+};
-} // namespace android::compositionengine
+} // namespace compositionengine
+} // namespace android
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h
index 2009380..e69b99f 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h
@@ -71,7 +71,7 @@
virtual status_t prepareFrame() = 0;
// Allocates a buffer as scratch space for GPU composition
- virtual sp<GraphicBuffer> dequeueBuffer() = 0;
+ virtual sp<GraphicBuffer> dequeueBuffer(base::unique_fd* bufferFence) = 0;
// Queues the drawn buffer for consumption by HWC. readyFence is the fence
// which will fire when the buffer is ready for consumption.
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/HwcBufferCache.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/HwcBufferCache.h
index b45de5a..02d7890 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/HwcBufferCache.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/HwcBufferCache.h
@@ -19,6 +19,7 @@
#include <cstdint>
#include <vector>
+#include <gui/BufferQueue.h>
#include <utils/StrongPointer.h>
namespace android {
@@ -39,19 +40,28 @@
class HwcBufferCache {
public:
HwcBufferCache();
-
- // Given a buffer queue slot and buffer, return the HWC cache slot and
+ // Given a buffer, return the HWC cache slot and
// buffer to be sent to HWC.
//
// outBuffer is set to buffer when buffer is not in the HWC cache;
// otherwise, outBuffer is set to nullptr.
- void getHwcBuffer(int slot, const sp<GraphicBuffer>& buffer, uint32_t* outSlot,
+ void getHwcBuffer(const sp<GraphicBuffer>& buffer, uint32_t* outSlot,
sp<GraphicBuffer>* outBuffer);
+protected:
+ bool getSlot(const sp<GraphicBuffer>& buffer, uint32_t* outSlot);
+ uint32_t getLeastRecentlyUsedSlot();
+ uint64_t getCounter();
+
private:
- // a vector as we expect "slot" to be in the range of [0, 63] (that is,
- // less than BufferQueue::NUM_BUFFER_SLOTS).
- std::vector<sp<GraphicBuffer>> mBuffers;
+ // an array where the index corresponds to a slot and the value corresponds to a (counter,
+ // buffer) pair. "counter" is a unique value that indicates the last time this slot was updated
+ // or used and allows us to keep track of the least-recently used buffer.
+ std::pair<uint64_t, wp<GraphicBuffer>> mBuffers[BufferQueue::NUM_BUFFER_SLOTS];
+
+ // The cache increments this counter value when a slot is updated or used.
+ // Used to track the least recently-used buffer
+ uint64_t mCounter = 1;
};
} // namespace compositionengine::impl
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h
index 58b13ed..3c79084 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h
@@ -52,7 +52,7 @@
void setProtected(bool useProtected) override;
status_t beginFrame(bool mustRecompose) override;
status_t prepareFrame() override;
- sp<GraphicBuffer> dequeueBuffer() override;
+ sp<GraphicBuffer> dequeueBuffer(base::unique_fd* bufferFence) override;
void queueBuffer(base::unique_fd&& readyFence) override;
void onPresentDisplayCompleted() override;
void setViewportAndProjection() override;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h
index 92e0070..a0c2a63 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h
@@ -18,6 +18,7 @@
#include <compositionengine/LayerFE.h>
#include <gmock/gmock.h>
+#include <ui/Fence.h>
namespace android::compositionengine::mock {
@@ -27,6 +28,8 @@
public:
LayerFE();
virtual ~LayerFE();
+
+ MOCK_METHOD1(onLayerDisplayed, void(const sp<Fence>&));
};
} // namespace android::compositionengine::mock
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h
index 8442bef..1562f58 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h
@@ -37,7 +37,7 @@
MOCK_METHOD1(setBufferDataspace, void(ui::Dataspace));
MOCK_METHOD1(beginFrame, status_t(bool mustRecompose));
MOCK_METHOD0(prepareFrame, status_t());
- MOCK_METHOD0(dequeueBuffer, sp<GraphicBuffer>());
+ MOCK_METHOD1(dequeueBuffer, sp<GraphicBuffer>(base::unique_fd*));
MOCK_METHOD1(queueBuffer, void(base::unique_fd&&));
MOCK_METHOD0(onPresentDisplayCompleted, void());
MOCK_METHOD0(setViewportAndProjection, void());
diff --git a/services/surfaceflinger/CompositionEngine/src/HwcBufferCache.cpp b/services/surfaceflinger/CompositionEngine/src/HwcBufferCache.cpp
index 6f340b9..8613210 100644
--- a/services/surfaceflinger/CompositionEngine/src/HwcBufferCache.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/HwcBufferCache.cpp
@@ -21,31 +21,52 @@
namespace android::compositionengine::impl {
HwcBufferCache::HwcBufferCache() {
- mBuffers.reserve(BufferQueue::NUM_BUFFER_SLOTS);
+ std::fill(std::begin(mBuffers), std::end(mBuffers),
+ std::pair<uint64_t, wp<GraphicBuffer>>(0, nullptr));
+}
+bool HwcBufferCache::getSlot(const sp<GraphicBuffer>& buffer, uint32_t* outSlot) {
+ // search for cached buffer first
+ for (int i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) {
+ // Weak pointers in the cache may have had their object destroyed.
+ // Comparisons between weak pointers will accurately reflect this case,
+ // but comparisons between weak and strong may not. Thus, we create a weak
+ // pointer from strong pointer buffer
+ wp<GraphicBuffer> weakCopy(buffer);
+ if (mBuffers[i].second == weakCopy) {
+ *outSlot = i;
+ return true;
+ }
+ }
+
+ // use the least-recently used slot
+ *outSlot = getLeastRecentlyUsedSlot();
+ return false;
}
-void HwcBufferCache::getHwcBuffer(int slot, const sp<GraphicBuffer>& buffer, uint32_t* outSlot,
+uint32_t HwcBufferCache::getLeastRecentlyUsedSlot() {
+ auto iter = std::min_element(std::begin(mBuffers), std::end(mBuffers));
+ return std::distance(std::begin(mBuffers), iter);
+}
+
+void HwcBufferCache::getHwcBuffer(const sp<GraphicBuffer>& buffer, uint32_t* outSlot,
sp<GraphicBuffer>* outBuffer) {
- if (slot == BufferQueue::INVALID_BUFFER_SLOT || slot < 0) {
- // default to slot 0
- slot = 0;
- }
+ bool cached = getSlot(buffer, outSlot);
- if (static_cast<size_t>(slot) >= mBuffers.size()) {
- mBuffers.resize(slot + 1);
- }
-
- *outSlot = slot;
-
- if (mBuffers[slot] == buffer) {
+ auto& [currentCounter, currentBuffer] = mBuffers[*outSlot];
+ if (cached) {
// already cached in HWC, skip sending the buffer
*outBuffer = nullptr;
+ currentCounter = getCounter();
} else {
*outBuffer = buffer;
// update cache
- mBuffers[slot] = buffer;
+ currentBuffer = buffer;
+ currentCounter = getCounter();
}
}
+uint64_t HwcBufferCache::getCounter() {
+ return mCounter++;
+}
} // namespace android::compositionengine::impl
diff --git a/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp b/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp
index ebb1bc2..b4dfba1 100644
--- a/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
#include <android-base/stringprintf.h>
#include <android/native_window.h>
#include <compositionengine/CompositionEngine.h>
@@ -28,6 +30,7 @@
#include <system/window.h>
#include <ui/GraphicBuffer.h>
#include <ui/Rect.h>
+#include <utils/Trace.h>
#include "DisplayHardware/HWComposer.h"
@@ -127,7 +130,8 @@
return mDisplaySurface->prepareFrame(compositionType);
}
-sp<GraphicBuffer> RenderSurface::dequeueBuffer() {
+sp<GraphicBuffer> RenderSurface::dequeueBuffer(base::unique_fd* bufferFence) {
+ ATRACE_CALL();
int fd = -1;
ANativeWindowBuffer* buffer = nullptr;
@@ -145,13 +149,7 @@
mGraphicBuffer->getNativeBuffer()->handle);
mGraphicBuffer = GraphicBuffer::from(buffer);
- // Block until the buffer is ready
- // TODO(alecmouri): it's perhaps more appropriate to block renderengine so
- // that the gl driver can block instead.
- if (fd >= 0) {
- sync_wait(fd, -1);
- close(fd);
- }
+ *bufferFence = base::unique_fd(fd);
return mGraphicBuffer;
}
@@ -172,7 +170,8 @@
// We shouldn't deadlock here, since mGraphicBuffer == nullptr only
// after a successful call to queueBuffer, or if dequeueBuffer has
// never been called.
- dequeueBuffer();
+ base::unique_fd unused;
+ dequeueBuffer(&unused);
}
if (mGraphicBuffer == nullptr) {
diff --git a/services/surfaceflinger/CompositionEngine/tests/HwcBufferCacheTest.cpp b/services/surfaceflinger/CompositionEngine/tests/HwcBufferCacheTest.cpp
index f2a1aad..ac04cb3 100644
--- a/services/surfaceflinger/CompositionEngine/tests/HwcBufferCacheTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/HwcBufferCacheTest.cpp
@@ -22,60 +22,80 @@
namespace android::compositionengine {
namespace {
+class TestableHwcBufferCache : public impl::HwcBufferCache {
+public:
+ void getHwcBuffer(const sp<GraphicBuffer>& buffer, uint32_t* outSlot,
+ sp<GraphicBuffer>* outBuffer) {
+ HwcBufferCache::getHwcBuffer(buffer, outSlot, outBuffer);
+ }
+ bool getSlot(const sp<GraphicBuffer>& buffer, uint32_t* outSlot) {
+ return HwcBufferCache::getSlot(buffer, outSlot);
+ }
+ uint32_t getLeastRecentlyUsedSlot() { return HwcBufferCache::getLeastRecentlyUsedSlot(); }
+};
+
class HwcBufferCacheTest : public testing::Test {
public:
~HwcBufferCacheTest() override = default;
- void testSlot(const int inSlot, const uint32_t expectedSlot) {
- uint32_t outSlot;
- sp<GraphicBuffer> outBuffer;
-
- // The first time, the output is the same as the input
- mCache.getHwcBuffer(inSlot, mBuffer1, &outSlot, &outBuffer);
- EXPECT_EQ(expectedSlot, outSlot);
- EXPECT_EQ(mBuffer1, outBuffer);
-
- // The second time with the same buffer, the outBuffer is nullptr.
- mCache.getHwcBuffer(inSlot, mBuffer1, &outSlot, &outBuffer);
- EXPECT_EQ(expectedSlot, outSlot);
- EXPECT_EQ(nullptr, outBuffer.get());
-
- // With a new buffer, the outBuffer is the input.
- mCache.getHwcBuffer(inSlot, mBuffer2, &outSlot, &outBuffer);
- EXPECT_EQ(expectedSlot, outSlot);
- EXPECT_EQ(mBuffer2, outBuffer);
-
- // Again, the second request with the same buffer sets outBuffer to nullptr.
- mCache.getHwcBuffer(inSlot, mBuffer2, &outSlot, &outBuffer);
- EXPECT_EQ(expectedSlot, outSlot);
- EXPECT_EQ(nullptr, outBuffer.get());
-
- // Setting a slot to use nullptr lookslike works, but note that
- // the output values make it look like no new buffer is being set....
- mCache.getHwcBuffer(inSlot, sp<GraphicBuffer>(), &outSlot, &outBuffer);
- EXPECT_EQ(expectedSlot, outSlot);
- EXPECT_EQ(nullptr, outBuffer.get());
- }
-
- impl::HwcBufferCache mCache;
+ TestableHwcBufferCache mCache;
sp<GraphicBuffer> mBuffer1{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)};
sp<GraphicBuffer> mBuffer2{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)};
};
-TEST_F(HwcBufferCacheTest, cacheWorksForSlotZero) {
- testSlot(0, 0);
+TEST_F(HwcBufferCacheTest, testSlot) {
+ uint32_t outSlot;
+ sp<GraphicBuffer> outBuffer;
+
+ // The first time, the output is the same as the input
+ mCache.getHwcBuffer(mBuffer1, &outSlot, &outBuffer);
+ EXPECT_EQ(0, outSlot);
+ EXPECT_EQ(mBuffer1, outBuffer);
+
+ // The second time with the same buffer, the outBuffer is nullptr.
+ mCache.getHwcBuffer(mBuffer1, &outSlot, &outBuffer);
+ EXPECT_EQ(0, outSlot);
+ EXPECT_EQ(nullptr, outBuffer.get());
+
+ // With a new buffer, the outBuffer is the input.
+ mCache.getHwcBuffer(mBuffer2, &outSlot, &outBuffer);
+ EXPECT_EQ(1, outSlot);
+ EXPECT_EQ(mBuffer2, outBuffer);
+
+ // Again, the second request with the same buffer sets outBuffer to nullptr.
+ mCache.getHwcBuffer(mBuffer2, &outSlot, &outBuffer);
+ EXPECT_EQ(1, outSlot);
+ EXPECT_EQ(nullptr, outBuffer.get());
+
+ // Setting a slot to use nullptr lookslike works, but note that
+ // the output values make it look like no new buffer is being set....
+ mCache.getHwcBuffer(sp<GraphicBuffer>(), &outSlot, &outBuffer);
+ EXPECT_EQ(2, outSlot);
+ EXPECT_EQ(nullptr, outBuffer.get());
}
-TEST_F(HwcBufferCacheTest, cacheWorksForMaxSlot) {
- testSlot(BufferQueue::NUM_BUFFER_SLOTS - 1, BufferQueue::NUM_BUFFER_SLOTS - 1);
-}
+TEST_F(HwcBufferCacheTest, testGetLeastRecentlyUsedSlot) {
+ int slot;
+ uint32_t outSlot;
+ sp<GraphicBuffer> outBuffer;
-TEST_F(HwcBufferCacheTest, cacheMapsNegativeSlotToZero) {
- testSlot(-123, 0);
-}
+ // fill up cache
+ for (int i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) {
+ sp<GraphicBuffer> buf{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)};
+ mCache.getHwcBuffer(buf, &outSlot, &outBuffer);
+ EXPECT_EQ(buf, outBuffer);
+ EXPECT_EQ(i, outSlot);
+ }
-TEST_F(HwcBufferCacheTest, cacheMapsInvalidBufferSlotToZero) {
- testSlot(BufferQueue::INVALID_BUFFER_SLOT, 0);
+ slot = mCache.getLeastRecentlyUsedSlot();
+ EXPECT_EQ(0, slot);
+
+ mCache.getHwcBuffer(mBuffer1, &outSlot, &outBuffer);
+ EXPECT_EQ(0, outSlot);
+ EXPECT_EQ(mBuffer1, outBuffer);
+
+ slot = mCache.getLeastRecentlyUsedSlot();
+ EXPECT_EQ(1, slot);
}
} // namespace
diff --git a/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp b/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp
index 0a7c462..84af9b9 100644
--- a/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp
@@ -358,7 +358,8 @@
.WillOnce(
DoAll(SetArgPointee<0>(buffer.get()), SetArgPointee<1>(-1), Return(NO_ERROR)));
- EXPECT_EQ(buffer.get(), mSurface.dequeueBuffer().get());
+ base::unique_fd fence;
+ EXPECT_EQ(buffer.get(), mSurface.dequeueBuffer(&fence).get());
EXPECT_EQ(buffer.get(), mSurface.mutableGraphicBufferForTest().get());
}
diff --git a/services/surfaceflinger/ContainerLayer.cpp b/services/surfaceflinger/ContainerLayer.cpp
index 22c40d7..738f4b6 100644
--- a/services/surfaceflinger/ContainerLayer.cpp
+++ b/services/surfaceflinger/ContainerLayer.cpp
@@ -26,7 +26,7 @@
ContainerLayer::~ContainerLayer() = default;
-bool ContainerLayer::prepareClientLayer(const RenderArea&, const Region&, bool, Region&,
+bool ContainerLayer::prepareClientLayer(const RenderArea&, const Region&, bool, Region&, const bool,
renderengine::LayerSettings&) {
return false;
}
diff --git a/services/surfaceflinger/ContainerLayer.h b/services/surfaceflinger/ContainerLayer.h
index c69997d..c7cfdcd 100644
--- a/services/surfaceflinger/ContainerLayer.h
+++ b/services/surfaceflinger/ContainerLayer.h
@@ -43,7 +43,8 @@
protected:
bool prepareClientLayer(const RenderArea& renderArea, const Region& clip,
bool useIdentityTransform, Region& clearRegion,
- renderengine::LayerSettings& layer);
+ const bool supportProtectedContent,
+ renderengine::LayerSettings& layer) override;
};
} // namespace android
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index a827c47..c80925e 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -255,17 +255,18 @@
device->getCompositionDataSpace(), rotation) {}
DisplayRenderArea(const sp<const DisplayDevice> device, Rect sourceCrop, uint32_t reqWidth,
uint32_t reqHeight, ui::Dataspace reqDataSpace,
- ui::Transform::orientation_flags rotation)
+ ui::Transform::orientation_flags rotation, bool allowSecureLayers = true)
: RenderArea(reqWidth, reqHeight, CaptureFill::OPAQUE, reqDataSpace,
getDisplayRotation(rotation, device->getInstallOrientation())),
mDevice(device),
- mSourceCrop(sourceCrop) {}
+ mSourceCrop(sourceCrop),
+ mAllowSecureLayers(allowSecureLayers) {}
const ui::Transform& getTransform() const override { return mDevice->getTransform(); }
Rect getBounds() const override { return mDevice->getBounds(); }
int getHeight() const override { return mDevice->getHeight(); }
int getWidth() const override { return mDevice->getWidth(); }
- bool isSecure() const override { return mDevice->isSecure(); }
+ bool isSecure() const override { return mAllowSecureLayers && mDevice->isSecure(); }
const sp<const DisplayDevice> getDisplayDevice() const override { return mDevice; }
bool needsFiltering() const override {
@@ -356,6 +357,7 @@
const sp<const DisplayDevice> mDevice;
const Rect mSourceCrop;
+ const bool mAllowSecureLayers;
};
}; // namespace android
diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
index 27812f7..775fb80 100644
--- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
@@ -111,8 +111,7 @@
BufferItem item;
status_t err = acquireBufferLocked(&item, 0);
if (err == BufferQueue::NO_BUFFER_AVAILABLE) {
- mHwcBufferCache.getHwcBuffer(mCurrentBufferSlot, mCurrentBuffer,
- &outSlot, &outBuffer);
+ mHwcBufferCache.getHwcBuffer(mCurrentBuffer, &outSlot, &outBuffer);
return NO_ERROR;
} else if (err != NO_ERROR) {
ALOGE("error acquiring buffer: %s (%d)", strerror(-err), err);
@@ -138,8 +137,7 @@
mCurrentFence = item.mFence;
outFence = item.mFence;
- mHwcBufferCache.getHwcBuffer(mCurrentBufferSlot, mCurrentBuffer,
- &outSlot, &outBuffer);
+ mHwcBufferCache.getHwcBuffer(mCurrentBuffer, &outSlot, &outBuffer);
outDataspace = static_cast<Dataspace>(item.mDataSpace);
status_t result = mHwc.setClientTarget(mDisplayId, outSlot, outFence, outBuffer, outDataspace);
if (result != NO_ERROR) {
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp
index bca0abc..910a527 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp
@@ -143,8 +143,8 @@
return error;
}
- auto display = std::make_unique<impl::Display>(*mComposer.get(), mPowerAdvisor, mCapabilities,
- displayId, DisplayType::Virtual);
+ auto display = std::make_unique<impl::Display>(*mComposer.get(), mCapabilities, displayId,
+ DisplayType::Virtual);
display->setConnected(true);
*outDisplay = display.get();
mDisplays.emplace(displayId, std::move(display));
@@ -182,8 +182,8 @@
return;
}
- auto newDisplay = std::make_unique<impl::Display>(*mComposer.get(), mPowerAdvisor,
- mCapabilities, displayId, displayType);
+ auto newDisplay = std::make_unique<impl::Display>(*mComposer.get(), mCapabilities,
+ displayId, displayType);
newDisplay->setConnected(true);
mDisplays.emplace(displayId, std::move(newDisplay));
} else if (connection == Connection::Disconnected) {
@@ -254,11 +254,10 @@
}
namespace impl {
-Display::Display(android::Hwc2::Composer& composer, android::Hwc2::PowerAdvisor& advisor,
+Display::Display(android::Hwc2::Composer& composer,
const std::unordered_set<Capability>& capabilities, hwc2_display_t id,
DisplayType type)
: mComposer(composer),
- mPowerAdvisor(advisor),
mCapabilities(capabilities),
mId(id),
mIsConnected(false),
@@ -636,12 +635,6 @@
Error Display::setColorMode(ColorMode mode, RenderIntent renderIntent)
{
- // When the color mode is switched to DISPLAY_P3, we want to boost the GPU frequency
- // so that GPU composition can finish in time. When color mode is switched from
- // DISPLAY_P3, we want to reset GPU frequency.
- const bool expensiveRenderingExpected = (mode == ColorMode::DISPLAY_P3);
- mPowerAdvisor.setExpensiveRenderingExpected(mId, expensiveRenderingExpected);
-
auto intError = mComposer.setColorMode(mId, mode, renderIntent);
return static_cast<Error>(intError);
}
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.h b/services/surfaceflinger/DisplayHardware/HWC2.h
index 70358a0..f96614f 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.h
+++ b/services/surfaceflinger/DisplayHardware/HWC2.h
@@ -37,8 +37,6 @@
#include <unordered_set>
#include <vector>
-#include "PowerAdvisor.h"
-
namespace android {
struct DisplayedFrameStats;
class Fence;
@@ -125,7 +123,6 @@
std::unique_ptr<android::Hwc2::Composer> mComposer;
std::unordered_set<Capability> mCapabilities;
std::unordered_map<hwc2_display_t, std::unique_ptr<Display>> mDisplays;
- android::Hwc2::impl::PowerAdvisor mPowerAdvisor;
bool mRegisteredCallback = false;
};
@@ -273,9 +270,8 @@
class Display : public HWC2::Display {
public:
- Display(android::Hwc2::Composer& composer, android::Hwc2::PowerAdvisor& advisor,
- const std::unordered_set<Capability>& capabilities, hwc2_display_t id,
- DisplayType type);
+ Display(android::Hwc2::Composer& composer, const std::unordered_set<Capability>& capabilities,
+ hwc2_display_t id, DisplayType type);
~Display() override;
// Required by HWC2
@@ -352,7 +348,6 @@
// this HWC2::Display, so these references are guaranteed to be valid for
// the lifetime of this object.
android::Hwc2::Composer& mComposer;
- android::Hwc2::PowerAdvisor& mPowerAdvisor;
const std::unordered_set<Capability>& mCapabilities;
hwc2_display_t mId;
diff --git a/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp b/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
index 12bbae2..039db73 100644
--- a/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
+++ b/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
@@ -38,7 +38,7 @@
PowerAdvisor::PowerAdvisor() = default;
-void PowerAdvisor::setExpensiveRenderingExpected(hwc2_display_t displayId, bool expected) {
+void PowerAdvisor::setExpensiveRenderingExpected(DisplayId displayId, bool expected) {
if (expected) {
mExpensiveDisplays.insert(displayId);
} else {
diff --git a/services/surfaceflinger/DisplayHardware/PowerAdvisor.h b/services/surfaceflinger/DisplayHardware/PowerAdvisor.h
index 573a1a9..5aa1f22 100644
--- a/services/surfaceflinger/DisplayHardware/PowerAdvisor.h
+++ b/services/surfaceflinger/DisplayHardware/PowerAdvisor.h
@@ -22,10 +22,12 @@
#undef HWC2_INCLUDE_STRINGIFICATION
#undef HWC2_USE_CPP11
+#include <unordered_set>
+
#include <android/hardware/power/1.3/IPower.h>
#include <utils/StrongPointer.h>
-#include <unordered_set>
+#include "DisplayIdentification.h"
namespace android {
namespace Hwc2 {
@@ -34,7 +36,7 @@
public:
virtual ~PowerAdvisor();
- virtual void setExpensiveRenderingExpected(hwc2_display_t displayId, bool expected) = 0;
+ virtual void setExpensiveRenderingExpected(DisplayId displayId, bool expected) = 0;
};
namespace impl {
@@ -48,12 +50,12 @@
PowerAdvisor();
~PowerAdvisor() override;
- void setExpensiveRenderingExpected(hwc2_display_t displayId, bool expected) override;
+ void setExpensiveRenderingExpected(DisplayId displayId, bool expected) override;
private:
sp<V1_3::IPower> getPowerHal();
- std::unordered_set<hwc2_display_t> mExpensiveDisplays;
+ std::unordered_set<DisplayId> mExpensiveDisplays;
bool mNotifiedExpensiveRendering = false;
bool mReconnectPowerHal = false;
};
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
index 1c2853a..613dc77 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
@@ -224,8 +224,7 @@
if (fbBuffer != nullptr) {
uint32_t hwcSlot = 0;
sp<GraphicBuffer> hwcBuffer;
- mHwcBufferCache.getHwcBuffer(mFbProducerSlot, fbBuffer,
- &hwcSlot, &hwcBuffer);
+ mHwcBufferCache.getHwcBuffer(fbBuffer, &hwcSlot, &hwcBuffer);
// TODO: Correctly propagate the dataspace from GL composition
result = mHwc.setClientTarget(*mDisplayId, hwcSlot, mFbFence, hwcBuffer,
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index daef7c6..4567916 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -69,10 +69,7 @@
std::atomic<int32_t> Layer::sSequence{1};
Layer::Layer(const LayerCreationArgs& args)
- : mFlinger(args.flinger),
- mName(args.name),
- mClientRef(args.client),
- mBE{this, args.name.string()} {
+ : mFlinger(args.flinger), mName(args.name), mClientRef(args.client) {
mCurrentCrop.makeInvalid();
uint32_t layerFlags = 0;
@@ -150,7 +147,7 @@
strongRelative->removeZOrderRelative(this);
mFlinger->setTransactionFlags(eTraversalNeeded);
}
- mCurrentState.zOrderRelativeOf = nullptr;
+ setZOrderRelativeOf(nullptr);
}
// Since we are no longer reachable from CurrentState SurfaceFlinger
@@ -683,18 +680,21 @@
// ---------------------------------------------------------------------------
bool Layer::prepareClientLayer(const RenderArea& renderArea, const Region& clip,
- Region& clearRegion, renderengine::LayerSettings& layer) {
- return prepareClientLayer(renderArea, clip, false, clearRegion, layer);
+ Region& clearRegion, const bool supportProtectedContent,
+ renderengine::LayerSettings& layer) {
+ return prepareClientLayer(renderArea, clip, false, clearRegion, supportProtectedContent, layer);
}
bool Layer::prepareClientLayer(const RenderArea& renderArea, bool useIdentityTransform,
- Region& clearRegion, renderengine::LayerSettings& layer) {
+ Region& clearRegion, const bool supportProtectedContent,
+ renderengine::LayerSettings& layer) {
return prepareClientLayer(renderArea, Region(renderArea.getBounds()), useIdentityTransform,
- clearRegion, layer);
+ clearRegion, supportProtectedContent, layer);
}
bool Layer::prepareClientLayer(const RenderArea& /*renderArea*/, const Region& /*clip*/,
bool useIdentityTransform, Region& /*clearRegion*/,
+ const bool /*supportProtectedContent*/,
renderengine::LayerSettings& layer) {
FloatRect bounds = getBounds();
half alpha = getAlpha();
@@ -1164,7 +1164,7 @@
if (strongRelative != nullptr) {
strongRelative->removeZOrderRelative(this);
}
- mCurrentState.zOrderRelativeOf = nullptr;
+ setZOrderRelativeOf(nullptr);
}
setTransactionFlags(eTransactionNeeded);
return true;
@@ -1184,6 +1184,13 @@
setTransactionFlags(eTransactionNeeded);
}
+void Layer::setZOrderRelativeOf(const wp<Layer>& relativeOf) {
+ mCurrentState.zOrderRelativeOf = relativeOf;
+ mCurrentState.sequence++;
+ mCurrentState.modified = true;
+ setTransactionFlags(eTransactionNeeded);
+}
+
bool Layer::setRelativeLayer(const sp<IBinder>& relativeToHandle, int32_t relativeZ) {
sp<Handle> handle = static_cast<Handle*>(relativeToHandle.get());
if (handle == nullptr) {
@@ -1207,7 +1214,7 @@
if (oldZOrderRelativeOf != nullptr) {
oldZOrderRelativeOf->removeZOrderRelative(this);
}
- mCurrentState.zOrderRelativeOf = relative;
+ setZOrderRelativeOf(relative);
relative->addZOrderRelative(this);
setTransactionFlags(eTransactionNeeded);
@@ -1338,10 +1345,8 @@
return true;
}
-bool Layer::setMetadata(LayerMetadata data) {
- bool changed = data.mMap != mCurrentState.metadata.mMap;
- if (!changed) return false;
- mCurrentState.metadata = std::move(data);
+bool Layer::setMetadata(const LayerMetadata& data) {
+ if (!mCurrentState.metadata.merge(data, true /* eraseEmpty */)) return false;
mCurrentState.sequence++;
mCurrentState.modified = true;
setTransactionFlags(eTransactionNeeded);
@@ -2042,26 +2047,26 @@
}
LayerProtoHelper::writeToProto(state.activeTransparentRegion_legacy,
- layerInfo->mutable_transparent_region());
- LayerProtoHelper::writeToProto(visibleRegion, layerInfo->mutable_visible_region());
- LayerProtoHelper::writeToProto(surfaceDamageRegion, layerInfo->mutable_damage_region());
+ [&]() { return layerInfo->mutable_transparent_region(); });
+ LayerProtoHelper::writeToProto(visibleRegion,
+ [&]() { return layerInfo->mutable_visible_region(); });
+ LayerProtoHelper::writeToProto(surfaceDamageRegion,
+ [&]() { return layerInfo->mutable_damage_region(); });
layerInfo->set_layer_stack(getLayerStack());
layerInfo->set_z(state.z);
- PositionProto* position = layerInfo->mutable_position();
- position->set_x(transform.tx());
- position->set_y(transform.ty());
+ LayerProtoHelper::writePositionToProto(transform.tx(), transform.ty(),
+ [&]() { return layerInfo->mutable_position(); });
- PositionProto* requestedPosition = layerInfo->mutable_requested_position();
- requestedPosition->set_x(requestedTransform.tx());
- requestedPosition->set_y(requestedTransform.ty());
+ LayerProtoHelper::writePositionToProto(requestedTransform.tx(), requestedTransform.ty(), [&]() {
+ return layerInfo->mutable_requested_position();
+ });
- SizeProto* size = layerInfo->mutable_size();
- size->set_w(state.active_legacy.w);
- size->set_h(state.active_legacy.h);
+ LayerProtoHelper::writeSizeToProto(state.active_legacy.w, state.active_legacy.h,
+ [&]() { return layerInfo->mutable_size(); });
- LayerProtoHelper::writeToProto(state.crop_legacy, layerInfo->mutable_crop());
+ LayerProtoHelper::writeToProto(state.crop_legacy, [&]() { return layerInfo->mutable_crop(); });
layerInfo->set_corner_radius(getRoundedCornerState().radius);
layerInfo->set_is_opaque(isOpaque(state));
@@ -2071,8 +2076,9 @@
layerInfo->set_dataspace(dataspaceDetails(static_cast<android_dataspace>(mCurrentDataSpace)));
layerInfo->set_pixel_format(decodePixelFormat(getPixelFormat()));
- LayerProtoHelper::writeToProto(getColor(), layerInfo->mutable_color());
- LayerProtoHelper::writeToProto(state.color, layerInfo->mutable_requested_color());
+ LayerProtoHelper::writeToProto(getColor(), [&]() { return layerInfo->mutable_color(); });
+ LayerProtoHelper::writeToProto(state.color,
+ [&]() { return layerInfo->mutable_requested_color(); });
layerInfo->set_flags(state.flags);
LayerProtoHelper::writeToProto(transform, layerInfo->mutable_transform());
@@ -2094,7 +2100,8 @@
auto buffer = mActiveBuffer;
if (buffer != nullptr) {
- LayerProtoHelper::writeToProto(buffer, layerInfo->mutable_active_buffer());
+ LayerProtoHelper::writeToProto(buffer,
+ [&]() { return layerInfo->mutable_active_buffer(); });
LayerProtoHelper::writeToProto(ui::Transform(mCurrentTransform),
layerInfo->mutable_buffer_transform());
}
@@ -2118,9 +2125,11 @@
(*protoMap)[entry.first] = std::string(entry.second.cbegin(), entry.second.cend());
}
LayerProtoHelper::writeToProto(mEffectiveTransform, layerInfo->mutable_effective_transform());
- LayerProtoHelper::writeToProto(mSourceBounds, layerInfo->mutable_source_bounds());
- LayerProtoHelper::writeToProto(mScreenBounds, layerInfo->mutable_screen_bounds());
- LayerProtoHelper::writeToProto(mBounds, layerInfo->mutable_bounds());
+ LayerProtoHelper::writeToProto(mSourceBounds,
+ [&]() { return layerInfo->mutable_source_bounds(); });
+ LayerProtoHelper::writeToProto(mScreenBounds,
+ [&]() { return layerInfo->mutable_screen_bounds(); });
+ LayerProtoHelper::writeToProto(mBounds, [&]() { return layerInfo->mutable_bounds(); });
}
void Layer::writeToProto(LayerProto* layerInfo, const sp<DisplayDevice>& displayDevice) {
@@ -2134,10 +2143,10 @@
const auto& compositionState = outputLayer->getState();
const Rect& frame = compositionState.displayFrame;
- LayerProtoHelper::writeToProto(frame, layerInfo->mutable_hwc_frame());
+ LayerProtoHelper::writeToProto(frame, [&]() { return layerInfo->mutable_hwc_frame(); });
const FloatRect& crop = compositionState.sourceCrop;
- LayerProtoHelper::writeToProto(crop, layerInfo->mutable_hwc_crop());
+ LayerProtoHelper::writeToProto(crop, [&]() { return layerInfo->mutable_hwc_crop(); });
const int32_t transform =
getCompositionLayer() ? static_cast<int32_t>(compositionState.bufferTransform) : 0;
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 1375a39..3763c58 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -45,7 +45,6 @@
#include "Client.h"
#include "FrameTracker.h"
-#include "LayerBE.h"
#include "LayerVector.h"
#include "MonitoredProducer.h"
#include "SurfaceFlinger.h"
@@ -67,7 +66,6 @@
class GraphicBuffer;
class SurfaceFlinger;
class LayerDebugInfo;
-class LayerBE;
namespace compositionengine {
class Layer;
@@ -97,9 +95,6 @@
static std::atomic<int32_t> sSequence;
public:
- friend class LayerBE;
- LayerBE& getBE() { return mBE; }
- LayerBE& getBE() const { return mBE; }
mutable bool contentDirty{false};
// regions below are in window-manager space
Region visibleRegion;
@@ -292,7 +287,7 @@
uint64_t frameNumber);
virtual void deferTransactionUntil_legacy(const sp<Layer>& barrierLayer, uint64_t frameNumber);
virtual bool setOverrideScalingMode(int32_t overrideScalingMode);
- virtual bool setMetadata(LayerMetadata data);
+ virtual bool setMetadata(const LayerMetadata& data);
virtual bool reparentChildren(const sp<IBinder>& layer);
virtual void setChildrenDrawingParent(const sp<Layer>& layer);
virtual bool reparent(const sp<IBinder>& newParentHandle);
@@ -437,9 +432,15 @@
protected:
virtual bool prepareClientLayer(const RenderArea& renderArea, const Region& clip,
bool useIdentityTransform, Region& clearRegion,
- renderengine::LayerSettings& layer) = 0;
+ const bool supportProtectedContent,
+ renderengine::LayerSettings& layer);
public:
+ /*
+ * compositionengine::LayerFE overrides
+ */
+ void onLayerDisplayed(const sp<Fence>& releaseFence) override;
+
virtual void setDefaultBufferSize(uint32_t /*w*/, uint32_t /*h*/) {}
virtual bool isHdrY410() const { return false; }
@@ -460,11 +461,6 @@
bool getClearClientTarget(const sp<const DisplayDevice>& display) const;
void updateCursorPosition(const sp<const DisplayDevice>& display);
- /*
- * called after page-flip
- */
- virtual void onLayerDisplayed(const sp<Fence>& releaseFence);
-
virtual bool shouldPresentNow(nsecs_t /*expectedPresentTime*/) const { return false; }
virtual void setTransformHint(uint32_t /*orientation*/) const { }
@@ -494,9 +490,10 @@
* false otherwise.
*/
bool prepareClientLayer(const RenderArea& renderArea, const Region& clip, Region& clearRegion,
- renderengine::LayerSettings& layer);
+ const bool supportProtectedContent, renderengine::LayerSettings& layer);
bool prepareClientLayer(const RenderArea& renderArea, bool useIdentityTransform,
- Region& clearRegion, renderengine::LayerSettings& layer);
+ Region& clearRegion, const bool supportProtectedContent,
+ renderengine::LayerSettings& layer);
/*
* doTransaction - process the transaction. This is a good place to figure
@@ -860,8 +857,6 @@
wp<Layer> mCurrentParent;
wp<Layer> mDrawingParent;
- mutable LayerBE mBE;
-
// Can only be accessed with the SF state lock held.
bool mLayerDetached{false};
// Can only be accessed with the SF state lock held.
@@ -904,6 +899,8 @@
// Layer bounds in screen space.
FloatRect mScreenBounds;
+
+ void setZOrderRelativeOf(const wp<Layer>& relativeOf);
};
} // namespace android
diff --git a/services/surfaceflinger/LayerBE.cpp b/services/surfaceflinger/LayerBE.cpp
deleted file mode 100644
index 9f63440..0000000
--- a/services/surfaceflinger/LayerBE.cpp
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_NDEBUG 0
-#undef LOG_TAG
-#define LOG_TAG "LayerBE"
-#define ATRACE_TAG ATRACE_TAG_GRAPHICS
-
-#include "Layer.h"
-
-namespace android {
-
-LayerBE::LayerBE(Layer* layer, std::string layerName) : mLayer(layer) {
- compositionInfo.layer = std::make_shared<LayerBE>(*this);
- compositionInfo.layerName = layerName;
-}
-
-LayerBE::LayerBE(const LayerBE& layer) : mLayer(layer.mLayer) {
- compositionInfo.layer = layer.compositionInfo.layer;
- compositionInfo.layerName = layer.mLayer->getName().string();
-}
-
-void LayerBE::onLayerDisplayed(const sp<Fence>& releaseFence) {
- mLayer->onLayerDisplayed(releaseFence);
-}
-
-}; // namespace android
diff --git a/services/surfaceflinger/LayerBE.h b/services/surfaceflinger/LayerBE.h
deleted file mode 100644
index 51f7857..0000000
--- a/services/surfaceflinger/LayerBE.h
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <stdint.h>
-#include <string.h>
-
-#include <ui/Fence.h>
-#include <utils/StrongPointer.h>
-
-#include "DisplayHardware/DisplayIdentification.h"
-
-namespace android {
-
-class LayerBE;
-
-struct CompositionInfo {
- std::string layerName;
- std::shared_ptr<LayerBE> layer;
- struct {
- DisplayId displayId;
- } hwc;
-};
-
-class LayerBE {
-public:
- friend class Layer;
- friend class BufferLayer;
- friend class BufferQueueLayer;
- friend class BufferStateLayer;
- friend class ColorLayer;
- friend class SurfaceFlinger;
-
- // For unit tests
- friend class TestableSurfaceFlinger;
-
- LayerBE(Layer* layer, std::string layerName);
- explicit LayerBE(const LayerBE& layer);
-
- void onLayerDisplayed(const sp<Fence>& releaseFence);
-
- Layer*const mLayer;
-
-private:
- CompositionInfo compositionInfo;
-};
-
-}; // namespace android
-
diff --git a/services/surfaceflinger/LayerProtoHelper.cpp b/services/surfaceflinger/LayerProtoHelper.cpp
index 3289e8f..2d6d33c 100644
--- a/services/surfaceflinger/LayerProtoHelper.cpp
+++ b/services/surfaceflinger/LayerProtoHelper.cpp
@@ -18,53 +18,104 @@
namespace android {
namespace surfaceflinger {
-void LayerProtoHelper::writeToProto(const Region& region, RegionProto* regionProto) {
+
+void LayerProtoHelper::writePositionToProto(const float x, const float y,
+ std::function<PositionProto*()> getPositionProto) {
+ if (x != 0 || y != 0) {
+ // Use a lambda do avoid writing the object header when the object is empty
+ PositionProto* position = getPositionProto();
+ position->set_x(x);
+ position->set_y(y);
+ }
+}
+
+void LayerProtoHelper::writeSizeToProto(const uint32_t w, const uint32_t h,
+ std::function<SizeProto*()> getSizeProto) {
+ if (w != 0 || h != 0) {
+ // Use a lambda do avoid writing the object header when the object is empty
+ SizeProto* size = getSizeProto();
+ size->set_w(w);
+ size->set_h(h);
+ }
+}
+
+void LayerProtoHelper::writeToProto(const Region& region,
+ std::function<RegionProto*()> getRegionProto) {
+ if (region.isEmpty()) {
+ return;
+ }
+
Region::const_iterator head = region.begin();
Region::const_iterator const tail = region.end();
- uint64_t address = reinterpret_cast<uint64_t>(®ion);
- regionProto->set_id(address);
+ // Use a lambda do avoid writing the object header when the object is empty
+ RegionProto* regionProto = getRegionProto();
while (head != tail) {
- RectProto* rectProto = regionProto->add_rect();
- writeToProto(*head, rectProto);
+ std::function<RectProto*()> getProtoRect = [&]() { return regionProto->add_rect(); };
+ writeToProto(*head, getProtoRect);
head++;
}
}
-void LayerProtoHelper::writeToProto(const Rect& rect, RectProto* rectProto) {
- rectProto->set_left(rect.left);
- rectProto->set_top(rect.top);
- rectProto->set_bottom(rect.bottom);
- rectProto->set_right(rect.right);
+void LayerProtoHelper::writeToProto(const Rect& rect, std::function<RectProto*()> getRectProto) {
+ if (rect.left != 0 || rect.right != 0 || rect.top != 0 || rect.bottom != 0) {
+ // Use a lambda do avoid writing the object header when the object is empty
+ RectProto* rectProto = getRectProto();
+ rectProto->set_left(rect.left);
+ rectProto->set_top(rect.top);
+ rectProto->set_bottom(rect.bottom);
+ rectProto->set_right(rect.right);
+ }
}
-void LayerProtoHelper::writeToProto(const FloatRect& rect, FloatRectProto* rectProto) {
- rectProto->set_left(rect.left);
- rectProto->set_top(rect.top);
- rectProto->set_bottom(rect.bottom);
- rectProto->set_right(rect.right);
+void LayerProtoHelper::writeToProto(const FloatRect& rect,
+ std::function<FloatRectProto*()> getFloatRectProto) {
+ if (rect.left != 0 || rect.right != 0 || rect.top != 0 || rect.bottom != 0) {
+ // Use a lambda do avoid writing the object header when the object is empty
+ FloatRectProto* rectProto = getFloatRectProto();
+ rectProto->set_left(rect.left);
+ rectProto->set_top(rect.top);
+ rectProto->set_bottom(rect.bottom);
+ rectProto->set_right(rect.right);
+ }
}
-void LayerProtoHelper::writeToProto(const half4 color, ColorProto* colorProto) {
- colorProto->set_r(color.r);
- colorProto->set_g(color.g);
- colorProto->set_b(color.b);
- colorProto->set_a(color.a);
+void LayerProtoHelper::writeToProto(const half4 color, std::function<ColorProto*()> getColorProto) {
+ if (color.r != 0 || color.g != 0 || color.b != 0 || color.a != 0) {
+ // Use a lambda do avoid writing the object header when the object is empty
+ ColorProto* colorProto = getColorProto();
+ colorProto->set_r(color.r);
+ colorProto->set_g(color.g);
+ colorProto->set_b(color.b);
+ colorProto->set_a(color.a);
+ }
}
void LayerProtoHelper::writeToProto(const ui::Transform& transform,
TransformProto* transformProto) {
- transformProto->set_dsdx(transform[0][0]);
- transformProto->set_dtdx(transform[0][1]);
- transformProto->set_dsdy(transform[1][0]);
- transformProto->set_dtdy(transform[1][1]);
+ const uint32_t type = transform.getType();
+ transformProto->set_type(type);
+
+ if (type &
+ (ui::Transform::SCALE | ui::Transform::ROTATE | ui::Transform::TRANSLATE |
+ ui::Transform::UNKNOWN)) {
+ transformProto->set_dsdx(transform[0][0]);
+ transformProto->set_dtdx(transform[0][1]);
+ transformProto->set_dsdy(transform[1][0]);
+ transformProto->set_dtdy(transform[1][1]);
+ }
}
void LayerProtoHelper::writeToProto(const sp<GraphicBuffer>& buffer,
- ActiveBufferProto* activeBufferProto) {
- activeBufferProto->set_width(buffer->getWidth());
- activeBufferProto->set_height(buffer->getHeight());
- activeBufferProto->set_stride(buffer->getStride());
- activeBufferProto->set_format(buffer->format);
+ std::function<ActiveBufferProto*()> getActiveBufferProto) {
+ if (buffer->getWidth() != 0 || buffer->getHeight() != 0 || buffer->getStride() != 0 ||
+ buffer->format != 0) {
+ // Use a lambda do avoid writing the object header when the object is empty
+ ActiveBufferProto* activeBufferProto = getActiveBufferProto();
+ activeBufferProto->set_width(buffer->getWidth());
+ activeBufferProto->set_height(buffer->getHeight());
+ activeBufferProto->set_stride(buffer->getStride());
+ activeBufferProto->set_format(buffer->format);
+ }
}
} // namespace surfaceflinger
diff --git a/services/surfaceflinger/LayerProtoHelper.h b/services/surfaceflinger/LayerProtoHelper.h
index 6df5aea..dca9a5e 100644
--- a/services/surfaceflinger/LayerProtoHelper.h
+++ b/services/surfaceflinger/LayerProtoHelper.h
@@ -26,12 +26,18 @@
namespace surfaceflinger {
class LayerProtoHelper {
public:
- static void writeToProto(const Rect& rect, RectProto* rectProto);
- static void writeToProto(const FloatRect& rect, FloatRectProto* rectProto);
- static void writeToProto(const Region& region, RegionProto* regionProto);
- static void writeToProto(const half4 color, ColorProto* colorProto);
+ static void writePositionToProto(const float x, const float y,
+ std::function<PositionProto*()> getPositionProto);
+ static void writeSizeToProto(const uint32_t w, const uint32_t h,
+ std::function<SizeProto*()> getSizeProto);
+ static void writeToProto(const Rect& rect, std::function<RectProto*()> getRectProto);
+ static void writeToProto(const FloatRect& rect,
+ std::function<FloatRectProto*()> getFloatRectProto);
+ static void writeToProto(const Region& region, std::function<RegionProto*()> getRegionProto);
+ static void writeToProto(const half4 color, std::function<ColorProto*()> getColorProto);
static void writeToProto(const ui::Transform& transform, TransformProto* transformProto);
- static void writeToProto(const sp<GraphicBuffer>& buffer, ActiveBufferProto* activeBufferProto);
+ static void writeToProto(const sp<GraphicBuffer>& buffer,
+ std::function<ActiveBufferProto*()> getActiveBufferProto);
};
} // namespace surfaceflinger
diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp
new file mode 100644
index 0000000..bd8548c
--- /dev/null
+++ b/services/surfaceflinger/RegionSamplingThread.cpp
@@ -0,0 +1,255 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+#undef LOG_TAG
+#define LOG_TAG "RegionSamplingThread"
+
+#include "RegionSamplingThread.h"
+
+#include <gui/IRegionSamplingListener.h>
+#include <utils/Trace.h>
+
+#include "DisplayDevice.h"
+#include "Layer.h"
+#include "SurfaceFlinger.h"
+
+namespace android {
+
+template <typename T>
+struct SpHash {
+ size_t operator()(const sp<T>& p) const { return std::hash<T*>()(p.get()); }
+};
+
+RegionSamplingThread::RegionSamplingThread(SurfaceFlinger& flinger) : mFlinger(flinger) {
+ std::lock_guard threadLock(mThreadMutex);
+ mThread = std::thread([this]() { threadMain(); });
+ pthread_setname_np(mThread.native_handle(), "RegionSamplingThread");
+}
+
+RegionSamplingThread::~RegionSamplingThread() {
+ {
+ std::lock_guard lock(mMutex);
+ mRunning = false;
+ mCondition.notify_one();
+ }
+
+ std::lock_guard threadLock(mThreadMutex);
+ if (mThread.joinable()) {
+ mThread.join();
+ }
+}
+
+void RegionSamplingThread::addListener(const Rect& samplingArea, const sp<IBinder>& stopLayerHandle,
+ const sp<IRegionSamplingListener>& listener) {
+ wp<Layer> stopLayer = stopLayerHandle != nullptr
+ ? static_cast<Layer::Handle*>(stopLayerHandle.get())->owner
+ : nullptr;
+
+ sp<IBinder> asBinder = IInterface::asBinder(listener);
+ asBinder->linkToDeath(this);
+ std::lock_guard lock(mMutex);
+ mDescriptors.emplace(wp<IBinder>(asBinder), Descriptor{samplingArea, stopLayer, listener});
+}
+
+void RegionSamplingThread::removeListener(const sp<IRegionSamplingListener>& listener) {
+ std::lock_guard lock(mMutex);
+ mDescriptors.erase(wp<IBinder>(IInterface::asBinder(listener)));
+}
+
+void RegionSamplingThread::sampleNow() {
+ std::lock_guard lock(mMutex);
+ mSampleRequested = true;
+ mCondition.notify_one();
+}
+
+void RegionSamplingThread::binderDied(const wp<IBinder>& who) {
+ std::lock_guard lock(mMutex);
+ mDescriptors.erase(who);
+}
+
+namespace {
+// Using Rec. 709 primaries
+float getLuma(float r, float g, float b) {
+ constexpr auto rec709_red_primary = 0.2126f;
+ constexpr auto rec709_green_primary = 0.7152f;
+ constexpr auto rec709_blue_primary = 0.0722f;
+ return rec709_red_primary * r + rec709_green_primary * g + rec709_blue_primary * b;
+}
+
+float sampleArea(const uint32_t* data, int32_t stride, const Rect& area) {
+ std::array<int32_t, 256> brightnessBuckets = {};
+ const int32_t majoritySampleNum = area.getWidth() * area.getHeight() / 2;
+
+ for (int32_t row = area.top; row < area.bottom; ++row) {
+ const uint32_t* rowBase = data + row * stride;
+ for (int32_t column = area.left; column < area.right; ++column) {
+ uint32_t pixel = rowBase[column];
+ const float r = (pixel & 0xFF) / 255.0f;
+ const float g = ((pixel >> 8) & 0xFF) / 255.0f;
+ const float b = ((pixel >> 16) & 0xFF) / 255.0f;
+ const uint8_t luma = std::round(getLuma(r, g, b) * 255.0f);
+ ++brightnessBuckets[luma];
+ if (brightnessBuckets[luma] > majoritySampleNum) return luma / 255.0f;
+ }
+ }
+
+ int32_t accumulated = 0;
+ size_t bucket = 0;
+ while (bucket++ < brightnessBuckets.size()) {
+ accumulated += brightnessBuckets[bucket];
+ if (accumulated > majoritySampleNum) break;
+ }
+
+ return bucket / 255.0f;
+}
+} // anonymous namespace
+
+std::vector<float> RegionSamplingThread::sampleBuffer(
+ const sp<GraphicBuffer>& buffer, const Point& leftTop,
+ const std::vector<RegionSamplingThread::Descriptor>& descriptors) {
+ void* data_raw = nullptr;
+ buffer->lock(GRALLOC_USAGE_SW_READ_OFTEN, &data_raw);
+ std::shared_ptr<uint32_t> data(reinterpret_cast<uint32_t*>(data_raw),
+ [&buffer](auto) { buffer->unlock(); });
+ if (!data) return {};
+
+ const int32_t stride = buffer->getStride();
+ std::vector<float> lumas(descriptors.size());
+ std::transform(descriptors.begin(), descriptors.end(), lumas.begin(),
+ [&](auto const& descriptor) {
+ return sampleArea(data.get(), stride, descriptor.area - leftTop);
+ });
+ return lumas;
+}
+
+void RegionSamplingThread::captureSample() {
+ ATRACE_CALL();
+
+ if (mDescriptors.empty()) {
+ return;
+ }
+
+ std::vector<RegionSamplingThread::Descriptor> descriptors;
+ Region sampleRegion;
+ for (const auto& [listener, descriptor] : mDescriptors) {
+ sampleRegion.orSelf(descriptor.area);
+ descriptors.emplace_back(descriptor);
+ }
+
+ const Rect sampledArea = sampleRegion.bounds();
+
+ sp<const DisplayDevice> device = mFlinger.getDefaultDisplayDevice();
+ DisplayRenderArea renderArea(device, sampledArea, sampledArea.getWidth(),
+ sampledArea.getHeight(), ui::Dataspace::V0_SRGB,
+ ui::Transform::ROT_0);
+
+ std::unordered_set<sp<IRegionSamplingListener>, SpHash<IRegionSamplingListener>> listeners;
+
+ auto traverseLayers = [&](const LayerVector::Visitor& visitor) {
+ bool stopLayerFound = false;
+ auto filterVisitor = [&](Layer* layer) {
+ // We don't want to capture any layers beyond the stop layer
+ if (stopLayerFound) return;
+
+ // Likewise if we just found a stop layer, set the flag and abort
+ for (const auto& [area, stopLayer, listener] : descriptors) {
+ if (layer == stopLayer.promote().get()) {
+ stopLayerFound = true;
+ return;
+ }
+ }
+
+ // Compute the layer's position on the screen
+ const Rect bounds = Rect(layer->getBounds());
+ const ui::Transform transform = layer->getTransform();
+ constexpr bool roundOutwards = true;
+ Rect transformed = transform.transform(bounds, roundOutwards);
+
+ // If this layer doesn't intersect with the larger sampledArea, skip capturing it
+ Rect ignore;
+ if (!transformed.intersect(sampledArea, &ignore)) return;
+
+ // If the layer doesn't intersect a sampling area, skip capturing it
+ bool intersectsAnyArea = false;
+ for (const auto& [area, stopLayer, listener] : descriptors) {
+ if (transformed.intersect(area, &ignore)) {
+ intersectsAnyArea = true;
+ listeners.insert(listener);
+ }
+ }
+ if (!intersectsAnyArea) return;
+
+ ALOGV("Traversing [%s] [%d, %d, %d, %d]", layer->getName().string(), bounds.left,
+ bounds.top, bounds.right, bounds.bottom);
+ visitor(layer);
+ };
+ mFlinger.traverseLayersInDisplay(device, filterVisitor);
+ };
+
+ const uint32_t usage = GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_HW_RENDER;
+ sp<GraphicBuffer> buffer =
+ new GraphicBuffer(sampledArea.getWidth(), sampledArea.getHeight(),
+ PIXEL_FORMAT_RGBA_8888, 1, usage, "RegionSamplingThread");
+
+ // When calling into SF, we post a message into the SF message queue (so the
+ // screen capture runs on the main thread). This message blocks until the
+ // screenshot is actually captured, but before the capture occurs, the main
+ // thread may perform a normal refresh cycle. At the end of this cycle, it
+ // can request another sample (because layers changed), which triggers a
+ // call into sampleNow. When sampleNow attempts to grab the mutex, we can
+ // deadlock.
+ //
+ // To avoid this, we drop the mutex while we call into SF.
+ mMutex.unlock();
+ mFlinger.captureScreenCommon(renderArea, traverseLayers, buffer, false);
+ mMutex.lock();
+
+ std::vector<Descriptor> activeDescriptors;
+ for (const auto& descriptor : descriptors) {
+ if (listeners.count(descriptor.listener) != 0) {
+ activeDescriptors.emplace_back(descriptor);
+ }
+ }
+
+ ALOGV("Sampling %zu descriptors", activeDescriptors.size());
+ std::vector<float> lumas = sampleBuffer(buffer, sampledArea.leftTop(), activeDescriptors);
+
+ if (lumas.size() != activeDescriptors.size()) {
+ ALOGW("collected %zu median luma values for %zu descriptors", lumas.size(),
+ activeDescriptors.size());
+ return;
+ }
+
+ for (size_t d = 0; d < activeDescriptors.size(); ++d) {
+ activeDescriptors[d].listener->onSampleCollected(lumas[d]);
+ }
+}
+
+void RegionSamplingThread::threadMain() {
+ std::lock_guard lock(mMutex);
+ while (mRunning) {
+ if (mSampleRequested) {
+ mSampleRequested = false;
+ captureSample();
+ }
+ mCondition.wait(mMutex,
+ [this]() REQUIRES(mMutex) { return mSampleRequested || !mRunning; });
+ }
+}
+
+} // namespace android
diff --git a/services/surfaceflinger/RegionSamplingThread.h b/services/surfaceflinger/RegionSamplingThread.h
new file mode 100644
index 0000000..ab06513
--- /dev/null
+++ b/services/surfaceflinger/RegionSamplingThread.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <condition_variable>
+#include <mutex>
+#include <thread>
+#include <unordered_map>
+
+#include <android-base/thread_annotations.h>
+#include <binder/IBinder.h>
+#include <ui/Rect.h>
+#include <utils/StrongPointer.h>
+
+namespace android {
+
+class GraphicBuffer;
+class IRegionSamplingListener;
+class Layer;
+class SurfaceFlinger;
+
+class RegionSamplingThread : public IBinder::DeathRecipient {
+public:
+ explicit RegionSamplingThread(SurfaceFlinger& flinger);
+ ~RegionSamplingThread();
+
+ // Add a listener to receive luma notifications. The luma reported via listener will
+ // report the median luma for the layers under the stopLayerHandle, in the samplingArea region.
+ void addListener(const Rect& samplingArea, const sp<IBinder>& stopLayerHandle,
+ const sp<IRegionSamplingListener>& listener);
+ // Remove the listener to stop receiving median luma notifications.
+ void removeListener(const sp<IRegionSamplingListener>& listener);
+ // Instruct the thread to perform a median luma sampling on the layers.
+ void sampleNow();
+
+private:
+ struct Descriptor {
+ Rect area = Rect::EMPTY_RECT;
+ wp<Layer> stopLayer;
+ sp<IRegionSamplingListener> listener;
+ };
+
+ struct WpHash {
+ size_t operator()(const wp<IBinder>& p) const {
+ return std::hash<IBinder*>()(p.unsafe_get());
+ }
+ };
+ std::vector<float> sampleBuffer(
+ const sp<GraphicBuffer>& buffer, const Point& leftTop,
+ const std::vector<RegionSamplingThread::Descriptor>& descriptors);
+
+ void binderDied(const wp<IBinder>& who) override;
+
+ void captureSample() REQUIRES(mMutex);
+ void threadMain();
+
+ SurfaceFlinger& mFlinger;
+
+ std::mutex mThreadMutex;
+ std::thread mThread GUARDED_BY(mThreadMutex);
+
+ std::mutex mMutex;
+ std::condition_variable_any mCondition;
+ bool mRunning GUARDED_BY(mMutex) = true;
+ bool mSampleRequested GUARDED_BY(mMutex) = false;
+
+ std::unordered_map<wp<IBinder>, Descriptor, WpHash> mDescriptors GUARDED_BY(mMutex);
+};
+
+} // namespace android
diff --git a/services/surfaceflinger/Scheduler/DispSync.cpp b/services/surfaceflinger/Scheduler/DispSync.cpp
index 075e238..665179e 100644
--- a/services/surfaceflinger/Scheduler/DispSync.cpp
+++ b/services/surfaceflinger/Scheduler/DispSync.cpp
@@ -78,6 +78,11 @@
mPeriod = period;
mPhase = phase;
mReferenceTime = referenceTime;
+ if (mTraceDetailedInfo) {
+ ATRACE_INT64("DispSync:Period", mPeriod);
+ ATRACE_INT64("DispSync:Phase", mPhase + mPeriod / 2);
+ ATRACE_INT64("DispSync:Reference Time", mReferenceTime);
+ }
ALOGV("[%s] updateModel: mPeriod = %" PRId64 ", mPhase = %" PRId64
" mReferenceTime = %" PRId64,
mName, ns2us(mPeriod), ns2us(mPhase), ns2us(mReferenceTime));
@@ -580,11 +585,6 @@
ALOGV("[%s] Adjusting mPhase -> %" PRId64, mName, ns2us(mPhase));
}
- if (mTraceDetailedInfo) {
- ATRACE_INT64("DispSync:Period", mPeriod);
- ATRACE_INT64("DispSync:Phase", mPhase + mPeriod / 2);
- }
-
// Artificially inflate the period if requested.
mPeriod += mPeriod * mRefreshSkipCount;
diff --git a/services/surfaceflinger/Scheduler/EventThread.cpp b/services/surfaceflinger/Scheduler/EventThread.cpp
index 4b500f1..78bf7c5 100644
--- a/services/surfaceflinger/Scheduler/EventThread.cpp
+++ b/services/surfaceflinger/Scheduler/EventThread.cpp
@@ -97,6 +97,13 @@
return event;
}
+DisplayEventReceiver::Event makeConfigChanged(uint32_t displayId, int32_t configId) {
+ DisplayEventReceiver::Event event;
+ event.header = {DisplayEventReceiver::DISPLAY_EVENT_CONFIG_CHANGED, displayId, systemTime()};
+ event.config.configId = configId;
+ return event;
+}
+
} // namespace
EventThreadConnection::EventThreadConnection(EventThread* eventThread,
@@ -307,6 +314,13 @@
mCondition.notify_all();
}
+void EventThread::onConfigChanged(PhysicalDisplayId displayId, int32_t configId) {
+ std::lock_guard<std::mutex> lock(mMutex);
+
+ mPendingEvents.push_back(makeConfigChanged(displayId, configId));
+ mCondition.notify_all();
+}
+
void EventThread::threadMain(std::unique_lock<std::mutex>& lock) {
DisplayEventConsumers consumers;
@@ -404,6 +418,7 @@
const sp<EventThreadConnection>& connection) const {
switch (event.header.type) {
case DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG:
+ case DisplayEventReceiver::DISPLAY_EVENT_CONFIG_CHANGED:
return true;
case DisplayEventReceiver::DISPLAY_EVENT_VSYNC:
diff --git a/services/surfaceflinger/Scheduler/EventThread.h b/services/surfaceflinger/Scheduler/EventThread.h
index 3411438..d5e3349 100644
--- a/services/surfaceflinger/Scheduler/EventThread.h
+++ b/services/surfaceflinger/Scheduler/EventThread.h
@@ -112,6 +112,9 @@
virtual void onHotplugReceived(PhysicalDisplayId displayId, bool connected) = 0;
+ // called when SF changes the active config and apps needs to be notified about the change
+ virtual void onConfigChanged(PhysicalDisplayId displayId, int32_t configId) = 0;
+
virtual void dump(std::string& result) const = 0;
virtual void setPhaseOffset(nsecs_t phaseOffset) = 0;
@@ -153,6 +156,8 @@
void onHotplugReceived(PhysicalDisplayId displayId, bool connected) override;
+ void onConfigChanged(PhysicalDisplayId displayId, int32_t configId) override;
+
void dump(std::string& result) const override;
void setPhaseOffset(nsecs_t phaseOffset) override;
diff --git a/services/surfaceflinger/Scheduler/PhaseOffsets.cpp b/services/surfaceflinger/Scheduler/PhaseOffsets.cpp
index ab1f460..7e2b03d 100644
--- a/services/surfaceflinger/Scheduler/PhaseOffsets.cpp
+++ b/services/surfaceflinger/Scheduler/PhaseOffsets.cpp
@@ -76,13 +76,13 @@
mDefaultRefreshRateOffsets.late = {sfVsyncPhaseOffsetNs, vsyncPhaseOffsetNs};
mHighRefreshRateOffsets.early = {highFpsEarlySfOffsetNs != -1 ? highFpsEarlySfOffsetNs
- : highFpsLateAppOffsetNs,
+ : highFpsLateSfOffsetNs,
highFpsEarlyAppOffsetNs != -1 ? highFpsEarlyAppOffsetNs
- : highFpsLateSfOffsetNs};
+ : highFpsLateAppOffsetNs};
mHighRefreshRateOffsets.earlyGl = {highFpsEarlyGlSfOffsetNs != -1 ? highFpsEarlyGlSfOffsetNs
- : highFpsLateAppOffsetNs,
+ : highFpsLateSfOffsetNs,
highFpsEarlyGlAppOffsetNs != -1 ? highFpsEarlyGlAppOffsetNs
- : highFpsLateSfOffsetNs};
+ : highFpsLateAppOffsetNs};
mHighRefreshRateOffsets.late = {highFpsLateSfOffsetNs, highFpsLateAppOffsetNs};
}
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 8ed3958..5b4af4a 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -26,7 +26,6 @@
#include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
#include <android/hardware/configstore/1.1/ISurfaceFlingerConfigs.h>
-#include <android/hardware/configstore/1.2/ISurfaceFlingerConfigs.h>
#include <configstore/Utils.h>
#include <cutils/properties.h>
#include <ui/DisplayStatInfo.h>
@@ -153,6 +152,12 @@
mConnections[handle->id]->thread->onScreenReleased();
}
+void Scheduler::onConfigChanged(const sp<ConnectionHandle>& handle, PhysicalDisplayId displayId,
+ int32_t configId) {
+ RETURN_IF_INVALID();
+ mConnections[handle->id]->thread->onConfigChanged(displayId, configId);
+}
+
void Scheduler::dump(const sp<Scheduler::ConnectionHandle>& handle, std::string& result) const {
RETURN_IF_INVALID();
mConnections.at(handle->id)->thread->dump(result);
@@ -299,6 +304,7 @@
}
void Scheduler::incrementFrameCounter() {
+ std::lock_guard<std::mutex> lock(mLayerHistoryLock);
mLayerHistory.incrementCounter();
}
@@ -323,25 +329,28 @@
void Scheduler::determineLayerTimestampStats(const std::string layerName,
const nsecs_t framePresentTime) {
- mLayerHistory.insert(layerName, framePresentTime);
std::vector<int64_t> differencesMs;
-
- // Traverse through the layer history, and determine the differences in present times.
- nsecs_t newestPresentTime = framePresentTime;
std::string differencesText = "";
- for (int i = 1; i < mLayerHistory.getSize(); i++) {
- std::unordered_map<std::string, nsecs_t> layers = mLayerHistory.get(i);
- for (auto layer : layers) {
- if (layer.first != layerName) {
- continue;
+ {
+ std::lock_guard<std::mutex> lock(mLayerHistoryLock);
+ mLayerHistory.insert(layerName, framePresentTime);
+
+ // Traverse through the layer history, and determine the differences in present times.
+ nsecs_t newestPresentTime = framePresentTime;
+ for (int i = 1; i < mLayerHistory.getSize(); i++) {
+ std::unordered_map<std::string, nsecs_t> layers = mLayerHistory.get(i);
+ for (auto layer : layers) {
+ if (layer.first != layerName) {
+ continue;
+ }
+ int64_t differenceMs = (newestPresentTime - layer.second) / 1000000;
+ // Dismiss noise.
+ if (differenceMs > 10 && differenceMs < 60) {
+ differencesMs.push_back(differenceMs);
+ }
+ IF_ALOGV() { differencesText += (std::to_string(differenceMs) + " "); }
+ newestPresentTime = layer.second;
}
- int64_t differenceMs = (newestPresentTime - layer.second) / 1000000;
- // Dismiss noise.
- if (differenceMs > 10 && differenceMs < 60) {
- differencesMs.push_back(differenceMs);
- }
- IF_ALOGV() { differencesText += (std::to_string(differenceMs) + " "); }
- newestPresentTime = layer.second;
}
}
ALOGV("Layer %s timestamp intervals: %s", layerName.c_str(), differencesText.c_str());
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index ce5c87e..7f113e7 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -105,6 +105,10 @@
// Should be called before the screen is turned off.
void onScreenReleased(const sp<ConnectionHandle>& handle);
+ // Should be called when display config changed
+ void onConfigChanged(const sp<ConnectionHandle>& handle, PhysicalDisplayId displayId,
+ int32_t configId);
+
// Should be called when dumpsys command is received.
void dump(const sp<ConnectionHandle>& handle, std::string& result) const;
@@ -201,7 +205,10 @@
std::array<int64_t, scheduler::ARRAY_SIZE> mTimeDifferences{};
size_t mCounter = 0;
- LayerHistory mLayerHistory;
+ // DetermineLayerTimestampStats is called from BufferQueueLayer::onFrameAvailable which
+ // can run on any thread, and cause failure.
+ std::mutex mLayerHistoryLock;
+ LayerHistory mLayerHistory GUARDED_BY(mLayerHistoryLock);
// Timer that records time between requests for next vsync. If the time is higher than a given
// interval, a callback is fired. Set this variable to >0 to use this feature.
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index e1e3dfb..128ebf9 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -62,7 +62,6 @@
#include <ui/GraphicBufferAllocator.h>
#include <ui/PixelFormat.h>
#include <ui/UiConfig.h>
-#include <utils/CallStack.h>
#include <utils/StopWatch.h>
#include <utils/String16.h>
#include <utils/String8.h>
@@ -110,7 +109,6 @@
#include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
#include <android/hardware/configstore/1.1/ISurfaceFlingerConfigs.h>
-#include <android/hardware/configstore/1.2/ISurfaceFlingerConfigs.h>
#include <android/hardware/configstore/1.1/types.h>
#include <configstore/Utils.h>
@@ -203,19 +201,6 @@
const String16 sReadFramebuffer("android.permission.READ_FRAME_BUFFER");
const String16 sDump("android.permission.DUMP");
-constexpr float kSrgbRedX = 0.4123f;
-constexpr float kSrgbRedY = 0.2126f;
-constexpr float kSrgbRedZ = 0.0193f;
-constexpr float kSrgbGreenX = 0.3576f;
-constexpr float kSrgbGreenY = 0.7152f;
-constexpr float kSrgbGreenZ = 0.1192f;
-constexpr float kSrgbBlueX = 0.1805f;
-constexpr float kSrgbBlueY = 0.0722f;
-constexpr float kSrgbBlueZ = 0.9506f;
-constexpr float kSrgbWhiteX = 0.9505f;
-constexpr float kSrgbWhiteY = 1.0000f;
-constexpr float kSrgbWhiteZ = 1.0891f;
-
constexpr float kDefaultRefreshRate = 60.f;
constexpr float kPerformanceRefreshRate = 90.f;
@@ -288,6 +273,7 @@
mDebugRegion(0),
mDebugDisableHWC(0),
mDebugDisableTransformHint(0),
+ mDebugEnableProtectedContent(false),
mDebugInTransaction(0),
mLastTransactionTime(0),
mForceFullDamage(false),
@@ -297,7 +283,9 @@
mNumLayers(0),
mVrFlingerRequestsDisplay(false),
mMainThreadId(std::this_thread::get_id()),
- mCompositionEngine{getFactory().createCompositionEngine()} {}
+ mCompositionEngine{getFactory().createCompositionEngine()} {
+ mSetInputWindowsListener = new SetInputWindowsListener(this);
+}
SurfaceFlinger::SurfaceFlinger(surfaceflinger::Factory& factory)
: SurfaceFlinger(factory, SkipInitialization) {
@@ -351,15 +339,7 @@
}
ALOGV("Primary Display Orientation is set to %2d.", SurfaceFlinger::primaryDisplayOrientation);
- auto surfaceFlingerConfigsServiceV1_2 = V1_2::ISurfaceFlingerConfigs::getService();
- if (surfaceFlingerConfigsServiceV1_2) {
- surfaceFlingerConfigsServiceV1_2->getDisplayNativePrimaries(
- [&](auto tmpPrimaries) {
- memcpy(&mInternalDisplayPrimaries, &tmpPrimaries, sizeof(ui::DisplayPrimaries));
- });
- } else {
- initDefaultDisplayNativePrimaries();
- }
+ mInternalDisplayPrimaries = sysprop::getDisplayNativePrimaries();
// debugging stuff...
char value[PROPERTY_VALUE_MAX];
@@ -396,6 +376,12 @@
property_get("debug.sf.use_90Hz", value, "0");
mUse90Hz = atoi(value);
+ property_get("debug.sf.use_smart_90_for_video", value, "0");
+ mUseSmart90ForVideo = atoi(value);
+
+ property_get("debug.sf.luma_sampling", value, "1");
+ mLumaSampling = atoi(value);
+
const auto [early, gl, late] = mPhaseOffsets->getCurrentOffsets();
mVsyncModulator.setPhaseOffsets(early, gl, late);
@@ -576,9 +562,24 @@
LOG_EVENT_LONG(LOGTAG_SF_STOP_BOOTANIM,
ns2ms(systemTime(SYSTEM_TIME_MONOTONIC)));
- postMessageAsync(new LambdaMessage([this] {
+ postMessageAsync(new LambdaMessage([this]() NO_THREAD_SAFETY_ANALYSIS {
readPersistentProperties();
mBootStage = BootStage::FINISHED;
+
+ // TODO(b/122905403): Once the display policy is completely integrated, this flag should go
+ // away and it should be controlled by flipping the switch in setting. The switch in
+ // settings should only be available to P19 devices, if they are opted into 90Hz fishfood.
+ // The boot must be complete before we can set the active config.
+
+ if (mUse90Hz) {
+ mPhaseOffsets->setRefreshRateType(
+ scheduler::RefreshRateConfigs::RefreshRateType::PERFORMANCE);
+ setRefreshRateTo(RefreshRateType::PERFORMANCE, ConfigEvent::None);
+ } else {
+ mPhaseOffsets->setRefreshRateType(
+ scheduler::RefreshRateConfigs::RefreshRateType::DEFAULT);
+ setRefreshRateTo(RefreshRateType::DEFAULT, ConfigEvent::None);
+ }
}));
}
@@ -635,11 +636,6 @@
mVsyncModulator.setSchedulerAndHandles(mScheduler.get(), mAppConnectionHandle.get(),
mSfConnectionHandle.get());
- if (mUse90Hz) {
- mPhaseOffsets->setRefreshRateType(
- scheduler::RefreshRateConfigs::RefreshRateType::PERFORMANCE);
- }
-
// Get a RenderEngine for the given display / config (can't fail)
int32_t renderEngineFeature = 0;
renderEngineFeature |= (useColorManagement ?
@@ -648,9 +644,10 @@
renderengine::RenderEngine::USE_HIGH_PRIORITY_CONTEXT : 0);
// TODO(b/77156734): We need to stop casting and use HAL types when possible.
+ // Sending maxFrameBufferAcquiredBuffers as the cache size is tightly tuned to single-display.
mCompositionEngine->setRenderEngine(
renderengine::RenderEngine::create(static_cast<int32_t>(defaultCompositionPixelFormat),
- renderEngineFeature));
+ renderEngineFeature, maxFrameBufferAcquiredBuffers));
LOG_ALWAYS_FATAL_IF(mVrFlingerRequestsDisplay,
"Starting with vr flinger active is not currently supported.");
@@ -705,15 +702,16 @@
ALOGE("Run StartPropertySetThread failed!");
}
- mScheduler->setExpiredIdleTimerCallback([this] {
- Mutex::Autolock lock(mStateLock);
- setRefreshRateTo(RefreshRateType::DEFAULT);
- });
- mScheduler->setResetIdleTimerCallback([this] {
- Mutex::Autolock lock(mStateLock);
- setRefreshRateTo(RefreshRateType::PERFORMANCE);
- });
-
+ if (mUse90Hz) {
+ mScheduler->setExpiredIdleTimerCallback([this] {
+ Mutex::Autolock lock(mStateLock);
+ setRefreshRateTo(RefreshRateType::DEFAULT, ConfigEvent::None);
+ });
+ mScheduler->setResetIdleTimerCallback([this] {
+ Mutex::Autolock lock(mStateLock);
+ setRefreshRateTo(RefreshRateType::PERFORMANCE, ConfigEvent::None);
+ });
+ }
mRefreshRateStats = std::make_unique<scheduler::RefreshRateStats>(getHwComposer().getConfigs(
*display->getId()),
mTimeStats);
@@ -919,7 +917,8 @@
return display->getActiveConfig();
}
-void SurfaceFlinger::setDesiredActiveConfig(const sp<IBinder>& displayToken, int mode) {
+void SurfaceFlinger::setDesiredActiveConfig(const sp<IBinder>& displayToken, int mode,
+ ConfigEvent event) {
ATRACE_CALL();
Vector<DisplayInfo> configs;
@@ -948,9 +947,11 @@
}
// Don't check against the current mode yet. Worst case we set the desired
- // config twice.
+ // config twice. However event generation config might have changed so we need to update it
+ // accordingly
std::lock_guard<std::mutex> lock(mActiveConfigLock);
- mDesiredActiveConfig = ActiveConfigInfo{mode, displayToken};
+ const ConfigEvent desiredConfig = mDesiredActiveConfig.event | event;
+ mDesiredActiveConfig = ActiveConfigInfo{mode, displayToken, desiredConfig};
if (!mDesiredActiveConfigChanged) {
// This is the first time we set the desired
@@ -965,9 +966,11 @@
status_t SurfaceFlinger::setActiveConfig(const sp<IBinder>& displayToken, int mode) {
ATRACE_CALL();
- postMessageSync(new LambdaMessage(
- [&]() NO_THREAD_SAFETY_ANALYSIS { setDesiredActiveConfig(displayToken, mode); }));
- return NO_ERROR;
+
+ std::vector<int32_t> allowedConfig;
+ allowedConfig.push_back(mode);
+
+ return setAllowedDisplayConfigs(displayToken, allowedConfig);
}
void SurfaceFlinger::setActiveConfigInternal() {
@@ -981,9 +984,14 @@
mScheduler->resyncToHardwareVsync(true, getVsyncPeriod());
ATRACE_INT("ActiveConfigMode", mUpcomingActiveConfig.configId);
+ if (mUpcomingActiveConfig.event != ConfigEvent::None) {
+ mScheduler->onConfigChanged(mAppConnectionHandle, display->getId()->value,
+ mUpcomingActiveConfig.configId);
+ }
}
bool SurfaceFlinger::performSetActiveConfig() NO_THREAD_SAFETY_ANALYSIS {
+ ATRACE_CALL();
// we may be in the process of changing the active state
if (mWaitForNextInvalidate) {
mWaitForNextInvalidate = false;
@@ -1028,7 +1036,14 @@
return false;
}
- // Desired active config was set, it is different than the config currently in use. Notify HWC.
+ // Desired active config was set, it is different than the config currently in use, however
+ // allowed configs might have change by the time we process the refresh.
+ // Make sure the desired config is still allowed
+ if (!isConfigAllowed(*display->getId(), desiredActiveConfig.configId)) {
+ std::lock_guard<std::mutex> lock(mActiveConfigLock);
+ mDesiredActiveConfig.configId = display->getActiveConfig();
+ return false;
+ }
mUpcomingActiveConfig = desiredActiveConfig;
const auto displayId = display->getId();
LOG_ALWAYS_FATAL_IF(!displayId);
@@ -1291,17 +1306,23 @@
return NO_ERROR;
}
-status_t SurfaceFlinger::addRegionSamplingListener(
- const Rect& /*samplingArea*/, const sp<IBinder>& /*stopLayerHandle*/,
- const sp<IRegionSamplingListener>& /*listener*/) {
+status_t SurfaceFlinger::addRegionSamplingListener(const Rect& samplingArea,
+ const sp<IBinder>& stopLayerHandle,
+ const sp<IRegionSamplingListener>& listener) {
+ if (!listener || samplingArea == Rect::INVALID_RECT) {
+ return BAD_VALUE;
+ }
+ mRegionSamplingThread->addListener(samplingArea, stopLayerHandle, listener);
return NO_ERROR;
}
-status_t SurfaceFlinger::removeRegionSamplingListener(
- const sp<IRegionSamplingListener>& /*listener*/) {
+status_t SurfaceFlinger::removeRegionSamplingListener(const sp<IRegionSamplingListener>& listener) {
+ if (!listener) {
+ return BAD_VALUE;
+ }
+ mRegionSamplingThread->removeListener(listener);
return NO_ERROR;
}
-
// ----------------------------------------------------------------------------
sp<IDisplayEventConnection> SurfaceFlinger::createDisplayEventConnection(
@@ -1393,7 +1414,18 @@
*compositorTiming = getBE().mCompositorTiming;
}
-void SurfaceFlinger::setRefreshRateTo(RefreshRateType refreshRate) {
+bool SurfaceFlinger::isConfigAllowed(const DisplayId& displayId, int32_t config) {
+ std::lock_guard lock(mAllowedConfigsLock);
+
+ // if allowed configs are not set yet for this display, every config is considered allowed
+ if (mAllowedConfigs.find(displayId) == mAllowedConfigs.end()) {
+ return true;
+ }
+
+ return mAllowedConfigs[displayId]->isConfigAllowed(config);
+}
+
+void SurfaceFlinger::setRefreshRateTo(RefreshRateType refreshRate, ConfigEvent event) {
mPhaseOffsets->setRefreshRateType(refreshRate);
const auto [early, gl, late] = mPhaseOffsets->getCurrentOffsets();
@@ -1428,6 +1460,11 @@
auto configs = getHwComposer().getConfigs(*displayId);
for (int i = 0; i < configs.size(); i++) {
+ if (!isConfigAllowed(*displayId, i)) {
+ ALOGV("Skipping config %d as it is not part of allowed configs", i);
+ continue;
+ }
+
const nsecs_t vsyncPeriod = configs.at(i)->getVsyncPeriod();
if (vsyncPeriod == 0) {
continue;
@@ -1436,7 +1473,7 @@
// TODO(b/113612090): There should be a better way at determining which config
// has the right refresh rate.
if (std::abs(fps - newFps) <= 1) {
- setDesiredActiveConfig(getInternalDisplayTokenLocked(), i);
+ setDesiredActiveConfig(getInternalDisplayTokenLocked(), i, event);
}
}
}
@@ -1496,6 +1533,7 @@
}
void SurfaceFlinger::updateVrFlinger() {
+ ATRACE_CALL();
if (!mVrFlinger)
return;
bool vrFlingerRequestsDisplay = mVrFlingerRequestsDisplay;
@@ -1585,15 +1623,21 @@
break;
}
- // This call is made each time SF wakes up and creates a new frame.
- mScheduler->incrementFrameCounter();
-
- bool frameMissed = !mHadClientComposition && mPreviousPresentFence != Fence::NO_FENCE &&
+ if (mUse90Hz && mUseSmart90ForVideo) {
+ // This call is made each time SF wakes up and creates a new frame. It is part
+ // of video detection feature.
+ mScheduler->incrementFrameCounter();
+ }
+ bool frameMissed = mPreviousPresentFence != Fence::NO_FENCE &&
(mPreviousPresentFence->getStatus() == Fence::Status::Unsignaled);
- mFrameMissedCount += frameMissed;
- ATRACE_INT("FrameMissed", static_cast<int>(frameMissed));
+ bool hwcFrameMissed = !mHadClientComposition && frameMissed;
if (frameMissed) {
+ ATRACE_INT("FrameMissed", static_cast<int>(frameMissed));
+ mFrameMissedCount++;
mTimeStats->incrementMissedFrames();
+ }
+ // For now, only propagate backpressure when missing a hwc frame.
+ if (hwcFrameMissed) {
if (mPropagateBackpressure) {
signalLayerUpdate();
break;
@@ -1628,6 +1672,7 @@
}
bool SurfaceFlinger::handleMessageTransaction() {
+ ATRACE_CALL();
uint32_t transactionFlags = peekTransactionFlags();
// Apply any ready transactions in the queues if there are still transactions that have not been
@@ -1680,8 +1725,6 @@
mVsyncModulator.onRefreshed(mHadClientComposition);
- getBE().mEndOfFrameCompositionInfo = std::move(getBE().mCompositionInfo);
-
mLayersWithQueuedFrames.clear();
}
@@ -1794,12 +1837,9 @@
for (const auto& [token, displayDevice] : mDisplays) {
auto display = displayDevice->getCompositionDisplay();
for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) {
- const auto displayId = display->getId();
auto& layerState = layer->getCompositionLayer()->editState().frontEnd;
layerState.compositionType = static_cast<Hwc2::IComposerClient::Composition>(
layer->getCompositionType(displayDevice));
- layer->getBE().compositionInfo.hwc.displayId = *displayId;
- getBE().mCompositionInfo[token].push_back(layer->getBE().compositionInfo);
}
}
}
@@ -1931,78 +1971,22 @@
getBE().mCompositorTiming.presentLatency = snappedCompositeToPresentLatency;
}
-// debug patch for b/119477596 - add stack guards to catch stack
-// corruptions and disable clang optimizations.
-// The code below is temporary and planned to be removed once stack
-// corruptions are found.
-#pragma clang optimize off
-class StackGuard {
-public:
- StackGuard(const char* name, const char* func, int line) {
- guarders.reserve(MIN_CAPACITY);
- guarders.push_back({this, name, func, line});
- validate();
- }
- ~StackGuard() {
- for (auto i = guarders.end() - 1; i >= guarders.begin(); --i) {
- if (i->guard == this) {
- guarders.erase(i);
- break;
- }
- }
- }
-
- static void validate() {
- for (const auto& guard : guarders) {
- if (guard.guard->cookie != COOKIE_VALUE) {
- ALOGE("%s:%d: Stack corruption detected at %s", guard.func, guard.line, guard.name);
- CallStack stack(LOG_TAG);
- abort();
- }
- }
- }
-
-private:
- uint64_t cookie = COOKIE_VALUE;
- static constexpr uint64_t COOKIE_VALUE = 0xc0febebedeadbeef;
- static constexpr size_t MIN_CAPACITY = 16;
-
- struct GuarderElement {
- StackGuard* guard;
- const char* name;
- const char* func;
- int line;
- };
-
- static std::vector<GuarderElement> guarders;
-};
-std::vector<StackGuard::GuarderElement> StackGuard::guarders;
-
-#define DEFINE_STACK_GUARD(__n) StackGuard __n##StackGuard(#__n, __FUNCTION__, __LINE__);
-
-#define ASSERT_ON_STACK_GUARD() StackGuard::validate();
void SurfaceFlinger::postComposition()
{
- DEFINE_STACK_GUARD(begin);
ATRACE_CALL();
ALOGV("postComposition");
// Release any buffers which were replaced this frame
nsecs_t dequeueReadyTime = systemTime();
- DEFINE_STACK_GUARD(dequeueReadyTime);
for (auto& layer : mLayersWithQueuedFrames) {
layer->releasePendingBuffer(dequeueReadyTime);
}
- ASSERT_ON_STACK_GUARD();
// |mStateLock| not needed as we are on the main thread
const auto displayDevice = getDefaultDisplayDeviceLocked();
- DEFINE_STACK_GUARD(displayDevice);
getBE().mGlCompositionDoneTimeline.updateSignalTimes();
std::shared_ptr<FenceTime> glCompositionDoneFenceTime;
- DEFINE_STACK_GUARD(glCompositionDoneFenceTime);
-
if (displayDevice && getHwComposer().hasClientComposition(displayDevice->getId())) {
glCompositionDoneFenceTime =
std::make_shared<FenceTime>(displayDevice->getCompositionDisplay()
@@ -2013,52 +1997,37 @@
glCompositionDoneFenceTime = FenceTime::NO_FENCE;
}
- ASSERT_ON_STACK_GUARD();
-
getBE().mDisplayTimeline.updateSignalTimes();
mPreviousPresentFence = displayDevice ? getHwComposer().getPresentFence(*displayDevice->getId())
: Fence::NO_FENCE;
auto presentFenceTime = std::make_shared<FenceTime>(mPreviousPresentFence);
- DEFINE_STACK_GUARD(presentFenceTime);
getBE().mDisplayTimeline.push(presentFenceTime);
DisplayStatInfo stats;
- DEFINE_STACK_GUARD(stats);
mScheduler->getDisplayStatInfo(&stats);
- ASSERT_ON_STACK_GUARD();
-
// We use the mRefreshStartTime which might be sampled a little later than
// when we started doing work for this frame, but that should be okay
// since updateCompositorTiming has snapping logic.
updateCompositorTiming(stats, mRefreshStartTime, presentFenceTime);
CompositorTiming compositorTiming;
- DEFINE_STACK_GUARD(compositorTiming);
-
{
std::lock_guard<std::mutex> lock(getBE().mCompositorTimingLock);
- DEFINE_STACK_GUARD(lock);
compositorTiming = getBE().mCompositorTiming;
-
- ASSERT_ON_STACK_GUARD();
}
mDrawingState.traverseInZOrder([&](Layer* layer) {
bool frameLatched =
layer->onPostComposition(displayDevice->getId(), glCompositionDoneFenceTime,
presentFenceTime, compositorTiming);
- DEFINE_STACK_GUARD(frameLatched);
if (frameLatched) {
recordBufferingStats(layer->getName().string(),
layer->getOccupancyHistory(false));
}
- ASSERT_ON_STACK_GUARD();
});
if (presentFenceTime->isValid()) {
- ASSERT_ON_STACK_GUARD();
mScheduler->addPresentFence(presentFenceTime);
- ASSERT_ON_STACK_GUARD();
}
if (!hasSyncFramework) {
@@ -2068,88 +2037,67 @@
}
}
- ASSERT_ON_STACK_GUARD();
-
if (mAnimCompositionPending) {
mAnimCompositionPending = false;
if (presentFenceTime->isValid()) {
mAnimFrameTracker.setActualPresentFence(
std::move(presentFenceTime));
-
- ASSERT_ON_STACK_GUARD();
} else if (displayDevice && getHwComposer().isConnected(*displayDevice->getId())) {
// The HWC doesn't support present fences, so use the refresh
// timestamp instead.
const nsecs_t presentTime =
getHwComposer().getRefreshTimestamp(*displayDevice->getId());
- DEFINE_STACK_GUARD(presentTime);
-
mAnimFrameTracker.setActualPresentTime(presentTime);
- ASSERT_ON_STACK_GUARD();
}
mAnimFrameTracker.advanceFrame();
}
- ASSERT_ON_STACK_GUARD();
-
mTimeStats->incrementTotalFrames();
if (mHadClientComposition) {
mTimeStats->incrementClientCompositionFrames();
}
- ASSERT_ON_STACK_GUARD();
-
mTimeStats->setPresentFenceGlobal(presentFenceTime);
- ASSERT_ON_STACK_GUARD();
-
if (displayDevice && getHwComposer().isConnected(*displayDevice->getId()) &&
!displayDevice->isPoweredOn()) {
return;
}
nsecs_t currentTime = systemTime();
- DEFINE_STACK_GUARD(currentTime);
if (mHasPoweredOff) {
mHasPoweredOff = false;
} else {
nsecs_t elapsedTime = currentTime - getBE().mLastSwapTime;
- DEFINE_STACK_GUARD(elapsedTime);
size_t numPeriods = static_cast<size_t>(elapsedTime / stats.vsyncPeriod);
- DEFINE_STACK_GUARD(numPeriods);
if (numPeriods < SurfaceFlingerBE::NUM_BUCKETS - 1) {
getBE().mFrameBuckets[numPeriods] += elapsedTime;
} else {
getBE().mFrameBuckets[SurfaceFlingerBE::NUM_BUCKETS - 1] += elapsedTime;
}
getBE().mTotalTime += elapsedTime;
-
- ASSERT_ON_STACK_GUARD();
}
getBE().mLastSwapTime = currentTime;
- ASSERT_ON_STACK_GUARD();
{
std::lock_guard lock(mTexturePoolMutex);
- DEFINE_STACK_GUARD(lock);
const size_t refillCount = mTexturePoolSize - mTexturePool.size();
- DEFINE_STACK_GUARD(refillCount);
if (refillCount > 0) {
const size_t offset = mTexturePool.size();
mTexturePool.resize(mTexturePoolSize);
getRenderEngine().genTextures(refillCount, mTexturePool.data() + offset);
ATRACE_INT("TexturePoolSize", mTexturePool.size());
}
- ASSERT_ON_STACK_GUARD();
}
mTransactionCompletedThread.addPresentFence(mPreviousPresentFence);
mTransactionCompletedThread.sendCallbacks();
- ASSERT_ON_STACK_GUARD();
+ if (mLumaSampling) {
+ mRegionSamplingThread->sampleNow();
+ }
}
-#pragma clang optimize on // b/119477596
void SurfaceFlinger::computeLayerBounds() {
for (const auto& pair : mDisplays) {
@@ -2170,17 +2118,6 @@
ATRACE_CALL();
ALOGV("rebuildLayerStacks");
- // We need to clear these out now as these may be holding on to a
- // HWC2::Layer reference at the same time as the LayerBE::HWCInfo structure
- // also holds a reference. When the set of visible layers is recomputed,
- // some layers may be destroyed if the only thing keeping them alive was
- // that list of visible layers associated with each display. The layer
- // destruction code asserts that the HWC2::Layer is properly destroyed, but
- // that doesn't happen if SurfaceFlingerBE::mCompositionInfo keeps it alive.
- for (const auto& [token, display] : mDisplays) {
- getBE().mCompositionInfo[token].clear();
- }
-
// rebuild the visible layer list per screen
if (CC_UNLIKELY(mVisibleRegionsDirty)) {
ATRACE_NAME("rebuildLayerStacks VR Dirty");
@@ -2454,16 +2391,19 @@
getHwComposer().presentAndGetReleaseFences(*displayId);
}
display->getRenderSurface()->onPresentDisplayCompleted();
- for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) {
+ for (auto& layer : display->getOutputLayersOrderedByZ()) {
sp<Fence> releaseFence = Fence::NO_FENCE;
+ bool usedClientComposition = true;
// The layer buffer from the previous frame (if any) is released
// by HWC only when the release fence from this frame (if any) is
// signaled. Always get the release fence from HWC first.
- if (displayId && layer->hasHwcLayer(displayDevice)) {
+ if (layer->getState().hwc) {
+ const auto& hwcState = *layer->getState().hwc;
releaseFence =
- getHwComposer().getLayerReleaseFence(*displayId,
- layer->getHwcLayer(displayDevice));
+ getHwComposer().getLayerReleaseFence(*displayId, hwcState.hwcLayer.get());
+ usedClientComposition =
+ hwcState.hwcCompositionType == Hwc2::IComposerClient::Composition::CLIENT;
}
// If the layer was client composited in the previous frame, we
@@ -2471,14 +2411,13 @@
// Since we do not track that, always merge with the current
// client target acquire fence when it is available, even though
// this is suboptimal.
- if (layer->getCompositionType(displayDevice) ==
- Hwc2::IComposerClient::Composition::CLIENT) {
+ if (usedClientComposition) {
releaseFence =
Fence::merge("LayerRelease", releaseFence,
display->getRenderSurface()->getClientTargetAcquireFence());
}
- layer->getBE().onLayerDisplayed(releaseFence);
+ layer->getLayerFE().onLayerDisplayed(releaseFence);
}
// We've got a list of layers needing fences, that are disjoint with
@@ -2488,7 +2427,7 @@
sp<Fence> presentFence =
displayId ? getHwComposer().getPresentFence(*displayId) : Fence::NO_FENCE;
for (auto& layer : displayDevice->getLayersNeedingFences()) {
- layer->getBE().onLayerDisplayed(presentFence);
+ layer->getCompositionLayer()->getLayerFE()->onLayerDisplayed(presentFence);
}
}
@@ -2933,6 +2872,10 @@
if (mVisibleRegionsDirty || mInputInfoChanged) {
mInputInfoChanged = false;
updateInputWindowInfo();
+ } else if (mInputWindowCommands.syncInputWindows) {
+ // If the caller requested to sync input windows, but there are no
+ // changes to input windows, notify immediately.
+ setInputWindowsFinished();
}
executeInputWindowCommands();
@@ -2948,7 +2891,10 @@
inputHandles.add(layer->fillInputInfo());
}
});
- mInputFlinger->setInputWindows(inputHandles);
+
+ mInputFlinger->setInputWindows(inputHandles,
+ mInputWindowCommands.syncInputWindows ? mSetInputWindowsListener
+ : nullptr);
}
void SurfaceFlinger::commitInputWindowCommands() {
@@ -3172,21 +3118,6 @@
}
}
-void SurfaceFlinger::initDefaultDisplayNativePrimaries() {
- mInternalDisplayPrimaries.red.X = kSrgbRedX;
- mInternalDisplayPrimaries.red.Y = kSrgbRedY;
- mInternalDisplayPrimaries.red.Z = kSrgbRedZ;
- mInternalDisplayPrimaries.green.X = kSrgbGreenX;
- mInternalDisplayPrimaries.green.Y = kSrgbGreenY;
- mInternalDisplayPrimaries.green.Z = kSrgbGreenZ;
- mInternalDisplayPrimaries.blue.X = kSrgbBlueX;
- mInternalDisplayPrimaries.blue.Y = kSrgbBlueY;
- mInternalDisplayPrimaries.blue.Z = kSrgbBlueZ;
- mInternalDisplayPrimaries.white.X = kSrgbWhiteX;
- mInternalDisplayPrimaries.white.Y = kSrgbWhiteY;
- mInternalDisplayPrimaries.white.Z = kSrgbWhiteZ;
-}
-
bool SurfaceFlinger::handlePageFlip()
{
ALOGV("handlePageFlip");
@@ -3289,6 +3220,9 @@
auto display = displayDevice->getCompositionDisplay();
const auto& displayState = display->getState();
const auto displayId = display->getId();
+ auto& renderEngine = getRenderEngine();
+ const bool supportProtectedContent =
+ mDebugEnableProtectedContent && renderEngine.supportsProtectedContent();
const Region bounds(displayState.bounds);
const DisplayRenderArea renderArea(displayDevice);
@@ -3301,11 +3235,27 @@
renderengine::DisplaySettings clientCompositionDisplay;
std::vector<renderengine::LayerSettings> clientCompositionLayers;
sp<GraphicBuffer> buf;
+ base::unique_fd fd;
if (hasClientComposition) {
ALOGV("hasClientComposition");
- buf = display->getRenderSurface()->dequeueBuffer();
+ if (displayDevice->isPrimary() && supportProtectedContent) {
+ bool needsProtected = false;
+ for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) {
+ // If the layer is a protected layer, mark protected context is needed.
+ if (layer->isProtected()) {
+ needsProtected = true;
+ break;
+ }
+ }
+ if (needsProtected != renderEngine.isProtected() &&
+ renderEngine.useProtectedContext(needsProtected)) {
+ display->getRenderSurface()->setProtected(needsProtected);
+ }
+ }
+
+ buf = display->getRenderSurface()->dequeueBuffer(&fd);
if (buf == nullptr) {
ALOGW("Dequeuing buffer for display [%s] failed, bailing out of "
@@ -3327,7 +3277,6 @@
m[3][0] = displayTransform[2][0];
m[3][1] = displayTransform[2][1];
m[3][3] = displayTransform[2][2];
-
clientCompositionDisplay.globalTransform = m;
const auto* profile = display->getDisplayColorProfile();
@@ -3379,8 +3328,9 @@
// guaranteed the FB is already cleared
renderengine::LayerSettings layerSettings;
Region dummyRegion;
- bool prepared = layer->prepareClientLayer(renderArea, clip, dummyRegion,
- layerSettings);
+ bool prepared =
+ layer->prepareClientLayer(renderArea, clip, dummyRegion,
+ supportProtectedContent, layerSettings);
if (prepared) {
layerSettings.source.buffer.buffer = nullptr;
@@ -3395,7 +3345,8 @@
case Hwc2::IComposerClient::Composition::CLIENT: {
renderengine::LayerSettings layerSettings;
bool prepared =
- layer->prepareClientLayer(renderArea, clip, clearRegion, layerSettings);
+ layer->prepareClientLayer(renderArea, clip, clearRegion,
+ supportProtectedContent, layerSettings);
if (prepared) {
clientCompositionLayers.push_back(layerSettings);
}
@@ -3413,6 +3364,16 @@
// Perform some cleanup steps if we used client composition.
if (hasClientComposition) {
clientCompositionDisplay.clearRegion = clearRegion;
+
+ // We boost GPU frequency here because there will be color spaces conversion
+ // and it's expensive. We boost the GPU frequency so that GPU composition can
+ // finish in time. We must reset GPU frequency afterwards, because high frequency
+ // consumes extra battery.
+ const bool expensiveRenderingExpected =
+ clientCompositionDisplay.outputDataspace == Dataspace::DISPLAY_P3;
+ if (expensiveRenderingExpected && displayId) {
+ mPowerAdvisor.setExpensiveRenderingExpected(*displayId, true);
+ }
if (!debugRegion.isEmpty()) {
Region::const_iterator it = debugRegion.begin();
Region::const_iterator end = debugRegion.end();
@@ -3426,8 +3387,11 @@
clientCompositionLayers.push_back(layerSettings);
}
}
- getRenderEngine().drawLayers(clientCompositionDisplay, clientCompositionLayers,
- buf->getNativeBuffer(), readyFence);
+ renderEngine.drawLayers(clientCompositionDisplay, clientCompositionLayers,
+ buf->getNativeBuffer(), std::move(fd), readyFence);
+ if (expensiveRenderingExpected && displayId) {
+ mPowerAdvisor.setExpensiveRenderingExpected(*displayId, false);
+ }
}
return true;
}
@@ -3659,13 +3623,16 @@
if (flags & eAnimation) {
mAnimTransactionPending = true;
}
- while (mTransactionPending) {
+
+ mPendingSyncInputWindows = mPendingInputWindowCommands.syncInputWindows;
+ while (mTransactionPending || mPendingSyncInputWindows) {
status_t err = mTransactionCV.waitRelative(mStateLock, s2ns(5));
if (CC_UNLIKELY(err != NO_ERROR)) {
// just in case something goes wrong in SF, return to the
// called after a few seconds.
ALOGW_IF(err == TIMED_OUT, "setTransactionState timed out!");
mTransactionPending = false;
+ mPendingSyncInputWindows = false;
break;
}
}
@@ -4058,7 +4025,7 @@
}
}
- layer->setMetadata(std::move(metadata));
+ layer->setMetadata(metadata);
bool addToCurrentState = callingThreadHasUnscopedSurfaceFlingerAccess();
result = addClientLayer(client, *handle, *gbp, layer, *parent,
@@ -4455,7 +4422,9 @@
" present offset: %9" PRId64 " ns\t VSYNC period: %9" PRId64 " ns\n\n",
dispSyncPresentTimeOffset, getVsyncPeriod());
- StringAppendF(&result, "Scheduler enabled. 90Hz feature: %s\n\n", mUse90Hz ? "on" : "off");
+ StringAppendF(&result, "Scheduler enabled. 90Hz feature: %s\n", mUse90Hz ? "on" : "off");
+ StringAppendF(&result, "+ Smart 90 for video detection: %s\n\n",
+ mUseSmart90ForVideo ? "on" : "off");
mScheduler->dump(mAppConnectionHandle, result);
}
@@ -4862,6 +4831,8 @@
case GET_ANIMATION_FRAME_STATS:
case GET_HDR_CAPABILITIES:
case SET_ACTIVE_CONFIG:
+ case SET_ALLOWED_DISPLAY_CONFIGS:
+ case GET_ALLOWED_DISPLAY_CONFIGS:
case SET_ACTIVE_COLOR_MODE:
case INJECT_VSYNC:
case SET_POWER_MODE:
@@ -4907,8 +4878,7 @@
case GET_COLOR_MANAGEMENT:
case GET_COMPOSITION_PREFERENCE:
case GET_PROTECTED_CONTENT_SUPPORT:
- case IS_WIDE_COLOR_DISPLAY:
- case SET_INPUT_WINDOWS_FINISHED: {
+ case IS_WIDE_COLOR_DISPLAY: {
return OK;
}
case CAPTURE_LAYERS:
@@ -4942,9 +4912,9 @@
code == IBinder::SYSPROPS_TRANSACTION) {
return OK;
}
- // Numbers from 1000 to 1031 are currently use for backdoors. The code
+ // Numbers from 1000 to 1032 are currently use for backdoors. The code
// in onTransact verifies that the user is root, and has access to use SF.
- if (code >= 1000 && code <= 1031) {
+ if (code >= 1000 && code <= 1032) {
ALOGV("Accessing SurfaceFlinger through backdoor code: %u", code);
return OK;
}
@@ -5222,6 +5192,11 @@
}
return NO_ERROR;
}
+ case 1032: {
+ n = data.readInt32();
+ mDebugEnableProtectedContent = n;
+ return NO_ERROR;
+ }
}
}
return err;
@@ -5255,7 +5230,8 @@
const ui::PixelFormat reqPixelFormat, Rect sourceCrop,
uint32_t reqWidth, uint32_t reqHeight,
bool useIdentityTransform,
- ISurfaceComposer::Rotation rotation) {
+ ISurfaceComposer::Rotation rotation,
+ bool captureSecureLayers) {
ATRACE_CALL();
if (!displayToken) return BAD_VALUE;
@@ -5278,7 +5254,7 @@
}
DisplayRenderArea renderArea(display, sourceCrop, reqWidth, reqHeight, reqDataspace,
- renderAreaRotation);
+ renderAreaRotation, captureSecureLayers);
auto traverseLayers = std::bind(&SurfaceFlinger::traverseLayersInDisplay, this, display,
std::placeholders::_1);
@@ -5440,6 +5416,13 @@
static_cast<android_pixel_format>(reqPixelFormat), 1,
usage, "screenshot");
+ return captureScreenCommon(renderArea, traverseLayers, *outBuffer, useIdentityTransform);
+}
+
+status_t SurfaceFlinger::captureScreenCommon(RenderArea& renderArea,
+ TraverseLayersFunction traverseLayers,
+ const sp<GraphicBuffer>& buffer,
+ bool useIdentityTransform) {
// This mutex protects syncFd and captureResult for communication of the return values from the
// main thread back to this Binder thread
std::mutex captureMutex;
@@ -5467,7 +5450,7 @@
{
Mutex::Autolock _l(mStateLock);
renderArea.render([&] {
- result = captureScreenImplLocked(renderArea, traverseLayers, (*outBuffer).get(),
+ result = captureScreenImplLocked(renderArea, traverseLayers, buffer.get(),
useIdentityTransform, forSystem, &fd);
});
}
@@ -5595,16 +5578,20 @@
traverseLayers([&](Layer* layer) {
renderengine::LayerSettings layerSettings;
bool prepared = layer->prepareClientLayer(renderArea, useIdentityTransform, clearRegion,
- layerSettings);
+ false, layerSettings);
if (prepared) {
clientCompositionLayers.push_back(layerSettings);
}
});
clientCompositionDisplay.clearRegion = clearRegion;
+ // Use an empty fence for the buffer fence, since we just created the buffer so
+ // there is no need for synchronization with the GPU.
+ base::unique_fd bufferFence;
base::unique_fd drawFence;
+ getRenderEngine().useProtectedContext(false);
getRenderEngine().drawLayers(clientCompositionDisplay, clientCompositionLayers, buffer,
- &drawFence);
+ std::move(bufferFence), &drawFence);
*outSyncFd = drawFence.release();
}
@@ -5634,7 +5621,12 @@
return NO_ERROR;
}
-void SurfaceFlinger::setInputWindowsFinished() {}
+void SurfaceFlinger::setInputWindowsFinished() {
+ Mutex::Autolock _l(mStateLock);
+
+ mPendingSyncInputWindows = false;
+ mTransactionCV.broadcast();
+}
// ---------------------------------------------------------------------------
@@ -5667,6 +5659,112 @@
}
}
+void SurfaceFlinger::setAllowedDisplayConfigsInternal(
+ const android::sp<android::IBinder>& displayToken,
+ std::unique_ptr<const AllowedDisplayConfigs>&& allowedConfigs) {
+ const auto displayId = getPhysicalDisplayIdLocked(displayToken);
+ if (!displayId) {
+ ALOGE("setAllowedDisplayConfigsInternal: getPhysicalDisplayId failed");
+ return;
+ }
+
+ ALOGV("Updating allowed configs");
+ {
+ std::lock_guard lock(mAllowedConfigsLock);
+ mAllowedConfigs[*displayId] = std::move(allowedConfigs);
+ }
+
+ // make sure that the current config is still allowed
+ int currentConfigIndex = getHwComposer().getActiveConfigIndex(*displayId);
+ if (!isConfigAllowed(*displayId, currentConfigIndex)) {
+ // TODO(b/122906558): stop querying HWC for the available configs and instead use the cached
+ // configs queried on boot
+ auto configs = getHwComposer().getConfigs(*displayId);
+
+ for (int i = 0; i < configs.size(); i++) {
+ if (isConfigAllowed(*displayId, i)) {
+ // TODO: we switch to the first allowed config. In the future
+ // we may want to enhance this logic to pick a similar config
+ // to the current one
+ ALOGV("Old config is not allowed - switching to config %d", i);
+ setDesiredActiveConfig(displayToken, i, ConfigEvent::Changed);
+ break;
+ }
+ }
+ }
+}
+
+status_t SurfaceFlinger::setAllowedDisplayConfigs(const android::sp<android::IBinder>& displayToken,
+ const std::vector<int32_t>& allowedConfigs) {
+ ATRACE_CALL();
+
+ if (!displayToken) {
+ ALOGE("setAllowedDisplayConfigs: displayToken is null");
+ return BAD_VALUE;
+ }
+
+ if (!allowedConfigs.size()) {
+ ALOGE("setAllowedDisplayConfigs: empty config set provided");
+ return BAD_VALUE;
+ }
+
+ {
+ ConditionalLock lock(mStateLock, std::this_thread::get_id() != mMainThreadId);
+ const auto displayId = getPhysicalDisplayIdLocked(displayToken);
+ if (!displayId) {
+ ALOGE("setAllowedDisplayConfigs: display not found");
+ return NAME_NOT_FOUND;
+ }
+ }
+
+ auto allowedDisplayConfigsBuilder = AllowedDisplayConfigs::Builder();
+ for (int config : allowedConfigs) {
+ ALOGV("setAllowedDisplayConfigs: Adding config to the allowed configs = %d", config);
+ allowedDisplayConfigsBuilder.addConfig(config);
+ }
+ auto allowedDisplayConfigs = allowedDisplayConfigsBuilder.build();
+ postMessageSync(new LambdaMessage([&]() NO_THREAD_SAFETY_ANALYSIS {
+ setAllowedDisplayConfigsInternal(displayToken, std::move(allowedDisplayConfigs));
+ }));
+ return NO_ERROR;
+}
+
+status_t SurfaceFlinger::getAllowedDisplayConfigs(const android::sp<android::IBinder>& displayToken,
+ std::vector<int32_t>* outAllowedConfigs) {
+ ATRACE_CALL();
+
+ if (!displayToken) {
+ ALOGE("getAllowedDisplayConfigs: displayToken is null");
+ return BAD_VALUE;
+ }
+
+ if (!outAllowedConfigs) {
+ ALOGE("getAllowedDisplayConfigs: outAllowedConfigs is null");
+ return BAD_VALUE;
+ }
+
+ ConditionalLock stateLock(mStateLock, std::this_thread::get_id() != mMainThreadId);
+ const auto displayId = getPhysicalDisplayIdLocked(displayToken);
+ if (!displayId) {
+ ALOGE("getAllowedDisplayConfigs: display not found");
+ return NAME_NOT_FOUND;
+ }
+
+ std::lock_guard allowedConfigLock(mAllowedConfigsLock);
+ auto allowedConfigIterator = mAllowedConfigs.find(displayId.value());
+ if (allowedConfigIterator != mAllowedConfigs.end()) {
+ allowedConfigIterator->second->getAllowedConfigs(outAllowedConfigs);
+ }
+
+ return NO_ERROR;
+}
+
+// ----------------------------------------------------------------------------
+
+void SetInputWindowsListener::onSetInputWindowsFinished() {
+ mFlinger->setInputWindowsFinished();
+}
+
}; // namespace android
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 220e664..57dab7f 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -33,6 +33,7 @@
#include <gui/LayerState.h>
#include <gui/OccupancyTracker.h>
#include <hardware/hwcomposer_defs.h>
+#include <input/ISetInputWindowsListener.h>
#include <layerproto/LayerProtoHeader.h>
#include <math/mat4.h>
#include <serviceutils/PriorityDumper.h>
@@ -46,16 +47,18 @@
#include <utils/Trace.h>
#include <utils/threads.h>
+#include "AllowedDisplayConfigs.h"
#include "Barrier.h"
#include "BufferStateLayerCache.h"
#include "DisplayDevice.h"
#include "DisplayHardware/HWC2.h"
#include "DisplayHardware/HWComposer.h"
+#include "DisplayHardware/PowerAdvisor.h"
#include "Effects/Daltonizer.h"
#include "FrameTracker.h"
-#include "LayerBE.h"
#include "LayerStats.h"
#include "LayerVector.h"
+#include "RegionSamplingThread.h"
#include "Scheduler/DispSync.h"
#include "Scheduler/EventThread.h"
#include "Scheduler/MessageQueue.h"
@@ -103,7 +106,6 @@
class SurfaceFlingerBE;
class TimeStats;
class VSyncSource;
-struct CompositionInfo;
namespace compositionengine {
class DisplaySurface;
@@ -196,11 +198,16 @@
// use to differentiate callbacks from different hardware composer
// instances. Each hardware composer instance gets a different sequence id.
int32_t mComposerSequenceId;
-
- std::map<wp<IBinder>, std::vector<CompositionInfo>> mCompositionInfo;
- std::map<wp<IBinder>, std::vector<CompositionInfo>> mEndOfFrameCompositionInfo;
};
+class SetInputWindowsListener : public BnSetInputWindowsListener {
+public:
+ SetInputWindowsListener(const sp<SurfaceFlinger>& flinger) : mFlinger(flinger) {}
+ void onSetInputWindowsFinished() override;
+
+private:
+ const sp<SurfaceFlinger> mFlinger;
+};
class SurfaceFlinger : public BnSurfaceComposer,
public PriorityDumper,
@@ -348,6 +355,8 @@
return mTransactionCompletedThread;
}
+ void setInputWindowsFinished();
+
private:
friend class Client;
friend class DisplayEventConnection;
@@ -357,6 +366,7 @@
friend class BufferQueueLayer;
friend class BufferStateLayer;
friend class MonitoredProducer;
+ friend class RegionSamplingThread;
// For unit tests
friend class TestableSurfaceFlinger;
@@ -429,7 +439,8 @@
status_t captureScreen(const sp<IBinder>& displayToken, sp<GraphicBuffer>* outBuffer,
const ui::Dataspace reqDataspace, const ui::PixelFormat reqPixelFormat,
Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
- bool useIdentityTransform, ISurfaceComposer::Rotation rotation) override;
+ bool useIdentityTransform, ISurfaceComposer::Rotation rotation,
+ bool captureSecureLayers) override;
status_t captureLayers(const sp<IBinder>& parentHandle, sp<GraphicBuffer>* outBuffer,
const ui::Dataspace reqDataspace, const ui::PixelFormat reqPixelFormat,
const Rect& sourceCrop, float frameScale, bool childrenOnly) override;
@@ -477,7 +488,11 @@
status_t addRegionSamplingListener(const Rect& samplingArea, const sp<IBinder>& stopLayerHandle,
const sp<IRegionSamplingListener>& listener) override;
status_t removeRegionSamplingListener(const sp<IRegionSamplingListener>& listener) override;
- void setInputWindowsFinished() override;
+ status_t setAllowedDisplayConfigs(const sp<IBinder>& displayToken,
+ const std::vector<int32_t>& allowedConfigs) override;
+ status_t getAllowedDisplayConfigs(const sp<IBinder>& displayToken,
+ std::vector<int32_t>* outAllowedConfigs) override;
+
/* ------------------------------------------------------------------------
* DeathRecipient interface
*/
@@ -507,10 +522,20 @@
void signalLayerUpdate();
void signalRefresh();
+ enum class ConfigEvent { None, Changed };
+
+ // logical or operator with the semantics of at least one of the events is Changed
+ friend ConfigEvent operator|(const ConfigEvent& first, const ConfigEvent& second) {
+ if (first == ConfigEvent::Changed) return ConfigEvent::Changed;
+ if (second == ConfigEvent::Changed) return ConfigEvent::Changed;
+ return ConfigEvent::None;
+ }
+
// called on the main thread in response to initializeDisplays()
void onInitializeDisplays() REQUIRES(mStateLock);
// Sets the desired active config bit. It obtains the lock, and sets mDesiredActiveConfig.
- void setDesiredActiveConfig(const sp<IBinder>& displayToken, int mode) REQUIRES(mStateLock);
+ void setDesiredActiveConfig(const sp<IBinder>& displayToken, int mode, ConfigEvent event)
+ REQUIRES(mStateLock);
// Once HWC has returned the present fence, this sets the active config and a new refresh
// rate in SF. It also triggers HWC vsync.
void setActiveConfigInternal() REQUIRES(mStateLock);
@@ -522,6 +547,11 @@
// called on the main thread in response to setPowerMode()
void setPowerModeInternal(const sp<DisplayDevice>& display, int mode) REQUIRES(mStateLock);
+ // called on the main thread in response to setAllowedDisplayConfigs()
+ void setAllowedDisplayConfigsInternal(
+ const sp<IBinder>& displayToken,
+ std::unique_ptr<const AllowedDisplayConfigs>&& allowedConfigs) REQUIRES(mStateLock);
+
// Returns whether the transaction actually modified any state
bool handleMessageTransaction();
@@ -623,6 +653,8 @@
status_t captureScreenCommon(RenderArea& renderArea, TraverseLayersFunction traverseLayers,
sp<GraphicBuffer>* outBuffer, const ui::PixelFormat reqPixelFormat,
bool useIdentityTransform);
+ status_t captureScreenCommon(RenderArea& renderArea, TraverseLayersFunction traverseLayers,
+ const sp<GraphicBuffer>& buffer, bool useIdentityTransform);
status_t captureScreenImplLocked(const RenderArea& renderArea,
TraverseLayersFunction traverseLayers,
ANativeWindowBuffer* buffer, bool useIdentityTransform,
@@ -685,10 +717,6 @@
// region of all screens presenting this layer stack.
void invalidateLayerStack(const sp<const Layer>& layer, const Region& dirty);
- // Initialize structures containing information about the internal
- // display's native color coordinates using default data
- void initDefaultDisplayNativePrimaries();
-
/* ------------------------------------------------------------------------
* H/W composer
*/
@@ -788,7 +816,10 @@
// Sets the refresh rate by switching active configs, if they are available for
// the desired refresh rate.
- void setRefreshRateTo(scheduler::RefreshRateConfigs::RefreshRateType) REQUIRES(mStateLock);
+ void setRefreshRateTo(scheduler::RefreshRateConfigs::RefreshRateType, ConfigEvent event)
+ REQUIRES(mStateLock);
+
+ bool isConfigAllowed(const DisplayId& displayId, int32_t config);
/*
* Display identification
@@ -973,6 +1004,7 @@
int mDebugRegion;
int mDebugDisableHWC;
int mDebugDisableTransformHint;
+ bool mDebugEnableProtectedContent;
volatile nsecs_t mDebugInSwapBuffers;
volatile nsecs_t mDebugInTransaction;
nsecs_t mLastTransactionTime;
@@ -988,6 +1020,9 @@
TransactionCompletedThread mTransactionCompletedThread;
+ bool mLumaSampling = true;
+ sp<RegionSamplingThread> mRegionSamplingThread = new RegionSamplingThread(*this);
+
// Restrict layers to use two buffers in their bufferqueues.
bool mLayerTripleBufferingDisabled = false;
@@ -1075,14 +1110,20 @@
* Scheduler
*/
bool mUse90Hz = false;
+ bool mUseSmart90ForVideo = false;
std::unique_ptr<Scheduler> mScheduler;
sp<Scheduler::ConnectionHandle> mAppConnectionHandle;
sp<Scheduler::ConnectionHandle> mSfConnectionHandle;
std::unique_ptr<scheduler::RefreshRateStats> mRefreshRateStats;
+ std::mutex mAllowedConfigsLock;
+ std::unordered_map<DisplayId, std::unique_ptr<const AllowedDisplayConfigs>> mAllowedConfigs
+ GUARDED_BY(mAllowedConfigsLock);
+
struct ActiveConfigInfo {
int configId;
sp<IBinder> displayToken;
+ ConfigEvent event;
bool operator!=(const ActiveConfigInfo& other) const {
if (configId != other.configId) {
@@ -1110,8 +1151,11 @@
InputWindowCommands mPendingInputWindowCommands GUARDED_BY(mStateLock);
// Should only be accessed by the main thread.
InputWindowCommands mInputWindowCommands;
-
ui::DisplayPrimaries mInternalDisplayPrimaries;
+
+ sp<SetInputWindowsListener> mSetInputWindowsListener;
+ bool mPendingSyncInputWindows GUARDED_BY(mStateLock);
+ Hwc2::impl::PowerAdvisor mPowerAdvisor;
};
}; // namespace android
diff --git a/services/surfaceflinger/SurfaceFlingerProperties.cpp b/services/surfaceflinger/SurfaceFlingerProperties.cpp
index b654ba7..f2881f5 100644
--- a/services/surfaceflinger/SurfaceFlingerProperties.cpp
+++ b/services/surfaceflinger/SurfaceFlingerProperties.cpp
@@ -4,9 +4,9 @@
#include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
#include <android/hardware/configstore/1.1/ISurfaceFlingerConfigs.h>
#include <android/hardware/configstore/1.1/types.h>
-#include <android/hardware/configstore/1.2/ISurfaceFlingerConfigs.h>
#include <configstore/Utils.h>
+#include <cstdlib>
#include <tuple>
#include "SurfaceFlingerProperties.h"
@@ -15,8 +15,9 @@
namespace sysprop {
using namespace android::hardware::configstore;
using namespace android::hardware::configstore::V1_0;
-using ::android::hardware::graphics::common::V1_2::Dataspace;
-using ::android::hardware::graphics::common::V1_2::PixelFormat;
+using android::hardware::graphics::common::V1_2::Dataspace;
+using android::hardware::graphics::common::V1_2::PixelFormat;
+using android::ui::DisplayPrimaries;
int64_t vsync_event_phase_offset_ns(int64_t defaultValue) {
auto temp = SurfaceFlingerProperties::vsync_event_phase_offset_ns();
@@ -169,40 +170,14 @@
tmpHasWideColorDisplay.has_value()) {
return *tmpuseColorManagement || *tmpHasHDRDisplay || *tmpHasWideColorDisplay;
}
- auto surfaceFlingerConfigsServiceV1_2 = ISurfaceFlingerConfigs::getService();
- if (surfaceFlingerConfigsServiceV1_2) {
- return getBool<V1_2::ISurfaceFlingerConfigs,
- &V1_2::ISurfaceFlingerConfigs::useColorManagement>(defaultValue);
- }
return defaultValue;
}
-auto getCompositionPreference(sp<V1_2::ISurfaceFlingerConfigs> configsServiceV1_2) {
- Dataspace defaultCompositionDataspace = Dataspace::V0_SRGB;
- PixelFormat defaultCompositionPixelFormat = PixelFormat::RGBA_8888;
- Dataspace wideColorGamutCompositionDataspace = Dataspace::V0_SRGB;
- PixelFormat wideColorGamutCompositionPixelFormat = PixelFormat::RGBA_8888;
- configsServiceV1_2->getCompositionPreference(
- [&](auto tmpDefaultDataspace, auto tmpDefaultPixelFormat,
- auto tmpWideColorGamutDataspace, auto tmpWideColorGamutPixelFormat) {
- defaultCompositionDataspace = tmpDefaultDataspace;
- defaultCompositionPixelFormat = tmpDefaultPixelFormat;
- wideColorGamutCompositionDataspace = tmpWideColorGamutDataspace;
- wideColorGamutCompositionPixelFormat = tmpWideColorGamutPixelFormat;
- });
- return std::tuple(defaultCompositionDataspace, defaultCompositionPixelFormat,
- wideColorGamutCompositionDataspace, wideColorGamutCompositionPixelFormat);
-}
-
int64_t default_composition_dataspace(Dataspace defaultValue) {
auto temp = SurfaceFlingerProperties::default_composition_dataspace();
if (temp.has_value()) {
return *temp;
}
- auto configsServiceV1_2 = V1_2::ISurfaceFlingerConfigs::getService();
- if (configsServiceV1_2) {
- return static_cast<int64_t>(get<0>(getCompositionPreference(configsServiceV1_2)));
- }
return static_cast<int64_t>(defaultValue);
}
@@ -211,10 +186,6 @@
if (temp.has_value()) {
return *temp;
}
- auto configsServiceV1_2 = V1_2::ISurfaceFlingerConfigs::getService();
- if (configsServiceV1_2) {
- return static_cast<int32_t>(get<1>(getCompositionPreference(configsServiceV1_2)));
- }
return static_cast<int32_t>(defaultValue);
}
@@ -223,10 +194,6 @@
if (temp.has_value()) {
return *temp;
}
- auto configsServiceV1_2 = V1_2::ISurfaceFlingerConfigs::getService();
- if (configsServiceV1_2) {
- return static_cast<int64_t>(get<2>(getCompositionPreference(configsServiceV1_2)));
- }
return static_cast<int64_t>(defaultValue);
}
@@ -235,12 +202,50 @@
if (temp.has_value()) {
return *temp;
}
- auto configsServiceV1_2 = V1_2::ISurfaceFlingerConfigs::getService();
- if (configsServiceV1_2) {
- return static_cast<int32_t>(get<3>(getCompositionPreference(configsServiceV1_2)));
- }
return static_cast<int32_t>(defaultValue);
}
+#define DISPLAY_PRIMARY_SIZE 3
+
+constexpr float kSrgbRedX = 0.4123f;
+constexpr float kSrgbRedY = 0.2126f;
+constexpr float kSrgbRedZ = 0.0193f;
+constexpr float kSrgbGreenX = 0.3576f;
+constexpr float kSrgbGreenY = 0.7152f;
+constexpr float kSrgbGreenZ = 0.1192f;
+constexpr float kSrgbBlueX = 0.1805f;
+constexpr float kSrgbBlueY = 0.0722f;
+constexpr float kSrgbBlueZ = 0.9506f;
+constexpr float kSrgbWhiteX = 0.9505f;
+constexpr float kSrgbWhiteY = 1.0000f;
+constexpr float kSrgbWhiteZ = 1.0891f;
+
+DisplayPrimaries getDisplayNativePrimaries() {
+ auto mDisplay_primary_red = SurfaceFlingerProperties::display_primary_red();
+ auto mDisplay_primary_green = SurfaceFlingerProperties::display_primary_green();
+ auto mDisplay_primary_blue = SurfaceFlingerProperties::display_primary_blue();
+ auto mDisplay_primary_white = SurfaceFlingerProperties::display_primary_white();
+ // To avoid null point exception.
+ mDisplay_primary_red.resize(DISPLAY_PRIMARY_SIZE);
+ mDisplay_primary_green.resize(DISPLAY_PRIMARY_SIZE);
+ mDisplay_primary_blue.resize(DISPLAY_PRIMARY_SIZE);
+ mDisplay_primary_white.resize(DISPLAY_PRIMARY_SIZE);
+ DisplayPrimaries primaries =
+ {{static_cast<float>(mDisplay_primary_red[0].value_or(kSrgbRedX)),
+ static_cast<float>(mDisplay_primary_red[1].value_or(kSrgbRedY)),
+ static_cast<float>(mDisplay_primary_red[2].value_or(kSrgbRedZ))},
+ {static_cast<float>(mDisplay_primary_green[0].value_or(kSrgbGreenX)),
+ static_cast<float>(mDisplay_primary_green[1].value_or(kSrgbGreenY)),
+ static_cast<float>(mDisplay_primary_green[2].value_or(kSrgbGreenZ))},
+ {static_cast<float>(mDisplay_primary_blue[0].value_or(kSrgbBlueX)),
+ static_cast<float>(mDisplay_primary_blue[1].value_or(kSrgbBlueY)),
+ static_cast<float>(mDisplay_primary_blue[2].value_or(kSrgbBlueZ))},
+ {static_cast<float>(mDisplay_primary_white[0].value_or(kSrgbWhiteX)),
+ static_cast<float>(mDisplay_primary_white[1].value_or(kSrgbWhiteY)),
+ static_cast<float>(mDisplay_primary_white[2].value_or(kSrgbWhiteZ))}};
+
+ return primaries;
+}
+
} // namespace sysprop
} // namespace android
diff --git a/services/surfaceflinger/SurfaceFlingerProperties.h b/services/surfaceflinger/SurfaceFlingerProperties.h
index 9b26883..9917683 100644
--- a/services/surfaceflinger/SurfaceFlingerProperties.h
+++ b/services/surfaceflinger/SurfaceFlingerProperties.h
@@ -3,8 +3,9 @@
#define SURFACEFLINGERPROPERTIES_H_
#include <android/hardware/configstore/1.1/ISurfaceFlingerConfigs.h>
-#include <android/hardware/configstore/1.2/ISurfaceFlingerConfigs.h>
+#include <android/hardware/graphics/common/1.2/types.h>
#include <sysprop/SurfaceFlingerProperties.sysprop.h>
+#include <ui/ConfigStoreTypes.h>
#include <cstdint>
#include <optional>
@@ -53,6 +54,8 @@
int32_t wcg_composition_pixel_format(
android::hardware::graphics::common::V1_2::PixelFormat defaultValue);
+
+android::ui::DisplayPrimaries getDisplayNativePrimaries();
} // namespace sysprop
} // namespace android
#endif // SURFACEFLINGERPROPERTIES_H_
diff --git a/services/surfaceflinger/layerproto/LayerProtoParser.cpp b/services/surfaceflinger/layerproto/LayerProtoParser.cpp
index 7ab57f9..7288232 100644
--- a/services/surfaceflinger/layerproto/LayerProtoParser.cpp
+++ b/services/surfaceflinger/layerproto/LayerProtoParser.cpp
@@ -132,7 +132,6 @@
LayerProtoParser::Region LayerProtoParser::generateRegion(const RegionProto& regionProto) {
LayerProtoParser::Region region;
- region.id = regionProto.id();
for (int i = 0; i < regionProto.rect_size(); i++) {
const RectProto& rectProto = regionProto.rect(i);
region.rects.push_back(generateRect(rectProto));
diff --git a/services/surfaceflinger/layerproto/layers.proto b/services/surfaceflinger/layerproto/layers.proto
index faf0c54..fd4695e 100644
--- a/services/surfaceflinger/layerproto/layers.proto
+++ b/services/surfaceflinger/layerproto/layers.proto
@@ -113,10 +113,11 @@
float dtdx = 2;
float dsdy = 3;
float dtdy = 4;
+ int32 type = 5;
}
message RegionProto {
- uint64 id = 1;
+ reserved 1; // Previously: uint64 id
repeated RectProto rect = 2;
}
diff --git a/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop b/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop
index cc7b280..429636b 100644
--- a/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop
+++ b/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop
@@ -250,3 +250,39 @@
access: Readonly
prop_name: "ro.surface_flinger.wcg_composition_pixel_format"
}
+
+# Return the native panel primary data. The data includes red, green,
+# blue and white. The primary format is CIE 1931 XYZ color space.
+# If unspecified, the primaries is sRGB gamut by default.
+
+prop {
+ api_name: "display_primary_red"
+ type: DoubleList
+ scope: Internal
+ access: Readonly
+ prop_name: "ro.surface_flinger.display_primary_red"
+}
+
+prop {
+ api_name: "display_primary_green"
+ type: DoubleList
+ scope: Internal
+ access: Readonly
+ prop_name: "ro.surface_flinger.display_primary_green"
+}
+
+prop {
+ api_name: "display_primary_blue"
+ type: DoubleList
+ scope: Internal
+ access: Readonly
+ prop_name: "ro.surface_flinger.display_primary_blue"
+}
+
+prop {
+ api_name: "display_primary_white"
+ type: DoubleList
+ scope: Internal
+ access: Readonly
+ prop_name: "ro.surface_flinger.display_primary_white"
+}
diff --git a/services/surfaceflinger/tests/Transaction_test.cpp b/services/surfaceflinger/tests/Transaction_test.cpp
index 181dac6..34cdff7 100644
--- a/services/surfaceflinger/tests/Transaction_test.cpp
+++ b/services/surfaceflinger/tests/Transaction_test.cpp
@@ -33,6 +33,7 @@
#include <gui/Surface.h>
#include <gui/SurfaceComposerClient.h>
#include <private/gui/ComposerService.h>
+#include <private/android_filesystem_config.h>
#include <ui/ColorSpace.h>
#include <ui/DisplayInfo.h>
@@ -41,6 +42,8 @@
#include <math.h>
#include <math/vec3.h>
+#include <sys/types.h>
+#include <unistd.h>
#include "BufferGenerator.h"
@@ -1201,6 +1204,56 @@
composer->captureScreen(mDisplay, &outBuffer, Rect(), 0, 0, false));
}
+/** RAII Wrapper around get/seteuid */
+class UIDFaker {
+ uid_t oldId;
+public:
+ UIDFaker(uid_t uid) {
+ oldId = geteuid();
+ seteuid(uid);
+ }
+ ~UIDFaker() {
+ seteuid(oldId);
+ }
+};
+
+TEST_F(LayerTransactionTest, SetFlagsSecureEUidSystem) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
+ ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
+
+ sp<ISurfaceComposer> composer = ComposerService::getComposerService();
+ sp<GraphicBuffer> outBuffer;
+ Transaction()
+ .setFlags(layer, layer_state_t::eLayerSecure, layer_state_t::eLayerSecure)
+ .apply(true);
+ ASSERT_EQ(PERMISSION_DENIED,
+ composer->captureScreen(mDisplay, &outBuffer, Rect(), 0, 0, false));
+
+ UIDFaker f(AID_SYSTEM);
+
+ // By default the system can capture screenshots with secure layers but they
+ // will be blacked out
+ ASSERT_EQ(NO_ERROR,
+ composer->captureScreen(mDisplay, &outBuffer, Rect(), 0, 0, false));
+
+ {
+ SCOPED_TRACE("as system");
+ auto shot = screenshot();
+ shot->expectColor(Rect(0, 0, 32, 32), Color::BLACK);
+ }
+
+ // Here we pass captureSecureLayers = true and since we are AID_SYSTEM we should be able
+ // to receive them...we are expected to take care with the results.
+ ASSERT_EQ(NO_ERROR,
+ composer->captureScreen(mDisplay, &outBuffer,
+ ui::Dataspace::V0_SRGB, ui::PixelFormat::RGBA_8888,
+ Rect(), 0, 0, false,
+ ISurfaceComposer::eRotateNone, true));
+ ScreenCapture sc(outBuffer);
+ sc.expectColor(Rect(0, 0, 32, 32), Color::RED);
+}
+
TEST_P(LayerRenderTypeTransactionTest, SetTransparentRegionHintBasic_BufferQueue) {
const Rect top(0, 0, 32, 16);
const Rect bottom(0, 16, 32, 32);
diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
index d0f7b90..30ae764 100644
--- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
@@ -312,7 +312,7 @@
.WillRepeatedly(
[](const renderengine::DisplaySettings& displaySettings,
const std::vector<renderengine::LayerSettings>& /*layerSettings*/,
- ANativeWindowBuffer*, base::unique_fd*) -> status_t {
+ ANativeWindowBuffer*, base::unique_fd&&, base::unique_fd*) -> status_t {
EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance);
EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
displaySettings.physicalDisplay);
@@ -351,7 +351,7 @@
.WillRepeatedly(
[](const renderengine::DisplaySettings& displaySettings,
const std::vector<renderengine::LayerSettings>& /*layerSettings*/,
- ANativeWindowBuffer*, base::unique_fd*) -> status_t {
+ ANativeWindowBuffer*, base::unique_fd&&, base::unique_fd*) -> status_t {
EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance);
EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
displaySettings.physicalDisplay);
@@ -580,7 +580,8 @@
EXPECT_CALL(*test->mRenderEngine, drawLayers)
.WillOnce([](const renderengine::DisplaySettings& displaySettings,
const std::vector<renderengine::LayerSettings>& layerSettings,
- ANativeWindowBuffer*, base::unique_fd*) -> status_t {
+ ANativeWindowBuffer*, base::unique_fd&&,
+ base::unique_fd*) -> status_t {
EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance);
EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
displaySettings.physicalDisplay);
@@ -591,8 +592,6 @@
renderengine::LayerSettings layer = layerSettings.back();
EXPECT_THAT(layer.source.buffer.buffer, Not(IsNull()));
EXPECT_THAT(layer.source.buffer.fence, Not(IsNull()));
- EXPECT_EQ(renderengine::Buffer::CachingHint::NO_CACHE,
- layer.source.buffer.cacheHint);
EXPECT_EQ(DEFAULT_TEXTURE_ID, layer.source.buffer.textureName);
EXPECT_EQ(false, layer.source.buffer.isY410BT2020);
EXPECT_EQ(true, layer.source.buffer.usePremultipliedAlpha);
@@ -624,7 +623,8 @@
EXPECT_CALL(*test->mRenderEngine, drawLayers)
.WillOnce([](const renderengine::DisplaySettings& displaySettings,
const std::vector<renderengine::LayerSettings>& layerSettings,
- ANativeWindowBuffer*, base::unique_fd*) -> status_t {
+ ANativeWindowBuffer*, base::unique_fd&&,
+ base::unique_fd*) -> status_t {
EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance);
EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
displaySettings.physicalDisplay);
@@ -693,7 +693,8 @@
EXPECT_CALL(*test->mRenderEngine, drawLayers)
.WillOnce([](const renderengine::DisplaySettings& displaySettings,
const std::vector<renderengine::LayerSettings>& layerSettings,
- ANativeWindowBuffer*, base::unique_fd*) -> status_t {
+ ANativeWindowBuffer*, base::unique_fd&&,
+ base::unique_fd*) -> status_t {
EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance);
EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
displaySettings.physicalDisplay);
diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
index 19f308b..9bf29a2 100644
--- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
@@ -1322,32 +1322,6 @@
EXPECT_EQ(BAD_VALUE, mFlinger.getDisplayNativePrimaries(nullptr, primaries));
}
-TEST_F(GetDisplayNativePrimaries, internalDisplayWithDefaultPrimariesData) {
- auto injector = SimplePrimaryDisplayCase::Display::makeFakeExistingDisplayInjector(this);
- injector.inject();
- auto internalDisplayToken = injector.token();
- // A nullptr would trigger a different execution path than what's being tested here
- EXPECT_NE(nullptr, internalDisplayToken.get());
-
- mFlinger.initDefaultDisplayNativePrimaries();
-
- ui::DisplayPrimaries primaries;
- // Expecting sRGB primaries
- EXPECT_EQ(NO_ERROR, mFlinger.getDisplayNativePrimaries(internalDisplayToken, primaries));
- EXPECT_EQ(primaries.red.X, 0.4123f);
- EXPECT_EQ(primaries.red.Y, 0.2126f);
- EXPECT_EQ(primaries.red.Z, 0.0193f);
- EXPECT_EQ(primaries.green.X, 0.3576f);
- EXPECT_EQ(primaries.green.Y, 0.7152f);
- EXPECT_EQ(primaries.green.Z, 0.1192f);
- EXPECT_EQ(primaries.blue.X, 0.1805f);
- EXPECT_EQ(primaries.blue.Y, 0.0722f);
- EXPECT_EQ(primaries.blue.Z, 0.9506f);
- EXPECT_EQ(primaries.white.X, 0.9505f);
- EXPECT_EQ(primaries.white.Y, 1.0000f);
- EXPECT_EQ(primaries.white.Z, 1.0891f);
-}
-
TEST_F(GetDisplayNativePrimaries, internalDisplayWithPrimariesData) {
auto injector = SimplePrimaryDisplayCase::Display::makeFakeExistingDisplayInjector(this);
injector.inject();
@@ -1952,6 +1926,10 @@
EXPECT_CALL(*mComposer, destroyVirtualDisplay(Case::Display::HWC_DISPLAY_ID))
.WillOnce(Return(Error::NONE));
EXPECT_CALL(*mConsumer, consumerDisconnect()).WillOnce(Return(NO_ERROR));
+
+ // Cleanup
+ mFlinger.mutableCurrentState().displays.removeItem(displayToken);
+ mFlinger.mutableDrawingState().displays.removeItem(displayToken);
}
TEST_F(HandleTransactionLockedTest, processesVirtualDisplayAddedWithNoSurface) {
diff --git a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
index e499ff5..406ec81 100644
--- a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
+++ b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
@@ -81,6 +81,8 @@
void expectVsyncEventReceivedByConnection(nsecs_t expectedTimestamp, unsigned expectedCount);
void expectHotplugEventReceivedByConnection(PhysicalDisplayId expectedDisplayId,
bool expectedConnected);
+ void expectConfigChangedEventReceivedByConnection(PhysicalDisplayId expectedDisplayId,
+ int32_t expectedConfigId);
AsyncCallRecorder<void (*)(bool)> mVSyncSetEnabledCallRecorder;
AsyncCallRecorder<void (*)(VSyncSource::Callback*)> mVSyncSetCallbackCallRecorder;
@@ -212,6 +214,16 @@
EXPECT_EQ(expectedConnected, event.hotplug.connected);
}
+void EventThreadTest::expectConfigChangedEventReceivedByConnection(
+ PhysicalDisplayId expectedDisplayId, int32_t expectedConfigId) {
+ auto args = mConnectionEventCallRecorder.waitForCall();
+ ASSERT_TRUE(args.has_value());
+ const auto& event = std::get<0>(args.value());
+ EXPECT_EQ(DisplayEventReceiver::DISPLAY_EVENT_CONFIG_CHANGED, event.header.type);
+ EXPECT_EQ(expectedDisplayId, event.header.displayId);
+ EXPECT_EQ(expectedConfigId, event.config.configId);
+}
+
namespace {
/* ------------------------------------------------------------------------
@@ -448,5 +460,15 @@
expectHotplugEventReceivedByConnection(EXTERNAL_DISPLAY_ID, true);
}
+TEST_F(EventThreadTest, postConfigChangedPrimary) {
+ mThread->onConfigChanged(INTERNAL_DISPLAY_ID, 7);
+ expectConfigChangedEventReceivedByConnection(INTERNAL_DISPLAY_ID, 7);
+}
+
+TEST_F(EventThreadTest, postConfigChangedExternal) {
+ mThread->onConfigChanged(EXTERNAL_DISPLAY_ID, 5);
+ expectConfigChangedEventReceivedByConnection(EXTERNAL_DISPLAY_ID, 5);
+}
+
} // namespace
} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/IdleTimerTest.cpp b/services/surfaceflinger/tests/unittests/IdleTimerTest.cpp
index 5e82225..ea39bf5 100644
--- a/services/surfaceflinger/tests/unittests/IdleTimerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/IdleTimerTest.cpp
@@ -140,7 +140,7 @@
mExpiredTimerCallback.getInvocable());
// The start hasn't happened, so the callback does not happen.
EXPECT_FALSE(mExpiredTimerCallback.waitForCall(waitTimeForUnexpected3msCallback).has_value());
- EXPECT_FALSE(mResetTimerCallback.waitForCall(1us).has_value());
+ EXPECT_FALSE(mResetTimerCallback.waitForCall().has_value());
mIdleTimer->stop();
// Final quick check that no more callback were observed.
EXPECT_FALSE(mExpiredTimerCallback.waitForCall(0ms).has_value());
@@ -159,7 +159,7 @@
EXPECT_FALSE(mExpiredTimerCallback.waitForCall(waitTimeForUnexpected3msCallback).has_value());
// Once reset, it should generate another
mIdleTimer->reset();
- EXPECT_TRUE(mResetTimerCallback.waitForCall(1ms).has_value());
+ EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value());
EXPECT_TRUE(mExpiredTimerCallback.waitForCall(waitTimeForExpected3msCallback).has_value());
mIdleTimer->stop();
// Final quick check that no more callback were observed.
@@ -171,7 +171,7 @@
mIdleTimer = std::make_unique<scheduler::IdleTimer>(3ms, mResetTimerCallback.getInvocable(),
mExpiredTimerCallback.getInvocable());
mIdleTimer->start();
- EXPECT_TRUE(mResetTimerCallback.waitForCall(1us).has_value());
+ EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value());
EXPECT_TRUE(mExpiredTimerCallback.waitForCall(waitTimeForExpected3msCallback).has_value());
mIdleTimer->stop();
}
@@ -180,21 +180,21 @@
mIdleTimer = std::make_unique<scheduler::IdleTimer>(3ms, mResetTimerCallback.getInvocable(),
mExpiredTimerCallback.getInvocable());
mIdleTimer->start();
- EXPECT_TRUE(mResetTimerCallback.waitForCall(1ms).has_value());
+ EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value());
EXPECT_TRUE(mExpiredTimerCallback.waitForCall(waitTimeForExpected3msCallback).has_value());
mIdleTimer->stop();
clearPendingCallbacks();
mIdleTimer->reset();
EXPECT_FALSE(mExpiredTimerCallback.waitForCall(waitTimeForUnexpected3msCallback).has_value());
- EXPECT_FALSE(mResetTimerCallback.waitForCall(1ms).has_value());
+ EXPECT_FALSE(mResetTimerCallback.waitForCall().has_value());
}
TEST_F(IdleTimerTest, noCallbacksAfterStopTest) {
mIdleTimer = std::make_unique<scheduler::IdleTimer>(3ms, mResetTimerCallback.getInvocable(),
mExpiredTimerCallback.getInvocable());
mIdleTimer->start();
- EXPECT_TRUE(mResetTimerCallback.waitForCall(1ms).has_value());
+ EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value());
mIdleTimer->stop();
clearPendingCallbacks();
@@ -202,7 +202,7 @@
// No more idle events should be observed
EXPECT_FALSE(mExpiredTimerCallback.waitForCall(waitTimeForUnexpected3msCallback).has_value());
- EXPECT_FALSE(mResetTimerCallback.waitForCall(1ms).has_value());
+ EXPECT_FALSE(mResetTimerCallback.waitForCall().has_value());
}
} // namespace
diff --git a/services/surfaceflinger/tests/unittests/LayerMetadataTest.cpp b/services/surfaceflinger/tests/unittests/LayerMetadataTest.cpp
index 92c9f92..75a061b 100644
--- a/services/surfaceflinger/tests/unittests/LayerMetadataTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerMetadataTest.cpp
@@ -62,17 +62,6 @@
metadata.mMap[2] = std::vector<uint8_t>{'a', 'b'};
ASSERT_EQ(0, metadata.getInt32(2, 0));
- LayerMetadata second;
- std::vector<uint8_t> someData{'c', 'd', '\0'};
- second.mMap[2] = someData;
- second.setInt32(6, 5);
- metadata.merge(second);
-
- ASSERT_EQ(3, metadata.mMap.size());
- ASSERT_EQ(someData, second.mMap[2]);
- ASSERT_EQ(5, metadata.getInt32(6, 0));
- ASSERT_EQ(2, metadata.getInt32(4, 0));
-
Parcel p;
metadata.writeToParcel(&p);
LayerMetadata reconstructed;
@@ -82,5 +71,39 @@
ASSERT_EQ(metadata.mMap, reconstructed.mMap);
}
+TEST_F(LayerMetadataTest, merge) {
+ LayerMetadata metadata;
+ metadata.setInt32(4, 2);
+ metadata.mMap[2] = std::vector<uint8_t>{'a', 'b'};
+
+ LayerMetadata second;
+ std::vector<uint8_t> someData{'c', 'd', '\0'};
+ second.mMap[2] = someData;
+ second.setInt32(6, 5);
+ second.mMap[4].clear(); // will not delete if eraseEmpty is false
+ bool changed = metadata.merge(second);
+
+ ASSERT_TRUE(changed);
+ ASSERT_EQ(3, metadata.mMap.size());
+ ASSERT_EQ(someData, second.mMap[2]);
+ ASSERT_EQ(5, metadata.getInt32(6, 0));
+ ASSERT_TRUE(metadata.mMap.at(4).empty());
+
+ LayerMetadata withErase;
+ withErase.mMap[6].clear();
+ changed = metadata.merge(withErase, true /* eraseEmpty */);
+ ASSERT_TRUE(changed);
+ ASSERT_EQ(2, metadata.mMap.size());
+ ASSERT_EQ(someData, second.mMap[2]);
+ ASSERT_EQ(true, metadata.has(4));
+
+ // test for change detection
+ LayerMetadata third;
+ third.mMap[2] = someData;
+ third.mMap[5].clear();
+ changed = metadata.merge(third);
+ ASSERT_FALSE(changed);
+}
+
} // namespace
} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index 6313f1f..79b5ca0 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -289,10 +289,6 @@
return mFlinger->SurfaceFlinger::getDisplayNativePrimaries(displayToken, primaries);
}
- void initDefaultDisplayNativePrimaries() {
- mFlinger->SurfaceFlinger::initDefaultDisplayNativePrimaries();
- }
-
/* ------------------------------------------------------------------------
* Read-only access to private data to assert post-conditions.
*/
@@ -328,6 +324,7 @@
auto& mutableTexturePool() { return mFlinger->mTexturePool; }
auto& mutableTransactionFlags() { return mFlinger->mTransactionFlags; }
auto& mutableUseHwcVirtualDisplays() { return mFlinger->mUseHwcVirtualDisplays; }
+ auto& mutablePowerAdvisor() { return mFlinger->mPowerAdvisor; }
auto& mutableComposerSequenceId() { return mFlinger->getBE().mComposerSequenceId; }
auto& mutableHwcDisplayData() { return getHwComposer().mDisplayData; }
@@ -356,18 +353,11 @@
* Wrapper classes for Read-write access to private data to set up
* preconditions and assert post-conditions.
*/
- class FakePowerAdvisor : public Hwc2::PowerAdvisor {
- public:
- FakePowerAdvisor() = default;
- ~FakePowerAdvisor() override = default;
- void setExpensiveRenderingExpected(hwc2_display_t, bool) override {}
- };
-
struct HWC2Display : public HWC2::impl::Display {
- HWC2Display(Hwc2::Composer& composer, Hwc2::PowerAdvisor& advisor,
+ HWC2Display(Hwc2::Composer& composer,
const std::unordered_set<HWC2::Capability>& capabilities, hwc2_display_t id,
HWC2::DisplayType type)
- : HWC2::impl::Display(composer, advisor, capabilities, id, type) {}
+ : HWC2::impl::Display(composer, capabilities, id, type) {}
~HWC2Display() {
// Prevents a call to disable vsyncs.
mType = HWC2::DisplayType::Invalid;
@@ -431,14 +421,7 @@
return *this;
}
- auto& setPowerAdvisor(Hwc2::PowerAdvisor* powerAdvisor) {
- mPowerAdvisor = powerAdvisor;
- return *this;
- }
-
void inject(TestableSurfaceFlinger* flinger, Hwc2::Composer* composer) {
- static FakePowerAdvisor defaultPowerAdvisor;
- if (mPowerAdvisor == nullptr) mPowerAdvisor = &defaultPowerAdvisor;
static const std::unordered_set<HWC2::Capability> defaultCapabilities;
if (mCapabilities == nullptr) mCapabilities = &defaultCapabilities;
@@ -446,8 +429,8 @@
// not refer to an instance owned by FakeHwcDisplayInjector. This
// class has temporary lifetime, while the constructed HWC2::Display
// is much longer lived.
- auto display = std::make_unique<HWC2Display>(*composer, *mPowerAdvisor, *mCapabilities,
- mHwcDisplayId, mHwcDisplayType);
+ auto display = std::make_unique<HWC2Display>(*composer, *mCapabilities, mHwcDisplayId,
+ mHwcDisplayType);
auto config = HWC2::Display::Config::Builder(*display, mActiveConfig);
config.setWidth(mWidth);
@@ -482,7 +465,6 @@
int32_t mDpiY = DEFAULT_DPI;
int32_t mActiveConfig = DEFAULT_ACTIVE_CONFIG;
const std::unordered_set<HWC2::Capability>* mCapabilities = nullptr;
- Hwc2::PowerAdvisor* mPowerAdvisor = nullptr;
};
class FakeDisplayDeviceInjector {
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.h
index dc6d83b..7c65f95 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.h
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.h
@@ -29,7 +29,7 @@
PowerAdvisor();
~PowerAdvisor() override;
- MOCK_METHOD2(setExpensiveRenderingExpected, void(hwc2_display_t displayId, bool expected));
+ MOCK_METHOD2(setExpensiveRenderingExpected, void(DisplayId displayId, bool expected));
};
} // namespace mock
diff --git a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
index 5edee6e..cb4a300 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
@@ -33,6 +33,7 @@
MOCK_METHOD0(onScreenReleased, void());
MOCK_METHOD0(onScreenAcquired, void());
MOCK_METHOD2(onHotplugReceived, void(PhysicalDisplayId, bool));
+ MOCK_METHOD2(onConfigChanged, void(PhysicalDisplayId, int32_t));
MOCK_CONST_METHOD1(dump, void(std::string&));
MOCK_METHOD1(setPhaseOffset, void(nsecs_t phaseOffset));
MOCK_METHOD1(registerDisplayEventConnection,
diff --git a/services/vr/bufferhubd/producer_channel.cpp b/services/vr/bufferhubd/producer_channel.cpp
index b49d894..a7fd912 100644
--- a/services/vr/bufferhubd/producer_channel.cpp
+++ b/services/vr/bufferhubd/producer_channel.cpp
@@ -392,8 +392,8 @@
Status<void> ProducerChannel::OnProducerPost(Message&,
LocalFence acquire_fence) {
ATRACE_NAME("ProducerChannel::OnProducerPost");
- ALOGD("ProducerChannel::OnProducerPost: buffer_id=%d, state=0x%x",
- buffer_id(), buffer_state_->load(std::memory_order_acquire));
+ ALOGD_IF(TRACE, "%s: buffer_id=%d, state=0x%x", __FUNCTION__, buffer_id(),
+ buffer_state_->load(std::memory_order_acquire));
epoll_event event;
event.events = 0;
@@ -437,7 +437,7 @@
Status<LocalFence> ProducerChannel::OnProducerGain(Message& /*message*/) {
ATRACE_NAME("ProducerChannel::OnGain");
- ALOGW("ProducerChannel::OnGain: buffer_id=%d", buffer_id());
+ ALOGD_IF(TRACE, "%s: buffer_id=%d", __FUNCTION__, buffer_id());
ClearAvailable();
post_fence_.close();
diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp
index 32e19f7..73fc7b2 100644
--- a/vulkan/libvulkan/swapchain.cpp
+++ b/vulkan/libvulkan/swapchain.cpp
@@ -688,6 +688,8 @@
{VK_FORMAT_R8G8B8A8_UNORM, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR},
{VK_FORMAT_R8G8B8A8_SRGB, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR},
{VK_FORMAT_R5G6B5_UNORM_PACK16, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR},
+ {VK_FORMAT_A2B10G10R10_UNORM_PACK32, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR},
+ {VK_FORMAT_R16G16B16A16_SFLOAT, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR},
};
const uint32_t kNumFormats = sizeof(kFormats) / sizeof(kFormats[0]);
uint32_t total_num_formats = kNumFormats;