Merge "Refactor dumpsys to expose helper apis"
diff --git a/cmds/dumpstate/Android.bp b/cmds/dumpstate/Android.bp
index ce3a6aa..35cff5f 100644
--- a/cmds/dumpstate/Android.bp
+++ b/cmds/dumpstate/Android.bp
@@ -83,7 +83,9 @@
],
srcs: [
"DumpstateInternal.cpp",
+ "DumpstateSectionReporter.cpp",
"DumpstateService.cpp",
+ "main.cpp",
"utils.cpp",
"dumpstate.cpp",
],
diff --git a/cmds/dumpstate/DumpstateSectionReporter.cpp b/cmds/dumpstate/DumpstateSectionReporter.cpp
new file mode 100644
index 0000000..f814bde
--- /dev/null
+++ b/cmds/dumpstate/DumpstateSectionReporter.cpp
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "dumpstate"
+
+#include "DumpstateSectionReporter.h"
+
+namespace android {
+namespace os {
+namespace dumpstate {
+
+DumpstateSectionReporter::DumpstateSectionReporter(const std::string& title,
+ sp<android::os::IDumpstateListener> listener,
+ bool sendReport)
+ : title_(title), listener_(listener), sendReport_(sendReport), status_(OK), size_(-1) {
+ started_ = std::chrono::steady_clock::now();
+}
+
+DumpstateSectionReporter::~DumpstateSectionReporter() {
+ if ((listener_ != nullptr) && (sendReport_)) {
+ auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(
+ std::chrono::steady_clock::now() - started_);
+ listener_->onSectionComplete(title_, status_, size_, (int32_t)elapsed.count());
+ }
+}
+
+} // namespace dumpstate
+} // namespace os
+} // namespace android
diff --git a/cmds/dumpstate/DumpstateSectionReporter.h b/cmds/dumpstate/DumpstateSectionReporter.h
new file mode 100644
index 0000000..e971de8
--- /dev/null
+++ b/cmds/dumpstate/DumpstateSectionReporter.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_OS_DUMPSTATESECTIONREPORTER_H_
+#define ANDROID_OS_DUMPSTATESECTIONREPORTER_H_
+
+#include <android/os/IDumpstateListener.h>
+#include <utils/StrongPointer.h>
+
+namespace android {
+namespace os {
+namespace dumpstate {
+
+
+/*
+ * Helper class used to report per section details to a listener.
+ *
+ * Typical usage:
+ *
+ * DumpstateSectionReporter sectionReporter(title, listener, sendReport);
+ * sectionReporter.setSize(5000);
+ *
+ */
+class DumpstateSectionReporter {
+ public:
+ DumpstateSectionReporter(const std::string& title, sp<android::os::IDumpstateListener> listener,
+ bool sendReport);
+
+ ~DumpstateSectionReporter();
+
+ void setStatus(status_t status) {
+ status_ = status;
+ }
+
+ void setSize(int size) {
+ size_ = size;
+ }
+
+ private:
+ std::string title_;
+ android::sp<android::os::IDumpstateListener> listener_;
+ bool sendReport_;
+ status_t status_;
+ int size_;
+ std::chrono::time_point<std::chrono::steady_clock> started_;
+};
+
+} // namespace dumpstate
+} // namespace os
+} // namespace android
+
+#endif // ANDROID_OS_DUMPSTATESECTIONREPORTER_H_
diff --git a/cmds/dumpstate/DumpstateService.cpp b/cmds/dumpstate/DumpstateService.cpp
index efe0466..49a78e7 100644
--- a/cmds/dumpstate/DumpstateService.cpp
+++ b/cmds/dumpstate/DumpstateService.cpp
@@ -52,6 +52,7 @@
binder::Status DumpstateService::setListener(const std::string& name,
const sp<IDumpstateListener>& listener,
+ bool getSectionDetails,
sp<IDumpstateToken>* returned_token) {
*returned_token = nullptr;
if (name.empty()) {
@@ -70,6 +71,7 @@
ds_.listener_name_ = name;
ds_.listener_ = listener;
+ ds_.report_section_ = getSectionDetails;
*returned_token = new DumpstateToken();
return binder::Status::ok();
diff --git a/cmds/dumpstate/DumpstateService.h b/cmds/dumpstate/DumpstateService.h
index 4352d3d..7bca24a 100644
--- a/cmds/dumpstate/DumpstateService.h
+++ b/cmds/dumpstate/DumpstateService.h
@@ -38,6 +38,7 @@
status_t dump(int fd, const Vector<String16>& args) override;
binder::Status setListener(const std::string& name, const sp<IDumpstateListener>& listener,
+ bool getSectionDetails,
sp<IDumpstateToken>* returned_token) override;
private:
diff --git a/cmds/dumpstate/binder/android/os/IDumpstate.aidl b/cmds/dumpstate/binder/android/os/IDumpstate.aidl
index 4becccf..9b11b96 100644
--- a/cmds/dumpstate/binder/android/os/IDumpstate.aidl
+++ b/cmds/dumpstate/binder/android/os/IDumpstate.aidl
@@ -30,6 +30,9 @@
*
* Returns a token used to monitor dumpstate death, or `nullptr` if the listener was already
* set (the listener behaves like a Highlander: There Can be Only One).
+ * Set {@code getSectionDetails} to true in order to receive callbacks with per section
+ * progress details
*/
- IDumpstateToken setListener(@utf8InCpp String name, IDumpstateListener listener);
+ IDumpstateToken setListener(@utf8InCpp String name, IDumpstateListener listener,
+ boolean getSectionDetails);
}
diff --git a/cmds/dumpstate/binder/android/os/IDumpstateListener.aidl b/cmds/dumpstate/binder/android/os/IDumpstateListener.aidl
index 32717f4..030d69d 100644
--- a/cmds/dumpstate/binder/android/os/IDumpstateListener.aidl
+++ b/cmds/dumpstate/binder/android/os/IDumpstateListener.aidl
@@ -24,4 +24,16 @@
interface IDumpstateListener {
void onProgressUpdated(int progress);
void onMaxProgressUpdated(int maxProgress);
+
+ /**
+ * Called after every section is complete.
+ * @param name section name
+ * @param status values from status_t
+ * {@code OK} section completed successfully
+ * {@code TIMEOUT} dump timed out
+ * {@code != OK} error
+ * @param size size in bytes, may be invalid if status != OK
+ * @param durationMs duration in ms
+ */
+ void onSectionComplete(@utf8InCpp String name, int status, int size, int durationMs);
}
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 2e3e3ca..93f8d43 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -43,8 +43,10 @@
#include <android-base/strings.h>
#include <android-base/unique_fd.h>
#include <android/hardware/dumpstate/1.0/IDumpstateDevice.h>
+#include <android/hidl/manager/1.0/IServiceManager.h>
#include <cutils/native_handle.h>
#include <cutils/properties.h>
+#include <hidl/ServiceManagement.h>
#include <openssl/sha.h>
#include <private/android_filesystem_config.h>
#include <private/android_logger.h>
@@ -131,8 +133,6 @@
};
static const int NUM_OF_DUMPS = arraysize(kDumpstateBoardFiles);
-static const std::string kLsHalDebugPath = "/bugreports/dumpstate_lshal.txt";
-
static constexpr char PROPERTY_EXTRA_OPTIONS[] = "dumpstate.options";
static constexpr char PROPERTY_LAST_ID[] = "dumpstate.last_id";
static constexpr char PROPERTY_VERSION[] = "dumpstate.version";
@@ -831,40 +831,52 @@
}
}
+static const long MINIMUM_LOGCAT_TIMEOUT_MS = 50000;
+
+static void DoKernelLogcat() {
+ unsigned long timeout_ms = logcat_timeout("kernel");
+ if (timeout_ms < MINIMUM_LOGCAT_TIMEOUT_MS) {
+ timeout_ms = MINIMUM_LOGCAT_TIMEOUT_MS;
+ }
+ RunCommand(
+ "KERNEL LOG",
+ {"logcat", "-b", "kernel", "-v", "threadtime", "-v", "printable", "-v", "uid", "-d", "*:v"},
+ CommandOptions::WithTimeoutInMs(timeout_ms).Build());
+}
+
static void DoLogcat() {
unsigned long timeout_ms;
// DumpFile("EVENT LOG TAGS", "/etc/event-log-tags");
// calculate timeout
timeout_ms = logcat_timeout("main") + logcat_timeout("system") + logcat_timeout("crash");
- if (timeout_ms < 20000) {
- timeout_ms = 20000;
+ if (timeout_ms < MINIMUM_LOGCAT_TIMEOUT_MS) {
+ timeout_ms = MINIMUM_LOGCAT_TIMEOUT_MS;
}
RunCommand("SYSTEM LOG",
{"logcat", "-v", "threadtime", "-v", "printable", "-v", "uid", "-d", "*:v"},
CommandOptions::WithTimeoutInMs(timeout_ms).Build());
timeout_ms = logcat_timeout("events");
- if (timeout_ms < 20000) {
- timeout_ms = 20000;
+ if (timeout_ms < MINIMUM_LOGCAT_TIMEOUT_MS) {
+ timeout_ms = MINIMUM_LOGCAT_TIMEOUT_MS;
}
- RunCommand("EVENT LOG",
- {"logcat", "-b", "events", "-v", "threadtime", "-v", "printable", "-v", "uid",
- "-d", "*:v"},
- CommandOptions::WithTimeoutInMs(timeout_ms).Build());
+ RunCommand(
+ "EVENT LOG",
+ {"logcat", "-b", "events", "-v", "threadtime", "-v", "printable", "-v", "uid", "-d", "*:v"},
+ CommandOptions::WithTimeoutInMs(timeout_ms).Build());
timeout_ms = logcat_timeout("radio");
- if (timeout_ms < 20000) {
- timeout_ms = 20000;
+ if (timeout_ms < MINIMUM_LOGCAT_TIMEOUT_MS) {
+ timeout_ms = MINIMUM_LOGCAT_TIMEOUT_MS;
}
- RunCommand("RADIO LOG",
- {"logcat", "-b", "radio", "-v", "threadtime", "-v", "printable", "-v", "uid",
- "-d", "*:v"},
- CommandOptions::WithTimeoutInMs(timeout_ms).Build());
+ RunCommand(
+ "RADIO LOG",
+ {"logcat", "-b", "radio", "-v", "threadtime", "-v", "printable", "-v", "uid", "-d", "*:v"},
+ CommandOptions::WithTimeoutInMs(timeout_ms).Build());
RunCommand("LOG STATISTICS", {"logcat", "-b", "all", "-S"});
/* kernels must set CONFIG_PSTORE_PMSG, slice up pstore with device tree */
- RunCommand("LAST LOGCAT",
- {"logcat", "-L", "-b", "all", "-v", "threadtime", "-v", "printable", "-v", "uid",
- "-d", "*:v"});
+ RunCommand("LAST LOGCAT", {"logcat", "-L", "-b", "all", "-v", "threadtime", "-v", "printable",
+ "-v", "uid", "-d", "*:v"});
}
static void DumpIpTablesAsRoot() {
@@ -1091,6 +1103,57 @@
}
}
+static void DumpHals() {
+ using android::sp;
+ using android::hidl::manager::V1_0::IServiceManager;
+ using android::hardware::defaultServiceManager;
+
+ sp<IServiceManager> sm = defaultServiceManager();
+ if (sm == nullptr) {
+ MYLOGE("Could not retrieve hwservicemanager to dump hals.\n");
+ return;
+ }
+
+ auto ret = sm->list([&](const auto& interfaces) {
+ for (const std::string& interface : interfaces) {
+ std::string cleanName = interface;
+ std::replace_if(cleanName.begin(),
+ cleanName.end(),
+ [](char c) {
+ return !isalnum(c) &&
+ std::string("@-_:.").find(c) == std::string::npos;
+ }, '_');
+ const std::string path = kDumpstateBoardPath + "lshal_debug_" + cleanName;
+
+ {
+ auto fd = android::base::unique_fd(
+ TEMP_FAILURE_RETRY(open(path.c_str(),
+ O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW,
+ S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)));
+ if (fd < 0) {
+ MYLOGE("Could not open %s to dump additional hal information.\n", path.c_str());
+ continue;
+ }
+ RunCommandToFd(fd,
+ "",
+ {"lshal", "debug", interface},
+ CommandOptions::WithTimeout(2).AsRootIfAvailable().Build());
+
+ bool empty = 0 == lseek(fd, 0, SEEK_END);
+ if (!empty) {
+ ds.AddZipEntry("lshal-debug/" + cleanName + ".txt", path);
+ }
+ }
+
+ unlink(path.c_str());
+ }
+ });
+
+ if (!ret.isOk()) {
+ MYLOGE("Could not list hals from hwservicemanager.\n");
+ }
+}
+
static void dumpstate() {
DurationReporter duration_reporter("DUMPSTATE");
@@ -1119,18 +1182,10 @@
RunCommand("LIBRANK", {"librank"}, CommandOptions::AS_ROOT);
if (ds.IsZipping()) {
- RunCommand(
- "HARDWARE HALS",
- {"lshal", std::string("--debug=") + kLsHalDebugPath},
- CommandOptions::WithTimeout(10).AsRootIfAvailable().Build());
-
- ds.AddZipEntry("lshal-debug.txt", kLsHalDebugPath);
-
- unlink(kLsHalDebugPath.c_str());
+ RunCommand("HARDWARE HALS", {"lshal"}, CommandOptions::WithTimeout(2).AsRootIfAvailable().Build());
+ DumpHals();
} else {
- RunCommand(
- "HARDWARE HALS", {"lshal", "--debug"},
- CommandOptions::WithTimeout(10).AsRootIfAvailable().Build());
+ RunCommand("HARDWARE HALS", {"lshal", "--debug"}, CommandOptions::WithTimeout(10).AsRootIfAvailable().Build());
}
RunCommand("PRINTENV", {"printenv"});
@@ -1142,7 +1197,12 @@
RunCommand("LSMOD", {"lsmod"});
}
- do_dmesg();
+ if (__android_logger_property_get_bool(
+ "ro.logd.kernel", BOOL_DEFAULT_TRUE | BOOL_DEFAULT_FLAG_ENG | BOOL_DEFAULT_FLAG_SVELTE)) {
+ DoKernelLogcat();
+ } else {
+ do_dmesg();
+ }
RunCommand("LIST OF OPEN FILES", {"lsof"}, CommandOptions::AS_ROOT);
for_each_pid(do_showmap, "SMAPS OF ALL PROCESSES");
@@ -1191,19 +1251,6 @@
RunCommand("LAST RADIO LOG", {"parse_radio_log", "/proc/last_radio_log"});
- printf("------ BACKLIGHTS ------\n");
- printf("LCD brightness=");
- DumpFile("", "/sys/class/leds/lcd-backlight/brightness");
- printf("Button brightness=");
- DumpFile("", "/sys/class/leds/button-backlight/brightness");
- printf("Keyboard brightness=");
- DumpFile("", "/sys/class/leds/keyboard-backlight/brightness");
- printf("ALS mode=");
- DumpFile("", "/sys/class/leds/lcd-backlight/als");
- printf("LCD driver registers:\n");
- DumpFile("", "/sys/class/leds/lcd-backlight/registers");
- printf("\n");
-
/* Binder state is expensive to look at as it uses a lot of memory. */
DumpFile("BINDER FAILED TRANSACTION LOG", "/sys/kernel/debug/binder/failed_transaction_log");
DumpFile("BINDER TRANSACTION LOG", "/sys/kernel/debug/binder/transaction_log");
@@ -1556,7 +1603,8 @@
// clang-format on
}
-int main(int argc, char *argv[]) {
+/** Main entry point for dumpstate. */
+int run_main(int argc, char* argv[]) {
int do_add_date = 0;
int do_zip_file = 0;
int do_vibrate = 1;
@@ -1569,6 +1617,8 @@
bool show_header_only = false;
bool do_start_service = false;
bool telephony_only = false;
+ int dup_stdout_fd;
+ int dup_stderr_fd;
/* set as high priority, and protect from OOM killer */
setpriority(PRIO_PROCESS, 0, -20);
@@ -1840,11 +1890,13 @@
}
if (is_redirecting) {
+ TEMP_FAILURE_RETRY(dup_stderr_fd = dup(fileno(stderr)));
redirect_to_file(stderr, const_cast<char*>(ds.log_path_.c_str()));
if (chown(ds.log_path_.c_str(), AID_SHELL, AID_SHELL)) {
MYLOGE("Unable to change ownership of dumpstate log file %s: %s\n",
ds.log_path_.c_str(), strerror(errno));
}
+ TEMP_FAILURE_RETRY(dup_stdout_fd = dup(fileno(stdout)));
/* TODO: rather than generating a text file now and zipping it later,
it would be more efficient to redirect stdout to the zip entry
directly, but the libziparchive doesn't support that option yet. */
@@ -1918,7 +1970,7 @@
/* close output if needed */
if (is_redirecting) {
- fclose(stdout);
+ TEMP_FAILURE_RETRY(dup2(dup_stdout_fd, fileno(stdout)));
}
/* rename or zip the (now complete) .tmp file to its final location */
@@ -2049,7 +2101,7 @@
MYLOGI("done (id %d)\n", ds.id_);
if (is_redirecting) {
- fclose(stderr);
+ TEMP_FAILURE_RETRY(dup2(dup_stderr_fd, fileno(stderr)));
}
if (use_control_socket && ds.control_socket_fd_ != -1) {
diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h
index 8db23a9..843c545 100644
--- a/cmds/dumpstate/dumpstate.h
+++ b/cmds/dumpstate/dumpstate.h
@@ -341,9 +341,10 @@
// Pointer to the zip structure.
std::unique_ptr<ZipWriter> zip_writer_;
- // Binder object listing to progress.
+ // Binder object listening to progress.
android::sp<android::os::IDumpstateListener> listener_;
std::string listener_name_;
+ bool report_section_;
// Notification title and description
std::string notification_title;
@@ -433,6 +434,9 @@
/** Gets command-line arguments. */
void format_args(int argc, const char *argv[], std::string *args);
+/** Main entry point for dumpstate. */
+int run_main(int argc, char* argv[]);
+
#ifdef __cplusplus
}
#endif
diff --git a/cmds/dumpstate/main.cpp b/cmds/dumpstate/main.cpp
new file mode 100644
index 0000000..78aad11
--- /dev/null
+++ b/cmds/dumpstate/main.cpp
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "dumpstate.h"
+
+int main(int argc, char* argv[]) {
+ return run_main(argc, argv);
+}
diff --git a/cmds/dumpstate/tests/dumpstate_test.cpp b/cmds/dumpstate/tests/dumpstate_test.cpp
index a2e9453..838b385 100644
--- a/cmds/dumpstate/tests/dumpstate_test.cpp
+++ b/cmds/dumpstate/tests/dumpstate_test.cpp
@@ -58,6 +58,8 @@
public:
MOCK_METHOD1(onProgressUpdated, binder::Status(int32_t progress));
MOCK_METHOD1(onMaxProgressUpdated, binder::Status(int32_t max_progress));
+ MOCK_METHOD4(onSectionComplete, binder::Status(const ::std::string& name, int32_t status,
+ int32_t size, int32_t durationMs));
protected:
MOCK_METHOD0(onAsBinder, IBinder*());
@@ -601,27 +603,43 @@
TEST_F(DumpstateServiceTest, SetListenerNoName) {
sp<DumpstateListenerMock> listener(new DumpstateListenerMock());
sp<IDumpstateToken> token;
- EXPECT_TRUE(dss.setListener("", listener, &token).isOk());
+ EXPECT_TRUE(dss.setListener("", listener, /* getSectionDetails = */ false, &token).isOk());
ASSERT_THAT(token, IsNull());
}
TEST_F(DumpstateServiceTest, SetListenerNoPointer) {
sp<IDumpstateToken> token;
- EXPECT_TRUE(dss.setListener("whatever", nullptr, &token).isOk());
+ EXPECT_TRUE(
+ dss.setListener("whatever", nullptr, /* getSectionDetails = */ false, &token).isOk());
ASSERT_THAT(token, IsNull());
}
TEST_F(DumpstateServiceTest, SetListenerTwice) {
sp<DumpstateListenerMock> listener(new DumpstateListenerMock());
sp<IDumpstateToken> token;
- EXPECT_TRUE(dss.setListener("whatever", listener, &token).isOk());
+ EXPECT_TRUE(
+ dss.setListener("whatever", listener, /* getSectionDetails = */ false, &token).isOk());
ASSERT_THAT(token, NotNull());
EXPECT_THAT(Dumpstate::GetInstance().listener_name_, StrEq("whatever"));
+ EXPECT_FALSE(Dumpstate::GetInstance().report_section_);
token.clear();
- EXPECT_TRUE(dss.setListener("whatsoever", listener, &token).isOk());
+ EXPECT_TRUE(
+ dss.setListener("whatsoever", listener, /* getSectionDetails = */ false, &token).isOk());
ASSERT_THAT(token, IsNull());
EXPECT_THAT(Dumpstate::GetInstance().listener_name_, StrEq("whatever"));
+ EXPECT_FALSE(Dumpstate::GetInstance().report_section_);
+}
+
+TEST_F(DumpstateServiceTest, SetListenerWithSectionDetails) {
+ sp<DumpstateListenerMock> listener(new DumpstateListenerMock());
+ sp<IDumpstateToken> token;
+ Dumpstate::GetInstance().listener_ = nullptr;
+ EXPECT_TRUE(
+ dss.setListener("whatever", listener, /* getSectionDetails = */ true, &token).isOk());
+ ASSERT_THAT(token, NotNull());
+ EXPECT_THAT(Dumpstate::GetInstance().listener_name_, StrEq("whatever"));
+ EXPECT_TRUE(Dumpstate::GetInstance().report_section_);
}
class ProgressTest : public DumpstateBaseTest {
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index 715bf8c..6f8c841 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -37,6 +37,7 @@
#include <unistd.h>
#include <android-base/logging.h>
+#include <android-base/properties.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
#include <android-base/unique_fd.h>
@@ -71,6 +72,7 @@
static constexpr const char* kCpPath = "/system/bin/cp";
static constexpr const char* kXattrDefault = "user.default";
+static constexpr const char* kPropHasReserved = "vold.has_reserved";
static constexpr const int MIN_RESTRICTED_HOME_SDK_VERSION = 24; // > M
@@ -82,6 +84,8 @@
static constexpr const char* IDMAP_PREFIX = "/data/resource-cache/";
static constexpr const char* IDMAP_SUFFIX = "@idmap";
+static constexpr const char* kPropApkVerityMode = "ro.apk_verity.mode";
+
// NOTE: keep in sync with Installer
static constexpr int FLAG_CLEAR_CACHE_ONLY = 1 << 8;
static constexpr int FLAG_CLEAR_CODE_CACHE_ONLY = 1 << 9;
@@ -302,6 +306,9 @@
*/
static int prepare_app_quota(const std::unique_ptr<std::string>& uuid, const std::string& device,
uid_t uid) {
+ // Skip when reserved blocks are protecting us against abusive apps
+ if (android::base::GetBoolProperty(kPropHasReserved, false)) return 0;
+ // Skip when device no quotas present
if (device.empty()) return 0;
struct dqblk dq;
@@ -2351,6 +2358,17 @@
return res ? ok() : error();
}
+binder::Status InstalldNativeService::installApkVerity(const std::string& /*filePath*/,
+ const ::android::base::unique_fd& /*verityInput*/) {
+ ENFORCE_UID(AID_SYSTEM);
+ if (!android::base::GetBoolProperty(kPropApkVerityMode, false)) {
+ return ok();
+ }
+ // TODO: Append verity to filePath then issue ioctl to enable
+ // it and hide the tree. See b/30972906.
+ return error("not implemented yet");
+}
+
binder::Status InstalldNativeService::reconcileSecondaryDexFile(
const std::string& dexPath, const std::string& packageName, int32_t uid,
const std::vector<std::string>& isas, const std::unique_ptr<std::string>& volumeUuid,
@@ -2417,14 +2435,18 @@
mQuotaReverseMounts[target] = source;
// ext4 only enables DQUOT_USAGE_ENABLED by default, so we
- // need to kick it again to enable DQUOT_LIMITS_ENABLED.
- if (quotactl(QCMD(Q_QUOTAON, USRQUOTA), source.c_str(), QFMT_VFS_V1, nullptr) != 0
- && errno != EBUSY) {
- PLOG(ERROR) << "Failed to enable USRQUOTA on " << source;
- }
- if (quotactl(QCMD(Q_QUOTAON, GRPQUOTA), source.c_str(), QFMT_VFS_V1, nullptr) != 0
- && errno != EBUSY) {
- PLOG(ERROR) << "Failed to enable GRPQUOTA on " << source;
+ // need to kick it again to enable DQUOT_LIMITS_ENABLED. We
+ // only need hard limits enabled when we're not being protected
+ // by reserved blocks.
+ if (!android::base::GetBoolProperty(kPropHasReserved, false)) {
+ if (quotactl(QCMD(Q_QUOTAON, USRQUOTA), source.c_str(), QFMT_VFS_V1,
+ nullptr) != 0 && errno != EBUSY) {
+ PLOG(ERROR) << "Failed to enable USRQUOTA on " << source;
+ }
+ if (quotactl(QCMD(Q_QUOTAON, GRPQUOTA), source.c_str(), QFMT_VFS_V1,
+ nullptr) != 0 && errno != EBUSY) {
+ PLOG(ERROR) << "Failed to enable GRPQUOTA on " << source;
+ }
}
}
}
diff --git a/cmds/installd/InstalldNativeService.h b/cmds/installd/InstalldNativeService.h
index 57dd834..b494c7a 100644
--- a/cmds/installd/InstalldNativeService.h
+++ b/cmds/installd/InstalldNativeService.h
@@ -117,6 +117,8 @@
const std::string& outputPath);
binder::Status deleteOdex(const std::string& apkPath, const std::string& instructionSet,
const std::unique_ptr<std::string>& outputPath);
+ binder::Status installApkVerity(const std::string& filePath,
+ const ::android::base::unique_fd& verityInput);
binder::Status reconcileSecondaryDexFile(const std::string& dexPath,
const std::string& packageName, int32_t uid, const std::vector<std::string>& isa,
const std::unique_ptr<std::string>& volumeUuid, int32_t storage_flag, bool* _aidl_return);
diff --git a/cmds/installd/binder/android/os/IInstalld.aidl b/cmds/installd/binder/android/os/IInstalld.aidl
index 394c028..89585a0 100644
--- a/cmds/installd/binder/android/os/IInstalld.aidl
+++ b/cmds/installd/binder/android/os/IInstalld.aidl
@@ -81,6 +81,7 @@
@utf8InCpp String outputPath);
void deleteOdex(@utf8InCpp String apkPath, @utf8InCpp String instructionSet,
@nullable @utf8InCpp String outputPath);
+ void installApkVerity(@utf8InCpp String filePath, in FileDescriptor verityInput);
boolean reconcileSecondaryDexFile(@utf8InCpp String dexPath, @utf8InCpp String pkgName,
int uid, in @utf8InCpp String[] isas, @nullable @utf8InCpp String volume_uuid,
diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp
index fd4eef3..2e88e3c 100644
--- a/cmds/installd/dexopt.cpp
+++ b/cmds/installd/dexopt.cpp
@@ -66,6 +66,7 @@
static constexpr const char* kMinidebugInfoSystemProperty = "dalvik.vm.dex2oat-minidebuginfo";
static constexpr bool kMinidebugInfoSystemPropertyDefault = false;
static constexpr const char* kMinidebugDex2oatFlag = "--generate-mini-debug-info";
+static constexpr const char* kDisableCompactDexFlag = "--compact-dex-level=none";
// Deleter using free() for use with std::unique_ptr<>. See also UniqueCPtr<> below.
struct FreeDelete {
@@ -414,6 +415,12 @@
ALOGV("Running %s in=%s out=%s\n", dex2oat_bin, relative_input_file_name, output_file_name);
+ // Disable cdex if update input vdex is true since this combination of options is not
+ // supported.
+ // Disable cdex for non-background compiles since we don't want to regress app install until
+ // there are enough benefits to justify the tradeoff.
+ const bool disable_cdex = !background_job_compile || (input_vdex_fd == output_vdex_fd);
+
const char* argv[9 // program name, mandatory arguments and the final NULL
+ (have_dex2oat_isa_variant ? 1 : 0)
+ (have_dex2oat_isa_features ? 1 : 0)
@@ -432,6 +439,7 @@
+ (class_loader_context != nullptr ? 1 : 0)
+ (has_base_dir ? 1 : 0)
+ (have_dex2oat_large_app_threshold ? 1 : 0)
+ + (disable_cdex ? 1 : 0)
+ (generate_minidebug_info ? 1 : 0)];
int i = 0;
argv[i++] = dex2oat_bin;
@@ -499,6 +507,9 @@
if (generate_minidebug_info) {
argv[i++] = kMinidebugDex2oatFlag;
}
+ if (disable_cdex) {
+ argv[i++] = kDisableCompactDexFlag;
+ }
// Do not add after dex2oat_flags, they should override others for debugging.
argv[i] = NULL;
@@ -963,7 +974,7 @@
if (EndsWith(oat_path, ".dex")) {
std::string new_path = oat_path;
new_path.replace(new_path.length() - strlen(".dex"), strlen(".dex"), new_ext);
- CHECK(EndsWith(new_path, new_ext.c_str()));
+ CHECK(EndsWith(new_path, new_ext));
return new_path;
}
diff --git a/cmds/installd/otapreopt.cpp b/cmds/installd/otapreopt.cpp
index 0c2d341..d938d8a 100644
--- a/cmds/installd/otapreopt.cpp
+++ b/cmds/installd/otapreopt.cpp
@@ -882,7 +882,7 @@
// backs to do weird things.)
const char* apk_path = package_parameters_.apk_path;
CHECK(apk_path != nullptr);
- if (StartsWith(apk_path, android_root_.c_str())) {
+ if (StartsWith(apk_path, android_root_)) {
const char* last_slash = strrchr(apk_path, '/');
if (last_slash != nullptr) {
std::string path(apk_path, last_slash - apk_path + 1);
diff --git a/cmds/lshal/DebugCommand.cpp b/cmds/lshal/DebugCommand.cpp
index 622f866..f371320 100644
--- a/cmds/lshal/DebugCommand.cpp
+++ b/cmds/lshal/DebugCommand.cpp
@@ -18,6 +18,8 @@
#include "Lshal.h"
+#include <hidl-util/FQName.h>
+
namespace android {
namespace lshal {
@@ -46,7 +48,15 @@
if (status != OK) {
return status;
}
+
auto pair = splitFirst(mInterfaceName, '/');
+
+ FQName fqName(pair.first);
+ if (!fqName.isValid() || fqName.isIdentifier() || !fqName.isFullyQualified()) {
+ mLshal.err() << "Invalid fully-qualified name '" << pair.first << "'\n\n";
+ return USAGE;
+ }
+
return mLshal.emitDebugInfo(
pair.first, pair.second.empty() ? "default" : pair.second, mOptions,
mLshal.out().buf(),
diff --git a/data/etc/android.hardware.telephony.mbms.xml b/data/etc/android.hardware.telephony.mbms.xml
new file mode 100644
index 0000000..271ea58
--- /dev/null
+++ b/data/etc/android.hardware.telephony.mbms.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<!-- Feature for devices that support MBMS. -->
+<permissions>
+ <feature name="android.hardware.telephony.mbms" />
+</permissions>
diff --git a/data/etc/handheld_core_hardware.xml b/data/etc/handheld_core_hardware.xml
index b6abc1b..d790bed 100644
--- a/data/etc/handheld_core_hardware.xml
+++ b/data/etc/handheld_core_hardware.xml
@@ -46,7 +46,7 @@
<feature name="android.software.home_screen" />
<feature name="android.software.input_methods" />
<feature name="android.software.picture_in_picture" notLowRam="true" />
- <feature name="android.software.activities_on_secondary_displays" />
+ <feature name="android.software.activities_on_secondary_displays" notLowRam="true" />
<feature name="android.software.print" />
<feature name="android.software.companion_device_setup" />
<feature name="android.software.autofill" />
diff --git a/libs/binder/ActivityManager.cpp b/libs/binder/ActivityManager.cpp
new file mode 100644
index 0000000..2904718
--- /dev/null
+++ b/libs/binder/ActivityManager.cpp
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <mutex>
+#include <binder/ActivityManager.h>
+#include <binder/Binder.h>
+#include <binder/IServiceManager.h>
+
+#include <utils/SystemClock.h>
+
+namespace android {
+
+ActivityManager::ActivityManager()
+{
+}
+
+sp<IActivityManager> ActivityManager::getService()
+{
+ std::lock_guard<Mutex> scoped_lock(mLock);
+ int64_t startTime = 0;
+ sp<IActivityManager> service = mService;
+ while (service == NULL || !IInterface::asBinder(service)->isBinderAlive()) {
+ sp<IBinder> binder = defaultServiceManager()->checkService(String16("activity"));
+ if (binder == NULL) {
+ // Wait for the activity service to come back...
+ if (startTime == 0) {
+ startTime = uptimeMillis();
+ ALOGI("Waiting for activity service");
+ } else if ((uptimeMillis() - startTime) > 10000) {
+ ALOGW("Waiting too long for activity service, giving up");
+ service = NULL;
+ break;
+ }
+ sleep(1);
+ } else {
+ service = interface_cast<IActivityManager>(binder);
+ mService = service;
+ }
+ }
+ return service;
+}
+
+int ActivityManager::openContentUri(const String16& stringUri)
+{
+ sp<IActivityManager> service = getService();
+ return service != NULL ? service->openContentUri(stringUri) : -1;
+}
+
+void ActivityManager::registerUidObserver(const sp<IUidObserver>& observer,
+ const int32_t event,
+ const int32_t cutpoint,
+ const String16& callingPackage)
+{
+ sp<IActivityManager> service = getService();
+ if (service != NULL) {
+ service->registerUidObserver(observer, event, cutpoint, callingPackage);
+ }
+}
+
+void ActivityManager::unregisterUidObserver(const sp<IUidObserver>& observer)
+{
+ sp<IActivityManager> service = getService();
+ if (service != NULL) {
+ service->unregisterUidObserver(observer);
+ }
+}
+
+}; // namespace android
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
index c130087..2a07cd1 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -38,6 +38,7 @@
},
srcs: [
+ "ActivityManager.cpp",
"AppOpsManager.cpp",
"Binder.cpp",
"BpBinder.cpp",
@@ -56,6 +57,7 @@
"IResultReceiver.cpp",
"IServiceManager.cpp",
"IShellCallback.cpp",
+ "IUidObserver.cpp",
"MemoryBase.cpp",
"MemoryDealer.cpp",
"MemoryHeapBase.cpp",
diff --git a/libs/binder/IActivityManager.cpp b/libs/binder/IActivityManager.cpp
index 50a8b28..b7a5fd9 100644
--- a/libs/binder/IActivityManager.cpp
+++ b/libs/binder/IActivityManager.cpp
@@ -56,6 +56,28 @@
}
return fd;
}
+
+ virtual void registerUidObserver(const sp<IUidObserver>& observer,
+ const int32_t event,
+ const int32_t cutpoint,
+ const String16& callingPackage)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IActivityManager::getInterfaceDescriptor());
+ data.writeStrongBinder(IInterface::asBinder(observer));
+ data.writeInt32(event);
+ data.writeInt32(cutpoint);
+ data.writeString16(callingPackage);
+ remote()->transact(REGISTER_UID_OBSERVER_TRANSACTION, data, &reply);
+ }
+
+ virtual void unregisterUidObserver(const sp<IUidObserver>& observer)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IActivityManager::getInterfaceDescriptor());
+ data.writeStrongBinder(IInterface::asBinder(observer));
+ remote()->transact(UNREGISTER_UID_OBSERVER_TRANSACTION, data, &reply);
+ }
};
// ------------------------------------------------------------------------------------
diff --git a/libs/binder/IUidObserver.cpp b/libs/binder/IUidObserver.cpp
new file mode 100644
index 0000000..697e948
--- /dev/null
+++ b/libs/binder/IUidObserver.cpp
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <binder/IUidObserver.h>
+
+#include <binder/Parcel.h>
+
+namespace android {
+
+// ------------------------------------------------------------------------------------
+
+class BpUidObserver : public BpInterface<IUidObserver>
+{
+public:
+ explicit BpUidObserver(const sp<IBinder>& impl)
+ : BpInterface<IUidObserver>(impl)
+ {
+ }
+
+ virtual void onUidGone(uid_t uid, bool disabled)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IUidObserver::getInterfaceDescriptor());
+ data.writeInt32((int32_t) uid);
+ data.writeInt32(disabled ? 1 : 0);
+ remote()->transact(ON_UID_GONE_TRANSACTION, data, &reply, IBinder::FLAG_ONEWAY);
+ }
+
+ virtual void onUidActive(uid_t uid)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IUidObserver::getInterfaceDescriptor());
+ data.writeInt32((int32_t) uid);
+ remote()->transact(ON_UID_ACTIVE_TRANSACTION, data, &reply, IBinder::FLAG_ONEWAY);
+ }
+
+ virtual void onUidIdle(uid_t uid, bool disabled)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IUidObserver::getInterfaceDescriptor());
+ data.writeInt32((int32_t) uid);
+ data.writeInt32(disabled ? 1 : 0);
+ remote()->transact(ON_UID_IDLE_TRANSACTION, data, &reply, IBinder::FLAG_ONEWAY);
+ }
+};
+
+// ----------------------------------------------------------------------
+
+IMPLEMENT_META_INTERFACE(UidObserver, "android.app.IUidObserver");
+
+// ----------------------------------------------------------------------
+
+status_t BnUidObserver::onTransact(
+ uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+ switch(code) {
+ case ON_UID_GONE_TRANSACTION: {
+ CHECK_INTERFACE(IUidObserver, data, reply);
+ uid_t uid = data.readInt32();
+ bool disabled = data.readInt32() == 1;
+ onUidGone(uid, disabled);
+ return NO_ERROR;
+ } break;
+
+ case ON_UID_ACTIVE_TRANSACTION: {
+ CHECK_INTERFACE(IUidObserver, data, reply);
+ uid_t uid = data.readInt32();
+ onUidActive(uid);
+ return NO_ERROR;
+ } break;
+
+ case ON_UID_IDLE_TRANSACTION: {
+ CHECK_INTERFACE(IUidObserver, data, reply);
+ uid_t uid = data.readInt32();
+ bool disabled = data.readInt32() == 1;
+ onUidIdle(uid, disabled);
+ return NO_ERROR;
+ } break;
+ default:
+ return BBinder::onTransact(code, data, reply, flags);
+ }
+}
+
+}; // namespace android
diff --git a/libs/binder/include/binder/ActivityManager.h b/libs/binder/include/binder/ActivityManager.h
new file mode 100644
index 0000000..408c428
--- /dev/null
+++ b/libs/binder/include/binder/ActivityManager.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_ACTIVITY_MANAGER_H
+#define ANDROID_ACTIVITY_MANAGER_H
+
+#include <binder/IActivityManager.h>
+
+#include <utils/threads.h>
+
+// ---------------------------------------------------------------------------
+namespace android {
+
+class ActivityManager
+{
+public:
+
+ enum {
+ // Flag for registerUidObserver: report uid gone
+ UID_OBSERVER_GONE = 1<<1,
+ // Flag for registerUidObserver: report uid has become idle
+ UID_OBSERVER_IDLE = 1<<2,
+ // Flag for registerUidObserver: report uid has become active
+ UID_OBSERVER_ACTIVE = 1<<3
+ };
+
+ enum {
+ // Not a real process state
+ PROCESS_STATE_UNKNOWN = -1
+ };
+
+ ActivityManager();
+
+ int openContentUri(const String16& stringUri);
+ void registerUidObserver(const sp<IUidObserver>& observer,
+ const int32_t event,
+ const int32_t cutpoint,
+ const String16& callingPackage);
+ void unregisterUidObserver(const sp<IUidObserver>& observer);
+
+private:
+ Mutex mLock;
+ sp<IActivityManager> mService;
+ sp<IActivityManager> getService();
+};
+
+
+}; // namespace android
+// ---------------------------------------------------------------------------
+#endif // ANDROID_ACTIVITY_MANAGER_H
diff --git a/libs/binder/include/binder/IActivityManager.h b/libs/binder/include/binder/IActivityManager.h
index 5ad2180..bac2a99 100644
--- a/libs/binder/include/binder/IActivityManager.h
+++ b/libs/binder/include/binder/IActivityManager.h
@@ -18,6 +18,7 @@
#define ANDROID_IACTIVITY_MANAGER_H
#include <binder/IInterface.h>
+#include <binder/IUidObserver.h>
namespace android {
@@ -28,10 +29,17 @@
public:
DECLARE_META_INTERFACE(ActivityManager)
- virtual int openContentUri(const String16& /* stringUri */) = 0;
+ virtual int openContentUri(const String16& stringUri) = 0;
+ virtual void registerUidObserver(const sp<IUidObserver>& observer,
+ const int32_t event,
+ const int32_t cutpoint,
+ const String16& callingPackage) = 0;
+ virtual void unregisterUidObserver(const sp<IUidObserver>& observer) = 0;
enum {
- OPEN_CONTENT_URI_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION
+ OPEN_CONTENT_URI_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION,
+ REGISTER_UID_OBSERVER_TRANSACTION,
+ UNREGISTER_UID_OBSERVER_TRANSACTION
};
};
@@ -39,4 +47,4 @@
}; // namespace android
-#endif // ANDROID_IACTIVITY_MANAGER_H
\ No newline at end of file
+#endif // ANDROID_IACTIVITY_MANAGER_H
diff --git a/libs/binder/include/binder/IUidObserver.h b/libs/binder/include/binder/IUidObserver.h
new file mode 100644
index 0000000..fd4d8a6
--- /dev/null
+++ b/libs/binder/include/binder/IUidObserver.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//
+#ifndef ANDROID_IUID_OBSERVER_H
+#define ANDROID_IUID_OBSERVER_H
+
+#include <binder/IInterface.h>
+
+namespace android {
+
+// ----------------------------------------------------------------------
+
+class IUidObserver : public IInterface
+{
+public:
+ DECLARE_META_INTERFACE(UidObserver)
+
+ virtual void onUidGone(uid_t uid, bool disabled) = 0;
+ virtual void onUidActive(uid_t uid) = 0;
+ virtual void onUidIdle(uid_t uid, bool disabled) = 0;
+
+ enum {
+ ON_UID_GONE_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION,
+ ON_UID_ACTIVE_TRANSACTION,
+ ON_UID_IDLE_TRANSACTION
+ };
+};
+
+// ----------------------------------------------------------------------
+
+class BnUidObserver : public BnInterface<IUidObserver>
+{
+public:
+ virtual status_t onTransact(uint32_t code,
+ const Parcel& data,
+ Parcel* reply,
+ uint32_t flags = 0);
+};
+
+// ----------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_IUID_OBSERVER_H
diff --git a/libs/graphicsenv/Android.bp b/libs/graphicsenv/Android.bp
index 9f99538..4da30e9 100644
--- a/libs/graphicsenv/Android.bp
+++ b/libs/graphicsenv/Android.bp
@@ -22,7 +22,6 @@
cflags: ["-Wall", "-Werror"],
shared_libs: [
- "libnativeloader",
"liblog",
],
diff --git a/libs/graphicsenv/GraphicsEnv.cpp b/libs/graphicsenv/GraphicsEnv.cpp
index f46e9f6..961f101 100644
--- a/libs/graphicsenv/GraphicsEnv.cpp
+++ b/libs/graphicsenv/GraphicsEnv.cpp
@@ -20,13 +20,23 @@
#include <mutex>
+#include <android/dlext.h>
#include <log/log.h>
-#include <nativeloader/dlext_namespaces.h>
-#include <nativeloader/native_loader.h>
// TODO(b/37049319) Get this from a header once one exists
extern "C" {
android_namespace_t* android_get_exported_namespace(const char*);
+ android_namespace_t* android_create_namespace(const char* name,
+ const char* ld_library_path,
+ const char* default_library_path,
+ uint64_t type,
+ const char* permitted_when_isolated_path,
+ android_namespace_t* parent);
+
+ enum {
+ ANDROID_NAMESPACE_TYPE_ISOLATED = 1,
+ ANDROID_NAMESPACE_TYPE_SHARED = 2,
+ };
}
namespace android {
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp
index c713e9e..7ee4d49 100644
--- a/libs/gui/Android.bp
+++ b/libs/gui/Android.bp
@@ -92,6 +92,7 @@
"FrameTimestamps.cpp",
"GLConsumer.cpp",
"GuiConfig.cpp",
+ "HdrMetadata.cpp",
"IDisplayEventConnection.cpp",
"IConsumerListener.cpp",
"IGraphicBufferConsumer.cpp",
diff --git a/libs/gui/BufferItem.cpp b/libs/gui/BufferItem.cpp
index 69b5962..f7409dc 100644
--- a/libs/gui/BufferItem.cpp
+++ b/libs/gui/BufferItem.cpp
@@ -98,6 +98,7 @@
size = FlattenableUtils::align<4>(size);
}
size += mSurfaceDamage.getFlattenedSize();
+ size += mHdrMetadata.getFlattenedSize();
size = FlattenableUtils::align<8>(size);
return size + getPodSize();
}
@@ -151,6 +152,10 @@
if (err) return err;
FlattenableUtils::advance(buffer, size, mSurfaceDamage.getFlattenedSize());
+ err = mHdrMetadata.flatten(buffer, size);
+ if (err) return err;
+ FlattenableUtils::advance(buffer, size, mHdrMetadata.getFlattenedSize());
+
// Check we still have enough space
if (size < getPodSize()) {
return NO_MEMORY;
@@ -212,6 +217,10 @@
if (err) return err;
FlattenableUtils::advance(buffer, size, mSurfaceDamage.getFlattenedSize());
+ err = mHdrMetadata.unflatten(buffer, size);
+ if (err) return err;
+ FlattenableUtils::advance(buffer, size, mHdrMetadata.getFlattenedSize());
+
// Check we still have enough space
if (size < getPodSize()) {
return NO_MEMORY;
diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp
index c5cab2d..add857c 100644
--- a/libs/gui/BufferQueueProducer.cpp
+++ b/libs/gui/BufferQueueProducer.cpp
@@ -765,6 +765,7 @@
&crop, &scalingMode, &transform, &acquireFence, &stickyTransform,
&getFrameTimestamps);
const Region& surfaceDamage = input.getSurfaceDamage();
+ const HdrMetadata& hdrMetadata = input.getHdrMetadata();
if (acquireFence == NULL) {
BQ_LOGE("queueBuffer: fence is NULL");
@@ -825,9 +826,9 @@
}
BQ_LOGV("queueBuffer: slot=%d/%" PRIu64 " time=%" PRIu64 " dataSpace=%d"
- " crop=[%d,%d,%d,%d] transform=%#x scale=%s",
- slot, mCore->mFrameCounter + 1, requestedPresentTimestamp,
- dataSpace, crop.left, crop.top, crop.right, crop.bottom,
+ " validHdrMetadataTypes=0x%x crop=[%d,%d,%d,%d] transform=%#x scale=%s",
+ slot, mCore->mFrameCounter + 1, requestedPresentTimestamp, dataSpace,
+ hdrMetadata.validTypes, crop.left, crop.top, crop.right, crop.bottom,
transform,
BufferItem::scalingModeName(static_cast<uint32_t>(scalingMode)));
@@ -866,6 +867,7 @@
item.mTimestamp = requestedPresentTimestamp;
item.mIsAutoTimestamp = isAutoTimestamp;
item.mDataSpace = dataSpace;
+ item.mHdrMetadata = hdrMetadata;
item.mFrameNumber = currentFrameNumber;
item.mSlot = slot;
item.mFence = acquireFence;
diff --git a/libs/gui/HdrMetadata.cpp b/libs/gui/HdrMetadata.cpp
new file mode 100644
index 0000000..299bdfa
--- /dev/null
+++ b/libs/gui/HdrMetadata.cpp
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gui/HdrMetadata.h>
+
+namespace android {
+
+size_t HdrMetadata::getFlattenedSize() const {
+ size_t size = sizeof(validTypes);
+ if (validTypes & SMPTE2086) {
+ size += sizeof(smpte2086);
+ }
+ if (validTypes & CTA861_3) {
+ size += sizeof(cta8613);
+ }
+ return size;
+}
+
+status_t HdrMetadata::flatten(void* buffer, size_t size) const {
+ if (size < getFlattenedSize()) {
+ return NO_MEMORY;
+ }
+
+ FlattenableUtils::write(buffer, size, validTypes);
+ if (validTypes & SMPTE2086) {
+ FlattenableUtils::write(buffer, size, smpte2086);
+ }
+ if (validTypes & CTA861_3) {
+ FlattenableUtils::write(buffer, size, cta8613);
+ }
+
+ return NO_ERROR;
+}
+
+status_t HdrMetadata::unflatten(void const* buffer, size_t size) {
+ if (size < sizeof(validTypes)) {
+ return NO_MEMORY;
+ }
+ FlattenableUtils::read(buffer, size, validTypes);
+ if (validTypes & SMPTE2086) {
+ if (size < sizeof(smpte2086)) {
+ return NO_MEMORY;
+ }
+ FlattenableUtils::read(buffer, size, smpte2086);
+ }
+ if (validTypes & CTA861_3) {
+ if (size < sizeof(cta8613)) {
+ return NO_MEMORY;
+ }
+ FlattenableUtils::read(buffer, size, cta8613);
+ }
+
+ return NO_ERROR;
+}
+
+} // namespace android
diff --git a/libs/gui/IGraphicBufferProducer.cpp b/libs/gui/IGraphicBufferProducer.cpp
index 71e22ce..7e49024 100644
--- a/libs/gui/IGraphicBufferProducer.cpp
+++ b/libs/gui/IGraphicBufferProducer.cpp
@@ -951,7 +951,8 @@
size_t IGraphicBufferProducer::QueueBufferInput::getFlattenedSize() const {
return minFlattenedSize() +
fence->getFlattenedSize() +
- surfaceDamage.getFlattenedSize();
+ surfaceDamage.getFlattenedSize() +
+ hdrMetadata.getFlattenedSize();
}
size_t IGraphicBufferProducer::QueueBufferInput::getFdCount() const {
@@ -978,7 +979,12 @@
if (result != NO_ERROR) {
return result;
}
- return surfaceDamage.flatten(buffer, size);
+ result = surfaceDamage.flatten(buffer, size);
+ if (result != NO_ERROR) {
+ return result;
+ }
+ FlattenableUtils::advance(buffer, size, surfaceDamage.getFlattenedSize());
+ return hdrMetadata.flatten(buffer, size);
}
status_t IGraphicBufferProducer::QueueBufferInput::unflatten(
@@ -1002,7 +1008,12 @@
if (result != NO_ERROR) {
return result;
}
- return surfaceDamage.unflatten(buffer, size);
+ result = surfaceDamage.unflatten(buffer, size);
+ if (result != NO_ERROR) {
+ return result;
+ }
+ FlattenableUtils::advance(buffer, size, surfaceDamage.getFlattenedSize());
+ return hdrMetadata.unflatten(buffer, size);
}
// ----------------------------------------------------------------------------
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index 80216bc..a4aec6e 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -667,6 +667,9 @@
mDataSpace, crop, mScalingMode, mTransform ^ mStickyTransform,
fence, mStickyTransform, mEnableFrameTimestamps);
+ // we should send HDR metadata as needed if this becomes a bottleneck
+ input.setHdrMetadata(mHdrMetadata);
+
if (mConnectedToCpu || mDirtyRegion.bounds() == Rect::INVALID_RECT) {
input.setSurfaceDamage(Region::INVALID_REGION);
} else {
@@ -944,6 +947,12 @@
case NATIVE_WINDOW_SET_BUFFERS_DATASPACE:
res = dispatchSetBuffersDataSpace(args);
break;
+ case NATIVE_WINDOW_SET_BUFFERS_SMPTE2086_METADATA:
+ res = dispatchSetBuffersSmpte2086Metadata(args);
+ break;
+ case NATIVE_WINDOW_SET_BUFFERS_CTA861_3_METADATA:
+ res = dispatchSetBuffersCta8613Metadata(args);
+ break;
case NATIVE_WINDOW_SET_SURFACE_DAMAGE:
res = dispatchSetSurfaceDamage(args);
break;
@@ -1088,6 +1097,18 @@
return setBuffersDataSpace(dataspace);
}
+int Surface::dispatchSetBuffersSmpte2086Metadata(va_list args) {
+ const android_smpte2086_metadata* metadata =
+ va_arg(args, const android_smpte2086_metadata*);
+ return setBuffersSmpte2086Metadata(metadata);
+}
+
+int Surface::dispatchSetBuffersCta8613Metadata(va_list args) {
+ const android_cta861_3_metadata* metadata =
+ va_arg(args, const android_cta861_3_metadata*);
+ return setBuffersCta8613Metadata(metadata);
+}
+
int Surface::dispatchSetSurfaceDamage(va_list args) {
android_native_rect_t* rects = va_arg(args, android_native_rect_t*);
size_t numRects = va_arg(args, size_t);
@@ -1512,6 +1533,30 @@
return NO_ERROR;
}
+int Surface::setBuffersSmpte2086Metadata(const android_smpte2086_metadata* metadata) {
+ ALOGV("Surface::setBuffersSmpte2086Metadata");
+ Mutex::Autolock lock(mMutex);
+ if (metadata) {
+ mHdrMetadata.smpte2086 = *metadata;
+ mHdrMetadata.validTypes |= HdrMetadata::SMPTE2086;
+ } else {
+ mHdrMetadata.validTypes &= ~HdrMetadata::SMPTE2086;
+ }
+ return NO_ERROR;
+}
+
+int Surface::setBuffersCta8613Metadata(const android_cta861_3_metadata* metadata) {
+ ALOGV("Surface::setBuffersCta8613Metadata");
+ Mutex::Autolock lock(mMutex);
+ if (metadata) {
+ mHdrMetadata.cta8613 = *metadata;
+ mHdrMetadata.validTypes |= HdrMetadata::CTA861_3;
+ } else {
+ mHdrMetadata.validTypes &= ~HdrMetadata::CTA861_3;
+ }
+ return NO_ERROR;
+}
+
android_dataspace_t Surface::getBuffersDataSpace() {
ALOGV("Surface::getBuffersDataSpace");
Mutex::Autolock lock(mMutex);
diff --git a/libs/gui/include/gui/BufferItem.h b/libs/gui/include/gui/BufferItem.h
index 55637a9..7740b9f 100644
--- a/libs/gui/include/gui/BufferItem.h
+++ b/libs/gui/include/gui/BufferItem.h
@@ -17,6 +17,8 @@
#ifndef ANDROID_GUI_BUFFERITEM_H
#define ANDROID_GUI_BUFFERITEM_H
+#include <gui/HdrMetadata.h>
+
#include <ui/FenceTime.h>
#include <ui/Rect.h>
#include <ui/Region.h>
@@ -86,6 +88,9 @@
// dataSpace is format-dependent.
android_dataspace mDataSpace;
+ // mHdrMetadata is the HDR metadata associated with this buffer slot.
+ HdrMetadata mHdrMetadata;
+
// mFrameNumber is the number of the queued frame for this slot.
uint64_t mFrameNumber;
diff --git a/libs/gui/include/gui/HdrMetadata.h b/libs/gui/include/gui/HdrMetadata.h
new file mode 100644
index 0000000..cd01952
--- /dev/null
+++ b/libs/gui/include/gui/HdrMetadata.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <stdint.h>
+
+#include <system/graphics.h>
+#include <utils/Flattenable.h>
+
+namespace android {
+
+struct HdrMetadata : public LightFlattenable<HdrMetadata> {
+ enum Type : uint32_t {
+ SMPTE2086 = 1 << 0,
+ CTA861_3 = 1 << 1,
+ };
+ uint32_t validTypes{0};
+
+ android_smpte2086_metadata smpte2086{};
+ android_cta861_3_metadata cta8613{};
+
+ // LightFlattenable
+ bool isFixedSize() const { return false; }
+ size_t getFlattenedSize() const;
+ status_t flatten(void* buffer, size_t size) const;
+ status_t unflatten(void const* buffer, size_t size);
+};
+
+} // namespace android
diff --git a/libs/gui/include/gui/IGraphicBufferProducer.h b/libs/gui/include/gui/IGraphicBufferProducer.h
index 039dc0d..722833e 100644
--- a/libs/gui/include/gui/IGraphicBufferProducer.h
+++ b/libs/gui/include/gui/IGraphicBufferProducer.h
@@ -31,6 +31,7 @@
#include <ui/Region.h>
#include <gui/FrameTimestamps.h>
+#include <gui/HdrMetadata.h>
#include <hidl/HybridInterface.h>
#include <android/hardware/graphics/bufferqueue/1.0/IGraphicBufferProducer.h>
@@ -354,6 +355,9 @@
const Region& getSurfaceDamage() const { return surfaceDamage; }
void setSurfaceDamage(const Region& damage) { surfaceDamage = damage; }
+ const HdrMetadata& getHdrMetadata() const { return hdrMetadata; }
+ void setHdrMetadata(const HdrMetadata& metadata) { hdrMetadata = metadata; }
+
private:
int64_t timestamp{0};
int isAutoTimestamp{0};
@@ -365,6 +369,7 @@
sp<Fence> fence;
Region surfaceDamage;
bool getFrameTimestamps{false};
+ HdrMetadata hdrMetadata;
};
struct QueueBufferOutput : public Flattenable<QueueBufferOutput> {
diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h
index 354f23a..641d62c 100644
--- a/libs/gui/include/gui/Surface.h
+++ b/libs/gui/include/gui/Surface.h
@@ -17,8 +17,9 @@
#ifndef ANDROID_GUI_SURFACE_H
#define ANDROID_GUI_SURFACE_H
-#include <gui/IGraphicBufferProducer.h>
#include <gui/BufferQueueDefs.h>
+#include <gui/HdrMetadata.h>
+#include <gui/IGraphicBufferProducer.h>
#include <ui/ANativeObjectBase.h>
#include <ui/Region.h>
@@ -214,6 +215,8 @@
int dispatchUnlockAndPost(va_list args);
int dispatchSetSidebandStream(va_list args);
int dispatchSetBuffersDataSpace(va_list args);
+ int dispatchSetBuffersSmpte2086Metadata(va_list args);
+ int dispatchSetBuffersCta8613Metadata(va_list args);
int dispatchSetSurfaceDamage(va_list args);
int dispatchSetSharedBufferMode(va_list args);
int dispatchSetAutoRefresh(va_list args);
@@ -243,6 +246,8 @@
virtual int setBuffersStickyTransform(uint32_t transform);
virtual int setBuffersTimestamp(int64_t timestamp);
virtual int setBuffersDataSpace(android_dataspace dataSpace);
+ virtual int setBuffersSmpte2086Metadata(const android_smpte2086_metadata* metadata);
+ virtual int setBuffersCta8613Metadata(const android_cta861_3_metadata* metadata);
virtual int setCrop(Rect const* rect);
virtual int setUsage(uint64_t reqUsage);
virtual void setSurfaceDamage(android_native_rect_t* rects, size_t numRects);
@@ -339,6 +344,10 @@
// means that the buffer contains some type of color data.
android_dataspace mDataSpace;
+ // mHdrMetadata is the HDR metadata that will be used for the next buffer
+ // queue operation. There is no HDR metadata by default.
+ HdrMetadata mHdrMetadata;
+
// mCrop is the crop rectangle that will be used for the next buffer
// that gets queued. It is set by calling setCrop.
Rect mCrop;
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index 470a338..cd29d4a 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -47,6 +47,9 @@
static bool hasWideColorDisplay =
getBool<ISurfaceFlingerConfigs, &ISurfaceFlingerConfigs::hasWideColorDisplay>(false);
+static bool hasHdrDisplay =
+ getBool<ISurfaceFlingerConfigs, &ISurfaceFlingerConfigs::hasHDRDisplay>(false);
+
class FakeSurfaceComposer;
class FakeProducerFrameEventHistory;
@@ -294,6 +297,68 @@
ASSERT_EQ(hasWideColorDisplay, supported);
}
+TEST_F(SurfaceTest, GetHdrSupport) {
+ sp<IGraphicBufferProducer> producer;
+ sp<IGraphicBufferConsumer> consumer;
+ BufferQueue::createBufferQueue(&producer, &consumer);
+
+ sp<DummyConsumer> dummyConsumer(new DummyConsumer);
+ consumer->consumerConnect(dummyConsumer, false);
+ consumer->setConsumerName(String8("TestConsumer"));
+
+ sp<Surface> surface = new Surface(producer);
+ sp<ANativeWindow> window(surface);
+ native_window_api_connect(window.get(), NATIVE_WINDOW_API_CPU);
+
+ bool supported;
+ status_t result = surface->getHdrSupport(&supported);
+ ASSERT_EQ(NO_ERROR, result);
+
+ // NOTE: This is not a CTS test.
+ // This test verifies that when the BoardConfig TARGET_HAS_HDR_DISPLAY
+ // is TRUE, getHdrSupport is also true.
+ // TODO: Add check for an HDR color mode on the primary display.
+ ASSERT_EQ(hasHdrDisplay, supported);
+}
+
+TEST_F(SurfaceTest, SetHdrMetadata) {
+ sp<IGraphicBufferProducer> producer;
+ sp<IGraphicBufferConsumer> consumer;
+ BufferQueue::createBufferQueue(&producer, &consumer);
+
+ sp<DummyConsumer> dummyConsumer(new DummyConsumer);
+ consumer->consumerConnect(dummyConsumer, false);
+ consumer->setConsumerName(String8("TestConsumer"));
+
+ sp<Surface> surface = new Surface(producer);
+ sp<ANativeWindow> window(surface);
+ native_window_api_connect(window.get(), NATIVE_WINDOW_API_CPU);
+
+ bool supported;
+ status_t result = surface->getHdrSupport(&supported);
+ ASSERT_EQ(NO_ERROR, result);
+
+ if (!hasHdrDisplay || !supported) {
+ return;
+ }
+ const android_smpte2086_metadata smpte2086 = {
+ {0.680, 0.320},
+ {0.265, 0.690},
+ {0.150, 0.060},
+ {0.3127, 0.3290},
+ 100.0,
+ 0.1,
+ };
+ const android_cta861_3_metadata cta861_3 = {
+ 78.0,
+ 62.0,
+ };
+ int error = native_window_set_buffers_smpte2086_metadata(window.get(), &smpte2086);
+ ASSERT_EQ(error, NO_ERROR);
+ error = native_window_set_buffers_cta861_3_metadata(window.get(), &cta861_3);
+ ASSERT_EQ(error, NO_ERROR);
+}
+
TEST_F(SurfaceTest, DynamicSetBufferCount) {
sp<IGraphicBufferProducer> producer;
sp<IGraphicBufferConsumer> consumer;
diff --git a/libs/input/VelocityTracker.cpp b/libs/input/VelocityTracker.cpp
index e54f147..57eee12 100644
--- a/libs/input/VelocityTracker.cpp
+++ b/libs/input/VelocityTracker.cpp
@@ -107,7 +107,7 @@
// this is the strategy that applications will actually use. Be very careful
// when adjusting the default strategy because it can dramatically affect
// (often in a bad way) the user experience.
-const char* VelocityTracker::DEFAULT_STRATEGY = "lsq2";
+const char* VelocityTracker::DEFAULT_STRATEGY = "impulse";
VelocityTracker::VelocityTracker(const char* strategy) :
mLastEventTime(0), mCurrentPointerIdBits(0), mActivePointerId(-1) {
diff --git a/libs/math/tests/mat_test.cpp b/libs/math/tests/mat_test.cpp
index 3217a1a..a14c7ea 100644
--- a/libs/math/tests/mat_test.cpp
+++ b/libs/math/tests/mat_test.cpp
@@ -35,7 +35,7 @@
TEST_F(MatTest, Basics) {
mat4 m0;
- EXPECT_EQ(sizeof(mat4), sizeof(float)*16);
+ EXPECT_EQ(sizeof(m0), sizeof(float)*16);
}
TEST_F(MatTest, ComparisonOps) {
@@ -76,6 +76,7 @@
EXPECT_EQ(m3, m1);
mat4 m4(vec4(1), vec4(2), vec4(3), vec4(4));
+ EXPECT_NE(m4, m1);
}
TEST_F(MatTest, ArithmeticOps) {
@@ -172,7 +173,7 @@
TEST_F(Mat3Test, Basics) {
mat3 m0;
- EXPECT_EQ(sizeof(mat3), sizeof(float)*9);
+ EXPECT_EQ(sizeof(m0), sizeof(float)*9);
}
TEST_F(Mat3Test, ComparisonOps) {
@@ -279,7 +280,7 @@
TEST_F(Mat2Test, Basics) {
mat2 m0;
- EXPECT_EQ(sizeof(mat2), sizeof(float)*4);
+ EXPECT_EQ(sizeof(m0), sizeof(float)*4);
}
TEST_F(Mat2Test, ComparisonOps) {
diff --git a/libs/nativewindow/Android.bp b/libs/nativewindow/Android.bp
index aa116bf..29555fd 100644
--- a/libs/nativewindow/Android.bp
+++ b/libs/nativewindow/Android.bp
@@ -47,6 +47,8 @@
"-std=c++1z"
],
+ version_script: "libnativewindow.map.txt",
+
srcs: [
"AHardwareBuffer.cpp",
"ANativeWindow.cpp",
diff --git a/libs/nativewindow/include/system/window.h b/libs/nativewindow/include/system/window.h
index 6490804..69e0951 100644
--- a/libs/nativewindow/include/system/window.h
+++ b/libs/nativewindow/include/system/window.h
@@ -225,6 +225,8 @@
NATIVE_WINDOW_GET_HDR_SUPPORT = 29,
NATIVE_WINDOW_SET_USAGE64 = 30,
NATIVE_WINDOW_GET_CONSUMER_USAGE64 = 31,
+ NATIVE_WINDOW_SET_BUFFERS_SMPTE2086_METADATA = 32,
+ NATIVE_WINDOW_SET_BUFFERS_CTA861_3_METADATA = 33,
// clang-format on
};
@@ -700,6 +702,42 @@
}
/*
+ * native_window_set_buffers_smpte2086_metadata(..., metadata)
+ * All buffers queued after this call will be associated with the SMPTE
+ * ST.2086 metadata specified.
+ *
+ * metadata specifies additional information about the contents of the buffer
+ * that may affect how it's displayed. When it is nullptr, it means no such
+ * information is available. No SMPTE ST.2086 metadata is associated with the
+ * buffers by default.
+ */
+static inline int native_window_set_buffers_smpte2086_metadata(
+ struct ANativeWindow* window,
+ const struct android_smpte2086_metadata* metadata)
+{
+ return window->perform(window, NATIVE_WINDOW_SET_BUFFERS_SMPTE2086_METADATA,
+ metadata);
+}
+
+/*
+ * native_window_set_buffers_cta861_3_metadata(..., metadata)
+ * All buffers queued after this call will be associated with the CTA-861.3
+ * metadata specified.
+ *
+ * metadata specifies additional information about the contents of the buffer
+ * that may affect how it's displayed. When it is nullptr, it means no such
+ * information is available. No CTA-861.3 metadata is associated with the
+ * buffers by default.
+ */
+static inline int native_window_set_buffers_cta861_3_metadata(
+ struct ANativeWindow* window,
+ const struct android_cta861_3_metadata* metadata)
+{
+ return window->perform(window, NATIVE_WINDOW_SET_BUFFERS_CTA861_3_METADATA,
+ metadata);
+}
+
+/*
* native_window_set_buffers_transform(..., int transform)
* All buffers queued after this call will be displayed transformed according
* to the transform parameter specified.
diff --git a/libs/nativewindow/libnativewindow.map.txt b/libs/nativewindow/libnativewindow.map.txt
index 58045be..105d01b 100644
--- a/libs/nativewindow/libnativewindow.map.txt
+++ b/libs/nativewindow/libnativewindow.map.txt
@@ -3,13 +3,11 @@
AHardwareBuffer_acquire;
AHardwareBuffer_allocate;
AHardwareBuffer_describe;
- AHardwareBuffer_fromHardwareBuffer;
AHardwareBuffer_getNativeHandle; # vndk
AHardwareBuffer_lock;
AHardwareBuffer_recvHandleFromUnixSocket;
AHardwareBuffer_release;
AHardwareBuffer_sendHandleToUnixSocket;
- AHardwareBuffer_toHardwareBuffer;
AHardwareBuffer_unlock;
ANativeWindowBuffer_getHardwareBuffer; # vndk
ANativeWindow_OemStorageGet; # vndk
@@ -17,8 +15,6 @@
ANativeWindow_acquire;
ANativeWindow_cancelBuffer; # vndk
ANativeWindow_dequeueBuffer; # vndk
- ANativeWindow_fromSurface;
- ANativeWindow_fromSurfaceTexture;
ANativeWindow_getFormat;
ANativeWindow_getHeight;
ANativeWindow_getWidth;
@@ -42,3 +38,17 @@
local:
*;
};
+
+LIBNATIVEWINDOW_PLATFORM {
+ global:
+ extern "C++" {
+ android::AHardwareBuffer_isValidPixelFormat*;
+ android::AHardwareBuffer_convertFromPixelFormat*;
+ android::AHardwareBuffer_convertToPixelFormat*;
+ android::AHardwareBuffer_convertFromGrallocUsageBits*;
+ android::AHardwareBuffer_convertToGrallocUsageBits*;
+ android::AHardwareBuffer_to_GraphicBuffer*;
+ android::AHardwareBuffer_to_ANativeWindowBuffer*;
+ android::AHardwareBuffer_from_GraphicBuffer*;
+ };
+} LIBNATIVEWINDOW;
diff --git a/libs/ui/Android.bp b/libs/ui/Android.bp
index 102964f..abe856e 100644
--- a/libs/ui/Android.bp
+++ b/libs/ui/Android.bp
@@ -95,6 +95,7 @@
],
header_libs: [
+ "libbase_headers",
"libnativebase_headers",
"libhardware_headers",
],
@@ -107,6 +108,7 @@
],
export_header_lib_headers: [
+ "libbase_headers",
"libnativebase_headers",
"libhardware_headers",
],
diff --git a/libs/ui/Fence.cpp b/libs/ui/Fence.cpp
index b67f4d9..ff53aa8 100644
--- a/libs/ui/Fence.cpp
+++ b/libs/ui/Fence.cpp
@@ -37,18 +37,12 @@
const sp<Fence> Fence::NO_FENCE = sp<Fence>(new Fence);
-Fence::Fence() :
- mFenceFd(-1) {
-}
-
Fence::Fence(int fenceFd) :
mFenceFd(fenceFd) {
}
-Fence::~Fence() {
- if (mFenceFd != -1) {
- close(mFenceFd);
- }
+Fence::Fence(base::unique_fd fenceFd) :
+ mFenceFd(std::move(fenceFd)) {
}
status_t Fence::wait(int timeout) {
@@ -68,7 +62,7 @@
int warningTimeout = 3000;
int err = sync_wait(mFenceFd, warningTimeout);
if (err < 0 && errno == ETIME) {
- ALOGE("%s: fence %d didn't signal in %u ms", logname, mFenceFd,
+ ALOGE("%s: fence %d didn't signal in %u ms", logname, mFenceFd.get(),
warningTimeout);
err = sync_wait(mFenceFd, TIMEOUT_NEVER);
}
@@ -94,7 +88,7 @@
if (result == -1) {
status_t err = -errno;
ALOGE("merge: sync_merge(\"%s\", %d, %d) returned an error: %s (%d)",
- name, f1->mFenceFd, f2->mFenceFd,
+ name, f1->mFenceFd.get(), f2->mFenceFd.get(),
strerror(-err), err);
return NO_FENCE;
}
@@ -117,7 +111,7 @@
struct sync_fence_info_data* finfo = sync_fence_info(mFenceFd);
if (finfo == NULL) {
- ALOGE("sync_fence_info returned NULL for fd %d", mFenceFd);
+ ALOGE("sync_fence_info returned NULL for fd %d", mFenceFd.get());
return SIGNAL_TIME_INVALID;
}
if (finfo->status != 1) {
@@ -181,7 +175,7 @@
}
if (numFds) {
- mFenceFd = *fds++;
+ mFenceFd.reset(*fds++);
count--;
}
diff --git a/libs/ui/include/ui/Fence.h b/libs/ui/include/ui/Fence.h
index 37811bc..ec67fa9 100644
--- a/libs/ui/include/ui/Fence.h
+++ b/libs/ui/include/ui/Fence.h
@@ -19,6 +19,7 @@
#include <stdint.h>
+#include <android-base/unique_fd.h>
#include <utils/Flattenable.h>
#include <utils/RefBase.h>
#include <utils/Timers.h>
@@ -49,12 +50,13 @@
// Construct a new Fence object with an invalid file descriptor. This
// should be done when the Fence object will be set up by unflattening
// serialized data.
- Fence();
+ Fence() = default;
// Construct a new Fence object to manage a given fence file descriptor.
// When the new Fence object is destructed the file descriptor will be
// closed.
explicit Fence(int fenceFd);
+ explicit Fence(base::unique_fd fenceFd);
// Not copyable or movable.
Fence(const Fence& rhs) = delete;
@@ -136,9 +138,9 @@
private:
// Only allow instantiation using ref counting.
friend class LightRefBase<Fence>;
- ~Fence();
+ ~Fence() = default;
- int mFenceFd;
+ base::unique_fd mFenceFd;
};
}; // namespace android
diff --git a/libs/ui/include/ui/FloatRect.h b/libs/ui/include/ui/FloatRect.h
index 270675c..6a7479a 100644
--- a/libs/ui/include/ui/FloatRect.h
+++ b/libs/ui/include/ui/FloatRect.h
@@ -27,6 +27,17 @@
float getWidth() const { return right - left; }
float getHeight() const { return bottom - top; }
+ FloatRect intersect(const FloatRect& other) const {
+ return {
+ // Inline to avoid tromping on other min/max defines or adding a
+ // dependency on STL
+ (left > other.left) ? left : other.left,
+ (top > other.top) ? top : other.top,
+ (right < other.right) ? right : other.right,
+ (bottom < other.bottom) ? bottom : other.bottom
+ };
+ }
+
float left = 0.0f;
float top = 0.0f;
float right = 0.0f;
diff --git a/libs/ui/include/ui/Rect.h b/libs/ui/include/ui/Rect.h
index 437fc14..0bec0b7 100644
--- a/libs/ui/include/ui/Rect.h
+++ b/libs/ui/include/ui/Rect.h
@@ -69,6 +69,15 @@
bottom = rb.y;
}
+ inline explicit Rect(const FloatRect& floatRect) {
+ // Ideally we would use std::round, but we don't want to add an STL
+ // dependency here, so we use an approximation
+ left = static_cast<int32_t>(floatRect.left + 0.5f);
+ top = static_cast<int32_t>(floatRect.top + 0.5f);
+ right = static_cast<int32_t>(floatRect.right + 0.5f);
+ bottom = static_cast<int32_t>(floatRect.bottom + 0.5f);
+ }
+
void makeInvalid();
inline void clear() {
diff --git a/libs/vr/libpdx/private/pdx/rpc/variant.h b/libs/vr/libpdx/private/pdx/rpc/variant.h
index 80b1769..2cc9664 100644
--- a/libs/vr/libpdx/private/pdx/rpc/variant.h
+++ b/libs/vr/libpdx/private/pdx/rpc/variant.h
@@ -450,12 +450,19 @@
Variant(Variant&& other)
: index_{other.index_}, value_{std::move(other.value_), other.index_} {}
+// Recent Clang versions has a regression that produces bogus
+// unused-lambda-capture warning. Suppress the warning as a temporary
+// workaround. http://b/71356631
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunused-lambda-capture"
// Copy and move construction from Variant types. Each element of OtherTypes
// must be convertible to an element of Types.
template <typename... OtherTypes>
explicit Variant(const Variant<OtherTypes...>& other) {
other.Visit([this](const auto& value) { Construct(value); });
}
+#pragma clang diagnostic pop
+
template <typename... OtherTypes>
explicit Variant(Variant<OtherTypes...>&& other) {
other.Visit([this](auto&& value) { Construct(std::move(value)); });
diff --git a/libs/vr/libvrflinger/display_service.h b/libs/vr/libvrflinger/display_service.h
index a3ee7bb..316f15a 100644
--- a/libs/vr/libvrflinger/display_service.h
+++ b/libs/vr/libvrflinger/display_service.h
@@ -71,6 +71,7 @@
void GrantDisplayOwnership() { hardware_composer_.Enable(); }
void SeizeDisplayOwnership() { hardware_composer_.Disable(); }
+ void OnBootFinished() { hardware_composer_.OnBootFinished(); }
private:
friend BASE;
diff --git a/libs/vr/libvrflinger/hardware_composer.cpp b/libs/vr/libvrflinger/hardware_composer.cpp
index be17ecf..5d796dc 100644
--- a/libs/vr/libvrflinger/hardware_composer.cpp
+++ b/libs/vr/libvrflinger/hardware_composer.cpp
@@ -53,6 +53,9 @@
const char kRightEyeOffsetProperty[] = "dvr.right_eye_offset_ns";
+// How long to wait after boot finishes before we turn the display off.
+constexpr int kBootFinishedDisplayOffTimeoutSec = 10;
+
// Get time offset from a vsync to when the pose for that vsync should be
// predicted out to. For example, if scanout gets halfway through the frame
// at the halfway point between vsyncs, then this could be half the period.
@@ -190,6 +193,16 @@
UpdatePostThreadState(PostThreadState::Suspended, true);
}
+void HardwareComposer::OnBootFinished() {
+ std::lock_guard<std::mutex> lock(post_thread_mutex_);
+ if (boot_finished_)
+ return;
+ boot_finished_ = true;
+ post_thread_wait_.notify_one();
+ if (is_standalone_device_)
+ request_display_callback_(true);
+}
+
// Update the post thread quiescent state based on idle and suspended inputs.
void HardwareComposer::UpdatePostThreadState(PostThreadStateType state,
bool suspend) {
@@ -276,6 +289,25 @@
property_set(kDvrPerformanceProperty, "idle");
}
+bool HardwareComposer::PostThreadCondWait(std::unique_lock<std::mutex>& lock,
+ int timeout_sec,
+ const std::function<bool()>& pred) {
+ auto pred_with_quit = [&] {
+ return pred() || (post_thread_state_ & PostThreadState::Quit);
+ };
+ if (timeout_sec >= 0) {
+ post_thread_wait_.wait_for(lock, std::chrono::seconds(timeout_sec),
+ pred_with_quit);
+ } else {
+ post_thread_wait_.wait(lock, pred_with_quit);
+ }
+ if (post_thread_state_ & PostThreadState::Quit) {
+ ALOGI("HardwareComposer::PostThread: Quitting.");
+ return true;
+ }
+ return false;
+}
+
HWC::Error HardwareComposer::Validate(hwc2_display_t display) {
uint32_t num_types;
uint32_t num_requests;
@@ -508,7 +540,7 @@
pending_surfaces_ = std::move(surfaces);
}
- if (request_display_callback_ && (!is_standalone_device_ || !composer_))
+ if (request_display_callback_ && !is_standalone_device_)
request_display_callback_(!display_idle);
// Set idle state based on whether there are any surfaces to handle.
@@ -697,6 +729,28 @@
bool was_running = false;
+ if (is_standalone_device_) {
+ // First, wait until boot finishes.
+ std::unique_lock<std::mutex> lock(post_thread_mutex_);
+ if (PostThreadCondWait(lock, -1, [this] { return boot_finished_; })) {
+ return;
+ }
+
+ // Then, wait until we're either leaving the quiescent state, or the boot
+ // finished display off timeout expires.
+ if (PostThreadCondWait(lock, kBootFinishedDisplayOffTimeoutSec,
+ [this] { return !post_thread_quiescent_; })) {
+ return;
+ }
+
+ LOG_ALWAYS_FATAL_IF(post_thread_state_ & PostThreadState::Suspended,
+ "Vr flinger should own the display by now.");
+ post_thread_resumed_ = true;
+ post_thread_ready_.notify_all();
+ OnPostThreadResumed();
+ was_running = true;
+ }
+
while (1) {
ATRACE_NAME("HardwareComposer::PostThread");
@@ -715,13 +769,12 @@
post_thread_resumed_ = false;
post_thread_ready_.notify_all();
- if (post_thread_state_ & PostThreadState::Quit) {
- ALOGI("HardwareComposer::PostThread: Quitting.");
+ if (PostThreadCondWait(lock, -1,
+ [this] { return !post_thread_quiescent_; })) {
+ // A true return value means we've been asked to quit.
return;
}
- post_thread_wait_.wait(lock, [this] { return !post_thread_quiescent_; });
-
post_thread_resumed_ = true;
post_thread_ready_.notify_all();
diff --git a/libs/vr/libvrflinger/hardware_composer.h b/libs/vr/libvrflinger/hardware_composer.h
index 9ed4b22..1d0c7ef 100644
--- a/libs/vr/libvrflinger/hardware_composer.h
+++ b/libs/vr/libvrflinger/hardware_composer.h
@@ -327,6 +327,9 @@
// it's paused. This should only be called from surface flinger's main thread.
void Disable();
+ // Called on a binder thread.
+ void OnBootFinished();
+
// Get the HMD display metrics for the current display.
display::Metrics GetHmdDisplayMetrics() const;
@@ -434,6 +437,16 @@
// Called on the post thread when the post thread is paused or quits.
void OnPostThreadPaused();
+ // Use post_thread_wait_ to wait for a specific condition, specified by pred.
+ // timeout_sec < 0 means wait indefinitely, otherwise it specifies the timeout
+ // in seconds.
+ // The lock must be held when this function is called.
+ // Returns true if the wait was interrupted because the post thread was asked
+ // to quit.
+ bool PostThreadCondWait(std::unique_lock<std::mutex>& lock,
+ int timeout_sec,
+ const std::function<bool()>& pred);
+
// Map the given shared memory buffer to our broadcast ring to track updates
// to the config parameters.
int MapConfigBuffer(IonBuffer& ion_buffer);
@@ -482,6 +495,10 @@
std::condition_variable post_thread_wait_;
std::condition_variable post_thread_ready_;
+ // When boot is finished this will be set to true and the post thread will be
+ // notified via post_thread_wait_.
+ bool boot_finished_ = false;
+
// Backlight LED brightness sysfs node.
pdx::LocalHandle backlight_brightness_fd_;
diff --git a/libs/vr/libvrflinger/vr_flinger.cpp b/libs/vr/libvrflinger/vr_flinger.cpp
index 5e7abd7..26aed4f 100644
--- a/libs/vr/libvrflinger/vr_flinger.cpp
+++ b/libs/vr/libvrflinger/vr_flinger.cpp
@@ -115,6 +115,7 @@
}
void VrFlinger::OnBootFinished() {
+ display_service_->OnBootFinished();
sp<IVrManager> vr_manager = interface_cast<IVrManager>(
defaultServiceManager()->checkService(String16("vrmanager")));
if (vr_manager.get()) {
diff --git a/opengl/libs/EGL/FileBlobCache.cpp b/opengl/libs/EGL/FileBlobCache.cpp
index ff608a3..7923715 100644
--- a/opengl/libs/EGL/FileBlobCache.cpp
+++ b/opengl/libs/EGL/FileBlobCache.cpp
@@ -16,6 +16,7 @@
#include "FileBlobCache.h"
+#include <errno.h>
#include <inttypes.h>
#include <log/log.h>
#include <sys/mman.h>
@@ -182,4 +183,4 @@
}
}
-}
\ No newline at end of file
+}
diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp
index 9822849..91a3455 100644
--- a/opengl/libs/EGL/Loader.cpp
+++ b/opengl/libs/EGL/Loader.cpp
@@ -407,9 +407,8 @@
DIR* d = opendir(search);
if (d != NULL) {
- struct dirent cur;
struct dirent* e;
- while (readdir_r(d, &cur, &e) == 0 && e) {
+ while ((e = readdir(d)) != NULL) {
if (e->d_type == DT_DIR) {
continue;
}
diff --git a/services/inputflinger/InputDispatcher.cpp b/services/inputflinger/InputDispatcher.cpp
index 4194dea..86492fd 100644
--- a/services/inputflinger/InputDispatcher.cpp
+++ b/services/inputflinger/InputDispatcher.cpp
@@ -1805,7 +1805,7 @@
ALOGD("channel '%s' ~ prepareDispatchCycle - flags=0x%08x, "
"xOffset=%f, yOffset=%f, scaleFactor=%f, "
"pointerIds=0x%x",
- connection->getInputChannelName(), inputTarget->flags,
+ connection->getInputChannelName().c_str(), inputTarget->flags,
inputTarget->xOffset, inputTarget->yOffset,
inputTarget->scaleFactor, inputTarget->pointerIds.value);
#endif
@@ -1815,7 +1815,7 @@
if (connection->status != Connection::STATUS_NORMAL) {
#if DEBUG_DISPATCH_CYCLE
ALOGD("channel '%s' ~ Dropping event because the channel status is %s",
- connection->getInputChannelName(), connection->getStatusLabel());
+ connection->getInputChannelName().c_str(), connection->getStatusLabel());
#endif
return;
}
@@ -1833,7 +1833,7 @@
}
#if DEBUG_FOCUS
ALOGD("channel '%s' ~ Split motion event.",
- connection->getInputChannelName());
+ connection->getInputChannelName().c_str());
logOutboundMotionDetailsLocked(" ", splitMotionEntry);
#endif
enqueueDispatchEntriesLocked(currentTime, connection,
@@ -1897,7 +1897,7 @@
dispatchEntry->resolvedAction, dispatchEntry->resolvedFlags)) {
#if DEBUG_DISPATCH_CYCLE
ALOGD("channel '%s' ~ enqueueDispatchEntryLocked: skipping inconsistent key event",
- connection->getInputChannelName());
+ connection->getInputChannelName().c_str());
#endif
delete dispatchEntry;
return; // skip the inconsistent event
@@ -1925,7 +1925,7 @@
motionEntry->deviceId, motionEntry->source, motionEntry->displayId)) {
#if DEBUG_DISPATCH_CYCLE
ALOGD("channel '%s' ~ enqueueDispatchEntryLocked: filling in missing hover enter event",
- connection->getInputChannelName());
+ connection->getInputChannelName().c_str());
#endif
dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_HOVER_ENTER;
}
@@ -1942,7 +1942,7 @@
dispatchEntry->resolvedAction, dispatchEntry->resolvedFlags)) {
#if DEBUG_DISPATCH_CYCLE
ALOGD("channel '%s' ~ enqueueDispatchEntryLocked: skipping inconsistent motion event",
- connection->getInputChannelName());
+ connection->getInputChannelName().c_str());
#endif
delete dispatchEntry;
return; // skip the inconsistent event
@@ -1965,7 +1965,7 @@
const sp<Connection>& connection) {
#if DEBUG_DISPATCH_CYCLE
ALOGD("channel '%s' ~ startDispatchCycle",
- connection->getInputChannelName());
+ connection->getInputChannelName().c_str());
#endif
while (connection->status == Connection::STATUS_NORMAL
@@ -2048,7 +2048,8 @@
ALOGE("channel '%s' ~ Could not publish event because the pipe is full. "
"This is unexpected because the wait queue is empty, so the pipe "
"should be empty and we shouldn't have any problems writing an "
- "event to it, status=%d", connection->getInputChannelName(), status);
+ "event to it, status=%d", connection->getInputChannelName().c_str(),
+ status);
abortBrokenDispatchCycleLocked(currentTime, connection, true /*notify*/);
} else {
// Pipe is full and we are waiting for the app to finish process some events
@@ -2056,13 +2057,13 @@
#if DEBUG_DISPATCH_CYCLE
ALOGD("channel '%s' ~ Could not publish event because the pipe is full, "
"waiting for the application to catch up",
- connection->getInputChannelName());
+ connection->getInputChannelName().c_str());
#endif
connection->inputPublisherBlocked = true;
}
} else {
ALOGE("channel '%s' ~ Could not publish event due to an unexpected error, "
- "status=%d", connection->getInputChannelName(), status);
+ "status=%d", connection->getInputChannelName().c_str(), status);
abortBrokenDispatchCycleLocked(currentTime, connection, true /*notify*/);
}
return;
@@ -2080,7 +2081,7 @@
const sp<Connection>& connection, uint32_t seq, bool handled) {
#if DEBUG_DISPATCH_CYCLE
ALOGD("channel '%s' ~ finishDispatchCycle - seq=%u, handled=%s",
- connection->getInputChannelName(), seq, toString(handled));
+ connection->getInputChannelName().c_str(), seq, toString(handled));
#endif
connection->inputPublisherBlocked = false;
@@ -2098,7 +2099,7 @@
const sp<Connection>& connection, bool notify) {
#if DEBUG_DISPATCH_CYCLE
ALOGD("channel '%s' ~ abortBrokenDispatchCycle - notify=%s",
- connection->getInputChannelName(), toString(notify));
+ connection->getInputChannelName().c_str(), toString(notify));
#endif
// Clear the dispatch queues.
@@ -2151,7 +2152,7 @@
if (!(events & (ALOOPER_EVENT_ERROR | ALOOPER_EVENT_HANGUP))) {
if (!(events & ALOOPER_EVENT_INPUT)) {
ALOGW("channel '%s' ~ Received spurious callback for unhandled poll event. "
- "events=0x%x", connection->getInputChannelName(), events);
+ "events=0x%x", connection->getInputChannelName().c_str(), events);
return 1;
}
@@ -2178,7 +2179,7 @@
notify = status != DEAD_OBJECT || !connection->monitor;
if (notify) {
ALOGE("channel '%s' ~ Failed to receive finished signal. status=%d",
- connection->getInputChannelName(), status);
+ connection->getInputChannelName().c_str(), status);
}
} else {
// Monitor channels are never explicitly unregistered.
@@ -2187,7 +2188,7 @@
notify = !connection->monitor;
if (notify) {
ALOGW("channel '%s' ~ Consumer closed input channel or an error occurred. "
- "events=0x%x", connection->getInputChannelName(), events);
+ "events=0x%x", connection->getInputChannelName().c_str(), events);
}
}
@@ -2237,7 +2238,7 @@
#if DEBUG_OUTBOUND_EVENT_DETAILS
ALOGD("channel '%s' ~ Synthesized %zu cancelation events to bring channel back in sync "
"with reality: %s, mode=%d.",
- connection->getInputChannelName(), cancelationEvents.size(),
+ connection->getInputChannelName().c_str(), cancelationEvents.size(),
options.reason, options.mode);
#endif
for (size_t i = 0; i < cancelationEvents.size(); i++) {
@@ -3285,7 +3286,8 @@
const sp<Connection>& connection = mConnectionsByFd.valueAt(i);
dump += StringPrintf(INDENT2 "%zu: channelName='%s', windowName='%s', "
"status=%s, monitor=%s, inputPublisherBlocked=%s\n",
- i, connection->getInputChannelName(), connection->getWindowName(),
+ i, connection->getInputChannelName().c_str(),
+ connection->getWindowName().c_str(),
connection->getStatusLabel(), toString(connection->monitor),
toString(connection->inputPublisherBlocked));
@@ -3451,7 +3453,7 @@
void InputDispatcher::onDispatchCycleBrokenLocked(
nsecs_t currentTime, const sp<Connection>& connection) {
ALOGE("channel '%s' ~ Channel is unrecoverably broken and will be disposed!",
- connection->getInputChannelName());
+ connection->getInputChannelName().c_str());
CommandEntry* commandEntry = postCommandLocked(
& InputDispatcher::doNotifyInputChannelBrokenLockedInterruptible);
@@ -3568,7 +3570,7 @@
if (eventDuration > SLOW_EVENT_PROCESSING_WARNING_TIMEOUT) {
std::string msg =
StringPrintf("Window '%s' spent %0.1fms processing the last input event: ",
- connection->getWindowName(), eventDuration * 0.000001f);
+ connection->getWindowName().c_str(), eventDuration * 0.000001f);
dispatchEntry->eventEntry->appendDescription(msg);
ALOGI("%s", msg.c_str());
}
@@ -3811,7 +3813,7 @@
void InputDispatcher::traceOutboundQueueLengthLocked(const sp<Connection>& connection) {
if (ATRACE_ENABLED()) {
char counterName[40];
- snprintf(counterName, sizeof(counterName), "oq:%s", connection->getWindowName());
+ snprintf(counterName, sizeof(counterName), "oq:%s", connection->getWindowName().c_str());
ATRACE_INT(counterName, connection->outboundQueue.count());
}
}
@@ -3819,7 +3821,7 @@
void InputDispatcher::traceWaitQueueLengthLocked(const sp<Connection>& connection) {
if (ATRACE_ENABLED()) {
char counterName[40];
- snprintf(counterName, sizeof(counterName), "wq:%s", connection->getWindowName());
+ snprintf(counterName, sizeof(counterName), "wq:%s", connection->getWindowName().c_str());
ATRACE_INT(counterName, connection->waitQueue.count());
}
}
@@ -4397,9 +4399,9 @@
InputDispatcher::Connection::~Connection() {
}
-const char* InputDispatcher::Connection::getWindowName() const {
+const std::string InputDispatcher::Connection::getWindowName() const {
if (inputWindowHandle != NULL) {
- return inputWindowHandle->getName().c_str();
+ return inputWindowHandle->getName();
}
if (monitor) {
return "monitor";
diff --git a/services/inputflinger/InputDispatcher.h b/services/inputflinger/InputDispatcher.h
index 92b3a9c..8da8450 100644
--- a/services/inputflinger/InputDispatcher.h
+++ b/services/inputflinger/InputDispatcher.h
@@ -831,9 +831,9 @@
explicit Connection(const sp<InputChannel>& inputChannel,
const sp<InputWindowHandle>& inputWindowHandle, bool monitor);
- inline const char* getInputChannelName() const { return inputChannel->getName().c_str(); }
+ inline const std::string getInputChannelName() const { return inputChannel->getName(); }
- const char* getWindowName() const;
+ const std::string getWindowName() const;
const char* getStatusLabel() const;
DispatchEntry* findWaitQueueEntry(uint32_t seq);
diff --git a/services/inputflinger/InputListener.cpp b/services/inputflinger/InputListener.cpp
index 2ee222b..520fea4 100644
--- a/services/inputflinger/InputListener.cpp
+++ b/services/inputflinger/InputListener.cpp
@@ -69,13 +69,15 @@
NotifyMotionArgs::NotifyMotionArgs(nsecs_t eventTime, int32_t deviceId, uint32_t source,
uint32_t policyFlags,
int32_t action, int32_t actionButton, int32_t flags, int32_t metaState,
- int32_t buttonState, int32_t edgeFlags, int32_t displayId, uint32_t pointerCount,
+ int32_t buttonState, int32_t edgeFlags, int32_t displayId, uint32_t deviceTimestamp,
+ uint32_t pointerCount,
const PointerProperties* pointerProperties, const PointerCoords* pointerCoords,
float xPrecision, float yPrecision, nsecs_t downTime) :
eventTime(eventTime), deviceId(deviceId), source(source), policyFlags(policyFlags),
action(action), actionButton(actionButton),
flags(flags), metaState(metaState), buttonState(buttonState),
- edgeFlags(edgeFlags), displayId(displayId), pointerCount(pointerCount),
+ edgeFlags(edgeFlags), displayId(displayId), deviceTimestamp(deviceTimestamp),
+ pointerCount(pointerCount),
xPrecision(xPrecision), yPrecision(yPrecision), downTime(downTime) {
for (uint32_t i = 0; i < pointerCount; i++) {
this->pointerProperties[i].copyFrom(pointerProperties[i]);
@@ -88,7 +90,8 @@
policyFlags(other.policyFlags),
action(other.action), actionButton(other.actionButton), flags(other.flags),
metaState(other.metaState), buttonState(other.buttonState),
- edgeFlags(other.edgeFlags), displayId(other.displayId), pointerCount(other.pointerCount),
+ edgeFlags(other.edgeFlags), displayId(other.displayId),
+ deviceTimestamp(other.deviceTimestamp), pointerCount(other.pointerCount),
xPrecision(other.xPrecision), yPrecision(other.yPrecision), downTime(other.downTime) {
for (uint32_t i = 0; i < pointerCount; i++) {
pointerProperties[i].copyFrom(other.pointerProperties[i]);
diff --git a/services/inputflinger/InputListener.h b/services/inputflinger/InputListener.h
index ea3dd1c..77afb34 100644
--- a/services/inputflinger/InputListener.h
+++ b/services/inputflinger/InputListener.h
@@ -90,6 +90,13 @@
int32_t buttonState;
int32_t edgeFlags;
int32_t displayId;
+ /**
+ * A timestamp in the input device's time base, not the platform's.
+ * The units are microseconds since the last reset.
+ * This can only be compared to other device timestamps from the same device.
+ * This value will overflow after a little over an hour.
+ */
+ uint32_t deviceTimestamp;
uint32_t pointerCount;
PointerProperties pointerProperties[MAX_POINTERS];
PointerCoords pointerCoords[MAX_POINTERS];
@@ -102,7 +109,7 @@
NotifyMotionArgs(nsecs_t eventTime, int32_t deviceId, uint32_t source, uint32_t policyFlags,
int32_t action, int32_t actionButton, int32_t flags,
int32_t metaState, int32_t buttonState,
- int32_t edgeFlags, int32_t displayId, uint32_t pointerCount,
+ int32_t edgeFlags, int32_t displayId, uint32_t deviceTimestamp, uint32_t pointerCount,
const PointerProperties* pointerProperties, const PointerCoords* pointerCoords,
float xPrecision, float yPrecision, nsecs_t downTime);
diff --git a/services/inputflinger/InputReader.cpp b/services/inputflinger/InputReader.cpp
index e398a84..e0cd8a0 100644
--- a/services/inputflinger/InputReader.cpp
+++ b/services/inputflinger/InputReader.cpp
@@ -1787,7 +1787,7 @@
MultiTouchMotionAccumulator::MultiTouchMotionAccumulator() :
mCurrentSlot(-1), mSlots(NULL), mSlotCount(0), mUsingSlotsProtocol(false),
- mHaveStylus(false) {
+ mHaveStylus(false), mDeviceTimestamp(0) {
}
MultiTouchMotionAccumulator::~MultiTouchMotionAccumulator() {
@@ -1828,6 +1828,7 @@
} else {
clearSlots(-1);
}
+ mDeviceTimestamp = 0;
}
void MultiTouchMotionAccumulator::clearSlots(int32_t initialSlot) {
@@ -1921,6 +1922,8 @@
} else if (rawEvent->type == EV_SYN && rawEvent->code == SYN_MT_REPORT) {
// MultiTouch Sync: The driver has returned all data for *one* of the pointers.
mCurrentSlot += 1;
+ } else if (rawEvent->type == EV_MSC && rawEvent->code == MSC_TIMESTAMP) {
+ mDeviceTimestamp = rawEvent->value;
}
}
@@ -2894,7 +2897,7 @@
NotifyMotionArgs releaseArgs(when, getDeviceId(), mSource, policyFlags,
AMOTION_EVENT_ACTION_BUTTON_RELEASE, actionButton, 0,
metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
- displayId, 1, &pointerProperties, &pointerCoords,
+ displayId, /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords,
mXPrecision, mYPrecision, downTime);
getListener()->notifyMotion(&releaseArgs);
}
@@ -2903,7 +2906,7 @@
NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags,
motionEventAction, 0, 0, metaState, currentButtonState,
AMOTION_EVENT_EDGE_FLAG_NONE,
- displayId, 1, &pointerProperties, &pointerCoords,
+ displayId, /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords,
mXPrecision, mYPrecision, downTime);
getListener()->notifyMotion(&args);
@@ -2915,7 +2918,7 @@
NotifyMotionArgs pressArgs(when, getDeviceId(), mSource, policyFlags,
AMOTION_EVENT_ACTION_BUTTON_PRESS, actionButton, 0,
metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
- displayId, 1, &pointerProperties, &pointerCoords,
+ displayId, /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords,
mXPrecision, mYPrecision, downTime);
getListener()->notifyMotion(&pressArgs);
}
@@ -2929,7 +2932,7 @@
NotifyMotionArgs hoverArgs(when, getDeviceId(), mSource, policyFlags,
AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0,
metaState, currentButtonState, AMOTION_EVENT_EDGE_FLAG_NONE,
- displayId, 1, &pointerProperties, &pointerCoords,
+ displayId, /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords,
mXPrecision, mYPrecision, downTime);
getListener()->notifyMotion(&hoverArgs);
}
@@ -2942,7 +2945,7 @@
NotifyMotionArgs scrollArgs(when, getDeviceId(), mSource, policyFlags,
AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState, currentButtonState,
AMOTION_EVENT_EDGE_FLAG_NONE,
- displayId, 1, &pointerProperties, &pointerCoords,
+ displayId, /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords,
mXPrecision, mYPrecision, downTime);
getListener()->notifyMotion(&scrollArgs);
}
@@ -3072,7 +3075,7 @@
NotifyMotionArgs scrollArgs(when, getDeviceId(), mSource, policyFlags,
AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState, 0,
AMOTION_EVENT_EDGE_FLAG_NONE,
- displayId, 1, &pointerProperties, &pointerCoords,
+ displayId, /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords,
0, 0, 0);
getListener()->notifyMotion(&scrollArgs);
}
@@ -3705,11 +3708,13 @@
// Pressure factors.
mPressureScale = 0;
+ float pressureMax = 1.0;
if (mCalibration.pressureCalibration == Calibration::PRESSURE_CALIBRATION_PHYSICAL
|| mCalibration.pressureCalibration
== Calibration::PRESSURE_CALIBRATION_AMPLITUDE) {
if (mCalibration.havePressureScale) {
mPressureScale = mCalibration.pressureScale;
+ pressureMax = mPressureScale * mRawPointerAxes.pressure.maxValue;
} else if (mRawPointerAxes.pressure.valid
&& mRawPointerAxes.pressure.maxValue != 0) {
mPressureScale = 1.0f / mRawPointerAxes.pressure.maxValue;
@@ -3719,7 +3724,7 @@
mOrientedRanges.pressure.axis = AMOTION_EVENT_AXIS_PRESSURE;
mOrientedRanges.pressure.source = mSource;
mOrientedRanges.pressure.min = 0;
- mOrientedRanges.pressure.max = 1.0;
+ mOrientedRanges.pressure.max = pressureMax;
mOrientedRanges.pressure.flat = 0;
mOrientedRanges.pressure.fuzz = 0;
mOrientedRanges.pressure.resolution = 0;
@@ -4727,6 +4732,7 @@
int32_t buttonState = mCurrentCookedState.buttonState;
dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_CANCEL, 0, 0,
metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
+ mCurrentCookedState.deviceTimestamp,
mCurrentCookedState.cookedPointerData.pointerProperties,
mCurrentCookedState.cookedPointerData.pointerCoords,
mCurrentCookedState.cookedPointerData.idToIndex,
@@ -4749,6 +4755,7 @@
dispatchMotion(when, policyFlags, mSource,
AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, buttonState,
AMOTION_EVENT_EDGE_FLAG_NONE,
+ mCurrentCookedState.deviceTimestamp,
mCurrentCookedState.cookedPointerData.pointerProperties,
mCurrentCookedState.cookedPointerData.pointerCoords,
mCurrentCookedState.cookedPointerData.idToIndex,
@@ -4783,6 +4790,7 @@
dispatchMotion(when, policyFlags, mSource,
AMOTION_EVENT_ACTION_POINTER_UP, 0, 0, metaState, buttonState, 0,
+ mCurrentCookedState.deviceTimestamp,
mLastCookedState.cookedPointerData.pointerProperties,
mLastCookedState.cookedPointerData.pointerCoords,
mLastCookedState.cookedPointerData.idToIndex,
@@ -4797,6 +4805,7 @@
ALOG_ASSERT(moveIdBits.value == dispatchedIdBits.value);
dispatchMotion(when, policyFlags, mSource,
AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, buttonState, 0,
+ mCurrentCookedState.deviceTimestamp,
mCurrentCookedState.cookedPointerData.pointerProperties,
mCurrentCookedState.cookedPointerData.pointerCoords,
mCurrentCookedState.cookedPointerData.idToIndex,
@@ -4815,6 +4824,7 @@
dispatchMotion(when, policyFlags, mSource,
AMOTION_EVENT_ACTION_POINTER_DOWN, 0, 0, metaState, buttonState, 0,
+ mCurrentCookedState.deviceTimestamp,
mCurrentCookedState.cookedPointerData.pointerProperties,
mCurrentCookedState.cookedPointerData.pointerCoords,
mCurrentCookedState.cookedPointerData.idToIndex,
@@ -4830,6 +4840,7 @@
int32_t metaState = getContext()->getGlobalMetaState();
dispatchMotion(when, policyFlags, mSource,
AMOTION_EVENT_ACTION_HOVER_EXIT, 0, 0, metaState, mLastCookedState.buttonState, 0,
+ mLastCookedState.deviceTimestamp,
mLastCookedState.cookedPointerData.pointerProperties,
mLastCookedState.cookedPointerData.pointerCoords,
mLastCookedState.cookedPointerData.idToIndex,
@@ -4846,6 +4857,7 @@
if (!mSentHoverEnter) {
dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_HOVER_ENTER,
0, 0, metaState, mCurrentRawState.buttonState, 0,
+ mCurrentCookedState.deviceTimestamp,
mCurrentCookedState.cookedPointerData.pointerProperties,
mCurrentCookedState.cookedPointerData.pointerCoords,
mCurrentCookedState.cookedPointerData.idToIndex,
@@ -4857,6 +4869,7 @@
dispatchMotion(when, policyFlags, mSource,
AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, metaState,
mCurrentRawState.buttonState, 0,
+ mCurrentCookedState.deviceTimestamp,
mCurrentCookedState.cookedPointerData.pointerProperties,
mCurrentCookedState.cookedPointerData.pointerCoords,
mCurrentCookedState.cookedPointerData.idToIndex,
@@ -4876,6 +4889,7 @@
dispatchMotion(when, policyFlags, mSource,
AMOTION_EVENT_ACTION_BUTTON_RELEASE, actionButton,
0, metaState, buttonState, 0,
+ mCurrentCookedState.deviceTimestamp,
mCurrentCookedState.cookedPointerData.pointerProperties,
mCurrentCookedState.cookedPointerData.pointerCoords,
mCurrentCookedState.cookedPointerData.idToIndex, idBits, -1,
@@ -4893,6 +4907,7 @@
buttonState |= actionButton;
dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_BUTTON_PRESS, actionButton,
0, metaState, buttonState, 0,
+ mCurrentCookedState.deviceTimestamp,
mCurrentCookedState.cookedPointerData.pointerProperties,
mCurrentCookedState.cookedPointerData.pointerCoords,
mCurrentCookedState.cookedPointerData.idToIndex, idBits, -1,
@@ -4911,6 +4926,8 @@
uint32_t currentPointerCount = mCurrentRawState.rawPointerData.pointerCount;
mCurrentCookedState.cookedPointerData.clear();
+ mCurrentCookedState.deviceTimestamp =
+ mCurrentRawState.deviceTimestamp;
mCurrentCookedState.cookedPointerData.pointerCount = currentPointerCount;
mCurrentCookedState.cookedPointerData.hoveringIdBits =
mCurrentRawState.rawPointerData.hoveringIdBits;
@@ -5303,7 +5320,7 @@
if (cancelPreviousGesture) {
dispatchMotion(when, policyFlags, mSource,
AMOTION_EVENT_ACTION_CANCEL, 0, 0, metaState, buttonState,
- AMOTION_EVENT_EDGE_FLAG_NONE,
+ AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0,
mPointerGesture.lastGestureProperties,
mPointerGesture.lastGestureCoords, mPointerGesture.lastGestureIdToIndex,
dispatchedGestureIdBits, -1, 0,
@@ -5324,6 +5341,7 @@
dispatchMotion(when, policyFlags, mSource,
AMOTION_EVENT_ACTION_POINTER_UP, 0, 0,
metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
+ /* deviceTimestamp */ 0,
mPointerGesture.lastGestureProperties,
mPointerGesture.lastGestureCoords, mPointerGesture.lastGestureIdToIndex,
dispatchedGestureIdBits, id,
@@ -5338,7 +5356,7 @@
if (moveNeeded) {
dispatchMotion(when, policyFlags, mSource,
AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, buttonState,
- AMOTION_EVENT_EDGE_FLAG_NONE,
+ AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0,
mPointerGesture.currentGestureProperties,
mPointerGesture.currentGestureCoords, mPointerGesture.currentGestureIdToIndex,
dispatchedGestureIdBits, -1,
@@ -5359,6 +5377,7 @@
dispatchMotion(when, policyFlags, mSource,
AMOTION_EVENT_ACTION_POINTER_DOWN, 0, 0, metaState, buttonState, 0,
+ /* deviceTimestamp */ 0,
mPointerGesture.currentGestureProperties,
mPointerGesture.currentGestureCoords, mPointerGesture.currentGestureIdToIndex,
dispatchedGestureIdBits, id,
@@ -5370,7 +5389,7 @@
if (mPointerGesture.currentGestureMode == PointerGesture::HOVER) {
dispatchMotion(when, policyFlags, mSource,
AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0,
- metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
+ metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0,
mPointerGesture.currentGestureProperties,
mPointerGesture.currentGestureCoords, mPointerGesture.currentGestureIdToIndex,
mPointerGesture.currentGestureIdBits, -1,
@@ -5397,7 +5416,7 @@
NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags,
AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0,
metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
- mViewport.displayId, 1, &pointerProperties, &pointerCoords,
+ mViewport.displayId, /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords,
0, 0, mPointerGesture.downTime);
getListener()->notifyMotion(&args);
}
@@ -5427,7 +5446,7 @@
int32_t buttonState = mCurrentRawState.buttonState;
dispatchMotion(when, policyFlags, mSource,
AMOTION_EVENT_ACTION_CANCEL, 0, 0, metaState, buttonState,
- AMOTION_EVENT_EDGE_FLAG_NONE,
+ AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0,
mPointerGesture.lastGestureProperties,
mPointerGesture.lastGestureCoords, mPointerGesture.lastGestureIdToIndex,
mPointerGesture.lastGestureIdBits, -1,
@@ -6319,7 +6338,7 @@
// Send up.
NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags,
AMOTION_EVENT_ACTION_UP, 0, 0, metaState, mLastRawState.buttonState, 0,
- mViewport.displayId,
+ mViewport.displayId, /* deviceTimestamp */ 0,
1, &mPointerSimple.lastProperties, &mPointerSimple.lastCoords,
mOrientedXPrecision, mOrientedYPrecision,
mPointerSimple.downTime);
@@ -6332,7 +6351,7 @@
// Send hover exit.
NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags,
AMOTION_EVENT_ACTION_HOVER_EXIT, 0, 0, metaState, mLastRawState.buttonState, 0,
- mViewport.displayId,
+ mViewport.displayId, /* deviceTimestamp */ 0,
1, &mPointerSimple.lastProperties, &mPointerSimple.lastCoords,
mOrientedXPrecision, mOrientedYPrecision,
mPointerSimple.downTime);
@@ -6347,7 +6366,7 @@
// Send down.
NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags,
AMOTION_EVENT_ACTION_DOWN, 0, 0, metaState, mCurrentRawState.buttonState, 0,
- mViewport.displayId,
+ mViewport.displayId, /* deviceTimestamp */ 0,
1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords,
mOrientedXPrecision, mOrientedYPrecision,
mPointerSimple.downTime);
@@ -6357,7 +6376,7 @@
// Send move.
NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags,
AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, mCurrentRawState.buttonState, 0,
- mViewport.displayId,
+ mViewport.displayId, /* deviceTimestamp */ 0,
1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords,
mOrientedXPrecision, mOrientedYPrecision,
mPointerSimple.downTime);
@@ -6372,7 +6391,7 @@
NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags,
AMOTION_EVENT_ACTION_HOVER_ENTER, 0, 0, metaState,
mCurrentRawState.buttonState, 0,
- mViewport.displayId,
+ mViewport.displayId, /* deviceTimestamp */ 0,
1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords,
mOrientedXPrecision, mOrientedYPrecision,
mPointerSimple.downTime);
@@ -6383,7 +6402,7 @@
NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags,
AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, metaState,
mCurrentRawState.buttonState, 0,
- mViewport.displayId,
+ mViewport.displayId, /* deviceTimestamp */ 0,
1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords,
mOrientedXPrecision, mOrientedYPrecision,
mPointerSimple.downTime);
@@ -6404,7 +6423,7 @@
NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags,
AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState, mCurrentRawState.buttonState, 0,
- mViewport.displayId,
+ mViewport.displayId, /* deviceTimestamp */ 0,
1, &mPointerSimple.currentProperties, &pointerCoords,
mOrientedXPrecision, mOrientedYPrecision,
mPointerSimple.downTime);
@@ -6429,7 +6448,7 @@
void TouchInputMapper::dispatchMotion(nsecs_t when, uint32_t policyFlags, uint32_t source,
int32_t action, int32_t actionButton, int32_t flags,
- int32_t metaState, int32_t buttonState, int32_t edgeFlags,
+ int32_t metaState, int32_t buttonState, int32_t edgeFlags, uint32_t deviceTimestamp,
const PointerProperties* properties, const PointerCoords* coords,
const uint32_t* idToIndex, BitSet32 idBits, int32_t changedId,
float xPrecision, float yPrecision, nsecs_t downTime) {
@@ -6467,7 +6486,7 @@
NotifyMotionArgs args(when, getDeviceId(), source, policyFlags,
action, actionButton, flags, metaState, buttonState, edgeFlags,
- mViewport.displayId, pointerCount, pointerProperties, pointerCoords,
+ mViewport.displayId, deviceTimestamp, pointerCount, pointerProperties, pointerCoords,
xPrecision, yPrecision, downTime);
getListener()->notifyMotion(&args);
}
@@ -6947,6 +6966,7 @@
outCount += 1;
}
+ outState->deviceTimestamp = mMultiTouchMotionAccumulator.getDeviceTimestamp();
outState->rawPointerData.pointerCount = outCount;
mPointerIdBits = newPointerIdBits;
@@ -7386,7 +7406,8 @@
NotifyMotionArgs args(when, getDeviceId(), AINPUT_SOURCE_JOYSTICK, policyFlags,
AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
- ADISPLAY_ID_NONE, 1, &pointerProperties, &pointerCoords, 0, 0, 0);
+ ADISPLAY_ID_NONE, /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords,
+ 0, 0, 0);
getListener()->notifyMotion(&args);
}
diff --git a/services/inputflinger/InputReader.h b/services/inputflinger/InputReader.h
index 4f48262..cef3212 100644
--- a/services/inputflinger/InputReader.h
+++ b/services/inputflinger/InputReader.h
@@ -947,6 +947,7 @@
inline size_t getSlotCount() const { return mSlotCount; }
inline const Slot* getSlot(size_t index) const { return &mSlots[index]; }
+ inline uint32_t getDeviceTimestamp() const { return mDeviceTimestamp; }
private:
int32_t mCurrentSlot;
@@ -954,6 +955,7 @@
size_t mSlotCount;
bool mUsingSlotsProtocol;
bool mHaveStylus;
+ uint32_t mDeviceTimestamp;
void clearSlots(int32_t initialSlot);
};
@@ -1396,6 +1398,7 @@
struct RawState {
nsecs_t when;
+ uint32_t deviceTimestamp;
// Raw pointer sample data.
RawPointerData rawPointerData;
@@ -1408,6 +1411,7 @@
void copyFrom(const RawState& other) {
when = other.when;
+ deviceTimestamp = other.deviceTimestamp;
rawPointerData.copyFrom(other.rawPointerData);
buttonState = other.buttonState;
rawVScroll = other.rawVScroll;
@@ -1416,6 +1420,7 @@
void clear() {
when = 0;
+ deviceTimestamp = 0;
rawPointerData.clear();
buttonState = 0;
rawVScroll = 0;
@@ -1424,6 +1429,7 @@
};
struct CookedState {
+ uint32_t deviceTimestamp;
// Cooked pointer sample data.
CookedPointerData cookedPointerData;
@@ -1435,6 +1441,7 @@
int32_t buttonState;
void copyFrom(const CookedState& other) {
+ deviceTimestamp = other.deviceTimestamp;
cookedPointerData.copyFrom(other.cookedPointerData);
fingerIdBits = other.fingerIdBits;
stylusIdBits = other.stylusIdBits;
@@ -1443,6 +1450,7 @@
}
void clear() {
+ deviceTimestamp = 0;
cookedPointerData.clear();
fingerIdBits.clear();
stylusIdBits.clear();
@@ -1837,6 +1845,7 @@
void dispatchMotion(nsecs_t when, uint32_t policyFlags, uint32_t source,
int32_t action, int32_t actionButton,
int32_t flags, int32_t metaState, int32_t buttonState, int32_t edgeFlags,
+ uint32_t deviceTimestamp,
const PointerProperties* properties, const PointerCoords* coords,
const uint32_t* idToIndex, BitSet32 idBits,
int32_t changedId, float xPrecision, float yPrecision, nsecs_t downTime);
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index 0344ead..22f15a0 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -2954,8 +2954,8 @@
const int32_t TouchInputMapperTest::RAW_TOUCH_MAX = 31;
const int32_t TouchInputMapperTest::RAW_TOOL_MIN = 0;
const int32_t TouchInputMapperTest::RAW_TOOL_MAX = 15;
-const int32_t TouchInputMapperTest::RAW_PRESSURE_MIN = RAW_TOUCH_MIN;
-const int32_t TouchInputMapperTest::RAW_PRESSURE_MAX = RAW_TOUCH_MAX;
+const int32_t TouchInputMapperTest::RAW_PRESSURE_MIN = 0;
+const int32_t TouchInputMapperTest::RAW_PRESSURE_MAX = 255;
const int32_t TouchInputMapperTest::RAW_ORIENTATION_MIN = -7;
const int32_t TouchInputMapperTest::RAW_ORIENTATION_MAX = 7;
const int32_t TouchInputMapperTest::RAW_DISTANCE_MIN = 0;
@@ -4384,6 +4384,7 @@
void processSlot(MultiTouchInputMapper* mapper, int32_t slot);
void processToolType(MultiTouchInputMapper* mapper, int32_t toolType);
void processKey(MultiTouchInputMapper* mapper, int32_t code, int32_t value);
+ void processTimestamp(MultiTouchInputMapper* mapper, uint32_t value);
void processMTSync(MultiTouchInputMapper* mapper);
void processSync(MultiTouchInputMapper* mapper);
};
@@ -4499,6 +4500,10 @@
process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, code, value);
}
+void MultiTouchInputMapperTest::processTimestamp(MultiTouchInputMapper* mapper, uint32_t value) {
+ process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_MSC, MSC_TIMESTAMP, value);
+}
+
void MultiTouchInputMapperTest::processMTSync(MultiTouchInputMapper* mapper) {
process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_MT_REPORT, 0);
}
@@ -5316,6 +5321,12 @@
addConfigurationProperty("touch.pressure.scale", "0.01");
addMapperAndConfigure(mapper);
+ InputDeviceInfo info;
+ mapper->populateDeviceInfo(&info);
+ ASSERT_NO_FATAL_FAILURE(assertMotionRange(info,
+ AINPUT_MOTION_RANGE_PRESSURE, AINPUT_SOURCE_TOUCHSCREEN,
+ 0.0f, RAW_PRESSURE_MAX * 0.01, 0.0f, 0.0f));
+
// These calculations are based on the input device calibration documentation.
int32_t rawX = 100;
int32_t rawY = 200;
@@ -5875,5 +5886,63 @@
toDisplayX(150), toDisplayY(250), 0, 0, 0, 0, 0, 0, 0, 0));
}
+TEST_F(MultiTouchInputMapperTest, Process_HandlesTimestamp) {
+ MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice);
+
+ addConfigurationProperty("touch.deviceType", "touchScreen");
+ prepareDisplay(DISPLAY_ORIENTATION_0);
+ prepareAxes(POSITION);
+ addMapperAndConfigure(mapper);
+ NotifyMotionArgs args;
+
+ // By default, deviceTimestamp should be zero
+ processPosition(mapper, 100, 100);
+ processMTSync(mapper);
+ processSync(mapper);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
+ ASSERT_EQ(0U, args.deviceTimestamp);
+
+ // Now the timestamp of 1000 is reported by evdev and should appear in MotionArgs
+ processPosition(mapper, 0, 0);
+ processTimestamp(mapper, 1000);
+ processMTSync(mapper);
+ processSync(mapper);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
+ ASSERT_EQ(1000U, args.deviceTimestamp);
+}
+
+TEST_F(MultiTouchInputMapperTest, WhenMapperIsReset_TimestampIsCleared) {
+ MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice);
+
+ addConfigurationProperty("touch.deviceType", "touchScreen");
+ prepareDisplay(DISPLAY_ORIENTATION_0);
+ prepareAxes(POSITION);
+ addMapperAndConfigure(mapper);
+ NotifyMotionArgs args;
+
+ // Send a touch event with a timestamp
+ processPosition(mapper, 100, 100);
+ processTimestamp(mapper, 1);
+ processMTSync(mapper);
+ processSync(mapper);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
+ ASSERT_EQ(1U, args.deviceTimestamp);
+
+ // Since the data accumulates, and new timestamp has not arrived, deviceTimestamp won't change
+ processPosition(mapper, 100, 200);
+ processMTSync(mapper);
+ processSync(mapper);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
+ ASSERT_EQ(1U, args.deviceTimestamp);
+
+ mapper->reset(/* when */ 0);
+ // After the mapper is reset, deviceTimestamp should become zero again
+ processPosition(mapper, 100, 300);
+ processMTSync(mapper);
+ processSync(mapper);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
+ ASSERT_EQ(0U, args.deviceTimestamp);
+}
+
} // namespace android
diff --git a/services/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk
index 35fe9de..5b6c1ca 100644
--- a/services/surfaceflinger/Android.mk
+++ b/services/surfaceflinger/Android.mk
@@ -35,6 +35,7 @@
EventLog/EventLogTags.logtags \
EventLog/EventLog.cpp \
RenderEngine/Description.cpp \
+ RenderEngine/Image.cpp \
RenderEngine/Mesh.cpp \
RenderEngine/Program.cpp \
RenderEngine/ProgramCache.cpp \
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index b52bef3..d860f58 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -53,7 +53,7 @@
BufferLayer::BufferLayer(SurfaceFlinger* flinger, const sp<Client>& client, const String8& name,
uint32_t w, uint32_t h, uint32_t flags)
: Layer(flinger, client, name, w, h, flags),
- mSurfaceFlingerConsumer(nullptr),
+ mConsumer(nullptr),
mTextureName(UINT32_MAX),
mFormat(PIXEL_FORMAT_NONE),
mCurrentScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE),
@@ -89,7 +89,7 @@
if (mFlinger->mForceFullDamage) {
surfaceDamageRegion = Region::INVALID_REGION;
} else {
- surfaceDamageRegion = mSurfaceFlingerConsumer->getSurfaceDamage();
+ surfaceDamageRegion = mConsumer->getSurfaceDamage();
}
}
@@ -105,7 +105,8 @@
bool BufferLayer::isVisible() const {
return !(isHiddenByPolicy()) && getAlpha() > 0.0f &&
- (getBE().compositionInfo.mBuffer != NULL || getBE().compositionInfo.hwc.sidebandStream != NULL);
+ (getBE().compositionInfo.mBuffer != nullptr ||
+ getBE().compositionInfo.hwc.sidebandStream != nullptr);
}
bool BufferLayer::isFixedSize() const {
@@ -129,9 +130,9 @@
mProtectedByApp = (flags & ISurfaceComposerClient::eProtectedByApp) ? true : false;
mCurrentOpacity = getOpacityForFormat(format);
- mSurfaceFlingerConsumer->setDefaultBufferSize(w, h);
- mSurfaceFlingerConsumer->setDefaultBufferFormat(format);
- mSurfaceFlingerConsumer->setConsumerUsageBits(getEffectiveUsage(0));
+ mConsumer->setDefaultBufferSize(w, h);
+ mConsumer->setDefaultBufferFormat(format);
+ mConsumer->setConsumerUsageBits(getEffectiveUsage(0));
return NO_ERROR;
}
@@ -190,7 +191,7 @@
// Bind the current buffer to the GL texture, and wait for it to be
// ready for us to draw into.
- status_t err = mSurfaceFlingerConsumer->bindTextureImage();
+ status_t err = mConsumer->bindTextureImage();
if (err != NO_ERROR) {
ALOGW("onDraw: bindTextureImage failed (err=%d)", err);
// Go ahead and draw the buffer anyway; no matter what we do the screen
@@ -207,8 +208,8 @@
// Query the texture matrix given our current filtering mode.
float textureMatrix[16];
- mSurfaceFlingerConsumer->setFilteringEnabled(useFiltering);
- mSurfaceFlingerConsumer->getTransformMatrix(textureMatrix);
+ mConsumer->setFilteringEnabled(useFiltering);
+ mConsumer->getTransformMatrix(textureMatrix);
if (getTransformToDisplayInverse()) {
/*
@@ -253,11 +254,11 @@
}
void BufferLayer::onLayerDisplayed(const sp<Fence>& releaseFence) {
- mSurfaceFlingerConsumer->setReleaseFence(releaseFence);
+ mConsumer->setReleaseFence(releaseFence);
}
void BufferLayer::abandon() {
- mSurfaceFlingerConsumer->abandon();
+ mConsumer->abandon();
}
bool BufferLayer::shouldPresentNow(const DispSync& dispSync) const {
@@ -270,7 +271,7 @@
return false;
}
auto timestamp = mQueueItems[0].mTimestamp;
- nsecs_t expectedPresent = mSurfaceFlingerConsumer->computeExpectedPresent(dispSync);
+ nsecs_t expectedPresent = mConsumer->computeExpectedPresent(dispSync);
// Ignore timestamps more than a second in the future
bool isPlausible = timestamp < (expectedPresent + s2ns(1));
@@ -284,7 +285,7 @@
}
void BufferLayer::setTransformHint(uint32_t orientation) const {
- mSurfaceFlingerConsumer->setTransformHint(orientation);
+ mConsumer->setTransformHint(orientation);
}
bool BufferLayer::onPreComposition(nsecs_t refreshStartTime) {
@@ -312,10 +313,10 @@
}
// Update mFrameTracker.
- nsecs_t desiredPresentTime = mSurfaceFlingerConsumer->getTimestamp();
+ nsecs_t desiredPresentTime = mConsumer->getTimestamp();
mFrameTracker.setDesiredPresentTime(desiredPresentTime);
- std::shared_ptr<FenceTime> frameReadyFence = mSurfaceFlingerConsumer->getCurrentFenceTime();
+ std::shared_ptr<FenceTime> frameReadyFence = mConsumer->getCurrentFenceTime();
if (frameReadyFence->isValid()) {
mFrameTracker.setFrameReadyFence(std::move(frameReadyFence));
} else {
@@ -340,7 +341,7 @@
std::vector<OccupancyTracker::Segment> BufferLayer::getOccupancyHistory(bool forceFlush) {
std::vector<OccupancyTracker::Segment> history;
- status_t result = mSurfaceFlingerConsumer->getOccupancyHistory(forceFlush, &history);
+ status_t result = mConsumer->getOccupancyHistory(forceFlush, &history);
if (result != NO_ERROR) {
ALOGW("[%s] Failed to obtain occupancy history (%d)", mName.string(), result);
return {};
@@ -349,16 +350,16 @@
}
bool BufferLayer::getTransformToDisplayInverse() const {
- return mSurfaceFlingerConsumer->getTransformToDisplayInverse();
+ return mConsumer->getTransformToDisplayInverse();
}
void BufferLayer::releasePendingBuffer(nsecs_t dequeueReadyTime) {
- if (!mSurfaceFlingerConsumer->releasePendingBuffer()) {
+ if (!mConsumer->releasePendingBuffer()) {
return;
}
auto releaseFenceTime =
- std::make_shared<FenceTime>(mSurfaceFlingerConsumer->getPrevFinalReleaseFence());
+ std::make_shared<FenceTime>(mConsumer->getPrevFinalReleaseFence());
mReleaseTimeline.updateSignalTimes();
mReleaseTimeline.push(releaseFenceTime);
@@ -374,10 +375,10 @@
if (android_atomic_acquire_cas(true, false, &mSidebandStreamChanged) == 0) {
// mSidebandStreamChanged was true
- mSidebandStream = mSurfaceFlingerConsumer->getSidebandStream();
+ mSidebandStream = mConsumer->getSidebandStream();
// replicated in LayerBE until FE/BE is ready to be synchronized
getBE().compositionInfo.hwc.sidebandStream = mSidebandStream;
- if (getBE().compositionInfo.hwc.sidebandStream != NULL) {
+ if (getBE().compositionInfo.hwc.sidebandStream != nullptr) {
setTransactionFlags(eTransactionNeeded);
mFlinger->setTransactionFlags(eTraversalNeeded);
}
@@ -427,7 +428,7 @@
getProducerStickyTransform() != 0, mName.string(),
mOverrideScalingMode, mFreezeGeometryUpdates);
status_t updateResult =
- mSurfaceFlingerConsumer->updateTexImage(&r, mFlinger->mPrimaryDispSync,
+ mConsumer->updateTexImage(&r, mFlinger->mPrimaryDispSync,
&mAutoRefresh, &queuedBuffer,
mLastFrameNumberReceived);
if (updateResult == BufferQueue::PRESENT_LATER) {
@@ -466,7 +467,7 @@
if (queuedBuffer) {
// Autolock scope
- auto currentFrameNumber = mSurfaceFlingerConsumer->getFrameNumber();
+ auto currentFrameNumber = mConsumer->getFrameNumber();
Mutex::Autolock lock(mQueueItemLock);
@@ -489,17 +490,17 @@
// update the active buffer
getBE().compositionInfo.mBuffer =
- mSurfaceFlingerConsumer->getCurrentBuffer(&getBE().compositionInfo.mBufferSlot);
+ mConsumer->getCurrentBuffer(&getBE().compositionInfo.mBufferSlot);
// replicated in LayerBE until FE/BE is ready to be synchronized
mActiveBuffer = getBE().compositionInfo.mBuffer;
- if (getBE().compositionInfo.mBuffer == NULL) {
+ if (getBE().compositionInfo.mBuffer == nullptr) {
// this can only happen if the very first buffer was rejected.
return outDirtyRegion;
}
mBufferLatched = true;
mPreviousFrameNumber = mCurrentFrameNumber;
- mCurrentFrameNumber = mSurfaceFlingerConsumer->getFrameNumber();
+ mCurrentFrameNumber = mConsumer->getFrameNumber();
{
Mutex::Autolock lock(mFrameEventHistoryMutex);
@@ -508,17 +509,17 @@
mRefreshPending = true;
mFrameLatencyNeeded = true;
- if (oldBuffer == NULL) {
+ if (oldBuffer == nullptr) {
// the first time we receive a buffer, we need to trigger a
// geometry invalidation.
recomputeVisibleRegions = true;
}
- setDataSpace(mSurfaceFlingerConsumer->getCurrentDataSpace());
+ setDataSpace(mConsumer->getCurrentDataSpace());
- Rect crop(mSurfaceFlingerConsumer->getCurrentCrop());
- const uint32_t transform(mSurfaceFlingerConsumer->getCurrentTransform());
- const uint32_t scalingMode(mSurfaceFlingerConsumer->getCurrentScalingMode());
+ Rect crop(mConsumer->getCurrentCrop());
+ const uint32_t transform(mConsumer->getCurrentTransform());
+ const uint32_t scalingMode(mConsumer->getCurrentScalingMode());
if ((crop != mCurrentCrop) ||
(transform != mCurrentTransform) ||
(scalingMode != mCurrentScalingMode)) {
@@ -528,7 +529,7 @@
recomputeVisibleRegions = true;
}
- if (oldBuffer != NULL) {
+ if (oldBuffer != nullptr) {
uint32_t bufWidth = getBE().compositionInfo.mBuffer->getWidth();
uint32_t bufHeight = getBE().compositionInfo.mBuffer->getHeight();
if (bufWidth != uint32_t(oldBuffer->width) ||
@@ -573,7 +574,7 @@
}
void BufferLayer::setDefaultBufferSize(uint32_t w, uint32_t h) {
- mSurfaceFlingerConsumer->setDefaultBufferSize(w, h);
+ mConsumer->setDefaultBufferSize(w, h);
}
void BufferLayer::setPerFrameData(const sp<const DisplayDevice>& displayDevice) {
@@ -633,7 +634,7 @@
hwcInfo.bufferCache.getHwcBuffer(getBE().compositionInfo.mBufferSlot,
getBE().compositionInfo.mBuffer, &hwcSlot, &hwcBuffer);
- auto acquireFence = mSurfaceFlingerConsumer->getCurrentFence();
+ auto acquireFence = mConsumer->getCurrentFence();
error = hwcLayer->setBuffer(hwcSlot, hwcBuffer, acquireFence);
if (error != HWC2::Error::None) {
ALOGE("[%s] Failed to set buffer %p: %s (%d)", mName.string(),
@@ -660,10 +661,11 @@
sp<IGraphicBufferConsumer> consumer;
BufferQueue::createBufferQueue(&producer, &consumer, true);
mProducer = new MonitoredProducer(producer, mFlinger, this);
- mSurfaceFlingerConsumer = new BufferLayerConsumer(consumer, mTextureName, this);
- mSurfaceFlingerConsumer->setConsumerUsageBits(getEffectiveUsage(0));
- mSurfaceFlingerConsumer->setContentsChangedListener(this);
- mSurfaceFlingerConsumer->setName(mName);
+ mConsumer = new BufferLayerConsumer(consumer,
+ mFlinger->getRenderEngine(), mTextureName, this);
+ mConsumer->setConsumerUsageBits(getEffectiveUsage(0));
+ mConsumer->setContentsChangedListener(this);
+ mConsumer->setName(mName);
if (mFlinger->isLayerTripleBufferingDisabled()) {
mProducer->setMaxDequeuedBufferCount(2);
@@ -787,16 +789,17 @@
* minimal value)? Or, we could make GL behave like HWC -- but this feel
* like more of a hack.
*/
- Rect win(computeBounds());
+ const Rect bounds{computeBounds()}; // Rounds from FloatRect
Transform t = getTransform();
+ Rect win = bounds;
if (!s.finalCrop.isEmpty()) {
win = t.transform(win);
if (!win.intersect(s.finalCrop, &win)) {
win.clear();
}
win = t.inverse().transform(win);
- if (!win.intersect(computeBounds(), &win)) {
+ if (!win.intersect(bounds, &win)) {
win.clear();
}
}
diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h
index fbe6367..6b02f8c 100644
--- a/services/surfaceflinger/BufferLayer.h
+++ b/services/surfaceflinger/BufferLayer.h
@@ -170,7 +170,7 @@
sp<IGraphicBufferProducer> getProducer() const;
private:
- sp<BufferLayerConsumer> mSurfaceFlingerConsumer;
+ sp<BufferLayerConsumer> mConsumer;
// Check all of the local sync points to ensure that all transactions
// which need to have been applied prior to the frame which is about to
diff --git a/services/surfaceflinger/BufferLayerConsumer.cpp b/services/surfaceflinger/BufferLayerConsumer.cpp
index 5569dfa..8f5c9c7 100644
--- a/services/surfaceflinger/BufferLayerConsumer.cpp
+++ b/services/surfaceflinger/BufferLayerConsumer.cpp
@@ -23,13 +23,10 @@
#include "DispSync.h"
#include "Layer.h"
+#include "RenderEngine/RenderEngine.h"
#include <inttypes.h>
-#include <EGL/egl.h>
-#include <EGL/eglext.h>
-#include <GLES2/gl2.h>
-#include <GLES2/gl2ext.h>
#include <cutils/compiler.h>
#include <hardware/hardware.h>
@@ -48,11 +45,6 @@
#include <utils/String8.h>
#include <utils/Trace.h>
-extern "C" EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name);
-#define CROP_EXT_STR "EGL_ANDROID_image_crop"
-#define PROT_CONTENT_EXT_STR "EGL_EXT_protected_content"
-#define EGL_PROTECTED_CONTENT_EXT 0x32C0
-
namespace android {
// Macros for including the BufferLayerConsumer name in log messages
@@ -64,52 +56,8 @@
static const mat4 mtxIdentity;
-static bool hasEglAndroidImageCropImpl() {
- EGLDisplay dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
- const char* exts = eglQueryStringImplementationANDROID(dpy, EGL_EXTENSIONS);
- size_t cropExtLen = strlen(CROP_EXT_STR);
- size_t extsLen = strlen(exts);
- bool equal = !strcmp(CROP_EXT_STR, exts);
- bool atStart = !strncmp(CROP_EXT_STR " ", exts, cropExtLen + 1);
- bool atEnd = (cropExtLen + 1) < extsLen &&
- !strcmp(" " CROP_EXT_STR, exts + extsLen - (cropExtLen + 1));
- bool inMiddle = strstr(exts, " " CROP_EXT_STR " ");
- return equal || atStart || atEnd || inMiddle;
-}
-
-static bool hasEglAndroidImageCrop() {
- // Only compute whether the extension is present once the first time this
- // function is called.
- static bool hasIt = hasEglAndroidImageCropImpl();
- return hasIt;
-}
-
-static bool hasEglProtectedContentImpl() {
- EGLDisplay dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
- const char* exts = eglQueryString(dpy, EGL_EXTENSIONS);
- size_t cropExtLen = strlen(PROT_CONTENT_EXT_STR);
- size_t extsLen = strlen(exts);
- bool equal = !strcmp(PROT_CONTENT_EXT_STR, exts);
- bool atStart = !strncmp(PROT_CONTENT_EXT_STR " ", exts, cropExtLen + 1);
- bool atEnd = (cropExtLen + 1) < extsLen &&
- !strcmp(" " PROT_CONTENT_EXT_STR, exts + extsLen - (cropExtLen + 1));
- bool inMiddle = strstr(exts, " " PROT_CONTENT_EXT_STR " ");
- return equal || atStart || atEnd || inMiddle;
-}
-
-static bool hasEglProtectedContent() {
- // Only compute whether the extension is present once the first time this
- // function is called.
- static bool hasIt = hasEglProtectedContentImpl();
- return hasIt;
-}
-
-static bool isEglImageCroppable(const Rect& crop) {
- return hasEglAndroidImageCrop() && (crop.left == 0 && crop.top == 0);
-}
-
-BufferLayerConsumer::BufferLayerConsumer(const sp<IGraphicBufferConsumer>& bq, uint32_t tex,
- Layer* layer)
+BufferLayerConsumer::BufferLayerConsumer(const sp<IGraphicBufferConsumer>& bq, RenderEngine& engine,
+ uint32_t tex, Layer* layer)
: ConsumerBase(bq, false),
mCurrentCrop(Rect::EMPTY_RECT),
mCurrentTransform(0),
@@ -123,10 +71,9 @@
mDefaultWidth(1),
mDefaultHeight(1),
mFilteringEnabled(true),
+ mRE(engine),
mTexName(tex),
mLayer(layer),
- mEglDisplay(EGL_NO_DISPLAY),
- mEglContext(EGL_NO_CONTEXT),
mCurrentTexture(BufferQueue::INVALID_BUFFER_SLOT) {
BLC_LOGV("BufferLayerConsumer");
@@ -211,10 +158,10 @@
return NO_INIT;
}
- // Make sure the EGL state is the same as in previous calls.
- status_t err = checkAndUpdateEglStateLocked();
- if (err != NO_ERROR) {
- return err;
+ // Make sure RenderEngine is current
+ if (!mRE.isCurrent()) {
+ BLC_LOGE("updateTexImage: RenderEngine is not current");
+ return INVALID_OPERATION;
}
BufferItem item;
@@ -222,7 +169,7 @@
// Acquire the next buffer.
// In asynchronous mode the list is guaranteed to be one buffer
// deep, while in synchronous mode we use the oldest buffer.
- err = acquireBufferLocked(&item, computeExpectedPresent(dispSync), maxFrameNumber);
+ status_t err = acquireBufferLocked(&item, computeExpectedPresent(dispSync), maxFrameNumber);
if (err != NO_ERROR) {
if (err == BufferQueue::NO_BUFFER_AVAILABLE) {
err = NO_ERROR;
@@ -324,43 +271,30 @@
// If item->mGraphicBuffer is not null, this buffer has not been acquired
// before, so any prior EglImage created is using a stale buffer. This
// replaces any old EglImage with a new one (using the new buffer).
- if (item->mGraphicBuffer != NULL) {
- int slot = item->mSlot;
- mEglSlots[slot].mEglImage = new EglImage(item->mGraphicBuffer);
+ if (item->mGraphicBuffer != nullptr) {
+ mImages[item->mSlot] = new Image(item->mGraphicBuffer, mRE);
}
return NO_ERROR;
}
+bool BufferLayerConsumer::canUseImageCrop(const Rect& crop) const {
+ // If the crop rect is not at the origin, we can't set the crop on the
+ // EGLImage because that's not allowed by the EGL_ANDROID_image_crop
+ // extension. In the future we can add a layered extension that
+ // removes this restriction if there is hardware that can support it.
+ return mRE.supportsImageCrop() && crop.left == 0 && crop.top == 0;
+}
+
status_t BufferLayerConsumer::updateAndReleaseLocked(const BufferItem& item,
PendingRelease* pendingRelease) {
status_t err = NO_ERROR;
int slot = item.mSlot;
- // Confirm state.
- err = checkAndUpdateEglStateLocked();
- if (err != NO_ERROR) {
- releaseBufferLocked(slot, mSlots[slot].mGraphicBuffer);
- return err;
- }
-
- // Ensure we have a valid EglImageKHR for the slot, creating an EglImage
- // if nessessary, for the gralloc buffer currently in the slot in
- // ConsumerBase.
- // We may have to do this even when item.mGraphicBuffer == NULL (which
- // means the buffer was previously acquired).
- err = mEglSlots[slot].mEglImage->createIfNeeded(mEglDisplay, item.mCrop);
- if (err != NO_ERROR) {
- BLC_LOGW("updateAndRelease: unable to createImage on display=%p slot=%d", mEglDisplay,
- slot);
- releaseBufferLocked(slot, mSlots[slot].mGraphicBuffer);
- return UNKNOWN_ERROR;
- }
-
// Do whatever sync ops we need to do before releasing the old slot.
if (slot != mCurrentTexture) {
- err = syncForReleaseLocked(mEglDisplay);
+ err = syncForReleaseLocked();
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.
@@ -372,13 +306,13 @@
}
BLC_LOGV("updateAndRelease: (slot=%d buf=%p) -> (slot=%d buf=%p)", mCurrentTexture,
- mCurrentTextureImage != NULL ? mCurrentTextureImage->graphicBufferHandle() : 0, slot,
- mSlots[slot].mGraphicBuffer->handle);
+ mCurrentTextureImage != nullptr ? mCurrentTextureImage->graphicBufferHandle() : 0,
+ slot, mSlots[slot].mGraphicBuffer->handle);
// Hang onto the pointer so that it isn't freed in the call to
// releaseBufferLocked() if we're in shared buffer mode and both buffers are
// the same.
- sp<EglImage> nextTextureImage = mEglSlots[slot].mEglImage;
+ sp<Image> nextTextureImage = mImages[slot];
// release old buffer
if (mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) {
@@ -406,6 +340,7 @@
mCurrentScalingMode = item.mScalingMode;
mCurrentTimestamp = item.mTimestamp;
mCurrentDataSpace = item.mDataSpace;
+ mCurrentHdrMetadata = item.mHdrMetadata;
mCurrentFence = item.mFence;
mCurrentFenceTime = item.mFenceTime;
mCurrentFrameNumber = item.mFrameNumber;
@@ -418,80 +353,39 @@
}
status_t BufferLayerConsumer::bindTextureImageLocked() {
- if (mEglDisplay == EGL_NO_DISPLAY) {
- ALOGE("bindTextureImage: invalid display");
- return INVALID_OPERATION;
- }
+ mRE.checkErrors();
- GLenum error;
- while ((error = glGetError()) != GL_NO_ERROR) {
- BLC_LOGW("bindTextureImage: clearing GL error: %#04x", error);
- }
-
- glBindTexture(sTexTarget, mTexName);
- if (mCurrentTexture == BufferQueue::INVALID_BUFFER_SLOT && mCurrentTextureImage == NULL) {
+ if (mCurrentTexture == BufferQueue::INVALID_BUFFER_SLOT && mCurrentTextureImage == nullptr) {
BLC_LOGE("bindTextureImage: no currently-bound texture");
+ mRE.bindExternalTextureImage(mTexName, RE::Image(mRE));
return NO_INIT;
}
- status_t err = mCurrentTextureImage->createIfNeeded(mEglDisplay, mCurrentCrop);
+ const Rect& imageCrop = canUseImageCrop(mCurrentCrop) ? mCurrentCrop : Rect::EMPTY_RECT;
+ status_t err = mCurrentTextureImage->createIfNeeded(imageCrop);
if (err != NO_ERROR) {
- BLC_LOGW("bindTextureImage: can't create image on display=%p slot=%d", mEglDisplay,
- mCurrentTexture);
+ BLC_LOGW("bindTextureImage: can't create image on slot=%d", mCurrentTexture);
+ mRE.bindExternalTextureImage(mTexName, RE::Image(mRE));
return UNKNOWN_ERROR;
}
- mCurrentTextureImage->bindToTextureTarget(sTexTarget);
+
+ mRE.bindExternalTextureImage(mTexName, mCurrentTextureImage->image());
// Wait for the new buffer to be ready.
- return doGLFenceWaitLocked();
+ return doFenceWaitLocked();
}
-status_t BufferLayerConsumer::checkAndUpdateEglStateLocked() {
- EGLDisplay dpy = eglGetCurrentDisplay();
- EGLContext ctx = eglGetCurrentContext();
-
- // if this is the first time we're called, mEglDisplay/mEglContext have
- // never been set, so don't error out (below).
- if (mEglDisplay == EGL_NO_DISPLAY) {
- mEglDisplay = dpy;
- }
- if (mEglContext == EGL_NO_CONTEXT) {
- mEglContext = ctx;
- }
-
- if (mEglDisplay != dpy || dpy == EGL_NO_DISPLAY) {
- BLC_LOGE("checkAndUpdateEglState: invalid current EGLDisplay");
- return INVALID_OPERATION;
- }
-
- if (mEglContext != ctx || ctx == EGL_NO_CONTEXT) {
- BLC_LOGE("checkAndUpdateEglState: invalid current EGLContext");
- return INVALID_OPERATION;
- }
-
- return NO_ERROR;
-}
-
-status_t BufferLayerConsumer::syncForReleaseLocked(EGLDisplay dpy) {
+status_t BufferLayerConsumer::syncForReleaseLocked() {
BLC_LOGV("syncForReleaseLocked");
if (mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) {
if (SyncFeatures::getInstance().useNativeFenceSync()) {
- EGLSyncKHR sync = eglCreateSyncKHR(dpy, EGL_SYNC_NATIVE_FENCE_ANDROID, NULL);
- if (sync == EGL_NO_SYNC_KHR) {
- BLC_LOGE("syncForReleaseLocked: error creating EGL fence: %#x", eglGetError());
+ base::unique_fd fenceFd = mRE.flush();
+ if (fenceFd == -1) {
+ BLC_LOGE("syncForReleaseLocked: failed to flush RenderEngine");
return UNKNOWN_ERROR;
}
- glFlush();
- int fenceFd = eglDupNativeFenceFDANDROID(dpy, sync);
- eglDestroySyncKHR(dpy, sync);
- if (fenceFd == EGL_NO_NATIVE_FENCE_FD_ANDROID) {
- BLC_LOGE("syncForReleaseLocked: error dup'ing native fence "
- "fd: %#x",
- eglGetError());
- return UNKNOWN_ERROR;
- }
- sp<Fence> fence(new Fence(fenceFd));
+ sp<Fence> fence(new Fence(std::move(fenceFd)));
status_t err = addReleaseFenceLocked(mCurrentTexture,
mCurrentTextureImage->graphicBuffer(), fence);
if (err != OK) {
@@ -520,11 +414,11 @@
bool needsRecompute = mFilteringEnabled != enabled;
mFilteringEnabled = enabled;
- if (needsRecompute && mCurrentTextureImage == NULL) {
- BLC_LOGD("setFilteringEnabled called with mCurrentTextureImage == NULL");
+ if (needsRecompute && mCurrentTextureImage == nullptr) {
+ BLC_LOGD("setFilteringEnabled called with mCurrentTextureImage == nullptr");
}
- if (needsRecompute && mCurrentTextureImage != NULL) {
+ if (needsRecompute && mCurrentTextureImage != nullptr) {
computeCurrentTransformMatrixLocked();
}
}
@@ -535,12 +429,11 @@
(mCurrentTextureImage == nullptr) ? nullptr : mCurrentTextureImage->graphicBuffer();
if (buf == nullptr) {
BLC_LOGD("computeCurrentTransformMatrixLocked: "
- "mCurrentTextureImage is NULL");
+ "mCurrentTextureImage is nullptr");
}
- GLConsumer::computeTransformMatrix(mCurrentTransformMatrix, buf,
- isEglImageCroppable(mCurrentCrop) ? Rect::EMPTY_RECT
- : mCurrentCrop,
- mCurrentTransform, mFilteringEnabled);
+ const Rect& cropRect = canUseImageCrop(mCurrentCrop) ? Rect::EMPTY_RECT : mCurrentCrop;
+ GLConsumer::computeTransformMatrix(mCurrentTransformMatrix, buf, cropRect, mCurrentTransform,
+ mFilteringEnabled);
}
nsecs_t BufferLayerConsumer::getTimestamp() {
@@ -555,6 +448,12 @@
return mCurrentDataSpace;
}
+const HdrMetadata& BufferLayerConsumer::getCurrentHdrMetadata() const {
+ BLC_LOGV("getCurrentHdrMetadata");
+ Mutex::Autolock lock(mMutex);
+ return mCurrentHdrMetadata;
+}
+
uint64_t BufferLayerConsumer::getFrameNumber() {
BLC_LOGV("getFrameNumber");
Mutex::Autolock lock(mMutex);
@@ -577,7 +476,7 @@
*outSlot = mCurrentTexture;
}
- return (mCurrentTextureImage == nullptr) ? NULL : mCurrentTextureImage->graphicBuffer();
+ return (mCurrentTextureImage == nullptr) ? nullptr : mCurrentTextureImage->graphicBuffer();
}
Rect BufferLayerConsumer::getCurrentCrop() const {
@@ -607,50 +506,27 @@
return mCurrentFenceTime;
}
-status_t BufferLayerConsumer::doGLFenceWaitLocked() const {
- EGLDisplay dpy = eglGetCurrentDisplay();
- EGLContext ctx = eglGetCurrentContext();
-
- if (mEglDisplay != dpy || mEglDisplay == EGL_NO_DISPLAY) {
- BLC_LOGE("doGLFenceWait: invalid current EGLDisplay");
- return INVALID_OPERATION;
- }
-
- if (mEglContext != ctx || mEglContext == EGL_NO_CONTEXT) {
- BLC_LOGE("doGLFenceWait: invalid current EGLContext");
+status_t BufferLayerConsumer::doFenceWaitLocked() const {
+ if (!mRE.isCurrent()) {
+ BLC_LOGE("doFenceWait: RenderEngine is not current");
return INVALID_OPERATION;
}
if (mCurrentFence->isValid()) {
if (SyncFeatures::getInstance().useWaitSync()) {
- // Create an EGLSyncKHR from the current fence.
- int fenceFd = mCurrentFence->dup();
+ base::unique_fd fenceFd(mCurrentFence->dup());
if (fenceFd == -1) {
- BLC_LOGE("doGLFenceWait: error dup'ing fence fd: %d", errno);
+ BLC_LOGE("doFenceWait: error dup'ing fence fd: %d", errno);
return -errno;
}
- EGLint attribs[] = {EGL_SYNC_NATIVE_FENCE_FD_ANDROID, fenceFd, EGL_NONE};
- EGLSyncKHR sync = eglCreateSyncKHR(dpy, EGL_SYNC_NATIVE_FENCE_ANDROID, attribs);
- if (sync == EGL_NO_SYNC_KHR) {
- close(fenceFd);
- BLC_LOGE("doGLFenceWait: error creating EGL fence: %#x", eglGetError());
- return UNKNOWN_ERROR;
- }
-
- // XXX: The spec draft is inconsistent as to whether this should
- // return an EGLint or void. Ignore the return value for now, as
- // it's not strictly needed.
- eglWaitSyncKHR(dpy, sync, 0);
- EGLint eglErr = eglGetError();
- eglDestroySyncKHR(dpy, sync);
- if (eglErr != EGL_SUCCESS) {
- BLC_LOGE("doGLFenceWait: error waiting for EGL fence: %#x", eglErr);
+ if (!mRE.waitFence(std::move(fenceFd))) {
+ BLC_LOGE("doFenceWait: failed to wait on fence fd");
return UNKNOWN_ERROR;
}
} else {
- status_t err = mCurrentFence->waitForever("BufferLayerConsumer::doGLFenceWaitLocked");
+ status_t err = mCurrentFence->waitForever("BufferLayerConsumer::doFenceWaitLocked");
if (err != NO_ERROR) {
- BLC_LOGE("doGLFenceWait: error waiting for fence: %d", err);
+ BLC_LOGE("doFenceWait: error waiting for fence: %d", err);
return err;
}
}
@@ -664,7 +540,7 @@
if (slotIndex == mCurrentTexture) {
mCurrentTexture = BufferQueue::INVALID_BUFFER_SLOT;
}
- mEglSlots[slotIndex].mEglImage.clear();
+ mImages[slotIndex].clear();
ConsumerBase::freeBufferLocked(slotIndex);
}
@@ -688,7 +564,7 @@
listener = mContentsChangedListener.promote();
}
- if (listener != NULL) {
+ if (listener != nullptr) {
listener->onSidebandStreamChanged();
}
}
@@ -721,106 +597,37 @@
ConsumerBase::dumpLocked(result, prefix);
}
-BufferLayerConsumer::EglImage::EglImage(sp<GraphicBuffer> graphicBuffer)
+BufferLayerConsumer::Image::Image(sp<GraphicBuffer> graphicBuffer, const RenderEngine& engine)
: mGraphicBuffer(graphicBuffer),
- mEglImage(EGL_NO_IMAGE_KHR),
- mEglDisplay(EGL_NO_DISPLAY),
- mCropRect(Rect::EMPTY_RECT) {}
+ mImage{engine},
+ mCreated(false),
+ mCropWidth(0),
+ mCropHeight(0) {}
-BufferLayerConsumer::EglImage::~EglImage() {
- if (mEglImage != EGL_NO_IMAGE_KHR) {
- if (!eglDestroyImageKHR(mEglDisplay, mEglImage)) {
- ALOGE("~EglImage: eglDestroyImageKHR failed");
- }
- eglTerminate(mEglDisplay);
- }
-}
-
-status_t BufferLayerConsumer::EglImage::createIfNeeded(EGLDisplay eglDisplay,
- const Rect& cropRect) {
- // If there's an image and it's no longer valid, destroy it.
- bool haveImage = mEglImage != EGL_NO_IMAGE_KHR;
- bool displayInvalid = mEglDisplay != eglDisplay;
- bool cropInvalid = hasEglAndroidImageCrop() && mCropRect != cropRect;
- if (haveImage && (displayInvalid || cropInvalid)) {
- if (!eglDestroyImageKHR(mEglDisplay, mEglImage)) {
- ALOGE("createIfNeeded: eglDestroyImageKHR failed");
- }
- eglTerminate(mEglDisplay);
- mEglImage = EGL_NO_IMAGE_KHR;
- mEglDisplay = EGL_NO_DISPLAY;
+status_t BufferLayerConsumer::Image::createIfNeeded(const Rect& imageCrop) {
+ const int32_t cropWidth = imageCrop.width();
+ const int32_t cropHeight = imageCrop.height();
+ if (mCreated && mCropWidth == cropWidth && mCropHeight == cropHeight) {
+ return OK;
}
- // If there's no image, create one.
- if (mEglImage == EGL_NO_IMAGE_KHR) {
- mEglDisplay = eglDisplay;
- mCropRect = cropRect;
- mEglImage = createImage(mEglDisplay, mGraphicBuffer, mCropRect);
- }
+ mCreated = mImage.setNativeWindowBuffer(mGraphicBuffer->getNativeBuffer(),
+ mGraphicBuffer->getUsage() & GRALLOC_USAGE_PROTECTED,
+ cropWidth, cropHeight);
+ if (mCreated) {
+ mCropWidth = cropWidth;
+ mCropHeight = cropHeight;
+ } else {
+ mCropWidth = 0;
+ mCropHeight = 0;
- // Fail if we can't create a valid image.
- if (mEglImage == EGL_NO_IMAGE_KHR) {
- mEglDisplay = EGL_NO_DISPLAY;
- mCropRect.makeInvalid();
const sp<GraphicBuffer>& buffer = mGraphicBuffer;
ALOGE("Failed to create image. size=%ux%u st=%u usage=%#" PRIx64 " fmt=%d",
buffer->getWidth(), buffer->getHeight(), buffer->getStride(), buffer->getUsage(),
buffer->getPixelFormat());
- return UNKNOWN_ERROR;
}
- return OK;
-}
-
-void BufferLayerConsumer::EglImage::bindToTextureTarget(uint32_t texTarget) {
- glEGLImageTargetTexture2DOES(texTarget, static_cast<GLeglImageOES>(mEglImage));
-}
-
-EGLImageKHR BufferLayerConsumer::EglImage::createImage(EGLDisplay dpy,
- const sp<GraphicBuffer>& graphicBuffer,
- const Rect& crop) {
- EGLClientBuffer cbuf = static_cast<EGLClientBuffer>(graphicBuffer->getNativeBuffer());
- const bool createProtectedImage =
- (graphicBuffer->getUsage() & GRALLOC_USAGE_PROTECTED) && hasEglProtectedContent();
- EGLint attrs[] = {
- EGL_IMAGE_PRESERVED_KHR,
- EGL_TRUE,
- EGL_IMAGE_CROP_LEFT_ANDROID,
- crop.left,
- EGL_IMAGE_CROP_TOP_ANDROID,
- crop.top,
- EGL_IMAGE_CROP_RIGHT_ANDROID,
- crop.right,
- EGL_IMAGE_CROP_BOTTOM_ANDROID,
- crop.bottom,
- createProtectedImage ? EGL_PROTECTED_CONTENT_EXT : EGL_NONE,
- createProtectedImage ? EGL_TRUE : EGL_NONE,
- EGL_NONE,
- };
- if (!crop.isValid()) {
- // No crop rect to set, so leave the crop out of the attrib array. Make
- // sure to propagate the protected content attrs if they are set.
- attrs[2] = attrs[10];
- attrs[3] = attrs[11];
- attrs[4] = EGL_NONE;
- } else if (!isEglImageCroppable(crop)) {
- // The crop rect is not at the origin, so we can't set the crop on the
- // EGLImage because that's not allowed by the EGL_ANDROID_image_crop
- // extension. In the future we can add a layered extension that
- // removes this restriction if there is hardware that can support it.
- attrs[2] = attrs[10];
- attrs[3] = attrs[11];
- attrs[4] = EGL_NONE;
- }
- eglInitialize(dpy, 0, 0);
- EGLImageKHR image =
- eglCreateImageKHR(dpy, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID, cbuf, attrs);
- if (image == EGL_NO_IMAGE_KHR) {
- EGLint error = eglGetError();
- ALOGE("error creating EGLImage: %#x", error);
- eglTerminate(dpy);
- }
- return image;
+ return mCreated ? OK : UNKNOWN_ERROR;
}
}; // namespace android
diff --git a/services/surfaceflinger/BufferLayerConsumer.h b/services/surfaceflinger/BufferLayerConsumer.h
index cc35a66..f473390 100644
--- a/services/surfaceflinger/BufferLayerConsumer.h
+++ b/services/surfaceflinger/BufferLayerConsumer.h
@@ -17,11 +17,11 @@
#ifndef ANDROID_BUFFERLAYERCONSUMER_H
#define ANDROID_BUFFERLAYERCONSUMER_H
-#include <EGL/egl.h>
-#include <EGL/eglext.h>
+#include "RenderEngine/Image.h"
#include <gui/BufferQueueDefs.h>
#include <gui/ConsumerBase.h>
+#include <gui/HdrMetadata.h>
#include <ui/FenceTime.h>
#include <ui/GraphicBuffer.h>
@@ -36,23 +36,20 @@
class DispSync;
class Layer;
+class RenderEngine;
class String8;
/*
* BufferLayerConsumer consumes buffers of graphics data from a BufferQueue,
- * and makes them available to OpenGL as a texture.
+ * and makes them available to RenderEngine as a texture.
*
- * A typical usage pattern is to set up the BufferLayerConsumer with the
- * desired options, and call updateTexImage() when a new frame is desired.
- * If a new frame is available, the texture will be updated. If not,
- * the previous contents are retained.
+ * A typical usage pattern is to call updateTexImage() when a new frame is
+ * desired. If a new frame is available, the frame is latched. If not, the
+ * previous contents are retained. The texture is attached and updated after
+ * bindTextureImage() is called.
*
- * The texture is attached to the GL_TEXTURE_EXTERNAL_OES texture target, in
- * the EGL context of the first thread that calls updateTexImage(). After that
- * point, all calls to updateTexImage must be made with the same OpenGL ES
- * context current.
- *
- * This class was previously called SurfaceTexture.
+ * All calls to updateTexImage must be made with RenderEngine being current.
+ * The texture is attached to the TEXTURE_EXTERNAL texture target.
*/
class BufferLayerConsumer : public ConsumerBase {
public:
@@ -70,10 +67,11 @@
virtual void onSidebandStreamChanged() = 0;
};
- // BufferLayerConsumer constructs a new BufferLayerConsumer object.
- // The tex parameter indicates the name of the OpenGL ES
- // texture to which images are to be streamed.
- BufferLayerConsumer(const sp<IGraphicBufferConsumer>& bq, uint32_t tex, Layer* layer);
+ // BufferLayerConsumer constructs a new BufferLayerConsumer object. The
+ // tex parameter indicates the name of the RenderEngine texture to which
+ // images are to be streamed.
+ BufferLayerConsumer(const sp<IGraphicBufferConsumer>& bq, RenderEngine& engine, uint32_t tex,
+ Layer* layer);
// Sets the contents changed listener. This should be used instead of
// ConsumerBase::setFrameAvailableListener().
@@ -84,15 +82,14 @@
// updateTexImage acquires the most recently queued buffer, and sets the
// image contents of the target texture to it.
//
- // This call may only be made while the OpenGL ES context to which the
- // target texture belongs is bound to the calling thread.
+ // This call may only be made while RenderEngine is current.
//
- // This calls doGLFenceWait to ensure proper synchronization.
+ // This calls doFenceWait to ensure proper synchronization unless native
+ // fence is supported.
//
- // This version of updateTexImage() takes a functor that may be used to
- // reject the newly acquired buffer. Unlike the GLConsumer version,
- // this does not guarantee that the buffer has been bound to the GL
- // texture.
+ // Unlike the GLConsumer version, this version takes a functor that may be
+ // used to reject the newly acquired buffer. It also does not bind the
+ // RenderEngine texture until bindTextureImage is called.
status_t updateTexImage(BufferRejecter* rejecter, const DispSync& dispSync, bool* autoRefresh,
bool* queuedBuffer, uint64_t maxFrameNumber);
@@ -110,24 +107,7 @@
sp<Fence> getPrevFinalReleaseFence() const;
- // getTransformMatrix retrieves the 4x4 texture coordinate transform matrix
- // associated with the texture image set by the most recent call to
- // updateTexImage.
- //
- // This transform matrix maps 2D homogeneous texture coordinates of the form
- // (s, t, 0, 1) with s and t in the inclusive range [0, 1] to the texture
- // coordinate that should be used to sample that location from the texture.
- // Sampling the texture outside of the range of this transform is undefined.
- //
- // This transform is necessary to compensate for transforms that the stream
- // content producer may implicitly apply to the content. By forcing users of
- // a BufferLayerConsumer to apply this transform we avoid performing an extra
- // copy of the data that would be needed to hide the transform from the
- // user.
- //
- // The matrix is stored in column-major order so that it may be passed
- // directly to OpenGL ES via the glLoadMatrixf or glUniformMatrix4fv
- // functions.
+ // See GLConsumer::getTransformMatrix.
void getTransformMatrix(float mtx[16]);
// getTimestamp retrieves the timestamp associated with the texture image
@@ -142,6 +122,10 @@
// set by the most recent call to updateTexImage.
android_dataspace getCurrentDataSpace();
+ // getCurrentHdrMetadata retrieves the HDR metadata associated with the
+ // texture image set by the most recent call to updateTexImage.
+ const HdrMetadata& getCurrentHdrMetadata() const;
+
// getFrameNumber retrieves the frame number associated with the texture
// image set by the most recent call to updateTexImage.
//
@@ -154,14 +138,7 @@
// must be called from SF main thread
const Region& getSurfaceDamage() const;
- // setDefaultBufferSize is used to set the size of buffers returned by
- // requestBuffers when a with and height of zero is requested.
- // A call to setDefaultBufferSize() may trigger requestBuffers() to
- // be called from the client.
- // The width and height parameters must be no greater than the minimum of
- // GL_MAX_VIEWPORT_DIMS and GL_MAX_TEXTURE_SIZE (see: glGetIntegerv).
- // An error due to invalid dimensions might not be reported until
- // updateTexImage() is called.
+ // See GLConsumer::setDefaultBufferSize.
status_t setDefaultBufferSize(uint32_t width, uint32_t height);
// setFilteringEnabled sets whether the transform matrix should be computed
@@ -204,10 +181,12 @@
virtual void dumpLocked(String8& result, const char* prefix) const;
// acquireBufferLocked overrides the ConsumerBase method to update the
- // mEglSlots array in addition to the ConsumerBase behavior.
+ // mImages array in addition to the ConsumerBase behavior.
virtual status_t acquireBufferLocked(BufferItem* item, nsecs_t presentWhen,
uint64_t maxFrameNumber = 0) override;
+ bool canUseImageCrop(const Rect& crop) const;
+
struct PendingRelease {
PendingRelease() : isPending(false), currentTexture(-1), graphicBuffer() {}
@@ -225,70 +204,54 @@
status_t updateAndReleaseLocked(const BufferItem& item,
PendingRelease* pendingRelease = nullptr);
- // Binds mTexName and the current buffer to sTexTarget. Uses
+ // Binds mTexName and the current buffer to TEXTURE_EXTERNAL target. Uses
// mCurrentTexture if it's set, mCurrentTextureImage if not. If the
- // bind succeeds, this calls doGLFenceWait.
+ // bind succeeds, this calls doFenceWait.
status_t bindTextureImageLocked();
- // Gets the current EGLDisplay and EGLContext values, and compares them
- // to mEglDisplay and mEglContext. If the fields have been previously
- // set, the values must match; if not, the fields are set to the current
- // values.
- status_t checkAndUpdateEglStateLocked();
-
private:
- // EglImage is a utility class for tracking and creating EGLImageKHRs. There
+ // Image is a utility class for tracking and creating RE::Images. There
// is primarily just one image per slot, but there is also special cases:
// - After freeBuffer, we must still keep the current image/buffer
- // Reference counting EGLImages lets us handle all these cases easily while
- // also only creating new EGLImages from buffers when required.
- class EglImage : public LightRefBase<EglImage> {
+ // Reference counting RE::Images lets us handle all these cases easily while
+ // also only creating new RE::Images from buffers when required.
+ class Image : public LightRefBase<Image> {
public:
- EglImage(sp<GraphicBuffer> graphicBuffer);
+ Image(sp<GraphicBuffer> graphicBuffer, const RenderEngine& engine);
- // createIfNeeded creates an EGLImage if required (we haven't created
- // one yet, or the EGLDisplay or crop-rect has changed).
- status_t createIfNeeded(EGLDisplay display, const Rect& cropRect);
+ Image(const Image& rhs) = delete;
+ Image& operator=(const Image& rhs) = delete;
- // This calls glEGLImageTargetTexture2DOES to bind the image to the
- // texture in the specified texture target.
- void bindToTextureTarget(uint32_t texTarget);
+ // createIfNeeded creates an RE::Image if required (we haven't created
+ // one yet, or the crop-rect has changed).
+ status_t createIfNeeded(const Rect& imageCrop);
const sp<GraphicBuffer>& graphicBuffer() { return mGraphicBuffer; }
const native_handle* graphicBufferHandle() {
- return mGraphicBuffer == NULL ? NULL : mGraphicBuffer->handle;
+ return mGraphicBuffer == nullptr ? nullptr : mGraphicBuffer->handle;
}
+ const RE::Image& image() const { return mImage; }
+
private:
// Only allow instantiation using ref counting.
- friend class LightRefBase<EglImage>;
- virtual ~EglImage();
-
- // createImage creates a new EGLImage from a GraphicBuffer.
- EGLImageKHR createImage(EGLDisplay dpy, const sp<GraphicBuffer>& graphicBuffer,
- const Rect& crop);
-
- // Disallow copying
- EglImage(const EglImage& rhs);
- void operator=(const EglImage& rhs);
+ friend class LightRefBase<Image>;
+ virtual ~Image() = default;
// mGraphicBuffer is the buffer that was used to create this image.
sp<GraphicBuffer> mGraphicBuffer;
- // mEglImage is the EGLImage created from mGraphicBuffer.
- EGLImageKHR mEglImage;
-
- // mEGLDisplay is the EGLDisplay that was used to create mEglImage.
- EGLDisplay mEglDisplay;
-
- // mCropRect is the crop rectangle passed to EGL when mEglImage
- // was created.
- Rect mCropRect;
+ // mImage is the image created from mGraphicBuffer.
+ RE::Image mImage;
+ bool mCreated;
+ int32_t mCropWidth;
+ int32_t mCropHeight;
};
// freeBufferLocked frees up the given buffer slot. If the slot has been
- // initialized this will release the reference to the GraphicBuffer in that
- // slot and destroy the EGLImage in that slot. Otherwise it has no effect.
+ // initialized this will release the reference to the GraphicBuffer in
+ // that slot and destroy the RE::Image in that slot. Otherwise it has no
+ // effect.
//
// This method must be called with mMutex locked.
virtual void freeBufferLocked(int slotIndex);
@@ -302,23 +265,19 @@
// computeCurrentTransformMatrixLocked computes the transform matrix for the
// current texture. It uses mCurrentTransform and the current GraphicBuffer
// to compute this matrix and stores it in mCurrentTransformMatrix.
- // mCurrentTextureImage must not be NULL.
+ // mCurrentTextureImage must not be nullptr.
void computeCurrentTransformMatrixLocked();
- // doGLFenceWaitLocked inserts a wait command into the OpenGL ES command
- // stream to ensure that it is safe for future OpenGL ES commands to
+ // doFenceWaitLocked inserts a wait command into the RenderEngine command
+ // stream to ensure that it is safe for future RenderEngine commands to
// access the current texture buffer.
- status_t doGLFenceWaitLocked() const;
+ status_t doFenceWaitLocked() const;
// syncForReleaseLocked performs the synchronization needed to release the
- // current slot from an OpenGL ES context. 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(EGLDisplay dpy);
-
- // sTexTarget is the GL texture target with which the GL texture object is
- // associated.
- static constexpr uint32_t sTexTarget = 0x8D65; // GL_TEXTURE_EXTERNAL_OES
+ // 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();
// The default consumer usage flags that BufferLayerConsumer always sets on its
// BufferQueue instance; these will be OR:d with any additional flags passed
@@ -326,10 +285,10 @@
// consume buffers as hardware textures.
static const uint64_t DEFAULT_USAGE_FLAGS = GraphicBuffer::USAGE_HW_TEXTURE;
- // mCurrentTextureImage is the EglImage/buffer of the current texture. It's
+ // mCurrentTextureImage is the Image/buffer of the current texture. It's
// possible that this buffer is not associated with any buffer slot, so we
// must track it separately in order to support the getCurrentBuffer method.
- sp<EglImage> mCurrentTextureImage;
+ sp<Image> mCurrentTextureImage;
// mCurrentCrop is the crop rectangle that applies to the current texture.
// It gets set each time updateTexImage is called.
@@ -362,6 +321,10 @@
// gets set each time updateTexImage is called.
android_dataspace mCurrentDataSpace;
+ // mCurrentHdrMetadata is the HDR metadata for the current texture. It
+ // gets set each time updateTexImage is called.
+ HdrMetadata mCurrentHdrMetadata;
+
// mCurrentFrameNumber is the frame counter for the current texture.
// It gets set each time updateTexImage is called.
uint64_t mCurrentFrameNumber;
@@ -381,8 +344,11 @@
// setFilteringEnabled().
bool mFilteringEnabled;
- // mTexName is the name of the OpenGL texture to which streamed images will
- // be bound when updateTexImage is called. It is set at construction time.
+ RenderEngine& mRE;
+
+ // mTexName is the name of the RenderEngine texture to which streamed
+ // images will be bound when bindTexImage is called. It is set at
+ // construction time.
const uint32_t mTexName;
// The layer for this BufferLayerConsumer
@@ -390,35 +356,17 @@
wp<ContentsChangedListener> mContentsChangedListener;
- // EGLSlot contains the information and object references that
- // BufferLayerConsumer maintains about a BufferQueue buffer slot.
- struct EglSlot {
- // mEglImage is the EGLImage created from mGraphicBuffer.
- sp<EglImage> mEglImage;
- };
-
- // mEglDisplay is the EGLDisplay with which this BufferLayerConsumer is currently
- // associated. It is intialized to EGL_NO_DISPLAY and gets set to the
- // current display when updateTexImage is called for the first time.
- EGLDisplay mEglDisplay;
-
- // mEglContext is the OpenGL ES context with which this BufferLayerConsumer is
- // currently associated. It is initialized to EGL_NO_CONTEXT and gets set
- // to the current GL context when updateTexImage is called for the first
- // time.
- EGLContext mEglContext;
-
- // mEGLSlots stores the buffers that have been allocated by the BufferQueue
+ // mImages stores the buffers that have been allocated by the BufferQueue
// for each buffer slot. It is initialized to null pointers, and gets
// filled in with the result of BufferQueue::acquire when the
// client dequeues a buffer from a
// slot that has not yet been used. The buffer allocated to a slot will also
// be replaced if the requested buffer usage or geometry differs from that
// of the buffer allocated to a slot.
- EglSlot mEglSlots[BufferQueueDefs::NUM_BUFFER_SLOTS];
+ sp<Image> mImages[BufferQueueDefs::NUM_BUFFER_SLOTS];
// mCurrentTexture is the buffer slot index of the buffer that is currently
- // bound to the OpenGL texture. It is initialized to INVALID_BUFFER_SLOT,
+ // bound to the RenderEngine texture. It is initialized to INVALID_BUFFER_SLOT,
// indicating that no buffer slot is currently bound to the texture. Note,
// however, that a value of INVALID_BUFFER_SLOT does not necessarily mean
// that no buffer is bound to the texture. A call to setBufferCount will
diff --git a/services/surfaceflinger/Client.cpp b/services/surfaceflinger/Client.cpp
index ea6541a..a69940a 100644
--- a/services/surfaceflinger/Client.cpp
+++ b/services/surfaceflinger/Client.cpp
@@ -206,7 +206,7 @@
status_t Client::clearLayerFrameStats(const sp<IBinder>& handle) const {
sp<Layer> layer = getLayerUser(handle);
- if (layer == NULL) {
+ if (layer == nullptr) {
return NAME_NOT_FOUND;
}
layer->clearFrameStats();
@@ -215,7 +215,7 @@
status_t Client::getLayerFrameStats(const sp<IBinder>& handle, FrameStats* outStats) const {
sp<Layer> layer = getLayerUser(handle);
- if (layer == NULL) {
+ if (layer == nullptr) {
return NAME_NOT_FOUND;
}
layer->getFrameStats(outStats);
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index 2753f11..a663487 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -127,20 +127,6 @@
mPowerMode = (mType >= DisplayDevice::DISPLAY_VIRTUAL) ?
HWC_POWER_MODE_NORMAL : HWC_POWER_MODE_OFF;
- // Name the display. The name will be replaced shortly if the display
- // was created with createDisplay().
- switch (mType) {
- case DISPLAY_PRIMARY:
- mDisplayName = "Built-in Screen";
- break;
- case DISPLAY_EXTERNAL:
- mDisplayName = "HDMI Screen";
- break;
- default:
- mDisplayName = "Virtual Screen"; // e.g. Overlay #n
- break;
- }
-
// initialize the display orientation transform.
setProjection(DisplayState::eOrientationDefault, mViewport, mFrame);
@@ -160,7 +146,7 @@
}
bool DisplayDevice::isValid() const {
- return mFlinger != NULL;
+ return mFlinger != nullptr;
}
int DisplayDevice::getWidth() const {
diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
index 8b5d4c9..4faba3b 100644
--- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
@@ -76,6 +76,10 @@
SurfaceFlinger::maxFrameBufferAcquiredBuffers - 1);
}
+void FramebufferSurface::resizeBuffers(const uint32_t width, const uint32_t height) {
+ mConsumer->setDefaultBufferSize(width, height);
+}
+
status_t FramebufferSurface::beginFrame(bool /*mustRecompose*/) {
return NO_ERROR;
}
diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.h b/services/surfaceflinger/DisplayHardware/FramebufferSurface.h
index 4186b7a..ed756c4 100644
--- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.h
+++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.h
@@ -46,9 +46,7 @@
virtual void onFrameCommitted();
virtual void dumpAsString(String8& result) const;
- // Cannot resize a buffers in a FramebufferSurface. Only works with virtual
- // displays.
- virtual void resizeBuffers(const uint32_t /*w*/, const uint32_t /*h*/) { };
+ virtual void resizeBuffers(const uint32_t width, const uint32_t height);
virtual const sp<Fence>& getClientTargetAcquireFence() const override;
@@ -80,7 +78,7 @@
// on/off.
android_dataspace mDataSpace;
- // mCurrentBuffer is the current buffer or NULL to indicate that there is
+ // mCurrentBuffer is the current buffer or nullptr to indicate that there is
// no current buffer.
sp<GraphicBuffer> mCurrentBuffer;
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp
index ab4a4b2..070b691 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp
@@ -52,24 +52,13 @@
class ComposerCallbackBridge : public Hwc2::IComposerCallback {
public:
ComposerCallbackBridge(ComposerCallback* callback, int32_t sequenceId)
- : mCallback(callback), mSequenceId(sequenceId),
- mHasPrimaryDisplay(false) {}
+ : mCallback(callback), mSequenceId(sequenceId) {}
Return<void> onHotplug(Hwc2::Display display,
IComposerCallback::Connection conn) override
{
HWC2::Connection connection = static_cast<HWC2::Connection>(conn);
- if (!mHasPrimaryDisplay) {
- LOG_ALWAYS_FATAL_IF(connection != HWC2::Connection::Connected,
- "Initial onHotplug callback should be "
- "primary display connected");
- mHasPrimaryDisplay = true;
- mCallback->onHotplugReceived(mSequenceId, display,
- connection, true);
- } else {
- mCallback->onHotplugReceived(mSequenceId, display,
- connection, false);
- }
+ mCallback->onHotplugReceived(mSequenceId, display, connection);
return Void();
}
@@ -85,12 +74,9 @@
return Void();
}
- bool HasPrimaryDisplay() { return mHasPrimaryDisplay; }
-
private:
ComposerCallback* mCallback;
int32_t mSequenceId;
- bool mHasPrimaryDisplay;
};
} // namespace anonymous
@@ -117,8 +103,6 @@
sp<ComposerCallbackBridge> callbackBridge(
new ComposerCallbackBridge(callback, sequenceId));
mComposer->registerCallback(callbackBridge);
- LOG_ALWAYS_FATAL_IF(!callbackBridge->HasPrimaryDisplay(),
- "Registered composer callback but didn't get primary display");
}
// Required by HWC2 device
@@ -467,7 +451,6 @@
Error Display::getHdrCapabilities(
std::unique_ptr<HdrCapabilities>* outCapabilities) const
{
- uint32_t numTypes = 0;
float maxLuminance = -1.0f;
float maxAverageLuminance = -1.0f;
float minLuminance = -1.0f;
@@ -480,7 +463,6 @@
for (auto type : intTypes) {
types.push_back(static_cast<int32_t>(type));
}
- numTypes = types.size();
if (error != Error::None) {
return error;
}
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.h b/services/surfaceflinger/DisplayHardware/HWC2.h
index a15c6d9..7b98b3e 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.h
+++ b/services/surfaceflinger/DisplayHardware/HWC2.h
@@ -65,8 +65,7 @@
class ComposerCallback {
public:
virtual void onHotplugReceived(int32_t sequenceId, hwc2_display_t display,
- Connection connection,
- bool primaryDisplay) = 0;
+ Connection connection) = 0;
virtual void onRefreshReceived(int32_t sequenceId,
hwc2_display_t display) = 0;
virtual void onVsyncReceived(int32_t sequenceId, hwc2_display_t display,
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 60b85c5..1677b07 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -119,23 +119,22 @@
}
}
-void HWComposer::onHotplug(hwc2_display_t displayId,
+void HWComposer::onHotplug(hwc2_display_t displayId, int32_t displayType,
HWC2::Connection connection) {
- ALOGV("hotplug: %" PRIu64 ", %s", displayId,
+ if (displayType >= HWC_NUM_PHYSICAL_DISPLAY_TYPES) {
+ ALOGE("Invalid display type of %d", displayType);
+ return;
+ }
+
+ ALOGV("hotplug: %" PRIu64 ", %s %s", displayId,
+ displayType == DisplayDevice::DISPLAY_PRIMARY ? "primary" : "external",
to_string(connection).c_str());
mHwcDevice->onHotplug(displayId, connection);
- if (!mDisplayData[0].hwcDisplay) {
- ALOGE_IF(connection != HWC2::Connection::Connected, "Assumed primary"
- " display would be connected");
- mDisplayData[0].hwcDisplay = mHwcDevice->getDisplayById(displayId);
- mHwcDisplaySlots[displayId] = 0;
- } else {
- // Disconnect is handled through HWComposer::disconnectDisplay via
- // SurfaceFlinger's onHotplugReceived callback handling
- if (connection == HWC2::Connection::Connected) {
- mDisplayData[1].hwcDisplay = mHwcDevice->getDisplayById(displayId);
- mHwcDisplaySlots[displayId] = 1;
- }
+ // Disconnect is handled through HWComposer::disconnectDisplay via
+ // SurfaceFlinger's onHotplugReceived callback handling
+ if (connection == HWC2::Connection::Connected) {
+ mDisplayData[displayType].hwcDisplay = mHwcDevice->getDisplayById(displayId);
+ mHwcDisplaySlots[displayId] = displayType;
}
}
@@ -444,10 +443,16 @@
HWC2::Error error = HWC2::Error::None;
- // First try to skip validate altogether if the HWC supports it.
+ // First try to skip validate altogether when there is no client
+ // composition. When there is client composition, since we haven't
+ // rendered to the client target yet, we should not attempt to skip
+ // validate.
+ //
+ // displayData.hasClientComposition hasn't been updated for this frame.
+ // The check below is incorrect. We actually rely on HWC here to fall
+ // back to validate when there is any client layer.
displayData.validateWasSkipped = false;
- if (hasCapability(HWC2::Capability::SkipValidate) &&
- !displayData.hasClientComposition) {
+ if (!displayData.hasClientComposition) {
sp<android::Fence> outPresentFence;
uint32_t state = UINT32_MAX;
error = hwcDisplay->presentOrValidate(&numTypes, &numRequests, &outPresentFence , &state);
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index 74b3a38..ee0a725 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -136,7 +136,7 @@
// DisplayDevice::DisplayType of the display is returned as an output param.
bool onVsync(hwc2_display_t displayId, int64_t timestamp,
int32_t* outDisplay);
- void onHotplug(hwc2_display_t displayId, HWC2::Connection connection);
+ void onHotplug(hwc2_display_t displayId, int32_t displayType, HWC2::Connection connection);
void setVsyncEnabled(int32_t displayId, HWC2::Vsync enabled);
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.h b/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.h
index 4bc63bb..fe7944f 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.h
@@ -190,7 +190,7 @@
virtual status_t setLayer(size_t index) = 0;
virtual HWCLayer* dup() = 0;
static HWCLayer* copy(HWCLayer *rhs) {
- return rhs ? rhs->dup() : NULL;
+ return rhs ? rhs->dup() : nullptr;
}
protected:
virtual ~HWCLayer() { }
@@ -205,7 +205,7 @@
HWCLayer* const mLayerList;
size_t mIndex;
- LayerListIterator() : mLayerList(NULL), mIndex(0) { }
+ LayerListIterator() : mLayerList(nullptr), mIndex(0) { }
LayerListIterator(HWCLayer* layer, size_t index)
: mLayerList(layer), mIndex(index) { }
@@ -371,8 +371,8 @@
sp<SurfaceFlinger> mFlinger;
framebuffer_device_t* mFbDev;
struct hwc_composer_device_1* mHwc;
- // invariant: mLists[0] != NULL iff mHwc != NULL
- // mLists[i>0] can be NULL. that display is to be ignored
+ // invariant: mLists[0] != nullptr iff mHwc != nullptr
+ // mLists[i>0] can be nullptr. that display is to be ignored
struct hwc_display_contents_1* mLists[MAX_HWC_DISPLAYS];
DisplayData mDisplayData[MAX_HWC_DISPLAYS];
// protect mDisplayData from races between prepare and dump
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
index cde96e4..3480b24 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
@@ -108,7 +108,7 @@
mConsumer->setDefaultBufferSize(sinkWidth, sinkHeight);
sink->setAsyncMode(true);
IGraphicBufferProducer::QueueBufferOutput output;
- mSource[SOURCE_SCRATCH]->connect(NULL, NATIVE_WINDOW_API_EGL, false, &output);
+ mSource[SOURCE_SCRATCH]->connect(nullptr, NATIVE_WINDOW_API_EGL, false, &output);
}
VirtualDisplaySurface::~VirtualDisplaySurface() {
@@ -203,7 +203,7 @@
}
sp<GraphicBuffer> fbBuffer = mFbProducerSlot >= 0 ?
- mProducerBuffers[mFbProducerSlot] : sp<GraphicBuffer>(NULL);
+ mProducerBuffers[mFbProducerSlot] : sp<GraphicBuffer>(nullptr);
sp<GraphicBuffer> outBuffer = mProducerBuffers[mOutputProducerSlot];
VDS_LOGV("advanceFrame: fb=%d(%p) out=%d(%p)",
mFbProducerSlot, fbBuffer.get(),
@@ -214,7 +214,7 @@
mHwc.setOutputBuffer(mDisplayId, mOutputFence, outBuffer);
status_t result = NO_ERROR;
- if (fbBuffer != NULL) {
+ if (fbBuffer != nullptr) {
uint32_t hwcSlot = 0;
sp<GraphicBuffer> hwcBuffer;
mHwcBufferCache.getHwcBuffer(mFbProducerSlot, fbBuffer,
diff --git a/services/surfaceflinger/EventThread.cpp b/services/surfaceflinger/EventThread.cpp
index a1a0420..5c0e3b3 100644
--- a/services/surfaceflinger/EventThread.cpp
+++ b/services/surfaceflinger/EventThread.cpp
@@ -216,7 +216,7 @@
size_t count = mDisplayEventConnections.size();
for (size_t i=0 ; i<count ; ) {
sp<Connection> connection(mDisplayEventConnections[i].promote());
- if (connection != NULL) {
+ if (connection != nullptr) {
bool added = false;
if (connection->count >= 0) {
// we need vsync events because at least
@@ -346,7 +346,7 @@
sp<Connection> connection =
mDisplayEventConnections.itemAt(i).promote();
result.appendFormat(" %p: count=%d\n",
- connection.get(), connection!=NULL ? connection->count : 0);
+ connection.get(), connection != nullptr ? connection->count : 0);
}
}
diff --git a/services/surfaceflinger/FrameTracker.cpp b/services/surfaceflinger/FrameTracker.cpp
index 99c4daa..1539873 100644
--- a/services/surfaceflinger/FrameTracker.cpp
+++ b/services/surfaceflinger/FrameTracker.cpp
@@ -82,17 +82,17 @@
mFrameRecords[mOffset].frameReadyTime = INT64_MAX;
mFrameRecords[mOffset].actualPresentTime = INT64_MAX;
- if (mFrameRecords[mOffset].frameReadyFence != NULL) {
+ if (mFrameRecords[mOffset].frameReadyFence != nullptr) {
// We're clobbering an unsignaled fence, so we need to decrement the
// fence count.
- mFrameRecords[mOffset].frameReadyFence = NULL;
+ mFrameRecords[mOffset].frameReadyFence = nullptr;
mNumFences--;
}
- if (mFrameRecords[mOffset].actualPresentFence != NULL) {
+ if (mFrameRecords[mOffset].actualPresentFence != nullptr) {
// We're clobbering an unsignaled fence, so we need to decrement the
// fence count.
- mFrameRecords[mOffset].actualPresentFence = NULL;
+ mFrameRecords[mOffset].actualPresentFence = nullptr;
mNumFences--;
}
}
@@ -153,10 +153,10 @@
bool updated = false;
const std::shared_ptr<FenceTime>& rfence = records[idx].frameReadyFence;
- if (rfence != NULL) {
+ if (rfence != nullptr) {
records[idx].frameReadyTime = rfence->getSignalTime();
if (records[idx].frameReadyTime < INT64_MAX) {
- records[idx].frameReadyFence = NULL;
+ records[idx].frameReadyFence = nullptr;
numFences--;
updated = true;
}
@@ -164,10 +164,10 @@
const std::shared_ptr<FenceTime>& pfence =
records[idx].actualPresentFence;
- if (pfence != NULL) {
+ if (pfence != nullptr) {
records[idx].actualPresentTime = pfence->getSignalTime();
if (records[idx].actualPresentTime < INT64_MAX) {
- records[idx].actualPresentFence = NULL;
+ records[idx].actualPresentFence = nullptr;
numFences--;
updated = true;
}
diff --git a/services/surfaceflinger/FrameTracker.h b/services/surfaceflinger/FrameTracker.h
index adcdfb5..b4a9fd6 100644
--- a/services/surfaceflinger/FrameTracker.h
+++ b/services/surfaceflinger/FrameTracker.h
@@ -35,7 +35,7 @@
// possible.
//
// Some of the time values tracked may be set either as a specific timestamp
-// or a fence. When a non-NULL fence is set for a given time value, the
+// or a fence. When a non-nullptr fence is set for a given time value, the
// signal time of that fence is used instead of the timestamp.
class FrameTracker {
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 13df1e2..63f6781 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -265,7 +265,7 @@
if (!mCurrentCrop.isEmpty()) {
// if the buffer crop is defined, we use that
crop = mCurrentCrop;
- } else if (getBE().compositionInfo.mBuffer != NULL) {
+ } else if (getBE().compositionInfo.mBuffer != nullptr) {
// otherwise we use the whole buffer
crop = getBE().compositionInfo.mBuffer->getBounds();
} else {
@@ -285,6 +285,14 @@
return Region(win).subtract(exclude).getBounds();
}
+static FloatRect reduce(const FloatRect& win, const Region& exclude) {
+ if (CC_LIKELY(exclude.isEmpty())) {
+ return win;
+ }
+ // Convert through Rect (by rounding) for lack of FloatRegion
+ return Region(Rect{win}).subtract(exclude).getBounds().toFloatRect();
+}
+
Rect Layer::computeScreenBounds(bool reduceTransparentRegion) const {
const Layer::State& s(getDrawingState());
Rect win(s.active.w, s.active.h);
@@ -323,12 +331,12 @@
return win;
}
-Rect Layer::computeBounds() const {
+FloatRect Layer::computeBounds() const {
const Layer::State& s(getDrawingState());
return computeBounds(s.activeTransparentRegion);
}
-Rect Layer::computeBounds(const Region& activeTransparentRegion) const {
+FloatRect Layer::computeBounds(const Region& activeTransparentRegion) const {
const Layer::State& s(getDrawingState());
Rect win(s.active.w, s.active.h);
@@ -345,14 +353,16 @@
}
Transform t = getTransform();
+
+ FloatRect floatWin = win.toFloatRect();
if (p != nullptr) {
- win = t.transform(win);
- win.intersect(bounds, &win);
- win = t.inverse().transform(win);
+ floatWin = t.transform(floatWin);
+ floatWin = floatWin.intersect(bounds.toFloatRect());
+ floatWin = t.inverse().transform(floatWin);
}
// subtract the transparent region and snap to the bounds
- return reduce(win, activeTransparentRegion);
+ return reduce(floatWin, activeTransparentRegion);
}
Rect Layer::computeInitialCrop(const sp<const DisplayDevice>& hw) const {
@@ -528,7 +538,9 @@
Rect(activeCrop.right, activeCrop.top, s.active.w, activeCrop.bottom));
}
- Rect frame(t.transform(computeBounds(activeTransparentRegion)));
+ // computeBounds returns a FloatRect to provide more accuracy during the
+ // transformation. We then round upon constructing 'frame'.
+ Rect frame{t.transform(computeBounds(activeTransparentRegion))};
if (!s.finalCrop.isEmpty()) {
if (!frame.intersect(s.finalCrop, &frame)) {
frame.clear();
@@ -807,7 +819,7 @@
const Layer::State& s(getDrawingState());
const Transform renderAreaTransform(renderArea.getTransform());
const uint32_t height = renderArea.getHeight();
- Rect win = computeBounds();
+ FloatRect win = computeBounds();
vec2 lt = vec2(win.left, win.top);
vec2 lb = vec2(win.left, win.bottom);
@@ -1117,8 +1129,9 @@
if (childLayer->setLayer(z)) {
mCurrentChildren.removeAt(idx);
mCurrentChildren.add(childLayer);
+ return true;
}
- return true;
+ return false;
}
bool Layer::setChildRelativeLayer(const sp<Layer>& childLayer,
@@ -1130,12 +1143,13 @@
if (childLayer->setRelativeLayer(relativeToHandle, relativeZ)) {
mCurrentChildren.removeAt(idx);
mCurrentChildren.add(childLayer);
+ return true;
}
- return true;
+ return false;
}
bool Layer::setLayer(int32_t z) {
- if (mCurrentState.z == z) return false;
+ if (mCurrentState.z == z && !usingRelativeZ(LayerVector::StateSet::Current)) return false;
mCurrentState.sequence++;
mCurrentState.z = z;
mCurrentState.modified = true;
@@ -1166,7 +1180,7 @@
setTransactionFlags(eTransactionNeeded);
}
-bool Layer::setRelativeLayer(const sp<IBinder>& relativeToHandle, int32_t z) {
+bool Layer::setRelativeLayer(const sp<IBinder>& relativeToHandle, int32_t relativeZ) {
sp<Handle> handle = static_cast<Handle*>(relativeToHandle.get());
if (handle == nullptr) {
return false;
@@ -1176,9 +1190,14 @@
return false;
}
+ if (mCurrentState.z == relativeZ && usingRelativeZ(LayerVector::StateSet::Current) &&
+ mCurrentState.zOrderRelativeOf == relative) {
+ return false;
+ }
+
mCurrentState.sequence++;
mCurrentState.modified = true;
- mCurrentState.z = z;
+ mCurrentState.z = relativeZ;
auto oldZOrderRelativeOf = mCurrentState.zOrderRelativeOf.promote();
if (oldZOrderRelativeOf != nullptr) {
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index cf7fc50..e44ccf8 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -24,6 +24,7 @@
#include <utils/String8.h>
#include <utils/Timers.h>
+#include <ui/FloatRect.h>
#include <ui/FrameStats.h>
#include <ui/GraphicBuffer.h>
#include <ui/PixelFormat.h>
@@ -303,8 +304,8 @@
}
void computeGeometry(const RenderArea& renderArea, Mesh& mesh, bool useIdentityTransform) const;
- Rect computeBounds(const Region& activeTransparentRegion) const;
- Rect computeBounds() const;
+ FloatRect computeBounds(const Region& activeTransparentRegion) const;
+ FloatRect computeBounds() const;
int32_t getSequence() const { return sequence; }
diff --git a/services/surfaceflinger/LayerRejecter.cpp b/services/surfaceflinger/LayerRejecter.cpp
index e864607..a5f0b98 100644
--- a/services/surfaceflinger/LayerRejecter.cpp
+++ b/services/surfaceflinger/LayerRejecter.cpp
@@ -41,7 +41,7 @@
mFreezeGeometryUpdates(freezePositionUpdates) {}
bool LayerRejecter::reject(const sp<GraphicBuffer>& buf, const BufferItem& item) {
- if (buf == NULL) {
+ if (buf == nullptr) {
return false;
}
diff --git a/services/surfaceflinger/RenderEngine/Description.cpp b/services/surfaceflinger/RenderEngine/Description.cpp
index e014406..1b5a466 100644
--- a/services/surfaceflinger/RenderEngine/Description.cpp
+++ b/services/surfaceflinger/RenderEngine/Description.cpp
@@ -26,15 +26,6 @@
namespace android {
-Description::Description() {
- mPremultipliedAlpha = false;
- mOpaque = true;
- mTextureEnabled = false;
- mColorMatrixEnabled = false;
-}
-
-Description::~Description() {}
-
void Description::setPremultipliedAlpha(bool premultipliedAlpha) {
mPremultipliedAlpha = premultipliedAlpha;
}
diff --git a/services/surfaceflinger/RenderEngine/Description.h b/services/surfaceflinger/RenderEngine/Description.h
index cbac855..1811952 100644
--- a/services/surfaceflinger/RenderEngine/Description.h
+++ b/services/surfaceflinger/RenderEngine/Description.h
@@ -36,27 +36,27 @@
friend class ProgramCache;
// whether textures are premultiplied
- bool mPremultipliedAlpha;
+ bool mPremultipliedAlpha = false;
// whether this layer is marked as opaque
- bool mOpaque;
+ bool mOpaque = true;
// Texture this layer uses
Texture mTexture;
- bool mTextureEnabled;
+ bool mTextureEnabled = false;
// color used when texturing is disabled or when setting alpha.
half4 mColor;
// projection matrix
mat4 mProjectionMatrix;
- bool mColorMatrixEnabled;
+ bool mColorMatrixEnabled = false;
mat4 mColorMatrix;
- bool mIsWideGamut;
+ bool mIsWideGamut = false;
public:
- Description();
- ~Description();
+ Description() = default;
+ ~Description() = default;
void setPremultipliedAlpha(bool premultipliedAlpha);
void setOpaque(bool opaque);
diff --git a/services/surfaceflinger/RenderEngine/GLExtensions.cpp b/services/surfaceflinger/RenderEngine/GLExtensions.cpp
index 7ffcc96..e6e4df1 100644
--- a/services/surfaceflinger/RenderEngine/GLExtensions.cpp
+++ b/services/surfaceflinger/RenderEngine/GLExtensions.cpp
@@ -25,7 +25,22 @@
ANDROID_SINGLETON_STATIC_INSTANCE(GLExtensions)
-GLExtensions::GLExtensions() : mHaveFramebufferObject(false) {}
+SortedVector<String8> GLExtensions::parseExtensionString(char const* extensions) {
+ SortedVector<String8> list;
+
+ char const* curr = extensions;
+ char const* head = curr;
+ do {
+ head = strchr(curr, ' ');
+ String8 s(curr, head ? head - curr : strlen(curr));
+ if (s.length()) {
+ list.add(s);
+ }
+ curr = head + 1;
+ } while (head);
+
+ return list;
+}
void GLExtensions::initWithGLStrings(GLubyte const* vendor, GLubyte const* renderer,
GLubyte const* version, GLubyte const* extensions) {
@@ -33,21 +48,7 @@
mRenderer = (char const*)renderer;
mVersion = (char const*)version;
mExtensions = (char const*)extensions;
-
- char const* curr = (char const*)extensions;
- char const* head = curr;
- do {
- head = strchr(curr, ' ');
- String8 s(curr, head ? head - curr : strlen(curr));
- if (s.length()) {
- mExtensionList.add(s);
- }
- curr = head + 1;
- } while (head);
-
- if (hasExtension("GL_OES_framebuffer_object")) {
- mHaveFramebufferObject = true;
- }
+ mExtensionList = parseExtensionString(mExtensions);
}
bool GLExtensions::hasExtension(char const* extension) const {
@@ -67,9 +68,58 @@
return mVersion.string();
}
-char const* GLExtensions::getExtension() const {
+char const* GLExtensions::getExtensions() const {
return mExtensions.string();
}
+void GLExtensions::initWithEGLStrings(char const* eglVersion, char const* eglExtensions) {
+ mEGLVersion = eglVersion;
+ mEGLExtensions = eglExtensions;
+ mEGLExtensionList = parseExtensionString(mEGLExtensions);
+
+ // EGL_ANDROIDX_no_config_context is an experimental extension with no
+ // written specification. It will be replaced by something more formal.
+ // SurfaceFlinger is using it to allow a single EGLContext to render to
+ // both a 16-bit primary display framebuffer and a 32-bit virtual display
+ // framebuffer.
+ //
+ // EGL_KHR_no_config_context is official extension to allow creating a
+ // context that works with any surface of a display.
+ if (hasEGLExtension("EGL_ANDROIDX_no_config_context") ||
+ hasEGLExtension("EGL_KHR_no_config_context")) {
+ mHasNoConfigContext = true;
+ }
+
+ if (hasEGLExtension("EGL_ANDROID_native_fence_sync")) {
+ mHasNativeFenceSync = true;
+ }
+ if (hasEGLExtension("EGL_KHR_fence_sync")) {
+ mHasFenceSync = true;
+ }
+ if (hasEGLExtension("EGL_KHR_wait_sync")) {
+ mHasWaitSync = true;
+ }
+
+ if (hasEGLExtension("EGL_ANDROID_image_crop")) {
+ mHasImageCrop = true;
+ }
+ if (hasEGLExtension("EGL_EXT_protected_content")) {
+ mHasProtectedContent = true;
+ }
+}
+
+char const* GLExtensions::getEGLVersion() const {
+ return mEGLVersion.string();
+}
+
+char const* GLExtensions::getEGLExtensions() const {
+ return mEGLExtensions.string();
+}
+
+bool GLExtensions::hasEGLExtension(char const* extension) const {
+ const String8 s(extension);
+ return mEGLExtensionList.indexOf(s) >= 0;
+}
+
// ---------------------------------------------------------------------------
}; // namespace android
diff --git a/services/surfaceflinger/RenderEngine/GLExtensions.h b/services/surfaceflinger/RenderEngine/GLExtensions.h
index ee7b446..81078e0 100644
--- a/services/surfaceflinger/RenderEngine/GLExtensions.h
+++ b/services/surfaceflinger/RenderEngine/GLExtensions.h
@@ -35,7 +35,12 @@
class GLExtensions : public Singleton<GLExtensions> {
friend class Singleton<GLExtensions>;
- bool mHaveFramebufferObject : 1;
+ bool mHasNoConfigContext = false;
+ bool mHasNativeFenceSync = false;
+ bool mHasFenceSync = false;
+ bool mHasWaitSync = false;
+ bool mHasImageCrop = false;
+ bool mHasProtectedContent = false;
String8 mVendor;
String8 mRenderer;
@@ -43,24 +48,38 @@
String8 mExtensions;
SortedVector<String8> mExtensionList;
+ String8 mEGLVersion;
+ String8 mEGLExtensions;
+ SortedVector<String8> mEGLExtensionList;
+
+ static SortedVector<String8> parseExtensionString(char const* extensions);
+
GLExtensions(const GLExtensions&);
GLExtensions& operator=(const GLExtensions&);
protected:
- GLExtensions();
+ GLExtensions() = default;
public:
- inline bool haveFramebufferObject() const { return mHaveFramebufferObject; }
+ bool hasNoConfigContext() const { return mHasNoConfigContext; }
+ bool hasNativeFenceSync() const { return mHasNativeFenceSync; }
+ bool hasFenceSync() const { return mHasFenceSync; }
+ bool hasWaitSync() const { return mHasWaitSync; }
+ bool hasImageCrop() const { return mHasImageCrop; }
+ bool hasProtectedContent() const { return mHasProtectedContent; }
void initWithGLStrings(GLubyte const* vendor, GLubyte const* renderer, GLubyte const* version,
GLubyte const* extensions);
-
char const* getVendor() const;
char const* getRenderer() const;
char const* getVersion() const;
- char const* getExtension() const;
-
+ char const* getExtensions() const;
bool hasExtension(char const* extension) const;
+
+ void initWithEGLStrings(char const* eglVersion, char const* eglExtensions);
+ char const* getEGLVersion() const;
+ char const* getEGLExtensions() const;
+ bool hasEGLExtension(char const* extension) const;
};
// ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/RenderEngine/Image.cpp b/services/surfaceflinger/RenderEngine/Image.cpp
new file mode 100644
index 0000000..1f8e75a
--- /dev/null
+++ b/services/surfaceflinger/RenderEngine/Image.cpp
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Image.h"
+
+#include <vector>
+
+#include <log/log.h>
+
+#include "GLExtensions.h"
+#include "RenderEngine.h"
+
+namespace android {
+namespace RE {
+
+Image::Image(const RenderEngine& engine) : mEGLDisplay(engine.getEGLDisplay()) {}
+
+Image::~Image() {
+ setNativeWindowBuffer(nullptr, false, 0, 0);
+}
+
+static std::vector<EGLint> buildAttributeList(bool isProtected, int32_t cropWidth,
+ int32_t cropHeight) {
+ std::vector<EGLint> attrs;
+ attrs.reserve(16);
+
+ attrs.push_back(EGL_IMAGE_PRESERVED_KHR);
+ attrs.push_back(EGL_TRUE);
+
+ if (isProtected && GLExtensions::getInstance().hasProtectedContent()) {
+ attrs.push_back(EGL_PROTECTED_CONTENT_EXT);
+ attrs.push_back(EGL_TRUE);
+ }
+
+ if (cropWidth > 0 && cropHeight > 0) {
+ attrs.push_back(EGL_IMAGE_CROP_LEFT_ANDROID);
+ attrs.push_back(0);
+ attrs.push_back(EGL_IMAGE_CROP_TOP_ANDROID);
+ attrs.push_back(0);
+ attrs.push_back(EGL_IMAGE_CROP_RIGHT_ANDROID);
+ attrs.push_back(cropWidth);
+ attrs.push_back(EGL_IMAGE_CROP_BOTTOM_ANDROID);
+ attrs.push_back(cropHeight);
+ }
+
+ attrs.push_back(EGL_NONE);
+
+ return attrs;
+}
+
+bool Image::setNativeWindowBuffer(ANativeWindowBuffer* buffer, bool isProtected, int32_t cropWidth,
+ int32_t cropHeight) {
+ if (mEGLImage != EGL_NO_IMAGE_KHR) {
+ if (!eglDestroyImageKHR(mEGLDisplay, mEGLImage)) {
+ ALOGE("failed to destroy image: %#x", eglGetError());
+ }
+ mEGLImage = EGL_NO_IMAGE_KHR;
+ }
+
+ if (buffer) {
+ std::vector<EGLint> attrs = buildAttributeList(isProtected, cropWidth, cropHeight);
+ mEGLImage = eglCreateImageKHR(mEGLDisplay, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID,
+ static_cast<EGLClientBuffer>(buffer), attrs.data());
+ if (mEGLImage == EGL_NO_IMAGE_KHR) {
+ ALOGE("failed to create EGLImage: %#x", eglGetError());
+ return false;
+ }
+ }
+
+ return true;
+}
+
+} // namespace RE
+} // namespace android
diff --git a/services/surfaceflinger/RenderEngine/Image.h b/services/surfaceflinger/RenderEngine/Image.h
new file mode 100644
index 0000000..f55aa59
--- /dev/null
+++ b/services/surfaceflinger/RenderEngine/Image.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <cstdint>
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+
+struct ANativeWindowBuffer;
+
+namespace android {
+
+class RenderEngine;
+
+namespace RE {
+
+class Image {
+public:
+ Image(const RenderEngine& engine);
+ ~Image();
+
+ Image(const Image&) = delete;
+ Image& operator=(const Image&) = delete;
+
+ bool setNativeWindowBuffer(ANativeWindowBuffer* buffer, bool isProtected, int32_t cropWidth,
+ int32_t cropHeight);
+
+private:
+ // methods internal to RenderEngine
+ friend class android::RenderEngine;
+ EGLSurface getEGLImage() const { return mEGLImage; }
+
+ EGLDisplay mEGLDisplay;
+ EGLImageKHR mEGLImage = EGL_NO_IMAGE_KHR;
+};
+
+} // namespace RE
+} // namespace android
diff --git a/services/surfaceflinger/RenderEngine/Program.cpp b/services/surfaceflinger/RenderEngine/Program.cpp
index baf92eb..225bcf0 100644
--- a/services/surfaceflinger/RenderEngine/Program.cpp
+++ b/services/surfaceflinger/RenderEngine/Program.cpp
@@ -115,7 +115,7 @@
GLint l;
glGetShaderiv(shader, GL_SHADER_SOURCE_LENGTH, &l);
char* src = new char[l];
- glGetShaderSource(shader, l, NULL, src);
+ glGetShaderSource(shader, l, nullptr, src);
result.append(src);
delete[] src;
return result;
diff --git a/services/surfaceflinger/RenderEngine/ProgramCache.cpp b/services/surfaceflinger/RenderEngine/ProgramCache.cpp
index 4f138dc..3b8ac0e 100644
--- a/services/surfaceflinger/RenderEngine/ProgramCache.cpp
+++ b/services/surfaceflinger/RenderEngine/ProgramCache.cpp
@@ -98,7 +98,7 @@
continue;
}
Program* program = mCache.valueFor(shaderKey);
- if (program == NULL) {
+ if (program == nullptr) {
program = generateProgram(shaderKey);
mCache.add(shaderKey, program);
shaderCount++;
@@ -273,7 +273,7 @@
// look-up the program in the cache
Program* program = mCache.valueFor(needs);
- if (program == NULL) {
+ if (program == nullptr) {
// we didn't find our program, so generate one...
nsecs_t time = -systemTime();
program = generateProgram(needs);
diff --git a/services/surfaceflinger/RenderEngine/RenderEngine.cpp b/services/surfaceflinger/RenderEngine/RenderEngine.cpp
index 883ae26..179b790 100644
--- a/services/surfaceflinger/RenderEngine/RenderEngine.cpp
+++ b/services/surfaceflinger/RenderEngine/RenderEngine.cpp
@@ -20,6 +20,7 @@
#include "GLES20RenderEngine.h"
#include "GLExtensions.h"
+#include "Image.h"
#include "Mesh.h"
#include "RenderEngine.h"
@@ -32,42 +33,21 @@
namespace android {
// ---------------------------------------------------------------------------
-static bool findExtension(const char* exts, const char* name) {
- if (!exts) return false;
- size_t len = strlen(name);
-
- const char* pos = exts;
- while ((pos = strstr(pos, name)) != NULL) {
- if (pos[len] == '\0' || pos[len] == ' ') return true;
- pos += len;
- }
-
- return false;
-}
-
std::unique_ptr<RenderEngine> RenderEngine::create(int hwcFormat, uint32_t featureFlags) {
// initialize EGL for the default display
EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
- if (!eglInitialize(display, NULL, NULL)) {
+ if (!eglInitialize(display, nullptr, nullptr)) {
LOG_ALWAYS_FATAL("failed to initialize EGL");
}
- // EGL_ANDROIDX_no_config_context is an experimental extension with no
- // written specification. It will be replaced by something more formal.
- // SurfaceFlinger is using it to allow a single EGLContext to render to
- // both a 16-bit primary display framebuffer and a 32-bit virtual display
- // framebuffer.
- //
- // EGL_KHR_no_config_context is official extension to allow creating a
- // context that works with any surface of a display.
- //
+ GLExtensions& extensions = GLExtensions::getInstance();
+ extensions.initWithEGLStrings(eglQueryStringImplementationANDROID(display, EGL_VERSION),
+ eglQueryStringImplementationANDROID(display, EGL_EXTENSIONS));
+
// The code assumes that ES2 or later is available if this extension is
// supported.
EGLConfig config = EGL_NO_CONFIG;
- if (!findExtension(eglQueryStringImplementationANDROID(display, EGL_EXTENSIONS),
- "EGL_ANDROIDX_no_config_context") &&
- !findExtension(eglQueryStringImplementationANDROID(display, EGL_EXTENSIONS),
- "EGL_KHR_no_config_context")) {
+ if (!extensions.hasNoConfigContext()) {
config = chooseEglConfig(display, hwcFormat, /*logConfig*/ true);
}
@@ -99,7 +79,7 @@
contextAttributes.push_back(EGL_NONE);
contextAttributes.push_back(EGL_NONE);
- EGLContext ctxt = eglCreateContext(display, config, NULL, contextAttributes.data());
+ EGLContext ctxt = eglCreateContext(display, config, nullptr, contextAttributes.data());
// if can't create a GL context, we can only abort.
LOG_ALWAYS_FATAL_IF(ctxt == EGL_NO_CONTEXT, "EGLContext creation failed");
@@ -117,7 +97,6 @@
EGLBoolean success = eglMakeCurrent(display, dummy, dummy, ctxt);
LOG_ALWAYS_FATAL_IF(!success, "can't make dummy pbuffer current");
- GLExtensions& extensions(GLExtensions::getInstance());
extensions.initWithGLStrings(glGetString(GL_VENDOR), glGetString(GL_RENDERER),
glGetString(GL_VERSION), glGetString(GL_EXTENSIONS));
@@ -142,7 +121,7 @@
ALOGI("vendor : %s", extensions.getVendor());
ALOGI("renderer : %s", extensions.getRenderer());
ALOGI("version : %s", extensions.getVersion());
- ALOGI("extensions: %s", extensions.getExtension());
+ ALOGI("extensions: %s", extensions.getExtensions());
ALOGI("GL_MAX_TEXTURE_SIZE = %zu", engine->getMaxTextureSize());
ALOGI("GL_MAX_VIEWPORT_DIMS = %zu", engine->getMaxViewportDims());
@@ -153,7 +132,7 @@
}
RenderEngine::RenderEngine()
- : mEGLDisplay(EGL_NO_DISPLAY), mEGLConfig(NULL), mEGLContext(EGL_NO_CONTEXT) {}
+ : mEGLDisplay(EGL_NO_DISPLAY), mEGLConfig(nullptr), mEGLContext(EGL_NO_CONTEXT) {}
RenderEngine::~RenderEngine() {
eglMakeCurrent(mEGLDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
@@ -174,6 +153,14 @@
return mEGLConfig;
}
+bool RenderEngine::supportsImageCrop() const {
+ return GLExtensions::getInstance().hasImageCrop();
+}
+
+bool RenderEngine::isCurrent() const {
+ return mEGLDisplay == eglGetCurrentDisplay() && mEGLContext == eglGetCurrentContext();
+}
+
bool RenderEngine::setCurrentSurface(const RE::Surface& surface) {
bool success = true;
EGLSurface eglSurface = surface.getEGLSurface();
@@ -191,6 +178,88 @@
eglMakeCurrent(mEGLDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
}
+base::unique_fd RenderEngine::flush() {
+ if (!GLExtensions::getInstance().hasNativeFenceSync()) {
+ return base::unique_fd();
+ }
+
+ EGLSyncKHR sync = eglCreateSyncKHR(mEGLDisplay, EGL_SYNC_NATIVE_FENCE_ANDROID, nullptr);
+ if (sync == EGL_NO_SYNC_KHR) {
+ ALOGW("failed to create EGL native fence sync: %#x", eglGetError());
+ return base::unique_fd();
+ }
+
+ // native fence fd will not be populated until flush() is done.
+ glFlush();
+
+ // get the fence fd
+ base::unique_fd fenceFd(eglDupNativeFenceFDANDROID(mEGLDisplay, sync));
+ eglDestroySyncKHR(mEGLDisplay, sync);
+ if (fenceFd == EGL_NO_NATIVE_FENCE_FD_ANDROID) {
+ ALOGW("failed to dup EGL native fence sync: %#x", eglGetError());
+ }
+
+ return fenceFd;
+}
+
+bool RenderEngine::finish() {
+ if (!GLExtensions::getInstance().hasFenceSync()) {
+ ALOGW("no synchronization support");
+ return false;
+ }
+
+ EGLSyncKHR sync = eglCreateSyncKHR(mEGLDisplay, EGL_SYNC_FENCE_KHR, nullptr);
+ if (sync == EGL_NO_SYNC_KHR) {
+ ALOGW("failed to create EGL fence sync: %#x", eglGetError());
+ return false;
+ }
+
+ EGLint result = eglClientWaitSyncKHR(mEGLDisplay, sync, EGL_SYNC_FLUSH_COMMANDS_BIT_KHR,
+ 2000000000 /*2 sec*/);
+ EGLint error = eglGetError();
+ eglDestroySyncKHR(mEGLDisplay, sync);
+ if (result != EGL_CONDITION_SATISFIED_KHR) {
+ if (result == EGL_TIMEOUT_EXPIRED_KHR) {
+ ALOGW("fence wait timed out");
+ } else {
+ ALOGW("error waiting on EGL fence: %#x", error);
+ }
+ return false;
+ }
+
+ return true;
+}
+
+bool RenderEngine::waitFence(base::unique_fd fenceFd) {
+ if (!GLExtensions::getInstance().hasNativeFenceSync() ||
+ !GLExtensions::getInstance().hasWaitSync()) {
+ return false;
+ }
+
+ EGLint attribs[] = {EGL_SYNC_NATIVE_FENCE_FD_ANDROID, fenceFd, EGL_NONE};
+ EGLSyncKHR sync = eglCreateSyncKHR(mEGLDisplay, EGL_SYNC_NATIVE_FENCE_ANDROID, attribs);
+ if (sync == EGL_NO_SYNC_KHR) {
+ ALOGE("failed to create EGL native fence sync: %#x", eglGetError());
+ return false;
+ }
+
+ // fenceFd is now owned by EGLSync
+ (void)fenceFd.release();
+
+ // XXX: The spec draft is inconsistent as to whether this should return an
+ // EGLint or void. Ignore the return value for now, as it's not strictly
+ // needed.
+ eglWaitSyncKHR(mEGLDisplay, sync, 0);
+ EGLint error = eglGetError();
+ eglDestroySyncKHR(mEGLDisplay, sync);
+ if (error != EGL_SUCCESS) {
+ ALOGE("failed to wait for EGL native fence sync: %#x", error);
+ return false;
+ }
+
+ return true;
+}
+
void RenderEngine::checkErrors() const {
do {
// there could be more than one error flag
@@ -242,52 +311,6 @@
drawMesh(mesh);
}
-int RenderEngine::flush(bool wait) {
- // Attempt to create a sync khr object that can produce a sync point. If that
- // isn't available, create a non-dupable sync object in the fallback path and
- // wait on it directly.
- EGLSyncKHR sync;
- if (!wait) {
- EGLint syncFd = EGL_NO_NATIVE_FENCE_FD_ANDROID;
-
- sync = eglCreateSyncKHR(mEGLDisplay, EGL_SYNC_NATIVE_FENCE_ANDROID, NULL);
- if (sync != EGL_NO_SYNC_KHR) {
- // native fence fd will not be populated until flush() is done.
- glFlush();
-
- // get the sync fd
- syncFd = eglDupNativeFenceFDANDROID(mEGLDisplay, sync);
- if (syncFd == EGL_NO_NATIVE_FENCE_FD_ANDROID) {
- ALOGW("failed to dup sync khr object");
- }
-
- eglDestroySyncKHR(mEGLDisplay, sync);
- }
-
- if (syncFd != EGL_NO_NATIVE_FENCE_FD_ANDROID) {
- return syncFd;
- }
- }
-
- // fallback or explicit wait
- sync = eglCreateSyncKHR(mEGLDisplay, EGL_SYNC_FENCE_KHR, NULL);
- if (sync != EGL_NO_SYNC_KHR) {
- EGLint result = eglClientWaitSyncKHR(mEGLDisplay, sync, EGL_SYNC_FLUSH_COMMANDS_BIT_KHR,
- 2000000000 /*2 sec*/);
- EGLint eglErr = eglGetError();
- if (result == EGL_TIMEOUT_EXPIRED_KHR) {
- ALOGW("fence wait timed out");
- } else {
- ALOGW_IF(eglErr != EGL_SUCCESS, "error waiting on EGL fence: %#x", eglErr);
- }
- eglDestroySyncKHR(mEGLDisplay, sync);
- } else {
- ALOGW("error creating EGL fence: %#x", eglGetError());
- }
-
- return -1;
-}
-
void RenderEngine::clearWithColor(float red, float green, float blue, float alpha) {
glClearColor(red, green, blue, alpha);
glClear(GL_COLOR_BUFFER_BIT);
@@ -310,19 +333,28 @@
glDeleteTextures(count, names);
}
+void RenderEngine::bindExternalTextureImage(uint32_t texName, const RE::Image& image) {
+ const GLenum target = GL_TEXTURE_EXTERNAL_OES;
+
+ glBindTexture(target, texName);
+ if (image.getEGLImage() != EGL_NO_IMAGE_KHR) {
+ glEGLImageTargetTexture2DOES(target, static_cast<GLeglImageOES>(image.getEGLImage()));
+ }
+}
+
void RenderEngine::readPixels(size_t l, size_t b, size_t w, size_t h, uint32_t* pixels) {
glReadPixels(l, b, w, h, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
}
void RenderEngine::dump(String8& result) {
- result.appendFormat("EGL implementation : %s\n",
- eglQueryStringImplementationANDROID(mEGLDisplay, EGL_VERSION));
- result.appendFormat("%s\n", eglQueryStringImplementationANDROID(mEGLDisplay, EGL_EXTENSIONS));
+ const GLExtensions& extensions = GLExtensions::getInstance();
- const GLExtensions& extensions(GLExtensions::getInstance());
+ result.appendFormat("EGL implementation : %s\n", extensions.getEGLVersion());
+ result.appendFormat("%s\n", extensions.getEGLExtensions());
+
result.appendFormat("GLES: %s, %s, %s\n", extensions.getVendor(), extensions.getRenderer(),
extensions.getVersion());
- result.appendFormat("%s\n", extensions.getExtension());
+ result.appendFormat("%s\n", extensions.getExtensions());
}
// ---------------------------------------------------------------------------
@@ -331,7 +363,7 @@
RenderEngine& engine, ANativeWindowBuffer* buffer)
: mEngine(engine) {
mImage = eglCreateImageKHR(mEngine.mEGLDisplay, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID,
- buffer, NULL);
+ buffer, nullptr);
if (mImage == EGL_NO_IMAGE_KHR) {
mStatus = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
return;
@@ -362,7 +394,7 @@
static status_t selectConfigForAttribute(EGLDisplay dpy, EGLint const* attrs, EGLint attribute,
EGLint wanted, EGLConfig* outConfig) {
EGLint numConfigs = -1, n = 0;
- eglGetConfigs(dpy, NULL, 0, &numConfigs);
+ eglGetConfigs(dpy, nullptr, 0, &numConfigs);
EGLConfig* const configs = new EGLConfig[numConfigs];
eglChooseConfig(dpy, attrs, configs, numConfigs, &n);
diff --git a/services/surfaceflinger/RenderEngine/RenderEngine.h b/services/surfaceflinger/RenderEngine/RenderEngine.h
index 3847347..f886919 100644
--- a/services/surfaceflinger/RenderEngine/RenderEngine.h
+++ b/services/surfaceflinger/RenderEngine/RenderEngine.h
@@ -25,6 +25,7 @@
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <Transform.h>
+#include <android-base/unique_fd.h>
#include <gui/SurfaceControl.h>
#include <math/mat4.h>
@@ -43,8 +44,9 @@
class Texture;
namespace RE {
+class Image;
class Surface;
-}
+} // namespace RE
class RenderEngine {
enum GlesVersion {
@@ -82,9 +84,26 @@
// dump the extension strings. always call the base class.
virtual void dump(String8& result);
+ bool supportsImageCrop() const;
+
+ bool isCurrent() const;
+ bool setCurrentSurface(const RE::Surface& surface);
+ void resetCurrentSurface();
+
+ // synchronization
+
+ // flush submits RenderEngine command stream for execution and returns a
+ // native fence fd that is signaled when the execution has completed. It
+ // returns -1 on errors.
+ base::unique_fd flush();
+ // finish waits until RenderEngine command stream has been executed. It
+ // returns false on errors.
+ bool finish();
+ // waitFence inserts a wait on an external fence fd to RenderEngine
+ // command stream. It returns false on errors.
+ bool waitFence(base::unique_fd fenceFd);
+
// helpers
- // flush returns -1 or a valid native fence fd owned by the caller
- int flush(bool wait);
void clearWithColor(float red, float green, float blue, float alpha);
void fillRegionWithColor(const Region& region, uint32_t height, float red, float green,
float blue, float alpha);
@@ -94,6 +113,7 @@
void disableScissor();
void genTextures(size_t count, uint32_t* names);
void deleteTextures(size_t count, uint32_t const* names);
+ void bindExternalTextureImage(uint32_t texName, const RE::Image& image);
void readPixels(size_t l, size_t b, size_t w, size_t h, uint32_t* pixels);
class BindNativeBufferAsFramebuffer {
@@ -108,9 +128,6 @@
int getStatus() const;
};
- bool setCurrentSurface(const RE::Surface& surface);
- void resetCurrentSurface();
-
// set-up
virtual void checkErrors() const;
virtual void setViewportAndProjection(size_t vpw, size_t vph, Rect sourceCrop, size_t hwh,
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 44d5ce4..f21a691 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -136,6 +136,7 @@
bool SurfaceFlinger::hasSyncFramework;
bool SurfaceFlinger::useVrFlinger;
int64_t SurfaceFlinger::maxFrameBufferAcquiredBuffers;
+// TODO(courtneygo): Rename hasWideColorDisplay to clarify its actual meaning.
bool SurfaceFlinger::hasWideColorDisplay;
@@ -368,21 +369,10 @@
setTransactionFlags(eDisplayTransactionNeeded);
}
-void SurfaceFlinger::createBuiltinDisplayLocked(DisplayDevice::DisplayType type) {
- ALOGV("createBuiltinDisplayLocked(%d)", type);
- ALOGW_IF(mBuiltinDisplays[type],
- "Overwriting display token for display type %d", type);
- mBuiltinDisplays[type] = new BBinder();
- // All non-virtual displays are currently considered secure.
- DisplayDeviceState info(type, true);
- mCurrentState.displays.add(mBuiltinDisplays[type], info);
- mInterceptor.saveDisplayCreation(info);
-}
-
sp<IBinder> SurfaceFlinger::getBuiltInDisplay(int32_t id) {
if (uint32_t(id) >= DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES) {
ALOGE("getDefaultDisplay: id=%d is not a valid default display id", id);
- return NULL;
+ return nullptr;
}
return mBuiltinDisplays[id];
}
@@ -531,7 +521,7 @@
}
}
- if (callback != NULL) {
+ if (callback != nullptr) {
callback->onVSyncEvent(when);
}
}
@@ -618,6 +608,14 @@
"Starting with vr flinger active is not currently supported.");
getBE().mHwc.reset(new HWComposer(getBE().mHwcServiceName));
getBE().mHwc->registerCallback(this, getBE().mComposerSequenceId);
+ // Process any initial hotplug and resulting display changes.
+ processDisplayHotplugEventsLocked();
+ LOG_ALWAYS_FATAL_IF(!getBE().mHwc->isConnected(HWC_DISPLAY_PRIMARY),
+ "Registered composer callback but didn't create the default primary display");
+
+ // make the default display GLContext current so that we can create textures
+ // when creating Layers (which may happens before we render something)
+ getDefaultDisplayDeviceLocked()->makeCurrent();
if (useVrFlinger) {
auto vrFlingerRequestDisplayCallback = [this] (bool requestDisplay) {
@@ -737,7 +735,7 @@
status_t SurfaceFlinger::getDisplayConfigs(const sp<IBinder>& display,
Vector<DisplayInfo>* configs) {
- if ((configs == NULL) || (display.get() == NULL)) {
+ if (configs == nullptr || display.get() == nullptr) {
return BAD_VALUE;
}
@@ -761,7 +759,7 @@
static int getDensityFromProperty(char const* propName) {
char property[PROPERTY_VALUE_MAX];
int density = 0;
- if (property_get(propName, property, NULL) > 0) {
+ if (property_get(propName, property, nullptr) > 0) {
density = atoi(property);
}
return density;
@@ -801,7 +799,7 @@
// TODO: this needs to go away (currently needed only by webkit)
sp<const DisplayDevice> hw(getDefaultDisplayDeviceLocked());
- info.orientation = hw->getOrientation();
+ info.orientation = hw ? hw->getOrientation() : 0;
} else {
// TODO: where should this value come from?
static const int TV_DENSITY = 213;
@@ -842,7 +840,7 @@
status_t SurfaceFlinger::getDisplayStats(const sp<IBinder>& /* display */,
DisplayStatInfo* stats) {
- if (stats == NULL) {
+ if (stats == nullptr) {
return BAD_VALUE;
}
@@ -854,13 +852,13 @@
}
int SurfaceFlinger::getActiveConfig(const sp<IBinder>& display) {
- if (display == NULL) {
- ALOGE("%s : display is NULL", __func__);
+ if (display == nullptr) {
+ ALOGE("%s : display is nullptr", __func__);
return BAD_VALUE;
}
sp<const DisplayDevice> device(getDisplayDevice(display));
- if (device != NULL) {
+ if (device != nullptr) {
return device->getActiveConfig();
}
@@ -905,7 +903,7 @@
return true;
}
sp<DisplayDevice> hw(mFlinger.getDisplayDevice(mDisplay));
- if (hw == NULL) {
+ if (hw == nullptr) {
ALOGE("Attempt to set active config = %d for null display %p",
mMode, mDisplay.get());
} else if (hw->getDisplayType() >= DisplayDevice::DISPLAY_VIRTUAL) {
@@ -1266,94 +1264,25 @@
*compositorTiming = getBE().mCompositorTiming;
}
-void SurfaceFlinger::createDefaultDisplayDevice() {
- const DisplayDevice::DisplayType type = DisplayDevice::DISPLAY_PRIMARY;
- wp<IBinder> token = mBuiltinDisplays[type];
+void SurfaceFlinger::onHotplugReceived(int32_t sequenceId, hwc2_display_t display,
+ HWC2::Connection connection) {
+ ALOGV("onHotplugReceived(%d, %" PRIu64 ", %s)", sequenceId, display,
+ connection == HWC2::Connection::Connected ? "connected" : "disconnected");
- // All non-virtual displays are currently considered secure.
- const bool isSecure = true;
-
- sp<IGraphicBufferProducer> producer;
- sp<IGraphicBufferConsumer> consumer;
- BufferQueue::createBufferQueue(&producer, &consumer);
-
- sp<FramebufferSurface> fbs = new FramebufferSurface(*getBE().mHwc, type, consumer);
-
- bool hasWideColorModes = false;
- std::vector<android_color_mode_t> modes = getHwComposer().getColorModes(type);
- for (android_color_mode_t colorMode : modes) {
- switch (colorMode) {
- case HAL_COLOR_MODE_DISPLAY_P3:
- case HAL_COLOR_MODE_ADOBE_RGB:
- case HAL_COLOR_MODE_DCI_P3:
- hasWideColorModes = true;
- break;
- default:
- break;
- }
+ // Ignore events that do not have the right sequenceId.
+ if (sequenceId != getBE().mComposerSequenceId) {
+ return;
}
- bool useWideColorMode = hasWideColorModes && hasWideColorDisplay && !mForceNativeColorMode;
- sp<DisplayDevice> hw = new DisplayDevice(this, DisplayDevice::DISPLAY_PRIMARY, type, isSecure,
- token, fbs, producer, useWideColorMode);
- mDisplays.add(token, hw);
- android_color_mode defaultColorMode = HAL_COLOR_MODE_NATIVE;
- if (useWideColorMode) {
- defaultColorMode = HAL_COLOR_MODE_SRGB;
- }
- setActiveColorModeInternal(hw, defaultColorMode);
- hw->setCompositionDataSpace(HAL_DATASPACE_UNKNOWN);
-
- // Add the primary display token to mDrawingState so we don't try to
- // recreate the DisplayDevice for the primary display.
- mDrawingState.displays.add(token, DisplayDeviceState(type, true));
-
- // make the GLContext current so that we can create textures when creating
- // Layers (which may happens before we render something)
- hw->makeCurrent();
-}
-
-void SurfaceFlinger::onHotplugReceived(int32_t sequenceId,
- hwc2_display_t display, HWC2::Connection connection,
- bool primaryDisplay) {
- ALOGV("onHotplugReceived(%d, %" PRIu64 ", %s, %s)",
- sequenceId, display,
- connection == HWC2::Connection::Connected ?
- "connected" : "disconnected",
- primaryDisplay ? "primary" : "external");
// Only lock if we're not on the main thread. This function is normally
// called on a hwbinder thread, but for the primary display it's called on
// the main thread with the state lock already held, so don't attempt to
// acquire it here.
- ConditionalLock lock(mStateLock,
- std::this_thread::get_id() != mMainThreadId);
+ ConditionalLock lock(mStateLock, std::this_thread::get_id() != mMainThreadId);
- if (primaryDisplay) {
- getBE().mHwc->onHotplug(display, connection);
- if (!mBuiltinDisplays[DisplayDevice::DISPLAY_PRIMARY].get()) {
- createBuiltinDisplayLocked(DisplayDevice::DISPLAY_PRIMARY);
- }
- createDefaultDisplayDevice();
- } else {
- if (sequenceId != getBE().mComposerSequenceId) {
- return;
- }
- if (getBE().mHwc->isUsingVrComposer()) {
- ALOGE("External displays are not supported by the vr hardware composer.");
- return;
- }
- getBE().mHwc->onHotplug(display, connection);
- auto type = DisplayDevice::DISPLAY_EXTERNAL;
- if (connection == HWC2::Connection::Connected) {
- createBuiltinDisplayLocked(type);
- } else {
- mCurrentState.displays.removeItem(mBuiltinDisplays[type]);
- mBuiltinDisplays[type].clear();
- }
- setTransactionFlags(eDisplayTransactionNeeded);
+ mPendingHotplugEvents.emplace_back(HotplugEvent{display, connection});
- // Defer EventThread notification until SF has updated mDisplays.
- }
+ setTransactionFlags(eDisplayTransactionNeeded);
}
void SurfaceFlinger::onRefreshReceived(int sequenceId,
@@ -1668,7 +1597,7 @@
getBE().mGlCompositionDoneTimeline.updateSignalTimes();
std::shared_ptr<FenceTime> glCompositionDoneFenceTime;
- if (getBE().mHwc->hasClientComposition(HWC_DISPLAY_PRIMARY)) {
+ if (hw && getBE().mHwc->hasClientComposition(HWC_DISPLAY_PRIMARY)) {
glCompositionDoneFenceTime =
std::make_shared<FenceTime>(hw->getClientTargetAcquireFence());
getBE().mGlCompositionDoneTimeline.push(glCompositionDoneFenceTime);
@@ -1713,7 +1642,7 @@
}
if (!hasSyncFramework) {
- if (hw->isDisplayOn()) {
+ if (getBE().mHwc->isConnected(HWC_DISPLAY_PRIMARY) && hw->isDisplayOn()) {
enableHardwareVsync();
}
}
@@ -1724,7 +1653,7 @@
if (presentFenceTime->isValid()) {
mAnimFrameTracker.setActualPresentFence(
std::move(presentFenceTime));
- } else {
+ } else if (getBE().mHwc->isConnected(HWC_DISPLAY_PRIMARY)) {
// The HWC doesn't support present fences, so use the refresh
// timestamp instead.
nsecs_t presentTime =
@@ -1734,7 +1663,8 @@
mAnimFrameTracker.advanceFrame();
}
- if (hw->getPowerMode() == HWC_POWER_MODE_OFF) {
+ if (getBE().mHwc->isConnected(HWC_DISPLAY_PRIMARY) &&
+ hw->getPowerMode() == HWC_POWER_MODE_OFF) {
return;
}
@@ -2077,9 +2007,11 @@
mDebugInSwapBuffers = 0;
// |mStateLock| not needed as we are on the main thread
- uint32_t flipCount = getDefaultDisplayDeviceLocked()->getPageFlipCount();
- if (flipCount % LOG_FRAME_STATS_PERIOD == 0) {
- logFrameStats();
+ if (getBE().mHwc->isConnected(HWC_DISPLAY_PRIMARY)) {
+ uint32_t flipCount = getDefaultDisplayDeviceLocked()->getPageFlipCount();
+ if (flipCount % LOG_FRAME_STATS_PERIOD == 0) {
+ logFrameStats();
+ }
}
}
@@ -2112,6 +2044,245 @@
// here the transaction has been committed
}
+DisplayDevice::DisplayType SurfaceFlinger::determineDisplayType(hwc2_display_t display,
+ HWC2::Connection connection) const {
+ // Figure out whether the event is for the primary display or an
+ // external display by matching the Hwc display id against one for a
+ // connected display. If we did not find a match, we then check what
+ // displays are not already connected to determine the type. If we don't
+ // have a connected primary display, we assume the new display is meant to
+ // be the primary display, and then if we don't have an external display,
+ // we assume it is that.
+ const auto primaryDisplayId =
+ getBE().mHwc->getHwcDisplayId(DisplayDevice::DISPLAY_PRIMARY);
+ const auto externalDisplayId =
+ getBE().mHwc->getHwcDisplayId(DisplayDevice::DISPLAY_EXTERNAL);
+ if (primaryDisplayId && primaryDisplayId == display) {
+ return DisplayDevice::DISPLAY_PRIMARY;
+ } else if (externalDisplayId && externalDisplayId == display) {
+ return DisplayDevice::DISPLAY_EXTERNAL;
+ } else if (connection == HWC2::Connection::Connected && !primaryDisplayId) {
+ return DisplayDevice::DISPLAY_PRIMARY;
+ } else if (connection == HWC2::Connection::Connected && !externalDisplayId) {
+ return DisplayDevice::DISPLAY_EXTERNAL;
+ }
+
+ return DisplayDevice::DISPLAY_ID_INVALID;
+}
+
+void SurfaceFlinger::processDisplayHotplugEventsLocked() {
+ for (const auto& event : mPendingHotplugEvents) {
+ auto displayType = determineDisplayType(event.display, event.connection);
+ if (displayType == DisplayDevice::DISPLAY_ID_INVALID) {
+ ALOGW("Unable to determine the display type for display %" PRIu64, event.display);
+ continue;
+ }
+
+ if (getBE().mHwc->isUsingVrComposer() && displayType == DisplayDevice::DISPLAY_EXTERNAL) {
+ ALOGE("External displays are not supported by the vr hardware composer.");
+ continue;
+ }
+
+ getBE().mHwc->onHotplug(event.display, displayType, event.connection);
+
+ if (event.connection == HWC2::Connection::Connected) {
+ ALOGV("Creating built in display %d", displayType);
+ ALOGW_IF(mBuiltinDisplays[displayType],
+ "Overwriting display token for display type %d", displayType);
+ mBuiltinDisplays[displayType] = new BBinder();
+ // All non-virtual displays are currently considered secure.
+ DisplayDeviceState info(displayType, true);
+ info.displayName = displayType == DisplayDevice::DISPLAY_PRIMARY ?
+ "Built-in Screen" : "External Screen";
+ mCurrentState.displays.add(mBuiltinDisplays[displayType], info);
+ mInterceptor.saveDisplayCreation(info);
+ } else {
+ ALOGV("Removing built in display %d", displayType);
+
+ ssize_t idx = mCurrentState.displays.indexOfKey(mBuiltinDisplays[displayType]);
+ if (idx >= 0) {
+ const DisplayDeviceState& info(mCurrentState.displays.valueAt(idx));
+ mInterceptor.saveDisplayDeletion(info.displayId);
+ mCurrentState.displays.removeItemsAt(idx);
+ }
+ mBuiltinDisplays[displayType].clear();
+ }
+
+ processDisplayChangesLocked();
+ }
+
+ mPendingHotplugEvents.clear();
+}
+
+void SurfaceFlinger::processDisplayChangesLocked() {
+ // here we take advantage of Vector's copy-on-write semantics to
+ // improve performance by skipping the transaction entirely when
+ // know that the lists are identical
+ const KeyedVector<wp<IBinder>, DisplayDeviceState>& curr(mCurrentState.displays);
+ const KeyedVector<wp<IBinder>, DisplayDeviceState>& draw(mDrawingState.displays);
+ if (!curr.isIdenticalTo(draw)) {
+ mVisibleRegionsDirty = true;
+ const size_t cc = curr.size();
+ size_t dc = draw.size();
+
+ // find the displays that were removed
+ // (ie: in drawing state but not in current state)
+ // also handle displays that changed
+ // (ie: displays that are in both lists)
+ for (size_t i = 0; i < dc;) {
+ const ssize_t j = curr.indexOfKey(draw.keyAt(i));
+ if (j < 0) {
+ // in drawing state but not in current state
+ // Call makeCurrent() on the primary display so we can
+ // be sure that nothing associated with this display
+ // is current.
+ const sp<const DisplayDevice> defaultDisplay(getDefaultDisplayDeviceLocked());
+ if (defaultDisplay != nullptr) defaultDisplay->makeCurrent();
+ sp<DisplayDevice> hw(getDisplayDeviceLocked(draw.keyAt(i)));
+ if (hw != nullptr) hw->disconnect(getHwComposer());
+ if (draw[i].type < DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES)
+ mEventThread->onHotplugReceived(draw[i].type, false);
+ mDisplays.removeItem(draw.keyAt(i));
+ } else {
+ // this display is in both lists. see if something changed.
+ const DisplayDeviceState& state(curr[j]);
+ const wp<IBinder>& display(curr.keyAt(j));
+ const sp<IBinder> state_binder = IInterface::asBinder(state.surface);
+ const sp<IBinder> draw_binder = IInterface::asBinder(draw[i].surface);
+ if (state_binder != draw_binder) {
+ // changing the surface is like destroying and
+ // recreating the DisplayDevice, so we just remove it
+ // from the drawing state, so that it get re-added
+ // below.
+ sp<DisplayDevice> hw(getDisplayDeviceLocked(display));
+ if (hw != nullptr) hw->disconnect(getHwComposer());
+ mDisplays.removeItem(display);
+ mDrawingState.displays.removeItemsAt(i);
+ dc--;
+ // at this point we must loop to the next item
+ continue;
+ }
+
+ const sp<DisplayDevice> disp(getDisplayDeviceLocked(display));
+ if (disp != nullptr) {
+ if (state.layerStack != draw[i].layerStack) {
+ disp->setLayerStack(state.layerStack);
+ }
+ if ((state.orientation != draw[i].orientation) ||
+ (state.viewport != draw[i].viewport) || (state.frame != draw[i].frame)) {
+ disp->setProjection(state.orientation, state.viewport, state.frame);
+ }
+ if (state.width != draw[i].width || state.height != draw[i].height) {
+ disp->setDisplaySize(state.width, state.height);
+ }
+ }
+ }
+ ++i;
+ }
+
+ // find displays that were added
+ // (ie: in current state but not in drawing state)
+ for (size_t i = 0; i < cc; i++) {
+ if (draw.indexOfKey(curr.keyAt(i)) < 0) {
+ const DisplayDeviceState& state(curr[i]);
+
+ sp<DisplaySurface> dispSurface;
+ sp<IGraphicBufferProducer> producer;
+ sp<IGraphicBufferProducer> bqProducer;
+ sp<IGraphicBufferConsumer> bqConsumer;
+ BufferQueue::createBufferQueue(&bqProducer, &bqConsumer);
+
+ int32_t hwcId = -1;
+ if (state.isVirtualDisplay()) {
+ // Virtual displays without a surface are dormant:
+ // they have external state (layer stack, projection,
+ // etc.) but no internal state (i.e. a DisplayDevice).
+ if (state.surface != nullptr) {
+ // Allow VR composer to use virtual displays.
+ if (mUseHwcVirtualDisplays || getBE().mHwc->isUsingVrComposer()) {
+ int width = 0;
+ int status = state.surface->query(NATIVE_WINDOW_WIDTH, &width);
+ ALOGE_IF(status != NO_ERROR, "Unable to query width (%d)", status);
+ int height = 0;
+ status = state.surface->query(NATIVE_WINDOW_HEIGHT, &height);
+ ALOGE_IF(status != NO_ERROR, "Unable to query height (%d)", status);
+ int intFormat = 0;
+ status = state.surface->query(NATIVE_WINDOW_FORMAT, &intFormat);
+ ALOGE_IF(status != NO_ERROR, "Unable to query format (%d)", status);
+ auto format = static_cast<android_pixel_format_t>(intFormat);
+
+ getBE().mHwc->allocateVirtualDisplay(width, height, &format, &hwcId);
+ }
+
+ // TODO: Plumb requested format back up to consumer
+
+ sp<VirtualDisplaySurface> vds =
+ new VirtualDisplaySurface(*getBE().mHwc, hwcId, state.surface,
+ bqProducer, bqConsumer,
+ state.displayName);
+
+ dispSurface = vds;
+ producer = vds;
+ }
+ } else {
+ ALOGE_IF(state.surface != nullptr,
+ "adding a supported display, but rendering "
+ "surface is provided (%p), ignoring it",
+ state.surface.get());
+
+ hwcId = state.type;
+ dispSurface = new FramebufferSurface(*getBE().mHwc, hwcId, bqConsumer);
+ producer = bqProducer;
+ }
+
+ const wp<IBinder>& display(curr.keyAt(i));
+
+ if (dispSurface != nullptr) {
+ bool useWideColorMode = hasWideColorDisplay;
+ if (!mForceNativeColorMode) {
+ bool hasWideColorModes = false;
+ std::vector<android_color_mode_t> modes =
+ getHwComposer().getColorModes(state.type);
+ for (android_color_mode_t colorMode : modes) {
+ switch (colorMode) {
+ case HAL_COLOR_MODE_DISPLAY_P3:
+ case HAL_COLOR_MODE_ADOBE_RGB:
+ case HAL_COLOR_MODE_DCI_P3:
+ hasWideColorModes = true;
+ break;
+ default:
+ break;
+ }
+ }
+ useWideColorMode = hasWideColorModes && hasWideColorDisplay;
+ }
+
+ sp<DisplayDevice> hw =
+ new DisplayDevice(this, state.type, hwcId, state.isSecure, display,
+ dispSurface, producer, useWideColorMode);
+
+ android_color_mode defaultColorMode = HAL_COLOR_MODE_NATIVE;
+ if (useWideColorMode) {
+ defaultColorMode = HAL_COLOR_MODE_SRGB;
+ }
+ setActiveColorModeInternal(hw, defaultColorMode);
+ hw->setCompositionDataSpace(HAL_DATASPACE_UNKNOWN);
+ hw->setLayerStack(state.layerStack);
+ hw->setProjection(state.orientation, state.viewport, state.frame);
+ hw->setDisplayName(state.displayName);
+
+ mDisplays.add(display, hw);
+ if (!state.isVirtualDisplay()) {
+ mEventThread->onHotplugReceived(state.type, true);
+ }
+ }
+ }
+ }
+ }
+
+ mDrawingState.displays = mCurrentState.displays;
+}
+
void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags)
{
// Notify all layers of available frames
@@ -2140,161 +2311,8 @@
*/
if (transactionFlags & eDisplayTransactionNeeded) {
- // here we take advantage of Vector's copy-on-write semantics to
- // improve performance by skipping the transaction entirely when
- // know that the lists are identical
- const KeyedVector< wp<IBinder>, DisplayDeviceState>& curr(mCurrentState.displays);
- const KeyedVector< wp<IBinder>, DisplayDeviceState>& draw(mDrawingState.displays);
- if (!curr.isIdenticalTo(draw)) {
- mVisibleRegionsDirty = true;
- const size_t cc = curr.size();
- size_t dc = draw.size();
-
- // find the displays that were removed
- // (ie: in drawing state but not in current state)
- // also handle displays that changed
- // (ie: displays that are in both lists)
- for (size_t i=0 ; i<dc ;) {
- const ssize_t j = curr.indexOfKey(draw.keyAt(i));
- if (j < 0) {
- // in drawing state but not in current state
- if (!draw[i].isMainDisplay()) {
- // Call makeCurrent() on the primary display so we can
- // be sure that nothing associated with this display
- // is current.
- const sp<const DisplayDevice> defaultDisplay(getDefaultDisplayDeviceLocked());
- defaultDisplay->makeCurrent();
- sp<DisplayDevice> hw(getDisplayDeviceLocked(draw.keyAt(i)));
- if (hw != NULL)
- hw->disconnect(getHwComposer());
- if (draw[i].type < DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES)
- mEventThread->onHotplugReceived(draw[i].type, false);
- mDisplays.removeItem(draw.keyAt(i));
- } else {
- ALOGW("trying to remove the main display");
- }
- } else {
- // this display is in both lists. see if something changed.
- const DisplayDeviceState& state(curr[j]);
- const wp<IBinder>& display(curr.keyAt(j));
- const sp<IBinder> state_binder = IInterface::asBinder(state.surface);
- const sp<IBinder> draw_binder = IInterface::asBinder(draw[i].surface);
- if (state_binder != draw_binder) {
- // changing the surface is like destroying and
- // recreating the DisplayDevice, so we just remove it
- // from the drawing state, so that it get re-added
- // below.
- sp<DisplayDevice> hw(getDisplayDeviceLocked(display));
- if (hw != NULL)
- hw->disconnect(getHwComposer());
- mDisplays.removeItem(display);
- mDrawingState.displays.removeItemsAt(i);
- dc--;
- // at this point we must loop to the next item
- continue;
- }
-
- const sp<DisplayDevice> disp(getDisplayDeviceLocked(display));
- if (disp != NULL) {
- if (state.layerStack != draw[i].layerStack) {
- disp->setLayerStack(state.layerStack);
- }
- if ((state.orientation != draw[i].orientation)
- || (state.viewport != draw[i].viewport)
- || (state.frame != draw[i].frame))
- {
- disp->setProjection(state.orientation,
- state.viewport, state.frame);
- }
- if (state.width != draw[i].width || state.height != draw[i].height) {
- disp->setDisplaySize(state.width, state.height);
- }
- }
- }
- ++i;
- }
-
- // find displays that were added
- // (ie: in current state but not in drawing state)
- for (size_t i=0 ; i<cc ; i++) {
- if (draw.indexOfKey(curr.keyAt(i)) < 0) {
- const DisplayDeviceState& state(curr[i]);
-
- sp<DisplaySurface> dispSurface;
- sp<IGraphicBufferProducer> producer;
- sp<IGraphicBufferProducer> bqProducer;
- sp<IGraphicBufferConsumer> bqConsumer;
- BufferQueue::createBufferQueue(&bqProducer, &bqConsumer);
-
- int32_t hwcId = -1;
- if (state.isVirtualDisplay()) {
- // Virtual displays without a surface are dormant:
- // they have external state (layer stack, projection,
- // etc.) but no internal state (i.e. a DisplayDevice).
- if (state.surface != NULL) {
-
- // Allow VR composer to use virtual displays.
- if (mUseHwcVirtualDisplays || getBE().mHwc->isUsingVrComposer()) {
- int width = 0;
- int status = state.surface->query(
- NATIVE_WINDOW_WIDTH, &width);
- ALOGE_IF(status != NO_ERROR,
- "Unable to query width (%d)", status);
- int height = 0;
- status = state.surface->query(
- NATIVE_WINDOW_HEIGHT, &height);
- ALOGE_IF(status != NO_ERROR,
- "Unable to query height (%d)", status);
- int intFormat = 0;
- status = state.surface->query(
- NATIVE_WINDOW_FORMAT, &intFormat);
- ALOGE_IF(status != NO_ERROR,
- "Unable to query format (%d)", status);
- auto format = static_cast<android_pixel_format_t>(
- intFormat);
-
- getBE().mHwc->allocateVirtualDisplay(width, height, &format,
- &hwcId);
- }
-
- // TODO: Plumb requested format back up to consumer
-
- sp<VirtualDisplaySurface> vds =
- new VirtualDisplaySurface(*getBE().mHwc,
- hwcId, state.surface, bqProducer,
- bqConsumer, state.displayName);
-
- dispSurface = vds;
- producer = vds;
- }
- } else {
- ALOGE_IF(state.surface!=NULL,
- "adding a supported display, but rendering "
- "surface is provided (%p), ignoring it",
- state.surface.get());
-
- hwcId = state.type;
- dispSurface = new FramebufferSurface(*getBE().mHwc, hwcId, bqConsumer);
- producer = bqProducer;
- }
-
- const wp<IBinder>& display(curr.keyAt(i));
- if (dispSurface != NULL) {
- sp<DisplayDevice> hw =
- new DisplayDevice(this, state.type, hwcId, state.isSecure, display,
- dispSurface, producer, hasWideColorDisplay);
- hw->setLayerStack(state.layerStack);
- hw->setProjection(state.orientation,
- state.viewport, state.frame);
- hw->setDisplayName(state.displayName);
- mDisplays.add(display, hw);
- if (!state.isVirtualDisplay()) {
- mEventThread->onHotplugReceived(state.type, true);
- }
- }
- }
- }
- }
+ processDisplayChangesLocked();
+ processDisplayHotplugEventsLocked();
}
if (transactionFlags & (eTraversalNeeded|eDisplayTransactionNeeded)) {
@@ -2334,25 +2352,31 @@
for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
sp<const DisplayDevice> hw(mDisplays[dpy]);
if (layer->belongsToDisplay(hw->getLayerStack(), hw->isPrimary())) {
- if (disp == NULL) {
+ if (disp == nullptr) {
disp = std::move(hw);
} else {
- disp = NULL;
+ disp = nullptr;
break;
}
}
}
}
- if (disp == NULL) {
- // NOTE: TEMPORARY FIX ONLY. Real fix should cause layers to
- // redraw after transform hint changes. See bug 8508397.
- // could be null when this layer is using a layerStack
- // that is not visible on any display. Also can occur at
- // screen off/on times.
- disp = getDefaultDisplayDeviceLocked();
+ if (transactionFlags & eDisplayTransactionNeeded) {
+ if (disp == nullptr) {
+ // NOTE: TEMPORARY FIX ONLY. Real fix should cause layers to
+ // redraw after transform hint changes. See bug 8508397.
+
+ // could be null when this layer is using a layerStack
+ // that is not visible on any display. Also can occur at
+ // screen off/on times.
+ disp = getDefaultDisplayDeviceLocked();
+ }
+ layer->updateTransformHint(disp);
}
- layer->updateTransformHint(disp);
+ if (disp != nullptr) {
+ layer->updateTransformHint(disp);
+ }
first = false;
});
@@ -2938,16 +2962,16 @@
for (size_t i=0 ; i<count ; i++) {
const ComposerState& s(state[i]);
// Here we need to check that the interface we're given is indeed
- // one of our own. A malicious client could give us a NULL
+ // one of our own. A malicious client could give us a nullptr
// IInterface, or one of its own or even one of our own but a
// different type. All these situations would cause us to crash.
//
// NOTE: it would be better to use RTTI as we could directly check
// that we have a Client*. however, RTTI is disabled in Android.
- if (s.client != NULL) {
+ if (s.client != nullptr) {
sp<IBinder> binder = IInterface::asBinder(s.client);
- if (binder != NULL) {
- if (binder->queryLocalInterface(ISurfaceComposerClient::descriptor) != NULL) {
+ if (binder != nullptr) {
+ if (binder->queryLocalInterface(ISurfaceComposerClient::descriptor) != nullptr) {
sp<Client> client( static_cast<Client *>(s.client.get()) );
transactionFlags |= setClientStateLocked(client, s.state);
}
@@ -3321,7 +3345,7 @@
// called by a client when it wants to remove a Layer
status_t err = NO_ERROR;
sp<Layer> l(client->getLayerUser(handle));
- if (l != NULL) {
+ if (l != nullptr) {
mInterceptor.saveSurfaceDeletion(l);
err = removeLayer(l);
ALOGE_IF(err<0 && err != NAME_NOT_FOUND,
@@ -3486,7 +3510,7 @@
mDisplay(disp) { mMode = mode; }
virtual bool handler() {
sp<DisplayDevice> hw(mFlinger.getDisplayDevice(mDisplay));
- if (hw == NULL) {
+ if (hw == nullptr) {
ALOGE("Attempt to set power mode = %d for null display %p",
mMode, mDisplay.get());
} else if (hw->getDisplayType() >= DisplayDevice::DISPLAY_VIRTUAL) {
@@ -3888,9 +3912,11 @@
getBE().mRenderEngine->dump(result);
- hw->undefinedRegion.dump(result, "undefinedRegion");
- result.appendFormat(" orientation=%d, isDisplayOn=%d\n",
- hw->getOrientation(), hw->isDisplayOn());
+ if (hw) {
+ hw->undefinedRegion.dump(result, "undefinedRegion");
+ result.appendFormat(" orientation=%d, isDisplayOn=%d\n",
+ hw->getOrientation(), hw->isDisplayOn());
+ }
result.appendFormat(
" last eglSwapBuffers() time: %f us\n"
" last transaction time : %f us\n"
@@ -3975,7 +4001,7 @@
break;
}
}
- if (dpy == NULL) {
+ if (dpy == nullptr) {
ALOGE("getLayerSortedByZForHwcDisplay: invalid hwc display id %d", id);
// Just use the primary display so we have something to return
dpy = getBuiltInDisplay(DisplayDevice::DISPLAY_PRIMARY);
@@ -4242,7 +4268,7 @@
reply->writeBool(hasWideColorDisplay);
return NO_ERROR;
}
- case 1025: { // tracing
+ case 1025: { // Set layer tracing
n = data.readInt32();
if (n) {
ALOGV("LayerTracing enabled");
@@ -4256,6 +4282,10 @@
}
return NO_ERROR;
}
+ case 1026: { // Get layer tracing status
+ reply->writeBool(mTracing.isEnabled());
+ return NO_ERROR;
+ }
}
}
return err;
@@ -4303,7 +4333,7 @@
}
status_t SurfaceFlinger::captureLayers(const sp<IBinder>& layerHandleBinder,
- sp<GraphicBuffer>* outBuffer, const Rect& sourceCrop,
+ sp<GraphicBuffer>* outBuffer, const Rect& sourceCrop,
float frameScale) {
ATRACE_CALL();
@@ -4397,6 +4427,9 @@
int syncFd = -1;
std::optional<status_t> captureResult;
+ const int uid = IPCThreadState::self()->getCallingUid();
+ const bool forSystem = uid == AID_GRAPHICS || uid == AID_SYSTEM;
+
sp<LambdaMessage> message = new LambdaMessage([&]() {
// If there is a refresh pending, bug out early and tell the binder thread to try again
// after the refresh.
@@ -4413,7 +4446,7 @@
{
Mutex::Autolock _l(mStateLock);
result = captureScreenImplLocked(renderArea, traverseLayers, (*outBuffer).get(),
- useIdentityTransform, &fd);
+ useIdentityTransform, forSystem, &fd);
}
{
@@ -4510,6 +4543,7 @@
TraverseLayersFunction traverseLayers,
ANativeWindowBuffer* buffer,
bool useIdentityTransform,
+ bool forSystem,
int* outSyncFd) {
ATRACE_CALL();
@@ -4519,7 +4553,10 @@
secureLayerIsVisible = secureLayerIsVisible || (layer->isVisible() && layer->isSecure());
});
- if (secureLayerIsVisible) {
+ // We allow the system server to take screenshots of secure layers for
+ // use in situations like the Screen-rotation animation and place
+ // the impetus on WindowManager to not persist them.
+ if (secureLayerIsVisible && !forSystem) {
ALOGW("FB is protected: PERMISSION_DENIED");
return PERMISSION_DENIED;
}
@@ -4538,9 +4575,10 @@
// dependent on the context's EGLConfig.
renderScreenImplLocked(renderArea, traverseLayers, true, useIdentityTransform);
- *outSyncFd = getRenderEngine().flush(DEBUG_SCREENSHOTS);
-
if (DEBUG_SCREENSHOTS) {
+ getRenderEngine().finish();
+ *outSyncFd = -1;
+
const auto reqWidth = renderArea.getReqWidth();
const auto reqHeight = renderArea.getReqHeight();
@@ -4548,6 +4586,12 @@
getRenderEngine().readPixels(0, 0, reqWidth, reqHeight, pixels);
checkScreenshot(reqWidth, reqHeight, reqWidth, pixels, traverseLayers);
delete [] pixels;
+ } else {
+ base::unique_fd syncFd = getRenderEngine().flush();
+ if (syncFd < 0) {
+ getRenderEngine().finish();
+ }
+ *outSyncFd = syncFd.release();
}
return NO_ERROR;
@@ -4618,4 +4662,4 @@
#if defined(__gl2_h_)
#error "don't include gl2/gl2.h in this file"
-#endif
\ No newline at end of file
+#endif
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 2477bdc..a18be9b 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -142,14 +142,14 @@
std::unique_ptr<RenderEngine> mRenderEngine;
EGLContext mEGLContext;
EGLDisplay mEGLDisplay;
-
+
FenceTimeline mGlCompositionDoneTimeline;
FenceTimeline mDisplayTimeline;
// protected by mCompositorTimingLock;
mutable std::mutex mCompositorTimingLock;
CompositorTiming mCompositorTiming;
-
+
// Only accessed from the main thread.
struct CompositePresentTime {
nsecs_t composite { -1 };
@@ -417,8 +417,7 @@
void onVsyncReceived(int32_t sequenceId, hwc2_display_t display,
int64_t timestamp) override;
void onHotplugReceived(int32_t sequenceId, hwc2_display_t display,
- HWC2::Connection connection,
- bool primaryDisplay) override;
+ HWC2::Connection connection) override;
void onRefreshReceived(int32_t sequenceId, hwc2_display_t display) override;
/* ------------------------------------------------------------------------
@@ -524,7 +523,7 @@
status_t captureScreenImplLocked(const RenderArea& renderArea,
TraverseLayersFunction traverseLayers,
ANativeWindowBuffer* buffer, bool useIdentityTransform,
- int* outSyncFd);
+ bool forSystem, int* outSyncFd);
void traverseLayersInDisplay(const sp<const DisplayDevice>& display, int32_t minLayerZ,
int32_t maxLayerZ, const LayerVector::Visitor& visitor);
@@ -547,10 +546,6 @@
// called when starting, or restarting after system_server death
void initializeDisplays();
- // Create an IBinder for a builtin display and add it to current state
- void createBuiltinDisplayLocked(DisplayDevice::DisplayType type);
-
-
sp<const DisplayDevice> getDisplayDevice(const wp<IBinder>& dpy) const {
Mutex::Autolock _l(mStateLock);
return getDisplayDeviceLocked(dpy);
@@ -575,8 +570,6 @@
return getDisplayDeviceLocked(mBuiltinDisplays[DisplayDevice::DISPLAY_PRIMARY]);
}
- void createDefaultDisplayDevice();
-
int32_t getDisplayType(const sp<IBinder>& display) {
if (!display.get()) return NAME_NOT_FOUND;
for (int i = 0; i < DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES; ++i) {
@@ -637,6 +630,10 @@
/* ------------------------------------------------------------------------
* Display management
*/
+ DisplayDevice::DisplayType determineDisplayType(hwc2_display_t display,
+ HWC2::Connection connection) const;
+ void processDisplayChangesLocked();
+ void processDisplayHotplugEventsLocked();
/* ------------------------------------------------------------------------
* VSync
@@ -738,6 +735,13 @@
sp<Fence> mPreviousPresentFence = Fence::NO_FENCE;
bool mHadClientComposition = false;
+ struct HotplugEvent {
+ hwc2_display_t display;
+ HWC2::Connection connection = HWC2::Connection::Invalid;
+ };
+ // protected by mStateLock
+ std::vector<HotplugEvent> mPendingHotplugEvents;
+
// this may only be written from the main thread with mStateLock held
// it may be read from other threads with mStateLock held
DefaultKeyedVector< wp<IBinder>, sp<DisplayDevice> > mDisplays;
diff --git a/services/surfaceflinger/Transform.cpp b/services/surfaceflinger/Transform.cpp
index 37925a1..e05ed53 100644
--- a/services/surfaceflinger/Transform.cpp
+++ b/services/surfaceflinger/Transform.cpp
@@ -224,6 +224,27 @@
return r;
}
+FloatRect Transform::transform(const FloatRect& bounds) const
+{
+ vec2 lt(bounds.left, bounds.top);
+ vec2 rt(bounds.right, bounds.top);
+ vec2 lb(bounds.left, bounds.bottom);
+ vec2 rb(bounds.right, bounds.bottom);
+
+ lt = transform(lt);
+ rt = transform(rt);
+ lb = transform(lb);
+ rb = transform(rb);
+
+ FloatRect r;
+ r.left = min(lt[0], rt[0], lb[0], rb[0]);
+ r.top = min(lt[1], rt[1], lb[1], rb[1]);
+ r.right = max(lt[0], rt[0], lb[0], rb[0]);
+ r.bottom = max(lt[1], rt[1], lb[1], rb[1]);
+
+ return r;
+}
+
Region Transform::transform(const Region& reg) const
{
Region out;
diff --git a/services/surfaceflinger/Transform.h b/services/surfaceflinger/Transform.h
index bfc66ec..b11d057 100644
--- a/services/surfaceflinger/Transform.h
+++ b/services/surfaceflinger/Transform.h
@@ -84,6 +84,7 @@
Region transform(const Region& reg) const;
Rect transform(const Rect& bounds,
bool roundOutwards = false) const;
+ FloatRect transform(const FloatRect& bounds) const;
Transform operator * (const Transform& rhs) const;
// assumes the last row is < 0 , 0 , 1 >
vec2 transform(const vec2& v) const;
diff --git a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
index ed806b8..de78c3f 100644
--- a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
+++ b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
@@ -148,7 +148,7 @@
mBGSurfaceControl = mComposerClient->createSurface(
String8("BG Interceptor Test Surface"), displayWidth, displayHeight,
PIXEL_FORMAT_RGBA_8888, 0);
- ASSERT_TRUE(mBGSurfaceControl != NULL);
+ ASSERT_TRUE(mBGSurfaceControl != nullptr);
ASSERT_TRUE(mBGSurfaceControl->isValid());
mBGLayerId = getSurfaceId("BG Interceptor Test Surface");
diff --git a/services/surfaceflinger/tests/Transaction_test.cpp b/services/surfaceflinger/tests/Transaction_test.cpp
index ff81dc9..ac8a2ad 100644
--- a/services/surfaceflinger/tests/Transaction_test.cpp
+++ b/services/surfaceflinger/tests/Transaction_test.cpp
@@ -148,8 +148,8 @@
bool unlock = true) {
ANativeWindow_Buffer outBuffer;
sp<Surface> s = sc->getSurface();
- ASSERT_TRUE(s != NULL);
- ASSERT_EQ(NO_ERROR, s->lock(&outBuffer, NULL));
+ ASSERT_TRUE(s != nullptr);
+ ASSERT_EQ(NO_ERROR, s->lock(&outBuffer, nullptr));
uint8_t* img = reinterpret_cast<uint8_t*>(outBuffer.bits);
for (int y = 0; y < outBuffer.height; y++) {
for (int x = 0; x < outBuffer.width; x++) {
@@ -279,7 +279,7 @@
private:
sp<GraphicBuffer> mOutBuffer;
- uint8_t* mPixels = NULL;
+ uint8_t* mPixels = nullptr;
};
class LayerTransactionTest : public ::testing::Test {
@@ -1483,14 +1483,14 @@
mBGSurfaceControl =
mComposerClient->createSurface(String8("BG Test Surface"), displayWidth,
displayHeight, PIXEL_FORMAT_RGBA_8888, 0);
- ASSERT_TRUE(mBGSurfaceControl != NULL);
+ ASSERT_TRUE(mBGSurfaceControl != nullptr);
ASSERT_TRUE(mBGSurfaceControl->isValid());
fillSurfaceRGBA8(mBGSurfaceControl, 63, 63, 195);
// Foreground surface
mFGSurfaceControl = mComposerClient->createSurface(String8("FG Test Surface"), 64, 64,
PIXEL_FORMAT_RGBA_8888, 0);
- ASSERT_TRUE(mFGSurfaceControl != NULL);
+ ASSERT_TRUE(mFGSurfaceControl != nullptr);
ASSERT_TRUE(mFGSurfaceControl->isValid());
fillSurfaceRGBA8(mFGSurfaceControl, 195, 63, 63);
@@ -1498,7 +1498,7 @@
// Synchronization surface
mSyncSurfaceControl = mComposerClient->createSurface(String8("Sync Test Surface"), 1, 1,
PIXEL_FORMAT_RGBA_8888, 0);
- ASSERT_TRUE(mSyncSurfaceControl != NULL);
+ ASSERT_TRUE(mSyncSurfaceControl != nullptr);
ASSERT_TRUE(mSyncSurfaceControl->isValid());
fillSurfaceRGBA8(mSyncSurfaceControl, 31, 31, 31);
@@ -2018,7 +2018,7 @@
mNewComposerClient->createSurface(String8("New Child Test Surface"), 10, 10,
PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
- ASSERT_TRUE(mChildNewClient != NULL);
+ ASSERT_TRUE(mChildNewClient != nullptr);
ASSERT_TRUE(mChildNewClient->isValid());
fillSurfaceRGBA8(mChildNewClient, 200, 200, 200);
@@ -2210,7 +2210,7 @@
TEST_F(ChildLayerTest, ReparentFromNoParent) {
sp<SurfaceControl> newSurface = mComposerClient->createSurface(String8("New Surface"), 10, 10,
PIXEL_FORMAT_RGBA_8888, 0);
- ASSERT_TRUE(newSurface != NULL);
+ ASSERT_TRUE(newSurface != nullptr);
ASSERT_TRUE(newSurface->isValid());
fillSurfaceRGBA8(newSurface, 63, 195, 63);
diff --git a/services/surfaceflinger/tests/fakehwc/FakeComposerClient.cpp b/services/surfaceflinger/tests/fakehwc/FakeComposerClient.cpp
index d949d48..e16e7ec 100644
--- a/services/surfaceflinger/tests/fakehwc/FakeComposerClient.cpp
+++ b/services/surfaceflinger/tests/fakehwc/FakeComposerClient.cpp
@@ -156,6 +156,10 @@
FakeComposerClient::~FakeComposerClient() {}
+bool FakeComposerClient::hasCapability(hwc2_capability_t /*capability*/) {
+ return false;
+}
+
void FakeComposerClient::removeClient() {
ALOGV("removeClient");
// TODO: Ahooga! Only thing current lifetime management choices in
@@ -177,6 +181,12 @@
}
}
+void FakeComposerClient::refreshDisplay(Display display) {
+ if (mCallbacksOn) {
+ mClient->onRefresh(display);
+ }
+}
+
uint32_t FakeComposerClient::getMaxVirtualDisplayCount() {
ALOGV("getMaxVirtualDisplayCount");
return 1;
diff --git a/services/surfaceflinger/tests/fakehwc/FakeComposerClient.h b/services/surfaceflinger/tests/fakehwc/FakeComposerClient.h
index b944182..cef7f5b 100644
--- a/services/surfaceflinger/tests/fakehwc/FakeComposerClient.h
+++ b/services/surfaceflinger/tests/fakehwc/FakeComposerClient.h
@@ -59,6 +59,8 @@
FakeComposerClient();
virtual ~FakeComposerClient();
+ bool hasCapability(hwc2_capability_t capability) override;
+
void removeClient() override;
void enableCallback(bool enable) override;
uint32_t getMaxVirtualDisplayCount() override;
@@ -140,6 +142,7 @@
Layer getLayer(size_t index) const;
void hotplugDisplay(Display display, IComposerCallback::Connection state);
+ void refreshDisplay(Display display);
private:
LayerImpl& getLayerImpl(Layer handle);
diff --git a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
index 8a97ea4..1873832 100644
--- a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
+++ b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
@@ -22,25 +22,22 @@
#include "FakeComposerService.h"
#include "FakeComposerUtils.h"
+#include <gui/DisplayEventReceiver.h>
#include <gui/ISurfaceComposer.h>
#include <gui/LayerDebugInfo.h>
#include <gui/LayerState.h>
#include <gui/Surface.h>
#include <gui/SurfaceComposerClient.h>
-#include <private/gui/ComposerService.h>
-
-#include <ui/DisplayInfo.h>
-
-#include <android/native_window.h>
-
#include <android/hidl/manager/1.0/IServiceManager.h>
-
-#include <hwbinder/ProcessState.h>
-
+#include <android/looper.h>
+#include <android/native_window.h>
#include <binder/ProcessState.h>
-
+#include <hwbinder/ProcessState.h>
#include <log/log.h>
+#include <private/gui/ComposerService.h>
+#include <ui/DisplayInfo.h>
+#include <utils/Looper.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
@@ -142,13 +139,22 @@
};
protected:
+ static int processDisplayEvents(int fd, int events, void* data);
+
void SetUp() override;
void TearDown() override;
+ void waitForDisplayTransaction();
+ bool waitForHotplugEvent(uint32_t id, bool connected);
+
sp<IComposer> mFakeService;
sp<SurfaceComposerClient> mComposerClient;
MockComposerClient* mMockComposer;
+
+ std::unique_ptr<DisplayEventReceiver> mReceiver;
+ sp<Looper> mLooper;;
+ std::deque<DisplayEventReceiver::Event> mReceivedDisplayEvents;
};
void DisplayTest::SetUp() {
@@ -188,9 +194,16 @@
mComposerClient = new SurfaceComposerClient;
ASSERT_EQ(NO_ERROR, mComposerClient->initCheck());
+
+ mReceiver.reset(new DisplayEventReceiver());
+ mLooper = new Looper(false);
+ mLooper->addFd(mReceiver->getFd(), 0, ALOOPER_EVENT_INPUT, processDisplayEvents, this);
}
void DisplayTest::TearDown() {
+ mLooper = nullptr;
+ mReceiver = nullptr;
+
mComposerClient->dispose();
mComposerClient = nullptr;
@@ -204,6 +217,55 @@
mMockComposer = nullptr;
}
+
+int DisplayTest::processDisplayEvents(int /*fd*/, int /*events*/, void* data) {
+ auto self = static_cast<DisplayTest*>(data);
+
+ ssize_t n;
+ DisplayEventReceiver::Event buffer[1];
+
+ while ((n = self->mReceiver->getEvents(buffer, 1)) > 0) {
+ for (int i=0 ; i<n ; i++) {
+ self->mReceivedDisplayEvents.push_back(buffer[i]);
+ }
+ }
+ ALOGD_IF(n < 0, "Error reading events (%s)\n", strerror(-n));
+ return 1;
+}
+
+void DisplayTest::waitForDisplayTransaction() {
+ // Both a refresh and a vsync event are needed to apply pending display
+ // transactions.
+ mMockComposer->refreshDisplay(EXTERNAL_DISPLAY);
+ mMockComposer->runVSyncAndWait();
+
+ // Extra vsync and wait to avoid a 10% flake due to a race.
+ mMockComposer->runVSyncAndWait();
+}
+
+bool DisplayTest::waitForHotplugEvent(uint32_t id, bool connected) {
+ int waitCount = 20;
+ while (waitCount--) {
+ while (!mReceivedDisplayEvents.empty()) {
+ auto event = mReceivedDisplayEvents.front();
+ mReceivedDisplayEvents.pop_front();
+
+ ALOGV_IF(event.header.type == DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG,
+ "event hotplug: id %d, connected %d\t", event.header.id,
+ event.hotplug.connected);
+
+ if (event.header.type == DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG &&
+ event.header.id == id && event.hotplug.connected == connected) {
+ return true;
+ }
+ }
+
+ mLooper->pollOnce(1);
+ }
+
+ return false;
+}
+
TEST_F(DisplayTest, Hotplug) {
ALOGD("DisplayTest::Hotplug");
@@ -215,7 +277,7 @@
EXPECT_CALL(*mMockComposer, getDisplayAttribute(EXTERNAL_DISPLAY, 1, _, _))
.Times(2 * 3)
.WillRepeatedly(Invoke(mMockComposer, &MockComposerClient::getDisplayAttributeFake));
- // ... and then special handling for dimensions. Specifying this
+ // ... and then special handling for dimensions. Specifying these
// rules later means that gmock will try them first, i.e.,
// ordering of width/height vs. the default implementation for
// other queries is significant.
@@ -229,11 +291,12 @@
.Times(2)
.WillRepeatedly(DoAll(SetArgPointee<3>(200), Return(Error::NONE)));
- // TODO: Width and height queries are not actually called. Display
- // info returns dimensions 0x0 in display info. Why?
-
mMockComposer->hotplugDisplay(EXTERNAL_DISPLAY, IComposerCallback::Connection::CONNECTED);
+ waitForDisplayTransaction();
+
+ EXPECT_TRUE(waitForHotplugEvent(ISurfaceComposer::eDisplayIdHdmi, true));
+
{
sp<android::IBinder> display(
SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdHdmi));
@@ -264,6 +327,11 @@
mMockComposer->hotplugDisplay(EXTERNAL_DISPLAY, IComposerCallback::Connection::CONNECTED);
+ waitForDisplayTransaction();
+
+ EXPECT_TRUE(waitForHotplugEvent(ISurfaceComposer::eDisplayIdHdmi, false));
+ EXPECT_TRUE(waitForHotplugEvent(ISurfaceComposer::eDisplayIdHdmi, true));
+
{
sp<android::IBinder> display(
SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdHdmi));
@@ -290,6 +358,64 @@
mMockComposer->hotplugDisplay(EXTERNAL_DISPLAY, IComposerCallback::Connection::DISCONNECTED);
}
+TEST_F(DisplayTest, HotplugPrimaryDisplay) {
+ ALOGD("DisplayTest::HotplugPrimaryDisplay");
+
+ mMockComposer->hotplugDisplay(PRIMARY_DISPLAY, IComposerCallback::Connection::DISCONNECTED);
+
+ waitForDisplayTransaction();
+
+ EXPECT_TRUE(waitForHotplugEvent(ISurfaceComposer::eDisplayIdMain, false));
+
+ {
+ sp<android::IBinder> display(
+ SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
+ DisplayInfo info;
+ auto result = SurfaceComposerClient::getDisplayInfo(display, &info);
+ EXPECT_NE(NO_ERROR, result);
+ }
+
+ mMockComposer->clearFrames();
+
+ EXPECT_CALL(*mMockComposer, getDisplayType(PRIMARY_DISPLAY, _))
+ .Times(2)
+ .WillRepeatedly(DoAll(SetArgPointee<1>(IComposerClient::DisplayType::PHYSICAL),
+ Return(Error::NONE)));
+ // The attribute queries will get done twice. This is for defaults
+ EXPECT_CALL(*mMockComposer, getDisplayAttribute(PRIMARY_DISPLAY, 1, _, _))
+ .Times(2 * 3)
+ .WillRepeatedly(Invoke(mMockComposer, &MockComposerClient::getDisplayAttributeFake));
+ // ... and then special handling for dimensions. Specifying these
+ // rules later means that gmock will try them first, i.e.,
+ // ordering of width/height vs. the default implementation for
+ // other queries is significant.
+ EXPECT_CALL(*mMockComposer,
+ getDisplayAttribute(PRIMARY_DISPLAY, 1, IComposerClient::Attribute::WIDTH, _))
+ .Times(2)
+ .WillRepeatedly(DoAll(SetArgPointee<3>(400), Return(Error::NONE)));
+
+ EXPECT_CALL(*mMockComposer,
+ getDisplayAttribute(PRIMARY_DISPLAY, 1, IComposerClient::Attribute::HEIGHT, _))
+ .Times(2)
+ .WillRepeatedly(DoAll(SetArgPointee<3>(200), Return(Error::NONE)));
+
+ mMockComposer->hotplugDisplay(PRIMARY_DISPLAY, IComposerCallback::Connection::CONNECTED);
+
+ waitForDisplayTransaction();
+
+ EXPECT_TRUE(waitForHotplugEvent(ISurfaceComposer::eDisplayIdMain, true));
+
+ {
+ sp<android::IBinder> display(
+ SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
+ DisplayInfo info;
+ auto result = SurfaceComposerClient::getDisplayInfo(display, &info);
+ EXPECT_EQ(NO_ERROR, result);
+ ASSERT_EQ(400u, info.w);
+ ASSERT_EQ(200u, info.h);
+ }
+}
+
////////////////////////////////////////////////
class TransactionTest : public ::testing::Test {
diff --git a/services/vr/hardware_composer/impl/vr_hwc.cpp b/services/vr/hardware_composer/impl/vr_hwc.cpp
index fd271d0..d5664d5 100644
--- a/services/vr/hardware_composer/impl/vr_hwc.cpp
+++ b/services/vr/hardware_composer/impl/vr_hwc.cpp
@@ -232,7 +232,7 @@
VrHwc::~VrHwc() {}
-bool VrHwc::hasCapability(Capability /* capability */) const { return false; }
+bool VrHwc::hasCapability(hwc2_capability_t /* capability */) { return false; }
void VrHwc::removeClient() {
std::lock_guard<std::mutex> guard(mutex_);
diff --git a/services/vr/hardware_composer/impl/vr_hwc.h b/services/vr/hardware_composer/impl/vr_hwc.h
index fce9a06..eff721b 100644
--- a/services/vr/hardware_composer/impl/vr_hwc.h
+++ b/services/vr/hardware_composer/impl/vr_hwc.h
@@ -196,8 +196,6 @@
VrHwc();
~VrHwc() override;
- bool hasCapability(Capability capability) const;
-
Error setLayerInfo(Display display, Layer layer, uint32_t type,
uint32_t appId);
Error setClientTargetMetadata(
@@ -207,6 +205,8 @@
const IVrComposerClient::BufferMetadata& metadata);
// ComposerBase
+ bool hasCapability(hwc2_capability_t capability) override;
+
void removeClient() override;
void enableCallback(bool enable) override;
diff --git a/vulkan/libvulkan/driver.cpp b/vulkan/libvulkan/driver.cpp
index ade0bde..26f60fb 100644
--- a/vulkan/libvulkan/driver.cpp
+++ b/vulkan/libvulkan/driver.cpp
@@ -19,9 +19,9 @@
#include <string.h>
#include <sys/prctl.h>
+#include <dlfcn.h>
#include <algorithm>
#include <array>
-#include <dlfcn.h>
#include <new>
#include <log/log.h>
@@ -1047,17 +1047,54 @@
VkInstance instance,
uint32_t* pPhysicalDeviceGroupCount,
VkPhysicalDeviceGroupProperties* pPhysicalDeviceGroupProperties) {
+ VkResult result = VK_SUCCESS;
const auto& data = GetData(instance);
- VkResult result = data.driver.EnumeratePhysicalDeviceGroups(
- instance, pPhysicalDeviceGroupCount, pPhysicalDeviceGroupProperties);
- if ((result == VK_SUCCESS || result == VK_INCOMPLETE) &&
- *pPhysicalDeviceGroupCount && pPhysicalDeviceGroupProperties) {
- for (uint32_t i = 0; i < *pPhysicalDeviceGroupCount; i++) {
- for (uint32_t j = 0;
- j < pPhysicalDeviceGroupProperties->physicalDeviceCount; j++) {
- SetData(pPhysicalDeviceGroupProperties->physicalDevices[j],
+ if (!data.driver.EnumeratePhysicalDeviceGroups) {
+ uint32_t device_count = 0;
+ result = EnumeratePhysicalDevices(instance, &device_count, nullptr);
+ if (result < 0)
+ return result;
+ if (!pPhysicalDeviceGroupProperties) {
+ *pPhysicalDeviceGroupCount = device_count;
+ return result;
+ }
+
+ device_count = std::min(device_count, *pPhysicalDeviceGroupCount);
+ if (!device_count) {
+ *pPhysicalDeviceGroupCount = 0;
+ return result;
+ }
+
+ android::Vector<VkPhysicalDevice> devices;
+ devices.resize(device_count);
+
+ result = EnumeratePhysicalDevices(instance, &device_count,
+ devices.editArray());
+ if (result < 0)
+ return result;
+
+ devices.resize(device_count);
+ *pPhysicalDeviceGroupCount = device_count;
+ for (uint32_t i = 0; i < device_count; ++i) {
+ pPhysicalDeviceGroupProperties[i].physicalDeviceCount = 1;
+ pPhysicalDeviceGroupProperties[i].physicalDevices[0] = devices[i];
+ pPhysicalDeviceGroupProperties[i].subsetAllocation = 0;
+ }
+ } else {
+ result = data.driver.EnumeratePhysicalDeviceGroups(
+ instance, pPhysicalDeviceGroupCount,
+ pPhysicalDeviceGroupProperties);
+ if ((result == VK_SUCCESS || result == VK_INCOMPLETE) &&
+ *pPhysicalDeviceGroupCount && pPhysicalDeviceGroupProperties) {
+ for (uint32_t i = 0; i < *pPhysicalDeviceGroupCount; i++) {
+ for (uint32_t j = 0;
+ j < pPhysicalDeviceGroupProperties[i].physicalDeviceCount;
+ j++) {
+ SetData(
+ pPhysicalDeviceGroupProperties[i].physicalDevices[j],
data);
+ }
}
}
}
diff --git a/vulkan/libvulkan/libvulkan.map.txt b/vulkan/libvulkan/libvulkan.map.txt
index 1745925..d1f6241 100644
--- a/vulkan/libvulkan/libvulkan.map.txt
+++ b/vulkan/libvulkan/libvulkan.map.txt
@@ -1,12 +1,15 @@
LIBVULKAN {
global:
+ vkAcquireNextImage2KHR; # introduced=28
vkAcquireNextImageKHR;
vkAllocateCommandBuffers;
vkAllocateDescriptorSets;
vkAllocateMemory;
vkBeginCommandBuffer;
vkBindBufferMemory;
+ vkBindBufferMemory2; # introduced=28
vkBindImageMemory;
+ vkBindImageMemory2; # introduced=28
vkCmdBeginQuery;
vkCmdBeginRenderPass;
vkCmdBindDescriptorSets;
@@ -23,6 +26,7 @@
vkCmdCopyImageToBuffer;
vkCmdCopyQueryPoolResults;
vkCmdDispatch;
+ vkCmdDispatchBase; # introduced=28
vkCmdDispatchIndirect;
vkCmdDraw;
vkCmdDrawIndexed;
@@ -41,6 +45,7 @@
vkCmdSetBlendConstants;
vkCmdSetDepthBias;
vkCmdSetDepthBounds;
+ vkCmdSetDeviceMask; # introduced=28
vkCmdSetEvent;
vkCmdSetLineWidth;
vkCmdSetScissor;
@@ -58,6 +63,7 @@
vkCreateComputePipelines;
vkCreateDescriptorPool;
vkCreateDescriptorSetLayout;
+ vkCreateDescriptorUpdateTemplate; # introduced=28
vkCreateDevice;
vkCreateEvent;
vkCreateFence;
@@ -71,6 +77,7 @@
vkCreateQueryPool;
vkCreateRenderPass;
vkCreateSampler;
+ vkCreateSamplerYcbcrConversion; # introduced=28
vkCreateSemaphore;
vkCreateShaderModule;
vkCreateSwapchainKHR;
@@ -79,6 +86,7 @@
vkDestroyCommandPool;
vkDestroyDescriptorPool;
vkDestroyDescriptorSetLayout;
+ vkDestroyDescriptorUpdateTemplate; # introduced=28
vkDestroyDevice;
vkDestroyEvent;
vkDestroyFence;
@@ -92,6 +100,7 @@
vkDestroyQueryPool;
vkDestroyRenderPass;
vkDestroySampler;
+ vkDestroySamplerYcbcrConversion; # introduced=28
vkDestroySemaphore;
vkDestroyShaderModule;
vkDestroySurfaceKHR;
@@ -102,28 +111,49 @@
vkEnumerateDeviceLayerProperties;
vkEnumerateInstanceExtensionProperties;
vkEnumerateInstanceLayerProperties;
+ vkEnumerateInstanceVersion; # introduced=28
+ vkEnumeratePhysicalDeviceGroups; # introduced=28
vkEnumeratePhysicalDevices;
vkFlushMappedMemoryRanges;
vkFreeCommandBuffers;
vkFreeDescriptorSets;
vkFreeMemory;
vkGetBufferMemoryRequirements;
+ vkGetBufferMemoryRequirements2; # introduced=28
+ vkGetDescriptorSetLayoutSupport; # introduced=28
+ vkGetDeviceGroupPeerMemoryFeatures; # introduced=28
+ vkGetDeviceGroupPresentCapabilitiesKHR; # introduced=28
+ vkGetDeviceGroupSurfacePresentModesKHR; # introduced=28
vkGetDeviceMemoryCommitment;
vkGetDeviceProcAddr;
vkGetDeviceQueue;
+ vkGetDeviceQueue2; # introduced=28
vkGetEventStatus;
vkGetFenceStatus;
vkGetImageMemoryRequirements;
+ vkGetImageMemoryRequirements2; # introduced=28
vkGetImageSparseMemoryRequirements;
+ vkGetImageSparseMemoryRequirements2; # introduced=28
vkGetImageSubresourceLayout;
vkGetInstanceProcAddr;
+ vkGetPhysicalDeviceExternalBufferProperties; # introduced=28
+ vkGetPhysicalDeviceExternalFenceProperties; # introduced=28
+ vkGetPhysicalDeviceExternalSemaphoreProperties; # introduced=28
vkGetPhysicalDeviceFeatures;
+ vkGetPhysicalDeviceFeatures2; # introduced=28
vkGetPhysicalDeviceFormatProperties;
+ vkGetPhysicalDeviceFormatProperties2; # introduced=28
vkGetPhysicalDeviceImageFormatProperties;
+ vkGetPhysicalDeviceImageFormatProperties2; # introduced=28
vkGetPhysicalDeviceMemoryProperties;
+ vkGetPhysicalDeviceMemoryProperties2; # introduced=28
+ vkGetPhysicalDevicePresentRectanglesKHR; # introduced=28
vkGetPhysicalDeviceProperties;
+ vkGetPhysicalDeviceProperties2; # introduced=28
vkGetPhysicalDeviceQueueFamilyProperties;
+ vkGetPhysicalDeviceQueueFamilyProperties2; # introduced=28
vkGetPhysicalDeviceSparseImageFormatProperties;
+ vkGetPhysicalDeviceSparseImageFormatProperties2; # introduced=28
vkGetPhysicalDeviceSurfaceCapabilitiesKHR;
vkGetPhysicalDeviceSurfaceFormatsKHR;
vkGetPhysicalDeviceSurfacePresentModesKHR;
@@ -145,8 +175,10 @@
vkResetEvent;
vkResetFences;
vkSetEvent;
+ vkTrimCommandPool; # introduced=28
vkUnmapMemory;
vkUpdateDescriptorSets;
+ vkUpdateDescriptorSetWithTemplate; # introduced=28
vkWaitForFences;
local:
*;