Merge "Enable more ColorSpaces in RenderEngine"
diff --git a/cmds/dumpstate/Android.bp b/cmds/dumpstate/Android.bp
index 74dbf4b..a2491e5 100644
--- a/cmds/dumpstate/Android.bp
+++ b/cmds/dumpstate/Android.bp
@@ -86,9 +86,11 @@
shared_libs: [
"android.hardware.dumpstate@1.0",
"android.hardware.dumpstate@1.1",
+ "android.hardware.dumpstate-V1-ndk",
"libziparchive",
"libbase",
"libbinder",
+ "libbinder_ndk",
"libcrypto",
"libcutils",
"libdebuggerd_client",
diff --git a/cmds/dumpstate/DumpstateService.cpp b/cmds/dumpstate/DumpstateService.cpp
index ba25a5a..77915d5 100644
--- a/cmds/dumpstate/DumpstateService.cpp
+++ b/cmds/dumpstate/DumpstateService.cpp
@@ -192,7 +192,7 @@
dprintf(fd, "progress:\n");
ds_->progress_->Dump(fd, " ");
dprintf(fd, "args: %s\n", ds_->options_->args.c_str());
- dprintf(fd, "bugreport_mode: %s\n", ds_->options_->bugreport_mode.c_str());
+ dprintf(fd, "bugreport_mode: %s\n", ds_->options_->bugreport_mode_string.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());
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index eab72f4..32e680d 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -57,12 +57,15 @@
#include <utility>
#include <vector>
+#include <aidl/android/hardware/dumpstate/IDumpstateDevice.h>
#include <android-base/file.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>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
#include <android/content/pm/IPackageManagerNative.h>
#include <android/hardware/dumpstate/1.0/IDumpstateDevice.h>
#include <android/hardware/dumpstate/1.1/IDumpstateDevice.h>
@@ -89,11 +92,10 @@
#include "DumpstateService.h"
#include "dumpstate.h"
-using IDumpstateDevice_1_0 = ::android::hardware::dumpstate::V1_0::IDumpstateDevice;
-using IDumpstateDevice_1_1 = ::android::hardware::dumpstate::V1_1::IDumpstateDevice;
-using ::android::hardware::dumpstate::V1_1::DumpstateMode;
-using ::android::hardware::dumpstate::V1_1::DumpstateStatus;
-using ::android::hardware::dumpstate::V1_1::toString;
+namespace dumpstate_hal_hidl_1_0 = android::hardware::dumpstate::V1_0;
+namespace dumpstate_hal_hidl = android::hardware::dumpstate::V1_1;
+namespace dumpstate_hal_aidl = aidl::android::hardware::dumpstate;
+
using ::std::literals::chrono_literals::operator""ms;
using ::std::literals::chrono_literals::operator""s;
using ::std::placeholders::_1;
@@ -807,7 +809,7 @@
printf("Bugreport format version: %s\n", version_.c_str());
printf("Dumpstate info: id=%d pid=%d dry_run=%d parallel_run=%d args=%s bugreport_mode=%s\n",
id_, pid_, PropertiesHelper::IsDryRun(), PropertiesHelper::IsParallelRun(),
- options_->args.c_str(), options_->bugreport_mode.c_str());
+ options_->args.c_str(), options_->bugreport_mode_string.c_str());
printf("\n");
}
@@ -2199,6 +2201,194 @@
return RunStatus::OK;
}
+static dumpstate_hal_hidl::DumpstateMode GetDumpstateHalModeHidl(
+ const Dumpstate::BugreportMode bugreport_mode) {
+ switch (bugreport_mode) {
+ case Dumpstate::BugreportMode::BUGREPORT_FULL:
+ return dumpstate_hal_hidl::DumpstateMode::FULL;
+ case Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE:
+ return dumpstate_hal_hidl::DumpstateMode::INTERACTIVE;
+ case Dumpstate::BugreportMode::BUGREPORT_REMOTE:
+ return dumpstate_hal_hidl::DumpstateMode::REMOTE;
+ case Dumpstate::BugreportMode::BUGREPORT_WEAR:
+ return dumpstate_hal_hidl::DumpstateMode::WEAR;
+ case Dumpstate::BugreportMode::BUGREPORT_TELEPHONY:
+ return dumpstate_hal_hidl::DumpstateMode::CONNECTIVITY;
+ case Dumpstate::BugreportMode::BUGREPORT_WIFI:
+ return dumpstate_hal_hidl::DumpstateMode::WIFI;
+ case Dumpstate::BugreportMode::BUGREPORT_DEFAULT:
+ return dumpstate_hal_hidl::DumpstateMode::DEFAULT;
+ }
+ return dumpstate_hal_hidl::DumpstateMode::DEFAULT;
+}
+
+static dumpstate_hal_aidl::IDumpstateDevice::DumpstateMode GetDumpstateHalModeAidl(
+ const Dumpstate::BugreportMode bugreport_mode) {
+ switch (bugreport_mode) {
+ case Dumpstate::BugreportMode::BUGREPORT_FULL:
+ return dumpstate_hal_aidl::IDumpstateDevice::DumpstateMode::FULL;
+ case Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE:
+ return dumpstate_hal_aidl::IDumpstateDevice::DumpstateMode::INTERACTIVE;
+ case Dumpstate::BugreportMode::BUGREPORT_REMOTE:
+ return dumpstate_hal_aidl::IDumpstateDevice::DumpstateMode::REMOTE;
+ case Dumpstate::BugreportMode::BUGREPORT_WEAR:
+ return dumpstate_hal_aidl::IDumpstateDevice::DumpstateMode::WEAR;
+ case Dumpstate::BugreportMode::BUGREPORT_TELEPHONY:
+ return dumpstate_hal_aidl::IDumpstateDevice::DumpstateMode::CONNECTIVITY;
+ case Dumpstate::BugreportMode::BUGREPORT_WIFI:
+ return dumpstate_hal_aidl::IDumpstateDevice::DumpstateMode::WIFI;
+ case Dumpstate::BugreportMode::BUGREPORT_DEFAULT:
+ return dumpstate_hal_aidl::IDumpstateDevice::DumpstateMode::DEFAULT;
+ }
+ return dumpstate_hal_aidl::IDumpstateDevice::DumpstateMode::DEFAULT;
+}
+
+static void DoDumpstateBoardHidl(
+ const sp<dumpstate_hal_hidl_1_0::IDumpstateDevice> dumpstate_hal_1_0,
+ const std::vector<::ndk::ScopedFileDescriptor>& dumpstate_fds,
+ const Dumpstate::BugreportMode bugreport_mode,
+ const size_t timeout_sec) {
+
+ using ScopedNativeHandle =
+ std::unique_ptr<native_handle_t, std::function<void(native_handle_t*)>>;
+ ScopedNativeHandle handle(native_handle_create(static_cast<int>(dumpstate_fds.size()), 0),
+ [](native_handle_t* handle) {
+ // we don't close file handle's here
+ // via native_handle_close(handle)
+ // instead we let dumpstate_fds close the file handles when
+ // dumpstate_fds gets destroyed
+ native_handle_delete(handle);
+ });
+ if (handle == nullptr) {
+ MYLOGE("Could not create native_handle for dumpstate HAL\n");
+ return;
+ }
+
+ for (size_t i = 0; i < dumpstate_fds.size(); i++) {
+ handle.get()->data[i] = dumpstate_fds[i].get();
+ }
+
+ // Prefer version 1.1 if available. New devices launching with R are no longer allowed to
+ // implement just 1.0.
+ const char* descriptor_to_kill;
+ using DumpstateBoardTask = std::packaged_task<bool()>;
+ DumpstateBoardTask dumpstate_board_task;
+ sp<dumpstate_hal_hidl::IDumpstateDevice> dumpstate_hal(
+ dumpstate_hal_hidl::IDumpstateDevice::castFrom(dumpstate_hal_1_0));
+ if (dumpstate_hal != nullptr) {
+ MYLOGI("Using IDumpstateDevice v1.1 HIDL HAL");
+
+ dumpstate_hal_hidl::DumpstateMode dumpstate_hal_mode =
+ GetDumpstateHalModeHidl(bugreport_mode);
+
+ descriptor_to_kill = dumpstate_hal_hidl::IDumpstateDevice::descriptor;
+ dumpstate_board_task =
+ DumpstateBoardTask([timeout_sec, dumpstate_hal_mode, dumpstate_hal, &handle]() -> bool {
+ ::android::hardware::Return<dumpstate_hal_hidl::DumpstateStatus> status =
+ dumpstate_hal->dumpstateBoard_1_1(handle.get(), dumpstate_hal_mode,
+ SEC_TO_MSEC(timeout_sec));
+ if (!status.isOk()) {
+ MYLOGE("dumpstateBoard failed: %s\n", status.description().c_str());
+ return false;
+ } else if (status != dumpstate_hal_hidl::DumpstateStatus::OK) {
+ MYLOGE("dumpstateBoard failed with DumpstateStatus::%s\n",
+ dumpstate_hal_hidl::toString(status).c_str());
+ return false;
+ }
+ return true;
+ });
+ } else {
+ MYLOGI("Using IDumpstateDevice v1.0 HIDL HAL");
+
+ descriptor_to_kill = dumpstate_hal_hidl_1_0::IDumpstateDevice::descriptor;
+ dumpstate_board_task = DumpstateBoardTask([dumpstate_hal_1_0, &handle]() -> bool {
+ ::android::hardware::Return<void> status =
+ dumpstate_hal_1_0->dumpstateBoard(handle.get());
+ if (!status.isOk()) {
+ MYLOGE("dumpstateBoard failed: %s\n", status.description().c_str());
+ return false;
+ }
+ return true;
+ });
+ }
+ auto result = dumpstate_board_task.get_future();
+ std::thread(std::move(dumpstate_board_task)).detach();
+
+ if (result.wait_for(std::chrono::seconds(timeout_sec)) != std::future_status::ready) {
+ MYLOGE("dumpstateBoard timed out after %zus, killing dumpstate HAL\n", timeout_sec);
+ if (!android::base::SetProperty(
+ "ctl.interface_restart",
+ android::base::StringPrintf("%s/default", descriptor_to_kill))) {
+ MYLOGE("Couldn't restart dumpstate HAL\n");
+ }
+ }
+ // Wait some time for init to kill dumpstate vendor HAL
+ constexpr size_t killing_timeout_sec = 10;
+ if (result.wait_for(std::chrono::seconds(killing_timeout_sec)) != std::future_status::ready) {
+ MYLOGE(
+ "killing dumpstateBoard timed out after %zus, continue and "
+ "there might be racing in content\n",
+ killing_timeout_sec);
+ }
+}
+
+static void DoDumpstateBoardAidl(
+ const std::shared_ptr<dumpstate_hal_aidl::IDumpstateDevice> dumpstate_hal,
+ const std::vector<::ndk::ScopedFileDescriptor>& dumpstate_fds,
+ const Dumpstate::BugreportMode bugreport_mode, const size_t timeout_sec) {
+ MYLOGI("Using IDumpstateDevice AIDL HAL");
+
+ const char* descriptor_to_kill;
+ using DumpstateBoardTask = std::packaged_task<bool()>;
+ DumpstateBoardTask dumpstate_board_task;
+ dumpstate_hal_aidl::IDumpstateDevice::DumpstateMode dumpstate_hal_mode =
+ GetDumpstateHalModeAidl(bugreport_mode);
+
+ descriptor_to_kill = dumpstate_hal_aidl::IDumpstateDevice::descriptor;
+ dumpstate_board_task = DumpstateBoardTask([dumpstate_hal, &dumpstate_fds, dumpstate_hal_mode,
+ timeout_sec]() -> bool {
+ auto status = dumpstate_hal->dumpstateBoard(dumpstate_fds, dumpstate_hal_mode, timeout_sec);
+
+ if (!status.isOk()) {
+ MYLOGE("dumpstateBoard failed: %s\n", status.getDescription().c_str());
+ return false;
+ }
+ return true;
+ });
+ auto result = dumpstate_board_task.get_future();
+ std::thread(std::move(dumpstate_board_task)).detach();
+
+ if (result.wait_for(std::chrono::seconds(timeout_sec)) != std::future_status::ready) {
+ MYLOGE("dumpstateBoard timed out after %zus, killing dumpstate HAL\n", timeout_sec);
+ if (!android::base::SetProperty(
+ "ctl.interface_restart",
+ android::base::StringPrintf("%s/default", descriptor_to_kill))) {
+ MYLOGE("Couldn't restart dumpstate HAL\n");
+ }
+ }
+ // Wait some time for init to kill dumpstate vendor HAL
+ constexpr size_t killing_timeout_sec = 10;
+ if (result.wait_for(std::chrono::seconds(killing_timeout_sec)) != std::future_status::ready) {
+ MYLOGE(
+ "killing dumpstateBoard timed out after %zus, continue and "
+ "there might be racing in content\n",
+ killing_timeout_sec);
+ }
+}
+
+static std::shared_ptr<dumpstate_hal_aidl::IDumpstateDevice> GetDumpstateBoardAidlService() {
+ const std::string aidl_instance_name =
+ std::string(dumpstate_hal_aidl::IDumpstateDevice::descriptor) + "/default";
+
+ if (!AServiceManager_isDeclared(aidl_instance_name.c_str())) {
+ return nullptr;
+ }
+
+ ndk::SpAIBinder dumpstateBinder(AServiceManager_waitForService(aidl_instance_name.c_str()));
+
+ return dumpstate_hal_aidl::IDumpstateDevice::fromBinder(dumpstateBinder);
+}
+
void Dumpstate::DumpstateBoard(int out_fd) {
dprintf(out_fd, "========================================================\n");
dprintf(out_fd, "== Board\n");
@@ -2220,8 +2410,7 @@
if (mount_debugfs) {
RunCommand("mount debugfs", {"mount", "-t", "debugfs", "debugfs", "/sys/kernel/debug"},
AS_ROOT_20);
- RunCommand("chmod debugfs", {"chmod", "0755", "/sys/kernel/debug"},
- AS_ROOT_20);
+ RunCommand("chmod debugfs", {"chmod", "0755", "/sys/kernel/debug"}, AS_ROOT_20);
}
std::vector<std::string> paths;
@@ -2233,23 +2422,31 @@
std::bind([](std::string path) { android::os::UnlinkAndLogOnError(path); }, paths[i])));
}
- sp<IDumpstateDevice_1_0> dumpstate_device_1_0(IDumpstateDevice_1_0::getService());
- if (dumpstate_device_1_0 == nullptr) {
- MYLOGE("No IDumpstateDevice implementation\n");
+ // get dumpstate HAL AIDL implementation
+ std::shared_ptr<dumpstate_hal_aidl::IDumpstateDevice> dumpstate_hal_handle_aidl(
+ GetDumpstateBoardAidlService());
+ if (dumpstate_hal_handle_aidl == nullptr) {
+ MYLOGI("No IDumpstateDevice AIDL implementation\n");
+ }
+
+ // get dumpstate HAL HIDL implementation, only if AIDL HAL implementation not found
+ sp<dumpstate_hal_hidl_1_0::IDumpstateDevice> dumpstate_hal_handle_hidl_1_0 = nullptr;
+ if (dumpstate_hal_handle_aidl == nullptr) {
+ dumpstate_hal_handle_hidl_1_0 = dumpstate_hal_hidl_1_0::IDumpstateDevice::getService();
+ if (dumpstate_hal_handle_hidl_1_0 == nullptr) {
+ MYLOGI("No IDumpstateDevice HIDL implementation\n");
+ }
+ }
+
+ // if neither HIDL nor AIDL implementation found, then return
+ if (dumpstate_hal_handle_hidl_1_0 == nullptr && dumpstate_hal_handle_aidl == nullptr) {
+ MYLOGE("Could not find IDumpstateDevice implementation\n");
return;
}
- using ScopedNativeHandle =
- std::unique_ptr<native_handle_t, std::function<void(native_handle_t*)>>;
- ScopedNativeHandle handle(native_handle_create(static_cast<int>(paths.size()), 0),
- [](native_handle_t* handle) {
- native_handle_close(handle);
- native_handle_delete(handle);
- });
- if (handle == nullptr) {
- MYLOGE("Could not create native_handle\n");
- return;
- }
+ // this is used to hold the file descriptors and when this variable goes out of scope
+ // the file descriptors are closed
+ std::vector<::ndk::ScopedFileDescriptor> dumpstate_fds;
// TODO(128270426): Check for consent in between?
for (size_t i = 0; i < paths.size(); i++) {
@@ -2262,65 +2459,26 @@
MYLOGE("Could not open file %s: %s\n", paths[i].c_str(), strerror(errno));
return;
}
- handle.get()->data[i] = fd.release();
+
+ dumpstate_fds.emplace_back(fd.release());
+ // we call fd.release() here to make sure "fd" does not get closed
+ // after "fd" goes out of scope after this block.
+ // "fd" will be closed when "dumpstate_fds" goes out of scope
+ // i.e. when we exit this function
}
// Given that bugreport is required to diagnose failures, it's better to set an arbitrary amount
// of timeout for IDumpstateDevice than to block the rest of bugreport. In the timeout case, we
// will kill the HAL and grab whatever it dumped in time.
constexpr size_t timeout_sec = 30;
- // Prefer version 1.1 if available. New devices launching with R are no longer allowed to
- // implement just 1.0.
- const char* descriptor_to_kill;
- using DumpstateBoardTask = std::packaged_task<bool()>;
- DumpstateBoardTask dumpstate_board_task;
- sp<IDumpstateDevice_1_1> dumpstate_device_1_1(
- IDumpstateDevice_1_1::castFrom(dumpstate_device_1_0));
- if (dumpstate_device_1_1 != nullptr) {
- MYLOGI("Using IDumpstateDevice v1.1");
- descriptor_to_kill = IDumpstateDevice_1_1::descriptor;
- dumpstate_board_task = DumpstateBoardTask([this, dumpstate_device_1_1, &handle]() -> bool {
- ::android::hardware::Return<DumpstateStatus> status =
- dumpstate_device_1_1->dumpstateBoard_1_1(handle.get(), options_->dumpstate_hal_mode,
- SEC_TO_MSEC(timeout_sec));
- if (!status.isOk()) {
- MYLOGE("dumpstateBoard failed: %s\n", status.description().c_str());
- return false;
- } else if (status != DumpstateStatus::OK) {
- MYLOGE("dumpstateBoard failed with DumpstateStatus::%s\n", toString(status).c_str());
- return false;
- }
- return true;
- });
- } else {
- MYLOGI("Using IDumpstateDevice v1.0");
- descriptor_to_kill = IDumpstateDevice_1_0::descriptor;
- dumpstate_board_task = DumpstateBoardTask([dumpstate_device_1_0, &handle]() -> bool {
- ::android::hardware::Return<void> status =
- dumpstate_device_1_0->dumpstateBoard(handle.get());
- if (!status.isOk()) {
- MYLOGE("dumpstateBoard failed: %s\n", status.description().c_str());
- return false;
- }
- return true;
- });
- }
- auto result = dumpstate_board_task.get_future();
- std::thread(std::move(dumpstate_board_task)).detach();
- if (result.wait_for(std::chrono::seconds(timeout_sec)) != std::future_status::ready) {
- MYLOGE("dumpstateBoard timed out after %zus, killing dumpstate vendor HAL\n", timeout_sec);
- if (!android::base::SetProperty(
- "ctl.interface_restart",
- android::base::StringPrintf("%s/default", descriptor_to_kill))) {
- MYLOGE("Couldn't restart dumpstate HAL\n");
- }
- }
- // Wait some time for init to kill dumpstate vendor HAL
- constexpr size_t killing_timeout_sec = 10;
- if (result.wait_for(std::chrono::seconds(killing_timeout_sec)) != std::future_status::ready) {
- MYLOGE("killing dumpstateBoard timed out after %zus, continue and "
- "there might be racing in content\n", killing_timeout_sec);
+ if (dumpstate_hal_handle_aidl != nullptr) {
+ DoDumpstateBoardAidl(dumpstate_hal_handle_aidl, dumpstate_fds, options_->bugreport_mode,
+ timeout_sec);
+ } else if (dumpstate_hal_handle_hidl_1_0 != nullptr) {
+ // run HIDL HAL only if AIDL HAL not found
+ DoDumpstateBoardHidl(dumpstate_hal_handle_hidl_1_0, dumpstate_fds, options_->bugreport_mode,
+ timeout_sec);
}
if (mount_debugfs) {
@@ -2333,9 +2491,8 @@
auto file_sizes = std::make_unique<ssize_t[]>(paths.size());
for (size_t i = 0; i < paths.size(); i++) {
struct stat s;
- if (fstat(handle.get()->data[i], &s) == -1) {
- MYLOGE("Failed to fstat %s: %s\n", kDumpstateBoardFiles[i].c_str(),
- strerror(errno));
+ if (fstat(dumpstate_fds[i].get(), &s) == -1) {
+ MYLOGE("Failed to fstat %s: %s\n", kDumpstateBoardFiles[i].c_str(), strerror(errno));
file_sizes[i] = -1;
continue;
}
@@ -2574,40 +2731,35 @@
bool is_screenshot_requested) {
// Modify com.android.shell.BugreportProgressService#isDefaultScreenshotRequired as well for
// default system screenshots.
- options->bugreport_mode = ModeToString(mode);
+ options->bugreport_mode = mode;
+ options->bugreport_mode_string = ModeToString(mode);
switch (mode) {
case Dumpstate::BugreportMode::BUGREPORT_FULL:
options->do_screenshot = is_screenshot_requested;
- options->dumpstate_hal_mode = DumpstateMode::FULL;
break;
case Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE:
// Currently, the dumpstate binder is only used by Shell to update progress.
options->do_progress_updates = true;
options->do_screenshot = is_screenshot_requested;
- options->dumpstate_hal_mode = DumpstateMode::INTERACTIVE;
break;
case Dumpstate::BugreportMode::BUGREPORT_REMOTE:
options->do_vibrate = false;
options->is_remote_mode = true;
options->do_screenshot = false;
- options->dumpstate_hal_mode = DumpstateMode::REMOTE;
break;
case Dumpstate::BugreportMode::BUGREPORT_WEAR:
options->do_progress_updates = true;
options->do_screenshot = is_screenshot_requested;
- options->dumpstate_hal_mode = DumpstateMode::WEAR;
break;
// TODO(b/148168577) rename TELEPHONY everywhere to CONNECTIVITY.
case Dumpstate::BugreportMode::BUGREPORT_TELEPHONY:
options->telephony_only = true;
options->do_progress_updates = true;
options->do_screenshot = false;
- options->dumpstate_hal_mode = DumpstateMode::CONNECTIVITY;
break;
case Dumpstate::BugreportMode::BUGREPORT_WIFI:
options->wifi_only = true;
options->do_screenshot = false;
- options->dumpstate_hal_mode = DumpstateMode::WIFI;
break;
case Dumpstate::BugreportMode::BUGREPORT_DEFAULT:
break;
@@ -2618,13 +2770,14 @@
MYLOGI(
"do_vibrate: %d stream_to_socket: %d progress_updates_to_socket: %d do_screenshot: %d "
"is_remote_mode: %d show_header_only: %d telephony_only: %d "
- "wifi_only: %d do_progress_updates: %d fd: %d bugreport_mode: %s dumpstate_hal_mode: %s "
+ "wifi_only: %d do_progress_updates: %d fd: %d bugreport_mode: %s "
"limited_only: %d args: %s\n",
options.do_vibrate, options.stream_to_socket, options.progress_updates_to_socket,
options.do_screenshot, options.is_remote_mode, options.show_header_only,
options.telephony_only, options.wifi_only,
- options.do_progress_updates, options.bugreport_fd.get(), options.bugreport_mode.c_str(),
- toString(options.dumpstate_hal_mode).c_str(), options.limited_only, options.args.c_str());
+ options.do_progress_updates, options.bugreport_fd.get(),
+ options.bugreport_mode_string.c_str(),
+ options.limited_only, options.args.c_str());
}
void Dumpstate::DumpOptions::Initialize(BugreportMode bugreport_mode,
@@ -2838,7 +2991,7 @@
}
MYLOGI("dumpstate info: id=%d, args='%s', bugreport_mode= %s bugreport format version: %s\n",
- id_, options_->args.c_str(), options_->bugreport_mode.c_str(), version_.c_str());
+ id_, options_->args.c_str(), options_->bugreport_mode_string.c_str(), version_.c_str());
do_early_screenshot_ = options_->do_progress_updates;
diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h
index 3722383..773e292 100644
--- a/cmds/dumpstate/dumpstate.h
+++ b/cmds/dumpstate/dumpstate.h
@@ -25,6 +25,7 @@
#include <string>
#include <vector>
+#include <aidl/android/hardware/dumpstate/IDumpstateDevice.h>
#include <android-base/macros.h>
#include <android-base/unique_fd.h>
#include <android/hardware/dumpstate/1.1/types.h>
@@ -400,19 +401,18 @@
bool limited_only = false;
// Whether progress updates should be published.
bool do_progress_updates = false;
- // The mode we'll use when calling IDumpstateDevice::dumpstateBoard.
+ // this is used to derive dumpstate HAL bug report mode
// TODO(b/148168577) get rid of the AIDL values, replace them with the HAL values instead.
// The HAL is actually an API surface that can be validated, while the AIDL is not (@hide).
- ::android::hardware::dumpstate::V1_1::DumpstateMode dumpstate_hal_mode =
- ::android::hardware::dumpstate::V1_1::DumpstateMode::DEFAULT;
+ BugreportMode bugreport_mode = Dumpstate::BugreportMode::BUGREPORT_DEFAULT;
// File descriptor to output zip file. Takes precedence over out_dir.
android::base::unique_fd bugreport_fd;
// File descriptor to screenshot file.
android::base::unique_fd screenshot_fd;
// Custom output directory.
std::string out_dir;
- // Bugreport mode of the bugreport.
- std::string bugreport_mode;
+ // Bugreport mode of the bugreport as a string
+ std::string bugreport_mode_string;
// Command-line arguments as string
std::string args;
// Notification title and description
diff --git a/cmds/dumpstate/tests/dumpstate_test.cpp b/cmds/dumpstate/tests/dumpstate_test.cpp
index db508b5..42beb2b 100644
--- a/cmds/dumpstate/tests/dumpstate_test.cpp
+++ b/cmds/dumpstate/tests/dumpstate_test.cpp
@@ -33,6 +33,7 @@
#include <unistd.h>
#include <thread>
+#include <aidl/android/hardware/dumpstate/IDumpstateDevice.h>
#include <android-base/file.h>
#include <android-base/properties.h>
#include <android-base/stringprintf.h>
@@ -47,6 +48,7 @@
namespace os {
namespace dumpstate {
+using DumpstateDeviceAidl = ::aidl::android::hardware::dumpstate::IDumpstateDevice;
using ::android::hardware::dumpstate::V1_1::DumpstateMode;
using ::testing::EndsWith;
using ::testing::Eq;
@@ -186,7 +188,6 @@
EXPECT_FALSE(options_.do_progress_updates);
EXPECT_FALSE(options_.is_remote_mode);
EXPECT_FALSE(options_.limited_only);
- EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::DEFAULT);
}
TEST_F(DumpOptionsTest, InitializeAdbBugreport) {
@@ -210,7 +211,6 @@
EXPECT_FALSE(options_.is_remote_mode);
EXPECT_FALSE(options_.stream_to_socket);
EXPECT_FALSE(options_.limited_only);
- EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::DEFAULT);
}
TEST_F(DumpOptionsTest, InitializeAdbShellBugreport) {
@@ -234,13 +234,11 @@
EXPECT_FALSE(options_.do_progress_updates);
EXPECT_FALSE(options_.is_remote_mode);
EXPECT_FALSE(options_.limited_only);
- EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::DEFAULT);
}
TEST_F(DumpOptionsTest, InitializeFullBugReport) {
options_.Initialize(Dumpstate::BugreportMode::BUGREPORT_FULL, fd, fd, true);
EXPECT_TRUE(options_.do_screenshot);
- EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::FULL);
// Other options retain default values
EXPECT_TRUE(options_.do_vibrate);
@@ -256,7 +254,6 @@
options_.Initialize(Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE, fd, fd, true);
EXPECT_TRUE(options_.do_progress_updates);
EXPECT_TRUE(options_.do_screenshot);
- EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::INTERACTIVE);
// Other options retain default values
EXPECT_TRUE(options_.do_vibrate);
@@ -272,7 +269,6 @@
EXPECT_TRUE(options_.is_remote_mode);
EXPECT_FALSE(options_.do_vibrate);
EXPECT_FALSE(options_.do_screenshot);
- EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::REMOTE);
// Other options retain default values
EXPECT_FALSE(options_.progress_updates_to_socket);
@@ -286,7 +282,7 @@
options_.Initialize(Dumpstate::BugreportMode::BUGREPORT_WEAR, fd, fd, true);
EXPECT_TRUE(options_.do_screenshot);
EXPECT_TRUE(options_.do_progress_updates);
- EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::WEAR);
+
// Other options retain default values
EXPECT_TRUE(options_.do_vibrate);
@@ -302,7 +298,6 @@
EXPECT_FALSE(options_.do_screenshot);
EXPECT_TRUE(options_.telephony_only);
EXPECT_TRUE(options_.do_progress_updates);
- EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::CONNECTIVITY);
// Other options retain default values
EXPECT_TRUE(options_.do_vibrate);
@@ -317,7 +312,6 @@
options_.Initialize(Dumpstate::BugreportMode::BUGREPORT_WIFI, fd, fd, false);
EXPECT_FALSE(options_.do_screenshot);
EXPECT_TRUE(options_.wifi_only);
- EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::WIFI);
// Other options retain default values
EXPECT_TRUE(options_.do_vibrate);
@@ -354,7 +348,6 @@
EXPECT_FALSE(options_.do_progress_updates);
EXPECT_FALSE(options_.is_remote_mode);
EXPECT_FALSE(options_.stream_to_socket);
- EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::DEFAULT);
}
TEST_F(DumpOptionsTest, InitializeDefaultBugReport) {
@@ -371,7 +364,6 @@
EXPECT_EQ(status, Dumpstate::RunStatus::OK);
EXPECT_TRUE(options_.do_screenshot);
- EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::DEFAULT);
// Other options retain default values
EXPECT_TRUE(options_.do_vibrate);
@@ -408,7 +400,6 @@
EXPECT_FALSE(options_.do_progress_updates);
EXPECT_FALSE(options_.is_remote_mode);
EXPECT_FALSE(options_.limited_only);
- EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::DEFAULT);
}
TEST_F(DumpOptionsTest, InitializePartial2) {
@@ -436,7 +427,6 @@
EXPECT_FALSE(options_.stream_to_socket);
EXPECT_FALSE(options_.progress_updates_to_socket);
EXPECT_FALSE(options_.limited_only);
- EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::DEFAULT);
}
TEST_F(DumpOptionsTest, InitializeHelp) {
diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp
index f05426f..dd50ca7 100644
--- a/libs/gui/BLASTBufferQueue.cpp
+++ b/libs/gui/BLASTBufferQueue.cpp
@@ -649,6 +649,9 @@
// add to shadow queue
mNumFrameAvailable++;
+ if (mWaitForTransactionCallback && mNumFrameAvailable == 2) {
+ acquireAndReleaseBuffer();
+ }
ATRACE_INT(mQueuedBufferTrace.c_str(),
mNumFrameAvailable + mNumAcquired - mPendingRelease.size());
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index ec0573a..cd1c810 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -550,7 +550,9 @@
}
bool InputWindowCommands::empty() const {
- return focusRequests.empty() && !syncInputWindows;
+ bool empty = true;
+ empty = focusRequests.empty() && !syncInputWindows;
+ return empty;
}
void InputWindowCommands::clear() {
diff --git a/libs/gui/tests/EndToEndNativeInputTest.cpp b/libs/gui/tests/EndToEndNativeInputTest.cpp
index d9beb23..f960e07 100644
--- a/libs/gui/tests/EndToEndNativeInputTest.cpp
+++ b/libs/gui/tests/EndToEndNativeInputTest.cpp
@@ -936,6 +936,20 @@
EXPECT_EQ(surface->consumeEvent(100), nullptr);
}
+TEST_F(InputSurfacesTest, ignore_touch_region_with_zero_sized_blast) {
+ std::unique_ptr<InputSurface> surface = makeSurface(100, 100);
+
+ std::unique_ptr<BlastInputSurface> bufferSurface =
+ BlastInputSurface::makeBlastInputSurface(mComposerClient, 0, 0);
+
+ surface->showAt(100, 100);
+ bufferSurface->mInputInfo.touchableRegion.orSelf(Rect(0, 0, 200, 200));
+ bufferSurface->showAt(100, 100, Rect::EMPTY_RECT);
+
+ injectTap(101, 101);
+ surface->expectTap(1, 1);
+}
+
TEST_F(InputSurfacesTest, drop_input_policy) {
std::unique_ptr<InputSurface> surface = makeSurface(100, 100);
surface->doTransaction(
diff --git a/libs/ui/PixelFormat.cpp b/libs/ui/PixelFormat.cpp
index e88fdd5..d1925cb 100644
--- a/libs/ui/PixelFormat.cpp
+++ b/libs/ui/PixelFormat.cpp
@@ -39,25 +39,6 @@
return 0;
}
-uint32_t bitsPerPixel(PixelFormat format) {
- switch (format) {
- case PIXEL_FORMAT_RGBA_FP16:
- return 64;
- case PIXEL_FORMAT_RGBA_8888:
- case PIXEL_FORMAT_RGBX_8888:
- case PIXEL_FORMAT_BGRA_8888:
- case PIXEL_FORMAT_RGBA_1010102:
- return 32;
- case PIXEL_FORMAT_RGB_888:
- return 24;
- case PIXEL_FORMAT_RGB_565:
- case PIXEL_FORMAT_RGBA_5551:
- case PIXEL_FORMAT_RGBA_4444:
- return 16;
- }
- return 0;
-}
-
// ----------------------------------------------------------------------------
}; // namespace android
// ----------------------------------------------------------------------------
diff --git a/libs/ui/include/ui/PixelFormat.h b/libs/ui/include/ui/PixelFormat.h
index 02773d9..91ff39e 100644
--- a/libs/ui/include/ui/PixelFormat.h
+++ b/libs/ui/include/ui/PixelFormat.h
@@ -67,7 +67,6 @@
typedef int32_t PixelFormat;
uint32_t bytesPerPixel(PixelFormat format);
-uint32_t bitsPerPixel(PixelFormat format);
}; // namespace android
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index f16cd63..5560ed7 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -205,6 +205,7 @@
"SurfaceFlingerDefaultFactory.cpp",
"SurfaceInterceptor.cpp",
"Tracing/LayerTracing.cpp",
+ "Tracing/TransactionTracing.cpp",
"Tracing/TransactionProtoParser.cpp",
"TransactionCallbackInvoker.cpp",
"TunnelModeEnabledReporter.cpp",
diff --git a/services/surfaceflinger/BackgroundExecutor.cpp b/services/surfaceflinger/BackgroundExecutor.cpp
index de8e6b3..3663cdb 100644
--- a/services/surfaceflinger/BackgroundExecutor.cpp
+++ b/services/surfaceflinger/BackgroundExecutor.cpp
@@ -32,9 +32,7 @@
std::vector<std::function<void()>> tasks;
{
std::unique_lock lock(mMutex);
- android::base::ScopedLockAssertion assumeLock(mMutex);
- mWorkAvailableCv.wait(lock,
- [&]() REQUIRES(mMutex) { return mDone || !mTasks.empty(); });
+ mWorkAvailableCv.wait(lock, [&]() { return mDone || !mTasks.empty(); });
tasks = std::move(mTasks);
mTasks.clear();
done = mDone;
@@ -49,7 +47,7 @@
BackgroundExecutor::~BackgroundExecutor() {
{
- std::scoped_lock lock(mMutex);
+ std::unique_lock lock(mMutex);
mDone = true;
mWorkAvailableCv.notify_all();
}
@@ -59,7 +57,7 @@
}
void BackgroundExecutor::execute(std::function<void()> task) {
- std::scoped_lock lock(mMutex);
+ std::unique_lock lock(mMutex);
mTasks.emplace_back(std::move(task));
mWorkAvailableCv.notify_all();
}
diff --git a/services/surfaceflinger/BackgroundExecutor.h b/services/surfaceflinger/BackgroundExecutor.h
index 6db7dda..6f6d305 100644
--- a/services/surfaceflinger/BackgroundExecutor.h
+++ b/services/surfaceflinger/BackgroundExecutor.h
@@ -16,7 +16,6 @@
#pragma once
-#include <android-base/thread_annotations.h>
#include <utils/Singleton.h>
#include <condition_variable>
#include <mutex>
@@ -34,10 +33,10 @@
private:
std::mutex mMutex;
- std::condition_variable mWorkAvailableCv GUARDED_BY(mMutex);
- bool mDone GUARDED_BY(mMutex) = false;
- std::vector<std::function<void()>> mTasks GUARDED_BY(mMutex);
+ std::condition_variable mWorkAvailableCv;
std::thread mThread;
+ bool mDone = false;
+ std::vector<std::function<void()>> mTasks;
};
} // namespace android
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index 490775f..494b61c 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -796,7 +796,7 @@
wp<Layer> tmpTouchableRegionCrop = mDrawingState.touchableRegionCrop;
WindowInfo tmpInputInfo = mDrawingState.inputInfo;
- mDrawingState = clonedFrom->mDrawingState;
+ cloneDrawingState(clonedFrom.get());
mDrawingState.touchableRegionCrop = tmpTouchableRegionCrop;
mDrawingState.zOrderRelativeOf = tmpZOrderRelativeOf;
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index 7d40fc8..2fac880 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -61,7 +61,7 @@
// one of the layers, in this case the original layer, needs to handle the deletion. The
// original layer and the clone should be removed at the same time so there shouldn't be any
// issue with the clone layer trying to use the texture.
- if (mBufferInfo.mBuffer != nullptr && !isClone()) {
+ if (mBufferInfo.mBuffer != nullptr) {
callReleaseBufferCallback(mDrawingState.releaseBufferListener,
mBufferInfo.mBuffer->getBuffer(), mBufferInfo.mFrameNumber,
mBufferInfo.mFence,
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 495d585..dfb99cc 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -2169,6 +2169,8 @@
info.frameRight = 0;
info.frameBottom = 0;
info.transform.reset();
+ info.touchableRegion = Region();
+ info.flags = WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::NOT_FOCUSABLE;
return;
}
@@ -2416,8 +2418,7 @@
}
void Layer::setInitialValuesForClone(const sp<Layer>& clonedFrom) {
- // copy drawing state from cloned layer
- mDrawingState = clonedFrom->mDrawingState;
+ cloneDrawingState(clonedFrom.get());
mClonedFrom = clonedFrom;
}
@@ -2452,7 +2453,7 @@
// since we may be able to pull out other children that are still alive.
if (isClonedFromAlive()) {
sp<Layer> clonedFrom = getClonedFrom();
- mDrawingState = clonedFrom->mDrawingState;
+ cloneDrawingState(clonedFrom.get());
clonedLayersMap.emplace(clonedFrom, this);
}
@@ -2615,6 +2616,13 @@
return true;
}
+void Layer::cloneDrawingState(const Layer* from) {
+ mDrawingState = from->mDrawingState;
+ // Skip callback info since they are not applicable for cloned layers.
+ mDrawingState.releaseBufferListener = nullptr;
+ mDrawingState.callbackHandles = {};
+}
+
// ---------------------------------------------------------------------------
std::ostream& operator<<(std::ostream& stream, const Layer::FrameRate& rate) {
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 47885a4..3f4d48b 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -922,6 +922,7 @@
bool isClone() { return mClonedFrom != nullptr; }
bool isClonedFromAlive() { return getClonedFrom() != nullptr; }
+ void cloneDrawingState(const Layer* from);
void updateClonedDrawingState(std::map<sp<Layer>, sp<Layer>>& clonedLayersMap);
void updateClonedChildren(const sp<Layer>& mirrorRoot,
std::map<sp<Layer>, sp<Layer>>& clonedLayersMap);
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index daf5980..21f3872 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -93,7 +93,6 @@
#include <type_traits>
#include <unordered_map>
-#include "BackgroundExecutor.h"
#include "BufferLayer.h"
#include "BufferQueueLayer.h"
#include "BufferStateLayer.h"
@@ -359,10 +358,11 @@
SurfaceFlinger::SurfaceFlinger(Factory& factory, SkipInitializationTag)
: mFactory(factory),
+ mPid(getpid()),
mInterceptor(mFactory.createSurfaceInterceptor()),
mTimeStats(std::make_shared<impl::TimeStats>()),
mFrameTracer(mFactory.createFrameTracer()),
- mFrameTimeline(mFactory.createFrameTimeline(mTimeStats, getpid())),
+ mFrameTimeline(mFactory.createFrameTimeline(mTimeStats, mPid)),
mCompositionEngine(mFactory.createCompositionEngine()),
mHwcServiceName(base::GetProperty("debug.sf.hwc_service_name"s, "default"s)),
mTunnelModeEnabledReporter(new TunnelModeEnabledReporter()),
@@ -491,6 +491,11 @@
enableSdrDimming = property_get_bool("debug.sf.enable_sdr_dimming", enable_sdr_dimming(false));
enableLatchUnsignaledConfig = getLatchUnsignaledConfig();
+
+ mTransactionTracingEnabled = property_get_bool("debug.sf.enable_transaction_tracing", false);
+ if (mTransactionTracingEnabled) {
+ mTransactionTracing.enable();
+ }
}
LatchUnsignaledConfig SurfaceFlinger::getLatchUnsignaledConfig() {
@@ -510,7 +515,7 @@
mBootFinished = false;
// Sever the link to inputflinger since it's gone as well.
- BackgroundExecutor::getInstance().execute([=] { mInputFlinger = nullptr; });
+ static_cast<void>(mScheduler->schedule([=] { mInputFlinger = nullptr; }));
// restore initial conditions (default device unblank, etc)
initializeDisplays();
@@ -721,15 +726,13 @@
sp<IBinder> input(defaultServiceManager()->getService(String16("inputflinger")));
- BackgroundExecutor::getInstance().execute([=] {
+ static_cast<void>(mScheduler->schedule([=] {
if (input == nullptr) {
ALOGE("Failed to link to input service");
} else {
mInputFlinger = interface_cast<os::IInputFlinger>(input);
}
- });
- static_cast<void>(mScheduler->schedule([=] {
readPersistentProperties();
mPowerAdvisor.onBootFinished();
mBootStage = BootStage::FINISHED;
@@ -1989,7 +1992,7 @@
}
if (mTracingEnabledChanged) {
- mTracingEnabled = mLayerTracing.isEnabled();
+ mLayerTracingEnabled = mLayerTracing.isEnabled();
mTracingEnabledChanged = false;
}
@@ -2007,7 +2010,7 @@
bool needsTraversal = false;
if (clearTransactionFlags(eTransactionFlushNeeded)) {
- needsTraversal = flushTransactionQueues();
+ needsTraversal = flushTransactionQueues(vsyncId);
}
const bool shouldCommit =
@@ -2138,7 +2141,7 @@
modulateVsync(&VsyncModulator::onDisplayRefresh, usedGpuComposition);
mLayersWithQueuedFrames.clear();
- if (mTracingEnabled) {
+ if (mLayerTracingEnabled) {
// This will block and should only be used for debugging.
if (mVisibleRegionsDirty) {
mLayerTracing.notify("visibleRegionsDirty");
@@ -3047,48 +3050,32 @@
void SurfaceFlinger::updateInputFlinger() {
ATRACE_CALL();
- std::vector<WindowInfo> windowInfos;
- std::vector<DisplayInfo> displayInfos;
- bool updateWindowInfo = false;
- if (mVisibleRegionsDirty || mInputInfoChanged) {
- mInputInfoChanged = false;
- updateWindowInfo = true;
- buildWindowInfos(windowInfos, displayInfos);
- }
- if (!updateWindowInfo && mInputWindowCommands.empty()) {
+ if (!mInputFlinger) {
return;
}
- BackgroundExecutor::getInstance().execute([updateWindowInfo,
- windowInfos = std::move(windowInfos),
- displayInfos = std::move(displayInfos),
- inputWindowCommands =
- std::move(mInputWindowCommands),
- this]() {
- ATRACE_NAME("BackgroundExecutor::updateInputFlinger");
- if (!mInputFlinger) {
- return;
- }
- if (updateWindowInfo) {
- mWindowInfosListenerInvoker->windowInfosChanged(windowInfos, displayInfos,
- inputWindowCommands.syncInputWindows);
- } else if (inputWindowCommands.syncInputWindows) {
- // If the caller requested to sync input windows, but there are no
- // changes to input windows, notify immediately.
- windowInfosReported();
- }
- for (const auto& focusRequest : inputWindowCommands.focusRequests) {
- mInputFlinger->setFocusedWindow(focusRequest);
- }
- });
+ if (mVisibleRegionsDirty || mInputInfoChanged) {
+ mInputInfoChanged = false;
+ notifyWindowInfos();
+ } else if (mInputWindowCommands.syncInputWindows) {
+ // If the caller requested to sync input windows, but there are no
+ // changes to input windows, notify immediately.
+ windowInfosReported();
+ }
+
+ for (const auto& focusRequest : mInputWindowCommands.focusRequests) {
+ mInputFlinger->setFocusedWindow(focusRequest);
+ }
mInputWindowCommands.clear();
}
-void SurfaceFlinger::buildWindowInfos(std::vector<WindowInfo>& outWindowInfos,
- std::vector<DisplayInfo>& outDisplayInfos) {
+void SurfaceFlinger::notifyWindowInfos() {
+ std::vector<WindowInfo> windowInfos;
+ std::vector<DisplayInfo> displayInfos;
std::unordered_map<uint32_t /*layerStackId*/,
std::pair<bool /* isSecure */, const ui::Transform>>
inputDisplayDetails;
+
for (const auto& [_, display] : ON_MAIN_THREAD(mDisplays)) {
if (!display->receivesInput()) {
continue;
@@ -3102,7 +3089,7 @@
layerStackId);
continue;
}
- outDisplayInfos.emplace_back(info);
+ displayInfos.emplace_back(info);
}
mDrawingState.traverseInReverseZOrder([&](Layer* layer) {
@@ -3122,8 +3109,10 @@
layer->getDebugName(), layerStackId);
}
- outWindowInfos.push_back(layer->fillInputInfo(displayTransform, isSecure));
+ windowInfos.push_back(layer->fillInputInfo(displayTransform, isSecure));
});
+ mWindowInfosListenerInvoker->windowInfosChanged(windowInfos, displayInfos,
+ mInputWindowCommands.syncInputWindows);
}
void SurfaceFlinger::updateCursorAsync() {
@@ -3441,10 +3430,11 @@
client->attachLayer(handle, lbc);
}
+ int64_t transactionId = (((int64_t)mPid) << 32) | mUniqueTransactionId++;
return setTransactionState(FrameTimelineInfo{}, states, displays, 0 /* flags */, nullptr,
InputWindowCommands{}, -1 /* desiredPresentTime */,
true /* isAutoTimestamp */, {}, false /* hasListenerCallbacks */, {},
- 0 /* Undefined transactionId */);
+ transactionId);
}
uint32_t SurfaceFlinger::getTransactionFlags() const {
@@ -3467,7 +3457,7 @@
return old;
}
-bool SurfaceFlinger::flushTransactionQueues() {
+bool SurfaceFlinger::flushTransactionQueues(int64_t vsyncId) {
// to prevent onHandleDestroyed from being called while the lock is held,
// we must keep a copy of the transactions (specifically the composer
// states) around outside the scope of the lock
@@ -3553,12 +3543,13 @@
ATRACE_INT("TransactionQueue", mTransactionQueue.size());
}
- return applyTransactions(transactions);
+ return applyTransactions(transactions, vsyncId);
}
}
}
-bool SurfaceFlinger::applyTransactions(std::vector<TransactionState>& transactions) {
+bool SurfaceFlinger::applyTransactions(std::vector<TransactionState>& transactions,
+ int64_t vsyncId) {
bool needsTraversal = false;
// Now apply all transactions.
for (const auto& transaction : transactions) {
@@ -3576,6 +3567,10 @@
std::move(transaction.transactionCommittedSignal));
}
}
+
+ if (mTransactionTracingEnabled) {
+ mTransactionTracing.addCommittedTransactions(transactions, vsyncId);
+ }
return needsTraversal;
}
@@ -3829,6 +3824,10 @@
state.traverseStatesWithBuffers([&](const layer_state_t& state) {
mBufferCountTracker.increment(state.surface->localBinder());
});
+
+ if (mTransactionTracingEnabled) {
+ mTransactionTracing.addQueuedTransaction(state);
+ }
queueTransaction(state);
// Check the pending state to make sure the transaction is synchronous.
@@ -4408,6 +4407,16 @@
return result;
}
+ int parentId = -1;
+ // We can safely promote the layer in binder thread because we have a strong reference
+ // to the layer's handle inside this scope or we were passed in a sp reference to the layer.
+ sp<Layer> parentSp = parent.promote();
+ if (parentSp != nullptr) {
+ parentId = parentSp->getSequence();
+ }
+ mTransactionTracing.onLayerAdded((*outHandle)->localBinder(), layer->sequence, args.name,
+ args.flags, parentId);
+
setTransactionFlags(eTransactionNeeded);
*outLayerId = layer->sequence;
return result;
@@ -4517,10 +4526,12 @@
displays.add(d);
nsecs_t now = systemTime();
+
+ int64_t transactionId = (((int64_t)mPid) << 32) | mUniqueTransactionId++;
// It should be on the main thread, apply it directly.
applyTransactionState(FrameTimelineInfo{}, state, displays, 0, mInputWindowCommands,
/* desiredPresentTime */ now, true, {}, /* postTime */ now, true, false,
- {}, getpid(), getuid(), 0 /* Undefined transactionId */);
+ {}, mPid, getuid(), transactionId);
setPowerModeInternal(display, hal::PowerMode::ON);
const nsecs_t vsyncPeriod =
@@ -4719,8 +4730,9 @@
}
status_t SurfaceFlinger::dumpCritical(int fd, const DumpArgs&, bool asProto) {
- if (asProto && mLayerTracing.isEnabled()) {
+ if (asProto) {
mLayerTracing.writeToFile();
+ mTransactionTracing.writeToFile();
}
return doDump(fd, DumpArgs(), asProto);
@@ -4917,7 +4929,6 @@
}
LayersProto SurfaceFlinger::dumpDrawingStateProto(uint32_t traceFlags) const {
- // If context is SurfaceTracing thread, mTracingLock blocks display transactions on main thread.
const auto display = ON_MAIN_THREAD(getDefaultDisplayDeviceLocked());
LayersProto layersProto;
@@ -5118,6 +5129,8 @@
*/
mLayerTracing.dump(result);
result.append("\n");
+ mTransactionTracing.dump(result);
+ result.append("\n");
/*
* HWC layer minidump
@@ -5350,9 +5363,9 @@
code == IBinder::SYSPROPS_TRANSACTION) {
return OK;
}
- // Numbers from 1000 to 1040 are currently used for backdoors. The code
+ // Numbers from 1000 to 1041 are currently used for backdoors. The code
// in onTransact verifies that the user is root, and has access to use SF.
- if (code >= 1000 && code <= 1040) {
+ if (code >= 1000 && code <= 1041) {
ALOGV("Accessing SurfaceFlinger through backdoor code: %u", code);
return OK;
}
@@ -5791,6 +5804,20 @@
scheduleRepaint();
return NO_ERROR;
}
+ case 1041: { // Transaction tracing
+ if (data.readInt32()) {
+ // Transaction tracing is always running but allow the user to temporarily
+ // increase the buffer when actively debugging.
+ mTransactionTracing.setBufferSize(
+ TransactionTracing::ACTIVE_TRACING_BUFFER_SIZE);
+ } else {
+ mTransactionTracing.setBufferSize(
+ TransactionTracing::CONTINUOUS_TRACING_BUFFER_SIZE);
+ mTransactionTracing.writeToFile();
+ }
+ reply->writeInt32(NO_ERROR);
+ return NO_ERROR;
+ }
}
}
return err;
@@ -6625,6 +6652,7 @@
if (!layer->isRemovedFromCurrentState()) {
mScheduler->deregisterLayer(layer);
}
+ mTransactionTracing.onLayerRemoved(layer->getSequence());
}
void SurfaceFlinger::onLayerUpdate() {
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 7355130..9794639 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -64,6 +64,7 @@
#include "SurfaceFlingerFactory.h"
#include "TracedOrdinal.h"
#include "Tracing/LayerTracing.h"
+#include "Tracing/TransactionTracing.h"
#include "TransactionCallbackInvoker.h"
#include "TransactionState.h"
@@ -689,8 +690,7 @@
void updateLayerGeometry();
void updateInputFlinger();
- void buildWindowInfos(std::vector<gui::WindowInfo>& outWindowInfos,
- std::vector<gui::DisplayInfo>& outDisplayInfos);
+ void notifyWindowInfos();
void commitInputWindowCommands() REQUIRES(mStateLock);
void updateCursorAsync();
@@ -712,7 +712,7 @@
int originPid, int originUid, uint64_t transactionId)
REQUIRES(mStateLock);
// flush pending transaction that was presented after desiredPresentTime.
- bool flushTransactionQueues();
+ bool flushTransactionQueues(int64_t vsyncId);
// Returns true if there is at least one transaction that needs to be flushed
bool transactionFlushNeeded();
@@ -748,7 +748,8 @@
bool allowedLatchUnsignaled() REQUIRES(mQueueLock, mStateLock);
bool checkTransactionCanLatchUnsignaled(const TransactionState& transaction)
REQUIRES(mStateLock);
- bool applyTransactions(std::vector<TransactionState>& transactions) REQUIRES(mStateLock);
+ bool applyTransactions(std::vector<TransactionState>& transactions, int64_t vsyncId)
+ REQUIRES(mStateLock);
uint32_t setDisplayStateLocked(const DisplayState& s) REQUIRES(mStateLock);
uint32_t addInputWindowCommands(const InputWindowCommands& inputWindowCommands)
REQUIRES(mStateLock);
@@ -1083,7 +1084,7 @@
sp<StartPropertySetThread> mStartPropertySetThread;
surfaceflinger::Factory& mFactory;
-
+ pid_t mPid;
std::future<void> mRenderEnginePrimeCacheFuture;
// access must be protected by mStateLock
@@ -1092,6 +1093,7 @@
std::atomic<int32_t> mTransactionFlags = 0;
std::vector<std::shared_ptr<CountDownLatch>> mTransactionCommittedSignals;
bool mAnimTransactionPending = false;
+ std::atomic<uint32_t> mUniqueTransactionId = 1;
SortedVector<sp<Layer>> mLayersPendingRemoval;
// global color transform states
@@ -1182,8 +1184,10 @@
sp<SurfaceInterceptor> mInterceptor;
LayerTracing mLayerTracing{*this};
- std::mutex mTracingLock;
- bool mTracingEnabled = false;
+ bool mLayerTracingEnabled = false;
+
+ TransactionTracing mTransactionTracing;
+ bool mTransactionTracingEnabled = false;
std::atomic<bool> mTracingEnabledChanged = false;
const std::shared_ptr<TimeStats> mTimeStats;
@@ -1290,7 +1294,6 @@
const float mInternalDisplayDensity;
const float mEmulatedDisplayDensity;
- // Should only be accessed by BackgroundExecutor thread.
sp<os::IInputFlinger> mInputFlinger;
// Should only be accessed by the main thread.
InputWindowCommands mInputWindowCommands;
diff --git a/services/surfaceflinger/Tracing/LayerTracing.cpp b/services/surfaceflinger/Tracing/LayerTracing.cpp
index 84890ee..d136e0b 100644
--- a/services/surfaceflinger/Tracing/LayerTracing.cpp
+++ b/services/surfaceflinger/Tracing/LayerTracing.cpp
@@ -53,6 +53,7 @@
mEnabled = false;
LayersTraceFileProto fileProto = createTraceFileProto();
mBuffer->writeToFile(fileProto, FILE_NAME);
+ mBuffer->reset();
return true;
}
diff --git a/services/surfaceflinger/Tracing/RingBuffer.h b/services/surfaceflinger/Tracing/RingBuffer.h
index d0fb3f2..281cd19 100644
--- a/services/surfaceflinger/Tracing/RingBuffer.h
+++ b/services/surfaceflinger/Tracing/RingBuffer.h
@@ -21,8 +21,9 @@
#include <log/log.h>
#include <utils/Errors.h>
-#include <utils/SystemClock.h>
+#include <utils/Timers.h>
#include <utils/Trace.h>
+#include <chrono>
#include <queue>
namespace android {
@@ -38,27 +39,27 @@
void setSize(size_t newSize) { mSizeInBytes = newSize; }
EntryProto& front() { return mStorage.front(); }
const EntryProto& front() const { return mStorage.front(); }
+ const EntryProto& back() const { return mStorage.back(); }
- void reset(size_t newSize) {
+ void reset() {
// use the swap trick to make sure memory is released
- std::queue<EntryProto>().swap(mStorage);
- mSizeInBytes = newSize;
+ std::deque<EntryProto>().swap(mStorage);
mUsedInBytes = 0U;
}
- void flush(FileProto& fileProto) {
- fileProto.mutable_entry()->Reserve(static_cast<int>(mStorage.size()));
- while (!mStorage.empty()) {
- auto entry = fileProto.add_entry();
- entry->Swap(&mStorage.front());
- mStorage.pop();
+
+ void writeToProto(FileProto& fileProto) {
+ fileProto.mutable_entry()->Reserve(static_cast<int>(mStorage.size()) +
+ fileProto.entry().size());
+ for (const EntryProto& entry : mStorage) {
+ EntryProto* entryProto = fileProto.add_entry();
+ *entryProto = entry;
}
}
status_t writeToFile(FileProto& fileProto, std::string filename) {
ATRACE_CALL();
+ writeToProto(fileProto);
std::string output;
- flush(fileProto);
- reset(mSizeInBytes);
if (!fileProto.SerializeToString(&output)) {
ALOGE("Could not serialize proto.");
return UNKNOWN_ERROR;
@@ -82,10 +83,10 @@
}
mUsedInBytes -= static_cast<size_t>(mStorage.front().ByteSize());
replacedEntries.emplace_back(mStorage.front());
- mStorage.pop();
+ mStorage.pop_front();
}
mUsedInBytes += protoSize;
- mStorage.emplace();
+ mStorage.emplace_back();
mStorage.back().Swap(&proto);
return replacedEntries;
}
@@ -99,14 +100,14 @@
const int64_t durationCount = duration.count();
base::StringAppendF(&result,
" number of entries: %zu (%.2fMB / %.2fMB) duration: %" PRIi64 "ms\n",
- frameCount(), float(used()) / 1024.f * 1024.f,
- float(size()) / 1024.f * 1024.f, durationCount);
+ frameCount(), float(used()) / (1024.f * 1024.f),
+ float(size()) / (1024.f * 1024.f), durationCount);
}
private:
size_t mUsedInBytes = 0U;
size_t mSizeInBytes = 0U;
- std::queue<EntryProto> mStorage;
+ std::deque<EntryProto> mStorage;
};
} // namespace android
diff --git a/services/surfaceflinger/Tracing/TransactionProtoParser.cpp b/services/surfaceflinger/Tracing/TransactionProtoParser.cpp
index d1dc076..7e12313 100644
--- a/services/surfaceflinger/Tracing/TransactionProtoParser.cpp
+++ b/services/surfaceflinger/Tracing/TransactionProtoParser.cpp
@@ -43,7 +43,7 @@
}
proto::TransactionState TransactionProtoParser::toProto(
- std::vector<std::pair<int32_t /* layerId */, TracingLayerState>> states) {
+ const std::unordered_map<int32_t /* layerId */, TracingLayerState> states) {
proto::TransactionState proto;
for (auto& [layerId, state] : states) {
proto::LayerState layerProto = toProto(state, nullptr);
diff --git a/services/surfaceflinger/Tracing/TransactionProtoParser.h b/services/surfaceflinger/Tracing/TransactionProtoParser.h
index e8a139f..619ee05 100644
--- a/services/surfaceflinger/Tracing/TransactionProtoParser.h
+++ b/services/surfaceflinger/Tracing/TransactionProtoParser.h
@@ -51,7 +51,7 @@
static proto::TransactionState toProto(const TransactionState&, LayerHandleToIdFn getLayerIdFn,
DisplayHandleToIdFn getDisplayIdFn);
static proto::TransactionState toProto(
- std::vector<std::pair<int32_t /* layerId */, TracingLayerState>>);
+ const std::unordered_map<int32_t /* layerId */, TracingLayerState>);
static proto::LayerCreationArgs toProto(const TracingLayerCreationArgs& args);
diff --git a/services/surfaceflinger/Tracing/TransactionTracing.cpp b/services/surfaceflinger/Tracing/TransactionTracing.cpp
new file mode 100644
index 0000000..cf488c2
--- /dev/null
+++ b/services/surfaceflinger/Tracing/TransactionTracing.cpp
@@ -0,0 +1,329 @@
+/*
+ * Copyright 2021 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 "TransactionTracing"
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
+#include <android-base/stringprintf.h>
+#include <log/log.h>
+#include <utils/SystemClock.h>
+#include <utils/Trace.h>
+
+#include "RingBuffer.h"
+#include "TransactionTracing.h"
+
+namespace android {
+
+TransactionTracing::TransactionTracing() {
+ mBuffer = std::make_unique<
+ RingBuffer<proto::TransactionTraceFile, proto::TransactionTraceEntry>>();
+}
+
+TransactionTracing::~TransactionTracing() = default;
+
+bool TransactionTracing::enable() {
+ std::scoped_lock lock(mTraceLock);
+ if (mEnabled) {
+ return false;
+ }
+ mBuffer->setSize(mBufferSizeInBytes);
+ mStartingTimestamp = systemTime();
+ mEnabled = true;
+ {
+ std::scoped_lock lock(mMainThreadLock);
+ mDone = false;
+ mThread = std::thread(&TransactionTracing::loop, this);
+ }
+ return true;
+}
+
+bool TransactionTracing::disable() {
+ std::thread thread;
+ {
+ std::scoped_lock lock(mMainThreadLock);
+ mDone = true;
+ mTransactionsAvailableCv.notify_all();
+ thread = std::move(mThread);
+ }
+ if (thread.joinable()) {
+ thread.join();
+ }
+
+ std::scoped_lock lock(mTraceLock);
+ if (!mEnabled) {
+ return false;
+ }
+ mEnabled = false;
+
+ writeToFileLocked();
+ mBuffer->reset();
+ mQueuedTransactions.clear();
+ mStartingStates.clear();
+ mLayerHandles.clear();
+ return true;
+}
+
+bool TransactionTracing::isEnabled() const {
+ std::scoped_lock lock(mTraceLock);
+ return mEnabled;
+}
+
+status_t TransactionTracing::writeToFile() {
+ std::scoped_lock lock(mTraceLock);
+ if (!mEnabled) {
+ return STATUS_OK;
+ }
+ return writeToFileLocked();
+}
+
+status_t TransactionTracing::writeToFileLocked() {
+ proto::TransactionTraceFile fileProto = createTraceFileProto();
+ addStartingStateToProtoLocked(fileProto);
+ return mBuffer->writeToFile(fileProto, FILE_NAME);
+}
+
+void TransactionTracing::setBufferSize(size_t bufferSizeInBytes) {
+ std::scoped_lock lock(mTraceLock);
+ mBufferSizeInBytes = bufferSizeInBytes;
+ mBuffer->setSize(mBufferSizeInBytes);
+}
+
+proto::TransactionTraceFile TransactionTracing::createTraceFileProto() const {
+ proto::TransactionTraceFile proto;
+ proto.set_magic_number(uint64_t(proto::TransactionTraceFile_MagicNumber_MAGIC_NUMBER_H) << 32 |
+ proto::TransactionTraceFile_MagicNumber_MAGIC_NUMBER_L);
+ return proto;
+}
+
+void TransactionTracing::dump(std::string& result) const {
+ std::scoped_lock lock(mTraceLock);
+ base::StringAppendF(&result, "Transaction tracing state: %s\n",
+ mEnabled ? "enabled" : "disabled");
+ base::StringAppendF(&result,
+ " queued transactions=%zu created layers=%zu handles=%zu states=%zu\n",
+ mQueuedTransactions.size(), mCreatedLayers.size(), mLayerHandles.size(),
+ mStartingStates.size());
+ mBuffer->dump(result);
+}
+
+void TransactionTracing::addQueuedTransaction(const TransactionState& transaction) {
+ std::scoped_lock lock(mTraceLock);
+ ATRACE_CALL();
+ if (!mEnabled) {
+ return;
+ }
+ mQueuedTransactions[transaction.id] =
+ TransactionProtoParser::toProto(transaction,
+ std::bind(&TransactionTracing::getLayerIdLocked, this,
+ std::placeholders::_1),
+ nullptr);
+}
+
+void TransactionTracing::addCommittedTransactions(std::vector<TransactionState>& transactions,
+ int64_t vsyncId) {
+ CommittedTransactions committedTransactions;
+ committedTransactions.vsyncId = vsyncId;
+ committedTransactions.timestamp = systemTime();
+ committedTransactions.transactionIds.reserve(transactions.size());
+ for (const auto& transaction : transactions) {
+ committedTransactions.transactionIds.emplace_back(transaction.id);
+ }
+
+ mPendingTransactions.emplace_back(committedTransactions);
+ tryPushToTracingThread();
+}
+
+void TransactionTracing::loop() {
+ while (true) {
+ std::vector<CommittedTransactions> committedTransactions;
+ std::vector<int32_t> removedLayers;
+ {
+ std::unique_lock<std::mutex> lock(mMainThreadLock);
+ base::ScopedLockAssertion assumeLocked(mMainThreadLock);
+ mTransactionsAvailableCv.wait(lock, [&]() REQUIRES(mMainThreadLock) {
+ return mDone || !mCommittedTransactions.empty();
+ });
+ if (mDone) {
+ mCommittedTransactions.clear();
+ mRemovedLayers.clear();
+ break;
+ }
+
+ removedLayers = std::move(mRemovedLayers);
+ mRemovedLayers.clear();
+ committedTransactions = std::move(mCommittedTransactions);
+ mCommittedTransactions.clear();
+ } // unlock mMainThreadLock
+
+ addEntry(committedTransactions, removedLayers);
+ }
+}
+
+void TransactionTracing::addEntry(const std::vector<CommittedTransactions>& committedTransactions,
+ const std::vector<int32_t>& removedLayers) {
+ ATRACE_CALL();
+ std::scoped_lock lock(mTraceLock);
+ std::vector<proto::TransactionTraceEntry> removedEntries;
+ for (const CommittedTransactions& entry : committedTransactions) {
+ proto::TransactionTraceEntry entryProto;
+ entryProto.set_elapsed_realtime_nanos(entry.timestamp);
+ entryProto.set_vsync_id(entry.vsyncId);
+ entryProto.mutable_added_layers()->Reserve(static_cast<int32_t>(mCreatedLayers.size()));
+ for (auto& newLayer : mCreatedLayers) {
+ entryProto.mutable_added_layers()->Add(std::move(newLayer));
+ }
+ entryProto.mutable_removed_layers()->Reserve(static_cast<int32_t>(removedLayers.size()));
+ for (auto& removedLayer : removedLayers) {
+ entryProto.mutable_removed_layers()->Add(removedLayer);
+ }
+ mCreatedLayers.clear();
+ entryProto.mutable_transactions()->Reserve(
+ static_cast<int32_t>(entry.transactionIds.size()));
+ for (const uint64_t& id : entry.transactionIds) {
+ auto it = mQueuedTransactions.find(id);
+ if (it != mQueuedTransactions.end()) {
+ entryProto.mutable_transactions()->Add(std::move(it->second));
+ mQueuedTransactions.erase(it);
+ } else {
+ ALOGE("Could not find transaction id %" PRIu64, id);
+ }
+ }
+ std::vector<proto::TransactionTraceEntry> entries = mBuffer->emplace(std::move(entryProto));
+ removedEntries.insert(removedEntries.end(), std::make_move_iterator(entries.begin()),
+ std::make_move_iterator(entries.end()));
+ }
+
+ for (const proto::TransactionTraceEntry& removedEntry : removedEntries) {
+ updateStartingStateLocked(removedEntry);
+ }
+ mTransactionsAddedToBufferCv.notify_one();
+}
+
+void TransactionTracing::flush(int64_t vsyncId) {
+ while (!mPendingTransactions.empty() || !mPendingRemovedLayers.empty()) {
+ tryPushToTracingThread();
+ }
+ std::unique_lock<std::mutex> lock(mTraceLock);
+ base::ScopedLockAssertion assumeLocked(mTraceLock);
+ mTransactionsAddedToBufferCv.wait(lock, [&]() REQUIRES(mTraceLock) {
+ return mBuffer->used() > 0 && mBuffer->back().vsync_id() >= vsyncId;
+ });
+}
+
+void TransactionTracing::onLayerAdded(BBinder* layerHandle, int layerId, const std::string& name,
+ uint32_t flags, int parentId) {
+ std::scoped_lock lock(mTraceLock);
+ TracingLayerCreationArgs args{layerId, name, flags, parentId};
+ mLayerHandles[layerHandle] = layerId;
+ mCreatedLayers.emplace_back(TransactionProtoParser::toProto(args));
+}
+
+void TransactionTracing::onLayerRemoved(int32_t layerId) {
+ mPendingRemovedLayers.emplace_back(layerId);
+ tryPushToTracingThread();
+}
+
+void TransactionTracing::tryPushToTracingThread() {
+ // Try to acquire the lock from main thread.
+ if (mMainThreadLock.try_lock()) {
+ // We got the lock! Collect any pending transactions and continue.
+ mCommittedTransactions.insert(mCommittedTransactions.end(),
+ std::make_move_iterator(mPendingTransactions.begin()),
+ std::make_move_iterator(mPendingTransactions.end()));
+ mPendingTransactions.clear();
+ mRemovedLayers.insert(mRemovedLayers.end(), mPendingRemovedLayers.begin(),
+ mPendingRemovedLayers.end());
+ mPendingRemovedLayers.clear();
+ mTransactionsAvailableCv.notify_one();
+ mMainThreadLock.unlock();
+ } else {
+ ALOGV("Couldn't get lock");
+ }
+}
+
+int32_t TransactionTracing::getLayerIdLocked(const sp<IBinder>& layerHandle) {
+ if (layerHandle == nullptr) {
+ return -1;
+ }
+ auto it = mLayerHandles.find(layerHandle->localBinder());
+ return it == mLayerHandles.end() ? -1 : it->second;
+}
+
+void TransactionTracing::updateStartingStateLocked(
+ const proto::TransactionTraceEntry& removedEntry) {
+ // Keep track of layer starting state so we can reconstruct the layer state as we purge
+ // transactions from the buffer.
+ for (const proto::LayerCreationArgs& addedLayer : removedEntry.added_layers()) {
+ TracingLayerState& startingState = mStartingStates[addedLayer.layer_id()];
+ startingState.layerId = addedLayer.layer_id();
+ startingState.name = addedLayer.name();
+ startingState.layerCreationFlags = addedLayer.flags();
+ startingState.parentId = addedLayer.parent_id();
+ }
+
+ // Merge layer states to starting transaction state.
+ for (const proto::TransactionState& transaction : removedEntry.transactions()) {
+ for (const proto::LayerState& layerState : transaction.layer_changes()) {
+ auto it = mStartingStates.find(layerState.layer_id());
+ if (it == mStartingStates.end()) {
+ ALOGE("Could not find layer id %d", layerState.layer_id());
+ continue;
+ }
+ TransactionProtoParser::fromProto(layerState, nullptr, it->second);
+ }
+ }
+
+ // Clean up stale starting states since the layer has been removed and the buffer does not
+ // contain any references to the layer.
+ for (const int32_t removedLayerId : removedEntry.removed_layers()) {
+ auto it = std::find_if(mLayerHandles.begin(), mLayerHandles.end(),
+ [removedLayerId](auto& layer) {
+ return layer.second == removedLayerId;
+ });
+ if (it != mLayerHandles.end()) {
+ mLayerHandles.erase(it);
+ }
+ mStartingStates.erase(removedLayerId);
+ }
+}
+
+void TransactionTracing::addStartingStateToProtoLocked(proto::TransactionTraceFile& proto) {
+ proto::TransactionTraceEntry* entryProto = proto.add_entry();
+ entryProto->set_elapsed_realtime_nanos(mStartingTimestamp);
+ entryProto->set_vsync_id(0);
+ entryProto->mutable_added_layers()->Reserve(static_cast<int32_t>(mStartingStates.size()));
+ for (auto& [layerId, state] : mStartingStates) {
+ TracingLayerCreationArgs args{layerId, state.name, state.layerCreationFlags,
+ state.parentId};
+ entryProto->mutable_added_layers()->Add(TransactionProtoParser::toProto(args));
+ }
+
+ proto::TransactionState transactionProto = TransactionProtoParser::toProto(mStartingStates);
+ transactionProto.set_vsync_id(0);
+ transactionProto.set_post_time(mStartingTimestamp);
+ entryProto->mutable_transactions()->Add(std::move(transactionProto));
+}
+
+proto::TransactionTraceFile TransactionTracing::writeToProto() {
+ std::scoped_lock<std::mutex> lock(mTraceLock);
+ proto::TransactionTraceFile proto = createTraceFileProto();
+ addStartingStateToProtoLocked(proto);
+ mBuffer->writeToProto(proto);
+ return proto;
+}
+
+} // namespace android
diff --git a/services/surfaceflinger/Tracing/TransactionTracing.h b/services/surfaceflinger/Tracing/TransactionTracing.h
new file mode 100644
index 0000000..0aa22ed
--- /dev/null
+++ b/services/surfaceflinger/Tracing/TransactionTracing.h
@@ -0,0 +1,126 @@
+/*
+ * Copyright 2021 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 <layerproto/TransactionProto.h>
+#include <utils/Errors.h>
+#include <utils/Timers.h>
+
+#include <memory>
+#include <mutex>
+#include <thread>
+
+#include "TransactionProtoParser.h"
+
+using namespace android::surfaceflinger;
+
+namespace android {
+
+template <typename FileProto, typename EntryProto>
+class RingBuffer;
+
+class SurfaceFlinger;
+class TransactionTracingTest;
+/*
+ * Records all committed transactions into a ring bufffer.
+ *
+ * Transactions come in via the binder thread. They are serialized to proto
+ * and stored in a map using the transaction id as key. Main thread will
+ * pass the list of transaction ids that are committed every vsync and notify
+ * the tracing thread. The tracing thread will then wake up and add the
+ * committed transactions to the ring buffer.
+ *
+ * When generating SF dump state, we will flush the buffer to a file which
+ * will then be included in the bugreport.
+ *
+ */
+class TransactionTracing {
+public:
+ TransactionTracing();
+ ~TransactionTracing();
+
+ bool enable();
+ bool disable();
+ bool isEnabled() const;
+
+ void addQueuedTransaction(const TransactionState&);
+ void addCommittedTransactions(std::vector<TransactionState>& transactions, int64_t vsyncId);
+ status_t writeToFile();
+ void setBufferSize(size_t bufferSizeInBytes);
+ void onLayerAdded(BBinder* layerHandle, int layerId, const std::string& name, uint32_t flags,
+ int parentId);
+ void onLayerRemoved(int layerId);
+ void dump(std::string&) const;
+ static constexpr auto CONTINUOUS_TRACING_BUFFER_SIZE = 512 * 1024;
+ static constexpr auto ACTIVE_TRACING_BUFFER_SIZE = 100 * 1024 * 1024;
+
+private:
+ friend class TransactionTracingTest;
+
+ static constexpr auto FILE_NAME = "/data/misc/wmtrace/transactions_trace.winscope";
+
+ mutable std::mutex mTraceLock;
+ bool mEnabled GUARDED_BY(mTraceLock) = false;
+ std::unique_ptr<RingBuffer<proto::TransactionTraceFile, proto::TransactionTraceEntry>> mBuffer
+ GUARDED_BY(mTraceLock);
+ size_t mBufferSizeInBytes GUARDED_BY(mTraceLock) = CONTINUOUS_TRACING_BUFFER_SIZE;
+ std::unordered_map<uint64_t, proto::TransactionState> mQueuedTransactions
+ GUARDED_BY(mTraceLock);
+ nsecs_t mStartingTimestamp GUARDED_BY(mTraceLock);
+ std::vector<proto::LayerCreationArgs> mCreatedLayers GUARDED_BY(mTraceLock);
+ std::unordered_map<BBinder* /* layerHandle */, int32_t /* layerId */> mLayerHandles
+ GUARDED_BY(mTraceLock);
+ std::unordered_map<int32_t /* layerId */, TracingLayerState> mStartingStates
+ GUARDED_BY(mTraceLock);
+
+ // We do not want main thread to block so main thread will try to acquire mMainThreadLock,
+ // otherwise will push data to temporary container.
+ std::mutex mMainThreadLock;
+ std::thread mThread GUARDED_BY(mMainThreadLock);
+ bool mDone GUARDED_BY(mMainThreadLock) = false;
+ std::condition_variable mTransactionsAvailableCv;
+ std::condition_variable mTransactionsAddedToBufferCv;
+ struct CommittedTransactions {
+ std::vector<uint64_t> transactionIds;
+ int64_t vsyncId;
+ int64_t timestamp;
+ };
+ std::vector<CommittedTransactions> mCommittedTransactions GUARDED_BY(mMainThreadLock);
+ std::vector<CommittedTransactions> mPendingTransactions; // only accessed by main thread
+
+ std::vector<int32_t /* layerId */> mRemovedLayers GUARDED_BY(mMainThreadLock);
+ std::vector<int32_t /* layerId */> mPendingRemovedLayers; // only accessed by main thread
+
+ proto::TransactionTraceFile createTraceFileProto() const;
+ void loop();
+ void addEntry(const std::vector<CommittedTransactions>& committedTransactions,
+ const std::vector<int32_t>& removedLayers) EXCLUDES(mTraceLock);
+ int32_t getLayerIdLocked(const sp<IBinder>& layerHandle) REQUIRES(mTraceLock);
+ void tryPushToTracingThread() EXCLUDES(mMainThreadLock);
+ void addStartingStateToProtoLocked(proto::TransactionTraceFile& proto) REQUIRES(mTraceLock);
+ void updateStartingStateLocked(const proto::TransactionTraceEntry& entry) REQUIRES(mTraceLock);
+ status_t writeToFileLocked() REQUIRES(mTraceLock);
+
+ // TEST
+ // Wait until all the committed transactions for the specified vsync id are added to the buffer.
+ void flush(int64_t vsyncId) EXCLUDES(mMainThreadLock);
+ // Return buffer contents as trace file proto
+ proto::TransactionTraceFile writeToProto() EXCLUDES(mMainThreadLock);
+};
+
+} // namespace android
diff --git a/services/surfaceflinger/layerproto/transactions.proto b/services/surfaceflinger/layerproto/transactions.proto
index edeacfa..10222cc 100644
--- a/services/surfaceflinger/layerproto/transactions.proto
+++ b/services/surfaceflinger/layerproto/transactions.proto
@@ -42,8 +42,10 @@
int64 elapsed_realtime_nanos = 1;
int64 vsync_id = 2;
repeated TransactionState transactions = 3;
- repeated LayerCreationArgs new_layers = 4;
- repeated DisplayState new_displays = 5;
+ repeated LayerCreationArgs added_layers = 4;
+ repeated int32 removed_layers = 5;
+ repeated DisplayState added_displays = 6;
+ repeated int32 removed_displays = 7;
}
message LayerCreationArgs {
diff --git a/services/surfaceflinger/tests/WindowInfosListener_test.cpp b/services/surfaceflinger/tests/WindowInfosListener_test.cpp
index 0069111..bb52245 100644
--- a/services/surfaceflinger/tests/WindowInfosListener_test.cpp
+++ b/services/surfaceflinger/tests/WindowInfosListener_test.cpp
@@ -112,11 +112,12 @@
sp<SurfaceControl> surfaceControl =
mClient->createSurface(String8(name.c_str()), 100, 100, PIXEL_FORMAT_RGBA_8888,
ISurfaceComposerClient::eFXSurfaceBufferState);
-
+ const Rect crop(0, 0, 100, 100);
Transaction()
.setLayerStack(surfaceControl, ui::DEFAULT_LAYER_STACK)
.show(surfaceControl)
.setLayer(surfaceControl, INT32_MAX - 1)
+ .setCrop(surfaceControl, crop)
.setInputWindowInfo(surfaceControl, windowInfo)
.apply();
diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp
index 5f47a1a..561d9e2 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -94,6 +94,7 @@
"TransactionFrameTracerTest.cpp",
"TransactionProtoParserTest.cpp",
"TransactionSurfaceFrameTest.cpp",
+ "TransactionTracingTest.cpp",
"TunnelModeEnabledReporterTest.cpp",
"StrongTypingTest.cpp",
"VSyncDispatchTimerQueueTest.cpp",
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index 7f949b9..100a78d 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -388,7 +388,7 @@
listenerCallbacks, transactionId);
}
- auto flushTransactionQueues() { return mFlinger->flushTransactionQueues(); };
+ auto flushTransactionQueues() { return mFlinger->flushTransactionQueues(0); };
auto onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) {
return mFlinger->onTransact(code, data, reply, flags);
diff --git a/services/surfaceflinger/tests/unittests/TransactionTracingTest.cpp b/services/surfaceflinger/tests/unittests/TransactionTracingTest.cpp
new file mode 100644
index 0000000..ffe5671
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/TransactionTracingTest.cpp
@@ -0,0 +1,291 @@
+/*
+ * Copyright 2021 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 <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include <gui/SurfaceComposerClient.h>
+
+#include "Tracing/RingBuffer.h"
+#include "Tracing/TransactionTracing.h"
+
+using namespace android::surfaceflinger;
+
+namespace android {
+
+class TransactionTracingTest : public testing::Test {
+protected:
+ static constexpr size_t SMALL_BUFFER_SIZE = 1024;
+ std::unique_ptr<android::TransactionTracing> mTracing;
+ void SetUp() override { mTracing = std::make_unique<android::TransactionTracing>(); }
+
+ void TearDown() override {
+ mTracing->disable();
+ mTracing.reset();
+ }
+
+ auto getCommittedTransactions() {
+ std::scoped_lock<std::mutex> lock(mTracing->mMainThreadLock);
+ return mTracing->mCommittedTransactions;
+ }
+
+ auto getQueuedTransactions() {
+ std::scoped_lock<std::mutex> lock(mTracing->mTraceLock);
+ return mTracing->mQueuedTransactions;
+ }
+
+ auto getUsedBufferSize() {
+ std::scoped_lock<std::mutex> lock(mTracing->mTraceLock);
+ return mTracing->mBuffer->used();
+ }
+
+ auto flush(int64_t vsyncId) { return mTracing->flush(vsyncId); }
+
+ auto bufferFront() {
+ std::scoped_lock<std::mutex> lock(mTracing->mTraceLock);
+ return mTracing->mBuffer->front();
+ }
+
+ bool threadIsJoinable() {
+ std::scoped_lock lock(mTracing->mMainThreadLock);
+ return mTracing->mThread.joinable();
+ }
+
+ proto::TransactionTraceFile writeToProto() { return mTracing->writeToProto(); }
+
+ auto getCreatedLayers() {
+ std::scoped_lock<std::mutex> lock(mTracing->mTraceLock);
+ return mTracing->mCreatedLayers;
+ }
+
+ auto getStartingStates() {
+ std::scoped_lock<std::mutex> lock(mTracing->mTraceLock);
+ return mTracing->mStartingStates;
+ }
+
+ void queueAndCommitTransaction(int64_t vsyncId) {
+ TransactionState transaction;
+ transaction.id = static_cast<uint64_t>(vsyncId * 3);
+ transaction.originUid = 1;
+ transaction.originPid = 2;
+ mTracing->addQueuedTransaction(transaction);
+ std::vector<TransactionState> transactions;
+ transactions.emplace_back(transaction);
+ mTracing->addCommittedTransactions(transactions, vsyncId);
+ flush(vsyncId);
+ }
+
+ // Test that we clean up the tracing thread and free any memory allocated.
+ void verifyDisabledTracingState() {
+ EXPECT_FALSE(mTracing->isEnabled());
+ EXPECT_FALSE(threadIsJoinable());
+ EXPECT_EQ(getCommittedTransactions().size(), 0u);
+ EXPECT_EQ(getQueuedTransactions().size(), 0u);
+ EXPECT_EQ(getUsedBufferSize(), 0u);
+ EXPECT_EQ(getStartingStates().size(), 0u);
+ }
+
+ void verifyEntry(const proto::TransactionTraceEntry& actualProto,
+ const std::vector<TransactionState> expectedTransactions,
+ int64_t expectedVsyncId) {
+ EXPECT_EQ(actualProto.vsync_id(), expectedVsyncId);
+ EXPECT_EQ(actualProto.transactions().size(),
+ static_cast<int32_t>(expectedTransactions.size()));
+ for (uint32_t i = 0; i < expectedTransactions.size(); i++) {
+ EXPECT_EQ(actualProto.transactions(static_cast<int32_t>(i)).pid(),
+ expectedTransactions[i].originPid);
+ }
+ }
+};
+
+TEST_F(TransactionTracingTest, enable) {
+ EXPECT_FALSE(mTracing->isEnabled());
+ mTracing->enable();
+ EXPECT_TRUE(mTracing->isEnabled());
+ mTracing->disable();
+ verifyDisabledTracingState();
+}
+
+TEST_F(TransactionTracingTest, addTransactions) {
+ mTracing->enable();
+ std::vector<TransactionState> transactions;
+ transactions.reserve(100);
+ for (uint64_t i = 0; i < 100; i++) {
+ TransactionState transaction;
+ transaction.id = i;
+ transaction.originPid = static_cast<int32_t>(i);
+ transactions.emplace_back(transaction);
+ mTracing->addQueuedTransaction(transaction);
+ }
+
+ // Split incoming transactions into two and commit them in reverse order to test out of order
+ // commits.
+ std::vector<TransactionState> firstTransactionSet =
+ std::vector<TransactionState>(transactions.begin() + 50, transactions.end());
+ int64_t firstTransactionSetVsyncId = 42;
+ mTracing->addCommittedTransactions(firstTransactionSet, firstTransactionSetVsyncId);
+
+ int64_t secondTransactionSetVsyncId = 43;
+ std::vector<TransactionState> secondTransactionSet =
+ std::vector<TransactionState>(transactions.begin(), transactions.begin() + 50);
+ mTracing->addCommittedTransactions(secondTransactionSet, secondTransactionSetVsyncId);
+ flush(secondTransactionSetVsyncId);
+
+ proto::TransactionTraceFile proto = writeToProto();
+ EXPECT_EQ(proto.entry().size(), 3);
+ // skip starting entry
+ verifyEntry(proto.entry(1), firstTransactionSet, firstTransactionSetVsyncId);
+ verifyEntry(proto.entry(2), secondTransactionSet, secondTransactionSetVsyncId);
+
+ mTracing->disable();
+ verifyDisabledTracingState();
+}
+
+class TransactionTracingLayerHandlingTest : public TransactionTracingTest {
+protected:
+ void SetUp() override {
+ TransactionTracingTest::SetUp();
+ mTracing->enable();
+ // add layers
+ mTracing->setBufferSize(SMALL_BUFFER_SIZE);
+ const sp<IBinder> fakeLayerHandle = new BBinder();
+ mTracing->onLayerAdded(fakeLayerHandle->localBinder(), mParentLayerId, "parent",
+ 123 /* flags */, -1 /* parentId */);
+ const sp<IBinder> fakeChildLayerHandle = new BBinder();
+ mTracing->onLayerAdded(fakeChildLayerHandle->localBinder(), 2 /* layerId */, "child",
+ 456 /* flags */, mParentLayerId);
+
+ // add some layer transaction
+ {
+ TransactionState transaction;
+ transaction.id = 50;
+ ComposerState layerState;
+ layerState.state.surface = fakeLayerHandle;
+ layerState.state.what = layer_state_t::eLayerChanged;
+ layerState.state.z = 42;
+ transaction.states.add(layerState);
+ ComposerState childState;
+ childState.state.surface = fakeChildLayerHandle;
+ layerState.state.z = 43;
+ transaction.states.add(childState);
+ mTracing->addQueuedTransaction(transaction);
+
+ std::vector<TransactionState> transactions;
+ transactions.emplace_back(transaction);
+ VSYNC_ID_FIRST_LAYER_CHANGE = ++mVsyncId;
+ mTracing->addCommittedTransactions(transactions, VSYNC_ID_FIRST_LAYER_CHANGE);
+ flush(VSYNC_ID_FIRST_LAYER_CHANGE);
+ }
+
+ // add transactions that modify the layer state further so we can test that layer state
+ // gets merged
+ {
+ TransactionState transaction;
+ transaction.id = 51;
+ ComposerState layerState;
+ layerState.state.surface = fakeLayerHandle;
+ layerState.state.what = layer_state_t::eLayerChanged | layer_state_t::ePositionChanged;
+ layerState.state.z = 41;
+ layerState.state.x = 22;
+ transaction.states.add(layerState);
+ mTracing->addQueuedTransaction(transaction);
+
+ std::vector<TransactionState> transactions;
+ transactions.emplace_back(transaction);
+ VSYNC_ID_SECOND_LAYER_CHANGE = ++mVsyncId;
+ mTracing->addCommittedTransactions(transactions, VSYNC_ID_SECOND_LAYER_CHANGE);
+ flush(VSYNC_ID_SECOND_LAYER_CHANGE);
+ }
+
+ // remove child layer
+ mTracing->onLayerRemoved(2);
+ VSYNC_ID_CHILD_LAYER_REMOVED = ++mVsyncId;
+ queueAndCommitTransaction(VSYNC_ID_CHILD_LAYER_REMOVED);
+
+ // remove layer
+ mTracing->onLayerRemoved(1);
+ queueAndCommitTransaction(++mVsyncId);
+ }
+
+ void TearDown() override {
+ mTracing->disable();
+ verifyDisabledTracingState();
+ TransactionTracingTest::TearDown();
+ }
+
+ int mParentLayerId = 1;
+ int64_t mVsyncId = 0;
+ int64_t VSYNC_ID_FIRST_LAYER_CHANGE;
+ int64_t VSYNC_ID_SECOND_LAYER_CHANGE;
+ int64_t VSYNC_ID_CHILD_LAYER_REMOVED;
+};
+
+TEST_F(TransactionTracingLayerHandlingTest, addStartingState) {
+ // add transactions until we drop the transaction with the first layer change
+ while (bufferFront().vsync_id() <= VSYNC_ID_FIRST_LAYER_CHANGE) {
+ queueAndCommitTransaction(++mVsyncId);
+ }
+ proto::TransactionTraceFile proto = writeToProto();
+ // verify we can still retrieve the layer change from the first entry containing starting
+ // states.
+ EXPECT_GT(proto.entry().size(), 0);
+ EXPECT_GT(proto.entry(0).transactions().size(), 0);
+ EXPECT_GT(proto.entry(0).added_layers().size(), 0);
+ EXPECT_GT(proto.entry(0).transactions(0).layer_changes().size(), 0);
+ EXPECT_EQ(proto.entry(0).transactions(0).layer_changes(0).z(), 42);
+}
+
+TEST_F(TransactionTracingLayerHandlingTest, updateStartingState) {
+ // add transactions until we drop the transaction with the second layer change
+ while (bufferFront().vsync_id() <= VSYNC_ID_SECOND_LAYER_CHANGE) {
+ queueAndCommitTransaction(++mVsyncId);
+ }
+ proto::TransactionTraceFile proto = writeToProto();
+ // verify starting states are updated correctly
+ EXPECT_EQ(proto.entry(0).transactions(0).layer_changes(0).z(), 41);
+}
+
+TEST_F(TransactionTracingLayerHandlingTest, removeStartingState) {
+ // add transactions until we drop the transaction which removes the child layer
+ while (bufferFront().vsync_id() <= VSYNC_ID_CHILD_LAYER_REMOVED) {
+ queueAndCommitTransaction(++mVsyncId);
+ }
+ proto::TransactionTraceFile proto = writeToProto();
+ // verify the child layer has been removed from the trace
+ EXPECT_EQ(proto.entry(0).transactions(0).layer_changes().size(), 1);
+ EXPECT_EQ(proto.entry(0).transactions(0).layer_changes(0).layer_id(), mParentLayerId);
+}
+
+TEST_F(TransactionTracingLayerHandlingTest, startingStateSurvivesBufferFlush) {
+ // add transactions until we drop the transaction with the second layer change
+ while (bufferFront().vsync_id() <= VSYNC_ID_SECOND_LAYER_CHANGE) {
+ queueAndCommitTransaction(++mVsyncId);
+ }
+ proto::TransactionTraceFile proto = writeToProto();
+ // verify we have two starting states
+ EXPECT_EQ(proto.entry(0).transactions(0).layer_changes().size(), 2);
+
+ // Continue adding transactions until child layer is removed
+ while (bufferFront().vsync_id() <= VSYNC_ID_CHILD_LAYER_REMOVED) {
+ queueAndCommitTransaction(++mVsyncId);
+ }
+ proto = writeToProto();
+ // verify we still have the parent layer state
+ EXPECT_EQ(proto.entry(0).transactions(0).layer_changes().size(), 1);
+ EXPECT_EQ(proto.entry(0).transactions(0).layer_changes(0).layer_id(), mParentLayerId);
+}
+
+} // namespace android
diff --git a/vulkan/libvulkan/api.cpp b/vulkan/libvulkan/api.cpp
index d1cd397..fa3b260 100644
--- a/vulkan/libvulkan/api.cpp
+++ b/vulkan/libvulkan/api.cpp
@@ -965,6 +965,13 @@
VkResult result = EnumerateDeviceExtensionProperties(physical_dev, nullptr,
&count, nullptr);
if (result == VK_SUCCESS && count) {
+ // Work-around a race condition during Android start-up, that can result
+ // in the second call to EnumerateDeviceExtensionProperties having
+ // another extension. That causes the second call to return
+ // VK_INCOMPLETE. A work-around is to add 1 to "count" and ask for one
+ // more extension property. See: http://anglebug.com/6715 and
+ // internal-to-Google b/206733351.
+ count++;
driver_extensions_ = AllocateDriverExtensionArray(count);
result = (driver_extensions_)
? EnumerateDeviceExtensionProperties(
diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp
index 54b10b1..b5a0bdf 100644
--- a/vulkan/libvulkan/swapchain.cpp
+++ b/vulkan/libvulkan/swapchain.cpp
@@ -537,30 +537,6 @@
}
}
-int get_min_buffer_count(ANativeWindow* window,
- uint32_t* out_min_buffer_count) {
- constexpr int kExtraBuffers = 2;
-
- int err;
- int min_undequeued_buffers;
- err = window->query(window, NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS,
- &min_undequeued_buffers);
- if (err != android::OK || min_undequeued_buffers < 0) {
- ALOGE(
- "NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS query failed: %s (%d) "
- "value=%d",
- strerror(-err), err, min_undequeued_buffers);
- if (err == android::OK) {
- err = android::UNKNOWN_ERROR;
- }
- return err;
- }
-
- *out_min_buffer_count =
- static_cast<uint32_t>(min_undequeued_buffers + kExtraBuffers);
- return android::OK;
-}
-
} // anonymous namespace
VKAPI_ATTR
@@ -675,7 +651,7 @@
strerror(-err), err);
return VK_ERROR_SURFACE_LOST_KHR;
}
- capabilities->minImageCount = max_buffer_count == 1 ? 1 : 2;
+ capabilities->minImageCount = std::min(max_buffer_count, 3);
capabilities->maxImageCount = static_cast<uint32_t>(max_buffer_count);
capabilities->currentExtent =
@@ -877,13 +853,18 @@
int err;
int query_value;
- uint32_t min_buffer_count;
ANativeWindow* window = SurfaceFromHandle(surface)->window.get();
- err = get_min_buffer_count(window, &min_buffer_count);
- if (err != android::OK) {
+ err = window->query(window, NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS,
+ &query_value);
+ if (err != android::OK || query_value < 0) {
+ ALOGE(
+ "NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS query failed: %s (%d) "
+ "value=%d",
+ strerror(-err), err, query_value);
return VK_ERROR_SURFACE_LOST_KHR;
}
+ uint32_t min_undequeued_buffers = static_cast<uint32_t>(query_value);
err = window->query(window, NATIVE_WINDOW_MAX_BUFFER_COUNT, &query_value);
if (err != android::OK || query_value < 0) {
@@ -894,7 +875,7 @@
uint32_t max_buffer_count = static_cast<uint32_t>(query_value);
std::vector<VkPresentModeKHR> present_modes;
- if (min_buffer_count < max_buffer_count)
+ if (min_undequeued_buffers + 1 < max_buffer_count)
present_modes.push_back(VK_PRESENT_MODE_MAILBOX_KHR);
present_modes.push_back(VK_PRESENT_MODE_FIFO_KHR);
@@ -1215,14 +1196,19 @@
}
}
- uint32_t min_buffer_count;
- err = get_min_buffer_count(window, &min_buffer_count);
- if (err != android::OK) {
+ int query_value;
+ err = window->query(window, NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS,
+ &query_value);
+ if (err != android::OK || query_value < 0) {
+ ALOGE("window->query failed: %s (%d) value=%d", strerror(-err), err,
+ query_value);
return VK_ERROR_SURFACE_LOST_KHR;
}
-
- uint32_t num_images =
- std::max(min_buffer_count, create_info->minImageCount);
+ uint32_t min_undequeued_buffers = static_cast<uint32_t>(query_value);
+ const auto mailbox_num_images = std::max(3u, create_info->minImageCount);
+ const auto requested_images =
+ swap_interval ? create_info->minImageCount : mailbox_num_images;
+ uint32_t num_images = requested_images - 1 + min_undequeued_buffers;
// Lower layer insists that we have at least two buffers. This is wasteful
// and we'd like to relax it in the shared case, but not all the pieces are
@@ -1236,12 +1222,6 @@
return VK_ERROR_SURFACE_LOST_KHR;
}
- // In shared mode the num_images must be one regardless of how many
- // buffers were allocated for the buffer queue.
- if (swapchain_image_usage & VK_SWAPCHAIN_IMAGE_USAGE_SHARED_BIT_ANDROID) {
- num_images = 1;
- }
-
int32_t legacy_usage = 0;
if (dispatch.GetSwapchainGrallocUsage2ANDROID) {
uint64_t consumer_usage, producer_usage;