Merge "Flag invalid robust access attribute"
diff --git a/cmds/atrace/atrace.cpp b/cmds/atrace/atrace.cpp
index 53b3a00..bd3d2d8 100644
--- a/cmds/atrace/atrace.cpp
+++ b/cmds/atrace/atrace.cpp
@@ -99,30 +99,31 @@
/* Tracing categories */
static const TracingCategory k_categories[] = {
- { "gfx", "Graphics", ATRACE_TAG_GRAPHICS, { } },
- { "input", "Input", ATRACE_TAG_INPUT, { } },
- { "view", "View System", ATRACE_TAG_VIEW, { } },
- { "webview", "WebView", ATRACE_TAG_WEBVIEW, { } },
- { "wm", "Window Manager", ATRACE_TAG_WINDOW_MANAGER, { } },
- { "am", "Activity Manager", ATRACE_TAG_ACTIVITY_MANAGER, { } },
- { "sm", "Sync Manager", ATRACE_TAG_SYNC_MANAGER, { } },
- { "audio", "Audio", ATRACE_TAG_AUDIO, { } },
- { "video", "Video", ATRACE_TAG_VIDEO, { } },
- { "camera", "Camera", ATRACE_TAG_CAMERA, { } },
- { "hal", "Hardware Modules", ATRACE_TAG_HAL, { } },
- { "res", "Resource Loading", ATRACE_TAG_RESOURCES, { } },
- { "dalvik", "Dalvik VM", ATRACE_TAG_DALVIK, { } },
- { "rs", "RenderScript", ATRACE_TAG_RS, { } },
- { "bionic", "Bionic C Library", ATRACE_TAG_BIONIC, { } },
- { "power", "Power Management", ATRACE_TAG_POWER, { } },
- { "pm", "Package Manager", ATRACE_TAG_PACKAGE_MANAGER, { } },
- { "ss", "System Server", ATRACE_TAG_SYSTEM_SERVER, { } },
- { "database", "Database", ATRACE_TAG_DATABASE, { } },
- { "network", "Network", ATRACE_TAG_NETWORK, { } },
- { "adb", "ADB", ATRACE_TAG_ADB, { } },
- { "vibrator", "Vibrator", ATRACE_TAG_VIBRATOR, { } },
- { "aidl", "AIDL calls", ATRACE_TAG_AIDL, { } },
- { "nnapi", "NNAPI", ATRACE_TAG_NNAPI, { } },
+ { "gfx", "Graphics", ATRACE_TAG_GRAPHICS, { } },
+ { "input", "Input", ATRACE_TAG_INPUT, { } },
+ { "view", "View System", ATRACE_TAG_VIEW, { } },
+ { "webview", "WebView", ATRACE_TAG_WEBVIEW, { } },
+ { "wm", "Window Manager", ATRACE_TAG_WINDOW_MANAGER, { } },
+ { "am", "Activity Manager", ATRACE_TAG_ACTIVITY_MANAGER, { } },
+ { "sm", "Sync Manager", ATRACE_TAG_SYNC_MANAGER, { } },
+ { "audio", "Audio", ATRACE_TAG_AUDIO, { } },
+ { "video", "Video", ATRACE_TAG_VIDEO, { } },
+ { "camera", "Camera", ATRACE_TAG_CAMERA, { } },
+ { "hal", "Hardware Modules", ATRACE_TAG_HAL, { } },
+ { "res", "Resource Loading", ATRACE_TAG_RESOURCES, { } },
+ { "dalvik", "Dalvik VM", ATRACE_TAG_DALVIK, { } },
+ { "rs", "RenderScript", ATRACE_TAG_RS, { } },
+ { "bionic", "Bionic C Library", ATRACE_TAG_BIONIC, { } },
+ { "power", "Power Management", ATRACE_TAG_POWER, { } },
+ { "pm", "Package Manager", ATRACE_TAG_PACKAGE_MANAGER, { } },
+ { "ss", "System Server", ATRACE_TAG_SYSTEM_SERVER, { } },
+ { "database", "Database", ATRACE_TAG_DATABASE, { } },
+ { "network", "Network", ATRACE_TAG_NETWORK, { } },
+ { "adb", "ADB", ATRACE_TAG_ADB, { } },
+ { "vibrator", "Vibrator", ATRACE_TAG_VIBRATOR, { } },
+ { "aidl", "AIDL calls", ATRACE_TAG_AIDL, { } },
+ { "nnapi", "NNAPI", ATRACE_TAG_NNAPI, { } },
+ { "rro", "Runtime Resource Overlay", ATRACE_TAG_RRO, { } },
{ k_coreServiceCategory, "Core services", 0, { } },
{ k_pdxServiceCategory, "PDX services", 0, { } },
{ "sched", "CPU Scheduling", 0, {
diff --git a/cmds/atrace/atrace.rc b/cmds/atrace/atrace.rc
index 9b12a02..a282424 100644
--- a/cmds/atrace/atrace.rc
+++ b/cmds/atrace/atrace.rc
@@ -107,6 +107,10 @@
chmod 0666 /sys/kernel/tracing/events/lowmemorykiller/lowmemory_kill/enable
chmod 0666 /sys/kernel/debug/tracing/events/oom/oom_score_adj_update/enable
chmod 0666 /sys/kernel/tracing/events/oom/oom_score_adj_update/enable
+ chmod 0666 /sys/kernel/debug/tracing/events/task/task_rename/enable
+ chmod 0666 /sys/kernel/tracing/events/task/task_rename/enable
+ chmod 0666 /sys/kernel/debug/tracing/events/task/task_newtask/enable
+ chmod 0666 /sys/kernel/tracing/events/task/task_newtask/enable
# disk
chmod 0666 /sys/kernel/tracing/events/f2fs/f2fs_get_data_block/enable
@@ -140,6 +144,12 @@
chmod 0666 /sys/kernel/tracing/events/block/block_rq_complete/enable
chmod 0666 /sys/kernel/debug/tracing/events/block/block_rq_complete/enable
+ # filemap events for iorapd
+ chmod 0666 /sys/kernel/tracing/events/filemap/mm_filemap_add_to_page_cache/enable
+ chmod 0666 /sys/kernel/debug/tracing/events/filemap/mm_filemap_add_to_page_cache/enable
+ chmod 0666 /sys/kernel/tracing/events/filemap/mm_filemap_delete_from_page_cache/enable
+ chmod 0666 /sys/kernel/debug/tracing/events/filemap/mm_filemap_delete_from_page_cache/enable
+
# Tracing disabled by default
write /sys/kernel/debug/tracing/tracing_on 0
write /sys/kernel/tracing/tracing_on 0
@@ -165,7 +175,7 @@
chmod 0666 /sys/kernel/tracing/per_cpu/cpu5/trace
chmod 0666 /sys/kernel/debug/tracing/per_cpu/cpu6/trace
chmod 0666 /sys/kernel/tracing/per_cpu/cpu6/trace
- chmod 0666 /sys/kernel/debug/tracing/per_cpu/cpu6/trace
+ chmod 0666 /sys/kernel/debug/tracing/per_cpu/cpu7/trace
chmod 0666 /sys/kernel/tracing/per_cpu/cpu7/trace
chmod 0666 /sys/kernel/debug/tracing/per_cpu/cpu8/trace
chmod 0666 /sys/kernel/tracing/per_cpu/cpu8/trace
diff --git a/cmds/atrace/atrace_userdebug.rc b/cmds/atrace/atrace_userdebug.rc
index 5c28c9d..6c86c21 100644
--- a/cmds/atrace/atrace_userdebug.rc
+++ b/cmds/atrace/atrace_userdebug.rc
@@ -5,6 +5,12 @@
# Access control to these files is now entirely in selinux policy.
on post-fs
+ # On userdebug allow to enable any event via the generic
+ # set_event interface:
+ # echo sched/foo > set_event == echo 1 > events/sched/foo/enable.
+ chmod 0666 /sys/kernel/tracing/set_event
+ chmod 0666 /sys/kernel/debug/tracing/set_event
+
chmod 0666 /sys/kernel/tracing/events/workqueue/enable
chmod 0666 /sys/kernel/debug/tracing/events/workqueue/enable
chmod 0666 /sys/kernel/tracing/events/regulator/enable
diff --git a/cmds/cmd/Android.bp b/cmds/cmd/Android.bp
index d91184a..8ea71cd 100644
--- a/cmds/cmd/Android.bp
+++ b/cmds/cmd/Android.bp
@@ -1,7 +1,31 @@
+cc_library_static {
+ name: "libcmd",
+
+ srcs: ["cmd.cpp"],
+ export_include_dirs: ["."],
+
+ shared_libs: [
+ "libutils",
+ "liblog",
+ "libselinux",
+ "libbinder",
+ ],
+
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-DXP_UNIX",
+ ],
+}
+
cc_binary {
name: "cmd",
- srcs: ["cmd.cpp"],
+ srcs: ["main.cpp"],
+
+ static_libs: [
+ "libcmd",
+ ],
shared_libs: [
"libutils",
diff --git a/cmds/cmd/cmd.cpp b/cmds/cmd/cmd.cpp
index 0616add..7b4aeb2 100644
--- a/cmds/cmd/cmd.cpp
+++ b/cmds/cmd/cmd.cpp
@@ -40,6 +40,8 @@
#include "selinux/selinux.h"
#include "selinux/android.h"
+#include "cmd.h"
+
#define DEBUG 0
using namespace android;
@@ -59,8 +61,11 @@
class MyShellCallback : public BnShellCallback
{
public:
+ TextOutput& mErrorLog;
bool mActive = true;
+ MyShellCallback(TextOutput& errorLog) : mErrorLog(errorLog) {}
+
virtual int openFile(const String16& path, const String16& seLinuxContext,
const String16& mode) {
String8 path8(path);
@@ -69,7 +74,7 @@
String8 fullPath(cwd);
fullPath.appendPath(path8);
if (!mActive) {
- aerr << "Open attempt after active for: " << fullPath << endl;
+ mErrorLog << "Open attempt after active for: " << fullPath << endl;
return -EPERM;
}
#if DEBUG
@@ -78,20 +83,20 @@
int flags = 0;
bool checkRead = false;
bool checkWrite = false;
- if (mode == String16("w")) {
+ if (mode == u"w") {
flags = O_WRONLY|O_CREAT|O_TRUNC;
checkWrite = true;
- } else if (mode == String16("w+")) {
+ } else if (mode == u"w+") {
flags = O_RDWR|O_CREAT|O_TRUNC;
checkRead = checkWrite = true;
- } else if (mode == String16("r")) {
+ } else if (mode == u"r") {
flags = O_RDONLY;
checkRead = true;
- } else if (mode == String16("r+")) {
+ } else if (mode == u"r+") {
flags = O_RDWR;
checkRead = checkWrite = true;
} else {
- aerr << "Invalid mode requested: " << mode.string() << endl;
+ mErrorLog << "Invalid mode requested: " << mode.string() << endl;
return -EINVAL;
}
int fd = open(fullPath.string(), flags, S_IRWXU|S_IRWXG);
@@ -114,9 +119,7 @@
ALOGD("openFile: failed selinux write check!");
#endif
close(fd);
- aerr << "System server has no access to write file context " << context.get()
- << " (from path " << fullPath.string() << ", context "
- << seLinuxContext8.string() << ")" << endl;
+ mErrorLog << "System server has no access to write file context " << context.get() << " (from path " << fullPath.string() << ", context " << seLinuxContext8.string() << ")" << endl;
return -EPERM;
}
}
@@ -128,9 +131,7 @@
ALOGD("openFile: failed selinux read check!");
#endif
close(fd);
- aerr << "System server has no access to read file context " << context.get()
- << " (from path " << fullPath.string() << ", context "
- << seLinuxContext8.string() << ")" << endl;
+ mErrorLog << "System server has no access to read file context " << context.get() << " (from path " << fullPath.string() << ", context " << seLinuxContext8.string() << ")" << endl;
return -EPERM;
}
}
@@ -163,9 +164,8 @@
}
};
-int main(int argc, char* const argv[])
-{
- signal(SIGPIPE, SIG_IGN);
+int cmdMain(const std::vector<std::string_view>& argv, TextOutput& outputLog, TextOutput& errorLog,
+ int in, int out, int err, RunMode runMode) {
sp<ProcessState> proc = ProcessState::self();
proc->startThreadPool();
@@ -173,68 +173,77 @@
ALOGD("cmd: starting");
#endif
sp<IServiceManager> sm = defaultServiceManager();
- fflush(stdout);
+ if (runMode == RunMode::kStandalone) {
+ fflush(stdout);
+ }
if (sm == nullptr) {
ALOGW("Unable to get default service manager!");
- aerr << "cmd: Unable to get default service manager!" << endl;
+ errorLog << "cmd: Unable to get default service manager!" << endl;
return 20;
}
- if (argc == 1) {
- aerr << "cmd: No service specified; use -l to list all services" << endl;
+ int argc = argv.size();
+
+ if (argc == 0) {
+ errorLog << "cmd: No service specified; use -l to list all services" << endl;
return 20;
}
- if ((argc == 2) && (strcmp(argv[1], "-l") == 0)) {
+ if ((argc == 1) && (argv[0] == "-l")) {
Vector<String16> services = sm->listServices();
services.sort(sort_func);
- aout << "Currently running services:" << endl;
+ outputLog << "Currently running services:" << endl;
for (size_t i=0; i<services.size(); i++) {
sp<IBinder> service = sm->checkService(services[i]);
if (service != nullptr) {
- aout << " " << services[i] << endl;
+ outputLog << " " << services[i] << endl;
}
}
return 0;
}
+ const auto cmd = argv[0];
+
Vector<String16> args;
- for (int i=2; i<argc; i++) {
- args.add(String16(argv[i]));
+ String16 serviceName = String16(cmd.data(), cmd.size());
+ for (int i = 1; i < argc; i++) {
+ args.add(String16(argv[i].data(), argv[i].size()));
}
- String16 cmd = String16(argv[1]);
- sp<IBinder> service = sm->checkService(cmd);
+ sp<IBinder> service = sm->checkService(serviceName);
if (service == nullptr) {
- ALOGW("Can't find service %s", argv[1]);
- aerr << "cmd: Can't find service: " << argv[1] << endl;
+ if (runMode == RunMode::kStandalone) {
+ ALOGW("Can't find service %.*s", static_cast<int>(cmd.size()), cmd.data());
+ }
+ errorLog << "cmd: Can't find service: " << cmd << endl;
return 20;
}
- sp<MyShellCallback> cb = new MyShellCallback();
+ sp<MyShellCallback> cb = new MyShellCallback(errorLog);
sp<MyResultReceiver> result = new MyResultReceiver();
#if DEBUG
- ALOGD("cmd: Invoking %s in=%d, out=%d, err=%d", argv[1], STDIN_FILENO, STDOUT_FILENO,
- STDERR_FILENO);
+ ALOGD("cmd: Invoking %s in=%d, out=%d, err=%d", cmd, in, out, err);
#endif
// TODO: block until a result is returned to MyResultReceiver.
- status_t err = IBinder::shellCommand(service, STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO, args,
- cb, result);
- if (err < 0) {
+ status_t error = IBinder::shellCommand(service, in, out, err, args, cb, result);
+ if (error < 0) {
const char* errstr;
- switch (err) {
+ switch (error) {
case BAD_TYPE: errstr = "Bad type"; break;
case FAILED_TRANSACTION: errstr = "Failed transaction"; break;
case FDS_NOT_ALLOWED: errstr = "File descriptors not allowed"; break;
case UNEXPECTED_NULL: errstr = "Unexpected null"; break;
- default: errstr = strerror(-err); break;
+ default: errstr = strerror(-error); break;
}
- ALOGW("Failure calling service %s: %s (%d)", argv[1], errstr, -err);
- aout << "cmd: Failure calling service " << argv[1] << ": " << errstr << " ("
- << (-err) << ")" << endl;
- return err;
+ if (runMode == RunMode::kStandalone) {
+ ALOGW("Failure calling service %.*s: %s (%d)", static_cast<int>(cmd.size()), cmd.data(),
+ errstr, -error);
+ }
+ outputLog << "cmd: Failure calling service " << cmd << ": " << errstr << " (" << (-error)
+ << ")" << endl;
+ return error;
}
cb->mActive = false;
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplaySurface.cpp b/cmds/cmd/cmd.h
similarity index 65%
copy from services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplaySurface.cpp
copy to cmds/cmd/cmd.h
index e6ac6bf..a91e009 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplaySurface.cpp
+++ b/cmds/cmd/cmd.h
@@ -14,14 +14,17 @@
* limitations under the License.
*/
-#include "mock/DisplayHardware/MockDisplaySurface.h"
+#pragma once
-namespace android {
-namespace mock {
+#include <binder/TextOutput.h>
-// Explicit default instantiation is recommended.
-DisplaySurface::DisplaySurface() = default;
-DisplaySurface::~DisplaySurface() = default;
+#include <string_view>
+#include <vector>
-} // namespace mock
-} // namespace android
+enum class RunMode {
+ kStandalone,
+ kLibrary,
+};
+
+int cmdMain(const std::vector<std::string_view>& argv, android::TextOutput& outputLog,
+ android::TextOutput& errorLog, int in, int out, int err, RunMode runMode);
diff --git a/cmds/cmd/main.cpp b/cmds/cmd/main.cpp
new file mode 100644
index 0000000..2256e2a
--- /dev/null
+++ b/cmds/cmd/main.cpp
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <unistd.h>
+
+#include "cmd.h"
+
+int main(int argc, char* const argv[]) {
+ signal(SIGPIPE, SIG_IGN);
+
+ std::vector<std::string_view> arguments;
+ arguments.reserve(argc - 1);
+ // 0th argument is a program name, skipping.
+ for (int i = 1; i < argc; ++i) {
+ arguments.emplace_back(argv[i]);
+ }
+
+ return cmdMain(arguments, android::aout, android::aerr, STDIN_FILENO, STDOUT_FILENO,
+ STDERR_FILENO, RunMode::kStandalone);
+}
diff --git a/cmds/dumpstate/Android.bp b/cmds/dumpstate/Android.bp
index 9aa1075..ee32cb4 100644
--- a/cmds/dumpstate/Android.bp
+++ b/cmds/dumpstate/Android.bp
@@ -57,7 +57,6 @@
export_aidl_headers: true,
},
srcs: [
- "binder/android/os/DumpstateOptions.cpp",
":dumpstate_aidl",
],
export_include_dirs: ["binder"],
@@ -68,7 +67,6 @@
srcs: [
"binder/android/os/IDumpstateListener.aidl",
"binder/android/os/IDumpstateToken.aidl",
- //"binder/android/os/DumpstateOptions.aidl",
"binder/android/os/IDumpstate.aidl",
],
path: "binder",
@@ -99,8 +97,9 @@
"utils.cpp",
],
static_libs: [
+ "libincidentcompanion",
"libdumpsys",
- "libserviceutils"
+ "libserviceutils",
],
}
@@ -158,3 +157,22 @@
],
static_libs: ["libgmock"],
}
+
+
+// =======================#
+// dumpstate_test_fixture #
+// =======================#
+cc_test {
+
+ name: "dumpstate_test_fixture",
+ test_suites: ["device-tests"],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-Wno-missing-field-initializers",
+ "-Wno-unused-variable",
+ "-Wunused-parameter",
+ ],
+ srcs: ["tests/dumpstate_test_fixture.cpp"],
+ data: ["tests/testdata/**/*"],
+}
diff --git a/cmds/dumpstate/Android.mk b/cmds/dumpstate/Android.mk
deleted file mode 100644
index ea5fbf1..0000000
--- a/cmds/dumpstate/Android.mk
+++ /dev/null
@@ -1,22 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-
-# =======================#
-# dumpstate_test_fixture #
-# =======================#
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := dumpstate_test_fixture
-LOCAL_COMPATIBILITY_SUITE := device-tests
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_CFLAGS := \
- -Wall -Werror -Wno-missing-field-initializers -Wno-unused-variable -Wunused-parameter
-
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-
-LOCAL_SRC_FILES := \
- tests/dumpstate_test_fixture.cpp
-
-LOCAL_TEST_DATA := $(call find-test-data-in-subdirs, $(LOCAL_PATH), *, tests/testdata)
-
-include $(BUILD_NATIVE_TEST)
diff --git a/cmds/dumpstate/DumpstateService.cpp b/cmds/dumpstate/DumpstateService.cpp
index 849eb44..bb089e6 100644
--- a/cmds/dumpstate/DumpstateService.cpp
+++ b/cmds/dumpstate/DumpstateService.cpp
@@ -18,8 +18,9 @@
#include "DumpstateService.h"
-#include <android-base/stringprintf.h>
+#include <memory>
+#include <android-base/stringprintf.h>
#include "android/os/BnDumpstate.h"
#include "DumpstateInternal.h"
@@ -31,6 +32,13 @@
namespace {
+struct DumpstateInfo {
+ public:
+ Dumpstate* ds = nullptr;
+ int32_t calling_uid = -1;
+ std::string calling_package;
+};
+
static binder::Status exception(uint32_t code, const std::string& msg) {
MYLOGE("%s (%d) ", msg.c_str(), code);
return binder::Status::fromExceptionCode(code, String8(msg.c_str()));
@@ -41,18 +49,19 @@
return binder::Status::fromServiceSpecificError(code, String8(msg.c_str()));
}
+// Takes ownership of data.
static void* callAndNotify(void* data) {
- Dumpstate& ds = *static_cast<Dumpstate*>(data);
- // TODO(111441001): Return status on listener.
- ds.Run();
- MYLOGE("Finished Run()\n");
+ std::unique_ptr<DumpstateInfo> ds_info(static_cast<DumpstateInfo*>(data));
+ ds_info->ds->Run(ds_info->calling_uid, ds_info->calling_package);
+ MYLOGD("Finished Run()\n");
return nullptr;
}
class DumpstateToken : public BnDumpstateToken {};
-}
-DumpstateService::DumpstateService() : ds_(Dumpstate::GetInstance()) {
+} // namespace
+
+DumpstateService::DumpstateService() : ds_(nullptr) {
}
char const* DumpstateService::getServiceName() {
@@ -71,6 +80,8 @@
return android::OK;
}
+// Note: this method is part of the old flow and is not expected to be used in combination
+// with startBugreport.
binder::Status DumpstateService::setListener(const std::string& name,
const sp<IDumpstateListener>& listener,
bool getSectionDetails,
@@ -85,22 +96,28 @@
return binder::Status::ok();
}
std::lock_guard<std::mutex> lock(lock_);
- if (ds_.listener_ != nullptr) {
- MYLOGE("setListener(%s): already set (%s)\n", name.c_str(), ds_.listener_name_.c_str());
+ if (ds_ == nullptr) {
+ ds_ = &(Dumpstate::GetInstance());
+ }
+ if (ds_->listener_ != nullptr) {
+ MYLOGE("setListener(%s): already set (%s)\n", name.c_str(), ds_->listener_name_.c_str());
return binder::Status::ok();
}
- ds_.listener_name_ = name;
- ds_.listener_ = listener;
- ds_.report_section_ = getSectionDetails;
+ ds_->listener_name_ = name;
+ ds_->listener_ = listener;
+ ds_->report_section_ = getSectionDetails;
*returned_token = new DumpstateToken();
return binder::Status::ok();
}
-binder::Status DumpstateService::startBugreport(int, int bugreport_mode, int32_t* returned_id) {
- // TODO(111441001): return a request id here.
- *returned_id = -1;
+binder::Status DumpstateService::startBugreport(int32_t calling_uid,
+ const std::string& calling_package,
+ const android::base::unique_fd& bugreport_fd,
+ const android::base::unique_fd& screenshot_fd,
+ int bugreport_mode,
+ const sp<IDumpstateListener>& listener) {
MYLOGI("startBugreport() with mode: %d\n", bugreport_mode);
if (bugreport_mode != Dumpstate::BugreportMode::BUGREPORT_FULL &&
@@ -114,43 +131,81 @@
StringPrintf("Invalid bugreport mode: %d", bugreport_mode));
}
+ if (bugreport_fd.get() == -1 || screenshot_fd.get() == -1) {
+ return exception(binder::Status::EX_ILLEGAL_ARGUMENT, "Invalid file descriptor");
+ }
+
std::unique_ptr<Dumpstate::DumpOptions> options = std::make_unique<Dumpstate::DumpOptions>();
- options->Initialize(static_cast<Dumpstate::BugreportMode>(bugreport_mode));
- ds_.SetOptions(std::move(options));
+ options->Initialize(static_cast<Dumpstate::BugreportMode>(bugreport_mode), bugreport_fd,
+ screenshot_fd);
+
+ // This is the bugreporting API flow, so ensure there is only one bugreport in progress at a
+ // time.
+ std::lock_guard<std::mutex> lock(lock_);
+ if (ds_ != nullptr) {
+ return exception(binder::Status::EX_SERVICE_SPECIFIC,
+ "There is already a bugreport in progress");
+ }
+ ds_ = &(Dumpstate::GetInstance());
+ ds_->SetOptions(std::move(options));
+ if (listener != nullptr) {
+ ds_->listener_ = listener;
+ }
+
+ DumpstateInfo* ds_info = new DumpstateInfo();
+ ds_info->ds = ds_;
+ ds_info->calling_uid = calling_uid;
+ ds_info->calling_package = calling_package;
pthread_t thread;
- status_t err = pthread_create(&thread, nullptr, callAndNotify, &ds_);
+ status_t err = pthread_create(&thread, nullptr, callAndNotify, ds_info);
if (err != 0) {
+ delete ds_info;
+ ds_info = nullptr;
return error(err, "Could not create a background thread.");
}
return binder::Status::ok();
}
+binder::Status DumpstateService::cancelBugreport() {
+ // This is a no-op since the cancellation is done from java side via setting sys properties.
+ // See BugreportManagerServiceImpl.
+ // TODO(b/111441001): maybe make native and java sides use different binder interface
+ // to avoid these annoyances.
+ return binder::Status::ok();
+}
+
status_t DumpstateService::dump(int fd, const Vector<String16>&) {
- dprintf(fd, "id: %d\n", ds_.id_);
- dprintf(fd, "pid: %d\n", ds_.pid_);
- dprintf(fd, "update_progress: %s\n", ds_.options_->do_progress_updates ? "true" : "false");
- dprintf(fd, "update_progress_threshold: %d\n", ds_.update_progress_threshold_);
- dprintf(fd, "last_updated_progress: %d\n", ds_.last_updated_progress_);
+ if (ds_ == nullptr) {
+ dprintf(fd, "Bugreport not in progress yet");
+ return NO_ERROR;
+ }
+ std::string destination = ds_->options_->bugreport_fd.get() != -1
+ ? StringPrintf("[fd:%d]", ds_->options_->bugreport_fd.get())
+ : ds_->bugreport_internal_dir_.c_str();
+ dprintf(fd, "id: %d\n", ds_->id_);
+ dprintf(fd, "pid: %d\n", ds_->pid_);
+ dprintf(fd, "update_progress: %s\n", ds_->options_->do_progress_updates ? "true" : "false");
+ dprintf(fd, "update_progress_threshold: %d\n", ds_->update_progress_threshold_);
+ dprintf(fd, "last_updated_progress: %d\n", ds_->last_updated_progress_);
dprintf(fd, "progress:\n");
- ds_.progress_->Dump(fd, " ");
- dprintf(fd, "args: %s\n", ds_.options_->args.c_str());
- dprintf(fd, "extra_options: %s\n", ds_.options_->extra_options.c_str());
- dprintf(fd, "version: %s\n", ds_.version_.c_str());
- dprintf(fd, "bugreport_dir: %s\n", ds_.bugreport_dir_.c_str());
- dprintf(fd, "bugreport_internal_dir_: %s\n", ds_.bugreport_internal_dir_.c_str());
- dprintf(fd, "screenshot_path: %s\n", ds_.screenshot_path_.c_str());
- dprintf(fd, "log_path: %s\n", ds_.log_path_.c_str());
- dprintf(fd, "tmp_path: %s\n", ds_.tmp_path_.c_str());
- dprintf(fd, "path: %s\n", ds_.path_.c_str());
- dprintf(fd, "extra_options: %s\n", ds_.options_->extra_options.c_str());
- dprintf(fd, "base_name: %s\n", ds_.base_name_.c_str());
- dprintf(fd, "name: %s\n", ds_.name_.c_str());
- dprintf(fd, "now: %ld\n", ds_.now_);
- dprintf(fd, "is_zipping: %s\n", ds_.IsZipping() ? "true" : "false");
- dprintf(fd, "listener: %s\n", ds_.listener_name_.c_str());
- dprintf(fd, "notification title: %s\n", ds_.options_->notification_title.c_str());
- dprintf(fd, "notification description: %s\n", ds_.options_->notification_description.c_str());
+ ds_->progress_->Dump(fd, " ");
+ dprintf(fd, "args: %s\n", ds_->options_->args.c_str());
+ dprintf(fd, "extra_options: %s\n", ds_->options_->extra_options.c_str());
+ dprintf(fd, "version: %s\n", ds_->version_.c_str());
+ dprintf(fd, "bugreport_dir: %s\n", destination.c_str());
+ dprintf(fd, "screenshot_path: %s\n", ds_->screenshot_path_.c_str());
+ dprintf(fd, "log_path: %s\n", ds_->log_path_.c_str());
+ dprintf(fd, "tmp_path: %s\n", ds_->tmp_path_.c_str());
+ dprintf(fd, "path: %s\n", ds_->path_.c_str());
+ dprintf(fd, "extra_options: %s\n", ds_->options_->extra_options.c_str());
+ dprintf(fd, "base_name: %s\n", ds_->base_name_.c_str());
+ dprintf(fd, "name: %s\n", ds_->name_.c_str());
+ dprintf(fd, "now: %ld\n", ds_->now_);
+ dprintf(fd, "is_zipping: %s\n", ds_->IsZipping() ? "true" : "false");
+ dprintf(fd, "listener: %s\n", ds_->listener_name_.c_str());
+ dprintf(fd, "notification title: %s\n", ds_->options_->notification_title.c_str());
+ dprintf(fd, "notification description: %s\n", ds_->options_->notification_description.c_str());
return NO_ERROR;
}
diff --git a/cmds/dumpstate/DumpstateService.h b/cmds/dumpstate/DumpstateService.h
index 58095b3..68eda47 100644
--- a/cmds/dumpstate/DumpstateService.h
+++ b/cmds/dumpstate/DumpstateService.h
@@ -20,6 +20,7 @@
#include <mutex>
#include <vector>
+#include <android-base/unique_fd.h>
#include <binder/BinderService.h>
#include "android/os/BnDumpstate.h"
@@ -41,10 +42,20 @@
bool getSectionDetails,
sp<IDumpstateToken>* returned_token) override;
- binder::Status startBugreport(int fd, int bugreport_mode, int32_t* returned_id) override;
+ binder::Status startBugreport(int32_t calling_uid, const std::string& calling_package,
+ const android::base::unique_fd& bugreport_fd,
+ const android::base::unique_fd& screenshot_fd, int bugreport_mode,
+ const sp<IDumpstateListener>& listener) override;
+
+ // No-op
+ binder::Status cancelBugreport();
private:
- Dumpstate& ds_;
+ // Dumpstate object which contains all the bugreporting logic.
+ // Note that dumpstate is a oneshot service, so this object is meant to be used at most for
+ // one bugreport.
+ // This service does not own this object.
+ Dumpstate* ds_;
std::mutex lock_;
};
diff --git a/cmds/dumpstate/README.md b/cmds/dumpstate/README.md
index 6ac17d8..273a5a6 100644
--- a/cmds/dumpstate/README.md
+++ b/cmds/dumpstate/README.md
@@ -49,7 +49,7 @@
Then run:
```
-mmm -j frameworks/native/cmds/dumpstate/ && adb push ${OUT}/data/nativetest64/dumpstate_test* /data/nativetest64 && adb shell /data/nativetest64/dumpstate_test/dumpstate_test
+mmm -j frameworks/native/cmds/dumpstate/ && adb push ${OUT}/data/nativetest64/dumpstate_* /data/nativetest64 && adb shell /data/nativetest64/dumpstate_test/dumpstate_test
```
And to run just one test (for example, `DumpstateTest.RunCommandNoArgs`):
diff --git a/cmds/dumpstate/binder/android/os/DumpstateOptions.cpp b/cmds/dumpstate/binder/android/os/DumpstateOptions.cpp
deleted file mode 100644
index 5654190..0000000
--- a/cmds/dumpstate/binder/android/os/DumpstateOptions.cpp
+++ /dev/null
@@ -1,46 +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.
- */
-
-#include <android/os/DumpstateOptions.h>
-
-#include <binder/IBinder.h>
-#include <binder/Parcel.h>
-
-namespace android {
-namespace os {
-
-status_t DumpstateOptions::readFromParcel(const ::android::Parcel* parcel) {
- if (status_t err = parcel->readBool(&get_section_details)) {
- return err;
- }
- if (status_t err = parcel->readUtf8FromUtf16(&name)) {
- return err;
- }
- return android::OK;
-}
-
-status_t DumpstateOptions::writeToParcel(::android::Parcel* parcel) const {
- if (status_t err = parcel->writeBool(get_section_details)) {
- return err;
- }
- if (status_t err = parcel->writeUtf8AsUtf16(name)) {
- return err;
- }
- return android::OK;
-}
-
-} // namespace os
-} // namespace android
diff --git a/cmds/dumpstate/binder/android/os/DumpstateOptions.h b/cmds/dumpstate/binder/android/os/DumpstateOptions.h
deleted file mode 100644
index a748e3c..0000000
--- a/cmds/dumpstate/binder/android/os/DumpstateOptions.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_OS_DUMPSTATE_OPTIONS_H_
-#define ANDROID_OS_DUMPSTATE_OPTIONS_H_
-
-#include <binder/Parcelable.h>
-
-namespace android {
-namespace os {
-
-struct DumpstateOptions : public android::Parcelable {
- // If true the caller can get callbacks with per-section progress details.
- bool get_section_details = false;
-
- // Name of the caller.
- std::string name;
-
- status_t writeToParcel(android::Parcel* parcel) const override;
- status_t readFromParcel(const android::Parcel* parcel) override;
-};
-
-} // namespace os
-} // namespace android
-
-#endif // ANDROID_OS_DUMPSTATE_OPTIONS_H_
diff --git a/cmds/dumpstate/binder/android/os/IDumpstate.aidl b/cmds/dumpstate/binder/android/os/IDumpstate.aidl
index 617eab3..b1005d3 100644
--- a/cmds/dumpstate/binder/android/os/IDumpstate.aidl
+++ b/cmds/dumpstate/binder/android/os/IDumpstate.aidl
@@ -18,15 +18,12 @@
import android.os.IDumpstateListener;
import android.os.IDumpstateToken;
-import android.os.DumpstateOptions;
/**
* Binder interface for the currently running dumpstate process.
* {@hide}
*/
interface IDumpstate {
-
-
// TODO: remove method once startBugReport is used by Shell.
/*
* Sets the listener for this dumpstate progress.
@@ -61,8 +58,29 @@
// Default mode.
const int BUGREPORT_MODE_DEFAULT = 6;
+ // TODO(b/111441001): Should the args be for the consuming application rather than triggering?
/*
* Starts a bugreport in the background.
+ *
+ *<p>Shows the user a dialog to get consent for sharing the bugreport with the calling
+ * application. If they deny {@link IDumpstateListener#onError} will be called. If they
+ * consent and bugreport generation is successful artifacts will be copied to the given fds and
+ * {@link IDumpstateListener#onFinished} will be called. If there
+ * are errors in bugreport generation {@link IDumpstateListener#onError} will be called.
+ *
+ * @param callingUid UID of the original application that requested the report.
+ * @param callingPackage package of the original application that requested the report.
+ * @param bugreportFd the file to which the zipped bugreport should be written
+ * @param screenshotFd the file to which screenshot should be written; optional
+ * @param bugreportMode the mode that specifies other run time options; must be one of above
+ * @param listener callback for updates; optional
*/
- int startBugreport(int fd, int bugreportMode);
+ void startBugreport(int callingUid, @utf8InCpp String callingPackage,
+ FileDescriptor bugreportFd, FileDescriptor screenshotFd,
+ int bugreportMode, IDumpstateListener listener);
+
+ /*
+ * Cancels the bugreport currently in progress.
+ */
+ void cancelBugreport();
}
diff --git a/cmds/dumpstate/binder/android/os/IDumpstateListener.aidl b/cmds/dumpstate/binder/android/os/IDumpstateListener.aidl
index 030d69d..907a67c 100644
--- a/cmds/dumpstate/binder/android/os/IDumpstateListener.aidl
+++ b/cmds/dumpstate/binder/android/os/IDumpstateListener.aidl
@@ -22,18 +22,49 @@
* {@hide}
*/
interface IDumpstateListener {
+ /**
+ * Called when there is a progress update.
+ *
+ * @param progress the progress in [0, 100]
+ */
+ oneway void onProgress(int progress);
+
+ /* Options specified are invalid or incompatible */
+ const int BUGREPORT_ERROR_INVALID_INPUT = 1;
+
+ /* Bugreport encountered a runtime error */
+ const int BUGREPORT_ERROR_RUNTIME_ERROR = 2;
+
+ /* User denied consent to share the bugreport with the specified app */
+ const int BUGREPORT_ERROR_USER_DENIED_CONSENT = 3;
+
+ /* The request to get user consent timed out */
+ const int BUGREPORT_ERROR_USER_CONSENT_TIMED_OUT = 4;
+
+ /**
+ * Called on an error condition with one of the error codes listed above.
+ */
+ oneway void onError(int errorCode);
+
+ /**
+ * Called when taking bugreport finishes successfully.
+ */
+ oneway void onFinished();
+
+ // TODO(b/111441001): Remove old methods when not used anymore.
void onProgressUpdated(int progress);
void onMaxProgressUpdated(int maxProgress);
/**
- * Called after every section is complete.
- * @param name section name
- * @param status values from status_t
- * {@code OK} section completed successfully
- * {@code TIMEOUT} dump timed out
- * {@code != OK} error
- * @param size size in bytes, may be invalid if status != OK
- * @param durationMs duration in ms
- */
+ * Called after every section is complete.
+ *
+ * @param name section name
+ * @param status values from status_t
+ * {@code OK} section completed successfully
+ * {@code TIMEOUT} dump timed out
+ * {@code != OK} error
+ * @param size size in bytes, may be invalid if status != OK
+ * @param durationMs duration in ms
+ */
void onSectionComplete(@utf8InCpp String name, int status, int size, int durationMs);
}
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 516e3d8..db8848a 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -51,6 +51,7 @@
#include <android-base/unique_fd.h>
#include <android/hardware/dumpstate/1.0/IDumpstateDevice.h>
#include <android/hidl/manager/1.0/IServiceManager.h>
+#include <android/os/IIncidentCompanion.h>
#include <cutils/native_handle.h>
#include <cutils/properties.h>
#include <dumpsys.h>
@@ -83,15 +84,19 @@
using android::UNKNOWN_ERROR;
using android::Vector;
using android::base::StringPrintf;
+using android::os::IDumpstateListener;
using android::os::dumpstate::CommandOptions;
using android::os::dumpstate::DumpFileToFd;
using android::os::dumpstate::DumpstateSectionReporter;
using android::os::dumpstate::GetPidByName;
using android::os::dumpstate::PropertiesHelper;
+typedef Dumpstate::ConsentCallback::ConsentResult UserConsentResult;
+
/* read before root is shed */
static char cmdline_buf[16384] = "(unknown)";
static const char *dump_traces_path = nullptr;
+static const uint64_t USER_CONSENT_TIMEOUT_MS = 30 * 1000;
// TODO: variables and functions below should be part of dumpstate object
@@ -135,10 +140,6 @@
return fd;
}
-static int OpenForWrite(std::string path) {
- return Open(path, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW,
- S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
-}
static int OpenForRead(std::string path) {
return Open(path, O_RDONLY | O_CLOEXEC | O_NOFOLLOW);
@@ -169,16 +170,12 @@
return false;
}
-static bool CopyFileToFile(const std::string& input_file, const std::string& output_file) {
- if (input_file == output_file) {
- MYLOGD("Skipping copying bugreport file since the destination is the same (%s)\n",
- output_file.c_str());
+static bool UnlinkAndLogOnError(const std::string& file) {
+ if (unlink(file.c_str()) != -1) {
+ MYLOGE("Failed to remove file (%s): %s\n", file.c_str(), strerror(errno));
return false;
}
-
- MYLOGD("Going to copy bugreport file (%s) to %s\n", input_file.c_str(), output_file.c_str());
- android::base::unique_fd out_fd(OpenForWrite(output_file));
- return CopyFileToFd(input_file, out_fd.get());
+ return true;
}
} // namespace
@@ -475,47 +472,6 @@
return false;
}
-static void dump_systrace() {
- if (!ds.IsZipping()) {
- MYLOGD("Not dumping systrace because it's not a zipped bugreport\n");
- return;
- }
- std::string systrace_path = ds.GetPath("-systrace.txt");
- if (systrace_path.empty()) {
- MYLOGE("Not dumping systrace because path is empty\n");
- return;
- }
- const char* path = "/sys/kernel/debug/tracing/tracing_on";
- long int is_tracing;
- if (read_file_as_long(path, &is_tracing)) {
- return; // error already logged
- }
- if (is_tracing <= 0) {
- MYLOGD("Skipping systrace because '%s' content is '%ld'\n", path, is_tracing);
- return;
- }
-
- MYLOGD("Running '/system/bin/atrace --async_dump -o %s', which can take several minutes",
- systrace_path.c_str());
- if (RunCommand("SYSTRACE", {"/system/bin/atrace", "--async_dump", "-o", systrace_path},
- CommandOptions::WithTimeout(120).Build())) {
- MYLOGE("systrace timed out, its zip entry will be incomplete\n");
- // TODO: RunCommand tries to kill the process, but atrace doesn't die
- // peacefully; ideally, we should call strace to stop itself, but there is no such option
- // yet (just a --async_stop, which stops and dump
- // if (RunCommand("SYSTRACE", {"/system/bin/atrace", "--kill"})) {
- // MYLOGE("could not stop systrace ");
- // }
- }
- if (!ds.AddZipEntry("systrace.txt", systrace_path)) {
- MYLOGE("Unable to add systrace file %s to zip file\n", systrace_path.c_str());
- } else {
- if (remove(systrace_path.c_str())) {
- MYLOGE("Error removing systrace file %s: %s", systrace_path.c_str(), strerror(errno));
- }
- }
-}
-
static bool skip_not_stat(const char *path) {
static const char stat[] = "/stat";
size_t len = strlen(path);
@@ -713,6 +669,32 @@
return timeout_ms > MINIMUM_LOGCAT_TIMEOUT_MS ? timeout_ms : MINIMUM_LOGCAT_TIMEOUT_MS;
}
+Dumpstate::ConsentCallback::ConsentCallback() : result_(UNAVAILABLE), start_time_(Nanotime()) {
+}
+
+android::binder::Status Dumpstate::ConsentCallback::onReportApproved() {
+ std::lock_guard<std::mutex> lock(lock_);
+ result_ = APPROVED;
+ MYLOGD("User approved consent to share bugreport\n");
+ return android::binder::Status::ok();
+}
+
+android::binder::Status Dumpstate::ConsentCallback::onReportDenied() {
+ std::lock_guard<std::mutex> lock(lock_);
+ result_ = DENIED;
+ MYLOGW("User denied consent to share bugreport\n");
+ return android::binder::Status::ok();
+}
+
+UserConsentResult Dumpstate::ConsentCallback::getResult() {
+ std::lock_guard<std::mutex> lock(lock_);
+ return result_;
+}
+
+uint64_t Dumpstate::ConsentCallback::getElapsedTimeMs() const {
+ return Nanotime() - start_time_;
+}
+
void Dumpstate::PrintHeader() const {
std::string build, fingerprint, radio, bootloader, network;
char date[80];
@@ -999,6 +981,8 @@
AddAnrTraceDir(add_to_zip, anr_traces_dir);
+ RunCommand("ANR FILES", {"ls", "-lt", ANR_DIR});
+
// Slow traces for slow operations.
struct stat st;
int i = 0;
@@ -1446,12 +1430,8 @@
/* Dumps state for the default case. Returns true if everything went fine. */
static bool DumpstateDefault() {
- // Dumps systrace right away, otherwise it will be filled with unnecessary events.
- // First try to dump anrd trace if the daemon is running. Otherwise, dump
- // the raw trace.
- if (!dump_anrd_trace()) {
- dump_systrace();
- }
+ // Try to dump anrd trace if the daemon is running.
+ dump_anrd_trace();
// Invoking the following dumpsys calls before dump_traces() to try and
// keep the system stats as close to its initial state as possible.
@@ -1572,6 +1552,15 @@
RunDumpsys("DUMPSYS", {"wifi"}, CommandOptions::WithTimeout(90).Build(),
SEC_TO_MSEC(10));
+ if (ds.IsZipping()) {
+ RunCommand("HARDWARE HALS", {"lshal", "-lVSietrpc", "--types=b,c,l,z"},
+ CommandOptions::WithTimeout(2).AsRootIfAvailable().Build());
+ DumpHals();
+ } else {
+ RunCommand("HARDWARE HALS", {"lshal", "-lVSietrpc", "--types=b,c,l,z", "--debug"},
+ CommandOptions::WithTimeout(10).AsRootIfAvailable().Build());
+ }
+
printf("========================================================\n");
printf("== dumpstate: done (id %d)\n", ds.id_);
printf("========================================================\n");
@@ -1692,7 +1681,7 @@
printf("*** See dumpstate-board.txt entry ***\n");
}
-static void ShowUsageAndExit(int exit_code = 1) {
+static void ShowUsage() {
fprintf(stderr,
"usage: dumpstate [-h] [-b soundfile] [-e soundfile] [-o file] [-d] [-p] "
"[-z]] [-s] [-S] [-q] [-B] [-P] [-R] [-V version]\n"
@@ -1711,13 +1700,8 @@
"progress (requires -o and -B)\n"
" -R: take bugreport in remote mode (requires -o, -z, -d and -B, "
"shouldn't be used with -P)\n"
+ " -w: start binder service and make it wait for a call to startBugreport\n"
" -v: prints the dumpstate header and exit\n");
- exit(exit_code);
-}
-
-static void ExitOnInvalidArgs() {
- fprintf(stderr, "invalid combination of args\n");
- ShowUsageAndExit();
}
static void register_sig_handler() {
@@ -1848,16 +1832,9 @@
static void PrepareToWriteToFile() {
MaybeResolveSymlink(&ds.bugreport_internal_dir_);
- std::string base_name_part1 = "bugreport";
- if (!ds.options_->use_outfile.empty()) {
- ds.bugreport_dir_ = dirname(ds.options_->use_outfile.c_str());
- base_name_part1 = basename(ds.options_->use_outfile.c_str());
- }
-
std::string build_id = android::base::GetProperty("ro.build.id", "UNKNOWN_BUILD");
std::string device_name = android::base::GetProperty("ro.product.name", "UNKNOWN_DEVICE");
- ds.base_name_ =
- StringPrintf("%s-%s-%s", base_name_part1.c_str(), device_name.c_str(), build_id.c_str());
+ ds.base_name_ = StringPrintf("bugreport-%s-%s", device_name.c_str(), build_id.c_str());
if (ds.options_->do_add_date) {
char date[80];
strftime(date, sizeof(date), "%Y-%m-%d-%H-%M-%S", localtime(&ds.now_));
@@ -1878,18 +1855,18 @@
ds.tmp_path_ = ds.GetPath(".tmp");
ds.log_path_ = ds.GetPath("-dumpstate_log-" + std::to_string(ds.pid_) + ".txt");
- std::string destination = ds.options_->fd != -1 ? StringPrintf("[fd:%d]", ds.options_->fd)
- : ds.bugreport_dir_.c_str();
+ std::string destination = ds.options_->bugreport_fd.get() != -1
+ ? StringPrintf("[fd:%d]", ds.options_->bugreport_fd.get())
+ : ds.bugreport_internal_dir_.c_str();
MYLOGD(
"Bugreport dir: %s\n"
- "Internal Bugreport dir: %s\n"
"Base name: %s\n"
"Suffix: %s\n"
"Log path: %s\n"
"Temporary path: %s\n"
"Screenshot path: %s\n",
- destination.c_str(), ds.bugreport_internal_dir_.c_str(), ds.base_name_.c_str(),
- ds.name_.c_str(), ds.log_path_.c_str(), ds.tmp_path_.c_str(), ds.screenshot_path_.c_str());
+ destination.c_str(), ds.base_name_.c_str(), ds.name_.c_str(), ds.log_path_.c_str(),
+ ds.tmp_path_.c_str(), ds.screenshot_path_.c_str());
if (ds.options_->do_zip_file) {
ds.path_ = ds.GetPath(".zip");
@@ -1955,19 +1932,6 @@
ds.path_ = new_path;
}
}
- // The zip file lives in an internal directory. Copy it over to output.
- bool copy_succeeded = false;
- if (ds.options_->fd != -1) {
- copy_succeeded = android::os::CopyFileToFd(ds.path_, ds.options_->fd);
- } else {
- ds.final_path_ = ds.GetPath(ds.bugreport_dir_, ".zip");
- copy_succeeded = android::os::CopyFileToFile(ds.path_, ds.final_path_);
- }
- if (copy_succeeded) {
- if (remove(ds.path_.c_str())) {
- MYLOGE("remove(%s): %s", ds.path_.c_str(), strerror(errno));
- }
- }
}
}
if (do_text_file) {
@@ -1993,8 +1957,8 @@
/* Broadcasts that we are done with the bugreport */
static void SendBugreportFinishedBroadcast() {
// TODO(b/111441001): use callback instead of broadcast.
- if (!ds.final_path_.empty()) {
- MYLOGI("Final bugreport path: %s\n", ds.final_path_.c_str());
+ if (!ds.path_.empty()) {
+ MYLOGI("Final bugreport path: %s\n", ds.path_.c_str());
// clang-format off
std::vector<std::string> am_args = {
@@ -2002,7 +1966,7 @@
"--ei", "android.intent.extra.ID", std::to_string(ds.id_),
"--ei", "android.intent.extra.PID", std::to_string(ds.pid_),
"--ei", "android.intent.extra.MAX", std::to_string(ds.progress_->GetMax()),
- "--es", "android.intent.extra.BUGREPORT", ds.final_path_,
+ "--es", "android.intent.extra.BUGREPORT", ds.path_,
"--es", "android.intent.extra.DUMPSTATE_LOG", ds.log_path_
};
// clang-format on
@@ -2024,7 +1988,7 @@
if (ds.options_->is_remote_mode) {
am_args.push_back("--es");
am_args.push_back("android.intent.extra.REMOTE_BUGREPORT_HASH");
- am_args.push_back(SHA256_file_hash(ds.final_path_));
+ am_args.push_back(SHA256_file_hash(ds.path_));
SendBroadcast("com.android.internal.intent.action.REMOTE_BUGREPORT_FINISHED", am_args);
} else {
SendBroadcast("com.android.internal.intent.action.BUGREPORT_FINISHED", am_args);
@@ -2161,22 +2125,24 @@
MYLOGI("telephony_only: %d\n", options.telephony_only);
MYLOGI("wifi_only: %d\n", options.wifi_only);
MYLOGI("do_progress_updates: %d\n", options.do_progress_updates);
- MYLOGI("fd: %d\n", options.fd);
- MYLOGI("use_outfile: %s\n", options.use_outfile.c_str());
+ MYLOGI("fd: %d\n", options.bugreport_fd.get());
MYLOGI("extra_options: %s\n", options.extra_options.c_str());
MYLOGI("args: %s\n", options.args.c_str());
MYLOGI("notification_title: %s\n", options.notification_title.c_str());
MYLOGI("notification_description: %s\n", options.notification_description.c_str());
}
-void Dumpstate::DumpOptions::Initialize(BugreportMode bugreport_mode) {
+void Dumpstate::DumpOptions::Initialize(BugreportMode bugreport_mode,
+ const android::base::unique_fd& bugreport_fd_in,
+ const android::base::unique_fd& screenshot_fd_in) {
// In the new API world, date is always added; output is always a zip file.
// TODO(111441001): remove these options once they are obsolete.
do_add_date = true;
do_zip_file = true;
- // STOPSHIP b/111441001: Remove hardcoded output file path; accept fd.
- use_outfile = "/data/user_de/0/com.android.shell/files/bugreports/bugreport";
+ // Duplicate the fds because the passed in fds don't outlive the binder transaction.
+ bugreport_fd.reset(dup(bugreport_fd_in.get()));
+ screenshot_fd.reset(dup(screenshot_fd_in.get()));
extra_options = ModeToString(bugreport_mode);
SetOptionsFromMode(bugreport_mode, this);
@@ -2185,12 +2151,14 @@
Dumpstate::RunStatus Dumpstate::DumpOptions::Initialize(int argc, char* argv[]) {
RunStatus status = RunStatus::OK;
int c;
- while ((c = getopt(argc, argv, "dho:svqzpPBRSV:")) != -1) {
+ while ((c = getopt(argc, argv, "dho:svqzpPBRSV:w")) != -1) {
switch (c) {
// clang-format off
case 'd': do_add_date = true; break;
case 'z': do_zip_file = true; break;
- case 'o': use_outfile = optarg; break;
+ // o=use_outfile not supported anymore.
+ // TODO(b/111441001): Remove when all callers have migrated.
+ case 'o': break;
case 's': use_socket = true; break;
case 'S': use_control_socket = true; break;
case 'v': show_header_only = true; break;
@@ -2200,6 +2168,9 @@
case 'R': is_remote_mode = true; break;
case 'B': do_broadcast = true; break;
case 'V': break; // compatibility no-op
+ case 'w':
+ // This was already processed
+ break;
case 'h':
status = RunStatus::HELP;
break;
@@ -2227,13 +2198,11 @@
}
bool Dumpstate::DumpOptions::ValidateOptions() const {
- if (fd != -1 && !do_zip_file) {
+ if (bugreport_fd.get() != -1 && !do_zip_file) {
return false;
}
- bool has_out_file_options = !use_outfile.empty() || fd != -1;
- if ((do_zip_file || do_add_date || do_progress_updates || do_broadcast) &&
- !has_out_file_options) {
+ if ((do_zip_file || do_add_date || do_progress_updates || do_broadcast) && !OutputToFile()) {
return false;
}
@@ -2255,6 +2224,32 @@
options_ = std::move(options);
}
+Dumpstate::RunStatus Dumpstate::Run(int32_t calling_uid, const std::string& calling_package) {
+ Dumpstate::RunStatus status = RunInternal(calling_uid, calling_package);
+ if (listener_ != nullptr) {
+ switch (status) {
+ case Dumpstate::RunStatus::OK:
+ listener_->onFinished();
+ break;
+ case Dumpstate::RunStatus::HELP:
+ break;
+ case Dumpstate::RunStatus::INVALID_INPUT:
+ listener_->onError(IDumpstateListener::BUGREPORT_ERROR_INVALID_INPUT);
+ break;
+ case Dumpstate::RunStatus::ERROR:
+ listener_->onError(IDumpstateListener::BUGREPORT_ERROR_RUNTIME_ERROR);
+ break;
+ case Dumpstate::RunStatus::USER_CONSENT_DENIED:
+ listener_->onError(IDumpstateListener::BUGREPORT_ERROR_USER_DENIED_CONSENT);
+ break;
+ case Dumpstate::RunStatus::USER_CONSENT_TIMED_OUT:
+ listener_->onError(IDumpstateListener::BUGREPORT_ERROR_USER_CONSENT_TIMED_OUT);
+ break;
+ }
+ }
+ return status;
+}
+
/*
* Dumps relevant information to a bugreport based on the given options.
*
@@ -2273,10 +2268,11 @@
* If zipping, a bunch of other files and dumps also get added to the zip archive. The log file also
* gets added to the archive.
*
- * Bugreports are first generated in a local directory and later copied to the caller's fd or
- * directory.
+ * Bugreports are first generated in a local directory and later copied to the caller's fd if
+ * supplied.
*/
-Dumpstate::RunStatus Dumpstate::Run() {
+Dumpstate::RunStatus Dumpstate::RunInternal(int32_t calling_uid,
+ const std::string& calling_package) {
LogDumpOptions(*options_);
if (!options_->ValidateOptions()) {
MYLOGE("Invalid options specified\n");
@@ -2314,8 +2310,14 @@
return RunStatus::OK;
}
+ if (options_->bugreport_fd.get() != -1) {
+ // If the output needs to be copied over to the caller's fd, get user consent.
+ android::String16 package(calling_package.c_str());
+ CheckUserConsent(calling_uid, package);
+ }
+
// Redirect output if needed
- bool is_redirecting = !options_->use_socket && !options_->use_outfile.empty();
+ bool is_redirecting = options_->OutputToFile();
// TODO: temporarily set progress until it's part of the Dumpstate constructor
std::string stats_path =
@@ -2465,11 +2467,31 @@
TEMP_FAILURE_RETRY(dup2(dup_stdout_fd, fileno(stdout)));
}
- /* rename or zip the (now complete) .tmp file to its final location */
- if (!options_->use_outfile.empty()) {
+ // Rename, and/or zip the (now complete) .tmp file within the internal directory.
+ if (options_->OutputToFile()) {
FinalizeFile();
}
+ // Share the final file with the caller if the user has consented.
+ Dumpstate::RunStatus status = Dumpstate::RunStatus::OK;
+ if (options_->bugreport_fd.get() != -1) {
+ status = CopyBugreportIfUserConsented();
+ if (status != Dumpstate::RunStatus::OK &&
+ status != Dumpstate::RunStatus::USER_CONSENT_TIMED_OUT) {
+ // Do an early return if there were errors. We make an exception for consent
+ // timing out because it's possible the user got distracted. In this case the
+ // bugreport is not shared but made available for manual retrieval.
+ return status;
+ }
+ if (options_->screenshot_fd.get() != -1) {
+ bool copy_succeeded = android::os::CopyFileToFd(screenshot_path_,
+ options_->screenshot_fd.get());
+ if (copy_succeeded) {
+ android::os::UnlinkAndLogOnError(screenshot_path_);
+ }
+ }
+ }
+
/* vibrate a few but shortly times to let user know it's finished */
if (options_->do_vibrate) {
for (int i = 0; i < 3; i++) {
@@ -2481,6 +2503,7 @@
/* tell activity manager we're done */
if (options_->do_broadcast) {
SendBugreportFinishedBroadcast();
+ // Note that listener_ is notified in Run();
}
MYLOGD("Final progress: %d/%d (estimated %d)\n", progress_->Get(), progress_->GetMax(),
@@ -2500,7 +2523,73 @@
tombstone_data_.clear();
anr_data_.clear();
- return RunStatus::OK;
+ return (consent_callback_ != nullptr &&
+ consent_callback_->getResult() == UserConsentResult::UNAVAILABLE)
+ ? USER_CONSENT_TIMED_OUT
+ : RunStatus::OK;
+}
+
+void Dumpstate::CheckUserConsent(int32_t calling_uid, const android::String16& calling_package) {
+ consent_callback_ = new ConsentCallback();
+ const String16 incidentcompanion("incidentcompanion");
+ sp<android::IBinder> ics(defaultServiceManager()->getService(incidentcompanion));
+ if (ics != nullptr) {
+ MYLOGD("Checking user consent via incidentcompanion service\n");
+ android::interface_cast<android::os::IIncidentCompanion>(ics)->authorizeReport(
+ calling_uid, calling_package, 0x1 /* FLAG_CONFIRMATION_DIALOG */,
+ consent_callback_.get());
+ } else {
+ MYLOGD("Unable to check user consent; incidentcompanion service unavailable\n");
+ }
+}
+
+void Dumpstate::CleanupFiles() {
+ android::os::UnlinkAndLogOnError(tmp_path_);
+ android::os::UnlinkAndLogOnError(screenshot_path_);
+ android::os::UnlinkAndLogOnError(path_);
+}
+
+Dumpstate::RunStatus Dumpstate::HandleUserConsentDenied() {
+ MYLOGD("User denied consent; deleting files and returning\n");
+ CleanupFiles();
+ return USER_CONSENT_DENIED;
+}
+
+Dumpstate::RunStatus Dumpstate::CopyBugreportIfUserConsented() {
+ // If the caller has asked to copy the bugreport over to their directory, we need explicit
+ // user consent.
+ UserConsentResult consent_result = consent_callback_->getResult();
+ if (consent_result == UserConsentResult::UNAVAILABLE) {
+ // User has not responded yet.
+ uint64_t elapsed_ms = consent_callback_->getElapsedTimeMs();
+ if (elapsed_ms < USER_CONSENT_TIMEOUT_MS) {
+ uint delay_seconds = (USER_CONSENT_TIMEOUT_MS - elapsed_ms) / 1000;
+ MYLOGD("Did not receive user consent yet; going to wait for %d seconds", delay_seconds);
+ sleep(delay_seconds);
+ }
+ consent_result = consent_callback_->getResult();
+ }
+ if (consent_result == UserConsentResult::DENIED) {
+ // User has explicitly denied sharing with the app. To be safe delete the
+ // internal bugreport & tmp files.
+ return HandleUserConsentDenied();
+ }
+ if (consent_result == UserConsentResult::APPROVED) {
+ bool copy_succeeded = android::os::CopyFileToFd(path_, options_->bugreport_fd.get());
+ if (copy_succeeded) {
+ android::os::UnlinkAndLogOnError(path_);
+ }
+ return copy_succeeded ? Dumpstate::RunStatus::OK : Dumpstate::RunStatus::ERROR;
+ } else if (consent_result == UserConsentResult::UNAVAILABLE) {
+ // consent_result is still UNAVAILABLE. The user has likely not responded yet.
+ // Since we do not have user consent to share the bugreport it does not get
+ // copied over to the calling app but remains in the internal directory from
+ // where the user can manually pull it.
+ return Dumpstate::RunStatus::USER_CONSENT_TIMED_OUT;
+ }
+ // Unknown result; must be a programming error.
+ MYLOGE("Unknown user consent result:%d\n", consent_result);
+ return Dumpstate::RunStatus::ERROR;
}
/* Main entry point for dumpstate binary. */
@@ -2509,22 +2598,31 @@
Dumpstate::RunStatus status = options->Initialize(argc, argv);
if (status == Dumpstate::RunStatus::OK) {
ds.SetOptions(std::move(options));
- status = ds.Run();
+ // When directly running dumpstate binary, the output is not expected to be written
+ // to any external file descriptor.
+ assert(ds.options_->bugreport_fd.get() == -1);
+
+ // calling_uid and calling_package are for user consent to share the bugreport with
+ // an app; they are irrelvant here because bugreport is only written to a local
+ // directory, and not shared.
+ status = ds.Run(-1 /* calling_uid */, "" /* calling_package */);
}
switch (status) {
case Dumpstate::RunStatus::OK:
- return 0;
- // TODO(b/111441001): Exit directly in the following cases.
+ exit(0);
case Dumpstate::RunStatus::HELP:
- ShowUsageAndExit(0 /* exit code */);
- break;
+ ShowUsage();
+ exit(0);
case Dumpstate::RunStatus::INVALID_INPUT:
- ExitOnInvalidArgs();
- break;
+ fprintf(stderr, "Invalid combination of args\n");
+ ShowUsage();
+ exit(1);
case Dumpstate::RunStatus::ERROR:
- exit(-1);
- break;
+ FALLTHROUGH_INTENDED;
+ case Dumpstate::RunStatus::USER_CONSENT_DENIED:
+ FALLTHROUGH_INTENDED;
+ case Dumpstate::RunStatus::USER_CONSENT_TIMED_OUT:
+ exit(2);
}
- return 0;
}
diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h
index 7ac25e4..7fb2f3b 100644
--- a/cmds/dumpstate/dumpstate.h
+++ b/cmds/dumpstate/dumpstate.h
@@ -27,6 +27,7 @@
#include <android-base/macros.h>
#include <android-base/unique_fd.h>
+#include <android/os/BnIncidentAuthListener.h>
#include <android/os/IDumpstate.h>
#include <android/os/IDumpstateListener.h>
#include <utils/StrongPointer.h>
@@ -192,7 +193,7 @@
friend class DumpstateTest;
public:
- enum RunStatus { OK, HELP, INVALID_INPUT, ERROR };
+ enum RunStatus { OK, HELP, INVALID_INPUT, ERROR, USER_CONSENT_DENIED, USER_CONSENT_TIMED_OUT };
// The mode under which the bugreport should be run. Each mode encapsulates a few options.
enum BugreportMode {
@@ -319,7 +320,7 @@
struct DumpOptions;
/* Main entry point for running a complete bugreport. */
- RunStatus Run();
+ RunStatus Run(int32_t calling_uid, const std::string& calling_package);
/* Sets runtime options. */
void SetOptions(std::unique_ptr<DumpOptions> options);
@@ -331,6 +332,7 @@
bool do_add_date = false;
bool do_zip_file = false;
bool do_vibrate = true;
+ // Writes bugreport content to a socket; only flatfile format is supported.
bool use_socket = false;
bool use_control_socket = false;
bool do_fb = false;
@@ -342,11 +344,10 @@
bool wifi_only = false;
// Whether progress updates should be published.
bool do_progress_updates = false;
- // File descriptor to output zip file. -1 indicates not set. Takes precedence over
- // use_outfile.
- int fd = -1;
- // Partial path to output file.
- std::string use_outfile;
+ // File descriptor to output zip file.
+ android::base::unique_fd bugreport_fd;
+ // File descriptor to screenshot file.
+ android::base::unique_fd screenshot_fd;
// TODO: rename to MODE.
// Extra options passed as system property.
std::string extra_options;
@@ -360,10 +361,18 @@
RunStatus Initialize(int argc, char* argv[]);
/* Initializes options from the requested mode. */
- void Initialize(BugreportMode bugreport_mode);
+ void Initialize(BugreportMode bugreport_mode, const android::base::unique_fd& bugreport_fd,
+ const android::base::unique_fd& screenshot_fd);
/* Returns true if the options set so far are consistent. */
bool ValidateOptions() const;
+
+ /* Returns if options specified require writing bugreport to a file */
+ bool OutputToFile() const {
+ // If we are not writing to socket, we will write to a file. If bugreport_fd is
+ // specified, it is preferred. If not bugreport is written to /bugreports.
+ return !use_socket;
+ }
};
// TODO: initialize fields on constructor
@@ -421,13 +430,6 @@
// Full path of the temporary file containing the screenshot (when requested).
std::string screenshot_path_;
- // TODO(b/111441001): remove when obsolete.
- // Full path of the final zip file inside the caller-specified directory, if available.
- std::string final_path_;
-
- // The caller-specified directory, if available.
- std::string bugreport_dir_;
-
// Pointer to the zipped file.
std::unique_ptr<FILE, int (*)(FILE*)> zip_file{nullptr, fclose};
@@ -445,10 +447,47 @@
// List of open ANR dump files.
std::vector<DumpData> anr_data_;
+ // A callback to IncidentCompanion service, which checks user consent for sharing the
+ // bugreport with the calling app. If the user has not responded yet to the dialog it will
+ // be neither confirmed nor denied.
+ class ConsentCallback : public android::os::BnIncidentAuthListener {
+ public:
+ ConsentCallback();
+ android::binder::Status onReportApproved() override;
+ android::binder::Status onReportDenied() override;
+
+ enum ConsentResult { APPROVED, DENIED, UNAVAILABLE };
+
+ ConsentResult getResult();
+
+ // Returns the time since creating this listener
+ uint64_t getElapsedTimeMs() const;
+
+ private:
+ ConsentResult result_;
+ uint64_t start_time_;
+ std::mutex lock_;
+ };
+
private:
+ RunStatus RunInternal(int32_t calling_uid, const std::string& calling_package);
+
+ void CheckUserConsent(int32_t calling_uid, const android::String16& calling_package);
+
+ // Removes the in progress files output files (tmp file, zip/txt file, screenshot),
+ // but leaves the log file alone.
+ void CleanupFiles();
+
+ RunStatus HandleUserConsentDenied();
+
+ // Copies bugreport artifacts over to the caller's directories provided there is user consent.
+ RunStatus CopyBugreportIfUserConsented();
+
// Used by GetInstance() only.
explicit Dumpstate(const std::string& version = VERSION_CURRENT);
+ android::sp<ConsentCallback> consent_callback_;
+
DISALLOW_COPY_AND_ASSIGN(Dumpstate);
};
diff --git a/cmds/dumpstate/dumpstate.rc b/cmds/dumpstate/dumpstate.rc
index 2e72574..14937b8 100644
--- a/cmds/dumpstate/dumpstate.rc
+++ b/cmds/dumpstate/dumpstate.rc
@@ -17,3 +17,9 @@
class main
disabled
oneshot
+
+# bugreportd starts dumpstate binder service and makes it wait for a listener to connect.
+service bugreportd /system/bin/dumpstate -w
+ class main
+ disabled
+ oneshot
diff --git a/cmds/dumpstate/main.cpp b/cmds/dumpstate/main.cpp
index 78aad11..68d3733 100644
--- a/cmds/dumpstate/main.cpp
+++ b/cmds/dumpstate/main.cpp
@@ -14,8 +14,55 @@
* limitations under the License.
*/
+#define LOG_TAG "dumpstate"
+
+#include <binder/IPCThreadState.h>
+
+#include "DumpstateInternal.h"
+#include "DumpstateService.h"
#include "dumpstate.h"
+namespace {
+
+// Returns true if we should start the service and wait for a listener
+// to bind with bugreport options.
+bool ShouldStartServiceAndWait(int argc, char* argv[]) {
+ bool do_wait = false;
+ int c;
+ // Keep flags in sync with Dumpstate::DumpOptions::Initialize.
+ while ((c = getopt(argc, argv, "wdho:svqzpPBRSV:")) != -1 && !do_wait) {
+ switch (c) {
+ case 'w':
+ do_wait = true;
+ break;
+ default:
+ // Ignore all other options
+ break;
+ }
+ }
+
+ // Reset next index used by getopt so getopt can be called called again in Dumpstate::Run to
+ // parse bugreport options.
+ optind = 1;
+ return do_wait;
+}
+
+} // namespace
+
int main(int argc, char* argv[]) {
- return run_main(argc, argv);
+ if (ShouldStartServiceAndWait(argc, argv)) {
+ int ret;
+ if ((ret = android::os::DumpstateService::Start()) != android::OK) {
+ MYLOGE("Unable to start 'dumpstate' service: %d", ret);
+ exit(1);
+ }
+ MYLOGI("'dumpstate' service started and will wait for a call to startBugreport()");
+
+ // Waits forever for an incoming connection.
+ // TODO(b/111441001): should this time out?
+ android::IPCThreadState::self()->joinThreadPool();
+ return 0;
+ } else {
+ return run_main(argc, argv);
+ }
}
diff --git a/cmds/dumpstate/tests/dumpstate_smoke_test.cpp b/cmds/dumpstate/tests/dumpstate_smoke_test.cpp
index 61a5ef5..570c6c9 100644
--- a/cmds/dumpstate/tests/dumpstate_smoke_test.cpp
+++ b/cmds/dumpstate/tests/dumpstate_smoke_test.cpp
@@ -53,6 +53,18 @@
DumpstateListener(int fd, std::shared_ptr<std::vector<SectionInfo>> sections)
: outFd_(fd), max_progress_(5000), sections_(sections) {
}
+ binder::Status onProgress(int32_t progress) override {
+ dprintf(outFd_, "\rIn progress %d", progress);
+ return binder::Status::ok();
+ }
+ binder::Status onError(int32_t error_code) override {
+ dprintf(outFd_, "\rError %d", error_code);
+ return binder::Status::ok();
+ }
+ binder::Status onFinished() override {
+ dprintf(outFd_, "\rFinished");
+ return binder::Status::ok();
+ }
binder::Status onProgressUpdated(int32_t progress) override {
dprintf(outFd_, "\rIn progress %d/%d", progress, max_progress_);
return binder::Status::ok();
diff --git a/cmds/dumpstate/tests/dumpstate_test.cpp b/cmds/dumpstate/tests/dumpstate_test.cpp
index fcf9371..eb73d41 100644
--- a/cmds/dumpstate/tests/dumpstate_test.cpp
+++ b/cmds/dumpstate/tests/dumpstate_test.cpp
@@ -59,6 +59,9 @@
class DumpstateListenerMock : public IDumpstateListener {
public:
+ MOCK_METHOD1(onProgress, binder::Status(int32_t progress));
+ MOCK_METHOD1(onError, binder::Status(int32_t error_code));
+ MOCK_METHOD0(onFinished, binder::Status());
MOCK_METHOD1(onProgressUpdated, binder::Status(int32_t progress));
MOCK_METHOD1(onMaxProgressUpdated, binder::Status(int32_t max_progress));
MOCK_METHOD4(onSectionComplete, binder::Status(const ::std::string& name, int32_t status,
@@ -169,7 +172,6 @@
EXPECT_FALSE(options_.do_add_date);
EXPECT_FALSE(options_.do_zip_file);
- EXPECT_EQ("", options_.use_outfile);
EXPECT_FALSE(options_.use_socket);
EXPECT_FALSE(options_.use_control_socket);
EXPECT_FALSE(options_.show_header_only);
@@ -187,7 +189,6 @@
const_cast<char*>("-S"),
const_cast<char*>("-d"),
const_cast<char*>("-z"),
- const_cast<char*>("-o abc"),
};
// clang-format on
@@ -197,7 +198,6 @@
EXPECT_TRUE(options_.do_add_date);
EXPECT_TRUE(options_.do_zip_file);
EXPECT_TRUE(options_.use_control_socket);
- EXPECT_EQ(" abc", std::string(options_.use_outfile));
// Other options retain default values
EXPECT_TRUE(options_.do_vibrate);
@@ -224,7 +224,6 @@
// Other options retain default values
EXPECT_TRUE(options_.do_vibrate);
- EXPECT_EQ("", options_.use_outfile);
EXPECT_FALSE(options_.do_add_date);
EXPECT_FALSE(options_.do_zip_file);
EXPECT_FALSE(options_.use_control_socket);
@@ -243,7 +242,6 @@
const_cast<char*>("-p"),
const_cast<char*>("-B"),
const_cast<char*>("-z"),
- const_cast<char*>("-o abc"),
};
// clang-format on
property_set("dumpstate.options", "bugreportfull");
@@ -255,7 +253,6 @@
EXPECT_TRUE(options_.do_fb);
EXPECT_TRUE(options_.do_zip_file);
EXPECT_TRUE(options_.do_broadcast);
- EXPECT_EQ(" abc", std::string(options_.use_outfile));
// Other options retain default values
EXPECT_TRUE(options_.do_vibrate);
@@ -275,7 +272,6 @@
const_cast<char*>("-p"),
const_cast<char*>("-B"),
const_cast<char*>("-z"),
- const_cast<char*>("-o abc"),
};
// clang-format on
@@ -290,7 +286,6 @@
EXPECT_TRUE(options_.do_progress_updates);
EXPECT_TRUE(options_.do_start_service);
EXPECT_FALSE(options_.do_fb);
- EXPECT_EQ(" abc", std::string(options_.use_outfile));
// Other options retain default values
EXPECT_TRUE(options_.do_vibrate);
@@ -308,7 +303,6 @@
const_cast<char*>("-p"),
const_cast<char*>("-B"),
const_cast<char*>("-z"),
- const_cast<char*>("-o abc"),
};
// clang-format on
@@ -323,7 +317,6 @@
EXPECT_TRUE(options_.is_remote_mode);
EXPECT_FALSE(options_.do_vibrate);
EXPECT_FALSE(options_.do_fb);
- EXPECT_EQ(" abc", std::string(options_.use_outfile));
// Other options retain default values
EXPECT_FALSE(options_.use_control_socket);
@@ -340,7 +333,6 @@
const_cast<char*>("-p"),
const_cast<char*>("-B"),
const_cast<char*>("-z"),
- const_cast<char*>("-o abc"),
};
// clang-format on
@@ -355,7 +347,6 @@
EXPECT_TRUE(options_.do_zip_file);
EXPECT_TRUE(options_.do_progress_updates);
EXPECT_TRUE(options_.do_start_service);
- EXPECT_EQ(" abc", std::string(options_.use_outfile));
// Other options retain default values
EXPECT_TRUE(options_.do_vibrate);
@@ -373,7 +364,6 @@
const_cast<char*>("-p"),
const_cast<char*>("-B"),
const_cast<char*>("-z"),
- const_cast<char*>("-o abc"),
};
// clang-format on
@@ -387,7 +377,6 @@
EXPECT_TRUE(options_.do_broadcast);
EXPECT_TRUE(options_.do_zip_file);
EXPECT_TRUE(options_.telephony_only);
- EXPECT_EQ(" abc", std::string(options_.use_outfile));
// Other options retain default values
EXPECT_TRUE(options_.do_vibrate);
@@ -406,7 +395,6 @@
const_cast<char*>("-p"),
const_cast<char*>("-B"),
const_cast<char*>("-z"),
- const_cast<char*>("-o abc"),
};
// clang-format on
@@ -420,7 +408,6 @@
EXPECT_TRUE(options_.do_broadcast);
EXPECT_TRUE(options_.do_zip_file);
EXPECT_TRUE(options_.wifi_only);
- EXPECT_EQ(" abc", std::string(options_.use_outfile));
// Other options retain default values
EXPECT_TRUE(options_.do_vibrate);
@@ -440,7 +427,6 @@
const_cast<char*>("-p"),
const_cast<char*>("-B"),
const_cast<char*>("-z"),
- const_cast<char*>("-o abc"),
};
// clang-format on
@@ -453,7 +439,6 @@
EXPECT_TRUE(options_.do_fb);
EXPECT_TRUE(options_.do_zip_file);
EXPECT_TRUE(options_.do_broadcast);
- EXPECT_EQ(" abc", std::string(options_.use_outfile));
// Other options retain default values
EXPECT_TRUE(options_.do_vibrate);
@@ -471,7 +456,6 @@
const_cast<char*>("dumpstate"),
const_cast<char*>("-d"),
const_cast<char*>("-z"),
- const_cast<char*>("-o abc"),
const_cast<char*>("-s"),
const_cast<char*>("-S"),
@@ -484,7 +468,6 @@
EXPECT_TRUE(options_.do_add_date);
EXPECT_TRUE(options_.do_zip_file);
// TODO: Maybe we should trim the filename
- EXPECT_EQ(" abc", std::string(options_.use_outfile));
EXPECT_TRUE(options_.use_socket);
EXPECT_TRUE(options_.use_control_socket);
@@ -523,7 +506,6 @@
// Other options retain default values
EXPECT_FALSE(options_.do_add_date);
EXPECT_FALSE(options_.do_zip_file);
- EXPECT_EQ("", options_.use_outfile);
EXPECT_FALSE(options_.use_socket);
EXPECT_FALSE(options_.use_control_socket);
}
@@ -558,15 +540,21 @@
TEST_F(DumpOptionsTest, ValidateOptionsNeedOutfile1) {
options_.do_zip_file = true;
+ // Writing to socket = !writing to file.
+ options_.use_socket = true;
EXPECT_FALSE(options_.ValidateOptions());
- options_.use_outfile = "a/b/c";
+
+ options_.use_socket = false;
EXPECT_TRUE(options_.ValidateOptions());
}
TEST_F(DumpOptionsTest, ValidateOptionsNeedOutfile2) {
options_.do_broadcast = true;
+ // Writing to socket = !writing to file.
+ options_.use_socket = true;
EXPECT_FALSE(options_.ValidateOptions());
- options_.use_outfile = "a/b/c";
+
+ options_.use_socket = false;
EXPECT_TRUE(options_.ValidateOptions());
}
@@ -575,13 +563,11 @@
EXPECT_FALSE(options_.ValidateOptions());
options_.do_zip_file = true;
- options_.use_outfile = "a/b/c"; // do_zip_file needs outfile
EXPECT_TRUE(options_.ValidateOptions());
}
TEST_F(DumpOptionsTest, ValidateOptionsUpdateProgressNeedsBroadcast) {
options_.do_progress_updates = true;
- options_.use_outfile = "a/b/c"; // do_progress_updates needs outfile
EXPECT_FALSE(options_.ValidateOptions());
options_.do_broadcast = true;
@@ -595,7 +581,6 @@
options_.do_broadcast = true;
options_.do_zip_file = true;
options_.do_add_date = true;
- options_.use_outfile = "a/b/c"; // do_broadcast needs outfile
EXPECT_TRUE(options_.ValidateOptions());
}
@@ -652,8 +637,9 @@
}
if (update_progress) {
- message += android::base::StringPrintf("Setting progress (%s): %d/%d\n",
- listener_name.c_str(), progress, max);
+ message += android::base::StringPrintf("Setting progress (%s): %d/%d (%d%%)\n",
+ listener_name.c_str(), progress, max,
+ (100 * progress / max));
}
return message;
@@ -812,12 +798,14 @@
SetProgress(0, 30);
EXPECT_CALL(*listener, onProgressUpdated(20));
+ EXPECT_CALL(*listener, onProgress(66)); // 20/30 %
EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(20).Build()));
std::string progress_message = GetProgressMessage(ds.listener_name_, 20, 30);
EXPECT_THAT(out, StrEq("stdout\n"));
EXPECT_THAT(err, StrEq("stderr\n" + progress_message));
EXPECT_CALL(*listener, onProgressUpdated(30));
+ EXPECT_CALL(*listener, onProgress(100)); // 35/35 %
EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(10).Build()));
progress_message = GetProgressMessage(ds.listener_name_, 30, 30);
EXPECT_THAT(out, StrEq("stdout\n"));
@@ -826,6 +814,7 @@
// Run a command that will increase maximum timeout.
EXPECT_CALL(*listener, onProgressUpdated(31));
EXPECT_CALL(*listener, onMaxProgressUpdated(37));
+ EXPECT_CALL(*listener, onProgress(83)); // 31/37 %
EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(1).Build()));
progress_message = GetProgressMessage(ds.listener_name_, 31, 37, 30); // 20% increase
EXPECT_THAT(out, StrEq("stdout\n"));
@@ -834,6 +823,7 @@
// Make sure command ran while in dry_run is counted.
SetDryRun(true);
EXPECT_CALL(*listener, onProgressUpdated(35));
+ EXPECT_CALL(*listener, onProgress(94)); // 35/37 %
EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(4).Build()));
progress_message = GetProgressMessage(ds.listener_name_, 35, 37);
EXPECT_THAT(out, IsEmpty());
@@ -850,6 +840,7 @@
// First update should always be sent.
EXPECT_CALL(*listener, onProgressUpdated(1));
+ EXPECT_CALL(*listener, onProgress(12)); // 1/12 %
EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(1).Build()));
std::string progress_message = GetProgressMessage(ds.listener_name_, 1, 8);
EXPECT_THAT(out, StrEq("stdout\n"));
@@ -862,6 +853,7 @@
// Third update should be sent because it reaches threshold (6 - 1 = 5).
EXPECT_CALL(*listener, onProgressUpdated(6));
+ EXPECT_CALL(*listener, onProgress(75)); // 6/8 %
EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(1).Build()));
progress_message = GetProgressMessage(ds.listener_name_, 6, 8);
EXPECT_THAT(out, StrEq("stdout\n"));
@@ -1101,6 +1093,7 @@
SetProgress(0, 30);
EXPECT_CALL(*listener, onProgressUpdated(5));
+ EXPECT_CALL(*listener, onProgress(16)); // 5/30 %
EXPECT_EQ(0, DumpFile("", kTestDataPath + "single-line.txt"));
std::string progress_message =
diff --git a/cmds/dumpstate/utils.cpp b/cmds/dumpstate/utils.cpp
index d97ffbf..528e43d 100644
--- a/cmds/dumpstate/utils.cpp
+++ b/cmds/dumpstate/utils.cpp
@@ -871,7 +871,11 @@
is_java_process ? 5 : 20, fd);
if (ret == -1) {
- dprintf(fd, "dumping failed, likely due to a timeout\n");
+ // For consistency, the header and footer to this message match those
+ // dumped by debuggerd in the success case.
+ dprintf(fd, "\n---- pid %d at [unknown] ----\n", pid);
+ dprintf(fd, "Dump failed, likely due to a timeout.\n");
+ dprintf(fd, "---- end %d ----", pid);
timeout_failures++;
continue;
}
@@ -945,16 +949,22 @@
fsync(control_socket_fd_);
}
+ int percent = 100 * progress / max;
if (listener_ != nullptr) {
- if (progress % 100 == 0) {
- // We don't want to spam logcat, so only log multiples of 100.
- MYLOGD("Setting progress (%s): %d/%d\n", listener_name_.c_str(), progress, max);
+ if (percent % 5 == 0) {
+ // We don't want to spam logcat, so only log multiples of 5.
+ MYLOGD("Setting progress (%s): %d/%d (%d%%)\n", listener_name_.c_str(), progress, max,
+ percent);
} else {
// stderr is ignored on normal invocations, but useful when calling
// /system/bin/dumpstate directly for debuggging.
- fprintf(stderr, "Setting progress (%s): %d/%d\n", listener_name_.c_str(), progress, max);
+ fprintf(stderr, "Setting progress (%s): %d/%d (%d%%)\n", listener_name_.c_str(),
+ progress, max, percent);
}
+ // TODO(b/111441001): Remove in favor of onProgress
listener_->onProgressUpdated(progress);
+
+ listener_->onProgress(percent);
}
}
diff --git a/cmds/dumpsys/Android.bp b/cmds/dumpsys/Android.bp
index f68b862..f99588f 100644
--- a/cmds/dumpsys/Android.bp
+++ b/cmds/dumpsys/Android.bp
@@ -20,8 +20,6 @@
static_libs: [
"libserviceutils",
],
-
- clang: true,
}
//
@@ -36,7 +34,6 @@
export_include_dirs: ["."],
}
-
//
// Executable
//
@@ -51,4 +48,15 @@
],
}
-subdirs = ["tests"]
+cc_binary {
+ name: "dumpsys_vendor",
+ stem: "dumpsys",
+
+ vendor: true,
+
+ defaults: ["dumpsys_defaults"],
+
+ srcs: [
+ "main.cpp",
+ ],
+}
diff --git a/cmds/installd/Android.bp b/cmds/installd/Android.bp
index 2e9701f..e33b2a8 100644
--- a/cmds/installd/Android.bp
+++ b/cmds/installd/Android.bp
@@ -18,6 +18,8 @@
"dexopt.cpp",
"globals.cpp",
"utils.cpp",
+ "utils_default.cpp",
+ "view_compiler.cpp",
":installd_aidl",
],
header_libs: [
@@ -30,6 +32,7 @@
"libcutils",
"liblog",
"liblogwrap",
+ "libprocessgroup",
"libselinux",
"libutils",
],
@@ -136,10 +139,23 @@
],
clang: true,
- srcs: ["otapreopt_chroot.cpp"],
+ srcs: [
+ "otapreopt_chroot.cpp",
+ "otapreopt_utils.cpp",
+ ],
shared_libs: [
"libbase",
"liblog",
+ "libprotobuf-cpp-full",
+ "libselinux",
+ "libziparchive",
+ ],
+ static_libs: [
+ "libapex",
+ "libapexd",
+ "lib_apex_manifest_proto",
+ "libavb",
+ "libdm",
],
}
@@ -168,6 +184,7 @@
"libbase",
"libcutils",
"liblog",
+ "libprocessgroup",
"libutils",
],
}
@@ -187,7 +204,10 @@
"dexopt.cpp",
"globals.cpp",
"otapreopt.cpp",
+ "otapreopt_utils.cpp",
"utils.cpp",
+ "utils_default.cpp",
+ "view_compiler.cpp",
],
header_libs: ["dex2oat_headers"],
@@ -204,7 +224,28 @@
"libcutils",
"liblog",
"liblogwrap",
+ "libprocessgroup",
"libselinux",
"libutils",
],
}
+
+// OTA slot script
+sh_binary {
+ name: "otapreopt_slot",
+ src: "otapreopt_slot.sh",
+ init_rc: ["otapreopt.rc"],
+}
+
+// OTA postinstall script
+sh_binary {
+ name: "otapreopt_script",
+ src: "otapreopt_script.sh",
+ // Let this depend on otapreopt, the chroot tool and the slot script,
+ // so we just have to mention one in a configuration.
+ required: [
+ "otapreopt",
+ "otapreopt_chroot",
+ "otapreopt_slot",
+ ],
+}
diff --git a/cmds/installd/Android.mk b/cmds/installd/Android.mk
deleted file mode 100644
index 30de0b3..0000000
--- a/cmds/installd/Android.mk
+++ /dev/null
@@ -1,26 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-
-# OTA slot script
-
-include $(CLEAR_VARS)
-LOCAL_MODULE:= otapreopt_slot
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_CLASS := EXECUTABLES
-LOCAL_SRC_FILES := otapreopt_slot.sh
-LOCAL_INIT_RC := otapreopt.rc
-
-include $(BUILD_PREBUILT)
-
-# OTA postinstall script
-
-include $(CLEAR_VARS)
-LOCAL_MODULE:= otapreopt_script
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_CLASS := EXECUTABLES
-LOCAL_SRC_FILES := otapreopt_script.sh
-
-# Let this depend on otapreopt, the chroot tool and the slot script, so we just have to mention one
-# in a configuration.
-LOCAL_REQUIRED_MODULES := otapreopt otapreopt_chroot otapreopt_slot
-
-include $(BUILD_PREBUILT)
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index 81055d8..49383e5 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -41,6 +41,7 @@
#include <android-base/logging.h>
#include <android-base/properties.h>
+#include <android-base/scopeguard.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
#include <android-base/unique_fd.h>
@@ -60,6 +61,7 @@
#include "installd_deps.h"
#include "otapreopt_utils.h"
#include "utils.h"
+#include "view_compiler.h"
#include "CacheTracker.h"
#include "MatchExtensionGen.h"
@@ -75,6 +77,9 @@
namespace android {
namespace installd {
+// An uuid used in unit tests.
+static constexpr const char* kTestUuid = "TEST";
+
static constexpr const char* kCpPath = "/system/bin/cp";
static constexpr const char* kXattrDefault = "user.default";
@@ -153,6 +158,15 @@
}
}
+binder::Status checkArgumentUuidTestOrNull(const std::unique_ptr<std::string>& uuid) {
+ if (!uuid || strcmp(uuid->c_str(), kTestUuid) == 0) {
+ return ok();
+ } else {
+ return exception(binder::Status::EX_ILLEGAL_ARGUMENT,
+ StringPrintf("UUID must be null or \"%s\", got: %s", kTestUuid, uuid->c_str()));
+ }
+}
+
binder::Status checkArgumentPackageName(const std::string& packageName) {
if (is_valid_package_name(packageName.c_str())) {
return ok();
@@ -205,6 +219,13 @@
} \
}
+#define CHECK_ARGUMENT_UUID_IS_TEST_OR_NULL(uuid) { \
+ auto status = checkArgumentUuidTestOrNull(uuid); \
+ if (!status.isOk()) { \
+ return status; \
+ } \
+} \
+
#define CHECK_ARGUMENT_PACKAGE_NAME(packageName) { \
binder::Status status = \
checkArgumentPackageName((packageName)); \
@@ -783,6 +804,233 @@
return ok();
}
+static int32_t copy_directory_recursive(const char* from, const char* to) {
+ char *argv[] = {
+ (char*) kCpPath,
+ (char*) "-F", /* delete any existing destination file first (--remove-destination) */
+ (char*) "-p", /* preserve timestamps, ownership, and permissions */
+ (char*) "-R", /* recurse into subdirectories (DEST must be a directory) */
+ (char*) "-P", /* Do not follow symlinks [default] */
+ (char*) "-d", /* don't dereference symlinks */
+ (char*) from,
+ (char*) to
+ };
+
+ LOG(DEBUG) << "Copying " << from << " to " << to;
+ return android_fork_execvp(ARRAY_SIZE(argv), argv, nullptr, false, true);
+}
+
+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) {
+ ENFORCE_UID(AID_SYSTEM);
+ CHECK_ARGUMENT_UUID_IS_TEST_OR_NULL(volumeUuid);
+ CHECK_ARGUMENT_PACKAGE_NAME(packageName);
+ std::lock_guard<std::recursive_mutex> lock(mLock);
+
+ const char* volume_uuid = volumeUuid ? volumeUuid->c_str() : nullptr;
+ const char* package_name = packageName.c_str();
+
+ binder::Status res = ok();
+ // Default result to 0, it will be populated with inode of ce data snapshot
+ // if FLAG_STORAGE_CE has been passed.
+ if (_aidl_return != nullptr) *_aidl_return = 0;
+
+ 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] {
+ if (clear_de_on_exit) {
+ auto to = create_data_misc_de_rollback_package_path(volume_uuid, user, 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);
+ if (delete_dir_contents(to.c_str(), 1, nullptr) != 0) {
+ LOG(WARNING) << "Failed to delete app data snapshot: " << to;
+ }
+ }
+ };
+
+ auto scope_guard = android::base::make_scope_guard(deleter);
+
+ // The app may not have any data at all, in which case it's OK to skip here.
+ auto from_ce = create_data_user_ce_package_path(volume_uuid, user, package_name);
+ if (access(from_ce.c_str(), F_OK) != 0) {
+ LOG(INFO) << "Missing source " << from_ce;
+ return ok();
+ }
+
+ // ce_data_inode is not needed when FLAG_CLEAR_CACHE_ONLY is set.
+ binder::Status clear_cache_result = clearAppData(volumeUuid, packageName, user,
+ storageFlags | FLAG_CLEAR_CACHE_ONLY, 0);
+ if (!clear_cache_result.isOk()) {
+ // It should be fine to continue snapshot if we for some reason failed
+ // to clear cache.
+ LOG(WARNING) << "Failed to clear cache of app " << packageName;
+ }
+
+ // ce_data_inode is not needed when FLAG_CLEAR_CODE_CACHE_ONLY is set.
+ binder::Status clear_code_cache_result = clearAppData(volumeUuid, packageName, user,
+ storageFlags | FLAG_CLEAR_CODE_CACHE_ONLY, 0);
+ if (!clear_code_cache_result.isOk()) {
+ // It should be fine to continue snapshot if we for some reason failed
+ // to clear code_cache.
+ LOG(WARNING) << "Failed to clear code_cache of app " << packageName;
+ }
+
+ 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);
+
+ 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 = 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;
+ return res;
+ }
+ }
+
+ 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);
+
+ 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 = 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;
+ return res;
+ }
+ if (_aidl_return != nullptr) {
+ auto ce_snapshot_path = create_data_misc_ce_rollback_package_path(volume_uuid, user,
+ 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);
+ clear_ce_on_exit = true;
+ return res;
+ }
+ }
+ }
+
+ return res;
+}
+
+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) {
+ ENFORCE_UID(AID_SYSTEM);
+ CHECK_ARGUMENT_UUID_IS_TEST_OR_NULL(volumeUuid);
+ CHECK_ARGUMENT_PACKAGE_NAME(packageName);
+ std::lock_guard<std::recursive_mutex> lock(mLock);
+
+ const char* volume_uuid = volumeUuid ? volumeUuid->c_str() : nullptr;
+ const char* package_name = packageName.c_str();
+
+ auto from_ce = create_data_misc_ce_rollback_package_path(volume_uuid,
+ user, package_name);
+ auto from_de = create_data_misc_de_rollback_package_path(volume_uuid,
+ user, package_name);
+
+ const bool needs_ce_rollback = (storageFlags & FLAG_STORAGE_CE) &&
+ (access(from_ce.c_str(), F_OK) == 0);
+ const bool needs_de_rollback = (storageFlags & FLAG_STORAGE_DE) &&
+ (access(from_de.c_str(), F_OK) == 0);
+
+ if (!needs_ce_rollback && !needs_de_rollback) {
+ return ok();
+ }
+
+ // We know we're going to rollback one of the CE or DE data, so we clear
+ // application data first. Note that it's possible that we're asked to
+ // restore both CE & DE data but that one of the restores fail. Leaving the
+ // 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);
+ if (!res.isOk()) {
+ return res;
+ }
+
+ if (needs_ce_rollback) {
+ auto to_ce = create_data_user_ce_path(volume_uuid, user);
+ int rc = copy_directory_recursive(from_ce.c_str(), to_ce.c_str());
+ if (rc != 0) {
+ res = error(rc, "Failed copying " + from_ce + " to " + to_ce);
+ return res;
+ }
+ }
+
+ if (needs_de_rollback) {
+ auto to_de = create_data_user_de_path(volume_uuid, user);
+ int rc = copy_directory_recursive(from_de.c_str(), to_de.c_str());
+ if (rc != 0) {
+ if (needs_ce_rollback) {
+ auto ce_data = create_data_user_ce_package_path(volume_uuid, user, package_name);
+ LOG(WARNING) << "de_data rollback failed. Erasing rolled back ce_data " << ce_data;
+ if (delete_dir_contents(ce_data.c_str(), 1, nullptr) != 0) {
+ LOG(WARNING) << "Failed to delete rolled back ce_data " << ce_data;
+ }
+ }
+ res = error(rc, "Failed copying " + from_de + " to " + to_de);
+ return res;
+ }
+ }
+
+ // Finally, restore the SELinux label on the app data.
+ return restoreconAppData(volumeUuid, packageName, user, storageFlags, appId, seInfo);
+}
+
+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) {
+ ENFORCE_UID(AID_SYSTEM);
+ CHECK_ARGUMENT_UUID_IS_TEST_OR_NULL(volumeUuid);
+ CHECK_ARGUMENT_PACKAGE_NAME(packageName);
+ std::lock_guard<std::recursive_mutex> lock(mLock);
+
+ const char* volume_uuid = volumeUuid ? volumeUuid->c_str() : nullptr;
+ const char* package_name = packageName.c_str();
+
+ if (storageFlags & FLAG_STORAGE_DE) {
+ auto de_snapshot_path = create_data_misc_de_rollback_package_path(volume_uuid,
+ user, package_name);
+
+ int res = delete_dir_contents_and_dir(de_snapshot_path, true /* ignore_if_missing */);
+ if (res != 0) {
+ return error(res, "Failed clearing snapshot " + de_snapshot_path);
+ }
+ }
+
+ if (storageFlags & FLAG_STORAGE_CE) {
+ auto ce_snapshot_path = create_data_misc_ce_rollback_package_path(volume_uuid,
+ user, 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);
+ }
+ }
+ return ok();
+}
+
+
binder::Status InstalldNativeService::moveCompleteApp(const std::unique_ptr<std::string>& fromUuid,
const std::unique_ptr<std::string>& toUuid, const std::string& packageName,
const std::string& dataAppName, int32_t appId, const std::string& seInfo,
@@ -807,19 +1055,7 @@
auto to = create_data_app_package_path(to_uuid, data_app_name);
auto to_parent = create_data_app_path(to_uuid);
- char *argv[] = {
- (char*) kCpPath,
- (char*) "-F", /* delete any existing destination file first (--remove-destination) */
- (char*) "-p", /* preserve timestamps, ownership, and permissions */
- (char*) "-R", /* recurse into subdirectories (DEST must be a directory) */
- (char*) "-P", /* Do not follow symlinks [default] */
- (char*) "-d", /* don't dereference symlinks */
- (char*) from.c_str(),
- (char*) to_parent.c_str()
- };
-
- LOG(DEBUG) << "Copying " << from << " to " << to;
- int rc = android_fork_execvp(ARRAY_SIZE(argv), argv, nullptr, false, true);
+ int rc = copy_directory_recursive(from.c_str(), to_parent.c_str());
if (rc != 0) {
res = error(rc, "Failed copying " + from + " to " + to);
goto fail;
@@ -847,25 +1083,11 @@
goto fail;
}
- char *argv[] = {
- (char*) kCpPath,
- (char*) "-F", /* delete any existing destination file first (--remove-destination) */
- (char*) "-p", /* preserve timestamps, ownership, and permissions */
- (char*) "-R", /* recurse into subdirectories (DEST must be a directory) */
- (char*) "-P", /* Do not follow symlinks [default] */
- (char*) "-d", /* don't dereference symlinks */
- nullptr,
- nullptr
- };
-
{
auto from = create_data_user_de_package_path(from_uuid, user, package_name);
auto to = create_data_user_de_path(to_uuid, user);
- argv[6] = (char*) from.c_str();
- argv[7] = (char*) to.c_str();
- LOG(DEBUG) << "Copying " << from << " to " << to;
- int rc = android_fork_execvp(ARRAY_SIZE(argv), argv, nullptr, false, true);
+ int rc = copy_directory_recursive(from.c_str(), to.c_str());
if (rc != 0) {
res = error(rc, "Failed copying " + from + " to " + to);
goto fail;
@@ -874,11 +1096,8 @@
{
auto from = create_data_user_ce_package_path(from_uuid, user, package_name);
auto to = create_data_user_ce_path(to_uuid, user);
- argv[6] = (char*) from.c_str();
- argv[7] = (char*) to.c_str();
- LOG(DEBUG) << "Copying " << from << " to " << to;
- int rc = android_fork_execvp(ARRAY_SIZE(argv), argv, nullptr, false, true);
+ int rc = copy_directory_recursive(from.c_str(), to.c_str());
if (rc != 0) {
res = error(rc, "Failed copying " + from + " to " + to);
goto fail;
@@ -1871,6 +2090,17 @@
return res ? error(res, error_msg) : ok();
}
+binder::Status InstalldNativeService::compileLayouts(const std::string& apkPath,
+ const std::string& packageName,
+ const std ::string& outDexFile, int uid,
+ bool* _aidl_return) {
+ const char* apk_path = apkPath.c_str();
+ const char* package_name = packageName.c_str();
+ const char* out_dex_file = outDexFile.c_str();
+ *_aidl_return = android::installd::view_compiler(apk_path, package_name, out_dex_file, uid);
+ return *_aidl_return ? ok() : error("viewcompiler failed");
+}
+
binder::Status InstalldNativeService::markBootComplete(const std::string& instructionSet) {
ENFORCE_UID(AID_SYSTEM);
std::lock_guard<std::recursive_mutex> lock(mLock);
@@ -1916,8 +2146,14 @@
return error("Failed to stat " + _pkgdir);
}
+ char *con = nullptr;
+ if (lgetfilecon(pkgdir, &con) < 0) {
+ return error("Failed to lgetfilecon " + _pkgdir);
+ }
+
if (chown(pkgdir, AID_INSTALL, AID_INSTALL) < 0) {
- return error("Failed to chown " + _pkgdir);
+ res = error("Failed to chown " + _pkgdir);
+ goto out;
}
if (chmod(pkgdir, 0700) < 0) {
@@ -1949,7 +2185,13 @@
goto out;
}
+ if (lsetfilecon(libsymlink, con) < 0) {
+ res = error("Failed to lsetfilecon " + _libsymlink);
+ goto out;
+ }
+
out:
+ free(con);
if (chmod(pkgdir, s.st_mode) < 0) {
auto msg = "Failed to cleanup chmod " + _pkgdir;
if (res.isOk()) {
@@ -2237,7 +2479,7 @@
if (validate_apk_path(packageDir.c_str())) {
return error("Invalid path " + packageDir);
}
- if (delete_dir_contents_and_dir(packageDir) != 0) {
+ if (rm_package_dir(packageDir) != 0) {
return error("Failed to delete " + packageDir);
}
return ok();
diff --git a/cmds/installd/InstalldNativeService.h b/cmds/installd/InstalldNativeService.h
index 367f2c1..578132d 100644
--- a/cmds/installd/InstalldNativeService.h
+++ b/cmds/installd/InstalldNativeService.h
@@ -60,6 +60,16 @@
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);
+ 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);
+ 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);
+
binder::Status getAppSize(const std::unique_ptr<std::string>& uuid,
const std::vector<std::string>& packageNames, int32_t userId, int32_t flags,
int32_t appId, const std::vector<int64_t>& ceDataInodes,
@@ -89,6 +99,9 @@
const std::unique_ptr<std::string>& dexMetadataPath,
const std::unique_ptr<std::string>& compilationReason);
+ binder::Status compileLayouts(const std::string& apkPath, const std::string& packageName,
+ const std::string& outDexFile, int uid, bool* _aidl_return);
+
binder::Status rmdex(const std::string& codePath, const std::string& instructionSet);
binder::Status mergeProfiles(int32_t uid, const std::string& packageName,
diff --git a/cmds/installd/binder/android/os/IInstalld.aidl b/cmds/installd/binder/android/os/IInstalld.aidl
index 89b08e5..b345210 100644
--- a/cmds/installd/binder/android/os/IInstalld.aidl
+++ b/cmds/installd/binder/android/os/IInstalld.aidl
@@ -55,6 +55,8 @@
@nullable @utf8InCpp String profileName,
@nullable @utf8InCpp String dexMetadataPath,
@nullable @utf8InCpp String compilationReason);
+ boolean compileLayouts(@utf8InCpp String apkPath, @utf8InCpp String packageName,
+ @utf8InCpp String outDexFile, int uid);
void rmdex(@utf8InCpp String codePath, @utf8InCpp String instructionSet);
@@ -103,6 +105,13 @@
int userId, int appId, @utf8InCpp String profileName, @utf8InCpp String codePath,
@nullable @utf8InCpp String dexMetadata);
+ long snapshotAppData(@nullable @utf8InCpp String uuid, in @utf8InCpp String packageName,
+ int userId, int storageFlags);
+ void restoreAppDataSnapshot(@nullable @utf8InCpp String uuid, in @utf8InCpp String packageName,
+ int appId, long ceDataInode, @utf8InCpp String seInfo, int user, int storageflags);
+ void destroyAppDataSnapshot(@nullable @utf8InCpp String uuid, @utf8InCpp String packageName,
+ int userId, long ceSnapshotInode, 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 32c1313..a639951 100644
--- a/cmds/installd/dexopt.cpp
+++ b/cmds/installd/dexopt.cpp
@@ -43,6 +43,7 @@
#include <log/log.h> // TODO: Move everything to base/logging.
#include <openssl/sha.h>
#include <private/android_filesystem_config.h>
+#include <processgroup/sched_policy.h>
#include <selinux/android.h>
#include <system/thread_defs.h>
@@ -313,9 +314,15 @@
bool skip_compilation = vold_decrypt == "trigger_restart_min_framework" ||
vold_decrypt == "1";
- const std::string resolve_startup_string_arg =
+ std::string resolve_startup_string_arg =
+ MapPropertyToArg("persist.device_config.runtime.dex2oat_resolve_startup_strings",
+ "--resolve-startup-const-strings=%s");
+ if (resolve_startup_string_arg.empty()) {
+ // If empty, fall back to system property.
+ resolve_startup_string_arg =
MapPropertyToArg("dalvik.vm.dex2oat-resolve-startup-strings",
"--resolve-startup-const-strings=%s");
+ }
const std::string image_block_size_arg =
MapPropertyToArg("dalvik.vm.dex2oat-max-image-block-size",
@@ -332,8 +339,7 @@
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 = "/system/bin/dex2oat";
- constexpr const char* kDex2oatDebugPath = "/system/bin/dex2oatd";
+ 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() ||
@@ -627,27 +633,6 @@
}
}
-static void drop_capabilities(uid_t uid) {
- if (setgid(uid) != 0) {
- PLOG(ERROR) << "setgid(" << uid << ") failed in installd during dexopt";
- exit(DexoptReturnCodes::kSetGid);
- }
- if (setuid(uid) != 0) {
- PLOG(ERROR) << "setuid(" << uid << ") failed in installd during dexopt";
- exit(DexoptReturnCodes::kSetUid);
- }
- // drop capabilities
- struct __user_cap_header_struct capheader;
- struct __user_cap_data_struct capdata[2];
- memset(&capheader, 0, sizeof(capheader));
- memset(&capdata, 0, sizeof(capdata));
- capheader.version = _LINUX_CAPABILITY_VERSION_3;
- if (capset(&capheader, &capdata[0]) < 0) {
- PLOG(ERROR) << "capset failed";
- exit(DexoptReturnCodes::kCapSet);
- }
-}
-
static constexpr int PROFMAN_BIN_RETURN_CODE_COMPILE = 0;
static constexpr int PROFMAN_BIN_RETURN_CODE_SKIP_COMPILATION = 1;
static constexpr int PROFMAN_BIN_RETURN_CODE_BAD_PROFILES = 2;
@@ -662,8 +647,7 @@
const std::vector<std::string>& dex_locations,
bool copy_and_update,
bool store_aggregation_counters) {
- const char* profman_bin =
- is_debug_runtime() ? "/system/bin/profmand" : "/system/bin/profman";
+ const char* profman_bin = is_debug_runtime() ? kProfmanDebugPath: kProfmanPath;
if (copy_and_update) {
CHECK_EQ(1u, profile_fds.size());
@@ -1479,9 +1463,7 @@
const char* class_loader_context) {
CHECK_GE(zip_fd, 0);
const char* dexoptanalyzer_bin =
- is_debug_runtime()
- ? "/system/bin/dexoptanalyzerd"
- : "/system/bin/dexoptanalyzer";
+ is_debug_runtime() ? kDexoptanalyzerDebugPath : kDexoptanalyzerPath;
std::string dex_file_arg = "--dex-file=" + dex_file;
std::string oat_fd_arg = "--oat-fd=" + std::to_string(oat_fd);
diff --git a/cmds/installd/dexopt.h b/cmds/installd/dexopt.h
index 0db11e1..5902659 100644
--- a/cmds/installd/dexopt.h
+++ b/cmds/installd/dexopt.h
@@ -32,6 +32,16 @@
static constexpr int DEX2OAT_FOR_BOOT_IMAGE = 2;
static constexpr int DEX2OAT_FOR_FILTER = 3;
+#define ANDROID_RUNTIME_APEX_BIN "/apex/com.android.runtime/bin"
+// 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* 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";
+#undef ANDROID_RUNTIME_APEX_BIN
+
// Clear the reference profile identified by the given profile name.
bool clear_primary_reference_profile(const std::string& pkgname, const std::string& profile_name);
// Clear the current profile identified by the given profile name (for single user).
diff --git a/cmds/installd/otapreopt.cpp b/cmds/installd/otapreopt.cpp
index b2e7047..de7b249 100644
--- a/cmds/installd/otapreopt.cpp
+++ b/cmds/installd/otapreopt.cpp
@@ -26,7 +26,6 @@
#include <sys/capability.h>
#include <sys/prctl.h>
#include <sys/stat.h>
-#include <sys/wait.h>
#include <android-base/logging.h>
#include <android-base/macros.h>
@@ -58,7 +57,6 @@
#define REPLY_MAX 256 /* largest reply allowed */
using android::base::EndsWith;
-using android::base::Join;
using android::base::Split;
using android::base::StartsWith;
using android::base::StringPrintf;
@@ -440,7 +438,7 @@
const char* isa) const {
// This needs to be kept in sync with ART, see art/runtime/gc/space/image_space.cc.
std::vector<std::string> cmd;
- cmd.push_back("/system/bin/dex2oat");
+ cmd.push_back(kDex2oatPath);
cmd.push_back(StringPrintf("--image=%s", art_path.c_str()));
for (const std::string& boot_part : Split(boot_cp, ":")) {
cmd.push_back(StringPrintf("--dex-file=%s", boot_part.c_str()));
@@ -619,61 +617,6 @@
// Helpers, mostly taken from ART //
////////////////////////////////////
- // Wrapper on fork/execv to run a command in a subprocess.
- static bool Exec(const std::vector<std::string>& arg_vector, std::string* error_msg) {
- const std::string command_line = Join(arg_vector, ' ');
-
- CHECK_GE(arg_vector.size(), 1U) << command_line;
-
- // Convert the args to char pointers.
- const char* program = arg_vector[0].c_str();
- std::vector<char*> args;
- for (size_t i = 0; i < arg_vector.size(); ++i) {
- const std::string& arg = arg_vector[i];
- char* arg_str = const_cast<char*>(arg.c_str());
- CHECK(arg_str != nullptr) << i;
- args.push_back(arg_str);
- }
- args.push_back(nullptr);
-
- // Fork and exec.
- pid_t pid = fork();
- if (pid == 0) {
- // No allocation allowed between fork and exec.
-
- // Change process groups, so we don't get reaped by ProcessManager.
- setpgid(0, 0);
-
- execv(program, &args[0]);
-
- PLOG(ERROR) << "Failed to execv(" << command_line << ")";
- // _exit to avoid atexit handlers in child.
- _exit(1);
- } else {
- if (pid == -1) {
- *error_msg = StringPrintf("Failed to execv(%s) because fork failed: %s",
- command_line.c_str(), strerror(errno));
- return false;
- }
-
- // wait for subprocess to finish
- int status;
- pid_t got_pid = TEMP_FAILURE_RETRY(waitpid(pid, &status, 0));
- if (got_pid != pid) {
- *error_msg = StringPrintf("Failed after fork for execv(%s) because waitpid failed: "
- "wanted %d, got %d: %s",
- command_line.c_str(), pid, got_pid, strerror(errno));
- return false;
- }
- if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
- *error_msg = StringPrintf("Failed execv(%s) because non-0 exit status",
- command_line.c_str());
- return false;
- }
- }
- return true;
- }
-
// Choose a random relocation offset. Taken from art/runtime/gc/image_space.cc.
static int32_t ChooseRelocationOffsetDelta(int32_t min_delta, int32_t max_delta) {
constexpr size_t kPageSize = PAGE_SIZE;
diff --git a/cmds/installd/otapreopt_chroot.cpp b/cmds/installd/otapreopt_chroot.cpp
index e90cf3b..609ddaf 100644
--- a/cmds/installd/otapreopt_chroot.cpp
+++ b/cmds/installd/otapreopt_chroot.cpp
@@ -17,6 +17,7 @@
#include <fcntl.h>
#include <linux/unistd.h>
#include <sys/mount.h>
+#include <sys/stat.h>
#include <sys/wait.h>
#include <sstream>
@@ -24,6 +25,9 @@
#include <android-base/logging.h>
#include <android-base/macros.h>
#include <android-base/stringprintf.h>
+#include <selinux/android.h>
+
+#include <apexd.h>
#include "installd_constants.h"
#include "otapreopt_utils.h"
@@ -37,6 +41,23 @@
namespace android {
namespace installd {
+// Configuration for bind-mounted Bionic artifacts.
+
+static constexpr const char* kLinkerMountPoint = "/bionic/bin/linker";
+static constexpr const char* kRuntimeLinkerPath = "/apex/com.android.runtime/bin/linker";
+
+static constexpr const char* kBionicLibsMountPointDir = "/bionic/lib/";
+static constexpr const char* kRuntimeBionicLibsDir = "/apex/com.android.runtime/lib/bionic/";
+
+static constexpr const char* kLinkerMountPoint64 = "/bionic/bin/linker64";
+static constexpr const char* kRuntimeLinkerPath64 = "/apex/com.android.runtime/bin/linker64";
+
+static constexpr const char* kBionicLibsMountPointDir64 = "/bionic/lib64/";
+static constexpr const char* kRuntimeBionicLibsDir64 = "/apex/com.android.runtime/lib64/bionic/";
+
+static const std::vector<std::string> kBionicLibFileNames = {"libc.so", "libm.so", "libdl.so"};
+
+
static void CloseDescriptor(int fd) {
if (fd >= 0) {
int result = close(fd);
@@ -54,6 +75,64 @@
}
}
+static std::vector<apex::ApexFile> ActivateApexPackages() {
+ // The logic here is (partially) copied and adapted from
+ // system/apex/apexd/apexd_main.cpp.
+ //
+ // Only scan the APEX directory under /system (within the chroot dir).
+ // Note that this leaves around the loop devices created and used by
+ // libapexd's code, but this is fine, as we expect to reboot soon after.
+ apex::scanPackagesDirAndActivate(apex::kApexPackageSystemDir);
+ return apex::getActivePackages();
+}
+
+static void DeactivateApexPackages(const std::vector<apex::ApexFile>& active_packages) {
+ for (const apex::ApexFile& apex_file : active_packages) {
+ const std::string& package_path = apex_file.GetPath();
+ apex::Status status = apex::deactivatePackage(package_path);
+ if (!status.Ok()) {
+ LOG(ERROR) << "Failed to deactivate " << package_path << ": " << status.ErrorMessage();
+ }
+ }
+}
+
+// Copied from system/core/init/mount_namespace.cpp.
+static bool BindMount(const std::string& source, const std::string& mount_point,
+ bool recursive = false) {
+ unsigned long mountflags = MS_BIND;
+ if (recursive) {
+ mountflags |= MS_REC;
+ }
+ if (mount(source.c_str(), mount_point.c_str(), nullptr, mountflags, nullptr) == -1) {
+ PLOG(ERROR) << "Could not bind-mount " << source << " to " << mount_point;
+ return false;
+ }
+ return true;
+}
+
+// Copied from system/core/init/mount_namespace.cpp and and adjusted (bind
+// mounts are not made private, as the /postinstall is already private (see
+// `android::installd::otapreopt_chroot`).
+static bool BindMountBionic(const std::string& linker_source, const std::string& lib_dir_source,
+ const std::string& linker_mount_point,
+ const std::string& lib_mount_dir) {
+ if (access(linker_source.c_str(), F_OK) != 0) {
+ PLOG(INFO) << linker_source << " does not exist. Skipping mounting Bionic there.";
+ return true;
+ }
+ if (!BindMount(linker_source, linker_mount_point)) {
+ return false;
+ }
+ for (const auto& libname : kBionicLibFileNames) {
+ std::string mount_point = lib_mount_dir + libname;
+ std::string source = lib_dir_source + libname;
+ if (!BindMount(source, mount_point)) {
+ return false;
+ }
+ }
+ return true;
+}
+
// Entry for otapreopt_chroot. Expected parameters are:
// [cmd] [status-fd] [target-slot] "dexopt" [dexopt-params]
// The file descriptor denoted by status-fd will be closed. The rest of the parameters will
@@ -138,6 +217,44 @@
UNUSED(product_result);
}
+ // Setup APEX mount point and its security context.
+ static constexpr const char* kPostinstallApexDir = "/postinstall/apex";
+ // The following logic is similar to the one in system/core/rootdir/init.rc:
+ //
+ // mount tmpfs tmpfs /apex nodev noexec nosuid
+ // chmod 0755 /apex
+ // chown root root /apex
+ // restorecon /apex
+ //
+ // except we perform the `restorecon` step just after mounting the tmpfs
+ // filesystem in /postinstall/apex, so that this directory is correctly
+ // labeled (with type `postinstall_apex_mnt_dir`) and may be manipulated in
+ // following operations (`chmod`, `chown`, etc.) following policies
+ // restricted to `postinstall_apex_mnt_dir`:
+ //
+ // mount tmpfs tmpfs /postinstall/apex nodev noexec nosuid
+ // restorecon /postinstall/apex
+ // chmod 0755 /postinstall/apex
+ // chown root root /postinstall/apex
+ //
+ if (mount("tmpfs", kPostinstallApexDir, "tmpfs", MS_NODEV | MS_NOEXEC | MS_NOSUID, nullptr)
+ != 0) {
+ PLOG(ERROR) << "Failed to mount tmpfs in " << kPostinstallApexDir;
+ exit(209);
+ }
+ if (selinux_android_restorecon(kPostinstallApexDir, 0) < 0) {
+ PLOG(ERROR) << "Failed to restorecon " << kPostinstallApexDir;
+ exit(214);
+ }
+ if (chmod(kPostinstallApexDir, 0755) != 0) {
+ PLOG(ERROR) << "Failed to chmod " << kPostinstallApexDir << " to 0755";
+ exit(210);
+ }
+ if (chown(kPostinstallApexDir, 0, 0) != 0) {
+ PLOG(ERROR) << "Failed to chown " << kPostinstallApexDir << " to root:root";
+ exit(211);
+ }
+
// Chdir into /postinstall.
if (chdir("/postinstall") != 0) {
PLOG(ERROR) << "Unable to chdir into /postinstall.";
@@ -155,22 +272,55 @@
exit(205);
}
- // Now go on and run otapreopt.
+ // Try to mount APEX packages in "/apex" in the chroot dir. We need at least
+ // the Android Runtime APEX, as it is required by otapreopt to run dex2oat.
+ std::vector<apex::ApexFile> active_packages = ActivateApexPackages();
- // Incoming: cmd + status-fd + target-slot + cmd... + null | Incoming | = argc + 1
- // Outgoing: cmd + target-slot + cmd... + null | Outgoing | = argc
- const char** argv = new const char*[argc];
-
- argv[0] = "/system/bin/otapreopt";
-
- // The first parameter is the status file descriptor, skip.
- for (size_t i = 2; i <= static_cast<size_t>(argc); ++i) {
- argv[i - 1] = arg[i];
+ // Bind-mount Bionic artifacts from the Runtime APEX.
+ // This logic is copied and adapted from system/core/init/mount_namespace.cpp.
+ if (!BindMountBionic(kRuntimeLinkerPath, kRuntimeBionicLibsDir, kLinkerMountPoint,
+ kBionicLibsMountPointDir)) {
+ LOG(ERROR) << "Failed to mount 32-bit Bionic artifacts from the Runtime APEX.";
+ // Clean up and exit.
+ DeactivateApexPackages(active_packages);
+ exit(215);
+ }
+ if (!BindMountBionic(kRuntimeLinkerPath64, kRuntimeBionicLibsDir64, kLinkerMountPoint64,
+ kBionicLibsMountPointDir64)) {
+ LOG(ERROR) << "Failed to mount 64-bit Bionic artifacts from the Runtime APEX.";
+ // Clean up and exit.
+ DeactivateApexPackages(active_packages);
+ exit(216);
}
- execv(argv[0], static_cast<char * const *>(const_cast<char**>(argv)));
- PLOG(ERROR) << "execv(OTAPREOPT) failed.";
- exit(99);
+ // Now go on and run otapreopt.
+
+ // Incoming: cmd + status-fd + target-slot + cmd... | Incoming | = argc
+ // Outgoing: cmd + target-slot + cmd... | Outgoing | = argc - 1
+ std::vector<std::string> cmd;
+ cmd.reserve(argc);
+ cmd.push_back("/system/bin/otapreopt");
+
+ // The first parameter is the status file descriptor, skip.
+ for (size_t i = 2; i < static_cast<size_t>(argc); ++i) {
+ cmd.push_back(arg[i]);
+ }
+
+ // Fork and execute otapreopt in its own process.
+ std::string error_msg;
+ bool exec_result = Exec(cmd, &error_msg);
+ if (!exec_result) {
+ LOG(ERROR) << "Running otapreopt failed: " << error_msg;
+ }
+
+ // Tear down the work down by the apexd logic. (i.e. deactivate packages).
+ DeactivateApexPackages(active_packages);
+
+ if (!exec_result) {
+ exit(213);
+ }
+
+ return 0;
}
} // namespace installd
diff --git a/cmds/installd/otapreopt_utils.cpp b/cmds/installd/otapreopt_utils.cpp
new file mode 100644
index 0000000..124f726
--- /dev/null
+++ b/cmds/installd/otapreopt_utils.cpp
@@ -0,0 +1,88 @@
+/*
+ ** 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 "otapreopt_utils.h"
+
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
+
+using android::base::Join;
+using android::base::StringPrintf;
+
+namespace android {
+namespace installd {
+
+bool Exec(const std::vector<std::string>& arg_vector, std::string* error_msg) {
+ const std::string command_line = Join(arg_vector, ' ');
+
+ CHECK_GE(arg_vector.size(), 1U) << command_line;
+
+ // Convert the args to char pointers.
+ const char* program = arg_vector[0].c_str();
+ std::vector<char*> args;
+ for (size_t i = 0; i < arg_vector.size(); ++i) {
+ const std::string& arg = arg_vector[i];
+ char* arg_str = const_cast<char*>(arg.c_str());
+ CHECK(arg_str != nullptr) << i;
+ args.push_back(arg_str);
+ }
+ args.push_back(nullptr);
+
+ // Fork and exec.
+ pid_t pid = fork();
+ if (pid == 0) {
+ // No allocation allowed between fork and exec.
+
+ // Change process groups, so we don't get reaped by ProcessManager.
+ setpgid(0, 0);
+
+ execv(program, &args[0]);
+
+ PLOG(ERROR) << "Failed to execv(" << command_line << ")";
+ // _exit to avoid atexit handlers in child.
+ _exit(1);
+ } else {
+ if (pid == -1) {
+ *error_msg = StringPrintf("Failed to execv(%s) because fork failed: %s",
+ command_line.c_str(), strerror(errno));
+ return false;
+ }
+
+ // wait for subprocess to finish
+ int status;
+ pid_t got_pid = TEMP_FAILURE_RETRY(waitpid(pid, &status, 0));
+ if (got_pid != pid) {
+ *error_msg = StringPrintf("Failed after fork for execv(%s) because waitpid failed: "
+ "wanted %d, got %d: %s",
+ command_line.c_str(), pid, got_pid, strerror(errno));
+ return false;
+ }
+ if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
+ *error_msg = StringPrintf("Failed execv(%s) because non-0 exit status",
+ command_line.c_str());
+ return false;
+ }
+ }
+ return true;
+}
+
+} // namespace installd
+} // namespace android
diff --git a/cmds/installd/otapreopt_utils.h b/cmds/installd/otapreopt_utils.h
index 436e554..03a6d87 100644
--- a/cmds/installd/otapreopt_utils.h
+++ b/cmds/installd/otapreopt_utils.h
@@ -18,6 +18,8 @@
#define OTAPREOPT_UTILS_H_
#include <regex>
+#include <string>
+#include <vector>
namespace android {
namespace installd {
@@ -28,6 +30,9 @@
return std::regex_match(input, slot_suffix_match, slot_suffix_regex);
}
+// Wrapper on fork/execv to run a command in a subprocess.
+bool Exec(const std::vector<std::string>& arg_vector, std::string* error_msg);
+
} // namespace installd
} // namespace android
diff --git a/cmds/installd/tests/Android.bp b/cmds/installd/tests/Android.bp
index 739f33f..9c9db0f 100644
--- a/cmds/installd/tests/Android.bp
+++ b/cmds/installd/tests/Android.bp
@@ -28,6 +28,7 @@
"libbinder",
"libcrypto",
"libcutils",
+ "libprocessgroup",
"libselinux",
"libutils",
],
@@ -50,6 +51,7 @@
"libbinder",
"libcrypto",
"libcutils",
+ "libprocessgroup",
"libselinux",
"libutils",
],
@@ -72,6 +74,7 @@
"libbinder",
"libcrypto",
"libcutils",
+ "libprocessgroup",
"libselinux",
"libutils",
],
diff --git a/cmds/installd/tests/binder_test_utils.h b/cmds/installd/tests/binder_test_utils.h
new file mode 100644
index 0000000..efd1391
--- /dev/null
+++ b/cmds/installd/tests/binder_test_utils.h
@@ -0,0 +1,46 @@
+/*
+ * 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/Status.h>
+#include <gtest/gtest.h>
+#include <utils/String8.h>
+
+#define ASSERT_BINDER_SUCCESS(expr) \
+ ({ \
+ binder::Status expect_status = (expr); \
+ ASSERT_TRUE(expect_status.isOk()) << expect_status.toString8().c_str(); \
+ expect_status; \
+ })
+#define ASSERT_BINDER_FAIL(expr) \
+ ({ \
+ binder::Status expect_status = (expr); \
+ ASSERT_FALSE(expect_status.isOk()); \
+ expect_status; \
+ })
+#define EXPECT_BINDER_SUCCESS(expr) \
+ ({ \
+ binder::Status expect_status = (expr); \
+ EXPECT_TRUE(expect_status.isOk()) << expect_status.toString8().c_str(); \
+ expect_status; \
+ })
+#define EXPECT_BINDER_FAIL(expr) \
+ ({ \
+ binder::Status expect_status = (expr); \
+ EXPECT_FALSE(expect_status.isOk()); \
+ expect_status; \
+ })
diff --git a/cmds/installd/tests/installd_dexopt_test.cpp b/cmds/installd/tests/installd_dexopt_test.cpp
index 79e6859..78edce0 100644
--- a/cmds/installd/tests/installd_dexopt_test.cpp
+++ b/cmds/installd/tests/installd_dexopt_test.cpp
@@ -23,9 +23,11 @@
#include <android-base/file.h>
#include <android-base/logging.h>
+#include <android-base/properties.h>
+#include <android-base/scopeguard.h>
#include <android-base/stringprintf.h>
#include <android-base/unique_fd.h>
-
+#include <binder/Status.h>
#include <cutils/properties.h>
#include <gtest/gtest.h>
@@ -33,6 +35,7 @@
#include <selinux/android.h>
#include <selinux/avc.h>
+#include "binder_test_utils.h"
#include "dexopt.h"
#include "InstalldNativeService.h"
#include "globals.h"
@@ -84,6 +87,23 @@
system(cmd.c_str());
}
+template <typename Visitor>
+static void run_cmd_and_process_output(const std::string& cmd, const Visitor& visitor) {
+ FILE* file = popen(cmd.c_str(), "r");
+ CHECK(file != nullptr) << "Failed to ptrace " << cmd;
+ char* line = nullptr;
+ while (true) {
+ size_t n = 0u;
+ ssize_t value = getline(&line, &n, file);
+ if (value == -1) {
+ break;
+ }
+ visitor(line);
+ }
+ free(line);
+ fclose(file);
+}
+
static int mkdir(const std::string& path, uid_t owner, gid_t group, mode_t mode) {
int ret = ::mkdir(path.c_str(), mode);
if (ret != 0) {
@@ -221,7 +241,8 @@
::testing::AssertionResult create_mock_app() {
// Create the oat dir.
app_oat_dir_ = app_apk_dir_ + "/oat";
- if (mkdir(app_apk_dir_, kSystemUid, kSystemGid, 0755) != 0) {
+ // For debug mode, the directory might already exist. Avoid erroring out.
+ if (mkdir(app_apk_dir_, kSystemUid, kSystemGid, 0755) != 0 && !kDebug) {
return ::testing::AssertionFailure() << "Could not create app dir " << app_apk_dir_
<< " : " << strerror(errno);
}
@@ -451,11 +472,9 @@
std::unique_ptr<std::string> compilation_reason_ptr(new std::string("test-reason"));
bool prof_result;
- binder::Status prof_binder_result = service_->prepareAppProfile(
+ ASSERT_BINDER_SUCCESS(service_->prepareAppProfile(
package_name_, kTestUserId, kTestAppId, *profile_name_ptr, apk_path_,
- /*dex_metadata*/ nullptr, &prof_result);
-
- ASSERT_TRUE(prof_binder_result.isOk()) << prof_binder_result.toString8().c_str();
+ /*dex_metadata*/ nullptr, &prof_result));
ASSERT_TRUE(prof_result);
binder::Status result = service_->dexopt(apk_path_,
@@ -629,6 +648,50 @@
DEX2OAT_FROM_SCRATCH);
}
+TEST_F(DexoptTest, ResolveStartupConstStrings) {
+ LOG(INFO) << "DexoptDex2oatResolveStartupStrings";
+ const std::string property = "persist.device_config.runtime.dex2oat_resolve_startup_strings";
+ const std::string previous_value = android::base::GetProperty(property, "");
+ auto restore_property = android::base::make_scope_guard([=]() {
+ android::base::SetProperty(property, previous_value);
+ });
+ std::string odex = GetPrimaryDexArtifact(app_oat_dir_.c_str(), apk_path_, "odex");
+ // Disable the property to start.
+ bool found_disable = false;
+ ASSERT_TRUE(android::base::SetProperty(property, "false")) << property;
+ CompilePrimaryDexOk("speed-profile",
+ DEXOPT_IDLE_BACKGROUND_JOB | DEXOPT_PROFILE_GUIDED |
+ DEXOPT_GENERATE_APP_IMAGE,
+ app_oat_dir_.c_str(),
+ kTestAppGid,
+ DEX2OAT_FROM_SCRATCH);
+ run_cmd_and_process_output(
+ "oatdump --header-only --oat-file=" + odex,
+ [&](const std::string& line) {
+ if (line.find("--resolve-startup-const-strings=false") != std::string::npos) {
+ found_disable = true;
+ }
+ });
+ EXPECT_TRUE(found_disable);
+ // Enable the property and inspect that .art artifact is larger.
+ bool found_enable = false;
+ ASSERT_TRUE(android::base::SetProperty(property, "true")) << property;
+ CompilePrimaryDexOk("speed-profile",
+ DEXOPT_IDLE_BACKGROUND_JOB | DEXOPT_PROFILE_GUIDED |
+ DEXOPT_GENERATE_APP_IMAGE,
+ app_oat_dir_.c_str(),
+ kTestAppGid,
+ DEX2OAT_FROM_SCRATCH);
+ run_cmd_and_process_output(
+ "oatdump --header-only --oat-file=" + odex,
+ [&](const std::string& line) {
+ if (line.find("--resolve-startup-const-strings=true") != std::string::npos) {
+ found_enable = true;
+ }
+ });
+ EXPECT_TRUE(found_enable);
+}
+
class PrimaryDexReCompilationTest : public DexoptTest {
public:
virtual void SetUp() {
@@ -760,9 +823,8 @@
void createProfileSnapshot(int32_t appid, const std::string& package_name,
bool expected_result) {
bool result;
- binder::Status binder_result = service_->createProfileSnapshot(
- appid, package_name, kPrimaryProfile, apk_path_, &result);
- ASSERT_TRUE(binder_result.isOk()) << binder_result.toString8().c_str();
+ ASSERT_BINDER_SUCCESS(service_->createProfileSnapshot(
+ appid, package_name, kPrimaryProfile, apk_path_, &result));
ASSERT_EQ(expected_result, result);
if (!expected_result) {
@@ -802,9 +864,8 @@
const std::string& code_path,
bool expected_result) {
bool result;
- binder::Status binder_result = service_->mergeProfiles(
- kTestAppUid, package_name, code_path, &result);
- ASSERT_TRUE(binder_result.isOk()) << binder_result.toString8().c_str();
+ ASSERT_BINDER_SUCCESS(service_->mergeProfiles(
+ kTestAppUid, package_name, code_path, &result));
ASSERT_EQ(expected_result, result);
if (!expected_result) {
@@ -830,10 +891,9 @@
void preparePackageProfile(const std::string& package_name, const std::string& profile_name,
bool expected_result) {
bool result;
- binder::Status binder_result = service_->prepareAppProfile(
+ ASSERT_BINDER_SUCCESS(service_->prepareAppProfile(
package_name, kTestUserId, kTestAppId, profile_name, apk_path_,
- /*dex_metadata*/ nullptr, &result);
- ASSERT_TRUE(binder_result.isOk()) << binder_result.toString8().c_str();
+ /*dex_metadata*/ nullptr, &result));
ASSERT_EQ(expected_result, result);
if (!expected_result) {
@@ -919,8 +979,7 @@
SetupProfiles(/*setup_ref*/ true);
createProfileSnapshot(kTestAppId, package_name_, /*expected_result*/ true);
- binder::Status binder_result = service_->destroyProfileSnapshot(package_name_, kPrimaryProfile);
- ASSERT_TRUE(binder_result.isOk()) << binder_result.toString8().c_str();
+ ASSERT_BINDER_SUCCESS(service_->destroyProfileSnapshot(package_name_, kPrimaryProfile));
struct stat st;
ASSERT_EQ(-1, stat(snap_profile_.c_str(), &st));
ASSERT_EQ(ENOENT, errno);
@@ -978,7 +1037,7 @@
ASSERT_EQ(0, chmod(ref_profile_dir.c_str(), 0700));
// Run createAppData again which will offer to fix-up the profile directories.
- ASSERT_TRUE(service_->createAppData(
+ ASSERT_BINDER_SUCCESS(service_->createAppData(
volume_uuid_,
package_name_,
kTestUserId,
@@ -986,7 +1045,7 @@
kTestAppUid,
se_info_,
kOSdkVersion,
- &ce_data_inode_).isOk());
+ &ce_data_inode_));
// Check the file access.
CheckFileAccess(cur_profile_dir, kTestAppUid, kTestAppUid, 0700 | S_IFDIR);
@@ -1032,9 +1091,8 @@
void createBootImageProfileSnapshot(const std::string& classpath, bool expected_result) {
bool result;
- binder::Status binder_result = service_->createProfileSnapshot(
- -1, "android", "android.prof", classpath, &result);
- ASSERT_TRUE(binder_result.isOk());
+ ASSERT_BINDER_SUCCESS(service_->createProfileSnapshot(
+ -1, "android", "android.prof", classpath, &result));
ASSERT_EQ(expected_result, result);
if (!expected_result) {
diff --git a/cmds/installd/tests/installd_service_test.cpp b/cmds/installd/tests/installd_service_test.cpp
index 9dad995..cc24ab3 100644
--- a/cmds/installd/tests/installd_service_test.cpp
+++ b/cmds/installd/tests/installd_service_test.cpp
@@ -15,16 +15,23 @@
*/
#include <sstream>
+#include <string>
+
+#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <sys/statvfs.h>
#include <sys/xattr.h>
+#include <android-base/file.h>
#include <android-base/logging.h>
+#include <android-base/properties.h>
+#include <android-base/scopeguard.h>
#include <android-base/stringprintf.h>
#include <cutils/properties.h>
#include <gtest/gtest.h>
+#include "binder_test_utils.h"
#include "InstalldNativeService.h"
#include "dexopt.h"
#include "globals.h"
@@ -162,8 +169,8 @@
std::vector<uint8_t> result;
std::string dexPath = get_full_path("com.example/foo/file");
- EXPECT_TRUE(service->hashSecondaryDexFile(
- dexPath, "com.example", 10000, testUuid, FLAG_STORAGE_CE, &result).isOk());
+ EXPECT_BINDER_SUCCESS(service->hashSecondaryDexFile(
+ dexPath, "com.example", 10000, testUuid, FLAG_STORAGE_CE, &result));
EXPECT_EQ(result.size(), 32U);
@@ -182,8 +189,8 @@
std::vector<uint8_t> result;
std::string dexPath = get_full_path("com.example/foo/file");
- EXPECT_TRUE(service->hashSecondaryDexFile(
- dexPath, "com.example", 10000, testUuid, FLAG_STORAGE_CE, &result).isOk());
+ EXPECT_BINDER_SUCCESS(service->hashSecondaryDexFile(
+ dexPath, "com.example", 10000, testUuid, FLAG_STORAGE_CE, &result));
EXPECT_EQ(result.size(), 0U);
}
@@ -197,8 +204,8 @@
std::vector<uint8_t> result;
std::string dexPath = get_full_path("com.example/foo/file");
- EXPECT_TRUE(service->hashSecondaryDexFile(
- dexPath, "com.example", 10000, testUuid, FLAG_STORAGE_CE, &result).isOk());
+ EXPECT_BINDER_SUCCESS(service->hashSecondaryDexFile(
+ dexPath, "com.example", 10000, testUuid, FLAG_STORAGE_CE, &result));
EXPECT_EQ(result.size(), 0U);
}
@@ -212,8 +219,8 @@
std::vector<uint8_t> result;
std::string dexPath = get_full_path("com.example/foo/file");
- EXPECT_FALSE(service->hashSecondaryDexFile(
- dexPath, "com.wrong", 10000, testUuid, FLAG_STORAGE_CE, &result).isOk());
+ EXPECT_BINDER_FAIL(service->hashSecondaryDexFile(
+ dexPath, "com.wrong", 10000, testUuid, FLAG_STORAGE_CE, &result));
}
TEST_F(ServiceTest, CalculateOat) {
@@ -240,5 +247,467 @@
EXPECT_EQ("/data/dalvik-cache/isa/path@to@file.apk@classes.dex", std::string(buf));
}
+static bool mkdirs(const std::string& path, mode_t mode) {
+ struct stat sb;
+ if (stat(path.c_str(), &sb) != -1 && S_ISDIR(sb.st_mode)) {
+ return true;
+ }
+
+ if (!mkdirs(android::base::Dirname(path), mode)) {
+ return false;
+ }
+
+ return (::mkdir(path.c_str(), mode) != -1);
+}
+
+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);
+
+ 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(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 */));
+
+ // 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));
+ struct stat buf;
+ memset(&buf, 0, sizeof(buf));
+ ASSERT_EQ(0, stat((rollback_ce_dir + "/com.foo").c_str(), &buf));
+ ASSERT_EQ(ce_snapshot_inode, (int64_t) buf.st_ino);
+
+ std::string ce_content, de_content;
+ // At this point, we should have the CE content but not the DE content.
+ ASSERT_TRUE(android::base::ReadFileToString(
+ rollback_ce_dir + "/com.foo/file1", &ce_content, false /* follow_symlinks */));
+ ASSERT_FALSE(android::base::ReadFileToString(
+ rollback_de_dir + "/com.foo/file1", &de_content, false /* follow_symlinks */));
+ ASSERT_EQ("TEST_CONTENT_CE", ce_content);
+
+ // Modify the CE content, so we can assert later that it's reflected
+ // in the snapshot.
+ ASSERT_TRUE(android::base::WriteStringToFile(
+ "TEST_CONTENT_CE_MODIFIED", fake_package_ce_path + "/file1",
+ 0700, 10000, 20000, false /* follow_symlinks */));
+
+ // 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));
+ // Only DE content snapshot was requested.
+ ASSERT_EQ(ce_snapshot_inode, 0);
+
+ // At this point, both the CE as well as the DE content should be fully
+ // populated.
+ ASSERT_TRUE(android::base::ReadFileToString(
+ rollback_ce_dir + "/com.foo/file1", &ce_content, false /* follow_symlinks */));
+ ASSERT_TRUE(android::base::ReadFileToString(
+ rollback_de_dir + "/com.foo/file1", &de_content, false /* follow_symlinks */));
+ ASSERT_EQ("TEST_CONTENT_CE", ce_content);
+ ASSERT_EQ("TEST_CONTENT_DE", de_content);
+
+ // Modify the DE content, so we can assert later that it's reflected
+ // in our final snapshot.
+ ASSERT_TRUE(android::base::WriteStringToFile(
+ "TEST_CONTENT_DE_MODIFIED", fake_package_de_path + "/file1",
+ 0700, 10000, 20000, false /* follow_symlinks */));
+
+ // 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));
+
+ ASSERT_TRUE(android::base::ReadFileToString(
+ rollback_ce_dir + "/com.foo/file1", &ce_content, false /* follow_symlinks */));
+ ASSERT_TRUE(android::base::ReadFileToString(
+ rollback_de_dir + "/com.foo/file1", &de_content, false /* follow_symlinks */));
+ ASSERT_EQ("TEST_CONTENT_CE_MODIFIED", ce_content);
+ 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);
+
+ 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);
+
+ 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));
+ ASSERT_BINDER_SUCCESS(service->snapshotAppData(std::make_unique<std::string>("TEST"),
+ "com.foo", 0, FLAG_STORAGE_DE, nullptr));
+ // No CE content snapshot was performed.
+ ASSERT_EQ(ce_snapshot_inode, 0);
+
+ // The snapshot calls must succeed but there should be no snapshot
+ // created.
+ struct stat sb;
+ 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, 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);
+
+ 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);
+
+ // Simulate presence of an existing snapshot
+ ASSERT_TRUE(android::base::WriteStringToFile(
+ "TEST_CONTENT_CE", rollback_ce_dir + "/file1",
+ 0700, 10000, 20000, false /* follow_symlinks */));
+ ASSERT_TRUE(android::base::WriteStringToFile(
+ "TEST_CONTENT_DE", rollback_de_dir + "/file1",
+ 0700, 10000, 20000, false /* follow_symlinks */));
+
+ // Create app data.
+ ASSERT_TRUE(android::base::WriteStringToFile(
+ "TEST_CONTENT_2_CE", fake_package_ce_path + "/file2",
+ 0700, 10000, 20000, false /* follow_symlinks */));
+ ASSERT_TRUE(android::base::WriteStringToFile(
+ "TEST_CONTENT_2_DE", fake_package_de_path + "/file2",
+ 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));
+
+ // 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));
+}
+
+TEST_F(ServiceTest, SnapshotAppData_WrongVolumeUuid) {
+ // Setup app 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);
+
+ 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);
+
+ EXPECT_BINDER_FAIL(service->snapshotAppData(std::make_unique<std::string>("FOO"),
+ "com.foo", 0, 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");
+ 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(android::base::WriteStringToFile(
+ "TEST_CONTENT_CE", fake_package_ce_cache_path + "/file1",
+ 0700, 10000, 20000, false /* follow_symlinks */));
+ ASSERT_TRUE(android::base::WriteStringToFile(
+ "TEST_CONTENT_CE", fake_package_ce_code_cache_path + "/file1",
+ 0700, 10000, 20000, false /* follow_symlinks */));
+ ASSERT_TRUE(android::base::WriteStringToFile(
+ "TEST_CONTENT_DE", fake_package_de_cache_path + "/file1",
+ 0700, 10000, 20000, false /* follow_symlinks */));
+ ASSERT_TRUE(android::base::WriteStringToFile(
+ "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));
+ // The snapshot call must clear cache.
+ struct stat sb;
+ ASSERT_EQ(-1, stat((fake_package_ce_cache_path + "/file1").c_str(), &sb));
+ ASSERT_EQ(-1, stat((fake_package_ce_code_cache_path + "/file1").c_str(), &sb));
+ ASSERT_EQ(-1, stat((fake_package_de_cache_path + "/file1").c_str(), &sb));
+ 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);
+
+ 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);
+
+ // 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(android::base::WriteStringToFile(
+ "CE_RESTORE_CONTENT", rollback_ce_dir + "/com.foo/file1",
+ 0700, 10000, 20000, false /* follow_symlinks */));
+ ASSERT_TRUE(android::base::WriteStringToFile(
+ "DE_RESTORE_CONTENT", rollback_de_dir + "/com.foo/file1",
+ 0700, 10000, 20000, false /* follow_symlinks */));
+ 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_BINDER_SUCCESS(service->restoreAppDataSnapshot(std::make_unique<std::string>("TEST"),
+ "com.foo", 10000, -1, "", 0, FLAG_STORAGE_DE | FLAG_STORAGE_CE));
+
+ std::string ce_content, de_content;
+ ASSERT_TRUE(android::base::ReadFileToString(
+ fake_package_ce_path + "/file1", &ce_content, false /* follow_symlinks */));
+ ASSERT_TRUE(android::base::ReadFileToString(
+ fake_package_de_path + "/file1", &de_content, false /* follow_symlinks */));
+ ASSERT_EQ("CE_RESTORE_CONTENT", ce_content);
+ 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);
+
+ // Prepare data for snapshot.
+ 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 */));
+
+ 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());
+ // Because CE data snapshot was requested, ce_snapshot_inode can't be null.
+ ASSERT_NE(0, ce_snapshot_inode);
+ // Check snapshot is there.
+ struct stat sb;
+ ASSERT_EQ(0, stat((rollback_ce_dir + "/com.foo").c_str(), &sb));
+ ASSERT_EQ(0, stat((rollback_de_dir + "/com.foo").c_str(), &sb));
+
+
+ ASSERT_TRUE(service->destroyAppDataSnapshot(std::make_unique<std::string>("TEST"),
+ "com.foo", 0, ce_snapshot_inode, 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);
+
+ // Create a snapshot
+ ASSERT_TRUE(mkdirs(rollback_ce_dir + "/com.foo/", 700));
+ ASSERT_TRUE(mkdirs(rollback_de_dir + "/com.foo/", 700));
+ ASSERT_TRUE(android::base::WriteStringToFile(
+ "CE_RESTORE_CONTENT", rollback_ce_dir + "/com.foo/file1",
+ 0700, 10000, 20000, false /* follow_symlinks */));
+ ASSERT_TRUE(android::base::WriteStringToFile(
+ "DE_RESTORE_CONTENT", rollback_de_dir + "/com.foo/file1",
+ 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());
+
+ // Check snapshot is deleted.
+ struct stat sb;
+ ASSERT_EQ(-1, stat((rollback_ce_dir + "/com.foo").c_str(), &sb));
+ ASSERT_EQ(-1, stat((rollback_de_dir + "/com.foo").c_str(), &sb));
+
+ // 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());
+}
+
+TEST_F(ServiceTest, 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);
+
+ 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_FALSE(service->destroyAppDataSnapshot(std::make_unique<std::string>("BAR"),
+ "com.foo", 0, 0, FLAG_STORAGE_DE).isOk());
+}
+
+TEST_F(ServiceTest, 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);
+
+ 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);
+
+ EXPECT_BINDER_FAIL(service->restoreAppDataSnapshot(std::make_unique<std::string>("BAR"),
+ "com.foo", 10000, -1, "", 0, FLAG_STORAGE_DE));
+}
+
} // namespace installd
} // namespace android
diff --git a/cmds/installd/tests/installd_utils_test.cpp b/cmds/installd/tests/installd_utils_test.cpp
index ad7a5ae..1782aa2 100644
--- a/cmds/installd/tests/installd_utils_test.cpp
+++ b/cmds/installd/tests/installd_utils_test.cpp
@@ -18,6 +18,7 @@
#include <string.h>
#include <android-base/logging.h>
+#include <android-base/scopeguard.h>
#include <gtest/gtest.h>
#include "InstalldNativeService.h"
@@ -544,5 +545,58 @@
EXPECT_EQ(0, MatchExtension("docx"));
}
+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_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_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_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_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));
+
+ 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 scope_guard = android::base::make_scope_guard(deleter);
+
+ ASSERT_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("/data/misc_ce/0/rollback/com.foo",
+ create_data_misc_ce_rollback_package_path(nullptr, 0, "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));
+
+ // 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"));
+}
+
} // namespace installd
} // namespace android
diff --git a/cmds/installd/tests/test_utils.h b/cmds/installd/tests/test_utils.h
index a7ef674..70eefe2 100644
--- a/cmds/installd/tests/test_utils.h
+++ b/cmds/installd/tests/test_utils.h
@@ -1,3 +1,21 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
#include <stdlib.h>
#include <string.h>
#include <sys/capability.h>
diff --git a/cmds/installd/utils.cpp b/cmds/installd/utils.cpp
index 74ad184..5b487bb 100644
--- a/cmds/installd/utils.cpp
+++ b/cmds/installd/utils.cpp
@@ -20,6 +20,7 @@
#include <fcntl.h>
#include <fts.h>
#include <stdlib.h>
+#include <sys/capability.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <sys/xattr.h>
@@ -34,6 +35,7 @@
#include <log/log.h>
#include <private/android_filesystem_config.h>
+#include "dexopt_return_codes.h"
#include "globals.h" // extern variables.
#ifndef LOG_TAG
@@ -68,6 +70,35 @@
CHECK(is_valid_package_name(package_name));
}
+static std::string resolve_ce_path_by_inode_or_fallback(const std::string& root_path,
+ ino_t ce_data_inode, const std::string& fallback) {
+ if (ce_data_inode != 0) {
+ DIR* dir = opendir(root_path.c_str());
+ if (dir == nullptr) {
+ PLOG(ERROR) << "Failed to opendir " << root_path;
+ return fallback;
+ }
+
+ struct dirent* ent;
+ while ((ent = readdir(dir))) {
+ if (ent->d_ino == ce_data_inode) {
+ auto resolved = StringPrintf("%s/%s", root_path.c_str(), ent->d_name);
+ if (resolved != fallback) {
+ LOG(DEBUG) << "Resolved path " << resolved << " for inode " << ce_data_inode
+ << " instead of " << fallback;
+ }
+ closedir(dir);
+ return resolved;
+ }
+ }
+ LOG(WARNING) << "Failed to resolve inode " << ce_data_inode << "; using " << fallback;
+ closedir(dir);
+ return fallback;
+ } else {
+ return fallback;
+ }
+}
+
/**
* Create the path name where package app contents should be stored for
* the given volume UUID and package name. An empty UUID is assumed to
@@ -111,34 +142,8 @@
// For testing purposes, rely on the inode when defined; this could be
// optimized to use access() in the future.
auto fallback = create_data_user_ce_package_path(volume_uuid, user, package_name);
- if (ce_data_inode != 0) {
- auto user_path = create_data_user_ce_path(volume_uuid, user);
- DIR* dir = opendir(user_path.c_str());
- if (dir == nullptr) {
- PLOG(ERROR) << "Failed to opendir " << user_path;
- return fallback;
- }
-
- struct dirent* ent;
- while ((ent = readdir(dir))) {
- if (ent->d_ino == ce_data_inode) {
- auto resolved = StringPrintf("%s/%s", user_path.c_str(), ent->d_name);
-#if DEBUG_XATTRS
- if (resolved != fallback) {
- LOG(DEBUG) << "Resolved path " << resolved << " for inode " << ce_data_inode
- << " instead of " << fallback;
- }
-#endif
- closedir(dir);
- return resolved;
- }
- }
- LOG(WARNING) << "Failed to resolve inode " << ce_data_inode << "; using " << fallback;
- closedir(dir);
- return fallback;
- } else {
- return fallback;
- }
+ auto user_path = create_data_user_ce_path(volume_uuid, user);
+ return resolve_ce_path_by_inode_or_fallback(user_path, ce_data_inode, fallback);
}
std::string create_data_user_de_package_path(const char* volume_uuid,
@@ -192,6 +197,34 @@
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) {
+ 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) {
+ 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_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);
+ 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) {
+ return StringPrintf("%s/%s",
+ create_data_misc_de_rollback_path(volume_uuid, user).c_str(), package_name);
+}
+
/**
* Create the path name for media for a certain userid.
*/
@@ -1063,5 +1096,26 @@
}
}
+void drop_capabilities(uid_t uid) {
+ if (setgid(uid) != 0) {
+ PLOG(ERROR) << "setgid(" << uid << ") failed in installd during dexopt";
+ exit(DexoptReturnCodes::kSetGid);
+ }
+ if (setuid(uid) != 0) {
+ PLOG(ERROR) << "setuid(" << uid << ") failed in installd during dexopt";
+ exit(DexoptReturnCodes::kSetUid);
+ }
+ // drop capabilities
+ struct __user_cap_header_struct capheader;
+ struct __user_cap_data_struct capdata[2];
+ memset(&capheader, 0, sizeof(capheader));
+ memset(&capdata, 0, sizeof(capdata));
+ capheader.version = _LINUX_CAPABILITY_VERSION_3;
+ if (capset(&capheader, &capdata[0]) < 0) {
+ PLOG(ERROR) << "capset failed";
+ exit(DexoptReturnCodes::kCapSet);
+ }
+}
+
} // namespace installd
} // namespace android
diff --git a/cmds/installd/utils.h b/cmds/installd/utils.h
index d05724a..0711b34 100644
--- a/cmds/installd/utils.h
+++ b/cmds/installd/utils.h
@@ -61,6 +61,15 @@
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_package_path(const char* volume_uuid,
+ userid_t user, 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);
+std::string create_data_misc_de_rollback_package_path(const char* volume_uuid,
+ userid_t user, 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);
std::string create_data_media_package_path(const char* volume_uuid, userid_t userid,
@@ -110,6 +119,8 @@
int delete_dir_contents_fd(int dfd, const char *name);
+int rm_package_dir(const std::string& package_dir);
+
int copy_dir_files(const char *srcname, const char *dstname, uid_t owner, gid_t group);
int64_t data_disk_free(const std::string& data_path);
@@ -140,6 +151,8 @@
// It returns true if there were no errors at all, and false otherwise.
bool collect_profiles(std::vector<std::string>* profiles_paths);
+void drop_capabilities(uid_t uid);
+
} // namespace installd
} // namespace android
diff --git a/cmds/installd/utils_default.cpp b/cmds/installd/utils_default.cpp
new file mode 100644
index 0000000..a6025e6
--- /dev/null
+++ b/cmds/installd/utils_default.cpp
@@ -0,0 +1,30 @@
+/*
+** 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 "utils.h"
+
+namespace android {
+namespace installd {
+
+// In this file are default definitions of the functions that may contain
+// platform dependent logic.
+
+int rm_package_dir(const std::string& package_dir) {
+ return delete_dir_contents_and_dir(package_dir);
+}
+
+} // namespace installd
+} // namespace android
diff --git a/cmds/installd/view_compiler.cpp b/cmds/installd/view_compiler.cpp
new file mode 100644
index 0000000..f1ac717
--- /dev/null
+++ b/cmds/installd/view_compiler.cpp
@@ -0,0 +1,99 @@
+/*
+ * 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 "view_compiler.h"
+
+#include <string>
+
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include "utils.h"
+
+#include "android-base/logging.h"
+#include "android-base/stringprintf.h"
+#include "android-base/unique_fd.h"
+
+namespace android {
+namespace installd {
+
+using base::unique_fd;
+
+bool view_compiler(const char* apk_path, const char* package_name, const char* out_dex_file,
+ int uid) {
+ CHECK(apk_path != nullptr);
+ CHECK(package_name != nullptr);
+ CHECK(out_dex_file != nullptr);
+
+ // viewcompiler won't have permission to open anything, so we have to open the files first
+ // and pass file descriptors.
+
+ // Open input file
+ unique_fd infd{open(apk_path, 0)};
+ if (infd.get() < 0) {
+ PLOG(ERROR) << "Could not open input file: " << apk_path;
+ return false;
+ }
+
+ // Set up output file. viewcompiler can't open outputs by fd, but it can write to stdout, so
+ // we close stdout and open it towards the right output.
+ unique_fd outfd{open(out_dex_file, O_CREAT | O_TRUNC | O_WRONLY, 0644)};
+ if (outfd.get() < 0) {
+ PLOG(ERROR) << "Could not open output file: " << out_dex_file;
+ return false;
+ }
+ if (fchmod(outfd, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) != 0) {
+ PLOG(ERROR) << "Could not change output file permissions";
+ return false;
+ }
+ if (close(STDOUT_FILENO) != 0) {
+ PLOG(ERROR) << "Could not close stdout";
+ return false;
+ }
+ if (dup2(outfd, STDOUT_FILENO) < 0) {
+ PLOG(ERROR) << "Could not duplicate output file descriptor";
+ return false;
+ }
+
+ // Prepare command line arguments for viewcompiler
+ std::string args[] = {"/system/bin/viewcompiler",
+ "--apk",
+ "--infd",
+ android::base::StringPrintf("%d", infd.get()),
+ "--dex",
+ "--package",
+ package_name};
+ char* const argv[] = {const_cast<char*>(args[0].c_str()), const_cast<char*>(args[1].c_str()),
+ const_cast<char*>(args[2].c_str()), const_cast<char*>(args[3].c_str()),
+ const_cast<char*>(args[4].c_str()), const_cast<char*>(args[5].c_str()),
+ const_cast<char*>(args[6].c_str()), nullptr};
+
+ pid_t pid = fork();
+ if (pid == 0) {
+ // Now that we've opened the files we need, drop privileges.
+ drop_capabilities(uid);
+ execv("/system/bin/viewcompiler", argv);
+ _exit(1);
+ }
+
+ return wait_child(pid) == 0;
+}
+
+} // namespace installd
+} // namespace android
\ No newline at end of file
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplaySurface.cpp b/cmds/installd/view_compiler.h
similarity index 66%
copy from services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplaySurface.cpp
copy to cmds/installd/view_compiler.h
index e6ac6bf..f7c6e57 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplaySurface.cpp
+++ b/cmds/installd/view_compiler.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018 The Android Open Source Project
+ * 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.
@@ -14,14 +14,16 @@
* limitations under the License.
*/
-#include "mock/DisplayHardware/MockDisplaySurface.h"
+#ifndef VIEW_COMPILER_H_
+#define VIEW_COMPILER_H_
namespace android {
-namespace mock {
+namespace installd {
-// Explicit default instantiation is recommended.
-DisplaySurface::DisplaySurface() = default;
-DisplaySurface::~DisplaySurface() = default;
+bool view_compiler(const char* apk_path, const char* package_name, const char* out_dex_file,
+ int uid);
-} // namespace mock
+} // namespace installd
} // namespace android
+
+#endif // VIEW_COMPILER_H_
\ No newline at end of file
diff --git a/cmds/lshal/Command.h b/cmds/lshal/Command.h
index 4f128ab..e19e3f7 100644
--- a/cmds/lshal/Command.h
+++ b/cmds/lshal/Command.h
@@ -27,7 +27,7 @@
// Base class for all *Commands
class Command {
public:
- Command(Lshal& lshal) : mLshal(lshal) {}
+ explicit Command(Lshal& lshal) : mLshal(lshal) {}
virtual ~Command() = default;
// Expect optind to be set by Lshal::main and points to the next argument
// to process.
diff --git a/cmds/lshal/DebugCommand.h b/cmds/lshal/DebugCommand.h
index 6e12008..3c3f56f 100644
--- a/cmds/lshal/DebugCommand.h
+++ b/cmds/lshal/DebugCommand.h
@@ -31,7 +31,7 @@
class DebugCommand : public Command {
public:
- DebugCommand(Lshal &lshal) : Command(lshal) {}
+ explicit DebugCommand(Lshal &lshal) : Command(lshal) {}
~DebugCommand() = default;
Status main(const Arg &arg) override;
void usage() const override;
diff --git a/cmds/lshal/HelpCommand.h b/cmds/lshal/HelpCommand.h
index cc709f8..da0cba6 100644
--- a/cmds/lshal/HelpCommand.h
+++ b/cmds/lshal/HelpCommand.h
@@ -31,7 +31,7 @@
class HelpCommand : public Command {
public:
- HelpCommand(Lshal &lshal) : Command(lshal) {}
+ explicit HelpCommand(Lshal &lshal) : Command(lshal) {}
~HelpCommand() = default;
Status main(const Arg &arg) override;
void usage() const override;
diff --git a/cmds/lshal/ListCommand.h b/cmds/lshal/ListCommand.h
index 3f7321d..85195fc 100644
--- a/cmds/lshal/ListCommand.h
+++ b/cmds/lshal/ListCommand.h
@@ -57,7 +57,7 @@
class ListCommand : public Command {
public:
- ListCommand(Lshal &lshal) : Command(lshal) {}
+ explicit ListCommand(Lshal &lshal) : Command(lshal) {}
virtual ~ListCommand() = default;
Status main(const Arg &arg) override;
void usage() const override;
diff --git a/cmds/lshal/NullableOStream.h b/cmds/lshal/NullableOStream.h
index ab37a04..737d3a2 100644
--- a/cmds/lshal/NullableOStream.h
+++ b/cmds/lshal/NullableOStream.h
@@ -25,8 +25,8 @@
template<typename S>
class NullableOStream {
public:
- NullableOStream(S &os) : mOs(&os) {}
- NullableOStream(S *os) : mOs(os) {}
+ explicit NullableOStream(S &os) : mOs(&os) {}
+ explicit NullableOStream(S *os) : mOs(os) {}
NullableOStream &operator=(S &os) {
mOs = &os;
return *this;
@@ -57,7 +57,7 @@
S& buf() const {
return *mOs;
}
- operator bool() const {
+ operator bool() const { // NOLINT(google-explicit-constructor)
return mOs != nullptr;
}
private:
diff --git a/cmds/lshal/TableEntry.h b/cmds/lshal/TableEntry.h
index 7294b0a..601b7e2 100644
--- a/cmds/lshal/TableEntry.h
+++ b/cmds/lshal/TableEntry.h
@@ -149,7 +149,7 @@
class MergedTable {
public:
- MergedTable(std::vector<const Table*>&& tables) : mTables(std::move(tables)) {}
+ explicit MergedTable(std::vector<const Table*>&& tables) : mTables(std::move(tables)) {}
TextTable createTextTable();
private:
std::vector<const Table*> mTables;
diff --git a/cmds/lshal/TextTable.h b/cmds/lshal/TextTable.h
index 91d522a..301b4bd 100644
--- a/cmds/lshal/TextTable.h
+++ b/cmds/lshal/TextTable.h
@@ -33,11 +33,11 @@
TextTableRow() {}
// A row of cells.
- TextTableRow(std::vector<std::string>&& v) : mFields(std::move(v)) {}
+ explicit TextTableRow(std::vector<std::string>&& v) : mFields(std::move(v)) {}
// A single comment string.
- TextTableRow(std::string&& s) : mLine(std::move(s)) {}
- TextTableRow(const std::string& s) : mLine(s) {}
+ explicit TextTableRow(std::string&& s) : mLine(std::move(s)) {}
+ explicit TextTableRow(const std::string& s) : mLine(s) {}
// Whether this row is an actual row of cells.
bool isRow() const { return !fields().empty(); }
diff --git a/cmds/lshal/Timeout.h b/cmds/lshal/Timeout.h
index 58119a6..46d8177 100644
--- a/cmds/lshal/Timeout.h
+++ b/cmds/lshal/Timeout.h
@@ -29,7 +29,7 @@
class BackgroundTaskState {
public:
- BackgroundTaskState(std::function<void(void)> &&func)
+ explicit BackgroundTaskState(std::function<void(void)> &&func)
: mFunc(std::forward<decltype(func)>(func)) {}
void notify() {
std::unique_lock<std::mutex> lock(mMutex);
diff --git a/cmds/lshal/test.cpp b/cmds/lshal/test.cpp
index 8d7405b..fc8d58b 100644
--- a/cmds/lshal/test.cpp
+++ b/cmds/lshal/test.cpp
@@ -191,7 +191,7 @@
// expose protected fields and methods for ListCommand
class MockListCommand : public ListCommand {
public:
- MockListCommand(Lshal* lshal) : ListCommand(*lshal) {}
+ explicit MockListCommand(Lshal* lshal) : ListCommand(*lshal) {}
Status parseArgs(const Arg& arg) { return ListCommand::parseArgs(arg); }
Status main(const Arg& arg) { return ListCommand::main(arg); }
@@ -308,7 +308,7 @@
// Fake service returned by mocked IServiceManager::get.
class TestService : public IBase {
public:
- TestService(pid_t id) : mId(id) {}
+ explicit TestService(pid_t id) : mId(id) {}
hardware::Return<void> getDebugInfo(getDebugInfo_cb cb) override {
cb({ mId /* pid */, getPtr(mId), DebugInfo::Architecture::IS_64BIT });
return hardware::Void();
diff --git a/cmds/servicemanager/binder.c b/cmds/servicemanager/binder.c
index fade8cf..cf3b172 100644
--- a/cmds/servicemanager/binder.c
+++ b/cmds/servicemanager/binder.c
@@ -146,7 +146,19 @@
int binder_become_context_manager(struct binder_state *bs)
{
- return ioctl(bs->fd, BINDER_SET_CONTEXT_MGR, 0);
+ struct flat_binder_object obj;
+ memset(&obj, 0, sizeof(obj));
+ obj.flags = FLAT_BINDER_FLAG_TXN_SECURITY_CTX;
+
+ int result = ioctl(bs->fd, BINDER_SET_CONTEXT_MGR_EXT, &obj);
+
+ // fallback to original method
+ if (result != 0) {
+ android_errorWriteLog(0x534e4554, "121035042");
+
+ result = ioctl(bs->fd, BINDER_SET_CONTEXT_MGR, 0);
+ }
+ return result;
}
int binder_write(struct binder_state *bs, void *data, size_t len)
@@ -240,13 +252,28 @@
#endif
ptr += sizeof(struct binder_ptr_cookie);
break;
+ case BR_TRANSACTION_SEC_CTX:
case BR_TRANSACTION: {
- struct binder_transaction_data *txn = (struct binder_transaction_data *) ptr;
- if ((end - ptr) < sizeof(*txn)) {
- ALOGE("parse: txn too small!\n");
- return -1;
+ struct binder_transaction_data_secctx txn;
+ if (cmd == BR_TRANSACTION_SEC_CTX) {
+ if ((end - ptr) < sizeof(struct binder_transaction_data_secctx)) {
+ ALOGE("parse: txn too small (binder_transaction_data_secctx)!\n");
+ return -1;
+ }
+ memcpy(&txn, (void*) ptr, sizeof(struct binder_transaction_data_secctx));
+ ptr += sizeof(struct binder_transaction_data_secctx);
+ } else /* BR_TRANSACTION */ {
+ if ((end - ptr) < sizeof(struct binder_transaction_data)) {
+ ALOGE("parse: txn too small (binder_transaction_data)!\n");
+ return -1;
+ }
+ memcpy(&txn.transaction_data, (void*) ptr, sizeof(struct binder_transaction_data));
+ ptr += sizeof(struct binder_transaction_data);
+
+ txn.secctx = 0;
}
- binder_dump_txn(txn);
+
+ binder_dump_txn(&txn.transaction_data);
if (func) {
unsigned rdata[256/4];
struct binder_io msg;
@@ -254,15 +281,14 @@
int res;
bio_init(&reply, rdata, sizeof(rdata), 4);
- bio_init_from_txn(&msg, txn);
- res = func(bs, txn, &msg, &reply);
- if (txn->flags & TF_ONE_WAY) {
- binder_free_buffer(bs, txn->data.ptr.buffer);
+ bio_init_from_txn(&msg, &txn.transaction_data);
+ res = func(bs, &txn, &msg, &reply);
+ if (txn.transaction_data.flags & TF_ONE_WAY) {
+ binder_free_buffer(bs, txn.transaction_data.data.ptr.buffer);
} else {
- binder_send_reply(bs, &reply, txn->data.ptr.buffer, res);
+ binder_send_reply(bs, &reply, txn.transaction_data.data.ptr.buffer, res);
}
}
- ptr += sizeof(*txn);
break;
}
case BR_REPLY: {
diff --git a/cmds/servicemanager/binder.h b/cmds/servicemanager/binder.h
index c95b33f..70be3b4 100644
--- a/cmds/servicemanager/binder.h
+++ b/cmds/servicemanager/binder.h
@@ -5,7 +5,8 @@
#define _BINDER_H_
#include <sys/ioctl.h>
-#include <linux/android/binder.h>
+
+#include "binder_kernel.h"
struct binder_state;
@@ -42,7 +43,7 @@
};
typedef int (*binder_handler)(struct binder_state *bs,
- struct binder_transaction_data *txn,
+ struct binder_transaction_data_secctx *txn,
struct binder_io *msg,
struct binder_io *reply);
diff --git a/cmds/servicemanager/binder_kernel.h b/cmds/servicemanager/binder_kernel.h
new file mode 100644
index 0000000..19fd773
--- /dev/null
+++ b/cmds/servicemanager/binder_kernel.h
@@ -0,0 +1,46 @@
+/*
+ * 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 ANDROID_BINDER_KERNEL_H
+#define ANDROID_BINDER_KERNEL_H
+
+#include <linux/android/binder.h>
+
+/**
+ * This file exists because the uapi kernel headers in bionic are built
+ * from upstream kernel headers only, and not all of the hwbinder kernel changes
+ * have made it upstream yet. Therefore, the modifications to the
+ * binder header are added locally in this file.
+ */
+
+enum {
+ FLAT_BINDER_FLAG_TXN_SECURITY_CTX = 0x1000,
+};
+
+#define BINDER_SET_CONTEXT_MGR_EXT _IOW('b', 13, struct flat_binder_object)
+
+struct binder_transaction_data_secctx {
+ struct binder_transaction_data transaction_data;
+ binder_uintptr_t secctx;
+};
+
+enum {
+ BR_TRANSACTION_SEC_CTX = _IOR('r', 2,
+ struct binder_transaction_data_secctx),
+};
+
+
+#endif // ANDROID_BINDER_KERNEL_H
diff --git a/cmds/servicemanager/service_manager.c b/cmds/servicemanager/service_manager.c
index 79cd6b5..ec3fac5 100644
--- a/cmds/servicemanager/service_manager.c
+++ b/cmds/servicemanager/service_manager.c
@@ -61,14 +61,14 @@
static char *service_manager_context;
static struct selabel_handle* sehandle;
-static bool check_mac_perms(pid_t spid, uid_t uid, const char *tctx, const char *perm, const char *name)
+static bool check_mac_perms(pid_t spid, const char* sid, uid_t uid, const char *tctx, const char *perm, const char *name)
{
- char *sctx = NULL;
+ char *lookup_sid = NULL;
const char *class = "service_manager";
bool allowed;
struct audit_data ad;
- if (getpidcon(spid, &sctx) < 0) {
+ if (sid == NULL && getpidcon(spid, &lookup_sid) < 0) {
ALOGE("SELinux: getpidcon(pid=%d) failed to retrieve pid context.\n", spid);
return false;
}
@@ -77,19 +77,23 @@
ad.uid = uid;
ad.name = name;
- int result = selinux_check_access(sctx, tctx, class, perm, (void *) &ad);
+ if (sid == NULL) {
+ android_errorWriteLog(0x534e4554, "121035042");
+ }
+
+ int result = selinux_check_access(sid ? sid : lookup_sid, tctx, class, perm, (void *) &ad);
allowed = (result == 0);
- freecon(sctx);
+ freecon(lookup_sid);
return allowed;
}
-static bool check_mac_perms_from_getcon(pid_t spid, uid_t uid, const char *perm)
+static bool check_mac_perms_from_getcon(pid_t spid, const char* sid, uid_t uid, const char *perm)
{
- return check_mac_perms(spid, uid, service_manager_context, perm, NULL);
+ return check_mac_perms(spid, sid, uid, service_manager_context, perm, NULL);
}
-static bool check_mac_perms_from_lookup(pid_t spid, uid_t uid, const char *perm, const char *name)
+static bool check_mac_perms_from_lookup(pid_t spid, const char* sid, uid_t uid, const char *perm, const char *name)
{
bool allowed;
char *tctx = NULL;
@@ -104,12 +108,12 @@
return false;
}
- allowed = check_mac_perms(spid, uid, tctx, perm, name);
+ allowed = check_mac_perms(spid, sid, uid, tctx, perm, name);
freecon(tctx);
return allowed;
}
-static int svc_can_register(const uint16_t *name, size_t name_len, pid_t spid, uid_t uid)
+static int svc_can_register(const uint16_t *name, size_t name_len, pid_t spid, const char* sid, uid_t uid)
{
const char *perm = "add";
@@ -117,19 +121,19 @@
return 0; /* Don't allow apps to register services */
}
- return check_mac_perms_from_lookup(spid, uid, perm, str8(name, name_len)) ? 1 : 0;
+ return check_mac_perms_from_lookup(spid, sid, uid, perm, str8(name, name_len)) ? 1 : 0;
}
-static int svc_can_list(pid_t spid, uid_t uid)
+static int svc_can_list(pid_t spid, const char* sid, uid_t uid)
{
const char *perm = "list";
- return check_mac_perms_from_getcon(spid, uid, perm) ? 1 : 0;
+ return check_mac_perms_from_getcon(spid, sid, uid, perm) ? 1 : 0;
}
-static int svc_can_find(const uint16_t *name, size_t name_len, pid_t spid, uid_t uid)
+static int svc_can_find(const uint16_t *name, size_t name_len, pid_t spid, const char* sid, uid_t uid)
{
const char *perm = "find";
- return check_mac_perms_from_lookup(spid, uid, perm, str8(name, name_len)) ? 1 : 0;
+ return check_mac_perms_from_lookup(spid, sid, uid, perm, str8(name, name_len)) ? 1 : 0;
}
struct svcinfo
@@ -175,7 +179,7 @@
};
-uint32_t do_find_service(const uint16_t *s, size_t len, uid_t uid, pid_t spid)
+uint32_t do_find_service(const uint16_t *s, size_t len, uid_t uid, pid_t spid, const char* sid)
{
struct svcinfo *si = find_svc(s, len);
@@ -192,7 +196,7 @@
}
}
- if (!svc_can_find(s, len, spid, uid)) {
+ if (!svc_can_find(s, len, spid, sid, uid)) {
return 0;
}
@@ -200,7 +204,7 @@
}
int do_add_service(struct binder_state *bs, const uint16_t *s, size_t len, uint32_t handle,
- uid_t uid, int allow_isolated, uint32_t dumpsys_priority, pid_t spid) {
+ uid_t uid, int allow_isolated, uint32_t dumpsys_priority, pid_t spid, const char* sid) {
struct svcinfo *si;
//ALOGI("add_service('%s',%x,%s) uid=%d\n", str8(s, len), handle,
@@ -209,7 +213,7 @@
if (!handle || (len == 0) || (len > 127))
return -1;
- if (!svc_can_register(s, len, spid, uid)) {
+ if (!svc_can_register(s, len, spid, sid, uid)) {
ALOGE("add_service('%s',%x) uid=%d - PERMISSION DENIED\n",
str8(s, len), handle, uid);
return -1;
@@ -248,7 +252,7 @@
}
int svcmgr_handler(struct binder_state *bs,
- struct binder_transaction_data *txn,
+ struct binder_transaction_data_secctx *txn_secctx,
struct binder_io *msg,
struct binder_io *reply)
{
@@ -260,6 +264,8 @@
int allow_isolated;
uint32_t dumpsys_priority;
+ struct binder_transaction_data *txn = &txn_secctx->transaction_data;
+
//ALOGI("target=%p code=%d pid=%d uid=%d\n",
// (void*) txn->target.ptr, txn->code, txn->sender_pid, txn->sender_euid);
@@ -305,7 +311,8 @@
if (s == NULL) {
return -1;
}
- handle = do_find_service(s, len, txn->sender_euid, txn->sender_pid);
+ handle = do_find_service(s, len, txn->sender_euid, txn->sender_pid,
+ (const char*) txn_secctx->secctx);
if (!handle)
break;
bio_put_ref(reply, handle);
@@ -320,7 +327,7 @@
allow_isolated = bio_get_uint32(msg) ? 1 : 0;
dumpsys_priority = bio_get_uint32(msg);
if (do_add_service(bs, s, len, handle, txn->sender_euid, allow_isolated, dumpsys_priority,
- txn->sender_pid))
+ txn->sender_pid, (const char*) txn_secctx->secctx))
return -1;
break;
@@ -328,7 +335,7 @@
uint32_t n = bio_get_uint32(msg);
uint32_t req_dumpsys_priority = bio_get_uint32(msg);
- if (!svc_can_list(txn->sender_pid, txn->sender_euid)) {
+ if (!svc_can_list(txn->sender_pid, (const char*) txn_secctx->secctx, txn->sender_euid)) {
ALOGE("list_service() uid=%d - PERMISSION DENIED\n",
txn->sender_euid);
return -1;
diff --git a/cmds/surfacereplayer/OWNERS b/cmds/surfacereplayer/OWNERS
new file mode 100644
index 0000000..cc4c842
--- /dev/null
+++ b/cmds/surfacereplayer/OWNERS
@@ -0,0 +1,2 @@
+mathias@google.com
+racarr@google.com
diff --git a/cmds/surfacereplayer/replayer/Replayer.cpp b/cmds/surfacereplayer/replayer/Replayer.cpp
index 384f21f..34886a9 100644
--- a/cmds/surfacereplayer/replayer/Replayer.cpp
+++ b/cmds/surfacereplayer/replayer/Replayer.cpp
@@ -286,10 +286,6 @@
std::thread(&Replayer::createSurfaceControl, this, increment.surface_creation(), event)
.detach();
} break;
- case increment.kSurfaceDeletion: {
- std::thread(&Replayer::deleteSurfaceControl, this, increment.surface_deletion(), event)
- .detach();
- } break;
case increment.kBufferUpdate: {
std::lock_guard<std::mutex> lock1(mLayerLock);
std::lock_guard<std::mutex> lock2(mBufferQueueSchedulerLock);
@@ -628,47 +624,10 @@
return NO_ERROR;
}
-status_t Replayer::deleteSurfaceControl(
- const SurfaceDeletion& delete_, const std::shared_ptr<Event>& event) {
- ALOGV("Deleting %d Surface Control", delete_.id());
- event->readyToExecute();
-
- std::lock_guard<std::mutex> lock1(mPendingLayersLock);
-
- mLayersPendingRemoval.push_back(delete_.id());
-
- const auto& iterator = mBufferQueueSchedulers.find(delete_.id());
- if (iterator != mBufferQueueSchedulers.end()) {
- (*iterator).second->stopScheduling();
- }
-
- std::lock_guard<std::mutex> lock2(mLayerLock);
- if (mLayers[delete_.id()] != nullptr) {
- mComposerClient->destroySurface(mLayers[delete_.id()]->getHandle());
- }
-
- return NO_ERROR;
-}
-
-void Replayer::doDeleteSurfaceControls() {
- std::lock_guard<std::mutex> lock1(mPendingLayersLock);
- std::lock_guard<std::mutex> lock2(mLayerLock);
- if (!mLayersPendingRemoval.empty()) {
- for (int id : mLayersPendingRemoval) {
- mLayers.erase(id);
- mColors.erase(id);
- mBufferQueueSchedulers.erase(id);
- }
- mLayersPendingRemoval.clear();
- }
-}
-
status_t Replayer::injectVSyncEvent(
const VSyncEvent& vSyncEvent, const std::shared_ptr<Event>& event) {
ALOGV("Injecting VSync Event");
- doDeleteSurfaceControls();
-
event->readyToExecute();
SurfaceComposerClient::injectVSync(vSyncEvent.when());
diff --git a/cmds/surfacereplayer/replayer/Replayer.h b/cmds/surfacereplayer/replayer/Replayer.h
index 120dd9b..ad807ee 100644
--- a/cmds/surfacereplayer/replayer/Replayer.h
+++ b/cmds/surfacereplayer/replayer/Replayer.h
@@ -70,8 +70,6 @@
status_t doTransaction(const Transaction& transaction, const std::shared_ptr<Event>& event);
status_t createSurfaceControl(const SurfaceCreation& create,
const std::shared_ptr<Event>& event);
- status_t deleteSurfaceControl(const SurfaceDeletion& delete_,
- const std::shared_ptr<Event>& event);
status_t injectVSyncEvent(const VSyncEvent& vsyncEvent, const std::shared_ptr<Event>& event);
void createDisplay(const DisplayCreation& create, const std::shared_ptr<Event>& event);
void deleteDisplay(const DisplayDeletion& delete_, const std::shared_ptr<Event>& event);
@@ -120,7 +118,6 @@
void setDisplayProjection(SurfaceComposerClient::Transaction& t,
display_id id, const ProjectionChange& pc);
- void doDeleteSurfaceControls();
void waitUntilTimestamp(int64_t timestamp);
void waitUntilDeferredTransactionLayerExists(
const DeferredTransactionChange& dtc, std::unique_lock<std::mutex>& lock);
diff --git a/data/etc/android.hardware.biometrics.fingerprint.xml b/data/etc/android.hardware.biometrics.fingerprint.xml
deleted file mode 100644
index e5af541..0000000
--- a/data/etc/android.hardware.biometrics.fingerprint.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ 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.
- -->
-
-<!-- This is the standard set of features for a biometric fingerprint sensor. -->
-<permissions>
- <feature name="android.hardware.biometrics.fingerprint" />
-</permissions>
diff --git a/data/etc/android.hardware.telephony.ims.xml b/data/etc/android.hardware.telephony.ims.xml
new file mode 100644
index 0000000..eeb7b00
--- /dev/null
+++ b/data/etc/android.hardware.telephony.ims.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<!-- Feature for devices that support IMS via ImsService APIs. -->
+<permissions>
+ <feature name="android.hardware.telephony.ims" />
+</permissions>
diff --git a/data/etc/android.software.secure_lock_screen.xml b/data/etc/android.software.secure_lock_screen.xml
new file mode 100644
index 0000000..3464487
--- /dev/null
+++ b/data/etc/android.software.secure_lock_screen.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<permissions>
+ <feature name="android.software.secure_lock_screen" />
+</permissions>
diff --git a/data/etc/car_core_hardware.xml b/data/etc/car_core_hardware.xml
index d6021c0..6cbe4ae 100644
--- a/data/etc/car_core_hardware.xml
+++ b/data/etc/car_core_hardware.xml
@@ -45,6 +45,7 @@
<feature name="android.software.companion_device_setup" />
<feature name="android.software.autofill" />
<feature name="android.software.cant_save_state" />
+ <feature name="android.software.secure_lock_screen" />
<!-- Feature to specify if the device supports adding device admins. -->
<feature name="android.software.device_admin" />
diff --git a/data/etc/go_handheld_core_hardware.xml b/data/etc/go_handheld_core_hardware.xml
index 8b5a461..915e579 100644
--- a/data/etc/go_handheld_core_hardware.xml
+++ b/data/etc/go_handheld_core_hardware.xml
@@ -43,6 +43,7 @@
<feature name="android.software.companion_device_setup" />
<feature name="android.software.autofill" />
<feature name="android.software.cant_save_state" />
+ <feature name="android.software.secure_lock_screen" />
<!-- Feature to specify if the device supports adding device admins. -->
<feature name="android.software.device_admin" />
diff --git a/data/etc/handheld_core_hardware.xml b/data/etc/handheld_core_hardware.xml
index 060a334..619d017 100644
--- a/data/etc/handheld_core_hardware.xml
+++ b/data/etc/handheld_core_hardware.xml
@@ -51,6 +51,7 @@
<feature name="android.software.companion_device_setup" />
<feature name="android.software.autofill" />
<feature name="android.software.cant_save_state" />
+ <feature name="android.software.secure_lock_screen" />
<!-- Feature to specify if the device supports adding device admins. -->
<feature name="android.software.device_admin" />
diff --git a/data/etc/tablet_core_hardware.xml b/data/etc/tablet_core_hardware.xml
index 6db2627..52524ca 100644
--- a/data/etc/tablet_core_hardware.xml
+++ b/data/etc/tablet_core_hardware.xml
@@ -51,6 +51,7 @@
<feature name="android.software.companion_device_setup" />
<feature name="android.software.autofill" />
<feature name="android.software.cant_save_state" />
+ <feature name="android.software.secure_lock_screen" />
<!-- Feature to specify if the device supports adding device admins. -->
<feature name="android.software.device_admin" />
diff --git a/data/etc/wearable_core_hardware.xml b/data/etc/wearable_core_hardware.xml
index e2ab71a..0f364c1 100644
--- a/data/etc/wearable_core_hardware.xml
+++ b/data/etc/wearable_core_hardware.xml
@@ -35,6 +35,7 @@
<!-- basic system services -->
<feature name="android.software.home_screen" />
+ <feature name="android.software.secure_lock_screen" />
<!-- input management and third-party input method editors -->
<feature name="android.software.input_methods" />
diff --git a/headers/media_plugin/media/cas/CasAPI.h b/headers/media_plugin/media/cas/CasAPI.h
index 4de314d..c87ee56 100644
--- a/headers/media_plugin/media/cas/CasAPI.h
+++ b/headers/media_plugin/media/cas/CasAPI.h
@@ -48,6 +48,14 @@
uint8_t *data,
size_t size);
+typedef void (*CasPluginCallbackExt)(
+ void *appData,
+ int32_t event,
+ int32_t arg,
+ uint8_t *data,
+ size_t size,
+ const CasSessionId *sessionId);
+
struct CasFactory {
CasFactory() {}
virtual ~CasFactory() {}
@@ -67,6 +75,13 @@
CasPluginCallback callback,
CasPlugin **plugin) = 0;
+ // Construct a new extend instance of a CasPlugin given a CA_system_id
+ virtual status_t createPlugin(
+ int32_t CA_system_id,
+ void *appData,
+ CasPluginCallbackExt callback,
+ CasPlugin **plugin) = 0;
+
private:
CasFactory(const CasFactory &);
CasFactory &operator=(const CasFactory &); /* NOLINT */
@@ -110,7 +125,15 @@
int32_t arg,
const CasData &eventData) = 0;
- // Native implementation of the MediaCas Java API provision method.
+ // Deliver an session event to the CasPlugin. The format of the event is
+ // specific to the CA scheme and is opaque to the framework.
+ virtual status_t sendSessionEvent(
+ const CasSessionId &sessionId,
+ int32_t event,
+ int32_t arg,
+ const CasData &eventData) = 0;
+
+ // Native implementation of the MediaCas Java API provision method.
virtual status_t provision(
const String8 &provisionString) = 0;
diff --git a/headers/media_plugin/media/drm/DrmAPI.h b/headers/media_plugin/media/drm/DrmAPI.h
index aa8bd3d..59bd292 100644
--- a/headers/media_plugin/media/drm/DrmAPI.h
+++ b/headers/media_plugin/media/drm/DrmAPI.h
@@ -84,6 +84,7 @@
kDrmPluginEventSessionReclaimed,
kDrmPluginEventExpirationUpdate,
kDrmPluginEventKeysChange,
+ kDrmPluginEventSessionLostState,
};
// Drm keys can be for offline content or for online streaming.
@@ -139,6 +140,8 @@
kHdcpV2_1,
// HDCP version 2.2 Type 1.
kHdcpV2_2,
+ // HDCP version 2.3 Type 1.
+ kHdcpV2_3,
// No digital output, implicitly secure
kHdcpNoOutput = 0x7fff
};
@@ -180,10 +183,10 @@
kOfflineLicenseStateUnknown,
// Offline license state is usable, the keys may be used for decryption.
kOfflineLicenseStateUsable,
- // Offline license state is inactive, the keys have been marked for
+ // Offline license state is released, the keys have been marked for
// release using getKeyRequest() with kKeyType_Release but the
// key response has not been received.
- kOfflineLicenseStateInactive
+ kOfflineLicenseStateReleased
};
DrmPlugin() {}
diff --git a/headers/media_plugin/media/openmax/OMX_AsString.h b/headers/media_plugin/media/openmax/OMX_AsString.h
index 152015b..ce30b41 100644
--- a/headers/media_plugin/media/openmax/OMX_AsString.h
+++ b/headers/media_plugin/media/openmax/OMX_AsString.h
@@ -911,6 +911,9 @@
case OMX_VIDEO_AVCLevel5: return "Level5";
case OMX_VIDEO_AVCLevel51: return "Level51";
case OMX_VIDEO_AVCLevel52: return "Level52";
+ case OMX_VIDEO_AVCLevel6: return "Level6";
+ case OMX_VIDEO_AVCLevel61: return "Level61";
+ case OMX_VIDEO_AVCLevel62: return "Level62";
default: return def;
}
}
diff --git a/headers/media_plugin/media/openmax/OMX_Video.h b/headers/media_plugin/media/openmax/OMX_Video.h
index 9fd2fd2..b6edaa9 100644
--- a/headers/media_plugin/media/openmax/OMX_Video.h
+++ b/headers/media_plugin/media/openmax/OMX_Video.h
@@ -832,6 +832,9 @@
OMX_VIDEO_AVCLevel5 = 0x4000, /**< Level 5 */
OMX_VIDEO_AVCLevel51 = 0x8000, /**< Level 5.1 */
OMX_VIDEO_AVCLevel52 = 0x10000, /**< Level 5.2 */
+ OMX_VIDEO_AVCLevel6 = 0x20000, /**< Level 6 */
+ OMX_VIDEO_AVCLevel61 = 0x40000, /**< Level 6.1 */
+ OMX_VIDEO_AVCLevel62 = 0x80000, /**< Level 6.2 */
OMX_VIDEO_AVCLevelKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */
OMX_VIDEO_AVCLevelVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */
OMX_VIDEO_AVCLevelMax = 0x7FFFFFFF
diff --git a/include/OWNERS b/include/OWNERS
new file mode 100644
index 0000000..22be776
--- /dev/null
+++ b/include/OWNERS
@@ -0,0 +1,14 @@
+alexeykuzmin@google.com
+dangittik@google.com
+lajos@google.com
+mathias@google.com
+michaelwr@google.com
+racarr@google.com
+romainguy@android.com
+santoscordon@google.com
+stoza@google.com
+svv@google.com
+
+# For multinetwork.h only.
+lorenzo@google.com
+
diff --git a/include/android/keycodes.h b/include/android/keycodes.h
index cfd2b40..214559d 100644
--- a/include/android/keycodes.h
+++ b/include/android/keycodes.h
@@ -774,7 +774,8 @@
AKEYCODE_THUMBS_UP = 286,
/** Thumbs down key. Apps can use this to let user downvote content. */
AKEYCODE_THUMBS_DOWN = 287,
- /** Consumed by system to switch current viewer profile. */
+ /** Used to switch current account that is consuming content.
+ * May be consumed by system to switch current viewer profile. */
AKEYCODE_PROFILE_SWITCH = 288
// NOTE: If you add a new keycode here you must also add it to several other files.
diff --git a/include/android/multinetwork.h b/include/android/multinetwork.h
index fa7d908..d31d1f1 100644
--- a/include/android/multinetwork.h
+++ b/include/android/multinetwork.h
@@ -113,28 +113,55 @@
#if __ANDROID_API__ >= 29
/**
+ * Possible values of the flags argument to android_res_nsend and android_res_nquery.
+ * Values are ORed together.
+ */
+enum ResNsendFlags : uint32_t {
+ /**
+ * Send a single request to a single resolver and fail on timeout or network errors
+ */
+ ANDROID_RESOLV_NO_RETRY = 1 << 0,
+
+ /**
+ * Do not cache the result of the lookup. The lookup may return a result that is already
+ * in the cache, unless the ANDROID_RESOLV_NO_CACHE_LOOKUP flag is also specified.
+ */
+ ANDROID_RESOLV_NO_CACHE_STORE = 1 << 1,
+
+ /**
+ * Don't lookup the request in cache.
+ */
+ ANDROID_RESOLV_NO_CACHE_LOOKUP = 1 << 2,
+};
+
+/**
* Look up the {|ns_class|, |ns_type|} Resource Record (RR) associated
* with Domain Name |dname| on the given |network|.
* The typical value for |ns_class| is ns_c_in, while |type| can be any
* record type (for instance, ns_t_aaaa or ns_t_txt).
+ * |flags| is a additional config to control actual querying behavior, see
+ * ResNsendFlags for detail.
*
* Returns a file descriptor to watch for read events, or a negative
* POSIX error code (see errno.h) if an immediate error occurs.
*/
int android_res_nquery(net_handle_t network,
- const char *dname, int ns_class, int ns_type) __INTRODUCED_IN(29);
+ const char *dname, int ns_class, int ns_type, uint32_t flags) __INTRODUCED_IN(29);
/**
* Issue the query |msg| on the given |network|.
+ * |flags| is a additional config to control actual querying behavior, see
+ * ResNsendFlags for detail.
*
* Returns a file descriptor to watch for read events, or a negative
* POSIX error code (see errno.h) if an immediate error occurs.
*/
int android_res_nsend(net_handle_t network,
- const uint8_t *msg, size_t msglen) __INTRODUCED_IN(29);
+ const uint8_t *msg, size_t msglen, uint32_t flags) __INTRODUCED_IN(29);
/**
* Read a result for the query associated with the |fd| descriptor.
+ * Closes |fd| before returning.
*
* Returns:
* < 0: negative POSIX error code (see errno.h for possible values). |rcode| is not set.
diff --git a/include/android/sensor.h b/include/android/sensor.h
index 005564d..e9d5c16 100644
--- a/include/android/sensor.h
+++ b/include/android/sensor.h
@@ -64,6 +64,7 @@
#define ASENSOR_RESOLUTION_INVALID (nanf(""))
#define ASENSOR_FIFO_COUNT_INVALID (-1)
#define ASENSOR_DELAY_INVALID INT32_MIN
+#define ASENSOR_INVALID (-1)
/* (Keep in sync with hardware/sensors-base.h and Sensor.java.) */
@@ -208,6 +209,35 @@
*/
ASENSOR_TYPE_HEART_BEAT = 31,
/**
+ * This sensor type is for delivering additional sensor information aside
+ * from sensor event data.
+ *
+ * Additional information may include:
+ * - {@link ASENSOR_ADDITIONAL_INFO_INTERNAL_TEMPERATURE}
+ * - {@link ASENSOR_ADDITIONAL_INFO_SAMPLING}
+ * - {@link ASENSOR_ADDITIONAL_INFO_SENSOR_PLACEMENT}
+ * - {@link ASENSOR_ADDITIONAL_INFO_UNTRACKED_DELAY}
+ * - {@link ASENSOR_ADDITIONAL_INFO_VEC3_CALIBRATION}
+ *
+ * This type will never bind to a sensor. In other words, no sensor in the
+ * sensor list can have the type {@link ASENSOR_TYPE_ADDITIONAL_INFO}.
+ *
+ * If a device supports the sensor additional information feature, it will
+ * report additional information events via {@link ASensorEvent} and will
+ * have {@link ASensorEvent#type} set to
+ * {@link ASENSOR_TYPE_ADDITIONAL_INFO} and {@link ASensorEvent#sensor} set
+ * to the handle of the reporting sensor.
+ *
+ * Additional information reports consist of multiple frames ordered by
+ * {@link ASensorEvent#timestamp}. The first frame in the report will have
+ * a {@link AAdditionalInfoEvent#type} of
+ * {@link ASENSOR_ADDITIONAL_INFO_BEGIN}, and the last frame in the report
+ * will have a {@link AAdditionalInfoEvent#type} of
+ * {@link ASENSOR_ADDITIONAL_INFO_END}.
+ *
+ */
+ ASENSOR_TYPE_ADDITIONAL_INFO = 33,
+ /**
* {@link ASENSOR_TYPE_LOW_LATENCY_OFFBODY_DETECT}
*/
ASENSOR_TYPE_LOW_LATENCY_OFFBODY_DETECT = 34,
@@ -273,6 +303,51 @@
ASENSOR_DIRECT_CHANNEL_TYPE_HARDWARE_BUFFER = 2
};
+/**
+ * Sensor Additional Info Types.
+ *
+ * Used to populate {@link AAdditionalInfoEvent#type}.
+ */
+enum {
+ /** Marks the beginning of additional information frames */
+ ASENSOR_ADDITIONAL_INFO_BEGIN = 0,
+
+ /** Marks the end of additional information frames */
+ ASENSOR_ADDITIONAL_INFO_END = 1,
+
+ /**
+ * Estimation of the delay that is not tracked by sensor timestamps. This
+ * includes delay introduced by sensor front-end filtering, data transport,
+ * etc.
+ * float[2]: delay in seconds, standard deviation of estimated value
+ */
+ ASENSOR_ADDITIONAL_INFO_UNTRACKED_DELAY = 0x10000,
+
+ /** float: Celsius temperature */
+ ASENSOR_ADDITIONAL_INFO_INTERNAL_TEMPERATURE,
+
+ /**
+ * First three rows of a homogeneous matrix, which represents calibration to
+ * a three-element vector raw sensor reading.
+ * float[12]: 3x4 matrix in row major order
+ */
+ ASENSOR_ADDITIONAL_INFO_VEC3_CALIBRATION,
+
+ /**
+ * Location and orientation of sensor element in the device frame: origin is
+ * the geometric center of the mobile device screen surface; the axis
+ * definition corresponds to Android sensor definitions.
+ * float[12]: 3x4 matrix in row major order
+ */
+ ASENSOR_ADDITIONAL_INFO_SENSOR_PLACEMENT,
+
+ /**
+ * float[2]: raw sample period in seconds,
+ * standard deviation of sampling period
+ */
+ ASENSOR_ADDITIONAL_INFO_SAMPLING,
+};
+
/*
* A few useful constants
*/
@@ -341,7 +416,7 @@
int32_t handle;
} ADynamicSensorEvent;
-typedef struct {
+typedef struct AAdditionalInfoEvent {
int32_t type;
int32_t serial;
union {
@@ -420,6 +495,7 @@
* - ASensorEventQueue_hasEvents()
* - ASensorEventQueue_getEvents()
* - ASensorEventQueue_setEventRate()
+ * - ASensorEventQueue_requestAdditionalInfoEvents()
*/
typedef struct ASensorEventQueue ASensorEventQueue;
@@ -444,6 +520,7 @@
* - ASensor_getStringType()
* - ASensor_getReportingMode()
* - ASensor_isWakeUpSensor()
+ * - ASensor_getHandle()
*/
typedef struct ASensor ASensor;
/**
@@ -703,6 +780,29 @@
*/
ssize_t ASensorEventQueue_getEvents(ASensorEventQueue* queue, ASensorEvent* events, size_t count);
+#if __ANDROID_API__ >= __ANDROID_API_Q__
+/**
+ * Request that {@link ASENSOR_TYPE_ADDITIONAL_INFO} events to be delivered on
+ * the given {@link ASensorEventQueue}.
+ *
+ * Sensor data events are always delivered to the {@ASensorEventQueue}.
+ *
+ * The {@link ASENSOR_TYPE_ADDITIONAL_INFO} events will be returned through
+ * {@link ASensorEventQueue_getEvents}. The client is responsible for checking
+ * {@link ASensorEvent#type} to determine the event type prior to handling of
+ * the event.
+ *
+ * The client must be tolerant of any value for
+ * {@link AAdditionalInfoEvent#type}, as new values may be defined in the future
+ * and may delivered to the client.
+ *
+ * \param queue {@link ASensorEventQueue} to configure
+ * \param enable true to request {@link ASENSOR_TYPE_ADDITIONAL_INFO} events,
+ * false to stop receiving events
+ * \return 0 on success or a negative error code on failure
+ */
+int ASensorEventQueue_requestAdditionalInfoEvents(ASensorEventQueue* queue, bool enable);
+#endif /* __ANDROID_API__ >= __ANDRDOID_API_Q__ */
/*****************************************************************************/
@@ -785,6 +885,24 @@
int ASensor_getHighestDirectReportRateLevel(ASensor const* sensor) __INTRODUCED_IN(26);
#endif /* __ANDROID_API__ >= 26 */
+#if __ANDROID_API__ >= __ANDROID_API_Q__
+/**
+ * Returns the sensor's handle.
+ *
+ * The handle identifies the sensor within the system and is included in the
+ * {@link ASensorEvent#sensor} field of sensor events, including those sent with type
+ * {@link ASENSOR_TYPE_ADDITIONAL_INFO}.
+ *
+ * A sensor's handle is able to be used to map {@link ASENSOR_TYPE_ADDITIONAL_INFO} events to the
+ * sensor that generated the event.
+ *
+ * It is important to note that the value returned by {@link ASensor_getHandle} is not the same as
+ * the value returned by the Java API {@link android.hardware.Sensor#getId} and no mapping exists
+ * between the values.
+ */
+int ASensor_getHandle(ASensor const* sensor) __INTRODUCED_IN(__ANDROID_API_Q__);
+#endif /* __ANDROID_API__ >= ANDROID_API_Q__ */
+
#ifdef __cplusplus
};
#endif
diff --git a/include/android/surface_control.h b/include/android/surface_control.h
new file mode 100644
index 0000000..0573187
--- /dev/null
+++ b/include/android/surface_control.h
@@ -0,0 +1,345 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @addtogroup NativeActivity Native Activity
+ * @{
+ */
+
+/**
+ * @file surface_control.h
+ */
+
+#ifndef ANDROID_SURFACE_CONTROL_H
+#define ANDROID_SURFACE_CONTROL_H
+
+#include <sys/cdefs.h>
+
+#include <android/hardware_buffer.h>
+#include <android/hdr_metadata.h>
+#include <android/native_window.h>
+
+__BEGIN_DECLS
+
+#if __ANDROID_API__ >= 29
+
+struct ASurfaceControl;
+
+/**
+ * The SurfaceControl API can be used to provide a heirarchy of surfaces for
+ * composition to the system compositor. ASurfaceControl represents a content node in
+ * this heirarchy.
+ */
+typedef struct ASurfaceControl ASurfaceControl;
+
+/*
+ * Creates an ASurfaceControl with either ANativeWindow or an ASurfaceControl as its parent.
+ * |debug_name| is a debug name associated with this surface. It can be used to
+ * identify this surface in the SurfaceFlinger's layer tree. It must not be
+ * null.
+ *
+ * The caller takes ownership of the ASurfaceControl returned and must release it
+ * using ASurfaceControl_release below.
+ */
+ASurfaceControl* ASurfaceControl_createFromWindow(ANativeWindow* parent, const char* debug_name)
+ __INTRODUCED_IN(29);
+
+ASurfaceControl* ASurfaceControl_create(ASurfaceControl* parent, const char* debug_name)
+ __INTRODUCED_IN(29);
+
+/**
+ * Releases the |surface_control| object. After releasing the ASurfaceControl the caller no longer
+ * has ownership of the AsurfaceControl. The surface and it's children may remain on display as long
+ * as their parent remains on display.
+ */
+void ASurfaceControl_release(ASurfaceControl* surface_control) __INTRODUCED_IN(29);
+
+struct ASurfaceTransaction;
+
+/**
+ * ASurfaceTransaction is a collection of updates to the surface tree that must
+ * be applied atomically.
+ */
+typedef struct ASurfaceTransaction ASurfaceTransaction;
+
+/**
+ * The caller takes ownership of the transaction and must release it using
+ * ASurfaceControl_delete below.
+ */
+ASurfaceTransaction* ASurfaceTransaction_create() __INTRODUCED_IN(29);
+
+/**
+ * Destroys the |transaction| object.
+ */
+void ASurfaceTransaction_delete(ASurfaceTransaction* transaction) __INTRODUCED_IN(29);
+
+/**
+ * Applies the updates accumulated in |transaction|.
+ *
+ * Note that the transaction is guaranteed to be applied atomically. The
+ * transactions which are applied on the same thread are also guaranteed to be
+ * applied in order.
+ */
+void ASurfaceTransaction_apply(ASurfaceTransaction* transaction) __INTRODUCED_IN(29);
+
+/**
+ * An opaque handle returned during a callback that can be used to query general stats and stats for
+ * surfaces which were either removed or for which buffers were updated after this transaction was
+ * applied.
+ */
+typedef struct ASurfaceTransactionStats ASurfaceTransactionStats;
+
+/**
+ * Since the transactions are applied asynchronously, the
+ * ASurfaceTransaction_OnComplete callback can be used to be notified when a frame
+ * including the updates in a transaction was presented.
+ *
+ * |context| is the optional context provided by the client that is passed into
+ * the callback.
+ *
+ * |stats| is an opaque handle that can be passed to ASurfaceTransactionStats functions to query
+ * information about the transaction. The handle is only valid during the the callback.
+ *
+ * THREADING
+ * The transaction completed callback can be invoked on any thread.
+ */
+typedef void (*ASurfaceTransaction_OnComplete)(void* context, ASurfaceTransactionStats* stats)
+ __INTRODUCED_IN(29);
+
+/**
+ * Returns the timestamp of when the frame was latched by the framework. Once a frame is
+ * latched by the framework, it is presented at the following hardware vsync.
+ */
+int64_t ASurfaceTransactionStats_getLatchTime(ASurfaceTransactionStats* surface_transaction_stats)
+ __INTRODUCED_IN(29);
+
+/**
+ * Returns a sync fence that signals when the transaction has been presented.
+ * The recipient of the callback takes ownership of the fence and is responsible for closing
+ * it.
+ */
+int ASurfaceTransactionStats_getPresentFenceFd(ASurfaceTransactionStats* surface_transaction_stats)
+ __INTRODUCED_IN(29);
+
+/**
+ * |outASurfaceControls| returns an array of ASurfaceControl pointers that were updated during the
+ * transaction. Stats for the surfaces can be queried through ASurfaceTransactionStats functions.
+ * When the client is done using the array, it must release it by calling
+ * ASurfaceTransactionStats_releaseASurfaceControls.
+ *
+ * |outASurfaceControlsSize| returns the size of the ASurfaceControls array.
+ */
+void ASurfaceTransactionStats_getASurfaceControls(ASurfaceTransactionStats* surface_transaction_stats,
+ ASurfaceControl*** outASurfaceControls,
+ size_t* outASurfaceControlsSize)
+ __INTRODUCED_IN(29);
+/**
+ * Releases the array of ASurfaceControls that were returned by
+ * ASurfaceTransactionStats_getASurfaceControls.
+ */
+void ASurfaceTransactionStats_releaseASurfaceControls(ASurfaceControl** surface_controls)
+ __INTRODUCED_IN(29);
+
+/**
+ * Returns the timestamp of when the CURRENT buffer was acquired. A buffer is considered
+ * acquired when its acquire_fence_fd has signaled. A buffer cannot be latched or presented until
+ * it is acquired. If no acquire_fence_fd was provided, this timestamp will be set to -1.
+ */
+int64_t ASurfaceTransactionStats_getAcquireTime(ASurfaceTransactionStats* surface_transaction_stats,
+ ASurfaceControl* surface_control)
+ __INTRODUCED_IN(29);
+
+/**
+ * The returns the fence used to signal the release of the PREVIOUS buffer set on
+ * this surface. If this fence is valid (>=0), the PREVIOUS buffer has not yet been released and the
+ * fence will signal when the PREVIOUS buffer has been released. If the fence is -1 , the PREVIOUS
+ * buffer is already released. The recipient of the callback takes ownership of the
+ * previousReleaseFenceFd and is responsible for closing it.
+ *
+ * Each time a buffer is set through ASurfaceTransaction_setBuffer()/_setCachedBuffer() on a
+ * transaction which is applied, the framework takes a ref on this buffer. The framework treats the
+ * addition of a buffer to a particular surface as a unique ref. When a transaction updates or
+ * removes a buffer from a surface, or removes the surface itself from the tree, this ref is
+ * guaranteed to be released in the OnComplete callback for this transaction. The
+ * ASurfaceControlStats provided in the callback for this surface may contain an optional fence
+ * which must be signaled before the ref is assumed to be released.
+ *
+ * The client must ensure that all pending refs on a buffer are released before attempting to reuse
+ * this buffer, otherwise synchronization errors may occur.
+ */
+int ASurfaceTransactionStats_getPreviousReleaseFenceFd(
+ ASurfaceTransactionStats* surface_transaction_stats,
+ ASurfaceControl* surface_control)
+ __INTRODUCED_IN(29);
+
+/**
+ * Sets the callback that will be invoked when the updates from this transaction
+ * are presented. For details on the callback semantics and data, see the
+ * comments on the ASurfaceTransaction_OnComplete declaration above.
+ */
+void ASurfaceTransaction_setOnComplete(ASurfaceTransaction* transaction, void* context,
+ ASurfaceTransaction_OnComplete func) __INTRODUCED_IN(29);
+
+/**
+ * Reparents the |surface_control| from its old parent to the |new_parent| surface control.
+ * Any children of the* reparented |surface_control| will remain children of the |surface_control|.
+ *
+ * The |new_parent| can be null. Surface controls with a null parent do not appear on the display.
+ */
+void ASurfaceTransaction_reparent(ASurfaceTransaction* transaction,
+ ASurfaceControl* surface_control, ASurfaceControl* new_parent)
+ __INTRODUCED_IN(29);
+
+/* Parameter for ASurfaceTransaction_setVisibility */
+enum {
+ ASURFACE_TRANSACTION_VISIBILITY_HIDE = 0,
+ ASURFACE_TRANSACTION_VISIBILITY_SHOW = 1,
+};
+/**
+ * Updates the visibility of |surface_control|. If show is set to
+ * ASURFACE_TRANSACTION_VISIBILITY_HIDE, the |surface_control| and all surfaces in its subtree will
+ * be hidden.
+ */
+void ASurfaceTransaction_setVisibility(ASurfaceTransaction* transaction,
+ ASurfaceControl* surface_control, int8_t visibility)
+ __INTRODUCED_IN(29);
+
+/**
+ * Updates the z order index for |surface_control|. Note that the z order for a surface
+ * is relative to other surfaces which are siblings of this surface. The behavior of sibilings with
+ * the same z order is undefined.
+ *
+ * Z orders may be from MIN_INT32 to MAX_INT32. A layer's default z order index is 0.
+ */
+void ASurfaceTransaction_setZOrder(ASurfaceTransaction* transaction,
+ ASurfaceControl* surface_control, int32_t z_order)
+ __INTRODUCED_IN(29);
+
+/**
+ * Updates the AHardwareBuffer displayed for |surface_control|. If not -1, the
+ * acquire_fence_fd should be a file descriptor that is signaled when all pending work
+ * for the buffer is complete and the buffer can be safely read.
+ *
+ * The frameworks takes ownership of the |acquire_fence_fd| passed and is responsible
+ * for closing it.
+ */
+void ASurfaceTransaction_setBuffer(ASurfaceTransaction* transaction,
+ ASurfaceControl* surface_control, AHardwareBuffer* buffer,
+ int acquire_fence_fd = -1) __INTRODUCED_IN(29);
+
+/**
+ * Updates the color for |surface_control|. This will make the background color for the
+ * ASurfaceControl visible in transparent regions of the surface. Colors |r|, |g|,
+ * and |b| must be within the range that is valid for |dataspace|. |dataspace| and |alpha|
+ * will be the dataspace and alpha set for the background color layer.
+ */
+void ASurfaceTransaction_setColor(ASurfaceTransaction* transaction,
+ ASurfaceControl* surface_control, float r, float g, float b,
+ float alpha, ADataSpace dataspace)
+ __INTRODUCED_IN(29);
+
+/**
+ * |source| the sub-rect within the buffer's content to be rendered inside the surface's area
+ * The surface's source rect is clipped by the bounds of its current buffer. The source rect's width
+ * and height must be > 0.
+ *
+ * |destination| specifies the rect in the parent's space where this surface will be drawn. The post
+ * source rect bounds are scaled to fit the destination rect. The surface's destination rect is
+ * clipped by the bounds of its parent. The destination rect's width and height must be > 0.
+ *
+ * |transform| the transform applied after the source rect is applied to the buffer. This parameter
+ * should be set to 0 for no transform. To specify a transfrom use the NATIVE_WINDOW_TRANSFORM_*
+ * enum.
+ */
+void ASurfaceTransaction_setGeometry(ASurfaceTransaction* transaction,
+ ASurfaceControl* surface_control, const ARect& source,
+ const ARect& destination, int32_t transform)
+ __INTRODUCED_IN(29);
+
+
+/* Parameter for ASurfaceTransaction_setBufferTransparency */
+enum {
+ ASURFACE_TRANSACTION_TRANSPARENCY_TRANSPARENT = 0,
+ ASURFACE_TRANSACTION_TRANSPARENCY_TRANSLUCENT = 1,
+ ASURFACE_TRANSACTION_TRANSPARENCY_OPAQUE = 2,
+};
+/**
+ * Updates whether the content for the buffer associated with this surface is
+ * completely opaque. If true, every pixel of content inside the buffer must be
+ * opaque or visual errors can occur.
+ */
+void ASurfaceTransaction_setBufferTransparency(ASurfaceTransaction* transaction,
+ ASurfaceControl* surface_control,
+ int8_t transparency)
+ __INTRODUCED_IN(29);
+
+/**
+ * Updates the region for the content on this surface updated in this
+ * transaction. If unspecified, the complete surface is assumed to be damaged.
+ */
+void ASurfaceTransaction_setDamageRegion(ASurfaceTransaction* transaction,
+ ASurfaceControl* surface_control, const ARect rects[],
+ uint32_t count) __INTRODUCED_IN(29);
+
+/**
+ * Specifies a desiredPresentTime for the transaction. The framework will try to present
+ * the transaction at or after the time specified.
+ *
+ * Transactions will not be presented until all of their acquire fences have signaled even if the
+ * app requests an earlier present time.
+ *
+ * If an earlier transaction has a desired present time of x, and a later transaction has a desired
+ * present time that is before x, the later transaction will not preempt the earlier transaction.
+ */
+void ASurfaceTransaction_setDesiredPresentTime(ASurfaceTransaction* transaction,
+ int64_t desiredPresentTime) __INTRODUCED_IN(29);
+
+/**
+ * Sets the alpha for the buffer. It uses a premultiplied blending.
+ *
+ * The |alpha| must be between 0.0 and 1.0.
+ */
+void ASurfaceTransaction_setBufferAlpha(ASurfaceTransaction* transaction,
+ ASurfaceControl* surface_control, float alpha)
+ __INTRODUCED_IN(29);
+
+/*
+ * SMPTE ST 2086 "Mastering Display Color Volume" static metadata
+ *
+ * When |metadata| is set to null, the framework does not use any smpte2086 metadata when rendering
+ * the surface's buffer.
+ */
+void ASurfaceTransaction_setHdrMetadata_smpte2086(ASurfaceTransaction* transaction,
+ ASurfaceControl* surface_control,
+ struct AHdrMetadata_smpte2086* metadata)
+ __INTRODUCED_IN(29);
+
+/*
+ * Sets the CTA 861.3 "HDR Static Metadata Extension" static metadata on a surface.
+ *
+ * When |metadata| is set to null, the framework does not use any cta861.3 metadata when rendering
+ * the surface's buffer.
+ */
+void ASurfaceTransaction_setHdrMetadata_cta861_3(ASurfaceTransaction* transaction,
+ ASurfaceControl* surface_control,
+ struct AHdrMetadata_cta861_3* metadata)
+ __INTRODUCED_IN(29);
+
+#endif // __ANDROID_API__ >= 29
+
+__END_DECLS
+
+#endif // ANDROID_SURFACE_CONTROL_H
diff --git a/include/input/IInputFlinger.h b/include/input/IInputFlinger.h
index 610834d..ff443c6 100644
--- a/include/input/IInputFlinger.h
+++ b/include/input/IInputFlinger.h
@@ -36,7 +36,7 @@
DECLARE_META_INTERFACE(InputFlinger)
virtual void setInputWindows(const Vector<InputWindowInfo>& inputHandles) = 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;
};
@@ -50,7 +50,8 @@
enum {
SET_INPUT_WINDOWS_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION,
REGISTER_INPUT_CHANNEL_TRANSACTION,
- UNREGISTER_INPUT_CHANNEL_TRANSACTION
+ UNREGISTER_INPUT_CHANNEL_TRANSACTION,
+ TRANSFER_TOUCH_FOCUS
};
virtual status_t onTransact(uint32_t code, const Parcel& data,
diff --git a/include/input/Input.h b/include/input/Input.h
index 037270c..805957a 100644
--- a/include/input/Input.h
+++ b/include/input/Input.h
@@ -220,6 +220,32 @@
POLICY_FLAG_PASS_TO_USER = 0x40000000,
};
+/**
+ * Classifications of the current gesture, if available.
+ *
+ * The following values must be kept in sync with MotionEvent.java
+ */
+enum class MotionClassification : uint8_t {
+ /**
+ * No classification is available.
+ */
+ NONE = 0,
+ /**
+ * Too early to classify the current gesture. Need more events. Look for changes in the
+ * upcoming motion events.
+ */
+ AMBIGUOUS_GESTURE = 1,
+ /**
+ * The current gesture likely represents a user intentionally exerting force on the touchscreen.
+ */
+ DEEP_PRESS = 2,
+};
+
+/**
+ * String representation of MotionClassification
+ */
+const char* motionClassificationToString(MotionClassification classification);
+
/*
* Pointer coordinate data.
*/
@@ -419,6 +445,8 @@
inline void setButtonState(int32_t buttonState) { mButtonState = buttonState; }
+ inline MotionClassification getClassification() const { return mClassification; }
+
inline int32_t getActionButton() const { return mActionButton; }
inline void setActionButton(int32_t button) { mActionButton = button; }
@@ -582,6 +610,7 @@
int32_t edgeFlags,
int32_t metaState,
int32_t buttonState,
+ MotionClassification classification,
float xOffset,
float yOffset,
float xPrecision,
@@ -635,6 +664,7 @@
int32_t mEdgeFlags;
int32_t mMetaState;
int32_t mButtonState;
+ MotionClassification mClassification;
float mXOffset;
float mYOffset;
float mXPrecision;
diff --git a/include/input/InputTransport.h b/include/input/InputTransport.h
index dddbfb0..63606e5 100644
--- a/include/input/InputTransport.h
+++ b/include/input/InputTransport.h
@@ -105,8 +105,9 @@
int32_t flags;
int32_t metaState;
int32_t buttonState;
+ MotionClassification classification; // base type: uint8_t
+ uint8_t empty2[3];
int32_t edgeFlags;
- uint32_t empty2;
nsecs_t downTime __attribute__((aligned(8)));
float xOffset;
float yOffset;
@@ -271,6 +272,7 @@
int32_t edgeFlags,
int32_t metaState,
int32_t buttonState,
+ MotionClassification classification,
float xOffset,
float yOffset,
float xPrecision,
diff --git a/include/input/InputWindow.h b/include/input/InputWindow.h
index 2b8cc57..a065a4c 100644
--- a/include/input/InputWindow.h
+++ b/include/input/InputWindow.h
@@ -163,6 +163,7 @@
int32_t ownerUid;
int32_t inputFeatures;
int32_t displayId;
+ int32_t portalToDisplayId = ADISPLAY_ID_NONE;
InputApplicationInfo applicationInfo;
void addTouchableRegion(const Rect& region);
diff --git a/include/input/TouchVideoFrame.h b/include/input/TouchVideoFrame.h
index d68f274..640bf1f 100644
--- a/include/input/TouchVideoFrame.h
+++ b/include/input/TouchVideoFrame.h
@@ -35,6 +35,14 @@
mWidth(width), mHeight(height), mData(std::move(data)), mTimestamp(timestamp) {
}
+ bool operator==(const TouchVideoFrame& rhs) const {
+ return mWidth == rhs.mWidth
+ && mHeight == rhs.mHeight
+ && mData == rhs.mData
+ && mTimestamp.tv_sec == rhs.mTimestamp.tv_sec
+ && mTimestamp.tv_usec == rhs.mTimestamp.tv_usec;
+ }
+
/**
* Width of the frame
*/
diff --git a/libs/arect/Android.bp b/libs/arect/Android.bp
index a20154f..ad8287c 100644
--- a/libs/arect/Android.bp
+++ b/libs/arect/Android.bp
@@ -25,4 +25,9 @@
host_supported: true,
vendor_available: true,
export_include_dirs: ["include"],
+ target: {
+ windows: {
+ enabled: true,
+ },
+ },
}
diff --git a/libs/binder/Binder.cpp b/libs/binder/Binder.cpp
index f6cc3af..96ee295 100644
--- a/libs/binder/Binder.cpp
+++ b/libs/binder/Binder.cpp
@@ -86,6 +86,10 @@
class BBinder::Extras
{
public:
+ // unlocked objects
+ bool mRequestingSid = false;
+
+ // for below objects
Mutex mLock;
BpBinder::ObjectManager mObjects;
};
@@ -163,19 +167,8 @@
const void* objectID, void* object, void* cleanupCookie,
object_cleanup_func func)
{
- Extras* e = mExtras.load(std::memory_order_acquire);
-
- if (!e) {
- e = new Extras;
- Extras* expected = nullptr;
- if (!mExtras.compare_exchange_strong(expected, e,
- std::memory_order_release,
- std::memory_order_acquire)) {
- delete e;
- e = expected; // Filled in by CAS
- }
- if (e == nullptr) return; // out of memory
- }
+ Extras* e = getOrCreateExtras();
+ if (!e) return; // out of memory
AutoMutex _l(e->mLock);
e->mObjects.attach(objectID, object, cleanupCookie, func);
@@ -204,6 +197,30 @@
return this;
}
+bool BBinder::isRequestingSid()
+{
+ Extras* e = mExtras.load(std::memory_order_acquire);
+
+ return e && e->mRequestingSid;
+}
+
+void BBinder::setRequestingSid(bool requestingSid)
+{
+ Extras* e = mExtras.load(std::memory_order_acquire);
+
+ if (!e) {
+ // default is false. Most things don't need sids, so avoiding allocations when possible.
+ if (!requestingSid) {
+ return;
+ }
+
+ e = getOrCreateExtras();
+ if (!e) return; // out of memory
+ }
+
+ e->mRequestingSid = true;
+}
+
BBinder::~BBinder()
{
Extras* e = mExtras.load(std::memory_order_relaxed);
@@ -267,6 +284,25 @@
}
}
+BBinder::Extras* BBinder::getOrCreateExtras()
+{
+ Extras* e = mExtras.load(std::memory_order_acquire);
+
+ if (!e) {
+ e = new Extras;
+ Extras* expected = nullptr;
+ if (!mExtras.compare_exchange_strong(expected, e,
+ std::memory_order_release,
+ std::memory_order_acquire)) {
+ delete e;
+ e = expected; // Filled in by CAS
+ }
+ if (e == nullptr) return nullptr; // out of memory
+ }
+
+ return e;
+}
+
// ---------------------------------------------------------------------------
enum {
diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp
index 8df83f1..9a561cb 100644
--- a/libs/binder/IPCThreadState.cpp
+++ b/libs/binder/IPCThreadState.cpp
@@ -23,7 +23,9 @@
#include <binder/BpBinder.h>
#include <binder/TextOutput.h>
+#include <android-base/macros.h>
#include <cutils/sched_policy.h>
+#include <utils/CallStack.h>
#include <utils/Log.h>
#include <utils/SystemClock.h>
#include <utils/threads.h>
@@ -86,7 +88,8 @@
"BR_FINISHED",
"BR_DEAD_BINDER",
"BR_CLEAR_DEATH_NOTIFICATION_DONE",
- "BR_FAILED_REPLY"
+ "BR_FAILED_REPLY",
+ "BR_TRANSACTION_SEC_CTX",
};
static const char *kCommandStrings[] = {
@@ -363,6 +366,11 @@
return mCallingPid;
}
+const char* IPCThreadState::getCallingSid() const
+{
+ return mCallingSid;
+}
+
uid_t IPCThreadState::getCallingUid() const
{
return mCallingUid;
@@ -370,6 +378,7 @@
int64_t IPCThreadState::clearCallingIdentity()
{
+ // ignore mCallingSid for legacy reasons
int64_t token = ((int64_t)mCallingUid<<32) | mCallingPid;
clearCaller();
return token;
@@ -440,12 +449,14 @@
void IPCThreadState::restoreCallingIdentity(int64_t token)
{
mCallingUid = (int)(token>>32);
+ mCallingSid = nullptr; // not enough data to restore
mCallingPid = (int)token;
}
void IPCThreadState::clearCaller()
{
mCallingPid = getpid();
+ mCallingSid = nullptr; // expensive to lookup
mCallingUid = getuid();
}
@@ -661,6 +672,16 @@
}
if ((flags & TF_ONE_WAY) == 0) {
+ if (UNLIKELY(mCallRestriction != ProcessState::CallRestriction::NONE)) {
+ if (mCallRestriction == ProcessState::CallRestriction::ERROR_IF_NOT_ONEWAY) {
+ ALOGE("Process making non-oneway call but is restricted.");
+ CallStack::logStack("non-oneway call", CallStack::getCurrent(10).get(),
+ ANDROID_LOG_ERROR);
+ } else /* FATAL_IF_NOT_ONEWAY */ {
+ LOG_ALWAYS_FATAL("Process may not make oneway calls.");
+ }
+ }
+
#if 0
if (code == 4) { // relayout
ALOGI(">>>>>> CALLING transaction 4");
@@ -783,7 +804,8 @@
mWorkSource(kUnsetWorkSource),
mPropagateWorkSource(false),
mStrictModePolicy(0),
- mLastTransactionBinderFlags(0)
+ mLastTransactionBinderFlags(0),
+ mCallRestriction(mProcess->mCallRestriction)
{
pthread_setspecific(gTLS, this);
clearCaller();
@@ -1122,10 +1144,19 @@
}
break;
+ case BR_TRANSACTION_SEC_CTX:
case BR_TRANSACTION:
{
- binder_transaction_data tr;
- result = mIn.read(&tr, sizeof(tr));
+ binder_transaction_data_secctx tr_secctx;
+ binder_transaction_data& tr = tr_secctx.transaction_data;
+
+ if (cmd == (int) BR_TRANSACTION_SEC_CTX) {
+ result = mIn.read(&tr_secctx, sizeof(tr_secctx));
+ } else {
+ result = mIn.read(&tr, sizeof(tr));
+ tr_secctx.secctx = 0;
+ }
+
ALOG_ASSERT(result == NO_ERROR,
"Not enough command data for brTRANSACTION");
if (result != NO_ERROR) break;
@@ -1141,6 +1172,7 @@
tr.offsets_size/sizeof(binder_size_t), freeBuffer, this);
const pid_t origPid = mCallingPid;
+ const char* origSid = mCallingSid;
const uid_t origUid = mCallingUid;
const int32_t origStrictModePolicy = mStrictModePolicy;
const int32_t origTransactionBinderFlags = mLastTransactionBinderFlags;
@@ -1153,10 +1185,12 @@
clearPropagateWorkSource();
mCallingPid = tr.sender_pid;
+ mCallingSid = reinterpret_cast<const char*>(tr_secctx.secctx);
mCallingUid = tr.sender_euid;
mLastTransactionBinderFlags = tr.flags;
- //ALOGI(">>>> TRANSACT from pid %d uid %d\n", mCallingPid, mCallingUid);
+ // ALOGI(">>>> TRANSACT from pid %d sid %s uid %d\n", mCallingPid,
+ // (mCallingSid ? mCallingSid : "<N/A>"), mCallingUid);
Parcel reply;
status_t error;
@@ -1188,8 +1222,8 @@
}
mIPCThreadStateBase->popCurrentState();
- //ALOGI("<<<< TRANSACT from pid %d restore pid %d uid %d\n",
- // mCallingPid, origPid, origUid);
+ //ALOGI("<<<< TRANSACT from pid %d restore pid %d sid %s uid %d\n",
+ // mCallingPid, origPid, (origSid ? origSid : "<N/A>"), origUid);
if ((tr.flags & TF_ONE_WAY) == 0) {
LOG_ONEWAY("Sending reply to %d!", mCallingPid);
@@ -1200,6 +1234,7 @@
}
mCallingPid = origPid;
+ mCallingSid = origSid;
mCallingUid = origUid;
mStrictModePolicy = origStrictModePolicy;
mLastTransactionBinderFlags = origTransactionBinderFlags;
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index d285030..a595c01 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -181,7 +181,10 @@
if ((outAshmemSize != nullptr) && ashmem_valid(obj.handle)) {
int size = ashmem_get_size_region(obj.handle);
if (size > 0) {
- *outAshmemSize -= size;
+ // ashmem size might have changed since last time it was accounted for, e.g.
+ // in acquire_object(). Value of *outAshmemSize is not critical since we are
+ // releasing the object anyway. Check for integer overflow condition.
+ *outAshmemSize -= std::min(*outAshmemSize, static_cast<size_t>(size));
}
}
@@ -220,7 +223,7 @@
}
if (binder != nullptr) {
- IBinder *local = binder->localBinder();
+ BBinder *local = binder->localBinder();
if (!local) {
BpBinder *proxy = binder->remoteBinder();
if (proxy == nullptr) {
@@ -232,6 +235,9 @@
obj.handle = handle;
obj.cookie = 0;
} else {
+ if (local->isRequestingSid()) {
+ obj.flags |= FLAT_BINDER_FLAG_TXN_SECURITY_CTX;
+ }
obj.hdr.type = BINDER_TYPE_BINDER;
obj.binder = reinterpret_cast<uintptr_t>(local->getWeakRefs());
obj.cookie = reinterpret_cast<uintptr_t>(local);
@@ -596,17 +602,53 @@
return mHasFds;
}
+void Parcel::updateWorkSourceRequestHeaderPosition() const {
+ // Only update the request headers once. We only want to point
+ // to the first headers read/written.
+ if (!mRequestHeaderPresent) {
+ mWorkSourceRequestHeaderPosition = dataPosition();
+ mRequestHeaderPresent = true;
+ }
+}
+
// Write RPC headers. (previously just the interface token)
status_t Parcel::writeInterfaceToken(const String16& interface)
{
const IPCThreadState* threadState = IPCThreadState::self();
writeInt32(threadState->getStrictModePolicy() | STRICT_MODE_PENALTY_GATHER);
+ updateWorkSourceRequestHeaderPosition();
writeInt32(threadState->shouldPropagateWorkSource() ?
threadState->getCallingWorkSourceUid() : IPCThreadState::kUnsetWorkSource);
// currently the interface identification token is just its name as a string
return writeString16(interface);
}
+bool Parcel::replaceCallingWorkSourceUid(uid_t uid)
+{
+ if (!mRequestHeaderPresent) {
+ return false;
+ }
+
+ const size_t initialPosition = dataPosition();
+ setDataPosition(mWorkSourceRequestHeaderPosition);
+ status_t err = writeInt32(uid);
+ setDataPosition(initialPosition);
+ return err == NO_ERROR;
+}
+
+uid_t Parcel::readCallingWorkSourceUid()
+{
+ if (!mRequestHeaderPresent) {
+ return IPCThreadState::kUnsetWorkSource;
+ }
+
+ const size_t initialPosition = dataPosition();
+ setDataPosition(mWorkSourceRequestHeaderPosition);
+ uid_t uid = readInt32();
+ setDataPosition(initialPosition);
+ return uid;
+}
+
bool Parcel::checkInterface(IBinder* binder) const
{
return enforceInterface(binder->getInterfaceDescriptor());
@@ -631,6 +673,7 @@
threadState->setStrictModePolicy(strictPolicy);
}
// WorkSource.
+ updateWorkSourceRequestHeaderPosition();
int32_t workSource = readInt32();
threadState->setCallingWorkSourceUidWithoutPropagation(workSource);
// Interface descriptor.
@@ -2886,6 +2929,8 @@
mAllowFds = true;
mOwner = nullptr;
mOpenAshmemSize = 0;
+ mWorkSourceRequestHeaderPosition = 0;
+ mRequestHeaderPresent = false;
// racing multiple init leads only to multiple identical write
if (gMaxFds == 0) {
diff --git a/libs/binder/ProcessState.cpp b/libs/binder/ProcessState.cpp
index 53f8ddd..79db0cb 100644
--- a/libs/binder/ProcessState.cpp
+++ b/libs/binder/ProcessState.cpp
@@ -181,8 +181,20 @@
mBinderContextCheckFunc = checkFunc;
mBinderContextUserData = userData;
- int dummy = 0;
- status_t result = ioctl(mDriverFD, BINDER_SET_CONTEXT_MGR, &dummy);
+ flat_binder_object obj {
+ .flags = FLAT_BINDER_FLAG_TXN_SECURITY_CTX,
+ };
+
+ status_t result = ioctl(mDriverFD, BINDER_SET_CONTEXT_MGR_EXT, &obj);
+
+ // fallback to original method
+ if (result != 0) {
+ android_errorWriteLog(0x534e4554, "121035042");
+
+ int dummy = 0;
+ result = ioctl(mDriverFD, BINDER_SET_CONTEXT_MGR, &dummy);
+ }
+
if (result == 0) {
mManagesContexts = true;
} else if (result == -1) {
@@ -234,6 +246,12 @@
return count;
}
+void ProcessState::setCallRestriction(CallRestriction restriction) {
+ LOG_ALWAYS_FATAL_IF(IPCThreadState::selfOrNull(), "Call restrictions must be set before the threadpool is started.");
+
+ mCallRestriction = restriction;
+}
+
ProcessState::handle_entry* ProcessState::lookupHandleLocked(int32_t handle)
{
const size_t N=mHandleToObject.size();
@@ -426,6 +444,7 @@
, mBinderContextUserData(nullptr)
, mThreadPoolStarted(false)
, mThreadPoolSeq(1)
+ , mCallRestriction(CallRestriction::NONE)
{
if (mDriverFD >= 0) {
// mmap the binder, providing a chunk of virtual address space to receive transactions.
diff --git a/libs/binder/include/binder/ActivityManager.h b/libs/binder/include/binder/ActivityManager.h
index 26dafd0..7b086d0 100644
--- a/libs/binder/include/binder/ActivityManager.h
+++ b/libs/binder/include/binder/ActivityManager.h
@@ -46,23 +46,24 @@
PROCESS_STATE_PERSISTENT = 0,
PROCESS_STATE_PERSISTENT_UI = 1,
PROCESS_STATE_TOP = 2,
- PROCESS_STATE_FOREGROUND_SERVICE = 3,
- PROCESS_STATE_BOUND_FOREGROUND_SERVICE = 4,
- PROCESS_STATE_IMPORTANT_FOREGROUND = 5,
- PROCESS_STATE_IMPORTANT_BACKGROUND = 6,
- PROCESS_STATE_TRANSIENT_BACKGROUND = 7,
- PROCESS_STATE_BACKUP = 8,
- PROCESS_STATE_SERVICE = 9,
- PROCESS_STATE_RECEIVER = 10,
- PROCESS_STATE_TOP_SLEEPING = 11,
- PROCESS_STATE_HEAVY_WEIGHT = 12,
- PROCESS_STATE_HOME = 13,
- PROCESS_STATE_LAST_ACTIVITY = 14,
- PROCESS_STATE_CACHED_ACTIVITY = 15,
- PROCESS_STATE_CACHED_ACTIVITY_CLIENT = 16,
- PROCESS_STATE_CACHED_RECENT = 17,
- PROCESS_STATE_CACHED_EMPTY = 18,
- PROCESS_STATE_NONEXISTENT = 19,
+ PROCESS_STATE_FOREGROUND_SERVICE_LOCATION = 3,
+ PROCESS_STATE_FOREGROUND_SERVICE = 4,
+ PROCESS_STATE_BOUND_FOREGROUND_SERVICE = 5,
+ PROCESS_STATE_IMPORTANT_FOREGROUND = 6,
+ PROCESS_STATE_IMPORTANT_BACKGROUND = 7,
+ PROCESS_STATE_TRANSIENT_BACKGROUND = 8,
+ PROCESS_STATE_BACKUP = 9,
+ PROCESS_STATE_SERVICE = 10,
+ PROCESS_STATE_RECEIVER = 11,
+ PROCESS_STATE_TOP_SLEEPING = 12,
+ PROCESS_STATE_HEAVY_WEIGHT = 13,
+ PROCESS_STATE_HOME = 14,
+ PROCESS_STATE_LAST_ACTIVITY = 15,
+ PROCESS_STATE_CACHED_ACTIVITY = 16,
+ PROCESS_STATE_CACHED_ACTIVITY_CLIENT = 17,
+ PROCESS_STATE_CACHED_RECENT = 18,
+ PROCESS_STATE_CACHED_EMPTY = 19,
+ PROCESS_STATE_NONEXISTENT = 20,
};
ActivityManager();
diff --git a/libs/binder/include/binder/Binder.h b/libs/binder/include/binder/Binder.h
index c251468..cf3ef84 100644
--- a/libs/binder/include/binder/Binder.h
+++ b/libs/binder/include/binder/Binder.h
@@ -60,6 +60,10 @@
virtual BBinder* localBinder();
+ bool isRequestingSid();
+ // This must be called before the object is sent to another process. Not thread safe.
+ void setRequestingSid(bool requestSid);
+
protected:
virtual ~BBinder();
@@ -75,6 +79,8 @@
class Extras;
+ Extras* getOrCreateExtras();
+
std::atomic<Extras*> mExtras;
void* mReserved0;
};
diff --git a/libs/binder/include/binder/IInterface.h b/libs/binder/include/binder/IInterface.h
index 5ec02b1..f6381f7 100644
--- a/libs/binder/include/binder/IInterface.h
+++ b/libs/binder/include/binder/IInterface.h
@@ -124,7 +124,9 @@
#define CHECK_INTERFACE(interface, data, reply) \
- if (!(data).checkInterface(this)) { return PERMISSION_DENIED; } \
+ do { \
+ if (!(data).checkInterface(this)) { return PERMISSION_DENIED; } \
+ } while (false) \
// ----------------------------------------------------------------------
diff --git a/libs/binder/include/binder/IPCThreadState.h b/libs/binder/include/binder/IPCThreadState.h
index 26e8c0b..614b0b3 100644
--- a/libs/binder/include/binder/IPCThreadState.h
+++ b/libs/binder/include/binder/IPCThreadState.h
@@ -42,6 +42,11 @@
status_t clearLastError();
pid_t getCallingPid() const;
+ // nullptr if unavailable
+ //
+ // this can't be restored once it's cleared, and it does not return the
+ // context of the current process when not in a binder call.
+ const char* getCallingSid() const;
uid_t getCallingUid() const;
void setStrictModePolicy(int32_t policy);
@@ -64,6 +69,7 @@
int32_t getLastTransactionBinderFlags() const;
int64_t clearCallingIdentity();
+ // Restores PID/UID (not SID)
void restoreCallingIdentity(int64_t token);
int setupPolling(int* fd);
@@ -174,6 +180,7 @@
Parcel mOut;
status_t mLastError;
pid_t mCallingPid;
+ const char* mCallingSid;
uid_t mCallingUid;
// The UID of the process who is responsible for this transaction.
// This is used for resource attribution.
@@ -183,6 +190,8 @@
int32_t mStrictModePolicy;
int32_t mLastTransactionBinderFlags;
IPCThreadStateBase *mIPCThreadStateBase;
+
+ ProcessState::CallRestriction mCallRestriction;
};
}; // namespace android
diff --git a/libs/binder/include/binder/Parcel.h b/libs/binder/include/binder/Parcel.h
index cd151ee..afdfe4f 100644
--- a/libs/binder/include/binder/Parcel.h
+++ b/libs/binder/include/binder/Parcel.h
@@ -27,8 +27,8 @@
#include <utils/String16.h>
#include <utils/Vector.h>
#include <utils/Flattenable.h>
-#include <linux/android/binder.h>
+#include <binder/binder_kernel.h>
#include <binder/IInterface.h>
#include <binder/Parcelable.h>
#include <binder/Map.h>
@@ -395,6 +395,12 @@
static size_t getGlobalAllocSize();
static size_t getGlobalAllocCount();
+ bool replaceCallingWorkSourceUid(uid_t uid);
+ // Returns the work source provided by the caller. This can only be trusted for trusted calling
+ // uid.
+ uid_t readCallingWorkSourceUid();
+ void readRequestHeaders() const;
+
private:
typedef void (*release_func)(Parcel* parcel,
const uint8_t* data, size_t dataSize,
@@ -429,6 +435,7 @@
void initState();
void scanForFds() const;
status_t validateReadData(size_t len) const;
+ void updateWorkSourceRequestHeaderPosition() const;
template<class T>
status_t readAligned(T *pArg) const;
@@ -477,6 +484,9 @@
mutable size_t mNextObjectHint;
mutable bool mObjectsSorted;
+ mutable bool mRequestHeaderPresent;
+ mutable size_t mWorkSourceRequestHeaderPosition;
+
mutable bool mFdsKnown;
mutable bool mHasFds;
bool mAllowFds;
diff --git a/libs/binder/include/binder/ProcessState.h b/libs/binder/include/binder/ProcessState.h
index 3712c84..224cb36 100644
--- a/libs/binder/include/binder/ProcessState.h
+++ b/libs/binder/include/binder/ProcessState.h
@@ -77,6 +77,18 @@
ssize_t getKernelReferences(size_t count, uintptr_t* buf);
+ enum class CallRestriction {
+ // all calls okay
+ NONE,
+ // log when calls are blocking
+ ERROR_IF_NOT_ONEWAY,
+ // abort process on blocking calls
+ FATAL_IF_NOT_ONEWAY,
+ };
+ // Sets calling restrictions for all transactions in this process. This must be called
+ // before any threads are spawned.
+ void setCallRestriction(CallRestriction restriction);
+
private:
friend class IPCThreadState;
@@ -123,6 +135,8 @@
String8 mRootDir;
bool mThreadPoolStarted;
volatile int32_t mThreadPoolSeq;
+
+ CallRestriction mCallRestriction;
};
}; // namespace android
diff --git a/libs/binder/include/binder/binder_kernel.h b/libs/binder/include/binder/binder_kernel.h
new file mode 100644
index 0000000..c7f6b4b
--- /dev/null
+++ b/libs/binder/include/binder/binder_kernel.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_BINDER_KERNEL_H
+#define ANDROID_BINDER_KERNEL_H
+
+#include <linux/android/binder.h>
+
+/**
+ * This file exists because the uapi kernel headers in bionic are built
+ * from upstream kernel headers only, and not all of the hwbinder kernel changes
+ * have made it upstream yet. Therefore, the modifications to the
+ * binder header are added locally in this file.
+ */
+
+enum {
+ FLAT_BINDER_FLAG_TXN_SECURITY_CTX = 0x1000,
+};
+
+#define BINDER_SET_CONTEXT_MGR_EXT _IOW('b', 13, struct flat_binder_object)
+
+struct binder_transaction_data_secctx {
+ struct binder_transaction_data transaction_data;
+ binder_uintptr_t secctx;
+};
+
+enum {
+ BR_TRANSACTION_SEC_CTX = _IOR('r', 2,
+ struct binder_transaction_data_secctx),
+};
+
+#endif // ANDROID_BINDER_KERNEL_H
diff --git a/libs/binder/ndk/Android.bp b/libs/binder/ndk/Android.bp
index 1b69dfd..68011bb 100644
--- a/libs/binder/ndk/Android.bp
+++ b/libs/binder/ndk/Android.bp
@@ -23,7 +23,11 @@
"include_apex",
],
- cflags: ["-Wall", "-Wextra", "-Werror"],
+ cflags: [
+ "-Wall",
+ "-Wextra",
+ "-Werror",
+ ],
srcs: [
"ibinder.cpp",
@@ -35,12 +39,17 @@
],
shared_libs: [
- "libandroid_runtime",
"libbase",
"libbinder",
"libutils",
],
+ required: [
+ // libbinder_ndk may be used by Java and non-Java things. When lower-level things use it,
+ // they shouldn't have to take on the cost of loading libandroid_runtime.
+ "libandroid_runtime",
+ ],
+
version_script: "libbinder_ndk.map.txt",
stubs: {
symbol_file: "libbinder_ndk.map.txt",
@@ -56,12 +65,10 @@
"include_ndk/android/*.h",
],
license: "NOTICE",
- draft: true,
}
ndk_library {
name: "libbinder_ndk",
symbol_file: "libbinder_ndk.map.txt",
first_version: "29",
- draft: true,
}
diff --git a/libs/binder/ndk/ibinder_jni.cpp b/libs/binder/ndk/ibinder_jni.cpp
index baea2e8..4a31080 100644
--- a/libs/binder/ndk/ibinder_jni.cpp
+++ b/libs/binder/ndk/ibinder_jni.cpp
@@ -17,15 +17,68 @@
#include <android/binder_ibinder_jni.h>
#include "ibinder_internal.h"
-#include <android_util_Binder.h>
+#include <android-base/logging.h>
+#include <binder/IBinder.h>
+
+#include <mutex>
+
+#include <dlfcn.h>
using ::android::IBinder;
-using ::android::ibinderForJavaObject;
-using ::android::javaObjectForIBinder;
using ::android::sp;
+struct LazyAndroidRuntime {
+ typedef sp<IBinder> (*FromJava)(JNIEnv* env, jobject obj);
+ typedef jobject (*ToJava)(JNIEnv* env, const sp<IBinder>& val);
+
+ static FromJava ibinderForJavaObject;
+ static ToJava javaObjectForIBinder;
+
+ static void load() {
+ std::call_once(mLoadFlag, []() {
+ void* handle = dlopen("libandroid_runtime.so", RTLD_LAZY);
+ if (handle == nullptr) {
+ LOG(WARNING) << "Could not open libandroid_runtime.";
+ return;
+ }
+
+ ibinderForJavaObject = reinterpret_cast<FromJava>(
+ dlsym(handle, "_ZN7android20ibinderForJavaObjectEP7_JNIEnvP8_jobject"));
+ if (ibinderForJavaObject == nullptr) {
+ LOG(WARNING) << "Could not find ibinderForJavaObject.";
+ // no return
+ }
+
+ javaObjectForIBinder = reinterpret_cast<ToJava>(dlsym(
+ handle, "_ZN7android20javaObjectForIBinderEP7_JNIEnvRKNS_2spINS_7IBinderEEE"));
+ if (javaObjectForIBinder == nullptr) {
+ LOG(WARNING) << "Could not find javaObjectForIBinder.";
+ // no return
+ }
+ });
+ }
+
+ private:
+ static std::once_flag mLoadFlag;
+
+ LazyAndroidRuntime(){};
+};
+
+LazyAndroidRuntime::FromJava LazyAndroidRuntime::ibinderForJavaObject = nullptr;
+LazyAndroidRuntime::ToJava LazyAndroidRuntime::javaObjectForIBinder = nullptr;
+std::once_flag LazyAndroidRuntime::mLoadFlag;
+
AIBinder* AIBinder_fromJavaBinder(JNIEnv* env, jobject binder) {
- sp<IBinder> ibinder = ibinderForJavaObject(env, binder);
+ if (binder == nullptr) {
+ return nullptr;
+ }
+
+ LazyAndroidRuntime::load();
+ if (LazyAndroidRuntime::ibinderForJavaObject == nullptr) {
+ return nullptr;
+ }
+
+ sp<IBinder> ibinder = (LazyAndroidRuntime::ibinderForJavaObject)(env, binder);
sp<AIBinder> cbinder = ABpBinder::lookupOrCreateFromBinder(ibinder);
AIBinder_incStrong(cbinder.get());
@@ -38,5 +91,10 @@
return nullptr;
}
- return javaObjectForIBinder(env, binder->getBinder());
+ LazyAndroidRuntime::load();
+ if (LazyAndroidRuntime::javaObjectForIBinder == nullptr) {
+ return nullptr;
+ }
+
+ return (LazyAndroidRuntime::javaObjectForIBinder)(env, binder->getBinder());
}
diff --git a/libs/binder/ndk/include_ndk/android/binder_auto_utils.h b/libs/binder/ndk/include_ndk/android/binder_auto_utils.h
index 80773f3..c6868b0 100644
--- a/libs/binder/ndk/include_ndk/android/binder_auto_utils.h
+++ b/libs/binder/ndk/include_ndk/android/binder_auto_utils.h
@@ -109,6 +109,8 @@
AIBinder* mBinder = nullptr;
};
+namespace impl {
+
/**
* This baseclass owns a single object, used to make various classes RAII.
*/
@@ -169,10 +171,12 @@
T mT;
};
+} // namespace impl
+
/**
* Convenience wrapper. See AParcel.
*/
-class ScopedAParcel : public ScopedAResource<AParcel*, void, AParcel_delete, nullptr> {
+class ScopedAParcel : public impl::ScopedAResource<AParcel*, void, AParcel_delete, nullptr> {
public:
/**
* Takes ownership of a.
@@ -185,7 +189,7 @@
/**
* Convenience wrapper. See AStatus.
*/
-class ScopedAStatus : public ScopedAResource<AStatus*, void, AStatus_delete, nullptr> {
+class ScopedAStatus : public impl::ScopedAResource<AStatus*, void, AStatus_delete, nullptr> {
public:
/**
* Takes ownership of a.
@@ -209,8 +213,8 @@
* Convenience wrapper. See AIBinder_DeathRecipient.
*/
class ScopedAIBinder_DeathRecipient
- : public ScopedAResource<AIBinder_DeathRecipient*, void, AIBinder_DeathRecipient_delete,
- nullptr> {
+ : public impl::ScopedAResource<AIBinder_DeathRecipient*, void, AIBinder_DeathRecipient_delete,
+ nullptr> {
public:
/**
* Takes ownership of a.
@@ -225,7 +229,7 @@
* Convenience wrapper. See AIBinder_Weak.
*/
class ScopedAIBinder_Weak
- : public ScopedAResource<AIBinder_Weak*, void, AIBinder_Weak_delete, nullptr> {
+ : public impl::ScopedAResource<AIBinder_Weak*, void, AIBinder_Weak_delete, nullptr> {
public:
/**
* Takes ownership of a.
@@ -243,7 +247,7 @@
/**
* Convenience wrapper for a file descriptor.
*/
-class ScopedFileDescriptor : public ScopedAResource<int, int, close, -1> {
+class ScopedFileDescriptor : public impl::ScopedAResource<int, int, close, -1> {
public:
/**
* Takes ownership of a.
diff --git a/libs/binder/ndk/libbinder_ndk.map.txt b/libs/binder/ndk/libbinder_ndk.map.txt
index ee7132f..f0d25f7 100644
--- a/libs/binder/ndk/libbinder_ndk.map.txt
+++ b/libs/binder/ndk/libbinder_ndk.map.txt
@@ -87,6 +87,11 @@
AStatus_getStatus;
AStatus_isOk;
AStatus_newOk;
+ ABinderProcess_joinThreadPool; # apex
+ ABinderProcess_setThreadPoolMaxThreadCount; # apex
+ ABinderProcess_startThreadPool; # apex
+ AServiceManager_addService; # apex
+ AServiceManager_getService; # apex
local:
*;
};
diff --git a/libs/binder/ndk/scripts/init_map.sh b/libs/binder/ndk/scripts/init_map.sh
index 1f74e43..3529b72 100755
--- a/libs/binder/ndk/scripts/init_map.sh
+++ b/libs/binder/ndk/scripts/init_map.sh
@@ -10,6 +10,10 @@
grep -oP "AParcel_[a-zA-Z0-9_]+(?=\()" include_ndk/android/binder_parcel.h;
grep -oP "AStatus_[a-zA-Z0-9_]+(?=\()" include_ndk/android/binder_status.h;
} | sort | uniq | awk '{ print " " $0 ";"; }'
+{
+ grep -oP "AServiceManager_[a-zA-Z0-9_]+(?=\()" include_apex/android/binder_manager.h;
+ grep -oP "ABinderProcess_[a-zA-Z0-9_]+(?=\()" include_apex/android/binder_process.h;
+} | sort | uniq | awk '{ print " " $0 "; # apex"; }'
echo " local:"
echo " *;"
echo "};"
diff --git a/libs/cputimeinstate/Android.bp b/libs/cputimeinstate/Android.bp
new file mode 100644
index 0000000..28cb138
--- /dev/null
+++ b/libs/cputimeinstate/Android.bp
@@ -0,0 +1,30 @@
+cc_library {
+ name: "libtimeinstate",
+ srcs: ["cputimeinstate.cpp"],
+ shared_libs: [
+ "libbase",
+ "libbpf",
+ "libbpf_android",
+ "liblog",
+ "libnetdutils"
+ ],
+ cflags: [
+ "-Werror",
+ "-Wall",
+ "-Wextra",
+ ],
+}
+
+cc_test {
+ name: "libtimeinstate_test",
+ srcs: ["testtimeinstate.cpp"],
+ shared_libs: [
+ "libtimeinstate",
+ ],
+ cflags: [
+ "-Werror",
+ "-Wall",
+ "-Wextra",
+ ],
+}
+
diff --git a/libs/cputimeinstate/cputimeinstate.cpp b/libs/cputimeinstate/cputimeinstate.cpp
new file mode 100644
index 0000000..4cddf94
--- /dev/null
+++ b/libs/cputimeinstate/cputimeinstate.cpp
@@ -0,0 +1,262 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "libtimeinstate"
+
+#include "cputimeinstate.h"
+
+#include <dirent.h>
+#include <errno.h>
+#include <inttypes.h>
+
+#include <mutex>
+#include <set>
+#include <string>
+#include <unordered_map>
+#include <vector>
+
+#include <android-base/file.h>
+#include <android-base/parseint.h>
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
+#include <android-base/unique_fd.h>
+#include <bpf/BpfMap.h>
+#include <libbpf.h>
+#include <log/log.h>
+
+#define BPF_FS_PATH "/sys/fs/bpf/"
+
+using android::base::StringPrintf;
+using android::base::unique_fd;
+
+namespace android {
+namespace bpf {
+
+typedef struct {
+ uint32_t uid;
+ uint32_t freq;
+} time_key_t;
+
+typedef struct {
+ uint64_t ar[100];
+} val_t;
+
+static std::mutex gInitializedMutex;
+static bool gInitialized = false;
+static uint32_t gNPolicies = 0;
+static std::vector<std::vector<uint32_t>> gPolicyFreqs;
+static std::vector<std::vector<uint32_t>> gPolicyCpus;
+static std::set<uint32_t> gAllFreqs;
+static unique_fd gMapFd;
+
+static bool readNumbersFromFile(const std::string &path, std::vector<uint32_t> *out) {
+ std::string data;
+
+ if (!android::base::ReadFileToString(path, &data)) {
+ ALOGD("Failed to read file %s", path.c_str());
+ return false;
+ }
+
+ auto strings = android::base::Split(data, " \n");
+ for (const auto &s : strings) {
+ if (s.empty()) continue;
+ uint32_t n;
+ if (!android::base::ParseUint(s, &n)) {
+ ALOGD("Failed to parse file %s", path.c_str());
+ return false;
+ }
+ out->emplace_back(n);
+ }
+ return true;
+}
+
+static int isPolicyFile(const struct dirent *d) {
+ return android::base::StartsWith(d->d_name, "policy");
+}
+
+static int comparePolicyFiles(const struct dirent **d1, const struct dirent **d2) {
+ uint32_t policyN1, policyN2;
+ if (sscanf((*d1)->d_name, "policy%" SCNu32 "", &policyN1) != 1 ||
+ sscanf((*d2)->d_name, "policy%" SCNu32 "", &policyN2) != 1)
+ return 0;
+ return policyN1 - policyN2;
+}
+
+static bool initGlobals() {
+ std::lock_guard<std::mutex> guard(gInitializedMutex);
+ if (gInitialized) return true;
+
+ struct dirent **dirlist;
+ const char basepath[] = "/sys/devices/system/cpu/cpufreq";
+ int ret = scandir(basepath, &dirlist, isPolicyFile, comparePolicyFiles);
+ if (ret == -1) return false;
+ gNPolicies = ret;
+
+ std::vector<std::string> policyFileNames;
+ for (uint32_t i = 0; i < gNPolicies; ++i) {
+ policyFileNames.emplace_back(dirlist[i]->d_name);
+ free(dirlist[i]);
+ }
+ free(dirlist);
+
+ for (const auto &policy : policyFileNames) {
+ std::vector<uint32_t> freqs;
+ for (const auto &name : {"available", "boost"}) {
+ std::string path =
+ StringPrintf("%s/%s/scaling_%s_frequencies", basepath, policy.c_str(), name);
+ if (!readNumbersFromFile(path, &freqs)) return false;
+ }
+ std::sort(freqs.begin(), freqs.end());
+ gPolicyFreqs.emplace_back(freqs);
+
+ for (auto freq : freqs) gAllFreqs.insert(freq);
+
+ std::vector<uint32_t> cpus;
+ std::string path = StringPrintf("%s/%s/%s", basepath, policy.c_str(), "related_cpus");
+ if (!readNumbersFromFile(path, &cpus)) return false;
+ gPolicyCpus.emplace_back(cpus);
+ }
+
+ gMapFd = unique_fd{bpf_obj_get(BPF_FS_PATH "map_time_in_state_uid_times")};
+ if (gMapFd < 0) return false;
+
+ gInitialized = true;
+ return true;
+}
+
+static bool attachTracepointProgram(const std::string &eventType, const std::string &eventName) {
+ std::string path = StringPrintf(BPF_FS_PATH "prog_time_in_state_tracepoint_%s_%s",
+ eventType.c_str(), eventName.c_str());
+ int prog_fd = bpf_obj_get(path.c_str());
+ if (prog_fd < 0) {
+ ALOGD("bpf_obj_get() failed for program %s", path.c_str());
+ return false;
+ }
+ if (bpf_attach_tracepoint(prog_fd, eventType.c_str(), eventName.c_str()) < 0) {
+ ALOGD("Failed to attach bpf program to tracepoint %s/%s", eventType.c_str(),
+ eventName.c_str());
+ return false;
+ }
+ return true;
+}
+
+// Start tracking and aggregating data to be reported by getUidCpuFreqTimes and getUidsCpuFreqTimes.
+// Returns true on success, false otherwise.
+// Tracking is active only once a live process has successfully called this function; if the calling
+// process dies then it must be called again to resume tracking.
+// This function should *not* be called while tracking is already active; doing so is unnecessary
+// and can lead to accounting errors.
+bool startTrackingUidCpuFreqTimes() {
+ return attachTracepointProgram("sched", "sched_switch") &&
+ attachTracepointProgram("power", "cpu_frequency");
+}
+
+// Retrieve the times in ns that uid spent running at each CPU frequency and store in freqTimes.
+// Returns false on error. Otherwise, returns true and populates freqTimes with a vector of vectors
+// using the format:
+// [[t0_0, t0_1, ...],
+// [t1_0, t1_1, ...], ...]
+// where ti_j is the ns that uid spent running on the ith cluster at that cluster's jth lowest freq.
+bool getUidCpuFreqTimes(uint32_t uid, std::vector<std::vector<uint64_t>> *freqTimes) {
+ if (!gInitialized && !initGlobals()) return false;
+ time_key_t key = {.uid = uid, .freq = 0};
+
+ freqTimes->clear();
+ freqTimes->resize(gNPolicies);
+ std::vector<uint32_t> idxs(gNPolicies, 0);
+
+ val_t value;
+ for (uint32_t freq : gAllFreqs) {
+ key.freq = freq;
+ int ret = findMapEntry(gMapFd, &key, &value);
+ if (ret) {
+ if (errno == ENOENT)
+ memset(&value.ar, 0, sizeof(value.ar));
+ else
+ return false;
+ }
+ for (uint32_t i = 0; i < gNPolicies; ++i) {
+ if (idxs[i] == gPolicyFreqs[i].size() || freq != gPolicyFreqs[i][idxs[i]]) continue;
+ uint64_t time = 0;
+ for (uint32_t cpu : gPolicyCpus[i]) time += value.ar[cpu];
+ idxs[i] += 1;
+ (*freqTimes)[i].emplace_back(time);
+ }
+ }
+
+ return true;
+}
+
+// Retrieve the times in ns that each uid spent running at each CPU freq and store in freqTimeMap.
+// Returns false on error. Otherwise, returns true and populates freqTimeMap with a map from uids to
+// vectors of vectors using the format:
+// { uid0 -> [[t0_0_0, t0_0_1, ...], [t0_1_0, t0_1_1, ...], ...],
+// uid1 -> [[t1_0_0, t1_0_1, ...], [t1_1_0, t1_1_1, ...], ...], ... }
+// where ti_j_k is the ns uid i spent running on the jth cluster at the cluster's kth lowest freq.
+bool getUidsCpuFreqTimes(
+ std::unordered_map<uint32_t, std::vector<std::vector<uint64_t>>> *freqTimeMap) {
+ if (!gInitialized && !initGlobals()) return false;
+
+ int fd = bpf_obj_get(BPF_FS_PATH "map_time_in_state_uid_times");
+ if (fd < 0) return false;
+ BpfMap<time_key_t, val_t> m(fd);
+
+ std::vector<std::unordered_map<uint32_t, uint32_t>> policyFreqIdxs;
+ for (uint32_t i = 0; i < gNPolicies; ++i) {
+ std::unordered_map<uint32_t, uint32_t> freqIdxs;
+ for (size_t j = 0; j < gPolicyFreqs[i].size(); ++j) freqIdxs[gPolicyFreqs[i][j]] = j;
+ policyFreqIdxs.emplace_back(freqIdxs);
+ }
+
+ auto fn = [freqTimeMap, &policyFreqIdxs](const time_key_t &key, const val_t &val,
+ const BpfMap<time_key_t, val_t> &) {
+ if (freqTimeMap->find(key.uid) == freqTimeMap->end()) {
+ std::vector<std::vector<uint64_t>> v;
+ for (uint32_t i = 0; i < gNPolicies; ++i) {
+ std::vector<uint64_t> v2(gPolicyFreqs[i].size(), 0);
+ v.emplace_back(v2);
+ }
+ (*freqTimeMap)[key.uid] = v;
+ }
+
+ for (size_t policy = 0; policy < gNPolicies; ++policy) {
+ for (const auto &cpu : gPolicyCpus[policy]) {
+ uint32_t cpuTime = val.ar[cpu];
+ if (cpuTime == 0) continue;
+ auto freqIdx = policyFreqIdxs[policy][key.freq];
+ (*freqTimeMap)[key.uid][policy][freqIdx] += cpuTime;
+ }
+ }
+ return android::netdutils::status::ok;
+ };
+ return isOk(m.iterateWithValue(fn));
+}
+
+// Clear all time in state data for a given uid. Returns false on error, true otherwise.
+bool clearUidCpuFreqTimes(uint32_t uid) {
+ if (!gInitialized && !initGlobals()) return false;
+ time_key_t key = {.uid = uid, .freq = 0};
+
+ std::vector<uint32_t> idxs(gNPolicies, 0);
+ for (auto freq : gAllFreqs) {
+ key.freq = freq;
+ if (deleteMapEntry(gMapFd, &key) && errno != ENOENT) return false;
+ }
+ return true;
+}
+
+} // namespace bpf
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplaySurface.cpp b/libs/cputimeinstate/cputimeinstate.h
similarity index 64%
copy from services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplaySurface.cpp
copy to libs/cputimeinstate/cputimeinstate.h
index e6ac6bf..0205452 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplaySurface.cpp
+++ b/libs/cputimeinstate/cputimeinstate.h
@@ -14,14 +14,16 @@
* limitations under the License.
*/
-#include "mock/DisplayHardware/MockDisplaySurface.h"
+#include <unordered_map>
+#include <vector>
namespace android {
-namespace mock {
+namespace bpf {
-// Explicit default instantiation is recommended.
-DisplaySurface::DisplaySurface() = default;
-DisplaySurface::~DisplaySurface() = default;
+bool startTrackingUidCpuFreqTimes();
+bool getUidCpuFreqTimes(unsigned int uid, std::vector<std::vector<uint64_t>> *freqTimes);
+bool getUidsCpuFreqTimes(std::unordered_map<uint32_t, std::vector<std::vector<uint64_t>>> *tisMap);
+bool clearUidCpuFreqTimes(unsigned int uid);
-} // namespace mock
+} // namespace bpf
} // namespace android
diff --git a/libs/cputimeinstate/testtimeinstate.cpp b/libs/cputimeinstate/testtimeinstate.cpp
new file mode 100644
index 0000000..9837865
--- /dev/null
+++ b/libs/cputimeinstate/testtimeinstate.cpp
@@ -0,0 +1,58 @@
+
+#include <unordered_map>
+#include <vector>
+
+#include <gtest/gtest.h>
+
+#include <cputimeinstate.h>
+
+namespace android {
+namespace bpf {
+
+using std::vector;
+
+TEST(TimeInStateTest, SingleUid) {
+ vector<vector<uint64_t>> times;
+ ASSERT_TRUE(getUidCpuFreqTimes(0, ×));
+ EXPECT_FALSE(times.empty());
+}
+
+TEST(TimeInStateTest, AllUid) {
+ vector<size_t> sizes;
+ std::unordered_map<uint32_t, vector<vector<uint64_t>>> map;
+ ASSERT_TRUE(getUidsCpuFreqTimes(&map));
+
+ ASSERT_FALSE(map.empty());
+
+ auto firstEntry = map.begin()->second;
+ for (const auto &subEntry : firstEntry) sizes.emplace_back(subEntry.size());
+
+ for (const auto &vec : map) {
+ ASSERT_EQ(vec.second.size(), sizes.size());
+ for (size_t i = 0; i < vec.second.size(); ++i) ASSERT_EQ(vec.second[i].size(), sizes[i]);
+ }
+}
+
+TEST(TimeInStateTest, RemoveUid) {
+ vector<vector<uint64_t>> times, times2;
+ ASSERT_TRUE(getUidCpuFreqTimes(0, ×));
+ ASSERT_FALSE(times.empty());
+
+ uint64_t sum = 0;
+ for (size_t i = 0; i < times.size(); ++i) {
+ for (auto x : times[i]) sum += x;
+ }
+ ASSERT_GT(sum, (uint64_t)0);
+
+ ASSERT_TRUE(clearUidCpuFreqTimes(0));
+
+ ASSERT_TRUE(getUidCpuFreqTimes(0, ×2));
+ ASSERT_EQ(times2.size(), times.size());
+ for (size_t i = 0; i < times.size(); ++i) {
+ ASSERT_EQ(times2[i].size(), times[i].size());
+ for (size_t j = 0; j < times[i].size(); ++j) ASSERT_LE(times2[i][j], times[i][j]);
+ }
+}
+
+} // namespace bpf
+} // namespace android
diff --git a/libs/graphicsenv/GraphicsEnv.cpp b/libs/graphicsenv/GraphicsEnv.cpp
index 9dc7431..b8c6cfe 100644
--- a/libs/graphicsenv/GraphicsEnv.cpp
+++ b/libs/graphicsenv/GraphicsEnv.cpp
@@ -30,7 +30,6 @@
#include <sys/prctl.h>
#include <memory>
-#include <mutex>
#include <string>
#include <dlfcn.h>
@@ -262,7 +261,7 @@
bool GraphicsEnv::shouldUseAngle() {
// Make sure we are init'ed
if (mAngleAppName.empty()) {
- ALOGE("App name is empty. setAngleInfo() must be called first to enable ANGLE.");
+ ALOGV("App name is empty. setAngleInfo() has not been called to enable ANGLE.");
return false;
}
@@ -284,16 +283,7 @@
} else {
// The "Developer Options" value wasn't set to force the use of ANGLE. Need to temporarily
// load ANGLE and call the updatable opt-in/out logic:
-
- // Check if ANGLE is enabled. Workaround for several bugs:
- // b/119305693 b/119322355 b/119305887
- // Something is not working correctly in the feature library
- char prop[PROPERTY_VALUE_MAX];
- property_get("debug.angle.enable", prop, "0");
- void* featureSo = nullptr;
- if (atoi(prop)) {
- featureSo = loadLibrary("feature_support");
- }
+ void* featureSo = loadLibrary("feature_support");
if (featureSo) {
ALOGV("loaded ANGLE's opt-in/out logic from namespace");
mUseAngle = checkAngleRules(featureSo);
@@ -415,19 +405,26 @@
}
android_namespace_t* GraphicsEnv::getAngleNamespace() {
- static std::once_flag once;
- std::call_once(once, [this]() {
- if (mAnglePath.empty()) return;
+ std::lock_guard<std::mutex> lock(mNamespaceMutex);
- mAngleNamespace = android_create_namespace("ANGLE",
- nullptr, // ld_library_path
- mAnglePath.c_str(), // default_library_path
- ANDROID_NAMESPACE_TYPE_SHARED |
- ANDROID_NAMESPACE_TYPE_ISOLATED,
- nullptr, // permitted_when_isolated_path
- nullptr);
- if (!mAngleNamespace) ALOGD("Could not create ANGLE namespace from default");
- });
+ if (mAngleNamespace) {
+ return mAngleNamespace;
+ }
+
+ if (mAnglePath.empty()) {
+ ALOGV("mAnglePath is empty, not creating ANGLE namespace");
+ return nullptr;
+ }
+
+ mAngleNamespace = android_create_namespace("ANGLE",
+ nullptr, // ld_library_path
+ mAnglePath.c_str(), // default_library_path
+ ANDROID_NAMESPACE_TYPE_SHARED |
+ ANDROID_NAMESPACE_TYPE_ISOLATED,
+ nullptr, // permitted_when_isolated_path
+ nullptr);
+
+ ALOGD_IF(!mAngleNamespace, "Could not create ANGLE namespace from default");
return mAngleNamespace;
}
diff --git a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
index 37c24ef..ed08882 100644
--- a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
+++ b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
@@ -17,6 +17,7 @@
#ifndef ANDROID_UI_GRAPHICS_ENV_H
#define ANDROID_UI_GRAPHICS_ENV_H 1
+#include <mutex>
#include <string>
#include <vector>
@@ -24,7 +25,7 @@
namespace android {
-class NativeLoaderNamespace;
+struct NativeLoaderNamespace;
class GraphicsEnv {
public:
@@ -77,6 +78,7 @@
std::string mDebugLayers;
std::string mDebugLayersGLES;
std::string mLayerPaths;
+ std::mutex mNamespaceMutex;
android_namespace_t* mDriverNamespace = nullptr;
android_namespace_t* mAngleNamespace = nullptr;
NativeLoaderNamespace* mAppNamespace = nullptr;
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp
index d1c732b..f40eb6c 100644
--- a/libs/gui/Android.bp
+++ b/libs/gui/Android.bp
@@ -108,6 +108,7 @@
"ISurfaceComposerClient.cpp",
"ITransactionCompletedListener.cpp",
"LayerDebugInfo.cpp",
+ "LayerMetadata.cpp",
"LayerState.cpp",
"OccupancyTracker.cpp",
"StreamSplitter.cpp",
@@ -121,6 +122,7 @@
],
shared_libs: [
+ "android.frameworks.bufferhub@1.0",
"android.hardware.graphics.common@1.1",
"libbase",
"libsync",
@@ -140,8 +142,6 @@
"libhidltransport",
"android.hidl.token@1.0-utils",
"android.hardware.graphics.bufferqueue@1.0",
- "android.hardware.configstore@1.0",
- "android.hardware.configstore-utils",
],
// bufferhub is not used when building libgui for vendors
@@ -153,6 +153,7 @@
"BufferHubProducer.cpp",
],
exclude_shared_libs: [
+ "android.frameworks.bufferhub@1.0",
"libbufferhub",
"libbufferhubqueue",
"libpdx_default_transport",
diff --git a/libs/gui/FrameTimestamps.cpp b/libs/gui/FrameTimestamps.cpp
index 96e9a85..c04d907 100644
--- a/libs/gui/FrameTimestamps.cpp
+++ b/libs/gui/FrameTimestamps.cpp
@@ -158,7 +158,7 @@
namespace {
struct FrameNumberEqual {
- FrameNumberEqual(uint64_t frameNumber) : mFrameNumber(frameNumber) {}
+ explicit FrameNumberEqual(uint64_t frameNumber) : mFrameNumber(frameNumber) {}
bool operator()(const FrameEvents& frame) {
return frame.valid && mFrameNumber == frame.frameNumber;
}
diff --git a/libs/gui/IGraphicBufferProducer.cpp b/libs/gui/IGraphicBufferProducer.cpp
index 68a6b1f..d997674 100644
--- a/libs/gui/IGraphicBufferProducer.cpp
+++ b/libs/gui/IGraphicBufferProducer.cpp
@@ -536,7 +536,7 @@
class HpGraphicBufferProducer : public HpInterface<
BpGraphicBufferProducer, H2BGraphicBufferProducer> {
public:
- HpGraphicBufferProducer(const sp<IBinder>& base) : PBase(base) {}
+ explicit HpGraphicBufferProducer(const sp<IBinder>& base) : PBase(base) {}
status_t requestBuffer(int slot, sp<GraphicBuffer>* buf) override {
return mBase->requestBuffer(slot, buf);
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index 799151a..fd30e3b 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -63,19 +63,11 @@
return interface_cast<ISurfaceComposerClient>(reply.readStrongBinder());
}
- virtual sp<ISurfaceComposerClient> createScopedConnection(
- const sp<IGraphicBufferProducer>& parent)
- {
- Parcel data, reply;
- data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
- data.writeStrongBinder(IInterface::asBinder(parent));
- remote()->transact(BnSurfaceComposer::CREATE_SCOPED_CONNECTION, data, &reply);
- return interface_cast<ISurfaceComposerClient>(reply.readStrongBinder());
- }
-
virtual void setTransactionState(const Vector<ComposerState>& state,
const Vector<DisplayState>& displays, uint32_t flags,
- const sp<IBinder>& applyToken) {
+ const sp<IBinder>& applyToken,
+ const InputWindowCommands& commands,
+ int64_t desiredPresentTime) {
Parcel data, reply;
data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
@@ -91,6 +83,8 @@
data.writeUint32(flags);
data.writeStrongBinder(applyToken);
+ commands.write(data);
+ data.writeInt64(desiredPresentTime);
remote()->transact(BnSurfaceComposer::SET_TRANSACTION_STATE, data, &reply);
}
@@ -401,6 +395,32 @@
return result;
}
+ virtual status_t getDisplayNativePrimaries(const sp<IBinder>& display,
+ ui::DisplayPrimaries& primaries) {
+ Parcel data, reply;
+ status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+ if (result != NO_ERROR) {
+ ALOGE("getDisplayNativePrimaries failed to writeInterfaceToken: %d", result);
+ return result;
+ }
+ result = data.writeStrongBinder(display);
+ if (result != NO_ERROR) {
+ ALOGE("getDisplayNativePrimaries failed to writeStrongBinder: %d", result);
+ return result;
+ }
+ result = remote()->transact(BnSurfaceComposer::GET_DISPLAY_NATIVE_PRIMARIES, data, &reply);
+ if (result != NO_ERROR) {
+ ALOGE("getDisplayNativePrimaries failed to transact: %d", result);
+ return result;
+ }
+ result = reply.readInt32();
+ if (result == NO_ERROR) {
+ memcpy(&primaries, reply.readInplace(sizeof(ui::DisplayPrimaries)),
+ sizeof(ui::DisplayPrimaries));
+ }
+ return result;
+ }
+
virtual ColorMode getActiveColorMode(const sp<IBinder>& display) {
Parcel data, reply;
status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
@@ -689,6 +709,38 @@
result = reply.readUint64Vector(&outStats->component_3_sample);
return result;
}
+
+ virtual status_t getProtectedContentSupport(bool* outSupported) const {
+ Parcel data, reply;
+ data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+ status_t error =
+ remote()->transact(BnSurfaceComposer::GET_PROTECTED_CONTENT_SUPPORT, data, &reply);
+ if (error != NO_ERROR) {
+ return error;
+ }
+ error = reply.readBool(outSupported);
+ return error;
+ }
+
+ virtual status_t isWideColorDisplay(const sp<IBinder>& token,
+ bool* outIsWideColorDisplay) const {
+ Parcel data, reply;
+ status_t error = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+ if (error != NO_ERROR) {
+ return error;
+ }
+ error = data.writeStrongBinder(token);
+ if (error != NO_ERROR) {
+ return error;
+ }
+
+ error = remote()->transact(BnSurfaceComposer::IS_WIDE_COLOR_DISPLAY, data, &reply);
+ if (error != NO_ERROR) {
+ return error;
+ }
+ error = reply.readBool(outIsWideColorDisplay);
+ return error;
+ }
};
// Out-of-line virtual method definition to trigger vtable emission in this
@@ -709,14 +761,6 @@
reply->writeStrongBinder(b);
return NO_ERROR;
}
- case CREATE_SCOPED_CONNECTION: {
- CHECK_INTERFACE(ISurfaceComposer, data, reply);
- sp<IGraphicBufferProducer> bufferProducer =
- interface_cast<IGraphicBufferProducer>(data.readStrongBinder());
- sp<IBinder> b = IInterface::asBinder(createScopedConnection(bufferProducer));
- reply->writeStrongBinder(b);
- return NO_ERROR;
- }
case SET_TRANSACTION_STATE: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
@@ -750,7 +794,12 @@
uint32_t stateFlags = data.readUint32();
sp<IBinder> applyToken = data.readStrongBinder();
- setTransactionState(state, displays, stateFlags, applyToken);
+ InputWindowCommands inputWindowCommands;
+ inputWindowCommands.read(data);
+
+ int64_t desiredPresentTime = data.readInt64();
+ setTransactionState(state, displays, stateFlags, applyToken, inputWindowCommands,
+ desiredPresentTime);
return NO_ERROR;
}
case BOOT_FINISHED: {
@@ -915,6 +964,26 @@
}
return NO_ERROR;
}
+ case GET_DISPLAY_NATIVE_PRIMARIES: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
+ ui::DisplayPrimaries primaries;
+ sp<IBinder> display = nullptr;
+
+ status_t result = data.readStrongBinder(&display);
+ if (result != NO_ERROR) {
+ ALOGE("getDisplayNativePrimaries failed to readStrongBinder: %d", result);
+ return result;
+ }
+
+ result = getDisplayNativePrimaries(display, primaries);
+ reply->writeInt32(result);
+ if (result == NO_ERROR) {
+ memcpy(reply->writeInplace(sizeof(ui::DisplayPrimaries)), &primaries,
+ sizeof(ui::DisplayPrimaries));
+ }
+
+ return NO_ERROR;
+ }
case GET_ACTIVE_COLOR_MODE: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
sp<IBinder> display = nullptr;
@@ -1031,7 +1100,7 @@
reply->writeInt32(static_cast<int32_t>(wideColorGamutDataspace));
reply->writeInt32(static_cast<int32_t>(wideColorGamutPixelFormat));
}
- return NO_ERROR;
+ return error;
}
case GET_COLOR_MANAGEMENT: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
@@ -1040,7 +1109,7 @@
if (error == NO_ERROR) {
reply->writeBool(result);
}
- return result;
+ return error;
}
case GET_DISPLAYED_CONTENT_SAMPLING_ATTRIBUTES: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
@@ -1124,6 +1193,29 @@
}
return result;
}
+ case GET_PROTECTED_CONTENT_SUPPORT: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
+ bool result;
+ status_t error = getProtectedContentSupport(&result);
+ if (error == NO_ERROR) {
+ reply->writeBool(result);
+ }
+ return error;
+ }
+ case IS_WIDE_COLOR_DISPLAY: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
+ sp<IBinder> display = nullptr;
+ status_t error = data.readStrongBinder(&display);
+ if (error != NO_ERROR) {
+ return error;
+ }
+ bool result;
+ error = isWideColorDisplay(display, &result);
+ if (error == NO_ERROR) {
+ reply->writeBool(result);
+ }
+ return error;
+ }
default: {
return BBinder::onTransact(code, data, reply, flags);
}
diff --git a/libs/gui/ISurfaceComposerClient.cpp b/libs/gui/ISurfaceComposerClient.cpp
index a6890ee..129558b 100644
--- a/libs/gui/ISurfaceComposerClient.cpp
+++ b/libs/gui/ISurfaceComposerClient.cpp
@@ -31,7 +31,7 @@
enum class Tag : uint32_t {
CREATE_SURFACE = IBinder::FIRST_CALL_TRANSACTION,
- DESTROY_SURFACE,
+ CREATE_WITH_SURFACE_PARENT,
CLEAR_LAYER_FRAME_STATS,
GET_LAYER_FRAME_STATS,
LAST = GET_LAYER_FRAME_STATS,
@@ -47,19 +47,26 @@
~BpSurfaceComposerClient() override;
status_t createSurface(const String8& name, uint32_t width, uint32_t height, PixelFormat format,
- uint32_t flags, const sp<IBinder>& parent, int32_t windowType,
- int32_t ownerUid, sp<IBinder>* handle,
- sp<IGraphicBufferProducer>* gbp) override {
+ uint32_t flags, const sp<IBinder>& parent, LayerMetadata metadata,
+ sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp) override {
return callRemote<decltype(&ISurfaceComposerClient::createSurface)>(Tag::CREATE_SURFACE,
name, width, height,
format, flags, parent,
- windowType, ownerUid,
+ std::move(metadata),
handle, gbp);
}
- status_t destroySurface(const sp<IBinder>& handle) override {
- return callRemote<decltype(&ISurfaceComposerClient::destroySurface)>(Tag::DESTROY_SURFACE,
- handle);
+ status_t createWithSurfaceParent(const String8& name, uint32_t width, uint32_t height,
+ PixelFormat format, uint32_t flags,
+ const sp<IGraphicBufferProducer>& parent,
+ LayerMetadata metadata, sp<IBinder>* handle,
+ sp<IGraphicBufferProducer>* gbp) override {
+ return callRemote<decltype(
+ &ISurfaceComposerClient::createWithSurfaceParent)>(Tag::CREATE_WITH_SURFACE_PARENT,
+ name, width, height, format,
+ flags, parent,
+ std::move(metadata), handle,
+ gbp);
}
status_t clearLayerFrameStats(const sp<IBinder>& handle) const override {
@@ -92,8 +99,8 @@
switch (tag) {
case Tag::CREATE_SURFACE:
return callLocal(data, reply, &ISurfaceComposerClient::createSurface);
- case Tag::DESTROY_SURFACE:
- return callLocal(data, reply, &ISurfaceComposerClient::destroySurface);
+ case Tag::CREATE_WITH_SURFACE_PARENT:
+ return callLocal(data, reply, &ISurfaceComposerClient::createWithSurfaceParent);
case Tag::CLEAR_LAYER_FRAME_STATS:
return callLocal(data, reply, &ISurfaceComposerClient::clearLayerFrameStats);
case Tag::GET_LAYER_FRAME_STATS:
diff --git a/libs/gui/ITransactionCompletedListener.cpp b/libs/gui/ITransactionCompletedListener.cpp
index 1be55e6..ce88d7b 100644
--- a/libs/gui/ITransactionCompletedListener.cpp
+++ b/libs/gui/ITransactionCompletedListener.cpp
@@ -39,7 +39,16 @@
if (err != NO_ERROR) {
return err;
}
- return output->writeBool(releasePreviousBuffer);
+ if (previousReleaseFence) {
+ err = output->writeBool(true);
+ if (err != NO_ERROR) {
+ return err;
+ }
+ err = output->write(*previousReleaseFence);
+ } else {
+ err = output->writeBool(false);
+ }
+ return err;
}
status_t SurfaceStats::readFromParcel(const Parcel* input) {
@@ -51,7 +60,19 @@
if (err != NO_ERROR) {
return err;
}
- return input->readBool(&releasePreviousBuffer);
+ bool hasFence = false;
+ err = input->readBool(&hasFence);
+ if (err != NO_ERROR) {
+ return err;
+ }
+ if (hasFence) {
+ previousReleaseFence = new Fence();
+ err = input->read(*previousReleaseFence);
+ if (err != NO_ERROR) {
+ return err;
+ }
+ }
+ return NO_ERROR;
}
status_t TransactionStats::writeToParcel(Parcel* output) const {
diff --git a/libs/gui/LayerMetadata.cpp b/libs/gui/LayerMetadata.cpp
new file mode 100644
index 0000000..745433a
--- /dev/null
+++ b/libs/gui/LayerMetadata.cpp
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/stringprintf.h>
+#include <binder/Parcel.h>
+#include <gui/LayerMetadata.h>
+
+using android::base::StringPrintf;
+
+namespace android {
+
+LayerMetadata::LayerMetadata() = default;
+
+LayerMetadata::LayerMetadata(std::unordered_map<uint32_t, std::vector<uint8_t>> map)
+ : mMap(std::move(map)) {}
+
+LayerMetadata::LayerMetadata(const LayerMetadata& other) = default;
+
+LayerMetadata::LayerMetadata(LayerMetadata&& other) = default;
+
+void LayerMetadata::merge(const LayerMetadata& other) {
+ for (const auto& entry : other.mMap) {
+ mMap[entry.first] = entry.second;
+ }
+}
+
+status_t LayerMetadata::writeToParcel(Parcel* parcel) const {
+ parcel->writeInt32(static_cast<int>(mMap.size()));
+ status_t status = OK;
+ for (const auto& entry : mMap) {
+ status = parcel->writeUint32(entry.first);
+ if (status != OK) {
+ break;
+ }
+ status = parcel->writeByteVector(entry.second);
+ if (status != OK) {
+ break;
+ }
+ }
+ return status;
+}
+
+status_t LayerMetadata::readFromParcel(const Parcel* parcel) {
+ int size = parcel->readInt32();
+ status_t status = OK;
+ mMap.clear();
+ for (int i = 0; i < size; ++i) {
+ uint32_t key = parcel->readUint32();
+ status = parcel->readByteVector(&mMap[key]);
+ if (status != OK) {
+ break;
+ }
+ }
+ return status;
+}
+
+LayerMetadata& LayerMetadata::operator=(const LayerMetadata& other) {
+ mMap = other.mMap;
+ return *this;
+}
+
+LayerMetadata& LayerMetadata::operator=(LayerMetadata&& other) {
+ mMap = std::move(other.mMap);
+ return *this;
+}
+
+bool LayerMetadata::has(uint32_t key) const {
+ return mMap.count(key);
+}
+
+int32_t LayerMetadata::getInt32(uint32_t key, int32_t fallback) const {
+ if (!has(key)) return fallback;
+ const std::vector<uint8_t>& data = mMap.at(key);
+ if (data.size() < sizeof(uint32_t)) return fallback;
+ Parcel p;
+ p.setData(data.data(), data.size());
+ return p.readInt32();
+}
+
+void LayerMetadata::setInt32(uint32_t key, int32_t value) {
+ std::vector<uint8_t>& data = mMap[key];
+ Parcel p;
+ p.writeInt32(value);
+ data.resize(p.dataSize());
+ memcpy(data.data(), p.data(), p.dataSize());
+}
+
+std::string LayerMetadata::itemToString(uint32_t key, const char* separator) const {
+ if (!has(key)) return std::string();
+ switch (key) {
+ case METADATA_OWNER_UID:
+ return StringPrintf("ownerUID%s%d", separator, getInt32(key, 0));
+ case METADATA_WINDOW_TYPE:
+ return StringPrintf("windowType%s%d", separator, getInt32(key, 0));
+ case METADATA_TASK_ID:
+ return StringPrintf("taskId%s%d", separator, getInt32(key, 0));
+ default:
+ return StringPrintf("%d%s%dbytes", key, separator,
+ static_cast<int>(mMap.at(key).size()));
+ }
+}
+
+} // namespace android
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index 35ce6e3..206bc30 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -94,6 +94,13 @@
}
}
+ output.writeStrongBinder(cachedBuffer.token);
+ output.writeInt32(cachedBuffer.bufferId);
+ output.writeParcelable(metadata);
+
+ output.writeFloat(bgColorAlpha);
+ output.writeUint32(static_cast<uint32_t>(bgColorDataspace));
+
return NO_ERROR;
}
@@ -164,6 +171,13 @@
listenerCallbacks.emplace_back(listener, callbackIds);
}
+ cachedBuffer.token = input.readStrongBinder();
+ cachedBuffer.bufferId = input.readInt32();
+ input.readParcelable(&metadata);
+
+ bgColorAlpha = input.readFloat();
+ bgColorDataspace = static_cast<ui::Dataspace>(input.readUint32());
+
return NO_ERROR;
}
@@ -372,6 +386,20 @@
}
#endif
+ if (other.what & eCachedBufferChanged) {
+ what |= eCachedBufferChanged;
+ cachedBuffer = other.cachedBuffer;
+ }
+ if (other.what & eBackgroundColorChanged) {
+ what |= eBackgroundColorChanged;
+ color = other.color;
+ bgColorAlpha = other.bgColorAlpha;
+ bgColorDataspace = other.bgColorDataspace;
+ }
+ if (other.what & eMetadataChanged) {
+ what |= eMetadataChanged;
+ metadata.merge(other.metadata);
+ }
if ((other.what & what) != other.what) {
ALOGE("Unmerged SurfaceComposer Transaction properties. LayerState::merge needs updating? "
"other.what=0x%" PRIu64 " what=0x%" PRIu64,
@@ -379,4 +407,36 @@
}
}
+// ------------------------------- InputWindowCommands ----------------------------------------
+
+void InputWindowCommands::merge(const InputWindowCommands& other) {
+ transferTouchFocusCommands
+ .insert(transferTouchFocusCommands.end(),
+ std::make_move_iterator(other.transferTouchFocusCommands.begin()),
+ std::make_move_iterator(other.transferTouchFocusCommands.end()));
+}
+
+void InputWindowCommands::clear() {
+ transferTouchFocusCommands.clear();
+}
+
+void InputWindowCommands::write(Parcel& output) const {
+ output.writeUint32(static_cast<uint32_t>(transferTouchFocusCommands.size()));
+ for (const auto& transferTouchFocusCommand : transferTouchFocusCommands) {
+ output.writeStrongBinder(transferTouchFocusCommand.fromToken);
+ output.writeStrongBinder(transferTouchFocusCommand.toToken);
+ }
+}
+
+void InputWindowCommands::read(const Parcel& input) {
+ size_t count = input.readUint32();
+ transferTouchFocusCommands.clear();
+ for (size_t i = 0; i < count; i++) {
+ TransferTouchFocusCommand transferTouchFocusCommand;
+ transferTouchFocusCommand.fromToken = input.readStrongBinder();
+ transferTouchFocusCommand.toToken = input.readStrongBinder();
+ transferTouchFocusCommands.emplace_back(transferTouchFocusCommand);
+ }
+}
+
}; // namespace android
diff --git a/libs/gui/OWNERS b/libs/gui/OWNERS
index a7c7e79..73150dc 100644
--- a/libs/gui/OWNERS
+++ b/libs/gui/OWNERS
@@ -1,8 +1,7 @@
-brianderson@google.com
jessehall@google.com
jwcai@google.com
+lpy@google.com
+marissaw@google.com
mathias@google.com
-olv@google.com
-pceballos@google.com
racarr@google.com
stoza@google.com
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index 00e23f0..1f726b2 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -39,9 +39,6 @@
#include <gui/ISurfaceComposer.h>
#include <private/gui/ComposerService.h>
-#include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
-#include <configstore/Utils.h>
-
namespace android {
using ui::ColorMode;
@@ -321,41 +318,14 @@
return NO_ERROR;
}
-using namespace android::hardware::configstore;
-using namespace android::hardware::configstore::V1_0;
-
status_t Surface::getWideColorSupport(bool* supported) {
ATRACE_CALL();
sp<IBinder> display(
composerService()->getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
- Vector<ColorMode> colorModes;
- status_t err =
- composerService()->getDisplayColorModes(display, &colorModes);
-
- if (err)
- return err;
-
- bool wideColorBoardConfig =
- getBool<ISurfaceFlingerConfigs,
- &ISurfaceFlingerConfigs::hasWideColorDisplay>(false);
-
*supported = false;
- for (ColorMode colorMode : colorModes) {
- switch (colorMode) {
- case ColorMode::DISPLAY_P3:
- case ColorMode::ADOBE_RGB:
- case ColorMode::DCI_P3:
- if (wideColorBoardConfig) {
- *supported = true;
- }
- break;
- default:
- break;
- }
- }
-
- return NO_ERROR;
+ status_t error = composerService()->isWideColorDisplay(display, supported);
+ return error;
}
status_t Surface::getHdrSupport(bool* supported) {
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 5b004e2..92b5588 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -48,6 +48,9 @@
#include <private/gui/ComposerService.h>
+// This server size should always be smaller than the server cache size
+#define BUFFER_CACHE_MAX_SIZE 64
+
namespace android {
using ui::ColorMode;
@@ -102,6 +105,27 @@
mDeathObserver = nullptr;
}
+class DefaultComposerClient: public Singleton<DefaultComposerClient> {
+ Mutex mLock;
+ sp<SurfaceComposerClient> mClient;
+ friend class Singleton<ComposerService>;
+public:
+ static sp<SurfaceComposerClient> getComposerClient() {
+ DefaultComposerClient& dc = DefaultComposerClient::getInstance();
+ Mutex::Autolock _l(dc.mLock);
+ if (dc.mClient == nullptr) {
+ dc.mClient = new SurfaceComposerClient;
+ }
+ return dc.mClient;
+ }
+};
+ANDROID_SINGLETON_STATIC_INSTANCE(DefaultComposerClient);
+
+
+sp<SurfaceComposerClient> SurfaceComposerClient::getDefault() {
+ return DefaultComposerClient::getComposerClient();
+}
+
// ---------------------------------------------------------------------------
// TransactionCompletedListener does not use ANDROID_SINGLETON_STATIC_INSTANCE because it needs
@@ -132,26 +156,76 @@
mListening = true;
}
-CallbackId TransactionCompletedListener::addCallback(const TransactionCompletedCallback& callback) {
+CallbackId TransactionCompletedListener::addCallbackFunction(
+ const TransactionCompletedCallback& callbackFunction,
+ const std::unordered_set<sp<SurfaceControl>, SurfaceComposerClient::SCHash>&
+ surfaceControls) {
std::lock_guard<std::mutex> lock(mMutex);
startListeningLocked();
CallbackId callbackId = getNextIdLocked();
- mCallbacks.emplace(callbackId, callback);
+ mCallbacks[callbackId].callbackFunction = callbackFunction;
+
+ auto& callbackSurfaceControls = mCallbacks[callbackId].surfaceControls;
+
+ for (const auto& surfaceControl : surfaceControls) {
+ callbackSurfaceControls[surfaceControl->getHandle()] = surfaceControl;
+ }
+
return callbackId;
}
+void TransactionCompletedListener::addSurfaceControlToCallbacks(
+ const sp<SurfaceControl>& surfaceControl,
+ const std::unordered_set<CallbackId>& callbackIds) {
+ std::lock_guard<std::mutex> lock(mMutex);
+
+ for (auto callbackId : callbackIds) {
+ mCallbacks[callbackId].surfaceControls.emplace(std::piecewise_construct,
+ std::forward_as_tuple(
+ surfaceControl->getHandle()),
+ std::forward_as_tuple(surfaceControl));
+ }
+}
+
void TransactionCompletedListener::onTransactionCompleted(ListenerStats listenerStats) {
std::lock_guard 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
+ * solved before this point because the Transactions could be merged together and applied in a
+ * different process.
+ *
+ * Fortunately, we get all the callbacks for this listener for the same frame together at the
+ * same time. This means if any Transactions were merged together, we will get their callbacks
+ * at the same time. We can combine all the sp<IBinder> to sp<SurfaceControl> maps for all the
+ * callbackIds to generate one super map that contains all the sp<IBinder> to sp<SurfaceControl>
+ * that could possibly exist for the callbacks.
+ */
+ std::unordered_map<sp<IBinder>, sp<SurfaceControl>, IBinderHash> surfaceControls;
for (const auto& [callbackIds, transactionStats] : listenerStats.transactionStats) {
for (auto callbackId : callbackIds) {
- const auto& callback = mCallbacks[callbackId];
- if (!callback) {
+ auto& [callbackFunction, callbackSurfaceControls] = mCallbacks[callbackId];
+ surfaceControls.insert(callbackSurfaceControls.begin(), callbackSurfaceControls.end());
+ }
+ }
+
+ for (const auto& [callbackIds, transactionStats] : listenerStats.transactionStats) {
+ for (auto callbackId : callbackIds) {
+ auto& [callbackFunction, callbackSurfaceControls] = mCallbacks[callbackId];
+ if (!callbackFunction) {
ALOGE("cannot call null callback function, skipping");
continue;
}
- callback(transactionStats);
+ std::vector<SurfaceControlStats> surfaceControlStats;
+ for (const auto& surfaceStats : transactionStats.surfaceStats) {
+ surfaceControlStats.emplace_back(surfaceControls[surfaceStats.surfaceControl],
+ surfaceStats.acquireTime,
+ surfaceStats.previousReleaseFence);
+ }
+
+ callbackFunction(transactionStats.latchTime, transactionStats.presentFence,
+ surfaceControlStats);
mCallbacks.erase(callbackId);
}
}
@@ -159,13 +233,122 @@
// ---------------------------------------------------------------------------
-SurfaceComposerClient::Transaction::Transaction(const Transaction& other) :
- mForceSynchronous(other.mForceSynchronous),
- mTransactionNestCount(other.mTransactionNestCount),
- mAnimation(other.mAnimation),
- mEarlyWakeup(other.mEarlyWakeup) {
+class BufferCache : public Singleton<BufferCache> {
+public:
+ BufferCache() : token(new BBinder()) {}
+
+ sp<IBinder> getToken() {
+ return IInterface::asBinder(TransactionCompletedListener::getIInstance());
+ }
+
+ int32_t getId(const sp<GraphicBuffer>& buffer) {
+ std::lock_guard lock(mMutex);
+
+ auto itr = mBuffers.find(buffer);
+ if (itr == mBuffers.end()) {
+ return -1;
+ }
+ itr->second.counter = getCounter();
+ return itr->second.id;
+ }
+
+ int32_t cache(const sp<GraphicBuffer>& buffer) {
+ std::lock_guard lock(mMutex);
+
+ int32_t bufferId = getNextAvailableId();
+
+ mBuffers[buffer].id = bufferId;
+ mBuffers[buffer].counter = getCounter();
+ return bufferId;
+ }
+
+private:
+ int32_t evictDestroyedBuffer() REQUIRES(mMutex) {
+ auto itr = mBuffers.begin();
+ while (itr != mBuffers.end()) {
+ auto& buffer = itr->first;
+ if (buffer == nullptr || buffer.promote() == nullptr) {
+ int32_t bufferId = itr->second.id;
+ mBuffers.erase(itr);
+ return bufferId;
+ }
+ itr++;
+ }
+ return -1;
+ }
+
+ int32_t evictLeastRecentlyUsedBuffer() REQUIRES(mMutex) {
+ if (mBuffers.size() < 0) {
+ return -1;
+ }
+ auto itr = mBuffers.begin();
+ uint64_t minCounter = itr->second.counter;
+ auto minBuffer = itr;
+ itr++;
+
+ while (itr != mBuffers.end()) {
+ uint64_t counter = itr->second.counter;
+ if (counter < minCounter) {
+ minCounter = counter;
+ minBuffer = itr;
+ }
+ itr++;
+ }
+ int32_t minBufferId = minBuffer->second.id;
+ mBuffers.erase(minBuffer);
+ return minBufferId;
+ }
+
+ int32_t getNextAvailableId() REQUIRES(mMutex) {
+ static int32_t id = 0;
+ if (id + 1 < BUFFER_CACHE_MAX_SIZE) {
+ return id++;
+ }
+
+ // There are no more valid cache ids. To set additional buffers, evict existing buffers
+ // and reuse their cache ids.
+ int32_t bufferId = evictDestroyedBuffer();
+ if (bufferId > 0) {
+ return bufferId;
+ }
+ return evictLeastRecentlyUsedBuffer();
+ }
+
+ uint64_t getCounter() REQUIRES(mMutex) {
+ static uint64_t counter = 0;
+ return counter++;
+ }
+
+ struct Metadata {
+ // The cache id of a buffer that can be set to ISurfaceComposer. When ISurfaceComposer
+ // recieves this id, it can retrieve the buffer from its cache. Caching GraphicBuffers
+ // is important because sending them across processes is expensive.
+ int32_t id = 0;
+ // When a buffer is set, a counter is incremented and stored in the cache's metadata.
+ // When an buffer must be evicted, the entry with the lowest counter value is chosen.
+ uint64_t counter = 0;
+ };
+
+ std::mutex mMutex;
+ std::map<wp<GraphicBuffer>, Metadata> mBuffers GUARDED_BY(mMutex);
+
+ // Used by ISurfaceComposer to identify which process is sending the cached buffer.
+ sp<IBinder> token;
+};
+
+ANDROID_SINGLETON_STATIC_INSTANCE(BufferCache);
+
+// ---------------------------------------------------------------------------
+
+SurfaceComposerClient::Transaction::Transaction(const Transaction& other)
+ : mForceSynchronous(other.mForceSynchronous),
+ mTransactionNestCount(other.mTransactionNestCount),
+ mAnimation(other.mAnimation),
+ mEarlyWakeup(other.mEarlyWakeup),
+ mDesiredPresentTime(other.mDesiredPresentTime) {
mDisplayStates = other.mDisplayStates;
mComposerStates = other.mComposerStates;
+ mInputWindowCommands = other.mInputWindowCommands;
}
SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::merge(Transaction&& other) {
@@ -199,9 +382,27 @@
}
other.mListenerCallbacks.clear();
+ mInputWindowCommands.merge(other.mInputWindowCommands);
+
return *this;
}
+void SurfaceComposerClient::doDropReferenceTransaction(const sp<IBinder>& handle,
+ const sp<ISurfaceComposerClient>& client) {
+ sp<ISurfaceComposer> sf(ComposerService::getComposerService());
+ Vector<ComposerState> composerStates;
+ Vector<DisplayState> displayStates;
+
+ ComposerState s;
+ s.client = client;
+ s.state.surface = handle;
+ s.state.what |= layer_state_t::eReparent;
+ s.state.parentHandleForChild = nullptr;
+
+ composerStates.add(s);
+ sf->setTransactionState(composerStates, displayStates, 0, nullptr, {}, -1);
+}
+
status_t SurfaceComposerClient::Transaction::apply(bool synchronous) {
if (mStatus != NO_ERROR) {
return mStatus;
@@ -265,8 +466,9 @@
mEarlyWakeup = false;
sp<IBinder> applyToken = IInterface::asBinder(TransactionCompletedListener::getIInstance());
-
- sf->setTransactionState(composerStates, displayStates, flags, applyToken);
+ sf->setTransactionState(composerStates, displayStates, flags, applyToken, mInputWindowCommands,
+ mDesiredPresentTime);
+ mInputWindowCommands.clear();
mStatus = NO_ERROR;
return NO_ERROR;
}
@@ -308,7 +510,11 @@
void SurfaceComposerClient::Transaction::registerSurfaceControlForCallback(
const sp<SurfaceControl>& sc) {
- mListenerCallbacks[TransactionCompletedListener::getIInstance()].surfaceControls.insert(sc);
+ auto& callbackInfo = mListenerCallbacks[TransactionCompletedListener::getIInstance()];
+ callbackInfo.surfaceControls.insert(sc);
+
+ TransactionCompletedListener::getInstance()
+ ->addSurfaceControlToCallbacks(sc, callbackInfo.callbackIds);
}
SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setPosition(
@@ -443,6 +649,20 @@
return *this;
}
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setMetadata(
+ const sp<SurfaceControl>& sc, uint32_t key, std::vector<uint8_t> data) {
+ layer_state_t* s = getLayerState(sc);
+ if (!s) {
+ mStatus = BAD_INDEX;
+ return *this;
+ }
+ s->what |= layer_state_t::eMetadataChanged;
+ s->metadata.mMap[key] = std::move(data);
+
+ registerSurfaceControlForCallback(sc);
+ return *this;
+}
+
SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setMatrix(
const sp<SurfaceControl>& sc, float dsdx, float dtdx,
float dtdy, float dsdy) {
@@ -568,6 +788,23 @@
return *this;
}
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setBackgroundColor(
+ const sp<SurfaceControl>& sc, const half3& color, float alpha, ui::Dataspace dataspace) {
+ layer_state_t* s = getLayerState(sc);
+ if (!s) {
+ mStatus = BAD_INDEX;
+ return *this;
+ }
+
+ s->what |= layer_state_t::eBackgroundColorChanged;
+ s->color = color;
+ s->bgColorAlpha = alpha;
+ s->bgColorDataspace = dataspace;
+
+ registerSurfaceControlForCallback(sc);
+ return *this;
+}
+
SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setTransform(
const sp<SurfaceControl>& sc, uint32_t transform) {
layer_state_t* s = getLayerState(sc);
@@ -632,8 +869,18 @@
mStatus = BAD_INDEX;
return *this;
}
- s->what |= layer_state_t::eBufferChanged;
- s->buffer = buffer;
+
+ int32_t bufferId = BufferCache::getInstance().getId(buffer);
+ if (bufferId < 0) {
+ bufferId = BufferCache::getInstance().cache(buffer);
+
+ s->what |= layer_state_t::eBufferChanged;
+ s->buffer = buffer;
+ }
+
+ s->what |= layer_state_t::eCachedBufferChanged;
+ s->cachedBuffer.token = BufferCache::getInstance().getToken();
+ s->cachedBuffer.bufferId = bufferId;
registerSurfaceControlForCallback(sc);
return *this;
@@ -723,14 +970,23 @@
return *this;
}
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setDesiredPresentTime(
+ nsecs_t desiredPresentTime) {
+ mDesiredPresentTime = desiredPresentTime;
+ return *this;
+}
+
SurfaceComposerClient::Transaction&
SurfaceComposerClient::Transaction::addTransactionCompletedCallback(
TransactionCompletedCallbackTakesContext callback, void* callbackContext) {
auto listener = TransactionCompletedListener::getInstance();
- auto callbackWithContext = std::bind(callback, callbackContext, std::placeholders::_1);
+ auto callbackWithContext = std::bind(callback, callbackContext, std::placeholders::_1,
+ std::placeholders::_2, std::placeholders::_3);
+ const auto& surfaceControls =
+ mListenerCallbacks[TransactionCompletedListener::getIInstance()].surfaceControls;
- CallbackId callbackId = listener->addCallback(callbackWithContext);
+ CallbackId callbackId = listener->addCallbackFunction(callbackWithContext, surfaceControls);
mListenerCallbacks[TransactionCompletedListener::getIInstance()].callbackIds.emplace(
callbackId);
@@ -804,19 +1060,18 @@
s->what |= layer_state_t::eInputInfoChanged;
return *this;
}
-#endif
-SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::destroySurface(
- const sp<SurfaceControl>& sc) {
- layer_state_t* s = getLayerState(sc);
- if (!s) {
- mStatus = BAD_INDEX;
- return *this;
- }
- s->what |= layer_state_t::eDestroySurface;
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::transferTouchFocus(
+ const sp<IBinder>& fromToken, const sp<IBinder>& toToken) {
+ InputWindowCommands::TransferTouchFocusCommand transferTouchFocusCommand;
+ transferTouchFocusCommand.fromToken = fromToken;
+ transferTouchFocusCommand.toToken = toToken;
+ mInputWindowCommands.transferTouchFocusCommands.emplace_back(transferTouchFocusCommand);
return *this;
}
+#endif
+
SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setColorTransform(
const sp<SurfaceControl>& sc, const mat3& matrix, const vec3& translation) {
layer_state_t* s = getLayerState(sc);
@@ -831,6 +1086,54 @@
return *this;
}
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setGeometry(
+ const sp<SurfaceControl>& sc, const Rect& source, const Rect& dst, int transform) {
+ setCrop_legacy(sc, source);
+
+ int x = dst.left;
+ int y = dst.top;
+ float xScale = dst.getWidth() / static_cast<float>(source.getWidth());
+ float yScale = dst.getHeight() / static_cast<float>(source.getHeight());
+ float matrix[4] = {1, 0, 0, 1};
+
+ switch (transform) {
+ case NATIVE_WINDOW_TRANSFORM_FLIP_H:
+ matrix[0] = -xScale; matrix[1] = 0;
+ matrix[2] = 0; matrix[3] = yScale;
+ x += source.getWidth();
+ break;
+ case NATIVE_WINDOW_TRANSFORM_FLIP_V:
+ matrix[0] = xScale; matrix[1] = 0;
+ matrix[2] = 0; matrix[3] = -yScale;
+ y += source.getHeight();
+ break;
+ case NATIVE_WINDOW_TRANSFORM_ROT_90:
+ matrix[0] = 0; matrix[1] = -yScale;
+ matrix[2] = xScale; matrix[3] = 0;
+ x += source.getHeight();
+ break;
+ case NATIVE_WINDOW_TRANSFORM_ROT_180:
+ matrix[0] = -xScale; matrix[1] = 0;
+ matrix[2] = 0; matrix[3] = -yScale;
+ x += source.getWidth();
+ y += source.getHeight();
+ break;
+ case NATIVE_WINDOW_TRANSFORM_ROT_270:
+ matrix[0] = 0; matrix[1] = yScale;
+ matrix[2] = -xScale; matrix[3] = 0;
+ y += source.getWidth();
+ break;
+ default:
+ matrix[0] = xScale; matrix[1] = 0;
+ matrix[2] = 0; matrix[3] = yScale;
+ break;
+ }
+ setMatrix(sc, matrix[0], matrix[1], matrix[2], matrix[3]);
+ setPosition(sc, x, y);
+
+ return *this;
+}
+
// ---------------------------------------------------------------------------
DisplayState& SurfaceComposerClient::Transaction::getDisplayState(const sp<IBinder>& token) {
@@ -897,11 +1200,6 @@
{
}
-SurfaceComposerClient::SurfaceComposerClient(const sp<IGraphicBufferProducer>& root)
- : mStatus(NO_INIT), mParent(root)
-{
-}
-
SurfaceComposerClient::SurfaceComposerClient(const sp<ISurfaceComposerClient>& client)
: mStatus(NO_ERROR), mClient(client)
{
@@ -910,10 +1208,8 @@
void SurfaceComposerClient::onFirstRef() {
sp<ISurfaceComposer> sf(ComposerService::getComposerService());
if (sf != nullptr && mStatus == NO_INIT) {
- auto rootProducer = mParent.promote();
sp<ISurfaceComposerClient> conn;
- conn = (rootProducer != nullptr) ? sf->createScopedConnection(rootProducer) :
- sf->createConnection();
+ conn = sf->createConnection();
if (conn != nullptr) {
mClient = conn;
mStatus = NO_ERROR;
@@ -951,32 +1247,42 @@
mStatus = NO_INIT;
}
-sp<SurfaceControl> SurfaceComposerClient::createSurface(
- const String8& name,
- uint32_t w,
- uint32_t h,
- PixelFormat format,
- uint32_t flags,
- SurfaceControl* parent,
- int32_t windowType,
- int32_t ownerUid)
-{
+sp<SurfaceControl> SurfaceComposerClient::createSurface(const String8& name, uint32_t w, uint32_t h,
+ PixelFormat format, uint32_t flags,
+ SurfaceControl* parent,
+ LayerMetadata metadata) {
sp<SurfaceControl> s;
- createSurfaceChecked(name, w, h, format, &s, flags, parent, windowType, ownerUid);
+ createSurfaceChecked(name, w, h, format, &s, flags, parent, std::move(metadata));
return s;
}
-status_t SurfaceComposerClient::createSurfaceChecked(
- const String8& name,
- uint32_t w,
- uint32_t h,
- PixelFormat format,
- sp<SurfaceControl>* outSurface,
- uint32_t flags,
- SurfaceControl* parent,
- int32_t windowType,
- int32_t ownerUid)
-{
+sp<SurfaceControl> SurfaceComposerClient::createWithSurfaceParent(const String8& name, uint32_t w,
+ uint32_t h, PixelFormat format,
+ uint32_t flags, Surface* parent,
+ LayerMetadata metadata) {
+ sp<SurfaceControl> sur;
+ status_t err = mStatus;
+
+ if (mStatus == NO_ERROR) {
+ sp<IBinder> handle;
+ sp<IGraphicBufferProducer> parentGbp = parent->getIGraphicBufferProducer();
+ sp<IGraphicBufferProducer> gbp;
+
+ err = mClient->createWithSurfaceParent(name, w, h, format, flags, parentGbp,
+ std::move(metadata), &handle, &gbp);
+ ALOGE_IF(err, "SurfaceComposerClient::createWithSurfaceParent error %s", strerror(-err));
+ if (err == NO_ERROR) {
+ return new SurfaceControl(this, handle, gbp, true /* owned */);
+ }
+ }
+ return nullptr;
+}
+
+status_t SurfaceComposerClient::createSurfaceChecked(const String8& name, uint32_t w, uint32_t h,
+ PixelFormat format,
+ sp<SurfaceControl>* outSurface, uint32_t flags,
+ SurfaceControl* parent,
+ LayerMetadata metadata) {
sp<SurfaceControl> sur;
status_t err = mStatus;
@@ -988,8 +1294,9 @@
if (parent != nullptr) {
parentHandle = parent->getHandle();
}
- err = mClient->createSurface(name, w, h, format, flags, parentHandle,
- windowType, ownerUid, &handle, &gbp);
+
+ err = mClient->createSurface(name, w, h, format, flags, parentHandle, std::move(metadata),
+ &handle, &gbp);
ALOGE_IF(err, "SurfaceComposerClient::createSurface error %s", strerror(-err));
if (err == NO_ERROR) {
*outSurface = new SurfaceControl(this, handle, gbp, true /* owned */);
@@ -998,13 +1305,6 @@
return err;
}
-status_t SurfaceComposerClient::destroySurface(const sp<IBinder>& sid) {
- if (mStatus != NO_ERROR)
- return mStatus;
- status_t err = mClient->destroySurface(sid);
- return err;
-}
-
status_t SurfaceComposerClient::clearLayerFrameStats(const sp<IBinder>& token) const {
if (mStatus != NO_ERROR) {
return mStatus;
@@ -1069,6 +1369,11 @@
return ComposerService::getComposerService()->getDisplayColorModes(display, outColorModes);
}
+status_t SurfaceComposerClient::getDisplayNativePrimaries(const sp<IBinder>& display,
+ ui::DisplayPrimaries& outPrimaries) {
+ return ComposerService::getComposerService()->getDisplayNativePrimaries(display, outPrimaries);
+}
+
ColorMode SurfaceComposerClient::getActiveColorMode(const sp<IBinder>& display) {
return ComposerService::getComposerService()->getActiveColorMode(display);
}
@@ -1091,6 +1396,12 @@
wideColorGamutDataspace, wideColorGamutPixelFormat);
}
+bool SurfaceComposerClient::getProtectedContentSupport() {
+ bool supported = false;
+ ComposerService::getComposerService()->getProtectedContentSupport(&supported);
+ return supported;
+}
+
status_t SurfaceComposerClient::clearAnimationFrameStats() {
return ComposerService::getComposerService()->clearAnimationFrameStats();
}
@@ -1128,6 +1439,13 @@
return ComposerService::getComposerService()->getDisplayedContentSample(display, maxFrames,
timestamp, outStats);
}
+
+status_t SurfaceComposerClient::isWideColorDisplay(const sp<IBinder>& display,
+ bool* outIsWideColorDisplay) {
+ return ComposerService::getComposerService()->isWideColorDisplay(display,
+ outIsWideColorDisplay);
+}
+
// ----------------------------------------------------------------------------
status_t ScreenshotClient::capture(const sp<IBinder>& display, const ui::Dataspace reqDataSpace,
diff --git a/libs/gui/SurfaceControl.cpp b/libs/gui/SurfaceControl.cpp
index 3a6dfda..008f520 100644
--- a/libs/gui/SurfaceControl.cpp
+++ b/libs/gui/SurfaceControl.cpp
@@ -54,9 +54,22 @@
{
}
+SurfaceControl::SurfaceControl(const sp<SurfaceControl>& other) {
+ mClient = other->mClient;
+ mHandle = other->mHandle;
+ mGraphicBufferProducer = other->mGraphicBufferProducer;
+ mOwned = false;
+}
+
SurfaceControl::~SurfaceControl()
{
- destroy();
+ if (mClient != nullptr && mHandle != nullptr && mOwned) {
+ SurfaceComposerClient::doDropReferenceTransaction(mHandle, mClient->getClient());
+ }
+ mClient.clear();
+ mHandle.clear();
+ mGraphicBufferProducer.clear();
+ IPCThreadState::self()->flushCommands();
}
void SurfaceControl::destroy()
@@ -64,7 +77,7 @@
// Avoid destroying the server-side surface if we are not the owner of it, meaning that we
// retrieved it from another process.
if (isValid() && mOwned) {
- mClient->destroySurface(mHandle);
+ SurfaceComposerClient::Transaction().reparent(this, nullptr).apply();
}
// clear all references and trigger an IPC now, to make sure things
// happen without delay, since these resources are quite heavy.
@@ -164,6 +177,12 @@
return mHandle;
}
+sp<IGraphicBufferProducer> SurfaceControl::getIGraphicBufferProducer() const
+{
+ Mutex::Autolock _l(mLock);
+ return mGraphicBufferProducer;
+}
+
sp<SurfaceComposerClient> SurfaceControl::getClient() const
{
return mClient;
diff --git a/libs/gui/include/gui/BufferQueueConsumer.h b/libs/gui/include/gui/BufferQueueConsumer.h
index d108120..aa13c0c 100644
--- a/libs/gui/include/gui/BufferQueueConsumer.h
+++ b/libs/gui/include/gui/BufferQueueConsumer.h
@@ -31,7 +31,7 @@
class BufferQueueConsumer : public BnGraphicBufferConsumer {
public:
- BufferQueueConsumer(const sp<BufferQueueCore>& core);
+ explicit BufferQueueConsumer(const sp<BufferQueueCore>& core);
~BufferQueueConsumer() override;
// acquireBuffer attempts to acquire ownership of the next pending buffer in
diff --git a/libs/gui/include/gui/BufferQueueCore.h b/libs/gui/include/gui/BufferQueueCore.h
index 537c957..b377a41 100644
--- a/libs/gui/include/gui/BufferQueueCore.h
+++ b/libs/gui/include/gui/BufferQueueCore.h
@@ -40,13 +40,14 @@
#define BQ_LOGW(x, ...) ALOGW("[%s] " x, mConsumerName.string(), ##__VA_ARGS__)
#define BQ_LOGE(x, ...) ALOGE("[%s] " x, mConsumerName.string(), ##__VA_ARGS__)
-#define ATRACE_BUFFER_INDEX(index) \
- if (ATRACE_ENABLED()) { \
- char ___traceBuf[1024]; \
- snprintf(___traceBuf, 1024, "%s: %d", \
- mCore->mConsumerName.string(), (index)); \
- android::ScopedTrace ___bufTracer(ATRACE_TAG, ___traceBuf); \
- }
+#define ATRACE_BUFFER_INDEX(index) \
+ do { \
+ if (ATRACE_ENABLED()) { \
+ char ___traceBuf[1024]; \
+ snprintf(___traceBuf, 1024, "%s: %d", mCore->mConsumerName.string(), (index)); \
+ android::ScopedTrace ___bufTracer(ATRACE_TAG, ___traceBuf); \
+ } \
+ } while (false)
namespace android {
diff --git a/libs/gui/include/gui/BufferQueueProducer.h b/libs/gui/include/gui/BufferQueueProducer.h
index 5c7ffb4..73bc5dd 100644
--- a/libs/gui/include/gui/BufferQueueProducer.h
+++ b/libs/gui/include/gui/BufferQueueProducer.h
@@ -29,7 +29,8 @@
public:
friend class BufferQueue; // Needed to access binderDied
- BufferQueueProducer(const sp<BufferQueueCore>& core, bool consumerIsSurfaceFlinger = false);
+ explicit BufferQueueProducer(const sp<BufferQueueCore>& core,
+ bool consumerIsSurfaceFlinger = false);
~BufferQueueProducer() override;
// requestBuffer returns the GraphicBuffer for slot N.
diff --git a/libs/gui/include/gui/DisplayEventReceiver.h b/libs/gui/include/gui/DisplayEventReceiver.h
index 32ce59a..a4102df 100644
--- a/libs/gui/include/gui/DisplayEventReceiver.h
+++ b/libs/gui/include/gui/DisplayEventReceiver.h
@@ -84,7 +84,7 @@
* or requestNextVsync to receive them.
* Other events start being delivered immediately.
*/
- DisplayEventReceiver(
+ explicit DisplayEventReceiver(
ISurfaceComposer::VsyncSource vsyncSource = ISurfaceComposer::eVsyncSourceApp);
/*
diff --git a/libs/gui/include/gui/GLConsumer.h b/libs/gui/include/gui/GLConsumer.h
index 46a99e1..ddd868d 100644
--- a/libs/gui/include/gui/GLConsumer.h
+++ b/libs/gui/include/gui/GLConsumer.h
@@ -301,7 +301,7 @@
// also only creating new EGLImages from buffers when required.
class EglImage : public LightRefBase<EglImage> {
public:
- EglImage(sp<GraphicBuffer> graphicBuffer);
+ explicit EglImage(sp<GraphicBuffer> graphicBuffer);
// createIfNeeded creates an EGLImage if required (we haven't created
// one yet, or the EGLDisplay or crop-rect has changed).
diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
index 8cb40e7..7146b7d 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -27,6 +27,7 @@
#include <binder/IInterface.h>
+#include <ui/ConfigStoreTypes.h>
#include <ui/DisplayedFrameStats.h>
#include <ui/FrameStats.h>
#include <ui/GraphicBuffer.h>
@@ -42,6 +43,7 @@
struct DisplayState;
struct DisplayInfo;
struct DisplayStatInfo;
+struct InputWindowCommands;
class LayerDebugInfo;
class HdrCapabilities;
class IDisplayEventConnection;
@@ -86,22 +88,11 @@
eVsyncSourceSurfaceFlinger = 1
};
- /* create connection with surface flinger, requires
- * ACCESS_SURFACE_FLINGER permission
+ /*
+ * Create a connection with SurfaceFlinger.
*/
virtual sp<ISurfaceComposerClient> createConnection() = 0;
- /** create a scoped connection with surface flinger.
- * Surfaces produced with this connection will act
- * as children of the passed in GBP. That is to say
- * SurfaceFlinger will draw them relative and confined to
- * drawing of buffers from the layer associated with parent.
- * As this is graphically equivalent in reach to just drawing
- * pixels into the parent buffers, it requires no special permission.
- */
- virtual sp<ISurfaceComposerClient> createScopedConnection(
- const sp<IGraphicBufferProducer>& parent) = 0;
-
/* return an IDisplayEventConnection */
virtual sp<IDisplayEventConnection> createDisplayEventConnection(
VsyncSource vsyncSource = eVsyncSourceApp) = 0;
@@ -125,7 +116,9 @@
/* open/close transactions. requires ACCESS_SURFACE_FLINGER permission */
virtual void setTransactionState(const Vector<ComposerState>& state,
const Vector<DisplayState>& displays, uint32_t flags,
- const sp<IBinder>& applyToken) = 0;
+ const sp<IBinder>& applyToken,
+ const InputWindowCommands& inputWindowCommands,
+ int64_t desiredPresentTime) = 0;
/* signal that we're done booting.
* Requires ACCESS_SURFACE_FLINGER permission
@@ -169,6 +162,8 @@
virtual status_t getDisplayColorModes(const sp<IBinder>& display,
Vector<ui::ColorMode>* outColorModes) = 0;
+ virtual status_t getDisplayNativePrimaries(const sp<IBinder>& display,
+ ui::DisplayPrimaries& primaries) = 0;
virtual ui::ColorMode getActiveColorMode(const sp<IBinder>& display) = 0;
virtual status_t setActiveColorMode(const sp<IBinder>& display,
ui::ColorMode colorMode) = 0;
@@ -318,6 +313,19 @@
virtual status_t getDisplayedContentSample(const sp<IBinder>& display, uint64_t maxFrames,
uint64_t timestamp,
DisplayedFrameStats* outStats) const = 0;
+
+ /*
+ * Gets whether SurfaceFlinger can support protected content in GPU composition.
+ * Requires the ACCESS_SURFACE_FLINGER permission.
+ */
+ virtual status_t getProtectedContentSupport(bool* outSupported) const = 0;
+
+ /*
+ * Queries whether the given display is a wide color display.
+ * Requires the ACCESS_SURFACE_FLINGER permission.
+ */
+ virtual status_t isWideColorDisplay(const sp<IBinder>& token,
+ bool* outIsWideColorDisplay) const = 0;
};
// ----------------------------------------------------------------------------
@@ -354,12 +362,15 @@
ENABLE_VSYNC_INJECTIONS,
INJECT_VSYNC,
GET_LAYER_DEBUG_INFO,
- CREATE_SCOPED_CONNECTION,
GET_COMPOSITION_PREFERENCE,
GET_COLOR_MANAGEMENT,
GET_DISPLAYED_CONTENT_SAMPLING_ATTRIBUTES,
SET_DISPLAY_CONTENT_SAMPLING_ENABLED,
GET_DISPLAYED_CONTENT_SAMPLE,
+ GET_PROTECTED_CONTENT_SUPPORT,
+ IS_WIDE_COLOR_DISPLAY,
+ GET_DISPLAY_NATIVE_PRIMARIES,
+ // Always append new enum to the end.
};
virtual status_t onTransact(uint32_t code, const Parcel& data,
diff --git a/libs/gui/include/gui/ISurfaceComposerClient.h b/libs/gui/include/gui/ISurfaceComposerClient.h
index 82b01b8..32ac9e8 100644
--- a/libs/gui/include/gui/ISurfaceComposerClient.h
+++ b/libs/gui/include/gui/ISurfaceComposerClient.h
@@ -18,8 +18,11 @@
#include <binder/IInterface.h>
#include <binder/SafeInterface.h>
+#include <gui/LayerMetadata.h>
#include <ui/PixelFormat.h>
+#include <unordered_map>
+
namespace android {
class FrameStats;
@@ -51,14 +54,18 @@
* Requires ACCESS_SURFACE_FLINGER permission
*/
virtual status_t createSurface(const String8& name, uint32_t w, uint32_t h, PixelFormat format,
- uint32_t flags, const sp<IBinder>& parent, int32_t windowType,
- int32_t ownerUid, sp<IBinder>* handle,
+ uint32_t flags, const sp<IBinder>& parent,
+ LayerMetadata metadata, sp<IBinder>* handle,
sp<IGraphicBufferProducer>* gbp) = 0;
/*
* Requires ACCESS_SURFACE_FLINGER permission
*/
- virtual status_t destroySurface(const sp<IBinder>& handle) = 0;
+ virtual status_t createWithSurfaceParent(const String8& name, uint32_t w, uint32_t h,
+ PixelFormat format, uint32_t flags,
+ const sp<IGraphicBufferProducer>& parent,
+ LayerMetadata metadata, sp<IBinder>* handle,
+ sp<IGraphicBufferProducer>* gbp) = 0;
/*
* Requires ACCESS_SURFACE_FLINGER permission
diff --git a/libs/gui/include/gui/ITransactionCompletedListener.h b/libs/gui/include/gui/ITransactionCompletedListener.h
index 8acfa7a..29ab026 100644
--- a/libs/gui/include/gui/ITransactionCompletedListener.h
+++ b/libs/gui/include/gui/ITransactionCompletedListener.h
@@ -52,12 +52,12 @@
status_t readFromParcel(const Parcel* input) override;
SurfaceStats() = default;
- SurfaceStats(const sp<IBinder>& sc, nsecs_t time, bool releasePrevBuffer)
- : surfaceControl(sc), acquireTime(time), releasePreviousBuffer(releasePrevBuffer) {}
+ SurfaceStats(const sp<IBinder>& sc, nsecs_t time, const sp<Fence>& prevReleaseFence)
+ : surfaceControl(sc), acquireTime(time), previousReleaseFence(prevReleaseFence) {}
sp<IBinder> surfaceControl;
nsecs_t acquireTime = -1;
- bool releasePreviousBuffer = false;
+ sp<Fence> previousReleaseFence;
};
class TransactionStats : public Parcelable {
diff --git a/libs/gui/include/gui/LayerMetadata.h b/libs/gui/include/gui/LayerMetadata.h
new file mode 100644
index 0000000..3ae10e4
--- /dev/null
+++ b/libs/gui/include/gui/LayerMetadata.h
@@ -0,0 +1,49 @@
+/*
+ * 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 <binder/Parcelable.h>
+
+#include <unordered_map>
+
+namespace android {
+
+enum { METADATA_OWNER_UID = 1, METADATA_WINDOW_TYPE = 2, METADATA_TASK_ID = 3 };
+
+struct LayerMetadata : public Parcelable {
+ std::unordered_map<uint32_t, std::vector<uint8_t>> mMap;
+
+ LayerMetadata();
+ LayerMetadata(const LayerMetadata& other);
+ LayerMetadata(LayerMetadata&& other);
+ explicit LayerMetadata(std::unordered_map<uint32_t, std::vector<uint8_t>> map);
+ LayerMetadata& operator=(const LayerMetadata& other);
+ LayerMetadata& operator=(LayerMetadata&& other);
+
+ void merge(const LayerMetadata& other);
+
+ status_t writeToParcel(Parcel* parcel) const override;
+ status_t readFromParcel(const Parcel* parcel) override;
+
+ bool has(uint32_t key) const;
+ int32_t getInt32(uint32_t key, int32_t fallback) const;
+ void setInt32(uint32_t key, int32_t value);
+
+ std::string itemToString(uint32_t key, const char* separator) const;
+};
+
+} // namespace android
diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h
index 02c6be2..c780c07 100644
--- a/libs/gui/include/gui/LayerState.h
+++ b/libs/gui/include/gui/LayerState.h
@@ -30,6 +30,7 @@
#include <input/InputWindow.h>
#endif
+#include <gui/LayerMetadata.h>
#include <math/vec3.h>
#include <ui/GraphicTypes.h>
#include <ui/Rect.h>
@@ -84,6 +85,9 @@
eInputInfoChanged = 0x40000000,
eCornerRadiusChanged = 0x80000000,
eFrameChanged = 0x1'00000000,
+ eCachedBufferChanged = 0x2'00000000,
+ eBackgroundColorChanged = 0x4'00000000,
+ eMetadataChanged = 0x8'00000000,
};
layer_state_t()
@@ -109,7 +113,9 @@
dataspace(ui::Dataspace::UNKNOWN),
surfaceDamageRegion(),
api(-1),
- colorTransform(mat4()) {
+ colorTransform(mat4()),
+ bgColorAlpha(0),
+ bgColorDataspace(ui::Dataspace::UNKNOWN) {
matrix.dsdx = matrix.dtdy = 1.0f;
matrix.dsdy = matrix.dtdx = 0.0f;
hdrMetadata.validTypes = 0;
@@ -125,6 +131,10 @@
float dtdy{0};
float dsdy{0};
};
+ struct cached_buffer_t {
+ sp<IBinder> token = nullptr;
+ int32_t bufferId = -1;
+ };
sp<IBinder> surface;
uint64_t what;
float x;
@@ -173,6 +183,15 @@
#ifndef NO_INPUT
InputWindowInfo inputInfo;
#endif
+
+ cached_buffer_t cachedBuffer;
+
+ LayerMetadata metadata;
+
+ // The following refer to the alpha, and dataspace, respectively of
+ // the background color layer
+ float bgColorAlpha;
+ ui::Dataspace bgColorDataspace;
};
struct ComposerState {
@@ -228,6 +247,20 @@
status_t read(const Parcel& input);
};
+struct InputWindowCommands {
+ struct TransferTouchFocusCommand {
+ sp<IBinder> fromToken;
+ sp<IBinder> toToken;
+ };
+
+ std::vector<TransferTouchFocusCommand> transferTouchFocusCommands;
+
+ void merge(const InputWindowCommands& other);
+ void clear();
+ void write(Parcel& output) const;
+ void read(const Parcel& input);
+};
+
static inline int compare_type(const ComposerState& lhs, const ComposerState& rhs) {
if (lhs.client < rhs.client) return -1;
if (lhs.client > rhs.client) return 1;
diff --git a/libs/gui/include/gui/StreamSplitter.h b/libs/gui/include/gui/StreamSplitter.h
index 8f47eb4..b4eef29 100644
--- a/libs/gui/include/gui/StreamSplitter.h
+++ b/libs/gui/include/gui/StreamSplitter.h
@@ -128,7 +128,7 @@
class BufferTracker : public LightRefBase<BufferTracker> {
public:
- BufferTracker(const sp<GraphicBuffer>& buffer);
+ explicit BufferTracker(const sp<GraphicBuffer>& buffer);
const sp<GraphicBuffer>& getBuffer() const { return mBuffer; }
const sp<Fence>& getMergedFence() const { return mMergedFence; }
@@ -154,7 +154,7 @@
};
// Only called from createSplitter
- StreamSplitter(const sp<IGraphicBufferConsumer>& inputQueue);
+ explicit StreamSplitter(const sp<IGraphicBufferConsumer>& inputQueue);
// Must be accessed through RefBase
virtual ~StreamSplitter();
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 8e3ba78..044106d 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -30,6 +30,7 @@
#include <utils/SortedVector.h>
#include <utils/threads.h>
+#include <ui/ConfigStoreTypes.h>
#include <ui/DisplayedFrameStats.h>
#include <ui/FrameStats.h>
#include <ui/GraphicTypes.h>
@@ -53,35 +54,24 @@
// ---------------------------------------------------------------------------
-using TransactionCompletedCallbackTakesContext =
- std::function<void(void* /*context*/, const TransactionStats&)>;
-using TransactionCompletedCallback = std::function<void(const TransactionStats&)>;
+struct SurfaceControlStats {
+ SurfaceControlStats(const sp<SurfaceControl>& sc, nsecs_t time,
+ const sp<Fence>& prevReleaseFence)
+ : surfaceControl(sc), acquireTime(time), previousReleaseFence(prevReleaseFence) {}
-class TransactionCompletedListener : public BnTransactionCompletedListener {
- TransactionCompletedListener();
-
- CallbackId getNextIdLocked() REQUIRES(mMutex);
-
- std::mutex mMutex;
-
- bool mListening GUARDED_BY(mMutex) = false;
-
- CallbackId mCallbackIdCounter GUARDED_BY(mMutex) = 1;
-
- std::map<CallbackId, TransactionCompletedCallback> mCallbacks GUARDED_BY(mMutex);
-
-public:
- static sp<TransactionCompletedListener> getInstance();
- static sp<ITransactionCompletedListener> getIInstance();
-
- void startListeningLocked() REQUIRES(mMutex);
-
- CallbackId addCallback(const TransactionCompletedCallback& callback);
-
- // Overrides BnTransactionCompletedListener's onTransactionCompleted
- void onTransactionCompleted(ListenerStats stats) override;
+ sp<SurfaceControl> surfaceControl;
+ nsecs_t acquireTime = -1;
+ sp<Fence> previousReleaseFence;
};
+using TransactionCompletedCallbackTakesContext =
+ std::function<void(void* /*context*/, nsecs_t /*latchTime*/,
+ const sp<Fence>& /*presentFence*/,
+ const std::vector<SurfaceControlStats>& /*stats*/)>;
+using TransactionCompletedCallback =
+ std::function<void(nsecs_t /*latchTime*/, const sp<Fence>& /*presentFence*/,
+ const std::vector<SurfaceControlStats>& /*stats*/)>;
+
// ---------------------------------------------------------------------------
class SurfaceComposerClient : public RefBase
@@ -90,7 +80,6 @@
public:
SurfaceComposerClient();
SurfaceComposerClient(const sp<ISurfaceComposerClient>& client);
- SurfaceComposerClient(const sp<IGraphicBufferProducer>& parent);
virtual ~SurfaceComposerClient();
// Always make sure we could initialize
@@ -126,6 +115,10 @@
static status_t getDisplayColorModes(const sp<IBinder>& display,
Vector<ui::ColorMode>* outColorModes);
+ // Get the coordinates of the display's native color primaries
+ static status_t getDisplayNativePrimaries(const sp<IBinder>& display,
+ ui::DisplayPrimaries& outPrimaries);
+
// Gets the active color mode for the given display
static ui::ColorMode getActiveColorMode(const sp<IBinder>& display);
@@ -146,31 +139,55 @@
ui::Dataspace* wideColorGamutDataspace,
ui::PixelFormat* wideColorGamutPixelFormat);
+ /*
+ * Gets whether SurfaceFlinger can support protected content in GPU composition.
+ * Requires the ACCESS_SURFACE_FLINGER permission.
+ */
+ static bool getProtectedContentSupport();
+
+ /**
+ * Called from SurfaceControl d'tor to 'destroy' the surface (or rather, reparent it
+ * to null), but without needing an sp<SurfaceControl> to avoid infinite ressurection.
+ */
+ static void doDropReferenceTransaction(const sp<IBinder>& handle,
+ const sp<ISurfaceComposerClient>& client);
+
+ // Queries whether a given display is wide color display.
+ static status_t isWideColorDisplay(const sp<IBinder>& display, bool* outIsWideColorDisplay);
+
// ------------------------------------------------------------------------
// surface creation / destruction
+ static sp<SurfaceComposerClient> getDefault();
+
//! Create a surface
- sp<SurfaceControl> createSurface(
- const String8& name,// name of the surface
- uint32_t w, // width in pixel
- uint32_t h, // height in pixel
- PixelFormat format, // pixel-format desired
- uint32_t flags = 0, // usage flags
- SurfaceControl* parent = nullptr, // parent
- int32_t windowType = -1, // from WindowManager.java (STATUS_BAR, INPUT_METHOD, etc.)
- int32_t ownerUid = -1 // UID of the task
+ sp<SurfaceControl> createSurface(const String8& name, // name of the surface
+ uint32_t w, // width in pixel
+ uint32_t h, // height in pixel
+ PixelFormat format, // pixel-format desired
+ uint32_t flags = 0, // usage flags
+ SurfaceControl* parent = nullptr, // parent
+ LayerMetadata metadata = LayerMetadata() // metadata
);
- status_t createSurfaceChecked(
- const String8& name,// name of the surface
- uint32_t w, // width in pixel
- uint32_t h, // height in pixel
- PixelFormat format, // pixel-format desired
- sp<SurfaceControl>* outSurface,
- uint32_t flags = 0, // usage flags
- SurfaceControl* parent = nullptr, // parent
- int32_t windowType = -1, // from WindowManager.java (STATUS_BAR, INPUT_METHOD, etc.)
- int32_t ownerUid = -1 // UID of the task
+ status_t createSurfaceChecked(const String8& name, // name of the surface
+ uint32_t w, // width in pixel
+ uint32_t h, // height in pixel
+ PixelFormat format, // pixel-format desired
+ sp<SurfaceControl>* outSurface,
+ uint32_t flags = 0, // usage flags
+ SurfaceControl* parent = nullptr, // parent
+ LayerMetadata metadata = LayerMetadata() // metadata
+ );
+
+ //! Create a surface
+ sp<SurfaceControl> createWithSurfaceParent(const String8& name, // name of the surface
+ uint32_t w, // width in pixel
+ uint32_t h, // height in pixel
+ PixelFormat format, // pixel-format desired
+ uint32_t flags = 0, // usage flags
+ Surface* parent = nullptr, // parent
+ LayerMetadata metadata = LayerMetadata() // metadata
);
//! Create a virtual display
@@ -219,6 +236,19 @@
bool mAnimation = false;
bool mEarlyWakeup = false;
+ // mDesiredPresentTime is the time in nanoseconds that the client would like the transaction
+ // to be presented. When it is not possible to present at exactly that time, it will be
+ // presented after the time has passed.
+ //
+ // Desired present times that are more than 1 second in the future may be ignored.
+ // When a desired present time has already passed, the transaction will be presented as soon
+ // as possible.
+ //
+ // Transactions from the same process are presented in the same order that they are applied.
+ // The desired present time does not affect this ordering.
+ int64_t mDesiredPresentTime = -1;
+
+ InputWindowCommands mInputWindowCommands;
int mStatus = NO_ERROR;
layer_state_t* getLayerState(const sp<SurfaceControl>& sc);
@@ -268,6 +298,8 @@
Transaction& setCrop_legacy(const sp<SurfaceControl>& sc, const Rect& crop);
Transaction& setCornerRadius(const sp<SurfaceControl>& sc, float cornerRadius);
Transaction& setLayerStack(const sp<SurfaceControl>& sc, uint32_t layerStack);
+ Transaction& setMetadata(const sp<SurfaceControl>& sc, uint32_t key,
+ std::vector<uint8_t> data);
// Defers applying any changes made in this transaction until the Layer
// identified by handle reaches the given frameNumber. If the Layer identified
// by handle is removed, then we will apply this transaction regardless of
@@ -292,12 +324,17 @@
Transaction& setColor(const sp<SurfaceControl>& sc, const half3& color);
+ // Sets the background color of a layer with the specified color, alpha, and dataspace
+ Transaction& setBackgroundColor(const sp<SurfaceControl>& sc, const half3& color,
+ float alpha, ui::Dataspace dataspace);
+
Transaction& setTransform(const sp<SurfaceControl>& sc, uint32_t transform);
Transaction& setTransformToDisplayInverse(const sp<SurfaceControl>& sc,
bool transformToDisplayInverse);
Transaction& setCrop(const sp<SurfaceControl>& sc, const Rect& crop);
Transaction& setFrame(const sp<SurfaceControl>& sc, const Rect& frame);
Transaction& setBuffer(const sp<SurfaceControl>& sc, const sp<GraphicBuffer>& buffer);
+ Transaction& setCachedBuffer(const sp<SurfaceControl>& sc, int32_t bufferId);
Transaction& setAcquireFence(const sp<SurfaceControl>& sc, const sp<Fence>& fence);
Transaction& setDataspace(const sp<SurfaceControl>& sc, ui::Dataspace dataspace);
Transaction& setHdrMetadata(const sp<SurfaceControl>& sc, const HdrMetadata& hdrMetadata);
@@ -306,6 +343,7 @@
Transaction& setApi(const sp<SurfaceControl>& sc, int32_t api);
Transaction& setSidebandStream(const sp<SurfaceControl>& sc,
const sp<NativeHandle>& sidebandStream);
+ Transaction& setDesiredPresentTime(nsecs_t desiredPresentTime);
Transaction& addTransactionCompletedCallback(
TransactionCompletedCallbackTakesContext callback, void* callbackContext);
@@ -335,14 +373,16 @@
#ifndef NO_INPUT
Transaction& setInputWindowInfo(const sp<SurfaceControl>& sc, const InputWindowInfo& info);
+ Transaction& transferTouchFocus(const sp<IBinder>& fromToken, const sp<IBinder>& toToken);
#endif
- Transaction& destroySurface(const sp<SurfaceControl>& sc);
-
// Set a color transform matrix on the given layer on the built-in display.
Transaction& setColorTransform(const sp<SurfaceControl>& sc, const mat3& matrix,
const vec3& translation);
+ Transaction& setGeometry(const sp<SurfaceControl>& sc,
+ const Rect& source, const Rect& dst, int transform);
+
status_t setDisplaySurface(const sp<IBinder>& token,
const sp<IGraphicBufferProducer>& bufferProducer);
@@ -367,8 +407,6 @@
void setEarlyWakeup();
};
- status_t destroySurface(const sp<IBinder>& id);
-
status_t clearLayerFrameStats(const sp<IBinder>& token) const;
status_t getLayerFrameStats(const sp<IBinder>& token, FrameStats* outStats) const;
static status_t clearAnimationFrameStats();
@@ -400,7 +438,6 @@
mutable Mutex mLock;
status_t mStatus;
sp<ISurfaceComposerClient> mClient;
- wp<IGraphicBufferProducer> mParent;
};
// ---------------------------------------------------------------------------
@@ -424,6 +461,50 @@
// ---------------------------------------------------------------------------
+class TransactionCompletedListener : public BnTransactionCompletedListener {
+ TransactionCompletedListener();
+
+ CallbackId getNextIdLocked() REQUIRES(mMutex);
+
+ std::mutex mMutex;
+
+ bool mListening GUARDED_BY(mMutex) = false;
+
+ CallbackId mCallbackIdCounter GUARDED_BY(mMutex) = 1;
+
+ struct IBinderHash {
+ std::size_t operator()(const sp<IBinder>& iBinder) const {
+ return std::hash<IBinder*>{}(iBinder.get());
+ }
+ };
+
+ struct CallbackTranslation {
+ TransactionCompletedCallback callbackFunction;
+ std::unordered_map<sp<IBinder>, sp<SurfaceControl>, IBinderHash> surfaceControls;
+ };
+
+ std::unordered_map<CallbackId, CallbackTranslation> mCallbacks GUARDED_BY(mMutex);
+
+public:
+ static sp<TransactionCompletedListener> getInstance();
+ static sp<ITransactionCompletedListener> getIInstance();
+
+ void startListeningLocked() REQUIRES(mMutex);
+
+ CallbackId addCallbackFunction(
+ const TransactionCompletedCallback& callbackFunction,
+ const std::unordered_set<sp<SurfaceControl>, SurfaceComposerClient::SCHash>&
+ surfaceControls);
+
+ void addSurfaceControlToCallbacks(const sp<SurfaceControl>& surfaceControl,
+ const std::unordered_set<CallbackId>& callbackIds);
+
+ // Overrides BnTransactionCompletedListener's onTransactionCompleted
+ void onTransactionCompleted(ListenerStats stats) override;
+};
+
+// ---------------------------------------------------------------------------
+
}; // namespace android
#endif // ANDROID_GUI_SURFACE_COMPOSER_CLIENT_H
diff --git a/libs/gui/include/gui/SurfaceControl.h b/libs/gui/include/gui/SurfaceControl.h
index ccb30fa..b584f36 100644
--- a/libs/gui/include/gui/SurfaceControl.h
+++ b/libs/gui/include/gui/SurfaceControl.h
@@ -71,10 +71,14 @@
sp<Surface> createSurface() const;
sp<IBinder> getHandle() const;
+ sp<IGraphicBufferProducer> getIGraphicBufferProducer() const;
+
status_t clearLayerFrameStats() const;
status_t getLayerFrameStats(FrameStats* outStats) const;
sp<SurfaceComposerClient> getClient() const;
+
+ explicit SurfaceControl(const sp<SurfaceControl>& other);
private:
// can't be copied
diff --git a/libs/gui/include/gui/bufferqueue/1.0/B2HProducerListener.h b/libs/gui/include/gui/bufferqueue/1.0/B2HProducerListener.h
index fa6c2d9..0f6fb45 100644
--- a/libs/gui/include/gui/bufferqueue/1.0/B2HProducerListener.h
+++ b/libs/gui/include/gui/bufferqueue/1.0/B2HProducerListener.h
@@ -50,7 +50,7 @@
struct B2HProducerListener : public HProducerListener {
sp<BProducerListener> mBase;
- B2HProducerListener(sp<BProducerListener> const& base);
+ explicit B2HProducerListener(sp<BProducerListener> const& base);
Return<void> onBufferReleased() override;
Return<bool> needsReleaseNotify() override;
};
diff --git a/libs/gui/include/gui/bufferqueue/1.0/H2BGraphicBufferProducer.h b/libs/gui/include/gui/bufferqueue/1.0/H2BGraphicBufferProducer.h
index 74850b4..c92fa9d 100644
--- a/libs/gui/include/gui/bufferqueue/1.0/H2BGraphicBufferProducer.h
+++ b/libs/gui/include/gui/bufferqueue/1.0/H2BGraphicBufferProducer.h
@@ -59,7 +59,7 @@
HGraphicBufferProducer,
BGraphicBufferProducer,
BnGraphicBufferProducer> {
- H2BGraphicBufferProducer(sp<HGraphicBufferProducer> const& base) : CBase(base) {}
+ explicit H2BGraphicBufferProducer(sp<HGraphicBufferProducer> const& base) : CBase(base) {}
status_t requestBuffer(int slot, sp<GraphicBuffer>* buf) override;
status_t setMaxDequeuedBufferCount(int maxDequeuedBuffers) override;
diff --git a/libs/gui/tests/EndToEndNativeInputTest.cpp b/libs/gui/tests/EndToEndNativeInputTest.cpp
index 60542bd..ac97733 100644
--- a/libs/gui/tests/EndToEndNativeInputTest.cpp
+++ b/libs/gui/tests/EndToEndNativeInputTest.cpp
@@ -133,6 +133,27 @@
EXPECT_EQ(AMOTION_EVENT_ACTION_UP, mev->getAction());
}
+ void expectMotionEvent(int motionEventType, int x, int y) {
+ InputEvent *ev = consumeEvent();
+ ASSERT_NE(ev, nullptr);
+ ASSERT_EQ(ev->getType(), AINPUT_EVENT_TYPE_MOTION);
+ MotionEvent *mev = static_cast<MotionEvent *>(ev);
+ EXPECT_EQ(motionEventType, mev->getAction());
+ EXPECT_EQ(x, mev->getX(0));
+ EXPECT_EQ(y, mev->getY(0));
+ }
+
+ void expectNoMotionEvent(int motionEventType) {
+ InputEvent *ev = consumeEvent();
+ if (ev == nullptr || ev->getType() != AINPUT_EVENT_TYPE_MOTION) {
+ // Didn't find an event or a motion event so assume action didn't occur.
+ return;
+ }
+
+ MotionEvent *mev = static_cast<MotionEvent *>(ev);
+ EXPECT_NE(motionEventType, mev->getAction());
+ }
+
~InputSurface() {
mInputFlinger->unregisterInputChannel(mServerChannel);
}
@@ -255,6 +276,15 @@
}
}
+void injectMotionEvent(std::string event, int x, int y) {
+ char *buf1, *buf2;
+ asprintf(&buf1, "%d", x);
+ asprintf(&buf2, "%d", y);
+ if (fork() == 0) {
+ execlp("input", "input", "motionevent", event.c_str(), buf1, buf2, NULL);
+ }
+}
+
TEST_F(InputSurfacesTest, can_receive_input) {
std::unique_ptr<InputSurface> surface = makeSurface(100, 100);
surface->showAt(100, 100);
@@ -439,5 +469,33 @@
injectTap(11, 11);
bgSurface->expectTap(1, 1);
}
+
+TEST_F(InputSurfacesTest, transfer_touch_focus) {
+ std::unique_ptr<InputSurface> fromSurface = makeSurface(100, 100);
+
+ fromSurface->showAt(10, 10);
+ injectMotionEvent("DOWN", 11, 11);
+ fromSurface->expectMotionEvent(AMOTION_EVENT_ACTION_DOWN, 1, 1);
+
+ std::unique_ptr<InputSurface> toSurface = makeSurface(100, 100);
+ toSurface->showAt(10, 10);
+
+ sp<IBinder> fromToken = fromSurface->mServerChannel->getToken();
+ sp<IBinder> toToken = toSurface->mServerChannel->getToken();
+ SurfaceComposerClient::Transaction t;
+ t.transferTouchFocus(fromToken, toToken).apply(true);
+
+ injectMotionEvent("UP", 11, 11);
+ toSurface->expectMotionEvent(AMOTION_EVENT_ACTION_UP, 1, 1);
+ fromSurface->expectNoMotionEvent(AMOTION_EVENT_ACTION_UP);
+}
+
+TEST_F(InputSurfacesTest, input_respects_outscreen) {
+ std::unique_ptr<InputSurface> surface = makeSurface(100, 100);
+ surface->showAt(-1, -1);
+
+ injectTap(0, 0);
+ surface->expectTap(1, 1);
+}
}
}
diff --git a/libs/gui/tests/Malicious.cpp b/libs/gui/tests/Malicious.cpp
index bb6b8a5..acd4297 100644
--- a/libs/gui/tests/Malicious.cpp
+++ b/libs/gui/tests/Malicious.cpp
@@ -27,7 +27,7 @@
class ProxyBQP : public BnGraphicBufferProducer {
public:
- ProxyBQP(const sp<IGraphicBufferProducer>& producer) : mProducer(producer) {}
+ explicit ProxyBQP(const sp<IGraphicBufferProducer>& producer) : mProducer(producer) {}
// Pass through calls to mProducer
status_t requestBuffer(int slot, sp<GraphicBuffer>* buf) override {
@@ -102,7 +102,7 @@
class MaliciousBQP : public ProxyBQP {
public:
- MaliciousBQP(const sp<IGraphicBufferProducer>& producer) : ProxyBQP(producer) {}
+ explicit MaliciousBQP(const sp<IGraphicBufferProducer>& producer) : ProxyBQP(producer) {}
void beMalicious(int32_t value) { mMaliciousValue = value; }
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index c56304f..8bd589d 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -545,10 +545,6 @@
}
sp<ISurfaceComposerClient> createConnection() override { return nullptr; }
- sp<ISurfaceComposerClient> createScopedConnection(
- const sp<IGraphicBufferProducer>& /* parent */) override {
- return nullptr;
- }
sp<IDisplayEventConnection> createDisplayEventConnection(ISurfaceComposer::VsyncSource)
override {
return nullptr;
@@ -559,7 +555,10 @@
sp<IBinder> getBuiltInDisplay(int32_t /*id*/) override { return nullptr; }
void setTransactionState(const Vector<ComposerState>& /*state*/,
const Vector<DisplayState>& /*displays*/, uint32_t /*flags*/,
- const sp<IBinder>& /*applyToken*/) override {}
+ const sp<IBinder>& /*applyToken*/,
+ const InputWindowCommands& /*inputWindowCommands*/,
+ int64_t /*desiredPresentTime*/) override {}
+
void bootFinished() override {}
bool authenticateSurfaceTexture(
const sp<IGraphicBufferProducer>& /*surface*/) const override {
@@ -599,6 +598,10 @@
Vector<ColorMode>* /*outColorModes*/) override {
return NO_ERROR;
}
+ status_t getDisplayNativePrimaries(const sp<IBinder>& /*display*/,
+ ui::DisplayPrimaries& /*primaries*/) override {
+ return NO_ERROR;
+ }
ColorMode getActiveColorMode(const sp<IBinder>& /*display*/)
override {
return ColorMode::NATIVE;
@@ -658,7 +661,10 @@
return NO_ERROR;
}
- virtual status_t getColorManagement(bool* /*outGetColorManagement*/) const { return NO_ERROR; }
+ status_t getColorManagement(bool* /*outGetColorManagement*/) const override { return NO_ERROR; }
+ status_t getProtectedContentSupport(bool* /*outSupported*/) const override { return NO_ERROR; }
+
+ status_t isWideColorDisplay(const sp<IBinder>&, bool*) const override { return NO_ERROR; }
protected:
IBinder* onAsBinder() override { return nullptr; }
@@ -669,8 +675,7 @@
class FakeProducerFrameEventHistory : public ProducerFrameEventHistory {
public:
- FakeProducerFrameEventHistory(FenceToFenceTimeMap* fenceMap)
- : mFenceMap(fenceMap) {}
+ explicit FakeProducerFrameEventHistory(FenceToFenceTimeMap* fenceMap) : mFenceMap(fenceMap) {}
~FakeProducerFrameEventHistory() {}
diff --git a/libs/incidentcompanion/Android.bp b/libs/incidentcompanion/Android.bp
new file mode 100644
index 0000000..45eab00
--- /dev/null
+++ b/libs/incidentcompanion/Android.bp
@@ -0,0 +1,48 @@
+/**
+ * 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.
+ */
+
+filegroup {
+ name: "incidentcompanion_aidl",
+ srcs: [
+ "binder/android/os/IIncidentAuthListener.aidl",
+ "binder/android/os/IIncidentCompanion.aidl",
+ ],
+ path: "binder",
+}
+
+cc_library_static {
+ name: "libincidentcompanion",
+ shared_libs: [
+ "libbinder",
+ "libutils",
+ ],
+ aidl: {
+ local_include_dirs: ["binder"],
+ export_aidl_headers: true,
+ },
+ srcs: [
+ ":incidentcompanion_aidl",
+ ],
+ export_include_dirs: ["binder"],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-Wno-missing-field-initializers",
+ "-Wno-unused-variable",
+ "-Wunused-parameter",
+ ],
+}
+
diff --git a/cmds/dumpstate/binder/android/os/DumpstateOptions.aidl b/libs/incidentcompanion/binder/android/os/IIncidentAuthListener.aidl
similarity index 66%
rename from cmds/dumpstate/binder/android/os/DumpstateOptions.aidl
rename to libs/incidentcompanion/binder/android/os/IIncidentAuthListener.aidl
index c1a7f15..5484be8 100644
--- a/cmds/dumpstate/binder/android/os/DumpstateOptions.aidl
+++ b/libs/incidentcompanion/binder/android/os/IIncidentAuthListener.aidl
@@ -17,7 +17,18 @@
package android.os;
/**
- * Specifies arguments for IDumpstate.
- * {@hide}
- */
-parcelable DumpstateOptions cpp_header "android/os/DumpstateOptions.h";
+ * Callback for IIncidentCompanion.
+ *
+ * @hide
+ */
+oneway interface IIncidentAuthListener {
+ /**
+ * The user approved the incident or bug report to be sent.
+ */
+ void onReportApproved();
+
+ /**
+ * The user did not approve the incident or bug report to be sent.
+ */
+ void onReportDenied();
+}
diff --git a/libs/incidentcompanion/binder/android/os/IIncidentCompanion.aidl b/libs/incidentcompanion/binder/android/os/IIncidentCompanion.aidl
new file mode 100644
index 0000000..6bf98d2
--- /dev/null
+++ b/libs/incidentcompanion/binder/android/os/IIncidentCompanion.aidl
@@ -0,0 +1,72 @@
+/**
+ * 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.
+ */
+
+package android.os;
+
+import android.os.IIncidentAuthListener;
+
+/**
+ * Helper service for incidentd and dumpstated to provide user feedback
+ * and authorization for bug and inicdent reports to be taken.
+ *
+ * @hide
+ */
+interface IIncidentCompanion {
+ /**
+ * Request an authorization for an incident or bug report.
+ * // TODO(b/111441001): Add the permission
+ * <p>
+ * This function requires the ___ permission.
+ *
+ * @param callingUid The original application that requested the report. This function
+ * returns via the callback whether the application should be trusted. It is up
+ * to the caller to actually implement the restriction to take or not take
+ * the incident or bug report.
+ * @param flags FLAG_CONFIRMATION_DIALOG (0x1) - to show this as a dialog. Otherwise
+ * a dialog will be shown as a notification.
+ * @param callback Interface to receive results. The results may not come back for
+ * a long (user's choice) time, or ever (if they never respond to the notification).
+ * Authorization requests are not persisted across reboot. It is up to the calling
+ * service to request another authorization after reboot if they still would like
+ * to send their report.
+ */
+ oneway void authorizeReport(int callingUid, String callingPackage,
+ int flags, IIncidentAuthListener callback);
+
+ /**
+ * Cancel an authorization.
+ */
+ oneway void cancelAuthorization(IIncidentAuthListener callback);
+
+ /**
+ * Return the list of pending approvals.
+ */
+ List<String> getPendingReports();
+
+ /**
+ * The user has authorized the report to be shared.
+ *
+ * @param uri the report.
+ */
+ void approveReport(String uri);
+
+ /**
+ * The user has denied the report from being shared.
+ *
+ * @param uri the report.
+ */
+ void denyReport(String uri);
+}
diff --git a/libs/input/IInputFlinger.cpp b/libs/input/IInputFlinger.cpp
index 139570a..acf40bc 100644
--- a/libs/input/IInputFlinger.cpp
+++ b/libs/input/IInputFlinger.cpp
@@ -42,6 +42,16 @@
IBinder::FLAG_ONEWAY);
}
+ virtual void transferTouchFocus(const sp<IBinder>& fromToken, const sp<IBinder>& toToken) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IInputFlinger::getInterfaceDescriptor());
+
+ data.writeStrongBinder(fromToken);
+ data.writeStrongBinder(toToken);
+ remote()->transact(BnInputFlinger::TRANSFER_TOUCH_FOCUS, data, &reply,
+ IBinder::FLAG_ONEWAY);
+ }
+
virtual void registerInputChannel(const sp<InputChannel>& channel) {
Parcel data, reply;
data.writeInterfaceToken(IInputFlinger::getInterfaceDescriptor());
@@ -90,6 +100,13 @@
unregisterInputChannel(channel);
break;
}
+ case TRANSFER_TOUCH_FOCUS: {
+ CHECK_INTERFACE(IInputFlinger, data, reply);
+ sp<IBinder> fromToken = data.readStrongBinder();
+ sp<IBinder> toToken = data.readStrongBinder();
+ transferTouchFocus(fromToken, toToken);
+ break;
+ }
default:
return BBinder::onTransact(code, data, reply, flags);
}
diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp
index a558970..9fd25f9 100644
--- a/libs/input/Input.cpp
+++ b/libs/input/Input.cpp
@@ -29,6 +29,17 @@
namespace android {
+const char* motionClassificationToString(MotionClassification classification) {
+ switch (classification) {
+ case MotionClassification::NONE:
+ return "NONE";
+ case MotionClassification::AMBIGUOUS_GESTURE:
+ return "AMBIGUOUS_GESTURE";
+ case MotionClassification::DEEP_PRESS:
+ return "DEEP_PRESS";
+ }
+}
+
// --- InputEvent ---
void InputEvent::initialize(int32_t deviceId, int32_t source, int32_t displayId) {
@@ -234,6 +245,7 @@
int32_t edgeFlags,
int32_t metaState,
int32_t buttonState,
+ MotionClassification classification,
float xOffset,
float yOffset,
float xPrecision,
@@ -250,6 +262,7 @@
mEdgeFlags = edgeFlags;
mMetaState = metaState;
mButtonState = buttonState;
+ mClassification = classification;
mXOffset = xOffset;
mYOffset = yOffset;
mXPrecision = xPrecision;
@@ -270,6 +283,7 @@
mEdgeFlags = other->mEdgeFlags;
mMetaState = other->mMetaState;
mButtonState = other->mButtonState;
+ mClassification = other->mClassification;
mXOffset = other->mXOffset;
mYOffset = other->mYOffset;
mXPrecision = other->mXPrecision;
@@ -451,6 +465,7 @@
mEdgeFlags = parcel->readInt32();
mMetaState = parcel->readInt32();
mButtonState = parcel->readInt32();
+ mClassification = static_cast<MotionClassification>(parcel->readByte());
mXOffset = parcel->readFloat();
mYOffset = parcel->readFloat();
mXPrecision = parcel->readFloat();
@@ -501,6 +516,7 @@
parcel->writeInt32(mEdgeFlags);
parcel->writeInt32(mMetaState);
parcel->writeInt32(mButtonState);
+ parcel->writeByte(static_cast<int8_t>(mClassification));
parcel->writeFloat(mXOffset);
parcel->writeFloat(mYOffset);
parcel->writeFloat(mXPrecision);
diff --git a/libs/input/InputTransport.cpp b/libs/input/InputTransport.cpp
index f33b210..0f7a1f0 100644
--- a/libs/input/InputTransport.cpp
+++ b/libs/input/InputTransport.cpp
@@ -157,6 +157,8 @@
msg->body.motion.metaState = body.motion.metaState;
// int32_t buttonState
msg->body.motion.buttonState = body.motion.buttonState;
+ // MotionClassification classification
+ msg->body.motion.classification = body.motion.classification;
// int32_t edgeFlags
msg->body.motion.edgeFlags = body.motion.edgeFlags;
// nsecs_t downTime
@@ -448,6 +450,7 @@
int32_t edgeFlags,
int32_t metaState,
int32_t buttonState,
+ MotionClassification classification,
float xOffset,
float yOffset,
float xPrecision,
@@ -461,13 +464,13 @@
ALOGD("channel '%s' publisher ~ publishMotionEvent: seq=%u, deviceId=%d, source=0x%x, "
"displayId=%" PRId32 ", "
"action=0x%x, actionButton=0x%08x, flags=0x%x, edgeFlags=0x%x, "
- "metaState=0x%x, buttonState=0x%x, xOffset=%f, yOffset=%f, "
+ "metaState=0x%x, buttonState=0x%x, classification=%s, xOffset=%f, yOffset=%f, "
"xPrecision=%f, yPrecision=%f, downTime=%" PRId64 ", eventTime=%" PRId64 ", "
"pointerCount=%" PRIu32,
mChannel->getName().c_str(), seq,
deviceId, source, displayId, action, actionButton, flags, edgeFlags, metaState,
- buttonState, xOffset, yOffset, xPrecision, yPrecision, downTime, eventTime,
- pointerCount);
+ buttonState, motionClassificationToString(classification),
+ xOffset, yOffset, xPrecision, yPrecision, downTime, eventTime, pointerCount);
#endif
if (!seq) {
@@ -493,6 +496,7 @@
msg.body.motion.edgeFlags = edgeFlags;
msg.body.motion.metaState = metaState;
msg.body.motion.buttonState = buttonState;
+ msg.body.motion.classification = classification;
msg.body.motion.xOffset = xOffset;
msg.body.motion.yOffset = yOffset;
msg.body.motion.xPrecision = xPrecision;
@@ -1112,6 +1116,7 @@
msg->body.motion.edgeFlags,
msg->body.motion.metaState,
msg->body.motion.buttonState,
+ msg->body.motion.classification,
msg->body.motion.xOffset,
msg->body.motion.yOffset,
msg->body.motion.xPrecision,
diff --git a/libs/input/InputWindow.cpp b/libs/input/InputWindow.cpp
index aa1371f..5c5613d 100644
--- a/libs/input/InputWindow.cpp
+++ b/libs/input/InputWindow.cpp
@@ -95,6 +95,7 @@
output.writeInt32(ownerUid);
output.writeInt32(inputFeatures);
output.writeInt32(displayId);
+ output.writeInt32(portalToDisplayId);
applicationInfo.write(output);
output.write(touchableRegion);
@@ -136,6 +137,7 @@
ret.ownerUid = from.readInt32();
ret.inputFeatures = from.readInt32();
ret.displayId = from.readInt32();
+ ret.portalToDisplayId = from.readInt32();
ret.applicationInfo = InputApplicationInfo::read(from);
from.read(ret.touchableRegion);
diff --git a/libs/input/tests/InputChannel_test.cpp b/libs/input/tests/InputChannel_test.cpp
index 96c165c..f1675c0 100644
--- a/libs/input/tests/InputChannel_test.cpp
+++ b/libs/input/tests/InputChannel_test.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#include <array>
+
#include "TestHelpers.h"
#include <unistd.h>
@@ -155,5 +157,37 @@
<< "sendMessage should have returned DEAD_OBJECT";
}
+TEST_F(InputChannelTest, SendAndReceive_MotionClassification) {
+ sp<InputChannel> serverChannel, clientChannel;
+ status_t result = InputChannel::openInputChannelPair("channel name",
+ serverChannel, clientChannel);
+ ASSERT_EQ(OK, result)
+ << "should have successfully opened a channel pair";
+
+ std::array<MotionClassification, 3> classifications = {
+ MotionClassification::NONE,
+ MotionClassification::AMBIGUOUS_GESTURE,
+ MotionClassification::DEEP_PRESS,
+ };
+
+ InputMessage serverMsg = {}, clientMsg;
+ serverMsg.header.type = InputMessage::TYPE_MOTION;
+ serverMsg.body.motion.seq = 1;
+ serverMsg.body.motion.pointerCount = 1;
+
+ for (MotionClassification classification : classifications) {
+ // Send and receive a message with classification
+ serverMsg.body.motion.classification = classification;
+ EXPECT_EQ(OK, serverChannel->sendMessage(&serverMsg))
+ << "server channel should be able to send message to client channel";
+
+ EXPECT_EQ(OK, clientChannel->receiveMessage(&clientMsg))
+ << "client channel should be able to receive message from server channel";
+ EXPECT_EQ(serverMsg.header.type, clientMsg.header.type);
+ EXPECT_EQ(classification, clientMsg.body.motion.classification) <<
+ "Expected to receive " << motionClassificationToString(classification);
+ }
+}
+
} // namespace android
diff --git a/libs/input/tests/InputEvent_test.cpp b/libs/input/tests/InputEvent_test.cpp
index 99f83ba..2b75c82 100644
--- a/libs/input/tests/InputEvent_test.cpp
+++ b/libs/input/tests/InputEvent_test.cpp
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#include <array>
#include <math.h>
#include <binder/Parcel.h>
@@ -25,11 +26,7 @@
// Default display id.
static constexpr int32_t DISPLAY_ID = ADISPLAY_ID_DEFAULT;
-class BaseTest : public testing::Test {
-protected:
- virtual void SetUp() { }
- virtual void TearDown() { }
-};
+class BaseTest : public testing::Test { };
// --- PointerCoordsTest ---
@@ -260,7 +257,7 @@
event->initialize(2, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID, AMOTION_EVENT_ACTION_MOVE, 0,
AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED,
AMOTION_EVENT_EDGE_FLAG_TOP, AMETA_ALT_ON, AMOTION_EVENT_BUTTON_PRIMARY,
- X_OFFSET, Y_OFFSET, 2.0f, 2.1f,
+ MotionClassification::NONE, X_OFFSET, Y_OFFSET, 2.0f, 2.1f,
ARBITRARY_DOWN_TIME, ARBITRARY_EVENT_TIME,
2, pointerProperties, pointerCoords);
@@ -316,6 +313,7 @@
ASSERT_EQ(AMOTION_EVENT_EDGE_FLAG_TOP, event->getEdgeFlags());
ASSERT_EQ(AMETA_ALT_ON, event->getMetaState());
ASSERT_EQ(AMOTION_EVENT_BUTTON_PRIMARY, event->getButtonState());
+ ASSERT_EQ(MotionClassification::NONE, event->getClassification());
ASSERT_EQ(X_OFFSET, event->getXOffset());
ASSERT_EQ(Y_OFFSET, event->getYOffset());
ASSERT_EQ(2.0f, event->getXPrecision());
@@ -572,8 +570,11 @@
pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, angle);
}
MotionEvent event;
- event.initialize(0, 0, DISPLAY_ID, AMOTION_EVENT_ACTION_MOVE, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, pointerCount, pointerProperties, pointerCoords);
+ event.initialize(0 /*deviceId*/, AINPUT_SOURCE_UNKNOWN, DISPLAY_ID, AMOTION_EVENT_ACTION_MOVE,
+ 0 /*actionButton*/, 0 /*flags*/, AMOTION_EVENT_EDGE_FLAG_NONE,
+ AMETA_NONE, 0 /*buttonState*/, MotionClassification::NONE,
+ 0 /*xOffset*/, 0 /*yOffset*/, 0 /*xPrecision*/, 0 /*yPrecision*/,
+ 0 /*downTime*/, 0 /*eventTime*/, pointerCount, pointerProperties, pointerCoords);
float originalRawX = 0 + 3;
float originalRawY = -RADIUS + 2;
@@ -606,4 +607,30 @@
ASSERT_NEAR(originalRawY, event.getRawY(0), 0.001);
}
+TEST_F(MotionEventTest, Initialize_SetsClassification) {
+ std::array<MotionClassification, 3> classifications = {
+ MotionClassification::NONE,
+ MotionClassification::AMBIGUOUS_GESTURE,
+ MotionClassification::DEEP_PRESS,
+ };
+
+ MotionEvent event;
+ constexpr size_t pointerCount = 1;
+ PointerProperties pointerProperties[pointerCount];
+ PointerCoords pointerCoords[pointerCount];
+ for (size_t i = 0; i < pointerCount; i++) {
+ pointerProperties[i].clear();
+ pointerProperties[i].id = i;
+ pointerCoords[i].clear();
+ }
+
+ for (MotionClassification classification : classifications) {
+ event.initialize(0 /*deviceId*/, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID,
+ AMOTION_EVENT_ACTION_DOWN, 0, 0, AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE, 0,
+ classification, 0, 0, 0, 0, 0 /*downTime*/, 0 /*eventTime*/,
+ pointerCount, pointerProperties, pointerCoords);
+ ASSERT_EQ(classification, event.getClassification());
+ }
+}
+
} // namespace android
diff --git a/libs/input/tests/InputPublisherAndConsumer_test.cpp b/libs/input/tests/InputPublisherAndConsumer_test.cpp
index 0788c89..f2cd1be 100644
--- a/libs/input/tests/InputPublisherAndConsumer_test.cpp
+++ b/libs/input/tests/InputPublisherAndConsumer_test.cpp
@@ -141,6 +141,7 @@
constexpr int32_t edgeFlags = AMOTION_EVENT_EDGE_FLAG_TOP;
constexpr int32_t metaState = AMETA_ALT_LEFT_ON | AMETA_ALT_ON;
constexpr int32_t buttonState = AMOTION_EVENT_BUTTON_PRIMARY;
+ constexpr MotionClassification classification = MotionClassification::AMBIGUOUS_GESTURE;
constexpr float xOffset = -10;
constexpr float yOffset = -20;
constexpr float xPrecision = 0.25;
@@ -168,8 +169,8 @@
}
status = mPublisher->publishMotionEvent(seq, deviceId, source, displayId, action, actionButton,
- flags, edgeFlags, metaState, buttonState, xOffset, yOffset, xPrecision, yPrecision,
- downTime, eventTime, pointerCount,
+ flags, edgeFlags, metaState, buttonState, classification,
+ xOffset, yOffset, xPrecision, yPrecision, downTime, eventTime, pointerCount,
pointerProperties, pointerCoords);
ASSERT_EQ(OK, status)
<< "publisher publishMotionEvent should return OK";
@@ -195,6 +196,7 @@
EXPECT_EQ(edgeFlags, motionEvent->getEdgeFlags());
EXPECT_EQ(metaState, motionEvent->getMetaState());
EXPECT_EQ(buttonState, motionEvent->getButtonState());
+ EXPECT_EQ(classification, motionEvent->getClassification());
EXPECT_EQ(xPrecision, motionEvent->getXPrecision());
EXPECT_EQ(yPrecision, motionEvent->getYPrecision());
EXPECT_EQ(downTime, motionEvent->getDownTime());
@@ -264,7 +266,8 @@
pointerCoords[i].clear();
}
- status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ MotionClassification::NONE, 0, 0, 0, 0, 0, 0,
pointerCount, pointerProperties, pointerCoords);
ASSERT_EQ(BAD_VALUE, status)
<< "publisher publishMotionEvent should return BAD_VALUE";
@@ -276,7 +279,8 @@
PointerProperties pointerProperties[pointerCount];
PointerCoords pointerCoords[pointerCount];
- status = mPublisher->publishMotionEvent(1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ status = mPublisher->publishMotionEvent(1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ MotionClassification::NONE, 0, 0, 0, 0, 0, 0,
pointerCount, pointerProperties, pointerCoords);
ASSERT_EQ(BAD_VALUE, status)
<< "publisher publishMotionEvent should return BAD_VALUE";
@@ -293,7 +297,8 @@
pointerCoords[i].clear();
}
- status = mPublisher->publishMotionEvent(1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ status = mPublisher->publishMotionEvent(1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ MotionClassification::NONE, 0, 0, 0, 0, 0, 0,
pointerCount, pointerProperties, pointerCoords);
ASSERT_EQ(BAD_VALUE, status)
<< "publisher publishMotionEvent should return BAD_VALUE";
diff --git a/libs/input/tests/InputWindow_test.cpp b/libs/input/tests/InputWindow_test.cpp
index 5e5893f..09dd72b 100644
--- a/libs/input/tests/InputWindow_test.cpp
+++ b/libs/input/tests/InputWindow_test.cpp
@@ -61,6 +61,7 @@
i.ownerUid = 24;
i.inputFeatures = 29;
i.displayId = 34;
+ i.portalToDisplayId = 2;
Parcel p;
i.write(p);
@@ -90,6 +91,7 @@
ASSERT_EQ(i.ownerUid, i2.ownerUid);
ASSERT_EQ(i.inputFeatures, i2.inputFeatures);
ASSERT_EQ(i.displayId, i2.displayId);
+ ASSERT_EQ(i.portalToDisplayId, i2.portalToDisplayId);
}
} // namespace test
diff --git a/libs/input/tests/StructLayout_test.cpp b/libs/input/tests/StructLayout_test.cpp
index 12a6782..62023fb 100644
--- a/libs/input/tests/StructLayout_test.cpp
+++ b/libs/input/tests/StructLayout_test.cpp
@@ -57,7 +57,8 @@
CHECK_OFFSET(InputMessage::Body::Motion, flags, 36);
CHECK_OFFSET(InputMessage::Body::Motion, metaState, 40);
CHECK_OFFSET(InputMessage::Body::Motion, buttonState, 44);
- CHECK_OFFSET(InputMessage::Body::Motion, edgeFlags, 48);
+ CHECK_OFFSET(InputMessage::Body::Motion, classification, 48);
+ CHECK_OFFSET(InputMessage::Body::Motion, edgeFlags, 52);
CHECK_OFFSET(InputMessage::Body::Motion, downTime, 56);
CHECK_OFFSET(InputMessage::Body::Motion, xOffset, 64);
CHECK_OFFSET(InputMessage::Body::Motion, yOffset, 68);
diff --git a/libs/input/tests/VelocityTracker_test.cpp b/libs/input/tests/VelocityTracker_test.cpp
index af97c34..3c67542 100644
--- a/libs/input/tests/VelocityTracker_test.cpp
+++ b/libs/input/tests/VelocityTracker_test.cpp
@@ -90,7 +90,8 @@
MotionEvent* event = new MotionEvent();
PointerCoords coords;
- PointerProperties properties[1];
+ constexpr size_t pointerCount = 1;
+ PointerProperties properties[pointerCount];
properties[0].id = DEFAULT_POINTER_ID;
properties[0].toolType = AMOTION_EVENT_TOOL_TYPE_FINGER;
@@ -98,8 +99,11 @@
// First sample added separately with initialize
coords.setAxisValue(AMOTION_EVENT_AXIS_X, positions[0].x);
coords.setAxisValue(AMOTION_EVENT_AXIS_Y, positions[0].y);
- event->initialize(0, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID, AMOTION_EVENT_ACTION_MOVE,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, positions[0].time, 1, properties, &coords);
+ event->initialize(0 /*deviceId*/, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID,
+ AMOTION_EVENT_ACTION_MOVE, 0 /*actionButton*/, 0 /*flags*/,
+ AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE, 0 /*buttonState*/, MotionClassification::NONE,
+ 0 /*xOffset*/, 0 /*yOffset*/, 0 /*xPrecision*/, 0 /*yPrecision*/,
+ 0 /*downTime*/, positions[0].time, pointerCount, properties, &coords);
for (size_t i = 1; i < numSamples; i++) {
coords.setAxisValue(AMOTION_EVENT_AXIS_X, positions[i].x);
diff --git a/libs/math/OWNERS b/libs/math/OWNERS
new file mode 100644
index 0000000..6fb149a
--- /dev/null
+++ b/libs/math/OWNERS
@@ -0,0 +1,6 @@
+jaesoo@google.com
+jiyong@google.com
+mathias@google.com
+pawin@google.com
+randolphs@google.com
+romainguy@google.com
diff --git a/libs/nativewindow/AHardwareBuffer.cpp b/libs/nativewindow/AHardwareBuffer.cpp
index a19fe17..6ea1270 100644
--- a/libs/nativewindow/AHardwareBuffer.cpp
+++ b/libs/nativewindow/AHardwareBuffer.cpp
@@ -268,7 +268,11 @@
AHardwareBuffer_Desc trialDesc = *desc;
trialDesc.width = 4;
trialDesc.height = desc->format == AHARDWAREBUFFER_FORMAT_BLOB ? 1 : 4;
- trialDesc.layers = desc->layers == 1 ? 1 : 2;
+ if (desc->usage & AHARDWAREBUFFER_USAGE_GPU_CUBE_MAP) {
+ trialDesc.layers = desc->layers == 6 ? 6 : 12;
+ } else {
+ trialDesc.layers = desc->layers == 1 ? 1 : 2;
+ }
AHardwareBuffer* trialBuffer = nullptr;
int result = AHardwareBuffer_allocate(&trialDesc, &trialBuffer);
if (result == NO_ERROR) {
diff --git a/libs/nativewindow/include/android/hardware_buffer.h b/libs/nativewindow/include/android/hardware_buffer.h
index 03545a6..2796c75 100644
--- a/libs/nativewindow/include/android/hardware_buffer.h
+++ b/libs/nativewindow/include/android/hardware_buffer.h
@@ -208,6 +208,17 @@
*/
AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT = AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER,
/**
+ * The buffer will be used as a composer HAL overlay layer.
+ *
+ * This flag is currently only needed when using ASurfaceTransaction_setBuffer
+ * to set a buffer. In all other cases, the framework adds this flag
+ * internally to buffers that could be presented in a composer overlay.
+ * ASurfaceTransaction_setBuffer is special because it uses buffers allocated
+ * directly through AHardwareBuffer_allocate instead of buffers allocated
+ * by the framework.
+ */
+ AHARDWAREBUFFER_USAGE_COMPOSER_OVERLAY = 1ULL << 11,
+ /**
* The buffer is protected from direct CPU access or being read by
* non-secure hardware, such as video encoders.
*
diff --git a/libs/nativewindow/include/android/hdr_metadata.h b/libs/nativewindow/include/android/hdr_metadata.h
new file mode 100644
index 0000000..7e1313b
--- /dev/null
+++ b/libs/nativewindow/include/android/hdr_metadata.h
@@ -0,0 +1,65 @@
+/*
+ * 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.
+ */
+
+/**
+ * @file hdr_metadata.h
+ */
+
+#ifndef ANDROID_HDR_METADATA_H
+#define ANDROID_HDR_METADATA_H
+
+#include <inttypes.h>
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+/**
+ * These structures are used to define the display's capabilities for HDR content.
+ * They can be used to better tone map content to user's display.
+ */
+
+/**
+ * Color is defined in CIE XYZ coordinates.
+ */
+struct AColor_xy {
+ float x;
+ float y;
+};
+
+/**
+ * SMPTE ST 2086 "Mastering Display Color Volume" static metadata
+ */
+struct AHdrMetadata_smpte2086 {
+ struct AColor_xy displayPrimaryRed;
+ struct AColor_xy displayPrimaryGreen;
+ struct AColor_xy displayPrimaryBlue;
+ struct AColor_xy whitePoint;
+ float maxLuminance;
+ float minLuminance;
+};
+
+/**
+ * CTA 861.3 "HDR Static Metadata Extension" static metadata
+ */
+struct AHdrMetadata_cta861_3 {
+ float maxContentLightLevel;
+ float maxFrameAverageLightLevel;
+};
+
+__END_DECLS
+
+#endif // ANDROID_HDR_METADATA_H
diff --git a/libs/renderengine/Android.bp b/libs/renderengine/Android.bp
index d872f02..36211ca 100644
--- a/libs/renderengine/Android.bp
+++ b/libs/renderengine/Android.bp
@@ -26,6 +26,7 @@
"libgui",
"liblog",
"libnativewindow",
+ "libsync",
"libui",
"libutils",
],
@@ -79,3 +80,19 @@
thin: true,
},
}
+
+cc_library_static {
+ name: "librenderengine_mocks",
+ defaults: ["librenderengine_defaults"],
+ srcs: [
+ "mock/Framebuffer.cpp",
+ "mock/Image.cpp",
+ "mock/RenderEngine.cpp",
+ ],
+ static_libs: [
+ "libgtest",
+ "libgmock",
+ ],
+ local_include_dirs: ["include"],
+ export_include_dirs: ["include"],
+}
diff --git a/libs/renderengine/gl/GLESRenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp
index 51cf188..c5a9942 100644
--- a/libs/renderengine/gl/GLESRenderEngine.cpp
+++ b/libs/renderengine/gl/GLESRenderEngine.cpp
@@ -24,14 +24,17 @@
#include <math.h>
#include <fstream>
#include <sstream>
+#include <unordered_set>
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
#include <android-base/stringprintf.h>
#include <cutils/compiler.h>
+#include <cutils/properties.h>
#include <renderengine/Mesh.h>
#include <renderengine/Texture.h>
#include <renderengine/private/Description.h>
+#include <sync/sync.h>
#include <ui/ColorSpace.h>
#include <ui/DebugUtils.h>
#include <ui/Rect.h>
@@ -414,6 +417,13 @@
mBt2020ToSrgb = mXyzToSrgb * mBt2020ToXyz;
mBt2020ToDisplayP3 = mXyzToDisplayP3 * mBt2020ToXyz;
}
+
+ char value[PROPERTY_VALUE_MAX];
+ property_get("debug.egl.traceGpuCompletion", value, "0");
+ if (atoi(value)) {
+ mTraceGpuCompletion = true;
+ mFlushTracer = std::make_unique<FlushTracer>(this);
+ }
}
GLESRenderEngine::~GLESRenderEngine() {
@@ -459,6 +469,12 @@
ALOGW("failed to dup EGL native fence sync: %#x", eglGetError());
}
+ // Only trace if we have a valid fence, as current usage falls back to
+ // calling finish() if the fence fd is invalid.
+ if (CC_UNLIKELY(mTraceGpuCompletion && mFlushTracer) && fenceFd.get() >= 0) {
+ mFlushTracer->queueSync(eglCreateSyncKHR(mEGLDisplay, EGL_SYNC_FENCE_KHR, nullptr));
+ }
+
return fenceFd;
}
@@ -474,8 +490,15 @@
return false;
}
- EGLint result = eglClientWaitSyncKHR(mEGLDisplay, sync, EGL_SYNC_FLUSH_COMMANDS_BIT_KHR,
- 2000000000 /*2 sec*/);
+ if (CC_UNLIKELY(mTraceGpuCompletion && mFlushTracer)) {
+ mFlushTracer->queueSync(eglCreateSyncKHR(mEGLDisplay, EGL_SYNC_FENCE_KHR, nullptr));
+ }
+
+ return waitSync(sync, EGL_SYNC_FLUSH_COMMANDS_BIT_KHR);
+}
+
+bool GLESRenderEngine::waitSync(EGLSyncKHR sync, EGLint flags) {
+ EGLint result = eglClientWaitSyncKHR(mEGLDisplay, sync, flags, 2000000000 /*2 sec*/);
EGLint error = eglGetError();
eglDestroySyncKHR(mEGLDisplay, sync);
if (result != EGL_CONDITION_SATISFIED_KHR) {
@@ -584,6 +607,101 @@
}
}
+status_t GLESRenderEngine::bindExternalTextureBuffer(uint32_t texName, sp<GraphicBuffer> buffer,
+ sp<Fence> bufferFence, bool readCache,
+ bool persistCache) {
+ if (readCache) {
+ auto cachedImage = mImageCache.find(buffer->getId());
+
+ if (cachedImage != mImageCache.end()) {
+ bindExternalTextureImage(texName, *cachedImage->second);
+ return NO_ERROR;
+ }
+ }
+
+ std::unique_ptr<Image> newImage = createImage();
+
+ bool created = newImage->setNativeWindowBuffer(buffer->getNativeBuffer(),
+ buffer->getUsage() & GRALLOC_USAGE_PROTECTED);
+ if (!created) {
+ ALOGE("Failed to create image. size=%ux%u st=%u usage=%#" PRIx64 " fmt=%d",
+ buffer->getWidth(), buffer->getHeight(), buffer->getStride(), buffer->getUsage(),
+ buffer->getPixelFormat());
+ bindExternalTextureImage(texName, *createImage());
+ return NO_INIT;
+ }
+
+ bindExternalTextureImage(texName, *newImage);
+
+ // Wait for the new buffer to be ready.
+ if (bufferFence != nullptr && bufferFence->isValid()) {
+ if (GLExtensions::getInstance().hasWaitSync()) {
+ base::unique_fd fenceFd(bufferFence->dup());
+ if (fenceFd == -1) {
+ ALOGE("error dup'ing fence fd: %d", errno);
+ return -errno;
+ }
+ if (!waitFence(std::move(fenceFd))) {
+ ALOGE("failed to wait on fence fd");
+ return UNKNOWN_ERROR;
+ }
+ } else {
+ status_t err = bufferFence->waitForever("RenderEngine::bindExternalTextureBuffer");
+ if (err != NO_ERROR) {
+ ALOGE("error waiting for fence: %d", err);
+ return err;
+ }
+ }
+ }
+
+ // We don't always want to persist to the cache, e.g. on older devices we
+ // might bind for synchronization purpoeses, 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)));
+ }
+
+ return NO_ERROR;
+}
+
+void GLESRenderEngine::evictImages(const std::vector<LayerSettings>& layers) {
+ // 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());
+ }
+ }
+
+ for (auto it = mImageCache.begin(); it != mImageCache.end();) {
+ if (bufIds.count(it->first) == 0) {
+ it = mImageCache.erase(it);
+ } else {
+ it++;
+ }
+ }
+}
+
+FloatRect GLESRenderEngine::setupLayerCropping(const LayerSettings& layer, Mesh& mesh) {
+ // Translate win by the rounded corners rect coordinates, to have all values in
+ // layer coordinate space.
+ FloatRect cropWin = layer.geometry.boundaries;
+ const FloatRect& roundedCornersCrop = layer.geometry.roundedCornersCrop;
+ cropWin.left -= roundedCornersCrop.left;
+ cropWin.right -= roundedCornersCrop.left;
+ cropWin.top -= roundedCornersCrop.top;
+ cropWin.bottom -= roundedCornersCrop.top;
+ Mesh::VertexArray<vec2> cropCoords(mesh.getCropCoordArray<vec2>());
+ cropCoords[0] = vec2(cropWin.left, cropWin.top);
+ cropCoords[1] = vec2(cropWin.left, cropWin.top + cropWin.getHeight());
+ cropCoords[2] = vec2(cropWin.right, cropWin.top + cropWin.getHeight());
+ cropCoords[3] = vec2(cropWin.right, cropWin.top);
+
+ setupCornerRadiusCropSize(roundedCornersCrop.getWidth(), roundedCornersCrop.getHeight());
+ return cropWin;
+}
+
status_t GLESRenderEngine::bindFrameBuffer(Framebuffer* framebuffer) {
GLFramebuffer* glFramebuffer = static_cast<GLFramebuffer*>(framebuffer);
EGLImageKHR eglImage = glFramebuffer->getEGLImage();
@@ -666,39 +784,77 @@
return fbo.getStatus();
}
+ evictImages(layers);
+
setViewportAndProjection(display.physicalDisplay, display.clip);
setOutputDataSpace(display.outputDataspace);
setDisplayMaxLuminance(display.maxLuminance);
mat4 projectionMatrix = mState.projectionMatrix * display.globalTransform;
+ mState.projectionMatrix = projectionMatrix;
+ if (!display.clearRegion.isEmpty()) {
+ fillRegionWithColor(display.clearRegion, 0.0, 0.0, 0.0, 1.0);
+ }
- Mesh mesh(Mesh::TRIANGLE_FAN, 4, 2);
+ Mesh mesh(Mesh::TRIANGLE_FAN, 4, 2, 2);
for (auto layer : layers) {
- // for now, assume that all pixel sources are solid colors.
- // TODO(alecmouri): support buffer sources
- if (layer.source.buffer.buffer != nullptr) {
- continue;
- }
-
- setColorTransform(display.colorTransform * layer.colorTransform);
-
mState.projectionMatrix = projectionMatrix * layer.geometry.positionTransform;
- FloatRect bounds = layer.geometry.boundaries;
+ const FloatRect bounds = layer.geometry.boundaries;
Mesh::VertexArray<vec2> position(mesh.getPositionArray<vec2>());
position[0] = vec2(bounds.left, bounds.top);
position[1] = vec2(bounds.left, bounds.bottom);
position[2] = vec2(bounds.right, bounds.bottom);
position[3] = vec2(bounds.right, bounds.top);
- half3 solidColor = layer.source.solidColor;
- half4 color = half4(solidColor.r, solidColor.g, solidColor.b, layer.alpha);
- setupLayerBlending(/*premultipliedAlpha=*/true, /*opaque=*/false, /*disableTexture=*/true,
- color, /*cornerRadius=*/0.0);
+ setupLayerCropping(layer, mesh);
+ setColorTransform(display.colorTransform * layer.colorTransform);
+
+ bool usePremultipliedAlpha = true;
+ bool disableTexture = true;
+
+ if (layer.source.buffer.buffer != nullptr) {
+ disableTexture = false;
+
+ 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);
+
+ usePremultipliedAlpha = layer.source.buffer.usePremultipliedAlpha;
+ Texture texture(Texture::TEXTURE_EXTERNAL, layer.source.buffer.textureName);
+ texture.setMatrix(layer.source.buffer.textureTransform.asArray());
+ texture.setFiltering(layer.source.buffer.useTextureFiltering);
+
+ texture.setDimensions(gBuf->getWidth(), gBuf->getHeight());
+ setSourceY410BT2020(layer.source.buffer.isY410BT2020);
+
+ renderengine::Mesh::VertexArray<vec2> texCoords(mesh.getTexCoordArray<vec2>());
+ texCoords[0] = vec2(0.0, 1.0);
+ texCoords[1] = vec2(0.0, 0.0);
+ texCoords[2] = vec2(1.0, 0.0);
+ texCoords[3] = vec2(1.0, 1.0);
+ setupLayerTexturing(texture);
+ }
+
+ const half3 solidColor = layer.source.solidColor;
+ const half4 color = half4(solidColor.r, solidColor.g, solidColor.b, layer.alpha);
+ // Buffer sources will have a black solid color ignored in the shader,
+ // so in that scenario the solid color passed here is arbitrary.
+ setupLayerBlending(usePremultipliedAlpha, layer.source.buffer.isOpaque, disableTexture,
+ color, layer.geometry.roundedCornersRadius);
setSourceDataSpace(layer.sourceDataspace);
drawMesh(mesh);
+
+ // Cleanup if there's a buffer source
+ if (layer.source.buffer.buffer != nullptr) {
+ disableBlending();
+ setSourceY410BT2020(false);
+ disableTexturing();
+ }
}
*drawFence = flush();
@@ -1128,6 +1284,61 @@
return (isInputHdrDataSpace || isOutputHdrDataSpace) && inputTransfer != outputTransfer;
}
+// FlushTracer implementation
+GLESRenderEngine::FlushTracer::FlushTracer(GLESRenderEngine* engine) : mEngine(engine) {
+ mThread = std::thread(&GLESRenderEngine::FlushTracer::loop, this);
+}
+
+GLESRenderEngine::FlushTracer::~FlushTracer() {
+ {
+ std::lock_guard<std::mutex> lock(mMutex);
+ mRunning = false;
+ }
+ mCondition.notify_all();
+ if (mThread.joinable()) {
+ mThread.join();
+ }
+}
+
+void GLESRenderEngine::FlushTracer::queueSync(EGLSyncKHR sync) {
+ std::lock_guard<std::mutex> lock(mMutex);
+ char name[64];
+ const uint64_t frameNum = mFramesQueued++;
+ snprintf(name, sizeof(name), "Queueing sync for frame: %lu",
+ static_cast<unsigned long>(frameNum));
+ ATRACE_NAME(name);
+ mQueue.push({sync, frameNum});
+ ATRACE_INT("GPU Frames Outstanding", mQueue.size());
+ mCondition.notify_one();
+}
+
+void GLESRenderEngine::FlushTracer::loop() {
+ while (mRunning) {
+ QueueEntry entry;
+ {
+ std::lock_guard<std::mutex> lock(mMutex);
+
+ mCondition.wait(mMutex,
+ [&]() REQUIRES(mMutex) { return !mQueue.empty() || !mRunning; });
+
+ if (!mRunning) {
+ // if mRunning is false, then FlushTracer is being destroyed, so
+ // bail out now.
+ break;
+ }
+ entry = mQueue.front();
+ mQueue.pop();
+ }
+ {
+ char name[64];
+ snprintf(name, sizeof(name), "waiting for frame %lu",
+ static_cast<unsigned long>(entry.mFrameNum));
+ ATRACE_NAME(name);
+ mEngine->waitSync(entry.mSync, 0);
+ }
+ }
+}
+
} // namespace gl
} // namespace renderengine
} // namespace android
diff --git a/libs/renderengine/gl/GLESRenderEngine.h b/libs/renderengine/gl/GLESRenderEngine.h
index b6fff33..e094860 100644
--- a/libs/renderengine/gl/GLESRenderEngine.h
+++ b/libs/renderengine/gl/GLESRenderEngine.h
@@ -17,14 +17,20 @@
#ifndef SF_GLESRENDERENGINE_H_
#define SF_GLESRENDERENGINE_H_
+#include <android-base/thread_annotations.h>
#include <stdint.h>
#include <sys/types.h>
+#include <condition_variable>
+#include <mutex>
+#include <queue>
+#include <thread>
#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)
@@ -119,6 +125,7 @@
Protection protection);
static EGLSurface createDummyEglPbufferSurface(EGLDisplay display, EGLConfig config,
int hwcFormat, Protection protection);
+ bool waitSync(EGLSyncKHR sync, EGLint flags);
// A data space is considered HDR data space if it has BT2020 color space
// with PQ or HLG transfer function.
@@ -127,6 +134,13 @@
// 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
+ // coordinates for the mesh.
+ FloatRect setupLayerCropping(const LayerSettings& layer, Mesh& mesh);
EGLDisplay mEGLDisplay;
EGLConfig mEGLConfig;
@@ -155,6 +169,8 @@
mat4 mBt2020ToDisplayP3;
bool mInProtectedContext = false;
+ // If set to true, then enables tracing flush() and finish() to systrace.
+ bool mTraceGpuCompletion = false;
int32_t mFboHeight = 0;
// Current dataspace of layer being rendered
@@ -166,6 +182,33 @@
// Whether device supports color management, currently color management
// supports sRGB, DisplayP3 color spaces.
const bool mUseColorManagement = false;
+
+ // Cache of GL images that we'll store per GraphicBuffer ID
+ std::unordered_map<uint64_t, std::unique_ptr<Image>> mImageCache;
+
+ class FlushTracer {
+ public:
+ FlushTracer(GLESRenderEngine* engine);
+ ~FlushTracer();
+ void queueSync(EGLSyncKHR sync) EXCLUDES(mMutex);
+
+ struct QueueEntry {
+ EGLSyncKHR mSync = nullptr;
+ uint64_t mFrameNum = 0;
+ };
+
+ private:
+ void loop();
+ GLESRenderEngine* const mEngine;
+ std::thread mThread;
+ std::condition_variable_any mCondition;
+ std::mutex mMutex;
+ std::queue<QueueEntry> mQueue GUARDED_BY(mMutex);
+ uint64_t mFramesQueued GUARDED_BY(mMutex) = 0;
+ bool mRunning = true;
+ };
+ friend class FlushTracer;
+ std::unique_ptr<FlushTracer> mFlushTracer;
};
} // namespace gl
diff --git a/libs/renderengine/include/renderengine/DisplaySettings.h b/libs/renderengine/include/renderengine/DisplaySettings.h
index 0c92353..af8de23 100644
--- a/libs/renderengine/include/renderengine/DisplaySettings.h
+++ b/libs/renderengine/include/renderengine/DisplaySettings.h
@@ -51,9 +51,10 @@
// to the output dataspace.
mat4 colorTransform = mat4();
- // Region that will be cleared to (0, 0, 0, 0) prior to rendering.
- // clearRegion will first be transformed by globalTransform so that it will
- // be in the same coordinate space as the rendered layers.
+ // Region that will be cleared to (0, 0, 0, 1) prior to rendering.
+ // RenderEngine will transform the clearRegion passed in here, by
+ // globalTransform, so that it will be in the same coordinate space as the
+ // rendered layers.
Region clearRegion = Region::INVALID_REGION;
};
diff --git a/libs/renderengine/include/renderengine/LayerSettings.h b/libs/renderengine/include/renderengine/LayerSettings.h
index 93abf5c..56ac714 100644
--- a/libs/renderengine/include/renderengine/LayerSettings.h
+++ b/libs/renderengine/include/renderengine/LayerSettings.h
@@ -19,6 +19,7 @@
#include <math/mat4.h>
#include <math/vec3.h>
#include <renderengine/Texture.h>
+#include <ui/Fence.h>
#include <ui/FloatRect.h>
#include <ui/GraphicBuffer.h>
#include <ui/GraphicTypes.h>
@@ -31,11 +32,27 @@
// 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.
sp<GraphicBuffer> buffer = nullptr;
+ // 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;
@@ -49,6 +66,11 @@
// Wheteher to use pre-multiplied alpha
bool usePremultipliedAlpha = true;
+ // Override flag that alpha for each pixel in the buffer *must* be 1.0.
+ // LayerSettings::alpha is still used if isOpaque==true - this flag only
+ // overrides the alpha channel of the buffer.
+ bool isOpaque = false;
+
// HDR color-space setting for Y410.
bool isY410BT2020 = false;
};
@@ -60,6 +82,20 @@
// Transform matrix to apply to mesh coordinates.
mat4 positionTransform = mat4();
+
+ // Radius of rounded corners, if greater than 0. Otherwise, this layer's
+ // corners are not rounded.
+ // Having corner radius will force GPU composition on the layer and its children, drawing it
+ // with a special shader. The shader will receive the radius and the crop rectangle as input,
+ // modifying the opacity of the destination texture, multiplying it by a number between 0 and 1.
+ // We query Layer#getRoundedCornerState() to retrieve the radius as well as the rounded crop
+ // rectangle to figure out how to apply the radius for this layer. The crop rectangle will be
+ // in local layer coordinate space, so we have to take the layer transform into account when
+ // walking up the tree.
+ float roundedCornersRadius = 0.0;
+
+ // Rectangle within which corners will be rounded.
+ FloatRect roundedCornersCrop = FloatRect();
};
// Descriptor of the source pixels for this layer.
@@ -81,15 +117,15 @@
// Source pixels for this layer.
PixelSource source = PixelSource();
- // Alpha option to apply to the source pixels
+ // Alpha option to blend with the source pixels
half alpha = half(0.0);
// Color space describing how the source pixels should be interpreted.
- ui::Dataspace sourceDataspace;
+ ui::Dataspace sourceDataspace = ui::Dataspace::UNKNOWN;
// Additional layer-specific color transform to be applied before the global
// transform.
- mat4 colorTransform;
+ mat4 colorTransform = mat4();
};
} // namespace renderengine
diff --git a/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.cpp b/libs/renderengine/include/renderengine/mock/Framebuffer.h
similarity index 63%
copy from services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.cpp
copy to libs/renderengine/include/renderengine/mock/Framebuffer.h
index fbfbc3f..7695885 100644
--- a/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.cpp
+++ b/libs/renderengine/include/renderengine/mock/Framebuffer.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,23 +14,22 @@
* limitations under the License.
*/
-#include "mock/RenderEngine/MockRenderEngine.h"
+#pragma once
-#include <ui/Region.h>
+#include <gmock/gmock.h>
+#include <renderengine/Framebuffer.h>
namespace android {
namespace renderengine {
namespace mock {
-// Explicit default instantiation is recommended.
-RenderEngine::RenderEngine() = default;
-RenderEngine::~RenderEngine() = default;
+class Framebuffer : public renderengine::Framebuffer {
+public:
+ Framebuffer();
+ ~Framebuffer() override;
-Image::Image() = default;
-Image::~Image() = default;
-
-Framebuffer::Framebuffer() = default;
-Framebuffer::~Framebuffer() = default;
+ MOCK_METHOD2(setNativeWindowBuffer, bool(ANativeWindowBuffer*, bool));
+};
} // namespace mock
} // namespace renderengine
diff --git a/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.cpp b/libs/renderengine/include/renderengine/mock/Image.h
similarity index 63%
copy from services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.cpp
copy to libs/renderengine/include/renderengine/mock/Image.h
index fbfbc3f..2b0eed1 100644
--- a/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.cpp
+++ b/libs/renderengine/include/renderengine/mock/Image.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,23 +14,22 @@
* limitations under the License.
*/
-#include "mock/RenderEngine/MockRenderEngine.h"
+#pragma once
-#include <ui/Region.h>
+#include <gmock/gmock.h>
+#include <renderengine/Image.h>
namespace android {
namespace renderengine {
namespace mock {
-// Explicit default instantiation is recommended.
-RenderEngine::RenderEngine() = default;
-RenderEngine::~RenderEngine() = default;
+class Image : public renderengine::Image {
+public:
+ Image();
+ ~Image() override;
-Image::Image() = default;
-Image::~Image() = default;
-
-Framebuffer::Framebuffer() = default;
-Framebuffer::~Framebuffer() = default;
+ MOCK_METHOD2(setNativeWindowBuffer, bool(ANativeWindowBuffer* buffer, bool isProtected));
+};
} // namespace mock
} // namespace renderengine
diff --git a/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.h b/libs/renderengine/include/renderengine/mock/RenderEngine.h
similarity index 82%
rename from services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.h
rename to libs/renderengine/include/renderengine/mock/RenderEngine.h
index 81a7768..b4c7c96 100644
--- a/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.h
+++ b/libs/renderengine/include/renderengine/mock/RenderEngine.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,13 +18,12 @@
#include <gmock/gmock.h>
#include <renderengine/DisplaySettings.h>
-#include <renderengine/Framebuffer.h>
-#include <renderengine/Image.h>
#include <renderengine/LayerSettings.h>
#include <renderengine/Mesh.h>
#include <renderengine/RenderEngine.h>
#include <renderengine/Texture.h>
#include <ui/GraphicBuffer.h>
+#include <ui/Region.h>
namespace android {
namespace renderengine {
@@ -35,7 +34,7 @@
RenderEngine();
~RenderEngine() override;
- MOCK_METHOD0(createFramebuffer, std::unique_ptr<Framebuffer>());
+ MOCK_METHOD0(createFramebuffer, std::unique_ptr<renderengine::Framebuffer>());
MOCK_METHOD0(createImage, std::unique_ptr<renderengine::Image>());
MOCK_CONST_METHOD0(primeCache, void());
MOCK_METHOD1(dump, void(std::string&));
@@ -69,9 +68,9 @@
MOCK_METHOD1(setSourceDataSpace, void(ui::Dataspace));
MOCK_METHOD1(setOutputDataSpace, void(ui::Dataspace));
MOCK_METHOD1(setDisplayMaxLuminance, void(const float));
- MOCK_METHOD1(bindFrameBuffer, status_t(Framebuffer*));
- MOCK_METHOD1(unbindFrameBuffer, void(Framebuffer*));
- MOCK_METHOD1(drawMesh, void(const Mesh&));
+ MOCK_METHOD1(bindFrameBuffer, status_t(renderengine::Framebuffer*));
+ MOCK_METHOD1(unbindFrameBuffer, void(renderengine::Framebuffer*));
+ MOCK_METHOD1(drawMesh, void(const renderengine::Mesh&));
MOCK_CONST_METHOD0(getMaxTextureSize, size_t());
MOCK_CONST_METHOD0(getMaxViewportDims, size_t());
MOCK_CONST_METHOD0(isProtected, bool());
@@ -82,22 +81,6 @@
ANativeWindowBuffer*, base::unique_fd*));
};
-class Image : public renderengine::Image {
-public:
- Image();
- ~Image() override;
-
- MOCK_METHOD2(setNativeWindowBuffer, bool(ANativeWindowBuffer*, bool));
-};
-
-class Framebuffer : public renderengine::Framebuffer {
-public:
- Framebuffer();
- ~Framebuffer() override;
-
- MOCK_METHOD2(setNativeWindowBuffer, bool(ANativeWindowBuffer*, bool));
-};
-
} // namespace mock
} // namespace renderengine
} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.cpp b/libs/renderengine/mock/Framebuffer.cpp
similarity index 70%
copy from services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.cpp
copy to libs/renderengine/mock/Framebuffer.cpp
index fbfbc3f..fbdcaab 100644
--- a/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.cpp
+++ b/libs/renderengine/mock/Framebuffer.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,21 +14,14 @@
* limitations under the License.
*/
-#include "mock/RenderEngine/MockRenderEngine.h"
-
-#include <ui/Region.h>
+#include <renderengine/mock/Framebuffer.h>
namespace android {
namespace renderengine {
namespace mock {
-// Explicit default instantiation is recommended.
-RenderEngine::RenderEngine() = default;
-RenderEngine::~RenderEngine() = default;
-
-Image::Image() = default;
-Image::~Image() = default;
-
+// The Google Mock documentation recommends explicit non-header instantiations
+// for better compile time performance.
Framebuffer::Framebuffer() = default;
Framebuffer::~Framebuffer() = default;
diff --git a/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.cpp b/libs/renderengine/mock/Image.cpp
similarity index 68%
copy from services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.cpp
copy to libs/renderengine/mock/Image.cpp
index fbfbc3f..57f4346 100644
--- a/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.cpp
+++ b/libs/renderengine/mock/Image.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,24 +14,17 @@
* limitations under the License.
*/
-#include "mock/RenderEngine/MockRenderEngine.h"
-
-#include <ui/Region.h>
+#include <renderengine/mock/Image.h>
namespace android {
namespace renderengine {
namespace mock {
-// Explicit default instantiation is recommended.
-RenderEngine::RenderEngine() = default;
-RenderEngine::~RenderEngine() = default;
-
+// The Google Mock documentation recommends explicit non-header instantiations
+// for better compile time performance.
Image::Image() = default;
Image::~Image() = default;
-Framebuffer::Framebuffer() = default;
-Framebuffer::~Framebuffer() = default;
-
} // namespace mock
} // namespace renderengine
} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.cpp b/libs/renderengine/mock/RenderEngine.cpp
similarity index 71%
rename from services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.cpp
rename to libs/renderengine/mock/RenderEngine.cpp
index fbfbc3f..261636d 100644
--- a/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.cpp
+++ b/libs/renderengine/mock/RenderEngine.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,24 +14,17 @@
* limitations under the License.
*/
-#include "mock/RenderEngine/MockRenderEngine.h"
-
-#include <ui/Region.h>
+#include <renderengine/mock/RenderEngine.h>
namespace android {
namespace renderengine {
namespace mock {
-// Explicit default instantiation is recommended.
+// The Google Mock documentation recommends explicit non-header instantiations
+// for better compile time performance.
RenderEngine::RenderEngine() = default;
RenderEngine::~RenderEngine() = default;
-Image::Image() = default;
-Image::~Image() = default;
-
-Framebuffer::Framebuffer() = default;
-Framebuffer::~Framebuffer() = default;
-
} // namespace mock
} // namespace renderengine
} // namespace android
diff --git a/libs/renderengine/tests/RenderEngineTest.cpp b/libs/renderengine/tests/RenderEngineTest.cpp
index a0542dd..bef25a8 100644
--- a/libs/renderengine/tests/RenderEngineTest.cpp
+++ b/libs/renderengine/tests/RenderEngineTest.cpp
@@ -27,15 +27,30 @@
namespace android {
struct RenderEngineTest : public ::testing::Test {
- sp<GraphicBuffer> allocateDefaultBuffer() {
+ static sp<GraphicBuffer> allocateDefaultBuffer() {
return new GraphicBuffer(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT,
HAL_PIXEL_FORMAT_RGBA_8888, 1,
- GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
+ GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN |
+ GRALLOC_USAGE_HW_RENDER,
"output");
}
+ // Allocates a 1x1 buffer to fill with a solid color
+ static sp<GraphicBuffer> allocateSourceBuffer(uint32_t width, uint32_t height) {
+ return new GraphicBuffer(width, height, HAL_PIXEL_FORMAT_RGBA_8888, 1,
+ GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN |
+ GRALLOC_USAGE_HW_TEXTURE,
+ "input");
+ }
+
RenderEngineTest() { mBuffer = allocateDefaultBuffer(); }
+ ~RenderEngineTest() {
+ for (uint32_t texName : mTexNames) {
+ sRE->deleteTextures(1, &texName);
+ }
+ }
+
void expectBufferColor(const Rect& region, uint8_t r, uint8_t g, uint8_t b, uint8_t a,
uint8_t tolerance = 0) {
uint8_t* pixels;
@@ -146,27 +161,112 @@
void fillBufferCheckersRotate270();
template <typename SourceVariant>
+ void fillBufferWithLayerTransform();
+
+ template <typename SourceVariant>
void fillBufferLayerTransform();
template <typename SourceVariant>
+ void fillBufferWithColorTransform();
+
+ template <typename SourceVariant>
void fillBufferColorTransform();
+ template <typename SourceVariant>
+ void fillRedBufferWithRoundedCorners();
+
+ template <typename SourceVariant>
+ void fillBufferWithRoundedCorners();
+
+ void fillRedBufferTextureTransform();
+
+ void fillBufferTextureTransform();
+
+ void fillRedBufferWithPremultiplyAlpha();
+
+ void fillBufferWithPremultiplyAlpha();
+
+ void fillRedBufferWithoutPremultiplyAlpha();
+
+ void fillBufferWithoutPremultiplyAlpha();
+
+ void fillGreenColorBufferThenClearRegion();
+
+ void clearLeftRegion();
+
+ void fillBufferThenClearRegion();
+
// Dumb hack to get aroud the fact that tear-down for renderengine isn't
// well defined right now, so we can't create multiple instances
static std::unique_ptr<renderengine::RenderEngine> sRE;
sp<GraphicBuffer> mBuffer;
+
+ std::vector<uint32_t> mTexNames;
};
std::unique_ptr<renderengine::RenderEngine> RenderEngineTest::sRE =
renderengine::RenderEngine::create(static_cast<int32_t>(ui::PixelFormat::RGBA_8888), 0);
struct ColorSourceVariant {
- static void fillColor(renderengine::LayerSettings& layer, half r, half g, half b) {
+ static void fillColor(renderengine::LayerSettings& layer, half r, half g, half b,
+ RenderEngineTest* /*fixture*/) {
layer.source.solidColor = half3(r, g, b);
}
};
+struct RelaxOpaqueBufferVariant {
+ static void setOpaqueBit(renderengine::LayerSettings& layer) {
+ layer.source.buffer.isOpaque = false;
+ }
+
+ static uint8_t getAlphaChannel() { return 255; }
+};
+
+struct ForceOpaqueBufferVariant {
+ static void setOpaqueBit(renderengine::LayerSettings& layer) {
+ layer.source.buffer.isOpaque = true;
+ }
+
+ static uint8_t getAlphaChannel() {
+ // The isOpaque bit will override the alpha channel, so this should be
+ // arbitrary.
+ return 10;
+ }
+};
+
+template <typename OpaquenessVariant>
+struct BufferSourceVariant {
+ static void fillColor(renderengine::LayerSettings& layer, half r, half g, half b,
+ RenderEngineTest* fixture) {
+ sp<GraphicBuffer> buf = RenderEngineTest::allocateSourceBuffer(1, 1);
+ uint32_t texName;
+ RenderEngineTest::sRE->genTextures(1, &texName);
+ fixture->mTexNames.push_back(texName);
+
+ uint8_t* pixels;
+ buf->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
+ reinterpret_cast<void**>(&pixels));
+
+ for (int32_t j = 0; j < buf->getHeight(); j++) {
+ uint8_t* iter = pixels + (buf->getStride() * j) * 4;
+ for (int32_t i = 0; i < buf->getWidth(); i++) {
+ iter[0] = uint8_t(r * 255);
+ iter[1] = uint8_t(g * 255);
+ iter[2] = uint8_t(b * 255);
+ iter[3] = OpaquenessVariant::getAlphaChannel();
+ iter += 4;
+ }
+ }
+
+ buf->unlock();
+
+ layer.source.buffer.buffer = buf;
+ layer.source.buffer.textureName = texName;
+ OpaquenessVariant::setOpaqueBit(layer);
+ }
+};
+
template <typename SourceVariant>
void RenderEngineTest::fillBuffer(half r, half g, half b, half a) {
renderengine::DisplaySettings settings;
@@ -177,7 +277,7 @@
renderengine::LayerSettings layer;
layer.geometry.boundaries = fullscreenRect().toFloatRect();
- SourceVariant::fillColor(layer, r, g, b);
+ SourceVariant::fillColor(layer, r, g, b, this);
layer.alpha = a;
layers.push_back(layer);
@@ -219,7 +319,7 @@
renderengine::LayerSettings layer;
layer.geometry.boundaries = offsetRectAtZero().toFloatRect();
- SourceVariant::fillColor(layer, 1.0f, 0.0f, 0.0f);
+ SourceVariant::fillColor(layer, 1.0f, 0.0f, 0.0f, this);
layer.alpha = 1.0f;
layers.push_back(layer);
@@ -253,19 +353,19 @@
renderengine::LayerSettings layerOne;
Rect rectOne(0, 0, 1, 1);
layerOne.geometry.boundaries = rectOne.toFloatRect();
- SourceVariant::fillColor(layerOne, 1.0f, 0.0f, 0.0f);
+ SourceVariant::fillColor(layerOne, 1.0f, 0.0f, 0.0f, this);
layerOne.alpha = 1.0f;
renderengine::LayerSettings layerTwo;
Rect rectTwo(0, 1, 1, 2);
layerTwo.geometry.boundaries = rectTwo.toFloatRect();
- SourceVariant::fillColor(layerTwo, 0.0f, 1.0f, 0.0f);
+ SourceVariant::fillColor(layerTwo, 0.0f, 1.0f, 0.0f, this);
layerTwo.alpha = 1.0f;
renderengine::LayerSettings layerThree;
Rect rectThree(1, 0, 2, 1);
layerThree.geometry.boundaries = rectThree.toFloatRect();
- SourceVariant::fillColor(layerThree, 0.0f, 0.0f, 1.0f);
+ SourceVariant::fillColor(layerThree, 0.0f, 0.0f, 1.0f, this);
layerThree.alpha = 1.0f;
layers.push_back(layerOne);
@@ -343,7 +443,7 @@
}
template <typename SourceVariant>
-void RenderEngineTest::fillBufferLayerTransform() {
+void RenderEngineTest::fillBufferWithLayerTransform() {
renderengine::DisplaySettings settings;
settings.physicalDisplay = fullscreenRect();
// Here logical space is 2x2
@@ -355,13 +455,18 @@
layer.geometry.boundaries = Rect(1, 1).toFloatRect();
// Translate one pixel diagonally
layer.geometry.positionTransform = mat4(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1);
+ SourceVariant::fillColor(layer, 1.0f, 0.0f, 0.0f, this);
layer.source.solidColor = half3(1.0f, 0.0f, 0.0f);
layer.alpha = 1.0f;
layers.push_back(layer);
invokeDraw(settings, layers, mBuffer);
+}
+template <typename SourceVariant>
+void RenderEngineTest::fillBufferLayerTransform() {
+ fillBufferWithLayerTransform<SourceVariant>();
expectBufferColor(Rect(0, 0, DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT / 2), 0, 0, 0, 0);
expectBufferColor(Rect(0, 0, DEFAULT_DISPLAY_WIDTH / 2, DEFAULT_DISPLAY_HEIGHT), 0, 0, 0, 0);
expectBufferColor(Rect(DEFAULT_DISPLAY_WIDTH / 2, DEFAULT_DISPLAY_HEIGHT / 2,
@@ -370,7 +475,7 @@
}
template <typename SourceVariant>
-void RenderEngineTest::fillBufferColorTransform() {
+void RenderEngineTest::fillBufferWithColorTransform() {
renderengine::DisplaySettings settings;
settings.physicalDisplay = fullscreenRect();
settings.clip = Rect(1, 1);
@@ -379,7 +484,7 @@
renderengine::LayerSettings layer;
layer.geometry.boundaries = Rect(1, 1).toFloatRect();
- layer.source.solidColor = half3(0.5f, 0.25f, 0.125f);
+ SourceVariant::fillColor(layer, 0.5f, 0.25f, 0.125f, this);
layer.alpha = 1.0f;
// construct a fake color matrix
@@ -388,13 +493,208 @@
// set red channel to red + green
layer.colorTransform = mat4(1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
+ layer.alpha = 1.0f;
+ layer.geometry.boundaries = Rect(1, 1).toFloatRect();
+
layers.push_back(layer);
invokeDraw(settings, layers, mBuffer);
+}
+template <typename SourceVariant>
+void RenderEngineTest::fillBufferColorTransform() {
+ fillBufferWithColorTransform<SourceVariant>();
expectBufferColor(fullscreenRect(), 191, 0, 0, 255);
}
+template <typename SourceVariant>
+void RenderEngineTest::fillRedBufferWithRoundedCorners() {
+ renderengine::DisplaySettings settings;
+ settings.physicalDisplay = fullscreenRect();
+ settings.clip = fullscreenRect();
+
+ std::vector<renderengine::LayerSettings> layers;
+
+ renderengine::LayerSettings layer;
+ layer.geometry.boundaries = fullscreenRect().toFloatRect();
+ layer.geometry.roundedCornersRadius = 5.0f;
+ layer.geometry.roundedCornersCrop = fullscreenRect().toFloatRect();
+ SourceVariant::fillColor(layer, 1.0f, 0.0f, 0.0f, this);
+ layer.alpha = 1.0f;
+
+ layers.push_back(layer);
+
+ invokeDraw(settings, layers, mBuffer);
+}
+
+template <typename SourceVariant>
+void RenderEngineTest::fillBufferWithRoundedCorners() {
+ fillRedBufferWithRoundedCorners<SourceVariant>();
+ // Corners should be ignored...
+ expectBufferColor(Rect(0, 0, 1, 1), 0, 0, 0, 0);
+ expectBufferColor(Rect(DEFAULT_DISPLAY_WIDTH - 1, 0, DEFAULT_DISPLAY_WIDTH, 1), 0, 0, 0, 0);
+ expectBufferColor(Rect(0, DEFAULT_DISPLAY_HEIGHT - 1, 1, DEFAULT_DISPLAY_HEIGHT), 0, 0, 0, 0);
+ expectBufferColor(Rect(DEFAULT_DISPLAY_WIDTH - 1, DEFAULT_DISPLAY_HEIGHT - 1,
+ DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
+ 0, 0, 0, 0);
+ // ...And the non-rounded portion should be red.
+ // Other pixels may be anti-aliased, so let's not check those.
+ expectBufferColor(Rect(5, 5, DEFAULT_DISPLAY_WIDTH - 5, DEFAULT_DISPLAY_HEIGHT - 5), 255, 0, 0,
+ 255);
+}
+
+void RenderEngineTest::fillRedBufferTextureTransform() {
+ renderengine::DisplaySettings settings;
+ settings.physicalDisplay = fullscreenRect();
+ settings.clip = Rect(1, 1);
+
+ std::vector<renderengine::LayerSettings> layers;
+
+ renderengine::LayerSettings layer;
+ // Here will allocate a checker board texture, but transform texture
+ // coordinates so that only the upper left is applied.
+ sp<GraphicBuffer> buf = allocateSourceBuffer(2, 2);
+ uint32_t texName;
+ RenderEngineTest::sRE->genTextures(1, &texName);
+ this->mTexNames.push_back(texName);
+
+ uint8_t* pixels;
+ buf->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
+ reinterpret_cast<void**>(&pixels));
+ // Red top left, Green top right, Blue bottom left, Black bottom right
+ pixels[0] = 255;
+ pixels[1] = 0;
+ pixels[2] = 0;
+ pixels[3] = 255;
+ pixels[4] = 0;
+ pixels[5] = 255;
+ pixels[6] = 0;
+ pixels[7] = 255;
+ pixels[8] = 0;
+ pixels[9] = 0;
+ pixels[10] = 255;
+ pixels[11] = 255;
+ buf->unlock();
+
+ layer.source.buffer.buffer = buf;
+ layer.source.buffer.textureName = texName;
+ // Transform coordinates to only be inside the red quadrant.
+ layer.source.buffer.textureTransform = mat4::scale(vec4(0.2, 0.2, 1, 1));
+ layer.alpha = 1.0f;
+ layer.geometry.boundaries = Rect(1, 1).toFloatRect();
+
+ layers.push_back(layer);
+
+ invokeDraw(settings, layers, mBuffer);
+}
+
+void RenderEngineTest::fillBufferTextureTransform() {
+ fillRedBufferTextureTransform();
+ expectBufferColor(fullscreenRect(), 255, 0, 0, 255);
+}
+
+void RenderEngineTest::fillRedBufferWithPremultiplyAlpha() {
+ renderengine::DisplaySettings settings;
+ settings.physicalDisplay = fullscreenRect();
+ // Here logical space is 1x1
+ settings.clip = Rect(1, 1);
+
+ std::vector<renderengine::LayerSettings> layers;
+
+ renderengine::LayerSettings layer;
+ sp<GraphicBuffer> buf = allocateSourceBuffer(1, 1);
+ uint32_t texName;
+ RenderEngineTest::sRE->genTextures(1, &texName);
+ this->mTexNames.push_back(texName);
+
+ uint8_t* pixels;
+ buf->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
+ reinterpret_cast<void**>(&pixels));
+ pixels[0] = 255;
+ pixels[1] = 0;
+ pixels[2] = 0;
+ pixels[3] = 255;
+ buf->unlock();
+
+ layer.source.buffer.buffer = buf;
+ layer.source.buffer.textureName = texName;
+ layer.source.buffer.usePremultipliedAlpha = true;
+ layer.alpha = 0.5f;
+ layer.geometry.boundaries = Rect(1, 1).toFloatRect();
+
+ layers.push_back(layer);
+
+ invokeDraw(settings, layers, mBuffer);
+}
+
+void RenderEngineTest::fillBufferWithPremultiplyAlpha() {
+ fillRedBufferWithPremultiplyAlpha();
+ expectBufferColor(fullscreenRect(), 128, 0, 0, 128);
+}
+
+void RenderEngineTest::fillRedBufferWithoutPremultiplyAlpha() {
+ renderengine::DisplaySettings settings;
+ settings.physicalDisplay = fullscreenRect();
+ // Here logical space is 1x1
+ settings.clip = Rect(1, 1);
+
+ std::vector<renderengine::LayerSettings> layers;
+
+ renderengine::LayerSettings layer;
+ sp<GraphicBuffer> buf = allocateSourceBuffer(1, 1);
+ uint32_t texName;
+ RenderEngineTest::sRE->genTextures(1, &texName);
+ this->mTexNames.push_back(texName);
+
+ uint8_t* pixels;
+ buf->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
+ reinterpret_cast<void**>(&pixels));
+ pixels[0] = 255;
+ pixels[1] = 0;
+ pixels[2] = 0;
+ pixels[3] = 255;
+ buf->unlock();
+
+ layer.source.buffer.buffer = buf;
+ layer.source.buffer.textureName = texName;
+ layer.source.buffer.usePremultipliedAlpha = false;
+ layer.alpha = 0.5f;
+ layer.geometry.boundaries = Rect(1, 1).toFloatRect();
+
+ layers.push_back(layer);
+
+ invokeDraw(settings, layers, mBuffer);
+}
+
+void RenderEngineTest::fillBufferWithoutPremultiplyAlpha() {
+ fillRedBufferWithoutPremultiplyAlpha();
+ expectBufferColor(fullscreenRect(), 128, 0, 0, 64, 1);
+}
+
+void RenderEngineTest::clearLeftRegion() {
+ renderengine::DisplaySettings settings;
+ settings.physicalDisplay = fullscreenRect();
+ // Here logical space is 4x4
+ settings.clip = Rect(4, 4);
+ settings.globalTransform = mat4::scale(vec4(2, 4, 0, 1));
+ settings.clearRegion = Region(Rect(1, 1));
+ std::vector<renderengine::LayerSettings> layers;
+ // dummy layer, without bounds should not render anything
+ renderengine::LayerSettings layer;
+ layers.push_back(layer);
+ invokeDraw(settings, layers, mBuffer);
+}
+
+void RenderEngineTest::fillBufferThenClearRegion() {
+ fillGreenBuffer<ColorSourceVariant>();
+ // Reuse mBuffer
+ clearLeftRegion();
+ expectBufferColor(Rect(DEFAULT_DISPLAY_WIDTH / 2, DEFAULT_DISPLAY_HEIGHT), 0, 0, 0, 255);
+ expectBufferColor(Rect(DEFAULT_DISPLAY_WIDTH / 2, 0, DEFAULT_DISPLAY_WIDTH,
+ DEFAULT_DISPLAY_HEIGHT),
+ 0, 255, 0, 255);
+}
+
TEST_F(RenderEngineTest, drawLayers_noLayersToDraw) {
drawEmptyLayers();
}
@@ -443,4 +743,120 @@
fillBufferLayerTransform<ColorSourceVariant>();
}
+TEST_F(RenderEngineTest, drawLayers_fillBufferRoundedCorners_colorSource) {
+ fillBufferWithRoundedCorners<ColorSourceVariant>();
+}
+
+TEST_F(RenderEngineTest, drawLayers_fillRedBuffer_opaqueBufferSource) {
+ fillRedBuffer<BufferSourceVariant<ForceOpaqueBufferVariant>>();
+}
+
+TEST_F(RenderEngineTest, drawLayers_fillGreenBuffer_opaqueBufferSource) {
+ fillGreenBuffer<BufferSourceVariant<ForceOpaqueBufferVariant>>();
+}
+
+TEST_F(RenderEngineTest, drawLayers_fillBlueBuffer_opaqueBufferSource) {
+ fillBlueBuffer<BufferSourceVariant<ForceOpaqueBufferVariant>>();
+}
+
+TEST_F(RenderEngineTest, drawLayers_fillRedTransparentBuffer_opaqueBufferSource) {
+ fillRedTransparentBuffer<BufferSourceVariant<ForceOpaqueBufferVariant>>();
+}
+
+TEST_F(RenderEngineTest, drawLayers_fillBufferPhysicalOffset_opaqueBufferSource) {
+ fillBufferPhysicalOffset<BufferSourceVariant<ForceOpaqueBufferVariant>>();
+}
+
+TEST_F(RenderEngineTest, drawLayers_fillBufferCheckersRotate0_opaqueBufferSource) {
+ fillBufferCheckersRotate0<BufferSourceVariant<ForceOpaqueBufferVariant>>();
+}
+
+TEST_F(RenderEngineTest, drawLayers_fillBufferCheckersRotate90_opaqueBufferSource) {
+ fillBufferCheckersRotate90<BufferSourceVariant<ForceOpaqueBufferVariant>>();
+}
+
+TEST_F(RenderEngineTest, drawLayers_fillBufferCheckersRotate180_opaqueBufferSource) {
+ fillBufferCheckersRotate180<BufferSourceVariant<ForceOpaqueBufferVariant>>();
+}
+
+TEST_F(RenderEngineTest, drawLayers_fillBufferCheckersRotate270_opaqueBufferSource) {
+ fillBufferCheckersRotate270<BufferSourceVariant<ForceOpaqueBufferVariant>>();
+}
+
+TEST_F(RenderEngineTest, drawLayers_fillBufferLayerTransform_opaqueBufferSource) {
+ fillBufferLayerTransform<BufferSourceVariant<ForceOpaqueBufferVariant>>();
+}
+
+TEST_F(RenderEngineTest, drawLayers_fillBufferColorTransform_opaqueBufferSource) {
+ fillBufferLayerTransform<BufferSourceVariant<ForceOpaqueBufferVariant>>();
+}
+
+TEST_F(RenderEngineTest, drawLayers_fillBufferRoundedCorners_opaqueBufferSource) {
+ fillBufferWithRoundedCorners<BufferSourceVariant<ForceOpaqueBufferVariant>>();
+}
+
+TEST_F(RenderEngineTest, drawLayers_fillRedBuffer_bufferSource) {
+ fillRedBuffer<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
+}
+
+TEST_F(RenderEngineTest, drawLayers_fillGreenBuffer_bufferSource) {
+ fillGreenBuffer<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
+}
+
+TEST_F(RenderEngineTest, drawLayers_fillBlueBuffer_bufferSource) {
+ fillBlueBuffer<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
+}
+
+TEST_F(RenderEngineTest, drawLayers_fillRedTransparentBuffer_bufferSource) {
+ fillRedTransparentBuffer<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
+}
+
+TEST_F(RenderEngineTest, drawLayers_fillBufferPhysicalOffset_bufferSource) {
+ fillBufferPhysicalOffset<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
+}
+
+TEST_F(RenderEngineTest, drawLayers_fillBufferCheckersRotate0_bufferSource) {
+ fillBufferCheckersRotate0<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
+}
+
+TEST_F(RenderEngineTest, drawLayers_fillBufferCheckersRotate90_bufferSource) {
+ fillBufferCheckersRotate90<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
+}
+
+TEST_F(RenderEngineTest, drawLayers_fillBufferCheckersRotate180_bufferSource) {
+ fillBufferCheckersRotate180<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
+}
+
+TEST_F(RenderEngineTest, drawLayers_fillBufferCheckersRotate270_bufferSource) {
+ fillBufferCheckersRotate270<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
+}
+
+TEST_F(RenderEngineTest, drawLayers_fillBufferLayerTransform_bufferSource) {
+ fillBufferLayerTransform<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
+}
+
+TEST_F(RenderEngineTest, drawLayers_fillBufferColorTransform_bufferSource) {
+ fillBufferLayerTransform<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
+}
+
+TEST_F(RenderEngineTest, drawLayers_fillBufferRoundedCorners_bufferSource) {
+ fillBufferWithRoundedCorners<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
+}
+
+TEST_F(RenderEngineTest, drawLayers_fillBufferTextureTransform) {
+ fillBufferTextureTransform();
+}
+
+TEST_F(RenderEngineTest, drawLayers_fillBuffer_premultipliesAlpha) {
+ fillBufferWithPremultiplyAlpha();
+}
+
+TEST_F(RenderEngineTest, drawLayers_fillBuffer_withoutPremultiplyingAlpha) {
+ fillBufferWithoutPremultiplyAlpha();
+}
+
+TEST_F(RenderEngineTest, drawLayers_fillBufferThenClearRegion) {
+ fillBufferThenClearRegion();
+}
+
} // namespace android
diff --git a/libs/sensor/SensorEventQueue.cpp b/libs/sensor/SensorEventQueue.cpp
index 46ba7c6..4438d45 100644
--- a/libs/sensor/SensorEventQueue.cpp
+++ b/libs/sensor/SensorEventQueue.cpp
@@ -29,6 +29,7 @@
#include <sensor/ISensorEventConnection.h>
#include <android/sensor.h>
+#include <hardware/sensors-base.h>
using std::min;
@@ -188,6 +189,52 @@
return;
}
+ssize_t SensorEventQueue::filterEvents(ASensorEvent* events, size_t count) const {
+ // Check if this Sensor Event Queue is registered to receive each type of event. If it is not,
+ // then do not copy the event into the final buffer. Minimize the number of copy operations by
+ // finding consecutive sequences of events that the Sensor Event Queue should receive and only
+ // copying the events once an unregistered event type is reached.
+ bool intervalStartLocSet = false;
+ size_t intervalStartLoc = 0;
+ size_t eventsInInterval = 0;
+ ssize_t eventsCopied = 0;
+
+ for (size_t i = 0; i < count; i++) {
+ bool includeEvent =
+ (events[i].type != SENSOR_TYPE_ADDITIONAL_INFO || requestAdditionalInfo);
+
+ if (includeEvent) {
+ // Do not copy events yet since there may be more consecutive events that should be
+ // copied together. Track the start location and number of events in the current
+ // sequence.
+ if (!intervalStartLocSet) {
+ intervalStartLoc = i;
+ intervalStartLocSet = true;
+ eventsInInterval = 0;
+ }
+ eventsInInterval++;
+ }
+
+ // Shift the events from the already processed interval once an event that should not be
+ // included is reached or if this is the final event to be processed.
+ if (!includeEvent || (i + 1 == count)) {
+ // Only shift the events if the interval did not start with the first event. If the
+ // interval started with the first event, the events are already in their correct
+ // location.
+ if (intervalStartLoc > 0) {
+ memmove(&events[eventsCopied], &events[intervalStartLoc],
+ eventsInInterval * sizeof(ASensorEvent));
+ }
+ eventsCopied += eventsInInterval;
+
+ // Reset the interval information
+ eventsInInterval = 0;
+ intervalStartLocSet = false;
+ }
+ }
+ return eventsCopied;
+}
+
// ----------------------------------------------------------------------------
}; // namespace android
diff --git a/libs/sensor/include/sensor/Sensor.h b/libs/sensor/include/sensor/Sensor.h
index 6926f7f..324d443 100644
--- a/libs/sensor/include/sensor/Sensor.h
+++ b/libs/sensor/include/sensor/Sensor.h
@@ -57,15 +57,15 @@
uint8_t b[16];
int64_t i64[2];
};
- uuid_t(const uint8_t (&uuid)[16]) { memcpy(b, uuid, sizeof(b));}
+ explicit uuid_t(const uint8_t (&uuid)[16]) { memcpy(b, uuid, sizeof(b));}
uuid_t() : b{0} {}
};
Sensor(const Sensor&) = default;
Sensor& operator=(const Sensor&) = default;
- Sensor(const char * name = "");
- Sensor(struct sensor_t const* hwSensor, int halVersion = 0);
+ explicit Sensor(const char * name = "");
+ explicit Sensor(struct sensor_t const* hwSensor, int halVersion = 0);
Sensor(struct sensor_t const& hwSensor, const uuid_t& uuid, int halVersion = 0);
~Sensor();
diff --git a/libs/sensor/include/sensor/SensorEventQueue.h b/libs/sensor/include/sensor/SensorEventQueue.h
index baed2ee..8c3fde0 100644
--- a/libs/sensor/include/sensor/SensorEventQueue.h
+++ b/libs/sensor/include/sensor/SensorEventQueue.h
@@ -34,6 +34,7 @@
// Concrete types for the NDK
struct ASensorEventQueue {
ALooper* looper;
+ bool requestAdditionalInfo;
};
// ----------------------------------------------------------------------------
@@ -64,7 +65,7 @@
// Default sensor sample period
static constexpr int32_t SENSOR_DELAY_NORMAL = 200000;
- SensorEventQueue(const sp<ISensorEventConnection>& connection);
+ explicit SensorEventQueue(const sp<ISensorEventConnection>& connection);
virtual ~SensorEventQueue();
virtual void onFirstRef();
@@ -92,6 +93,13 @@
void sendAck(const ASensorEvent* events, int count);
status_t injectSensorEvent(const ASensorEvent& event);
+
+ // Filters the given sensor events in place and returns the new number of events.
+ //
+ // The filtering is controlled by ASensorEventQueue.requestAdditionalInfo, and if this value is
+ // false, then all SENSOR_TYPE_ADDITIONAL_INFO sensor events will be removed.
+ ssize_t filterEvents(ASensorEvent* events, size_t count) const;
+
private:
sp<Looper> getLooper() const;
sp<ISensorEventConnection> mSensorEventConnection;
diff --git a/libs/sensor/include/sensor/SensorManager.h b/libs/sensor/include/sensor/SensorManager.h
index 23f7a91..f09c9c6 100644
--- a/libs/sensor/include/sensor/SensorManager.h
+++ b/libs/sensor/include/sensor/SensorManager.h
@@ -71,7 +71,7 @@
void sensorManagerDied();
static status_t waitForSensorService(sp<ISensorServer> *server);
- SensorManager(const String16& opPackageName);
+ explicit SensorManager(const String16& opPackageName);
status_t assertStateLocked();
private:
diff --git a/libs/sensor/tests/Android.bp b/libs/sensor/tests/Android.bp
index 9fd84bc..c9a7668 100644
--- a/libs/sensor/tests/Android.bp
+++ b/libs/sensor/tests/Android.bp
@@ -21,6 +21,7 @@
srcs: [
"Sensor_test.cpp",
+ "SensorEventQueue_test.cpp",
],
shared_libs: [
diff --git a/libs/sensor/tests/SensorEventQueue_test.cpp b/libs/sensor/tests/SensorEventQueue_test.cpp
new file mode 100644
index 0000000..1eb5883
--- /dev/null
+++ b/libs/sensor/tests/SensorEventQueue_test.cpp
@@ -0,0 +1,172 @@
+/*
+ * 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 <stdint.h>
+
+#include <gtest/gtest.h>
+#include <utils/Errors.h>
+
+#include <android/sensor.h>
+#include <hardware/sensors-base.h>
+#include <sensor/SensorManager.h>
+#include <sensor/SensorEventQueue.h>
+
+namespace android {
+
+class SensorEventQueueTest : public ::testing::Test {
+protected:
+ typedef std::vector<int32_t> Events;
+
+ SensorEventQueueTest() {};
+
+ virtual void SetUp() override {
+ SensorManager& manager = SensorManager::getInstanceForPackage(String16("SensorEventQueueTest"));
+ mQueue = manager.createEventQueue();
+ }
+
+ void configureAdditionalInfo(bool enable) {
+ mQueue->requestAdditionalInfo = enable;
+ }
+
+ Events filterEvents(const Events &types) const {
+ // Convert the events into SensorEvent array
+ ASensorEvent* events = new ASensorEvent[types.size()];
+ for (size_t i = 0; i < types.size(); i++) {
+ events[i].type = types[i];
+ }
+
+ // Filter the events
+ ssize_t filteredCount = mQueue->filterEvents(events, types.size());
+
+ // Copy the result into an output vector
+ Events result;
+ for (size_t i = 0; i < filteredCount; i++) {
+ result.push_back(events[i].type);
+ }
+ delete[] events;
+
+ return result;
+ }
+
+ Events getExpectedEvents(const Events &events) const {
+ Events output;
+ for (size_t i = 0; i != events.size(); i++) {
+ // Copy events if the event queue is configured to receive them
+ if (events[i] != SENSOR_TYPE_ADDITIONAL_INFO || mQueue->requestAdditionalInfo) {
+ output.push_back(events[i]);
+ }
+ }
+ return output;
+ }
+
+ void runFilterTest(const Events& events) {
+ Events filtered = filterEvents(events);
+ Events expected = getExpectedEvents(events);
+ EXPECT_EQ(expected.size(), filtered.size());
+ EXPECT_EQ(expected, filtered);
+ }
+
+private:
+ sp<SensorEventQueue> mQueue;
+};
+
+TEST_F(SensorEventQueueTest, FilterZeroEvents) {
+ configureAdditionalInfo(false /* enable */);
+ runFilterTest({});
+}
+
+TEST_F(SensorEventQueueTest, FilterEvents_ReceiveAdditionalInfo) {
+ configureAdditionalInfo(true /* enable */);
+ runFilterTest({SENSOR_TYPE_ADDITIONAL_INFO,
+ SENSOR_TYPE_ACCELEROMETER,
+ SENSOR_TYPE_GYROSCOPE,
+ SENSOR_TYPE_ADDITIONAL_INFO,
+ SENSOR_TYPE_ADDITIONAL_INFO,
+ SENSOR_TYPE_MAGNETIC_FIELD});
+}
+
+TEST_F(SensorEventQueueTest, FilterEvents_RemoveAll) {
+ configureAdditionalInfo(false /* enable */);
+ runFilterTest({SENSOR_TYPE_ADDITIONAL_INFO,
+ SENSOR_TYPE_ADDITIONAL_INFO,
+ SENSOR_TYPE_ADDITIONAL_INFO});
+}
+
+TEST_F(SensorEventQueueTest, FilterEvents_RemoveFirst) {
+ configureAdditionalInfo(false /* enable */);
+ runFilterTest({SENSOR_TYPE_ADDITIONAL_INFO,
+ SENSOR_TYPE_ACCELEROMETER,
+ SENSOR_TYPE_GYROSCOPE,
+ SENSOR_TYPE_MAGNETIC_FIELD});
+}
+
+TEST_F(SensorEventQueueTest, FilterEvents_RemoveAllButOne) {
+ configureAdditionalInfo(false /* enable */);
+ runFilterTest({SENSOR_TYPE_ADDITIONAL_INFO,
+ SENSOR_TYPE_ADDITIONAL_INFO,
+ SENSOR_TYPE_ACCELEROMETER,
+ SENSOR_TYPE_ADDITIONAL_INFO});
+}
+
+TEST_F(SensorEventQueueTest, FilterEvents_RemoveLast) {
+ configureAdditionalInfo(false /* enable */);
+ runFilterTest({SENSOR_TYPE_ACCELEROMETER,
+ SENSOR_TYPE_GYROSCOPE,
+ SENSOR_TYPE_MAGNETIC_FIELD,
+ SENSOR_TYPE_ADDITIONAL_INFO});
+}
+
+TEST_F(SensorEventQueueTest, FilterEvents_RemoveConsecutive) {
+ configureAdditionalInfo(false /* enable */);
+ runFilterTest({SENSOR_TYPE_MAGNETIC_FIELD,
+ SENSOR_TYPE_ADDITIONAL_INFO,
+ SENSOR_TYPE_ADDITIONAL_INFO,
+ SENSOR_TYPE_ADDITIONAL_INFO,
+ SENSOR_TYPE_ADDITIONAL_INFO,
+ SENSOR_TYPE_ADDITIONAL_INFO,
+ SENSOR_TYPE_ACCELEROMETER});
+}
+
+TEST_F(SensorEventQueueTest, FilterEvents_RemoveInterleaved) {
+ configureAdditionalInfo(false /* enable */);
+ runFilterTest({SENSOR_TYPE_ACCELEROMETER,
+ SENSOR_TYPE_GYROSCOPE,
+ SENSOR_TYPE_ADDITIONAL_INFO,
+ SENSOR_TYPE_ACCELEROMETER,
+ SENSOR_TYPE_GYROSCOPE,
+ SENSOR_TYPE_ADDITIONAL_INFO,
+ SENSOR_TYPE_MAGNETIC_FIELD});
+}
+
+TEST_F(SensorEventQueueTest, FilterEvents_ReconfigureAdditionalInfo) {
+ configureAdditionalInfo(false /* enable */);
+ const Events events = {SENSOR_TYPE_ACCELEROMETER,
+ SENSOR_TYPE_GYROSCOPE,
+ SENSOR_TYPE_ADDITIONAL_INFO,
+ SENSOR_TYPE_MAGNETIC_FIELD,
+ SENSOR_TYPE_ADDITIONAL_INFO};
+ runFilterTest(events);
+
+ // Update setting to request Additional Info
+ configureAdditionalInfo(true /* enable */);
+ runFilterTest(events);
+
+ // Update setting to stop requesting Additional Info
+ configureAdditionalInfo(true /* enable */);
+ runFilterTest(events);
+}
+
+} // namespace android
diff --git a/libs/sensorprivacy/SensorPrivacyManager.cpp b/libs/sensorprivacy/SensorPrivacyManager.cpp
index 1da79a0..f973cba 100644
--- a/libs/sensorprivacy/SensorPrivacyManager.cpp
+++ b/libs/sensorprivacy/SensorPrivacyManager.cpp
@@ -85,4 +85,22 @@
return false;
}
+status_t SensorPrivacyManager::linkToDeath(const sp<IBinder::DeathRecipient>& recipient)
+{
+ sp<hardware::ISensorPrivacyManager> service = getService();
+ if (service != nullptr) {
+ return IInterface::asBinder(service)->linkToDeath(recipient);
+ }
+ return INVALID_OPERATION;
+}
+
+status_t SensorPrivacyManager::unlinkToDeath(const sp<IBinder::DeathRecipient>& recipient)
+{
+ sp<hardware::ISensorPrivacyManager> service = getService();
+ if (service != nullptr) {
+ return IInterface::asBinder(service)->unlinkToDeath(recipient);
+ }
+ return INVALID_OPERATION;
+}
+
}; // namespace android
diff --git a/libs/sensorprivacy/include/sensorprivacy/SensorPrivacyManager.h b/libs/sensorprivacy/include/sensorprivacy/SensorPrivacyManager.h
index 8826595..2546a68 100644
--- a/libs/sensorprivacy/include/sensorprivacy/SensorPrivacyManager.h
+++ b/libs/sensorprivacy/include/sensorprivacy/SensorPrivacyManager.h
@@ -34,6 +34,9 @@
void removeSensorPrivacyListener(const sp<hardware::ISensorPrivacyListener>& listener);
bool isSensorPrivacyEnabled();
+ status_t linkToDeath(const sp<IBinder::DeathRecipient>& recipient);
+ status_t unlinkToDeath(const sp<IBinder::DeathRecipient>& recipient);
+
private:
Mutex mLock;
sp<hardware::ISensorPrivacyManager> mService;
diff --git a/libs/ui/Android.bp b/libs/ui/Android.bp
index 956465c..00e227f 100644
--- a/libs/ui/Android.bp
+++ b/libs/ui/Android.bp
@@ -60,7 +60,9 @@
"Fence.cpp",
"FenceTime.cpp",
"FrameStats.cpp",
+ "Gralloc.cpp",
"Gralloc2.cpp",
+ "Gralloc3.cpp",
"GraphicBuffer.cpp",
"GraphicBufferAllocator.cpp",
"GraphicBufferMapper.cpp",
@@ -68,6 +70,7 @@
"PixelFormat.cpp",
"Rect.cpp",
"Region.cpp",
+ "Size.cpp",
"Transform.cpp",
"UiConfig.cpp",
],
@@ -77,11 +80,14 @@
],
shared_libs: [
+ "android.frameworks.bufferhub@1.0",
"android.hardware.graphics.allocator@2.0",
+ "android.hardware.graphics.allocator@3.0",
"android.hardware.graphics.common@1.2",
"android.hardware.graphics.mapper@2.0",
"android.hardware.graphics.mapper@2.1",
- "android.hardware.configstore@1.0",
+ "android.hardware.graphics.mapper@3.0",
+ "android.hardware.configstore@1.2",
"android.hardware.configstore-utils",
"libbase",
"libcutils",
@@ -93,10 +99,10 @@
"libutils",
"libutilscallstack",
"liblog",
- "libpdx_default_transport", // TODO(b/112338294): Remove this once BufferHub moved to use Binder.
],
export_shared_lib_headers: [
+ "android.hardware.configstore@1.2",
"android.hardware.graphics.common@1.2",
],
@@ -121,6 +127,7 @@
"libnativewindow_headers",
],
exclude_shared_libs: [
+ "android.frameworks.bufferhub@1.0",
"libpdx_default_transport",
],
},
@@ -148,9 +155,6 @@
"libhardware_headers",
"libui_headers",
],
-
- // TODO(b/117568153): Temporarily opt out using libcrt.
- no_libcrt: true,
}
cc_library_headers {
diff --git a/libs/ui/BufferHubBuffer.cpp b/libs/ui/BufferHubBuffer.cpp
index 0582e1a..4b20772 100644
--- a/libs/ui/BufferHubBuffer.cpp
+++ b/libs/ui/BufferHubBuffer.cpp
@@ -14,151 +14,195 @@
* limitations under the License.
*/
-// We would eliminate the clang warnings introduced by libdpx.
-// TODO(b/112338294): Remove those once BufferHub moved to use Binder
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wconversion"
-#pragma clang diagnostic ignored "-Wdouble-promotion"
-#pragma clang diagnostic ignored "-Wgnu-case-range"
-#pragma clang diagnostic ignored "-Wgnu-zero-variadic-macro-arguments"
-#pragma clang diagnostic ignored "-Winconsistent-missing-destructor-override"
-#pragma clang diagnostic ignored "-Wnested-anon-types"
-#pragma clang diagnostic ignored "-Wpacked"
-#pragma clang diagnostic ignored "-Wshadow"
-#pragma clang diagnostic ignored "-Wsign-conversion"
-#pragma clang diagnostic ignored "-Wswitch-enum"
-#pragma clang diagnostic ignored "-Wundefined-func-template"
-#pragma clang diagnostic ignored "-Wunused-template"
-#pragma clang diagnostic ignored "-Wweak-vtables"
-#include <pdx/default_transport/client_channel.h>
-#include <pdx/default_transport/client_channel_factory.h>
-#include <pdx/file_handle.h>
-#include <private/dvr/bufferhub_rpc.h>
-#pragma clang diagnostic pop
-
#include <poll.h>
#include <android-base/unique_fd.h>
+#include <android/frameworks/bufferhub/1.0/IBufferHub.h>
+#include <log/log.h>
#include <ui/BufferHubBuffer.h>
#include <ui/BufferHubDefs.h>
+#include <utils/Trace.h>
-using android::base::unique_fd;
-using android::dvr::BufferTraits;
-using android::dvr::DetachedBufferRPC;
-using android::dvr::NativeHandleWrapper;
-
-// TODO(b/112338294): Remove PDX dependencies from libui.
-using android::pdx::LocalChannelHandle;
-using android::pdx::LocalHandle;
-using android::pdx::Status;
-using android::pdx::default_transport::ClientChannel;
-using android::pdx::default_transport::ClientChannelFactory;
+using ::android::base::unique_fd;
+using ::android::BufferHubDefs::AnyClientAcquired;
+using ::android::BufferHubDefs::AnyClientGained;
+using ::android::BufferHubDefs::IsClientAcquired;
+using ::android::BufferHubDefs::IsClientGained;
+using ::android::BufferHubDefs::IsClientPosted;
+using ::android::BufferHubDefs::IsClientReleased;
+using ::android::frameworks::bufferhub::V1_0::BufferHubStatus;
+using ::android::frameworks::bufferhub::V1_0::BufferTraits;
+using ::android::frameworks::bufferhub::V1_0::IBufferClient;
+using ::android::frameworks::bufferhub::V1_0::IBufferHub;
+using ::android::hardware::hidl_handle;
+using ::android::hardware::graphics::common::V1_2::HardwareBufferDescription;
namespace android {
-namespace {
-
-// TODO(b/112338294): Remove this string literal after refactoring BufferHub
-// to use Binder.
-static constexpr char kBufferHubClientPath[] = "system/buffer_hub/client";
-
-using BufferHubDefs::AnyClientAcquired;
-using BufferHubDefs::AnyClientGained;
-using BufferHubDefs::AnyClientPosted;
-using BufferHubDefs::IsClientAcquired;
-using BufferHubDefs::IsClientGained;
-using BufferHubDefs::IsClientPosted;
-using BufferHubDefs::IsClientReleased;
-using BufferHubDefs::kHighBitsMask;
-
-} // namespace
-
-BufferHubClient::BufferHubClient() : Client(ClientChannelFactory::Create(kBufferHubClientPath)) {}
-
-BufferHubClient::BufferHubClient(LocalChannelHandle mChannelHandle)
- : Client(ClientChannel::Create(std::move(mChannelHandle))) {}
-
-BufferHubClient::~BufferHubClient() {}
-
-bool BufferHubClient::IsValid() const {
- return IsConnected() && GetChannelHandle().valid();
+std::unique_ptr<BufferHubBuffer> BufferHubBuffer::Create(uint32_t width, uint32_t height,
+ uint32_t layerCount, uint32_t format,
+ uint64_t usage, size_t userMetadataSize) {
+ auto buffer = std::unique_ptr<BufferHubBuffer>(
+ new BufferHubBuffer(width, height, layerCount, format, usage, userMetadataSize));
+ return buffer->IsValid() ? std::move(buffer) : nullptr;
}
-LocalChannelHandle BufferHubClient::TakeChannelHandle() {
- if (IsConnected()) {
- return std::move(GetChannelHandle());
- } else {
- return {};
+std::unique_ptr<BufferHubBuffer> BufferHubBuffer::Import(const native_handle_t* token) {
+ if (token == nullptr) {
+ ALOGE("%s: token cannot be nullptr!", __FUNCTION__);
+ return nullptr;
}
+
+ auto buffer = std::unique_ptr<BufferHubBuffer>(new BufferHubBuffer(token));
+ return buffer->IsValid() ? std::move(buffer) : nullptr;
}
BufferHubBuffer::BufferHubBuffer(uint32_t width, uint32_t height, uint32_t layerCount,
- uint32_t format, uint64_t usage, size_t mUserMetadataSize) {
+ uint32_t format, uint64_t usage, size_t userMetadataSize) {
ATRACE_CALL();
- ALOGD("%s: width=%u height=%u layerCount=%u, format=%u usage=%" PRIx64 " mUserMetadataSize=%zu",
- __FUNCTION__, width, height, layerCount, format, usage, mUserMetadataSize);
+ ALOGD("%s: width=%u height=%u layerCount=%u, format=%u "
+ "usage=%" PRIx64 " mUserMetadataSize=%zu",
+ __FUNCTION__, width, height, layerCount, format, usage, userMetadataSize);
- auto status =
- mClient.InvokeRemoteMethod<DetachedBufferRPC::Create>(width, height, layerCount, format,
- usage, mUserMetadataSize);
- if (!status) {
- ALOGE("%s: Failed to create detached buffer: %s", __FUNCTION__,
- status.GetErrorMessage().c_str());
- mClient.Close(-status.error());
+ sp<IBufferHub> bufferhub = IBufferHub::getService();
+ if (bufferhub.get() == nullptr) {
+ ALOGE("%s: BufferHub service not found!", __FUNCTION__);
+ return;
}
- const int ret = ImportGraphicBuffer();
- if (ret < 0) {
- ALOGE("%s: Failed to import buffer: %s", __FUNCTION__, strerror(-ret));
- mClient.Close(ret);
+ AHardwareBuffer_Desc aDesc = {width, height, layerCount, format,
+ usage, /*stride=*/0UL, /*rfu0=*/0UL, /*rfu1=*/0ULL};
+ HardwareBufferDescription desc;
+ memcpy(&desc, &aDesc, sizeof(HardwareBufferDescription));
+
+ BufferHubStatus ret;
+ sp<IBufferClient> client;
+ BufferTraits bufferTraits;
+ IBufferHub::allocateBuffer_cb alloc_cb = [&](const auto& status, const auto& outClient,
+ const auto& traits) {
+ ret = status;
+ client = std::move(outClient);
+ bufferTraits = std::move(traits);
+ };
+
+ if (!bufferhub->allocateBuffer(desc, static_cast<uint32_t>(userMetadataSize), alloc_cb)
+ .isOk()) {
+ ALOGE("%s: allocateBuffer transaction failed!", __FUNCTION__);
+ return;
+ } else if (ret != BufferHubStatus::NO_ERROR) {
+ ALOGE("%s: allocateBuffer failed with error %u.", __FUNCTION__, ret);
+ return;
+ } else if (client == nullptr) {
+ ALOGE("%s: allocateBuffer got null BufferClient.", __FUNCTION__);
+ return;
+ }
+
+ const int importRet = initWithBufferTraits(bufferTraits);
+ if (importRet < 0) {
+ ALOGE("%s: Failed to import buffer: %s", __FUNCTION__, strerror(-importRet));
+ client->close();
+ }
+ mBufferClient = std::move(client);
+}
+
+BufferHubBuffer::BufferHubBuffer(const native_handle_t* token) {
+ sp<IBufferHub> bufferhub = IBufferHub::getService();
+ if (bufferhub.get() == nullptr) {
+ ALOGE("%s: BufferHub service not found!", __FUNCTION__);
+ return;
+ }
+
+ BufferHubStatus ret;
+ sp<IBufferClient> client;
+ BufferTraits bufferTraits;
+ IBufferHub::importBuffer_cb import_cb = [&](const auto& status, const auto& outClient,
+ const auto& traits) {
+ ret = status;
+ client = std::move(outClient);
+ bufferTraits = std::move(traits);
+ };
+
+ // hidl_handle(native_handle_t*) simply creates a raw pointer reference withouth ownership
+ // transfer.
+ if (!bufferhub->importBuffer(hidl_handle(token), import_cb).isOk()) {
+ ALOGE("%s: importBuffer transaction failed!", __FUNCTION__);
+ return;
+ } else if (ret != BufferHubStatus::NO_ERROR) {
+ ALOGE("%s: importBuffer failed with error %u.", __FUNCTION__, ret);
+ return;
+ } else if (client == nullptr) {
+ ALOGE("%s: importBuffer got null BufferClient.", __FUNCTION__);
+ return;
+ }
+
+ const int importRet = initWithBufferTraits(bufferTraits);
+ if (importRet < 0) {
+ ALOGE("%s: Failed to import buffer: %s", __FUNCTION__, strerror(-importRet));
+ client->close();
+ }
+ mBufferClient = std::move(client);
+}
+
+BufferHubBuffer::~BufferHubBuffer() {
+ // Close buffer client to avoid possible race condition: user could first duplicate and hold
+ // token with the original buffer gone, and then try to import the token. The close function
+ // will explicitly invalidate the token to avoid this.
+ if (mBufferClient != nullptr) {
+ if (!mBufferClient->close().isOk()) {
+ ALOGE("%s: close BufferClient transaction failed!", __FUNCTION__);
+ }
}
}
-BufferHubBuffer::BufferHubBuffer(LocalChannelHandle mChannelHandle)
- : mClient(std::move(mChannelHandle)) {
- const int ret = ImportGraphicBuffer();
- if (ret < 0) {
- ALOGE("%s: Failed to import buffer: %s", __FUNCTION__, strerror(-ret));
- mClient.Close(ret);
- }
-}
-
-int BufferHubBuffer::ImportGraphicBuffer() {
+int BufferHubBuffer::initWithBufferTraits(const BufferTraits& bufferTraits) {
ATRACE_CALL();
- auto status = mClient.InvokeRemoteMethod<DetachedBufferRPC::Import>();
- if (!status) {
- ALOGE("%s: Failed to import GraphicBuffer: %s", __FUNCTION__,
- status.GetErrorMessage().c_str());
- return -status.error();
+ if (bufferTraits.bufferInfo.getNativeHandle() == nullptr) {
+ ALOGE("%s: missing buffer info handle.", __FUNCTION__);
+ return -EINVAL;
}
- BufferTraits<LocalHandle> bufferTraits = status.take();
- if (bufferTraits.id() < 0) {
- ALOGE("%s: Received an invalid id!", __FUNCTION__);
- return -EIO;
+ if (bufferTraits.bufferHandle.getNativeHandle() == nullptr) {
+ ALOGE("%s: missing gralloc handle.", __FUNCTION__);
+ return -EINVAL;
}
- // Stash the buffer id to replace the value in mId.
- const int bufferId = bufferTraits.id();
-
- // Import the metadata.
- LocalHandle metadataHandle = bufferTraits.take_metadata_handle();
- unique_fd metadataFd(metadataHandle.Release());
- mMetadata = BufferHubMetadata::Import(std::move(metadataFd));
-
+ // Import fds. Dup fds because hidl_handle owns the fds.
+ unique_fd ashmemFd(fcntl(bufferTraits.bufferInfo->data[0], F_DUPFD_CLOEXEC, 0));
+ mMetadata = BufferHubMetadata::Import(std::move(ashmemFd));
if (!mMetadata.IsValid()) {
- ALOGE("%s: invalid metadata.", __FUNCTION__);
- return -ENOMEM;
+ ALOGE("%s: Received an invalid metadata.", __FUNCTION__);
+ return -EINVAL;
}
- if (mMetadata.metadata_size() != bufferTraits.metadata_size()) {
- ALOGE("%s: metadata buffer too small: %zu, expected: %" PRIu64 ".", __FUNCTION__,
- mMetadata.metadata_size(), bufferTraits.metadata_size());
- return -ENOMEM;
+ mEventFd = BufferHubEventFd(fcntl(bufferTraits.bufferInfo->data[1], F_DUPFD_CLOEXEC, 0));
+ if (!mEventFd.isValid()) {
+ ALOGE("%s: Received ad invalid event fd.", __FUNCTION__);
+ return -EINVAL;
}
- size_t metadataSize = static_cast<size_t>(bufferTraits.metadata_size());
+ int bufferId = bufferTraits.bufferInfo->data[2];
+ if (bufferId < 0) {
+ ALOGE("%s: Received an invalid (negative) id.", __FUNCTION__);
+ return -EINVAL;
+ }
+
+ uint32_t clientBitMask;
+ memcpy(&clientBitMask, &bufferTraits.bufferInfo->data[3], sizeof(clientBitMask));
+ if (clientBitMask == 0U) {
+ ALOGE("%s: Received an invalid client state mask.", __FUNCTION__);
+ return -EINVAL;
+ }
+
+ uint32_t userMetadataSize;
+ memcpy(&userMetadataSize, &bufferTraits.bufferInfo->data[4], sizeof(userMetadataSize));
+ if (mMetadata.user_metadata_size() != userMetadataSize) {
+ ALOGE("%s: user metadata size not match: expected %u, actual %zu.", __FUNCTION__,
+ userMetadataSize, mMetadata.user_metadata_size());
+ return -EINVAL;
+ }
+
+ size_t metadataSize = static_cast<size_t>(mMetadata.metadata_size());
if (metadataSize < BufferHubDefs::kMetadataHeaderSize) {
ALOGE("%s: metadata too small: %zu", __FUNCTION__, metadataSize);
return -EINVAL;
@@ -179,24 +223,14 @@
// Import the buffer: We only need to hold on the native_handle_t here so that
// GraphicBuffer instance can be created in future.
- mBufferHandle = bufferTraits.take_buffer_handle();
+ mBufferHandle = std::move(bufferTraits.bufferHandle);
+ memcpy(&mBufferDesc, &bufferTraits.bufferDesc, sizeof(AHardwareBuffer_Desc));
- // Populate buffer desc based on buffer traits.
- mBufferDesc.width = bufferTraits.width();
- mBufferDesc.height = bufferTraits.height();
- mBufferDesc.layers = bufferTraits.layer_count();
- mBufferDesc.format = bufferTraits.format();
- mBufferDesc.usage = bufferTraits.usage();
- mBufferDesc.stride = bufferTraits.stride();
- mBufferDesc.rfu0 = 0U;
- mBufferDesc.rfu1 = 0U;
-
- // If all imports succeed, replace the previous buffer and id.
mId = bufferId;
- mClientStateMask = bufferTraits.client_state_mask();
+ mClientStateMask = clientBitMask;
// TODO(b/112012161) Set up shared fences.
- ALOGD("%s: id=%d, buffer_state=%" PRIx32 ".", __FUNCTION__, id(),
+ ALOGD("%s: id=%d, buffer_state=%" PRIx32 ".", __FUNCTION__, mId,
buffer_state_->load(std::memory_order_acquire));
return 0;
}
@@ -226,8 +260,7 @@
int BufferHubBuffer::Post() {
uint32_t current_buffer_state = buffer_state_->load(std::memory_order_acquire);
- uint32_t current_active_clients_bit_mask = 0U;
- uint32_t updated_buffer_state = 0U;
+ uint32_t updated_buffer_state = (~mClientStateMask) & BufferHubDefs::kHighBitsMask;
do {
if (!IsClientGained(current_buffer_state, mClientStateMask)) {
ALOGE("%s: Cannot post a buffer that is not gained by this client. buffer_id=%d "
@@ -236,9 +269,7 @@
return -EBUSY;
}
// Set the producer client buffer state to released, other clients' buffer state to posted.
- current_active_clients_bit_mask = active_clients_bit_mask_->load(std::memory_order_acquire);
- updated_buffer_state =
- current_active_clients_bit_mask & (~mClientStateMask) & kHighBitsMask;
+ // Post to all existing and non-existing clients.
} while (!buffer_state_->compare_exchange_weak(current_buffer_state, updated_buffer_state,
std::memory_order_acq_rel,
std::memory_order_acquire));
@@ -287,24 +318,41 @@
return 0;
}
-int BufferHubBuffer::Poll(int timeoutMs) {
- ATRACE_CALL();
-
- pollfd p = {mClient.event_fd(), POLLIN, 0};
- return poll(&p, 1, timeoutMs);
+bool BufferHubBuffer::IsReleased() const {
+ return (buffer_state_->load(std::memory_order_acquire) &
+ active_clients_bit_mask_->load(std::memory_order_acquire)) == 0;
}
-Status<LocalChannelHandle> BufferHubBuffer::Duplicate() {
- ATRACE_CALL();
- ALOGD("%s: id=%d.", __FUNCTION__, mId);
+bool BufferHubBuffer::IsValid() const {
+ return mBufferHandle.getNativeHandle() != nullptr && mId >= 0 && mClientStateMask != 0U &&
+ mEventFd.get() >= 0 && mMetadata.IsValid() && mBufferClient != nullptr;
+}
- auto statusOrHandle = mClient.InvokeRemoteMethod<DetachedBufferRPC::Duplicate>();
-
- if (!statusOrHandle.ok()) {
- ALOGE("%s: Failed to duplicate buffer (id=%d): %s.", __FUNCTION__, mId,
- statusOrHandle.GetErrorMessage().c_str());
+native_handle_t* BufferHubBuffer::Duplicate() {
+ if (mBufferClient == nullptr) {
+ ALOGE("%s: missing BufferClient!", __FUNCTION__);
+ return nullptr;
}
- return statusOrHandle;
+
+ hidl_handle token;
+ BufferHubStatus ret;
+ IBufferClient::duplicate_cb dup_cb = [&](const auto& outToken, const auto& status) {
+ token = std::move(outToken);
+ ret = status;
+ };
+
+ if (!mBufferClient->duplicate(dup_cb).isOk()) {
+ ALOGE("%s: duplicate transaction failed!", __FUNCTION__);
+ return nullptr;
+ } else if (ret != BufferHubStatus::NO_ERROR) {
+ ALOGE("%s: duplicate failed with error %u.", __FUNCTION__, ret);
+ return nullptr;
+ } else if (token.getNativeHandle() == nullptr) {
+ ALOGE("%s: duplicate got null token.", __FUNCTION__);
+ return nullptr;
+ }
+
+ return native_handle_clone(token.getNativeHandle());
}
} // namespace android
diff --git a/libs/ui/BufferHubEventFd.cpp b/libs/ui/BufferHubEventFd.cpp
index 978b352..bffc2ca 100644
--- a/libs/ui/BufferHubEventFd.cpp
+++ b/libs/ui/BufferHubEventFd.cpp
@@ -23,6 +23,8 @@
BufferHubEventFd::BufferHubEventFd() : mFd(eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK)) {}
+BufferHubEventFd::BufferHubEventFd(int fd) : mFd(fd) {}
+
status_t BufferHubEventFd::signal() const {
if (!isValid()) {
ALOGE("%s: cannot signal an invalid eventfd.", __FUNCTION__);
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplaySurface.cpp b/libs/ui/Gralloc.cpp
similarity index 67%
copy from services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplaySurface.cpp
copy to libs/ui/Gralloc.cpp
index e6ac6bf..8e09a13 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplaySurface.cpp
+++ b/libs/ui/Gralloc.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,14 +14,14 @@
* limitations under the License.
*/
-#include "mock/DisplayHardware/MockDisplaySurface.h"
+#define LOG_TAG "Gralloc"
+
+#include <ui/Gralloc.h>
namespace android {
-namespace mock {
-// Explicit default instantiation is recommended.
-DisplaySurface::DisplaySurface() = default;
-DisplaySurface::~DisplaySurface() = default;
+GrallocMapper::~GrallocMapper() {}
-} // namespace mock
+GrallocAllocator::~GrallocAllocator() {}
+
} // namespace android
diff --git a/libs/ui/Gralloc2.cpp b/libs/ui/Gralloc2.cpp
index 20f27c5..5dc4530 100644
--- a/libs/ui/Gralloc2.cpp
+++ b/libs/ui/Gralloc2.cpp
@@ -27,9 +27,15 @@
#include <sync/sync.h>
#pragma clang diagnostic pop
-namespace android {
+using android::hardware::graphics::allocator::V2_0::IAllocator;
+using android::hardware::graphics::common::V1_1::BufferUsage;
+using android::hardware::graphics::common::V1_1::PixelFormat;
+using android::hardware::graphics::mapper::V2_0::BufferDescriptor;
+using android::hardware::graphics::mapper::V2_0::Error;
+using android::hardware::graphics::mapper::V2_0::YCbCrLayout;
+using android::hardware::graphics::mapper::V2_1::IMapper;
-namespace Gralloc2 {
+namespace android {
namespace {
@@ -59,17 +65,26 @@
return valid11UsageBits;
}
+static inline IMapper::Rect sGralloc2Rect(const Rect& rect) {
+ IMapper::Rect outRect{};
+ outRect.left = rect.left;
+ outRect.top = rect.top;
+ outRect.width = rect.width();
+ outRect.height = rect.height();
+ return outRect;
+}
+
} // anonymous namespace
-void Mapper::preload() {
+void Gralloc2Mapper::preload() {
android::hardware::preloadPassthroughService<hardware::graphics::mapper::V2_0::IMapper>();
}
-Mapper::Mapper()
-{
+Gralloc2Mapper::Gralloc2Mapper() {
mMapper = hardware::graphics::mapper::V2_0::IMapper::getService();
if (mMapper == nullptr) {
- LOG_ALWAYS_FATAL("gralloc-mapper is missing");
+ ALOGW("mapper 2.x is not supported");
+ return;
}
if (mMapper->isRemote()) {
LOG_ALWAYS_FATAL("gralloc-mapper must be in passthrough mode");
@@ -79,30 +94,37 @@
mMapperV2_1 = IMapper::castFrom(mMapper);
}
-Gralloc2::Error Mapper::validateBufferDescriptorInfo(
- const IMapper::BufferDescriptorInfo& descriptorInfo) const {
+bool Gralloc2Mapper::isLoaded() const {
+ return mMapper != nullptr;
+}
+
+status_t Gralloc2Mapper::validateBufferDescriptorInfo(
+ IMapper::BufferDescriptorInfo* descriptorInfo) const {
uint64_t validUsageBits = getValid10UsageBits();
if (mMapperV2_1 != nullptr) {
validUsageBits = validUsageBits | getValid11UsageBits();
}
- if (descriptorInfo.usage & ~validUsageBits) {
+ if (descriptorInfo->usage & ~validUsageBits) {
ALOGE("buffer descriptor contains invalid usage bits 0x%" PRIx64,
- descriptorInfo.usage & ~validUsageBits);
- return Error::BAD_VALUE;
+ descriptorInfo->usage & ~validUsageBits);
+ return BAD_VALUE;
}
- return Error::NONE;
+ return NO_ERROR;
}
-Error Mapper::createDescriptor(
- const IMapper::BufferDescriptorInfo& descriptorInfo,
- BufferDescriptor* outDescriptor) const
-{
- Error error = validateBufferDescriptorInfo(descriptorInfo);
- if (error != Error::NONE) {
- return error;
+status_t Gralloc2Mapper::createDescriptor(void* bufferDescriptorInfo,
+ void* outBufferDescriptor) const {
+ IMapper::BufferDescriptorInfo* descriptorInfo =
+ static_cast<IMapper::BufferDescriptorInfo*>(bufferDescriptorInfo);
+ BufferDescriptor* outDescriptor = static_cast<BufferDescriptor*>(outBufferDescriptor);
+
+ status_t status = validateBufferDescriptorInfo(descriptorInfo);
+ if (status != NO_ERROR) {
+ return status;
}
+ Error error;
auto hidl_cb = [&](const auto& tmpError, const auto& tmpDescriptor)
{
error = tmpError;
@@ -115,24 +137,23 @@
hardware::Return<void> ret;
if (mMapperV2_1 != nullptr) {
- ret = mMapperV2_1->createDescriptor_2_1(descriptorInfo, hidl_cb);
+ ret = mMapperV2_1->createDescriptor_2_1(*descriptorInfo, hidl_cb);
} else {
const hardware::graphics::mapper::V2_0::IMapper::BufferDescriptorInfo info = {
- descriptorInfo.width,
- descriptorInfo.height,
- descriptorInfo.layerCount,
- static_cast<hardware::graphics::common::V1_0::PixelFormat>(descriptorInfo.format),
- descriptorInfo.usage,
+ descriptorInfo->width,
+ descriptorInfo->height,
+ descriptorInfo->layerCount,
+ static_cast<hardware::graphics::common::V1_0::PixelFormat>(descriptorInfo->format),
+ descriptorInfo->usage,
};
ret = mMapper->createDescriptor(info, hidl_cb);
}
- return (ret.isOk()) ? error : kTransactionError;
+ return static_cast<status_t>((ret.isOk()) ? error : kTransactionError);
}
-Error Mapper::importBuffer(const hardware::hidl_handle& rawHandle,
- buffer_handle_t* outBufferHandle) const
-{
+status_t Gralloc2Mapper::importBuffer(const hardware::hidl_handle& rawHandle,
+ buffer_handle_t* outBufferHandle) const {
Error error;
auto ret = mMapper->importBuffer(rawHandle,
[&](const auto& tmpError, const auto& tmpBuffer)
@@ -145,11 +166,10 @@
*outBufferHandle = static_cast<buffer_handle_t>(tmpBuffer);
});
- return (ret.isOk()) ? error : kTransactionError;
+ return static_cast<status_t>((ret.isOk()) ? error : kTransactionError);
}
-void Mapper::freeBuffer(buffer_handle_t bufferHandle) const
-{
+void Gralloc2Mapper::freeBuffer(buffer_handle_t bufferHandle) const {
auto buffer = const_cast<native_handle_t*>(bufferHandle);
auto ret = mMapper->freeBuffer(buffer);
@@ -158,23 +178,29 @@
buffer, error);
}
-Error Mapper::validateBufferSize(buffer_handle_t bufferHandle,
- const IMapper::BufferDescriptorInfo& descriptorInfo,
- uint32_t stride) const
-{
+status_t Gralloc2Mapper::validateBufferSize(buffer_handle_t bufferHandle, uint32_t width,
+ uint32_t height, android::PixelFormat format,
+ uint32_t layerCount, uint64_t usage,
+ uint32_t stride) const {
if (mMapperV2_1 == nullptr) {
- return Error::NONE;
+ return NO_ERROR;
}
+ IMapper::BufferDescriptorInfo descriptorInfo = {};
+ descriptorInfo.width = width;
+ descriptorInfo.height = height;
+ descriptorInfo.layerCount = layerCount;
+ descriptorInfo.format = static_cast<hardware::graphics::common::V1_1::PixelFormat>(format);
+ descriptorInfo.usage = usage;
+
auto buffer = const_cast<native_handle_t*>(bufferHandle);
auto ret = mMapperV2_1->validateBufferSize(buffer, descriptorInfo, stride);
- return (ret.isOk()) ? static_cast<Error>(ret) : kTransactionError;
+ return static_cast<status_t>((ret.isOk()) ? static_cast<Error>(ret) : kTransactionError);
}
-void Mapper::getTransportSize(buffer_handle_t bufferHandle,
- uint32_t* outNumFds, uint32_t* outNumInts) const
-{
+void Gralloc2Mapper::getTransportSize(buffer_handle_t bufferHandle, uint32_t* outNumFds,
+ uint32_t* outNumInts) const {
*outNumFds = uint32_t(bufferHandle->numFds);
*outNumInts = uint32_t(bufferHandle->numInts);
@@ -195,19 +221,24 @@
*outNumInts = tmpNumInts;
});
- if (!ret.isOk()) {
- error = kTransactionError;
- }
- ALOGE_IF(error != Error::NONE, "getTransportSize(%p) failed with %d",
- buffer, error);
+ error = (ret.isOk()) ? error : kTransactionError;
+
+ ALOGE_IF(error != Error::NONE, "getTransportSize(%p) failed with %d", buffer, error);
}
-Error Mapper::lock(buffer_handle_t bufferHandle, uint64_t usage,
- const IMapper::Rect& accessRegion,
- int acquireFence, void** outData) const
-{
+status_t Gralloc2Mapper::lock(buffer_handle_t bufferHandle, uint64_t usage, const Rect& bounds,
+ int acquireFence, void** outData, int32_t* outBytesPerPixel,
+ int32_t* outBytesPerStride) const {
+ if (outBytesPerPixel) {
+ *outBytesPerPixel = -1;
+ }
+ if (outBytesPerStride) {
+ *outBytesPerStride = -1;
+ }
auto buffer = const_cast<native_handle_t*>(bufferHandle);
+ IMapper::Rect accessRegion = sGralloc2Rect(bounds);
+
// put acquireFence in a hidl_handle
hardware::hidl_handle acquireFenceHandle;
NATIVE_HANDLE_DECLARE_STORAGE(acquireFenceStorage, 1, 0);
@@ -234,15 +265,19 @@
close(acquireFence);
}
- return (ret.isOk()) ? error : kTransactionError;
+ error = (ret.isOk()) ? error : kTransactionError;
+
+ ALOGW_IF(error != Error::NONE, "lock(%p, ...) failed: %d", bufferHandle, error);
+
+ return static_cast<status_t>(error);
}
-Error Mapper::lock(buffer_handle_t bufferHandle, uint64_t usage,
- const IMapper::Rect& accessRegion,
- int acquireFence, YCbCrLayout* outLayout) const
-{
+status_t Gralloc2Mapper::lock(buffer_handle_t bufferHandle, uint64_t usage, const Rect& bounds,
+ int acquireFence, android_ycbcr* ycbcr) const {
auto buffer = const_cast<native_handle_t*>(bufferHandle);
+ IMapper::Rect accessRegion = sGralloc2Rect(bounds);
+
// put acquireFence in a hidl_handle
hardware::hidl_handle acquireFenceHandle;
NATIVE_HANDLE_DECLARE_STORAGE(acquireFenceStorage, 1, 0);
@@ -252,6 +287,7 @@
acquireFenceHandle = h;
}
+ YCbCrLayout layout;
Error error;
auto ret = mMapper->lockYCbCr(buffer, usage, accessRegion,
acquireFenceHandle,
@@ -262,19 +298,27 @@
return;
}
- *outLayout = tmpLayout;
+ layout = tmpLayout;
});
+ if (error == Error::NONE) {
+ ycbcr->y = layout.y;
+ ycbcr->cb = layout.cb;
+ ycbcr->cr = layout.cr;
+ ycbcr->ystride = static_cast<size_t>(layout.yStride);
+ ycbcr->cstride = static_cast<size_t>(layout.cStride);
+ ycbcr->chroma_step = static_cast<size_t>(layout.chromaStep);
+ }
+
// we own acquireFence even on errors
if (acquireFence >= 0) {
close(acquireFence);
}
- return (ret.isOk()) ? error : kTransactionError;
+ return static_cast<status_t>((ret.isOk()) ? error : kTransactionError);
}
-int Mapper::unlock(buffer_handle_t bufferHandle) const
-{
+int Gralloc2Mapper::unlock(buffer_handle_t bufferHandle) const {
auto buffer = const_cast<native_handle_t*>(bufferHandle);
int releaseFence = -1;
@@ -299,10 +343,7 @@
}
});
- if (!ret.isOk()) {
- error = kTransactionError;
- }
-
+ error = (ret.isOk()) ? error : kTransactionError;
if (error != Error::NONE) {
ALOGE("unlock(%p) failed with %d", buffer, error);
}
@@ -310,17 +351,25 @@
return releaseFence;
}
-Allocator::Allocator(const Mapper& mapper)
- : mMapper(mapper)
-{
+status_t Gralloc2Mapper::isSupported(uint32_t /*width*/, uint32_t /*height*/,
+ android::PixelFormat /*format*/, uint32_t /*layerCount*/,
+ uint64_t /*usage*/, bool* /*outSupported*/) const {
+ return INVALID_OPERATION;
+}
+
+Gralloc2Allocator::Gralloc2Allocator(const Gralloc2Mapper& mapper) : mMapper(mapper) {
mAllocator = IAllocator::getService();
if (mAllocator == nullptr) {
- LOG_ALWAYS_FATAL("gralloc-alloc is missing");
+ ALOGW("allocator 2.x is not supported");
+ return;
}
}
-std::string Allocator::dumpDebugInfo() const
-{
+bool Gralloc2Allocator::isLoaded() const {
+ return mAllocator != nullptr;
+}
+
+std::string Gralloc2Allocator::dumpDebugInfo() const {
std::string debugInfo;
mAllocator->dumpDebugInfo([&](const auto& tmpDebugInfo) {
@@ -330,40 +379,51 @@
return debugInfo;
}
-Error Allocator::allocate(BufferDescriptor descriptor, uint32_t count,
- uint32_t* outStride, buffer_handle_t* outBufferHandles) const
-{
- Error error;
- auto ret = mAllocator->allocate(descriptor, count,
- [&](const auto& tmpError, const auto& tmpStride,
- const auto& tmpBuffers) {
- error = tmpError;
- if (tmpError != Error::NONE) {
- return;
- }
+status_t Gralloc2Allocator::allocate(uint32_t width, uint32_t height, PixelFormat format,
+ uint32_t layerCount, uint64_t usage, uint32_t bufferCount,
+ uint32_t* outStride, buffer_handle_t* outBufferHandles) const {
+ IMapper::BufferDescriptorInfo descriptorInfo = {};
+ descriptorInfo.width = width;
+ descriptorInfo.height = height;
+ descriptorInfo.layerCount = layerCount;
+ descriptorInfo.format = static_cast<hardware::graphics::common::V1_1::PixelFormat>(format);
+ descriptorInfo.usage = usage;
- // import buffers
- for (uint32_t i = 0; i < count; i++) {
- error = mMapper.importBuffer(tmpBuffers[i],
- &outBufferHandles[i]);
- if (error != Error::NONE) {
- for (uint32_t j = 0; j < i; j++) {
- mMapper.freeBuffer(outBufferHandles[j]);
- outBufferHandles[j] = nullptr;
- }
- return;
- }
- }
+ BufferDescriptor descriptor;
+ status_t error = mMapper.createDescriptor(static_cast<void*>(&descriptorInfo),
+ static_cast<void*>(&descriptor));
+ if (error != NO_ERROR) {
+ return error;
+ }
- *outStride = tmpStride;
- });
+ auto ret = mAllocator->allocate(descriptor, bufferCount,
+ [&](const auto& tmpError, const auto& tmpStride,
+ const auto& tmpBuffers) {
+ error = static_cast<status_t>(tmpError);
+ if (tmpError != Error::NONE) {
+ return;
+ }
+
+ // import buffers
+ for (uint32_t i = 0; i < bufferCount; i++) {
+ error = mMapper.importBuffer(tmpBuffers[i],
+ &outBufferHandles[i]);
+ if (error != NO_ERROR) {
+ for (uint32_t j = 0; j < i; j++) {
+ mMapper.freeBuffer(outBufferHandles[j]);
+ outBufferHandles[j] = nullptr;
+ }
+ return;
+ }
+ }
+
+ *outStride = tmpStride;
+ });
// make sure the kernel driver sees BC_FREE_BUFFER and closes the fds now
hardware::IPCThreadState::self()->flushCommands();
- return (ret.isOk()) ? error : kTransactionError;
+ return (ret.isOk()) ? error : static_cast<status_t>(kTransactionError);
}
-} // namespace Gralloc2
-
} // namespace android
diff --git a/libs/ui/Gralloc3.cpp b/libs/ui/Gralloc3.cpp
new file mode 100644
index 0000000..7f8e57c
--- /dev/null
+++ b/libs/ui/Gralloc3.cpp
@@ -0,0 +1,409 @@
+/*
+ * Copyright 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "Gralloc3"
+
+#include <hidl/ServiceManagement.h>
+#include <hwbinder/IPCThreadState.h>
+#include <ui/Gralloc3.h>
+
+#include <inttypes.h>
+#include <log/log.h>
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wzero-length-array"
+#include <sync/sync.h>
+#pragma clang diagnostic pop
+
+using android::hardware::graphics::allocator::V3_0::IAllocator;
+using android::hardware::graphics::common::V1_1::BufferUsage;
+using android::hardware::graphics::mapper::V3_0::BufferDescriptor;
+using android::hardware::graphics::mapper::V3_0::Error;
+using android::hardware::graphics::mapper::V3_0::IMapper;
+using android::hardware::graphics::mapper::V3_0::YCbCrLayout;
+
+namespace android {
+
+namespace {
+
+static constexpr Error kTransactionError = Error::NO_RESOURCES;
+
+uint64_t getValidUsageBits() {
+ static const uint64_t validUsageBits = []() -> uint64_t {
+ uint64_t bits = 0;
+ for (const auto bit :
+ hardware::hidl_enum_range<hardware::graphics::common::V1_0::BufferUsage>()) {
+ bits = bits | bit;
+ }
+ for (const auto bit :
+ hardware::hidl_enum_range<hardware::graphics::common::V1_1::BufferUsage>()) {
+ bits = bits | bit;
+ }
+ return bits;
+ }();
+ return validUsageBits;
+}
+
+static inline IMapper::Rect sGralloc3Rect(const Rect& rect) {
+ IMapper::Rect outRect{};
+ outRect.left = rect.left;
+ outRect.top = rect.top;
+ outRect.width = rect.width();
+ outRect.height = rect.height();
+ return outRect;
+}
+static inline void sBufferDescriptorInfo(uint32_t width, uint32_t height,
+ android::PixelFormat format, uint32_t layerCount,
+ uint64_t usage,
+ IMapper::BufferDescriptorInfo* outDescriptorInfo) {
+ outDescriptorInfo->width = width;
+ outDescriptorInfo->height = height;
+ outDescriptorInfo->layerCount = layerCount;
+ outDescriptorInfo->format = static_cast<hardware::graphics::common::V1_1::PixelFormat>(format);
+ outDescriptorInfo->usage = usage;
+}
+
+} // anonymous namespace
+
+void Gralloc3Mapper::preload() {
+ android::hardware::preloadPassthroughService<IMapper>();
+}
+
+Gralloc3Mapper::Gralloc3Mapper() {
+ mMapper = IMapper::getService();
+ if (mMapper == nullptr) {
+ ALOGW("mapper 3.x is not supported");
+ return;
+ }
+ if (mMapper->isRemote()) {
+ LOG_ALWAYS_FATAL("gralloc-mapper must be in passthrough mode");
+ }
+}
+
+bool Gralloc3Mapper::isLoaded() const {
+ return mMapper != nullptr;
+}
+
+status_t Gralloc3Mapper::validateBufferDescriptorInfo(
+ IMapper::BufferDescriptorInfo* descriptorInfo) const {
+ uint64_t validUsageBits = getValidUsageBits();
+
+ if (descriptorInfo->usage & ~validUsageBits) {
+ ALOGE("buffer descriptor contains invalid usage bits 0x%" PRIx64,
+ descriptorInfo->usage & ~validUsageBits);
+ return BAD_VALUE;
+ }
+ return NO_ERROR;
+}
+
+status_t Gralloc3Mapper::createDescriptor(void* bufferDescriptorInfo,
+ void* outBufferDescriptor) const {
+ IMapper::BufferDescriptorInfo* descriptorInfo =
+ static_cast<IMapper::BufferDescriptorInfo*>(bufferDescriptorInfo);
+ BufferDescriptor* outDescriptor = static_cast<BufferDescriptor*>(outBufferDescriptor);
+
+ status_t status = validateBufferDescriptorInfo(descriptorInfo);
+ if (status != NO_ERROR) {
+ return status;
+ }
+
+ Error error;
+ auto hidl_cb = [&](const auto& tmpError, const auto& tmpDescriptor) {
+ error = tmpError;
+ if (error != Error::NONE) {
+ return;
+ }
+ *outDescriptor = tmpDescriptor;
+ };
+
+ hardware::Return<void> ret = mMapper->createDescriptor(*descriptorInfo, hidl_cb);
+
+ return static_cast<status_t>((ret.isOk()) ? error : kTransactionError);
+}
+
+status_t Gralloc3Mapper::importBuffer(const hardware::hidl_handle& rawHandle,
+ buffer_handle_t* outBufferHandle) const {
+ Error error;
+ auto ret = mMapper->importBuffer(rawHandle, [&](const auto& tmpError, const auto& tmpBuffer) {
+ error = tmpError;
+ if (error != Error::NONE) {
+ return;
+ }
+ *outBufferHandle = static_cast<buffer_handle_t>(tmpBuffer);
+ });
+
+ return static_cast<status_t>((ret.isOk()) ? error : kTransactionError);
+}
+
+void Gralloc3Mapper::freeBuffer(buffer_handle_t bufferHandle) const {
+ auto buffer = const_cast<native_handle_t*>(bufferHandle);
+ auto ret = mMapper->freeBuffer(buffer);
+
+ auto error = (ret.isOk()) ? static_cast<Error>(ret) : kTransactionError;
+ ALOGE_IF(error != Error::NONE, "freeBuffer(%p) failed with %d", buffer, error);
+}
+
+status_t Gralloc3Mapper::validateBufferSize(buffer_handle_t bufferHandle, uint32_t width,
+ uint32_t height, android::PixelFormat format,
+ uint32_t layerCount, uint64_t usage,
+ uint32_t stride) const {
+ IMapper::BufferDescriptorInfo descriptorInfo;
+ sBufferDescriptorInfo(width, height, format, layerCount, usage, &descriptorInfo);
+
+ auto buffer = const_cast<native_handle_t*>(bufferHandle);
+ auto ret = mMapper->validateBufferSize(buffer, descriptorInfo, stride);
+
+ return static_cast<status_t>((ret.isOk()) ? static_cast<Error>(ret) : kTransactionError);
+}
+
+void Gralloc3Mapper::getTransportSize(buffer_handle_t bufferHandle, uint32_t* outNumFds,
+ uint32_t* outNumInts) const {
+ *outNumFds = uint32_t(bufferHandle->numFds);
+ *outNumInts = uint32_t(bufferHandle->numInts);
+
+ Error error;
+ auto buffer = const_cast<native_handle_t*>(bufferHandle);
+ auto ret = mMapper->getTransportSize(buffer,
+ [&](const auto& tmpError, const auto& tmpNumFds,
+ const auto& tmpNumInts) {
+ error = tmpError;
+ if (error != Error::NONE) {
+ return;
+ }
+ *outNumFds = tmpNumFds;
+ *outNumInts = tmpNumInts;
+ });
+
+ error = (ret.isOk()) ? error : kTransactionError;
+
+ ALOGE_IF(error != Error::NONE, "getTransportSize(%p) failed with %d", buffer, error);
+}
+
+status_t Gralloc3Mapper::lock(buffer_handle_t bufferHandle, uint64_t usage, const Rect& bounds,
+ int acquireFence, void** outData, int32_t* outBytesPerPixel,
+ int32_t* outBytesPerStride) const {
+ auto buffer = const_cast<native_handle_t*>(bufferHandle);
+
+ IMapper::Rect accessRegion = sGralloc3Rect(bounds);
+
+ // put acquireFence in a hidl_handle
+ hardware::hidl_handle acquireFenceHandle;
+ NATIVE_HANDLE_DECLARE_STORAGE(acquireFenceStorage, 1, 0);
+ if (acquireFence >= 0) {
+ auto h = native_handle_init(acquireFenceStorage, 1, 0);
+ h->data[0] = acquireFence;
+ acquireFenceHandle = h;
+ }
+
+ Error error;
+ auto ret = mMapper->lock(buffer, usage, accessRegion, acquireFenceHandle,
+ [&](const auto& tmpError, const auto& tmpData,
+ const auto& tmpBytesPerPixel, const auto& tmpBytesPerStride) {
+ error = tmpError;
+ if (error != Error::NONE) {
+ return;
+ }
+ *outData = tmpData;
+ if (outBytesPerPixel) {
+ *outBytesPerPixel = tmpBytesPerPixel;
+ }
+ if (outBytesPerStride) {
+ *outBytesPerStride = tmpBytesPerStride;
+ }
+ });
+
+ // we own acquireFence even on errors
+ if (acquireFence >= 0) {
+ close(acquireFence);
+ }
+
+ error = (ret.isOk()) ? error : kTransactionError;
+
+ ALOGW_IF(error != Error::NONE, "lock(%p, ...) failed: %d", bufferHandle, error);
+
+ return static_cast<status_t>(error);
+}
+
+status_t Gralloc3Mapper::lock(buffer_handle_t bufferHandle, uint64_t usage, const Rect& bounds,
+ int acquireFence, android_ycbcr* ycbcr) const {
+ auto buffer = const_cast<native_handle_t*>(bufferHandle);
+
+ IMapper::Rect accessRegion = sGralloc3Rect(bounds);
+
+ // put acquireFence in a hidl_handle
+ hardware::hidl_handle acquireFenceHandle;
+ NATIVE_HANDLE_DECLARE_STORAGE(acquireFenceStorage, 1, 0);
+ if (acquireFence >= 0) {
+ auto h = native_handle_init(acquireFenceStorage, 1, 0);
+ h->data[0] = acquireFence;
+ acquireFenceHandle = h;
+ }
+
+ YCbCrLayout layout;
+ Error error;
+ auto ret = mMapper->lockYCbCr(buffer, usage, accessRegion, acquireFenceHandle,
+ [&](const auto& tmpError, const auto& tmpLayout) {
+ error = tmpError;
+ if (error != Error::NONE) {
+ return;
+ }
+
+ layout = tmpLayout;
+ });
+
+ if (error == Error::NONE) {
+ ycbcr->y = layout.y;
+ ycbcr->cb = layout.cb;
+ ycbcr->cr = layout.cr;
+ ycbcr->ystride = static_cast<size_t>(layout.yStride);
+ ycbcr->cstride = static_cast<size_t>(layout.cStride);
+ ycbcr->chroma_step = static_cast<size_t>(layout.chromaStep);
+ }
+
+ // we own acquireFence even on errors
+ if (acquireFence >= 0) {
+ close(acquireFence);
+ }
+
+ return static_cast<status_t>((ret.isOk()) ? error : kTransactionError);
+}
+
+int Gralloc3Mapper::unlock(buffer_handle_t bufferHandle) const {
+ auto buffer = const_cast<native_handle_t*>(bufferHandle);
+
+ int releaseFence = -1;
+ Error error;
+ auto ret = mMapper->unlock(buffer, [&](const auto& tmpError, const auto& tmpReleaseFence) {
+ error = tmpError;
+ if (error != Error::NONE) {
+ return;
+ }
+
+ auto fenceHandle = tmpReleaseFence.getNativeHandle();
+ if (fenceHandle && fenceHandle->numFds == 1) {
+ int fd = dup(fenceHandle->data[0]);
+ if (fd >= 0) {
+ releaseFence = fd;
+ } else {
+ ALOGD("failed to dup unlock release fence");
+ sync_wait(fenceHandle->data[0], -1);
+ }
+ }
+ });
+
+ if (!ret.isOk()) {
+ error = kTransactionError;
+ }
+
+ if (error != Error::NONE) {
+ ALOGE("unlock(%p) failed with %d", buffer, error);
+ }
+
+ return releaseFence;
+}
+
+status_t Gralloc3Mapper::isSupported(uint32_t width, uint32_t height, android::PixelFormat format,
+ uint32_t layerCount, uint64_t usage,
+ bool* outSupported) const {
+ IMapper::BufferDescriptorInfo descriptorInfo;
+ sBufferDescriptorInfo(width, height, format, layerCount, usage, &descriptorInfo);
+
+ Error error;
+ auto ret = mMapper->isSupported(descriptorInfo,
+ [&](const auto& tmpError, const auto& tmpSupported) {
+ error = tmpError;
+ if (error != Error::NONE) {
+ return;
+ }
+ if (outSupported) {
+ *outSupported = tmpSupported;
+ }
+ });
+
+ if (!ret.isOk()) {
+ error = kTransactionError;
+ }
+
+ if (error != Error::NONE) {
+ ALOGE("isSupported(%u, %u, %d, %u, ...) failed with %d", width, height, format, layerCount,
+ error);
+ }
+
+ return static_cast<status_t>(error);
+}
+
+Gralloc3Allocator::Gralloc3Allocator(const Gralloc3Mapper& mapper) : mMapper(mapper) {
+ mAllocator = IAllocator::getService();
+ if (mAllocator == nullptr) {
+ ALOGW("allocator 3.x is not supported");
+ return;
+ }
+}
+
+bool Gralloc3Allocator::isLoaded() const {
+ return mAllocator != nullptr;
+}
+
+std::string Gralloc3Allocator::dumpDebugInfo() const {
+ std::string debugInfo;
+
+ mAllocator->dumpDebugInfo([&](const auto& tmpDebugInfo) { debugInfo = tmpDebugInfo.c_str(); });
+
+ return debugInfo;
+}
+
+status_t Gralloc3Allocator::allocate(uint32_t width, uint32_t height, android::PixelFormat format,
+ uint32_t layerCount, uint64_t usage, uint32_t bufferCount,
+ uint32_t* outStride, buffer_handle_t* outBufferHandles) const {
+ IMapper::BufferDescriptorInfo descriptorInfo;
+ sBufferDescriptorInfo(width, height, format, layerCount, usage, &descriptorInfo);
+
+ BufferDescriptor descriptor;
+ status_t error = mMapper.createDescriptor(static_cast<void*>(&descriptorInfo),
+ static_cast<void*>(&descriptor));
+ if (error != NO_ERROR) {
+ return error;
+ }
+
+ auto ret = mAllocator->allocate(descriptor, bufferCount,
+ [&](const auto& tmpError, const auto& tmpStride,
+ const auto& tmpBuffers) {
+ error = static_cast<status_t>(tmpError);
+ if (tmpError != Error::NONE) {
+ return;
+ }
+
+ // import buffers
+ for (uint32_t i = 0; i < bufferCount; i++) {
+ error = mMapper.importBuffer(tmpBuffers[i],
+ &outBufferHandles[i]);
+ if (error != NO_ERROR) {
+ for (uint32_t j = 0; j < i; j++) {
+ mMapper.freeBuffer(outBufferHandles[j]);
+ outBufferHandles[j] = nullptr;
+ }
+ return;
+ }
+ }
+ *outStride = tmpStride;
+ });
+
+ // make sure the kernel driver sees BC_FREE_BUFFER and closes the fds now
+ hardware::IPCThreadState::self()->flushCommands();
+
+ return (ret.isOk()) ? error : static_cast<status_t>(kTransactionError);
+}
+
+} // namespace android
diff --git a/libs/ui/GraphicBuffer.cpp b/libs/ui/GraphicBuffer.cpp
index f408fcb..e678c58 100644
--- a/libs/ui/GraphicBuffer.cpp
+++ b/libs/ui/GraphicBuffer.cpp
@@ -236,15 +236,15 @@
return NO_ERROR;
}
-status_t GraphicBuffer::lock(uint32_t inUsage, void** vaddr)
-{
+status_t GraphicBuffer::lock(uint32_t inUsage, void** vaddr, int32_t* outBytesPerPixel,
+ int32_t* outBytesPerStride) {
const Rect lockBounds(width, height);
- status_t res = lock(inUsage, lockBounds, vaddr);
+ status_t res = lock(inUsage, lockBounds, vaddr, outBytesPerPixel, outBytesPerStride);
return res;
}
-status_t GraphicBuffer::lock(uint32_t inUsage, const Rect& rect, void** vaddr)
-{
+status_t GraphicBuffer::lock(uint32_t inUsage, const Rect& rect, void** vaddr,
+ int32_t* outBytesPerPixel, int32_t* outBytesPerStride) {
if (rect.left < 0 || rect.right > width ||
rect.top < 0 || rect.bottom > height) {
ALOGE("locking pixels (%d,%d,%d,%d) outside of buffer (w=%d, h=%d)",
@@ -252,7 +252,10 @@
width, height);
return BAD_VALUE;
}
- status_t res = getBufferMapper().lock(handle, inUsage, rect, vaddr);
+
+ status_t res = getBufferMapper().lock(handle, inUsage, rect, vaddr, outBytesPerPixel,
+ outBytesPerStride);
+
return res;
}
@@ -306,8 +309,10 @@
width, height);
return BAD_VALUE;
}
- status_t res = getBufferMapper().lockAsync(handle, inProducerUsage,
- inConsumerUsage, rect, vaddr, fenceFd);
+
+ int32_t bytesPerPixel, bytesPerStride;
+ status_t res = getBufferMapper().lockAsync(handle, inProducerUsage, inConsumerUsage, rect,
+ vaddr, fenceFd, &bytesPerPixel, &bytesPerStride);
return res;
}
@@ -339,6 +344,13 @@
return res;
}
+status_t GraphicBuffer::isSupported(uint32_t inWidth, uint32_t inHeight, PixelFormat inFormat,
+ uint32_t inLayerCount, uint64_t inUsage,
+ bool* outSupported) const {
+ return mBufferMapper.isSupported(inWidth, inHeight, inFormat, inLayerCount, inUsage,
+ outSupported);
+}
+
size_t GraphicBuffer::getFlattenedSize() const {
return static_cast<size_t>(13 + (handle ? mTransportNumInts : 0)) * sizeof(int);
}
diff --git a/libs/ui/GraphicBufferAllocator.cpp b/libs/ui/GraphicBufferAllocator.cpp
index f56e6b9..5a67dc4 100644
--- a/libs/ui/GraphicBufferAllocator.cpp
+++ b/libs/ui/GraphicBufferAllocator.cpp
@@ -29,7 +29,9 @@
#include <utils/Singleton.h>
#include <utils/Trace.h>
+#include <ui/Gralloc.h>
#include <ui/Gralloc2.h>
+#include <ui/Gralloc3.h>
#include <ui/GraphicBufferMapper.h>
namespace android {
@@ -43,11 +45,17 @@
KeyedVector<buffer_handle_t,
GraphicBufferAllocator::alloc_rec_t> GraphicBufferAllocator::sAllocList;
-GraphicBufferAllocator::GraphicBufferAllocator()
- : mMapper(GraphicBufferMapper::getInstance()),
- mAllocator(std::make_unique<Gralloc2::Allocator>(
- mMapper.getGrallocMapper()))
-{
+GraphicBufferAllocator::GraphicBufferAllocator() : mMapper(GraphicBufferMapper::getInstance()) {
+ mAllocator = std::make_unique<const Gralloc3Allocator>(
+ reinterpret_cast<const Gralloc3Mapper&>(mMapper.getGrallocMapper()));
+ if (!mAllocator->isLoaded()) {
+ mAllocator = std::make_unique<const Gralloc2Allocator>(
+ reinterpret_cast<const Gralloc2Mapper&>(mMapper.getGrallocMapper()));
+ }
+
+ if (!mAllocator->isLoaded()) {
+ LOG_ALWAYS_FATAL("gralloc-allocator is missing");
+ }
}
GraphicBufferAllocator::~GraphicBufferAllocator() {}
@@ -104,15 +112,9 @@
// TODO(b/72323293, b/72703005): Remove these invalid bits from callers
usage &= ~static_cast<uint64_t>((1 << 10) | (1 << 13));
- Gralloc2::IMapper::BufferDescriptorInfo info = {};
- info.width = width;
- info.height = height;
- info.layerCount = layerCount;
- info.format = static_cast<Gralloc2::PixelFormat>(format);
- info.usage = usage;
-
- Gralloc2::Error error = mAllocator->allocate(info, stride, handle);
- if (error == Gralloc2::Error::NONE) {
+ status_t error =
+ mAllocator->allocate(width, height, format, layerCount, usage, 1, stride, handle);
+ if (error == NO_ERROR) {
Mutex::Autolock _l(sLock);
KeyedVector<buffer_handle_t, alloc_rec_t>& list(sAllocList);
uint32_t bpp = bytesPerPixel(format);
diff --git a/libs/ui/GraphicBufferMapper.cpp b/libs/ui/GraphicBufferMapper.cpp
index 2d8e582..06981c3 100644
--- a/libs/ui/GraphicBufferMapper.cpp
+++ b/libs/ui/GraphicBufferMapper.cpp
@@ -32,7 +32,9 @@
#include <utils/Log.h>
#include <utils/Trace.h>
+#include <ui/Gralloc.h>
#include <ui/Gralloc2.h>
+#include <ui/Gralloc3.h>
#include <ui/GraphicBuffer.h>
#include <system/graphics.h>
@@ -43,12 +45,19 @@
ANDROID_SINGLETON_STATIC_INSTANCE( GraphicBufferMapper )
void GraphicBufferMapper::preloadHal() {
- Gralloc2::Mapper::preload();
+ Gralloc2Mapper::preload();
+ Gralloc3Mapper::preload();
}
-GraphicBufferMapper::GraphicBufferMapper()
- : mMapper(std::make_unique<const Gralloc2::Mapper>())
-{
+GraphicBufferMapper::GraphicBufferMapper() {
+ mMapper = std::make_unique<const Gralloc3Mapper>();
+ if (!mMapper->isLoaded()) {
+ mMapper = std::make_unique<const Gralloc2Mapper>();
+ }
+
+ if (!mMapper->isLoaded()) {
+ LOG_ALWAYS_FATAL("gralloc-mapper is missing");
+ }
}
status_t GraphicBufferMapper::importBuffer(buffer_handle_t rawHandle,
@@ -59,22 +68,15 @@
ATRACE_CALL();
buffer_handle_t bufferHandle;
- Gralloc2::Error error = mMapper->importBuffer(
- hardware::hidl_handle(rawHandle), &bufferHandle);
- if (error != Gralloc2::Error::NONE) {
+ status_t error = mMapper->importBuffer(hardware::hidl_handle(rawHandle), &bufferHandle);
+ if (error != NO_ERROR) {
ALOGW("importBuffer(%p) failed: %d", rawHandle, error);
- return static_cast<status_t>(error);
+ return error;
}
- Gralloc2::IMapper::BufferDescriptorInfo info = {};
- info.width = width;
- info.height = height;
- info.layerCount = layerCount;
- info.format = static_cast<Gralloc2::PixelFormat>(format);
- info.usage = usage;
-
- error = mMapper->validateBufferSize(bufferHandle, info, stride);
- if (error != Gralloc2::Error::NONE) {
+ error = mMapper->validateBufferSize(bufferHandle, width, height, format, layerCount, usage,
+ stride);
+ if (error != NO_ERROR) {
ALOGE("validateBufferSize(%p) failed: %d", rawHandle, error);
freeBuffer(bufferHandle);
return static_cast<status_t>(error);
@@ -100,19 +102,10 @@
return NO_ERROR;
}
-static inline Gralloc2::IMapper::Rect asGralloc2Rect(const Rect& rect) {
- Gralloc2::IMapper::Rect outRect{};
- outRect.left = rect.left;
- outRect.top = rect.top;
- outRect.width = rect.width();
- outRect.height = rect.height();
- return outRect;
-}
-
-status_t GraphicBufferMapper::lock(buffer_handle_t handle, uint32_t usage,
- const Rect& bounds, void** vaddr)
-{
- return lockAsync(handle, usage, bounds, vaddr, -1);
+status_t GraphicBufferMapper::lock(buffer_handle_t handle, uint32_t usage, const Rect& bounds,
+ void** vaddr, int32_t* outBytesPerPixel,
+ int32_t* outBytesPerStride) {
+ return lockAsync(handle, usage, bounds, vaddr, -1, outBytesPerPixel, outBytesPerStride);
}
status_t GraphicBufferMapper::lockYCbCr(buffer_handle_t handle, uint32_t usage,
@@ -132,27 +125,23 @@
return error;
}
-status_t GraphicBufferMapper::lockAsync(buffer_handle_t handle,
- uint32_t usage, const Rect& bounds, void** vaddr, int fenceFd)
-{
- return lockAsync(handle, usage, usage, bounds, vaddr, fenceFd);
+status_t GraphicBufferMapper::lockAsync(buffer_handle_t handle, uint32_t usage, const Rect& bounds,
+ void** vaddr, int fenceFd, int32_t* outBytesPerPixel,
+ int32_t* outBytesPerStride) {
+ return lockAsync(handle, usage, usage, bounds, vaddr, fenceFd, outBytesPerPixel,
+ outBytesPerStride);
}
-status_t GraphicBufferMapper::lockAsync(buffer_handle_t handle,
- uint64_t producerUsage, uint64_t consumerUsage, const Rect& bounds,
- void** vaddr, int fenceFd)
-{
+status_t GraphicBufferMapper::lockAsync(buffer_handle_t handle, uint64_t producerUsage,
+ uint64_t consumerUsage, const Rect& bounds, void** vaddr,
+ int fenceFd, int32_t* outBytesPerPixel,
+ int32_t* outBytesPerStride) {
ATRACE_CALL();
const uint64_t usage = static_cast<uint64_t>(
android_convertGralloc1To0Usage(producerUsage, consumerUsage));
- Gralloc2::Error error = mMapper->lock(handle, usage,
- asGralloc2Rect(bounds), fenceFd, vaddr);
-
- ALOGW_IF(error != Gralloc2::Error::NONE, "lock(%p, ...) failed: %d",
- handle, error);
-
- return static_cast<status_t>(error);
+ return mMapper->lock(handle, usage, bounds, fenceFd, vaddr, outBytesPerPixel,
+ outBytesPerStride);
}
status_t GraphicBufferMapper::lockAsyncYCbCr(buffer_handle_t handle,
@@ -160,19 +149,7 @@
{
ATRACE_CALL();
- Gralloc2::YCbCrLayout layout;
- Gralloc2::Error error = mMapper->lock(handle, usage,
- asGralloc2Rect(bounds), fenceFd, &layout);
- if (error == Gralloc2::Error::NONE) {
- ycbcr->y = layout.y;
- ycbcr->cb = layout.cb;
- ycbcr->cr = layout.cr;
- ycbcr->ystride = static_cast<size_t>(layout.yStride);
- ycbcr->cstride = static_cast<size_t>(layout.cStride);
- ycbcr->chroma_step = static_cast<size_t>(layout.chromaStep);
- }
-
- return static_cast<status_t>(error);
+ return mMapper->lock(handle, usage, bounds, fenceFd, ycbcr);
}
status_t GraphicBufferMapper::unlockAsync(buffer_handle_t handle, int *fenceFd)
@@ -184,5 +161,10 @@
return NO_ERROR;
}
+status_t GraphicBufferMapper::isSupported(uint32_t width, uint32_t height,
+ android::PixelFormat format, uint32_t layerCount,
+ uint64_t usage, bool* outSupported) {
+ return mMapper->isSupported(width, height, format, layerCount, usage, outSupported);
+}
// ---------------------------------------------------------------------------
}; // namespace android
diff --git a/libs/ui/OWNERS b/libs/ui/OWNERS
new file mode 100644
index 0000000..97ead21
--- /dev/null
+++ b/libs/ui/OWNERS
@@ -0,0 +1,7 @@
+lpy@google.com
+marissaw@google.com
+mathias@google.com
+romainguy@google.com
+stoza@google.com
+jwcai@google.com
+tianyuj@google.com
diff --git a/cmds/dumpstate/binder/android/os/DumpstateOptions.aidl b/libs/ui/Size.cpp
similarity index 65%
copy from cmds/dumpstate/binder/android/os/DumpstateOptions.aidl
copy to libs/ui/Size.cpp
index c1a7f15..d2996d1 100644
--- a/cmds/dumpstate/binder/android/os/DumpstateOptions.aidl
+++ b/libs/ui/Size.cpp
@@ -1,11 +1,11 @@
-/**
- * Copyright (c) 2018, The Android Open Source Project
+/*
+ * 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
+ * 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,
@@ -14,10 +14,11 @@
* limitations under the License.
*/
-package android.os;
+#include <ui/Size.h>
-/**
- * Specifies arguments for IDumpstate.
- * {@hide}
- */
-parcelable DumpstateOptions cpp_header "android/os/DumpstateOptions.h";
+namespace android::ui {
+
+const Size Size::INVALID{-1, -1};
+const Size Size::EMPTY{0, 0};
+
+} // namespace android::ui
diff --git a/libs/ui/Transform.cpp b/libs/ui/Transform.cpp
index 25128ef..d13942d 100644
--- a/libs/ui/Transform.cpp
+++ b/libs/ui/Transform.cpp
@@ -16,6 +16,7 @@
#include <math.h>
+#include <android-base/stringprintf.h>
#include <cutils/compiler.h>
#include <ui/Region.h>
#include <ui/Transform.h>
@@ -380,44 +381,47 @@
return (getOrientation() & ROT_INVALID) ? false : true;
}
-void Transform::dump(const char* name) const
-{
- type(); // updates the type
+void Transform::dump(std::string& out, const char* name) const {
+ using android::base::StringAppendF;
- String8 flags, type;
- const mat33& m(mMatrix);
- uint32_t orient = mType >> 8;
+ type(); // Ensure the information in mType is up to date
- if (orient&ROT_INVALID) {
- flags.append("ROT_INVALID ");
+ const uint32_t type = mType;
+ const uint32_t orient = type >> 8;
+
+ StringAppendF(&out, "%s 0x%08x (", name, orient);
+
+ if (orient & ROT_INVALID) {
+ out.append("ROT_INVALID ");
} else {
- if (orient&ROT_90) {
- flags.append("ROT_90 ");
+ if (orient & ROT_90) {
+ out.append("ROT_90 ");
} else {
- flags.append("ROT_0 ");
+ out.append("ROT_0 ");
}
- if (orient&FLIP_V)
- flags.append("FLIP_V ");
- if (orient&FLIP_H)
- flags.append("FLIP_H ");
+ if (orient & FLIP_V) out.append("FLIP_V ");
+ if (orient & FLIP_H) out.append("FLIP_H ");
}
- if (!(mType&(SCALE|ROTATE|TRANSLATE)))
- type.append("IDENTITY ");
- if (mType&SCALE)
- type.append("SCALE ");
- if (mType&ROTATE)
- type.append("ROTATE ");
- if (mType&TRANSLATE)
- type.append("TRANSLATE ");
+ StringAppendF(&out, ") 0x%02x (", type);
- ALOGD("%s 0x%08x (%s, %s)", name, mType, flags.string(), type.string());
- ALOGD("%.4f %.4f %.4f", static_cast<double>(m[0][0]), static_cast<double>(m[1][0]),
- static_cast<double>(m[2][0]));
- ALOGD("%.4f %.4f %.4f", static_cast<double>(m[0][1]), static_cast<double>(m[1][1]),
- static_cast<double>(m[2][1]));
- ALOGD("%.4f %.4f %.4f", static_cast<double>(m[0][2]), static_cast<double>(m[1][2]),
- static_cast<double>(m[2][2]));
+ if (!(type & (SCALE | ROTATE | TRANSLATE))) out.append("IDENTITY ");
+ if (type & SCALE) out.append("SCALE ");
+ if (type & ROTATE) out.append("ROTATE ");
+ if (type & TRANSLATE) out.append("TRANSLATE ");
+
+ out.append(")\n");
+
+ for (size_t i = 0; i < 3; i++) {
+ StringAppendF(&out, " %.4f %.4f %.4f\n", static_cast<double>(mMatrix[0][i]),
+ static_cast<double>(mMatrix[1][i]), static_cast<double>(mMatrix[2][i]));
+ }
+}
+
+void Transform::dump(const char* name) const {
+ std::string out;
+ dump(out, name);
+ ALOGD("%s", out.c_str());
}
} // namespace ui
diff --git a/libs/ui/include/ui/BufferHubBuffer.h b/libs/ui/include/ui/BufferHubBuffer.h
index 90dd391..0b6d75a 100644
--- a/libs/ui/include/ui/BufferHubBuffer.h
+++ b/libs/ui/include/ui/BufferHubBuffer.h
@@ -17,78 +17,49 @@
#ifndef ANDROID_BUFFER_HUB_BUFFER_H_
#define ANDROID_BUFFER_HUB_BUFFER_H_
-// We would eliminate the clang warnings introduced by libdpx.
-// TODO(b/112338294): Remove those once BufferHub moved to use Binder
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wconversion"
-#pragma clang diagnostic ignored "-Wdouble-promotion"
-#pragma clang diagnostic ignored "-Wgnu-case-range"
-#pragma clang diagnostic ignored "-Wgnu-zero-variadic-macro-arguments"
-#pragma clang diagnostic ignored "-Winconsistent-missing-destructor-override"
-#pragma clang diagnostic ignored "-Wnested-anon-types"
-#pragma clang diagnostic ignored "-Wpacked"
-#pragma clang diagnostic ignored "-Wshadow"
-#pragma clang diagnostic ignored "-Wsign-conversion"
-#pragma clang diagnostic ignored "-Wswitch-enum"
-#pragma clang diagnostic ignored "-Wundefined-func-template"
-#pragma clang diagnostic ignored "-Wunused-template"
-#pragma clang diagnostic ignored "-Wweak-vtables"
-#include <pdx/client.h>
-#include <private/dvr/native_handle_wrapper.h>
-#pragma clang diagnostic pop
-
+#include <android/frameworks/bufferhub/1.0/IBufferClient.h>
#include <android/hardware_buffer.h>
+#include <cutils/native_handle.h>
#include <ui/BufferHubDefs.h>
+#include <ui/BufferHubEventFd.h>
#include <ui/BufferHubMetadata.h>
namespace android {
-class BufferHubClient : public pdx::Client {
-public:
- BufferHubClient();
- virtual ~BufferHubClient();
- explicit BufferHubClient(pdx::LocalChannelHandle mChannelHandle);
-
- bool IsValid() const;
- pdx::LocalChannelHandle TakeChannelHandle();
-
- using pdx::Client::Close;
- using pdx::Client::event_fd;
- using pdx::Client::GetChannel;
- using pdx::Client::InvokeRemoteMethod;
-};
-
class BufferHubBuffer {
public:
- // Allocates a standalone BufferHubBuffer not associated with any producer consumer set.
+ // Allocates a standalone BufferHubBuffer.
static std::unique_ptr<BufferHubBuffer> Create(uint32_t width, uint32_t height,
uint32_t layerCount, uint32_t format,
- uint64_t usage, size_t userMetadataSize) {
- return std::unique_ptr<BufferHubBuffer>(
- new BufferHubBuffer(width, height, layerCount, format, usage, userMetadataSize));
- }
+ uint64_t usage, size_t userMetadataSize);
- // Imports the given channel handle to a BufferHubBuffer, taking ownership.
- static std::unique_ptr<BufferHubBuffer> Import(pdx::LocalChannelHandle mChannelHandle) {
- return std::unique_ptr<BufferHubBuffer>(new BufferHubBuffer(std::move(mChannelHandle)));
- }
+ // Imports the given token to a BufferHubBuffer. Not taking ownership of the token. Caller
+ // should close and destroy the token after calling this function regardless of output.
+ // TODO(b/122543147): use a movable wrapper for token
+ static std::unique_ptr<BufferHubBuffer> Import(const native_handle_t* token);
BufferHubBuffer(const BufferHubBuffer&) = delete;
void operator=(const BufferHubBuffer&) = delete;
+ virtual ~BufferHubBuffer();
+
// Gets ID of the buffer client. All BufferHubBuffer clients derived from the same buffer in
- // bufferhubd share the same buffer id.
+ // BufferHub share the same buffer id.
int id() const { return mId; }
- // Returns the buffer description, which is guaranteed to be faithful values from bufferhubd.
+ // Returns the buffer description, which is guaranteed to be faithful values from BufferHub.
const AHardwareBuffer_Desc& desc() const { return mBufferDesc; }
- const native_handle_t* DuplicateHandle() { return mBufferHandle.DuplicateHandle(); }
+ // Duplicate the underlying Gralloc buffer handle. Caller is responsible to free the handle
+ // after use.
+ native_handle_t* DuplicateHandle() {
+ return native_handle_clone(mBufferHandle.getNativeHandle());
+ }
+
+ const BufferHubEventFd& eventFd() const { return mEventFd; }
// Returns the current value of MetadataHeader::buffer_state.
- uint32_t buffer_state() {
- return mMetadata.metadata_header()->buffer_state.load(std::memory_order_acquire);
- }
+ uint32_t buffer_state() const { return buffer_state_->load(std::memory_order_acquire); }
// A state mask which is unique to a buffer hub client among all its siblings sharing the same
// concrete graphic buffer.
@@ -96,12 +67,12 @@
size_t user_metadata_size() const { return mMetadata.user_metadata_size(); }
- // Returns true if the buffer holds an open PDX channels towards bufferhubd.
- bool IsConnected() const { return mClient.IsValid(); }
+ // Returns true if the BufferClient is still alive.
+ bool IsConnected() const { return mBufferClient->ping().isOk(); }
- // Returns true if the buffer holds an valid native buffer handle that's availble for the client
- // to read from and/or write into.
- bool IsValid() const { return mBufferHandle.IsValid(); }
+ // Returns true if the buffer is valid: non-null buffer handle, valid id, valid client bit mask,
+ // valid metadata and valid buffer client
+ bool IsValid() const;
// Gains the buffer for exclusive write permission. Read permission is implied once a buffer is
// gained.
@@ -124,33 +95,27 @@
// current cycle of the usage of the buffer.
int Release();
- // Returns the event mask for all the events that are pending on this buffer (see sys/poll.h for
- // all possible bits).
- pdx::Status<int> GetEventMask(int events) {
- if (auto* channel = mClient.GetChannel()) {
- return channel->GetEventMask(events);
- } else {
- return pdx::ErrorStatus(EINVAL);
- }
- }
+ // Returns whether the buffer is released by all active clients or not.
+ bool IsReleased() const;
- // Polls the fd for |timeoutMs| milliseconds (-1 for infinity).
- int Poll(int timeoutMs);
-
- // Creates a BufferHubBuffer client from an existing one. The new client will
- // share the same underlying gralloc buffer and ashmem region for metadata.
- pdx::Status<pdx::LocalChannelHandle> Duplicate();
+ // Creates a token that stands for this BufferHubBuffer client and could be used for Import to
+ // create another BufferHubBuffer. The new BufferHubBuffer will share the same underlying
+ // gralloc buffer and ashmem region for metadata. Note that the caller owns the token and
+ // should free it after use.
+ // Returns a valid token on success, nullptr on failure.
+ // TODO(b/122543147): use a movable wrapper for token
+ native_handle_t* Duplicate();
private:
BufferHubBuffer(uint32_t width, uint32_t height, uint32_t layerCount, uint32_t format,
uint64_t usage, size_t userMetadataSize);
- BufferHubBuffer(pdx::LocalChannelHandle mChannelHandle);
+ BufferHubBuffer(const native_handle_t* token);
- int ImportGraphicBuffer();
+ int initWithBufferTraits(const frameworks::bufferhub::V1_0::BufferTraits& bufferTraits);
// Global id for the buffer that is consistent across processes.
- int mId = -1;
+ int mId = 0;
// Client state mask of this BufferHubBuffer object. It is unique amoung all
// clients/users of the buffer.
@@ -159,8 +124,11 @@
// Stores ground truth of the buffer.
AHardwareBuffer_Desc mBufferDesc;
- // Wrapps the gralloc buffer handle of this buffer.
- dvr::NativeHandleWrapper<pdx::LocalHandle> mBufferHandle;
+ // Wraps the gralloc buffer handle of this buffer.
+ hardware::hidl_handle mBufferHandle;
+
+ // Event fd used for signalling buffer state changes. Shared by all clients of the same buffer.
+ BufferHubEventFd mEventFd;
// An ashmem-based metadata object. The same shared memory are mapped to the
// bufferhubd daemon and all buffer clients.
@@ -170,8 +138,8 @@
std::atomic<uint32_t>* fence_state_ = nullptr;
std::atomic<uint32_t>* active_clients_bit_mask_ = nullptr;
- // PDX backend.
- BufferHubClient mClient;
+ // HwBinder backend
+ sp<frameworks::bufferhub::V1_0::IBufferClient> mBufferClient;
};
} // namespace android
diff --git a/libs/ui/include/ui/BufferHubDefs.h b/libs/ui/include/ui/BufferHubDefs.h
index d259fef..ff970cb 100644
--- a/libs/ui/include/ui/BufferHubDefs.h
+++ b/libs/ui/include/ui/BufferHubDefs.h
@@ -106,11 +106,6 @@
return high_bits == 0U;
}
-// Returns true if all clients are in released state.
-static inline bool IsBufferReleased(uint32_t state) {
- return state == 0U;
-}
-
// Returns true if the input client is in released state.
static inline bool IsClientReleased(uint32_t state, uint32_t client_bit_mask) {
return (state & client_bit_mask) == 0U;
@@ -158,6 +153,30 @@
static_assert(sizeof(MetadataHeader) == 128, "Unexpected MetadataHeader size");
static constexpr size_t kMetadataHeaderSize = sizeof(MetadataHeader);
+/**
+ * android.frameworks.bufferhub@1.0::BufferTraits.bufferInfo is an opaque handle. See
+ * https://cs.corp.google.com/android/frameworks/hardware/interfaces/bufferhub/1.0/types.hal for
+ * more details about android.frameworks.bufferhub@1.0::BufferTraits.
+ *
+ * This definition could be changed, but implementation of BufferHubService::buildBufferInfo
+ * (frameworks/native/services/bufferhub), VtsHalBufferHubV1_0TargetTest
+ * (frameworks/hardware/interfaces/bufferhub) and BufferHubBuffer::readBufferTraits (libui) will
+ * also need to be updated.
+ *
+ * It's definition should follow the following format:
+ * {
+ * NumFds = 2,
+ * NumInts = 3,
+ * data[0] = Ashmem fd for BufferHubMetadata,
+ * data[1] = event fd,
+ * data[2] = buffer id,
+ * data[3] = client state bit mask,
+ * data[4] = user metadata size,
+ * }
+ */
+static constexpr int kBufferInfoNumFds = 2;
+static constexpr int kBufferInfoNumInts = 3;
+
} // namespace BufferHubDefs
} // namespace android
diff --git a/libs/ui/include/ui/BufferHubEventFd.h b/libs/ui/include/ui/BufferHubEventFd.h
index 0e856bd..8772304 100644
--- a/libs/ui/include/ui/BufferHubEventFd.h
+++ b/libs/ui/include/ui/BufferHubEventFd.h
@@ -30,6 +30,12 @@
BufferHubEventFd();
/**
+ * Constructs from a valid event fd. Caller is responsible for the validity of the fd. Takes
+ * ownership.
+ */
+ BufferHubEventFd(int fd);
+
+ /**
* Returns whether this BufferHubEventFd holds a valid event_fd.
*/
bool isValid() const { return get() >= 0; }
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplaySurface.cpp b/libs/ui/include/ui/ConfigStoreTypes.h
similarity index 62%
copy from services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplaySurface.cpp
copy to libs/ui/include/ui/ConfigStoreTypes.h
index e6ac6bf..37a2bd5 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplaySurface.cpp
+++ b/libs/ui/include/ui/ConfigStoreTypes.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018 The Android Open Source Project
+ * 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.
@@ -14,14 +14,16 @@
* limitations under the License.
*/
-#include "mock/DisplayHardware/MockDisplaySurface.h"
+#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 mock {
+namespace ui {
-// Explicit default instantiation is recommended.
-DisplaySurface::DisplaySurface() = default;
-DisplaySurface::~DisplaySurface() = default;
+using android::hardware::configstore::V1_2::DisplayPrimaries;
-} // namespace mock
-} // namespace android
+} // namespace ui
+} // namespace android
diff --git a/libs/ui/include/ui/Gralloc.h b/libs/ui/include/ui/Gralloc.h
new file mode 100644
index 0000000..6cc23f0
--- /dev/null
+++ b/libs/ui/include/ui/Gralloc.h
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_UI_GRALLOC_H
+#define ANDROID_UI_GRALLOC_H
+
+#include <string>
+
+#include <hidl/HidlSupport.h>
+#include <ui/PixelFormat.h>
+#include <ui/Rect.h>
+#include <utils/StrongPointer.h>
+
+namespace android {
+
+// A wrapper to IMapper
+class GrallocMapper {
+public:
+ virtual ~GrallocMapper();
+
+ virtual bool isLoaded() const = 0;
+
+ virtual status_t createDescriptor(void* bufferDescriptorInfo,
+ void* outBufferDescriptor) const = 0;
+
+ // Import a buffer that is from another HAL, another process, or is
+ // cloned.
+ //
+ // The returned handle must be freed with freeBuffer.
+ virtual status_t importBuffer(const hardware::hidl_handle& rawHandle,
+ buffer_handle_t* outBufferHandle) const = 0;
+
+ virtual void freeBuffer(buffer_handle_t bufferHandle) const = 0;
+
+ virtual status_t validateBufferSize(buffer_handle_t bufferHandle, uint32_t width,
+ uint32_t height, android::PixelFormat format,
+ uint32_t layerCount, uint64_t usage,
+ uint32_t stride) const = 0;
+
+ virtual void getTransportSize(buffer_handle_t bufferHandle, uint32_t* outNumFds,
+ uint32_t* outNumInts) const = 0;
+
+ // The ownership of acquireFence is always transferred to the callee, even
+ // on errors.
+ virtual status_t lock(buffer_handle_t bufferHandle, uint64_t usage, const Rect& bounds,
+ int acquireFence, void** outData, int32_t* outBytesPerPixel,
+ int32_t* outBytesPerStride) const = 0;
+
+ // The ownership of acquireFence is always transferred to the callee, even
+ // on errors.
+ virtual status_t lock(buffer_handle_t bufferHandle, uint64_t usage, const Rect& bounds,
+ int acquireFence, android_ycbcr* ycbcr) const = 0;
+
+ // unlock returns a fence sync object (or -1) and the fence sync object is
+ // owned by the caller
+ virtual int unlock(buffer_handle_t bufferHandle) const = 0;
+
+ // isSupported queries whether or not a buffer with the given width, height,
+ // format, layer count, and usage can be allocated on the device. If
+ // *outSupported is set to true, a buffer with the given specifications may be successfully
+ // allocated if resources are available. If false, a buffer with the given specifications will
+ // never successfully allocate on this device. Note that this function is not guaranteed to be
+ // supported on all devices, in which case a status_t of INVALID_OPERATION will be returned.
+ virtual status_t isSupported(uint32_t width, uint32_t height, android::PixelFormat format,
+ uint32_t layerCount, uint64_t usage, bool* outSupported) const = 0;
+};
+
+// A wrapper to IAllocator
+class GrallocAllocator {
+public:
+ virtual ~GrallocAllocator();
+
+ virtual bool isLoaded() const = 0;
+
+ virtual std::string dumpDebugInfo() const = 0;
+
+ /*
+ * The returned buffers are already imported and must not be imported
+ * again. outBufferHandles must point to a space that can contain at
+ * least "bufferCount" buffer_handle_t.
+ */
+ virtual status_t allocate(uint32_t width, uint32_t height, PixelFormat format,
+ uint32_t layerCount, uint64_t usage, uint32_t bufferCount,
+ uint32_t* outStride, buffer_handle_t* outBufferHandles) const = 0;
+};
+
+} // namespace android
+
+#endif // ANDROID_UI_GRALLOC_H
diff --git a/libs/ui/include/ui/Gralloc2.h b/libs/ui/include/ui/Gralloc2.h
index 5a8dbda..948f597 100644
--- a/libs/ui/include/ui/Gralloc2.h
+++ b/libs/ui/include/ui/Gralloc2.h
@@ -23,119 +23,75 @@
#include <android/hardware/graphics/common/1.1/types.h>
#include <android/hardware/graphics/mapper/2.0/IMapper.h>
#include <android/hardware/graphics/mapper/2.1/IMapper.h>
+#include <ui/Gralloc.h>
+#include <ui/PixelFormat.h>
+#include <ui/Rect.h>
#include <utils/StrongPointer.h>
namespace android {
-namespace Gralloc2 {
-
-using hardware::graphics::allocator::V2_0::IAllocator;
-using hardware::graphics::common::V1_1::BufferUsage;
-using hardware::graphics::common::V1_1::PixelFormat;
-using hardware::graphics::mapper::V2_1::IMapper;
-using hardware::graphics::mapper::V2_0::BufferDescriptor;
-using hardware::graphics::mapper::V2_0::Error;
-using hardware::graphics::mapper::V2_0::YCbCrLayout;
-
-// A wrapper to IMapper
-class Mapper {
+class Gralloc2Mapper : public GrallocMapper {
public:
static void preload();
- Mapper();
+ Gralloc2Mapper();
- Error createDescriptor(
- const IMapper::BufferDescriptorInfo& descriptorInfo,
- BufferDescriptor* outDescriptor) const;
+ bool isLoaded() const override;
- // Import a buffer that is from another HAL, another process, or is
- // cloned.
- //
- // The returned handle must be freed with freeBuffer.
- Error importBuffer(const hardware::hidl_handle& rawHandle,
- buffer_handle_t* outBufferHandle) const;
+ status_t createDescriptor(void* bufferDescriptorInfo, void* outBufferDescriptor) const override;
- void freeBuffer(buffer_handle_t bufferHandle) const;
+ status_t importBuffer(const hardware::hidl_handle& rawHandle,
+ buffer_handle_t* outBufferHandle) const override;
- Error validateBufferSize(buffer_handle_t bufferHandle,
- const IMapper::BufferDescriptorInfo& descriptorInfo,
- uint32_t stride) const;
+ void freeBuffer(buffer_handle_t bufferHandle) const override;
- void getTransportSize(buffer_handle_t bufferHandle,
- uint32_t* outNumFds, uint32_t* outNumInts) const;
+ status_t validateBufferSize(buffer_handle_t bufferHandle, uint32_t width, uint32_t height,
+ android::PixelFormat format, uint32_t layerCount, uint64_t usage,
+ uint32_t stride) const override;
- // The ownership of acquireFence is always transferred to the callee, even
- // on errors.
- Error lock(buffer_handle_t bufferHandle, uint64_t usage,
- const IMapper::Rect& accessRegion,
- int acquireFence, void** outData) const;
+ void getTransportSize(buffer_handle_t bufferHandle, uint32_t* outNumFds,
+ uint32_t* outNumInts) const override;
- // The ownership of acquireFence is always transferred to the callee, even
- // on errors.
- Error lock(buffer_handle_t bufferHandle, uint64_t usage,
- const IMapper::Rect& accessRegion,
- int acquireFence, YCbCrLayout* outLayout) const;
+ status_t lock(buffer_handle_t bufferHandle, uint64_t usage, const Rect& bounds,
+ int acquireFence, void** outData, int32_t* outBytesPerPixel,
+ int32_t* outBytesPerStride) const override;
- // unlock returns a fence sync object (or -1) and the fence sync object is
- // owned by the caller
- int unlock(buffer_handle_t bufferHandle) const;
+ status_t lock(buffer_handle_t bufferHandle, uint64_t usage, const Rect& bounds,
+ int acquireFence, android_ycbcr* ycbcr) const override;
+
+ int unlock(buffer_handle_t bufferHandle) const override;
+
+ status_t isSupported(uint32_t width, uint32_t height, android::PixelFormat format,
+ uint32_t layerCount, uint64_t usage, bool* outSupported) const override;
private:
// Determines whether the passed info is compatible with the mapper.
- Error validateBufferDescriptorInfo(
- const IMapper::BufferDescriptorInfo& descriptorInfo) const;
+ status_t validateBufferDescriptorInfo(
+ hardware::graphics::mapper::V2_1::IMapper::BufferDescriptorInfo* descriptorInfo) const;
sp<hardware::graphics::mapper::V2_0::IMapper> mMapper;
- sp<IMapper> mMapperV2_1;
+ sp<hardware::graphics::mapper::V2_1::IMapper> mMapperV2_1;
};
-// A wrapper to IAllocator
-class Allocator {
+class Gralloc2Allocator : public GrallocAllocator {
public:
// An allocator relies on a mapper, and that mapper must be alive at all
// time.
- Allocator(const Mapper& mapper);
+ Gralloc2Allocator(const Gralloc2Mapper& mapper);
- std::string dumpDebugInfo() const;
+ bool isLoaded() const override;
- /*
- * The returned buffers are already imported and must not be imported
- * again. outBufferHandles must point to a space that can contain at
- * least "count" buffer_handle_t.
- */
- Error allocate(BufferDescriptor descriptor, uint32_t count,
- uint32_t* outStride, buffer_handle_t* outBufferHandles) const;
+ std::string dumpDebugInfo() const override;
- Error allocate(BufferDescriptor descriptor,
- uint32_t* outStride, buffer_handle_t* outBufferHandle) const
- {
- return allocate(descriptor, 1, outStride, outBufferHandle);
- }
-
- Error allocate(const IMapper::BufferDescriptorInfo& descriptorInfo, uint32_t count,
- uint32_t* outStride, buffer_handle_t* outBufferHandles) const
- {
- BufferDescriptor descriptor;
- Error error = mMapper.createDescriptor(descriptorInfo, &descriptor);
- if (error == Error::NONE) {
- error = allocate(descriptor, count, outStride, outBufferHandles);
- }
- return error;
- }
-
- Error allocate(const IMapper::BufferDescriptorInfo& descriptorInfo,
- uint32_t* outStride, buffer_handle_t* outBufferHandle) const
- {
- return allocate(descriptorInfo, 1, outStride, outBufferHandle);
- }
+ status_t allocate(uint32_t width, uint32_t height, PixelFormat format, uint32_t layerCount,
+ uint64_t usage, uint32_t bufferCount, uint32_t* outStride,
+ buffer_handle_t* outBufferHandles) const override;
private:
- const Mapper& mMapper;
- sp<IAllocator> mAllocator;
+ const Gralloc2Mapper& mMapper;
+ sp<hardware::graphics::allocator::V2_0::IAllocator> mAllocator;
};
-} // namespace Gralloc2
-
} // namespace android
#endif // ANDROID_UI_GRALLOC2_H
diff --git a/libs/ui/include/ui/Gralloc3.h b/libs/ui/include/ui/Gralloc3.h
new file mode 100644
index 0000000..0965f52
--- /dev/null
+++ b/libs/ui/include/ui/Gralloc3.h
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_UI_GRALLOC3_H
+#define ANDROID_UI_GRALLOC3_H
+
+#include <string>
+
+#include <android/hardware/graphics/allocator/3.0/IAllocator.h>
+#include <android/hardware/graphics/common/1.1/types.h>
+#include <android/hardware/graphics/mapper/3.0/IMapper.h>
+#include <ui/Gralloc.h>
+#include <ui/PixelFormat.h>
+#include <ui/Rect.h>
+#include <utils/StrongPointer.h>
+
+namespace android {
+
+class Gralloc3Mapper : public GrallocMapper {
+public:
+ static void preload();
+
+ Gralloc3Mapper();
+
+ bool isLoaded() const override;
+
+ status_t createDescriptor(void* bufferDescriptorInfo, void* outBufferDescriptor) const override;
+
+ status_t importBuffer(const hardware::hidl_handle& rawHandle,
+ buffer_handle_t* outBufferHandle) const override;
+
+ void freeBuffer(buffer_handle_t bufferHandle) const override;
+
+ status_t validateBufferSize(buffer_handle_t bufferHandle, uint32_t width, uint32_t height,
+ android::PixelFormat format, uint32_t layerCount, uint64_t usage,
+ uint32_t stride) const override;
+
+ void getTransportSize(buffer_handle_t bufferHandle, uint32_t* outNumFds,
+ uint32_t* outNumInts) const override;
+
+ status_t lock(buffer_handle_t bufferHandle, uint64_t usage, const Rect& bounds,
+ int acquireFence, void** outData, int32_t* outBytesPerPixel,
+ int32_t* outBytesPerStride) const override;
+
+ status_t lock(buffer_handle_t bufferHandle, uint64_t usage, const Rect& bounds,
+ int acquireFence, android_ycbcr* ycbcr) const override;
+
+ int unlock(buffer_handle_t bufferHandle) const override;
+
+ status_t isSupported(uint32_t width, uint32_t height, android::PixelFormat format,
+ uint32_t layerCount, uint64_t usage, bool* outSupported) const override;
+
+private:
+ // Determines whether the passed info is compatible with the mapper.
+ status_t validateBufferDescriptorInfo(
+ hardware::graphics::mapper::V3_0::IMapper::BufferDescriptorInfo* descriptorInfo) const;
+
+ sp<hardware::graphics::mapper::V3_0::IMapper> mMapper;
+};
+
+class Gralloc3Allocator : public GrallocAllocator {
+public:
+ // An allocator relies on a mapper, and that mapper must be alive at all
+ // time.
+ Gralloc3Allocator(const Gralloc3Mapper& mapper);
+
+ bool isLoaded() const override;
+
+ std::string dumpDebugInfo() const override;
+
+ status_t allocate(uint32_t width, uint32_t height, PixelFormat format, uint32_t layerCount,
+ uint64_t usage, uint32_t bufferCount, uint32_t* outStride,
+ buffer_handle_t* outBufferHandles) const override;
+
+private:
+ const Gralloc3Mapper& mMapper;
+ sp<hardware::graphics::allocator::V3_0::IAllocator> mAllocator;
+};
+
+} // namespace android
+
+#endif // ANDROID_UI_GRALLOC3_H
diff --git a/libs/ui/include/ui/GraphicBuffer.h b/libs/ui/include/ui/GraphicBuffer.h
index b73ca2b..7d88c58 100644
--- a/libs/ui/include/ui/GraphicBuffer.h
+++ b/libs/ui/include/ui/GraphicBuffer.h
@@ -169,8 +169,12 @@
bool needsReallocation(uint32_t inWidth, uint32_t inHeight,
PixelFormat inFormat, uint32_t inLayerCount, uint64_t inUsage);
- status_t lock(uint32_t inUsage, void** vaddr);
- status_t lock(uint32_t inUsage, const Rect& rect, void** vaddr);
+ // For the following two lock functions, if bytesPerStride or bytesPerPixel
+ // are unknown or variable, -1 will be returned
+ status_t lock(uint32_t inUsage, void** vaddr, int32_t* outBytesPerPixel = nullptr,
+ int32_t* outBytesPerStride = nullptr);
+ status_t lock(uint32_t inUsage, const Rect& rect, void** vaddr,
+ int32_t* outBytesPerPixel = nullptr, int32_t* outBytesPerStride = nullptr);
// For HAL_PIXEL_FORMAT_YCbCr_420_888
status_t lockYCbCr(uint32_t inUsage, android_ycbcr *ycbcr);
status_t lockYCbCr(uint32_t inUsage, const Rect& rect,
@@ -187,6 +191,9 @@
android_ycbcr *ycbcr, int fenceFd);
status_t unlockAsync(int *fenceFd);
+ status_t isSupported(uint32_t inWidth, uint32_t inHeight, PixelFormat inFormat,
+ uint32_t inLayerCount, uint64_t inUsage, bool* outSupported) const;
+
ANativeWindowBuffer* getNativeBuffer() const;
// for debugging
diff --git a/libs/ui/include/ui/GraphicBufferAllocator.h b/libs/ui/include/ui/GraphicBufferAllocator.h
index 7e2b230..3a547b6 100644
--- a/libs/ui/include/ui/GraphicBufferAllocator.h
+++ b/libs/ui/include/ui/GraphicBufferAllocator.h
@@ -34,10 +34,7 @@
namespace android {
-namespace Gralloc2 {
-class Allocator;
-}
-
+class GrallocAllocator;
class GraphicBufferMapper;
class GraphicBufferAllocator : public Singleton<GraphicBufferAllocator>
@@ -75,7 +72,7 @@
~GraphicBufferAllocator();
GraphicBufferMapper& mMapper;
- const std::unique_ptr<const Gralloc2::Allocator> mAllocator;
+ std::unique_ptr<const GrallocAllocator> mAllocator;
};
// ---------------------------------------------------------------------------
diff --git a/libs/ui/include/ui/GraphicBufferMapper.h b/libs/ui/include/ui/GraphicBufferMapper.h
index 7cf003d..77c99cc 100644
--- a/libs/ui/include/ui/GraphicBufferMapper.h
+++ b/libs/ui/include/ui/GraphicBufferMapper.h
@@ -35,10 +35,7 @@
// ---------------------------------------------------------------------------
-namespace Gralloc2 {
-class Mapper;
-}
-
+class GrallocMapper;
class Rect;
class GraphicBufferMapper : public Singleton<GraphicBufferMapper>
@@ -59,20 +56,21 @@
void getTransportSize(buffer_handle_t handle,
uint32_t* outTransportNumFds, uint32_t* outTransportNumInts);
- status_t lock(buffer_handle_t handle,
- uint32_t usage, const Rect& bounds, void** vaddr);
+ status_t lock(buffer_handle_t handle, uint32_t usage, const Rect& bounds, void** vaddr,
+ int32_t* outBytesPerPixel = nullptr, int32_t* outBytesPerStride = nullptr);
status_t lockYCbCr(buffer_handle_t handle,
uint32_t usage, const Rect& bounds, android_ycbcr *ycbcr);
status_t unlock(buffer_handle_t handle);
- status_t lockAsync(buffer_handle_t handle,
- uint32_t usage, const Rect& bounds, void** vaddr, int fenceFd);
+ status_t lockAsync(buffer_handle_t handle, uint32_t usage, const Rect& bounds, void** vaddr,
+ int fenceFd, int32_t* outBytesPerPixel = nullptr,
+ int32_t* outBytesPerStride = nullptr);
- status_t lockAsync(buffer_handle_t handle,
- uint64_t producerUsage, uint64_t consumerUsage, const Rect& bounds,
- void** vaddr, int fenceFd);
+ status_t lockAsync(buffer_handle_t handle, uint64_t producerUsage, uint64_t consumerUsage,
+ const Rect& bounds, void** vaddr, int fenceFd,
+ int32_t* outBytesPerPixel = nullptr, int32_t* outBytesPerStride = nullptr);
status_t lockAsyncYCbCr(buffer_handle_t handle,
uint32_t usage, const Rect& bounds, android_ycbcr *ycbcr,
@@ -80,9 +78,11 @@
status_t unlockAsync(buffer_handle_t handle, int *fenceFd);
- const Gralloc2::Mapper& getGrallocMapper() const
- {
- return *mMapper;
+ status_t isSupported(uint32_t width, uint32_t height, android::PixelFormat format,
+ uint32_t layerCount, uint64_t usage, bool* outSupported);
+
+ const GrallocMapper& getGrallocMapper() const {
+ return reinterpret_cast<const GrallocMapper&>(*mMapper);
}
private:
@@ -90,7 +90,7 @@
GraphicBufferMapper();
- const std::unique_ptr<const Gralloc2::Mapper> mMapper;
+ std::unique_ptr<const GrallocMapper> mMapper;
};
// ---------------------------------------------------------------------------
diff --git a/libs/ui/include/ui/GraphicTypes.h b/libs/ui/include/ui/GraphicTypes.h
index fb3c5f8..4b03e44 100644
--- a/libs/ui/include/ui/GraphicTypes.h
+++ b/libs/ui/include/ui/GraphicTypes.h
@@ -25,11 +25,11 @@
namespace android {
namespace ui {
-using android::hardware::graphics::common::V1_1::PixelFormat;
using android::hardware::graphics::common::V1_1::RenderIntent;
using android::hardware::graphics::common::V1_2::ColorMode;
using android::hardware::graphics::common::V1_2::Dataspace;
using android::hardware::graphics::common::V1_2::Hdr;
+using android::hardware::graphics::common::V1_2::PixelFormat;
} // namespace ui
} // namespace android
diff --git a/libs/ui/include/ui/Rect.h b/libs/ui/include/ui/Rect.h
index e9da087..1768805 100644
--- a/libs/ui/include/ui/Rect.h
+++ b/libs/ui/include/ui/Rect.h
@@ -24,6 +24,7 @@
#include <ui/FloatRect.h>
#include <ui/Point.h>
+#include <ui/Size.h>
#include <android/rect.h>
@@ -78,6 +79,13 @@
bottom = static_cast<int32_t>(floatRect.bottom + 0.5f);
}
+ inline explicit Rect(const ui::Size& size) {
+ left = 0;
+ top = 0;
+ right = size.width;
+ bottom = size.height;
+ }
+
void makeInvalid();
inline void clear() {
@@ -106,6 +114,8 @@
return bottom - top;
}
+ ui::Size getSize() const { return ui::Size(getWidth(), getHeight()); }
+
__attribute__((no_sanitize("signed-integer-overflow")))
inline Rect getBounds() const {
return Rect(right - left, bottom - top);
diff --git a/libs/ui/include/ui/Size.h b/libs/ui/include/ui/Size.h
new file mode 100644
index 0000000..c39d8af
--- /dev/null
+++ b/libs/ui/include/ui/Size.h
@@ -0,0 +1,158 @@
+/*
+ * 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 <algorithm>
+#include <cstdint>
+#include <limits>
+#include <type_traits>
+#include <utility>
+
+namespace android {
+namespace ui {
+
+// Forward declare a few things.
+struct Size;
+bool operator==(const Size& lhs, const Size& rhs);
+
+/**
+ * A simple value type representing a two-dimensional size
+ */
+struct Size {
+ int32_t width;
+ int32_t height;
+
+ // Special values
+ static const Size INVALID;
+ static const Size EMPTY;
+
+ // ------------------------------------------------------------------------
+ // Construction
+ // ------------------------------------------------------------------------
+
+ Size() : Size(INVALID) {}
+ template <typename T>
+ Size(T&& w, T&& h)
+ : width(Size::clamp<int32_t, T>(std::forward<T>(w))),
+ height(Size::clamp<int32_t, T>(std::forward<T>(h))) {}
+
+ // ------------------------------------------------------------------------
+ // Accessors
+ // ------------------------------------------------------------------------
+
+ int32_t getWidth() const { return width; }
+ int32_t getHeight() const { return height; }
+
+ template <typename T>
+ void setWidth(T&& v) {
+ width = Size::clamp<int32_t, T>(std::forward<T>(v));
+ }
+ template <typename T>
+ void setHeight(T&& v) {
+ height = Size::clamp<int32_t, T>(std::forward<T>(v));
+ }
+
+ // ------------------------------------------------------------------------
+ // Assignment
+ // ------------------------------------------------------------------------
+
+ void set(const Size& size) { *this = size; }
+ template <typename T>
+ void set(T&& w, T&& h) {
+ set(Size(std::forward<T>(w), std::forward<T>(h)));
+ }
+
+ // Sets the value to INVALID
+ void makeInvalid() { set(INVALID); }
+
+ // Sets the value to EMPTY
+ void clear() { set(EMPTY); }
+
+ // ------------------------------------------------------------------------
+ // Semantic checks
+ // ------------------------------------------------------------------------
+
+ // Valid means non-negative width and height
+ bool isValid() const { return width >= 0 && height >= 0; }
+
+ // Empty means zero width and height
+ bool isEmpty() const { return *this == EMPTY; }
+
+ // ------------------------------------------------------------------------
+ // Clamp Helpers
+ // ------------------------------------------------------------------------
+
+ // Note: We use only features available in C++11 here for compatibility with
+ // external targets which include this file directly or indirectly and which
+ // themselves use C++11.
+
+ // C++11 compatible replacement for std::remove_cv_reference_t [C++20]
+ template <typename T>
+ using remove_cv_reference_t =
+ typename std::remove_cv<typename std::remove_reference<T>::type>::type;
+
+ // Takes a value of type FromType, and ensures it can be represented as a value of type ToType,
+ // clamping the input value to the output range if necessary.
+ template <typename ToType, typename FromType>
+ static Size::remove_cv_reference_t<ToType> clamp(
+ typename std::enable_if<
+ std::numeric_limits<Size::remove_cv_reference_t<ToType>>::is_bounded &&
+ std::numeric_limits<Size::remove_cv_reference_t<FromType>>::is_bounded,
+ FromType&&>::type v) {
+ static constexpr auto toHighest = std::numeric_limits<remove_cv_reference_t<ToType>>::max();
+ static constexpr auto toLowest =
+ std::numeric_limits<remove_cv_reference_t<ToType>>::lowest();
+ static constexpr auto fromHighest =
+ std::numeric_limits<remove_cv_reference_t<FromType>>::max();
+ static constexpr auto fromLowest =
+ std::numeric_limits<remove_cv_reference_t<FromType>>::lowest();
+
+ // A clamp is needed if the range of FromType is not a subset of the range of ToType
+ static constexpr bool isClampNeeded = (toLowest > fromLowest) || (toHighest < fromHighest);
+
+ // If a clamp is not needed, the conversion is just a trivial cast.
+ if (!isClampNeeded) {
+ return static_cast<ToType>(v);
+ }
+
+ // Otherwise we leverage implicit conversion to safely compare values of
+ // different types, to ensure we return a value clamped to the range of
+ // ToType.
+ return v < toLowest ? toLowest : (v > toHighest ? toHighest : static_cast<ToType>(v));
+ }
+};
+
+// ------------------------------------------------------------------------
+// Comparisons
+// ------------------------------------------------------------------------
+
+inline bool operator==(const Size& lhs, const Size& rhs) {
+ return lhs.width == rhs.width && lhs.height == rhs.height;
+}
+
+inline bool operator!=(const Size& lhs, const Size& rhs) {
+ return !operator==(lhs, rhs);
+}
+
+inline bool operator<(const Size& lhs, const Size& rhs) {
+ // Orders by increasing width, then height.
+ if (lhs.width != rhs.width) return lhs.width < rhs.width;
+ return lhs.height < rhs.height;
+}
+
+} // namespace ui
+} // namespace android
diff --git a/libs/ui/include/ui/Transform.h b/libs/ui/include/ui/Transform.h
index 900a5c4..dcb26cf 100644
--- a/libs/ui/include/ui/Transform.h
+++ b/libs/ui/include/ui/Transform.h
@@ -19,6 +19,7 @@
#include <stdint.h>
#include <sys/types.h>
+#include <string>
#include <hardware/hardware.h>
#include <math/vec2.h>
@@ -90,6 +91,7 @@
Transform inverse() const;
// for debugging
+ void dump(std::string& result, const char* name) const;
void dump(const char* name) const;
private:
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplaySurface.cpp b/libs/ui/include_vndk/ui/ConfigStoreTypes.h
similarity index 62%
copy from services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplaySurface.cpp
copy to libs/ui/include_vndk/ui/ConfigStoreTypes.h
index e6ac6bf..37a2bd5 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplaySurface.cpp
+++ b/libs/ui/include_vndk/ui/ConfigStoreTypes.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018 The Android Open Source Project
+ * 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.
@@ -14,14 +14,16 @@
* limitations under the License.
*/
-#include "mock/DisplayHardware/MockDisplaySurface.h"
+#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 mock {
+namespace ui {
-// Explicit default instantiation is recommended.
-DisplaySurface::DisplaySurface() = default;
-DisplaySurface::~DisplaySurface() = default;
+using android::hardware::configstore::V1_2::DisplayPrimaries;
-} // namespace mock
-} // namespace android
+} // namespace ui
+} // namespace android
diff --git a/libs/ui/include_vndk/ui/Size.h b/libs/ui/include_vndk/ui/Size.h
new file mode 120000
index 0000000..fd2b21b
--- /dev/null
+++ b/libs/ui/include_vndk/ui/Size.h
@@ -0,0 +1 @@
+../../include/ui/Size.h
\ No newline at end of file
diff --git a/libs/ui/tests/Android.bp b/libs/ui/tests/Android.bp
index a670b3c..373fa4f 100644
--- a/libs/ui/tests/Android.bp
+++ b/libs/ui/tests/Android.bp
@@ -31,12 +31,14 @@
cc_test {
name: "GraphicBuffer_test",
header_libs: [
- "libbufferhub_headers",
"libdvr_headers",
"libnativewindow_headers",
],
shared_libs: [
- "libpdx_default_transport",
+ "android.frameworks.bufferhub@1.0",
+ "libcutils",
+ "libhidlbase",
+ "libhwbinder",
"libui",
"libutils",
],
@@ -47,7 +49,6 @@
cc_test {
name: "BufferHub_test",
header_libs: [
- "libbufferhub_headers",
"libdvr_headers",
"libnativewindow_headers",
],
@@ -60,7 +61,6 @@
"libhidlbase",
"libhwbinder",
"liblog",
- "libpdx_default_transport",
"libui",
"libutils"
],
@@ -71,3 +71,10 @@
],
cflags: ["-Wall", "-Werror"],
}
+
+cc_test {
+ name: "Size_test",
+ shared_libs: ["libui"],
+ srcs: ["Size_test.cpp"],
+ cflags: ["-Wall", "-Werror"],
+}
diff --git a/libs/ui/tests/BufferHubBuffer_test.cpp b/libs/ui/tests/BufferHubBuffer_test.cpp
index 1b339a0..3bcd935 100644
--- a/libs/ui/tests/BufferHubBuffer_test.cpp
+++ b/libs/ui/tests/BufferHubBuffer_test.cpp
@@ -16,49 +16,53 @@
#define LOG_TAG "BufferHubBufferTest"
-#include <android/frameworks/bufferhub/1.0/IBufferClient.h>
-#include <android/frameworks/bufferhub/1.0/IBufferHub.h>
+#include <errno.h>
+#include <sys/epoll.h>
+
#include <android/hardware_buffer.h>
#include <cutils/native_handle.h>
+#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <hidl/ServiceManagement.h>
#include <hwbinder/IPCThreadState.h>
#include <ui/BufferHubBuffer.h>
+#include <ui/BufferHubEventFd.h>
namespace android {
namespace {
+using ::android::BufferHubDefs::AnyClientAcquired;
+using ::android::BufferHubDefs::AnyClientGained;
+using ::android::BufferHubDefs::AnyClientPosted;
+using ::android::BufferHubDefs::IsClientAcquired;
+using ::android::BufferHubDefs::IsClientGained;
+using ::android::BufferHubDefs::IsClientPosted;
+using ::android::BufferHubDefs::IsClientReleased;
+using ::android::BufferHubDefs::kMetadataHeaderSize;
+using ::testing::IsNull;
+using ::testing::NotNull;
+
const int kWidth = 640;
const int kHeight = 480;
const int kLayerCount = 1;
const int kFormat = HAL_PIXEL_FORMAT_RGBA_8888;
const int kUsage = 0;
-const size_t kUserMetadataSize = 0;
-
-using BufferHubDefs::AnyClientAcquired;
-using BufferHubDefs::AnyClientGained;
-using BufferHubDefs::AnyClientPosted;
-using BufferHubDefs::IsBufferReleased;
-using BufferHubDefs::IsClientAcquired;
-using BufferHubDefs::IsClientGained;
-using BufferHubDefs::IsClientPosted;
-using BufferHubDefs::IsClientReleased;
-using BufferHubDefs::kFirstClientBitMask;
-using BufferHubDefs::kMetadataHeaderSize;
-using frameworks::bufferhub::V1_0::BufferHubStatus;
-using frameworks::bufferhub::V1_0::IBufferClient;
-using frameworks::bufferhub::V1_0::IBufferHub;
-using hardware::hidl_handle;
-using hardware::graphics::common::V1_2::HardwareBufferDescription;
-using hidl::base::V1_0::IBase;
-using pdx::LocalChannelHandle;
+const AHardwareBuffer_Desc kDesc = {kWidth, kHeight, kLayerCount, kFormat,
+ kUsage, /*stride=*/0UL, /*rfu0=*/0UL, /*rfu1=*/0ULL};
+const size_t kUserMetadataSize = 1;
class BufferHubBufferTest : public ::testing::Test {
protected:
void SetUp() override { android::hardware::ProcessState::self()->startThreadPool(); }
};
+bool cmpAHardwareBufferDesc(const AHardwareBuffer_Desc& desc, const AHardwareBuffer_Desc& other) {
+ // Not comparing stride because it's unknown before allocation
+ return desc.format == other.format && desc.height == other.height &&
+ desc.layers == other.layers && desc.usage == other.usage && desc.width == other.width;
+}
+
class BufferHubBufferStateTransitionTest : public BufferHubBufferTest {
protected:
void SetUp() override {
@@ -67,9 +71,9 @@
}
std::unique_ptr<BufferHubBuffer> b1;
- uint64_t b1ClientMask = 0U;
+ uint32_t b1ClientMask = 0U;
std::unique_ptr<BufferHubBuffer> b2;
- uint64_t b2ClientMask = 0U;
+ uint32_t b2ClientMask = 0U;
private:
// Creates b1 and b2 as the clients of the same buffer for testing.
@@ -78,95 +82,154 @@
void BufferHubBufferStateTransitionTest::CreateTwoClientsOfABuffer() {
b1 = BufferHubBuffer::Create(kWidth, kHeight, kLayerCount, kFormat, kUsage, kUserMetadataSize);
+ ASSERT_THAT(b1, NotNull());
b1ClientMask = b1->client_state_mask();
ASSERT_NE(b1ClientMask, 0U);
- auto statusOrHandle = b1->Duplicate();
- ASSERT_TRUE(statusOrHandle);
- LocalChannelHandle h2 = statusOrHandle.take();
- b2 = BufferHubBuffer::Import(std::move(h2));
+
+ native_handle_t* token = b1->Duplicate();
+ ASSERT_THAT(token, NotNull());
+
+ // TODO(b/122543147): use a movalbe wrapper for token
+ b2 = BufferHubBuffer::Import(token);
+ native_handle_close(token);
+ native_handle_delete(token);
+ ASSERT_THAT(b2, NotNull());
+
b2ClientMask = b2->client_state_mask();
ASSERT_NE(b2ClientMask, 0U);
ASSERT_NE(b2ClientMask, b1ClientMask);
}
-TEST_F(BufferHubBufferTest, CreateBufferHubBufferFails) {
+TEST_F(BufferHubBufferTest, CreateBufferFails) {
// Buffer Creation will fail: BLOB format requires height to be 1.
auto b1 = BufferHubBuffer::Create(kWidth, /*height=*/2, kLayerCount,
/*format=*/HAL_PIXEL_FORMAT_BLOB, kUsage, kUserMetadataSize);
- EXPECT_FALSE(b1->IsConnected());
- EXPECT_FALSE(b1->IsValid());
+ EXPECT_THAT(b1, IsNull());
// Buffer Creation will fail: user metadata size too large.
auto b2 = BufferHubBuffer::Create(kWidth, kHeight, kLayerCount, kFormat, kUsage,
/*userMetadataSize=*/std::numeric_limits<size_t>::max());
- EXPECT_FALSE(b2->IsConnected());
- EXPECT_FALSE(b2->IsValid());
+ EXPECT_THAT(b2, IsNull());
// Buffer Creation will fail: user metadata size too large.
const size_t userMetadataSize = std::numeric_limits<size_t>::max() - kMetadataHeaderSize;
auto b3 = BufferHubBuffer::Create(kWidth, kHeight, kLayerCount, kFormat, kUsage,
userMetadataSize);
- EXPECT_FALSE(b3->IsConnected());
- EXPECT_FALSE(b3->IsValid());
+ EXPECT_THAT(b3, IsNull());
}
-TEST_F(BufferHubBufferTest, CreateBufferHubBuffer) {
+TEST_F(BufferHubBufferTest, CreateBuffer) {
auto b1 = BufferHubBuffer::Create(kWidth, kHeight, kLayerCount, kFormat, kUsage,
kUserMetadataSize);
+ ASSERT_THAT(b1, NotNull());
EXPECT_TRUE(b1->IsConnected());
EXPECT_TRUE(b1->IsValid());
- EXPECT_NE(b1->id(), 0);
+ EXPECT_TRUE(cmpAHardwareBufferDesc(b1->desc(), kDesc));
+ EXPECT_EQ(b1->user_metadata_size(), kUserMetadataSize);
}
-TEST_F(BufferHubBufferTest, DuplicateBufferHubBuffer) {
+TEST_F(BufferHubBufferTest, DuplicateAndImportBuffer) {
auto b1 = BufferHubBuffer::Create(kWidth, kHeight, kLayerCount, kFormat, kUsage,
kUserMetadataSize);
- int id1 = b1->id();
- uint64_t bufferStateMask1 = b1->client_state_mask();
- EXPECT_NE(bufferStateMask1, 0U);
+ ASSERT_THAT(b1, NotNull());
EXPECT_TRUE(b1->IsValid());
- EXPECT_EQ(b1->user_metadata_size(), kUserMetadataSize);
- auto statusOrHandle = b1->Duplicate();
- EXPECT_TRUE(statusOrHandle);
+ native_handle_t* token = b1->Duplicate();
+ EXPECT_TRUE(token);
// The detached buffer should still be valid.
EXPECT_TRUE(b1->IsConnected());
EXPECT_TRUE(b1->IsValid());
- // Gets the channel handle for the duplicated buffer.
- LocalChannelHandle h2 = statusOrHandle.take();
- EXPECT_TRUE(h2.valid());
+ std::unique_ptr<BufferHubBuffer> b2 = BufferHubBuffer::Import(token);
+ native_handle_close(token);
+ native_handle_delete(token);
- std::unique_ptr<BufferHubBuffer> b2 = BufferHubBuffer::Import(std::move(h2));
- EXPECT_FALSE(h2.valid());
- ASSERT_TRUE(b2 != nullptr);
+ ASSERT_THAT(b2, NotNull());
EXPECT_TRUE(b2->IsValid());
- EXPECT_EQ(b2->user_metadata_size(), kUserMetadataSize);
- int id2 = b2->id();
- uint64_t bufferStateMask2 = b2->client_state_mask();
- EXPECT_NE(bufferStateMask2, 0U);
+ EXPECT_TRUE(cmpAHardwareBufferDesc(b1->desc(), b2->desc()));
+ EXPECT_EQ(b1->user_metadata_size(), b2->user_metadata_size());
// These two buffer instances are based on the same physical buffer under the
// hood, so they should share the same id.
- EXPECT_EQ(id1, id2);
+ EXPECT_EQ(b1->id(), b2->id());
// We use client_state_mask() to tell those two instances apart.
- EXPECT_NE(bufferStateMask1, bufferStateMask2);
+ EXPECT_NE(b1->client_state_mask(), b2->client_state_mask());
// Both buffer instances should be in released state currently.
- EXPECT_TRUE(IsBufferReleased(b1->buffer_state()));
- EXPECT_TRUE(IsBufferReleased(b2->buffer_state()));
+ EXPECT_TRUE(b1->IsReleased());
+ EXPECT_TRUE(b2->IsReleased());
- // TODO(b/112338294): rewrite test after migration
- return;
+ // The event fd should behave like duped event fds.
+ const BufferHubEventFd& eventFd1 = b1->eventFd();
+ ASSERT_GE(eventFd1.get(), 0);
+ const BufferHubEventFd& eventFd2 = b2->eventFd();
+ ASSERT_GE(eventFd2.get(), 0);
+
+ base::unique_fd epollFd(epoll_create(64));
+ ASSERT_GE(epollFd.get(), 0);
+
+ // Add eventFd1 to epoll set, and signal eventFd2.
+ epoll_event e = {.events = EPOLLIN | EPOLLET, .data = {.u32 = 0}};
+ ASSERT_EQ(epoll_ctl(epollFd.get(), EPOLL_CTL_ADD, eventFd1.get(), &e), 0) << strerror(errno);
+
+ std::array<epoll_event, 1> events;
+ EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 0);
+
+ eventFd2.signal();
+ EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 1);
+
+ // The epoll fd is edge triggered, so it only responds to the eventFd once.
+ EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 0);
+
+ eventFd2.signal();
+ eventFd2.clear();
+ EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 0);
+}
+
+TEST_F(BufferHubBufferTest, ImportFreedBuffer) {
+ auto b1 = BufferHubBuffer::Create(kWidth, kHeight, kLayerCount, kFormat, kUsage,
+ kUserMetadataSize);
+ ASSERT_THAT(b1, NotNull());
+ EXPECT_TRUE(b1->IsValid());
+
+ native_handle_t* token = b1->Duplicate();
+ EXPECT_TRUE(token);
+
+ // Explicitly destroy b1. Backend buffer should be freed and token becomes invalid
+ b1.reset();
+
+ // TODO(b/122543147): use a movalbe wrapper for token
+ std::unique_ptr<BufferHubBuffer> b2 = BufferHubBuffer::Import(token);
+ native_handle_close(token);
+ native_handle_delete(token);
+
+ // Import should fail with INVALID_TOKEN
+ EXPECT_THAT(b2, IsNull());
+}
+
+// nullptr must not crash the service
+TEST_F(BufferHubBufferTest, ImportNullToken) {
+ auto b1 = BufferHubBuffer::Import(nullptr);
+ EXPECT_THAT(b1, IsNull());
+}
+
+TEST_F(BufferHubBufferTest, ImportInvalidToken) {
+ native_handle_t* token = native_handle_create(/*numFds=*/0, /*numInts=*/1);
+ token->data[0] = 0;
+
+ auto b1 = BufferHubBuffer::Import(token);
+ native_handle_delete(token);
+
+ EXPECT_THAT(b1, IsNull());
}
TEST_F(BufferHubBufferStateTransitionTest, GainBuffer_fromReleasedState) {
- ASSERT_TRUE(IsBufferReleased(b1->buffer_state()));
+ ASSERT_TRUE(b1->IsReleased());
// Successful gaining the buffer should change the buffer state bit of b1 to
// gained state, other client state bits to released state.
@@ -255,7 +318,7 @@
}
TEST_F(BufferHubBufferStateTransitionTest, PostBuffer_fromReleasedState) {
- ASSERT_TRUE(IsBufferReleased(b1->buffer_state()));
+ ASSERT_TRUE(b1->IsReleased());
// Posting from released state should fail.
EXPECT_EQ(b1->Post(), -EBUSY);
@@ -293,7 +356,7 @@
}
TEST_F(BufferHubBufferStateTransitionTest, AcquireBuffer_fromReleasedState) {
- ASSERT_TRUE(IsBufferReleased(b1->buffer_state()));
+ ASSERT_TRUE(b1->IsReleased());
// Acquiring form released state should fail.
EXPECT_EQ(b1->Acquire(), -EBUSY);
@@ -310,13 +373,13 @@
}
TEST_F(BufferHubBufferStateTransitionTest, ReleaseBuffer_fromSelfInReleasedState) {
- ASSERT_TRUE(IsBufferReleased(b1->buffer_state()));
+ ASSERT_TRUE(b1->IsReleased());
EXPECT_EQ(b1->Release(), 0);
}
TEST_F(BufferHubBufferStateTransitionTest, ReleaseBuffer_fromSelfInGainedState) {
- ASSERT_TRUE(IsBufferReleased(b1->buffer_state()));
+ ASSERT_TRUE(b1->IsReleased());
ASSERT_EQ(b1->Gain(), 0);
ASSERT_TRUE(AnyClientGained(b1->buffer_state()));
@@ -340,5 +403,67 @@
EXPECT_EQ(b2->Release(), 0);
}
+TEST_F(BufferHubBufferStateTransitionTest, BasicUsage) {
+ // 1 producer buffer and 1 consumer buffer initialised in testcase setup.
+ // Test if this set of basic operation succeed:
+ // Producer post three times to the consumer, and released by consumer.
+ for (int i = 0; i < 3; ++i) {
+ ASSERT_EQ(b1->Gain(), 0);
+ ASSERT_EQ(b1->Post(), 0);
+ ASSERT_EQ(b2->Acquire(), 0);
+ ASSERT_EQ(b2->Release(), 0);
+ }
+}
+
+TEST_F(BufferHubBufferTest, createNewConsumerAfterGain) {
+ // Create a poducer buffer and gain.
+ std::unique_ptr<BufferHubBuffer> b1 =
+ BufferHubBuffer::Create(kWidth, kHeight, kLayerCount, kFormat, kUsage,
+ kUserMetadataSize);
+ ASSERT_THAT(b1, NotNull());
+ ASSERT_EQ(b1->Gain(), 0);
+
+ // Create a consumer of the buffer and test if the consumer can acquire the
+ // buffer if producer posts.
+ // TODO(b/122543147): use a movalbe wrapper for token
+ native_handle_t* token = b1->Duplicate();
+ ASSERT_TRUE(token);
+
+ std::unique_ptr<BufferHubBuffer> b2 = BufferHubBuffer::Import(token);
+ native_handle_close(token);
+ native_handle_delete(token);
+
+ ASSERT_THAT(b2, NotNull());
+ ASSERT_NE(b1->client_state_mask(), b2->client_state_mask());
+
+ ASSERT_EQ(b1->Post(), 0);
+ EXPECT_EQ(b2->Acquire(), 0);
+}
+
+TEST_F(BufferHubBufferTest, createNewConsumerAfterPost) {
+ // Create a poducer buffer and post.
+ std::unique_ptr<BufferHubBuffer> b1 =
+ BufferHubBuffer::Create(kWidth, kHeight, kLayerCount, kFormat, kUsage,
+ kUserMetadataSize);
+ ASSERT_EQ(b1->Gain(), 0);
+ ASSERT_EQ(b1->Post(), 0);
+
+ // Create a consumer of the buffer and test if the consumer can acquire the
+ // buffer if producer posts.
+ // TODO(b/122543147): use a movalbe wrapper for token
+ native_handle_t* token = b1->Duplicate();
+ ASSERT_TRUE(token);
+
+ std::unique_ptr<BufferHubBuffer> b2 = BufferHubBuffer::Import(token);
+ native_handle_close(token);
+ native_handle_delete(token);
+
+ ASSERT_THAT(b2, NotNull());
+ ASSERT_NE(b1->client_state_mask(), b2->client_state_mask());
+
+ EXPECT_EQ(b2->Acquire(), 0);
+}
+
} // namespace
+
} // namespace android
diff --git a/libs/ui/tests/BufferHubEventFd_test.cpp b/libs/ui/tests/BufferHubEventFd_test.cpp
index 92fb33f..ef1781f 100644
--- a/libs/ui/tests/BufferHubEventFd_test.cpp
+++ b/libs/ui/tests/BufferHubEventFd_test.cpp
@@ -35,6 +35,7 @@
const int kTimeout = 100;
const std::chrono::milliseconds kTimeoutMs(kTimeout);
+const int kTestRuns = 5;
using ::testing::Contains;
using BufferHubEventFdTest = ::testing::Test;
@@ -46,9 +47,9 @@
ASSERT_TRUE(eventFd.isValid());
base::unique_fd epollFd(epoll_create(64));
- epoll_event e = {.events = EPOLLIN | EPOLLET, .data = {.u32 = 0}};
-
ASSERT_GE(epollFd.get(), 0);
+
+ epoll_event e = {.events = EPOLLIN | EPOLLET, .data = {.u32 = 0}};
ASSERT_EQ(epoll_ctl(epollFd.get(), EPOLL_CTL_ADD, eventFd.get(), &e), 0);
std::array<epoll_event, 1> events;
@@ -59,6 +60,96 @@
// The epoll fd is edge triggered, so it only responds to the eventFd once.
EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 0);
+
+ // Check that it can receive consecutive signal.
+ eventFd.signal();
+ EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 1);
+ EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 0);
+
+ // Check that it can receive consecutive signal from a duplicated eventfd.
+ BufferHubEventFd dupEventFd(dup(eventFd.get()));
+ ASSERT_TRUE(dupEventFd.isValid());
+ dupEventFd.signal();
+ EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 1);
+ EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 0);
+ dupEventFd.signal();
+ EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 1);
+ EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 0);
+}
+
+TEST_F(BufferHubEventFdTest, EventFd_testCreateEpollFdAndAddSignaledEventFd) {
+ BufferHubEventFd eventFd;
+ ASSERT_TRUE(eventFd.isValid());
+ eventFd.signal();
+
+ base::unique_fd epollFd(epoll_create(64));
+ ASSERT_GE(epollFd.get(), 0);
+
+ // Make sure that the epoll set has not been signal yet.
+ std::array<epoll_event, 1> events;
+ ASSERT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 0);
+
+ // Check that adding an signaled fd into this epoll set will trigger the epoll set.
+ epoll_event e = {.events = EPOLLIN | EPOLLET, .data = {.u32 = 0}};
+ ASSERT_EQ(epoll_ctl(epollFd.get(), EPOLL_CTL_ADD, eventFd.get(), &e), 0);
+ EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 1);
+
+ // The epoll fd is edge triggered, so it only responds to the eventFd once.
+ EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 0);
+}
+
+TEST_F(BufferHubEventFdTest, EventFd_testAddSignaledEventFdToEpollFd) {
+ BufferHubEventFd eventFd;
+ ASSERT_TRUE(eventFd.isValid());
+
+ base::unique_fd epollFd(epoll_create(64));
+ ASSERT_GE(epollFd.get(), 0);
+
+ eventFd.signal();
+
+ epoll_event e = {.events = EPOLLIN | EPOLLET, .data = {.u32 = 0}};
+ ASSERT_EQ(epoll_ctl(epollFd.get(), EPOLL_CTL_ADD, eventFd.get(), &e), 0);
+
+ std::array<epoll_event, 1> events;
+ EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 1);
+
+ // The epoll fd is edge triggered, so it only responds to the eventFd once.
+ EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 0);
+}
+
+TEST_F(BufferHubEventFdTest, EventFd_testConsecutiveSignalsFromAEventFd) {
+ BufferHubEventFd eventFd;
+ ASSERT_TRUE(eventFd.isValid());
+ base::unique_fd epollFd(epoll_create(64));
+ ASSERT_GE(epollFd.get(), 0);
+ epoll_event e = {.events = EPOLLIN | EPOLLET, .data = {.u32 = 0}};
+ ASSERT_EQ(epoll_ctl(epollFd.get(), EPOLL_CTL_ADD, eventFd.get(), &e), 0);
+
+ std::array<epoll_event, 1> events;
+ for (int i = 0; i < kTestRuns; ++i) {
+ eventFd.signal();
+ EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 1);
+ EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 0);
+ }
+}
+
+TEST_F(BufferHubEventFdTest, EventFd_testConsecutiveSignalsFromADuplicatedEventFd) {
+ BufferHubEventFd eventFd;
+ ASSERT_TRUE(eventFd.isValid());
+ base::unique_fd epollFd(epoll_create(64));
+ ASSERT_GE(epollFd.get(), 0);
+ epoll_event e = {.events = EPOLLIN | EPOLLET, .data = {.u32 = 0}};
+ ASSERT_EQ(epoll_ctl(epollFd.get(), EPOLL_CTL_ADD, eventFd.get(), &e), 0);
+
+ BufferHubEventFd dupEventFd(dup(eventFd.get()));
+ ASSERT_TRUE(dupEventFd.isValid());
+
+ std::array<epoll_event, 1> events;
+ for (int i = 0; i < kTestRuns; ++i) {
+ dupEventFd.signal();
+ EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 1);
+ EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 0);
+ }
}
TEST_F(BufferHubEventFdTest, EventFd_testClear) {
@@ -91,22 +182,21 @@
// Technically, the dupliated eventFd and the original eventFd are pointing
// to the same kernel object. This test signals the duplicated eventFd but epolls the origianl
// eventFd.
- base::unique_fd dupedEventFd(dup(eventFd.get()));
+ BufferHubEventFd dupedEventFd(dup(eventFd.get()));
ASSERT_GE(dupedEventFd.get(), 0);
std::array<epoll_event, 1> events;
EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 0);
- eventfd_write(dupedEventFd.get(), 1);
+ dupedEventFd.signal();
EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 1);
// The epoll fd is edge triggered, so it only responds to the eventFd once.
EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 0);
- eventfd_write(dupedEventFd.get(), 1);
+ dupedEventFd.signal();
- eventfd_t value;
- eventfd_read(dupedEventFd.get(), &value);
+ dupedEventFd.clear();
EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 0);
}
diff --git a/libs/ui/tests/BufferHubMetadata_test.cpp b/libs/ui/tests/BufferHubMetadata_test.cpp
index 11f8e57..b7f0b4b 100644
--- a/libs/ui/tests/BufferHubMetadata_test.cpp
+++ b/libs/ui/tests/BufferHubMetadata_test.cpp
@@ -17,8 +17,6 @@
#include <gtest/gtest.h>
#include <ui/BufferHubMetadata.h>
-using android::BufferHubDefs::IsBufferReleased;
-
namespace android {
namespace dvr {
@@ -52,13 +50,17 @@
BufferHubDefs::MetadataHeader* mh1 = m1.metadata_header();
EXPECT_NE(mh1, nullptr);
- EXPECT_TRUE(IsBufferReleased(mh1->buffer_state.load()));
+ // Check if the newly allocated buffer is initialized in released state (i.e.
+ // state equals to 0U).
+ EXPECT_TRUE(mh1->buffer_state.load() == 0U);
EXPECT_TRUE(m2.IsValid());
BufferHubDefs::MetadataHeader* mh2 = m2.metadata_header();
EXPECT_NE(mh2, nullptr);
- EXPECT_TRUE(IsBufferReleased(mh2->buffer_state.load()));
+ // Check if the newly allocated buffer is initialized in released state (i.e.
+ // state equals to 0U).
+ EXPECT_TRUE(mh2->buffer_state.load() == 0U);
}
TEST_F(BufferHubMetadataTest, MoveMetadataInvalidatesOldOne) {
diff --git a/libs/ui/tests/GraphicBuffer_test.cpp b/libs/ui/tests/GraphicBuffer_test.cpp
index 81ab3ac..5b46454 100644
--- a/libs/ui/tests/GraphicBuffer_test.cpp
+++ b/libs/ui/tests/GraphicBuffer_test.cpp
@@ -39,7 +39,7 @@
std::unique_ptr<BufferHubBuffer> b1 =
BufferHubBuffer::Create(kTestWidth, kTestHeight, kTestLayerCount, kTestFormat,
kTestUsage, /*userMetadataSize=*/0);
- EXPECT_NE(b1, nullptr);
+ ASSERT_NE(b1, nullptr);
EXPECT_TRUE(b1->IsValid());
sp<GraphicBuffer> gb(new GraphicBuffer(std::move(b1)));
diff --git a/libs/ui/tests/Size_test.cpp b/libs/ui/tests/Size_test.cpp
new file mode 100644
index 0000000..69e1ac8
--- /dev/null
+++ b/libs/ui/tests/Size_test.cpp
@@ -0,0 +1,184 @@
+/*
+ * 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_TAG "SizeTest"
+
+#include <cmath>
+#include <cstdlib>
+
+#include <ui/Size.h>
+
+#include <gtest/gtest.h>
+
+namespace android {
+namespace ui {
+
+TEST(SizeTest, BasicConstructionAndEqualityComparison) {
+ Size s(123, 456);
+
+ EXPECT_EQ(123, s.width);
+ EXPECT_EQ(123, s.getWidth());
+
+ EXPECT_EQ(456, s.height);
+ EXPECT_EQ(456, s.getHeight());
+
+ EXPECT_EQ(Size(123, 456), s);
+ EXPECT_NE(Size(456, 123), s);
+}
+
+TEST(SizeTest, BasicLessThanComparison) {
+ EXPECT_TRUE(Size(0, 1) < Size(2, 3));
+ EXPECT_FALSE(Size(2, 3) < Size(0, 1));
+
+ EXPECT_TRUE(Size(0, 3) < Size(2, 1));
+ EXPECT_FALSE(Size(2, 1) < Size(0, 3));
+
+ EXPECT_TRUE(Size(0, 1) < Size(0, 3));
+ EXPECT_FALSE(Size(0, 3) < Size(0, 1));
+
+ EXPECT_FALSE(Size(1, 1) < Size(1, 1));
+}
+
+TEST(SizeTest, ValidAndEmpty) {
+ {
+ Size s;
+ EXPECT_FALSE(s.isValid());
+ EXPECT_FALSE(s.isEmpty());
+ }
+
+ {
+ Size s(-1, -1);
+ EXPECT_FALSE(s.isValid());
+ EXPECT_FALSE(s.isEmpty());
+ }
+
+ {
+ Size s(1, -1000);
+ EXPECT_FALSE(s.isValid());
+ EXPECT_FALSE(s.isEmpty());
+ }
+
+ {
+ Size s(-1000, 1);
+ EXPECT_FALSE(s.isValid());
+ EXPECT_FALSE(s.isEmpty());
+ }
+
+ {
+ Size s(-1000, -1000);
+ EXPECT_FALSE(s.isValid());
+ EXPECT_FALSE(s.isEmpty());
+ }
+
+ {
+ const auto& s = Size::INVALID;
+ EXPECT_FALSE(s.isValid());
+ EXPECT_FALSE(s.isEmpty());
+ }
+
+ {
+ Size s(123, 456);
+ s.makeInvalid();
+ EXPECT_FALSE(s.isValid());
+ EXPECT_FALSE(s.isEmpty());
+ }
+
+ {
+ Size s(0, 0);
+ EXPECT_TRUE(s.isValid());
+ EXPECT_TRUE(s.isEmpty());
+ }
+
+ {
+ const auto& s = Size::EMPTY;
+ EXPECT_TRUE(s.isValid());
+ EXPECT_TRUE(s.isEmpty());
+ }
+
+ {
+ Size s(123, 456);
+ s.clear();
+ EXPECT_TRUE(s.isValid());
+ EXPECT_TRUE(s.isEmpty());
+ }
+
+ {
+ Size s(123, 456);
+ EXPECT_TRUE(s.isValid());
+ EXPECT_FALSE(s.isEmpty());
+ }
+}
+
+TEST(SizeTest, Set) {
+ {
+ Size s;
+ s.setWidth(0);
+ EXPECT_EQ(Size(0, -1), s);
+ }
+
+ {
+ Size s;
+ s.setHeight(0);
+ EXPECT_EQ(Size(-1, 0), s);
+ }
+
+ {
+ Size s;
+ s.set(123, 456);
+ EXPECT_EQ(Size(123, 456), s);
+ }
+}
+
+template <typename T, typename U>
+void ClampTest(T input, U expected) {
+ // The constructor, set(), setWidth() and setHeight() all allow arbitrary
+ // conversions from other numeric types, and implement clamping if necessary.
+
+ EXPECT_EQ(Size(expected, expected), Size(input, input));
+
+ {
+ Size s;
+ s.set(input, input);
+ EXPECT_EQ(Size(expected, expected), s);
+ }
+
+ {
+ Size s;
+ s.setWidth(input);
+ EXPECT_EQ(expected, s.width);
+ }
+
+ {
+ Size s;
+ s.setHeight(input);
+ EXPECT_EQ(expected, s.height);
+ }
+}
+
+TEST(SizeTest, Int8RangeIsNotClamped) {
+ ClampTest(std::numeric_limits<int8_t>::max(), std::numeric_limits<int8_t>::max());
+ ClampTest(int8_t(0), int8_t(0));
+ ClampTest(std::numeric_limits<int8_t>::lowest(), std::numeric_limits<int8_t>::lowest());
+}
+
+TEST(SizeTest, FloatRangeIsClamped) {
+ ClampTest(std::numeric_limits<float>::max(), std::numeric_limits<int32_t>::max());
+ ClampTest(float(0), int32_t(0));
+ ClampTest(std::numeric_limits<float>::lowest(), std::numeric_limits<int32_t>::lowest());
+}
+
+} // namespace ui
+} // namespace android
diff --git a/libs/vibrator/Android.bp b/libs/vibrator/Android.bp
new file mode 100644
index 0000000..e95a080
--- /dev/null
+++ b/libs/vibrator/Android.bp
@@ -0,0 +1,48 @@
+// 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.
+
+cc_library_shared {
+ name: "libvibrator",
+
+ shared_libs: [
+ "libbinder",
+ "liblog",
+ "libutils",
+ ],
+
+ header_libs: [
+ "libaudio_system_headers",
+ ],
+
+ aidl: {
+ include_dirs: ["frameworks/base/core/java"],
+ local_include_dirs: ["include/"],
+ export_aidl_headers: true,
+ },
+
+ srcs: [
+ ":libvibrator_aidl",
+ "*.cpp",
+ ],
+
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-Wno-missing-field-initializers",
+ "-Wno-unused-variable",
+ "-Wno-unused-parameter",
+ ],
+
+ export_include_dirs: ["include"],
+}
diff --git a/libs/vibrator/ExternalVibration.cpp b/libs/vibrator/ExternalVibration.cpp
new file mode 100644
index 0000000..f6fc19e
--- /dev/null
+++ b/libs/vibrator/ExternalVibration.cpp
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <vibrator/ExternalVibration.h>
+
+#include <binder/Parcel.h>
+#include <log/log.h>
+#include <utils/Errors.h>
+
+void writeAudioAttributes(const audio_attributes_t& attrs, android::Parcel* out) {
+ out->writeInt32(attrs.usage);
+ out->writeInt32(attrs.content_type);
+ out->writeInt32(attrs.source);
+ out->writeInt32(attrs.flags);
+}
+
+void readAudioAttributes(audio_attributes_t* attrs, const android::Parcel* in) {
+ attrs->usage = static_cast<audio_usage_t>(in->readInt32());
+ attrs->content_type = static_cast<audio_content_type_t>(in->readInt32());
+ attrs->source = static_cast<audio_source_t>(in->readInt32());
+ attrs->flags = static_cast<audio_flags_mask_t>(in->readInt32());
+}
+
+namespace android {
+namespace os {
+
+ExternalVibration::ExternalVibration(int32_t uid, std::string pkg, const audio_attributes_t& attrs,
+ sp<IExternalVibrationController> controller) :
+ mUid(uid), mPkg(pkg), mAttrs(attrs), mController(controller) { }
+
+status_t ExternalVibration::writeToParcel(Parcel* parcel) const {
+ parcel->writeInt32(mUid);
+ parcel->writeString16(String16(mPkg.c_str()));
+ writeAudioAttributes(mAttrs, parcel);
+ parcel->writeStrongBinder(IInterface::asBinder(mController));
+ parcel->writeStrongBinder(mToken);
+ return OK;
+}
+status_t ExternalVibration::readFromParcel(const Parcel* parcel) {
+ mUid = parcel->readInt32();
+ String8 pkgStr8 = String8(parcel->readString16());
+ mPkg = pkgStr8.c_str();
+ readAudioAttributes(&mAttrs, parcel);
+ mController = IExternalVibrationController::asInterface(parcel->readStrongBinder());
+ mToken = parcel->readStrongBinder();
+ return OK;
+}
+
+inline bool ExternalVibration::operator==(const ExternalVibration& rhs) const {
+ return mToken == rhs.mToken;
+}
+
+} // namespace os
+} // namespace android
diff --git a/libs/vibrator/include/vibrator/ExternalVibration.h b/libs/vibrator/include/vibrator/ExternalVibration.h
new file mode 100644
index 0000000..c6eb3d1
--- /dev/null
+++ b/libs/vibrator/include/vibrator/ExternalVibration.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_EXTERNAL_VIBRATION_H
+#define ANDROID_EXTERNAL_VIBRATION_H
+
+#include <android/os/IExternalVibrationController.h>
+#include <binder/Binder.h>
+#include <binder/IBinder.h>
+#include <binder/Parcelable.h>
+#include <system/audio.h>
+#include <utils/RefBase.h>
+
+namespace android {
+namespace os {
+
+class ExternalVibration : public Parcelable, public virtual RefBase {
+public :
+ ExternalVibration() = default;
+ ExternalVibration(int32_t uid, std::string pkg, const audio_attributes_t& attrs,
+ sp<IExternalVibrationController> controller);
+ virtual ~ExternalVibration() = default;
+ ExternalVibration(const ExternalVibration&) = default;
+
+ bool operator==(const ExternalVibration&) const;
+
+ status_t writeToParcel(Parcel* parcel) const override;
+ status_t readFromParcel(const Parcel* parcel) override;
+
+ int32_t getUid() const { return mUid; }
+ std::string getPackage() const { return mPkg; }
+ audio_attributes_t getAudioAttributes() const { return mAttrs; }
+ sp<IExternalVibrationController> getController() { return mController; }
+
+
+private:
+ int32_t mUid;
+ std::string mPkg;
+ audio_attributes_t mAttrs;
+ sp<IExternalVibrationController> mController;
+ sp<IBinder> mToken = new BBinder();
+};
+
+} // namespace android
+} // namespace os
+
+#endif // ANDROID_EXTERNAL_VIBRATION_H
diff --git a/libs/vr/libbufferhub/buffer_hub-test.cpp b/libs/vr/libbufferhub/buffer_hub-test.cpp
index 1359f4c..527a27d 100644
--- a/libs/vr/libbufferhub/buffer_hub-test.cpp
+++ b/libs/vr/libbufferhub/buffer_hub-test.cpp
@@ -5,12 +5,12 @@
#include <private/dvr/producer_buffer.h>
#include <sys/epoll.h>
#include <sys/eventfd.h>
-#include <ui/BufferHubBuffer.h>
#include <ui/BufferHubDefs.h>
#include <mutex>
#include <thread>
+namespace {
#define RETRY_EINTR(fnc_call) \
([&]() -> decltype(fnc_call) { \
decltype(fnc_call) result; \
@@ -20,37 +20,38 @@
return result; \
})()
-using android::BufferHubBuffer;
-using android::GraphicBuffer;
-using android::sp;
using android::BufferHubDefs::AnyClientAcquired;
using android::BufferHubDefs::AnyClientGained;
using android::BufferHubDefs::AnyClientPosted;
-using android::BufferHubDefs::IsBufferReleased;
using android::BufferHubDefs::IsClientAcquired;
using android::BufferHubDefs::IsClientPosted;
using android::BufferHubDefs::IsClientReleased;
using android::BufferHubDefs::kFirstClientBitMask;
-using android::BufferHubDefs::kMetadataHeaderSize;
using android::dvr::ConsumerBuffer;
using android::dvr::ProducerBuffer;
-using android::pdx::LocalChannelHandle;
using android::pdx::LocalHandle;
using android::pdx::Status;
+using LibBufferHubTest = ::testing::Test;
const int kWidth = 640;
const int kHeight = 480;
-const int kLayerCount = 1;
const int kFormat = HAL_PIXEL_FORMAT_RGBA_8888;
const int kUsage = 0;
-const size_t kUserMetadataSize = 0;
// Maximum number of consumers for the buffer that only has one producer in the
// test.
const size_t kMaxConsumerCount =
android::BufferHubDefs::kMaxNumberOfClients - 1;
const int kPollTimeoutMs = 100;
-using LibBufferHubTest = ::testing::Test;
+// Helper function to poll the eventfd in BufferHubBase.
+template <class BufferHubBase>
+int PollBufferEvent(const std::unique_ptr<BufferHubBase>& buffer,
+ int timeout_ms = kPollTimeoutMs) {
+ pollfd p = {buffer->event_fd(), POLLIN, 0};
+ return poll(&p, 1, timeout_ms);
+}
+
+} // namespace
TEST_F(LibBufferHubTest, TestBasicUsage) {
std::unique_ptr<ProducerBuffer> p = ProducerBuffer::Create(
@@ -70,36 +71,36 @@
EXPECT_EQ(c2->client_state_mask(), kFirstClientBitMask << 2);
// Initial state: producer not available, consumers not available.
- EXPECT_EQ(0, RETRY_EINTR(p->Poll(kPollTimeoutMs)));
- EXPECT_EQ(0, RETRY_EINTR(c1->Poll(kPollTimeoutMs)));
- EXPECT_EQ(0, RETRY_EINTR(c2->Poll(kPollTimeoutMs)));
+ EXPECT_EQ(0, RETRY_EINTR(PollBufferEvent(p)));
+ EXPECT_EQ(0, RETRY_EINTR(PollBufferEvent(c1)));
+ EXPECT_EQ(0, RETRY_EINTR(PollBufferEvent(c2)));
EXPECT_EQ(0, p->GainAsync());
EXPECT_EQ(0, p->Post(LocalHandle()));
// New state: producer not available, consumers available.
- EXPECT_EQ(0, RETRY_EINTR(p->Poll(kPollTimeoutMs)));
- EXPECT_EQ(1, RETRY_EINTR(c1->Poll(kPollTimeoutMs)));
- EXPECT_EQ(1, RETRY_EINTR(c2->Poll(kPollTimeoutMs)));
+ EXPECT_EQ(0, RETRY_EINTR(PollBufferEvent(p)));
+ EXPECT_EQ(1, RETRY_EINTR(PollBufferEvent(c1)));
+ EXPECT_EQ(1, RETRY_EINTR(PollBufferEvent(c2)));
LocalHandle fence;
EXPECT_EQ(0, c1->Acquire(&fence));
- EXPECT_EQ(0, RETRY_EINTR(c1->Poll(kPollTimeoutMs)));
- EXPECT_EQ(1, RETRY_EINTR(c2->Poll(kPollTimeoutMs)));
+ EXPECT_EQ(0, RETRY_EINTR(PollBufferEvent(c1)));
+ EXPECT_EQ(1, RETRY_EINTR(PollBufferEvent(c2)));
EXPECT_EQ(0, c2->Acquire(&fence));
- EXPECT_EQ(0, RETRY_EINTR(c2->Poll(kPollTimeoutMs)));
- EXPECT_EQ(0, RETRY_EINTR(c1->Poll(kPollTimeoutMs)));
+ EXPECT_EQ(0, RETRY_EINTR(PollBufferEvent(c2)));
+ EXPECT_EQ(0, RETRY_EINTR(PollBufferEvent(c1)));
EXPECT_EQ(0, c1->Release(LocalHandle()));
- EXPECT_EQ(0, RETRY_EINTR(p->Poll(kPollTimeoutMs)));
+ EXPECT_EQ(0, RETRY_EINTR(PollBufferEvent(p)));
EXPECT_EQ(0, c2->Discard());
- EXPECT_EQ(1, RETRY_EINTR(p->Poll(kPollTimeoutMs)));
+ EXPECT_EQ(1, RETRY_EINTR(PollBufferEvent(p)));
EXPECT_EQ(0, p->Gain(&fence));
- EXPECT_EQ(0, RETRY_EINTR(p->Poll(kPollTimeoutMs)));
- EXPECT_EQ(0, RETRY_EINTR(c1->Poll(kPollTimeoutMs)));
- EXPECT_EQ(0, RETRY_EINTR(c2->Poll(kPollTimeoutMs)));
+ EXPECT_EQ(0, RETRY_EINTR(PollBufferEvent(p)));
+ EXPECT_EQ(0, RETRY_EINTR(PollBufferEvent(c1)));
+ EXPECT_EQ(0, RETRY_EINTR(PollBufferEvent(c2)));
}
TEST_F(LibBufferHubTest, TestEpoll) {
@@ -234,7 +235,7 @@
// Release in acquired state should succeed.
EXPECT_EQ(0, c->Release(LocalHandle()));
- EXPECT_LT(0, RETRY_EINTR(p->Poll(kPollTimeoutMs)));
+ EXPECT_LT(0, RETRY_EINTR(PollBufferEvent(p)));
// Acquire and post in released state should fail.
EXPECT_EQ(-EBUSY, c->Acquire(&fence));
@@ -275,7 +276,7 @@
EXPECT_FALSE(invalid_fence.IsValid());
// Acquire in posted state should succeed.
- EXPECT_LT(0, RETRY_EINTR(c->Poll(kPollTimeoutMs)));
+ EXPECT_LT(0, RETRY_EINTR(PollBufferEvent(c)));
EXPECT_EQ(0, c->AcquireAsync(&metadata, &invalid_fence));
EXPECT_FALSE(invalid_fence.IsValid());
EXPECT_EQ(p->buffer_state(), c->buffer_state());
@@ -290,9 +291,9 @@
// Release in acquired state should succeed.
EXPECT_EQ(0, c->ReleaseAsync(&metadata, invalid_fence));
- EXPECT_LT(0, RETRY_EINTR(p->Poll(kPollTimeoutMs)));
+ EXPECT_LT(0, RETRY_EINTR(PollBufferEvent(p)));
EXPECT_EQ(p->buffer_state(), c->buffer_state());
- EXPECT_TRUE(IsBufferReleased(p->buffer_state()));
+ EXPECT_TRUE(p->is_released());
// Acquire and post in released state should fail.
EXPECT_EQ(-EBUSY, c->AcquireAsync(&metadata, &invalid_fence));
@@ -361,9 +362,11 @@
ASSERT_TRUE(p.get() != nullptr);
ASSERT_EQ(0, p->GainAsync());
ASSERT_EQ(0, p->Post(LocalHandle()));
- // Producer state bit is in released state after post. The overall state of
- // the buffer is also released because there is no consumer of this buffer.
- ASSERT_TRUE(IsBufferReleased(p->buffer_state()));
+ // Producer state bit is in released state after post, other clients shall be
+ // in posted state although there is no consumer of this buffer yet.
+ ASSERT_TRUE(IsClientReleased(p->buffer_state(), p->client_state_mask()));
+ ASSERT_TRUE(p->is_released());
+ ASSERT_TRUE(AnyClientPosted(p->buffer_state()));
// Gain in released state should succeed.
LocalHandle invalid_fence;
@@ -380,7 +383,7 @@
for (size_t i = 0; i < kMaxConsumerCount; ++i) {
cs[i] = ConsumerBuffer::Import(p->CreateConsumer());
ASSERT_TRUE(cs[i].get() != nullptr);
- EXPECT_TRUE(IsBufferReleased(cs[i]->buffer_state()));
+ EXPECT_TRUE(cs[i]->is_released());
EXPECT_NE(producer_state_mask, cs[i]->client_state_mask());
}
@@ -394,7 +397,7 @@
for (size_t i = 0; i < kMaxConsumerCount; ++i) {
EXPECT_TRUE(
IsClientPosted(cs[i]->buffer_state(), cs[i]->client_state_mask()));
- EXPECT_LT(0, RETRY_EINTR(cs[i]->Poll(kPollTimeoutMs)));
+ EXPECT_LT(0, RETRY_EINTR(PollBufferEvent(cs[i])));
EXPECT_EQ(0, cs[i]->AcquireAsync(&metadata, &invalid_fence));
EXPECT_TRUE(
IsClientAcquired(p->buffer_state(), cs[i]->client_state_mask()));
@@ -403,12 +406,12 @@
// All consumers have to release before the buffer is considered to be
// released.
for (size_t i = 0; i < kMaxConsumerCount; i++) {
- EXPECT_FALSE(IsBufferReleased(p->buffer_state()));
+ EXPECT_FALSE(p->is_released());
EXPECT_EQ(0, cs[i]->ReleaseAsync(&metadata, invalid_fence));
}
- EXPECT_LT(0, RETRY_EINTR(p->Poll(kPollTimeoutMs)));
- EXPECT_TRUE(IsBufferReleased(p->buffer_state()));
+ EXPECT_LT(0, RETRY_EINTR(PollBufferEvent(p)));
+ EXPECT_TRUE(p->is_released());
// Buffer state cross all clients must be consistent.
for (size_t i = 0; i < kMaxConsumerCount; i++) {
@@ -434,7 +437,7 @@
// Post the gained buffer should signal already created consumer.
EXPECT_EQ(0, p->PostAsync(&metadata, invalid_fence));
EXPECT_TRUE(AnyClientPosted(p->buffer_state()));
- EXPECT_LT(0, RETRY_EINTR(c->Poll(kPollTimeoutMs)));
+ EXPECT_LT(0, RETRY_EINTR(PollBufferEvent(c)));
EXPECT_EQ(0, c->AcquireAsync(&metadata, &invalid_fence));
EXPECT_TRUE(AnyClientAcquired(c->buffer_state()));
}
@@ -450,27 +453,17 @@
LocalHandle invalid_fence;
// Post the gained buffer before any consumer gets created.
- // The buffer should be in released state because it is not expected to be
- // read by any clients.
EXPECT_EQ(0, p->PostAsync(&metadata, invalid_fence));
- EXPECT_TRUE(IsBufferReleased(p->buffer_state()));
- EXPECT_EQ(0, RETRY_EINTR(p->Poll(kPollTimeoutMs)));
+ EXPECT_TRUE(p->is_released());
+ EXPECT_EQ(0, RETRY_EINTR(PollBufferEvent(p)));
- // Newly created consumer will not be signalled for the posted buffer before
- // its creation. It cannot acquire the buffer immediately.
+ // Newly created consumer will be signalled for the posted buffer although it
+ // is created after producer posting.
std::unique_ptr<ConsumerBuffer> c =
ConsumerBuffer::Import(p->CreateConsumer());
ASSERT_TRUE(c.get() != nullptr);
- EXPECT_FALSE(IsClientPosted(c->buffer_state(), c->client_state_mask()));
- EXPECT_EQ(-EBUSY, c->AcquireAsync(&metadata, &invalid_fence));
-
- // Producer should be able to gain back and post the buffer
- EXPECT_EQ(0, p->GainAsync());
- EXPECT_EQ(0, p->PostAsync(&metadata, invalid_fence));
-
- // Consumer should be able to pick up the buffer this time.
+ EXPECT_TRUE(IsClientPosted(c->buffer_state(), c->client_state_mask()));
EXPECT_EQ(0, c->AcquireAsync(&metadata, &invalid_fence));
- EXPECT_TRUE(IsClientAcquired(c->buffer_state(), c->client_state_mask()));
}
TEST_F(LibBufferHubTest, TestCreateConsumerWhenBufferReleased) {
@@ -488,7 +481,7 @@
// Post, acquire, and release the buffer..
EXPECT_EQ(0, p->PostAsync(&metadata, invalid_fence));
- EXPECT_LT(0, RETRY_EINTR(c1->Poll(kPollTimeoutMs)));
+ EXPECT_LT(0, RETRY_EINTR(PollBufferEvent(c1)));
EXPECT_EQ(0, c1->AcquireAsync(&metadata, &invalid_fence));
EXPECT_EQ(0, c1->ReleaseAsync(&metadata, invalid_fence));
@@ -496,8 +489,8 @@
// executed before Release impulse gets executed by bufferhubd. Thus, here we
// need to wait until the releasd is confirmed before creating another
// consumer.
- EXPECT_LT(0, RETRY_EINTR(p->Poll(kPollTimeoutMs)));
- EXPECT_TRUE(IsBufferReleased(p->buffer_state()));
+ EXPECT_LT(0, RETRY_EINTR(PollBufferEvent(p)));
+ EXPECT_TRUE(p->is_released());
// Create another consumer immediately after the release, should not make the
// buffer un-released.
@@ -505,7 +498,7 @@
ConsumerBuffer::Import(p->CreateConsumer());
ASSERT_TRUE(c2.get() != nullptr);
- EXPECT_TRUE(IsBufferReleased(p->buffer_state()));
+ EXPECT_TRUE(p->is_released());
EXPECT_EQ(0, p->GainAsync(&metadata, &invalid_fence));
EXPECT_TRUE(AnyClientGained(p->buffer_state()));
}
@@ -524,14 +517,14 @@
EXPECT_EQ(0, p->GainAsync());
Metadata m = {1, 3};
EXPECT_EQ(0, p->Post(LocalHandle(), &m, sizeof(Metadata)));
- EXPECT_LE(0, RETRY_EINTR(c->Poll(kPollTimeoutMs)));
+ EXPECT_LE(0, RETRY_EINTR(PollBufferEvent(c)));
LocalHandle fence;
Metadata m2 = {};
EXPECT_EQ(0, c->Acquire(&fence, &m2, sizeof(m2)));
EXPECT_EQ(m.field1, m2.field1);
EXPECT_EQ(m.field2, m2.field2);
EXPECT_EQ(0, c->Release(LocalHandle()));
- EXPECT_LT(0, RETRY_EINTR(p->Poll(0)));
+ EXPECT_LT(0, RETRY_EINTR(PollBufferEvent(p, /*timeout_ms=*/0)));
}
TEST_F(LibBufferHubTest, TestPostWithWrongMetaSize) {
@@ -556,7 +549,7 @@
// buffer allocation.
OverSizedMetadata evil_meta = {};
EXPECT_NE(0, p->Post(LocalHandle(), &evil_meta, sizeof(OverSizedMetadata)));
- EXPECT_GE(0, RETRY_EINTR(c->Poll(kPollTimeoutMs)));
+ EXPECT_GE(0, RETRY_EINTR(PollBufferEvent(c)));
// It is ok to post metadata smaller than originally requested during
// buffer allocation.
@@ -668,7 +661,7 @@
// Should acquire a valid fence.
LocalHandle f2;
- EXPECT_LT(0, RETRY_EINTR(c->Poll(kPollTimeoutMs)));
+ EXPECT_LT(0, RETRY_EINTR(PollBufferEvent(c)));
EXPECT_EQ(0, c->AcquireAsync(&meta, &f2));
EXPECT_TRUE(f2.IsValid());
// The original fence and acquired fence should have different fd number.
@@ -685,7 +678,7 @@
// Should gain an invalid fence.
LocalHandle f3;
- EXPECT_LT(0, RETRY_EINTR(p->Poll(kPollTimeoutMs)));
+ EXPECT_LT(0, RETRY_EINTR(PollBufferEvent(p)));
EXPECT_EQ(0, p->GainAsync(&meta, &f3));
EXPECT_FALSE(f3.IsValid());
@@ -694,7 +687,7 @@
// Should acquire a valid fence and it's already signalled.
LocalHandle f4;
- EXPECT_LT(0, RETRY_EINTR(c->Poll(kPollTimeoutMs)));
+ EXPECT_LT(0, RETRY_EINTR(PollBufferEvent(c)));
EXPECT_EQ(0, c->AcquireAsync(&meta, &f4));
EXPECT_TRUE(f4.IsValid());
EXPECT_LT(0, PollFd(f4.Get(), kPollTimeoutMs));
@@ -707,7 +700,7 @@
// Should gain a valid fence, which is already signaled.
LocalHandle f6;
- EXPECT_LT(0, RETRY_EINTR(p->Poll(kPollTimeoutMs)));
+ EXPECT_LT(0, RETRY_EINTR(PollBufferEvent(p)));
EXPECT_EQ(0, p->GainAsync(&meta, &f6));
EXPECT_TRUE(f6.IsValid());
EXPECT_LT(0, PollFd(f6.Get(), kPollTimeoutMs));
@@ -727,14 +720,14 @@
EXPECT_EQ(0, p->PostAsync(&meta, LocalHandle()));
LocalHandle fence;
- EXPECT_LT(0, RETRY_EINTR(c1->Poll(kPollTimeoutMs)));
+ EXPECT_LT(0, RETRY_EINTR(PollBufferEvent(c1)));
EXPECT_EQ(0, c1->AcquireAsync(&meta, &fence));
// Destroy the consumer who has acquired but not released the buffer.
c1 = nullptr;
// The buffer is now available for the producer to gain.
- EXPECT_LT(0, RETRY_EINTR(p->Poll(kPollTimeoutMs)));
+ EXPECT_LT(0, RETRY_EINTR(PollBufferEvent(p)));
// Newly added consumer is not able to acquire the buffer.
std::unique_ptr<ConsumerBuffer> c2 =
@@ -742,7 +735,7 @@
ASSERT_TRUE(c2.get() != nullptr);
const uint32_t client_state_mask2 = c2->client_state_mask();
EXPECT_NE(client_state_mask1, client_state_mask2);
- EXPECT_EQ(0, RETRY_EINTR(c2->Poll(kPollTimeoutMs)));
+ EXPECT_EQ(0, RETRY_EINTR(PollBufferEvent(c2)));
EXPECT_EQ(-EBUSY, c2->AcquireAsync(&meta, &fence));
// Producer should be able to gain.
@@ -761,7 +754,7 @@
EXPECT_EQ(0, p->GainAsync());
DvrNativeBufferMetadata meta;
EXPECT_EQ(0, p->PostAsync(&meta, LocalHandle()));
- EXPECT_LT(0, RETRY_EINTR(c1->Poll(kPollTimeoutMs)));
+ EXPECT_LT(0, RETRY_EINTR(PollBufferEvent(c1)));
// c2 is created when the buffer is in posted state. buffer state for c1 is
// posted. Thus, c2 should be automatically set to posted and able to acquire.
@@ -770,7 +763,7 @@
ASSERT_TRUE(c2.get() != nullptr);
const uint32_t client_state_mask2 = c2->client_state_mask();
EXPECT_NE(client_state_mask1, client_state_mask2);
- EXPECT_LT(0, RETRY_EINTR(c2->Poll(kPollTimeoutMs)));
+ EXPECT_LT(0, RETRY_EINTR(PollBufferEvent(c2)));
LocalHandle invalid_fence;
EXPECT_EQ(0, c2->AcquireAsync(&meta, &invalid_fence));
@@ -785,7 +778,7 @@
const uint32_t client_state_mask3 = c3->client_state_mask();
EXPECT_NE(client_state_mask1, client_state_mask3);
EXPECT_NE(client_state_mask2, client_state_mask3);
- EXPECT_LT(0, RETRY_EINTR(c3->Poll(kPollTimeoutMs)));
+ EXPECT_LT(0, RETRY_EINTR(PollBufferEvent(c3)));
EXPECT_EQ(0, c3->AcquireAsync(&meta, &invalid_fence));
// Releasing c2 and c3 in normal ways.
@@ -796,7 +789,7 @@
c1 = nullptr;
// The buffer is now available for the producer to gain.
- EXPECT_LT(0, RETRY_EINTR(p->Poll(kPollTimeoutMs)));
+ EXPECT_LT(0, RETRY_EINTR(PollBufferEvent(p)));
// C4 is created in released state. Thus, it cannot gain the just posted
// buffer.
@@ -805,7 +798,7 @@
ASSERT_TRUE(c4.get() != nullptr);
const uint32_t client_state_mask4 = c4->client_state_mask();
EXPECT_NE(client_state_mask3, client_state_mask4);
- EXPECT_GE(0, RETRY_EINTR(c3->Poll(kPollTimeoutMs)));
+ EXPECT_GE(0, RETRY_EINTR(PollBufferEvent(c3)));
EXPECT_EQ(-EBUSY, c3->AcquireAsync(&meta, &invalid_fence));
// Producer should be able to gain.
@@ -816,7 +809,7 @@
// TODO(b/112338294) rewrite test after migration
return;
- std::unique_ptr<ProducerBuffer> p = ProducerBuffer::Create(
+ /* std::unique_ptr<ProducerBuffer> p = ProducerBuffer::Create(
kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t));
std::unique_ptr<ConsumerBuffer> c =
ConsumerBuffer::Import(p->CreateConsumer());
@@ -830,7 +823,7 @@
// Detach in posted state should fail.
EXPECT_EQ(0, p->GainAsync());
EXPECT_EQ(0, p->PostAsync(&metadata, invalid_fence));
- EXPECT_GT(RETRY_EINTR(c->Poll(kPollTimeoutMs)), 0);
+ EXPECT_GT(RETRY_EINTR(PollBufferEvent(c)), 0);
auto s1 = p->Detach();
EXPECT_FALSE(s1);
@@ -841,7 +834,7 @@
// Detach in released state should fail.
EXPECT_EQ(0, c->ReleaseAsync(&metadata, invalid_fence));
- EXPECT_GT(RETRY_EINTR(p->Poll(kPollTimeoutMs)), 0);
+ EXPECT_GT(RETRY_EINTR(PollBufferEvent(p)), 0);
s1 = p->Detach();
EXPECT_FALSE(s1);
@@ -854,12 +847,12 @@
EXPECT_TRUE(handle.valid());
// Both producer and consumer should have hangup.
- EXPECT_GT(RETRY_EINTR(p->Poll(kPollTimeoutMs)), 0);
+ EXPECT_GT(RETRY_EINTR(PollBufferEvent(p)), 0);
auto s2 = p->GetEventMask(POLLHUP);
EXPECT_TRUE(s2);
EXPECT_EQ(s2.get(), POLLHUP);
- EXPECT_GT(RETRY_EINTR(c->Poll(kPollTimeoutMs)), 0);
+ EXPECT_GT(RETRY_EINTR(PollBufferEvent(c)), 0);
s2 = p->GetEventMask(POLLHUP);
EXPECT_TRUE(s2);
EXPECT_EQ(s2.get(), POLLHUP);
@@ -884,49 +877,14 @@
EXPECT_TRUE(d->IsConnected());
EXPECT_TRUE(d->IsValid());
- EXPECT_EQ(d->id(), p_id);
-}
-
-TEST_F(LibBufferHubTest, TestCreateBufferHubBufferFails) {
- // Buffer Creation will fail: BLOB format requires height to be 1.
- auto b1 = BufferHubBuffer::Create(kWidth, /*height=2*/ 2, kLayerCount,
- /*format=*/HAL_PIXEL_FORMAT_BLOB, kUsage,
- kUserMetadataSize);
-
- EXPECT_FALSE(b1->IsConnected());
- EXPECT_FALSE(b1->IsValid());
-
- // Buffer Creation will fail: user metadata size too large.
- auto b2 = BufferHubBuffer::Create(
- kWidth, kHeight, kLayerCount, kFormat, kUsage,
- /*user_metadata_size=*/std::numeric_limits<size_t>::max());
-
- EXPECT_FALSE(b2->IsConnected());
- EXPECT_FALSE(b2->IsValid());
-
- // Buffer Creation will fail: user metadata size too large.
- auto b3 = BufferHubBuffer::Create(
- kWidth, kHeight, kLayerCount, kFormat, kUsage,
- /*user_metadata_size=*/std::numeric_limits<size_t>::max() -
- kMetadataHeaderSize);
-
- EXPECT_FALSE(b3->IsConnected());
- EXPECT_FALSE(b3->IsValid());
-}
-
-TEST_F(LibBufferHubTest, TestCreateBufferHubBuffer) {
- auto b1 = BufferHubBuffer::Create(kWidth, kHeight, kLayerCount, kFormat,
- kUsage, kUserMetadataSize);
- EXPECT_TRUE(b1->IsConnected());
- EXPECT_TRUE(b1->IsValid());
- EXPECT_NE(b1->id(), 0);
+ EXPECT_EQ(d->id(), p_id); */
}
TEST_F(LibBufferHubTest, TestDetach) {
// TODO(b/112338294) rewrite test after migration
return;
- std::unique_ptr<ProducerBuffer> p1 = ProducerBuffer::Create(
+ /* std::unique_ptr<ProducerBuffer> p1 = ProducerBuffer::Create(
kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t));
ASSERT_TRUE(p1.get() != nullptr);
int p1_id = p1->id();
@@ -944,47 +902,5 @@
EXPECT_FALSE(h1.valid());
EXPECT_TRUE(b1->IsValid());
int b1_id = b1->id();
- EXPECT_EQ(b1_id, p1_id);
-}
-
-TEST_F(LibBufferHubTest, TestDuplicateBufferHubBuffer) {
- auto b1 = BufferHubBuffer::Create(kWidth, kHeight, kLayerCount, kFormat,
- kUsage, kUserMetadataSize);
- int b1_id = b1->id();
- EXPECT_TRUE(b1->IsValid());
- EXPECT_EQ(b1->user_metadata_size(), kUserMetadataSize);
- EXPECT_NE(b1->client_state_mask(), 0U);
-
- auto status_or_handle = b1->Duplicate();
- EXPECT_TRUE(status_or_handle);
-
- // The detached buffer should still be valid.
- EXPECT_TRUE(b1->IsConnected());
- EXPECT_TRUE(b1->IsValid());
-
- // Gets the channel handle for the duplicated buffer.
- LocalChannelHandle h2 = status_or_handle.take();
- EXPECT_TRUE(h2.valid());
-
- std::unique_ptr<BufferHubBuffer> b2 = BufferHubBuffer::Import(std::move(h2));
- EXPECT_FALSE(h2.valid());
- ASSERT_TRUE(b2 != nullptr);
- EXPECT_TRUE(b2->IsValid());
- EXPECT_EQ(b2->user_metadata_size(), kUserMetadataSize);
- EXPECT_NE(b2->client_state_mask(), 0U);
-
- int b2_id = b2->id();
-
- // These two buffer instances are based on the same physical buffer under the
- // hood, so they should share the same id.
- EXPECT_EQ(b1_id, b2_id);
- // We use client_state_mask() to tell those two instances apart.
- EXPECT_NE(b1->client_state_mask(), b2->client_state_mask());
-
- // Both buffer instances should be in gained state.
- EXPECT_TRUE(IsBufferReleased(b1->buffer_state()));
- EXPECT_TRUE(IsBufferReleased(b2->buffer_state()));
-
- // TODO(b/112338294) rewrite test after migration
- return;
+ EXPECT_EQ(b1_id, p1_id); */
}
diff --git a/libs/vr/libbufferhub/buffer_hub_base.cpp b/libs/vr/libbufferhub/buffer_hub_base.cpp
index 8497f3e..b28d101 100644
--- a/libs/vr/libbufferhub/buffer_hub_base.cpp
+++ b/libs/vr/libbufferhub/buffer_hub_base.cpp
@@ -196,12 +196,6 @@
return 0;
}
-int BufferHubBase::Poll(int timeout_ms) {
- ATRACE_NAME("BufferHubBase::Poll");
- pollfd p = {event_fd(), POLLIN, 0};
- return poll(&p, 1, timeout_ms);
-}
-
int BufferHubBase::Lock(int usage, int x, int y, int width, int height,
void** address) {
return buffer_.Lock(usage, x, y, width, height, address);
@@ -218,12 +212,5 @@
return ret;
}
-void BufferHubBase::GetBlobFds(int* fds, size_t* fds_count,
- size_t max_fds_count) const {
- size_t numFds = static_cast<size_t>(native_handle()->numFds);
- *fds_count = std::min(max_fds_count, numFds);
- std::copy(native_handle()->data, native_handle()->data + *fds_count, fds);
-}
-
} // namespace dvr
} // namespace android
diff --git a/libs/vr/libbufferhub/include/private/dvr/buffer_hub_base.h b/libs/vr/libbufferhub/include/private/dvr/buffer_hub_base.h
index 440a59d..fa39d08 100644
--- a/libs/vr/libbufferhub/include/private/dvr/buffer_hub_base.h
+++ b/libs/vr/libbufferhub/include/private/dvr/buffer_hub_base.h
@@ -21,19 +21,6 @@
// a file descriptor for the new channel or a negative error code.
Status<LocalChannelHandle> CreateConsumer();
- // Polls the fd for |timeout_ms| milliseconds (-1 for infinity).
- int Poll(int timeout_ms);
-
- // Locks the area specified by (x, y, width, height) for a specific usage. If
- // the usage is software then |addr| will be updated to point to the address
- // of the buffer in virtual memory. The caller should only access/modify the
- // pixels in the specified area. anything else is undefined behavior.
- int Lock(int usage, int x, int y, int width, int height, void** addr);
-
- // Must be called after Lock() when the caller has finished changing the
- // buffer.
- int Unlock();
-
// Gets a blob buffer that was created with ProducerBuffer::CreateBlob.
// Locking and Unlocking is handled internally. There's no need to Unlock
// after calling this method.
@@ -52,10 +39,6 @@
return LocalHandle(dup(native_handle()->data[0]));
}
- // Get up to |max_fds_count| file descriptors for accessing the blob shared
- // memory. |fds_count| will contain the actual number of file descriptors.
- void GetBlobFds(int* fds, size_t* fds_count, size_t max_fds_count) const;
-
using Client::event_fd;
Status<int> GetEventMask(int events) {
@@ -94,6 +77,12 @@
return buffer_state_->load(std::memory_order_acquire);
};
+ // Returns whether the buffer is already released by all current clients.
+ bool is_released() {
+ return (buffer_state() &
+ active_clients_bit_mask_->load(std::memory_order_acquire)) == 0;
+ }
+
// A state mask which is unique to a buffer hub client among all its siblings
// sharing the same concrete graphic buffer.
uint32_t client_state_mask() const { return client_state_mask_; }
@@ -129,6 +118,16 @@
int UpdateSharedFence(const LocalHandle& new_fence,
const LocalHandle& shared_fence);
+ // Locks the area specified by (x, y, width, height) for a specific usage. If
+ // the usage is software then |addr| will be updated to point to the address
+ // of the buffer in virtual memory. The caller should only access/modify the
+ // pixels in the specified area. anything else is undefined behavior.
+ int Lock(int usage, int x, int y, int width, int height, void** addr);
+
+ // Must be called after Lock() when the caller has finished changing the
+ // buffer.
+ int Unlock();
+
// IonBuffer that is shared between bufferhubd, producer, and consumers.
size_t metadata_buf_size_{0};
size_t user_metadata_size_{0};
diff --git a/libs/vr/libbufferhub/include/private/dvr/buffer_hub_defs.h b/libs/vr/libbufferhub/include/private/dvr/buffer_hub_defs.h
index f2c40fe..bab7367 100644
--- a/libs/vr/libbufferhub/include/private/dvr/buffer_hub_defs.h
+++ b/libs/vr/libbufferhub/include/private/dvr/buffer_hub_defs.h
@@ -51,10 +51,6 @@
return android::BufferHubDefs::IsClientAcquired(state, client_bit_mask);
}
-static inline bool IsBufferReleased(uint32_t state) {
- return android::BufferHubDefs::IsBufferReleased(state);
-}
-
static inline bool IsClientReleased(uint32_t state, uint32_t client_bit_mask) {
return android::BufferHubDefs::IsClientReleased(state, client_bit_mask);
}
@@ -162,39 +158,6 @@
void operator=(const BufferTraits&) = delete;
};
-struct DetachedBufferRPC {
- private:
- enum {
- kOpDetachedBufferBase = 1000,
-
- // Allocates a standalone DetachedBuffer not associated with any producer
- // consumer set.
- kOpCreate,
-
- // Imports the given channel handle to a DetachedBuffer, taking ownership.
- kOpImport,
-
- // Creates a DetachedBuffer client from an existing one. The new client will
- // share the same underlying gralloc buffer and ashmem region for metadata.
- kOpDuplicate,
- };
-
- // Aliases.
- using LocalChannelHandle = pdx::LocalChannelHandle;
- using LocalHandle = pdx::LocalHandle;
- using Void = pdx::rpc::Void;
-
- public:
- PDX_REMOTE_METHOD(Create, kOpCreate,
- void(uint32_t width, uint32_t height, uint32_t layer_count,
- uint32_t format, uint64_t usage,
- size_t user_metadata_size));
- PDX_REMOTE_METHOD(Import, kOpImport, BufferTraits<LocalHandle>(Void));
- PDX_REMOTE_METHOD(Duplicate, kOpDuplicate, LocalChannelHandle(Void));
-
- PDX_REMOTE_API(API, Create, Import, Duplicate);
-};
-
} // namespace dvr
} // namespace android
diff --git a/libs/vr/libbufferhub/producer_buffer.cpp b/libs/vr/libbufferhub/producer_buffer.cpp
index 5274bf2..edfdddf 100644
--- a/libs/vr/libbufferhub/producer_buffer.cpp
+++ b/libs/vr/libbufferhub/producer_buffer.cpp
@@ -89,13 +89,10 @@
return -EBUSY;
}
- // Set the producer client buffer state to released, other clients' buffer
- // state to posted.
- uint32_t current_active_clients_bit_mask =
- active_clients_bit_mask_->load(std::memory_order_acquire);
- uint32_t updated_buffer_state = current_active_clients_bit_mask &
- (~client_state_mask()) &
- BufferHubDefs::kHighBitsMask;
+ // Set the producer client buffer state to released, that of all other clients
+ // (both existing and non-existing clients) to posted.
+ uint32_t updated_buffer_state =
+ (~client_state_mask()) & BufferHubDefs::kHighBitsMask;
while (!buffer_state_->compare_exchange_weak(
current_buffer_state, updated_buffer_state, std::memory_order_acq_rel,
std::memory_order_acquire)) {
@@ -176,7 +173,9 @@
}
if (BufferHubDefs::AnyClientAcquired(current_buffer_state) ||
BufferHubDefs::AnyClientGained(current_buffer_state) ||
- (BufferHubDefs::AnyClientPosted(current_buffer_state) &&
+ (BufferHubDefs::AnyClientPosted(
+ current_buffer_state &
+ active_clients_bit_mask_->load(std::memory_order_acquire)) &&
!gain_posted_buffer)) {
ALOGE("%s: not released id=%d state=%" PRIx32 ".", __FUNCTION__, id(),
current_buffer_state);
@@ -198,7 +197,9 @@
if (BufferHubDefs::AnyClientAcquired(current_buffer_state) ||
BufferHubDefs::AnyClientGained(current_buffer_state) ||
- (BufferHubDefs::AnyClientPosted(current_buffer_state) &&
+ (BufferHubDefs::AnyClientPosted(
+ current_buffer_state &
+ active_clients_bit_mask_->load(std::memory_order_acquire)) &&
!gain_posted_buffer)) {
ALOGE(
"%s: Failed to gain the buffer. The buffer is no longer released. "
diff --git a/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h b/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h
index d1f0564..74b4b3d 100644
--- a/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h
+++ b/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h
@@ -131,8 +131,8 @@
bool hung_up() const { return hung_up_; }
protected:
- BufferHubQueue(pdx::LocalChannelHandle channel);
- BufferHubQueue(const std::string& endpoint_path);
+ explicit BufferHubQueue(pdx::LocalChannelHandle channel);
+ explicit BufferHubQueue(const std::string& endpoint_path);
// Imports the queue parameters by querying BufferHub for the parameters for
// this channel.
@@ -458,7 +458,7 @@
private:
friend BufferHubQueue;
- ConsumerQueue(pdx::LocalChannelHandle handle);
+ explicit ConsumerQueue(pdx::LocalChannelHandle handle);
// Add a consumer buffer to populate the queue. Once added, a consumer buffer
// is NOT available to use until the producer side |Post| it. |WaitForBuffers|
diff --git a/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_parcelable.h b/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_parcelable.h
index ad3f56b..36ab5f6 100644
--- a/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_parcelable.h
+++ b/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_parcelable.h
@@ -35,7 +35,7 @@
}
// Constructs an parcelable contains the channel parcelable.
- BufferHubQueueParcelable(
+ explicit BufferHubQueueParcelable(
std::unique_ptr<pdx::ChannelParcelable> channel_parcelable)
: channel_parcelable_(std::move(channel_parcelable)) {}
diff --git a/libs/vr/libdisplay/include/private/dvr/display_protocol.h b/libs/vr/libdisplay/include/private/dvr/display_protocol.h
index eff50ba..3786d1d 100644
--- a/libs/vr/libdisplay/include/private/dvr/display_protocol.h
+++ b/libs/vr/libdisplay/include/private/dvr/display_protocol.h
@@ -60,11 +60,13 @@
using Base = Flags<Integer>;
using Type = Integer;
+ // NOLINTNEXTLINE(google-explicit-constructor)
Flags(const Integer& value) : value_{value} {}
Flags(const Flags&) = default;
Flags& operator=(const Flags&) = default;
Integer value() const { return value_; }
+ // NOLINTNEXTLINE(google-explicit-constructor)
operator Integer() const { return value_; }
bool IsSet(Integer bits) const { return (value_ & bits) == bits; }
diff --git a/libs/vr/libpdx/private/pdx/channel_handle.h b/libs/vr/libpdx/private/pdx/channel_handle.h
index daa08f4..bd04305 100644
--- a/libs/vr/libpdx/private/pdx/channel_handle.h
+++ b/libs/vr/libpdx/private/pdx/channel_handle.h
@@ -26,7 +26,7 @@
class ChannelHandleBase {
public:
ChannelHandleBase() = default;
- ChannelHandleBase(const int32_t& value) : value_{value} {}
+ explicit ChannelHandleBase(const int32_t& value) : value_{value} {}
ChannelHandleBase(const ChannelHandleBase&) = delete;
ChannelHandleBase& operator=(const ChannelHandleBase&) = delete;
diff --git a/libs/vr/libpdx/private/pdx/client.h b/libs/vr/libpdx/private/pdx/client.h
index c35dabd..7e2d55c 100644
--- a/libs/vr/libpdx/private/pdx/client.h
+++ b/libs/vr/libpdx/private/pdx/client.h
@@ -206,7 +206,7 @@
class Transaction final : public OutputResourceMapper,
public InputResourceMapper {
public:
- Transaction(Client& client);
+ explicit Transaction(Client& client);
~Transaction();
template <typename T>
diff --git a/libs/vr/libpdx/private/pdx/rpc/buffer_wrapper.h b/libs/vr/libpdx/private/pdx/rpc/buffer_wrapper.h
index 0421220..43184dd 100644
--- a/libs/vr/libpdx/private/pdx/rpc/buffer_wrapper.h
+++ b/libs/vr/libpdx/private/pdx/rpc/buffer_wrapper.h
@@ -110,10 +110,10 @@
using const_iterator = typename BufferType::const_iterator;
BufferWrapper() {}
- BufferWrapper(const BufferType& buffer) : buffer_(buffer) {}
+ explicit BufferWrapper(const BufferType& buffer) : buffer_(buffer) {}
BufferWrapper(const BufferType& buffer, const Allocator& allocator)
: buffer_(buffer, allocator) {}
- BufferWrapper(BufferType&& buffer) : buffer_(std::move(buffer)) {}
+ explicit BufferWrapper(BufferType&& buffer) : buffer_(std::move(buffer)) {}
BufferWrapper(BufferType&& buffer, const Allocator& allocator)
: buffer_(std::move(buffer), allocator) {}
BufferWrapper(const BufferWrapper&) = default;
diff --git a/libs/vr/libpdx/private/pdx/rpc/payload.h b/libs/vr/libpdx/private/pdx/rpc/payload.h
index a48a64c..d2df14f 100644
--- a/libs/vr/libpdx/private/pdx/rpc/payload.h
+++ b/libs/vr/libpdx/private/pdx/rpc/payload.h
@@ -83,7 +83,7 @@
public MessageWriter,
public MessageReader {
public:
- ServicePayload(Message& message) : message_(message) {}
+ explicit ServicePayload(Message& message) : message_(message) {}
// MessageWriter
void* GetNextWriteBufferSection(size_t size) override {
@@ -120,7 +120,8 @@
MessageBuffer<ThreadLocalTypeSlot<ClientPayload<Slot>>, 1024u, int>;
using BufferType = typename ContainerType::BufferType;
- ClientPayload(Transaction& transaction) : transaction_{transaction} {}
+ explicit ClientPayload(Transaction& transaction)
+ : transaction_{transaction} {}
// MessageWriter
void* GetNextWriteBufferSection(size_t size) override {
diff --git a/libs/vr/libpdx/private/pdx/rpc/pointer_wrapper.h b/libs/vr/libpdx/private/pdx/rpc/pointer_wrapper.h
index 1cb85de..88868fe 100644
--- a/libs/vr/libpdx/private/pdx/rpc/pointer_wrapper.h
+++ b/libs/vr/libpdx/private/pdx/rpc/pointer_wrapper.h
@@ -13,7 +13,7 @@
public:
using BaseType = T;
- PointerWrapper(T* pointer) : pointer_(pointer) {}
+ explicit PointerWrapper(T* pointer) : pointer_(pointer) {}
PointerWrapper(const PointerWrapper&) = default;
PointerWrapper(PointerWrapper&&) noexcept = default;
PointerWrapper& operator=(const PointerWrapper&) = default;
diff --git a/libs/vr/libpdx/private/pdx/rpc/serialization.h b/libs/vr/libpdx/private/pdx/rpc/serialization.h
index f12aef1..914ea66 100644
--- a/libs/vr/libpdx/private/pdx/rpc/serialization.h
+++ b/libs/vr/libpdx/private/pdx/rpc/serialization.h
@@ -134,7 +134,7 @@
// ErrorType constructor for generic error codes. Explicitly not explicit,
// implicit conversion from ErrorCode to ErrorType is desirable behavior.
- // NOLINTNEXTLINE(runtime/explicit)
+ // NOLINTNEXTLINE(google-explicit-constructor)
ErrorType(ErrorCode error_code) : error_code_(error_code) {}
// ErrorType constructor for encoding type errors.
@@ -148,6 +148,7 @@
// Evaluates to true if the ErrorType represents an error.
explicit operator bool() const { return error_code_ != ErrorCode::NO_ERROR; }
+ // NOLINTNEXTLINE(google-explicit-constructor)
operator ErrorCode() const { return error_code_; }
ErrorCode error_code() const { return error_code_; }
@@ -159,6 +160,7 @@
return unexpected_encoding_.encoding_type;
}
+ // NOLINTNEXTLINE(google-explicit-constructor)
operator std::string() const {
std::ostringstream stream;
diff --git a/libs/vr/libpdx/private/pdx/service.h b/libs/vr/libpdx/private/pdx/service.h
index d38b174..f5a2d5e 100644
--- a/libs/vr/libpdx/private/pdx/service.h
+++ b/libs/vr/libpdx/private/pdx/service.h
@@ -95,7 +95,7 @@
class Message : public OutputResourceMapper, public InputResourceMapper {
public:
Message();
- Message(const MessageInfo& info);
+ explicit Message(const MessageInfo& info);
~Message();
/*
diff --git a/libs/vr/libpdx/private/pdx/status.h b/libs/vr/libpdx/private/pdx/status.h
index 7e51a52..498dd6d 100644
--- a/libs/vr/libpdx/private/pdx/status.h
+++ b/libs/vr/libpdx/private/pdx/status.h
@@ -11,6 +11,7 @@
// This is a helper class for constructing Status<T> with an error code.
struct ErrorStatus {
public:
+ // NOLINTNEXTLINE(google-explicit-constructor)
ErrorStatus(int error) : error_{error} {}
int error() const { return error_; }
@@ -31,12 +32,14 @@
// Value copy/move constructors. These are intentionally not marked as
// explicit to allow direct value returns from functions without having
// to explicitly wrap them into Status<T>().
- Status(const T& value) : value_{value} {} // NOLINT(runtime/explicit)
- Status(T&& value) : value_{std::move(value)} {} // NOLINT(runtime/explicit)
+ // NOLINTNEXTLINE(google-explicit-constructor)
+ Status(const T& value) : value_{value} {}
+ // NOLINTNEXTLINE(google-explicit-constructor)
+ Status(T&& value) : value_{std::move(value)} {}
// Constructor for storing an error code inside the Status object.
- Status(const ErrorStatus& error_status) // NOLINT(runtime/explicit)
- : error_{error_status.error()} {}
+ // NOLINTNEXTLINE(google-explicit-constructor)
+ Status(const ErrorStatus& error_status) : error_{error_status.error()} {}
// Copy/move constructors. Move constructor leaves |other| object in empty
// state.
@@ -135,8 +138,8 @@
class Status<void> {
public:
Status() = default;
- Status(const ErrorStatus& error_status) // NOLINT(runtime/explicit)
- : error_{error_status.error()} {}
+ // NOLINTNEXTLINE(google-explicit-constructor)
+ Status(const ErrorStatus& error_status) : error_{error_status.error()} {}
void SetValue() { error_ = 0; }
void SetError(int error) { error_ = error; }
diff --git a/libs/vr/libpdx/serialization_tests.cpp b/libs/vr/libpdx/serialization_tests.cpp
index 5ad1047..ee800f6 100644
--- a/libs/vr/libpdx/serialization_tests.cpp
+++ b/libs/vr/libpdx/serialization_tests.cpp
@@ -70,7 +70,7 @@
FileHandleType fd;
TestTemplateType() {}
- TestTemplateType(FileHandleType fd) : fd(std::move(fd)) {}
+ explicit TestTemplateType(FileHandleType fd) : fd(std::move(fd)) {}
bool operator==(const TestTemplateType& other) const {
return fd.Get() == other.fd.Get();
diff --git a/libs/vr/libpdx/variant_tests.cpp b/libs/vr/libpdx/variant_tests.cpp
index e3520f5..a977fd3 100644
--- a/libs/vr/libpdx/variant_tests.cpp
+++ b/libs/vr/libpdx/variant_tests.cpp
@@ -14,18 +14,22 @@
namespace {
struct BaseType {
+ // NOLINTNEXTLINE(google-explicit-constructor)
BaseType(int value) : value(value) {}
int value;
};
struct DerivedType : BaseType {
+ // NOLINTNEXTLINE(google-explicit-constructor)
DerivedType(int value) : BaseType{value} {};
};
template <typename T>
class TestType {
public:
+ // NOLINTNEXTLINE(google-explicit-constructor)
TestType(const T& value) : value_(value) {}
+ // NOLINTNEXTLINE(google-explicit-constructor)
TestType(T&& value) : value_(std::move(value)) {}
TestType(const TestType&) = default;
TestType(TestType&&) = default;
@@ -43,7 +47,9 @@
template <typename T>
class InstrumentType {
public:
+ // NOLINTNEXTLINE(google-explicit-constructor)
InstrumentType(const T& value) : value_(value) { constructor_count_++; }
+ // NOLINTNEXTLINE(google-explicit-constructor)
InstrumentType(T&& value) : value_(std::move(value)) { constructor_count_++; }
InstrumentType(const InstrumentType& other) : value_(other.value_) {
constructor_count_++;
@@ -51,9 +57,11 @@
InstrumentType(InstrumentType&& other) : value_(std::move(other.value_)) {
constructor_count_++;
}
+ // NOLINTNEXTLINE(google-explicit-constructor)
InstrumentType(const TestType<T>& other) : value_(other.get()) {
constructor_count_++;
}
+ // NOLINTNEXTLINE(google-explicit-constructor)
InstrumentType(TestType<T>&& other) : value_(other.take()) {
constructor_count_++;
}
@@ -1101,6 +1109,7 @@
TEST(Variant, IsConstructible) {
using ArrayType = const float[3];
struct ImplicitBool {
+ // NOLINTNEXTLINE(google-explicit-constructor)
operator bool() const { return true; }
};
struct ExplicitBool {
diff --git a/libs/vr/libpdx_default_transport/pdx_benchmarks.cpp b/libs/vr/libpdx_default_transport/pdx_benchmarks.cpp
index f72dabc..5c9e74c 100644
--- a/libs/vr/libpdx_default_transport/pdx_benchmarks.cpp
+++ b/libs/vr/libpdx_default_transport/pdx_benchmarks.cpp
@@ -82,7 +82,7 @@
class SchedStats {
public:
SchedStats() : SchedStats(gettid()) {}
- SchedStats(pid_t task_id) : task_id_(task_id) {}
+ explicit SchedStats(pid_t task_id) : task_id_(task_id) {}
SchedStats(const SchedStats&) = default;
SchedStats& operator=(const SchedStats&) = default;
@@ -379,7 +379,7 @@
private:
friend BASE;
- BenchmarkService(std::unique_ptr<Endpoint> endpoint)
+ explicit BenchmarkService(std::unique_ptr<Endpoint> endpoint)
: BASE("BenchmarkService", std::move(endpoint)),
send_buffer(kMaxMessageSize),
receive_buffer(kMaxMessageSize) {}
@@ -492,7 +492,7 @@
private:
friend BASE;
- BenchmarkClient(const std::string& service_path)
+ explicit BenchmarkClient(const std::string& service_path)
: BASE(ClientChannelFactory::Create(service_path),
ProgramOptions.timeout) {}
diff --git a/libs/vr/libpdx_default_transport/private/pdx/default_transport/service_utility.h b/libs/vr/libpdx_default_transport/private/pdx/default_transport/service_utility.h
index 81bb17b..3ebab86 100644
--- a/libs/vr/libpdx_default_transport/private/pdx/default_transport/service_utility.h
+++ b/libs/vr/libpdx_default_transport/private/pdx/default_transport/service_utility.h
@@ -41,7 +41,8 @@
private:
friend BASE;
- ServiceUtility(const std::string& endpoint_path, int* error = nullptr)
+ explicit ServiceUtility(const std::string& endpoint_path,
+ int* error = nullptr)
: BASE(ClientChannelFactory::Create(endpoint_path), 0) {
if (error)
*error = Client::error();
diff --git a/libs/vr/libpdx_uds/client_channel_tests.cpp b/libs/vr/libpdx_uds/client_channel_tests.cpp
index 1560030..c9c5d15 100644
--- a/libs/vr/libpdx_uds/client_channel_tests.cpp
+++ b/libs/vr/libpdx_uds/client_channel_tests.cpp
@@ -45,7 +45,7 @@
class TestService : public ServiceBase<TestService> {
public:
- TestService(std::unique_ptr<Endpoint> endpoint)
+ explicit TestService(std::unique_ptr<Endpoint> endpoint)
: ServiceBase{"TestService", std::move(endpoint)} {}
Status<void> HandleMessage(Message& message) override {
@@ -78,7 +78,7 @@
class TestServiceRunner {
public:
- TestServiceRunner(LocalHandle channel_socket) {
+ explicit TestServiceRunner(LocalHandle channel_socket) {
auto endpoint = Endpoint::CreateFromSocketFd(LocalHandle{});
endpoint->RegisterNewChannelForTests(std::move(channel_socket));
service_ = TestService::Create(std::move(endpoint));
diff --git a/libs/vr/libpdx_uds/private/uds/ipc_helper.h b/libs/vr/libpdx_uds/private/uds/ipc_helper.h
index 63b5b10..704a569 100644
--- a/libs/vr/libpdx_uds/private/uds/ipc_helper.h
+++ b/libs/vr/libpdx_uds/private/uds/ipc_helper.h
@@ -57,7 +57,7 @@
class SendPayload : public MessageWriter, public OutputResourceMapper {
public:
- SendPayload(SendInterface* sender = nullptr) : sender_{sender} {}
+ explicit SendPayload(SendInterface* sender = nullptr) : sender_{sender} {}
Status<void> Send(const BorrowedHandle& socket_fd);
Status<void> Send(const BorrowedHandle& socket_fd, const ucred* cred,
const iovec* data_vec = nullptr, size_t vec_count = 0);
@@ -85,7 +85,8 @@
class ReceivePayload : public MessageReader, public InputResourceMapper {
public:
- ReceivePayload(RecvInterface* receiver = nullptr) : receiver_{receiver} {}
+ explicit ReceivePayload(RecvInterface* receiver = nullptr)
+ : receiver_{receiver} {}
Status<void> Receive(const BorrowedHandle& socket_fd);
Status<void> Receive(const BorrowedHandle& socket_fd, ucred* cred);
diff --git a/libs/vr/libpdx_uds/private/uds/service_endpoint.h b/libs/vr/libpdx_uds/private/uds/service_endpoint.h
index 01ebf65..50fc484 100644
--- a/libs/vr/libpdx_uds/private/uds/service_endpoint.h
+++ b/libs/vr/libpdx_uds/private/uds/service_endpoint.h
@@ -117,7 +117,7 @@
// This class must be instantiated using Create() static methods above.
Endpoint(const std::string& endpoint_path, bool blocking,
bool use_init_socket_fd = true);
- Endpoint(LocalHandle socket_fd);
+ explicit Endpoint(LocalHandle socket_fd);
void Init(LocalHandle socket_fd);
diff --git a/libs/vr/libpdx_uds/remote_method_tests.cpp b/libs/vr/libpdx_uds/remote_method_tests.cpp
index 3f25776..4f0670e 100644
--- a/libs/vr/libpdx_uds/remote_method_tests.cpp
+++ b/libs/vr/libpdx_uds/remote_method_tests.cpp
@@ -94,7 +94,7 @@
FileHandleType fd;
TestTemplateType() {}
- TestTemplateType(FileHandleType fd) : fd(std::move(fd)) {}
+ explicit TestTemplateType(FileHandleType fd) : fd(std::move(fd)) {}
private:
PDX_SERIALIZABLE_MEMBERS(TestTemplateType<FileHandleType>, fd);
@@ -328,7 +328,7 @@
private:
friend BASE;
- TestClient(LocalChannelHandle channel_handle)
+ explicit TestClient(LocalChannelHandle channel_handle)
: BASE{android::pdx::uds::ClientChannel::Create(
std::move(channel_handle))} {}
TestClient()
diff --git a/libs/vr/libvrflinger/Android.bp b/libs/vr/libvrflinger/Android.bp
index 4f8bdbf..2829353 100644
--- a/libs/vr/libvrflinger/Android.bp
+++ b/libs/vr/libvrflinger/Android.bp
@@ -47,6 +47,7 @@
"liblog",
"libhardware",
"libnativewindow",
+ "libprocessgroup",
"libutils",
"libEGL",
"libGLESv1_CM",
diff --git a/libs/vr/libvrflinger/hardware_composer.cpp b/libs/vr/libvrflinger/hardware_composer.cpp
index 6d259bd..e1240d6 100644
--- a/libs/vr/libvrflinger/hardware_composer.cpp
+++ b/libs/vr/libvrflinger/hardware_composer.cpp
@@ -104,7 +104,7 @@
class TraceArgs {
public:
template <typename... Args>
- TraceArgs(const char* format, Args&&... args) {
+ explicit TraceArgs(const char* format, Args&&... args) {
std::array<char, 1024> buffer;
snprintf(buffer.data(), buffer.size(), format, std::forward<Args>(args)...);
atrace_begin(ATRACE_TAG, buffer.data());
diff --git a/libs/vr/libvrflinger/hardware_composer.h b/libs/vr/libvrflinger/hardware_composer.h
index 6c25b3e..db0d6a7 100644
--- a/libs/vr/libvrflinger/hardware_composer.h
+++ b/libs/vr/libvrflinger/hardware_composer.h
@@ -195,7 +195,7 @@
AcquiredBuffer acquired_buffer;
pdx::LocalHandle release_fence;
- SourceSurface(const std::shared_ptr<DirectDisplaySurface>& surface)
+ explicit SourceSurface(const std::shared_ptr<DirectDisplaySurface>& surface)
: surface(surface) {}
// Attempts to acquire a new buffer from the surface and return a tuple with
diff --git a/libs/vr/libvrflinger/hwc_types.h b/libs/vr/libvrflinger/hwc_types.h
index cbf636c..8b5c3b3 100644
--- a/libs/vr/libvrflinger/hwc_types.h
+++ b/libs/vr/libvrflinger/hwc_types.h
@@ -116,19 +116,24 @@
Wrapper(const Wrapper&) = default;
// Implicit conversion from ValueType.
+ // NOLINTNEXTLINE(google-explicit-constructor)
Wrapper(ValueType value) : value(value) {}
// Implicit conversion from BaseType.
+ // NOLINTNEXTLINE(google-explicit-constructor)
Wrapper(BaseType value) : value(static_cast<ValueType>(value)) {}
// Implicit conversion from an enum type of the same underlying type.
template <typename T, typename = EnableIfMatchingEnum<T, ValueType>>
+ // NOLINTNEXTLINE(google-explicit-constructor)
Wrapper(const T& value) : value(static_cast<ValueType>(value)) {}
// Implicit conversion to BaseType.
+ // NOLINTNEXTLINE(google-explicit-constructor)
operator BaseType() const { return static_cast<BaseType>(value); }
// Implicit conversion to ValueType.
+ // NOLINTNEXTLINE(google-explicit-constructor)
operator ValueType() const { return value; }
template <typename T, typename = EnableIfMatchingEnum<T, ValueType>>
@@ -275,8 +280,10 @@
struct Color final {
Color(const Color&) = default;
Color(uint8_t r, uint8_t g, uint8_t b, uint8_t a) : r(r), g(g), b(b), a(a) {}
+ // NOLINTNEXTLINE(google-explicit-constructor)
Color(hwc_color_t color) : r(color.r), g(color.g), b(color.b), a(color.a) {}
+ // NOLINTNEXTLINE(google-explicit-constructor)
operator hwc_color_t() const { return {r, g, b, a}; }
uint8_t r __attribute__((aligned(1)));
diff --git a/libs/vr/libvrflinger/include/dvr/vr_flinger.h b/libs/vr/libvrflinger/include/dvr/vr_flinger.h
index c740dde..ae52076 100644
--- a/libs/vr/libvrflinger/include/dvr/vr_flinger.h
+++ b/libs/vr/libvrflinger/include/dvr/vr_flinger.h
@@ -49,7 +49,8 @@
// Needs to be a separate class for binder's ref counting
class PersistentVrStateCallback : public BnPersistentVrStateCallbacks {
public:
- PersistentVrStateCallback(RequestDisplayCallback request_display_callback)
+ explicit PersistentVrStateCallback(
+ RequestDisplayCallback request_display_callback)
: request_display_callback_(request_display_callback) {}
void onPersistentVrStateChanged(bool enabled) override;
private:
diff --git a/libs/vr/libvrflinger/tests/vrflinger_test.cpp b/libs/vr/libvrflinger/tests/vrflinger_test.cpp
index 0eb7fec..7075e88 100644
--- a/libs/vr/libvrflinger/tests/vrflinger_test.cpp
+++ b/libs/vr/libvrflinger/tests/vrflinger_test.cpp
@@ -205,9 +205,9 @@
ASSERT_EQ(buffer.get()->height(), metrics.get().display_height);
void* raw_buf = nullptr;
- ASSERT_GE(buffer.get()->Lock(AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN,
- /*x=*/0, /*y=*/0, buffer.get()->width(),
- buffer.get()->height(), &raw_buf),
+ ASSERT_GE(buffer.get()->buffer()->Lock(
+ AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN, /*x=*/0, /*y=*/0,
+ buffer.get()->width(), buffer.get()->height(), &raw_buf),
0);
ASSERT_NE(raw_buf, nullptr);
uint32_t* pixels = static_cast<uint32_t*>(raw_buf);
@@ -216,7 +216,7 @@
pixels[i] = 0x0000ff00;
}
- ASSERT_GE(buffer.get()->Unlock(), 0);
+ ASSERT_GE(buffer.get()->buffer()->Unlock(), 0);
ASSERT_GE(buffer.get()->Post(/*ready_fence=*/pdx::LocalHandle()), 0);
diff --git a/libs/vr/libvrflinger/vr_flinger.cpp b/libs/vr/libvrflinger/vr_flinger.cpp
index b57383a..a8a8476 100644
--- a/libs/vr/libvrflinger/vr_flinger.cpp
+++ b/libs/vr/libvrflinger/vr_flinger.cpp
@@ -12,9 +12,9 @@
#include <binder/IServiceManager.h>
#include <binder/ProcessState.h>
#include <cutils/properties.h>
-#include <cutils/sched_policy.h>
#include <log/log.h>
#include <private/dvr/display_client.h>
+#include <processgroup/sched_policy.h>
#include <sys/prctl.h>
#include <sys/resource.h>
diff --git a/libs/vr/libvrsensor/include/private/dvr/latency_model.h b/libs/vr/libvrsensor/include/private/dvr/latency_model.h
index 40b4638..bf0e687 100644
--- a/libs/vr/libvrsensor/include/private/dvr/latency_model.h
+++ b/libs/vr/libvrsensor/include/private/dvr/latency_model.h
@@ -10,7 +10,7 @@
// window_size measurements and return their average after that.
class LatencyModel {
public:
- LatencyModel(size_t window_size);
+ explicit LatencyModel(size_t window_size);
~LatencyModel() = default;
void AddLatency(int64_t latency_ns);
diff --git a/opengl/libs/Android.mk b/opengl/libs/Android.mk
deleted file mode 100644
index 2f42ab6..0000000
--- a/opengl/libs/Android.mk
+++ /dev/null
@@ -1 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
diff --git a/opengl/libs/EGL/egl_layers.cpp b/opengl/libs/EGL/egl_layers.cpp
index dd8fbfc..f936ac0 100644
--- a/opengl/libs/EGL/egl_layers.cpp
+++ b/opengl/libs/EGL/egl_layers.cpp
@@ -375,12 +375,13 @@
auto app_namespace = android::GraphicsEnv::getInstance().getAppNamespace();
if (app_namespace && !android::base::StartsWith(layer, kSystemLayerLibraryDir)) {
bool native_bridge = false;
- std::string error_message;
- handle = OpenNativeLibrary(app_namespace, layer.c_str(), &native_bridge,
- &error_message);
+ char* error_message = nullptr;
+ handle = OpenNativeLibraryInNamespace(
+ app_namespace, layer.c_str(), &native_bridge, &error_message);
if (!handle) {
ALOGE("Failed to load layer %s with error: %s", layer.c_str(),
- error_message.c_str());
+ error_message);
+ android::NativeLoaderFreeErrorMessage(error_message);
return;
}
diff --git a/opengl/tests/Android.mk b/opengl/tests/Android.mk
deleted file mode 100644
index 134854a..0000000
--- a/opengl/tests/Android.mk
+++ /dev/null
@@ -1,28 +0,0 @@
-dirs := \
- linetex \
- swapinterval \
- textures \
- tritex \
-
-ifneq (,$(TARGET_BUILD_JAVA_SUPPORT_LEVEL))
-dirs += \
- gl2_cameraeye \
- gl2_java \
- gl2_jni \
- gldual \
- gl_jni \
- gl_perfapp \
- lighting1709 \
- testLatency \
- testPauseResume \
- testViewport \
-
-endif # JAVA_SUPPORT
-
-ifeq (platform,$(TARGET_BUILD_JAVA_SUPPORT_LEVEL))
-dirs += \
- testFramerate
-
-endif # JAVA_SUPPORT platform
-
-include $(call all-named-subdir-makefiles, $(dirs))
diff --git a/opengl/tests/gl2_cameraeye/Android.bp b/opengl/tests/gl2_cameraeye/Android.bp
new file mode 100644
index 0000000..00e00df
--- /dev/null
+++ b/opengl/tests/gl2_cameraeye/Android.bp
@@ -0,0 +1,6 @@
+android_app {
+ name: "GL2CameraEye",
+ // Only compile source java files in this apk.
+ srcs: ["src/**/*.java"],
+ sdk_version: "current",
+}
diff --git a/opengl/tests/gl2_cameraeye/Android.mk b/opengl/tests/gl2_cameraeye/Android.mk
deleted file mode 100644
index 4a43a9e..0000000
--- a/opengl/tests/gl2_cameraeye/Android.mk
+++ /dev/null
@@ -1,16 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := optional
-
-# Only compile source java files in this apk.
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_PACKAGE_NAME := GL2CameraEye
-
-LOCAL_SDK_VERSION := current
-
-include $(BUILD_PACKAGE)
-
-# Use the following include to make our test apk.
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/opengl/tests/gl2_java/Android.bp b/opengl/tests/gl2_java/Android.bp
new file mode 100644
index 0000000..a8e5d7d
--- /dev/null
+++ b/opengl/tests/gl2_java/Android.bp
@@ -0,0 +1,8 @@
+//########################################################################
+// OpenGL ES 2.0 Java sample
+//########################################################################
+android_app {
+ name: "GL2Java",
+ srcs: ["**/*.java"],
+ sdk_version: "current",
+}
diff --git a/opengl/tests/gl2_java/Android.mk b/opengl/tests/gl2_java/Android.mk
deleted file mode 100644
index 71aa5a0..0000000
--- a/opengl/tests/gl2_java/Android.mk
+++ /dev/null
@@ -1,19 +0,0 @@
-#########################################################################
-# OpenGL ES 2.0 Java sample
-#########################################################################
-
-TOP_LOCAL_PATH:= $(call my-dir)
-
-# Build activity
-
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_PACKAGE_NAME := GL2Java
-LOCAL_SDK_VERSION := current
-
-include $(BUILD_PACKAGE)
diff --git a/opengl/tests/gl2_jni/Android.bp b/opengl/tests/gl2_jni/Android.bp
new file mode 100644
index 0000000..65f89b1
--- /dev/null
+++ b/opengl/tests/gl2_jni/Android.bp
@@ -0,0 +1,27 @@
+//########################################################################
+// OpenGL ES JNI sample
+// This makefile builds both an activity and a shared library.
+//########################################################################
+
+android_app {
+ name: "GL2JNI",
+ srcs: ["**/*.java"],
+ sdk_version: "current",
+ jni_libs: ["libgl2jni"],
+}
+
+// Build JNI Shared Library
+cc_library_shared {
+ name: "libgl2jni",
+ cflags: [
+ "-Werror",
+ "-Wno-error=unused-parameter",
+ ],
+ srcs: ["jni/gl_code.cpp"],
+ shared_libs: [
+ "liblog",
+ "libEGL",
+ "libGLESv2",
+ ],
+ sdk_version: "current",
+}
diff --git a/opengl/tests/gl2_jni/Android.mk b/opengl/tests/gl2_jni/Android.mk
deleted file mode 100644
index b0081c2..0000000
--- a/opengl/tests/gl2_jni/Android.mk
+++ /dev/null
@@ -1,49 +0,0 @@
-#########################################################################
-# OpenGL ES JNI sample
-# This makefile builds both an activity and a shared library.
-#########################################################################
-TOP_LOCAL_PATH:= $(call my-dir)
-
-# Build activity
-
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_PACKAGE_NAME := GL2JNI
-LOCAL_SDK_VERSION := current
-
-LOCAL_JNI_SHARED_LIBRARIES := libgl2jni
-
-include $(BUILD_PACKAGE)
-
-#########################################################################
-# Build JNI Shared Library
-#########################################################################
-
-LOCAL_PATH:= $(LOCAL_PATH)/jni
-
-include $(CLEAR_VARS)
-
-# Optional tag would mean it doesn't get installed by default
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_CFLAGS := -Werror -Wno-error=unused-parameter
-
-LOCAL_SRC_FILES:= \
- gl_code.cpp
-
-LOCAL_SHARED_LIBRARIES := \
- liblog \
- libEGL \
- libGLESv2
-
-LOCAL_MODULE := libgl2jni
-
-LOCAL_SDK_VERSION := current
-
-
-include $(BUILD_SHARED_LIBRARY)
diff --git a/opengl/tests/gl_jni/Android.bp b/opengl/tests/gl_jni/Android.bp
new file mode 100644
index 0000000..5bec336
--- /dev/null
+++ b/opengl/tests/gl_jni/Android.bp
@@ -0,0 +1,34 @@
+//########################################################################
+// OpenGL ES JNI sample
+// This makefile builds both an activity and a shared library.
+//########################################################################
+// Build activity
+
+android_app {
+ name: "GLJNI",
+ srcs: ["**/*.java"],
+ sdk_version: "current",
+ jni_libs: ["libgljni"],
+}
+
+// Build JNI Shared Library
+
+cc_library_shared {
+ name: "libgljni",
+ cflags: [
+ "-Werror",
+ "-Wno-error=unused-parameter",
+ ],
+ srcs: ["jni/gl_code.cpp"],
+ shared_libs: [
+ "liblog",
+ "libEGL",
+ "libGLESv1_CM",
+ ],
+ sdk_version: "current",
+ arch: {
+ arm: {
+ instruction_set: "arm",
+ },
+ },
+}
diff --git a/opengl/tests/gl_jni/Android.mk b/opengl/tests/gl_jni/Android.mk
deleted file mode 100644
index d64dfcf..0000000
--- a/opengl/tests/gl_jni/Android.mk
+++ /dev/null
@@ -1,52 +0,0 @@
-#########################################################################
-# OpenGL ES JNI sample
-# This makefile builds both an activity and a shared library.
-#########################################################################
-TOP_LOCAL_PATH:= $(call my-dir)
-
-# Build activity
-
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_PACKAGE_NAME := GLJNI
-LOCAL_SDK_VERSION := current
-
-LOCAL_JNI_SHARED_LIBRARIES := libgljni
-
-include $(BUILD_PACKAGE)
-
-#########################################################################
-# Build JNI Shared Library
-#########################################################################
-
-LOCAL_PATH:= $(LOCAL_PATH)/jni
-
-include $(CLEAR_VARS)
-
-# Optional tag would mean it doesn't get installed by default
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_CFLAGS := -Werror -Wno-error=unused-parameter
-
-LOCAL_SRC_FILES:= \
- gl_code.cpp
-
-LOCAL_SHARED_LIBRARIES := \
- liblog \
- libEGL \
- libGLESv1_CM
-
-LOCAL_MODULE := libgljni
-
-LOCAL_SDK_VERSION := current
-
-LOCAL_ARM_MODE := arm
-
-
-
-include $(BUILD_SHARED_LIBRARY)
diff --git a/opengl/tests/gl_perfapp/Android.bp b/opengl/tests/gl_perfapp/Android.bp
new file mode 100644
index 0000000..cf899ac
--- /dev/null
+++ b/opengl/tests/gl_perfapp/Android.bp
@@ -0,0 +1,27 @@
+//########################################################################
+// OpenGL ES Perf App
+// This makefile builds both an activity and a shared library.
+//########################################################################
+android_app {
+ name: "GLPerf",
+ srcs: ["**/*.java"],
+ jni_libs: ["libglperf"],
+ // Run on Eclair
+ sdk_version: "7",
+}
+
+// Build JNI Shared Library
+cc_library_shared {
+ name: "libglperf",
+ cflags: [
+ "-Werror",
+ "-Wno-error=unused-parameter",
+ ],
+ srcs: ["jni/gl_code.cpp"],
+ shared_libs: [
+ "liblog",
+ "libEGL",
+ "libGLESv2",
+ ],
+ sdk_version: "current",
+}
diff --git a/opengl/tests/gl_perfapp/Android.mk b/opengl/tests/gl_perfapp/Android.mk
deleted file mode 100644
index 3f411ea..0000000
--- a/opengl/tests/gl_perfapp/Android.mk
+++ /dev/null
@@ -1,52 +0,0 @@
-#########################################################################
-# OpenGL ES Perf App
-# This makefile builds both an activity and a shared library.
-#########################################################################
-TOP_LOCAL_PATH:= $(call my-dir)
-
-# Build activity
-
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_PACKAGE_NAME := GLPerf
-
-LOCAL_JNI_SHARED_LIBRARIES := libglperf
-
-# Run on Eclair
-LOCAL_SDK_VERSION := 7
-
-include $(BUILD_PACKAGE)
-
-#########################################################################
-# Build JNI Shared Library
-#########################################################################
-
-LOCAL_PATH:= $(LOCAL_PATH)/jni
-
-include $(CLEAR_VARS)
-
-# Optional tag would mean it doesn't get installed by default
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_CFLAGS := -Werror -Wno-error=unused-parameter
-
-LOCAL_SRC_FILES:= \
- gl_code.cpp
-
-LOCAL_SHARED_LIBRARIES := \
- liblog \
- libEGL \
- libGLESv2
-
-LOCAL_SDK_VERSION := current
-
-LOCAL_MODULE := libglperf
-
-
-
-include $(BUILD_SHARED_LIBRARY)
diff --git a/opengl/tests/gldual/Android.bp b/opengl/tests/gldual/Android.bp
new file mode 100644
index 0000000..2432566
--- /dev/null
+++ b/opengl/tests/gldual/Android.bp
@@ -0,0 +1,30 @@
+//########################################################################
+// OpenGL ES JNI sample
+// This makefile builds both an activity and a shared library.
+//########################################################################
+// Build activity
+
+android_app {
+ name: "GLDual",
+ srcs: ["**/*.java"],
+ sdk_version: "current",
+ jni_libs: ["libgldualjni"],
+}
+
+//########################################################################
+// Build JNI Shared Library
+//########################################################################
+cc_library_shared {
+ name: "libgldualjni",
+ cflags: [
+ "-Werror",
+ "-Wno-error=unused-parameter",
+ ],
+ srcs: ["jni/gl_code.cpp"],
+ shared_libs: [
+ "liblog",
+ "libEGL",
+ "libGLESv2",
+ ],
+ sdk_version: "current",
+}
diff --git a/opengl/tests/gldual/Android.mk b/opengl/tests/gldual/Android.mk
deleted file mode 100644
index 5bdc0a8..0000000
--- a/opengl/tests/gldual/Android.mk
+++ /dev/null
@@ -1,49 +0,0 @@
-#########################################################################
-# OpenGL ES JNI sample
-# This makefile builds both an activity and a shared library.
-#########################################################################
-TOP_LOCAL_PATH:= $(call my-dir)
-
-# Build activity
-
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_PACKAGE_NAME := GLDual
-LOCAL_SDK_VERSION := current
-
-LOCAL_JNI_SHARED_LIBRARIES := libgldualjni
-
-include $(BUILD_PACKAGE)
-
-#########################################################################
-# Build JNI Shared Library
-#########################################################################
-
-LOCAL_PATH:= $(LOCAL_PATH)/jni
-
-include $(CLEAR_VARS)
-
-# Optional tag would mean it doesn't get installed by default
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_CFLAGS := -Werror -Wno-error=unused-parameter
-
-LOCAL_SRC_FILES:= \
- gl_code.cpp
-
-LOCAL_SHARED_LIBRARIES := \
- liblog \
- libEGL \
- libGLESv2
-
-LOCAL_MODULE := libgldualjni
-
-LOCAL_SDK_VERSION := current
-
-
-include $(BUILD_SHARED_LIBRARY)
diff --git a/opengl/tests/lighting1709/Android.bp b/opengl/tests/lighting1709/Android.bp
new file mode 100644
index 0000000..e734dd1
--- /dev/null
+++ b/opengl/tests/lighting1709/Android.bp
@@ -0,0 +1,6 @@
+android_test {
+ name: "LightingTest",
+ srcs: ["**/*.java"],
+ sdk_version: "current",
+ certificate: "platform",
+}
diff --git a/opengl/tests/lighting1709/Android.mk b/opengl/tests/lighting1709/Android.mk
deleted file mode 100644
index 0047231..0000000
--- a/opengl/tests/lighting1709/Android.mk
+++ /dev/null
@@ -1,12 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_PACKAGE_NAME := LightingTest
-LOCAL_SDK_VERSION := current
-LOCAL_CERTIFICATE := platform
-
-include $(BUILD_PACKAGE)
diff --git a/opengl/tests/linetex/Android.bp b/opengl/tests/linetex/Android.bp
new file mode 100644
index 0000000..dbc2cdb
--- /dev/null
+++ b/opengl/tests/linetex/Android.bp
@@ -0,0 +1,17 @@
+cc_binary {
+ name: "test-opengl-linetex",
+ srcs: ["linetex.cpp"],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
+ shared_libs: [
+ "libcutils",
+ "libEGL",
+ "libGLESv1_CM",
+ "libui",
+ "libgui",
+ "libutils",
+ ],
+ static_libs: ["libglTest"],
+}
diff --git a/opengl/tests/linetex/Android.mk b/opengl/tests/linetex/Android.mk
deleted file mode 100644
index 3df0a0f..0000000
--- a/opengl/tests/linetex/Android.mk
+++ /dev/null
@@ -1,25 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
- linetex.cpp
-
-LOCAL_CFLAGS := -Wall -Werror
-
-LOCAL_SHARED_LIBRARIES := \
- libcutils \
- libEGL \
- libGLESv1_CM \
- libui \
- libgui \
- libutils
-
-LOCAL_STATIC_LIBRARIES += libglTest
-
-LOCAL_C_INCLUDES += $(call include-path-for, opengl-tests-includes)
-
-LOCAL_MODULE:= test-opengl-linetex
-
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_EXECUTABLE)
diff --git a/opengl/tests/swapinterval/Android.bp b/opengl/tests/swapinterval/Android.bp
new file mode 100644
index 0000000..eed4dff
--- /dev/null
+++ b/opengl/tests/swapinterval/Android.bp
@@ -0,0 +1,17 @@
+cc_binary {
+ name: "test-opengl-swapinterval",
+ srcs: ["swapinterval.cpp"],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
+ shared_libs: [
+ "libcutils",
+ "libutils",
+ "libEGL",
+ "libGLESv1_CM",
+ "libui",
+ "libgui",
+ ],
+ static_libs: ["libglTest"],
+}
diff --git a/opengl/tests/swapinterval/Android.mk b/opengl/tests/swapinterval/Android.mk
deleted file mode 100644
index 2a2c12f..0000000
--- a/opengl/tests/swapinterval/Android.mk
+++ /dev/null
@@ -1,25 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
- swapinterval.cpp
-
-LOCAL_CFLAGS := -Wall -Werror
-
-LOCAL_SHARED_LIBRARIES := \
- libcutils \
- libutils \
- libEGL \
- libGLESv1_CM \
- libui \
- libgui
-
-LOCAL_STATIC_LIBRARIES += libglTest
-
-LOCAL_C_INCLUDES += $(call include-path-for, opengl-tests-includes)
-
-LOCAL_MODULE:= test-opengl-swapinterval
-
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_EXECUTABLE)
diff --git a/opengl/tests/testFramerate/Android.bp b/opengl/tests/testFramerate/Android.bp
new file mode 100644
index 0000000..5aa83b0
--- /dev/null
+++ b/opengl/tests/testFramerate/Android.bp
@@ -0,0 +1,9 @@
+//########################################################################
+// Test framerate and look for hiccups
+//########################################################################
+
+android_app {
+ name: "TestFramerate",
+ srcs: ["**/*.java"],
+ sdk_version: "system_current",
+}
diff --git a/opengl/tests/testFramerate/Android.mk b/opengl/tests/testFramerate/Android.mk
deleted file mode 100644
index ca6654a..0000000
--- a/opengl/tests/testFramerate/Android.mk
+++ /dev/null
@@ -1,20 +0,0 @@
-#########################################################################
-# Test framerate and look for hiccups
-#########################################################################
-
-TOP_LOCAL_PATH:= $(call my-dir)
-
-# Build activity
-
-
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_PACKAGE_NAME := TestFramerate
-LOCAL_SDK_VERSION := system_current
-
-include $(BUILD_PACKAGE)
diff --git a/opengl/tests/testLatency/Android.bp b/opengl/tests/testLatency/Android.bp
new file mode 100644
index 0000000..c516dc3
--- /dev/null
+++ b/opengl/tests/testLatency/Android.bp
@@ -0,0 +1,8 @@
+//########################################################################
+// Test end-to-end latency.
+//########################################################################
+android_app {
+ name: "TestLatency",
+ sdk_version: "8",
+ srcs: ["**/*.java"],
+}
diff --git a/opengl/tests/testLatency/Android.mk b/opengl/tests/testLatency/Android.mk
deleted file mode 100644
index 96417c7..0000000
--- a/opengl/tests/testLatency/Android.mk
+++ /dev/null
@@ -1,20 +0,0 @@
-#########################################################################
-# Test end-to-end latency.
-#########################################################################
-
-TOP_LOCAL_PATH:= $(call my-dir)
-
-# Build activity
-
-
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SDK_VERSION := 8
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_PACKAGE_NAME := TestLatency
-
-include $(BUILD_PACKAGE)
diff --git a/opengl/tests/testPauseResume/Android.bp b/opengl/tests/testPauseResume/Android.bp
new file mode 100644
index 0000000..810e895
--- /dev/null
+++ b/opengl/tests/testPauseResume/Android.bp
@@ -0,0 +1,6 @@
+// OpenGL ES JNI sample
+android_app {
+ name: "TestEGL",
+ srcs: ["**/*.java"],
+ sdk_version: "current",
+}
diff --git a/opengl/tests/testPauseResume/Android.mk b/opengl/tests/testPauseResume/Android.mk
deleted file mode 100644
index dda5424..0000000
--- a/opengl/tests/testPauseResume/Android.mk
+++ /dev/null
@@ -1,19 +0,0 @@
-#########################################################################
-# OpenGL ES JNI sample
-# This makefile builds both an activity and a shared library.
-#########################################################################
-TOP_LOCAL_PATH:= $(call my-dir)
-
-# Build activity
-
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_PACKAGE_NAME := TestEGL
-LOCAL_SDK_VERSION := current
-
-include $(BUILD_PACKAGE)
diff --git a/opengl/tests/testViewport/Android.bp b/opengl/tests/testViewport/Android.bp
new file mode 100644
index 0000000..629b573
--- /dev/null
+++ b/opengl/tests/testViewport/Android.bp
@@ -0,0 +1,9 @@
+//########################################################################
+// OpenGL ES JNI sample
+// This makefile builds both an activity and a shared library.
+//########################################################################
+android_app {
+ name: "TestViewport",
+ srcs: ["**/*.java"],
+ sdk_version: "8",
+}
diff --git a/opengl/tests/testViewport/Android.mk b/opengl/tests/testViewport/Android.mk
deleted file mode 100644
index 9980e7d..0000000
--- a/opengl/tests/testViewport/Android.mk
+++ /dev/null
@@ -1,22 +0,0 @@
-#########################################################################
-# OpenGL ES JNI sample
-# This makefile builds both an activity and a shared library.
-#########################################################################
-TOP_LOCAL_PATH:= $(call my-dir)
-
-# Build activity
-
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_PACKAGE_NAME := TestViewport
-
-# Set a specific SDK version so we can run on Froyo.
-
-LOCAL_SDK_VERSION := 8
-
-include $(BUILD_PACKAGE)
diff --git a/opengl/tests/textures/Android.bp b/opengl/tests/textures/Android.bp
new file mode 100644
index 0000000..84adda2
--- /dev/null
+++ b/opengl/tests/textures/Android.bp
@@ -0,0 +1,18 @@
+cc_binary {
+ name: "test-opengl-textures",
+ srcs: ["textures.cpp"],
+ shared_libs: [
+ "libcutils",
+ "libEGL",
+ "libGLESv1_CM",
+ "libui",
+ "libgui",
+ "libutils",
+ ],
+ static_libs: ["libglTest"],
+ cflags: [
+ "-DGL_GLEXT_PROTOTYPES",
+ "-Wall",
+ "-Werror",
+ ],
+}
diff --git a/opengl/tests/textures/Android.mk b/opengl/tests/textures/Android.mk
deleted file mode 100644
index 629a2d2..0000000
--- a/opengl/tests/textures/Android.mk
+++ /dev/null
@@ -1,26 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
- textures.cpp
-
-LOCAL_SHARED_LIBRARIES := \
- libcutils \
- libEGL \
- libGLESv1_CM \
- libui \
- libgui \
- libutils
-
-LOCAL_STATIC_LIBRARIES += libglTest
-
-LOCAL_C_INCLUDES += $(call include-path-for, opengl-tests-includes)
-
-LOCAL_MODULE:= test-opengl-textures
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES
-LOCAL_CFLAGS += -Wall -Werror
-
-include $(BUILD_EXECUTABLE)
diff --git a/opengl/tests/tritex/Android.bp b/opengl/tests/tritex/Android.bp
new file mode 100644
index 0000000..390397b
--- /dev/null
+++ b/opengl/tests/tritex/Android.bp
@@ -0,0 +1,17 @@
+cc_binary {
+ name: "test-opengl-tritex",
+ srcs: ["tritex.cpp"],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
+ shared_libs: [
+ "libcutils",
+ "libEGL",
+ "libGLESv1_CM",
+ "libui",
+ "libgui",
+ "libutils",
+ ],
+ static_libs: ["libglTest"],
+}
diff --git a/opengl/tests/tritex/Android.mk b/opengl/tests/tritex/Android.mk
deleted file mode 100644
index 7055afa..0000000
--- a/opengl/tests/tritex/Android.mk
+++ /dev/null
@@ -1,25 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
- tritex.cpp
-
-LOCAL_CFLAGS := -Wall -Werror
-
-LOCAL_SHARED_LIBRARIES := \
- libcutils \
- libEGL \
- libGLESv1_CM \
- libui \
- libgui \
- libutils
-
-LOCAL_STATIC_LIBRARIES += libglTest
-
-LOCAL_C_INCLUDES += $(call include-path-for, opengl-tests-includes)
-
-LOCAL_MODULE:= test-opengl-tritex
-
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_EXECUTABLE)
diff --git a/services/bufferhub/Android.bp b/services/bufferhub/Android.bp
index 72d210c..a4b81fe 100644
--- a/services/bufferhub/Android.bp
+++ b/services/bufferhub/Android.bp
@@ -34,6 +34,7 @@
],
shared_libs: [
"android.frameworks.bufferhub@1.0",
+ "libcrypto",
"libcutils",
"libhidlbase",
"libhidltransport",
@@ -60,6 +61,7 @@
shared_libs: [
"android.frameworks.bufferhub@1.0",
"libbufferhubservice",
+ "libcrypto",
"libcutils",
"libhidltransport",
"libhwbinder",
diff --git a/services/bufferhub/BufferClient.cpp b/services/bufferhub/BufferClient.cpp
index e312011..ec7e535 100644
--- a/services/bufferhub/BufferClient.cpp
+++ b/services/bufferhub/BufferClient.cpp
@@ -41,6 +41,14 @@
}
BufferClient::~BufferClient() {
+ {
+ std::lock_guard<std::mutex> lock(mClosedMutex);
+ if (!mClosed) {
+ ALOGW("%s: client of buffer #%d destroyed without close. Closing it now.", __FUNCTION__,
+ mBufferNode->id());
+ }
+ }
+
close();
}
diff --git a/services/bufferhub/BufferHubIdGenerator.cpp b/services/bufferhub/BufferHubIdGenerator.cpp
index 6444a03..2c12f0e 100644
--- a/services/bufferhub/BufferHubIdGenerator.cpp
+++ b/services/bufferhub/BufferHubIdGenerator.cpp
@@ -15,6 +15,7 @@
*/
#include <bufferhub/BufferHubIdGenerator.h>
+#include <log/log.h>
namespace android {
namespace frameworks {
@@ -22,20 +23,18 @@
namespace V1_0 {
namespace implementation {
-constexpr uint32_t BufferHubIdGenerator::kInvalidId;
-
BufferHubIdGenerator& BufferHubIdGenerator::getInstance() {
static BufferHubIdGenerator generator;
return generator;
}
-uint32_t BufferHubIdGenerator::getId() {
+int BufferHubIdGenerator::getId() {
std::lock_guard<std::mutex> lock(mIdsInUseMutex);
do {
- if (++mLastId >= std::numeric_limits<uint32_t>::max()) {
- mLastId = kInvalidId + 1;
+ if (++mLastId >= std::numeric_limits<int>::max()) {
+ mLastId = 0;
}
} while (mIdsInUse.find(mLastId) != mIdsInUse.end());
@@ -43,15 +42,14 @@
return mLastId;
}
-bool BufferHubIdGenerator::freeId(uint32_t id) {
+void BufferHubIdGenerator::freeId(int id) {
std::lock_guard<std::mutex> lock(mIdsInUseMutex);
auto iter = mIdsInUse.find(id);
if (iter != mIdsInUse.end()) {
mIdsInUse.erase(iter);
- return true;
+ } else {
+ ALOGW("%s: Cannot free nonexistent id #%d", __FUNCTION__, id);
}
-
- return false;
}
} // namespace implementation
diff --git a/services/bufferhub/BufferHubService.cpp b/services/bufferhub/BufferHubService.cpp
index 2663812..6b802fb 100644
--- a/services/bufferhub/BufferHubService.cpp
+++ b/services/bufferhub/BufferHubService.cpp
@@ -14,10 +14,21 @@
* limitations under the License.
*/
+#include <array>
+#include <iomanip>
+#include <random>
+#include <sstream>
+
#include <android/hardware_buffer.h>
#include <bufferhub/BufferHubService.h>
#include <cutils/native_handle.h>
#include <log/log.h>
+#include <openssl/hmac.h>
+#include <system/graphics-base.h>
+#include <ui/BufferHubDefs.h>
+
+using ::android::BufferHubDefs::MetadataHeader;
+using ::android::hardware::Void;
namespace android {
namespace frameworks {
@@ -25,7 +36,12 @@
namespace V1_0 {
namespace implementation {
-using hardware::Void;
+BufferHubService::BufferHubService() {
+ std::mt19937_64 randomEngine;
+ randomEngine.seed(time(nullptr));
+
+ mKey = randomEngine();
+}
Return<void> BufferHubService::allocateBuffer(const HardwareBufferDescription& description,
const uint32_t userMetadataSize,
@@ -49,39 +65,68 @@
std::lock_guard<std::mutex> lock(mClientSetMutex);
mClientSet.emplace(client);
+ // Allocate memory for bufferInfo of type hidl_handle on the stack. See
+ // http://aosp/286282 for the usage of NATIVE_HANDLE_DECLARE_STORAGE.
+ NATIVE_HANDLE_DECLARE_STORAGE(bufferInfoStorage, BufferHubDefs::kBufferInfoNumFds,
+ BufferHubDefs::kBufferInfoNumInts);
+ hidl_handle bufferInfo =
+ buildBufferInfo(bufferInfoStorage, node->id(), node->AddNewActiveClientsBitToMask(),
+ node->user_metadata_size(), node->metadata().ashmem_fd(),
+ node->eventFd().get());
BufferTraits bufferTraits = {/*bufferDesc=*/description,
/*bufferHandle=*/hidl_handle(node->buffer_handle()),
- // TODO(b/116681016): return real data to client
- /*bufferInfo=*/hidl_handle()};
+ /*bufferInfo=*/std::move(bufferInfo)};
_hidl_cb(/*status=*/BufferHubStatus::NO_ERROR, /*bufferClient=*/client,
- /*bufferTraits=*/bufferTraits);
+ /*bufferTraits=*/std::move(bufferTraits));
return Void();
}
Return<void> BufferHubService::importBuffer(const hidl_handle& tokenHandle,
importBuffer_cb _hidl_cb) {
- if (!tokenHandle.getNativeHandle() || tokenHandle->numFds != 0 || tokenHandle->numInts != 1) {
+ if (!tokenHandle.getNativeHandle() || tokenHandle->numFds != 0 || tokenHandle->numInts <= 1) {
// nullptr handle or wrong format
_hidl_cb(/*status=*/BufferHubStatus::INVALID_TOKEN, /*bufferClient=*/nullptr,
/*bufferTraits=*/{});
return Void();
}
- uint32_t token = tokenHandle->data[0];
+ int tokenId = tokenHandle->data[0];
wp<BufferClient> originClientWp;
{
- std::lock_guard<std::mutex> lock(mTokenMapMutex);
- auto iter = mTokenMap.find(token);
+ std::lock_guard<std::mutex> lock(mTokenMutex);
+ auto iter = mTokenMap.find(tokenId);
if (iter == mTokenMap.end()) {
- // Invalid token
+ // Token Id not exist
+ ALOGD("%s: token #%d not found.", __FUNCTION__, tokenId);
_hidl_cb(/*status=*/BufferHubStatus::INVALID_TOKEN, /*bufferClient=*/nullptr,
/*bufferTraits=*/{});
return Void();
}
- originClientWp = iter->second;
+ const std::vector<uint8_t>& tokenHMAC = iter->second.first;
+
+ int numIntsForHMAC = (int)ceil(tokenHMAC.size() * sizeof(uint8_t) / (double)sizeof(int));
+ if (tokenHandle->numInts - 1 != numIntsForHMAC) {
+ // HMAC size not match
+ ALOGD("%s: token #%d HMAC size not match. Expected: %d Actual: %d", __FUNCTION__,
+ tokenId, numIntsForHMAC, tokenHandle->numInts - 1);
+ _hidl_cb(/*status=*/BufferHubStatus::INVALID_TOKEN, /*bufferClient=*/nullptr,
+ /*bufferTraits=*/{});
+ return Void();
+ }
+
+ size_t hmacSize = tokenHMAC.size() * sizeof(uint8_t);
+ if (memcmp(tokenHMAC.data(), &tokenHandle->data[1], hmacSize) != 0) {
+ // HMAC not match
+ ALOGD("%s: token #%d HMAC not match.", __FUNCTION__, tokenId);
+ _hidl_cb(/*status=*/BufferHubStatus::INVALID_TOKEN, /*bufferClient=*/nullptr,
+ /*bufferTraits=*/{});
+ return Void();
+ }
+
+ originClientWp = iter->second.second;
mTokenMap.erase(iter);
}
@@ -114,32 +159,185 @@
HardwareBufferDescription bufferDesc;
memcpy(&bufferDesc, &node->buffer_desc(), sizeof(HardwareBufferDescription));
+ // Allocate memory for bufferInfo of type hidl_handle on the stack. See
+ // http://aosp/286282 for the usage of NATIVE_HANDLE_DECLARE_STORAGE.
+ NATIVE_HANDLE_DECLARE_STORAGE(bufferInfoStorage, BufferHubDefs::kBufferInfoNumFds,
+ BufferHubDefs::kBufferInfoNumInts);
+ hidl_handle bufferInfo = buildBufferInfo(bufferInfoStorage, node->id(), clientStateMask,
+ node->user_metadata_size(),
+ node->metadata().ashmem_fd(), node->eventFd().get());
BufferTraits bufferTraits = {/*bufferDesc=*/bufferDesc,
/*bufferHandle=*/hidl_handle(node->buffer_handle()),
- // TODO(b/116681016): return real data to client
- /*bufferInfo=*/hidl_handle()};
+ /*bufferInfo=*/std::move(bufferInfo)};
_hidl_cb(/*status=*/BufferHubStatus::NO_ERROR, /*bufferClient=*/client,
- /*bufferTraits=*/bufferTraits);
+ /*bufferTraits=*/std::move(bufferTraits));
+ return Void();
+}
+
+Return<void> BufferHubService::debug(const hidl_handle& fd, const hidl_vec<hidl_string>& args) {
+ if (fd.getNativeHandle() == nullptr || fd->numFds < 1) {
+ ALOGE("%s: missing fd for writing.", __FUNCTION__);
+ return Void();
+ }
+
+ FILE* out = fdopen(dup(fd->data[0]), "w");
+
+ if (args.size() != 0) {
+ fprintf(out,
+ "Note: lshal bufferhub currently does not support args. Input arguments are "
+ "ignored.\n");
+ }
+
+ std::ostringstream stream;
+
+ // Get the number of clients of each buffer.
+ // Map from bufferId to bufferNode_clientCount pair.
+ std::map<int, std::pair<const std::shared_ptr<BufferNode>, uint32_t>> clientCount;
+ {
+ std::lock_guard<std::mutex> lock(mClientSetMutex);
+ for (auto iter = mClientSet.begin(); iter != mClientSet.end(); ++iter) {
+ sp<BufferClient> client = iter->promote();
+ if (client != nullptr) {
+ const std::shared_ptr<BufferNode> node = client->getBufferNode();
+ auto mapIter = clientCount.find(node->id());
+ if (mapIter != clientCount.end()) {
+ ++mapIter->second.second;
+ } else {
+ clientCount.emplace(node->id(),
+ std::pair<std::shared_ptr<BufferNode>, uint32_t>(node, 1U));
+ }
+ }
+ }
+ }
+
+ stream << "Active Buffers:\n";
+ stream << std::right;
+ stream << std::setw(6) << "Id";
+ stream << " ";
+ stream << std::setw(9) << "#Clients";
+ stream << " ";
+ stream << std::setw(14) << "Geometry";
+ stream << " ";
+ stream << std::setw(6) << "Format";
+ stream << " ";
+ stream << std::setw(10) << "Usage";
+ stream << " ";
+ stream << std::setw(10) << "State";
+ stream << " ";
+ stream << std::setw(8) << "Index";
+ stream << std::endl;
+
+ for (auto iter = clientCount.begin(); iter != clientCount.end(); ++iter) {
+ const std::shared_ptr<BufferNode> node = std::move(iter->second.first);
+ const uint32_t clientCount = iter->second.second;
+ AHardwareBuffer_Desc desc = node->buffer_desc();
+
+ MetadataHeader* metadataHeader =
+ const_cast<BufferHubMetadata*>(&node->metadata())->metadata_header();
+ const uint32_t state = metadataHeader->buffer_state.load(std::memory_order_acquire);
+ const uint64_t index = metadataHeader->queue_index;
+
+ stream << std::right;
+ stream << std::setw(6) << /*Id=*/node->id();
+ stream << " ";
+ stream << std::setw(9) << /*#Clients=*/clientCount;
+ stream << " ";
+ if (desc.format == HAL_PIXEL_FORMAT_BLOB) {
+ std::string size = std::to_string(desc.width) + " B";
+ stream << std::setw(14) << /*Geometry=*/size;
+ } else {
+ std::string dimensions = std::to_string(desc.width) + "x" +
+ std::to_string(desc.height) + "x" + std::to_string(desc.layers);
+ stream << std::setw(14) << /*Geometry=*/dimensions;
+ }
+ stream << " ";
+ stream << std::setw(6) << /*Format=*/desc.format;
+ stream << " ";
+ stream << "0x" << std::hex << std::setfill('0');
+ stream << std::setw(8) << /*Usage=*/desc.usage;
+ stream << std::dec << std::setfill(' ');
+ stream << " ";
+ stream << "0x" << std::hex << std::setfill('0');
+ stream << std::setw(8) << /*State=*/state;
+ stream << std::dec << std::setfill(' ');
+ stream << " ";
+ stream << std::setw(8) << /*Index=*/index;
+ stream << std::endl;
+ }
+
+ stream << std::endl;
+
+ // Get the number of tokens of each buffer.
+ // Map from bufferId to tokenCount
+ std::map<int, uint32_t> tokenCount;
+ {
+ std::lock_guard<std::mutex> lock(mTokenMutex);
+ for (auto iter = mTokenMap.begin(); iter != mTokenMap.end(); ++iter) {
+ sp<BufferClient> client = iter->second.second.promote();
+ if (client != nullptr) {
+ const std::shared_ptr<BufferNode> node = client->getBufferNode();
+ auto mapIter = tokenCount.find(node->id());
+ if (mapIter != tokenCount.end()) {
+ ++mapIter->second;
+ } else {
+ tokenCount.emplace(node->id(), 1U);
+ }
+ }
+ }
+ }
+
+ stream << "Unused Tokens:\n";
+ stream << std::right;
+ stream << std::setw(8) << "Buffer Id";
+ stream << " ";
+ stream << std::setw(7) << "#Tokens";
+ stream << std::endl;
+
+ for (auto iter = tokenCount.begin(); iter != tokenCount.end(); ++iter) {
+ stream << std::right;
+ stream << std::setw(8) << /*Buffer Id=*/iter->first;
+ stream << " ";
+ stream << std::setw(7) << /*#Tokens=*/iter->second;
+ stream << std::endl;
+ }
+
+ fprintf(out, "%s", stream.str().c_str());
+
+ fclose(out);
return Void();
}
hidl_handle BufferHubService::registerToken(const wp<BufferClient>& client) {
- uint32_t token;
- std::lock_guard<std::mutex> lock(mTokenMapMutex);
+ // Find next available token id
+ std::lock_guard<std::mutex> lock(mTokenMutex);
do {
- token = mTokenEngine();
- } while (mTokenMap.find(token) != mTokenMap.end());
+ ++mLastTokenId;
+ } while (mTokenMap.find(mLastTokenId) != mTokenMap.end());
- // native_handle_t use int[], so here need one slots to fit in uint32_t
- native_handle_t* handle = native_handle_create(/*numFds=*/0, /*numInts=*/1);
- handle->data[0] = token;
+ std::array<uint8_t, EVP_MAX_MD_SIZE> hmac;
+ uint32_t hmacSize = 0U;
+
+ HMAC(/*evp_md=*/EVP_sha256(), /*key=*/&mKey, /*key_len=*/kKeyLen,
+ /*data=*/(uint8_t*)&mLastTokenId, /*data_len=*/mTokenIdSize,
+ /*out=*/hmac.data(), /*out_len=*/&hmacSize);
+
+ int numIntsForHMAC = (int)ceil(hmacSize / (double)sizeof(int));
+ native_handle_t* handle = native_handle_create(/*numFds=*/0, /*numInts=*/1 + numIntsForHMAC);
+ handle->data[0] = mLastTokenId;
+ // Set all the the bits of last int to 0 since it might not be fully overwritten
+ handle->data[numIntsForHMAC] = 0;
+ memcpy(&handle->data[1], hmac.data(), hmacSize);
// returnToken owns the native_handle_t* thus doing lifecycle management
hidl_handle returnToken;
returnToken.setTo(handle, /*shoudOwn=*/true);
- mTokenMap.emplace(token, client);
+ std::vector<uint8_t> hmacVec;
+ hmacVec.resize(hmacSize);
+ memcpy(hmacVec.data(), hmac.data(), hmacSize);
+ mTokenMap.emplace(mLastTokenId, std::pair(hmacVec, client));
+
return returnToken;
}
@@ -153,11 +351,34 @@
}
}
+// Implementation of this function should be consistent with the definition of bufferInfo handle in
+// ui/BufferHubDefs.h.
+hidl_handle BufferHubService::buildBufferInfo(char* bufferInfoStorage, int bufferId,
+ uint32_t clientBitMask, uint32_t userMetadataSize,
+ int metadataFd, int eventFd) {
+ native_handle_t* infoHandle =
+ native_handle_init(bufferInfoStorage, BufferHubDefs::kBufferInfoNumFds,
+ BufferHubDefs::kBufferInfoNumInts);
+
+ infoHandle->data[0] = metadataFd;
+ infoHandle->data[1] = eventFd;
+ infoHandle->data[2] = bufferId;
+ // Use memcpy to convert to int without missing digit.
+ // TOOD(b/121345852): use bit_cast to unpack bufferInfo when C++20 becomes available.
+ memcpy(&infoHandle->data[3], &clientBitMask, sizeof(clientBitMask));
+ memcpy(&infoHandle->data[4], &userMetadataSize, sizeof(userMetadataSize));
+
+ hidl_handle bufferInfo;
+ bufferInfo.setTo(infoHandle, /*shouldOwn=*/false);
+
+ return bufferInfo;
+}
+
void BufferHubService::removeTokenByClient(const BufferClient* client) {
- std::lock_guard<std::mutex> lock(mTokenMapMutex);
+ std::lock_guard<std::mutex> lock(mTokenMutex);
auto iter = mTokenMap.begin();
while (iter != mTokenMap.end()) {
- if (iter->second == client) {
+ if (iter->second.second == client) {
auto oldIter = iter;
++iter;
mTokenMap.erase(oldIter);
diff --git a/services/bufferhub/BufferNode.cpp b/services/bufferhub/BufferNode.cpp
index da19a6f..5106390 100644
--- a/services/bufferhub/BufferNode.cpp
+++ b/services/bufferhub/BufferNode.cpp
@@ -30,7 +30,7 @@
// Allocates a new BufferNode.
BufferNode::BufferNode(uint32_t width, uint32_t height, uint32_t layer_count, uint32_t format,
- uint64_t usage, size_t user_metadata_size, uint32_t id)
+ uint64_t usage, size_t user_metadata_size, int id)
: mId(id) {
uint32_t out_stride = 0;
// graphicBufferId is not used in GraphicBufferAllocator::allocate
@@ -73,12 +73,8 @@
}
// Free the id, if valid
- if (id() != BufferHubIdGenerator::kInvalidId) {
- if (BufferHubIdGenerator::getInstance().freeId(id())) {
- ALOGI("%s: id #%u is freed.", __FUNCTION__, id());
- } else {
- ALOGE("%s: Cannot free nonexistent id #%u", __FUNCTION__, id());
- }
+ if (mId >= 0) {
+ BufferHubIdGenerator::getInstance().freeId(mId);
}
}
diff --git a/services/bufferhub/include/bufferhub/BufferHubIdGenerator.h b/services/bufferhub/include/bufferhub/BufferHubIdGenerator.h
index b51fcda..ef7c077 100644
--- a/services/bufferhub/include/bufferhub/BufferHubIdGenerator.h
+++ b/services/bufferhub/include/bufferhub/BufferHubIdGenerator.h
@@ -28,30 +28,28 @@
namespace V1_0 {
namespace implementation {
-// A thread-safe incremental uint32_t id generator.
+// A thread-safe, non-negative, incremental, int id generator.
class BufferHubIdGenerator {
public:
- // 0 is considered invalid
- static constexpr uint32_t kInvalidId = 0U;
-
// Get the singleton instance of this class
static BufferHubIdGenerator& getInstance();
- // Gets next available id. If next id is greater than std::numeric_limits<uint32_t>::max() (2 ^
- // 32 - 1), it will try to get an id start from 1 again.
- uint32_t getId();
+ // Gets next available id. If next id is greater than std::numeric_limits<int32_t>::max(), it
+ // will try to get an id start from 0 again.
+ int getId();
- // Free a specific id. Return true on freed, false on not found.
- bool freeId(uint32_t id);
+ // Free a specific id.
+ void freeId(int id);
private:
BufferHubIdGenerator() = default;
~BufferHubIdGenerator() = default;
+ // Start from -1 so all valid ids will be >= 0
+ int mLastId = -1;
+
std::mutex mIdsInUseMutex;
- // Start from kInvalidID to avoid generating it.
- uint32_t mLastId = kInvalidId;
- std::set<uint32_t> mIdsInUse GUARDED_BY(mIdsInUseMutex);
+ std::set<int> mIdsInUse GUARDED_BY(mIdsInUseMutex);
};
} // namespace implementation
diff --git a/services/bufferhub/include/bufferhub/BufferHubService.h b/services/bufferhub/include/bufferhub/BufferHubService.h
index f2c8ef8..edad20b 100644
--- a/services/bufferhub/include/bufferhub/BufferHubService.h
+++ b/services/bufferhub/include/bufferhub/BufferHubService.h
@@ -17,8 +17,10 @@
#ifndef ANDROID_FRAMEWORKS_BUFFERHUB_V1_0_BUFFER_HUB_SERVICE_H
#define ANDROID_FRAMEWORKS_BUFFERHUB_V1_0_BUFFER_HUB_SERVICE_H
+#include <map>
#include <mutex>
-#include <random>
+#include <set>
+#include <vector>
#include <android/frameworks/bufferhub/1.0/IBufferHub.h>
#include <bufferhub/BufferClient.h>
@@ -32,16 +34,22 @@
namespace implementation {
using hardware::hidl_handle;
+using hardware::hidl_string;
+using hardware::hidl_vec;
using hardware::Return;
using hardware::graphics::common::V1_2::HardwareBufferDescription;
class BufferHubService : public IBufferHub {
public:
+ BufferHubService();
+
Return<void> allocateBuffer(const HardwareBufferDescription& description,
const uint32_t userMetadataSize,
allocateBuffer_cb _hidl_cb) override;
Return<void> importBuffer(const hidl_handle& tokenHandle, importBuffer_cb _hidl_cb) override;
+ Return<void> debug(const hidl_handle& fd, const hidl_vec<hidl_string>& args) override;
+
// Non-binder functions
// Internal help function for IBufferClient::duplicate.
hidl_handle registerToken(const wp<BufferClient>& client);
@@ -49,6 +57,10 @@
void onClientClosed(const BufferClient* client);
private:
+ // Helper function to build BufferTraits.bufferInfo handle
+ hidl_handle buildBufferInfo(char* bufferInfoStorage, int bufferId, uint32_t clientBitMask,
+ uint32_t userMetadataSize, int metadataFd, int eventFd);
+
// Helper function to remove all the token belongs to a specific client.
void removeTokenByClient(const BufferClient* client);
@@ -56,11 +68,19 @@
std::mutex mClientSetMutex;
std::set<wp<BufferClient>> mClientSet GUARDED_BY(mClientSetMutex);
- // TODO(b/118180214): use a more secure implementation
- std::mt19937 mTokenEngine;
- // The mapping from token to the client creates it.
- std::mutex mTokenMapMutex;
- std::map<uint32_t, const wp<BufferClient>> mTokenMap GUARDED_BY(mTokenMapMutex);
+ // Token generation related
+ // A random number used as private key for HMAC
+ uint64_t mKey;
+ static constexpr size_t kKeyLen = sizeof(uint64_t);
+
+ std::mutex mTokenMutex;
+ // The first TokenId will be 1. TokenId could be negative.
+ int mLastTokenId GUARDED_BY(mTokenMutex) = 0;
+ static constexpr size_t mTokenIdSize = sizeof(int);
+ // A map from token id to the token-buffer_client pair. Using token id as the key to reduce
+ // looking up time
+ std::map<int, std::pair<std::vector<uint8_t>, const wp<BufferClient>>> mTokenMap
+ GUARDED_BY(mTokenMutex);
};
} // namespace implementation
diff --git a/services/bufferhub/include/bufferhub/BufferNode.h b/services/bufferhub/include/bufferhub/BufferNode.h
index cf56c33..4729e1c 100644
--- a/services/bufferhub/include/bufferhub/BufferNode.h
+++ b/services/bufferhub/include/bufferhub/BufferNode.h
@@ -4,6 +4,7 @@
#include <android/hardware_buffer.h>
#include <bufferhub/BufferHubIdGenerator.h>
#include <cutils/native_handle.h>
+#include <ui/BufferHubEventFd.h>
#include <ui/BufferHubMetadata.h>
namespace android {
@@ -16,15 +17,14 @@
public:
// Allocates a new BufferNode.
BufferNode(uint32_t width, uint32_t height, uint32_t layer_count, uint32_t format,
- uint64_t usage, size_t user_metadata_size,
- uint32_t id = BufferHubIdGenerator::kInvalidId);
+ uint64_t usage, size_t user_metadata_size, int id = -1);
~BufferNode();
// Returns whether the object holds a valid metadata.
bool IsValid() const { return metadata_.IsValid(); }
- uint32_t id() const { return mId; }
+ int id() const { return mId; }
size_t user_metadata_size() const { return metadata_.user_metadata_size(); }
@@ -32,6 +32,9 @@
const native_handle_t* buffer_handle() const { return buffer_handle_; }
const AHardwareBuffer_Desc& buffer_desc() const { return buffer_desc_; }
+ // Accessor of event fd.
+ const BufferHubEventFd& eventFd() const { return mEventFd; }
+
// Accessors of metadata.
const BufferHubMetadata& metadata() const { return metadata_; }
@@ -61,13 +64,16 @@
native_handle_t* buffer_handle_;
AHardwareBuffer_Desc buffer_desc_;
+ // Eventfd used for signalling buffer events among the clients of the buffer.
+ BufferHubEventFd mEventFd;
+
// Metadata in shared memory.
BufferHubMetadata metadata_;
- // A system-unique id generated by bufferhub from 1 to std::numeric_limits<uint32_t>::max().
- // BufferNodes not created by bufferhub will have id = 0, meaning "not specified".
- // TODO(b/118891412): remove default id = 0 and update comments after pdx is no longer in use
- const uint32_t mId = 0;
+ // A system-unique id generated by bufferhub from 0 to std::numeric_limits<int>::max().
+ // BufferNodes not created by bufferhub will have id < 0, meaning "not specified".
+ // TODO(b/118891412): remove default id = -1 and update comments after pdx is no longer in use
+ const int mId = -1;
// The following variables are atomic variables in metadata_ that are visible
// to Bn object and Bp objects. Please find more info in
diff --git a/services/bufferhub/tests/BufferHubIdGenerator_test.cpp b/services/bufferhub/tests/BufferHubIdGenerator_test.cpp
index fe01013..fb6de0d 100644
--- a/services/bufferhub/tests/BufferHubIdGenerator_test.cpp
+++ b/services/bufferhub/tests/BufferHubIdGenerator_test.cpp
@@ -15,25 +15,28 @@
};
TEST_F(BufferHubIdGeneratorTest, TestGenerateAndFreeID) {
- uint32_t id = mIdGenerator->getId();
- EXPECT_NE(id, BufferHubIdGenerator::kInvalidId);
+ int id = mIdGenerator->getId();
+ EXPECT_GE(id, 0);
- EXPECT_TRUE(mIdGenerator->freeId(id));
- EXPECT_FALSE(mIdGenerator->freeId(id));
+ mIdGenerator->freeId(id);
}
TEST_F(BufferHubIdGeneratorTest, TestGenerateUniqueIncrementalID) {
// 10 IDs should not overflow the UniqueIdGenerator to cause a roll back to start, so the
// resulting IDs should still keep incresing.
- const size_t kTestSize = 10U;
- uint32_t ids[kTestSize];
- for (size_t i = 0UL; i < kTestSize; ++i) {
+ const int kTestSize = 10;
+ int ids[kTestSize];
+ for (int i = 0; i < kTestSize; ++i) {
ids[i] = mIdGenerator->getId();
- EXPECT_NE(ids[i], BufferHubIdGenerator::kInvalidId);
+ EXPECT_GE(ids[i], 0);
if (i >= 1) {
EXPECT_GT(ids[i], ids[i - 1]);
}
}
+
+ for (int i = 0; i < kTestSize; ++i) {
+ mIdGenerator->freeId(ids[i]);
+ }
}
} // namespace
diff --git a/services/displayservice/OWNERS b/services/displayservice/OWNERS
new file mode 100644
index 0000000..7a3e4c2
--- /dev/null
+++ b/services/displayservice/OWNERS
@@ -0,0 +1,2 @@
+smoreland@google.com
+lpy@google.com
diff --git a/services/displayservice/include/displayservice/DisplayEventReceiver.h b/services/displayservice/include/displayservice/DisplayEventReceiver.h
index 5d569b6..042a054 100644
--- a/services/displayservice/include/displayservice/DisplayEventReceiver.h
+++ b/services/displayservice/include/displayservice/DisplayEventReceiver.h
@@ -45,7 +45,7 @@
using FwkReceiver = ::android::DisplayEventReceiver;
struct AttachedEvent : LooperCallback {
- AttachedEvent(const sp<IEventCallback> &callback);
+ explicit AttachedEvent(const sp<IEventCallback> &callback);
~AttachedEvent();
bool detach();
diff --git a/services/inputflinger/Android.bp b/services/inputflinger/Android.bp
index 0d8d34f..f73d498 100644
--- a/services/inputflinger/Android.bp
+++ b/services/inputflinger/Android.bp
@@ -16,20 +16,25 @@
name: "libinputflinger",
srcs: [
+ "InputClassifier.cpp",
"InputDispatcher.cpp",
"InputManager.cpp",
],
shared_libs: [
+ "android.hardware.input.classifier@1.0",
"libinputflinger_base",
+ "libinputreporter",
"libinputreader",
"libbase",
"libbinder",
"libcutils",
+ "libhidlbase",
"libinput",
"liblog",
"libutils",
"libui",
+ "server_configurable_flags",
],
cflags: [
@@ -37,7 +42,9 @@
"-Wextra",
"-Werror",
"-Wno-unused-parameter",
- // TODO: Move inputflinger to its own process and mark it hidden
+ // TODO(b/123097103): annotate InputDispatcher and uncomment the following line
+ //"-Wthread-safety",
+ // TODO(b/23084678): Move inputflinger to its own process and mark it hidden
//-fvisibility=hidden
],
@@ -75,7 +82,8 @@
"libutils",
"libui",
"libhardware_legacy",
- "libutils"
+ "libstatslog",
+ "libutils",
],
header_libs: [
@@ -125,6 +133,35 @@
],
}
+cc_library_shared {
+ name: "libinputreporter",
+
+ srcs: [
+ "InputReporter.cpp",
+ ],
+
+ shared_libs: [
+ "libbase",
+ "liblog",
+ "libutils",
+ ],
+
+ header_libs: [
+ "libinputflinger_headers",
+ ],
+
+ export_header_lib_headers: [
+ "libinputflinger_headers",
+ ],
+
+ cflags: [
+ "-Wall",
+ "-Wextra",
+ "-Werror",
+ "-Wno-unused-parameter",
+ ],
+}
+
subdirs = [
"host",
"tests",
diff --git a/services/inputflinger/BlockingQueue.h b/services/inputflinger/BlockingQueue.h
new file mode 100644
index 0000000..b892120
--- /dev/null
+++ b/services/inputflinger/BlockingQueue.h
@@ -0,0 +1,98 @@
+/*
+ * 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_INPUT_BLOCKING_QUEUE_H
+#define _UI_INPUT_BLOCKING_QUEUE_H
+
+#include <condition_variable>
+#include <mutex>
+#include <vector>
+
+namespace android {
+
+/**
+ * A FIFO queue that stores up to <i>capacity</i> objects.
+ * Objects can always be added. Objects are added immediately.
+ * If the queue is full, new objects cannot be added.
+ *
+ * The action of retrieving an object will block until an element is available.
+ */
+template <class T>
+class BlockingQueue {
+public:
+ BlockingQueue(size_t capacity) : mCapacity(capacity) {
+ mQueue.reserve(mCapacity);
+ };
+
+ /**
+ * Retrieve and remove the oldest object.
+ * Blocks execution while queue is empty.
+ */
+ T pop() {
+ std::unique_lock<std::mutex> lock(mLock);
+ mHasElements.wait(lock, [this]{ return !this->mQueue.empty(); });
+ T t = std::move(mQueue.front());
+ mQueue.erase(mQueue.begin());
+ return std::move(t);
+ };
+
+ /**
+ * Add a new object to the queue.
+ * Does not block.
+ * Return true if an element was successfully added.
+ * Return false if the queue is full.
+ */
+ bool push(T&& t) {
+ std::unique_lock<std::mutex> lock(mLock);
+ if (mQueue.size() == mCapacity) {
+ return false;
+ }
+ mQueue.push_back(std::move(t));
+ mHasElements.notify_one();
+ return true;
+ };
+
+ void erase(const std::function<bool(const T&)>& lambda) {
+ std::unique_lock<std::mutex> lock(mLock);
+ mQueue.erase(std::remove_if(mQueue.begin(), mQueue.end(),
+ [&lambda](const T& t) { return lambda(t); }), mQueue.end());
+ }
+
+ /**
+ * Remove all elements.
+ * Does not block.
+ */
+ void clear() {
+ std::scoped_lock lock(mLock);
+ mQueue.clear();
+ };
+
+private:
+ size_t mCapacity;
+ /**
+ * Used to signal that mQueue is non-empty.
+ */
+ std::condition_variable mHasElements;
+ /**
+ * Lock for accessing and waiting on elements.
+ */
+ std::mutex mLock;
+ std::vector<T> mQueue; //GUARDED_BY(mLock)
+};
+
+
+} // namespace android
+#endif
diff --git a/services/inputflinger/EventHub.cpp b/services/inputflinger/EventHub.cpp
index 18c3ded..cf9d3c7 100644
--- a/services/inputflinger/EventHub.cpp
+++ b/services/inputflinger/EventHub.cpp
@@ -40,6 +40,7 @@
#include <hardware_legacy/power.h>
#include <android-base/stringprintf.h>
+#include <cutils/properties.h>
#include <openssl/sha.h>
#include <utils/Log.h>
#include <utils/Timers.h>
@@ -108,6 +109,19 @@
return strstr(name, "v4l-touch") == name;
}
+/**
+ * Returns true if V4L devices should be scanned.
+ *
+ * The system property ro.input.video_enabled can be used to control whether
+ * EventHub scans and opens V4L devices. As V4L does not support multiple
+ * clients, EventHub effectively blocks access to these devices when it opens
+ * them. This property enables other clients to read these devices for testing
+ * and development.
+ */
+static bool isV4lScanningEnabled() {
+ return property_get_bool("ro.input.video_enabled", true /* default_value */);
+}
+
static nsecs_t processEventTimestamp(const struct input_event& event) {
// Use the time specified in the event instead of the current time
// so that downstream code can get more accurate estimates of
@@ -237,9 +251,14 @@
mInputWd = inotify_add_watch(mINotifyFd, DEVICE_PATH, IN_DELETE | IN_CREATE);
LOG_ALWAYS_FATAL_IF(mInputWd < 0, "Could not register INotify for %s: %s",
DEVICE_PATH, strerror(errno));
- mVideoWd = inotify_add_watch(mINotifyFd, VIDEO_DEVICE_PATH, IN_DELETE | IN_CREATE);
- LOG_ALWAYS_FATAL_IF(mVideoWd < 0, "Could not register INotify for %s: %s",
- VIDEO_DEVICE_PATH, strerror(errno));
+ if (isV4lScanningEnabled()) {
+ mVideoWd = inotify_add_watch(mINotifyFd, VIDEO_DEVICE_PATH, IN_DELETE | IN_CREATE);
+ LOG_ALWAYS_FATAL_IF(mVideoWd < 0, "Could not register INotify for %s: %s",
+ VIDEO_DEVICE_PATH, strerror(errno));
+ } else {
+ mVideoWd = -1;
+ ALOGI("Video device scanning disabled");
+ }
struct epoll_event eventItem;
memset(&eventItem, 0, sizeof(eventItem));
@@ -1056,9 +1075,11 @@
if(result < 0) {
ALOGE("scan dir failed for %s", DEVICE_PATH);
}
- result = scanVideoDirLocked(VIDEO_DEVICE_PATH);
- if (result != OK) {
- ALOGE("scan video dir failed for %s", VIDEO_DEVICE_PATH);
+ if (isV4lScanningEnabled()) {
+ result = scanVideoDirLocked(VIDEO_DEVICE_PATH);
+ if (result != OK) {
+ ALOGE("scan video dir failed for %s", VIDEO_DEVICE_PATH);
+ }
}
if (mDevices.indexOfKey(VIRTUAL_KEYBOARD_ID) < 0) {
createVirtualKeyboardLocked();
diff --git a/services/inputflinger/InputClassifier.cpp b/services/inputflinger/InputClassifier.cpp
new file mode 100644
index 0000000..7ade0d4
--- /dev/null
+++ b/services/inputflinger/InputClassifier.cpp
@@ -0,0 +1,697 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "InputClassifier"
+
+#include "InputClassifier.h"
+
+#include <algorithm>
+#include <cmath>
+#include <inttypes.h>
+#include <log/log.h>
+#if defined(__linux__)
+ #include <pthread.h>
+#endif
+#include <server_configurable_flags/get_flags.h>
+
+#include <android/hardware/input/classifier/1.0/IInputClassifier.h>
+
+using android::hardware::hidl_bitfield;
+using android::hardware::hidl_vec;
+using namespace android::hardware::input;
+
+namespace android {
+
+static constexpr bool DEBUG = false;
+
+// Category (=namespace) name for the input settings that are applied at boot time
+static const char* INPUT_NATIVE_BOOT = "input_native_boot";
+// Feature flag name for the deep press feature
+static const char* DEEP_PRESS_ENABLED = "deep_press_enabled";
+
+//Max number of elements to store in mEvents.
+static constexpr size_t MAX_EVENTS = 5;
+
+template<class K, class V>
+static V getValueForKey(const std::unordered_map<K, V>& map, K key, V defaultValue) {
+ auto it = map.find(key);
+ if (it == map.end()) {
+ return defaultValue;
+ }
+ return it->second;
+}
+
+static common::V1_0::Source getSource(uint32_t source) {
+ static_assert(static_cast<common::V1_0::Source>(AINPUT_SOURCE_UNKNOWN) ==
+ common::V1_0::Source::UNKNOWN, "SOURCE_UNKNOWN mismatch");
+ static_assert(static_cast<common::V1_0::Source>(AINPUT_SOURCE_KEYBOARD) ==
+ common::V1_0::Source::KEYBOARD, "SOURCE_KEYBOARD mismatch");
+ static_assert(static_cast<common::V1_0::Source>(AINPUT_SOURCE_DPAD) ==
+ common::V1_0::Source::DPAD, "SOURCE_DPAD mismatch");
+ static_assert(static_cast<common::V1_0::Source>(AINPUT_SOURCE_GAMEPAD) ==
+ common::V1_0::Source::GAMEPAD, "SOURCE_GAMEPAD mismatch");
+ static_assert(static_cast<common::V1_0::Source>(AINPUT_SOURCE_TOUCHSCREEN) ==
+ common::V1_0::Source::TOUCHSCREEN, "SOURCE_TOUCHSCREEN mismatch");
+ static_assert(static_cast<common::V1_0::Source>(AINPUT_SOURCE_MOUSE) ==
+ common::V1_0::Source::MOUSE, "SOURCE_MOUSE mismatch");
+ static_assert(static_cast<common::V1_0::Source>(AINPUT_SOURCE_STYLUS) ==
+ common::V1_0::Source::STYLUS, "SOURCE_STYLUS mismatch");
+ static_assert(static_cast<common::V1_0::Source>(AINPUT_SOURCE_BLUETOOTH_STYLUS) ==
+ common::V1_0::Source::BLUETOOTH_STYLUS, "SOURCE_BLUETOOTH_STYLUS mismatch");
+ static_assert(static_cast<common::V1_0::Source>(AINPUT_SOURCE_TRACKBALL) ==
+ common::V1_0::Source::TRACKBALL, "SOURCE_TRACKBALL mismatch");
+ static_assert(static_cast<common::V1_0::Source>(AINPUT_SOURCE_MOUSE_RELATIVE) ==
+ common::V1_0::Source::MOUSE_RELATIVE, "SOURCE_MOUSE_RELATIVE mismatch");
+ static_assert(static_cast<common::V1_0::Source>(AINPUT_SOURCE_TOUCHPAD) ==
+ common::V1_0::Source::TOUCHPAD, "SOURCE_TOUCHPAD mismatch");
+ static_assert(static_cast<common::V1_0::Source>(AINPUT_SOURCE_TOUCH_NAVIGATION) ==
+ common::V1_0::Source::TOUCH_NAVIGATION, "SOURCE_TOUCH_NAVIGATION mismatch");
+ static_assert(static_cast<common::V1_0::Source>(AINPUT_SOURCE_JOYSTICK) ==
+ common::V1_0::Source::JOYSTICK, "SOURCE_JOYSTICK mismatch");
+ static_assert(static_cast<common::V1_0::Source>(AINPUT_SOURCE_ROTARY_ENCODER) ==
+ common::V1_0::Source::ROTARY_ENCODER, "SOURCE_ROTARY_ENCODER mismatch");
+ static_assert(static_cast<common::V1_0::Source>(AINPUT_SOURCE_ANY) ==
+ common::V1_0::Source::ANY, "SOURCE_ANY mismatch");
+ return static_cast<common::V1_0::Source>(source);
+}
+
+static common::V1_0::Action getAction(int32_t actionMasked) {
+ static_assert(static_cast<common::V1_0::Action>(AMOTION_EVENT_ACTION_DOWN) ==
+ common::V1_0::Action::DOWN, "ACTION_DOWN mismatch");
+ static_assert(static_cast<common::V1_0::Action>(AMOTION_EVENT_ACTION_UP) ==
+ common::V1_0::Action::UP, "ACTION_UP mismatch");
+ static_assert(static_cast<common::V1_0::Action>(AMOTION_EVENT_ACTION_MOVE) ==
+ common::V1_0::Action::MOVE, "ACTION_MOVE mismatch");
+ static_assert(static_cast<common::V1_0::Action>(AMOTION_EVENT_ACTION_CANCEL) ==
+ common::V1_0::Action::CANCEL, "ACTION_CANCEL mismatch");
+ static_assert(static_cast<common::V1_0::Action>(AMOTION_EVENT_ACTION_OUTSIDE) ==
+ common::V1_0::Action::OUTSIDE, "ACTION_OUTSIDE mismatch");
+ static_assert(static_cast<common::V1_0::Action>(AMOTION_EVENT_ACTION_POINTER_DOWN) ==
+ common::V1_0::Action::POINTER_DOWN, "ACTION_POINTER_DOWN mismatch");
+ static_assert(static_cast<common::V1_0::Action>(AMOTION_EVENT_ACTION_POINTER_UP) ==
+ common::V1_0::Action::POINTER_UP, "ACTION_POINTER_UP mismatch");
+ static_assert(static_cast<common::V1_0::Action>( AMOTION_EVENT_ACTION_HOVER_MOVE) ==
+ common::V1_0::Action::HOVER_MOVE, "ACTION_HOVER_MOVE mismatch");
+ static_assert(static_cast<common::V1_0::Action>(AMOTION_EVENT_ACTION_SCROLL) ==
+ common::V1_0::Action::SCROLL, "ACTION_SCROLL mismatch");
+ static_assert(static_cast<common::V1_0::Action>(AMOTION_EVENT_ACTION_HOVER_ENTER) ==
+ common::V1_0::Action::HOVER_ENTER, "ACTION_HOVER_ENTER mismatch");
+ static_assert(static_cast<common::V1_0::Action>(AMOTION_EVENT_ACTION_HOVER_EXIT) ==
+ common::V1_0::Action::HOVER_EXIT, "ACTION_HOVER_EXIT mismatch");
+ static_assert(static_cast<common::V1_0::Action>(AMOTION_EVENT_ACTION_BUTTON_PRESS) ==
+ common::V1_0::Action::BUTTON_PRESS, "ACTION_BUTTON_PRESS mismatch");
+ static_assert(static_cast<common::V1_0::Action>(AMOTION_EVENT_ACTION_BUTTON_RELEASE) ==
+ common::V1_0::Action::BUTTON_RELEASE, "ACTION_BUTTON_RELEASE mismatch");
+ return static_cast<common::V1_0::Action>(actionMasked);
+}
+
+static common::V1_0::Button getActionButton(int32_t actionButton) {
+ static_assert(static_cast<common::V1_0::Button>(0) ==
+ common::V1_0::Button::NONE, "BUTTON_NONE mismatch");
+ static_assert(static_cast<common::V1_0::Button>(AMOTION_EVENT_BUTTON_PRIMARY) ==
+ common::V1_0::Button::PRIMARY, "BUTTON_PRIMARY mismatch");
+ static_assert(static_cast<common::V1_0::Button>(AMOTION_EVENT_BUTTON_SECONDARY) ==
+ common::V1_0::Button::SECONDARY, "BUTTON_SECONDARY mismatch");
+ static_assert(static_cast<common::V1_0::Button>(AMOTION_EVENT_BUTTON_TERTIARY) ==
+ common::V1_0::Button::TERTIARY, "BUTTON_TERTIARY mismatch");
+ static_assert(static_cast<common::V1_0::Button>(AMOTION_EVENT_BUTTON_BACK) ==
+ common::V1_0::Button::BACK, "BUTTON_BACK mismatch");
+ static_assert(static_cast<common::V1_0::Button>(AMOTION_EVENT_BUTTON_FORWARD) ==
+ common::V1_0::Button::FORWARD, "BUTTON_FORWARD mismatch");
+ static_assert(static_cast<common::V1_0::Button>(AMOTION_EVENT_BUTTON_STYLUS_PRIMARY) ==
+ common::V1_0::Button::STYLUS_PRIMARY, "BUTTON_STYLUS_PRIMARY mismatch");
+ static_assert(static_cast<common::V1_0::Button>(AMOTION_EVENT_BUTTON_STYLUS_SECONDARY) ==
+ common::V1_0::Button::STYLUS_SECONDARY, "BUTTON_STYLUS_SECONDARY mismatch");
+ return static_cast<common::V1_0::Button>(actionButton);
+}
+
+static hidl_bitfield<common::V1_0::Flag> getFlags(int32_t flags) {
+ static_assert(static_cast<common::V1_0::Flag>(AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED) ==
+ common::V1_0::Flag::WINDOW_IS_OBSCURED);
+ static_assert(static_cast<common::V1_0::Flag>(AMOTION_EVENT_FLAG_IS_GENERATED_GESTURE) ==
+ common::V1_0::Flag::IS_GENERATED_GESTURE);
+ static_assert(static_cast<common::V1_0::Flag>(AMOTION_EVENT_FLAG_TAINTED) ==
+ common::V1_0::Flag::TAINTED);
+ return static_cast<hidl_bitfield<common::V1_0::Flag>>(flags);
+}
+
+static hidl_bitfield<common::V1_0::PolicyFlag> getPolicyFlags(int32_t flags) {
+ static_assert(static_cast<common::V1_0::PolicyFlag>(POLICY_FLAG_WAKE) ==
+ common::V1_0::PolicyFlag::WAKE);
+ static_assert(static_cast<common::V1_0::PolicyFlag>(POLICY_FLAG_VIRTUAL) ==
+ common::V1_0::PolicyFlag::VIRTUAL);
+ static_assert(static_cast<common::V1_0::PolicyFlag>(POLICY_FLAG_FUNCTION) ==
+ common::V1_0::PolicyFlag::FUNCTION);
+ static_assert(static_cast<common::V1_0::PolicyFlag>(POLICY_FLAG_GESTURE) ==
+ common::V1_0::PolicyFlag::GESTURE);
+ static_assert(static_cast<common::V1_0::PolicyFlag>(POLICY_FLAG_INJECTED) ==
+ common::V1_0::PolicyFlag::INJECTED);
+ static_assert(static_cast<common::V1_0::PolicyFlag>(POLICY_FLAG_TRUSTED) ==
+ common::V1_0::PolicyFlag::TRUSTED);
+ static_assert(static_cast<common::V1_0::PolicyFlag>(POLICY_FLAG_FILTERED) ==
+ common::V1_0::PolicyFlag::FILTERED);
+ static_assert(static_cast<common::V1_0::PolicyFlag>(POLICY_FLAG_DISABLE_KEY_REPEAT) ==
+ common::V1_0::PolicyFlag::DISABLE_KEY_REPEAT);
+ static_assert(static_cast<common::V1_0::PolicyFlag>(POLICY_FLAG_INTERACTIVE) ==
+ common::V1_0::PolicyFlag::INTERACTIVE);
+ static_assert(static_cast<common::V1_0::PolicyFlag>(POLICY_FLAG_PASS_TO_USER) ==
+ common::V1_0::PolicyFlag::PASS_TO_USER);
+ return static_cast<hidl_bitfield<common::V1_0::PolicyFlag>>(flags);
+}
+
+static hidl_bitfield<common::V1_0::EdgeFlag> getEdgeFlags(int32_t flags) {
+ static_assert(static_cast<common::V1_0::EdgeFlag>(AMOTION_EVENT_EDGE_FLAG_NONE) ==
+ common::V1_0::EdgeFlag::NONE);
+ static_assert(static_cast<common::V1_0::EdgeFlag>(AMOTION_EVENT_EDGE_FLAG_TOP) ==
+ common::V1_0::EdgeFlag::TOP);
+ static_assert(static_cast<common::V1_0::EdgeFlag>(AMOTION_EVENT_EDGE_FLAG_BOTTOM) ==
+ common::V1_0::EdgeFlag::BOTTOM);
+ static_assert(static_cast<common::V1_0::EdgeFlag>(AMOTION_EVENT_EDGE_FLAG_LEFT) ==
+ common::V1_0::EdgeFlag::LEFT);
+ static_assert(static_cast<common::V1_0::EdgeFlag>(AMOTION_EVENT_EDGE_FLAG_RIGHT) ==
+ common::V1_0::EdgeFlag::RIGHT);
+ return static_cast<hidl_bitfield<common::V1_0::EdgeFlag>>(flags);
+}
+
+static hidl_bitfield<common::V1_0::Meta> getMetastate(int32_t state) {
+ static_assert(static_cast<common::V1_0::Meta>(AMETA_NONE) ==
+ common::V1_0::Meta::NONE);
+ static_assert(static_cast<common::V1_0::Meta>(AMETA_ALT_ON) ==
+ common::V1_0::Meta::ALT_ON);
+ static_assert(static_cast<common::V1_0::Meta>(AMETA_ALT_LEFT_ON) ==
+ common::V1_0::Meta::ALT_LEFT_ON);
+ static_assert(static_cast<common::V1_0::Meta>(AMETA_ALT_RIGHT_ON) ==
+ common::V1_0::Meta::ALT_RIGHT_ON);
+ static_assert(static_cast<common::V1_0::Meta>(AMETA_SHIFT_ON) ==
+ common::V1_0::Meta::SHIFT_ON);
+ static_assert(static_cast<common::V1_0::Meta>(AMETA_SHIFT_LEFT_ON) ==
+ common::V1_0::Meta::SHIFT_LEFT_ON);
+ static_assert(static_cast<common::V1_0::Meta>(AMETA_SHIFT_RIGHT_ON) ==
+ common::V1_0::Meta::SHIFT_RIGHT_ON);
+ static_assert(static_cast<common::V1_0::Meta>(AMETA_SYM_ON) ==
+ common::V1_0::Meta::SYM_ON);
+ static_assert(static_cast<common::V1_0::Meta>(AMETA_FUNCTION_ON) ==
+ common::V1_0::Meta::FUNCTION_ON);
+ static_assert(static_cast<common::V1_0::Meta>(AMETA_CTRL_ON) ==
+ common::V1_0::Meta::CTRL_ON);
+ static_assert(static_cast<common::V1_0::Meta>(AMETA_CTRL_LEFT_ON) ==
+ common::V1_0::Meta::CTRL_LEFT_ON);
+ static_assert(static_cast<common::V1_0::Meta>(AMETA_CTRL_RIGHT_ON) ==
+ common::V1_0::Meta::CTRL_RIGHT_ON);
+ static_assert(static_cast<common::V1_0::Meta>(AMETA_META_ON) ==
+ common::V1_0::Meta::META_ON);
+ static_assert(static_cast<common::V1_0::Meta>(AMETA_META_LEFT_ON) ==
+ common::V1_0::Meta::META_LEFT_ON);
+ static_assert(static_cast<common::V1_0::Meta>(AMETA_META_RIGHT_ON) ==
+ common::V1_0::Meta::META_RIGHT_ON);
+ static_assert(static_cast<common::V1_0::Meta>(AMETA_CAPS_LOCK_ON) ==
+ common::V1_0::Meta::CAPS_LOCK_ON);
+ static_assert(static_cast<common::V1_0::Meta>(AMETA_NUM_LOCK_ON) ==
+ common::V1_0::Meta::NUM_LOCK_ON);
+ static_assert(static_cast<common::V1_0::Meta>(AMETA_SCROLL_LOCK_ON) ==
+ common::V1_0::Meta::SCROLL_LOCK_ON);
+ return static_cast<hidl_bitfield<common::V1_0::Meta>>(state);
+}
+
+static hidl_bitfield<common::V1_0::Button> getButtonState(int32_t buttonState) {
+ // No need for static_assert here.
+ // The button values have already been asserted in getActionButton(..) above
+ return static_cast<hidl_bitfield<common::V1_0::Button>>(buttonState);
+}
+
+static common::V1_0::ToolType getToolType(int32_t toolType) {
+ static_assert(static_cast<common::V1_0::ToolType>(AMOTION_EVENT_TOOL_TYPE_UNKNOWN) ==
+ common::V1_0::ToolType::UNKNOWN);
+ static_assert(static_cast<common::V1_0::ToolType>(AMOTION_EVENT_TOOL_TYPE_FINGER) ==
+ common::V1_0::ToolType::FINGER);
+ static_assert(static_cast<common::V1_0::ToolType>(AMOTION_EVENT_TOOL_TYPE_STYLUS) ==
+ common::V1_0::ToolType::STYLUS);
+ static_assert(static_cast<common::V1_0::ToolType>(AMOTION_EVENT_TOOL_TYPE_MOUSE) ==
+ common::V1_0::ToolType::MOUSE);
+ static_assert(static_cast<common::V1_0::ToolType>(AMOTION_EVENT_TOOL_TYPE_ERASER) ==
+ common::V1_0::ToolType::ERASER);
+ return static_cast<common::V1_0::ToolType>(toolType);
+}
+
+static common::V1_0::Axis getAxis(uint64_t axis) {
+ static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_X) ==
+ common::V1_0::Axis::X);
+ static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_Y) ==
+ common::V1_0::Axis::Y);
+ static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_PRESSURE) ==
+ common::V1_0::Axis::PRESSURE);
+ static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_SIZE) ==
+ common::V1_0::Axis::SIZE);
+ static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_TOUCH_MAJOR) ==
+ common::V1_0::Axis::TOUCH_MAJOR);
+ static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_TOUCH_MINOR) ==
+ common::V1_0::Axis::TOUCH_MINOR);
+ static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_TOOL_MAJOR) ==
+ common::V1_0::Axis::TOOL_MAJOR);
+ static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_TOOL_MINOR) ==
+ common::V1_0::Axis::TOOL_MINOR);
+ static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_ORIENTATION) ==
+ common::V1_0::Axis::ORIENTATION);
+ static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_VSCROLL) ==
+ common::V1_0::Axis::VSCROLL);
+ static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_HSCROLL) ==
+ common::V1_0::Axis::HSCROLL);
+ static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_Z) ==
+ common::V1_0::Axis::Z);
+ static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_RX) ==
+ common::V1_0::Axis::RX);
+ static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_RY) ==
+ common::V1_0::Axis::RY);
+ static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_RZ) ==
+ common::V1_0::Axis::RZ);
+ static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_HAT_X) ==
+ common::V1_0::Axis::HAT_X);
+ static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_HAT_Y) ==
+ common::V1_0::Axis::HAT_Y);
+ static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_LTRIGGER) ==
+ common::V1_0::Axis::LTRIGGER);
+ static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_RTRIGGER) ==
+ common::V1_0::Axis::RTRIGGER);
+ static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_THROTTLE) ==
+ common::V1_0::Axis::THROTTLE);
+ static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_RUDDER) ==
+ common::V1_0::Axis::RUDDER);
+ static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_WHEEL) ==
+ common::V1_0::Axis::WHEEL);
+ static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_GAS) ==
+ common::V1_0::Axis::GAS);
+ static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_BRAKE) ==
+ common::V1_0::Axis::BRAKE);
+ static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_DISTANCE) ==
+ common::V1_0::Axis::DISTANCE);
+ static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_TILT) ==
+ common::V1_0::Axis::TILT);
+ static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_SCROLL) ==
+ common::V1_0::Axis::SCROLL);
+ static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_RELATIVE_X) ==
+ common::V1_0::Axis::RELATIVE_X);
+ static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_RELATIVE_Y) ==
+ common::V1_0::Axis::RELATIVE_Y);
+ static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_GENERIC_1) ==
+ common::V1_0::Axis::GENERIC_1);
+ static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_GENERIC_2) ==
+ common::V1_0::Axis::GENERIC_2);
+ static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_GENERIC_3) ==
+ common::V1_0::Axis::GENERIC_3);
+ static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_GENERIC_4) ==
+ common::V1_0::Axis::GENERIC_4);
+ static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_GENERIC_5) ==
+ common::V1_0::Axis::GENERIC_5);
+ static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_GENERIC_6) ==
+ common::V1_0::Axis::GENERIC_6);
+ static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_GENERIC_7) ==
+ common::V1_0::Axis::GENERIC_7);
+ static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_GENERIC_8) ==
+ common::V1_0::Axis::GENERIC_8);
+ static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_GENERIC_9) ==
+ common::V1_0::Axis::GENERIC_9);
+ static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_GENERIC_10) ==
+ common::V1_0::Axis::GENERIC_10);
+ static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_GENERIC_11) ==
+ common::V1_0::Axis::GENERIC_11);
+ static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_GENERIC_12) ==
+ common::V1_0::Axis::GENERIC_12);
+ static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_GENERIC_13) ==
+ common::V1_0::Axis::GENERIC_13);
+ static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_GENERIC_14) ==
+ common::V1_0::Axis::GENERIC_14);
+ static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_GENERIC_15) ==
+ common::V1_0::Axis::GENERIC_15);
+ static_assert(static_cast<common::V1_0::Axis>(AMOTION_EVENT_AXIS_GENERIC_16) ==
+ common::V1_0::Axis::GENERIC_16);
+ return static_cast<common::V1_0::Axis>(axis);
+}
+
+static common::V1_0::VideoFrame getHalVideoFrame(const TouchVideoFrame& frame) {
+ common::V1_0::VideoFrame out;
+ out.width = frame.getWidth();
+ out.height = frame.getHeight();
+ out.data = frame.getData();
+ struct timeval timestamp = frame.getTimestamp();
+ out.timestamp = seconds_to_nanoseconds(timestamp.tv_sec) +
+ microseconds_to_nanoseconds(timestamp.tv_usec);
+ return out;
+}
+
+static std::vector<common::V1_0::VideoFrame> convertVideoFrames(
+ const std::vector<TouchVideoFrame>& frames) {
+ std::vector<common::V1_0::VideoFrame> out;
+ for (const TouchVideoFrame& frame : frames) {
+ out.push_back(getHalVideoFrame(frame));
+ }
+ return out;
+}
+
+static uint8_t getActionIndex(int32_t action) {
+ return (action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >>
+ AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
+}
+
+static void getHidlPropertiesAndCoords(const NotifyMotionArgs& args,
+ std::vector<common::V1_0::PointerProperties>* outPointerProperties,
+ std::vector<common::V1_0::PointerCoords>* outPointerCoords) {
+ outPointerProperties->reserve(args.pointerCount);
+ outPointerCoords->reserve(args.pointerCount);
+ for (size_t i = 0; i < args.pointerCount; i++) {
+ common::V1_0::PointerProperties properties;
+ properties.id = args.pointerProperties[i].id;
+ properties.toolType = getToolType(args.pointerProperties[i].toolType);
+ outPointerProperties->push_back(properties);
+
+ common::V1_0::PointerCoords coords;
+ BitSet64 bits (args.pointerCoords[i].bits);
+ std::vector<float> values;
+ size_t index = 0;
+ while (!bits.isEmpty()) {
+ uint32_t axis = bits.clearFirstMarkedBit();
+ coords.bits |= 1 << static_cast<uint64_t>(getAxis(axis));
+ float value = args.pointerCoords[i].values[index++];
+ values.push_back(value);
+ }
+ coords.values = values;
+ outPointerCoords->push_back(coords);
+ }
+}
+
+static common::V1_0::MotionEvent getMotionEvent(const NotifyMotionArgs& args) {
+ common::V1_0::MotionEvent event;
+ event.deviceId = args.deviceId;
+ event.source = getSource(args.source);
+ event.displayId = args.displayId;
+ event.downTime = args.downTime;
+ event.eventTime = args.eventTime;
+ event.action = getAction(args.action & AMOTION_EVENT_ACTION_MASK);
+ event.actionIndex = getActionIndex(args.action);
+ event.actionButton = getActionButton(args.actionButton);
+ event.flags = getFlags(args.flags);
+ event.policyFlags = getPolicyFlags(args.policyFlags);
+ event.edgeFlags = getEdgeFlags(args.edgeFlags);
+ event.metaState = getMetastate(args.metaState);
+ event.buttonState = getButtonState(args.buttonState);
+ event.xPrecision = args.xPrecision;
+ event.yPrecision = args.yPrecision;
+
+ std::vector<common::V1_0::PointerProperties> pointerProperties;
+ std::vector<common::V1_0::PointerCoords> pointerCoords;
+ getHidlPropertiesAndCoords(args, /*out*/&pointerProperties, /*out*/&pointerCoords);
+ event.pointerProperties = pointerProperties;
+ event.pointerCoords = pointerCoords;
+
+ event.deviceTimestamp = args.deviceTimestamp;
+ event.frames = convertVideoFrames(args.videoFrames);
+
+ return event;
+}
+
+static MotionClassification getMotionClassification(common::V1_0::Classification classification) {
+ static_assert(MotionClassification::NONE ==
+ static_cast<MotionClassification>(common::V1_0::Classification::NONE));
+ static_assert(MotionClassification::AMBIGUOUS_GESTURE ==
+ static_cast<MotionClassification>(common::V1_0::Classification::AMBIGUOUS_GESTURE));
+ static_assert(MotionClassification::DEEP_PRESS ==
+ static_cast<MotionClassification>(common::V1_0::Classification::DEEP_PRESS));
+ return static_cast<MotionClassification>(classification);
+}
+
+static bool isTouchEvent(const NotifyMotionArgs& args) {
+ return args.source == AINPUT_SOURCE_TOUCHPAD || args.source == AINPUT_SOURCE_TOUCHSCREEN;
+}
+
+// Check if the "deep touch" feature is on.
+static bool deepPressEnabled() {
+ std::string flag_value = server_configurable_flags::GetServerConfigurableFlag(
+ INPUT_NATIVE_BOOT, DEEP_PRESS_ENABLED, "true");
+ std::transform(flag_value.begin(), flag_value.end(), flag_value.begin(), ::tolower);
+ if (flag_value == "1" || flag_value == "true") {
+ ALOGI("Deep press feature enabled.");
+ return true;
+ }
+ ALOGI("Deep press feature is not enabled.");
+ return false;
+}
+
+
+// --- ClassifierEvent ---
+
+ClassifierEvent::ClassifierEvent(std::unique_ptr<NotifyMotionArgs> args) :
+ type(ClassifierEventType::MOTION), args(std::move(args)) { };
+ClassifierEvent::ClassifierEvent(std::unique_ptr<NotifyDeviceResetArgs> args) :
+ type(ClassifierEventType::DEVICE_RESET), args(std::move(args)) { };
+ClassifierEvent::ClassifierEvent(ClassifierEventType type, std::unique_ptr<NotifyArgs> args) :
+ type(type), args(std::move(args)) { };
+
+ClassifierEvent::ClassifierEvent(ClassifierEvent&& other) :
+ type(other.type), args(std::move(other.args)) { };
+
+ClassifierEvent& ClassifierEvent::operator=(ClassifierEvent&& other) {
+ type = other.type;
+ args = std::move(other.args);
+ return *this;
+}
+
+ClassifierEvent ClassifierEvent::createHalResetEvent() {
+ return ClassifierEvent(ClassifierEventType::HAL_RESET, nullptr);
+}
+
+ClassifierEvent ClassifierEvent::createExitEvent() {
+ return ClassifierEvent(ClassifierEventType::EXIT, nullptr);
+}
+
+std::optional<int32_t> ClassifierEvent::getDeviceId() const {
+ switch (type) {
+ case ClassifierEventType::MOTION: {
+ NotifyMotionArgs* motionArgs = static_cast<NotifyMotionArgs*>(args.get());
+ return motionArgs->deviceId;
+ }
+ case ClassifierEventType::DEVICE_RESET: {
+ NotifyDeviceResetArgs* deviceResetArgs =
+ static_cast<NotifyDeviceResetArgs*>(args.get());
+ return deviceResetArgs->deviceId;
+ }
+ case ClassifierEventType::HAL_RESET: {
+ return std::nullopt;
+ }
+ case ClassifierEventType::EXIT: {
+ return std::nullopt;
+ }
+ }
+}
+
+// --- MotionClassifier ---
+
+MotionClassifier::MotionClassifier(
+ sp<android::hardware::input::classifier::V1_0::IInputClassifier> service) :
+ mEvents(MAX_EVENTS), mService(service) {
+ mHalThread = std::thread(&MotionClassifier::callInputClassifierHal, this);
+#if defined(__linux__)
+ // Set the thread name for debugging
+ pthread_setname_np(mHalThread.native_handle(), "InputClassifier");
+#endif
+ // Under normal operation, we do not need to reset the HAL here. But in the case where system
+ // crashed, but HAL didn't, we may be connecting to an existing HAL process that might already
+ // have received events in the past. That means, that HAL could be in an inconsistent state
+ // once it receives events from the newly created MotionClassifier.
+ mEvents.push(ClassifierEvent::createHalResetEvent());
+}
+
+MotionClassifier::~MotionClassifier() {
+ requestExit();
+ mHalThread.join();
+}
+
+void MotionClassifier::ensureHalThread(const char* function) {
+ if (DEBUG) {
+ if (std::this_thread::get_id() != mHalThread.get_id()) {
+ ALOGE("Function %s should only be called from InputClassifier thread", function);
+ }
+ }
+}
+
+/**
+ * Obtain the classification from the HAL for a given MotionEvent.
+ * Should only be called from the InputClassifier thread (mHalThread).
+ * Should not be called from the thread that notifyMotion runs on.
+ *
+ * There is no way to provide a timeout for a HAL call. So if the HAL takes too long
+ * to return a classification, this would directly impact the touch latency.
+ * To remove any possibility of negatively affecting the touch latency, the HAL
+ * is called from a dedicated thread.
+ */
+void MotionClassifier::callInputClassifierHal() {
+ ensureHalThread(__func__);
+ while (true) {
+ ClassifierEvent event = mEvents.pop();
+ switch (event.type) {
+ case ClassifierEventType::MOTION: {
+ NotifyMotionArgs* motionArgs = static_cast<NotifyMotionArgs*>(event.args.get());
+ common::V1_0::MotionEvent motionEvent = getMotionEvent(*motionArgs);
+ common::V1_0::Classification halClassification = mService->classify(motionEvent);
+ updateClassification(motionArgs->deviceId, motionArgs->eventTime,
+ getMotionClassification(halClassification));
+ break;
+ }
+ case ClassifierEventType::DEVICE_RESET: {
+ const int32_t deviceId = *(event.getDeviceId());
+ mService->resetDevice(deviceId);
+ setClassification(deviceId, MotionClassification::NONE);
+ break;
+ }
+ case ClassifierEventType::HAL_RESET: {
+ mService->reset();
+ clearClassifications();
+ break;
+ }
+ case ClassifierEventType::EXIT: {
+ clearClassifications();
+ return;
+ }
+ }
+ }
+}
+
+void MotionClassifier::requestExit() {
+ reset();
+ mEvents.push(ClassifierEvent::createExitEvent());
+}
+
+void MotionClassifier::updateClassification(int32_t deviceId, nsecs_t eventTime,
+ MotionClassification classification) {
+ std::scoped_lock lock(mLock);
+ const nsecs_t lastDownTime = getValueForKey(mLastDownTimes, deviceId, static_cast<nsecs_t>(0));
+ if (eventTime < lastDownTime) {
+ // HAL just finished processing an event that belonged to an earlier gesture,
+ // but new gesture is already in progress. Drop this classification.
+ ALOGW("Received late classification. Late by at least %" PRId64 " ms.",
+ nanoseconds_to_milliseconds(lastDownTime - eventTime));
+ return;
+ }
+ mClassifications[deviceId] = classification;
+}
+
+void MotionClassifier::setClassification(int32_t deviceId, MotionClassification classification) {
+ std::scoped_lock lock(mLock);
+ mClassifications[deviceId] = classification;
+}
+
+void MotionClassifier::clearClassifications() {
+ std::scoped_lock lock(mLock);
+ mClassifications.clear();
+}
+
+MotionClassification MotionClassifier::getClassification(int32_t deviceId) {
+ std::scoped_lock lock(mLock);
+ return getValueForKey(mClassifications, deviceId, MotionClassification::NONE);
+}
+
+void MotionClassifier::updateLastDownTime(int32_t deviceId, nsecs_t downTime) {
+ std::scoped_lock lock(mLock);
+ mLastDownTimes[deviceId] = downTime;
+ mClassifications[deviceId] = MotionClassification::NONE;
+}
+
+MotionClassification MotionClassifier::classify(const NotifyMotionArgs& args) {
+ if (!mService) {
+ // If HAL is not present, do nothing
+ return MotionClassification::NONE;
+ }
+ if ((args.action & AMOTION_EVENT_ACTION_MASK) == AMOTION_EVENT_ACTION_DOWN) {
+ updateLastDownTime(args.deviceId, args.downTime);
+ }
+
+ ClassifierEvent event(std::make_unique<NotifyMotionArgs>(args));
+ bool elementAdded = mEvents.push(std::move(event));
+ if (!elementAdded) {
+ // Queue should not ever overfill. Suspect HAL is slow.
+ ALOGE("Dropped element with eventTime %" PRIu64, args.eventTime);
+ reset();
+ return MotionClassification::NONE;
+ }
+ return getClassification(args.deviceId);
+}
+
+void MotionClassifier::reset() {
+ mEvents.clear();
+ mEvents.push(ClassifierEvent::createHalResetEvent());
+}
+
+/**
+ * Per-device reset. Clear the outstanding events that are going to be sent to HAL.
+ * Request InputClassifier thread to call resetDevice for this particular device.
+ */
+void MotionClassifier::reset(const NotifyDeviceResetArgs& args) {
+ int32_t deviceId = args.deviceId;
+ // Clear the pending events right away, to avoid unnecessary work done by the HAL.
+ mEvents.erase([deviceId](const ClassifierEvent& event) {
+ std::optional<int32_t> eventDeviceId = event.getDeviceId();
+ return eventDeviceId && (*eventDeviceId == deviceId);
+ });
+ mEvents.push(std::make_unique<NotifyDeviceResetArgs>(args));
+}
+
+// --- InputClassifier ---
+
+InputClassifier::InputClassifier(const sp<InputListenerInterface>& listener) :
+ mListener(listener) {
+ if (deepPressEnabled()) {
+ sp<android::hardware::input::classifier::V1_0::IInputClassifier> service =
+ classifier::V1_0::IInputClassifier::getService();
+ if (service) {
+ mMotionClassifier = std::make_unique<MotionClassifier>(service);
+ } else {
+ ALOGI("Could not obtain InputClassifier HAL");
+ }
+ }
+};
+
+void InputClassifier::notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) {
+ // pass through
+ mListener->notifyConfigurationChanged(args);
+}
+
+void InputClassifier::notifyKey(const NotifyKeyArgs* args) {
+ // pass through
+ mListener->notifyKey(args);
+}
+
+void InputClassifier::notifyMotion(const NotifyMotionArgs* args) {
+ if (mMotionClassifier && isTouchEvent(*args)) {
+ // We only cover touch events, for now.
+ NotifyMotionArgs newArgs = NotifyMotionArgs(*args);
+ newArgs.classification = mMotionClassifier->classify(newArgs);
+ args = &newArgs;
+ }
+ mListener->notifyMotion(args);
+}
+
+void InputClassifier::notifySwitch(const NotifySwitchArgs* args) {
+ // pass through
+ mListener->notifySwitch(args);
+}
+
+void InputClassifier::notifyDeviceReset(const NotifyDeviceResetArgs* args) {
+ if (mMotionClassifier) {
+ mMotionClassifier->reset(*args);
+ }
+ // continue to next stage
+ mListener->notifyDeviceReset(args);
+}
+
+} // namespace android
\ No newline at end of file
diff --git a/services/inputflinger/InputClassifier.h b/services/inputflinger/InputClassifier.h
new file mode 100644
index 0000000..cb46494
--- /dev/null
+++ b/services/inputflinger/InputClassifier.h
@@ -0,0 +1,196 @@
+/*
+ * 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_INPUT_CLASSIFIER_H
+#define _UI_INPUT_CLASSIFIER_H
+
+#include <utils/RefBase.h>
+#include <unordered_map>
+#include <thread>
+
+#include "BlockingQueue.h"
+#include "InputListener.h"
+#include <android/hardware/input/classifier/1.0/IInputClassifier.h>
+
+namespace android {
+
+enum class ClassifierEventType : uint8_t {
+ MOTION = 0,
+ DEVICE_RESET = 1,
+ HAL_RESET = 2,
+ EXIT = 3,
+};
+
+struct ClassifierEvent {
+ ClassifierEventType type;
+ std::unique_ptr<NotifyArgs> args;
+
+ ClassifierEvent(ClassifierEventType type, std::unique_ptr<NotifyArgs> args);
+ ClassifierEvent(std::unique_ptr<NotifyMotionArgs> args);
+ ClassifierEvent(std::unique_ptr<NotifyDeviceResetArgs> args);
+ ClassifierEvent(ClassifierEvent&& other);
+ ClassifierEvent& operator=(ClassifierEvent&& other);
+
+ // Convenience function to create a HAL_RESET event
+ static ClassifierEvent createHalResetEvent();
+ // Convenience function to create an EXIT event
+ static ClassifierEvent createExitEvent();
+
+ std::optional<int32_t> getDeviceId() const;
+};
+
+// --- Interfaces ---
+
+/**
+ * Interface for adding a MotionClassification to NotifyMotionArgs.
+ *
+ * To implement, override the classify function.
+ */
+class MotionClassifierInterface {
+public:
+ MotionClassifierInterface() { }
+ virtual ~MotionClassifierInterface() { }
+ /**
+ * Based on the motion event described by NotifyMotionArgs,
+ * provide a MotionClassification for the current gesture.
+ */
+ virtual MotionClassification classify(const NotifyMotionArgs& args) = 0;
+ virtual void reset() = 0;
+ virtual void reset(const NotifyDeviceResetArgs& args) = 0;
+};
+
+/**
+ * Base interface for an InputListener stage.
+ * Provides classification to events.
+ */
+class InputClassifierInterface : public virtual RefBase, public InputListenerInterface {
+protected:
+ InputClassifierInterface() { }
+ virtual ~InputClassifierInterface() { }
+};
+
+// --- Implementations ---
+
+/**
+ * Implementation of MotionClassifierInterface that calls the InputClassifier HAL
+ * in order to determine the classification for the current gesture.
+ *
+ * The InputClassifier HAL may keep track of the entire gesture in order to determine
+ * the classification, and may be hardware-specific. It may use the data in
+ * NotifyMotionArgs::videoFrames field to drive the classification decisions.
+ * The HAL is called from a separate thread.
+ */
+class MotionClassifier final : public MotionClassifierInterface {
+public:
+ MotionClassifier(sp<android::hardware::input::classifier::V1_0::IInputClassifier> service);
+ ~MotionClassifier();
+ /**
+ * Classifies events asynchronously; that is, it doesn't block events on a classification,
+ * but instead sends them over to the classifier HAL
+ * and after a classification is determined,
+ * it then marks the next event it sees in the stream with it.
+ *
+ * Therefore, it is acceptable to have the classifications be delayed by 1-2 events
+ * in a particular gesture.
+ */
+ virtual MotionClassification classify(const NotifyMotionArgs& args) override;
+ virtual void reset() override;
+ virtual void reset(const NotifyDeviceResetArgs& args) override;
+
+private:
+ // The events that need to be sent to the HAL.
+ BlockingQueue<ClassifierEvent> mEvents;
+ /**
+ * Thread that will communicate with InputClassifier HAL.
+ * This should be the only thread that communicates with InputClassifier HAL,
+ * because this thread is allowed to block on the HAL calls.
+ */
+ std::thread mHalThread;
+ /**
+ * Print an error message if the caller is not on the InputClassifier thread.
+ * Caller must supply the name of the calling function as __function__
+ */
+ void ensureHalThread(const char* function);
+ /**
+ * Call the InputClassifier HAL
+ */
+ void callInputClassifierHal();
+ /**
+ * Access to the InputClassifier HAL
+ */
+ sp<android::hardware::input::classifier::V1_0::IInputClassifier> mService;
+ std::mutex mLock;
+ /**
+ * Per-device input classifications. Should only be accessed using the
+ * getClassification / setClassification methods.
+ */
+ std::unordered_map<int32_t /*deviceId*/, MotionClassification>
+ mClassifications; //GUARDED_BY(mLock);
+ /**
+ * Set the current classification for a given device.
+ */
+ void setClassification(int32_t deviceId, MotionClassification classification);
+ /**
+ * Get the current classification for a given device.
+ */
+ MotionClassification getClassification(int32_t deviceId);
+ void updateClassification(int32_t deviceId, nsecs_t eventTime,
+ MotionClassification classification);
+ /**
+ * Clear all current classifications
+ */
+ void clearClassifications();
+ /**
+ * Per-device times when the last ACTION_DOWN was received.
+ * Used to reject late classifications that do not belong to the current gesture.
+ *
+ * Accessed indirectly by both InputClassifier thread and the thread that receives notifyMotion.
+ */
+ std::unordered_map<int32_t /*deviceId*/, nsecs_t /*downTime*/>
+ mLastDownTimes; //GUARDED_BY(mLock);
+ void updateLastDownTime(int32_t deviceId, nsecs_t downTime);
+
+ /**
+ * Exit the InputClassifier HAL thread.
+ * Useful for tests to ensure proper cleanup.
+ */
+ void requestExit();
+};
+
+/**
+ * Implementation of the InputClassifierInterface.
+ * Represents a separate stage of input processing. All of the input events go through this stage.
+ * Acts as a passthrough for all input events except for motion events.
+ * The events of motion type are sent to MotionClassifier.
+ */
+class InputClassifier : public InputClassifierInterface {
+public:
+ explicit InputClassifier(const sp<InputListenerInterface>& listener);
+
+ virtual void notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) override;
+ virtual void notifyKey(const NotifyKeyArgs* args) override;
+ virtual void notifyMotion(const NotifyMotionArgs* args) override;
+ virtual void notifySwitch(const NotifySwitchArgs* args) override;
+ virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args) override;
+
+private:
+ std::unique_ptr<MotionClassifierInterface> mMotionClassifier = nullptr;
+ // The next stage to pass input events to
+ sp<InputListenerInterface> mListener;
+};
+
+} // namespace android
+#endif
diff --git a/services/inputflinger/InputDispatcher.cpp b/services/inputflinger/InputDispatcher.cpp
index 7fa9cb6..9702fb2 100644
--- a/services/inputflinger/InputDispatcher.cpp
+++ b/services/inputflinger/InputDispatcher.cpp
@@ -215,10 +215,6 @@
return true;
}
-static bool isMainDisplay(int32_t displayId) {
- return displayId == ADISPLAY_ID_DEFAULT || displayId == ADISPLAY_ID_NONE;
-}
-
static void dumpRegion(std::string& dump, const Region& region) {
if (region.isEmpty()) {
dump += "<empty>";
@@ -257,6 +253,7 @@
mFocusedDisplayId(ADISPLAY_ID_DEFAULT),
mInputTargetWaitCause(INPUT_TARGET_WAIT_CAUSE_NONE) {
mLooper = new Looper(false);
+ mReporter = createInputReporter();
mKeyRepeatState.lastKeyEntry = nullptr;
@@ -524,7 +521,7 @@
}
sp<InputWindowHandle> InputDispatcher::findTouchedWindowAtLocked(int32_t displayId,
- int32_t x, int32_t y) {
+ int32_t x, int32_t y, bool addOutsideTargets, bool addPortalWindows) {
// Traverse windows from front to back to find touched window.
const Vector<sp<InputWindowHandle>> windowHandles = getWindowHandlesLocked(displayId);
size_t numWindows = windowHandles.size();
@@ -539,10 +536,25 @@
bool isTouchModal = (flags & (InputWindowInfo::FLAG_NOT_FOCUSABLE
| InputWindowInfo::FLAG_NOT_TOUCH_MODAL)) == 0;
if (isTouchModal || windowInfo->touchableRegionContainsPoint(x, y)) {
+ int32_t portalToDisplayId = windowInfo->portalToDisplayId;
+ if (portalToDisplayId != ADISPLAY_ID_NONE
+ && portalToDisplayId != displayId) {
+ if (addPortalWindows) {
+ // For the monitoring channels of the display.
+ mTempTouchState.addPortalWindow(windowHandle);
+ }
+ return findTouchedWindowAtLocked(
+ portalToDisplayId, x, y, addOutsideTargets, addPortalWindows);
+ }
// Found window.
return windowHandle;
}
}
+
+ if (addOutsideTargets && (flags & InputWindowInfo::FLAG_WATCH_OUTSIDE_TOUCH)) {
+ mTempTouchState.addOrUpdateWindow(
+ windowHandle, InputTarget::FLAG_DISPATCH_AS_OUTSIDE, BitSet32(0));
+ }
}
}
}
@@ -841,6 +853,7 @@
if (*dropReason != DROP_REASON_NOT_DROPPED) {
setInjectionResultLocked(entry, *dropReason == DROP_REASON_POLICY
? INPUT_EVENT_INJECTION_SUCCEEDED : INPUT_EVENT_INJECTION_FAILED);
+ mReporter->reportDroppedKey(entry->sequenceNum);
return true;
}
@@ -928,6 +941,22 @@
// Add monitor channels from event's or focused display.
addMonitoringTargetsLocked(inputTargets, getTargetDisplayId(entry));
+ if (isPointerEvent) {
+ ssize_t stateIndex = mTouchStatesByDisplay.indexOfKey(entry->displayId);
+ if (stateIndex >= 0) {
+ const TouchState& state = mTouchStatesByDisplay.valueAt(stateIndex);
+ if (!state.portalWindows.isEmpty()) {
+ // The event has gone through these portal windows, so we add monitoring targets of
+ // the corresponding displays as well.
+ for (size_t i = 0; i < state.portalWindows.size(); i++) {
+ const InputWindowInfo* windowInfo = state.portalWindows.itemAt(i)->getInfo();
+ addMonitoringTargetsLocked(inputTargets, windowInfo->portalToDisplayId,
+ -windowInfo->frameLeft, -windowInfo->frameTop);
+ }
+ }
+ }
+ }
+
// Dispatch the motion.
if (conflictingPointerActions) {
CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS,
@@ -1295,37 +1324,8 @@
getAxisValue(AMOTION_EVENT_AXIS_X));
int32_t y = int32_t(entry->pointerCoords[pointerIndex].
getAxisValue(AMOTION_EVENT_AXIS_Y));
- sp<InputWindowHandle> newTouchedWindowHandle;
- bool isTouchModal = false;
-
- // Traverse windows from front to back to find touched window and outside targets.
- const Vector<sp<InputWindowHandle>> windowHandles = getWindowHandlesLocked(displayId);
- size_t numWindows = windowHandles.size();
- for (size_t i = 0; i < numWindows; i++) {
- sp<InputWindowHandle> windowHandle = windowHandles.itemAt(i);
- const InputWindowInfo* windowInfo = windowHandle->getInfo();
- if (windowInfo->displayId != displayId) {
- continue; // wrong display
- }
-
- int32_t flags = windowInfo->layoutParamsFlags;
- if (windowInfo->visible) {
- if (! (flags & InputWindowInfo::FLAG_NOT_TOUCHABLE)) {
- isTouchModal = (flags & (InputWindowInfo::FLAG_NOT_FOCUSABLE
- | InputWindowInfo::FLAG_NOT_TOUCH_MODAL)) == 0;
- if (isTouchModal || windowInfo->touchableRegionContainsPoint(x, y)) {
- newTouchedWindowHandle = windowHandle;
- break; // found touched window, exit window loop
- }
- }
-
- if (maskedAction == AMOTION_EVENT_ACTION_DOWN
- && (flags & InputWindowInfo::FLAG_WATCH_OUTSIDE_TOUCH)) {
- mTempTouchState.addOrUpdateWindow(
- windowHandle, InputTarget::FLAG_DISPATCH_AS_OUTSIDE, BitSet32(0));
- }
- }
- }
+ sp<InputWindowHandle> newTouchedWindowHandle = findTouchedWindowAtLocked(
+ displayId, x, y, maskedAction == AMOTION_EVENT_ACTION_DOWN, true);
// Figure out whether splitting will be allowed for this window.
if (newTouchedWindowHandle != nullptr
@@ -1687,7 +1687,7 @@
}
void InputDispatcher::addMonitoringTargetsLocked(Vector<InputTarget>& inputTargets,
- int32_t displayId) {
+ int32_t displayId, float xOffset, float yOffset) {
std::unordered_map<int32_t, Vector<sp<InputChannel>>>::const_iterator it =
mMonitoringChannelsByDisplay.find(displayId);
@@ -1700,8 +1700,8 @@
InputTarget& target = inputTargets.editTop();
target.inputChannel = monitoringChannels[i];
target.flags = InputTarget::FLAG_DISPATCH_AS_IS;
- target.xOffset = 0;
- target.yOffset = 0;
+ target.xOffset = xOffset;
+ target.yOffset = yOffset;
target.pointerIds.clear();
target.globalScaleFactor = 1.0f;
}
@@ -2153,7 +2153,7 @@
motionEntry->deviceId, motionEntry->source, motionEntry->displayId,
dispatchEntry->resolvedAction, motionEntry->actionButton,
dispatchEntry->resolvedFlags, motionEntry->edgeFlags,
- motionEntry->metaState, motionEntry->buttonState,
+ motionEntry->metaState, motionEntry->buttonState, motionEntry->classification,
xOffset, yOffset, motionEntry->xPrecision, motionEntry->yPrecision,
motionEntry->downTime, motionEntry->eventTime,
motionEntry->pointerCount, motionEntry->pointerProperties,
@@ -2384,7 +2384,8 @@
}
InputTarget target;
- sp<InputWindowHandle> windowHandle = getWindowHandleLocked(connection->inputChannel);
+ sp<InputWindowHandle> windowHandle = getWindowHandleLocked(
+ connection->inputChannel->getToken());
if (windowHandle != nullptr) {
const InputWindowInfo* windowInfo = windowHandle->getInfo();
target.xOffset = -windowInfo->frameLeft;
@@ -2488,6 +2489,7 @@
originalMotionEntry->flags,
originalMotionEntry->metaState,
originalMotionEntry->buttonState,
+ originalMotionEntry->classification,
originalMotionEntry->edgeFlags,
originalMotionEntry->xPrecision,
originalMotionEntry->yPrecision,
@@ -2688,7 +2690,7 @@
event.initialize(args->deviceId, args->source, args->displayId,
args->action, args->actionButton,
args->flags, args->edgeFlags, args->metaState, args->buttonState,
- 0, 0, args->xPrecision, args->yPrecision,
+ args->classification, 0, 0, args->xPrecision, args->yPrecision,
args->downTime, args->eventTime,
args->pointerCount, args->pointerProperties, args->pointerCoords);
@@ -2704,7 +2706,7 @@
MotionEntry* newEntry = new MotionEntry(args->sequenceNum, args->eventTime,
args->deviceId, args->source, args->displayId, policyFlags,
args->action, args->actionButton, args->flags,
- args->metaState, args->buttonState,
+ args->metaState, args->buttonState, args->classification,
args->edgeFlags, args->xPrecision, args->yPrecision, args->downTime,
args->pointerCount, args->pointerProperties, args->pointerCoords, 0, 0);
@@ -2718,8 +2720,7 @@
}
bool InputDispatcher::shouldSendMotionToInputFilterLocked(const NotifyMotionArgs* args) {
- // TODO: support sending secondary display events to input filter
- return mInputFilterEnabled && isMainDisplay(args->displayId);
+ return mInputFilterEnabled;
}
void InputDispatcher::notifySwitch(const NotifySwitchArgs* args) {
@@ -2842,7 +2843,7 @@
policyFlags,
action, actionButton, motionEvent->getFlags(),
motionEvent->getMetaState(), motionEvent->getButtonState(),
- motionEvent->getEdgeFlags(),
+ motionEvent->getClassification(), motionEvent->getEdgeFlags(),
motionEvent->getXPrecision(), motionEvent->getYPrecision(),
motionEvent->getDownTime(),
uint32_t(pointerCount), pointerProperties, samplePointerCoords,
@@ -2857,7 +2858,7 @@
motionEvent->getDisplayId(), policyFlags,
action, actionButton, motionEvent->getFlags(),
motionEvent->getMetaState(), motionEvent->getButtonState(),
- motionEvent->getEdgeFlags(),
+ motionEvent->getClassification(), motionEvent->getEdgeFlags(),
motionEvent->getXPrecision(), motionEvent->getYPrecision(),
motionEvent->getDownTime(),
uint32_t(pointerCount), pointerProperties, samplePointerCoords,
@@ -3022,13 +3023,13 @@
}
sp<InputWindowHandle> InputDispatcher::getWindowHandleLocked(
- const sp<InputChannel>& inputChannel) const {
+ const sp<IBinder>& windowHandleToken) const {
for (auto& it : mWindowHandlesByDisplay) {
const Vector<sp<InputWindowHandle>> windowHandles = it.second;
size_t numWindows = windowHandles.size();
for (size_t i = 0; i < numWindows; i++) {
const sp<InputWindowHandle>& windowHandle = windowHandles.itemAt(i);
- if (windowHandle->getToken() == inputChannel->getToken()) {
+ if (windowHandle->getToken() == windowHandleToken) {
return windowHandle;
}
}
@@ -3103,7 +3104,8 @@
Vector<sp<InputWindowHandle>> newHandles;
for (size_t i = 0; i < numWindows; i++) {
const sp<InputWindowHandle>& handle = inputWindowHandles.itemAt(i);
- if (!handle->updateInfo() || getInputChannelLocked(handle->getToken()) == nullptr) {
+ if (!handle->updateInfo() || (getInputChannelLocked(handle->getToken()) == nullptr
+ && handle->getInfo()->portalToDisplayId == ADISPLAY_ID_NONE)) {
ALOGE("Window handle %s has no registered input channel",
handle->getName().c_str());
continue;
@@ -3128,7 +3130,9 @@
for (size_t i = 0; i < newHandles.size(); i++) {
const sp<InputWindowHandle>& windowHandle = newHandles.itemAt(i);
- if (windowHandle->getInfo()->hasFocus && windowHandle->getInfo()->visible) {
+ // Set newFocusedWindowHandle to the top most focused window instead of the last one
+ if (!newFocusedWindowHandle && windowHandle->getInfo()->hasFocus
+ && windowHandle->getInfo()->visible) {
newFocusedWindowHandle = windowHandle;
}
if (windowHandle == mLastHoverWindowHandle) {
@@ -3172,7 +3176,7 @@
}
if (mFocusedDisplayId == displayId) {
- onFocusChangedLocked(newFocusedWindowHandle);
+ onFocusChangedLocked(oldFocusedWindowHandle, newFocusedWindowHandle);
}
}
@@ -3290,7 +3294,7 @@
// Sanity check
sp<InputWindowHandle> newFocusedWindowHandle =
getValueByKey(mFocusedWindowHandlesByDisplay, displayId);
- onFocusChangedLocked(newFocusedWindowHandle);
+ onFocusChangedLocked(oldFocusedWindowHandle, newFocusedWindowHandle);
if (newFocusedWindowHandle == nullptr) {
ALOGW("Focused display #%" PRId32 " does not have a focused window.", displayId);
@@ -3371,29 +3375,27 @@
mLooper->wake();
}
-bool InputDispatcher::transferTouchFocus(const sp<InputChannel>& fromChannel,
- const sp<InputChannel>& toChannel) {
+bool InputDispatcher::transferTouchFocus(const sp<IBinder>& fromToken, const sp<IBinder>& toToken) {
+ if (fromToken == toToken) {
#if DEBUG_FOCUS
- ALOGD("transferTouchFocus: fromChannel=%s, toChannel=%s",
- fromChannel->getName().c_str(), toChannel->getName().c_str());
+ ALOGD("Trivial transfer to same window.");
#endif
+ return true;
+ }
+
{ // acquire lock
AutoMutex _l(mLock);
- sp<InputWindowHandle> fromWindowHandle = getWindowHandleLocked(fromChannel);
- sp<InputWindowHandle> toWindowHandle = getWindowHandleLocked(toChannel);
+ sp<InputWindowHandle> fromWindowHandle = getWindowHandleLocked(fromToken);
+ sp<InputWindowHandle> toWindowHandle = getWindowHandleLocked(toToken);
if (fromWindowHandle == nullptr || toWindowHandle == nullptr) {
-#if DEBUG_FOCUS
- ALOGD("Cannot transfer focus because from or to window not found.");
-#endif
+ ALOGW("Cannot transfer focus because from or to window not found.");
return false;
}
- if (fromWindowHandle == toWindowHandle) {
#if DEBUG_FOCUS
- ALOGD("Trivial transfer to same window.");
+ ALOGD("transferTouchFocus: fromWindowHandle=%s, toWindowHandle=%s",
+ fromWindowHandle->getName().c_str(), toWindowHandle->getName().c_str());
#endif
- return true;
- }
if (fromWindowHandle->getInfo()->displayId != toWindowHandle->getInfo()->displayId) {
#if DEBUG_FOCUS
ALOGD("Cannot transfer focus because windows are on different displays.");
@@ -3431,6 +3433,9 @@
return false;
}
+
+ sp<InputChannel> fromChannel = getInputChannelLocked(fromToken);
+ sp<InputChannel> toChannel = getInputChannelLocked(toToken);
ssize_t fromConnectionIndex = getConnectionIndexLocked(fromChannel);
ssize_t toConnectionIndex = getConnectionIndexLocked(toChannel);
if (fromConnectionIndex >= 0 && toConnectionIndex >= 0) {
@@ -3535,6 +3540,14 @@
} else {
dump += INDENT3 "Windows: <none>\n";
}
+ if (!state.portalWindows.isEmpty()) {
+ dump += INDENT3 "Portal windows:\n";
+ for (size_t i = 0; i < state.portalWindows.size(); i++) {
+ const sp<InputWindowHandle> portalWindowHandle = state.portalWindows.itemAt(i);
+ dump += StringPrintf(INDENT4 "%zu: name='%s'\n",
+ i, portalWindowHandle->getName().c_str());
+ }
+ }
}
} else {
dump += INDENT "TouchStates: <no displays touched>\n";
@@ -3551,11 +3564,12 @@
const InputWindowInfo* windowInfo = windowHandle->getInfo();
dump += StringPrintf(INDENT3 "%zu: name='%s', displayId=%d, "
- "paused=%s, hasFocus=%s, hasWallpaper=%s, "
+ "portalToDisplayId=%d, paused=%s, hasFocus=%s, hasWallpaper=%s, "
"visible=%s, canReceiveKeys=%s, flags=0x%08x, type=0x%08x, layer=%d, "
"frame=[%d,%d][%d,%d], globalScale=%f, windowScale=(%f,%f), "
"touchableRegion=",
i, windowInfo->name.c_str(), windowInfo->displayId,
+ windowInfo->portalToDisplayId,
toString(windowInfo->paused),
toString(windowInfo->hasFocus),
toString(windowInfo->hasWallpaper),
@@ -3851,11 +3865,14 @@
commandEntry->connection = connection;
}
-void InputDispatcher::onFocusChangedLocked(const sp<InputWindowHandle>& newFocus) {
- sp<IBinder> token = newFocus != nullptr ? newFocus->getToken() : nullptr;
+void InputDispatcher::onFocusChangedLocked(const sp<InputWindowHandle>& oldFocus,
+ const sp<InputWindowHandle>& newFocus) {
+ sp<IBinder> oldToken = oldFocus != nullptr ? oldFocus->getToken() : nullptr;
+ sp<IBinder> newToken = newFocus != nullptr ? newFocus->getToken() : nullptr;
CommandEntry* commandEntry = postCommandLocked(
& InputDispatcher::doNotifyFocusChangedLockedInterruptible);
- commandEntry->token = token;
+ commandEntry->oldToken = oldToken;
+ commandEntry->newToken = newToken;
}
void InputDispatcher::onANRLocked(
@@ -3917,9 +3934,10 @@
void InputDispatcher::doNotifyFocusChangedLockedInterruptible(
CommandEntry* commandEntry) {
- sp<IBinder> token = commandEntry->token;
+ sp<IBinder> oldToken = commandEntry->oldToken;
+ sp<IBinder> newToken = commandEntry->newToken;
mLock.unlock();
- mPolicy->notifyFocusChanged(token);
+ mPolicy->notifyFocusChanged(oldToken, newToken);
mLock.lock();
}
@@ -4025,6 +4043,10 @@
bool InputDispatcher::afterKeyEventLockedInterruptible(const sp<Connection>& connection,
DispatchEntry* dispatchEntry, KeyEntry* keyEntry, bool handled) {
if (keyEntry->flags & AKEY_EVENT_FLAG_FALLBACK) {
+ if (!handled) {
+ // Report the key as unhandled, since the fallback was not handled.
+ mReporter->reportUnhandledKey(keyEntry->sequenceNum);
+ }
return false;
}
@@ -4192,6 +4214,9 @@
#if DEBUG_OUTBOUND_EVENT_DETAILS
ALOGD("Unhandled key event: No fallback key.");
#endif
+
+ // Report the key as unhandled, since there is no fallback key.
+ mReporter->reportUnhandledKey(keyEntry->sequenceNum);
}
}
return false;
@@ -4387,8 +4412,8 @@
InputDispatcher::MotionEntry::MotionEntry(uint32_t sequenceNum, nsecs_t eventTime, int32_t deviceId,
uint32_t source, int32_t displayId, uint32_t policyFlags, int32_t action,
int32_t actionButton,
- int32_t flags, int32_t metaState, int32_t buttonState, int32_t edgeFlags,
- float xPrecision, float yPrecision, nsecs_t downTime,
+ int32_t flags, int32_t metaState, int32_t buttonState, MotionClassification classification,
+ int32_t edgeFlags, float xPrecision, float yPrecision, nsecs_t downTime,
uint32_t pointerCount,
const PointerProperties* pointerProperties, const PointerCoords* pointerCoords,
float xOffset, float yOffset) :
@@ -4396,7 +4421,8 @@
eventTime(eventTime),
deviceId(deviceId), source(source), displayId(displayId), action(action),
actionButton(actionButton), flags(flags), metaState(metaState), buttonState(buttonState),
- edgeFlags(edgeFlags), xPrecision(xPrecision), yPrecision(yPrecision),
+ classification(classification), edgeFlags(edgeFlags),
+ xPrecision(xPrecision), yPrecision(yPrecision),
downTime(downTime), pointerCount(pointerCount) {
for (uint32_t i = 0; i < pointerCount; i++) {
this->pointerProperties[i].copyFrom(pointerProperties[i]);
@@ -4413,9 +4439,10 @@
void InputDispatcher::MotionEntry::appendDescription(std::string& msg) const {
msg += StringPrintf("MotionEvent(deviceId=%d, source=0x%08x, displayId=%" PRId32
", action=%s, actionButton=0x%08x, flags=0x%08x, metaState=0x%08x, buttonState=0x%08x, "
- "edgeFlags=0x%08x, xPrecision=%.1f, yPrecision=%.1f, pointers=[",
+ "classification=%s, edgeFlags=0x%08x, xPrecision=%.1f, yPrecision=%.1f, pointers=[",
deviceId, source, displayId, motionActionToString(action).c_str(), actionButton, flags,
- metaState, buttonState, edgeFlags, xPrecision, yPrecision);
+ metaState, buttonState, motionClassificationToString(classification), edgeFlags,
+ xPrecision, yPrecision);
for (uint32_t i = 0; i < pointerCount; i++) {
if (i) {
@@ -4716,15 +4743,15 @@
for (size_t i = 0; i < mMotionMementos.size(); i++) {
const MotionMemento& memento = mMotionMementos.itemAt(i);
if (shouldCancelMotion(memento, options)) {
+ const int32_t action = memento.hovering ?
+ AMOTION_EVENT_ACTION_HOVER_EXIT : AMOTION_EVENT_ACTION_CANCEL;
outEvents.push(new MotionEntry(SYNTHESIZED_EVENT_SEQUENCE_NUM, currentTime,
memento.deviceId, memento.source, memento.displayId, memento.policyFlags,
- memento.hovering
- ? AMOTION_EVENT_ACTION_HOVER_EXIT
- : AMOTION_EVENT_ACTION_CANCEL,
- memento.flags, 0, 0, 0, 0,
+ action, 0 /*actionButton*/, memento.flags, AMETA_NONE, 0 /*buttonState*/,
+ MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE,
memento.xPrecision, memento.yPrecision, memento.downTime,
memento.pointerCount, memento.pointerProperties, memento.pointerCoords,
- 0, 0));
+ 0 /*xOffset*/, 0 /*yOffset*/));
}
}
}
@@ -4891,6 +4918,7 @@
source = 0;
displayId = ADISPLAY_ID_NONE;
windows.clear();
+ portalWindows.clear();
}
void InputDispatcher::TouchState::copyFrom(const TouchState& other) {
@@ -4900,6 +4928,7 @@
source = other.source;
displayId = other.displayId;
windows = other.windows;
+ portalWindows = other.portalWindows;
}
void InputDispatcher::TouchState::addOrUpdateWindow(const sp<InputWindowHandle>& windowHandle,
@@ -4928,6 +4957,17 @@
touchedWindow.pointerIds = pointerIds;
}
+void InputDispatcher::TouchState::addPortalWindow(const sp<InputWindowHandle>& windowHandle) {
+ size_t numWindows = portalWindows.size();
+ for (size_t i = 0; i < numWindows; i++) {
+ sp<InputWindowHandle> portalWindowHandle = portalWindows.itemAt(i);
+ if (portalWindowHandle == windowHandle) {
+ return;
+ }
+ }
+ portalWindows.push_back(windowHandle);
+}
+
void InputDispatcher::TouchState::removeWindow(const sp<InputWindowHandle>& windowHandle) {
for (size_t i = 0; i < windows.size(); i++) {
if (windows.itemAt(i).windowHandle == windowHandle) {
diff --git a/services/inputflinger/InputDispatcher.h b/services/inputflinger/InputDispatcher.h
index 05b5dad..2d8df5c 100644
--- a/services/inputflinger/InputDispatcher.h
+++ b/services/inputflinger/InputDispatcher.h
@@ -37,6 +37,7 @@
#include <unordered_map>
#include "InputListener.h"
+#include "InputReporterInterface.h"
namespace android {
@@ -216,7 +217,7 @@
/* Notifies the system that an input channel is unrecoverably broken. */
virtual void notifyInputChannelBroken(const sp<IBinder>& token) = 0;
- virtual void notifyFocusChanged(const sp<IBinder>& token) = 0;
+ virtual void notifyFocusChanged(const sp<IBinder>& oldToken, const sp<IBinder>& newToken) = 0;
/* Gets the input dispatcher configuration. */
virtual void getDispatcherConfiguration(InputDispatcherConfiguration* outConfig) = 0;
@@ -342,13 +343,11 @@
*/
virtual void setInputFilterEnabled(bool enabled) = 0;
- /* Transfers touch focus from the window associated with one channel to the
- * window associated with the other channel.
+ /* Transfers touch focus from one window to another window.
*
* Returns true on success. False if the window did not actually have touch focus.
*/
- virtual bool transferTouchFocus(const sp<InputChannel>& fromChannel,
- const sp<InputChannel>& toChannel) = 0;
+ virtual bool transferTouchFocus(const sp<IBinder>& fromToken, const sp<IBinder>& toToken) = 0;
/* Registers input channels that may be used as targets for input events.
* If inputWindowHandle is null, and displayId is not ADISPLAY_ID_NONE,
@@ -413,8 +412,7 @@
virtual void setInputDispatchMode(bool enabled, bool frozen);
virtual void setInputFilterEnabled(bool enabled);
- virtual bool transferTouchFocus(const sp<InputChannel>& fromChannel,
- const sp<InputChannel>& toChannel);
+ virtual bool transferTouchFocus(const sp<IBinder>& fromToken, const sp<IBinder>& toToken);
virtual status_t registerInputChannel(const sp<InputChannel>& inputChannel,
int32_t displayId);
@@ -537,6 +535,7 @@
int32_t flags;
int32_t metaState;
int32_t buttonState;
+ MotionClassification classification;
int32_t edgeFlags;
float xPrecision;
float yPrecision;
@@ -548,8 +547,9 @@
MotionEntry(uint32_t sequenceNum, nsecs_t eventTime,
int32_t deviceId, uint32_t source, int32_t displayId, uint32_t policyFlags,
int32_t action, int32_t actionButton, int32_t flags,
- int32_t metaState, int32_t buttonState, int32_t edgeFlags,
- float xPrecision, float yPrecision, nsecs_t downTime, uint32_t pointerCount,
+ int32_t metaState, int32_t buttonState, MotionClassification classification,
+ int32_t edgeFlags, float xPrecision, float yPrecision,
+ nsecs_t downTime, uint32_t pointerCount,
const PointerProperties* pointerProperties, const PointerCoords* pointerCoords,
float xOffset, float yOffset);
virtual void appendDescription(std::string& msg) const;
@@ -630,7 +630,8 @@
uint32_t seq;
bool handled;
sp<InputChannel> inputChannel;
- sp<IBinder> token;
+ sp<IBinder> oldToken;
+ sp<IBinder> newToken;
};
// Generic queue implementation.
@@ -920,7 +921,8 @@
// to transfer focus to a new application.
EventEntry* mNextUnblockedEvent;
- sp<InputWindowHandle> findTouchedWindowAtLocked(int32_t displayId, int32_t x, int32_t y);
+ sp<InputWindowHandle> findTouchedWindowAtLocked(int32_t displayId, int32_t x, int32_t y,
+ bool addOutsideTargets = false, bool addPortalWindows = false);
// All registered connections mapped by channel file descriptor.
KeyedVector<int, sp<Connection> > mConnectionsByFd;
@@ -994,7 +996,7 @@
std::unordered_map<int32_t, Vector<sp<InputWindowHandle>>> mWindowHandlesByDisplay;
// Get window handles by display, return an empty vector if not found.
Vector<sp<InputWindowHandle>> getWindowHandlesLocked(int32_t displayId) const;
- sp<InputWindowHandle> getWindowHandleLocked(const sp<InputChannel>& inputChannel) const;
+ sp<InputWindowHandle> getWindowHandleLocked(const sp<IBinder>& windowHandleToken) const;
sp<InputChannel> getInputChannelLocked(const sp<IBinder>& windowToken) const;
bool hasWindowHandleLocked(const sp<InputWindowHandle>& windowHandle) const;
@@ -1015,12 +1017,18 @@
int32_t displayId; // id to the display that currently has a touch, others are rejected
Vector<TouchedWindow> windows;
+ // This collects the portal windows that the touch has gone through. Each portal window
+ // targets a display (embedded display for most cases). With this info, we can add the
+ // monitoring channels of the displays touched.
+ Vector<sp<InputWindowHandle>> portalWindows;
+
TouchState();
~TouchState();
void reset();
void copyFrom(const TouchState& other);
void addOrUpdateWindow(const sp<InputWindowHandle>& windowHandle,
int32_t targetFlags, BitSet32 pointerIds);
+ void addPortalWindow(const sp<InputWindowHandle>& windowHandle);
void removeWindow(const sp<InputWindowHandle>& windowHandle);
void removeWindowByToken(const sp<IBinder>& token);
void filterNonAsIsTouchWindows();
@@ -1095,7 +1103,8 @@
void addWindowTargetLocked(const sp<InputWindowHandle>& windowHandle,
int32_t targetFlags, BitSet32 pointerIds, Vector<InputTarget>& inputTargets);
- void addMonitoringTargetsLocked(Vector<InputTarget>& inputTargets, int32_t displayId);
+ void addMonitoringTargetsLocked(Vector<InputTarget>& inputTargets, int32_t displayId,
+ float xOffset = 0, float yOffset = 0);
void pokeUserActivityLocked(const EventEntry* eventEntry);
bool checkInjectionPermission(const sp<InputWindowHandle>& windowHandle,
@@ -1160,7 +1169,8 @@
nsecs_t currentTime, const sp<Connection>& connection, uint32_t seq, bool handled);
void onDispatchCycleBrokenLocked(
nsecs_t currentTime, const sp<Connection>& connection);
- void onFocusChangedLocked(const sp<InputWindowHandle>& newFocus);
+ void onFocusChangedLocked(const sp<InputWindowHandle>& oldFocus,
+ const sp<InputWindowHandle>& newFocus);
void onANRLocked(
nsecs_t currentTime, const sp<InputApplicationHandle>& applicationHandle,
const sp<InputWindowHandle>& windowHandle,
@@ -1186,6 +1196,8 @@
void traceInboundQueueLengthLocked();
void traceOutboundQueueLengthLocked(const sp<Connection>& connection);
void traceWaitQueueLengthLocked(const sp<Connection>& connection);
+
+ sp<InputReporterInterface> mReporter;
};
/* Enqueues and dispatches input events, endlessly. */
diff --git a/services/inputflinger/InputListener.cpp b/services/inputflinger/InputListener.cpp
index b4eb370..e537e09 100644
--- a/services/inputflinger/InputListener.cpp
+++ b/services/inputflinger/InputListener.cpp
@@ -36,6 +36,10 @@
NotifyArgs(other.sequenceNum), eventTime(other.eventTime) {
}
+bool NotifyConfigurationChangedArgs::operator==(const NotifyConfigurationChangedArgs& rhs) const {
+ return sequenceNum == rhs.sequenceNum && eventTime == rhs.eventTime;
+}
+
void NotifyConfigurationChangedArgs::notify(const sp<InputListenerInterface>& listener) const {
listener->notifyConfigurationChanged(this);
}
@@ -61,6 +65,21 @@
metaState(other.metaState), downTime(other.downTime) {
}
+bool NotifyKeyArgs::operator==(const NotifyKeyArgs& rhs) const {
+ return sequenceNum == rhs.sequenceNum
+ && eventTime == rhs.eventTime
+ && deviceId == rhs.deviceId
+ && source == rhs.source
+ && displayId == rhs.displayId
+ && policyFlags == rhs.policyFlags
+ && action == rhs.action
+ && flags == rhs.flags
+ && keyCode == rhs.keyCode
+ && scanCode == rhs.scanCode
+ && metaState == rhs.metaState
+ && downTime == rhs.downTime;
+}
+
void NotifyKeyArgs::notify(const sp<InputListenerInterface>& listener) const {
listener->notifyKey(this);
}
@@ -71,8 +90,8 @@
NotifyMotionArgs::NotifyMotionArgs(uint32_t sequenceNum, nsecs_t eventTime, int32_t deviceId,
uint32_t source, int32_t displayId, uint32_t policyFlags,
int32_t action, int32_t actionButton, int32_t flags, int32_t metaState,
- int32_t buttonState, int32_t edgeFlags, uint32_t deviceTimestamp,
- uint32_t pointerCount,
+ int32_t buttonState, MotionClassification classification,
+ int32_t edgeFlags, uint32_t deviceTimestamp, uint32_t pointerCount,
const PointerProperties* pointerProperties, const PointerCoords* pointerCoords,
float xPrecision, float yPrecision, nsecs_t downTime,
const std::vector<TouchVideoFrame>& videoFrames) :
@@ -80,7 +99,7 @@
displayId(displayId), policyFlags(policyFlags),
action(action), actionButton(actionButton),
flags(flags), metaState(metaState), buttonState(buttonState),
- edgeFlags(edgeFlags), deviceTimestamp(deviceTimestamp),
+ classification(classification), edgeFlags(edgeFlags), deviceTimestamp(deviceTimestamp),
pointerCount(pointerCount),
xPrecision(xPrecision), yPrecision(yPrecision), downTime(downTime),
videoFrames(videoFrames) {
@@ -95,7 +114,7 @@
source(other.source), displayId(other.displayId), policyFlags(other.policyFlags),
action(other.action), actionButton(other.actionButton), flags(other.flags),
metaState(other.metaState), buttonState(other.buttonState),
- edgeFlags(other.edgeFlags),
+ classification(other.classification), edgeFlags(other.edgeFlags),
deviceTimestamp(other.deviceTimestamp), pointerCount(other.pointerCount),
xPrecision(other.xPrecision), yPrecision(other.yPrecision), downTime(other.downTime),
videoFrames(other.videoFrames) {
@@ -105,6 +124,43 @@
}
}
+bool NotifyMotionArgs::operator==(const NotifyMotionArgs& rhs) const {
+ bool equal =
+ sequenceNum == rhs.sequenceNum
+ && eventTime == rhs.eventTime
+ && deviceId == rhs.deviceId
+ && source == rhs.source
+ && displayId == rhs.displayId
+ && policyFlags == rhs.policyFlags
+ && action == rhs.action
+ && actionButton == rhs.actionButton
+ && flags == rhs.flags
+ && metaState == rhs.metaState
+ && buttonState == rhs.buttonState
+ && classification == rhs.classification
+ && edgeFlags == rhs.edgeFlags
+ && deviceTimestamp == rhs.deviceTimestamp
+ && pointerCount == rhs.pointerCount
+ // PointerProperties and PointerCoords are compared separately below
+ && xPrecision == rhs.xPrecision
+ && yPrecision == rhs.yPrecision
+ && downTime == rhs.downTime
+ && videoFrames == rhs.videoFrames;
+ if (!equal) {
+ return false;
+ }
+
+ for (size_t i = 0; i < pointerCount; i++) {
+ equal =
+ pointerProperties[i] == rhs.pointerProperties[i]
+ && pointerCoords[i] == rhs.pointerCoords[i];
+ if (!equal) {
+ return false;
+ }
+ }
+ return true;
+}
+
void NotifyMotionArgs::notify(const sp<InputListenerInterface>& listener) const {
listener->notifyMotion(this);
}
@@ -123,6 +179,14 @@
switchValues(other.switchValues), switchMask(other.switchMask) {
}
+bool NotifySwitchArgs::operator==(const NotifySwitchArgs rhs) const {
+ return sequenceNum == rhs.sequenceNum
+ && eventTime == rhs.eventTime
+ && policyFlags == rhs.policyFlags
+ && switchValues == rhs.switchValues
+ && switchMask == rhs.switchMask;
+}
+
void NotifySwitchArgs::notify(const sp<InputListenerInterface>& listener) const {
listener->notifySwitch(this);
}
@@ -139,6 +203,12 @@
NotifyArgs(other.sequenceNum), eventTime(other.eventTime), deviceId(other.deviceId) {
}
+bool NotifyDeviceResetArgs::operator==(const NotifyDeviceResetArgs& rhs) const {
+ return sequenceNum == rhs.sequenceNum
+ && eventTime == rhs.eventTime
+ && deviceId == rhs.deviceId;
+}
+
void NotifyDeviceResetArgs::notify(const sp<InputListenerInterface>& listener) const {
listener->notifyDeviceReset(this);
}
diff --git a/services/inputflinger/InputManager.cpp b/services/inputflinger/InputManager.cpp
index 15d8070..b3b9e3e 100644
--- a/services/inputflinger/InputManager.cpp
+++ b/services/inputflinger/InputManager.cpp
@@ -34,7 +34,8 @@
const sp<InputReaderPolicyInterface>& readerPolicy,
const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) {
mDispatcher = new InputDispatcher(dispatcherPolicy);
- mReader = createInputReader(readerPolicy, mDispatcher);
+ mClassifier = new InputClassifier(mDispatcher);
+ mReader = createInputReader(readerPolicy, mClassifier);
initialize();
}
@@ -111,6 +112,10 @@
}
}
+void InputManager::transferTouchFocus(const sp<IBinder>& fromToken, const sp<IBinder>& toToken) {
+ mDispatcher->transferTouchFocus(fromToken, toToken);
+}
+
// Used by tests only.
void InputManager::registerInputChannel(const sp<InputChannel>& channel) {
IPCThreadState* ipc = IPCThreadState::self();
diff --git a/services/inputflinger/InputManager.h b/services/inputflinger/InputManager.h
index 8f7551e..142ec0c 100644
--- a/services/inputflinger/InputManager.h
+++ b/services/inputflinger/InputManager.h
@@ -23,7 +23,9 @@
#include "EventHub.h"
#include "InputReaderBase.h"
+#include "InputClassifier.h"
#include "InputDispatcher.h"
+#include "InputReader.h"
#include <input/Input.h>
#include <input/InputTransport.h>
@@ -91,6 +93,7 @@
virtual sp<InputDispatcherInterface> getDispatcher();
virtual void setInputWindows(const Vector<InputWindowInfo>& handles);
+ virtual void transferTouchFocus(const sp<IBinder>& fromToken, const sp<IBinder>& toToken);
virtual void registerInputChannel(const sp<InputChannel>& channel);
virtual void unregisterInputChannel(const sp<InputChannel>& channel);
@@ -99,6 +102,8 @@
sp<InputReaderInterface> mReader;
sp<InputReaderThread> mReaderThread;
+ sp<InputClassifierInterface> mClassifier;
+
sp<InputDispatcherInterface> mDispatcher;
sp<InputDispatcherThread> mDispatcherThread;
diff --git a/services/inputflinger/InputReader.cpp b/services/inputflinger/InputReader.cpp
index 3d5f1d9..f84aa34 100644
--- a/services/inputflinger/InputReader.cpp
+++ b/services/inputflinger/InputReader.cpp
@@ -57,6 +57,7 @@
#include <android-base/stringprintf.h>
#include <input/Keyboard.h>
#include <input/VirtualKeyMap.h>
+#include <statslog.h>
#define INDENT " "
#define INDENT2 " "
@@ -71,18 +72,21 @@
// --- Constants ---
// Maximum number of slots supported when using the slot-based Multitouch Protocol B.
-static const size_t MAX_SLOTS = 32;
+static constexpr size_t MAX_SLOTS = 32;
// Maximum amount of latency to add to touch events while waiting for data from an
// external stylus.
-static const nsecs_t EXTERNAL_STYLUS_DATA_TIMEOUT = ms2ns(72);
+static constexpr nsecs_t EXTERNAL_STYLUS_DATA_TIMEOUT = ms2ns(72);
// Maximum amount of time to wait on touch data before pushing out new pressure data.
-static const nsecs_t TOUCH_DATA_TIMEOUT = ms2ns(20);
+static constexpr nsecs_t TOUCH_DATA_TIMEOUT = ms2ns(20);
// Artificial latency on synthetic events created from stylus data without corresponding touch
// data.
-static const nsecs_t STYLUS_DATA_LATENCY = ms2ns(10);
+static constexpr nsecs_t STYLUS_DATA_LATENCY = ms2ns(10);
+
+// How often to report input event statistics
+static constexpr nsecs_t STATISTICS_REPORT_FREQUENCY = seconds_to_nanoseconds(5 * 60);
// --- Static Functions ---
@@ -801,6 +805,30 @@
return false;
}
+bool InputReader::canDispatchToDisplay(int32_t deviceId, int32_t displayId) {
+ AutoMutex _l(mLock);
+
+ ssize_t deviceIndex = mDevices.indexOfKey(deviceId);
+ if (deviceIndex < 0) {
+ ALOGW("Ignoring invalid device id %" PRId32 ".", deviceId);
+ return false;
+ }
+
+ InputDevice* device = mDevices.valueAt(deviceIndex);
+ std::optional<int32_t> associatedDisplayId = device->getAssociatedDisplay();
+ // No associated display. By default, can dispatch to all displays.
+ if (!associatedDisplayId) {
+ return true;
+ }
+
+ if (*associatedDisplayId == ADISPLAY_ID_NONE) {
+ ALOGW("Device has associated, but no associated display id.");
+ return true;
+ }
+
+ return *associatedDisplayId == displayId;
+}
+
void InputReader::dump(std::string& dump) {
AutoMutex _l(mLock);
@@ -1271,6 +1299,18 @@
mContext->getListener()->notifyDeviceReset(&args);
}
+std::optional<int32_t> InputDevice::getAssociatedDisplay() {
+ size_t numMappers = mMappers.size();
+ for (size_t i = 0; i < numMappers; i++) {
+ InputMapper* mapper = mMappers[i];
+ std::optional<int32_t> associatedDisplayId = mapper->getAssociatedDisplay();
+ if (associatedDisplayId) {
+ return associatedDisplayId;
+ }
+ }
+
+ return std::nullopt;
+}
// --- CursorButtonAccumulator ---
@@ -2641,6 +2681,11 @@
mOrientation = internalViewport->orientation;
}
}
+
+ // Update the PointerController if viewports changed.
+ if (mParameters.mode == Parameters::MODE_POINTER) {
+ getPolicy()->obtainPointerController(getDeviceId());
+ }
bumpGeneration();
}
}
@@ -2786,7 +2831,7 @@
pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, y);
pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, deltaX);
pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, deltaY);
- displayId = ADISPLAY_ID_DEFAULT;
+ displayId = mPointerController->getDisplayId();
} else {
pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_X, deltaX);
pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, deltaY);
@@ -2829,7 +2874,8 @@
NotifyMotionArgs releaseArgs(mContext->getNextSequenceNum(), when, getDeviceId(),
mSource, displayId, policyFlags,
AMOTION_EVENT_ACTION_BUTTON_RELEASE, actionButton, 0,
- metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
+ metaState, buttonState,
+ MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE,
/* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords,
mXPrecision, mYPrecision, downTime, /* videoFrames */ {});
getListener()->notifyMotion(&releaseArgs);
@@ -2838,7 +2884,7 @@
NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), mSource,
displayId, policyFlags, motionEventAction, 0, 0, metaState, currentButtonState,
- AMOTION_EVENT_EDGE_FLAG_NONE,
+ MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE,
/* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords,
mXPrecision, mYPrecision, downTime, /* videoFrames */ {});
getListener()->notifyMotion(&args);
@@ -2850,7 +2896,8 @@
buttonState |= actionButton;
NotifyMotionArgs pressArgs(mContext->getNextSequenceNum(), when, getDeviceId(),
mSource, displayId, policyFlags, AMOTION_EVENT_ACTION_BUTTON_PRESS,
- actionButton, 0, metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
+ actionButton, 0, metaState, buttonState,
+ MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE,
/* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords,
mXPrecision, mYPrecision, downTime, /* videoFrames */ {});
getListener()->notifyMotion(&pressArgs);
@@ -2864,7 +2911,8 @@
&& (mSource == AINPUT_SOURCE_MOUSE)) {
NotifyMotionArgs hoverArgs(mContext->getNextSequenceNum(), when, getDeviceId(),
mSource, displayId, policyFlags, AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0,
- metaState, currentButtonState, AMOTION_EVENT_EDGE_FLAG_NONE,
+ metaState, currentButtonState,
+ MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE,
/* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords,
mXPrecision, mYPrecision, downTime, /* videoFrames */ {});
getListener()->notifyMotion(&hoverArgs);
@@ -2878,7 +2926,7 @@
NotifyMotionArgs scrollArgs(mContext->getNextSequenceNum(), when, getDeviceId(),
mSource, displayId, policyFlags,
AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState, currentButtonState,
- AMOTION_EVENT_EDGE_FLAG_NONE,
+ MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE,
/* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords,
mXPrecision, mYPrecision, downTime, /* videoFrames */ {});
getListener()->notifyMotion(&scrollArgs);
@@ -2907,6 +2955,19 @@
}
}
+std::optional<int32_t> CursorInputMapper::getAssociatedDisplay() {
+ if (mParameters.hasAssociatedDisplay) {
+ if (mParameters.mode == Parameters::MODE_POINTER) {
+ return std::make_optional(mPointerController->getDisplayId());
+ } else {
+ // If the device is orientationAware and not a mouse,
+ // it expects to dispatch events to any display
+ return std::make_optional(ADISPLAY_ID_NONE);
+ }
+ }
+ return std::nullopt;
+}
+
// --- RotaryEncoderInputMapper ---
RotaryEncoderInputMapper::RotaryEncoderInputMapper(InputDevice* device) :
@@ -3009,8 +3070,8 @@
NotifyMotionArgs scrollArgs(mContext->getNextSequenceNum(), when, getDeviceId(),
mSource, displayId, policyFlags,
- AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState, 0,
- AMOTION_EVENT_EDGE_FLAG_NONE,
+ AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState, /* buttonState */ 0,
+ MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE,
/* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords,
0, 0, 0, /* videoFrames */ {});
getListener()->notifyMotion(&scrollArgs);
@@ -3612,10 +3673,10 @@
mOrientedRanges.clear();
}
- // Create pointer controller if needed.
+ // Create or update pointer controller if needed.
if (mDeviceMode == DEVICE_MODE_POINTER ||
(mDeviceMode == DEVICE_MODE_DIRECT && mConfig.showTouches)) {
- if (mPointerController == nullptr) {
+ if (mPointerController == nullptr || viewportChanged) {
mPointerController = getPolicy()->obtainPointerController(getDeviceId());
}
} else {
@@ -4279,12 +4340,25 @@
mExternalStylusFusionTimeout = LLONG_MAX;
}
+void TouchInputMapper::reportEventForStatistics(nsecs_t evdevTime) {
+ nsecs_t now = systemTime(CLOCK_MONOTONIC);
+ nsecs_t latency = now - evdevTime;
+ mStatistics.addValue(nanoseconds_to_microseconds(latency));
+ nsecs_t timeSinceLastReport = now - mStatistics.lastReportTime;
+ if (timeSinceLastReport > STATISTICS_REPORT_FREQUENCY) {
+ android::util::stats_write(android::util::TOUCH_EVENT_REPORTED,
+ mStatistics.min, mStatistics.max, mStatistics.mean(), mStatistics.stdev());
+ mStatistics.reset(now);
+ }
+}
+
void TouchInputMapper::process(const RawEvent* rawEvent) {
mCursorButtonAccumulator.process(rawEvent);
mCursorScrollAccumulator.process(rawEvent);
mTouchButtonAccumulator.process(rawEvent);
if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) {
+ reportEventForStatistics(rawEvent->when);
sync(rawEvent->when);
}
}
@@ -5404,10 +5478,11 @@
pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_X, x);
pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, y);
+ const int32_t displayId = mPointerController->getDisplayId();
NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(),
- mSource, mViewport.displayId, policyFlags,
+ mSource, displayId, policyFlags,
AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0,
- metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
+ metaState, buttonState, MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE,
/* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords,
0, 0, mPointerGesture.downTime, /* videoFrames */ {});
getListener()->notifyMotion(&args);
@@ -6312,6 +6387,7 @@
void TouchInputMapper::dispatchPointerSimple(nsecs_t when, uint32_t policyFlags,
bool down, bool hovering) {
int32_t metaState = getContext()->getGlobalMetaState();
+ int32_t displayId = mViewport.displayId;
if (mPointerController != nullptr) {
if (down || hovering) {
@@ -6322,6 +6398,7 @@
} else if (!down && !hovering && (mPointerSimple.down || mPointerSimple.hovering)) {
mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL);
}
+ displayId = mPointerController->getDisplayId();
}
if (mPointerSimple.down && !down) {
@@ -6329,9 +6406,9 @@
// Send up.
NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(),
- mSource, mViewport.displayId, policyFlags,
- AMOTION_EVENT_ACTION_UP, 0, 0, metaState, mLastRawState.buttonState, 0,
- /* deviceTimestamp */ 0,
+ mSource, displayId, policyFlags,
+ AMOTION_EVENT_ACTION_UP, 0, 0, metaState, mLastRawState.buttonState,
+ MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0,
1, &mPointerSimple.lastProperties, &mPointerSimple.lastCoords,
mOrientedXPrecision, mOrientedYPrecision,
mPointerSimple.downTime, /* videoFrames */ {});
@@ -6342,10 +6419,10 @@
mPointerSimple.hovering = false;
// Send hover exit.
- NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(),
- mSource, mViewport.displayId, policyFlags,
- AMOTION_EVENT_ACTION_HOVER_EXIT, 0, 0, metaState, mLastRawState.buttonState, 0,
- /* deviceTimestamp */ 0,
+ NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(),
+ mSource, displayId, policyFlags,
+ AMOTION_EVENT_ACTION_HOVER_EXIT, 0, 0, metaState, mLastRawState.buttonState,
+ MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0,
1, &mPointerSimple.lastProperties, &mPointerSimple.lastCoords,
mOrientedXPrecision, mOrientedYPrecision,
mPointerSimple.downTime, /* videoFrames */ {});
@@ -6358,9 +6435,10 @@
mPointerSimple.downTime = when;
// Send down.
- NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(),
- mSource, mViewport.displayId, policyFlags,
- AMOTION_EVENT_ACTION_DOWN, 0, 0, metaState, mCurrentRawState.buttonState, 0,
+ NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(),
+ mSource, displayId, policyFlags,
+ AMOTION_EVENT_ACTION_DOWN, 0, 0, metaState, mCurrentRawState.buttonState,
+ MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE,
/* deviceTimestamp */ 0,
1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords,
mOrientedXPrecision, mOrientedYPrecision,
@@ -6369,10 +6447,10 @@
}
// Send move.
- NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(),
- mSource, mViewport.displayId, policyFlags,
- AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, mCurrentRawState.buttonState, 0,
- /* deviceTimestamp */ 0,
+ NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(),
+ mSource, displayId, policyFlags,
+ AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, mCurrentRawState.buttonState,
+ MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0,
1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords,
mOrientedXPrecision, mOrientedYPrecision,
mPointerSimple.downTime, /* videoFrames */ {});
@@ -6384,11 +6462,11 @@
mPointerSimple.hovering = true;
// Send hover enter.
- NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(),
- mSource, mViewport.displayId, policyFlags,
+ NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(),
+ mSource, displayId, policyFlags,
AMOTION_EVENT_ACTION_HOVER_ENTER, 0, 0, metaState,
- mCurrentRawState.buttonState, 0,
- /* deviceTimestamp */ 0,
+ mCurrentRawState.buttonState, MotionClassification::NONE,
+ AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0,
1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords,
mOrientedXPrecision, mOrientedYPrecision,
mPointerSimple.downTime, /* videoFrames */ {});
@@ -6396,11 +6474,11 @@
}
// Send hover move.
- NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(),
- mSource, mViewport.displayId, policyFlags,
+ NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(),
+ mSource, displayId, policyFlags,
AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, metaState,
- mCurrentRawState.buttonState, 0,
- /* deviceTimestamp */ 0,
+ mCurrentRawState.buttonState, MotionClassification::NONE,
+ AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0,
1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords,
mOrientedXPrecision, mOrientedYPrecision,
mPointerSimple.downTime, /* videoFrames */ {});
@@ -6419,10 +6497,10 @@
pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_VSCROLL, vscroll);
pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_HSCROLL, hscroll);
- NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(),
- mSource, mViewport.displayId, policyFlags,
- AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState, mCurrentRawState.buttonState, 0,
- /* deviceTimestamp */ 0,
+ NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(),
+ mSource, displayId, policyFlags,
+ AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState, mCurrentRawState.buttonState,
+ MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0,
1, &mPointerSimple.currentProperties, &pointerCoords,
mOrientedXPrecision, mOrientedYPrecision,
mPointerSimple.downTime, /* videoFrames */ {});
@@ -6482,13 +6560,13 @@
ALOG_ASSERT(false);
}
}
-
+ const int32_t displayId = getAssociatedDisplay().value_or(ADISPLAY_ID_NONE);
const int32_t deviceId = getDeviceId();
std::vector<TouchVideoFrame> frames = mDevice->getEventHub()->getVideoFrames(deviceId);
NotifyMotionArgs args(mContext->getNextSequenceNum(), when, deviceId,
- source, mViewport.displayId, policyFlags,
- action, actionButton, flags, metaState, buttonState, edgeFlags,
- deviceTimestamp, pointerCount, pointerProperties, pointerCoords,
+ source, displayId, policyFlags,
+ action, actionButton, flags, metaState, buttonState, MotionClassification::NONE,
+ edgeFlags, deviceTimestamp, pointerCount, pointerProperties, pointerCoords,
xPrecision, yPrecision, downTime, std::move(frames));
getListener()->notifyMotion(&args);
}
@@ -6799,6 +6877,16 @@
return true;
}
+std::optional<int32_t> TouchInputMapper::getAssociatedDisplay() {
+ if (mParameters.hasAssociatedDisplay) {
+ if (mDeviceMode == DEVICE_MODE_POINTER) {
+ return std::make_optional(mPointerController->getDisplayId());
+ } else {
+ return std::make_optional(mViewport.displayId);
+ }
+ }
+ return std::nullopt;
+}
// --- SingleTouchInputMapper ---
@@ -7412,9 +7500,9 @@
NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(),
AINPUT_SOURCE_JOYSTICK, ADISPLAY_ID_NONE, policyFlags,
- AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
- /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords,
- 0, 0, 0, /* videoFrames */ {});
+ AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, buttonState, MotionClassification::NONE,
+ AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0, 1,
+ &pointerProperties, &pointerCoords, 0, 0, 0, /* videoFrames */ {});
getListener()->notifyMotion(&args);
}
diff --git a/services/inputflinger/InputReader.h b/services/inputflinger/InputReader.h
index 35f3c23..fed55ac 100644
--- a/services/inputflinger/InputReader.h
+++ b/services/inputflinger/InputReader.h
@@ -146,6 +146,7 @@
ssize_t repeat, int32_t token);
virtual void cancelVibrate(int32_t deviceId, int32_t token);
+ virtual bool canDispatchToDisplay(int32_t deviceId, int32_t displayId);
protected:
// These members are protected so they can be instrumented by test cases.
virtual InputDevice* createDeviceLocked(int32_t deviceId, int32_t controllerNumber,
@@ -320,6 +321,7 @@
return value;
}
+ std::optional<int32_t> getAssociatedDisplay();
private:
InputReaderContext* mContext;
int32_t mId;
@@ -567,6 +569,69 @@
}
};
+/**
+ * Basic statistics information.
+ * Keep track of min, max, average, and standard deviation of the received samples.
+ * Used to report latency information about input events.
+ */
+struct LatencyStatistics {
+ float min;
+ float max;
+ // Sum of all samples
+ float sum;
+ // Sum of squares of all samples
+ float sum2;
+ // The number of samples
+ size_t count;
+ // The last time statistics were reported.
+ nsecs_t lastReportTime;
+
+ LatencyStatistics() {
+ reset(systemTime(SYSTEM_TIME_MONOTONIC));
+ }
+
+ inline void addValue(float x) {
+ if (x < min) {
+ min = x;
+ }
+ if (x > max) {
+ max = x;
+ }
+ sum += x;
+ sum2 += x * x;
+ count++;
+ }
+
+ // Get the average value. Should not be called if no samples have been added.
+ inline float mean() {
+ if (count == 0) {
+ return 0;
+ }
+ return sum / count;
+ }
+
+ // Get the standard deviation. Should not be called if no samples have been added.
+ inline float stdev() {
+ if (count == 0) {
+ return 0;
+ }
+ float average = mean();
+ return sqrt(sum2 / count - average * average);
+ }
+
+ /**
+ * Reset internal state. The variable 'when' is the time when the data collection started.
+ * Call this to start a new data collection window.
+ */
+ inline void reset(nsecs_t when) {
+ max = 0;
+ min = std::numeric_limits<float>::max();
+ sum = 0;
+ sum2 = 0;
+ count = 0;
+ lastReportTime = when;
+ }
+};
/* Keeps track of the state of single-touch protocol. */
class SingleTouchMotionAccumulator {
@@ -715,7 +780,9 @@
virtual void updateExternalStylusState(const StylusState& state);
virtual void fadePointer();
-
+ virtual std::optional<int32_t> getAssociatedDisplay() {
+ return std::nullopt;
+ }
protected:
InputDevice* mDevice;
InputReaderContext* mContext;
@@ -869,6 +936,7 @@
virtual void fadePointer();
+ virtual std::optional<int32_t> getAssociatedDisplay();
private:
// Amount that trackball needs to move in order to generate a key event.
static const int32_t TRACKBALL_MOVEMENT_THRESHOLD = 6;
@@ -962,7 +1030,7 @@
virtual void cancelTouch(nsecs_t when);
virtual void timeoutExpired(nsecs_t when);
virtual void updateExternalStylusState(const StylusState& state);
-
+ virtual std::optional<int32_t> getAssociatedDisplay();
protected:
CursorButtonAccumulator mCursorButtonAccumulator;
CursorScrollAccumulator mCursorScrollAccumulator;
@@ -1511,6 +1579,9 @@
VelocityControl mWheelXVelocityControl;
VelocityControl mWheelYVelocityControl;
+ // Latency statistics for touch events
+ struct LatencyStatistics mStatistics;
+
std::optional<DisplayViewport> findViewport();
void resetExternalStylus();
@@ -1580,6 +1651,8 @@
static void assignPointerIds(const RawState* last, RawState* current);
+ void reportEventForStatistics(nsecs_t evdevTime);
+
const char* modeToString(DeviceMode deviceMode);
};
diff --git a/services/inputflinger/InputReporter.cpp b/services/inputflinger/InputReporter.cpp
new file mode 100644
index 0000000..8d3153c
--- /dev/null
+++ b/services/inputflinger/InputReporter.cpp
@@ -0,0 +1,41 @@
+/*
+ * 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 "InputReporterInterface.h"
+
+namespace android {
+
+// --- InputReporter ---
+
+class InputReporter : public InputReporterInterface {
+public:
+ void reportUnhandledKey(uint32_t sequenceNum) override;
+ void reportDroppedKey(uint32_t sequenceNum) override;
+};
+
+void InputReporter::reportUnhandledKey(uint32_t sequenceNum) {
+ // do nothing
+}
+
+void InputReporter::reportDroppedKey(uint32_t sequenceNum) {
+ // do nothing
+}
+
+sp<InputReporterInterface> createInputReporter() {
+ return new InputReporter();
+}
+
+} // namespace android
diff --git a/services/inputflinger/OWNERS b/services/inputflinger/OWNERS
new file mode 100644
index 0000000..0313a40
--- /dev/null
+++ b/services/inputflinger/OWNERS
@@ -0,0 +1,2 @@
+michaelwr@google.com
+svv@google.com
diff --git a/services/inputflinger/host/InputFlinger.h b/services/inputflinger/host/InputFlinger.h
index 82ff089..9d0be95 100644
--- a/services/inputflinger/host/InputFlinger.h
+++ b/services/inputflinger/host/InputFlinger.h
@@ -40,6 +40,7 @@
virtual status_t dump(int fd, const Vector<String16>& args);
void setInputWindows(const Vector<InputWindowInfo>&) {}
+ void transferTouchFocus(const sp<IBinder>&, const sp<IBinder>&) {}
void registerInputChannel(const sp<InputChannel>&) {}
void unregisterInputChannel(const sp<InputChannel>&) {}
diff --git a/services/inputflinger/include/InputListener.h b/services/inputflinger/include/InputListener.h
index 2442cc0..13ae7dd 100644
--- a/services/inputflinger/include/InputListener.h
+++ b/services/inputflinger/include/InputListener.h
@@ -49,6 +49,8 @@
inline NotifyConfigurationChangedArgs() { }
+ bool operator==(const NotifyConfigurationChangedArgs& rhs) const;
+
NotifyConfigurationChangedArgs(uint32_t sequenceNum, nsecs_t eventTime);
NotifyConfigurationChangedArgs(const NotifyConfigurationChangedArgs& other);
@@ -79,6 +81,8 @@
int32_t displayId, uint32_t policyFlags, int32_t action, int32_t flags, int32_t keyCode,
int32_t scanCode, int32_t metaState, nsecs_t downTime);
+ bool operator==(const NotifyKeyArgs& rhs) const;
+
NotifyKeyArgs(const NotifyKeyArgs& other);
virtual ~NotifyKeyArgs() { }
@@ -99,6 +103,10 @@
int32_t flags;
int32_t metaState;
int32_t buttonState;
+ /**
+ * Classification of the current touch gesture
+ */
+ MotionClassification classification;
int32_t edgeFlags;
/**
* A timestamp in the input device's time base, not the platform's.
@@ -120,7 +128,7 @@
NotifyMotionArgs(uint32_t sequenceNum, nsecs_t eventTime, int32_t deviceId, uint32_t source,
int32_t displayId, uint32_t policyFlags,
int32_t action, int32_t actionButton, int32_t flags,
- int32_t metaState, int32_t buttonState,
+ int32_t metaState, int32_t buttonState, MotionClassification classification,
int32_t edgeFlags, uint32_t deviceTimestamp, uint32_t pointerCount,
const PointerProperties* pointerProperties, const PointerCoords* pointerCoords,
float xPrecision, float yPrecision, nsecs_t downTime,
@@ -130,6 +138,8 @@
virtual ~NotifyMotionArgs() { }
+ bool operator==(const NotifyMotionArgs& rhs) const;
+
virtual void notify(const sp<InputListenerInterface>& listener) const;
};
@@ -148,6 +158,8 @@
NotifySwitchArgs(const NotifySwitchArgs& other);
+ bool operator==(const NotifySwitchArgs rhs) const;
+
virtual ~NotifySwitchArgs() { }
virtual void notify(const sp<InputListenerInterface>& listener) const;
@@ -166,6 +178,8 @@
NotifyDeviceResetArgs(const NotifyDeviceResetArgs& other);
+ bool operator==(const NotifyDeviceResetArgs& rhs) const;
+
virtual ~NotifyDeviceResetArgs() { }
virtual void notify(const sp<InputListenerInterface>& listener) const;
diff --git a/services/inputflinger/include/InputReaderBase.h b/services/inputflinger/include/InputReaderBase.h
index fe1c50b..fe1d4d0 100644
--- a/services/inputflinger/include/InputReaderBase.h
+++ b/services/inputflinger/include/InputReaderBase.h
@@ -100,6 +100,9 @@
virtual void vibrate(int32_t deviceId, const nsecs_t* pattern, size_t patternSize,
ssize_t repeat, int32_t token) = 0;
virtual void cancelVibrate(int32_t deviceId, int32_t token) = 0;
+
+ /* Return true if the device can send input events to the specified display. */
+ virtual bool canDispatchToDisplay(int32_t deviceId, int32_t displayId) = 0;
};
/* Reads raw events from the event hub and processes them, endlessly. */
@@ -265,7 +268,7 @@
pointerGestureSwipeMaxWidthRatio(0.25f),
pointerGestureMovementSpeedRatio(0.8f),
pointerGestureZoomSpeedRatio(0.3f),
- showTouches(false) { }
+ showTouches(false), pointerCapture(false) { }
std::optional<DisplayViewport> getDisplayViewportByType(ViewportType type) const;
std::optional<DisplayViewport> getDisplayViewportByUniqueId(const std::string& uniqueDisplayId)
diff --git a/services/inputflinger/include/InputReporterInterface.h b/services/inputflinger/include/InputReporterInterface.h
new file mode 100644
index 0000000..906d7f2
--- /dev/null
+++ b/services/inputflinger/include/InputReporterInterface.h
@@ -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.
+ */
+
+#ifndef _UI_INPUT_REPORTER_INTERFACE_H
+#define _UI_INPUT_REPORTER_INTERFACE_H
+
+#include <utils/RefBase.h>
+
+namespace android {
+
+/*
+ * The interface used by the InputDispatcher to report information about input events after
+ * it is sent to the application, such as if a key is unhandled or dropped.
+ */
+class InputReporterInterface : public virtual RefBase {
+protected:
+ virtual ~InputReporterInterface() { }
+
+public:
+ // Report a key that was not handled by the system or apps.
+ // A key event is unhandled if:
+ // - The event was not handled and there is no fallback key; or
+ // - The event was not handled and it has a fallback key,
+ // but the fallback key was not handled.
+ virtual void reportUnhandledKey(uint32_t sequenceNum) = 0;
+
+ // Report a key that was dropped by InputDispatcher.
+ // A key can be dropped for several reasons. See the enum
+ // InputDispatcher::DropReason for details.
+ virtual void reportDroppedKey(uint32_t sequenceNum) = 0;
+};
+
+/*
+ * Factory method for InputReporter.
+ */
+sp<InputReporterInterface> createInputReporter();
+
+} // namespace android
+
+#endif // _UI_INPUT_REPORTER_INTERFACE_H
diff --git a/services/inputflinger/include/PointerControllerInterface.h b/services/inputflinger/include/PointerControllerInterface.h
index e94dd94..bc0f1f9 100644
--- a/services/inputflinger/include/PointerControllerInterface.h
+++ b/services/inputflinger/include/PointerControllerInterface.h
@@ -98,6 +98,9 @@
/* Removes all spots. */
virtual void clearSpots() = 0;
+
+ /* Gets the id of the display where the pointer should be shown. */
+ virtual int32_t getDisplayId() const = 0;
};
} // namespace android
diff --git a/services/inputflinger/tests/Android.bp b/services/inputflinger/tests/Android.bp
index 5b275fb..1835449 100644
--- a/services/inputflinger/tests/Android.bp
+++ b/services/inputflinger/tests/Android.bp
@@ -3,8 +3,11 @@
cc_test {
name: "inputflinger_tests",
srcs: [
- "InputReader_test.cpp",
+ "BlockingQueue_test.cpp",
+ "TestInputListener.cpp",
+ "InputClassifier_test.cpp",
"InputDispatcher_test.cpp",
+ "InputReader_test.cpp",
],
cflags: [
"-Wall",
@@ -13,6 +16,7 @@
"-Wno-unused-parameter",
],
shared_libs: [
+ "android.hardware.input.classifier@1.0",
"libbase",
"libbinder",
"libcutils",
diff --git a/services/inputflinger/tests/BlockingQueue_test.cpp b/services/inputflinger/tests/BlockingQueue_test.cpp
new file mode 100644
index 0000000..0dea8d7
--- /dev/null
+++ b/services/inputflinger/tests/BlockingQueue_test.cpp
@@ -0,0 +1,142 @@
+/*
+ * 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 "../BlockingQueue.h"
+
+
+#include <gtest/gtest.h>
+#include <thread>
+
+namespace android {
+
+
+// --- BlockingQueueTest ---
+
+/**
+ * Sanity check of basic pop and push operation.
+ */
+TEST(BlockingQueueTest, Queue_AddAndRemove) {
+ constexpr size_t capacity = 10;
+ BlockingQueue<int> queue(capacity);
+
+ ASSERT_TRUE(queue.push(1));
+ ASSERT_EQ(queue.pop(), 1);
+}
+
+/**
+ * Make sure the queue has strict capacity limits.
+ */
+TEST(BlockingQueueTest, Queue_ReachesCapacity) {
+ constexpr size_t capacity = 3;
+ BlockingQueue<int> queue(capacity);
+
+ // First 3 elements should be added successfully
+ ASSERT_TRUE(queue.push(1));
+ ASSERT_TRUE(queue.push(2));
+ ASSERT_TRUE(queue.push(3));
+ ASSERT_FALSE(queue.push(4)) << "Queue should reach capacity at size " << capacity;
+}
+
+/**
+ * Make sure the queue maintains FIFO order.
+ * Add elements and remove them, and check the order.
+ */
+TEST(BlockingQueueTest, Queue_isFIFO) {
+ constexpr size_t capacity = 10;
+ BlockingQueue<int> queue(capacity);
+
+ for (size_t i = 0; i < capacity; i++) {
+ ASSERT_TRUE(queue.push(static_cast<int>(i)));
+ }
+ for (size_t i = 0; i < capacity; i++) {
+ ASSERT_EQ(queue.pop(), static_cast<int>(i));
+ }
+}
+
+TEST(BlockingQueueTest, Queue_Clears) {
+ constexpr size_t capacity = 2;
+ BlockingQueue<int> queue(capacity);
+
+ queue.push(1);
+ queue.push(2);
+ queue.clear();
+ queue.push(3);
+ // Should no longer receive elements 1 and 2
+ ASSERT_EQ(3, queue.pop());
+}
+
+TEST(BlockingQueueTest, Queue_Erases) {
+ constexpr size_t capacity = 4;
+ BlockingQueue<int> queue(capacity);
+
+ queue.push(1);
+ queue.push(2);
+ queue.push(3);
+ queue.push(4);
+ // Erase elements 2 and 4
+ queue.erase([](int element) { return element == 2 || element == 4; });
+ // Should no longer receive elements 2 and 4
+ ASSERT_EQ(1, queue.pop());
+ ASSERT_EQ(3, queue.pop());
+}
+
+// --- BlockingQueueTest - Multiple threads ---
+
+TEST(BlockingQueueTest, Queue_AllowsMultipleThreads) {
+ constexpr size_t capacity = 100; // large capacity to increase likelihood that threads overlap
+ BlockingQueue<int> queue(capacity);
+
+ // Fill queue from a different thread
+ std::thread fillQueue([&queue](){
+ for (size_t i = 0; i < capacity; i++) {
+ ASSERT_TRUE(queue.push(static_cast<int>(i)));
+ }
+ });
+
+ // Make sure all elements are received in correct order
+ for (size_t i = 0; i < capacity; i++) {
+ ASSERT_EQ(queue.pop(), static_cast<int>(i));
+ }
+
+ fillQueue.join();
+}
+
+/**
+ * When the queue has no elements, and pop is called, it should block
+ * the current thread until an element is added to the queue (from another thread).
+ * Here we create a separate thread and call pop on an empty queue. Next,
+ * we check that the thread is blocked.
+ */
+TEST(BlockingQueueTest, Queue_BlocksWhileWaitingForElements) {
+ constexpr size_t capacity = 1;
+ BlockingQueue<int> queue(capacity);
+
+ std::atomic_bool hasReceivedElement = false;
+
+ // fill queue from a different thread
+ std::thread waitUntilHasElements([&queue, &hasReceivedElement](){
+ queue.pop(); // This should block until an element has been added
+ hasReceivedElement = true;
+ });
+
+ ASSERT_FALSE(hasReceivedElement);
+ queue.push(1);
+ waitUntilHasElements.join();
+ ASSERT_TRUE(hasReceivedElement);
+}
+
+
+} // namespace android
diff --git a/services/inputflinger/tests/InputClassifier_test.cpp b/services/inputflinger/tests/InputClassifier_test.cpp
new file mode 100644
index 0000000..20699c9
--- /dev/null
+++ b/services/inputflinger/tests/InputClassifier_test.cpp
@@ -0,0 +1,233 @@
+/*
+ * 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 "../InputClassifier.h"
+#include <gtest/gtest.h>
+
+#include "TestInputListener.h"
+
+#include <android/hardware/input/classifier/1.0/IInputClassifier.h>
+
+using namespace android::hardware::input;
+
+namespace android {
+
+// --- InputClassifierTest ---
+
+static NotifyMotionArgs generateBasicMotionArgs() {
+ // Create a basic motion event for testing
+ constexpr size_t pointerCount = 1;
+ PointerProperties properties[pointerCount];
+ properties[0].id = 0;
+ properties[0].toolType = AMOTION_EVENT_TOOL_TYPE_FINGER;
+
+ PointerCoords coords[pointerCount];
+ coords[0].setAxisValue(AMOTION_EVENT_AXIS_X, 1);
+ coords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, 1);
+ static constexpr nsecs_t downTime = 2;
+ NotifyMotionArgs motionArgs(1/*sequenceNum*/, downTime/*eventTime*/, 3/*deviceId*/,
+ AINPUT_SOURCE_ANY, ADISPLAY_ID_DEFAULT, 4/*policyFlags*/, AMOTION_EVENT_ACTION_DOWN,
+ 0/*actionButton*/, 0/*flags*/, AMETA_NONE, 0/*buttonState*/, MotionClassification::NONE,
+ AMOTION_EVENT_EDGE_FLAG_NONE, 5/*deviceTimestamp*/,
+ 0/*pointerCount*/, properties, coords, 0/*xPrecision*/, 0/*yPrecision*/,
+ downTime, {}/*videoFrames*/);
+ return motionArgs;
+}
+
+class InputClassifierTest : public testing::Test {
+protected:
+ sp<InputClassifierInterface> mClassifier;
+ sp<TestInputListener> mTestListener;
+
+ virtual void SetUp() override {
+ mTestListener = new TestInputListener();
+ mClassifier = new InputClassifier(mTestListener);
+ }
+
+ virtual void TearDown() override {
+ mClassifier.clear();
+ mTestListener.clear();
+ }
+};
+
+/**
+ * Create a basic configuration change and send it to input classifier.
+ * Expect that the event is received by the next input stage, unmodified.
+ */
+TEST_F(InputClassifierTest, SendToNextStage_NotifyConfigurationChangedArgs) {
+ // Create a basic configuration change and send to classifier
+ NotifyConfigurationChangedArgs args(1/*sequenceNum*/, 2/*eventTime*/);
+
+ mClassifier->notifyConfigurationChanged(&args);
+ NotifyConfigurationChangedArgs outArgs;
+ ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyConfigurationChangedWasCalled(&outArgs));
+ ASSERT_EQ(args, outArgs);
+}
+
+TEST_F(InputClassifierTest, SendToNextStage_NotifyKeyArgs) {
+ // Create a basic key event and send to classifier
+ NotifyKeyArgs args(1/*sequenceNum*/, 2/*eventTime*/, 3/*deviceId*/, AINPUT_SOURCE_KEYBOARD,
+ ADISPLAY_ID_DEFAULT, 0/*policyFlags*/, AKEY_EVENT_ACTION_DOWN, 4/*flags*/,
+ AKEYCODE_HOME, 5/*scanCode*/, AMETA_NONE, 6/*downTime*/);
+
+ mClassifier->notifyKey(&args);
+ NotifyKeyArgs outArgs;
+ ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyKeyWasCalled(&outArgs));
+ ASSERT_EQ(args, outArgs);
+}
+
+
+/**
+ * Create a basic motion event and send it to input classifier.
+ * Expect that the event is received by the next input stage, unmodified.
+ */
+TEST_F(InputClassifierTest, SendToNextStage_NotifyMotionArgs) {
+ NotifyMotionArgs motionArgs = generateBasicMotionArgs();
+ mClassifier->notifyMotion(&motionArgs);
+ NotifyMotionArgs args;
+ ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(&args));
+ ASSERT_EQ(motionArgs, args);
+}
+
+/**
+ * Create a basic switch event and send it to input classifier.
+ * Expect that the event is received by the next input stage, unmodified.
+ */
+TEST_F(InputClassifierTest, SendToNextStage_NotifySwitchArgs) {
+ NotifySwitchArgs args(1/*sequenceNum*/, 2/*eventTime*/, 3/*policyFlags*/, 4/*switchValues*/,
+ 5/*switchMask*/);
+
+ mClassifier->notifySwitch(&args);
+ NotifySwitchArgs outArgs;
+ ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifySwitchWasCalled(&outArgs));
+ ASSERT_EQ(args, outArgs);
+}
+
+/**
+ * Create a basic device reset event and send it to input classifier.
+ * Expect that the event is received by the next input stage, unmodified.
+ */
+TEST_F(InputClassifierTest, SendToNextStage_NotifyDeviceResetArgs) {
+ NotifyDeviceResetArgs args(1/*sequenceNum*/, 2/*eventTime*/, 3/*deviceId*/);
+
+ mClassifier->notifyDeviceReset(&args);
+ NotifyDeviceResetArgs outArgs;
+ ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyDeviceResetWasCalled(&outArgs));
+ ASSERT_EQ(args, outArgs);
+}
+
+// --- MotionClassifierTest ---
+
+class MotionClassifierTest : public testing::Test {
+protected:
+ std::unique_ptr<MotionClassifierInterface> mMotionClassifier;
+
+ virtual void SetUp() override {
+ sp<android::hardware::input::classifier::V1_0::IInputClassifier> service =
+ classifier::V1_0::IInputClassifier::getService();
+ if (service) {
+ mMotionClassifier = std::make_unique<MotionClassifier>(service);
+ }
+ }
+};
+
+/**
+ * Since MotionClassifier creates a new thread to communicate with HAL,
+ * it's not really expected to ever exit. However, for testing purposes,
+ * we need to ensure that it is able to exit cleanly.
+ * If the thread is not properly cleaned up, it will generate SIGABRT.
+ * The logic for exiting the thread and cleaning up the resources is inside
+ * the destructor. Here, we just make sure the destructor does not crash.
+ */
+TEST_F(MotionClassifierTest, Destructor_DoesNotCrash) {
+ mMotionClassifier = nullptr;
+}
+
+/**
+ * Make sure MotionClassifier can handle events that don't have any
+ * video frames.
+ */
+TEST_F(MotionClassifierTest, Classify_NoVideoFrames) {
+ NotifyMotionArgs motionArgs = generateBasicMotionArgs();
+
+ // We are not checking the return value, because we can't be making assumptions
+ // about the HAL operation, since it will be highly hardware-dependent
+ if (mMotionClassifier) {
+ ASSERT_NO_FATAL_FAILURE(mMotionClassifier->classify(motionArgs));
+ }
+}
+
+/**
+ * Make sure nothing crashes when a videoFrame is sent.
+ */
+TEST_F(MotionClassifierTest, Classify_OneVideoFrame) {
+ NotifyMotionArgs motionArgs = generateBasicMotionArgs();
+
+ std::vector<int16_t> videoData = {1, 2, 3, 4};
+ timeval timestamp = { 1, 1};
+ TouchVideoFrame frame(2, 2, std::move(videoData), timestamp);
+ motionArgs.videoFrames = {frame};
+
+ // We are not checking the return value, because we can't be making assumptions
+ // about the HAL operation, since it will be highly hardware-dependent
+ if (mMotionClassifier) {
+ ASSERT_NO_FATAL_FAILURE(mMotionClassifier->classify(motionArgs));
+ }
+}
+
+/**
+ * Make sure nothing crashes when 2 videoFrames are sent.
+ */
+TEST_F(MotionClassifierTest, Classify_TwoVideoFrames) {
+ NotifyMotionArgs motionArgs = generateBasicMotionArgs();
+
+ std::vector<int16_t> videoData1 = {1, 2, 3, 4};
+ timeval timestamp1 = { 1, 1};
+ TouchVideoFrame frame1(2, 2, std::move(videoData1), timestamp1);
+
+ std::vector<int16_t> videoData2 = {6, 6, 6, 6};
+ timeval timestamp2 = { 1, 2};
+ TouchVideoFrame frame2(2, 2, std::move(videoData2), timestamp2);
+
+ motionArgs.videoFrames = {frame1, frame2};
+
+ // We are not checking the return value, because we can't be making assumptions
+ // about the HAL operation, since it will be highly hardware-dependent
+ if (mMotionClassifier) {
+ ASSERT_NO_FATAL_FAILURE(mMotionClassifier->classify(motionArgs));
+ }
+}
+
+/**
+ * Make sure MotionClassifier does not crash when it is reset.
+ */
+TEST_F(MotionClassifierTest, Reset_DoesNotCrash) {
+ if (mMotionClassifier) {
+ ASSERT_NO_FATAL_FAILURE(mMotionClassifier->reset());
+ }
+}
+
+/**
+ * Make sure MotionClassifier does not crash when a device is reset.
+ */
+TEST_F(MotionClassifierTest, DeviceReset_DoesNotCrash) {
+ NotifyDeviceResetArgs args(1/*sequenceNum*/, 2/*eventTime*/, 3/*deviceId*/);
+ if (mMotionClassifier) {
+ ASSERT_NO_FATAL_FAILURE(mMotionClassifier->reset(args));
+ }
+}
+
+} // namespace android
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index 26f01b7..0f987c3 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -48,9 +48,51 @@
public:
FakeInputDispatcherPolicy() {
+ mInputEventFiltered = false;
+ mTime = -1;
+ mAction = -1;
+ mDisplayId = -1;
+ }
+
+ void assertFilterInputEventWasCalledWithExpectedArgs(const NotifyMotionArgs* args) {
+ ASSERT_TRUE(mInputEventFiltered)
+ << "Expected filterInputEvent() to have been called.";
+
+ ASSERT_EQ(mTime, args->eventTime)
+ << "Expected time of filtered event was not matched";
+ ASSERT_EQ(mAction, args->action)
+ << "Expected action of filtered event was not matched";
+ ASSERT_EQ(mDisplayId, args->displayId)
+ << "Expected displayId of filtered event was not matched";
+
+ reset();
+ }
+
+ void assertFilterInputEventWasCalledWithExpectedArgs(const NotifyKeyArgs* args) {
+ ASSERT_TRUE(mInputEventFiltered)
+ << "Expected filterInputEvent() to have been called.";
+
+ ASSERT_EQ(mTime, args->eventTime)
+ << "Expected time of filtered event was not matched";
+ ASSERT_EQ(mAction, args->action)
+ << "Expected action of filtered event was not matched";
+ ASSERT_EQ(mDisplayId, args->displayId)
+ << "Expected displayId of filtered event was not matched";
+
+ reset();
+ }
+
+ void assertFilterInputEventWasNotCalled() {
+ ASSERT_FALSE(mInputEventFiltered)
+ << "Expected filterInputEvent() to not have been called.";
}
private:
+ bool mInputEventFiltered;
+ nsecs_t mTime;
+ int32_t mAction;
+ int32_t mDisplayId;
+
virtual void notifyConfigurationChanged(nsecs_t) {
}
@@ -63,14 +105,33 @@
virtual void notifyInputChannelBroken(const sp<IBinder>&) {
}
- virtual void notifyFocusChanged(const sp<IBinder>&) {
+ virtual void notifyFocusChanged(const sp<IBinder>&, const sp<IBinder>&) {
}
virtual void getDispatcherConfiguration(InputDispatcherConfiguration* outConfig) {
*outConfig = mConfig;
}
- virtual bool filterInputEvent(const InputEvent*, uint32_t) {
+ virtual bool filterInputEvent(const InputEvent* inputEvent, uint32_t policyFlags) {
+ switch (inputEvent->getType()) {
+ case AINPUT_EVENT_TYPE_KEY: {
+ const KeyEvent* keyEvent = static_cast<const KeyEvent*>(inputEvent);
+ mTime = keyEvent->getEventTime();
+ mAction = keyEvent->getAction();
+ mDisplayId = keyEvent->getDisplayId();
+ break;
+ }
+
+ case AINPUT_EVENT_TYPE_MOTION: {
+ const MotionEvent* motionEvent = static_cast<const MotionEvent*>(inputEvent);
+ mTime = motionEvent->getEventTime();
+ mAction = motionEvent->getAction();
+ mDisplayId = motionEvent->getDisplayId();
+ break;
+ }
+ }
+
+ mInputEventFiltered = true;
return true;
}
@@ -99,6 +160,13 @@
virtual bool checkInjectEventsPermissionNonReentrant(int32_t, int32_t) {
return false;
}
+
+ void reset() {
+ mInputEventFiltered = false;
+ mTime = -1;
+ mAction = -1;
+ mDisplayId = -1;
+ }
};
@@ -160,70 +228,70 @@
pointerCoords[i].clear();
}
+ // Some constants commonly used below
+ constexpr int32_t source = AINPUT_SOURCE_TOUCHSCREEN;
+ constexpr int32_t edgeFlags = AMOTION_EVENT_EDGE_FLAG_NONE;
+ constexpr int32_t metaState = AMETA_NONE;
+ constexpr MotionClassification classification = MotionClassification::NONE;
+
// Rejects undefined motion actions.
- event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID,
- /*action*/ -1, 0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
- ARBITRARY_TIME, ARBITRARY_TIME,
- /*pointerCount*/ 1, pointerProperties, pointerCoords);
+ event.initialize(DEVICE_ID, source, DISPLAY_ID,
+ /*action*/ -1, 0, 0, edgeFlags, metaState, 0, classification, 0, 0, 0, 0,
+ ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, pointerCoords);
ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
&event,
INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
<< "Should reject motion events with undefined action.";
// Rejects pointer down with invalid index.
- event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID,
+ event.initialize(DEVICE_ID, source, DISPLAY_ID,
AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
- 0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
- ARBITRARY_TIME, ARBITRARY_TIME,
- /*pointerCount*/ 1, pointerProperties, pointerCoords);
+ 0, 0, edgeFlags, metaState, 0, classification, 0, 0, 0, 0,
+ ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, pointerCoords);
ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
&event,
INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
<< "Should reject motion events with pointer down index too large.";
- event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID,
+ event.initialize(DEVICE_ID, source, DISPLAY_ID,
AMOTION_EVENT_ACTION_POINTER_DOWN | (~0U << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
- 0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
- ARBITRARY_TIME, ARBITRARY_TIME,
- /*pointerCount*/ 1, pointerProperties, pointerCoords);
+ 0, 0, edgeFlags, metaState, 0, classification, 0, 0, 0, 0,
+ ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, pointerCoords);
ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
&event,
INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
<< "Should reject motion events with pointer down index too small.";
// Rejects pointer up with invalid index.
- event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID,
+ event.initialize(DEVICE_ID, source, DISPLAY_ID,
AMOTION_EVENT_ACTION_POINTER_UP | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
- 0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
- ARBITRARY_TIME, ARBITRARY_TIME,
- /*pointerCount*/ 1, pointerProperties, pointerCoords);
+ 0, 0, edgeFlags, metaState, 0, classification, 0, 0, 0, 0,
+ ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, pointerCoords);
ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
&event,
INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
<< "Should reject motion events with pointer up index too large.";
- event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID,
+ event.initialize(DEVICE_ID, source, DISPLAY_ID,
AMOTION_EVENT_ACTION_POINTER_UP | (~0U << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
- 0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
- ARBITRARY_TIME, ARBITRARY_TIME,
- /*pointerCount*/ 1, pointerProperties, pointerCoords);
+ 0, 0, edgeFlags, metaState, 0, classification, 0, 0, 0, 0,
+ ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, pointerCoords);
ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
&event,
INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
<< "Should reject motion events with pointer up index too small.";
// Rejects motion events with invalid number of pointers.
- event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID,
- AMOTION_EVENT_ACTION_DOWN, 0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
- ARBITRARY_TIME, ARBITRARY_TIME,
- /*pointerCount*/ 0, pointerProperties, pointerCoords);
+ event.initialize(DEVICE_ID, source, DISPLAY_ID,
+ AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification, 0, 0, 0, 0,
+ ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 0, pointerProperties, pointerCoords);
ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
&event,
INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
<< "Should reject motion events with 0 pointers.";
- event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID,
- AMOTION_EVENT_ACTION_DOWN, 0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
+ event.initialize(DEVICE_ID, source, DISPLAY_ID,
+ AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification, 0, 0, 0, 0,
ARBITRARY_TIME, ARBITRARY_TIME,
/*pointerCount*/ MAX_POINTERS + 1, pointerProperties, pointerCoords);
ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
@@ -233,20 +301,18 @@
// Rejects motion events with invalid pointer ids.
pointerProperties[0].id = -1;
- event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID,
- AMOTION_EVENT_ACTION_DOWN, 0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
- ARBITRARY_TIME, ARBITRARY_TIME,
- /*pointerCount*/ 1, pointerProperties, pointerCoords);
+ event.initialize(DEVICE_ID, source, DISPLAY_ID,
+ AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification, 0, 0, 0, 0,
+ ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, pointerCoords);
ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
&event,
INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
<< "Should reject motion events with pointer ids less than 0.";
pointerProperties[0].id = MAX_POINTER_ID + 1;
- event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID,
- AMOTION_EVENT_ACTION_DOWN, 0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
- ARBITRARY_TIME, ARBITRARY_TIME,
- /*pointerCount*/ 1, pointerProperties, pointerCoords);
+ event.initialize(DEVICE_ID, source, DISPLAY_ID,
+ AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification, 0, 0, 0, 0,
+ ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, pointerCoords);
ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
&event,
INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
@@ -255,10 +321,9 @@
// Rejects motion events with duplicate pointer ids.
pointerProperties[0].id = 1;
pointerProperties[1].id = 1;
- event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID,
- AMOTION_EVENT_ACTION_DOWN, 0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
- ARBITRARY_TIME, ARBITRARY_TIME,
- /*pointerCount*/ 2, pointerProperties, pointerCoords);
+ event.initialize(DEVICE_ID, source, DISPLAY_ID,
+ AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification, 0, 0, 0, 0,
+ ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 2, pointerProperties, pointerCoords);
ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
&event,
INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
@@ -379,7 +444,7 @@
}
virtual bool updateInfo() {
- mInfo.token = mServerChannel->getToken();
+ mInfo.token = mServerChannel ? mServerChannel->getToken() : nullptr;
mInfo.name = mName;
mInfo.layoutParamsFlags = 0;
mInfo.layoutParamsType = InputWindowInfo::TYPE_APPLICATION;
@@ -408,14 +473,9 @@
mFocused = true;
}
- void assertNoEvents() {
- uint32_t consumeSeq;
- InputEvent* event;
- status_t status = mConsumer->consume(&mEventFactory, false /*consumeBatches*/, -1,
- &consumeSeq, &event);
- ASSERT_NE(OK, status)
- << mName.c_str()
- << ": should not have received any events, so consume(..) should not return OK.";
+ void releaseChannel() {
+ mServerChannel.clear();
+ InputWindowHandle::releaseChannel();
}
protected:
virtual bool handled() {
@@ -460,7 +520,8 @@
// Define a valid motion down event.
event.initialize(DEVICE_ID, source, displayId,
AMOTION_EVENT_ACTION_DOWN, /* actionButton */0, /* flags */ 0, /* edgeFlags */ 0,
- AMETA_NONE, /* buttonState */ 0, /* xOffset */ 0, /* yOffset */ 0, /* xPrecision */ 0,
+ AMETA_NONE, /* buttonState */ 0, MotionClassification::NONE,
+ /* xOffset */ 0, /* yOffset */ 0, /* xPrecision */ 0,
/* yPrecision */ 0, currentTime, currentTime, /*pointerCount*/ 1, pointerProperties,
pointerCoords);
@@ -471,6 +532,40 @@
INJECT_EVENT_TIMEOUT, POLICY_FLAG_FILTERED | POLICY_FLAG_PASS_TO_USER);
}
+static NotifyKeyArgs generateKeyArgs(int32_t action, int32_t displayId = ADISPLAY_ID_NONE) {
+ nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ // Define a valid key event.
+ NotifyKeyArgs args(/* sequenceNum */ 0, currentTime, DEVICE_ID, AINPUT_SOURCE_KEYBOARD,
+ displayId, POLICY_FLAG_PASS_TO_USER, action, /* flags */ 0,
+ AKEYCODE_A, KEY_A, AMETA_NONE, currentTime);
+
+ return args;
+}
+
+static NotifyMotionArgs generateMotionArgs(int32_t action, int32_t source, int32_t displayId) {
+ PointerProperties pointerProperties[1];
+ PointerCoords pointerCoords[1];
+
+ pointerProperties[0].clear();
+ pointerProperties[0].id = 0;
+ pointerProperties[0].toolType = AMOTION_EVENT_TOOL_TYPE_FINGER;
+
+ pointerCoords[0].clear();
+ pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, 100);
+ pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, 200);
+
+ nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ // Define a valid motion event.
+ NotifyMotionArgs args(/* sequenceNum */ 0, currentTime, DEVICE_ID, source, displayId,
+ POLICY_FLAG_PASS_TO_USER, action, /* actionButton */ 0, /* flags */ 0,
+ AMETA_NONE, /* buttonState */ 0, MotionClassification::NONE,
+ AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0, 1, pointerProperties,
+ pointerCoords, /* xPrecision */ 0, /* yPrecision */ 0, currentTime,
+ /* videoFrames */ {});
+
+ return args;
+}
+
TEST_F(InputDispatcherTest, SetInputWindow_SingleWindowTouch) {
sp<FakeApplicationHandle> application = new FakeApplicationHandle();
sp<FakeWindowHandle> window = new FakeWindowHandle(application, mDispatcher, "Fake Window",
@@ -517,7 +612,7 @@
sp<FakeWindowHandle> windowSecond = new FakeWindowHandle(application, mDispatcher, "Second",
ADISPLAY_ID_DEFAULT);
- // Set focus application.
+ // Set focused application.
mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
// Expect one focus window exist in display.
@@ -535,6 +630,32 @@
windowSecond->consumeEvent(AINPUT_EVENT_TYPE_KEY, ADISPLAY_ID_NONE);
}
+TEST_F(InputDispatcherTest, SetInputWindow_FocusPriority) {
+ sp<FakeApplicationHandle> application = new FakeApplicationHandle();
+ sp<FakeWindowHandle> windowTop = new FakeWindowHandle(application, mDispatcher, "Top",
+ ADISPLAY_ID_DEFAULT);
+ sp<FakeWindowHandle> windowSecond = new FakeWindowHandle(application, mDispatcher, "Second",
+ ADISPLAY_ID_DEFAULT);
+
+ // Set focused application.
+ mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
+
+ // Display has two focused windows. Add them to inputWindowsHandles in z-order (top most first)
+ windowTop->setFocus();
+ windowSecond->setFocus();
+ Vector<sp<InputWindowHandle>> inputWindowHandles;
+ inputWindowHandles.add(windowTop);
+ inputWindowHandles.add(windowSecond);
+
+ mDispatcher->setInputWindows(inputWindowHandles, ADISPLAY_ID_DEFAULT);
+ ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectKeyDown(mDispatcher))
+ << "Inject key event should return INPUT_EVENT_INJECTION_SUCCEEDED";
+
+ // Top focused window should receive event.
+ windowTop->consumeEvent(AINPUT_EVENT_TYPE_KEY, ADISPLAY_ID_NONE);
+ windowSecond->assertNoEvents();
+}
+
TEST_F(InputDispatcherTest, SetInputWindow_InputWindowInfo) {
sp<FakeApplicationHandle> application = new FakeApplicationHandle();
@@ -543,24 +664,25 @@
sp<FakeWindowHandle> windowSecond = new FakeWindowHandle(application, mDispatcher, "Second",
ADISPLAY_ID_DEFAULT);
- windowTop->setFocus();
+ // Set focused application.
+ mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
+ windowTop->setFocus();
+ windowSecond->setFocus();
Vector<sp<InputWindowHandle>> inputWindowHandles;
inputWindowHandles.add(windowTop);
inputWindowHandles.add(windowSecond);
-
- mDispatcher->setInputWindows(inputWindowHandles, ADISPLAY_ID_DEFAULT);
-
// Release channel for window is no longer valid.
windowTop->releaseChannel();
+ mDispatcher->setInputWindows(inputWindowHandles, ADISPLAY_ID_DEFAULT);
- // Test inject a motion down, should timeout because of no target channel.
- ASSERT_EQ(INPUT_EVENT_INJECTION_TIMED_OUT, injectKeyDown(mDispatcher))
- << "Inject key event should return INPUT_EVENT_INJECTION_TIMED_OUT";
+ // Test inject a key down, should dispatch to a valid window.
+ ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectKeyDown(mDispatcher))
+ << "Inject key event should return INPUT_EVENT_INJECTION_SUCCEEDED";
// Top window is invalid, so it should not receive any input event.
windowTop->assertNoEvents();
- windowSecond->assertNoEvents();
+ windowSecond->consumeEvent(AINPUT_EVENT_TYPE_KEY, ADISPLAY_ID_NONE);
}
/* Test InputDispatcher for MultiDisplay */
@@ -716,4 +838,76 @@
monitorInSecondary->consumeEvent(AINPUT_EVENT_TYPE_KEY, ADISPLAY_ID_NONE);
}
+class InputFilterTest : public InputDispatcherTest {
+protected:
+ static constexpr int32_t SECOND_DISPLAY_ID = 1;
+
+ void testNotifyMotion(int32_t displayId, bool expectToBeFiltered) {
+ NotifyMotionArgs motionArgs;
+
+ motionArgs = generateMotionArgs(
+ AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, displayId);
+ mDispatcher->notifyMotion(&motionArgs);
+ motionArgs = generateMotionArgs(
+ AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN, displayId);
+ mDispatcher->notifyMotion(&motionArgs);
+
+ if (expectToBeFiltered) {
+ mFakePolicy->assertFilterInputEventWasCalledWithExpectedArgs(&motionArgs);
+ } else {
+ mFakePolicy->assertFilterInputEventWasNotCalled();
+ }
+ }
+
+ void testNotifyKey(bool expectToBeFiltered) {
+ NotifyKeyArgs keyArgs;
+
+ keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_DOWN);
+ mDispatcher->notifyKey(&keyArgs);
+ keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_UP);
+ mDispatcher->notifyKey(&keyArgs);
+
+ if (expectToBeFiltered) {
+ mFakePolicy->assertFilterInputEventWasCalledWithExpectedArgs(&keyArgs);
+ } else {
+ mFakePolicy->assertFilterInputEventWasNotCalled();
+ }
+ }
+};
+
+// Test InputFilter for MotionEvent
+TEST_F(InputFilterTest, MotionEvent_InputFilter) {
+ // Since the InputFilter is disabled by default, check if touch events aren't filtered.
+ testNotifyMotion(ADISPLAY_ID_DEFAULT, /*expectToBeFiltered*/ false);
+ testNotifyMotion(SECOND_DISPLAY_ID, /*expectToBeFiltered*/ false);
+
+ // Enable InputFilter
+ mDispatcher->setInputFilterEnabled(true);
+ // Test touch on both primary and second display, and check if both events are filtered.
+ testNotifyMotion(ADISPLAY_ID_DEFAULT, /*expectToBeFiltered*/ true);
+ testNotifyMotion(SECOND_DISPLAY_ID, /*expectToBeFiltered*/ true);
+
+ // Disable InputFilter
+ mDispatcher->setInputFilterEnabled(false);
+ // Test touch on both primary and second display, and check if both events aren't filtered.
+ testNotifyMotion(ADISPLAY_ID_DEFAULT, /*expectToBeFiltered*/ false);
+ testNotifyMotion(SECOND_DISPLAY_ID, /*expectToBeFiltered*/ false);
+}
+
+// Test InputFilter for KeyEvent
+TEST_F(InputFilterTest, KeyEvent_InputFilter) {
+ // Since the InputFilter is disabled by default, check if key event aren't filtered.
+ testNotifyKey(/*expectToBeFiltered*/ false);
+
+ // Enable InputFilter
+ mDispatcher->setInputFilterEnabled(true);
+ // Send a key event, and check if it is filtered.
+ testNotifyKey(/*expectToBeFiltered*/ true);
+
+ // Disable InputFilter
+ mDispatcher->setInputFilterEnabled(false);
+ // Send a key event, and check if it isn't filtered.
+ testNotifyKey(/*expectToBeFiltered*/ false);
+}
+
} // namespace android
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index d39d8dc..84c5ad6 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -15,12 +15,13 @@
*/
#include "../InputReader.h"
+#include "TestInputListener.h"
-#include <inttypes.h>
-#include <utils/List.h>
#include <gtest/gtest.h>
+#include <inttypes.h>
#include <math.h>
+
namespace android {
// An arbitrary time value.
@@ -57,6 +58,7 @@
float mMinX, mMinY, mMaxX, mMaxY;
float mX, mY;
int32_t mButtonState;
+ int32_t mDisplayId;
protected:
virtual ~FakePointerController() { }
@@ -64,7 +66,7 @@
public:
FakePointerController() :
mHaveBounds(false), mMinX(0), mMinY(0), mMaxX(0), mMaxY(0), mX(0), mY(0),
- mButtonState(0) {
+ mButtonState(0), mDisplayId(ADISPLAY_ID_DEFAULT) {
}
void setBounds(float minX, float minY, float maxX, float maxY) {
@@ -75,6 +77,10 @@
mMaxY = maxY;
}
+ void setDisplayId(int32_t displayId) {
+ mDisplayId = displayId;
+ }
+
virtual void setPosition(float x, float y) {
mX = x;
mY = y;
@@ -93,6 +99,10 @@
*outY = mY;
}
+ virtual int32_t getDisplayId() const {
+ return mDisplayId;
+ }
+
private:
virtual bool getBounds(float* outMinX, float* outMinY, float* outMaxX, float* outMaxY) const {
*outMinX = mMinX;
@@ -264,114 +274,6 @@
}
};
-
-// --- FakeInputListener ---
-
-class FakeInputListener : public InputListenerInterface {
-private:
- List<NotifyConfigurationChangedArgs> mNotifyConfigurationChangedArgsQueue;
- List<NotifyDeviceResetArgs> mNotifyDeviceResetArgsQueue;
- List<NotifyKeyArgs> mNotifyKeyArgsQueue;
- List<NotifyMotionArgs> mNotifyMotionArgsQueue;
- List<NotifySwitchArgs> mNotifySwitchArgsQueue;
-
-protected:
- virtual ~FakeInputListener() { }
-
-public:
- FakeInputListener() {
- }
-
- void assertNotifyConfigurationChangedWasCalled(
- NotifyConfigurationChangedArgs* outEventArgs = nullptr) {
- ASSERT_FALSE(mNotifyConfigurationChangedArgsQueue.empty())
- << "Expected notifyConfigurationChanged() to have been called.";
- if (outEventArgs) {
- *outEventArgs = *mNotifyConfigurationChangedArgsQueue.begin();
- }
- mNotifyConfigurationChangedArgsQueue.erase(mNotifyConfigurationChangedArgsQueue.begin());
- }
-
- void assertNotifyConfigurationChangedWasNotCalled() {
- ASSERT_TRUE(mNotifyConfigurationChangedArgsQueue.empty())
- << "Expected notifyConfigurationChanged() to not have been called.";
- }
-
- void assertNotifyDeviceResetWasCalled(
- NotifyDeviceResetArgs* outEventArgs = nullptr) {
- ASSERT_FALSE(mNotifyDeviceResetArgsQueue.empty())
- << "Expected notifyDeviceReset() to have been called.";
- if (outEventArgs) {
- *outEventArgs = *mNotifyDeviceResetArgsQueue.begin();
- }
- mNotifyDeviceResetArgsQueue.erase(mNotifyDeviceResetArgsQueue.begin());
- }
-
- void assertNotifyDeviceResetWasNotCalled() {
- ASSERT_TRUE(mNotifyDeviceResetArgsQueue.empty())
- << "Expected notifyDeviceReset() to not have been called.";
- }
-
- void assertNotifyKeyWasCalled(NotifyKeyArgs* outEventArgs = nullptr) {
- ASSERT_FALSE(mNotifyKeyArgsQueue.empty())
- << "Expected notifyKey() to have been called.";
- if (outEventArgs) {
- *outEventArgs = *mNotifyKeyArgsQueue.begin();
- }
- mNotifyKeyArgsQueue.erase(mNotifyKeyArgsQueue.begin());
- }
-
- void assertNotifyKeyWasNotCalled() {
- ASSERT_TRUE(mNotifyKeyArgsQueue.empty())
- << "Expected notifyKey() to not have been called.";
- }
-
- void assertNotifyMotionWasCalled(NotifyMotionArgs* outEventArgs = nullptr) {
- ASSERT_FALSE(mNotifyMotionArgsQueue.empty())
- << "Expected notifyMotion() to have been called.";
- if (outEventArgs) {
- *outEventArgs = *mNotifyMotionArgsQueue.begin();
- }
- mNotifyMotionArgsQueue.erase(mNotifyMotionArgsQueue.begin());
- }
-
- void assertNotifyMotionWasNotCalled() {
- ASSERT_TRUE(mNotifyMotionArgsQueue.empty())
- << "Expected notifyMotion() to not have been called.";
- }
-
- void assertNotifySwitchWasCalled(NotifySwitchArgs* outEventArgs = nullptr) {
- ASSERT_FALSE(mNotifySwitchArgsQueue.empty())
- << "Expected notifySwitch() to have been called.";
- if (outEventArgs) {
- *outEventArgs = *mNotifySwitchArgsQueue.begin();
- }
- mNotifySwitchArgsQueue.erase(mNotifySwitchArgsQueue.begin());
- }
-
-private:
- virtual void notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) {
- mNotifyConfigurationChangedArgsQueue.push_back(*args);
- }
-
- virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args) {
- mNotifyDeviceResetArgsQueue.push_back(*args);
- }
-
- virtual void notifyKey(const NotifyKeyArgs* args) {
- mNotifyKeyArgsQueue.push_back(*args);
- }
-
- virtual void notifyMotion(const NotifyMotionArgs* args) {
- mNotifyMotionArgsQueue.push_back(*args);
- }
-
- virtual void notifySwitch(const NotifySwitchArgs* args) {
- mNotifySwitchArgsQueue.push_back(*args);
- }
-};
-
-
// --- FakeEventHub ---
class FakeEventHub : public EventHubInterface {
@@ -939,6 +841,7 @@
bool mResetWasCalled;
bool mProcessWasCalled;
+ std::optional<DisplayViewport> mViewport;
public:
FakeInputMapper(InputDevice* device, uint32_t sources) :
InputMapper(device),
@@ -1007,8 +910,14 @@
}
}
- virtual void configure(nsecs_t, const InputReaderConfiguration*, uint32_t) {
+ virtual void configure(nsecs_t, const InputReaderConfiguration* config, uint32_t changes) {
mConfigureWasCalled = true;
+
+ // Find the associated viewport if exist.
+ const std::optional<uint8_t> displayPort = mDevice->getAssociatedDisplayPort();
+ if (displayPort && (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO)) {
+ mViewport = config->getDisplayViewportByPort(*displayPort);
+ }
}
virtual void reset(nsecs_t) {
@@ -1055,6 +964,13 @@
virtual void fadePointer() {
}
+
+ virtual std::optional<int32_t> getAssociatedDisplay() {
+ if (mViewport) {
+ return std::make_optional(mViewport->displayId);
+ }
+ return std::nullopt;
+ }
};
@@ -1082,9 +998,10 @@
}
InputDevice* newDevice(int32_t deviceId, int32_t controllerNumber, const std::string& name,
- uint32_t classes) {
+ uint32_t classes, const std::string& location = "") {
InputDeviceIdentifier identifier;
identifier.name = name;
+ identifier.location = location;
int32_t generation = deviceId + 1;
return new InputDevice(&mContext, deviceId, generation, controllerNumber, identifier,
classes);
@@ -1294,7 +1211,7 @@
class InputReaderTest : public testing::Test {
protected:
- sp<FakeInputListener> mFakeListener;
+ sp<TestInputListener> mFakeListener;
sp<FakeInputReaderPolicy> mFakePolicy;
sp<FakeEventHub> mFakeEventHub;
sp<InstrumentedInputReader> mReader;
@@ -1302,7 +1219,7 @@
virtual void SetUp() {
mFakeEventHub = new FakeEventHub();
mFakePolicy = new FakeInputReaderPolicy();
- mFakeListener = new FakeInputListener();
+ mFakeListener = new TestInputListener();
mReader = new InstrumentedInputReader(mFakeEventHub, mFakePolicy, mFakeListener);
}
@@ -1384,7 +1301,7 @@
TEST_F(InputReaderTest, WhenEnabledChanges_SendsDeviceResetNotification) {
constexpr int32_t deviceId = 1;
constexpr uint32_t deviceClass = INPUT_DEVICE_CLASS_KEYBOARD;
- InputDevice* device = mReader->newDevice(deviceId, 0, "fake", deviceClass);
+ InputDevice* device = mReader->newDevice(deviceId, 0 /*controllerNumber*/, "fake", deviceClass);
// Must add at least one mapper or the device will be ignored!
FakeInputMapper* mapper = new FakeInputMapper(device, AINPUT_SOURCE_KEYBOARD);
device->addMapper(mapper);
@@ -1568,7 +1485,7 @@
TEST_F(InputReaderTest, DeviceReset_IncrementsSequenceNumber) {
constexpr int32_t deviceId = 1;
constexpr uint32_t deviceClass = INPUT_DEVICE_CLASS_KEYBOARD;
- InputDevice* device = mReader->newDevice(deviceId, 0, "fake", deviceClass);
+ InputDevice* device = mReader->newDevice(deviceId, 0 /*controllerNumber*/, "fake", deviceClass);
// Must add at least one mapper or the device will be ignored!
FakeInputMapper* mapper = new FakeInputMapper(device, AINPUT_SOURCE_KEYBOARD);
device->addMapper(mapper);
@@ -1598,6 +1515,36 @@
prevSequenceNum = resetArgs.sequenceNum;
}
+TEST_F(InputReaderTest, Device_CanDispatchToDisplay) {
+ constexpr int32_t deviceId = 1;
+ constexpr uint32_t deviceClass = INPUT_DEVICE_CLASS_KEYBOARD;
+ const char* DEVICE_LOCATION = "USB1";
+ InputDevice* device = mReader->newDevice(deviceId, 0 /*controllerNumber*/, "fake", deviceClass,
+ DEVICE_LOCATION);
+ FakeInputMapper* mapper = new FakeInputMapper(device, AINPUT_SOURCE_TOUCHSCREEN);
+ device->addMapper(mapper);
+ mReader->setNextDevice(device);
+ addDevice(deviceId, "fake", deviceClass, nullptr);
+
+ const uint8_t hdmi1 = 1;
+
+ // Associated touch screen with second display.
+ mFakePolicy->addInputPortAssociation(DEVICE_LOCATION, hdmi1);
+
+ // Add default and second display.
+ mFakePolicy->addDisplayViewport(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT,
+ DISPLAY_ORIENTATION_0, "local:0", NO_PORT, ViewportType::VIEWPORT_INTERNAL);
+ mFakePolicy->addDisplayViewport(SECONDARY_DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT,
+ DISPLAY_ORIENTATION_0, "local:1", hdmi1, ViewportType::VIEWPORT_EXTERNAL);
+ mReader->requestRefreshConfiguration(InputReaderConfiguration::CHANGE_DISPLAY_INFO);
+ mReader->loopOnce();
+
+ // Check device.
+ ASSERT_EQ(deviceId, device->getId());
+ ASSERT_FALSE(mReader->canDispatchToDisplay(deviceId, DISPLAY_ID));
+ ASSERT_TRUE(mReader->canDispatchToDisplay(deviceId, SECONDARY_DISPLAY_ID));
+}
+
// --- InputDeviceTest ---
@@ -1611,7 +1558,7 @@
sp<FakeEventHub> mFakeEventHub;
sp<FakeInputReaderPolicy> mFakePolicy;
- sp<FakeInputListener> mFakeListener;
+ sp<TestInputListener> mFakeListener;
FakeInputReaderContext* mFakeContext;
InputDevice* mDevice;
@@ -1619,7 +1566,7 @@
virtual void SetUp() {
mFakeEventHub = new FakeEventHub();
mFakePolicy = new FakeInputReaderPolicy();
- mFakeListener = new FakeInputListener();
+ mFakeListener = new TestInputListener();
mFakeContext = new FakeInputReaderContext(mFakeEventHub, mFakePolicy, mFakeListener);
mFakeEventHub->addDevice(DEVICE_ID, DEVICE_NAME, 0);
@@ -1806,14 +1753,14 @@
sp<FakeEventHub> mFakeEventHub;
sp<FakeInputReaderPolicy> mFakePolicy;
- sp<FakeInputListener> mFakeListener;
+ sp<TestInputListener> mFakeListener;
FakeInputReaderContext* mFakeContext;
InputDevice* mDevice;
virtual void SetUp() {
mFakeEventHub = new FakeEventHub();
mFakePolicy = new FakeInputReaderPolicy();
- mFakeListener = new FakeInputListener();
+ mFakeListener = new TestInputListener();
mFakeContext = new FakeInputReaderContext(mFakeEventHub, mFakePolicy, mFakeListener);
InputDeviceIdentifier identifier;
identifier.name = DEVICE_NAME;
@@ -3169,6 +3116,30 @@
ASSERT_NO_FATAL_FAILURE(assertPosition(mFakePointerController, 110.0f, 220.0f));
}
+TEST_F(CursorInputMapperTest, Process_ShouldHandleDisplayId) {
+ CursorInputMapper* mapper = new CursorInputMapper(mDevice);
+ addMapperAndConfigure(mapper);
+
+ // Setup PointerController for second display.
+ constexpr int32_t SECOND_DISPLAY_ID = 1;
+ mFakePointerController->setBounds(0, 0, 800 - 1, 480 - 1);
+ mFakePointerController->setPosition(100, 200);
+ mFakePointerController->setButtonState(0);
+ mFakePointerController->setDisplayId(SECOND_DISPLAY_ID);
+
+ NotifyMotionArgs args;
+ process(mapper, ARBITRARY_TIME, EV_REL, REL_X, 10);
+ process(mapper, ARBITRARY_TIME, EV_REL, REL_Y, 20);
+ process(mapper, ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
+ ASSERT_EQ(AINPUT_SOURCE_MOUSE, args.source);
+ ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, args.action);
+ ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0],
+ 110.0f, 220.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f));
+ ASSERT_NO_FATAL_FAILURE(assertPosition(mFakePointerController, 110.0f, 220.0f));
+ ASSERT_EQ(SECOND_DISPLAY_ID, args.displayId);
+}
+
// --- TouchInputMapperTest ---
@@ -6318,4 +6289,30 @@
ASSERT_EQ(SECONDARY_DISPLAY_ID, motionArgs.displayId);
}
+TEST_F(MultiTouchInputMapperTest, Process_Pointer_ShouldHandleDisplayId) {
+ // Setup PointerController for second display.
+ sp<FakePointerController> fakePointerController = new FakePointerController();
+ fakePointerController->setBounds(0, 0, 800 - 1, 480 - 1);
+ fakePointerController->setPosition(100, 200);
+ fakePointerController->setButtonState(0);
+ fakePointerController->setDisplayId(SECONDARY_DISPLAY_ID);
+ mFakePolicy->setPointerController(mDevice->getId(), fakePointerController);
+
+ MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice);
+ prepareDisplay(DISPLAY_ORIENTATION_0);
+ prepareAxes(POSITION);
+ addMapperAndConfigure(mapper);
+
+ // Check source is mouse that would obtain the PointerController.
+ ASSERT_EQ(AINPUT_SOURCE_MOUSE, mapper->getSources());
+
+ NotifyMotionArgs motionArgs;
+ processPosition(mapper, 100, 100);
+ processSync(mapper);
+
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+ ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, motionArgs.action);
+ ASSERT_EQ(SECONDARY_DISPLAY_ID, motionArgs.displayId);
+}
+
} // namespace android
diff --git a/services/inputflinger/tests/TestInputListener.cpp b/services/inputflinger/tests/TestInputListener.cpp
new file mode 100644
index 0000000..3ee33f1
--- /dev/null
+++ b/services/inputflinger/tests/TestInputListener.cpp
@@ -0,0 +1,115 @@
+/*
+ * 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 "TestInputListener.h"
+
+namespace android {
+
+// --- TestInputListener ---
+
+TestInputListener::TestInputListener() { }
+
+TestInputListener::~TestInputListener() { }
+
+void TestInputListener::assertNotifyConfigurationChangedWasCalled(
+ NotifyConfigurationChangedArgs* outEventArgs) {
+ ASSERT_FALSE(mNotifyConfigurationChangedArgsQueue.empty())
+ << "Expected notifyConfigurationChanged() to have been called.";
+ if (outEventArgs) {
+ *outEventArgs = *mNotifyConfigurationChangedArgsQueue.begin();
+ }
+ mNotifyConfigurationChangedArgsQueue.erase(mNotifyConfigurationChangedArgsQueue.begin());
+}
+
+void TestInputListener::assertNotifyConfigurationChangedWasNotCalled() {
+ ASSERT_TRUE(mNotifyConfigurationChangedArgsQueue.empty())
+ << "Expected notifyConfigurationChanged() to not have been called.";
+}
+
+void TestInputListener::assertNotifyDeviceResetWasCalled(
+ NotifyDeviceResetArgs* outEventArgs) {
+ ASSERT_FALSE(mNotifyDeviceResetArgsQueue.empty())
+ << "Expected notifyDeviceReset() to have been called.";
+ if (outEventArgs) {
+ *outEventArgs = *mNotifyDeviceResetArgsQueue.begin();
+ }
+ mNotifyDeviceResetArgsQueue.erase(mNotifyDeviceResetArgsQueue.begin());
+}
+
+void TestInputListener::assertNotifyDeviceResetWasNotCalled() {
+ ASSERT_TRUE(mNotifyDeviceResetArgsQueue.empty())
+ << "Expected notifyDeviceReset() to not have been called.";
+}
+
+void TestInputListener::assertNotifyKeyWasCalled(NotifyKeyArgs* outEventArgs) {
+ ASSERT_FALSE(mNotifyKeyArgsQueue.empty()) << "Expected notifyKey() to have been called.";
+ if (outEventArgs) {
+ *outEventArgs = *mNotifyKeyArgsQueue.begin();
+ }
+ mNotifyKeyArgsQueue.erase(mNotifyKeyArgsQueue.begin());
+}
+
+void TestInputListener::assertNotifyKeyWasNotCalled() {
+ ASSERT_TRUE(mNotifyKeyArgsQueue.empty()) << "Expected notifyKey() to not have been called.";
+}
+
+void TestInputListener::assertNotifyMotionWasCalled(NotifyMotionArgs* outEventArgs) {
+ ASSERT_FALSE(mNotifyMotionArgsQueue.empty()) << "Expected notifyMotion() to have been called.";
+ if (outEventArgs) {
+ *outEventArgs = *mNotifyMotionArgsQueue.begin();
+ }
+ mNotifyMotionArgsQueue.erase(mNotifyMotionArgsQueue.begin());
+}
+
+void TestInputListener::assertNotifyMotionWasNotCalled() {
+ ASSERT_TRUE(mNotifyMotionArgsQueue.empty())
+ << "Expected notifyMotion() to not have been called.";
+}
+
+void TestInputListener::assertNotifySwitchWasCalled(NotifySwitchArgs* outEventArgs) {
+ ASSERT_FALSE(mNotifySwitchArgsQueue.empty())
+ << "Expected notifySwitch() to have been called.";
+ if (outEventArgs) {
+ *outEventArgs = *mNotifySwitchArgsQueue.begin();
+ }
+ mNotifySwitchArgsQueue.erase(mNotifySwitchArgsQueue.begin());
+}
+
+void TestInputListener::notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) {
+ mNotifyConfigurationChangedArgsQueue.push_back(*args);
+}
+
+void TestInputListener::notifyDeviceReset(const NotifyDeviceResetArgs* args) {
+ mNotifyDeviceResetArgsQueue.push_back(*args);
+}
+
+void TestInputListener::notifyKey(const NotifyKeyArgs* args) {
+ mNotifyKeyArgsQueue.push_back(*args);
+}
+
+void TestInputListener::notifyMotion(const NotifyMotionArgs* args) {
+ mNotifyMotionArgsQueue.push_back(*args);
+}
+
+void TestInputListener::notifySwitch(const NotifySwitchArgs* args) {
+ mNotifySwitchArgsQueue.push_back(*args);
+ }
+
+
+} // namespace android
diff --git a/services/inputflinger/tests/TestInputListener.h b/services/inputflinger/tests/TestInputListener.h
new file mode 100644
index 0000000..085d343
--- /dev/null
+++ b/services/inputflinger/tests/TestInputListener.h
@@ -0,0 +1,73 @@
+/*
+ * 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_TEST_INPUT_LISTENER_H
+#define _UI_TEST_INPUT_LISTENER_H
+
+#include <gtest/gtest.h>
+#include "InputListener.h"
+
+namespace android {
+
+// --- TestInputListener ---
+
+class TestInputListener : public InputListenerInterface {
+private:
+ std::vector<NotifyConfigurationChangedArgs> mNotifyConfigurationChangedArgsQueue;
+ std::vector<NotifyDeviceResetArgs> mNotifyDeviceResetArgsQueue;
+ std::vector<NotifyKeyArgs> mNotifyKeyArgsQueue;
+ std::vector<NotifyMotionArgs> mNotifyMotionArgsQueue;
+ std::vector<NotifySwitchArgs> mNotifySwitchArgsQueue;
+
+protected:
+ virtual ~TestInputListener();
+
+public:
+ TestInputListener();
+
+ void assertNotifyConfigurationChangedWasCalled(
+ NotifyConfigurationChangedArgs* outEventArgs = nullptr);
+
+ void assertNotifyConfigurationChangedWasNotCalled();
+
+ void assertNotifyDeviceResetWasCalled(NotifyDeviceResetArgs* outEventArgs = nullptr);
+
+ void assertNotifyDeviceResetWasNotCalled();
+
+ void assertNotifyKeyWasCalled(NotifyKeyArgs* outEventArgs = nullptr);
+
+ void assertNotifyKeyWasNotCalled();
+
+ void assertNotifyMotionWasCalled(NotifyMotionArgs* outEventArgs = nullptr);
+
+ void assertNotifyMotionWasNotCalled();
+
+ void assertNotifySwitchWasCalled(NotifySwitchArgs* outEventArgs = nullptr);
+
+private:
+ virtual void notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args);
+
+ virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args);
+
+ virtual void notifyKey(const NotifyKeyArgs* args);
+
+ virtual void notifyMotion(const NotifyMotionArgs* args);
+
+ virtual void notifySwitch(const NotifySwitchArgs* args);
+};
+
+} // namespace android
+#endif
diff --git a/services/nativeperms/Android.bp b/services/nativeperms/Android.bp
new file mode 100644
index 0000000..cbc7d66
--- /dev/null
+++ b/services/nativeperms/Android.bp
@@ -0,0 +1,34 @@
+// Copyright 2016 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_binary {
+ name: "nativeperms",
+ srcs: [
+ "nativeperms.cpp",
+ "android/os/IPermissionController.aidl",
+ ],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
+ shared_libs: [
+ "libbinder",
+ "libbrillo",
+ "libbrillo-binder",
+ "libchrome",
+ "libutils",
+ ],
+ init_rc: ["nativeperms.rc"],
+}
diff --git a/services/nativeperms/Android.mk b/services/nativeperms/Android.mk
deleted file mode 100644
index 34ccd0b..0000000
--- a/services/nativeperms/Android.mk
+++ /dev/null
@@ -1,31 +0,0 @@
-# Copyright 2016 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := nativeperms
-LOCAL_SRC_FILES := \
- nativeperms.cpp \
- android/os/IPermissionController.aidl
-LOCAL_CFLAGS := -Wall -Werror
-LOCAL_SHARED_LIBRARIES := \
- libbinder \
- libbrillo \
- libbrillo-binder \
- libchrome \
- libutils
-LOCAL_INIT_RC := nativeperms.rc
-include $(BUILD_EXECUTABLE)
diff --git a/services/sensorservice/SensorDevice.cpp b/services/sensorservice/SensorDevice.cpp
index 9b2cd50..189ae36 100644
--- a/services/sensorservice/SensorDevice.cpp
+++ b/services/sensorservice/SensorDevice.cpp
@@ -35,6 +35,7 @@
using namespace android::hardware::sensors::V1_0::implementation;
using android::hardware::sensors::V2_0::ISensorsCallback;
using android::hardware::sensors::V2_0::EventQueueFlagBits;
+using android::hardware::sensors::V2_0::WakeLockQueueFlagBits;
using android::hardware::hidl_vec;
using android::hardware::Return;
using android::SensorDeviceUtils::HidlServiceRegistrationWaiter;
@@ -94,6 +95,8 @@
SensorDevice::SensorDevice()
: mHidlTransportErrors(20),
mRestartWaiter(new HidlServiceRegistrationWaiter()),
+ mEventQueueFlag(nullptr),
+ mWakeLockQueueFlag(nullptr),
mReconnecting(false) {
if (!connectHidlService()) {
return;
@@ -137,6 +140,11 @@
hardware::EventFlag::deleteEventFlag(&mEventQueueFlag);
mEventQueueFlag = nullptr;
}
+
+ if (mWakeLockQueueFlag != nullptr) {
+ hardware::EventFlag::deleteEventFlag(&mWakeLockQueueFlag);
+ mWakeLockQueueFlag = nullptr;
+ }
}
bool SensorDevice::connectHidlService() {
@@ -198,10 +206,16 @@
SensorEventQueue::MAX_RECEIVE_BUFFER_EVENT_COUNT,
true /* configureEventFlagWord */);
+ hardware::EventFlag::deleteEventFlag(&mEventQueueFlag);
hardware::EventFlag::createEventFlag(mEventQueue->getEventFlagWord(), &mEventQueueFlag);
+ hardware::EventFlag::deleteEventFlag(&mWakeLockQueueFlag);
+ hardware::EventFlag::createEventFlag(mWakeLockQueue->getEventFlagWord(),
+ &mWakeLockQueueFlag);
+
CHECK(mSensors != nullptr && mEventQueue != nullptr &&
- mWakeLockQueue != nullptr && mEventQueueFlag != nullptr);
+ mWakeLockQueue != nullptr && mEventQueueFlag != nullptr &&
+ mWakeLockQueueFlag != nullptr);
status_t status = StatusFromResult(checkReturn(mSensors->initialize(
*mEventQueue->getDesc(),
@@ -512,9 +526,12 @@
}
void SensorDevice::writeWakeLockHandled(uint32_t count) {
- if (mSensors != nullptr && mSensors->supportsMessageQueues() &&
- !mWakeLockQueue->write(&count)) {
- ALOGW("Failed to write wake lock handled");
+ if (mSensors != nullptr && mSensors->supportsMessageQueues()) {
+ if (mWakeLockQueue->write(&count)) {
+ mWakeLockQueueFlag->wake(asBaseType(WakeLockQueueFlagBits::DATA_WRITTEN));
+ } else {
+ ALOGW("Failed to write wake lock handled");
+ }
}
}
diff --git a/services/sensorservice/SensorDevice.h b/services/sensorservice/SensorDevice.h
index e1024ac..2a69654 100644
--- a/services/sensorservice/SensorDevice.h
+++ b/services/sensorservice/SensorDevice.h
@@ -238,6 +238,7 @@
std::unique_ptr<WakeLockQueue> mWakeLockQueue;
hardware::EventFlag* mEventQueueFlag;
+ hardware::EventFlag* mWakeLockQueueFlag;
std::array<Event, SensorEventQueue::MAX_RECEIVE_BUFFER_EVENT_COUNT> mEventBuffer;
diff --git a/services/sensorservice/SensorRecord.h b/services/sensorservice/SensorRecord.h
index 5a35410..031744a 100644
--- a/services/sensorservice/SensorRecord.h
+++ b/services/sensorservice/SensorRecord.h
@@ -25,7 +25,7 @@
class SensorService::SensorRecord {
public:
- SensorRecord(const sp<const SensorEventConnection>& connection);
+ explicit SensorRecord(const sp<const SensorEventConnection>& connection);
bool addConnection(const sp<const SensorEventConnection>& connection);
bool removeConnection(const wp<const SensorEventConnection>& connection);
size_t getNumConnections() const { return mConnections.size(); }
diff --git a/services/sensorservice/hidl/include/sensorservicehidl/SensorManager.h b/services/sensorservice/hidl/include/sensorservicehidl/SensorManager.h
index ddcee28..8d7a05b 100644
--- a/services/sensorservice/hidl/include/sensorservicehidl/SensorManager.h
+++ b/services/sensorservice/hidl/include/sensorservicehidl/SensorManager.h
@@ -43,7 +43,7 @@
struct SensorManager final : public ISensorManager {
- SensorManager(JavaVM* vm);
+ explicit SensorManager(JavaVM* vm);
~SensorManager();
// Methods from ::android::frameworks::sensorservice::V1_0::ISensorManager follow.
diff --git a/services/sensorservice/mat.h b/services/sensorservice/mat.h
index 495c14e..934ae58 100644
--- a/services/sensorservice/mat.h
+++ b/services/sensorservice/mat.h
@@ -139,13 +139,13 @@
mat() { }
mat(const mat& rhs) : base(rhs) { }
- mat(const base& rhs) : base(rhs) { } // NOLINT(implicit)
+ mat(const base& rhs) : base(rhs) { } // NOLINT(google-explicit-constructor)
// -----------------------------------------------------------------------
// conversion constructors
// sets the diagonal to the value, off-diagonal to zero
- mat(pTYPE rhs) { // NOLINT(implicit)
+ mat(pTYPE rhs) { // NOLINT(google-explicit-constructor)
helpers::doAssign(*this, rhs);
}
diff --git a/services/sensorservice/tests/Android.bp b/services/sensorservice/tests/Android.bp
new file mode 100644
index 0000000..d33c0ca
--- /dev/null
+++ b/services/sensorservice/tests/Android.bp
@@ -0,0 +1,13 @@
+cc_binary {
+ name: "test-sensorservice",
+ srcs: ["sensorservicetest.cpp"],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
+ shared_libs: [
+ "libutils",
+ "libsensor",
+ "libandroid",
+ ],
+}
diff --git a/services/sensorservice/tests/Android.mk b/services/sensorservice/tests/Android.mk
deleted file mode 100644
index 8a9c36b..0000000
--- a/services/sensorservice/tests/Android.mk
+++ /dev/null
@@ -1,16 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
- sensorservicetest.cpp
-
-LOCAL_CFLAGS := -Wall -Werror
-
-LOCAL_SHARED_LIBRARIES := \
- libutils libsensor libandroid
-
-LOCAL_MODULE:= test-sensorservice
-
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_EXECUTABLE)
diff --git a/services/sensorservice/vec.h b/services/sensorservice/vec.h
index 9e5d280..c195434 100644
--- a/services/sensorservice/vec.h
+++ b/services/sensorservice/vec.h
@@ -322,12 +322,12 @@
vec() { }
vec(const vec& rhs) : base(rhs) { }
- vec(const base& rhs) : base(rhs) { } // NOLINT(implicit)
+ vec(const base& rhs) : base(rhs) { } // NOLINT(google-explicit-constructor)
// -----------------------------------------------------------------------
// conversion constructors
- vec(pTYPE rhs) { // NOLINT(implicit)
+ vec(pTYPE rhs) { // NOLINT(google-explicit-constructor)
for (size_t i=0 ; i<SIZE ; i++)
base::operator[](i) = rhs;
}
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index 0c1ea44..734ed6c 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -1,7 +1,6 @@
cc_defaults {
name: "surfaceflinger_defaults",
cflags: [
- "-DLOG_TAG=\"SurfaceFlinger\"",
"-Wall",
"-Werror",
"-Wformat",
@@ -15,6 +14,7 @@
name: "libsurfaceflinger_defaults",
defaults: ["surfaceflinger_defaults"],
cflags: [
+ "-DLOG_TAG=\"SurfaceFlinger\"",
"-DGL_GLEXT_PROTOTYPES",
"-DEGL_EGLEXT_PROTOTYPES",
],
@@ -25,6 +25,7 @@
"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",
"android.hardware.graphics.composer@2.1",
"android.hardware.graphics.composer@2.2",
@@ -49,14 +50,18 @@
"liblog",
"libnativewindow",
"libpdx_default_transport",
+ "libprocessgroup",
"libprotobuf-cpp-lite",
"libsync",
"libtimestats_proto",
"libui",
"libinput",
"libutils",
+ "libutilscallstack",
+ "libSurfaceFlingerProperties",
],
static_libs: [
+ "libcompositionengine",
"librenderengine",
"libserviceutils",
"libtrace_proto",
@@ -69,11 +74,13 @@
"android.hardware.graphics.composer@2.3-command-buffer",
],
export_static_lib_headers: [
+ "libcompositionengine",
"librenderengine",
"libserviceutils",
],
export_shared_lib_headers: [
"android.hardware.graphics.allocator@2.0",
+ "android.hardware.graphics.allocator@3.0",
"android.hardware.graphics.common@1.2",
"android.hardware.graphics.composer@2.1",
"android.hardware.graphics.composer@2.2",
@@ -111,6 +118,7 @@
"BufferLayerConsumer.cpp",
"BufferQueueLayer.cpp",
"BufferStateLayer.cpp",
+ "BufferStateLayerCache.cpp",
"Client.cpp",
"ColorLayer.cpp",
"ContainerLayer.cpp",
@@ -120,7 +128,6 @@
"DisplayHardware/FramebufferSurface.cpp",
"DisplayHardware/HWC2.cpp",
"DisplayHardware/HWComposer.cpp",
- "DisplayHardware/HWComposerBufferCache.cpp",
"DisplayHardware/PowerAdvisor.cpp",
"DisplayHardware/VirtualDisplaySurface.cpp",
"Effects/Daltonizer.cpp",
@@ -144,6 +151,7 @@
"Scheduler/MessageQueue.cpp",
"Scheduler/Scheduler.cpp",
"Scheduler/SchedulerUtils.cpp",
+ "Scheduler/PhaseOffsets.cpp",
"StartPropertySetThread.cpp",
"SurfaceFlinger.cpp",
"SurfaceInterceptor.cpp",
@@ -171,6 +179,9 @@
cc_defaults {
name: "libsurfaceflinger_binary",
defaults: ["surfaceflinger_defaults"],
+ cflags: [
+ "-DLOG_TAG=\"SurfaceFlinger\"",
+ ],
whole_static_libs: [
"libsigchain",
],
@@ -180,6 +191,7 @@
"android.hardware.configstore@1.0",
"android.hardware.configstore@1.2",
"android.hardware.graphics.allocator@2.0",
+ "android.hardware.graphics.allocator@3.0",
"libbinder",
"libcutils",
"libdisplayservicehidl",
@@ -188,6 +200,7 @@
"libinput",
"liblayers_proto",
"liblog",
+ "libprocessgroup",
"libsync",
"libtimestats_proto",
"libutils",
@@ -209,24 +222,10 @@
defaults: ["libsurfaceflinger_binary"],
init_rc: ["surfaceflinger.rc"],
srcs: [":surfaceflinger_binary_sources"],
- shared_libs: ["libsurfaceflinger"],
-}
-
-cc_library_shared {
- name: "libsurfaceflinger_ddmconnection",
- defaults: ["surfaceflinger_defaults"],
- srcs: ["DdmConnection.cpp"],
shared_libs: [
- "libcutils",
- "libdl",
- "liblog",
+ "libsurfaceflinger",
+ "libSurfaceFlingerProperties",
],
- product_variables: {
- // uses jni which may not be available in PDK
- pdk: {
- enabled: false,
- },
- },
}
subdirs = [
@@ -234,3 +233,26 @@
"TimeStats/timestatsproto",
"tests",
]
+
+cc_library_shared {
+ name: "libSurfaceFlingerProperties",
+ srcs: [
+ "SurfaceFlingerProperties.cpp",
+ "sysprop/*.sysprop",
+ ],
+ shared_libs: [
+ "android.hardware.configstore-utils",
+ "android.hardware.configstore@1.0",
+ "android.hardware.configstore@1.1",
+ "android.hardware.configstore@1.2",
+ "libhidlbase",
+ "libhidltransport",
+ "libhwbinder",
+ "libutils",
+ ],
+ export_shared_lib_headers: [
+ "libhidlbase",
+ "libhidltransport",
+ "libhwbinder",
+ ],
+}
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index 0a3be71..65308a6 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -19,6 +19,28 @@
#define LOG_TAG "BufferLayer"
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+#include <cmath>
+#include <cstdlib>
+#include <mutex>
+
+#include <compositionengine/CompositionEngine.h>
+#include <compositionengine/Layer.h>
+#include <compositionengine/LayerCreationArgs.h>
+#include <cutils/compiler.h>
+#include <cutils/native_handle.h>
+#include <cutils/properties.h>
+#include <gui/BufferItem.h>
+#include <gui/BufferQueue.h>
+#include <gui/LayerDebugInfo.h>
+#include <gui/Surface.h>
+#include <renderengine/RenderEngine.h>
+#include <ui/DebugUtils.h>
+#include <utils/Errors.h>
+#include <utils/Log.h>
+#include <utils/NativeHandle.h>
+#include <utils/StopWatch.h>
+#include <utils/Trace.h>
+
#include "BufferLayer.h"
#include "Colorizer.h"
#include "DisplayDevice.h"
@@ -26,33 +48,13 @@
#include "TimeStats/TimeStats.h"
-#include <renderengine/RenderEngine.h>
-
-#include <gui/BufferItem.h>
-#include <gui/BufferQueue.h>
-#include <gui/LayerDebugInfo.h>
-#include <gui/Surface.h>
-
-#include <ui/DebugUtils.h>
-
-#include <utils/Errors.h>
-#include <utils/Log.h>
-#include <utils/NativeHandle.h>
-#include <utils/StopWatch.h>
-#include <utils/Trace.h>
-
-#include <cutils/compiler.h>
-#include <cutils/native_handle.h>
-#include <cutils/properties.h>
-
-#include <math.h>
-#include <stdlib.h>
-#include <mutex>
-
namespace android {
BufferLayer::BufferLayer(const LayerCreationArgs& args)
- : Layer(args), mTextureName(args.flinger->getNewTexture()) {
+ : Layer(args),
+ mTextureName(args.flinger->getNewTexture()),
+ mCompositionLayer{mFlinger->getCompositionEngine().createLayer(
+ compositionengine::LayerCreationArgs{this})} {
ALOGV("Creating Layer %s", args.name.string());
mTexture.init(renderengine::Texture::TEXTURE_EXTERNAL, mTextureName);
@@ -176,7 +178,7 @@
if (!blackOutLayer) {
// TODO: we could be more subtle with isFixedSize()
- const bool useFiltering = needsFiltering(renderArea) || isFixedSize();
+ const bool useFiltering = needsFiltering() || renderArea.needsFiltering() || isFixedSize();
// Query the texture matrix given our current filtering mode.
float textureMatrix[16];
@@ -396,7 +398,6 @@
}
// Capture the old state of the layer for comparisons later
- Mutex::Autolock lock(mStateMutex);
const State& s(getDrawingState());
const bool oldOpacity = isOpaque(s);
sp<GraphicBuffer> oldBuffer = mActiveBuffer;
@@ -503,7 +504,7 @@
// FIXME: postedRegion should be dirty & bounds
// transform the dirty region to window-manager space
- return getTransformLocked().transform(Region(getBufferSize(s)));
+ return getTransform().transform(Region(getBufferSize(s)));
}
// transaction
@@ -551,7 +552,7 @@
// h/w composer set-up
bool BufferLayer::allTransactionsSignaled() {
- auto headFrameNumber = getHeadFrameNumberLocked();
+ auto headFrameNumber = getHeadFrameNumber();
bool matchingFramesFound = false;
bool allTransactionsApplied = true;
Mutex::Autolock lock(mLocalSyncPointMutex);
@@ -598,13 +599,15 @@
return true;
}
-bool BufferLayer::needsFiltering(const RenderArea& renderArea) const {
- return mNeedsFiltering || renderArea.needsFiltering();
+bool BufferLayer::needsFiltering() const {
+ const auto displayFrame = getBE().compositionInfo.hwc.displayFrame;
+ const auto sourceCrop = getBE().compositionInfo.hwc.sourceCrop;
+ return mNeedsFiltering || sourceCrop.getHeight() != displayFrame.getHeight() ||
+ sourceCrop.getWidth() != displayFrame.getWidth();
}
void BufferLayer::drawWithOpenGL(const RenderArea& renderArea, bool useIdentityTransform) const {
ATRACE_CALL();
- Mutex::Autolock lock(mStateMutex);
const State& s(getDrawingState());
computeGeometry(renderArea, getBE().mMesh, useIdentityTransform);
@@ -623,9 +626,8 @@
* minimal value)? Or, we could make GL behave like HWC -- but this feel
* like more of a hack.
*/
- const Rect bounds{computeBoundsLocked()}; // Rounds from FloatRect
+ const Rect bounds{computeBounds()}; // Rounds from FloatRect
- ui::Transform t = getTransformLocked();
Rect win = bounds;
const int bufferWidth = getBufferSize(s).getWidth();
const int bufferHeight = getBufferSize(s).getHeight();
@@ -644,7 +646,7 @@
texCoords[2] = vec2(right, 1.0f - bottom);
texCoords[3] = vec2(right, 1.0f - top);
- const auto roundedCornerState = getRoundedCornerStateLocked();
+ const auto roundedCornerState = getRoundedCornerState();
const auto cropRect = roundedCornerState.cropRect;
setupRoundedCornersCropCoordinates(win, cropRect);
@@ -666,12 +668,7 @@
}
uint64_t BufferLayer::getHeadFrameNumber() const {
- Mutex::Autolock lock(mStateMutex);
- return getHeadFrameNumberLocked();
-}
-
-uint64_t BufferLayer::getHeadFrameNumberLocked() const {
- if (hasFrameUpdateLocked()) {
+ if (hasFrameUpdate()) {
return getFrameNumber();
} else {
return mCurrentFrameNumber;
@@ -698,7 +695,7 @@
std::swap(bufWidth, bufHeight);
}
- if (getTransformToDisplayInverseLocked()) {
+ if (getTransformToDisplayInverse()) {
uint32_t invTransform = DisplayDevice::getPrimaryDisplayOrientationTransform();
if (invTransform & ui::Transform::ROT_90) {
std::swap(bufWidth, bufHeight);
@@ -708,6 +705,10 @@
return Rect(bufWidth, bufHeight);
}
+std::shared_ptr<compositionengine::Layer> BufferLayer::getCompositionLayer() const {
+ return mCompositionLayer;
+}
+
} // namespace android
#if defined(__gl_h_)
diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h
index 98ae286..8158d6c 100644
--- a/services/surfaceflinger/BufferLayer.h
+++ b/services/surfaceflinger/BufferLayer.h
@@ -16,34 +16,31 @@
#pragma once
-#include "BufferLayerConsumer.h"
-#include "Client.h"
-#include "Layer.h"
-#include "DisplayHardware/HWComposer.h"
-#include "DisplayHardware/HWComposerBufferCache.h"
-#include "FrameTracker.h"
-#include "LayerVector.h"
-#include "MonitoredProducer.h"
-#include "SurfaceFlinger.h"
+#include <sys/types.h>
+#include <cstdint>
+#include <list>
#include <gui/ISurfaceComposerClient.h>
#include <gui/LayerState.h>
#include <renderengine/Mesh.h>
#include <renderengine/Texture.h>
+#include <system/window.h> // For NATIVE_WINDOW_SCALING_MODE_FREEZE
#include <ui/FrameStats.h>
#include <ui/GraphicBuffer.h>
#include <ui/PixelFormat.h>
#include <ui/Region.h>
-
#include <utils/RefBase.h>
#include <utils/String8.h>
#include <utils/Timers.h>
-#include <system/window.h> // For NATIVE_WINDOW_SCALING_MODE_FREEZE
-
-#include <stdint.h>
-#include <sys/types.h>
-#include <list>
+#include "BufferLayerConsumer.h"
+#include "Client.h"
+#include "DisplayHardware/HWComposer.h"
+#include "FrameTracker.h"
+#include "Layer.h"
+#include "LayerVector.h"
+#include "MonitoredProducer.h"
+#include "SurfaceFlinger.h"
namespace android {
@@ -56,6 +53,8 @@
// Overriden from Layer
// -----------------------------------------------------------------------
public:
+ std::shared_ptr<compositionengine::Layer> getCompositionLayer() const override;
+
// If we have received a new buffer this frame, we will pass its surface
// damage down to hardware composer. Otherwise, we must send a region with
// one empty rect.
@@ -69,7 +68,7 @@
bool isOpaque(const Layer::State& s) const override;
// isVisible - true if this layer is visible, false otherwise
- bool isVisible() const override EXCLUDES(mStateMutex);
+ bool isVisible() const override;
// isProtected - true if the layer may contain protected content in the
// GRALLOC_USAGE_PROTECTED sense.
@@ -91,7 +90,7 @@
bool onPostComposition(const std::optional<DisplayId>& displayId,
const std::shared_ptr<FenceTime>& glDoneFence,
const std::shared_ptr<FenceTime>& presentFence,
- const CompositorTiming& compositorTiming) override EXCLUDES(mStateMutex);
+ const CompositorTiming& compositorTiming) override;
// latchBuffer - called each time the screen is redrawn and returns whether
// the visible regions need to be recomputed (this is a fairly heavy
@@ -101,13 +100,13 @@
// releaseFence will be populated with a native fence that fires when
// composition has completed.
Region latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime,
- const sp<Fence>& releaseFence) override EXCLUDES(mStateMutex);
+ const sp<Fence>& releaseFence) override;
bool isBufferLatched() const override { return mRefreshPending; }
void notifyAvailableFrames() override;
- bool hasReadyFrame() const override EXCLUDES(mStateMutex);
+ bool hasReadyFrame() const override;
// Returns the current scaling mode, unless mOverrideScalingMode
// is set, in which case, it returns mOverrideScalingMode
@@ -118,24 +117,19 @@
// Functions that must be implemented by derived classes
// -----------------------------------------------------------------------
private:
- virtual bool fenceHasSignaled() const EXCLUDES(mStateMutex) = 0;
+ virtual bool fenceHasSignaled() const = 0;
virtual nsecs_t getDesiredPresentTime() = 0;
- std::shared_ptr<FenceTime> getCurrentFenceTime() const EXCLUDES(mStateMutex) {
- Mutex::Autolock lock(mStateMutex);
- return getCurrentFenceTimeLocked();
- }
-
- virtual std::shared_ptr<FenceTime> getCurrentFenceTimeLocked() const REQUIRES(mStateMutex) = 0;
+ virtual std::shared_ptr<FenceTime> getCurrentFenceTime() const = 0;
virtual void getDrawingTransformMatrix(float *matrix) = 0;
- virtual uint32_t getDrawingTransform() const REQUIRES(mStateMutex) = 0;
- virtual ui::Dataspace getDrawingDataSpace() const REQUIRES(mStateMutex) = 0;
- virtual Rect getDrawingCrop() const REQUIRES(mStateMutex) = 0;
+ virtual uint32_t getDrawingTransform() const = 0;
+ virtual ui::Dataspace getDrawingDataSpace() const = 0;
+ virtual Rect getDrawingCrop() const = 0;
virtual uint32_t getDrawingScalingMode() const = 0;
- virtual Region getDrawingSurfaceDamage() const EXCLUDES(mStateMutex) = 0;
- virtual const HdrMetadata& getDrawingHdrMetadata() const EXCLUDES(mStateMutex) = 0;
- virtual int getDrawingApi() const EXCLUDES(mStateMutex) = 0;
+ virtual Region getDrawingSurfaceDamage() const = 0;
+ virtual const HdrMetadata& getDrawingHdrMetadata() const = 0;
+ virtual int getDrawingApi() const = 0;
virtual PixelFormat getPixelFormat() const = 0;
virtual uint64_t getFrameNumber() const = 0;
@@ -143,21 +137,20 @@
virtual bool getAutoRefresh() const = 0;
virtual bool getSidebandStreamChanged() const = 0;
- virtual std::optional<Region> latchSidebandStream(bool& recomputeVisibleRegions)
- EXCLUDES(mStateMutex) = 0;
+ virtual std::optional<Region> latchSidebandStream(bool& recomputeVisibleRegions) = 0;
- virtual bool hasFrameUpdateLocked() const REQUIRES(mStateMutex) = 0;
+ virtual bool hasFrameUpdate() const = 0;
virtual void setFilteringEnabled(bool enabled) = 0;
- virtual status_t bindTextureImage() EXCLUDES(mStateMutex) = 0;
+ virtual status_t bindTextureImage() = 0;
virtual status_t updateTexImage(bool& recomputeVisibleRegions, nsecs_t latchTime,
- const sp<Fence>& flushFence) REQUIRES(mStateMutex) = 0;
+ const sp<Fence>& flushFence) = 0;
- virtual status_t updateActiveBuffer() REQUIRES(mStateMutex) = 0;
+ virtual status_t updateActiveBuffer() = 0;
virtual status_t updateFrameNumber(nsecs_t latchTime) = 0;
- virtual void setHwcLayerBuffer(DisplayId displayId) EXCLUDES(mStateMutex) = 0;
+ virtual void setHwcLayerBuffer(DisplayId displayId) = 0;
protected:
// Loads the corresponding system property once per process
@@ -166,29 +159,23 @@
// Check all of the local sync points to ensure that all transactions
// which need to have been applied prior to the frame which is about to
// be latched have signaled
- bool allTransactionsSignaled() REQUIRES(mStateMutex);
+ bool allTransactionsSignaled();
static bool getOpacityForFormat(uint32_t format);
- bool hasFrameUpdate() const EXCLUDES(mStateMutex) {
- Mutex::Autolock lock(mStateMutex);
- return hasFrameUpdateLocked();
- }
-
// from GLES
const uint32_t mTextureName;
+ bool mRefreshPending{false};
+
private:
- // needsLinearFiltering - true if this surface's state requires filtering
- bool needsFiltering(const RenderArea& renderArea) const;
+ // Returns true if this layer requires filtering
+ bool needsFiltering() const;
// drawing
- void drawWithOpenGL(const RenderArea& renderArea, bool useIdentityTransform) const
- EXCLUDES(mStateMutex);
+ void drawWithOpenGL(const RenderArea& renderArea, bool useIdentityTransform) const;
- uint64_t getHeadFrameNumber() const EXCLUDES(mStateMutex);
-
- uint64_t getHeadFrameNumberLocked() const REQUIRES(mStateMutex);
+ uint64_t getHeadFrameNumber() const;
uint32_t mCurrentScalingMode{NATIVE_WINDOW_SCALING_MODE_FREEZE};
@@ -198,9 +185,9 @@
// The texture used to draw the layer in GLES composition mode
mutable renderengine::Texture mTexture;
- bool mRefreshPending{false};
+ Rect getBufferSize(const State& s) const override;
- Rect getBufferSize(const State& s) const override REQUIRES(mStateMutex);
+ std::shared_ptr<compositionengine::Layer> mCompositionLayer;
};
} // namespace android
diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp
index 3341b98..42021d1 100644
--- a/services/surfaceflinger/BufferQueueLayer.cpp
+++ b/services/surfaceflinger/BufferQueueLayer.cpp
@@ -51,7 +51,7 @@
return history;
}
-bool BufferQueueLayer::getTransformToDisplayInverseLocked() const {
+bool BufferQueueLayer::getTransformToDisplayInverse() const {
return mConsumer->getTransformToDisplayInverse();
}
@@ -131,7 +131,7 @@
return mConsumer->getTimestamp();
}
-std::shared_ptr<FenceTime> BufferQueueLayer::getCurrentFenceTimeLocked() const {
+std::shared_ptr<FenceTime> BufferQueueLayer::getCurrentFenceTime() const {
return mConsumer->getCurrentFenceTime();
}
@@ -192,7 +192,6 @@
std::optional<Region> BufferQueueLayer::latchSidebandStream(bool& recomputeVisibleRegions) {
bool sidebandStreamChanged = true;
- Mutex::Autolock lock(mStateMutex);
if (mSidebandStreamChanged.compare_exchange_strong(sidebandStreamChanged, false)) {
// mSidebandStreamChanged was changed to false
// replicated in LayerBE until FE/BE is ready to be synchronized
@@ -201,15 +200,15 @@
setTransactionFlags(eTransactionNeeded);
mFlinger->setTransactionFlags(eTraversalNeeded);
}
-
recomputeVisibleRegions = true;
+
const State& s(getDrawingState());
- return getTransformLocked().transform(Region(Rect(s.active_legacy.w, s.active_legacy.h)));
+ return getTransform().transform(Region(Rect(s.active_legacy.w, s.active_legacy.h)));
}
return {};
}
-bool BufferQueueLayer::hasFrameUpdateLocked() const {
+bool BufferQueueLayer::hasFrameUpdate() const {
return mQueuedFrames > 0;
}
@@ -229,18 +228,16 @@
// buffer mode.
bool queuedBuffer = false;
const int32_t layerID = getSequence();
- status_t updateResult;
- LayerRejecter r(mState.drawing, getCurrentState(), recomputeVisibleRegions,
+ LayerRejecter r(mDrawingState, getCurrentState(), recomputeVisibleRegions,
getProducerStickyTransform() != 0, mName.string(), mOverrideScalingMode,
- getTransformToDisplayInverseLocked(), mFreezeGeometryUpdates);
+ getTransformToDisplayInverse(), mFreezeGeometryUpdates);
const nsecs_t expectedPresentTime = mFlinger->mUseScheduler
? mFlinger->mScheduler->mPrimaryDispSync->expectedPresentTime()
: mFlinger->mPrimaryDispSync->expectedPresentTime();
-
- updateResult = mConsumer->updateTexImage(&r, expectedPresentTime, &mAutoRefresh, &queuedBuffer,
- mLastFrameNumberReceived, releaseFence);
-
+ status_t updateResult =
+ mConsumer->updateTexImage(&r, expectedPresentTime, &mAutoRefresh, &queuedBuffer,
+ mLastFrameNumberReceived, releaseFence);
if (updateResult == BufferQueue::PRESENT_LATER) {
// Producer doesn't want buffer to be displayed yet. Signal a
// layer update so we check again at the next opportunity.
@@ -355,6 +352,14 @@
// Interface implementation for BufferLayerConsumer::ContentsChangedListener
// -----------------------------------------------------------------------
+void BufferQueueLayer::fakeVsync() {
+ mRefreshPending = false;
+ bool ignored = false;
+ latchBuffer(ignored, systemTime(), Fence::NO_FENCE);
+ usleep(16000);
+ releasePendingBuffer(systemTime());
+}
+
void BufferQueueLayer::onFrameAvailable(const BufferItem& item) {
// Add this buffer from our internal queue tracker
{ // Autolock scope
@@ -393,10 +398,7 @@
// If this layer is orphaned, then we run a fake vsync pulse so that
// dequeueBuffer doesn't block indefinitely.
if (isRemovedFromCurrentState()) {
- bool ignored = false;
- latchBuffer(ignored, systemTime(), Fence::NO_FENCE);
- usleep(16000);
- releasePendingBuffer(systemTime());
+ fakeVsync();
} else {
mFlinger->signalLayerUpdate();
}
diff --git a/services/surfaceflinger/BufferQueueLayer.h b/services/surfaceflinger/BufferQueueLayer.h
index f9da044..d7c3f6a 100644
--- a/services/surfaceflinger/BufferQueueLayer.h
+++ b/services/surfaceflinger/BufferQueueLayer.h
@@ -44,7 +44,7 @@
std::vector<OccupancyTracker::Segment> getOccupancyHistory(bool forceFlush) override;
- bool getTransformToDisplayInverseLocked() const override REQUIRES(mStateMutex);
+ bool getTransformToDisplayInverse() const override;
// If a buffer was replaced this frame, release the former buffer
void releasePendingBuffer(nsecs_t dequeueReadyTime) override;
@@ -64,12 +64,12 @@
private:
nsecs_t getDesiredPresentTime() override;
- std::shared_ptr<FenceTime> getCurrentFenceTimeLocked() const override REQUIRES(mStateMutex);
+ std::shared_ptr<FenceTime> getCurrentFenceTime() const override;
void getDrawingTransformMatrix(float *matrix) override;
- uint32_t getDrawingTransform() const override REQUIRES(mStateMutex);
- ui::Dataspace getDrawingDataSpace() const override REQUIRES(mStateMutex);
- Rect getDrawingCrop() const override REQUIRES(mStateMutex);
+ uint32_t getDrawingTransform() const override;
+ ui::Dataspace getDrawingDataSpace() const override;
+ Rect getDrawingCrop() const override;
uint32_t getDrawingScalingMode() const override;
Region getDrawingSurfaceDamage() const override;
const HdrMetadata& getDrawingHdrMetadata() const override;
@@ -81,18 +81,17 @@
bool getAutoRefresh() const override;
bool getSidebandStreamChanged() const override;
- std::optional<Region> latchSidebandStream(bool& recomputeVisibleRegions) override
- EXCLUDES(mStateMutex);
+ std::optional<Region> latchSidebandStream(bool& recomputeVisibleRegions) override;
- bool hasFrameUpdateLocked() const override REQUIRES(mStateMutex);
+ bool hasFrameUpdate() const override;
void setFilteringEnabled(bool enabled) override;
status_t bindTextureImage() override;
status_t updateTexImage(bool& recomputeVisibleRegions, nsecs_t latchTime,
- const sp<Fence>& releaseFence) override REQUIRES(mStateMutex);
+ const sp<Fence>& releaseFence) override;
- status_t updateActiveBuffer() override REQUIRES(mStateMutex);
+ status_t updateActiveBuffer() override;
status_t updateFrameNumber(nsecs_t latchTime) override;
void setHwcLayerBuffer(DisplayId displayId) override;
@@ -138,6 +137,8 @@
// thread-safe
std::atomic<int32_t> mQueuedFrames{0};
std::atomic<bool> mSidebandStreamChanged{false};
+
+ void fakeVsync();
};
} // namespace android
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index 0e46928..044662c 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -20,6 +20,7 @@
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
#include "BufferStateLayer.h"
+#include "ColorLayer.h"
#include "TimeStats/TimeStats.h"
@@ -48,10 +49,28 @@
// Interface implementation for Layer
// -----------------------------------------------------------------------
void BufferStateLayer::onLayerDisplayed(const sp<Fence>& releaseFence) {
- // The transaction completed callback can only be sent if the release fence from the PREVIOUS
- // frame has fired. In practice, we should never actually wait on the previous release fence
- // but we should store it just in case.
- mPreviousReleaseFence = releaseFence;
+ // The previous release fence notifies the client that SurfaceFlinger is done with the previous
+ // buffer that was presented on this layer. The first transaction that came in this frame that
+ // replaced the previous buffer on this layer needs this release fence, because the fence will
+ // let the client know when that previous buffer is removed from the screen.
+ //
+ // Every other transaction on this layer does not need a release fence because no other
+ // Transactions that were set on this layer this frame are going to have their preceeding buffer
+ // removed from the display this frame.
+ //
+ // For example, if we have 3 transactions this frame. The first transaction doesn't contain a
+ // buffer so it doesn't need a previous release fence because the layer still needs the previous
+ // buffer. The second transaction contains a buffer so it needs a previous release fence because
+ // the previous buffer will be released this frame. The third transaction also contains a
+ // buffer. It replaces the buffer in the second transaction. The buffer in the second
+ // transaction will now no longer be presented so it is released immediately and the third
+ // transaction doesn't need a previous release fence.
+ for (auto& handle : mDrawingState.callbackHandles) {
+ if (handle->releasePreviousBuffer) {
+ handle->previousReleaseFence = releaseFence;
+ break;
+ }
+ }
}
void BufferStateLayer::setTransformHint(uint32_t /*orientation*/) const {
@@ -60,7 +79,10 @@
}
void BufferStateLayer::releasePendingBuffer(nsecs_t /*dequeueReadyTime*/) {
- return;
+ mFlinger->getTransactionCompletedThread().addPresentedCallbackHandles(
+ mDrawingState.callbackHandles);
+
+ mDrawingState.callbackHandles = {};
}
bool BufferStateLayer::shouldPresentNow(nsecs_t /*expectedPresentTime*/) const {
@@ -72,31 +94,30 @@
}
bool BufferStateLayer::willPresentCurrentTransaction() const {
- Mutex::Autolock lock(mStateMutex);
// Returns true if the most recent Transaction applied to CurrentState will be presented.
return getSidebandStreamChanged() || getAutoRefresh() ||
- (mState.current.modified && mState.current.buffer != nullptr);
+ (mCurrentState.modified && mCurrentState.buffer != nullptr);
}
-bool BufferStateLayer::getTransformToDisplayInverseLocked() const {
- return mState.current.transformToDisplayInverse;
+bool BufferStateLayer::getTransformToDisplayInverse() const {
+ return mCurrentState.transformToDisplayInverse;
}
-void BufferStateLayer::pushPendingStateLocked() {
- if (!mState.current.modified) {
+void BufferStateLayer::pushPendingState() {
+ if (!mCurrentState.modified) {
return;
}
- mState.pending.push_back(mState.current);
- ATRACE_INT(mTransactionName.string(), mState.pending.size());
+ mPendingStates.push_back(mCurrentState);
+ ATRACE_INT(mTransactionName.string(), mPendingStates.size());
}
bool BufferStateLayer::applyPendingStates(Layer::State* stateToCommit) {
- const bool stateUpdateAvailable = !mState.pending.empty();
- while (!mState.pending.empty()) {
+ const bool stateUpdateAvailable = !mPendingStates.empty();
+ while (!mPendingStates.empty()) {
popPendingState(stateToCommit);
}
- mCurrentStateModified = stateUpdateAvailable && mState.current.modified;
- mState.current.modified = false;
+ mCurrentStateModified = stateUpdateAvailable && mCurrentState.modified;
+ mCurrentState.modified = false;
return stateUpdateAvailable;
}
@@ -106,31 +127,28 @@
}
bool BufferStateLayer::setTransform(uint32_t transform) {
- Mutex::Autolock lock(mStateMutex);
- if (mState.current.transform == transform) return false;
- mState.current.sequence++;
- mState.current.transform = transform;
- mState.current.modified = true;
+ if (mCurrentState.transform == transform) return false;
+ mCurrentState.sequence++;
+ mCurrentState.transform = transform;
+ mCurrentState.modified = true;
setTransactionFlags(eTransactionNeeded);
return true;
}
bool BufferStateLayer::setTransformToDisplayInverse(bool transformToDisplayInverse) {
- Mutex::Autolock lock(mStateMutex);
- if (mState.current.transformToDisplayInverse == transformToDisplayInverse) return false;
- mState.current.sequence++;
- mState.current.transformToDisplayInverse = transformToDisplayInverse;
- mState.current.modified = true;
+ if (mCurrentState.transformToDisplayInverse == transformToDisplayInverse) return false;
+ mCurrentState.sequence++;
+ mCurrentState.transformToDisplayInverse = transformToDisplayInverse;
+ mCurrentState.modified = true;
setTransactionFlags(eTransactionNeeded);
return true;
}
bool BufferStateLayer::setCrop(const Rect& crop) {
- Mutex::Autolock lock(mStateMutex);
- if (mState.current.crop == crop) return false;
- mState.current.sequence++;
- mState.current.crop = crop;
- mState.current.modified = true;
+ if (mCurrentState.crop == crop) return false;
+ mCurrentState.sequence++;
+ mCurrentState.crop = crop;
+ mCurrentState.modified = true;
setTransactionFlags(eTransactionNeeded);
return true;
}
@@ -141,94 +159,96 @@
int w = frame.getWidth();
int h = frame.getHeight();
- Mutex::Autolock lock(mStateMutex);
- if (mState.current.active.transform.tx() == x && mState.current.active.transform.ty() == y &&
- mState.current.active.w == w && mState.current.active.h == h) {
+ if (x < 0) {
+ x = 0;
+ w = frame.right;
+ }
+
+ if (y < 0) {
+ y = 0;
+ h = frame.bottom;
+ }
+
+ if (mCurrentState.active.transform.tx() == x && mCurrentState.active.transform.ty() == y &&
+ mCurrentState.active.w == w && mCurrentState.active.h == h) {
return false;
}
if (!frame.isValid()) {
x = y = w = h = 0;
}
- mState.current.active.transform.set(x, y);
- mState.current.active.w = w;
- mState.current.active.h = h;
+ mCurrentState.active.transform.set(x, y);
+ mCurrentState.active.w = w;
+ mCurrentState.active.h = h;
- mState.current.sequence++;
- mState.current.modified = true;
+ mCurrentState.sequence++;
+ mCurrentState.modified = true;
setTransactionFlags(eTransactionNeeded);
return true;
}
bool BufferStateLayer::setBuffer(const sp<GraphicBuffer>& buffer) {
- Mutex::Autolock lock(mStateMutex);
- if (mState.current.buffer) {
+ if (mCurrentState.buffer) {
mReleasePreviousBuffer = true;
}
- mState.current.sequence++;
- mState.current.buffer = buffer;
- mState.current.modified = true;
+ mCurrentState.sequence++;
+ mCurrentState.buffer = buffer;
+ mCurrentState.modified = true;
setTransactionFlags(eTransactionNeeded);
return true;
}
bool BufferStateLayer::setAcquireFence(const sp<Fence>& fence) {
- Mutex::Autolock lock(mStateMutex);
// The acquire fences of BufferStateLayers have already signaled before they are set
mCallbackHandleAcquireTime = fence->getSignalTime();
- mState.current.acquireFence = fence;
- mState.current.modified = true;
+ mCurrentState.acquireFence = fence;
+ mCurrentState.modified = true;
setTransactionFlags(eTransactionNeeded);
return true;
}
bool BufferStateLayer::setDataspace(ui::Dataspace dataspace) {
- Mutex::Autolock lock(mStateMutex);
- if (mState.current.dataspace == dataspace) return false;
- mState.current.sequence++;
- mState.current.dataspace = dataspace;
- mState.current.modified = true;
+ if (mCurrentState.dataspace == dataspace) return false;
+ mCurrentState.sequence++;
+ mCurrentState.dataspace = dataspace;
+ mCurrentState.modified = true;
setTransactionFlags(eTransactionNeeded);
return true;
}
bool BufferStateLayer::setHdrMetadata(const HdrMetadata& hdrMetadata) {
- Mutex::Autolock lock(mStateMutex);
- if (mState.current.hdrMetadata == hdrMetadata) return false;
- mState.current.sequence++;
- mState.current.hdrMetadata = hdrMetadata;
- mState.current.modified = true;
+ if (mCurrentState.hdrMetadata == hdrMetadata) return false;
+ mCurrentState.sequence++;
+ mCurrentState.hdrMetadata = hdrMetadata;
+ mCurrentState.modified = true;
setTransactionFlags(eTransactionNeeded);
return true;
}
bool BufferStateLayer::setSurfaceDamageRegion(const Region& surfaceDamage) {
- Mutex::Autolock lock(mStateMutex);
- mState.current.sequence++;
- mState.current.surfaceDamageRegion = surfaceDamage;
- mState.current.modified = true;
+ mCurrentState.sequence++;
+ mCurrentState.surfaceDamageRegion = surfaceDamage;
+ mCurrentState.modified = true;
setTransactionFlags(eTransactionNeeded);
return true;
}
bool BufferStateLayer::setApi(int32_t api) {
- Mutex::Autolock lock(mStateMutex);
- if (mState.current.api == api) return false;
- mState.current.sequence++;
- mState.current.api = api;
- mState.current.modified = true;
+ if (mCurrentState.api == api) return false;
+ mCurrentState.sequence++;
+ mCurrentState.api = api;
+ mCurrentState.modified = true;
setTransactionFlags(eTransactionNeeded);
return true;
}
bool BufferStateLayer::setSidebandStream(const sp<NativeHandle>& sidebandStream) {
- Mutex::Autolock lock(mStateMutex);
- if (mState.current.sidebandStream == sidebandStream) return false;
- mState.current.sequence++;
- mState.current.sidebandStream = sidebandStream;
- mState.current.modified = true;
+ if (mCurrentState.sidebandStream == sidebandStream) return false;
+ mCurrentState.sequence++;
+ mCurrentState.sidebandStream = sidebandStream;
+ mCurrentState.modified = true;
setTransactionFlags(eTransactionNeeded);
if (!mSidebandStreamChanged.exchange(true)) {
@@ -259,17 +279,14 @@
// Notify the transaction completed thread that there is a pending latched callback
// handle
- mFlinger->getTransactionCompletedThread().registerPendingLatchedCallbackHandle(handle);
+ mFlinger->getTransactionCompletedThread().registerPendingCallbackHandle(handle);
// Store so latched time and release fence can be set
- {
- Mutex::Autolock lock(mStateMutex);
- mState.current.callbackHandles.push_back(handle);
- }
+ mCurrentState.callbackHandles.push_back(handle);
} else { // If this layer will NOT need to be relatched and presented this frame
// Notify the transaction completed thread this handle is done
- mFlinger->getTransactionCompletedThread().addUnlatchedCallbackHandle(handle);
+ mFlinger->getTransactionCompletedThread().addUnpresentedCallbackHandle(handle);
}
}
@@ -280,9 +297,8 @@
}
bool BufferStateLayer::setTransparentRegionHint(const Region& transparent) {
- Mutex::Autolock lock(mStateMutex);
- mState.current.transparentRegionHint = transparent;
- mState.current.modified = true;
+ mCurrentState.transparentRegionHint = transparent;
+ mCurrentState.modified = true;
setTransactionFlags(eTransactionNeeded);
return true;
}
@@ -318,7 +334,6 @@
return true;
}
- Mutex::Autolock lock(mStateMutex);
return getDrawingState().acquireFence->getStatus() == Fence::Status::Signaled;
}
@@ -327,7 +342,7 @@
return 0;
}
-std::shared_ptr<FenceTime> BufferStateLayer::getCurrentFenceTimeLocked() const {
+std::shared_ptr<FenceTime> BufferStateLayer::getCurrentFenceTime() const {
return std::make_shared<FenceTime>(getDrawingState().acquireFence);
}
@@ -374,17 +389,14 @@
}
Region BufferStateLayer::getDrawingSurfaceDamage() const {
- Mutex::Autolock lock(mStateMutex);
return getDrawingState().surfaceDamageRegion;
}
const HdrMetadata& BufferStateLayer::getDrawingHdrMetadata() const {
- Mutex::Autolock lock(mStateMutex);
return getDrawingState().hdrMetadata;
}
int BufferStateLayer::getDrawingApi() const {
- Mutex::Autolock lock(mStateMutex);
return getDrawingState().api;
}
@@ -409,7 +421,6 @@
}
std::optional<Region> BufferStateLayer::latchSidebandStream(bool& recomputeVisibleRegions) {
- Mutex::Autolock lock(mStateMutex);
if (mSidebandStreamChanged.exchange(false)) {
const State& s(getDrawingState());
// mSidebandStreamChanged was true
@@ -421,12 +432,12 @@
}
recomputeVisibleRegions = true;
- return getTransformLocked().transform(Region(Rect(s.active.w, s.active.h)));
+ return getTransform().transform(Region(Rect(s.active.w, s.active.h)));
}
return {};
}
-bool BufferStateLayer::hasFrameUpdateLocked() const {
+bool BufferStateLayer::hasFrameUpdate() const {
return mCurrentStateModified && getCurrentState().buffer != nullptr;
}
@@ -436,10 +447,6 @@
}
status_t BufferStateLayer::bindTextureImage() {
- Mutex::Autolock lock(mStateMutex);
- return bindTextureImageLocked();
-}
-status_t BufferStateLayer::bindTextureImageLocked() {
const State& s(getDrawingState());
auto& engine(mFlinger->getRenderEngine());
@@ -519,9 +526,9 @@
return BAD_VALUE;
}
- mFlinger->getTransactionCompletedThread()
- .addLatchedCallbackHandles(getDrawingState().callbackHandles, latchTime,
- mPreviousReleaseFence);
+ for (auto& handle : mDrawingState.callbackHandles) {
+ handle->latchTime = latchTime;
+ }
// Handle sync fences
if (SyncFeatures::getInstance().useNativeFenceSync() && releaseFence != Fence::NO_FENCE) {
@@ -544,7 +551,7 @@
auto incomingStatus = releaseFence->getStatus();
if (incomingStatus == Fence::Status::Invalid) {
ALOGE("New fence has invalid state");
- mState.drawing.acquireFence = releaseFence;
+ mDrawingState.acquireFence = releaseFence;
mFlinger->mTimeStats->onDestroy(layerID);
return BAD_VALUE;
}
@@ -555,16 +562,16 @@
char fenceName[32] = {};
snprintf(fenceName, 32, "%.28s:%d", mName.string(), mFrameNumber);
sp<Fence> mergedFence =
- Fence::merge(fenceName, mState.drawing.acquireFence, releaseFence);
+ Fence::merge(fenceName, mDrawingState.acquireFence, releaseFence);
if (!mergedFence.get()) {
ALOGE("failed to merge release fences");
// synchronization is broken, the best we can do is hope fences
// signal in order so the new fence will act like a union
- mState.drawing.acquireFence = releaseFence;
+ mDrawingState.acquireFence = releaseFence;
mFlinger->mTimeStats->onDestroy(layerID);
return BAD_VALUE;
}
- mState.drawing.acquireFence = mergedFence;
+ mDrawingState.acquireFence = mergedFence;
} else if (incomingStatus == Fence::Status::Unsignaled) {
// If one fence has signaled and the other hasn't, the unsignaled
// fence will approximately correspond with the correct timestamp.
@@ -573,7 +580,7 @@
// by this point, they will have both signaled and only the timestamp
// will be slightly off; any dependencies after this point will
// already have been met.
- mState.drawing.acquireFence = releaseFence;
+ mDrawingState.acquireFence = releaseFence;
}
} else {
// Bind the new buffer to the GL texture.
@@ -582,7 +589,7 @@
// by glEGLImageTargetTexture2DOES, which this method calls. Newer
// devices will either call this in Layer::onDraw, or (if it's not
// a GL-composited layer) not at all.
- status_t err = bindTextureImageLocked();
+ status_t err = bindTextureImage();
if (err != NO_ERROR) {
mFlinger->mTimeStats->onDestroy(layerID);
return BAD_VALUE;
@@ -591,7 +598,7 @@
// TODO(marissaw): properly support mTimeStats
mFlinger->mTimeStats->setPostTime(layerID, getFrameNumber(), getName().c_str(), latchTime);
- mFlinger->mTimeStats->setAcquireFence(layerID, getFrameNumber(), getCurrentFenceTimeLocked());
+ mFlinger->mTimeStats->setAcquireFence(layerID, getFrameNumber(), getCurrentFenceTime());
mFlinger->mTimeStats->setLatchTime(layerID, getFrameNumber(), latchTime);
return NO_ERROR;
@@ -618,7 +625,6 @@
}
void BufferStateLayer::setHwcLayerBuffer(DisplayId displayId) {
- Mutex::Autolock lock(mStateMutex);
auto& hwcInfo = getBE().mHwcLayers[displayId];
auto& hwcLayer = hwcInfo.layer;
diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h
index 655353c..3f891d3 100644
--- a/services/surfaceflinger/BufferStateLayer.h
+++ b/services/surfaceflinger/BufferStateLayer.h
@@ -41,14 +41,13 @@
bool shouldPresentNow(nsecs_t expectedPresentTime) const override;
- bool getTransformToDisplayInverseLocked() const override REQUIRES(mStateMutex);
+ bool getTransformToDisplayInverse() const override;
uint32_t doTransactionResize(uint32_t flags, Layer::State* /*stateToCommit*/) override {
return flags;
}
-
- void pushPendingStateLocked() override REQUIRES(mStateMutex);
- bool applyPendingStates(Layer::State* stateToCommit) override REQUIRES(mStateMutex);
+ void pushPendingState() override;
+ bool applyPendingStates(Layer::State* stateToCommit) override;
uint32_t getActiveWidth(const Layer::State& s) const override { return s.active.w; }
uint32_t getActiveHeight(const Layer::State& s) const override { return s.active.h; }
@@ -60,20 +59,18 @@
}
Rect getCrop(const Layer::State& s) const;
- bool setTransform(uint32_t transform) override EXCLUDES(mStateMutex);
- bool setTransformToDisplayInverse(bool transformToDisplayInverse) override
- EXCLUDES(mStateMutex);
- bool setCrop(const Rect& crop) override EXCLUDES(mStateMutex);
- bool setFrame(const Rect& frame) override EXCLUDES(mStateMutex);
- bool setBuffer(const sp<GraphicBuffer>& buffer) override EXCLUDES(mStateMutex);
- bool setAcquireFence(const sp<Fence>& fence) override EXCLUDES(mStateMutex);
- bool setDataspace(ui::Dataspace dataspace) override EXCLUDES(mStateMutex);
- bool setHdrMetadata(const HdrMetadata& hdrMetadata) override EXCLUDES(mStateMutex);
- bool setSurfaceDamageRegion(const Region& surfaceDamage) override EXCLUDES(mStateMutex);
- bool setApi(int32_t api) override EXCLUDES(mStateMutex);
- bool setSidebandStream(const sp<NativeHandle>& sidebandStream) override EXCLUDES(mStateMutex);
- bool setTransactionCompletedListeners(const std::vector<sp<CallbackHandle>>& handles) override
- EXCLUDES(mStateMutex);
+ bool setTransform(uint32_t transform) override;
+ bool setTransformToDisplayInverse(bool transformToDisplayInverse) override;
+ bool setCrop(const Rect& crop) override;
+ bool setFrame(const Rect& frame) override;
+ bool setBuffer(const sp<GraphicBuffer>& buffer) override;
+ bool setAcquireFence(const sp<Fence>& fence) override;
+ bool setDataspace(ui::Dataspace dataspace) override;
+ bool setHdrMetadata(const HdrMetadata& hdrMetadata) override;
+ bool setSurfaceDamageRegion(const Region& surfaceDamage) override;
+ bool setApi(int32_t api) override;
+ bool setSidebandStream(const sp<NativeHandle>& sidebandStream) override;
+ bool setTransactionCompletedListeners(const std::vector<sp<CallbackHandle>>& handles) override;
// Override to ignore legacy layer state properties that are not used by BufferStateLayer
bool setSize(uint32_t /*w*/, uint32_t /*h*/) override { return false; }
@@ -90,26 +87,26 @@
void deferTransactionUntil_legacy(const sp<Layer>& /*barrierLayer*/,
uint64_t /*frameNumber*/) override {}
- Rect getBufferSize(const State& s) const override REQUIRES(mStateMutex);
+ Rect getBufferSize(const State& s) const override;
// -----------------------------------------------------------------------
// -----------------------------------------------------------------------
// Interface implementation for BufferLayer
// -----------------------------------------------------------------------
- bool fenceHasSignaled() const override EXCLUDES(mStateMutex);
+ bool fenceHasSignaled() const override;
private:
nsecs_t getDesiredPresentTime() override;
- std::shared_ptr<FenceTime> getCurrentFenceTimeLocked() const override REQUIRES(mStateMutex);
+ std::shared_ptr<FenceTime> getCurrentFenceTime() const override;
void getDrawingTransformMatrix(float *matrix) override;
- uint32_t getDrawingTransform() const override REQUIRES(mStateMutex);
- ui::Dataspace getDrawingDataSpace() const override REQUIRES(mStateMutex);
- Rect getDrawingCrop() const override REQUIRES(mStateMutex);
+ uint32_t getDrawingTransform() const override;
+ ui::Dataspace getDrawingDataSpace() const override;
+ Rect getDrawingCrop() const override;
uint32_t getDrawingScalingMode() const override;
- Region getDrawingSurfaceDamage() const override EXCLUDES(mStateMutex);
- const HdrMetadata& getDrawingHdrMetadata() const override EXCLUDES(mStateMutex);
- int getDrawingApi() const override EXCLUDES(mStateMutex);
+ Region getDrawingSurfaceDamage() const override;
+ const HdrMetadata& getDrawingHdrMetadata() const override;
+ int getDrawingApi() const override;
PixelFormat getPixelFormat() const override;
uint64_t getFrameNumber() const override;
@@ -117,26 +114,24 @@
bool getAutoRefresh() const override;
bool getSidebandStreamChanged() const override;
- std::optional<Region> latchSidebandStream(bool& recomputeVisibleRegions) override
- EXCLUDES(mStateMutex);
+ std::optional<Region> latchSidebandStream(bool& recomputeVisibleRegions) override;
- bool hasFrameUpdateLocked() const override REQUIRES(mStateMutex);
+ bool hasFrameUpdate() const override;
void setFilteringEnabled(bool enabled) override;
- status_t bindTextureImage() override EXCLUDES(mStateMutex);
+ status_t bindTextureImage() override;
status_t updateTexImage(bool& recomputeVisibleRegions, nsecs_t latchTime,
- const sp<Fence>& releaseFence) override REQUIRES(mStateMutex);
+ const sp<Fence>& releaseFence) override;
- status_t updateActiveBuffer() override REQUIRES(mStateMutex);
+ status_t updateActiveBuffer() override;
status_t updateFrameNumber(nsecs_t latchTime) override;
- void setHwcLayerBuffer(DisplayId displayId) override EXCLUDES(mStateMutex);
+ void setHwcLayerBuffer(DisplayId displayId) override;
private:
void onFirstRef() override;
bool willPresentCurrentTransaction() const;
- status_t bindTextureImageLocked() REQUIRES(mStateMutex);
static const std::array<float, 16> IDENTITY_MATRIX;
diff --git a/services/surfaceflinger/BufferStateLayerCache.cpp b/services/surfaceflinger/BufferStateLayerCache.cpp
new file mode 100644
index 0000000..cb02d16
--- /dev/null
+++ b/services/surfaceflinger/BufferStateLayerCache.cpp
@@ -0,0 +1,102 @@
+/*
+ * 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
+#undef LOG_TAG
+#define LOG_TAG "BufferStateLayerCache"
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
+#include <cinttypes>
+
+#include "BufferStateLayerCache.h"
+
+#define VALID_CACHE_ID(id) ((id) >= 0 || (id) < (BUFFER_CACHE_MAX_SIZE))
+
+namespace android {
+
+ANDROID_SINGLETON_STATIC_INSTANCE(BufferStateLayerCache);
+
+BufferStateLayerCache::BufferStateLayerCache() : mDeathRecipient(new CacheDeathRecipient) {}
+
+void BufferStateLayerCache::add(sp<IBinder> processToken, int32_t id,
+ const sp<GraphicBuffer>& buffer) {
+ if (!VALID_CACHE_ID(id)) {
+ ALOGE("failed to cache buffer: invalid buffer id");
+ return;
+ }
+
+ if (!processToken) {
+ ALOGE("failed to cache buffer: invalid process token");
+ return;
+ }
+
+ if (!buffer) {
+ ALOGE("failed to cache buffer: invalid buffer");
+ return;
+ }
+
+ std::lock_guard lock(mMutex);
+
+ // If this is a new process token, set a death recipient. If the client process dies, we will
+ // get a callback through binderDied.
+ if (mBuffers.find(processToken) == mBuffers.end()) {
+ status_t err = processToken->linkToDeath(mDeathRecipient);
+ if (err != NO_ERROR) {
+ ALOGE("failed to cache buffer: could not link to death");
+ return;
+ }
+ }
+
+ auto& processBuffers = mBuffers[processToken];
+ processBuffers[id] = buffer;
+}
+
+sp<GraphicBuffer> BufferStateLayerCache::get(sp<IBinder> processToken, int32_t id) {
+ if (!VALID_CACHE_ID(id)) {
+ ALOGE("failed to get buffer: invalid buffer id");
+ return nullptr;
+ }
+
+ if (!processToken) {
+ ALOGE("failed to cache buffer: invalid process token");
+ return nullptr;
+ }
+
+ std::lock_guard lock(mMutex);
+ auto itr = mBuffers.find(processToken);
+ if (itr == mBuffers.end()) {
+ ALOGE("failed to get buffer: process token not found");
+ return nullptr;
+ }
+
+ if (id >= itr->second.size()) {
+ ALOGE("failed to get buffer: id outside the bounds of the cache");
+ return nullptr;
+ }
+
+ return itr->second[id];
+}
+
+void BufferStateLayerCache::removeProcess(const wp<IBinder>& processToken) {
+ std::lock_guard lock(mMutex);
+ mBuffers.erase(processToken);
+}
+
+void BufferStateLayerCache::CacheDeathRecipient::binderDied(const wp<IBinder>& who) {
+ BufferStateLayerCache::getInstance().removeProcess(who);
+}
+
+}; // namespace android
diff --git a/services/surfaceflinger/BufferStateLayerCache.h b/services/surfaceflinger/BufferStateLayerCache.h
new file mode 100644
index 0000000..ede3feb
--- /dev/null
+++ b/services/surfaceflinger/BufferStateLayerCache.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android-base/thread_annotations.h>
+#include <binder/IBinder.h>
+#include <ui/GraphicBuffer.h>
+#include <utils/RefBase.h>
+#include <utils/Singleton.h>
+
+#include <array>
+#include <map>
+#include <mutex>
+
+#define BUFFER_CACHE_MAX_SIZE 64
+
+namespace android {
+
+class BufferStateLayerCache : public Singleton<BufferStateLayerCache> {
+public:
+ BufferStateLayerCache();
+
+ void add(sp<IBinder> processToken, int32_t id, const sp<GraphicBuffer>& buffer);
+ sp<GraphicBuffer> get(sp<IBinder> processToken, int32_t id);
+
+ void removeProcess(const wp<IBinder>& processToken);
+
+private:
+ std::mutex mMutex;
+ std::map<wp<IBinder> /*caching process*/, std::array<sp<GraphicBuffer>, BUFFER_CACHE_MAX_SIZE>>
+ mBuffers GUARDED_BY(mMutex);
+
+ class CacheDeathRecipient : public IBinder::DeathRecipient {
+ public:
+ void binderDied(const wp<IBinder>& who) override;
+ };
+
+ sp<CacheDeathRecipient> mDeathRecipient;
+};
+
+}; // namespace android
diff --git a/services/surfaceflinger/Client.cpp b/services/surfaceflinger/Client.cpp
index 0b59147..0ca3759 100644
--- a/services/surfaceflinger/Client.cpp
+++ b/services/surfaceflinger/Client.cpp
@@ -35,55 +35,10 @@
// ---------------------------------------------------------------------------
Client::Client(const sp<SurfaceFlinger>& flinger)
- : Client(flinger, nullptr)
+ : mFlinger(flinger)
{
}
-Client::Client(const sp<SurfaceFlinger>& flinger, const sp<Layer>& parentLayer)
- : mFlinger(flinger),
- mParentLayer(parentLayer)
-{
-}
-
-Client::~Client()
-{
- // We need to post a message to remove our remaining layers rather than
- // do so directly by acquiring the SurfaceFlinger lock. If we were to
- // attempt to directly call the lock it becomes effectively impossible
- // to use sp<Client> while holding the SF lock as descoping it could
- // then trigger a dead-lock.
-
- const size_t count = mLayers.size();
- for (size_t i=0 ; i<count ; i++) {
- sp<Layer> l = mLayers.valueAt(i).promote();
- if (l == nullptr) {
- continue;
- }
- mFlinger->postMessageAsync(new LambdaMessage([flinger = mFlinger, l]() {
- flinger->removeLayer(l);
- }));
- }
-}
-
-void Client::updateParent(const sp<Layer>& parentLayer) {
- Mutex::Autolock _l(mLock);
-
- // If we didn't ever have a parent, then we must instead be
- // relying on permissions and we never need a parent.
- if (mParentLayer != nullptr) {
- mParentLayer = parentLayer;
- }
-}
-
-sp<Layer> Client::getParentLayer(bool* outParentDied) const {
- Mutex::Autolock _l(mLock);
- sp<Layer> parent = mParentLayer.promote();
- if (outParentDied != nullptr) {
- *outParentDied = (mParentLayer != nullptr && parent == nullptr);
- }
- return parent;
-}
-
status_t Client::initCheck() const {
return NO_ERROR;
}
@@ -118,40 +73,10 @@
return lbc;
}
-
-status_t Client::onTransact(
- uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
-{
- // these must be checked
- IPCThreadState* ipc = IPCThreadState::self();
- const int pid = ipc->getCallingPid();
- const int uid = ipc->getCallingUid();
- const int self_pid = getpid();
- // If we are called from another non root process without the GRAPHICS, SYSTEM, or ROOT
- // uid we require the sAccessSurfaceFlinger permission.
- // We grant an exception in the case that the Client has a "parent layer", as its
- // effects will be scoped to that layer.
- if (CC_UNLIKELY(pid != self_pid && uid != AID_GRAPHICS && uid != AID_SYSTEM && uid != 0)
- && (getParentLayer() == nullptr)) {
- // we're called from a different process, do the real check
- if (!PermissionCache::checkCallingPermission(sAccessSurfaceFlinger))
- {
- ALOGE("Permission Denial: "
- "can't openGlobalTransaction pid=%d, uid<=%d", pid, uid);
- return PERMISSION_DENIED;
- }
- }
- return BnSurfaceComposerClient::onTransact(code, data, reply, flags);
-}
-
-
-status_t Client::createSurface(
- const String8& name,
- uint32_t w, uint32_t h, PixelFormat format, uint32_t flags,
- const sp<IBinder>& parentHandle, int32_t windowType, int32_t ownerUid,
- sp<IBinder>* handle,
- sp<IGraphicBufferProducer>* gbp)
-{
+status_t Client::createSurface(const String8& name, uint32_t w, uint32_t h, PixelFormat format,
+ uint32_t flags, const sp<IBinder>& parentHandle,
+ LayerMetadata metadata, sp<IBinder>* handle,
+ sp<IGraphicBufferProducer>* gbp) {
sp<Layer> parent = nullptr;
if (parentHandle != nullptr) {
auto layerHandle = reinterpret_cast<Layer::Handle*>(parentHandle.get());
@@ -160,22 +85,29 @@
return NAME_NOT_FOUND;
}
}
- if (parent == nullptr) {
- bool parentDied;
- parent = getParentLayer(&parentDied);
- // If we had a parent, but it died, we've lost all
- // our capabilities.
- if (parentDied) {
- return NAME_NOT_FOUND;
- }
- }
- return mFlinger->createLayer(name, this, w, h, format, flags, windowType,
- ownerUid, handle, gbp, &parent);
+ // We rely on createLayer to check permissions.
+ return mFlinger->createLayer(name, this, w, h, format, flags, std::move(metadata), handle, gbp,
+ &parent);
}
-status_t Client::destroySurface(const sp<IBinder>& handle) {
- return mFlinger->onLayerRemoved(this, handle);
+status_t Client::createWithSurfaceParent(const String8& name, uint32_t w, uint32_t h,
+ PixelFormat format, uint32_t flags,
+ const sp<IGraphicBufferProducer>& parent,
+ LayerMetadata metadata, sp<IBinder>* handle,
+ sp<IGraphicBufferProducer>* gbp) {
+ if (mFlinger->authenticateSurfaceTexture(parent) == false) {
+ return BAD_VALUE;
+ }
+
+ const auto& layer = (static_cast<MonitoredProducer*>(parent.get()))->getLayer();
+ if (layer == nullptr) {
+ return BAD_VALUE;
+ }
+
+ sp<IBinder> parentHandle = layer->getHandle();
+
+ return createSurface(name, w, h, format, flags, parentHandle, std::move(metadata), handle, gbp);
}
status_t Client::clearLayerFrameStats(const sp<IBinder>& handle) const {
diff --git a/services/surfaceflinger/Client.h b/services/surfaceflinger/Client.h
index 49437ed..74e4818 100644
--- a/services/surfaceflinger/Client.h
+++ b/services/surfaceflinger/Client.h
@@ -39,46 +39,38 @@
{
public:
explicit Client(const sp<SurfaceFlinger>& flinger);
- Client(const sp<SurfaceFlinger>& flinger, const sp<Layer>& parentLayer);
- ~Client();
+ ~Client() = default;
status_t initCheck() const;
// protected by SurfaceFlinger::mStateLock
void attachLayer(const sp<IBinder>& handle, const sp<Layer>& layer);
-
void detachLayer(const Layer* layer);
sp<Layer> getLayerUser(const sp<IBinder>& handle) const;
- void updateParent(const sp<Layer>& parentLayer);
-
private:
// ISurfaceComposerClient interface
- virtual status_t createSurface(
- const String8& name,
- uint32_t w, uint32_t h,PixelFormat format, uint32_t flags,
- const sp<IBinder>& parent, int32_t windowType, int32_t ownerUid,
- sp<IBinder>* handle,
- sp<IGraphicBufferProducer>* gbp);
+ virtual status_t createSurface(const String8& name, uint32_t w, uint32_t h, PixelFormat format,
+ uint32_t flags, const sp<IBinder>& parent,
+ LayerMetadata metadata, sp<IBinder>* handle,
+ sp<IGraphicBufferProducer>* gbp);
- virtual status_t destroySurface(const sp<IBinder>& handle);
+ virtual status_t createWithSurfaceParent(const String8& name, uint32_t w, uint32_t h,
+ PixelFormat format, uint32_t flags,
+ const sp<IGraphicBufferProducer>& parent,
+ LayerMetadata metadata, sp<IBinder>* handle,
+ sp<IGraphicBufferProducer>* gbp);
virtual status_t clearLayerFrameStats(const sp<IBinder>& handle) const;
virtual status_t getLayerFrameStats(const sp<IBinder>& handle, FrameStats* outStats) const;
- virtual status_t onTransact(
- uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags);
-
- sp<Layer> getParentLayer(bool* outParentDied = nullptr) const;
-
// constant
sp<SurfaceFlinger> mFlinger;
// protected by mLock
DefaultKeyedVector< wp<IBinder>, wp<Layer> > mLayers;
- wp<Layer> mParentLayer;
// thread-safe
mutable Mutex mLock;
diff --git a/services/surfaceflinger/ColorLayer.cpp b/services/surfaceflinger/ColorLayer.cpp
index cb7642e..b4e9d17 100644
--- a/services/surfaceflinger/ColorLayer.cpp
+++ b/services/surfaceflinger/ColorLayer.cpp
@@ -22,6 +22,9 @@
#include <stdlib.h>
#include <sys/types.h>
+#include <compositionengine/CompositionEngine.h>
+#include <compositionengine/Layer.h>
+#include <compositionengine/LayerCreationArgs.h>
#include <renderengine/RenderEngine.h>
#include <ui/GraphicBuffer.h>
#include <utils/Errors.h>
@@ -34,22 +37,24 @@
namespace android {
// ---------------------------------------------------------------------------
-ColorLayer::ColorLayer(const LayerCreationArgs& args) : Layer(args) {}
+ColorLayer::ColorLayer(const LayerCreationArgs& args)
+ : Layer(args),
+ mCompositionLayer{mFlinger->getCompositionEngine().createLayer(
+ compositionengine::LayerCreationArgs{this})} {}
ColorLayer::~ColorLayer() = default;
void ColorLayer::onDraw(const RenderArea& renderArea, const Region& /* clip */,
bool useIdentityTransform) {
- Mutex::Autolock lock(mStateMutex);
half4 color = getColor();
if (color.a > 0) {
renderengine::Mesh mesh(renderengine::Mesh::TRIANGLE_FAN, 4, 2);
computeGeometry(renderArea, mesh, useIdentityTransform);
auto& engine(mFlinger->getRenderEngine());
- Rect win{computeBoundsLocked()};
+ Rect win{computeBounds()};
- const auto roundedCornerState = getRoundedCornerStateLocked();
+ const auto roundedCornerState = getRoundedCornerState();
const auto cropRect = roundedCornerState.cropRect;
setupRoundedCornersCropCoordinates(win, cropRect);
@@ -67,6 +72,21 @@
return !isHiddenByPolicy() && getAlpha() > 0.0f;
}
+bool ColorLayer::setColor(const half3& color) {
+ if (mCurrentState.color.r == color.r && mCurrentState.color.g == color.g &&
+ mCurrentState.color.b == color.b) {
+ return false;
+ }
+
+ mCurrentState.sequence++;
+ mCurrentState.color.r = color.r;
+ mCurrentState.color.g = color.g;
+ mCurrentState.color.b = color.b;
+ mCurrentState.modified = true;
+ setTransactionFlags(eTransactionNeeded);
+ return true;
+}
+
void ColorLayer::setPerFrameData(DisplayId displayId, const ui::Transform& transform,
const Rect& viewport, int32_t /* supportedPerFrameMetadata */) {
RETURN_IF_NO_HWC_LAYER(displayId);
@@ -92,7 +112,6 @@
}
getBE().compositionInfo.hwc.dataspace = mCurrentDataSpace;
- Mutex::Autolock lock(mStateMutex);
half4 color = getColor();
error = hwcLayer->setColor({static_cast<uint8_t>(std::round(255.0f * color.r)),
static_cast<uint8_t>(std::round(255.0f * color.g)),
@@ -113,12 +132,12 @@
}
getBE().compositionInfo.hwc.transform = HWC2::Transform::None;
- error = hwcLayer->setColorTransform(getColorTransformLocked());
+ error = hwcLayer->setColorTransform(getColorTransform());
if (error != HWC2::Error::None) {
ALOGE("[%s] Failed to setColorTransform: %s (%d)", mName.string(),
to_string(error).c_str(), static_cast<int32_t>(error));
}
- getBE().compositionInfo.hwc.colorTransform = getColorTransformLocked();
+ getBE().compositionInfo.hwc.colorTransform = getColorTransform();
error = hwcLayer->setSurfaceDamage(surfaceDamageRegion);
if (error != HWC2::Error::None) {
@@ -129,6 +148,10 @@
getBE().compositionInfo.hwc.surfaceDamage = surfaceDamageRegion;
}
+std::shared_ptr<compositionengine::Layer> ColorLayer::getCompositionLayer() const {
+ return mCompositionLayer;
+}
+
// ---------------------------------------------------------------------------
}; // namespace android
diff --git a/services/surfaceflinger/ColorLayer.h b/services/surfaceflinger/ColorLayer.h
index 5850a2e..3b98e8c 100644
--- a/services/surfaceflinger/ColorLayer.h
+++ b/services/surfaceflinger/ColorLayer.h
@@ -28,18 +28,25 @@
explicit ColorLayer(const LayerCreationArgs&);
~ColorLayer() override;
+ std::shared_ptr<compositionengine::Layer> getCompositionLayer() const override;
+
virtual const char* getTypeId() const { return "ColorLayer"; }
- virtual void onDraw(const RenderArea& renderArea, const Region& clip, bool useIdentityTransform)
- EXCLUDES(mStateMutex);
- bool isVisible() const override EXCLUDES(mStateMutex);
+ virtual void onDraw(const RenderArea& renderArea, const Region& clip,
+ bool useIdentityTransform);
+ bool isVisible() const override;
+
+ bool setColor(const half3& color) override;
void setPerFrameData(DisplayId displayId, const ui::Transform& transform, const Rect& viewport,
- int32_t supportedPerFrameMetadata) override EXCLUDES(mStateMutex);
+ int32_t supportedPerFrameMetadata) override;
bool onPreComposition(nsecs_t /*refreshStartTime*/) override { return false; }
protected:
FloatRect computeCrop(const sp<const DisplayDevice>& /*display*/) const override { return {}; }
+
+private:
+ std::shared_ptr<compositionengine::Layer> mCompositionLayer;
};
} // namespace android
diff --git a/services/surfaceflinger/CompositionEngine/Android.bp b/services/surfaceflinger/CompositionEngine/Android.bp
new file mode 100644
index 0000000..ce6b06c
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/Android.bp
@@ -0,0 +1,115 @@
+cc_defaults {
+ name: "libcompositionengine_defaults",
+ defaults: ["surfaceflinger_defaults"],
+ cflags: [
+ "-DLOG_TAG=\"CompositionEngine\"",
+ ],
+ shared_libs: [
+ "android.hardware.graphics.allocator@2.0",
+ "android.hardware.graphics.composer@2.1",
+ "android.hardware.graphics.composer@2.2",
+ "android.hardware.graphics.composer@2.3",
+ "android.hardware.power@1.0",
+ "android.hardware.power@1.3",
+ "libbase",
+ "libcutils",
+ "libgui",
+ "liblayers_proto",
+ "liblog",
+ "libnativewindow",
+ "libsync",
+ "libtimestats_proto",
+ "libui",
+ "libutils",
+ ],
+ static_libs: [
+ "libmath",
+ "librenderengine",
+ "libtrace_proto",
+ ],
+ header_libs: [
+ "libsurfaceflinger_headers",
+ ],
+}
+
+cc_library {
+ name: "libcompositionengine",
+ defaults: ["libcompositionengine_defaults"],
+ srcs: [
+ "src/CompositionEngine.cpp",
+ "src/Display.cpp",
+ "src/DisplayColorProfile.cpp",
+ "src/DisplaySurface.cpp",
+ "src/DumpHelpers.cpp",
+ "src/HwcBufferCache.cpp",
+ "src/Layer.cpp",
+ "src/Output.cpp",
+ "src/OutputCompositionState.cpp",
+ "src/OutputLayer.cpp",
+ "src/RenderSurface.cpp",
+ ],
+ local_include_dirs: ["include"],
+ export_include_dirs: ["include"],
+}
+
+cc_library {
+ name: "libcompositionengine_mocks",
+ defaults: ["libcompositionengine_defaults"],
+ srcs: [
+ "mock/CompositionEngine.cpp",
+ "mock/Display.cpp",
+ "mock/DisplayColorProfile.cpp",
+ "mock/DisplaySurface.cpp",
+ "mock/Layer.cpp",
+ "mock/LayerFE.cpp",
+ "mock/Output.cpp",
+ "mock/OutputLayer.cpp",
+ "mock/RenderSurface.cpp",
+ ],
+ static_libs: [
+ "libgtest",
+ "libgmock",
+ "libcompositionengine",
+ ],
+ local_include_dirs: ["include"],
+ export_include_dirs: ["include"],
+}
+
+cc_test {
+ name: "libcompositionengine_test",
+ test_suites: ["device-tests"],
+ defaults: ["libcompositionengine_defaults"],
+ srcs: [
+ "tests/CompositionEngineTest.cpp",
+ "tests/DisplayColorProfileTest.cpp",
+ "tests/DisplayTest.cpp",
+ "tests/HwcBufferCacheTest.cpp",
+ "tests/LayerTest.cpp",
+ "tests/MockHWComposer.cpp",
+ "tests/OutputTest.cpp",
+ "tests/OutputLayerTest.cpp",
+ "tests/RenderSurfaceTest.cpp",
+ ],
+ static_libs: [
+ "libcompositionengine",
+ "libcompositionengine_mocks",
+ "librenderengine_mocks",
+ "libgmock",
+ "libgtest",
+ ],
+ sanitize: {
+ // By using the address sanitizer, we not only uncover any issues
+ // with the test, but also any issues with the code under test.
+ //
+ // Note: If you get an runtime link error like:
+ //
+ // CANNOT LINK EXECUTABLE "/data/local/tmp/libcompositionengine_test": library "libclang_rt.asan-aarch64-android.so" not found
+ //
+ // it is because the address sanitizer shared objects are not installed
+ // by default in the system image.
+ //
+ // You can either "make dist tests" before flashing, or set this
+ // option to false temporarily.
+ address: true,
+ },
+}
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionEngine.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionEngine.h
new file mode 100644
index 0000000..896f8aa
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionEngine.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <memory>
+
+namespace android {
+
+class HWComposer;
+
+namespace renderengine {
+class RenderEngine;
+} // namespace renderengine
+
+namespace compositionengine {
+
+class Display;
+class Layer;
+
+struct DisplayCreationArgs;
+struct LayerCreationArgs;
+
+/**
+ * Encapsulates all the interfaces and implementation details for performing
+ * display output composition.
+ */
+class CompositionEngine {
+public:
+ virtual ~CompositionEngine();
+
+ // Create a composition Display
+ virtual std::shared_ptr<Display> createDisplay(DisplayCreationArgs&&) = 0;
+ virtual std::shared_ptr<Layer> createLayer(LayerCreationArgs&&) = 0;
+
+ virtual HWComposer& getHwComposer() const = 0;
+ virtual void setHwComposer(std::unique_ptr<HWComposer>) = 0;
+
+ virtual renderengine::RenderEngine& getRenderEngine() const = 0;
+ virtual void setRenderEngine(std::unique_ptr<renderengine::RenderEngine>) = 0;
+};
+
+} // namespace compositionengine
+} // namespace android
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Display.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Display.h
new file mode 100644
index 0000000..dbcd3bd
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Display.h
@@ -0,0 +1,59 @@
+/*
+ * 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 <cstdint>
+#include <optional>
+
+#include "DisplayHardware/DisplayIdentification.h"
+
+#include <compositionengine/Output.h>
+
+namespace android::compositionengine {
+
+struct RenderSurfaceCreationArgs;
+struct DisplayColorProfileCreationArgs;
+
+/**
+ * A display is a composition target which may be backed by a hardware composer
+ * display device
+ */
+class Display : public virtual Output {
+public:
+ // Gets the HWC DisplayId for the display if there is one
+ virtual const std::optional<DisplayId>& getId() const = 0;
+
+ // True if the display is secure
+ virtual bool isSecure() const = 0;
+
+ // True if the display is virtual
+ virtual bool isVirtual() const = 0;
+
+ // Releases the use of the HWC display, if any
+ virtual void disconnect() = 0;
+
+ // Creates a render color mode for the display
+ virtual void createDisplayColorProfile(DisplayColorProfileCreationArgs&&) = 0;
+
+ // Creates a render surface for the display
+ virtual void createRenderSurface(RenderSurfaceCreationArgs&&) = 0;
+
+protected:
+ ~Display() = default;
+};
+
+} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayColorProfile.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayColorProfile.h
new file mode 100644
index 0000000..e2a0d42
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayColorProfile.h
@@ -0,0 +1,83 @@
+/*
+ * 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 <cstdint>
+
+#include <ui/GraphicTypes.h>
+
+namespace android {
+
+class HdrCapabilities;
+
+namespace compositionengine {
+
+/**
+ * Encapsulates all the state and functionality for how colors should be
+ * transformed for a display
+ */
+class DisplayColorProfile {
+public:
+ constexpr static float sDefaultMinLumiance = 0.0;
+ constexpr static float sDefaultMaxLumiance = 500.0;
+
+ virtual ~DisplayColorProfile();
+
+ // Returns true if the profile is valid. This is meant to be checked post-
+ // construction and prior to use, as not everything is set up by the
+ // constructor.
+ virtual bool isValid() const = 0;
+
+ // Returns true if the profile supports the indicated render intent
+ virtual bool hasRenderIntent(ui::RenderIntent) const = 0;
+
+ // Returns true if the profile supports the indicated dataspace
+ virtual bool hasLegacyHdrSupport(ui::Dataspace) const = 0;
+
+ // Obtains the best combination of color mode and render intent for the
+ // input values
+ virtual void getBestColorMode(ui::Dataspace dataspace, ui::RenderIntent intent,
+ ui::Dataspace* outDataspace, ui::ColorMode* outMode,
+ ui::RenderIntent* outIntent) const = 0;
+
+ // Returns true if the profile supports a wide color gamut
+ virtual bool hasWideColorGamut() const = 0;
+
+ // Returns the per-frame metadata value for this profile
+ virtual int32_t getSupportedPerFrameMetadata() const = 0;
+
+ // Returns true if HWC for this profile supports HDR10Plus
+ virtual bool hasHDR10PlusSupport() const = 0;
+
+ // Returns true if HWC for this profile supports HDR10
+ virtual bool hasHDR10Support() const = 0;
+
+ // Returns true if HWC for this profile supports HLG
+ virtual bool hasHLGSupport() const = 0;
+
+ // Returns true if HWC for this profile supports DolbyVision
+ virtual bool hasDolbyVisionSupport() const = 0;
+
+ // Gets the supported HDR capabilities for the profile
+ virtual const HdrCapabilities& getHdrCapabilities() const = 0;
+
+ // Debugging
+ virtual void dump(std::string&) const = 0;
+};
+
+} // namespace compositionengine
+} // namespace android
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayColorProfileCreationArgs.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayColorProfileCreationArgs.h
new file mode 100644
index 0000000..ef0f925
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayColorProfileCreationArgs.h
@@ -0,0 +1,89 @@
+/*
+ * 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 <cstdint>
+#include <unordered_map>
+#include <vector>
+
+#include <ui/GraphicTypes.h>
+#include <ui/HdrCapabilities.h>
+
+namespace android::compositionengine {
+
+/**
+ * A parameter object for creating DisplayColorProfile instances
+ */
+struct DisplayColorProfileCreationArgs {
+ using HwcColorModes = std::unordered_map<ui::ColorMode, std::vector<ui::RenderIntent>>;
+
+ // True if this display supports a wide color gamut
+ bool hasWideColorGamut;
+
+ // The HDR capabilities supported by the HWC
+ HdrCapabilities hdrCapabilities;
+
+ // The per-frame metadata supported by the HWC
+ int32_t supportedPerFrameMetadata;
+
+ // The mapping of color modes and render intents supported by the HWC
+ HwcColorModes hwcColorModes;
+};
+
+/**
+ * A helper for setting up a DisplayColorProfileCreationArgs value in-line.
+ *
+ * Prefer this builder over raw structure initialization.
+ *
+ * Instead of:
+ *
+ * DisplayColorProfileCreationArgs{false, HdrCapabilities(), 0,
+ * HwcColorModes()}
+ *
+ * Prefer:
+ *
+ * DisplayColorProfileCreationArgsBuilder().setHasWideColorGamut(false)
+ * .setIsVirtual(false).setDisplayId(displayId).Build();
+ */
+class DisplayColorProfileCreationArgsBuilder {
+public:
+ DisplayColorProfileCreationArgs Build() { return std::move(mArgs); }
+
+ DisplayColorProfileCreationArgsBuilder& setHasWideColorGamut(bool hasWideColorGamut) {
+ mArgs.hasWideColorGamut = hasWideColorGamut;
+ return *this;
+ }
+ DisplayColorProfileCreationArgsBuilder& setHdrCapabilities(HdrCapabilities&& hdrCapabilities) {
+ mArgs.hdrCapabilities = std::move(hdrCapabilities);
+ return *this;
+ }
+ DisplayColorProfileCreationArgsBuilder& setSupportedPerFrameMetadata(
+ int32_t supportedPerFrameMetadata) {
+ mArgs.supportedPerFrameMetadata = supportedPerFrameMetadata;
+ return *this;
+ }
+ DisplayColorProfileCreationArgsBuilder& setHwcColorModes(
+ DisplayColorProfileCreationArgs::HwcColorModes&& hwcColorModes) {
+ mArgs.hwcColorModes = std::move(hwcColorModes);
+ return *this;
+ }
+
+private:
+ DisplayColorProfileCreationArgs mArgs;
+};
+
+} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayCreationArgs.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayCreationArgs.h
new file mode 100644
index 0000000..0b6b4e4
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayCreationArgs.h
@@ -0,0 +1,76 @@
+/*
+ * 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 <cstdint>
+#include <optional>
+
+#include "DisplayHardware/DisplayIdentification.h"
+
+namespace android::compositionengine {
+
+class CompositionEngine;
+
+/**
+ * A parameter object for creating Display instances
+ */
+struct DisplayCreationArgs {
+ // True if this display is secure
+ bool isSecure = false;
+
+ // True if this display is a virtual display
+ bool isVirtual = false;
+
+ // Identifies the display to the HWC, if composition is supported by it
+ std::optional<DisplayId> displayId;
+};
+
+/**
+ * A helper for setting up a DisplayCreationArgs value in-line.
+ * Prefer this builder over raw structure initialization.
+ *
+ * Instead of:
+ *
+ * DisplayCreationArgs{false, false, displayId}
+ *
+ * Prefer:
+ *
+ * DisplayCreationArgsBuilder().setIsSecure(false).setIsVirtual(false)
+ * .setDisplayId(displayId).build();
+ */
+class DisplayCreationArgsBuilder {
+public:
+ DisplayCreationArgs build() { return std::move(mArgs); }
+
+ DisplayCreationArgsBuilder& setIsSecure(bool isSecure) {
+ mArgs.isSecure = isSecure;
+ return *this;
+ }
+ DisplayCreationArgsBuilder& setIsVirtual(bool isVirtual) {
+ mArgs.isVirtual = isVirtual;
+ return *this;
+ }
+ DisplayCreationArgsBuilder& setDisplayId(std::optional<DisplayId> displayId) {
+ mArgs.displayId = displayId;
+ return *this;
+ }
+
+private:
+ DisplayCreationArgs mArgs;
+};
+
+} // namespace android::compositionengine
diff --git a/services/surfaceflinger/DisplayHardware/DisplaySurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplaySurface.h
similarity index 80%
rename from services/surfaceflinger/DisplayHardware/DisplaySurface.h
rename to services/surfaceflinger/CompositionEngine/include/compositionengine/DisplaySurface.h
index f744f5c..0e67acf 100644
--- a/services/surfaceflinger/DisplayHardware/DisplaySurface.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplaySurface.h
@@ -14,23 +14,27 @@
* limitations under the License.
*/
-#ifndef ANDROID_SF_DISPLAY_SURFACE_H
-#define ANDROID_SF_DISPLAY_SURFACE_H
+#pragma once
#include <utils/Errors.h>
#include <utils/RefBase.h>
#include <utils/StrongPointer.h>
-// ---------------------------------------------------------------------------
namespace android {
-// ---------------------------------------------------------------------------
class Fence;
class IGraphicBufferProducer;
class String8;
+namespace compositionengine {
+
+/**
+ * An abstraction for working with a display surface (buffer queue)
+ */
class DisplaySurface : public virtual RefBase {
public:
+ virtual ~DisplaySurface();
+
// beginFrame is called at the beginning of the composition loop, before
// the configuration is known. The DisplaySurface should do anything it
// needs to do to enable HWComposer to decide how to compose the frame.
@@ -44,9 +48,9 @@
// GLES and HWC for this frame.
enum CompositionType {
COMPOSITION_UNKNOWN = 0,
- COMPOSITION_GLES = 1,
- COMPOSITION_HWC = 2,
- COMPOSITION_MIXED = COMPOSITION_GLES | COMPOSITION_HWC
+ COMPOSITION_GLES = 1,
+ COMPOSITION_HWC = 2,
+ COMPOSITION_MIXED = COMPOSITION_GLES | COMPOSITION_HWC
};
virtual status_t prepareFrame(CompositionType compositionType) = 0;
@@ -70,15 +74,7 @@
virtual void resizeBuffers(const uint32_t w, const uint32_t h) = 0;
virtual const sp<Fence>& getClientTargetAcquireFence() const = 0;
-
-protected:
- DisplaySurface() {}
- virtual ~DisplaySurface() {}
};
-// ---------------------------------------------------------------------------
+} // namespace compositionengine
} // namespace android
-// ---------------------------------------------------------------------------
-
-#endif // ANDROID_SF_DISPLAY_SURFACE_H
-
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Layer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Layer.h
new file mode 100644
index 0000000..29a7dea
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Layer.h
@@ -0,0 +1,46 @@
+/*
+ * 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 <cstdint>
+
+#include <utils/StrongPointer.h>
+
+namespace android {
+
+typedef int64_t nsecs_t;
+
+namespace compositionengine {
+
+class Display;
+class LayerFE;
+
+/**
+ * A layer contains the output-independent composition state for a front-end
+ * Layer
+ */
+class Layer {
+public:
+ virtual ~Layer();
+
+ // Gets the front-end interface for this layer. Can return nullptr if the
+ // front-end layer no longer exists.
+ virtual sp<LayerFE> getLayerFE() const = 0;
+};
+
+} // namespace compositionengine
+} // namespace android
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerCreationArgs.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerCreationArgs.h
new file mode 100644
index 0000000..db3312b
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerCreationArgs.h
@@ -0,0 +1,35 @@
+/*
+ * 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 <utils/RefBase.h>
+
+namespace android::compositionengine {
+
+class CompositionEngine;
+class LayerFE;
+
+/**
+ * A parameter object for creating Layer instances
+ */
+struct LayerCreationArgs {
+ // A weak pointer to the front-end layer instance that the new layer will
+ // represent.
+ wp<LayerFE> layerFE;
+};
+
+} // namespace android::compositionengine
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplaySurface.cpp b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
similarity index 63%
copy from services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplaySurface.cpp
copy to services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
index e6ac6bf..f9a3624 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplaySurface.cpp
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018 The Android Open Source Project
+ * 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.
@@ -14,14 +14,14 @@
* limitations under the License.
*/
-#include "mock/DisplayHardware/MockDisplaySurface.h"
+#pragma once
-namespace android {
-namespace mock {
+#include <utils/RefBase.h>
-// Explicit default instantiation is recommended.
-DisplaySurface::DisplaySurface() = default;
-DisplaySurface::~DisplaySurface() = default;
+namespace android::compositionengine {
-} // namespace mock
-} // namespace android
+// Defines the interface used by the CompositionEngine to make requests
+// of the front-end layer
+class LayerFE : public virtual RefBase {};
+
+} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
new file mode 100644
index 0000000..a7ab472
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
@@ -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.
+ */
+
+#pragma once
+
+#include <cstdint>
+#include <string>
+
+#include <math/mat4.h>
+#include <ui/GraphicTypes.h>
+#include <ui/Region.h>
+#include <ui/Transform.h>
+#include <utils/StrongPointer.h>
+
+namespace android::compositionengine {
+
+class DisplayColorProfile;
+class Layer;
+class LayerFE;
+class RenderSurface;
+class OutputLayer;
+
+namespace impl {
+struct OutputCompositionState;
+} // namespace impl
+
+/**
+ * Encapsulates all the state involved with composing layers for an output
+ */
+class Output {
+public:
+ using OutputLayers = std::vector<std::unique_ptr<compositionengine::OutputLayer>>;
+
+ virtual ~Output();
+
+ // Returns true if the output is valid. This is meant to be checked post-
+ // construction and prior to use, as not everything is set up by the
+ // constructor.
+ virtual bool isValid() const = 0;
+
+ // Enables (or disables) composition on this output
+ virtual void setCompositionEnabled(bool) = 0;
+
+ // Sets the projection state to use
+ virtual void setProjection(const ui::Transform&, int32_t orientation, const Rect& frame,
+ const Rect& viewport, const Rect& scissor, bool needsFiltering) = 0;
+ // Sets the bounds to use
+ virtual void setBounds(const ui::Size&) = 0;
+
+ // Sets the layer stack filtering settings for this output. See
+ // belongsInOutput for full details.
+ virtual void setLayerStackFilter(uint32_t layerStackId, bool isInternal) = 0;
+
+ // Sets the color transform matrix to use
+ virtual void setColorTransform(const mat4&) = 0;
+
+ // Sets the output color mode
+ virtual void setColorMode(ui::ColorMode, ui::Dataspace, ui::RenderIntent) = 0;
+
+ // Outputs a string with a state dump
+ virtual void dump(std::string&) const = 0;
+
+ // Gets the debug name for the output
+ virtual const std::string& getName() const = 0;
+
+ // Sets a debug name for the output
+ virtual void setName(const std::string&) = 0;
+
+ // Gets the current render color mode for the output
+ virtual DisplayColorProfile* getDisplayColorProfile() const = 0;
+
+ // Gets the current render surface for the output
+ virtual RenderSurface* getRenderSurface() const = 0;
+
+ using OutputCompositionState = compositionengine::impl::OutputCompositionState;
+
+ // Gets the raw composition state data for the output
+ // TODO(lpique): Make this protected once it is only internally called.
+ virtual const OutputCompositionState& getState() const = 0;
+
+ // Allows mutable access to the raw composition state data for the output.
+ // This is meant to be used by the various functions that are part of the
+ // composition process.
+ // TODO(lpique): Make this protected once it is only internally called.
+ virtual OutputCompositionState& editState() = 0;
+
+ // Gets the physical space dirty region. If repaintEverything is true, this
+ // will be the full display bounds. Internally the dirty region is stored in
+ // logical (aka layer stack) space.
+ virtual Region getPhysicalSpaceDirtyRegion(bool repaintEverything) const = 0;
+
+ // Tests whether a given layerStackId belongs in this output.
+ // A layer belongs to the output if its layerStackId matches the of the output layerStackId,
+ // unless the layer should display on the primary output only and this is not the primary output
+
+ // A layer belongs to the output if its layerStackId matches. Additionally
+ // if the layer should only show in the internal (primary) display only and
+ // this output allows that.
+ virtual bool belongsInOutput(uint32_t layerStackId, bool internalOnly) const = 0;
+
+ // Returns a pointer to the output layer corresponding to the given layer on
+ // this output, or nullptr if the layer does not have one
+ virtual OutputLayer* getOutputLayerForLayer(Layer*) const = 0;
+
+ // Gets the OutputLayer corresponding to the input Layer instance from the
+ // current ordered set of output layers. If there is no such layer, a new
+ // one is created and returned.
+ virtual std::unique_ptr<OutputLayer> getOrCreateOutputLayer(std::shared_ptr<Layer>,
+ sp<LayerFE>) = 0;
+
+ // Sets the new ordered set of output layers for this output
+ virtual void setOutputLayersOrderedByZ(OutputLayers&&) = 0;
+
+ // Gets the ordered set of output layers for this output
+ virtual const OutputLayers& getOutputLayersOrderedByZ() const = 0;
+
+protected:
+ virtual void setDisplayColorProfile(std::unique_ptr<DisplayColorProfile>) = 0;
+ virtual void setRenderSurface(std::unique_ptr<RenderSurface>) = 0;
+};
+
+} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h
new file mode 100644
index 0000000..4b8ef38
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <utils/StrongPointer.h>
+
+namespace android::compositionengine {
+
+class Output;
+class Layer;
+class LayerFE;
+
+/**
+ * An output layer contains the output-dependent composition state for a layer
+ */
+class OutputLayer {
+public:
+ virtual ~OutputLayer();
+
+ // Gets the output which owns this output layer
+ virtual const Output& getOutput() const = 0;
+
+ // Gets the display-independent layer which this output layer represents
+ virtual Layer& getLayer() const = 0;
+
+ // Gets the front-end layer interface this output layer represents
+ virtual LayerFE& getLayerFE() const = 0;
+};
+
+} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h
new file mode 100644
index 0000000..dd01b05
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h
@@ -0,0 +1,104 @@
+/*
+ * 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 <cstdint>
+#include <vector>
+
+#include <ui/Fence.h>
+#include <ui/GraphicTypes.h>
+#include <ui/Size.h>
+#include <utils/Errors.h>
+#include <utils/StrongPointer.h>
+
+namespace android {
+
+class GraphicBuffer;
+
+struct CompositionInfo;
+
+namespace compositionengine {
+
+/**
+ * Encapsulates everything for composing to a render surface with RenderEngine
+ */
+class RenderSurface {
+public:
+ virtual ~RenderSurface();
+
+ // Returns true if the render surface is valid. This is meant to be checked
+ // post-construction and prior to use, as not everything is set up by the
+ // constructor.
+ virtual bool isValid() const = 0;
+
+ // Performs one-time initialization of the render surface. This is meant
+ // to be called after the validation check.
+ virtual void initialize() = 0;
+
+ // Returns the bounds of the surface
+ virtual const ui::Size& getSize() const = 0;
+
+ // Gets the latest fence to pass to the HWC to signal that the surface
+ // buffer is done rendering
+ virtual const sp<Fence>& getClientTargetAcquireFence() const = 0;
+
+ // Sets the size of the surface
+ virtual void setDisplaySize(const ui::Size&) = 0;
+
+ // Sets the dataspace used for rendering the surface
+ virtual void setBufferDataspace(ui::Dataspace) = 0;
+
+ // Configures the protected rendering on the surface
+ virtual void setProtected(bool useProtected) = 0;
+
+ // Called to signal that rendering has started. 'mustRecompose' should be
+ // true if the entire frame must be recomposed.
+ virtual status_t beginFrame(bool mustRecompose) = 0;
+
+ // Prepares the frame for rendering
+ virtual status_t prepareFrame(std::vector<CompositionInfo>& compositionData) = 0;
+
+ // Allocates a buffer as scratch space for GPU composition
+ virtual sp<GraphicBuffer> dequeueBuffer() = 0;
+
+ // Queues the drawn buffer for consumption by HWC
+ virtual void queueBuffer() = 0;
+
+ // Called after the HWC calls are made to present the display
+ virtual void onPresentDisplayCompleted() = 0;
+
+ // Marks the current buffer has finished, so that it can be presented and
+ // swapped out
+ virtual void finishBuffer() = 0;
+
+ // Called to set the viewport and projection state for rendering into this
+ // surface
+ virtual void setViewportAndProjection() = 0;
+
+ // Called after the surface has been rendering to signal the surface should
+ // be made ready for displaying
+ virtual void flip() = 0;
+
+ // Debugging - Dumps the state of the RenderSurface to a string
+ virtual void dump(std::string& result) const = 0;
+
+ // Debugging - gets the page flip count for the RenderSurface
+ virtual std::uint32_t getPageFlipCount() const = 0;
+};
+
+} // namespace compositionengine
+} // namespace android
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurfaceCreationArgs.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurfaceCreationArgs.h
new file mode 100644
index 0000000..a1230b3
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurfaceCreationArgs.h
@@ -0,0 +1,89 @@
+/*
+ * 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 <cstdint>
+#include <memory>
+
+#include <compositionengine/DisplaySurface.h>
+#include <utils/StrongPointer.h>
+
+struct ANativeWindow;
+
+namespace android {
+
+namespace compositionengine {
+
+class Display;
+
+/**
+ * A parameter object for creating RenderSurface instances
+ */
+struct RenderSurfaceCreationArgs {
+ // The initial width of the surface
+ int32_t displayWidth;
+
+ // The initial height of the surface
+ int32_t displayHeight;
+
+ // The ANativeWindow for the buffer queue for this surface
+ sp<ANativeWindow> nativeWindow;
+
+ // The DisplaySurface for this surface
+ sp<DisplaySurface> displaySurface;
+};
+
+/**
+ * A helper for setting up a RenderSurfaceCreationArgs value in-line.
+ * Prefer this builder over raw structure initialization.
+ *
+ * Instead of:
+ *
+ * RenderSurfaceCreationArgs{1000, 1000, nativeWindow, displaySurface}
+ *
+ * Prefer:
+ *
+ * RenderSurfaceCreationArgsBuilder().setDisplayWidth(1000).setDisplayHeight(1000)
+ * .setNativeWindow(nativeWindow).setDisplaySurface(displaySurface).Build();
+ */
+class RenderSurfaceCreationArgsBuilder {
+public:
+ RenderSurfaceCreationArgs build() { return std::move(mArgs); }
+
+ RenderSurfaceCreationArgsBuilder& setDisplayWidth(int32_t displayWidth) {
+ mArgs.displayWidth = displayWidth;
+ return *this;
+ }
+ RenderSurfaceCreationArgsBuilder& setDisplayHeight(int32_t displayHeight) {
+ mArgs.displayHeight = displayHeight;
+ return *this;
+ }
+ RenderSurfaceCreationArgsBuilder& setNativeWindow(sp<ANativeWindow> nativeWindow) {
+ mArgs.nativeWindow = nativeWindow;
+ return *this;
+ }
+ RenderSurfaceCreationArgsBuilder& setDisplaySurface(sp<DisplaySurface> displaySurface) {
+ mArgs.displaySurface = displaySurface;
+ return *this;
+ }
+
+private:
+ RenderSurfaceCreationArgs mArgs;
+};
+
+} // namespace compositionengine
+} // namespace android
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/CompositionEngine.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/CompositionEngine.h
new file mode 100644
index 0000000..b01eb64
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/CompositionEngine.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <compositionengine/CompositionEngine.h>
+
+namespace android::compositionengine::impl {
+
+class CompositionEngine : public compositionengine::CompositionEngine {
+public:
+ CompositionEngine();
+ ~CompositionEngine() override;
+
+ std::shared_ptr<compositionengine::Display> createDisplay(
+ compositionengine::DisplayCreationArgs&&) override;
+ std::shared_ptr<compositionengine::Layer> createLayer(
+ compositionengine::LayerCreationArgs&&) override;
+
+ HWComposer& getHwComposer() const override;
+ void setHwComposer(std::unique_ptr<HWComposer>) override;
+
+ renderengine::RenderEngine& getRenderEngine() const override;
+ void setRenderEngine(std::unique_ptr<renderengine::RenderEngine>) override;
+
+private:
+ std::unique_ptr<HWComposer> mHwComposer;
+ std::unique_ptr<renderengine::RenderEngine> mRenderEngine;
+};
+
+std::unique_ptr<compositionengine::CompositionEngine> createCompositionEngine();
+
+} // namespace android::compositionengine::impl
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h
new file mode 100644
index 0000000..0e20c43
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h
@@ -0,0 +1,60 @@
+/*
+ * 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 <memory>
+
+#include <compositionengine/Display.h>
+#include <compositionengine/impl/Output.h>
+
+#include "DisplayHardware/DisplayIdentification.h"
+
+namespace android::compositionengine {
+
+class CompositionEngine;
+
+struct DisplayCreationArgs;
+
+namespace impl {
+
+class Display : public compositionengine::impl::Output, public compositionengine::Display {
+public:
+ Display(const CompositionEngine&, compositionengine::DisplayCreationArgs&&);
+ virtual ~Display();
+
+ // compositionengine::Output overrides
+ void dump(std::string&) const override;
+ void setColorTransform(const mat4&) override;
+ void setColorMode(ui::ColorMode, ui::Dataspace, ui::RenderIntent) override;
+
+ // compositionengine::Display overrides
+ const std::optional<DisplayId>& getId() const override;
+ bool isSecure() const override;
+ bool isVirtual() const override;
+ void disconnect() override;
+ void createDisplayColorProfile(compositionengine::DisplayColorProfileCreationArgs&&) override;
+ void createRenderSurface(compositionengine::RenderSurfaceCreationArgs&&) override;
+
+private:
+ const bool mIsVirtual;
+ std::optional<DisplayId> mId;
+};
+
+std::shared_ptr<compositionengine::Display> createDisplay(
+ const compositionengine::CompositionEngine&, compositionengine::DisplayCreationArgs&&);
+} // namespace impl
+} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/DisplayColorProfile.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/DisplayColorProfile.h
new file mode 100644
index 0000000..49c2d2c
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/DisplayColorProfile.h
@@ -0,0 +1,95 @@
+/*
+ * 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 <cstdint>
+#include <unordered_map>
+#include <vector>
+
+#include <compositionengine/DisplayColorProfile.h>
+#include <compositionengine/DisplayColorProfileCreationArgs.h>
+#include <ui/HdrCapabilities.h>
+
+namespace android::compositionengine {
+
+class CompositionEngine;
+class Display;
+
+namespace impl {
+
+class DisplayColorProfile : public compositionengine::DisplayColorProfile {
+public:
+ DisplayColorProfile(DisplayColorProfileCreationArgs&&);
+ ~DisplayColorProfile() override;
+
+ bool isValid() const override;
+
+ bool hasRenderIntent(ui::RenderIntent intent) const override;
+ bool hasLegacyHdrSupport(ui::Dataspace dataspace) const override;
+ void getBestColorMode(ui::Dataspace dataspace, ui::RenderIntent intent,
+ ui::Dataspace* outDataspace, ui::ColorMode* outMode,
+ ui::RenderIntent* outIntent) const override;
+
+ bool hasWideColorGamut() const override;
+ int32_t getSupportedPerFrameMetadata() const override;
+
+ // Whether h/w composer has native support for specific HDR type.
+ bool hasHDR10PlusSupport() const override;
+ bool hasHDR10Support() const override;
+ bool hasHLGSupport() const override;
+ bool hasDolbyVisionSupport() const override;
+
+ const HdrCapabilities& getHdrCapabilities() const override;
+
+ void dump(std::string&) const override;
+
+private:
+ void populateColorModes(const DisplayColorProfileCreationArgs::HwcColorModes& hwcColorModes);
+ void addColorMode(const DisplayColorProfileCreationArgs::HwcColorModes& hwcColorModes,
+ const ui::ColorMode mode, const ui::RenderIntent intent);
+
+ // Mappings from desired Dataspace/RenderIntent to the supported
+ // Dataspace/ColorMode/RenderIntent.
+ using ColorModeKey = uint64_t;
+ struct ColorModeValue {
+ ui::Dataspace dataspace;
+ ui::ColorMode colorMode;
+ ui::RenderIntent renderIntent;
+ };
+
+ static ColorModeKey getColorModeKey(ui::Dataspace dataspace, ui::RenderIntent intent) {
+ return (static_cast<uint64_t>(dataspace) << 32) | static_cast<uint32_t>(intent);
+ }
+
+ // Need to know if display is wide-color capable or not.
+ // Initialized by SurfaceFlinger when the DisplayDevice is created.
+ // Fed to RenderEngine during composition.
+ bool mHasWideColorGamut{false};
+ int32_t mSupportedPerFrameMetadata{0};
+ bool mHasHdr10Plus{false};
+ bool mHasHdr10{false};
+ bool mHasHLG{false};
+ bool mHasDolbyVision{false};
+ HdrCapabilities mHdrCapabilities;
+ std::unordered_map<ColorModeKey, ColorModeValue> mColorModes;
+};
+
+std::unique_ptr<compositionengine::DisplayColorProfile> createDisplayColorProfile(
+ DisplayColorProfileCreationArgs&&);
+
+} // namespace impl
+} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/DumpHelpers.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/DumpHelpers.h
new file mode 100644
index 0000000..782c8d7
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/DumpHelpers.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 <cstdint>
+#include <string>
+#include <type_traits>
+
+#include <math/mat4.h>
+#include <ui/FloatRect.h>
+#include <ui/Rect.h>
+#include <ui/Region.h>
+#include <ui/Transform.h>
+
+namespace android::compositionengine::impl {
+
+void dumpVal(std::string& out, const char* name, bool);
+void dumpVal(std::string& out, const char* name, const void*);
+void dumpVal(std::string& out, const char* name, int);
+void dumpVal(std::string& out, const char* name, float);
+void dumpVal(std::string& out, const char* name, uint32_t);
+void dumpHex(std::string& out, const char* name, uint64_t);
+void dumpVal(std::string& out, const char* name, const char* value);
+void dumpVal(std::string& out, const char* name, const std::string& value);
+
+// For enums with named values
+void dumpVal(std::string& out, const char* name, const char*, int);
+void dumpVal(std::string& out, const char* name, const std::string&, int);
+
+template <typename EnumType>
+void dumpVal(std::string& out, const char* name, const char* valueName, EnumType value) {
+ dumpVal(out, name, valueName, static_cast<std::underlying_type_t<EnumType>>(value));
+}
+
+template <typename EnumType>
+void dumpVal(std::string& out, const char* name, const std::string& valueName, EnumType value) {
+ dumpVal(out, name, valueName, static_cast<std::underlying_type_t<EnumType>>(value));
+}
+
+void dumpVal(std::string& out, const char* name, const FloatRect& rect);
+void dumpVal(std::string& out, const char* name, const Rect& rect);
+void dumpVal(std::string& out, const char* name, const Region& region);
+void dumpVal(std::string& out, const char* name, const ui::Transform&);
+void dumpVal(std::string& out, const char* name, const ui::Size&);
+
+void dumpVal(std::string& out, const char* name, const mat4& tr);
+
+} // namespace android::compositionengine::impl
diff --git a/services/surfaceflinger/DisplayHardware/HWComposerBufferCache.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/HwcBufferCache.h
similarity index 79%
rename from services/surfaceflinger/DisplayHardware/HWComposerBufferCache.h
rename to services/surfaceflinger/CompositionEngine/include/compositionengine/impl/HwcBufferCache.h
index a008ca9..b45de5a 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposerBufferCache.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/HwcBufferCache.h
@@ -14,20 +14,19 @@
* limitations under the License.
*/
-#ifndef ANDROID_SF_HWCOMPOSERBUFFERCACHE_H
-#define ANDROID_SF_HWCOMPOSERBUFFERCACHE_H
+#pragma once
-#include <stdint.h>
+#include <cstdint>
+#include <vector>
#include <utils/StrongPointer.h>
-#include <vector>
-
namespace android {
-// ---------------------------------------------------------------------------
class GraphicBuffer;
+namespace compositionengine::impl {
+
// With HIDLized hwcomposer HAL, the HAL can maintain a buffer cache for each
// HWC display and layer. When updating a display target or a layer buffer,
// we have the option to send the buffer handle over or to request the HAL to
@@ -37,17 +36,17 @@
//
// To be able to find out whether a buffer is already in the HAL's cache, we
// use HWComposerBufferCache to mirror the cache in SF.
-class HWComposerBufferCache {
+class HwcBufferCache {
public:
- HWComposerBufferCache();
+ HwcBufferCache();
// Given a buffer queue slot and 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, sp<GraphicBuffer>* outBuffer);
+ void getHwcBuffer(int slot, const sp<GraphicBuffer>& buffer, uint32_t* outSlot,
+ sp<GraphicBuffer>* outBuffer);
private:
// a vector as we expect "slot" to be in the range of [0, 63] (that is,
@@ -55,7 +54,5 @@
std::vector<sp<GraphicBuffer>> mBuffers;
};
-// ---------------------------------------------------------------------------
-}; // namespace android
-
-#endif // ANDROID_SF_HWCOMPOSERBUFFERCACHE_H
+} // namespace compositionengine::impl
+} // namespace android
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Layer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Layer.h
new file mode 100644
index 0000000..631351b
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Layer.h
@@ -0,0 +1,52 @@
+/*
+ * 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 <memory>
+
+#include <compositionengine/Layer.h>
+#include <utils/RefBase.h>
+#include <utils/StrongPointer.h>
+
+namespace android::compositionengine {
+
+class CompositionEngine;
+class LayerFE;
+
+struct LayerCreationArgs;
+
+namespace impl {
+
+class Display;
+
+class Layer : public compositionengine::Layer {
+public:
+ Layer(const CompositionEngine&, compositionengine::LayerCreationArgs&&);
+ ~Layer() override;
+
+ sp<LayerFE> getLayerFE() const override;
+
+private:
+ const compositionengine::CompositionEngine& mCompositionEngine;
+ const wp<LayerFE> mLayerFE;
+};
+
+std::shared_ptr<compositionengine::Layer> createLayer(const compositionengine::CompositionEngine&,
+ compositionengine::LayerCreationArgs&&);
+
+} // namespace impl
+} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
new file mode 100644
index 0000000..d876c03
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <memory>
+#include <utility>
+#include <vector>
+
+#include <compositionengine/Output.h>
+#include <compositionengine/impl/OutputCompositionState.h>
+
+namespace android::compositionengine {
+
+class CompositionEngine;
+class Layer;
+class OutputLayer;
+
+namespace impl {
+
+class Output : public virtual compositionengine::Output {
+public:
+ Output(const CompositionEngine&);
+ ~Output() override;
+
+ bool isValid() const override;
+
+ void setCompositionEnabled(bool) override;
+ void setProjection(const ui::Transform&, int32_t orientation, const Rect& frame,
+ const Rect& viewport, const Rect& scissor, bool needsFiltering) override;
+ void setBounds(const ui::Size&) override;
+ void setLayerStackFilter(uint32_t layerStackId, bool isInternal) override;
+
+ void setColorTransform(const mat4&) override;
+ void setColorMode(ui::ColorMode, ui::Dataspace, ui::RenderIntent) override;
+
+ void dump(std::string&) const override;
+
+ const std::string& getName() const override;
+ void setName(const std::string&) override;
+
+ compositionengine::DisplayColorProfile* getDisplayColorProfile() const override;
+ void setDisplayColorProfile(std::unique_ptr<compositionengine::DisplayColorProfile>) override;
+
+ compositionengine::RenderSurface* getRenderSurface() const override;
+ void setRenderSurface(std::unique_ptr<compositionengine::RenderSurface>) override;
+
+ const OutputCompositionState& getState() const override;
+ OutputCompositionState& editState() override;
+
+ Region getPhysicalSpaceDirtyRegion(bool repaintEverything) const override;
+ bool belongsInOutput(uint32_t, bool) const override;
+
+ compositionengine::OutputLayer* getOutputLayerForLayer(
+ compositionengine::Layer*) const override;
+ std::unique_ptr<compositionengine::OutputLayer> getOrCreateOutputLayer(
+ std::shared_ptr<compositionengine::Layer>, sp<LayerFE>) override;
+ void setOutputLayersOrderedByZ(OutputLayers&&) override;
+ const OutputLayers& getOutputLayersOrderedByZ() const override;
+
+ // Testing
+ void setDisplayColorProfileForTest(std::unique_ptr<compositionengine::DisplayColorProfile>);
+ void setRenderSurfaceForTest(std::unique_ptr<compositionengine::RenderSurface>);
+
+protected:
+ const CompositionEngine& getCompositionEngine() const;
+ void dumpBase(std::string&) const;
+
+private:
+ void dirtyEntireOutput();
+
+ const CompositionEngine& mCompositionEngine;
+
+ std::string mName;
+
+ OutputCompositionState mState;
+
+ std::unique_ptr<compositionengine::DisplayColorProfile> mDisplayColorProfile;
+ std::unique_ptr<compositionengine::RenderSurface> mRenderSurface;
+
+ OutputLayers mOutputLayersOrderedByZ;
+};
+
+} // namespace impl
+} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
new file mode 100644
index 0000000..024ed45
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
@@ -0,0 +1,95 @@
+/*
+ * 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 <cstdint>
+
+#include <ui/GraphicTypes.h>
+#include <ui/Rect.h>
+#include <ui/Region.h>
+#include <ui/Transform.h>
+
+namespace android {
+
+namespace compositionengine::impl {
+
+struct OutputCompositionState {
+ // If false, composition will not per performed for this display
+ bool isEnabled{false};
+
+ // If false, this output is not considered secure
+ bool isSecure{false};
+
+ // If true, this output displays layers that are internal-only
+ bool layerStackInternal{false};
+
+ // The layer stack to display on this display
+ uint32_t layerStackId{~0u};
+
+ // The physical space screen bounds
+ Rect bounds;
+
+ // The logical to physical transformation to use
+ ui::Transform transform;
+
+ // The physical orientation of the display, expressed as ui::Transform
+ // orientation flags.
+ uint32_t orientation{0};
+
+ // The logical space user visible bounds
+ Rect frame;
+
+ // The logical space user viewport rectangle
+ Rect viewport;
+
+ // The physical space scissor rectangle
+ Rect scissor;
+
+ // If true, RenderEngine filtering should be enabled
+ bool needsFiltering{false};
+
+ // The logical coordinates for the dirty region for the display.
+ // dirtyRegion is semi-persistent state. Dirty rectangles are added to it
+ // by the FE until composition happens, at which point it is cleared.
+ Region dirtyRegion;
+
+ // The logical coordinates for the undefined region for the display.
+ // The undefined region is internal to the composition engine. It is
+ // updated every time the geometry changes.
+ Region undefinedRegion;
+
+ // True if the last composition frame had visible layers
+ bool lastCompositionHadVisibleLayers{false};
+
+ // The color transform to apply
+ android_color_transform_t colorTransform{HAL_COLOR_TRANSFORM_IDENTITY};
+
+ // Current active color mode
+ ui::ColorMode colorMode{ui::ColorMode::NATIVE};
+
+ // Current active render intent
+ ui::RenderIntent renderIntent{ui::RenderIntent::COLORIMETRIC};
+
+ // Current active dstaspace
+ ui::Dataspace dataspace{ui::Dataspace::UNKNOWN};
+
+ // Debugging
+ void dump(std::string& result) const;
+};
+
+} // namespace compositionengine::impl
+} // namespace android
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h
new file mode 100644
index 0000000..f3d0258
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h
@@ -0,0 +1,45 @@
+/*
+ * 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 <memory>
+
+#include <compositionengine/OutputLayer.h>
+
+namespace android::compositionengine::impl {
+
+class OutputLayer : public compositionengine::OutputLayer {
+public:
+ OutputLayer(const compositionengine::Output&, std::shared_ptr<compositionengine::Layer>,
+ sp<compositionengine::LayerFE>);
+ ~OutputLayer() override;
+
+ const compositionengine::Output& getOutput() const override;
+ compositionengine::Layer& getLayer() const override;
+ compositionengine::LayerFE& getLayerFE() const override;
+
+private:
+ const compositionengine::Output& mOutput;
+ std::shared_ptr<compositionengine::Layer> mLayer;
+ sp<compositionengine::LayerFE> mLayerFE;
+};
+
+std::unique_ptr<compositionengine::OutputLayer> createOutputLayer(
+ const compositionengine::Output&, std::shared_ptr<compositionengine::Layer>,
+ sp<compositionengine::LayerFE>);
+
+} // namespace android::compositionengine::impl
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h
new file mode 100644
index 0000000..0489310
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h
@@ -0,0 +1,94 @@
+/*
+ * 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 <memory>
+
+#include <android-base/unique_fd.h>
+#include <compositionengine/RenderSurface.h>
+#include <utils/StrongPointer.h>
+
+struct ANativeWindow;
+
+namespace android {
+
+namespace compositionengine {
+
+class CompositionEngine;
+class Display;
+class DisplaySurface;
+
+struct RenderSurfaceCreationArgs;
+
+namespace impl {
+
+class RenderSurface : public compositionengine::RenderSurface {
+public:
+ RenderSurface(const CompositionEngine&, compositionengine::Display&,
+ compositionengine::RenderSurfaceCreationArgs&&);
+ ~RenderSurface() override;
+
+ bool isValid() const override;
+ void initialize() override;
+ const ui::Size& getSize() const override;
+
+ const sp<Fence>& getClientTargetAcquireFence() const override;
+ void setBufferDataspace(ui::Dataspace) override;
+ void setDisplaySize(const ui::Size&) override;
+ void setProtected(bool useProtected) override;
+ status_t beginFrame(bool mustRecompose) override;
+ status_t prepareFrame(std::vector<CompositionInfo>& compositionData) override;
+ sp<GraphicBuffer> dequeueBuffer() override;
+ void queueBuffer() override;
+ void onPresentDisplayCompleted() override;
+ void finishBuffer() override;
+ void setViewportAndProjection() override;
+ void flip() override;
+
+ // Debugging
+ void dump(std::string& result) const override;
+ std::uint32_t getPageFlipCount() const override;
+
+ // Testing
+ void setPageFlipCountForTest(std::uint32_t);
+ void setSizeForTest(const ui::Size&);
+ sp<GraphicBuffer>& mutableGraphicBufferForTest();
+ base::unique_fd& mutableBufferReadyForTest();
+
+private:
+ const compositionengine::CompositionEngine& mCompositionEngine;
+ const compositionengine::Display& mDisplay;
+
+ // ANativeWindow being rendered into
+ const sp<ANativeWindow> mNativeWindow;
+ // Current buffer being rendered into
+ sp<GraphicBuffer> mGraphicBuffer;
+ // File descriptor indicating that mGraphicBuffer is ready for display, i.e.
+ // that drawing to the buffer is now complete.
+ base::unique_fd mBufferReady;
+ const sp<DisplaySurface> mDisplaySurface;
+ ui::Size mSize;
+ std::uint32_t mPageFlipCount{0};
+};
+
+std::unique_ptr<compositionengine::RenderSurface> createRenderSurface(
+ const compositionengine::CompositionEngine&, compositionengine::Display&,
+ compositionengine::RenderSurfaceCreationArgs&&);
+
+} // namespace impl
+} // namespace compositionengine
+} // namespace android
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/CompositionEngine.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/CompositionEngine.h
new file mode 100644
index 0000000..0f57685
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/CompositionEngine.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <compositionengine/CompositionEngine.h>
+#include <compositionengine/DisplayCreationArgs.h>
+#include <compositionengine/LayerCreationArgs.h>
+#include <gmock/gmock.h>
+#include <renderengine/RenderEngine.h>
+
+#include "DisplayHardware/HWComposer.h"
+
+namespace android::compositionengine::mock {
+
+class CompositionEngine : public compositionengine::CompositionEngine {
+public:
+ CompositionEngine();
+ ~CompositionEngine() override;
+
+ MOCK_METHOD1(createDisplay, std::shared_ptr<Display>(DisplayCreationArgs&&));
+ MOCK_METHOD1(createLayer, std::shared_ptr<Layer>(LayerCreationArgs&&));
+
+ MOCK_CONST_METHOD0(getHwComposer, HWComposer&());
+ MOCK_METHOD1(setHwComposer, void(std::unique_ptr<HWComposer>));
+
+ MOCK_CONST_METHOD0(getRenderEngine, renderengine::RenderEngine&());
+ MOCK_METHOD1(setRenderEngine, void(std::unique_ptr<renderengine::RenderEngine>));
+};
+
+} // namespace android::compositionengine::mock
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Display.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Display.h
new file mode 100644
index 0000000..d763aa6
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Display.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <compositionengine/Display.h>
+#include <compositionengine/DisplayColorProfileCreationArgs.h>
+#include <compositionengine/RenderSurfaceCreationArgs.h>
+#include <compositionengine/mock/Output.h>
+#include <gmock/gmock.h>
+#include <system/window.h>
+
+#include "DisplayHardware/DisplayIdentification.h"
+
+namespace android::compositionengine::mock {
+
+class Display : public compositionengine::mock::Output, public compositionengine::Display {
+public:
+ Display();
+ virtual ~Display();
+
+ MOCK_CONST_METHOD0(getId, const std::optional<DisplayId>&());
+ MOCK_CONST_METHOD0(isSecure, bool());
+ MOCK_CONST_METHOD0(isVirtual, bool());
+
+ MOCK_METHOD0(disconnect, void());
+
+ MOCK_METHOD1(createDisplayColorProfile, void(DisplayColorProfileCreationArgs&&));
+ MOCK_METHOD1(createRenderSurface, void(RenderSurfaceCreationArgs&&));
+};
+
+} // namespace android::compositionengine::mock
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/DisplayColorProfile.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/DisplayColorProfile.h
new file mode 100644
index 0000000..8056c9d
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/DisplayColorProfile.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <compositionengine/DisplayColorProfile.h>
+#include <gmock/gmock.h>
+#include <ui/HdrCapabilities.h>
+
+namespace android::compositionengine::mock {
+
+class DisplayColorProfile : public compositionengine::DisplayColorProfile {
+public:
+ DisplayColorProfile();
+ ~DisplayColorProfile() override;
+
+ MOCK_CONST_METHOD0(isValid, bool());
+
+ MOCK_CONST_METHOD1(hasRenderIntent, bool(ui::RenderIntent));
+ MOCK_CONST_METHOD1(hasLegacyHdrSupport, bool(ui::Dataspace));
+ MOCK_CONST_METHOD5(getBestColorMode,
+ void(ui::Dataspace, ui::RenderIntent, ui::Dataspace*, ui::ColorMode*,
+ ui::RenderIntent*));
+ MOCK_CONST_METHOD0(hasWideColorGamut, bool());
+ MOCK_CONST_METHOD0(getSupportedPerFrameMetadata, int32_t());
+ MOCK_CONST_METHOD0(hasHDR10PlusSupport, bool());
+ MOCK_CONST_METHOD0(hasHDR10Support, bool());
+ MOCK_CONST_METHOD0(hasHLGSupport, bool());
+ MOCK_CONST_METHOD0(hasDolbyVisionSupport, bool());
+
+ MOCK_CONST_METHOD0(getHdrCapabilities, const HdrCapabilities&());
+
+ MOCK_CONST_METHOD1(dump, void(std::string&));
+};
+
+} // namespace android::compositionengine::mock
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplaySurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/DisplaySurface.h
similarity index 81%
rename from services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplaySurface.h
rename to services/surfaceflinger/CompositionEngine/include/compositionengine/mock/DisplaySurface.h
index d6c9aa4..31b5f95 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplaySurface.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/DisplaySurface.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018 The Android Open Source Project
+ * 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.
@@ -16,16 +16,13 @@
#pragma once
+#include <compositionengine/DisplaySurface.h>
#include <gmock/gmock.h>
-
#include <utils/String8.h>
-#include "DisplayHardware/DisplaySurface.h"
+namespace android::compositionengine::mock {
-namespace android {
-namespace mock {
-
-class DisplaySurface : public android::DisplaySurface {
+class DisplaySurface : public compositionengine::DisplaySurface {
public:
DisplaySurface();
~DisplaySurface() override;
@@ -39,5 +36,4 @@
MOCK_CONST_METHOD0(getClientTargetAcquireFence, const sp<Fence>&());
};
-} // namespace mock
-} // namespace android
+} // namespace android::compositionengine::mock
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Layer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Layer.h
new file mode 100644
index 0000000..a7cc08e
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Layer.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <compositionengine/Layer.h>
+#include <compositionengine/LayerFE.h>
+#include <gmock/gmock.h>
+
+namespace android::compositionengine::mock {
+
+class Layer : public compositionengine::Layer {
+public:
+ Layer();
+ virtual ~Layer();
+
+ MOCK_CONST_METHOD0(getLayerFE, sp<LayerFE>());
+};
+
+} // namespace android::compositionengine::mock
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h
new file mode 100644
index 0000000..92e0070
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <compositionengine/LayerFE.h>
+#include <gmock/gmock.h>
+
+namespace android::compositionengine::mock {
+
+// Defines the interface used by the CompositionEngine to make requests
+// of the front-end layer.
+class LayerFE : public compositionengine::LayerFE {
+public:
+ LayerFE();
+ virtual ~LayerFE();
+};
+
+} // namespace android::compositionengine::mock
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
new file mode 100644
index 0000000..e79a44c
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <compositionengine/DisplayColorProfile.h>
+#include <compositionengine/Layer.h>
+#include <compositionengine/LayerFE.h>
+#include <compositionengine/Output.h>
+#include <compositionengine/OutputLayer.h>
+#include <compositionengine/RenderSurface.h>
+#include <compositionengine/impl/OutputCompositionState.h>
+#include <gmock/gmock.h>
+
+namespace android::compositionengine::mock {
+
+class Output : public virtual compositionengine::Output {
+public:
+ Output();
+ virtual ~Output();
+
+ MOCK_CONST_METHOD0(isValid, bool());
+
+ MOCK_METHOD1(setCompositionEnabled, void(bool));
+ MOCK_METHOD6(setProjection,
+ void(const ui::Transform&, int32_t, const Rect&, const Rect&, const Rect&, bool));
+ MOCK_METHOD1(setBounds, void(const ui::Size&));
+ MOCK_METHOD2(setLayerStackFilter, void(uint32_t, bool));
+
+ MOCK_METHOD1(setColorTransform, void(const mat4&));
+ MOCK_METHOD3(setColorMode, void(ui::ColorMode, ui::Dataspace, ui::RenderIntent));
+
+ MOCK_CONST_METHOD1(dump, void(std::string&));
+ MOCK_CONST_METHOD0(getName, const std::string&());
+ MOCK_METHOD1(setName, void(const std::string&));
+
+ MOCK_CONST_METHOD0(getDisplayColorProfile, DisplayColorProfile*());
+ MOCK_METHOD1(setDisplayColorProfile, void(std::unique_ptr<DisplayColorProfile>));
+
+ MOCK_CONST_METHOD0(getRenderSurface, RenderSurface*());
+ MOCK_METHOD1(setRenderSurface, void(std::unique_ptr<RenderSurface>));
+
+ MOCK_CONST_METHOD0(getState, const OutputCompositionState&());
+ MOCK_METHOD0(editState, OutputCompositionState&());
+
+ MOCK_CONST_METHOD1(getPhysicalSpaceDirtyRegion, Region(bool));
+ MOCK_CONST_METHOD2(belongsInOutput, bool(uint32_t, bool));
+
+ MOCK_CONST_METHOD1(getOutputLayerForLayer,
+ compositionengine::OutputLayer*(compositionengine::Layer*));
+ MOCK_METHOD2(getOrCreateOutputLayer,
+ std::unique_ptr<compositionengine::OutputLayer>(
+ std::shared_ptr<compositionengine::Layer>,
+ sp<compositionengine::LayerFE>));
+ MOCK_METHOD1(setOutputLayersOrderedByZ, void(OutputLayers&&));
+ MOCK_CONST_METHOD0(getOutputLayersOrderedByZ, OutputLayers&());
+};
+
+} // namespace android::compositionengine::mock
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h
new file mode 100644
index 0000000..f5e5026
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <compositionengine/Layer.h>
+#include <compositionengine/LayerFE.h>
+#include <compositionengine/Output.h>
+#include <compositionengine/OutputLayer.h>
+#include <gmock/gmock.h>
+
+namespace android::compositionengine::mock {
+
+class OutputLayer : public compositionengine::OutputLayer {
+public:
+ OutputLayer();
+ virtual ~OutputLayer();
+
+ MOCK_CONST_METHOD0(getOutput, const compositionengine::Output&());
+ MOCK_CONST_METHOD0(getLayer, compositionengine::Layer&());
+ MOCK_CONST_METHOD0(getLayerFE, compositionengine::LayerFE&());
+};
+
+} // namespace android::compositionengine::mock
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h
new file mode 100644
index 0000000..2269e57
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <compositionengine/RenderSurface.h>
+#include <gmock/gmock.h>
+#include <ui/GraphicBuffer.h>
+
+#include "LayerBE.h"
+
+namespace android::compositionengine::mock {
+
+class RenderSurface : public compositionengine::RenderSurface {
+public:
+ RenderSurface();
+ ~RenderSurface() override;
+
+ MOCK_CONST_METHOD0(isValid, bool());
+ MOCK_METHOD0(initialize, void());
+ MOCK_CONST_METHOD0(getSize, const ui::Size&());
+ MOCK_CONST_METHOD0(getClientTargetAcquireFence, const sp<Fence>&());
+ MOCK_METHOD1(setDisplaySize, void(const ui::Size&));
+ MOCK_METHOD1(setProtected, void(bool));
+ MOCK_METHOD1(setBufferDataspace, void(ui::Dataspace));
+ MOCK_METHOD1(beginFrame, status_t(bool mustRecompose));
+ MOCK_METHOD1(prepareFrame, status_t(std::vector<CompositionInfo>& compositionData));
+ MOCK_METHOD0(dequeueBuffer, sp<GraphicBuffer>());
+ MOCK_METHOD0(queueBuffer, void());
+ MOCK_METHOD0(onPresentDisplayCompleted, void());
+ MOCK_METHOD0(finishBuffer, void());
+ MOCK_METHOD0(setViewportAndProjection, void());
+ MOCK_METHOD0(flip, void());
+ MOCK_CONST_METHOD1(dump, void(std::string& result));
+ MOCK_CONST_METHOD0(getPageFlipCount, std::uint32_t());
+};
+
+} // namespace android::compositionengine::mock
diff --git a/services/surfaceflinger/CompositionEngine/mock/CompositionEngine.cpp b/services/surfaceflinger/CompositionEngine/mock/CompositionEngine.cpp
new file mode 100644
index 0000000..778a09e
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/mock/CompositionEngine.cpp
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <compositionengine/mock/CompositionEngine.h>
+
+namespace android::compositionengine::mock {
+
+// The Google Mock documentation recommends explicit non-header instantiations
+// for better compile time performance.
+CompositionEngine::CompositionEngine() = default;
+CompositionEngine::~CompositionEngine() = default;
+
+} // namespace android::compositionengine::mock
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplaySurface.cpp b/services/surfaceflinger/CompositionEngine/mock/Display.cpp
similarity index 60%
copy from services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplaySurface.cpp
copy to services/surfaceflinger/CompositionEngine/mock/Display.cpp
index e6ac6bf..01cf112 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplaySurface.cpp
+++ b/services/surfaceflinger/CompositionEngine/mock/Display.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018 The Android Open Source Project
+ * 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.
@@ -14,14 +14,13 @@
* limitations under the License.
*/
-#include "mock/DisplayHardware/MockDisplaySurface.h"
+#include <compositionengine/mock/Display.h>
-namespace android {
-namespace mock {
+namespace android::compositionengine::mock {
-// Explicit default instantiation is recommended.
-DisplaySurface::DisplaySurface() = default;
-DisplaySurface::~DisplaySurface() = default;
+// The Google Mock documentation recommends explicit non-header instantiations
+// for better compile time performance.
+Display::Display() = default;
+Display::~Display() = default;
-} // namespace mock
-} // namespace android
+} // namespace android::compositionengine::mock
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplaySurface.cpp b/services/surfaceflinger/CompositionEngine/mock/DisplayColorProfile.cpp
similarity index 66%
copy from services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplaySurface.cpp
copy to services/surfaceflinger/CompositionEngine/mock/DisplayColorProfile.cpp
index e6ac6bf..581d1f7 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplaySurface.cpp
+++ b/services/surfaceflinger/CompositionEngine/mock/DisplayColorProfile.cpp
@@ -1,6 +1,6 @@
/*
- * Copyright (C) 2018 The Android Open Source Project
- *
+ * 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
@@ -14,14 +14,12 @@
* limitations under the License.
*/
-#include "mock/DisplayHardware/MockDisplaySurface.h"
+#include <compositionengine/mock/DisplayColorProfile.h>
-namespace android {
-namespace mock {
+namespace android::compositionengine::mock {
// Explicit default instantiation is recommended.
-DisplaySurface::DisplaySurface() = default;
-DisplaySurface::~DisplaySurface() = default;
+DisplayColorProfile::DisplayColorProfile() = default;
+DisplayColorProfile::~DisplayColorProfile() = default;
-} // namespace mock
-} // namespace android
+} // namespace android::compositionengine::mock
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplaySurface.cpp b/services/surfaceflinger/CompositionEngine/mock/DisplaySurface.cpp
similarity index 67%
copy from services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplaySurface.cpp
copy to services/surfaceflinger/CompositionEngine/mock/DisplaySurface.cpp
index e6ac6bf..bbbd7c1 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplaySurface.cpp
+++ b/services/surfaceflinger/CompositionEngine/mock/DisplaySurface.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018 The Android Open Source Project
+ * 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.
@@ -14,14 +14,13 @@
* limitations under the License.
*/
-#include "mock/DisplayHardware/MockDisplaySurface.h"
+#include "compositionengine/mock/DisplaySurface.h"
-namespace android {
-namespace mock {
+namespace android::compositionengine::mock {
-// Explicit default instantiation is recommended.
+// The Google Mock documentation recommends explicit non-header instantiations
+// for better compile time performance.
DisplaySurface::DisplaySurface() = default;
DisplaySurface::~DisplaySurface() = default;
-} // namespace mock
-} // namespace android
+} // namespace android::compositionengine::mock
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplaySurface.cpp b/services/surfaceflinger/CompositionEngine/mock/Layer.cpp
similarity index 61%
copy from services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplaySurface.cpp
copy to services/surfaceflinger/CompositionEngine/mock/Layer.cpp
index e6ac6bf..08483cb 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplaySurface.cpp
+++ b/services/surfaceflinger/CompositionEngine/mock/Layer.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018 The Android Open Source Project
+ * 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.
@@ -14,14 +14,13 @@
* limitations under the License.
*/
-#include "mock/DisplayHardware/MockDisplaySurface.h"
+#include <compositionengine/mock/Layer.h>
-namespace android {
-namespace mock {
+namespace android::compositionengine::mock {
-// Explicit default instantiation is recommended.
-DisplaySurface::DisplaySurface() = default;
-DisplaySurface::~DisplaySurface() = default;
+// The Google Mock documentation recommends explicit non-header instantiations
+// for better compile time performance.
+Layer::Layer() = default;
+Layer::~Layer() = default;
-} // namespace mock
-} // namespace android
+} // namespace android::compositionengine::mock
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplaySurface.cpp b/services/surfaceflinger/CompositionEngine/mock/LayerFE.cpp
similarity index 60%
copy from services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplaySurface.cpp
copy to services/surfaceflinger/CompositionEngine/mock/LayerFE.cpp
index e6ac6bf..607eaad 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplaySurface.cpp
+++ b/services/surfaceflinger/CompositionEngine/mock/LayerFE.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018 The Android Open Source Project
+ * 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.
@@ -14,14 +14,13 @@
* limitations under the License.
*/
-#include "mock/DisplayHardware/MockDisplaySurface.h"
+#include <compositionengine/mock/LayerFE.h>
-namespace android {
-namespace mock {
+namespace android::compositionengine::mock {
-// Explicit default instantiation is recommended.
-DisplaySurface::DisplaySurface() = default;
-DisplaySurface::~DisplaySurface() = default;
+// The Google Mock documentation recommends explicit non-header instantiations
+// for better compile time performance.
+LayerFE::LayerFE() = default;
+LayerFE::~LayerFE() = default;
-} // namespace mock
-} // namespace android
+} // namespace android::compositionengine::mock
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplaySurface.cpp b/services/surfaceflinger/CompositionEngine/mock/Output.cpp
similarity index 60%
copy from services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplaySurface.cpp
copy to services/surfaceflinger/CompositionEngine/mock/Output.cpp
index e6ac6bf..44df4c3 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplaySurface.cpp
+++ b/services/surfaceflinger/CompositionEngine/mock/Output.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018 The Android Open Source Project
+ * 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.
@@ -14,14 +14,13 @@
* limitations under the License.
*/
-#include "mock/DisplayHardware/MockDisplaySurface.h"
+#include <compositionengine/mock/Output.h>
-namespace android {
-namespace mock {
+namespace android::compositionengine::mock {
-// Explicit default instantiation is recommended.
-DisplaySurface::DisplaySurface() = default;
-DisplaySurface::~DisplaySurface() = default;
+// The Google Mock documentation recommends explicit non-header instantiations
+// for better compile time performance.
+Output::Output() = default;
+Output::~Output() = default;
-} // namespace mock
-} // namespace android
+} // namespace android::compositionengine::mock
diff --git a/services/surfaceflinger/CompositionEngine/mock/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/mock/OutputLayer.cpp
new file mode 100644
index 0000000..4da9377
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/mock/OutputLayer.cpp
@@ -0,0 +1,26 @@
+/*
+ * 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 <compositionengine/mock/OutputLayer.h>
+
+namespace android::compositionengine::mock {
+
+// The Google Mock documentation recommends explicit non-header instantiations
+// for better compile time performance.
+OutputLayer::OutputLayer() = default;
+OutputLayer::~OutputLayer() = default;
+
+} // namespace android::compositionengine::mock
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplaySurface.cpp b/services/surfaceflinger/CompositionEngine/mock/RenderSurface.cpp
similarity index 68%
copy from services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplaySurface.cpp
copy to services/surfaceflinger/CompositionEngine/mock/RenderSurface.cpp
index e6ac6bf..fe718d6 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplaySurface.cpp
+++ b/services/surfaceflinger/CompositionEngine/mock/RenderSurface.cpp
@@ -1,6 +1,6 @@
/*
- * Copyright (C) 2018 The Android Open Source Project
- *
+ * 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
@@ -14,14 +14,12 @@
* limitations under the License.
*/
-#include "mock/DisplayHardware/MockDisplaySurface.h"
+#include <compositionengine/mock/RenderSurface.h>
-namespace android {
-namespace mock {
+namespace android::compositionengine::mock {
// Explicit default instantiation is recommended.
-DisplaySurface::DisplaySurface() = default;
-DisplaySurface::~DisplaySurface() = default;
+RenderSurface::RenderSurface() = default;
+RenderSurface::~RenderSurface() = default;
-} // namespace mock
-} // namespace android
+} // namespace android::compositionengine::mock
diff --git a/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp b/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp
new file mode 100644
index 0000000..cb08b81
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <compositionengine/impl/CompositionEngine.h>
+#include <compositionengine/impl/Display.h>
+#include <compositionengine/impl/Layer.h>
+#include <renderengine/RenderEngine.h>
+
+#include "DisplayHardware/HWComposer.h"
+
+namespace android::compositionengine {
+
+CompositionEngine::~CompositionEngine() = default;
+
+namespace impl {
+
+std::unique_ptr<compositionengine::CompositionEngine> createCompositionEngine() {
+ return std::make_unique<CompositionEngine>();
+}
+
+CompositionEngine::CompositionEngine() = default;
+CompositionEngine::~CompositionEngine() = default;
+
+std::shared_ptr<compositionengine::Display> CompositionEngine::createDisplay(
+ DisplayCreationArgs&& args) {
+ return compositionengine::impl::createDisplay(*this, std::move(args));
+}
+
+std::shared_ptr<compositionengine::Layer> CompositionEngine::createLayer(LayerCreationArgs&& args) {
+ return compositionengine::impl::createLayer(*this, std::move(args));
+}
+
+HWComposer& CompositionEngine::getHwComposer() const {
+ return *mHwComposer.get();
+}
+
+void CompositionEngine::setHwComposer(std::unique_ptr<HWComposer> hwComposer) {
+ mHwComposer = std::move(hwComposer);
+}
+
+renderengine::RenderEngine& CompositionEngine::getRenderEngine() const {
+ return *mRenderEngine.get();
+}
+
+void CompositionEngine::setRenderEngine(std::unique_ptr<renderengine::RenderEngine> renderEngine) {
+ mRenderEngine = std::move(renderEngine);
+}
+
+} // namespace impl
+} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/src/Display.cpp b/services/surfaceflinger/CompositionEngine/src/Display.cpp
new file mode 100644
index 0000000..f9d70e3
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/src/Display.cpp
@@ -0,0 +1,122 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/stringprintf.h>
+#include <compositionengine/CompositionEngine.h>
+#include <compositionengine/DisplayCreationArgs.h>
+#include <compositionengine/DisplaySurface.h>
+#include <compositionengine/impl/Display.h>
+#include <compositionengine/impl/DisplayColorProfile.h>
+#include <compositionengine/impl/DumpHelpers.h>
+#include <compositionengine/impl/RenderSurface.h>
+
+#include "DisplayHardware/HWComposer.h"
+
+namespace android::compositionengine::impl {
+
+std::shared_ptr<compositionengine::Display> createDisplay(
+ const compositionengine::CompositionEngine& compositionEngine,
+ compositionengine::DisplayCreationArgs&& args) {
+ return std::make_shared<Display>(compositionEngine, std::move(args));
+}
+
+Display::Display(const CompositionEngine& compositionEngine, DisplayCreationArgs&& args)
+ : compositionengine::impl::Output(compositionEngine),
+ mIsVirtual(args.isVirtual),
+ mId(args.displayId) {
+ editState().isSecure = args.isSecure;
+}
+
+Display::~Display() = default;
+
+const std::optional<DisplayId>& Display::getId() const {
+ return mId;
+}
+
+bool Display::isSecure() const {
+ return getState().isSecure;
+}
+
+bool Display::isVirtual() const {
+ return mIsVirtual;
+}
+
+void Display::disconnect() {
+ if (!mId) {
+ return;
+ }
+
+ auto& hwc = getCompositionEngine().getHwComposer();
+ hwc.disconnectDisplay(*mId);
+ mId.reset();
+}
+
+void Display::setColorTransform(const mat4& transform) {
+ Output::setColorTransform(transform);
+
+ auto& hwc = getCompositionEngine().getHwComposer();
+ status_t result = hwc.setColorTransform(*mId, transform);
+ ALOGE_IF(result != NO_ERROR, "Failed to set color transform on display \"%s\": %d",
+ mId ? to_string(*mId).c_str() : "", result);
+}
+
+void Display::setColorMode(ui::ColorMode mode, ui::Dataspace dataspace,
+ ui::RenderIntent renderIntent) {
+ if (mode == getState().colorMode && dataspace == getState().dataspace &&
+ renderIntent == getState().renderIntent) {
+ return;
+ }
+
+ if (mIsVirtual) {
+ ALOGW("%s: Invalid operation on virtual display", __FUNCTION__);
+ return;
+ }
+
+ Output::setColorMode(mode, dataspace, renderIntent);
+
+ auto& hwc = getCompositionEngine().getHwComposer();
+ hwc.setActiveColorMode(*mId, mode, renderIntent);
+}
+
+void Display::dump(std::string& out) const {
+ using android::base::StringAppendF;
+
+ StringAppendF(&out, " Composition Display State: [\"%s\"]", getName().c_str());
+
+ out.append("\n ");
+
+ dumpVal(out, "isVirtual", mIsVirtual);
+ if (mId) {
+ dumpVal(out, "hwcId", to_string(*mId));
+ } else {
+ StringAppendF(&out, "no hwcId, ");
+ }
+
+ out.append("\n");
+
+ Output::dumpBase(out);
+}
+
+void Display::createDisplayColorProfile(DisplayColorProfileCreationArgs&& args) {
+ setDisplayColorProfile(compositionengine::impl::createDisplayColorProfile(std::move(args)));
+}
+
+void Display::createRenderSurface(RenderSurfaceCreationArgs&& args) {
+ setRenderSurface(compositionengine::impl::createRenderSurface(getCompositionEngine(), *this,
+ std::move(args)));
+}
+
+} // namespace android::compositionengine::impl
diff --git a/services/surfaceflinger/CompositionEngine/src/DisplayColorProfile.cpp b/services/surfaceflinger/CompositionEngine/src/DisplayColorProfile.cpp
new file mode 100644
index 0000000..6e6f3c0
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/src/DisplayColorProfile.cpp
@@ -0,0 +1,395 @@
+/*
+ * 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 <array>
+#include <unordered_set>
+
+#include <compositionengine/CompositionEngine.h>
+#include <compositionengine/Display.h>
+#include <compositionengine/DisplayColorProfileCreationArgs.h>
+#include <compositionengine/RenderSurface.h>
+#include <compositionengine/impl/DisplayColorProfile.h>
+#include <compositionengine/impl/DumpHelpers.h>
+#include <log/log.h>
+#include <ui/DebugUtils.h>
+
+#include "DisplayHardware/HWComposer.h"
+
+namespace android::compositionengine {
+
+DisplayColorProfile::~DisplayColorProfile() = default;
+
+namespace impl {
+namespace {
+
+using ui::ColorMode;
+using ui::Dataspace;
+using ui::RenderIntent;
+
+// ordered list of known SDR color modes
+const std::array<ColorMode, 3> sSdrColorModes = {
+ ColorMode::DISPLAY_BT2020,
+ ColorMode::DISPLAY_P3,
+ ColorMode::SRGB,
+};
+
+// ordered list of known HDR color modes
+const std::array<ColorMode, 2> sHdrColorModes = {
+ ColorMode::BT2100_PQ,
+ ColorMode::BT2100_HLG,
+};
+
+// ordered list of known SDR render intents
+const std::array<RenderIntent, 2> sSdrRenderIntents = {
+ RenderIntent::ENHANCE,
+ RenderIntent::COLORIMETRIC,
+};
+
+// ordered list of known HDR render intents
+const std::array<RenderIntent, 2> sHdrRenderIntents = {
+ RenderIntent::TONE_MAP_ENHANCE,
+ RenderIntent::TONE_MAP_COLORIMETRIC,
+};
+
+// map known color mode to dataspace
+Dataspace colorModeToDataspace(ColorMode mode) {
+ switch (mode) {
+ case ColorMode::SRGB:
+ return Dataspace::V0_SRGB;
+ case ColorMode::DISPLAY_P3:
+ return Dataspace::DISPLAY_P3;
+ case ColorMode::DISPLAY_BT2020:
+ return Dataspace::DISPLAY_BT2020;
+ case ColorMode::BT2100_HLG:
+ return Dataspace::BT2020_HLG;
+ case ColorMode::BT2100_PQ:
+ return Dataspace::BT2020_PQ;
+ default:
+ return Dataspace::UNKNOWN;
+ }
+}
+
+// Return a list of candidate color modes.
+std::vector<ColorMode> getColorModeCandidates(ColorMode mode) {
+ std::vector<ColorMode> candidates;
+
+ // add mode itself
+ candidates.push_back(mode);
+
+ // check if mode is HDR
+ bool isHdr = false;
+ for (auto hdrMode : sHdrColorModes) {
+ if (hdrMode == mode) {
+ isHdr = true;
+ break;
+ }
+ }
+
+ // add other HDR candidates when mode is HDR
+ if (isHdr) {
+ for (auto hdrMode : sHdrColorModes) {
+ if (hdrMode != mode) {
+ candidates.push_back(hdrMode);
+ }
+ }
+ }
+
+ // add other SDR candidates
+ for (auto sdrMode : sSdrColorModes) {
+ if (sdrMode != mode) {
+ candidates.push_back(sdrMode);
+ }
+ }
+
+ return candidates;
+}
+
+// Return a list of candidate render intents.
+std::vector<RenderIntent> getRenderIntentCandidates(RenderIntent intent) {
+ std::vector<RenderIntent> candidates;
+
+ // add intent itself
+ candidates.push_back(intent);
+
+ // check if intent is HDR
+ bool isHdr = false;
+ for (auto hdrIntent : sHdrRenderIntents) {
+ if (hdrIntent == intent) {
+ isHdr = true;
+ break;
+ }
+ }
+
+ if (isHdr) {
+ // add other HDR candidates when intent is HDR
+ for (auto hdrIntent : sHdrRenderIntents) {
+ if (hdrIntent != intent) {
+ candidates.push_back(hdrIntent);
+ }
+ }
+ } else {
+ // add other SDR candidates when intent is SDR
+ for (auto sdrIntent : sSdrRenderIntents) {
+ if (sdrIntent != intent) {
+ candidates.push_back(sdrIntent);
+ }
+ }
+ }
+
+ return candidates;
+}
+
+// Return the best color mode supported by HWC.
+ColorMode getHwcColorMode(
+ const std::unordered_map<ColorMode, std::vector<RenderIntent>>& hwcColorModes,
+ ColorMode mode) {
+ std::vector<ColorMode> candidates = getColorModeCandidates(mode);
+ for (auto candidate : candidates) {
+ auto iter = hwcColorModes.find(candidate);
+ if (iter != hwcColorModes.end()) {
+ return candidate;
+ }
+ }
+
+ return ColorMode::NATIVE;
+}
+
+// Return the best render intent supported by HWC.
+RenderIntent getHwcRenderIntent(const std::vector<RenderIntent>& hwcIntents, RenderIntent intent) {
+ std::vector<RenderIntent> candidates = getRenderIntentCandidates(intent);
+ for (auto candidate : candidates) {
+ for (auto hwcIntent : hwcIntents) {
+ if (candidate == hwcIntent) {
+ return candidate;
+ }
+ }
+ }
+
+ return RenderIntent::COLORIMETRIC;
+}
+
+} // anonymous namespace
+
+std::unique_ptr<compositionengine::DisplayColorProfile> createDisplayColorProfile(
+ DisplayColorProfileCreationArgs&& args) {
+ return std::make_unique<DisplayColorProfile>(std::move(args));
+}
+
+DisplayColorProfile::DisplayColorProfile(DisplayColorProfileCreationArgs&& args)
+ : mHasWideColorGamut(args.hasWideColorGamut),
+ mSupportedPerFrameMetadata(args.supportedPerFrameMetadata) {
+ populateColorModes(args.hwcColorModes);
+
+ std::vector<ui::Hdr> types = args.hdrCapabilities.getSupportedHdrTypes();
+ for (ui::Hdr hdrType : types) {
+ switch (hdrType) {
+ case ui::Hdr::HDR10_PLUS:
+ mHasHdr10Plus = true;
+ break;
+ case ui::Hdr::HDR10:
+ mHasHdr10 = true;
+ break;
+ case ui::Hdr::HLG:
+ mHasHLG = true;
+ break;
+ case ui::Hdr::DOLBY_VISION:
+ mHasDolbyVision = true;
+ break;
+ default:
+ ALOGE("UNKNOWN HDR capability: %d", static_cast<int32_t>(hdrType));
+ }
+ }
+
+ float minLuminance = args.hdrCapabilities.getDesiredMinLuminance();
+ float maxLuminance = args.hdrCapabilities.getDesiredMaxLuminance();
+ float maxAverageLuminance = args.hdrCapabilities.getDesiredMaxAverageLuminance();
+
+ minLuminance = minLuminance <= 0.0 ? sDefaultMinLumiance : minLuminance;
+ maxLuminance = maxLuminance <= 0.0 ? sDefaultMaxLumiance : maxLuminance;
+ maxAverageLuminance = maxAverageLuminance <= 0.0 ? sDefaultMaxLumiance : maxAverageLuminance;
+ if (args.hasWideColorGamut) {
+ // insert HDR10/HLG as we will force client composition for HDR10/HLG
+ // layers
+ if (!hasHDR10Support()) {
+ types.push_back(ui::Hdr::HDR10);
+ }
+
+ if (!hasHLGSupport()) {
+ types.push_back(ui::Hdr::HLG);
+ }
+ }
+
+ mHdrCapabilities = HdrCapabilities(types, maxLuminance, maxAverageLuminance, minLuminance);
+}
+
+DisplayColorProfile::~DisplayColorProfile() = default;
+
+bool DisplayColorProfile::isValid() const {
+ return true;
+}
+
+bool DisplayColorProfile::hasWideColorGamut() const {
+ return mHasWideColorGamut;
+}
+
+int32_t DisplayColorProfile::getSupportedPerFrameMetadata() const {
+ return mSupportedPerFrameMetadata;
+}
+
+bool DisplayColorProfile::hasHDR10PlusSupport() const {
+ return mHasHdr10Plus;
+}
+
+bool DisplayColorProfile::hasHDR10Support() const {
+ return mHasHdr10;
+}
+
+bool DisplayColorProfile::hasHLGSupport() const {
+ return mHasHLG;
+}
+
+bool DisplayColorProfile::hasDolbyVisionSupport() const {
+ return mHasDolbyVision;
+}
+
+const HdrCapabilities& DisplayColorProfile::getHdrCapabilities() const {
+ return mHdrCapabilities;
+}
+
+void DisplayColorProfile::populateColorModes(
+ const DisplayColorProfileCreationArgs::HwcColorModes& hwcColorModes) {
+ if (!hasWideColorGamut()) {
+ return;
+ }
+
+ // collect all known SDR render intents
+ std::unordered_set<RenderIntent> sdrRenderIntents(sSdrRenderIntents.begin(),
+ sSdrRenderIntents.end());
+ auto iter = hwcColorModes.find(ColorMode::SRGB);
+ if (iter != hwcColorModes.end()) {
+ for (auto intent : iter->second) {
+ sdrRenderIntents.insert(intent);
+ }
+ }
+
+ // add all known SDR combinations
+ for (auto intent : sdrRenderIntents) {
+ for (auto mode : sSdrColorModes) {
+ addColorMode(hwcColorModes, mode, intent);
+ }
+ }
+
+ // collect all known HDR render intents
+ std::unordered_set<RenderIntent> hdrRenderIntents(sHdrRenderIntents.begin(),
+ sHdrRenderIntents.end());
+ iter = hwcColorModes.find(ColorMode::BT2100_PQ);
+ if (iter != hwcColorModes.end()) {
+ for (auto intent : iter->second) {
+ hdrRenderIntents.insert(intent);
+ }
+ }
+
+ // add all known HDR combinations
+ for (auto intent : sHdrRenderIntents) {
+ for (auto mode : sHdrColorModes) {
+ addColorMode(hwcColorModes, mode, intent);
+ }
+ }
+}
+
+// Map dataspace/intent to the best matched dataspace/colorMode/renderIntent
+// supported by HWC.
+void DisplayColorProfile::addColorMode(
+ const DisplayColorProfileCreationArgs::HwcColorModes& hwcColorModes, const ColorMode mode,
+ const RenderIntent intent) {
+ // find the best color mode
+ const ColorMode hwcColorMode = getHwcColorMode(hwcColorModes, mode);
+
+ // find the best render intent
+ auto iter = hwcColorModes.find(hwcColorMode);
+ const auto& hwcIntents =
+ iter != hwcColorModes.end() ? iter->second : std::vector<RenderIntent>();
+ const RenderIntent hwcIntent = getHwcRenderIntent(hwcIntents, intent);
+
+ const Dataspace dataspace = colorModeToDataspace(mode);
+ const Dataspace hwcDataspace = colorModeToDataspace(hwcColorMode);
+
+ ALOGV("DisplayColorProfile: map (%s, %s) to (%s, %s, %s)",
+ dataspaceDetails(static_cast<android_dataspace_t>(dataspace)).c_str(),
+ decodeRenderIntent(intent).c_str(),
+ dataspaceDetails(static_cast<android_dataspace_t>(hwcDataspace)).c_str(),
+ decodeColorMode(hwcColorMode).c_str(), decodeRenderIntent(hwcIntent).c_str());
+
+ mColorModes[getColorModeKey(dataspace, intent)] = {hwcDataspace, hwcColorMode, hwcIntent};
+}
+
+bool DisplayColorProfile::hasRenderIntent(RenderIntent intent) const {
+ // assume a render intent is supported when SRGB supports it; we should
+ // get rid of that assumption.
+ auto iter = mColorModes.find(getColorModeKey(Dataspace::V0_SRGB, intent));
+ return iter != mColorModes.end() && iter->second.renderIntent == intent;
+}
+
+bool DisplayColorProfile::hasLegacyHdrSupport(Dataspace dataspace) const {
+ if ((dataspace == Dataspace::BT2020_PQ && hasHDR10Support()) ||
+ (dataspace == Dataspace::BT2020_HLG && hasHLGSupport())) {
+ auto iter =
+ mColorModes.find(getColorModeKey(dataspace, RenderIntent::TONE_MAP_COLORIMETRIC));
+ return iter == mColorModes.end() || iter->second.dataspace != dataspace;
+ }
+
+ return false;
+}
+
+void DisplayColorProfile::getBestColorMode(Dataspace dataspace, RenderIntent intent,
+ Dataspace* outDataspace, ColorMode* outMode,
+ RenderIntent* outIntent) const {
+ auto iter = mColorModes.find(getColorModeKey(dataspace, intent));
+ if (iter != mColorModes.end()) {
+ *outDataspace = iter->second.dataspace;
+ *outMode = iter->second.colorMode;
+ *outIntent = iter->second.renderIntent;
+ } else {
+ // this is unexpected on a WCG display
+ if (hasWideColorGamut()) {
+ ALOGE("map unknown (%s)/(%s) to default color mode",
+ dataspaceDetails(static_cast<android_dataspace_t>(dataspace)).c_str(),
+ decodeRenderIntent(intent).c_str());
+ }
+
+ *outDataspace = Dataspace::UNKNOWN;
+ *outMode = ColorMode::NATIVE;
+ *outIntent = RenderIntent::COLORIMETRIC;
+ }
+}
+
+void DisplayColorProfile::dump(std::string& out) const {
+ out.append(" Composition Display Color State:");
+
+ out.append("\n HWC Support: ");
+
+ dumpVal(out, "wideColorGamut", hasWideColorGamut());
+ dumpVal(out, "hdr10plus", hasHDR10PlusSupport());
+ dumpVal(out, "hdr10", hasHDR10Support());
+ dumpVal(out, "hlg", hasHLGSupport());
+ dumpVal(out, "dv", hasDolbyVisionSupport());
+ dumpVal(out, "metadata", getSupportedPerFrameMetadata());
+
+ out.append("\n");
+}
+
+} // namespace impl
+} // namespace android::compositionengine
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplaySurface.cpp b/services/surfaceflinger/CompositionEngine/src/DisplaySurface.cpp
similarity index 68%
copy from services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplaySurface.cpp
copy to services/surfaceflinger/CompositionEngine/src/DisplaySurface.cpp
index e6ac6bf..db6d4f2 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplaySurface.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/DisplaySurface.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018 The Android Open Source Project
+ * 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.
@@ -14,14 +14,10 @@
* limitations under the License.
*/
-#include "mock/DisplayHardware/MockDisplaySurface.h"
+#include <compositionengine/DisplaySurface.h>
-namespace android {
-namespace mock {
+namespace android::compositionengine {
-// Explicit default instantiation is recommended.
-DisplaySurface::DisplaySurface() = default;
DisplaySurface::~DisplaySurface() = default;
-} // namespace mock
-} // namespace android
+} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/src/DumpHelpers.cpp b/services/surfaceflinger/CompositionEngine/src/DumpHelpers.cpp
new file mode 100644
index 0000000..c497013
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/src/DumpHelpers.cpp
@@ -0,0 +1,102 @@
+/*
+ * 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 <cinttypes>
+
+#include <android-base/stringprintf.h>
+#include <compositionengine/impl/DumpHelpers.h>
+
+namespace android::compositionengine::impl {
+
+using android::base::StringAppendF;
+
+void dumpVal(std::string& out, const char* name, bool value) {
+ StringAppendF(&out, "%s=%c ", name, value ? 'T' : 'F');
+}
+
+void dumpVal(std::string& out, const char* name, const void* value) {
+ StringAppendF(&out, "%s=%p ", name, value);
+}
+
+void dumpVal(std::string& out, const char* name, int value) {
+ StringAppendF(&out, "%s=%d ", name, value);
+}
+
+void dumpVal(std::string& out, const char* name, float value) {
+ StringAppendF(&out, "%s=%f ", name, value);
+}
+
+void dumpVal(std::string& out, const char* name, uint32_t value) {
+ StringAppendF(&out, "%s=%u ", name, value);
+}
+
+void dumpHex(std::string& out, const char* name, uint64_t value) {
+ StringAppendF(&out, "%s=0x08%" PRIx64 " ", name, value);
+}
+
+void dumpVal(std::string& out, const char* name, const char* value) {
+ StringAppendF(&out, "%s=%s ", name, value);
+}
+
+void dumpVal(std::string& out, const char* name, const std::string& value) {
+ dumpVal(out, name, value.c_str());
+}
+
+void dumpVal(std::string& out, const char* name, const char* valueName, int value) {
+ StringAppendF(&out, "%s=%s (%d)", name, valueName, value);
+}
+
+void dumpVal(std::string& out, const char* name, const std::string& valueName, int value) {
+ dumpVal(out, name, valueName.c_str(), value);
+}
+
+void dumpVal(std::string& out, const char* name, const FloatRect& rect) {
+ StringAppendF(&out, "%s=[%f %f %f %f] ", name, rect.left, rect.top, rect.right, rect.bottom);
+}
+
+void dumpVal(std::string& out, const char* name, const Rect& rect) {
+ StringAppendF(&out, "%s=[%d %d %d %d] ", name, rect.left, rect.top, rect.right, rect.bottom);
+}
+
+void dumpVal(std::string& out, const char* name, const Region& region) {
+ region.dump(out, name, 0);
+}
+
+void dumpVal(std::string& out, const char* name, const ui::Transform& transform) {
+ transform.dump(out, name);
+}
+
+void dumpVal(std::string& out, const char* name, const ui::Size& size) {
+ StringAppendF(&out, "%s=[%d %d] ", name, size.width, size.height);
+}
+
+void dumpVal(std::string& out, const char* name, const mat4& tr) {
+ StringAppendF(&out,
+ "%s=["
+ /* clang-format off */
+ "[%0.3f,%0.3f,%0.3f,%0.3f]"
+ "[%0.3f,%0.3f,%0.3f,%0.3f]"
+ "[%0.3f,%0.3f,%0.3f,%0.3f]"
+ "[%0.3f,%0.3f,%0.3f,%0.3f]]",
+ name,
+ tr[0][0], tr[1][0], tr[2][0], tr[3][0],
+ tr[0][1], tr[1][1], tr[2][1], tr[3][1],
+ tr[0][2], tr[1][2], tr[2][2], tr[3][2],
+ tr[0][3], tr[1][3], tr[2][3], tr[3][3]
+ ); /* clang-format on */
+}
+
+} // namespace android::compositionengine::impl
diff --git a/services/surfaceflinger/DisplayHardware/HWComposerBufferCache.cpp b/services/surfaceflinger/CompositionEngine/src/HwcBufferCache.cpp
similarity index 75%
rename from services/surfaceflinger/DisplayHardware/HWComposerBufferCache.cpp
rename to services/surfaceflinger/CompositionEngine/src/HwcBufferCache.cpp
index a234b63..6f340b9 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposerBufferCache.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/HwcBufferCache.cpp
@@ -14,21 +14,18 @@
* limitations under the License.
*/
-#include "HWComposerBufferCache.h"
-
+#include <compositionengine/impl/HwcBufferCache.h>
#include <gui/BufferQueue.h>
+#include <ui/GraphicBuffer.h>
-namespace android {
+namespace android::compositionengine::impl {
-HWComposerBufferCache::HWComposerBufferCache()
-{
+HwcBufferCache::HwcBufferCache() {
mBuffers.reserve(BufferQueue::NUM_BUFFER_SLOTS);
}
-void HWComposerBufferCache::getHwcBuffer(int slot,
- const sp<GraphicBuffer>& buffer,
- uint32_t* outSlot, sp<GraphicBuffer>* outBuffer)
-{
+void HwcBufferCache::getHwcBuffer(int slot, const sp<GraphicBuffer>& buffer, uint32_t* outSlot,
+ sp<GraphicBuffer>* outBuffer) {
if (slot == BufferQueue::INVALID_BUFFER_SLOT || slot < 0) {
// default to slot 0
slot = 0;
@@ -51,4 +48,4 @@
}
}
-} // namespace android
+} // namespace android::compositionengine::impl
diff --git a/services/surfaceflinger/CompositionEngine/src/Layer.cpp b/services/surfaceflinger/CompositionEngine/src/Layer.cpp
new file mode 100644
index 0000000..aaa758e
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/src/Layer.cpp
@@ -0,0 +1,46 @@
+/*
+ * 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 <compositionengine/CompositionEngine.h>
+#include <compositionengine/LayerCreationArgs.h>
+#include <compositionengine/LayerFE.h>
+#include <compositionengine/impl/Layer.h>
+
+namespace android::compositionengine {
+
+Layer::~Layer() = default;
+
+namespace impl {
+
+std::shared_ptr<compositionengine::Layer> createLayer(
+ const compositionengine::CompositionEngine& compositionEngine,
+ compositionengine::LayerCreationArgs&& args) {
+ return std::make_shared<Layer>(compositionEngine, std::move(args));
+}
+
+Layer::Layer(const CompositionEngine& compositionEngine, LayerCreationArgs&& args)
+ : mCompositionEngine(compositionEngine), mLayerFE(args.layerFE) {
+ static_cast<void>(mCompositionEngine); // Temporary use to prevent an unused warning
+}
+
+Layer::~Layer() = default;
+
+sp<LayerFE> Layer::getLayerFE() const {
+ return mLayerFE.promote();
+}
+
+} // namespace impl
+} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
new file mode 100644
index 0000000..6d5147d
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -0,0 +1,223 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/stringprintf.h>
+#include <compositionengine/CompositionEngine.h>
+#include <compositionengine/DisplayColorProfile.h>
+#include <compositionengine/LayerFE.h>
+#include <compositionengine/RenderSurface.h>
+#include <compositionengine/impl/Output.h>
+#include <compositionengine/impl/OutputLayer.h>
+#include <ui/DebugUtils.h>
+
+namespace android::compositionengine {
+
+Output::~Output() = default;
+
+namespace impl {
+
+Output::Output(const CompositionEngine& compositionEngine)
+ : mCompositionEngine(compositionEngine) {}
+
+Output::~Output() = default;
+
+const CompositionEngine& Output::getCompositionEngine() const {
+ return mCompositionEngine;
+}
+
+bool Output::isValid() const {
+ return mDisplayColorProfile && mDisplayColorProfile->isValid() && mRenderSurface &&
+ mRenderSurface->isValid();
+}
+
+const std::string& Output::getName() const {
+ return mName;
+}
+
+void Output::setName(const std::string& name) {
+ mName = name;
+}
+
+void Output::setCompositionEnabled(bool enabled) {
+ if (mState.isEnabled == enabled) {
+ return;
+ }
+
+ mState.isEnabled = enabled;
+ dirtyEntireOutput();
+}
+
+void Output::setProjection(const ui::Transform& transform, int32_t orientation, const Rect& frame,
+ const Rect& viewport, const Rect& scissor, bool needsFiltering) {
+ mState.transform = transform;
+ mState.orientation = orientation;
+ mState.scissor = scissor;
+ mState.frame = frame;
+ mState.viewport = viewport;
+ mState.needsFiltering = needsFiltering;
+
+ dirtyEntireOutput();
+}
+
+// TODO(lpique): Rename setSize() once more is moved.
+void Output::setBounds(const ui::Size& size) {
+ mRenderSurface->setDisplaySize(size);
+ // TODO(lpique): Rename mState.size once more is moved.
+ mState.bounds = Rect(mRenderSurface->getSize());
+
+ dirtyEntireOutput();
+}
+
+void Output::setLayerStackFilter(uint32_t layerStackId, bool isInternal) {
+ mState.layerStackId = layerStackId;
+ mState.layerStackInternal = isInternal;
+
+ dirtyEntireOutput();
+}
+
+void Output::setColorTransform(const mat4& transform) {
+ const bool isIdentity = (transform == mat4());
+
+ mState.colorTransform =
+ isIdentity ? HAL_COLOR_TRANSFORM_IDENTITY : HAL_COLOR_TRANSFORM_ARBITRARY_MATRIX;
+}
+
+void Output::setColorMode(ui::ColorMode mode, ui::Dataspace dataspace,
+ ui::RenderIntent renderIntent) {
+ mState.colorMode = mode;
+ mState.dataspace = dataspace;
+ mState.renderIntent = renderIntent;
+
+ mRenderSurface->setBufferDataspace(dataspace);
+
+ ALOGV("Set active color mode: %s (%d), active render intent: %s (%d)",
+ decodeColorMode(mode).c_str(), mode, decodeRenderIntent(renderIntent).c_str(),
+ renderIntent);
+}
+
+void Output::dump(std::string& out) const {
+ using android::base::StringAppendF;
+
+ StringAppendF(&out, " Composition Output State: [\"%s\"]", mName.c_str());
+
+ out.append("\n ");
+
+ dumpBase(out);
+}
+
+void Output::dumpBase(std::string& out) const {
+ mState.dump(out);
+
+ if (mDisplayColorProfile) {
+ mDisplayColorProfile->dump(out);
+ } else {
+ out.append(" No display color profile!\n");
+ }
+
+ if (mRenderSurface) {
+ mRenderSurface->dump(out);
+ } else {
+ out.append(" No render surface!\n");
+ }
+}
+
+compositionengine::DisplayColorProfile* Output::getDisplayColorProfile() const {
+ return mDisplayColorProfile.get();
+}
+
+void Output::setDisplayColorProfile(std::unique_ptr<compositionengine::DisplayColorProfile> mode) {
+ mDisplayColorProfile = std::move(mode);
+}
+
+void Output::setDisplayColorProfileForTest(
+ std::unique_ptr<compositionengine::DisplayColorProfile> mode) {
+ mDisplayColorProfile = std::move(mode);
+}
+
+compositionengine::RenderSurface* Output::getRenderSurface() const {
+ return mRenderSurface.get();
+}
+
+void Output::setRenderSurface(std::unique_ptr<compositionengine::RenderSurface> surface) {
+ mRenderSurface = std::move(surface);
+ mState.bounds = Rect(mRenderSurface->getSize());
+
+ dirtyEntireOutput();
+}
+
+void Output::setRenderSurfaceForTest(std::unique_ptr<compositionengine::RenderSurface> surface) {
+ mRenderSurface = std::move(surface);
+}
+
+const OutputCompositionState& Output::getState() const {
+ return mState;
+}
+
+OutputCompositionState& Output::editState() {
+ return mState;
+}
+
+Region Output::getPhysicalSpaceDirtyRegion(bool repaintEverything) const {
+ Region dirty;
+ if (repaintEverything) {
+ dirty.set(mState.bounds);
+ } else {
+ dirty = mState.transform.transform(mState.dirtyRegion);
+ dirty.andSelf(mState.bounds);
+ }
+ return dirty;
+}
+
+bool Output::belongsInOutput(uint32_t layerStackId, bool internalOnly) const {
+ // The layerStackId's must match, and also the layer must not be internal
+ // only when not on an internal output.
+ return (layerStackId == mState.layerStackId) && (!internalOnly || mState.layerStackInternal);
+}
+
+compositionengine::OutputLayer* Output::getOutputLayerForLayer(
+ compositionengine::Layer* layer) const {
+ for (const auto& outputLayer : mOutputLayersOrderedByZ) {
+ if (outputLayer && &outputLayer->getLayer() == layer) {
+ return outputLayer.get();
+ }
+ }
+ return nullptr;
+}
+
+std::unique_ptr<compositionengine::OutputLayer> Output::getOrCreateOutputLayer(
+ std::shared_ptr<compositionengine::Layer> layer, sp<compositionengine::LayerFE> layerFE) {
+ for (auto& outputLayer : mOutputLayersOrderedByZ) {
+ if (outputLayer && &outputLayer->getLayer() == layer.get()) {
+ return std::move(outputLayer);
+ }
+ }
+ return createOutputLayer(*this, layer, layerFE);
+}
+
+void Output::setOutputLayersOrderedByZ(OutputLayers&& layers) {
+ mOutputLayersOrderedByZ = std::move(layers);
+}
+
+const Output::OutputLayers& Output::getOutputLayersOrderedByZ() const {
+ return mOutputLayersOrderedByZ;
+}
+
+void Output::dirtyEntireOutput() {
+ mState.dirtyRegion.set(mState.bounds);
+}
+
+} // namespace impl
+} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp b/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp
new file mode 100644
index 0000000..78807ff
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp
@@ -0,0 +1,50 @@
+/*
+ * 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 <compositionengine/impl/DumpHelpers.h>
+#include <compositionengine/impl/OutputCompositionState.h>
+
+namespace android::compositionengine::impl {
+
+void OutputCompositionState::dump(std::string& out) const {
+ dumpVal(out, "isEnabled", isEnabled);
+ dumpVal(out, "isSecure", isSecure);
+
+ dumpVal(out, "layerStack", layerStackId);
+ dumpVal(out, "layerStackInternal", layerStackInternal);
+
+ out.append("\n ");
+
+ dumpVal(out, "transform", transform);
+
+ out.append("\n ");
+
+ dumpVal(out, "frame", frame);
+ dumpVal(out, "viewport", viewport);
+ dumpVal(out, "scissor", scissor);
+ dumpVal(out, "needsFiltering", needsFiltering);
+
+ out.append("\n");
+
+ dumpVal(out, "colorMode", toString(colorMode), colorMode);
+ dumpVal(out, "renderIntent", toString(renderIntent), renderIntent);
+ dumpVal(out, "dataspace", toString(dataspace), dataspace);
+ dumpVal(out, "colorTransform", colorTransform);
+
+ out.append("\n");
+}
+
+} // namespace android::compositionengine::impl
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
new file mode 100644
index 0000000..e95f3a6
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
@@ -0,0 +1,52 @@
+/*
+ * 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 <compositionengine/Layer.h>
+#include <compositionengine/LayerFE.h>
+#include <compositionengine/Output.h>
+#include <compositionengine/impl/OutputLayer.h>
+
+namespace android::compositionengine {
+
+OutputLayer::~OutputLayer() = default;
+
+namespace impl {
+
+std::unique_ptr<compositionengine::OutputLayer> createOutputLayer(
+ const compositionengine::Output& display, std::shared_ptr<compositionengine::Layer> layer,
+ sp<compositionengine::LayerFE> layerFE) {
+ return std::make_unique<OutputLayer>(display, layer, layerFE);
+}
+
+OutputLayer::OutputLayer(const Output& output, std::shared_ptr<Layer> layer, sp<LayerFE> layerFE)
+ : mOutput(output), mLayer(layer), mLayerFE(layerFE) {}
+
+OutputLayer::~OutputLayer() = default;
+
+const compositionengine::Output& OutputLayer::getOutput() const {
+ return mOutput;
+}
+
+compositionengine::Layer& OutputLayer::getLayer() const {
+ return *mLayer;
+}
+
+compositionengine::LayerFE& OutputLayer::getLayerFE() const {
+ return *mLayerFE;
+}
+
+} // namespace impl
+} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp b/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp
new file mode 100644
index 0000000..d546fc8
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp
@@ -0,0 +1,271 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/stringprintf.h>
+#include <android/native_window.h>
+#include <compositionengine/CompositionEngine.h>
+#include <compositionengine/Display.h>
+#include <compositionengine/DisplaySurface.h>
+#include <compositionengine/RenderSurfaceCreationArgs.h>
+#include <compositionengine/impl/DumpHelpers.h>
+#include <compositionengine/impl/RenderSurface.h>
+#include <log/log.h>
+#include <renderengine/RenderEngine.h>
+#include <sync/sync.h>
+#include <system/window.h>
+#include <ui/GraphicBuffer.h>
+#include <ui/Rect.h>
+
+#include "DisplayHardware/HWComposer.h"
+
+namespace android::compositionengine {
+
+RenderSurface::~RenderSurface() = default;
+
+namespace impl {
+
+std::unique_ptr<compositionengine::RenderSurface> createRenderSurface(
+ const compositionengine::CompositionEngine& compositionEngine,
+ compositionengine::Display& display, compositionengine::RenderSurfaceCreationArgs&& args) {
+ return std::make_unique<RenderSurface>(compositionEngine, display, std::move(args));
+}
+
+RenderSurface::RenderSurface(const CompositionEngine& compositionEngine, Display& display,
+ RenderSurfaceCreationArgs&& args)
+ : mCompositionEngine(compositionEngine),
+ mDisplay(display),
+ mNativeWindow(args.nativeWindow),
+ mDisplaySurface(args.displaySurface),
+ mSize(args.displayWidth, args.displayHeight) {}
+
+RenderSurface::~RenderSurface() = default;
+
+bool RenderSurface::isValid() const {
+ return mSize.isValid();
+}
+
+void RenderSurface::initialize() {
+ ANativeWindow* const window = mNativeWindow.get();
+
+ int status = native_window_api_connect(window, NATIVE_WINDOW_API_EGL);
+ ALOGE_IF(status != NO_ERROR, "Unable to connect BQ producer: %d", status);
+ status = native_window_set_buffers_format(window, HAL_PIXEL_FORMAT_RGBA_8888);
+ ALOGE_IF(status != NO_ERROR, "Unable to set BQ format to RGBA888: %d", status);
+ status = native_window_set_usage(window, GRALLOC_USAGE_HW_RENDER);
+ ALOGE_IF(status != NO_ERROR, "Unable to set BQ usage bits for GPU rendering: %d", status);
+}
+
+const ui::Size& RenderSurface::getSize() const {
+ return mSize;
+}
+
+const sp<Fence>& RenderSurface::getClientTargetAcquireFence() const {
+ return mDisplaySurface->getClientTargetAcquireFence();
+}
+
+void RenderSurface::setDisplaySize(const ui::Size& size) {
+ mDisplaySurface->resizeBuffers(size.width, size.height);
+ mSize = size;
+}
+
+void RenderSurface::setBufferDataspace(ui::Dataspace dataspace) {
+ native_window_set_buffers_data_space(mNativeWindow.get(),
+ static_cast<android_dataspace>(dataspace));
+}
+
+void RenderSurface::setProtected(bool useProtected) {
+ uint64_t usageFlags = GRALLOC_USAGE_HW_RENDER;
+ if (useProtected) {
+ usageFlags |= GRALLOC_USAGE_PROTECTED;
+ }
+ const int status = native_window_set_usage(mNativeWindow.get(), usageFlags);
+ ALOGE_IF(status != NO_ERROR, "Unable to set BQ usage bits for protected content: %d", status);
+}
+
+status_t RenderSurface::beginFrame(bool mustRecompose) {
+ return mDisplaySurface->beginFrame(mustRecompose);
+}
+
+status_t RenderSurface::prepareFrame(std::vector<CompositionInfo>& compositionData) {
+ auto& hwc = mCompositionEngine.getHwComposer();
+ const auto id = mDisplay.getId();
+ if (id) {
+ status_t error = hwc.prepare(*id, compositionData);
+ if (error != NO_ERROR) {
+ return error;
+ }
+ }
+
+ DisplaySurface::CompositionType compositionType;
+ const bool hasClient = hwc.hasClientComposition(id);
+ const bool hasDevice = hwc.hasDeviceComposition(id);
+ if (hasClient && hasDevice) {
+ compositionType = DisplaySurface::COMPOSITION_MIXED;
+ } else if (hasClient) {
+ compositionType = DisplaySurface::COMPOSITION_GLES;
+ } else if (hasDevice) {
+ compositionType = DisplaySurface::COMPOSITION_HWC;
+ } else {
+ // Nothing to do -- when turning the screen off we get a frame like
+ // this. Call it a HWC frame since we won't be doing any GLES work but
+ // will do a prepare/set cycle.
+ compositionType = DisplaySurface::COMPOSITION_HWC;
+ }
+ return mDisplaySurface->prepareFrame(compositionType);
+}
+
+sp<GraphicBuffer> RenderSurface::dequeueBuffer() {
+ int fd = -1;
+ ANativeWindowBuffer* buffer = nullptr;
+
+ status_t result = mNativeWindow->dequeueBuffer(mNativeWindow.get(), &buffer, &fd);
+
+ if (result != NO_ERROR) {
+ ALOGE("ANativeWindow::dequeueBuffer failed for display [%s] with error: %d",
+ mDisplay.getName().c_str(), result);
+ // Return fast here as we can't do much more - any rendering we do
+ // now will just be wrong.
+ return mGraphicBuffer;
+ }
+
+ ALOGW_IF(mGraphicBuffer != nullptr, "Clobbering a non-null pointer to a buffer [%p].",
+ 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);
+ }
+
+ return mGraphicBuffer;
+}
+
+void RenderSurface::queueBuffer() {
+ auto& hwc = mCompositionEngine.getHwComposer();
+ const auto id = mDisplay.getId();
+
+ if (hwc.hasClientComposition(id) || hwc.hasFlipClientTargetRequest(id)) {
+ // hasFlipClientTargetRequest could return true even if we haven't
+ // dequeued a buffer before. Try dequeueing one if we don't have a
+ // buffer ready.
+ if (mGraphicBuffer == nullptr) {
+ ALOGI("Attempting to queue a client composited buffer without one "
+ "previously dequeued for display [%s]. Attempting to dequeue "
+ "a scratch buffer now",
+ mDisplay.getName().c_str());
+ // We shouldn't deadlock here, since mGraphicBuffer == nullptr only
+ // after a successful call to queueBuffer, or if dequeueBuffer has
+ // never been called.
+ dequeueBuffer();
+ }
+
+ if (mGraphicBuffer == nullptr) {
+ ALOGE("No buffer is ready for display [%s]", mDisplay.getName().c_str());
+ } else {
+ status_t result = mNativeWindow->queueBuffer(mNativeWindow.get(),
+ mGraphicBuffer->getNativeBuffer(),
+ dup(mBufferReady));
+ if (result != NO_ERROR) {
+ ALOGE("Error when queueing buffer for display [%s]: %d", mDisplay.getName().c_str(),
+ result);
+ // We risk blocking on dequeueBuffer if the primary display failed
+ // to queue up its buffer, so crash here.
+ if (!mDisplay.isVirtual()) {
+ LOG_ALWAYS_FATAL("ANativeWindow::queueBuffer failed with error: %d", result);
+ } else {
+ mNativeWindow->cancelBuffer(mNativeWindow.get(),
+ mGraphicBuffer->getNativeBuffer(),
+ dup(mBufferReady));
+ }
+ }
+
+ mBufferReady.reset();
+ mGraphicBuffer = nullptr;
+ }
+ }
+
+ status_t result = mDisplaySurface->advanceFrame();
+ if (result != NO_ERROR) {
+ ALOGE("[%s] failed pushing new frame to HWC: %d", mDisplay.getName().c_str(), result);
+ }
+}
+
+void RenderSurface::onPresentDisplayCompleted() {
+ mDisplaySurface->onFrameCommitted();
+}
+
+void RenderSurface::setViewportAndProjection() {
+ auto& renderEngine = mCompositionEngine.getRenderEngine();
+ Rect sourceCrop = Rect(mSize);
+ renderEngine.setViewportAndProjection(mSize.width, mSize.height, sourceCrop,
+ ui::Transform::ROT_0);
+}
+
+void RenderSurface::finishBuffer() {
+ auto& renderEngine = mCompositionEngine.getRenderEngine();
+ mBufferReady = renderEngine.flush();
+ if (mBufferReady.get() < 0) {
+ renderEngine.finish();
+ }
+}
+
+void RenderSurface::flip() {
+ mPageFlipCount++;
+}
+
+void RenderSurface::dump(std::string& out) const {
+ using android::base::StringAppendF;
+
+ out.append(" Composition RenderSurface State:");
+
+ out.append("\n ");
+
+ dumpVal(out, "size", mSize);
+ StringAppendF(&out, "ANativeWindow=%p (format %d) ", mNativeWindow.get(),
+ ANativeWindow_getFormat(mNativeWindow.get()));
+ dumpVal(out, "flips", mPageFlipCount);
+ out.append("\n");
+
+ String8 surfaceDump;
+ mDisplaySurface->dumpAsString(surfaceDump);
+ out.append(surfaceDump);
+}
+
+std::uint32_t RenderSurface::getPageFlipCount() const {
+ return mPageFlipCount;
+}
+
+void RenderSurface::setPageFlipCountForTest(std::uint32_t count) {
+ mPageFlipCount = count;
+}
+
+void RenderSurface::setSizeForTest(const ui::Size& size) {
+ mSize = size;
+}
+
+sp<GraphicBuffer>& RenderSurface::mutableGraphicBufferForTest() {
+ return mGraphicBuffer;
+}
+
+base::unique_fd& RenderSurface::mutableBufferReadyForTest() {
+ return mBufferReady;
+}
+
+} // namespace impl
+} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/tests/CompositionEngineTest.cpp b/services/surfaceflinger/CompositionEngine/tests/CompositionEngineTest.cpp
new file mode 100644
index 0000000..3766f27
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/tests/CompositionEngineTest.cpp
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <compositionengine/impl/CompositionEngine.h>
+#include <gtest/gtest.h>
+#include <renderengine/mock/RenderEngine.h>
+
+#include "MockHWComposer.h"
+
+namespace android::compositionengine {
+namespace {
+
+using ::testing::StrictMock;
+
+class CompositionEngineTest : public testing::Test {
+public:
+ ~CompositionEngineTest() override;
+ mock::HWComposer* mHwc = new StrictMock<mock::HWComposer>();
+ renderengine::mock::RenderEngine* mRenderEngine =
+ new StrictMock<renderengine::mock::RenderEngine>();
+ impl::CompositionEngine mEngine;
+};
+
+CompositionEngineTest::~CompositionEngineTest() = default;
+
+TEST_F(CompositionEngineTest, canInstantiateCompositionEngine) {
+ auto engine = impl::createCompositionEngine();
+ EXPECT_TRUE(engine.get() != nullptr);
+}
+
+TEST_F(CompositionEngineTest, canSetHWComposer) {
+ mEngine.setHwComposer(std::unique_ptr<android::HWComposer>(mHwc));
+
+ EXPECT_EQ(mHwc, &mEngine.getHwComposer());
+}
+
+TEST_F(CompositionEngineTest, canSetRenderEngine) {
+ mEngine.setRenderEngine(std::unique_ptr<renderengine::RenderEngine>(mRenderEngine));
+
+ EXPECT_EQ(mRenderEngine, &mEngine.getRenderEngine());
+}
+
+} // namespace
+} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/tests/DisplayColorProfileTest.cpp b/services/surfaceflinger/CompositionEngine/tests/DisplayColorProfileTest.cpp
new file mode 100644
index 0000000..d20fdda
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/tests/DisplayColorProfileTest.cpp
@@ -0,0 +1,644 @@
+/*
+ * 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 <compositionengine/DisplayColorProfileCreationArgs.h>
+#include <compositionengine/impl/DisplayColorProfile.h>
+#include <compositionengine/mock/CompositionEngine.h>
+#include <gtest/gtest.h>
+
+namespace android::hardware::graphics::common::V1_1 {
+
+// Note: These operator overloads need to be defined in the same namespace as
+// the values they print.
+
+std::ostream& operator<<(std::ostream& os, const RenderIntent& value) {
+ return os << toString(value) << " (" << static_cast<std::underlying_type_t<Dataspace>>(value)
+ << ")";
+}
+
+} // namespace android::hardware::graphics::common::V1_1
+
+namespace android::hardware::graphics::common::V1_2 {
+
+// Note: These operator overloads need to be defined in the same namespace as
+// the values they print.
+
+std::ostream& operator<<(std::ostream& os, const Dataspace& value) {
+ return os << toString(value) << " (" << static_cast<std::underlying_type_t<Dataspace>>(value)
+ << ")";
+}
+
+std::ostream& operator<<(std::ostream& os, const ColorMode& value) {
+ return os << toString(value) << " (" << static_cast<std::underlying_type_t<Dataspace>>(value)
+ << ")";
+}
+
+} // namespace android::hardware::graphics::common::V1_2
+
+namespace android::compositionengine {
+namespace {
+
+using testing::_;
+using testing::Contains;
+using testing::IsEmpty;
+using testing::Ref;
+using testing::Return;
+using testing::ReturnRef;
+using testing::SizeIs;
+using testing::StrictMock;
+
+using ui::ColorMode;
+using ui::Dataspace;
+using ui::Hdr;
+using ui::RenderIntent;
+
+// This allows us to simulate a vendor-specified intent being used.
+constexpr RenderIntent VendorRenderIntent = static_cast<RenderIntent>(0x100);
+
+class DisplayColorProfileTest : public testing::Test {
+public:
+ ~DisplayColorProfileTest() override = default;
+
+ StrictMock<mock::CompositionEngine> mCompositionEngine;
+};
+
+class ProfileFactory {
+public:
+ impl::DisplayColorProfile build() const {
+ return impl::DisplayColorProfile{DisplayColorProfileCreationArgs{
+ mHasWideColorGamut,
+ HdrCapabilities(mSupportedHdrTypes, mMaxLuminance, mMaxAverageLuminance,
+ mMinLuminance),
+ mSupportedPerFrameMetadata,
+ mSupportedColorModes,
+ }};
+ }
+
+ ProfileFactory& setHasWideColorGamut(bool value) {
+ mHasWideColorGamut = value;
+ return *this;
+ }
+
+ ProfileFactory& setPerFrameMetadata(int32_t value) {
+ mSupportedPerFrameMetadata = value;
+ return *this;
+ }
+
+ ProfileFactory& addHdrType(Hdr value) {
+ mSupportedHdrTypes.emplace_back(value);
+ return *this;
+ }
+
+ ProfileFactory& addHdrTypes(std::initializer_list<Hdr> values) {
+ for (auto value : values) {
+ mSupportedHdrTypes.emplace_back(value);
+ }
+ return *this;
+ }
+
+ ProfileFactory& setMaxLuminance(float value) {
+ mMaxLuminance = value;
+ return *this;
+ }
+
+ ProfileFactory& setMaxAverageLuminance(float value) {
+ mMaxAverageLuminance = value;
+ return *this;
+ }
+
+ ProfileFactory& setMinLuminance(float value) {
+ mMinLuminance = value;
+ return *this;
+ }
+
+ ProfileFactory& addColorModeRenderIntent(ColorMode colorMode, RenderIntent renderIntent) {
+ mSupportedColorModes[colorMode].emplace_back(renderIntent);
+ return *this;
+ }
+
+ ProfileFactory& addColorModeRenderIntents(ColorMode colorMode,
+ std::initializer_list<RenderIntent> renderIntents) {
+ auto& profileedRenderIntents = mSupportedColorModes[colorMode];
+ for (auto renderIntent : renderIntents) {
+ profileedRenderIntents.emplace_back(renderIntent);
+ }
+ return *this;
+ }
+
+ static impl::DisplayColorProfile createProfileWithNoColorModeSupport() {
+ return ProfileFactory().build();
+ }
+
+ static impl::DisplayColorProfile createProfileWithBT2020ColorModeSupport() {
+ return ProfileFactory()
+ .setHasWideColorGamut(true)
+ .addHdrType(Hdr::HDR10)
+ .addColorModeRenderIntent(ColorMode::DISPLAY_BT2020, VendorRenderIntent)
+ .build();
+ }
+
+ static impl::DisplayColorProfile createProfileWithSRGBColorModeSupport() {
+ return ProfileFactory()
+ .setHasWideColorGamut(true)
+ .addHdrType(Hdr::HDR10)
+ .addColorModeRenderIntent(ColorMode::SRGB, VendorRenderIntent)
+ .build();
+ }
+
+ static impl::DisplayColorProfile createProfileWithBT2100PQSupport() {
+ return ProfileFactory()
+ .setHasWideColorGamut(true)
+ .addHdrType(Hdr::HLG)
+ .addColorModeRenderIntent(ColorMode::BT2100_PQ, VendorRenderIntent)
+ .build();
+ }
+
+private:
+ bool mHasWideColorGamut = false;
+ std::vector<Hdr> mSupportedHdrTypes;
+ float mMaxLuminance = -1.f;
+ float mMaxAverageLuminance = -1.f;
+ float mMinLuminance = -1.f;
+ int32_t mSupportedPerFrameMetadata = 0;
+ std::unordered_map<ColorMode, std::vector<RenderIntent>> mSupportedColorModes;
+};
+
+/* ------------------------------------------------------------------------
+ * RenderSurface Construction
+ */
+
+TEST_F(DisplayColorProfileTest, ctorSetsHasWideColorGamutFromInputArgs) {
+ {
+ auto profile = ProfileFactory().setHasWideColorGamut(false).build();
+
+ EXPECT_FALSE(profile.hasWideColorGamut());
+ }
+
+ {
+ auto profile = ProfileFactory().setHasWideColorGamut(true).build();
+
+ EXPECT_TRUE(profile.hasWideColorGamut());
+ }
+}
+
+TEST_F(DisplayColorProfileTest, ctorSetsSupportedPerFrameMetadataFromInputArgs) {
+ {
+ auto profile = ProfileFactory().setPerFrameMetadata(0).build();
+
+ EXPECT_EQ(0, profile.getSupportedPerFrameMetadata());
+ }
+
+ {
+ impl::DisplayColorProfile profile = ProfileFactory().setPerFrameMetadata(123).build();
+
+ EXPECT_EQ(123, profile.getSupportedPerFrameMetadata());
+ }
+}
+
+TEST_F(DisplayColorProfileTest, ctorDetectsSupportedHdrTypesFromInputArgs) {
+ {
+ // The constructor will set the internal state to not indicate any
+ // profile for HDR modes if none are profileed.
+ auto profile = ProfileFactory().build();
+
+ EXPECT_FALSE(profile.hasHDR10PlusSupport());
+ EXPECT_FALSE(profile.hasHDR10Support());
+ EXPECT_FALSE(profile.hasHLGSupport());
+ EXPECT_FALSE(profile.hasDolbyVisionSupport());
+ }
+
+ {
+ // The constructor will set the intenral state to indicate HDR10Plus
+ // profile if the input arguments indicate it is profileed.
+ auto profile = ProfileFactory().addHdrType(Hdr::HDR10_PLUS).build();
+
+ EXPECT_TRUE(profile.hasHDR10PlusSupport());
+ EXPECT_FALSE(profile.hasHDR10Support());
+ EXPECT_FALSE(profile.hasHLGSupport());
+ EXPECT_FALSE(profile.hasDolbyVisionSupport());
+ }
+
+ {
+ // The constructor will set the intenral state to indicate HDR10 profile
+ // if the input arguments indicate it is profileed.
+ auto profile = ProfileFactory().addHdrType(Hdr::HDR10).build();
+
+ EXPECT_FALSE(profile.hasHDR10PlusSupport());
+ EXPECT_TRUE(profile.hasHDR10Support());
+ EXPECT_FALSE(profile.hasHLGSupport());
+ EXPECT_FALSE(profile.hasDolbyVisionSupport());
+ }
+
+ {
+ // The constructor will set the intenral state to indicate HLG profile
+ // if the input arguments indicate it is profileed.
+ auto profile = ProfileFactory().addHdrType(Hdr::HLG).build();
+
+ EXPECT_FALSE(profile.hasHDR10PlusSupport());
+ EXPECT_FALSE(profile.hasHDR10Support());
+ EXPECT_TRUE(profile.hasHLGSupport());
+ EXPECT_FALSE(profile.hasDolbyVisionSupport());
+ }
+
+ {
+ // The constructor will set the intenral state to indicate Dolbyvision profile
+ // if the input arguments indicate it is profileed.
+ auto profile = ProfileFactory().addHdrType(Hdr::DOLBY_VISION).build();
+
+ EXPECT_FALSE(profile.hasHDR10Support());
+ EXPECT_FALSE(profile.hasHLGSupport());
+ EXPECT_TRUE(profile.hasDolbyVisionSupport());
+ }
+}
+
+TEST_F(DisplayColorProfileTest, ctorUsesOrDefaultsLuminanceValuesFromInputArgs) {
+ {
+ // The constructor will use a default value for each luminance setting
+ // that is negative.
+ auto profile = ProfileFactory()
+ .setMaxLuminance(-1.f)
+ .setMaxAverageLuminance(-1.f)
+ .setMinLuminance(-1.f)
+ .build();
+
+ EXPECT_EQ(DisplayColorProfile::sDefaultMaxLumiance,
+ profile.getHdrCapabilities().getDesiredMaxLuminance());
+ EXPECT_EQ(DisplayColorProfile::sDefaultMaxLumiance,
+ profile.getHdrCapabilities().getDesiredMaxAverageLuminance());
+ EXPECT_EQ(DisplayColorProfile::sDefaultMinLumiance,
+ profile.getHdrCapabilities().getDesiredMinLuminance());
+ }
+
+ {
+ // The constructor will otherwise take and use a positive value for each
+ // of the luminance settings.
+ auto profile = ProfileFactory()
+ .setMaxLuminance(1001.f)
+ .setMaxAverageLuminance(1002.f)
+ .setMinLuminance(1003.f)
+ .build();
+
+ EXPECT_EQ(1001.f, profile.getHdrCapabilities().getDesiredMaxLuminance());
+ EXPECT_EQ(1002.f, profile.getHdrCapabilities().getDesiredMaxAverageLuminance());
+ EXPECT_EQ(1003.f, profile.getHdrCapabilities().getDesiredMinLuminance());
+ }
+}
+
+TEST_F(DisplayColorProfileTest, ctorSignalsHdrSupportForAnyWideColorGamutDevice) {
+ {
+ // If the output does not profile wide color gamut, then no HDR modes
+ // will be profileed in the generated HDR capabilities.
+ auto profile = ProfileFactory().setHasWideColorGamut(false).build();
+
+ EXPECT_THAT(profile.getHdrCapabilities().getSupportedHdrTypes(), IsEmpty());
+ }
+
+ {
+ // If the HWC does not show profile for certain HDR modes, then the
+ // generated HDR capabilities will indicate profile anyway.
+ auto profile = ProfileFactory().setHasWideColorGamut(true).build();
+
+ EXPECT_THAT(profile.getHdrCapabilities().getSupportedHdrTypes(), SizeIs(2));
+ EXPECT_THAT(profile.getHdrCapabilities().getSupportedHdrTypes(), Contains(Hdr::HDR10));
+ EXPECT_THAT(profile.getHdrCapabilities().getSupportedHdrTypes(), Contains(Hdr::HLG));
+ }
+
+ {
+ // If the HWC profiles the HDR modes, then the generated capabilities
+ // still has one entry for each HDR type.
+ auto profile = ProfileFactory()
+ .setHasWideColorGamut(true)
+ .addHdrTypes({Hdr::HLG, Hdr::HDR10})
+ .build();
+
+ EXPECT_THAT(profile.getHdrCapabilities().getSupportedHdrTypes(), SizeIs(2));
+ EXPECT_THAT(profile.getHdrCapabilities().getSupportedHdrTypes(), Contains(Hdr::HDR10));
+ EXPECT_THAT(profile.getHdrCapabilities().getSupportedHdrTypes(), Contains(Hdr::HLG));
+ }
+}
+
+/* ------------------------------------------------------------------------
+ * DisplayColorProfile::hasRenderIntent
+ */
+
+TEST_F(DisplayColorProfileTest, hasRenderIntentReturnsExpectedValueWhenOutputHasNoSupport) {
+ auto profile = ProfileFactory::createProfileWithNoColorModeSupport();
+
+ EXPECT_FALSE(profile.hasRenderIntent(RenderIntent::COLORIMETRIC));
+ EXPECT_FALSE(profile.hasRenderIntent(RenderIntent::ENHANCE));
+ EXPECT_FALSE(profile.hasRenderIntent(RenderIntent::TONE_MAP_COLORIMETRIC));
+ EXPECT_FALSE(profile.hasRenderIntent(RenderIntent::TONE_MAP_ENHANCE));
+ EXPECT_FALSE(profile.hasRenderIntent(VendorRenderIntent));
+}
+
+TEST_F(DisplayColorProfileTest, hasRenderIntentReturnsExpectedValueWhenOutputHasBT2020upport) {
+ auto profile = ProfileFactory::createProfileWithBT2020ColorModeSupport();
+
+ EXPECT_TRUE(profile.hasRenderIntent(RenderIntent::COLORIMETRIC));
+ EXPECT_FALSE(profile.hasRenderIntent(RenderIntent::ENHANCE));
+ EXPECT_FALSE(profile.hasRenderIntent(RenderIntent::TONE_MAP_COLORIMETRIC));
+ EXPECT_FALSE(profile.hasRenderIntent(RenderIntent::TONE_MAP_ENHANCE));
+ EXPECT_FALSE(profile.hasRenderIntent(VendorRenderIntent));
+}
+
+TEST_F(DisplayColorProfileTest, hasRenderIntentReturnsExpectedValueWhenOutputHasSRGBSupport) {
+ auto profile = ProfileFactory::createProfileWithSRGBColorModeSupport();
+
+ EXPECT_TRUE(profile.hasRenderIntent(RenderIntent::COLORIMETRIC));
+ EXPECT_FALSE(profile.hasRenderIntent(RenderIntent::ENHANCE));
+ EXPECT_FALSE(profile.hasRenderIntent(RenderIntent::TONE_MAP_COLORIMETRIC));
+ EXPECT_FALSE(profile.hasRenderIntent(RenderIntent::TONE_MAP_ENHANCE));
+ EXPECT_TRUE(profile.hasRenderIntent(VendorRenderIntent));
+}
+
+TEST_F(DisplayColorProfileTest, hasRenderIntentReturnsExpectedValueWhenOutputHasBTG2100PQSupport) {
+ auto profile = ProfileFactory::createProfileWithBT2100PQSupport();
+
+ EXPECT_TRUE(profile.hasRenderIntent(RenderIntent::COLORIMETRIC));
+ EXPECT_FALSE(profile.hasRenderIntent(RenderIntent::ENHANCE));
+ EXPECT_FALSE(profile.hasRenderIntent(RenderIntent::TONE_MAP_COLORIMETRIC));
+ EXPECT_FALSE(profile.hasRenderIntent(RenderIntent::TONE_MAP_ENHANCE));
+ EXPECT_FALSE(profile.hasRenderIntent(VendorRenderIntent));
+}
+
+/* ------------------------------------------------------------------------
+ * DisplayColorProfile::hasLegacyHdrSupport
+ */
+
+TEST_F(DisplayColorProfileTest, hasLegacyHdrSupport) {
+ {
+ auto profile = ProfileFactory::createProfileWithNoColorModeSupport();
+
+ EXPECT_FALSE(profile.hasLegacyHdrSupport(Dataspace::BT2020_PQ));
+ EXPECT_FALSE(profile.hasLegacyHdrSupport(Dataspace::BT2020_HLG));
+ }
+
+ {
+ auto profile = ProfileFactory::createProfileWithBT2020ColorModeSupport();
+
+ EXPECT_TRUE(profile.hasLegacyHdrSupport(Dataspace::BT2020_PQ));
+ EXPECT_FALSE(profile.hasLegacyHdrSupport(Dataspace::BT2020_HLG));
+ }
+
+ {
+ auto profile = ProfileFactory::createProfileWithSRGBColorModeSupport();
+
+ EXPECT_TRUE(profile.hasLegacyHdrSupport(Dataspace::BT2020_PQ));
+ EXPECT_FALSE(profile.hasLegacyHdrSupport(Dataspace::BT2020_HLG));
+ }
+
+ {
+ auto profile = ProfileFactory::createProfileWithBT2100PQSupport();
+
+ EXPECT_FALSE(profile.hasLegacyHdrSupport(Dataspace::BT2020_PQ));
+ EXPECT_TRUE(profile.hasLegacyHdrSupport(Dataspace::BT2020_HLG));
+ }
+}
+
+/* ------------------------------------------------------------------------
+ * RenderSurface::getBestColorMode()
+ */
+
+void checkGetBestColorMode(
+ DisplayColorProfile& profile,
+ const std::array<std::tuple<Dataspace, ColorMode, RenderIntent>, 25>& expected) {
+ using ArgsType = std::tuple<Dataspace, RenderIntent>;
+
+ // These are the combinations of dataspaces and render intents that could be
+ // passed to RenderSurface::getBestColorMode()
+ const std::array<std::tuple<Dataspace, RenderIntent>, 25> kArgs = {
+ /* clang-format off */
+
+ // Non-HDR combinations
+
+ /* 0 */ ArgsType{Dataspace::DISPLAY_BT2020, RenderIntent::COLORIMETRIC},
+ /* 1 */ ArgsType{Dataspace::DISPLAY_BT2020, RenderIntent::ENHANCE},
+ /* 2 */ ArgsType{Dataspace::DISPLAY_BT2020, RenderIntent::TONE_MAP_COLORIMETRIC}, // Vendor explicit setting
+ /* 3 */ ArgsType{Dataspace::DISPLAY_BT2020, RenderIntent::TONE_MAP_ENHANCE}, // Vendor explicit setting
+ /* 4 */ ArgsType{Dataspace::DISPLAY_BT2020, VendorRenderIntent}, // Vendor explicit setting
+
+ /* 5 */ ArgsType{Dataspace::DISPLAY_P3, RenderIntent::COLORIMETRIC},
+ /* 6 */ ArgsType{Dataspace::DISPLAY_P3, RenderIntent::ENHANCE},
+ /* 7 */ ArgsType{Dataspace::DISPLAY_P3, RenderIntent::TONE_MAP_COLORIMETRIC}, // Vendor explicit setting
+ /* 8 */ ArgsType{Dataspace::DISPLAY_P3, RenderIntent::TONE_MAP_ENHANCE}, // Vendor explicit setting
+ /* 9 */ ArgsType{Dataspace::DISPLAY_P3, VendorRenderIntent}, // Vendor explicit setting
+
+ /* 10 */ ArgsType{Dataspace::V0_SRGB, RenderIntent::COLORIMETRIC},
+ /* 11 */ ArgsType{Dataspace::V0_SRGB, RenderIntent::ENHANCE},
+ /* 12 */ ArgsType{Dataspace::V0_SRGB, RenderIntent::TONE_MAP_COLORIMETRIC}, // Vendor explicit setting
+ /* 13 */ ArgsType{Dataspace::V0_SRGB, RenderIntent::TONE_MAP_ENHANCE}, // Vendor explicit setting
+ /* 14 */ ArgsType{Dataspace::V0_SRGB, VendorRenderIntent}, // Vendor explicit setting
+
+ // HDR combinations
+
+ /* 15 */ ArgsType{Dataspace::BT2020_PQ, RenderIntent::TONE_MAP_COLORIMETRIC},
+ /* 16 */ ArgsType{Dataspace::BT2020_PQ, RenderIntent::TONE_MAP_ENHANCE},
+ /* 17 */ ArgsType{Dataspace::BT2020_PQ, RenderIntent::COLORIMETRIC}, // Vendor explicit setting
+ /* 18 */ ArgsType{Dataspace::BT2020_PQ, RenderIntent::ENHANCE}, // Vendor explicit setting
+ /* 19 */ ArgsType{Dataspace::BT2020_PQ, VendorRenderIntent}, // Vendor explicit setting
+
+ /* 20 */ ArgsType{Dataspace::BT2020_HLG, RenderIntent::TONE_MAP_COLORIMETRIC},
+ /* 21 */ ArgsType{Dataspace::BT2020_HLG, RenderIntent::TONE_MAP_ENHANCE},
+ /* 22 */ ArgsType{Dataspace::BT2020_HLG, RenderIntent::COLORIMETRIC}, // Vendor explicit setting
+ /* 23 */ ArgsType{Dataspace::BT2020_HLG, RenderIntent::ENHANCE}, // Vendor explicit setting
+ /* 24 */ ArgsType{Dataspace::BT2020_HLG, VendorRenderIntent}, // Vendor explicit setting
+ /* clang-format on */
+ };
+
+ for (size_t i = 0; i < kArgs.size(); i++) {
+ std::tuple<Dataspace, ColorMode, RenderIntent> actual;
+ profile.getBestColorMode(std::get<0>(kArgs[i]), std::get<1>(kArgs[i]), &std::get<0>(actual),
+ &std::get<1>(actual), &std::get<2>(actual));
+
+ EXPECT_EQ(expected[i], actual) << " for index " << i;
+ }
+}
+
+TEST_F(DisplayColorProfileTest, getBestColorModeReturnsExpectedModesWhenOutputHasNoSupport) {
+ auto profile = ProfileFactory::createProfileWithNoColorModeSupport();
+
+ // Note: This table of expected values goes with the table of arguments
+ // used in checkGetBestColorMode.
+ using Result = std::tuple<Dataspace, ColorMode, RenderIntent>;
+ std::array<Result, 25> expectedResults = {
+ /* clang-format off */
+ /* 0 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 1 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 2 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 3 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 4 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+
+ /* 5 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 6 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 7 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 8 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 9 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+
+ /* 10 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 11 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 12 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 13 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 14 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+
+ /* 15 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 16 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 17 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 18 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 19 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+
+ /* 20 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 21 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 22 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 23 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 24 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+
+ /* clang-format on */
+ };
+
+ checkGetBestColorMode(profile, expectedResults);
+}
+
+TEST_F(DisplayColorProfileTest, getBestColorModeReturnsExpectedModesWhenOutputHasBT2020Support) {
+ auto profile = ProfileFactory::createProfileWithBT2020ColorModeSupport();
+
+ // Note: This table of expected values goes with the table of arguments
+ // used in checkGetBestColorMode.
+ using Result = std::tuple<Dataspace, ColorMode, RenderIntent>;
+ std::array<Result, 25> expectedResults = {
+ /* clang-format off */
+ /* 0 */ Result{Dataspace::DISPLAY_BT2020, ColorMode::DISPLAY_BT2020, RenderIntent::COLORIMETRIC},
+ /* 1 */ Result{Dataspace::DISPLAY_BT2020, ColorMode::DISPLAY_BT2020, RenderIntent::COLORIMETRIC},
+ /* 2 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 3 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 4 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+
+ /* 5 */ Result{Dataspace::DISPLAY_BT2020, ColorMode::DISPLAY_BT2020, RenderIntent::COLORIMETRIC},
+ /* 6 */ Result{Dataspace::DISPLAY_BT2020, ColorMode::DISPLAY_BT2020, RenderIntent::COLORIMETRIC},
+ /* 7 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 8 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 9 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+
+ /* 10 */ Result{Dataspace::DISPLAY_BT2020, ColorMode::DISPLAY_BT2020, RenderIntent::COLORIMETRIC},
+ /* 11 */ Result{Dataspace::DISPLAY_BT2020, ColorMode::DISPLAY_BT2020, RenderIntent::COLORIMETRIC},
+ /* 12 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 13 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 14 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+
+ /* 15 */ Result{Dataspace::DISPLAY_BT2020, ColorMode::DISPLAY_BT2020, RenderIntent::COLORIMETRIC},
+ /* 16 */ Result{Dataspace::DISPLAY_BT2020, ColorMode::DISPLAY_BT2020, RenderIntent::COLORIMETRIC},
+ /* 17 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 18 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 19 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+
+ /* 20 */ Result{Dataspace::DISPLAY_BT2020, ColorMode::DISPLAY_BT2020, RenderIntent::COLORIMETRIC},
+ /* 21 */ Result{Dataspace::DISPLAY_BT2020, ColorMode::DISPLAY_BT2020, RenderIntent::COLORIMETRIC},
+ /* 22 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 23 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 24 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* clang-format on */
+ };
+
+ checkGetBestColorMode(profile, expectedResults);
+}
+
+TEST_F(DisplayColorProfileTest, getBestColorModeReturnsExpectedModesWhenOutputHasSRGBSupport) {
+ auto profile = ProfileFactory::createProfileWithSRGBColorModeSupport();
+
+ // Note: This table of expected values goes with the table of arguments
+ // used in checkGetBestColorMode.
+ using Result = std::tuple<Dataspace, ColorMode, RenderIntent>;
+ std::array<Result, 25> expectedResults = {
+ /* clang-format off */
+ /* 0 */ Result{Dataspace::V0_SRGB, ColorMode::SRGB, RenderIntent::COLORIMETRIC},
+ /* 1 */ Result{Dataspace::V0_SRGB, ColorMode::SRGB, RenderIntent::COLORIMETRIC},
+ /* 2 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 3 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 4 */ Result{Dataspace::V0_SRGB, ColorMode::SRGB, VendorRenderIntent},
+
+ /* 5 */ Result{Dataspace::V0_SRGB, ColorMode::SRGB, RenderIntent::COLORIMETRIC},
+ /* 6 */ Result{Dataspace::V0_SRGB, ColorMode::SRGB, RenderIntent::COLORIMETRIC},
+ /* 7 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 8 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 9 */ Result{Dataspace::V0_SRGB, ColorMode::SRGB, VendorRenderIntent},
+
+ /* 10 */ Result{Dataspace::V0_SRGB, ColorMode::SRGB, RenderIntent::COLORIMETRIC},
+ /* 11 */ Result{Dataspace::V0_SRGB, ColorMode::SRGB, RenderIntent::COLORIMETRIC},
+ /* 12 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 13 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 14 */ Result{Dataspace::V0_SRGB, ColorMode::SRGB, VendorRenderIntent},
+
+ /* 15 */ Result{Dataspace::V0_SRGB, ColorMode::SRGB, RenderIntent::COLORIMETRIC},
+ /* 16 */ Result{Dataspace::V0_SRGB, ColorMode::SRGB, RenderIntent::COLORIMETRIC},
+ /* 17 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 18 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 19 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+
+ /* 20 */ Result{Dataspace::V0_SRGB, ColorMode::SRGB, RenderIntent::COLORIMETRIC},
+ /* 21 */ Result{Dataspace::V0_SRGB, ColorMode::SRGB, RenderIntent::COLORIMETRIC},
+ /* 22 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 23 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 24 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* clang-format on */
+ };
+
+ checkGetBestColorMode(profile, expectedResults);
+}
+
+TEST_F(DisplayColorProfileTest, getBestColorModeReturnsExpectedModesWhenOutputHasBT2100PQSupport) {
+ auto profile = ProfileFactory::createProfileWithBT2100PQSupport();
+
+ // Note: This table of expected values goes with the table of arguments
+ // used in checkGetBestColorMode.
+ using Result = std::tuple<Dataspace, ColorMode, RenderIntent>;
+ std::array<Result, 25> expectedResults = {
+ /* clang-format off */
+ /* 0 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 1 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 2 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 3 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 4 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+
+ /* 5 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 6 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 7 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 8 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 9 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+
+ /* 19 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 11 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 12 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 13 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 14 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+
+ /* 15 */ Result{Dataspace::BT2020_PQ, ColorMode::BT2100_PQ, RenderIntent::COLORIMETRIC},
+ /* 16 */ Result{Dataspace::BT2020_PQ, ColorMode::BT2100_PQ, RenderIntent::COLORIMETRIC},
+ /* 17 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 18 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 19 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+
+ /* 20 */ Result{Dataspace::BT2020_PQ, ColorMode::BT2100_PQ, RenderIntent::COLORIMETRIC},
+ /* 21 */ Result{Dataspace::BT2020_PQ, ColorMode::BT2100_PQ, RenderIntent::COLORIMETRIC},
+ /* 22 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 23 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 24 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* clang-format on */
+ };
+
+ checkGetBestColorMode(profile, expectedResults);
+}
+
+} // namespace
+} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
new file mode 100644
index 0000000..8cb6936
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
@@ -0,0 +1,208 @@
+/*
+ * 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 <cmath>
+
+#include <compositionengine/DisplayColorProfileCreationArgs.h>
+#include <compositionengine/DisplayCreationArgs.h>
+#include <compositionengine/DisplaySurface.h>
+#include <compositionengine/RenderSurfaceCreationArgs.h>
+#include <compositionengine/impl/Display.h>
+#include <compositionengine/mock/CompositionEngine.h>
+#include <compositionengine/mock/RenderSurface.h>
+#include <gtest/gtest.h>
+#include <system/window.h>
+
+#include "MockHWComposer.h"
+
+namespace android::compositionengine {
+namespace {
+
+using testing::Return;
+using testing::ReturnRef;
+using testing::StrictMock;
+
+constexpr DisplayId DEFAULT_DISPLAY_ID = DisplayId{42};
+
+class DisplayTest : public testing::Test {
+public:
+ ~DisplayTest() override = default;
+
+ StrictMock<android::mock::HWComposer> mHwComposer;
+ StrictMock<mock::CompositionEngine> mCompositionEngine;
+ impl::Display mDisplay{mCompositionEngine,
+ DisplayCreationArgsBuilder().setDisplayId(DEFAULT_DISPLAY_ID).build()};
+};
+
+/* ------------------------------------------------------------------------
+ * Basic construction
+ */
+
+TEST_F(DisplayTest, canInstantiateDisplay) {
+ {
+ constexpr DisplayId display1 = DisplayId{123u};
+ auto display =
+ impl::createDisplay(mCompositionEngine,
+ DisplayCreationArgsBuilder().setDisplayId(display1).build());
+ EXPECT_FALSE(display->isSecure());
+ EXPECT_FALSE(display->isVirtual());
+ EXPECT_EQ(display1, display->getId());
+ }
+
+ {
+ constexpr DisplayId display2 = DisplayId{546u};
+ auto display = impl::createDisplay(mCompositionEngine,
+ DisplayCreationArgsBuilder()
+ .setIsSecure(true)
+ .setDisplayId(display2)
+ .build());
+ EXPECT_TRUE(display->isSecure());
+ EXPECT_FALSE(display->isVirtual());
+ EXPECT_EQ(display2, display->getId());
+ }
+
+ {
+ constexpr DisplayId display3 = DisplayId{789u};
+ auto display = impl::createDisplay(mCompositionEngine,
+ DisplayCreationArgsBuilder()
+ .setIsVirtual(true)
+ .setDisplayId(display3)
+ .build());
+ EXPECT_FALSE(display->isSecure());
+ EXPECT_TRUE(display->isVirtual());
+ EXPECT_EQ(display3, display->getId());
+ }
+}
+
+/* ------------------------------------------------------------------------
+ * Display::disconnect()
+ */
+
+TEST_F(DisplayTest, disconnectDisconnectsDisplay) {
+ EXPECT_CALL(mCompositionEngine, getHwComposer()).WillRepeatedly(ReturnRef(mHwComposer));
+
+ // The first call to disconnect will disconnect the display with the HWC and
+ // set mHwcId to -1.
+ EXPECT_CALL(mHwComposer, disconnectDisplay(DEFAULT_DISPLAY_ID)).Times(1);
+ mDisplay.disconnect();
+ EXPECT_FALSE(mDisplay.getId());
+
+ // Subsequent calls will do nothing,
+ EXPECT_CALL(mHwComposer, disconnectDisplay(DEFAULT_DISPLAY_ID)).Times(0);
+ mDisplay.disconnect();
+ EXPECT_FALSE(mDisplay.getId());
+}
+
+/* ------------------------------------------------------------------------
+ * Display::setColorTransform()
+ */
+
+TEST_F(DisplayTest, setColorTransformSetsTransform) {
+ // Identity matrix sets an identity state value
+ const mat4 identity;
+
+ EXPECT_CALL(mCompositionEngine, getHwComposer()).WillRepeatedly(ReturnRef(mHwComposer));
+
+ EXPECT_CALL(mHwComposer, setColorTransform(DEFAULT_DISPLAY_ID, identity)).Times(1);
+
+ mDisplay.setColorTransform(identity);
+
+ EXPECT_EQ(HAL_COLOR_TRANSFORM_IDENTITY, mDisplay.getState().colorTransform);
+
+ // Non-identity matrix sets a non-identity state value
+ const mat4 nonIdentity = mat4() * 2;
+
+ EXPECT_CALL(mHwComposer, setColorTransform(DEFAULT_DISPLAY_ID, nonIdentity)).Times(1);
+
+ mDisplay.setColorTransform(nonIdentity);
+
+ EXPECT_EQ(HAL_COLOR_TRANSFORM_ARBITRARY_MATRIX, mDisplay.getState().colorTransform);
+}
+
+/* ------------------------------------------------------------------------
+ * Display::setColorMode()
+ */
+
+TEST_F(DisplayTest, setColorModeSetsModeUnlessNoChange) {
+ mock::RenderSurface* renderSurface = new StrictMock<mock::RenderSurface>();
+ mDisplay.setRenderSurfaceForTest(std::unique_ptr<RenderSurface>(renderSurface));
+
+ EXPECT_CALL(mCompositionEngine, getHwComposer()).WillRepeatedly(ReturnRef(mHwComposer));
+
+ // These values are expected to be the initial state.
+ ASSERT_EQ(ui::ColorMode::NATIVE, mDisplay.getState().colorMode);
+ ASSERT_EQ(ui::Dataspace::UNKNOWN, mDisplay.getState().dataspace);
+ ASSERT_EQ(ui::RenderIntent::COLORIMETRIC, mDisplay.getState().renderIntent);
+
+ // Otherwise if the values are unchanged, nothing happens
+ mDisplay.setColorMode(ui::ColorMode::NATIVE, ui::Dataspace::UNKNOWN,
+ ui::RenderIntent::COLORIMETRIC);
+
+ EXPECT_EQ(ui::ColorMode::NATIVE, mDisplay.getState().colorMode);
+ EXPECT_EQ(ui::Dataspace::UNKNOWN, mDisplay.getState().dataspace);
+ EXPECT_EQ(ui::RenderIntent::COLORIMETRIC, mDisplay.getState().renderIntent);
+
+ // Otherwise if the values are different, updates happen
+ EXPECT_CALL(*renderSurface, setBufferDataspace(ui::Dataspace::SRGB)).Times(1);
+ EXPECT_CALL(mHwComposer,
+ setActiveColorMode(DEFAULT_DISPLAY_ID, ui::ColorMode::BT2100_PQ,
+ ui::RenderIntent::TONE_MAP_COLORIMETRIC))
+ .Times(1);
+
+ mDisplay.setColorMode(ui::ColorMode::BT2100_PQ, ui::Dataspace::SRGB,
+ ui::RenderIntent::TONE_MAP_COLORIMETRIC);
+
+ EXPECT_EQ(ui::ColorMode::BT2100_PQ, mDisplay.getState().colorMode);
+ EXPECT_EQ(ui::Dataspace::SRGB, mDisplay.getState().dataspace);
+ EXPECT_EQ(ui::RenderIntent::TONE_MAP_COLORIMETRIC, mDisplay.getState().renderIntent);
+}
+
+TEST_F(DisplayTest, setColorModeDoesNothingForVirtualDisplay) {
+ impl::Display virtualDisplay{mCompositionEngine,
+ DisplayCreationArgs{false, true, DEFAULT_DISPLAY_ID}};
+
+ virtualDisplay.setColorMode(ui::ColorMode::BT2100_PQ, ui::Dataspace::SRGB,
+ ui::RenderIntent::TONE_MAP_COLORIMETRIC);
+
+ EXPECT_EQ(ui::ColorMode::NATIVE, virtualDisplay.getState().colorMode);
+ EXPECT_EQ(ui::Dataspace::UNKNOWN, virtualDisplay.getState().dataspace);
+ EXPECT_EQ(ui::RenderIntent::COLORIMETRIC, virtualDisplay.getState().renderIntent);
+}
+
+/* ------------------------------------------------------------------------
+ * Display::createDisplayColorProfile()
+ */
+
+TEST_F(DisplayTest, createDisplayColorProfileSetsDisplayColorProfile) {
+ EXPECT_TRUE(mDisplay.getDisplayColorProfile() == nullptr);
+ mDisplay.createDisplayColorProfile(
+ DisplayColorProfileCreationArgs{false, HdrCapabilities(), 0,
+ DisplayColorProfileCreationArgs::HwcColorModes()});
+ EXPECT_TRUE(mDisplay.getDisplayColorProfile() != nullptr);
+}
+
+/* ------------------------------------------------------------------------
+ * Display::createRenderSurface()
+ */
+
+TEST_F(DisplayTest, createRenderSurfaceSetsRenderSurface) {
+ EXPECT_TRUE(mDisplay.getRenderSurface() == nullptr);
+ mDisplay.createRenderSurface(RenderSurfaceCreationArgs{640, 480, nullptr, nullptr});
+ EXPECT_TRUE(mDisplay.getRenderSurface() != nullptr);
+}
+
+} // namespace
+} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/tests/HwcBufferCacheTest.cpp b/services/surfaceflinger/CompositionEngine/tests/HwcBufferCacheTest.cpp
new file mode 100644
index 0000000..f2a1aad
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/tests/HwcBufferCacheTest.cpp
@@ -0,0 +1,82 @@
+/*
+ * 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 <compositionengine/impl/HwcBufferCache.h>
+#include <gtest/gtest.h>
+#include <gui/BufferQueue.h>
+#include <ui/GraphicBuffer.h>
+
+namespace android::compositionengine {
+namespace {
+
+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;
+ 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, cacheWorksForMaxSlot) {
+ testSlot(BufferQueue::NUM_BUFFER_SLOTS - 1, BufferQueue::NUM_BUFFER_SLOTS - 1);
+}
+
+TEST_F(HwcBufferCacheTest, cacheMapsNegativeSlotToZero) {
+ testSlot(-123, 0);
+}
+
+TEST_F(HwcBufferCacheTest, cacheMapsInvalidBufferSlotToZero) {
+ testSlot(BufferQueue::INVALID_BUFFER_SLOT, 0);
+}
+
+} // namespace
+} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/tests/LayerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/LayerTest.cpp
new file mode 100644
index 0000000..26115a3
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/tests/LayerTest.cpp
@@ -0,0 +1,45 @@
+/*
+ * 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 <compositionengine/LayerCreationArgs.h>
+#include <compositionengine/impl/Layer.h>
+#include <compositionengine/mock/CompositionEngine.h>
+#include <compositionengine/mock/LayerFE.h>
+
+namespace android::compositionengine {
+namespace {
+
+using testing::StrictMock;
+
+class LayerTest : public testing::Test {
+public:
+ ~LayerTest() override = default;
+
+ StrictMock<mock::CompositionEngine> mCompositionEngine;
+ sp<LayerFE> mLayerFE = new StrictMock<mock::LayerFE>();
+ impl::Layer mLayer{mCompositionEngine, LayerCreationArgs{mLayerFE}};
+};
+
+/* ------------------------------------------------------------------------
+ * Basic construction
+ */
+
+TEST_F(LayerTest, canInstantiateLayer) {}
+
+} // namespace
+} // namespace android::compositionengine
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplaySurface.cpp b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.cpp
similarity index 62%
copy from services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplaySurface.cpp
copy to services/surfaceflinger/CompositionEngine/tests/MockHWComposer.cpp
index e6ac6bf..ae52670 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplaySurface.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.cpp
@@ -1,6 +1,6 @@
/*
- * Copyright (C) 2018 The Android Open Source Project
- *
+ * Copyright 2018 The Android Open Source Project
+
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
@@ -14,14 +14,19 @@
* limitations under the License.
*/
-#include "mock/DisplayHardware/MockDisplaySurface.h"
+#include "MockHWComposer.h"
namespace android {
+
+// This will go away once HWComposer is moved into the "backend" library
+HWComposer::~HWComposer() = default;
+
namespace mock {
-// Explicit default instantiation is recommended.
-DisplaySurface::DisplaySurface() = default;
-DisplaySurface::~DisplaySurface() = default;
+// The Google Mock documentation recommends explicit non-header instantiations
+// for better compile time performance.
+HWComposer::HWComposer() = default;
+HWComposer::~HWComposer() = default;
} // namespace mock
} // namespace android
diff --git a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
new file mode 100644
index 0000000..ece412f
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <gmock/gmock.h>
+
+#include "LayerBE.h"
+
+#include "DisplayHardware/HWComposer.h"
+
+namespace android {
+namespace mock {
+
+class HWComposer : public android::HWComposer {
+public:
+ HWComposer();
+ ~HWComposer() override;
+
+ MOCK_METHOD2(registerCallback, void(HWC2::ComposerCallback*, int32_t));
+ MOCK_CONST_METHOD3(getDisplayIdentificationData,
+ bool(hwc2_display_t, uint8_t*, DisplayIdentificationData*));
+ MOCK_CONST_METHOD1(hasCapability, bool(HWC2::Capability));
+ MOCK_CONST_METHOD2(hasDisplayCapability,
+ bool(const std::optional<DisplayId>&, HWC2::DisplayCapability));
+
+ MOCK_METHOD3(allocateVirtualDisplay,
+ std::optional<DisplayId>(uint32_t, uint32_t, ui::PixelFormat*));
+ MOCK_METHOD1(createLayer, HWC2::Layer*(DisplayId));
+ MOCK_METHOD2(destroyLayer, void(DisplayId, HWC2::Layer*));
+ MOCK_METHOD2(prepare, status_t(DisplayId, std::vector<CompositionInfo>&));
+ MOCK_METHOD5(setClientTarget,
+ status_t(DisplayId, uint32_t, const sp<Fence>&, const sp<GraphicBuffer>&,
+ ui::Dataspace));
+ MOCK_METHOD1(presentAndGetReleaseFences, status_t(DisplayId));
+ MOCK_METHOD2(setPowerMode, status_t(DisplayId, int));
+ MOCK_METHOD2(setActiveConfig, status_t(DisplayId, size_t));
+ MOCK_METHOD2(setColorTransform, status_t(DisplayId, const mat4&));
+ MOCK_METHOD1(disconnectDisplay, void(DisplayId));
+ MOCK_CONST_METHOD1(hasDeviceComposition, bool(const std::optional<DisplayId>&));
+ MOCK_CONST_METHOD1(hasFlipClientTargetRequest, bool(const std::optional<DisplayId>&));
+ MOCK_CONST_METHOD1(hasClientComposition, bool(const std::optional<DisplayId>&));
+ MOCK_CONST_METHOD1(getPresentFence, sp<Fence>(DisplayId));
+ MOCK_CONST_METHOD2(getLayerReleaseFence, sp<Fence>(DisplayId, HWC2::Layer*));
+ MOCK_METHOD3(setOutputBuffer, status_t(DisplayId, const sp<Fence>&, const sp<GraphicBuffer>&));
+ MOCK_METHOD1(clearReleaseFences, void(DisplayId));
+ MOCK_METHOD2(getHdrCapabilities, status_t(DisplayId, HdrCapabilities*));
+ MOCK_CONST_METHOD1(getSupportedPerFrameMetadata, int32_t(DisplayId));
+ MOCK_CONST_METHOD2(getRenderIntents, std::vector<ui::RenderIntent>(DisplayId, ui::ColorMode));
+ MOCK_METHOD2(getDataspaceSaturationMatrix, mat4(DisplayId, ui::Dataspace));
+ MOCK_METHOD4(getDisplayedContentSamplingAttributes,
+ status_t(DisplayId, ui::PixelFormat*, ui::Dataspace*, uint8_t*));
+ MOCK_METHOD4(setDisplayContentSamplingEnabled, status_t(DisplayId, bool, uint8_t, uint64_t));
+ MOCK_METHOD4(getDisplayedContentSample,
+ status_t(DisplayId, uint64_t, uint64_t, DisplayedFrameStats*));
+
+ MOCK_METHOD2(onHotplug,
+ std::optional<DisplayIdentificationInfo>(hwc2_display_t, HWC2::Connection));
+ MOCK_METHOD2(onVsync, bool(hwc2_display_t, int64_t));
+ MOCK_METHOD2(setVsyncEnabled, void(DisplayId, HWC2::Vsync));
+ MOCK_CONST_METHOD1(getRefreshTimestamp, nsecs_t(DisplayId));
+ MOCK_CONST_METHOD1(isConnected, bool(DisplayId));
+ MOCK_CONST_METHOD1(getConfigs,
+ std::vector<std::shared_ptr<const HWC2::Display::Config>>(DisplayId));
+ MOCK_CONST_METHOD1(getActiveConfig, std::shared_ptr<const HWC2::Display::Config>(DisplayId));
+ MOCK_CONST_METHOD1(getActiveConfigIndex, int(DisplayId));
+ MOCK_CONST_METHOD1(getColorModes, std::vector<ui::ColorMode>(DisplayId));
+ MOCK_METHOD3(setActiveColorMode, status_t(DisplayId, ui::ColorMode, ui::RenderIntent));
+ MOCK_CONST_METHOD0(isUsingVrComposer, bool());
+
+ MOCK_CONST_METHOD1(dump, void(std::string&));
+ MOCK_CONST_METHOD0(getComposer, android::Hwc2::Composer*());
+ MOCK_CONST_METHOD1(getHwcDisplayId, std::optional<hwc2_display_t>(int32_t));
+ MOCK_CONST_METHOD0(getInternalHwcDisplayId, std::optional<hwc2_display_t>());
+ MOCK_CONST_METHOD0(getExternalHwcDisplayId, std::optional<hwc2_display_t>());
+ MOCK_CONST_METHOD1(toPhysicalDisplayId, std::optional<DisplayId>(hwc2_display_t));
+ MOCK_CONST_METHOD1(fromPhysicalDisplayId, std::optional<hwc2_display_t>(DisplayId));
+};
+
+} // namespace mock
+} // namespace android
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
new file mode 100644
index 0000000..0a929ac
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
@@ -0,0 +1,47 @@
+/*
+ * 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 <compositionengine/impl/OutputLayer.h>
+#include <compositionengine/mock/Layer.h>
+#include <compositionengine/mock/LayerFE.h>
+#include <compositionengine/mock/Output.h>
+#include <gtest/gtest.h>
+
+namespace android::compositionengine {
+namespace {
+
+using testing::StrictMock;
+
+class OutputLayerTest : public testing::Test {
+public:
+ ~OutputLayerTest() override = default;
+
+ compositionengine::mock::Output mOutput;
+ std::shared_ptr<compositionengine::mock::Layer> mLayer{
+ new StrictMock<compositionengine::mock::Layer>()};
+ sp<compositionengine::mock::LayerFE> mLayerFE{
+ new StrictMock<compositionengine::mock::LayerFE>()};
+ impl::OutputLayer mOutputLayer{mOutput, mLayer, mLayerFE};
+};
+
+/* ------------------------------------------------------------------------
+ * Basic construction
+ */
+
+TEST_F(OutputLayerTest, canInstantiateOutputLayer) {}
+
+} // namespace
+} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
new file mode 100644
index 0000000..cc1211b
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
@@ -0,0 +1,373 @@
+/*
+ * 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 <cmath>
+
+#include <compositionengine/impl/Output.h>
+#include <compositionengine/mock/CompositionEngine.h>
+#include <compositionengine/mock/DisplayColorProfile.h>
+#include <compositionengine/mock/Layer.h>
+#include <compositionengine/mock/LayerFE.h>
+#include <compositionengine/mock/OutputLayer.h>
+#include <compositionengine/mock/RenderSurface.h>
+#include <gtest/gtest.h>
+#include <ui/Rect.h>
+#include <ui/Region.h>
+
+#include "RegionMatcher.h"
+#include "TransformMatcher.h"
+
+namespace android::compositionengine {
+namespace {
+
+using testing::Return;
+using testing::ReturnRef;
+using testing::StrictMock;
+
+class OutputTest : public testing::Test {
+public:
+ OutputTest() {
+ mOutput.setDisplayColorProfileForTest(
+ std::unique_ptr<DisplayColorProfile>(mDisplayColorProfile));
+ mOutput.setRenderSurfaceForTest(std::unique_ptr<RenderSurface>(mRenderSurface));
+ }
+ ~OutputTest() override = default;
+
+ StrictMock<mock::CompositionEngine> mCompositionEngine;
+ mock::DisplayColorProfile* mDisplayColorProfile = new StrictMock<mock::DisplayColorProfile>();
+ mock::RenderSurface* mRenderSurface = new StrictMock<mock::RenderSurface>();
+ impl::Output mOutput{mCompositionEngine};
+};
+
+/* ------------------------------------------------------------------------
+ * Basic construction
+ */
+
+TEST_F(OutputTest, canInstantiateOutput) {
+ // The validation check checks each required component.
+ EXPECT_CALL(*mDisplayColorProfile, isValid()).WillOnce(Return(true));
+ EXPECT_CALL(*mRenderSurface, isValid()).WillOnce(Return(true));
+
+ EXPECT_TRUE(mOutput.isValid());
+
+ // If we take away the required components, it is no longer valid.
+ mOutput.setRenderSurfaceForTest(std::unique_ptr<RenderSurface>());
+
+ EXPECT_CALL(*mDisplayColorProfile, isValid()).WillOnce(Return(true));
+
+ EXPECT_FALSE(mOutput.isValid());
+}
+
+/* ------------------------------------------------------------------------
+ * Output::setCompositionEnabled()
+ */
+
+TEST_F(OutputTest, setCompositionEnabledDoesNothingIfAlreadyEnabled) {
+ const Rect displaySize{100, 200};
+ mOutput.editState().bounds = displaySize;
+ mOutput.editState().isEnabled = true;
+
+ mOutput.setCompositionEnabled(true);
+
+ EXPECT_TRUE(mOutput.getState().isEnabled);
+ EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region()));
+}
+
+TEST_F(OutputTest, setCompositionEnabledSetsEnabledAndDirtiesEntireOutput) {
+ const Rect displaySize{100, 200};
+ mOutput.editState().bounds = displaySize;
+ mOutput.editState().isEnabled = false;
+
+ mOutput.setCompositionEnabled(true);
+
+ EXPECT_TRUE(mOutput.getState().isEnabled);
+ EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region(displaySize)));
+}
+
+TEST_F(OutputTest, setCompositionEnabledSetsDisabledAndDirtiesEntireOutput) {
+ const Rect displaySize{100, 200};
+ mOutput.editState().bounds = displaySize;
+ mOutput.editState().isEnabled = true;
+
+ mOutput.setCompositionEnabled(false);
+
+ EXPECT_FALSE(mOutput.getState().isEnabled);
+ EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region(displaySize)));
+}
+
+/* ------------------------------------------------------------------------
+ * Output::setProjection()
+ */
+
+TEST_F(OutputTest, setProjectionTriviallyWorks) {
+ const ui::Transform transform{ui::Transform::ROT_180};
+ const int32_t orientation = 123;
+ const Rect frame{1, 2, 3, 4};
+ const Rect viewport{5, 6, 7, 8};
+ const Rect scissor{9, 10, 11, 12};
+ const bool needsFiltering = true;
+
+ mOutput.setProjection(transform, orientation, frame, viewport, scissor, needsFiltering);
+
+ EXPECT_THAT(mOutput.getState().transform, TransformEq(transform));
+ EXPECT_EQ(orientation, mOutput.getState().orientation);
+ EXPECT_EQ(frame, mOutput.getState().frame);
+ EXPECT_EQ(viewport, mOutput.getState().viewport);
+ EXPECT_EQ(scissor, mOutput.getState().scissor);
+ EXPECT_EQ(needsFiltering, mOutput.getState().needsFiltering);
+}
+
+/* ------------------------------------------------------------------------
+ * Output::setBounds()
+ */
+
+TEST_F(OutputTest, setBoundsSetsSizeAndDirtiesEntireOutput) {
+ const ui::Size displaySize{100, 200};
+
+ EXPECT_CALL(*mRenderSurface, setDisplaySize(displaySize)).Times(1);
+ EXPECT_CALL(*mRenderSurface, getSize()).WillOnce(ReturnRef(displaySize));
+
+ mOutput.setBounds(displaySize);
+
+ EXPECT_EQ(Rect(displaySize), mOutput.getState().bounds);
+
+ EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region(Rect(displaySize))));
+}
+
+/* ------------------------------------------------------------------------
+ * Output::setLayerStackFilter()
+ */
+
+TEST_F(OutputTest, setLayerStackFilterSetsFilterAndDirtiesEntireOutput) {
+ const Rect displaySize{100, 200};
+ mOutput.editState().bounds = displaySize;
+
+ const uint32_t layerStack = 123u;
+ mOutput.setLayerStackFilter(layerStack, true);
+
+ EXPECT_TRUE(mOutput.getState().layerStackInternal);
+ EXPECT_EQ(layerStack, mOutput.getState().layerStackId);
+
+ EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region(displaySize)));
+}
+
+/* ------------------------------------------------------------------------
+ * Output::setColorTransform
+ */
+
+TEST_F(OutputTest, setColorTransformSetsTransform) {
+ // Identity matrix sets an identity state value
+ const mat4 identity;
+
+ mOutput.setColorTransform(identity);
+
+ EXPECT_EQ(HAL_COLOR_TRANSFORM_IDENTITY, mOutput.getState().colorTransform);
+
+ // Non-identity matrix sets a non-identity state value
+ const mat4 nonIdentity = mat4() * 2;
+
+ mOutput.setColorTransform(nonIdentity);
+
+ EXPECT_EQ(HAL_COLOR_TRANSFORM_ARBITRARY_MATRIX, mOutput.getState().colorTransform);
+}
+
+/* ------------------------------------------------------------------------
+ * Output::setColorMode
+ */
+
+TEST_F(OutputTest, setColorModeSetsModeUnlessNoChange) {
+ EXPECT_CALL(*mRenderSurface, setBufferDataspace(ui::Dataspace::SRGB)).Times(1);
+
+ mOutput.setColorMode(ui::ColorMode::BT2100_PQ, ui::Dataspace::SRGB,
+ ui::RenderIntent::TONE_MAP_COLORIMETRIC);
+
+ EXPECT_EQ(ui::ColorMode::BT2100_PQ, mOutput.getState().colorMode);
+ EXPECT_EQ(ui::Dataspace::SRGB, mOutput.getState().dataspace);
+ EXPECT_EQ(ui::RenderIntent::TONE_MAP_COLORIMETRIC, mOutput.getState().renderIntent);
+}
+
+/* ------------------------------------------------------------------------
+ * Output::setRenderSurface()
+ */
+
+TEST_F(OutputTest, setRenderSurfaceResetsBounds) {
+ const ui::Size newDisplaySize{640, 480};
+
+ mock::RenderSurface* renderSurface = new StrictMock<mock::RenderSurface>();
+ EXPECT_CALL(*renderSurface, getSize()).WillOnce(ReturnRef(newDisplaySize));
+
+ mOutput.setRenderSurface(std::unique_ptr<RenderSurface>(renderSurface));
+
+ EXPECT_EQ(Rect(newDisplaySize), mOutput.getState().bounds);
+}
+
+/* ------------------------------------------------------------------------
+ * Output::getPhysicalSpaceDirtyRegion()
+ */
+
+TEST_F(OutputTest, getPhysicalSpaceDirtyRegionWithRepaintEverythingTrue) {
+ const Rect displaySize{100, 200};
+ mOutput.editState().bounds = displaySize;
+ mOutput.editState().dirtyRegion.set(50, 300);
+
+ {
+ Region result = mOutput.getPhysicalSpaceDirtyRegion(true);
+
+ EXPECT_THAT(result, RegionEq(Region(displaySize)));
+ }
+
+ // For repaint everything == true, the returned value does not depend on the display
+ // rotation.
+ mOutput.editState().transform.set(ui::Transform::ROT_90, 0, 0);
+
+ {
+ Region result = mOutput.getPhysicalSpaceDirtyRegion(true);
+
+ EXPECT_THAT(result, RegionEq(Region(displaySize)));
+ }
+}
+
+TEST_F(OutputTest, getPhysicalSpaceDirtyRegionWithRepaintEverythingFalse) {
+ const Rect displaySize{100, 200};
+ mOutput.editState().bounds = displaySize;
+ mOutput.editState().dirtyRegion.set(50, 300);
+
+ {
+ Region result = mOutput.getPhysicalSpaceDirtyRegion(false);
+
+ // The dirtyRegion should be clipped to the display bounds.
+ EXPECT_THAT(result, RegionEq(Region(Rect(50, 200))));
+ }
+
+ mOutput.editState().transform.set(ui::Transform::ROT_90, displaySize.getWidth(),
+ displaySize.getHeight());
+
+ {
+ Region result = mOutput.getPhysicalSpaceDirtyRegion(false);
+
+ // The dirtyRegion should be rotated and clipped to the display bounds.
+ EXPECT_THAT(result, RegionEq(Region(Rect(100, 50))));
+ }
+}
+
+/* ------------------------------------------------------------------------
+ * Output::belongsInOutput()
+ */
+
+TEST_F(OutputTest, belongsInOutputFiltersAsExpected) {
+ const uint32_t layerStack1 = 123u;
+ const uint32_t layerStack2 = 456u;
+
+ // If the output accepts layerStack1 and internal-only layers....
+ mOutput.setLayerStackFilter(layerStack1, true);
+
+ // Any layer with layerStack1 belongs to it, internal-only or not.
+ EXPECT_TRUE(mOutput.belongsInOutput(layerStack1, false));
+ EXPECT_TRUE(mOutput.belongsInOutput(layerStack1, true));
+ EXPECT_FALSE(mOutput.belongsInOutput(layerStack2, true));
+ EXPECT_FALSE(mOutput.belongsInOutput(layerStack2, false));
+
+ // If the output accepts layerStack21 but not internal-only layers...
+ mOutput.setLayerStackFilter(layerStack1, false);
+
+ // Only non-internal layers with layerStack1 belong to it.
+ EXPECT_TRUE(mOutput.belongsInOutput(layerStack1, false));
+ EXPECT_FALSE(mOutput.belongsInOutput(layerStack1, true));
+ EXPECT_FALSE(mOutput.belongsInOutput(layerStack2, true));
+ EXPECT_FALSE(mOutput.belongsInOutput(layerStack2, false));
+}
+
+/* ------------------------------------------------------------------------
+ * Output::getOutputLayerForLayer()
+ */
+
+TEST_F(OutputTest, getOutputLayerForLayerWorks) {
+ mock::OutputLayer* outputLayer1 = new StrictMock<mock::OutputLayer>();
+ mock::OutputLayer* outputLayer2 = new StrictMock<mock::OutputLayer>();
+
+ Output::OutputLayers outputLayers;
+ outputLayers.emplace_back(std::unique_ptr<OutputLayer>(outputLayer1));
+ outputLayers.emplace_back(nullptr);
+ outputLayers.emplace_back(std::unique_ptr<OutputLayer>(outputLayer2));
+ mOutput.setOutputLayersOrderedByZ(std::move(outputLayers));
+
+ StrictMock<mock::Layer> layer;
+ StrictMock<mock::Layer> otherLayer;
+
+ // If the input layer matches the first OutputLayer, it will be returned.
+ EXPECT_CALL(*outputLayer1, getLayer()).WillOnce(ReturnRef(layer));
+ EXPECT_EQ(outputLayer1, mOutput.getOutputLayerForLayer(&layer));
+
+ // If the input layer matches the second OutputLayer, it will be returned.
+ EXPECT_CALL(*outputLayer1, getLayer()).WillOnce(ReturnRef(otherLayer));
+ EXPECT_CALL(*outputLayer2, getLayer()).WillOnce(ReturnRef(layer));
+ EXPECT_EQ(outputLayer2, mOutput.getOutputLayerForLayer(&layer));
+
+ // If the input layer does not match an output layer, null will be returned.
+ EXPECT_CALL(*outputLayer1, getLayer()).WillOnce(ReturnRef(otherLayer));
+ EXPECT_CALL(*outputLayer2, getLayer()).WillOnce(ReturnRef(otherLayer));
+ EXPECT_EQ(nullptr, mOutput.getOutputLayerForLayer(&layer));
+}
+
+/* ------------------------------------------------------------------------
+ * Output::getOrCreateOutputLayer()
+ */
+
+TEST_F(OutputTest, getOrCreateOutputLayerWorks) {
+ mock::OutputLayer* existingOutputLayer = new StrictMock<mock::OutputLayer>();
+
+ Output::OutputLayers outputLayers;
+ outputLayers.emplace_back(nullptr);
+ outputLayers.emplace_back(std::unique_ptr<OutputLayer>(existingOutputLayer));
+ mOutput.setOutputLayersOrderedByZ(std::move(outputLayers));
+
+ std::shared_ptr<mock::Layer> layer{new StrictMock<mock::Layer>()};
+ sp<LayerFE> layerFE{new StrictMock<mock::LayerFE>()};
+
+ StrictMock<mock::Layer> otherLayer;
+
+ {
+ // If there is no OutputLayer corresponding to the input layer, a
+ // new OutputLayer is constructed and returned.
+ EXPECT_CALL(*existingOutputLayer, getLayer()).WillOnce(ReturnRef(otherLayer));
+ auto result = mOutput.getOrCreateOutputLayer(layer, layerFE);
+ EXPECT_NE(existingOutputLayer, result.get());
+ EXPECT_TRUE(result.get() != nullptr);
+ EXPECT_EQ(layer.get(), &result->getLayer());
+ EXPECT_EQ(layerFE.get(), &result->getLayerFE());
+
+ // The entries in the ordered array should be unchanged.
+ auto& outputLayers = mOutput.getOutputLayersOrderedByZ();
+ EXPECT_EQ(nullptr, outputLayers[0].get());
+ EXPECT_EQ(existingOutputLayer, outputLayers[1].get());
+ }
+
+ {
+ // If there is an existing OutputLayer for the requested layer, an owned
+ // pointer is returned
+ EXPECT_CALL(*existingOutputLayer, getLayer()).WillOnce(ReturnRef(*layer));
+ auto result = mOutput.getOrCreateOutputLayer(layer, layerFE);
+ EXPECT_EQ(existingOutputLayer, result.get());
+
+ // The corresponding entry in the ordered array should be cleared.
+ auto& outputLayers = mOutput.getOutputLayersOrderedByZ();
+ EXPECT_EQ(nullptr, outputLayers[0].get());
+ EXPECT_EQ(nullptr, outputLayers[1].get());
+ }
+}
+
+} // namespace
+} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/tests/RegionMatcher.h b/services/surfaceflinger/CompositionEngine/tests/RegionMatcher.h
new file mode 100644
index 0000000..5a4efa9
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/tests/RegionMatcher.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <gmock/gmock.h>
+
+namespace {
+
+// Checks for a region match
+MATCHER_P(RegionEq, expected, "") {
+ std::string buf;
+ buf.append("Regions are not equal\n");
+ expected.dump(buf, "expected region");
+ arg.dump(buf, "actual region");
+ *result_listener << buf;
+
+ size_t expectedRectCount = 0;
+ android::Rect const* expectedRects = expected.getArray(&expectedRectCount);
+ size_t actualRectCount = 0;
+ android::Rect const* actualRects = arg.getArray(&actualRectCount);
+
+ if (expectedRectCount != actualRectCount) return false;
+ for (size_t i = 0; i < expectedRectCount; i++) {
+ if (expectedRects[i] != actualRects[i]) return false;
+ }
+ return true;
+}
+
+} // namespace
diff --git a/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp b/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp
new file mode 100644
index 0000000..13cc663
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp
@@ -0,0 +1,504 @@
+/*
+ * 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 <cstdarg>
+#include <cstdint>
+
+#include <compositionengine/RenderSurfaceCreationArgs.h>
+#include <compositionengine/impl/RenderSurface.h>
+#include <compositionengine/mock/CompositionEngine.h>
+#include <compositionengine/mock/Display.h>
+#include <compositionengine/mock/DisplaySurface.h>
+#include <gtest/gtest.h>
+#include <renderengine/mock/RenderEngine.h>
+#include <system/window.h>
+#include <ui/ANativeObjectBase.h>
+
+#include "MockHWComposer.h"
+
+namespace android::compositionengine {
+namespace {
+
+/* ------------------------------------------------------------------------
+ * MockNativeWindow
+ *
+ * An intentionally simplified Mock which implements a minimal subset of the full
+ * ANativeWindow interface.
+ */
+
+class MockNativeWindow : public ANativeObjectBase<ANativeWindow, MockNativeWindow, RefBase> {
+public:
+ MockNativeWindow() {
+ ANativeWindow::setSwapInterval = &forwardSetSwapInterval;
+ ANativeWindow::dequeueBuffer = &forwardDequeueBuffer;
+ ANativeWindow::cancelBuffer = &forwardCancelBuffer;
+ ANativeWindow::queueBuffer = &forwardQueueBuffer;
+ ANativeWindow::query = &forwardQuery;
+ ANativeWindow::perform = &forwardPerform;
+
+ ANativeWindow::dequeueBuffer_DEPRECATED = &forwardDequeueBufferDeprecated;
+ ANativeWindow::cancelBuffer_DEPRECATED = &forwardCancelBufferDeprecated;
+ ANativeWindow::lockBuffer_DEPRECATED = &forwardLockBufferDeprecated;
+ ANativeWindow::queueBuffer_DEPRECATED = &forwardQueueBufferDeprecated;
+ }
+
+ MOCK_METHOD1(setSwapInterval, int(int));
+ MOCK_METHOD2(dequeueBuffer, int(struct ANativeWindowBuffer**, int*));
+ MOCK_METHOD2(cancelBuffer, int(struct ANativeWindowBuffer*, int));
+ MOCK_METHOD2(queueBuffer, int(struct ANativeWindowBuffer*, int));
+ MOCK_CONST_METHOD2(query, int(int, int*));
+ MOCK_METHOD1(connect, int(int));
+ MOCK_METHOD1(lockBuffer_DEPRECATED, int(struct ANativeWindowBuffer*));
+ MOCK_METHOD1(setBuffersFormat, int(PixelFormat));
+ MOCK_METHOD1(setBuffersDataSpace, int(ui::Dataspace));
+ MOCK_METHOD1(setUsage, int(uint64_t));
+
+ static void unexpectedCall(...) { LOG_ALWAYS_FATAL("Unexpected ANativeWindow API call"); }
+
+ static int forwardSetSwapInterval(ANativeWindow* window, int interval) {
+ return getSelf(window)->setSwapInterval(interval);
+ }
+
+ static int forwardDequeueBuffer(ANativeWindow* window, ANativeWindowBuffer** buffer,
+ int* fenceFd) {
+ return getSelf(window)->dequeueBuffer(buffer, fenceFd);
+ }
+
+ static int forwardCancelBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer,
+ int fenceFd) {
+ return getSelf(window)->cancelBuffer(buffer, fenceFd);
+ }
+
+ static int forwardQueueBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer, int fenceFd) {
+ return getSelf(window)->queueBuffer(buffer, fenceFd);
+ }
+
+ static int forwardQuery(const ANativeWindow* window, int what, int* value) {
+ return getSelf(window)->query(what, value);
+ }
+
+ static int forwardPerform(ANativeWindow* window, int operation, ...) {
+ va_list args;
+ va_start(args, operation);
+ int result = NO_ERROR;
+ switch (operation) {
+ case NATIVE_WINDOW_API_CONNECT: {
+ int api = va_arg(args, int);
+ result = getSelf(window)->connect(api);
+ break;
+ }
+ case NATIVE_WINDOW_SET_BUFFERS_FORMAT: {
+ PixelFormat format = va_arg(args, PixelFormat);
+ result = getSelf(window)->setBuffersFormat(format);
+ break;
+ }
+ case NATIVE_WINDOW_SET_BUFFERS_DATASPACE: {
+ ui::Dataspace dataspace = static_cast<ui::Dataspace>(va_arg(args, int));
+ result = getSelf(window)->setBuffersDataSpace(dataspace);
+ break;
+ }
+ case NATIVE_WINDOW_SET_USAGE: {
+ // Note: Intentionally widens usage from 32 to 64 bits so we
+ // just have one implementation.
+ uint64_t usage = va_arg(args, uint32_t);
+ result = getSelf(window)->setUsage(usage);
+ break;
+ }
+ case NATIVE_WINDOW_SET_USAGE64: {
+ uint64_t usage = va_arg(args, uint64_t);
+ result = getSelf(window)->setUsage(usage);
+ break;
+ }
+ default:
+ LOG_ALWAYS_FATAL("Unexpected operation %d", operation);
+ break;
+ }
+
+ va_end(args);
+ return result;
+ }
+
+ static int forwardDequeueBufferDeprecated(ANativeWindow* window, ANativeWindowBuffer** buffer) {
+ int ignoredFenceFd = -1;
+ return getSelf(window)->dequeueBuffer(buffer, &ignoredFenceFd);
+ }
+
+ static int forwardCancelBufferDeprecated(ANativeWindow* window, ANativeWindowBuffer* buffer) {
+ return getSelf(window)->cancelBuffer(buffer, -1);
+ }
+
+ static int forwardLockBufferDeprecated(ANativeWindow* window, ANativeWindowBuffer* buffer) {
+ return getSelf(window)->lockBuffer_DEPRECATED(buffer);
+ }
+
+ static int forwardQueueBufferDeprecated(ANativeWindow* window, ANativeWindowBuffer* buffer) {
+ return getSelf(window)->queueBuffer(buffer, -1);
+ }
+};
+
+/* ------------------------------------------------------------------------
+ * RenderSurfaceTest
+ */
+
+constexpr int32_t DEFAULT_DISPLAY_WIDTH = 1920;
+constexpr int32_t DEFAULT_DISPLAY_HEIGHT = 1080;
+constexpr std::optional<DisplayId> DEFAULT_DISPLAY_ID = std::make_optional(DisplayId{123u});
+const std::string DEFAULT_DISPLAY_NAME = "Mock Display";
+
+using testing::_;
+using testing::ByMove;
+using testing::DoAll;
+using testing::Ref;
+using testing::Return;
+using testing::ReturnRef;
+using testing::SetArgPointee;
+using testing::StrictMock;
+
+class RenderSurfaceTest : public testing::Test {
+public:
+ RenderSurfaceTest() {
+ EXPECT_CALL(mDisplay, getId()).WillRepeatedly(ReturnRef(DEFAULT_DISPLAY_ID));
+ EXPECT_CALL(mDisplay, getName()).WillRepeatedly(ReturnRef(DEFAULT_DISPLAY_NAME));
+ EXPECT_CALL(mCompositionEngine, getHwComposer).WillRepeatedly(ReturnRef(mHwComposer));
+ EXPECT_CALL(mCompositionEngine, getRenderEngine).WillRepeatedly(ReturnRef(mRenderEngine));
+ }
+ ~RenderSurfaceTest() override = default;
+
+ StrictMock<android::mock::HWComposer> mHwComposer;
+ StrictMock<renderengine::mock::RenderEngine> mRenderEngine;
+ StrictMock<mock::CompositionEngine> mCompositionEngine;
+ StrictMock<mock::Display> mDisplay;
+ sp<MockNativeWindow> mNativeWindow = new StrictMock<MockNativeWindow>();
+ sp<mock::DisplaySurface> mDisplaySurface = new StrictMock<mock::DisplaySurface>();
+ impl::RenderSurface mSurface{mCompositionEngine, mDisplay,
+ RenderSurfaceCreationArgs{DEFAULT_DISPLAY_WIDTH,
+ DEFAULT_DISPLAY_HEIGHT, mNativeWindow,
+ mDisplaySurface}};
+};
+
+/* ------------------------------------------------------------------------
+ * Basic construction
+ */
+
+TEST_F(RenderSurfaceTest, canInstantiate) {
+ EXPECT_TRUE(mSurface.isValid());
+}
+
+/* ------------------------------------------------------------------------
+ * RenderSurface::initialize()
+ */
+
+TEST_F(RenderSurfaceTest, initializeConfiguresNativeWindow) {
+ EXPECT_CALL(*mNativeWindow, connect(NATIVE_WINDOW_API_EGL)).WillOnce(Return(NO_ERROR));
+ EXPECT_CALL(*mNativeWindow, setBuffersFormat(HAL_PIXEL_FORMAT_RGBA_8888))
+ .WillOnce(Return(NO_ERROR));
+ EXPECT_CALL(*mNativeWindow, setUsage(GRALLOC_USAGE_HW_RENDER)).WillOnce(Return(NO_ERROR));
+
+ mSurface.initialize();
+}
+
+/* ------------------------------------------------------------------------
+ * RenderSurface::getSize()
+ */
+
+TEST_F(RenderSurfaceTest, sizeReturnsConstructedSize) {
+ const ui::Size expected{DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT};
+
+ EXPECT_EQ(expected, mSurface.getSize());
+}
+
+/* ------------------------------------------------------------------------
+ * RenderSurface::getClientTargetAcquireFence()
+ */
+
+TEST_F(RenderSurfaceTest, getClientTargetAcquireFenceForwardsCall) {
+ sp<Fence> fence = new Fence();
+
+ EXPECT_CALL(*mDisplaySurface, getClientTargetAcquireFence()).WillOnce(ReturnRef(fence));
+
+ EXPECT_EQ(fence.get(), mSurface.getClientTargetAcquireFence().get());
+}
+
+/* ------------------------------------------------------------------------
+ * RenderSurface::setDisplaySize()
+ */
+
+TEST_F(RenderSurfaceTest, setDisplaySizeAppliesChange) {
+ EXPECT_CALL(*mDisplaySurface, resizeBuffers(640, 480)).Times(1);
+
+ mSurface.setDisplaySize(ui::Size(640, 480));
+}
+
+/* ------------------------------------------------------------------------
+ * RenderSurface::setBufferDataspace()
+ */
+
+TEST_F(RenderSurfaceTest, setBufferDataspaceAppliesChange) {
+ EXPECT_CALL(*mNativeWindow, setBuffersDataSpace(ui::Dataspace::DISPLAY_P3))
+ .WillOnce(Return(NO_ERROR));
+
+ mSurface.setBufferDataspace(ui::Dataspace::DISPLAY_P3);
+}
+
+/* ------------------------------------------------------------------------
+ * RenderSurface::setProtected()
+ */
+
+TEST_F(RenderSurfaceTest, setProtectedTrueEnablesProtection) {
+ EXPECT_CALL(*mNativeWindow, setUsage(GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_PROTECTED))
+ .WillOnce(Return(NO_ERROR));
+
+ mSurface.setProtected(true);
+}
+
+TEST_F(RenderSurfaceTest, setProtectedFalseDisablesProtection) {
+ EXPECT_CALL(*mNativeWindow, setUsage(GRALLOC_USAGE_HW_RENDER)).WillOnce(Return(NO_ERROR));
+
+ mSurface.setProtected(false);
+}
+
+/* ------------------------------------------------------------------------
+ * RenderSurface::beginFrame()
+ */
+
+TEST_F(RenderSurfaceTest, beginFrameAppliesChange) {
+ EXPECT_CALL(*mDisplaySurface, beginFrame(true)).WillOnce(Return(NO_ERROR));
+
+ EXPECT_EQ(NO_ERROR, mSurface.beginFrame(true));
+}
+
+/* ------------------------------------------------------------------------
+ * RenderSurface::prepareFrame()
+ */
+
+TEST_F(RenderSurfaceTest, prepareFrameTakesEarlyOutOnHwcError) {
+ std::vector<CompositionInfo> data;
+
+ EXPECT_CALL(mHwComposer, prepare(*DEFAULT_DISPLAY_ID, Ref(data)))
+ .WillOnce(Return(INVALID_OPERATION));
+
+ EXPECT_EQ(INVALID_OPERATION, mSurface.prepareFrame(data));
+}
+
+TEST_F(RenderSurfaceTest, prepareFrameHandlesMixedComposition) {
+ std::vector<CompositionInfo> data;
+ EXPECT_CALL(mHwComposer, prepare(*DEFAULT_DISPLAY_ID, Ref(data))).WillOnce(Return(NO_ERROR));
+ EXPECT_CALL(mHwComposer, hasClientComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(true));
+ EXPECT_CALL(mHwComposer, hasDeviceComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(true));
+
+ EXPECT_CALL(*mDisplaySurface, prepareFrame(DisplaySurface::COMPOSITION_MIXED))
+ .WillOnce(Return(INVALID_OPERATION));
+
+ EXPECT_EQ(INVALID_OPERATION, mSurface.prepareFrame(data));
+}
+
+TEST_F(RenderSurfaceTest, prepareFrameHandlesOnlyGlesComposition) {
+ std::vector<CompositionInfo> data;
+
+ EXPECT_CALL(mHwComposer, prepare(*DEFAULT_DISPLAY_ID, Ref(data))).WillOnce(Return(NO_ERROR));
+ EXPECT_CALL(mHwComposer, hasClientComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(true));
+ EXPECT_CALL(mHwComposer, hasDeviceComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(false));
+
+ EXPECT_CALL(*mDisplaySurface, prepareFrame(DisplaySurface::COMPOSITION_GLES))
+ .WillOnce(Return(NO_ERROR));
+
+ EXPECT_EQ(NO_ERROR, mSurface.prepareFrame(data));
+}
+
+TEST_F(RenderSurfaceTest, prepareFrameHandlesOnlyHwcComposition) {
+ std::vector<CompositionInfo> data;
+
+ EXPECT_CALL(mHwComposer, prepare(*DEFAULT_DISPLAY_ID, Ref(data))).WillOnce(Return(NO_ERROR));
+ EXPECT_CALL(mHwComposer, hasClientComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(false));
+ EXPECT_CALL(mHwComposer, hasDeviceComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(true));
+
+ EXPECT_CALL(*mDisplaySurface, prepareFrame(DisplaySurface::COMPOSITION_HWC))
+ .WillOnce(Return(NO_ERROR));
+
+ EXPECT_EQ(NO_ERROR, mSurface.prepareFrame(data));
+}
+
+TEST_F(RenderSurfaceTest, prepareFrameHandlesNoComposition) {
+ std::vector<CompositionInfo> data;
+
+ EXPECT_CALL(mHwComposer, prepare(*DEFAULT_DISPLAY_ID, Ref(data))).WillOnce(Return(NO_ERROR));
+ EXPECT_CALL(mHwComposer, hasClientComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(false));
+ EXPECT_CALL(mHwComposer, hasDeviceComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(false));
+
+ EXPECT_CALL(*mDisplaySurface, prepareFrame(DisplaySurface::COMPOSITION_HWC))
+ .WillOnce(Return(NO_ERROR));
+
+ EXPECT_EQ(NO_ERROR, mSurface.prepareFrame(data));
+}
+
+/* ------------------------------------------------------------------------
+ * RenderSurface::dequeueBuffer()
+ */
+
+TEST_F(RenderSurfaceTest, dequeueBufferObtainsABuffer) {
+ sp<GraphicBuffer> buffer = new GraphicBuffer();
+
+ EXPECT_CALL(*mNativeWindow, dequeueBuffer(_, _))
+ .WillOnce(
+ DoAll(SetArgPointee<0>(buffer.get()), SetArgPointee<1>(-1), Return(NO_ERROR)));
+
+ EXPECT_EQ(buffer.get(), mSurface.dequeueBuffer().get());
+
+ EXPECT_EQ(buffer.get(), mSurface.mutableGraphicBufferForTest().get());
+}
+
+/* ------------------------------------------------------------------------
+ * RenderSurface::queueBuffer()
+ */
+
+TEST_F(RenderSurfaceTest, queueBufferHandlesNoClientComposition) {
+ sp<GraphicBuffer> buffer = new GraphicBuffer();
+ mSurface.mutableGraphicBufferForTest() = buffer;
+
+ EXPECT_CALL(mHwComposer, hasClientComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(false));
+ EXPECT_CALL(mHwComposer, hasFlipClientTargetRequest(DEFAULT_DISPLAY_ID))
+ .WillOnce(Return(false));
+ EXPECT_CALL(*mDisplaySurface, advanceFrame()).Times(1);
+
+ mSurface.queueBuffer();
+
+ EXPECT_EQ(buffer.get(), mSurface.mutableGraphicBufferForTest().get());
+}
+
+TEST_F(RenderSurfaceTest, queueBufferHandlesClientComposition) {
+ sp<GraphicBuffer> buffer = new GraphicBuffer();
+ mSurface.mutableGraphicBufferForTest() = buffer;
+
+ EXPECT_CALL(mHwComposer, hasClientComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(true));
+ EXPECT_CALL(*mNativeWindow, queueBuffer(buffer->getNativeBuffer(), -1))
+ .WillOnce(Return(NO_ERROR));
+ EXPECT_CALL(*mDisplaySurface, advanceFrame()).Times(1);
+
+ mSurface.queueBuffer();
+
+ EXPECT_EQ(nullptr, mSurface.mutableGraphicBufferForTest().get());
+}
+
+TEST_F(RenderSurfaceTest, queueBufferHandlesFlipClientTargetRequest) {
+ sp<GraphicBuffer> buffer = new GraphicBuffer();
+ mSurface.mutableGraphicBufferForTest() = buffer;
+
+ EXPECT_CALL(mHwComposer, hasClientComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(false));
+ EXPECT_CALL(mHwComposer, hasFlipClientTargetRequest(DEFAULT_DISPLAY_ID)).WillOnce(Return(true));
+ EXPECT_CALL(*mNativeWindow, queueBuffer(buffer->getNativeBuffer(), -1))
+ .WillOnce(Return(NO_ERROR));
+ EXPECT_CALL(*mDisplaySurface, advanceFrame()).Times(1);
+
+ mSurface.queueBuffer();
+
+ EXPECT_EQ(nullptr, mSurface.mutableGraphicBufferForTest().get());
+}
+
+TEST_F(RenderSurfaceTest, queueBufferHandlesFlipClientTargetRequestWithNoBufferYetDequeued) {
+ sp<GraphicBuffer> buffer = new GraphicBuffer();
+
+ EXPECT_CALL(mHwComposer, hasClientComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(false));
+ EXPECT_CALL(mHwComposer, hasFlipClientTargetRequest(DEFAULT_DISPLAY_ID)).WillOnce(Return(true));
+ EXPECT_CALL(*mNativeWindow, dequeueBuffer(_, _))
+ .WillOnce(
+ DoAll(SetArgPointee<0>(buffer.get()), SetArgPointee<1>(-1), Return(NO_ERROR)));
+ EXPECT_CALL(*mNativeWindow, queueBuffer(buffer->getNativeBuffer(), -1))
+ .WillOnce(Return(NO_ERROR));
+ EXPECT_CALL(*mDisplaySurface, advanceFrame()).Times(1);
+
+ mSurface.queueBuffer();
+
+ EXPECT_EQ(nullptr, mSurface.mutableGraphicBufferForTest().get());
+}
+
+TEST_F(RenderSurfaceTest, queueBufferHandlesNativeWindowQueueBufferFailureOnVirtualDisplay) {
+ sp<GraphicBuffer> buffer = new GraphicBuffer();
+ mSurface.mutableGraphicBufferForTest() = buffer;
+
+ EXPECT_CALL(mHwComposer, hasClientComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(true));
+ EXPECT_CALL(*mNativeWindow, queueBuffer(buffer->getNativeBuffer(), -1))
+ .WillOnce(Return(INVALID_OPERATION));
+ EXPECT_CALL(mDisplay, isVirtual()).WillOnce(Return(true));
+ EXPECT_CALL(*mNativeWindow, cancelBuffer(buffer->getNativeBuffer(), -1))
+ .WillOnce(Return(NO_ERROR));
+ EXPECT_CALL(*mDisplaySurface, advanceFrame()).Times(1);
+
+ mSurface.queueBuffer();
+
+ EXPECT_EQ(nullptr, mSurface.mutableGraphicBufferForTest().get());
+}
+
+/* ------------------------------------------------------------------------
+ * RenderSurface::onPresentDisplayCompleted()
+ */
+
+TEST_F(RenderSurfaceTest, onPresentDisplayCompletedForwardsSignal) {
+ EXPECT_CALL(*mDisplaySurface, onFrameCommitted()).Times(1);
+
+ mSurface.onPresentDisplayCompleted();
+}
+
+/* ------------------------------------------------------------------------
+ * RenderSurface::finishBuffer()
+ */
+
+TEST_F(RenderSurfaceTest, finishBufferJustFlushesRenderEngine) {
+ int fd = dup(1);
+
+ EXPECT_CALL(mRenderEngine, flush()).WillOnce(Return(ByMove(base::unique_fd(fd))));
+
+ mSurface.finishBuffer();
+
+ EXPECT_EQ(fd, mSurface.mutableBufferReadyForTest().release());
+}
+
+TEST_F(RenderSurfaceTest, finishBufferFlushesAndFinishesRenderEngine) {
+ EXPECT_CALL(mRenderEngine, flush()).WillOnce(Return(ByMove(base::unique_fd(-2))));
+ EXPECT_CALL(mRenderEngine, finish()).Times(1);
+
+ mSurface.finishBuffer();
+
+ EXPECT_EQ(-2, mSurface.mutableBufferReadyForTest().release());
+}
+
+/* ------------------------------------------------------------------------
+ * RenderSurface::setViewportAndProjection()
+ */
+
+TEST_F(RenderSurfaceTest, setViewportAndProjectionAppliesChang) {
+ mSurface.setSizeForTest(ui::Size(100, 200));
+
+ EXPECT_CALL(mRenderEngine,
+ setViewportAndProjection(100, 200, Rect(100, 200), ui::Transform::ROT_0))
+ .Times(1);
+
+ mSurface.setViewportAndProjection();
+}
+
+/* ------------------------------------------------------------------------
+ * RenderSurface::flip()
+ */
+
+TEST_F(RenderSurfaceTest, flipForwardsSignal) {
+ mSurface.setPageFlipCountForTest(500);
+
+ mSurface.flip();
+
+ EXPECT_EQ(501, mSurface.getPageFlipCount());
+}
+
+} // namespace
+} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/tests/TransformMatcher.h b/services/surfaceflinger/CompositionEngine/tests/TransformMatcher.h
new file mode 100644
index 0000000..ea07bed
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/tests/TransformMatcher.h
@@ -0,0 +1,46 @@
+/*
+ * 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 <gmock/gmock.h>
+
+namespace {
+
+// Check for a transform match
+MATCHER_P(TransformEq, expected, "") {
+ std::string buf;
+ buf.append("Transforms are not equal\n");
+ expected.dump(buf, "expected transform");
+ arg.dump(buf, "actual transform");
+ *result_listener << buf;
+
+ const float TOLERANCE = 1e-3f;
+
+ for (int i = 0; i < 3; i++) {
+ for (int j = 0; j < 3; j++) {
+ if (std::fabs(expected[i][j] - arg[i][j]) > TOLERANCE) {
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+} // namespace
diff --git a/services/surfaceflinger/ContainerLayer.h b/services/surfaceflinger/ContainerLayer.h
index 6c4f7c8..413844b 100644
--- a/services/surfaceflinger/ContainerLayer.h
+++ b/services/surfaceflinger/ContainerLayer.h
@@ -31,7 +31,7 @@
const char* getTypeId() const override { return "ContainerLayer"; }
void onDraw(const RenderArea& renderArea, const Region& clip,
bool useIdentityTransform) override;
- bool isVisible() const override EXCLUDES(mStateMutex);
+ bool isVisible() const override;
void setPerFrameData(DisplayId displayId, const ui::Transform& transform, const Rect& viewport,
int32_t supportedPerFrameMetadata) override;
diff --git a/services/surfaceflinger/DdmConnection.cpp b/services/surfaceflinger/DdmConnection.cpp
deleted file mode 100644
index 35d55f5..0000000
--- a/services/surfaceflinger/DdmConnection.cpp
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * Copyright (C) 2011 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 <dlfcn.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <log/log.h>
-
-#include "jni.h"
-#include "DdmConnection.h"
-
-namespace android {
-
-void DdmConnection_start(const char* name) {
- ALOGI("DdmConnection_start");
- DdmConnection::start(name);
-}
-
-void DdmConnection::start(const char* name) {
- JavaVM* vm;
- JNIEnv* env;
-
- // start a VM
- JavaVMInitArgs args;
- JavaVMOption opt;
-
- opt.optionString =
- "-agentlib:jdwp=transport=dt_android_adb,suspend=n,server=y";
-
- args.version = JNI_VERSION_1_4;
- args.options = &opt;
- args.nOptions = 1;
- args.ignoreUnrecognized = JNI_FALSE;
-
-
- // TODO: Should this just link against libnativehelper and use its
- // JNI_CreateJavaVM wrapper that essential does this dlopen/dlsym
- // work based on the current system default runtime?
- void* libart_dso = dlopen("libart.so", RTLD_NOW);
- ALOGE_IF(!libart_dso, "DdmConnection: %s", dlerror());
-
- void* libandroid_runtime_dso = dlopen("libandroid_runtime.so", RTLD_NOW);
- ALOGE_IF(!libandroid_runtime_dso, "DdmConnection: %s", dlerror());
-
- if (!libart_dso || !libandroid_runtime_dso) {
- goto error;
- }
-
- jint (*JNI_CreateJavaVM)(JavaVM** p_vm, JNIEnv** p_env, void* vm_args);
- JNI_CreateJavaVM = reinterpret_cast<decltype(JNI_CreateJavaVM)>(
- dlsym(libart_dso, "JNI_CreateJavaVM"));
- ALOGE_IF(!JNI_CreateJavaVM, "DdmConnection: %s", dlerror());
-
- jint (*registerNatives)(JNIEnv* env, jclass clazz);
- registerNatives = reinterpret_cast<decltype(registerNatives)>(
- dlsym(libandroid_runtime_dso,
- "Java_com_android_internal_util_WithFramework_registerNatives"));
- ALOGE_IF(!registerNatives, "DdmConnection: %s", dlerror());
-
- if (!JNI_CreateJavaVM || !registerNatives) {
- goto error;
- }
-
- if (JNI_CreateJavaVM(&vm, &env, &args) == 0) {
- jclass startClass;
- jmethodID startMeth;
-
- // register native code
- if (registerNatives(env, 0) == 0) {
- // set our name by calling DdmHandleAppName.setAppName()
- startClass = env->FindClass("android/ddm/DdmHandleAppName");
- if (startClass) {
- startMeth = env->GetStaticMethodID(startClass,
- "setAppName", "(Ljava/lang/String;I)V");
- if (startMeth) {
- jstring str = env->NewStringUTF(name);
- env->CallStaticVoidMethod(startClass, startMeth, str, getuid());
- env->DeleteLocalRef(str);
- }
- }
-
- // initialize DDMS communication by calling
- // DdmRegister.registerHandlers()
- startClass = env->FindClass("android/ddm/DdmRegister");
- if (startClass) {
- startMeth = env->GetStaticMethodID(startClass,
- "registerHandlers", "()V");
- if (startMeth) {
- env->CallStaticVoidMethod(startClass, startMeth);
- }
- }
- }
- }
- return;
-
-error:
- if (libandroid_runtime_dso) {
- dlclose(libandroid_runtime_dso);
- }
- if (libart_dso) {
- dlclose(libart_dso);
- }
-}
-
-}; // namespace android
diff --git a/services/surfaceflinger/DdmConnection.h b/services/surfaceflinger/DdmConnection.h
deleted file mode 100644
index 938d14b..0000000
--- a/services/surfaceflinger/DdmConnection.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_SF_DDM_CONNECTION
-#define ANDROID_SF_DDM_CONNECTION
-
-namespace android {
-
-// wrapper for dlsym
-extern "C" void DdmConnection_start(const char* name);
-
-class DdmConnection {
-public:
- // Creates a JVM and registers all handlers to DDMS.
- // This allows tools relying on DDMS to find surfaceflinger
- // (e.g: Memory Leak finder, heap analyzer, ...)
- static void start(const char* name);
-};
-
-}; // namespace android
-
-#endif /* ANDROID_SF_DDM_CONNECTION */
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index e7b7fbe..4a13bfb 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -18,47 +18,28 @@
#undef LOG_TAG
#define LOG_TAG "DisplayDevice"
-#include "DisplayDevice.h"
-
-#include <array>
-#include <unordered_set>
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <math.h>
-
#include <android-base/stringprintf.h>
-#include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
+#include <compositionengine/CompositionEngine.h>
+#include <compositionengine/Display.h>
+#include <compositionengine/DisplayColorProfile.h>
+#include <compositionengine/DisplayColorProfileCreationArgs.h>
+#include <compositionengine/DisplayCreationArgs.h>
+#include <compositionengine/DisplaySurface.h>
+#include <compositionengine/RenderSurface.h>
+#include <compositionengine/RenderSurfaceCreationArgs.h>
+#include <compositionengine/impl/OutputCompositionState.h>
#include <configstore/Utils.h>
-#include <cutils/properties.h>
-#include <gui/Surface.h>
-#include <hardware/gralloc.h>
-#include <renderengine/RenderEngine.h>
-#include <sync/sync.h>
+#include <log/log.h>
#include <system/window.h>
-#include <ui/DebugUtils.h>
-#include <ui/DisplayInfo.h>
-#include <ui/PixelFormat.h>
-#include <utils/Log.h>
-#include <utils/RefBase.h>
+#include <ui/GraphicTypes.h>
-#include "DisplayHardware/DisplaySurface.h"
-#include "DisplayHardware/HWComposer.h"
-#include "DisplayHardware/HWC2.h"
-#include "SurfaceFlinger.h"
+#include "DisplayDevice.h"
#include "Layer.h"
+#include "SurfaceFlinger.h"
namespace android {
-// retrieve triple buffer setting from configstore
-using namespace android::hardware::configstore;
-using namespace android::hardware::configstore::V1_0;
using android::base::StringAppendF;
-using android::ui::ColorMode;
-using android::ui::Dataspace;
-using android::ui::Hdr;
-using android::ui::RenderIntent;
/*
* Initialize the display to the specified values.
@@ -67,413 +48,72 @@
uint32_t DisplayDevice::sPrimaryDisplayOrientation = 0;
-namespace {
-
-// ordered list of known SDR color modes
-const std::array<ColorMode, 3> sSdrColorModes = {
- ColorMode::DISPLAY_BT2020,
- ColorMode::DISPLAY_P3,
- ColorMode::SRGB,
-};
-
-// ordered list of known HDR color modes
-const std::array<ColorMode, 2> sHdrColorModes = {
- ColorMode::BT2100_PQ,
- ColorMode::BT2100_HLG,
-};
-
-// ordered list of known SDR render intents
-const std::array<RenderIntent, 2> sSdrRenderIntents = {
- RenderIntent::ENHANCE,
- RenderIntent::COLORIMETRIC,
-};
-
-// ordered list of known HDR render intents
-const std::array<RenderIntent, 2> sHdrRenderIntents = {
- RenderIntent::TONE_MAP_ENHANCE,
- RenderIntent::TONE_MAP_COLORIMETRIC,
-};
-
-// map known color mode to dataspace
-Dataspace colorModeToDataspace(ColorMode mode) {
- switch (mode) {
- case ColorMode::SRGB:
- return Dataspace::V0_SRGB;
- case ColorMode::DISPLAY_P3:
- return Dataspace::DISPLAY_P3;
- case ColorMode::DISPLAY_BT2020:
- return Dataspace::DISPLAY_BT2020;
- case ColorMode::BT2100_HLG:
- return Dataspace::BT2020_HLG;
- case ColorMode::BT2100_PQ:
- return Dataspace::BT2020_PQ;
- default:
- return Dataspace::UNKNOWN;
- }
-}
-
-// Return a list of candidate color modes.
-std::vector<ColorMode> getColorModeCandidates(ColorMode mode) {
- std::vector<ColorMode> candidates;
-
- // add mode itself
- candidates.push_back(mode);
-
- // check if mode is HDR
- bool isHdr = false;
- for (auto hdrMode : sHdrColorModes) {
- if (hdrMode == mode) {
- isHdr = true;
- break;
- }
- }
-
- // add other HDR candidates when mode is HDR
- if (isHdr) {
- for (auto hdrMode : sHdrColorModes) {
- if (hdrMode != mode) {
- candidates.push_back(hdrMode);
- }
- }
- }
-
- // add other SDR candidates
- for (auto sdrMode : sSdrColorModes) {
- if (sdrMode != mode) {
- candidates.push_back(sdrMode);
- }
- }
-
- return candidates;
-}
-
-// Return a list of candidate render intents.
-std::vector<RenderIntent> getRenderIntentCandidates(RenderIntent intent) {
- std::vector<RenderIntent> candidates;
-
- // add intent itself
- candidates.push_back(intent);
-
- // check if intent is HDR
- bool isHdr = false;
- for (auto hdrIntent : sHdrRenderIntents) {
- if (hdrIntent == intent) {
- isHdr = true;
- break;
- }
- }
-
- if (isHdr) {
- // add other HDR candidates when intent is HDR
- for (auto hdrIntent : sHdrRenderIntents) {
- if (hdrIntent != intent) {
- candidates.push_back(hdrIntent);
- }
- }
- } else {
- // add other SDR candidates when intent is SDR
- for (auto sdrIntent : sSdrRenderIntents) {
- if (sdrIntent != intent) {
- candidates.push_back(sdrIntent);
- }
- }
- }
-
- return candidates;
-}
-
-// Return the best color mode supported by HWC.
-ColorMode getHwcColorMode(
- const std::unordered_map<ColorMode, std::vector<RenderIntent>>& hwcColorModes,
- ColorMode mode) {
- std::vector<ColorMode> candidates = getColorModeCandidates(mode);
- for (auto candidate : candidates) {
- auto iter = hwcColorModes.find(candidate);
- if (iter != hwcColorModes.end()) {
- return candidate;
- }
- }
-
- return ColorMode::NATIVE;
-}
-
-// Return the best render intent supported by HWC.
-RenderIntent getHwcRenderIntent(const std::vector<RenderIntent>& hwcIntents, RenderIntent intent) {
- std::vector<RenderIntent> candidates = getRenderIntentCandidates(intent);
- for (auto candidate : candidates) {
- for (auto hwcIntent : hwcIntents) {
- if (candidate == hwcIntent) {
- return candidate;
- }
- }
- }
-
- return RenderIntent::COLORIMETRIC;
-}
-
-} // anonymous namespace
-
DisplayDeviceCreationArgs::DisplayDeviceCreationArgs(const sp<SurfaceFlinger>& flinger,
const wp<IBinder>& displayToken,
const std::optional<DisplayId>& displayId)
: flinger(flinger), displayToken(displayToken), displayId(displayId) {}
DisplayDevice::DisplayDevice(DisplayDeviceCreationArgs&& args)
- : lastCompositionHadVisibleLayers(false),
- mFlinger(args.flinger),
+ : mFlinger(args.flinger),
mDisplayToken(args.displayToken),
mSequenceId(args.sequenceId),
- mId(args.displayId),
- mNativeWindow(args.nativeWindow),
- mGraphicBuffer(nullptr),
- mDisplaySurface(args.displaySurface),
mDisplayInstallOrientation(args.displayInstallOrientation),
- mPageFlipCount(0),
+ mCompositionDisplay{mFlinger->getCompositionEngine().createDisplay(
+ compositionengine::DisplayCreationArgs{args.isSecure, args.isVirtual,
+ args.displayId})},
mIsVirtual(args.isVirtual),
- mIsSecure(args.isSecure),
- mLayerStack(NO_LAYER_STACK),
mOrientation(),
- mViewport(Rect::INVALID_RECT),
- mFrame(Rect::INVALID_RECT),
- mPowerMode(args.initialPowerMode),
mActiveConfig(0),
- mColorTransform(HAL_COLOR_TRANSFORM_IDENTITY),
- mHasWideColorGamut(args.hasWideColorGamut),
- mHasHdr10Plus(false),
- mHasHdr10(false),
- mHasHLG(false),
- mHasDolbyVision(false),
- mSupportedPerFrameMetadata(args.supportedPerFrameMetadata),
mIsPrimary(args.isPrimary) {
- populateColorModes(args.hwcColorModes);
+ mCompositionDisplay->createRenderSurface(
+ compositionengine::RenderSurfaceCreationArgs{ANativeWindow_getWidth(
+ args.nativeWindow.get()),
+ ANativeWindow_getHeight(
+ args.nativeWindow.get()),
+ args.nativeWindow, args.displaySurface});
- ALOGE_IF(!mNativeWindow, "No native window was set for display");
- ALOGE_IF(!mDisplaySurface, "No display surface was set for display");
+ mCompositionDisplay->createDisplayColorProfile(
+ compositionengine::DisplayColorProfileCreationArgs{args.hasWideColorGamut,
+ std::move(args.hdrCapabilities),
+ args.supportedPerFrameMetadata,
+ args.hwcColorModes});
- std::vector<Hdr> types = args.hdrCapabilities.getSupportedHdrTypes();
- for (Hdr hdrType : types) {
- switch (hdrType) {
- case Hdr::HDR10_PLUS:
- mHasHdr10Plus = true;
- break;
- case Hdr::HDR10:
- mHasHdr10 = true;
- break;
- case Hdr::HLG:
- mHasHLG = true;
- break;
- case Hdr::DOLBY_VISION:
- mHasDolbyVision = true;
- break;
- default:
- ALOGE("UNKNOWN HDR capability: %d", static_cast<int32_t>(hdrType));
- }
+ if (!mCompositionDisplay->isValid()) {
+ ALOGE("Composition Display did not validate!");
}
- float minLuminance = args.hdrCapabilities.getDesiredMinLuminance();
- float maxLuminance = args.hdrCapabilities.getDesiredMaxLuminance();
- float maxAverageLuminance = args.hdrCapabilities.getDesiredMaxAverageLuminance();
+ mCompositionDisplay->getRenderSurface()->initialize();
- minLuminance = minLuminance <= 0.0 ? sDefaultMinLumiance : minLuminance;
- maxLuminance = maxLuminance <= 0.0 ? sDefaultMaxLumiance : maxLuminance;
- maxAverageLuminance = maxAverageLuminance <= 0.0 ? sDefaultMaxLumiance : maxAverageLuminance;
- if (this->hasWideColorGamut()) {
- // insert HDR10/HLG as we will force client composition for HDR10/HLG
- // layers
- if (!hasHDR10Support()) {
- types.push_back(Hdr::HDR10);
- }
-
- if (!hasHLGSupport()) {
- types.push_back(Hdr::HLG);
- }
- }
- mHdrCapabilities = HdrCapabilities(types, maxLuminance, maxAverageLuminance, minLuminance);
-
- ANativeWindow* const window = mNativeWindow.get();
-
- int status = native_window_api_connect(window, NATIVE_WINDOW_API_EGL);
- ALOGE_IF(status != NO_ERROR, "Unable to connect BQ producer: %d", status);
- status = native_window_set_buffers_format(window, HAL_PIXEL_FORMAT_RGBA_8888);
- ALOGE_IF(status != NO_ERROR, "Unable to set BQ format to RGBA888: %d", status);
- status = native_window_set_usage(window, GRALLOC_USAGE_HW_RENDER);
- ALOGE_IF(status != NO_ERROR, "Unable to set BQ usage bits for GPU rendering: %d", status);
-
- mDisplayWidth = ANativeWindow_getWidth(window);
- mDisplayHeight = ANativeWindow_getHeight(window);
+ setPowerMode(args.initialPowerMode);
// initialize the display orientation transform.
- setProjection(DisplayState::eOrientationDefault, mViewport, mFrame);
+ setProjection(DisplayState::eOrientationDefault, Rect::INVALID_RECT, Rect::INVALID_RECT);
}
DisplayDevice::~DisplayDevice() = default;
-void DisplayDevice::disconnect(HWComposer& hwc) {
- if (mId) {
- hwc.disconnectDisplay(*mId);
- mId.reset();
- }
+void DisplayDevice::disconnect() {
+ mCompositionDisplay->disconnect();
}
int DisplayDevice::getWidth() const {
- return mDisplayWidth;
+ return mCompositionDisplay->getState().bounds.getWidth();
}
int DisplayDevice::getHeight() const {
- return mDisplayHeight;
+ return mCompositionDisplay->getState().bounds.getHeight();
}
void DisplayDevice::setDisplayName(const std::string& displayName) {
if (!displayName.empty()) {
// never override the name with an empty name
mDisplayName = displayName;
+ mCompositionDisplay->setName(displayName);
}
}
uint32_t DisplayDevice::getPageFlipCount() const {
- return mPageFlipCount;
-}
-
-void DisplayDevice::flip() const
-{
- mPageFlipCount++;
-}
-
-status_t DisplayDevice::beginFrame(bool mustRecompose) const {
- return mDisplaySurface->beginFrame(mustRecompose);
-}
-
-status_t DisplayDevice::prepareFrame(HWComposer& hwc,
- std::vector<CompositionInfo>& compositionData) {
- if (mId) {
- status_t error = hwc.prepare(*mId, compositionData);
- if (error != NO_ERROR) {
- return error;
- }
- }
-
- DisplaySurface::CompositionType compositionType;
- bool hasClient = hwc.hasClientComposition(mId);
- bool hasDevice = hwc.hasDeviceComposition(mId);
- if (hasClient && hasDevice) {
- compositionType = DisplaySurface::COMPOSITION_MIXED;
- } else if (hasClient) {
- compositionType = DisplaySurface::COMPOSITION_GLES;
- } else if (hasDevice) {
- compositionType = DisplaySurface::COMPOSITION_HWC;
- } else {
- // Nothing to do -- when turning the screen off we get a frame like
- // this. Call it a HWC frame since we won't be doing any GLES work but
- // will do a prepare/set cycle.
- compositionType = DisplaySurface::COMPOSITION_HWC;
- }
- return mDisplaySurface->prepareFrame(compositionType);
-}
-
-void DisplayDevice::setProtected(bool useProtected) {
- uint64_t usageFlags = GRALLOC_USAGE_HW_RENDER;
- if (useProtected) {
- usageFlags |= GRALLOC_USAGE_PROTECTED;
- }
- const int status = native_window_set_usage(mNativeWindow.get(), usageFlags);
- ALOGE_IF(status != NO_ERROR, "Unable to set BQ usage bits for protected content: %d", status);
-}
-
-sp<GraphicBuffer> DisplayDevice::dequeueBuffer() {
- int fd;
- ANativeWindowBuffer* buffer;
-
- status_t res = mNativeWindow->dequeueBuffer(mNativeWindow.get(), &buffer, &fd);
-
- if (res != NO_ERROR) {
- ALOGE("ANativeWindow::dequeueBuffer failed for display [%s] with error: %d",
- getDisplayName().c_str(), res);
- // Return fast here as we can't do much more - any rendering we do
- // now will just be wrong.
- return mGraphicBuffer;
- }
-
- ALOGW_IF(mGraphicBuffer != nullptr, "Clobbering a non-null pointer to a buffer [%p].",
- 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);
- }
-
- return mGraphicBuffer;
-}
-
-void DisplayDevice::queueBuffer(HWComposer& hwc) {
- if (hwc.hasClientComposition(mId) || hwc.hasFlipClientTargetRequest(mId)) {
- // hasFlipClientTargetRequest could return true even if we haven't
- // dequeued a buffer before. Try dequeueing one if we don't have a
- // buffer ready.
- if (mGraphicBuffer == nullptr) {
- ALOGI("Attempting to queue a client composited buffer without one "
- "previously dequeued for display [%s]. Attempting to dequeue "
- "a scratch buffer now",
- mDisplayName.c_str());
- // We shouldn't deadlock here, since mGraphicBuffer == nullptr only
- // after a successful call to queueBuffer, or if dequeueBuffer has
- // never been called.
- dequeueBuffer();
- }
-
- if (mGraphicBuffer == nullptr) {
- ALOGE("No buffer is ready for display [%s]", mDisplayName.c_str());
- } else {
- status_t res = mNativeWindow->queueBuffer(mNativeWindow.get(),
- mGraphicBuffer->getNativeBuffer(),
- dup(mBufferReady));
- if (res != NO_ERROR) {
- ALOGE("Error when queueing buffer for display [%s]: %d", mDisplayName.c_str(), res);
- // We risk blocking on dequeueBuffer if the primary display failed
- // to queue up its buffer, so crash here.
- if (isPrimary()) {
- LOG_ALWAYS_FATAL("ANativeWindow::queueBuffer failed with error: %d", res);
- } else {
- mNativeWindow->cancelBuffer(mNativeWindow.get(),
- mGraphicBuffer->getNativeBuffer(),
- dup(mBufferReady));
- }
- }
-
- mBufferReady.reset();
- mGraphicBuffer = nullptr;
- }
- }
-
- status_t result = mDisplaySurface->advanceFrame();
- if (result != NO_ERROR) {
- ALOGE("[%s] failed pushing new frame to HWC: %d", mDisplayName.c_str(), result);
- }
-}
-
-void DisplayDevice::onPresentDisplayCompleted() {
- mDisplaySurface->onFrameCommitted();
-}
-
-void DisplayDevice::setViewportAndProjection() const {
- size_t w = mDisplayWidth;
- size_t h = mDisplayHeight;
- Rect sourceCrop(0, 0, w, h);
- mFlinger->getRenderEngine().setViewportAndProjection(w, h, sourceCrop, ui::Transform::ROT_0);
-}
-
-void DisplayDevice::finishBuffer() {
- mBufferReady = mFlinger->getRenderEngine().flush();
- if (mBufferReady.get() < 0) {
- mFlinger->getRenderEngine().finish();
- }
-}
-
-const sp<Fence>& DisplayDevice::getClientTargetAcquireFence() const {
- return mDisplaySurface->getClientTargetAcquireFence();
+ return mCompositionDisplay->getRenderSurface()->getPageFlipCount();
}
// ----------------------------------------------------------------------------
@@ -494,21 +134,10 @@
return mLayersNeedingFences;
}
-Region DisplayDevice::getDirtyRegion(bool repaintEverything) const {
- Region dirty;
- if (repaintEverything) {
- dirty.set(getBounds());
- } else {
- const ui::Transform& planeTransform(mGlobalTransform);
- dirty = planeTransform.transform(this->dirtyRegion);
- dirty.andSelf(getBounds());
- }
- return dirty;
-}
-
// ----------------------------------------------------------------------------
void DisplayDevice::setPowerMode(int mode) {
mPowerMode = mode;
+ getCompositionDisplay()->setCompositionEnabled(mPowerMode != HWC_POWER_MODE_OFF);
}
int DisplayDevice::getPowerMode() const {
@@ -529,88 +158,37 @@
}
// ----------------------------------------------------------------------------
-void DisplayDevice::setActiveColorMode(ColorMode mode) {
- mActiveColorMode = mode;
-}
-
-ColorMode DisplayDevice::getActiveColorMode() const {
- return mActiveColorMode;
-}
-
-RenderIntent DisplayDevice::getActiveRenderIntent() const {
- return mActiveRenderIntent;
-}
-
-void DisplayDevice::setActiveRenderIntent(RenderIntent renderIntent) {
- mActiveRenderIntent = renderIntent;
-}
-
-void DisplayDevice::setColorTransform(const mat4& transform) {
- const bool isIdentity = (transform == mat4());
- mColorTransform =
- isIdentity ? HAL_COLOR_TRANSFORM_IDENTITY : HAL_COLOR_TRANSFORM_ARBITRARY_MATRIX;
-}
-
-android_color_transform_t DisplayDevice::getColorTransform() const {
- return mColorTransform;
-}
-
-void DisplayDevice::setCompositionDataSpace(ui::Dataspace dataspace) {
- mCompositionDataSpace = dataspace;
- ANativeWindow* const window = mNativeWindow.get();
- native_window_set_buffers_data_space(window, static_cast<android_dataspace>(dataspace));
-}
ui::Dataspace DisplayDevice::getCompositionDataSpace() const {
- return mCompositionDataSpace;
+ return mCompositionDisplay->getState().dataspace;
}
// ----------------------------------------------------------------------------
void DisplayDevice::setLayerStack(uint32_t stack) {
- mLayerStack = stack;
- dirtyRegion.set(bounds());
+ mCompositionDisplay->setLayerStackFilter(stack, isPrimary());
}
// ----------------------------------------------------------------------------
-uint32_t DisplayDevice::getOrientationTransform() const {
- uint32_t transform = 0;
- switch (mOrientation) {
- case DisplayState::eOrientationDefault:
- transform = ui::Transform::ROT_0;
- break;
- case DisplayState::eOrientation90:
- transform = ui::Transform::ROT_90;
- break;
- case DisplayState::eOrientation180:
- transform = ui::Transform::ROT_180;
- break;
- case DisplayState::eOrientation270:
- transform = ui::Transform::ROT_270;
- break;
- }
- return transform;
-}
-
-status_t DisplayDevice::orientationToTransfrom(
- int orientation, int w, int h, ui::Transform* tr)
-{
- uint32_t flags = 0;
+uint32_t DisplayDevice::displayStateOrientationToTransformOrientation(int orientation) {
switch (orientation) {
case DisplayState::eOrientationDefault:
- flags = ui::Transform::ROT_0;
- break;
+ return ui::Transform::ROT_0;
case DisplayState::eOrientation90:
- flags = ui::Transform::ROT_90;
- break;
+ return ui::Transform::ROT_90;
case DisplayState::eOrientation180:
- flags = ui::Transform::ROT_180;
- break;
+ return ui::Transform::ROT_180;
case DisplayState::eOrientation270:
- flags = ui::Transform::ROT_270;
- break;
+ return ui::Transform::ROT_270;
default:
+ return ui::Transform::ROT_INVALID;
+ }
+}
+
+status_t DisplayDevice::orientationToTransfrom(int orientation, int w, int h, ui::Transform* tr) {
+ uint32_t flags = displayStateOrientationToTransformOrientation(orientation);
+ if (flags == ui::Transform::ROT_INVALID) {
return BAD_VALUE;
}
tr->set(flags, w, h);
@@ -618,12 +196,7 @@
}
void DisplayDevice::setDisplaySize(const int newWidth, const int newHeight) {
- dirtyRegion.set(getBounds());
-
- mDisplaySurface->resizeBuffers(newWidth, newHeight);
-
- mDisplayWidth = newWidth;
- mDisplayHeight = newHeight;
+ mCompositionDisplay->setBounds(ui::Size(newWidth, newHeight));
}
void DisplayDevice::setProjection(int orientation,
@@ -631,8 +204,11 @@
Rect viewport(newViewport);
Rect frame(newFrame);
- const int w = mDisplayWidth;
- const int h = mDisplayHeight;
+ mOrientation = orientation;
+
+ const Rect& displayBounds = getCompositionDisplay()->getState().bounds;
+ const int w = displayBounds.width();
+ const int h = displayBounds.height();
ui::Transform R;
DisplayDevice::orientationToTransfrom(orientation, w, h, &R);
@@ -656,8 +232,6 @@
}
}
- dirtyRegion.set(getBounds());
-
ui::Transform TL, TP, S;
float src_width = viewport.width();
float src_height = viewport.height();
@@ -676,7 +250,7 @@
TL.set(-src_x, -src_y);
TP.set(dst_x, dst_y);
- // need to take care of primary display rotation for mGlobalTransform
+ // need to take care of primary display rotation for globalTransform
// for case if the panel is not installed aligned with device orientation
if (isPrimary()) {
DisplayDevice::orientationToTransfrom(
@@ -687,38 +261,25 @@
// The viewport and frame are both in the logical orientation.
// Apply the logical translation, scale to physical size, apply the
// physical translation and finally rotate to the physical orientation.
- mGlobalTransform = R * TP * S * TL;
+ ui::Transform globalTransform = R * TP * S * TL;
- const uint8_t type = mGlobalTransform.getType();
- mNeedsFiltering = (!mGlobalTransform.preserveRects() ||
- (type >= ui::Transform::SCALE));
+ const uint8_t type = globalTransform.getType();
+ const bool needsFiltering =
+ (!globalTransform.preserveRects() || (type >= ui::Transform::SCALE));
- mScissor = mGlobalTransform.transform(viewport);
- if (mScissor.isEmpty()) {
- mScissor = getBounds();
+ Rect scissor = globalTransform.transform(viewport);
+ if (scissor.isEmpty()) {
+ scissor = displayBounds;
}
- mOrientation = orientation;
if (isPrimary()) {
- uint32_t transform = 0;
- switch (mOrientation) {
- case DisplayState::eOrientationDefault:
- transform = ui::Transform::ROT_0;
- break;
- case DisplayState::eOrientation90:
- transform = ui::Transform::ROT_90;
- break;
- case DisplayState::eOrientation180:
- transform = ui::Transform::ROT_180;
- break;
- case DisplayState::eOrientation270:
- transform = ui::Transform::ROT_270;
- break;
- }
- sPrimaryDisplayOrientation = transform;
+ sPrimaryDisplayOrientation = displayStateOrientationToTransformOrientation(orientation);
}
- mViewport = viewport;
- mFrame = frame;
+
+ getCompositionDisplay()->setProjection(globalTransform,
+ displayStateOrientationToTransformOrientation(
+ orientation),
+ frame, viewport, scissor, needsFiltering);
}
uint32_t DisplayDevice::getPrimaryDisplayOrientationTransform() {
@@ -726,149 +287,94 @@
}
std::string DisplayDevice::getDebugName() const {
- const auto id = mId ? to_string(*mId) + ", " : std::string();
+ const auto id = getId() ? to_string(*getId()) + ", " : std::string();
return base::StringPrintf("DisplayDevice{%s%s%s\"%s\"}", id.c_str(),
isPrimary() ? "primary, " : "", isVirtual() ? "virtual, " : "",
mDisplayName.c_str());
}
void DisplayDevice::dump(std::string& result) const {
- const ui::Transform& tr(mGlobalTransform);
- ANativeWindow* const window = mNativeWindow.get();
StringAppendF(&result, "+ %s\n", getDebugName().c_str());
- StringAppendF(&result,
- " layerStack=%u, (%4dx%4d), ANativeWindow=%p "
- "format=%d, orient=%2d (type=%08x), flips=%u, isSecure=%d, "
- "powerMode=%d, activeConfig=%d, numLayers=%zu\n",
- mLayerStack, mDisplayWidth, mDisplayHeight, window,
- ANativeWindow_getFormat(window), mOrientation, tr.getType(), getPageFlipCount(),
- mIsSecure, mPowerMode, mActiveConfig, mVisibleLayersSortedByZ.size());
- StringAppendF(&result,
- " v:[%d,%d,%d,%d], f:[%d,%d,%d,%d], s:[%d,%d,%d,%d],"
- "transform:[[%0.3f,%0.3f,%0.3f][%0.3f,%0.3f,%0.3f][%0.3f,%0.3f,%0.3f]]\n",
- mViewport.left, mViewport.top, mViewport.right, mViewport.bottom, mFrame.left,
- mFrame.top, mFrame.right, mFrame.bottom, mScissor.left, mScissor.top,
- mScissor.right, mScissor.bottom, tr[0][0], tr[1][0], tr[2][0], tr[0][1], tr[1][1],
- tr[2][1], tr[0][2], tr[1][2], tr[2][2]);
- auto const surface = static_cast<Surface*>(window);
- ui::Dataspace dataspace = surface->getBuffersDataSpace();
- StringAppendF(&result,
- " wideColorGamut=%d, hdr10plus =%d, hdr10=%d, colorMode=%s, dataspace: %s "
- "(%d)\n",
- mHasWideColorGamut, mHasHdr10Plus, mHasHdr10,
- decodeColorMode(mActiveColorMode).c_str(),
- dataspaceDetails(static_cast<android_dataspace>(dataspace)).c_str(), dataspace);
- String8 surfaceDump;
- mDisplaySurface->dumpAsString(surfaceDump);
- result.append(surfaceDump.string(), surfaceDump.size());
+ result.append(" ");
+ StringAppendF(&result, "powerMode=%d, ", mPowerMode);
+ StringAppendF(&result, "activeConfig=%d, ", mActiveConfig);
+ StringAppendF(&result, "numLayers=%zu\n", mVisibleLayersSortedByZ.size());
+ getCompositionDisplay()->dump(result);
}
-// Map dataspace/intent to the best matched dataspace/colorMode/renderIntent
-// supported by HWC.
-void DisplayDevice::addColorMode(
- const std::unordered_map<ColorMode, std::vector<RenderIntent>>& hwcColorModes,
- const ColorMode mode, const RenderIntent intent) {
- // find the best color mode
- const ColorMode hwcColorMode = getHwcColorMode(hwcColorModes, mode);
-
- // find the best render intent
- auto iter = hwcColorModes.find(hwcColorMode);
- const auto& hwcIntents =
- iter != hwcColorModes.end() ? iter->second : std::vector<RenderIntent>();
- const RenderIntent hwcIntent = getHwcRenderIntent(hwcIntents, intent);
-
- const Dataspace dataspace = colorModeToDataspace(mode);
- const Dataspace hwcDataspace = colorModeToDataspace(hwcColorMode);
-
- ALOGV("%s: map (%s, %s) to (%s, %s, %s)", getDebugName().c_str(),
- dataspaceDetails(static_cast<android_dataspace_t>(dataspace)).c_str(),
- decodeRenderIntent(intent).c_str(),
- dataspaceDetails(static_cast<android_dataspace_t>(hwcDataspace)).c_str(),
- decodeColorMode(hwcColorMode).c_str(), decodeRenderIntent(hwcIntent).c_str());
-
- mColorModes[getColorModeKey(dataspace, intent)] = {hwcDataspace, hwcColorMode, hwcIntent};
+bool DisplayDevice::hasRenderIntent(ui::RenderIntent intent) const {
+ return mCompositionDisplay->getDisplayColorProfile()->hasRenderIntent(intent);
}
-void DisplayDevice::populateColorModes(
- const std::unordered_map<ColorMode, std::vector<RenderIntent>>& hwcColorModes) {
- if (!hasWideColorGamut()) {
- return;
- }
+// ----------------------------------------------------------------------------
- // collect all known SDR render intents
- std::unordered_set<RenderIntent> sdrRenderIntents(sSdrRenderIntents.begin(),
- sSdrRenderIntents.end());
- auto iter = hwcColorModes.find(ColorMode::SRGB);
- if (iter != hwcColorModes.end()) {
- for (auto intent : iter->second) {
- sdrRenderIntents.insert(intent);
- }
- }
-
- // add all known SDR combinations
- for (auto intent : sdrRenderIntents) {
- for (auto mode : sSdrColorModes) {
- addColorMode(hwcColorModes, mode, intent);
- }
- }
-
- // collect all known HDR render intents
- std::unordered_set<RenderIntent> hdrRenderIntents(sHdrRenderIntents.begin(),
- sHdrRenderIntents.end());
- iter = hwcColorModes.find(ColorMode::BT2100_PQ);
- if (iter != hwcColorModes.end()) {
- for (auto intent : iter->second) {
- hdrRenderIntents.insert(intent);
- }
- }
-
- // add all known HDR combinations
- for (auto intent : sHdrRenderIntents) {
- for (auto mode : sHdrColorModes) {
- addColorMode(hwcColorModes, mode, intent);
- }
- }
+const std::optional<DisplayId>& DisplayDevice::getId() const {
+ return mCompositionDisplay->getId();
}
-bool DisplayDevice::hasRenderIntent(RenderIntent intent) const {
- // assume a render intent is supported when SRGB supports it; we should
- // get rid of that assumption.
- auto iter = mColorModes.find(getColorModeKey(Dataspace::V0_SRGB, intent));
- return iter != mColorModes.end() && iter->second.renderIntent == intent;
+bool DisplayDevice::isSecure() const {
+ return mCompositionDisplay->isSecure();
}
-bool DisplayDevice::hasLegacyHdrSupport(Dataspace dataspace) const {
- if ((dataspace == Dataspace::BT2020_PQ && hasHDR10Support()) ||
- (dataspace == Dataspace::BT2020_HLG && hasHLGSupport())) {
- auto iter =
- mColorModes.find(getColorModeKey(dataspace, RenderIntent::TONE_MAP_COLORIMETRIC));
- return iter == mColorModes.end() || iter->second.dataspace != dataspace;
- }
-
- return false;
+const Rect& DisplayDevice::getBounds() const {
+ return mCompositionDisplay->getState().bounds;
}
-void DisplayDevice::getBestColorMode(Dataspace dataspace, RenderIntent intent,
- Dataspace* outDataspace, ColorMode* outMode,
- RenderIntent* outIntent) const {
- auto iter = mColorModes.find(getColorModeKey(dataspace, intent));
- if (iter != mColorModes.end()) {
- *outDataspace = iter->second.dataspace;
- *outMode = iter->second.colorMode;
- *outIntent = iter->second.renderIntent;
- } else {
- // this is unexpected on a WCG display
- if (hasWideColorGamut()) {
- ALOGE("map unknown (%s)/(%s) to default color mode",
- dataspaceDetails(static_cast<android_dataspace_t>(dataspace)).c_str(),
- decodeRenderIntent(intent).c_str());
- }
+const Region& DisplayDevice::getUndefinedRegion() const {
+ return mCompositionDisplay->getState().undefinedRegion;
+}
- *outDataspace = Dataspace::UNKNOWN;
- *outMode = ColorMode::NATIVE;
- *outIntent = RenderIntent::COLORIMETRIC;
- }
+bool DisplayDevice::needsFiltering() const {
+ return mCompositionDisplay->getState().needsFiltering;
+}
+
+uint32_t DisplayDevice::getLayerStack() const {
+ return mCompositionDisplay->getState().layerStackId;
+}
+
+const ui::Transform& DisplayDevice::getTransform() const {
+ return mCompositionDisplay->getState().transform;
+}
+
+const Rect& DisplayDevice::getViewport() const {
+ return mCompositionDisplay->getState().viewport;
+}
+
+const Rect& DisplayDevice::getFrame() const {
+ return mCompositionDisplay->getState().frame;
+}
+
+const Rect& DisplayDevice::getScissor() const {
+ return mCompositionDisplay->getState().scissor;
+}
+
+bool DisplayDevice::hasWideColorGamut() const {
+ return mCompositionDisplay->getDisplayColorProfile()->hasWideColorGamut();
+}
+
+bool DisplayDevice::hasHDR10PlusSupport() const {
+ return mCompositionDisplay->getDisplayColorProfile()->hasHDR10PlusSupport();
+}
+
+bool DisplayDevice::hasHDR10Support() const {
+ return mCompositionDisplay->getDisplayColorProfile()->hasHDR10Support();
+}
+
+bool DisplayDevice::hasHLGSupport() const {
+ return mCompositionDisplay->getDisplayColorProfile()->hasHLGSupport();
+}
+
+bool DisplayDevice::hasDolbyVisionSupport() const {
+ return mCompositionDisplay->getDisplayColorProfile()->hasDolbyVisionSupport();
+}
+
+int DisplayDevice::getSupportedPerFrameMetadata() const {
+ return mCompositionDisplay->getDisplayColorProfile()->getSupportedPerFrameMetadata();
+}
+
+const HdrCapabilities& DisplayDevice::getHdrCapabilities() const {
+ return mCompositionDisplay->getDisplayColorProfile()->getHdrCapabilities();
}
std::atomic<int32_t> DisplayDeviceState::sNextSequenceId(1);
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index 250a650..9674f0d 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -44,7 +44,6 @@
namespace android {
-class DisplaySurface;
class Fence;
class HWComposer;
class IGraphicBufferProducer;
@@ -55,35 +54,33 @@
struct DisplayDeviceCreationArgs;
struct DisplayInfo;
-class DisplayDevice : public LightRefBase<DisplayDevice>
-{
+namespace compositionengine {
+class Display;
+class DisplaySurface;
+} // namespace compositionengine
+
+class DisplayDevice : public LightRefBase<DisplayDevice> {
public:
constexpr static float sDefaultMinLumiance = 0.0;
constexpr static float sDefaultMaxLumiance = 500.0;
- // region in layer-stack space
- mutable Region dirtyRegion;
- // region in screen space
- Region undefinedRegion;
- bool lastCompositionHadVisibleLayers;
-
enum {
NO_LAYER_STACK = 0xFFFFFFFF,
};
explicit DisplayDevice(DisplayDeviceCreationArgs&& args);
- ~DisplayDevice();
+ virtual ~DisplayDevice();
+
+ std::shared_ptr<compositionengine::Display> getCompositionDisplay() const {
+ return mCompositionDisplay;
+ }
bool isVirtual() const { return mIsVirtual; }
bool isPrimary() const { return mIsPrimary; }
// isSecure indicates whether this display can be trusted to display
// secure surfaces.
- bool isSecure() const { return mIsSecure; }
-
- // Flip the front and back buffers if the back buffer is "dirty". Might
- // be instantaneous, might involve copying the frame buffer around.
- void flip() const;
+ bool isSecure() const;
int getWidth() const;
int getHeight() const;
@@ -93,44 +90,34 @@
const Vector< sp<Layer> >& getVisibleLayersSortedByZ() const;
void setLayersNeedingFences(const Vector< sp<Layer> >& layers);
const Vector< sp<Layer> >& getLayersNeedingFences() const;
- Region getDirtyRegion(bool repaintEverything) const;
void setLayerStack(uint32_t stack);
void setDisplaySize(const int newWidth, const int newHeight);
void setProjection(int orientation, const Rect& viewport, const Rect& frame);
int getOrientation() const { return mOrientation; }
- uint32_t getOrientationTransform() const;
static uint32_t getPrimaryDisplayOrientationTransform();
- const ui::Transform& getTransform() const { return mGlobalTransform; }
- const Rect getViewport() const { return mViewport; }
- const Rect getFrame() const { return mFrame; }
- const Rect& getScissor() const { return mScissor; }
- bool needsFiltering() const { return mNeedsFiltering; }
+ const ui::Transform& getTransform() const;
+ const Rect& getViewport() const;
+ const Rect& getFrame() const;
+ const Rect& getScissor() const;
+ bool needsFiltering() const;
+ uint32_t getLayerStack() const;
- uint32_t getLayerStack() const { return mLayerStack; }
-
- const std::optional<DisplayId>& getId() const { return mId; }
+ const std::optional<DisplayId>& getId() const;
const wp<IBinder>& getDisplayToken() const { return mDisplayToken; }
int32_t getSequenceId() const { return mSequenceId; }
- int32_t getSupportedPerFrameMetadata() const { return mSupportedPerFrameMetadata; }
+ const Region& getUndefinedRegion() const;
- // We pass in mustRecompose so we can keep VirtualDisplaySurface's state
- // machine happy without actually queueing a buffer if nothing has changed
- status_t beginFrame(bool mustRecompose) const;
- status_t prepareFrame(HWComposer& hwc, std::vector<CompositionInfo>& compositionInfo);
+ int32_t getSupportedPerFrameMetadata() const;
- bool hasWideColorGamut() const { return mHasWideColorGamut; }
+ bool hasWideColorGamut() const;
// Whether h/w composer has native support for specific HDR type.
- bool hasHDR10PlusSupport() const { return mHasHdr10Plus; }
- bool hasHDR10Support() const { return mHasHdr10; }
- bool hasHLGSupport() const { return mHasHLG; }
- bool hasDolbyVisionSupport() const { return mHasDolbyVision; }
-
- // Return true if the HDR dataspace is supported but
- // there is no corresponding color mode.
- bool hasLegacyHdrSupport(ui::Dataspace dataspace) const;
+ bool hasHDR10PlusSupport() const;
+ bool hasHDR10Support() const;
+ bool hasHLGSupport() const;
+ bool hasDolbyVisionSupport() const;
// The returned HdrCapabilities is the combination of HDR capabilities from
// hardware composer and RenderEngine. When the DisplayDevice supports wide
@@ -138,41 +125,17 @@
// color space for both PQ and HLG HDR contents. The minimum and maximum
// luminance will be set to sDefaultMinLumiance and sDefaultMaxLumiance
// respectively if hardware composer doesn't return meaningful values.
- const HdrCapabilities& getHdrCapabilities() const { return mHdrCapabilities; }
+ const HdrCapabilities& getHdrCapabilities() const;
// Return true if intent is supported by the display.
bool hasRenderIntent(ui::RenderIntent intent) const;
- void getBestColorMode(ui::Dataspace dataspace, ui::RenderIntent intent,
- ui::Dataspace* outDataspace, ui::ColorMode* outMode,
- ui::RenderIntent* outIntent) const;
-
- void setProtected(bool useProtected);
- // Queues the drawn buffer for consumption by HWC.
- void queueBuffer(HWComposer& hwc);
- // Allocates a buffer as scratch space for GPU composition
- sp<GraphicBuffer> dequeueBuffer();
-
- // called after h/w composer has completed its set() call
- void onPresentDisplayCompleted();
-
- Rect getBounds() const {
- return Rect(mDisplayWidth, mDisplayHeight);
- }
- inline Rect bounds() const { return getBounds(); }
+ const Rect& getBounds() const;
+ const Rect& bounds() const { return getBounds(); }
void setDisplayName(const std::string& displayName);
const std::string& getDisplayName() const { return mDisplayName; }
- // Acquires a new buffer for GPU composition.
- void readyNewBuffer();
- // Marks the current buffer has finished, so that it can be presented and
- // swapped out.
- void finishBuffer();
- void setViewportAndProjection() const;
-
- const sp<Fence>& getClientTargetAcquireFence() const;
-
/* ------------------------------------------------------------------------
* Display power mode management.
*/
@@ -180,13 +143,6 @@
void setPowerMode(int mode);
bool isPoweredOn() const;
- ui::ColorMode getActiveColorMode() const;
- void setActiveColorMode(ui::ColorMode mode);
- ui::RenderIntent getActiveRenderIntent() const;
- void setActiveRenderIntent(ui::RenderIntent renderIntent);
- android_color_transform_t getColorTransform() const;
- void setColorTransform(const mat4& transform);
- void setCompositionDataSpace(ui::Dataspace dataspace);
ui::Dataspace getCompositionDataSpace() const;
/* ------------------------------------------------------------------------
@@ -196,7 +152,7 @@
void setActiveConfig(int mode);
// release HWC resources (if any) for removable displays
- void disconnect(HWComposer& hwc);
+ void disconnect();
/* ------------------------------------------------------------------------
* Debugging
@@ -206,29 +162,18 @@
void dump(std::string& result) const;
private:
+ /*
+ * Constants, set during initialization
+ */
const sp<SurfaceFlinger> mFlinger;
const wp<IBinder> mDisplayToken;
const int32_t mSequenceId;
- std::optional<DisplayId> mId;
+ const int mDisplayInstallOrientation;
+ const std::shared_ptr<compositionengine::Display> mCompositionDisplay;
- // ANativeWindow this display is rendering into
- sp<ANativeWindow> mNativeWindow;
- // Current buffer that this display can render to.
- sp<GraphicBuffer> mGraphicBuffer;
- sp<DisplaySurface> mDisplaySurface;
- // File descriptor indicating that mGraphicBuffer is ready for display, i.e.
- // that drawing to the buffer is now complete.
- base::unique_fd mBufferReady;
-
- int mDisplayWidth;
- int mDisplayHeight;
- const int mDisplayInstallOrientation;
- mutable uint32_t mPageFlipCount;
- std::string mDisplayName;
-
+ std::string mDisplayName;
const bool mIsVirtual;
- const bool mIsSecure;
/*
* Can only accessed from the main thread, these members
@@ -243,66 +188,17 @@
/*
* Transaction state
*/
+ static uint32_t displayStateOrientationToTransformOrientation(int orientation);
static status_t orientationToTransfrom(int orientation,
int w, int h, ui::Transform* tr);
- // The identifier of the active layer stack for this display. Several displays
- // can use the same layer stack: A z-ordered group of layers (sometimes called
- // "surfaces"). Any given layer can only be on a single layer stack.
- uint32_t mLayerStack;
-
int mOrientation;
static uint32_t sPrimaryDisplayOrientation;
- // user-provided visible area of the layer stack
- Rect mViewport;
- // user-provided rectangle where mViewport gets mapped to
- Rect mFrame;
- // pre-computed scissor to apply to the display
- Rect mScissor;
- ui::Transform mGlobalTransform;
- bool mNeedsFiltering;
+
// Current power mode
int mPowerMode;
// Current active config
int mActiveConfig;
- // current active color mode
- ui::ColorMode mActiveColorMode = ui::ColorMode::NATIVE;
- // Current active render intent.
- ui::RenderIntent mActiveRenderIntent = ui::RenderIntent::COLORIMETRIC;
- ui::Dataspace mCompositionDataSpace = ui::Dataspace::UNKNOWN;
- // Current color transform
- android_color_transform_t mColorTransform;
-
- // Need to know if display is wide-color capable or not.
- // Initialized by SurfaceFlinger when the DisplayDevice is created.
- // Fed to RenderEngine during composition.
- bool mHasWideColorGamut;
- bool mHasHdr10Plus;
- bool mHasHdr10;
- bool mHasHLG;
- bool mHasDolbyVision;
- HdrCapabilities mHdrCapabilities;
- const int32_t mSupportedPerFrameMetadata;
-
- // Mappings from desired Dataspace/RenderIntent to the supported
- // Dataspace/ColorMode/RenderIntent.
- using ColorModeKey = uint64_t;
- struct ColorModeValue {
- ui::Dataspace dataspace;
- ui::ColorMode colorMode;
- ui::RenderIntent renderIntent;
- };
-
- static ColorModeKey getColorModeKey(ui::Dataspace dataspace, ui::RenderIntent intent) {
- return (static_cast<uint64_t>(dataspace) << 32) | static_cast<uint32_t>(intent);
- }
- void populateColorModes(
- const std::unordered_map<ui::ColorMode, std::vector<ui::RenderIntent>>& hwcColorModes);
- void addColorMode(
- const std::unordered_map<ui::ColorMode, std::vector<ui::RenderIntent>>& hwcColorModes,
- const ui::ColorMode mode, const ui::RenderIntent intent);
-
- std::unordered_map<ColorModeKey, ColorModeValue> mColorModes;
// TODO(b/74619554): Remove special cases for primary display.
const bool mIsPrimary;
@@ -341,7 +237,7 @@
bool isVirtual{false};
bool isSecure{false};
sp<ANativeWindow> nativeWindow;
- sp<DisplaySurface> displaySurface;
+ sp<compositionengine::DisplaySurface> displaySurface;
int displayInstallOrientation{DisplayState::eOrientationDefault};
bool hasWideColorGamut{false};
HdrCapabilities hdrCapabilities;
diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
index 2d91c68..8343e5a 100644
--- a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
+++ b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
@@ -40,13 +40,12 @@
class BufferHandle {
public:
- BufferHandle(const native_handle_t* buffer)
- {
+ explicit BufferHandle(const native_handle_t* buffer) {
// nullptr is not a valid handle to HIDL
mHandle = (buffer) ? buffer : native_handle_init(mStorage, 0, 0);
}
- operator const hidl_handle&() const
+ operator const hidl_handle&() const // NOLINT(google-explicit-constructor)
{
return mHandle;
}
@@ -80,7 +79,7 @@
}
}
- operator const hidl_handle&() const
+ operator const hidl_handle&() const // NOLINT(google-explicit-constructor)
{
return mHandle;
}
@@ -261,17 +260,20 @@
const uint32_t bufferSlotCount = 1;
Error error = kDefaultError;
if (mClient_2_2) {
- mClient_2_2->createVirtualDisplay_2_2(width, height, *format, bufferSlotCount,
- [&](const auto& tmpError, const auto& tmpDisplay,
- const auto& tmpFormat) {
- error = tmpError;
- if (error != Error::NONE) {
- return;
- }
+ mClient_2_2->createVirtualDisplay_2_2(width, height,
+ static_cast<types::V1_1::PixelFormat>(*format),
+ bufferSlotCount,
+ [&](const auto& tmpError, const auto& tmpDisplay,
+ const auto& tmpFormat) {
+ error = tmpError;
+ if (error != Error::NONE) {
+ return;
+ }
- *outDisplay = tmpDisplay;
- *format = tmpFormat;
- });
+ *outDisplay = tmpDisplay;
+ *format = static_cast<types::V1_2::PixelFormat>(
+ tmpFormat);
+ });
} else {
mClient->createVirtualDisplay(width, height,
static_cast<types::V1_0::PixelFormat>(*format), bufferSlotCount,
diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.h b/services/surfaceflinger/DisplayHardware/ComposerHal.h
index 9d0d8d9..542e840 100644
--- a/services/surfaceflinger/DisplayHardware/ComposerHal.h
+++ b/services/surfaceflinger/DisplayHardware/ComposerHal.h
@@ -48,11 +48,11 @@
using types::V1_0::ColorTransform;
using types::V1_0::Transform;
-using types::V1_1::PixelFormat;
using types::V1_1::RenderIntent;
using types::V1_2::ColorMode;
using types::V1_2::Dataspace;
using types::V1_2::Hdr;
+using types::V1_2::PixelFormat;
using V2_1::Config;
using V2_1::Display;
@@ -285,7 +285,7 @@
// Composer is a wrapper to IComposer, a proxy to server-side composer.
class Composer final : public Hwc2::Composer {
public:
- Composer(const std::string& serviceName);
+ explicit Composer(const std::string& serviceName);
~Composer() override;
std::vector<IComposer::Capability> getCapabilities() override;
@@ -418,7 +418,7 @@
private:
class CommandWriter : public CommandWriterBase {
public:
- CommandWriter(uint32_t initialMaxSize);
+ explicit CommandWriter(uint32_t initialMaxSize);
~CommandWriter() override;
void setLayerInfo(uint32_t type, uint32_t appId);
diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.h b/services/surfaceflinger/DisplayHardware/FramebufferSurface.h
index 2431dfd..7f451a5 100644
--- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.h
+++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.h
@@ -17,15 +17,15 @@
#ifndef ANDROID_SF_FRAMEBUFFER_SURFACE_H
#define ANDROID_SF_FRAMEBUFFER_SURFACE_H
-#include "DisplayIdentification.h"
-#include "DisplaySurface.h"
-#include "HWComposerBufferCache.h"
-
#include <stdint.h>
#include <sys/types.h>
+#include <compositionengine/DisplaySurface.h>
+#include <compositionengine/impl/HwcBufferCache.h>
#include <gui/ConsumerBase.h>
+#include "DisplayIdentification.h"
+
// ---------------------------------------------------------------------------
namespace android {
// ---------------------------------------------------------------------------
@@ -36,8 +36,7 @@
// ---------------------------------------------------------------------------
-class FramebufferSurface : public ConsumerBase,
- public DisplaySurface {
+class FramebufferSurface : public ConsumerBase, public compositionengine::DisplaySurface {
public:
FramebufferSurface(HWComposer& hwc, DisplayId displayId,
const sp<IGraphicBufferConsumer>& consumer);
@@ -89,7 +88,7 @@
// Hardware composer, owned by SurfaceFlinger.
HWComposer& mHwc;
- HWComposerBufferCache mHwcBufferCache;
+ compositionengine::impl::HwcBufferCache mHwcBufferCache;
// Previous buffer to release after getting an updated retire fence
bool mHasPendingRelease;
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp
index 392b608..68e7876 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp
@@ -143,8 +143,8 @@
return error;
}
- auto display = std::make_unique<Display>(
- *mComposer.get(), mPowerAdvisor, mCapabilities, displayId, DisplayType::Virtual);
+ auto display = std::make_unique<impl::Display>(*mComposer.get(), mPowerAdvisor, 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<Display>(
- *mComposer.get(), mPowerAdvisor, mCapabilities, displayId, displayType);
+ auto newDisplay = std::make_unique<impl::Display>(*mComposer.get(), mPowerAdvisor,
+ mCapabilities, displayId, displayType);
newDisplay->setConnected(true);
mDisplays.emplace(displayId, std::move(newDisplay));
} else if (connection == Connection::Disconnected) {
@@ -224,7 +224,36 @@
}
// Display methods
+Display::~Display() = default;
+Display::Config::Config(Display& display, hwc2_config_t id)
+ : mDisplay(display),
+ mId(id),
+ mWidth(-1),
+ mHeight(-1),
+ mVsyncPeriod(-1),
+ mDpiX(-1),
+ mDpiY(-1) {}
+
+Display::Config::Builder::Builder(Display& display, hwc2_config_t id)
+ : mConfig(new Config(display, id)) {}
+
+float Display::Config::Builder::getDefaultDensity() {
+ // Default density is based on TVs: 1080p displays get XHIGH density, lower-
+ // resolution displays get TV density. Maybe eventually we'll need to update
+ // it for 4k displays, though hopefully those will just report accurate DPI
+ // information to begin with. This is also used for virtual displays and
+ // older HWC implementations, so be careful about orientation.
+
+ auto longDimension = std::max(mConfig->mWidth, mConfig->mHeight);
+ if (longDimension >= 1080) {
+ return ACONFIGURATION_DENSITY_XHIGH;
+ } else {
+ return ACONFIGURATION_DENSITY_TV;
+ }
+}
+
+namespace impl {
Display::Display(android::Hwc2::Composer& composer, android::Hwc2::PowerAdvisor& advisor,
const std::unordered_set<Capability>& capabilities, hwc2_display_t id,
DisplayType type)
@@ -272,35 +301,7 @@
}
}
-Display::Config::Config(Display& display, hwc2_config_t id)
- : mDisplay(display),
- mId(id),
- mWidth(-1),
- mHeight(-1),
- mVsyncPeriod(-1),
- mDpiX(-1),
- mDpiY(-1) {}
-
-Display::Config::Builder::Builder(Display& display, hwc2_config_t id)
- : mConfig(new Config(display, id)) {}
-
-float Display::Config::Builder::getDefaultDensity() {
- // Default density is based on TVs: 1080p displays get XHIGH density, lower-
- // resolution displays get TV density. Maybe eventually we'll need to update
- // it for 4k displays, though hopefully those will just report accurate DPI
- // information to begin with. This is also used for virtual displays and
- // older HWC implementations, so be careful about orientation.
-
- auto longDimension = std::max(mConfig->mWidth, mConfig->mHeight);
- if (longDimension >= 1080) {
- return ACONFIGURATION_DENSITY_XHIGH;
- } else {
- return ACONFIGURATION_DENSITY_TV;
- }
-}
-
// Required by HWC2 display
-
Error Display::acceptChanges()
{
auto intError = mComposer.acceptDisplayChanges(mId);
@@ -794,6 +795,7 @@
return mLayers.at(id).get();
}
+} // namespace impl
// Layer methods
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.h b/services/surfaceflinger/DisplayHardware/HWC2.h
index f5cb97e..c1f481a 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.h
+++ b/services/surfaceflinger/DisplayHardware/HWC2.h
@@ -130,16 +130,11 @@
};
// Convenience C++ class to access hwc2_device_t Display functions directly.
-class Display
-{
+class Display {
public:
- Display(android::Hwc2::Composer& composer, android::Hwc2::PowerAdvisor& advisor,
- const std::unordered_set<Capability>& capabilities,
- hwc2_display_t id, DisplayType type);
- ~Display();
+ virtual ~Display();
- class Config
- {
+ class Config {
public:
class Builder
{
@@ -207,78 +202,136 @@
float mDpiY;
};
- // Required by HWC2
+ virtual hwc2_display_t getId() const = 0;
+ virtual bool isConnected() const = 0;
+ virtual void setConnected(bool connected) = 0; // For use by Device only
+ virtual const std::unordered_set<DisplayCapability>& getCapabilities() const = 0;
- [[clang::warn_unused_result]] Error acceptChanges();
- [[clang::warn_unused_result]] Error createLayer(Layer** outLayer);
- [[clang::warn_unused_result]] Error destroyLayer(Layer* layer);
- [[clang::warn_unused_result]] Error getActiveConfig(
- std::shared_ptr<const Config>* outConfig) const;
- [[clang::warn_unused_result]] Error getActiveConfigIndex(int* outIndex) const;
- [[clang::warn_unused_result]] Error getChangedCompositionTypes(
- std::unordered_map<Layer*, Composition>* outTypes);
- [[clang::warn_unused_result]] Error getColorModes(
- std::vector<android::ui::ColorMode>* outModes) const;
+ [[clang::warn_unused_result]] virtual Error acceptChanges() = 0;
+ [[clang::warn_unused_result]] virtual Error createLayer(Layer** outLayer) = 0;
+ [[clang::warn_unused_result]] virtual Error destroyLayer(Layer* layer) = 0;
+ [[clang::warn_unused_result]] virtual Error getActiveConfig(
+ std::shared_ptr<const Config>* outConfig) const = 0;
+ [[clang::warn_unused_result]] virtual Error getActiveConfigIndex(int* outIndex) const = 0;
+ [[clang::warn_unused_result]] virtual Error getChangedCompositionTypes(
+ std::unordered_map<Layer*, Composition>* outTypes) = 0;
+ [[clang::warn_unused_result]] virtual Error getColorModes(
+ std::vector<android::ui::ColorMode>* outModes) const = 0;
// Returns a bitmask which contains HdrMetadata::Type::*.
- [[clang::warn_unused_result]] int32_t getSupportedPerFrameMetadata() const;
- [[clang::warn_unused_result]] Error getRenderIntents(
+ [[clang::warn_unused_result]] virtual int32_t getSupportedPerFrameMetadata() const = 0;
+ [[clang::warn_unused_result]] virtual Error getRenderIntents(
android::ui::ColorMode colorMode,
- std::vector<android::ui::RenderIntent>* outRenderIntents) const;
- [[clang::warn_unused_result]] Error getDataspaceSaturationMatrix(
- android::ui::Dataspace dataspace, android::mat4* outMatrix);
+ std::vector<android::ui::RenderIntent>* outRenderIntents) const = 0;
+ [[clang::warn_unused_result]] virtual Error getDataspaceSaturationMatrix(
+ android::ui::Dataspace dataspace, android::mat4* outMatrix) = 0;
+
+ // Doesn't call into the HWC2 device, so no Errors are possible
+ virtual std::vector<std::shared_ptr<const Config>> getConfigs() const = 0;
+
+ [[clang::warn_unused_result]] virtual Error getName(std::string* outName) const = 0;
+ [[clang::warn_unused_result]] virtual Error getRequests(
+ DisplayRequest* outDisplayRequests,
+ std::unordered_map<Layer*, LayerRequest>* outLayerRequests) = 0;
+ [[clang::warn_unused_result]] virtual Error getType(DisplayType* outType) const = 0;
+ [[clang::warn_unused_result]] virtual Error supportsDoze(bool* outSupport) const = 0;
+ [[clang::warn_unused_result]] virtual Error getHdrCapabilities(
+ android::HdrCapabilities* outCapabilities) const = 0;
+ [[clang::warn_unused_result]] virtual Error getDisplayedContentSamplingAttributes(
+ android::ui::PixelFormat* outFormat, android::ui::Dataspace* outDataspace,
+ uint8_t* outComponentMask) const = 0;
+ [[clang::warn_unused_result]] virtual Error setDisplayContentSamplingEnabled(
+ bool enabled, uint8_t componentMask, uint64_t maxFrames) const = 0;
+ [[clang::warn_unused_result]] virtual Error getDisplayedContentSample(
+ uint64_t maxFrames, uint64_t timestamp,
+ android::DisplayedFrameStats* outStats) const = 0;
+ [[clang::warn_unused_result]] virtual Error getReleaseFences(
+ std::unordered_map<Layer*, android::sp<android::Fence>>* outFences) const = 0;
+ [[clang::warn_unused_result]] virtual Error present(
+ android::sp<android::Fence>* outPresentFence) = 0;
+ [[clang::warn_unused_result]] virtual Error setActiveConfig(
+ const std::shared_ptr<const Config>& config) = 0;
+ [[clang::warn_unused_result]] virtual Error setClientTarget(
+ uint32_t slot, const android::sp<android::GraphicBuffer>& target,
+ const android::sp<android::Fence>& acquireFence, android::ui::Dataspace dataspace) = 0;
+ [[clang::warn_unused_result]] virtual Error setColorMode(
+ android::ui::ColorMode mode, android::ui::RenderIntent renderIntent) = 0;
+ [[clang::warn_unused_result]] virtual Error setColorTransform(
+ const android::mat4& matrix, android_color_transform_t hint) = 0;
+ [[clang::warn_unused_result]] virtual Error setOutputBuffer(
+ const android::sp<android::GraphicBuffer>& buffer,
+ const android::sp<android::Fence>& releaseFence) = 0;
+ [[clang::warn_unused_result]] virtual Error setPowerMode(PowerMode mode) = 0;
+ [[clang::warn_unused_result]] virtual Error setVsyncEnabled(Vsync enabled) = 0;
+ [[clang::warn_unused_result]] virtual Error validate(uint32_t* outNumTypes,
+ uint32_t* outNumRequests) = 0;
+ [[clang::warn_unused_result]] virtual Error presentOrValidate(
+ uint32_t* outNumTypes, uint32_t* outNumRequests,
+ android::sp<android::Fence>* outPresentFence, uint32_t* state) = 0;
+};
+
+namespace impl {
+
+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() override;
+
+ // Required by HWC2
+ Error acceptChanges() override;
+ Error createLayer(Layer** outLayer) override;
+ Error destroyLayer(Layer* layer) override;
+ Error getActiveConfig(std::shared_ptr<const Config>* outConfig) const override;
+ Error getActiveConfigIndex(int* outIndex) const override;
+ Error getChangedCompositionTypes(std::unordered_map<Layer*, Composition>* outTypes) override;
+ Error getColorModes(std::vector<android::ui::ColorMode>* outModes) const override;
+ // Returns a bitmask which contains HdrMetadata::Type::*.
+ int32_t getSupportedPerFrameMetadata() const override;
+ Error getRenderIntents(android::ui::ColorMode colorMode,
+ std::vector<android::ui::RenderIntent>* outRenderIntents) const override;
+ Error getDataspaceSaturationMatrix(android::ui::Dataspace dataspace,
+ android::mat4* outMatrix) override;
// Doesn't call into the HWC2 device, so no errors are possible
- std::vector<std::shared_ptr<const Config>> getConfigs() const;
+ std::vector<std::shared_ptr<const Config>> getConfigs() const override;
- [[clang::warn_unused_result]] Error getName(std::string* outName) const;
- [[clang::warn_unused_result]] Error getRequests(
- DisplayRequest* outDisplayRequests,
- std::unordered_map<Layer*, LayerRequest>* outLayerRequests);
- [[clang::warn_unused_result]] Error getType(DisplayType* outType) const;
- [[clang::warn_unused_result]] Error supportsDoze(bool* outSupport) const;
- [[clang::warn_unused_result]] Error getHdrCapabilities(
- android::HdrCapabilities* outCapabilities) const;
- [[clang::warn_unused_result]] Error getDisplayedContentSamplingAttributes(
- android::ui::PixelFormat* outFormat, android::ui::Dataspace* outDataspace,
- uint8_t* outComponentMask) const;
- [[clang::warn_unused_result]] Error setDisplayContentSamplingEnabled(bool enabled,
- uint8_t componentMask,
- uint64_t maxFrames) const;
- [[clang::warn_unused_result]] Error getDisplayedContentSample(
- uint64_t maxFrames, uint64_t timestamp, android::DisplayedFrameStats* outStats) const;
- [[clang::warn_unused_result]] Error getReleaseFences(
- std::unordered_map<Layer*,
- android::sp<android::Fence>>* outFences) const;
- [[clang::warn_unused_result]] Error present(
- android::sp<android::Fence>* outPresentFence);
- [[clang::warn_unused_result]] Error setActiveConfig(
- const std::shared_ptr<const Config>& config);
- [[clang::warn_unused_result]] Error setClientTarget(
- uint32_t slot, const android::sp<android::GraphicBuffer>& target,
- const android::sp<android::Fence>& acquireFence,
- android::ui::Dataspace dataspace);
- [[clang::warn_unused_result]] Error setColorMode(
- android::ui::ColorMode mode,
- android::ui::RenderIntent renderIntent);
- [[clang::warn_unused_result]] Error setColorTransform(
- const android::mat4& matrix, android_color_transform_t hint);
- [[clang::warn_unused_result]] Error setOutputBuffer(
- const android::sp<android::GraphicBuffer>& buffer,
- const android::sp<android::Fence>& releaseFence);
- [[clang::warn_unused_result]] Error setPowerMode(PowerMode mode);
- [[clang::warn_unused_result]] Error setVsyncEnabled(Vsync enabled);
- [[clang::warn_unused_result]] Error validate(uint32_t* outNumTypes,
- uint32_t* outNumRequests);
- [[clang::warn_unused_result]] Error presentOrValidate(uint32_t* outNumTypes,
- uint32_t* outNumRequests,
- android::sp<android::Fence>* outPresentFence, uint32_t* state);
+ Error getName(std::string* outName) const override;
+ Error getRequests(DisplayRequest* outDisplayRequests,
+ std::unordered_map<Layer*, LayerRequest>* outLayerRequests) override;
+ Error getType(DisplayType* outType) const override;
+ Error supportsDoze(bool* outSupport) const override;
+ Error getHdrCapabilities(android::HdrCapabilities* outCapabilities) const override;
+ Error getDisplayedContentSamplingAttributes(android::ui::PixelFormat* outFormat,
+ android::ui::Dataspace* outDataspace,
+ uint8_t* outComponentMask) const override;
+ Error setDisplayContentSamplingEnabled(bool enabled, uint8_t componentMask,
+ uint64_t maxFrames) const override;
+ Error getDisplayedContentSample(uint64_t maxFrames, uint64_t timestamp,
+ android::DisplayedFrameStats* outStats) const override;
+ Error getReleaseFences(
+ std::unordered_map<Layer*, android::sp<android::Fence>>* outFences) const override;
+ Error present(android::sp<android::Fence>* outPresentFence) override;
+ Error setActiveConfig(const std::shared_ptr<const HWC2::Display::Config>& config) override;
+ Error setClientTarget(uint32_t slot, const android::sp<android::GraphicBuffer>& target,
+ const android::sp<android::Fence>& acquireFence,
+ android::ui::Dataspace dataspace) override;
+ Error setColorMode(android::ui::ColorMode mode,
+ android::ui::RenderIntent renderIntent) override;
+ Error setColorTransform(const android::mat4& matrix, android_color_transform_t hint) override;
+ Error setOutputBuffer(const android::sp<android::GraphicBuffer>& buffer,
+ const android::sp<android::Fence>& releaseFence) override;
+ Error setPowerMode(PowerMode mode) override;
+ Error setVsyncEnabled(Vsync enabled) override;
+ Error validate(uint32_t* outNumTypes, uint32_t* outNumRequests) override;
+ Error presentOrValidate(uint32_t* outNumTypes, uint32_t* outNumRequests,
+ android::sp<android::Fence>* outPresentFence, uint32_t* state) override;
// Other Display methods
-
- hwc2_display_t getId() const { return mId; }
- bool isConnected() const { return mIsConnected; }
- void setConnected(bool connected); // For use by Device only
- const std::unordered_set<DisplayCapability>& getCapabilities() const {
+ hwc2_display_t getId() const override { return mId; }
+ bool isConnected() const override { return mIsConnected; }
+ void setConnected(bool connected) override; // For use by Device only
+ const std::unordered_set<DisplayCapability>& getCapabilities() const override {
return mDisplayCapabilities;
};
@@ -309,6 +362,7 @@
std::unordered_map<hwc2_config_t, std::shared_ptr<const Config>> mConfigs;
std::unordered_set<DisplayCapability> mDisplayCapabilities;
};
+} // namespace impl
// Convenience C++ class to access hwc2_device_t Layer functions directly.
class Layer
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 0497571..5b4d347 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -66,6 +66,10 @@
namespace android {
+HWComposer::~HWComposer() = default;
+
+namespace impl {
+
HWComposer::HWComposer(std::unique_ptr<Hwc2::Composer> composer)
: mHwcDevice(std::make_unique<HWC2::Device>(std::move(composer))) {}
@@ -98,6 +102,10 @@
bool HWComposer::hasDisplayCapability(const std::optional<DisplayId>& displayId,
HWC2::DisplayCapability capability) const {
if (!displayId) {
+ // Checkout global capabilities for displays without a corresponding HWC display.
+ if (capability == HWC2::DisplayCapability::SkipClientColorTransform) {
+ return hasCapability(HWC2::Capability::SkipClientColorTransform);
+ }
return false;
}
RETURN_IF_INVALID_DISPLAY(*displayId, false);
@@ -854,4 +862,5 @@
: "External display"};
}
+} // namespace impl
} // namespace android
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index d9a0916..f42f860 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -45,134 +45,273 @@
class Composer;
} // namespace Hwc2
-class HWComposer
-{
+class HWComposer {
+public:
+ virtual ~HWComposer();
+
+ virtual void registerCallback(HWC2::ComposerCallback* callback, int32_t sequenceId) = 0;
+
+ virtual bool getDisplayIdentificationData(hwc2_display_t hwcDisplayId, uint8_t* outPort,
+ DisplayIdentificationData* outData) const = 0;
+
+ virtual bool hasCapability(HWC2::Capability capability) const = 0;
+ virtual bool hasDisplayCapability(const std::optional<DisplayId>& displayId,
+ HWC2::DisplayCapability capability) const = 0;
+
+ // Attempts to allocate a virtual display and returns its ID if created on the HWC device.
+ virtual std::optional<DisplayId> allocateVirtualDisplay(uint32_t width, uint32_t height,
+ ui::PixelFormat* format) = 0;
+
+ // Attempts to create a new layer on this display
+ virtual HWC2::Layer* createLayer(DisplayId displayId) = 0;
+ // Destroy a previously created layer
+ virtual void destroyLayer(DisplayId displayId, HWC2::Layer* layer) = 0;
+
+ // Asks the HAL what it can do
+ virtual status_t prepare(DisplayId displayId,
+ std::vector<CompositionInfo>& compositionData) = 0;
+
+ virtual status_t setClientTarget(DisplayId displayId, uint32_t slot,
+ const sp<Fence>& acquireFence, const sp<GraphicBuffer>& target,
+ ui::Dataspace dataspace) = 0;
+
+ // Present layers to the display and read releaseFences.
+ virtual status_t presentAndGetReleaseFences(DisplayId displayId) = 0;
+
+ // set power mode
+ virtual status_t setPowerMode(DisplayId displayId, int mode) = 0;
+
+ // set active config
+ virtual status_t setActiveConfig(DisplayId displayId, size_t configId) = 0;
+
+ // Sets a color transform to be applied to the result of composition
+ virtual status_t setColorTransform(DisplayId displayId, const mat4& transform) = 0;
+
+ // reset state when an external, non-virtual display is disconnected
+ virtual void disconnectDisplay(DisplayId displayId) = 0;
+
+ // does this display have layers handled by HWC
+ virtual bool hasDeviceComposition(const std::optional<DisplayId>& displayId) const = 0;
+
+ // does this display have pending request to flip client target
+ virtual bool hasFlipClientTargetRequest(const std::optional<DisplayId>& displayId) const = 0;
+
+ // does this display have layers handled by GLES
+ virtual bool hasClientComposition(const std::optional<DisplayId>& displayId) const = 0;
+
+ // get the present fence received from the last call to present.
+ virtual sp<Fence> getPresentFence(DisplayId displayId) const = 0;
+
+ // Get last release fence for the given layer
+ virtual sp<Fence> getLayerReleaseFence(DisplayId displayId, HWC2::Layer* layer) const = 0;
+
+ // Set the output buffer and acquire fence for a virtual display.
+ // Returns INVALID_OPERATION if displayId is not a virtual display.
+ virtual status_t setOutputBuffer(DisplayId displayId, const sp<Fence>& acquireFence,
+ const sp<GraphicBuffer>& buffer) = 0;
+
+ // After SurfaceFlinger has retrieved the release fences for all the frames,
+ // it can call this to clear the shared pointers in the release fence map
+ virtual void clearReleaseFences(DisplayId displayId) = 0;
+
+ // Fetches the HDR capabilities of the given display
+ virtual status_t getHdrCapabilities(DisplayId displayId, HdrCapabilities* outCapabilities) = 0;
+
+ virtual int32_t getSupportedPerFrameMetadata(DisplayId displayId) const = 0;
+
+ // Returns the available RenderIntent of the given display.
+ virtual std::vector<ui::RenderIntent> getRenderIntents(DisplayId displayId,
+ ui::ColorMode colorMode) const = 0;
+
+ virtual mat4 getDataspaceSaturationMatrix(DisplayId displayId, ui::Dataspace dataspace) = 0;
+
+ // Returns the attributes of the color sampling engine.
+ virtual status_t getDisplayedContentSamplingAttributes(DisplayId displayId,
+ ui::PixelFormat* outFormat,
+ ui::Dataspace* outDataspace,
+ uint8_t* outComponentMask) = 0;
+ virtual status_t setDisplayContentSamplingEnabled(DisplayId displayId, bool enabled,
+ uint8_t componentMask,
+ uint64_t maxFrames) = 0;
+ virtual status_t getDisplayedContentSample(DisplayId displayId, uint64_t maxFrames,
+ uint64_t timestamp,
+ DisplayedFrameStats* outStats) = 0;
+
+ // Events handling ---------------------------------------------------------
+
+ // Returns stable display ID (and display name on connection of new or previously disconnected
+ // display), or std::nullopt if hotplug event was ignored.
+ virtual std::optional<DisplayIdentificationInfo> onHotplug(hwc2_display_t hwcDisplayId,
+ HWC2::Connection connection) = 0;
+
+ virtual bool onVsync(hwc2_display_t hwcDisplayId, int64_t timestamp) = 0;
+ virtual void setVsyncEnabled(DisplayId displayId, HWC2::Vsync enabled) = 0;
+
+ virtual nsecs_t getRefreshTimestamp(DisplayId displayId) const = 0;
+ virtual bool isConnected(DisplayId displayId) const = 0;
+
+ // Non-const because it can update configMap inside of mDisplayData
+ virtual std::vector<std::shared_ptr<const HWC2::Display::Config>> getConfigs(
+ DisplayId displayId) const = 0;
+
+ virtual std::shared_ptr<const HWC2::Display::Config> getActiveConfig(
+ DisplayId displayId) const = 0;
+ virtual int getActiveConfigIndex(DisplayId displayId) const = 0;
+
+ virtual std::vector<ui::ColorMode> getColorModes(DisplayId displayId) const = 0;
+
+ virtual status_t setActiveColorMode(DisplayId displayId, ui::ColorMode mode,
+ ui::RenderIntent renderIntent) = 0;
+
+ virtual bool isUsingVrComposer() const = 0;
+
+ // for debugging ----------------------------------------------------------
+ virtual void dump(std::string& out) const = 0;
+
+ virtual Hwc2::Composer* getComposer() const = 0;
+
+ // TODO(b/74619554): Remove special cases for internal/external display.
+ virtual std::optional<hwc2_display_t> getInternalHwcDisplayId() const = 0;
+ virtual std::optional<hwc2_display_t> getExternalHwcDisplayId() const = 0;
+
+ virtual std::optional<DisplayId> toPhysicalDisplayId(hwc2_display_t hwcDisplayId) const = 0;
+ virtual std::optional<hwc2_display_t> fromPhysicalDisplayId(DisplayId displayId) const = 0;
+};
+
+namespace impl {
+
+class HWComposer final : public android::HWComposer {
public:
explicit HWComposer(std::unique_ptr<Hwc2::Composer> composer);
- ~HWComposer();
+ ~HWComposer() override;
- void registerCallback(HWC2::ComposerCallback* callback,
- int32_t sequenceId);
+ void registerCallback(HWC2::ComposerCallback* callback, int32_t sequenceId) override;
bool getDisplayIdentificationData(hwc2_display_t hwcDisplayId, uint8_t* outPort,
- DisplayIdentificationData* outData) const;
+ DisplayIdentificationData* outData) const override;
- bool hasCapability(HWC2::Capability capability) const;
+ bool hasCapability(HWC2::Capability capability) const override;
bool hasDisplayCapability(const std::optional<DisplayId>& displayId,
- HWC2::DisplayCapability capability) const;
+ HWC2::DisplayCapability capability) const override;
// Attempts to allocate a virtual display and returns its ID if created on the HWC device.
std::optional<DisplayId> allocateVirtualDisplay(uint32_t width, uint32_t height,
- ui::PixelFormat* format);
+ ui::PixelFormat* format) override;
// Attempts to create a new layer on this display
- HWC2::Layer* createLayer(DisplayId displayId);
+ HWC2::Layer* createLayer(DisplayId displayId) override;
// Destroy a previously created layer
- void destroyLayer(DisplayId displayId, HWC2::Layer* layer);
+ void destroyLayer(DisplayId displayId, HWC2::Layer* layer) override;
// Asks the HAL what it can do
- status_t prepare(DisplayId displayId, std::vector<CompositionInfo>& compositionData);
+ status_t prepare(DisplayId displayId, std::vector<CompositionInfo>& compositionData) override;
status_t setClientTarget(DisplayId displayId, uint32_t slot, const sp<Fence>& acquireFence,
- const sp<GraphicBuffer>& target, ui::Dataspace dataspace);
+ const sp<GraphicBuffer>& target, ui::Dataspace dataspace) override;
// Present layers to the display and read releaseFences.
- status_t presentAndGetReleaseFences(DisplayId displayId);
+ status_t presentAndGetReleaseFences(DisplayId displayId) override;
// set power mode
- status_t setPowerMode(DisplayId displayId, int mode);
+ status_t setPowerMode(DisplayId displayId, int mode) override;
// set active config
- status_t setActiveConfig(DisplayId displayId, size_t configId);
+ status_t setActiveConfig(DisplayId displayId, size_t configId) override;
// Sets a color transform to be applied to the result of composition
- status_t setColorTransform(DisplayId displayId, const mat4& transform);
+ status_t setColorTransform(DisplayId displayId, const mat4& transform) override;
// reset state when an external, non-virtual display is disconnected
- void disconnectDisplay(DisplayId displayId);
+ void disconnectDisplay(DisplayId displayId) override;
// does this display have layers handled by HWC
- bool hasDeviceComposition(const std::optional<DisplayId>& displayId) const;
+ bool hasDeviceComposition(const std::optional<DisplayId>& displayId) const override;
// does this display have pending request to flip client target
- bool hasFlipClientTargetRequest(const std::optional<DisplayId>& displayId) const;
+ bool hasFlipClientTargetRequest(const std::optional<DisplayId>& displayId) const override;
// does this display have layers handled by GLES
- bool hasClientComposition(const std::optional<DisplayId>& displayId) const;
+ bool hasClientComposition(const std::optional<DisplayId>& displayId) const override;
// get the present fence received from the last call to present.
- sp<Fence> getPresentFence(DisplayId displayId) const;
+ sp<Fence> getPresentFence(DisplayId displayId) const override;
// Get last release fence for the given layer
- sp<Fence> getLayerReleaseFence(DisplayId displayId, HWC2::Layer* layer) const;
+ sp<Fence> getLayerReleaseFence(DisplayId displayId, HWC2::Layer* layer) const override;
// Set the output buffer and acquire fence for a virtual display.
// Returns INVALID_OPERATION if displayId is not a virtual display.
status_t setOutputBuffer(DisplayId displayId, const sp<Fence>& acquireFence,
- const sp<GraphicBuffer>& buffer);
+ const sp<GraphicBuffer>& buffer) override;
// After SurfaceFlinger has retrieved the release fences for all the frames,
// it can call this to clear the shared pointers in the release fence map
- void clearReleaseFences(DisplayId displayId);
+ void clearReleaseFences(DisplayId displayId) override;
// Fetches the HDR capabilities of the given display
- status_t getHdrCapabilities(DisplayId displayId, HdrCapabilities* outCapabilities);
+ status_t getHdrCapabilities(DisplayId displayId, HdrCapabilities* outCapabilities) override;
- int32_t getSupportedPerFrameMetadata(DisplayId displayId) const;
+ int32_t getSupportedPerFrameMetadata(DisplayId displayId) const override;
// Returns the available RenderIntent of the given display.
std::vector<ui::RenderIntent> getRenderIntents(DisplayId displayId,
- ui::ColorMode colorMode) const;
+ ui::ColorMode colorMode) const override;
- mat4 getDataspaceSaturationMatrix(DisplayId displayId, ui::Dataspace dataspace);
+ mat4 getDataspaceSaturationMatrix(DisplayId displayId, ui::Dataspace dataspace) override;
// Returns the attributes of the color sampling engine.
status_t getDisplayedContentSamplingAttributes(DisplayId displayId, ui::PixelFormat* outFormat,
ui::Dataspace* outDataspace,
- uint8_t* outComponentMask);
+ uint8_t* outComponentMask) override;
status_t setDisplayContentSamplingEnabled(DisplayId displayId, bool enabled,
- uint8_t componentMask, uint64_t maxFrames);
+ uint8_t componentMask, uint64_t maxFrames) override;
status_t getDisplayedContentSample(DisplayId displayId, uint64_t maxFrames, uint64_t timestamp,
- DisplayedFrameStats* outStats);
+ DisplayedFrameStats* outStats) override;
// Events handling ---------------------------------------------------------
// Returns stable display ID (and display name on connection of new or previously disconnected
// display), or std::nullopt if hotplug event was ignored.
std::optional<DisplayIdentificationInfo> onHotplug(hwc2_display_t hwcDisplayId,
- HWC2::Connection connection);
+ HWC2::Connection connection) override;
- bool onVsync(hwc2_display_t hwcDisplayId, int64_t timestamp);
- void setVsyncEnabled(DisplayId displayId, HWC2::Vsync enabled);
+ bool onVsync(hwc2_display_t hwcDisplayId, int64_t timestamp) override;
+ void setVsyncEnabled(DisplayId displayId, HWC2::Vsync enabled) override;
- nsecs_t getRefreshTimestamp(DisplayId displayId) const;
- bool isConnected(DisplayId displayId) const;
+ nsecs_t getRefreshTimestamp(DisplayId displayId) const override;
+ bool isConnected(DisplayId displayId) const override;
// Non-const because it can update configMap inside of mDisplayData
- std::vector<std::shared_ptr<const HWC2::Display::Config>> getConfigs(DisplayId displayId) const;
+ std::vector<std::shared_ptr<const HWC2::Display::Config>> getConfigs(
+ DisplayId displayId) const override;
- std::shared_ptr<const HWC2::Display::Config> getActiveConfig(DisplayId displayId) const;
- int getActiveConfigIndex(DisplayId displayId) const;
+ std::shared_ptr<const HWC2::Display::Config> getActiveConfig(
+ DisplayId displayId) const override;
+ int getActiveConfigIndex(DisplayId displayId) const override;
- std::vector<ui::ColorMode> getColorModes(DisplayId displayId) const;
+ std::vector<ui::ColorMode> getColorModes(DisplayId displayId) const override;
status_t setActiveColorMode(DisplayId displayId, ui::ColorMode mode,
- ui::RenderIntent renderIntent);
+ ui::RenderIntent renderIntent) override;
- bool isUsingVrComposer() const;
+ bool isUsingVrComposer() const override;
// for debugging ----------------------------------------------------------
- void dump(std::string& out) const;
+ void dump(std::string& out) const override;
- Hwc2::Composer* getComposer() const { return mHwcDevice->getComposer(); }
+ Hwc2::Composer* getComposer() const override { return mHwcDevice->getComposer(); }
// TODO(b/74619554): Remove special cases for internal/external display.
- std::optional<hwc2_display_t> getInternalHwcDisplayId() const { return mInternalHwcDisplayId; }
- std::optional<hwc2_display_t> getExternalHwcDisplayId() const { return mExternalHwcDisplayId; }
+ std::optional<hwc2_display_t> getInternalHwcDisplayId() const override {
+ return mInternalHwcDisplayId;
+ }
+ std::optional<hwc2_display_t> getExternalHwcDisplayId() const override {
+ return mExternalHwcDisplayId;
+ }
- std::optional<DisplayId> toPhysicalDisplayId(hwc2_display_t hwcDisplayId) const;
- std::optional<hwc2_display_t> fromPhysicalDisplayId(DisplayId displayId) const;
+ std::optional<DisplayId> toPhysicalDisplayId(hwc2_display_t hwcDisplayId) const override;
+ std::optional<hwc2_display_t> fromPhysicalDisplayId(DisplayId displayId) const override;
private:
// For unit tests
@@ -223,6 +362,7 @@
uint32_t mRemainingHwcVirtualDisplays{mHwcDevice->getMaxVirtualDisplayCount()};
};
+} // namespace impl
} // namespace android
#endif // ANDROID_SF_HWCOMPOSER_H
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
index 27d3dc5..1c2853a 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
@@ -38,12 +38,16 @@
#define VDS_LOGV(msg, ...) ALOGV("[%s] " msg, \
mDisplayName.c_str(), ##__VA_ARGS__)
-static const char* dbgCompositionTypeStr(DisplaySurface::CompositionType type) {
+static const char* dbgCompositionTypeStr(compositionengine::DisplaySurface::CompositionType type) {
switch (type) {
- case DisplaySurface::COMPOSITION_UNKNOWN: return "UNKNOWN";
- case DisplaySurface::COMPOSITION_GLES: return "GLES";
- case DisplaySurface::COMPOSITION_HWC: return "HWC";
- case DisplaySurface::COMPOSITION_MIXED: return "MIXED";
+ case compositionengine::DisplaySurface::COMPOSITION_UNKNOWN:
+ return "UNKNOWN";
+ case compositionengine::DisplaySurface::COMPOSITION_GLES:
+ return "GLES";
+ case compositionengine::DisplaySurface::COMPOSITION_HWC:
+ return "HWC";
+ case compositionengine::DisplaySurface::COMPOSITION_MIXED:
+ return "MIXED";
default: return "<INVALID>";
}
}
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
index 33678df..d6543d1 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
@@ -20,13 +20,13 @@
#include <optional>
#include <string>
-#include "DisplayIdentification.h"
-#include "DisplaySurface.h"
-#include "HWComposerBufferCache.h"
-
+#include <compositionengine/DisplaySurface.h>
+#include <compositionengine/impl/HwcBufferCache.h>
#include <gui/ConsumerBase.h>
#include <gui/IGraphicBufferProducer.h>
+#include "DisplayIdentification.h"
+
// ---------------------------------------------------------------------------
namespace android {
// ---------------------------------------------------------------------------
@@ -73,7 +73,7 @@
* the HWC output buffer. When HWC composition is complete, the scratch buffer
* is released and the output buffer is queued to the sink.
*/
-class VirtualDisplaySurface : public DisplaySurface,
+class VirtualDisplaySurface : public compositionengine::DisplaySurface,
public BnGraphicBufferProducer,
private ConsumerBase {
public:
@@ -253,7 +253,7 @@
bool mMustRecompose;
- HWComposerBufferCache mHwcBufferCache;
+ compositionengine::impl::HwcBufferCache mHwcBufferCache;
bool mForceHwcCopy;
};
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index f4b3cdd..2de169d 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -46,6 +46,7 @@
#include <gui/Surface.h>
#include "BufferLayer.h"
+#include "ColorLayer.h"
#include "Colorizer.h"
#include "DisplayDevice.h"
#include "Layer.h"
@@ -83,35 +84,33 @@
mTransactionName = String8("TX - ") + mName;
- mState.current.active_legacy.w = args.w;
- mState.current.active_legacy.h = args.h;
- mState.current.flags = layerFlags;
- mState.current.active_legacy.transform.set(0, 0);
- mState.current.crop_legacy.makeInvalid();
- mState.current.requestedCrop_legacy = mState.current.crop_legacy;
- mState.current.z = 0;
- mState.current.color.a = 1.0f;
- mState.current.layerStack = 0;
- mState.current.sequence = 0;
- mState.current.requested_legacy = mState.current.active_legacy;
- mState.current.appId = 0;
- mState.current.type = 0;
- mState.current.active.w = UINT32_MAX;
- mState.current.active.h = UINT32_MAX;
- mState.current.active.transform.set(0, 0);
- mState.current.transform = 0;
- mState.current.transformToDisplayInverse = false;
- mState.current.crop.makeInvalid();
- mState.current.acquireFence = new Fence(-1);
- mState.current.dataspace = ui::Dataspace::UNKNOWN;
- mState.current.hdrMetadata.validTypes = 0;
- mState.current.surfaceDamageRegion.clear();
- mState.current.cornerRadius = 0.0f;
- mState.current.api = -1;
- mState.current.hasColorTransform = false;
+ mCurrentState.active_legacy.w = args.w;
+ mCurrentState.active_legacy.h = args.h;
+ mCurrentState.flags = layerFlags;
+ mCurrentState.active_legacy.transform.set(0, 0);
+ mCurrentState.crop_legacy.makeInvalid();
+ mCurrentState.requestedCrop_legacy = mCurrentState.crop_legacy;
+ mCurrentState.z = 0;
+ mCurrentState.color.a = 1.0f;
+ mCurrentState.layerStack = 0;
+ mCurrentState.sequence = 0;
+ mCurrentState.requested_legacy = mCurrentState.active_legacy;
+ mCurrentState.active.w = UINT32_MAX;
+ mCurrentState.active.h = UINT32_MAX;
+ mCurrentState.active.transform.set(0, 0);
+ mCurrentState.transform = 0;
+ mCurrentState.transformToDisplayInverse = false;
+ mCurrentState.crop.makeInvalid();
+ mCurrentState.acquireFence = new Fence(-1);
+ mCurrentState.dataspace = ui::Dataspace::UNKNOWN;
+ mCurrentState.hdrMetadata.validTypes = 0;
+ mCurrentState.surfaceDamageRegion.clear();
+ mCurrentState.cornerRadius = 0.0f;
+ mCurrentState.api = -1;
+ mCurrentState.hasColorTransform = false;
// drawing state & current state are identical
- mState.drawing = mState.current;
+ mDrawingState = mCurrentState;
CompositorTiming compositorTiming;
args.flinger->getCompositorTiming(&compositorTiming);
@@ -148,17 +147,14 @@
void Layer::onRemovedFromCurrentState() {
mRemovedFromCurrentState = true;
- {
- Mutex::Autolock lock(mStateMutex);
- // the layer is removed from SF mState.current to mLayersPendingRemoval
- if (mState.current.zOrderRelativeOf != nullptr) {
- sp<Layer> strongRelative = mState.current.zOrderRelativeOf.promote();
- if (strongRelative != nullptr) {
- strongRelative->removeZOrderRelative(this);
- mFlinger->setTransactionFlags(eTraversalNeeded);
- }
- mState.current.zOrderRelativeOf = nullptr;
+ // the layer is removed from SF mCurrentState to mLayersPendingRemoval
+ if (mCurrentState.zOrderRelativeOf != nullptr) {
+ sp<Layer> strongRelative = mCurrentState.zOrderRelativeOf.promote();
+ if (strongRelative != nullptr) {
+ strongRelative->removeZOrderRelative(this);
+ mFlinger->setTransactionFlags(eTraversalNeeded);
}
+ mCurrentState.zOrderRelativeOf = nullptr;
}
// Since we are no longer reachable from CurrentState SurfaceFlinger
@@ -182,6 +178,8 @@
for (const auto& child : mCurrentChildren) {
child->onRemovedFromCurrentState();
}
+
+ mFlinger->markLayerPendingRemovalLocked(this);
}
void Layer::addToCurrentState() {
@@ -297,32 +295,21 @@
}
Rect Layer::computeScreenBounds(bool reduceTransparentRegion) const {
- Mutex::Autolock lock(mStateMutex);
const State& s(getDrawingState());
Region transparentRegion = reduceTransparentRegion ? getActiveTransparentRegion(s) : Region();
- FloatRect bounds = computeBoundsLocked(transparentRegion);
- ui::Transform t = getTransformLocked();
+ FloatRect bounds = computeBounds(transparentRegion);
+ ui::Transform t = getTransform();
// Transform to screen space.
bounds = t.transform(bounds);
return Rect{bounds};
}
FloatRect Layer::computeBounds() const {
- Mutex::Autolock lock(mStateMutex);
- return computeBoundsLocked();
-}
-
-FloatRect Layer::computeBoundsLocked() const {
const State& s(getDrawingState());
- return computeBoundsLocked(getActiveTransparentRegion(s));
+ return computeBounds(getActiveTransparentRegion(s));
}
FloatRect Layer::computeBounds(const Region& activeTransparentRegion) const {
- Mutex::Autolock lock(mStateMutex);
- return computeBoundsLocked(activeTransparentRegion);
-}
-
-FloatRect Layer::computeBoundsLocked(const Region& activeTransparentRegion) const {
const State& s(getDrawingState());
Rect bounds = getCroppedBufferSize(s);
FloatRect floatBounds = bounds.toFloatRect();
@@ -375,7 +362,6 @@
// child bounds as well.
ui::Transform t = s.active_legacy.transform;
croppedBounds = t.transform(croppedBounds);
- Mutex::Autolock lock(p->mStateMutex);
croppedBounds = p->cropChildBounds(croppedBounds);
croppedBounds = t.inverse().transform(croppedBounds);
}
@@ -403,8 +389,8 @@
// if there are no window scaling involved, this operation will map to full
// pixels in the buffer.
- FloatRect activeCropFloat = computeBoundsLocked();
- ui::Transform t = getTransformLocked();
+ FloatRect activeCropFloat = computeBounds();
+ ui::Transform t = getTransform();
// Transform to screen space.
activeCropFloat = t.transform(activeCropFloat);
activeCropFloat = activeCropFloat.intersect(display->getViewport().toFloatRect());
@@ -454,7 +440,7 @@
// which means using the inverse of the current transform set on the
// SurfaceFlingerConsumer.
uint32_t invTransform = mCurrentTransform;
- if (getTransformToDisplayInverseLocked()) {
+ if (getTransformToDisplayInverse()) {
/*
* the code below applies the primary display's inverse transform to the
* buffer
@@ -505,7 +491,6 @@
}
void Layer::setGeometry(const sp<const DisplayDevice>& display, uint32_t z) {
- Mutex::Autolock lock(mStateMutex);
const auto displayId = display->getId();
LOG_ALWAYS_FATAL_IF(!displayId);
RETURN_IF_NO_HWC_LAYER(*displayId);
@@ -514,7 +499,7 @@
// enable this layer
hwcInfo.forceClientComposition = false;
- if (isSecureLocked() && !display->isSecure()) {
+ if (isSecure() && !display->isSecure()) {
hwcInfo.forceClientComposition = true;
}
@@ -524,7 +509,7 @@
const State& s(getDrawingState());
const Rect bufferSize = getBufferSize(s);
auto blendMode = HWC2::BlendMode::None;
- if (!isOpaque(s) || getAlphaLocked() != 1.0f) {
+ if (!isOpaque(s) || getAlpha() != 1.0f) {
blendMode =
mPremultipliedAlpha ? HWC2::BlendMode::Premultiplied : HWC2::BlendMode::Coverage;
}
@@ -539,7 +524,7 @@
// apply the layer's transform, followed by the display's global transform
// here we're guaranteed that the layer's transform preserves rects
Region activeTransparentRegion(getActiveTransparentRegion(s));
- ui::Transform t = getTransformLocked();
+ ui::Transform t = getTransform();
Rect activeCrop = getCrop(s);
if (!activeCrop.isEmpty() && bufferSize.isValid()) {
activeCrop = t.transform(activeCrop);
@@ -567,7 +552,7 @@
// computeBounds returns a FloatRect to provide more accuracy during the
// transformation. We then round upon constructing 'frame'.
- Rect frame{t.transform(computeBoundsLocked(activeTransparentRegion))};
+ Rect frame{t.transform(computeBounds(activeTransparentRegion))};
if (!frame.intersect(display->getViewport(), &frame)) {
frame.clear();
}
@@ -595,7 +580,7 @@
}
getBE().compositionInfo.hwc.sourceCrop = sourceCrop;
- float alpha = static_cast<float>(getAlphaLocked());
+ float alpha = static_cast<float>(getAlpha());
error = hwcLayer->setPlaneAlpha(alpha);
ALOGE_IF(error != HWC2::Error::None,
"[%s] Failed to set plane alpha %.3f: "
@@ -608,15 +593,16 @@
to_string(error).c_str(), static_cast<int32_t>(error));
getBE().compositionInfo.hwc.z = z;
- int type = s.type;
- int appId = s.appId;
+ int type = s.metadata.getInt32(METADATA_WINDOW_TYPE, 0);
+ int appId = s.metadata.getInt32(METADATA_OWNER_UID, 0);
sp<Layer> parent = mDrawingParent.promote();
if (parent.get()) {
- Mutex::Autolock lock(parent->mStateMutex);
auto& parentState = parent->getDrawingState();
- if (parentState.type >= 0 || parentState.appId >= 0) {
- type = parentState.type;
- appId = parentState.appId;
+ const int parentType = parentState.metadata.getInt32(METADATA_WINDOW_TYPE, 0);
+ const int parentAppId = parentState.metadata.getInt32(METADATA_OWNER_UID, 0);
+ if (parentType >= 0 || parentAppId >= 0) {
+ type = parentType;
+ appId = parentAppId;
}
}
@@ -638,7 +624,7 @@
const ui::Transform bufferOrientation(mCurrentTransform);
ui::Transform transform(tr * t * bufferOrientation);
- if (getTransformToDisplayInverseLocked()) {
+ if (getTransformToDisplayInverse()) {
/*
* the code below applies the primary display's inverse transform to the
* buffer
@@ -688,7 +674,6 @@
}
void Layer::updateCursorPosition(const sp<const DisplayDevice>& display) {
- Mutex::Autolock lock(mStateMutex);
const auto displayId = display->getId();
LOG_ALWAYS_FATAL_IF(!displayId);
if (!hasHwcLayer(*displayId) || getCompositionType(displayId) != HWC2::Composition::Cursor) {
@@ -703,7 +688,7 @@
Rect win = getCroppedBufferSize(s);
// Subtract the transparent region and snap to the bounds
Rect bounds = reduce(win, getActiveTransparentRegion(s));
- Rect frame(getTransformLocked().transform(bounds));
+ Rect frame(getTransform().transform(bounds));
frame.intersect(display->getViewport(), &frame);
auto& displayTransform = display->getTransform();
auto position = displayTransform.transform(frame);
@@ -733,7 +718,6 @@
void Layer::clearWithOpenGL(const RenderArea& renderArea, float red, float green, float blue,
float alpha) const {
auto& engine(mFlinger->getRenderEngine());
- Mutex::Autolock lock(mStateMutex);
computeGeometry(renderArea, getBE().mMesh, false);
engine.setupFillWithColor(red, green, blue, alpha);
engine.drawMesh(getBE().mMesh);
@@ -818,14 +802,14 @@
renderengine::Mesh& mesh,
bool useIdentityTransform) const {
const ui::Transform renderAreaTransform(renderArea.getTransform());
- FloatRect win = computeBoundsLocked();
+ FloatRect win = computeBounds();
vec2 lt = vec2(win.left, win.top);
vec2 lb = vec2(win.left, win.bottom);
vec2 rb = vec2(win.right, win.bottom);
vec2 rt = vec2(win.right, win.top);
- ui::Transform layerTransform = getTransformLocked();
+ ui::Transform layerTransform = getTransform();
if (!useIdentityTransform) {
lt = layerTransform.transform(lt);
lb = layerTransform.transform(lb);
@@ -841,12 +825,7 @@
}
bool Layer::isSecure() const {
- Mutex::Autolock lock(mStateMutex);
- return isSecureLocked();
-}
-
-bool Layer::isSecureLocked() const {
- const State& s(mState.drawing);
+ const State& s(mDrawingState);
return (s.flags & layer_state_t::eLayerSecure);
}
@@ -874,13 +853,9 @@
// ----------------------------------------------------------------------------
// transaction
// ----------------------------------------------------------------------------
-void Layer::pushPendingState() {
- Mutex::Autolock lock(mStateMutex);
- pushPendingStateLocked();
-}
-void Layer::pushPendingStateLocked() {
- if (!mState.current.modified) {
+void Layer::pushPendingState() {
+ if (!mCurrentState.modified) {
return;
}
@@ -888,22 +863,22 @@
// point and send it to the remote layer.
// We don't allow installing sync points after we are removed from the current state
// as we won't be able to signal our end.
- if (mState.current.barrierLayer_legacy != nullptr && !isRemovedFromCurrentState()) {
- sp<Layer> barrierLayer = mState.current.barrierLayer_legacy.promote();
+ if (mCurrentState.barrierLayer_legacy != nullptr && !isRemovedFromCurrentState()) {
+ sp<Layer> barrierLayer = mCurrentState.barrierLayer_legacy.promote();
if (barrierLayer == nullptr) {
ALOGE("[%s] Unable to promote barrier Layer.", mName.string());
// If we can't promote the layer we are intended to wait on,
// then it is expired or otherwise invalid. Allow this transaction
// to be applied as per normal (no synchronization).
- mState.current.barrierLayer_legacy = nullptr;
+ mCurrentState.barrierLayer_legacy = nullptr;
} else {
- auto syncPoint = std::make_shared<SyncPoint>(mState.current.frameNumber_legacy);
+ auto syncPoint = std::make_shared<SyncPoint>(mCurrentState.frameNumber_legacy);
if (barrierLayer->addSyncPoint(syncPoint)) {
mRemoteSyncPoints.push_back(std::move(syncPoint));
} else {
// We already missed the frame we're supposed to synchronize
// on, so go ahead and apply the state update
- mState.current.barrierLayer_legacy = nullptr;
+ mCurrentState.barrierLayer_legacy = nullptr;
}
}
@@ -911,21 +886,21 @@
setTransactionFlags(eTransactionNeeded);
mFlinger->setTransactionFlags(eTraversalNeeded);
}
- mState.pending.push_back(mState.current);
- ATRACE_INT(mTransactionName.string(), mState.pending.size());
+ mPendingStates.push_back(mCurrentState);
+ ATRACE_INT(mTransactionName.string(), mPendingStates.size());
}
void Layer::popPendingState(State* stateToCommit) {
- *stateToCommit = mState.pending[0];
+ *stateToCommit = mPendingStates[0];
- mState.pending.removeAt(0);
- ATRACE_INT(mTransactionName.string(), mState.pending.size());
+ mPendingStates.removeAt(0);
+ ATRACE_INT(mTransactionName.string(), mPendingStates.size());
}
bool Layer::applyPendingStates(State* stateToCommit) {
bool stateUpdateAvailable = false;
- while (!mState.pending.empty()) {
- if (mState.pending[0].barrierLayer_legacy != nullptr) {
+ while (!mPendingStates.empty()) {
+ if (mPendingStates[0].barrierLayer_legacy != nullptr) {
if (mRemoteSyncPoints.empty()) {
// If we don't have a sync point for this, apply it anyway. It
// will be visually wrong, but it should keep us from getting
@@ -937,7 +912,7 @@
}
if (mRemoteSyncPoints.front()->getFrameNumber() !=
- mState.pending[0].frameNumber_legacy) {
+ mPendingStates[0].frameNumber_legacy) {
ALOGE("[%s] Unexpected sync point frame number found", mName.string());
// Signal our end of the sync point and then dispose of it
@@ -965,12 +940,12 @@
// If we still have pending updates, wake SurfaceFlinger back up and point
// it at this layer so we can process them
- if (!mState.pending.empty()) {
+ if (!mPendingStates.empty()) {
setTransactionFlags(eTransactionNeeded);
mFlinger->setTransactionFlags(eTraversalNeeded);
}
- mState.current.modified = false;
+ mCurrentState.modified = false;
return stateUpdateAvailable;
}
@@ -1067,8 +1042,7 @@
return 0;
}
- Mutex::Autolock lock(mStateMutex);
- pushPendingStateLocked();
+ pushPendingState();
State c = getCurrentState();
if (!applyPendingStates(&c)) {
return 0;
@@ -1093,6 +1067,11 @@
mNeedsFiltering = (!getActiveTransform(c).preserveRects() || type >= ui::Transform::SCALE);
}
+ if (mChildrenChanged) {
+ flags |= eVisibleRegion;
+ mChildrenChanged = false;
+ }
+
// If the layer is hidden, signal and clear out all local sync points so
// that transactions for layers depending on this layer's frames becoming
// visible are not blocked
@@ -1100,60 +1079,49 @@
clearSyncPoints();
}
- if (mState.current.inputInfoChanged) {
+ if (mCurrentState.inputInfoChanged) {
flags |= eInputInfoChanged;
- mState.current.inputInfoChanged = false;
+ mCurrentState.inputInfoChanged = false;
}
// Commit the transaction
commitTransaction(c);
- mState.current.callbackHandles = {};
+ mCurrentState.callbackHandles = {};
return flags;
}
void Layer::commitTransaction(const State& stateToCommit) {
- mState.drawing = stateToCommit;
-}
-
-uint32_t Layer::getTransactionFlags() const {
- Mutex::Autolock lock(mStateMutex);
- return mState.transactionFlags;
+ mDrawingState = stateToCommit;
}
uint32_t Layer::getTransactionFlags(uint32_t flags) {
- Mutex::Autolock lock(mStateMutex);
- uint32_t and_flags = mState.transactionFlags & flags;
- mState.transactionFlags &= ~flags;
- return and_flags;
+ return mTransactionFlags.fetch_and(~flags) & flags;
}
uint32_t Layer::setTransactionFlags(uint32_t flags) {
- uint32_t old_flags = mState.transactionFlags;
- mState.transactionFlags |= flags;
- return old_flags;
+ return mTransactionFlags.fetch_or(flags);
}
bool Layer::setPosition(float x, float y, bool immediate) {
- Mutex::Autolock lock(mStateMutex);
- if (mState.current.requested_legacy.transform.tx() == x &&
- mState.current.requested_legacy.transform.ty() == y)
+ if (mCurrentState.requested_legacy.transform.tx() == x &&
+ mCurrentState.requested_legacy.transform.ty() == y)
return false;
- mState.current.sequence++;
+ mCurrentState.sequence++;
// We update the requested and active position simultaneously because
// we want to apply the position portion of the transform matrix immediately,
// but still delay scaling when resizing a SCALING_MODE_FREEZE layer.
- mState.current.requested_legacy.transform.set(x, y);
+ mCurrentState.requested_legacy.transform.set(x, y);
if (immediate && !mFreezeGeometryUpdates) {
// Here we directly update the active state
// unlike other setters, because we store it within
// the transform, but use different latching rules.
// b/38182305
- mState.current.active_legacy.transform.set(x, y);
+ mCurrentState.active_legacy.transform.set(x, y);
}
mFreezeGeometryUpdates = mFreezeGeometryUpdates || !immediate;
- mState.current.modified = true;
+ mCurrentState.modified = true;
setTransactionFlags(eTransactionNeeded);
return true;
}
@@ -1186,44 +1154,38 @@
}
bool Layer::setLayer(int32_t z) {
- Mutex::Autolock lock(mStateMutex);
- if (mState.current.z == z && !usingRelativeZLocked(LayerVector::StateSet::Current))
- return false;
-
- mState.current.sequence++;
- mState.current.z = z;
- mState.current.modified = true;
+ if (mCurrentState.z == z && !usingRelativeZ(LayerVector::StateSet::Current)) return false;
+ mCurrentState.sequence++;
+ mCurrentState.z = z;
+ mCurrentState.modified = true;
// Discard all relative layering.
- if (mState.current.zOrderRelativeOf != nullptr) {
- sp<Layer> strongRelative = mState.current.zOrderRelativeOf.promote();
+ if (mCurrentState.zOrderRelativeOf != nullptr) {
+ sp<Layer> strongRelative = mCurrentState.zOrderRelativeOf.promote();
if (strongRelative != nullptr) {
strongRelative->removeZOrderRelative(this);
}
- mState.current.zOrderRelativeOf = nullptr;
+ mCurrentState.zOrderRelativeOf = nullptr;
}
setTransactionFlags(eTransactionNeeded);
return true;
}
void Layer::removeZOrderRelative(const wp<Layer>& relative) {
- Mutex::Autolock lock(mStateMutex);
- mState.current.zOrderRelatives.remove(relative);
- mState.current.sequence++;
- mState.current.modified = true;
+ mCurrentState.zOrderRelatives.remove(relative);
+ mCurrentState.sequence++;
+ mCurrentState.modified = true;
setTransactionFlags(eTransactionNeeded);
}
void Layer::addZOrderRelative(const wp<Layer>& relative) {
- Mutex::Autolock lock(mStateMutex);
- mState.current.zOrderRelatives.add(relative);
- mState.current.modified = true;
- mState.current.sequence++;
+ mCurrentState.zOrderRelatives.add(relative);
+ mCurrentState.modified = true;
+ mCurrentState.sequence++;
setTransactionFlags(eTransactionNeeded);
}
bool Layer::setRelativeLayer(const sp<IBinder>& relativeToHandle, int32_t relativeZ) {
- Mutex::Autolock lock(mStateMutex);
sp<Handle> handle = static_cast<Handle*>(relativeToHandle.get());
if (handle == nullptr) {
return false;
@@ -1233,20 +1195,20 @@
return false;
}
- if (mState.current.z == relativeZ && usingRelativeZLocked(LayerVector::StateSet::Current) &&
- mState.current.zOrderRelativeOf == relative) {
+ if (mCurrentState.z == relativeZ && usingRelativeZ(LayerVector::StateSet::Current) &&
+ mCurrentState.zOrderRelativeOf == relative) {
return false;
}
- mState.current.sequence++;
- mState.current.modified = true;
- mState.current.z = relativeZ;
+ mCurrentState.sequence++;
+ mCurrentState.modified = true;
+ mCurrentState.z = relativeZ;
- auto oldZOrderRelativeOf = mState.current.zOrderRelativeOf.promote();
+ auto oldZOrderRelativeOf = mCurrentState.zOrderRelativeOf.promote();
if (oldZOrderRelativeOf != nullptr) {
oldZOrderRelativeOf->removeZOrderRelative(this);
}
- mState.current.zOrderRelativeOf = relative;
+ mCurrentState.zOrderRelativeOf = relative;
relative->addZOrderRelative(this);
setTransactionFlags(eTransactionNeeded);
@@ -1255,51 +1217,65 @@
}
bool Layer::setSize(uint32_t w, uint32_t h) {
- Mutex::Autolock lock(mStateMutex);
- if (mState.current.requested_legacy.w == w && mState.current.requested_legacy.h == h)
+ if (mCurrentState.requested_legacy.w == w && mCurrentState.requested_legacy.h == h)
return false;
- mState.current.requested_legacy.w = w;
- mState.current.requested_legacy.h = h;
- mState.current.modified = true;
+ mCurrentState.requested_legacy.w = w;
+ mCurrentState.requested_legacy.h = h;
+ mCurrentState.modified = true;
setTransactionFlags(eTransactionNeeded);
// record the new size, from this point on, when the client request
// a buffer, it'll get the new size.
- setDefaultBufferSize(mState.current.requested_legacy.w, mState.current.requested_legacy.h);
+ setDefaultBufferSize(mCurrentState.requested_legacy.w, mCurrentState.requested_legacy.h);
return true;
}
bool Layer::setAlpha(float alpha) {
- Mutex::Autolock lock(mStateMutex);
- if (mState.current.color.a == alpha) return false;
- mState.current.sequence++;
- mState.current.color.a = alpha;
- mState.current.modified = true;
+ if (mCurrentState.color.a == alpha) return false;
+ mCurrentState.sequence++;
+ mCurrentState.color.a = alpha;
+ mCurrentState.modified = true;
setTransactionFlags(eTransactionNeeded);
return true;
}
-bool Layer::setColor(const half3& color) {
- Mutex::Autolock lock(mStateMutex);
- if (color.r == mState.current.color.r && color.g == mState.current.color.g &&
- color.b == mState.current.color.b)
+bool Layer::setBackgroundColor(const half3& color, float alpha, ui::Dataspace dataspace) {
+ if (!mCurrentState.bgColorLayer && alpha == 0) {
return false;
+ } else if (!mCurrentState.bgColorLayer && alpha != 0) {
+ // create background color layer if one does not yet exist
+ uint32_t flags = ISurfaceComposerClient::eFXSurfaceColor;
+ const String8& name = mName + "BackgroundColorLayer";
+ mCurrentState.bgColorLayer =
+ new ColorLayer(LayerCreationArgs(mFlinger.get(), nullptr, name, 0, 0, flags));
- mState.current.sequence++;
- mState.current.color.r = color.r;
- mState.current.color.g = color.g;
- mState.current.color.b = color.b;
- mState.current.modified = true;
- setTransactionFlags(eTransactionNeeded);
+ // add to child list
+ addChild(mCurrentState.bgColorLayer);
+ mFlinger->mLayersAdded = true;
+ // set up SF to handle added color layer
+ if (isRemovedFromCurrentState()) {
+ mCurrentState.bgColorLayer->onRemovedFromCurrentState();
+ }
+ mFlinger->setTransactionFlags(eTransactionNeeded);
+ } else if (mCurrentState.bgColorLayer && alpha == 0) {
+ mCurrentState.bgColorLayer->reparent(nullptr);
+ mCurrentState.bgColorLayer = nullptr;
+ return true;
+ }
+
+ mCurrentState.bgColorLayer->setColor(color);
+ mCurrentState.bgColorLayer->setLayer(std::numeric_limits<int32_t>::min());
+ mCurrentState.bgColorLayer->setAlpha(alpha);
+ mCurrentState.bgColorLayer->setDataspace(dataspace);
+
return true;
}
bool Layer::setCornerRadius(float cornerRadius) {
- Mutex::Autolock lock(mStateMutex);
- if (mState.current.cornerRadius == cornerRadius) return false;
+ if (mCurrentState.cornerRadius == cornerRadius) return false;
- mState.current.sequence++;
- mState.current.cornerRadius = cornerRadius;
- mState.current.modified = true;
+ mCurrentState.sequence++;
+ mCurrentState.cornerRadius = cornerRadius;
+ mCurrentState.modified = true;
setTransactionFlags(eTransactionNeeded);
return true;
}
@@ -1313,80 +1289,71 @@
ALOGW("Attempt to set rotation matrix without permission ACCESS_SURFACE_FLINGER ignored");
return false;
}
- Mutex::Autolock lock(mStateMutex);
- mState.current.sequence++;
- mState.current.requested_legacy.transform.set(matrix.dsdx, matrix.dtdy, matrix.dtdx,
- matrix.dsdy);
- mState.current.modified = true;
+ mCurrentState.sequence++;
+ mCurrentState.requested_legacy.transform.set(matrix.dsdx, matrix.dtdy, matrix.dtdx,
+ matrix.dsdy);
+ mCurrentState.modified = true;
setTransactionFlags(eTransactionNeeded);
return true;
}
bool Layer::setTransparentRegionHint(const Region& transparent) {
- Mutex::Autolock lock(mStateMutex);
- mState.current.requestedTransparentRegion_legacy = transparent;
- mState.current.modified = true;
+ mCurrentState.requestedTransparentRegion_legacy = transparent;
+ mCurrentState.modified = true;
setTransactionFlags(eTransactionNeeded);
return true;
}
bool Layer::setFlags(uint8_t flags, uint8_t mask) {
- Mutex::Autolock lock(mStateMutex);
- const uint32_t newFlags = (mState.current.flags & ~mask) | (flags & mask);
- if (mState.current.flags == newFlags) return false;
- mState.current.sequence++;
- mState.current.flags = newFlags;
- mState.current.modified = true;
+ const uint32_t newFlags = (mCurrentState.flags & ~mask) | (flags & mask);
+ if (mCurrentState.flags == newFlags) return false;
+ mCurrentState.sequence++;
+ mCurrentState.flags = newFlags;
+ mCurrentState.modified = true;
setTransactionFlags(eTransactionNeeded);
return true;
}
bool Layer::setCrop_legacy(const Rect& crop, bool immediate) {
- Mutex::Autolock lock(mStateMutex);
- if (mState.current.requestedCrop_legacy == crop) return false;
- mState.current.sequence++;
- mState.current.requestedCrop_legacy = crop;
+ if (mCurrentState.requestedCrop_legacy == crop) return false;
+ mCurrentState.sequence++;
+ mCurrentState.requestedCrop_legacy = crop;
if (immediate && !mFreezeGeometryUpdates) {
- mState.current.crop_legacy = crop;
+ mCurrentState.crop_legacy = crop;
}
mFreezeGeometryUpdates = mFreezeGeometryUpdates || !immediate;
- mState.current.modified = true;
+ mCurrentState.modified = true;
setTransactionFlags(eTransactionNeeded);
return true;
}
bool Layer::setOverrideScalingMode(int32_t scalingMode) {
- Mutex::Autolock lock(mStateMutex);
if (scalingMode == mOverrideScalingMode) return false;
mOverrideScalingMode = scalingMode;
setTransactionFlags(eTransactionNeeded);
return true;
}
-void Layer::setInfo(int32_t type, int32_t appId) {
- Mutex::Autolock lock(mStateMutex);
- mState.current.appId = appId;
- mState.current.type = type;
- mState.current.modified = true;
+bool Layer::setMetadata(LayerMetadata data) {
+ bool changed = data.mMap != mCurrentState.metadata.mMap;
+ if (!changed) return false;
+ mCurrentState.metadata = std::move(data);
+ mCurrentState.sequence++;
+ mCurrentState.modified = true;
setTransactionFlags(eTransactionNeeded);
+ return true;
}
bool Layer::setLayerStack(uint32_t layerStack) {
- Mutex::Autolock lock(mStateMutex);
- if (mState.current.layerStack == layerStack) return false;
- mState.current.sequence++;
- mState.current.layerStack = layerStack;
- mState.current.modified = true;
+ if (mCurrentState.layerStack == layerStack) return false;
+ mCurrentState.sequence++;
+ mCurrentState.layerStack = layerStack;
+ mCurrentState.modified = true;
setTransactionFlags(eTransactionNeeded);
return true;
}
uint32_t Layer::getLayerStack() const {
- Mutex::Autolock lock(mStateMutex);
- return getLayerStackLocked();
-}
-
-uint32_t Layer::getLayerStackLocked() const {
auto p = mDrawingParent.promote();
if (p == nullptr) {
return getDrawingState().layerStack;
@@ -1395,16 +1362,15 @@
}
void Layer::deferTransactionUntil_legacy(const sp<Layer>& barrierLayer, uint64_t frameNumber) {
- Mutex::Autolock lock(mStateMutex);
- mState.current.barrierLayer_legacy = barrierLayer;
- mState.current.frameNumber_legacy = frameNumber;
+ mCurrentState.barrierLayer_legacy = barrierLayer;
+ mCurrentState.frameNumber_legacy = frameNumber;
// We don't set eTransactionNeeded, because just receiving a deferral
// request without any other state updates shouldn't actually induce a delay
- mState.current.modified = true;
- pushPendingStateLocked();
- mState.current.barrierLayer_legacy = nullptr;
- mState.current.frameNumber_legacy = 0;
- mState.current.modified = false;
+ mCurrentState.modified = true;
+ pushPendingState();
+ mCurrentState.barrierLayer_legacy = nullptr;
+ mCurrentState.frameNumber_legacy = 0;
+ mCurrentState.modified = false;
}
void Layer::deferTransactionUntil_legacy(const sp<IBinder>& barrierHandle, uint64_t frameNumber) {
@@ -1417,8 +1383,7 @@
// ----------------------------------------------------------------------------
bool Layer::isHiddenByPolicy() const {
- Mutex::Autolock lock(mStateMutex);
- const State& s(mState.drawing);
+ const State& s(mDrawingState);
const auto& parent = mDrawingParent.promote();
if (parent != nullptr && parent->isHiddenByPolicy()) {
return true;
@@ -1463,7 +1428,6 @@
// TODO(marissaw): add new layer state info to layer debugging
LayerDebugInfo Layer::getLayerDebugInfo() const {
- Mutex::Autolock lock(mStateMutex);
LayerDebugInfo info;
const State& ds = getDrawingState();
info.mName = getName();
@@ -1473,7 +1437,7 @@
info.mTransparentRegion = ds.activeTransparentRegion_legacy;
info.mVisibleRegion = visibleRegion;
info.mSurfaceDamageRegion = surfaceDamageRegion;
- info.mLayerStack = getLayerStackLocked();
+ info.mLayerStack = getLayerStack();
info.mX = ds.active_legacy.transform.tx();
info.mY = ds.active_legacy.transform.ty();
info.mZ = ds.z;
@@ -1509,13 +1473,6 @@
return info;
}
-std::tuple<uint32_t, int32_t> Layer::getLayerStackAndZ(StateSet stateSet) {
- Mutex::Autolock lock(mStateMutex);
- const State& state = (stateSet == StateSet::Current) ? mState.current : mState.drawing;
-
- return {state.layerStack, state.z};
-}
-
void Layer::miniDumpHeader(std::string& result) {
result.append("-------------------------------");
result.append("-------------------------------");
@@ -1532,7 +1489,6 @@
}
void Layer::miniDump(std::string& result, DisplayId displayId) const {
- Mutex::Autolock lock(mStateMutex);
if (!hasHwcLayer(displayId)) {
return;
}
@@ -1638,11 +1594,15 @@
}
void Layer::addChild(const sp<Layer>& layer) {
+ mChildrenChanged = true;
+
mCurrentChildren.add(layer);
layer->setParent(this);
}
ssize_t Layer::removeChild(const sp<Layer>& layer) {
+ mChildrenChanged = true;
+
layer->setParent(nullptr);
return mCurrentChildren.remove(layer);
}
@@ -1661,16 +1621,10 @@
}
if (attachChildren()) {
- Mutex::Autolock lock(mStateMutex);
setTransactionFlags(eTransactionNeeded);
}
for (const sp<Layer>& child : mCurrentChildren) {
newParent->addChild(child);
-
- sp<Client> client(child->mClientRef.promote());
- if (client != nullptr) {
- client->updateParent(newParent);
- }
}
mCurrentChildren.clear();
@@ -1684,40 +1638,53 @@
}
bool Layer::reparent(const sp<IBinder>& newParentHandle) {
- if (newParentHandle == nullptr) {
+ bool callSetTransactionFlags = false;
+
+ // While layers are detached, we allow most operations
+ // and simply halt performing the actual transaction. However
+ // for reparent != null we would enter the mRemovedFromCurrentState
+ // state, regardless of whether doTransaction was called, and
+ // so we need to prevent the update here.
+ if (mLayerDetached && newParentHandle == nullptr) {
return false;
}
- auto handle = static_cast<Handle*>(newParentHandle.get());
- sp<Layer> newParent = handle->owner.promote();
- if (newParent == nullptr) {
- ALOGE("Unable to promote Layer handle");
- return false;
+ sp<Layer> newParent;
+ if (newParentHandle != nullptr) {
+ auto handle = static_cast<Handle*>(newParentHandle.get());
+ newParent = handle->owner.promote();
+ if (newParent == nullptr) {
+ ALOGE("Unable to promote Layer handle");
+ return false;
+ }
+ if (newParent == this) {
+ ALOGE("Invalid attempt to reparent Layer (%s) to itself", getName().c_str());
+ return false;
+ }
}
sp<Layer> parent = getParent();
if (parent != nullptr) {
parent->removeChild(this);
}
- newParent->addChild(this);
- if (!newParent->isRemovedFromCurrentState()) {
- addToCurrentState();
+ if (newParentHandle != nullptr) {
+ newParent->addChild(this);
+ if (!newParent->isRemovedFromCurrentState()) {
+ addToCurrentState();
+ } else {
+ onRemovedFromCurrentState();
+ }
+
+ if (mLayerDetached) {
+ mLayerDetached = false;
+ callSetTransactionFlags = true;
+ }
+ } else {
+ onRemovedFromCurrentState();
}
- sp<Client> client(mClientRef.promote());
- sp<Client> newParentClient(newParent->mClientRef.promote());
-
- if (client != newParentClient) {
- client->updateParent(newParent);
- }
-
- Mutex::Autolock lock(mStateMutex);
- if (mLayerDetached) {
- mLayerDetached = false;
- setTransactionFlags(eTransactionNeeded);
- }
- if (attachChildren()) {
+ if (callSetTransactionFlags || attachChildren()) {
setTransactionFlags(eTransactionNeeded);
}
return true;
@@ -1756,24 +1723,18 @@
bool Layer::setColorTransform(const mat4& matrix) {
static const mat4 identityMatrix = mat4();
- Mutex::Autolock lock(mStateMutex);
- if (mState.current.colorTransform == matrix) {
+ if (mCurrentState.colorTransform == matrix) {
return false;
}
- ++mState.current.sequence;
- mState.current.colorTransform = matrix;
- mState.current.hasColorTransform = matrix != identityMatrix;
- mState.current.modified = true;
+ ++mCurrentState.sequence;
+ mCurrentState.colorTransform = matrix;
+ mCurrentState.hasColorTransform = matrix != identityMatrix;
+ mCurrentState.modified = true;
setTransactionFlags(eTransactionNeeded);
return true;
}
mat4 Layer::getColorTransform() const {
- Mutex::Autolock lock(mStateMutex);
- return getColorTransformLocked();
-}
-
-mat4 Layer::getColorTransformLocked() const {
mat4 colorTransform = mat4(getDrawingState().colorTransform);
if (sp<Layer> parent = mDrawingParent.promote(); parent != nullptr) {
colorTransform = parent->getColorTransform() * colorTransform;
@@ -1782,7 +1743,6 @@
}
bool Layer::hasColorTransform() const {
- Mutex::Autolock lock(mStateMutex);
bool hasColorTransform = getDrawingState().hasColorTransform;
if (sp<Layer> parent = mDrawingParent.promote(); parent != nullptr) {
hasColorTransform = hasColorTransform || parent->hasColorTransform();
@@ -1813,18 +1773,12 @@
}
int32_t Layer::getZ() const {
- Mutex::Autolock lock(mStateMutex);
- return mState.drawing.z;
+ return mDrawingState.z;
}
bool Layer::usingRelativeZ(LayerVector::StateSet stateSet) {
- Mutex::Autolock lock(mStateMutex);
- return usingRelativeZLocked(stateSet);
-}
-
-bool Layer::usingRelativeZLocked(LayerVector::StateSet stateSet) {
const bool useDrawing = stateSet == LayerVector::StateSet::Drawing;
- const State& state = useDrawing ? mState.drawing : mState.current;
+ const State& state = useDrawing ? mDrawingState : mCurrentState;
return state.zOrderRelativeOf != nullptr;
}
@@ -1834,7 +1788,7 @@
"makeTraversalList received invalid stateSet");
const bool useDrawing = stateSet == LayerVector::StateSet::Drawing;
const LayerVector& children = useDrawing ? mDrawingChildren : mCurrentChildren;
- const State& state = useDrawing ? mState.drawing : mState.current;
+ const State& state = useDrawing ? mDrawingState : mCurrentState;
if (state.zOrderRelatives.size() == 0) {
*outSkipRelativeZUsers = true;
@@ -1850,7 +1804,7 @@
}
for (const sp<Layer>& child : children) {
- const State& childState = useDrawing ? child->mState.drawing : child->mState.current;
+ const State& childState = useDrawing ? child->mDrawingState : child->mCurrentState;
if (childState.zOrderRelativeOf != nullptr) {
continue;
}
@@ -1889,6 +1843,7 @@
visitor(this);
for (; i < list.size(); i++) {
const auto& relative = list[i];
+
if (skipRelativeZUsers && relative->usingRelativeZ(stateSet)) {
continue;
}
@@ -1936,7 +1891,7 @@
"makeTraversalList received invalid stateSet");
const bool useDrawing = stateSet == LayerVector::StateSet::Drawing;
const LayerVector& children = useDrawing ? mDrawingChildren : mCurrentChildren;
- const State& state = useDrawing ? mState.drawing : mState.current;
+ const State& state = useDrawing ? mDrawingState : mCurrentState;
LayerVector traverse(stateSet);
for (const wp<Layer>& weakRelative : state.zOrderRelatives) {
@@ -1949,7 +1904,7 @@
}
for (const sp<Layer>& child : children) {
- const State& childState = useDrawing ? child->mState.drawing : child->mState.current;
+ const State& childState = useDrawing ? child->mDrawingState : child->mCurrentState;
// If a layer has a relativeOf layer, only ignore if the layer it's relative to is a
// descendent of the top most parent of the tree. If it's not a descendent, then just add
// the child here since it won't be added later as a relative.
@@ -2006,16 +1961,10 @@
}
ui::Transform Layer::getTransform() const {
- Mutex::Autolock lock(mStateMutex);
- return getTransformLocked();
-}
-
-ui::Transform Layer::getTransformLocked() const {
ui::Transform t;
const auto& p = mDrawingParent.promote();
if (p != nullptr) {
- Mutex::Autolock lock(p->mStateMutex);
- t = p->getTransformLocked();
+ t = p->getTransform();
// If the parent is not using NATIVE_WINDOW_SCALING_MODE_FREEZE (e.g.
// it isFixedSize) then there may be additional scaling not accounted
@@ -2043,27 +1992,18 @@
}
half Layer::getAlpha() const {
- Mutex::Autolock lock(mStateMutex);
- return getAlphaLocked();
-}
-
-half Layer::getAlphaLocked() const {
const auto& p = mDrawingParent.promote();
+
half parentAlpha = (p != nullptr) ? p->getAlpha() : 1.0_hf;
return parentAlpha * getDrawingState().color.a;
}
half4 Layer::getColor() const {
const half4 color(getDrawingState().color);
- return half4(color.r, color.g, color.b, getAlphaLocked());
+ return half4(color.r, color.g, color.b, getAlpha());
}
Layer::RoundedCornerState Layer::getRoundedCornerState() const {
- Mutex::Autolock lock(mStateMutex);
- return getRoundedCornerStateLocked();
-}
-
-Layer::RoundedCornerState Layer::getRoundedCornerStateLocked() const {
const auto& p = mDrawingParent.promote();
if (p != nullptr) {
RoundedCornerState parentState = p->getRoundedCornerState();
@@ -2080,7 +2020,7 @@
}
}
const float radius = getDrawingState().cornerRadius;
- return radius > 0 ? RoundedCornerState(computeBoundsLocked(), radius) : RoundedCornerState();
+ return radius > 0 ? RoundedCornerState(computeBounds(), radius) : RoundedCornerState();
}
void Layer::commitChildList() {
@@ -2093,21 +2033,19 @@
}
void Layer::setInputInfo(const InputWindowInfo& info) {
- Mutex::Autolock lock(mStateMutex);
- mState.current.inputInfo = info;
- mState.current.modified = true;
- mState.current.inputInfoChanged = true;
+ mCurrentState.inputInfo = info;
+ mCurrentState.modified = true;
+ mCurrentState.inputInfoChanged = true;
setTransactionFlags(eTransactionNeeded);
}
void Layer::writeToProto(LayerProto* layerInfo, LayerVector::StateSet stateSet) {
- Mutex::Autolock lock(mStateMutex);
const bool useDrawing = stateSet == LayerVector::StateSet::Drawing;
const LayerVector& children = useDrawing ? mDrawingChildren : mCurrentChildren;
- const State& state = useDrawing ? mState.drawing : mState.current;
+ const State& state = useDrawing ? mDrawingState : mCurrentState;
ui::Transform requestedTransform = state.active_legacy.transform;
- ui::Transform transform = getTransformLocked();
+ ui::Transform transform = getTransform();
layerInfo->set_id(sequence);
layerInfo->set_name(getName().c_str());
@@ -2129,7 +2067,7 @@
LayerProtoHelper::writeToProto(visibleRegion, layerInfo->mutable_visible_region());
LayerProtoHelper::writeToProto(surfaceDamageRegion, layerInfo->mutable_damage_region());
- layerInfo->set_layer_stack(getLayerStackLocked());
+ layerInfo->set_layer_stack(getLayerStack());
layerInfo->set_z(state.z);
PositionProto* position = layerInfo->mutable_position();
@@ -2145,7 +2083,7 @@
size->set_h(state.active_legacy.h);
LayerProtoHelper::writeToProto(state.crop_legacy, layerInfo->mutable_crop());
- layerInfo->set_corner_radius(getRoundedCornerStateLocked().radius);
+ layerInfo->set_corner_radius(getRoundedCornerState().radius);
layerInfo->set_is_opaque(isOpaque(state));
layerInfo->set_invalidate(contentDirty);
@@ -2181,12 +2119,10 @@
layerInfo->set_queued_frames(getQueuedFrameCount());
layerInfo->set_refresh_pending(isBufferLatched());
- layerInfo->set_window_type(state.type);
- layerInfo->set_app_id(state.appId);
layerInfo->set_curr_frame(mCurrentFrameNumber);
layerInfo->set_effective_scaling_mode(getEffectiveScalingMode());
- for (const auto& pendingState : mState.pending) {
+ for (const auto& pendingState : mPendingStates) {
auto barrierLayer = pendingState.barrierLayer_legacy.promote();
if (barrierLayer != nullptr) {
BarrierLayerProto* barrierLayerProto = layerInfo->add_barrier_layer();
@@ -2194,6 +2130,11 @@
barrierLayerProto->set_frame_number(pendingState.frameNumber_legacy);
}
}
+
+ auto protoMap = layerInfo->mutable_metadata();
+ for (const auto& entry : state.metadata.mMap) {
+ (*protoMap)[entry.first] = std::string(entry.second.cbegin(), entry.second.cend());
+ }
}
void Layer::writeToProto(LayerProto* layerInfo, DisplayId displayId) {
@@ -2229,39 +2170,38 @@
return mRemovedFromCurrentState;
}
-InputWindowInfo Layer::fillInputInfo(const Rect& screenBounds) {
- InputWindowInfo info;
- ui::Transform t;
- Rect layerBounds;
- {
- Mutex::Autolock lock(mStateMutex);
- info = mState.drawing.inputInfo;
- t = getTransformLocked();
- const float xScale = t.sx();
- const float yScale = t.sy();
- if (xScale != 1.0f || yScale != 1.0f) {
- info.windowXScale *= 1.0f / xScale;
- info.windowYScale *= 1.0f / yScale;
- info.touchableRegion.scaleSelf(xScale, yScale);
- }
+InputWindowInfo Layer::fillInputInfo() {
+ InputWindowInfo info = mDrawingState.inputInfo;
- // Transform layer size to screen space and inset it by surface insets.
- layerBounds = getCroppedBufferSize(getDrawingState());
+ if (info.displayId == ADISPLAY_ID_NONE) {
+ info.displayId = mDrawingState.layerStack;
}
+ ui::Transform t = getTransform();
+ const float xScale = t.sx();
+ const float yScale = t.sy();
+ if (xScale != 1.0f || yScale != 1.0f) {
+ info.windowXScale *= 1.0f / xScale;
+ info.windowYScale *= 1.0f / yScale;
+ info.touchableRegion.scaleSelf(xScale, yScale);
+ }
+
+ // Transform layer size to screen space and inset it by surface insets.
+ // If this is a portal window, set the touchableRegion to the layerBounds.
+ Rect layerBounds = info.portalToDisplayId == ADISPLAY_ID_NONE
+ ? getBufferSize(getDrawingState())
+ : info.touchableRegion.getBounds();
+ if (!layerBounds.isValid()) {
+ layerBounds = getCroppedBufferSize(getDrawingState());
+ }
layerBounds = t.transform(layerBounds);
layerBounds.inset(info.surfaceInset, info.surfaceInset, info.surfaceInset, info.surfaceInset);
- // Intersect with screen bounds to shrink the frame by the surface insets. The surface insets
- // are not set on the screen bounds directly since the surface inset region may already be
- // cropped by a parent layer.
- Rect frame;
- screenBounds.intersect(layerBounds, &frame);
-
- info.frameLeft = frame.left;
- info.frameTop = frame.top;
- info.frameRight = frame.right;
- info.frameBottom = frame.bottom;
+ // Input coordinate should match the layer bounds.
+ info.frameLeft = layerBounds.left;
+ info.frameTop = layerBounds.top;
+ info.frameRight = layerBounds.right;
+ info.frameBottom = layerBounds.bottom;
// Position the touchable region relative to frame screen location and restrict it to frame
// bounds.
@@ -2271,8 +2211,11 @@
}
bool Layer::hasInput() const {
- Mutex::Autolock lock(mStateMutex);
- return mState.drawing.inputInfo.token != nullptr;
+ return mDrawingState.inputInfo.token != nullptr;
+}
+
+std::shared_ptr<compositionengine::Layer> Layer::getCompositionLayer() const {
+ return nullptr;
}
// ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index fb75e4c..f099df6 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -19,6 +19,7 @@
#include <sys/types.h>
+#include <compositionengine/LayerFE.h>
#include <gui/BufferQueue.h>
#include <gui/ISurfaceComposerClient.h>
#include <gui/LayerState.h>
@@ -51,11 +52,9 @@
#include "TransactionCompletedThread.h"
#include "DisplayHardware/HWComposer.h"
-#include "DisplayHardware/HWComposerBufferCache.h"
#include "RenderArea.h"
using namespace android::surfaceflinger;
-using StateSet = android::LayerVector::StateSet;
namespace android {
@@ -69,6 +68,10 @@
class LayerDebugInfo;
class LayerBE;
+namespace compositionengine {
+class Layer;
+}
+
namespace impl {
class SurfaceInterceptor;
}
@@ -88,7 +91,7 @@
uint32_t flags;
};
-class Layer : public virtual RefBase {
+class Layer : public virtual compositionengine::LayerFE {
static std::atomic<int32_t> sSequence;
public:
@@ -168,8 +171,7 @@
Region activeTransparentRegion_legacy;
Region requestedTransparentRegion_legacy;
- int32_t appId;
- int32_t type;
+ LayerMetadata metadata;
// If non-null, a Surface this Surface's Z-order is interpreted relative to.
wp<Layer> zOrderRelativeOf;
@@ -203,6 +205,11 @@
mat4 colorTransform;
bool hasColorTransform;
+ // pointer to background color layer that, if set, appears below the buffer state layer
+ // and the buffer state layer's children. Z order will be set to
+ // INT_MIN
+ sp<Layer> bgColorLayer;
+
// The deque of callback handles for this frame. The back of the deque contains the most
// recent callback handle.
std::deque<sp<CallbackHandle>> callbackHandles;
@@ -212,6 +219,7 @@
virtual ~Layer();
void setPrimaryDisplayOnly() { mPrimaryDisplayOnly = true; }
+ bool getPrimaryDisplayOnly() const { return mPrimaryDisplayOnly; }
// ------------------------------------------------------------------------
// Geometry setting functions.
@@ -240,7 +248,7 @@
// also the rendered size of the layer prior to any transformations. Parent
// or local matrix transformations will not affect the size of the buffer,
// but may affect it's on-screen size or clipping.
- virtual bool setSize(uint32_t w, uint32_t h) EXCLUDES(mStateMutex);
+ virtual bool setSize(uint32_t w, uint32_t h);
// Set a 2x2 transformation matrix on the layer. This transform
// will be applied after parent transforms, but before any final
// producer specified transform.
@@ -255,78 +263,61 @@
// setPosition operates in parent buffer space (pre parent-transform) or display
// space for top-level layers.
- virtual bool setPosition(float x, float y, bool immediate) EXCLUDES(mStateMutex);
+ virtual bool setPosition(float x, float y, bool immediate);
// Buffer space
- virtual bool setCrop_legacy(const Rect& crop, bool immediate) EXCLUDES(mStateMutex);
+ virtual bool setCrop_legacy(const Rect& crop, bool immediate);
// TODO(b/38182121): Could we eliminate the various latching modes by
// using the layer hierarchy?
// -----------------------------------------------------------------------
- virtual bool setLayer(int32_t z) EXCLUDES(mStateMutex);
- virtual bool setRelativeLayer(const sp<IBinder>& relativeToHandle, int32_t relativeZ)
- EXCLUDES(mStateMutex);
+ virtual bool setLayer(int32_t z);
+ virtual bool setRelativeLayer(const sp<IBinder>& relativeToHandle, int32_t relativeZ);
- virtual bool setAlpha(float alpha) EXCLUDES(mStateMutex);
- virtual bool setColor(const half3& color) EXCLUDES(mStateMutex);
+ virtual bool setAlpha(float alpha);
+ virtual bool setColor(const half3& /*color*/) { return false; };
// Set rounded corner radius for this layer and its children.
//
// We only support 1 radius per layer in the hierarchy, where parent layers have precedence.
// The shape of the rounded corner rectangle is specified by the crop rectangle of the layer
// from which we inferred the rounded corner radius.
- virtual bool setCornerRadius(float cornerRadius) EXCLUDES(mStateMutex);
- virtual bool setTransparentRegionHint(const Region& transparent) EXCLUDES(mStateMutex);
- virtual bool setFlags(uint8_t flags, uint8_t mask) EXCLUDES(mStateMutex);
- virtual bool setLayerStack(uint32_t layerStack) EXCLUDES(mStateMutex);
- virtual uint32_t getLayerStack() const EXCLUDES(mStateMutex);
+ virtual bool setCornerRadius(float cornerRadius);
+ virtual bool setTransparentRegionHint(const Region& transparent);
+ virtual bool setFlags(uint8_t flags, uint8_t mask);
+ virtual bool setLayerStack(uint32_t layerStack);
+ virtual uint32_t getLayerStack() const;
virtual void deferTransactionUntil_legacy(const sp<IBinder>& barrierHandle,
uint64_t frameNumber);
- virtual void deferTransactionUntil_legacy(const sp<Layer>& barrierLayer, uint64_t frameNumber)
- EXCLUDES(mStateMutex);
- virtual bool setOverrideScalingMode(int32_t overrideScalingMode) EXCLUDES(mStateMutex);
- virtual void setInfo(int32_t type, int32_t appId) EXCLUDES(mStateMutex);
- virtual bool reparentChildren(const sp<IBinder>& layer) EXCLUDES(mStateMutex);
+ virtual void deferTransactionUntil_legacy(const sp<Layer>& barrierLayer, uint64_t frameNumber);
+ virtual bool setOverrideScalingMode(int32_t overrideScalingMode);
+ virtual bool setMetadata(LayerMetadata data);
+ virtual bool reparentChildren(const sp<IBinder>& layer);
virtual void setChildrenDrawingParent(const sp<Layer>& layer);
- virtual bool reparent(const sp<IBinder>& newParentHandle) EXCLUDES(mStateMutex);
+ virtual bool reparent(const sp<IBinder>& newParentHandle);
virtual bool detachChildren();
bool attachChildren();
bool isLayerDetached() const { return mLayerDetached; }
- virtual bool setColorTransform(const mat4& matrix) EXCLUDES(mStateMutex);
- mat4 getColorTransform() const EXCLUDES(mStateMutex);
- virtual mat4 getColorTransformLocked() const REQUIRES(mStateMutex);
- virtual bool hasColorTransform() const EXCLUDES(mStateMutex);
- ;
+ virtual bool setColorTransform(const mat4& matrix);
+ virtual mat4 getColorTransform() const;
+ virtual bool hasColorTransform() const;
// Used only to set BufferStateLayer state
- virtual bool setTransform(uint32_t /*transform*/) EXCLUDES(mStateMutex) { return false; };
- virtual bool setTransformToDisplayInverse(bool /*transformToDisplayInverse*/)
- EXCLUDES(mStateMutex) {
- return false;
- };
- virtual bool setCrop(const Rect& /*crop*/) EXCLUDES(mStateMutex) { return false; };
- virtual bool setFrame(const Rect& /*frame*/) EXCLUDES(mStateMutex) { return false; };
- virtual bool setBuffer(const sp<GraphicBuffer>& /*buffer*/) EXCLUDES(mStateMutex) {
- return false;
- };
- virtual bool setAcquireFence(const sp<Fence>& /*fence*/) EXCLUDES(mStateMutex) {
- return false;
- };
- virtual bool setDataspace(ui::Dataspace /*dataspace*/) EXCLUDES(mStateMutex) { return false; };
- virtual bool setHdrMetadata(const HdrMetadata& /*hdrMetadata*/) EXCLUDES(mStateMutex) {
- return false;
- };
- virtual bool setSurfaceDamageRegion(const Region& /*surfaceDamage*/) EXCLUDES(mStateMutex) {
- return false;
- };
- virtual bool setApi(int32_t /*api*/) EXCLUDES(mStateMutex) { return false; };
- virtual bool setSidebandStream(const sp<NativeHandle>& /*sidebandStream*/)
- EXCLUDES(mStateMutex) {
- return false;
- };
+ virtual bool setTransform(uint32_t /*transform*/) { return false; };
+ virtual bool setTransformToDisplayInverse(bool /*transformToDisplayInverse*/) { return false; };
+ virtual bool setCrop(const Rect& /*crop*/) { return false; };
+ virtual bool setFrame(const Rect& /*frame*/) { return false; };
+ virtual bool setBuffer(const sp<GraphicBuffer>& /*buffer*/) { return false; };
+ virtual bool setAcquireFence(const sp<Fence>& /*fence*/) { return false; };
+ virtual bool setDataspace(ui::Dataspace /*dataspace*/) { return false; };
+ virtual bool setHdrMetadata(const HdrMetadata& /*hdrMetadata*/) { return false; };
+ virtual bool setSurfaceDamageRegion(const Region& /*surfaceDamage*/) { return false; };
+ virtual bool setApi(int32_t /*api*/) { return false; };
+ virtual bool setSidebandStream(const sp<NativeHandle>& /*sidebandStream*/) { return false; };
virtual bool setTransactionCompletedListeners(
- const std::vector<sp<CallbackHandle>>& /*handles*/) EXCLUDES(mStateMutex) {
+ const std::vector<sp<CallbackHandle>>& /*handles*/) {
return false;
};
+ virtual bool setBackgroundColor(const half3& color, float alpha, ui::Dataspace dataspace);
ui::Dataspace getDataSpace() const { return mCurrentDataSpace; }
@@ -337,27 +328,29 @@
// visually.
bool isLegacyDataSpace() const;
+ virtual std::shared_ptr<compositionengine::Layer> getCompositionLayer() const;
+
// If we have received a new buffer this frame, we will pass its surface
// damage down to hardware composer. Otherwise, we must send a region with
// one empty rect.
virtual void useSurfaceDamage() {}
virtual void useEmptyDamage() {}
- uint32_t getTransactionFlags() const EXCLUDES(mStateMutex);
- uint32_t getTransactionFlags(uint32_t flags) EXCLUDES(mStateMutex);
- uint32_t setTransactionFlags(uint32_t flags) REQUIRES(mStateMutex);
+ uint32_t getTransactionFlags() const { return mTransactionFlags; }
+ uint32_t getTransactionFlags(uint32_t flags);
+ uint32_t setTransactionFlags(uint32_t flags);
- bool belongsToDisplay(uint32_t layerStack, bool isPrimaryDisplay) const EXCLUDES(mStateMutex) {
+ // Deprecated, please use compositionengine::Output::belongsInOutput()
+ // instead.
+ // TODO(lpique): Move the remaining callers (screencap) to the new function.
+ bool belongsToDisplay(uint32_t layerStack, bool isPrimaryDisplay) const {
return getLayerStack() == layerStack && (!mPrimaryDisplayOnly || isPrimaryDisplay);
}
void computeGeometry(const RenderArea& renderArea, renderengine::Mesh& mesh,
- bool useIdentityTransform) const REQUIRES(mStateMutex);
- FloatRect computeBounds(const Region& activeTransparentRegion) const EXCLUDES(mStateMutex);
- FloatRect computeBoundsLocked(const Region& activeTransparentRegion) const
- REQUIRES(mStateMutex);
- FloatRect computeBounds() const EXCLUDES(mStateMutex);
- FloatRect computeBoundsLocked() const REQUIRES(mStateMutex);
+ bool useIdentityTransform) const;
+ FloatRect computeBounds(const Region& activeTransparentRegion) const;
+ FloatRect computeBounds() const;
int32_t getSequence() const { return sequence; }
@@ -374,21 +367,16 @@
*/
virtual bool isOpaque(const Layer::State&) const { return false; }
- virtual bool isDrawingOpaque() const EXCLUDES(mStateMutex) {
- Mutex::Autolock lock(mStateMutex);
- return isOpaque(mState.drawing);
- }
-
/*
* isSecure - true if this surface is secure, that is if it prevents
* screenshots or VNC servers.
*/
- bool isSecure() const EXCLUDES(mStateMutex);
+ bool isSecure() const;
/*
* isVisible - true if this layer is visible, false otherwise
*/
- virtual bool isVisible() const EXCLUDES(mStateMutex) = 0;
+ virtual bool isVisible() const = 0;
/*
* isHiddenByPolicy - true if this layer has been forced invisible.
@@ -396,7 +384,7 @@
* For example if this layer has no active buffer, it may not be hidden by
* policy, but it still can not be visible.
*/
- bool isHiddenByPolicy() const EXCLUDES(mStateMutex);
+ bool isHiddenByPolicy() const;
/*
* isProtected - true if the layer may contain protected content in the
@@ -417,8 +405,7 @@
bool isRemovedFromCurrentState() const;
void writeToProto(LayerProto* layerInfo,
- LayerVector::StateSet stateSet = LayerVector::StateSet::Drawing)
- EXCLUDES(mStateMutex);
+ LayerVector::StateSet stateSet = LayerVector::StateSet::Drawing);
void writeToProto(LayerProto* layerInfo, DisplayId displayId);
@@ -431,32 +418,25 @@
virtual Region getActiveTransparentRegion(const Layer::State& s) const {
return s.activeTransparentRegion_legacy;
}
-
- virtual Region getDrawingActiveTransparentRegion() const EXCLUDES(mStateMutex) {
- Mutex::Autolock lock(mStateMutex);
- return getActiveTransparentRegion(mState.drawing);
- }
-
virtual Rect getCrop(const Layer::State& s) const { return s.crop_legacy; }
protected:
/*
* onDraw - draws the surface.
*/
- virtual void onDraw(const RenderArea& renderArea, const Region& clip, bool useIdentityTransform)
- EXCLUDES(mStateMutex) = 0;
+ virtual void onDraw(const RenderArea& renderArea, const Region& clip,
+ bool useIdentityTransform) = 0;
public:
virtual void setDefaultBufferSize(uint32_t /*w*/, uint32_t /*h*/) {}
virtual bool isHdrY410() const { return false; }
- void setGeometry(const sp<const DisplayDevice>& display, uint32_t z) EXCLUDES(mStateMutex);
+ void setGeometry(const sp<const DisplayDevice>& display, uint32_t z);
void forceClientComposition(DisplayId displayId);
bool getForceClientComposition(DisplayId displayId);
virtual void setPerFrameData(DisplayId displayId, const ui::Transform& transform,
- const Rect& viewport, int32_t supportedPerFrameMetadata)
- EXCLUDES(mStateMutex) = 0;
+ const Rect& viewport, int32_t supportedPerFrameMetadata) = 0;
// callIntoHwc exists so we can update our local state and call
// acceptDisplayChanges without unnecessarily updating the device's state
@@ -464,7 +444,7 @@
HWC2::Composition getCompositionType(const std::optional<DisplayId>& displayId) const;
void setClearClientTarget(DisplayId displayId, bool clear);
bool getClearClientTarget(DisplayId displayId) const;
- void updateCursorPosition(const sp<const DisplayDevice>& display) EXCLUDES(mStateMutex);
+ void updateCursorPosition(const sp<const DisplayDevice>& display);
/*
* called after page-flip
@@ -487,27 +467,25 @@
virtual bool onPostComposition(const std::optional<DisplayId>& /*displayId*/,
const std::shared_ptr<FenceTime>& /*glDoneFence*/,
const std::shared_ptr<FenceTime>& /*presentFence*/,
- const CompositorTiming& /*compositorTiming*/)
- EXCLUDES(mStateMutex) {
+ const CompositorTiming& /*compositorTiming*/) {
return false;
}
// If a buffer was replaced this frame, release the former buffer
virtual void releasePendingBuffer(nsecs_t /*dequeueReadyTime*/) { }
-
/*
* draw - performs some global clipping optimizations
* and calls onDraw().
*/
- void draw(const RenderArea& renderArea, const Region& clip) EXCLUDES(mStateMutex);
- void draw(const RenderArea& renderArea, bool useIdentityTransform) EXCLUDES(mStateMutex);
+ void draw(const RenderArea& renderArea, const Region& clip);
+ void draw(const RenderArea& renderArea, bool useIdentityTransform);
/*
* doTransaction - process the transaction. This is a good place to figure
* out which attributes of the surface have changed.
*/
- uint32_t doTransaction(uint32_t transactionFlags) EXCLUDES(mStateMutex);
+ uint32_t doTransaction(uint32_t transactionFlags);
/*
* setVisibleRegion - called to set the new visible region. This gives
@@ -540,17 +518,17 @@
* to figure out if the content or size of a surface has changed.
*/
virtual Region latchBuffer(bool& /*recomputeVisibleRegions*/, nsecs_t /*latchTime*/,
- const sp<Fence>& /*releaseFence*/) EXCLUDES(mStateMutex) {
+ const sp<Fence>& /*releaseFence*/) {
return {};
}
virtual bool isBufferLatched() const { return false; }
/*
- * called with SurfaceFlinger mStateLock a binder thread when the layer is
+ * called with the state lock from a binder thread when the layer is
* removed from the current list to the pending removal list
*/
- void onRemovedFromCurrentState() EXCLUDES(mStateMutex);
+ void onRemovedFromCurrentState();
/*
* Called when the layer is added back to the current state list.
@@ -570,7 +548,7 @@
/*
* Returns if a frame is ready
*/
- virtual bool hasReadyFrame() const EXCLUDES(mStateMutex) { return false; }
+ virtual bool hasReadyFrame() const { return false; }
virtual int32_t getQueuedFrameCount() const { return 0; }
@@ -599,32 +577,17 @@
}
// -----------------------------------------------------------------------
- void clearWithOpenGL(const RenderArea& renderArea) const EXCLUDES(mStateMutex);
+ void clearWithOpenGL(const RenderArea& renderArea) const;
- inline const State& getDrawingState() const REQUIRES(mStateMutex) { return mState.drawing; }
+ inline const State& getDrawingState() const { return mDrawingState; }
+ inline const State& getCurrentState() const { return mCurrentState; }
+ inline State& getCurrentState() { return mCurrentState; }
- inline const State& getCurrentState() const REQUIRES(mStateMutex) { return mState.current; }
-
- inline State& getCurrentState() REQUIRES(mStateMutex) { return mState.current; }
-
- std::tuple<uint32_t, int32_t> getLayerStackAndZ(StateSet stateSet) EXCLUDES(mStateMutex);
- wp<Layer> getZOrderRelativeOf(StateSet stateSet) EXCLUDES(mStateMutex) {
- Mutex::Autolock lock(mStateMutex);
- const State& state = (stateSet == StateSet::Current) ? mState.current : mState.drawing;
-
- return state.zOrderRelativeOf;
- }
-
- uint8_t getCurrentFlags() EXCLUDES(mStateMutex) {
- Mutex::Autolock lock(mStateMutex);
- return mState.current.flags;
- }
-
- LayerDebugInfo getLayerDebugInfo() const EXCLUDES(mStateMutex);
+ LayerDebugInfo getLayerDebugInfo() const;
/* always call base class first */
static void miniDumpHeader(std::string& result);
- void miniDump(std::string& result, DisplayId displayId) const EXCLUDES(mStateMutex);
+ void miniDump(std::string& result, DisplayId displayId) const;
void dumpFrameStats(std::string& result) const;
void dumpFrameEvents(std::string& result);
void clearFrameStats();
@@ -639,29 +602,22 @@
void addAndGetFrameTimestamps(const NewFrameEventsEntry* newEntry,
FrameEventHistoryDelta* outDelta);
- bool getTransformToDisplayInverse() const EXCLUDES(mStateMutex) {
- Mutex::Autolock lock(mStateMutex);
- return getTransformToDisplayInverseLocked();
- }
+ virtual bool getTransformToDisplayInverse() const { return false; }
- virtual bool getTransformToDisplayInverseLocked() const REQUIRES(mStateMutex) { return false; }
-
- ui::Transform getTransform() const EXCLUDES(mStateMutex);
- ui::Transform getTransformLocked() const REQUIRES(mStateMutex);
+ ui::Transform getTransform() const;
// Returns the Alpha of the Surface, accounting for the Alpha
// of parent Surfaces in the hierarchy (alpha's will be multiplied
// down the hierarchy).
- half getAlpha() const EXCLUDES(mStateMutex);
- half4 getColor() const REQUIRES(mStateMutex);
+ half getAlpha() const;
+ half4 getColor() const;
// Returns how rounded corners should be drawn for this layer.
// This will traverse the hierarchy until it reaches its root, finding topmost rounded
// corner definition and converting it into current layer's coordinates.
// As of now, only 1 corner radius per display list is supported. Subsequent ones will be
// ignored.
- RoundedCornerState getRoundedCornerState() const EXCLUDES(mStateMutex);
- RoundedCornerState getRoundedCornerStateLocked() const REQUIRES(mStateMutex);
+ RoundedCornerState getRoundedCornerState() const;
void traverseInReverseZOrder(LayerVector::StateSet stateSet,
const LayerVector::Visitor& visitor);
@@ -681,7 +637,7 @@
ssize_t removeChild(const sp<Layer>& layer);
sp<Layer> getParent() const { return mCurrentParent.promote(); }
bool hasParent() const { return getParent() != nullptr; }
- Rect computeScreenBounds(bool reduceTransparentRegion = true) const EXCLUDES(mStateMutex);
+ Rect computeScreenBounds(bool reduceTransparentRegion = true) const;
bool setChildLayer(const sp<Layer>& childLayer, int32_t z);
bool setChildRelativeLayer(const sp<Layer>& childLayer,
const sp<IBinder>& relativeToHandle, int32_t relativeZ);
@@ -689,23 +645,14 @@
// Copy the current list of children to the drawing state. Called by
// SurfaceFlinger to complete a transaction.
void commitChildList();
- int32_t getZ() const EXCLUDES(mStateMutex);
- void pushPendingState() EXCLUDES(mStateMutex);
- virtual void pushPendingStateLocked() REQUIRES(mStateMutex);
+ int32_t getZ() const;
+ virtual void pushPendingState();
/**
* Returns active buffer size in the correct orientation. Buffer size is determined by undoing
* any buffer transformations. If the layer has no buffer then return INVALID_RECT.
*/
- virtual Rect getBufferSize(const Layer::State&) const REQUIRES(mStateMutex) {
- return Rect::INVALID_RECT;
- }
-
- virtual Rect getBufferSize(StateSet stateSet) const EXCLUDES(mStateMutex) {
- Mutex::Autolock lock(mStateMutex);
- const State& state = (stateSet == StateSet::Current) ? mState.current : mState.drawing;
- return getBufferSize(state);
- }
+ virtual Rect getBufferSize(const Layer::State&) const { return Rect::INVALID_RECT; }
protected:
// constant
@@ -734,17 +681,16 @@
// For unit tests
friend class TestableSurfaceFlinger;
- void commitTransaction(const State& stateToCommit) REQUIRES(mStateMutex);
+ void commitTransaction(const State& stateToCommit);
uint32_t getEffectiveUsage(uint32_t usage) const;
- virtual FloatRect computeCrop(const sp<const DisplayDevice>& display) const
- REQUIRES(mStateMutex);
+ virtual FloatRect computeCrop(const sp<const DisplayDevice>& display) const;
// Compute the initial crop as specified by parent layers and the
// SurfaceControl for this layer. Does not include buffer crop from the
// IGraphicBufferProducer client, as that should not affect child clipping.
// Returns in screen space.
- Rect computeInitialCrop(const sp<const DisplayDevice>& display) const REQUIRES(mStateMutex);
+ Rect computeInitialCrop(const sp<const DisplayDevice>& display) const;
/**
* Setup rounded corners coordinates of this layer, taking into account the layer bounds and
* crop coordinates, transforming them into layer space.
@@ -752,13 +698,13 @@
void setupRoundedCornersCropCoordinates(Rect win, const FloatRect& roundedCornersCrop) const;
// drawing
- void clearWithOpenGL(const RenderArea& renderArea, float r, float g, float b, float alpha) const
- EXCLUDES(mStateMutex);
+ void clearWithOpenGL(const RenderArea& renderArea, float r, float g, float b,
+ float alpha) const;
void setParent(const sp<Layer>& layer);
LayerVector makeTraversalList(LayerVector::StateSet stateSet, bool* outSkipRelativeZUsers);
- void addZOrderRelative(const wp<Layer>& relative) EXCLUDES(mStateMutex);
- void removeZOrderRelative(const wp<Layer>& relative) EXCLUDES(mStateMutex);
+ void addZOrderRelative(const wp<Layer>& relative);
+ void removeZOrderRelative(const wp<Layer>& relative);
class SyncPoint {
public:
@@ -794,10 +740,9 @@
// Returns false if the relevant frame has already been latched
bool addSyncPoint(const std::shared_ptr<SyncPoint>& point);
- void popPendingState(State* stateToCommit) REQUIRES(mStateMutex);
- virtual bool applyPendingStates(State* stateToCommit) REQUIRES(mStateMutex);
- virtual uint32_t doTransactionResize(uint32_t flags, Layer::State* stateToCommit)
- REQUIRES(mStateMutex);
+ void popPendingState(State* stateToCommit);
+ virtual bool applyPendingStates(State* stateToCommit);
+ virtual uint32_t doTransactionResize(uint32_t flags, Layer::State* stateToCommit);
void clearSyncPoints();
@@ -830,15 +775,14 @@
bool getPremultipledAlpha() const;
bool mPendingHWCDestroy{false};
- void setInputInfo(const InputWindowInfo& info) EXCLUDES(mStateMutex);
+ void setInputInfo(const InputWindowInfo& info);
- InputWindowInfo fillInputInfo(const Rect& screenBounds) EXCLUDES(mStateMutex);
- bool hasInput() const EXCLUDES(mStateMutex);
+ InputWindowInfo fillInputInfo();
+ bool hasInput() const;
protected:
// -----------------------------------------------------------------------
- bool usingRelativeZ(LayerVector::StateSet stateSet) EXCLUDES(mStateMutex);
- bool usingRelativeZLocked(LayerVector::StateSet stateSet) REQUIRES(mStateMutex);
+ bool usingRelativeZ(LayerVector::StateSet stateSet);
bool mPremultipliedAlpha{true};
String8 mName;
@@ -846,14 +790,14 @@
bool mPrimaryDisplayOnly = false;
+ // these are protected by an external lock
+ State mCurrentState;
+ State mDrawingState;
+ std::atomic<uint32_t> mTransactionFlags{0};
+
// Accessed from main thread and binder threads
- mutable Mutex mStateMutex;
- struct {
- State current;
- State drawing;
- uint32_t transactionFlags{0};
- Vector<State> pending;
- } mState GUARDED_BY(mStateMutex);
+ Mutex mPendingStateMutex;
+ Vector<State> mPendingStates;
// Timestamp history for UIAutomation. Thread safe.
FrameTracker mFrameTracker;
@@ -904,6 +848,8 @@
// Can only be accessed with the SF state lock held.
bool mLayerDetached{false};
+ // Can only be accessed with the SF state lock held.
+ bool mChildrenChanged{false};
private:
/**
@@ -926,7 +872,7 @@
* The cropped bounds must be transformed back from parent layer space to child layer space by
* applying the inverse of the child's transformation.
*/
- FloatRect cropChildBounds(const FloatRect& childBounds) const REQUIRES(mStateMutex);
+ FloatRect cropChildBounds(const FloatRect& childBounds) const;
/**
* Returns the cropped buffer size or the layer crop if the layer has no buffer. Return
@@ -934,12 +880,7 @@
* A layer with an invalid buffer size and no crop is considered to be boundless. The layer
* bounds are constrained by its parent bounds.
*/
- Rect getCroppedBufferSize(const Layer::State& s) const REQUIRES(mStateMutex);
-
- // locked version of public methods
- bool isSecureLocked() const REQUIRES(mStateMutex);
- virtual uint32_t getLayerStackLocked() const REQUIRES(mStateMutex);
- half getAlphaLocked() const REQUIRES(mStateMutex);
+ Rect getCroppedBufferSize(const Layer::State& s) const;
};
} // namespace android
diff --git a/services/surfaceflinger/LayerBE.h b/services/surfaceflinger/LayerBE.h
index 3f5134e..6270efa 100644
--- a/services/surfaceflinger/LayerBE.h
+++ b/services/surfaceflinger/LayerBE.h
@@ -19,6 +19,8 @@
#include <stdint.h>
#include <sys/types.h>
+#include <compositionengine/impl/HwcBufferCache.h>
+
#include <renderengine/Mesh.h>
#include <renderengine/RenderEngine.h>
#include <renderengine/Texture.h>
@@ -26,7 +28,6 @@
#include "DisplayHardware/DisplayIdentification.h"
#include "DisplayHardware/HWComposer.h"
-#include "DisplayHardware/HWComposerBufferCache.h"
#include "SurfaceFlinger.h"
namespace android {
@@ -120,7 +121,7 @@
bool clearClientTarget;
Rect displayFrame;
FloatRect sourceCrop;
- HWComposerBufferCache bufferCache;
+ compositionengine::impl::HwcBufferCache bufferCache;
HWC2::Transform transform;
};
diff --git a/services/surfaceflinger/LayerVector.cpp b/services/surfaceflinger/LayerVector.cpp
index a7db23e..8494524 100644
--- a/services/surfaceflinger/LayerVector.cpp
+++ b/services/surfaceflinger/LayerVector.cpp
@@ -38,12 +38,18 @@
const auto& l = *reinterpret_cast<const sp<Layer>*>(lhs);
const auto& r = *reinterpret_cast<const sp<Layer>*>(rhs);
- const auto& [ls, lz] = l->getLayerStackAndZ(mStateSet);
- const auto& [rs, rz] = r->getLayerStackAndZ(mStateSet);
+ const auto& lState =
+ (mStateSet == StateSet::Current) ? l->getCurrentState() : l->getDrawingState();
+ const auto& rState =
+ (mStateSet == StateSet::Current) ? r->getCurrentState() : r->getDrawingState();
+ uint32_t ls = lState.layerStack;
+ uint32_t rs = rState.layerStack;
if (ls != rs)
return (ls > rs) ? 1 : -1;
+ int32_t lz = lState.z;
+ int32_t rz = rState.z;
if (lz != rz)
return (lz > rz) ? 1 : -1;
@@ -56,8 +62,9 @@
void LayerVector::traverseInZOrder(StateSet stateSet, const Visitor& visitor) const {
for (size_t i = 0; i < size(); i++) {
const auto& layer = (*this)[i];
- auto zOrderRelativeOf = layer->getZOrderRelativeOf(stateSet);
- if (zOrderRelativeOf != nullptr) {
+ auto& state = (stateSet == StateSet::Current) ? layer->getCurrentState()
+ : layer->getDrawingState();
+ if (state.zOrderRelativeOf != nullptr) {
continue;
}
layer->traverseInZOrder(stateSet, visitor);
@@ -67,8 +74,9 @@
void LayerVector::traverseInReverseZOrder(StateSet stateSet, const Visitor& visitor) const {
for (auto i = static_cast<int64_t>(size()) - 1; i >= 0; i--) {
const auto& layer = (*this)[i];
- auto zOrderRelativeOf = layer->getZOrderRelativeOf(stateSet);
- if (zOrderRelativeOf != nullptr) {
+ auto& state = (stateSet == StateSet::Current) ? layer->getCurrentState()
+ : layer->getDrawingState();
+ if (state.zOrderRelativeOf != nullptr) {
continue;
}
layer->traverseInReverseZOrder(stateSet, visitor);
diff --git a/services/surfaceflinger/Scheduler/DispSync.cpp b/services/surfaceflinger/Scheduler/DispSync.cpp
index b74b901..075e238 100644
--- a/services/surfaceflinger/Scheduler/DispSync.cpp
+++ b/services/surfaceflinger/Scheduler/DispSync.cpp
@@ -657,6 +657,9 @@
Mutex::Autolock lock(mMutex);
nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
nsecs_t phase = mReferenceTime + mPhase;
+ if (mPeriod == 0) {
+ return 0;
+ }
return (((now - phase) / mPeriod) + periodOffset + 1) * mPeriod + phase;
}
@@ -754,18 +757,7 @@
const uint32_t hwcLatency = 0;
// Ask DispSync when the next refresh will be (CLOCK_MONOTONIC).
- const nsecs_t nextRefresh = computeNextRefresh(hwcLatency);
-
- // The DispSync time is already adjusted for the difference between
- // vsync and reported-vsync (SurfaceFlinger::dispSyncPresentTimeOffset), so
- // we don't need to factor that in here. Pad a little to avoid
- // weird effects if apps might be requesting times right on the edge.
- nsecs_t extraPadding = 0;
- if (SurfaceFlinger::vsyncPhaseOffsetNs == 0) {
- extraPadding = 1000000; // 1ms (6% of 60Hz)
- }
-
- return nextRefresh + extraPadding;
+ return computeNextRefresh(hwcLatency);
}
} // namespace impl
diff --git a/services/surfaceflinger/Scheduler/EventThread.cpp b/services/surfaceflinger/Scheduler/EventThread.cpp
index 1683982..52abe9c 100644
--- a/services/surfaceflinger/Scheduler/EventThread.cpp
+++ b/services/surfaceflinger/Scheduler/EventThread.cpp
@@ -19,8 +19,11 @@
#include <pthread.h>
#include <sched.h>
#include <sys/types.h>
+
#include <chrono>
#include <cstdint>
+#include <optional>
+#include <type_traits>
#include <android-base/stringprintf.h>
@@ -35,16 +38,68 @@
#include "EventThread.h"
using namespace std::chrono_literals;
-using android::base::StringAppendF;
-
-// ---------------------------------------------------------------------------
namespace android {
-// ---------------------------------------------------------------------------
+using base::StringAppendF;
+using base::StringPrintf;
-EventThreadConnection::EventThreadConnection(EventThread* eventThread)
- : count(-1), mEventThread(eventThread), mChannel(gui::BitTube::DefaultSize) {}
+namespace {
+
+auto vsyncPeriod(VSyncRequest request) {
+ return static_cast<std::underlying_type_t<VSyncRequest>>(request);
+}
+
+std::string toString(VSyncRequest request) {
+ switch (request) {
+ case VSyncRequest::None:
+ return "VSyncRequest::None";
+ case VSyncRequest::Single:
+ return "VSyncRequest::Single";
+ default:
+ return StringPrintf("VSyncRequest::Periodic{period=%d}", vsyncPeriod(request));
+ }
+}
+
+std::string toString(const EventThreadConnection& connection) {
+ return StringPrintf("Connection{%p, %s}", &connection,
+ toString(connection.vsyncRequest).c_str());
+}
+
+std::string toString(const DisplayEventReceiver::Event& event) {
+ switch (event.header.type) {
+ case DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG:
+ return StringPrintf("Hotplug{displayId=%u, %s}", event.header.id,
+ event.hotplug.connected ? "connected" : "disconnected");
+ case DisplayEventReceiver::DISPLAY_EVENT_VSYNC:
+ return StringPrintf("VSync{displayId=%u, count=%u}", event.header.id,
+ event.vsync.count);
+ default:
+ return "Event{}";
+ }
+}
+
+DisplayEventReceiver::Event makeHotplug(uint32_t displayId, nsecs_t timestamp, bool connected) {
+ DisplayEventReceiver::Event event;
+ event.header = {DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG, displayId, timestamp};
+ event.hotplug.connected = connected;
+ return event;
+}
+
+DisplayEventReceiver::Event makeVSync(uint32_t displayId, nsecs_t timestamp, uint32_t count) {
+ DisplayEventReceiver::Event event;
+ event.header = {DisplayEventReceiver::DISPLAY_EVENT_VSYNC, displayId, timestamp};
+ event.vsync.count = count;
+ return event;
+}
+
+} // namespace
+
+EventThreadConnection::EventThreadConnection(EventThread* eventThread,
+ ResyncCallback resyncCallback)
+ : resyncCallback(std::move(resyncCallback)),
+ mEventThread(eventThread),
+ mChannel(gui::BitTube::DefaultSize) {}
EventThreadConnection::~EventThreadConnection() {
// do nothing here -- clean-up will happen automatically
@@ -61,13 +116,19 @@
return NO_ERROR;
}
-status_t EventThreadConnection::setVsyncRate(uint32_t count) {
- mEventThread->setVsyncRate(count, this);
+status_t EventThreadConnection::setVsyncRate(uint32_t rate) {
+ mEventThread->setVsyncRate(rate, this);
return NO_ERROR;
}
void EventThreadConnection::requestNextVsync() {
- mEventThread->requestNextVsync(this);
+ ATRACE_NAME("requestNextVsync");
+ mEventThread->requestNextVsync(this, true);
+}
+
+void EventThreadConnection::requestNextVsyncForHWC() {
+ ATRACE_NAME("requestNextVsyncForHWC");
+ mEventThread->requestNextVsync(this, false);
}
status_t EventThreadConnection::postEvent(const DisplayEventReceiver::Event& event) {
@@ -82,38 +143,32 @@
namespace impl {
EventThread::EventThread(std::unique_ptr<VSyncSource> src,
- const ResyncWithRateLimitCallback& resyncWithRateLimitCallback,
const InterceptVSyncsCallback& interceptVSyncsCallback,
const ResetIdleTimerCallback& resetIdleTimerCallback,
const char* threadName)
- : EventThread(nullptr, std::move(src), resyncWithRateLimitCallback, interceptVSyncsCallback,
- threadName) {
+ : EventThread(nullptr, std::move(src), interceptVSyncsCallback, threadName) {
mResetIdleTimer = resetIdleTimerCallback;
}
-EventThread::EventThread(VSyncSource* src, ResyncWithRateLimitCallback resyncWithRateLimitCallback,
- InterceptVSyncsCallback interceptVSyncsCallback, const char* threadName)
- : EventThread(src, nullptr, resyncWithRateLimitCallback, interceptVSyncsCallback,
- threadName) {}
+EventThread::EventThread(VSyncSource* src, InterceptVSyncsCallback interceptVSyncsCallback,
+ const char* threadName)
+ : EventThread(src, nullptr, interceptVSyncsCallback, threadName) {}
EventThread::EventThread(VSyncSource* src, std::unique_ptr<VSyncSource> uniqueSrc,
- ResyncWithRateLimitCallback resyncWithRateLimitCallback,
InterceptVSyncsCallback interceptVSyncsCallback, const char* threadName)
: mVSyncSource(src),
mVSyncSourceUnique(std::move(uniqueSrc)),
- mResyncWithRateLimitCallback(resyncWithRateLimitCallback),
- mInterceptVSyncsCallback(interceptVSyncsCallback) {
+ mInterceptVSyncsCallback(interceptVSyncsCallback),
+ mThreadName(threadName) {
if (src == nullptr) {
mVSyncSource = mVSyncSourceUnique.get();
}
- for (auto& event : mVSyncEvent) {
- event.header.type = DisplayEventReceiver::DISPLAY_EVENT_VSYNC;
- event.header.id = 0;
- event.header.timestamp = 0;
- event.vsync.count = 0;
- }
+ mVSyncSource->setCallback(this);
- mThread = std::thread(&EventThread::threadMain, this);
+ mThread = std::thread([this]() NO_THREAD_SAFETY_ANALYSIS {
+ std::unique_lock<std::mutex> lock(mMutex);
+ threadMain(lock);
+ });
pthread_setname_np(mThread.native_handle(), threadName);
@@ -131,9 +186,11 @@
}
EventThread::~EventThread() {
+ mVSyncSource->setCallback(nullptr);
+
{
std::lock_guard<std::mutex> lock(mMutex);
- mKeepRunning = false;
+ mState = State::Quit;
mCondition.notify_all();
}
mThread.join();
@@ -144,8 +201,8 @@
mVSyncSource->setPhaseOffset(phaseOffset);
}
-sp<EventThreadConnection> EventThread::createEventConnection() const {
- return new EventThreadConnection(const_cast<EventThread*>(this));
+sp<EventThreadConnection> EventThread::createEventConnection(ResyncCallback resyncCallback) const {
+ return new EventThreadConnection(const_cast<EventThread*>(this), std::move(resyncCallback));
}
status_t EventThread::registerDisplayEventConnection(const sp<EventThreadConnection>& connection) {
@@ -173,270 +230,246 @@
}
}
-void EventThread::setVsyncRate(uint32_t count, const sp<EventThreadConnection>& connection) {
- if (int32_t(count) >= 0) { // server must protect against bad params
- std::lock_guard<std::mutex> lock(mMutex);
- const int32_t new_count = (count == 0) ? -1 : count;
- if (connection->count != new_count) {
- connection->count = new_count;
- mCondition.notify_all();
- }
+void EventThread::setVsyncRate(uint32_t rate, const sp<EventThreadConnection>& connection) {
+ if (static_cast<std::underlying_type_t<VSyncRequest>>(rate) < 0) {
+ return;
+ }
+
+ std::lock_guard<std::mutex> lock(mMutex);
+
+ const auto request = rate == 0 ? VSyncRequest::None : static_cast<VSyncRequest>(rate);
+ if (connection->vsyncRequest != request) {
+ connection->vsyncRequest = request;
+ mCondition.notify_all();
}
}
-void EventThread::requestNextVsync(const sp<EventThreadConnection>& connection) {
- std::lock_guard<std::mutex> lock(mMutex);
- if (mResetIdleTimer) {
+void EventThread::requestNextVsync(const sp<EventThreadConnection>& connection, bool reset) {
+ if (mResetIdleTimer && reset) {
+ ATRACE_NAME("resetIdleTimer");
mResetIdleTimer();
}
- if (mResyncWithRateLimitCallback) {
- mResyncWithRateLimitCallback();
+ if (connection->resyncCallback) {
+ connection->resyncCallback();
}
- if (connection->count < 0) {
- connection->count = 0;
+ std::lock_guard<std::mutex> lock(mMutex);
+
+ if (connection->vsyncRequest == VSyncRequest::None) {
+ connection->vsyncRequest = VSyncRequest::Single;
mCondition.notify_all();
}
}
void EventThread::onScreenReleased() {
std::lock_guard<std::mutex> lock(mMutex);
- if (!mUseSoftwareVSync) {
- // disable reliance on h/w vsync
- mUseSoftwareVSync = true;
- mCondition.notify_all();
+ if (!mVSyncState || mVSyncState->synthetic) {
+ return;
}
+
+ mVSyncState->synthetic = true;
+ mCondition.notify_all();
}
void EventThread::onScreenAcquired() {
std::lock_guard<std::mutex> lock(mMutex);
- if (mUseSoftwareVSync) {
- // resume use of h/w vsync
- mUseSoftwareVSync = false;
- mCondition.notify_all();
+ if (!mVSyncState || !mVSyncState->synthetic) {
+ return;
}
+
+ mVSyncState->synthetic = false;
+ mCondition.notify_all();
}
void EventThread::onVSyncEvent(nsecs_t timestamp) {
std::lock_guard<std::mutex> lock(mMutex);
- mVSyncEvent[0].header.type = DisplayEventReceiver::DISPLAY_EVENT_VSYNC;
- mVSyncEvent[0].header.id = 0;
- mVSyncEvent[0].header.timestamp = timestamp;
- mVSyncEvent[0].vsync.count++;
+
+ LOG_FATAL_IF(!mVSyncState);
+ mPendingEvents.push_back(makeVSync(mVSyncState->displayId, timestamp, ++mVSyncState->count));
mCondition.notify_all();
}
void EventThread::onHotplugReceived(DisplayType displayType, bool connected) {
std::lock_guard<std::mutex> lock(mMutex);
- DisplayEventReceiver::Event event;
- event.header.type = DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG;
- event.header.id = displayType == DisplayType::Primary ? 0 : 1;
- event.header.timestamp = systemTime();
- event.hotplug.connected = connected;
-
- mPendingEvents.push(event);
+ const uint32_t displayId = displayType == DisplayType::Primary ? 0 : 1;
+ mPendingEvents.push_back(makeHotplug(displayId, systemTime(), connected));
mCondition.notify_all();
}
-void EventThread::threadMain() NO_THREAD_SAFETY_ANALYSIS {
- std::unique_lock<std::mutex> lock(mMutex);
- while (mKeepRunning) {
- DisplayEventReceiver::Event event;
- std::vector<sp<EventThreadConnection>> signalConnections;
- signalConnections = waitForEventLocked(&lock, &event);
+void EventThread::threadMain(std::unique_lock<std::mutex>& lock) {
+ DisplayEventConsumers consumers;
- // dispatch events to listeners...
- for (const sp<EventThreadConnection>& conn : signalConnections) {
- // now see if we still need to report this event
- status_t err = conn->postEvent(event);
- if (err == -EAGAIN || err == -EWOULDBLOCK) {
- // The destination doesn't accept events anymore, it's probably
- // full. For now, we just drop the events on the floor.
- // FIXME: Note that some events cannot be dropped and would have
- // to be re-sent later.
- // Right-now we don't have the ability to do this.
- ALOGW("EventThread: dropping event (%08x) for connection %p", event.header.type,
- conn.get());
- } else if (err < 0) {
- // handle any other error on the pipe as fatal. the only
- // reasonable thing to do is to clean-up this connection.
- // The most common error we'll get here is -EPIPE.
- removeDisplayEventConnectionLocked(conn);
- }
- }
- }
-}
+ while (mState != State::Quit) {
+ std::optional<DisplayEventReceiver::Event> event;
-// This will return when (1) a vsync event has been received, and (2) there was
-// at least one connection interested in receiving it when we started waiting.
-std::vector<sp<EventThreadConnection>> EventThread::waitForEventLocked(
- std::unique_lock<std::mutex>* lock, DisplayEventReceiver::Event* outEvent) {
- std::vector<sp<EventThreadConnection>> signalConnections;
+ // Determine next event to dispatch.
+ if (!mPendingEvents.empty()) {
+ event = mPendingEvents.front();
+ mPendingEvents.pop_front();
- while (signalConnections.empty() && mKeepRunning) {
- bool eventPending = false;
- bool waitForVSync = false;
+ switch (event->header.type) {
+ case DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG:
+ if (event->hotplug.connected && !mVSyncState) {
+ mVSyncState.emplace(event->header.id);
+ } else if (!event->hotplug.connected && mVSyncState &&
+ mVSyncState->displayId == event->header.id) {
+ mVSyncState.reset();
+ }
+ break;
- size_t vsyncCount = 0;
- nsecs_t timestamp = 0;
- for (auto& event : mVSyncEvent) {
- timestamp = event.header.timestamp;
- if (timestamp) {
- // we have a vsync event to dispatch
- if (mInterceptVSyncsCallback) {
- mInterceptVSyncsCallback(timestamp);
- }
- *outEvent = event;
- event.header.timestamp = 0;
- vsyncCount = event.vsync.count;
- break;
+ case DisplayEventReceiver::DISPLAY_EVENT_VSYNC:
+ if (mInterceptVSyncsCallback) {
+ mInterceptVSyncsCallback(event->header.timestamp);
+ }
+ break;
}
}
- if (!timestamp) {
- // no vsync event, see if there are some other event
- eventPending = !mPendingEvents.empty();
- if (eventPending) {
- // we have some other event to dispatch
- *outEvent = mPendingEvents.front();
- mPendingEvents.pop();
- }
- }
+ bool vsyncRequested = false;
- // find out connections waiting for events
+ // Find connections that should consume this event.
auto it = mDisplayEventConnections.begin();
while (it != mDisplayEventConnections.end()) {
- sp<EventThreadConnection> connection(it->promote());
- if (connection != nullptr) {
- bool added = false;
- if (connection->count >= 0) {
- // we need vsync events because at least
- // one connection is waiting for it
- waitForVSync = true;
- if (timestamp) {
- // we consume the event only if it's time
- // (ie: we received a vsync event)
- if (connection->count == 0) {
- // fired this time around
- connection->count = -1;
- signalConnections.push_back(connection);
- added = true;
- } else if (connection->count == 1 ||
- (vsyncCount % connection->count) == 0) {
- // continuous event, and time to report it
- signalConnections.push_back(connection);
- added = true;
- }
- }
+ if (const auto connection = it->promote()) {
+ vsyncRequested |= connection->vsyncRequest != VSyncRequest::None;
+
+ if (event && shouldConsumeEvent(*event, connection)) {
+ consumers.push_back(connection);
}
- if (eventPending && !timestamp && !added) {
- // we don't have a vsync event to process
- // (timestamp==0), but we have some pending
- // messages.
- signalConnections.push_back(connection);
- }
++it;
} else {
- // we couldn't promote this reference, the connection has
- // died, so clean-up!
it = mDisplayEventConnections.erase(it);
}
}
- // Here we figure out if we need to enable or disable vsyncs
- if (timestamp && !waitForVSync) {
- // we received a VSYNC but we have no clients
- // don't report it, and disable VSYNC events
- disableVSyncLocked();
- } else if (!timestamp && waitForVSync) {
- // we have at least one client, so we want vsync enabled
- // (TODO: this function is called right after we finish
- // notifying clients of a vsync, so this call will be made
- // at the vsync rate, e.g. 60fps. If we can accurately
- // track the current state we could avoid making this call
- // so often.)
- enableVSyncLocked();
+ if (!consumers.empty()) {
+ dispatchEvent(*event, consumers);
+ consumers.clear();
}
- // note: !timestamp implies signalConnections.isEmpty(), because we
- // don't populate signalConnections if there's no vsync pending
- if (!timestamp && !eventPending) {
- // wait for something to happen
- if (waitForVSync) {
- // This is where we spend most of our time, waiting
- // for vsync events and new client registrations.
- //
- // If the screen is off, we can't use h/w vsync, so we
- // use a 16ms timeout instead. It doesn't need to be
- // precise, we just need to keep feeding our clients.
- //
- // We don't want to stall if there's a driver bug, so we
- // use a (long) timeout when waiting for h/w vsync, and
- // generate fake events when necessary.
- bool softwareSync = mUseSoftwareVSync;
- auto timeout = softwareSync ? 16ms : 1000ms;
- if (mCondition.wait_for(*lock, timeout) == std::cv_status::timeout) {
- if (!softwareSync) {
- ALOGW("Timed out waiting for hw vsync; faking it");
- }
- // FIXME: how do we decide which display id the fake
- // vsync came from ?
- mVSyncEvent[0].header.type = DisplayEventReceiver::DISPLAY_EVENT_VSYNC;
- mVSyncEvent[0].header.id = 0;
- mVSyncEvent[0].header.timestamp = systemTime(SYSTEM_TIME_MONOTONIC);
- mVSyncEvent[0].vsync.count++;
- }
- } else {
- // Nobody is interested in vsync, so we just want to sleep.
- // h/w vsync should be disabled, so this will wait until we
- // get a new connection, or an existing connection becomes
- // interested in receiving vsync again.
- mCondition.wait(*lock);
+ State nextState;
+ if (mVSyncState && vsyncRequested) {
+ nextState = mVSyncState->synthetic ? State::SyntheticVSync : State::VSync;
+ } else {
+ ALOGW_IF(!mVSyncState, "Ignoring VSYNC request while display is disconnected");
+ nextState = State::Idle;
+ }
+
+ if (mState != nextState) {
+ if (mState == State::VSync) {
+ mVSyncSource->setVSyncEnabled(false);
+ } else if (nextState == State::VSync) {
+ mVSyncSource->setVSyncEnabled(true);
+ }
+
+ mState = nextState;
+ }
+
+ if (event) {
+ continue;
+ }
+
+ // Wait for event or client registration/request.
+ if (mState == State::Idle) {
+ mCondition.wait(lock);
+ } else {
+ // Generate a fake VSYNC after a long timeout in case the driver stalls. When the
+ // display is off, keep feeding clients at 60 Hz.
+ const auto timeout = mState == State::SyntheticVSync ? 16ms : 1000ms;
+ if (mCondition.wait_for(lock, timeout) == std::cv_status::timeout) {
+ ALOGW_IF(mState == State::VSync, "Faking VSYNC due to driver stall");
+
+ LOG_FATAL_IF(!mVSyncState);
+ mPendingEvents.push_back(makeVSync(mVSyncState->displayId,
+ systemTime(SYSTEM_TIME_MONOTONIC),
+ ++mVSyncState->count));
}
}
}
-
- // here we're guaranteed to have a timestamp and some connections to signal
- // (The connections might have dropped out of mDisplayEventConnections
- // while we were asleep, but we'll still have strong references to them.)
- return signalConnections;
}
-void EventThread::enableVSyncLocked() {
- if (!mUseSoftwareVSync) {
- // never enable h/w VSYNC when screen is off
- if (!mVsyncEnabled) {
- mVsyncEnabled = true;
- mVSyncSource->setCallback(this);
- mVSyncSource->setVSyncEnabled(true);
- }
+bool EventThread::shouldConsumeEvent(const DisplayEventReceiver::Event& event,
+ const sp<EventThreadConnection>& connection) const {
+ switch (event.header.type) {
+ case DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG:
+ return true;
+
+ case DisplayEventReceiver::DISPLAY_EVENT_VSYNC:
+ switch (connection->vsyncRequest) {
+ case VSyncRequest::None:
+ return false;
+ case VSyncRequest::Single:
+ connection->vsyncRequest = VSyncRequest::None;
+ return true;
+ case VSyncRequest::Periodic:
+ return true;
+ default:
+ return event.vsync.count % vsyncPeriod(connection->vsyncRequest) == 0;
+ }
+
+ default:
+ return false;
}
- mDebugVsyncEnabled = true;
}
-void EventThread::disableVSyncLocked() {
- if (mVsyncEnabled) {
- mVsyncEnabled = false;
- mVSyncSource->setVSyncEnabled(false);
- mDebugVsyncEnabled = false;
+void EventThread::dispatchEvent(const DisplayEventReceiver::Event& event,
+ const DisplayEventConsumers& consumers) {
+ for (const auto& consumer : consumers) {
+ switch (consumer->postEvent(event)) {
+ case NO_ERROR:
+ break;
+
+ case -EAGAIN:
+ // TODO: Try again if pipe is full.
+ ALOGW("Failed dispatching %s for %s", toString(event).c_str(),
+ toString(*consumer).c_str());
+ break;
+
+ default:
+ // Treat EPIPE and other errors as fatal.
+ removeDisplayEventConnectionLocked(consumer);
+ }
}
}
void EventThread::dump(std::string& result) const {
std::lock_guard<std::mutex> lock(mMutex);
- StringAppendF(&result, "VSYNC state: %s\n", mDebugVsyncEnabled ? "enabled" : "disabled");
- StringAppendF(&result, " soft-vsync: %s\n", mUseSoftwareVSync ? "enabled" : "disabled");
- StringAppendF(&result, " numListeners=%zu,\n events-delivered: %u\n",
- mDisplayEventConnections.size(), mVSyncEvent[0].vsync.count);
- for (const wp<EventThreadConnection>& weak : mDisplayEventConnections) {
- sp<EventThreadConnection> connection = weak.promote();
- StringAppendF(&result, " %p: count=%d\n", connection.get(),
- connection != nullptr ? connection->count : 0);
+
+ StringAppendF(&result, "%s: state=%s VSyncState=", mThreadName, toCString(mState));
+ if (mVSyncState) {
+ StringAppendF(&result, "{displayId=%u, count=%u%s}\n", mVSyncState->displayId,
+ mVSyncState->count, mVSyncState->synthetic ? ", synthetic" : "");
+ } else {
+ StringAppendF(&result, "none\n");
}
- StringAppendF(&result, " other-events-pending: %zu\n", mPendingEvents.size());
+
+ StringAppendF(&result, " pending events (count=%zu):\n", mPendingEvents.size());
+ for (const auto& event : mPendingEvents) {
+ StringAppendF(&result, " %s\n", toString(event).c_str());
+ }
+
+ StringAppendF(&result, " connections (count=%zu):\n", mDisplayEventConnections.size());
+ for (const auto& ptr : mDisplayEventConnections) {
+ if (const auto connection = ptr.promote()) {
+ StringAppendF(&result, " %s\n", toString(*connection).c_str());
+ }
+ }
+}
+
+const char* EventThread::toCString(State state) {
+ switch (state) {
+ case State::Idle:
+ return "Idle";
+ case State::Quit:
+ return "Quit";
+ case State::SyntheticVSync:
+ return "SyntheticVSync";
+ case State::VSync:
+ return "VSync";
+ }
}
} // namespace impl
diff --git a/services/surfaceflinger/Scheduler/EventThread.h b/services/surfaceflinger/Scheduler/EventThread.h
index 66f54bd..89b799e 100644
--- a/services/surfaceflinger/Scheduler/EventThread.h
+++ b/services/surfaceflinger/Scheduler/EventThread.h
@@ -18,11 +18,11 @@
#include <sys/types.h>
-#include <array>
#include <condition_variable>
#include <cstdint>
+#include <deque>
#include <mutex>
-#include <queue>
+#include <optional>
#include <thread>
#include <vector>
@@ -44,6 +44,15 @@
// ---------------------------------------------------------------------------
+using ResyncCallback = std::function<void()>;
+
+enum class VSyncRequest {
+ None = -1,
+ Single = 0,
+ Periodic = 1,
+ // Subsequent values are periods.
+};
+
class VSyncSource {
public:
class Callback {
@@ -60,19 +69,22 @@
class EventThreadConnection : public BnDisplayEventConnection {
public:
- explicit EventThreadConnection(EventThread* eventThread);
+ EventThreadConnection(EventThread* eventThread, ResyncCallback resyncCallback);
virtual ~EventThreadConnection();
virtual status_t postEvent(const DisplayEventReceiver::Event& event);
status_t stealReceiveChannel(gui::BitTube* outChannel) override;
- status_t setVsyncRate(uint32_t count) override;
+ status_t setVsyncRate(uint32_t rate) override;
void requestNextVsync() override; // asynchronous
+ // Requesting Vsync for HWC does not reset the idle timer, since HWC requires a refresh
+ // in order to update the configs.
+ void requestNextVsyncForHWC();
- // count >= 1 : continuous event. count is the vsync rate
- // count == 0 : one-shot event that has not fired
- // count ==-1 : one-shot event that fired this round / disabled
- int32_t count;
+ // Called in response to requestNextVsync.
+ const ResyncCallback resyncCallback;
+
+ VSyncRequest vsyncRequest = VSyncRequest::None;
private:
virtual void onFirstRef();
@@ -87,7 +99,8 @@
virtual ~EventThread();
- virtual sp<EventThreadConnection> createEventConnection() const = 0;
+ virtual sp<EventThreadConnection> createEventConnection(
+ ResyncCallback resyncCallback) const = 0;
// called before the screen is turned off from main thread
virtual void onScreenReleased() = 0;
@@ -104,32 +117,33 @@
virtual status_t registerDisplayEventConnection(
const sp<EventThreadConnection>& connection) = 0;
- virtual void setVsyncRate(uint32_t count, const sp<EventThreadConnection>& connection) = 0;
- virtual void requestNextVsync(const sp<EventThreadConnection>& connection) = 0;
+ virtual void setVsyncRate(uint32_t rate, const sp<EventThreadConnection>& connection) = 0;
+ // Requests the next vsync. If resetIdleTimer is set to true, it resets the idle timer.
+ virtual void requestNextVsync(const sp<EventThreadConnection>& connection,
+ bool resetIdleTimer) = 0;
};
namespace impl {
class EventThread : public android::EventThread, private VSyncSource::Callback {
public:
- using ResyncWithRateLimitCallback = std::function<void()>;
using InterceptVSyncsCallback = std::function<void(nsecs_t)>;
using ResetIdleTimerCallback = std::function<void()>;
// TODO(b/113612090): Once the Scheduler is complete this constructor will become obsolete.
- EventThread(VSyncSource* src, ResyncWithRateLimitCallback resyncWithRateLimitCallback,
- InterceptVSyncsCallback interceptVSyncsCallback, const char* threadName);
+ EventThread(VSyncSource* src, InterceptVSyncsCallback interceptVSyncsCallback,
+ const char* threadName);
EventThread(std::unique_ptr<VSyncSource> src,
- const ResyncWithRateLimitCallback& resyncWithRateLimitCallback,
const InterceptVSyncsCallback& interceptVSyncsCallback,
const ResetIdleTimerCallback& resetIdleTimerCallback, const char* threadName);
~EventThread();
- sp<EventThreadConnection> createEventConnection() const override;
+ sp<EventThreadConnection> createEventConnection(ResyncCallback resyncCallback) const override;
status_t registerDisplayEventConnection(const sp<EventThreadConnection>& connection) override;
- void setVsyncRate(uint32_t count, const sp<EventThreadConnection>& connection) override;
- void requestNextVsync(const sp<EventThreadConnection>& connection) override;
+ void setVsyncRate(uint32_t rate, const sp<EventThreadConnection>& connection) override;
+ void requestNextVsync(const sp<EventThreadConnection>& connection,
+ bool resetIdleTimer) override;
// called before the screen is turned off from main thread
void onScreenReleased() override;
@@ -147,46 +161,70 @@
private:
friend EventThreadTest;
+ using DisplayEventConsumers = std::vector<sp<EventThreadConnection>>;
+
// TODO(b/113612090): Once the Scheduler is complete this constructor will become obsolete.
EventThread(VSyncSource* src, std::unique_ptr<VSyncSource> uniqueSrc,
- ResyncWithRateLimitCallback resyncWithRateLimitCallback,
InterceptVSyncsCallback interceptVSyncsCallback, const char* threadName);
+ void threadMain(std::unique_lock<std::mutex>& lock) REQUIRES(mMutex);
- void threadMain();
- std::vector<sp<EventThreadConnection>> waitForEventLocked(std::unique_lock<std::mutex>* lock,
- DisplayEventReceiver::Event* event)
- REQUIRES(mMutex);
+ bool shouldConsumeEvent(const DisplayEventReceiver::Event& event,
+ const sp<EventThreadConnection>& connection) const REQUIRES(mMutex);
+ void dispatchEvent(const DisplayEventReceiver::Event& event,
+ const DisplayEventConsumers& consumers) REQUIRES(mMutex);
void removeDisplayEventConnectionLocked(const wp<EventThreadConnection>& connection)
REQUIRES(mMutex);
- void enableVSyncLocked() REQUIRES(mMutex);
- void disableVSyncLocked() REQUIRES(mMutex);
// Implements VSyncSource::Callback
void onVSyncEvent(nsecs_t timestamp) override;
+ // Acquires mutex and requests next vsync.
+ void requestNextVsyncInternal(const sp<EventThreadConnection>& connection) EXCLUDES(mMutex);
+
// TODO(b/113612090): Once the Scheduler is complete this pointer will become obsolete.
VSyncSource* mVSyncSource GUARDED_BY(mMutex) = nullptr;
std::unique_ptr<VSyncSource> mVSyncSourceUnique GUARDED_BY(mMutex) = nullptr;
- // constants
- const ResyncWithRateLimitCallback mResyncWithRateLimitCallback;
+
const InterceptVSyncsCallback mInterceptVSyncsCallback;
+ const char* const mThreadName;
std::thread mThread;
mutable std::mutex mMutex;
mutable std::condition_variable mCondition;
- // protected by mLock
std::vector<wp<EventThreadConnection>> mDisplayEventConnections GUARDED_BY(mMutex);
- std::queue<DisplayEventReceiver::Event> mPendingEvents GUARDED_BY(mMutex);
- std::array<DisplayEventReceiver::Event, 2> mVSyncEvent GUARDED_BY(mMutex);
- bool mUseSoftwareVSync GUARDED_BY(mMutex) = false;
- bool mVsyncEnabled GUARDED_BY(mMutex) = false;
- bool mKeepRunning GUARDED_BY(mMutex) = true;
+ std::deque<DisplayEventReceiver::Event> mPendingEvents GUARDED_BY(mMutex);
- // for debugging
- bool mDebugVsyncEnabled GUARDED_BY(mMutex) = false;
+ // VSYNC state of connected display.
+ struct VSyncState {
+ explicit VSyncState(uint32_t displayId) : displayId(displayId) {}
+
+ const uint32_t displayId;
+
+ // Number of VSYNC events since display was connected.
+ uint32_t count = 0;
+
+ // True if VSYNC should be faked, e.g. when display is off.
+ bool synthetic = false;
+ };
+
+ // TODO(b/74619554): Create per-display threads waiting on respective VSYNC signals,
+ // and support headless mode by injecting a fake display with synthetic VSYNC.
+ std::optional<VSyncState> mVSyncState GUARDED_BY(mMutex);
+
+ // State machine for event loop.
+ enum class State {
+ Idle,
+ Quit,
+ SyntheticVSync,
+ VSync,
+ };
+
+ State mState GUARDED_BY(mMutex) = State::Idle;
+
+ static const char* toCString(State);
// Callback that resets the idle timer when the next vsync is received.
ResetIdleTimerCallback mResetIdleTimer;
diff --git a/services/surfaceflinger/Scheduler/MessageQueue.cpp b/services/surfaceflinger/Scheduler/MessageQueue.cpp
index 36403cc..75a410b 100644
--- a/services/surfaceflinger/Scheduler/MessageQueue.cpp
+++ b/services/surfaceflinger/Scheduler/MessageQueue.cpp
@@ -85,7 +85,8 @@
mHandler = new Handler(*this);
}
-void MessageQueue::setEventThread(android::EventThread* eventThread) {
+void MessageQueue::setEventThread(android::EventThread* eventThread,
+ ResyncCallback resyncCallback) {
if (mEventThread == eventThread) {
return;
}
@@ -95,7 +96,7 @@
}
mEventThread = eventThread;
- mEvents = eventThread->createEventConnection();
+ mEvents = eventThread->createEventConnection(std::move(resyncCallback));
mEvents->stealReceiveChannel(&mEventTube);
mLooper->addFd(mEventTube.getFd(), 0, Looper::EVENT_INPUT, MessageQueue::cb_eventReceiver,
this);
@@ -148,6 +149,10 @@
mEvents->requestNextVsync();
}
+void MessageQueue::invalidateForHWC() {
+ mEvents->requestNextVsyncForHWC();
+}
+
void MessageQueue::refresh() {
mHandler->dispatchRefresh();
}
diff --git a/services/surfaceflinger/Scheduler/MessageQueue.h b/services/surfaceflinger/Scheduler/MessageQueue.h
index 24a3834..56a00c0 100644
--- a/services/surfaceflinger/Scheduler/MessageQueue.h
+++ b/services/surfaceflinger/Scheduler/MessageQueue.h
@@ -29,12 +29,12 @@
#include <private/gui/BitTube.h>
#include "Barrier.h"
+#include "EventThread.h"
#include <functional>
namespace android {
-class EventThread;
class SurfaceFlinger;
// ---------------------------------------------------------------------------
@@ -86,11 +86,12 @@
virtual void init(const sp<SurfaceFlinger>& flinger) = 0;
// TODO(akrulec): Remove this function once everything is migrated to Scheduler.
- virtual void setEventThread(EventThread* events) = 0;
+ virtual void setEventThread(EventThread* events, ResyncCallback resyncCallback) = 0;
virtual void setEventConnection(const sp<EventThreadConnection>& connection) = 0;
virtual void waitMessage() = 0;
virtual status_t postMessage(const sp<MessageBase>& message, nsecs_t reltime = 0) = 0;
virtual void invalidate() = 0;
+ virtual void invalidateForHWC() = 0;
virtual void refresh() = 0;
};
@@ -126,7 +127,7 @@
public:
~MessageQueue() override = default;
void init(const sp<SurfaceFlinger>& flinger) override;
- void setEventThread(android::EventThread* events) override;
+ void setEventThread(android::EventThread* events, ResyncCallback resyncCallback) override;
void setEventConnection(const sp<EventThreadConnection>& connection) override;
void waitMessage() override;
@@ -134,6 +135,9 @@
// sends INVALIDATE message at next VSYNC
void invalidate() override;
+
+ // sends INVALIDATE message at next VSYNC, without resetting the idle timer in the Scheduler
+ void invalidateForHWC();
// sends REFRESH message at next VSYNC
void refresh() override;
};
diff --git a/services/surfaceflinger/Scheduler/PhaseOffsets.cpp b/services/surfaceflinger/Scheduler/PhaseOffsets.cpp
new file mode 100644
index 0000000..a0a4455
--- /dev/null
+++ b/services/surfaceflinger/Scheduler/PhaseOffsets.cpp
@@ -0,0 +1,117 @@
+/*
+ * 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 "PhaseOffsets.h"
+
+#include <cutils/properties.h>
+
+#include "SurfaceFlingerProperties.h"
+
+namespace android {
+using namespace android::sysprop;
+
+namespace scheduler {
+
+PhaseOffsets::~PhaseOffsets() = default;
+
+namespace impl {
+PhaseOffsets::PhaseOffsets() {
+ int64_t vsyncPhaseOffsetNs = vsync_event_phase_offset_ns(1000000);
+
+ int64_t sfVsyncPhaseOffsetNs = vsync_sf_event_phase_offset_ns(1000000);
+
+ char value[PROPERTY_VALUE_MAX];
+ property_get("debug.sf.early_phase_offset_ns", value, "-1");
+ const int earlySfOffsetNs = atoi(value);
+
+ property_get("debug.sf.early_gl_phase_offset_ns", value, "-1");
+ const int earlyGlSfOffsetNs = atoi(value);
+
+ property_get("debug.sf.early_app_phase_offset_ns", value, "-1");
+ const int earlyAppOffsetNs = atoi(value);
+
+ property_get("debug.sf.early_gl_app_phase_offset_ns", value, "-1");
+ const int earlyGlAppOffsetNs = atoi(value);
+
+ property_get("debug.sf.high_fps_early_phase_offset_ns", value, "-1");
+ const int highFpsEarlySfOffsetNs = atoi(value);
+
+ property_get("debug.sf.high_fps_early_gl_phase_offset_ns", value, "-1");
+ const int highFpsEarlyGlSfOffsetNs = atoi(value);
+
+ property_get("debug.sf.high_fps_early_app_phase_offset_ns", value, "-1");
+ const int highFpsEarlyAppOffsetNs = atoi(value);
+
+ property_get("debug.sf.high_fps_early_gl_app_phase_offset_ns", value, "-1");
+ const int highFpsEarlyGlAppOffsetNs = atoi(value);
+
+ // TODO(b/122905996): Define these in device.mk.
+ property_get("debug.sf.high_fps_late_app_phase_offset_ns", value, "1000000");
+ const int highFpsLateAppOffsetNs = atoi(value);
+
+ property_get("debug.sf.high_fps_late_sf_phase_offset_ns", value, "8000000");
+ const int highFpsLateSfOffsetNs = atoi(value);
+
+ mDefaultRefreshRateOffsets.early = {earlySfOffsetNs != -1 ? earlySfOffsetNs
+ : sfVsyncPhaseOffsetNs,
+ earlyAppOffsetNs != -1 ? earlyAppOffsetNs
+ : vsyncPhaseOffsetNs};
+ mDefaultRefreshRateOffsets.earlyGl = {earlyGlSfOffsetNs != -1 ? earlyGlSfOffsetNs
+ : sfVsyncPhaseOffsetNs,
+ earlyGlAppOffsetNs != -1 ? earlyGlAppOffsetNs
+ : vsyncPhaseOffsetNs};
+ mDefaultRefreshRateOffsets.late = {sfVsyncPhaseOffsetNs, vsyncPhaseOffsetNs};
+
+ mHighRefreshRateOffsets.early = {highFpsEarlySfOffsetNs != -1 ? highFpsEarlySfOffsetNs
+ : highFpsLateAppOffsetNs,
+ highFpsEarlyAppOffsetNs != -1 ? highFpsEarlyAppOffsetNs
+ : highFpsLateSfOffsetNs};
+ mHighRefreshRateOffsets.earlyGl = {highFpsEarlyGlSfOffsetNs != -1 ? highFpsEarlyGlSfOffsetNs
+ : highFpsLateAppOffsetNs,
+ highFpsEarlyGlAppOffsetNs != -1 ? highFpsEarlyGlAppOffsetNs
+ : highFpsLateSfOffsetNs};
+ mHighRefreshRateOffsets.late = {highFpsLateAppOffsetNs, highFpsLateSfOffsetNs};
+}
+
+PhaseOffsets::Offsets PhaseOffsets::getCurrentOffsets() const {
+ switch (mRefreshRateType) {
+ case RefreshRateConfigs::RefreshRateType::PERFORMANCE:
+ return mHighRefreshRateOffsets;
+ default:
+ return mDefaultRefreshRateOffsets;
+ }
+}
+
+void PhaseOffsets::dump(std::string& result) const {
+ const auto [early, earlyGl, late] = getCurrentOffsets();
+ base::StringAppendF(&result,
+ " app phase: %9" PRId64 " ns\t SF phase: %9" PRId64 " ns\n"
+ " early app phase: %9" PRId64 " ns\t early SF phase: %9" PRId64 " ns\n"
+ "GL early app phase: %9" PRId64 " ns\tGL early SF phase: %9" PRId64 " ns\n",
+ late.app, late.sf, early.app, early.sf, earlyGl.app, earlyGl.sf);
+}
+
+nsecs_t PhaseOffsets::getCurrentAppOffset() {
+ return getCurrentOffsets().late.app;
+}
+
+nsecs_t PhaseOffsets::getCurrentSfOffset() {
+ return getCurrentOffsets().late.sf;
+}
+
+} // namespace impl
+} // namespace scheduler
+} // namespace android
diff --git a/services/surfaceflinger/Scheduler/PhaseOffsets.h b/services/surfaceflinger/Scheduler/PhaseOffsets.h
new file mode 100644
index 0000000..cbcaade
--- /dev/null
+++ b/services/surfaceflinger/Scheduler/PhaseOffsets.h
@@ -0,0 +1,83 @@
+/*
+ * 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 <cinttypes>
+
+#include "RefreshRateConfigs.h"
+#include "VSyncModulator.h"
+
+namespace android {
+namespace scheduler {
+
+/*
+ * This class encapsulates offsets for different refresh rates. Depending
+ * on what refresh rate we are using, and wheter we are composing in GL,
+ * different offsets will help us with latency. This class keeps track of
+ * which mode the device is on, and returns approprate offsets when needed.
+ */
+class PhaseOffsets {
+public:
+ struct Offsets {
+ VSyncModulator::Offsets early;
+ VSyncModulator::Offsets earlyGl;
+ VSyncModulator::Offsets late;
+ };
+
+ virtual ~PhaseOffsets();
+
+ virtual nsecs_t getCurrentAppOffset() = 0;
+ virtual nsecs_t getCurrentSfOffset() = 0;
+ virtual Offsets getCurrentOffsets() const = 0;
+ virtual void setRefreshRateType(RefreshRateConfigs::RefreshRateType refreshRateType) = 0;
+ virtual void dump(std::string& result) const = 0;
+};
+
+namespace impl {
+class PhaseOffsets : public scheduler::PhaseOffsets {
+public:
+ PhaseOffsets();
+
+ nsecs_t getCurrentAppOffset() override;
+ nsecs_t getCurrentSfOffset() override;
+
+ // Returns early, early GL, and late offsets for Apps and SF.
+ Offsets getCurrentOffsets() const override;
+
+ // This function should be called when the device is switching between different
+ // refresh rates, to properly update the offsets.
+ void setRefreshRateType(RefreshRateConfigs::RefreshRateType refreshRateType) override {
+ mRefreshRateType = refreshRateType;
+ }
+
+ // Returns current offsets in human friendly format.
+ void dump(std::string& result) const override;
+
+private:
+ Offsets getmDefaultRefreshRateOffsets() { return mDefaultRefreshRateOffsets; }
+ Offsets getmHighRefreshRateOffsets() { return mHighRefreshRateOffsets; }
+
+ std::atomic<RefreshRateConfigs::RefreshRateType> mRefreshRateType =
+ RefreshRateConfigs::RefreshRateType::DEFAULT;
+
+ Offsets mDefaultRefreshRateOffsets;
+ Offsets mHighRefreshRateOffsets;
+};
+} // namespace impl
+
+} // namespace scheduler
+} // namespace android
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
new file mode 100644
index 0000000..026f7c7
--- /dev/null
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
@@ -0,0 +1,115 @@
+/*
+ * 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 <algorithm>
+#include <numeric>
+
+#include "android-base/stringprintf.h"
+
+#include "DisplayHardware/HWComposer.h"
+#include "Scheduler/SchedulerUtils.h"
+
+namespace android {
+namespace scheduler {
+
+/**
+ * This class is used to encapsulate configuration for refresh rates. It holds infomation
+ * about available refresh rates on the device, and the mapping between the numbers and human
+ * readable names.
+ */
+class RefreshRateConfigs {
+public:
+ // Enum to indicate which vsync rate to run at. Power saving is intended to be the lowest
+ // (eg. when the screen is in AOD mode or off), default is the old 60Hz, and performance
+ // is the new 90Hz. Eventually we want to have a way for vendors to map these in the configs.
+ enum class RefreshRateType { POWER_SAVING, DEFAULT, PERFORMANCE };
+
+ struct RefreshRate {
+ // Type of the refresh rate.
+ RefreshRateType type;
+ // This config ID corresponds to the position of the config in the vector that is stored
+ // on the device.
+ int configId;
+ // Human readable name of the refresh rate.
+ std::string name;
+ // Refresh rate in frames per second, rounded to the nearest integer.
+ uint32_t fps = 0;
+ };
+
+ // TODO(b/122916473): Get this information from configs prepared by vendors, instead of
+ // baking them in.
+ explicit RefreshRateConfigs(
+ const std::vector<std::shared_ptr<const HWC2::Display::Config>>& configs) {
+ init(configs);
+ }
+ ~RefreshRateConfigs() = default;
+
+ const std::vector<RefreshRate>& getRefreshRates() { return mRefreshRates; }
+
+private:
+ void init(const std::vector<std::shared_ptr<const HWC2::Display::Config>>& configs) {
+ // This is the rate that HWC encapsulates right now when the device is in DOZE mode.
+ mRefreshRates.push_back(
+ RefreshRate{RefreshRateType::POWER_SAVING, SCREEN_OFF_CONFIG_ID, "ScreenOff", 0});
+
+ if (configs.size() < 1) {
+ ALOGE("Device does not have valid configs. Config size is 0.");
+ return;
+ }
+
+ // Create a map between config index and vsync period. This is all the info we need
+ // from the configs.
+ std::vector<std::pair<int, nsecs_t>> configIdToVsyncPeriod;
+ for (int i = 0; i < configs.size(); ++i) {
+ configIdToVsyncPeriod.emplace_back(i, configs.at(i)->getVsyncPeriod());
+ }
+
+ std::sort(configIdToVsyncPeriod.begin(), configIdToVsyncPeriod.end(),
+ [](const std::pair<int, nsecs_t>& a, const std::pair<int, nsecs_t>& b) {
+ return a.second > b.second;
+ });
+
+ // When the configs are ordered by the resync rate. We assume that the first one is DEFAULT.
+ nsecs_t vsyncPeriod = configIdToVsyncPeriod[0].second;
+ if (vsyncPeriod != 0) {
+ const float fps = 1e9 / vsyncPeriod;
+ mRefreshRates.push_back(
+ RefreshRate{RefreshRateType::DEFAULT, configIdToVsyncPeriod[0].first,
+ base::StringPrintf("%2.ffps", fps), static_cast<uint32_t>(fps)});
+ }
+
+ if (configs.size() < 2) {
+ return;
+ }
+
+ // When the configs are ordered by the resync rate. We assume that the second one is
+ // PERFORMANCE, eg. the higher rate.
+ vsyncPeriod = configIdToVsyncPeriod[1].second;
+ if (vsyncPeriod != 0) {
+ const float fps = 1e9 / vsyncPeriod;
+ mRefreshRates.push_back(
+ RefreshRate{RefreshRateType::PERFORMANCE, configIdToVsyncPeriod[1].first,
+ base::StringPrintf("%2.ffps", fps), static_cast<uint32_t>(fps)});
+ }
+ }
+
+ std::vector<RefreshRate> mRefreshRates;
+};
+
+} // namespace scheduler
+} // namespace android
diff --git a/services/surfaceflinger/Scheduler/RefreshRateStats.h b/services/surfaceflinger/Scheduler/RefreshRateStats.h
new file mode 100644
index 0000000..dcb2988
--- /dev/null
+++ b/services/surfaceflinger/Scheduler/RefreshRateStats.h
@@ -0,0 +1,160 @@
+/*
+ * 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 <numeric>
+
+#include "Scheduler/RefreshRateConfigs.h"
+#include "Scheduler/SchedulerUtils.h"
+#include "TimeStats/TimeStats.h"
+
+#include "android-base/stringprintf.h"
+#include "utils/Timers.h"
+
+namespace android {
+namespace scheduler {
+
+/**
+ * Class to encapsulate statistics about refresh rates that the display is using. When the power
+ * mode is set to HWC_POWER_MODE_NORMAL, SF is switching between refresh rates that are stored in
+ * the device's configs. Otherwise, we assume the HWC is running in power saving mode under the
+ * hood (eg. the device is in DOZE, or screen off mode).
+ */
+class RefreshRateStats {
+ static constexpr int64_t MS_PER_S = 1000;
+ static constexpr int64_t MS_PER_MIN = 60 * MS_PER_S;
+ static constexpr int64_t MS_PER_HOUR = 60 * MS_PER_MIN;
+ static constexpr int64_t MS_PER_DAY = 24 * MS_PER_HOUR;
+
+public:
+ explicit RefreshRateStats(
+ const std::vector<std::shared_ptr<const HWC2::Display::Config>>& configs,
+ const std::shared_ptr<TimeStats>& timeStats)
+ : mRefreshRateConfigs(std::make_unique<RefreshRateConfigs>(configs)),
+ mTimeStats(timeStats),
+ mPreviousRecordedTime(systemTime()) {}
+ ~RefreshRateStats() = default;
+
+ // Sets power mode. We only collect the information when the power mode is not
+ // HWC_POWER_MODE_NORMAL. When power mode is HWC_POWER_MODE_NORMAL, we collect the stats based
+ // on config mode.
+ void setPowerMode(int mode) {
+ if (mCurrentPowerMode == mode) {
+ return;
+ }
+ // If power mode is normal, the time is going to be recorded under config modes.
+ if (mode == HWC_POWER_MODE_NORMAL) {
+ mCurrentPowerMode = mode;
+ return;
+ }
+ flushTime();
+ mCurrentPowerMode = mode;
+ }
+
+ // Sets config mode. If the mode has changed, it records how much time was spent in the previous
+ // mode.
+ void setConfigMode(int mode) {
+ if (mCurrentConfigMode == mode) {
+ return;
+ }
+ flushTime();
+ mCurrentConfigMode = mode;
+ }
+
+ // Returns a map between human readable refresh rate and number of seconds the device spent in
+ // that mode.
+ std::unordered_map<std::string, int64_t> getTotalTimes() {
+ // If the power mode is on, then we are probably switching between the config modes. If
+ // it's not then the screen is probably off. Make sure to flush times before printing
+ // them.
+ flushTime();
+
+ std::unordered_map<std::string, int64_t> totalTime;
+ for (auto config : mRefreshRateConfigs->getRefreshRates()) {
+ int64_t totalTimeForConfig = 0;
+ if (mConfigModesTotalTime.find(config.configId) != mConfigModesTotalTime.end()) {
+ totalTimeForConfig = mConfigModesTotalTime.at(config.configId);
+ }
+ totalTime[config.name] = totalTimeForConfig;
+ }
+ return totalTime;
+ }
+
+ // Traverses through the map of config modes and returns how long they've been running in easy
+ // to read format.
+ std::string doDump() {
+ std::ostringstream stream;
+ stream << "+ Refresh rate: running time in seconds\n";
+ for (auto stats : getTotalTimes()) {
+ stream << stats.first.c_str() << ": " << getDateFormatFromMs(stats.second) << "\n";
+ }
+ return stream.str();
+ }
+
+private:
+ void flushTime() {
+ // Normal power mode is counted under different config modes.
+ if (mCurrentPowerMode == HWC_POWER_MODE_NORMAL) {
+ flushTimeForMode(mCurrentConfigMode);
+ } else {
+ flushTimeForMode(SCREEN_OFF_CONFIG_ID);
+ }
+ }
+
+ // Calculates the time that passed in ms between the last time we recorded time and the time
+ // this method was called.
+ void flushTimeForMode(int mode) {
+ nsecs_t currentTime = systemTime();
+ nsecs_t timeElapsed = currentTime - mPreviousRecordedTime;
+ int64_t timeElapsedMs = ns2ms(timeElapsed);
+ mPreviousRecordedTime = currentTime;
+
+ mConfigModesTotalTime[mode] += timeElapsedMs;
+ for (const auto& config : mRefreshRateConfigs->getRefreshRates()) {
+ if (config.configId == mode) {
+ mTimeStats->recordRefreshRate(config.fps, timeElapsed);
+ }
+ }
+ }
+
+ // Formats the time in milliseconds into easy to read format.
+ static std::string getDateFormatFromMs(int64_t timeMs) {
+ auto [days, dayRemainderMs] = std::div(timeMs, MS_PER_DAY);
+ auto [hours, hourRemainderMs] = std::div(dayRemainderMs, MS_PER_HOUR);
+ auto [mins, minsRemainderMs] = std::div(hourRemainderMs, MS_PER_MIN);
+ auto [sec, secRemainderMs] = std::div(minsRemainderMs, MS_PER_S);
+ return base::StringPrintf("%" PRId64 "d%02" PRId64 ":%02" PRId64 ":%02" PRId64
+ ".%03" PRId64,
+ days, hours, mins, sec, secRemainderMs);
+ }
+
+ // Keeps information about refresh rate configs that device has.
+ std::unique_ptr<RefreshRateConfigs> mRefreshRateConfigs;
+
+ // Aggregate refresh rate statistics for telemetry.
+ std::shared_ptr<TimeStats> mTimeStats;
+
+ int64_t mCurrentConfigMode = 0;
+ int32_t mCurrentPowerMode = HWC_POWER_MODE_OFF;
+
+ std::unordered_map<int /* power mode */, int64_t /* duration in ms */> mConfigModesTotalTime;
+
+ nsecs_t mPreviousRecordedTime;
+};
+
+} // namespace scheduler
+} // namespace android
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index c363ba5..00820f1 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -28,7 +28,6 @@
#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 <gui/ISurfaceComposer.h>
#include <ui/DisplayStatInfo.h>
@@ -42,11 +41,13 @@
#include "IdleTimer.h"
#include "InjectVSyncSource.h"
#include "SchedulerUtils.h"
+#include "SurfaceFlingerProperties.h"
namespace android {
using namespace android::hardware::configstore;
using namespace android::hardware::configstore::V1_0;
+using namespace android::sysprop;
#define RETURN_VALUE_IF_INVALID(value) \
if (handle == nullptr || mConnections.count(handle->id) == 0) return value
@@ -56,11 +57,8 @@
std::atomic<int64_t> Scheduler::sNextId = 0;
Scheduler::Scheduler(impl::EventControlThread::SetVSyncEnabledFunction function)
- : mHasSyncFramework(
- getBool<ISurfaceFlingerConfigs, &ISurfaceFlingerConfigs::hasSyncFramework>(true)),
- mDispSyncPresentTimeOffset(
- getInt64<ISurfaceFlingerConfigs,
- &ISurfaceFlingerConfigs::presentTimeOffsetFromVSyncNs>(0)),
+ : mHasSyncFramework(running_without_sync_framework(true)),
+ mDispSyncPresentTimeOffset(present_time_offset_from_vsync_ns(0)),
mPrimaryHWVsyncEnabled(false),
mHWVsyncAvailable(false) {
// Note: We create a local temporary with the real DispSync implementation
@@ -72,7 +70,7 @@
mEventControlThread = std::make_unique<impl::EventControlThread>(function);
char value[PROPERTY_VALUE_MAX];
- property_get("debug.sf.set_idle_timer_ms", value, "0");
+ property_get("debug.sf.set_idle_timer_ms", value, "30");
mSetIdleTimerMs = atoi(value);
if (mSetIdleTimerMs > 0) {
@@ -86,39 +84,37 @@
Scheduler::~Scheduler() = default;
sp<Scheduler::ConnectionHandle> Scheduler::createConnection(
- const std::string& connectionName, int64_t phaseOffsetNs,
- impl::EventThread::ResyncWithRateLimitCallback resyncCallback,
+ const char* connectionName, int64_t phaseOffsetNs, ResyncCallback resyncCallback,
impl::EventThread::InterceptVSyncsCallback interceptCallback) {
const int64_t id = sNextId++;
ALOGV("Creating a connection handle with ID: %" PRId64 "\n", id);
std::unique_ptr<EventThread> eventThread =
- makeEventThread(connectionName, mPrimaryDispSync.get(), phaseOffsetNs, resyncCallback,
- interceptCallback);
+ makeEventThread(connectionName, mPrimaryDispSync.get(), phaseOffsetNs,
+ std::move(interceptCallback));
auto connection = std::make_unique<Connection>(new ConnectionHandle(id),
- eventThread->createEventConnection(),
+ eventThread->createEventConnection(
+ std::move(resyncCallback)),
std::move(eventThread));
+
mConnections.insert(std::make_pair(id, std::move(connection)));
return mConnections[id]->handle;
}
std::unique_ptr<EventThread> Scheduler::makeEventThread(
- const std::string& connectionName, DispSync* dispSync, int64_t phaseOffsetNs,
- impl::EventThread::ResyncWithRateLimitCallback resyncCallback,
+ const char* connectionName, DispSync* dispSync, int64_t phaseOffsetNs,
impl::EventThread::InterceptVSyncsCallback interceptCallback) {
- const std::string sourceName = connectionName + "Source";
std::unique_ptr<VSyncSource> eventThreadSource =
- std::make_unique<DispSyncSource>(dispSync, phaseOffsetNs, true, sourceName.c_str());
- const std::string threadName = connectionName + "Thread";
- return std::make_unique<impl::EventThread>(std::move(eventThreadSource), resyncCallback,
- interceptCallback, [this] { resetIdleTimer(); },
- threadName.c_str());
+ std::make_unique<DispSyncSource>(dispSync, phaseOffsetNs, true, connectionName);
+ return std::make_unique<impl::EventThread>(std::move(eventThreadSource),
+ std::move(interceptCallback),
+ [this] { resetIdleTimer(); }, connectionName);
}
sp<IDisplayEventConnection> Scheduler::createDisplayEventConnection(
- const sp<Scheduler::ConnectionHandle>& handle) {
+ const sp<Scheduler::ConnectionHandle>& handle, ResyncCallback resyncCallback) {
RETURN_VALUE_IF_INVALID(nullptr);
- return mConnections[handle->id]->thread->createEventConnection();
+ return mConnections[handle->id]->thread->createEventConnection(std::move(resyncCallback));
}
EventThread* Scheduler::getEventThread(const sp<Scheduler::ConnectionHandle>& handle) {
@@ -238,6 +234,16 @@
mLayerHistory.incrementCounter();
}
+void Scheduler::setExpiredIdleTimerCallback(const ExpiredIdleTimerCallback& expiredTimerCallback) {
+ std::lock_guard<std::mutex> lock(mCallbackLock);
+ mExpiredTimerCallback = expiredTimerCallback;
+}
+
+void Scheduler::setResetIdleTimerCallback(const ResetIdleTimerCallback& resetTimerCallback) {
+ std::lock_guard<std::mutex> lock(mCallbackLock);
+ mResetTimerCallback = resetTimerCallback;
+}
+
void Scheduler::updateFrameSkipping(const int64_t skipCount) {
ATRACE_INT("FrameSkipCount", skipCount);
if (mSkipCount != skipCount) {
@@ -314,12 +320,12 @@
// TODO(b/113612090): This are current numbers from trial and error while running videos
// from YouTube at 24, 30, and 60 fps.
if (mean > 14 && mean < 18) {
- ATRACE_INT("FPS", 60);
+ ATRACE_INT("MediaFPS", 60);
} else if (mean > 31 && mean < 34) {
- ATRACE_INT("FPS", 30);
+ ATRACE_INT("MediaFPS", 30);
return;
} else if (mean > 39 && mean < 42) {
- ATRACE_INT("FPS", 24);
+ ATRACE_INT("MediaFPS", 24);
}
}
@@ -328,13 +334,25 @@
mIdleTimer->reset();
ATRACE_INT("ExpiredIdleTimer", 0);
}
+
+ std::lock_guard<std::mutex> lock(mCallbackLock);
+ if (mResetTimerCallback) {
+ mResetTimerCallback();
+ }
}
void Scheduler::expiredTimerCallback() {
- // TODO(b/113612090): Each time a timer expired, we should record the information into
- // a circular buffer. Once this has happened a given amount (TBD) of times, we can comfortably
- // say that the device is sitting in idle.
- ATRACE_INT("ExpiredIdleTimer", 1);
+ std::lock_guard<std::mutex> lock(mCallbackLock);
+ if (mExpiredTimerCallback) {
+ mExpiredTimerCallback();
+ ATRACE_INT("ExpiredIdleTimer", 1);
+ }
+}
+
+std::string Scheduler::doDump() {
+ std::ostringstream stream;
+ stream << "+ Idle timer interval: " << mSetIdleTimerMs << " ms" << std::endl;
+ return stream.str();
}
} // namespace android
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index 9d7dd4d..b717605 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -36,6 +36,9 @@
class Scheduler {
public:
+ using ExpiredIdleTimerCallback = std::function<void()>;
+ using ResetIdleTimerCallback = std::function<void()>;
+
// Enum to indicate whether to start the transaction early, or at vsync time.
enum class TransactionStart { EARLY, NORMAL };
@@ -70,11 +73,11 @@
/** Creates an EventThread connection. */
sp<ConnectionHandle> createConnection(
- const std::string& connectionName, int64_t phaseOffsetNs,
- impl::EventThread::ResyncWithRateLimitCallback resyncCallback,
+ const char* connectionName, int64_t phaseOffsetNs, ResyncCallback resyncCallback,
impl::EventThread::InterceptVSyncsCallback interceptCallback);
- sp<IDisplayEventConnection> createDisplayEventConnection(const sp<ConnectionHandle>& handle);
+ sp<IDisplayEventConnection> createDisplayEventConnection(const sp<ConnectionHandle>& handle,
+ ResyncCallback resyncCallback);
// Getter methods.
EventThread* getEventThread(const sp<ConnectionHandle>& handle);
@@ -111,11 +114,16 @@
const std::string layerName);
// Increments counter in the layer history to indicate that SF has started a new frame.
void incrementFrameCounter();
+ // Callback that gets invoked once the idle timer expires.
+ void setExpiredIdleTimerCallback(const ExpiredIdleTimerCallback& expiredTimerCallback);
+ // Callback that gets invoked once the idle timer is reset.
+ void setResetIdleTimerCallback(const ResetIdleTimerCallback& resetTimerCallback);
+ // Returns relevant information about Scheduler for dumpsys purposes.
+ std::string doDump();
protected:
virtual std::unique_ptr<EventThread> makeEventThread(
- const std::string& connectionName, DispSync* dispSync, int64_t phaseOffsetNs,
- impl::EventThread::ResyncWithRateLimitCallback resyncCallback,
+ const char* connectionName, DispSync* dispSync, int64_t phaseOffsetNs,
impl::EventThread::InterceptVSyncsCallback interceptCallback);
private:
@@ -141,7 +149,7 @@
// The offset in nanoseconds to use, when DispSync timestamps present fence
// signaling time.
- const nsecs_t mDispSyncPresentTimeOffset;
+ nsecs_t mDispSyncPresentTimeOffset;
// Each connection has it's own ID. This variable keeps track of the count.
static std::atomic<int64_t> sNextId;
@@ -173,6 +181,10 @@
// interval, a callback is fired. Set this variable to >0 to use this feature.
int64_t mSetIdleTimerMs = 0;
std::unique_ptr<scheduler::IdleTimer> mIdleTimer;
+
+ std::mutex mCallbackLock;
+ ExpiredIdleTimerCallback mExpiredTimerCallback GUARDED_BY(mCallbackLock);
+ ResetIdleTimerCallback mResetTimerCallback GUARDED_BY(mCallbackLock);
};
} // namespace android
diff --git a/services/surfaceflinger/Scheduler/SchedulerUtils.h b/services/surfaceflinger/Scheduler/SchedulerUtils.h
index 17c57db..edd23de 100644
--- a/services/surfaceflinger/Scheduler/SchedulerUtils.h
+++ b/services/surfaceflinger/Scheduler/SchedulerUtils.h
@@ -26,6 +26,11 @@
// about layers.
static constexpr size_t ARRAY_SIZE = 30;
+// This number is used to have a place holder for when the screen is not NORMAL/ON. Currently
+// the config is not visible to SF, and is completely maintained by HWC. However, we would
+// still like to keep track of time when the device is in this config.
+static constexpr int SCREEN_OFF_CONFIG_ID = -1;
+
// Calculates the statistical mean (average) in the data structure (array, vector). The
// function does not modify the contents of the array.
template <typename T>
diff --git a/services/surfaceflinger/Scheduler/VSyncModulator.h b/services/surfaceflinger/Scheduler/VSyncModulator.h
index dde0c57..d7ec733 100644
--- a/services/surfaceflinger/Scheduler/VSyncModulator.h
+++ b/services/surfaceflinger/Scheduler/VSyncModulator.h
@@ -18,9 +18,10 @@
#include <utils/Errors.h>
+#include <cinttypes>
#include <mutex>
-using namespace android::surfaceflinger;
+#include "Scheduler.h"
namespace android {
diff --git a/services/surfaceflinger/StartPropertySetThread.h b/services/surfaceflinger/StartPropertySetThread.h
index a64c21b..bbdcde2 100644
--- a/services/surfaceflinger/StartPropertySetThread.h
+++ b/services/surfaceflinger/StartPropertySetThread.h
@@ -33,7 +33,7 @@
// Any property_set() will block during init stage so need to be offloaded
// to this thread. see b/63844978.
public:
- StartPropertySetThread(bool timestampPropertyValue);
+ explicit StartPropertySetThread(bool timestampPropertyValue);
status_t Start();
private:
virtual bool threadLoop();
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 02cd9d9..d54a1d5 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -17,16 +17,18 @@
// #define LOG_NDEBUG 0
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
-#include <stdint.h>
#include <sys/types.h>
-#include <algorithm>
#include <errno.h>
-#include <math.h>
-#include <mutex>
#include <dlfcn.h>
-#include <inttypes.h>
-#include <stdatomic.h>
+
+#include <algorithm>
+#include <cinttypes>
+#include <cmath>
+#include <cstdint>
+#include <functional>
+#include <mutex>
#include <optional>
+#include <unordered_map>
#include <cutils/properties.h>
#include <log/log.h>
@@ -35,32 +37,36 @@
#include <binder/IServiceManager.h>
#include <binder/PermissionCache.h>
+#include <compositionengine/CompositionEngine.h>
+#include <compositionengine/Display.h>
+#include <compositionengine/DisplayColorProfile.h>
+#include <compositionengine/Layer.h>
+#include <compositionengine/OutputLayer.h>
+#include <compositionengine/RenderSurface.h>
+#include <compositionengine/impl/OutputCompositionState.h>
#include <dvr/vr_flinger.h>
-
-#include <input/IInputFlinger.h>
-
-#include <ui/ColorSpace.h>
-#include <ui/DebugUtils.h>
-#include <ui/DisplayInfo.h>
-#include <ui/DisplayStatInfo.h>
-
#include <gui/BufferQueue.h>
#include <gui/GuiConfig.h>
#include <gui/IDisplayEventConnection.h>
#include <gui/IProducerListener.h>
#include <gui/LayerDebugInfo.h>
#include <gui/Surface.h>
+#include <input/IInputFlinger.h>
#include <renderengine/RenderEngine.h>
+#include <ui/ColorSpace.h>
+#include <ui/DebugUtils.h>
+#include <ui/DisplayInfo.h>
+#include <ui/DisplayStatInfo.h>
#include <ui/GraphicBufferAllocator.h>
#include <ui/PixelFormat.h>
#include <ui/UiConfig.h>
-
-#include <utils/misc.h>
-#include <utils/String8.h>
-#include <utils/String16.h>
+#include <utils/CallStack.h>
#include <utils/StopWatch.h>
+#include <utils/String16.h>
+#include <utils/String8.h>
#include <utils/Timers.h>
#include <utils/Trace.h>
+#include <utils/misc.h>
#include <private/android_filesystem_config.h>
#include <private/gui/SyncFeatures.h>
@@ -72,7 +78,6 @@
#include "ColorLayer.h"
#include "Colorizer.h"
#include "ContainerLayer.h"
-#include "DdmConnection.h"
#include "DisplayDevice.h"
#include "Layer.h"
#include "LayerVector.h"
@@ -108,14 +113,17 @@
#include <configstore/Utils.h>
#include <layerproto/LayerProtoParser.h>
+#include "SurfaceFlingerProperties.h"
namespace android {
using namespace android::hardware::configstore;
using namespace android::hardware::configstore::V1_0;
+using namespace android::sysprop;
using base::StringAppendF;
using ui::ColorMode;
using ui::Dataspace;
+using ui::DisplayPrimaries;
using ui::Hdr;
using ui::RenderIntent;
@@ -190,9 +198,20 @@
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;
+
// ---------------------------------------------------------------------------
-int64_t SurfaceFlinger::vsyncPhaseOffsetNs;
-int64_t SurfaceFlinger::sfVsyncPhaseOffsetNs;
int64_t SurfaceFlinger::dispSyncPresentTimeOffset;
bool SurfaceFlinger::useHwcForRgbToYuv;
uint64_t SurfaceFlinger::maxVirtualDisplaySize;
@@ -238,7 +257,6 @@
SurfaceFlingerBE::SurfaceFlingerBE()
: mHwcServiceName(getHwcServiceName()),
- mRenderEngine(nullptr),
mFrameBuckets(),
mTotalTime(0),
mLastSwapTime(0),
@@ -254,12 +272,12 @@
mLayersRemoved(false),
mLayersAdded(false),
mBootTime(systemTime()),
+ mPhaseOffsets{getFactory().createPhaseOffsets()},
mVisibleRegionsDirty(false),
mGeometryInvalid(false),
mAnimCompositionPending(false),
mBootStage(BootStage::BOOTLOADER),
mDebugRegion(0),
- mDebugDDMS(0),
mDebugDisableHWC(0),
mDebugDisableTransformHint(0),
mDebugInTransaction(0),
@@ -272,73 +290,53 @@
mHasPoweredOff(false),
mNumLayers(0),
mVrFlingerRequestsDisplay(false),
- mMainThreadId(std::this_thread::get_id()) {}
+ mMainThreadId(std::this_thread::get_id()),
+ mCompositionEngine{getFactory().createCompositionEngine()} {}
SurfaceFlinger::SurfaceFlinger(surfaceflinger::Factory& factory)
: SurfaceFlinger(factory, SkipInitialization) {
ALOGI("SurfaceFlinger is starting");
- vsyncPhaseOffsetNs = getInt64< ISurfaceFlingerConfigs,
- &ISurfaceFlingerConfigs::vsyncEventPhaseOffsetNs>(1000000);
+ hasSyncFramework = running_without_sync_framework(true);
- sfVsyncPhaseOffsetNs = getInt64< ISurfaceFlingerConfigs,
- &ISurfaceFlingerConfigs::vsyncSfEventPhaseOffsetNs>(1000000);
+ dispSyncPresentTimeOffset = present_time_offset_from_vsync_ns(0);
- hasSyncFramework = getBool< ISurfaceFlingerConfigs,
- &ISurfaceFlingerConfigs::hasSyncFramework>(true);
+ useHwcForRgbToYuv = force_hwc_copy_for_virtual_displays(false);
- dispSyncPresentTimeOffset = getInt64< ISurfaceFlingerConfigs,
- &ISurfaceFlingerConfigs::presentTimeOffsetFromVSyncNs>(0);
-
- useHwcForRgbToYuv = getBool< ISurfaceFlingerConfigs,
- &ISurfaceFlingerConfigs::useHwcForRGBtoYUV>(false);
-
- maxVirtualDisplaySize = getUInt64<ISurfaceFlingerConfigs,
- &ISurfaceFlingerConfigs::maxVirtualDisplaySize>(0);
+ maxVirtualDisplaySize = max_virtual_display_dimension(0);
// Vr flinger is only enabled on Daydream ready devices.
- useVrFlinger = getBool< ISurfaceFlingerConfigs,
- &ISurfaceFlingerConfigs::useVrFlinger>(false);
+ useVrFlinger = use_vr_flinger(false);
- maxFrameBufferAcquiredBuffers = getInt64< ISurfaceFlingerConfigs,
- &ISurfaceFlingerConfigs::maxFrameBufferAcquiredBuffers>(2);
+ maxFrameBufferAcquiredBuffers = max_frame_buffer_acquired_buffers(2);
- hasWideColorDisplay =
- getBool<ISurfaceFlingerConfigs, &ISurfaceFlingerConfigs::hasWideColorDisplay>(false);
- useColorManagement =
- getBool<V1_2::ISurfaceFlingerConfigs,
- &V1_2::ISurfaceFlingerConfigs::useColorManagement>(false);
+ hasWideColorDisplay = has_wide_color_display(false);
- auto surfaceFlingerConfigsServiceV1_2 = V1_2::ISurfaceFlingerConfigs::getService();
- if (surfaceFlingerConfigsServiceV1_2) {
- surfaceFlingerConfigsServiceV1_2->getCompositionPreference(
- [&](auto tmpDefaultDataspace, auto tmpDefaultPixelFormat,
- auto tmpWideColorGamutDataspace, auto tmpWideColorGamutPixelFormat) {
- defaultCompositionDataspace = tmpDefaultDataspace;
- defaultCompositionPixelFormat = tmpDefaultPixelFormat;
- wideColorGamutCompositionDataspace = tmpWideColorGamutDataspace;
- wideColorGamutCompositionPixelFormat = tmpWideColorGamutPixelFormat;
- });
- }
- mDefaultCompositionDataspace = defaultCompositionDataspace;
- mWideColorGamutCompositionDataspace = wideColorGamutCompositionDataspace;
+ useColorManagement = use_color_management(false);
- useContextPriority = getBool<ISurfaceFlingerConfigs,
- &ISurfaceFlingerConfigs::useContextPriority>(true);
+ mDefaultCompositionDataspace =
+ static_cast<ui::Dataspace>(default_composition_dataspace(Dataspace::V0_SRGB));
+ mWideColorGamutCompositionDataspace =
+ static_cast<ui::Dataspace>(wcg_composition_dataspace(Dataspace::V0_SRGB));
+ defaultCompositionDataspace = mDefaultCompositionDataspace;
+ wideColorGamutCompositionDataspace = mWideColorGamutCompositionDataspace;
+ defaultCompositionPixelFormat = static_cast<ui::PixelFormat>(
+ default_composition_pixel_format(ui::PixelFormat::RGBA_8888));
+ wideColorGamutCompositionPixelFormat =
+ static_cast<ui::PixelFormat>(wcg_composition_pixel_format(ui::PixelFormat::RGBA_8888));
- V1_1::DisplayOrientation primaryDisplayOrientation =
- getDisplayOrientation<V1_1::ISurfaceFlingerConfigs,
- &V1_1::ISurfaceFlingerConfigs::primaryDisplayOrientation>(
- V1_1::DisplayOrientation::ORIENTATION_0);
+ useContextPriority = use_context_priority(true);
- switch (primaryDisplayOrientation) {
- case V1_1::DisplayOrientation::ORIENTATION_90:
+ auto tmpPrimaryDisplayOrientation = primary_display_orientation(
+ SurfaceFlingerProperties::primary_display_orientation_values::ORIENTATION_0);
+ switch (tmpPrimaryDisplayOrientation) {
+ case SurfaceFlingerProperties::primary_display_orientation_values::ORIENTATION_90:
SurfaceFlinger::primaryDisplayOrientation = DisplayState::eOrientation90;
break;
- case V1_1::DisplayOrientation::ORIENTATION_180:
+ case SurfaceFlingerProperties::primary_display_orientation_values::ORIENTATION_180:
SurfaceFlinger::primaryDisplayOrientation = DisplayState::eOrientation180;
break;
- case V1_1::DisplayOrientation::ORIENTATION_270:
+ case SurfaceFlingerProperties::primary_display_orientation_values::ORIENTATION_270:
SurfaceFlinger::primaryDisplayOrientation = DisplayState::eOrientation270;
break;
default:
@@ -351,6 +349,16 @@
getFactory().createDispSync("PrimaryDispSync", SurfaceFlinger::hasSyncFramework,
SurfaceFlinger::dispSyncPresentTimeOffset);
+ auto surfaceFlingerConfigsServiceV1_2 = V1_2::ISurfaceFlingerConfigs::getService();
+ if (surfaceFlingerConfigsServiceV1_2) {
+ surfaceFlingerConfigsServiceV1_2->getDisplayNativePrimaries(
+ [&](auto tmpPrimaries) {
+ memcpy(&mInternalDisplayPrimaries, &tmpPrimaries, sizeof(ui::DisplayPrimaries));
+ });
+ } else {
+ initDefaultDisplayNativePrimaries();
+ }
+
// debugging stuff...
char value[PROPERTY_VALUE_MAX];
@@ -360,16 +368,12 @@
property_get("debug.sf.showupdates", value, "0");
mDebugRegion = atoi(value);
- property_get("debug.sf.ddms", value, "0");
- mDebugDDMS = atoi(value);
- if (mDebugDDMS) {
- if (!startDdmConnection()) {
- // start failed, and DDMS debugging not enabled
- mDebugDDMS = 0;
- }
- }
ALOGI_IF(mDebugRegion, "showupdates enabled");
- ALOGI_IF(mDebugDDMS, "DDMS debugging enabled");
+
+ // DDMS debugging deprecated (b/120782499)
+ property_get("debug.sf.ddms", value, "0");
+ int debugDdms = atoi(value);
+ ALOGI_IF(debugDdms, "DDMS debugging not supported");
property_get("debug.sf.disable_backpressure", value, "0");
mPropagateBackpressure = !atoi(value);
@@ -387,29 +391,11 @@
auto listSize = property_get_int32("debug.sf.max_igbp_list_size", int32_t(defaultListSize));
mMaxGraphicBufferProducerListSize = (listSize > 0) ? size_t(listSize) : defaultListSize;
- property_get("debug.sf.early_phase_offset_ns", value, "-1");
- const int earlySfOffsetNs = atoi(value);
-
- property_get("debug.sf.early_gl_phase_offset_ns", value, "-1");
- const int earlyGlSfOffsetNs = atoi(value);
-
- property_get("debug.sf.early_app_phase_offset_ns", value, "-1");
- const int earlyAppOffsetNs = atoi(value);
-
- property_get("debug.sf.early_gl_app_phase_offset_ns", value, "-1");
- const int earlyGlAppOffsetNs = atoi(value);
-
property_get("debug.sf.use_scheduler", value, "0");
mUseScheduler = atoi(value);
- const VSyncModulator::Offsets earlyOffsets =
- {earlySfOffsetNs != -1 ? earlySfOffsetNs : sfVsyncPhaseOffsetNs,
- earlyAppOffsetNs != -1 ? earlyAppOffsetNs : vsyncPhaseOffsetNs};
- const VSyncModulator::Offsets earlyGlOffsets =
- {earlyGlSfOffsetNs != -1 ? earlyGlSfOffsetNs : sfVsyncPhaseOffsetNs,
- earlyGlAppOffsetNs != -1 ? earlyGlAppOffsetNs : vsyncPhaseOffsetNs};
- mVsyncModulator.setPhaseOffsets(earlyOffsets, earlyGlOffsets,
- {sfVsyncPhaseOffsetNs, vsyncPhaseOffsetNs});
+ const auto [early, gl, late] = mPhaseOffsets->getCurrentOffsets();
+ mVsyncModulator.setPhaseOffsets(early, gl, late);
// We should be reading 'persist.sys.sf.color_saturation' here
// but since /data may be encrypted, we need to wait until after vold
@@ -458,19 +444,6 @@
return initClient(new Client(this));
}
-sp<ISurfaceComposerClient> SurfaceFlinger::createScopedConnection(
- const sp<IGraphicBufferProducer>& gbp) {
- if (authenticateSurfaceTexture(gbp) == false) {
- return nullptr;
- }
- const auto& layer = (static_cast<MonitoredProducer*>(gbp.get()))->getLayer();
- if (layer == nullptr) {
- return nullptr;
- }
-
- return initClient(new Client(this, layer));
-}
-
sp<IBinder> SurfaceFlinger::createDisplay(const String8& displayName,
bool secure)
{
@@ -544,6 +517,18 @@
return NO_ERROR;
}
+HWComposer& SurfaceFlinger::getHwComposer() const {
+ return mCompositionEngine->getHwComposer();
+}
+
+renderengine::RenderEngine& SurfaceFlinger::getRenderEngine() const {
+ return mCompositionEngine->getRenderEngine();
+}
+
+compositionengine::CompositionEngine& SurfaceFlinger::getCompositionEngine() const {
+ return *mCompositionEngine.get();
+}
+
void SurfaceFlinger::bootFinished()
{
if (mStartPropertySetThread->join() != NO_ERROR) {
@@ -617,24 +602,29 @@
ALOGI( "SurfaceFlinger's main thread ready to run. "
"Initializing graphics H/W...");
- ALOGI("Phase offest NS: %" PRId64 "", vsyncPhaseOffsetNs);
+ ALOGI("Phase offset NS: %" PRId64 "", mPhaseOffsets->getCurrentAppOffset());
Mutex::Autolock _l(mStateLock);
+ auto resyncCallback = makeResyncCallback(std::bind(&SurfaceFlinger::getVsyncPeriod, this));
+
// start the EventThread
if (mUseScheduler) {
mScheduler = getFactory().createScheduler([this](bool enabled) {
setVsyncEnabled(EventThread::DisplayType::Primary, enabled);
});
+ // TODO(b/113612090): Currently we assume that if scheduler is turned on, then the refresh
+ // rate is 90. Once b/122905403 is completed, this should be updated accordingly.
+ mPhaseOffsets->setRefreshRateType(
+ scheduler::RefreshRateConfigs::RefreshRateType::PERFORMANCE);
mAppConnectionHandle =
- mScheduler->createConnection("appConnection", SurfaceFlinger::vsyncPhaseOffsetNs,
- [this] { resyncWithRateLimit(); },
+ mScheduler->createConnection("appConnection", mPhaseOffsets->getCurrentAppOffset(),
+ resyncCallback,
impl::EventThread::InterceptVSyncsCallback());
mSfConnectionHandle =
- mScheduler->createConnection("sfConnection", SurfaceFlinger::sfVsyncPhaseOffsetNs,
- [this] { resyncWithRateLimit(); },
- [this](nsecs_t timestamp) {
+ mScheduler->createConnection("sfConnection", mPhaseOffsets->getCurrentSfOffset(),
+ resyncCallback, [this](nsecs_t timestamp) {
mInterceptor->saveVSyncEvent(timestamp);
});
@@ -644,24 +634,22 @@
} else {
mEventThreadSource =
std::make_unique<DispSyncSource>(mPrimaryDispSync.get(),
- SurfaceFlinger::vsyncPhaseOffsetNs, true, "app");
+ mPhaseOffsets->getCurrentAppOffset(), true, "app");
mEventThread =
std::make_unique<impl::EventThread>(mEventThreadSource.get(),
- [this] { resyncWithRateLimit(); },
impl::EventThread::InterceptVSyncsCallback(),
"appEventThread");
mSfEventThreadSource =
std::make_unique<DispSyncSource>(mPrimaryDispSync.get(),
- SurfaceFlinger::sfVsyncPhaseOffsetNs, true, "sf");
+ mPhaseOffsets->getCurrentSfOffset(), true, "sf");
mSFEventThread =
std::make_unique<impl::EventThread>(mSfEventThreadSource.get(),
- [this] { resyncWithRateLimit(); },
[this](nsecs_t timestamp) {
mInterceptor->saveVSyncEvent(timestamp);
},
"sfEventThread");
- mEventQueue->setEventThread(mSFEventThread.get());
+ mEventQueue->setEventThread(mSFEventThread.get(), std::move(resyncCallback));
mVsyncModulator.setEventThreads(mSFEventThread.get(), mEventThread.get());
}
@@ -673,15 +661,14 @@
renderengine::RenderEngine::USE_HIGH_PRIORITY_CONTEXT : 0);
// TODO(b/77156734): We need to stop casting and use HAL types when possible.
- getBE().mRenderEngine =
+ mCompositionEngine->setRenderEngine(
renderengine::RenderEngine::create(static_cast<int32_t>(defaultCompositionPixelFormat),
- renderEngineFeature);
- LOG_ALWAYS_FATAL_IF(getBE().mRenderEngine == nullptr, "couldn't create RenderEngine");
+ renderEngineFeature));
LOG_ALWAYS_FATAL_IF(mVrFlingerRequestsDisplay,
"Starting with vr flinger active is not currently supported.");
- getBE().mHwc = getFactory().createHWComposer(getBE().mHwcServiceName);
- getBE().mHwc->registerCallback(this, getBE().mComposerSequenceId);
+ mCompositionEngine->setHwComposer(getFactory().createHWComposer(getBE().mHwcServiceName));
+ mCompositionEngine->getHwComposer().registerCallback(this, getBE().mComposerSequenceId);
// Process any initial hotplug and resulting display changes.
processDisplayHotplugEventsLocked();
const auto display = getDefaultDisplayDeviceLocked();
@@ -722,7 +709,7 @@
// set initial conditions (e.g. unblank default device)
initializeDisplays();
- getBE().mRenderEngine->primeCache();
+ getRenderEngine().primeCache();
// Inform native graphics APIs whether the present timestamp is supported:
@@ -734,6 +721,27 @@
ALOGE("Run StartPropertySetThread failed!");
}
+ if (mUseScheduler) {
+ mScheduler->setExpiredIdleTimerCallback([this]() {
+ mPhaseOffsets->setRefreshRateType(
+ scheduler::RefreshRateConfigs::RefreshRateType::DEFAULT);
+ const auto [early, gl, late] = mPhaseOffsets->getCurrentOffsets();
+ mVsyncModulator.setPhaseOffsets(early, gl, late);
+ setRefreshRateTo(60.f /* fps */);
+ });
+ mScheduler->setResetIdleTimerCallback([this]() {
+ mPhaseOffsets->setRefreshRateType(
+ scheduler::RefreshRateConfigs::RefreshRateType::PERFORMANCE);
+ const auto [early, gl, late] = mPhaseOffsets->getCurrentOffsets();
+ mVsyncModulator.setPhaseOffsets(early, gl, late);
+ setRefreshRateTo(90.f /* fps */);
+ });
+ mRefreshRateStats =
+ std::make_unique<scheduler::RefreshRateStats>(getHwComposer().getConfigs(
+ *display->getId()),
+ mTimeStats);
+ }
+
ALOGV("Done initializing");
}
@@ -762,11 +770,11 @@
}
size_t SurfaceFlinger::getMaxTextureSize() const {
- return getBE().mRenderEngine->getMaxTextureSize();
+ return getRenderEngine().getMaxTextureSize();
}
size_t SurfaceFlinger::getMaxViewportDims() const {
- return getBE().mRenderEngine->getMaxViewportDims();
+ return getRenderEngine().getMaxViewportDims();
}
// ----------------------------------------------------------------------------
@@ -884,7 +892,7 @@
info.xdpi = xdpi;
info.ydpi = ydpi;
info.fps = 1e9 / hwConfig->getVsyncPeriod();
- info.appVsyncOffset = vsyncPhaseOffsetNs;
+ info.appVsyncOffset = mPhaseOffsets->getCurrentAppOffset();
// This is how far in advance a buffer must be queued for
// presentation at a given time. If you want a buffer to appear
@@ -898,8 +906,8 @@
//
// We add an additional 1ms to allow for processing time and
// differences between the ideal and actual refresh rate.
- info.presentationDeadline = hwConfig->getVsyncPeriod() -
- sfVsyncPhaseOffsetNs + 1000000;
+ info.presentationDeadline =
+ hwConfig->getVsyncPeriod() - mPhaseOffsets->getCurrentSfOffset() + 1000000;
// All non-virtual displays are currently considered secure.
info.secure = true;
@@ -939,45 +947,61 @@
return display->getActiveConfig();
}
-void SurfaceFlinger::setActiveConfigInternal(const sp<DisplayDevice>& display, int mode) {
+status_t SurfaceFlinger::setActiveConfigAsync(const sp<IBinder>& displayToken, int mode) {
+ ATRACE_NAME("setActiveConfigAsync");
+ postMessageAsync(new LambdaMessage(
+ [=]() NO_THREAD_SAFETY_ANALYSIS { setActiveConfigInternal(displayToken, mode); }));
+ return NO_ERROR;
+}
+
+status_t SurfaceFlinger::setActiveConfig(const sp<IBinder>& displayToken, int mode) {
+ ATRACE_NAME("setActiveConfigSync");
+ postMessageSync(new LambdaMessage(
+ [&]() NO_THREAD_SAFETY_ANALYSIS { setActiveConfigInternal(displayToken, mode); }));
+ return NO_ERROR;
+}
+
+void SurfaceFlinger::setActiveConfigInternal(const sp<IBinder>& displayToken, int mode) {
+ Vector<DisplayInfo> configs;
+ getDisplayConfigs(displayToken, &configs);
+ if (mode < 0 || mode >= static_cast<int>(configs.size())) {
+ ALOGE("Attempt to set active config %d for display with %zu configs", mode, configs.size());
+ return;
+ }
+
+ const auto display = getDisplayDevice(displayToken);
+ if (!display) {
+ ALOGE("Attempt to set active config %d for invalid display token %p", mode,
+ displayToken.get());
+ return;
+ }
if (display->isVirtual()) {
- ALOGE("%s: Invalid operation on virtual display", __FUNCTION__);
+ ALOGW("Attempt to set active config %d for virtual display", mode);
+ return;
+ }
+ int currentDisplayPowerMode = display->getPowerMode();
+ if (currentDisplayPowerMode != HWC_POWER_MODE_NORMAL) {
+ // Don't change active config when in AoD.
return;
}
int currentMode = display->getActiveConfig();
if (mode == currentMode) {
+ // Don't update config if we are already running in the desired mode.
return;
}
+ if (mUseScheduler) {
+ mRefreshRateStats->setConfigMode(mode);
+ }
const auto displayId = display->getId();
LOG_ALWAYS_FATAL_IF(!displayId);
display->setActiveConfig(mode);
getHwComposer().setActiveConfig(*displayId, mode);
-}
-status_t SurfaceFlinger::setActiveConfig(const sp<IBinder>& displayToken, int mode) {
- postMessageSync(new LambdaMessage([&] {
- Vector<DisplayInfo> configs;
- getDisplayConfigs(displayToken, &configs);
- if (mode < 0 || mode >= static_cast<int>(configs.size())) {
- ALOGE("Attempt to set active config %d for display with %zu configs", mode,
- configs.size());
- return;
- }
- const auto display = getDisplayDevice(displayToken);
- if (!display) {
- ALOGE("Attempt to set active config %d for invalid display token %p", mode,
- displayToken.get());
- } else if (display->isVirtual()) {
- ALOGW("Attempt to set active config %d for virtual display", mode);
- } else {
- setActiveConfigInternal(display, mode);
- }
- }));
-
- return NO_ERROR;
+ ATRACE_INT("ActiveConfigMode", mode);
+ resyncToHardwareVsync(true, getVsyncPeriod());
}
status_t SurfaceFlinger::getDisplayColorModes(const sp<IBinder>& displayToken,
@@ -1003,40 +1027,26 @@
return NO_ERROR;
}
-ColorMode SurfaceFlinger::getActiveColorMode(const sp<IBinder>& displayToken) {
- if (const auto display = getDisplayDevice(displayToken)) {
- return display->getActiveColorMode();
+status_t SurfaceFlinger::getDisplayNativePrimaries(const sp<IBinder>& displayToken,
+ ui::DisplayPrimaries &primaries) {
+ if (!displayToken) {
+ return BAD_VALUE;
}
- return static_cast<ColorMode>(BAD_VALUE);
+
+ // Currently we only support this API for a single internal display.
+ if (getInternalDisplayToken() != displayToken) {
+ return BAD_VALUE;
+ }
+
+ memcpy(&primaries, &mInternalDisplayPrimaries, sizeof(ui::DisplayPrimaries));
+ return NO_ERROR;
}
-void SurfaceFlinger::setActiveColorModeInternal(const sp<DisplayDevice>& display, ColorMode mode,
- Dataspace dataSpace, RenderIntent renderIntent) {
- if (display->isVirtual()) {
- ALOGE("%s: Invalid operation on virtual display", __FUNCTION__);
- return;
+ColorMode SurfaceFlinger::getActiveColorMode(const sp<IBinder>& displayToken) {
+ if (const auto display = getDisplayDevice(displayToken)) {
+ return display->getCompositionDisplay()->getState().colorMode;
}
-
- ColorMode currentMode = display->getActiveColorMode();
- Dataspace currentDataSpace = display->getCompositionDataSpace();
- RenderIntent currentRenderIntent = display->getActiveRenderIntent();
-
- if (mode == currentMode && dataSpace == currentDataSpace &&
- renderIntent == currentRenderIntent) {
- return;
- }
-
- display->setActiveColorMode(mode);
- display->setCompositionDataSpace(dataSpace);
- display->setActiveRenderIntent(renderIntent);
-
- const auto displayId = display->getId();
- LOG_ALWAYS_FATAL_IF(!displayId);
- getHwComposer().setActiveColorMode(*displayId, mode, renderIntent);
-
- ALOGV("Set active color mode: %s (%d), active render intent: %s (%d), display=%s",
- decodeColorMode(mode).c_str(), mode, decodeRenderIntent(renderIntent).c_str(),
- renderIntent, to_string(*displayId).c_str());
+ return static_cast<ColorMode>(BAD_VALUE);
}
status_t SurfaceFlinger::setActiveColorMode(const sp<IBinder>& displayToken, ColorMode mode) {
@@ -1057,8 +1067,8 @@
ALOGW("Attempt to set active color mode %s (%d) for virtual display",
decodeColorMode(mode).c_str(), mode);
} else {
- setActiveColorModeInternal(display, mode, Dataspace::UNKNOWN,
- RenderIntent::COLORIMETRIC);
+ display->getCompositionDisplay()->setColorMode(mode, Dataspace::UNKNOWN,
+ RenderIntent::COLORIMETRIC);
}
}));
@@ -1141,6 +1151,28 @@
outStats);
}
+status_t SurfaceFlinger::getProtectedContentSupport(bool* outSupported) const {
+ if (!outSupported) {
+ return BAD_VALUE;
+ }
+ *outSupported = getRenderEngine().supportsProtectedContent();
+ return NO_ERROR;
+}
+
+status_t SurfaceFlinger::isWideColorDisplay(const sp<IBinder>& displayToken,
+ bool* outIsWideColorDisplay) const {
+ if (!displayToken || !outIsWideColorDisplay) {
+ return BAD_VALUE;
+ }
+ Mutex::Autolock _l(mStateLock);
+ const auto display = getDisplayDeviceLocked(displayToken);
+ if (!display) {
+ return BAD_VALUE;
+ }
+ *outIsWideColorDisplay = display->hasWideColorGamut();
+ return NO_ERROR;
+}
+
status_t SurfaceFlinger::enableVSyncInjections(bool enable) {
postMessageSync(new LambdaMessage([&] {
Mutex::Autolock _l(mStateLock);
@@ -1149,6 +1181,8 @@
return;
}
+ auto resyncCallback = makeResyncCallback(std::bind(&SurfaceFlinger::getVsyncPeriod, this));
+
// TODO(akrulec): Part of the Injector should be refactored, so that it
// can be passed to Scheduler.
if (enable) {
@@ -1156,14 +1190,14 @@
if (mVSyncInjector.get() == nullptr) {
mVSyncInjector = std::make_unique<InjectVSyncSource>();
mInjectorEventThread = std::make_unique<
- impl::EventThread>(mVSyncInjector.get(), [this] { resyncWithRateLimit(); },
+ impl::EventThread>(mVSyncInjector.get(),
impl::EventThread::InterceptVSyncsCallback(),
"injEventThread");
}
- mEventQueue->setEventThread(mInjectorEventThread.get());
+ mEventQueue->setEventThread(mInjectorEventThread.get(), std::move(resyncCallback));
} else {
ALOGV("VSync Injections disabled");
- mEventQueue->setEventThread(mSFEventThread.get());
+ mEventQueue->setEventThread(mSFEventThread.get(), std::move(resyncCallback));
}
mInjectVSyncs = enable;
@@ -1220,17 +1254,22 @@
sp<IDisplayEventConnection> SurfaceFlinger::createDisplayEventConnection(
ISurfaceComposer::VsyncSource vsyncSource) {
+ auto resyncCallback = makeResyncCallback([this] {
+ Mutex::Autolock lock(mStateLock);
+ return getVsyncPeriod();
+ });
+
if (mUseScheduler) {
if (vsyncSource == eVsyncSourceSurfaceFlinger) {
- return mScheduler->createDisplayEventConnection(mSfConnectionHandle);
+ return mScheduler->createDisplayEventConnection(mSfConnectionHandle, resyncCallback);
} else {
- return mScheduler->createDisplayEventConnection(mAppConnectionHandle);
+ return mScheduler->createDisplayEventConnection(mAppConnectionHandle, resyncCallback);
}
} else {
if (vsyncSource == eVsyncSourceSurfaceFlinger) {
- return mSFEventThread->createEventConnection();
+ return mSFEventThread->createEventConnection(resyncCallback);
} else {
- return mEventThread->createEventConnection();
+ return mEventThread->createEventConnection(resyncCallback);
}
}
}
@@ -1274,6 +1313,16 @@
} while (true);
}
+nsecs_t SurfaceFlinger::getVsyncPeriod() const {
+ const auto displayId = getInternalDisplayId();
+ if (!displayId || !getHwComposer().isConnected(*displayId)) {
+ return 0;
+ }
+
+ const auto config = getHwComposer().getActiveConfig(*displayId);
+ return config ? config->getVsyncPeriod() : 0;
+}
+
void SurfaceFlinger::enableHardwareVsync() {
Mutex::Autolock _l(mHWVsyncLock);
if (!mPrimaryHWVsyncEnabled && mHWVsyncAvailable) {
@@ -1283,7 +1332,7 @@
}
}
-void SurfaceFlinger::resyncToHardwareVsync(bool makeAvailable) {
+void SurfaceFlinger::resyncToHardwareVsync(bool makeAvailable, nsecs_t period) {
Mutex::Autolock _l(mHWVsyncLock);
if (makeAvailable) {
@@ -1298,14 +1347,10 @@
return;
}
- const auto displayId = getInternalDisplayId();
- if (!displayId || !getHwComposer().isConnected(*displayId)) {
+ if (period <= 0) {
return;
}
- const auto activeConfig = getHwComposer().getActiveConfig(*displayId);
- const nsecs_t period = activeConfig->getVsyncPeriod();
-
if (mUseScheduler) {
mScheduler->setVsyncPeriod(period);
} else {
@@ -1332,16 +1377,15 @@
}
}
-void SurfaceFlinger::resyncWithRateLimit() {
+void SurfaceFlinger::VsyncState::resync(const GetVsyncPeriod& getVsyncPeriod) {
static constexpr nsecs_t kIgnoreDelay = ms2ns(500);
- // No explicit locking is needed here since EventThread holds a lock while calling this method
- static nsecs_t sLastResyncAttempted = 0;
const nsecs_t now = systemTime();
- if (now - sLastResyncAttempted > kIgnoreDelay) {
- resyncToHardwareVsync(false);
+ const nsecs_t last = lastResyncTime.exchange(now);
+
+ if (now - last > kIgnoreDelay) {
+ flinger.resyncToHardwareVsync(false, getVsyncPeriod());
}
- sLastResyncAttempted = now;
}
void SurfaceFlinger::onVsyncReceived(int32_t sequenceId, hwc2_display_t hwcDisplayId,
@@ -1387,6 +1431,49 @@
*compositorTiming = getBE().mCompositorTiming;
}
+void SurfaceFlinger::setRefreshRateTo(float newFps) {
+ const auto displayId = getInternalDisplayId();
+ if (!displayId || mBootStage != BootStage::FINISHED) {
+ return;
+ }
+ // TODO(b/113612090): There should be a message queue flush here. Because this esentially
+ // runs on a mainthread, we cannot call postMessageSync. This can be resolved in a better
+ // manner, once the setActiveConfig is synchronous, and is executed at a known time in a
+ // refresh cycle.
+
+ // Don't do any updating if the current fps is the same as the new one.
+ const auto activeConfig = getHwComposer().getActiveConfig(*displayId);
+ const nsecs_t currentVsyncPeriod = activeConfig->getVsyncPeriod();
+ if (currentVsyncPeriod == 0) {
+ return;
+ }
+ // TODO(b/113612090): Consider having an enum value for correct refresh rates, rather than
+ // floating numbers.
+ const float currentFps = 1e9 / currentVsyncPeriod;
+ if (std::abs(currentFps - newFps) <= 1) {
+ return;
+ }
+
+ auto configs = getHwComposer().getConfigs(*displayId);
+ for (int i = 0; i < configs.size(); i++) {
+ const nsecs_t vsyncPeriod = configs.at(i)->getVsyncPeriod();
+ if (vsyncPeriod == 0) {
+ continue;
+ }
+ const float fps = 1e9 / vsyncPeriod;
+ // TODO(b/113612090): There should be a better way at determining which config
+ // has the right refresh rate.
+ if (std::abs(fps - newFps) <= 1) {
+ const auto display = getBuiltInDisplay(HWC_DISPLAY_PRIMARY);
+ if (!display) return;
+ // This is posted in async function to avoid deadlock when getDisplayDevice
+ // requires mStateLock.
+ setActiveConfigAsync(display, i);
+ ATRACE_INT("FPS", newFps);
+ }
+ }
+}
+
void SurfaceFlinger::onHotplugReceived(int32_t sequenceId, hwc2_display_t hwcDisplayId,
HWC2::Connection connection) {
ALOGV("%s(%d, %" PRIu64 ", %s)", __FUNCTION__, sequenceId, hwcDisplayId,
@@ -1418,7 +1505,7 @@
if (sequenceId != getBE().mComposerSequenceId) {
return;
}
- repaintEverything();
+ repaintEverythingForHWC();
}
void SurfaceFlinger::setVsyncEnabled(EventThread::DisplayType /*displayType*/, bool enabled) {
@@ -1449,11 +1536,11 @@
if (!mVrFlinger)
return;
bool vrFlingerRequestsDisplay = mVrFlingerRequestsDisplay;
- if (vrFlingerRequestsDisplay == getBE().mHwc->isUsingVrComposer()) {
+ if (vrFlingerRequestsDisplay == getHwComposer().isUsingVrComposer()) {
return;
}
- if (vrFlingerRequestsDisplay && !getBE().mHwc->getComposer()->isRemote()) {
+ if (vrFlingerRequestsDisplay && !getHwComposer().getComposer()->isRemote()) {
ALOGE("Vr flinger is only supported for remote hardware composer"
" service connections. Ignoring request to transition to vr"
" flinger.");
@@ -1476,12 +1563,13 @@
}
resetDisplayState();
- getBE().mHwc.reset(); // Delete the current instance before creating the new one
- getBE().mHwc = getFactory().createHWComposer(
- vrFlingerRequestsDisplay ? "vr" : getBE().mHwcServiceName);
- getBE().mHwc->registerCallback(this, ++getBE().mComposerSequenceId);
+ // Delete the current instance before creating the new one
+ mCompositionEngine->setHwComposer(std::unique_ptr<HWComposer>());
+ mCompositionEngine->setHwComposer(getFactory().createHWComposer(
+ vrFlingerRequestsDisplay ? "vr" : getBE().mHwcServiceName));
+ getHwComposer().registerCallback(this, ++getBE().mComposerSequenceId);
- LOG_ALWAYS_FATAL_IF(!getBE().mHwc->getComposer()->isRemote(),
+ LOG_ALWAYS_FATAL_IF(!getHwComposer().getComposer()->isRemote(),
"Switched to non-remote hardware composer");
if (vrFlingerRequestsDisplay) {
@@ -1497,25 +1585,25 @@
setPowerModeInternal(display, currentDisplayPowerMode);
// Reset the timing values to account for the period of the swapped in HWC
- const auto activeConfig = getHwComposer().getActiveConfig(*display->getId());
- const nsecs_t period = activeConfig->getVsyncPeriod();
- mAnimFrameTracker.setDisplayRefreshPeriod(period);
+ const nsecs_t vsyncPeriod = getVsyncPeriod();
+ mAnimFrameTracker.setDisplayRefreshPeriod(vsyncPeriod);
// The present fences returned from vr_hwc are not an accurate
// representation of vsync times.
if (mUseScheduler) {
- mScheduler->setIgnorePresentFences(getBE().mHwc->isUsingVrComposer() || !hasSyncFramework);
+ mScheduler->setIgnorePresentFences(getHwComposer().isUsingVrComposer() ||
+ !hasSyncFramework);
} else {
- mPrimaryDispSync->setIgnorePresentFences(getBE().mHwc->isUsingVrComposer() ||
+ mPrimaryDispSync->setIgnorePresentFences(getHwComposer().isUsingVrComposer() ||
!hasSyncFramework);
}
// Use phase of 0 since phase is not known.
// Use latency of 0, which will snap to the ideal latency.
- DisplayStatInfo stats{0 /* vsyncTime */, period /* vsyncPeriod */};
+ DisplayStatInfo stats{0 /* vsyncTime */, vsyncPeriod};
setCompositorTimingSnapped(stats, 0);
- resyncToHardwareVsync(false);
+ resyncToHardwareVsync(false, vsyncPeriod);
mRepaintEverything = true;
setTransactionFlags(eDisplayTransactionNeeded);
@@ -1610,13 +1698,15 @@
postComposition();
mHadClientComposition = false;
- for (const auto& [token, display] : mDisplays) {
- mHadClientComposition = mHadClientComposition ||
- getBE().mHwc->hasClientComposition(display->getId());
+ for (const auto& [token, displayDevice] : mDisplays) {
+ auto display = displayDevice->getCompositionDisplay();
+ const auto displayId = display->getId();
+ mHadClientComposition =
+ mHadClientComposition || getHwComposer().hasClientComposition(displayId);
}
// Setup RenderEngine sync fences if native sync is supported.
- if (getBE().mRenderEngine->useNativeFenceSync()) {
+ if (getRenderEngine().useNativeFenceSync()) {
if (mHadClientComposition) {
base::unique_fd flushFence(getRenderEngine().flush());
ALOGE_IF(flushFence < 0, "Failed to flush RenderEngine!");
@@ -1652,13 +1742,14 @@
// build the h/w work list
if (CC_UNLIKELY(mGeometryInvalid)) {
mGeometryInvalid = false;
- for (const auto& [token, display] : mDisplays) {
+ for (const auto& [token, displayDevice] : mDisplays) {
+ auto display = displayDevice->getCompositionDisplay();
const auto displayId = display->getId();
if (!displayId) {
continue;
}
- const Vector<sp<Layer>>& currentLayers = display->getVisibleLayersSortedByZ();
+ const Vector<sp<Layer>>& currentLayers = displayDevice->getVisibleLayersSortedByZ();
for (size_t i = 0; i < currentLayers.size(); i++) {
const auto& layer = currentLayers[i];
@@ -1669,7 +1760,7 @@
}
}
- layer->setGeometry(display, i);
+ layer->setGeometry(displayDevice, i);
if (mDebugDisableHWC || mDebugRegion) {
layer->forceClientComposition(*displayId);
}
@@ -1678,29 +1769,27 @@
}
// Set the per-frame data
- for (const auto& [token, display] : mDisplays) {
+ for (const auto& [token, displayDevice] : mDisplays) {
+ auto display = displayDevice->getCompositionDisplay();
const auto displayId = display->getId();
if (!displayId) {
continue;
}
+ auto* profile = display->getDisplayColorProfile();
if (mDrawingState.colorMatrixChanged) {
display->setColorTransform(mDrawingState.colorMatrix);
- status_t result =
- getHwComposer().setColorTransform(*displayId, mDrawingState.colorMatrix);
- ALOGE_IF(result != NO_ERROR, "Failed to set color transform on display %s: %d",
- to_string(*displayId).c_str(), result);
}
- for (auto& layer : display->getVisibleLayersSortedByZ()) {
+ for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) {
if (layer->isHdrY410()) {
layer->forceClientComposition(*displayId);
} else if ((layer->getDataSpace() == Dataspace::BT2020_PQ ||
layer->getDataSpace() == Dataspace::BT2020_ITU_PQ) &&
- !display->hasHDR10Support()) {
+ !profile->hasHDR10Support()) {
layer->forceClientComposition(*displayId);
} else if ((layer->getDataSpace() == Dataspace::BT2020_HLG ||
layer->getDataSpace() == Dataspace::BT2020_ITU_HLG) &&
- !display->hasHLGSupport()) {
+ !profile->hasHLGSupport()) {
layer->forceClientComposition(*displayId);
}
@@ -1719,16 +1808,17 @@
continue;
}
- layer->setPerFrameData(*displayId, display->getTransform(), display->getViewport(),
- display->getSupportedPerFrameMetadata());
+ const auto& displayState = display->getState();
+ layer->setPerFrameData(*displayId, displayState.transform, displayState.viewport,
+ displayDevice->getSupportedPerFrameMetadata());
}
if (useColorManagement) {
ColorMode colorMode;
Dataspace dataSpace;
RenderIntent renderIntent;
- pickColorMode(display, &colorMode, &dataSpace, &renderIntent);
- setActiveColorModeInternal(display, colorMode, dataSpace, renderIntent);
+ pickColorMode(displayDevice, &colorMode, &dataSpace, &renderIntent);
+ display->setColorMode(colorMode, dataSpace, renderIntent);
}
}
@@ -1752,34 +1842,37 @@
}
}
-void SurfaceFlinger::doDebugFlashRegions(const sp<DisplayDevice>& display, bool repaintEverything)
-{
+void SurfaceFlinger::doDebugFlashRegions(const sp<DisplayDevice>& displayDevice,
+ bool repaintEverything) {
+ auto display = displayDevice->getCompositionDisplay();
+ const auto& displayState = display->getState();
+
// is debugging enabled
if (CC_LIKELY(!mDebugRegion))
return;
- if (display->isPoweredOn()) {
+ if (displayState.isEnabled) {
// transform the dirty region into this screen's coordinate space
- const Region dirtyRegion(display->getDirtyRegion(repaintEverything));
+ const Region dirtyRegion = display->getPhysicalSpaceDirtyRegion(repaintEverything);
if (!dirtyRegion.isEmpty()) {
// redraw the whole screen
- doComposeSurfaces(display);
+ doComposeSurfaces(displayDevice);
// and draw the dirty region
auto& engine(getRenderEngine());
engine.fillRegionWithColor(dirtyRegion, 1, 0, 1, 1);
- display->queueBuffer(getHwComposer());
+ display->getRenderSurface()->queueBuffer();
}
}
- postFramebuffer(display);
+ postFramebuffer(displayDevice);
if (mDebugRegion > 1) {
usleep(mDebugRegion * 1000);
}
- prepareFrame(display);
+ prepareFrame(displayDevice);
}
void SurfaceFlinger::doTracing(const char* where) {
@@ -1853,11 +1946,11 @@
nsecs_t compositeToPresentLatency) {
// Integer division and modulo round toward 0 not -inf, so we need to
// treat negative and positive offsets differently.
- nsecs_t idealLatency = (sfVsyncPhaseOffsetNs > 0)
- ? (stats.vsyncPeriod - (sfVsyncPhaseOffsetNs % stats.vsyncPeriod))
- : ((-sfVsyncPhaseOffsetNs) % stats.vsyncPeriod);
+ nsecs_t idealLatency = (mPhaseOffsets->getCurrentSfOffset() > 0)
+ ? (stats.vsyncPeriod - (mPhaseOffsets->getCurrentSfOffset() % stats.vsyncPeriod))
+ : ((-mPhaseOffsets->getCurrentSfOffset()) % stats.vsyncPeriod);
- // Just in case sfVsyncPhaseOffsetNs == -vsyncInterval.
+ // Just in case mPhaseOffsets->getCurrentSfOffset() == -vsyncInterval.
if (idealLatency <= 0) {
idealLatency = stats.vsyncPeriod;
}
@@ -1866,7 +1959,7 @@
// composition and present times, which often have >1ms of jitter.
// Reducing jitter is important if an app attempts to extrapolate
// something (such as user input) to an accurate diasplay time.
- // Snapping also allows an app to precisely calculate sfVsyncPhaseOffsetNs
+ // Snapping also allows an app to precisely calculate mPhaseOffsets->getCurrentSfOffset()
// with (presentLatency % interval).
nsecs_t bias = stats.vsyncPeriod / 2;
int64_t extraVsyncs = (compositeToPresentLatency - idealLatency + bias) / stats.vsyncPeriod;
@@ -1879,37 +1972,99 @@
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 display = getDefaultDisplayDeviceLocked();
+ const auto displayDevice = getDefaultDisplayDeviceLocked();
+ DEFINE_STACK_GUARD(displayDevice);
getBE().mGlCompositionDoneTimeline.updateSignalTimes();
std::shared_ptr<FenceTime> glCompositionDoneFenceTime;
- if (display && getHwComposer().hasClientComposition(display->getId())) {
+ DEFINE_STACK_GUARD(glCompositionDoneFenceTime);
+
+ if (displayDevice && getHwComposer().hasClientComposition(displayDevice->getId())) {
glCompositionDoneFenceTime =
- std::make_shared<FenceTime>(display->getClientTargetAcquireFence());
+ std::make_shared<FenceTime>(displayDevice->getCompositionDisplay()
+ ->getRenderSurface()
+ ->getClientTargetAcquireFence());
getBE().mGlCompositionDoneTimeline.push(glCompositionDoneFenceTime);
} else {
glCompositionDoneFenceTime = FenceTime::NO_FENCE;
}
+ ASSERT_ON_STACK_GUARD();
+
getBE().mDisplayTimeline.updateSignalTimes();
- mPreviousPresentFence =
- display ? getHwComposer().getPresentFence(*display->getId()) : Fence::NO_FENCE;
+ 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);
if (mUseScheduler) {
mScheduler->getDisplayStatInfo(&stats);
} else {
@@ -1917,39 +2072,53 @@
stats.vsyncPeriod = mPrimaryDispSync->getPeriod();
}
+ 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(display->getId(), glCompositionDoneFenceTime,
- presentFenceTime, compositorTiming);
+ 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();
if (mUseScheduler) {
mScheduler->addPresentFence(presentFenceTime);
+ ASSERT_ON_STACK_GUARD();
} else {
if (mPrimaryDispSync->addPresentFence(presentFenceTime)) {
enableHardwareVsync();
} else {
disableHardwareVsync(false);
}
+ ASSERT_ON_STACK_GUARD();
}
}
if (!hasSyncFramework) {
- if (display && getHwComposer().isConnected(*display->getId()) && display->isPoweredOn()) {
+ if (displayDevice && getHwComposer().isConnected(*displayDevice->getId()) &&
+ displayDevice->isPoweredOn()) {
if (mUseScheduler) {
mScheduler->enableHardwareVsync();
} else {
@@ -1958,61 +2127,88 @@
}
}
+ ASSERT_ON_STACK_GUARD();
+
if (mAnimCompositionPending) {
mAnimCompositionPending = false;
if (presentFenceTime->isValid()) {
mAnimFrameTracker.setActualPresentFence(
std::move(presentFenceTime));
- } else if (display && getHwComposer().isConnected(*display->getId())) {
+
+ 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(*display->getId());
+ 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);
- if (display && getHwComposer().isConnected(*display->getId()) && !display->isPoweredOn()) {
+ 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();
}
+#pragma clang optimize on // b/119477596
void SurfaceFlinger::rebuildLayerStacks() {
ATRACE_CALL();
@@ -2036,25 +2232,41 @@
invalidateHwcGeometry();
for (const auto& pair : mDisplays) {
- const auto& display = pair.second;
+ const auto& displayDevice = pair.second;
+ auto display = displayDevice->getCompositionDisplay();
+ const auto& displayState = display->getState();
Region opaqueRegion;
Region dirtyRegion;
- Vector<sp<Layer>> layersSortedByZ;
+ compositionengine::Output::OutputLayers layersSortedByZ;
+ Vector<sp<Layer>> deprecated_layersSortedByZ;
Vector<sp<Layer>> layersNeedingFences;
- const ui::Transform& tr = display->getTransform();
- const Rect bounds = display->getBounds();
- if (display->isPoweredOn()) {
- computeVisibleRegions(display, dirtyRegion, opaqueRegion);
+ const ui::Transform& tr = displayState.transform;
+ const Rect bounds = displayState.bounds;
+ if (displayState.isEnabled) {
+ computeVisibleRegions(displayDevice, dirtyRegion, opaqueRegion);
mDrawingState.traverseInZOrder([&](Layer* layer) {
+ auto compositionLayer = layer->getCompositionLayer();
+ if (compositionLayer == nullptr) {
+ return;
+ }
+
bool hwcLayerDestroyed = false;
- const auto displayId = display->getId();
- if (layer->belongsToDisplay(display->getLayerStack(), display->isPrimary())) {
+ const auto displayId = displayDevice->getId();
+ sp<compositionengine::LayerFE> layerFE = compositionLayer->getLayerFE();
+ LOG_ALWAYS_FATAL_IF(layerFE.get() == nullptr);
+
+ if (display->belongsInOutput(layer->getLayerStack(),
+ layer->getPrimaryDisplayOnly())) {
Region drawRegion(tr.transform(
layer->visibleNonTransparentRegion));
drawRegion.andSelf(bounds);
if (!drawRegion.isEmpty()) {
- layersSortedByZ.add(layer);
+ layersSortedByZ.emplace_back(
+ display->getOrCreateOutputLayer(layer->getCompositionLayer(),
+ layerFE));
+
+ deprecated_layersSortedByZ.add(layer);
} else {
// Clear out the HWC layer if this layer was
// previously visible, but no longer is
@@ -2080,11 +2292,17 @@
}
});
}
- display->setVisibleLayersSortedByZ(layersSortedByZ);
- display->setLayersNeedingFences(layersNeedingFences);
- display->undefinedRegion.set(bounds);
- display->undefinedRegion.subtractSelf(tr.transform(opaqueRegion));
- display->dirtyRegion.orSelf(dirtyRegion);
+
+ display->setOutputLayersOrderedByZ(std::move(layersSortedByZ));
+
+ displayDevice->setVisibleLayersSortedByZ(deprecated_layersSortedByZ);
+ displayDevice->setLayersNeedingFences(layersNeedingFences);
+
+ Region undefinedRegion{bounds};
+ undefinedRegion.subtractSelf(tr.transform(opaqueRegion));
+
+ display->editState().undefinedRegion = undefinedRegion;
+ display->editState().dirtyRegion.orSelf(dirtyRegion);
}
}
}
@@ -2118,10 +2336,12 @@
break;
case Dataspace::BT2020_PQ:
case Dataspace::BT2020_ITU_PQ:
+ bestDataSpace = Dataspace::DISPLAY_P3;
*outHdrDataSpace = Dataspace::BT2020_PQ;
break;
case Dataspace::BT2020_HLG:
case Dataspace::BT2020_ITU_HLG:
+ bestDataSpace = Dataspace::DISPLAY_P3;
// When there's mixed PQ content and HLG content, we set the HDR
// data space to be BT2020_PQ and convert HLG to PQ.
if (*outHdrDataSpace == Dataspace::UNKNOWN) {
@@ -2149,9 +2369,11 @@
Dataspace hdrDataSpace;
Dataspace bestDataSpace = getBestDataspace(display, &hdrDataSpace);
+ auto* profile = display->getCompositionDisplay()->getDisplayColorProfile();
+
// respect hdrDataSpace only when there is no legacy HDR support
- const bool isHdr = hdrDataSpace != Dataspace::UNKNOWN &&
- !display->hasLegacyHdrSupport(hdrDataSpace);
+ const bool isHdr =
+ hdrDataSpace != Dataspace::UNKNOWN && !profile->hasLegacyHdrSupport(hdrDataSpace);
if (isHdr) {
bestDataSpace = hdrDataSpace;
}
@@ -2170,14 +2392,16 @@
break;
}
- display->getBestColorMode(bestDataSpace, intent, outDataSpace, outMode, outRenderIntent);
+ profile->getBestColorMode(bestDataSpace, intent, outDataSpace, outMode, outRenderIntent);
}
-void SurfaceFlinger::beginFrame(const sp<DisplayDevice>& display)
-{
- bool dirty = !display->getDirtyRegion(false).isEmpty();
- bool empty = display->getVisibleLayersSortedByZ().size() == 0;
- bool wasEmpty = !display->lastCompositionHadVisibleLayers;
+void SurfaceFlinger::beginFrame(const sp<DisplayDevice>& displayDevice) {
+ auto display = displayDevice->getCompositionDisplay();
+ const auto& displayState = display->getState();
+
+ bool dirty = !display->getPhysicalSpaceDirtyRegion(false).isEmpty();
+ bool empty = displayDevice->getVisibleLayersSortedByZ().size() == 0;
+ bool wasEmpty = !displayState.lastCompositionHadVisibleLayers;
// If nothing has changed (!dirty), don't recompose.
// If something changed, but we don't currently have any visible layers,
@@ -2191,44 +2415,50 @@
const char flagPrefix[] = {'-', '+'};
static_cast<void>(flagPrefix);
- ALOGV_IF(display->isVirtual(), "%s: %s composition for %s (%cdirty %cempty %cwasEmpty)",
- __FUNCTION__, mustRecompose ? "doing" : "skipping", display->getDebugName().c_str(),
- flagPrefix[dirty], flagPrefix[empty], flagPrefix[wasEmpty]);
+ ALOGV_IF(displayDevice->isVirtual(), "%s: %s composition for %s (%cdirty %cempty %cwasEmpty)",
+ __FUNCTION__, mustRecompose ? "doing" : "skipping",
+ displayDevice->getDebugName().c_str(), flagPrefix[dirty], flagPrefix[empty],
+ flagPrefix[wasEmpty]);
- display->beginFrame(mustRecompose);
+ display->getRenderSurface()->beginFrame(mustRecompose);
if (mustRecompose) {
- display->lastCompositionHadVisibleLayers = !empty;
+ display->editState().lastCompositionHadVisibleLayers = !empty;
}
}
-void SurfaceFlinger::prepareFrame(const sp<DisplayDevice>& display)
-{
- if (!display->isPoweredOn()) {
+void SurfaceFlinger::prepareFrame(const sp<DisplayDevice>& displayDevice) {
+ auto display = displayDevice->getCompositionDisplay();
+ const auto& displayState = display->getState();
+
+ if (!displayState.isEnabled) {
return;
}
- status_t result = display->prepareFrame(getHwComposer(),
- getBE().mCompositionInfo[display->getDisplayToken()]);
+ status_t result = display->getRenderSurface()->prepareFrame(
+ getBE().mCompositionInfo[displayDevice->getDisplayToken()]);
ALOGE_IF(result != NO_ERROR, "prepareFrame failed for %s: %d (%s)",
- display->getDebugName().c_str(), result, strerror(-result));
+ displayDevice->getDebugName().c_str(), result, strerror(-result));
}
-void SurfaceFlinger::doComposition(const sp<DisplayDevice>& display, bool repaintEverything) {
+void SurfaceFlinger::doComposition(const sp<DisplayDevice>& displayDevice, bool repaintEverything) {
ATRACE_CALL();
ALOGV("doComposition");
- if (display->isPoweredOn()) {
+ auto display = displayDevice->getCompositionDisplay();
+ const auto& displayState = display->getState();
+
+ if (displayState.isEnabled) {
// transform the dirty region into this screen's coordinate space
- const Region dirtyRegion(display->getDirtyRegion(repaintEverything));
+ const Region dirtyRegion = display->getPhysicalSpaceDirtyRegion(repaintEverything);
// repaint the framebuffer (if needed)
- doDisplayComposition(display, dirtyRegion);
+ doDisplayComposition(displayDevice, dirtyRegion);
- display->dirtyRegion.clear();
- display->flip();
+ display->editState().dirtyRegion.clear();
+ display->getRenderSurface()->flip();
}
- postFramebuffer(display);
+ postFramebuffer(displayDevice);
}
void SurfaceFlinger::postFrame()
@@ -2243,20 +2473,22 @@
}
}
-void SurfaceFlinger::postFramebuffer(const sp<DisplayDevice>& display)
-{
+void SurfaceFlinger::postFramebuffer(const sp<DisplayDevice>& displayDevice) {
ATRACE_CALL();
ALOGV("postFramebuffer");
+ auto display = displayDevice->getCompositionDisplay();
+ const auto& displayState = display->getState();
+ const auto displayId = display->getId();
+
mPostFramebufferTime = systemTime();
- if (display->isPoweredOn()) {
- const auto displayId = display->getId();
+ if (displayState.isEnabled) {
if (displayId) {
getHwComposer().presentAndGetReleaseFences(*displayId);
}
- display->onPresentDisplayCompleted();
- for (auto& layer : display->getVisibleLayersSortedByZ()) {
+ display->getRenderSurface()->onPresentDisplayCompleted();
+ for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) {
sp<Fence> releaseFence = Fence::NO_FENCE;
// The layer buffer from the previous frame (if any) is released
@@ -2273,8 +2505,9 @@
// client target acquire fence when it is available, even though
// this is suboptimal.
if (layer->getCompositionType(displayId) == HWC2::Composition::Client) {
- releaseFence = Fence::merge("LayerRelease", releaseFence,
- display->getClientTargetAcquireFence());
+ releaseFence =
+ Fence::merge("LayerRelease", releaseFence,
+ display->getRenderSurface()->getClientTargetAcquireFence());
}
layer->getBE().onLayerDisplayed(releaseFence);
@@ -2283,10 +2516,10 @@
// We've got a list of layers needing fences, that are disjoint with
// display->getVisibleLayersSortedByZ. The best we can do is to
// supply them with the present fence.
- if (!display->getLayersNeedingFences().isEmpty()) {
+ if (!displayDevice->getLayersNeedingFences().isEmpty()) {
sp<Fence> presentFence =
- displayId ? getBE().mHwc->getPresentFence(*displayId) : Fence::NO_FENCE;
- for (auto& layer : display->getLayersNeedingFences()) {
+ displayId ? getHwComposer().getPresentFence(*displayId) : Fence::NO_FENCE;
+ for (auto& layer : displayDevice->getLayersNeedingFences()) {
layer->getBE().onLayerDisplayed(presentFence);
}
}
@@ -2365,9 +2598,20 @@
mPendingHotplugEvents.clear();
}
+void SurfaceFlinger::dispatchDisplayHotplugEvent(EventThread::DisplayType displayType,
+ bool connected) {
+ if (mUseScheduler) {
+ mScheduler->hotplugReceived(mAppConnectionHandle, displayType, connected);
+ mScheduler->hotplugReceived(mSfConnectionHandle, displayType, connected);
+ } else {
+ mEventThread->onHotplugReceived(displayType, connected);
+ mSFEventThread->onHotplugReceived(displayType, connected);
+ }
+}
+
sp<DisplayDevice> SurfaceFlinger::setupNewDisplayDeviceInternal(
const wp<IBinder>& displayToken, const std::optional<DisplayId>& displayId,
- const DisplayDeviceState& state, const sp<DisplaySurface>& dispSurface,
+ const DisplayDeviceState& state, const sp<compositionengine::DisplaySurface>& dispSurface,
const sp<IGraphicBufferProducer>& producer) {
DisplayDeviceCreationArgs creationArgs(this, displayToken, displayId);
creationArgs.sequenceId = state.sequenceId;
@@ -2428,8 +2672,8 @@
defaultColorMode = ColorMode::SRGB;
defaultDataSpace = Dataspace::V0_SRGB;
}
- setActiveColorModeInternal(display, defaultColorMode, defaultDataSpace,
- RenderIntent::COLORIMETRIC);
+ display->getCompositionDisplay()->setColorMode(defaultColorMode, defaultDataSpace,
+ RenderIntent::COLORIMETRIC);
if (!state.isVirtual()) {
LOG_ALWAYS_FATAL_IF(!displayId);
display->setActiveConfig(getHwComposer().getActiveConfigIndex(*displayId));
@@ -2466,22 +2710,12 @@
// in drawing state but not in current state
if (const auto display = getDisplayDeviceLocked(draw.keyAt(i))) {
- display->disconnect(getHwComposer());
+ display->disconnect();
}
if (internalDisplayId && internalDisplayId == draw[i].displayId) {
- if (mUseScheduler) {
- mScheduler->hotplugReceived(mAppConnectionHandle,
- EventThread::DisplayType::Primary, false);
- } else {
- mEventThread->onHotplugReceived(EventThread::DisplayType::Primary, false);
- }
+ dispatchDisplayHotplugEvent(EventThread::DisplayType::Primary, false);
} else if (externalDisplayId && externalDisplayId == draw[i].displayId) {
- if (mUseScheduler) {
- mScheduler->hotplugReceived(mAppConnectionHandle,
- EventThread::DisplayType::External, false);
- } else {
- mEventThread->onHotplugReceived(EventThread::DisplayType::External, false);
- }
+ dispatchDisplayHotplugEvent(EventThread::DisplayType::External, false);
}
mDisplays.erase(draw.keyAt(i));
} else {
@@ -2496,7 +2730,7 @@
// from the drawing state, so that it get re-added
// below.
if (const auto display = getDisplayDeviceLocked(displayToken)) {
- display->disconnect(getHwComposer());
+ display->disconnect();
}
mDisplays.erase(displayToken);
mDrawingState.displays.removeItemsAt(i);
@@ -2527,7 +2761,7 @@
if (draw.indexOfKey(curr.keyAt(i)) < 0) {
const DisplayDeviceState& state(curr[i]);
- sp<DisplaySurface> dispSurface;
+ sp<compositionengine::DisplaySurface> dispSurface;
sp<IGraphicBufferProducer> producer;
sp<IGraphicBufferProducer> bqProducer;
sp<IGraphicBufferConsumer> bqConsumer;
@@ -2587,23 +2821,9 @@
LOG_ALWAYS_FATAL_IF(!displayId);
if (displayId == getInternalDisplayId()) {
- if (mUseScheduler) {
- mScheduler->hotplugReceived(mAppConnectionHandle,
- EventThread::DisplayType::Primary,
- true);
- } else {
- mEventThread->onHotplugReceived(EventThread::DisplayType::Primary,
- true);
- }
+ dispatchDisplayHotplugEvent(EventThread::DisplayType::Primary, true);
} else if (displayId == getExternalDisplayId()) {
- if (mUseScheduler) {
- mScheduler->hotplugReceived(mAppConnectionHandle,
- EventThread::DisplayType::External,
- true);
- } else {
- mEventThread->onHotplugReceived(EventThread::DisplayType::External,
- true);
- }
+ dispatchDisplayHotplugEvent(EventThread::DisplayType::External, true);
}
}
}
@@ -2686,7 +2906,9 @@
// if not, pick the only display it's on.
hintDisplay = nullptr;
for (const auto& [token, display] : mDisplays) {
- if (layer->belongsToDisplay(display->getLayerStack(), display->isPrimary())) {
+ if (display->getCompositionDisplay()
+ ->belongsInOutput(layer->getLayerStack(),
+ layer->getPrimaryDisplayOnly())) {
if (hintDisplay) {
hintDisplay = nullptr;
break;
@@ -2751,6 +2973,7 @@
if (inputChanged || mVisibleRegionsDirty) {
updateInputWindows();
}
+ executeInputWindowCommands();
updateCursorAsync();
}
@@ -2768,13 +2991,29 @@
if (layer->hasInput()) {
// When calculating the screen bounds we ignore the transparent region since it may
// result in an unwanted offset.
- inputHandles.add(layer->fillInputInfo(
- layer->computeScreenBounds(false /* reduceTransparentRegion */)));
+ inputHandles.add(layer->fillInputInfo());
}
});
mInputFlinger->setInputWindows(inputHandles);
}
+void SurfaceFlinger::executeInputWindowCommands() {
+ if (!mInputFlinger) {
+ return;
+ }
+
+ for (const auto& transferTouchFocusCommand : mInputWindowCommands.transferTouchFocusCommands) {
+ if (transferTouchFocusCommand.fromToken != nullptr &&
+ transferTouchFocusCommand.toToken != nullptr &&
+ transferTouchFocusCommand.fromToken != transferTouchFocusCommand.toToken) {
+ mInputFlinger->transferTouchFocus(transferTouchFocusCommand.fromToken,
+ transferTouchFocusCommand.toToken);
+ }
+ }
+
+ mInputWindowCommands.clear();
+}
+
void SurfaceFlinger::updateCursorAsync()
{
for (const auto& [token, display] : mDisplays) {
@@ -2812,10 +3051,8 @@
// showing at its last configured state until we eventually
// abandon the buffer queue.
if (l->isRemovedFromCurrentState()) {
- l->traverseInZOrder(LayerVector::StateSet::Drawing, [&](Layer* child) {
- child->destroyHwcLayersForAllDisplays();
- latchAndReleaseBuffer(child);
- });
+ l->destroyHwcLayersForAllDisplays();
+ latchAndReleaseBuffer(l);
}
}
mLayersPendingRemoval.clear();
@@ -2837,11 +3074,13 @@
mTransactionCV.broadcast();
}
-void SurfaceFlinger::computeVisibleRegions(const sp<const DisplayDevice>& display,
+void SurfaceFlinger::computeVisibleRegions(const sp<const DisplayDevice>& displayDevice,
Region& outDirtyRegion, Region& outOpaqueRegion) {
ATRACE_CALL();
ALOGV("computeVisibleRegions");
+ auto display = displayDevice->getCompositionDisplay();
+
Region aboveOpaqueLayers;
Region aboveCoveredLayers;
Region dirty;
@@ -2849,8 +3088,11 @@
outDirtyRegion.clear();
mDrawingState.traverseInReverseZOrder([&](Layer* layer) {
+ // start with the whole surface at its current location
+ const Layer::State& s(layer->getDrawingState());
+
// only consider the layers on the given layer stack
- if (!layer->belongsToDisplay(display->getLayerStack(), display->isPrimary())) {
+ if (!display->belongsInOutput(layer->getLayerStack(), layer->getPrimaryDisplayOnly())) {
return;
}
@@ -2886,7 +3128,7 @@
// handle hidden surfaces by setting the visible region to empty
if (CC_LIKELY(layer->isVisible())) {
- const bool translucent = !layer->isDrawingOpaque();
+ const bool translucent = !layer->isOpaque(s);
Rect bounds(layer->computeScreenBounds());
visibleRegion.set(bounds);
@@ -2896,8 +3138,7 @@
if (translucent) {
if (tr.preserveRects()) {
// transform the transparent region
- transparentRegion =
- tr.transform(layer->getDrawingActiveTransparentRegion());
+ transparentRegion = tr.transform(layer->getActiveTransparentRegion(s));
} else {
// transformation too complex, can't do the
// transparent region optimization.
@@ -2975,13 +3216,29 @@
}
void SurfaceFlinger::invalidateLayerStack(const sp<const Layer>& layer, const Region& dirty) {
- for (const auto& [token, display] : mDisplays) {
- if (layer->belongsToDisplay(display->getLayerStack(), display->isPrimary())) {
- display->dirtyRegion.orSelf(dirty);
+ for (const auto& [token, displayDevice] : mDisplays) {
+ auto display = displayDevice->getCompositionDisplay();
+ if (display->belongsInOutput(layer->getLayerStack(), layer->getPrimaryDisplayOnly())) {
+ display->editState().dirtyRegion.orSelf(dirty);
}
}
}
+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");
@@ -3015,12 +3272,18 @@
}
});
- for (auto& layer : mLayersWithQueuedFrames) {
- const Region dirty(layer->latchBuffer(visibleRegions, latchTime, getBE().flushFence));
- layer->useSurfaceDamage();
- invalidateLayerStack(layer, dirty);
- if (layer->isBufferLatched()) {
- newDataLatched = true;
+ if (!mLayersWithQueuedFrames.empty()) {
+ // mStateLock is needed for latchBuffer as LayerRejecter::reject()
+ // writes to Layer current state. See also b/119481871
+ Mutex::Autolock lock(mStateLock);
+
+ for (auto& layer : mLayersWithQueuedFrames) {
+ const Region dirty(layer->latchBuffer(visibleRegions, latchTime, getBE().flushFence));
+ layer->useSurfaceDamage();
+ invalidateLayerStack(layer, dirty);
+ if (layer->isBufferLatched()) {
+ newDataLatched = true;
+ }
}
}
@@ -3058,31 +3321,36 @@
mGeometryInvalid = true;
}
-void SurfaceFlinger::doDisplayComposition(const sp<DisplayDevice>& display,
+void SurfaceFlinger::doDisplayComposition(const sp<DisplayDevice>& displayDevice,
const Region& inDirtyRegion) {
+ auto display = displayDevice->getCompositionDisplay();
+
// We only need to actually compose the display if:
// 1) It is being handled by hardware composer, which may need this to
// keep its virtual display state machine in sync, or
// 2) There is work to be done (the dirty region isn't empty)
- if (!display->getId() && inDirtyRegion.isEmpty()) {
+ if (!displayDevice->getId() && inDirtyRegion.isEmpty()) {
ALOGV("Skipping display composition");
return;
}
ALOGV("doDisplayComposition");
- if (!doComposeSurfaces(display)) return;
+ if (!doComposeSurfaces(displayDevice)) return;
// swap buffers (presentation)
- display->queueBuffer(getHwComposer());
+ display->getRenderSurface()->queueBuffer();
}
-bool SurfaceFlinger::doComposeSurfaces(const sp<DisplayDevice>& display) {
+bool SurfaceFlinger::doComposeSurfaces(const sp<DisplayDevice>& displayDevice) {
ALOGV("doComposeSurfaces");
- const Region bounds(display->bounds());
- const DisplayRenderArea renderArea(display);
+ auto display = displayDevice->getCompositionDisplay();
+ const auto& displayState = display->getState();
const auto displayId = display->getId();
- const bool hasClientComposition = getBE().mHwc->hasClientComposition(displayId);
+
+ const Region bounds(displayState.bounds);
+ const DisplayRenderArea renderArea(displayDevice);
+ const bool hasClientComposition = getHwComposer().hasClientComposition(displayId);
ATRACE_INT("hasClientComposition", hasClientComposition);
mat4 colorMatrix;
@@ -3094,12 +3362,12 @@
if (hasClientComposition) {
ALOGV("hasClientComposition");
- sp<GraphicBuffer> buf = display->dequeueBuffer();
+ sp<GraphicBuffer> buf = display->getRenderSurface()->dequeueBuffer();
if (buf == nullptr) {
ALOGW("Dequeuing buffer for display [%s] failed, bailing out of "
"client composition for this frame",
- display->getDisplayName().c_str());
+ displayDevice->getDisplayName().c_str());
return false;
}
@@ -3109,23 +3377,24 @@
if (fbo->getStatus() != NO_ERROR) {
ALOGW("Binding buffer for display [%s] failed with status: %d",
- display->getDisplayName().c_str(), fbo->getStatus());
+ displayDevice->getDisplayName().c_str(), fbo->getStatus());
return false;
}
+ const auto* profile = display->getDisplayColorProfile();
Dataspace outputDataspace = Dataspace::UNKNOWN;
- if (display->hasWideColorGamut()) {
- outputDataspace = display->getCompositionDataSpace();
+ if (profile->hasWideColorGamut()) {
+ outputDataspace = displayState.dataspace;
}
- getBE().mRenderEngine->setOutputDataSpace(outputDataspace);
- getBE().mRenderEngine->setDisplayMaxLuminance(
- display->getHdrCapabilities().getDesiredMaxLuminance());
+ getRenderEngine().setOutputDataSpace(outputDataspace);
+ getRenderEngine().setDisplayMaxLuminance(
+ profile->getHdrCapabilities().getDesiredMaxLuminance());
- const bool hasDeviceComposition = getBE().mHwc->hasDeviceComposition(displayId);
+ const bool hasDeviceComposition = getHwComposer().hasDeviceComposition(displayId);
const bool skipClientColorTransform =
- getBE().mHwc
- ->hasDisplayCapability(displayId,
- HWC2::DisplayCapability::SkipClientColorTransform);
+ getHwComposer()
+ .hasDisplayCapability(displayId,
+ HWC2::DisplayCapability::SkipClientColorTransform);
// Compute the global color transform matrix.
applyColorMatrix = !hasDeviceComposition && !skipClientColorTransform;
@@ -3133,7 +3402,7 @@
colorMatrix = mDrawingState.colorMatrix;
}
- display->setViewportAndProjection();
+ display->getRenderSurface()->setViewportAndProjection();
// Never touch the framebuffer if we don't have any framebuffer layers
if (hasDeviceComposition) {
@@ -3142,15 +3411,15 @@
// remove where there are opaque FB layers. however, on some
// GPUs doing a "clean slate" clear might be more efficient.
// We'll revisit later if needed.
- getBE().mRenderEngine->clearWithColor(0, 0, 0, 0);
+ getRenderEngine().clearWithColor(0, 0, 0, 0);
} else {
// we start with the whole screen area and remove the scissor part
// we're left with the letterbox region
// (common case is that letterbox ends-up being empty)
- const Region letterbox = bounds.subtract(display->getScissor());
+ const Region letterbox = bounds.subtract(displayState.scissor);
// compute the area to clear
- const Region region = display->undefinedRegion.merge(letterbox);
+ const Region region = displayState.undefinedRegion.merge(letterbox);
// screen is already cleared here
if (!region.isEmpty()) {
@@ -3159,15 +3428,15 @@
}
}
- const Rect& bounds = display->getBounds();
- const Rect& scissor = display->getScissor();
+ const Rect& bounds = displayState.bounds;
+ const Rect& scissor = displayState.scissor;
if (scissor != bounds) {
// scissor doesn't match the screen's dimensions, so we
// need to clear everything outside of it and enable
// the GL scissor so we don't draw anything where we shouldn't
// enable scissor for this frame
- getBE().mRenderEngine->setScissor(scissor);
+ getRenderEngine().setScissor(scissor);
}
}
@@ -3176,11 +3445,10 @@
*/
ALOGV("Rendering client layers");
- const ui::Transform& displayTransform = display->getTransform();
+ const ui::Transform& displayTransform = displayState.transform;
bool firstLayer = true;
- for (auto& layer : display->getVisibleLayersSortedByZ()) {
- const Region clip(bounds.intersect(
- displayTransform.transform(layer->visibleRegion)));
+ for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) {
+ const Region clip(bounds.intersect(displayTransform.transform(layer->visibleRegion)));
ALOGV("Layer: %s", layer->getName().string());
ALOGV(" Composition type: %s", to_string(layer->getCompositionType(displayId)).c_str());
if (!clip.isEmpty()) {
@@ -3190,8 +3458,9 @@
case HWC2::Composition::Sideband:
case HWC2::Composition::SolidColor: {
LOG_ALWAYS_FATAL_IF(!displayId);
+ const Layer::State& state(layer->getDrawingState());
if (layer->getClearClientTarget(*displayId) && !firstLayer &&
- layer->isDrawingOpaque() && (layer->getAlpha() == 1.0f) &&
+ layer->isOpaque(state) && (layer->getAlpha() == 1.0f) &&
layer->getRoundedCornerState().radius == 0.0f && hasClientComposition) {
// never clear the very first layer since we're
// guaranteed the FB is already cleared
@@ -3225,8 +3494,8 @@
// Perform some cleanup steps if we used client composition.
if (hasClientComposition) {
getRenderEngine().setColorTransform(mat4());
- getBE().mRenderEngine->disableScissor();
- display->finishBuffer();
+ getRenderEngine().disableScissor();
+ display->getRenderSurface()->finishBuffer();
// Clear out error flags here so that we don't wait until next
// composition to log.
getRenderEngine().checkErrors();
@@ -3243,7 +3512,8 @@
const sp<IBinder>& handle,
const sp<IGraphicBufferProducer>& gbc,
const sp<Layer>& lbc,
- const sp<Layer>& parent)
+ const sp<Layer>& parent,
+ bool addToCurrentState)
{
// add this layer to the current state list
{
@@ -3253,13 +3523,14 @@
MAX_LAYERS);
return NO_MEMORY;
}
- if (parent == nullptr) {
+ if (parent == nullptr && addToCurrentState) {
mCurrentState.layersSortedByZ.add(lbc);
+ } else if (parent == nullptr) {
+ lbc->onRemovedFromCurrentState();
+ } else if (parent->isRemovedFromCurrentState()) {
+ parent->addChild(lbc);
+ lbc->onRemovedFromCurrentState();
} else {
- if (parent->isRemovedFromCurrentState()) {
- ALOGE("addClientLayer called with a removed parent");
- lbc->onRemovedFromCurrentState();
- }
parent->addChild(lbc);
}
@@ -3280,30 +3551,6 @@
return NO_ERROR;
}
-status_t SurfaceFlinger::removeLayer(const sp<Layer>& layer) {
- Mutex::Autolock _l(mStateLock);
- return removeLayerLocked(mStateLock, layer);
-}
-
-status_t SurfaceFlinger::removeLayerLocked(const Mutex& lock, const sp<Layer>& layer) {
- if (layer->isLayerDetached()) {
- return NO_ERROR;
- }
-
- const auto& p = layer->getParent();
- ssize_t index;
- if (p != nullptr) {
- index = p->removeChild(layer);
- } else {
- index = mCurrentState.layersSortedByZ.remove(layer);
- }
-
- layer->onRemovedFromCurrentState();
-
- markLayerPendingRemovalLocked(lock, layer);
- return NO_ERROR;
-}
-
uint32_t SurfaceFlinger::peekTransactionFlags() {
return mTransactionFlags;
}
@@ -3333,11 +3580,11 @@
auto& [applyToken, transactionQueue] = *it;
while (!transactionQueue.empty()) {
- const auto& [states, displays, flags] = transactionQueue.front();
- if (composerStateContainsUnsignaledFences(states)) {
+ const auto& [states, displays, flags, desiredPresentTime] = transactionQueue.front();
+ if (!transactionIsReadyToBeApplied(desiredPresentTime, states)) {
break;
}
- applyTransactionState(states, displays, flags);
+ applyTransactionState(states, displays, flags, mInputWindowCommands);
transactionQueue.pop();
}
@@ -3368,22 +3615,33 @@
return false;
}
-bool SurfaceFlinger::composerStateContainsUnsignaledFences(const Vector<ComposerState>& states) {
+bool SurfaceFlinger::transactionIsReadyToBeApplied(int64_t desiredPresentTime,
+ const Vector<ComposerState>& states) {
+ const nsecs_t expectedPresentTime = mPrimaryDispSync->expectedPresentTime();
+ // Do not present if the desiredPresentTime has not passed unless it is more than one second
+ // in the future. We ignore timestamps more than 1 second in the future for stability reasons.
+ if (desiredPresentTime >= 0 && desiredPresentTime >= expectedPresentTime &&
+ desiredPresentTime < expectedPresentTime + s2ns(1)) {
+ return false;
+ }
+
for (const ComposerState& state : states) {
const layer_state_t& s = state.state;
if (!(s.what & layer_state_t::eAcquireFenceChanged)) {
continue;
}
if (s.acquireFence && s.acquireFence->getStatus() == Fence::Status::Unsignaled) {
- return true;
+ return false;
}
}
- return false;
+ return true;
}
void SurfaceFlinger::setTransactionState(const Vector<ComposerState>& states,
const Vector<DisplayState>& displays, uint32_t flags,
- const sp<IBinder>& applyToken) {
+ const sp<IBinder>& applyToken,
+ const InputWindowCommands& inputWindowCommands,
+ int64_t desiredPresentTime) {
ATRACE_CALL();
Mutex::Autolock _l(mStateLock);
@@ -3393,17 +3651,18 @@
// If its TransactionQueue already has a pending TransactionState or if it is pending
if (mTransactionQueues.find(applyToken) != mTransactionQueues.end() ||
- composerStateContainsUnsignaledFences(states)) {
- mTransactionQueues[applyToken].emplace(states, displays, flags);
+ !transactionIsReadyToBeApplied(desiredPresentTime, states)) {
+ mTransactionQueues[applyToken].emplace(states, displays, flags, desiredPresentTime);
setTransactionFlags(eTransactionNeeded);
return;
}
- applyTransactionState(states, displays, flags);
+ applyTransactionState(states, displays, flags, inputWindowCommands);
}
void SurfaceFlinger::applyTransactionState(const Vector<ComposerState>& states,
- const Vector<DisplayState>& displays, uint32_t flags) {
+ const Vector<DisplayState>& displays, uint32_t flags,
+ const InputWindowCommands& inputWindowCommands) {
uint32_t transactionFlags = 0;
if (flags & eAnimation) {
@@ -3436,13 +3695,7 @@
}
transactionFlags |= clientStateFlags;
- // Iterate through all layers again to determine if any need to be destroyed. Marking layers
- // as destroyed should only occur after setting all other states. This is to allow for a
- // child re-parent to happen before marking its original parent as destroyed (which would
- // then mark the child as destroyed).
- for (const ComposerState& state : states) {
- setDestroyStateLocked(state);
- }
+ transactionFlags |= addInputWindowCommands(inputWindowCommands);
// If a synchronous transaction is explicitly requested without any changes, force a transaction
// anyway. This can be used as a flush mechanism for previous async transactions.
@@ -3623,6 +3876,11 @@
flags |= eTraversalNeeded;
}
}
+ if (what & layer_state_t::eBackgroundColorChanged) {
+ if (layer->setBackgroundColor(s.color, s.bgColorAlpha, s.bgColorDataspace)) {
+ flags |= eTraversalNeeded;
+ }
+ }
if (what & layer_state_t::eMatrixChanged) {
// TODO: b/109894387
//
@@ -3729,9 +3987,6 @@
if (what & layer_state_t::eFrameChanged) {
if (layer->setFrame(s.frame)) flags |= eTraversalNeeded;
}
- if (what & layer_state_t::eBufferChanged) {
- if (layer->setBuffer(s.buffer)) flags |= eTraversalNeeded;
- }
if (what & layer_state_t::eAcquireFenceChanged) {
if (layer->setAcquireFence(s.acquireFence)) flags |= eTraversalNeeded;
}
@@ -3751,8 +4006,15 @@
if (layer->setSidebandStream(s.sidebandStream)) flags |= eTraversalNeeded;
}
if (what & layer_state_t::eInputInfoChanged) {
- layer->setInputInfo(s.inputInfo);
- flags |= eTraversalNeeded;
+ if (callingThreadHasUnscopedSurfaceFlingerAccess()) {
+ layer->setInputInfo(s.inputInfo);
+ flags |= eTraversalNeeded;
+ } else {
+ ALOGE("Attempt to update InputWindowInfo without permission ACCESS_SURFACE_FLINGER");
+ }
+ }
+ if (what & layer_state_t::eMetadataChanged) {
+ if (layer->setMetadata(s.metadata)) flags |= eTraversalNeeded;
}
std::vector<sp<CallbackHandle>> callbackHandles;
if ((what & layer_state_t::eListenerCallbacksChanged) && (!s.listenerCallbacks.empty())) {
@@ -3761,33 +4023,38 @@
callbackHandles.emplace_back(new CallbackHandle(listener, callbackIds, s.surface));
}
}
+
+ if (what & layer_state_t::eBufferChanged) {
+ // Add the new buffer to the cache. This should always come before eCachedBufferChanged.
+ BufferStateLayerCache::getInstance().add(s.cachedBuffer.token, s.cachedBuffer.bufferId,
+ s.buffer);
+ }
+ if (what & layer_state_t::eCachedBufferChanged) {
+ sp<GraphicBuffer> buffer =
+ BufferStateLayerCache::getInstance().get(s.cachedBuffer.token,
+ s.cachedBuffer.bufferId);
+ if (layer->setBuffer(buffer)) flags |= eTraversalNeeded;
+ }
if (layer->setTransactionCompletedListeners(callbackHandles)) flags |= eTraversalNeeded;
// Do not put anything that updates layer state or modifies flags after
// setTransactionCompletedListener
return flags;
}
-void SurfaceFlinger::setDestroyStateLocked(const ComposerState& composerState) {
- const layer_state_t& state = composerState.state;
- sp<Client> client(static_cast<Client*>(composerState.client.get()));
-
- sp<Layer> layer(client->getLayerUser(state.surface));
- if (layer == nullptr) {
- return;
+uint32_t SurfaceFlinger::addInputWindowCommands(const InputWindowCommands& inputWindowCommands) {
+ uint32_t flags = 0;
+ if (!inputWindowCommands.transferTouchFocusCommands.empty()) {
+ flags |= eTraversalNeeded;
}
- if (state.what & layer_state_t::eDestroySurface) {
- removeLayerLocked(mStateLock, layer);
- }
+ mInputWindowCommands.merge(inputWindowCommands);
+ return flags;
}
-status_t SurfaceFlinger::createLayer(
- const String8& name,
- const sp<Client>& client,
- uint32_t w, uint32_t h, PixelFormat format, uint32_t flags,
- int32_t windowType, int32_t ownerUid, sp<IBinder>* handle,
- sp<IGraphicBufferProducer>* gbp, sp<Layer>* parent)
-{
+status_t SurfaceFlinger::createLayer(const String8& name, const sp<Client>& client, uint32_t w,
+ uint32_t h, PixelFormat format, uint32_t flags,
+ LayerMetadata metadata, sp<IBinder>* handle,
+ sp<IGraphicBufferProducer>* gbp, sp<Layer>* parent) {
if (int32_t(w|h) < 0) {
ALOGE("createLayer() failed, w or h is negative (w=%d, h=%d)",
int(w), int(h));
@@ -3843,14 +4110,19 @@
// window type is WINDOW_TYPE_DONT_SCREENSHOT from SurfaceControl.java
// TODO b/64227542
- if (windowType == 441731) {
- windowType = 2024; // TYPE_NAVIGATION_BAR_PANEL
- layer->setPrimaryDisplayOnly();
+ if (metadata.has(METADATA_WINDOW_TYPE)) {
+ int32_t windowType = metadata.getInt32(METADATA_WINDOW_TYPE, 0);
+ if (windowType == 441731) {
+ metadata.setInt32(METADATA_WINDOW_TYPE, 2024); // TYPE_NAVIGATION_BAR_PANEL
+ layer->setPrimaryDisplayOnly();
+ }
}
- layer->setInfo(windowType, ownerUid);
+ layer->setMetadata(std::move(metadata));
- result = addClientLayer(client, *handle, *gbp, layer, *parent);
+ bool addToCurrentState = callingThreadHasUnscopedSurfaceFlingerAccess();
+ result = addClientLayer(client, *handle, *gbp, layer, *parent,
+ addToCurrentState);
if (result != NO_ERROR) {
return result;
}
@@ -3948,21 +4220,7 @@
}
-status_t SurfaceFlinger::onLayerRemoved(const sp<Client>& client, const sp<IBinder>& handle)
-{
- // called by a client when it wants to remove a Layer
- status_t err = NO_ERROR;
- sp<Layer> l(client->getLayerUser(handle));
- if (l != nullptr) {
- mInterceptor->saveSurfaceDeletion(l);
- err = removeLayer(l);
- ALOGE_IF(err<0 && err != NAME_NOT_FOUND,
- "error removing layer=%p (%s)", l.get(), strerror(-err));
- }
- return err;
-}
-
-void SurfaceFlinger::markLayerPendingRemovalLocked(const Mutex&, const sp<Layer>& layer) {
+void SurfaceFlinger::markLayerPendingRemovalLocked(const sp<Layer>& layer) {
mLayersPendingRemoval.add(layer);
mLayersRemoved = true;
setTransactionFlags(eTransactionNeeded);
@@ -3971,15 +4229,25 @@
void SurfaceFlinger::onHandleDestroyed(sp<Layer>& layer)
{
Mutex::Autolock lock(mStateLock);
- markLayerPendingRemovalLocked(mStateLock, layer);
+ // If a layer has a parent, we allow it to out-live it's handle
+ // with the idea that the parent holds a reference and will eventually
+ // be cleaned up. However no one cleans up the top-level so we do so
+ // here.
+ if (layer->getParent() == nullptr) {
+ mCurrentState.layersSortedByZ.remove(layer);
+ }
+ markLayerPendingRemovalLocked(layer);
layer.clear();
}
// ---------------------------------------------------------------------------
void SurfaceFlinger::onInitializeDisplays() {
- const auto displayToken = getInternalDisplayToken();
- if (!displayToken) return;
+ const auto display = getDefaultDisplayDeviceLocked();
+ if (!display) return;
+
+ const sp<IBinder> token = display->getDisplayToken().promote();
+ LOG_ALWAYS_FATAL_IF(token == nullptr);
// reset screen orientation and use primary layer stack
Vector<ComposerState> state;
@@ -3987,7 +4255,7 @@
DisplayState d;
d.what = DisplayState::eDisplayProjectionChanged |
DisplayState::eLayerStackChanged;
- d.token = displayToken;
+ d.token = token;
d.layerStack = 0;
d.orientation = DisplayState::eOrientationDefault;
d.frame.makeInvalid();
@@ -3995,26 +4263,23 @@
d.width = 0;
d.height = 0;
displays.add(d);
- setTransactionState(state, displays, 0, nullptr);
-
- const auto display = getDisplayDevice(displayToken);
- if (!display) return;
+ setTransactionState(state, displays, 0, nullptr, mInputWindowCommands, -1);
setPowerModeInternal(display, HWC_POWER_MODE_NORMAL);
- const auto activeConfig = getHwComposer().getActiveConfig(*display->getId());
- const nsecs_t period = activeConfig->getVsyncPeriod();
- mAnimFrameTracker.setDisplayRefreshPeriod(period);
+ const nsecs_t vsyncPeriod = getVsyncPeriod();
+ mAnimFrameTracker.setDisplayRefreshPeriod(vsyncPeriod);
// Use phase of 0 since phase is not known.
// Use latency of 0, which will snap to the ideal latency.
- DisplayStatInfo stats{0 /* vsyncTime */, period /* vsyncPeriod */};
+ DisplayStatInfo stats{0 /* vsyncTime */, vsyncPeriod};
setCompositorTimingSnapped(stats, 0);
}
void SurfaceFlinger::initializeDisplays() {
// Async since we may be called from the main thread.
- postMessageAsync(new LambdaMessage([this] { onInitializeDisplays(); }));
+ postMessageAsync(
+ new LambdaMessage([this]() NO_THREAD_SAFETY_ANALYSIS { onInitializeDisplays(); }));
}
void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& display, int mode) {
@@ -4048,7 +4313,7 @@
} else {
mEventThread->onScreenAcquired();
}
- resyncToHardwareVsync(true);
+ resyncToHardwareVsync(true, getVsyncPeriod());
}
mVisibleRegionsDirty = true;
@@ -4093,7 +4358,7 @@
} else {
mEventThread->onScreenAcquired();
}
- resyncToHardwareVsync(true);
+ resyncToHardwareVsync(true, getVsyncPeriod());
}
} else if (mode == HWC_POWER_MODE_DOZE_SUSPEND) {
// Leave display going to doze
@@ -4117,13 +4382,17 @@
if (display->isPrimary()) {
mTimeStats->setPowerMode(mode);
+ if (mUseScheduler && mRefreshRateStats) {
+ // Update refresh rate stats.
+ mRefreshRateStats->setPowerMode(mode);
+ }
}
ALOGD("Finished setting power mode %d on display %s", mode, to_string(*displayId).c_str());
}
void SurfaceFlinger::setPowerMode(const sp<IBinder>& displayToken, int mode) {
- postMessageSync(new LambdaMessage([&] {
+ postMessageSync(new LambdaMessage([&]() NO_THREAD_SAFETY_ANALYSIS {
const auto display = getDisplayDevice(displayToken);
if (!display) {
ALOGE("Attempt to set power mode %d for invalid display token %p", mode,
@@ -4138,8 +4407,8 @@
// ---------------------------------------------------------------------------
-status_t SurfaceFlinger::doDump(int fd, const Vector<String16>& args, bool asProto)
- NO_THREAD_SAFETY_ANALYSIS {
+status_t SurfaceFlinger::doDump(int fd, const DumpArgs& args,
+ bool asProto) NO_THREAD_SAFETY_ANALYSIS {
std::string result;
IPCThreadState* ipc = IPCThreadState::self();
@@ -4163,114 +4432,36 @@
strerror(-err), err);
}
- bool dumpAll = true;
- size_t index = 0;
- size_t numArgs = args.size();
+ using namespace std::string_literals;
- if (numArgs) {
- if ((index < numArgs) &&
- (args[index] == String16("--list"))) {
- index++;
- listLayersLocked(args, index, result);
- dumpAll = false;
- }
+ static const std::unordered_map<std::string, Dumper> dumpers = {
+ {"--clear-layer-stats"s, dumper([this](std::string&) { mLayerStats.clear(); })},
+ {"--disable-layer-stats"s, dumper([this](std::string&) { mLayerStats.disable(); })},
+ {"--display-id"s, dumper(&SurfaceFlinger::dumpDisplayIdentificationData)},
+ {"--dispsync"s, dumper([this](std::string& s) { mPrimaryDispSync->dump(s); })},
+ {"--dump-layer-stats"s, dumper([this](std::string& s) { mLayerStats.dump(s); })},
+ {"--enable-layer-stats"s, dumper([this](std::string&) { mLayerStats.enable(); })},
+ {"--frame-composition"s, dumper(&SurfaceFlinger::dumpFrameCompositionInfo)},
+ {"--frame-events"s, dumper(&SurfaceFlinger::dumpFrameEventsLocked)},
+ {"--latency"s, argsDumper(&SurfaceFlinger::dumpStatsLocked)},
+ {"--latency-clear"s, argsDumper(&SurfaceFlinger::clearStatsLocked)},
+ {"--list"s, dumper(&SurfaceFlinger::listLayersLocked)},
+ {"--static-screen"s, dumper(&SurfaceFlinger::dumpStaticScreenStats)},
+ {"--timestats"s, protoDumper(&SurfaceFlinger::dumpTimeStats)},
+ {"--vsync"s, dumper(&SurfaceFlinger::dumpVSync)},
+ {"--wide-color"s, dumper(&SurfaceFlinger::dumpWideColorInfo)},
+ };
- if ((index < numArgs) &&
- (args[index] == String16("--latency"))) {
- index++;
- dumpStatsLocked(args, index, result);
- dumpAll = false;
- }
+ const auto flag = args.empty() ? ""s : std::string(String8(args[0]));
- if ((index < numArgs) &&
- (args[index] == String16("--latency-clear"))) {
- index++;
- clearStatsLocked(args, index, result);
- dumpAll = false;
- }
-
- if ((index < numArgs) &&
- (args[index] == String16("--dispsync"))) {
- index++;
- mPrimaryDispSync->dump(result);
- dumpAll = false;
- }
-
- if ((index < numArgs) &&
- (args[index] == String16("--static-screen"))) {
- index++;
- dumpStaticScreenStats(result);
- dumpAll = false;
- }
-
- if ((index < numArgs) &&
- (args[index] == String16("--frame-events"))) {
- index++;
- dumpFrameEventsLocked(result);
- dumpAll = false;
- }
-
- if ((index < numArgs) && (args[index] == String16("--wide-color"))) {
- index++;
- dumpWideColorInfo(result);
- dumpAll = false;
- }
-
- if ((index < numArgs) &&
- (args[index] == String16("--enable-layer-stats"))) {
- index++;
- mLayerStats.enable();
- dumpAll = false;
- }
-
- if ((index < numArgs) &&
- (args[index] == String16("--disable-layer-stats"))) {
- index++;
- mLayerStats.disable();
- dumpAll = false;
- }
-
- if ((index < numArgs) &&
- (args[index] == String16("--clear-layer-stats"))) {
- index++;
- mLayerStats.clear();
- dumpAll = false;
- }
-
- if ((index < numArgs) &&
- (args[index] == String16("--dump-layer-stats"))) {
- index++;
- mLayerStats.dump(result);
- dumpAll = false;
- }
-
- if ((index < numArgs) &&
- (args[index] == String16("--frame-composition"))) {
- index++;
- dumpFrameCompositionInfo(result);
- dumpAll = false;
- }
-
- if ((index < numArgs) &&
- (args[index] == String16("--display-identification"))) {
- index++;
- dumpDisplayIdentificationData(result);
- dumpAll = false;
- }
-
- if ((index < numArgs) && (args[index] == String16("--timestats"))) {
- index++;
- mTimeStats->parseArgs(asProto, args, index, result);
- dumpAll = false;
- }
- }
-
- if (dumpAll) {
+ if (const auto it = dumpers.find(flag); it != dumpers.end()) {
+ (it->second)(args, asProto, result);
+ } else {
if (asProto) {
LayersProto layersProto = dumpProtoInfo(LayerVector::StateSet::Current);
result.append(layersProto.SerializeAsString().c_str(), layersProto.ByteSize());
} else {
- dumpAllLocked(args, index, result);
+ dumpAllLocked(args, result);
}
}
@@ -4282,48 +4473,29 @@
return NO_ERROR;
}
-void SurfaceFlinger::listLayersLocked(const Vector<String16>& /* args */, size_t& /* index */,
- std::string& result) const {
+void SurfaceFlinger::listLayersLocked(std::string& result) const {
mCurrentState.traverseInZOrder(
[&](Layer* layer) { StringAppendF(&result, "%s\n", layer->getName().string()); });
}
-void SurfaceFlinger::dumpStatsLocked(const Vector<String16>& args, size_t& index,
- std::string& result) const {
- String8 name;
- if (index < args.size()) {
- name = String8(args[index]);
- index++;
- }
+void SurfaceFlinger::dumpStatsLocked(const DumpArgs& args, std::string& result) const {
+ StringAppendF(&result, "%" PRId64 "\n", getVsyncPeriod());
- if (const auto displayId = getInternalDisplayId();
- displayId && getHwComposer().isConnected(*displayId)) {
- const auto activeConfig = getHwComposer().getActiveConfig(*displayId);
- const nsecs_t period = activeConfig->getVsyncPeriod();
- StringAppendF(&result, "%" PRId64 "\n", period);
- }
-
- if (name.isEmpty()) {
- mAnimFrameTracker.dumpStats(result);
- } else {
+ if (args.size() > 1) {
+ const auto name = String8(args[1]);
mCurrentState.traverseInZOrder([&](Layer* layer) {
if (name == layer->getName()) {
layer->dumpFrameStats(result);
}
});
+ } else {
+ mAnimFrameTracker.dumpStats(result);
}
}
-void SurfaceFlinger::clearStatsLocked(const Vector<String16>& args, size_t& index,
- std::string& /* result */) {
- String8 name;
- if (index < args.size()) {
- name = String8(args[index]);
- index++;
- }
-
+void SurfaceFlinger::clearStatsLocked(const DumpArgs& args, std::string&) {
mCurrentState.traverseInZOrder([&](Layer* layer) {
- if (name.isEmpty() || (name == layer->getName())) {
+ if (args.size() < 2 || String8(args[1]) == layer->getName()) {
layer->clearFrameStats();
}
});
@@ -4331,6 +4503,10 @@
mAnimFrameTracker.clearStats();
}
+void SurfaceFlinger::dumpTimeStats(const DumpArgs& args, bool asProto, std::string& result) const {
+ mTimeStats->parseArgs(asProto, args, result);
+}
+
// This should only be called from the main thread. Otherwise it would need
// the lock and should use mCurrentState rather than mDrawingState.
void SurfaceFlinger::logFrameStats() {
@@ -4356,6 +4532,21 @@
result.append("]");
}
+void SurfaceFlinger::dumpVSync(std::string& result) const {
+ mPhaseOffsets->dump(result);
+ StringAppendF(&result,
+ " present offset: %9" PRId64 " ns\t VSYNC period: %9" PRId64 " ns\n\n",
+ dispSyncPresentTimeOffset, getVsyncPeriod());
+
+ StringAppendF(&result, "Scheduler: %s\n\n", mUseScheduler ? "enabled" : "disabled");
+
+ if (mUseScheduler) {
+ mScheduler->dump(mAppConnectionHandle, result);
+ } else {
+ mEventThread->dump(result);
+ }
+}
+
void SurfaceFlinger::dumpStaticScreenStats(std::string& result) const {
result.append("Static screen stats:\n");
for (size_t b = 0; b < SurfaceFlingerBE::NUM_BUCKETS - 1; ++b) {
@@ -4497,7 +4688,7 @@
StringAppendF(&result, " %s (%d)\n", decodeColorMode(mode).c_str(), mode);
}
- ColorMode currentMode = display->getActiveColorMode();
+ ColorMode currentMode = display->getCompositionDisplay()->getState().colorMode;
StringAppendF(&result, " Current color mode: %s (%d)\n",
decodeColorMode(currentMode).c_str(), currentMode);
}
@@ -4533,18 +4724,21 @@
return layersProto;
}
-LayersProto SurfaceFlinger::dumpVisibleLayersProtoInfo(const DisplayDevice& display) const {
+LayersProto SurfaceFlinger::dumpVisibleLayersProtoInfo(const DisplayDevice& displayDevice) const {
LayersProto layersProto;
SizeProto* resolution = layersProto.mutable_resolution();
- resolution->set_w(display.getWidth());
- resolution->set_h(display.getHeight());
+ resolution->set_w(displayDevice.getWidth());
+ resolution->set_h(displayDevice.getHeight());
- layersProto.set_color_mode(decodeColorMode(display.getActiveColorMode()));
- layersProto.set_color_transform(decodeColorTransform(display.getColorTransform()));
- layersProto.set_global_transform(static_cast<int32_t>(display.getOrientationTransform()));
+ auto display = displayDevice.getCompositionDisplay();
+ const auto& displayState = display->getState();
- const auto displayId = display.getId();
+ layersProto.set_color_mode(decodeColorMode(displayState.colorMode));
+ layersProto.set_color_transform(decodeColorTransform(displayState.colorTransform));
+ layersProto.set_global_transform(displayState.orientation);
+
+ const auto displayId = displayDevice.getId();
LOG_ALWAYS_FATAL_IF(!displayId);
mDrawingState.traverseInZOrder([&](Layer* layer) {
if (!layer->visibleRegion.isEmpty() && layer->getBE().mHwcLayers.count(*displayId)) {
@@ -4556,15 +4750,8 @@
return layersProto;
}
-void SurfaceFlinger::dumpAllLocked(const Vector<String16>& args, size_t& index,
- std::string& result) const {
- bool colorize = false;
- if (index < args.size()
- && (args[index] == String16("--color"))) {
- colorize = true;
- index++;
- }
-
+void SurfaceFlinger::dumpAllLocked(const DumpArgs& args, std::string& result) const {
+ const bool colorize = !args.empty() && args[0] == String16("--color");
Colorizer colorizer(colorize);
// figure out if we're stuck somewhere
@@ -4594,33 +4781,14 @@
result.append("Sync configuration: ");
colorizer.reset(result);
result.append(SyncFeatures::getInstance().toString());
- result.append("\n");
+ result.append("\n\n");
colorizer.bold(result);
- result.append("DispSync configuration:\n");
+ result.append("VSYNC configuration:\n");
colorizer.reset(result);
-
- const auto [sfEarlyOffset, appEarlyOffset] = mVsyncModulator.getEarlyOffsets();
- const auto [sfEarlyGlOffset, appEarlyGlOffset] = mVsyncModulator.getEarlyGlOffsets();
- if (const auto displayId = getInternalDisplayId();
- displayId && getHwComposer().isConnected(*displayId)) {
- const auto activeConfig = getHwComposer().getActiveConfig(*displayId);
- StringAppendF(&result,
- "Display %s: app phase %" PRId64 " ns, "
- "sf phase %" PRId64 " ns, "
- "early app phase %" PRId64 " ns, "
- "early sf phase %" PRId64 " ns, "
- "early app gl phase %" PRId64 " ns, "
- "early sf gl phase %" PRId64 " ns, "
- "present offset %" PRId64 " ns (refresh %" PRId64 " ns)",
- to_string(*displayId).c_str(), vsyncPhaseOffsetNs, sfVsyncPhaseOffsetNs,
- appEarlyOffset, sfEarlyOffset, appEarlyGlOffset, sfEarlyGlOffset,
- dispSyncPresentTimeOffset, activeConfig->getVsyncPeriod());
- }
+ dumpVSync(result);
result.append("\n");
- // Dump static screen stats
- result.append("\n");
dumpStaticScreenStats(result);
result.append("\n");
@@ -4668,10 +4836,11 @@
result.append("SurfaceFlinger global state:\n");
colorizer.reset(result);
- getBE().mRenderEngine->dump(result);
+ getRenderEngine().dump(result);
if (const auto display = getDefaultDisplayDeviceLocked()) {
- display->undefinedRegion.dump(result, "undefinedRegion");
+ display->getCompositionDisplay()->getState().undefinedRegion.dump(result,
+ "undefinedRegion");
StringAppendF(&result, " orientation=%d, isPoweredOn=%d\n", display->getOrientation(),
display->isPoweredOn());
}
@@ -4693,17 +4862,6 @@
StringAppendF(&result, " transaction time: %f us\n", inTransactionDuration / 1000.0);
- StringAppendF(&result, " use Scheduler: %s\n", mUseScheduler ? "true" : "false");
- /*
- * VSYNC state
- */
- if (mUseScheduler) {
- mScheduler->dump(mAppConnectionHandle, result);
- } else {
- mEventThread->dump(result);
- }
- result.append("\n");
-
/*
* Tracing state
*/
@@ -4749,6 +4907,15 @@
result.append(mVrFlinger->Dump());
result.append("\n");
}
+
+ /**
+ * Scheduler dump state.
+ */
+ if (mUseScheduler) {
+ result.append("\nScheduler state:\n");
+ result.append(mScheduler->doDump() + "\n");
+ result.append(mRefreshRateStats->doDump() + "\n");
+ }
}
const Vector<sp<Layer>>& SurfaceFlinger::getLayerSortedByZForHwcDisplay(DisplayId displayId) {
@@ -4764,24 +4931,6 @@
return empty;
}
-bool SurfaceFlinger::startDdmConnection()
-{
- void* libddmconnection_dso =
- dlopen("libsurfaceflinger_ddmconnection.so", RTLD_NOW);
- if (!libddmconnection_dso) {
- return false;
- }
- void (*DdmConnection_start)(const char* name);
- DdmConnection_start =
- (decltype(DdmConnection_start))dlsym(libddmconnection_dso, "DdmConnection_start");
- if (!DdmConnection_start) {
- dlclose(libddmconnection_dso);
- return false;
- }
- (*DdmConnection_start)(getServiceName());
- return true;
-}
-
void SurfaceFlinger::updateColorMatrixLocked() {
mat4 colorMatrix;
if (mGlobalSaturationFactor != 1.0f) {
@@ -4814,7 +4963,6 @@
// access to SF.
case BOOT_FINISHED:
case CLEAR_ANIMATION_FRAME_STATS:
- case CREATE_CONNECTION:
case CREATE_DISPLAY:
case DESTROY_DISPLAY:
case ENABLE_VSYNC_INJECTIONS:
@@ -4855,16 +5003,18 @@
case GET_ACTIVE_CONFIG:
case GET_BUILT_IN_DISPLAY:
case GET_DISPLAY_COLOR_MODES:
+ case GET_DISPLAY_NATIVE_PRIMARIES:
case GET_DISPLAY_CONFIGS:
case GET_DISPLAY_STATS:
case GET_SUPPORTED_FRAME_TIMESTAMPS:
// Calling setTransactionState is safe, because you need to have been
// granted a reference to Client* and Handle* to do anything with it.
case SET_TRANSACTION_STATE:
- // Creating a scoped connection is safe, as per discussion in ISurfaceComposer.h
- case CREATE_SCOPED_CONNECTION:
+ case CREATE_CONNECTION:
case GET_COLOR_MANAGEMENT:
- case GET_COMPOSITION_PREFERENCE: {
+ case GET_COMPOSITION_PREFERENCE:
+ case GET_PROTECTED_CONTENT_SUPPORT:
+ case IS_WIDE_COLOR_DISPLAY: {
return OK;
}
case CAPTURE_LAYERS:
@@ -5144,7 +5294,7 @@
// Is VrFlinger active?
case 1028: {
Mutex::Autolock _l(mStateLock);
- reply->writeBool(getBE().mHwc->isUsingVrComposer());
+ reply->writeBool(getHwComposer().isUsingVrComposer());
return NO_ERROR;
}
// Is device color managed?
@@ -5194,6 +5344,11 @@
signalTransaction();
}
+void SurfaceFlinger::repaintEverythingForHWC() {
+ mRepaintEverything = true;
+ mEventQueue->invalidateForHWC();
+}
+
// A simple RAII class to disconnect from an ANativeWindow* when it goes out of scope
class WindowDisconnector {
public:
@@ -5261,12 +5416,15 @@
mFlinger(flinger),
mChildrenOnly(childrenOnly) {}
const ui::Transform& getTransform() const override { return mTransform; }
- Rect getBounds() const override { return mLayer->getBufferSize(StateSet::Drawing); }
+ Rect getBounds() const override {
+ const Layer::State& layerState(mLayer->getDrawingState());
+ return mLayer->getBufferSize(layerState);
+ }
int getHeight() const override {
- return mLayer->getBufferSize(StateSet::Drawing).getHeight();
+ return mLayer->getBufferSize(mLayer->getDrawingState()).getHeight();
}
int getWidth() const override {
- return mLayer->getBufferSize(StateSet::Drawing).getWidth();
+ return mLayer->getBufferSize(mLayer->getDrawingState()).getWidth();
}
bool isSecure() const override { return false; }
bool needsFiltering() const override { return mNeedsFiltering; }
@@ -5333,7 +5491,7 @@
const int uid = IPCThreadState::self()->getCallingUid();
const bool forSystem = uid == AID_GRAPHICS || uid == AID_SYSTEM;
- if (!forSystem && parent->getCurrentFlags() & layer_state_t::eLayerSecure) {
+ if (!forSystem && parent->getCurrentState().flags & layer_state_t::eLayerSecure) {
ALOGW("Attempting to capture secure layer: PERMISSION_DENIED");
return PERMISSION_DENIED;
}
@@ -5341,12 +5499,12 @@
Rect crop(sourceCrop);
if (sourceCrop.width() <= 0) {
crop.left = 0;
- crop.right = parent->getBufferSize(StateSet::Current).getWidth();
+ crop.right = parent->getBufferSize(parent->getCurrentState()).getWidth();
}
if (sourceCrop.height() <= 0) {
crop.top = 0;
- crop.bottom = parent->getBufferSize(StateSet::Current).getHeight();
+ crop.bottom = parent->getBufferSize(parent->getCurrentState()).getHeight();
}
int32_t reqWidth = crop.width() * frameScale;
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 822bb18..a127550 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -17,73 +17,71 @@
#ifndef ANDROID_SURFACE_FLINGER_H
#define ANDROID_SURFACE_FLINGER_H
-#include <memory>
-#include <stdint.h>
#include <sys/types.h>
/*
* NOTE: Make sure this file doesn't include anything from <gl/ > or <gl2/ >
*/
-#include <cutils/compiler.h>
+#include <android-base/thread_annotations.h>
#include <cutils/atomic.h>
-
-#include <utils/Errors.h>
-#include <utils/KeyedVector.h>
-#include <utils/RefBase.h>
-#include <utils/SortedVector.h>
-#include <utils/threads.h>
-#include <utils/Trace.h>
-
-#include <ui/FenceTime.h>
-#include <ui/PixelFormat.h>
-#include <math/mat4.h>
-
+#include <cutils/compiler.h>
+#include <gui/BufferQueue.h>
#include <gui/FrameTimestamps.h>
#include <gui/ISurfaceComposer.h>
#include <gui/ISurfaceComposerClient.h>
#include <gui/LayerState.h>
-
#include <gui/OccupancyTracker.h>
-#include <gui/BufferQueue.h>
-
#include <hardware/hwcomposer_defs.h>
-
+#include <layerproto/LayerProtoHeader.h>
+#include <math/mat4.h>
#include <serviceutils/PriorityDumper.h>
-
#include <system/graphics.h>
+#include <ui/FenceTime.h>
+#include <ui/PixelFormat.h>
+#include <utils/Errors.h>
+#include <utils/KeyedVector.h>
+#include <utils/RefBase.h>
+#include <utils/SortedVector.h>
+#include <utils/Trace.h>
+#include <utils/threads.h>
#include "Barrier.h"
+#include "BufferStateLayerCache.h"
#include "DisplayDevice.h"
+#include "DisplayHardware/HWC2.h"
+#include "DisplayHardware/HWComposer.h"
+#include "Effects/Daltonizer.h"
#include "FrameTracker.h"
#include "LayerBE.h"
#include "LayerStats.h"
#include "LayerVector.h"
+#include "Scheduler/DispSync.h"
+#include "Scheduler/EventThread.h"
+#include "Scheduler/MessageQueue.h"
+#include "Scheduler/PhaseOffsets.h"
+#include "Scheduler/RefreshRateStats.h"
+#include "Scheduler/Scheduler.h"
+#include "Scheduler/VSyncModulator.h"
#include "SurfaceFlingerFactory.h"
#include "SurfaceInterceptor.h"
#include "SurfaceTracing.h"
#include "TransactionCompletedThread.h"
-#include "DisplayHardware/HWC2.h"
-#include "DisplayHardware/HWComposer.h"
-#include "Effects/Daltonizer.h"
-#include "Scheduler/DispSync.h"
-#include "Scheduler/EventThread.h"
-#include "Scheduler/MessageQueue.h"
-#include "Scheduler/Scheduler.h"
-#include "Scheduler/VSyncModulator.h"
-
+#include <atomic>
+#include <cstdint>
+#include <functional>
#include <map>
+#include <memory>
#include <mutex>
#include <queue>
#include <set>
#include <string>
#include <thread>
+#include <type_traits>
#include <unordered_map>
#include <utility>
-#include <layerproto/LayerProtoHeader.h>
-
using namespace android::surfaceflinger;
namespace android {
@@ -106,6 +104,10 @@
class VSyncSource;
struct CompositionInfo;
+namespace compositionengine {
+class DisplaySurface;
+} // namespace compositionengine
+
namespace impl {
class EventThread;
} // namespace impl
@@ -140,41 +142,13 @@
ENHANCED = 2,
};
-
class SurfaceFlingerBE
{
public:
SurfaceFlingerBE();
- // The current hardware composer interface.
- //
- // The following thread safety rules apply when accessing mHwc, either
- // directly or via getHwComposer():
- //
- // 1. When recreating mHwc, acquire mStateLock. We currently recreate mHwc
- // only when switching into and out of vr. Recreating mHwc must only be
- // done on the main thread.
- //
- // 2. When accessing mHwc on the main thread, it's not necessary to acquire
- // mStateLock.
- //
- // 3. When accessing mHwc on a thread other than the main thread, we always
- // need to acquire mStateLock. This is because the main thread could be
- // in the process of destroying the current mHwc instance.
- //
- // The above thread safety rules only apply to SurfaceFlinger.cpp. In
- // SurfaceFlinger_hwc1.cpp we create mHwc at surface flinger init and never
- // destroy it, so it's always safe to access mHwc from any thread without
- // acquiring mStateLock.
- std::unique_ptr<HWComposer> mHwc;
-
const std::string mHwcServiceName; // "default" for real use, something else for testing.
- // constant members (no synchronization needed for access)
- std::unique_ptr<renderengine::RenderEngine> mRenderEngine;
- EGLContext mEGLContext;
- EGLDisplay mEGLDisplay;
-
FenceTimeline mGlCompositionDoneTimeline;
FenceTimeline mDisplayTimeline;
@@ -321,10 +295,6 @@
// starts SurfaceFlinger main loop in the current thread
void run() ANDROID_API;
- enum {
- EVENT_VSYNC = HWC_EVENT_VSYNC
- };
-
// post an asynchronous message to the main thread
status_t postMessageAsync(const sp<MessageBase>& msg, nsecs_t reltime = 0, uint32_t flags = 0);
@@ -334,8 +304,14 @@
// force full composition on all displays
void repaintEverything();
+ // force full composition on all displays without resetting the scheduler idle timer.
+ void repaintEverythingForHWC();
+
surfaceflinger::Factory& getFactory() { return mFactory; }
+ // The CompositionEngine encapsulates all composition related interfaces and actions.
+ compositionengine::CompositionEngine& getCompositionEngine() const;
+
// returns the default Display
sp<const DisplayDevice> getDefaultDisplayDevice() const {
Mutex::Autolock _l(mStateLock);
@@ -362,7 +338,7 @@
// TODO: this should be made accessible only to HWComposer
const Vector<sp<Layer>>& getLayerSortedByZForHwcDisplay(DisplayId displayId);
- renderengine::RenderEngine& getRenderEngine() const { return *getBE().mRenderEngine; }
+ renderengine::RenderEngine& getRenderEngine() const;
bool authenticateSurfaceTextureLocked(
const sp<IGraphicBufferProducer>& bufferProducer) const;
@@ -429,77 +405,80 @@
/* ------------------------------------------------------------------------
* IBinder interface
*/
- virtual status_t onTransact(uint32_t code, const Parcel& data,
- Parcel* reply, uint32_t flags);
- virtual status_t dump(int fd, const Vector<String16>& args) { return priorityDump(fd, args); }
+ status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) override;
+ status_t dump(int fd, const Vector<String16>& args) override { return priorityDump(fd, args); }
/* ------------------------------------------------------------------------
* ISurfaceComposer interface
*/
- virtual sp<ISurfaceComposerClient> createConnection();
- virtual sp<ISurfaceComposerClient> createScopedConnection(const sp<IGraphicBufferProducer>& gbp);
- virtual sp<IBinder> createDisplay(const String8& displayName, bool secure);
- virtual void destroyDisplay(const sp<IBinder>& displayToken);
- virtual sp<IBinder> getBuiltInDisplay(int32_t id);
- virtual void setTransactionState(const Vector<ComposerState>& state,
- const Vector<DisplayState>& displays, uint32_t flags,
- const sp<IBinder>& applyToken);
- virtual void bootFinished();
- virtual bool authenticateSurfaceTexture(
- const sp<IGraphicBufferProducer>& bufferProducer) const;
- virtual status_t getSupportedFrameTimestamps(
- std::vector<FrameEvent>* outSupported) const;
- virtual sp<IDisplayEventConnection> createDisplayEventConnection(
- ISurfaceComposer::VsyncSource vsyncSource = eVsyncSourceApp);
- virtual 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);
- virtual 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);
- virtual status_t getDisplayStats(const sp<IBinder>& displayToken, DisplayStatInfo* stats);
- virtual status_t getDisplayConfigs(const sp<IBinder>& displayToken,
- Vector<DisplayInfo>* configs);
- virtual int getActiveConfig(const sp<IBinder>& displayToken);
- virtual status_t getDisplayColorModes(const sp<IBinder>& displayToken,
- Vector<ui::ColorMode>* configs);
- virtual ui::ColorMode getActiveColorMode(const sp<IBinder>& displayToken);
- virtual status_t setActiveColorMode(const sp<IBinder>& displayToken, ui::ColorMode colorMode);
- virtual void setPowerMode(const sp<IBinder>& displayToken, int mode);
- virtual status_t setActiveConfig(const sp<IBinder>& displayToken, int id);
- virtual status_t clearAnimationFrameStats();
- virtual status_t getAnimationFrameStats(FrameStats* outStats) const;
- virtual status_t getHdrCapabilities(const sp<IBinder>& displayToken,
- HdrCapabilities* outCapabilities) const;
- virtual status_t enableVSyncInjections(bool enable);
- virtual status_t injectVSync(nsecs_t when);
- virtual status_t getLayerDebugInfo(std::vector<LayerDebugInfo>* outLayers) const;
- virtual status_t getColorManagement(bool* outGetColorManagement) const;
+ sp<ISurfaceComposerClient> createConnection() override;
+ sp<IBinder> createDisplay(const String8& displayName, bool secure) override;
+ void destroyDisplay(const sp<IBinder>& displayToken) override;
+ sp<IBinder> getBuiltInDisplay(int32_t id) override;
+ void setTransactionState(const Vector<ComposerState>& state,
+ const Vector<DisplayState>& displays, uint32_t flags,
+ const sp<IBinder>& applyToken,
+ const InputWindowCommands& inputWindowCommands,
+ int64_t desiredPresentTime) override;
+ void bootFinished() override;
+ bool authenticateSurfaceTexture(
+ const sp<IGraphicBufferProducer>& bufferProducer) const override;
+ status_t getSupportedFrameTimestamps(std::vector<FrameEvent>* outSupported) const override;
+ sp<IDisplayEventConnection> createDisplayEventConnection(
+ ISurfaceComposer::VsyncSource vsyncSource = eVsyncSourceApp) override;
+ 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;
+ 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;
+ status_t getDisplayStats(const sp<IBinder>& displayToken, DisplayStatInfo* stats) override;
+ status_t getDisplayConfigs(const sp<IBinder>& displayToken,
+ Vector<DisplayInfo>* configs) override;
+ int getActiveConfig(const sp<IBinder>& displayToken) override;
+ status_t getDisplayColorModes(const sp<IBinder>& displayToken,
+ Vector<ui::ColorMode>* configs) override;
+ status_t getDisplayNativePrimaries(const sp<IBinder>& displayToken,
+ ui::DisplayPrimaries &primaries);
+ ui::ColorMode getActiveColorMode(const sp<IBinder>& displayToken) override;
+ status_t setActiveColorMode(const sp<IBinder>& displayToken, ui::ColorMode colorMode) override;
+ void setPowerMode(const sp<IBinder>& displayToken, int mode) override;
+ status_t setActiveConfig(const sp<IBinder>& displayToken, int id) override;
+ status_t clearAnimationFrameStats() override;
+ status_t getAnimationFrameStats(FrameStats* outStats) const override;
+ status_t getHdrCapabilities(const sp<IBinder>& displayToken,
+ HdrCapabilities* outCapabilities) const override;
+ status_t enableVSyncInjections(bool enable) override;
+ status_t injectVSync(nsecs_t when) override;
+ status_t getLayerDebugInfo(std::vector<LayerDebugInfo>* outLayers) const override;
+ status_t getColorManagement(bool* outGetColorManagement) const override;
status_t getCompositionPreference(ui::Dataspace* outDataspace, ui::PixelFormat* outPixelFormat,
ui::Dataspace* outWideColorGamutDataspace,
ui::PixelFormat* outWideColorGamutPixelFormat) const override;
- virtual status_t getDisplayedContentSamplingAttributes(
- const sp<IBinder>& display, ui::PixelFormat* outFormat, ui::Dataspace* outDataspace,
- uint8_t* outComponentMask) const override;
- virtual status_t setDisplayContentSamplingEnabled(const sp<IBinder>& display, bool enable,
- uint8_t componentMask,
- uint64_t maxFrames) const override;
- virtual status_t getDisplayedContentSample(const sp<IBinder>& display, uint64_t maxFrames,
- uint64_t timestamp,
- DisplayedFrameStats* outStats) const override;
+ status_t getDisplayedContentSamplingAttributes(const sp<IBinder>& display,
+ ui::PixelFormat* outFormat,
+ ui::Dataspace* outDataspace,
+ uint8_t* outComponentMask) const override;
+ status_t setDisplayContentSamplingEnabled(const sp<IBinder>& display, bool enable,
+ uint8_t componentMask,
+ uint64_t maxFrames) const override;
+ status_t getDisplayedContentSample(const sp<IBinder>& display, uint64_t maxFrames,
+ uint64_t timestamp,
+ DisplayedFrameStats* outStats) const override;
+ status_t getProtectedContentSupport(bool* outSupported) const override;
+ status_t isWideColorDisplay(const sp<IBinder>& displayToken,
+ bool* outIsWideColorDisplay) const override;
/* ------------------------------------------------------------------------
* DeathRecipient interface
*/
- virtual void binderDied(const wp<IBinder>& who);
+ void binderDied(const wp<IBinder>& who) override;
/* ------------------------------------------------------------------------
* RefBase interface
*/
- virtual void onFirstRef();
+ void onFirstRef() override;
/* ------------------------------------------------------------------------
* HWC2::ComposerCallback / HWComposer::EventHandler interface
@@ -521,15 +500,13 @@
void signalRefresh();
// called on the main thread in response to initializeDisplays()
- void onInitializeDisplays();
+ void onInitializeDisplays() REQUIRES(mStateLock);
+ // setActiveConfigInternal() posted on a main thread for async execution
+ status_t setActiveConfigAsync(const sp<IBinder>& displayToken, int mode);
// called on the main thread in response to setActiveConfig()
- void setActiveConfigInternal(const sp<DisplayDevice>& display, int mode);
+ void setActiveConfigInternal(const sp<IBinder>& displayToken, int mode) REQUIRES(mStateLock);
// called on the main thread in response to setPowerMode()
- void setPowerModeInternal(const sp<DisplayDevice>& display, int mode);
-
- // Called on the main thread in response to setActiveColorMode()
- void setActiveColorModeInternal(const sp<DisplayDevice>& display, ui::ColorMode colorMode,
- ui::Dataspace dataSpace, ui::RenderIntent renderIntent);
+ void setPowerModeInternal(const sp<DisplayDevice>& display, int mode) REQUIRES(mStateLock);
// Returns whether the transaction actually modified any state
bool handleMessageTransaction();
@@ -543,6 +520,7 @@
void handleTransactionLocked(uint32_t transactionFlags);
void updateInputWindows();
+ void executeInputWindowCommands();
void updateCursorAsync();
/* handlePageFlip - latch a new buffer if available and compute the dirty
@@ -555,8 +533,8 @@
* Transactions
*/
void applyTransactionState(const Vector<ComposerState>& state,
- const Vector<DisplayState>& displays, uint32_t flags)
- REQUIRES(mStateLock);
+ const Vector<DisplayState>& displays, uint32_t flags,
+ const InputWindowCommands& inputWindowCommands) REQUIRES(mStateLock);
bool flushTransactionQueues();
uint32_t getTransactionFlags(uint32_t flags);
uint32_t peekTransactionFlags();
@@ -566,18 +544,18 @@
void latchAndReleaseBuffer(const sp<Layer>& layer);
void commitTransaction();
bool containsAnyInvalidClientState(const Vector<ComposerState>& states);
- bool composerStateContainsUnsignaledFences(const Vector<ComposerState>& states);
+ bool transactionIsReadyToBeApplied(int64_t desiredPresentTime,
+ const Vector<ComposerState>& states);
uint32_t setClientStateLocked(const ComposerState& composerState);
uint32_t setDisplayStateLocked(const DisplayState& s);
- void setDestroyStateLocked(const ComposerState& composerState);
+ uint32_t addInputWindowCommands(const InputWindowCommands& inputWindowCommands);
/* ------------------------------------------------------------------------
* Layer management
*/
- status_t createLayer(const String8& name, const sp<Client>& client,
- uint32_t w, uint32_t h, PixelFormat format, uint32_t flags,
- int32_t windowType, int32_t ownerUid, sp<IBinder>* handle,
- sp<IGraphicBufferProducer>* gbp, sp<Layer>* parent);
+ status_t createLayer(const String8& name, const sp<Client>& client, uint32_t w, uint32_t h,
+ PixelFormat format, uint32_t flags, LayerMetadata metadata,
+ sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp, sp<Layer>* parent);
status_t createBufferQueueLayer(const sp<Client>& client, const String8& name, uint32_t w,
uint32_t h, uint32_t flags, PixelFormat& format,
@@ -598,27 +576,19 @@
String8 getUniqueLayerName(const String8& name);
- // called in response to the window-manager calling
- // ISurfaceComposerClient::destroySurface()
- status_t onLayerRemoved(const sp<Client>& client, const sp<IBinder>& handle);
-
- void markLayerPendingRemovalLocked(const Mutex& /* mStateLock */, const sp<Layer>& layer);
-
// called when all clients have released all their references to
// this layer meaning it is entirely safe to destroy all
// resources associated to this layer.
void onHandleDestroyed(sp<Layer>& layer);
-
- // remove a layer from SurfaceFlinger immediately
- status_t removeLayer(const sp<Layer>& layer);
- status_t removeLayerLocked(const Mutex&, const sp<Layer>& layer);
+ void markLayerPendingRemovalLocked(const sp<Layer>& layer);
// add a layer to SurfaceFlinger
status_t addClientLayer(const sp<Client>& client,
const sp<IBinder>& handle,
const sp<IGraphicBufferProducer>& gbc,
const sp<Layer>& lbc,
- const sp<Layer>& parent);
+ const sp<Layer>& parent,
+ bool addToCurrentState);
/* ------------------------------------------------------------------------
* Boot animation, on/off animations and screen capture
@@ -693,11 +663,35 @@
// 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
*/
- HWComposer& getHwComposer() const { return *getBE().mHwc; }
+ // The current hardware composer interface.
+ //
+ // The following thread safety rules apply when accessing mHwc, either
+ // directly or via getHwComposer():
+ //
+ // 1. When recreating mHwc, acquire mStateLock. We currently recreate mHwc
+ // only when switching into and out of vr. Recreating mHwc must only be
+ // done on the main thread.
+ //
+ // 2. When accessing mHwc on the main thread, it's not necessary to acquire
+ // mStateLock.
+ //
+ // 3. When accessing mHwc on a thread other than the main thread, we always
+ // need to acquire mStateLock. This is because the main thread could be
+ // in the process of destroying the current mHwc instance.
+ //
+ // The above thread safety rules only apply to SurfaceFlinger.cpp. In
+ // SurfaceFlinger_hwc1.cpp we create mHwc at surface flinger init and never
+ // destroy it, so it's always safe to access mHwc from any thread without
+ // acquiring mStateLock.
+ HWComposer& getHwComposer() const;
/* ------------------------------------------------------------------------
* Compositing
@@ -708,6 +702,7 @@
void preComposition();
void postComposition();
+ void getCompositorTiming(CompositorTiming* compositorTiming);
void updateCompositorTiming(const DisplayStatInfo& stats, nsecs_t compositeTime,
std::shared_ptr<FenceTime>& presentFenceTime);
void setCompositorTimingSnapped(const DisplayStatInfo& stats,
@@ -751,39 +746,54 @@
/* ------------------------------------------------------------------------
* Display management
*/
- sp<DisplayDevice> setupNewDisplayDeviceInternal(const wp<IBinder>& displayToken,
- const std::optional<DisplayId>& displayId,
- const DisplayDeviceState& state,
- const sp<DisplaySurface>& dispSurface,
- const sp<IGraphicBufferProducer>& producer);
+ sp<DisplayDevice> setupNewDisplayDeviceInternal(
+ const wp<IBinder>& displayToken, const std::optional<DisplayId>& displayId,
+ const DisplayDeviceState& state,
+ const sp<compositionengine::DisplaySurface>& dispSurface,
+ const sp<IGraphicBufferProducer>& producer);
void processDisplayChangesLocked();
void processDisplayHotplugEventsLocked();
+ void dispatchDisplayHotplugEvent(EventThread::DisplayType displayType, bool connected);
+
/* ------------------------------------------------------------------------
* VSync
*/
+ nsecs_t getVsyncPeriod() const REQUIRES(mStateLock);
void enableHardwareVsync();
- void resyncToHardwareVsync(bool makeAvailable);
+ void resyncToHardwareVsync(bool makeAvailable, nsecs_t period);
void disableHardwareVsync(bool makeUnavailable);
-public:
- void resyncWithRateLimit();
- void getCompositorTiming(CompositorTiming* compositorTiming);
-private:
+ // Sets the refresh rate to newFps by switching active configs, if they are available for
+ // the desired refresh rate.
+ void setRefreshRateTo(float newFps);
- /* ------------------------------------------------------------------------
- * Debugging & dumpsys
+ using GetVsyncPeriod = std::function<nsecs_t()>;
+
+ // Stores per-display state about VSYNC.
+ struct VsyncState {
+ explicit VsyncState(SurfaceFlinger& flinger) : flinger(flinger) {}
+
+ void resync(const GetVsyncPeriod&);
+
+ SurfaceFlinger& flinger;
+ std::atomic<nsecs_t> lastResyncTime = 0;
+ };
+
+ const std::shared_ptr<VsyncState> mPrimaryVsyncState{std::make_shared<VsyncState>(*this)};
+
+ auto makeResyncCallback(GetVsyncPeriod&& getVsyncPeriod) {
+ std::weak_ptr<VsyncState> ptr = mPrimaryVsyncState;
+ return [ptr, getVsyncPeriod = std::move(getVsyncPeriod)]() {
+ if (const auto vsync = ptr.lock()) {
+ vsync->resync(getVsyncPeriod);
+ }
+ };
+ }
+
+ /*
+ * Display identification
*/
-public:
- status_t dumpCritical(int fd, const Vector<String16>& /*args*/, bool asProto) {
- return doDump(fd, Vector<String16>(), asProto);
- }
-
- status_t dumpAll(int fd, const Vector<String16>& args, bool asProto) {
- return doDump(fd, args, asProto);
- }
-
-private:
sp<IBinder> getPhysicalDisplayToken(DisplayId displayId) const {
const auto it = mPhysicalDisplayTokens.find(displayId);
return it != mPhysicalDisplayTokens.end() ? it->second : nullptr;
@@ -815,15 +825,46 @@
return hwcDisplayId ? getHwComposer().toPhysicalDisplayId(*hwcDisplayId) : std::nullopt;
}
- void listLayersLocked(const Vector<String16>& args, size_t& index, std::string& result) const;
- void dumpStatsLocked(const Vector<String16>& args, size_t& index, std::string& result) const;
- void clearStatsLocked(const Vector<String16>& args, size_t& index, std::string& result);
- void dumpAllLocked(const Vector<String16>& args, size_t& index, std::string& result) const;
- bool startDdmConnection();
- void appendSfConfigString(std::string& result) const;
+ /*
+ * Debugging & dumpsys
+ */
+ using DumpArgs = Vector<String16>;
+ using Dumper = std::function<void(const DumpArgs&, bool asProto, std::string&)>;
+ template <typename F, std::enable_if_t<!std::is_member_function_pointer_v<F>>* = nullptr>
+ static Dumper dumper(F&& dump) {
+ using namespace std::placeholders;
+ return std::bind(std::forward<F>(dump), _3);
+ }
+
+ template <typename F, std::enable_if_t<std::is_member_function_pointer_v<F>>* = nullptr>
+ Dumper dumper(F dump) {
+ using namespace std::placeholders;
+ return std::bind(dump, this, _3);
+ }
+
+ template <typename F>
+ Dumper argsDumper(F dump) {
+ using namespace std::placeholders;
+ return std::bind(dump, this, _1, _3);
+ }
+
+ template <typename F>
+ Dumper protoDumper(F dump) {
+ using namespace std::placeholders;
+ return std::bind(dump, this, _1, _2, _3);
+ }
+
+ void dumpAllLocked(const DumpArgs& args, std::string& result) const REQUIRES(mStateLock);
+
+ void appendSfConfigString(std::string& result) const;
+ void listLayersLocked(std::string& result) const;
+ void dumpStatsLocked(const DumpArgs& args, std::string& result) const REQUIRES(mStateLock);
+ void clearStatsLocked(const DumpArgs& args, std::string& result);
+ void dumpTimeStats(const DumpArgs& args, bool asProto, std::string& result) const;
void logFrameStats();
+ void dumpVSync(std::string& result) const REQUIRES(mStateLock);
void dumpStaticScreenStats(std::string& result) const;
// Not const because each Layer needs to query Fences and cache timestamps.
void dumpFrameEventsLocked(std::string& result);
@@ -840,7 +881,16 @@
bool isLayerTripleBufferingDisabled() const {
return this->mLayerTripleBufferingDisabled;
}
- status_t doDump(int fd, const Vector<String16>& args, bool asProto);
+
+ status_t doDump(int fd, const DumpArgs& args, bool asProto);
+
+ status_t dumpCritical(int fd, const DumpArgs&, bool asProto) override {
+ return doDump(fd, DumpArgs(), asProto);
+ }
+
+ status_t dumpAll(int fd, const DumpArgs& args, bool asProto) override {
+ return doDump(fd, args, asProto);
+ }
/* ------------------------------------------------------------------------
* VrFlinger
@@ -894,7 +944,10 @@
std::unique_ptr<EventControlThread> mEventControlThread;
std::unordered_map<DisplayId, sp<IBinder>> mPhysicalDisplayTokens;
+ // Calculates correct offsets.
VSyncModulator mVsyncModulator;
+ // Keeps track of all available phase offsets for different refresh types.
+ std::unique_ptr<scheduler::PhaseOffsets> mPhaseOffsets;
// Can only accessed from the main thread, these members
// don't need synchronization
@@ -926,7 +979,6 @@
// don't use a lock for these, we don't care
int mDebugRegion;
- int mDebugDDMS;
int mDebugDisableHWC;
int mDebugDisableTransformHint;
volatile nsecs_t mDebugInSwapBuffers;
@@ -938,7 +990,7 @@
std::unique_ptr<SurfaceInterceptor> mInterceptor{mFactory.createSurfaceInterceptor(this)};
SurfaceTracing mTracing;
LayerStats mLayerStats;
- std::unique_ptr<TimeStats> mTimeStats;
+ std::shared_ptr<TimeStats> mTimeStats;
bool mUseHwcVirtualDisplays = false;
std::atomic<uint32_t> mFrameMissedCount{0};
@@ -978,12 +1030,17 @@
};
struct TransactionState {
TransactionState(const Vector<ComposerState>& composerStates,
- const Vector<DisplayState>& displayStates, uint32_t transactionFlags)
- : states(composerStates), displays(displayStates), flags(transactionFlags) {}
+ const Vector<DisplayState>& displayStates, uint32_t transactionFlags,
+ int64_t desiredPresentTime)
+ : states(composerStates),
+ displays(displayStates),
+ flags(transactionFlags),
+ time(desiredPresentTime) {}
Vector<ComposerState> states;
Vector<DisplayState> displays;
uint32_t flags;
+ int64_t time;
};
std::unordered_map<sp<IBinder>, std::queue<TransactionState>, IBinderHash> mTransactionQueues;
@@ -1013,13 +1070,23 @@
ui::Dataspace mWideColorGamutCompositionDataspace;
SurfaceFlingerBE mBE;
+ std::unique_ptr<compositionengine::CompositionEngine> mCompositionEngine;
+ /* ------------------------------------------------------------------------
+ * Scheduler
+ */
bool mUseScheduler = false;
std::unique_ptr<Scheduler> mScheduler;
sp<Scheduler::ConnectionHandle> mAppConnectionHandle;
sp<Scheduler::ConnectionHandle> mSfConnectionHandle;
+ std::unique_ptr<scheduler::RefreshRateStats> mRefreshRateStats;
+ /* ------------------------------------------------------------------------ */
sp<IInputFlinger> mInputFlinger;
+
+ InputWindowCommands mInputWindowCommands;
+
+ ui::DisplayPrimaries mInternalDisplayPrimaries;
};
}; // namespace android
diff --git a/services/surfaceflinger/SurfaceFlingerFactory.cpp b/services/surfaceflinger/SurfaceFlingerFactory.cpp
index 88649e3..26d2c21 100644
--- a/services/surfaceflinger/SurfaceFlingerFactory.cpp
+++ b/services/surfaceflinger/SurfaceFlingerFactory.cpp
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#include <compositionengine/impl/CompositionEngine.h>
#include <ui/GraphicBuffer.h>
#include "BufferQueueLayer.h"
@@ -32,6 +33,7 @@
#include "Scheduler/DispSync.h"
#include "Scheduler/EventControlThread.h"
#include "Scheduler/MessageQueue.h"
+#include "Scheduler/PhaseOffsets.h"
#include "Scheduler/Scheduler.h"
#include "TimeStats/TimeStats.h"
@@ -59,7 +61,7 @@
}
std::unique_ptr<HWComposer> createHWComposer(const std::string& serviceName) override {
- return std::make_unique<HWComposer>(
+ return std::make_unique<android::impl::HWComposer>(
std::make_unique<Hwc2::impl::Composer>(serviceName));
}
@@ -67,6 +69,10 @@
return std::make_unique<android::impl::MessageQueue>();
}
+ std::unique_ptr<scheduler::PhaseOffsets> createPhaseOffsets() override {
+ return std::make_unique<scheduler::impl::PhaseOffsets>();
+ }
+
std::unique_ptr<Scheduler> createScheduler(std::function<void(bool)> callback) override {
return std::make_unique<Scheduler>(callback);
}
@@ -102,6 +108,10 @@
return surfaceflinger::impl::createNativeWindowSurface(producer);
}
+ std::unique_ptr<compositionengine::CompositionEngine> createCompositionEngine() override {
+ return compositionengine::impl::createCompositionEngine();
+ }
+
sp<ContainerLayer> createContainerLayer(const LayerCreationArgs& args) override {
return new ContainerLayer(args);
}
@@ -118,8 +128,8 @@
return new ColorLayer(args);
}
- std::unique_ptr<TimeStats> createTimeStats() override {
- return std::make_unique<TimeStats>();
+ std::shared_ptr<TimeStats> createTimeStats() override {
+ return std::make_shared<android::impl::TimeStats>();
}
};
static Factory factory;
diff --git a/services/surfaceflinger/SurfaceFlingerFactory.h b/services/surfaceflinger/SurfaceFlingerFactory.h
index 1c27cc7..fc1d0f8 100644
--- a/services/surfaceflinger/SurfaceFlingerFactory.h
+++ b/services/surfaceflinger/SurfaceFlingerFactory.h
@@ -49,6 +49,13 @@
struct DisplayDeviceCreationArgs;
struct LayerCreationArgs;
+namespace compositionengine {
+class CompositionEngine;
+} // namespace compositionengine
+
+namespace scheduler {
+class PhaseOffsets;
+} // namespace scheduler
namespace surfaceflinger {
class NativeWindowSurface;
@@ -63,6 +70,7 @@
std::function<void(bool)> setVSyncEnabled) = 0;
virtual std::unique_ptr<HWComposer> createHWComposer(const std::string& serviceName) = 0;
virtual std::unique_ptr<MessageQueue> createMessageQueue() = 0;
+ virtual std::unique_ptr<scheduler::PhaseOffsets> createPhaseOffsets() = 0;
virtual std::unique_ptr<Scheduler> createScheduler(std::function<void(bool)> callback) = 0;
virtual std::unique_ptr<SurfaceInterceptor> createSurfaceInterceptor(SurfaceFlinger*) = 0;
@@ -78,12 +86,14 @@
virtual std::unique_ptr<surfaceflinger::NativeWindowSurface> createNativeWindowSurface(
const sp<IGraphicBufferProducer>&) = 0;
+ virtual std::unique_ptr<compositionengine::CompositionEngine> createCompositionEngine() = 0;
+
virtual sp<BufferQueueLayer> createBufferQueueLayer(const LayerCreationArgs& args) = 0;
virtual sp<BufferStateLayer> createBufferStateLayer(const LayerCreationArgs& args) = 0;
virtual sp<ColorLayer> createColorLayer(const LayerCreationArgs& args) = 0;
virtual sp<ContainerLayer> createContainerLayer(const LayerCreationArgs& args) = 0;
- virtual std::unique_ptr<TimeStats> createTimeStats() = 0;
+ virtual std::shared_ptr<TimeStats> createTimeStats() = 0;
protected:
~Factory() = default;
diff --git a/services/surfaceflinger/SurfaceFlingerProperties.cpp b/services/surfaceflinger/SurfaceFlingerProperties.cpp
new file mode 100644
index 0000000..b654ba7
--- /dev/null
+++ b/services/surfaceflinger/SurfaceFlingerProperties.cpp
@@ -0,0 +1,246 @@
+
+#include <sysprop/SurfaceFlingerProperties.sysprop.h>
+
+#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 <tuple>
+
+#include "SurfaceFlingerProperties.h"
+
+namespace android {
+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;
+
+int64_t vsync_event_phase_offset_ns(int64_t defaultValue) {
+ auto temp = SurfaceFlingerProperties::vsync_event_phase_offset_ns();
+ if (temp.has_value()) {
+ return *temp;
+ }
+ return getInt64<ISurfaceFlingerConfigs, &ISurfaceFlingerConfigs::vsyncEventPhaseOffsetNs>(
+ defaultValue);
+}
+
+int64_t vsync_sf_event_phase_offset_ns(int64_t defaultValue) {
+ auto temp = SurfaceFlingerProperties::vsync_sf_event_phase_offset_ns();
+ if (temp.has_value()) {
+ return *temp;
+ }
+ return getInt64<ISurfaceFlingerConfigs, &ISurfaceFlingerConfigs::vsyncSfEventPhaseOffsetNs>(
+ defaultValue);
+}
+
+bool use_context_priority(bool defaultValue) {
+ auto temp = SurfaceFlingerProperties::use_context_priority();
+ if (temp.has_value()) {
+ return *temp;
+ }
+ return getBool<ISurfaceFlingerConfigs, &ISurfaceFlingerConfigs::useContextPriority>(
+ defaultValue);
+}
+
+int64_t max_frame_buffer_acquired_buffers(int64_t defaultValue) {
+ auto temp = SurfaceFlingerProperties::max_frame_buffer_acquired_buffers();
+ if (temp.has_value()) {
+ return *temp;
+ }
+ return getInt64<ISurfaceFlingerConfigs, &ISurfaceFlingerConfigs::maxFrameBufferAcquiredBuffers>(
+ defaultValue);
+}
+
+bool has_wide_color_display(bool defaultValue) {
+ auto temp = SurfaceFlingerProperties::has_wide_color_display();
+ if (temp.has_value()) {
+ return *temp;
+ }
+ return getBool<ISurfaceFlingerConfigs, &ISurfaceFlingerConfigs::hasWideColorDisplay>(
+ defaultValue);
+}
+
+bool running_without_sync_framework(bool defaultValue) {
+ auto temp = SurfaceFlingerProperties::running_without_sync_framework();
+ if (temp.has_value()) {
+ return !(*temp);
+ }
+ return getBool<ISurfaceFlingerConfigs, &ISurfaceFlingerConfigs::hasSyncFramework>(defaultValue);
+}
+
+bool has_HDR_display(bool defaultValue) {
+ auto temp = SurfaceFlingerProperties::has_HDR_display();
+ if (temp.has_value()) {
+ return *temp;
+ }
+ return getBool<ISurfaceFlingerConfigs, &ISurfaceFlingerConfigs::hasHDRDisplay>(defaultValue);
+}
+
+int64_t present_time_offset_from_vsync_ns(int64_t defaultValue) {
+ auto temp = SurfaceFlingerProperties::present_time_offset_from_vsync_ns();
+ if (temp.has_value()) {
+ return *temp;
+ }
+ return getInt64<ISurfaceFlingerConfigs, &ISurfaceFlingerConfigs::presentTimeOffsetFromVSyncNs>(
+ defaultValue);
+}
+
+bool force_hwc_copy_for_virtual_displays(bool defaultValue) {
+ auto temp = SurfaceFlingerProperties::force_hwc_copy_for_virtual_displays();
+ if (temp.has_value()) {
+ return *temp;
+ }
+ return getBool<ISurfaceFlingerConfigs, &ISurfaceFlingerConfigs::useHwcForRGBtoYUV>(
+ defaultValue);
+}
+
+int64_t max_virtual_display_dimension(int64_t defaultValue) {
+ auto temp = SurfaceFlingerProperties::max_virtual_display_dimension();
+ if (temp.has_value()) {
+ return *temp;
+ }
+ return getUInt64<ISurfaceFlingerConfigs, &ISurfaceFlingerConfigs::maxVirtualDisplaySize>(
+ defaultValue);
+}
+
+bool use_vr_flinger(bool defaultValue) {
+ auto temp = SurfaceFlingerProperties::use_vr_flinger();
+ if (temp.has_value()) {
+ return *temp;
+ }
+ return getBool<ISurfaceFlingerConfigs, &ISurfaceFlingerConfigs::useVrFlinger>(defaultValue);
+}
+
+bool start_graphics_allocator_service(bool defaultValue) {
+ auto temp = SurfaceFlingerProperties::start_graphics_allocator_service();
+ if (temp.has_value()) {
+ return *temp;
+ }
+ return getBool<ISurfaceFlingerConfigs, &ISurfaceFlingerConfigs::startGraphicsAllocatorService>(
+ defaultValue);
+}
+
+SurfaceFlingerProperties::primary_display_orientation_values primary_display_orientation(
+ SurfaceFlingerProperties::primary_display_orientation_values defaultValue) {
+ auto temp = SurfaceFlingerProperties::primary_display_orientation();
+ if (temp.has_value()) {
+ return *temp;
+ }
+ auto configDefault = DisplayOrientation::ORIENTATION_0;
+ switch (defaultValue) {
+ case SurfaceFlingerProperties::primary_display_orientation_values::ORIENTATION_90:
+ configDefault = DisplayOrientation::ORIENTATION_90;
+ break;
+ case SurfaceFlingerProperties::primary_display_orientation_values::ORIENTATION_180:
+ configDefault = DisplayOrientation::ORIENTATION_180;
+ break;
+ case SurfaceFlingerProperties::primary_display_orientation_values::ORIENTATION_270:
+ configDefault = DisplayOrientation::ORIENTATION_270;
+ break;
+ default:
+ configDefault = DisplayOrientation::ORIENTATION_0;
+ break;
+ }
+ DisplayOrientation result =
+ getDisplayOrientation<V1_1::ISurfaceFlingerConfigs,
+ &V1_1::ISurfaceFlingerConfigs::primaryDisplayOrientation>(
+ configDefault);
+ switch (result) {
+ case DisplayOrientation::ORIENTATION_90:
+ return SurfaceFlingerProperties::primary_display_orientation_values::ORIENTATION_90;
+ case DisplayOrientation::ORIENTATION_180:
+ return SurfaceFlingerProperties::primary_display_orientation_values::ORIENTATION_180;
+ case DisplayOrientation::ORIENTATION_270:
+ return SurfaceFlingerProperties::primary_display_orientation_values::ORIENTATION_270;
+ default:
+ break;
+ }
+ return SurfaceFlingerProperties::primary_display_orientation_values::ORIENTATION_0;
+}
+
+bool use_color_management(bool defaultValue) {
+ auto tmpuseColorManagement = SurfaceFlingerProperties::use_color_management();
+ auto tmpHasHDRDisplay = SurfaceFlingerProperties::has_HDR_display();
+ auto tmpHasWideColorDisplay = SurfaceFlingerProperties::has_wide_color_display();
+ if (tmpuseColorManagement.has_value() && tmpHasHDRDisplay.has_value() &&
+ 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);
+}
+
+int32_t default_composition_pixel_format(PixelFormat defaultValue) {
+ auto temp = SurfaceFlingerProperties::default_composition_pixel_format();
+ 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);
+}
+
+int64_t wcg_composition_dataspace(Dataspace defaultValue) {
+ auto temp = SurfaceFlingerProperties::wcg_composition_dataspace();
+ 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);
+}
+
+int32_t wcg_composition_pixel_format(PixelFormat defaultValue) {
+ auto temp = SurfaceFlingerProperties::wcg_composition_pixel_format();
+ 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);
+}
+
+} // namespace sysprop
+} // namespace android
diff --git a/services/surfaceflinger/SurfaceFlingerProperties.h b/services/surfaceflinger/SurfaceFlingerProperties.h
new file mode 100644
index 0000000..9b26883
--- /dev/null
+++ b/services/surfaceflinger/SurfaceFlingerProperties.h
@@ -0,0 +1,58 @@
+
+#ifndef SURFACEFLINGERPROPERTIES_H_
+#define SURFACEFLINGERPROPERTIES_H_
+
+#include <android/hardware/configstore/1.1/ISurfaceFlingerConfigs.h>
+#include <android/hardware/configstore/1.2/ISurfaceFlingerConfigs.h>
+#include <sysprop/SurfaceFlingerProperties.sysprop.h>
+
+#include <cstdint>
+#include <optional>
+#include <vector>
+
+namespace android {
+namespace sysprop {
+
+int64_t vsync_event_phase_offset_ns(int64_t defaultValue);
+
+int64_t vsync_sf_event_phase_offset_ns(int64_t defaultValue);
+
+bool use_context_priority(bool defaultValue);
+
+int64_t max_frame_buffer_acquired_buffers(int64_t defaultValue);
+
+bool has_wide_color_display(bool defaultValue);
+
+bool running_without_sync_framework(bool defaultValue);
+
+bool has_HDR_display(bool defaultValue);
+
+int64_t present_time_offset_from_vsync_ns(int64_t defaultValue);
+
+bool force_hwc_copy_for_virtual_displays(bool defaultValue);
+
+int64_t max_virtual_display_dimension(int64_t defaultValue);
+
+bool use_vr_flinger(bool defaultValue);
+
+bool start_graphics_allocator_service(bool defaultValue);
+
+SurfaceFlingerProperties::primary_display_orientation_values primary_display_orientation(
+ SurfaceFlingerProperties::primary_display_orientation_values defaultValue);
+
+bool use_color_management(bool defaultValue);
+
+int64_t default_composition_dataspace(
+ android::hardware::graphics::common::V1_2::Dataspace defaultValue);
+
+int32_t default_composition_pixel_format(
+ android::hardware::graphics::common::V1_2::PixelFormat defaultValue);
+
+int64_t wcg_composition_dataspace(
+ android::hardware::graphics::common::V1_2::Dataspace defaultValue);
+
+int32_t wcg_composition_pixel_format(
+ android::hardware::graphics::common::V1_2::PixelFormat defaultValue);
+} // namespace sysprop
+} // namespace android
+#endif // SURFACEFLINGERPROPERTIES_H_
diff --git a/services/surfaceflinger/SurfaceInterceptor.cpp b/services/surfaceflinger/SurfaceInterceptor.cpp
index a6dcb7e..7bfe033 100644
--- a/services/surfaceflinger/SurfaceInterceptor.cpp
+++ b/services/surfaceflinger/SurfaceInterceptor.cpp
@@ -101,23 +101,22 @@
transaction->set_animation(layerFlags & BnSurfaceComposer::eAnimation);
const int32_t layerId(getLayerId(layer));
- Mutex::Autolock lock(layer->mStateMutex);
- addPositionLocked(transaction, layerId, layer->mState.current.active_legacy.transform.tx(),
- layer->mState.current.active_legacy.transform.ty());
- addDepthLocked(transaction, layerId, layer->mState.current.z);
- addAlphaLocked(transaction, layerId, layer->mState.current.color.a);
+ addPositionLocked(transaction, layerId, layer->mCurrentState.active_legacy.transform.tx(),
+ layer->mCurrentState.active_legacy.transform.ty());
+ addDepthLocked(transaction, layerId, layer->mCurrentState.z);
+ addAlphaLocked(transaction, layerId, layer->mCurrentState.color.a);
addTransparentRegionLocked(transaction, layerId,
- layer->mState.current.activeTransparentRegion_legacy);
- addLayerStackLocked(transaction, layerId, layer->mState.current.layerStack);
- addCropLocked(transaction, layerId, layer->mState.current.crop_legacy);
- addCornerRadiusLocked(transaction, layerId, layer->mState.current.cornerRadius);
- if (layer->mState.current.barrierLayer_legacy != nullptr) {
+ layer->mCurrentState.activeTransparentRegion_legacy);
+ addLayerStackLocked(transaction, layerId, layer->mCurrentState.layerStack);
+ addCropLocked(transaction, layerId, layer->mCurrentState.crop_legacy);
+ addCornerRadiusLocked(transaction, layerId, layer->mCurrentState.cornerRadius);
+ if (layer->mCurrentState.barrierLayer_legacy != nullptr) {
addDeferTransactionLocked(transaction, layerId,
- layer->mState.current.barrierLayer_legacy.promote(),
- layer->mState.current.frameNumber_legacy);
+ layer->mCurrentState.barrierLayer_legacy.promote(),
+ layer->mCurrentState.frameNumber_legacy);
}
addOverrideScalingModeLocked(transaction, layerId, layer->getEffectiveScalingMode());
- addFlagsLocked(transaction, layerId, layer->mState.current.flags);
+ addFlagsLocked(transaction, layerId, layer->mCurrentState.flags);
}
void SurfaceInterceptor::addInitialDisplayStateLocked(Increment* increment,
@@ -427,9 +426,8 @@
SurfaceCreation* creation(increment->mutable_surface_creation());
creation->set_id(getLayerId(layer));
creation->set_name(getLayerName(layer));
- Mutex::Autolock lock(layer->mStateMutex);
- creation->set_w(layer->mState.current.active_legacy.w);
- creation->set_h(layer->mState.current.active_legacy.h);
+ creation->set_w(layer->mCurrentState.active_legacy.w);
+ creation->set_h(layer->mCurrentState.active_legacy.h);
}
void SurfaceInterceptor::addSurfaceDeletionLocked(Increment* increment,
diff --git a/services/surfaceflinger/TEST_MAPPING b/services/surfaceflinger/TEST_MAPPING
new file mode 100644
index 0000000..cab33ae
--- /dev/null
+++ b/services/surfaceflinger/TEST_MAPPING
@@ -0,0 +1,10 @@
+{
+ "presubmit": [
+ {
+ "name": "libsurfaceflinger_unittest"
+ },
+ {
+ "name": "libcompositionengine_test"
+ }
+ ]
+}
diff --git a/services/surfaceflinger/TimeStats/TimeStats.cpp b/services/surfaceflinger/TimeStats/TimeStats.cpp
index 6a5488a..78c6e74 100644
--- a/services/surfaceflinger/TimeStats/TimeStats.cpp
+++ b/services/surfaceflinger/TimeStats/TimeStats.cpp
@@ -32,19 +32,14 @@
namespace android {
-void TimeStats::parseArgs(bool asProto, const Vector<String16>& args, size_t& index,
- std::string& result) {
+namespace impl {
+
+void TimeStats::parseArgs(bool asProto, const Vector<String16>& args, std::string& result) {
ATRACE_CALL();
- if (args.size() > index + 10) {
- ALOGD("Invalid args count");
- return;
- }
-
std::unordered_map<std::string, int32_t> argsMap;
- while (index < args.size()) {
+ for (size_t index = 0; index < args.size(); ++index) {
argsMap[std::string(String8(args[index]).c_str())] = index;
- ++index;
}
if (argsMap.count("-disable")) {
@@ -457,6 +452,15 @@
mPowerTime.powerMode = powerMode;
}
+void TimeStats::recordRefreshRate(uint32_t fps, nsecs_t duration) {
+ std::lock_guard<std::mutex> lock(mMutex);
+ if (mTimeStats.refreshRateStats.count(fps)) {
+ mTimeStats.refreshRateStats[fps] += duration;
+ } else {
+ mTimeStats.refreshRateStats.insert({fps, duration});
+ }
+}
+
void TimeStats::flushAvailableGlobalRecordsToStatsLocked() {
ATRACE_CALL();
@@ -554,6 +558,7 @@
mTimeStats.clientCompositionFrames = 0;
mTimeStats.displayOnTime = 0;
mTimeStats.presentToPresent.hist.clear();
+ mTimeStats.refreshRateStats.clear();
mPowerTime.prevTime = systemTime();
mGlobalRecord.prevPresentTime = 0;
mGlobalRecord.presentFences.clear();
@@ -587,4 +592,6 @@
}
}
+} // namespace impl
+
} // namespace android
diff --git a/services/surfaceflinger/TimeStats/TimeStats.h b/services/surfaceflinger/TimeStats/TimeStats.h
index 71c3ed7..d8c0786 100644
--- a/services/surfaceflinger/TimeStats/TimeStats.h
+++ b/services/surfaceflinger/TimeStats/TimeStats.h
@@ -36,6 +36,40 @@
namespace android {
class TimeStats {
+public:
+ virtual ~TimeStats() = default;
+
+ virtual void parseArgs(bool asProto, const Vector<String16>& args, std::string& result) = 0;
+ virtual bool isEnabled() = 0;
+
+ virtual void incrementTotalFrames() = 0;
+ virtual void incrementMissedFrames() = 0;
+ virtual void incrementClientCompositionFrames() = 0;
+
+ virtual void setPostTime(int32_t layerID, uint64_t frameNumber, const std::string& layerName,
+ nsecs_t postTime) = 0;
+ virtual void setLatchTime(int32_t layerID, uint64_t frameNumber, nsecs_t latchTime) = 0;
+ virtual void setDesiredTime(int32_t layerID, uint64_t frameNumber, nsecs_t desiredTime) = 0;
+ virtual void setAcquireTime(int32_t layerID, uint64_t frameNumber, nsecs_t acquireTime) = 0;
+ virtual void setAcquireFence(int32_t layerID, uint64_t frameNumber,
+ const std::shared_ptr<FenceTime>& acquireFence) = 0;
+ virtual void setPresentTime(int32_t layerID, uint64_t frameNumber, nsecs_t presentTime) = 0;
+ virtual void setPresentFence(int32_t layerID, uint64_t frameNumber,
+ const std::shared_ptr<FenceTime>& presentFence) = 0;
+ // Clean up the layer record
+ virtual void onDestroy(int32_t layerID) = 0;
+ // If SF skips or rejects a buffer, remove the corresponding TimeRecord.
+ virtual void removeTimeRecord(int32_t layerID, uint64_t frameNumber) = 0;
+
+ virtual void setPowerMode(int32_t powerMode) = 0;
+ // Source of truth is RefrehRateStats.
+ virtual void recordRefreshRate(uint32_t fps, nsecs_t duration) = 0;
+ virtual void setPresentFenceGlobal(const std::shared_ptr<FenceTime>& presentFence) = 0;
+};
+
+namespace impl {
+
+class TimeStats : public android::TimeStats {
struct FrameTime {
uint64_t frameNumber = 0;
nsecs_t postTime = 0;
@@ -75,32 +109,33 @@
public:
TimeStats() = default;
- ~TimeStats() = default;
- void parseArgs(bool asProto, const Vector<String16>& args, size_t& index, std::string& result);
- bool isEnabled();
+ void parseArgs(bool asProto, const Vector<String16>& args, std::string& result) override;
+ bool isEnabled() override;
- void incrementTotalFrames();
- void incrementMissedFrames();
- void incrementClientCompositionFrames();
+ void incrementTotalFrames() override;
+ void incrementMissedFrames() override;
+ void incrementClientCompositionFrames() override;
void setPostTime(int32_t layerID, uint64_t frameNumber, const std::string& layerName,
- nsecs_t postTime);
- void setLatchTime(int32_t layerID, uint64_t frameNumber, nsecs_t latchTime);
- void setDesiredTime(int32_t layerID, uint64_t frameNumber, nsecs_t desiredTime);
- void setAcquireTime(int32_t layerID, uint64_t frameNumber, nsecs_t acquireTime);
+ nsecs_t postTime) override;
+ void setLatchTime(int32_t layerID, uint64_t frameNumber, nsecs_t latchTime) override;
+ void setDesiredTime(int32_t layerID, uint64_t frameNumber, nsecs_t desiredTime) override;
+ void setAcquireTime(int32_t layerID, uint64_t frameNumber, nsecs_t acquireTime) override;
void setAcquireFence(int32_t layerID, uint64_t frameNumber,
- const std::shared_ptr<FenceTime>& acquireFence);
- void setPresentTime(int32_t layerID, uint64_t frameNumber, nsecs_t presentTime);
+ const std::shared_ptr<FenceTime>& acquireFence) override;
+ void setPresentTime(int32_t layerID, uint64_t frameNumber, nsecs_t presentTime) override;
void setPresentFence(int32_t layerID, uint64_t frameNumber,
- const std::shared_ptr<FenceTime>& presentFence);
+ const std::shared_ptr<FenceTime>& presentFence) override;
// Clean up the layer record
- void onDestroy(int32_t layerID);
+ void onDestroy(int32_t layerID) override;
// If SF skips or rejects a buffer, remove the corresponding TimeRecord.
- void removeTimeRecord(int32_t layerID, uint64_t frameNumber);
+ void removeTimeRecord(int32_t layerID, uint64_t frameNumber) override;
- void setPowerMode(int32_t powerMode);
- void setPresentFenceGlobal(const std::shared_ptr<FenceTime>& presentFence);
+ void setPowerMode(int32_t powerMode) override;
+ // Source of truth is RefrehRateStats.
+ void recordRefreshRate(uint32_t fps, nsecs_t duration) override;
+ void setPresentFenceGlobal(const std::shared_ptr<FenceTime>& presentFence) override;
// TODO(zzyiwei): Bound the timeStatsTracker with weighted LRU
// static const size_t MAX_NUM_LAYER_RECORDS = 200;
@@ -126,4 +161,6 @@
GlobalRecord mGlobalRecord;
};
+} // namespace impl
+
} // namespace android
diff --git a/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp b/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp
index 75ce4be..16d2da0 100644
--- a/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp
+++ b/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp
@@ -103,6 +103,11 @@
StringAppendF(&result, "missedFrames = %d\n", missedFrames);
StringAppendF(&result, "clientCompositionFrames = %d\n", clientCompositionFrames);
StringAppendF(&result, "displayOnTime = %" PRId64 " ms\n", displayOnTime);
+ StringAppendF(&result, "displayConfigStats is as below:\n");
+ for (const auto& [fps, duration] : refreshRateStats) {
+ StringAppendF(&result, "%dfps=%ldms ", fps, ns2ms(duration));
+ }
+ result.back() = '\n';
StringAppendF(&result, "totalP2PTime = %" PRId64 " ms\n", presentToPresent.totalTime());
StringAppendF(&result, "presentToPresent histogram is as below:\n");
result.append(presentToPresent.toString());
@@ -141,6 +146,13 @@
globalProto.set_missed_frames(missedFrames);
globalProto.set_client_composition_frames(clientCompositionFrames);
globalProto.set_display_on_time(displayOnTime);
+ for (const auto& ele : refreshRateStats) {
+ SFTimeStatsDisplayConfigBucketProto* configBucketProto =
+ globalProto.add_display_config_stats();
+ SFTimeStatsDisplayConfigProto* configProto = configBucketProto->mutable_config();
+ configProto->set_fps(ele.first);
+ configBucketProto->set_duration_millis(ns2ms(ele.second));
+ }
for (const auto& histEle : presentToPresent.hist) {
SFTimeStatsHistogramBucketProto* histProto = globalProto.add_present_to_present();
histProto->set_time_millis(histEle.first);
diff --git a/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h b/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h
index 5f40a1a..f2ac7ff 100644
--- a/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h
+++ b/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h
@@ -16,6 +16,7 @@
#pragma once
#include <timestatsproto/TimeStatsProtoHeader.h>
+#include <utils/Timers.h>
#include <optional>
#include <string>
@@ -61,6 +62,7 @@
int64_t displayOnTime = 0;
Histogram presentToPresent;
std::unordered_map<std::string, TimeStatsLayer> stats;
+ std::unordered_map<uint32_t, nsecs_t> refreshRateStats;
std::string toString(std::optional<uint32_t> maxLayers) const;
SFTimeStatsGlobalProto toProto(std::optional<uint32_t> maxLayers) const;
diff --git a/services/surfaceflinger/TimeStats/timestatsproto/timestats.proto b/services/surfaceflinger/TimeStats/timestatsproto/timestats.proto
index 377612a..0dacbeb 100644
--- a/services/surfaceflinger/TimeStats/timestatsproto/timestats.proto
+++ b/services/surfaceflinger/TimeStats/timestatsproto/timestats.proto
@@ -25,7 +25,7 @@
// changes to these messages, and keep google3 side proto messages in sync if
// the end to end pipeline needs to be updated.
-// Next tag: 9
+// Next tag: 10
message SFTimeStatsGlobalProto {
// The stats start time in UTC as seconds since January 1, 1970
optional int64 stats_start = 1;
@@ -39,6 +39,8 @@
optional int32 client_composition_frames = 5;
// Primary display on time in milliseconds.
optional int64 display_on_time = 7;
+ // Stats per display configuration.
+ repeated SFTimeStatsDisplayConfigBucketProto display_config_stats = 9;
// Present to present histogram.
repeated SFTimeStatsHistogramBucketProto present_to_present = 8;
// Stats per layer. Apps could have multiple layers.
@@ -80,3 +82,18 @@
// Number of frames in the bucket.
optional int32 frame_count = 2;
}
+
+// Next tag: 3
+message SFTimeStatsDisplayConfigBucketProto {
+ // Metadata desribing a display config.
+ optional SFTimeStatsDisplayConfigProto config = 1;
+ // Duration in milliseconds for how long the display was in this
+ // configuration.
+ optional int64 duration_millis = 2;
+}
+
+// Next tag: 2
+message SFTimeStatsDisplayConfigProto {
+ // Frames per second, rounded to the nearest integer.
+ optional int32 fps = 1;
+}
diff --git a/services/surfaceflinger/TransactionCompletedThread.cpp b/services/surfaceflinger/TransactionCompletedThread.cpp
index a1a8692..d2b7fe0 100644
--- a/services/surfaceflinger/TransactionCompletedThread.cpp
+++ b/services/surfaceflinger/TransactionCompletedThread.cpp
@@ -62,8 +62,7 @@
mThread = std::thread(&TransactionCompletedThread::threadMain, this);
}
-void TransactionCompletedThread::registerPendingLatchedCallbackHandle(
- const sp<CallbackHandle>& handle) {
+void TransactionCompletedThread::registerPendingCallbackHandle(const sp<CallbackHandle>& handle) {
std::lock_guard lock(mMutex);
sp<IBinder> listener = IInterface::asBinder(handle->listener);
@@ -72,19 +71,10 @@
mPendingTransactions[listener][callbackIds]++;
}
-void TransactionCompletedThread::addLatchedCallbackHandles(
- const std::deque<sp<CallbackHandle>>& handles, nsecs_t latchTime,
- const sp<Fence>& previousReleaseFence) {
+void TransactionCompletedThread::addPresentedCallbackHandles(
+ const std::deque<sp<CallbackHandle>>& handles) {
std::lock_guard lock(mMutex);
- // If the previous release fences have not signaled, something as probably gone wrong.
- // Store the fences and check them again before sending a callback.
- if (previousReleaseFence &&
- previousReleaseFence->getSignalTime() == Fence::SIGNAL_TIME_PENDING) {
- ALOGD("release fence from the previous frame has not signaled");
- mPreviousReleaseFences.push_back(previousReleaseFence);
- }
-
for (const auto& handle : handles) {
auto listener = mPendingTransactions.find(IInterface::asBinder(handle->listener));
auto& pendingCallbacks = listener->second;
@@ -101,17 +91,16 @@
ALOGE("there are more latched callbacks than there were registered callbacks");
}
- addCallbackHandle(handle, latchTime);
+ addCallbackHandle(handle);
}
}
-void TransactionCompletedThread::addUnlatchedCallbackHandle(const sp<CallbackHandle>& handle) {
+void TransactionCompletedThread::addUnpresentedCallbackHandle(const sp<CallbackHandle>& handle) {
std::lock_guard lock(mMutex);
addCallbackHandle(handle);
}
-void TransactionCompletedThread::addCallbackHandle(const sp<CallbackHandle>& handle,
- nsecs_t latchTime) {
+void TransactionCompletedThread::addCallbackHandle(const sp<CallbackHandle>& handle) {
const sp<IBinder> listener = IInterface::asBinder(handle->listener);
// If we don't already have a reference to this listener, linkToDeath so we get a notification
@@ -128,9 +117,9 @@
listenerStats.listener = handle->listener;
auto& transactionStats = listenerStats.transactionStats[handle->callbackIds];
- transactionStats.latchTime = latchTime;
+ transactionStats.latchTime = handle->latchTime;
transactionStats.surfaceStats.emplace_back(handle->surfaceControl, handle->acquireTime,
- handle->releasePreviousBuffer);
+ handle->previousReleaseFence);
}
void TransactionCompletedThread::addPresentFence(const sp<Fence>& presentFence) {
@@ -151,15 +140,6 @@
while (mKeepRunning) {
mConditionVariable.wait(mMutex);
- // We should never hit this case. The release fences from the previous frame should have
- // signaled long before the current frame is presented.
- for (const auto& fence : mPreviousReleaseFences) {
- status_t status = fence->wait(100);
- if (status != NO_ERROR) {
- ALOGE("previous release fence has not signaled, err %d", status);
- }
- }
-
// For each listener
auto it = mListenerStats.begin();
while (it != mListenerStats.end()) {
@@ -200,7 +180,6 @@
if (mPresentFence) {
mPresentFence.clear();
- mPreviousReleaseFences.clear();
}
}
}
diff --git a/services/surfaceflinger/TransactionCompletedThread.h b/services/surfaceflinger/TransactionCompletedThread.h
index 1612f69..f49306d 100644
--- a/services/surfaceflinger/TransactionCompletedThread.h
+++ b/services/surfaceflinger/TransactionCompletedThread.h
@@ -40,7 +40,9 @@
sp<IBinder> surfaceControl;
bool releasePreviousBuffer = false;
+ sp<Fence> previousReleaseFence;
nsecs_t acquireTime = -1;
+ nsecs_t latchTime = -1;
};
class TransactionCompletedThread {
@@ -54,14 +56,13 @@
// layer has received the CallbackHandle so the TransactionCompletedThread knows not to send
// a callback for that Listener/Transaction pair until that CallbackHandle has been latched and
// presented.
- void registerPendingLatchedCallbackHandle(const sp<CallbackHandle>& handle);
- // Notifies the TransactionCompletedThread that a pending CallbackHandle has been latched.
- void addLatchedCallbackHandles(const std::deque<sp<CallbackHandle>>& handles, nsecs_t latchTime,
- const sp<Fence>& previousReleaseFence);
+ void registerPendingCallbackHandle(const sp<CallbackHandle>& handle);
+ // Notifies the TransactionCompletedThread that a pending CallbackHandle has been presented.
+ void addPresentedCallbackHandles(const std::deque<sp<CallbackHandle>>& handles);
// Adds the Transaction CallbackHandle from a layer that does not need to be relatched and
// presented this frame.
- void addUnlatchedCallbackHandle(const sp<CallbackHandle>& handle);
+ void addUnpresentedCallbackHandle(const sp<CallbackHandle>& handle);
void addPresentFence(const sp<Fence>& presentFence);
@@ -70,8 +71,7 @@
private:
void threadMain();
- void addCallbackHandle(const sp<CallbackHandle>& handle, nsecs_t latchTime = -1)
- REQUIRES(mMutex);
+ void addCallbackHandle(const sp<CallbackHandle>& handle) REQUIRES(mMutex);
class ThreadDeathRecipient : public IBinder::DeathRecipient {
public:
@@ -110,7 +110,6 @@
bool mKeepRunning GUARDED_BY(mMutex) = true;
sp<Fence> mPresentFence GUARDED_BY(mMutex);
- std::vector<sp<Fence>> mPreviousReleaseFences GUARDED_BY(mMutex);
};
} // namespace android
diff --git a/services/surfaceflinger/layerproto/Android.bp b/services/surfaceflinger/layerproto/Android.bp
index ac147fe..cb368b0 100644
--- a/services/surfaceflinger/layerproto/Android.bp
+++ b/services/surfaceflinger/layerproto/Android.bp
@@ -1,6 +1,5 @@
cc_library_shared {
name: "liblayers_proto",
- vendor_available: true,
export_include_dirs: ["include"],
srcs: [
@@ -11,6 +10,7 @@
shared_libs: [
"android.hardware.graphics.common@1.1",
+ "libgui",
"libui",
"libprotobuf-cpp-lite",
"libbase",
diff --git a/services/surfaceflinger/layerproto/LayerProtoParser.cpp b/services/surfaceflinger/layerproto/LayerProtoParser.cpp
index d020a39..5c72fea 100644
--- a/services/surfaceflinger/layerproto/LayerProtoParser.cpp
+++ b/services/surfaceflinger/layerproto/LayerProtoParser.cpp
@@ -117,11 +117,15 @@
layer.hwcFrame = generateRect(layerProto.hwc_frame());
layer.hwcCrop = generateFloatRect(layerProto.hwc_crop());
layer.hwcTransform = layerProto.hwc_transform();
- layer.windowType = layerProto.window_type();
- layer.appId = layerProto.app_id();
layer.hwcCompositionType = layerProto.hwc_composition_type();
layer.isProtected = layerProto.is_protected();
layer.cornerRadius = layerProto.corner_radius();
+ for (const auto& entry : layerProto.metadata()) {
+ const std::string& dataStr = entry.second;
+ std::vector<uint8_t>& outData = layer.metadata.mMap[entry.first];
+ outData.resize(dataStr.size());
+ memcpy(outData.data(), dataStr.data(), dataStr.size());
+ }
return layer;
}
@@ -310,7 +314,14 @@
StringAppendF(&result, " activeBuffer=%s,", activeBuffer.to_string().c_str());
StringAppendF(&result, " tr=%s", bufferTransform.to_string().c_str());
StringAppendF(&result, " queued-frames=%d, mRefreshPending=%d,", queuedFrames, refreshPending);
- StringAppendF(&result, " windowType=%d, appId=%d", windowType, appId);
+ StringAppendF(&result, " metadata={");
+ bool first = true;
+ for (const auto& entry : metadata.mMap) {
+ if (!first) result.append(", ");
+ first = false;
+ result.append(metadata.itemToString(entry.first, ":"));
+ }
+ result.append("}");
return result;
}
diff --git a/services/surfaceflinger/layerproto/include/layerproto/LayerProtoParser.h b/services/surfaceflinger/layerproto/include/layerproto/LayerProtoParser.h
index a794ca5..d1b2b1f 100644
--- a/services/surfaceflinger/layerproto/include/layerproto/LayerProtoParser.h
+++ b/services/surfaceflinger/layerproto/include/layerproto/LayerProtoParser.h
@@ -17,6 +17,7 @@
#include <layerproto/LayerProtoHeader.h>
+#include <gui/LayerMetadata.h>
#include <math/vec4.h>
#include <memory>
@@ -110,11 +111,10 @@
LayerProtoParser::Rect hwcFrame;
LayerProtoParser::FloatRect hwcCrop;
int32_t hwcTransform;
- int32_t windowType;
- int32_t appId;
int32_t hwcCompositionType;
bool isProtected;
float cornerRadius;
+ LayerMetadata metadata;
std::string to_string() const;
};
diff --git a/services/surfaceflinger/layerproto/layers.proto b/services/surfaceflinger/layerproto/layers.proto
index b100438..4c756d9 100644
--- a/services/surfaceflinger/layerproto/layers.proto
+++ b/services/surfaceflinger/layerproto/layers.proto
@@ -74,8 +74,8 @@
optional FloatRectProto hwc_crop = 31;
// The layer's composer backend transform
optional int32 hwc_transform = 32;
- optional int32 window_type = 33;
- optional int32 app_id = 34;
+ optional int32 window_type = 33 [deprecated=true];
+ optional int32 app_id = 34 [deprecated=true];
// The layer's composition type
optional int32 hwc_composition_type = 35;
// If it's a buffer layer, indicate if the content is protected
@@ -89,6 +89,8 @@
optional int32 effective_scaling_mode = 40;
// Layer's corner radius.
optional float corner_radius = 41;
+ // Metadata map. May be empty.
+ map<int32, bytes> metadata = 42;
}
message PositionProto {
diff --git a/services/surfaceflinger/main_surfaceflinger.cpp b/services/surfaceflinger/main_surfaceflinger.cpp
index 92ae87b..e7986d3 100644
--- a/services/surfaceflinger/main_surfaceflinger.cpp
+++ b/services/surfaceflinger/main_surfaceflinger.cpp
@@ -21,30 +21,35 @@
#include <android/frameworks/displayservice/1.0/IDisplayService.h>
#include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
#include <android/hardware/graphics/allocator/2.0/IAllocator.h>
+#include <android/hardware/graphics/allocator/3.0/IAllocator.h>
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
#include <binder/ProcessState.h>
#include <configstore/Utils.h>
-#include <cutils/sched_policy.h>
#include <displayservice/DisplayService.h>
#include <hidl/LegacySupport.h>
+#include <processgroup/sched_policy.h>
#include "SurfaceFlinger.h"
#include "SurfaceFlingerFactory.h"
+#include "SurfaceFlingerProperties.h"
using namespace android;
static status_t startGraphicsAllocatorService() {
using android::hardware::configstore::getBool;
using android::hardware::configstore::V1_0::ISurfaceFlingerConfigs;
- if (!getBool<ISurfaceFlingerConfigs,
- &ISurfaceFlingerConfigs::startGraphicsAllocatorService>(false)) {
+ if (!android::sysprop::start_graphics_allocator_service(false)) {
return OK;
}
- using android::hardware::graphics::allocator::V2_0::IAllocator;
+ status_t result = hardware::registerPassthroughServiceImplementation<
+ android::hardware::graphics::allocator::V3_0::IAllocator>();
+ if (result == OK) {
+ return OK;
+ }
- status_t result =
- hardware::registerPassthroughServiceImplementation<IAllocator>();
+ result = hardware::registerPassthroughServiceImplementation<
+ android::hardware::graphics::allocator::V2_0::IAllocator>();
if (result != OK) {
ALOGE("could not start graphics allocator service");
return result;
diff --git a/services/surfaceflinger/surfaceflinger.rc b/services/surfaceflinger/surfaceflinger.rc
index aea602b..5bec502 100644
--- a/services/surfaceflinger/surfaceflinger.rc
+++ b/services/surfaceflinger/surfaceflinger.rc
@@ -2,6 +2,7 @@
class core animation
user system
group graphics drmrpc readproc
+ updatable
onrestart restart zygote
writepid /dev/stune/foreground/tasks
socket pdx/system/vr/display/client stream 0666 system graphics u:object_r:pdx_display_client_endpoint_socket:s0
diff --git a/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop b/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop
new file mode 100644
index 0000000..cc7b280
--- /dev/null
+++ b/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop
@@ -0,0 +1,252 @@
+# 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.
+
+module: "android.sysprop.SurfaceFlingerProperties"
+owner: Platform
+
+# The following two propertiess define (respectively):
+#
+# - The phase offset between hardware vsync and when apps are woken up by the
+# Choreographer callback
+# - The phase offset between hardware vsync and when SurfaceFlinger wakes up
+# to consume input
+# Their values may be tuned to trade off between display pipeline latency (both
+# overall latency and the lengths of the app --> SF and SF --> display phases)
+# and frame delivery jitter (which typically manifests as "jank" or "jerkiness"
+# while interacting with the device). The default values must produce a
+# relatively low amount of jitter at the expense of roughly two frames of
+# app --> display latency, and unless significant testing is performed to avoid
+# increased display jitter (both manual investigation using systrace [1] and
+# automated testing using dumpsys gfxinfo [2] are recommended), they should not
+# be modified.
+#
+# [1] https://developer.android.com/studio/profile/systrace.html
+# [2] https://developer.android.com/training/testing/performance.html
+prop {
+ api_name: "vsync_event_phase_offset_ns"
+ type: Long
+ scope: Internal
+ access: Readonly
+ prop_name: "ro.surface_flinger.vsync_event_phase_offset_ns"
+}
+
+prop {
+ api_name: "vsync_sf_event_phase_offset_ns"
+ type: Long
+ scope: Internal
+ access: Readonly
+ prop_name: "ro.surface_flinger.vsync_sf_event_phase_offset_ns"
+}
+
+# Instruct the Render Engine to use EGL_IMG_context_priority hint if available.
+prop {
+ api_name: "use_context_priority"
+ type: Boolean
+ scope: Internal
+ access: Readonly
+ prop_name: "ro.surface_flinger.use_context_priority"
+}
+
+# Controls the number of buffers SurfaceFlinger will allocate for use in FramebufferSurface.
+prop {
+ api_name: "max_frame_buffer_acquired_buffers"
+ type: Long
+ scope: Internal
+ access: Readonly
+ prop_name: "ro.surface_flinger.max_frame_buffer_acquired_buffers"
+}
+
+# hasWideColorDisplay indicates that the device has
+# or can support a wide-color display, e.g. color space
+# greater than sRGB. Typical display may have same
+# color primaries as DCI-P3.
+# Indicate support for this feature by setting
+# TARGET_HAS_WIDE_COLOR_DISPLAY to true in BoardConfig.mk
+# This also means that the device is color managed.
+# A color managed device will use the appropriate
+# display mode depending on the content on the screen.
+# Default is sRGB.
+prop {
+ api_name: "has_wide_color_display"
+ type: Boolean
+ scope: Internal
+ access: Readonly
+ prop_name: "ro.surface_flinger.has_wide_color_display"
+}
+
+# Indicates if Sync framework is available. Sync framework provides fence
+# mechanism which significantly reduces buffer processing latency.
+prop {
+ api_name: "running_without_sync_framework"
+ type: Boolean
+ scope: Internal
+ access: Readonly
+ prop_name: "ro.surface_flinger.running_without_sync_framework"
+}
+
+# hwHDRDisplay indicates that the device has an High Dynamic Range display.
+# A display is considered High Dynamic Range if it
+#
+# 1. is a wide color gamut display, typically DCI-P3 or lager
+# 2. has high luminance capability, typically 540 nits or higher at 10% OPR
+#
+# Indicate support for this feature by setting
+# ro.surface_flinger.has_HDR_display to true in device.mk
+# ro.surface_flinger.has_wide_color_display must be set to true when
+# ro.surface_flinger.has_HDR_display is true.
+prop {
+ api_name: "has_HDR_display"
+ type: Boolean
+ scope: Internal
+ access: Readonly
+ prop_name: "ro.surface_flinger.has_HDR_display"
+}
+
+# Specify the offset in nanoseconds to add to vsync time when timestamping present fences.
+prop {
+ api_name: "present_time_offset_from_vsync_ns"
+ type: Long
+ scope: Internal
+ access: Readonly
+ prop_name: "ro.surface_flinger.present_time_offset_from_vsync_ns"
+}
+
+# Some hardware can do RGB->YUV conversion more efficiently in hardware
+# controlled by HWC than in hardware controlled by the video encoder.
+# This instruct VirtualDisplaySurface to use HWC for such conversion on
+# GL composition.
+prop {
+ api_name: "force_hwc_copy_for_virtual_displays"
+ type: Boolean
+ scope: Internal
+ access: Readonly
+ prop_name: "ro.surface_flinger.force_hwc_copy_for_virtual_displays"
+}
+
+# Maximum dimension supported by HWC for virtual display.
+# Must be equals to min(max_width, max_height).
+prop {
+ api_name: "max_virtual_display_dimension"
+ type: Long
+ scope: Internal
+ access: Readonly
+ prop_name: "ro.surface_flinger.max_virtual_display_dimension"
+}
+
+# Return true if surface flinger should use vr flinger for compatible vr
+# apps, false otherwise. Devices that will never be running vr apps should
+# return false to avoid extra resource usage. Daydream ready devices must
+# return true for full vr support.
+prop {
+ api_name: "use_vr_flinger"
+ type: Boolean
+ scope: Internal
+ access: Readonly
+ prop_name: "ro.surface_flinger.use_vr_flinger"
+}
+
+# Returns true if surface flinger should start
+# hardware.graphics.allocator@2.0::IAllocator service.
+prop {
+ api_name: "start_graphics_allocator_service"
+ type: Boolean
+ scope: Internal
+ access: Readonly
+ prop_name: "ro.surface_flinger.start_graphics_allocator_service"
+}
+
+# Returns the orientation of the primary display device.
+prop {
+ api_name: "primary_display_orientation"
+ type: Enum
+ enum_values: "ORIENTATION_0|ORIENTATION_90|ORIENTATION_180|ORIENTATION_270"
+ scope: Internal
+ access: Readonly
+ prop_name: "ro.surface_flinger.primary_display_orientation"
+}
+
+# useColorManagement indicates whether SurfaceFlinger should manage color
+# by switching to appropriate color mode automatically depending on the
+# Dataspace of the surfaces on screen.
+prop {
+ api_name: "use_color_management"
+ type: Boolean
+ scope: Internal
+ access: Readonly
+ prop_name: "ro.surface_flinger.use_color_management"
+}
+
+# The following four propertiess define:
+# Returns the default data space and pixel format that SurfaceFlinger
+# expects to receive and output as well as the wide color gamut data space
+# and pixel format for wide color gamut surfaces.
+# To determine the data space and pixel format, there are a few things
+# we recommend to consider:
+#
+# 1. Hardware composer's capability to composite contents with the chosen
+# data space and pixel format efficiently;
+# 2. Hardware composer's ability to composite contents when sRGB contents
+# and the chosen wide color gamut data space contents coexist;
+# 3. For better blending, consider using pixel format where the alpha
+# channel has as many bits as the RGB color channel.
+# 4. Memory consumption and efficient buffer compression when considering
+# more bits in pixel format.
+
+# dataspace is the default data space that SurfaceFlinger expects.
+# The data space must not be Dataspace::UNKNOWN, if unspecified,
+# the default data space is Dataspace::V0_SRGB;
+prop {
+ api_name: "default_composition_dataspace"
+ type: Long
+ scope: Internal
+ access: Readonly
+ prop_name: "ro.surface_flinger.default_composition_dataspace"
+}
+
+# pixelFormat is the default pixel format that SurfaceFlinger
+# expects. If unspecified, the default pixel format is
+# PixelFormat::RGBA_8888.
+prop {
+ api_name: "default_composition_pixel_format"
+ type: Integer
+ scope: Internal
+ access: Readonly
+ prop_name: "ro.surface_flinger.default_composition_pixel_format"
+}
+
+# wcgDataspace is the data space that SurfaceFlinger expects for
+# wide color gamut surfaces.
+# When hasWideColorDisplay returns true, this API must return a
+# valid wide color gamut data space.
+# The data space must not be UNKNOWN, if unspecified, the data space
+# is V0_SRGB by default, which essentially indicates there's no wide
+# color gamut, meaning hasWideColorDisplay returns false.
+prop {
+ api_name: "wcg_composition_dataspace"
+ type: Long
+ scope: Internal
+ access: Readonly
+ prop_name: "ro.surface_flinger.wcg_composition_dataspace"
+}
+
+# wcgPixelFormat is the pixel format that SurfaceFlinger expects for
+# wide color gamut surfaces. If unspecified, the pixel format is
+# PixelFormat::RGBA_8888 by default.
+prop {
+ api_name: "wcg_composition_pixel_format"
+ type: Integer
+ scope: Internal
+ access: Readonly
+ prop_name: "ro.surface_flinger.wcg_composition_pixel_format"
+}
diff --git a/services/surfaceflinger/tests/Credentials_test.cpp b/services/surfaceflinger/tests/Credentials_test.cpp
index a73ec6c..f021d3d 100644
--- a/services/surfaceflinger/tests/Credentials_test.cpp
+++ b/services/surfaceflinger/tests/Credentials_test.cpp
@@ -19,6 +19,7 @@
namespace android {
using Transaction = SurfaceComposerClient::Transaction;
+using ui::ColorMode;
namespace {
const String8 DISPLAY_NAME("Credentials Display Test");
@@ -162,10 +163,10 @@
setSystemUID();
ASSERT_NO_FATAL_FAILURE(initClient());
- // No one else can init the client.
+ // Anyone else can init the client.
setBinUID();
mComposerClient = new SurfaceComposerClient;
- ASSERT_EQ(NO_INIT, mComposerClient->initCheck());
+ ASSERT_NO_FATAL_FAILURE(initClient());
}
TEST_F(CredentialsTest, GetBuiltInDisplayAccessTest) {
@@ -206,6 +207,15 @@
ASSERT_NO_FATAL_FAILURE(checkWithPrivileges<status_t>(condition, NO_ERROR, NO_ERROR));
}
+TEST_F(CredentialsTest, GetDisplayNativePrimariesTest) {
+ sp<IBinder> display(SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
+ std::function<status_t()> condition = [=]() {
+ ui::DisplayPrimaries primaries;
+ return SurfaceComposerClient::getDisplayNativePrimaries(display, primaries);
+ };
+ ASSERT_NO_FATAL_FAILURE(checkWithPrivileges<status_t>(condition, NO_ERROR, NO_ERROR));
+}
+
TEST_F(CredentialsTest, SetActiveConfigTest) {
sp<IBinder> display(SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
std::function<status_t()> condition = [=]() {
@@ -222,22 +232,6 @@
ASSERT_NO_FATAL_FAILURE(checkWithPrivileges<status_t>(condition, NO_ERROR, PERMISSION_DENIED));
}
-TEST_F(CredentialsTest, CreateSurfaceTest) {
- sp<IBinder> display(SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
- DisplayInfo info;
- SurfaceComposerClient::getDisplayInfo(display, &info);
- const ssize_t displayWidth = info.w;
- const ssize_t displayHeight = info.h;
-
- std::function<bool()> condition = [=]() {
- mBGSurfaceControl =
- mComposerClient->createSurface(SURFACE_NAME, displayWidth, displayHeight,
- PIXEL_FORMAT_RGBA_8888, 0);
- return mBGSurfaceControl != nullptr && mBGSurfaceControl->isValid();
- };
- ASSERT_NO_FATAL_FAILURE(checkWithPrivileges(condition, true, false));
-}
-
TEST_F(CredentialsTest, CreateDisplayTest) {
std::function<bool()> condition = [=]() {
sp<IBinder> testDisplay = SurfaceComposerClient::createDisplay(DISPLAY_NAME, true);
@@ -328,4 +322,36 @@
seteuid(AID_BIN);
ASSERT_EQ(PERMISSION_DENIED, sf->getLayerDebugInfo(&outLayers));
}
+
+TEST_F(CredentialsTest, IsWideColorDisplayBasicCorrectness) {
+ sp<IBinder> display(SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
+ bool result = false;
+ status_t error = SurfaceComposerClient::isWideColorDisplay(display, &result);
+ ASSERT_EQ(NO_ERROR, error);
+ bool hasWideColorMode = false;
+ Vector<ColorMode> colorModes;
+ SurfaceComposerClient::getDisplayColorModes(display, &colorModes);
+ for (ColorMode colorMode : colorModes) {
+ switch (colorMode) {
+ case ColorMode::DISPLAY_P3:
+ case ColorMode::ADOBE_RGB:
+ case ColorMode::DCI_P3:
+ hasWideColorMode = true;
+ break;
+ default:
+ break;
+ }
+ }
+ ASSERT_EQ(hasWideColorMode, result);
+}
+
+TEST_F(CredentialsTest, IsWideColorDisplayWithPrivileges) {
+ sp<IBinder> display(SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
+ std::function<status_t()> condition = [=]() {
+ bool result = false;
+ return SurfaceComposerClient::isWideColorDisplay(display, &result);
+ };
+ ASSERT_NO_FATAL_FAILURE(checkWithPrivileges<status_t>(condition, NO_ERROR, NO_ERROR));
+}
+
} // namespace android
diff --git a/services/surfaceflinger/tests/Stress_test.cpp b/services/surfaceflinger/tests/Stress_test.cpp
index 3e1be8e..89c26f4 100644
--- a/services/surfaceflinger/tests/Stress_test.cpp
+++ b/services/surfaceflinger/tests/Stress_test.cpp
@@ -34,7 +34,7 @@
auto surf = client->createSurface(String8("t"), 100, 100,
PIXEL_FORMAT_RGBA_8888, 0);
ASSERT_TRUE(surf != nullptr);
- client->destroySurface(surf->getHandle());
+ surf->clear();
}
};
diff --git a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
index e506757..8ec3e15 100644
--- a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
+++ b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
@@ -806,18 +806,6 @@
Increment::IncrementCase::kSurfaceCreation);
}
-TEST_F(SurfaceInterceptorTest, InterceptSurfaceDeletionWorks) {
- enableInterceptor();
- sp<SurfaceControl> layerToDelete = mComposerClient->createSurface(String8(LAYER_NAME),
- SIZE_UPDATE, SIZE_UPDATE, PIXEL_FORMAT_RGBA_8888, 0);
- mComposerClient->destroySurface(layerToDelete->getHandle());
- disableInterceptor();
-
- Trace capturedTrace;
- ASSERT_EQ(NO_ERROR, readProtoFile(&capturedTrace));
- ASSERT_TRUE(singleIncrementFound(capturedTrace, Increment::IncrementCase::kSurfaceDeletion));
-}
-
TEST_F(SurfaceInterceptorTest, InterceptDisplayCreationWorks) {
captureTest(&SurfaceInterceptorTest::displayCreation,
Increment::IncrementCase::kDisplayCreation);
diff --git a/services/surfaceflinger/tests/Transaction_test.cpp b/services/surfaceflinger/tests/Transaction_test.cpp
index d118ad6..1ae7008 100644
--- a/services/surfaceflinger/tests/Transaction_test.cpp
+++ b/services/surfaceflinger/tests/Transaction_test.cpp
@@ -26,6 +26,8 @@
#include <android/native_window.h>
+#include <binder/ProcessState.h>
+#include <gui/BufferItemConsumer.h>
#include <gui/ISurfaceComposer.h>
#include <gui/LayerState.h>
#include <gui/Surface.h>
@@ -302,7 +304,7 @@
void expectChildColor(uint32_t x, uint32_t y) { checkPixel(x, y, 200, 200, 200); }
- ScreenCapture(const sp<GraphicBuffer>& outBuffer) : mOutBuffer(outBuffer) {
+ explicit ScreenCapture(const sp<GraphicBuffer>& outBuffer) : mOutBuffer(outBuffer) {
mOutBuffer->lock(GRALLOC_USAGE_SW_READ_OFTEN, reinterpret_cast<void**>(&mPixels));
}
@@ -495,10 +497,6 @@
// leave room for ~256 layers
const int32_t mLayerZBase = std::numeric_limits<int32_t>::max() - 256;
- void setRelativeZBasicHelper(uint32_t layerType);
- void setRelativeZGroupHelper(uint32_t layerType);
- void setAlphaBasicHelper(uint32_t layerType);
-
sp<SurfaceControl> mBlackBgSurface;
bool mColorManagementUsed;
@@ -544,15 +542,72 @@
}
int32_t mBufferPostDelay;
+
+ friend class LayerRenderPathTestHarness;
+};
+enum class RenderPath { SCREENSHOT, VIRTUAL_DISPLAY };
+
+class LayerRenderPathTestHarness {
+public:
+ LayerRenderPathTestHarness(LayerTransactionTest* delegate, RenderPath renderPath)
+ : mDelegate(delegate), mRenderPath(renderPath) {}
+
+ std::unique_ptr<ScreenCapture> getScreenCapture() {
+ switch (mRenderPath) {
+ case RenderPath::SCREENSHOT:
+ return mDelegate->screenshot();
+ case RenderPath::VIRTUAL_DISPLAY:
+
+ sp<IBinder> mainDisplay =
+ SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain);
+ DisplayInfo mainDisplayInfo;
+ SurfaceComposerClient::getDisplayInfo(mainDisplay, &mainDisplayInfo);
+
+ sp<IBinder> vDisplay;
+ sp<IGraphicBufferProducer> producer;
+ sp<IGraphicBufferConsumer> consumer;
+ sp<BufferItemConsumer> itemConsumer;
+ BufferQueue::createBufferQueue(&producer, &consumer);
+
+ consumer->setConsumerName(String8("Virtual disp consumer"));
+ consumer->setDefaultBufferSize(mainDisplayInfo.w, mainDisplayInfo.h);
+
+ itemConsumer = new BufferItemConsumer(consumer,
+ // Sample usage bits from screenrecord
+ GRALLOC_USAGE_HW_VIDEO_ENCODER |
+ GRALLOC_USAGE_SW_READ_OFTEN);
+
+ vDisplay = SurfaceComposerClient::createDisplay(String8("VirtualDisplay"),
+ false /*secure*/);
+
+ SurfaceComposerClient::Transaction t;
+ t.setDisplaySurface(vDisplay, producer);
+ t.setDisplayLayerStack(vDisplay, 0);
+ t.setDisplayProjection(vDisplay, mainDisplayInfo.orientation,
+ Rect(mainDisplayInfo.viewportW, mainDisplayInfo.viewportH),
+ Rect(mainDisplayInfo.w, mainDisplayInfo.h));
+ t.apply();
+ SurfaceComposerClient::Transaction().apply(true);
+ BufferItem item;
+ itemConsumer->acquireBuffer(&item, 0, true);
+ auto sc = std::make_unique<ScreenCapture>(item.mGraphicBuffer);
+ itemConsumer->releaseBuffer(item);
+ SurfaceComposerClient::destroyDisplay(vDisplay);
+ return sc;
+ }
+ }
+
+protected:
+ LayerTransactionTest* mDelegate;
+ RenderPath mRenderPath;
};
-class LayerTypeTransactionTest : public LayerTransactionTest,
- public ::testing::WithParamInterface<uint32_t> {
+class LayerTypeTransactionHarness : public LayerTransactionTest {
public:
- LayerTypeTransactionTest() { mLayerType = GetParam(); }
+ LayerTypeTransactionHarness(uint32_t layerType) : mLayerType(layerType) {}
sp<SurfaceControl> createLayer(const char* name, uint32_t width, uint32_t height,
- uint32_t flags = 0, SurfaceControl* parent = nullptr) override {
+ uint32_t flags = 0, SurfaceControl* parent = nullptr) {
// if the flags already have a layer type specified, return an error
if (flags & ISurfaceComposerClient::eFXSurfaceMask) {
return nullptr;
@@ -579,12 +634,71 @@
uint32_t mLayerType;
};
+class LayerTypeTransactionTest : public LayerTypeTransactionHarness,
+ public ::testing::WithParamInterface<uint32_t> {
+public:
+ LayerTypeTransactionTest() : LayerTypeTransactionHarness(GetParam()) {}
+};
+
+class LayerTypeAndRenderTypeTransactionTest
+ : public LayerTypeTransactionHarness,
+ public ::testing::WithParamInterface<std::tuple<uint32_t, RenderPath>> {
+public:
+ LayerTypeAndRenderTypeTransactionTest()
+ : LayerTypeTransactionHarness(std::get<0>(GetParam())),
+ mRenderPathHarness(LayerRenderPathTestHarness(this, std::get<1>(GetParam()))) {}
+
+ std::unique_ptr<ScreenCapture> getScreenCapture() {
+ return mRenderPathHarness.getScreenCapture();
+ }
+
+protected:
+ LayerRenderPathTestHarness mRenderPathHarness;
+};
+
+// Environment for starting up binder threads. This is required for testing
+// virtual displays, as BufferQueue parameters may be queried over binder.
+class BinderEnvironment : public ::testing::Environment {
+public:
+ void SetUp() override { ProcessState::self()->startThreadPool(); }
+};
+
+::testing::Environment* const binderEnv =
+ ::testing::AddGlobalTestEnvironment(new BinderEnvironment());
+
+class LayerRenderTypeTransactionTest : public LayerTransactionTest,
+ public ::testing::WithParamInterface<RenderPath> {
+public:
+ LayerRenderTypeTransactionTest() : mHarness(LayerRenderPathTestHarness(this, GetParam())) {}
+
+ std::unique_ptr<ScreenCapture> getScreenCapture() { return mHarness.getScreenCapture(); }
+ void setRelativeZBasicHelper(uint32_t layerType);
+ void setRelativeZGroupHelper(uint32_t layerType);
+ void setAlphaBasicHelper(uint32_t layerType);
+ void setBackgroundColorHelper(uint32_t layerType, bool priorColor, bool bufferFill, float alpha,
+ Color finalColor);
+
+protected:
+ LayerRenderPathTestHarness mHarness;
+};
+
+INSTANTIATE_TEST_CASE_P(
+ LayerTypeAndRenderTypeTransactionTests, LayerTypeAndRenderTypeTransactionTest,
+ ::testing::Combine(
+ ::testing::Values(
+ static_cast<uint32_t>(ISurfaceComposerClient::eFXSurfaceBufferQueue),
+ static_cast<uint32_t>(ISurfaceComposerClient::eFXSurfaceBufferState)),
+ ::testing::Values(RenderPath::VIRTUAL_DISPLAY, RenderPath::SCREENSHOT)));
+
+INSTANTIATE_TEST_CASE_P(LayerRenderTypeTransactionTests, LayerRenderTypeTransactionTest,
+ ::testing::Values(RenderPath::VIRTUAL_DISPLAY, RenderPath::SCREENSHOT));
+
INSTANTIATE_TEST_CASE_P(
LayerTypeTransactionTests, LayerTypeTransactionTest,
::testing::Values(static_cast<uint32_t>(ISurfaceComposerClient::eFXSurfaceBufferQueue),
static_cast<uint32_t>(ISurfaceComposerClient::eFXSurfaceBufferState)));
-TEST_F(LayerTransactionTest, SetPositionBasic_BufferQueue) {
+TEST_P(LayerRenderTypeTransactionTest, SetPositionBasic_BufferQueue) {
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
@@ -592,7 +706,7 @@
{
SCOPED_TRACE("default position");
const Rect rect(0, 0, 32, 32);
- auto shot = screenshot();
+ auto shot = getScreenCapture();
shot->expectColor(rect, Color::RED);
shot->expectBorder(rect, Color::BLACK);
}
@@ -601,13 +715,13 @@
{
SCOPED_TRACE("new position");
const Rect rect(5, 10, 37, 42);
- auto shot = screenshot();
+ auto shot = getScreenCapture();
shot->expectColor(rect, Color::RED);
shot->expectBorder(rect, Color::BLACK);
}
}
-TEST_F(LayerTransactionTest, SetPositionRounding_BufferQueue) {
+TEST_P(LayerRenderTypeTransactionTest, SetPositionRounding_BufferQueue) {
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
@@ -619,17 +733,17 @@
Transaction().setPosition(layer, 0.5f - epsilon, 0.5f - epsilon).apply();
{
SCOPED_TRACE("rounding down");
- screenshot()->expectColor(Rect(0, 0, 32, 32), Color::RED);
+ getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED);
}
Transaction().setPosition(layer, 0.5f + epsilon, 0.5f + epsilon).apply();
{
SCOPED_TRACE("rounding up");
- screenshot()->expectColor(Rect(1, 1, 33, 33), Color::RED);
+ getScreenCapture()->expectColor(Rect(1, 1, 33, 33), Color::RED);
}
}
-TEST_F(LayerTransactionTest, SetPositionOutOfBounds_BufferQueue) {
+TEST_P(LayerRenderTypeTransactionTest, SetPositionOutOfBounds_BufferQueue) {
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
@@ -637,17 +751,17 @@
Transaction().setPosition(layer, -32, -32).apply();
{
SCOPED_TRACE("negative coordinates");
- screenshot()->expectColor(mDisplayRect, Color::BLACK);
+ getScreenCapture()->expectColor(mDisplayRect, Color::BLACK);
}
Transaction().setPosition(layer, mDisplayWidth, mDisplayHeight).apply();
{
SCOPED_TRACE("positive coordinates");
- screenshot()->expectColor(mDisplayRect, Color::BLACK);
+ getScreenCapture()->expectColor(mDisplayRect, Color::BLACK);
}
}
-TEST_F(LayerTransactionTest, SetPositionPartiallyOutOfBounds_BufferQueue) {
+TEST_P(LayerRenderTypeTransactionTest, SetPositionPartiallyOutOfBounds_BufferQueue) {
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
@@ -656,19 +770,19 @@
Transaction().setPosition(layer, -30, -30).apply();
{
SCOPED_TRACE("negative coordinates");
- screenshot()->expectColor(Rect(0, 0, 2, 2), Color::RED);
+ getScreenCapture()->expectColor(Rect(0, 0, 2, 2), Color::RED);
}
Transaction().setPosition(layer, mDisplayWidth - 2, mDisplayHeight - 2).apply();
{
SCOPED_TRACE("positive coordinates");
- screenshot()->expectColor(Rect(mDisplayWidth - 2, mDisplayHeight - 2, mDisplayWidth,
- mDisplayHeight),
- Color::RED);
+ getScreenCapture()->expectColor(Rect(mDisplayWidth - 2, mDisplayHeight - 2, mDisplayWidth,
+ mDisplayHeight),
+ Color::RED);
}
}
-TEST_F(LayerTransactionTest, SetPositionWithResize_BufferQueue) {
+TEST_P(LayerRenderTypeTransactionTest, SetPositionWithResize_BufferQueue) {
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
@@ -678,7 +792,7 @@
Transaction().setPosition(layer, 5, 10).setSize(layer, 64, 64).apply();
{
SCOPED_TRACE("resize pending");
- auto shot = screenshot();
+ auto shot = getScreenCapture();
const Rect rect(5, 10, 37, 42);
shot->expectColor(rect, Color::RED);
shot->expectBorder(rect, Color::BLACK);
@@ -687,11 +801,11 @@
ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 64, 64));
{
SCOPED_TRACE("resize applied");
- screenshot()->expectColor(Rect(5, 10, 69, 74), Color::RED);
+ getScreenCapture()->expectColor(Rect(5, 10, 69, 74), Color::RED);
}
}
-TEST_F(LayerTransactionTest, SetPositionWithNextResize_BufferQueue) {
+TEST_P(LayerRenderTypeTransactionTest, SetPositionWithNextResize_BufferQueue) {
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
@@ -700,30 +814,30 @@
Transaction().setPosition(layer, 5, 10).setGeometryAppliesWithResize(layer).apply();
{
SCOPED_TRACE("new position pending");
- screenshot()->expectColor(Rect(0, 0, 32, 32), Color::RED);
+ getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED);
}
Transaction().setPosition(layer, 15, 20).apply();
{
SCOPED_TRACE("pending new position modified");
- screenshot()->expectColor(Rect(0, 0, 32, 32), Color::RED);
+ getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED);
}
Transaction().setSize(layer, 64, 64).apply();
{
SCOPED_TRACE("resize pending");
- screenshot()->expectColor(Rect(0, 0, 32, 32), Color::RED);
+ getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED);
}
// finally resize and latch the buffer
ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 64, 64));
{
SCOPED_TRACE("new position applied");
- screenshot()->expectColor(Rect(15, 20, 79, 84), Color::RED);
+ getScreenCapture()->expectColor(Rect(15, 20, 79, 84), Color::RED);
}
}
-TEST_F(LayerTransactionTest, SetPositionWithNextResizeScaleToWindow_BufferQueue) {
+TEST_P(LayerRenderTypeTransactionTest, SetPositionWithNextResizeScaleToWindow_BufferQueue) {
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
@@ -737,17 +851,17 @@
.apply();
{
SCOPED_TRACE("new position pending");
- screenshot()->expectColor(Rect(0, 0, 64, 64), Color::RED);
+ getScreenCapture()->expectColor(Rect(0, 0, 64, 64), Color::RED);
}
ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 64, 64));
{
SCOPED_TRACE("new position applied");
- screenshot()->expectColor(Rect(5, 10, 69, 74), Color::RED);
+ getScreenCapture()->expectColor(Rect(5, 10, 69, 74), Color::RED);
}
}
-TEST_F(LayerTransactionTest, SetSizeBasic_BufferQueue) {
+TEST_P(LayerRenderTypeTransactionTest, SetSizeBasic_BufferQueue) {
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
@@ -755,7 +869,7 @@
Transaction().setSize(layer, 64, 64).apply();
{
SCOPED_TRACE("resize pending");
- auto shot = screenshot();
+ auto shot = getScreenCapture();
const Rect rect(0, 0, 32, 32);
shot->expectColor(rect, Color::RED);
shot->expectBorder(rect, Color::BLACK);
@@ -764,18 +878,18 @@
ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 64, 64));
{
SCOPED_TRACE("resize applied");
- auto shot = screenshot();
+ auto shot = getScreenCapture();
const Rect rect(0, 0, 64, 64);
shot->expectColor(rect, Color::RED);
shot->expectBorder(rect, Color::BLACK);
}
}
-TEST_P(LayerTypeTransactionTest, SetSizeInvalid) {
+TEST_P(LayerTypeAndRenderTypeTransactionTest, SetSizeInvalid) {
// cannot test robustness against invalid sizes (zero or really huge)
}
-TEST_F(LayerTransactionTest, SetSizeWithScaleToWindow_BufferQueue) {
+TEST_P(LayerRenderTypeTransactionTest, SetSizeWithScaleToWindow_BufferQueue) {
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
@@ -785,10 +899,10 @@
.setSize(layer, 64, 64)
.setOverrideScalingMode(layer, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW)
.apply();
- screenshot()->expectColor(Rect(0, 0, 64, 64), Color::RED);
+ getScreenCapture()->expectColor(Rect(0, 0, 64, 64), Color::RED);
}
-TEST_P(LayerTypeTransactionTest, SetZBasic) {
+TEST_P(LayerTypeAndRenderTypeTransactionTest, SetZBasic) {
sp<SurfaceControl> layerR;
sp<SurfaceControl> layerG;
ASSERT_NO_FATAL_FAILURE(layerR = createLayer("test R", 32, 32));
@@ -799,17 +913,17 @@
Transaction().setLayer(layerR, mLayerZBase + 1).apply();
{
SCOPED_TRACE("layerR");
- screenshot()->expectColor(Rect(0, 0, 32, 32), Color::RED);
+ getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED);
}
Transaction().setLayer(layerG, mLayerZBase + 2).apply();
{
SCOPED_TRACE("layerG");
- screenshot()->expectColor(Rect(0, 0, 32, 32), Color::GREEN);
+ getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::GREEN);
}
}
-TEST_P(LayerTypeTransactionTest, SetZNegative) {
+TEST_P(LayerTypeAndRenderTypeTransactionTest, SetZNegative) {
sp<SurfaceControl> parent =
LayerTransactionTest::createLayer("Parent", 0 /* buffer width */, 0 /* buffer height */,
ISurfaceComposerClient::eFXSurfaceContainer);
@@ -828,19 +942,19 @@
Transaction().setLayer(layerR, -1).setLayer(layerG, -2).apply();
{
SCOPED_TRACE("layerR");
- auto shot = screenshot();
+ auto shot = getScreenCapture();
shot->expectColor(Rect(0, 0, 32, 32), Color::RED);
}
Transaction().setLayer(layerR, -3).apply();
{
SCOPED_TRACE("layerG");
- auto shot = screenshot();
+ auto shot = getScreenCapture();
shot->expectColor(Rect(0, 0, 32, 32), Color::GREEN);
}
}
-void LayerTransactionTest::setRelativeZBasicHelper(uint32_t layerType) {
+void LayerRenderTypeTransactionTest::setRelativeZBasicHelper(uint32_t layerType) {
sp<SurfaceControl> layerR;
sp<SurfaceControl> layerG;
ASSERT_NO_FATAL_FAILURE(layerR = createLayer("test R", 32, 32, layerType));
@@ -867,7 +981,7 @@
}
{
SCOPED_TRACE("layerG above");
- auto shot = screenshot();
+ auto shot = getScreenCapture();
shot->expectColor(Rect(0, 0, 16, 16), Color::RED);
shot->expectColor(Rect(16, 16, 48, 48), Color::GREEN);
}
@@ -875,17 +989,17 @@
Transaction().setRelativeLayer(layerG, layerR->getHandle(), -1).apply();
{
SCOPED_TRACE("layerG below");
- auto shot = screenshot();
+ auto shot = getScreenCapture();
shot->expectColor(Rect(0, 0, 32, 32), Color::RED);
shot->expectColor(Rect(32, 32, 48, 48), Color::GREEN);
}
}
-TEST_F(LayerTransactionTest, SetRelativeZBasic_BufferQueue) {
+TEST_P(LayerRenderTypeTransactionTest, SetRelativeZBasic_BufferQueue) {
ASSERT_NO_FATAL_FAILURE(setRelativeZBasicHelper(ISurfaceComposerClient::eFXSurfaceBufferQueue));
}
-TEST_F(LayerTransactionTest, SetRelativeZBasic_BufferState) {
+TEST_P(LayerRenderTypeTransactionTest, SetRelativeZBasic_BufferState) {
ASSERT_NO_FATAL_FAILURE(setRelativeZBasicHelper(ISurfaceComposerClient::eFXSurfaceBufferState));
}
@@ -918,7 +1032,7 @@
screenshot->expectColor(Rect(0, 0, 32, 32), Color::BLUE);
}
-void LayerTransactionTest::setRelativeZGroupHelper(uint32_t layerType) {
+void LayerRenderTypeTransactionTest::setRelativeZGroupHelper(uint32_t layerType) {
sp<SurfaceControl> layerR;
sp<SurfaceControl> layerG;
sp<SurfaceControl> layerB;
@@ -954,7 +1068,7 @@
{
SCOPED_TRACE("(layerR < layerG) < layerB");
- auto shot = screenshot();
+ auto shot = getScreenCapture();
shot->expectColor(Rect(0, 0, 8, 8), Color::RED);
shot->expectColor(Rect(8, 8, 16, 16), Color::GREEN);
shot->expectColor(Rect(16, 16, 48, 48), Color::BLUE);
@@ -964,7 +1078,7 @@
Transaction().setLayer(layerR, mLayerZBase + 4).apply();
{
SCOPED_TRACE("layerB < (layerR < layerG)");
- auto shot = screenshot();
+ auto shot = getScreenCapture();
shot->expectColor(Rect(0, 0, 8, 8), Color::RED);
shot->expectColor(Rect(8, 8, 40, 40), Color::GREEN);
shot->expectColor(Rect(40, 40, 48, 48), Color::BLUE);
@@ -974,7 +1088,7 @@
Transaction().setRelativeLayer(layerG, layerR->getHandle(), -3).apply();
{
SCOPED_TRACE("layerB < (layerG < layerR)");
- auto shot = screenshot();
+ auto shot = getScreenCapture();
shot->expectColor(Rect(0, 0, 32, 32), Color::RED);
shot->expectColor(Rect(32, 32, 40, 40), Color::GREEN);
shot->expectColor(Rect(40, 40, 48, 48), Color::BLUE);
@@ -985,7 +1099,7 @@
Transaction().setLayer(layerG, mLayerZBase).apply();
{
SCOPED_TRACE("layerG < layerB < layerR");
- auto shot = screenshot();
+ auto shot = getScreenCapture();
shot->expectColor(Rect(0, 0, 32, 32), Color::RED);
shot->expectColor(Rect(32, 32, 48, 48), Color::BLUE);
}
@@ -995,21 +1109,21 @@
Transaction().setLayer(layerR, mLayerZBase + 1).apply();
{
SCOPED_TRACE("layerG < layerR < layerB");
- auto shot = screenshot();
+ auto shot = getScreenCapture();
shot->expectColor(Rect(0, 0, 16, 16), Color::RED);
shot->expectColor(Rect(16, 16, 48, 48), Color::BLUE);
}
}
-TEST_F(LayerTransactionTest, SetRelativeZGroup_BufferQueue) {
+TEST_P(LayerRenderTypeTransactionTest, SetRelativeZGroup_BufferQueue) {
ASSERT_NO_FATAL_FAILURE(setRelativeZGroupHelper(ISurfaceComposerClient::eFXSurfaceBufferQueue));
}
-TEST_F(LayerTransactionTest, SetRelativeZGroup_BufferState) {
+TEST_P(LayerRenderTypeTransactionTest, SetRelativeZGroup_BufferState) {
ASSERT_NO_FATAL_FAILURE(setRelativeZGroupHelper(ISurfaceComposerClient::eFXSurfaceBufferState));
}
-TEST_P(LayerTypeTransactionTest, SetRelativeZBug64572777) {
+TEST_P(LayerTypeAndRenderTypeTransactionTest, SetRelativeZBug64572777) {
sp<SurfaceControl> layerR;
sp<SurfaceControl> layerG;
@@ -1023,12 +1137,12 @@
.setRelativeLayer(layerG, layerR->getHandle(), 1)
.apply();
- mClient->destroySurface(layerG->getHandle());
+ layerG->clear();
// layerG should have been removed
- screenshot()->expectColor(Rect(0, 0, 32, 32), Color::RED);
+ getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED);
}
-TEST_P(LayerTypeTransactionTest, SetFlagsHidden) {
+TEST_P(LayerTypeAndRenderTypeTransactionTest, SetFlagsHidden) {
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED, 32, 32));
@@ -1036,17 +1150,17 @@
Transaction().setFlags(layer, layer_state_t::eLayerHidden, layer_state_t::eLayerHidden).apply();
{
SCOPED_TRACE("layer hidden");
- screenshot()->expectColor(mDisplayRect, Color::BLACK);
+ getScreenCapture()->expectColor(mDisplayRect, Color::BLACK);
}
Transaction().setFlags(layer, 0, layer_state_t::eLayerHidden).apply();
{
SCOPED_TRACE("layer shown");
- screenshot()->expectColor(Rect(0, 0, 32, 32), Color::RED);
+ getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED);
}
}
-TEST_P(LayerTypeTransactionTest, SetFlagsOpaque) {
+TEST_P(LayerTypeAndRenderTypeTransactionTest, SetFlagsOpaque) {
const Color translucentRed = {100, 0, 0, 100};
sp<SurfaceControl> layerR;
sp<SurfaceControl> layerG;
@@ -1061,14 +1175,14 @@
.apply();
{
SCOPED_TRACE("layerR opaque");
- screenshot()->expectColor(Rect(0, 0, 32, 32), {100, 0, 0, 255});
+ getScreenCapture()->expectColor(Rect(0, 0, 32, 32), {100, 0, 0, 255});
}
Transaction().setFlags(layerR, 0, layer_state_t::eLayerOpaque).apply();
{
SCOPED_TRACE("layerR translucent");
const uint8_t g = uint8_t(255 - translucentRed.a);
- screenshot()->expectColor(Rect(0, 0, 32, 32), {100, g, 0, 255});
+ getScreenCapture()->expectColor(Rect(0, 0, 32, 32), {100, g, 0, 255});
}
}
@@ -1090,7 +1204,7 @@
composer->captureScreen(mDisplay, &outBuffer, Rect(), 0, 0, false));
}
-TEST_F(LayerTransactionTest, SetTransparentRegionHintBasic_BufferQueue) {
+TEST_P(LayerRenderTypeTransactionTest, SetTransparentRegionHintBasic_BufferQueue) {
const Rect top(0, 0, 32, 16);
const Rect bottom(0, 16, 32, 32);
sp<SurfaceControl> layer;
@@ -1105,7 +1219,7 @@
ASSERT_NO_FATAL_FAILURE(postBufferQueueLayerBuffer(layer));
{
SCOPED_TRACE("top transparent");
- auto shot = screenshot();
+ auto shot = getScreenCapture();
shot->expectColor(top, Color::BLACK);
shot->expectColor(bottom, Color::RED);
}
@@ -1113,7 +1227,7 @@
Transaction().setTransparentRegionHint(layer, Region(bottom)).apply();
{
SCOPED_TRACE("transparent region hint pending");
- auto shot = screenshot();
+ auto shot = getScreenCapture();
shot->expectColor(top, Color::BLACK);
shot->expectColor(bottom, Color::RED);
}
@@ -1124,13 +1238,13 @@
ASSERT_NO_FATAL_FAILURE(postBufferQueueLayerBuffer(layer));
{
SCOPED_TRACE("bottom transparent");
- auto shot = screenshot();
+ auto shot = getScreenCapture();
shot->expectColor(top, Color::RED);
shot->expectColor(bottom, Color::BLACK);
}
}
-TEST_F(LayerTransactionTest, SetTransparentRegionHintBasic_BufferState) {
+TEST_P(LayerRenderTypeTransactionTest, SetTransparentRegionHintBasic_BufferState) {
const Rect top(0, 0, 32, 16);
const Rect bottom(0, 16, 32, 32);
sp<SurfaceControl> layer;
@@ -1152,7 +1266,7 @@
.apply();
{
SCOPED_TRACE("top transparent");
- auto shot = screenshot();
+ auto shot = getScreenCapture();
shot->expectColor(top, Color::BLACK);
shot->expectColor(bottom, Color::RED);
}
@@ -1160,7 +1274,7 @@
Transaction().setTransparentRegionHint(layer, Region(bottom)).apply();
{
SCOPED_TRACE("transparent region hint intermediate");
- auto shot = screenshot();
+ auto shot = getScreenCapture();
shot->expectColor(top, Color::BLACK);
shot->expectColor(bottom, Color::BLACK);
}
@@ -1175,13 +1289,13 @@
Transaction().setBuffer(layer, buffer).apply();
{
SCOPED_TRACE("bottom transparent");
- auto shot = screenshot();
+ auto shot = getScreenCapture();
shot->expectColor(top, Color::RED);
shot->expectColor(bottom, Color::BLACK);
}
}
-TEST_F(LayerTransactionTest, SetTransparentRegionHintOutOfBounds_BufferQueue) {
+TEST_P(LayerRenderTypeTransactionTest, SetTransparentRegionHintOutOfBounds_BufferQueue) {
sp<SurfaceControl> layerTransparent;
sp<SurfaceControl> layerR;
ASSERT_NO_FATAL_FAILURE(layerTransparent = createLayer("test transparent", 32, 32));
@@ -1196,10 +1310,10 @@
ASSERT_NO_FATAL_FAILURE(
fillBufferQueueLayerColor(layerTransparent, Color::TRANSPARENT, 32, 32));
ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layerR, Color::RED, 32, 32));
- screenshot()->expectColor(Rect(16, 16, 48, 48), Color::RED);
+ getScreenCapture()->expectColor(Rect(16, 16, 48, 48), Color::RED);
}
-TEST_F(LayerTransactionTest, SetTransparentRegionHintOutOfBounds_BufferState) {
+TEST_P(LayerRenderTypeTransactionTest, SetTransparentRegionHintOutOfBounds_BufferState) {
sp<SurfaceControl> layerTransparent;
sp<SurfaceControl> layerR;
ASSERT_NO_FATAL_FAILURE(layerTransparent = createLayer("test transparent", 32, 32));
@@ -1215,10 +1329,10 @@
ASSERT_NO_FATAL_FAILURE(
fillBufferQueueLayerColor(layerTransparent, Color::TRANSPARENT, 32, 32));
ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layerR, Color::RED, 32, 32));
- screenshot()->expectColor(Rect(16, 16, 48, 48), Color::RED);
+ getScreenCapture()->expectColor(Rect(16, 16, 48, 48), Color::RED);
}
-void LayerTransactionTest::setAlphaBasicHelper(uint32_t layerType) {
+void LayerRenderTypeTransactionTest::setAlphaBasicHelper(uint32_t layerType) {
sp<SurfaceControl> layer1;
sp<SurfaceControl> layer2;
ASSERT_NO_FATAL_FAILURE(layer1 = createLayer("test 1", 32, 32, layerType));
@@ -1248,7 +1362,7 @@
ASSERT_FALSE(true) << "Unsupported layer type";
}
{
- auto shot = screenshot();
+ auto shot = getScreenCapture();
uint8_t r = 16; // 64 * 0.25f
uint8_t g = 48; // 64 * 0.75f
shot->expectColor(Rect(0, 0, 16, 32), {r, 0, 0, 255});
@@ -1259,15 +1373,15 @@
}
}
-TEST_F(LayerTransactionTest, SetAlphaBasic_BufferQueue) {
+TEST_P(LayerRenderTypeTransactionTest, SetAlphaBasic_BufferQueue) {
ASSERT_NO_FATAL_FAILURE(setAlphaBasicHelper(ISurfaceComposerClient::eFXSurfaceBufferQueue));
}
-TEST_F(LayerTransactionTest, SetAlphaBasic_BufferState) {
+TEST_P(LayerRenderTypeTransactionTest, SetAlphaBasic_BufferState) {
ASSERT_NO_FATAL_FAILURE(setAlphaBasicHelper(ISurfaceComposerClient::eFXSurfaceBufferState));
}
-TEST_P(LayerTypeTransactionTest, SetAlphaClamped) {
+TEST_P(LayerTypeAndRenderTypeTransactionTest, SetAlphaClamped) {
const Color color = {64, 0, 0, 255};
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
@@ -1276,17 +1390,17 @@
Transaction().setAlpha(layer, 2.0f).apply();
{
SCOPED_TRACE("clamped to 1.0f");
- screenshot()->expectColor(Rect(0, 0, 32, 32), color);
+ getScreenCapture()->expectColor(Rect(0, 0, 32, 32), color);
}
Transaction().setAlpha(layer, -1.0f).apply();
{
SCOPED_TRACE("clamped to 0.0f");
- screenshot()->expectColor(Rect(0, 0, 32, 32), Color::BLACK);
+ getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::BLACK);
}
}
-TEST_P(LayerTypeTransactionTest, SetCornerRadius) {
+TEST_P(LayerTypeAndRenderTypeTransactionTest, SetCornerRadius) {
sp<SurfaceControl> layer;
const uint8_t size = 64;
const uint8_t testArea = 4;
@@ -1300,7 +1414,7 @@
{
const uint8_t bottom = size - 1;
const uint8_t right = size - 1;
- auto shot = screenshot();
+ auto shot = getScreenCapture();
// Transparent corners
shot->expectColor(Rect(0, 0, testArea, testArea), Color::BLACK);
shot->expectColor(Rect(size - testArea, 0, right, testArea), Color::BLACK);
@@ -1309,7 +1423,7 @@
}
}
-TEST_P(LayerTypeTransactionTest, SetCornerRadiusChildCrop) {
+TEST_P(LayerTypeAndRenderTypeTransactionTest, SetCornerRadiusChildCrop) {
sp<SurfaceControl> parent;
sp<SurfaceControl> child;
const uint8_t size = 64;
@@ -1328,7 +1442,7 @@
{
const uint8_t bottom = size - 1;
const uint8_t right = size - 1;
- auto shot = screenshot();
+ auto shot = getScreenCapture();
// Top edge of child should not have rounded corners because it's translated in the parent
shot->expectColor(Rect(0, size / 2, right, static_cast<int>(bottom - cornerRadius)),
Color::GREEN);
@@ -1338,7 +1452,7 @@
}
}
-TEST_F(LayerTransactionTest, SetColorBasic) {
+TEST_P(LayerRenderTypeTransactionTest, SetColorBasic) {
sp<SurfaceControl> bufferLayer;
sp<SurfaceControl> colorLayer;
ASSERT_NO_FATAL_FAILURE(bufferLayer = createLayer("test bg", 32, 32));
@@ -1354,7 +1468,7 @@
{
SCOPED_TRACE("default color");
- screenshot()->expectColor(Rect(0, 0, 32, 32), Color::BLACK);
+ getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::BLACK);
}
const half3 color(15.0f / 255.0f, 51.0f / 255.0f, 85.0f / 255.0f);
@@ -1365,11 +1479,197 @@
Transaction().setColor(colorLayer, color).apply();
{
SCOPED_TRACE("new color");
- screenshot()->expectColor(Rect(0, 0, 32, 32), expected, tolerance);
+ getScreenCapture()->expectColor(Rect(0, 0, 32, 32), expected, tolerance);
}
}
-TEST_F(LayerTransactionTest, SetColorClamped) {
+// RED: Color layer base color and BufferQueueLayer/BufferStateLayer fill
+// BLUE: prior background color
+// GREEN: final background color
+// BLACK: no color or fill
+void LayerRenderTypeTransactionTest::setBackgroundColorHelper(uint32_t layerType, bool priorColor,
+ bool bufferFill, float alpha,
+ Color finalColor) {
+ sp<SurfaceControl> layer;
+ int32_t width = 500;
+ int32_t height = 500;
+
+ Color fillColor = Color::RED;
+ Color priorBgColor = Color::BLUE;
+ Color expectedColor = Color::BLACK;
+ switch (layerType) {
+ case ISurfaceComposerClient::eFXSurfaceColor:
+ ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 0, 0, layerType));
+ Transaction()
+ .setCrop_legacy(layer, Rect(0, 0, width, height))
+ .setColor(layer, half3(1.0f, 0, 0))
+ .apply();
+ expectedColor = fillColor;
+ break;
+ case ISurfaceComposerClient::eFXSurfaceBufferQueue:
+ ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", width, height));
+ if (bufferFill) {
+ ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, fillColor, width, height));
+ expectedColor = fillColor;
+ }
+ Transaction().setCrop_legacy(layer, Rect(0, 0, width, height)).apply();
+ break;
+ case ISurfaceComposerClient::eFXSurfaceBufferState:
+ ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", width, height, layerType));
+ if (bufferFill) {
+ ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, fillColor, width, height));
+ expectedColor = fillColor;
+ }
+ Transaction().setFrame(layer, Rect(0, 0, width, height)).apply();
+ break;
+ default:
+ GTEST_FAIL() << "Unknown layer type in setBackgroundColorHelper";
+ return;
+ }
+
+ if (priorColor && layerType != ISurfaceComposerClient::eFXSurfaceColor) {
+ Transaction()
+ .setBackgroundColor(layer, half3(0, 0, 1.0f), 1.0f, ui::Dataspace::UNKNOWN)
+ .apply();
+ if (!bufferFill) {
+ expectedColor = priorBgColor;
+ }
+ }
+
+ {
+ SCOPED_TRACE("default before setting background color layer");
+ screenshot()->expectColor(Rect(0, 0, width, height), expectedColor);
+ }
+
+ Transaction()
+ .setBackgroundColor(layer, half3(0, 1.0f, 0), alpha, ui::Dataspace::UNKNOWN)
+ .apply();
+
+ {
+ auto shot = screenshot();
+ shot->expectColor(Rect(0, 0, width, height), finalColor);
+ shot->expectBorder(Rect(0, 0, width, height), Color::BLACK);
+ }
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetBackgroundColor_Color_NoEffect) {
+ bool priorColor = false;
+ bool bufferFill = false;
+ float alpha = 1.0f;
+ Color finalColor = Color::RED;
+ ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceColor,
+ priorColor, bufferFill, alpha, finalColor));
+}
+
+TEST_P(LayerRenderTypeTransactionTest,
+ SetBackgroundColor_BufferQueue_BufferFill_NoPriorColor_Basic) {
+ bool priorColor = false;
+ bool bufferFill = true;
+ float alpha = 1.0f;
+ Color finalColor = Color::RED;
+ ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferQueue,
+ priorColor, bufferFill, alpha, finalColor));
+}
+
+TEST_P(LayerRenderTypeTransactionTest,
+ SetBackgroundColor_BufferQueue_NoBufferFill_NoPriorColor_Basic) {
+ bool priorColor = false;
+ bool bufferFill = false;
+ float alpha = 1.0f;
+ Color finalColor = Color::GREEN;
+ ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferQueue,
+ priorColor, bufferFill, alpha, finalColor));
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetBackgroundColor_BufferQueue_BufferFill_PriorColor_Basic) {
+ bool priorColor = true;
+ bool bufferFill = true;
+ float alpha = 1.0f;
+ Color finalColor = Color::RED;
+ ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferQueue,
+ priorColor, bufferFill, alpha, finalColor));
+}
+
+TEST_P(LayerRenderTypeTransactionTest,
+ SetBackgroundColor_BufferQueue_NoBufferFill_PriorColor_Basic) {
+ bool priorColor = true;
+ bool bufferFill = false;
+ float alpha = 1.0f;
+ Color finalColor = Color::GREEN;
+ ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferQueue,
+ priorColor, bufferFill, alpha, finalColor));
+}
+TEST_P(LayerRenderTypeTransactionTest,
+ SetBackgroundColor_BufferQueue_NoPriorColor_ZeroAlpha_NoEffect) {
+ bool priorColor = false;
+ bool bufferFill = false;
+ float alpha = 0;
+ Color finalColor = Color::BLACK;
+ ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferQueue,
+ priorColor, bufferFill, alpha, finalColor));
+}
+
+TEST_P(LayerRenderTypeTransactionTest,
+ SetBackgroundColor_BufferQueue_PriorColor_ZeroAlpha_DeleteBackground) {
+ bool priorColor = true;
+ bool bufferFill = false;
+ float alpha = 0;
+ Color finalColor = Color::BLACK;
+ ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferQueue,
+ priorColor, bufferFill, alpha, finalColor));
+}
+
+TEST_P(LayerRenderTypeTransactionTest,
+ SetBackgroundColor_BufferState_BufferFill_NoPriorColor_Basic) {
+ bool priorColor = false;
+ bool bufferFill = true;
+ float alpha = 1.0f;
+ Color finalColor = Color::RED;
+ ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferState,
+ priorColor, bufferFill, alpha, finalColor));
+}
+
+TEST_P(LayerRenderTypeTransactionTest,
+ SetBackgroundColor_BufferState_NoBufferFill_NoPriorColor_Basic) {
+ bool priorColor = false;
+ bool bufferFill = false;
+ float alpha = 1.0f;
+ Color finalColor = Color::GREEN;
+ ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferState,
+ priorColor, bufferFill, alpha, finalColor));
+}
+
+TEST_P(LayerRenderTypeTransactionTest,
+ SetBackgroundColor_BufferState_NoBufferFill_PriorColor_Basic) {
+ bool priorColor = true;
+ bool bufferFill = false;
+ float alpha = 1.0f;
+ Color finalColor = Color::GREEN;
+ ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferState,
+ priorColor, bufferFill, alpha, finalColor));
+}
+
+TEST_P(LayerRenderTypeTransactionTest,
+ SetBackgroundColor_BufferState_NoPriorColor_ZeroAlpha_NoEffect) {
+ bool priorColor = false;
+ bool bufferFill = false;
+ float alpha = 0;
+ Color finalColor = Color::BLACK;
+ ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferState,
+ priorColor, bufferFill, alpha, finalColor));
+}
+
+TEST_P(LayerRenderTypeTransactionTest,
+ SetBackgroundColor_BufferState_PriorColor_ZeroAlpha_DeleteBackground) {
+ bool priorColor = true;
+ bool bufferFill = false;
+ float alpha = 0;
+ Color finalColor = Color::BLACK;
+ ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferState,
+ priorColor, bufferFill, alpha, finalColor));
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetColorClamped) {
sp<SurfaceControl> colorLayer;
ASSERT_NO_FATAL_FAILURE(colorLayer =
createLayer("test", 0 /* buffer width */, 0 /* buffer height */,
@@ -1379,10 +1679,10 @@
.setColor(colorLayer, half3(2.0f, -1.0f, 0.0f))
.apply();
- screenshot()->expectColor(Rect(0, 0, 32, 32), Color::RED);
+ getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED);
}
-TEST_F(LayerTransactionTest, SetColorWithAlpha) {
+TEST_P(LayerRenderTypeTransactionTest, SetColorWithAlpha) {
sp<SurfaceControl> bufferLayer;
sp<SurfaceControl> colorLayer;
ASSERT_NO_FATAL_FAILURE(bufferLayer = createLayer("test bg", 32, 32));
@@ -1403,11 +1703,11 @@
.setAlpha(colorLayer, alpha)
.setLayer(colorLayer, mLayerZBase + 1)
.apply();
- screenshot()->expectColor(Rect(0, 0, 32, 32), {expected.r, expected.g, expected.b, 255},
- tolerance);
+ getScreenCapture()->expectColor(Rect(0, 0, 32, 32), {expected.r, expected.g, expected.b, 255},
+ tolerance);
}
-TEST_F(LayerTransactionTest, SetColorWithParentAlpha_Bug74220420) {
+TEST_P(LayerRenderTypeTransactionTest, SetColorWithParentAlpha_Bug74220420) {
sp<SurfaceControl> bufferLayer;
sp<SurfaceControl> parentLayer;
sp<SurfaceControl> colorLayer;
@@ -1430,21 +1730,21 @@
.setAlpha(parentLayer, alpha)
.setLayer(parentLayer, mLayerZBase + 1)
.apply();
- screenshot()->expectColor(Rect(0, 0, 32, 32), {expected.r, expected.g, expected.b, 255},
- tolerance);
+ getScreenCapture()->expectColor(Rect(0, 0, 32, 32), {expected.r, expected.g, expected.b, 255},
+ tolerance);
}
-TEST_P(LayerTypeTransactionTest, SetColorWithBuffer) {
+TEST_P(LayerTypeAndRenderTypeTransactionTest, SetColorWithBuffer) {
sp<SurfaceControl> bufferLayer;
ASSERT_NO_FATAL_FAILURE(bufferLayer = createLayer("test", 32, 32));
ASSERT_NO_FATAL_FAILURE(fillLayerColor(bufferLayer, Color::RED, 32, 32));
// color is ignored
Transaction().setColor(bufferLayer, half3(0.0f, 1.0f, 0.0f)).apply();
- screenshot()->expectColor(Rect(0, 0, 32, 32), Color::RED);
+ getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED);
}
-TEST_P(LayerTypeTransactionTest, SetLayerStackBasic) {
+TEST_P(LayerTypeAndRenderTypeTransactionTest, SetLayerStackBasic) {
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED, 32, 32));
@@ -1452,17 +1752,17 @@
Transaction().setLayerStack(layer, mDisplayLayerStack + 1).apply();
{
SCOPED_TRACE("non-existing layer stack");
- screenshot()->expectColor(mDisplayRect, Color::BLACK);
+ getScreenCapture()->expectColor(mDisplayRect, Color::BLACK);
}
Transaction().setLayerStack(layer, mDisplayLayerStack).apply();
{
SCOPED_TRACE("original layer stack");
- screenshot()->expectColor(Rect(0, 0, 32, 32), Color::RED);
+ getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED);
}
}
-TEST_F(LayerTransactionTest, SetMatrixBasic_BufferQueue) {
+TEST_P(LayerRenderTypeTransactionTest, SetMatrixBasic_BufferQueue) {
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerQuadrant(layer, 32, 32, Color::RED, Color::GREEN,
@@ -1471,40 +1771,40 @@
Transaction().setMatrix(layer, 1.0f, 0.0f, 0.0f, 1.0f).setPosition(layer, 0, 0).apply();
{
SCOPED_TRACE("IDENTITY");
- screenshot()->expectQuadrant(Rect(0, 0, 32, 32), Color::RED, Color::GREEN, Color::BLUE,
- Color::WHITE);
+ getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::RED, Color::GREEN,
+ Color::BLUE, Color::WHITE);
}
Transaction().setMatrix(layer, -1.0f, 0.0f, 0.0f, 1.0f).setPosition(layer, 32, 0).apply();
{
SCOPED_TRACE("FLIP_H");
- screenshot()->expectQuadrant(Rect(0, 0, 32, 32), Color::GREEN, Color::RED, Color::WHITE,
- Color::BLUE);
+ getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::GREEN, Color::RED,
+ Color::WHITE, Color::BLUE);
}
Transaction().setMatrix(layer, 1.0f, 0.0f, 0.0f, -1.0f).setPosition(layer, 0, 32).apply();
{
SCOPED_TRACE("FLIP_V");
- screenshot()->expectQuadrant(Rect(0, 0, 32, 32), Color::BLUE, Color::WHITE, Color::RED,
- Color::GREEN);
+ getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::BLUE, Color::WHITE,
+ Color::RED, Color::GREEN);
}
Transaction().setMatrix(layer, 0.0f, 1.0f, -1.0f, 0.0f).setPosition(layer, 32, 0).apply();
{
SCOPED_TRACE("ROT_90");
- screenshot()->expectQuadrant(Rect(0, 0, 32, 32), Color::BLUE, Color::RED, Color::WHITE,
- Color::GREEN);
+ getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::BLUE, Color::RED,
+ Color::WHITE, Color::GREEN);
}
Transaction().setMatrix(layer, 2.0f, 0.0f, 0.0f, 2.0f).setPosition(layer, 0, 0).apply();
{
SCOPED_TRACE("SCALE");
- screenshot()->expectQuadrant(Rect(0, 0, 64, 64), Color::RED, Color::GREEN, Color::BLUE,
- Color::WHITE, true /* filtered */);
+ getScreenCapture()->expectQuadrant(Rect(0, 0, 64, 64), Color::RED, Color::GREEN,
+ Color::BLUE, Color::WHITE, true /* filtered */);
}
}
-TEST_F(LayerTransactionTest, SetMatrixBasic_BufferState) {
+TEST_P(LayerRenderTypeTransactionTest, SetMatrixBasic_BufferState) {
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(
layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
@@ -1517,40 +1817,40 @@
.apply();
{
SCOPED_TRACE("IDENTITY");
- screenshot()->expectQuadrant(Rect(0, 0, 32, 32), Color::RED, Color::GREEN, Color::BLUE,
- Color::WHITE);
+ getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::RED, Color::GREEN,
+ Color::BLUE, Color::WHITE);
}
Transaction().setMatrix(layer, -1.0f, 0.0f, 0.0f, 1.0f).apply();
{
SCOPED_TRACE("FLIP_H");
- screenshot()->expectQuadrant(Rect(0, 0, 32, 32), Color::RED, Color::GREEN, Color::BLUE,
- Color::WHITE);
+ getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::RED, Color::GREEN,
+ Color::BLUE, Color::WHITE);
}
Transaction().setMatrix(layer, 1.0f, 0.0f, 0.0f, -1.0f).apply();
{
SCOPED_TRACE("FLIP_V");
- screenshot()->expectQuadrant(Rect(0, 0, 32, 32), Color::RED, Color::GREEN, Color::BLUE,
- Color::WHITE);
+ getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::RED, Color::GREEN,
+ Color::BLUE, Color::WHITE);
}
Transaction().setMatrix(layer, 0.0f, 1.0f, -1.0f, 0.0f).apply();
{
SCOPED_TRACE("ROT_90");
- screenshot()->expectQuadrant(Rect(0, 0, 32, 32), Color::RED, Color::GREEN, Color::BLUE,
- Color::WHITE);
+ getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::RED, Color::GREEN,
+ Color::BLUE, Color::WHITE);
}
Transaction().setMatrix(layer, 2.0f, 0.0f, 0.0f, 2.0f).apply();
{
SCOPED_TRACE("SCALE");
- screenshot()->expectQuadrant(Rect(0, 0, 32, 32), Color::RED, Color::GREEN, Color::BLUE,
- Color::WHITE);
+ getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::RED, Color::GREEN,
+ Color::BLUE, Color::WHITE);
}
}
-TEST_F(LayerTransactionTest, SetMatrixRot45_BufferQueue) {
+TEST_P(LayerRenderTypeTransactionTest, SetMatrixRot45_BufferQueue) {
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerQuadrant(layer, 32, 32, Color::RED, Color::GREEN,
@@ -1560,7 +1860,7 @@
const float trans = M_SQRT2 * 16.0f;
Transaction().setMatrix(layer, rot, rot, -rot, rot).setPosition(layer, trans, 0).apply();
- auto shot = screenshot();
+ auto shot = getScreenCapture();
// check a 8x8 region inside each color
auto get8x8Rect = [](int32_t centerX, int32_t centerY) {
const int32_t halfL = 4;
@@ -1573,7 +1873,7 @@
shot->expectColor(get8x8Rect(2 * unit, 3 * unit), Color::WHITE);
}
-TEST_F(LayerTransactionTest, SetMatrixWithResize_BufferQueue) {
+TEST_P(LayerRenderTypeTransactionTest, SetMatrixWithResize_BufferQueue) {
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
@@ -1582,7 +1882,7 @@
Transaction().setMatrix(layer, 2.0f, 0.0f, 0.0f, 2.0f).setSize(layer, 64, 64).apply();
{
SCOPED_TRACE("resize pending");
- auto shot = screenshot();
+ auto shot = getScreenCapture();
const Rect rect(0, 0, 32, 32);
shot->expectColor(rect, Color::RED);
shot->expectBorder(rect, Color::BLACK);
@@ -1592,11 +1892,11 @@
{
SCOPED_TRACE("resize applied");
const Rect rect(0, 0, 128, 128);
- screenshot()->expectColor(rect, Color::RED);
+ getScreenCapture()->expectColor(rect, Color::RED);
}
}
-TEST_F(LayerTransactionTest, SetMatrixWithScaleToWindow_BufferQueue) {
+TEST_P(LayerRenderTypeTransactionTest, SetMatrixWithScaleToWindow_BufferQueue) {
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
@@ -1607,10 +1907,10 @@
.setSize(layer, 64, 64)
.setOverrideScalingMode(layer, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW)
.apply();
- screenshot()->expectColor(Rect(0, 0, 128, 128), Color::RED);
+ getScreenCapture()->expectColor(Rect(0, 0, 128, 128), Color::RED);
}
-TEST_F(LayerTransactionTest, SetOverrideScalingModeBasic_BufferQueue) {
+TEST_P(LayerRenderTypeTransactionTest, SetOverrideScalingModeBasic_BufferQueue) {
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerQuadrant(layer, 32, 32, Color::RED, Color::GREEN,
@@ -1625,8 +1925,8 @@
.apply();
{
SCOPED_TRACE("SCALE_TO_WINDOW");
- screenshot()->expectQuadrant(Rect(0, 0, 64, 16), Color::RED, Color::GREEN, Color::BLUE,
- Color::WHITE, true /* filtered */);
+ getScreenCapture()->expectQuadrant(Rect(0, 0, 64, 16), Color::RED, Color::GREEN,
+ Color::BLUE, Color::WHITE, true /* filtered */);
}
}
@@ -1643,19 +1943,19 @@
ASSERT_GT(frameStats.refreshPeriodNano, static_cast<nsecs_t>(0));
}
-TEST_F(LayerTransactionTest, SetCropBasic_BufferQueue) {
+TEST_P(LayerRenderTypeTransactionTest, SetCropBasic_BufferQueue) {
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
const Rect crop(8, 8, 24, 24);
Transaction().setCrop_legacy(layer, crop).apply();
- auto shot = screenshot();
+ auto shot = getScreenCapture();
shot->expectColor(crop, Color::RED);
shot->expectBorder(crop, Color::BLACK);
}
-TEST_F(LayerTransactionTest, SetCropBasic_BufferState) {
+TEST_P(LayerRenderTypeTransactionTest, SetCropBasic_BufferState) {
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(
layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
@@ -1663,12 +1963,12 @@
const Rect crop(8, 8, 24, 24);
Transaction().setCrop(layer, crop).apply();
- auto shot = screenshot();
+ auto shot = getScreenCapture();
shot->expectColor(Rect(0, 0, 32, 32), Color::RED);
shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
}
-TEST_F(LayerTransactionTest, SetCropEmpty_BufferQueue) {
+TEST_P(LayerRenderTypeTransactionTest, SetCropEmpty_BufferQueue) {
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
@@ -1676,17 +1976,17 @@
{
SCOPED_TRACE("empty rect");
Transaction().setCrop_legacy(layer, Rect(8, 8, 8, 8)).apply();
- screenshot()->expectColor(Rect(0, 0, 32, 32), Color::RED);
+ getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED);
}
{
SCOPED_TRACE("negative rect");
Transaction().setCrop_legacy(layer, Rect(8, 8, 0, 0)).apply();
- screenshot()->expectColor(Rect(0, 0, 32, 32), Color::RED);
+ getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED);
}
}
-TEST_F(LayerTransactionTest, SetCropEmpty_BufferState) {
+TEST_P(LayerRenderTypeTransactionTest, SetCropEmpty_BufferState) {
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(
layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
@@ -1695,28 +1995,28 @@
{
SCOPED_TRACE("empty rect");
Transaction().setCrop(layer, Rect(8, 8, 8, 8)).apply();
- screenshot()->expectColor(Rect(0, 0, 32, 32), Color::RED);
+ getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED);
}
{
SCOPED_TRACE("negative rect");
Transaction().setCrop(layer, Rect(8, 8, 0, 0)).apply();
- screenshot()->expectColor(Rect(0, 0, 32, 32), Color::RED);
+ getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED);
}
}
-TEST_F(LayerTransactionTest, SetCropOutOfBounds_BufferQueue) {
+TEST_P(LayerRenderTypeTransactionTest, SetCropOutOfBounds_BufferQueue) {
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
Transaction().setCrop_legacy(layer, Rect(-128, -64, 128, 64)).apply();
- auto shot = screenshot();
+ auto shot = getScreenCapture();
shot->expectColor(Rect(0, 0, 32, 32), Color::RED);
shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
}
-TEST_F(LayerTransactionTest, SetCropOutOfBounds_BufferState) {
+TEST_P(LayerRenderTypeTransactionTest, SetCropOutOfBounds_BufferState) {
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", mDisplayWidth, mDisplayHeight / 2,
ISurfaceComposerClient::eFXSurfaceBufferState));
@@ -1735,7 +2035,7 @@
Transaction().setCrop(layer, Rect(-128, -128, mDisplayWidth, mDisplayHeight / 4)).apply();
{
SCOPED_TRACE("out of bounds, negative (upper left) direction");
- auto shot = screenshot();
+ auto shot = getScreenCapture();
shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight / 2), Color::BLUE);
shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight / 2), Color::BLACK);
}
@@ -1746,7 +2046,7 @@
.apply();
{
SCOPED_TRACE("out of bounds, positive (lower right) direction");
- auto shot = screenshot();
+ auto shot = getScreenCapture();
shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight / 2), Color::RED);
shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight / 2), Color::BLACK);
}
@@ -1755,14 +2055,14 @@
Transaction().setCrop(layer, Rect(-128, -128, -1, -1)).apply();
{
SCOPED_TRACE("Fully out of bounds");
- auto shot = screenshot();
+ auto shot = getScreenCapture();
shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight / 4), Color::BLUE);
shot->expectColor(Rect(0, mDisplayHeight / 4, mDisplayWidth, mDisplayHeight / 2),
Color::RED);
}
}
-TEST_F(LayerTransactionTest, SetCropWithTranslation_BufferQueue) {
+TEST_P(LayerRenderTypeTransactionTest, SetCropWithTranslation_BufferQueue) {
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
@@ -1770,12 +2070,12 @@
const Point position(32, 32);
const Rect crop(8, 8, 24, 24);
Transaction().setPosition(layer, position.x, position.y).setCrop_legacy(layer, crop).apply();
- auto shot = screenshot();
+ auto shot = getScreenCapture();
shot->expectColor(crop + position, Color::RED);
shot->expectBorder(crop + position, Color::BLACK);
}
-TEST_F(LayerTransactionTest, SetCropWithTranslation_BufferState) {
+TEST_P(LayerRenderTypeTransactionTest, SetCropWithTranslation_BufferState) {
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(
layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
@@ -1784,12 +2084,12 @@
const Rect frame(32, 32, 64, 64);
const Rect crop(8, 8, 24, 24);
Transaction().setFrame(layer, frame).setCrop(layer, crop).apply();
- auto shot = screenshot();
+ auto shot = getScreenCapture();
shot->expectColor(frame, Color::RED);
shot->expectBorder(frame, Color::BLACK);
}
-TEST_F(LayerTransactionTest, SetCropWithScale_BufferQueue) {
+TEST_P(LayerRenderTypeTransactionTest, SetCropWithScale_BufferQueue) {
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
@@ -1799,12 +2099,12 @@
.setMatrix(layer, 2.0f, 0.0f, 0.0f, 2.0f)
.setCrop_legacy(layer, Rect(8, 8, 24, 24))
.apply();
- auto shot = screenshot();
+ auto shot = getScreenCapture();
shot->expectColor(Rect(16, 16, 48, 48), Color::RED);
shot->expectBorder(Rect(16, 16, 48, 48), Color::BLACK);
}
-TEST_F(LayerTransactionTest, SetCropWithResize_BufferQueue) {
+TEST_P(LayerRenderTypeTransactionTest, SetCropWithResize_BufferQueue) {
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
@@ -1813,7 +2113,7 @@
Transaction().setCrop_legacy(layer, Rect(8, 8, 24, 24)).setSize(layer, 16, 16).apply();
{
SCOPED_TRACE("resize pending");
- auto shot = screenshot();
+ auto shot = getScreenCapture();
shot->expectColor(Rect(8, 8, 24, 24), Color::RED);
shot->expectBorder(Rect(8, 8, 24, 24), Color::BLACK);
}
@@ -1821,13 +2121,13 @@
ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 16, 16));
{
SCOPED_TRACE("resize applied");
- auto shot = screenshot();
+ auto shot = getScreenCapture();
shot->expectColor(Rect(8, 8, 16, 16), Color::RED);
shot->expectBorder(Rect(8, 8, 16, 16), Color::BLACK);
}
}
-TEST_F(LayerTransactionTest, SetCropWithNextResize_BufferQueue) {
+TEST_P(LayerRenderTypeTransactionTest, SetCropWithNextResize_BufferQueue) {
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
@@ -1839,32 +2139,32 @@
.apply();
{
SCOPED_TRACE("waiting for next resize");
- screenshot()->expectColor(Rect(0, 0, 32, 32), Color::RED);
+ getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED);
}
Transaction().setCrop_legacy(layer, Rect(4, 4, 12, 12)).apply();
{
SCOPED_TRACE("pending crop modified");
- screenshot()->expectColor(Rect(0, 0, 32, 32), Color::RED);
+ getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED);
}
Transaction().setSize(layer, 16, 16).apply();
{
SCOPED_TRACE("resize pending");
- screenshot()->expectColor(Rect(0, 0, 32, 32), Color::RED);
+ getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED);
}
// finally resize
ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 16, 16));
{
SCOPED_TRACE("new crop applied");
- auto shot = screenshot();
+ auto shot = getScreenCapture();
shot->expectColor(Rect(4, 4, 12, 12), Color::RED);
shot->expectBorder(Rect(4, 4, 12, 12), Color::BLACK);
}
}
-TEST_F(LayerTransactionTest, SetCropWithNextResizeScaleToWindow_BufferQueue) {
+TEST_P(LayerRenderTypeTransactionTest, SetCropWithNextResizeScaleToWindow_BufferQueue) {
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
@@ -1878,7 +2178,7 @@
.apply();
{
SCOPED_TRACE("new crop pending");
- auto shot = screenshot();
+ auto shot = getScreenCapture();
shot->expectColor(Rect(0, 0, 16, 16), Color::RED);
shot->expectBorder(Rect(0, 0, 16, 16), Color::BLACK);
}
@@ -1889,13 +2189,13 @@
Transaction().setPosition(layer, 0, 0).apply();
{
SCOPED_TRACE("new crop applied");
- auto shot = screenshot();
+ auto shot = getScreenCapture();
shot->expectColor(Rect(4, 4, 12, 12), Color::RED);
shot->expectBorder(Rect(4, 4, 12, 12), Color::BLACK);
}
}
-TEST_F(LayerTransactionTest, SetFrameBasic_BufferState) {
+TEST_P(LayerRenderTypeTransactionTest, SetFrameBasic_BufferState) {
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(
layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
@@ -1903,12 +2203,12 @@
const Rect frame(8, 8, 24, 24);
Transaction().setFrame(layer, frame).apply();
- auto shot = screenshot();
+ auto shot = getScreenCapture();
shot->expectColor(frame, Color::RED);
shot->expectBorder(frame, Color::BLACK);
}
-TEST_F(LayerTransactionTest, SetFrameEmpty_BufferState) {
+TEST_P(LayerRenderTypeTransactionTest, SetFrameEmpty_BufferState) {
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(
layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
@@ -1917,29 +2217,29 @@
{
SCOPED_TRACE("empty rect");
Transaction().setFrame(layer, Rect(8, 8, 8, 8)).apply();
- screenshot()->expectColor(Rect(0, 0, 32, 32), Color::BLACK);
+ getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::BLACK);
}
{
SCOPED_TRACE("negative rect");
Transaction().setFrame(layer, Rect(8, 8, 0, 0)).apply();
- screenshot()->expectColor(Rect(0, 0, 32, 32), Color::BLACK);
+ getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::BLACK);
}
}
-TEST_F(LayerTransactionTest, SetFrameDefaultParentless_BufferState) {
+TEST_P(LayerRenderTypeTransactionTest, SetFrameDefaultParentless_BufferState) {
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(
layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 10, 10));
// A parentless layer will default to a frame with the same size as the buffer
- auto shot = screenshot();
+ auto shot = getScreenCapture();
shot->expectColor(Rect(0, 0, 10, 10), Color::RED);
shot->expectBorder(Rect(0, 0, 10, 10), Color::BLACK);
}
-TEST_F(LayerTransactionTest, SetFrameDefaultBSParent_BufferState) {
+TEST_P(LayerRenderTypeTransactionTest, SetFrameDefaultBSParent_BufferState) {
sp<SurfaceControl> parent, child;
ASSERT_NO_FATAL_FAILURE(
parent = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
@@ -1953,12 +2253,12 @@
Transaction().reparent(child, parent->getHandle()).apply();
// A layer will default to the frame of its parent
- auto shot = screenshot();
+ auto shot = getScreenCapture();
shot->expectColor(Rect(0, 0, 32, 32), Color::BLUE);
shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
}
-TEST_F(LayerTransactionTest, SetFrameDefaultBQParent_BufferState) {
+TEST_P(LayerRenderTypeTransactionTest, SetFrameDefaultBQParent_BufferState) {
sp<SurfaceControl> parent, child;
ASSERT_NO_FATAL_FAILURE(parent = createLayer("test", 32, 32));
ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(parent, Color::RED, 32, 32));
@@ -1970,12 +2270,12 @@
Transaction().reparent(child, parent->getHandle()).apply();
// A layer will default to the frame of its parent
- auto shot = screenshot();
+ auto shot = getScreenCapture();
shot->expectColor(Rect(0, 0, 32, 32), Color::BLUE);
shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
}
-TEST_F(LayerTransactionTest, SetFrameUpdate_BufferState) {
+TEST_P(LayerRenderTypeTransactionTest, SetFrameUpdate_BufferState) {
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(
layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
@@ -1986,12 +2286,12 @@
Transaction().setFrame(layer, Rect(16, 16, 48, 48)).apply();
- auto shot = screenshot();
+ auto shot = getScreenCapture();
shot->expectColor(Rect(16, 16, 48, 48), Color::RED);
shot->expectBorder(Rect(16, 16, 48, 48), Color::BLACK);
}
-TEST_F(LayerTransactionTest, SetFrameOutsideBounds_BufferState) {
+TEST_P(LayerRenderTypeTransactionTest, SetFrameOutsideBounds_BufferState) {
sp<SurfaceControl> parent, child;
ASSERT_NO_FATAL_FAILURE(
parent = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
@@ -2005,25 +2305,25 @@
ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(child, Color::BLUE, 10, 10));
Transaction().setFrame(child, Rect(0, 16, 32, 32)).apply();
- auto shot = screenshot();
+ auto shot = getScreenCapture();
shot->expectColor(Rect(0, 0, 32, 16), Color::RED);
shot->expectColor(Rect(0, 16, 32, 32), Color::BLUE);
shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
}
-TEST_F(LayerTransactionTest, SetBufferBasic_BufferState) {
+TEST_P(LayerRenderTypeTransactionTest, SetBufferBasic_BufferState) {
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(
layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32));
- auto shot = screenshot();
+ auto shot = getScreenCapture();
shot->expectColor(Rect(0, 0, 32, 32), Color::RED);
shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
}
-TEST_F(LayerTransactionTest, SetBufferMultipleBuffers_BufferState) {
+TEST_P(LayerRenderTypeTransactionTest, SetBufferMultipleBuffers_BufferState) {
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(
layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
@@ -2032,7 +2332,7 @@
{
SCOPED_TRACE("set buffer 1");
- auto shot = screenshot();
+ auto shot = getScreenCapture();
shot->expectColor(Rect(0, 0, 32, 32), Color::RED);
shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
}
@@ -2041,7 +2341,7 @@
{
SCOPED_TRACE("set buffer 2");
- auto shot = screenshot();
+ auto shot = getScreenCapture();
shot->expectColor(Rect(0, 0, 32, 32), Color::BLUE);
shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
}
@@ -2050,13 +2350,13 @@
{
SCOPED_TRACE("set buffer 3");
- auto shot = screenshot();
+ auto shot = getScreenCapture();
shot->expectColor(Rect(0, 0, 32, 32), Color::RED);
shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
}
}
-TEST_F(LayerTransactionTest, SetBufferMultipleLayers_BufferState) {
+TEST_P(LayerRenderTypeTransactionTest, SetBufferMultipleLayers_BufferState) {
sp<SurfaceControl> layer1;
ASSERT_NO_FATAL_FAILURE(
layer1 = createLayer("test", 64, 64, ISurfaceComposerClient::eFXSurfaceBufferState));
@@ -2070,7 +2370,7 @@
Transaction().setFrame(layer1, Rect(0, 0, 64, 64)).apply();
{
SCOPED_TRACE("set layer 1 buffer red");
- auto shot = screenshot();
+ auto shot = getScreenCapture();
shot->expectColor(Rect(0, 0, 64, 64), Color::RED);
}
@@ -2079,7 +2379,7 @@
Transaction().setFrame(layer2, Rect(0, 0, 32, 32)).apply();
{
SCOPED_TRACE("set layer 2 buffer blue");
- auto shot = screenshot();
+ auto shot = getScreenCapture();
shot->expectColor(Rect(0, 0, 32, 32), Color::BLUE);
shot->expectColor(Rect(0, 32, 64, 64), Color::RED);
shot->expectColor(Rect(0, 32, 32, 64), Color::RED);
@@ -2088,7 +2388,7 @@
ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer1, Color::GREEN, 64, 64));
{
SCOPED_TRACE("set layer 1 buffer green");
- auto shot = screenshot();
+ auto shot = getScreenCapture();
shot->expectColor(Rect(0, 0, 32, 32), Color::BLUE);
shot->expectColor(Rect(0, 32, 64, 64), Color::GREEN);
shot->expectColor(Rect(0, 32, 32, 64), Color::GREEN);
@@ -2098,14 +2398,125 @@
{
SCOPED_TRACE("set layer 2 buffer white");
- auto shot = screenshot();
+ auto shot = getScreenCapture();
shot->expectColor(Rect(0, 0, 32, 32), Color::WHITE);
shot->expectColor(Rect(0, 32, 64, 64), Color::GREEN);
shot->expectColor(Rect(0, 32, 32, 64), Color::GREEN);
}
}
-TEST_F(LayerTransactionTest, SetTransformRotate90_BufferState) {
+TEST_P(LayerRenderTypeTransactionTest, SetBufferCaching_BufferState) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(
+ layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+
+ std::array<Color, 4> colors = {Color::RED, Color::BLUE, Color::WHITE, Color::GREEN};
+
+ std::array<sp<GraphicBuffer>, 10> buffers;
+
+ size_t idx = 0;
+ for (auto& buffer : buffers) {
+ buffer = new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1,
+ BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
+ BufferUsage::COMPOSER_OVERLAY,
+ "test");
+ Color color = colors[idx % colors.size()];
+ fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), color);
+ idx++;
+ }
+
+ // Set each buffer twice. The first time adds it to the cache, the second time tests that the
+ // cache is working.
+ idx = 0;
+ for (auto& buffer : buffers) {
+ for (int i = 0; i < 2; i++) {
+ Transaction().setBuffer(layer, buffer).apply();
+
+ Color color = colors[idx % colors.size()];
+ auto shot = screenshot();
+ shot->expectColor(Rect(0, 0, 32, 32), color);
+ shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
+ }
+ idx++;
+ }
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetBufferCaching_LeastRecentlyUsed_BufferState) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(
+ layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+
+ std::array<Color, 4> colors = {Color::RED, Color::BLUE, Color::WHITE, Color::GREEN};
+
+ std::array<sp<GraphicBuffer>, 70> buffers;
+
+ size_t idx = 0;
+ for (auto& buffer : buffers) {
+ buffer = new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1,
+ BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
+ BufferUsage::COMPOSER_OVERLAY,
+ "test");
+ Color color = colors[idx % colors.size()];
+ fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), color);
+ idx++;
+ }
+
+ // Set each buffer twice. The first time adds it to the cache, the second time tests that the
+ // cache is working.
+ idx = 0;
+ for (auto& buffer : buffers) {
+ for (int i = 0; i < 2; i++) {
+ Transaction().setBuffer(layer, buffer).apply();
+
+ Color color = colors[idx % colors.size()];
+ auto shot = screenshot();
+ shot->expectColor(Rect(0, 0, 32, 32), color);
+ shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
+ }
+ idx++;
+ }
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetBufferCaching_DestroyedBuffer_BufferState) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(
+ layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+
+ std::array<Color, 4> colors = {Color::RED, Color::BLUE, Color::WHITE, Color::GREEN};
+
+ std::array<sp<GraphicBuffer>, 65> buffers;
+
+ size_t idx = 0;
+ for (auto& buffer : buffers) {
+ buffer = new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1,
+ BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
+ BufferUsage::COMPOSER_OVERLAY,
+ "test");
+ Color color = colors[idx % colors.size()];
+ fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), color);
+ idx++;
+ }
+
+ // Set each buffer twice. The first time adds it to the cache, the second time tests that the
+ // cache is working.
+ idx = 0;
+ for (auto& buffer : buffers) {
+ for (int i = 0; i < 2; i++) {
+ Transaction().setBuffer(layer, buffer).apply();
+
+ Color color = colors[idx % colors.size()];
+ auto shot = screenshot();
+ shot->expectColor(Rect(0, 0, 32, 32), color);
+ shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
+ }
+ if (idx == 0) {
+ buffers[0].clear();
+ }
+ idx++;
+ }
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetTransformRotate90_BufferState) {
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(
layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
@@ -2118,11 +2529,11 @@
.setTransform(layer, NATIVE_WINDOW_TRANSFORM_ROT_90)
.apply();
- screenshot()->expectQuadrant(Rect(0, 0, 32, 32), Color::BLUE, Color::RED, Color::WHITE,
- Color::GREEN, true /* filtered */);
+ getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::BLUE, Color::RED, Color::WHITE,
+ Color::GREEN, true /* filtered */);
}
-TEST_F(LayerTransactionTest, SetTransformFlipH_BufferState) {
+TEST_P(LayerRenderTypeTransactionTest, SetTransformFlipH_BufferState) {
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(
layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
@@ -2135,11 +2546,11 @@
.setTransform(layer, NATIVE_WINDOW_TRANSFORM_FLIP_H)
.apply();
- screenshot()->expectQuadrant(Rect(0, 0, 32, 32), Color::GREEN, Color::RED, Color::WHITE,
- Color::BLUE, true /* filtered */);
+ getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::GREEN, Color::RED, Color::WHITE,
+ Color::BLUE, true /* filtered */);
}
-TEST_F(LayerTransactionTest, SetTransformFlipV_BufferState) {
+TEST_P(LayerRenderTypeTransactionTest, SetTransformFlipV_BufferState) {
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(
layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
@@ -2152,8 +2563,8 @@
.setTransform(layer, NATIVE_WINDOW_TRANSFORM_FLIP_V)
.apply();
- screenshot()->expectQuadrant(Rect(0, 0, 32, 32), Color::BLUE, Color::WHITE, Color::RED,
- Color::GREEN, true /* filtered */);
+ getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::BLUE, Color::WHITE, Color::RED,
+ Color::GREEN, true /* filtered */);
}
TEST_F(LayerTransactionTest, SetTransformToDisplayInverse_BufferState) {
@@ -2168,7 +2579,7 @@
Transaction().setTransformToDisplayInverse(layer, true).apply();
}
-TEST_F(LayerTransactionTest, SetFenceBasic_BufferState) {
+TEST_P(LayerRenderTypeTransactionTest, SetFenceBasic_BufferState) {
sp<SurfaceControl> layer;
Transaction transaction;
ASSERT_NO_FATAL_FAILURE(
@@ -2193,12 +2604,12 @@
ASSERT_NE(static_cast<status_t>(Fence::Status::Unsignaled), status);
std::this_thread::sleep_for(200ms);
- auto shot = screenshot();
+ auto shot = getScreenCapture();
shot->expectColor(Rect(0, 0, 32, 32), Color::RED);
shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
}
-TEST_F(LayerTransactionTest, SetFenceNull_BufferState) {
+TEST_P(LayerRenderTypeTransactionTest, SetFenceNull_BufferState) {
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(
layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
@@ -2217,12 +2628,12 @@
.setAcquireFence(layer, fence)
.apply();
- auto shot = screenshot();
+ auto shot = getScreenCapture();
shot->expectColor(Rect(0, 0, 32, 32), Color::RED);
shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
}
-TEST_F(LayerTransactionTest, SetDataspaceBasic_BufferState) {
+TEST_P(LayerRenderTypeTransactionTest, SetDataspaceBasic_BufferState) {
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(
layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
@@ -2239,12 +2650,12 @@
.setDataspace(layer, ui::Dataspace::UNKNOWN)
.apply();
- auto shot = screenshot();
+ auto shot = getScreenCapture();
shot->expectColor(Rect(0, 0, 32, 32), Color::RED);
shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
}
-TEST_F(LayerTransactionTest, SetHdrMetadataBasic_BufferState) {
+TEST_P(LayerRenderTypeTransactionTest, SetHdrMetadataBasic_BufferState) {
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(
layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
@@ -2263,12 +2674,12 @@
.setHdrMetadata(layer, hdrMetadata)
.apply();
- auto shot = screenshot();
+ auto shot = getScreenCapture();
shot->expectColor(Rect(0, 0, 32, 32), Color::RED);
shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
}
-TEST_F(LayerTransactionTest, SetSurfaceDamageRegionBasic_BufferState) {
+TEST_P(LayerRenderTypeTransactionTest, SetSurfaceDamageRegionBasic_BufferState) {
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(
layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
@@ -2287,12 +2698,12 @@
.setSurfaceDamageRegion(layer, region)
.apply();
- auto shot = screenshot();
+ auto shot = getScreenCapture();
shot->expectColor(Rect(0, 0, 32, 32), Color::RED);
shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
}
-TEST_F(LayerTransactionTest, SetApiBasic_BufferState) {
+TEST_P(LayerRenderTypeTransactionTest, SetApiBasic_BufferState) {
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(
layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
@@ -2309,7 +2720,7 @@
.setApi(layer, NATIVE_WINDOW_API_CPU)
.apply();
- auto shot = screenshot();
+ auto shot = getScreenCapture();
shot->expectColor(Rect(0, 0, 32, 32), Color::RED);
shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
}
@@ -2323,6 +2734,23 @@
Transaction().setSidebandStream(layer, nullptr).apply();
}
+TEST_F(LayerTransactionTest, ReparentToSelf) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
+ ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
+ Transaction().reparent(layer, layer->getHandle()).apply();
+
+ {
+ // We expect the transaction to be silently dropped, but for SurfaceFlinger
+ // to still be functioning.
+ SCOPED_TRACE("after reparent to self");
+ const Rect rect(0, 0, 32, 32);
+ auto shot = screenshot();
+ shot->expectColor(rect, Color::RED);
+ shot->expectBorder(rect, Color::BLACK);
+ }
+}
+
class ColorTransformHelper {
public:
static void DegammaColorSingle(half& s) {
@@ -2364,7 +2792,7 @@
}
};
-TEST_F(LayerTransactionTest, SetColorTransformBasic) {
+TEST_P(LayerRenderTypeTransactionTest, SetColorTransformBasic) {
sp<SurfaceControl> colorLayer;
ASSERT_NO_FATAL_FAILURE(colorLayer =
createLayer("test", 0 /* buffer width */, 0 /* buffer height */,
@@ -2375,7 +2803,7 @@
.apply();
{
SCOPED_TRACE("default color");
- screenshot()->expectColor(Rect(0, 0, 32, 32), Color::BLACK);
+ getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::BLACK);
}
const half3 color(50.0f / 255.0f, 100.0f / 255.0f, 150.0f / 255.0f);
@@ -2407,11 +2835,11 @@
.setColorTransform(colorLayer, matrix, vec3()).apply();
{
SCOPED_TRACE("new color");
- screenshot()->expectColor(Rect(0, 0, 32, 32), expectedColor, tolerance);
+ getScreenCapture()->expectColor(Rect(0, 0, 32, 32), expectedColor, tolerance);
}
}
-TEST_F(LayerTransactionTest, SetColorTransformOnParent) {
+TEST_P(LayerRenderTypeTransactionTest, SetColorTransformOnParent) {
sp<SurfaceControl> parentLayer;
sp<SurfaceControl> colorLayer;
ASSERT_NO_FATAL_FAILURE(parentLayer = createLayer("parent", 0 /* buffer width */,
@@ -2428,7 +2856,7 @@
.apply();
{
SCOPED_TRACE("default color");
- screenshot()->expectColor(Rect(0, 0, 32, 32), Color::BLACK);
+ getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::BLACK);
}
const half3 color(50.0f / 255.0f, 100.0f / 255.0f, 150.0f / 255.0f);
@@ -2462,11 +2890,11 @@
.apply();
{
SCOPED_TRACE("new color");
- screenshot()->expectColor(Rect(0, 0, 32, 32), expectedColor, tolerance);
+ getScreenCapture()->expectColor(Rect(0, 0, 32, 32), expectedColor, tolerance);
}
}
-TEST_F(LayerTransactionTest, SetColorTransformOnChildAndParent) {
+TEST_P(LayerRenderTypeTransactionTest, SetColorTransformOnChildAndParent) {
sp<SurfaceControl> parentLayer;
sp<SurfaceControl> colorLayer;
ASSERT_NO_FATAL_FAILURE(parentLayer = createLayer("parent", 0 /* buffer width */,
@@ -2483,7 +2911,7 @@
.apply();
{
SCOPED_TRACE("default color");
- screenshot()->expectColor(Rect(0, 0, 32, 32), Color::BLACK);
+ getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::BLACK);
}
const half3 color(50.0f / 255.0f, 100.0f / 255.0f, 150.0f / 255.0f);
@@ -2523,10 +2951,21 @@
.apply();
{
SCOPED_TRACE("new color");
- screenshot()->expectColor(Rect(0, 0, 32, 32), expectedColor, tolerance);
+ getScreenCapture()->expectColor(Rect(0, 0, 32, 32), expectedColor, tolerance);
}
}
+struct CallbackData {
+ CallbackData() = default;
+ CallbackData(nsecs_t time, const sp<Fence>& fence,
+ const std::vector<SurfaceControlStats>& stats)
+ : latchTime(time), presentFence(fence), surfaceControlStats(stats) {}
+
+ nsecs_t latchTime;
+ sp<Fence> presentFence;
+ std::vector<SurfaceControlStats> surfaceControlStats;
+};
+
class ExpectedResult {
public:
enum Transaction {
@@ -2542,6 +2981,7 @@
enum PreviousBuffer {
NOT_RELEASED = 0,
RELEASED,
+ UNKNOWN,
};
void reset() {
@@ -2553,8 +2993,7 @@
ExpectedResult::Buffer bufferResult = ACQUIRED,
ExpectedResult::PreviousBuffer previousBufferResult = NOT_RELEASED) {
mTransactionResult = transactionResult;
- mExpectedSurfaceResults.emplace(std::piecewise_construct,
- std::forward_as_tuple(layer->getHandle()),
+ mExpectedSurfaceResults.emplace(std::piecewise_construct, std::forward_as_tuple(layer),
std::forward_as_tuple(bufferResult, previousBufferResult));
}
@@ -2567,24 +3006,38 @@
}
}
- void verifyTransactionStats(const TransactionStats& transactionStats) const {
- const auto& [latchTime, presentFence, surfaceStats] = transactionStats;
+ void addExpectedPresentTime(nsecs_t expectedPresentTime) {
+ mExpectedPresentTime = expectedPresentTime;
+ }
+
+ void verifyCallbackData(const CallbackData& callbackData) const {
+ const auto& [latchTime, presentFence, surfaceControlStats] = callbackData;
if (mTransactionResult == ExpectedResult::Transaction::PRESENTED) {
ASSERT_GE(latchTime, 0) << "bad latch time";
ASSERT_NE(presentFence, nullptr);
+ if (mExpectedPresentTime >= 0) {
+ ASSERT_EQ(presentFence->wait(3000), NO_ERROR);
+ ASSERT_GE(presentFence->getSignalTime(), mExpectedPresentTime - nsecs_t(5 * 1e6));
+ // if the panel is running at 30 hz, at the worst case, our expected time just
+ // misses vsync and we have to wait another 33.3ms
+ ASSERT_LE(presentFence->getSignalTime(),
+ mExpectedPresentTime + nsecs_t(66.666666 * 1e6));
+ }
} else {
ASSERT_EQ(presentFence, nullptr) << "transaction shouldn't have been presented";
ASSERT_EQ(latchTime, -1) << "unpresented transactions shouldn't be latched";
}
- ASSERT_EQ(surfaceStats.size(), mExpectedSurfaceResults.size())
+ ASSERT_EQ(surfaceControlStats.size(), mExpectedSurfaceResults.size())
<< "wrong number of surfaces";
- for (const auto& stats : surfaceStats) {
+ for (const auto& stats : surfaceControlStats) {
+ ASSERT_NE(stats.surfaceControl, nullptr) << "returned null surface control";
+
const auto& expectedSurfaceResult = mExpectedSurfaceResults.find(stats.surfaceControl);
ASSERT_NE(expectedSurfaceResult, mExpectedSurfaceResults.end())
<< "unexpected surface control";
- expectedSurfaceResult->second.verifySurfaceStats(stats, latchTime);
+ expectedSurfaceResult->second.verifySurfaceControlStats(stats, latchTime);
}
}
@@ -2595,15 +3048,21 @@
ExpectedResult::PreviousBuffer previousBufferResult)
: mBufferResult(bufferResult), mPreviousBufferResult(previousBufferResult) {}
- void verifySurfaceStats(const SurfaceStats& surfaceStats, nsecs_t latchTime) const {
- const auto& [surfaceControl, acquireTime, releasePreviousBuffer] = surfaceStats;
+ void verifySurfaceControlStats(const SurfaceControlStats& surfaceControlStats,
+ nsecs_t latchTime) const {
+ const auto& [surfaceControl, acquireTime, previousReleaseFence] = surfaceControlStats;
ASSERT_EQ(acquireTime > 0, mBufferResult == ExpectedResult::Buffer::ACQUIRED)
<< "bad acquire time";
ASSERT_LE(acquireTime, latchTime) << "acquire time should be <= latch time";
- ASSERT_EQ(releasePreviousBuffer,
- mPreviousBufferResult == ExpectedResult::PreviousBuffer::RELEASED)
- << "bad previous buffer released";
+
+ if (mPreviousBufferResult == ExpectedResult::PreviousBuffer::RELEASED) {
+ ASSERT_NE(previousReleaseFence, nullptr)
+ << "failed to set release prev buffer fence";
+ } else if (mPreviousBufferResult == ExpectedResult::PreviousBuffer::NOT_RELEASED) {
+ ASSERT_EQ(previousReleaseFence, nullptr)
+ << "should not have set released prev buffer fence";
+ }
}
private:
@@ -2611,38 +3070,40 @@
ExpectedResult::PreviousBuffer mPreviousBufferResult;
};
- struct IBinderHash {
- std::size_t operator()(const sp<IBinder>& strongPointer) const {
- return std::hash<IBinder*>{}(strongPointer.get());
+ struct SCHash {
+ std::size_t operator()(const sp<SurfaceControl>& sc) const {
+ return std::hash<IBinder*>{}(sc->getHandle().get());
}
};
ExpectedResult::Transaction mTransactionResult = ExpectedResult::Transaction::NOT_PRESENTED;
- std::unordered_map<sp<IBinder>, ExpectedSurfaceResult, IBinderHash> mExpectedSurfaceResults;
+ nsecs_t mExpectedPresentTime = -1;
+ std::unordered_map<sp<SurfaceControl>, ExpectedSurfaceResult, SCHash> mExpectedSurfaceResults;
};
class CallbackHelper {
public:
- static void function(void* callbackContext, const TransactionStats& transactionStats) {
+ static void function(void* callbackContext, nsecs_t latchTime, const sp<Fence>& presentFence,
+ const std::vector<SurfaceControlStats>& stats) {
if (!callbackContext) {
ALOGE("failed to get callback context");
}
CallbackHelper* helper = static_cast<CallbackHelper*>(callbackContext);
std::lock_guard lock(helper->mMutex);
- helper->mTransactionStatsQueue.push(transactionStats);
+ helper->mCallbackDataQueue.emplace(latchTime, presentFence, stats);
helper->mConditionVariable.notify_all();
}
- void getTransactionStats(TransactionStats* outStats) {
+ void getCallbackData(CallbackData* outData) {
std::unique_lock lock(mMutex);
- if (mTransactionStatsQueue.empty()) {
+ if (mCallbackDataQueue.empty()) {
ASSERT_NE(mConditionVariable.wait_for(lock, std::chrono::seconds(3)),
std::cv_status::timeout)
<< "did not receive callback";
}
- *outStats = std::move(mTransactionStatsQueue.front());
- mTransactionStatsQueue.pop();
+ *outData = std::move(mCallbackDataQueue.front());
+ mCallbackDataQueue.pop();
}
void verifyFinalState() {
@@ -2650,15 +3111,15 @@
std::this_thread::sleep_for(500ms);
std::lock_guard lock(mMutex);
- EXPECT_EQ(mTransactionStatsQueue.size(), 0) << "extra callbacks received";
- mTransactionStatsQueue = {};
+ EXPECT_EQ(mCallbackDataQueue.size(), 0) << "extra callbacks received";
+ mCallbackDataQueue = {};
}
void* getContext() { return static_cast<void*>(this); }
std::mutex mMutex;
std::condition_variable mConditionVariable;
- std::queue<TransactionStats> mTransactionStatsQueue;
+ std::queue<CallbackData> mCallbackDataQueue;
};
class LayerCallbackTest : public LayerTransactionTest {
@@ -2687,9 +3148,9 @@
static void waitForCallback(CallbackHelper& helper, const ExpectedResult& expectedResult,
bool finalState = false) {
- TransactionStats transactionStats;
- ASSERT_NO_FATAL_FAILURE(helper.getTransactionStats(&transactionStats));
- EXPECT_NO_FATAL_FAILURE(expectedResult.verifyTransactionStats(transactionStats));
+ CallbackData callbackData;
+ ASSERT_NO_FATAL_FAILURE(helper.getCallbackData(&callbackData));
+ EXPECT_NO_FATAL_FAILURE(expectedResult.verifyCallbackData(callbackData));
if (finalState) {
ASSERT_NO_FATAL_FAILURE(helper.verifyFinalState());
@@ -3177,13 +3638,11 @@
Transaction transaction;
CallbackHelper callback;
std::vector<ExpectedResult> expectedResults(50);
- ExpectedResult::PreviousBuffer previousBufferResult =
- ExpectedResult::PreviousBuffer::NOT_RELEASED;
for (auto& expected : expectedResults) {
expected.reset();
expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer,
- ExpectedResult::Buffer::ACQUIRED, previousBufferResult);
- previousBufferResult = ExpectedResult::PreviousBuffer::RELEASED;
+ ExpectedResult::Buffer::ACQUIRED,
+ ExpectedResult::PreviousBuffer::UNKNOWN);
int err = fillTransaction(transaction, &callback, layer);
if (err) {
@@ -3268,6 +3727,143 @@
EXPECT_NO_FATAL_FAILURE(waitForCallbacks(callback, expectedResults, true));
}
+TEST_F(LayerCallbackTest, DesiredPresentTime) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
+
+ Transaction transaction;
+ CallbackHelper callback;
+ int err = fillTransaction(transaction, &callback, layer);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+
+ // Try to present 100ms in the future
+ nsecs_t time = systemTime() + (100 * 1e6);
+
+ transaction.setDesiredPresentTime(time);
+ transaction.apply();
+
+ ExpectedResult expected;
+ expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer);
+ expected.addExpectedPresentTime(time);
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true));
+}
+
+TEST_F(LayerCallbackTest, DesiredPresentTime_Multiple) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
+
+ Transaction transaction;
+ CallbackHelper callback1;
+ int err = fillTransaction(transaction, &callback1, layer);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+
+ // Try to present 100ms in the future
+ nsecs_t time = systemTime() + (100 * 1e6);
+
+ transaction.setDesiredPresentTime(time);
+ transaction.apply();
+
+ ExpectedResult expected1;
+ expected1.addSurface(ExpectedResult::Transaction::PRESENTED, layer);
+ expected1.addExpectedPresentTime(time);
+
+ CallbackHelper callback2;
+ err = fillTransaction(transaction, &callback2, layer);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+
+ // Try to present 33ms after the first frame
+ time += (33.3 * 1e6);
+
+ transaction.setDesiredPresentTime(time);
+ transaction.apply();
+
+ ExpectedResult expected2;
+ expected2.addSurface(ExpectedResult::Transaction::PRESENTED, layer,
+ ExpectedResult::Buffer::ACQUIRED,
+ ExpectedResult::PreviousBuffer::RELEASED);
+ expected2.addExpectedPresentTime(time);
+
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected1, true));
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected2, true));
+}
+
+TEST_F(LayerCallbackTest, DesiredPresentTime_OutOfOrder) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
+
+ Transaction transaction;
+ CallbackHelper callback1;
+ int err = fillTransaction(transaction, &callback1, layer);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+
+ // Try to present 100ms in the future
+ nsecs_t time = systemTime() + (100 * 1e6);
+
+ transaction.setDesiredPresentTime(time);
+ transaction.apply();
+
+ ExpectedResult expected1;
+ expected1.addSurface(ExpectedResult::Transaction::PRESENTED, layer);
+ expected1.addExpectedPresentTime(time);
+
+ CallbackHelper callback2;
+ err = fillTransaction(transaction, &callback2, layer);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+
+ // Try to present 33ms before the previous frame
+ time -= (33.3 * 1e6);
+
+ transaction.setDesiredPresentTime(time);
+ transaction.apply();
+
+ ExpectedResult expected2;
+ expected2.addSurface(ExpectedResult::Transaction::PRESENTED, layer,
+ ExpectedResult::Buffer::ACQUIRED,
+ ExpectedResult::PreviousBuffer::RELEASED);
+
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected1, true));
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected2, true));
+}
+
+TEST_F(LayerCallbackTest, DesiredPresentTime_Past) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
+
+ Transaction transaction;
+ CallbackHelper callback;
+ int err = fillTransaction(transaction, &callback, layer);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+
+ // Try to present 100ms in the past
+ nsecs_t time = systemTime() - (100 * 1e6);
+
+ transaction.setDesiredPresentTime(time);
+ transaction.apply();
+
+ ExpectedResult expected;
+ expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer);
+ expected.addExpectedPresentTime(systemTime());
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true));
+}
+
class LayerUpdateTest : public LayerTransactionTest {
protected:
virtual void SetUp() {
@@ -4030,9 +4626,9 @@
asTransaction([&](Transaction& t) { t.reparent(mChild, nullptr); });
{
mCapture = screenshot();
- // Nothing should have changed.
+ // The surface should now be offscreen.
mCapture->expectFGColor(64, 64);
- mCapture->expectChildColor(74, 74);
+ mCapture->expectFGColor(74, 74);
mCapture->expectFGColor(84, 84);
}
}
@@ -4610,7 +5206,7 @@
ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(redLayer, Color::RED, 60, 60));
auto redLayerHandle = redLayer->getHandle();
- mClient->destroySurface(redLayerHandle);
+ redLayer->clear();
SurfaceComposerClient::Transaction().apply(true);
sp<GraphicBuffer> outBuffer;
diff --git a/services/surfaceflinger/tests/fakehwc/Android.bp b/services/surfaceflinger/tests/fakehwc/Android.bp
index a5b522e..68cf61e 100644
--- a/services/surfaceflinger/tests/fakehwc/Android.bp
+++ b/services/surfaceflinger/tests/fakehwc/Android.bp
@@ -11,6 +11,7 @@
shared_libs: [
"android.hardware.graphics.composer@2.1",
"android.hardware.graphics.mapper@2.0",
+ "android.hardware.graphics.mapper@3.0",
"android.hardware.power@1.3",
"libbase",
"libbinder",
@@ -30,6 +31,7 @@
"libutils",
],
static_libs: [
+ "libcompositionengine",
"libgmock",
"librenderengine",
"libtrace_proto",
diff --git a/services/surfaceflinger/tests/fakehwc/FakeComposerClient.cpp b/services/surfaceflinger/tests/fakehwc/FakeComposerClient.cpp
index 973156a..eeb6efe 100644
--- a/services/surfaceflinger/tests/fakehwc/FakeComposerClient.cpp
+++ b/services/surfaceflinger/tests/fakehwc/FakeComposerClient.cpp
@@ -81,7 +81,7 @@
class DelayedEventGenerator {
public:
- DelayedEventGenerator(std::function<void()> onTimerExpired)
+ explicit DelayedEventGenerator(std::function<void()> onTimerExpired)
: mOnTimerExpired(onTimerExpired), mThread([this]() { loop(); }) {}
~DelayedEventGenerator() {
diff --git a/services/surfaceflinger/tests/fakehwc/FakeComposerService.h b/services/surfaceflinger/tests/fakehwc/FakeComposerService.h
index c439b7e..a3fb8a6 100644
--- a/services/surfaceflinger/tests/fakehwc/FakeComposerService.h
+++ b/services/surfaceflinger/tests/fakehwc/FakeComposerService.h
@@ -26,7 +26,7 @@
class FakeComposerService : public IComposer {
public:
- FakeComposerService(android::sp<ComposerClient>& client);
+ explicit FakeComposerService(android::sp<ComposerClient>& client);
virtual ~FakeComposerService();
Return<void> getCapabilities(getCapabilities_cb hidl_cb) override;
diff --git a/services/surfaceflinger/tests/fakehwc/FakeComposerUtils.h b/services/surfaceflinger/tests/fakehwc/FakeComposerUtils.h
index 1258a97..7d20d3c 100644
--- a/services/surfaceflinger/tests/fakehwc/FakeComposerUtils.h
+++ b/services/surfaceflinger/tests/fakehwc/FakeComposerUtils.h
@@ -100,10 +100,7 @@
*/
class TransactionScope : public android::SurfaceComposerClient::Transaction {
public:
- TransactionScope(FakeComposerClient& composer) :
- Transaction(),
- mComposer(composer) {
- }
+ explicit TransactionScope(FakeComposerClient& composer) : Transaction(), mComposer(composer) {}
~TransactionScope() {
int frameCount = mComposer.getFrameCount();
diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestProperties.h b/services/surfaceflinger/tests/hwc2/Hwc2TestProperties.h
index d7082f3..06ae314 100644
--- a/services/surfaceflinger/tests/hwc2/Hwc2TestProperties.h
+++ b/services/surfaceflinger/tests/hwc2/Hwc2TestProperties.h
@@ -171,7 +171,7 @@
class Hwc2TestBlendMode : public Hwc2TestProperty<hwc2_blend_mode_t> {
public:
- Hwc2TestBlendMode(Hwc2TestCoverage coverage);
+ explicit Hwc2TestBlendMode(Hwc2TestCoverage coverage);
std::string dump() const override;
@@ -192,8 +192,8 @@
class Hwc2TestColor : public Hwc2TestProperty<hwc_color_t> {
public:
- Hwc2TestColor(Hwc2TestCoverage coverage,
- hwc2_blend_mode_t blendMode = HWC2_BLEND_MODE_NONE);
+ explicit Hwc2TestColor(Hwc2TestCoverage coverage,
+ hwc2_blend_mode_t blendMode = HWC2_BLEND_MODE_NONE);
std::string dump() const override;
@@ -217,7 +217,7 @@
class Hwc2TestComposition : public Hwc2TestProperty<hwc2_composition_t> {
public:
- Hwc2TestComposition(Hwc2TestCoverage coverage);
+ explicit Hwc2TestComposition(Hwc2TestCoverage coverage);
std::string dump() const override;
@@ -232,7 +232,7 @@
class Hwc2TestDataspace : public Hwc2TestProperty<android::ui::Dataspace> {
public:
- Hwc2TestDataspace(Hwc2TestCoverage coverage);
+ explicit Hwc2TestDataspace(Hwc2TestCoverage coverage);
std::string dump() const override;
@@ -248,7 +248,7 @@
class Hwc2TestDisplayDimension : public Hwc2TestProperty<UnsignedArea> {
public:
- Hwc2TestDisplayDimension(Hwc2TestCoverage coverage);
+ explicit Hwc2TestDisplayDimension(Hwc2TestCoverage coverage);
std::string dump() const;
@@ -291,7 +291,7 @@
class Hwc2TestPlaneAlpha : public Hwc2TestProperty<float> {
public:
- Hwc2TestPlaneAlpha(Hwc2TestCoverage coverage);
+ explicit Hwc2TestPlaneAlpha(Hwc2TestCoverage coverage);
std::string dump() const override;
@@ -306,7 +306,7 @@
class Hwc2TestSourceCrop : public Hwc2TestProperty<hwc_frect_t> {
public:
- Hwc2TestSourceCrop(Hwc2TestCoverage coverage, const Area& bufferArea = {0, 0});
+ explicit Hwc2TestSourceCrop(Hwc2TestCoverage coverage, const Area& bufferArea = {0, 0});
std::string dump() const override;
@@ -330,7 +330,7 @@
class Hwc2TestSurfaceDamage : public Hwc2TestProperty<hwc_region_t> {
public:
- Hwc2TestSurfaceDamage(Hwc2TestCoverage coverage);
+ explicit Hwc2TestSurfaceDamage(Hwc2TestCoverage coverage);
~Hwc2TestSurfaceDamage();
std::string dump() const override;
@@ -356,7 +356,7 @@
class Hwc2TestTransform : public Hwc2TestProperty<hwc_transform_t> {
public:
- Hwc2TestTransform(Hwc2TestCoverage coverage);
+ explicit Hwc2TestTransform(Hwc2TestCoverage coverage);
std::string dump() const override;
diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestVirtualDisplay.h b/services/surfaceflinger/tests/hwc2/Hwc2TestVirtualDisplay.h
index 10c8ef0..5a74a6c 100644
--- a/services/surfaceflinger/tests/hwc2/Hwc2TestVirtualDisplay.h
+++ b/services/surfaceflinger/tests/hwc2/Hwc2TestVirtualDisplay.h
@@ -29,7 +29,7 @@
class Hwc2TestVirtualDisplay {
public:
- Hwc2TestVirtualDisplay(Hwc2TestCoverage coverage);
+ explicit Hwc2TestVirtualDisplay(Hwc2TestCoverage coverage);
std::string dump() const;
diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp
index 2f35ae5..b1d45f39 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -20,6 +20,16 @@
// Using the address sanitizer not only helps uncover issues in the code
// covered by the tests, but also covers some of the tricky injection of
// fakes the unit tests currently do.
+ //
+ // Note: If you get an runtime link error like:
+ //
+ // CANNOT LINK EXECUTABLE "/data/local/tmp/libsurfaceflinger_unittest": library "libclang_rt.asan-aarch64-android.so" not found
+ //
+ // it is because the address sanitizer shared objects are not installed
+ // by default in the system image.
+ //
+ // You can either "make dist tests" before flashing, or set this
+ // option to false temporarily.
address: true,
},
srcs: [
@@ -32,11 +42,13 @@
"EventThreadTest.cpp",
"IdleTimerTest.cpp",
"LayerHistoryTest.cpp",
+ "LayerMetadataTest.cpp",
"SchedulerTest.cpp",
"SchedulerUtilsTest.cpp",
+ "RefreshRateStatsTest.cpp",
"TimeStatsTest.cpp",
"mock/DisplayHardware/MockComposer.cpp",
- "mock/DisplayHardware/MockDisplaySurface.cpp",
+ "mock/DisplayHardware/MockDisplay.cpp",
"mock/DisplayHardware/MockPowerAdvisor.cpp",
"mock/gui/MockGraphicBufferConsumer.cpp",
"mock/gui/MockGraphicBufferProducer.cpp",
@@ -46,11 +58,14 @@
"mock/MockMessageQueue.cpp",
"mock/MockNativeWindowSurface.cpp",
"mock/MockSurfaceInterceptor.cpp",
- "mock/RenderEngine/MockRenderEngine.cpp",
+ "mock/MockTimeStats.cpp",
"mock/system/window/MockNativeWindow.cpp",
],
static_libs: [
"libgmock",
+ "libcompositionengine",
+ "libcompositionengine_mocks",
+ "librenderengine_mocks",
],
header_libs: [
"libsurfaceflinger_headers",
diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
index b7c09ed..e092aed 100644
--- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
@@ -17,11 +17,14 @@
#undef LOG_TAG
#define LOG_TAG "CompositionTest"
+#include <compositionengine/mock/DisplaySurface.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
-
#include <gui/IProducerListener.h>
#include <log/log.h>
+#include <renderengine/mock/Framebuffer.h>
+#include <renderengine/mock/Image.h>
+#include <renderengine/mock/RenderEngine.h>
#include <system/window.h>
#include <utils/String8.h>
@@ -31,12 +34,10 @@
#include "TestableSurfaceFlinger.h"
#include "mock/DisplayHardware/MockComposer.h"
-#include "mock/DisplayHardware/MockDisplaySurface.h"
#include "mock/MockDispSync.h"
#include "mock/MockEventControlThread.h"
#include "mock/MockEventThread.h"
#include "mock/MockMessageQueue.h"
-#include "mock/RenderEngine/MockRenderEngine.h"
#include "mock/system/window/MockNativeWindow.h"
namespace android {
@@ -94,6 +95,7 @@
EXPECT_CALL(*mPrimaryDispSync, computeNextRefresh(0)).WillRepeatedly(Return(0));
EXPECT_CALL(*mPrimaryDispSync, getPeriod())
.WillRepeatedly(Return(FakeHwcDisplayInjector::DEFAULT_REFRESH_RATE));
+ EXPECT_CALL(*mPrimaryDispSync, expectedPresentTime()).WillRepeatedly(Return(0));
EXPECT_CALL(*mNativeWindow, query(NATIVE_WINDOW_WIDTH, _))
.WillRepeatedly(DoAll(SetArgPointee<1>(DEFAULT_DISPLAY_WIDTH), Return(0)));
EXPECT_CALL(*mNativeWindow, query(NATIVE_WINDOW_HEIGHT, _))
@@ -143,7 +145,8 @@
TestableSurfaceFlinger mFlinger;
sp<DisplayDevice> mDisplay;
sp<DisplayDevice> mExternalDisplay;
- sp<mock::DisplaySurface> mDisplaySurface = new mock::DisplaySurface();
+ sp<compositionengine::mock::DisplaySurface> mDisplaySurface =
+ new compositionengine::mock::DisplaySurface();
mock::NativeWindow* mNativeWindow = new mock::NativeWindow();
sp<GraphicBuffer> mBuffer = new GraphicBuffer();
@@ -236,16 +239,23 @@
static constexpr int INIT_POWER_MODE = HWC_POWER_MODE_NORMAL;
static void setupPreconditions(CompositionTest* test) {
- EXPECT_CALL(*test->mNativeWindow, query(NATIVE_WINDOW_WIDTH, _))
- .WillRepeatedly(DoAll(SetArgPointee<1>(DEFAULT_DISPLAY_WIDTH), Return(0)));
- EXPECT_CALL(*test->mNativeWindow, query(NATIVE_WINDOW_HEIGHT, _))
- .WillRepeatedly(DoAll(SetArgPointee<1>(DEFAULT_DISPLAY_HEIGHT), Return(0)));
+ EXPECT_CALL(*test->mComposer, getDisplayCapabilities(HWC_DISPLAY, _))
+ .WillOnce(DoAll(SetArgPointee<1>(std::vector<Hwc2::DisplayCapability>({})),
+ Return(Error::NONE)));
FakeHwcDisplayInjector(DEFAULT_DISPLAY_ID, HWC2::DisplayType::Physical,
true /* isPrimary */)
.setCapabilities(&test->mDefaultCapabilities)
.inject(&test->mFlinger, test->mComposer);
+ Mock::VerifyAndClear(test->mComposer);
+ EXPECT_CALL(*test->mNativeWindow, query(NATIVE_WINDOW_WIDTH, _))
+ .WillRepeatedly(DoAll(SetArgPointee<1>(DEFAULT_DISPLAY_WIDTH), Return(0)));
+ EXPECT_CALL(*test->mNativeWindow, query(NATIVE_WINDOW_HEIGHT, _))
+ .WillRepeatedly(DoAll(SetArgPointee<1>(DEFAULT_DISPLAY_HEIGHT), Return(0)));
+ EXPECT_CALL(*test->mNativeWindow, perform(NATIVE_WINDOW_SET_BUFFERS_FORMAT)).Times(1);
+ EXPECT_CALL(*test->mNativeWindow, perform(NATIVE_WINDOW_API_CONNECT)).Times(1);
+ EXPECT_CALL(*test->mNativeWindow, perform(NATIVE_WINDOW_SET_USAGE64)).Times(1);
test->mDisplay = FakeDisplayDeviceInjector(test->mFlinger, DEFAULT_DISPLAY_ID,
false /* isVirtual */, true /* isPrimary */)
.setDisplaySurface(test->mDisplaySurface)
@@ -253,6 +263,7 @@
.setSecure(Derived::IS_SECURE)
.setPowerMode(Derived::INIT_POWER_MODE)
.inject();
+ Mock::VerifyAndClear(test->mNativeWindow);
test->mDisplay->setLayerStack(DEFAULT_LAYER_STACK);
}
@@ -325,11 +336,14 @@
}
static void setupHwcCompositionCallExpectations(CompositionTest* test) {
- EXPECT_CALL(*test->mDisplaySurface, prepareFrame(DisplaySurface::COMPOSITION_HWC)).Times(1);
+ EXPECT_CALL(*test->mDisplaySurface,
+ prepareFrame(compositionengine::DisplaySurface::COMPOSITION_HWC))
+ .Times(1);
}
static void setupRECompositionCallExpectations(CompositionTest* test) {
- EXPECT_CALL(*test->mDisplaySurface, prepareFrame(DisplaySurface::COMPOSITION_GLES))
+ EXPECT_CALL(*test->mDisplaySurface,
+ prepareFrame(compositionengine::DisplaySurface::COMPOSITION_GLES))
.Times(1);
EXPECT_CALL(*test->mDisplaySurface, getClientTargetAcquireFence())
.WillRepeatedly(ReturnRef(test->mClientTargetAcquireFence));
@@ -400,6 +414,8 @@
template <typename Case>
static void setupCommonCompositionCallExpectations(CompositionTest* test) {
+ EXPECT_CALL(*test->mRenderEngine, useNativeFenceSync()).WillRepeatedly(Return(true));
+
// TODO: This seems like an unnecessary call if display is powered off.
EXPECT_CALL(*test->mComposer,
setColorTransform(HWC_DISPLAY, _, Hwc2::ColorTransform::IDENTITY))
@@ -412,6 +428,8 @@
static void setupHwcCompositionCallExpectations(CompositionTest*) {}
static void setupRECompositionCallExpectations(CompositionTest* test) {
+ EXPECT_CALL(*test->mRenderEngine, useNativeFenceSync()).WillRepeatedly(Return(true));
+
// TODO: This seems like an unnecessary call if display is powered off.
EXPECT_CALL(*test->mDisplaySurface, getClientTargetAcquireFence())
.WillRepeatedly(ReturnRef(test->mClientTargetAcquireFence));
@@ -570,7 +588,6 @@
setLayerColor(HWC_DISPLAY, HWC_LAYER,
IComposerClient::Color({0xff, 0xff, 0xff, 0xff})))
.Times(1);
-
}
static void setupHwcSetPerFrameBufferCallExpectations(CompositionTest* test) {
@@ -696,7 +713,8 @@
EXPECT_CALL(*test->mRenderEngine,
setupLayerBlending(true, false, false,
half4(Base::COLOR[0], Base::COLOR[1], Base::COLOR[2],
- Base::COLOR[3]), 0.0f))
+ Base::COLOR[3]),
+ 0.0f))
.Times(1);
EXPECT_CALL(*test->mRenderEngine, setSourceDataSpace(ui::Dataspace::UNKNOWN)).Times(1);
EXPECT_CALL(*test->mRenderEngine, drawMesh(_)).Times(1);
@@ -767,7 +785,7 @@
const auto displayId = test->mDisplay->getId();
ASSERT_TRUE(displayId);
- layer->createHwcLayer(test->mFlinger.mFlinger->getBE().mHwc.get(), *displayId);
+ layer->createHwcLayer(&test->mFlinger.getHwComposer(), *displayId);
Mock::VerifyAndClear(test->mComposer);
diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
index bd9b140..b7464d2 100644
--- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
@@ -19,24 +19,24 @@
#include <type_traits>
+#include <compositionengine/Display.h>
+#include <compositionengine/DisplayColorProfile.h>
+#include <compositionengine/mock/DisplaySurface.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
-
#include <log/log.h>
-
+#include <renderengine/mock/RenderEngine.h>
#include <ui/DebugUtils.h>
#include "DisplayIdentificationTest.h"
#include "TestableSurfaceFlinger.h"
#include "mock/DisplayHardware/MockComposer.h"
-#include "mock/DisplayHardware/MockDisplaySurface.h"
#include "mock/MockDispSync.h"
#include "mock/MockEventControlThread.h"
#include "mock/MockEventThread.h"
#include "mock/MockMessageQueue.h"
#include "mock/MockNativeWindowSurface.h"
#include "mock/MockSurfaceInterceptor.h"
-#include "mock/RenderEngine/MockRenderEngine.h"
#include "mock/gui/MockGraphicBufferConsumer.h"
#include "mock/gui/MockGraphicBufferProducer.h"
#include "mock/system/window/MockNativeWindow.h"
@@ -118,6 +118,7 @@
TestableSurfaceFlinger mFlinger;
mock::EventThread* mEventThread = new mock::EventThread();
+ mock::EventThread* mSFEventThread = new mock::EventThread();
mock::EventControlThread* mEventControlThread = new mock::EventControlThread();
sp<mock::NativeWindow> mNativeWindow = new mock::NativeWindow();
sp<GraphicBuffer> mBuffer = new GraphicBuffer();
@@ -161,6 +162,7 @@
mFlinger.mutableEventControlThread().reset(mEventControlThread);
mFlinger.mutableEventThread().reset(mEventThread);
+ mFlinger.mutableSFEventThread().reset(mSFEventThread);
mFlinger.mutableEventQueue().reset(mMessageQueue);
mFlinger.setupRenderEngine(std::unique_ptr<renderengine::RenderEngine>(mRenderEngine));
mFlinger.mutableInterceptor().reset(mSurfaceInterceptor);
@@ -319,6 +321,11 @@
// Whether the display is primary
static constexpr Primary PRIMARY = primary;
+ static constexpr auto displayType() {
+ return static_cast<bool>(PRIMARY) ? EventThread::DisplayType::Primary
+ : EventThread::DisplayType::External;
+ }
+
static auto makeFakeExistingDisplayInjector(DisplayTransactionTest* test) {
auto injector =
FakeDisplayDeviceInjector(test->mFlinger, DISPLAY_ID::get(),
@@ -328,11 +335,17 @@
injector.setNativeWindow(test->mNativeWindow);
// Creating a DisplayDevice requires getting default dimensions from the
- // native window.
+ // native window along with some other initial setup.
EXPECT_CALL(*test->mNativeWindow, query(NATIVE_WINDOW_WIDTH, _))
.WillRepeatedly(DoAll(SetArgPointee<1>(WIDTH), Return(0)));
EXPECT_CALL(*test->mNativeWindow, query(NATIVE_WINDOW_HEIGHT, _))
.WillRepeatedly(DoAll(SetArgPointee<1>(HEIGHT), Return(0)));
+ EXPECT_CALL(*test->mNativeWindow, perform(NATIVE_WINDOW_SET_BUFFERS_FORMAT))
+ .WillRepeatedly(Return(0));
+ EXPECT_CALL(*test->mNativeWindow, perform(NATIVE_WINDOW_API_CONNECT))
+ .WillRepeatedly(Return(0));
+ EXPECT_CALL(*test->mNativeWindow, perform(NATIVE_WINDOW_SET_USAGE64))
+ .WillRepeatedly(Return(0));
return injector;
}
@@ -345,6 +358,12 @@
.WillRepeatedly(DoAll(SetArgPointee<1>(WIDTH), Return(0)));
EXPECT_CALL(*test->mNativeWindow, query(NATIVE_WINDOW_HEIGHT, _))
.WillRepeatedly(DoAll(SetArgPointee<1>(HEIGHT), Return(0)));
+ EXPECT_CALL(*test->mNativeWindow, perform(NATIVE_WINDOW_SET_BUFFERS_FORMAT))
+ .WillRepeatedly(Return(0));
+ EXPECT_CALL(*test->mNativeWindow, perform(NATIVE_WINDOW_API_CONNECT))
+ .WillRepeatedly(Return(0));
+ EXPECT_CALL(*test->mNativeWindow, perform(NATIVE_WINDOW_SET_USAGE64))
+ .WillRepeatedly(Return(0));
}
static void setupFramebufferConsumerBufferQueueCallExpectations(DisplayTransactionTest* test) {
@@ -382,7 +401,7 @@
}
// Called by tests to inject a HWC display setup
- static void injectHwcDisplay(DisplayTransactionTest* test) {
+ static void injectHwcDisplayWithNoDefaultCapabilities(DisplayTransactionTest* test) {
const auto displayId = DisplayVariant::DISPLAY_ID::get();
ASSERT_TRUE(displayId);
FakeHwcDisplayInjector(*displayId, HWC_DISPLAY_TYPE,
@@ -394,6 +413,14 @@
.inject(&test->mFlinger, test->mComposer);
}
+ // Called by tests to inject a HWC display setup
+ static void injectHwcDisplay(DisplayTransactionTest* test) {
+ EXPECT_CALL(*test->mComposer, getDisplayCapabilities(HWC_DISPLAY_ID, _))
+ .WillOnce(DoAll(SetArgPointee<1>(std::vector<Hwc2::DisplayCapability>({})),
+ Return(Error::NONE)));
+ injectHwcDisplayWithNoDefaultCapabilities(test);
+ }
+
static void setupHwcHotplugCallExpectations(DisplayTransactionTest* test) {
EXPECT_CALL(*test->mComposer, getDisplayType(HWC_DISPLAY_ID, _))
.WillOnce(DoAll(SetArgPointee<1>(static_cast<IComposerClient::DisplayType>(
@@ -423,6 +450,9 @@
getDisplayAttribute(HWC_DISPLAY_ID, HWC_ACTIVE_CONFIG_ID,
IComposerClient::Attribute::DPI_Y, _))
.WillOnce(DoAll(SetArgPointee<3>(DEFAULT_DPI), Return(Error::NONE)));
+ EXPECT_CALL(*test->mComposer, getDisplayCapabilities(HWC_DISPLAY_ID, _))
+ .WillOnce(DoAll(SetArgPointee<1>(std::vector<Hwc2::DisplayCapability>({})),
+ Return(Error::NONE)));
if (PhysicalDisplay::HAS_IDENTIFICATION_DATA) {
EXPECT_CALL(*test->mComposer, getDisplayIdentificationData(HWC_DISPLAY_ID, _, _))
@@ -475,6 +505,8 @@
struct TertiaryDisplay {
static constexpr Primary PRIMARY = Primary::FALSE;
+ static constexpr uint8_t PORT = 253;
+ static constexpr auto GET_IDENTIFICATION_DATA = getExternalEdid;
};
// A primary display is a physical display that is critical
@@ -570,6 +602,8 @@
}
static void setupComposerCallExpectations(DisplayTransactionTest* test) {
+ EXPECT_CALL(*test->mNativeWindow, perform(NATIVE_WINDOW_SET_BUFFERS_DATASPACE)).Times(1);
+
EXPECT_CALL(*test->mComposer, getColorModes(Display::HWC_DISPLAY_ID, _))
.WillOnce(DoAll(SetArgPointee<1>(std::vector<ColorMode>({ColorMode::DISPLAY_P3})),
Return(Error::NONE)));
@@ -1149,13 +1183,15 @@
.WillRepeatedly(DoAll(SetArgPointee<1>(1080 /* arbitrary */), Return(0)));
EXPECT_CALL(*mNativeWindow, query(NATIVE_WINDOW_HEIGHT, _))
.WillRepeatedly(DoAll(SetArgPointee<1>(1920 /* arbitrary */), Return(0)));
- EXPECT_CALL(*mNativeWindow, perform(9)).Times(1);
- EXPECT_CALL(*mNativeWindow, perform(13)).Times(1);
- EXPECT_CALL(*mNativeWindow, perform(30)).Times(1);
+ EXPECT_CALL(*mNativeWindow, perform(NATIVE_WINDOW_SET_BUFFERS_FORMAT)).Times(1);
+ EXPECT_CALL(*mNativeWindow, perform(NATIVE_WINDOW_API_CONNECT)).Times(1);
+ EXPECT_CALL(*mNativeWindow, perform(NATIVE_WINDOW_SET_USAGE64)).Times(1);
auto displayDevice = mInjector.inject();
- displayDevice->getBestColorMode(mInputDataspace, mInputRenderIntent, &mOutDataspace,
- &mOutColorMode, &mOutRenderIntent);
+ displayDevice->getCompositionDisplay()
+ ->getDisplayColorProfile()
+ ->getBestColorMode(mInputDataspace, mInputRenderIntent, &mOutDataspace,
+ &mOutColorMode, &mOutRenderIntent);
}
ui::Dataspace mOutDataspace;
@@ -1217,6 +1253,116 @@
}
/* ------------------------------------------------------------------------
+ * SurfaceFlinger::getDisplayNativePrimaries
+ */
+
+class GetDisplayNativePrimaries : public DisplayTransactionTest {
+public:
+ GetDisplayNativePrimaries();
+ void populateDummyDisplayNativePrimaries(ui::DisplayPrimaries& primaries);
+ void checkDummyDisplayNativePrimaries(const ui::DisplayPrimaries& primaries);
+
+private:
+ static constexpr float mStartingTestValue = 1.0f;
+};
+
+GetDisplayNativePrimaries::GetDisplayNativePrimaries() {
+ SimplePrimaryDisplayCase::Display::injectHwcDisplay(this);
+ injectFakeNativeWindowSurfaceFactory();
+}
+
+void GetDisplayNativePrimaries::populateDummyDisplayNativePrimaries(
+ ui::DisplayPrimaries& primaries) {
+ float startingVal = mStartingTestValue;
+ primaries.red.X = startingVal++;
+ primaries.red.Y = startingVal++;
+ primaries.red.Z = startingVal++;
+ primaries.green.X = startingVal++;
+ primaries.green.Y = startingVal++;
+ primaries.green.Z = startingVal++;
+ primaries.blue.X = startingVal++;
+ primaries.blue.Y = startingVal++;
+ primaries.blue.Z = startingVal++;
+ primaries.white.X = startingVal++;
+ primaries.white.Y = startingVal++;
+ primaries.white.Z = startingVal++;
+}
+
+void GetDisplayNativePrimaries::checkDummyDisplayNativePrimaries(
+ const ui::DisplayPrimaries& primaries) {
+ float startingVal = mStartingTestValue;
+ EXPECT_EQ(primaries.red.X, startingVal++);
+ EXPECT_EQ(primaries.red.Y, startingVal++);
+ EXPECT_EQ(primaries.red.Z, startingVal++);
+ EXPECT_EQ(primaries.green.X, startingVal++);
+ EXPECT_EQ(primaries.green.Y, startingVal++);
+ EXPECT_EQ(primaries.green.Z, startingVal++);
+ EXPECT_EQ(primaries.blue.X, startingVal++);
+ EXPECT_EQ(primaries.blue.Y, startingVal++);
+ EXPECT_EQ(primaries.blue.Z, startingVal++);
+ EXPECT_EQ(primaries.white.X, startingVal++);
+ EXPECT_EQ(primaries.white.Y, startingVal++);
+ EXPECT_EQ(primaries.white.Z, startingVal++);
+}
+
+TEST_F(GetDisplayNativePrimaries, nullDisplayToken) {
+ ui::DisplayPrimaries primaries;
+ 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();
+ auto internalDisplayToken = injector.token();
+
+ ui::DisplayPrimaries expectedPrimaries;
+ populateDummyDisplayNativePrimaries(expectedPrimaries);
+ mFlinger.setInternalDisplayPrimaries(expectedPrimaries);
+
+ ui::DisplayPrimaries primaries;
+ EXPECT_EQ(NO_ERROR, mFlinger.getDisplayNativePrimaries(internalDisplayToken, primaries));
+
+ checkDummyDisplayNativePrimaries(primaries);
+}
+
+TEST_F(GetDisplayNativePrimaries, notInternalDisplayToken) {
+ sp<BBinder> notInternalDisplayToken = new BBinder();
+
+ ui::DisplayPrimaries primaries;
+ populateDummyDisplayNativePrimaries(primaries);
+ EXPECT_EQ(BAD_VALUE, mFlinger.getDisplayNativePrimaries(notInternalDisplayToken, primaries));
+
+ // Check primaries argument wasn't modified in case of failure
+ checkDummyDisplayNativePrimaries(primaries);
+}
+
+/* ------------------------------------------------------------------------
* SurfaceFlinger::setupNewDisplayDeviceInternal
*/
@@ -1229,7 +1375,8 @@
template <typename Case>
void SetupNewDisplayDeviceInternalTest::setupNewDisplayDeviceInternalTest() {
const sp<BBinder> displayToken = new BBinder();
- const sp<mock::DisplaySurface> displaySurface = new mock::DisplaySurface();
+ const sp<compositionengine::mock::DisplaySurface> displaySurface =
+ new compositionengine::mock::DisplaySurface();
const sp<mock::GraphicBufferProducer> producer = new mock::GraphicBufferProducer();
// --------------------------------------------------------------------
@@ -1401,23 +1548,17 @@
Case::PerFrameMetadataSupport::setupComposerCallExpectations(this);
EXPECT_CALL(*mSurfaceInterceptor, saveDisplayCreation(_)).Times(1);
- EXPECT_CALL(*mEventThread,
- onHotplugReceived(static_cast<bool>(Case::Display::PRIMARY)
- ? EventThread::DisplayType::Primary
- : EventThread::DisplayType::External,
- true))
- .Times(1);
+
+ EXPECT_CALL(*mEventThread, onHotplugReceived(Case::Display::displayType(), true)).Times(1);
+ EXPECT_CALL(*mSFEventThread, onHotplugReceived(Case::Display::displayType(), true)).Times(1);
}
template <typename Case>
void HandleTransactionLockedTest::setupCommonCallExpectationsForDisconnectProcessing() {
EXPECT_CALL(*mSurfaceInterceptor, saveDisplayDeletion(_)).Times(1);
- EXPECT_CALL(*mEventThread,
- onHotplugReceived(static_cast<bool>(Case::Display::PRIMARY)
- ? EventThread::DisplayType::Primary
- : EventThread::DisplayType::External,
- false))
- .Times(1);
+
+ EXPECT_CALL(*mEventThread, onHotplugReceived(Case::Display::displayType(), false)).Times(1);
+ EXPECT_CALL(*mSFEventThread, onHotplugReceived(Case::Display::displayType(), false)).Times(1);
}
template <typename Case>
@@ -1591,6 +1732,13 @@
PrimaryDisplayVariant::injectHwcDisplay(this);
ExternalDisplayVariant::injectHwcDisplay(this);
+ // TODO: This is an unnecessary call.
+ EXPECT_CALL(*mComposer,
+ getDisplayIdentificationData(TertiaryDisplayVariant::HWC_DISPLAY_ID, _, _))
+ .WillOnce(DoAll(SetArgPointee<1>(TertiaryDisplay::PORT),
+ SetArgPointee<2>(TertiaryDisplay::GET_IDENTIFICATION_DATA()),
+ Return(Error::NONE)));
+
EXPECT_CALL(*mComposer, isUsingVrComposer()).WillRepeatedly(Return(false));
ignoresHotplugConnectCommon<SimpleTertiaryDisplayCase>();
@@ -1738,6 +1886,10 @@
Case::Display::setupFramebufferConsumerBufferQueueCallExpectations(this);
Case::Display::setupNativeWindowSurfaceCreationCallExpectations(this);
+ EXPECT_CALL(*mComposer, getDisplayCapabilities(Case::Display::HWC_DISPLAY_ID, _))
+ .WillOnce(DoAll(SetArgPointee<1>(std::vector<Hwc2::DisplayCapability>({})),
+ Return(Error::NONE)));
+
EXPECT_CALL(*surface, query(NATIVE_WINDOW_WIDTH, _))
.WillRepeatedly(DoAll(SetArgPointee<1>(Case::Display::WIDTH), Return(NO_ERROR)));
EXPECT_CALL(*surface, query(NATIVE_WINDOW_HEIGHT, _))
@@ -1750,6 +1902,7 @@
EXPECT_CALL(*surface, setAsyncMode(true)).Times(1);
+ EXPECT_CALL(*mProducer, connect(_, NATIVE_WINDOW_API_EGL, false, _)).Times(1);
EXPECT_CALL(*mProducer, disconnect(_, _)).Times(1);
Case::Display::setupHwcVirtualDisplayCreationCallExpectations(this);
@@ -1972,7 +2125,7 @@
// A display is set up
auto nativeWindow = new mock::NativeWindow();
- auto displaySurface = new mock::DisplaySurface();
+ auto displaySurface = new compositionengine::mock::DisplaySurface();
sp<GraphicBuffer> buf = new GraphicBuffer();
auto display = Case::Display::makeFakeExistingDisplayInjector(this);
display.setNativeWindow(nativeWindow);
@@ -1982,9 +2135,9 @@
.WillOnce(DoAll(SetArgPointee<1>(oldWidth), Return(0)));
EXPECT_CALL(*nativeWindow, query(NATIVE_WINDOW_HEIGHT, _))
.WillOnce(DoAll(SetArgPointee<1>(oldHeight), Return(0)));
- EXPECT_CALL(*nativeWindow, perform(9)).Times(1);
- EXPECT_CALL(*nativeWindow, perform(13)).Times(1);
- EXPECT_CALL(*nativeWindow, perform(30)).Times(1);
+ EXPECT_CALL(*nativeWindow, perform(NATIVE_WINDOW_SET_BUFFERS_FORMAT)).Times(1);
+ EXPECT_CALL(*nativeWindow, perform(NATIVE_WINDOW_API_CONNECT)).Times(1);
+ EXPECT_CALL(*nativeWindow, perform(NATIVE_WINDOW_SET_USAGE64)).Times(1);
display.inject();
// There is a change to the viewport state
@@ -2016,7 +2169,7 @@
// A display is set up
auto nativeWindow = new mock::NativeWindow();
- auto displaySurface = new mock::DisplaySurface();
+ auto displaySurface = new compositionengine::mock::DisplaySurface();
sp<GraphicBuffer> buf = new GraphicBuffer();
auto display = Case::Display::makeFakeExistingDisplayInjector(this);
display.setNativeWindow(nativeWindow);
@@ -2026,9 +2179,9 @@
.WillOnce(DoAll(SetArgPointee<1>(oldWidth), Return(0)));
EXPECT_CALL(*nativeWindow, query(NATIVE_WINDOW_HEIGHT, _))
.WillOnce(DoAll(SetArgPointee<1>(oldHeight), Return(0)));
- EXPECT_CALL(*nativeWindow, perform(9)).Times(1);
- EXPECT_CALL(*nativeWindow, perform(13)).Times(1);
- EXPECT_CALL(*nativeWindow, perform(30)).Times(1);
+ EXPECT_CALL(*nativeWindow, perform(NATIVE_WINDOW_SET_BUFFERS_FORMAT)).Times(1);
+ EXPECT_CALL(*nativeWindow, perform(NATIVE_WINDOW_API_CONNECT)).Times(1);
+ EXPECT_CALL(*nativeWindow, perform(NATIVE_WINDOW_SET_USAGE64)).Times(1);
display.inject();
// There is a change to the viewport state
@@ -2542,6 +2695,8 @@
// processing.
EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
+ EXPECT_CALL(*mPrimaryDispSync, expectedPresentTime()).WillRepeatedly(Return(0));
+
// --------------------------------------------------------------------
// Invocation
@@ -2836,7 +2991,7 @@
using Transition = TransitionVariant;
static auto injectDisplayWithInitialPowerMode(DisplayTransactionTest* test, int mode) {
- Display::injectHwcDisplay(test);
+ Display::injectHwcDisplayWithNoDefaultCapabilities(test);
auto display = Display::makeFakeExistingDisplayInjector(test);
display.inject();
display.mutableDisplayDevice()->setPowerMode(mode);
diff --git a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
index acbed51..dd90063 100644
--- a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
+++ b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
@@ -47,10 +47,11 @@
class EventThreadTest : public testing::Test {
protected:
- class MockEventThreadConnection : public android::EventThreadConnection {
+ class MockEventThreadConnection : public EventThreadConnection {
public:
- explicit MockEventThreadConnection(android::impl::EventThread* eventThread)
- : android::EventThreadConnection(eventThread) {}
+ MockEventThreadConnection(android::impl::EventThread* eventThread,
+ ResyncCallback&& resyncCallback)
+ : EventThreadConnection(eventThread, std::move(resyncCallback)) {}
MOCK_METHOD1(postEvent, status_t(const DisplayEventReceiver::Event& event));
};
@@ -82,6 +83,7 @@
ConnectionEventRecorder mConnectionEventCallRecorder{0};
MockVSyncSource mVSyncSource;
+ VSyncSource::Callback* mCallback = nullptr;
std::unique_ptr<android::impl::EventThread> mThread;
sp<MockEventThreadConnection> mConnection;
};
@@ -102,25 +104,36 @@
createThread();
mConnection = createConnection(mConnectionEventCallRecorder);
+
+ // A display must be connected for VSYNC events to be delivered.
+ mThread->onHotplugReceived(EventThread::DisplayType::Primary, true);
+ expectHotplugEventReceivedByConnection(EventThread::DisplayType::Primary, true);
}
EventThreadTest::~EventThreadTest() {
const ::testing::TestInfo* const test_info =
::testing::UnitTest::GetInstance()->current_test_info();
ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name());
+
+ // EventThread should unregister itself as VSyncSource callback.
+ EXPECT_FALSE(expectVSyncSetCallbackCallReceived());
}
void EventThreadTest::createThread() {
mThread =
std::make_unique<android::impl::EventThread>(&mVSyncSource,
- mResyncCallRecorder.getInvocable(),
mInterceptVSyncCallRecorder.getInvocable(),
"unit-test-event-thread");
+
+ // EventThread should register itself as VSyncSource callback.
+ mCallback = expectVSyncSetCallbackCallReceived();
+ ASSERT_TRUE(mCallback);
}
sp<EventThreadTest::MockEventThreadConnection> EventThreadTest::createConnection(
ConnectionEventRecorder& recorder) {
- sp<MockEventThreadConnection> connection = new MockEventThreadConnection(mThread.get());
+ sp<MockEventThreadConnection> connection =
+ new MockEventThreadConnection(mThread.get(), mResyncCallRecorder.getInvocable());
EXPECT_CALL(*connection, postEvent(_)).WillRepeatedly(Invoke(recorder.getInvocable()));
return connection;
}
@@ -198,29 +211,37 @@
EXPECT_FALSE(mConnectionEventCallRecorder.waitForCall(0us).has_value());
}
+TEST_F(EventThreadTest, vsyncRequestIsIgnoredIfDisplayIsDisconnected) {
+ mThread->onHotplugReceived(EventThread::DisplayType::Primary, false);
+ expectHotplugEventReceivedByConnection(EventThread::DisplayType::Primary, false);
+
+ // Signal that we want the next vsync event to be posted to the connection.
+ mThread->requestNextVsync(mConnection, false);
+
+ // EventThread should not enable vsync callbacks.
+ EXPECT_FALSE(mVSyncSetEnabledCallRecorder.waitForUnexpectedCall().has_value());
+}
+
TEST_F(EventThreadTest, requestNextVsyncPostsASingleVSyncEventToTheConnection) {
// Signal that we want the next vsync event to be posted to the connection
- mThread->requestNextVsync(mConnection);
+ mThread->requestNextVsync(mConnection, false);
// EventThread should immediately request a resync.
EXPECT_TRUE(mResyncCallRecorder.waitForCall().has_value());
- // EventThread should enable vsync callbacks, and set a callback interface
- // pointer to use them with the VSync source.
+ // EventThread should enable vsync callbacks.
expectVSyncSetEnabledCallReceived(true);
- auto callback = expectVSyncSetCallbackCallReceived();
- ASSERT_TRUE(callback);
// Use the received callback to signal a first vsync event.
// The interceptor should receive the event, as well as the connection.
- callback->onVSyncEvent(123);
+ mCallback->onVSyncEvent(123);
expectInterceptCallReceived(123);
expectVsyncEventReceivedByConnection(123, 1u);
// Use the received callback to signal a second vsync event.
// The interceptor should receive the event, but the the connection should
// not as it was only interested in the first.
- callback->onVSyncEvent(456);
+ mCallback->onVSyncEvent(456);
expectInterceptCallReceived(456);
EXPECT_FALSE(mConnectionEventCallRecorder.waitForUnexpectedCall().has_value());
@@ -245,16 +266,13 @@
createConnection(secondConnectionEventRecorder);
mThread->setVsyncRate(1, secondConnection);
- // EventThread should enable vsync callbacks, and set a callback interface
- // pointer to use them with the VSync source.
+ // EventThread should enable vsync callbacks.
expectVSyncSetEnabledCallReceived(true);
- auto callback = expectVSyncSetCallbackCallReceived();
- ASSERT_TRUE(callback);
// Send a vsync event. EventThread should then make a call to the
// interceptor, and the second connection. The first connection should not
// get the event.
- callback->onVSyncEvent(123);
+ mCallback->onVSyncEvent(123);
expectInterceptCallReceived(123);
EXPECT_FALSE(firstConnectionEventRecorder.waitForUnexpectedCall().has_value());
expectVsyncEventReceivedByConnection("secondConnection", secondConnectionEventRecorder, 123,
@@ -264,25 +282,22 @@
TEST_F(EventThreadTest, setVsyncRateOnePostsAllEventsToThatConnection) {
mThread->setVsyncRate(1, mConnection);
- // EventThread should enable vsync callbacks, and set a callback interface
- // pointer to use them with the VSync source.
+ // EventThread should enable vsync callbacks.
expectVSyncSetEnabledCallReceived(true);
- auto callback = expectVSyncSetCallbackCallReceived();
- ASSERT_TRUE(callback);
// Send a vsync event. EventThread should then make a call to the
// interceptor, and the connection.
- callback->onVSyncEvent(123);
+ mCallback->onVSyncEvent(123);
expectInterceptCallReceived(123);
expectVsyncEventReceivedByConnection(123, 1u);
// A second event should go to the same places.
- callback->onVSyncEvent(456);
+ mCallback->onVSyncEvent(456);
expectInterceptCallReceived(456);
expectVsyncEventReceivedByConnection(456, 2u);
// A third event should go to the same places.
- callback->onVSyncEvent(789);
+ mCallback->onVSyncEvent(789);
expectInterceptCallReceived(789);
expectVsyncEventReceivedByConnection(789, 3u);
}
@@ -290,29 +305,26 @@
TEST_F(EventThreadTest, setVsyncRateTwoPostsEveryOtherEventToThatConnection) {
mThread->setVsyncRate(2, mConnection);
- // EventThread should enable vsync callbacks, and set a callback interface
- // pointer to use them with the VSync source.
+ // EventThread should enable vsync callbacks.
expectVSyncSetEnabledCallReceived(true);
- auto callback = expectVSyncSetCallbackCallReceived();
- ASSERT_TRUE(callback);
// The first event will be seen by the interceptor, and not the connection.
- callback->onVSyncEvent(123);
+ mCallback->onVSyncEvent(123);
expectInterceptCallReceived(123);
EXPECT_FALSE(mConnectionEventCallRecorder.waitForUnexpectedCall().has_value());
// The second event will be seen by the interceptor and the connection.
- callback->onVSyncEvent(456);
+ mCallback->onVSyncEvent(456);
expectInterceptCallReceived(456);
expectVsyncEventReceivedByConnection(456, 2u);
// The third event will be seen by the interceptor, and not the connection.
- callback->onVSyncEvent(789);
+ mCallback->onVSyncEvent(789);
expectInterceptCallReceived(789);
EXPECT_FALSE(mConnectionEventCallRecorder.waitForUnexpectedCall().has_value());
// The fourth event will be seen by the interceptor and the connection.
- callback->onVSyncEvent(101112);
+ mCallback->onVSyncEvent(101112);
expectInterceptCallReceived(101112);
expectVsyncEventReceivedByConnection(101112, 4u);
}
@@ -320,17 +332,14 @@
TEST_F(EventThreadTest, connectionsRemovedIfInstanceDestroyed) {
mThread->setVsyncRate(1, mConnection);
- // EventThread should enable vsync callbacks, and set a callback interface
- // pointer to use them with the VSync source.
+ // EventThread should enable vsync callbacks.
expectVSyncSetEnabledCallReceived(true);
- auto callback = expectVSyncSetCallbackCallReceived();
- ASSERT_TRUE(callback);
// Destroy the only (strong) reference to the connection.
mConnection = nullptr;
// The first event will be seen by the interceptor, and not the connection.
- callback->onVSyncEvent(123);
+ mCallback->onVSyncEvent(123);
expectInterceptCallReceived(123);
EXPECT_FALSE(mConnectionEventCallRecorder.waitForUnexpectedCall().has_value());
@@ -343,21 +352,18 @@
sp<MockEventThreadConnection> errorConnection = createConnection(errorConnectionEventRecorder);
mThread->setVsyncRate(1, errorConnection);
- // EventThread should enable vsync callbacks, and set a callback interface
- // pointer to use them with the VSync source.
+ // EventThread should enable vsync callbacks.
expectVSyncSetEnabledCallReceived(true);
- auto callback = expectVSyncSetCallbackCallReceived();
- ASSERT_TRUE(callback);
// The first event will be seen by the interceptor, and by the connection,
// which then returns an error.
- callback->onVSyncEvent(123);
+ mCallback->onVSyncEvent(123);
expectInterceptCallReceived(123);
expectVsyncEventReceivedByConnection("errorConnection", errorConnectionEventRecorder, 123, 1u);
// A subsequent event will be seen by the interceptor and not by the
// connection.
- callback->onVSyncEvent(456);
+ mCallback->onVSyncEvent(456);
expectInterceptCallReceived(456);
EXPECT_FALSE(errorConnectionEventRecorder.waitForUnexpectedCall().has_value());
@@ -370,21 +376,18 @@
sp<MockEventThreadConnection> errorConnection = createConnection(errorConnectionEventRecorder);
mThread->setVsyncRate(1, errorConnection);
- // EventThread should enable vsync callbacks, and set a callback interface
- // pointer to use them with the VSync source.
+ // EventThread should enable vsync callbacks.
expectVSyncSetEnabledCallReceived(true);
- auto callback = expectVSyncSetCallbackCallReceived();
- ASSERT_TRUE(callback);
// The first event will be seen by the interceptor, and by the connection,
// which then returns an non-fatal error.
- callback->onVSyncEvent(123);
+ mCallback->onVSyncEvent(123);
expectInterceptCallReceived(123);
expectVsyncEventReceivedByConnection("errorConnection", errorConnectionEventRecorder, 123, 1u);
// A subsequent event will be seen by the interceptor, and by the connection,
// which still then returns an non-fatal error.
- callback->onVSyncEvent(456);
+ mCallback->onVSyncEvent(456);
expectInterceptCallReceived(456);
expectVsyncEventReceivedByConnection("errorConnection", errorConnectionEventRecorder, 456, 2u);
diff --git a/services/surfaceflinger/tests/unittests/FakePhaseOffsets.h b/services/surfaceflinger/tests/unittests/FakePhaseOffsets.h
new file mode 100644
index 0000000..0739f15
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/FakePhaseOffsets.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <gmock/gmock.h>
+
+#include "Scheduler/PhaseOffsets.h"
+
+namespace android {
+namespace scheduler {
+
+class FakePhaseOffsets : public android::scheduler::PhaseOffsets {
+ nsecs_t FAKE_PHASE_OFFSET_NS = 0;
+
+public:
+ FakePhaseOffsets() = default;
+ ~FakePhaseOffsets() = default;
+
+ nsecs_t getCurrentAppOffset() override { return FAKE_PHASE_OFFSET_NS; }
+ nsecs_t getCurrentSfOffset() override { return FAKE_PHASE_OFFSET_NS; }
+
+ // Returns early, early GL, and late offsets for Apps and SF.
+ PhaseOffsets::Offsets getCurrentOffsets() const override {
+ return Offsets{{FAKE_PHASE_OFFSET_NS, FAKE_PHASE_OFFSET_NS},
+ {FAKE_PHASE_OFFSET_NS, FAKE_PHASE_OFFSET_NS},
+ {FAKE_PHASE_OFFSET_NS, FAKE_PHASE_OFFSET_NS}};
+ }
+
+ // This function should be called when the device is switching between different
+ // refresh rates, to properly update the offsets.
+ void setRefreshRateType(RefreshRateConfigs::RefreshRateType /*refreshRateType*/) override {}
+
+ // Returns current offsets in human friendly format.
+ void dump(std::string& /*result*/) const override {}
+};
+
+} // namespace scheduler
+} // namespace android
\ No newline at end of file
diff --git a/services/surfaceflinger/tests/unittests/LayerMetadataTest.cpp b/services/surfaceflinger/tests/unittests/LayerMetadataTest.cpp
new file mode 100644
index 0000000..92c9f92
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/LayerMetadataTest.cpp
@@ -0,0 +1,86 @@
+/*
+ * 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.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "LibSurfaceFlingerUnittests"
+
+#include <binder/Parcel.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <gui/LayerMetadata.h>
+#include <log/log.h>
+
+namespace android {
+namespace {
+
+class LayerMetadataTest : public testing::Test {
+public:
+ LayerMetadataTest();
+ ~LayerMetadataTest() override;
+};
+
+LayerMetadataTest::LayerMetadataTest() {
+ const ::testing::TestInfo* const test_info =
+ ::testing::UnitTest::GetInstance()->current_test_info();
+ ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name());
+}
+
+LayerMetadataTest::~LayerMetadataTest() {
+ const ::testing::TestInfo* const test_info =
+ ::testing::UnitTest::GetInstance()->current_test_info();
+ ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name());
+}
+
+TEST_F(LayerMetadataTest, testLayerMetadata) {
+ LayerMetadata metadata;
+
+ ASSERT_EQ(0, metadata.mMap.size());
+
+ // Test non-set
+ ASSERT_EQ(3, metadata.getInt32(4, 3));
+
+ // Make sure it's still unset
+ ASSERT_EQ(5, metadata.getInt32(4, 5));
+
+ metadata.setInt32(4, 2);
+ ASSERT_EQ(2, metadata.getInt32(4, 0));
+
+ // data is too small
+ 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;
+ reconstructed.setInt32(3, 1); // to make sure it gets replaced
+ p.setDataPosition(0);
+ reconstructed.readFromParcel(&p);
+ ASSERT_EQ(metadata.mMap, reconstructed.mMap);
+}
+
+} // namespace
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp
new file mode 100644
index 0000000..3d887ea
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp
@@ -0,0 +1,223 @@
+/*
+ * 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 "SchedulerUnittests"
+
+#include <gmock/gmock.h>
+#include <log/log.h>
+#include <thread>
+
+#include "Scheduler/RefreshRateStats.h"
+#include "mock/DisplayHardware/MockDisplay.h"
+#include "mock/MockTimeStats.h"
+
+using namespace std::chrono_literals;
+using testing::_;
+
+namespace android {
+namespace scheduler {
+
+class RefreshRateStatsTest : public testing::Test {
+protected:
+ static constexpr int CONFIG_ID_90 = 0;
+ static constexpr int CONFIG_ID_60 = 1;
+ static constexpr int64_t VSYNC_90 = 11111111;
+ static constexpr int64_t VSYNC_60 = 16666667;
+
+ RefreshRateStatsTest();
+ ~RefreshRateStatsTest();
+
+ void init(std::vector<std::shared_ptr<const HWC2::Display::Config>> configs);
+
+ std::unique_ptr<RefreshRateStats> mRefreshRateStats;
+ std::shared_ptr<android::mock::TimeStats> mTimeStats;
+};
+
+RefreshRateStatsTest::RefreshRateStatsTest() {
+ const ::testing::TestInfo* const test_info =
+ ::testing::UnitTest::GetInstance()->current_test_info();
+ ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name());
+}
+
+RefreshRateStatsTest::~RefreshRateStatsTest() {
+ const ::testing::TestInfo* const test_info =
+ ::testing::UnitTest::GetInstance()->current_test_info();
+ ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name());
+}
+
+void RefreshRateStatsTest::init(std::vector<std::shared_ptr<const HWC2::Display::Config>> configs) {
+ mTimeStats = std::make_shared<android::mock::TimeStats>();
+ mRefreshRateStats = std::make_unique<RefreshRateStats>(configs, mTimeStats);
+}
+
+namespace {
+/* ------------------------------------------------------------------------
+ * Test cases
+ */
+TEST_F(RefreshRateStatsTest, canCreateAndDestroyTest) {
+ std::vector<std::shared_ptr<const HWC2::Display::Config>> configs;
+ init(configs);
+
+ // There is one default config, so the refresh rates should have one item.
+ ASSERT_EQ(1, mRefreshRateStats->getTotalTimes().size());
+}
+
+TEST_F(RefreshRateStatsTest, oneConfigTest) {
+ auto display = new Hwc2::mock::Display();
+
+ auto config = HWC2::Display::Config::Builder(*display, CONFIG_ID_90);
+ config.setVsyncPeriod(VSYNC_90);
+ std::vector<std::shared_ptr<const HWC2::Display::Config>> configs;
+ configs.push_back(config.build());
+
+ init(configs);
+
+ EXPECT_CALL(*mTimeStats, recordRefreshRate(0, _)).Times(4);
+ EXPECT_CALL(*mTimeStats, recordRefreshRate(90, _)).Times(2);
+
+ std::unordered_map<std::string, int64_t> times = mRefreshRateStats->getTotalTimes();
+ ASSERT_EQ(2, times.size());
+ ASSERT_EQ(0, times["ScreenOff"]);
+ ASSERT_EQ(0, times["90fps"]);
+ // Setting up tests on mobile harness can be flaky with time passing, so testing for
+ // exact time changes can result in flaxy numbers. To avoid that remember old
+ // numbers to make sure the correct values are increasing in the next test.
+ int screenOff = times["ScreenOff"];
+ int ninety = times["90fps"];
+
+ // Screen is off by default.
+ std::this_thread::sleep_for(std::chrono::milliseconds(2));
+ times = mRefreshRateStats->getTotalTimes();
+ ASSERT_LT(screenOff, times["ScreenOff"]);
+ ASSERT_EQ(0, times["90fps"]);
+ screenOff = times["ScreenOff"];
+
+ mRefreshRateStats->setPowerMode(HWC_POWER_MODE_NORMAL);
+ std::this_thread::sleep_for(std::chrono::milliseconds(2));
+ times = mRefreshRateStats->getTotalTimes();
+ ASSERT_EQ(screenOff, times["ScreenOff"]);
+ ASSERT_LT(ninety, times["90fps"]);
+ ninety = times["90fps"];
+
+ mRefreshRateStats->setPowerMode(HWC_POWER_MODE_DOZE);
+ std::this_thread::sleep_for(std::chrono::milliseconds(2));
+ times = mRefreshRateStats->getTotalTimes();
+ ASSERT_LT(screenOff, times["ScreenOff"]);
+ ASSERT_EQ(ninety, times["90fps"]);
+ screenOff = times["ScreenOff"];
+
+ mRefreshRateStats->setConfigMode(CONFIG_ID_90);
+ std::this_thread::sleep_for(std::chrono::milliseconds(2));
+ times = mRefreshRateStats->getTotalTimes();
+ // Because the power mode is not HWC_POWER_MODE_NORMAL, switching the config
+ // does not update refresh rates that come from the config.
+ ASSERT_LT(screenOff, times["ScreenOff"]);
+ ASSERT_EQ(ninety, times["90fps"]);
+}
+
+TEST_F(RefreshRateStatsTest, twoConfigsTest) {
+ auto display = new Hwc2::mock::Display();
+
+ auto config90 = HWC2::Display::Config::Builder(*display, CONFIG_ID_90);
+ config90.setVsyncPeriod(VSYNC_90);
+ std::vector<std::shared_ptr<const HWC2::Display::Config>> configs;
+ configs.push_back(config90.build());
+
+ auto config60 = HWC2::Display::Config::Builder(*display, CONFIG_ID_60);
+ config60.setVsyncPeriod(VSYNC_60);
+ configs.push_back(config60.build());
+
+ init(configs);
+
+ EXPECT_CALL(*mTimeStats, recordRefreshRate(0, _)).Times(6);
+ EXPECT_CALL(*mTimeStats, recordRefreshRate(60, _)).Times(4);
+ EXPECT_CALL(*mTimeStats, recordRefreshRate(90, _)).Times(4);
+
+ std::unordered_map<std::string, int64_t> times = mRefreshRateStats->getTotalTimes();
+ ASSERT_EQ(3, times.size());
+ ASSERT_EQ(0, times["ScreenOff"]);
+ ASSERT_EQ(0, times["60fps"]);
+ ASSERT_EQ(0, times["90fps"]);
+ // Setting up tests on mobile harness can be flaky with time passing, so testing for
+ // exact time changes can result in flaxy numbers. To avoid that remember old
+ // numbers to make sure the correct values are increasing in the next test.
+ int screenOff = times["ScreenOff"];
+ int sixty = times["60fps"];
+ int ninety = times["90fps"];
+
+ // Screen is off by default.
+ std::this_thread::sleep_for(std::chrono::milliseconds(2));
+ times = mRefreshRateStats->getTotalTimes();
+ ASSERT_LT(screenOff, times["ScreenOff"]);
+ ASSERT_EQ(sixty, times["60fps"]);
+ ASSERT_EQ(ninety, times["90fps"]);
+ screenOff = times["ScreenOff"];
+
+ mRefreshRateStats->setPowerMode(HWC_POWER_MODE_NORMAL);
+ std::this_thread::sleep_for(std::chrono::milliseconds(2));
+ times = mRefreshRateStats->getTotalTimes();
+ ASSERT_EQ(screenOff, times["ScreenOff"]);
+ ASSERT_EQ(sixty, times["60fps"]);
+ ASSERT_LT(ninety, times["90fps"]);
+ ninety = times["90fps"];
+
+ // When power mode is normal, time for configs updates.
+ mRefreshRateStats->setConfigMode(CONFIG_ID_60);
+ std::this_thread::sleep_for(std::chrono::milliseconds(2));
+ times = mRefreshRateStats->getTotalTimes();
+ ASSERT_EQ(screenOff, times["ScreenOff"]);
+ ASSERT_EQ(ninety, times["90fps"]);
+ ASSERT_LT(sixty, times["60fps"]);
+ sixty = times["60fps"];
+
+ mRefreshRateStats->setConfigMode(CONFIG_ID_90);
+ std::this_thread::sleep_for(std::chrono::milliseconds(2));
+ times = mRefreshRateStats->getTotalTimes();
+ ASSERT_EQ(screenOff, times["ScreenOff"]);
+ ASSERT_LT(ninety, times["90fps"]);
+ ASSERT_EQ(sixty, times["60fps"]);
+ ninety = times["90fps"];
+
+ mRefreshRateStats->setConfigMode(CONFIG_ID_60);
+ std::this_thread::sleep_for(std::chrono::milliseconds(2));
+ times = mRefreshRateStats->getTotalTimes();
+ ASSERT_EQ(screenOff, times["ScreenOff"]);
+ ASSERT_EQ(ninety, times["90fps"]);
+ ASSERT_LT(sixty, times["60fps"]);
+ sixty = times["60fps"];
+
+ // Because the power mode is not HWC_POWER_MODE_NORMAL, switching the config
+ // does not update refresh rates that come from the config.
+ mRefreshRateStats->setPowerMode(HWC_POWER_MODE_DOZE);
+ mRefreshRateStats->setConfigMode(CONFIG_ID_90);
+ std::this_thread::sleep_for(std::chrono::milliseconds(2));
+ times = mRefreshRateStats->getTotalTimes();
+ ASSERT_LT(screenOff, times["ScreenOff"]);
+ ASSERT_EQ(ninety, times["90fps"]);
+ ASSERT_EQ(sixty, times["60fps"]);
+ screenOff = times["ScreenOff"];
+
+ mRefreshRateStats->setConfigMode(CONFIG_ID_60);
+ std::this_thread::sleep_for(std::chrono::milliseconds(2));
+ times = mRefreshRateStats->getTotalTimes();
+ ASSERT_LT(screenOff, times["ScreenOff"]);
+ ASSERT_EQ(ninety, times["90fps"]);
+ ASSERT_EQ(sixty, times["60fps"]);
+}
+} // namespace
+} // namespace scheduler
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
index 4253ad8..4d9aec6 100644
--- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
@@ -8,12 +8,9 @@
#include <mutex>
-#include "AsyncCallRecorder.h"
-#include "Scheduler/DispSync.h"
#include "Scheduler/EventControlThread.h"
#include "Scheduler/EventThread.h"
#include "Scheduler/Scheduler.h"
-#include "mock/MockDispSync.h"
#include "mock/MockEventThread.h"
using testing::_;
@@ -26,7 +23,7 @@
class MockEventThreadConnection : public android::EventThreadConnection {
public:
explicit MockEventThreadConnection(EventThread* eventThread)
- : EventThreadConnection(eventThread) {}
+ : EventThreadConnection(eventThread, ResyncCallback()) {}
~MockEventThreadConnection() = default;
MOCK_METHOD1(stealReceiveChannel, status_t(gui::BitTube* outChannel));
@@ -44,9 +41,8 @@
: Scheduler([](bool) {}), mEventThread(std::move(eventThread)) {}
std::unique_ptr<EventThread> makeEventThread(
- const std::string& /* connectionName */, DispSync* /* dispSync */,
+ const char* /* connectionName */, DispSync* /* dispSync */,
nsecs_t /* phaseOffsetNs */,
- impl::EventThread::ResyncWithRateLimitCallback /* resyncCallback */,
impl::EventThread::InterceptVSyncsCallback /* interceptCallback */) override {
return std::move(mEventThread);
}
@@ -61,13 +57,9 @@
~SchedulerTest() override;
sp<Scheduler::ConnectionHandle> mConnectionHandle;
- mock::DispSync* mPrimaryDispSync = new mock::DispSync();
mock::EventThread* mEventThread;
std::unique_ptr<MockScheduler> mScheduler;
sp<MockEventThreadConnection> mEventThreadConnection;
-
- AsyncCallRecorder<void (*)()> mResyncCallRecorder;
- AsyncCallRecorder<void (*)(nsecs_t)> mInterceptVSyncCallRecorder;
};
SchedulerTest::SchedulerTest() {
@@ -84,12 +76,12 @@
// createConnection call to scheduler makes a createEventConnection call to EventThread. Make
// sure that call gets executed and returns an EventThread::Connection object.
- EXPECT_CALL(*mEventThread, createEventConnection())
+ EXPECT_CALL(*mEventThread, createEventConnection(_))
.WillRepeatedly(Return(mEventThreadConnection));
- mConnectionHandle =
- mScheduler->createConnection("appConnection", 16, mResyncCallRecorder.getInvocable(),
- mInterceptVSyncCallRecorder.getInvocable());
+ mConnectionHandle = mScheduler->createConnection("appConnection", 16, ResyncCallback(),
+ impl::EventThread::InterceptVSyncsCallback());
+ EXPECT_TRUE(mConnectionHandle != nullptr);
}
SchedulerTest::~SchedulerTest() {
@@ -102,17 +94,13 @@
/* ------------------------------------------------------------------------
* Test cases
*/
-TEST_F(SchedulerTest, canCreateAndDestroyTest) {
- EXPECT_FALSE(mResyncCallRecorder.waitForCall().has_value());
- EXPECT_FALSE(mInterceptVSyncCallRecorder.waitForCall().has_value());
- EXPECT_EQ(0, mConnectionHandle->id);
-}
TEST_F(SchedulerTest, testNullPtr) {
// Passing a null pointer for ConnectionHandle is a valid argument. The code doesn't throw any
// exceptions, just gracefully continues.
sp<IDisplayEventConnection> returnedValue;
- ASSERT_NO_FATAL_FAILURE(returnedValue = mScheduler->createDisplayEventConnection(nullptr));
+ ASSERT_NO_FATAL_FAILURE(
+ returnedValue = mScheduler->createDisplayEventConnection(nullptr, ResyncCallback()));
EXPECT_TRUE(returnedValue == nullptr);
EXPECT_TRUE(mScheduler->getEventThread(nullptr) == nullptr);
EXPECT_TRUE(mScheduler->getEventConnection(nullptr) == nullptr);
@@ -132,8 +120,9 @@
sp<Scheduler::ConnectionHandle> connectionHandle = new Scheduler::ConnectionHandle(20);
sp<IDisplayEventConnection> returnedValue;
- ASSERT_NO_FATAL_FAILURE(returnedValue =
- mScheduler->createDisplayEventConnection(connectionHandle));
+ ASSERT_NO_FATAL_FAILURE(
+ returnedValue =
+ mScheduler->createDisplayEventConnection(connectionHandle, ResyncCallback()));
EXPECT_TRUE(returnedValue == nullptr);
EXPECT_TRUE(mScheduler->getEventThread(connectionHandle) == nullptr);
EXPECT_TRUE(mScheduler->getEventConnection(connectionHandle) == nullptr);
@@ -160,8 +149,9 @@
TEST_F(SchedulerTest, validConnectionHandle) {
sp<IDisplayEventConnection> returnedValue;
- ASSERT_NO_FATAL_FAILURE(returnedValue =
- mScheduler->createDisplayEventConnection(mConnectionHandle));
+ ASSERT_NO_FATAL_FAILURE(
+ returnedValue =
+ mScheduler->createDisplayEventConnection(mConnectionHandle, ResyncCallback()));
EXPECT_TRUE(returnedValue != nullptr);
ASSERT_EQ(returnedValue, mEventThreadConnection);
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index 4da08b8..e639b4d 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -16,11 +16,14 @@
#pragma once
+#include <compositionengine/impl/CompositionEngine.h>
+
#include "BufferQueueLayer.h"
#include "BufferStateLayer.h"
#include "ColorLayer.h"
#include "ContainerLayer.h"
#include "DisplayDevice.h"
+#include "FakePhaseOffsets.h"
#include "Layer.h"
#include "NativeWindowSurface.h"
#include "StartPropertySetThread.h"
@@ -73,6 +76,10 @@
return std::make_unique<android::impl::MessageQueue>();
}
+ std::unique_ptr<scheduler::PhaseOffsets> createPhaseOffsets() override {
+ return std::make_unique<scheduler::FakePhaseOffsets>();
+ }
+
std::unique_ptr<Scheduler> createScheduler(std::function<void(bool)>) override {
// TODO: Use test-fixture controlled factory
return nullptr;
@@ -113,6 +120,10 @@
return mCreateNativeWindowSurface(producer);
}
+ std::unique_ptr<compositionengine::CompositionEngine> createCompositionEngine() override {
+ return compositionengine::impl::createCompositionEngine();
+ }
+
sp<BufferQueueLayer> createBufferQueueLayer(const LayerCreationArgs&) override {
// TODO: Use test-fixture controlled factory
return nullptr;
@@ -133,9 +144,9 @@
return nullptr;
}
- std::unique_ptr<TimeStats> createTimeStats() override {
+ std::shared_ptr<TimeStats> createTimeStats() override {
// TODO: Use test-fixture controlled factory
- return std::make_unique<TimeStats>();
+ return std::make_shared<android::impl::TimeStats>();
}
using CreateBufferQueueFunction =
@@ -148,6 +159,10 @@
std::function<std::unique_ptr<surfaceflinger::NativeWindowSurface>(
const sp<IGraphicBufferProducer>&)>;
CreateNativeWindowSurfaceFunction mCreateNativeWindowSurface;
+
+ using CreateCompositionEngineFunction =
+ std::function<std::unique_ptr<compositionengine::CompositionEngine>()>;
+ CreateCompositionEngineFunction mCreateCompositionEngine;
};
} // namespace surfaceflinger::test
@@ -158,11 +173,12 @@
// functions.
void setupRenderEngine(std::unique_ptr<renderengine::RenderEngine> renderEngine) {
- mFlinger->getBE().mRenderEngine = std::move(renderEngine);
+ mFlinger->mCompositionEngine->setRenderEngine(std::move(renderEngine));
}
void setupComposer(std::unique_ptr<Hwc2::Composer> composer) {
- mFlinger->getBE().mHwc.reset(new HWComposer(std::move(composer)));
+ mFlinger->mCompositionEngine->setHwComposer(
+ std::make_unique<impl::HWComposer>(std::move(composer)));
}
using CreateBufferQueueFunction = surfaceflinger::test::Factory::CreateBufferQueueFunction;
@@ -176,14 +192,17 @@
mFactory.mCreateNativeWindowSurface = f;
}
+ void setInternalDisplayPrimaries(const ui::DisplayPrimaries& primaries) {
+ memcpy(&mFlinger->mInternalDisplayPrimaries, &primaries, sizeof(ui::DisplayPrimaries));
+ }
+
using HotplugEvent = SurfaceFlinger::HotplugEvent;
- auto& mutableLayerCurrentState(sp<Layer> layer) { return layer->mState.current; }
- auto& mutableLayerDrawingState(sp<Layer> layer) { return layer->mState.drawing; }
+ auto& mutableLayerCurrentState(sp<Layer> layer) { return layer->mCurrentState; }
+ auto& mutableLayerDrawingState(sp<Layer> layer) { return layer->mDrawingState; }
void setLayerSidebandStream(sp<Layer> layer, sp<NativeHandle> sidebandStream) {
- Mutex::Autolock lock(layer->mStateMutex);
- layer->mState.drawing.sidebandStream = sidebandStream;
+ layer->mDrawingState.sidebandStream = sidebandStream;
layer->getBE().compositionInfo.hwc.sidebandStream = sidebandStream;
}
@@ -208,7 +227,7 @@
auto setupNewDisplayDeviceInternal(const wp<IBinder>& displayToken,
const std::optional<DisplayId>& displayId,
const DisplayDeviceState& state,
- const sp<DisplaySurface>& dispSurface,
+ const sp<compositionengine::DisplaySurface>& dispSurface,
const sp<IGraphicBufferProducer>& producer) {
return mFlinger->setupNewDisplayDeviceInternal(displayToken, displayId, state, dispSurface,
producer);
@@ -225,9 +244,14 @@
auto setDisplayStateLocked(const DisplayState& s) { return mFlinger->setDisplayStateLocked(s); }
- auto onInitializeDisplays() { return mFlinger->onInitializeDisplays(); }
+ // Allow reading display state without locking, as if called on the SF main thread.
+ auto onInitializeDisplays() NO_THREAD_SAFETY_ANALYSIS {
+ return mFlinger->onInitializeDisplays();
+ }
- auto setPowerModeInternal(const sp<DisplayDevice>& display, int mode) {
+ // Allow reading display state without locking, as if called on the SF main thread.
+ auto setPowerModeInternal(const sp<DisplayDevice>& display,
+ int mode) NO_THREAD_SAFETY_ANALYSIS {
return mFlinger->setPowerModeInternal(display, mode);
}
@@ -245,6 +269,15 @@
return mFlinger->SurfaceFlinger::traverseLayersInDisplay(display, visitor);
}
+ auto getDisplayNativePrimaries(const sp<IBinder>& displayToken,
+ ui::DisplayPrimaries &primaries) {
+ return mFlinger->SurfaceFlinger::getDisplayNativePrimaries(displayToken, primaries);
+ }
+
+ void initDefaultDisplayNativePrimaries() {
+ mFlinger->SurfaceFlinger::initDefaultDisplayNativePrimaries();
+ }
+
/* ------------------------------------------------------------------------
* Read-only access to private data to assert post-conditions.
*/
@@ -253,6 +286,9 @@
const auto& getHasPoweredOff() const { return mFlinger->mHasPoweredOff; }
const auto& getHWVsyncAvailable() const { return mFlinger->mHWVsyncAvailable; }
const auto& getVisibleRegionsDirty() const { return mFlinger->mVisibleRegionsDirty; }
+ auto& getHwComposer() const {
+ return static_cast<impl::HWComposer&>(mFlinger->getHwComposer());
+ }
const auto& getCompositorTiming() const { return mFlinger->getBE().mCompositorTiming; }
@@ -272,6 +308,7 @@
auto& mutableEventControlThread() { return mFlinger->mEventControlThread; }
auto& mutableEventQueue() { return mFlinger->mEventQueue; }
auto& mutableEventThread() { return mFlinger->mEventThread; }
+ auto& mutableSFEventThread() { return mFlinger->mSFEventThread; }
auto& mutableGeometryInvalid() { return mFlinger->mGeometryInvalid; }
auto& mutableHWVsyncAvailable() { return mFlinger->mHWVsyncAvailable; }
auto& mutableInterceptor() { return mFlinger->mInterceptor; }
@@ -285,13 +322,10 @@
auto& mutableUseHwcVirtualDisplays() { return mFlinger->mUseHwcVirtualDisplays; }
auto& mutableComposerSequenceId() { return mFlinger->getBE().mComposerSequenceId; }
- auto& mutableHwcDisplayData() { return mFlinger->getHwComposer().mDisplayData; }
- auto& mutableHwcPhysicalDisplayIdMap() {
- return mFlinger->getHwComposer().mPhysicalDisplayIdMap;
- }
-
- auto& mutableInternalHwcDisplayId() { return mFlinger->getHwComposer().mInternalHwcDisplayId; }
- auto& mutableExternalHwcDisplayId() { return mFlinger->getHwComposer().mExternalHwcDisplayId; }
+ auto& mutableHwcDisplayData() { return getHwComposer().mDisplayData; }
+ auto& mutableHwcPhysicalDisplayIdMap() { return getHwComposer().mPhysicalDisplayIdMap; }
+ auto& mutableInternalHwcDisplayId() { return getHwComposer().mInternalHwcDisplayId; }
+ auto& mutableExternalHwcDisplayId() { return getHwComposer().mExternalHwcDisplayId; }
~TestableSurfaceFlinger() {
// All these pointer and container clears help ensure that GMock does
@@ -302,10 +336,12 @@
mutableEventControlThread().reset();
mutableEventQueue().reset();
mutableEventThread().reset();
+ mutableSFEventThread().reset();
mutableInterceptor().reset();
mutablePrimaryDispSync().reset();
- mFlinger->getBE().mHwc.reset();
- mFlinger->getBE().mRenderEngine.reset();
+ mFlinger->mCompositionEngine->setHwComposer(std::unique_ptr<HWComposer>());
+ mFlinger->mCompositionEngine->setRenderEngine(
+ std::unique_ptr<renderengine::RenderEngine>());
}
/* ------------------------------------------------------------------------
@@ -319,11 +355,11 @@
void setExpensiveRenderingExpected(hwc2_display_t, bool) override {}
};
- struct HWC2Display : public HWC2::Display {
+ struct HWC2Display : public HWC2::impl::Display {
HWC2Display(Hwc2::Composer& composer, Hwc2::PowerAdvisor& advisor,
const std::unordered_set<HWC2::Capability>& capabilities, hwc2_display_t id,
HWC2::DisplayType type)
- : HWC2::Display(composer, advisor, capabilities, id, type) {}
+ : HWC2::impl::Display(composer, advisor, capabilities, id, type) {}
~HWC2Display() {
// Prevents a call to disable vsyncs.
mType = HWC2::DisplayType::Invalid;
@@ -476,7 +512,7 @@
return *this;
}
- auto& setDisplaySurface(const sp<DisplaySurface>& displaySurface) {
+ auto& setDisplaySurface(const sp<compositionengine::DisplaySurface>& displaySurface) {
mCreationArgs.displaySurface = displaySurface;
return *this;
}
diff --git a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
index 86f1a39..f35758d 100644
--- a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
@@ -17,6 +17,7 @@
#undef LOG_TAG
#define LOG_TAG "LibSurfaceFlingerUnittests"
+#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <log/log.h>
@@ -24,6 +25,7 @@
#include <utils/Vector.h>
#include <random>
+#include <unordered_set>
#include "TimeStats/TimeStats.h"
@@ -35,6 +37,10 @@
namespace android {
namespace {
+using testing::Contains;
+using testing::SizeIs;
+using testing::UnorderedElementsAre;
+
// clang-format off
#define FMT_PROTO true
#define FMT_STRING false
@@ -127,11 +133,10 @@
}
std::mt19937 mRandomEngine = std::mt19937(std::random_device()());
- std::unique_ptr<TimeStats> mTimeStats = std::make_unique<TimeStats>();
+ std::unique_ptr<TimeStats> mTimeStats = std::make_unique<impl::TimeStats>();
};
std::string TimeStatsTest::inputCommand(InputCommand cmd, bool useProto) {
- size_t index = 0;
std::string result;
Vector<String16> args;
@@ -162,7 +167,7 @@
ALOGD("Invalid control command");
}
- EXPECT_NO_FATAL_FAILURE(mTimeStats->parseArgs(useProto, args, index, result));
+ EXPECT_NO_FATAL_FAILURE(mTimeStats->parseArgs(useProto, args, result));
return result;
}
@@ -372,6 +377,63 @@
}
}
+TEST_F(TimeStatsTest, recordRefreshRateNewConfigs) {
+ EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
+
+ uint32_t fpsOne = 30;
+ uint32_t fpsTwo = 90;
+ uint64_t millisOne = 5000;
+ uint64_t millisTwo = 7000;
+
+ mTimeStats->recordRefreshRate(fpsOne, ms2ns(millisOne));
+ mTimeStats->recordRefreshRate(fpsTwo, ms2ns(millisTwo));
+
+ SFTimeStatsGlobalProto globalProto;
+ ASSERT_TRUE(globalProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));
+
+ SFTimeStatsDisplayConfigBucketProto expectedBucketOne;
+ SFTimeStatsDisplayConfigProto* expectedConfigOne = expectedBucketOne.mutable_config();
+ expectedConfigOne->set_fps(fpsOne);
+ expectedBucketOne.set_duration_millis(millisOne);
+
+ SFTimeStatsDisplayConfigBucketProto expectedBucketTwo;
+ SFTimeStatsDisplayConfigProto* expectedConfigTwo = expectedBucketTwo.mutable_config();
+ expectedConfigTwo->set_fps(fpsTwo);
+ expectedBucketTwo.set_duration_millis(millisTwo);
+
+ EXPECT_THAT(globalProto.display_config_stats(), SizeIs(2));
+
+ std::unordered_set<uint32_t> seen_fps;
+ for (const auto& bucket : globalProto.display_config_stats()) {
+ seen_fps.emplace(bucket.config().fps());
+ if (fpsOne == bucket.config().fps()) {
+ EXPECT_EQ(millisOne, bucket.duration_millis());
+ } else if (fpsTwo == bucket.config().fps()) {
+ EXPECT_EQ(millisTwo, bucket.duration_millis());
+ } else {
+ FAIL() << "Unknown fps: " << bucket.config().fps();
+ }
+ }
+ EXPECT_THAT(seen_fps, UnorderedElementsAre(fpsOne, fpsTwo));
+}
+
+TEST_F(TimeStatsTest, recordRefreshRateUpdatesConfig) {
+ EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
+
+ uint32_t fps = 30;
+ uint64_t millisOne = 5000;
+ uint64_t millisTwo = 7000;
+
+ mTimeStats->recordRefreshRate(fps, ms2ns(millisOne));
+ mTimeStats->recordRefreshRate(fps, ms2ns(millisTwo));
+
+ SFTimeStatsGlobalProto globalProto;
+ ASSERT_TRUE(globalProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));
+ EXPECT_THAT(globalProto.display_config_stats(), SizeIs(1));
+ EXPECT_EQ(fps, globalProto.display_config_stats().Get(0).config().fps());
+ EXPECT_EQ(millisOne + millisTwo, globalProto.display_config_stats().Get(0).duration_millis());
+}
+
TEST_F(TimeStatsTest, canRemoveTimeRecord) {
EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
@@ -395,7 +457,7 @@
uint64_t frameNumber = 1;
nsecs_t ts = 1000000;
insertTimeRecord(INCOMPLETE_SEQUENCE, LAYER_ID_0, 1, 1000000);
- for (size_t i = 0; i < TimeStats::MAX_NUM_TIME_RECORDS + 2; i++) {
+ for (size_t i = 0; i < impl::TimeStats::MAX_NUM_TIME_RECORDS + 2; i++) {
frameNumber++;
ts += 1000000;
insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, frameNumber, ts);
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
index 551fae7..e6f1a06 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
@@ -29,11 +29,11 @@
using android::hardware::graphics::common::V1_0::ColorTransform;
using android::hardware::graphics::common::V1_0::Transform;
-using android::hardware::graphics::common::V1_1::PixelFormat;
using android::hardware::graphics::common::V1_1::RenderIntent;
using android::hardware::graphics::common::V1_2::ColorMode;
using android::hardware::graphics::common::V1_2::Dataspace;
using android::hardware::graphics::common::V1_2::Hdr;
+using android::hardware::graphics::common::V1_2::PixelFormat;
using android::hardware::graphics::composer::V2_1::Config;
using android::hardware::graphics::composer::V2_1::Display;
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplaySurface.cpp b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplay.cpp
similarity index 77%
copy from services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplaySurface.cpp
copy to services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplay.cpp
index e6ac6bf..2ec37c1 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplaySurface.cpp
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplay.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018 The Android Open Source Project
+ * 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.
@@ -14,14 +14,16 @@
* limitations under the License.
*/
-#include "mock/DisplayHardware/MockDisplaySurface.h"
+#include "mock/DisplayHardware/MockDisplay.h"
namespace android {
+namespace Hwc2 {
namespace mock {
// Explicit default instantiation is recommended.
-DisplaySurface::DisplaySurface() = default;
-DisplaySurface::~DisplaySurface() = default;
+Display::Display() = default;
+Display::~Display() = default;
} // namespace mock
-} // namespace android
+} // namespace Hwc2
+} // namespace android
\ No newline at end of file
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplay.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplay.h
new file mode 100644
index 0000000..d7e20c4
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplay.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <gmock/gmock.h>
+
+#include "DisplayHardware/HWC2.h"
+
+using HWC2::Error;
+using HWC2::Layer;
+
+namespace android {
+namespace Hwc2 {
+namespace mock {
+
+class Display : public HWC2::Display {
+public:
+ Display();
+ ~Display();
+
+ MOCK_CONST_METHOD0(getId, hwc2_layer_t());
+ MOCK_CONST_METHOD0(isConnected, bool());
+ MOCK_METHOD1(setConnected, void(bool));
+ MOCK_CONST_METHOD0(getCapabilities, const std::unordered_set<HWC2::DisplayCapability>&());
+
+ MOCK_METHOD0(acceptChanges, Error());
+ MOCK_METHOD1(createLayer, Error(Layer**));
+ MOCK_METHOD1(destroyLayer, Error(Layer*));
+ MOCK_CONST_METHOD1(getActiveConfig, Error(std::shared_ptr<const Config>*));
+ MOCK_CONST_METHOD1(getActiveConfigIndex, Error(int* outIndex));
+ MOCK_METHOD1(getChangedCompositionTypes, Error(std::unordered_map<Layer*, HWC2::Composition>*));
+ MOCK_CONST_METHOD1(getColorModes, Error(std::vector<android::ui::ColorMode>*));
+
+ MOCK_CONST_METHOD0(getSupportedPerFrameMetadata, int32_t());
+ MOCK_CONST_METHOD2(getRenderIntents,
+ Error(android::ui::ColorMode, std::vector<android::ui::RenderIntent>*));
+ MOCK_METHOD2(getDataspaceSaturationMatrix, Error(android::ui::Dataspace, android::mat4*));
+ MOCK_CONST_METHOD0(getConfigs, std::vector<std::shared_ptr<const Config>>());
+
+ MOCK_CONST_METHOD1(getName, Error(std::string*));
+ MOCK_METHOD2(getRequests,
+ Error(HWC2::DisplayRequest*, std::unordered_map<Layer*, HWC2::LayerRequest>*));
+ MOCK_CONST_METHOD1(getType, Error(HWC2::DisplayType*));
+ MOCK_CONST_METHOD1(supportsDoze, Error(bool*));
+ MOCK_CONST_METHOD1(getHdrCapabilities, Error(android::HdrCapabilities*));
+ MOCK_CONST_METHOD3(getDisplayedContentSamplingAttributes,
+ Error(android::ui::PixelFormat*, android::ui::Dataspace*, uint8_t*));
+ MOCK_CONST_METHOD3(setDisplayContentSamplingEnabled, Error(bool, uint8_t, uint64_t));
+ MOCK_CONST_METHOD3(getDisplayedContentSample,
+ Error(uint64_t, uint64_t, android::DisplayedFrameStats*));
+ MOCK_CONST_METHOD1(getReleaseFences,
+ Error(std::unordered_map<Layer*, android::sp<android::Fence>>* outFences));
+ MOCK_METHOD1(present, Error(android::sp<android::Fence>*));
+ MOCK_METHOD1(setActiveConfig, Error(const std::shared_ptr<const HWC2::Display::Config>&));
+ MOCK_METHOD4(setClientTarget,
+ Error(uint32_t, const android::sp<android::GraphicBuffer>&,
+ const android::sp<android::Fence>&, android::ui::Dataspace));
+ MOCK_METHOD2(setColorMode, Error(android::ui::ColorMode, android::ui::RenderIntent));
+ MOCK_METHOD2(setColorTransform, Error(const android::mat4&, android_color_transform_t));
+ MOCK_METHOD2(setOutputBuffer,
+ Error(const android::sp<android::GraphicBuffer>&,
+ const android::sp<android::Fence>&));
+ MOCK_METHOD1(setPowerMode, Error(HWC2::PowerMode));
+ MOCK_METHOD1(setVsyncEnabled, Error(HWC2::Vsync));
+ MOCK_METHOD2(validate, Error(uint32_t*, uint32_t*));
+ MOCK_METHOD4(presentOrValidate,
+ Error(uint32_t*, uint32_t*, android::sp<android::Fence>*, uint32_t*));
+};
+
+} // namespace mock
+} // namespace Hwc2
+} // namespace android
\ No newline at end of file
diff --git a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
index bb6e183..3242ef1 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
@@ -28,7 +28,7 @@
EventThread();
~EventThread() override;
- MOCK_CONST_METHOD0(createEventConnection, sp<EventThreadConnection>());
+ MOCK_CONST_METHOD1(createEventConnection, sp<EventThreadConnection>(ResyncCallback));
MOCK_METHOD0(onScreenReleased, void());
MOCK_METHOD0(onScreenAcquired, void());
MOCK_METHOD2(onHotplugReceived, void(DisplayType, bool));
@@ -37,7 +37,7 @@
MOCK_METHOD1(registerDisplayEventConnection,
status_t(const sp<android::EventThreadConnection> &));
MOCK_METHOD2(setVsyncRate, void(uint32_t, const sp<android::EventThreadConnection> &));
- MOCK_METHOD1(requestNextVsync, void(const sp<android::EventThreadConnection> &));
+ MOCK_METHOD2(requestNextVsync, void(const sp<android::EventThreadConnection> &, bool));
};
} // namespace mock
diff --git a/services/surfaceflinger/tests/unittests/mock/MockMessageQueue.h b/services/surfaceflinger/tests/unittests/mock/MockMessageQueue.h
index dc8d606..e22d3e8 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockMessageQueue.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockMessageQueue.h
@@ -30,11 +30,12 @@
~MessageQueue() override;
MOCK_METHOD1(init, void(const sp<SurfaceFlinger>&));
- MOCK_METHOD1(setEventThread, void(android::EventThread*));
- MOCK_METHOD1(setEventConnection, void(const sp<android::EventThreadConnection>& connection));
+ MOCK_METHOD2(setEventThread, void(android::EventThread*, ResyncCallback));
+ MOCK_METHOD1(setEventConnection, void(const sp<EventThreadConnection>& connection));
MOCK_METHOD0(waitMessage, void());
MOCK_METHOD2(postMessage, status_t(const sp<MessageBase>&, nsecs_t));
MOCK_METHOD0(invalidate, void());
+ MOCK_METHOD0(invalidateForHWC, void());
MOCK_METHOD0(refresh, void());
};
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplaySurface.cpp b/services/surfaceflinger/tests/unittests/mock/MockTimeStats.cpp
similarity index 77%
rename from services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplaySurface.cpp
rename to services/surfaceflinger/tests/unittests/mock/MockTimeStats.cpp
index e6ac6bf..d686939 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplaySurface.cpp
+++ b/services/surfaceflinger/tests/unittests/mock/MockTimeStats.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018 The Android Open Source Project
+ * 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.
@@ -14,14 +14,14 @@
* limitations under the License.
*/
-#include "mock/DisplayHardware/MockDisplaySurface.h"
+#include "mock/MockTimeStats.h"
namespace android {
namespace mock {
// Explicit default instantiation is recommended.
-DisplaySurface::DisplaySurface() = default;
-DisplaySurface::~DisplaySurface() = default;
+TimeStats::TimeStats() = default;
+TimeStats::~TimeStats() = default;
} // namespace mock
} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h b/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h
new file mode 100644
index 0000000..08fdb9d
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <gmock/gmock.h>
+
+#include "TimeStats/TimeStats.h"
+
+namespace android {
+namespace mock {
+
+class TimeStats : public android::TimeStats {
+public:
+ TimeStats();
+ ~TimeStats() override;
+
+ MOCK_METHOD3(parseArgs, void(bool, const Vector<String16>&, std::string&));
+ MOCK_METHOD0(isEnabled, bool());
+ MOCK_METHOD0(incrementTotalFrames, void());
+ MOCK_METHOD0(incrementMissedFrames, void());
+ MOCK_METHOD0(incrementClientCompositionFrames, void());
+ MOCK_METHOD4(setPostTime, void(int32_t, uint64_t, const std::string&, nsecs_t));
+ MOCK_METHOD3(setLatchTime, void(int32_t, uint64_t, nsecs_t));
+ MOCK_METHOD3(setDesiredTime, void(int32_t, uint64_t, nsecs_t));
+ MOCK_METHOD3(setAcquireTime, void(int32_t, uint64_t, nsecs_t));
+ MOCK_METHOD3(setAcquireFence, void(int32_t, uint64_t, const std::shared_ptr<FenceTime>&));
+ MOCK_METHOD3(setPresentTime, void(int32_t, uint64_t, nsecs_t));
+ MOCK_METHOD3(setPresentFence, void(int32_t, uint64_t, const std::shared_ptr<FenceTime>&));
+ MOCK_METHOD1(onDestroy, void(int32_t));
+ MOCK_METHOD2(removeTimeRecord, void(int32_t, uint64_t));
+ MOCK_METHOD1(setPowerMode, void(int32_t));
+ MOCK_METHOD2(recordRefreshRate, void(uint32_t, nsecs_t));
+ MOCK_METHOD1(setPresentFenceGlobal, void(const std::shared_ptr<FenceTime>&));
+};
+
+} // namespace mock
+} // namespace android
diff --git a/services/utils/Android.bp b/services/utils/Android.bp
index 6132956..f3d2bc9 100644
--- a/services/utils/Android.bp
+++ b/services/utils/Android.bp
@@ -18,6 +18,8 @@
cc_library_static {
name: "libserviceutils",
+ vendor_available: true,
+
cflags: [
"-Wall",
"-Werror",
@@ -27,8 +29,13 @@
"PriorityDumper.cpp",
],
- clang: true,
+ header_libs: [
+ "libutils_headers",
+ ],
+
+ export_header_lib_headers: [
+ "libutils_headers",
+ ],
+
export_include_dirs: ["include"],
}
-
-subdirs = ["tests"]
diff --git a/services/vr/bufferhubd/Android.bp b/services/vr/bufferhubd/Android.bp
index 7a7e437..4e24a64 100644
--- a/services/vr/bufferhubd/Android.bp
+++ b/services/vr/bufferhubd/Android.bp
@@ -14,7 +14,6 @@
sharedLibraries = [
"libbase",
- "libbufferhubservice",
"libcutils",
"libgtest_prod",
"libgui",
@@ -28,7 +27,6 @@
cc_library_static {
name: "libbufferhubd",
srcs: [
- "buffer_channel.cpp",
"buffer_hub.cpp",
"consumer_channel.cpp",
"consumer_queue_channel.cpp",
diff --git a/services/vr/bufferhubd/buffer_channel.cpp b/services/vr/bufferhubd/buffer_channel.cpp
deleted file mode 100644
index 695396c..0000000
--- a/services/vr/bufferhubd/buffer_channel.cpp
+++ /dev/null
@@ -1,138 +0,0 @@
-#include <errno.h>
-#include <private/dvr/buffer_channel.h>
-#include <private/dvr/producer_channel.h>
-
-using android::pdx::BorrowedHandle;
-using android::pdx::ErrorStatus;
-using android::pdx::Message;
-using android::pdx::RemoteChannelHandle;
-using android::pdx::Status;
-using android::pdx::rpc::DispatchRemoteMethod;
-
-namespace android {
-namespace dvr {
-
-BufferChannel::BufferChannel(BufferHubService* service, int buffer_id,
- uint32_t width, uint32_t height,
- uint32_t layer_count, uint32_t format,
- uint64_t usage, size_t user_metadata_size)
- : BufferHubChannel(service, buffer_id, buffer_id, kDetachedBufferType) {
- buffer_node_ = std::make_shared<BufferNode>(
- width, height, layer_count, format, usage, user_metadata_size);
- if (!buffer_node_->IsValid()) {
- ALOGE("BufferChannel::BufferChannel: Failed to create BufferNode.");
- return;
- }
- client_state_mask_ = buffer_node_->AddNewActiveClientsBitToMask();
-}
-
-BufferChannel::BufferChannel(BufferHubService* service, int buffer_id,
- int channel_id,
- std::shared_ptr<BufferNode> buffer_node)
- : BufferHubChannel(service, buffer_id, channel_id, kDetachedBufferType),
- buffer_node_(buffer_node) {
- client_state_mask_ = buffer_node_->AddNewActiveClientsBitToMask();
- if (client_state_mask_ == 0U) {
- ALOGE("BufferChannel::BufferChannel: %s", strerror(errno));
- buffer_node_ = nullptr;
- }
-}
-
-BufferChannel::~BufferChannel() {
- ALOGD_IF(TRACE, "BufferChannel::~BufferChannel: channel_id=%d buffer_id=%d.",
- channel_id(), buffer_id());
- if (client_state_mask_ != 0U) {
- buffer_node_->RemoveClientsBitFromMask(client_state_mask_);
- }
- Hangup();
-}
-
-BufferHubChannel::BufferInfo BufferChannel::GetBufferInfo() const {
- return BufferInfo(
- buffer_id(), /*consumer_count=*/0, buffer_node_->buffer_desc().width,
- buffer_node_->buffer_desc().height, buffer_node_->buffer_desc().layers,
- buffer_node_->buffer_desc().format, buffer_node_->buffer_desc().usage,
- /*state=*/0, /*signaled_mask=*/0, /*index=*/0);
-}
-
-void BufferChannel::HandleImpulse(Message& /*message*/) {
- ATRACE_NAME("BufferChannel::HandleImpulse");
-}
-
-bool BufferChannel::HandleMessage(Message& message) {
- ATRACE_NAME("BufferChannel::HandleMessage");
- switch (message.GetOp()) {
- case DetachedBufferRPC::Import::Opcode:
- DispatchRemoteMethod<DetachedBufferRPC::Import>(
- *this, &BufferChannel::OnImport, message);
- return true;
-
- case DetachedBufferRPC::Duplicate::Opcode:
- DispatchRemoteMethod<DetachedBufferRPC::Duplicate>(
- *this, &BufferChannel::OnDuplicate, message);
- return true;
-
- default:
- return false;
- }
-}
-
-Status<BufferTraits<BorrowedHandle>> BufferChannel::OnImport(
- Message& /*message*/) {
- ATRACE_NAME("BufferChannel::OnImport");
- ALOGD_IF(TRACE, "BufferChannel::OnImport: buffer=%d.", buffer_id());
-
- BorrowedHandle ashmem_handle =
- BorrowedHandle(buffer_node_->metadata().ashmem_fd().get());
-
- // TODO(b/112057680) Move away from the GraphicBuffer-based IonBuffer.
- return BufferTraits<BorrowedHandle>{
- /*buffer_handle=*/buffer_node_->buffer_handle(),
- /*metadata_handle=*/ashmem_handle,
- /*id=*/buffer_id(),
- /*client_state_mask=*/client_state_mask_,
- /*metadata_size=*/buffer_node_->metadata().metadata_size(),
- /*width=*/buffer_node_->buffer_desc().width,
- /*height=*/buffer_node_->buffer_desc().height,
- /*layer_count=*/buffer_node_->buffer_desc().layers,
- /*format=*/buffer_node_->buffer_desc().format,
- /*usage=*/buffer_node_->buffer_desc().usage,
- /*stride=*/buffer_node_->buffer_desc().stride,
- /*acquire_fence_fd=*/BorrowedHandle{},
- /*released_fence_fd=*/BorrowedHandle{}};
-}
-
-Status<RemoteChannelHandle> BufferChannel::OnDuplicate(Message& message) {
- ATRACE_NAME("BufferChannel::OnDuplicate");
- ALOGD_IF(TRACE, "BufferChannel::OnDuplicate: buffer=%d.", buffer_id());
-
- int channel_id;
- auto status = message.PushChannel(0, nullptr, &channel_id);
- if (!status.ok()) {
- ALOGE("BufferChannel::OnDuplicate: Failed to push buffer channel: %s",
- status.GetErrorMessage().c_str());
- return ErrorStatus(ENOMEM);
- }
-
- auto channel = std::shared_ptr<BufferChannel>(
- new BufferChannel(service(), buffer_id(), channel_id, buffer_node_));
- if (!channel->IsValid()) {
- ALOGE("BufferChannel::OnDuplicate: Invalid buffer. %s", strerror(errno));
- return ErrorStatus(EINVAL);
- }
-
- const auto channel_status =
- service()->SetChannel(channel_id, std::move(channel));
- if (!channel_status) {
- // Technically, this should never fail, as we just pushed the channel. Note
- // that LOG_FATAL will be stripped out in non-debug build.
- LOG_FATAL(
- "BufferChannel::OnDuplicate: Failed to set new buffer channel: %s.",
- channel_status.GetErrorMessage().c_str());
- }
-
- return status;
-}
-
-} // namespace dvr
-} // namespace android
diff --git a/services/vr/bufferhubd/buffer_hub.cpp b/services/vr/bufferhubd/buffer_hub.cpp
index f50d292..6409265 100644
--- a/services/vr/bufferhubd/buffer_hub.cpp
+++ b/services/vr/bufferhubd/buffer_hub.cpp
@@ -10,7 +10,6 @@
#include <log/log.h>
#include <pdx/default_transport/service_endpoint.h>
#include <private/dvr/bufferhub_rpc.h>
-#include <private/dvr/buffer_channel.h>
#include <private/dvr/buffer_hub.h>
#include <private/dvr/consumer_channel.h>
#include <private/dvr/producer_channel.h>
@@ -242,11 +241,6 @@
*this, &BufferHubService::OnCreateBuffer, message);
return {};
- case DetachedBufferRPC::Create::Opcode:
- DispatchRemoteMethod<DetachedBufferRPC::Create>(
- *this, &BufferHubService::OnCreateDetachedBuffer, message);
- return {};
-
case BufferHubRPC::CreateProducerQueue::Opcode:
DispatchRemoteMethod<BufferHubRPC::CreateProducerQueue>(
*this, &BufferHubService::OnCreateProducerQueue, message);
@@ -288,43 +282,6 @@
}
}
-pdx::Status<void> BufferHubService::OnCreateDetachedBuffer(
- pdx::Message& message, uint32_t width, uint32_t height,
- uint32_t layer_count, uint32_t format, uint64_t usage,
- size_t user_metadata_size) {
- // Use the producer channel id as the global buffer id.
- const int buffer_id = message.GetChannelId();
- ALOGD_IF(TRACE,
- "BufferHubService::OnCreateDetachedBuffer: buffer_id=%d width=%u "
- "height=%u layer_count=%u format=%u usage=%" PRIx64
- " user_metadata_size=%zu",
- buffer_id, width, height, layer_count, format, usage,
- user_metadata_size);
-
- // See if this channel is already attached to a buffer.
- if (const auto channel = message.GetChannel<BufferHubChannel>()) {
- ALOGE(
- "BufferHubService::OnCreateDetachedBuffer: Buffer already created: "
- "buffer=%d",
- buffer_id);
- return ErrorStatus(EALREADY);
- }
-
- std::unique_ptr<BufferChannel> channel =
- BufferChannel::Create(this, buffer_id, width, height, layer_count, format,
- usage, user_metadata_size);
- if (!channel) {
- ALOGE(
- "BufferHubService::OnCreateDetachedBuffer: Failed to allocate buffer, "
- "buffer=%d.",
- buffer_id);
- return ErrorStatus(ENOMEM);
- }
-
- message.SetChannel(std::move(channel));
- return {};
-}
-
Status<QueueInfo> BufferHubService::OnCreateProducerQueue(
pdx::Message& message, const ProducerQueueConfig& producer_config,
const UsagePolicy& usage_policy) {
diff --git a/services/vr/bufferhubd/include/private/dvr/buffer_channel.h b/services/vr/bufferhubd/include/private/dvr/buffer_channel.h
deleted file mode 100644
index 9888db6..0000000
--- a/services/vr/bufferhubd/include/private/dvr/buffer_channel.h
+++ /dev/null
@@ -1,61 +0,0 @@
-#ifndef ANDROID_DVR_BUFFERHUBD_BUFFER_CHANNEL_H_
-#define ANDROID_DVR_BUFFERHUBD_BUFFER_CHANNEL_H_
-
-#include <pdx/channel_handle.h>
-#include <pdx/file_handle.h>
-#include <private/dvr/buffer_hub.h>
-#include <private/dvr/buffer_hub_defs.h>
-#include <private/dvr/buffer_node.h>
-
-namespace android {
-namespace dvr {
-
-class BufferChannel : public BufferHubChannel {
- public:
- ~BufferChannel() override;
-
- template <typename... Args>
- static std::unique_ptr<BufferChannel> Create(Args&&... args) {
- auto buffer = std::unique_ptr<BufferChannel>(
- new BufferChannel(std::forward<Args>(args)...));
- return buffer->IsValid() ? std::move(buffer) : nullptr;
- }
-
- // Returns whether the object holds a valid graphic buffer.
- bool IsValid() const {
- return buffer_node_ != nullptr && buffer_node_->IsValid();
- }
-
- // Captures buffer info for use by BufferHubService::DumpState().
- BufferInfo GetBufferInfo() const override;
-
- bool HandleMessage(pdx::Message& message) override;
- void HandleImpulse(pdx::Message& message) override;
-
- private:
-
- // Allocates a new detached buffer.
- BufferChannel(BufferHubService* service, int buffer_id, uint32_t width,
- uint32_t height, uint32_t layer_count, uint32_t format,
- uint64_t usage, size_t user_metadata_size);
-
- // Creates a detached buffer from an existing BufferNode. This method is used
- // in OnDuplicate method.
- BufferChannel(BufferHubService* service, int buffer_id, int channel_id,
- std::shared_ptr<BufferNode> buffer_node);
-
- pdx::Status<BufferTraits<pdx::BorrowedHandle>> OnImport(
- pdx::Message& message);
- pdx::Status<pdx::RemoteChannelHandle> OnDuplicate(pdx::Message& message);
-
- // The concrete implementation of the Buffer object.
- std::shared_ptr<BufferNode> buffer_node_ = nullptr;
-
- // The state bit of this buffer.
- uint32_t client_state_mask_ = 0U;
-};
-
-} // namespace dvr
-} // namespace android
-
-#endif // ANDROID_DVR_BUFFERHUBD_BUFFER_CHANNEL_H_
diff --git a/services/vr/bufferhubd/include/private/dvr/buffer_hub.h b/services/vr/bufferhubd/include/private/dvr/buffer_hub.h
index 01520fc..909d69b 100644
--- a/services/vr/bufferhubd/include/private/dvr/buffer_hub.h
+++ b/services/vr/bufferhubd/include/private/dvr/buffer_hub.h
@@ -144,11 +144,6 @@
pdx::Status<void> OnCreateBuffer(pdx::Message& message, uint32_t width,
uint32_t height, uint32_t format,
uint64_t usage, size_t meta_size_bytes);
- pdx::Status<void> OnCreateDetachedBuffer(pdx::Message& message,
- uint32_t width, uint32_t height,
- uint32_t layer_count,
- uint32_t format, uint64_t usage,
- size_t user_metadata_size);
pdx::Status<QueueInfo> OnCreateProducerQueue(
pdx::Message& message, const ProducerQueueConfig& producer_config,
const UsagePolicy& usage_policy);
diff --git a/services/vr/bufferhubd/include/private/dvr/buffer_node.h b/services/vr/bufferhubd/include/private/dvr/buffer_node.h
deleted file mode 100644
index 997aeda..0000000
--- a/services/vr/bufferhubd/include/private/dvr/buffer_node.h
+++ /dev/null
@@ -1,16 +0,0 @@
-#ifndef ANDROID_DVR_BUFFERHUBD_BUFFER_NODE_H_
-#define ANDROID_DVR_BUFFERHUBD_BUFFER_NODE_H_
-// TODO(b/118891412) Remove this file
-
-#include <bufferhub/BufferNode.h>
-
-namespace android {
-namespace dvr {
-
-typedef android::frameworks::bufferhub::V1_0::implementation::BufferNode
- BufferNode;
-
-} // namespace dvr
-} // namespace android
-
-#endif // ANDROID_DVR_BUFFERHUBD_BUFFER_NODE_H_
diff --git a/services/vr/bufferhubd/include/private/dvr/producer_channel.h b/services/vr/bufferhubd/include/private/dvr/producer_channel.h
index 96ef1a2..45593ad 100644
--- a/services/vr/bufferhubd/include/private/dvr/producer_channel.h
+++ b/services/vr/bufferhubd/include/private/dvr/producer_channel.h
@@ -69,7 +69,7 @@
bool CheckParameters(uint32_t width, uint32_t height, uint32_t layer_count,
uint32_t format, uint64_t usage,
- size_t user_metadata_size);
+ size_t user_metadata_size) const;
private:
std::vector<ConsumerChannel*> consumer_channels_;
@@ -112,6 +112,10 @@
// This function is used for clean up for failures in CreateConsumer method.
void RemoveConsumerClientMask(uint32_t consumer_state_mask);
+ // Checks whether the buffer is released by all active clients, excluding
+ // orphaned consumers.
+ bool IsBufferReleasedByAllActiveClientsExceptForOrphans() const;
+
ProducerChannel(const ProducerChannel&) = delete;
void operator=(const ProducerChannel&) = delete;
};
diff --git a/services/vr/bufferhubd/producer_channel.cpp b/services/vr/bufferhubd/producer_channel.cpp
index 2a6e9da..164d9e6 100644
--- a/services/vr/bufferhubd/producer_channel.cpp
+++ b/services/vr/bufferhubd/producer_channel.cpp
@@ -7,7 +7,6 @@
#include <thread>
#include <log/log.h>
-#include <private/dvr/buffer_channel.h>
#include <private/dvr/bufferhub_rpc.h>
#include <private/dvr/consumer_channel.h>
#include <private/dvr/producer_channel.h>
@@ -334,7 +333,10 @@
uint32_t current_buffer_state =
buffer_state_->load(std::memory_order_acquire);
- if (BufferHubDefs::IsBufferReleased(current_buffer_state) ||
+ // Return the consumer channel handle without signal when adding the new
+ // consumer to a buffer that is available to producer (a.k.a a fully-released
+ // buffer) or a gained buffer.
+ if (current_buffer_state == 0U ||
BufferHubDefs::AnyClientGained(current_buffer_state)) {
return {status.take()};
}
@@ -357,7 +359,7 @@
". About to try again if the buffer is still not gained nor fully "
"released.",
__FUNCTION__, current_buffer_state, updated_buffer_state);
- if (BufferHubDefs::IsBufferReleased(current_buffer_state) ||
+ if (current_buffer_state == 0U ||
BufferHubDefs::AnyClientGained(current_buffer_state)) {
ALOGI("%s: buffer is gained or fully released, state=%" PRIx32 ".",
__FUNCTION__, current_buffer_state);
@@ -369,7 +371,9 @@
(consumer_state_mask & BufferHubDefs::kHighBitsMask);
}
}
- if (update_buffer_state) {
+ if (update_buffer_state || BufferHubDefs::IsClientPosted(
+ buffer_state_->load(std::memory_order_acquire),
+ consumer_state_mask)) {
consumer->OnProducerPosted();
}
@@ -535,10 +539,8 @@
}
}
- uint32_t current_buffer_state =
- buffer_state_->load(std::memory_order_acquire);
- if (BufferHubDefs::IsBufferReleased(current_buffer_state &
- ~orphaned_consumer_bit_mask_)) {
+ if (IsBufferReleasedByAllActiveClientsExceptForOrphans()) {
+ buffer_state_->store(0U);
SignalAvailable();
if (orphaned_consumer_bit_mask_) {
ALOGW(
@@ -562,10 +564,8 @@
__FUNCTION__, consumer_state_mask);
orphaned_consumer_bit_mask_ |= consumer_state_mask;
- uint32_t current_buffer_state =
- buffer_state_->load(std::memory_order_acquire);
- if (BufferHubDefs::IsBufferReleased(current_buffer_state &
- ~orphaned_consumer_bit_mask_)) {
+ if (IsBufferReleasedByAllActiveClientsExceptForOrphans()) {
+ buffer_state_->store(0U);
SignalAvailable();
}
@@ -656,12 +656,19 @@
bool ProducerChannel::CheckParameters(uint32_t width, uint32_t height,
uint32_t layer_count, uint32_t format,
uint64_t usage,
- size_t user_metadata_size) {
+ size_t user_metadata_size) const {
return user_metadata_size == user_metadata_size_ &&
buffer_.width() == width && buffer_.height() == height &&
buffer_.layer_count() == layer_count && buffer_.format() == format &&
buffer_.usage() == usage;
}
+bool ProducerChannel::IsBufferReleasedByAllActiveClientsExceptForOrphans()
+ const {
+ return (buffer_state_->load(std::memory_order_acquire) &
+ ~orphaned_consumer_bit_mask_ &
+ active_clients_bit_mask_->load(std::memory_order_acquire)) == 0U;
+}
+
} // namespace dvr
} // namespace android
diff --git a/services/vr/hardware_composer/Android.bp b/services/vr/hardware_composer/Android.bp
index 258b45b..d9df204 100644
--- a/services/vr/hardware_composer/Android.bp
+++ b/services/vr/hardware_composer/Android.bp
@@ -15,6 +15,7 @@
"android.frameworks.vr.composer@1.0",
"android.hardware.graphics.composer@2.1",
"android.hardware.graphics.mapper@2.0",
+ "android.hardware.graphics.mapper@3.0",
"libbase",
"libbufferhubqueue",
"libbinder",
diff --git a/services/vr/hardware_composer/aidl/android/dvr/parcelable_composer_frame.h b/services/vr/hardware_composer/aidl/android/dvr/parcelable_composer_frame.h
index b478bb5..a82df7f 100644
--- a/services/vr/hardware_composer/aidl/android/dvr/parcelable_composer_frame.h
+++ b/services/vr/hardware_composer/aidl/android/dvr/parcelable_composer_frame.h
@@ -10,7 +10,7 @@
class ParcelableComposerFrame : public Parcelable {
public:
ParcelableComposerFrame();
- ParcelableComposerFrame(const ComposerView::Frame& frame);
+ explicit ParcelableComposerFrame(const ComposerView::Frame& frame);
~ParcelableComposerFrame() override;
ComposerView::Frame frame() const { return frame_; }
diff --git a/services/vr/hardware_composer/aidl/android/dvr/parcelable_composer_layer.h b/services/vr/hardware_composer/aidl/android/dvr/parcelable_composer_layer.h
index 4cf48f1..6d2ac09 100644
--- a/services/vr/hardware_composer/aidl/android/dvr/parcelable_composer_layer.h
+++ b/services/vr/hardware_composer/aidl/android/dvr/parcelable_composer_layer.h
@@ -12,7 +12,7 @@
class ParcelableComposerLayer : public Parcelable {
public:
ParcelableComposerLayer();
- ParcelableComposerLayer(const ComposerView::ComposerLayer& layer);
+ explicit ParcelableComposerLayer(const ComposerView::ComposerLayer& layer);
~ParcelableComposerLayer() override;
ComposerView::ComposerLayer layer() const { return layer_; }
diff --git a/services/vr/hardware_composer/aidl/android/dvr/parcelable_unique_fd.h b/services/vr/hardware_composer/aidl/android/dvr/parcelable_unique_fd.h
index daf9e6d..c4216f6 100644
--- a/services/vr/hardware_composer/aidl/android/dvr/parcelable_unique_fd.h
+++ b/services/vr/hardware_composer/aidl/android/dvr/parcelable_unique_fd.h
@@ -13,7 +13,7 @@
class ParcelableUniqueFd : public Parcelable {
public:
ParcelableUniqueFd();
- ParcelableUniqueFd(const base::unique_fd& fence);
+ explicit ParcelableUniqueFd(const base::unique_fd& fence);
~ParcelableUniqueFd() override;
void set_fence(const base::unique_fd& fence) {
diff --git a/services/vr/hardware_composer/impl/vr_composer_client.h b/services/vr/hardware_composer/impl/vr_composer_client.h
index de22640..0b7ce5e 100644
--- a/services/vr/hardware_composer/impl/vr_composer_client.h
+++ b/services/vr/hardware_composer/impl/vr_composer_client.h
@@ -35,13 +35,13 @@
class VrComposerClient : public ComposerClient {
public:
- VrComposerClient(android::dvr::VrHwc& hal);
+ explicit VrComposerClient(android::dvr::VrHwc& hal);
virtual ~VrComposerClient();
private:
class VrCommandEngine : public ComposerCommandEngine {
public:
- VrCommandEngine(VrComposerClient& client);
+ explicit VrCommandEngine(VrComposerClient& client);
~VrCommandEngine() override;
bool executeCommand(IComposerClient::Command command,
diff --git a/services/vr/hardware_composer/impl/vr_hwc.h b/services/vr/hardware_composer/impl/vr_hwc.h
index f9872b2..e8c0212 100644
--- a/services/vr/hardware_composer/impl/vr_hwc.h
+++ b/services/vr/hardware_composer/impl/vr_hwc.h
@@ -113,9 +113,7 @@
using Composition =
hardware::graphics::composer::V2_1::IComposerClient::Composition;
- HwcLayer(Layer new_id) {
- info.id = new_id;
- }
+ explicit HwcLayer(Layer new_id) { info.id = new_id; }
void dumpDebugInfo(std::string* result) const;
diff --git a/services/vr/virtual_touchpad/VirtualTouchpadService.h b/services/vr/virtual_touchpad/VirtualTouchpadService.h
index 2c46209..2c88aec 100644
--- a/services/vr/virtual_touchpad/VirtualTouchpadService.h
+++ b/services/vr/virtual_touchpad/VirtualTouchpadService.h
@@ -13,7 +13,7 @@
//
class VirtualTouchpadService : public BnVirtualTouchpadService {
public:
- VirtualTouchpadService(std::unique_ptr<VirtualTouchpad> touchpad)
+ explicit VirtualTouchpadService(std::unique_ptr<VirtualTouchpad> touchpad)
: touchpad_(std::move(touchpad)), client_pid_(0) {}
~VirtualTouchpadService() override;
diff --git a/vulkan/libvulkan/layers_extensions.cpp b/vulkan/libvulkan/layers_extensions.cpp
index 009b257..ba4cf00 100644
--- a/vulkan/libvulkan/layers_extensions.cpp
+++ b/vulkan/libvulkan/layers_extensions.cpp
@@ -139,12 +139,12 @@
auto app_namespace = android::GraphicsEnv::getInstance().getAppNamespace();
if (app_namespace &&
!android::base::StartsWith(path_, kSystemLayerLibraryDir)) {
- std::string error_msg;
- dlhandle_ = OpenNativeLibrary(
+ char* error_msg = nullptr;
+ dlhandle_ = OpenNativeLibraryInNamespace(
app_namespace, path_.c_str(), &native_bridge_, &error_msg);
if (!dlhandle_) {
- ALOGE("failed to load layer library '%s': %s", path_.c_str(),
- error_msg.c_str());
+ ALOGE("failed to load layer library '%s': %s", path_.c_str(), error_msg);
+ android::NativeLoaderFreeErrorMessage(error_msg);
refcount_ = 0;
return false;
}
@@ -165,9 +165,10 @@
std::lock_guard<std::mutex> lock(mutex_);
if (--refcount_ == 0) {
ALOGV("closing layer library '%s'", path_.c_str());
- std::string error_msg;
+ char* error_msg = nullptr;
if (!android::CloseNativeLibrary(dlhandle_, native_bridge_, &error_msg)) {
- ALOGE("failed to unload library '%s': %s", path_.c_str(), error_msg.c_str());
+ ALOGE("failed to unload library '%s': %s", path_.c_str(), error_msg);
+ android::NativeLoaderFreeErrorMessage(error_msg);
refcount_++;
} else {
dlhandle_ = nullptr;
diff --git a/vulkan/libvulkan/layers_extensions.h b/vulkan/libvulkan/layers_extensions.h
index 1dae456..9e2ff5b 100644
--- a/vulkan/libvulkan/layers_extensions.h
+++ b/vulkan/libvulkan/layers_extensions.h
@@ -33,6 +33,7 @@
LayerRef& operator=(const LayerRef&) = delete;
// provides bool-like behavior
+ // NOLINTNEXTLINE(google-explicit-constructor)
operator const Layer*() const { return layer_; }
PFN_vkGetInstanceProcAddr GetGetInstanceProcAddr() const;
diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp
index 8601373..47334f6 100644
--- a/vulkan/libvulkan/swapchain.cpp
+++ b/vulkan/libvulkan/swapchain.cpp
@@ -416,7 +416,7 @@
case VK_FORMAT_R16G16B16A16_SFLOAT:
native_format = HAL_PIXEL_FORMAT_RGBA_FP16;
break;
- case VK_FORMAT_A2R10G10B10_UNORM_PACK32:
+ case VK_FORMAT_A2B10G10R10_UNORM_PACK32:
native_format = HAL_PIXEL_FORMAT_RGBA_1010102;
break;
default:
@@ -570,6 +570,7 @@
case HAL_PIXEL_FORMAT_RGBA_8888:
case HAL_PIXEL_FORMAT_RGB_565:
case HAL_PIXEL_FORMAT_RGBA_FP16:
+ case HAL_PIXEL_FORMAT_RGBA_1010102:
format_supported = true;
break;
default:
@@ -700,6 +701,8 @@
VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT},
{VK_FORMAT_R16G16B16A16_SFLOAT,
VK_COLOR_SPACE_EXTENDED_SRGB_NONLINEAR_EXT},
+ {VK_FORMAT_A2B10G10R10_UNORM_PACK32,
+ VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT},
};
const uint32_t kNumWideColorFormats =
sizeof(kWideColorFormats) / sizeof(kWideColorFormats[0]);