Merge "installd: implement installApkVerity"
diff --git a/cmds/dumpstate/Android.bp b/cmds/dumpstate/Android.bp
index 35cff5f..562898d 100644
--- a/cmds/dumpstate/Android.bp
+++ b/cmds/dumpstate/Android.bp
@@ -14,7 +14,7 @@
// limitations under the License.
cc_defaults {
- name: "dumpstate_defaults",
+ name: "dumpstate_cflag_defaults",
cflags: [
"-Wall",
"-Werror",
@@ -26,7 +26,7 @@
cc_library_shared {
name: "libdumpstateutil",
- defaults: ["dumpstate_defaults"],
+ defaults: ["dumpstate_cflag_defaults"],
vendor_available: true,
vndk: {
enabled: true,
@@ -47,7 +47,7 @@
cc_library_shared {
name: "libdumpstateaidl",
- defaults: ["dumpstate_defaults"],
+ defaults: ["dumpstate_cflag_defaults"],
shared_libs: [
"libbinder",
"libutils",
@@ -63,9 +63,9 @@
],
}
-cc_binary {
- name: "dumpstate",
- defaults: ["dumpstate_defaults"],
+cc_defaults {
+ name: "dumpstate_defaults",
+ defaults: ["dumpstate_cflag_defaults"],
shared_libs: [
"android.hardware.dumpstate@1.0",
"libziparchive",
@@ -82,12 +82,22 @@
"libutils",
],
srcs: [
- "DumpstateInternal.cpp",
"DumpstateSectionReporter.cpp",
"DumpstateService.cpp",
- "main.cpp",
"utils.cpp",
+ ],
+ static_libs: [
+ "libdumpsys",
+ "libserviceutils"
+ ],
+}
+
+cc_binary {
+ name: "dumpstate",
+ defaults: ["dumpstate_defaults"],
+ srcs: [
"dumpstate.cpp",
+ "main.cpp",
],
init_rc: ["dumpstate.rc"],
}
@@ -95,24 +105,18 @@
cc_test {
name: "dumpstate_test",
defaults: ["dumpstate_defaults"],
- shared_libs: [
- "libziparchive",
- "libbase",
- "libbinder",
- "libcutils",
- "libdebuggerd_client",
- "libdumpstateaidl",
- "libdumpstateutil",
- "libhidlbase",
- "libhidltransport",
- "liblog",
- "libutils",
- ],
srcs: [
- "DumpstateInternal.cpp",
- "DumpstateService.cpp",
- "utils.cpp",
"tests/dumpstate_test.cpp",
],
static_libs: ["libgmock"],
}
+
+cc_test {
+ name: "dumpstate_smoke_test",
+ defaults: ["dumpstate_defaults"],
+ srcs: [
+ "dumpstate.cpp",
+ "tests/dumpstate_smoke_test.cpp",
+ ],
+ static_libs: ["libgmock"],
+}
\ No newline at end of file
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 1a0e456..ef5064c 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -25,6 +25,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <sys/poll.h>
#include <sys/prctl.h>
#include <sys/resource.h>
#include <sys/stat.h>
@@ -46,22 +47,39 @@
#include <android/hidl/manager/1.0/IServiceManager.h>
#include <cutils/native_handle.h>
#include <cutils/properties.h>
+#include <dumpsys.h>
#include <hidl/ServiceManagement.h>
#include <openssl/sha.h>
#include <private/android_filesystem_config.h>
#include <private/android_logger.h>
-
+#include <serviceutils/PriorityDumper.h>
#include "DumpstateInternal.h"
+#include "DumpstateSectionReporter.h"
#include "DumpstateService.h"
#include "dumpstate.h"
using ::android::hardware::dumpstate::V1_0::IDumpstateDevice;
+using ::std::literals::chrono_literals::operator""ms;
+using ::std::literals::chrono_literals::operator""s;
// TODO: remove once moved to namespace
+using android::defaultServiceManager;
+using android::Dumpsys;
+using android::INVALID_OPERATION;
+using android::IServiceManager;
+using android::OK;
+using android::sp;
+using android::status_t;
+using android::String16;
+using android::String8;
+using android::TIMED_OUT;
+using android::UNKNOWN_ERROR;
+using android::Vector;
using android::os::dumpstate::CommandOptions;
using android::os::dumpstate::DumpFileToFd;
-using android::os::dumpstate::PropertiesHelper;
+using android::os::dumpstate::DumpstateSectionReporter;
using android::os::dumpstate::GetPidByName;
+using android::os::dumpstate::PropertiesHelper;
/* read before root is shed */
static char cmdline_buf[16384] = "(unknown)";
@@ -127,6 +145,8 @@
// Must be hardcoded because dumpstate HAL implementation need SELinux access to it
static const std::string kDumpstateBoardPath = "/bugreports/";
+static const std::string kProtoPath = "proto/";
+static const std::string kProtoExt = ".proto";
static const std::string kDumpstateBoardFiles[] = {
"dumpstate_board.txt",
"dumpstate_board.bin"
@@ -221,7 +241,7 @@
}
if (ds.IsZipping() && add_to_zip) {
- if (!ds.AddZipEntryFromFd(ZIP_ROOT_DIR + name, fd)) {
+ if (ds.AddZipEntryFromFd(ZIP_ROOT_DIR + name, fd, /* timeout = */ 0ms) != OK) {
MYLOGE("Unable to add %s to zip file, addZipEntryFromFd failed\n", name.c_str());
}
} else {
@@ -657,12 +677,18 @@
return 0;
}
-/* timeout in ms */
-static unsigned long logcat_timeout(const char *name) {
- log_id_t id = android_name_to_log_id(name);
- unsigned long property_size = __android_logger_get_buffer_size(id);
- /* Engineering margin is ten-fold our guess */
- return 10 * (property_size + worst_write_perf) / worst_write_perf;
+static const long MINIMUM_LOGCAT_TIMEOUT_MS = 50000;
+
+/* timeout in ms to read a list of buffers */
+static unsigned long logcat_timeout(const std::vector<std::string>& buffers) {
+ unsigned long timeout_ms = 0;
+ for (const auto& buffer : buffers) {
+ log_id_t id = android_name_to_log_id(buffer.c_str());
+ unsigned long property_size = __android_logger_get_buffer_size(id);
+ /* Engineering margin is ten-fold our guess */
+ timeout_ms += 10 * (property_size + worst_write_perf) / worst_write_perf;
+ }
+ return timeout_ms > MINIMUM_LOGCAT_TIMEOUT_MS ? timeout_ms : MINIMUM_LOGCAT_TIMEOUT_MS;
}
void Dumpstate::PrintHeader() const {
@@ -708,11 +734,12 @@
".shb", ".sys", ".vb", ".vbe", ".vbs", ".vxd", ".wsc", ".wsf", ".wsh"
};
-bool Dumpstate::AddZipEntryFromFd(const std::string& entry_name, int fd) {
+status_t Dumpstate::AddZipEntryFromFd(const std::string& entry_name, int fd,
+ std::chrono::milliseconds timeout = 0ms) {
if (!IsZipping()) {
MYLOGD("Not adding zip entry %s from fd because it's not a zipped bugreport\n",
entry_name.c_str());
- return false;
+ return INVALID_OPERATION;
}
std::string valid_name = entry_name;
@@ -734,32 +761,55 @@
if (err != 0) {
MYLOGE("zip_writer_->StartEntryWithTime(%s): %s\n", valid_name.c_str(),
ZipWriter::ErrorCodeString(err));
- return false;
+ return UNKNOWN_ERROR;
}
+ auto start = std::chrono::steady_clock::now();
+ auto end = start + timeout;
+ struct pollfd pfd = {fd, POLLIN};
std::vector<uint8_t> buffer(65536);
while (1) {
+ if (timeout.count() > 0) {
+ // lambda to recalculate the timeout.
+ auto time_left_ms = [end]() {
+ auto now = std::chrono::steady_clock::now();
+ auto diff = std::chrono::duration_cast<std::chrono::milliseconds>(end - now);
+ return std::max(diff.count(), 0LL);
+ };
+
+ int rc = TEMP_FAILURE_RETRY(poll(&pfd, 1, time_left_ms()));
+ if (rc < 0) {
+ MYLOGE("Error in poll while adding from fd to zip entry %s:%s", entry_name.c_str(),
+ strerror(errno));
+ return -errno;
+ } else if (rc == 0) {
+ MYLOGE("Timed out adding from fd to zip entry %s:%s Timeout:%lldms",
+ entry_name.c_str(), strerror(errno), timeout.count());
+ return TIMED_OUT;
+ }
+ }
+
ssize_t bytes_read = TEMP_FAILURE_RETRY(read(fd, buffer.data(), buffer.size()));
if (bytes_read == 0) {
break;
} else if (bytes_read == -1) {
MYLOGE("read(%s): %s\n", entry_name.c_str(), strerror(errno));
- return false;
+ return -errno;
}
err = zip_writer_->WriteBytes(buffer.data(), bytes_read);
if (err) {
MYLOGE("zip_writer_->WriteBytes(): %s\n", ZipWriter::ErrorCodeString(err));
- return false;
+ return UNKNOWN_ERROR;
}
}
err = zip_writer_->FinishEntry();
if (err != 0) {
MYLOGE("zip_writer_->FinishEntry(): %s\n", ZipWriter::ErrorCodeString(err));
- return false;
+ return UNKNOWN_ERROR;
}
- return true;
+ return OK;
}
bool Dumpstate::AddZipEntry(const std::string& entry_name, const std::string& entry_path) {
@@ -770,12 +820,12 @@
return false;
}
- return AddZipEntryFromFd(entry_name, fd.get());
+ return (AddZipEntryFromFd(entry_name, fd.get()) == OK);
}
/* adds a file to the existing zipped bugreport */
static int _add_file_from_fd(const char* title __attribute__((unused)), const char* path, int fd) {
- return ds.AddZipEntryFromFd(ZIP_ROOT_DIR + path, fd) ? 0 : 1;
+ return (ds.AddZipEntryFromFd(ZIP_ROOT_DIR + path, fd) == OK) ? 0 : 1;
}
void Dumpstate::AddDir(const std::string& dir, bool recursive) {
@@ -831,13 +881,8 @@
}
}
-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;
- }
+ unsigned long timeout_ms = logcat_timeout({"kernel"});
RunCommand(
"KERNEL LOG",
{"logcat", "-b", "kernel", "-v", "threadtime", "-v", "printable", "-v", "uid", "-d", "*:v"},
@@ -848,25 +893,21 @@
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 < MINIMUM_LOGCAT_TIMEOUT_MS) {
- timeout_ms = MINIMUM_LOGCAT_TIMEOUT_MS;
- }
+ timeout_ms = logcat_timeout({"main", "system", "crash"});
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 < MINIMUM_LOGCAT_TIMEOUT_MS) {
- timeout_ms = MINIMUM_LOGCAT_TIMEOUT_MS;
- }
+ timeout_ms = logcat_timeout({"events"});
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 < MINIMUM_LOGCAT_TIMEOUT_MS) {
- timeout_ms = MINIMUM_LOGCAT_TIMEOUT_MS;
- }
+ timeout_ms = logcat_timeout({"stats"});
+ RunCommand(
+ "STATS LOG",
+ {"logcat", "-b", "stats", "-v", "threadtime", "-v", "printable", "-v", "uid", "-d", "*:v"},
+ CommandOptions::WithTimeoutInMs(timeout_ms).Build());
+ timeout_ms = logcat_timeout({"radio"});
RunCommand(
"RADIO LOG",
{"logcat", "-b", "radio", "-v", "threadtime", "-v", "printable", "-v", "uid", "-d", "*:v"},
@@ -1069,11 +1110,97 @@
RunCommand("IP RULES v6", {"ip", "-6", "rule", "show"});
}
+void RunDumpsysText(const std::string& title, int priority, std::chrono::milliseconds timeout,
+ std::chrono::milliseconds service_timeout) {
+ sp<android::IServiceManager> sm = defaultServiceManager();
+ Dumpsys dumpsys(sm.get());
+ DurationReporter duration_reporter(title);
+ Vector<String16> args;
+ Dumpsys::setServiceArgs(args, /* asProto = */ false, priority);
+
+ if (!title.empty()) {
+ dprintf(STDOUT_FILENO, "------ %s (%s) ------\n", title.c_str(), "/system/bin/dumpsys");
+ fsync(STDOUT_FILENO);
+ }
+
+ auto start = std::chrono::steady_clock::now();
+ Vector<String16> services = dumpsys.listServices(priority, /* supports_proto = */ false);
+ for (const String16& service : services) {
+ std::string path(title);
+ path.append(" - ").append(String8(service).c_str());
+ DumpstateSectionReporter section_reporter(path, ds.listener_, ds.report_section_);
+ size_t bytes_written = 0;
+ status_t status = dumpsys.startDumpThread(service, args);
+ if (status == OK) {
+ dumpsys.writeDumpHeader(STDOUT_FILENO, service, priority);
+ std::chrono::duration<double> elapsed_seconds;
+ status = dumpsys.writeDump(STDOUT_FILENO, service, service_timeout,
+ /* as_proto = */ false, elapsed_seconds, bytes_written);
+ section_reporter.setSize(bytes_written);
+ dumpsys.writeDumpFooter(STDOUT_FILENO, service, elapsed_seconds);
+ bool dump_complete = (status == OK);
+ dumpsys.stopDumpThread(dump_complete);
+ }
+ section_reporter.setStatus(status);
+
+ auto elapsed_duration = std::chrono::duration_cast<std::chrono::milliseconds>(
+ std::chrono::steady_clock::now() - start);
+ if (elapsed_duration > timeout) {
+ MYLOGE("*** command '%s' timed out after %llums\n", title.c_str(),
+ elapsed_duration.count());
+ break;
+ }
+ }
+}
+
+void RunDumpsysProto(const std::string& title, int priority, std::chrono::milliseconds timeout,
+ std::chrono::milliseconds service_timeout) {
+ sp<android::IServiceManager> sm = defaultServiceManager();
+ Dumpsys dumpsys(sm.get());
+ Vector<String16> args;
+ Dumpsys::setServiceArgs(args, /* asProto = */ true, priority);
+ DurationReporter duration_reporter(title);
+
+ auto start = std::chrono::steady_clock::now();
+ Vector<String16> services = dumpsys.listServices(priority, /* supports_proto = */ true);
+ for (const String16& service : services) {
+ std::string path(kProtoPath);
+ path.append(String8(service).c_str());
+ if (priority == IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL) {
+ path.append("_CRITICAL");
+ } else if (priority == IServiceManager::DUMP_FLAG_PRIORITY_HIGH) {
+ path.append("_HIGH");
+ }
+ path.append(kProtoExt);
+ DumpstateSectionReporter section_reporter(path, ds.listener_, ds.report_section_);
+ status_t status = dumpsys.startDumpThread(service, args);
+ if (status == OK) {
+ status = ds.AddZipEntryFromFd(path, dumpsys.getDumpFd(), service_timeout);
+ bool dumpTerminated = (status == OK);
+ dumpsys.stopDumpThread(dumpTerminated);
+ }
+ ZipWriter::FileEntry file_entry;
+ ds.zip_writer_->GetLastEntry(&file_entry);
+ section_reporter.setSize(file_entry.compressed_size);
+ section_reporter.setStatus(status);
+
+ auto elapsed_duration = std::chrono::duration_cast<std::chrono::milliseconds>(
+ std::chrono::steady_clock::now() - start);
+ if (elapsed_duration > timeout) {
+ MYLOGE("*** command '%s' timed out after %llums\n", title.c_str(),
+ elapsed_duration.count());
+ break;
+ }
+ }
+}
+
// Runs dumpsys on services that must dump first and and will take less than 100ms to dump.
static void RunDumpsysCritical() {
if (ds.CurrentVersionSupportsPriorityDumps()) {
- RunDumpsys("DUMPSYS CRITICAL", {"--priority", "CRITICAL"},
- CommandOptions::WithTimeout(5).DropRoot().Build());
+ RunDumpsysText("DUMPSYS CRITICAL", IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL,
+ /* timeout= */ 5s, /* service_timeout= */ 500ms);
+ RunDumpsysProto("DUMPSYS CRITICAL PROTO", IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL,
+ /* timeout= */ 5s, /* service_timeout= */ 500ms);
} else {
RunDumpsys("DUMPSYS MEMINFO", {"meminfo", "-a"},
CommandOptions::WithTimeout(90).DropRoot().Build());
@@ -1085,8 +1212,13 @@
// Runs dumpsys on services that must dump first but can take up to 250ms to dump.
static void RunDumpsysHigh() {
if (ds.CurrentVersionSupportsPriorityDumps()) {
- RunDumpsys("DUMPSYS HIGH", {"--priority", "HIGH"},
- CommandOptions::WithTimeout(20).DropRoot().Build());
+ // TODO meminfo takes ~10s, connectivity takes ~5sec to dump. They are both
+ // high priority. Reduce timeout once they are able to dump in a shorter time or
+ // moved to a parallel task.
+ RunDumpsysText("DUMPSYS HIGH", IServiceManager::DUMP_FLAG_PRIORITY_HIGH,
+ /* timeout= */ 90s, /* service_timeout= */ 30s);
+ RunDumpsysProto("DUMPSYS HIGH PROTO", IServiceManager::DUMP_FLAG_PRIORITY_HIGH,
+ /* timeout= */ 5s, /* service_timeout= */ 1s);
} else {
RunDumpsys("NETWORK DIAGNOSTICS", {"connectivity", "--diag"});
}
@@ -1095,8 +1227,10 @@
// Runs dumpsys on services that must dump but can take up to 10s to dump.
static void RunDumpsysNormal() {
if (ds.CurrentVersionSupportsPriorityDumps()) {
- RunDumpsys("DUMPSYS NORMAL", {"--priority", "NORMAL"},
- CommandOptions::WithTimeout(90).DropRoot().Build());
+ RunDumpsysText("DUMPSYS", IServiceManager::DUMP_FLAG_PRIORITY_NORMAL,
+ /* timeout= */ 90s, /* service_timeout= */ 10s);
+ RunDumpsysProto("DUMPSYS PROTO", IServiceManager::DUMP_FLAG_PRIORITY_NORMAL,
+ /* timeout= */ 90s, /* service_timeout= */ 10s);
} else {
RunDumpsys("DUMPSYS", {"--skip", "meminfo", "cpuinfo"},
CommandOptions::WithTimeout(90).Build(), SEC_TO_MSEC(10));
diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h
index 843c545..2554b63 100644
--- a/cmds/dumpstate/dumpstate.h
+++ b/cmds/dumpstate/dumpstate.h
@@ -226,8 +226,14 @@
/*
* Adds a new entry to the existing zip file.
+ *
+ * |entry_name| destination path of the new entry.
+ * |fd| file descriptor to read from.
+ * |timeout| timeout to terminate the read if not completed. Set
+ * value of 0s (default) to disable timeout.
*/
- bool AddZipEntryFromFd(const std::string& entry_name, int fd);
+ android::status_t AddZipEntryFromFd(const std::string& entry_name, int fd,
+ std::chrono::milliseconds timeout);
/*
* Adds a text entry entry to the existing zip file.
diff --git a/cmds/dumpstate/tests/dumpstate_smoke_test.cpp b/cmds/dumpstate/tests/dumpstate_smoke_test.cpp
new file mode 100644
index 0000000..61a5ef5
--- /dev/null
+++ b/cmds/dumpstate/tests/dumpstate_smoke_test.cpp
@@ -0,0 +1,286 @@
+/*
+ * 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 <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include <fcntl.h>
+#include <libgen.h>
+
+#include <android-base/file.h>
+#include <cutils/properties.h>
+#include <ziparchive/zip_archive.h>
+
+#include "dumpstate.h"
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+
+namespace android {
+namespace os {
+namespace dumpstate {
+
+using ::testing::Test;
+using ::std::literals::chrono_literals::operator""s;
+
+struct SectionInfo {
+ std::string name;
+ status_t status;
+ int32_t size_bytes;
+ int32_t duration_ms;
+};
+
+/**
+ * Listens to bugreport progress and updates the user by writing the progress to STDOUT. All the
+ * section details generated by dumpstate are added to a vector to be used by Tests later.
+ */
+class DumpstateListener : public IDumpstateListener {
+ public:
+ int outFd_, max_progress_;
+ std::shared_ptr<std::vector<SectionInfo>> sections_;
+ DumpstateListener(int fd, std::shared_ptr<std::vector<SectionInfo>> sections)
+ : outFd_(fd), max_progress_(5000), sections_(sections) {
+ }
+ binder::Status onProgressUpdated(int32_t progress) override {
+ dprintf(outFd_, "\rIn progress %d/%d", progress, max_progress_);
+ return binder::Status::ok();
+ }
+ binder::Status onMaxProgressUpdated(int32_t max_progress) override {
+ max_progress_ = max_progress;
+ return binder::Status::ok();
+ }
+ binder::Status onSectionComplete(const ::std::string& name, int32_t status, int32_t size_bytes,
+ int32_t duration_ms) override {
+ sections_->push_back({name, status, size_bytes, duration_ms});
+ return binder::Status::ok();
+ }
+ IBinder* onAsBinder() override {
+ return nullptr;
+ }
+};
+
+/**
+ * Generates bug report and provide access to the bug report file and other info for other tests.
+ * Since bug report generation is slow, the bugreport is only generated once.
+ */
+class ZippedBugreportGenerationTest : public Test {
+ public:
+ static std::shared_ptr<std::vector<SectionInfo>> sections;
+ static Dumpstate& ds;
+ static std::chrono::milliseconds duration;
+ static void SetUpTestCase() {
+ property_set("dumpstate.options", "bugreportplus");
+ // clang-format off
+ char* argv[] = {
+ (char*)"dumpstate",
+ (char*)"-d",
+ (char*)"-z",
+ (char*)"-B",
+ (char*)"-o",
+ (char*)dirname(android::base::GetExecutablePath().c_str())
+ };
+ // clang-format on
+ sp<DumpstateListener> listener(new DumpstateListener(dup(fileno(stdout)), sections));
+ ds.listener_ = listener;
+ ds.listener_name_ = "Smokey";
+ ds.report_section_ = true;
+ auto start = std::chrono::steady_clock::now();
+ run_main(ARRAY_SIZE(argv), argv);
+ auto end = std::chrono::steady_clock::now();
+ duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
+ }
+
+ static const char* getZipFilePath() {
+ return ds.GetPath(".zip").c_str();
+ }
+};
+std::shared_ptr<std::vector<SectionInfo>> ZippedBugreportGenerationTest::sections =
+ std::make_shared<std::vector<SectionInfo>>();
+Dumpstate& ZippedBugreportGenerationTest::ds = Dumpstate::GetInstance();
+std::chrono::milliseconds ZippedBugreportGenerationTest::duration = 0s;
+
+TEST_F(ZippedBugreportGenerationTest, IsGeneratedWithoutErrors) {
+ EXPECT_EQ(access(getZipFilePath(), F_OK), 0);
+}
+
+TEST_F(ZippedBugreportGenerationTest, Is3MBto30MBinSize) {
+ struct stat st;
+ EXPECT_EQ(stat(getZipFilePath(), &st), 0);
+ EXPECT_GE(st.st_size, 3000000 /* 3MB */);
+ EXPECT_LE(st.st_size, 30000000 /* 30MB */);
+}
+
+TEST_F(ZippedBugreportGenerationTest, TakesBetween30And150Seconds) {
+ EXPECT_GE(duration, 30s) << "Expected completion in more than 30s. Actual time "
+ << duration.count() << " s.";
+ EXPECT_LE(duration, 150s) << "Expected completion in less than 150s. Actual time "
+ << duration.count() << " s.";
+}
+
+/**
+ * Run tests on contents of zipped bug report.
+ */
+class ZippedBugReportContentsTest : public Test {
+ public:
+ ZipArchiveHandle handle;
+ void SetUp() {
+ ASSERT_EQ(OpenArchive(ZippedBugreportGenerationTest::getZipFilePath(), &handle), 0);
+ }
+ void TearDown() {
+ CloseArchive(handle);
+ }
+
+ void FileExists(const char* filename, uint32_t minsize, uint32_t maxsize) {
+ ZipEntry entry;
+ EXPECT_EQ(FindEntry(handle, ZipString(filename), &entry), 0);
+ EXPECT_GT(entry.uncompressed_length, minsize);
+ EXPECT_LT(entry.uncompressed_length, maxsize);
+ }
+};
+
+TEST_F(ZippedBugReportContentsTest, ContainsMainEntry) {
+ ZipEntry mainEntryLoc;
+ // contains main entry name file
+ EXPECT_EQ(FindEntry(handle, ZipString("main_entry.txt"), &mainEntryLoc), 0);
+
+ char* buf = new char[mainEntryLoc.uncompressed_length];
+ ExtractToMemory(handle, &mainEntryLoc, (uint8_t*)buf, mainEntryLoc.uncompressed_length);
+ delete[] buf;
+
+ // contains main entry file
+ FileExists(buf, 1000000U, 50000000U);
+}
+
+TEST_F(ZippedBugReportContentsTest, ContainsVersion) {
+ ZipEntry entry;
+ // contains main entry name file
+ EXPECT_EQ(FindEntry(handle, ZipString("version.txt"), &entry), 0);
+
+ char* buf = new char[entry.uncompressed_length + 1];
+ ExtractToMemory(handle, &entry, (uint8_t*)buf, entry.uncompressed_length);
+ buf[entry.uncompressed_length] = 0;
+ EXPECT_STREQ(buf, ZippedBugreportGenerationTest::ds.version_.c_str());
+ delete[] buf;
+}
+
+TEST_F(ZippedBugReportContentsTest, ContainsBoardSpecificFiles) {
+ FileExists("dumpstate_board.bin", 1000000U, 80000000U);
+ FileExists("dumpstate_board.txt", 100000U, 1000000U);
+}
+
+// Spot check on some files pulled from the file system
+TEST_F(ZippedBugReportContentsTest, ContainsSomeFileSystemFiles) {
+ // FS/proc/*/mountinfo size > 0
+ FileExists("FS/proc/1/mountinfo", 0U, 100000U);
+
+ // FS/data/misc/profiles/cur/0/*/primary.prof size > 0
+ FileExists("FS/data/misc/profiles/cur/0/com.android.phone/primary.prof", 0U, 100000U);
+}
+
+/**
+ * Runs tests on section data generated by dumpstate and captured by DumpstateListener.
+ */
+class BugreportSectionTest : public Test {
+ public:
+ int numMatches(const std::string& substring) {
+ int matches = 0;
+ for (auto const& section : *ZippedBugreportGenerationTest::sections) {
+ if (section.name.find(substring) != std::string::npos) {
+ matches++;
+ }
+ }
+ return matches;
+ }
+ void SectionExists(const std::string& sectionName, int minsize) {
+ for (auto const& section : *ZippedBugreportGenerationTest::sections) {
+ if (sectionName == section.name) {
+ EXPECT_GE(section.size_bytes, minsize);
+ return;
+ }
+ }
+ FAIL() << sectionName << " not found.";
+ }
+};
+
+// Test all sections are generated without timeouts or errors
+TEST_F(BugreportSectionTest, GeneratedWithoutErrors) {
+ for (auto const& section : *ZippedBugreportGenerationTest::sections) {
+ EXPECT_EQ(section.status, 0) << section.name << " failed with status " << section.status;
+ }
+}
+
+TEST_F(BugreportSectionTest, Atleast3CriticalDumpsysSectionsGenerated) {
+ int numSections = numMatches("DUMPSYS CRITICAL");
+ EXPECT_GE(numSections, 3);
+}
+
+TEST_F(BugreportSectionTest, Atleast2HighDumpsysSectionsGenerated) {
+ int numSections = numMatches("DUMPSYS HIGH");
+ EXPECT_GE(numSections, 2);
+}
+
+TEST_F(BugreportSectionTest, Atleast50NormalDumpsysSectionsGenerated) {
+ int allSections = numMatches("DUMPSYS");
+ int criticalSections = numMatches("DUMPSYS CRITICAL");
+ int highSections = numMatches("DUMPSYS HIGH");
+ int normalSections = allSections - criticalSections - highSections;
+
+ EXPECT_GE(normalSections, 50) << "Total sections less than 50 (Critical:" << criticalSections
+ << "High:" << highSections << "Normal:" << normalSections << ")";
+}
+
+TEST_F(BugreportSectionTest, Atleast1ProtoDumpsysSectionGenerated) {
+ int numSections = numMatches("proto/");
+ EXPECT_GE(numSections, 1);
+}
+
+// Test if some critical sections are being generated.
+TEST_F(BugreportSectionTest, CriticalSurfaceFlingerSectionGenerated) {
+ SectionExists("DUMPSYS CRITICAL - SurfaceFlinger", /* bytes= */ 10000);
+}
+
+TEST_F(BugreportSectionTest, ActivitySectionsGenerated) {
+ SectionExists("DUMPSYS CRITICAL - activity", /* bytes= */ 5000);
+ SectionExists("DUMPSYS - activity", /* bytes= */ 10000);
+}
+
+TEST_F(BugreportSectionTest, CpuinfoSectionGenerated) {
+ SectionExists("DUMPSYS CRITICAL - cpuinfo", /* bytes= */ 1000);
+}
+
+TEST_F(BugreportSectionTest, WindowSectionGenerated) {
+ SectionExists("DUMPSYS CRITICAL - window", /* bytes= */ 20000);
+}
+
+TEST_F(BugreportSectionTest, ConnectivitySectionsGenerated) {
+ SectionExists("DUMPSYS HIGH - connectivity", /* bytes= */ 5000);
+ SectionExists("DUMPSYS - connectivity", /* bytes= */ 5000);
+}
+
+TEST_F(BugreportSectionTest, MeminfoSectionGenerated) {
+ SectionExists("DUMPSYS HIGH - meminfo", /* bytes= */ 100000);
+}
+
+TEST_F(BugreportSectionTest, BatteryStatsSectionGenerated) {
+ SectionExists("DUMPSYS - batterystats", /* bytes= */ 1000);
+}
+
+TEST_F(BugreportSectionTest, WifiSectionGenerated) {
+ SectionExists("DUMPSYS - wifi", /* bytes= */ 100000);
+}
+
+} // namespace dumpstate
+} // namespace os
+} // namespace android
diff --git a/cmds/dumpsys/dumpsys.cpp b/cmds/dumpsys/dumpsys.cpp
index ae0cc01..ca7d95e 100644
--- a/cmds/dumpsys/dumpsys.cpp
+++ b/cmds/dumpsys/dumpsys.cpp
@@ -283,7 +283,7 @@
return services;
}
-void Dumpsys::setServiceArgs(Vector<String16>& args, bool asProto, int priorityFlags) const {
+void Dumpsys::setServiceArgs(Vector<String16>& args, bool asProto, int priorityFlags) {
if ((priorityFlags == IServiceManager::DUMP_FLAG_PRIORITY_ALL) ||
(priorityFlags == IServiceManager::DUMP_FLAG_PRIORITY_NORMAL)) {
args.add(String16("-a"));
diff --git a/cmds/dumpsys/dumpsys.h b/cmds/dumpsys/dumpsys.h
index 1d78aa4..84f3b02 100644
--- a/cmds/dumpsys/dumpsys.h
+++ b/cmds/dumpsys/dumpsys.h
@@ -49,7 +49,7 @@
* @param priorityFlags indicates priority of dump by passing additional priority args
* to the service
*/
- void setServiceArgs(Vector<String16>& args, bool asProto, int priorityFlags) const;
+ static void setServiceArgs(Vector<String16>& args, bool asProto, int priorityFlags);
/**
* Starts a thread to connect to a service and get its dump output. The thread redirects
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index d51aec9..1627756 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -1952,27 +1952,6 @@
return ok();
}
-void mkinnerdirs(char* path, int basepos, mode_t mode, int uid, int gid,
- struct stat* statbuf)
-{
- while (path[basepos] != 0) {
- if (path[basepos] == '/') {
- path[basepos] = 0;
- if (lstat(path, statbuf) < 0) {
- ALOGV("Making directory: %s\n", path);
- if (mkdir(path, mode) == 0) {
- chown(path, uid, gid);
- } else {
- ALOGW("Unable to make directory %s: %s\n", path, strerror(errno));
- }
- }
- path[basepos] = '/';
- basepos++;
- }
- basepos++;
- }
-}
-
binder::Status InstalldNativeService::linkNativeLibraryDirectory(
const std::unique_ptr<std::string>& uuid, const std::string& packageName,
const std::string& nativeLibPath32, int32_t userId) {
diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp
index 80e18d3..0f635e0 100644
--- a/cmds/installd/dexopt.cpp
+++ b/cmds/installd/dexopt.cpp
@@ -217,7 +217,7 @@
const char* input_file_name, const char* output_file_name, int swap_fd,
const char* instruction_set, const char* compiler_filter,
bool debuggable, bool post_bootcomplete, bool background_job_compile, int profile_fd,
- const char* class_loader_context, int target_sdk_version) {
+ const char* class_loader_context, int target_sdk_version, bool disable_hidden_api_checks) {
static const unsigned int MAX_INSTRUCTION_SET_LEN = 7;
if (strlen(instruction_set) >= MAX_INSTRUCTION_SET_LEN) {
@@ -443,7 +443,8 @@
+ (have_dex2oat_large_app_threshold ? 1 : 0)
+ (disable_cdex ? 1 : 0)
+ (generate_minidebug_info ? 1 : 0)
- + (target_sdk_version != 0 ? 2 : 0)];
+ + (target_sdk_version != 0 ? 2 : 0)
+ + (disable_hidden_api_checks ? 2 : 0)];
int i = 0;
argv[i++] = dex2oat_bin;
argv[i++] = zip_fd_arg;
@@ -517,6 +518,10 @@
argv[i++] = RUNTIME_ARG;
argv[i++] = target_sdk_version_arg;
}
+ if (disable_hidden_api_checks) {
+ argv[i++] = RUNTIME_ARG;
+ argv[i++] = "-Xno-hidden-api-checks";
+ }
// Do not add after dex2oat_flags, they should override others for debugging.
argv[i] = NULL;
@@ -1801,6 +1806,7 @@
bool profile_guided = (dexopt_flags & DEXOPT_PROFILE_GUIDED) != 0;
bool is_secondary_dex = (dexopt_flags & DEXOPT_SECONDARY_DEX) != 0;
bool background_job_compile = (dexopt_flags & DEXOPT_IDLE_BACKGROUND_JOB) != 0;
+ bool disable_hidden_api_checks = (dexopt_flags & DEXOPT_DISABLE_HIDDEN_API_CHECKS) != 0;
// Check if we're dealing with a secondary dex file and if we need to compile it.
std::string oat_dir_str;
@@ -1897,7 +1903,8 @@
background_job_compile,
reference_profile_fd.get(),
class_loader_context,
- target_sdk_version);
+ target_sdk_version,
+ disable_hidden_api_checks);
_exit(68); /* only get here on exec failure */
} else {
int res = wait_child(pid);
diff --git a/cmds/installd/installd_constants.h b/cmds/installd/installd_constants.h
index b49057d..9b6714d 100644
--- a/cmds/installd/installd_constants.h
+++ b/cmds/installd/installd_constants.h
@@ -52,6 +52,7 @@
// Tells the compiler that it is invoked from the background service. This
// controls whether extra debugging flags can be used (taking more compile time.)
constexpr int DEXOPT_IDLE_BACKGROUND_JOB = 1 << 9;
+constexpr int DEXOPT_DISABLE_HIDDEN_API_CHECKS = 1 << 10;
/* all known values for dexopt flags */
constexpr int DEXOPT_MASK =
@@ -62,7 +63,8 @@
| DEXOPT_SECONDARY_DEX
| DEXOPT_FORCE
| DEXOPT_STORAGE_CE
- | DEXOPT_STORAGE_DE;
+ | DEXOPT_STORAGE_DE
+ | DEXOPT_DISABLE_HIDDEN_API_CHECKS;
// NOTE: keep in sync with StorageManager
constexpr int FLAG_STORAGE_DE = 1 << 0;
diff --git a/cmds/installd/otapreopt.cpp b/cmds/installd/otapreopt.cpp
index 0e36c33..dbd7051 100644
--- a/cmds/installd/otapreopt.cpp
+++ b/cmds/installd/otapreopt.cpp
@@ -78,8 +78,10 @@
static_assert(DEXOPT_FORCE == 1 << 6, "DEXOPT_FORCE unexpected.");
static_assert(DEXOPT_STORAGE_CE == 1 << 7, "DEXOPT_STORAGE_CE unexpected.");
static_assert(DEXOPT_STORAGE_DE == 1 << 8, "DEXOPT_STORAGE_DE unexpected.");
+static_assert(DEXOPT_DISABLE_HIDDEN_API_CHECKS == 1 << 10,
+ "DEXOPT_DISABLE_HIDDEN_API_CHECKS unexpected");
-static_assert(DEXOPT_MASK == 0x1fe, "DEXOPT_MASK unexpected.");
+static_assert(DEXOPT_MASK == 0x5fe, "DEXOPT_MASK unexpected.");
diff --git a/headers/media_plugin/media/arcvideobridge/IArcVideoBridge.h b/headers/media_plugin/media/arcvideobridge/IArcVideoBridge.h
new file mode 100644
index 0000000..b32c92e
--- /dev/null
+++ b/headers/media_plugin/media/arcvideobridge/IArcVideoBridge.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_IARC_VIDEO_BRIDGE_H
+#define ANDROID_IARC_VIDEO_BRIDGE_H
+
+#include <arc/IArcBridgeService.h>
+#include <binder/IInterface.h>
+#include <utils/Errors.h>
+
+namespace android {
+
+class IArcVideoBridge : public IInterface {
+public:
+ DECLARE_META_INTERFACE(ArcVideoBridge);
+
+ // Returns MojoBootstrapResult for creating mojo ipc channel of
+ // VideoAcceleratorFactory.
+ virtual ::arc::MojoBootstrapResult bootstrapVideoAcceleratorFactory() = 0;
+
+ // Get the version of the remote VideoHost on Chromium side.
+ virtual int32_t hostVersion() = 0;
+};
+
+class BnArcVideoBridge : public BnInterface<IArcVideoBridge> {
+public:
+ virtual status_t onTransact(
+ uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0);
+};
+
+}; // namespace android
+
+#endif // ANDROID_IARC_VIDEO_BRIDGE_H
diff --git a/include/audiomanager/IAudioManager.h b/include/audiomanager/IAudioManager.h
index ce7804b..067dc5c 100644
--- a/include/audiomanager/IAudioManager.h
+++ b/include/audiomanager/IAudioManager.h
@@ -110,6 +110,11 @@
/*
DISABLE_RINGTONE_SYNC = IBinder::FIRST_CALL_TRANSACTION + 71,
+ GET_FOCUS_RAMP_TIME_MS = IBinder::FIRST_CALL_TRANSACTION + 72,
+ DISPATCH_FOCUS_CHANGE = IBinder::FIRST_CALL_TRANSACTION + 73,
+ PLAYER_HAS_OP_PLAY_AUDIO = IBinder::FIRST_CALL_TRANSACTION + 74,
+ SET_BLUETOOTH_A2DP_DEVICE_CONNECTION_STATE_SUPPRESS_NOISY_INTENT
+ = IBinder::FIRST_CALL_TRANSACTION + 75,
*/
};
diff --git a/libs/binder/ActivityManager.cpp b/libs/binder/ActivityManager.cpp
index 2904718..7724bf1 100644
--- a/libs/binder/ActivityManager.cpp
+++ b/libs/binder/ActivityManager.cpp
@@ -39,7 +39,7 @@
if (startTime == 0) {
startTime = uptimeMillis();
ALOGI("Waiting for activity service");
- } else if ((uptimeMillis() - startTime) > 10000) {
+ } else if ((uptimeMillis() - startTime) > 1000000) {
ALOGW("Waiting too long for activity service, giving up");
service = NULL;
break;
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
index 239c04d..6103188 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -63,6 +63,7 @@
"MemoryHeapBase.cpp",
"Parcel.cpp",
"PermissionCache.cpp",
+ "PermissionController.cpp",
"PersistableBundle.cpp",
"ProcessInfoService.cpp",
"ProcessState.cpp",
diff --git a/libs/binder/IPermissionController.cpp b/libs/binder/IPermissionController.cpp
index 674bddf..ef67ab8 100644
--- a/libs/binder/IPermissionController.cpp
+++ b/libs/binder/IPermissionController.cpp
@@ -78,6 +78,18 @@
if (reply.readExceptionCode() != 0) return false;
return reply.readInt32() != 0;
}
+
+ virtual int getPackageUid(const String16& package, int flags)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IPermissionController::getInterfaceDescriptor());
+ data.writeString16(package);
+ data.writeInt32(flags);
+ remote()->transact(GET_PACKAGE_UID_TRANSACTION, data, &reply);
+ // fail on exception
+ if (reply.readExceptionCode() != 0) return false;
+ return reply.readInt32();
+ }
};
IMPLEMENT_META_INTERFACE(PermissionController, "android.os.IPermissionController");
@@ -122,6 +134,16 @@
return NO_ERROR;
} break;
+ case GET_PACKAGE_UID_TRANSACTION: {
+ CHECK_INTERFACE(IPermissionController, data, reply);
+ String16 package = data.readString16();
+ int flags = data.readInt32();
+ const int uid = getPackageUid(package, flags);
+ reply->writeNoException();
+ reply->writeInt32(uid);
+ return NO_ERROR;
+ } break;
+
default:
return BBinder::onTransact(code, data, reply, flags);
}
diff --git a/libs/binder/PermissionController.cpp b/libs/binder/PermissionController.cpp
new file mode 100644
index 0000000..25748ca
--- /dev/null
+++ b/libs/binder/PermissionController.cpp
@@ -0,0 +1,82 @@
+/*
+ * 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 <mutex>
+#include <binder/PermissionController.h>
+#include <binder/Binder.h>
+#include <binder/IServiceManager.h>
+
+#include <utils/SystemClock.h>
+
+namespace android {
+
+PermissionController::PermissionController()
+{
+}
+
+sp<IPermissionController> PermissionController::getService()
+{
+ std::lock_guard<Mutex> scoped_lock(mLock);
+ int64_t startTime = 0;
+ sp<IPermissionController> service = mService;
+ while (service == nullptr || !IInterface::asBinder(service)->isBinderAlive()) {
+ sp<IBinder> binder = defaultServiceManager()->checkService(String16("permission"));
+ if (binder == nullptr) {
+ // Wait for the activity service to come back...
+ if (startTime == 0) {
+ startTime = uptimeMillis();
+ ALOGI("Waiting for permission service");
+ } else if ((uptimeMillis() - startTime) > 10000) {
+ ALOGW("Waiting too long for permission service, giving up");
+ service = NULL;
+ break;
+ }
+ sleep(1);
+ } else {
+ service = interface_cast<IPermissionController>(binder);
+ mService = service;
+ }
+ }
+ return service;
+}
+
+bool PermissionController::checkPermission(const String16& permission, int32_t pid, int32_t uid)
+{
+ sp<IPermissionController> service = getService();
+ return service != NULL ? service->checkPermission(permission, pid, uid) : false;
+}
+
+void PermissionController::getPackagesForUid(const uid_t uid, Vector<String16> &packages)
+{
+ sp<IPermissionController> service = getService();
+ if (service != nullptr) {
+ service->getPackagesForUid(uid, packages);
+ }
+}
+
+bool PermissionController::isRuntimePermission(const String16& permission)
+{
+ sp<IPermissionController> service = getService();
+ return service != nullptr ? service->isRuntimePermission(permission) : false;
+}
+
+int PermissionController::getPackageUid(const String16& package, int flags)
+{
+ sp<IPermissionController> service = getService();
+ return service != nullptr ? service->getPackageUid(package, flags) : -1;
+}
+
+}; // namespace android
diff --git a/libs/binder/include/binder/IPermissionController.h b/libs/binder/include/binder/IPermissionController.h
index 25f3431..2f63677 100644
--- a/libs/binder/include/binder/IPermissionController.h
+++ b/libs/binder/include/binder/IPermissionController.h
@@ -36,10 +36,13 @@
virtual bool isRuntimePermission(const String16& permission) = 0;
+ virtual int getPackageUid(const String16& package, int flags) = 0;
+
enum {
CHECK_PERMISSION_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION,
GET_PACKAGES_FOR_UID_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION + 1,
- IS_RUNTIME_PERMISSION_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION + 2
+ IS_RUNTIME_PERMISSION_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION + 2,
+ GET_PACKAGE_UID_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION + 3
};
};
diff --git a/libs/binder/include/binder/PermissionController.h b/libs/binder/include/binder/PermissionController.h
new file mode 100644
index 0000000..c4c98d0
--- /dev/null
+++ b/libs/binder/include/binder/PermissionController.h
@@ -0,0 +1,55 @@
+/*
+ * 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_PERMISSION_CONTROLLER_H
+#define ANDROID_PERMISSION_CONTROLLER_H
+
+#include <binder/IPermissionController.h>
+
+#include <utils/threads.h>
+
+// ---------------------------------------------------------------------------
+namespace android {
+
+class PermissionController
+{
+public:
+
+ enum {
+ MATCH_SYSTEM_ONLY = 1<<16,
+ MATCH_UNINSTALLED_PACKAGES = 1<<13,
+ MATCH_FACTORY_ONLY = 1<<21,
+ MATCH_INSTANT = 1<<23
+ };
+
+ PermissionController();
+
+ bool checkPermission(const String16& permission, int32_t pid, int32_t uid);
+ void getPackagesForUid(const uid_t uid, Vector<String16>& packages);
+ bool isRuntimePermission(const String16& permission);
+ int getPackageUid(const String16& package, int flags);
+
+private:
+ Mutex mLock;
+ sp<IPermissionController> mService;
+
+ sp<IPermissionController> getService();
+};
+
+
+}; // namespace android
+// ---------------------------------------------------------------------------
+#endif // ANDROID_PERMISSION_CONTROLLER_H
diff --git a/libs/gui/BufferItem.cpp b/libs/gui/BufferItem.cpp
index f7409dc..f50379b 100644
--- a/libs/gui/BufferItem.cpp
+++ b/libs/gui/BufferItem.cpp
@@ -55,7 +55,8 @@
mSurfaceDamage(),
mAutoRefresh(false),
mQueuedBuffer(true),
- mIsStale(false) {
+ mIsStale(false),
+ mApi(0) {
}
BufferItem::~BufferItem() {}
@@ -84,6 +85,7 @@
addAligned(size, mAutoRefresh);
addAligned(size, mQueuedBuffer);
addAligned(size, mIsStale);
+ addAligned(size, mApi);
return size;
}
@@ -177,6 +179,7 @@
writeAligned(buffer, size, mAutoRefresh);
writeAligned(buffer, size, mQueuedBuffer);
writeAligned(buffer, size, mIsStale);
+ writeAligned(buffer, size, mApi);
return NO_ERROR;
}
@@ -247,6 +250,7 @@
readAligned(buffer, size, mAutoRefresh);
readAligned(buffer, size, mQueuedBuffer);
readAligned(buffer, size, mIsStale);
+ readAligned(buffer, size, mApi);
return NO_ERROR;
}
diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp
index add857c..e583b40 100644
--- a/libs/gui/BufferQueueProducer.cpp
+++ b/libs/gui/BufferQueueProducer.cpp
@@ -878,6 +878,7 @@
item.mSurfaceDamage = surfaceDamage;
item.mQueuedBuffer = true;
item.mAutoRefresh = mCore->mSharedBufferMode && mCore->mAutoRefresh;
+ item.mApi = mCore->mConnectedApi;
mStickyTransform = stickyTransform;
diff --git a/libs/gui/include/gui/BufferItem.h b/libs/gui/include/gui/BufferItem.h
index 7740b9f..218bb42 100644
--- a/libs/gui/include/gui/BufferItem.h
+++ b/libs/gui/include/gui/BufferItem.h
@@ -127,6 +127,9 @@
// Indicates that this BufferItem contains a stale buffer which has already
// been released by the BufferQueue.
bool mIsStale;
+
+ // Indicates the API (NATIVE_WINDOW_API_xxx) that queues the buffer.
+ int mApi;
};
} // namespace android
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index cd29d4a..8060b6e 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -22,6 +22,7 @@
#include <binder/ProcessState.h>
#include <configstore/Utils.h>
#include <cutils/properties.h>
+#include <inttypes.h>
#include <gui/BufferItemConsumer.h>
#include <gui/IDisplayEventConnection.h>
#include <gui/IProducerListener.h>
@@ -869,7 +870,7 @@
(iOldFrame == NO_FRAME_INDEX) ? nullptr : &mFrames[iOldFrame];
FrameEvents* newFrame = &mFrames[iNewFrame];
- uint64_t nOldFrame = iOldFrame + 1;
+ uint64_t nOldFrame = (iOldFrame == NO_FRAME_INDEX) ? 0 : iOldFrame + 1;
uint64_t nNewFrame = iNewFrame + 1;
// Latch, Composite, and Release the frames in a plausible order.
diff --git a/libs/input/VelocityTracker.cpp b/libs/input/VelocityTracker.cpp
index 57eee12..e54f147 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 = "impulse";
+const char* VelocityTracker::DEFAULT_STRATEGY = "lsq2";
VelocityTracker::VelocityTracker(const char* strategy) :
mLastEventTime(0), mCurrentPointerIdBits(0), mActivePointerId(-1) {
diff --git a/libs/nativewindow/AHardwareBuffer.cpp b/libs/nativewindow/AHardwareBuffer.cpp
index ed292e7..a2712b4 100644
--- a/libs/nativewindow/AHardwareBuffer.cpp
+++ b/libs/nativewindow/AHardwareBuffer.cpp
@@ -29,7 +29,7 @@
#include <system/graphics.h>
#include <private/android/AHardwareBufferHelpers.h>
-#include <android/hardware/graphics/common/1.0/types.h>
+#include <android/hardware/graphics/common/1.1/types.h>
static constexpr int kFdBufferSize = 128 * sizeof(int); // 128 ints
@@ -311,6 +311,18 @@
"HAL and AHardwareBuffer pixel format don't match");
static_assert(HAL_PIXEL_FORMAT_BLOB == AHARDWAREBUFFER_FORMAT_BLOB,
"HAL and AHardwareBuffer pixel format don't match");
+ static_assert(HAL_PIXEL_FORMAT_DEPTH_16 == AHARDWAREBUFFER_FORMAT_D16_UNORM,
+ "HAL and AHardwareBuffer pixel format don't match");
+ static_assert(HAL_PIXEL_FORMAT_DEPTH_24 == AHARDWAREBUFFER_FORMAT_D24_UNORM,
+ "HAL and AHardwareBuffer pixel format don't match");
+ static_assert(HAL_PIXEL_FORMAT_DEPTH_24_STENCIL_8 == AHARDWAREBUFFER_FORMAT_D24_UNORM_S8_UINT,
+ "HAL and AHardwareBuffer pixel format don't match");
+ static_assert(HAL_PIXEL_FORMAT_DEPTH_32F == AHARDWAREBUFFER_FORMAT_D32_FLOAT,
+ "HAL and AHardwareBuffer pixel format don't match");
+ static_assert(HAL_PIXEL_FORMAT_DEPTH_32F_STENCIL_8 == AHARDWAREBUFFER_FORMAT_D32_FLOAT_S8_UINT,
+ "HAL and AHardwareBuffer pixel format don't match");
+ static_assert(HAL_PIXEL_FORMAT_STENCIL_8 == AHARDWAREBUFFER_FORMAT_S8_UINT,
+ "HAL and AHardwareBuffer pixel format don't match");
static_assert(HAL_PIXEL_FORMAT_BGRA_8888 == AHARDWAREBUFFER_FORMAT_B8G8R8A8_UNORM,
"HAL and AHardwareBuffer pixel format don't match");
static_assert(HAL_PIXEL_FORMAT_YV12 == AHARDWAREBUFFER_FORMAT_YV12,
@@ -354,6 +366,12 @@
case AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT:
case AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM:
case AHARDWAREBUFFER_FORMAT_BLOB:
+ case AHARDWAREBUFFER_FORMAT_D16_UNORM:
+ case AHARDWAREBUFFER_FORMAT_D24_UNORM:
+ case AHARDWAREBUFFER_FORMAT_D24_UNORM_S8_UINT:
+ case AHARDWAREBUFFER_FORMAT_D32_FLOAT:
+ case AHARDWAREBUFFER_FORMAT_D32_FLOAT_S8_UINT:
+ case AHARDWAREBUFFER_FORMAT_S8_UINT:
// VNDK formats only -- unfortunately we can't differentiate from where we're called
case AHARDWAREBUFFER_FORMAT_B8G8R8A8_UNORM:
case AHARDWAREBUFFER_FORMAT_YV12:
@@ -388,7 +406,7 @@
}
uint64_t AHardwareBuffer_convertToGrallocUsageBits(uint64_t usage) {
- using android::hardware::graphics::common::V1_0::BufferUsage;
+ using android::hardware::graphics::common::V1_1::BufferUsage;
static_assert(AHARDWAREBUFFER_USAGE_CPU_READ_NEVER == (uint64_t)BufferUsage::CPU_READ_NEVER,
"gralloc and AHardwareBuffer flags don't match");
static_assert(AHARDWAREBUFFER_USAGE_CPU_READ_RARELY == (uint64_t)BufferUsage::CPU_READ_RARELY,
@@ -413,6 +431,10 @@
"gralloc and AHardwareBuffer flags don't match");
static_assert(AHARDWAREBUFFER_USAGE_SENSOR_DIRECT_DATA == (uint64_t)BufferUsage::SENSOR_DIRECT_DATA,
"gralloc and AHardwareBuffer flags don't match");
+ static_assert(AHARDWAREBUFFER_USAGE_GPU_CUBE_MAP == (uint64_t)BufferUsage::GPU_CUBE_MAP,
+ "gralloc and AHardwareBuffer flags don't match");
+ static_assert(AHARDWAREBUFFER_USAGE_GPU_MIPMAP_COMPLETE == (uint64_t)BufferUsage::GPU_MIPMAP_COMPLETE,
+ "gralloc and AHardwareBuffer flags don't match");
return usage;
}
diff --git a/libs/nativewindow/Android.bp b/libs/nativewindow/Android.bp
index 29555fd..5fbb3b2 100644
--- a/libs/nativewindow/Android.bp
+++ b/libs/nativewindow/Android.bp
@@ -60,7 +60,7 @@
"liblog",
"libutils",
"libui",
- "android.hardware.graphics.common@1.0",
+ "android.hardware.graphics.common@1.1",
],
static_libs: [
diff --git a/libs/nativewindow/include/android/hardware_buffer.h b/libs/nativewindow/include/android/hardware_buffer.h
index 52440a5..a477bf2 100644
--- a/libs/nativewindow/include/android/hardware_buffer.h
+++ b/libs/nativewindow/include/android/hardware_buffer.h
@@ -80,6 +80,48 @@
* the buffer size in bytes.
*/
AHARDWAREBUFFER_FORMAT_BLOB = 0x21,
+
+ /**
+ * Corresponding formats:
+ * Vulkan: VK_FORMAT_D16_UNORM
+ * OpenGL ES: GL_DEPTH_COMPONENT16
+ */
+ AHARDWAREBUFFER_FORMAT_D16_UNORM = 0x30,
+
+ /**
+ * Corresponding formats:
+ * Vulkan: VK_FORMAT_X8_D24_UNORM_PACK32
+ * OpenGL ES: GL_DEPTH_COMPONENT24
+ */
+ AHARDWAREBUFFER_FORMAT_D24_UNORM = 0x31,
+
+ /**
+ * Corresponding formats:
+ * Vulkan: VK_FORMAT_D24_UNORM_S8_UINT
+ * OpenGL ES: GL_DEPTH24_STENCIL8
+ */
+ AHARDWAREBUFFER_FORMAT_D24_UNORM_S8_UINT = 0x32,
+
+ /**
+ * Corresponding formats:
+ * Vulkan: VK_FORMAT_D32_SFLOAT
+ * OpenGL ES: GL_DEPTH_COMPONENT32F
+ */
+ AHARDWAREBUFFER_FORMAT_D32_FLOAT = 0x33,
+
+ /**
+ * Corresponding formats:
+ * Vulkan: VK_FORMAT_D32_SFLOAT_S8_UINT
+ * OpenGL ES: GL_DEPTH32F_STENCIL8
+ */
+ AHARDWAREBUFFER_FORMAT_D32_FLOAT_S8_UINT = 0x34,
+
+ /**
+ * Corresponding formats:
+ * Vulkan: VK_FORMAT_S8_UINT
+ * OpenGL ES: GL_STENCIL_INDEX8
+ */
+ AHARDWAREBUFFER_FORMAT_S8_UINT = 0x35,
};
enum {
@@ -109,10 +151,14 @@
AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT = 1UL << 14,
/* The buffer will be read by a hardware video encoder */
AHARDWAREBUFFER_USAGE_VIDEO_ENCODE = 1UL << 16,
- /** The buffer will be used for sensor direct data */
+ /* The buffer will be used for sensor direct data */
AHARDWAREBUFFER_USAGE_SENSOR_DIRECT_DATA = 1UL << 23,
- /* The buffer will be used as a shader storage or uniform buffer object*/
+ /* The buffer will be used as a shader storage or uniform buffer object */
AHARDWAREBUFFER_USAGE_GPU_DATA_BUFFER = 1UL << 24,
+ /* The buffer will be used as a cube map texture */
+ AHARDWAREBUFFER_USAGE_GPU_CUBE_MAP = 1UL << 25,
+ /* The buffer contains a complete mipmap hierarchy */
+ AHARDWAREBUFFER_USAGE_GPU_MIPMAP_COMPLETE = 1UL << 26,
AHARDWAREBUFFER_USAGE_VENDOR_0 = 1ULL << 28,
AHARDWAREBUFFER_USAGE_VENDOR_1 = 1ULL << 29,
diff --git a/libs/sensor/ISensorServer.cpp b/libs/sensor/ISensorServer.cpp
index efbbf7d..5200545 100644
--- a/libs/sensor/ISensorServer.cpp
+++ b/libs/sensor/ISensorServer.cpp
@@ -27,6 +27,7 @@
#include <binder/Parcel.h>
#include <binder/IInterface.h>
+#include <binder/IResultReceiver.h>
#include <sensor/Sensor.h>
#include <sensor/ISensorEventConnection.h>
@@ -227,6 +228,30 @@
reply->writeInt32(ret);
return NO_ERROR;
}
+ case SHELL_COMMAND_TRANSACTION: {
+ int in = data.readFileDescriptor();
+ int out = data.readFileDescriptor();
+ int err = data.readFileDescriptor();
+ int argc = data.readInt32();
+ Vector<String16> args;
+ for (int i = 0; i < argc && data.dataAvail() > 0; i++) {
+ args.add(data.readString16());
+ }
+ sp<IBinder> unusedCallback;
+ sp<IResultReceiver> resultReceiver;
+ status_t status;
+ if ((status = data.readNullableStrongBinder(&unusedCallback)) != NO_ERROR) {
+ return status;
+ }
+ if ((status = data.readNullableStrongBinder(&resultReceiver)) != NO_ERROR) {
+ return status;
+ }
+ status = shellCommand(in, out, err, args);
+ if (resultReceiver != nullptr) {
+ resultReceiver->send(status);
+ }
+ return NO_ERROR;
+ }
}
return BBinder::onTransact(code, data, reply, flags);
}
diff --git a/libs/sensor/include/sensor/ISensorServer.h b/libs/sensor/include/sensor/ISensorServer.h
index edf3e0f..402678f 100644
--- a/libs/sensor/include/sensor/ISensorServer.h
+++ b/libs/sensor/include/sensor/ISensorServer.h
@@ -60,6 +60,9 @@
class BnSensorServer : public BnInterface<ISensorServer>
{
public:
+ virtual status_t shellCommand(int in, int out, int err,
+ Vector<String16>& args) = 0;
+
virtual status_t onTransact( uint32_t code,
const Parcel& data,
Parcel* reply,
diff --git a/libs/ui/Gralloc2.cpp b/libs/ui/Gralloc2.cpp
index 1f746a2..60ec38c 100644
--- a/libs/ui/Gralloc2.cpp
+++ b/libs/ui/Gralloc2.cpp
@@ -20,6 +20,7 @@
#include <hwbinder/IPCThreadState.h>
#include <ui/Gralloc2.h>
+#include <inttypes.h>
#include <log/log.h>
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wzero-length-array"
@@ -30,8 +31,40 @@
namespace Gralloc2 {
+namespace {
+
static constexpr Error kTransactionError = Error::NO_RESOURCES;
+uint64_t getValid10UsageBits() {
+ static const uint64_t valid10UsageBits = []() -> uint64_t {
+ using hardware::graphics::common::V1_0::BufferUsage;
+ uint64_t bits = 0;
+ for (const auto bit : hardware::hidl_enum_iterator<BufferUsage>()) {
+ bits = bits | bit;
+ }
+ // TODO(b/72323293): Remove this mask for EXTERNAL_DISP.
+ bits = bits | (1 << 13);
+
+ return bits;
+ }();
+ return valid10UsageBits;
+}
+
+uint64_t getValid11UsageBits() {
+ static const uint64_t valid11UsageBits = []() -> uint64_t {
+ using hardware::graphics::common::V1_1::BufferUsage;
+ uint64_t bits = 0;
+ for (const auto bit : hardware::hidl_enum_iterator<BufferUsage>()) {
+ bits = bits | bit;
+ }
+ // Return only the overlapping bits.
+ return bits & ~getValid10UsageBits();
+ }();
+ return valid11UsageBits;
+}
+
+} // anonymous namespace
+
void Mapper::preload() {
android::hardware::preloadPassthroughService<hardware::graphics::mapper::V2_0::IMapper>();
}
@@ -50,11 +83,39 @@
mMapperV2_1 = hardware::graphics::mapper::V2_1::IMapper::castFrom(mMapper);
}
+Gralloc2::Error Mapper::validateBufferDescriptorInfo(
+ const IMapper::BufferDescriptorInfo& descriptorInfo) const {
+ uint64_t validUsageBits = getValid10UsageBits();
+ if (mMapperV2_1 != nullptr) {
+ validUsageBits = validUsageBits | getValid11UsageBits();
+ }
+
+ if (descriptorInfo.usage & ~validUsageBits) {
+ ALOGE("buffer descriptor contains invalid usage bits 0x%" PRIx64,
+ descriptorInfo.usage & ~validUsageBits);
+ return Error::BAD_VALUE;
+ }
+ return Error::NONE;
+}
+
Error Mapper::createDescriptor(
const IMapper::BufferDescriptorInfo& descriptorInfo,
BufferDescriptor* outDescriptor) const
{
Error error;
+
+ if (descriptorInfo.usage & getValid11UsageBits()) {
+ // TODO(b/66900669): Use mMapperV2_1->createDescriptorV2_1().
+ ALOGW("full support for new usage bits is unimplemented 0x%" PRIx64,
+ descriptorInfo.usage & getValid11UsageBits());
+ return Error::BAD_VALUE;
+ }
+
+ error = validateBufferDescriptorInfo(descriptorInfo);
+ if (error != Error::NONE) {
+ return error;
+ }
+
auto ret = mMapper->createDescriptor(descriptorInfo,
[&](const auto& tmpError, const auto& tmpDescriptor)
{
diff --git a/libs/ui/GraphicBufferMapper.cpp b/libs/ui/GraphicBufferMapper.cpp
index 2cac287..2d8e582 100644
--- a/libs/ui/GraphicBufferMapper.cpp
+++ b/libs/ui/GraphicBufferMapper.cpp
@@ -72,6 +72,7 @@
info.layerCount = layerCount;
info.format = static_cast<Gralloc2::PixelFormat>(format);
info.usage = usage;
+
error = mMapper->validateBufferSize(bufferHandle, info, stride);
if (error != Gralloc2::Error::NONE) {
ALOGE("validateBufferSize(%p) failed: %d", rawHandle, error);
diff --git a/libs/ui/include/ui/Gralloc2.h b/libs/ui/include/ui/Gralloc2.h
index 69c35f7..db3f10a 100644
--- a/libs/ui/include/ui/Gralloc2.h
+++ b/libs/ui/include/ui/Gralloc2.h
@@ -20,6 +20,7 @@
#include <string>
#include <android/hardware/graphics/allocator/2.0/IAllocator.h>
+#include <android/hardware/graphics/common/1.1/types.h>
#include <android/hardware/graphics/mapper/2.0/IMapper.h>
#include <android/hardware/graphics/mapper/2.1/IMapper.h>
#include <utils/StrongPointer.h>
@@ -29,8 +30,8 @@
namespace Gralloc2 {
using hardware::graphics::allocator::V2_0::IAllocator;
-using hardware::graphics::common::V1_0::BufferUsage;
using hardware::graphics::common::V1_0::PixelFormat;
+using hardware::graphics::common::V1_1::BufferUsage;
using hardware::graphics::mapper::V2_0::BufferDescriptor;
using hardware::graphics::mapper::V2_0::Error;
using hardware::graphics::mapper::V2_0::IMapper;
@@ -80,6 +81,10 @@
int unlock(buffer_handle_t bufferHandle) const;
private:
+ // Determines whether the passed info is compatible with the mapper.
+ Error validateBufferDescriptorInfo(
+ const IMapper::BufferDescriptorInfo& descriptorInfo) const;
+
sp<IMapper> mMapper;
sp<hardware::graphics::mapper::V2_1::IMapper> mMapperV2_1;
};
diff --git a/libs/vr/libvrflinger/Android.bp b/libs/vr/libvrflinger/Android.bp
index 4d80e91..1c5b2d6 100644
--- a/libs/vr/libvrflinger/Android.bp
+++ b/libs/vr/libvrflinger/Android.bp
@@ -27,7 +27,6 @@
staticLibraries = [
"libsurfaceflingerincludes",
- "libhwcomposer-command-buffer",
"libbufferhub",
"libbufferhubqueue",
"libdisplay",
@@ -64,7 +63,8 @@
]
headerLibraries = [
- "libdvr_headers"
+ "libdvr_headers",
+ "android.hardware.graphics.composer@2.1-command-buffer",
]
cc_library_static {
diff --git a/services/media/arcvideobridge/Android.bp b/services/media/arcvideobridge/Android.bp
new file mode 100644
index 0000000..ed0f613
--- /dev/null
+++ b/services/media/arcvideobridge/Android.bp
@@ -0,0 +1,29 @@
+cc_library_shared {
+ name: "libarcvideobridge",
+ product_variables: {
+ arc: {
+ srcs: [
+ "IArcVideoBridge.cpp",
+ ],
+ // TODO: remove the suffix "_bp" after finishing migration to Android.bp.
+ shared_libs: [
+ "libarcbridge",
+ "libarcbridgeservice",
+ "libbinder",
+ "libchrome",
+ "liblog",
+ "libmojo_bp",
+ "libutils",
+ ],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-Wunused",
+ "-Wunreachable-code",
+ ],
+ include_dirs: [
+ "frameworks/native/include/media/arcvideobridge",
+ ]
+ }
+ }
+}
diff --git a/services/media/arcvideobridge/IArcVideoBridge.cpp b/services/media/arcvideobridge/IArcVideoBridge.cpp
new file mode 100644
index 0000000..468b76b
--- /dev/null
+++ b/services/media/arcvideobridge/IArcVideoBridge.cpp
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "IArcVideoBridge"
+//#define LOG_NDEBUG 0
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include "IArcVideoBridge.h"
+#include <binder/Parcel.h>
+#include <utils/Log.h>
+
+namespace android {
+
+enum {
+ BOOTSTRAP_VIDEO_ACCELERATOR_FACTORY = IBinder::FIRST_CALL_TRANSACTION,
+ HOST_VERSION,
+};
+
+class BpArcVideoBridge : public BpInterface<IArcVideoBridge> {
+public:
+ BpArcVideoBridge(const sp<IBinder>& impl) : BpInterface<IArcVideoBridge>(impl) { }
+
+ virtual ::arc::MojoBootstrapResult bootstrapVideoAcceleratorFactory() {
+ Parcel data, reply;
+ ALOGV("bootstrapVideoAcceleratorFactory");
+ data.writeInterfaceToken(IArcVideoBridge::getInterfaceDescriptor());
+ status_t status = remote()->transact(
+ BOOTSTRAP_VIDEO_ACCELERATOR_FACTORY, data, &reply, 0);
+ if (status != 0) {
+ ALOGE("transact failed: %d", status);
+ return arc::MojoBootstrapResult();
+ }
+ return arc::MojoBootstrapResult::createFromParcel(reply);
+ }
+
+ virtual int32_t hostVersion() {
+ Parcel data, reply;
+ ALOGV("hostVersion");
+ data.writeInterfaceToken(IArcVideoBridge::getInterfaceDescriptor());
+ status_t status = remote()->transact(HOST_VERSION, data, &reply, 0);
+ if (status != 0) {
+ ALOGE("transact failed: %d", status);
+ return false;
+ }
+ return reply.readInt32();
+ }
+};
+
+IMPLEMENT_META_INTERFACE(ArcVideoBridge, "android.os.IArcVideoBridge");
+
+status_t BnArcVideoBridge::onTransact(
+ uint32_t code, const Parcel &data, Parcel *reply, uint32_t flags) {
+ switch(code) {
+ case BOOTSTRAP_VIDEO_ACCELERATOR_FACTORY: {
+ ALOGV("BOOTSTRAP_VIDEO_ACCELERATOR_FACTORY");
+ CHECK_INTERFACE(IArcVideoBridge, data, reply);
+ arc::MojoBootstrapResult result = bootstrapVideoAcceleratorFactory();
+ return result.writeToParcel(reply);
+ }
+ case HOST_VERSION: {
+ ALOGV("HOST_VERSION");
+ CHECK_INTERFACE(IArcVideoBridge, data, reply);
+ reply->writeInt32(hostVersion());
+ return OK;
+ }
+ default:
+ return BBinder::onTransact(code, data, reply, flags);
+ }
+}
+
+} // namespace android
diff --git a/services/sensorservice/SensorEventConnection.cpp b/services/sensorservice/SensorEventConnection.cpp
index 0a05dd1..956844f 100644
--- a/services/sensorservice/SensorEventConnection.cpp
+++ b/services/sensorservice/SensorEventConnection.cpp
@@ -29,11 +29,11 @@
SensorService::SensorEventConnection::SensorEventConnection(
const sp<SensorService>& service, uid_t uid, String8 packageName, bool isDataInjectionMode,
- const String16& opPackageName)
+ const String16& opPackageName, bool hasSensorAccess)
: mService(service), mUid(uid), mWakeLockRefCount(0), mHasLooperCallbacks(false),
mDead(false), mDataInjectionMode(isDataInjectionMode), mEventCache(NULL),
mCacheSize(0), mMaxCacheSize(0), mPackageName(packageName), mOpPackageName(opPackageName),
- mDestroyed(false) {
+ mDestroyed(false), mHasSensorAccess(hasSensorAccess) {
mChannel = new BitTube(mService->mSocketBufferSize);
#if DEBUG_CONNECTIONS
mEventsReceived = mEventsSentFromCache = mEventsSent = 0;
@@ -223,6 +223,9 @@
sensors_event_t* scratch,
wp<const SensorEventConnection> const * mapFlushEventsToConnections) {
// filter out events not for this connection
+
+ sensors_event_t* sanitizedBuffer = nullptr;
+
int count = 0;
Mutex::Autolock _l(mConnectionLock);
if (scratch) {
@@ -273,24 +276,36 @@
if (mapFlushEventsToConnections[i] == this) {
scratch[count++] = buffer[i];
}
- ++i;
} else {
// Regular sensor event, just copy it to the scratch buffer.
- scratch[count++] = buffer[i++];
+ if (mHasSensorAccess) {
+ scratch[count++] = buffer[i];
+ }
}
+ i++;
} while ((i<numEvents) && ((buffer[i].sensor == sensor_handle &&
buffer[i].type != SENSOR_TYPE_META_DATA) ||
(buffer[i].type == SENSOR_TYPE_META_DATA &&
buffer[i].meta_data.sensor == sensor_handle)));
}
} else {
- scratch = const_cast<sensors_event_t *>(buffer);
- count = numEvents;
+ if (mHasSensorAccess) {
+ scratch = const_cast<sensors_event_t *>(buffer);
+ count = numEvents;
+ } else {
+ scratch = sanitizedBuffer = new sensors_event_t[numEvents];
+ for (size_t i = 0; i < numEvents; i++) {
+ if (buffer[i].type == SENSOR_TYPE_META_DATA) {
+ scratch[count++] = buffer[i++];
+ }
+ }
+ }
}
sendPendingFlushEventsLocked();
// Early return if there are no events for this connection.
if (count == 0) {
+ delete sanitizedBuffer;
return status_t(NO_ERROR);
}
@@ -308,6 +323,7 @@
// the max cache size that is desired.
if (mCacheSize + count < computeMaxCacheSizeLocked()) {
reAllocateCacheLocked(scratch, count);
+ delete sanitizedBuffer;
return status_t(NO_ERROR);
}
// Some events need to be dropped.
@@ -326,16 +342,20 @@
memcpy(&mEventCache[mCacheSize - numEventsDropped], scratch + remaningCacheSize,
numEventsDropped * sizeof(sensors_event_t));
}
+ delete sanitizedBuffer;
return status_t(NO_ERROR);
}
- int index_wake_up_event = findWakeUpSensorEventLocked(scratch, count);
- if (index_wake_up_event >= 0) {
- scratch[index_wake_up_event].flags |= WAKE_UP_SENSOR_EVENT_NEEDS_ACK;
- ++mWakeLockRefCount;
+ int index_wake_up_event = -1;
+ if (mHasSensorAccess) {
+ index_wake_up_event = findWakeUpSensorEventLocked(scratch, count);
+ if (index_wake_up_event >= 0) {
+ scratch[index_wake_up_event].flags |= WAKE_UP_SENSOR_EVENT_NEEDS_ACK;
+ ++mWakeLockRefCount;
#if DEBUG_CONNECTIONS
- ++mTotalAcksNeeded;
+ ++mTotalAcksNeeded;
#endif
+ }
}
// NOTE: ASensorEvent and sensors_event_t are the same type.
@@ -364,6 +384,7 @@
// Add this file descriptor to the looper to get a callback when this fd is available for
// writing.
updateLooperRegistrationLocked(mService->getLooper());
+ delete sanitizedBuffer;
return size;
}
@@ -373,9 +394,15 @@
}
#endif
+ delete sanitizedBuffer;
return size < 0 ? status_t(size) : status_t(NO_ERROR);
}
+void SensorService::SensorEventConnection::setSensorAccess(const bool hasAccess) {
+ Mutex::Autolock _l(mConnectionLock);
+ mHasSensorAccess = hasAccess;
+}
+
void SensorService::SensorEventConnection::reAllocateCacheLocked(sensors_event_t const* scratch,
int count) {
sensors_event_t *eventCache_new;
@@ -437,15 +464,18 @@
sendPendingFlushEventsLocked();
for (int numEventsSent = 0; numEventsSent < mCacheSize;) {
const int numEventsToWrite = helpers::min(mCacheSize - numEventsSent, maxWriteSize);
- int index_wake_up_event =
- findWakeUpSensorEventLocked(mEventCache + numEventsSent, numEventsToWrite);
- if (index_wake_up_event >= 0) {
- mEventCache[index_wake_up_event + numEventsSent].flags |=
- WAKE_UP_SENSOR_EVENT_NEEDS_ACK;
- ++mWakeLockRefCount;
+ int index_wake_up_event = -1;
+ if (mHasSensorAccess) {
+ index_wake_up_event =
+ findWakeUpSensorEventLocked(mEventCache + numEventsSent, numEventsToWrite);
+ if (index_wake_up_event >= 0) {
+ mEventCache[index_wake_up_event + numEventsSent].flags |=
+ WAKE_UP_SENSOR_EVENT_NEEDS_ACK;
+ ++mWakeLockRefCount;
#if DEBUG_CONNECTIONS
- ++mTotalAcksNeeded;
+ ++mTotalAcksNeeded;
#endif
+ }
}
ssize_t size = SensorEventQueue::write(mChannel,
diff --git a/services/sensorservice/SensorEventConnection.h b/services/sensorservice/SensorEventConnection.h
index 6f282cd..032721e 100644
--- a/services/sensorservice/SensorEventConnection.h
+++ b/services/sensorservice/SensorEventConnection.h
@@ -49,7 +49,8 @@
public:
SensorEventConnection(const sp<SensorService>& service, uid_t uid, String8 packageName,
- bool isDataInjectionMode, const String16& opPackageName);
+ bool isDataInjectionMode, const String16& opPackageName,
+ bool hasSensorAccess);
status_t sendEvents(sensors_event_t const* buffer, size_t count, sensors_event_t* scratch,
wp<const SensorEventConnection> const * mapFlushEventsToConnections = NULL);
@@ -66,6 +67,8 @@
uid_t getUid() const { return mUid; }
+ void setSensorAccess(const bool hasAccess);
+
private:
virtual ~SensorEventConnection();
virtual void onFirstRef();
@@ -167,6 +170,7 @@
mutable Mutex mDestroyLock;
bool mDestroyed;
+ bool mHasSensorAccess;
};
} // namepsace android
diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
index dc491d9..c32ffb9 100644
--- a/services/sensorservice/SensorService.cpp
+++ b/services/sensorservice/SensorService.cpp
@@ -13,11 +13,14 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+#include <binder/ActivityManager.h>
#include <binder/AppOpsManager.h>
#include <binder/BinderService.h>
#include <binder/IServiceManager.h>
#include <binder/PermissionCache.h>
+#include <binder/PermissionController.h>
#include <cutils/ashmem.h>
+#include <cutils/misc.h>
#include <cutils/properties.h>
#include <hardware/sensors.h>
#include <hardware_legacy/power.h>
@@ -52,6 +55,8 @@
#include <sys/types.h>
#include <unistd.h>
+#include <private/android_filesystem_config.h>
+
namespace android {
// ---------------------------------------------------------------------------
@@ -75,6 +80,7 @@
// Permissions.
static const String16 sDumpPermission("android.permission.DUMP");
static const String16 sLocationHardwarePermission("android.permission.LOCATION_HARDWARE");
+static const String16 sManageSensorsPermission("android.permission.MANAGE_SENSORS");
SensorService::SensorService()
: mInitCheck(NO_INIT), mSocketBufferSize(SOCKET_BUFFER_SIZE_NON_BATCHED),
@@ -274,6 +280,23 @@
// priority can only be changed after run
enableSchedFifoMode();
+
+ // Start watching UID changes to apply policy.
+ mUidPolicy = new UidPolicy(this);
+ mUidPolicy->registerSelf();
+ }
+ }
+}
+
+void SensorService::setSensorAccess(uid_t uid, bool hasAccess) {
+ SortedVector< sp<SensorEventConnection> > activeConnections;
+ populateActiveConnections(&activeConnections);
+ {
+ Mutex::Autolock _l(mLock);
+ for (size_t i = 0 ; i < activeConnections.size(); i++) {
+ if (activeConnections[i] != 0 && activeConnections[i]->getUid() == uid) {
+ activeConnections[i]->setSensorAccess(hasAccess);
+ }
}
}
}
@@ -312,6 +335,7 @@
for (auto && entry : mRecentEvent) {
delete entry.second;
}
+ mUidPolicy->unregisterSelf();
}
status_t SensorService::dump(int fd, const Vector<String16>& args) {
@@ -488,6 +512,82 @@
return NO_ERROR;
}
+// NOTE: This is a remote API - make sure all args are validated
+status_t SensorService::shellCommand(int in, int out, int err, Vector<String16>& args) {
+ if (!checkCallingPermission(sManageSensorsPermission, nullptr, nullptr)) {
+ return PERMISSION_DENIED;
+ }
+ if (in == BAD_TYPE || out == BAD_TYPE || err == BAD_TYPE) {
+ return BAD_VALUE;
+ }
+ if (args.size() == 3 && args[0] == String16("set-uid-state")) {
+ return handleSetUidState(args, err);
+ } else if (args.size() == 2 && args[0] == String16("reset-uid-state")) {
+ return handleResetUidState(args, err);
+ } else if (args.size() == 2 && args[0] == String16("get-uid-state")) {
+ return handleGetUidState(args, out, err);
+ } else if (args.size() == 1 && args[0] == String16("help")) {
+ printHelp(out);
+ return NO_ERROR;
+ }
+ printHelp(err);
+ return BAD_VALUE;
+}
+
+status_t SensorService::handleSetUidState(Vector<String16>& args, int err) {
+ PermissionController pc;
+ int uid = pc.getPackageUid(args[1], 0);
+ if (uid <= 0) {
+ ALOGE("Unknown package: '%s'", String8(args[1]).string());
+ dprintf(err, "Unknown package: '%s'\n", String8(args[1]).string());
+ return BAD_VALUE;
+ }
+ bool active = false;
+ if (args[2] == String16("active")) {
+ active = true;
+ } else if ((args[2] != String16("idle"))) {
+ ALOGE("Expected active or idle but got: '%s'", String8(args[2]).string());
+ return BAD_VALUE;
+ }
+ mUidPolicy->addOverrideUid(uid, active);
+ return NO_ERROR;
+}
+
+status_t SensorService::handleResetUidState(Vector<String16>& args, int err) {
+ PermissionController pc;
+ int uid = pc.getPackageUid(args[1], 0);
+ if (uid < 0) {
+ ALOGE("Unknown package: '%s'", String8(args[1]).string());
+ dprintf(err, "Unknown package: '%s'\n", String8(args[1]).string());
+ return BAD_VALUE;
+ }
+ mUidPolicy->removeOverrideUid(uid);
+ return NO_ERROR;
+}
+
+status_t SensorService::handleGetUidState(Vector<String16>& args, int out, int err) {
+ PermissionController pc;
+ int uid = pc.getPackageUid(args[1], 0);
+ if (uid < 0) {
+ ALOGE("Unknown package: '%s'", String8(args[1]).string());
+ dprintf(err, "Unknown package: '%s'\n", String8(args[1]).string());
+ return BAD_VALUE;
+ }
+ if (mUidPolicy->isUidActive(uid)) {
+ return dprintf(out, "active\n");
+ } else {
+ return dprintf(out, "idle\n");
+ }
+}
+
+status_t SensorService::printHelp(int out) {
+ return dprintf(out, "Sensor service commands:\n"
+ " get-uid-state <PACKAGE> gets the uid state\n"
+ " set-uid-state <PACKAGE> <active|idle> overrides the uid state\n"
+ " reset-uid-state <PACKAGE> clears the uid state override\n"
+ " help print this message\n");
+}
+
//TODO: move to SensorEventConnection later
void SensorService::cleanupAutoDisabledSensorLocked(const sp<SensorEventConnection>& connection,
sensors_event_t const* buffer, const int count) {
@@ -677,7 +777,6 @@
}
}
-
// Send our events to clients. Check the state of wake lock for each client and release the
// lock if none of the clients need it.
bool needsWakeLock = false;
@@ -939,8 +1038,9 @@
(packageName == "") ? String8::format("unknown_package_pid_%d", pid) : packageName;
String16 connOpPackageName =
(opPackageName == String16("")) ? String16(connPackageName) : opPackageName;
+ bool hasSensorAccess = mUidPolicy->isUidActive(uid);
sp<SensorEventConnection> result(new SensorEventConnection(this, uid, connPackageName,
- requestedMode == DATA_INJECTION, connOpPackageName));
+ requestedMode == DATA_INJECTION, connOpPackageName, hasSensorAccess));
if (requestedMode == DATA_INJECTION) {
if (mActiveConnections.indexOf(result) < 0) {
mActiveConnections.add(result);
@@ -1530,4 +1630,98 @@
return false;
}
+void SensorService::UidPolicy::registerSelf() {
+ ActivityManager am;
+ am.registerUidObserver(this, ActivityManager::UID_OBSERVER_GONE
+ | ActivityManager::UID_OBSERVER_IDLE
+ | ActivityManager::UID_OBSERVER_ACTIVE,
+ ActivityManager::PROCESS_STATE_UNKNOWN,
+ String16("android"));
+}
+
+void SensorService::UidPolicy::unregisterSelf() {
+ ActivityManager am;
+ am.unregisterUidObserver(this);
+}
+
+void SensorService::UidPolicy::onUidGone(__unused uid_t uid, __unused bool disabled) {
+ onUidIdle(uid, disabled);
+}
+
+void SensorService::UidPolicy::onUidActive(uid_t uid) {
+ {
+ Mutex::Autolock _l(mUidLock);
+ mActiveUids.insert(uid);
+ }
+ sp<SensorService> service = mService.promote();
+ if (service != nullptr) {
+ service->setSensorAccess(uid, true);
+ }
+}
+
+void SensorService::UidPolicy::onUidIdle(uid_t uid, __unused bool disabled) {
+ bool deleted = false;
+ {
+ Mutex::Autolock _l(mUidLock);
+ if (mActiveUids.erase(uid) > 0) {
+ deleted = true;
+ }
+ }
+ if (deleted) {
+ sp<SensorService> service = mService.promote();
+ if (service != nullptr) {
+ service->setSensorAccess(uid, false);
+ }
+ }
+}
+
+void SensorService::UidPolicy::addOverrideUid(uid_t uid, bool active) {
+ updateOverrideUid(uid, active, true);
+}
+
+void SensorService::UidPolicy::removeOverrideUid(uid_t uid) {
+ updateOverrideUid(uid, false, false);
+}
+
+void SensorService::UidPolicy::updateOverrideUid(uid_t uid, bool active, bool insert) {
+ bool wasActive = false;
+ bool isActive = false;
+ {
+ Mutex::Autolock _l(mUidLock);
+ wasActive = isUidActiveLocked(uid);
+ mOverrideUids.erase(uid);
+ if (insert) {
+ mOverrideUids.insert(std::pair<uid_t, bool>(uid, active));
+ }
+ isActive = isUidActiveLocked(uid);
+ }
+ if (wasActive != isActive) {
+ sp<SensorService> service = mService.promote();
+ if (service != nullptr) {
+ service->setSensorAccess(uid, isActive);
+ }
+ }
+}
+
+bool SensorService::UidPolicy::isUidActive(uid_t uid) {
+ // Non-app UIDs are considered always active
+ if (uid < FIRST_APPLICATION_UID) {
+ return true;
+ }
+ Mutex::Autolock _l(mUidLock);
+ return isUidActiveLocked(uid);
+}
+
+bool SensorService::UidPolicy::isUidActiveLocked(uid_t uid) {
+ // Non-app UIDs are considered always active
+ if (uid < FIRST_APPLICATION_UID) {
+ return true;
+ }
+ auto it = mOverrideUids.find(uid);
+ if (it != mOverrideUids.end()) {
+ return it->second;
+ }
+ return mActiveUids.find(uid) != mActiveUids.end();
+}
+
}; // namespace android
diff --git a/services/sensorservice/SensorService.h b/services/sensorservice/SensorService.h
index 3e18394..f71723d 100644
--- a/services/sensorservice/SensorService.h
+++ b/services/sensorservice/SensorService.h
@@ -21,6 +21,7 @@
#include "RecentEventLogger.h"
#include <binder/BinderService.h>
+#include <binder/IUidObserver.h>
#include <cutils/compiler.h>
#include <sensor/ISensorServer.h>
#include <sensor/ISensorEventConnection.h>
@@ -85,6 +86,9 @@
status_t flushSensor(const sp<SensorEventConnection>& connection,
const String16& opPackageName);
+
+ virtual status_t shellCommand(int in, int out, int err, Vector<String16>& args);
+
private:
friend class BinderService<SensorService>;
@@ -93,6 +97,40 @@
class SensorEventAckReceiver;
class SensorRegistrationInfo;
+ // If accessing a sensor we need to make sure the UID has access to it. If
+ // the app UID is idle then it cannot access sensors and gets no trigger
+ // events, no on-change events, flush event behavior does not change, and
+ // recurring events are the same as the first one delivered in idle state
+ // emulating no sensor change. As soon as the app UID transitions to an
+ // active state we will start reporting events as usual and vise versa. This
+ // approach transparently handles observing sensors while the app UID transitions
+ // between idle/active state avoiding to get stuck in a state receiving sensor
+ // data while idle or not receiving sensor data while active.
+ class UidPolicy : public BnUidObserver {
+ public:
+ explicit UidPolicy(wp<SensorService> service)
+ : mService(service) {}
+ void registerSelf();
+ void unregisterSelf();
+
+ bool isUidActive(uid_t uid);
+
+ void onUidGone(uid_t uid, bool disabled);
+ void onUidActive(uid_t uid);
+ void onUidIdle(uid_t uid, bool disabled);
+
+ void addOverrideUid(uid_t uid, bool active);
+ void removeOverrideUid(uid_t uid);
+ private:
+ bool isUidActiveLocked(uid_t uid);
+ void updateOverrideUid(uid_t uid, bool active, bool insert);
+
+ Mutex mUidLock;
+ wp<SensorService> mService;
+ std::unordered_set<uid_t> mActiveUids;
+ std::unordered_map<uid_t, bool> mOverrideUids;
+ };
+
enum Mode {
// The regular operating mode where any application can register/unregister/call flush on
// sensors.
@@ -161,7 +199,6 @@
virtual int setOperationParameter(
int32_t handle, int32_t type, const Vector<float> &floats, const Vector<int32_t> &ints);
virtual status_t dump(int fd, const Vector<String16>& args);
-
String8 getSensorName(int handle) const;
bool isVirtualSensor(int handle) const;
sp<SensorInterface> getSensorInterfaceFromHandle(int handle) const;
@@ -225,6 +262,18 @@
// Enable SCHED_FIFO priority for thread
void enableSchedFifoMode();
+ // Sets whether the given UID can get sensor data
+ void setSensorAccess(uid_t uid, bool hasAccess);
+
+ // Overrides the UID state as if it is idle
+ status_t handleSetUidState(Vector<String16>& args, int err);
+ // Clears the override for the UID state
+ status_t handleResetUidState(Vector<String16>& args, int err);
+ // Gets the UID state
+ status_t handleGetUidState(Vector<String16>& args, int out, int err);
+ // Prints the shell command help
+ status_t printHelp(int out);
+
static uint8_t sHmacGlobalKey[128];
static bool sHmacGlobalKeyIsValid;
@@ -257,6 +306,8 @@
int mNextSensorRegIndex;
Vector<SensorRegistrationInfo> mLastNSensorRegistrations;
+
+ sp<UidPolicy> mUidPolicy;
};
} // namespace android
diff --git a/services/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk
index 5b6c1ca..6c54ec3 100644
--- a/services/surfaceflinger/Android.mk
+++ b/services/surfaceflinger/Android.mk
@@ -59,13 +59,15 @@
LOCAL_CFLAGS += -fvisibility=hidden -Werror=format
LOCAL_STATIC_LIBRARIES := \
- libhwcomposer-command-buffer \
libtrace_proto \
libvkjson \
libvr_manager \
libvrflinger \
libserviceutils
+LOCAL_HEADER_LIBRARIES := \
+ android.hardware.graphics.composer@2.1-command-buffer
+
LOCAL_EXPORT_STATIC_LIBRARY_HEADERS := libserviceutils
LOCAL_SHARED_LIBRARIES := \
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index d860f58..ab6a559 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -821,8 +821,17 @@
engine.setupLayerBlending(mPremultipliedAlpha, isOpaque(s), false /* disableTexture */,
getColor());
engine.setSourceDataSpace(mCurrentState.dataSpace);
+
+ if (mCurrentState.dataSpace == HAL_DATASPACE_BT2020_PQ &&
+ mConsumer->getCurrentApi() == NATIVE_WINDOW_API_MEDIA &&
+ getBE().compositionInfo.mBuffer->getPixelFormat() == HAL_PIXEL_FORMAT_RGBA_1010102) {
+ engine.setSourceY410BT2020(true);
+ }
+
engine.drawMesh(getBE().mMesh);
engine.disableBlending();
+
+ engine.setSourceY410BT2020(false);
}
uint32_t BufferLayer::getProducerStickyTransform() const {
diff --git a/services/surfaceflinger/BufferLayerConsumer.cpp b/services/surfaceflinger/BufferLayerConsumer.cpp
index 8f5c9c7..4d9b43f 100644
--- a/services/surfaceflinger/BufferLayerConsumer.cpp
+++ b/services/surfaceflinger/BufferLayerConsumer.cpp
@@ -68,6 +68,7 @@
mCurrentFrameNumber(0),
mCurrentTransformToDisplayInverse(false),
mCurrentSurfaceDamage(),
+ mCurrentApi(0),
mDefaultWidth(1),
mDefaultHeight(1),
mFilteringEnabled(true),
@@ -346,6 +347,7 @@
mCurrentFrameNumber = item.mFrameNumber;
mCurrentTransformToDisplayInverse = item.mTransformToDisplayInverse;
mCurrentSurfaceDamage = item.mSurfaceDamage;
+ mCurrentApi = item.mApi;
computeCurrentTransformMatrixLocked();
@@ -469,6 +471,11 @@
return mCurrentSurfaceDamage;
}
+int BufferLayerConsumer::getCurrentApi() const {
+ Mutex::Autolock lock(mMutex);
+ return mCurrentApi;
+}
+
sp<GraphicBuffer> BufferLayerConsumer::getCurrentBuffer(int* outSlot) const {
Mutex::Autolock lock(mMutex);
diff --git a/services/surfaceflinger/BufferLayerConsumer.h b/services/surfaceflinger/BufferLayerConsumer.h
index f473390..a0272b3 100644
--- a/services/surfaceflinger/BufferLayerConsumer.h
+++ b/services/surfaceflinger/BufferLayerConsumer.h
@@ -138,6 +138,9 @@
// must be called from SF main thread
const Region& getSurfaceDamage() const;
+ // getCurrentApi retrieves the API which queues the current buffer.
+ int getCurrentApi() const;
+
// See GLConsumer::setDefaultBufferSize.
status_t setDefaultBufferSize(uint32_t width, uint32_t height);
@@ -337,6 +340,8 @@
// The portion of this surface that has changed since the previous frame
Region mCurrentSurfaceDamage;
+ int mCurrentApi;
+
uint32_t mDefaultWidth, mDefaultHeight;
// mFilteringEnabled indicates whether the transform matrix is computed for
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index d121a86..cf70529 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -76,7 +76,8 @@
const wp<IBinder>& displayToken,
const sp<DisplaySurface>& displaySurface,
const sp<IGraphicBufferProducer>& producer,
- bool supportWideColor)
+ bool supportWideColor,
+ bool supportHdr)
: lastCompositionHadVisibleLayers(false),
mFlinger(flinger),
mType(type),
@@ -100,6 +101,8 @@
mActiveColorMode = HAL_COLOR_MODE_NATIVE;
mDisplayHasWideColor = supportWideColor;
+ mDisplayHasHdr = supportHdr;
+
/*
* Create our display's surface
*/
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index 499bf8e..a470670 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -78,7 +78,7 @@
const wp<IBinder>& displayToken,
const sp<DisplaySurface>& displaySurface,
const sp<IGraphicBufferProducer>& producer,
- bool supportWideColor);
+ bool supportWideColor, bool supportHdr);
// clang-format on
~DisplayDevice();
@@ -128,6 +128,7 @@
status_t beginFrame(bool mustRecompose) const;
status_t prepareFrame(HWComposer& hwc);
bool getWideColorSupport() const { return mDisplayHasWideColor; }
+ bool getHdrSupport() const { return mDisplayHasHdr; }
void swapBuffers(HWComposer& hwc) const;
@@ -235,6 +236,7 @@
// Initialized by SurfaceFlinger when the DisplayDevice is created.
// Fed to RenderEngine during composition.
bool mDisplayHasWideColor;
+ bool mDisplayHasHdr;
};
struct DisplayDeviceState {
diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.h b/services/surfaceflinger/DisplayHardware/ComposerHal.h
index 104ca60..3d9993e 100644
--- a/services/surfaceflinger/DisplayHardware/ComposerHal.h
+++ b/services/surfaceflinger/DisplayHardware/ComposerHal.h
@@ -25,8 +25,8 @@
#include <android/frameworks/vr/composer/1.0/IVrComposerClient.h>
#include <android/hardware/graphics/composer/2.1/IComposer.h>
+#include <composer-command-buffer/2.1/ComposerCommandBuffer.h>
#include <utils/StrongPointer.h>
-#include <IComposerCommandBuffer.h>
namespace android {
diff --git a/services/surfaceflinger/RenderEngine/Description.cpp b/services/surfaceflinger/RenderEngine/Description.cpp
index 1b5a466..5e79e7a 100644
--- a/services/surfaceflinger/RenderEngine/Description.cpp
+++ b/services/surfaceflinger/RenderEngine/Description.cpp
@@ -61,8 +61,20 @@
return mColorMatrix;
}
-void Description::setWideGamut(bool wideGamut) {
- mIsWideGamut = wideGamut;
+void Description::setY410BT2020(bool enable) {
+ mY410BT2020 = enable;
+}
+
+void Description::setInputTransferFunction(TransferFunction transferFunction) {
+ mInputTransferFunction = transferFunction;
+}
+
+void Description::setOutputTransferFunction(TransferFunction transferFunction) {
+ mOutputTransferFunction = transferFunction;
+}
+
+void Description::enableToneMapping(bool enable) {
+ mToneMappingEnabled = enable;
}
} /* namespace android */
diff --git a/services/surfaceflinger/RenderEngine/Description.h b/services/surfaceflinger/RenderEngine/Description.h
index 1811952..75c1981 100644
--- a/services/surfaceflinger/RenderEngine/Description.h
+++ b/services/surfaceflinger/RenderEngine/Description.h
@@ -32,6 +32,32 @@
* Program and ProgramCache are friends and access the state directly
*/
class Description {
+public:
+ Description() = default;
+ ~Description() = default;
+
+ void setPremultipliedAlpha(bool premultipliedAlpha);
+ void setOpaque(bool opaque);
+ void setTexture(const Texture& texture);
+ void disableTexture();
+ void setColor(const half4& color);
+ void setProjectionMatrix(const mat4& mtx);
+ void setColorMatrix(const mat4& mtx);
+ const mat4& getColorMatrix() const;
+
+ void setY410BT2020(bool enable);
+
+ enum class TransferFunction : int {
+ LINEAR,
+ SRGB,
+ ST2084,
+ };
+ void setInputTransferFunction(TransferFunction transferFunction);
+ void setOutputTransferFunction(TransferFunction transferFunction);
+
+ void enableToneMapping(bool enable);
+
+private:
friend class Program;
friend class ProgramCache;
@@ -52,21 +78,15 @@
bool mColorMatrixEnabled = false;
mat4 mColorMatrix;
- bool mIsWideGamut = false;
+ // true if the sampled pixel values are in Y410/BT2020 rather than RGBA
+ bool mY410BT2020 = false;
-public:
- Description() = default;
- ~Description() = default;
+ // transfer functions for the input/output
+ TransferFunction mInputTransferFunction = TransferFunction::LINEAR;
+ TransferFunction mOutputTransferFunction = TransferFunction::LINEAR;
- void setPremultipliedAlpha(bool premultipliedAlpha);
- void setOpaque(bool opaque);
- void setTexture(const Texture& texture);
- void disableTexture();
- void setColor(const half4& color);
- void setProjectionMatrix(const mat4& mtx);
- void setColorMatrix(const mat4& mtx);
- const mat4& getColorMatrix() const;
- void setWideGamut(bool wideGamut);
+ // tone-map the color
+ bool mToneMappingEnabled = false;
};
} /* namespace android */
diff --git a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp
index d1ee6f8..323cec7 100644
--- a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp
+++ b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp
@@ -130,14 +130,12 @@
// Compute sRGB to DisplayP3 color transform
// NOTE: For now, we are limiting wide-color support to
// Display-P3 only.
- mat3 srgbToP3 =
- ColorSpaceConnector(ColorSpace::sRGB(), ColorSpace::DisplayP3()).getTransform();
+ mSrgbToDisplayP3 = mat4(
+ ColorSpaceConnector(ColorSpace::sRGB(), ColorSpace::DisplayP3()).getTransform());
- // color transform needs to be expanded to 4x4 to be what the shader wants
- // mat has an initializer that expands mat3 to mat4, but
- // not an assignment operator
- mat4 gamutTransform(srgbToP3);
- mSrgbToDisplayP3 = gamutTransform;
+ // Compute BT2020 to DisplayP3 color transform
+ mBt2020ToDisplayP3 = mat4(
+ ColorSpaceConnector(ColorSpace::BT2020(), ColorSpace::DisplayP3()).getTransform());
}
}
@@ -235,6 +233,10 @@
mDataSpace = source;
}
+void GLES20RenderEngine::setSourceY410BT2020(bool enable) {
+ mState.setY410BT2020(enable);
+}
+
void GLES20RenderEngine::setWideColor(bool hasWideColor) {
ALOGV("setWideColor: %s", hasWideColor ? "true" : "false");
mDisplayHasWideColor = hasWideColor;
@@ -324,10 +326,22 @@
if (usesWideColor()) {
Description wideColorState = mState;
- if (mDataSpace != HAL_DATASPACE_DISPLAY_P3) {
- wideColorState.setColorMatrix(mState.getColorMatrix() * mSrgbToDisplayP3);
- wideColorState.setWideGamut(true);
- ALOGV("drawMesh: gamut transform applied");
+ switch (mDataSpace) {
+ case HAL_DATASPACE_DISPLAY_P3:
+ // input matches output
+ break;
+ case HAL_DATASPACE_BT2020_PQ:
+ wideColorState.setColorMatrix(mState.getColorMatrix() * mBt2020ToDisplayP3);
+ wideColorState.setInputTransferFunction(Description::TransferFunction::ST2084);
+ wideColorState.setOutputTransferFunction(Description::TransferFunction::SRGB);
+ wideColorState.enableToneMapping(true);
+ break;
+ default:
+ wideColorState.setColorMatrix(mState.getColorMatrix() * mSrgbToDisplayP3);
+ wideColorState.setInputTransferFunction(Description::TransferFunction::SRGB);
+ wideColorState.setOutputTransferFunction(Description::TransferFunction::SRGB);
+ ALOGV("drawMesh: gamut transform applied");
+ break;
}
ProgramCache::getInstance().useProgram(wideColorState);
diff --git a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h
index 5ee9326..f3af547 100644
--- a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h
+++ b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h
@@ -71,6 +71,7 @@
// Color management related functions and state
void setColorMode(android_color_mode mode);
void setSourceDataSpace(android_dataspace source);
+ void setSourceY410BT2020(bool enable);
void setWideColor(bool hasWideColor);
bool usesWideColor();
@@ -85,8 +86,9 @@
bool mUseWideColor = false;
uint64_t mWideColorFrameCount = 0;
- // Currently only supporting sRGB and DisplayP3 color spaces
+ // Currently only supporting sRGB, BT2020 and DisplayP3 color spaces
mat4 mSrgbToDisplayP3;
+ mat4 mBt2020ToDisplayP3;
bool mPlatformHasWideColor = false;
virtual void setupLayerTexturing(const Texture& texture);
diff --git a/services/surfaceflinger/RenderEngine/ProgramCache.cpp b/services/surfaceflinger/RenderEngine/ProgramCache.cpp
index 3b8ac0e..7a43ea9 100644
--- a/services/surfaceflinger/RenderEngine/ProgramCache.cpp
+++ b/services/surfaceflinger/RenderEngine/ProgramCache.cpp
@@ -126,9 +126,42 @@
.set(Key::OPACITY_MASK,
description.mOpaque ? Key::OPACITY_OPAQUE : Key::OPACITY_TRANSLUCENT)
.set(Key::COLOR_MATRIX_MASK,
- description.mColorMatrixEnabled ? Key::COLOR_MATRIX_ON : Key::COLOR_MATRIX_OFF)
- .set(Key::WIDE_GAMUT_MASK,
- description.mIsWideGamut ? Key::WIDE_GAMUT_ON : Key::WIDE_GAMUT_OFF);
+ description.mColorMatrixEnabled ? Key::COLOR_MATRIX_ON : Key::COLOR_MATRIX_OFF);
+
+ needs.set(Key::Y410_BT2020_MASK,
+ description.mY410BT2020 ? Key::Y410_BT2020_ON : Key::Y410_BT2020_OFF);
+
+ if (needs.hasColorMatrix()) {
+ switch (description.mInputTransferFunction) {
+ case Description::TransferFunction::LINEAR:
+ default:
+ needs.set(Key::INPUT_TF_MASK, Key::INPUT_TF_LINEAR);
+ break;
+ case Description::TransferFunction::SRGB:
+ needs.set(Key::INPUT_TF_MASK, Key::INPUT_TF_SRGB);
+ break;
+ case Description::TransferFunction::ST2084:
+ needs.set(Key::INPUT_TF_MASK, Key::INPUT_TF_ST2084);
+ break;
+ }
+
+ switch (description.mOutputTransferFunction) {
+ case Description::TransferFunction::LINEAR:
+ default:
+ needs.set(Key::OUTPUT_TF_MASK, Key::OUTPUT_TF_LINEAR);
+ break;
+ case Description::TransferFunction::SRGB:
+ needs.set(Key::OUTPUT_TF_MASK, Key::OUTPUT_TF_SRGB);
+ break;
+ case Description::TransferFunction::ST2084:
+ needs.set(Key::OUTPUT_TF_MASK, Key::OUTPUT_TF_ST2084);
+ break;
+ }
+
+ needs.set(Key::TONE_MAPPING_MASK,
+ description.mToneMappingEnabled ? Key::TONE_MAPPING_ON : Key::TONE_MAPPING_OFF);
+ }
+
return needs;
}
@@ -170,56 +203,186 @@
fs << "uniform vec4 color;";
}
+ if (needs.isY410BT2020()) {
+ fs << R"__SHADER__(
+ vec3 convertY410BT2020(const vec3 color) {
+ const vec3 offset = vec3(0.0625, 0.5, 0.5);
+ const mat3 transform = mat3(
+ vec3(1.1678, 1.1678, 1.1678),
+ vec3( 0.0, -0.1878, 2.1481),
+ vec3(1.6836, -0.6523, 0.0));
+ // Y is in G, U is in R, and V is in B
+ return clamp(transform * (color.grb - offset), 0.0, 1.0);
+ }
+ )__SHADER__";
+ }
+
if (needs.hasColorMatrix()) {
fs << "uniform mat4 colorMatrix;";
- }
- if (needs.hasColorMatrix()) {
- // When in wide gamut mode, the color matrix will contain a color space
- // conversion matrix that needs to be applied in linear space
- // When not in wide gamut, we can simply no-op the transfer functions
- // and let the shader compiler get rid of them
- if (needs.isWideGamut()) {
+
+ switch (needs.getInputTF()) {
+ case Key::INPUT_TF_LINEAR:
+ default:
+ fs << R"__SHADER__(
+ vec3 EOTF(const vec3 linear) {
+ return linear;
+ }
+ )__SHADER__";
+ break;
+ case Key::INPUT_TF_SRGB:
+ fs << R"__SHADER__(
+ float EOTF_sRGB(float srgb) {
+ return srgb <= 0.04045 ? srgb / 12.92 : pow((srgb + 0.055) / 1.055, 2.4);
+ }
+
+ vec3 EOTF_sRGB(const vec3 srgb) {
+ return vec3(EOTF_sRGB(srgb.r), EOTF_sRGB(srgb.g), EOTF_sRGB(srgb.b));
+ }
+
+ vec3 EOTF(const vec3 srgb) {
+ return sign(srgb.rgb) * EOTF_sRGB(abs(srgb.rgb));
+ }
+ )__SHADER__";
+ break;
+ case Key::INPUT_TF_ST2084:
+ fs << R"__SHADER__(
+ vec3 EOTF(const highp vec3 color) {
+ const highp float m1 = (2610.0 / 4096.0) / 4.0;
+ const highp float m2 = (2523.0 / 4096.0) * 128.0;
+ const highp float c1 = (3424.0 / 4096.0);
+ const highp float c2 = (2413.0 / 4096.0) * 32.0;
+ const highp float c3 = (2392.0 / 4096.0) * 32.0;
+
+ highp vec3 tmp = pow(color, 1.0 / vec3(m2));
+ tmp = max(tmp - c1, 0.0) / (c2 - c3 * tmp);
+ return pow(tmp, 1.0 / vec3(m1));
+ }
+ )__SHADER__";
+ break;
+ }
+
+ switch (needs.getOutputTF()) {
+ case Key::OUTPUT_TF_LINEAR:
+ default:
+ fs << R"__SHADER__(
+ vec3 OETF(const vec3 linear) {
+ return linear;
+ }
+ )__SHADER__";
+ break;
+ case Key::OUTPUT_TF_SRGB:
+ fs << R"__SHADER__(
+ float OETF_sRGB(const float linear) {
+ return linear <= 0.0031308 ?
+ linear * 12.92 : (pow(linear, 1.0 / 2.4) * 1.055) - 0.055;
+ }
+
+ vec3 OETF_sRGB(const vec3 linear) {
+ return vec3(OETF_sRGB(linear.r), OETF_sRGB(linear.g), OETF_sRGB(linear.b));
+ }
+
+ vec3 OETF(const vec3 linear) {
+ return sign(linear.rgb) * OETF_sRGB(abs(linear.rgb));
+ }
+ )__SHADER__";
+ break;
+ case Key::OUTPUT_TF_ST2084:
+ fs << R"__SHADER__(
+ vec3 OETF(const vec3 linear) {
+ const float m1 = (2610.0 / 4096.0) / 4.0;
+ const float m2 = (2523.0 / 4096.0) * 128.0;
+ const float c1 = (3424.0 / 4096.0);
+ const float c2 = (2413.0 / 4096.0) * 32.0;
+ const float c3 = (2392.0 / 4096.0) * 32.0;
+
+ vec3 tmp = pow(linear, vec3(m1));
+ tmp = (c1 + c2 * tmp) / (1.0 + c3 * tmp);
+ return pow(tmp, vec3(m2));
+ }
+ )__SHADER__";
+ break;
+ }
+
+ if (needs.hasToneMapping()) {
fs << R"__SHADER__(
- float OETF_sRGB(const float linear) {
- return linear <= 0.0031308 ?
- linear * 12.92 : (pow(linear, 1.0 / 2.4) * 1.055) - 0.055;
- }
+ float ToneMapChannel(const float color) {
+ const float maxLumi = 10000.0;
+ const float maxMasteringLumi = 1000.0;
+ const float maxContentLumi = 1000.0;
+ const float maxInLumi = min(maxMasteringLumi, maxContentLumi);
+ const float maxOutLumi = 500.0;
- vec3 OETF_sRGB(const vec3 linear) {
- return vec3(OETF_sRGB(linear.r), OETF_sRGB(linear.g), OETF_sRGB(linear.b));
- }
+ // convert to nits first
+ float nits = color * maxLumi;
- vec3 OETF_scRGB(const vec3 linear) {
- return sign(linear.rgb) * OETF_sRGB(abs(linear.rgb));
- }
+ // clamp to max input luminance
+ nits = clamp(nits, 0.0, maxInLumi);
- float EOTF_sRGB(float srgb) {
- return srgb <= 0.04045 ? srgb / 12.92 : pow((srgb + 0.055) / 1.055, 2.4);
- }
+ // scale [0.0, maxInLumi] to [0.0, maxOutLumi]
+ if (maxInLumi <= maxOutLumi) {
+ nits *= maxOutLumi / maxInLumi;
+ } else {
+ // three control points
+ const float x0 = 10.0;
+ const float y0 = 17.0;
+ const float x1 = maxOutLumi * 0.75;
+ const float y1 = x1;
+ const float x2 = x1 + (maxInLumi - x1) / 2.0;
+ const float y2 = y1 + (maxOutLumi - y1) * 0.75;
- vec3 EOTF_sRGB(const vec3 srgb) {
- return vec3(EOTF_sRGB(srgb.r), EOTF_sRGB(srgb.g), EOTF_sRGB(srgb.b));
- }
+ // horizontal distances between the last three control points
+ const float h12 = x2 - x1;
+ const float h23 = maxInLumi - x2;
+ // tangents at the last three control points
+ const float m1 = (y2 - y1) / h12;
+ const float m3 = (maxOutLumi - y2) / h23;
+ const float m2 = (m1 + m3) / 2.0;
- vec3 EOTF_scRGB(const vec3 srgb) {
- return sign(srgb.rgb) * EOTF_sRGB(abs(srgb.rgb));
- }
+ if (nits < x0) {
+ // scale [0.0, x0] to [0.0, y0] linearly
+ const float slope = y0 / x0;
+ nits *= slope;
+ } else if (nits < x1) {
+ // scale [x0, x1] to [y0, y1] linearly
+ const float slope = (y1 - y0) / (x1 - x0);
+ nits = y0 + (nits - x0) * slope;
+ } else if (nits < x2) {
+ // scale [x1, x2] to [y1, y2] using Hermite interp
+ float t = (nits - x1) / h12;
+ nits = (y1 * (1.0 + 2.0 * t) + h12 * m1 * t) * (1.0 - t) * (1.0 - t) +
+ (y2 * (3.0 - 2.0 * t) + h12 * m2 * (t - 1.0)) * t * t;
+ } else {
+ // scale [x2, maxInLumi] to [y2, maxOutLumi] using Hermite interp
+ float t = (nits - x2) / h23;
+ nits = (y2 * (1.0 + 2.0 * t) + h23 * m2 * t) * (1.0 - t) * (1.0 - t) +
+ (maxOutLumi * (3.0 - 2.0 * t) + h23 * m3 * (t - 1.0)) * t * t;
+ }
+ }
+
+ // convert back to [0.0, 1.0]
+ return nits / maxOutLumi;
+ }
+
+ vec3 ToneMap(const vec3 color) {
+ return vec3(ToneMapChannel(color.r), ToneMapChannel(color.g),
+ ToneMapChannel(color.b));
+ }
)__SHADER__";
} else {
fs << R"__SHADER__(
- vec3 OETF_scRGB(const vec3 linear) {
- return linear;
- }
-
- vec3 EOTF_scRGB(const vec3 srgb) {
- return srgb;
- }
+ vec3 ToneMap(const vec3 color) {
+ return color;
+ }
)__SHADER__";
}
}
+
fs << "void main(void) {" << indent;
if (needs.isTexturing()) {
fs << "gl_FragColor = texture2D(sampler, outTexCoords);";
+ if (needs.isY410BT2020()) {
+ fs << "gl_FragColor.rgb = convertY410BT2020(gl_FragColor.rgb);";
+ }
} else {
fs << "gl_FragColor.rgb = color.rgb;";
fs << "gl_FragColor.a = 1.0;";
@@ -243,9 +406,12 @@
// avoid divide by 0 by adding 0.5/256 to the alpha channel
fs << "gl_FragColor.rgb = gl_FragColor.rgb / (gl_FragColor.a + 0.0019);";
}
- fs << "vec4 transformed = colorMatrix * vec4(EOTF_scRGB(gl_FragColor.rgb), 1);";
+ fs << "vec4 transformed = colorMatrix * vec4(ToneMap(EOTF(gl_FragColor.rgb)), 1);";
+ // the transformation from a wider colorspace to a narrower one can
+ // result in >1.0 or <0.0 pixel values
+ fs << "transformed.rgb = clamp(transformed.rgb, 0.0, 1.0);";
// We assume the last row is always {0,0,0,1} and we skip the division by w
- fs << "gl_FragColor.rgb = OETF_scRGB(transformed.rgb);";
+ fs << "gl_FragColor.rgb = OETF(transformed.rgb);";
if (!needs.isOpaque() && needs.isPremultiplied()) {
// and re-premultiply if needed after gamma correction
fs << "gl_FragColor.rgb = gl_FragColor.rgb * (gl_FragColor.a + 0.0019);";
diff --git a/services/surfaceflinger/RenderEngine/ProgramCache.h b/services/surfaceflinger/RenderEngine/ProgramCache.h
index 54d3722..dcc8cc6 100644
--- a/services/surfaceflinger/RenderEngine/ProgramCache.h
+++ b/services/surfaceflinger/RenderEngine/ProgramCache.h
@@ -50,30 +50,53 @@
public:
enum {
- BLEND_PREMULT = 0x00000001,
- BLEND_NORMAL = 0x00000000,
- BLEND_MASK = 0x00000001,
+ BLEND_SHIFT = 0,
+ BLEND_MASK = 1 << BLEND_SHIFT,
+ BLEND_PREMULT = 1 << BLEND_SHIFT,
+ BLEND_NORMAL = 0 << BLEND_SHIFT,
- OPACITY_OPAQUE = 0x00000002,
- OPACITY_TRANSLUCENT = 0x00000000,
- OPACITY_MASK = 0x00000002,
+ OPACITY_SHIFT = 1,
+ OPACITY_MASK = 1 << OPACITY_SHIFT,
+ OPACITY_OPAQUE = 1 << OPACITY_SHIFT,
+ OPACITY_TRANSLUCENT = 0 << OPACITY_SHIFT,
- ALPHA_LT_ONE = 0x00000004,
- ALPHA_EQ_ONE = 0x00000000,
- ALPHA_MASK = 0x00000004,
+ ALPHA_SHIFT = 2,
+ ALPHA_MASK = 1 << ALPHA_SHIFT,
+ ALPHA_LT_ONE = 1 << ALPHA_SHIFT,
+ ALPHA_EQ_ONE = 0 << ALPHA_SHIFT,
- TEXTURE_OFF = 0x00000000,
- TEXTURE_EXT = 0x00000008,
- TEXTURE_2D = 0x00000010,
- TEXTURE_MASK = 0x00000018,
+ TEXTURE_SHIFT = 3,
+ TEXTURE_MASK = 3 << TEXTURE_SHIFT,
+ TEXTURE_OFF = 0 << TEXTURE_SHIFT,
+ TEXTURE_EXT = 1 << TEXTURE_SHIFT,
+ TEXTURE_2D = 2 << TEXTURE_SHIFT,
- COLOR_MATRIX_OFF = 0x00000000,
- COLOR_MATRIX_ON = 0x00000020,
- COLOR_MATRIX_MASK = 0x00000020,
+ COLOR_MATRIX_SHIFT = 5,
+ COLOR_MATRIX_MASK = 1 << COLOR_MATRIX_SHIFT,
+ COLOR_MATRIX_OFF = 0 << COLOR_MATRIX_SHIFT,
+ COLOR_MATRIX_ON = 1 << COLOR_MATRIX_SHIFT,
- WIDE_GAMUT_OFF = 0x00000000,
- WIDE_GAMUT_ON = 0x00000040,
- WIDE_GAMUT_MASK = 0x00000040,
+ INPUT_TF_SHIFT = 6,
+ INPUT_TF_MASK = 3 << INPUT_TF_SHIFT,
+ INPUT_TF_LINEAR = 0 << INPUT_TF_SHIFT,
+ INPUT_TF_SRGB = 1 << INPUT_TF_SHIFT,
+ INPUT_TF_ST2084 = 2 << INPUT_TF_SHIFT,
+
+ OUTPUT_TF_SHIFT = 8,
+ OUTPUT_TF_MASK = 3 << OUTPUT_TF_SHIFT,
+ OUTPUT_TF_LINEAR = 0 << OUTPUT_TF_SHIFT,
+ OUTPUT_TF_SRGB = 1 << OUTPUT_TF_SHIFT,
+ OUTPUT_TF_ST2084 = 2 << OUTPUT_TF_SHIFT,
+
+ TONE_MAPPING_SHIFT = 10,
+ TONE_MAPPING_MASK = 1 << TONE_MAPPING_SHIFT,
+ TONE_MAPPING_OFF = 0 << TONE_MAPPING_SHIFT,
+ TONE_MAPPING_ON = 1 << TONE_MAPPING_SHIFT,
+
+ Y410_BT2020_SHIFT = 11,
+ Y410_BT2020_MASK = 1 << Y410_BT2020_SHIFT,
+ Y410_BT2020_OFF = 0 << Y410_BT2020_SHIFT,
+ Y410_BT2020_ON = 1 << Y410_BT2020_SHIFT,
};
inline Key() : mKey(0) {}
@@ -90,7 +113,10 @@
inline bool isOpaque() const { return (mKey & OPACITY_MASK) == OPACITY_OPAQUE; }
inline bool hasAlpha() const { return (mKey & ALPHA_MASK) == ALPHA_LT_ONE; }
inline bool hasColorMatrix() const { return (mKey & COLOR_MATRIX_MASK) == COLOR_MATRIX_ON; }
- inline bool isWideGamut() const { return (mKey & WIDE_GAMUT_MASK) == WIDE_GAMUT_ON; }
+ inline int getInputTF() const { return (mKey & INPUT_TF_MASK); }
+ inline int getOutputTF() const { return (mKey & OUTPUT_TF_MASK); }
+ inline bool hasToneMapping() const { return (mKey & TONE_MAPPING_MASK) == TONE_MAPPING_ON; }
+ inline bool isY410BT2020() const { return (mKey & Y410_BT2020_MASK) == Y410_BT2020_ON; }
// this is the definition of a friend function -- not a method of class Needs
friend inline int strictly_order_type(const Key& lhs, const Key& rhs) {
diff --git a/services/surfaceflinger/RenderEngine/RenderEngine.h b/services/surfaceflinger/RenderEngine/RenderEngine.h
index 737b1dd..67c0d1c 100644
--- a/services/surfaceflinger/RenderEngine/RenderEngine.h
+++ b/services/surfaceflinger/RenderEngine/RenderEngine.h
@@ -138,6 +138,7 @@
const half4& color) = 0;
virtual void setColorMode(android_color_mode mode) = 0;
virtual void setSourceDataSpace(android_dataspace source) = 0;
+ virtual void setSourceY410BT2020(bool enable) = 0;
virtual void setWideColor(bool hasWideColor) = 0;
virtual bool usesWideColor() = 0;
virtual void setupLayerTexturing(const Texture& texture) = 0;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index a91525d..974a261 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -1041,7 +1041,19 @@
std::unique_ptr<HdrCapabilities> capabilities =
getBE().mHwc->getHdrCapabilities(displayDevice->getHwcDisplayId());
if (capabilities) {
- std::swap(*outCapabilities, *capabilities);
+ if (displayDevice->getWideColorSupport() && !displayDevice->getHdrSupport()) {
+ // insert HDR10 as we will force client composition for HDR10
+ // layers
+ std::vector<int32_t> types = capabilities->getSupportedHdrTypes();
+ types.push_back(HAL_HDR_HDR10);
+
+ *outCapabilities = HdrCapabilities(types,
+ capabilities->getDesiredMaxLuminance(),
+ capabilities->getDesiredMaxAverageLuminance(),
+ capabilities->getDesiredMinLuminance());
+ } else {
+ *outCapabilities = std::move(*capabilities);
+ }
} else {
return BAD_VALUE;
}
@@ -1793,7 +1805,7 @@
}
android_dataspace SurfaceFlinger::bestTargetDataSpace(
- android_dataspace a, android_dataspace b) const {
+ android_dataspace a, android_dataspace b, bool hasHdr) const {
// Only support sRGB and Display-P3 right now.
if (a == HAL_DATASPACE_DISPLAY_P3 || b == HAL_DATASPACE_DISPLAY_P3) {
return HAL_DATASPACE_DISPLAY_P3;
@@ -1804,6 +1816,9 @@
if (a == HAL_DATASPACE_V0_SCRGB || b == HAL_DATASPACE_V0_SCRGB) {
return HAL_DATASPACE_DISPLAY_P3;
}
+ if (!hasHdr && (a == HAL_DATASPACE_BT2020_PQ || b == HAL_DATASPACE_BT2020_PQ)) {
+ return HAL_DATASPACE_DISPLAY_P3;
+ }
return HAL_DATASPACE_V0_SRGB;
}
@@ -1885,6 +1900,11 @@
"display %zd: %d", displayId, result);
}
for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) {
+ if (layer->getDataSpace() == HAL_DATASPACE_BT2020_PQ &&
+ !displayDevice->getHdrSupport()) {
+ layer->forceClientComposition(hwcId);
+ }
+
if (layer->getForceClientComposition(hwcId)) {
ALOGV("[%s] Requesting Client composition", layer->getName().string());
layer->setCompositionType(hwcId, HWC2::Composition::Client);
@@ -1899,7 +1919,8 @@
android_dataspace newDataSpace = HAL_DATASPACE_V0_SRGB;
for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) {
- newDataSpace = bestTargetDataSpace(layer->getDataSpace(), newDataSpace);
+ newDataSpace = bestTargetDataSpace(layer->getDataSpace(), newDataSpace,
+ displayDevice->getHdrSupport());
ALOGV("layer: %s, dataspace: %s (%#x), newDataSpace: %s (%#x)",
layer->getName().string(), dataspaceDetails(layer->getDataSpace()).c_str(),
layer->getDataSpace(), dataspaceDetails(newDataSpace).c_str(), newDataSpace);
@@ -2253,9 +2274,19 @@
useWideColorMode = hasWideColorModes && hasWideColorDisplay;
}
+ bool hasHdrSupport = false;
+ std::unique_ptr<HdrCapabilities> hdrCapabilities =
+ getHwComposer().getHdrCapabilities(state.type);
+ if (hdrCapabilities) {
+ const std::vector<int32_t> types = hdrCapabilities->getSupportedHdrTypes();
+ auto iter = std::find(types.cbegin(), types.cend(), HAL_HDR_HDR10);
+ hasHdrSupport = iter != types.cend();
+ }
+
sp<DisplayDevice> hw =
new DisplayDevice(this, state.type, hwcId, state.isSecure, display,
- dispSurface, producer, useWideColorMode);
+ dispSurface, producer, useWideColorMode,
+ hasHdrSupport);
android_color_mode defaultColorMode = HAL_COLOR_MODE_NATIVE;
if (useWideColorMode) {
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 4da0803..1349bec 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -607,7 +607,8 @@
// Given a dataSpace, returns the appropriate color_mode to use
// to display that dataSpace.
android_color_mode pickColorMode(android_dataspace dataSpace) const;
- android_dataspace bestTargetDataSpace(android_dataspace a, android_dataspace b) const;
+ android_dataspace bestTargetDataSpace(android_dataspace a, android_dataspace b,
+ bool hasHdr) const;
mat4 computeSaturationMatrix() const;
diff --git a/services/surfaceflinger/tests/fakehwc/Android.bp b/services/surfaceflinger/tests/fakehwc/Android.bp
index 47c4f4a..eeb0f54 100644
--- a/services/surfaceflinger/tests/fakehwc/Android.bp
+++ b/services/surfaceflinger/tests/fakehwc/Android.bp
@@ -31,6 +31,9 @@
"libtrace_proto",
"libgmock"
],
+ header_libs: [
+ "android.hardware.graphics.composer@2.1-command-buffer",
+ ],
cppflags: [
"-std=c++1z",
],
diff --git a/services/vr/hardware_composer/Android.bp b/services/vr/hardware_composer/Android.bp
index 76ec42d..063d83c 100644
--- a/services/vr/hardware_composer/Android.bp
+++ b/services/vr/hardware_composer/Android.bp
@@ -32,6 +32,10 @@
"libutils",
],
+ header_libs: [
+ "android.hardware.graphics.composer@2.1-command-buffer",
+ ],
+
export_static_lib_headers: [
"libhwcomposer-client",
],
diff --git a/services/vr/hardware_composer/impl/vr_composer_client.h b/services/vr/hardware_composer/impl/vr_composer_client.h
index dfc656a..63ee86f 100644
--- a/services/vr/hardware_composer/impl/vr_composer_client.h
+++ b/services/vr/hardware_composer/impl/vr_composer_client.h
@@ -17,9 +17,9 @@
#ifndef ANDROID_DVR_HARDWARE_COMPOSER_IMPL_VR_COMPOSER_CLIENT_H
#define ANDROID_DVR_HARDWARE_COMPOSER_IMPL_VR_COMPOSER_CLIENT_H
-#include <android/frameworks/vr/composer/1.0/IVrComposerClient.h>
#include <ComposerClient.h>
-#include <IComposerCommandBuffer.h>
+#include <android/frameworks/vr/composer/1.0/IVrComposerClient.h>
+#include <composer-command-buffer/2.1/ComposerCommandBuffer.h>
namespace android {
namespace dvr {