Merge "blast: adding a buffer doesn't make the frame dirty"
diff --git a/cmds/dumpstate/DumpstateService.cpp b/cmds/dumpstate/DumpstateService.cpp
index bb089e6..768cb4f 100644
--- a/cmds/dumpstate/DumpstateService.cpp
+++ b/cmds/dumpstate/DumpstateService.cpp
@@ -44,17 +44,18 @@
return binder::Status::fromExceptionCode(code, String8(msg.c_str()));
}
-static binder::Status error(uint32_t code, const std::string& msg) {
- MYLOGE("%s (%d) ", msg.c_str(), code);
- return binder::Status::fromServiceSpecificError(code, String8(msg.c_str()));
-}
-
-// Takes ownership of data.
-static void* callAndNotify(void* data) {
+// Creates a bugreport and exits, thus preserving the oneshot nature of the service.
+// Note: takes ownership of data.
+[[noreturn]] static void* dumpstate_thread_main(void* data) {
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;
+ MYLOGD("Finished taking a bugreport. Exiting.\n");
+ exit(0);
+}
+
+[[noreturn]] static void signalErrorAndExit(sp<IDumpstateListener> listener, int error_code) {
+ listener->onError(error_code);
+ exit(0);
}
class DumpstateToken : public BnDumpstateToken {};
@@ -120,6 +121,25 @@
const sp<IDumpstateListener>& listener) {
MYLOGI("startBugreport() with mode: %d\n", bugreport_mode);
+ // 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) {
+ MYLOGE("Error! There is already a bugreport in progress. Returning.");
+ if (listener != nullptr) {
+ listener->onError(IDumpstateListener::BUGREPORT_ERROR_CONCURRENT_BUGREPORTS_FORBIDDEN);
+ }
+ return exception(binder::Status::EX_SERVICE_SPECIFIC,
+ "There is already a bugreport in progress");
+ }
+
+ // From here on, all conditions that indicate we are done with this incoming request should
+ // result in exiting the service to free it up for next invocation.
+ if (listener == nullptr) {
+ MYLOGE("Invalid input: no listener");
+ exit(0);
+ }
+
if (bugreport_mode != Dumpstate::BugreportMode::BUGREPORT_FULL &&
bugreport_mode != Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE &&
bugreport_mode != Dumpstate::BugreportMode::BUGREPORT_REMOTE &&
@@ -127,30 +147,23 @@
bugreport_mode != Dumpstate::BugreportMode::BUGREPORT_TELEPHONY &&
bugreport_mode != Dumpstate::BugreportMode::BUGREPORT_WIFI &&
bugreport_mode != Dumpstate::BugreportMode::BUGREPORT_DEFAULT) {
- return exception(binder::Status::EX_ILLEGAL_ARGUMENT,
- StringPrintf("Invalid bugreport mode: %d", bugreport_mode));
+ MYLOGE("Invalid input: bad bugreport mode: %d", bugreport_mode);
+ signalErrorAndExit(listener, IDumpstateListener::BUGREPORT_ERROR_INVALID_INPUT);
}
if (bugreport_fd.get() == -1 || screenshot_fd.get() == -1) {
- return exception(binder::Status::EX_ILLEGAL_ARGUMENT, "Invalid file descriptor");
+ // TODO(b/111441001): screenshot fd should be optional
+ MYLOGE("Invalid filedescriptor");
+ signalErrorAndExit(listener, IDumpstateListener::BUGREPORT_ERROR_INVALID_INPUT);
}
std::unique_ptr<Dumpstate::DumpOptions> options = std::make_unique<Dumpstate::DumpOptions>();
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;
- }
+ ds_->listener_ = listener;
DumpstateInfo* ds_info = new DumpstateInfo();
ds_info->ds = ds_;
@@ -158,11 +171,12 @@
ds_info->calling_package = calling_package;
pthread_t thread;
- status_t err = pthread_create(&thread, nullptr, callAndNotify, ds_info);
+ status_t err = pthread_create(&thread, nullptr, dumpstate_thread_main, ds_info);
if (err != 0) {
delete ds_info;
ds_info = nullptr;
- return error(err, "Could not create a background thread.");
+ MYLOGE("Could not create a thread");
+ signalErrorAndExit(listener, IDumpstateListener::BUGREPORT_ERROR_RUNTIME_ERROR);
}
return binder::Status::ok();
}
diff --git a/cmds/dumpstate/README.md b/cmds/dumpstate/README.md
index 1bf55e4..c818c05 100644
--- a/cmds/dumpstate/README.md
+++ b/cmds/dumpstate/README.md
@@ -14,7 +14,8 @@
mmm -j frameworks/native/cmds/dumpstate
```
-If you're working on device-specific code, you might need to build them as well. Example:
+If you're working on device-specific code, you might need to build them as well.
+Example:
```
mmm -j frameworks/native/cmds/dumpstate device/acme/secret_device/dumpstate/ hardware/interfaces/dumpstate
@@ -26,17 +27,20 @@
mmm -j frameworks/native/cmds/dumpstate && adb push ${OUT}/system/bin/dumpstate system/bin && adb push ${OUT}/system/lib64/*dumpstate*.so /system/lib64/ && adb shell am bug-report
```
-Make sure that the device is remounted before running the above command.
-* If you're working with `userdebug` variant, you may need to run the following to remount your device:
+Make sure that the device is remounted before running the above command. * If
+you're working with `userdebug` variant, you may need to run the following to
+remount your device:
- ```
+```
adb root && adb remount -R && adb wait-for-device && adb root && adb remount
- ```
-* If you're working with `eng` variant, you may need to run the following to remount your device:
+```
- ```
- adb root && adb remount
- ```
+* If you're working with `eng` variant, you may need to run the following to
+ remount your device:
+
+ ```
+ adb root && adb remount
+ ```
## To build, deploy, and run unit tests
@@ -82,7 +86,6 @@
adb shell setprop dumpstate.version split-dumpsys && adb shell dumpstate -v
```
-
Then to restore the default version:
```
@@ -91,8 +94,9 @@
## Code style and formatting
-Use the style defined at the [Google C++ Style Guide](https://google.github.io/styleguide/cppguide.html)
-and make sure to run the following command prior to `repo upload`:
+Use the style defined at the
+[Google C++ Style Guide](https://google.github.io/styleguide/cppguide.html) and
+make sure to run the following command prior to `repo upload`:
```
git clang-format --style=file HEAD~
diff --git a/cmds/dumpstate/binder/android/os/IDumpstate.aidl b/cmds/dumpstate/binder/android/os/IDumpstate.aidl
index b1005d3..37ff442 100644
--- a/cmds/dumpstate/binder/android/os/IDumpstate.aidl
+++ b/cmds/dumpstate/binder/android/os/IDumpstate.aidl
@@ -36,6 +36,9 @@
IDumpstateToken setListener(@utf8InCpp String name, IDumpstateListener listener,
boolean getSectionDetails);
+ // NOTE: If you add to or change these modes, please also change the corresponding enums
+ // in system server, in BugreportParams.java.
+
// These modes encapsulate a set of run time options for generating bugreports.
// Takes a bugreport without user interference.
const int BUGREPORT_MODE_FULL = 0;
diff --git a/cmds/dumpstate/binder/android/os/IDumpstateListener.aidl b/cmds/dumpstate/binder/android/os/IDumpstateListener.aidl
index 907a67c..42858e0 100644
--- a/cmds/dumpstate/binder/android/os/IDumpstateListener.aidl
+++ b/cmds/dumpstate/binder/android/os/IDumpstateListener.aidl
@@ -19,6 +19,11 @@
/**
* Listener for dumpstate events.
*
+ * <p>When bugreport creation is complete one of {@code onError} or {@code onFinished} is called.
+ *
+ * <p>These methods are synchronous by design in order to make dumpstate's lifecycle simpler
+ * to handle.
+ *
* {@hide}
*/
interface IDumpstateListener {
@@ -27,7 +32,10 @@
*
* @param progress the progress in [0, 100]
*/
- oneway void onProgress(int progress);
+ void onProgress(int progress);
+
+ // NOTE: If you add to or change these error codes, please also change the corresponding enums
+ // in system server, in BugreportManager.java.
/* Options specified are invalid or incompatible */
const int BUGREPORT_ERROR_INVALID_INPUT = 1;
@@ -41,15 +49,18 @@
/* The request to get user consent timed out */
const int BUGREPORT_ERROR_USER_CONSENT_TIMED_OUT = 4;
+ /* There is currently a bugreport running. The caller should try again later. */
+ const int BUGREPORT_ERROR_CONCURRENT_BUGREPORTS_FORBIDDEN = 5;
+
/**
* Called on an error condition with one of the error codes listed above.
*/
- oneway void onError(int errorCode);
+ void onError(int errorCode);
/**
* Called when taking bugreport finishes successfully.
*/
- oneway void onFinished();
+ void onFinished();
// TODO(b/111441001): Remove old methods when not used anymore.
void onProgressUpdated(int progress);
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 61745b5..60a7de2 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -113,6 +113,7 @@
#define LOGPERSIST_DATA_DIR "/data/misc/logd"
#define PROFILE_DATA_DIR_CUR "/data/misc/profiles/cur"
#define PROFILE_DATA_DIR_REF "/data/misc/profiles/ref"
+#define XFRM_STAT_PROC_FILE "/proc/net/xfrm_stat"
#define WLUTIL "/vendor/xbin/wlutil"
#define WMTRACE_DATA_DIR "/data/misc/wmtrace"
@@ -157,7 +158,7 @@
}
static bool CopyFileToFd(const std::string& input_file, int out_fd) {
- MYLOGD("Going to copy bugreport file (%s) to %d\n", ds.path_.c_str(), out_fd);
+ MYLOGD("Going to copy file (%s) to %d\n", input_file.c_str(), out_fd);
// Obtain a handle to the source file.
android::base::unique_fd in_fd(OpenForRead(input_file));
@@ -165,14 +166,14 @@
if (CopyFile(in_fd.get(), out_fd)) {
return true;
}
- MYLOGE("Failed to copy zip file: %s\n", strerror(errno));
+ MYLOGE("Failed to copy file: %s\n", strerror(errno));
}
return false;
}
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));
+ if (unlink(file.c_str())) {
+ MYLOGE("Failed to unlink file (%s): %s\n", file.c_str(), strerror(errno));
return false;
}
return true;
@@ -460,9 +461,7 @@
if (!ds.AddZipEntry("anrd_trace.txt", path)) {
MYLOGE("Unable to add anrd_trace file %s to zip file\n", path);
} else {
- if (remove(path)) {
- MYLOGE("Error removing anrd_trace file %s: %s", path, strerror(errno));
- }
+ android::os::UnlinkAndLogOnError(path);
return true;
}
} else {
@@ -1330,6 +1329,7 @@
DumpFile("BINDER STATS", "/sys/kernel/debug/binder/stats");
DumpFile("BINDER STATE", "/sys/kernel/debug/binder/state");
+ RunDumpsys("WINSCOPE TRACE", {"window", "trace"});
/* Add window and surface trace files. */
if (!PropertiesHelper::IsUserBuild()) {
ds.AddDir(WMTRACE_DATA_DIR, false);
@@ -1455,9 +1455,12 @@
add_mountinfo();
DumpIpTablesAsRoot();
- // Capture any IPSec policies in play. No keys are exposed here.
+ // Capture any IPSec policies in play. No keys are exposed here.
RunCommand("IP XFRM POLICY", {"ip", "xfrm", "policy"}, CommandOptions::WithTimeout(10).Build());
+ // Dump IPsec stats. No keys are exposed here.
+ DumpFile("XFRM STATS", XFRM_STAT_PROC_FILE);
+
// Run ss as root so we can see socket marks.
RunCommand("DETAILED SOCKET STATE", {"ss", "-eionptu"}, CommandOptions::WithTimeout(10).Build());
@@ -1588,13 +1591,8 @@
for (int i = 0; i < NUM_OF_DUMPS; i++) {
paths.emplace_back(StringPrintf("%s/%s", ds.bugreport_internal_dir_.c_str(),
kDumpstateBoardFiles[i].c_str()));
- remover.emplace_back(android::base::make_scope_guard(std::bind(
- [](std::string path) {
- if (remove(path.c_str()) != 0 && errno != ENOENT) {
- MYLOGE("Could not remove(%s): %s\n", path.c_str(), strerror(errno));
- }
- },
- paths[i])));
+ remover.emplace_back(android::base::make_scope_guard(
+ std::bind([](std::string path) { android::os::UnlinkAndLogOnError(path); }, paths[i])));
}
sp<IDumpstateDevice> dumpstate_device(IDumpstateDevice::getService());
@@ -1755,9 +1753,7 @@
ds.zip_file.reset(nullptr);
MYLOGD("Removing temporary file %s\n", tmp_path_.c_str())
- if (remove(tmp_path_.c_str()) != 0) {
- MYLOGE("Failed to remove temporary file (%s): %s\n", tmp_path_.c_str(), strerror(errno));
- }
+ android::os::UnlinkAndLogOnError(tmp_path_);
return true;
}
@@ -2341,6 +2337,7 @@
register_sig_handler();
+ // TODO(b/111441001): maybe skip if already started?
if (options_->do_start_service) {
MYLOGI("Starting 'dumpstate' service\n");
android::status_t ret;
@@ -2487,15 +2484,24 @@
// 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.
+ MYLOGI("User denied consent. Returning\n");
return status;
}
- if (options_->screenshot_fd.get() != -1) {
+ if (options_->do_fb && 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_);
}
}
+ if (status == Dumpstate::RunStatus::USER_CONSENT_TIMED_OUT) {
+ MYLOGI(
+ "Did not receive user consent yet."
+ " Will not copy the bugreport artifacts to caller.\n");
+ // TODO(b/111441001):
+ // 1. cancel outstanding requests
+ // 2. check for result more frequently
+ }
}
/* vibrate a few but shortly times to let user know it's finished */
@@ -2598,21 +2604,26 @@
return Dumpstate::RunStatus::ERROR;
}
-/* Main entry point for dumpstate binary. */
-int run_main(int argc, char* argv[]) {
+Dumpstate::RunStatus Dumpstate::ParseCommandlineAndRun(int argc, char* argv[]) {
std::unique_ptr<Dumpstate::DumpOptions> options = std::make_unique<Dumpstate::DumpOptions>();
Dumpstate::RunStatus status = options->Initialize(argc, argv);
if (status == Dumpstate::RunStatus::OK) {
- ds.SetOptions(std::move(options));
+ SetOptions(std::move(options));
// 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);
+ assert(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 */);
+ status = Run(-1 /* calling_uid */, "" /* calling_package */);
}
+ return status;
+}
+
+/* Main entry point for dumpstate binary. */
+int run_main(int argc, char* argv[]) {
+ Dumpstate::RunStatus status = ds.ParseCommandlineAndRun(argc, argv);
switch (status) {
case Dumpstate::RunStatus::OK:
diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h
index 7fb2f3b..9803f00 100644
--- a/cmds/dumpstate/dumpstate.h
+++ b/cmds/dumpstate/dumpstate.h
@@ -322,6 +322,8 @@
/* Main entry point for running a complete bugreport. */
RunStatus Run(int32_t calling_uid, const std::string& calling_package);
+ RunStatus ParseCommandlineAndRun(int argc, char* argv[]);
+
/* Sets runtime options. */
void SetOptions(std::unique_ptr<DumpOptions> options);
diff --git a/cmds/dumpstate/tests/dumpstate_smoke_test.cpp b/cmds/dumpstate/tests/dumpstate_smoke_test.cpp
index 570c6c9..555badd 100644
--- a/cmds/dumpstate/tests/dumpstate_smoke_test.cpp
+++ b/cmds/dumpstate/tests/dumpstate_smoke_test.cpp
@@ -21,6 +21,10 @@
#include <libgen.h>
#include <android-base/file.h>
+#include <android/os/BnDumpstate.h>
+#include <android/os/BnDumpstateListener.h>
+#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
#include <cutils/properties.h>
#include <ziparchive/zip_archive.h>
@@ -34,6 +38,24 @@
using ::testing::Test;
using ::std::literals::chrono_literals::operator""s;
+using android::base::unique_fd;
+
+class DumpstateListener;
+
+namespace {
+
+sp<IDumpstate> GetDumpstateService() {
+ return android::interface_cast<IDumpstate>(
+ android::defaultServiceManager()->getService(String16("dumpstate")));
+}
+
+int OpenForWrite(const std::string& filename) {
+ return TEMP_FAILURE_RETRY(open(filename.c_str(),
+ O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW,
+ S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH));
+}
+
+} // namespace
struct SectionInfo {
std::string name;
@@ -46,41 +68,71 @@
* Listens to bugreport progress and updates the user by writing the progress to STDOUT. All the
* section details generated by dumpstate are added to a vector to be used by Tests later.
*/
-class DumpstateListener : public IDumpstateListener {
+class DumpstateListener : public BnDumpstateListener {
public:
- int outFd_, max_progress_;
- std::shared_ptr<std::vector<SectionInfo>> sections_;
DumpstateListener(int fd, std::shared_ptr<std::vector<SectionInfo>> sections)
- : outFd_(fd), max_progress_(5000), sections_(sections) {
+ : out_fd_(fd), sections_(sections) {
}
+
+ DumpstateListener(int fd) : out_fd_(fd) {
+ }
+
binder::Status onProgress(int32_t progress) override {
- dprintf(outFd_, "\rIn progress %d", progress);
+ dprintf(out_fd_, "\rIn progress %d", progress);
return binder::Status::ok();
}
+
binder::Status onError(int32_t error_code) override {
- dprintf(outFd_, "\rError %d", error_code);
+ std::lock_guard<std::mutex> lock(lock_);
+ error_code_ = error_code;
+ dprintf(out_fd_, "\rError code %d", error_code);
return binder::Status::ok();
}
+
binder::Status onFinished() override {
- dprintf(outFd_, "\rFinished");
+ std::lock_guard<std::mutex> lock(lock_);
+ is_finished_ = true;
+ dprintf(out_fd_, "\rFinished");
return binder::Status::ok();
}
+
binder::Status onProgressUpdated(int32_t progress) override {
- dprintf(outFd_, "\rIn progress %d/%d", progress, max_progress_);
+ dprintf(out_fd_, "\rIn progress %d/%d", progress, max_progress_);
return binder::Status::ok();
}
+
binder::Status onMaxProgressUpdated(int32_t max_progress) override {
+ std::lock_guard<std::mutex> lock(lock_);
max_progress_ = max_progress;
return binder::Status::ok();
}
+
binder::Status onSectionComplete(const ::std::string& name, int32_t status, int32_t size_bytes,
int32_t duration_ms) override {
- sections_->push_back({name, status, size_bytes, duration_ms});
+ std::lock_guard<std::mutex> lock(lock_);
+ if (sections_.get() != nullptr) {
+ sections_->push_back({name, status, size_bytes, duration_ms});
+ }
return binder::Status::ok();
}
- IBinder* onAsBinder() override {
- return nullptr;
+
+ bool getIsFinished() {
+ std::lock_guard<std::mutex> lock(lock_);
+ return is_finished_;
}
+
+ int getErrorCode() {
+ std::lock_guard<std::mutex> lock(lock_);
+ return error_code_;
+ }
+
+ private:
+ int out_fd_;
+ int max_progress_ = 5000;
+ int error_code_ = -1;
+ bool is_finished_ = false;
+ std::shared_ptr<std::vector<SectionInfo>> sections_;
+ std::mutex lock_;
};
/**
@@ -109,7 +161,7 @@
ds.listener_name_ = "Smokey";
ds.report_section_ = true;
auto start = std::chrono::steady_clock::now();
- run_main(ARRAY_SIZE(argv), argv);
+ ds.ParseCommandlineAndRun(ARRAY_SIZE(argv), argv);
auto end = std::chrono::steady_clock::now();
duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
}
@@ -293,6 +345,148 @@
SectionExists("DUMPSYS - wifi", /* bytes= */ 100000);
}
+class DumpstateBinderTest : public Test {
+ protected:
+ void SetUp() override {
+ // In case there is a stray service, stop it first.
+ property_set("ctl.stop", "bugreportd");
+ // dry_run results in a faster bugreport.
+ property_set("dumpstate.dry_run", "true");
+ // We need to receive some async calls later. Ensure we have binder threads.
+ ProcessState::self()->startThreadPool();
+ }
+
+ void TearDown() override {
+ property_set("ctl.stop", "bugreportd");
+ property_set("dumpstate.dry_run", "");
+
+ unlink("/data/local/tmp/tmp.zip");
+ unlink("/data/local/tmp/tmp.png");
+ }
+
+ // Waits until listener gets the callbacks.
+ void WaitTillExecutionComplete(DumpstateListener* listener) {
+ // Wait till one of finished, error or timeout.
+ static const int kBugreportTimeoutSeconds = 120;
+ int i = 0;
+ while (!listener->getIsFinished() && listener->getErrorCode() == -1 &&
+ i < kBugreportTimeoutSeconds) {
+ sleep(1);
+ i++;
+ }
+ }
+};
+
+TEST_F(DumpstateBinderTest, Baseline) {
+ // In the beginning dumpstate binder service is not running.
+ sp<android::os::IDumpstate> ds_binder(GetDumpstateService());
+ EXPECT_EQ(ds_binder, nullptr);
+
+ // Start bugreportd, which runs dumpstate binary with -w; which starts dumpstate service
+ // and makes it wait.
+ property_set("dumpstate.dry_run", "true");
+ property_set("ctl.start", "bugreportd");
+
+ // Now we are able to retrieve dumpstate binder service.
+ ds_binder = GetDumpstateService();
+ EXPECT_NE(ds_binder, nullptr);
+
+ // Prepare arguments
+ unique_fd bugreport_fd(OpenForWrite("/bugreports/tmp.zip"));
+ unique_fd screenshot_fd(OpenForWrite("/bugreports/tmp.png"));
+
+ EXPECT_NE(bugreport_fd.get(), -1);
+ EXPECT_NE(screenshot_fd.get(), -1);
+
+ sp<DumpstateListener> listener(new DumpstateListener(dup(fileno(stdout))));
+ android::binder::Status status =
+ ds_binder->startBugreport(123, "com.dummy.package", bugreport_fd, screenshot_fd,
+ Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE, listener);
+ // startBugreport is an async call. Verify binder call succeeded first, then wait till listener
+ // gets expected callbacks.
+ EXPECT_TRUE(status.isOk());
+ WaitTillExecutionComplete(listener.get());
+
+ // Bugreport generation requires user consent, which we cannot get in a test set up,
+ // so instead of getting is_finished_, we are more likely to get a consent error.
+ EXPECT_TRUE(
+ listener->getErrorCode() == IDumpstateListener::BUGREPORT_ERROR_USER_DENIED_CONSENT ||
+ listener->getErrorCode() == IDumpstateListener::BUGREPORT_ERROR_USER_CONSENT_TIMED_OUT);
+
+ // The service should have died on its own, freeing itself up for a new invocation.
+ sleep(2);
+ ds_binder = GetDumpstateService();
+ EXPECT_EQ(ds_binder, nullptr);
+}
+
+TEST_F(DumpstateBinderTest, ServiceDies_OnInvalidInput) {
+ // Start bugreportd, which runs dumpstate binary with -w; which starts dumpstate service
+ // and makes it wait.
+ property_set("ctl.start", "bugreportd");
+ sp<android::os::IDumpstate> ds_binder(GetDumpstateService());
+ EXPECT_NE(ds_binder, nullptr);
+
+ // Prepare arguments
+ unique_fd bugreport_fd(OpenForWrite("/data/local/tmp/tmp.zip"));
+ unique_fd screenshot_fd(OpenForWrite("/data/local/tmp/tmp.png"));
+
+ EXPECT_NE(bugreport_fd.get(), -1);
+ EXPECT_NE(screenshot_fd.get(), -1);
+
+ // Call startBugreport with bad arguments.
+ sp<DumpstateListener> listener(new DumpstateListener(dup(fileno(stdout))));
+ android::binder::Status status =
+ ds_binder->startBugreport(123, "com.dummy.package", bugreport_fd, screenshot_fd,
+ 2000, // invalid bugreport mode
+ listener);
+ EXPECT_EQ(listener->getErrorCode(), IDumpstateListener::BUGREPORT_ERROR_INVALID_INPUT);
+
+ // The service should have died, freeing itself up for a new invocation.
+ sleep(2);
+ ds_binder = GetDumpstateService();
+ EXPECT_EQ(ds_binder, nullptr);
+}
+
+TEST_F(DumpstateBinderTest, SimultaneousBugreportsNotAllowed) {
+ // Start bugreportd, which runs dumpstate binary with -w; which starts dumpstate service
+ // and makes it wait.
+ property_set("dumpstate.dry_run", "true");
+ property_set("ctl.start", "bugreportd");
+ sp<android::os::IDumpstate> ds_binder(GetDumpstateService());
+ EXPECT_NE(ds_binder, nullptr);
+
+ // Prepare arguments
+ unique_fd bugreport_fd(OpenForWrite("/data/local/tmp/tmp.zip"));
+ unique_fd screenshot_fd(OpenForWrite("/data/local/tmp/tmp.png"));
+
+ EXPECT_NE(bugreport_fd.get(), -1);
+ EXPECT_NE(screenshot_fd.get(), -1);
+
+ sp<DumpstateListener> listener1(new DumpstateListener(dup(fileno(stdout))));
+ android::binder::Status status =
+ ds_binder->startBugreport(123, "com.dummy.package", bugreport_fd, screenshot_fd,
+ Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE, listener1);
+ EXPECT_TRUE(status.isOk());
+
+ // try to make another call to startBugreport. This should fail.
+ sp<DumpstateListener> listener2(new DumpstateListener(dup(fileno(stdout))));
+ status = ds_binder->startBugreport(123, "com.dummy.package", bugreport_fd, screenshot_fd,
+ Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE, listener2);
+ EXPECT_FALSE(status.isOk());
+ WaitTillExecutionComplete(listener2.get());
+ EXPECT_EQ(listener2->getErrorCode(),
+ IDumpstateListener::BUGREPORT_ERROR_CONCURRENT_BUGREPORTS_FORBIDDEN);
+
+ // Meanwhile the first call works as expected. Service should not die in this case.
+ WaitTillExecutionComplete(listener1.get());
+
+ // Bugreport generation requires user consent, which we cannot get in a test set up,
+ // so instead of getting is_finished_, we are more likely to get a consent error.
+ EXPECT_TRUE(
+ listener1->getErrorCode() == IDumpstateListener::BUGREPORT_ERROR_USER_DENIED_CONSENT ||
+ listener1->getErrorCode() == IDumpstateListener::BUGREPORT_ERROR_USER_CONSENT_TIMED_OUT);
+}
+
} // namespace dumpstate
} // namespace os
} // namespace android
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index 49383e5..2efcf11 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -39,6 +39,7 @@
#include <sys/xattr.h>
#include <unistd.h>
+#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/properties.h>
#include <android-base/scopeguard.h>
@@ -80,6 +81,8 @@
// An uuid used in unit tests.
static constexpr const char* kTestUuid = "TEST";
+static constexpr const mode_t kRollbackFolderMode = 0700;
+
static constexpr const char* kCpPath = "/system/bin/cp";
static constexpr const char* kXattrDefault = "user.default";
@@ -822,8 +825,8 @@
binder::Status InstalldNativeService::snapshotAppData(
const std::unique_ptr<std::string>& volumeUuid,
- const std::string& packageName, int32_t user, int32_t storageFlags,
- int64_t* _aidl_return) {
+ const std::string& packageName, int32_t user, int32_t snapshotId,
+ int32_t storageFlags, int64_t* _aidl_return) {
ENFORCE_UID(AID_SYSTEM);
CHECK_ARGUMENT_UUID_IS_TEST_OR_NULL(volumeUuid);
CHECK_ARGUMENT_PACKAGE_NAME(packageName);
@@ -840,16 +843,19 @@
bool clear_ce_on_exit = false;
bool clear_de_on_exit = false;
- auto deleter = [&clear_ce_on_exit, &clear_de_on_exit, &volume_uuid, &user, &package_name] {
+ auto deleter = [&clear_ce_on_exit, &clear_de_on_exit, &volume_uuid, &user, &package_name,
+ &snapshotId] {
if (clear_de_on_exit) {
- auto to = create_data_misc_de_rollback_package_path(volume_uuid, user, package_name);
+ auto to = create_data_misc_de_rollback_package_path(volume_uuid, user, snapshotId,
+ package_name);
if (delete_dir_contents(to.c_str(), 1, nullptr) != 0) {
LOG(WARNING) << "Failed to delete app data snapshot: " << to;
}
}
if (clear_ce_on_exit) {
- auto to = create_data_misc_ce_rollback_package_path(volume_uuid, user, package_name);
+ auto to = create_data_misc_ce_rollback_package_path(volume_uuid, user, snapshotId,
+ package_name);
if (delete_dir_contents(to.c_str(), 1, nullptr) != 0) {
LOG(WARNING) << "Failed to delete app data snapshot: " << to;
}
@@ -885,15 +891,21 @@
if (storageFlags & FLAG_STORAGE_DE) {
auto from = create_data_user_de_package_path(volume_uuid, user, package_name);
- auto to = create_data_misc_de_rollback_path(volume_uuid, user);
+ auto to = create_data_misc_de_rollback_path(volume_uuid, user, snapshotId);
+ auto rollback_package_path = create_data_misc_de_rollback_package_path(volume_uuid, user,
+ snapshotId, package_name);
- int rd = delete_dir_contents(to, true /* ignore_if_missing */);
- if (rd != 0) {
- res = error(rd, "Failed clearing existing snapshot " + to);
- return res;
+ int rc = create_dir_if_needed(to.c_str(), kRollbackFolderMode);
+ if (rc != 0) {
+ return error(rc, "Failed to create folder " + to);
}
- int rc = copy_directory_recursive(from.c_str(), to.c_str());
+ rc = delete_dir_contents(rollback_package_path, true /* ignore_if_missing */);
+ if (rc != 0) {
+ return error(rc, "Failed clearing existing snapshot " + rollback_package_path);
+ }
+
+ rc = copy_directory_recursive(from.c_str(), to.c_str());
if (rc != 0) {
res = error(rc, "Failed copying " + from + " to " + to);
clear_de_on_exit = true;
@@ -903,15 +915,21 @@
if (storageFlags & FLAG_STORAGE_CE) {
auto from = create_data_user_ce_package_path(volume_uuid, user, package_name);
- auto to = create_data_misc_ce_rollback_path(volume_uuid, user);
+ auto to = create_data_misc_ce_rollback_path(volume_uuid, user, snapshotId);
+ auto rollback_package_path = create_data_misc_ce_rollback_package_path(volume_uuid, user,
+ snapshotId, package_name);
- int rd = delete_dir_contents(to, true /* ignore_if_missing */);
- if (rd != 0) {
- res = error(rd, "Failed clearing existing snapshot " + to);
- return res;
+ int rc = create_dir_if_needed(to.c_str(), kRollbackFolderMode);
+ if (rc != 0) {
+ return error(rc, "Failed to create folder " + to);
}
- int rc = copy_directory_recursive(from.c_str(), to.c_str());
+ rc = delete_dir_contents(rollback_package_path, true /* ignore_if_missing */);
+ if (rc != 0) {
+ return error(rc, "Failed clearing existing snapshot " + rollback_package_path);
+ }
+
+ rc = copy_directory_recursive(from.c_str(), to.c_str());
if (rc != 0) {
res = error(rc, "Failed copying " + from + " to " + to);
clear_ce_on_exit = true;
@@ -919,7 +937,7 @@
}
if (_aidl_return != nullptr) {
auto ce_snapshot_path = create_data_misc_ce_rollback_package_path(volume_uuid, user,
- package_name);
+ snapshotId, package_name);
rc = get_path_inode(ce_snapshot_path, reinterpret_cast<ino_t*>(_aidl_return));
if (rc != 0) {
res = error(rc, "Failed to get_path_inode for " + ce_snapshot_path);
@@ -934,8 +952,8 @@
binder::Status InstalldNativeService::restoreAppDataSnapshot(
const std::unique_ptr<std::string>& volumeUuid, const std::string& packageName,
- const int32_t appId, const int64_t ceDataInode, const std::string& seInfo,
- const int32_t user, int32_t storageFlags) {
+ const int32_t appId, const std::string& seInfo, const int32_t user,
+ const int32_t snapshotId, int32_t storageFlags) {
ENFORCE_UID(AID_SYSTEM);
CHECK_ARGUMENT_UUID_IS_TEST_OR_NULL(volumeUuid);
CHECK_ARGUMENT_PACKAGE_NAME(packageName);
@@ -945,9 +963,9 @@
const char* package_name = packageName.c_str();
auto from_ce = create_data_misc_ce_rollback_package_path(volume_uuid,
- user, package_name);
+ user, snapshotId, package_name);
auto from_de = create_data_misc_de_rollback_package_path(volume_uuid,
- user, package_name);
+ user, snapshotId, package_name);
const bool needs_ce_rollback = (storageFlags & FLAG_STORAGE_CE) &&
(access(from_ce.c_str(), F_OK) == 0);
@@ -964,7 +982,11 @@
// app with no data in those cases is arguably better than leaving the app
// with mismatched / stale data.
LOG(INFO) << "Clearing app data for " << packageName << " to restore snapshot.";
- binder::Status res = clearAppData(volumeUuid, packageName, user, storageFlags, ceDataInode);
+ // It's fine to pass 0 as ceDataInode here, because restoreAppDataSnapshot
+ // can only be called when user unlocks the phone, meaning that CE user data
+ // is decrypted.
+ binder::Status res = clearAppData(volumeUuid, packageName, user, storageFlags,
+ 0 /* ceDataInode */);
if (!res.isOk()) {
return res;
}
@@ -1000,7 +1022,8 @@
binder::Status InstalldNativeService::destroyAppDataSnapshot(
const std::unique_ptr<std::string> &volumeUuid, const std::string& packageName,
- const int32_t user, const int64_t ceSnapshotInode, int32_t storageFlags) {
+ const int32_t user, const int64_t ceSnapshotInode, const int32_t snapshotId,
+ int32_t storageFlags) {
ENFORCE_UID(AID_SYSTEM);
CHECK_ARGUMENT_UUID_IS_TEST_OR_NULL(volumeUuid);
CHECK_ARGUMENT_PACKAGE_NAME(packageName);
@@ -1011,7 +1034,7 @@
if (storageFlags & FLAG_STORAGE_DE) {
auto de_snapshot_path = create_data_misc_de_rollback_package_path(volume_uuid,
- user, package_name);
+ user, snapshotId, package_name);
int res = delete_dir_contents_and_dir(de_snapshot_path, true /* ignore_if_missing */);
if (res != 0) {
@@ -1021,7 +1044,7 @@
if (storageFlags & FLAG_STORAGE_CE) {
auto ce_snapshot_path = create_data_misc_ce_rollback_package_path(volume_uuid,
- user, package_name, ceSnapshotInode);
+ user, snapshotId, package_name, ceSnapshotInode);
int res = delete_dir_contents_and_dir(ce_snapshot_path, true /* ignore_if_missing */);
if (res != 0) {
return error(res, "Failed clearing snapshot " + ce_snapshot_path);
diff --git a/cmds/installd/InstalldNativeService.h b/cmds/installd/InstalldNativeService.h
index 578132d..0e91cb2 100644
--- a/cmds/installd/InstalldNativeService.h
+++ b/cmds/installd/InstalldNativeService.h
@@ -61,14 +61,14 @@
binder::Status fixupAppData(const std::unique_ptr<std::string>& uuid, int32_t flags);
binder::Status snapshotAppData(const std::unique_ptr<std::string>& volumeUuid,
- const std::string& packageName, const int32_t user, int32_t storageFlags,
- int64_t* _aidl_return);
+ const std::string& packageName, const int32_t user, const int32_t snapshotId,
+ int32_t storageFlags, int64_t* _aidl_return);
binder::Status restoreAppDataSnapshot(const std::unique_ptr<std::string>& volumeUuid,
- const std::string& packageName, const int32_t appId, const int64_t ceDataInode,
- const std::string& seInfo, const int32_t user, int32_t storageFlags);
+ const std::string& packageName, const int32_t appId, const std::string& seInfo,
+ const int32_t user, const int32_t snapshotId, int32_t storageFlags);
binder::Status destroyAppDataSnapshot(const std::unique_ptr<std::string> &volumeUuid,
const std::string& packageName, const int32_t user, const int64_t ceSnapshotInode,
- int32_t storageFlags);
+ const int32_t snapshotId, int32_t storageFlags);
binder::Status getAppSize(const std::unique_ptr<std::string>& uuid,
const std::vector<std::string>& packageNames, int32_t userId, int32_t flags,
diff --git a/cmds/installd/TEST_MAPPING b/cmds/installd/TEST_MAPPING
index 3de5c79..287f2d9 100644
--- a/cmds/installd/TEST_MAPPING
+++ b/cmds/installd/TEST_MAPPING
@@ -14,6 +14,15 @@
},
{
"name": "installd_utils_test"
+ },
+ {
+ "name": "CtsUsesLibraryHostTestCases"
+ },
+ {
+ "name": "CtsClassloaderSplitsHostTestCases"
+ },
+ {
+ "name": "CtsCompilationTestCases"
}
]
}
diff --git a/cmds/installd/binder/android/os/IInstalld.aidl b/cmds/installd/binder/android/os/IInstalld.aidl
index b345210..63c9765 100644
--- a/cmds/installd/binder/android/os/IInstalld.aidl
+++ b/cmds/installd/binder/android/os/IInstalld.aidl
@@ -106,11 +106,11 @@
@nullable @utf8InCpp String dexMetadata);
long snapshotAppData(@nullable @utf8InCpp String uuid, in @utf8InCpp String packageName,
- int userId, int storageFlags);
+ int userId, int snapshotId, int storageFlags);
void restoreAppDataSnapshot(@nullable @utf8InCpp String uuid, in @utf8InCpp String packageName,
- int appId, long ceDataInode, @utf8InCpp String seInfo, int user, int storageflags);
+ int appId, @utf8InCpp String seInfo, int user, int snapshotId, int storageflags);
void destroyAppDataSnapshot(@nullable @utf8InCpp String uuid, @utf8InCpp String packageName,
- int userId, long ceSnapshotInode, int storageFlags);
+ int userId, long ceSnapshotInode, int snapshotId, int storageFlags);
const int FLAG_STORAGE_DE = 0x1;
const int FLAG_STORAGE_CE = 0x2;
diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp
index 852aa79..acc0647 100644
--- a/cmds/installd/dexopt.cpp
+++ b/cmds/installd/dexopt.cpp
@@ -352,6 +352,8 @@
bool generate_minidebug_info = kEnableMinidebugInfo &&
GetBoolProperty(kMinidebugInfoSystemProperty, kMinidebugInfoSystemPropertyDefault);
+ std::string boot_image = MapPropertyToArg("dalvik.vm.boot-image", "-Ximage:%s");
+
// clang FORTIFY doesn't let us use strlen in constant array bounds, so we
// use arraysize instead.
std::string zip_fd_arg = StringPrintf("--zip-fd=%d", zip_fd);
@@ -366,7 +368,7 @@
std::string dex2oat_image_fd;
std::string target_sdk_version_arg;
if (target_sdk_version != 0) {
- StringPrintf("-Xtarget-sdk-version:%d", target_sdk_version);
+ target_sdk_version_arg = StringPrintf("-Xtarget-sdk-version:%d", target_sdk_version);
}
std::string class_loader_context_arg;
if (class_loader_context != nullptr) {
@@ -437,6 +439,7 @@
AddArg(instruction_set_variant_arg);
AddArg(instruction_set_features_arg);
+ AddRuntimeArg(boot_image);
AddRuntimeArg(dex2oat_Xms_arg);
AddRuntimeArg(dex2oat_Xmx_arg);
@@ -468,7 +471,7 @@
if (disable_cdex) {
AddArg(kDisableCompactDexFlag);
}
- AddArg(target_sdk_version_arg);
+ AddRuntimeArg(target_sdk_version_arg);
if (enable_hidden_api_checks) {
AddRuntimeArg("-Xhidden-api-checks");
}
diff --git a/cmds/installd/tests/installd_service_test.cpp b/cmds/installd/tests/installd_service_test.cpp
index 48b07c4..a31d510 100644
--- a/cmds/installd/tests/installd_service_test.cpp
+++ b/cmds/installd/tests/installd_service_test.cpp
@@ -259,32 +259,59 @@
return false;
}
- return (::mkdir(path.c_str(), mode) != -1);
+ if (::mkdir(path.c_str(), mode) != 0) {
+ PLOG(DEBUG) << "Failed to create folder " << path;
+ return false;
+ }
+ return true;
}
-TEST_F(ServiceTest, CreateAppDataSnapshot) {
- auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0);
- auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0);
+class AppDataSnapshotTest : public testing::Test {
+private:
+ std::string rollback_ce_base_dir;
+ std::string rollback_de_base_dir;
- ASSERT_TRUE(mkdirs(rollback_ce_dir, 700));
- ASSERT_TRUE(mkdirs(rollback_de_dir, 700));
+protected:
+ InstalldNativeService* service;
- auto fake_package_ce_path = create_data_user_ce_package_path("TEST", 0, "com.foo");
- auto fake_package_de_path = create_data_user_de_package_path("TEST", 0, "com.foo");
+ std::string fake_package_ce_path;
+ std::string fake_package_de_path;
- ASSERT_TRUE(mkdirs(fake_package_ce_path, 700));
- ASSERT_TRUE(mkdirs(fake_package_de_path, 700));
+ virtual void SetUp() {
+ setenv("ANDROID_LOG_TAGS", "*:v", 1);
+ android::base::InitLogging(nullptr);
- auto deleter = [&rollback_ce_dir, &rollback_de_dir,
- &fake_package_ce_path, &fake_package_de_path]() {
- delete_dir_contents(rollback_ce_dir, true);
- delete_dir_contents(rollback_de_dir, true);
- delete_dir_contents(fake_package_ce_path, true);
- delete_dir_contents(fake_package_de_path, true);
- rmdir(rollback_ce_dir.c_str());
- rmdir(rollback_de_dir.c_str());
- };
- auto scope_guard = android::base::make_scope_guard(deleter);
+ service = new InstalldNativeService();
+ ASSERT_TRUE(mkdirs("/data/local/tmp/user/0", 0700));
+
+ init_globals_from_data_and_root();
+
+ rollback_ce_base_dir = create_data_misc_ce_rollback_base_path("TEST", 0);
+ rollback_de_base_dir = create_data_misc_de_rollback_base_path("TEST", 0);
+
+ fake_package_ce_path = create_data_user_ce_package_path("TEST", 0, "com.foo");
+ fake_package_de_path = create_data_user_de_package_path("TEST", 0, "com.foo");
+
+ ASSERT_TRUE(mkdirs(rollback_ce_base_dir, 0700));
+ ASSERT_TRUE(mkdirs(rollback_de_base_dir, 0700));
+ ASSERT_TRUE(mkdirs(fake_package_ce_path, 0700));
+ ASSERT_TRUE(mkdirs(fake_package_de_path, 0700));
+ }
+
+ virtual void TearDown() {
+ ASSERT_EQ(0, delete_dir_contents_and_dir(rollback_ce_base_dir, true));
+ ASSERT_EQ(0, delete_dir_contents_and_dir(rollback_de_base_dir, true));
+ ASSERT_EQ(0, delete_dir_contents(fake_package_ce_path, true));
+ ASSERT_EQ(0, delete_dir_contents(fake_package_de_path, true));
+
+ delete service;
+ ASSERT_EQ(0, delete_dir_contents_and_dir("/data/local/tmp/user/0", true));
+ }
+};
+
+TEST_F(AppDataSnapshotTest, CreateAppDataSnapshot) {
+ auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0, 37);
+ auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0, 37);
ASSERT_TRUE(android::base::WriteStringToFile(
"TEST_CONTENT_CE", fake_package_ce_path + "/file1",
@@ -296,7 +323,7 @@
// Request a snapshot of the CE content but not the DE content.
int64_t ce_snapshot_inode;
ASSERT_BINDER_SUCCESS(service->snapshotAppData(std::make_unique<std::string>("TEST"),
- "com.foo", 0, FLAG_STORAGE_CE, &ce_snapshot_inode));
+ "com.foo", 0, 37, FLAG_STORAGE_CE, &ce_snapshot_inode));
struct stat buf;
memset(&buf, 0, sizeof(buf));
ASSERT_EQ(0, stat((rollback_ce_dir + "/com.foo").c_str(), &buf));
@@ -318,7 +345,7 @@
// Request a snapshot of the DE content but not the CE content.
ASSERT_BINDER_SUCCESS(service->snapshotAppData(std::make_unique<std::string>("TEST"),
- "com.foo", 0, FLAG_STORAGE_DE, &ce_snapshot_inode));
+ "com.foo", 0, 37, FLAG_STORAGE_DE, &ce_snapshot_inode));
// Only DE content snapshot was requested.
ASSERT_EQ(ce_snapshot_inode, 0);
@@ -339,7 +366,7 @@
// Request a snapshot of both the CE as well as the DE content.
ASSERT_BINDER_SUCCESS(service->snapshotAppData(std::make_unique<std::string>("TEST"),
- "com.foo", 0, FLAG_STORAGE_DE | FLAG_STORAGE_CE, nullptr));
+ "com.foo", 0, 37, FLAG_STORAGE_DE | FLAG_STORAGE_CE, nullptr));
ASSERT_TRUE(android::base::ReadFileToString(
rollback_ce_dir + "/com.foo/file1", &ce_content, false /* follow_symlinks */));
@@ -349,27 +376,73 @@
ASSERT_EQ("TEST_CONTENT_DE_MODIFIED", de_content);
}
-TEST_F(ServiceTest, CreateAppDataSnapshot_AppDataAbsent) {
- auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0);
- auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0);
+TEST_F(AppDataSnapshotTest, CreateAppDataSnapshot_TwoSnapshotsWithTheSameId) {
+ auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0, 67);
+ auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0, 67);
- ASSERT_TRUE(mkdirs(rollback_ce_dir, 700));
- ASSERT_TRUE(mkdirs(rollback_de_dir, 700));
+ auto another_fake_package_ce_path = create_data_user_ce_package_path("TEST", 0, "com.bar");
+ auto another_fake_package_de_path = create_data_user_de_package_path("TEST", 0, "com.bar");
- auto deleter = [&rollback_ce_dir, &rollback_de_dir]() {
- delete_dir_contents(rollback_ce_dir, true);
- delete_dir_contents(rollback_de_dir, true);
- rmdir(rollback_ce_dir.c_str());
- rmdir(rollback_de_dir.c_str());
+ // Since this test sets up data for another package, some bookkeeping is required.
+ auto deleter = [&]() {
+ ASSERT_EQ(0, delete_dir_contents_and_dir(another_fake_package_ce_path, true));
+ ASSERT_EQ(0, delete_dir_contents_and_dir(another_fake_package_de_path, true));
};
-
auto scope_guard = android::base::make_scope_guard(deleter);
+ ASSERT_TRUE(mkdirs(another_fake_package_ce_path, 0700));
+ ASSERT_TRUE(mkdirs(another_fake_package_de_path, 0700));
+
+ ASSERT_TRUE(android::base::WriteStringToFile(
+ "TEST_CONTENT_CE", fake_package_ce_path + "/file1",
+ 0700, 10000, 20000, false /* follow_symlinks */));
+ ASSERT_TRUE(android::base::WriteStringToFile(
+ "TEST_CONTENT_DE", fake_package_de_path + "/file1",
+ 0700, 10000, 20000, false /* follow_symlinks */));
+ ASSERT_TRUE(android::base::WriteStringToFile(
+ "ANOTHER_TEST_CONTENT_CE", another_fake_package_ce_path + "/file1",
+ 0700, 10000, 20000, false /* follow_symlinks */));
+ ASSERT_TRUE(android::base::WriteStringToFile(
+ "ANOTHER_TEST_CONTENT_DE", another_fake_package_de_path + "/file1",
+ 0700, 10000, 20000, false /* follow_symlinks */));
+
+ // Request snapshot for the package com.foo.
+ ASSERT_BINDER_SUCCESS(service->snapshotAppData(std::make_unique<std::string>("TEST"),
+ "com.foo", 0, 67, FLAG_STORAGE_DE | FLAG_STORAGE_CE, nullptr));
+ // Now request snapshot with the same id for the package com.bar
+ ASSERT_BINDER_SUCCESS(service->snapshotAppData(std::make_unique<std::string>("TEST"),
+ "com.bar", 0, 67, FLAG_STORAGE_DE | FLAG_STORAGE_CE, nullptr));
+
+ // Check that both snapshots have correct data in them.
+ std::string com_foo_ce_content, com_foo_de_content;
+ std::string com_bar_ce_content, com_bar_de_content;
+ ASSERT_TRUE(android::base::ReadFileToString(
+ rollback_ce_dir + "/com.foo/file1", &com_foo_ce_content, false /* follow_symlinks */));
+ ASSERT_TRUE(android::base::ReadFileToString(
+ rollback_de_dir + "/com.foo/file1", &com_foo_de_content, false /* follow_symlinks */));
+ ASSERT_TRUE(android::base::ReadFileToString(
+ rollback_ce_dir + "/com.bar/file1", &com_bar_ce_content, false /* follow_symlinks */));
+ ASSERT_TRUE(android::base::ReadFileToString(
+ rollback_de_dir + "/com.bar/file1", &com_bar_de_content, false /* follow_symlinks */));
+ ASSERT_EQ("TEST_CONTENT_CE", com_foo_ce_content);
+ ASSERT_EQ("TEST_CONTENT_DE", com_foo_de_content);
+ ASSERT_EQ("ANOTHER_TEST_CONTENT_CE", com_bar_ce_content);
+ ASSERT_EQ("ANOTHER_TEST_CONTENT_DE", com_bar_de_content);
+}
+
+TEST_F(AppDataSnapshotTest, CreateAppDataSnapshot_AppDataAbsent) {
+ auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0, 73);
+ auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0, 73);
+
+ // Similuating app data absence.
+ ASSERT_EQ(0, delete_dir_contents_and_dir(fake_package_ce_path, true));
+ ASSERT_EQ(0, delete_dir_contents_and_dir(fake_package_de_path, true));
+
int64_t ce_snapshot_inode;
ASSERT_BINDER_SUCCESS(service->snapshotAppData(std::make_unique<std::string>("TEST"),
- "com.foo", 0, FLAG_STORAGE_CE, &ce_snapshot_inode));
+ "com.foo", 0, 73, FLAG_STORAGE_CE, &ce_snapshot_inode));
ASSERT_BINDER_SUCCESS(service->snapshotAppData(std::make_unique<std::string>("TEST"),
- "com.foo", 0, FLAG_STORAGE_DE, nullptr));
+ "com.foo", 0, 73, FLAG_STORAGE_DE, nullptr));
// No CE content snapshot was performed.
ASSERT_EQ(ce_snapshot_inode, 0);
@@ -380,29 +453,12 @@
ASSERT_EQ(-1, stat((rollback_de_dir + "/com.foo").c_str(), &sb));
}
-TEST_F(ServiceTest, CreateAppDataSnapshot_ClearsExistingSnapshot) {
- auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0);
- auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0);
+TEST_F(AppDataSnapshotTest, CreateAppDataSnapshot_ClearsExistingSnapshot) {
+ auto rollback_ce_dir = create_data_misc_ce_rollback_package_path("TEST", 0, 13, "com.foo");
+ auto rollback_de_dir = create_data_misc_de_rollback_package_path("TEST", 0, 13, "com.foo");
- ASSERT_TRUE(mkdirs(rollback_ce_dir, 700));
- ASSERT_TRUE(mkdirs(rollback_de_dir, 700));
-
- auto fake_package_ce_path = create_data_user_ce_package_path("TEST", 0, "com.foo");
- auto fake_package_de_path = create_data_user_de_package_path("TEST", 0, "com.foo");
-
- ASSERT_TRUE(mkdirs(fake_package_ce_path, 700));
- ASSERT_TRUE(mkdirs(fake_package_de_path, 700));
-
- auto deleter = [&rollback_ce_dir, &rollback_de_dir,
- &fake_package_ce_path, &fake_package_de_path]() {
- delete_dir_contents(rollback_ce_dir, true);
- delete_dir_contents(rollback_de_dir, true);
- delete_dir_contents(fake_package_ce_path, true);
- delete_dir_contents(fake_package_de_path, true);
- rmdir(rollback_ce_dir.c_str());
- rmdir(rollback_de_dir.c_str());
- };
- auto scope_guard = android::base::make_scope_guard(deleter);
+ ASSERT_TRUE(mkdirs(rollback_ce_dir, 0700));
+ ASSERT_TRUE(mkdirs(rollback_de_dir, 0700));
// Simulate presence of an existing snapshot
ASSERT_TRUE(android::base::WriteStringToFile(
@@ -421,62 +477,40 @@
0700, 10000, 20000, false /* follow_symlinks */));
ASSERT_BINDER_SUCCESS(service->snapshotAppData(std::make_unique<std::string>("TEST"),
- "com.foo", 0, FLAG_STORAGE_DE | FLAG_STORAGE_CE, nullptr));
+ "com.foo", 0, 13, FLAG_STORAGE_DE | FLAG_STORAGE_CE, nullptr));
// Previous snapshot (with data for file1) must be cleared.
struct stat sb;
- ASSERT_EQ(-1, stat((rollback_ce_dir + "/com.foo/file1").c_str(), &sb));
- ASSERT_EQ(-1, stat((rollback_de_dir + "/com.foo/file1").c_str(), &sb));
+ ASSERT_EQ(-1, stat((rollback_ce_dir + "/file1").c_str(), &sb));
+ ASSERT_EQ(-1, stat((rollback_de_dir + "/file1").c_str(), &sb));
+ // New snapshot (with data for file2) must be present.
+ ASSERT_NE(-1, stat((rollback_ce_dir + "/file2").c_str(), &sb));
+ ASSERT_NE(-1, stat((rollback_de_dir + "/file2").c_str(), &sb));
}
-TEST_F(ServiceTest, SnapshotAppData_WrongVolumeUuid) {
- // Setup app data to make sure that fails due to wrong volumeUuid being
+TEST_F(AppDataSnapshotTest, SnapshotAppData_WrongVolumeUuid) {
+ // Setup rollback folders to make sure that fails due to wrong volumeUuid being
// passed, not because of some other reason.
- auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0);
- auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0);
+ auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0, 17);
+ auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0, 17);
- ASSERT_TRUE(mkdirs(rollback_ce_dir, 700));
- ASSERT_TRUE(mkdirs(rollback_de_dir, 700));
-
- auto deleter = [&rollback_ce_dir, &rollback_de_dir]() {
- delete_dir_contents(rollback_ce_dir, true);
- delete_dir_contents(rollback_de_dir, true);
- rmdir(rollback_ce_dir.c_str());
- rmdir(rollback_de_dir.c_str());
- };
- auto scope_guard = android::base::make_scope_guard(deleter);
+ ASSERT_TRUE(mkdirs(rollback_ce_dir, 0700));
+ ASSERT_TRUE(mkdirs(rollback_de_dir, 0700));
EXPECT_BINDER_FAIL(service->snapshotAppData(std::make_unique<std::string>("FOO"),
- "com.foo", 0, FLAG_STORAGE_DE, nullptr));
+ "com.foo", 0, 17, FLAG_STORAGE_DE, nullptr));
}
-TEST_F(ServiceTest, CreateAppDataSnapshot_ClearsCache) {
- auto fake_package_ce_path = create_data_user_ce_package_path("TEST", 0, "com.foo");
- auto fake_package_de_path = create_data_user_de_package_path("TEST", 0, "com.foo");
+TEST_F(AppDataSnapshotTest, CreateAppDataSnapshot_ClearsCache) {
auto fake_package_ce_cache_path = fake_package_ce_path + "/cache";
auto fake_package_ce_code_cache_path = fake_package_ce_path + "/code_cache";
auto fake_package_de_cache_path = fake_package_de_path + "/cache";
auto fake_package_de_code_cache_path = fake_package_de_path + "/code_cache";
- auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0);
- auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0);
- ASSERT_TRUE(mkdirs(fake_package_ce_path, 700));
- ASSERT_TRUE(mkdirs(fake_package_de_path, 700));
- ASSERT_TRUE(mkdirs(fake_package_ce_cache_path, 700));
- ASSERT_TRUE(mkdirs(fake_package_ce_code_cache_path, 700));
- ASSERT_TRUE(mkdirs(fake_package_de_cache_path, 700));
- ASSERT_TRUE(mkdirs(fake_package_de_code_cache_path, 700));
- ASSERT_TRUE(mkdirs(rollback_ce_dir, 700));
- ASSERT_TRUE(mkdirs(rollback_de_dir, 700));
-
- auto deleter = [&fake_package_ce_path, &fake_package_de_path,
- &rollback_ce_dir, &rollback_de_dir]() {
- delete_dir_contents(fake_package_ce_path, true);
- delete_dir_contents(fake_package_de_path, true);
- delete_dir_contents_and_dir(rollback_ce_dir, true);
- delete_dir_contents_and_dir(rollback_de_dir, true);
- };
- auto scope_guard = android::base::make_scope_guard(deleter);
+ ASSERT_TRUE(mkdirs(fake_package_ce_cache_path, 0700));
+ ASSERT_TRUE(mkdirs(fake_package_ce_code_cache_path, 0700));
+ ASSERT_TRUE(mkdirs(fake_package_de_cache_path, 0700));
+ ASSERT_TRUE(mkdirs(fake_package_de_code_cache_path, 0700));
ASSERT_TRUE(android::base::WriteStringToFile(
"TEST_CONTENT_CE", fake_package_ce_cache_path + "/file1",
@@ -491,7 +525,7 @@
"TEST_CONTENT_DE", fake_package_de_code_cache_path + "/file1",
0700, 10000, 20000, false /* follow_symlinks */));
ASSERT_BINDER_SUCCESS(service->snapshotAppData(std::make_unique<std::string>("TEST"),
- "com.foo", 0, FLAG_STORAGE_CE | FLAG_STORAGE_DE, nullptr));
+ "com.foo", 0, 23, FLAG_STORAGE_CE | FLAG_STORAGE_DE, nullptr));
// The snapshot call must clear cache.
struct stat sb;
ASSERT_EQ(-1, stat((fake_package_ce_cache_path + "/file1").c_str(), &sb));
@@ -500,34 +534,17 @@
ASSERT_EQ(-1, stat((fake_package_de_code_cache_path + "/file1").c_str(), &sb));
}
-TEST_F(ServiceTest, RestoreAppDataSnapshot) {
- auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0);
- auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0);
+TEST_F(AppDataSnapshotTest, RestoreAppDataSnapshot) {
+ auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0, 239);
+ auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0, 239);
- ASSERT_TRUE(mkdirs(rollback_ce_dir, 700));
- ASSERT_TRUE(mkdirs(rollback_de_dir, 700));
-
- auto fake_package_ce_path = create_data_user_ce_package_path("TEST", 0, "com.foo");
- auto fake_package_de_path = create_data_user_de_package_path("TEST", 0, "com.foo");
-
- ASSERT_TRUE(mkdirs(fake_package_ce_path, 700));
- ASSERT_TRUE(mkdirs(fake_package_de_path, 700));
-
- auto deleter = [&rollback_ce_dir, &rollback_de_dir,
- &fake_package_ce_path, &fake_package_de_path]() {
- delete_dir_contents(rollback_ce_dir, true);
- delete_dir_contents(rollback_de_dir, true);
- delete_dir_contents(fake_package_ce_path, true);
- delete_dir_contents(fake_package_de_path, true);
- rmdir(rollback_ce_dir.c_str());
- rmdir(rollback_de_dir.c_str());
- };
- auto scope_guard = android::base::make_scope_guard(deleter);
+ ASSERT_TRUE(mkdirs(rollback_ce_dir, 0700));
+ ASSERT_TRUE(mkdirs(rollback_de_dir, 0700));
// Write contents to the rollback location. We'll write the same files to the
// app data location and make sure the restore has overwritten them.
- ASSERT_TRUE(mkdirs(rollback_ce_dir + "/com.foo/", 700));
- ASSERT_TRUE(mkdirs(rollback_de_dir + "/com.foo/", 700));
+ ASSERT_TRUE(mkdirs(rollback_ce_dir + "/com.foo/", 0700));
+ ASSERT_TRUE(mkdirs(rollback_de_dir + "/com.foo/", 0700));
ASSERT_TRUE(android::base::WriteStringToFile(
"CE_RESTORE_CONTENT", rollback_ce_dir + "/com.foo/file1",
0700, 10000, 20000, false /* follow_symlinks */));
@@ -542,7 +559,7 @@
0700, 10000, 20000, false /* follow_symlinks */));
ASSERT_BINDER_SUCCESS(service->restoreAppDataSnapshot(std::make_unique<std::string>("TEST"),
- "com.foo", 10000, -1, "", 0, FLAG_STORAGE_DE | FLAG_STORAGE_CE));
+ "com.foo", 10000, "", 0, 239, FLAG_STORAGE_DE | FLAG_STORAGE_CE));
std::string ce_content, de_content;
ASSERT_TRUE(android::base::ReadFileToString(
@@ -553,29 +570,9 @@
ASSERT_EQ("DE_RESTORE_CONTENT", de_content);
}
-TEST_F(ServiceTest, CreateSnapshotThenDestroyIt) {
- auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0);
- auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0);
-
- ASSERT_TRUE(mkdirs(rollback_ce_dir, 700));
- ASSERT_TRUE(mkdirs(rollback_de_dir, 700));
-
- auto fake_package_ce_path = create_data_user_ce_package_path("TEST", 0, "com.foo");
- auto fake_package_de_path = create_data_user_de_package_path("TEST", 0, "com.foo");
-
- ASSERT_TRUE(mkdirs(fake_package_ce_path, 700));
- ASSERT_TRUE(mkdirs(fake_package_de_path, 700));
-
- auto deleter = [&rollback_ce_dir, &rollback_de_dir,
- &fake_package_ce_path, &fake_package_de_path]() {
- delete_dir_contents(rollback_ce_dir, true);
- delete_dir_contents(rollback_de_dir, true);
- delete_dir_contents(fake_package_ce_path, true);
- delete_dir_contents(fake_package_de_path, true);
- rmdir(rollback_ce_dir.c_str());
- rmdir(rollback_de_dir.c_str());
- };
- auto scope_guard = android::base::make_scope_guard(deleter);
+TEST_F(AppDataSnapshotTest, CreateSnapshotThenDestroyIt) {
+ auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0, 57);
+ auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0, 57);
// Prepare data for snapshot.
ASSERT_TRUE(android::base::WriteStringToFile(
@@ -588,7 +585,7 @@
int64_t ce_snapshot_inode;
// Request a snapshot of both the CE as well as the DE content.
ASSERT_TRUE(service->snapshotAppData(std::make_unique<std::string>("TEST"),
- "com.foo", 0, FLAG_STORAGE_DE | FLAG_STORAGE_CE, &ce_snapshot_inode).isOk());
+ "com.foo", 0, 57, FLAG_STORAGE_DE | FLAG_STORAGE_CE, &ce_snapshot_inode).isOk());
// Because CE data snapshot was requested, ce_snapshot_inode can't be null.
ASSERT_NE(0, ce_snapshot_inode);
// Check snapshot is there.
@@ -598,39 +595,19 @@
ASSERT_TRUE(service->destroyAppDataSnapshot(std::make_unique<std::string>("TEST"),
- "com.foo", 0, ce_snapshot_inode, FLAG_STORAGE_DE | FLAG_STORAGE_CE).isOk());
+ "com.foo", 0, ce_snapshot_inode, 57, FLAG_STORAGE_DE | FLAG_STORAGE_CE).isOk());
// Check snapshot is deleted.
ASSERT_EQ(-1, stat((rollback_ce_dir + "/com.foo").c_str(), &sb));
ASSERT_EQ(-1, stat((rollback_de_dir + "/com.foo").c_str(), &sb));
}
-TEST_F(ServiceTest, DestroyAppDataSnapshot_CeSnapshotInodeIsZero) {
- auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0);
- auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0);
-
- ASSERT_TRUE(mkdirs(rollback_ce_dir, 700));
- ASSERT_TRUE(mkdirs(rollback_de_dir, 700));
-
- auto fake_package_ce_path = create_data_user_ce_package_path("TEST", 0, "com.foo");
- auto fake_package_de_path = create_data_user_de_package_path("TEST", 0, "com.foo");
-
- ASSERT_TRUE(mkdirs(fake_package_ce_path, 700));
- ASSERT_TRUE(mkdirs(fake_package_de_path, 700));
-
- auto deleter = [&rollback_ce_dir, &rollback_de_dir,
- &fake_package_ce_path, &fake_package_de_path]() {
- delete_dir_contents(rollback_ce_dir, true);
- delete_dir_contents(rollback_de_dir, true);
- delete_dir_contents(fake_package_ce_path, true);
- delete_dir_contents(fake_package_de_path, true);
- rmdir(rollback_ce_dir.c_str());
- rmdir(rollback_de_dir.c_str());
- };
- auto scope_guard = android::base::make_scope_guard(deleter);
+TEST_F(AppDataSnapshotTest, DestroyAppDataSnapshot_CeSnapshotInodeIsZero) {
+ auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0, 1543);
+ auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0, 1543);
// Create a snapshot
- ASSERT_TRUE(mkdirs(rollback_ce_dir + "/com.foo/", 700));
- ASSERT_TRUE(mkdirs(rollback_de_dir + "/com.foo/", 700));
+ ASSERT_TRUE(mkdirs(rollback_ce_dir + "/com.foo/", 0700));
+ ASSERT_TRUE(mkdirs(rollback_de_dir + "/com.foo/", 0700));
ASSERT_TRUE(android::base::WriteStringToFile(
"CE_RESTORE_CONTENT", rollback_ce_dir + "/com.foo/file1",
0700, 10000, 20000, false /* follow_symlinks */));
@@ -639,7 +616,7 @@
0700, 10000, 20000, false /* follow_symlinks */));
ASSERT_TRUE(service->destroyAppDataSnapshot(std::make_unique<std::string>("TEST"),
- "com.foo", 0, 0, FLAG_STORAGE_DE | FLAG_STORAGE_CE).isOk());
+ "com.foo", 0, 0, 1543, FLAG_STORAGE_DE | FLAG_STORAGE_CE).isOk());
// Check snapshot is deleted.
struct stat sb;
@@ -648,67 +625,33 @@
// Check that deleting already deleted snapshot is no-op.
ASSERT_TRUE(service->destroyAppDataSnapshot(std::make_unique<std::string>("TEST"),
- "com.foo", 0, 0, FLAG_STORAGE_DE | FLAG_STORAGE_CE).isOk());
+ "com.foo", 0, 0, 1543, FLAG_STORAGE_DE | FLAG_STORAGE_CE).isOk());
}
-TEST_F(ServiceTest, DestroyAppDataSnapshot_WrongVolumeUuid) {
+TEST_F(AppDataSnapshotTest, DestroyAppDataSnapshot_WrongVolumeUuid) {
// Setup rollback data to make sure that test fails due to wrong volumeUuid
// being passed, not because of some other reason.
- auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0);
- auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0);
+ auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0, 43);
+ auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0, 43);
- ASSERT_TRUE(mkdirs(rollback_ce_dir, 700));
- ASSERT_TRUE(mkdirs(rollback_de_dir, 700));
-
- auto fake_package_ce_path = create_data_user_ce_package_path("TEST", 0, "com.foo");
- auto fake_package_de_path = create_data_user_de_package_path("TEST", 0, "com.foo");
-
- ASSERT_TRUE(mkdirs(fake_package_ce_path, 700));
- ASSERT_TRUE(mkdirs(fake_package_de_path, 700));
-
- auto deleter = [&rollback_ce_dir, &rollback_de_dir,
- &fake_package_ce_path, &fake_package_de_path]() {
- delete_dir_contents(rollback_ce_dir, true);
- delete_dir_contents(rollback_de_dir, true);
- delete_dir_contents(fake_package_ce_path, true);
- delete_dir_contents(fake_package_de_path, true);
- rmdir(rollback_ce_dir.c_str());
- rmdir(rollback_de_dir.c_str());
- };
- auto scope_guard = android::base::make_scope_guard(deleter);
+ ASSERT_TRUE(mkdirs(rollback_ce_dir, 0700));
+ ASSERT_TRUE(mkdirs(rollback_de_dir, 0700));
ASSERT_FALSE(service->destroyAppDataSnapshot(std::make_unique<std::string>("BAR"),
- "com.foo", 0, 0, FLAG_STORAGE_DE).isOk());
+ "com.foo", 0, 0, 43, FLAG_STORAGE_DE).isOk());
}
-TEST_F(ServiceTest, RestoreAppDataSnapshot_WrongVolumeUuid) {
+TEST_F(AppDataSnapshotTest, RestoreAppDataSnapshot_WrongVolumeUuid) {
// Setup rollback data to make sure that fails due to wrong volumeUuid being
// passed, not because of some other reason.
- auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0);
- auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0);
+ auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0, 41);
+ auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0, 41);
- ASSERT_TRUE(mkdirs(rollback_ce_dir, 700));
- ASSERT_TRUE(mkdirs(rollback_de_dir, 700));
-
- auto fake_package_ce_path = create_data_user_ce_package_path("TEST", 0, "com.foo");
- auto fake_package_de_path = create_data_user_de_package_path("TEST", 0, "com.foo");
-
- ASSERT_TRUE(mkdirs(fake_package_ce_path, 700));
- ASSERT_TRUE(mkdirs(fake_package_de_path, 700));
-
- auto deleter = [&rollback_ce_dir, &rollback_de_dir,
- &fake_package_ce_path, &fake_package_de_path]() {
- delete_dir_contents(rollback_ce_dir, true);
- delete_dir_contents(rollback_de_dir, true);
- delete_dir_contents(fake_package_ce_path, true);
- delete_dir_contents(fake_package_de_path, true);
- rmdir(rollback_ce_dir.c_str());
- rmdir(rollback_de_dir.c_str());
- };
- auto scope_guard = android::base::make_scope_guard(deleter);
+ ASSERT_TRUE(mkdirs(rollback_ce_dir, 0700));
+ ASSERT_TRUE(mkdirs(rollback_de_dir, 0700));
EXPECT_BINDER_FAIL(service->restoreAppDataSnapshot(std::make_unique<std::string>("BAR"),
- "com.foo", 10000, -1, "", 0, FLAG_STORAGE_DE));
+ "com.foo", 10000, "", 0, 41, FLAG_STORAGE_DE));
}
} // namespace installd
diff --git a/cmds/installd/tests/installd_utils_test.cpp b/cmds/installd/tests/installd_utils_test.cpp
index 1782aa2..e61eb6e 100644
--- a/cmds/installd/tests/installd_utils_test.cpp
+++ b/cmds/installd/tests/installd_utils_test.cpp
@@ -546,56 +546,86 @@
}
TEST_F(UtilsTest, TestRollbackPaths) {
- EXPECT_EQ("/data/misc_ce/0/rollback/com.foo",
- create_data_misc_ce_rollback_package_path(nullptr, 0, "com.foo"));
- EXPECT_EQ("/data/misc_ce/10/rollback/com.foo",
- create_data_misc_ce_rollback_package_path(nullptr, 10, "com.foo"));
+ EXPECT_EQ("/data/misc_ce/0/rollback/239/com.foo",
+ create_data_misc_ce_rollback_package_path(nullptr, 0, 239, "com.foo"));
+ EXPECT_EQ("/data/misc_ce/10/rollback/37/com.foo",
+ create_data_misc_ce_rollback_package_path(nullptr, 10, 37, "com.foo"));
- EXPECT_EQ("/data/misc_de/0/rollback/com.foo",
- create_data_misc_de_rollback_package_path(nullptr, 0, "com.foo"));
- EXPECT_EQ("/data/misc_de/10/rollback/com.foo",
- create_data_misc_de_rollback_package_path(nullptr, 10, "com.foo"));
+ EXPECT_EQ("/data/misc_de/0/rollback/73/com.foo",
+ create_data_misc_de_rollback_package_path(nullptr, 0, 73, "com.foo"));
+ EXPECT_EQ("/data/misc_de/10/rollback/13/com.foo",
+ create_data_misc_de_rollback_package_path(nullptr, 10, 13, "com.foo"));
- EXPECT_EQ("/data/misc_ce/0/rollback",
- create_data_misc_ce_rollback_path(nullptr, 0));
- EXPECT_EQ("/data/misc_ce/10/rollback",
- create_data_misc_ce_rollback_path(nullptr, 10));
+ EXPECT_EQ("/data/misc_ce/0/rollback/57",
+ create_data_misc_ce_rollback_path(nullptr, 0, 57));
+ EXPECT_EQ("/data/misc_ce/10/rollback/1543",
+ create_data_misc_ce_rollback_path(nullptr, 10, 1543));
- EXPECT_EQ("/data/misc_de/0/rollback",
- create_data_misc_de_rollback_path(nullptr, 0));
- EXPECT_EQ("/data/misc_de/10/rollback",
- create_data_misc_de_rollback_path(nullptr, 10));
+ EXPECT_EQ("/data/misc_de/0/rollback/43",
+ create_data_misc_de_rollback_path(nullptr, 0, 43));
+ EXPECT_EQ("/data/misc_de/10/rollback/41",
+ create_data_misc_de_rollback_path(nullptr, 10, 41));
- EXPECT_EQ("/data/misc_ce/0/rollback/com.foo",
- create_data_misc_ce_rollback_package_path(nullptr, 0, "com.foo", 0));
- EXPECT_EQ("/data/misc_ce/0/rollback/com.foo",
- create_data_misc_ce_rollback_package_path(nullptr, 0, "com.foo", 239));
+ EXPECT_EQ("/data/misc_ce/0/rollback/17/com.foo",
+ create_data_misc_ce_rollback_package_path(nullptr, 0, 17, "com.foo", 0));
+ EXPECT_EQ("/data/misc_ce/0/rollback/19/com.foo",
+ create_data_misc_ce_rollback_package_path(nullptr, 0, 19, "com.foo", 239));
- auto rollback_ce_package_path = create_data_misc_ce_rollback_package_path(nullptr, 0, "com.foo");
- auto deleter = [&rollback_ce_package_path]() {
- delete_dir_contents_and_dir(rollback_ce_package_path, true /* ignore_if_missing */);
+ auto rollback_ce_path = create_data_misc_ce_rollback_path(nullptr, 0, 53);
+ auto rollback_ce_package_path = create_data_misc_ce_rollback_package_path(nullptr, 0, 53,
+ "com.foo");
+ auto deleter = [&rollback_ce_path]() {
+ delete_dir_contents_and_dir(rollback_ce_path, true /* ignore_if_missing */);
};
auto scope_guard = android::base::make_scope_guard(deleter);
- ASSERT_NE(-1, mkdir(rollback_ce_package_path.c_str(), 700));
+ EXPECT_NE(-1, mkdir(rollback_ce_path.c_str(), 700));
+ EXPECT_NE(-1, mkdir(rollback_ce_package_path.c_str(), 700));
ino_t ce_data_inode;
- ASSERT_EQ(0, get_path_inode(rollback_ce_package_path, &ce_data_inode));
+ EXPECT_EQ(0, get_path_inode(rollback_ce_package_path, &ce_data_inode));
- EXPECT_EQ("/data/misc_ce/0/rollback/com.foo",
- create_data_misc_ce_rollback_package_path(nullptr, 0, "com.foo", ce_data_inode));
+ EXPECT_EQ("/data/misc_ce/0/rollback/53/com.foo",
+ create_data_misc_ce_rollback_package_path(nullptr, 0, 53, "com.foo", ce_data_inode));
// Check that path defined by inode is picked even if it's not the same as
// the fallback one.
- EXPECT_EQ("/data/misc_ce/0/rollback/com.foo",
- create_data_misc_ce_rollback_package_path(nullptr, 0, "com.bar", ce_data_inode));
+ EXPECT_EQ("/data/misc_ce/0/rollback/53/com.foo",
+ create_data_misc_ce_rollback_package_path(nullptr, 0, 53, "com.bar", ce_data_inode));
// These last couple of cases are never exercised in production because we
// only snapshot apps in the primary data partition. Exercise them here for
// the sake of completeness.
- EXPECT_EQ("/mnt/expand/57f8f4bc-abf4-655f-bf67-946fc0f9f25b/misc_ce/0/rollback/com.example",
- create_data_misc_ce_rollback_package_path("57f8f4bc-abf4-655f-bf67-946fc0f9f25b", 0, "com.example"));
- EXPECT_EQ("/mnt/expand/57f8f4bc-abf4-655f-bf67-946fc0f9f25b/misc_de/0/rollback/com.example",
- create_data_misc_de_rollback_package_path("57f8f4bc-abf4-655f-bf67-946fc0f9f25b", 0, "com.example"));
+ EXPECT_EQ("/mnt/expand/57f8f4bc-abf4-655f-bf67-946fc0f9f25b/misc_ce/0/rollback/7/com.example",
+ create_data_misc_ce_rollback_package_path("57f8f4bc-abf4-655f-bf67-946fc0f9f25b", 0, 7,
+ "com.example"));
+ EXPECT_EQ("/mnt/expand/57f8f4bc-abf4-655f-bf67-946fc0f9f25b/misc_de/0/rollback/11/com.example",
+ create_data_misc_de_rollback_package_path("57f8f4bc-abf4-655f-bf67-946fc0f9f25b", 0, 11,
+ "com.example"));
+}
+
+TEST_F(UtilsTest, TestCreateDirIfNeeded) {
+ system("mkdir -p /data/local/tmp/user/0");
+
+ auto deleter = [&]() {
+ delete_dir_contents_and_dir("/data/local/tmp/user/0", true /* ignore_if_missing */);
+ };
+ auto scope_guard = android::base::make_scope_guard(deleter);
+
+ // Create folder and check it's permissions.
+ ASSERT_EQ(0, create_dir_if_needed("/data/local/tmp/user/0/foo", 0700));
+ struct stat st;
+ ASSERT_EQ(0, stat("/data/local/tmp/user/0/foo", &st));
+ ASSERT_EQ(0700, st.st_mode & ALLPERMS);
+
+ // Check that create_dir_if_needed is no-op if folder already exists with
+ // correct permissions.
+ ASSERT_EQ(0, create_dir_if_needed("/data/local/tmp/user/0/foo", 0700));
+
+ // Check -1 is returned if folder exists but with different permissions.
+ ASSERT_EQ(-1, create_dir_if_needed("/data/local/tmp/user/0/foo", 0750));
+
+ // Check that call fails if parent doesn't exist.
+ ASSERT_NE(0, create_dir_if_needed("/data/local/tmp/user/0/bar/baz", 0700));
}
} // namespace installd
diff --git a/cmds/installd/utils.cpp b/cmds/installd/utils.cpp
index 5b487bb..52ca0df 100644
--- a/cmds/installd/utils.cpp
+++ b/cmds/installd/utils.cpp
@@ -197,32 +197,44 @@
return StringPrintf("%s/user_de/%u", data.c_str(), userid);
}
-
-std::string create_data_misc_ce_rollback_path(const char* volume_uuid, userid_t user) {
+std::string create_data_misc_ce_rollback_base_path(const char* volume_uuid, userid_t user) {
return StringPrintf("%s/misc_ce/%u/rollback", create_data_path(volume_uuid).c_str(), user);
}
-std::string create_data_misc_de_rollback_path(const char* volume_uuid, userid_t user) {
+std::string create_data_misc_de_rollback_base_path(const char* volume_uuid, userid_t user) {
return StringPrintf("%s/misc_de/%u/rollback", create_data_path(volume_uuid).c_str(), user);
}
-std::string create_data_misc_ce_rollback_package_path(const char* volume_uuid,
- userid_t user, const char* package_name) {
- return StringPrintf("%s/%s",
- create_data_misc_ce_rollback_path(volume_uuid, user).c_str(), package_name);
+std::string create_data_misc_ce_rollback_path(const char* volume_uuid, userid_t user,
+ int32_t snapshot_id) {
+ return StringPrintf("%s/%d", create_data_misc_ce_rollback_base_path(volume_uuid, user).c_str(),
+ snapshot_id);
+}
+
+std::string create_data_misc_de_rollback_path(const char* volume_uuid, userid_t user,
+ int32_t snapshot_id) {
+ return StringPrintf("%s/%d", create_data_misc_de_rollback_base_path(volume_uuid, user).c_str(),
+ snapshot_id);
}
std::string create_data_misc_ce_rollback_package_path(const char* volume_uuid,
- userid_t user, const char* package_name, ino_t ce_rollback_inode) {
- auto fallback = create_data_misc_ce_rollback_package_path(volume_uuid, user, package_name);
- auto user_path = create_data_misc_ce_rollback_path(volume_uuid, user);
+ userid_t user, int32_t snapshot_id, const char* package_name) {
+ return StringPrintf("%s/%s",
+ create_data_misc_ce_rollback_path(volume_uuid, user, snapshot_id).c_str(), package_name);
+}
+
+std::string create_data_misc_ce_rollback_package_path(const char* volume_uuid,
+ userid_t user, int32_t snapshot_id, const char* package_name, ino_t ce_rollback_inode) {
+ auto fallback = create_data_misc_ce_rollback_package_path(volume_uuid, user, snapshot_id,
+ package_name);
+ auto user_path = create_data_misc_ce_rollback_path(volume_uuid, user, snapshot_id);
return resolve_ce_path_by_inode_or_fallback(user_path, ce_rollback_inode, fallback);
}
std::string create_data_misc_de_rollback_package_path(const char* volume_uuid,
- userid_t user, const char* package_name) {
+ userid_t user, int32_t snapshot_id, const char* package_name) {
return StringPrintf("%s/%s",
- create_data_misc_de_rollback_path(volume_uuid, user).c_str(), package_name);
+ create_data_misc_de_rollback_path(volume_uuid, user, snapshot_id).c_str(), package_name);
}
/**
@@ -528,6 +540,30 @@
return result;
}
+int create_dir_if_needed(const std::string& pathname, mode_t perms) {
+ struct stat st;
+
+ int rc;
+ if ((rc = stat(pathname.c_str(), &st)) != 0) {
+ if (errno == ENOENT) {
+ return mkdir(pathname.c_str(), perms);
+ } else {
+ return rc;
+ }
+ } else if (!S_ISDIR(st.st_mode)) {
+ LOG(DEBUG) << pathname << " is not a folder";
+ return -1;
+ }
+
+ mode_t actual_perms = st.st_mode & ALLPERMS;
+ if (actual_perms != perms) {
+ LOG(WARNING) << pathname << " permissions " << actual_perms << " expected " << perms;
+ return -1;
+ }
+
+ return 0;
+}
+
int delete_dir_contents(const std::string& pathname, bool ignore_if_missing) {
return delete_dir_contents(pathname.c_str(), 0, nullptr, ignore_if_missing);
}
diff --git a/cmds/installd/utils.h b/cmds/installd/utils.h
index 0711b34..955d524 100644
--- a/cmds/installd/utils.h
+++ b/cmds/installd/utils.h
@@ -61,14 +61,18 @@
std::string create_data_user_ce_package_path_as_user_link(
const char* volume_uuid, userid_t userid, const char* package_name);
-std::string create_data_misc_ce_rollback_path(const char* volume_uuid, userid_t user);
-std::string create_data_misc_de_rollback_path(const char* volume_uuid, userid_t user);
+std::string create_data_misc_ce_rollback_base_path(const char* volume_uuid, userid_t user);
+std::string create_data_misc_de_rollback_base_path(const char* volume_uuid, userid_t user);
+std::string create_data_misc_ce_rollback_path(const char* volume_uuid, userid_t user,
+ int32_t snapshot_id);
+std::string create_data_misc_de_rollback_path(const char* volume_uuid, userid_t user,
+ int32_t snapshot_id);
std::string create_data_misc_ce_rollback_package_path(const char* volume_uuid,
- userid_t user, const char* package_name);
+ userid_t user, int32_t snapshot_id, const char* package_name);
std::string create_data_misc_ce_rollback_package_path(const char* volume_uuid,
- userid_t user, const char* package_name, ino_t ce_rollback_inode);
+ userid_t user, int32_t snapshot_id, const char* package_name, ino_t ce_rollback_inode);
std::string create_data_misc_de_rollback_package_path(const char* volume_uuid,
- userid_t user, const char* package_name);
+ userid_t user, int32_t snapshot_id, const char* package_name);
std::string create_data_media_path(const char* volume_uuid, userid_t userid);
std::string create_data_media_obb_path(const char* volume_uuid, const char* package_name);
@@ -109,6 +113,8 @@
bool is_valid_filename(const std::string& name);
bool is_valid_package_name(const std::string& packageName);
+int create_dir_if_needed(const std::string& pathname, mode_t mode);
+
int delete_dir_contents(const std::string& pathname, bool ignore_if_missing = false);
int delete_dir_contents_and_dir(const std::string& pathname, bool ignore_if_missing = false);
diff --git a/include/input/IInputFlinger.h b/include/input/IInputFlinger.h
index ff443c6..cd12fcd 100644
--- a/include/input/IInputFlinger.h
+++ b/include/input/IInputFlinger.h
@@ -24,6 +24,7 @@
#include <utils/Vector.h>
#include <input/InputWindow.h>
+#include <input/ISetInputWindowsListener.h>
namespace android {
@@ -35,7 +36,8 @@
public:
DECLARE_META_INTERFACE(InputFlinger)
- virtual void setInputWindows(const Vector<InputWindowInfo>& inputHandles) = 0;
+ virtual void setInputWindows(const Vector<InputWindowInfo>& inputHandles,
+ const sp<ISetInputWindowsListener>& setInputWindowsListener) = 0;
virtual void transferTouchFocus(const sp<IBinder>& fromToken, const sp<IBinder>& toToken) = 0;
virtual void registerInputChannel(const sp<InputChannel>& channel) = 0;
virtual void unregisterInputChannel(const sp<InputChannel>& channel) = 0;
diff --git a/include/input/ISetInputWindowsListener.h b/include/input/ISetInputWindowsListener.h
new file mode 100644
index 0000000..15d31b2
--- /dev/null
+++ b/include/input/ISetInputWindowsListener.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <binder/IInterface.h>
+#include <binder/Parcel.h>
+
+namespace android {
+
+class ISetInputWindowsListener : public IInterface {
+public:
+ DECLARE_META_INTERFACE(SetInputWindowsListener)
+ virtual void onSetInputWindowsFinished() = 0;
+};
+
+class BnSetInputWindowsListener: public BnInterface<ISetInputWindowsListener> {
+public:
+ enum SetInputWindowsTag : uint32_t {
+ ON_SET_INPUT_WINDOWS_FINISHED
+ };
+
+ virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply,
+ uint32_t flags = 0) override;
+};
+
+}; // namespace android
diff --git a/include/input/InputDevice.h b/include/input/InputDevice.h
index ce8db91..48ac88d 100644
--- a/include/input/InputDevice.h
+++ b/include/input/InputDevice.h
@@ -51,6 +51,15 @@
// is intended to be a minimum way to distinguish from other active devices and may
// reuse values that are not associated with an input anymore.
uint16_t nonce;
+
+ /**
+ * Return InputDeviceIdentifier.name that has been adjusted as follows:
+ * - all characters besides alphanumerics, dash,
+ * and underscore have been replaced with underscores.
+ * This helps in situations where a file that matches the device name is needed,
+ * while conforming to the filename limitations.
+ */
+ std::string getCanonicalName() const;
};
/*
diff --git a/include/input/Keyboard.h b/include/input/Keyboard.h
index 8b66f69..92da10c 100644
--- a/include/input/Keyboard.h
+++ b/include/input/Keyboard.h
@@ -25,15 +25,6 @@
namespace android {
-enum {
- /* Device id of the built in keyboard. */
- DEVICE_ID_BUILT_IN_KEYBOARD = 0,
-
- /* Device id of a generic virtual keyboard with a full layout that can be used
- * to synthesize key events. */
- DEVICE_ID_VIRTUAL_KEYBOARD = -1,
-};
-
class KeyLayoutMap;
class KeyCharacterMap;
diff --git a/include/input/TouchVideoFrame.h b/include/input/TouchVideoFrame.h
index 640bf1f..b49c623 100644
--- a/include/input/TouchVideoFrame.h
+++ b/include/input/TouchVideoFrame.h
@@ -19,6 +19,7 @@
#include <stdint.h>
#include <sys/time.h>
+#include <ui/DisplayInfo.h>
#include <vector>
namespace android {
@@ -30,44 +31,48 @@
*/
class TouchVideoFrame {
public:
- TouchVideoFrame(uint32_t width, uint32_t height, std::vector<int16_t> data,
- const struct timeval& timestamp) :
- mWidth(width), mHeight(height), mData(std::move(data)), mTimestamp(timestamp) {
- }
+ TouchVideoFrame(uint32_t height, uint32_t width, std::vector<int16_t> data,
+ const struct timeval& 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;
- }
+ bool operator==(const TouchVideoFrame& rhs) const;
/**
- * Width of the frame
- */
- uint32_t getWidth() const { return mWidth; }
- /**
* Height of the frame
*/
- uint32_t getHeight() const { return mHeight; }
+ uint32_t getHeight() const;
+ /**
+ * Width of the frame
+ */
+ uint32_t getWidth() const;
/**
* The touch strength data.
* The array is a 2-D row-major matrix, with dimensions (height, width).
* Total size of the array should equal getHeight() * getWidth().
* Data is allowed to be negative.
*/
- const std::vector<int16_t>& getData() const { return mData; }
+ const std::vector<int16_t>& getData() const;
/**
* Time at which the heatmap was taken.
*/
- const struct timeval& getTimestamp() const { return mTimestamp; }
+ const struct timeval& getTimestamp() const;
+
+ /**
+ * Rotate the video frame.
+ * The rotation value is an enum from ui/DisplayInfo.h
+ */
+ void rotate(int32_t orientation);
private:
- uint32_t mWidth;
uint32_t mHeight;
+ uint32_t mWidth;
std::vector<int16_t> mData;
struct timeval mTimestamp;
+
+ /**
+ * Common method for 90 degree and 270 degree rotation
+ */
+ void rotateQuarterTurn(bool clockwise);
+ void rotate180();
};
} // namespace android
diff --git a/include/input/VirtualKeyMap.h b/include/input/VirtualKeyMap.h
index 24e0e0e..4f7cfb6 100644
--- a/include/input/VirtualKeyMap.h
+++ b/include/input/VirtualKeyMap.h
@@ -49,7 +49,7 @@
public:
~VirtualKeyMap();
- static status_t load(const std::string& filename, VirtualKeyMap** outMap);
+ static std::unique_ptr<VirtualKeyMap> load(const std::string& filename);
inline const Vector<VirtualKeyDefinition>& getVirtualKeys() const {
return mVirtualKeys;
diff --git a/libs/binder/ndk/include_apex/android/binder_manager.h b/libs/binder/ndk/include_apex/android/binder_manager.h
index 80b6c07..055c79b 100644
--- a/libs/binder/ndk/include_apex/android/binder_manager.h
+++ b/libs/binder/ndk/include_apex/android/binder_manager.h
@@ -33,6 +33,15 @@
binder_status_t AServiceManager_addService(AIBinder* binder, const char* instance);
/**
+ * Gets a binder object with this specific instance name. Will return nullptr immediately if the
+ * service is not available This also implicitly calls AIBinder_incStrong (so the caller of this
+ * function is responsible for calling AIBinder_decStrong).
+ *
+ * \param instance identifier of the service used to lookup the service.
+ */
+__attribute__((warn_unused_result)) AIBinder* AServiceManager_checkService(const char* instance);
+
+/**
* Gets a binder object with this specific instance name. Blocks for a couple of seconds waiting on
* it. This also implicitly calls AIBinder_incStrong (so the caller of this function is responsible
* for calling AIBinder_decStrong).
diff --git a/libs/binder/ndk/libbinder_ndk.map.txt b/libs/binder/ndk/libbinder_ndk.map.txt
index f0d25f7..655f4d5 100644
--- a/libs/binder/ndk/libbinder_ndk.map.txt
+++ b/libs/binder/ndk/libbinder_ndk.map.txt
@@ -91,6 +91,7 @@
ABinderProcess_setThreadPoolMaxThreadCount; # apex
ABinderProcess_startThreadPool; # apex
AServiceManager_addService; # apex
+ AServiceManager_checkService; # apex
AServiceManager_getService; # apex
local:
*;
diff --git a/libs/binder/ndk/service_manager.cpp b/libs/binder/ndk/service_manager.cpp
index 9ddc555..d0b166d 100644
--- a/libs/binder/ndk/service_manager.cpp
+++ b/libs/binder/ndk/service_manager.cpp
@@ -37,6 +37,18 @@
status_t status = sm->addService(String16(instance), binder->getBinder());
return PruneStatusT(status);
}
+AIBinder* AServiceManager_checkService(const char* instance) {
+ if (instance == nullptr) {
+ return nullptr;
+ }
+
+ sp<IServiceManager> sm = defaultServiceManager();
+ sp<IBinder> binder = sm->checkService(String16(instance));
+
+ sp<AIBinder> ret = ABpBinder::lookupOrCreateFromBinder(binder);
+ AIBinder_incStrong(ret.get());
+ return ret.get();
+}
AIBinder* AServiceManager_getService(const char* instance) {
if (instance == nullptr) {
return nullptr;
diff --git a/libs/binder/ndk/test/main_client.cpp b/libs/binder/ndk/test/main_client.cpp
index c159d71..bff601e 100644
--- a/libs/binder/ndk/test/main_client.cpp
+++ b/libs/binder/ndk/test/main_client.cpp
@@ -35,6 +35,19 @@
// EXPECT_EQ(nullptr, foo.get());
// }
+TEST(NdkBinder, CheckServiceThatDoesntExist) {
+ AIBinder* binder = AServiceManager_checkService("asdfghkl;");
+ ASSERT_EQ(nullptr, binder);
+}
+
+TEST(NdkBinder, CheckServiceThatDoesExist) {
+ AIBinder* binder = AServiceManager_checkService(kExistingNonNdkService);
+ EXPECT_NE(nullptr, binder);
+ EXPECT_EQ(STATUS_OK, AIBinder_ping(binder));
+
+ AIBinder_decStrong(binder);
+}
+
TEST(NdkBinder, DoubleNumber) {
sp<IFoo> foo = IFoo::getService(IFoo::kSomeInstanceName);
ASSERT_NE(foo, nullptr);
diff --git a/libs/graphicsenv/GraphicsEnv.cpp b/libs/graphicsenv/GraphicsEnv.cpp
index 75fe2d3..13c0d87 100644
--- a/libs/graphicsenv/GraphicsEnv.cpp
+++ b/libs/graphicsenv/GraphicsEnv.cpp
@@ -146,38 +146,119 @@
return 0;
}
-void GraphicsEnv::setDriverPath(const std::string path) {
- if (!mDriverPath.empty()) {
- ALOGV("ignoring attempt to change driver path from '%s' to '%s'", mDriverPath.c_str(),
- path.c_str());
+void GraphicsEnv::setDriverPathAndSphalLibraries(const std::string path,
+ const std::string sphalLibraries) {
+ if (!mDriverPath.empty() || !mSphalLibraries.empty()) {
+ ALOGV("ignoring attempt to change driver path from '%s' to '%s' or change sphal libraries "
+ "from '%s' to '%s'",
+ mDriverPath.c_str(), path.c_str(), mSphalLibraries.c_str(), sphalLibraries.c_str());
return;
}
- ALOGV("setting driver path to '%s'", path.c_str());
+ ALOGV("setting driver path to '%s' and sphal libraries to '%s'", path.c_str(),
+ sphalLibraries.c_str());
mDriverPath = path;
+ mSphalLibraries = sphalLibraries;
}
void GraphicsEnv::setGpuStats(const std::string& driverPackageName,
- const std::string& driverVersionName,
- const uint64_t driverVersionCode, const std::string& appPackageName) {
+ const std::string& driverVersionName, uint64_t driverVersionCode,
+ int64_t driverBuildTime, const std::string& appPackageName) {
ATRACE_CALL();
+ std::lock_guard<std::mutex> lock(mStatsLock);
ALOGV("setGpuStats:\n"
"\tdriverPackageName[%s]\n"
"\tdriverVersionName[%s]\n"
- "\tdriverVersionCode[%llu]\n"
+ "\tdriverVersionCode[%" PRIu64 "]\n"
+ "\tdriverBuildTime[%" PRId64 "]\n"
"\tappPackageName[%s]\n",
- driverPackageName.c_str(), driverVersionName.c_str(),
- (unsigned long long)driverVersionCode, appPackageName.c_str());
+ driverPackageName.c_str(), driverVersionName.c_str(), driverVersionCode, driverBuildTime,
+ appPackageName.c_str());
- mGpuStats = {
- .driverPackageName = driverPackageName,
- .driverVersionName = driverVersionName,
- .driverVersionCode = driverVersionCode,
- .appPackageName = appPackageName,
- };
+ mGpuStats.driverPackageName = driverPackageName;
+ mGpuStats.driverVersionName = driverVersionName;
+ mGpuStats.driverVersionCode = driverVersionCode;
+ mGpuStats.driverBuildTime = driverBuildTime;
+ mGpuStats.appPackageName = appPackageName;
}
-void GraphicsEnv::sendGpuStats() {
+void GraphicsEnv::setDriverToLoad(GraphicsEnv::Driver driver) {
+ ATRACE_CALL();
+
+ std::lock_guard<std::mutex> lock(mStatsLock);
+ switch (driver) {
+ case GraphicsEnv::Driver::GL:
+ case GraphicsEnv::Driver::GL_UPDATED:
+ case GraphicsEnv::Driver::ANGLE: {
+ if (mGpuStats.glDriverToLoad == GraphicsEnv::Driver::NONE) {
+ mGpuStats.glDriverToLoad = driver;
+ break;
+ }
+
+ if (mGpuStats.glDriverFallback == GraphicsEnv::Driver::NONE) {
+ mGpuStats.glDriverFallback = driver;
+ }
+ break;
+ }
+ case Driver::VULKAN:
+ case Driver::VULKAN_UPDATED: {
+ if (mGpuStats.vkDriverToLoad == GraphicsEnv::Driver::NONE) {
+ mGpuStats.vkDriverToLoad = driver;
+ break;
+ }
+
+ if (mGpuStats.vkDriverFallback == GraphicsEnv::Driver::NONE) {
+ mGpuStats.vkDriverFallback = driver;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+void GraphicsEnv::setDriverLoaded(GraphicsEnv::Api api, bool isLoaded, int64_t driverLoadingTime) {
+ ATRACE_CALL();
+
+ std::lock_guard<std::mutex> lock(mStatsLock);
+ GraphicsEnv::Driver driver = GraphicsEnv::Driver::NONE;
+ bool isIntendedDriverLoaded = false;
+ if (api == GraphicsEnv::Api::API_GL) {
+ driver = mGpuStats.glDriverToLoad;
+ isIntendedDriverLoaded = isLoaded &&
+ ((mGpuStats.glDriverFallback == GraphicsEnv::Driver::NONE) ||
+ (mGpuStats.glDriverToLoad == mGpuStats.glDriverFallback));
+ } else {
+ driver = mGpuStats.vkDriverToLoad;
+ isIntendedDriverLoaded =
+ isLoaded && (mGpuStats.vkDriverFallback == GraphicsEnv::Driver::NONE);
+ }
+
+ sendGpuStatsLocked(driver, isIntendedDriverLoaded, driverLoadingTime);
+}
+
+void GraphicsEnv::clearDriverLoadingInfo(GraphicsEnv::Api api) {
+ ATRACE_CALL();
+
+ std::lock_guard<std::mutex> lock(mStatsLock);
+ if (api == GraphicsEnv::Api::API_GL) {
+ mGpuStats.glDriverToLoad = GraphicsEnv::Driver::NONE;
+ mGpuStats.glDriverFallback = GraphicsEnv::Driver::NONE;
+ }
+}
+
+static sp<IGpuService> getGpuService() {
+ const sp<IBinder> binder = defaultServiceManager()->checkService(String16("gpu"));
+ if (!binder) {
+ ALOGE("Failed to get gpu service");
+ return nullptr;
+ }
+
+ return interface_cast<IGpuService>(binder);
+}
+
+void GraphicsEnv::sendGpuStatsLocked(GraphicsEnv::Driver driver, bool isDriverLoaded,
+ int64_t driverLoadingTime) {
ATRACE_CALL();
// Do not sendGpuStats for those skipping the GraphicsEnvironment setup
@@ -186,21 +267,23 @@
ALOGV("sendGpuStats:\n"
"\tdriverPackageName[%s]\n"
"\tdriverVersionName[%s]\n"
- "\tdriverVersionCode[%llu]\n"
- "\tappPackageName[%s]\n",
+ "\tdriverVersionCode[%" PRIu64 "]\n"
+ "\tdriverBuildTime[%" PRId64 "]\n"
+ "\tappPackageName[%s]\n"
+ "\tdriver[%d]\n"
+ "\tisDriverLoaded[%d]\n"
+ "\tdriverLoadingTime[%" PRId64 "]",
mGpuStats.driverPackageName.c_str(), mGpuStats.driverVersionName.c_str(),
- (unsigned long long)mGpuStats.driverVersionCode, mGpuStats.appPackageName.c_str());
+ mGpuStats.driverVersionCode, mGpuStats.driverBuildTime, mGpuStats.appPackageName.c_str(),
+ static_cast<int32_t>(driver), isDriverLoaded, driverLoadingTime);
- const sp<IBinder> binder = defaultServiceManager()->checkService(String16("gpu"));
- if (!binder) {
- ALOGE("Failed to get gpu service for [%s]", mGpuStats.appPackageName.c_str());
- return;
+ const sp<IGpuService> gpuService = getGpuService();
+ if (gpuService) {
+ gpuService->setGpuStats(mGpuStats.driverPackageName, mGpuStats.driverVersionName,
+ mGpuStats.driverVersionCode, mGpuStats.driverBuildTime,
+ mGpuStats.appPackageName, driver, isDriverLoaded,
+ driverLoadingTime);
}
-
- interface_cast<IGpuService>(binder)->setGpuStats(mGpuStats.driverPackageName,
- mGpuStats.driverVersionName,
- mGpuStats.driverVersionCode,
- mGpuStats.appPackageName);
}
void* GraphicsEnv::loadLibrary(std::string name) {
@@ -457,6 +540,23 @@
mDriverNamespace = nullptr;
return;
}
+
+ if (mSphalLibraries.empty()) return;
+
+ // Make additional libraries in sphal to be accessible
+ auto sphalNamespace = android_get_exported_namespace("sphal");
+ if (!sphalNamespace) {
+ ALOGE("Depend on these libraries[%s] in sphal, but failed to get sphal namespace",
+ mSphalLibraries.c_str());
+ mDriverNamespace = nullptr;
+ return;
+ }
+
+ if (!android_link_namespaces(mDriverNamespace, sphalNamespace, mSphalLibraries.c_str())) {
+ ALOGE("Failed to link sphal namespace[%s]", dlerror());
+ mDriverNamespace = nullptr;
+ return;
+ }
});
return mDriverNamespace;
diff --git a/libs/graphicsenv/IGpuService.cpp b/libs/graphicsenv/IGpuService.cpp
index 762a27b..f755e00 100644
--- a/libs/graphicsenv/IGpuService.cpp
+++ b/libs/graphicsenv/IGpuService.cpp
@@ -28,17 +28,23 @@
explicit BpGpuService(const sp<IBinder>& impl) : BpInterface<IGpuService>(impl) {}
virtual void setGpuStats(const std::string& driverPackageName,
- const std::string& driverVersionName, const uint64_t driverVersionCode,
- const std::string& appPackageName) {
+ const std::string& driverVersionName, uint64_t driverVersionCode,
+ int64_t driverBuildTime, const std::string& appPackageName,
+ GraphicsEnv::Driver driver, bool isDriverLoaded,
+ int64_t driverLoadingTime) {
Parcel data, reply;
data.writeInterfaceToken(IGpuService::getInterfaceDescriptor());
data.writeUtf8AsUtf16(driverPackageName);
data.writeUtf8AsUtf16(driverVersionName);
data.writeUint64(driverVersionCode);
+ data.writeInt64(driverBuildTime);
data.writeUtf8AsUtf16(appPackageName);
+ data.writeInt32(static_cast<int32_t>(driver));
+ data.writeBool(isDriverLoaded);
+ data.writeInt64(driverLoadingTime);
- remote()->transact(BnGpuService::SET_GPU_STATS, data, &reply);
+ remote()->transact(BnGpuService::SET_GPU_STATS, data, &reply, IBinder::FLAG_ONEWAY);
}
};
@@ -62,10 +68,24 @@
uint64_t driverVersionCode;
if ((status = data.readUint64(&driverVersionCode)) != OK) return status;
+ int64_t driverBuildTime;
+ if ((status = data.readInt64(&driverBuildTime)) != OK) return status;
+
std::string appPackageName;
if ((status = data.readUtf8FromUtf16(&appPackageName)) != OK) return status;
- setGpuStats(driverPackageName, driverVersionName, driverVersionCode, appPackageName);
+ int32_t driver;
+ if ((status = data.readInt32(&driver)) != OK) return status;
+
+ bool isDriverLoaded;
+ if ((status = data.readBool(&isDriverLoaded)) != OK) return status;
+
+ int64_t driverLoadingTime;
+ if ((status = data.readInt64(&driverLoadingTime)) != OK) return status;
+
+ setGpuStats(driverPackageName, driverVersionName, driverVersionCode, driverBuildTime,
+ appPackageName, static_cast<GraphicsEnv::Driver>(driver), isDriverLoaded,
+ driverLoadingTime);
return OK;
}
diff --git a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
index c4482b7..cb4239f 100644
--- a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
+++ b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
@@ -28,11 +28,43 @@
struct NativeLoaderNamespace;
class GraphicsEnv {
+public:
+ enum Api {
+ API_GL = 0,
+ API_VK = 1,
+ };
+
+ enum Driver {
+ NONE = 0,
+ GL = 1,
+ GL_UPDATED = 2,
+ VULKAN = 3,
+ VULKAN_UPDATED = 4,
+ ANGLE = 5,
+ };
+
+private:
struct GpuStats {
std::string driverPackageName;
std::string driverVersionName;
uint64_t driverVersionCode;
+ int64_t driverBuildTime;
std::string appPackageName;
+ Driver glDriverToLoad;
+ Driver glDriverFallback;
+ Driver vkDriverToLoad;
+ Driver vkDriverFallback;
+
+ GpuStats()
+ : driverPackageName(""),
+ driverVersionName(""),
+ driverVersionCode(0),
+ driverBuildTime(0),
+ appPackageName(""),
+ glDriverToLoad(Driver::NONE),
+ glDriverFallback(Driver::NONE),
+ vkDriverToLoad(Driver::NONE),
+ vkDriverFallback(Driver::NONE) {}
};
public:
@@ -45,11 +77,18 @@
// (drivers must be stored uncompressed and page aligned); such elements
// in the search path must have a '!' after the zip filename, e.g.
// /data/app/com.example.driver/base.apk!/lib/arm64-v8a
- void setDriverPath(const std::string path);
+ // Also set additional required sphal libraries to the linker for loading
+ // graphics drivers. The string is a list of libraries separated by ':',
+ // which is required by android_link_namespaces.
+ void setDriverPathAndSphalLibraries(const std::string path, const std::string sphalLibraries);
android_namespace_t* getDriverNamespace();
void setGpuStats(const std::string& driverPackageName, const std::string& driverVersionName,
- const uint64_t versionCode, const std::string& appPackageName);
- void sendGpuStats();
+ uint64_t versionCode, int64_t driverBuildTime,
+ const std::string& appPackageName);
+ void setDriverToLoad(Driver driver);
+ void setDriverLoaded(Api api, bool isDriverLoaded, int64_t driverLoadingTime);
+ void clearDriverLoadingInfo(Api api);
+ void sendGpuStatsLocked(Driver driver, bool isDriverLoaded, int64_t driverLoadingTime);
bool shouldUseAngle(std::string appName);
bool shouldUseAngle();
@@ -82,6 +121,8 @@
GraphicsEnv() = default;
std::string mDriverPath;
+ std::string mSphalLibraries;
+ std::mutex mStatsLock;
GpuStats mGpuStats;
std::string mAnglePath;
std::string mAngleAppName;
diff --git a/libs/graphicsenv/include/graphicsenv/IGpuService.h b/libs/graphicsenv/include/graphicsenv/IGpuService.h
index 1e74d60..5f9340d 100644
--- a/libs/graphicsenv/include/graphicsenv/IGpuService.h
+++ b/libs/graphicsenv/include/graphicsenv/IGpuService.h
@@ -18,6 +18,7 @@
#include <binder/IInterface.h>
#include <cutils/compiler.h>
+#include <graphicsenv/GraphicsEnv.h>
#include <vector>
@@ -29,12 +30,14 @@
*/
class IGpuService : public IInterface {
public:
- DECLARE_META_INTERFACE(GpuService);
+ DECLARE_META_INTERFACE(GpuService)
// set GPU stats from GraphicsEnvironment.
virtual void setGpuStats(const std::string& driverPackageName,
- const std::string& driverVersionName, const uint64_t driverVersionCode,
- const std::string& appPackageName) = 0;
+ const std::string& driverVersionName, uint64_t driverVersionCode,
+ int64_t driverBuildTime, const std::string& appPackageName,
+ GraphicsEnv::Driver driver, bool isDriverLoaded,
+ int64_t driverLoadingTime) = 0;
};
class BnGpuService : public BnInterface<IGpuService> {
diff --git a/libs/gui/IGraphicBufferProducer.cpp b/libs/gui/IGraphicBufferProducer.cpp
index d997674..8907de4 100644
--- a/libs/gui/IGraphicBufferProducer.cpp
+++ b/libs/gui/IGraphicBufferProducer.cpp
@@ -651,7 +651,7 @@
}
};
-IMPLEMENT_HYBRID_META_INTERFACE(GraphicBufferProducer, HGraphicBufferProducer,
+IMPLEMENT_HYBRID_META_INTERFACE(GraphicBufferProducer,
"android.gui.IGraphicBufferProducer");
// ----------------------------------------------------------------------
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index 206bc30..962d263 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -414,10 +414,13 @@
.insert(transferTouchFocusCommands.end(),
std::make_move_iterator(other.transferTouchFocusCommands.begin()),
std::make_move_iterator(other.transferTouchFocusCommands.end()));
+
+ syncInputWindows |= other.syncInputWindows;
}
void InputWindowCommands::clear() {
transferTouchFocusCommands.clear();
+ syncInputWindows = false;
}
void InputWindowCommands::write(Parcel& output) const {
@@ -426,6 +429,8 @@
output.writeStrongBinder(transferTouchFocusCommand.fromToken);
output.writeStrongBinder(transferTouchFocusCommand.toToken);
}
+
+ output.writeBool(syncInputWindows);
}
void InputWindowCommands::read(const Parcel& input) {
@@ -437,6 +442,8 @@
transferTouchFocusCommand.toToken = input.readStrongBinder();
transferTouchFocusCommands.emplace_back(transferTouchFocusCommand);
}
+
+ syncInputWindows = input.readBool();
}
}; // namespace android
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index bf2a03d..8c2538c 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -1083,6 +1083,11 @@
return *this;
}
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::syncInputWindows() {
+ mInputWindowCommands.syncInputWindows = true;
+ return *this;
+}
+
#endif
SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setColorTransform(
diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
index 1a0b6bb..e6700e7 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -406,6 +406,7 @@
GET_PHYSICAL_DISPLAY_IDS,
ADD_REGION_SAMPLING_LISTENER,
REMOVE_REGION_SAMPLING_LISTENER,
+
// Always append new enum to the end.
};
diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h
index c780c07..32d7391 100644
--- a/libs/gui/include/gui/LayerState.h
+++ b/libs/gui/include/gui/LayerState.h
@@ -254,6 +254,7 @@
};
std::vector<TransferTouchFocusCommand> transferTouchFocusCommands;
+ bool syncInputWindows{false};
void merge(const InputWindowCommands& other);
void clear();
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index aa99bd2..cb38209 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -378,6 +378,7 @@
#ifndef NO_INPUT
Transaction& setInputWindowInfo(const sp<SurfaceControl>& sc, const InputWindowInfo& info);
Transaction& transferTouchFocus(const sp<IBinder>& fromToken, const sp<IBinder>& toToken);
+ Transaction& syncInputWindows();
#endif
// Set a color transform matrix on the given layer on the built-in display.
diff --git a/libs/gui/include/gui/bufferqueue/1.0/H2BGraphicBufferProducer.h b/libs/gui/include/gui/bufferqueue/1.0/H2BGraphicBufferProducer.h
index c92fa9d..c4d0245 100644
--- a/libs/gui/include/gui/bufferqueue/1.0/H2BGraphicBufferProducer.h
+++ b/libs/gui/include/gui/bufferqueue/1.0/H2BGraphicBufferProducer.h
@@ -57,7 +57,6 @@
struct H2BGraphicBufferProducer : public ::android::H2BConverter<
HGraphicBufferProducer,
- BGraphicBufferProducer,
BnGraphicBufferProducer> {
explicit H2BGraphicBufferProducer(sp<HGraphicBufferProducer> const& base) : CBase(base) {}
diff --git a/libs/gui/tests/Android.bp b/libs/gui/tests/Android.bp
index f020a40..a5b87ec 100644
--- a/libs/gui/tests/Android.bp
+++ b/libs/gui/tests/Android.bp
@@ -87,3 +87,26 @@
"libdvr_headers",
],
}
+
+cc_test {
+ name: "SamplingDemo",
+
+ clang: true,
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
+
+ srcs: [
+ "SamplingDemo.cpp",
+ ],
+
+ shared_libs: [
+ "libbinder",
+ "libcutils",
+ "libgui",
+ "liblog",
+ "libui",
+ "libutils",
+ ]
+}
diff --git a/libs/gui/tests/SamplingDemo.cpp b/libs/gui/tests/SamplingDemo.cpp
new file mode 100644
index 0000000..9891587
--- /dev/null
+++ b/libs/gui/tests/SamplingDemo.cpp
@@ -0,0 +1,135 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+#define LOG_TAG "SamplingTest"
+
+#include <chrono>
+#include <thread>
+
+#include <binder/IPCThreadState.h>
+#include <binder/ProcessState.h>
+#include <gui/IRegionSamplingListener.h>
+#include <gui/ISurfaceComposer.h>
+#include <gui/SurfaceComposerClient.h>
+#include <gui/SurfaceControl.h>
+#include <private/gui/ComposerService.h>
+#include <utils/Trace.h>
+
+using namespace std::chrono_literals;
+
+namespace android {
+
+class Button : public BnRegionSamplingListener {
+public:
+ Button(const char* name, const Rect& samplingArea) {
+ sp<SurfaceComposerClient> client = new SurfaceComposerClient;
+
+ mButton = client->createSurface(String8(name), 0, 0, PIXEL_FORMAT_RGBA_8888,
+ ISurfaceComposerClient::eFXSurfaceColor);
+
+ const int32_t width = samplingArea.getWidth();
+ const int32_t height = samplingArea.getHeight();
+
+ SurfaceComposerClient::Transaction{}
+ .setLayer(mButton, 0x7fffffff)
+ .setCrop_legacy(mButton,
+ {0, 0, width - 2 * BUTTON_PADDING, height - 2 * BUTTON_PADDING})
+ .setPosition(mButton, samplingArea.left + BUTTON_PADDING,
+ samplingArea.top + BUTTON_PADDING)
+ .setColor(mButton, half3{1, 1, 1})
+ .show(mButton)
+ .apply();
+
+ mButtonBlend = client->createSurface(String8(name) + "Blend", 0, 0, PIXEL_FORMAT_RGBA_8888,
+ ISurfaceComposerClient::eFXSurfaceColor);
+
+ SurfaceComposerClient::Transaction{}
+ .setLayer(mButtonBlend, 0x7ffffffe)
+ .setCrop_legacy(mButtonBlend,
+ {0, 0, width - 2 * SAMPLE_AREA_PADDING,
+ height - 2 * SAMPLE_AREA_PADDING})
+ .setPosition(mButtonBlend, samplingArea.left + SAMPLE_AREA_PADDING,
+ samplingArea.top + SAMPLE_AREA_PADDING)
+ .setColor(mButtonBlend, half3{1, 1, 1})
+ .setAlpha(mButtonBlend, 0.2)
+ .show(mButtonBlend)
+ .apply(true);
+
+ const bool HIGHLIGHT_SAMPLING_AREA = false;
+ if (HIGHLIGHT_SAMPLING_AREA) {
+ mSamplingArea =
+ client->createSurface(String8("SamplingArea"), 0, 0, PIXEL_FORMAT_RGBA_8888,
+ ISurfaceComposerClient::eFXSurfaceColor);
+
+ SurfaceComposerClient::Transaction{}
+ .setLayer(mSamplingArea, 0x7ffffffd)
+ .setCrop_legacy(mSamplingArea, {0, 0, 100, 32})
+ .setPosition(mSamplingArea, 490, 1606)
+ .setColor(mSamplingArea, half3{0, 1, 0})
+ .setAlpha(mSamplingArea, 0.1)
+ .show(mSamplingArea)
+ .apply();
+ }
+ }
+
+ sp<IBinder> getStopLayerHandle() { return mButtonBlend->getHandle(); }
+
+private:
+ static const int32_t BLEND_WIDTH = 2;
+ static const int32_t SAMPLE_AREA_PADDING = 8;
+ static const int32_t BUTTON_PADDING = BLEND_WIDTH + SAMPLE_AREA_PADDING;
+
+ void setColor(float color) {
+ const float complement = std::fmod(color + 0.5f, 1.0f);
+ SurfaceComposerClient::Transaction{}
+ .setColor(mButton, half3{complement, complement, complement})
+ .setColor(mButtonBlend, half3{color, color, color})
+ .apply();
+ }
+
+ void onSampleCollected(float medianLuma) override {
+ ATRACE_CALL();
+ setColor(medianLuma);
+ }
+
+ sp<SurfaceComposerClient> mClient;
+ sp<SurfaceControl> mButton;
+ sp<SurfaceControl> mButtonBlend;
+ sp<SurfaceControl> mSamplingArea;
+};
+
+} // namespace android
+
+using namespace android;
+
+int main(int, const char**) {
+ const Rect homeButtonArea{490, 1606, 590, 1654};
+ sp<android::Button> homeButton = new android::Button("HomeButton", homeButtonArea);
+ const Rect backButtonArea{200, 1606, 248, 1654};
+ sp<android::Button> backButton = new android::Button("BackButton", backButtonArea);
+
+ sp<ISurfaceComposer> composer = ComposerService::getComposerService();
+ composer->addRegionSamplingListener(homeButtonArea, homeButton->getStopLayerHandle(),
+ homeButton);
+ composer->addRegionSamplingListener(backButtonArea, backButton->getStopLayerHandle(),
+ backButton);
+
+ ProcessState::self()->startThreadPool();
+ IPCThreadState::self()->joinThreadPool();
+
+ return 0;
+}
diff --git a/libs/input/Android.bp b/libs/input/Android.bp
index fc676f1..2d78811 100644
--- a/libs/input/Android.bp
+++ b/libs/input/Android.bp
@@ -28,6 +28,7 @@
"Keyboard.cpp",
"KeyCharacterMap.cpp",
"KeyLayoutMap.cpp",
+ "TouchVideoFrame.cpp",
"VirtualKeyMap.cpp",
],
@@ -42,12 +43,13 @@
target: {
android: {
srcs: [
+ "IInputFlinger.cpp",
+ "InputApplication.cpp",
"InputTransport.cpp",
+ "InputWindow.cpp",
+ "ISetInputWindowsListener.cpp",
"VelocityControl.cpp",
"VelocityTracker.cpp",
- "InputApplication.cpp",
- "InputWindow.cpp",
- "IInputFlinger.cpp"
],
shared_libs: [
diff --git a/libs/input/IInputFlinger.cpp b/libs/input/IInputFlinger.cpp
index acf40bc..4ce5a10 100644
--- a/libs/input/IInputFlinger.cpp
+++ b/libs/input/IInputFlinger.cpp
@@ -30,7 +30,8 @@
explicit BpInputFlinger(const sp<IBinder>& impl) :
BpInterface<IInputFlinger>(impl) { }
- virtual void setInputWindows(const Vector<InputWindowInfo>& inputInfo) {
+ virtual void setInputWindows(const Vector<InputWindowInfo>& inputInfo,
+ const sp<ISetInputWindowsListener>& setInputWindowsListener) {
Parcel data, reply;
data.writeInterfaceToken(IInputFlinger::getInterfaceDescriptor());
@@ -38,6 +39,8 @@
for (const auto& info : inputInfo) {
info.write(data);
}
+ data.writeStrongBinder(IInterface::asBinder(setInputWindowsListener));
+
remote()->transact(BnInputFlinger::SET_INPUT_WINDOWS_TRANSACTION, data, &reply,
IBinder::FLAG_ONEWAY);
}
@@ -83,7 +86,9 @@
for (size_t i = 0; i < count; i++) {
handles.add(InputWindowInfo(data));
}
- setInputWindows(handles);
+ const sp<ISetInputWindowsListener> setInputWindowsListener =
+ ISetInputWindowsListener::asInterface(data.readStrongBinder());
+ setInputWindows(handles, setInputWindowsListener);
break;
}
case REGISTER_INPUT_CHANNEL_TRANSACTION: {
diff --git a/libs/input/ISetInputWindowsListener.cpp b/libs/input/ISetInputWindowsListener.cpp
new file mode 100644
index 0000000..a0330da
--- /dev/null
+++ b/libs/input/ISetInputWindowsListener.cpp
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <input/ISetInputWindowsListener.h>
+
+namespace android {
+
+class BpSetInputWindowsListener : public BpInterface<ISetInputWindowsListener> {
+public:
+ explicit BpSetInputWindowsListener(const sp<IBinder>& impl)
+ : BpInterface<ISetInputWindowsListener>(impl) {
+ }
+
+ virtual ~BpSetInputWindowsListener() = default;
+
+ virtual void onSetInputWindowsFinished() {
+ Parcel data, reply;
+ data.writeInterfaceToken(ISetInputWindowsListener::getInterfaceDescriptor());
+ remote()->transact(BnSetInputWindowsListener::ON_SET_INPUT_WINDOWS_FINISHED, data, &reply,
+ IBinder::FLAG_ONEWAY);
+ }
+};
+
+IMPLEMENT_META_INTERFACE(SetInputWindowsListener, "android.input.ISetInputWindowsListener");
+
+status_t BnSetInputWindowsListener::onTransact(uint32_t code, const Parcel& data, Parcel* reply,
+ uint32_t flags) {
+ switch(code) {
+ case ON_SET_INPUT_WINDOWS_FINISHED: {
+ CHECK_INTERFACE(ISetInputWindowsListener, data, reply);
+ onSetInputWindowsFinished();
+ return NO_ERROR;
+ }
+ default: {
+ return BBinder::onTransact(code, data, reply, flags);
+ }
+ }
+}
+
+} // namespace android
diff --git a/libs/input/InputDevice.cpp b/libs/input/InputDevice.cpp
index 778c453..dab6eac 100644
--- a/libs/input/InputDevice.cpp
+++ b/libs/input/InputDevice.cpp
@@ -46,15 +46,9 @@
static void appendInputDeviceConfigurationFileRelativePath(std::string& path,
const std::string& name, InputDeviceConfigurationFileType type) {
- path.append(CONFIGURATION_FILE_DIR[type]);
- for (size_t i = 0; i < name.length(); i++) {
- char ch = name[i];
- if (!isValidNameChar(ch)) {
- ch = '_';
- }
- path.append(&ch, 1);
- }
- path.append(CONFIGURATION_FILE_EXTENSION[type]);
+ path += CONFIGURATION_FILE_DIR[type];
+ path += name;
+ path += CONFIGURATION_FILE_EXTENSION[type];
}
std::string getInputDeviceConfigurationFilePathByDeviceIdentifier(
@@ -84,7 +78,7 @@
}
// Try device name.
- return getInputDeviceConfigurationFilePathByName(deviceIdentifier.name, type);
+ return getInputDeviceConfigurationFilePathByName(deviceIdentifier.getCanonicalName(), type);
}
std::string getInputDeviceConfigurationFilePathByName(
@@ -140,6 +134,18 @@
return "";
}
+// --- InputDeviceIdentifier
+
+std::string InputDeviceIdentifier::getCanonicalName() const {
+ std::string replacedName = name;
+ for (char& ch : replacedName) {
+ if (!isValidNameChar(ch)) {
+ ch = '_';
+ }
+ }
+ return replacedName;
+}
+
// --- InputDeviceInfo ---
diff --git a/libs/input/TouchVideoFrame.cpp b/libs/input/TouchVideoFrame.cpp
new file mode 100644
index 0000000..8a4298a
--- /dev/null
+++ b/libs/input/TouchVideoFrame.cpp
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <input/TouchVideoFrame.h>
+
+namespace android {
+
+TouchVideoFrame::TouchVideoFrame(uint32_t height, uint32_t width, std::vector<int16_t> data,
+ const struct timeval& timestamp) :
+ mHeight(height), mWidth(width),mData(std::move(data)), mTimestamp(timestamp) {
+}
+
+bool TouchVideoFrame::operator==(const TouchVideoFrame& rhs) const {
+ return mHeight == rhs.mHeight
+ && mWidth == rhs.mWidth
+ && mData == rhs.mData
+ && mTimestamp.tv_sec == rhs.mTimestamp.tv_sec
+ && mTimestamp.tv_usec == rhs.mTimestamp.tv_usec;
+}
+
+uint32_t TouchVideoFrame::getHeight() const { return mHeight; }
+
+uint32_t TouchVideoFrame::getWidth() const { return mWidth; }
+
+const std::vector<int16_t>& TouchVideoFrame::getData() const { return mData; }
+
+const struct timeval& TouchVideoFrame::getTimestamp() const { return mTimestamp; }
+
+void TouchVideoFrame::rotate(int32_t orientation) {
+ switch (orientation) {
+ case DISPLAY_ORIENTATION_90:
+ rotateQuarterTurn(true /*clockwise*/);
+ break;
+ case DISPLAY_ORIENTATION_180:
+ rotate180();
+ break;
+ case DISPLAY_ORIENTATION_270:
+ rotateQuarterTurn(false /*clockwise*/);
+ break;
+ }
+}
+
+/**
+ * Rotate once clockwise by a quarter turn === rotate 90 degrees
+ * Rotate once counterclockwise by a quarter turn === rotate 270 degrees
+ * For a clockwise rotation:
+ * An element at position (i, j) is rotated to (j, height - i - 1)
+ * For a counterclockwise rotation:
+ * An element at position (i, j) is rotated to (width - j - 1, i)
+ */
+void TouchVideoFrame::rotateQuarterTurn(bool clockwise) {
+ std::vector<int16_t> rotated(mData.size());
+ for (size_t i = 0; i < mHeight; i++) {
+ for (size_t j = 0; j < mWidth; j++) {
+ size_t iRotated, jRotated;
+ if (clockwise) {
+ iRotated = j;
+ jRotated = mHeight - i - 1;
+ } else {
+ iRotated = mWidth - j - 1;
+ jRotated = i;
+ }
+ size_t indexRotated = iRotated * mHeight + jRotated;
+ rotated[indexRotated] = mData[i * mWidth + j];
+ }
+ }
+ mData = std::move(rotated);
+ std::swap(mHeight, mWidth);
+}
+
+/**
+ * An element at position (i, j) is rotated to (height - i - 1, width - j - 1)
+ * This is equivalent to moving element [i] to position [height * width - i - 1]
+ * Since element at [height * width - i - 1] would move to position [i],
+ * we can just swap elements [i] and [height * width - i - 1].
+ */
+void TouchVideoFrame::rotate180() {
+ if (mData.size() == 0) {
+ return;
+ }
+ // Just need to swap elements i and (height * width - 1 - i)
+ for (size_t i = 0; i < mData.size() / 2; i++) {
+ std::swap(mData[i], mData[mHeight * mWidth - 1 - i]);
+ }
+}
+
+} // namespace android
diff --git a/libs/input/VirtualKeyMap.cpp b/libs/input/VirtualKeyMap.cpp
index 3ec53bf..624f152 100644
--- a/libs/input/VirtualKeyMap.cpp
+++ b/libs/input/VirtualKeyMap.cpp
@@ -28,10 +28,6 @@
// Enables debug output for the parser.
#define DEBUG_PARSER 0
-// Enables debug output for parser performance.
-#define DEBUG_PARSER_PERFORMANCE 0
-
-
namespace android {
static const char* WHITESPACE = " \t\r";
@@ -46,39 +42,28 @@
VirtualKeyMap::~VirtualKeyMap() {
}
-status_t VirtualKeyMap::load(const std::string& filename, VirtualKeyMap** outMap) {
- *outMap = nullptr;
-
- Tokenizer* tokenizer;
- status_t status = Tokenizer::open(String8(filename.c_str()), &tokenizer);
- if (status) {
+std::unique_ptr<VirtualKeyMap> VirtualKeyMap::load(const std::string& filename) {
+ Tokenizer* t;
+ status_t status = Tokenizer::open(String8(filename.c_str()), &t);
+ if (status != OK) {
ALOGE("Error %d opening virtual key map file %s.", status, filename.c_str());
- } else {
- VirtualKeyMap* map = new VirtualKeyMap();
- if (!map) {
- ALOGE("Error allocating virtual key map.");
- status = NO_MEMORY;
- } else {
-#if DEBUG_PARSER_PERFORMANCE
- nsecs_t startTime = systemTime(SYSTEM_TIME_MONOTONIC);
-#endif
- Parser parser(map, tokenizer);
- status = parser.parse();
-#if DEBUG_PARSER_PERFORMANCE
- nsecs_t elapsedTime = systemTime(SYSTEM_TIME_MONOTONIC) - startTime;
- ALOGD("Parsed key character map file '%s' %d lines in %0.3fms.",
- tokenizer->getFilename().string(), tokenizer->getLineNumber(),
- elapsedTime / 1000000.0);
-#endif
- if (status) {
- delete map;
- } else {
- *outMap = map;
- }
- }
- delete tokenizer;
+ return nullptr;
}
- return status;
+ std::unique_ptr<Tokenizer> tokenizer(t);
+ // Using 'new' to access a non-public constructor
+ std::unique_ptr<VirtualKeyMap> map(new VirtualKeyMap());
+ if (!map) {
+ ALOGE("Error allocating virtual key map.");
+ return nullptr;
+ }
+
+ Parser parser(map.get(), tokenizer.get());
+ status = parser.parse();
+ if (status != OK) {
+ return nullptr;
+ }
+
+ return map;
}
diff --git a/libs/input/tests/Android.bp b/libs/input/tests/Android.bp
index fdd945e..57ba2a2 100644
--- a/libs/input/tests/Android.bp
+++ b/libs/input/tests/Android.bp
@@ -5,8 +5,9 @@
"InputChannel_test.cpp",
"InputEvent_test.cpp",
"InputPublisherAndConsumer_test.cpp",
+ "InputWindow_test.cpp",
+ "TouchVideoFrame_test.cpp",
"VelocityTracker_test.cpp",
- "InputWindow_test.cpp"
],
cflags: [
"-Wall",
diff --git a/libs/input/tests/TouchVideoFrame_test.cpp b/libs/input/tests/TouchVideoFrame_test.cpp
new file mode 100644
index 0000000..815424e
--- /dev/null
+++ b/libs/input/tests/TouchVideoFrame_test.cpp
@@ -0,0 +1,196 @@
+/*
+ * 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 <input/TouchVideoFrame.h>
+
+namespace android {
+namespace test {
+
+static const struct timeval TIMESTAMP = {1, 2};
+
+TEST(TouchVideoFrame, Constructor) {
+ const std::vector<int16_t> data = {1, 2, 3, 4, 5, 6};
+ constexpr uint32_t height = 3;
+ constexpr uint32_t width = 2;
+
+ TouchVideoFrame frame(height, width, data, TIMESTAMP);
+
+ ASSERT_EQ(data, frame.getData());
+ ASSERT_EQ(height, frame.getHeight());
+ ASSERT_EQ(width, frame.getWidth());
+ ASSERT_EQ(TIMESTAMP.tv_sec, frame.getTimestamp().tv_sec);
+ ASSERT_EQ(TIMESTAMP.tv_usec, frame.getTimestamp().tv_usec);
+}
+
+TEST(TouchVideoFrame, Equality) {
+ const std::vector<int16_t> data = {1, 2, 3, 4, 5, 6};
+ constexpr uint32_t height = 3;
+ constexpr uint32_t width = 2;
+ TouchVideoFrame frame(height, width, data, TIMESTAMP);
+
+ TouchVideoFrame identicalFrame(height, width, data, TIMESTAMP);
+ ASSERT_EQ(frame, identicalFrame);
+
+ // The two cases below create an invalid frame, but it is OK for comparison purposes.
+ // There aren't any checks currently enforced on the frame dimensions and data
+ // Change height
+ TouchVideoFrame changedHeightFrame(height + 1, width, data, TIMESTAMP);
+ ASSERT_FALSE(frame == changedHeightFrame);
+
+ // Change width
+ TouchVideoFrame changedWidthFrame(height, width + 1, data, TIMESTAMP);
+ ASSERT_FALSE(frame == changedWidthFrame);
+
+ // Change data
+ const std::vector<int16_t> differentData = {1, 2, 3, 3, 5, 6};
+ TouchVideoFrame changedDataFrame(height, width, differentData, TIMESTAMP);
+ ASSERT_FALSE(frame == changedDataFrame);
+
+ // Change timestamp
+ const struct timeval differentTimestamp = {TIMESTAMP.tv_sec + 1, TIMESTAMP.tv_usec + 1};
+ TouchVideoFrame changedTimestampFrame(height, width, data, differentTimestamp);
+ ASSERT_FALSE(frame == changedTimestampFrame);
+}
+
+// --- Rotate 90 degrees ---
+
+TEST(TouchVideoFrame, Rotate90_0x0) {
+ TouchVideoFrame frame(0, 0, {}, TIMESTAMP);
+ TouchVideoFrame frameRotated(0, 0, {}, TIMESTAMP);
+ frame.rotate(DISPLAY_ORIENTATION_90);
+ ASSERT_EQ(frame, frameRotated);
+}
+
+TEST(TouchVideoFrame, Rotate90_1x1) {
+ TouchVideoFrame frame(1, 1, {1}, TIMESTAMP);
+ TouchVideoFrame frameRotated(1, 1, {1}, TIMESTAMP);
+ frame.rotate(DISPLAY_ORIENTATION_90);
+ ASSERT_EQ(frame, frameRotated);
+}
+
+TEST(TouchVideoFrame, Rotate90_2x2) {
+ TouchVideoFrame frame(2, 2, {1, 2, 3, 4}, TIMESTAMP);
+ TouchVideoFrame frameRotated(2, 2, {3, 1, 4, 2}, TIMESTAMP);
+ frame.rotate(DISPLAY_ORIENTATION_90);
+ ASSERT_EQ(frame, frameRotated);
+}
+
+TEST(TouchVideoFrame, Rotate90_3x2) {
+ TouchVideoFrame frame(3, 2, {1, 2, 3, 4, 5, 6}, TIMESTAMP);
+ TouchVideoFrame frameRotated(2, 3, {5, 3, 1, 6, 4, 2}, TIMESTAMP);
+ frame.rotate(DISPLAY_ORIENTATION_90);
+ ASSERT_EQ(frame, frameRotated);
+}
+
+TEST(TouchVideoFrame, Rotate90_3x2_4times) {
+ TouchVideoFrame frame(3, 2, {1, 2, 3, 4, 5, 6}, TIMESTAMP);
+ TouchVideoFrame frameOriginal(3, 2, {1, 2, 3, 4, 5, 6}, TIMESTAMP);
+ frame.rotate(DISPLAY_ORIENTATION_90);
+ frame.rotate(DISPLAY_ORIENTATION_90);
+ frame.rotate(DISPLAY_ORIENTATION_90);
+ frame.rotate(DISPLAY_ORIENTATION_90);
+ ASSERT_EQ(frame, frameOriginal);
+}
+
+// --- Rotate 180 degrees ---
+
+TEST(TouchVideoFrame, Rotate180_0x0) {
+ TouchVideoFrame frame(0, 0, {}, TIMESTAMP);
+ TouchVideoFrame frameRotated(0, 0, {}, TIMESTAMP);
+ frame.rotate(DISPLAY_ORIENTATION_180);
+ ASSERT_EQ(frame, frameRotated);
+}
+
+TEST(TouchVideoFrame, Rotate180_1x1) {
+ TouchVideoFrame frame(1, 1, {1}, TIMESTAMP);
+ TouchVideoFrame frameRotated(1, 1, {1}, TIMESTAMP);
+ frame.rotate(DISPLAY_ORIENTATION_180);
+ ASSERT_EQ(frame, frameRotated);
+}
+
+TEST(TouchVideoFrame, Rotate180_2x2) {
+ TouchVideoFrame frame(2, 2, {1, 2, 3, 4}, TIMESTAMP);
+ TouchVideoFrame frameRotated(2, 2, {4, 3, 2, 1}, TIMESTAMP);
+ frame.rotate(DISPLAY_ORIENTATION_180);
+ ASSERT_EQ(frame, frameRotated);
+}
+
+TEST(TouchVideoFrame, Rotate180_3x2) {
+ TouchVideoFrame frame(3, 2, {1, 2, 3, 4, 5, 6}, TIMESTAMP);
+ TouchVideoFrame frameRotated(3, 2, {6, 5, 4, 3, 2, 1}, TIMESTAMP);
+ frame.rotate(DISPLAY_ORIENTATION_180);
+ ASSERT_EQ(frame, frameRotated);
+}
+
+TEST(TouchVideoFrame, Rotate180_3x2_2times) {
+ TouchVideoFrame frame(3, 2, {1, 2, 3, 4, 5, 6}, TIMESTAMP);
+ TouchVideoFrame frameOriginal(3, 2, {1, 2, 3, 4, 5, 6}, TIMESTAMP);
+ frame.rotate(DISPLAY_ORIENTATION_180);
+ frame.rotate(DISPLAY_ORIENTATION_180);
+ ASSERT_EQ(frame, frameOriginal);
+}
+
+TEST(TouchVideoFrame, Rotate180_3x3) {
+ TouchVideoFrame frame(3, 3, {1, 2, 3, 4, 5, 6, 7, 8, 9}, TIMESTAMP);
+ TouchVideoFrame frameRotated(3, 3, {9, 8, 7, 6, 5, 4, 3, 2, 1}, TIMESTAMP);
+ frame.rotate(DISPLAY_ORIENTATION_180);
+ ASSERT_EQ(frame, frameRotated);
+}
+
+// --- Rotate 270 degrees ---
+
+TEST(TouchVideoFrame, Rotate270_0x0) {
+ TouchVideoFrame frame(0, 0, {}, TIMESTAMP);
+ TouchVideoFrame frameRotated(0, 0, {}, TIMESTAMP);
+ frame.rotate(DISPLAY_ORIENTATION_270);
+ ASSERT_EQ(frame, frameRotated);
+}
+
+TEST(TouchVideoFrame, Rotate270_1x1) {
+ TouchVideoFrame frame(1, 1, {1}, TIMESTAMP);
+ TouchVideoFrame frameRotated(1, 1, {1}, TIMESTAMP);
+ frame.rotate(DISPLAY_ORIENTATION_270);
+ ASSERT_EQ(frame, frameRotated);
+}
+
+TEST(TouchVideoFrame, Rotate270_2x2) {
+ TouchVideoFrame frame(2, 2, {1, 2, 3, 4}, TIMESTAMP);
+ TouchVideoFrame frameRotated(2, 2, {2, 4, 1, 3}, TIMESTAMP);
+ frame.rotate(DISPLAY_ORIENTATION_270);
+ ASSERT_EQ(frame, frameRotated);
+}
+
+TEST(TouchVideoFrame, Rotate270_3x2) {
+ TouchVideoFrame frame(3, 2, {1, 2, 3, 4, 5, 6}, TIMESTAMP);
+ TouchVideoFrame frameRotated(2, 3, {2, 4, 6, 1, 3, 5}, TIMESTAMP);
+ frame.rotate(DISPLAY_ORIENTATION_270);
+ ASSERT_EQ(frame, frameRotated);
+}
+
+TEST(TouchVideoFrame, Rotate270_3x2_4times) {
+ TouchVideoFrame frame(3, 2, {1, 2, 3, 4, 5, 6}, TIMESTAMP);
+ TouchVideoFrame frameOriginal(3, 2, {1, 2, 3, 4, 5, 6}, TIMESTAMP);
+ frame.rotate(DISPLAY_ORIENTATION_270);
+ frame.rotate(DISPLAY_ORIENTATION_270);
+ frame.rotate(DISPLAY_ORIENTATION_270);
+ frame.rotate(DISPLAY_ORIENTATION_270);
+ ASSERT_EQ(frame, frameOriginal);
+}
+
+} // namespace test
+} // namespace android
diff --git a/libs/renderengine/OWNERS b/libs/renderengine/OWNERS
new file mode 100644
index 0000000..c00fbba
--- /dev/null
+++ b/libs/renderengine/OWNERS
@@ -0,0 +1,2 @@
+lpy@google.com
+stoza@google.com
diff --git a/libs/renderengine/gl/GLESRenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp
index 8f9071e..e7ff9ab 100644
--- a/libs/renderengine/gl/GLESRenderEngine.cpp
+++ b/libs/renderengine/gl/GLESRenderEngine.cpp
@@ -789,13 +789,18 @@
status_t GLESRenderEngine::drawLayers(const DisplaySettings& display,
const std::vector<LayerSettings>& layers,
ANativeWindowBuffer* const buffer,
- base::unique_fd* drawFence) {
+ base::unique_fd&& bufferFence, base::unique_fd* drawFence) {
ATRACE_CALL();
if (layers.empty()) {
ALOGV("Drawing empty layer stack");
return NO_ERROR;
}
+ if (bufferFence.get() >= 0 && !waitFence(std::move(bufferFence))) {
+ ATRACE_NAME("Waiting before draw");
+ sync_wait(bufferFence.get(), -1);
+ }
+
BindNativeBufferAsFramebuffer fbo(*this, buffer);
if (fbo.getStatus() != NO_ERROR) {
diff --git a/libs/renderengine/gl/GLESRenderEngine.h b/libs/renderengine/gl/GLESRenderEngine.h
index 7b72666..a86b4f5 100644
--- a/libs/renderengine/gl/GLESRenderEngine.h
+++ b/libs/renderengine/gl/GLESRenderEngine.h
@@ -81,7 +81,8 @@
bool supportsProtectedContent() const override;
bool useProtectedContext(bool useProtectedContext) override;
status_t drawLayers(const DisplaySettings& display, const std::vector<LayerSettings>& layers,
- ANativeWindowBuffer* buffer, base::unique_fd* drawFence) override;
+ ANativeWindowBuffer* buffer, base::unique_fd&& bufferFence,
+ base::unique_fd* drawFence) override;
// internal to RenderEngine
EGLDisplay getEGLDisplay() const { return mEGLDisplay; }
diff --git a/libs/renderengine/include/renderengine/RenderEngine.h b/libs/renderengine/include/renderengine/RenderEngine.h
index b51ed22..812d761 100644
--- a/libs/renderengine/include/renderengine/RenderEngine.h
+++ b/libs/renderengine/include/renderengine/RenderEngine.h
@@ -167,7 +167,9 @@
// drawing any layers.
// @param layers The layers to draw onto the display, in Z-order.
// @param buffer The buffer which will be drawn to. This buffer will be
- // ready once displayFence fires.
+ // ready once drawFence fires.
+ // @param bufferFence Fence signalling that the buffer is ready to be drawn
+ // to.
// @param drawFence A pointer to a fence, which will fire when the buffer
// has been drawn to and is ready to be examined. The fence will be
// initialized by this method. The caller will be responsible for owning the
@@ -176,7 +178,8 @@
// now, this always returns NO_ERROR.
virtual status_t drawLayers(const DisplaySettings& display,
const std::vector<LayerSettings>& layers,
- ANativeWindowBuffer* buffer, base::unique_fd* drawFence) = 0;
+ ANativeWindowBuffer* buffer, base::unique_fd&& bufferFence,
+ base::unique_fd* drawFence) = 0;
protected:
// Gets a framebuffer to render to. This framebuffer may or may not be
diff --git a/libs/renderengine/include/renderengine/mock/RenderEngine.h b/libs/renderengine/include/renderengine/mock/RenderEngine.h
index 800eac3..5956c46 100644
--- a/libs/renderengine/include/renderengine/mock/RenderEngine.h
+++ b/libs/renderengine/include/renderengine/mock/RenderEngine.h
@@ -78,9 +78,9 @@
MOCK_CONST_METHOD0(isProtected, bool());
MOCK_CONST_METHOD0(supportsProtectedContent, bool());
MOCK_METHOD1(useProtectedContext, bool(bool));
- MOCK_METHOD4(drawLayers,
+ MOCK_METHOD5(drawLayers,
status_t(const DisplaySettings&, const std::vector<LayerSettings>&,
- ANativeWindowBuffer*, base::unique_fd*));
+ ANativeWindowBuffer*, base::unique_fd&&, base::unique_fd*));
};
} // namespace mock
diff --git a/libs/renderengine/tests/RenderEngineTest.cpp b/libs/renderengine/tests/RenderEngineTest.cpp
index f82beeb..f28f672 100644
--- a/libs/renderengine/tests/RenderEngineTest.cpp
+++ b/libs/renderengine/tests/RenderEngineTest.cpp
@@ -105,7 +105,8 @@
std::vector<renderengine::LayerSettings> layers,
sp<GraphicBuffer> buffer) {
base::unique_fd fence;
- status_t status = sRE->drawLayers(settings, layers, buffer->getNativeBuffer(), &fence);
+ status_t status = sRE->drawLayers(settings, layers, buffer->getNativeBuffer(),
+ base::unique_fd(), &fence);
int fd = fence.release();
if (fd >= 0) {
diff --git a/libs/ui/GraphicBuffer.cpp b/libs/ui/GraphicBuffer.cpp
index f487dfa..79958ec 100644
--- a/libs/ui/GraphicBuffer.cpp
+++ b/libs/ui/GraphicBuffer.cpp
@@ -15,6 +15,7 @@
*/
#define LOG_TAG "GraphicBuffer"
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
#include <ui/GraphicBuffer.h>
@@ -29,6 +30,7 @@
#include <ui/Gralloc2.h>
#include <ui/GraphicBufferAllocator.h>
#include <ui/GraphicBufferMapper.h>
+#include <utils/Trace.h>
namespace android {
@@ -111,6 +113,7 @@
GraphicBuffer::~GraphicBuffer()
{
+ ATRACE_CALL();
if (handle) {
free_handle();
}
diff --git a/opengl/libs/Android.bp b/opengl/libs/Android.bp
index c80b79a..c0bace8 100644
--- a/opengl/libs/Android.bp
+++ b/opengl/libs/Android.bp
@@ -154,8 +154,8 @@
"libbase",
"libhidlbase",
"libhidltransport",
- "libnativebridge",
- "libnativeloader",
+ "libnativebridge_lazy",
+ "libnativeloader_lazy",
"libutils",
],
static_libs: [
diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp
index 4cafe2b..259242b 100644
--- a/opengl/libs/EGL/Loader.cpp
+++ b/opengl/libs/EGL/Loader.cpp
@@ -27,6 +27,7 @@
#include <android/dlext.h>
#include <cutils/properties.h>
#include <log/log.h>
+#include <utils/Timers.h>
#ifndef __ANDROID_VNDK__
#include <graphicsenv/GraphicsEnv.h>
@@ -217,6 +218,7 @@
void* Loader::open(egl_connection_t* cnx)
{
ATRACE_CALL();
+ const nsecs_t openTime = systemTime();
void* dso;
driver_t* hnd = nullptr;
@@ -234,6 +236,8 @@
if (dso) {
hnd = new driver_t(dso);
} else {
+ android::GraphicsEnv::getInstance().clearDriverLoadingInfo(
+ android::GraphicsEnv::Api::API_GL);
// Always load EGL first
dso = load_driver("EGL", cnx, EGL);
if (dso) {
@@ -243,19 +247,30 @@
}
}
+ if (!hnd) {
+ android::GraphicsEnv::getInstance().setDriverLoaded(android::GraphicsEnv::Api::API_GL,
+ false, systemTime() - openTime);
+ }
+
LOG_ALWAYS_FATAL_IF(!hnd, "couldn't find an OpenGL ES implementation");
cnx->libEgl = load_wrapper(EGL_WRAPPER_DIR "/libEGL.so");
cnx->libGles2 = load_wrapper(EGL_WRAPPER_DIR "/libGLESv2.so");
cnx->libGles1 = load_wrapper(EGL_WRAPPER_DIR "/libGLESv1_CM.so");
+ if (!cnx->libEgl || !cnx->libGles2 || !cnx->libGles1) {
+ android::GraphicsEnv::getInstance().setDriverLoaded(android::GraphicsEnv::Api::API_GL,
+ false, systemTime() - openTime);
+ }
+
LOG_ALWAYS_FATAL_IF(!cnx->libEgl,
"couldn't load system EGL wrapper libraries");
LOG_ALWAYS_FATAL_IF(!cnx->libGles2 || !cnx->libGles1,
"couldn't load system OpenGL ES wrapper libraries");
- android::GraphicsEnv::getInstance().sendGpuStats();
+ android::GraphicsEnv::getInstance().setDriverLoaded(android::GraphicsEnv::Api::API_GL, true,
+ systemTime() - openTime);
return (void*)hnd;
}
@@ -591,17 +606,21 @@
void* dso = nullptr;
android_namespace_t* ns = android::GraphicsEnv::getInstance().getAngleNamespace();
if (ns) {
+ android::GraphicsEnv::getInstance().setDriverToLoad(android::GraphicsEnv::Driver::ANGLE);
dso = load_angle(kind, ns, cnx);
}
#ifndef __ANDROID_VNDK__
if (!dso) {
android_namespace_t* ns = android::GraphicsEnv::getInstance().getDriverNamespace();
if (ns) {
+ android::GraphicsEnv::getInstance().setDriverToLoad(
+ android::GraphicsEnv::Driver::GL_UPDATED);
dso = load_updated_driver(kind, ns);
}
}
#endif
if (!dso) {
+ android::GraphicsEnv::getInstance().setDriverToLoad(android::GraphicsEnv::Driver::GL);
dso = load_system_driver(kind);
if (!dso)
return nullptr;
diff --git a/services/gpuservice/GpuService.cpp b/services/gpuservice/GpuService.cpp
index 68c185c..ed56c49 100644
--- a/services/gpuservice/GpuService.cpp
+++ b/services/gpuservice/GpuService.cpp
@@ -38,18 +38,24 @@
GpuService::GpuService() = default;
void GpuService::setGpuStats(const std::string& driverPackageName,
- const std::string& driverVersionName, const uint64_t driverVersionCode,
- const std::string& appPackageName) {
+ const std::string& driverVersionName, uint64_t driverVersionCode,
+ int64_t driverBuildTime, const std::string& appPackageName,
+ GraphicsEnv::Driver driver, bool isDriverLoaded,
+ int64_t driverLoadingTime) {
ATRACE_CALL();
std::lock_guard<std::mutex> lock(mStateLock);
ALOGV("Received:\n"
"\tdriverPackageName[%s]\n"
"\tdriverVersionName[%s]\n"
- "\tdriverVersionCode[%llu]\n"
- "\tappPackageName[%s]\n",
- driverPackageName.c_str(), driverVersionName.c_str(),
- (unsigned long long)driverVersionCode, appPackageName.c_str());
+ "\tdriverVersionCode[%" PRIu64 "]\n"
+ "\tdriverBuildTime[%" PRId64 "]\n"
+ "\tappPackageName[%s]\n"
+ "\tdriver[%d]\n"
+ "\tisDriverLoaded[%d]\n"
+ "\tdriverLoadingTime[%" PRId64 "]",
+ driverPackageName.c_str(), driverVersionName.c_str(), driverVersionCode, driverBuildTime,
+ appPackageName.c_str(), static_cast<int32_t>(driver), isDriverLoaded, driverLoadingTime);
}
status_t GpuService::shellCommand(int /*in*/, int out, int err, std::vector<String16>& args) {
diff --git a/services/gpuservice/GpuService.h b/services/gpuservice/GpuService.h
index 5304fa1..389e695 100644
--- a/services/gpuservice/GpuService.h
+++ b/services/gpuservice/GpuService.h
@@ -38,7 +38,9 @@
private:
// IGpuService interface
void setGpuStats(const std::string& driverPackageName, const std::string& driverVersionName,
- const uint64_t driverVersionCode, const std::string& appPackageName);
+ uint64_t driverVersionCode, int64_t driverBuildTime,
+ const std::string& appPackageName, GraphicsEnv::Driver driver,
+ bool isDriverLoaded, int64_t driverLoadingTime);
// GpuStats access must be protected by mStateLock
std::mutex mStateLock;
diff --git a/services/inputflinger/Android.bp b/services/inputflinger/Android.bp
index f73d498..63e759c 100644
--- a/services/inputflinger/Android.bp
+++ b/services/inputflinger/Android.bp
@@ -12,8 +12,20 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+cc_defaults {
+ name: "inputflinger_defaults",
+ cflags: [
+ "-Wall",
+ "-Wextra",
+ "-Werror",
+ "-Wno-unused-parameter",
+ "-Wthread-safety",
+ ],
+}
+
cc_library_shared {
name: "libinputflinger",
+ defaults: ["inputflinger_defaults"],
srcs: [
"InputClassifier.cpp",
@@ -23,10 +35,10 @@
shared_libs: [
"android.hardware.input.classifier@1.0",
+ "libbase",
"libinputflinger_base",
"libinputreporter",
"libinputreader",
- "libbase",
"libbinder",
"libcutils",
"libhidlbase",
@@ -38,12 +50,6 @@
],
cflags: [
- "-Wall",
- "-Wextra",
- "-Werror",
- "-Wno-unused-parameter",
- // 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
],
@@ -55,15 +61,14 @@
}
-
cc_library_headers {
- name: "libinputflinger_headers",
-
- export_include_dirs: ["include"],
+ name: "libinputflinger_headers",
+ export_include_dirs: ["include"],
}
cc_library_shared {
name: "libinputreader",
+ defaults: ["inputflinger_defaults"],
srcs: [
"EventHub.cpp",
@@ -73,17 +78,16 @@
],
shared_libs: [
- "libinputflinger_base",
"libbase",
+ "libinputflinger_base",
"libcrypto",
"libcutils",
"libinput",
"liblog",
- "libutils",
"libui",
+ "libutils",
"libhardware_legacy",
"libstatslog",
- "libutils",
],
header_libs: [
@@ -93,17 +97,11 @@
export_header_lib_headers: [
"libinputflinger_headers",
],
-
- cflags: [
- "-Wall",
- "-Wextra",
- "-Werror",
- "-Wno-unused-parameter",
- ],
}
cc_library_shared {
name: "libinputflinger_base",
+ defaults: ["inputflinger_defaults"],
srcs: [
"InputListener.cpp",
@@ -124,24 +122,17 @@
export_header_lib_headers: [
"libinputflinger_headers",
],
-
- cflags: [
- "-Wall",
- "-Wextra",
- "-Werror",
- "-Wno-unused-parameter",
- ],
}
cc_library_shared {
name: "libinputreporter",
+ defaults: ["inputflinger_defaults"],
srcs: [
"InputReporter.cpp",
],
shared_libs: [
- "libbase",
"liblog",
"libutils",
],
@@ -153,13 +144,6 @@
export_header_lib_headers: [
"libinputflinger_headers",
],
-
- cflags: [
- "-Wall",
- "-Wextra",
- "-Werror",
- "-Wno-unused-parameter",
- ],
}
subdirs = [
diff --git a/services/inputflinger/BlockingQueue.h b/services/inputflinger/BlockingQueue.h
index c9eb683..4b16027 100644
--- a/services/inputflinger/BlockingQueue.h
+++ b/services/inputflinger/BlockingQueue.h
@@ -17,6 +17,7 @@
#ifndef _UI_INPUT_BLOCKING_QUEUE_H
#define _UI_INPUT_BLOCKING_QUEUE_H
+#include "android-base/thread_annotations.h"
#include <condition_variable>
#include <mutex>
#include <vector>
@@ -43,10 +44,14 @@
*/
T pop() {
std::unique_lock<std::mutex> lock(mLock);
- mHasElements.wait(lock, [this]{ return !this->mQueue.empty(); });
+ android::base::ScopedLockAssertion assumeLock(mLock);
+ mHasElements.wait(lock, [this]{
+ android::base::ScopedLockAssertion assumeLock(mLock);
+ return !this->mQueue.empty();
+ });
T t = std::move(mQueue.front());
mQueue.erase(mQueue.begin());
- return std::move(t);
+ return t;
};
/**
@@ -56,17 +61,19 @@
* Return false if the queue is full.
*/
bool push(T&& t) {
- std::unique_lock<std::mutex> lock(mLock);
- if (mQueue.size() == mCapacity) {
- return false;
+ {
+ std::scoped_lock lock(mLock);
+ if (mQueue.size() == mCapacity) {
+ return false;
+ }
+ mQueue.push_back(std::move(t));
}
- 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);
+ std::scoped_lock lock(mLock);
mQueue.erase(std::remove_if(mQueue.begin(), mQueue.end(),
[&lambda](const T& t) { return lambda(t); }), mQueue.end());
}
@@ -91,7 +98,7 @@
}
private:
- size_t mCapacity;
+ const size_t mCapacity;
/**
* Used to signal that mQueue is non-empty.
*/
@@ -100,7 +107,7 @@
* Lock for accessing and waiting on elements.
*/
std::mutex mLock;
- std::vector<T> mQueue; //GUARDED_BY(mLock)
+ std::vector<T> mQueue GUARDED_BY(mLock);
};
diff --git a/services/inputflinger/EventHub.cpp b/services/inputflinger/EventHub.cpp
index c13bac6..4da1473 100644
--- a/services/inputflinger/EventHub.cpp
+++ b/services/inputflinger/EventHub.cpp
@@ -202,7 +202,6 @@
EventHub::Device::~Device() {
close();
delete configuration;
- delete virtualKeyMap;
}
void EventHub::Device::close() {
@@ -1364,8 +1363,8 @@
if ((device->classes & INPUT_DEVICE_CLASS_TOUCH)) {
// Load the virtual keys for the touch screen, if any.
// We do this now so that we can make sure to load the keymap if necessary.
- status_t status = loadVirtualKeyMapLocked(device);
- if (!status) {
+ bool success = loadVirtualKeyMapLocked(device);
+ if (success) {
device->classes |= INPUT_DEVICE_CLASS_KEYBOARD;
}
}
@@ -1614,15 +1613,16 @@
}
}
-status_t EventHub::loadVirtualKeyMapLocked(Device* device) {
+bool EventHub::loadVirtualKeyMapLocked(Device* device) {
// The virtual key map is supplied by the kernel as a system board property file.
std::string path;
path += "/sys/board_properties/virtualkeys.";
- path += device->identifier.name;
+ path += device->identifier.getCanonicalName();
if (access(path.c_str(), R_OK)) {
- return NAME_NOT_FOUND;
+ return false;
}
- return VirtualKeyMap::load(path, &device->virtualKeyMap);
+ device->virtualKeyMap = VirtualKeyMap::load(path);
+ return device->virtualKeyMap != nullptr;
}
status_t EventHub::loadKeyMapLocked(Device* device) {
diff --git a/services/inputflinger/EventHub.h b/services/inputflinger/EventHub.h
index d176648..44f7b37 100644
--- a/services/inputflinger/EventHub.h
+++ b/services/inputflinger/EventHub.h
@@ -345,7 +345,7 @@
std::string configurationFile;
PropertyMap* configuration;
- VirtualKeyMap* virtualKeyMap;
+ std::unique_ptr<VirtualKeyMap> virtualKeyMap;
KeyMap keyMap;
sp<KeyCharacterMap> overlayKeyMap;
@@ -416,7 +416,7 @@
bool hasKeycodeLocked(Device* device, int keycode) const;
void loadConfigurationLocked(Device* device);
- status_t loadVirtualKeyMapLocked(Device* device);
+ bool loadVirtualKeyMapLocked(Device* device);
status_t loadKeyMapLocked(Device* device);
bool isExternalDeviceLocked(Device* device);
diff --git a/services/inputflinger/InputClassifier.h b/services/inputflinger/InputClassifier.h
index 4b9dae2..b97357d 100644
--- a/services/inputflinger/InputClassifier.h
+++ b/services/inputflinger/InputClassifier.h
@@ -17,6 +17,7 @@
#ifndef _UI_INPUT_CLASSIFIER_H
#define _UI_INPUT_CLASSIFIER_H
+#include <android-base/thread_annotations.h>
#include <utils/RefBase.h>
#include <unordered_map>
#include <thread>
@@ -151,7 +152,7 @@
* getClassification / setClassification methods.
*/
std::unordered_map<int32_t /*deviceId*/, MotionClassification>
- mClassifications; //GUARDED_BY(mLock);
+ mClassifications GUARDED_BY(mLock);
/**
* Set the current classification for a given device.
*/
@@ -161,7 +162,7 @@
*/
MotionClassification getClassification(int32_t deviceId);
void updateClassification(int32_t deviceId, nsecs_t eventTime,
- MotionClassification classification);
+ MotionClassification classification);
/**
* Clear all current classifications
*/
@@ -172,8 +173,8 @@
*
* 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);
+ std::unordered_map<int32_t /*deviceId*/, nsecs_t /*downTime*/> mLastDownTimes GUARDED_BY(mLock);
+
void updateLastDownTime(int32_t deviceId, nsecs_t downTime);
/**
diff --git a/services/inputflinger/InputDispatcher.cpp b/services/inputflinger/InputDispatcher.cpp
index 7ff8b20..d288736 100644
--- a/services/inputflinger/InputDispatcher.cpp
+++ b/services/inputflinger/InputDispatcher.cpp
@@ -401,7 +401,7 @@
case EventEntry::TYPE_KEY: {
KeyEntry* typedEntry = static_cast<KeyEntry*>(mPendingEvent);
if (isAppSwitchDue) {
- if (isAppSwitchKeyEventLocked(typedEntry)) {
+ if (isAppSwitchKeyEvent(typedEntry)) {
resetPendingAppSwitchLocked(true);
isAppSwitchDue = false;
} else if (dropReason == DROP_REASON_NOT_DROPPED) {
@@ -409,7 +409,7 @@
}
}
if (dropReason == DROP_REASON_NOT_DROPPED
- && isStaleEventLocked(currentTime, typedEntry)) {
+ && isStaleEvent(currentTime, typedEntry)) {
dropReason = DROP_REASON_STALE;
}
if (dropReason == DROP_REASON_NOT_DROPPED && mNextUnblockedEvent) {
@@ -425,7 +425,7 @@
dropReason = DROP_REASON_APP_SWITCH;
}
if (dropReason == DROP_REASON_NOT_DROPPED
- && isStaleEventLocked(currentTime, typedEntry)) {
+ && isStaleEvent(currentTime, typedEntry)) {
dropReason = DROP_REASON_STALE;
}
if (dropReason == DROP_REASON_NOT_DROPPED && mNextUnblockedEvent) {
@@ -463,7 +463,7 @@
// If the application takes too long to catch up then we drop all events preceding
// the app switch key.
KeyEntry* keyEntry = static_cast<KeyEntry*>(entry);
- if (isAppSwitchKeyEventLocked(keyEntry)) {
+ if (isAppSwitchKeyEvent(keyEntry)) {
if (keyEntry->action == AKEY_EVENT_ACTION_DOWN) {
mAppSwitchSawKeyDown = true;
} else if (keyEntry->action == AKEY_EVENT_ACTION_UP) {
@@ -615,13 +615,13 @@
}
}
-bool InputDispatcher::isAppSwitchKeyCode(int32_t keyCode) {
+static bool isAppSwitchKeyCode(int32_t keyCode) {
return keyCode == AKEYCODE_HOME
|| keyCode == AKEYCODE_ENDCALL
|| keyCode == AKEYCODE_APP_SWITCH;
}
-bool InputDispatcher::isAppSwitchKeyEventLocked(KeyEntry* keyEntry) {
+bool InputDispatcher::isAppSwitchKeyEvent(KeyEntry* keyEntry) {
return ! (keyEntry->flags & AKEY_EVENT_FLAG_CANCELED)
&& isAppSwitchKeyCode(keyEntry->keyCode)
&& (keyEntry->policyFlags & POLICY_FLAG_TRUSTED)
@@ -644,7 +644,7 @@
#endif
}
-bool InputDispatcher::isStaleEventLocked(nsecs_t currentTime, EventEntry* entry) {
+bool InputDispatcher::isStaleEvent(nsecs_t currentTime, EventEntry* entry) {
return currentTime - entry->eventTime >= STALE_EVENT_TIMEOUT;
}
@@ -756,7 +756,7 @@
// Enqueue a command to run outside the lock to tell the policy that the configuration changed.
CommandEntry* commandEntry = postCommandLocked(
- & InputDispatcher::doNotifyConfigurationChangedInterruptible);
+ & InputDispatcher::doNotifyConfigurationChangedLockedInterruptible);
commandEntry->eventTime = entry->eventTime;
return true;
}
@@ -811,7 +811,7 @@
entry->dispatchInProgress = true;
- logOutboundKeyDetailsLocked("dispatchKey - ", entry);
+ logOutboundKeyDetails("dispatchKey - ", entry);
}
// Handle case where the policy asked us to try again later last time.
@@ -878,7 +878,7 @@
return true;
}
-void InputDispatcher::logOutboundKeyDetailsLocked(const char* prefix, const KeyEntry* entry) {
+void InputDispatcher::logOutboundKeyDetails(const char* prefix, const KeyEntry* entry) {
#if DEBUG_OUTBOUND_EVENT_DETAILS
ALOGD("%seventTime=%" PRId64 ", deviceId=%d, source=0x%x, displayId=%" PRId32 ", "
"policyFlags=0x%x, action=0x%x, flags=0x%x, keyCode=0x%x, scanCode=0x%x, "
@@ -896,7 +896,7 @@
if (! entry->dispatchInProgress) {
entry->dispatchInProgress = true;
- logOutboundMotionDetailsLocked("dispatchMotion - ", entry);
+ logOutboundMotionDetails("dispatchMotion - ", entry);
}
// Clean up if dropping the event.
@@ -968,7 +968,7 @@
}
-void InputDispatcher::logOutboundMotionDetailsLocked(const char* prefix, const MotionEntry* entry) {
+void InputDispatcher::logOutboundMotionDetails(const char* prefix, const MotionEntry* entry) {
#if DEBUG_OUTBOUND_EVENT_DETAILS
ALOGD("%seventTime=%" PRId64 ", deviceId=%d, source=0x%x, displayId=%" PRId32
", policyFlags=0x%x, "
@@ -1049,7 +1049,7 @@
if (mInputTargetWaitCause != INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY) {
#if DEBUG_FOCUS
ALOGD("Waiting for application to become ready for input: %s. Reason: %s",
- getApplicationWindowLabelLocked(applicationHandle, windowHandle).c_str(),
+ getApplicationWindowLabel(applicationHandle, windowHandle).c_str(),
reason);
#endif
nsecs_t timeout;
@@ -1233,8 +1233,7 @@
Failed:
Unresponsive:
nsecs_t timeSpentWaitingForApplication = getTimeSpentWaitingForApplicationLocked(currentTime);
- updateDispatchStatisticsLocked(currentTime, entry,
- injectionResult, timeSpentWaitingForApplication);
+ updateDispatchStatistics(currentTime, entry, injectionResult, timeSpentWaitingForApplication);
#if DEBUG_FOCUS
ALOGD("findFocusedWindow finished: injectionResult=%d, "
"timeSpentWaitingForApplication=%0.1fms",
@@ -1654,8 +1653,7 @@
mTempTouchState.reset();
nsecs_t timeSpentWaitingForApplication = getTimeSpentWaitingForApplicationLocked(currentTime);
- updateDispatchStatisticsLocked(currentTime, entry,
- injectionResult, timeSpentWaitingForApplication);
+ updateDispatchStatistics(currentTime, entry, injectionResult, timeSpentWaitingForApplication);
#if DEBUG_FOCUS
ALOGD("findTouchedWindow finished: injectionResult=%d, injectionPermission=%d, "
"timeSpentWaitingForApplication=%0.1fms",
@@ -1857,7 +1855,7 @@
return "";
}
-std::string InputDispatcher::getApplicationWindowLabelLocked(
+std::string InputDispatcher::getApplicationWindowLabel(
const sp<InputApplicationHandle>& applicationHandle,
const sp<InputWindowHandle>& windowHandle) {
if (applicationHandle != nullptr) {
@@ -1956,7 +1954,7 @@
#if DEBUG_FOCUS
ALOGD("channel '%s' ~ Split motion event.",
connection->getInputChannelName().c_str());
- logOutboundMotionDetailsLocked(" ", splitMotionEntry);
+ logOutboundMotionDetails(" ", splitMotionEntry);
#endif
enqueueDispatchEntriesLocked(currentTime, connection,
splitMotionEntry, inputTarget);
@@ -2076,12 +2074,12 @@
// Remember that we are waiting for this dispatch to complete.
if (dispatchEntry->hasForegroundTarget()) {
- incrementPendingForegroundDispatchesLocked(eventEntry);
+ incrementPendingForegroundDispatches(eventEntry);
}
// Enqueue the dispatch entry.
connection->outboundQueue.enqueueAtTail(dispatchEntry);
- traceOutboundQueueLengthLocked(connection);
+ traceOutboundQueueLength(connection);
}
void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,
@@ -2196,9 +2194,9 @@
// Re-enqueue the event on the wait queue.
connection->outboundQueue.dequeue(dispatchEntry);
- traceOutboundQueueLengthLocked(connection);
+ traceOutboundQueueLength(connection);
connection->waitQueue.enqueueAtTail(dispatchEntry);
- traceWaitQueueLengthLocked(connection);
+ traceWaitQueueLength(connection);
}
}
@@ -2229,9 +2227,9 @@
// Clear the dispatch queues.
drainDispatchQueueLocked(&connection->outboundQueue);
- traceOutboundQueueLengthLocked(connection);
+ traceOutboundQueueLength(connection);
drainDispatchQueueLocked(&connection->waitQueue);
- traceWaitQueueLengthLocked(connection);
+ traceWaitQueueLength(connection);
// The connection appears to be unrecoverably broken.
// Ignore already broken or zombie connections.
@@ -2323,7 +2321,7 @@
} // release lock
}
-void InputDispatcher::synthesizeCancelationEventsForAllConnectionsLocked(
+void InputDispatcher::synthesizeCancelationEventsForAllConnectionsLocked (
const CancelationOptions& options) {
for (size_t i = 0; i < mConnectionsByFd.size(); i++) {
synthesizeCancelationEventsForConnectionLocked(
@@ -2331,7 +2329,7 @@
}
}
-void InputDispatcher::synthesizeCancelationEventsForMonitorsLocked(
+void InputDispatcher::synthesizeCancelationEventsForMonitorsLocked (
const CancelationOptions& options) {
for (auto& it : mMonitoringChannelsByDisplay) {
const Vector<sp<InputChannel>>& monitoringChannels = it.second;
@@ -2374,11 +2372,11 @@
EventEntry* cancelationEventEntry = cancelationEvents.itemAt(i);
switch (cancelationEventEntry->type) {
case EventEntry::TYPE_KEY:
- logOutboundKeyDetailsLocked("cancel - ",
+ logOutboundKeyDetails("cancel - ",
static_cast<KeyEntry*>(cancelationEventEntry));
break;
case EventEntry::TYPE_MOTION:
- logOutboundMotionDetailsLocked("cancel - ",
+ logOutboundMotionDetails("cancel - ",
static_cast<MotionEntry*>(cancelationEventEntry));
break;
}
@@ -2994,7 +2992,7 @@
}
}
-void InputDispatcher::incrementPendingForegroundDispatchesLocked(EventEntry* entry) {
+void InputDispatcher::incrementPendingForegroundDispatches(EventEntry* entry) {
InjectionState* injectionState = entry->injectionState;
if (injectionState) {
injectionState->pendingForegroundDispatches += 1;
@@ -3014,7 +3012,7 @@
Vector<sp<InputWindowHandle>> InputDispatcher::getWindowHandlesLocked(int32_t displayId) const {
std::unordered_map<int32_t, Vector<sp<InputWindowHandle>>>::const_iterator it =
- mWindowHandlesByDisplay.find(displayId);
+ mWindowHandlesByDisplay.find(displayId);
if(it != mWindowHandlesByDisplay.end()) {
return it->second;
}
@@ -3038,8 +3036,7 @@
return nullptr;
}
-bool InputDispatcher::hasWindowHandleLocked(
- const sp<InputWindowHandle>& windowHandle) const {
+bool InputDispatcher::hasWindowHandleLocked(const sp<InputWindowHandle>& windowHandle) const {
for (auto& it : mWindowHandlesByDisplay) {
const Vector<sp<InputWindowHandle>> windowHandles = it.second;
size_t numWindows = windowHandles.size();
@@ -3075,7 +3072,7 @@
* For removed handle, check if need to send a cancel event if already in touch.
*/
void InputDispatcher::setInputWindows(const Vector<sp<InputWindowHandle>>& inputWindowHandles,
- int32_t displayId) {
+ int32_t displayId, const sp<ISetInputWindowsListener>& setInputWindowsListener) {
#if DEBUG_FOCUS
ALOGD("setInputWindows displayId=%" PRId32, displayId);
#endif
@@ -3225,6 +3222,10 @@
// Wake up poll loop since it may need to make new input dispatching choices.
mLooper->wake();
+
+ if (setInputWindowsListener) {
+ setInputWindowsListener->onSetInputWindowsFinished();
+ }
}
void InputDispatcher::setFocusedApplication(
@@ -3884,7 +3885,7 @@
float waitDuration = (currentTime - waitStartTime) * 0.000001f;
ALOGI("Application is not responding: %s. "
"It has been %0.1fms since event, %0.1fms since wait started. Reason: %s",
- getApplicationWindowLabelLocked(applicationHandle, windowHandle).c_str(),
+ getApplicationWindowLabel(applicationHandle, windowHandle).c_str(),
dispatchLatency, waitDuration, reason);
// Capture a record of the InputDispatcher state at the time of the ANR.
@@ -3897,7 +3898,7 @@
mLastANRState += INDENT "ANR:\n";
mLastANRState += StringPrintf(INDENT2 "Time: %s\n", timestr);
mLastANRState += StringPrintf(INDENT2 "Window: %s\n",
- getApplicationWindowLabelLocked(applicationHandle, windowHandle).c_str());
+ getApplicationWindowLabel(applicationHandle, windowHandle).c_str());
mLastANRState += StringPrintf(INDENT2 "DispatchLatency: %0.1fms\n", dispatchLatency);
mLastANRState += StringPrintf(INDENT2 "WaitDuration: %0.1fms\n", waitDuration);
mLastANRState += StringPrintf(INDENT2 "Reason: %s\n", reason);
@@ -3911,7 +3912,7 @@
commandEntry->reason = reason;
}
-void InputDispatcher::doNotifyConfigurationChangedInterruptible(
+void InputDispatcher::doNotifyConfigurationChangedLockedInterruptible (
CommandEntry* commandEntry) {
mLock.unlock();
@@ -4027,10 +4028,10 @@
// a few things.
if (dispatchEntry == connection->findWaitQueueEntry(seq)) {
connection->waitQueue.dequeue(dispatchEntry);
- traceWaitQueueLengthLocked(connection);
+ traceWaitQueueLength(connection);
if (restartEvent && connection->status == Connection::STATUS_NORMAL) {
connection->outboundQueue.enqueueAtHead(dispatchEntry);
- traceOutboundQueueLengthLocked(connection);
+ traceOutboundQueueLength(connection);
} else {
releaseDispatchEntryLocked(dispatchEntry);
}
@@ -4242,7 +4243,7 @@
entry->downTime, entry->eventTime);
}
-void InputDispatcher::updateDispatchStatisticsLocked(nsecs_t currentTime, const EventEntry* entry,
+void InputDispatcher::updateDispatchStatistics(nsecs_t currentTime, const EventEntry* entry,
int32_t injectionResult, nsecs_t timeSpentWaitingForApplication) {
// TODO Write some statistics about how long we spend waiting.
}
@@ -4253,7 +4254,7 @@
}
}
-void InputDispatcher::traceOutboundQueueLengthLocked(const sp<Connection>& connection) {
+void InputDispatcher::traceOutboundQueueLength(const sp<Connection>& connection) {
if (ATRACE_ENABLED()) {
char counterName[40];
snprintf(counterName, sizeof(counterName), "oq:%s", connection->getWindowName().c_str());
@@ -4261,7 +4262,7 @@
}
}
-void InputDispatcher::traceWaitQueueLengthLocked(const sp<Connection>& connection) {
+void InputDispatcher::traceWaitQueueLength(const sp<Connection>& connection) {
if (ATRACE_ENABLED()) {
char counterName[40];
snprintf(counterName, sizeof(counterName), "wq:%s", connection->getWindowName().c_str());
diff --git a/services/inputflinger/InputDispatcher.h b/services/inputflinger/InputDispatcher.h
index 595b01d..9d8919b 100644
--- a/services/inputflinger/InputDispatcher.h
+++ b/services/inputflinger/InputDispatcher.h
@@ -21,6 +21,7 @@
#include <input/InputApplication.h>
#include <input/InputTransport.h>
#include <input/InputWindow.h>
+#include <input/ISetInputWindowsListener.h>
#include <utils/KeyedVector.h>
#include <utils/Vector.h>
#include <utils/threads.h>
@@ -39,7 +40,6 @@
#include "InputListener.h"
#include "InputReporterInterface.h"
-
namespace android {
/*
@@ -315,7 +315,8 @@
* This method may be called on any thread (usually by the input manager).
*/
virtual void setInputWindows(const Vector<sp<InputWindowHandle> >& inputWindowHandles,
- int32_t displayId) = 0;
+ int32_t displayId,
+ const sp<ISetInputWindowsListener>& setInputWindowsListener = nullptr) = 0;
/* Sets the focused application on the given display.
*
@@ -406,7 +407,8 @@
uint32_t policyFlags);
virtual void setInputWindows(const Vector<sp<InputWindowHandle> >& inputWindowHandles,
- int32_t displayId);
+ int32_t displayId,
+ const sp<ISetInputWindowsListener>& setInputWindowsListener = nullptr);
virtual void setFocusedApplication(int32_t displayId,
const sp<InputApplicationHandle>& inputApplicationHandle);
virtual void setFocusedDisplay(int32_t displayId);
@@ -888,57 +890,58 @@
sp<Looper> mLooper;
- EventEntry* mPendingEvent;
- Queue<EventEntry> mInboundQueue;
- Queue<EventEntry> mRecentQueue;
- Queue<CommandEntry> mCommandQueue;
+ EventEntry* mPendingEvent GUARDED_BY(mLock);
+ Queue<EventEntry> mInboundQueue GUARDED_BY(mLock);
+ Queue<EventEntry> mRecentQueue GUARDED_BY(mLock);
+ Queue<CommandEntry> mCommandQueue GUARDED_BY(mLock);
- DropReason mLastDropReason;
+ DropReason mLastDropReason GUARDED_BY(mLock);
- void dispatchOnceInnerLocked(nsecs_t* nextWakeupTime);
+ void dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) REQUIRES(mLock);
// Enqueues an inbound event. Returns true if mLooper->wake() should be called.
- bool enqueueInboundEventLocked(EventEntry* entry);
+ bool enqueueInboundEventLocked(EventEntry* entry) REQUIRES(mLock);
// Cleans up input state when dropping an inbound event.
- void dropInboundEventLocked(EventEntry* entry, DropReason dropReason);
+ void dropInboundEventLocked(EventEntry* entry, DropReason dropReason) REQUIRES(mLock);
// Adds an event to a queue of recent events for debugging purposes.
- void addRecentEventLocked(EventEntry* entry);
+ void addRecentEventLocked(EventEntry* entry) REQUIRES(mLock);
// App switch latency optimization.
- bool mAppSwitchSawKeyDown;
- nsecs_t mAppSwitchDueTime;
+ bool mAppSwitchSawKeyDown GUARDED_BY(mLock);
+ nsecs_t mAppSwitchDueTime GUARDED_BY(mLock);
- static bool isAppSwitchKeyCode(int32_t keyCode);
- bool isAppSwitchKeyEventLocked(KeyEntry* keyEntry);
- bool isAppSwitchPendingLocked();
- void resetPendingAppSwitchLocked(bool handled);
+ bool isAppSwitchKeyEvent(KeyEntry* keyEntry);
+ bool isAppSwitchPendingLocked() REQUIRES(mLock);
+ void resetPendingAppSwitchLocked(bool handled) REQUIRES(mLock);
// Stale event latency optimization.
- static bool isStaleEventLocked(nsecs_t currentTime, EventEntry* entry);
+ static bool isStaleEvent(nsecs_t currentTime, EventEntry* entry);
// Blocked event latency optimization. Drops old events when the user intends
// to transfer focus to a new application.
- EventEntry* mNextUnblockedEvent;
+ EventEntry* mNextUnblockedEvent GUARDED_BY(mLock);
sp<InputWindowHandle> findTouchedWindowAtLocked(int32_t displayId, int32_t x, int32_t y,
- bool addOutsideTargets = false, bool addPortalWindows = false);
+ bool addOutsideTargets = false, bool addPortalWindows = false) REQUIRES(mLock);
// All registered connections mapped by channel file descriptor.
- KeyedVector<int, sp<Connection> > mConnectionsByFd;
+ KeyedVector<int, sp<Connection> > mConnectionsByFd GUARDED_BY(mLock);
struct IBinderHash {
std::size_t operator()(const sp<IBinder>& b) const {
return std::hash<IBinder *>{}(b.get());
}
};
- std::unordered_map<sp<IBinder>, sp<InputChannel>, IBinderHash> mInputChannelsByToken;
+ std::unordered_map<sp<IBinder>, sp<InputChannel>, IBinderHash> mInputChannelsByToken
+ GUARDED_BY(mLock);
- ssize_t getConnectionIndexLocked(const sp<InputChannel>& inputChannel);
+ ssize_t getConnectionIndexLocked(const sp<InputChannel>& inputChannel) REQUIRES(mLock);
// Input channels that will receive a copy of all input events sent to the provided display.
- std::unordered_map<int32_t, Vector<sp<InputChannel>>> mMonitoringChannelsByDisplay;
+ std::unordered_map<int32_t, Vector<sp<InputChannel>>> mMonitoringChannelsByDisplay
+ GUARDED_BY(mLock);
// Event injection and synchronization.
Condition mInjectionResultAvailableCondition;
@@ -946,17 +949,17 @@
void setInjectionResultLocked(EventEntry* entry, int32_t injectionResult);
Condition mInjectionSyncFinishedCondition;
- void incrementPendingForegroundDispatchesLocked(EventEntry* entry);
+ void incrementPendingForegroundDispatches(EventEntry* entry);
void decrementPendingForegroundDispatchesLocked(EventEntry* entry);
// Key repeat tracking.
struct KeyRepeatState {
KeyEntry* lastKeyEntry; // or null if no repeat
nsecs_t nextRepeatTime;
- } mKeyRepeatState;
+ } mKeyRepeatState GUARDED_BY(mLock);
- void resetKeyRepeatLocked();
- KeyEntry* synthesizeKeyRepeatLocked(nsecs_t currentTime);
+ void resetKeyRepeatLocked() REQUIRES(mLock);
+ KeyEntry* synthesizeKeyRepeatLocked(nsecs_t currentTime) REQUIRES(mLock);
// Key replacement tracking
struct KeyReplacement {
@@ -970,39 +973,42 @@
}
};
// Maps the key code replaced, device id tuple to the key code it was replaced with
- KeyedVector<KeyReplacement, int32_t> mReplacedKeys;
+ KeyedVector<KeyReplacement, int32_t> mReplacedKeys GUARDED_BY(mLock);
// Process certain Meta + Key combinations
void accelerateMetaShortcuts(const int32_t deviceId, const int32_t action,
int32_t& keyCode, int32_t& metaState);
// Deferred command processing.
- bool haveCommandsLocked() const;
- bool runCommandsLockedInterruptible();
- CommandEntry* postCommandLocked(Command command);
+ bool haveCommandsLocked() const REQUIRES(mLock);
+ bool runCommandsLockedInterruptible() REQUIRES(mLock);
+ CommandEntry* postCommandLocked(Command command) REQUIRES(mLock);
// Input filter processing.
- bool shouldSendKeyToInputFilterLocked(const NotifyKeyArgs* args);
- bool shouldSendMotionToInputFilterLocked(const NotifyMotionArgs* args);
+ bool shouldSendKeyToInputFilterLocked(const NotifyKeyArgs* args) REQUIRES(mLock);
+ bool shouldSendMotionToInputFilterLocked(const NotifyMotionArgs* args) REQUIRES(mLock);
// Inbound event processing.
- void drainInboundQueueLocked();
- void releasePendingEventLocked();
- void releaseInboundEventLocked(EventEntry* entry);
+ void drainInboundQueueLocked() REQUIRES(mLock);
+ void releasePendingEventLocked() REQUIRES(mLock);
+ void releaseInboundEventLocked(EventEntry* entry) REQUIRES(mLock);
// Dispatch state.
- bool mDispatchEnabled;
- bool mDispatchFrozen;
- bool mInputFilterEnabled;
+ bool mDispatchEnabled GUARDED_BY(mLock);
+ bool mDispatchFrozen GUARDED_BY(mLock);
+ bool mInputFilterEnabled GUARDED_BY(mLock);
- std::unordered_map<int32_t, Vector<sp<InputWindowHandle>>> mWindowHandlesByDisplay;
+ std::unordered_map<int32_t, Vector<sp<InputWindowHandle>>> mWindowHandlesByDisplay
+ GUARDED_BY(mLock);
// 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<IBinder>& windowHandleToken) const;
- sp<InputChannel> getInputChannelLocked(const sp<IBinder>& windowToken) const;
- bool hasWindowHandleLocked(const sp<InputWindowHandle>& windowHandle) const;
+ Vector<sp<InputWindowHandle>> getWindowHandlesLocked(int32_t displayId) const REQUIRES(mLock);
+ sp<InputWindowHandle> getWindowHandleLocked(const sp<IBinder>& windowHandleToken) const
+ REQUIRES(mLock);
+ sp<InputChannel> getInputChannelLocked(const sp<IBinder>& windowToken) const REQUIRES(mLock);
+ bool hasWindowHandleLocked(const sp<InputWindowHandle>& windowHandle) const REQUIRES(mLock);
// Focus tracking for keys, trackball, etc.
- std::unordered_map<int32_t, sp<InputWindowHandle>> mFocusedWindowHandlesByDisplay;
+ std::unordered_map<int32_t, sp<InputWindowHandle>> mFocusedWindowHandlesByDisplay
+ GUARDED_BY(mLock);
// Focus tracking for touch.
struct TouchedWindow {
@@ -1037,34 +1043,35 @@
bool isSlippery() const;
};
- KeyedVector<int32_t, TouchState> mTouchStatesByDisplay;
- TouchState mTempTouchState;
+ KeyedVector<int32_t, TouchState> mTouchStatesByDisplay GUARDED_BY(mLock);
+ TouchState mTempTouchState GUARDED_BY(mLock);
// Focused applications.
- std::unordered_map<int32_t, sp<InputApplicationHandle>> mFocusedApplicationHandlesByDisplay;
+ std::unordered_map<int32_t, sp<InputApplicationHandle>> mFocusedApplicationHandlesByDisplay
+ GUARDED_BY(mLock);
// Top focused display.
- int32_t mFocusedDisplayId;
+ int32_t mFocusedDisplayId GUARDED_BY(mLock);
// Dispatcher state at time of last ANR.
- std::string mLastANRState;
+ std::string mLastANRState GUARDED_BY(mLock);
// Dispatch inbound events.
bool dispatchConfigurationChangedLocked(
- nsecs_t currentTime, ConfigurationChangedEntry* entry);
+ nsecs_t currentTime, ConfigurationChangedEntry* entry) REQUIRES(mLock);
bool dispatchDeviceResetLocked(
- nsecs_t currentTime, DeviceResetEntry* entry);
+ nsecs_t currentTime, DeviceResetEntry* entry) REQUIRES(mLock);
bool dispatchKeyLocked(
nsecs_t currentTime, KeyEntry* entry,
- DropReason* dropReason, nsecs_t* nextWakeupTime);
+ DropReason* dropReason, nsecs_t* nextWakeupTime) REQUIRES(mLock);
bool dispatchMotionLocked(
nsecs_t currentTime, MotionEntry* entry,
- DropReason* dropReason, nsecs_t* nextWakeupTime);
+ DropReason* dropReason, nsecs_t* nextWakeupTime) REQUIRES(mLock);
void dispatchEventLocked(nsecs_t currentTime, EventEntry* entry,
- const Vector<InputTarget>& inputTargets);
+ const Vector<InputTarget>& inputTargets) REQUIRES(mLock);
- void logOutboundKeyDetailsLocked(const char* prefix, const KeyEntry* entry);
- void logOutboundMotionDetailsLocked(const char* prefix, const MotionEntry* entry);
+ void logOutboundKeyDetails(const char* prefix, const KeyEntry* entry);
+ void logOutboundMotionDetails(const char* prefix, const MotionEntry* entry);
// Keeping track of ANR timeouts.
enum InputTargetWaitCause {
@@ -1073,130 +1080,133 @@
INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY,
};
- InputTargetWaitCause mInputTargetWaitCause;
- nsecs_t mInputTargetWaitStartTime;
- nsecs_t mInputTargetWaitTimeoutTime;
- bool mInputTargetWaitTimeoutExpired;
- sp<IBinder> mInputTargetWaitApplicationToken;
+ InputTargetWaitCause mInputTargetWaitCause GUARDED_BY(mLock);
+ nsecs_t mInputTargetWaitStartTime GUARDED_BY(mLock);
+ nsecs_t mInputTargetWaitTimeoutTime GUARDED_BY(mLock);
+ bool mInputTargetWaitTimeoutExpired GUARDED_BY(mLock);
+ sp<IBinder> mInputTargetWaitApplicationToken GUARDED_BY(mLock);
// Contains the last window which received a hover event.
- sp<InputWindowHandle> mLastHoverWindowHandle;
+ sp<InputWindowHandle> mLastHoverWindowHandle GUARDED_BY(mLock);
// Finding targets for input events.
int32_t handleTargetsNotReadyLocked(nsecs_t currentTime, const EventEntry* entry,
const sp<InputApplicationHandle>& applicationHandle,
const sp<InputWindowHandle>& windowHandle,
- nsecs_t* nextWakeupTime, const char* reason);
+ nsecs_t* nextWakeupTime, const char* reason) REQUIRES(mLock);
- void removeWindowByTokenLocked(const sp<IBinder>& token);
+ void removeWindowByTokenLocked(const sp<IBinder>& token) REQUIRES(mLock);
void resumeAfterTargetsNotReadyTimeoutLocked(nsecs_t newTimeout,
- const sp<InputChannel>& inputChannel);
- nsecs_t getTimeSpentWaitingForApplicationLocked(nsecs_t currentTime);
- void resetANRTimeoutsLocked();
+ const sp<InputChannel>& inputChannel) REQUIRES(mLock);
+ nsecs_t getTimeSpentWaitingForApplicationLocked(nsecs_t currentTime) REQUIRES(mLock);
+ void resetANRTimeoutsLocked() REQUIRES(mLock);
int32_t getTargetDisplayId(const EventEntry* entry);
int32_t findFocusedWindowTargetsLocked(nsecs_t currentTime, const EventEntry* entry,
- Vector<InputTarget>& inputTargets, nsecs_t* nextWakeupTime);
+ Vector<InputTarget>& inputTargets, nsecs_t* nextWakeupTime) REQUIRES(mLock);
int32_t findTouchedWindowTargetsLocked(nsecs_t currentTime, const MotionEntry* entry,
Vector<InputTarget>& inputTargets, nsecs_t* nextWakeupTime,
- bool* outConflictingPointerActions);
+ bool* outConflictingPointerActions) REQUIRES(mLock);
void addWindowTargetLocked(const sp<InputWindowHandle>& windowHandle,
- int32_t targetFlags, BitSet32 pointerIds, Vector<InputTarget>& inputTargets);
+ int32_t targetFlags, BitSet32 pointerIds, Vector<InputTarget>& inputTargets)
+ REQUIRES(mLock);
void addMonitoringTargetsLocked(Vector<InputTarget>& inputTargets, int32_t displayId,
- float xOffset = 0, float yOffset = 0);
+ float xOffset = 0, float yOffset = 0) REQUIRES(mLock);
- void pokeUserActivityLocked(const EventEntry* eventEntry);
+ void pokeUserActivityLocked(const EventEntry* eventEntry) REQUIRES(mLock);
bool checkInjectionPermission(const sp<InputWindowHandle>& windowHandle,
const InjectionState* injectionState);
bool isWindowObscuredAtPointLocked(const sp<InputWindowHandle>& windowHandle,
- int32_t x, int32_t y) const;
- bool isWindowObscuredLocked(const sp<InputWindowHandle>& windowHandle) const;
- std::string getApplicationWindowLabelLocked(const sp<InputApplicationHandle>& applicationHandle,
+ int32_t x, int32_t y) const REQUIRES(mLock);
+ bool isWindowObscuredLocked(const sp<InputWindowHandle>& windowHandle) const REQUIRES(mLock);
+ std::string getApplicationWindowLabel(const sp<InputApplicationHandle>& applicationHandle,
const sp<InputWindowHandle>& windowHandle);
std::string checkWindowReadyForMoreInputLocked(nsecs_t currentTime,
const sp<InputWindowHandle>& windowHandle, const EventEntry* eventEntry,
- const char* targetType);
+ const char* targetType) REQUIRES(mLock);
// Manage the dispatch cycle for a single connection.
// These methods are deliberately not Interruptible because doing all of the work
// with the mutex held makes it easier to ensure that connection invariants are maintained.
// If needed, the methods post commands to run later once the critical bits are done.
void prepareDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection,
- EventEntry* eventEntry, const InputTarget* inputTarget);
+ EventEntry* eventEntry, const InputTarget* inputTarget) REQUIRES(mLock);
void enqueueDispatchEntriesLocked(nsecs_t currentTime, const sp<Connection>& connection,
- EventEntry* eventEntry, const InputTarget* inputTarget);
+ EventEntry* eventEntry, const InputTarget* inputTarget) REQUIRES(mLock);
void enqueueDispatchEntryLocked(const sp<Connection>& connection,
EventEntry* eventEntry, const InputTarget* inputTarget, int32_t dispatchMode);
- void startDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection);
+ void startDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection)
+ REQUIRES(mLock);
void finishDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection,
- uint32_t seq, bool handled);
+ uint32_t seq, bool handled) REQUIRES(mLock);
void abortBrokenDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection,
- bool notify);
+ bool notify) REQUIRES(mLock);
void drainDispatchQueueLocked(Queue<DispatchEntry>* queue);
void releaseDispatchEntryLocked(DispatchEntry* dispatchEntry);
static int handleReceiveCallback(int fd, int events, void* data);
void synthesizeCancelationEventsForAllConnectionsLocked(
- const CancelationOptions& options);
- void synthesizeCancelationEventsForMonitorsLocked(const CancelationOptions& options);
+ const CancelationOptions& options) REQUIRES(mLock);
+ void synthesizeCancelationEventsForMonitorsLocked(
+ const CancelationOptions& options) REQUIRES(mLock);
void synthesizeCancelationEventsForInputChannelLocked(const sp<InputChannel>& channel,
- const CancelationOptions& options);
+ const CancelationOptions& options) REQUIRES(mLock);
void synthesizeCancelationEventsForConnectionLocked(const sp<Connection>& connection,
- const CancelationOptions& options);
+ const CancelationOptions& options) REQUIRES(mLock);
// Splitting motion events across windows.
MotionEntry* splitMotionEvent(const MotionEntry* originalMotionEntry, BitSet32 pointerIds);
// Reset and drop everything the dispatcher is doing.
- void resetAndDropEverythingLocked(const char* reason);
+ void resetAndDropEverythingLocked(const char* reason) REQUIRES(mLock);
// Dump state.
- void dumpDispatchStateLocked(std::string& dump);
- void logDispatchStateLocked();
+ void dumpDispatchStateLocked(std::string& dump) REQUIRES(mLock);
+ void logDispatchStateLocked() REQUIRES(mLock);
// Registration.
- void removeMonitorChannelLocked(const sp<InputChannel>& inputChannel);
- status_t unregisterInputChannelLocked(const sp<InputChannel>& inputChannel, bool notify);
-
- // Add or remove a connection to the mActiveConnections vector.
- void activateConnectionLocked(Connection* connection);
- void deactivateConnectionLocked(Connection* connection);
+ void removeMonitorChannelLocked(const sp<InputChannel>& inputChannel) REQUIRES(mLock);
+ status_t unregisterInputChannelLocked(const sp<InputChannel>& inputChannel, bool notify)
+ REQUIRES(mLock);
// Interesting events that we might like to log or tell the framework about.
void onDispatchCycleFinishedLocked(
- nsecs_t currentTime, const sp<Connection>& connection, uint32_t seq, bool handled);
+ nsecs_t currentTime, const sp<Connection>& connection, uint32_t seq, bool handled)
+ REQUIRES(mLock);
void onDispatchCycleBrokenLocked(
- nsecs_t currentTime, const sp<Connection>& connection);
+ nsecs_t currentTime, const sp<Connection>& connection) REQUIRES(mLock);
void onFocusChangedLocked(const sp<InputWindowHandle>& oldFocus,
- const sp<InputWindowHandle>& newFocus);
+ const sp<InputWindowHandle>& newFocus) REQUIRES(mLock);
void onANRLocked(
nsecs_t currentTime, const sp<InputApplicationHandle>& applicationHandle,
const sp<InputWindowHandle>& windowHandle,
- nsecs_t eventTime, nsecs_t waitStartTime, const char* reason);
+ nsecs_t eventTime, nsecs_t waitStartTime, const char* reason) REQUIRES(mLock);
// Outbound policy interactions.
- void doNotifyConfigurationChangedInterruptible(CommandEntry* commandEntry);
- void doNotifyInputChannelBrokenLockedInterruptible(CommandEntry* commandEntry);
- void doNotifyFocusChangedLockedInterruptible(CommandEntry* commandEntry);
- void doNotifyANRLockedInterruptible(CommandEntry* commandEntry);
- void doInterceptKeyBeforeDispatchingLockedInterruptible(CommandEntry* commandEntry);
- void doDispatchCycleFinishedLockedInterruptible(CommandEntry* commandEntry);
+ void doNotifyConfigurationChangedLockedInterruptible(CommandEntry* commandEntry)
+ REQUIRES(mLock);
+ void doNotifyInputChannelBrokenLockedInterruptible(CommandEntry* commandEntry) REQUIRES(mLock);
+ void doNotifyFocusChangedLockedInterruptible(CommandEntry* commandEntry) REQUIRES(mLock);
+ void doNotifyANRLockedInterruptible(CommandEntry* commandEntry) REQUIRES(mLock);
+ void doInterceptKeyBeforeDispatchingLockedInterruptible(CommandEntry* commandEntry)
+ REQUIRES(mLock);
+ void doDispatchCycleFinishedLockedInterruptible(CommandEntry* commandEntry) REQUIRES(mLock);
bool afterKeyEventLockedInterruptible(const sp<Connection>& connection,
- DispatchEntry* dispatchEntry, KeyEntry* keyEntry, bool handled);
+ DispatchEntry* dispatchEntry, KeyEntry* keyEntry, bool handled) REQUIRES(mLock);
bool afterMotionEventLockedInterruptible(const sp<Connection>& connection,
DispatchEntry* dispatchEntry, MotionEntry* motionEntry, bool handled);
- void doPokeUserActivityLockedInterruptible(CommandEntry* commandEntry);
+ void doPokeUserActivityLockedInterruptible(CommandEntry* commandEntry) REQUIRES(mLock);
void initializeKeyEvent(KeyEvent* event, const KeyEntry* entry);
// Statistics gathering.
- void updateDispatchStatisticsLocked(nsecs_t currentTime, const EventEntry* entry,
+ void updateDispatchStatistics(nsecs_t currentTime, const EventEntry* entry,
int32_t injectionResult, nsecs_t timeSpentWaitingForApplication);
- void traceInboundQueueLengthLocked();
- void traceOutboundQueueLengthLocked(const sp<Connection>& connection);
- void traceWaitQueueLengthLocked(const sp<Connection>& connection);
+ void traceInboundQueueLengthLocked() REQUIRES(mLock);
+ void traceOutboundQueueLength(const sp<Connection>& connection);
+ void traceWaitQueueLength(const sp<Connection>& connection);
sp<InputReporterInterface> mReporter;
};
diff --git a/services/inputflinger/InputManager.cpp b/services/inputflinger/InputManager.cpp
index a7fd9ba..b0157a1 100644
--- a/services/inputflinger/InputManager.cpp
+++ b/services/inputflinger/InputManager.cpp
@@ -103,7 +103,8 @@
}
};
-void InputManager::setInputWindows(const Vector<InputWindowInfo>& infos) {
+void InputManager::setInputWindows(const Vector<InputWindowInfo>& infos,
+ const sp<ISetInputWindowsListener>& setInputWindowsListener) {
std::unordered_map<int32_t, Vector<sp<InputWindowHandle>>> handlesPerDisplay;
Vector<sp<InputWindowHandle>> handles;
@@ -112,7 +113,7 @@
handlesPerDisplay[info.displayId].add(new BinderWindowHandle(info));
}
for (auto const& i : handlesPerDisplay) {
- mDispatcher->setInputWindows(i.second, i.first);
+ mDispatcher->setInputWindows(i.second, i.first, setInputWindowsListener);
}
}
diff --git a/services/inputflinger/InputManager.h b/services/inputflinger/InputManager.h
index e632da3..ff9a080 100644
--- a/services/inputflinger/InputManager.h
+++ b/services/inputflinger/InputManager.h
@@ -29,6 +29,7 @@
#include <input/Input.h>
#include <input/InputTransport.h>
+#include <input/ISetInputWindowsListener.h>
#include <input/IInputFlinger.h>
#include <utils/Errors.h>
@@ -93,7 +94,8 @@
virtual sp<InputClassifierInterface> getClassifier();
virtual sp<InputDispatcherInterface> getDispatcher();
- virtual void setInputWindows(const Vector<InputWindowInfo>& handles);
+ virtual void setInputWindows(const Vector<InputWindowInfo>& handles,
+ const sp<ISetInputWindowsListener>& setInputWindowsListener);
virtual void transferTouchFocus(const sp<IBinder>& fromToken, const sp<IBinder>& toToken);
virtual void registerInputChannel(const sp<InputChannel>& channel);
diff --git a/services/inputflinger/InputReader.cpp b/services/inputflinger/InputReader.cpp
index 1a1ae21..21ba029 100644
--- a/services/inputflinger/InputReader.cpp
+++ b/services/inputflinger/InputReader.cpp
@@ -6565,6 +6565,8 @@
const int32_t displayId = getAssociatedDisplay().value_or(ADISPLAY_ID_NONE);
const int32_t deviceId = getDeviceId();
std::vector<TouchVideoFrame> frames = mDevice->getEventHub()->getVideoFrames(deviceId);
+ std::for_each(frames.begin(), frames.end(),
+ [this](TouchVideoFrame& frame) { frame.rotate(this->mSurfaceOrientation); });
NotifyMotionArgs args(mContext->getNextSequenceNum(), when, deviceId,
source, displayId, policyFlags,
action, actionButton, flags, metaState, buttonState, MotionClassification::NONE,
diff --git a/services/inputflinger/TouchVideoDevice.cpp b/services/inputflinger/TouchVideoDevice.cpp
index ad70ccc..76df3a1 100644
--- a/services/inputflinger/TouchVideoDevice.cpp
+++ b/services/inputflinger/TouchVideoDevice.cpp
@@ -37,10 +37,10 @@
namespace android {
TouchVideoDevice::TouchVideoDevice(int fd, std::string&& name, std::string&& devicePath,
- uint32_t width, uint32_t height,
+ uint32_t height, uint32_t width,
const std::array<const int16_t*, NUM_BUFFERS>& readLocations) :
mFd(fd), mName(std::move(name)), mPath(std::move(devicePath)),
- mWidth(width), mHeight(height),
+ mHeight(height), mWidth(width),
mReadLocations(readLocations) {
mFrames.reserve(MAX_QUEUE_SIZE);
};
@@ -87,9 +87,9 @@
ALOGE("VIDIOC_G_FMT failed: %s", strerror(errno));
return nullptr;
}
- const uint32_t width = v4l2_fmt.fmt.pix.width;
const uint32_t height = v4l2_fmt.fmt.pix.height;
- ALOGI("Frame dimensions: width = %" PRIu32 " height = %" PRIu32, width, height);
+ const uint32_t width = v4l2_fmt.fmt.pix.width;
+ ALOGI("Frame dimensions: height = %" PRIu32 " width = %" PRIu32, height, width);
struct v4l2_requestbuffers req;
req.count = NUM_BUFFERS;
@@ -116,7 +116,7 @@
ALOGE("VIDIOC_QUERYBUF failed: %s", strerror(errno));
return nullptr;
}
- if (buf.length != width * height * sizeof(int16_t)) {
+ if (buf.length != height * width * sizeof(int16_t)) {
ALOGE("Unexpected value of buf.length = %i (offset = %" PRIu32 ")",
buf.length, buf.m.offset);
return nullptr;
@@ -148,7 +148,7 @@
}
// Using 'new' to access a non-public constructor.
return std::unique_ptr<TouchVideoDevice>(new TouchVideoDevice(
- fd.release(), std::move(name), std::move(devicePath), width, height, readLocations));
+ fd.release(), std::move(name), std::move(devicePath), height, width, readLocations));
}
size_t TouchVideoDevice::readAndQueueFrames() {
@@ -193,10 +193,10 @@
ALOGW("The timestamp %ld.%ld was not acquired using CLOCK_MONOTONIC",
buf.timestamp.tv_sec, buf.timestamp.tv_usec);
}
- std::vector<int16_t> data(mWidth * mHeight);
+ std::vector<int16_t> data(mHeight * mWidth);
const int16_t* readFrom = mReadLocations[buf.index];
- std::copy(readFrom, readFrom + mWidth * mHeight, data.begin());
- TouchVideoFrame frame(mWidth, mHeight, std::move(data), buf.timestamp);
+ std::copy(readFrom, readFrom + mHeight * mWidth, data.begin());
+ TouchVideoFrame frame(mHeight, mWidth, std::move(data), buf.timestamp);
result = ioctl(mFd.get(), VIDIOC_QBUF, &buf);
if (result == -1) {
@@ -230,7 +230,7 @@
}
for (const int16_t* buffer : mReadLocations) {
void* bufferAddress = static_cast<void*>(const_cast<int16_t*>(buffer));
- result = munmap(bufferAddress, mWidth * mHeight * sizeof(int16_t));
+ result = munmap(bufferAddress, mHeight * mWidth * sizeof(int16_t));
if (result == -1) {
ALOGE("%s: Couldn't unmap: [%s]", __func__, strerror(errno));
}
@@ -238,9 +238,9 @@
}
std::string TouchVideoDevice::dump() const {
- return StringPrintf("Video device %s (%s) : width=%" PRIu32 ", height=%" PRIu32
+ return StringPrintf("Video device %s (%s) : height=%" PRIu32 ", width=%" PRIu32
", fd=%i, hasValidFd=%s",
- mName.c_str(), mPath.c_str(), mWidth, mHeight, mFd.get(),
+ mName.c_str(), mPath.c_str(), mHeight, mWidth, mFd.get(),
hasValidFd() ? "true" : "false");
}
diff --git a/services/inputflinger/TouchVideoDevice.h b/services/inputflinger/TouchVideoDevice.h
index 3d5c8c6..0e7e2ef 100644
--- a/services/inputflinger/TouchVideoDevice.h
+++ b/services/inputflinger/TouchVideoDevice.h
@@ -54,14 +54,14 @@
*/
const std::string& getPath() const { return mPath; }
/**
- * Get the width of the heatmap frame
- */
- uint32_t getWidth() const { return mWidth; }
- /**
* Get the height of the heatmap frame
*/
uint32_t getHeight() const { return mHeight; }
/**
+ * Get the width of the heatmap frame
+ */
+ uint32_t getWidth() const { return mWidth; }
+ /**
* Direct read of the frame. Stores the frame into internal buffer.
* Return the number of frames that were successfully read.
*
@@ -87,8 +87,8 @@
std::string mName;
std::string mPath;
- uint32_t mWidth;
uint32_t mHeight;
+ uint32_t mWidth;
static constexpr int INVALID_FD = -1;
/**
@@ -110,7 +110,7 @@
* To get a new TouchVideoDevice, use 'create' instead.
*/
explicit TouchVideoDevice(int fd, std::string&& name, std::string&& devicePath,
- uint32_t width, uint32_t height,
+ uint32_t height, uint32_t width,
const std::array<const int16_t*, NUM_BUFFERS>& readLocations);
/**
* Read all currently available frames.
diff --git a/services/inputflinger/host/InputFlinger.h b/services/inputflinger/host/InputFlinger.h
index 9d0be95..a00b5fb 100644
--- a/services/inputflinger/host/InputFlinger.h
+++ b/services/inputflinger/host/InputFlinger.h
@@ -24,6 +24,7 @@
#include <cutils/compiler.h>
#include <input/IInputFlinger.h>
+#include <input/ISetInputWindowsListener.h>
#include <utils/String8.h>
#include <utils/String16.h>
#include <utils/StrongPointer.h>
@@ -39,7 +40,7 @@
InputFlinger() ANDROID_API;
virtual status_t dump(int fd, const Vector<String16>& args);
- void setInputWindows(const Vector<InputWindowInfo>&) {}
+ void setInputWindows(const Vector<InputWindowInfo>&, const sp<ISetInputWindowsListener>&) {}
void transferTouchFocus(const sp<IBinder>&, const sp<IBinder>&) {}
void registerInputChannel(const sp<InputChannel>&) {}
void unregisterInputChannel(const sp<InputChannel>&) {}
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index fbacb9b..80a55f1 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -335,6 +335,7 @@
KeyedVector<int32_t, Device*> mDevices;
std::vector<std::string> mExcludedDevices;
List<RawEvent> mEvents;
+ std::unordered_map<int32_t /*deviceId*/, std::vector<TouchVideoFrame>> mVideoFrames;
protected:
virtual ~FakeEventHub() {
@@ -499,6 +500,11 @@
}
}
+ void setVideoFrames(std::unordered_map<int32_t /*deviceId*/,
+ std::vector<TouchVideoFrame>> videoFrames) {
+ mVideoFrames = std::move(videoFrames);
+ }
+
void assertQueueIsEmpty() {
ASSERT_EQ(size_t(0), mEvents.size())
<< "Expected the event queue to be empty (fully consumed).";
@@ -614,6 +620,12 @@
}
virtual std::vector<TouchVideoFrame> getVideoFrames(int32_t deviceId) {
+ auto it = mVideoFrames.find(deviceId);
+ if (it != mVideoFrames.end()) {
+ std::vector<TouchVideoFrame> frames = std::move(it->second);
+ mVideoFrames.erase(deviceId);
+ return frames;
+ }
return {};
}
@@ -6415,4 +6427,78 @@
ASSERT_EQ(size_t(2), iter->second.size());
}
+TEST_F(MultiTouchInputMapperTest, VideoFrames_ReceivedByListener) {
+ MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice);
+ prepareAxes(POSITION);
+ addConfigurationProperty("touch.deviceType", "touchScreen");
+ prepareDisplay(DISPLAY_ORIENTATION_0);
+ addMapperAndConfigure(mapper);
+
+ NotifyMotionArgs motionArgs;
+ // Unrotated video frame
+ TouchVideoFrame frame(3, 2, {1, 2, 3, 4, 5, 6}, {1, 2});
+ std::vector<TouchVideoFrame> frames{frame};
+ mFakeEventHub->setVideoFrames({{mDevice->getId(), frames}});
+ processPosition(mapper, 100, 200);
+ processSync(mapper);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+ ASSERT_EQ(frames, motionArgs.videoFrames);
+
+ // Subsequent touch events should not have any videoframes
+ // This is implemented separately in FakeEventHub,
+ // but that should match the behaviour of TouchVideoDevice.
+ processPosition(mapper, 200, 200);
+ processSync(mapper);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+ ASSERT_EQ(std::vector<TouchVideoFrame>(), motionArgs.videoFrames);
+}
+
+TEST_F(MultiTouchInputMapperTest, VideoFrames_AreRotated) {
+ MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice);
+ prepareAxes(POSITION);
+ addConfigurationProperty("touch.deviceType", "touchScreen");
+ addMapperAndConfigure(mapper);
+ // Unrotated video frame
+ TouchVideoFrame frame(3, 2, {1, 2, 3, 4, 5, 6}, {1, 2});
+ NotifyMotionArgs motionArgs;
+
+ // Test all 4 orientations
+ for (int32_t orientation : {DISPLAY_ORIENTATION_0, DISPLAY_ORIENTATION_90,
+ DISPLAY_ORIENTATION_180, DISPLAY_ORIENTATION_270}) {
+ SCOPED_TRACE("Orientation " + StringPrintf("%i", orientation));
+ clearViewports();
+ prepareDisplay(orientation);
+ std::vector<TouchVideoFrame> frames{frame};
+ mFakeEventHub->setVideoFrames({{mDevice->getId(), frames}});
+ processPosition(mapper, 100, 200);
+ processSync(mapper);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+ frames[0].rotate(orientation);
+ ASSERT_EQ(frames, motionArgs.videoFrames);
+ }
+}
+
+TEST_F(MultiTouchInputMapperTest, VideoFrames_MultipleFramesAreRotated) {
+ MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice);
+ prepareAxes(POSITION);
+ addConfigurationProperty("touch.deviceType", "touchScreen");
+ addMapperAndConfigure(mapper);
+ // Unrotated video frames. There's no rule that they must all have the same dimensions,
+ // so mix these.
+ TouchVideoFrame frame1(3, 2, {1, 2, 3, 4, 5, 6}, {1, 2});
+ TouchVideoFrame frame2(3, 3, {0, 1, 2, 3, 4, 5, 6, 7, 8}, {1, 3});
+ TouchVideoFrame frame3(2, 2, {10, 20, 10, 0}, {1, 4});
+ std::vector<TouchVideoFrame> frames{frame1, frame2, frame3};
+ NotifyMotionArgs motionArgs;
+
+ prepareDisplay(DISPLAY_ORIENTATION_90);
+ mFakeEventHub->setVideoFrames({{mDevice->getId(), frames}});
+ processPosition(mapper, 100, 200);
+ processSync(mapper);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+ std::for_each(frames.begin(), frames.end(),
+ [](TouchVideoFrame& frame) { frame.rotate(DISPLAY_ORIENTATION_90); });
+ ASSERT_EQ(frames, motionArgs.videoFrames);
+}
+
} // namespace android
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index 734ed6c..3304fd1 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -142,6 +142,7 @@
"MonitoredProducer.cpp",
"NativeWindowSurface.cpp",
"RenderArea.cpp",
+ "RegionSamplingThread.cpp",
"Scheduler/DispSync.cpp",
"Scheduler/DispSyncSource.cpp",
"Scheduler/EventControlThread.cpp",
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index c077b68..2501fae 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -69,13 +69,6 @@
BufferLayer::~BufferLayer() {
mFlinger->deleteTextureAsync(mTextureName);
-
- if (destroyAllHwcLayersPlusChildren()) {
- ALOGE("Found stale hardware composer layers when destroying "
- "surface flinger layer %s",
- mName.string());
- }
-
mFlinger->mTimeStats->onDestroy(getSequence());
}
@@ -380,8 +373,7 @@
return true;
}
-bool BufferLayer::latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime,
- const sp<Fence>& releaseFence) {
+bool BufferLayer::latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime) {
ATRACE_CALL();
bool refreshRequired = latchSidebandStream(recomputeVisibleRegions);
@@ -420,7 +412,7 @@
return false;
}
- status_t err = updateTexImage(recomputeVisibleRegions, latchTime, releaseFence);
+ status_t err = updateTexImage(recomputeVisibleRegions, latchTime);
if (err != NO_ERROR) {
return false;
}
diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h
index d358bae..e3b10fc 100644
--- a/services/surfaceflinger/BufferLayer.h
+++ b/services/surfaceflinger/BufferLayer.h
@@ -93,11 +93,7 @@
// the visible regions need to be recomputed (this is a fairly heavy
// operation, so this should be set only if needed). Typically this is used
// to figure out if the content or size of a surface has changed.
- // If there was a GL composition step rendering the previous frame, then
- // releaseFence will be populated with a native fence that fires when
- // composition has completed.
- bool latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime,
- const sp<Fence>& releaseFence) override;
+ bool latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime) override;
bool isBufferLatched() const override { return mRefreshPending; }
@@ -142,8 +138,7 @@
virtual void setFilteringEnabled(bool enabled) = 0;
virtual status_t bindTextureImage() = 0;
- virtual status_t updateTexImage(bool& recomputeVisibleRegions, nsecs_t latchTime,
- const sp<Fence>& flushFence) = 0;
+ virtual status_t updateTexImage(bool& recomputeVisibleRegions, nsecs_t latchTime) = 0;
virtual status_t updateActiveBuffer() = 0;
virtual status_t updateFrameNumber(nsecs_t latchTime) = 0;
diff --git a/services/surfaceflinger/BufferLayerConsumer.cpp b/services/surfaceflinger/BufferLayerConsumer.cpp
index 7ed8184..6866e5c 100644
--- a/services/surfaceflinger/BufferLayerConsumer.cpp
+++ b/services/surfaceflinger/BufferLayerConsumer.cpp
@@ -100,8 +100,7 @@
status_t BufferLayerConsumer::updateTexImage(BufferRejecter* rejecter, nsecs_t expectedPresentTime,
bool* autoRefresh, bool* queuedBuffer,
- uint64_t maxFrameNumber,
- const sp<Fence>& releaseFence) {
+ uint64_t maxFrameNumber) {
ATRACE_CALL();
BLC_LOGV("updateTexImage");
Mutex::Autolock lock(mMutex);
@@ -146,7 +145,7 @@
}
// Release the previous buffer.
- err = updateAndReleaseLocked(item, &mPendingRelease, releaseFence);
+ err = updateAndReleaseLocked(item, &mPendingRelease);
if (err != NO_ERROR) {
return err;
}
@@ -224,25 +223,11 @@
}
status_t BufferLayerConsumer::updateAndReleaseLocked(const BufferItem& item,
- PendingRelease* pendingRelease,
- const sp<Fence>& releaseFence) {
+ PendingRelease* pendingRelease) {
status_t err = NO_ERROR;
int slot = item.mSlot;
- // Do whatever sync ops we need to do before releasing the old slot.
- if (slot != mCurrentTexture) {
- err = syncForReleaseLocked(releaseFence);
- if (err != NO_ERROR) {
- // Release the buffer we just acquired. It's not safe to
- // release the old buffer, so instead we just drop the new frame.
- // As we are still under lock since acquireBuffer, it is safe to
- // release by slot.
- releaseBufferLocked(slot, mSlots[slot].mGraphicBuffer);
- return err;
- }
- }
-
BLC_LOGV("updateAndRelease: (slot=%d buf=%p) -> (slot=%d buf=%p)", mCurrentTexture,
mCurrentTextureBuffer != nullptr ? mCurrentTextureBuffer->handle : 0, slot,
mSlots[slot].mGraphicBuffer->handle);
@@ -298,30 +283,6 @@
return mRE.bindExternalTextureBuffer(mTexName, mCurrentTextureBuffer, mCurrentFence, false);
}
-status_t BufferLayerConsumer::syncForReleaseLocked(const sp<Fence>& releaseFence) {
- BLC_LOGV("syncForReleaseLocked");
-
- if (mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) {
- if (mRE.useNativeFenceSync() && releaseFence != Fence::NO_FENCE) {
- // TODO(alecmouri): fail further upstream if the fence is invalid
- if (!releaseFence->isValid()) {
- BLC_LOGE("syncForReleaseLocked: failed to flush RenderEngine");
- return UNKNOWN_ERROR;
- }
- status_t err =
- addReleaseFenceLocked(mCurrentTexture, mCurrentTextureBuffer, releaseFence);
- if (err != OK) {
- BLC_LOGE("syncForReleaseLocked: error adding release fence: "
- "%s (%d)",
- strerror(-err), err);
- return err;
- }
- }
- }
-
- return OK;
-}
-
void BufferLayerConsumer::getTransformMatrix(float mtx[16]) {
Mutex::Autolock lock(mMutex);
memcpy(mtx, mCurrentTransformMatrix, sizeof(mCurrentTransformMatrix));
diff --git a/services/surfaceflinger/BufferLayerConsumer.h b/services/surfaceflinger/BufferLayerConsumer.h
index e2ef399..e2a6d2e 100644
--- a/services/surfaceflinger/BufferLayerConsumer.h
+++ b/services/surfaceflinger/BufferLayerConsumer.h
@@ -92,8 +92,7 @@
// used to reject the newly acquired buffer. It also does not bind the
// RenderEngine texture until bindTextureImage is called.
status_t updateTexImage(BufferRejecter* rejecter, nsecs_t expectedPresentTime,
- bool* autoRefresh, bool* queuedBuffer, uint64_t maxFrameNumber,
- const sp<Fence>& releaseFence);
+ bool* autoRefresh, bool* queuedBuffer, uint64_t maxFrameNumber);
// See BufferLayerConsumer::bindTextureImageLocked().
status_t bindTextureImage();
@@ -212,8 +211,7 @@
// completion of the method will instead be returned to the caller, so that
// it may call releaseBufferLocked itself later.
status_t updateAndReleaseLocked(const BufferItem& item,
- PendingRelease* pendingRelease = nullptr,
- const sp<Fence>& releaseFence = Fence::NO_FENCE);
+ PendingRelease* pendingRelease = nullptr);
// Binds mTexName and the current buffer to TEXTURE_EXTERNAL target.
// If the bind succeeds, this calls doFenceWait.
@@ -244,12 +242,6 @@
// access the current texture buffer.
status_t doFenceWaitLocked() const;
- // syncForReleaseLocked performs the synchronization needed to release the
- // current slot from RenderEngine. If needed it will set the current
- // slot's fence to guard against a producer accessing the buffer before
- // the outstanding accesses have completed.
- status_t syncForReleaseLocked(const sp<Fence>& releaseFence);
-
// The default consumer usage flags that BufferLayerConsumer always sets on its
// BufferQueue instance; these will be OR:d with any additional flags passed
// from the BufferLayerConsumer user. In particular, BufferLayerConsumer will always
diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp
index 5a60fcd..96c4992 100644
--- a/services/surfaceflinger/BufferQueueLayer.cpp
+++ b/services/surfaceflinger/BufferQueueLayer.cpp
@@ -225,8 +225,7 @@
return mConsumer->bindTextureImage();
}
-status_t BufferQueueLayer::updateTexImage(bool& recomputeVisibleRegions, nsecs_t latchTime,
- const sp<Fence>& releaseFence) {
+status_t BufferQueueLayer::updateTexImage(bool& recomputeVisibleRegions, nsecs_t latchTime) {
// This boolean is used to make sure that SurfaceFlinger's shadow copy
// of the buffer queue isn't modified when the buffer queue is returning
// BufferItem's that weren't actually queued. This can happen in shared
@@ -237,9 +236,7 @@
getProducerStickyTransform() != 0, mName.string(), mOverrideScalingMode,
getTransformToDisplayInverse(), mFreezeGeometryUpdates);
- nsecs_t expectedPresentTime = mFlinger->mUseScheduler
- ? mFlinger->mScheduler->expectedPresentTime()
- : mFlinger->mPrimaryDispSync->expectedPresentTime();
+ nsecs_t expectedPresentTime = mFlinger->mScheduler->expectedPresentTime();
if (isRemovedFromCurrentState()) {
expectedPresentTime = 0;
@@ -264,9 +261,8 @@
const uint64_t maxFrameNumberToAcquire =
std::min(mLastFrameNumberReceived.load(), lastSignaledFrameNumber);
- status_t updateResult =
- mConsumer->updateTexImage(&r, expectedPresentTime, &mAutoRefresh, &queuedBuffer,
- maxFrameNumberToAcquire, releaseFence);
+ status_t updateResult = mConsumer->updateTexImage(&r, expectedPresentTime, &mAutoRefresh,
+ &queuedBuffer, maxFrameNumberToAcquire);
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.
@@ -393,7 +389,7 @@
void BufferQueueLayer::fakeVsync() {
mRefreshPending = false;
bool ignored = false;
- latchBuffer(ignored, systemTime(), Fence::NO_FENCE);
+ latchBuffer(ignored, systemTime());
usleep(16000);
releasePendingBuffer(systemTime());
}
@@ -401,8 +397,8 @@
void BufferQueueLayer::onFrameAvailable(const BufferItem& item) {
// Add this buffer from our internal queue tracker
{ // Autolock scope
- // Report the requested present time to the Scheduler.
- if (mFlinger->mUseScheduler) {
+ if (mFlinger->mUse90Hz && mFlinger->mUseSmart90ForVideo) {
+ // Report the requested present time to the Scheduler, if the feature is turned on.
mFlinger->mScheduler->addFramePresentTimeForLayer(item.mTimestamp,
item.mIsAutoTimestamp, mName.c_str());
}
diff --git a/services/surfaceflinger/BufferQueueLayer.h b/services/surfaceflinger/BufferQueueLayer.h
index 30107e2..fbb8c14 100644
--- a/services/surfaceflinger/BufferQueueLayer.h
+++ b/services/surfaceflinger/BufferQueueLayer.h
@@ -91,8 +91,7 @@
void setFilteringEnabled(bool enabled) override;
status_t bindTextureImage() override;
- status_t updateTexImage(bool& recomputeVisibleRegions, nsecs_t latchTime,
- const sp<Fence>& releaseFence) override;
+ status_t updateTexImage(bool& recomputeVisibleRegions, nsecs_t latchTime) override;
status_t updateActiveBuffer() override;
status_t updateFrameNumber(nsecs_t latchTime) override;
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index 292d4a5..f6b69eb 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -471,8 +471,7 @@
return engine.bindExternalTextureBuffer(mTextureName, s.buffer, s.acquireFence, false);
}
-status_t BufferStateLayer::updateTexImage(bool& /*recomputeVisibleRegions*/, nsecs_t latchTime,
- const sp<Fence>& releaseFence) {
+status_t BufferStateLayer::updateTexImage(bool& /*recomputeVisibleRegions*/, nsecs_t latchTime) {
const State& s(getDrawingState());
if (!s.buffer) {
@@ -514,59 +513,7 @@
handle->latchTime = latchTime;
}
- // Handle sync fences
- if (SyncFeatures::getInstance().useNativeFenceSync() && releaseFence != Fence::NO_FENCE) {
- // TODO(alecmouri): Fail somewhere upstream if the fence is invalid.
- if (!releaseFence->isValid()) {
- mFlinger->mTimeStats->onDestroy(layerID);
- return UNKNOWN_ERROR;
- }
-
- // Check status of fences first because merging is expensive.
- // Merging an invalid fence with any other fence results in an
- // invalid fence.
- auto currentStatus = s.acquireFence->getStatus();
- if (currentStatus == Fence::Status::Invalid) {
- ALOGE("Existing fence has invalid state");
- mFlinger->mTimeStats->onDestroy(layerID);
- return BAD_VALUE;
- }
-
- auto incomingStatus = releaseFence->getStatus();
- if (incomingStatus == Fence::Status::Invalid) {
- ALOGE("New fence has invalid state");
- mDrawingState.acquireFence = releaseFence;
- mFlinger->mTimeStats->onDestroy(layerID);
- return BAD_VALUE;
- }
-
- // If both fences are signaled or both are unsignaled, we need to merge
- // them to get an accurate timestamp.
- if (currentStatus == incomingStatus) {
- char fenceName[32] = {};
- snprintf(fenceName, 32, "%.28s:%d", mName.string(), mFrameNumber);
- sp<Fence> mergedFence =
- 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
- mDrawingState.acquireFence = releaseFence;
- mFlinger->mTimeStats->onDestroy(layerID);
- return BAD_VALUE;
- }
- 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.
- // There's a small race if both fences signal at about the same time
- // and their statuses are retrieved with unfortunate timing. However,
- // 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.
- mDrawingState.acquireFence = releaseFence;
- }
- } else {
+ if (!SyncFeatures::getInstance().useNativeFenceSync()) {
// Bind the new buffer to the GL texture.
//
// Older devices require the "implicit" synchronization provided
diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h
index a97f0a4..0b03f49 100644
--- a/services/surfaceflinger/BufferStateLayer.h
+++ b/services/surfaceflinger/BufferStateLayer.h
@@ -125,8 +125,7 @@
void setFilteringEnabled(bool enabled) override;
status_t bindTextureImage() override;
- status_t updateTexImage(bool& recomputeVisibleRegions, nsecs_t latchTime,
- const sp<Fence>& releaseFence) override;
+ status_t updateTexImage(bool& recomputeVisibleRegions, nsecs_t latchTime) override;
status_t updateActiveBuffer() override;
status_t updateFrameNumber(nsecs_t latchTime) override;
diff --git a/services/surfaceflinger/CompositionEngine/Android.bp b/services/surfaceflinger/CompositionEngine/Android.bp
index f5376a5..e86d35d 100644
--- a/services/surfaceflinger/CompositionEngine/Android.bp
+++ b/services/surfaceflinger/CompositionEngine/Android.bp
@@ -91,6 +91,7 @@
"tests/DisplayTest.cpp",
"tests/HwcBufferCacheTest.cpp",
"tests/LayerTest.cpp",
+ "tests/MockHWC2.cpp",
"tests/MockHWComposer.cpp",
"tests/OutputTest.cpp",
"tests/OutputLayerTest.cpp",
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h
index 2201bdd..785a6d7 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h
@@ -36,6 +36,10 @@
* Used by LayerFE::getCompositionState
*/
struct LayerFECompositionState {
+ // TODO(lpique): b/121291683 Remove this one we are sure we don't need the
+ // value recomputed / set every frame.
+ Region geomVisibleRegion;
+
/*
* Presentation
*/
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
index 84b2423..54e6bd6 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
@@ -17,6 +17,7 @@
#pragma once
#include <cstdint>
+#include <optional>
#include <string>
#include <math/mat4.h>
@@ -25,6 +26,8 @@
#include <ui/Transform.h>
#include <utils/StrongPointer.h>
+#include "DisplayHardware/DisplayIdentification.h"
+
namespace android::compositionengine {
class DisplayColorProfile;
@@ -117,7 +120,8 @@
// 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>,
+ virtual std::unique_ptr<OutputLayer> getOrCreateOutputLayer(std::optional<DisplayId>,
+ std::shared_ptr<Layer>,
sp<LayerFE>) = 0;
// Sets the new ordered set of output layers for this output
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h
index 48cb581..e7a17c4 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h
@@ -16,14 +16,18 @@
#pragma once
+#include <optional>
#include <string>
#include <utils/StrongPointer.h>
+#include "DisplayHardware/DisplayIdentification.h"
+
namespace android {
namespace compositionengine {
+class CompositionEngine;
class Output;
class Layer;
class LayerFE;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h
index 2009380..e69b99f 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h
@@ -71,7 +71,7 @@
virtual status_t prepareFrame() = 0;
// Allocates a buffer as scratch space for GPU composition
- virtual sp<GraphicBuffer> dequeueBuffer() = 0;
+ virtual sp<GraphicBuffer> dequeueBuffer(base::unique_fd* bufferFence) = 0;
// Queues the drawn buffer for consumption by HWC. readyFence is the fence
// which will fire when the buffer is ready for consumption.
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
index 3fd057c..b1d1f42 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
@@ -67,7 +67,8 @@
compositionengine::OutputLayer* getOutputLayerForLayer(
compositionengine::Layer*) const override;
std::unique_ptr<compositionengine::OutputLayer> getOrCreateOutputLayer(
- std::shared_ptr<compositionengine::Layer>, sp<LayerFE>) override;
+ std::optional<DisplayId>, std::shared_ptr<compositionengine::Layer>,
+ sp<LayerFE>) override;
void setOutputLayersOrderedByZ(OutputLayers&&) override;
const OutputLayers& getOutputLayersOrderedByZ() const override;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h
index 5798540..d8f0cdd 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h
@@ -22,6 +22,8 @@
#include <compositionengine/OutputLayer.h>
#include <compositionengine/impl/OutputLayerCompositionState.h>
+#include "DisplayHardware/DisplayIdentification.h"
+
namespace android::compositionengine::impl {
class OutputLayer : public compositionengine::OutputLayer {
@@ -30,6 +32,8 @@
sp<compositionengine::LayerFE>);
~OutputLayer() override;
+ void initialize(const CompositionEngine&, std::optional<DisplayId>);
+
const compositionengine::Output& getOutput() const override;
compositionengine::Layer& getLayer() const override;
compositionengine::LayerFE& getLayerFE() const override;
@@ -48,7 +52,7 @@
};
std::unique_ptr<compositionengine::OutputLayer> createOutputLayer(
- const compositionengine::Output&, std::shared_ptr<compositionengine::Layer>,
- sp<compositionengine::LayerFE>);
+ const CompositionEngine&, std::optional<DisplayId>, 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
index 58b13ed..3c79084 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h
@@ -52,7 +52,7 @@
void setProtected(bool useProtected) override;
status_t beginFrame(bool mustRecompose) override;
status_t prepareFrame() override;
- sp<GraphicBuffer> dequeueBuffer() override;
+ sp<GraphicBuffer> dequeueBuffer(base::unique_fd* bufferFence) override;
void queueBuffer(base::unique_fd&& readyFence) override;
void onPresentDisplayCompleted() override;
void setViewportAndProjection() override;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
index 2972ad7..d0e7b19 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
@@ -61,9 +61,9 @@
MOCK_CONST_METHOD1(getOutputLayerForLayer,
compositionengine::OutputLayer*(compositionengine::Layer*));
- MOCK_METHOD2(getOrCreateOutputLayer,
+ MOCK_METHOD3(getOrCreateOutputLayer,
std::unique_ptr<compositionengine::OutputLayer>(
- std::shared_ptr<compositionengine::Layer>,
+ std::optional<DisplayId>, std::shared_ptr<compositionengine::Layer>,
sp<compositionengine::LayerFE>));
MOCK_METHOD1(setOutputLayersOrderedByZ, void(OutputLayers&&));
MOCK_CONST_METHOD0(getOutputLayersOrderedByZ, OutputLayers&());
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h
index 6bd61ee..54c7407 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h
@@ -16,6 +16,7 @@
#pragma once
+#include <compositionengine/CompositionEngine.h>
#include <compositionengine/Layer.h>
#include <compositionengine/LayerFE.h>
#include <compositionengine/Output.h>
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h
index 8442bef..1562f58 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h
@@ -37,7 +37,7 @@
MOCK_METHOD1(setBufferDataspace, void(ui::Dataspace));
MOCK_METHOD1(beginFrame, status_t(bool mustRecompose));
MOCK_METHOD0(prepareFrame, status_t());
- MOCK_METHOD0(dequeueBuffer, sp<GraphicBuffer>());
+ MOCK_METHOD1(dequeueBuffer, sp<GraphicBuffer>(base::unique_fd*));
MOCK_METHOD1(queueBuffer, void(base::unique_fd&&));
MOCK_METHOD0(onPresentDisplayCompleted, void());
MOCK_METHOD0(setViewportAndProjection, void());
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index f97add4..ad4c7bf 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -217,13 +217,14 @@
}
std::unique_ptr<compositionengine::OutputLayer> Output::getOrCreateOutputLayer(
- std::shared_ptr<compositionengine::Layer> layer, sp<compositionengine::LayerFE> layerFE) {
+ std::optional<DisplayId> displayId, 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);
+ return createOutputLayer(mCompositionEngine, displayId, *this, layer, layerFE);
}
void Output::setOutputLayersOrderedByZ(OutputLayers&& layers) {
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
index 78c1403..10da49d 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
@@ -15,11 +15,14 @@
*/
#include <android-base/stringprintf.h>
+#include <compositionengine/CompositionEngine.h>
#include <compositionengine/Layer.h>
#include <compositionengine/LayerFE.h>
#include <compositionengine/Output.h>
#include <compositionengine/impl/OutputLayer.h>
+#include "DisplayHardware/HWComposer.h"
+
namespace android::compositionengine {
OutputLayer::~OutputLayer() = default;
@@ -27,9 +30,12 @@
namespace impl {
std::unique_ptr<compositionengine::OutputLayer> createOutputLayer(
- const compositionengine::Output& display, std::shared_ptr<compositionengine::Layer> layer,
+ const CompositionEngine& compositionEngine, std::optional<DisplayId> displayId,
+ const compositionengine::Output& output, std::shared_ptr<compositionengine::Layer> layer,
sp<compositionengine::LayerFE> layerFE) {
- return std::make_unique<OutputLayer>(display, layer, layerFE);
+ auto result = std::make_unique<OutputLayer>(output, layer, layerFE);
+ result->initialize(compositionEngine, displayId);
+ return result;
}
OutputLayer::OutputLayer(const Output& output, std::shared_ptr<Layer> layer, sp<LayerFE> layerFE)
@@ -37,6 +43,20 @@
OutputLayer::~OutputLayer() = default;
+void OutputLayer::initialize(const CompositionEngine& compositionEngine,
+ std::optional<DisplayId> displayId) {
+ if (!displayId) {
+ return;
+ }
+
+ auto& hwc = compositionEngine.getHwComposer();
+
+ mState.hwc.emplace(std::shared_ptr<HWC2::Layer>(hwc.createLayer(*displayId),
+ [&hwc, displayId](HWC2::Layer* layer) {
+ hwc.destroyLayer(*displayId, layer);
+ }));
+}
+
const compositionengine::Output& OutputLayer::getOutput() const {
return mOutput;
}
diff --git a/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp b/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp
index ebb1bc2..b4dfba1 100644
--- a/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
#include <android-base/stringprintf.h>
#include <android/native_window.h>
#include <compositionengine/CompositionEngine.h>
@@ -28,6 +30,7 @@
#include <system/window.h>
#include <ui/GraphicBuffer.h>
#include <ui/Rect.h>
+#include <utils/Trace.h>
#include "DisplayHardware/HWComposer.h"
@@ -127,7 +130,8 @@
return mDisplaySurface->prepareFrame(compositionType);
}
-sp<GraphicBuffer> RenderSurface::dequeueBuffer() {
+sp<GraphicBuffer> RenderSurface::dequeueBuffer(base::unique_fd* bufferFence) {
+ ATRACE_CALL();
int fd = -1;
ANativeWindowBuffer* buffer = nullptr;
@@ -145,13 +149,7 @@
mGraphicBuffer->getNativeBuffer()->handle);
mGraphicBuffer = GraphicBuffer::from(buffer);
- // Block until the buffer is ready
- // TODO(alecmouri): it's perhaps more appropriate to block renderengine so
- // that the gl driver can block instead.
- if (fd >= 0) {
- sync_wait(fd, -1);
- close(fd);
- }
+ *bufferFence = base::unique_fd(fd);
return mGraphicBuffer;
}
@@ -172,7 +170,8 @@
// We shouldn't deadlock here, since mGraphicBuffer == nullptr only
// after a successful call to queueBuffer, or if dequeueBuffer has
// never been called.
- dequeueBuffer();
+ base::unique_fd unused;
+ dequeueBuffer(&unused);
}
if (mGraphicBuffer == nullptr) {
diff --git a/services/surfaceflinger/CompositionEngine/tests/MockHWC2.cpp b/services/surfaceflinger/CompositionEngine/tests/MockHWC2.cpp
new file mode 100644
index 0000000..8c10341
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/tests/MockHWC2.cpp
@@ -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.
+ */
+
+#include "MockHWC2.h"
+
+namespace HWC2 {
+
+// This will go away once HWC2::Layer is moved into the "backend" library
+Layer::~Layer() = default;
+
+namespace mock {
+
+// The Google Mock documentation recommends explicit non-header instantiations
+// for better compile time performance.
+Layer::Layer() = default;
+Layer::~Layer() = default;
+
+} // namespace mock
+} // namespace HWC2
diff --git a/services/surfaceflinger/CompositionEngine/tests/MockHWC2.h b/services/surfaceflinger/CompositionEngine/tests/MockHWC2.h
new file mode 100644
index 0000000..7fd6541
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/tests/MockHWC2.h
@@ -0,0 +1,63 @@
+/*
+ * 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 <ui/Fence.h>
+#include <ui/FloatRect.h>
+#include <ui/GraphicBuffer.h>
+#include <ui/GraphicTypes.h>
+#include <ui/Rect.h>
+#include <ui/Region.h>
+#include <ui/Transform.h>
+
+#include "DisplayHardware/HWC2.h"
+
+namespace HWC2 {
+namespace mock {
+
+class Layer : public HWC2::Layer {
+public:
+ Layer();
+ ~Layer() override;
+
+ MOCK_CONST_METHOD0(getId, hwc2_layer_t());
+
+ MOCK_METHOD2(setCursorPosition, Error(int32_t, int32_t));
+ MOCK_METHOD3(setBuffer,
+ Error(uint32_t, const android::sp<android::GraphicBuffer>&,
+ const android::sp<android::Fence>&));
+ MOCK_METHOD1(setSurfaceDamage, Error(const android::Region&));
+ MOCK_METHOD1(setBlendMode, Error(BlendMode));
+ MOCK_METHOD1(setColor, Error(hwc_color_t));
+ MOCK_METHOD1(setCompositionType, Error(Composition));
+ MOCK_METHOD1(setDataspace, Error(android::ui::Dataspace));
+ MOCK_METHOD2(setPerFrameMetadata, Error(const int32_t, const android::HdrMetadata&));
+ MOCK_METHOD1(setDisplayFrame, Error(const android::Rect&));
+ MOCK_METHOD1(setPlaneAlpha, Error(float));
+ MOCK_METHOD1(setSidebandStream, Error(const native_handle_t*));
+ MOCK_METHOD1(setSourceCrop, Error(const android::FloatRect&));
+ MOCK_METHOD1(setTransform, Error(Transform));
+ MOCK_METHOD1(setVisibleRegion, Error(const android::Region&));
+ MOCK_METHOD1(setZOrder, Error(uint32_t));
+ MOCK_METHOD2(setInfo, Error(uint32_t, uint32_t));
+
+ MOCK_METHOD1(setColorTransform, Error(const android::mat4&));
+};
+
+} // namespace mock
+} // namespace HWC2
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
index 0a929ac..f7dcf6f 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
@@ -15,16 +15,22 @@
*/
#include <compositionengine/impl/OutputLayer.h>
+#include <compositionengine/mock/CompositionEngine.h>
#include <compositionengine/mock/Layer.h>
#include <compositionengine/mock/LayerFE.h>
#include <compositionengine/mock/Output.h>
#include <gtest/gtest.h>
+#include "MockHWC2.h"
+#include "MockHWComposer.h"
+
namespace android::compositionengine {
namespace {
using testing::StrictMock;
+constexpr DisplayId DEFAULT_DISPLAY_ID = DisplayId{42};
+
class OutputLayerTest : public testing::Test {
public:
~OutputLayerTest() override = default;
@@ -43,5 +49,37 @@
TEST_F(OutputLayerTest, canInstantiateOutputLayer) {}
+/* ------------------------------------------------------------------------
+ * OutputLayer::initialize()
+ */
+
+TEST_F(OutputLayerTest, initializingOutputLayerWithoutHwcDoesNothingInteresting) {
+ StrictMock<compositionengine::mock::CompositionEngine> compositionEngine;
+
+ mOutputLayer.initialize(compositionEngine, std::nullopt);
+
+ EXPECT_FALSE(mOutputLayer.getState().hwc);
+}
+
+TEST_F(OutputLayerTest, initializingOutputLayerWithHwcDisplayCreatesHwcLayer) {
+ StrictMock<compositionengine::mock::CompositionEngine> compositionEngine;
+ StrictMock<android::mock::HWComposer> hwc;
+ StrictMock<HWC2::mock::Layer> hwcLayer;
+
+ EXPECT_CALL(compositionEngine, getHwComposer()).WillOnce(ReturnRef(hwc));
+ EXPECT_CALL(hwc, createLayer(DEFAULT_DISPLAY_ID)).WillOnce(Return(&hwcLayer));
+
+ mOutputLayer.initialize(compositionEngine, DEFAULT_DISPLAY_ID);
+
+ const auto& state = mOutputLayer.getState();
+ ASSERT_TRUE(state.hwc);
+
+ const auto& hwcState = *state.hwc;
+ EXPECT_EQ(&hwcLayer, hwcState.hwcLayer.get());
+
+ EXPECT_CALL(hwc, destroyLayer(DEFAULT_DISPLAY_ID, &hwcLayer));
+ mOutputLayer.editState().hwc.reset();
+}
+
} // namespace
} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
index cb71821..a84af3a 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
@@ -338,7 +338,7 @@
// 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);
+ auto result = mOutput.getOrCreateOutputLayer(std::nullopt, layer, layerFE);
EXPECT_NE(existingOutputLayer, result.get());
EXPECT_TRUE(result.get() != nullptr);
EXPECT_EQ(layer.get(), &result->getLayer());
@@ -354,7 +354,7 @@
// 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);
+ auto result = mOutput.getOrCreateOutputLayer(std::nullopt, layer, layerFE);
EXPECT_EQ(existingOutputLayer, result.get());
// The corresponding entry in the ordered array should be cleared.
diff --git a/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp b/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp
index 0a7c462..84af9b9 100644
--- a/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp
@@ -358,7 +358,8 @@
.WillOnce(
DoAll(SetArgPointee<0>(buffer.get()), SetArgPointee<1>(-1), Return(NO_ERROR)));
- EXPECT_EQ(buffer.get(), mSurface.dequeueBuffer().get());
+ base::unique_fd fence;
+ EXPECT_EQ(buffer.get(), mSurface.dequeueBuffer(&fence).get());
EXPECT_EQ(buffer.get(), mSurface.mutableGraphicBufferForTest().get());
}
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp
index 68e7876..bca0abc 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp
@@ -308,8 +308,7 @@
return static_cast<Error>(intError);
}
-Error Display::createLayer(Layer** outLayer)
-{
+Error Display::createLayer(HWC2::Layer** outLayer) {
if (!outLayer) {
return Error::BadParameter;
}
@@ -320,15 +319,13 @@
return error;
}
- auto layer = std::make_unique<Layer>(
- mComposer, mCapabilities, mId, layerId);
+ auto layer = std::make_unique<impl::Layer>(mComposer, mCapabilities, mId, layerId);
*outLayer = layer.get();
mLayers.emplace(layerId, std::move(layer));
return Error::None;
}
-Error Display::destroyLayer(Layer* layer)
-{
+Error Display::destroyLayer(HWC2::Layer* layer) {
if (!layer) {
return Error::BadParameter;
}
@@ -388,9 +385,7 @@
return Error::None;
}
-Error Display::getChangedCompositionTypes(
- std::unordered_map<Layer*, Composition>* outTypes)
-{
+Error Display::getChangedCompositionTypes(std::unordered_map<HWC2::Layer*, Composition>* outTypes) {
std::vector<Hwc2::Layer> layerIds;
std::vector<Hwc2::IComposerClient::Composition> types;
auto intError = mComposer.getChangedCompositionTypes(
@@ -492,8 +487,7 @@
}
Error Display::getRequests(HWC2::DisplayRequest* outDisplayRequests,
- std::unordered_map<Layer*, LayerRequest>* outLayerRequests)
-{
+ std::unordered_map<HWC2::Layer*, LayerRequest>* outLayerRequests) {
uint32_t intDisplayRequests;
std::vector<Hwc2::Layer> layerIds;
std::vector<uint32_t> layerRequests;
@@ -574,9 +568,7 @@
return static_cast<Error>(intError);
}
-Error Display::getReleaseFences(
- std::unordered_map<Layer*, sp<Fence>>* outFences) const
-{
+Error Display::getReleaseFences(std::unordered_map<HWC2::Layer*, sp<Fence>>* outFences) const {
std::vector<Hwc2::Layer> layerIds;
std::vector<int> fenceFds;
auto intError = mComposer.getReleaseFences(mId, &layerIds, &fenceFds);
@@ -586,7 +578,7 @@
return error;
}
- std::unordered_map<Layer*, sp<Fence>> releaseFences;
+ std::unordered_map<HWC2::Layer*, sp<Fence>> releaseFences;
releaseFences.reserve(numElements);
for (uint32_t element = 0; element < numElements; ++element) {
auto layer = getLayerById(layerIds[element]);
@@ -787,8 +779,7 @@
// Other Display methods
-Layer* Display::getLayerById(hwc2_layer_t id) const
-{
+HWC2::Layer* Display::getLayerById(hwc2_layer_t id) const {
if (mLayers.count(id) == 0) {
return nullptr;
}
@@ -799,6 +790,10 @@
// Layer methods
+Layer::~Layer() = default;
+
+namespace impl {
+
Layer::Layer(android::Hwc2::Composer& composer, const std::unordered_set<Capability>& capabilities,
hwc2_display_t displayId, hwc2_layer_t layerId)
: mComposer(composer),
@@ -817,15 +812,6 @@
ALOGE_IF(error != Error::None, "destroyLayer(%" PRIu64 ", %" PRIu64 ")"
" failed: %s (%d)", mDisplayId, mId, to_string(error).c_str(),
intError);
- if (mLayerDestroyedListener) {
- mLayerDestroyedListener(this);
- }
-}
-
-void Layer::setLayerDestroyedListener(std::function<void(Layer*)> listener) {
- LOG_ALWAYS_FATAL_IF(mLayerDestroyedListener && listener,
- "Attempt to set layer destroyed listener multiple times");
- mLayerDestroyedListener = listener;
}
Error Layer::setCursorPosition(int32_t x, int32_t y)
@@ -1033,4 +1019,6 @@
auto intError = mComposer.setLayerColorTransform(mDisplayId, mId, matrix.asArray());
return static_cast<Error>(intError);
}
+
+} // namespace impl
} // namespace HWC2
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.h b/services/surfaceflinger/DisplayHardware/HWC2.h
index c1f481a..70358a0 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.h
+++ b/services/surfaceflinger/DisplayHardware/HWC2.h
@@ -364,52 +364,73 @@
};
} // namespace impl
+class Layer {
+public:
+ virtual ~Layer();
+
+ virtual hwc2_layer_t getId() const = 0;
+
+ [[clang::warn_unused_result]] virtual Error setCursorPosition(int32_t x, int32_t y) = 0;
+ [[clang::warn_unused_result]] virtual Error setBuffer(
+ uint32_t slot, const android::sp<android::GraphicBuffer>& buffer,
+ const android::sp<android::Fence>& acquireFence) = 0;
+ [[clang::warn_unused_result]] virtual Error setSurfaceDamage(const android::Region& damage) = 0;
+
+ [[clang::warn_unused_result]] virtual Error setBlendMode(BlendMode mode) = 0;
+ [[clang::warn_unused_result]] virtual Error setColor(hwc_color_t color) = 0;
+ [[clang::warn_unused_result]] virtual Error setCompositionType(Composition type) = 0;
+ [[clang::warn_unused_result]] virtual Error setDataspace(android::ui::Dataspace dataspace) = 0;
+ [[clang::warn_unused_result]] virtual Error setPerFrameMetadata(
+ const int32_t supportedPerFrameMetadata, const android::HdrMetadata& metadata) = 0;
+ [[clang::warn_unused_result]] virtual Error setDisplayFrame(const android::Rect& frame) = 0;
+ [[clang::warn_unused_result]] virtual Error setPlaneAlpha(float alpha) = 0;
+ [[clang::warn_unused_result]] virtual Error setSidebandStream(
+ const native_handle_t* stream) = 0;
+ [[clang::warn_unused_result]] virtual Error setSourceCrop(const android::FloatRect& crop) = 0;
+ [[clang::warn_unused_result]] virtual Error setTransform(Transform transform) = 0;
+ [[clang::warn_unused_result]] virtual Error setVisibleRegion(const android::Region& region) = 0;
+ [[clang::warn_unused_result]] virtual Error setZOrder(uint32_t z) = 0;
+ [[clang::warn_unused_result]] virtual Error setInfo(uint32_t type, uint32_t appId) = 0;
+
+ // Composer HAL 2.3
+ [[clang::warn_unused_result]] virtual Error setColorTransform(const android::mat4& matrix) = 0;
+};
+
+namespace impl {
+
// Convenience C++ class to access hwc2_device_t Layer functions directly.
-class Layer
-{
+
+class Layer : public HWC2::Layer {
public:
Layer(android::Hwc2::Composer& composer,
const std::unordered_set<Capability>& capabilities,
hwc2_display_t displayId, hwc2_layer_t layerId);
- ~Layer();
+ ~Layer() override;
- hwc2_layer_t getId() const { return mId; }
+ hwc2_layer_t getId() const override { return mId; }
- // Register a listener to be notified when the layer is destroyed. When the
- // listener function is called, the Layer will be in the process of being
- // destroyed, so it's not safe to call methods on it.
- void setLayerDestroyedListener(std::function<void(Layer*)> listener);
+ Error setCursorPosition(int32_t x, int32_t y) override;
+ Error setBuffer(uint32_t slot, const android::sp<android::GraphicBuffer>& buffer,
+ const android::sp<android::Fence>& acquireFence) override;
+ Error setSurfaceDamage(const android::Region& damage) override;
- [[clang::warn_unused_result]] Error setCursorPosition(int32_t x, int32_t y);
- [[clang::warn_unused_result]] Error setBuffer(uint32_t slot,
- const android::sp<android::GraphicBuffer>& buffer,
- const android::sp<android::Fence>& acquireFence);
- [[clang::warn_unused_result]] Error setSurfaceDamage(
- const android::Region& damage);
-
- [[clang::warn_unused_result]] Error setBlendMode(BlendMode mode);
- [[clang::warn_unused_result]] Error setColor(hwc_color_t color);
- [[clang::warn_unused_result]] Error setCompositionType(Composition type);
- [[clang::warn_unused_result]] Error setDataspace(
- android::ui::Dataspace dataspace);
- [[clang::warn_unused_result]] Error setPerFrameMetadata(
- const int32_t supportedPerFrameMetadata,
- const android::HdrMetadata& metadata);
- [[clang::warn_unused_result]] Error setDisplayFrame(
- const android::Rect& frame);
- [[clang::warn_unused_result]] Error setPlaneAlpha(float alpha);
- [[clang::warn_unused_result]] Error setSidebandStream(
- const native_handle_t* stream);
- [[clang::warn_unused_result]] Error setSourceCrop(
- const android::FloatRect& crop);
- [[clang::warn_unused_result]] Error setTransform(Transform transform);
- [[clang::warn_unused_result]] Error setVisibleRegion(
- const android::Region& region);
- [[clang::warn_unused_result]] Error setZOrder(uint32_t z);
- [[clang::warn_unused_result]] Error setInfo(uint32_t type, uint32_t appId);
+ Error setBlendMode(BlendMode mode) override;
+ Error setColor(hwc_color_t color) override;
+ Error setCompositionType(Composition type) override;
+ Error setDataspace(android::ui::Dataspace dataspace) override;
+ Error setPerFrameMetadata(const int32_t supportedPerFrameMetadata,
+ const android::HdrMetadata& metadata) override;
+ Error setDisplayFrame(const android::Rect& frame) override;
+ Error setPlaneAlpha(float alpha) override;
+ Error setSidebandStream(const native_handle_t* stream) override;
+ Error setSourceCrop(const android::FloatRect& crop) override;
+ Error setTransform(Transform transform) override;
+ Error setVisibleRegion(const android::Region& region) override;
+ Error setZOrder(uint32_t z) override;
+ Error setInfo(uint32_t type, uint32_t appId) override;
// Composer HAL 2.3
- [[clang::warn_unused_result]] Error setColorTransform(const android::mat4& matrix);
+ Error setColorTransform(const android::mat4& matrix) override;
private:
// These are references to data owned by HWC2::Device, which will outlive
@@ -422,10 +443,11 @@
hwc2_layer_t mId;
android::ui::Dataspace mDataSpace = android::ui::Dataspace::UNKNOWN;
android::HdrMetadata mHdrMetadata;
- std::function<void(Layer*)> mLayerDestroyedListener;
android::mat4 mColorMatrix;
};
+} // namespace impl
+
} // namespace HWC2
#endif // ANDROID_SF_HWC2_H
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 7b8ad71..daef7c6 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -126,8 +126,6 @@
mFrameTracker.logAndResetStats(mName);
- destroyAllHwcLayersPlusChildren();
-
mFlinger->onLayerDestroyed();
}
@@ -209,61 +207,6 @@
// h/w composer set-up
// ---------------------------------------------------------------------------
-bool Layer::createHwcLayer(HWComposer* hwc, const sp<DisplayDevice>& displayDevice) {
- LOG_ALWAYS_FATAL_IF(!displayDevice->getId());
- auto displayId = *displayDevice->getId();
- auto outputLayer = findOutputLayerForDisplay(displayDevice);
- LOG_ALWAYS_FATAL_IF(!outputLayer);
-
- LOG_ALWAYS_FATAL_IF(outputLayer->getState().hwc.has_value(),
- "Already have a layer for display %s",
- displayDevice->getDisplayName().c_str());
-
- auto layer = std::shared_ptr<HWC2::Layer>(
- hwc->createLayer(displayId),
- [hwc, displayId](HWC2::Layer* layer) {
- hwc->destroyLayer(displayId, layer); });
- if (!layer) {
- return false;
- }
- auto& state = outputLayer->editState();
- state.hwc.emplace(layer);
- return true;
-}
-
-bool Layer::destroyHwcLayer(const sp<DisplayDevice>& displayDevice) {
- auto outputLayer = findOutputLayerForDisplay(displayDevice);
- if (outputLayer == nullptr) {
- return false;
- }
- auto& state = outputLayer->editState();
- bool result = state.hwc.has_value();
- state.hwc.reset();
- return result;
-}
-
-bool Layer::destroyHwcLayersForAllDisplays() {
- bool destroyedAnyLayers = false;
-
- for (const auto& [token, displayDevice] : mFlinger->mDisplays) {
- if (destroyHwcLayer(displayDevice)) {
- destroyedAnyLayers = true;
- }
- }
-
- return destroyedAnyLayers;
-}
-
-bool Layer::destroyAllHwcLayersPlusChildren() {
- bool result = destroyHwcLayersForAllDisplays();
-
- for (const sp<Layer>& child : mDrawingChildren) {
- result |= child->destroyAllHwcLayersPlusChildren();
- }
-
- return result;
-}
-
bool Layer::hasHwcLayer(const sp<const DisplayDevice>& displayDevice) {
auto outputLayer = findOutputLayerForDisplay(displayDevice);
LOG_FATAL_IF(!outputLayer);
@@ -2138,11 +2081,15 @@
auto parent = useDrawing ? mDrawingParent.promote() : mCurrentParent.promote();
if (parent != nullptr) {
layerInfo->set_parent(parent->sequence);
+ } else {
+ layerInfo->set_parent(-1);
}
auto zOrderRelativeOf = state.zOrderRelativeOf.promote();
if (zOrderRelativeOf != nullptr) {
layerInfo->set_z_order_relative_of(zOrderRelativeOf->sequence);
+ } else {
+ layerInfo->set_z_order_relative_of(-1);
}
auto buffer = mActiveBuffer;
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 8ae057f..1375a39 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -534,8 +534,7 @@
* operation, so this should be set only if needed). Typically this is used
* to figure out if the content or size of a surface has changed.
*/
- virtual bool latchBuffer(bool& /*recomputeVisibleRegions*/, nsecs_t /*latchTime*/,
- const sp<Fence>& /*releaseFence*/) {
+ virtual bool latchBuffer(bool& /*recomputeVisibleRegions*/, nsecs_t /*latchTime*/) {
return {};
}
@@ -571,11 +570,6 @@
// -----------------------------------------------------------------------
- bool createHwcLayer(HWComposer* hwc, const sp<DisplayDevice>& display);
- bool destroyHwcLayer(const sp<DisplayDevice>& display);
- bool destroyHwcLayersForAllDisplays();
- bool destroyAllHwcLayersPlusChildren();
-
bool hasHwcLayer(const sp<const DisplayDevice>& displayDevice);
HWC2::Layer* getHwcLayer(const sp<const DisplayDevice>& displayDevice);
diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp
new file mode 100644
index 0000000..cbc7ada
--- /dev/null
+++ b/services/surfaceflinger/RegionSamplingThread.cpp
@@ -0,0 +1,252 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+#undef LOG_TAG
+#define LOG_TAG "RegionSamplingThread"
+
+#include "RegionSamplingThread.h"
+
+#include <gui/IRegionSamplingListener.h>
+#include <utils/Trace.h>
+
+#include "DisplayDevice.h"
+#include "Layer.h"
+#include "SurfaceFlinger.h"
+
+namespace android {
+
+template <typename T>
+struct SpHash {
+ size_t operator()(const sp<T>& p) const { return std::hash<T*>()(p.get()); }
+};
+
+RegionSamplingThread::RegionSamplingThread(SurfaceFlinger& flinger) : mFlinger(flinger) {
+ std::lock_guard threadLock(mThreadMutex);
+ mThread = std::thread([this]() { threadMain(); });
+ pthread_setname_np(mThread.native_handle(), "RegionSamplingThread");
+}
+
+RegionSamplingThread::~RegionSamplingThread() {
+ {
+ std::lock_guard lock(mMutex);
+ mRunning = false;
+ mCondition.notify_one();
+ }
+
+ std::lock_guard threadLock(mThreadMutex);
+ if (mThread.joinable()) {
+ mThread.join();
+ }
+}
+
+void RegionSamplingThread::addListener(const Rect& samplingArea, const sp<IBinder>& stopLayerHandle,
+ const sp<IRegionSamplingListener>& listener) {
+ wp<Layer> stopLayer = stopLayerHandle != nullptr
+ ? static_cast<Layer::Handle*>(stopLayerHandle.get())->owner
+ : nullptr;
+
+ sp<IBinder> asBinder = IInterface::asBinder(listener);
+ asBinder->linkToDeath(this);
+ std::lock_guard lock(mMutex);
+ mDescriptors.emplace(wp<IBinder>(asBinder), Descriptor{samplingArea, stopLayer, listener});
+}
+
+void RegionSamplingThread::removeListener(const sp<IRegionSamplingListener>& listener) {
+ std::lock_guard lock(mMutex);
+ mDescriptors.erase(wp<IBinder>(IInterface::asBinder(listener)));
+}
+
+void RegionSamplingThread::sampleNow() {
+ std::lock_guard lock(mMutex);
+ mSampleRequested = true;
+ mCondition.notify_one();
+}
+
+void RegionSamplingThread::binderDied(const wp<IBinder>& who) {
+ std::lock_guard lock(mMutex);
+ mDescriptors.erase(who);
+}
+
+namespace {
+// Using Rec. 709 primaries
+float getLuma(float r, float g, float b) {
+ constexpr auto rec709_red_primary = 0.2126f;
+ constexpr auto rec709_green_primary = 0.7152f;
+ constexpr auto rec709_blue_primary = 0.0722f;
+ return rec709_red_primary * r + rec709_green_primary * g + rec709_blue_primary * b;
+}
+
+float sampleArea(const uint32_t* data, int32_t stride, const Rect& area) {
+ std::array<int32_t, 256> brightnessBuckets = {};
+ const int32_t majoritySampleNum = area.getWidth() * area.getHeight() / 2;
+
+ for (int32_t row = area.top; row < area.bottom; ++row) {
+ const uint32_t* rowBase = data + row * stride;
+ for (int32_t column = area.left; column < area.right; ++column) {
+ uint32_t pixel = rowBase[column];
+ const float r = (pixel & 0xFF) / 255.0f;
+ const float g = ((pixel >> 8) & 0xFF) / 255.0f;
+ const float b = ((pixel >> 16) & 0xFF) / 255.0f;
+ const uint8_t luma = std::round(getLuma(r, g, b) * 255.0f);
+ ++brightnessBuckets[luma];
+ if (brightnessBuckets[luma] > majoritySampleNum) return luma / 255.0f;
+ }
+ }
+
+ int32_t accumulated = 0;
+ size_t bucket = 0;
+ while (bucket++ < brightnessBuckets.size()) {
+ accumulated += brightnessBuckets[bucket];
+ if (accumulated > majoritySampleNum) break;
+ }
+
+ return bucket / 255.0f;
+}
+} // anonymous namespace
+
+std::vector<float> sampleBuffer(const sp<GraphicBuffer>& buffer, const Point& leftTop,
+ const std::vector<RegionSamplingThread::Descriptor>& descriptors) {
+ void* data_raw = nullptr;
+ buffer->lock(GRALLOC_USAGE_SW_READ_OFTEN, &data_raw);
+ std::shared_ptr<uint32_t> data(reinterpret_cast<uint32_t*>(data_raw),
+ [&buffer](auto) { buffer->unlock(); });
+ if (!data) return {};
+
+ const int32_t stride = buffer->getStride();
+ std::vector<float> lumas(descriptors.size());
+ std::transform(descriptors.begin(), descriptors.end(), lumas.begin(),
+ [&](auto const& descriptor) {
+ return sampleArea(data.get(), stride, descriptor.area - leftTop);
+ });
+ return lumas;
+}
+
+void RegionSamplingThread::captureSample() {
+ ATRACE_CALL();
+
+ if (mDescriptors.empty()) {
+ return;
+ }
+
+ std::vector<RegionSamplingThread::Descriptor> descriptors;
+ Region sampleRegion;
+ for (const auto& [listener, descriptor] : mDescriptors) {
+ sampleRegion.orSelf(descriptor.area);
+ descriptors.emplace_back(descriptor);
+ }
+
+ Rect sampledArea = sampleRegion.bounds();
+
+ sp<const DisplayDevice> device = mFlinger.getDefaultDisplayDevice();
+ DisplayRenderArea renderArea(device, sampledArea, sampledArea.getWidth(),
+ sampledArea.getHeight(), ui::Dataspace::V0_SRGB,
+ ui::Transform::ROT_0);
+
+ std::unordered_set<sp<IRegionSamplingListener>, SpHash<IRegionSamplingListener>> listeners;
+
+ auto traverseLayers = [&](const LayerVector::Visitor& visitor) {
+ bool stopLayerFound = false;
+ auto filterVisitor = [&](Layer* layer) {
+ // We don't want to capture any layers beyond the stop layer
+ if (stopLayerFound) return;
+
+ // Likewise if we just found a stop layer, set the flag and abort
+ for (const auto& [area, stopLayer, listener] : descriptors) {
+ if (layer == stopLayer.promote().get()) {
+ stopLayerFound = true;
+ return;
+ }
+ }
+
+ // Compute the layer's position on the screen
+ Rect bounds = Rect(layer->getBounds());
+ ui::Transform transform = layer->getTransform();
+ constexpr bool roundOutwards = true;
+ Rect transformed = transform.transform(bounds, roundOutwards);
+
+ // If this layer doesn't intersect with the larger sampledArea, skip capturing it
+ Rect ignore;
+ if (!transformed.intersect(sampledArea, &ignore)) return;
+
+ // If the layer doesn't intersect a sampling area, skip capturing it
+ bool intersectsAnyArea = false;
+ for (const auto& [area, stopLayer, listener] : descriptors) {
+ if (transformed.intersect(area, &ignore)) {
+ intersectsAnyArea = true;
+ listeners.insert(listener);
+ }
+ }
+ if (!intersectsAnyArea) return;
+
+ ALOGV("Traversing [%s] [%d, %d, %d, %d]", layer->getName().string(), bounds.left,
+ bounds.top, bounds.right, bounds.bottom);
+ visitor(layer);
+ };
+ mFlinger.traverseLayersInDisplay(device, filterVisitor);
+ };
+
+ const uint32_t usage = GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_HW_RENDER;
+ sp<GraphicBuffer> buffer =
+ new GraphicBuffer(sampledArea.getWidth(), sampledArea.getHeight(),
+ PIXEL_FORMAT_RGBA_8888, 1, usage, "RegionSamplingThread");
+
+ // When calling into SF, we post a message into the SF message queue (so the
+ // screen capture runs on the main thread). This message blocks until the
+ // screenshot is actually captured, but before the capture occurs, the main
+ // thread may perform a normal refresh cycle. At the end of this cycle, it
+ // can request another sample (because layers changed), which triggers a
+ // call into sampleNow. When sampleNow attempts to grab the mutex, we can
+ // deadlock.
+ //
+ // To avoid this, we drop the mutex while we call into SF.
+ mMutex.unlock();
+ mFlinger.captureScreenCore(renderArea, traverseLayers, buffer, false);
+ mMutex.lock();
+
+ std::vector<Descriptor> activeDescriptors;
+ for (const auto& descriptor : descriptors) {
+ if (listeners.count(descriptor.listener) != 0) {
+ activeDescriptors.emplace_back(descriptor);
+ }
+ }
+
+ ALOGV("Sampling %zu descriptors", activeDescriptors.size());
+ std::vector<float> lumas = sampleBuffer(buffer, sampledArea.leftTop(), activeDescriptors);
+
+ if (lumas.size() != activeDescriptors.size()) {
+ return;
+ }
+
+ for (size_t d = 0; d < activeDescriptors.size(); ++d) {
+ activeDescriptors[d].listener->onSampleCollected(lumas[d]);
+ }
+}
+
+void RegionSamplingThread::threadMain() {
+ std::lock_guard lock(mMutex);
+ while (mRunning) {
+ if (mSampleRequested) {
+ mSampleRequested = false;
+ captureSample();
+ }
+ mCondition.wait(mMutex,
+ [this]() REQUIRES(mMutex) { return mSampleRequested || !mRunning; });
+ }
+}
+
+} // namespace android
diff --git a/services/surfaceflinger/RegionSamplingThread.h b/services/surfaceflinger/RegionSamplingThread.h
new file mode 100644
index 0000000..bf59007
--- /dev/null
+++ b/services/surfaceflinger/RegionSamplingThread.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <condition_variable>
+#include <mutex>
+#include <thread>
+#include <unordered_map>
+
+#include <android-base/thread_annotations.h>
+#include <binder/IBinder.h>
+#include <ui/Rect.h>
+#include <utils/StrongPointer.h>
+
+namespace android {
+
+class GraphicBuffer;
+class IRegionSamplingListener;
+class Layer;
+class SurfaceFlinger;
+
+class RegionSamplingThread : public IBinder::DeathRecipient {
+public:
+ explicit RegionSamplingThread(SurfaceFlinger& flinger);
+ ~RegionSamplingThread();
+
+ void addListener(const Rect& samplingArea, const sp<IBinder>& stopLayerHandle,
+ const sp<IRegionSamplingListener>& listener);
+ void removeListener(const sp<IRegionSamplingListener>& listener);
+ void sampleNow();
+
+ struct Descriptor {
+ Rect area = Rect::EMPTY_RECT;
+ wp<Layer> stopLayer;
+ sp<IRegionSamplingListener> listener;
+ };
+
+ struct WpHash {
+ size_t operator()(const wp<IBinder>& p) const {
+ return std::hash<IBinder*>()(p.unsafe_get());
+ }
+ };
+
+private:
+ void binderDied(const wp<IBinder>& who) override;
+
+ void captureSample() REQUIRES(mMutex);
+ void threadMain();
+
+ SurfaceFlinger& mFlinger;
+
+ std::mutex mThreadMutex;
+ std::thread mThread GUARDED_BY(mThreadMutex);
+
+ std::mutex mMutex;
+ std::condition_variable_any mCondition;
+ bool mRunning GUARDED_BY(mMutex) = true;
+ bool mSampleRequested GUARDED_BY(mMutex) = false;
+
+ std::unordered_map<wp<IBinder>, Descriptor, WpHash> mDescriptors GUARDED_BY(mMutex);
+};
+
+} // namespace android
diff --git a/services/surfaceflinger/Scheduler/DispSyncSource.cpp b/services/surfaceflinger/Scheduler/DispSyncSource.cpp
index 697d634..d848c97 100644
--- a/services/surfaceflinger/Scheduler/DispSyncSource.cpp
+++ b/services/surfaceflinger/Scheduler/DispSyncSource.cpp
@@ -85,7 +85,19 @@
}
}
+void DispSyncSource::pauseVsyncCallback(bool pause) {
+ std::lock_guard lock(mVsyncMutex);
+ mCallbackPaused = pause;
+}
+
void DispSyncSource::onDispSyncEvent(nsecs_t when) {
+ {
+ std::lock_guard lock(mVsyncMutex);
+ if (mCallbackPaused) {
+ return;
+ }
+ }
+
VSyncSource::Callback* callback;
{
std::lock_guard lock(mCallbackMutex);
diff --git a/services/surfaceflinger/Scheduler/DispSyncSource.h b/services/surfaceflinger/Scheduler/DispSyncSource.h
index 0fd84a2..5e3d181 100644
--- a/services/surfaceflinger/Scheduler/DispSyncSource.h
+++ b/services/surfaceflinger/Scheduler/DispSyncSource.h
@@ -33,6 +33,7 @@
void setVSyncEnabled(bool enable) override;
void setCallback(VSyncSource::Callback* callback) override;
void setPhaseOffset(nsecs_t phaseOffset) override;
+ void pauseVsyncCallback(bool pause) override;
private:
// The following method is the implementation of the DispSync::Callback.
@@ -53,6 +54,7 @@
std::mutex mVsyncMutex;
nsecs_t mPhaseOffset GUARDED_BY(mVsyncMutex);
bool mEnabled GUARDED_BY(mVsyncMutex) = false;
+ bool mCallbackPaused GUARDED_BY(mVsyncMutex) = false;
};
} // namespace android
\ No newline at end of file
diff --git a/services/surfaceflinger/Scheduler/EventThread.cpp b/services/surfaceflinger/Scheduler/EventThread.cpp
index 5d9cfde..4b500f1 100644
--- a/services/surfaceflinger/Scheduler/EventThread.cpp
+++ b/services/surfaceflinger/Scheduler/EventThread.cpp
@@ -203,6 +203,12 @@
mVSyncSource->setPhaseOffset(phaseOffset);
}
+void EventThread::pauseVsyncCallback(bool pause) {
+ std::lock_guard<std::mutex> lock(mMutex);
+ ATRACE_INT("vsyncPaused", pause);
+ mVSyncSource->pauseVsyncCallback(pause);
+}
+
sp<EventThreadConnection> EventThread::createEventConnection(
ResyncCallback resyncCallback, ResetIdleTimerCallback resetIdleTimerCallback) const {
return new EventThreadConnection(const_cast<EventThread*>(this), std::move(resyncCallback),
diff --git a/services/surfaceflinger/Scheduler/EventThread.h b/services/surfaceflinger/Scheduler/EventThread.h
index b275183..3411438 100644
--- a/services/surfaceflinger/Scheduler/EventThread.h
+++ b/services/surfaceflinger/Scheduler/EventThread.h
@@ -66,6 +66,9 @@
virtual void setVSyncEnabled(bool enable) = 0;
virtual void setCallback(Callback* callback) = 0;
virtual void setPhaseOffset(nsecs_t phaseOffset) = 0;
+
+ // pause/resume vsync callback generation
+ virtual void pauseVsyncCallback(bool pause) = 0;
};
class EventThreadConnection : public BnDisplayEventConnection {
@@ -119,6 +122,8 @@
// 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;
+
+ virtual void pauseVsyncCallback(bool pause) = 0;
};
namespace impl {
@@ -152,6 +157,8 @@
void setPhaseOffset(nsecs_t phaseOffset) override;
+ void pauseVsyncCallback(bool pause) override;
+
private:
friend EventThreadTest;
diff --git a/services/surfaceflinger/Scheduler/InjectVSyncSource.h b/services/surfaceflinger/Scheduler/InjectVSyncSource.h
index a0e1447..90609af 100644
--- a/services/surfaceflinger/Scheduler/InjectVSyncSource.h
+++ b/services/surfaceflinger/Scheduler/InjectVSyncSource.h
@@ -44,6 +44,7 @@
void setVSyncEnabled(bool) override {}
void setPhaseOffset(nsecs_t) override {}
+ void pauseVsyncCallback(bool) {}
private:
std::mutex mCallbackMutex;
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index af439f7..4f846db 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -163,6 +163,12 @@
mConnections[handle->id]->thread->setPhaseOffset(phaseOffset);
}
+void Scheduler::pauseVsyncCallback(const android::sp<android::Scheduler::ConnectionHandle>& handle,
+ bool pause) {
+ RETURN_IF_INVALID();
+ mConnections[handle->id]->thread->pauseVsyncCallback(pause);
+}
+
void Scheduler::getDisplayStatInfo(DisplayStatInfo* stats) {
stats->vsyncTime = mPrimaryDispSync->computeNextRefresh(0);
stats->vsyncPeriod = mPrimaryDispSync->getPeriod();
@@ -189,6 +195,49 @@
}
}
+void Scheduler::resyncToHardwareVsync(bool makeAvailable, nsecs_t period) {
+ {
+ std::lock_guard<std::mutex> lock(mHWVsyncLock);
+ if (makeAvailable) {
+ mHWVsyncAvailable = makeAvailable;
+ } else if (!mHWVsyncAvailable) {
+ // Hardware vsync is not currently available, so abort the resync
+ // attempt for now
+ return;
+ }
+ }
+
+ if (period <= 0) {
+ return;
+ }
+
+ setVsyncPeriod(period);
+}
+
+ResyncCallback Scheduler::makeResyncCallback(GetVsyncPeriod&& getVsyncPeriod) {
+ std::weak_ptr<VsyncState> ptr = mPrimaryVsyncState;
+ return [ptr, getVsyncPeriod = std::move(getVsyncPeriod)]() {
+ if (const auto vsync = ptr.lock()) {
+ vsync->resync(getVsyncPeriod);
+ }
+ };
+}
+
+void Scheduler::VsyncState::resync(const GetVsyncPeriod& getVsyncPeriod) {
+ static constexpr nsecs_t kIgnoreDelay = ms2ns(500);
+
+ const nsecs_t now = systemTime();
+ const nsecs_t last = lastResyncTime.exchange(now);
+
+ if (now - last > kIgnoreDelay) {
+ scheduler.resyncToHardwareVsync(false, getVsyncPeriod());
+ }
+}
+
+void Scheduler::setRefreshSkipCount(int count) {
+ mPrimaryDispSync->setRefreshSkipCount(count);
+}
+
void Scheduler::setVsyncPeriod(const nsecs_t period) {
std::lock_guard<std::mutex> lock(mHWVsyncLock);
mPrimaryDispSync->reset();
@@ -229,16 +278,6 @@
mPrimaryDispSync->setIgnorePresentFences(ignore);
}
-void Scheduler::makeHWSyncAvailable(bool makeAvailable) {
- std::lock_guard<std::mutex> lock(mHWVsyncLock);
- mHWVsyncAvailable = makeAvailable;
-}
-
-bool Scheduler::getHWSyncAvailable() {
- std::lock_guard<std::mutex> lock(mHWVsyncLock);
- return mHWVsyncAvailable;
-}
-
nsecs_t Scheduler::expectedPresentTime() {
return mPrimaryDispSync->expectedPresentTime();
}
@@ -260,6 +299,7 @@
}
void Scheduler::incrementFrameCounter() {
+ std::lock_guard<std::mutex> lock(mLayerHistoryLock);
mLayerHistory.incrementCounter();
}
@@ -284,25 +324,28 @@
void Scheduler::determineLayerTimestampStats(const std::string layerName,
const nsecs_t framePresentTime) {
- mLayerHistory.insert(layerName, framePresentTime);
std::vector<int64_t> differencesMs;
-
- // Traverse through the layer history, and determine the differences in present times.
- nsecs_t newestPresentTime = framePresentTime;
std::string differencesText = "";
- for (int i = 1; i < mLayerHistory.getSize(); i++) {
- std::unordered_map<std::string, nsecs_t> layers = mLayerHistory.get(i);
- for (auto layer : layers) {
- if (layer.first != layerName) {
- continue;
+ {
+ std::lock_guard<std::mutex> lock(mLayerHistoryLock);
+ mLayerHistory.insert(layerName, framePresentTime);
+
+ // Traverse through the layer history, and determine the differences in present times.
+ nsecs_t newestPresentTime = framePresentTime;
+ for (int i = 1; i < mLayerHistory.getSize(); i++) {
+ std::unordered_map<std::string, nsecs_t> layers = mLayerHistory.get(i);
+ for (auto layer : layers) {
+ if (layer.first != layerName) {
+ continue;
+ }
+ int64_t differenceMs = (newestPresentTime - layer.second) / 1000000;
+ // Dismiss noise.
+ if (differenceMs > 10 && differenceMs < 60) {
+ differencesMs.push_back(differenceMs);
+ }
+ IF_ALOGV() { differencesText += (std::to_string(differenceMs) + " "); }
+ newestPresentTime = layer.second;
}
- int64_t differenceMs = (newestPresentTime - layer.second) / 1000000;
- // Dismiss noise.
- if (differenceMs > 10 && differenceMs < 60) {
- differencesMs.push_back(differenceMs);
- }
- IF_ALOGV() { differencesText += (std::to_string(differenceMs) + " "); }
- newestPresentTime = layer.second;
}
}
ALOGV("Layer %s timestamp intervals: %s", layerName.c_str(), differencesText.c_str());
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index d628e40..c566922 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -37,6 +37,7 @@
class Scheduler {
public:
using ExpiredIdleTimerCallback = std::function<void()>;
+ using GetVsyncPeriod = std::function<nsecs_t()>;
using ResetIdleTimerCallback = std::function<void()>;
// Enum to indicate whether to start the transaction early, or at vsync time.
@@ -67,6 +68,16 @@
const std::unique_ptr<EventThread> thread;
};
+ // Stores per-display state about VSYNC.
+ struct VsyncState {
+ explicit VsyncState(Scheduler& scheduler) : scheduler(scheduler) {}
+
+ void resync(const GetVsyncPeriod&);
+
+ Scheduler& scheduler;
+ std::atomic<nsecs_t> lastResyncTime = 0;
+ };
+
explicit Scheduler(impl::EventControlThread::SetVSyncEnabledFunction function);
virtual ~Scheduler();
@@ -100,17 +111,20 @@
// Offers ability to modify phase offset in the event thread.
void setPhaseOffset(const sp<ConnectionHandle>& handle, nsecs_t phaseOffset);
+ // pause/resume vsync callback generation to avoid sending vsync callbacks during config switch
+ void pauseVsyncCallback(const sp<ConnectionHandle>& handle, bool pause);
+
void getDisplayStatInfo(DisplayStatInfo* stats);
void enableHardwareVsync();
void disableHardwareVsync(bool makeUnavailable);
- void setVsyncPeriod(const nsecs_t period);
+ void resyncToHardwareVsync(bool makeAvailable, nsecs_t period);
+ // Creates a callback for resyncing.
+ ResyncCallback makeResyncCallback(GetVsyncPeriod&& getVsyncPeriod);
+ void setRefreshSkipCount(int count);
void addResyncSample(const nsecs_t timestamp);
void addPresentFence(const std::shared_ptr<FenceTime>& fenceTime);
void setIgnorePresentFences(bool ignore);
- void makeHWSyncAvailable(bool makeAvailable);
- // returns HWSyncAvailable flag to SF would enable HW vsync based on this
- bool getHWSyncAvailable();
nsecs_t expectedPresentTime();
// Adds the present time for given layer to the history of present times.
void addFramePresentTimeForLayer(const nsecs_t framePresentTime, bool isAutoTimestamp,
@@ -133,6 +147,8 @@
impl::EventThread::InterceptVSyncsCallback interceptCallback);
private:
+ friend class TestableScheduler;
+
// Creates a connection on the given EventThread and forwards the given callbacks.
sp<EventThreadConnection> createConnectionInternal(EventThread*, ResyncCallback&&);
@@ -150,6 +166,8 @@
void resetTimerCallback();
// Function that is called when the timer expires.
void expiredTimerCallback();
+ // Sets vsync period.
+ void setVsyncPeriod(const nsecs_t period);
// If fences from sync Framework are supported.
const bool mHasSyncFramework;
@@ -167,6 +185,7 @@
std::mutex mHWVsyncLock;
bool mPrimaryHWVsyncEnabled GUARDED_BY(mHWVsyncLock);
bool mHWVsyncAvailable GUARDED_BY(mHWVsyncLock);
+ const std::shared_ptr<VsyncState> mPrimaryVsyncState{std::make_shared<VsyncState>(*this)};
std::unique_ptr<DispSync> mPrimaryDispSync;
std::unique_ptr<EventControlThread> mEventControlThread;
@@ -182,7 +201,10 @@
std::array<int64_t, scheduler::ARRAY_SIZE> mTimeDifferences{};
size_t mCounter = 0;
- LayerHistory mLayerHistory;
+ // DetermineLayerTimestampStats is called from BufferQueueLayer::onFrameAvailable which
+ // can run on any thread, and cause failure.
+ std::mutex mLayerHistoryLock;
+ LayerHistory mLayerHistory GUARDED_BY(mLayerHistoryLock);
// Timer that records time between requests for next vsync. If the time is higher than a given
// interval, a callback is fired. Set this variable to >0 to use this feature.
diff --git a/services/surfaceflinger/Scheduler/VSyncModulator.h b/services/surfaceflinger/Scheduler/VSyncModulator.h
index 0bf3ceb..dab2003 100644
--- a/services/surfaceflinger/Scheduler/VSyncModulator.h
+++ b/services/surfaceflinger/Scheduler/VSyncModulator.h
@@ -54,6 +54,15 @@
mEarlyOffsets = early;
mEarlyGlOffsets = earlyGl;
mLateOffsets = late;
+
+ if (mSfConnectionHandle && late.sf != mOffsets.load().sf) {
+ mScheduler->setPhaseOffset(mSfConnectionHandle, late.sf);
+ }
+
+ if (mAppConnectionHandle && late.app != mOffsets.load().app) {
+ mScheduler->setPhaseOffset(mAppConnectionHandle, late.app);
+ }
+
mOffsets = late;
}
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 08ba17a..6d10986 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -292,14 +292,14 @@
mLastTransactionTime(0),
mForceFullDamage(false),
mTimeStats(factory.createTimeStats()),
- mPrimaryHWVsyncEnabled(false),
- mHWVsyncAvailable(false),
mRefreshStartTime(0),
mHasPoweredOff(false),
mNumLayers(0),
mVrFlingerRequestsDisplay(false),
mMainThreadId(std::this_thread::get_id()),
- mCompositionEngine{getFactory().createCompositionEngine()} {}
+ mCompositionEngine{getFactory().createCompositionEngine()} {
+ mSetInputWindowsListener = new SetInputWindowsListener(this);
+}
SurfaceFlinger::SurfaceFlinger(surfaceflinger::Factory& factory)
: SurfaceFlinger(factory, SkipInitialization) {
@@ -395,14 +395,14 @@
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.use_scheduler", value, "0");
- mUseScheduler = atoi(value);
+ property_get("debug.sf.use_90Hz", value, "0");
+ mUse90Hz = atoi(value);
- if (!mUseScheduler) {
- mPrimaryDispSync =
- getFactory().createDispSync("PrimaryDispSync", SurfaceFlinger::hasSyncFramework,
- SurfaceFlinger::dispSyncPresentTimeOffset);
- }
+ property_get("debug.sf.use_smart_90_for_video", value, "0");
+ mUseSmart90ForVideo = atoi(value);
+
+ property_get("debug.sf.luma_sampling", value, "1");
+ mLumaSampling = atoi(value);
const auto [early, gl, late] = mPhaseOffsets->getCurrentOffsets();
mVsyncModulator.setPhaseOffsets(early, gl, late);
@@ -584,9 +584,24 @@
LOG_EVENT_LONG(LOGTAG_SF_STOP_BOOTANIM,
ns2ms(systemTime(SYSTEM_TIME_MONOTONIC)));
- postMessageAsync(new LambdaMessage([this] {
+ postMessageAsync(new LambdaMessage([this]() NO_THREAD_SAFETY_ANALYSIS {
readPersistentProperties();
mBootStage = BootStage::FINISHED;
+
+ // TODO(b/122905403): Once the display policy is completely integrated, this flag should go
+ // away and it should be controlled by flipping the switch in setting. The switch in
+ // settings should only be available to P19 devices, if they are opted into 90Hz fishfood.
+ // The boot must be complete before we can set the active config.
+
+ if (mUse90Hz) {
+ mPhaseOffsets->setRefreshRateType(
+ scheduler::RefreshRateConfigs::RefreshRateType::PERFORMANCE);
+ setRefreshRateTo(RefreshRateType::PERFORMANCE);
+ } else {
+ mPhaseOffsets->setRefreshRateType(
+ scheduler::RefreshRateConfigs::RefreshRateType::DEFAULT);
+ setRefreshRateTo(RefreshRateType::DEFAULT);
+ }
}));
}
@@ -624,53 +639,24 @@
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) { setPrimaryVsyncEnabled(enabled); });
+ mScheduler =
+ getFactory().createScheduler([this](bool enabled) { setPrimaryVsyncEnabled(enabled); });
+ auto resyncCallback =
+ mScheduler->makeResyncCallback(std::bind(&SurfaceFlinger::getVsyncPeriod, this));
- // 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("app", mPhaseOffsets->getCurrentAppOffset(),
+ resyncCallback,
+ impl::EventThread::InterceptVSyncsCallback());
+ mSfConnectionHandle = mScheduler->createConnection("sf", mPhaseOffsets->getCurrentSfOffset(),
+ resyncCallback, [this](nsecs_t timestamp) {
+ mInterceptor->saveVSyncEvent(timestamp);
+ });
- mAppConnectionHandle =
- mScheduler->createConnection("app", mPhaseOffsets->getCurrentAppOffset(),
- resyncCallback,
- impl::EventThread::InterceptVSyncsCallback());
- mSfConnectionHandle =
- mScheduler->createConnection("sf", mPhaseOffsets->getCurrentSfOffset(),
- resyncCallback, [this](nsecs_t timestamp) {
- mInterceptor->saveVSyncEvent(timestamp);
- });
-
- mEventQueue->setEventConnection(mScheduler->getEventConnection(mSfConnectionHandle));
- mVsyncModulator.setSchedulerAndHandles(mScheduler.get(), mAppConnectionHandle.get(),
- mSfConnectionHandle.get());
- } else {
- mEventThreadSource =
- std::make_unique<DispSyncSource>(mPrimaryDispSync.get(),
- mPhaseOffsets->getCurrentAppOffset(), true, "app");
- mEventThread =
- std::make_unique<impl::EventThread>(mEventThreadSource.get(),
- impl::EventThread::InterceptVSyncsCallback(),
- "appEventThread");
- mSfEventThreadSource =
- std::make_unique<DispSyncSource>(mPrimaryDispSync.get(),
- mPhaseOffsets->getCurrentSfOffset(), true, "sf");
-
- mSFEventThread =
- std::make_unique<impl::EventThread>(mSfEventThreadSource.get(),
- [this](nsecs_t timestamp) {
- mInterceptor->saveVSyncEvent(timestamp);
- },
- "sfEventThread");
- mEventQueue->setEventThread(mSFEventThread.get(), std::move(resyncCallback));
- mVsyncModulator.setEventThreads(mSFEventThread.get(), mEventThread.get());
- }
+ mEventQueue->setEventConnection(mScheduler->getEventConnection(mSfConnectionHandle));
+ mVsyncModulator.setSchedulerAndHandles(mScheduler.get(), mAppConnectionHandle.get(),
+ mSfConnectionHandle.get());
// Get a RenderEngine for the given display / config (can't fail)
int32_t renderEngineFeature = 0;
@@ -719,11 +705,6 @@
}
}
- if (!mUseScheduler) {
- mEventControlThread = getFactory().createEventControlThread(
- [this](bool enabled) { setPrimaryVsyncEnabled(enabled); });
- }
-
// initialize our drawing state
mDrawingState = mCurrentState;
@@ -742,7 +723,7 @@
ALOGE("Run StartPropertySetThread failed!");
}
- if (mUseScheduler) {
+ if (mUse90Hz) {
mScheduler->setExpiredIdleTimerCallback([this] {
Mutex::Autolock lock(mStateLock);
setRefreshRateTo(RefreshRateType::DEFAULT);
@@ -751,12 +732,10 @@
Mutex::Autolock lock(mStateLock);
setRefreshRateTo(RefreshRateType::PERFORMANCE);
});
-
- mRefreshRateStats =
- std::make_unique<scheduler::RefreshRateStats>(getHwComposer().getConfigs(
- *display->getId()),
- mTimeStats);
}
+ mRefreshRateStats = std::make_unique<scheduler::RefreshRateStats>(getHwComposer().getConfigs(
+ *display->getId()),
+ mTimeStats);
ALOGV("Done initializing");
}
@@ -945,12 +924,7 @@
return BAD_VALUE;
}
- if (mUseScheduler) {
- mScheduler->getDisplayStatInfo(stats);
- } else {
- stats->vsyncTime = mPrimaryDispSync->computeNextRefresh(0);
- stats->vsyncPeriod = mPrimaryDispSync->getPeriod();
- }
+ mScheduler->getDisplayStatInfo(stats);
return NO_ERROR;
}
@@ -994,12 +968,18 @@
// Don't check against the current mode yet. Worst case we set the desired
// config twice.
- {
- std::lock_guard<std::mutex> lock(mActiveConfigLock);
- mDesiredActiveConfig = ActiveConfigInfo{mode, displayToken};
+ std::lock_guard<std::mutex> lock(mActiveConfigLock);
+ mDesiredActiveConfig = ActiveConfigInfo{mode, displayToken};
+
+ if (!mDesiredActiveConfigChanged) {
+ // This is the first time we set the desired
+ mScheduler->pauseVsyncCallback(mAppConnectionHandle, true);
+
+ // This will trigger HWC refresh without resetting the idle timer.
+ repaintEverythingForHWC();
}
- // This will trigger HWC refresh without resetting the idle timer.
- repaintEverythingForHWC();
+ mDesiredActiveConfigChanged = true;
+ ATRACE_INT("DesiredActiveConfigChanged", mDesiredActiveConfigChanged);
}
status_t SurfaceFlinger::setActiveConfig(const sp<IBinder>& displayToken, int mode) {
@@ -1009,78 +989,78 @@
return NO_ERROR;
}
-void SurfaceFlinger::setActiveConfigInHWC() {
+void SurfaceFlinger::setActiveConfigInternal() {
ATRACE_CALL();
- const auto display = getDisplayDevice(mUpcomingActiveConfig.displayToken);
- if (!display) {
- return;
+ std::lock_guard<std::mutex> lock(mActiveConfigLock);
+ mRefreshRateStats->setConfigMode(mUpcomingActiveConfig.configId);
+
+ const auto display = getDisplayDeviceLocked(mUpcomingActiveConfig.displayToken);
+ display->setActiveConfig(mUpcomingActiveConfig.configId);
+
+ mScheduler->resyncToHardwareVsync(true, getVsyncPeriod());
+ ATRACE_INT("ActiveConfigMode", mUpcomingActiveConfig.configId);
+}
+
+bool SurfaceFlinger::performSetActiveConfig() NO_THREAD_SAFETY_ANALYSIS {
+ ATRACE_CALL();
+ // we may be in the process of changing the active state
+ if (mWaitForNextInvalidate) {
+ mWaitForNextInvalidate = false;
+
+ repaintEverythingForHWC();
+ // We do not want to give another frame to HWC while we are transitioning.
+ return true;
}
+
+ if (mCheckPendingFence) {
+ if (mPreviousPresentFence != Fence::NO_FENCE &&
+ (mPreviousPresentFence->getStatus() == Fence::Status::Unsignaled)) {
+ // fence has not signaled yet. wait for the next invalidate
+ repaintEverythingForHWC();
+ return true;
+ }
+
+ // We received the present fence from the HWC, so we assume it successfully updated
+ // the config, hence we update SF.
+ mCheckPendingFence = false;
+ setActiveConfigInternal();
+ }
+
+ // Store the local variable to release the lock.
+ ActiveConfigInfo desiredActiveConfig;
+ {
+ std::lock_guard<std::mutex> lock(mActiveConfigLock);
+ if (!mDesiredActiveConfigChanged) {
+ return false;
+ }
+ desiredActiveConfig = mDesiredActiveConfig;
+ }
+
+ const auto display = getDisplayDevice(desiredActiveConfig.displayToken);
+ if (!display || display->getActiveConfig() == desiredActiveConfig.configId) {
+ // display is not valid or we are already in the requested mode
+ // on both cases there is nothing left to do
+ std::lock_guard<std::mutex> lock(mActiveConfigLock);
+ mScheduler->pauseVsyncCallback(mAppConnectionHandle, false);
+ mDesiredActiveConfigChanged = false;
+ ATRACE_INT("DesiredActiveConfigChanged", mDesiredActiveConfigChanged);
+ return false;
+ }
+
+ // Desired active config was set, it is different than the config currently in use. Notify HWC.
+ mUpcomingActiveConfig = desiredActiveConfig;
const auto displayId = display->getId();
LOG_ALWAYS_FATAL_IF(!displayId);
ATRACE_INT("ActiveConfigModeHWC", mUpcomingActiveConfig.configId);
getHwComposer().setActiveConfig(*displayId, mUpcomingActiveConfig.configId);
- mSetActiveConfigState = SetActiveConfigState::NOTIFIED_HWC;
- ATRACE_INT("SetActiveConfigState", mSetActiveConfigState);
-}
-void SurfaceFlinger::setActiveConfigInternal() {
- ATRACE_CALL();
+ // we need to submit an empty frame to HWC to start the process
+ mWaitForNextInvalidate = true;
+ mCheckPendingFence = true;
- std::lock_guard<std::mutex> lock(mActiveConfigLock);
- if (mUseScheduler) {
- mRefreshRateStats->setConfigMode(mUpcomingActiveConfig.configId);
- }
-
- const auto display = getDisplayDeviceLocked(mUpcomingActiveConfig.displayToken);
- display->setActiveConfig(mUpcomingActiveConfig.configId);
-
- mSetActiveConfigState = SetActiveConfigState::NONE;
- ATRACE_INT("SetActiveConfigState", mSetActiveConfigState);
-
- resyncToHardwareVsync(true, getVsyncPeriod());
- ATRACE_INT("ActiveConfigMode", mUpcomingActiveConfig.configId);
-}
-
-bool SurfaceFlinger::updateSetActiveConfigStateMachine() NO_THREAD_SAFETY_ANALYSIS {
- // Store the local variable to release the lock.
- ActiveConfigInfo desiredActiveConfig;
- {
- std::lock_guard<std::mutex> lock(mActiveConfigLock);
- desiredActiveConfig = mDesiredActiveConfig;
- }
-
- const auto display = getDisplayDevice(desiredActiveConfig.displayToken);
- if (display) {
- if (mSetActiveConfigState == SetActiveConfigState::NONE &&
- display->getActiveConfig() != desiredActiveConfig.configId) {
- // Step 1) Desired active config was set, it is different than the
- // config currently in use. Notify HWC.
- mUpcomingActiveConfig = desiredActiveConfig;
- setActiveConfigInHWC();
- } else if (mSetActiveConfigState == SetActiveConfigState::NOTIFIED_HWC) {
- // Step 2) HWC was notified and we received refresh from it.
- mSetActiveConfigState = SetActiveConfigState::REFRESH_RECEIVED;
- ATRACE_INT("SetActiveConfigState", mSetActiveConfigState);
- repaintEverythingForHWC();
- // We do not want to give another frame to HWC while we are transitioning.
- return false;
- } else if (mSetActiveConfigState == SetActiveConfigState::REFRESH_RECEIVED &&
- !(mPreviousPresentFence != Fence::NO_FENCE &&
- (mPreviousPresentFence->getStatus() == Fence::Status::Unsignaled))) {
- // Step 3) We received the present fence from the HWC, so we assume it
- // successfully updated the config, hence we update SF.
- setActiveConfigInternal();
- // If the config changed again while we were transitioning, restart the
- // process.
- if (desiredActiveConfig != mUpcomingActiveConfig) {
- mUpcomingActiveConfig = desiredActiveConfig;
- setActiveConfigInHWC(); // sets the state to NOTIFY_HWC
- }
- }
- }
- return true;
+ return false;
}
status_t SurfaceFlinger::getDisplayColorModes(const sp<IBinder>& displayToken,
@@ -1260,7 +1240,8 @@
return;
}
- auto resyncCallback = makeResyncCallback(std::bind(&SurfaceFlinger::getVsyncPeriod, this));
+ auto resyncCallback =
+ mScheduler->makeResyncCallback(std::bind(&SurfaceFlinger::getVsyncPeriod, this));
// TODO(akrulec): Part of the Injector should be refactored, so that it
// can be passed to Scheduler.
@@ -1276,7 +1257,8 @@
mEventQueue->setEventThread(mInjectorEventThread.get(), std::move(resyncCallback));
} else {
ALOGV("VSync Injections disabled");
- mEventQueue->setEventThread(mSFEventThread.get(), std::move(resyncCallback));
+ mEventQueue->setEventThread(mScheduler->getEventThread(mSfConnectionHandle),
+ std::move(resyncCallback));
}
mInjectVSyncs = enable;
@@ -1329,38 +1311,33 @@
return NO_ERROR;
}
-status_t SurfaceFlinger::addRegionSamplingListener(
- const Rect& /*samplingArea*/, const sp<IBinder>& /*stopLayerHandle*/,
- const sp<IRegionSamplingListener>& /*listener*/) {
+status_t SurfaceFlinger::addRegionSamplingListener(const Rect& samplingArea,
+ const sp<IBinder>& stopLayerHandle,
+ const sp<IRegionSamplingListener>& listener) {
+ if (!listener) {
+ return BAD_VALUE;
+ }
+ mRegionSamplingThread->addListener(samplingArea, stopLayerHandle, listener);
return NO_ERROR;
}
-status_t SurfaceFlinger::removeRegionSamplingListener(
- const sp<IRegionSamplingListener>& /*listener*/) {
+status_t SurfaceFlinger::removeRegionSamplingListener(const sp<IRegionSamplingListener>& listener) {
+ mRegionSamplingThread->removeListener(listener);
return NO_ERROR;
}
-
// ----------------------------------------------------------------------------
sp<IDisplayEventConnection> SurfaceFlinger::createDisplayEventConnection(
ISurfaceComposer::VsyncSource vsyncSource) {
- auto resyncCallback = makeResyncCallback([this] {
+ auto resyncCallback = mScheduler->makeResyncCallback([this] {
Mutex::Autolock lock(mStateLock);
return getVsyncPeriod();
});
- if (mUseScheduler) {
- const auto& handle = vsyncSource == eVsyncSourceSurfaceFlinger ? mSfConnectionHandle
- : mAppConnectionHandle;
+ const auto& handle =
+ vsyncSource == eVsyncSourceSurfaceFlinger ? mSfConnectionHandle : mAppConnectionHandle;
- return mScheduler->createDisplayEventConnection(handle, std::move(resyncCallback));
- } else {
- if (vsyncSource == eVsyncSourceSurfaceFlinger) {
- return mSFEventThread->createEventConnection(resyncCallback, ResetIdleTimerCallback());
- } else {
- return mEventThread->createEventConnection(resyncCallback, ResetIdleTimerCallback());
- }
- }
+ return mScheduler->createDisplayEventConnection(handle, std::move(resyncCallback));
}
// ----------------------------------------------------------------------------
@@ -1412,79 +1389,6 @@
return config ? config->getVsyncPeriod() : 0;
}
-void SurfaceFlinger::enableHardwareVsync() {
- assert(!mUseScheduler);
- Mutex::Autolock _l(mHWVsyncLock);
- if (!mPrimaryHWVsyncEnabled && mHWVsyncAvailable) {
- mPrimaryDispSync->beginResync();
- mEventControlThread->setVsyncEnabled(true);
- mPrimaryHWVsyncEnabled = true;
- }
-}
-
-void SurfaceFlinger::resyncToHardwareVsync(bool makeAvailable, nsecs_t period) {
- Mutex::Autolock _l(mHWVsyncLock);
- // TODO(b/113612090): This is silly, but necessary evil until we turn on the flag for good.
- if (mUseScheduler) {
- if (makeAvailable) {
- mScheduler->makeHWSyncAvailable(true);
- } else if (!mScheduler->getHWSyncAvailable()) {
- // Hardware vsync is not currently available, so abort the resync
- // attempt for now
- return;
- }
- } else {
- if (makeAvailable) {
- mHWVsyncAvailable = true;
- } else if (!mHWVsyncAvailable) {
- // Hardware vsync is not currently available, so abort the resync
- // attempt for now
- return;
- }
- }
-
- if (period <= 0) {
- return;
- }
-
- if (mUseScheduler) {
- mScheduler->setVsyncPeriod(period);
- } else {
- mPrimaryDispSync->reset();
- mPrimaryDispSync->setPeriod(period);
-
- if (!mPrimaryHWVsyncEnabled) {
- mPrimaryDispSync->beginResync();
- mEventControlThread->setVsyncEnabled(true);
- mPrimaryHWVsyncEnabled = true;
- }
- }
-}
-
-void SurfaceFlinger::disableHardwareVsync(bool makeUnavailable) {
- assert(!mUseScheduler);
- Mutex::Autolock _l(mHWVsyncLock);
- if (mPrimaryHWVsyncEnabled) {
- mEventControlThread->setVsyncEnabled(false);
- mPrimaryDispSync->endResync();
- mPrimaryHWVsyncEnabled = false;
- }
- if (makeUnavailable) {
- mHWVsyncAvailable = false;
- }
-}
-
-void SurfaceFlinger::VsyncState::resync(const GetVsyncPeriod& getVsyncPeriod) {
- static constexpr nsecs_t kIgnoreDelay = ms2ns(500);
-
- const nsecs_t now = systemTime();
- const nsecs_t last = lastResyncTime.exchange(now);
-
- if (now - last > kIgnoreDelay) {
- flinger.resyncToHardwareVsync(false, getVsyncPeriod());
- }
-}
-
void SurfaceFlinger::onVsyncReceived(int32_t sequenceId, hwc2_display_t hwcDisplayId,
int64_t timestamp) {
ATRACE_NAME("SF onVsync");
@@ -1504,23 +1408,7 @@
return;
}
- if (mUseScheduler) {
- mScheduler->addResyncSample(timestamp);
- } else {
- bool needsHwVsync = false;
- { // Scope for the lock
- Mutex::Autolock _l(mHWVsyncLock);
- if (mPrimaryHWVsyncEnabled) {
- needsHwVsync = mPrimaryDispSync->addResyncSample(timestamp);
- }
- }
-
- if (needsHwVsync) {
- enableHardwareVsync();
- } else {
- disableHardwareVsync(false);
- }
- }
+ mScheduler->addResyncSample(timestamp);
}
void SurfaceFlinger::getCompositorTiming(CompositorTiming* compositorTiming) {
@@ -1621,11 +1509,7 @@
// Note: it is assumed the caller holds |mStateLock| when this is called
void SurfaceFlinger::resetDisplayState() {
- if (mUseScheduler) {
- mScheduler->disableHardwareVsync(true);
- } else {
- disableHardwareVsync(true);
- }
+ mScheduler->disableHardwareVsync(true);
// Clear the drawing state so that the logic inside of
// handleTransactionLocked will fire. It will determine the delta between
// mCurrentState and mDrawingState and re-apply all changes when we make the
@@ -1635,6 +1519,7 @@
}
void SurfaceFlinger::updateVrFlinger() {
+ ATRACE_CALL();
if (!mVrFlinger)
return;
bool vrFlingerRequestsDisplay = mVrFlingerRequestsDisplay;
@@ -1654,7 +1539,18 @@
sp<DisplayDevice> display = getDefaultDisplayDeviceLocked();
LOG_ALWAYS_FATAL_IF(!display);
+
const int currentDisplayPowerMode = display->getPowerMode();
+
+ // Clear out all the output layers from the composition engine for all
+ // displays before destroying the hardware composer interface. This ensures
+ // any HWC layers are destroyed through that interface before it becomes
+ // invalid.
+ for (const auto& [token, displayDevice] : mDisplays) {
+ displayDevice->getCompositionDisplay()->setOutputLayersOrderedByZ(
+ compositionengine::Output::OutputLayers());
+ }
+
// This DisplayDevice will no longer be relevant once resetDisplayState() is
// called below. Clear the reference now so we don't accidentally use it
// later.
@@ -1692,20 +1588,14 @@
// The present fences returned from vr_hwc are not an accurate
// representation of vsync times.
- if (mUseScheduler) {
- mScheduler->setIgnorePresentFences(getHwComposer().isUsingVrComposer() ||
- !hasSyncFramework);
- } else {
- mPrimaryDispSync->setIgnorePresentFences(getHwComposer().isUsingVrComposer() ||
- !hasSyncFramework);
- }
+ mScheduler->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 */, vsyncPeriod};
setCompositorTimingSnapped(stats, 0);
- resyncToHardwareVsync(false, vsyncPeriod);
+ mScheduler->resyncToHardwareVsync(false, vsyncPeriod);
mRepaintEverything = true;
setTransactionFlags(eDisplayTransactionNeeded);
@@ -1715,20 +1605,25 @@
ATRACE_CALL();
switch (what) {
case MessageQueue::INVALIDATE: {
- if (!updateSetActiveConfigStateMachine()) {
+ if (performSetActiveConfig()) {
break;
}
- if (mUseScheduler) {
- // This call is made each time SF wakes up and creates a new frame.
+ if (mUse90Hz && mUseSmart90ForVideo) {
+ // This call is made each time SF wakes up and creates a new frame. It is part
+ // of video detection feature.
mScheduler->incrementFrameCounter();
}
- bool frameMissed = !mHadClientComposition && mPreviousPresentFence != Fence::NO_FENCE &&
+ bool frameMissed = mPreviousPresentFence != Fence::NO_FENCE &&
(mPreviousPresentFence->getStatus() == Fence::Status::Unsignaled);
- mFrameMissedCount += frameMissed;
- ATRACE_INT("FrameMissed", static_cast<int>(frameMissed));
+ bool hwcFrameMissed = !mHadClientComposition && frameMissed;
if (frameMissed) {
+ ATRACE_INT("FrameMissed", static_cast<int>(frameMissed));
+ mFrameMissedCount++;
mTimeStats->incrementMissedFrames();
+ }
+ // For now, only propagate backpressure when missing a hwc frame.
+ if (hwcFrameMissed) {
if (mPropagateBackpressure) {
signalLayerUpdate();
break;
@@ -1763,6 +1658,7 @@
}
bool SurfaceFlinger::handleMessageTransaction() {
+ ATRACE_CALL();
uint32_t transactionFlags = peekTransactionFlags();
// Apply any ready transactions in the queues if there are still transactions that have not been
@@ -1813,18 +1709,6 @@
mHadClientComposition || getHwComposer().hasClientComposition(displayId);
}
- // Setup RenderEngine sync fences if native sync is supported.
- if (getRenderEngine().useNativeFenceSync()) {
- if (mHadClientComposition) {
- base::unique_fd flushFence(getRenderEngine().flush());
- ALOGE_IF(flushFence < 0, "Failed to flush RenderEngine!");
- getBE().flushFence = new Fence(std::move(flushFence));
- } else {
- // Cleanup for hygiene.
- getBE().flushFence = Fence::NO_FENCE;
- }
- }
-
mVsyncModulator.onRefreshed(mHadClientComposition);
getBE().mEndOfFrameCompositionInfo = std::move(getBE().mCompositionInfo);
@@ -1869,10 +1753,8 @@
const auto& layer = currentLayers[i];
if (!layer->hasHwcLayer(displayDevice)) {
- if (!layer->createHwcLayer(&getHwComposer(), displayDevice)) {
- layer->forceClientComposition(displayDevice);
- continue;
- }
+ layer->forceClientComposition(displayDevice);
+ continue;
}
layer->setGeometry(displayDevice, i);
@@ -2173,12 +2055,7 @@
DisplayStatInfo stats;
DEFINE_STACK_GUARD(stats);
- if (mUseScheduler) {
- mScheduler->getDisplayStatInfo(&stats);
- } else {
- stats.vsyncTime = mPrimaryDispSync->computeNextRefresh(0);
- stats.vsyncPeriod = mPrimaryDispSync->getPeriod();
- }
+ mScheduler->getDisplayStatInfo(&stats);
ASSERT_ON_STACK_GUARD();
@@ -2211,27 +2088,14 @@
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();
- }
+ mScheduler->addPresentFence(presentFenceTime);
+ ASSERT_ON_STACK_GUARD();
}
if (!hasSyncFramework) {
if (displayDevice && getHwComposer().isConnected(*displayDevice->getId()) &&
displayDevice->isPoweredOn()) {
- if (mUseScheduler) {
- mScheduler->enableHardwareVsync();
- } else {
- enableHardwareVsync();
- }
+ mScheduler->enableHardwareVsync();
}
}
@@ -2314,6 +2178,10 @@
mTransactionCompletedThread.addPresentFence(mPreviousPresentFence);
mTransactionCompletedThread.sendCallbacks();
+ if (mLumaSampling) {
+ mRegionSamplingThread->sampleNow();
+ }
+
ASSERT_ON_STACK_GUARD();
}
#pragma clang optimize on // b/119477596
@@ -2374,42 +2242,42 @@
return;
}
- bool hwcLayerDestroyed = false;
const auto displayId = displayDevice->getId();
sp<compositionengine::LayerFE> layerFE = compositionLayer->getLayerFE();
LOG_ALWAYS_FATAL_IF(layerFE.get() == nullptr);
+ bool needsOutputLayer = false;
+
if (display->belongsInOutput(layer->getLayerStack(),
layer->getPrimaryDisplayOnly())) {
Region drawRegion(tr.transform(
layer->visibleNonTransparentRegion));
drawRegion.andSelf(bounds);
if (!drawRegion.isEmpty()) {
- 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
- hwcLayerDestroyed = displayId && layer->destroyHwcLayer(displayDevice);
+ needsOutputLayer = true;
}
- } else {
- // WM changes display->layerStack upon sleep/awake.
- // Here we make sure we delete the HWC layers even if
- // WM changed their layer stack.
- hwcLayerDestroyed = displayId && layer->destroyHwcLayer(displayDevice);
}
- // If a layer is not going to get a release fence because
- // it is invisible, but it is also going to release its
- // old buffer, add it to the list of layers needing
- // fences.
- if (hwcLayerDestroyed) {
- auto found = std::find(mLayersWithQueuedFrames.cbegin(),
- mLayersWithQueuedFrames.cend(), layer);
- if (found != mLayersWithQueuedFrames.cend()) {
+ if (needsOutputLayer) {
+ layersSortedByZ.emplace_back(
+ display->getOrCreateOutputLayer(displayId, compositionLayer,
+ layerFE));
+ deprecated_layersSortedByZ.add(layer);
+
+ auto& outputLayerState = layersSortedByZ.back()->editState();
+ outputLayerState.visibleRegion =
+ tr.transform(layer->visibleRegion.intersect(displayState.viewport));
+ } else if (displayId) {
+ // For layers that are being removed from a HWC display,
+ // and that have queued frames, add them to a a list of
+ // released layers so we can properly set a fence.
+ bool hasExistingOutputLayer =
+ display->getOutputLayerForLayer(compositionLayer.get()) != nullptr;
+ bool hasQueuedFrames = std::find(mLayersWithQueuedFrames.cbegin(),
+ mLayersWithQueuedFrames.cend(),
+ layer) != mLayersWithQueuedFrames.cend();
+
+ if (hasExistingOutputLayer && hasQueuedFrames) {
layersNeedingFences.add(layer);
}
}
@@ -2734,13 +2602,8 @@
}
void SurfaceFlinger::dispatchDisplayHotplugEvent(PhysicalDisplayId displayId, bool connected) {
- if (mUseScheduler) {
- mScheduler->hotplugReceived(mAppConnectionHandle, displayId, connected);
- mScheduler->hotplugReceived(mSfConnectionHandle, displayId, connected);
- } else {
- mEventThread->onHotplugReceived(displayId, connected);
- mSFEventThread->onHotplugReceived(displayId, connected);
- }
+ mScheduler->hotplugReceived(mAppConnectionHandle, displayId, connected);
+ mScheduler->hotplugReceived(mSfConnectionHandle, displayId, connected);
}
sp<DisplayDevice> SurfaceFlinger::setupNewDisplayDeviceInternal(
@@ -3105,6 +2968,10 @@
if (mVisibleRegionsDirty || mInputInfoChanged) {
mInputInfoChanged = false;
updateInputWindowInfo();
+ } else if (mInputWindowCommands.syncInputWindows) {
+ // If the caller requested to sync input windows, but there are no
+ // changes to input windows, notify immediately.
+ setInputWindowsFinished();
}
executeInputWindowCommands();
@@ -3120,7 +2987,10 @@
inputHandles.add(layer->fillInputInfo());
}
});
- mInputFlinger->setInputWindows(inputHandles);
+
+ mInputFlinger->setInputWindows(inputHandles,
+ mInputWindowCommands.syncInputWindows ? mSetInputWindowsListener
+ : nullptr);
}
void SurfaceFlinger::commitInputWindowCommands() {
@@ -3157,7 +3027,7 @@
void SurfaceFlinger::latchAndReleaseBuffer(const sp<Layer>& layer) {
if (layer->hasReadyFrame()) {
bool ignored = false;
- layer->latchBuffer(ignored, systemTime(), Fence::NO_FENCE);
+ layer->latchBuffer(ignored, systemTime());
}
layer->releasePendingBuffer(systemTime());
}
@@ -3170,12 +3040,8 @@
recordBufferingStats(l->getName().string(),
l->getOccupancyHistory(true));
- // We need to release the HWC layers when the Layer is removed
- // from the current state otherwise the HWC layer just continues
- // showing at its last configured state until we eventually
- // abandon the buffer queue.
+ // Ensure any buffers set to display on any children are released.
if (l->isRemovedFromCurrentState()) {
- l->destroyHwcLayersForAllDisplays();
latchAndReleaseBuffer(l);
}
}
@@ -3386,11 +3252,7 @@
if (layer->hasReadyFrame()) {
frameQueued = true;
nsecs_t expectedPresentTime;
- if (mUseScheduler) {
- expectedPresentTime = mScheduler->expectedPresentTime();
- } else {
- expectedPresentTime = mPrimaryDispSync->expectedPresentTime();
- }
+ expectedPresentTime = mScheduler->expectedPresentTime();
if (layer->shouldPresentNow(expectedPresentTime)) {
mLayersWithQueuedFrames.push_back(layer);
} else {
@@ -3407,7 +3269,7 @@
Mutex::Autolock lock(mStateLock);
for (auto& layer : mLayersWithQueuedFrames) {
- if (layer->latchBuffer(visibleRegions, latchTime, getBE().flushFence)) {
+ if (layer->latchBuffer(visibleRegions, latchTime)) {
mLayersPendingRefresh.push_back(layer);
}
layer->useSurfaceDamage();
@@ -3417,11 +3279,6 @@
}
}
- // Clear the renderengine fence here...
- // downstream code assumes that a cleared fence == NO_FENCE, so reassign to
- // clear instead of sp::clear.
- getBE().flushFence = Fence::NO_FENCE;
-
mVisibleRegionsDirty |= visibleRegions;
// If we will need to wake up at some time in the future to deal with a
@@ -3486,12 +3343,12 @@
renderengine::DisplaySettings clientCompositionDisplay;
std::vector<renderengine::LayerSettings> clientCompositionLayers;
sp<GraphicBuffer> buf;
+ base::unique_fd fd;
if (hasClientComposition) {
ALOGV("hasClientComposition");
- buf = display->getRenderSurface()->dequeueBuffer();
-
+ buf = display->getRenderSurface()->dequeueBuffer(&fd);
if (buf == nullptr) {
ALOGW("Dequeuing buffer for display [%s] failed, bailing out of "
"client composition for this frame",
@@ -3512,7 +3369,6 @@
m[3][0] = displayTransform[2][0];
m[3][1] = displayTransform[2][1];
m[3][3] = displayTransform[2][2];
-
clientCompositionDisplay.globalTransform = m;
const auto* profile = display->getDisplayColorProfile();
@@ -3612,7 +3468,7 @@
}
}
getRenderEngine().drawLayers(clientCompositionDisplay, clientCompositionLayers,
- buf->getNativeBuffer(), readyFence);
+ buf->getNativeBuffer(), std::move(fd), readyFence);
}
return true;
}
@@ -3732,12 +3588,7 @@
bool SurfaceFlinger::transactionIsReadyToBeApplied(int64_t desiredPresentTime,
const Vector<ComposerState>& states) {
- nsecs_t expectedPresentTime;
- if (mUseScheduler) {
- expectedPresentTime = mScheduler->expectedPresentTime();
- } else {
- expectedPresentTime = mPrimaryDispSync->expectedPresentTime();
- }
+ nsecs_t expectedPresentTime = mScheduler->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 &&
@@ -3849,13 +3700,16 @@
if (flags & eAnimation) {
mAnimTransactionPending = true;
}
- while (mTransactionPending) {
+
+ mPendingSyncInputWindows = mPendingInputWindowCommands.syncInputWindows;
+ while (mTransactionPending || mPendingSyncInputWindows) {
status_t err = mTransactionCV.waitRelative(mStateLock, s2ns(5));
if (CC_UNLIKELY(err != NO_ERROR)) {
// just in case something goes wrong in SF, return to the
// called after a few seconds.
ALOGW_IF(err == TIMED_OUT, "setTransactionState timed out!");
mTransactionPending = false;
+ mPendingSyncInputWindows = false;
break;
}
}
@@ -4173,6 +4027,10 @@
flags |= eTraversalNeeded;
}
+ if (inputWindowCommands.syncInputWindows) {
+ flags |= eTraversalNeeded;
+ }
+
mPendingInputWindowCommands.merge(inputWindowCommands);
return flags;
}
@@ -4434,12 +4292,8 @@
// Turn on the display
getHwComposer().setPowerMode(*displayId, mode);
if (display->isPrimary() && mode != HWC_POWER_MODE_DOZE_SUSPEND) {
- if (mUseScheduler) {
- mScheduler->onScreenAcquired(mAppConnectionHandle);
- } else {
- mEventThread->onScreenAcquired();
- }
- resyncToHardwareVsync(true, getVsyncPeriod());
+ mScheduler->onScreenAcquired(mAppConnectionHandle);
+ mScheduler->resyncToHardwareVsync(true, getVsyncPeriod());
}
mVisibleRegionsDirty = true;
@@ -4459,16 +4313,8 @@
}
if (display->isPrimary() && currentMode != HWC_POWER_MODE_DOZE_SUSPEND) {
- if (mUseScheduler) {
- mScheduler->disableHardwareVsync(true);
- } else {
- disableHardwareVsync(true); // also cancels any in-progress resync
- }
- if (mUseScheduler) {
- mScheduler->onScreenReleased(mAppConnectionHandle);
- } else {
- mEventThread->onScreenReleased();
- }
+ mScheduler->disableHardwareVsync(true);
+ mScheduler->onScreenReleased(mAppConnectionHandle);
}
getHwComposer().setPowerMode(*displayId, mode);
@@ -4479,26 +4325,14 @@
// Update display while dozing
getHwComposer().setPowerMode(*displayId, mode);
if (display->isPrimary() && currentMode == HWC_POWER_MODE_DOZE_SUSPEND) {
- if (mUseScheduler) {
- mScheduler->onScreenAcquired(mAppConnectionHandle);
- } else {
- mEventThread->onScreenAcquired();
- }
- resyncToHardwareVsync(true, getVsyncPeriod());
+ mScheduler->onScreenAcquired(mAppConnectionHandle);
+ mScheduler->resyncToHardwareVsync(true, getVsyncPeriod());
}
} else if (mode == HWC_POWER_MODE_DOZE_SUSPEND) {
// Leave display going to doze
if (display->isPrimary()) {
- if (mUseScheduler) {
- mScheduler->disableHardwareVsync(true);
- } else {
- disableHardwareVsync(true); // also cancels any in-progress resync
- }
- if (mUseScheduler) {
- mScheduler->onScreenReleased(mAppConnectionHandle);
- } else {
- mEventThread->onScreenReleased();
- }
+ mScheduler->disableHardwareVsync(true);
+ mScheduler->onScreenReleased(mAppConnectionHandle);
}
getHwComposer().setPowerMode(*displayId, mode);
} else {
@@ -4508,7 +4342,7 @@
if (display->isPrimary()) {
mTimeStats->setPowerMode(mode);
- if (mUseScheduler && mRefreshRateStats) {
+ if (mRefreshRateStats) {
// Update refresh rate stats.
mRefreshRateStats->setPowerMode(mode);
}
@@ -4565,11 +4399,7 @@
{"--disable-layer-stats"s, dumper([this](std::string&) { mLayerStats.disable(); })},
{"--display-id"s, dumper(&SurfaceFlinger::dumpDisplayIdentificationData)},
{"--dispsync"s, dumper([this](std::string& s) {
- if (mUseScheduler) {
mScheduler->dumpPrimaryDispSync(s);
- } else {
- 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(); })},
@@ -4669,13 +4499,10 @@
" 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);
- }
+ StringAppendF(&result, "Scheduler enabled. 90Hz feature: %s\n", mUse90Hz ? "on" : "off");
+ StringAppendF(&result, "+ Smart 90 for video detection: %s\n\n",
+ mUseSmart90ForVideo ? "on" : "off");
+ mScheduler->dump(mAppConnectionHandle, result);
}
void SurfaceFlinger::dumpStaticScreenStats(std::string& result) const {
@@ -5024,11 +4851,9 @@
/**
* Scheduler dump state.
*/
- if (mUseScheduler) {
- result.append("\nScheduler state:\n");
- result.append(mScheduler->doDump() + "\n");
- result.append(mRefreshRateStats->doDump() + "\n");
- }
+ result.append("\nScheduler state:\n");
+ result.append(mScheduler->doDump() + "\n");
+ result.append(mRefreshRateStats->doDump() + "\n");
}
const Vector<sp<Layer>>& SurfaceFlinger::getLayerSortedByZForHwcDisplay(DisplayId displayId) {
@@ -5304,7 +5129,7 @@
case 1016: {
n = data.readInt32();
// TODO(b/113612090): Evaluate if this can be removed.
- mPrimaryDispSync->setRefreshSkipCount(n);
+ mScheduler->setRefreshSkipCount(n);
return NO_ERROR;
}
case 1017: {
@@ -5314,20 +5139,12 @@
}
case 1018: { // Modify Choreographer's phase offset
n = data.readInt32();
- if (mUseScheduler) {
- mScheduler->setPhaseOffset(mAppConnectionHandle, static_cast<nsecs_t>(n));
- } else {
- mEventThread->setPhaseOffset(static_cast<nsecs_t>(n));
- }
+ mScheduler->setPhaseOffset(mAppConnectionHandle, static_cast<nsecs_t>(n));
return NO_ERROR;
}
case 1019: { // Modify SurfaceFlinger's phase offset
n = data.readInt32();
- if (mUseScheduler) {
- mScheduler->setPhaseOffset(mSfConnectionHandle, static_cast<nsecs_t>(n));
- } else {
- mSFEventThread->setPhaseOffset(static_cast<nsecs_t>(n));
- }
+ mScheduler->setPhaseOffset(mSfConnectionHandle, static_cast<nsecs_t>(n));
return NO_ERROR;
}
case 1020: { // Layer updates interceptor
@@ -5668,6 +5485,13 @@
static_cast<android_pixel_format>(reqPixelFormat), 1,
usage, "screenshot");
+ return captureScreenCore(renderArea, traverseLayers, *outBuffer, useIdentityTransform);
+}
+
+status_t SurfaceFlinger::captureScreenCore(RenderArea& renderArea,
+ TraverseLayersFunction traverseLayers,
+ const sp<GraphicBuffer>& buffer,
+ bool useIdentityTransform) {
// This mutex protects syncFd and captureResult for communication of the return values from the
// main thread back to this Binder thread
std::mutex captureMutex;
@@ -5695,7 +5519,7 @@
{
Mutex::Autolock _l(mStateLock);
renderArea.render([&] {
- result = captureScreenImplLocked(renderArea, traverseLayers, (*outBuffer).get(),
+ result = captureScreenImplLocked(renderArea, traverseLayers, buffer.get(),
useIdentityTransform, forSystem, &fd);
});
}
@@ -5830,9 +5654,12 @@
});
clientCompositionDisplay.clearRegion = clearRegion;
+ // Use an empty fence for the buffer fence, since we just created the buffer so
+ // there is no need for synchronization with the GPU.
+ base::unique_fd bufferFence;
base::unique_fd drawFence;
getRenderEngine().drawLayers(clientCompositionDisplay, clientCompositionLayers, buffer,
- &drawFence);
+ std::move(bufferFence), &drawFence);
*outSyncFd = drawFence.release();
}
@@ -5862,6 +5689,13 @@
return NO_ERROR;
}
+void SurfaceFlinger::setInputWindowsFinished() {
+ Mutex::Autolock _l(mStateLock);
+
+ mPendingSyncInputWindows = false;
+ mTransactionCV.broadcast();
+}
+
// ---------------------------------------------------------------------------
void SurfaceFlinger::State::traverseInZOrder(const LayerVector::Visitor& visitor) const {
@@ -5893,6 +5727,12 @@
}
}
+// ----------------------------------------------------------------------------
+
+void SetInputWindowsListener::onSetInputWindowsFinished() {
+ mFlinger->setInputWindowsFinished();
+}
+
}; // namespace android
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 18f0ced..31b4fb6 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -33,6 +33,7 @@
#include <gui/LayerState.h>
#include <gui/OccupancyTracker.h>
#include <hardware/hwcomposer_defs.h>
+#include <input/ISetInputWindowsListener.h>
#include <layerproto/LayerProtoHeader.h>
#include <math/mat4.h>
#include <serviceutils/PriorityDumper.h>
@@ -56,6 +57,7 @@
#include "LayerBE.h"
#include "LayerStats.h"
#include "LayerVector.h"
+#include "RegionSamplingThread.h"
#include "Scheduler/DispSync.h"
#include "Scheduler/EventThread.h"
#include "Scheduler/MessageQueue.h"
@@ -169,9 +171,6 @@
nsecs_t mTotalTime;
std::atomic<nsecs_t> mLastSwapTime;
- // Synchronization fence from a GL composition.
- sp<Fence> flushFence = Fence::NO_FENCE;
-
// Double- vs. triple-buffering stats
struct BufferingStats {
BufferingStats()
@@ -204,6 +203,14 @@
std::map<wp<IBinder>, std::vector<CompositionInfo>> mEndOfFrameCompositionInfo;
};
+class SetInputWindowsListener : public BnSetInputWindowsListener {
+public:
+ SetInputWindowsListener(const sp<SurfaceFlinger>& flinger) : mFlinger(flinger) {}
+ void onSetInputWindowsFinished() override;
+
+private:
+ const sp<SurfaceFlinger> mFlinger;
+};
class SurfaceFlinger : public BnSurfaceComposer,
public PriorityDumper,
@@ -351,6 +358,8 @@
return mTransactionCompletedThread;
}
+ void setInputWindowsFinished();
+
private:
friend class Client;
friend class DisplayEventConnection;
@@ -360,6 +369,7 @@
friend class BufferQueueLayer;
friend class BufferStateLayer;
friend class MonitoredProducer;
+ friend class RegionSamplingThread;
// For unit tests
friend class TestableSurfaceFlinger;
@@ -513,16 +523,14 @@
void onInitializeDisplays() REQUIRES(mStateLock);
// Sets the desired active config bit. It obtains the lock, and sets mDesiredActiveConfig.
void setDesiredActiveConfig(const sp<IBinder>& displayToken, int mode) REQUIRES(mStateLock);
- // Calls setActiveConfig in HWC.
- void setActiveConfigInHWC();
// Once HWC has returned the present fence, this sets the active config and a new refresh
// rate in SF. It also triggers HWC vsync.
void setActiveConfigInternal() REQUIRES(mStateLock);
// Active config is updated on INVALIDATE call in a state machine-like manner. When the
- // desired config was set, HWC needs to update the pannel on the next refresh, and when
+ // desired config was set, HWC needs to update the panel on the next refresh, and when
// we receive the fence back, we know that the process was complete. It returns whether
- // the invalidate process should continue.
- bool updateSetActiveConfigStateMachine();
+ // we need to wait for the next invalidate
+ bool performSetActiveConfig();
// called on the main thread in response to setPowerMode()
void setPowerModeInternal(const sp<DisplayDevice>& display, int mode) REQUIRES(mStateLock);
@@ -627,6 +635,8 @@
status_t captureScreenCommon(RenderArea& renderArea, TraverseLayersFunction traverseLayers,
sp<GraphicBuffer>* outBuffer, const ui::PixelFormat reqPixelFormat,
bool useIdentityTransform);
+ status_t captureScreenCore(RenderArea& renderArea, TraverseLayersFunction traverseLayers,
+ const sp<GraphicBuffer>& buffer, bool useIdentityTransform);
status_t captureScreenImplLocked(const RenderArea& renderArea,
TraverseLayersFunction traverseLayers,
ANativeWindowBuffer* buffer, bool useIdentityTransform,
@@ -789,37 +799,11 @@
* VSync
*/
nsecs_t getVsyncPeriod() const REQUIRES(mStateLock);
- void enableHardwareVsync();
- void resyncToHardwareVsync(bool makeAvailable, nsecs_t period);
- void disableHardwareVsync(bool makeUnavailable);
// Sets the refresh rate by switching active configs, if they are available for
// the desired refresh rate.
void setRefreshRateTo(scheduler::RefreshRateConfigs::RefreshRateType) REQUIRES(mStateLock);
- 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
*/
@@ -957,11 +941,7 @@
// constant members (no synchronization needed for access)
nsecs_t mBootTime;
bool mGpuToCpuSupported;
- std::unique_ptr<EventThread> mEventThread;
- std::unique_ptr<EventThread> mSFEventThread;
std::unique_ptr<EventThread> mInjectorEventThread;
- std::unique_ptr<VSyncSource> mEventThreadSource;
- std::unique_ptr<VSyncSource> mSfEventThreadSource;
std::unique_ptr<InjectVSyncSource> mVSyncInjector;
std::unique_ptr<EventControlThread> mEventControlThread;
@@ -1022,22 +1002,20 @@
TransactionCompletedThread mTransactionCompletedThread;
+ bool mLumaSampling = true;
+ sp<RegionSamplingThread> mRegionSamplingThread = new RegionSamplingThread(*this);
+
// Restrict layers to use two buffers in their bufferqueues.
bool mLayerTripleBufferingDisabled = false;
// these are thread safe
mutable std::unique_ptr<MessageQueue> mEventQueue{mFactory.createMessageQueue()};
FrameTracker mAnimFrameTracker;
- std::unique_ptr<DispSync> mPrimaryDispSync;
// protected by mDestroyedLayerLock;
mutable Mutex mDestroyedLayerLock;
Vector<Layer const *> mDestroyedLayers;
- // protected by mHWVsyncLock
- Mutex mHWVsyncLock;
- bool mPrimaryHWVsyncEnabled;
- bool mHWVsyncAvailable;
nsecs_t mRefreshStartTime;
std::atomic<bool> mRefreshPending{false};
@@ -1113,21 +1091,13 @@
/* ------------------------------------------------------------------------
* Scheduler
*/
- bool mUseScheduler = false;
+ bool mUse90Hz = false;
+ bool mUseSmart90ForVideo = false;
std::unique_ptr<Scheduler> mScheduler;
sp<Scheduler::ConnectionHandle> mAppConnectionHandle;
sp<Scheduler::ConnectionHandle> mSfConnectionHandle;
std::unique_ptr<scheduler::RefreshRateStats> mRefreshRateStats;
- // The following structs are used for configuring active config state at a desired time,
- // which is once per vsync at invalidate time.
- enum SetActiveConfigState {
- NONE, // not in progress
- NOTIFIED_HWC, // call to HWC has been made
- REFRESH_RECEIVED // onRefresh was received from HWC
- };
- std::atomic<SetActiveConfigState> mSetActiveConfigState = SetActiveConfigState::NONE;
-
struct ActiveConfigInfo {
int configId;
sp<IBinder> displayToken;
@@ -1147,6 +1117,11 @@
// This bit can be set at any point in time when the system wants the new config.
ActiveConfigInfo mDesiredActiveConfig GUARDED_BY(mActiveConfigLock);
+ // below flags are set by main thread only
+ bool mDesiredActiveConfigChanged GUARDED_BY(mActiveConfigLock) = false;
+ bool mWaitForNextInvalidate = false;
+ bool mCheckPendingFence = false;
+
/* ------------------------------------------------------------------------ */
sp<IInputFlinger> mInputFlinger;
@@ -1155,6 +1130,9 @@
InputWindowCommands mInputWindowCommands;
ui::DisplayPrimaries mInternalDisplayPrimaries;
+
+ sp<SetInputWindowsListener> mSetInputWindowsListener;
+ bool mPendingSyncInputWindows GUARDED_BY(mStateLock);
};
}; // namespace android
diff --git a/services/surfaceflinger/layerproto/LayerProtoParser.cpp b/services/surfaceflinger/layerproto/LayerProtoParser.cpp
index 5c72fea..7ab57f9 100644
--- a/services/surfaceflinger/layerproto/LayerProtoParser.cpp
+++ b/services/surfaceflinger/layerproto/LayerProtoParser.cpp
@@ -199,13 +199,13 @@
}
}
- if (layerProto.has_parent()) {
+ if (layerProto.parent() != -1) {
if (layerMap.count(layerProto.parent()) > 0) {
currLayer->parent = layerMap[layerProto.parent()];
}
}
- if (layerProto.has_z_order_relative_of()) {
+ if (layerProto.z_order_relative_of() != -1) {
if (layerMap.count(layerProto.z_order_relative_of()) > 0) {
currLayer->zOrderRelativeOf = layerMap[layerProto.z_order_relative_of()];
}
diff --git a/services/surfaceflinger/layerproto/layers.proto b/services/surfaceflinger/layerproto/layers.proto
index 72cbfac..faf0c54 100644
--- a/services/surfaceflinger/layerproto/layers.proto
+++ b/services/surfaceflinger/layerproto/layers.proto
@@ -1,156 +1,156 @@
// Definitions for SurfaceFlinger layers.
-syntax = "proto2";
+syntax = "proto3";
option optimize_for = LITE_RUNTIME;
package android.surfaceflinger;
// Contains a list of all layers.
message LayersProto {
repeated LayerProto layers = 1;
- optional SizeProto resolution = 2;
- optional string color_mode = 3;
- optional string color_transform = 4;
- optional int32 global_transform = 5;
+ SizeProto resolution = 2;
+ string color_mode = 3;
+ string color_transform = 4;
+ int32 global_transform = 5;
}
// Information about each layer.
message LayerProto {
// unique id per layer.
- optional int32 id = 1;
+ int32 id = 1;
// unique name per layer.
- optional string name = 2;
+ string name = 2;
// list of children this layer may have. May be empty.
repeated int32 children = 3;
// list of layers that are z order relative to this layer.
repeated int32 relatives = 4;
// The type of layer, ex Color, Layer
- optional string type = 5;
- optional RegionProto transparent_region = 6;
- optional RegionProto visible_region = 7;
- optional RegionProto damage_region = 8;
- optional uint32 layer_stack = 9;
+ string type = 5;
+ RegionProto transparent_region = 6;
+ RegionProto visible_region = 7;
+ RegionProto damage_region = 8;
+ uint32 layer_stack = 9;
// The layer's z order. Can be z order in layer stack, relative to parent,
// or relative to another layer specified in zOrderRelative.
- optional int32 z = 10;
+ int32 z = 10;
// The layer's position on the display.
- optional PositionProto position = 11;
+ PositionProto position = 11;
// The layer's requested position.
- optional PositionProto requested_position = 12;
+ PositionProto requested_position = 12;
// The layer's size.
- optional SizeProto size = 13;
+ SizeProto size = 13;
// The layer's crop in it's own bounds.
- optional RectProto crop = 14;
+ RectProto crop = 14;
// The layer's crop in it's parent's bounds.
- optional RectProto final_crop = 15 [deprecated=true];
- optional bool is_opaque = 16;
- optional bool invalidate = 17;
- optional string dataspace = 18;
- optional string pixel_format = 19;
+ RectProto final_crop = 15 [deprecated=true];
+ bool is_opaque = 16;
+ bool invalidate = 17;
+ string dataspace = 18;
+ string pixel_format = 19;
// The layer's actual color.
- optional ColorProto color = 20;
+ ColorProto color = 20;
// The layer's requested color.
- optional ColorProto requested_color = 21;
+ ColorProto requested_color = 21;
// Can be any combination of
// hidden = 0x01
// opaque = 0x02,
// secure = 0x80,
- optional uint32 flags = 22;
+ uint32 flags = 22;
// The layer's actual transform
- optional TransformProto transform = 23;
+ TransformProto transform = 23;
// The layer's requested transform.
- optional TransformProto requested_transform = 24;
+ TransformProto requested_transform = 24;
// The parent layer. This value can be null if there is no parent.
- optional int32 parent = 25 [default = -1];
+ int32 parent = 25;
// The layer that this layer has a z order relative to. This value can be null.
- optional int32 z_order_relative_of = 26 [default = -1];
+ int32 z_order_relative_of = 26;
// This value can be null if there's nothing to draw.
- optional ActiveBufferProto active_buffer = 27;
+ ActiveBufferProto active_buffer = 27;
// The number of frames available.
- optional int32 queued_frames = 28;
- optional bool refresh_pending = 29;
+ int32 queued_frames = 28;
+ bool refresh_pending = 29;
// The layer's composer backend destination frame
- optional RectProto hwc_frame = 30;
+ RectProto hwc_frame = 30;
// The layer's composer backend source crop
- optional FloatRectProto hwc_crop = 31;
+ FloatRectProto hwc_crop = 31;
// The layer's composer backend transform
- optional int32 hwc_transform = 32;
- optional int32 window_type = 33 [deprecated=true];
- optional int32 app_id = 34 [deprecated=true];
+ int32 hwc_transform = 32;
+ int32 window_type = 33 [deprecated=true];
+ int32 app_id = 34 [deprecated=true];
// The layer's composition type
- optional int32 hwc_composition_type = 35;
+ int32 hwc_composition_type = 35;
// If it's a buffer layer, indicate if the content is protected
- optional bool is_protected = 36;
+ bool is_protected = 36;
// Current frame number being rendered.
- optional uint64 curr_frame = 37;
+ uint64 curr_frame = 37;
// A list of barriers that the layer is waiting to update state.
repeated BarrierLayerProto barrier_layer = 38;
// If active_buffer is not null, record its transform.
- optional TransformProto buffer_transform = 39;
- optional int32 effective_scaling_mode = 40;
+ TransformProto buffer_transform = 39;
+ int32 effective_scaling_mode = 40;
// Layer's corner radius.
- optional float corner_radius = 41;
+ float corner_radius = 41;
// Metadata map. May be empty.
map<int32, bytes> metadata = 42;
- optional TransformProto effective_transform = 43;
- optional FloatRectProto source_bounds = 44;
- optional FloatRectProto bounds = 45;
- optional FloatRectProto screen_bounds = 46;
+ TransformProto effective_transform = 43;
+ FloatRectProto source_bounds = 44;
+ FloatRectProto bounds = 45;
+ FloatRectProto screen_bounds = 46;
}
message PositionProto {
- optional float x = 1;
- optional float y = 2;
+ float x = 1;
+ float y = 2;
}
message SizeProto {
- optional int32 w = 1;
- optional int32 h = 2;
+ int32 w = 1;
+ int32 h = 2;
}
message TransformProto {
- optional float dsdx = 1;
- optional float dtdx = 2;
- optional float dsdy = 3;
- optional float dtdy = 4;
+ float dsdx = 1;
+ float dtdx = 2;
+ float dsdy = 3;
+ float dtdy = 4;
}
message RegionProto {
- optional uint64 id = 1;
+ uint64 id = 1;
repeated RectProto rect = 2;
}
message RectProto {
- optional int32 left = 1;
- optional int32 top = 2;
- optional int32 right = 3;
- optional int32 bottom = 4;
+ int32 left = 1;
+ int32 top = 2;
+ int32 right = 3;
+ int32 bottom = 4;
}
message FloatRectProto {
- optional float left = 1;
- optional float top = 2;
- optional float right = 3;
- optional float bottom = 4;
+ float left = 1;
+ float top = 2;
+ float right = 3;
+ float bottom = 4;
}
message ActiveBufferProto {
- optional uint32 width = 1;
- optional uint32 height = 2;
- optional uint32 stride = 3;
- optional int32 format = 4;
+ uint32 width = 1;
+ uint32 height = 2;
+ uint32 stride = 3;
+ int32 format = 4;
}
message ColorProto {
- optional float r = 1;
- optional float g = 2;
- optional float b = 3;
- optional float a = 4;
+ float r = 1;
+ float g = 2;
+ float b = 3;
+ float a = 4;
}
message BarrierLayerProto {
// layer id the barrier is waiting on.
- optional int32 id = 1;
+ int32 id = 1;
// frame number the barrier is waiting on.
- optional uint64 frame_number = 2;
+ uint64 frame_number = 2;
}
diff --git a/services/surfaceflinger/tests/Transaction_test.cpp b/services/surfaceflinger/tests/Transaction_test.cpp
index 7b21dbc..181dac6 100644
--- a/services/surfaceflinger/tests/Transaction_test.cpp
+++ b/services/surfaceflinger/tests/Transaction_test.cpp
@@ -5126,23 +5126,35 @@
SurfaceComposerClient::Transaction().show(mChild).apply(true);
}
- void verify() {
+ void verify(std::function<void()> verifyStartingState) {
+ // Verify starting state before a screenshot is taken.
+ verifyStartingState();
+
+ // Verify child layer does not inherit any of the properties of its
+ // parent when its screenshot is captured.
auto fgHandle = mFGSurfaceControl->getHandle();
ScreenCapture::captureChildLayers(&mCapture, fgHandle);
mCapture->checkPixel(10, 10, 0, 0, 0);
mCapture->expectChildColor(0, 0);
+
+ // Verify all assumptions are still true after the screenshot is taken.
+ verifyStartingState();
}
std::unique_ptr<ScreenCapture> mCapture;
sp<SurfaceControl> mChild;
};
+// Regression test b/76099859
TEST_F(ScreenCaptureChildOnlyTest, CaptureLayerIgnoresParentVisibility) {
SurfaceComposerClient::Transaction().hide(mFGSurfaceControl).apply(true);
// Even though the parent is hidden we should still capture the child.
- verify();
+
+ // Before and after reparenting, verify child is properly hidden
+ // when rendering full-screen.
+ verify([&] { screenshot()->expectBGColor(64, 64); });
}
TEST_F(ScreenCaptureChildOnlyTest, CaptureLayerIgnoresParentCrop) {
@@ -5151,25 +5163,19 @@
.apply(true);
// Even though the parent is cropped out we should still capture the child.
- verify();
+
+ // Before and after reparenting, verify child is cropped by parent.
+ verify([&] { screenshot()->expectBGColor(65, 65); });
}
+// Regression test b/124372894
TEST_F(ScreenCaptureChildOnlyTest, CaptureLayerIgnoresTransform) {
-
- SurfaceComposerClient::Transaction().setMatrix(mFGSurfaceControl, 2, 0, 0, 2);
+ SurfaceComposerClient::Transaction().setMatrix(mFGSurfaceControl, 2, 0, 0, 2).apply(true);
// We should not inherit the parent scaling.
- verify();
-}
-TEST_F(ScreenCaptureChildOnlyTest, RegressionTest76099859) {
- SurfaceComposerClient::Transaction().hide(mFGSurfaceControl).apply(true);
-
- // Even though the parent is hidden we should still capture the child.
- verify();
-
- // Verify everything was properly hidden when rendering the full-screen.
- screenshot()->expectBGColor(0,0);
+ // Before and after reparenting, verify child is properly scaled.
+ verify([&] { screenshot()->expectChildColor(80, 80); });
}
diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
index 3addd61..6deec29 100644
--- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
@@ -33,6 +33,7 @@
#include "ColorLayer.h"
#include "Layer.h"
+#include "TestableScheduler.h"
#include "TestableSurfaceFlinger.h"
#include "mock/DisplayHardware/MockComposer.h"
#include "mock/MockDispSync.h"
@@ -90,11 +91,9 @@
::testing::UnitTest::GetInstance()->current_test_info();
ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name());
- mFlinger.mutableEventControlThread().reset(mEventControlThread);
- mFlinger.mutableEventThread().reset(mEventThread);
mFlinger.mutableEventQueue().reset(mMessageQueue);
+ setupScheduler();
- mFlinger.mutablePrimaryDispSync().reset(mPrimaryDispSync);
EXPECT_CALL(*mPrimaryDispSync, computeNextRefresh(0)).WillRepeatedly(Return(0));
EXPECT_CALL(*mPrimaryDispSync, getPeriod())
.WillRepeatedly(Return(FakeHwcDisplayInjector::DEFAULT_REFRESH_RATE));
@@ -124,6 +123,18 @@
Mock::VerifyAndClear(mComposer);
}
+ void setupScheduler() {
+ mScheduler = new TestableScheduler();
+ mScheduler->mutableEventControlThread().reset(mEventControlThread);
+ mScheduler->mutablePrimaryDispSync().reset(mPrimaryDispSync);
+ EXPECT_CALL(*mEventThread.get(), registerDisplayEventConnection(_));
+ sp<Scheduler::ConnectionHandle> connectionHandle =
+ mScheduler->addConnection(std::move(mEventThread));
+ mFlinger.mutableSfConnectionHandle() = std::move(connectionHandle);
+
+ mFlinger.mutableScheduler().reset(mScheduler);
+ }
+
void setupForceGeometryDirty() {
// TODO: This requires the visible region and other related
// state to be set, and is problematic for BufferLayers since they are
@@ -145,6 +156,7 @@
std::unordered_set<HWC2::Capability> mDefaultCapabilities = {HWC2::Capability::SidebandStream};
+ TestableScheduler* mScheduler;
TestableSurfaceFlinger mFlinger;
sp<DisplayDevice> mDisplay;
sp<DisplayDevice> mExternalDisplay;
@@ -155,7 +167,7 @@
sp<GraphicBuffer> mBuffer = new GraphicBuffer();
ANativeWindowBuffer* mNativeWindowBuffer = mBuffer->getNativeBuffer();
- mock::EventThread* mEventThread = new mock::EventThread();
+ std::unique_ptr<mock::EventThread> mEventThread = std::make_unique<mock::EventThread>();
mock::EventControlThread* mEventControlThread = new mock::EventControlThread();
Hwc2::mock::Composer* mComposer = nullptr;
@@ -300,7 +312,7 @@
.WillRepeatedly(
[](const renderengine::DisplaySettings& displaySettings,
const std::vector<renderengine::LayerSettings>& /*layerSettings*/,
- ANativeWindowBuffer*, base::unique_fd*) -> status_t {
+ ANativeWindowBuffer*, base::unique_fd&&, base::unique_fd*) -> status_t {
EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance);
EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
displaySettings.physicalDisplay);
@@ -339,7 +351,7 @@
.WillRepeatedly(
[](const renderengine::DisplaySettings& displaySettings,
const std::vector<renderengine::LayerSettings>& /*layerSettings*/,
- ANativeWindowBuffer*, base::unique_fd*) -> status_t {
+ ANativeWindowBuffer*, base::unique_fd&&, base::unique_fd*) -> status_t {
EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance);
EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
displaySettings.physicalDisplay);
@@ -482,7 +494,7 @@
EXPECT_CALL(*test->mRenderEngine, useNativeFenceSync()).WillRepeatedly(Return(true));
bool ignoredRecomputeVisibleRegions;
- layer->latchBuffer(ignoredRecomputeVisibleRegions, 0, Fence::NO_FENCE);
+ layer->latchBuffer(ignoredRecomputeVisibleRegions, 0);
Mock::VerifyAndClear(test->mRenderEngine);
}
@@ -568,7 +580,8 @@
EXPECT_CALL(*test->mRenderEngine, drawLayers)
.WillOnce([](const renderengine::DisplaySettings& displaySettings,
const std::vector<renderengine::LayerSettings>& layerSettings,
- ANativeWindowBuffer*, base::unique_fd*) -> status_t {
+ ANativeWindowBuffer*, base::unique_fd&&,
+ base::unique_fd*) -> status_t {
EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance);
EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
displaySettings.physicalDisplay);
@@ -612,7 +625,8 @@
EXPECT_CALL(*test->mRenderEngine, drawLayers)
.WillOnce([](const renderengine::DisplaySettings& displaySettings,
const std::vector<renderengine::LayerSettings>& layerSettings,
- ANativeWindowBuffer*, base::unique_fd*) -> status_t {
+ ANativeWindowBuffer*, base::unique_fd&&,
+ base::unique_fd*) -> status_t {
EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance);
EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
displaySettings.physicalDisplay);
@@ -681,7 +695,8 @@
EXPECT_CALL(*test->mRenderEngine, drawLayers)
.WillOnce([](const renderengine::DisplaySettings& displaySettings,
const std::vector<renderengine::LayerSettings>& layerSettings,
- ANativeWindowBuffer*, base::unique_fd*) -> status_t {
+ ANativeWindowBuffer*, base::unique_fd&&,
+ base::unique_fd*) -> status_t {
EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance);
EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
displaySettings.physicalDisplay);
@@ -754,16 +769,16 @@
}
static void injectLayer(CompositionTest* test, sp<Layer> layer) {
- std::vector<std::unique_ptr<compositionengine::OutputLayer>> outputLayers;
- outputLayers.emplace_back(
- test->mDisplay->getCompositionDisplay()
- ->getOrCreateOutputLayer(layer->getCompositionLayer(), layer));
- test->mDisplay->getCompositionDisplay()->setOutputLayersOrderedByZ(std::move(outputLayers));
-
EXPECT_CALL(*test->mComposer, createLayer(HWC_DISPLAY, _))
.WillOnce(DoAll(SetArgPointee<1>(HWC_LAYER), Return(Error::NONE)));
- layer->createHwcLayer(&test->mFlinger.getHwComposer(), test->mDisplay);
+ std::vector<std::unique_ptr<compositionengine::OutputLayer>> outputLayers;
+ outputLayers.emplace_back(test->mDisplay->getCompositionDisplay()
+ ->getOrCreateOutputLayer(DEFAULT_DISPLAY_ID,
+ layer->getCompositionLayer(),
+ layer));
+
+ test->mDisplay->getCompositionDisplay()->setOutputLayersOrderedByZ(std::move(outputLayers));
Mock::VerifyAndClear(test->mComposer);
@@ -779,10 +794,6 @@
test->mDisplay->getCompositionDisplay()->setOutputLayersOrderedByZ(
std::vector<std::unique_ptr<compositionengine::OutputLayer>>());
-
- for (auto layer : test->mFlinger.mutableDrawingState().layersSortedByZ) {
- layer->destroyHwcLayer(test->mDisplay);
- }
test->mFlinger.mutableDrawingState().layersSortedByZ.clear();
}
};
diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
index 6659d4a..19f308b 100644
--- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
@@ -29,6 +29,7 @@
#include <ui/DebugUtils.h>
#include "DisplayIdentificationTest.h"
+#include "TestableScheduler.h"
#include "TestableSurfaceFlinger.h"
#include "mock/DisplayHardware/MockComposer.h"
#include "mock/MockDispSync.h"
@@ -94,6 +95,8 @@
DisplayTransactionTest();
~DisplayTransactionTest() override;
+ void setupScheduler();
+
// --------------------------------------------------------------------
// Mock/Fake injection
@@ -116,6 +119,7 @@
// --------------------------------------------------------------------
// Test instances
+ TestableScheduler* mScheduler;
TestableSurfaceFlinger mFlinger;
mock::EventThread* mEventThread = new mock::EventThread();
mock::EventThread* mSFEventThread = new mock::EventThread();
@@ -160,13 +164,10 @@
return nullptr;
});
- mFlinger.mutableEventControlThread().reset(mEventControlThread);
- mFlinger.mutableEventThread().reset(mEventThread);
- mFlinger.mutableSFEventThread().reset(mSFEventThread);
+ setupScheduler();
mFlinger.mutableEventQueue().reset(mMessageQueue);
mFlinger.setupRenderEngine(std::unique_ptr<renderengine::RenderEngine>(mRenderEngine));
mFlinger.mutableInterceptor().reset(mSurfaceInterceptor);
- mFlinger.mutablePrimaryDispSync().reset(mPrimaryDispSync);
injectMockComposer(0);
}
@@ -177,6 +178,22 @@
ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name());
}
+void DisplayTransactionTest::setupScheduler() {
+ mScheduler = new TestableScheduler();
+ mScheduler->mutableEventControlThread().reset(mEventControlThread);
+ mScheduler->mutablePrimaryDispSync().reset(mPrimaryDispSync);
+ EXPECT_CALL(*mEventThread, registerDisplayEventConnection(_));
+ EXPECT_CALL(*mSFEventThread, registerDisplayEventConnection(_));
+
+ sp<Scheduler::ConnectionHandle> sfConnectionHandle =
+ mScheduler->addConnection(std::unique_ptr<EventThread>(mSFEventThread));
+ mFlinger.mutableSfConnectionHandle() = std::move(sfConnectionHandle);
+ sp<Scheduler::ConnectionHandle> appConnectionHandle =
+ mScheduler->addConnection(std::unique_ptr<EventThread>(mEventThread));
+ mFlinger.mutableAppConnectionHandle() = std::move(appConnectionHandle);
+ mFlinger.mutableScheduler().reset(mScheduler);
+}
+
void DisplayTransactionTest::injectMockComposer(int virtualDisplayCount) {
mComposer = new Hwc2::mock::Composer();
EXPECT_CALL(*mComposer, getCapabilities())
@@ -1106,8 +1123,8 @@
// Preconditions
// vsync is enabled and available
- mFlinger.mutablePrimaryHWVsyncEnabled() = true;
- mFlinger.mutableHWVsyncAvailable() = true;
+ mScheduler->mutablePrimaryHWVsyncEnabled() = true;
+ mScheduler->mutableHWVsyncAvailable() = true;
// A display exists
auto existing = Case::Display::makeFakeExistingDisplayInjector(this);
@@ -1131,8 +1148,8 @@
// Postconditions
// vsyncs should be off and not available.
- EXPECT_FALSE(mFlinger.mutablePrimaryHWVsyncEnabled());
- EXPECT_FALSE(mFlinger.mutableHWVsyncAvailable());
+ EXPECT_FALSE(mScheduler->mutablePrimaryHWVsyncEnabled());
+ EXPECT_FALSE(mScheduler->mutableHWVsyncAvailable());
// The display should have been removed from the display map.
EXPECT_FALSE(hasDisplayDevice(existing.token()));
@@ -1557,7 +1574,6 @@
Case::PerFrameMetadataSupport::setupComposerCallExpectations(this);
EXPECT_CALL(*mSurfaceInterceptor, saveDisplayCreation(_)).Times(1);
-
expectHotplugReceived<Case, true>(mEventThread);
expectHotplugReceived<Case, true>(mSFEventThread);
}
@@ -3008,7 +3024,7 @@
}
static void setInitialPrimaryHWVsyncEnabled(DisplayTransactionTest* test, bool enabled) {
- test->mFlinger.mutablePrimaryHWVsyncEnabled() = enabled;
+ test->mScheduler->mutablePrimaryHWVsyncEnabled() = enabled;
}
static void setupRepaintEverythingCallExpectations(DisplayTransactionTest* test) {
diff --git a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
index 3a7cfba..e499ff5 100644
--- a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
+++ b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
@@ -44,6 +44,7 @@
MOCK_METHOD1(setVSyncEnabled, void(bool));
MOCK_METHOD1(setCallback, void(VSyncSource::Callback*));
MOCK_METHOD1(setPhaseOffset, void(nsecs_t));
+ MOCK_METHOD1(pauseVsyncCallback, void(bool));
};
} // namespace
@@ -71,6 +72,7 @@
void expectVSyncSetEnabledCallReceived(bool expectedState);
void expectVSyncSetPhaseOffsetCallReceived(nsecs_t expectedPhaseOffset);
+ void expectVSyncPauseVsyncCallbackCallReceived(bool expectedPause);
VSyncSource::Callback* expectVSyncSetCallbackCallReceived();
void expectInterceptCallReceived(nsecs_t expectedTimestamp);
void expectVsyncEventReceivedByConnection(const char* name,
@@ -83,6 +85,7 @@
AsyncCallRecorder<void (*)(bool)> mVSyncSetEnabledCallRecorder;
AsyncCallRecorder<void (*)(VSyncSource::Callback*)> mVSyncSetCallbackCallRecorder;
AsyncCallRecorder<void (*)(nsecs_t)> mVSyncSetPhaseOffsetCallRecorder;
+ AsyncCallRecorder<void (*)(bool)> mVSyncPauseVsyncCallbackCallRecorder;
AsyncCallRecorder<void (*)()> mResyncCallRecorder;
AsyncCallRecorder<void (*)()> mResetIdleTimerCallRecorder;
AsyncCallRecorder<void (*)(nsecs_t)> mInterceptVSyncCallRecorder;
@@ -108,6 +111,9 @@
EXPECT_CALL(mVSyncSource, setPhaseOffset(_))
.WillRepeatedly(Invoke(mVSyncSetPhaseOffsetCallRecorder.getInvocable()));
+ EXPECT_CALL(mVSyncSource, pauseVsyncCallback(_))
+ .WillRepeatedly(Invoke(mVSyncPauseVsyncCallbackCallRecorder.getInvocable()));
+
createThread();
mConnection = createConnection(mConnectionEventCallRecorder);
@@ -157,6 +163,12 @@
EXPECT_EQ(expectedPhaseOffset, std::get<0>(args.value()));
}
+void EventThreadTest::expectVSyncPauseVsyncCallbackCallReceived(bool expectedPause) {
+ auto args = mVSyncPauseVsyncCallbackCallRecorder.waitForCall();
+ ASSERT_TRUE(args.has_value());
+ EXPECT_EQ(expectedPause, std::get<0>(args.value()));
+}
+
VSyncSource::Callback* EventThreadTest::expectVSyncSetCallbackCallReceived() {
auto callbackSet = mVSyncSetCallbackCallRecorder.waitForCall();
return callbackSet.has_value() ? std::get<0>(callbackSet.value()) : nullptr;
@@ -406,6 +418,16 @@
expectVSyncSetPhaseOffsetCallReceived(321);
}
+TEST_F(EventThreadTest, pauseVsyncCallbackForwardsToVSyncSource) {
+ mThread->pauseVsyncCallback(true);
+ expectVSyncPauseVsyncCallbackCallReceived(true);
+}
+
+TEST_F(EventThreadTest, resumeVsyncCallbackForwardsToVSyncSource) {
+ mThread->pauseVsyncCallback(false);
+ expectVSyncPauseVsyncCallbackCallReceived(false);
+}
+
TEST_F(EventThreadTest, postHotplugInternalDisconnect) {
mThread->onHotplugReceived(INTERNAL_DISPLAY_ID, false);
expectHotplugEventReceivedByConnection(INTERNAL_DISPLAY_ID, false);
diff --git a/services/surfaceflinger/tests/unittests/TestableScheduler.h b/services/surfaceflinger/tests/unittests/TestableScheduler.h
new file mode 100644
index 0000000..dcbf973
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/TestableScheduler.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.
+ */
+
+#pragma once
+
+#include <gmock/gmock.h>
+
+#include "Scheduler/EventThread.h"
+#include "Scheduler/Scheduler.h"
+
+namespace android {
+
+class TestableScheduler : public Scheduler {
+public:
+ TestableScheduler() : Scheduler([](bool) {}) {}
+
+ // Creates EventThreadConnection with the given eventThread. Creates Scheduler::Connection
+ // and adds it to the list of connectins. Returns the ConnectionHandle for the
+ // Scheduler::Connection. This allows plugging in mock::EventThread.
+ sp<Scheduler::ConnectionHandle> addConnection(std::unique_ptr<EventThread> eventThread) {
+ sp<EventThreadConnection> eventThreadConnection =
+ new EventThreadConnection(eventThread.get(), ResyncCallback(),
+ ResetIdleTimerCallback());
+ const int64_t id = sNextId++;
+ mConnections.emplace(id,
+ std::make_unique<Scheduler::Connection>(new ConnectionHandle(id),
+ eventThreadConnection,
+ std::move(eventThread)));
+ return mConnections[id]->handle;
+ }
+
+ /* ------------------------------------------------------------------------
+ * Read-write access to private data to set up preconditions and assert
+ * post-conditions.
+ */
+ auto& mutablePrimaryHWVsyncEnabled() { return mPrimaryHWVsyncEnabled; }
+ auto& mutableEventControlThread() { return mEventControlThread; }
+ auto& mutablePrimaryDispSync() { return mPrimaryDispSync; }
+ auto& mutableHWVsyncAvailable() { return mHWVsyncAvailable; }
+
+ ~TestableScheduler() {
+ // All these pointer and container clears help ensure that GMock does
+ // not report a leaked object, since the Scheduler instance may
+ // still be referenced by something despite our best efforts to destroy
+ // it after each test is done.
+ mutableEventControlThread().reset();
+ mutablePrimaryDispSync().reset();
+ mConnections.clear();
+ };
+};
+
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index 959126e..6313f1f 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -299,7 +299,6 @@
const auto& getAnimFrameTracker() const { return mFlinger->mAnimFrameTracker; }
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());
@@ -320,18 +319,12 @@
auto& mutableDisplayColorSetting() { return mFlinger->mDisplayColorSetting; }
auto& mutableDisplays() { return mFlinger->mDisplays; }
auto& mutableDrawingState() { return mFlinger->mDrawingState; }
- 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; }
auto& mutableMainThreadId() { return mFlinger->mMainThreadId; }
auto& mutablePendingHotplugEvents() { return mFlinger->mPendingHotplugEvents; }
auto& mutablePhysicalDisplayTokens() { return mFlinger->mPhysicalDisplayTokens; }
- auto& mutablePrimaryDispSync() { return mFlinger->mPrimaryDispSync; }
- auto& mutablePrimaryHWVsyncEnabled() { return mFlinger->mPrimaryHWVsyncEnabled; }
auto& mutableTexturePool() { return mFlinger->mTexturePool; }
auto& mutableTransactionFlags() { return mFlinger->mTransactionFlags; }
auto& mutableUseHwcVirtualDisplays() { return mFlinger->mUseHwcVirtualDisplays; }
@@ -341,6 +334,9 @@
auto& mutableHwcPhysicalDisplayIdMap() { return getHwComposer().mPhysicalDisplayIdMap; }
auto& mutableInternalHwcDisplayId() { return getHwComposer().mInternalHwcDisplayId; }
auto& mutableExternalHwcDisplayId() { return getHwComposer().mExternalHwcDisplayId; }
+ auto& mutableScheduler() { return mFlinger->mScheduler; }
+ auto& mutableAppConnectionHandle() { return mFlinger->mAppConnectionHandle; }
+ auto& mutableSfConnectionHandle() { return mFlinger->mSfConnectionHandle; }
~TestableSurfaceFlinger() {
// All these pointer and container clears help ensure that GMock does
@@ -348,12 +344,9 @@
// still be referenced by something despite our best efforts to destroy
// it after each test is done.
mutableDisplays().clear();
- mutableEventControlThread().reset();
mutableEventQueue().reset();
- mutableEventThread().reset();
- mutableSFEventThread().reset();
mutableInterceptor().reset();
- mutablePrimaryDispSync().reset();
+ mutableScheduler().reset();
mFlinger->mCompositionEngine->setHwComposer(std::unique_ptr<HWComposer>());
mFlinger->mCompositionEngine->setRenderEngine(
std::unique_ptr<renderengine::RenderEngine>());
diff --git a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
index 589237d..5edee6e 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
@@ -39,6 +39,7 @@
status_t(const sp<android::EventThreadConnection> &));
MOCK_METHOD2(setVsyncRate, void(uint32_t, const sp<android::EventThreadConnection> &));
MOCK_METHOD2(requestNextVsync, void(const sp<android::EventThreadConnection> &, bool));
+ MOCK_METHOD1(pauseVsyncCallback, void(bool));
};
} // namespace mock
diff --git a/services/vr/bufferhubd/producer_channel.cpp b/services/vr/bufferhubd/producer_channel.cpp
index b49d894..a7fd912 100644
--- a/services/vr/bufferhubd/producer_channel.cpp
+++ b/services/vr/bufferhubd/producer_channel.cpp
@@ -392,8 +392,8 @@
Status<void> ProducerChannel::OnProducerPost(Message&,
LocalFence acquire_fence) {
ATRACE_NAME("ProducerChannel::OnProducerPost");
- ALOGD("ProducerChannel::OnProducerPost: buffer_id=%d, state=0x%x",
- buffer_id(), buffer_state_->load(std::memory_order_acquire));
+ ALOGD_IF(TRACE, "%s: buffer_id=%d, state=0x%x", __FUNCTION__, buffer_id(),
+ buffer_state_->load(std::memory_order_acquire));
epoll_event event;
event.events = 0;
@@ -437,7 +437,7 @@
Status<LocalFence> ProducerChannel::OnProducerGain(Message& /*message*/) {
ATRACE_NAME("ProducerChannel::OnGain");
- ALOGW("ProducerChannel::OnGain: buffer_id=%d", buffer_id());
+ ALOGD_IF(TRACE, "%s: buffer_id=%d", __FUNCTION__, buffer_id());
ClearAvailable();
post_fence_.close();
diff --git a/vulkan/libvulkan/driver.cpp b/vulkan/libvulkan/driver.cpp
index 3a8e34e..b3259de 100644
--- a/vulkan/libvulkan/driver.cpp
+++ b/vulkan/libvulkan/driver.cpp
@@ -33,6 +33,7 @@
#include <configstore/Utils.h>
#include <cutils/properties.h>
#include <graphicsenv/GraphicsEnv.h>
+#include <utils/Timers.h>
#include <utils/Trace.h>
#include <utils/Vector.h>
@@ -210,6 +211,8 @@
auto ns = android_get_exported_namespace("sphal");
if (!ns)
return -ENOENT;
+ android::GraphicsEnv::getInstance().setDriverToLoad(
+ android::GraphicsEnv::Driver::VULKAN);
return LoadDriver(ns, module);
}
@@ -219,12 +222,16 @@
auto ns = android::GraphicsEnv::getInstance().getDriverNamespace();
if (!ns)
return -ENOENT;
+ android::GraphicsEnv::getInstance().setDriverToLoad(
+ android::GraphicsEnv::Driver::VULKAN_UPDATED);
return LoadDriver(ns, module);
}
bool Hal::Open() {
ATRACE_CALL();
+ const nsecs_t openTime = systemTime();
+
ALOG_ASSERT(!hal_.dev_, "OpenHAL called more than once");
// Use a stub device unless we successfully open a real HAL device.
@@ -250,11 +257,12 @@
}
}
if (result != 0) {
+ android::GraphicsEnv::getInstance().setDriverLoaded(
+ android::GraphicsEnv::Api::API_VK, false, systemTime() - openTime);
ALOGV("unable to load Vulkan HAL, using stub HAL (result=%d)", result);
return true;
}
- android::GraphicsEnv::getInstance().sendGpuStats();
hwvulkan_device_t* device;
ATRACE_BEGIN("hwvulkan module open");
@@ -263,6 +271,8 @@
reinterpret_cast<hw_device_t**>(&device));
ATRACE_END();
if (result != 0) {
+ android::GraphicsEnv::getInstance().setDriverLoaded(
+ android::GraphicsEnv::Api::API_VK, false, systemTime() - openTime);
// Any device with a Vulkan HAL should be able to open the device.
ALOGE("failed to open Vulkan HAL device: %s (%d)", strerror(-result),
result);
@@ -273,6 +283,9 @@
hal_.InitDebugReportIndex();
+ android::GraphicsEnv::getInstance().setDriverLoaded(
+ android::GraphicsEnv::Api::API_VK, true, systemTime() - openTime);
+
return true;
}
diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp
index 32e19f7..73fc7b2 100644
--- a/vulkan/libvulkan/swapchain.cpp
+++ b/vulkan/libvulkan/swapchain.cpp
@@ -688,6 +688,8 @@
{VK_FORMAT_R8G8B8A8_UNORM, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR},
{VK_FORMAT_R8G8B8A8_SRGB, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR},
{VK_FORMAT_R5G6B5_UNORM_PACK16, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR},
+ {VK_FORMAT_A2B10G10R10_UNORM_PACK32, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR},
+ {VK_FORMAT_R16G16B16A16_SFLOAT, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR},
};
const uint32_t kNumFormats = sizeof(kFormats) / sizeof(kFormats[0]);
uint32_t total_num_formats = kNumFormats;