Merge "Delete RenderEngine path for OpenGL ES 1.0/1.1"
diff --git a/cmds/atrace/atrace.rc b/cmds/atrace/atrace.rc
index f3b12b1..d486a3d 100644
--- a/cmds/atrace/atrace.rc
+++ b/cmds/atrace/atrace.rc
@@ -1,6 +1,6 @@
## Permissions to allow system-wide tracing to the kernel trace buffer.
##
-on boot
+on fs
# Allow writing to the kernel trace log.
chmod 0222 /sys/kernel/debug/tracing/trace_marker
diff --git a/cmds/cmd/cmd.cpp b/cmds/cmd/cmd.cpp
index 443511e..73d274f 100644
--- a/cmds/cmd/cmd.cpp
+++ b/cmds/cmd/cmd.cpp
@@ -23,6 +23,8 @@
#include <binder/IServiceManager.h>
#include <binder/IShellCallback.h>
#include <binder/TextOutput.h>
+#include <utils/Condition.h>
+#include <utils/Mutex.h>
#include <utils/Vector.h>
#include <getopt.h>
@@ -39,6 +41,8 @@
#include <UniquePtr.h>
+#define DEBUG 0
+
using namespace android;
static int sort_func(const String16* lhs, const String16* rhs)
@@ -94,7 +98,24 @@
class MyResultReceiver : public BnResultReceiver
{
public:
- virtual void send(int32_t /*resultCode*/) {
+ Mutex mMutex;
+ Condition mCondition;
+ bool mHaveResult = false;
+ int32_t mResult = 0;
+
+ virtual void send(int32_t resultCode) {
+ AutoMutex _l(mMutex);
+ mResult = resultCode;
+ mHaveResult = true;
+ mCondition.signal();
+ }
+
+ int32_t waitForResult() {
+ AutoMutex _l(mMutex);
+ while (!mHaveResult) {
+ mCondition.wait(mMutex);
+ }
+ return mResult;
}
};
@@ -107,13 +128,13 @@
sp<IServiceManager> sm = defaultServiceManager();
fflush(stdout);
if (sm == NULL) {
- ALOGE("Unable to get default service manager!");
+ ALOGW("Unable to get default service manager!");
aerr << "cmd: Unable to get default service manager!" << endl;
return 20;
}
if (argc == 1) {
- aout << "cmd: no service specified; use -l to list all services" << endl;
+ aerr << "cmd: No service specified; use -l to list all services" << endl;
return 20;
}
@@ -138,17 +159,41 @@
String16 cmd = String16(argv[1]);
sp<IBinder> service = sm->checkService(cmd);
if (service == NULL) {
- aerr << "Can't find service: " << argv[1] << endl;
+ ALOGW("Can't find service %s", argv[1]);
+ aerr << "cmd: Can't find service: " << argv[1] << endl;
return 20;
}
sp<MyShellCallback> cb = new MyShellCallback();
+ sp<MyResultReceiver> result = new MyResultReceiver();
+
+#if DEBUG
+ ALOGD("cmd: Invoking %s in=%d, out=%d, err=%d", argv[1], STDIN_FILENO, STDOUT_FILENO,
+ STDERR_FILENO);
+#endif
// TODO: block until a result is returned to MyResultReceiver.
- IBinder::shellCommand(service, STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO, args,
- cb, new MyResultReceiver());
+ status_t err = IBinder::shellCommand(service, STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO, args,
+ cb, result);
+ if (err < 0) {
+ const char* errstr;
+ switch (err) {
+ case BAD_TYPE: errstr = "Bad type"; break;
+ case FAILED_TRANSACTION: errstr = "Failed transaction"; break;
+ case FDS_NOT_ALLOWED: errstr = "File descriptors not allowed"; break;
+ case UNEXPECTED_NULL: errstr = "Unexpected null"; break;
+ default: errstr = strerror(-err); break;
+ }
+ ALOGW("Failure calling service %s: %s (%d)", argv[1], errstr, -err);
+ aout << "cmd: Failure calling service " << argv[1] << ": " << errstr << " ("
+ << (-err) << ")" << endl;
+ return err;
+ }
cb->mActive = false;
-
- return 0;
+ status_t res = result->waitForResult();
+#if DEBUG
+ ALOGD("result=%d", (int)res);
+#endif
+ return res;
}
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 32dbf8d..a48f112 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -56,18 +56,10 @@
static char cmdline_buf[16384] = "(unknown)";
static const char *dump_traces_path = NULL;
-// Command-line arguments as string
-static std::string args;
-
// TODO: variables below should be part of dumpstate object
-static time_t now;
static std::unique_ptr<ZipWriter> zip_writer;
static std::set<std::string> mount_points;
void add_mountinfo();
-/* suffix of the bugreport files - it's typically the date (when invoked with -d),
- * although it could be changed by the user using a system property */
-static std::string suffix;
-static std::string extraOptions;
#define PSTORE_LAST_KMSG "/sys/fs/pstore/console-ramoops"
#define ALT_PSTORE_LAST_KMSG "/sys/fs/pstore/console-ramoops-0"
@@ -111,13 +103,6 @@
return ds.IsUserBuild();
}
-/*
- * List of supported zip format versions.
- *
- * See bugreport-format.md for more info.
- */
-static std::string VERSION_DEFAULT = "1.0";
-
// Relative directory (inside the zip) for all files copied as-is into the bugreport.
static const std::string ZIP_ROOT_DIR = "FS";
@@ -127,7 +112,7 @@
/* gets the tombstone data, according to the bugreport type: if zipped, gets all tombstones;
* otherwise, gets just those modified in the last half an hour. */
static void get_tombstone_fds(tombstone_data_t data[NUM_TOMBSTONES]) {
- time_t thirty_minutes_ago = now - 60*30;
+ time_t thirty_minutes_ago = ds.now_ - 60 * 30;
for (size_t i = 0; i < NUM_TOMBSTONES; i++) {
snprintf(data[i].name, sizeof(data[i].name), "%s%02zu", TOMBSTONE_FILE_PREFIX, i);
int fd = TEMP_FAILURE_RETRY(open(data[i].name,
@@ -336,7 +321,7 @@
MYLOGD("Not dumping systrace because zip_writer is not set\n");
return;
}
- std::string systrace_path = ds.bugreportDir_ + "/systrace-" + suffix + ".txt";
+ std::string systrace_path = ds.GetPath("-systrace.txt");
if (systrace_path.empty()) {
MYLOGE("Not dumping systrace because path is empty\n");
return;
@@ -377,7 +362,7 @@
return;
}
- std::string raft_log_path = ds.bugreportDir_ + "/raft_log.txt";
+ std::string raft_log_path = ds.GetPath("-raft_log.txt");
if (raft_log_path.empty()) {
MYLOGD("raft_log_path is empty\n");
return;
@@ -686,8 +671,8 @@
/* End copy from system/core/logd/LogBuffer.cpp */
-/* dumps the current system state to stdout */
-void print_header(const std::string& version) {
+// TODO: move to utils.cpp
+void Dumpstate::PrintHeader() {
std::string build, fingerprint, radio, bootloader, network;
char date[80];
@@ -696,7 +681,7 @@
radio = android::base::GetProperty("gsm.version.baseband", "(unknown)");
bootloader = android::base::GetProperty("ro.bootloader", "(unknown)");
network = android::base::GetProperty("gsm.operator.alpha", "(unknown)");
- strftime(date, sizeof(date), "%Y-%m-%d %H:%M:%S", localtime(&now));
+ strftime(date, sizeof(date), "%Y-%m-%d %H:%M:%S", localtime(&now_));
printf("========================================================\n");
printf("== dumpstate: %s\n", date);
@@ -713,9 +698,9 @@
printf("Kernel: ");
DumpFile("", "/proc/version");
printf("Command line: %s\n", strtok(cmdline_buf, "\n"));
- printf("Bugreport format version: %s\n", version.c_str());
- printf("Dumpstate info: id=%lu pid=%d dryRun=%d args=%s extraOptions=%s\n", ds.id_, getpid(),
- ds.IsDryRun(), args.c_str(), extraOptions.c_str());
+ printf("Bugreport format version: %s\n", version_.c_str());
+ printf("Dumpstate info: id=%lu pid=%d dryRun=%d args=%s extraOptions=%s\n", id_, getpid(),
+ dryRun_, args_.c_str(), extraOptions_.c_str());
printf("\n");
}
@@ -748,8 +733,8 @@
// Logging statement below is useful to time how long each entry takes, but it's too verbose.
// MYLOGD("Adding zip entry %s\n", entry_name.c_str());
- int32_t err = zip_writer->StartEntryWithTime(valid_name.c_str(),
- ZipWriter::kCompress, get_mtime(fd, now));
+ int32_t err = zip_writer->StartEntryWithTime(valid_name.c_str(), ZipWriter::kCompress,
+ get_mtime(fd, ds.now_));
if (err) {
MYLOGE("zip_writer->StartEntryWithTime(%s): %s\n", valid_name.c_str(),
ZipWriter::ErrorCodeString(err));
@@ -815,7 +800,7 @@
return false;
}
MYLOGD("Adding zip text entry %s\n", entry_name.c_str());
- int32_t err = zip_writer->StartEntryWithTime(entry_name.c_str(), ZipWriter::kCompress, now);
+ int32_t err = zip_writer->StartEntryWithTime(entry_name.c_str(), ZipWriter::kCompress, ds.now_);
if (err) {
MYLOGE("zip_writer->StartEntryWithTime(%s): %s\n", entry_name.c_str(),
ZipWriter::ErrorCodeString(err));
@@ -849,8 +834,7 @@
RunCommand("IP6TABLES RAW", {"ip6tables", "-t", "raw", "-L", "-nvx"});
}
-static void dumpstate(const std::string& screenshot_path,
- const std::string& version __attribute__((unused))) {
+static void dumpstate() {
DurationReporter durationReporter("DUMPSTATE");
unsigned long timeout;
@@ -897,10 +881,9 @@
/* Dump Bluetooth HCI logs */
add_dir("/data/misc/bluetooth/logs", true);
- if (!screenshot_path.empty()) {
+ if (!ds.doEarlyScreenshot_) {
MYLOGI("taking late screenshot\n");
- take_screenshot(screenshot_path);
- MYLOGI("wrote screenshot: %s\n", screenshot_path.c_str());
+ ds.TakeScreenshot();
}
// DumpFile("EVENT LOG TAGS", "/etc/event-log-tags");
@@ -1147,7 +1130,7 @@
static void ShowUsageAndExit(int exitCode = 1) {
fprintf(stderr,
- "usage: dumpstate [-h] [-b soundfile] [-e soundfile] [-o file [-d] [-p] "
+ "usage: dumpstate [-h] [-b soundfile] [-e soundfile] [-o file] [-d] [-p] "
"[-z]] [-s] [-S] [-q] [-B] [-P] [-R] [-V version]\n"
" -h: display this help message\n"
" -b: play sound file instead of vibrate, at beginning of job\n"
@@ -1203,13 +1186,13 @@
temporary file.
*/
static bool finish_zip_file(const std::string& bugreport_name, const std::string& bugreport_path,
- const std::string& log_path, time_t now) {
+ const std::string& log_path) {
// Final timestamp
char date[80];
time_t the_real_now_please_stand_up = time(nullptr);
strftime(date, sizeof(date), "%Y/%m/%d %H:%M:%S", localtime(&the_real_now_please_stand_up));
MYLOGD("dumpstate id %lu finished around %s (%ld s)\n", ds.id_, date,
- the_real_now_please_stand_up - now);
+ the_real_now_please_stand_up - ds.now_);
if (!add_zip_entry(bugreport_name, bugreport_path)) {
MYLOGE("Failed to add text entry to .zip file\n");
@@ -1292,11 +1275,7 @@
int use_control_socket = 0;
int do_fb = 0;
int do_broadcast = 0;
- int do_early_screenshot = 0;
int is_remote_mode = 0;
- std::string version = VERSION_DEFAULT;
-
- now = time(nullptr);
MYLOGI("begin\n");
@@ -1314,14 +1293,14 @@
// TODO: use helper function to convert argv into a string
for (int i = 0; i < argc; i++) {
- args += argv[i];
+ ds.args_ += argv[i];
if (i < argc - 1) {
- args += " ";
+ ds.args_ += " ";
}
}
- extraOptions = android::base::GetProperty(PROPERTY_EXTRA_OPTIONS, "");
- MYLOGI("Dumpstate args: %s (extra options: %s)\n", args.c_str(), extraOptions.c_str());
+ ds.extraOptions_ = android::base::GetProperty(PROPERTY_EXTRA_OPTIONS, "");
+ MYLOGI("Dumpstate args: %s (extra options: %s)\n", ds.args_.c_str(), ds.extraOptions_.c_str());
/* gets the sequential id */
int lastId = android::base::GetIntProperty(PROPERTY_LAST_ID, 0);
@@ -1350,18 +1329,18 @@
while ((c = getopt(argc, argv, "dho:svqzpPBRSV:")) != -1) {
switch (c) {
// clang-format off
- case 'd': do_add_date = 1; break;
- case 'z': do_zip_file = 1; break;
- case 'o': use_outfile = optarg; break;
- case 's': use_socket = 1; break;
- case 'S': use_control_socket = 1; break;
- case 'v': break; // compatibility no-op
- case 'q': do_vibrate = 0; break;
- case 'p': do_fb = 1; break;
- case 'P': ds.updateProgress_ = 1; break;
- case 'R': is_remote_mode = 1; break;
- case 'B': do_broadcast = 1; break;
- case 'V': version = optarg; break;
+ case 'd': do_add_date = 1; break;
+ case 'z': do_zip_file = 1; break;
+ case 'o': use_outfile = optarg; break;
+ case 's': use_socket = 1; break;
+ case 'S': use_control_socket = 1; break;
+ case 'v': break; // compatibility no-op
+ case 'q': do_vibrate = 0; break;
+ case 'p': do_fb = 1; break;
+ case 'P': ds.updateProgress_ = true; break;
+ case 'R': is_remote_mode = 1; break;
+ case 'B': do_broadcast = 1; break;
+ case 'V': ds.version_ = optarg; break;
case 'h':
ShowUsageAndExit(0);
break;
@@ -1372,23 +1351,23 @@
}
}
- if (!extraOptions.empty()) {
+ if (!ds.extraOptions_.empty()) {
// Framework uses a system property to override some command-line args.
// Currently, it contains the type of the requested bugreport.
- if (extraOptions == "bugreportplus") {
+ if (ds.extraOptions_ == "bugreportplus") {
MYLOGD("Running as bugreportplus: add -P, remove -p\n");
- ds.updateProgress_ = 1;
+ ds.updateProgress_ = true;
do_fb = 0;
- } else if (extraOptions == "bugreportremote") {
+ } else if (ds.extraOptions_ == "bugreportremote") {
MYLOGD("Running as bugreportremote: add -q -R, remove -p\n");
do_vibrate = 0;
is_remote_mode = 1;
do_fb = 0;
- } else if (extraOptions == "bugreportwear") {
+ } else if (ds.extraOptions_ == "bugreportwear") {
MYLOGD("Running as bugreportwear: add -P\n");
- ds.updateProgress_ = 1;
+ ds.updateProgress_ = true;
} else {
- MYLOGE("Unknown extra option: %s\n", extraOptions.c_str());
+ MYLOGE("Unknown extra option: %s\n", ds.extraOptions_.c_str());
}
// Reset the property
android::base::SetProperty(PROPERTY_EXTRA_OPTIONS, "");
@@ -1410,13 +1389,13 @@
ExitOnInvalidArgs();
}
- if (version != VERSION_DEFAULT) {
+ if (ds.version_ != VERSION_DEFAULT) {
ShowUsageAndExit();
}
- MYLOGI("bugreport format version: %s\n", version.c_str());
+ MYLOGI("bugreport format version: %s\n", ds.version_.c_str());
- do_early_screenshot = ds.updateProgress_;
+ ds.doEarlyScreenshot_ = ds.updateProgress_;
// If we are going to use a socket, do it as early as possible
// to avoid timeouts from bugreport.
@@ -1436,15 +1415,6 @@
/* full path of the file containing the dumpstate logs */
std::string log_path;
- /* full path of the systrace file, when enabled */
- std::string systrace_path;
-
- /* full path of the temporary file containing the screenshot (when requested) */
- std::string screenshot_path;
-
- /* base name (without suffix or extensions) of the bugreport files */
- std::string base_name;
-
/* pointer to the actual path, be it zip or text */
std::string path;
@@ -1456,25 +1426,21 @@
if (is_redirecting) {
ds.bugreportDir_ = dirname(use_outfile);
- base_name = basename(use_outfile);
+ ds.baseName_ = basename(use_outfile);
if (do_add_date) {
char date[80];
- strftime(date, sizeof(date), "%Y-%m-%d-%H-%M-%S", localtime(&now));
- suffix = date;
+ strftime(date, sizeof(date), "%Y-%m-%d-%H-%M-%S", localtime(&ds.now_));
+ ds.suffix_ = date;
} else {
- suffix = "undated";
+ ds.suffix_ = "undated";
}
std::string buildId = android::base::GetProperty("ro.build.id", "UNKNOWN_BUILD");
- base_name = base_name + "-" + buildId;
+ ds.baseName_ = ds.baseName_ + "-" + buildId;
if (do_fb) {
- // TODO: if dumpstate was an object, the paths could be internal variables and then
- // we could have a function to calculate the derived values, such as:
- // screenshot_path = GetPath(".png");
- screenshot_path = ds.bugreportDir_ + "/" + base_name + "-" + suffix + ".png";
+ ds.screenshotPath_ = ds.GetPath(".png");
}
- tmp_path = ds.bugreportDir_ + "/" + base_name + "-" + suffix + ".tmp";
- log_path =
- ds.bugreportDir_ + "/dumpstate_log-" + suffix + "-" + std::to_string(getpid()) + ".txt";
+ tmp_path = ds.GetPath(".tmp");
+ log_path = ds.GetPath("-dumpstate_log-" + std::to_string(getpid()) + ".txt");
MYLOGD(
"Bugreport dir: %s\n"
@@ -1483,11 +1449,11 @@
"Log path: %s\n"
"Temporary path: %s\n"
"Screenshot path: %s\n",
- ds.bugreportDir_.c_str(), base_name.c_str(), suffix.c_str(), log_path.c_str(),
- tmp_path.c_str(), screenshot_path.c_str());
+ ds.bugreportDir_.c_str(), ds.baseName_.c_str(), ds.suffix_.c_str(), log_path.c_str(),
+ tmp_path.c_str(), ds.screenshotPath_.c_str());
if (do_zip_file) {
- path = ds.bugreportDir_ + "/" + base_name + "-" + suffix + ".zip";
+ path = ds.GetPath(".zip");
MYLOGD("Creating initial .zip file (%s)\n", path.c_str());
create_parent_dirs(path.c_str());
zip_file.reset(fopen(path.c_str(), "wb"));
@@ -1497,7 +1463,7 @@
} else {
zip_writer.reset(new ZipWriter(zip_file.get()));
}
- add_text_zip_entry("version.txt", version);
+ add_text_zip_entry("version.txt", ds.version_);
}
if (ds.updateProgress_) {
@@ -1505,7 +1471,7 @@
// clang-format off
std::vector<std::string> am_args = {
"--receiver-permission", "android.permission.DUMP", "--receiver-foreground",
- "--es", "android.intent.extra.NAME", suffix,
+ "--es", "android.intent.extra.NAME", ds.suffix_,
"--ei", "android.intent.extra.ID", std::to_string(ds.id_),
"--ei", "android.intent.extra.PID", std::to_string(getpid()),
"--ei", "android.intent.extra.MAX", std::to_string(WEIGHT_TOTAL),
@@ -1535,18 +1501,13 @@
}
}
- if (do_fb && do_early_screenshot) {
- if (screenshot_path.empty()) {
+ if (do_fb && ds.doEarlyScreenshot_) {
+ if (ds.screenshotPath_.empty()) {
// should not have happened
MYLOGE("INTERNAL ERROR: skipping early screenshot because path was not set\n");
} else {
MYLOGI("taking early screenshot\n");
- take_screenshot(screenshot_path);
- MYLOGI("wrote screenshot: %s\n", screenshot_path.c_str());
- if (chown(screenshot_path.c_str(), AID_SHELL, AID_SHELL)) {
- MYLOGE("Unable to change ownership of screenshot file %s: %s\n",
- screenshot_path.c_str(), strerror(errno));
- }
+ ds.TakeScreenshot();
}
}
@@ -1574,7 +1535,7 @@
// NOTE: there should be no stdout output until now, otherwise it would break the header.
// In particular, DurationReport objects should be created passing 'title, NULL', so their
// duration is logged into MYLOG instead.
- print_header(version);
+ ds.PrintHeader();
// Dumps systrace right away, otherwise it will be filled with unnecessary events.
// First try to dump anrd trace if the daemon is running. Otherwise, dump
@@ -1619,7 +1580,7 @@
return -1;
}
- dumpstate(do_early_screenshot ? "": screenshot_path, version);
+ dumpstate();
/* close output if needed */
if (is_redirecting) {
@@ -1643,31 +1604,30 @@
}
}
if (change_suffix) {
- MYLOGI("changing suffix from %s to %s\n", suffix.c_str(), name.c_str());
- suffix = name;
- if (!screenshot_path.empty()) {
- std::string new_screenshot_path =
- ds.bugreportDir_ + "/" + base_name + "-" + suffix + ".png";
- if (rename(screenshot_path.c_str(), new_screenshot_path.c_str())) {
- MYLOGE("rename(%s, %s): %s\n", screenshot_path.c_str(),
- new_screenshot_path.c_str(), strerror(errno));
+ MYLOGI("changing suffix from %s to %s\n", ds.suffix_.c_str(), name.c_str());
+ ds.suffix_ = name;
+ if (!ds.screenshotPath_.empty()) {
+ std::string newScreenshotPath = ds.GetPath(".png");
+ if (rename(ds.screenshotPath_.c_str(), newScreenshotPath.c_str())) {
+ MYLOGE("rename(%s, %s): %s\n", ds.screenshotPath_.c_str(),
+ newScreenshotPath.c_str(), strerror(errno));
} else {
- screenshot_path = new_screenshot_path;
+ ds.screenshotPath_ = newScreenshotPath;
}
}
}
bool do_text_file = true;
if (do_zip_file) {
- std::string entry_name = base_name + "-" + suffix + ".txt";
+ std::string entry_name = ds.baseName_ + "-" + ds.suffix_ + ".txt";
MYLOGD("Adding main entry (%s) to .zip bugreport\n", entry_name.c_str());
- if (!finish_zip_file(entry_name, tmp_path, log_path, now)) {
+ if (!finish_zip_file(entry_name, tmp_path, log_path)) {
MYLOGE("Failed to finish zip file; sending text bugreport instead\n");
do_text_file = true;
} else {
do_text_file = false;
// Since zip file is already created, it needs to be renamed.
- std::string new_path = ds.bugreportDir_ + "/" + base_name + "-" + suffix + ".zip";
+ std::string new_path = ds.GetPath(".zip");
if (path != new_path) {
MYLOGD("Renaming zip file from %s to %s\n", path.c_str(), new_path.c_str());
if (rename(path.c_str(), new_path.c_str())) {
@@ -1680,7 +1640,7 @@
}
}
if (do_text_file) {
- path = ds.bugreportDir_ + "/" + base_name + "-" + suffix + ".txt";
+ path = ds.GetPath(".txt");
MYLOGD("Generating .txt bugreport at %s from %s\n", path.c_str(), tmp_path.c_str());
if (rename(tmp_path.c_str(), path.c_str())) {
MYLOGE("rename(%s, %s): %s\n", tmp_path.c_str(), path.c_str(), strerror(errno));
@@ -1724,7 +1684,7 @@
if (do_fb) {
am_args.push_back("--es");
am_args.push_back("android.intent.extra.SCREENSHOT");
- am_args.push_back(screenshot_path);
+ am_args.push_back(ds.screenshotPath_);
}
if (is_remote_mode) {
am_args.push_back("--es");
diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h
index adaf29e..54d91f7 100644
--- a/cmds/dumpstate/dumpstate.h
+++ b/cmds/dumpstate/dumpstate.h
@@ -193,6 +193,13 @@
static const int WEIGHT_TOTAL = 6500;
/*
+ * List of supported zip format versions.
+ *
+ * See bugreport-format.md for more info.
+ */
+static std::string VERSION_DEFAULT = "1.0";
+
+/*
* Main class driving a bugreport generation.
*
* Currently, it only contains variables that are accessed externally, but gradually the functions
@@ -255,6 +262,13 @@
*/
int DumpFile(const std::string& title, const std::string& path);
+ /*
+ * Takes a screenshot and save it to the given `path`.
+ *
+ * If `path` is empty, uses a standard path based on the bugreport name.
+ */
+ void TakeScreenshot(const std::string& path = "");
+
// TODO: members below should be private once refactor is finished
/*
@@ -262,6 +276,12 @@
*/
void UpdateProgress(int delta);
+ /* Prints the dumpstate header on `stdout`. */
+ void PrintHeader();
+
+ /* Gets the path of a bugreport file with the given suffix. */
+ std::string GetPath(const std::string& suffix);
+
// TODO: initialize fields on constructor
// dumpstate id - unique after each device reboot.
@@ -270,6 +290,9 @@
// Whether progress updates should be published.
bool updateProgress_ = false;
+ // Whether it should take an screenshot earlier in the process.
+ bool doEarlyScreenshot_ = false;
+
// Currrent progress.
int progress_ = 0;
@@ -279,10 +302,30 @@
// When set, defines a socket file-descriptor use to report progress to bugreportz.
int controlSocketFd_ = -1;
+ // Bugreport format version;
+ std::string version_ = VERSION_DEFAULT;
- // Full path of the directory where the bugreport files will be written;
+ // Command-line arguments as string
+ std::string args_;
+
+ // Extra options passed as system property.
+ std::string extraOptions_;
+
+ // Full path of the directory where the bugreport files will be written.
std::string bugreportDir_;
+ // Full path of the temporary file containing the screenshot (when requested).
+ std::string screenshotPath_;
+
+ time_t now_;
+
+ // Suffix of the bugreport files - it's typically the date (when invoked with -d),
+ // although it could be changed by the user using a system property.
+ std::string suffix_;
+
+ // Base name (without suffix or extensions) of the bugreport files.
+ std::string baseName_;
+
private:
// Used by GetInstance() only.
Dumpstate(bool dryRun = false, const std::string& buildType = "user");
@@ -380,9 +423,6 @@
/* Implemented by libdumpstate_board to dump board-specific info */
void dumpstate_board();
-/* Takes a screenshot and save it to the given file */
-void take_screenshot(const std::string& path);
-
/* Vibrates for a given durating (in milliseconds). */
void vibrate(FILE* vibrator, int ms);
diff --git a/cmds/dumpstate/utils.cpp b/cmds/dumpstate/utils.cpp
index fc1f721..83fcf21 100644
--- a/cmds/dumpstate/utils.cpp
+++ b/cmds/dumpstate/utils.cpp
@@ -163,7 +163,7 @@
}
Dumpstate::Dumpstate(bool dryRun, const std::string& buildType)
- : dryRun_(dryRun), buildType_(buildType) {
+ : now_(time(nullptr)), dryRun_(dryRun), buildType_(buildType) {
}
Dumpstate& Dumpstate::GetInstance() {
@@ -208,6 +208,10 @@
return "user" == buildType_;
}
+std::string Dumpstate::GetPath(const std::string& suffix) {
+ return bugreportDir_ + "/" + baseName_ + "-" + suffix_ + suffix;
+}
+
void for_each_userid(void (*func)(int), const char *header) {
if (IsDryRun()) return;
@@ -1342,9 +1346,16 @@
}
}
-void take_screenshot(const std::string& path) {
- RunCommand("", {"/system/bin/screencap", "-p", path},
- CommandOptions::WithTimeout(10).Always().RedirectStderr().Build());
+void Dumpstate::TakeScreenshot(const std::string& path) {
+ const std::string& realPath = path.empty() ? screenshotPath_ : path;
+ int status =
+ RunCommand("", {"/system/bin/screencap", "-p", realPath},
+ CommandOptions::WithTimeout(10).Always().DropRoot().RedirectStderr().Build());
+ if (status == 0) {
+ MYLOGD("Screenshot saved on %s\n", realPath.c_str());
+ } else {
+ MYLOGE("Failed to take screenshot on %s\n", realPath.c_str());
+ }
}
void vibrate(FILE* vibrator, int ms) {
diff --git a/data/etc/android.hardware.sensor.heartrate.fitness.xml b/data/etc/android.hardware.sensor.heartrate.fitness.xml
new file mode 100644
index 0000000..aef77b4
--- /dev/null
+++ b/data/etc/android.hardware.sensor.heartrate.fitness.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<!-- Feature for devices supporting a fitness heart rate monitor -->
+<permissions>
+ <feature name="android.hardware.sensor.heartrate.fitness" />
+</permissions>
diff --git a/data/etc/handheld_core_hardware.xml b/data/etc/handheld_core_hardware.xml
index 9cb4d6d..f10cbc3 100644
--- a/data/etc/handheld_core_hardware.xml
+++ b/data/etc/handheld_core_hardware.xml
@@ -42,6 +42,7 @@
<feature name="android.software.backup" />
<feature name="android.software.home_screen" />
<feature name="android.software.input_methods" />
+ <feature name="android.software.picture_in_picture" />
<feature name="android.software.print" />
<!-- Feature to specify if the device supports adding device admins. -->
diff --git a/data/etc/tablet_core_hardware.xml b/data/etc/tablet_core_hardware.xml
index 8128165..7f545e6 100644
--- a/data/etc/tablet_core_hardware.xml
+++ b/data/etc/tablet_core_hardware.xml
@@ -42,6 +42,7 @@
<feature name="android.software.backup" />
<feature name="android.software.home_screen" />
<feature name="android.software.input_methods" />
+ <feature name="android.software.picture_in_picture" />
<feature name="android.software.print" />
<!-- Feature to specify if the device supports adding device admins. -->
diff --git a/include/media/openmax/OMX_AsString.h b/include/media/openmax/OMX_AsString.h
index 4c74bc5..b18fd54 100644
--- a/include/media/openmax/OMX_AsString.h
+++ b/include/media/openmax/OMX_AsString.h
@@ -546,6 +546,8 @@
case OMX_IndexConfigAndroidIntraRefresh: return "ConfigAndroidIntraRefresh";
case OMX_IndexParamAndroidVideoTemporalLayering: return "ParamAndroidVideoTemporalLayering";
case OMX_IndexConfigAndroidVideoTemporalLayering: return "ConfigAndroidVideoTemporalLayering";
+ case OMX_IndexParamMaxFrameDurationForBitrateControl:
+ return "ParamMaxFrameDurationForBitrateControl";
case OMX_IndexConfigAutoFramerateConversion: return "ConfigAutoFramerateConversion";
case OMX_IndexConfigPriority: return "ConfigPriority";
case OMX_IndexConfigOperatingRate: return "ConfigOperatingRate";
diff --git a/include/media/openmax/OMX_Index.h b/include/media/openmax/OMX_Index.h
index 1a2a548..5be1355 100644
--- a/include/media/openmax/OMX_Index.h
+++ b/include/media/openmax/OMX_Index.h
@@ -98,10 +98,13 @@
OMX_IndexParamMetadataKeyFilter, /**< reference: OMX_PARAM_METADATAFILTERTYPE */
OMX_IndexConfigPriorityMgmt, /**< reference: OMX_PRIORITYMGMTTYPE */
OMX_IndexParamStandardComponentRole, /**< reference: OMX_PARAM_COMPONENTROLETYPE */
+ OMX_IndexComponentEndUnused,
OMX_IndexPortStartUnused = 0x02000000,
OMX_IndexParamPortDefinition, /**< reference: OMX_PARAM_PORTDEFINITIONTYPE */
OMX_IndexParamCompBufferSupplier, /**< reference: OMX_PARAM_BUFFERSUPPLIERTYPE */
+ OMX_IndexPortEndUnused,
+
OMX_IndexReservedStartUnused = 0x03000000,
/* Audio parameters and configurations */
@@ -134,6 +137,7 @@
OMX_IndexParamAudioSmv, /**< reference: OMX_AUDIO_PARAM_SMVTYPE */
OMX_IndexParamAudioVorbis, /**< reference: OMX_AUDIO_PARAM_VORBISTYPE */
OMX_IndexParamAudioFlac, /**< reference: OMX_AUDIO_PARAM_FLACTYPE */
+ OMX_IndexAudioEndUnused,
OMX_IndexConfigAudioMidiImmediateEvent, /**< reference: OMX_AUDIO_CONFIG_MIDIIMMEDIATEEVENTTYPE */
OMX_IndexConfigAudioMidiControl, /**< reference: OMX_AUDIO_CONFIG_MIDICONTROLTYPE */
@@ -194,6 +198,7 @@
OMX_IndexParamVideoSliceFMO, /**< reference: OMX_VIDEO_PARAM_AVCSLICEFMO */
OMX_IndexConfigVideoAVCIntraPeriod, /**< reference: OMX_VIDEO_CONFIG_AVCINTRAPERIOD */
OMX_IndexConfigVideoNalSize, /**< reference: OMX_VIDEO_CONFIG_NALSIZE */
+ OMX_IndexVideoEndUnused,
/* Image & Video common Configurations */
OMX_IndexCommonStartUnused = 0x07000000,
@@ -231,6 +236,7 @@
OMX_IndexConfigCommonFocusRegion, /**< reference: OMX_CONFIG_FOCUSREGIONTYPE */
OMX_IndexConfigCommonFocusStatus, /**< reference: OMX_PARAM_FOCUSSTATUSTYPE */
OMX_IndexConfigCommonTransitionEffect, /**< reference: OMX_CONFIG_TRANSITIONEFFECTTYPE */
+ OMX_IndexCommonEndUnused,
/* Reserved Configuration range */
OMX_IndexOtherStartUnused = 0x08000000,
diff --git a/include/media/openmax/OMX_IndexExt.h b/include/media/openmax/OMX_IndexExt.h
index 78d1f5d..63fbff8 100644
--- a/include/media/openmax/OMX_IndexExt.h
+++ b/include/media/openmax/OMX_IndexExt.h
@@ -62,6 +62,7 @@
OMX_IndexParamAudioAndroidAacPresentation, /**< reference: OMX_AUDIO_PARAM_ANDROID_AACPRESENTATIONTYPE */
OMX_IndexParamAudioAndroidEac3, /**< reference: OMX_AUDIO_PARAM_ANDROID_EAC3TYPE */
OMX_IndexParamAudioProfileQuerySupported, /**< reference: OMX_AUDIO_PARAM_ANDROID_PROFILETYPE */
+ OMX_IndexExtAudioEndUnused,
/* Image parameters and configurations */
OMX_IndexExtImageStartUnused = OMX_IndexKhronosExtensions + 0x00500000,
@@ -82,6 +83,8 @@
OMX_IndexConfigAndroidIntraRefresh, /**< reference: OMX_VIDEO_CONFIG_ANDROID_INTRAREFRESHTYPE */
OMX_IndexParamAndroidVideoTemporalLayering, /**< reference: OMX_VIDEO_PARAM_ANDROID_TEMPORALLAYERINGTYPE */
OMX_IndexConfigAndroidVideoTemporalLayering, /**< reference: OMX_VIDEO_CONFIG_ANDROID_TEMPORALLAYERINGTYPE */
+ OMX_IndexParamMaxFrameDurationForBitrateControl,/**< reference: OMX_PARAM_U32TYPE */
+ OMX_IndexExtVideoEndUnused,
/* Image & Video common configurations */
OMX_IndexExtCommonStartUnused = OMX_IndexKhronosExtensions + 0x00700000,
@@ -92,6 +95,7 @@
OMX_IndexConfigPriority, /**< reference: OMX_PARAM_U32TYPE */
OMX_IndexConfigOperatingRate, /**< reference: OMX_PARAM_U32TYPE in Q16 format for video and in Hz for audio */
OMX_IndexParamConsumerUsageBits, /**< reference: OMX_PARAM_U32TYPE */
+ OMX_IndexExtOtherEndUnused,
/* Time configurations */
OMX_IndexExtTimeStartUnused = OMX_IndexKhronosExtensions + 0x00900000,
diff --git a/include/ui/Fence.h b/include/ui/Fence.h
index d45ad76..1df15f8 100644
--- a/include/ui/Fence.h
+++ b/include/ui/Fence.h
@@ -27,6 +27,8 @@
#include <utils/String8.h>
#include <utils/Timers.h>
+#include <experimental/optional>
+
struct ANativeWindowBuffer;
namespace android {
@@ -96,6 +98,27 @@
// occurs then -1 is returned.
nsecs_t getSignalTime() const;
+#if __cplusplus > 201103L
+ // hasSignaled returns whether the fence has signaled yet. Prefer this to
+ // getSignalTime() or wait() if all you care about is whether the fence has
+ // signaled. Returns an optional bool, which will have a value if there was
+ // no error.
+ inline std::experimental::optional<bool> hasSignaled() {
+ // The sync_wait call underlying wait() has been measured to be
+ // significantly faster than the sync_fence_info call underlying
+ // getSignalTime(), which might otherwise appear to be the more obvious
+ // way to check whether a fence has signaled.
+ switch (wait(0)) {
+ case NO_ERROR:
+ return true;
+ case -ETIME:
+ return false;
+ default:
+ return {};
+ }
+ }
+#endif
+
// Flattenable interface
size_t getFlattenedSize() const;
size_t getFdCount() const;
diff --git a/include/ui/GrallocAllocator.h b/include/ui/GrallocAllocator.h
new file mode 100644
index 0000000..23b78ed
--- /dev/null
+++ b/include/ui/GrallocAllocator.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_UI_GRALLOC_ALLOCATOR_H
+#define ANDROID_UI_GRALLOC_ALLOCATOR_H
+
+#include <string>
+
+#include <android/hardware/graphics/allocator/2.0/IAllocator.h>
+#include <utils/StrongPointer.h>
+
+namespace android {
+
+namespace Gralloc2 {
+
+using hardware::graphics::allocator::V2_0::Error;
+using hardware::graphics::allocator::V2_0::PixelFormat;
+using hardware::graphics::allocator::V2_0::ProducerUsage;
+using hardware::graphics::allocator::V2_0::ConsumerUsage;
+using hardware::graphics::allocator::V2_0::BufferDescriptor;
+using hardware::graphics::allocator::V2_0::Buffer;
+using hardware::graphics::allocator::V2_0::IAllocator;
+
+// Allocator is a wrapper to IAllocator, a proxy to server-side allocator.
+class Allocator {
+public:
+ Allocator();
+
+ // this will be removed and Allocator will be always valid
+ bool valid() const { return (mService != nullptr); }
+
+ std::string dumpDebugInfo() const;
+
+ Error createBufferDescriptor(
+ const IAllocator::BufferDescriptorInfo& descriptorInfo,
+ BufferDescriptor& descriptor) const;
+ void destroyBufferDescriptor(BufferDescriptor descriptor) const;
+
+ Error allocate(BufferDescriptor descriptor, Buffer& buffer) const;
+ void free(Buffer buffer) const;
+
+ Error exportHandle(BufferDescriptor descriptor, Buffer buffer,
+ native_handle_t*& bufferHandle) const;
+
+private:
+ sp<IAllocator> mService;
+};
+
+} // namespace Gralloc2
+
+} // namespace android
+
+#endif // ANDROID_UI_GRALLOC_ALLOCATOR_H
diff --git a/include/ui/GrallocMapper.h b/include/ui/GrallocMapper.h
new file mode 100644
index 0000000..5517449
--- /dev/null
+++ b/include/ui/GrallocMapper.h
@@ -0,0 +1,127 @@
+/*
+ * Copyright 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_UI_GRALLOC_MAPPER_H
+#define ANDROID_UI_GRALLOC_MAPPER_H
+
+#include <memory>
+
+#include <android/hardware/graphics/mapper/2.0/IMapper.h>
+#include <system/window.h>
+
+namespace android {
+
+namespace Gralloc2 {
+
+using hardware::graphics::allocator::V2_0::Error;
+using hardware::graphics::allocator::V2_0::PixelFormat;
+using hardware::graphics::allocator::V2_0::ProducerUsage;
+using hardware::graphics::allocator::V2_0::ConsumerUsage;
+using hardware::graphics::mapper::V2_0::FlexLayout;
+using hardware::graphics::mapper::V2_0::BackingStore;
+using hardware::graphics::mapper::V2_0::Device;
+using hardware::graphics::mapper::V2_0::IMapper;
+
+// Mapper is a wrapper to IMapper, a client-side graphics buffer mapper.
+class Mapper {
+public:
+ Mapper();
+ ~Mapper();
+
+ // this will be removed and Mapper will be always valid
+ bool valid() const { return (mMapper != nullptr); }
+
+ Error retain(buffer_handle_t handle) const
+ {
+ return mMapper->retain(mDevice, handle);
+ }
+
+ void release(buffer_handle_t handle) const;
+
+ Error getDimensions(buffer_handle_t handle,
+ uint32_t& width, uint32_t& height) const
+ {
+ return mMapper->getDimensions(mDevice, handle, &width, &height);
+ }
+
+ Error getFormat(buffer_handle_t handle,
+ PixelFormat& format) const
+ {
+ return mMapper->getFormat(mDevice, handle, &format);
+ }
+
+ Error getProducerUsageMask(buffer_handle_t handle,
+ uint64_t& usageMask) const
+ {
+ return mMapper->getProducerUsageMask(mDevice, handle, &usageMask);
+ }
+
+ Error getConsumerUsageMask(buffer_handle_t handle,
+ uint64_t& usageMask) const
+ {
+ return mMapper->getConsumerUsageMask(mDevice, handle, &usageMask);
+ }
+
+ Error getBackingStore(buffer_handle_t handle,
+ BackingStore& store) const
+ {
+ return mMapper->getBackingStore(mDevice, handle, &store);
+ }
+
+ Error getStride(buffer_handle_t handle, uint32_t& stride) const
+ {
+ return mMapper->getStride(mDevice, handle, &stride);
+ }
+
+ Error getNumFlexPlanes(buffer_handle_t handle, uint32_t& numPlanes) const
+ {
+ return mMapper->getNumFlexPlanes(mDevice, handle, &numPlanes);
+ }
+
+ Error lock(buffer_handle_t handle,
+ uint64_t producerUsageMask,
+ uint64_t consumerUsageMask,
+ const Device::Rect& accessRegion,
+ int acquireFence, void*& data) const
+ {
+ return mMapper->lock(mDevice, handle,
+ producerUsageMask, consumerUsageMask,
+ &accessRegion, acquireFence, &data);
+ }
+
+ Error lock(buffer_handle_t handle,
+ uint64_t producerUsageMask,
+ uint64_t consumerUsageMask,
+ const Device::Rect& accessRegion,
+ int acquireFence, FlexLayout& flexLayout) const
+ {
+ return mMapper->lockFlex(mDevice, handle,
+ producerUsageMask, consumerUsageMask,
+ &accessRegion, acquireFence, &flexLayout);
+ }
+
+ int unlock(buffer_handle_t handle) const;
+
+private:
+ const IMapper* mMapper;
+ Device* mDevice;
+};
+
+} // namespace Gralloc2
+
+} // namespace android
+
+#endif // ANDROID_UI_GRALLOC_MAPPER_H
diff --git a/include/ui/GraphicBufferAllocator.h b/include/ui/GraphicBufferAllocator.h
index 28d0238..9cc5806 100644
--- a/include/ui/GraphicBufferAllocator.h
+++ b/include/ui/GraphicBufferAllocator.h
@@ -32,7 +32,12 @@
namespace android {
+namespace Gralloc2 {
+class Allocator;
+}
+
class Gralloc1Loader;
+class GraphicBufferMapper;
class String8;
class GraphicBufferAllocator : public Singleton<GraphicBufferAllocator>
@@ -86,6 +91,9 @@
GraphicBufferAllocator();
~GraphicBufferAllocator();
+ const std::unique_ptr<const Gralloc2::Allocator> mAllocator;
+ GraphicBufferMapper& mMapper;
+
std::unique_ptr<Gralloc1::Loader> mLoader;
std::unique_ptr<Gralloc1::Device> mDevice;
};
diff --git a/include/ui/GraphicBufferMapper.h b/include/ui/GraphicBufferMapper.h
index a25809c..b6de1b2 100644
--- a/include/ui/GraphicBufferMapper.h
+++ b/include/ui/GraphicBufferMapper.h
@@ -28,6 +28,10 @@
// ---------------------------------------------------------------------------
+namespace Gralloc2 {
+class Mapper;
+}
+
class Rect;
class GraphicBufferMapper : public Singleton<GraphicBufferMapper>
@@ -57,11 +61,18 @@
status_t unlockAsync(buffer_handle_t handle, int *fenceFd);
+ const Gralloc2::Mapper& getGrallocMapper() const
+ {
+ return *mMapper;
+ }
+
private:
friend class Singleton<GraphicBufferMapper>;
GraphicBufferMapper();
+ const std::unique_ptr<const Gralloc2::Mapper> mMapper;
+
std::unique_ptr<Gralloc1::Loader> mLoader;
std::unique_ptr<Gralloc1::Device> mDevice;
};
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp
new file mode 100644
index 0000000..8e8bb80
--- /dev/null
+++ b/libs/gui/Android.bp
@@ -0,0 +1,111 @@
+// Copyright 2010 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_library_shared {
+ name: "libgui",
+
+ clang: true,
+ cppflags: [
+ "-Weverything",
+ "-Werror",
+
+ // The static constructors and destructors in this library have not been noted to
+ // introduce significant overheads
+ "-Wno-exit-time-destructors",
+ "-Wno-global-constructors",
+
+ // We only care about compiling as C++14
+ "-Wno-c++98-compat-pedantic",
+
+ // We don't need to enumerate every case in a switch as long as a default case
+ // is present
+ "-Wno-switch-enum",
+
+ // Allow calling variadic macros without a __VA_ARGS__ list
+ "-Wno-gnu-zero-variadic-macro-arguments",
+
+ // Don't warn about struct padding
+ "-Wno-padded",
+
+ // android/sensors.h uses nested anonymous unions and anonymous structs
+ "-Wno-nested-anon-types",
+ "-Wno-gnu-anonymous-struct",
+
+ "-DDEBUG_ONLY_CODE=0",
+ ],
+
+ product_variables: {
+ brillo: {
+ cflags: ["-DHAVE_NO_SURFACE_FLINGER"],
+ },
+ debuggable: {
+ cppflags: [
+ "-UDEBUG_ONLY_CODE",
+ "-DDEBUG_ONLY_CODE=1",
+ ],
+ },
+ },
+
+ srcs: [
+ "IGraphicBufferConsumer.cpp",
+ "IConsumerListener.cpp",
+ "BitTube.cpp",
+ "BufferItem.cpp",
+ "BufferItemConsumer.cpp",
+ "BufferQueue.cpp",
+ "BufferQueueConsumer.cpp",
+ "BufferQueueCore.cpp",
+ "BufferQueueProducer.cpp",
+ "BufferSlot.cpp",
+ "ConsumerBase.cpp",
+ "CpuConsumer.cpp",
+ "DisplayEventReceiver.cpp",
+ "GLConsumer.cpp",
+ "GraphicBufferAlloc.cpp",
+ "GuiConfig.cpp",
+ "IDisplayEventConnection.cpp",
+ "IGraphicBufferAlloc.cpp",
+ "IGraphicBufferProducer.cpp",
+ "IProducerListener.cpp",
+ "ISensorEventConnection.cpp",
+ "ISensorServer.cpp",
+ "ISurfaceComposer.cpp",
+ "ISurfaceComposerClient.cpp",
+ "LayerState.cpp",
+ "OccupancyTracker.cpp",
+ "Sensor.cpp",
+ "SensorEventQueue.cpp",
+ "SensorManager.cpp",
+ "StreamSplitter.cpp",
+ "Surface.cpp",
+ "SurfaceControl.cpp",
+ "SurfaceComposerClient.cpp",
+ "SyncFeatures.cpp",
+ ],
+
+ shared_libs: [
+ "libbinder",
+ "libcutils",
+ "libEGL",
+ "libGLESv2",
+ "libsync",
+ "libui",
+ "libutils",
+ "liblog",
+ ],
+
+ export_shared_lib_headers: ["libbinder"],
+}
+
+subdirs = ["tests"]
diff --git a/libs/gui/Android.mk b/libs/gui/Android.mk
deleted file mode 100644
index 71b5cca..0000000
--- a/libs/gui/Android.mk
+++ /dev/null
@@ -1,109 +0,0 @@
-# Copyright 2010 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_CLANG := true
-LOCAL_CPPFLAGS := -std=c++1y -Weverything -Werror
-
-# The static constructors and destructors in this library have not been noted to
-# introduce significant overheads
-LOCAL_CPPFLAGS += -Wno-exit-time-destructors
-LOCAL_CPPFLAGS += -Wno-global-constructors
-
-# We only care about compiling as C++14
-LOCAL_CPPFLAGS += -Wno-c++98-compat-pedantic
-
-# We don't need to enumerate every case in a switch as long as a default case
-# is present
-LOCAL_CPPFLAGS += -Wno-switch-enum
-
-# Allow calling variadic macros without a __VA_ARGS__ list
-LOCAL_CPPFLAGS += -Wno-gnu-zero-variadic-macro-arguments
-
-# Don't warn about struct padding
-LOCAL_CPPFLAGS += -Wno-padded
-
-# android/sensors.h uses nested anonymous unions and anonymous structs
-LOCAL_CPPFLAGS += -Wno-nested-anon-types -Wno-gnu-anonymous-struct
-
-LOCAL_CPPFLAGS += -DDEBUG_ONLY_CODE=$(if $(filter userdebug eng,$(TARGET_BUILD_VARIANT)),1,0)
-
-LOCAL_SRC_FILES := \
- IGraphicBufferConsumer.cpp \
- IConsumerListener.cpp \
- BitTube.cpp \
- BufferItem.cpp \
- BufferItemConsumer.cpp \
- BufferQueue.cpp \
- BufferQueueConsumer.cpp \
- BufferQueueCore.cpp \
- BufferQueueProducer.cpp \
- BufferSlot.cpp \
- ConsumerBase.cpp \
- CpuConsumer.cpp \
- DisplayEventReceiver.cpp \
- GLConsumer.cpp \
- GraphicBufferAlloc.cpp \
- GuiConfig.cpp \
- IDisplayEventConnection.cpp \
- IGraphicBufferAlloc.cpp \
- IGraphicBufferProducer.cpp \
- IProducerListener.cpp \
- ISensorEventConnection.cpp \
- ISensorServer.cpp \
- ISurfaceComposer.cpp \
- ISurfaceComposerClient.cpp \
- LayerState.cpp \
- OccupancyTracker.cpp \
- Sensor.cpp \
- SensorEventQueue.cpp \
- SensorManager.cpp \
- StreamSplitter.cpp \
- Surface.cpp \
- SurfaceControl.cpp \
- SurfaceComposerClient.cpp \
- SyncFeatures.cpp \
-
-LOCAL_SHARED_LIBRARIES := \
- libbinder \
- libcutils \
- libEGL \
- libGLESv2 \
- libsync \
- libui \
- libutils \
- liblog
-
-LOCAL_EXPORT_SHARED_LIBRARY_HEADERS := libbinder
-
-LOCAL_MODULE := libgui
-
-ifeq ($(TARGET_BOARD_PLATFORM), tegra)
- LOCAL_CFLAGS += -DDONT_USE_FENCE_SYNC
-endif
-ifeq ($(TARGET_BOARD_PLATFORM), tegra3)
- LOCAL_CFLAGS += -DDONT_USE_FENCE_SYNC
-endif
-
-ifeq ($(TARGET_BOARD_HAS_NO_SURFACE_FLINGER), true)
- LOCAL_CFLAGS += -DHAVE_NO_SURFACE_FLINGER
-endif
-
-include $(BUILD_SHARED_LIBRARY)
-
-ifeq (,$(ONE_SHOT_MAKEFILE))
-include $(call first-makefiles-under,$(LOCAL_PATH))
-endif
diff --git a/libs/gui/ConsumerBase.cpp b/libs/gui/ConsumerBase.cpp
index 5546d54..3cf3078 100644
--- a/libs/gui/ConsumerBase.cpp
+++ b/libs/gui/ConsumerBase.cpp
@@ -314,6 +314,18 @@
if (!mSlots[slot].mFence.get()) {
mSlots[slot].mFence = fence;
+ return OK;
+ }
+
+ auto signaled = mSlots[slot].mFence->hasSignaled();
+
+ if (!signaled) {
+ CB_LOGE("fence has invalid state");
+ return BAD_VALUE;
+ }
+
+ if (*signaled) {
+ mSlots[slot].mFence = fence;
} else {
char fenceName[32] = {};
snprintf(fenceName, 32, "%.28s:%d", mName.string(), slot);
diff --git a/libs/gui/SensorManager.cpp b/libs/gui/SensorManager.cpp
index 5338034..57c3073 100644
--- a/libs/gui/SensorManager.cpp
+++ b/libs/gui/SensorManager.cpp
@@ -194,7 +194,8 @@
// a non_wake-up version.
if (type == SENSOR_TYPE_PROXIMITY || type == SENSOR_TYPE_SIGNIFICANT_MOTION ||
type == SENSOR_TYPE_TILT_DETECTOR || type == SENSOR_TYPE_WAKE_GESTURE ||
- type == SENSOR_TYPE_GLANCE_GESTURE || type == SENSOR_TYPE_PICK_UP_GESTURE) {
+ type == SENSOR_TYPE_GLANCE_GESTURE || type == SENSOR_TYPE_PICK_UP_GESTURE ||
+ type == SENSOR_TYPE_WRIST_TILT_GESTURE) {
wakeUpSensor = true;
}
// For now we just return the first sensor of that type we find.
diff --git a/libs/gui/tests/Android.bp b/libs/gui/tests/Android.bp
new file mode 100644
index 0000000..3c7958f
--- /dev/null
+++ b/libs/gui/tests/Android.bp
@@ -0,0 +1,42 @@
+// Build the unit tests,
+
+// Build the binary to $(TARGET_OUT_DATA_NATIVE_TESTS)/$(LOCAL_MODULE)
+// to integrate with auto-test framework.
+cc_test {
+ name: "libgui_test",
+
+ clang: true,
+
+ srcs: [
+ "BufferQueue_test.cpp",
+ "CpuConsumer_test.cpp",
+ "FillBuffer.cpp",
+ "GLTest.cpp",
+ "IGraphicBufferProducer_test.cpp",
+ "MultiTextureConsumer_test.cpp",
+ "Sensor_test.cpp",
+ "SRGB_test.cpp",
+ "StreamSplitter_test.cpp",
+ "SurfaceTextureClient_test.cpp",
+ "SurfaceTextureFBO_test.cpp",
+ "SurfaceTextureGLThreadToGL_test.cpp",
+ "SurfaceTextureGLToGL_test.cpp",
+ "SurfaceTextureGL_test.cpp",
+ "SurfaceTextureMultiContextGL_test.cpp",
+ "Surface_test.cpp",
+ "TextureRenderer.cpp",
+ ],
+
+ shared_libs: [
+ "liblog",
+ "libEGL",
+ "libGLESv1_CM",
+ "libGLESv2",
+ "libbinder",
+ "libcutils",
+ "libgui",
+ "libsync",
+ "libui",
+ "libutils",
+ ],
+}
diff --git a/libs/gui/tests/Android.mk b/libs/gui/tests/Android.mk
deleted file mode 100644
index efae7f6..0000000
--- a/libs/gui/tests/Android.mk
+++ /dev/null
@@ -1,54 +0,0 @@
-# Build the unit tests,
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-
-LOCAL_CLANG := true
-
-LOCAL_MODULE := libgui_test
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := \
- BufferQueue_test.cpp \
- CpuConsumer_test.cpp \
- FillBuffer.cpp \
- GLTest.cpp \
- IGraphicBufferProducer_test.cpp \
- MultiTextureConsumer_test.cpp \
- Sensor_test.cpp \
- SRGB_test.cpp \
- StreamSplitter_test.cpp \
- SurfaceTextureClient_test.cpp \
- SurfaceTextureFBO_test.cpp \
- SurfaceTextureGLThreadToGL_test.cpp \
- SurfaceTextureGLToGL_test.cpp \
- SurfaceTextureGL_test.cpp \
- SurfaceTextureMultiContextGL_test.cpp \
- Surface_test.cpp \
- TextureRenderer.cpp \
-
-LOCAL_SHARED_LIBRARIES := \
- liblog \
- libEGL \
- libGLESv1_CM \
- libGLESv2 \
- libbinder \
- libcutils \
- libgui \
- libsync \
- libui \
- libutils \
-
-# Build the binary to $(TARGET_OUT_DATA_NATIVE_TESTS)/$(LOCAL_MODULE)
-# to integrate with auto-test framework.
-include $(BUILD_NATIVE_TEST)
-
-# Include subdirectory makefiles
-# ============================================================
-
-# If we're building with ONE_SHOT_MAKEFILE (mm, mmm), then what the framework
-# team really wants is to build the stuff defined by this makefile.
-ifeq (,$(ONE_SHOT_MAKEFILE))
-include $(call first-makefiles-under,$(LOCAL_PATH))
-endif
diff --git a/libs/ui/Android.bp b/libs/ui/Android.bp
index 0777468..37b2873 100644
--- a/libs/ui/Android.bp
+++ b/libs/ui/Android.bp
@@ -17,7 +17,6 @@
clang: true,
cppflags: [
- "-std=c++1y",
"-Weverything",
"-Werror",
@@ -46,6 +45,8 @@
"FrameStats.cpp",
"Gralloc1.cpp",
"Gralloc1On0Adapter.cpp",
+ "GrallocAllocator.cpp",
+ "GrallocMapper.cpp",
"GraphicBuffer.cpp",
"GraphicBufferAllocator.cpp",
"GraphicBufferMapper.cpp",
@@ -56,10 +57,17 @@
"UiConfig.cpp",
],
+ static_libs: [
+ "android.hardware.graphics.mapper@2.0",
+ ],
+
shared_libs: [
+ "android.hardware.graphics.allocator@2.0",
"libbinder",
"libcutils",
"libhardware",
+ "libhidl",
+ "libhwbinder",
"libsync",
"libutils",
"liblog",
diff --git a/libs/ui/GrallocAllocator.cpp b/libs/ui/GrallocAllocator.cpp
new file mode 100644
index 0000000..2eb1988
--- /dev/null
+++ b/libs/ui/GrallocAllocator.cpp
@@ -0,0 +1,114 @@
+/*
+ * 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 "GrallocAllocator"
+
+#include <log/log.h>
+#include <ui/GrallocAllocator.h>
+
+namespace android {
+
+namespace Gralloc2 {
+
+// assume NO_RESOURCES when Status::isOk returns false
+constexpr Error kDefaultError = Error::NO_RESOURCES;
+
+Allocator::Allocator()
+{
+ mService = IAllocator::getService("gralloc");
+}
+
+std::string Allocator::dumpDebugInfo() const
+{
+ std::string info;
+
+ mService->dumpDebugInfo([&](const auto& tmpInfo) {
+ info = tmpInfo.c_str();
+ });
+
+ return info;
+}
+
+Error Allocator::createBufferDescriptor(
+ const IAllocator::BufferDescriptorInfo& descriptorInfo,
+ BufferDescriptor& descriptor) const
+{
+ Error error = kDefaultError;
+ mService->createDescriptor(descriptorInfo,
+ [&](const auto& tmpError, const auto& tmpDescriptor) {
+ error = tmpError;
+ if (error != Error::NONE) {
+ return;
+ }
+
+ descriptor = tmpDescriptor;
+ });
+
+ return error;
+}
+
+void Allocator::destroyBufferDescriptor(BufferDescriptor descriptor) const
+{
+ mService->destroyDescriptor(descriptor);
+}
+
+Error Allocator::allocate(BufferDescriptor descriptor, Buffer& buffer) const
+{
+ hardware::hidl_vec<BufferDescriptor> descriptors;
+ descriptors.setToExternal(&descriptor, 1);
+
+ Error error = kDefaultError;
+ auto status = mService->allocate(descriptors,
+ [&](const auto& tmpError, const auto& tmpBuffers) {
+ error = tmpError;
+ if (tmpError != Error::NONE) {
+ return;
+ }
+
+ buffer = tmpBuffers[0];
+ });
+
+ return error;
+}
+
+void Allocator::free(Buffer buffer) const
+{
+ mService->free(buffer);
+}
+
+Error Allocator::exportHandle(BufferDescriptor descriptor, Buffer buffer,
+ native_handle_t*& bufferHandle) const
+{
+ Error error = kDefaultError;
+ auto status = mService->exportHandle(descriptor, buffer,
+ [&](const auto& tmpError, const auto& tmpBufferHandle) {
+ error = tmpError;
+ if (tmpError != Error::NONE) {
+ return;
+ }
+
+ bufferHandle = native_handle_clone(tmpBufferHandle);
+ if (!bufferHandle) {
+ error = Error::NO_RESOURCES;
+ }
+ });
+
+ return error;
+}
+
+} // namespace Gralloc2
+
+} // namespace android
diff --git a/libs/ui/GrallocMapper.cpp b/libs/ui/GrallocMapper.cpp
new file mode 100644
index 0000000..d568b68
--- /dev/null
+++ b/libs/ui/GrallocMapper.cpp
@@ -0,0 +1,118 @@
+/*
+ * 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 "GrallocMapper"
+
+#include <array>
+#include <string>
+
+#include <log/log.h>
+#include <ui/GrallocMapper.h>
+
+namespace android {
+
+namespace Gralloc2 {
+
+typedef const void*(*FetchInterface)(const char* name);
+
+static FetchInterface loadHalLib(const char* pkg_name)
+{
+ static const std::array<const char*, 3> sSearchDirs = {{
+ HAL_LIBRARY_PATH_ODM,
+ HAL_LIBRARY_PATH_VENDOR,
+ HAL_LIBRARY_PATH_SYSTEM,
+ }};
+ static const char sSymbolName[] = "HALLIB_FETCH_Interface";
+
+ void* handle = nullptr;
+ std::string path;
+ for (auto dir : sSearchDirs) {
+ path = dir;
+ path += pkg_name;
+ path += ".hallib.so";
+ handle = dlopen(path.c_str(), RTLD_LOCAL | RTLD_NOW);
+ if (handle) {
+ break;
+ }
+ }
+ if (!handle) {
+ return nullptr;
+ }
+
+ void* symbol = dlsym(handle, sSymbolName);
+ if (!symbol) {
+ ALOGE("%s is missing from %s", sSymbolName, path.c_str());
+ dlclose(handle);
+ return nullptr;
+ }
+
+ return reinterpret_cast<FetchInterface>(symbol);
+}
+
+Mapper::Mapper()
+ : mMapper(nullptr), mDevice(nullptr)
+{
+ static const char sHalLibName[] = "android.hardware.graphics.mapper";
+ static const char sSupportedInterface[] =
+ "android.hardware.graphics.mapper@2.0::IMapper";
+
+ FetchInterface fetchInterface = loadHalLib(sHalLibName);
+ if (!fetchInterface) {
+ return;
+ }
+
+ mMapper = static_cast<const IMapper*>(
+ fetchInterface(sSupportedInterface));
+ if (!mMapper) {
+ ALOGE("%s is not supported", sSupportedInterface);
+ return;
+ }
+
+ if (mMapper->createDevice(&mDevice) != Error::NONE) {
+ ALOGE("failed to create mapper device");
+ mMapper = nullptr;
+ }
+}
+
+Mapper::~Mapper()
+{
+ if (mMapper) {
+ mMapper->destroyDevice(mDevice);
+ }
+}
+
+void Mapper::release(buffer_handle_t handle) const
+{
+ auto error = mMapper->release(mDevice, handle);
+ ALOGE_IF(error != Error::NONE,
+ "release(%p) failed with %d", handle, error);
+}
+
+int Mapper::unlock(buffer_handle_t handle) const
+{
+ int releaseFence;
+ auto error = mMapper->unlock(mDevice, handle, &releaseFence);
+ if (error != Error::NONE) {
+ ALOGE("unlock(%p) failed with %d", handle, error);
+ releaseFence = -1;
+ }
+
+ return releaseFence;
+}
+
+} // namespace Gralloc2
+
+} // namespace android
diff --git a/libs/ui/GraphicBuffer.cpp b/libs/ui/GraphicBuffer.cpp
index 97b948d..6d72900 100644
--- a/libs/ui/GraphicBuffer.cpp
+++ b/libs/ui/GraphicBuffer.cpp
@@ -23,6 +23,7 @@
#include <utils/Errors.h>
#include <utils/Log.h>
+#include <ui/GrallocMapper.h>
#include <ui/GraphicBuffer.h>
#include <ui/GraphicBufferAllocator.h>
#include <ui/GraphicBufferMapper.h>
@@ -108,8 +109,10 @@
{
if (mOwner == ownHandle) {
mBufferMapper.unregisterBuffer(handle);
- native_handle_close(handle);
- native_handle_delete(const_cast<native_handle*>(handle));
+ if (!mBufferMapper.getGrallocMapper().valid()) {
+ native_handle_close(handle);
+ native_handle_delete(const_cast<native_handle*>(handle));
+ }
} else if (mOwner == ownData) {
GraphicBufferAllocator& allocator(GraphicBufferAllocator::get());
allocator.free(handle);
diff --git a/libs/ui/GraphicBufferAllocator.cpp b/libs/ui/GraphicBufferAllocator.cpp
index edfff4d..693c7cb 100644
--- a/libs/ui/GraphicBufferAllocator.cpp
+++ b/libs/ui/GraphicBufferAllocator.cpp
@@ -26,6 +26,9 @@
#include <ui/GraphicBufferAllocator.h>
#include <ui/Gralloc1On0Adapter.h>
+#include <ui/GrallocAllocator.h>
+#include <ui/GrallocMapper.h>
+#include <ui/GraphicBufferMapper.h>
namespace android {
// ---------------------------------------------------------------------------
@@ -37,8 +40,14 @@
GraphicBufferAllocator::alloc_rec_t> GraphicBufferAllocator::sAllocList;
GraphicBufferAllocator::GraphicBufferAllocator()
- : mLoader(std::make_unique<Gralloc1::Loader>()),
- mDevice(mLoader->getDevice()) {}
+ : mAllocator(std::make_unique<Gralloc2::Allocator>()),
+ mMapper(GraphicBufferMapper::getInstance())
+{
+ if (!mAllocator->valid()) {
+ mLoader = std::make_unique<Gralloc1::Loader>();
+ mDevice = mLoader->getDevice();
+ }
+}
GraphicBufferAllocator::~GraphicBufferAllocator() {}
@@ -70,7 +79,14 @@
}
snprintf(buffer, SIZE, "Total allocated (estimate): %.2f KB\n", total/1024.0f);
result.append(buffer);
- std::string deviceDump = mDevice->dump();
+
+ std::string deviceDump;
+ if (mAllocator->valid()) {
+ deviceDump = mAllocator->dumpDebugInfo();
+ } else {
+ deviceDump = mDevice->dump();
+ }
+
result.append(deviceDump.c_str(), deviceDump.size());
}
@@ -81,6 +97,103 @@
ALOGD("%s", s.string());
}
+namespace {
+
+class HalBuffer {
+public:
+ HalBuffer(const Gralloc2::Allocator* allocator,
+ uint32_t width, uint32_t height,
+ PixelFormat format, uint32_t usage)
+ : mAllocator(allocator), mBufferValid(false)
+ {
+ Gralloc2::IAllocator::BufferDescriptorInfo info = {};
+ info.width = width;
+ info.height = height;
+ info.format = static_cast<Gralloc2::PixelFormat>(format);
+ info.producerUsageMask = usage;
+ info.consumerUsageMask = usage;
+
+ Gralloc2::BufferDescriptor descriptor;
+ auto error = mAllocator->createBufferDescriptor(info, descriptor);
+ if (error != Gralloc2::Error::NONE) {
+ ALOGE("Failed to create desc (%u x %u) format %d usage %u: %d",
+ width, height, format, usage, error);
+ return;
+ }
+
+ error = mAllocator->allocate(descriptor, mBuffer);
+ if (error == Gralloc2::Error::NOT_SHARED) {
+ error = Gralloc2::Error::NONE;
+ }
+
+ if (error != Gralloc2::Error::NONE) {
+ ALOGE("Failed to allocate (%u x %u) format %d usage %u: %d",
+ width, height, format, usage, error);
+ mAllocator->destroyBufferDescriptor(descriptor);
+ return;
+ }
+
+ error = mAllocator->exportHandle(descriptor, mBuffer, mHandle);
+ if (error != Gralloc2::Error::NONE) {
+ ALOGE("Failed to export handle");
+ mAllocator->free(mBuffer);
+ mAllocator->destroyBufferDescriptor(descriptor);
+ return;
+ }
+
+ mAllocator->destroyBufferDescriptor(descriptor);
+
+ mBufferValid = true;
+ }
+
+ ~HalBuffer()
+ {
+ if (mBufferValid) {
+ if (mHandle) {
+ native_handle_close(mHandle);
+ native_handle_delete(mHandle);
+ }
+
+ mAllocator->free(mBuffer);
+ }
+ }
+
+ bool exportHandle(GraphicBufferMapper& mapper,
+ buffer_handle_t* handle, uint32_t* stride)
+ {
+ if (!mBufferValid) {
+ return false;
+ }
+
+ if (mapper.registerBuffer(mHandle)) {
+ return false;
+ }
+
+ *handle = mHandle;
+
+ auto error = mapper.getGrallocMapper().getStride(mHandle, *stride);
+ if (error != Gralloc2::Error::NONE) {
+ ALOGW("Failed to get stride from buffer: %d", error);
+ *stride = 0;
+ }
+
+ mHandle = nullptr;
+ mAllocator->free(mBuffer);
+ mBufferValid = false;
+
+ return true;
+ }
+
+private:
+ const Gralloc2::Allocator* mAllocator;
+
+ bool mBufferValid;
+ Gralloc2::Buffer mBuffer;
+ native_handle_t* mHandle;
+};
+
+} // namespace
+
status_t GraphicBufferAllocator::allocate(uint32_t width, uint32_t height,
PixelFormat format, uint32_t usage, buffer_handle_t* handle,
uint32_t* stride, uint64_t graphicBufferId, std::string requestorName)
@@ -95,40 +208,51 @@
// Filter out any usage bits that should not be passed to the gralloc module
usage &= GRALLOC_USAGE_ALLOC_MASK;
- auto descriptor = mDevice->createDescriptor();
- auto error = descriptor->setDimensions(width, height);
- if (error != GRALLOC1_ERROR_NONE) {
- ALOGE("Failed to set dimensions to (%u, %u): %d", width, height, error);
- return BAD_VALUE;
- }
- error = descriptor->setFormat(static_cast<android_pixel_format_t>(format));
- if (error != GRALLOC1_ERROR_NONE) {
- ALOGE("Failed to set format to %d: %d", format, error);
- return BAD_VALUE;
- }
- error = descriptor->setProducerUsage(
- static_cast<gralloc1_producer_usage_t>(usage));
- if (error != GRALLOC1_ERROR_NONE) {
- ALOGE("Failed to set producer usage to %u: %d", usage, error);
- return BAD_VALUE;
- }
- error = descriptor->setConsumerUsage(
- static_cast<gralloc1_consumer_usage_t>(usage));
- if (error != GRALLOC1_ERROR_NONE) {
- ALOGE("Failed to set consumer usage to %u: %d", usage, error);
- return BAD_VALUE;
- }
+ gralloc1_error_t error;
+ if (mAllocator->valid()) {
+ HalBuffer buffer(mAllocator.get(), width, height, format, usage);
+ if (!buffer.exportHandle(mMapper, handle, stride)) {
+ return NO_MEMORY;
+ }
+ error = GRALLOC1_ERROR_NONE;
+ } else {
+ auto descriptor = mDevice->createDescriptor();
+ error = descriptor->setDimensions(width, height);
+ if (error != GRALLOC1_ERROR_NONE) {
+ ALOGE("Failed to set dimensions to (%u, %u): %d",
+ width, height, error);
+ return BAD_VALUE;
+ }
+ error = descriptor->setFormat(
+ static_cast<android_pixel_format_t>(format));
+ if (error != GRALLOC1_ERROR_NONE) {
+ ALOGE("Failed to set format to %d: %d", format, error);
+ return BAD_VALUE;
+ }
+ error = descriptor->setProducerUsage(
+ static_cast<gralloc1_producer_usage_t>(usage));
+ if (error != GRALLOC1_ERROR_NONE) {
+ ALOGE("Failed to set producer usage to %u: %d", usage, error);
+ return BAD_VALUE;
+ }
+ error = descriptor->setConsumerUsage(
+ static_cast<gralloc1_consumer_usage_t>(usage));
+ if (error != GRALLOC1_ERROR_NONE) {
+ ALOGE("Failed to set consumer usage to %u: %d", usage, error);
+ return BAD_VALUE;
+ }
- error = mDevice->allocate(descriptor, graphicBufferId, handle);
- if (error != GRALLOC1_ERROR_NONE) {
- ALOGE("Failed to allocate (%u x %u) format %d usage %u: %d",
- width, height, format, usage, error);
- return NO_MEMORY;
- }
+ error = mDevice->allocate(descriptor, graphicBufferId, handle);
+ if (error != GRALLOC1_ERROR_NONE) {
+ ALOGE("Failed to allocate (%u x %u) format %d usage %u: %d",
+ width, height, format, usage, error);
+ return NO_MEMORY;
+ }
- error = mDevice->getStride(*handle, stride);
- if (error != GRALLOC1_ERROR_NONE) {
- ALOGW("Failed to get stride from buffer: %d", error);
+ error = mDevice->getStride(*handle, stride);
+ if (error != GRALLOC1_ERROR_NONE) {
+ ALOGW("Failed to get stride from buffer: %d", error);
+ }
}
if (error == NO_ERROR) {
@@ -153,7 +277,14 @@
{
ATRACE_CALL();
- auto error = mDevice->release(handle);
+ gralloc1_error_t error;
+ if (mAllocator->valid()) {
+ error = static_cast<gralloc1_error_t>(
+ mMapper.unregisterBuffer(handle));
+ } else {
+ error = mDevice->release(handle);
+ }
+
if (error != GRALLOC1_ERROR_NONE) {
ALOGE("Failed to free buffer: %d", error);
}
diff --git a/libs/ui/GraphicBufferMapper.cpp b/libs/ui/GraphicBufferMapper.cpp
index 481d43c..fb55bf1 100644
--- a/libs/ui/GraphicBufferMapper.cpp
+++ b/libs/ui/GraphicBufferMapper.cpp
@@ -33,6 +33,7 @@
#include <utils/Trace.h>
#include <ui/Gralloc1On0Adapter.h>
+#include <ui/GrallocMapper.h>
#include <ui/GraphicBufferMapper.h>
#include <ui/Rect.h>
@@ -44,8 +45,13 @@
ANDROID_SINGLETON_STATIC_INSTANCE( GraphicBufferMapper )
GraphicBufferMapper::GraphicBufferMapper()
- : mLoader(std::make_unique<Gralloc1::Loader>()),
- mDevice(mLoader->getDevice()) {}
+ : mMapper(std::make_unique<const Gralloc2::Mapper>())
+{
+ if (!mMapper->valid()) {
+ mLoader = std::make_unique<Gralloc1::Loader>();
+ mDevice = mLoader->getDevice();
+ }
+}
@@ -53,7 +59,13 @@
{
ATRACE_CALL();
- gralloc1_error_t error = mDevice->retain(handle);
+ gralloc1_error_t error;
+ if (mMapper->valid()) {
+ error = static_cast<gralloc1_error_t>(mMapper->retain(handle));
+ } else {
+ error = mDevice->retain(handle);
+ }
+
ALOGW_IF(error != GRALLOC1_ERROR_NONE, "registerBuffer(%p) failed: %d",
handle, error);
@@ -64,7 +76,14 @@
{
ATRACE_CALL();
- gralloc1_error_t error = mDevice->retain(buffer);
+ gralloc1_error_t error;
+ if (mMapper->valid()) {
+ error = static_cast<gralloc1_error_t>(
+ mMapper->retain(buffer->getNativeBuffer()->handle));
+ } else {
+ error = mDevice->retain(buffer);
+ }
+
ALOGW_IF(error != GRALLOC1_ERROR_NONE, "registerBuffer(%p) failed: %d",
buffer->getNativeBuffer()->handle, error);
@@ -75,7 +94,14 @@
{
ATRACE_CALL();
- gralloc1_error_t error = mDevice->release(handle);
+ gralloc1_error_t error;
+ if (mMapper->valid()) {
+ mMapper->release(handle);
+ error = GRALLOC1_ERROR_NONE;
+ } else {
+ error = mDevice->release(handle);
+ }
+
ALOGW_IF(error != GRALLOC1_ERROR_NONE, "unregisterBuffer(%p): failed %d",
handle, error);
@@ -120,11 +146,20 @@
ATRACE_CALL();
gralloc1_rect_t accessRegion = asGralloc1Rect(bounds);
- sp<Fence> fence = new Fence(fenceFd);
- gralloc1_error_t error = mDevice->lock(handle,
- static_cast<gralloc1_producer_usage_t>(usage),
- static_cast<gralloc1_consumer_usage_t>(usage),
- &accessRegion, vaddr, fence);
+ gralloc1_error_t error;
+ if (mMapper->valid()) {
+ const Gralloc2::Device::Rect& accessRect =
+ *reinterpret_cast<Gralloc2::Device::Rect*>(&accessRegion);
+ error = static_cast<gralloc1_error_t>(mMapper->lock(
+ handle, usage, usage, accessRect, fenceFd, *vaddr));
+ } else {
+ sp<Fence> fence = new Fence(fenceFd);
+ error = mDevice->lock(handle,
+ static_cast<gralloc1_producer_usage_t>(usage),
+ static_cast<gralloc1_consumer_usage_t>(usage),
+ &accessRegion, vaddr, fence);
+ }
+
ALOGW_IF(error != GRALLOC1_ERROR_NONE, "lock(%p, ...) failed: %d", handle,
error);
@@ -160,20 +195,29 @@
ATRACE_CALL();
gralloc1_rect_t accessRegion = asGralloc1Rect(bounds);
- sp<Fence> fence = new Fence(fenceFd);
- if (mDevice->hasCapability(GRALLOC1_CAPABILITY_ON_ADAPTER)) {
- gralloc1_error_t error = mDevice->lockYCbCr(handle,
- static_cast<gralloc1_producer_usage_t>(usage),
- static_cast<gralloc1_consumer_usage_t>(usage),
- &accessRegion, ycbcr, fence);
- ALOGW_IF(error != GRALLOC1_ERROR_NONE, "lockYCbCr(%p, ...) failed: %d",
- handle, error);
- return error;
+ if (!mMapper->valid()) {
+ if (mDevice->hasCapability(GRALLOC1_CAPABILITY_ON_ADAPTER)) {
+ sp<Fence> fence = new Fence(fenceFd);
+ gralloc1_error_t error = mDevice->lockYCbCr(handle,
+ static_cast<gralloc1_producer_usage_t>(usage),
+ static_cast<gralloc1_consumer_usage_t>(usage),
+ &accessRegion, ycbcr, fence);
+ ALOGW_IF(error != GRALLOC1_ERROR_NONE,
+ "lockYCbCr(%p, ...) failed: %d", handle, error);
+ return error;
+ }
}
uint32_t numPlanes = 0;
- gralloc1_error_t error = mDevice->getNumFlexPlanes(handle, &numPlanes);
+ gralloc1_error_t error;
+ if (mMapper->valid()) {
+ error = static_cast<gralloc1_error_t>(
+ mMapper->getNumFlexPlanes(handle, numPlanes));
+ } else {
+ error = mDevice->getNumFlexPlanes(handle, &numPlanes);
+ }
+
if (error != GRALLOC1_ERROR_NONE) {
ALOGV("Failed to retrieve number of flex planes: %d", error);
return error;
@@ -188,10 +232,21 @@
flexLayout.num_planes = numPlanes;
flexLayout.planes = planes.data();
- error = mDevice->lockFlex(handle,
- static_cast<gralloc1_producer_usage_t>(usage),
- static_cast<gralloc1_consumer_usage_t>(usage),
- &accessRegion, &flexLayout, fence);
+ if (mMapper->valid()) {
+ const Gralloc2::Device::Rect& accessRect =
+ *reinterpret_cast<Gralloc2::Device::Rect*>(&accessRegion);
+ Gralloc2::FlexLayout& layout =
+ *reinterpret_cast<Gralloc2::FlexLayout*>(&flexLayout);
+ error = static_cast<gralloc1_error_t>(mMapper->lock(
+ handle, usage, usage, accessRect, fenceFd, layout));
+ } else {
+ sp<Fence> fence = new Fence(fenceFd);
+ error = mDevice->lockFlex(handle,
+ static_cast<gralloc1_producer_usage_t>(usage),
+ static_cast<gralloc1_consumer_usage_t>(usage),
+ &accessRegion, &flexLayout, fence);
+ }
+
if (error != GRALLOC1_ERROR_NONE) {
ALOGW("lockFlex(%p, ...) failed: %d", handle, error);
return error;
@@ -276,14 +331,20 @@
{
ATRACE_CALL();
- sp<Fence> fence = Fence::NO_FENCE;
- gralloc1_error_t error = mDevice->unlock(handle, &fence);
- if (error != GRALLOC1_ERROR_NONE) {
- ALOGE("unlock(%p) failed: %d", handle, error);
- return error;
- }
+ gralloc1_error_t error;
+ if (mMapper->valid()) {
+ *fenceFd = mMapper->unlock(handle);
+ error = GRALLOC1_ERROR_NONE;
+ } else {
+ sp<Fence> fence = Fence::NO_FENCE;
+ error = mDevice->unlock(handle, &fence);
+ if (error != GRALLOC1_ERROR_NONE) {
+ ALOGE("unlock(%p) failed: %d", handle, error);
+ return error;
+ }
- *fenceFd = fence->dup();
+ *fenceFd = fence->dup();
+ }
return error;
}
diff --git a/opengl/libs/Android.bp b/opengl/libs/Android.bp
index bdd5152..6a8aac8 100644
--- a/opengl/libs/Android.bp
+++ b/opengl/libs/Android.bp
@@ -45,3 +45,116 @@
symbol_file: "libGLESv3.map.txt",
first_version: "18",
}
+
+cc_defaults {
+ name: "gl_libs_defaults",
+ cflags: [
+ "-DGL_GLEXT_PROTOTYPES",
+ "-DEGL_EGLEXT_PROTOTYPES",
+ "-fvisibility=hidden",
+ ],
+ shared_libs: [
+ "libcutils",
+ "liblog",
+ "libdl",
+ ],
+
+ // we need to access the private Bionic header <bionic_tls.h>
+ include_dirs: ["bionic/libc/private"],
+}
+
+//##############################################################################
+// Build META EGL library
+//
+cc_defaults {
+ name: "egl_libs_defaults",
+ defaults: ["gl_libs_defaults"],
+ cflags: [
+ "-DLOG_TAG=\"libEGL\"",
+ ],
+ shared_libs: [
+ "libbinder",
+ "libutils",
+ "libui",
+ ],
+}
+
+cc_library_static {
+ name: "libEGL_getProcAddress",
+ defaults: ["egl_libs_defaults"],
+ srcs: ["EGL/getProcAddress.cpp"],
+ arch: {
+ arm: {
+ instruction_set: "arm",
+ },
+ },
+}
+
+cc_library_shared {
+ name: "libEGL",
+ defaults: ["egl_libs_defaults"],
+ srcs: [
+ "EGL/egl_tls.cpp",
+ "EGL/egl_cache.cpp",
+ "EGL/egl_display.cpp",
+ "EGL/egl_object.cpp",
+ "EGL/egl.cpp",
+ "EGL/eglApi.cpp",
+ "EGL/Loader.cpp",
+ ],
+ static_libs: ["libEGL_getProcAddress"],
+ ldflags: ["-Wl,--exclude-libs=ALL"],
+
+ required: ["egl.cfg"],
+}
+
+cc_defaults {
+ name: "gles_libs_defaults",
+ defaults: ["gl_libs_defaults"],
+ arch: {
+ arm: {
+ instruction_set: "arm",
+
+ // TODO: This is to work around b/20093774. Remove after root cause is fixed
+ ldflags: ["-Wl,--hash-style,both"],
+ },
+ },
+ shared_libs: ["libEGL"],
+}
+
+//##############################################################################
+// Build the wrapper OpenGL ES 1.x library
+//
+cc_library_shared {
+ name: "libGLESv1_CM",
+ defaults: ["gles_libs_defaults"],
+ srcs: ["GLES_CM/gl.cpp"],
+
+ cflags: ["-DLOG_TAG=\"libGLESv1\""],
+}
+
+//##############################################################################
+// Build the wrapper OpenGL ES 2.x library
+//
+cc_library_shared {
+ name: "libGLESv2",
+ defaults: ["gles_libs_defaults"],
+ srcs: ["GLES2/gl2.cpp"],
+
+ shared_libs: ["libutils"],
+
+ cflags: ["-DLOG_TAG=\"libGLESv2\""],
+}
+
+//##############################################################################
+// Build the wrapper OpenGL ES 3.x library (this is just different name for v2)
+//
+cc_library_shared {
+ name: "libGLESv3",
+ defaults: ["gles_libs_defaults"],
+ srcs: ["GLES2/gl2.cpp"],
+
+ shared_libs: ["libutils"],
+
+ cflags: ["-DLOG_TAG=\"libGLESv3\""],
+}
diff --git a/opengl/libs/Android.mk b/opengl/libs/Android.mk
index f0ba728..21e76f5 100644
--- a/opengl/libs/Android.mk
+++ b/opengl/libs/Android.mk
@@ -1,13 +1,7 @@
LOCAL_PATH:= $(call my-dir)
-###############################################################################
-# Build META EGL library
-#
-
-egl.cfg_config_module :=
# OpenGL drivers config file
ifneq ($(BOARD_EGL_CFG),)
-
include $(CLEAR_VARS)
LOCAL_MODULE := egl.cfg
LOCAL_MODULE_TAGS := optional
@@ -15,136 +9,4 @@
LOCAL_MODULE_PATH := $(TARGET_OUT)/lib/egl
LOCAL_SRC_FILES := ../../../../$(BOARD_EGL_CFG)
include $(BUILD_PREBUILT)
-egl.cfg_config_module := $(LOCAL_MODULE)
endif
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
- EGL/egl_tls.cpp \
- EGL/egl_cache.cpp \
- EGL/egl_display.cpp \
- EGL/egl_object.cpp \
- EGL/egl.cpp \
- EGL/eglApi.cpp \
- EGL/getProcAddress.cpp.arm \
- EGL/Loader.cpp \
-#
-
-LOCAL_SHARED_LIBRARIES += libbinder libcutils libutils liblog libui
-LOCAL_MODULE:= libEGL
-LOCAL_LDFLAGS += -Wl,--exclude-libs=ALL
-LOCAL_SHARED_LIBRARIES += libdl
-# we need to access the private Bionic header <bionic_tls.h>
-LOCAL_C_INCLUDES += bionic/libc/private
-
-LOCAL_CFLAGS += -DLOG_TAG=\"libEGL\"
-LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
-LOCAL_CFLAGS += -fvisibility=hidden
-
-ifeq ($(BOARD_ALLOW_EGL_HIBERNATION),true)
- LOCAL_CFLAGS += -DBOARD_ALLOW_EGL_HIBERNATION
-endif
-ifneq ($(MAX_EGL_CACHE_ENTRY_SIZE),)
- LOCAL_CFLAGS += -DMAX_EGL_CACHE_ENTRY_SIZE=$(MAX_EGL_CACHE_ENTRY_SIZE)
-endif
-
-ifneq ($(MAX_EGL_CACHE_KEY_SIZE),)
- LOCAL_CFLAGS += -DMAX_EGL_CACHE_KEY_SIZE=$(MAX_EGL_CACHE_KEY_SIZE)
-endif
-
-ifneq ($(MAX_EGL_CACHE_SIZE),)
- LOCAL_CFLAGS += -DMAX_EGL_CACHE_SIZE=$(MAX_EGL_CACHE_SIZE)
-endif
-
-ifneq ($(filter address,$(SANITIZE_TARGET)),)
- LOCAL_CFLAGS_32 += -DEGL_WRAPPER_DIR=\"/$(TARGET_COPY_OUT_DATA)/lib\"
- LOCAL_CFLAGS_64 += -DEGL_WRAPPER_DIR=\"/$(TARGET_COPY_OUT_DATA)/lib64\"
-endif
-
-LOCAL_REQUIRED_MODULES := $(egl.cfg_config_module)
-egl.cfg_config_module :=
-
-include $(BUILD_SHARED_LIBRARY)
-
-###############################################################################
-# Build the wrapper OpenGL ES 1.x library
-#
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
- GLES_CM/gl.cpp.arm \
-#
-
-LOCAL_SHARED_LIBRARIES += libcutils liblog libEGL
-LOCAL_MODULE:= libGLESv1_CM
-
-LOCAL_SHARED_LIBRARIES += libdl
-# we need to access the private Bionic header <bionic_tls.h>
-LOCAL_C_INCLUDES += bionic/libc/private
-
-LOCAL_CFLAGS += -DLOG_TAG=\"libGLESv1\"
-LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
-LOCAL_CFLAGS += -fvisibility=hidden
-
-# TODO: This is to work around b/20093774. Remove after root cause is fixed
-LOCAL_LDFLAGS_arm += -Wl,--hash-style,both
-
-include $(BUILD_SHARED_LIBRARY)
-
-
-###############################################################################
-# Build the wrapper OpenGL ES 2.x library
-#
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
- GLES2/gl2.cpp \
-#
-
-LOCAL_ARM_MODE := arm
-LOCAL_SHARED_LIBRARIES += libcutils libutils liblog libEGL
-LOCAL_MODULE:= libGLESv2
-
-LOCAL_SHARED_LIBRARIES += libdl
-# we need to access the private Bionic header <bionic_tls.h>
-LOCAL_C_INCLUDES += bionic/libc/private
-
-LOCAL_CFLAGS += -DLOG_TAG=\"libGLESv2\"
-LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
-LOCAL_CFLAGS += -fvisibility=hidden
-
-# TODO: This is to work around b/20093774. Remove after root cause is fixed
-LOCAL_LDFLAGS_arm += -Wl,--hash-style,both
-
-include $(BUILD_SHARED_LIBRARY)
-
-###############################################################################
-# Build the wrapper OpenGL ES 3.x library (this is just different name for v2)
-#
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
- GLES2/gl2.cpp \
-#
-
-LOCAL_ARM_MODE := arm
-LOCAL_SHARED_LIBRARIES += libcutils libutils liblog libEGL
-LOCAL_MODULE:= libGLESv3
-LOCAL_SHARED_LIBRARIES += libdl
-# we need to access the private Bionic header <bionic_tls.h>
-LOCAL_C_INCLUDES += bionic/libc/private
-
-LOCAL_CFLAGS += -DLOG_TAG=\"libGLESv3\"
-LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
-LOCAL_CFLAGS += -fvisibility=hidden
-
-# TODO: This is to work around b/20093774. Remove after root cause is fixed
-LOCAL_LDFLAGS_arm += -Wl,--hash-style,both
-
-include $(BUILD_SHARED_LIBRARY)
-
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/opengl/libs/EGL/egl_cache.cpp b/opengl/libs/EGL/egl_cache.cpp
index 8c135c8..1fe322d 100644
--- a/opengl/libs/EGL/egl_cache.cpp
+++ b/opengl/libs/EGL/egl_cache.cpp
@@ -27,22 +27,10 @@
#include <sys/types.h>
#include <unistd.h>
-#ifndef MAX_EGL_CACHE_ENTRY_SIZE
-#define MAX_EGL_CACHE_ENTRY_SIZE (16 * 1024);
-#endif
-
-#ifndef MAX_EGL_CACHE_KEY_SIZE
-#define MAX_EGL_CACHE_KEY_SIZE (1024);
-#endif
-
-#ifndef MAX_EGL_CACHE_SIZE
-#define MAX_EGL_CACHE_SIZE (64 * 1024);
-#endif
-
// Cache size limits.
-static const size_t maxKeySize = MAX_EGL_CACHE_KEY_SIZE;
-static const size_t maxValueSize = MAX_EGL_CACHE_ENTRY_SIZE;
-static const size_t maxTotalSize = MAX_EGL_CACHE_SIZE;
+static const size_t maxKeySize = 12 * 1024;
+static const size_t maxValueSize = 64 * 1024;
+static const size_t maxTotalSize = 2 * 1024 * 1024;
// Cache file header
static const char* cacheFileMagic = "EGL$";
diff --git a/opengl/libs/EGL/egl_display.cpp b/opengl/libs/EGL/egl_display.cpp
index 1e39aae..a32f037 100644
--- a/opengl/libs/EGL/egl_display.cpp
+++ b/opengl/libs/EGL/egl_display.cpp
@@ -215,8 +215,6 @@
*major = VERSION_MAJOR;
if (minor != NULL)
*minor = VERSION_MINOR;
-
- mHibernation.setDisplayValid(true);
}
{
@@ -265,8 +263,6 @@
res = EGL_TRUE;
}
- mHibernation.setDisplayValid(false);
-
// Reset the extension string since it will be regenerated if we get
// reinitialized.
mExtensionString.setTo("");
@@ -345,16 +341,12 @@
disp.dpy, impl_draw, impl_read, impl_ctx);
if (result == EGL_TRUE) {
c->onMakeCurrent(draw, read);
- if (!cur_c) {
- mHibernation.incWakeCount(HibernationMachine::STRONG);
- }
}
} else {
result = cur_c->cnx->egl.eglMakeCurrent(
disp.dpy, impl_draw, impl_read, impl_ctx);
if (result == EGL_TRUE) {
cur_c->onLooseCurrent();
- mHibernation.decWakeCount(HibernationMachine::STRONG);
}
}
}
@@ -379,63 +371,5 @@
}
// ----------------------------------------------------------------------------
-
-bool egl_display_t::HibernationMachine::incWakeCount(WakeRefStrength strength) {
- Mutex::Autolock _l(mLock);
- ALOGE_IF(mWakeCount < 0 || mWakeCount == INT32_MAX,
- "Invalid WakeCount (%d) on enter\n", mWakeCount);
-
- mWakeCount++;
- if (strength == STRONG)
- mAttemptHibernation = false;
-
- if (CC_UNLIKELY(mHibernating)) {
- ALOGV("Awakening\n");
- egl_connection_t* const cnx = &gEGLImpl;
-
- // These conditions should be guaranteed before entering hibernation;
- // we don't want to get into a state where we can't wake up.
- ALOGD_IF(!mDpyValid || !cnx->egl.eglAwakenProcessIMG,
- "Invalid hibernation state, unable to awaken\n");
-
- if (!cnx->egl.eglAwakenProcessIMG()) {
- ALOGE("Failed to awaken EGL implementation\n");
- return false;
- }
- mHibernating = false;
- }
- return true;
-}
-
-void egl_display_t::HibernationMachine::decWakeCount(WakeRefStrength strength) {
- Mutex::Autolock _l(mLock);
- ALOGE_IF(mWakeCount <= 0, "Invalid WakeCount (%d) on leave\n", mWakeCount);
-
- mWakeCount--;
- if (strength == STRONG)
- mAttemptHibernation = true;
-
- if (mWakeCount == 0 && CC_UNLIKELY(mAttemptHibernation)) {
- egl_connection_t* const cnx = &gEGLImpl;
- mAttemptHibernation = false;
- if (mAllowHibernation && mDpyValid &&
- cnx->egl.eglHibernateProcessIMG &&
- cnx->egl.eglAwakenProcessIMG) {
- ALOGV("Hibernating\n");
- if (!cnx->egl.eglHibernateProcessIMG()) {
- ALOGE("Failed to hibernate EGL implementation\n");
- return;
- }
- mHibernating = true;
- }
- }
-}
-
-void egl_display_t::HibernationMachine::setDisplayValid(bool valid) {
- Mutex::Autolock _l(mLock);
- mDpyValid = valid;
-}
-
-// ----------------------------------------------------------------------------
}; // namespace android
// ----------------------------------------------------------------------------
diff --git a/opengl/libs/EGL/egl_display.h b/opengl/libs/EGL/egl_display.h
index 2d86295..e17558c 100644
--- a/opengl/libs/EGL/egl_display.h
+++ b/opengl/libs/EGL/egl_display.h
@@ -68,20 +68,6 @@
// add reference to this object. returns true if this is a valid object.
bool getObject(egl_object_t* object) const;
- // These notifications allow the display to keep track of how many window
- // surfaces exist, which it uses to decide whether to hibernate the
- // underlying EGL implementation. They can be called by any thread without
- // holding a lock, but must be called via egl_display_ptr to ensure
- // proper hibernate/wakeup sequencing. If a surface destruction triggers
- // hibernation, hibernation will be delayed at least until the calling
- // thread's egl_display_ptr is destroyed.
- void onWindowSurfaceCreated() {
- mHibernation.incWakeCount(HibernationMachine::STRONG);
- }
- void onWindowSurfaceDestroyed() {
- mHibernation.decWakeCount(HibernationMachine::STRONG);
- }
-
static egl_display_t* get(EGLDisplay dpy);
static EGLDisplay getFromNativeDisplay(EGLNativeDisplayType disp);
@@ -127,8 +113,6 @@
private:
friend class egl_display_ptr;
- bool enter() { return mHibernation.incWakeCount(HibernationMachine::WEAK); }
- void leave() { return mHibernation.decWakeCount(HibernationMachine::WEAK); }
uint32_t refs;
bool eglIsInitialized;
@@ -139,47 +123,6 @@
String8 mVersionString;
String8 mClientApiString;
String8 mExtensionString;
-
- // HibernationMachine uses its own internal mutex to protect its own data.
- // The owning egl_display_t's lock may be but is not required to be held
- // when calling HibernationMachine methods. As a result, nothing in this
- // class may call back up to egl_display_t directly or indirectly.
- class HibernationMachine {
- public:
- // STRONG refs cancel (inc) or initiate (dec) a hibernation attempt
- // the next time the wakecount reaches zero. WEAK refs don't affect
- // whether a hibernation attempt will be made. Use STRONG refs only
- // for infrequent/heavy changes that are likely to indicate the
- // EGLDisplay is entering or leaving a long-term idle state.
- enum WakeRefStrength {
- WEAK = 0,
- STRONG = 1,
- };
-
- HibernationMachine(): mWakeCount(0), mHibernating(false),
- mAttemptHibernation(false), mDpyValid(false),
-#if BOARD_ALLOW_EGL_HIBERNATION
- mAllowHibernation(true)
-#else
- mAllowHibernation(false)
-#endif
- {}
- ~HibernationMachine() {}
-
- bool incWakeCount(WakeRefStrength strenth);
- void decWakeCount(WakeRefStrength strenth);
-
- void setDisplayValid(bool valid);
-
- private:
- Mutex mLock;
- int32_t mWakeCount;
- bool mHibernating;
- bool mAttemptHibernation;
- bool mDpyValid;
- const bool mAllowHibernation;
- };
- HibernationMachine mHibernation;
};
// ----------------------------------------------------------------------------
@@ -190,13 +133,7 @@
// as the egl_display_ptr exists.
class egl_display_ptr {
public:
- explicit egl_display_ptr(egl_display_t* dpy): mDpy(dpy) {
- if (mDpy) {
- if (CC_UNLIKELY(!mDpy->enter())) {
- mDpy = NULL;
- }
- }
- }
+ explicit egl_display_ptr(egl_display_t* dpy): mDpy(dpy) {}
// We only really need a C++11 move constructor, not a copy constructor.
// A move constructor would save an enter()/leave() pair on every EGL API
@@ -208,17 +145,9 @@
// other.mDpy = NULL;
// }
//
- egl_display_ptr(const egl_display_ptr& other): mDpy(other.mDpy) {
- if (mDpy) {
- mDpy->enter();
- }
- }
+ egl_display_ptr(const egl_display_ptr& other): mDpy(other.mDpy) {}
- ~egl_display_ptr() {
- if (mDpy) {
- mDpy->leave();
- }
- }
+ ~egl_display_ptr() {}
const egl_display_t* operator->() const { return mDpy; }
egl_display_t* operator->() { return mDpy; }
diff --git a/opengl/libs/EGL/egl_object.cpp b/opengl/libs/EGL/egl_object.cpp
index cfecf77..6a76737 100644
--- a/opengl/libs/EGL/egl_object.cpp
+++ b/opengl/libs/EGL/egl_object.cpp
@@ -69,17 +69,12 @@
egl_connection_t const* cnx) :
egl_object_t(dpy), surface(surface), config(config), win(win), cnx(cnx),
enableTimestamps(false), connected(true)
-{
- if (win) {
- getDisplay()->onWindowSurfaceCreated();
- }
-}
+{}
egl_surface_t::~egl_surface_t() {
ANativeWindow* const window = win.get();
if (window != NULL) {
disconnect();
- getDisplay()->onWindowSurfaceDestroyed();
}
}
diff --git a/services/sensorservice/Android.mk b/services/sensorservice/Android.mk
index 7b10319..d6e6187 100644
--- a/services/sensorservice/Android.mk
+++ b/services/sensorservice/Android.mk
@@ -10,7 +10,6 @@
OrientationSensor.cpp \
RecentEventLogger.cpp \
RotationVectorSensor.cpp \
- SensorDevice.cpp \
SensorEventConnection.cpp \
SensorFusion.cpp \
SensorInterface.cpp \
@@ -19,13 +18,19 @@
SensorService.cpp \
SensorServiceUtils.cpp \
-
LOCAL_CFLAGS:= -DLOG_TAG=\"SensorService\"
LOCAL_CFLAGS += -Wall -Werror -Wextra
LOCAL_CFLAGS += -fvisibility=hidden
+ifeq ($(ENABLE_TREBLE), true)
+LOCAL_SRC_FILES += SensorDeviceTreble.cpp
+LOCAL_CFLAGS += -DENABLE_TREBLE=1
+else
+LOCAL_SRC_FILES += SensorDevice.cpp
+endif
+
LOCAL_SHARED_LIBRARIES := \
libcutils \
libhardware \
@@ -35,7 +40,20 @@
libbinder \
libui \
libgui \
- libcrypto
+ libcrypto \
+
+ifeq ($(ENABLE_TREBLE), true)
+
+LOCAL_SHARED_LIBRARIES += \
+ libbase \
+ libhidl \
+ libhwbinder \
+ android.hardware.sensors@1.0
+
+LOCAL_STATIC_LIBRARIES := \
+ android.hardware.sensors@1.0-convert
+
+endif # ENABLE_TREBLE
LOCAL_MODULE:= libsensorservice
diff --git a/services/sensorservice/SensorDevice.h b/services/sensorservice/SensorDevice.h
index d340da3..0bb0752 100644
--- a/services/sensorservice/SensorDevice.h
+++ b/services/sensorservice/SensorDevice.h
@@ -27,19 +27,29 @@
#include <stdint.h>
#include <sys/types.h>
+#ifdef ENABLE_TREBLE
+#include <map>
+
+#include "android/hardware/sensors/1.0/ISensors.h"
+#endif
+
// ---------------------------------------------------------------------------
namespace android {
+
// ---------------------------------------------------------------------------
using SensorServiceUtil::Dumpable;
class SensorDevice : public Singleton<SensorDevice>, public Dumpable {
public:
ssize_t getSensorList(sensor_t const** list);
+
void handleDynamicSensorConnection(int handle, bool connected);
status_t initCheck() const;
int getHalDeviceVersion() const;
+
ssize_t poll(sensors_event_t* buffer, size_t count);
+
status_t activate(void* ident, int handle, int enabled);
status_t batch(void* ident, int handle, int flags, int64_t samplingPeriodNs,
int64_t maxBatchReportLatencyNs);
@@ -50,6 +60,7 @@
void disableAllSensors();
void enableAllSensors();
void autoDisable(void *ident, int handle);
+
status_t injectSensorData(const sensors_event_t *event);
void notifyConnectionDestroyed(void *ident);
@@ -57,8 +68,15 @@
virtual std::string dump() const;
private:
friend class Singleton<SensorDevice>;
+#ifdef ENABLE_TREBLE
+ sp<android::hardware::sensors::V1_0::ISensors> mSensors;
+ Vector<sensor_t> mSensorList;
+ std::map<int32_t, sensor_t*> mConnectedDynamicSensors;
+#else
sensors_poll_device_1_t* mSensorDevice;
struct sensors_module_t* mSensorModule;
+#endif
+
static const nsecs_t MINIMUM_EVENTS_PERIOD = 1000000; // 1000 Hz
mutable Mutex mLock; // protect mActivationCount[].batchParams
// fixed-size array after construction
@@ -111,6 +129,18 @@
bool isClientDisabled(void* ident);
bool isClientDisabledLocked(void* ident);
+
+#ifdef ENABLE_TREBLE
+ using Event = hardware::sensors::V1_0::Event;
+ using SensorInfo = hardware::sensors::V1_0::SensorInfo;
+
+ void convertToSensorEvent(const Event &src, sensors_event_t *dst);
+
+ void convertToSensorEvents(
+ const hardware::hidl_vec<Event> &src,
+ const hardware::hidl_vec<SensorInfo> &dynamicSensorsAdded,
+ sensors_event_t *dst);
+#endif // ENABLE_TREBLE
};
// ---------------------------------------------------------------------------
diff --git a/services/sensorservice/SensorDeviceTreble.cpp b/services/sensorservice/SensorDeviceTreble.cpp
new file mode 100644
index 0000000..22b1105
--- /dev/null
+++ b/services/sensorservice/SensorDeviceTreble.cpp
@@ -0,0 +1,610 @@
+/*
+ * Copyright (C) 2010 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 <inttypes.h>
+#include <math.h>
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <android-base/logging.h>
+#include <hidl/IServiceManager.h>
+#include <utils/Atomic.h>
+#include <utils/Errors.h>
+#include <utils/Singleton.h>
+
+#include "SensorDevice.h"
+#include "SensorService.h"
+
+#include "convert.h"
+
+using android::hardware::sensors::V1_0::ISensors;
+using android::hardware::hidl_vec;
+
+using Event = android::hardware::sensors::V1_0::Event;
+using SensorInfo = android::hardware::sensors::V1_0::SensorInfo;
+using SensorType = android::hardware::sensors::V1_0::SensorType;
+using DynamicSensorInfo = android::hardware::sensors::V1_0::DynamicSensorInfo;
+using SensorInfo = android::hardware::sensors::V1_0::SensorInfo;
+using Result = android::hardware::sensors::V1_0::Result;
+
+using namespace android::hardware::sensors::V1_0::implementation;
+
+namespace android {
+// ---------------------------------------------------------------------------
+
+ANDROID_SINGLETON_STATIC_INSTANCE(SensorDevice)
+
+static status_t StatusFromResult(Result result) {
+ switch (result) {
+ case Result::OK:
+ return OK;
+ case Result::BAD_VALUE:
+ return BAD_VALUE;
+ case Result::PERMISSION_DENIED:
+ return PERMISSION_DENIED;
+ case Result::INVALID_OPERATION:
+ return INVALID_OPERATION;
+ }
+}
+
+SensorDevice::SensorDevice() {
+ mSensors = ISensors::getService("sensors");
+
+ if (mSensors == NULL) {
+ return;
+ }
+
+ mSensors->getSensorsList(
+ [&](const auto &list) {
+ const size_t count = list.size();
+
+ mActivationCount.setCapacity(count);
+ Info model;
+ for (size_t i=0 ; i < count; i++) {
+ sensor_t sensor;
+ convertToSensor(list[i], &sensor);
+ mSensorList.push_back(sensor);
+
+ mActivationCount.add(list[i].sensorHandle, model);
+
+ /* auto result = */mSensors->activate(
+ list[i].sensorHandle, 0 /* enabled */);
+ }
+ });
+}
+
+void SensorDevice::handleDynamicSensorConnection(int handle, bool connected) {
+ if (connected) {
+ Info model;
+ mActivationCount.add(handle, model);
+ /* auto result = */mSensors->activate(handle, 0 /* enabled */);
+ } else {
+ mActivationCount.removeItem(handle);
+ }
+}
+
+std::string SensorDevice::dump() const {
+ if (mSensors == NULL) return "HAL not initialized\n";
+
+#if 0
+ result.appendFormat("HAL: %s (%s), version %#010x\n",
+ mSensorModule->common.name,
+ mSensorModule->common.author,
+ getHalDeviceVersion());
+#endif
+
+ String8 result;
+ mSensors->getSensorsList([&](const auto &list) {
+ const size_t count = list.size();
+
+ result.appendFormat(
+ "Total %zu h/w sensors, %zu running:\n",
+ count,
+ mActivationCount.size());
+
+ Mutex::Autolock _l(mLock);
+ for (size_t i = 0 ; i < count ; i++) {
+ const Info& info = mActivationCount.valueFor(
+ list[i].sensorHandle);
+
+ if (info.batchParams.isEmpty()) continue;
+ result.appendFormat(
+ "0x%08x) active-count = %zu; ",
+ list[i].sensorHandle,
+ info.batchParams.size());
+
+ result.append("sampling_period(ms) = {");
+ for (size_t j = 0; j < info.batchParams.size(); j++) {
+ const BatchParams& params = info.batchParams.valueAt(j);
+ result.appendFormat(
+ "%.1f%s",
+ params.batchDelay / 1e6f,
+ j < info.batchParams.size() - 1 ? ", " : "");
+ }
+ result.appendFormat(
+ "}, selected = %.1f ms; ",
+ info.bestBatchParams.batchDelay / 1e6f);
+
+ result.append("batching_period(ms) = {");
+ for (size_t j = 0; j < info.batchParams.size(); j++) {
+ BatchParams params = info.batchParams.valueAt(j);
+
+ result.appendFormat(
+ "%.1f%s",
+ params.batchTimeout / 1e6f,
+ j < info.batchParams.size() - 1 ? ", " : "");
+ }
+
+ result.appendFormat(
+ "}, selected = %.1f ms\n",
+ info.bestBatchParams.batchTimeout / 1e6f);
+ }
+ });
+
+ return result.string();
+}
+
+ssize_t SensorDevice::getSensorList(sensor_t const** list) {
+ *list = &mSensorList[0];
+
+ return mSensorList.size();
+}
+
+status_t SensorDevice::initCheck() const {
+ return mSensors != NULL ? NO_ERROR : NO_INIT;
+}
+
+ssize_t SensorDevice::poll(sensors_event_t* buffer, size_t count) {
+ if (mSensors == NULL) return NO_INIT;
+
+ ssize_t err;
+
+ mSensors->poll(
+ count,
+ [&](auto result,
+ const auto &events,
+ const auto &dynamicSensorsAdded) {
+ if (result == Result::OK) {
+ convertToSensorEvents(events, dynamicSensorsAdded, buffer);
+ err = (ssize_t)events.size();
+ } else {
+ err = StatusFromResult(result);
+ }
+ });
+
+ return err;
+}
+
+void SensorDevice::autoDisable(void *ident, int handle) {
+ Info& info( mActivationCount.editValueFor(handle) );
+ Mutex::Autolock _l(mLock);
+ info.removeBatchParamsForIdent(ident);
+}
+
+status_t SensorDevice::activate(void* ident, int handle, int enabled) {
+ if (mSensors == NULL) return NO_INIT;
+
+ status_t err(NO_ERROR);
+ bool actuateHardware = false;
+
+ Mutex::Autolock _l(mLock);
+ Info& info( mActivationCount.editValueFor(handle) );
+
+ ALOGD_IF(DEBUG_CONNECTIONS,
+ "SensorDevice::activate: ident=%p, handle=0x%08x, enabled=%d, count=%zu",
+ ident, handle, enabled, info.batchParams.size());
+
+ if (enabled) {
+ ALOGD_IF(DEBUG_CONNECTIONS, "enable index=%zd", info.batchParams.indexOfKey(ident));
+
+ if (isClientDisabledLocked(ident)) {
+ ALOGE("SensorDevice::activate, isClientDisabledLocked(%p):true, handle:%d",
+ ident, handle);
+ return INVALID_OPERATION;
+ }
+
+ if (info.batchParams.indexOfKey(ident) >= 0) {
+ if (info.numActiveClients() == 1) {
+ // This is the first connection, we need to activate the underlying h/w sensor.
+ actuateHardware = true;
+ }
+ } else {
+ // Log error. Every activate call should be preceded by a batch() call.
+ ALOGE("\t >>>ERROR: activate called without batch");
+ }
+ } else {
+ ALOGD_IF(DEBUG_CONNECTIONS, "disable index=%zd", info.batchParams.indexOfKey(ident));
+
+ // If a connected dynamic sensor is deactivated, remove it from the
+ // dictionary.
+ auto it = mConnectedDynamicSensors.find(handle);
+ if (it != mConnectedDynamicSensors.end()) {
+ delete it->second;
+ mConnectedDynamicSensors.erase(it);
+ }
+
+ if (info.removeBatchParamsForIdent(ident) >= 0) {
+ if (info.numActiveClients() == 0) {
+ // This is the last connection, we need to de-activate the underlying h/w sensor.
+ actuateHardware = true;
+ } else {
+ const int halVersion = getHalDeviceVersion();
+ if (halVersion >= SENSORS_DEVICE_API_VERSION_1_1) {
+ // Call batch for this sensor with the previously calculated best effort
+ // batch_rate and timeout. One of the apps has unregistered for sensor
+ // events, and the best effort batch parameters might have changed.
+ ALOGD_IF(DEBUG_CONNECTIONS,
+ "\t>>> actuating h/w batch %d %d %" PRId64 " %" PRId64, handle,
+ info.bestBatchParams.flags, info.bestBatchParams.batchDelay,
+ info.bestBatchParams.batchTimeout);
+ /* auto result = */mSensors->batch(
+ handle,
+ info.bestBatchParams.flags,
+ info.bestBatchParams.batchDelay,
+ info.bestBatchParams.batchTimeout);
+ }
+ }
+ } else {
+ // sensor wasn't enabled for this ident
+ }
+
+ if (isClientDisabledLocked(ident)) {
+ return NO_ERROR;
+ }
+ }
+
+ if (actuateHardware) {
+ ALOGD_IF(DEBUG_CONNECTIONS, "\t>>> actuating h/w activate handle=%d enabled=%d", handle,
+ enabled);
+ err = StatusFromResult(mSensors->activate(handle, enabled));
+ ALOGE_IF(err, "Error %s sensor %d (%s)", enabled ? "activating" : "disabling", handle,
+ strerror(-err));
+
+ if (err != NO_ERROR && enabled) {
+ // Failure when enabling the sensor. Clean up on failure.
+ info.removeBatchParamsForIdent(ident);
+ }
+ }
+
+ // On older devices which do not support batch, call setDelay().
+ if (getHalDeviceVersion() < SENSORS_DEVICE_API_VERSION_1_1 && info.numActiveClients() > 0) {
+ ALOGD_IF(DEBUG_CONNECTIONS, "\t>>> actuating h/w setDelay %d %" PRId64, handle,
+ info.bestBatchParams.batchDelay);
+ /* auto result = */mSensors->setDelay(
+ handle, info.bestBatchParams.batchDelay);
+ }
+ return err;
+}
+
+status_t SensorDevice::batch(
+ void* ident,
+ int handle,
+ int flags,
+ int64_t samplingPeriodNs,
+ int64_t maxBatchReportLatencyNs) {
+ if (mSensors == NULL) return NO_INIT;
+
+ if (samplingPeriodNs < MINIMUM_EVENTS_PERIOD) {
+ samplingPeriodNs = MINIMUM_EVENTS_PERIOD;
+ }
+
+ const int halVersion = getHalDeviceVersion();
+ if (halVersion < SENSORS_DEVICE_API_VERSION_1_1 && maxBatchReportLatencyNs != 0) {
+ // Batch is not supported on older devices return invalid operation.
+ return INVALID_OPERATION;
+ }
+
+ ALOGD_IF(DEBUG_CONNECTIONS,
+ "SensorDevice::batch: ident=%p, handle=0x%08x, flags=%d, period_ns=%" PRId64 " timeout=%" PRId64,
+ ident, handle, flags, samplingPeriodNs, maxBatchReportLatencyNs);
+
+ Mutex::Autolock _l(mLock);
+ Info& info(mActivationCount.editValueFor(handle));
+
+ if (info.batchParams.indexOfKey(ident) < 0) {
+ BatchParams params(flags, samplingPeriodNs, maxBatchReportLatencyNs);
+ info.batchParams.add(ident, params);
+ } else {
+ // A batch has already been called with this ident. Update the batch parameters.
+ info.setBatchParamsForIdent(ident, flags, samplingPeriodNs, maxBatchReportLatencyNs);
+ }
+
+ BatchParams prevBestBatchParams = info.bestBatchParams;
+ // Find the minimum of all timeouts and batch_rates for this sensor.
+ info.selectBatchParams();
+
+ ALOGD_IF(DEBUG_CONNECTIONS,
+ "\t>>> curr_period=%" PRId64 " min_period=%" PRId64
+ " curr_timeout=%" PRId64 " min_timeout=%" PRId64,
+ prevBestBatchParams.batchDelay, info.bestBatchParams.batchDelay,
+ prevBestBatchParams.batchTimeout, info.bestBatchParams.batchTimeout);
+
+ status_t err(NO_ERROR);
+ // If the min period or min timeout has changed since the last batch call, call batch.
+ if (prevBestBatchParams != info.bestBatchParams) {
+ if (halVersion >= SENSORS_DEVICE_API_VERSION_1_1) {
+ ALOGD_IF(DEBUG_CONNECTIONS, "\t>>> actuating h/w BATCH %d %d %" PRId64 " %" PRId64, handle,
+ info.bestBatchParams.flags, info.bestBatchParams.batchDelay,
+ info.bestBatchParams.batchTimeout);
+ err = StatusFromResult(
+ mSensors->batch(
+ handle,
+ info.bestBatchParams.flags,
+ info.bestBatchParams.batchDelay,
+ info.bestBatchParams.batchTimeout));
+ } else {
+ // For older devices which do not support batch, call setDelay() after activate() is
+ // called. Some older devices may not support calling setDelay before activate(), so
+ // call setDelay in SensorDevice::activate() method.
+ }
+ if (err != NO_ERROR) {
+ ALOGE("sensor batch failed %p %d %d %" PRId64 " %" PRId64 " err=%s",
+ mSensors.get(), handle,
+ info.bestBatchParams.flags, info.bestBatchParams.batchDelay,
+ info.bestBatchParams.batchTimeout, strerror(-err));
+ info.removeBatchParamsForIdent(ident);
+ }
+ }
+ return err;
+}
+
+status_t SensorDevice::setDelay(void* ident, int handle, int64_t samplingPeriodNs) {
+ if (mSensors == NULL) return NO_INIT;
+ if (samplingPeriodNs < MINIMUM_EVENTS_PERIOD) {
+ samplingPeriodNs = MINIMUM_EVENTS_PERIOD;
+ }
+ Mutex::Autolock _l(mLock);
+ if (isClientDisabledLocked(ident)) return INVALID_OPERATION;
+ Info& info( mActivationCount.editValueFor(handle) );
+ // If the underlying sensor is NOT in continuous mode, setDelay() should return an error.
+ // Calling setDelay() in batch mode is an invalid operation.
+ if (info.bestBatchParams.batchTimeout != 0) {
+ return INVALID_OPERATION;
+ }
+ ssize_t index = info.batchParams.indexOfKey(ident);
+ if (index < 0) {
+ return BAD_INDEX;
+ }
+ BatchParams& params = info.batchParams.editValueAt(index);
+ params.batchDelay = samplingPeriodNs;
+ info.selectBatchParams();
+
+ return StatusFromResult(
+ mSensors->setDelay(handle, info.bestBatchParams.batchDelay));
+}
+
+int SensorDevice::getHalDeviceVersion() const {
+ if (mSensors == NULL) return -1;
+ return SENSORS_DEVICE_API_VERSION_1_4;
+}
+
+status_t SensorDevice::flush(void* ident, int handle) {
+ if (getHalDeviceVersion() < SENSORS_DEVICE_API_VERSION_1_1) {
+ return INVALID_OPERATION;
+ }
+ if (isClientDisabled(ident)) return INVALID_OPERATION;
+ ALOGD_IF(DEBUG_CONNECTIONS, "\t>>> actuating h/w flush %d", handle);
+ return StatusFromResult(mSensors->flush(handle));
+}
+
+bool SensorDevice::isClientDisabled(void* ident) {
+ Mutex::Autolock _l(mLock);
+ return isClientDisabledLocked(ident);
+}
+
+bool SensorDevice::isClientDisabledLocked(void* ident) {
+ return mDisabledClients.indexOf(ident) >= 0;
+}
+
+void SensorDevice::enableAllSensors() {
+ Mutex::Autolock _l(mLock);
+ mDisabledClients.clear();
+ ALOGI("cleared mDisabledClients");
+ const int halVersion = getHalDeviceVersion();
+ for (size_t i = 0; i< mActivationCount.size(); ++i) {
+ Info& info = mActivationCount.editValueAt(i);
+ if (info.batchParams.isEmpty()) continue;
+ info.selectBatchParams();
+ const int sensor_handle = mActivationCount.keyAt(i);
+ ALOGD_IF(DEBUG_CONNECTIONS, "\t>> reenable actuating h/w sensor enable handle=%d ",
+ sensor_handle);
+ status_t err(NO_ERROR);
+ if (halVersion > SENSORS_DEVICE_API_VERSION_1_0) {
+ err = StatusFromResult(
+ mSensors->batch(
+ sensor_handle,
+ info.bestBatchParams.flags,
+ info.bestBatchParams.batchDelay,
+ info.bestBatchParams.batchTimeout));
+ ALOGE_IF(err, "Error calling batch on sensor %d (%s)", sensor_handle, strerror(-err));
+ }
+
+ if (err == NO_ERROR) {
+ err = StatusFromResult(
+ mSensors->activate(sensor_handle, 1 /* enabled */));
+ ALOGE_IF(err, "Error activating sensor %d (%s)", sensor_handle, strerror(-err));
+ }
+
+ if (halVersion <= SENSORS_DEVICE_API_VERSION_1_0) {
+ err = StatusFromResult(
+ mSensors->setDelay(
+ sensor_handle, info.bestBatchParams.batchDelay));
+ ALOGE_IF(err, "Error calling setDelay sensor %d (%s)", sensor_handle, strerror(-err));
+ }
+ }
+}
+
+void SensorDevice::disableAllSensors() {
+ Mutex::Autolock _l(mLock);
+ for (size_t i = 0; i< mActivationCount.size(); ++i) {
+ const Info& info = mActivationCount.valueAt(i);
+ // Check if this sensor has been activated previously and disable it.
+ if (info.batchParams.size() > 0) {
+ const int sensor_handle = mActivationCount.keyAt(i);
+ ALOGD_IF(DEBUG_CONNECTIONS, "\t>> actuating h/w sensor disable handle=%d ",
+ sensor_handle);
+ /* auto result = */mSensors->activate(
+ sensor_handle, 0 /* enabled */);
+
+ // Add all the connections that were registered for this sensor to the disabled
+ // clients list.
+ for (size_t j = 0; j < info.batchParams.size(); ++j) {
+ mDisabledClients.add(info.batchParams.keyAt(j));
+ ALOGI("added %p to mDisabledClients", info.batchParams.keyAt(j));
+ }
+ }
+ }
+}
+
+status_t SensorDevice::injectSensorData(
+ const sensors_event_t *injected_sensor_event) {
+ ALOGD_IF(DEBUG_CONNECTIONS,
+ "sensor_event handle=%d ts=%" PRId64 " data=%.2f, %.2f, %.2f %.2f %.2f %.2f",
+ injected_sensor_event->sensor,
+ injected_sensor_event->timestamp, injected_sensor_event->data[0],
+ injected_sensor_event->data[1], injected_sensor_event->data[2],
+ injected_sensor_event->data[3], injected_sensor_event->data[4],
+ injected_sensor_event->data[5]);
+
+ if (getHalDeviceVersion() < SENSORS_DEVICE_API_VERSION_1_4) {
+ return INVALID_OPERATION;
+ }
+
+ Event ev;
+ convertFromSensorEvent(*injected_sensor_event, &ev);
+
+ return StatusFromResult(mSensors->injectSensorData(ev));
+}
+
+status_t SensorDevice::setMode(uint32_t mode) {
+ if (getHalDeviceVersion() < SENSORS_DEVICE_API_VERSION_1_4) {
+ return INVALID_OPERATION;
+ }
+
+ return StatusFromResult(
+ mSensors->setOperationMode(
+ static_cast<hardware::sensors::V1_0::OperationMode>(mode)));
+}
+
+// ---------------------------------------------------------------------------
+
+int SensorDevice::Info::numActiveClients() {
+ SensorDevice& device(SensorDevice::getInstance());
+ int num = 0;
+ for (size_t i = 0; i < batchParams.size(); ++i) {
+ if (!device.isClientDisabledLocked(batchParams.keyAt(i))) {
+ ++num;
+ }
+ }
+ return num;
+}
+
+status_t SensorDevice::Info::setBatchParamsForIdent(void* ident, int flags,
+ int64_t samplingPeriodNs,
+ int64_t maxBatchReportLatencyNs) {
+ ssize_t index = batchParams.indexOfKey(ident);
+ if (index < 0) {
+ ALOGE("Info::setBatchParamsForIdent(ident=%p, period_ns=%" PRId64 " timeout=%" PRId64 ") failed (%s)",
+ ident, samplingPeriodNs, maxBatchReportLatencyNs, strerror(-index));
+ return BAD_INDEX;
+ }
+ BatchParams& params = batchParams.editValueAt(index);
+ params.flags = flags;
+ params.batchDelay = samplingPeriodNs;
+ params.batchTimeout = maxBatchReportLatencyNs;
+ return NO_ERROR;
+}
+
+void SensorDevice::Info::selectBatchParams() {
+ BatchParams bestParams(0, -1, -1);
+ SensorDevice& device(SensorDevice::getInstance());
+
+ for (size_t i = 0; i < batchParams.size(); ++i) {
+ if (device.isClientDisabledLocked(batchParams.keyAt(i))) continue;
+ BatchParams params = batchParams.valueAt(i);
+ if (bestParams.batchDelay == -1 || params.batchDelay < bestParams.batchDelay) {
+ bestParams.batchDelay = params.batchDelay;
+ }
+ if (bestParams.batchTimeout == -1 || params.batchTimeout < bestParams.batchTimeout) {
+ bestParams.batchTimeout = params.batchTimeout;
+ }
+ }
+ bestBatchParams = bestParams;
+}
+
+ssize_t SensorDevice::Info::removeBatchParamsForIdent(void* ident) {
+ ssize_t idx = batchParams.removeItem(ident);
+ if (idx >= 0) {
+ selectBatchParams();
+ }
+ return idx;
+}
+
+void SensorDevice::notifyConnectionDestroyed(void* ident) {
+ Mutex::Autolock _l(mLock);
+ mDisabledClients.remove(ident);
+}
+
+void SensorDevice::convertToSensorEvent(
+ const Event &src, sensors_event_t *dst) {
+ ::android::hardware::sensors::V1_0::implementation::convertToSensorEvent(
+ src, dst);
+
+ if (src.sensorType == SensorType::SENSOR_TYPE_DYNAMIC_SENSOR_META) {
+ const DynamicSensorInfo &dyn = src.u.dynamic;
+
+ dst->dynamic_sensor_meta.connected = dyn.connected;
+ dst->dynamic_sensor_meta.handle = dyn.sensorHandle;
+ if (dyn.connected) {
+ auto it = mConnectedDynamicSensors.find(dyn.sensorHandle);
+ CHECK(it != mConnectedDynamicSensors.end());
+
+ dst->dynamic_sensor_meta.sensor = it->second;
+
+ memcpy(dst->dynamic_sensor_meta.uuid,
+ dyn.uuid.data(),
+ sizeof(dst->dynamic_sensor_meta.uuid));
+ }
+ }
+}
+
+void SensorDevice::convertToSensorEvents(
+ const hidl_vec<Event> &src,
+ const hidl_vec<SensorInfo> &dynamicSensorsAdded,
+ sensors_event_t *dst) {
+ // Allocate a sensor_t structure for each dynamic sensor added and insert
+ // it into the dictionary of connected dynamic sensors keyed by handle.
+ for (size_t i = 0; i < dynamicSensorsAdded.size(); ++i) {
+ const SensorInfo &info = dynamicSensorsAdded[i];
+
+ auto it = mConnectedDynamicSensors.find(info.sensorHandle);
+ CHECK(it == mConnectedDynamicSensors.end());
+
+ sensor_t *sensor = new sensor_t;
+ convertToSensor(info, sensor);
+
+ mConnectedDynamicSensors.insert(
+ std::make_pair(sensor->handle, sensor));
+ }
+
+ for (size_t i = 0; i < src.size(); ++i) {
+ convertToSensorEvent(src[i], &dst[i]);
+ }
+}
+
+// ---------------------------------------------------------------------------
+}; // namespace android
+
diff --git a/services/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk
index 58f71eb..f695edb 100644
--- a/services/surfaceflinger/Android.mk
+++ b/services/surfaceflinger/Android.mk
@@ -20,6 +20,7 @@
SurfaceFlingerConsumer.cpp \
SurfaceInterceptor.cpp \
Transform.cpp \
+ DisplayHardware/ComposerHal.cpp \
DisplayHardware/FramebufferSurface.cpp \
DisplayHardware/HWC2.cpp \
DisplayHardware/HWC2On1Adapter.cpp \
@@ -127,10 +128,14 @@
LOCAL_STATIC_LIBRARIES := libtrace_proto libvkjson
LOCAL_SHARED_LIBRARIES := \
+ android.hardware.graphics.allocator@2.0 \
+ android.hardware.graphics.composer@2.1 \
libcutils \
liblog \
libdl \
libhardware \
+ libhidl \
+ libhwbinder \
libutils \
libEGL \
libGLESv1_CM \
@@ -140,7 +145,18 @@
libgui \
libpowermanager \
libvulkan \
- libprotobuf-cpp-full
+ libprotobuf-cpp-full \
+ libhidl \
+ libhwbinder \
+ libbase \
+ libutils \
+ android.hardware.power@1.0
+
+LOCAL_EXPORT_SHARED_LIBRARY_HEADERS := \
+ android.hardware.graphics.allocator@2.0 \
+ android.hardware.graphics.composer@2.1 \
+ libhidl \
+ libhwbinder
LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code
diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
new file mode 100644
index 0000000..128e2b0
--- /dev/null
+++ b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
@@ -0,0 +1,650 @@
+/*
+ * 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.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "HwcComposer"
+
+#include <inttypes.h>
+#include <log/log.h>
+
+#include "ComposerHal.h"
+
+namespace android {
+
+using hardware::Return;
+using hardware::hidl_vec;
+
+namespace Hwc2 {
+
+namespace {
+
+class BufferHandle {
+public:
+ BufferHandle(const native_handle_t* buffer)
+ {
+ // nullptr is not a valid handle to HIDL
+ mHandle = (buffer) ? buffer : native_handle_init(mStorage, 0, 0);
+ }
+
+ operator const native_handle_t*() const
+ {
+ return mHandle;
+ }
+
+private:
+ NATIVE_HANDLE_DECLARE_STORAGE(mStorage, 0, 0);
+ const native_handle_t* mHandle;
+};
+
+class FenceHandle
+{
+public:
+ FenceHandle(int fd, bool owned)
+ : mOwned(owned)
+ {
+ if (fd >= 0) {
+ mHandle = native_handle_init(mStorage, 1, 0);
+ mHandle->data[0] = fd;
+ } else {
+ // nullptr is not a valid handle to HIDL
+ mHandle = native_handle_init(mStorage, 0, 0);
+ }
+ }
+
+ ~FenceHandle()
+ {
+ if (mOwned) {
+ native_handle_close(mHandle);
+ }
+ }
+
+ operator const native_handle_t*() const
+ {
+ return mHandle;
+ }
+
+private:
+ bool mOwned;
+ NATIVE_HANDLE_DECLARE_STORAGE(mStorage, 1, 0);
+ native_handle_t* mHandle;
+};
+
+// assume NO_RESOURCES when Status::isOk returns false
+constexpr Error kDefaultError = Error::NO_RESOURCES;
+
+template<typename T, typename U>
+T unwrapRet(Return<T>& ret, const U& default_val)
+{
+ return (ret.getStatus().isOk()) ? static_cast<T>(ret) :
+ static_cast<T>(default_val);
+}
+
+Error unwrapRet(Return<Error>& ret)
+{
+ return unwrapRet(ret, kDefaultError);
+}
+
+template<typename T>
+void assignFromHidlVec(std::vector<T>& vec, const hidl_vec<T>& data)
+{
+ vec.clear();
+ vec.insert(vec.begin(), &data[0], &data[data.size()]);
+}
+
+} // anonymous namespace
+
+Composer::Composer()
+{
+ mService = IComposer::getService("hwcomposer");
+ if (mService == nullptr) {
+ LOG_ALWAYS_FATAL("failed to get hwcomposer service");
+ }
+}
+
+std::vector<IComposer::Capability> Composer::getCapabilities() const
+{
+ std::vector<IComposer::Capability> capabilities;
+ mService->getCapabilities(
+ [&](const auto& tmpCapabilities) {
+ assignFromHidlVec(capabilities, tmpCapabilities);
+ });
+
+ return capabilities;
+}
+
+std::string Composer::dumpDebugInfo() const
+{
+ std::string info;
+ mService->dumpDebugInfo([&](const auto& tmpInfo) {
+ info = tmpInfo.c_str();
+ });
+
+ return info;
+}
+
+void Composer::registerCallback(const sp<IComposerCallback>& callback) const
+{
+ auto ret = mService->registerCallback(callback);
+ if (!ret.getStatus().isOk()) {
+ ALOGE("failed to register IComposerCallback");
+ }
+}
+
+uint32_t Composer::getMaxVirtualDisplayCount() const
+{
+ auto ret = mService->getMaxVirtualDisplayCount();
+ return unwrapRet(ret, 0);
+}
+
+Error Composer::createVirtualDisplay(uint32_t width, uint32_t height,
+ PixelFormat& format, Display& display) const
+{
+ Error error = kDefaultError;
+ mService->createVirtualDisplay(width, height, format,
+ [&](const auto& tmpError, const auto& tmpDisplay,
+ const auto& tmpFormat) {
+ error = tmpError;
+ if (error != Error::NONE) {
+ return;
+ }
+
+ display = tmpDisplay;
+ format = tmpFormat;
+ });
+
+ return error;
+}
+
+Error Composer::destroyVirtualDisplay(Display display) const
+{
+ auto ret = mService->destroyVirtualDisplay(display);
+ return unwrapRet(ret);
+}
+
+Error Composer::acceptDisplayChanges(Display display) const
+{
+ auto ret = mService->acceptDisplayChanges(display);
+ return unwrapRet(ret);
+}
+
+Error Composer::createLayer(Display display, Layer& layer) const
+{
+ Error error = kDefaultError;
+ mService->createLayer(display,
+ [&](const auto& tmpError, const auto& tmpLayer) {
+ error = tmpError;
+ if (error != Error::NONE) {
+ return;
+ }
+
+ layer = tmpLayer;
+ });
+
+ return error;
+}
+
+Error Composer::destroyLayer(Display display, Layer layer) const
+{
+ auto ret = mService->destroyLayer(display, layer);
+ return unwrapRet(ret);
+}
+
+Error Composer::getActiveConfig(Display display, Config& config) const
+{
+ Error error = kDefaultError;
+ mService->getActiveConfig(display,
+ [&](const auto& tmpError, const auto& tmpConfig) {
+ error = tmpError;
+ if (error != Error::NONE) {
+ return;
+ }
+
+ config = tmpConfig;
+ });
+
+ return error;
+}
+
+Error Composer::getChangedCompositionTypes(Display display,
+ std::vector<Layer>& layers,
+ std::vector<IComposer::Composition>& types) const
+{
+ Error error = kDefaultError;
+ mService->getChangedCompositionTypes(display,
+ [&](const auto& tmpError, const auto& tmpLayers,
+ const auto& tmpTypes) {
+ error = tmpError;
+ if (error != Error::NONE) {
+ return;
+ }
+
+ assignFromHidlVec(layers, tmpLayers);
+ assignFromHidlVec(types, tmpTypes);
+ });
+
+ return error;
+}
+
+Error Composer::getColorModes(Display display,
+ std::vector<ColorMode>& modes) const
+{
+ Error error = kDefaultError;
+ mService->getColorModes(display,
+ [&](const auto& tmpError, const auto& tmpModes) {
+ error = tmpError;
+ if (error != Error::NONE) {
+ return;
+ }
+
+ assignFromHidlVec(modes, tmpModes);
+ });
+
+ return error;
+}
+
+Error Composer::getDisplayAttribute(Display display, Config config,
+ IComposer::Attribute attribute, int32_t& value) const
+{
+ Error error = kDefaultError;
+ mService->getDisplayAttribute(display, config, attribute,
+ [&](const auto& tmpError, const auto& tmpValue) {
+ error = tmpError;
+ if (error != Error::NONE) {
+ return;
+ }
+
+ value = tmpValue;
+ });
+
+ return error;
+}
+
+Error Composer::getDisplayConfigs(Display display,
+ std::vector<Config>& configs) const
+{
+ Error error = kDefaultError;
+ mService->getDisplayConfigs(display,
+ [&](const auto& tmpError, const auto& tmpConfigs) {
+ error = tmpError;
+ if (error != Error::NONE) {
+ return;
+ }
+
+ assignFromHidlVec(configs, tmpConfigs);
+ });
+
+ return error;
+}
+
+Error Composer::getDisplayName(Display display, std::string& name) const
+{
+ Error error = kDefaultError;
+ mService->getDisplayName(display,
+ [&](const auto& tmpError, const auto& tmpName) {
+ error = tmpError;
+ if (error != Error::NONE) {
+ return;
+ }
+
+ name = tmpName.c_str();
+ });
+
+ return error;
+}
+
+Error Composer::getDisplayRequests(Display display,
+ uint32_t& displayRequestMask, std::vector<Layer>& layers,
+ std::vector<uint32_t>& layerRequestMasks) const
+{
+ Error error = kDefaultError;
+ mService->getDisplayRequests(display,
+ [&](const auto& tmpError, const auto& tmpDisplayRequestMask,
+ const auto& tmpLayers, const auto& tmpLayerRequestMasks) {
+ error = tmpError;
+ if (error != Error::NONE) {
+ return;
+ }
+
+ displayRequestMask = tmpDisplayRequestMask;
+ assignFromHidlVec(layers, tmpLayers);
+ assignFromHidlVec(layerRequestMasks, tmpLayerRequestMasks);
+ });
+
+ return error;
+}
+
+Error Composer::getDisplayType(Display display, IComposer::DisplayType& type) const
+{
+ Error error = kDefaultError;
+ mService->getDisplayType(display,
+ [&](const auto& tmpError, const auto& tmpType) {
+ error = tmpError;
+ if (error != Error::NONE) {
+ return;
+ }
+
+ type = tmpType;
+ });
+
+ return error;
+}
+
+Error Composer::getDozeSupport(Display display, bool& support) const
+{
+ Error error = kDefaultError;
+ mService->getDozeSupport(display,
+ [&](const auto& tmpError, const auto& tmpSupport) {
+ error = tmpError;
+ if (error != Error::NONE) {
+ return;
+ }
+
+ support = tmpSupport;
+ });
+
+ return error;
+}
+
+Error Composer::getHdrCapabilities(Display display, std::vector<Hdr>& types,
+ float& maxLuminance, float& maxAverageLuminance,
+ float& minLuminance) const
+{
+ Error error = kDefaultError;
+ mService->getHdrCapabilities(display,
+ [&](const auto& tmpError, const auto& tmpTypes,
+ const auto& tmpMaxLuminance,
+ const auto& tmpMaxAverageLuminance,
+ const auto& tmpMinLuminance) {
+ error = tmpError;
+ if (error != Error::NONE) {
+ return;
+ }
+
+ assignFromHidlVec(types, tmpTypes);
+ maxLuminance = tmpMaxLuminance;
+ maxAverageLuminance = tmpMaxAverageLuminance;
+ minLuminance = tmpMinLuminance;
+ });
+
+ return error;
+}
+
+Error Composer::getReleaseFences(Display display, std::vector<Layer>& layers,
+ std::vector<int>& releaseFences) const
+{
+ Error error = kDefaultError;
+ mService->getReleaseFences(display,
+ [&](const auto& tmpError, const auto& tmpLayers,
+ const auto& tmpReleaseFences) {
+ error = tmpError;
+ if (error != Error::NONE) {
+ return;
+ }
+
+ if (static_cast<int>(tmpLayers.size()) !=
+ tmpReleaseFences->numFds) {
+ ALOGE("invalid releaseFences outputs: "
+ "layer count %zu != fence count %d",
+ tmpLayers.size(), tmpReleaseFences->numFds);
+ error = Error::NO_RESOURCES;
+ return;
+ }
+
+ // dup the file descriptors
+ std::vector<int> tmpFds;
+ tmpFds.reserve(tmpReleaseFences->numFds);
+ for (int i = 0; i < tmpReleaseFences->numFds; i++) {
+ int fd = dup(tmpReleaseFences->data[i]);
+ if (fd < 0) {
+ break;
+ }
+ tmpFds.push_back(fd);
+ }
+ if (static_cast<int>(tmpFds.size()) <
+ tmpReleaseFences->numFds) {
+ for (auto fd : tmpFds) {
+ close(fd);
+ }
+
+ error = Error::NO_RESOURCES;
+ return;
+ }
+
+ assignFromHidlVec(layers, tmpLayers);
+ releaseFences = std::move(tmpFds);
+ });
+
+ return error;
+}
+
+Error Composer::presentDisplay(Display display, int& presentFence) const
+{
+ Error error = kDefaultError;
+ mService->presentDisplay(display,
+ [&](const auto& tmpError, const auto& tmpPresentFence) {
+ error = tmpError;
+ if (error != Error::NONE) {
+ return;
+ }
+
+ if (tmpPresentFence->numFds == 1) {
+ int fd = dup(tmpPresentFence->data[0]);
+ if (fd >= 0) {
+ presentFence = fd;
+ } else {
+ error = Error::NO_RESOURCES;
+ }
+ } else {
+ presentFence = -1;
+ }
+ });
+
+ return error;
+}
+
+Error Composer::setActiveConfig(Display display, Config config) const
+{
+ auto ret = mService->setActiveConfig(display, config);
+ return unwrapRet(ret);
+}
+
+Error Composer::setClientTarget(Display display, const native_handle_t* target,
+ int acquireFence, Dataspace dataspace,
+ const std::vector<IComposer::Rect>& damage) const
+{
+ BufferHandle tmpTarget(target);
+ FenceHandle tmpAcquireFence(acquireFence, true);
+
+ hidl_vec<IComposer::Rect> tmpDamage;
+ tmpDamage.setToExternal(const_cast<IComposer::Rect*>(damage.data()),
+ damage.size());
+
+ auto ret = mService->setClientTarget(display, tmpTarget,
+ tmpAcquireFence, dataspace, tmpDamage);
+ return unwrapRet(ret);
+}
+
+Error Composer::setColorMode(Display display, ColorMode mode) const
+{
+ auto ret = mService->setColorMode(display, mode);
+ return unwrapRet(ret);
+}
+
+Error Composer::setColorTransform(Display display, const float* matrix,
+ ColorTransform hint) const
+{
+ hidl_vec<float> tmpMatrix;
+ tmpMatrix.setToExternal(const_cast<float*>(matrix), 16);
+
+ auto ret = mService->setColorTransform(display, tmpMatrix, hint);
+ return unwrapRet(ret);
+}
+
+Error Composer::setOutputBuffer(Display display, const native_handle_t* buffer,
+ int releaseFence) const
+{
+ BufferHandle tmpBuffer(buffer);
+ FenceHandle tmpReleaseFence(releaseFence, false);
+
+ auto ret = mService->setOutputBuffer(display, tmpBuffer, tmpReleaseFence);
+ return unwrapRet(ret);
+}
+
+Error Composer::setPowerMode(Display display, IComposer::PowerMode mode) const
+{
+ auto ret = mService->setPowerMode(display, mode);
+ return unwrapRet(ret);
+}
+
+Error Composer::setVsyncEnabled(Display display, IComposer::Vsync enabled) const
+{
+ auto ret = mService->setVsyncEnabled(display, enabled);
+ return unwrapRet(ret);
+}
+
+Error Composer::validateDisplay(Display display, uint32_t& numTypes, uint32_t&
+ numRequests) const
+{
+ Error error = kDefaultError;
+ mService->validateDisplay(display,
+ [&](const auto& tmpError, const auto& tmpNumTypes,
+ const auto& tmpNumRequests) {
+ error = tmpError;
+ if (error != Error::NONE) {
+ return;
+ }
+
+ numTypes = tmpNumTypes;
+ numRequests = tmpNumRequests;
+ });
+
+ return error;
+}
+
+Error Composer::setCursorPosition(Display display, Layer layer,
+ int32_t x, int32_t y) const
+{
+ auto ret = mService->setCursorPosition(display, layer, x, y);
+ return unwrapRet(ret);
+}
+
+Error Composer::setLayerBuffer(Display display, Layer layer,
+ const native_handle_t* buffer, int acquireFence) const
+{
+ BufferHandle tmpBuffer(buffer);
+ FenceHandle tmpAcquireFence(acquireFence, true);
+
+ auto ret = mService->setLayerBuffer(display, layer,
+ tmpBuffer, tmpAcquireFence);
+ return unwrapRet(ret);
+}
+
+Error Composer::setLayerSurfaceDamage(Display display, Layer layer,
+ const std::vector<IComposer::Rect>& damage) const
+{
+ hidl_vec<IComposer::Rect> tmpDamage;
+ tmpDamage.setToExternal(const_cast<IComposer::Rect*>(damage.data()),
+ damage.size());
+
+ auto ret = mService->setLayerSurfaceDamage(display, layer, tmpDamage);
+ return unwrapRet(ret);
+}
+
+Error Composer::setLayerBlendMode(Display display, Layer layer,
+ IComposer::BlendMode mode) const
+{
+ auto ret = mService->setLayerBlendMode(display, layer, mode);
+ return unwrapRet(ret);
+}
+
+Error Composer::setLayerColor(Display display, Layer layer,
+ const IComposer::Color& color) const
+{
+ auto ret = mService->setLayerColor(display, layer, color);
+ return unwrapRet(ret);
+}
+
+Error Composer::setLayerCompositionType(Display display, Layer layer,
+ IComposer::Composition type) const
+{
+ auto ret = mService->setLayerCompositionType(display, layer, type);
+ return unwrapRet(ret);
+}
+
+Error Composer::setLayerDataspace(Display display, Layer layer,
+ Dataspace dataspace) const
+{
+ auto ret = mService->setLayerDataspace(display, layer, dataspace);
+ return unwrapRet(ret);
+}
+
+Error Composer::setLayerDisplayFrame(Display display, Layer layer,
+ const IComposer::Rect& frame) const
+{
+ auto ret = mService->setLayerDisplayFrame(display, layer, frame);
+ return unwrapRet(ret);
+}
+
+Error Composer::setLayerPlaneAlpha(Display display, Layer layer,
+ float alpha) const
+{
+ auto ret = mService->setLayerPlaneAlpha(display, layer, alpha);
+ return unwrapRet(ret);
+}
+
+Error Composer::setLayerSidebandStream(Display display, Layer layer,
+ const native_handle_t* stream) const
+{
+ BufferHandle tmpStream(stream);
+
+ auto ret = mService->setLayerSidebandStream(display, layer, tmpStream);
+ return unwrapRet(ret);
+}
+
+Error Composer::setLayerSourceCrop(Display display, Layer layer,
+ const IComposer::FRect& crop) const
+{
+ auto ret = mService->setLayerSourceCrop(display, layer, crop);
+ return unwrapRet(ret);
+}
+
+Error Composer::setLayerTransform(Display display, Layer layer,
+ Transform transform) const
+{
+ auto ret = mService->setLayerTransform(display, layer, transform);
+ return unwrapRet(ret);
+}
+
+Error Composer::setLayerVisibleRegion(Display display, Layer layer,
+ const std::vector<IComposer::Rect>& visible) const
+{
+ hidl_vec<IComposer::Rect> tmpVisible;
+ tmpVisible.setToExternal(const_cast<IComposer::Rect*>(visible.data()),
+ visible.size());
+
+ auto ret = mService->setLayerVisibleRegion(display, layer, tmpVisible);
+ return unwrapRet(ret);
+}
+
+Error Composer::setLayerZOrder(Display display, Layer layer, uint32_t z) const
+{
+ auto ret = mService->setLayerZOrder(display, layer, z);
+ return unwrapRet(ret);
+}
+
+} // namespace Hwc2
+
+} // namespace android
diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.h b/services/surfaceflinger/DisplayHardware/ComposerHal.h
new file mode 100644
index 0000000..fd74a92
--- /dev/null
+++ b/services/surfaceflinger/DisplayHardware/ComposerHal.h
@@ -0,0 +1,142 @@
+/*
+ * 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_SF_COMPOSER_HAL_H
+#define ANDROID_SF_COMPOSER_HAL_H
+
+#include <string>
+#include <vector>
+
+#include <android/hardware/graphics/composer/2.1/IComposer.h>
+#include <utils/StrongPointer.h>
+
+namespace android {
+
+namespace Hwc2 {
+
+using android::hardware::graphics::allocator::V2_0::PixelFormat;
+
+using android::hardware::graphics::composer::V2_1::IComposer;
+using android::hardware::graphics::composer::V2_1::IComposerCallback;
+using android::hardware::graphics::composer::V2_1::Error;
+using android::hardware::graphics::composer::V2_1::Display;
+using android::hardware::graphics::composer::V2_1::Layer;
+using android::hardware::graphics::composer::V2_1::Config;
+
+using android::hardware::graphics::composer::V2_1::ColorMode;
+using android::hardware::graphics::composer::V2_1::Hdr;
+using android::hardware::graphics::composer::V2_1::Dataspace;
+using android::hardware::graphics::composer::V2_1::ColorTransform;
+using android::hardware::graphics::composer::V2_1::Transform;
+
+// Composer is a wrapper to IComposer, a proxy to server-side composer.
+class Composer {
+public:
+ Composer();
+
+ std::vector<IComposer::Capability> getCapabilities() const;
+ std::string dumpDebugInfo() const;
+
+ void registerCallback(const sp<IComposerCallback>& callback) const;
+
+ uint32_t getMaxVirtualDisplayCount() const;
+ Error createVirtualDisplay(uint32_t width, uint32_t height,
+ PixelFormat& format, Display& display) const;
+ Error destroyVirtualDisplay(Display display) const;
+
+ Error acceptDisplayChanges(Display display) const;
+
+ Error createLayer(Display display, Layer& layer) const;
+ Error destroyLayer(Display display, Layer layer) const;
+
+ Error getActiveConfig(Display display, Config& config) const;
+ Error getChangedCompositionTypes(Display display,
+ std::vector<Layer>& layers,
+ std::vector<IComposer::Composition>& types) const;
+ Error getColorModes(Display display, std::vector<ColorMode>& modes) const;
+ Error getDisplayAttribute(Display display, Config config,
+ IComposer::Attribute attribute, int32_t& value) const;
+ Error getDisplayConfigs(Display display,
+ std::vector<Config>& configs) const;
+ Error getDisplayName(Display display, std::string& name) const;
+
+ Error getDisplayRequests(Display display, uint32_t& displayRequestMask,
+ std::vector<Layer>& layers,
+ std::vector<uint32_t>& layerRequestMasks) const;
+
+ Error getDisplayType(Display display, IComposer::DisplayType& type) const;
+ Error getDozeSupport(Display display, bool& support) const;
+ Error getHdrCapabilities(Display display, std::vector<Hdr>& types,
+ float& maxLuminance, float& maxAverageLuminance,
+ float& minLuminance) const;
+
+ Error getReleaseFences(Display display, std::vector<Layer>& layers,
+ std::vector<int>& releaseFences) const;
+
+ Error presentDisplay(Display display, int& presentFence) const;
+
+ Error setActiveConfig(Display display, Config config) const;
+ Error setClientTarget(Display display, const native_handle_t* target,
+ int acquireFence, Dataspace dataspace,
+ const std::vector<IComposer::Rect>& damage) const;
+ Error setColorMode(Display display, ColorMode mode) const;
+ Error setColorTransform(Display display, const float* matrix,
+ ColorTransform hint) const;
+ Error setOutputBuffer(Display display, const native_handle_t* buffer,
+ int releaseFence) const;
+ Error setPowerMode(Display display, IComposer::PowerMode mode) const;
+ Error setVsyncEnabled(Display display, IComposer::Vsync enabled) const;
+
+ Error validateDisplay(Display display, uint32_t& numTypes,
+ uint32_t& numRequests) const;
+
+ Error setCursorPosition(Display display, Layer layer,
+ int32_t x, int32_t y) const;
+ Error setLayerBuffer(Display display, Layer layer,
+ const native_handle_t* buffer, int acquireFence) const;
+ Error setLayerSurfaceDamage(Display display, Layer layer,
+ const std::vector<IComposer::Rect>& damage) const;
+ Error setLayerBlendMode(Display display, Layer layer,
+ IComposer::BlendMode mode) const;
+ Error setLayerColor(Display display, Layer layer,
+ const IComposer::Color& color) const;
+ Error setLayerCompositionType(Display display, Layer layer,
+ IComposer::Composition type) const;
+ Error setLayerDataspace(Display display, Layer layer,
+ Dataspace dataspace) const;
+ Error setLayerDisplayFrame(Display display, Layer layer,
+ const IComposer::Rect& frame) const;
+ Error setLayerPlaneAlpha(Display display, Layer layer,
+ float alpha) const;
+ Error setLayerSidebandStream(Display display, Layer layer,
+ const native_handle_t* stream) const;
+ Error setLayerSourceCrop(Display display, Layer layer,
+ const IComposer::FRect& crop) const;
+ Error setLayerTransform(Display display, Layer layer,
+ Transform transform) const;
+ Error setLayerVisibleRegion(Display display, Layer layer,
+ const std::vector<IComposer::Rect>& visible) const;
+ Error setLayerZOrder(Display display, Layer layer, uint32_t z) const;
+
+private:
+ sp<IComposer> mService;
+};
+
+} // namespace Hwc2
+
+} // namespace android
+
+#endif // ANDROID_SF_COMPOSER_HAL_H
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp
index 4fe3cfd..c79caf4 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp
@@ -21,6 +21,7 @@
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
#include "HWC2.h"
+#include "ComposerHal.h"
#include "FloatRect.h"
@@ -79,11 +80,16 @@
using android::Rect;
using android::Region;
using android::sp;
+using android::hardware::Return;
+using android::hardware::Void;
namespace HWC2 {
+namespace Hwc2 = android::Hwc2;
+
// Device methods
+#ifdef BYPASS_IHWC
Device::Device(hwc2_device_t* device)
: mHwcDevice(device),
mCreateVirtualDisplay(nullptr),
@@ -128,6 +134,10 @@
mSetLayerTransform(nullptr),
mSetLayerVisibleRegion(nullptr),
mSetLayerZOrder(nullptr),
+#else
+Device::Device()
+ : mComposer(std::make_unique<Hwc2::Composer>()),
+#endif // BYPASS_IHWC
mCapabilities(),
mDisplays(),
mHotplug(),
@@ -144,9 +154,11 @@
Device::~Device()
{
+#ifdef BYPASS_IHWC
if (mHwcDevice == nullptr) {
return;
}
+#endif
for (auto element : mDisplays) {
auto display = element.second.lock();
@@ -175,13 +187,16 @@
}
}
+#ifdef BYPASS_IHWC
hwc2_close(mHwcDevice);
+#endif
}
// Required by HWC2 device
std::string Device::dump() const
{
+#ifdef BYPASS_IHWC
uint32_t numBytes = 0;
mDump(mHwcDevice, &numBytes, nullptr);
@@ -189,11 +204,18 @@
mDump(mHwcDevice, &numBytes, buffer.data());
return std::string(buffer.data(), buffer.size());
+#else
+ return mComposer->dumpDebugInfo();
+#endif
}
uint32_t Device::getMaxVirtualDisplayCount() const
{
+#ifdef BYPASS_IHWC
return mGetMaxVirtualDisplayCount(mHwcDevice);
+#else
+ return mComposer->getMaxVirtualDisplayCount();
+#endif
}
Error Device::createVirtualDisplay(uint32_t width, uint32_t height,
@@ -202,9 +224,15 @@
ALOGI("Creating virtual display");
hwc2_display_t displayId = 0;
+#ifdef BYPASS_IHWC
int32_t intFormat = static_cast<int32_t>(*format);
int32_t intError = mCreateVirtualDisplay(mHwcDevice, width, height,
&intFormat, &displayId);
+#else
+ auto intFormat = static_cast<Hwc2::PixelFormat>(*format);
+ auto intError = mComposer->createVirtualDisplay(width, height,
+ intFormat, displayId);
+#endif
auto error = static_cast<Error>(intError);
if (error != Error::None) {
return error;
@@ -315,6 +343,7 @@
{
static_assert(sizeof(Capability) == sizeof(int32_t),
"Capability size has changed");
+#ifdef BYPASS_IHWC
uint32_t numCapabilities = 0;
mHwcDevice->getCapabilities(mHwcDevice, &numCapabilities, nullptr);
std::vector<Capability> capabilities(numCapabilities);
@@ -323,6 +352,12 @@
for (auto capability : capabilities) {
mCapabilities.emplace(capability);
}
+#else
+ auto capabilities = mComposer->getCapabilities();
+ for (auto capability : capabilities) {
+ mCapabilities.emplace(static_cast<Capability>(capability));
+ }
+#endif
}
bool Device::hasCapability(HWC2::Capability capability) const
@@ -333,6 +368,7 @@
void Device::loadFunctionPointers()
{
+#ifdef BYPASS_IHWC
// For all of these early returns, we log an error message inside
// loadFunctionPointer specifying which function failed to load
@@ -426,13 +462,48 @@
mSetLayerVisibleRegion)) return;
if (!loadFunctionPointer(FunctionDescriptor::SetLayerZOrder,
mSetLayerZOrder)) return;
+#endif // BYPASS_IHWC
}
+namespace {
+class ComposerCallback : public Hwc2::IComposerCallback {
+public:
+ ComposerCallback(Device* device) : mDevice(device) {}
+
+ Return<void> onHotplug(Hwc2::Display display,
+ Connection connected) override
+ {
+ hotplug_hook(mDevice, display, static_cast<int32_t>(connected));
+ return Void();
+ }
+
+ Return<void> onRefresh(Hwc2::Display display) override
+ {
+ refresh_hook(mDevice, display);
+ return Void();
+ }
+
+ Return<void> onVsync(Hwc2::Display display, int64_t timestamp) override
+ {
+ vsync_hook(mDevice, display, timestamp);
+ return Void();
+ }
+
+private:
+ Device* mDevice;
+};
+} // namespace anonymous
+
void Device::registerCallbacks()
{
+#ifdef BYPASS_IHWC
registerCallback<HWC2_PFN_HOTPLUG>(Callback::Hotplug, hotplug_hook);
registerCallback<HWC2_PFN_REFRESH>(Callback::Refresh, refresh_hook);
registerCallback<HWC2_PFN_VSYNC>(Callback::Vsync, vsync_hook);
+#else
+ sp<ComposerCallback> callback = new ComposerCallback(this);
+ mComposer->registerCallback(callback);
+#endif
}
@@ -441,7 +512,11 @@
void Device::destroyVirtualDisplay(hwc2_display_t display)
{
ALOGI("Destroying virtual display");
+#ifdef BYPASS_IHWC
int32_t intError = mDestroyVirtualDisplay(mHwcDevice, display);
+#else
+ auto intError = mComposer->destroyVirtualDisplay(display);
+#endif
auto error = static_cast<Error>(intError);
ALOGE_IF(error != Error::None, "destroyVirtualDisplay(%" PRIu64 ") failed:"
" %s (%d)", display, to_string(error).c_str(), intError);
@@ -498,14 +573,22 @@
Error Display::acceptChanges()
{
+#ifdef BYPASS_IHWC
int32_t intError = mDevice.mAcceptDisplayChanges(mDevice.mHwcDevice, mId);
+#else
+ auto intError = mDevice.mComposer->acceptDisplayChanges(mId);
+#endif
return static_cast<Error>(intError);
}
Error Display::createLayer(std::shared_ptr<Layer>* outLayer)
{
hwc2_layer_t layerId = 0;
+#ifdef BYPASS_IHWC
int32_t intError = mDevice.mCreateLayer(mDevice.mHwcDevice, mId, &layerId);
+#else
+ auto intError = mDevice.mComposer->createLayer(mId, layerId);
+#endif
auto error = static_cast<Error>(intError);
if (error != Error::None) {
return error;
@@ -522,8 +605,12 @@
{
ALOGV("[%" PRIu64 "] getActiveConfig", mId);
hwc2_config_t configId = 0;
+#ifdef BYPASS_IHWC
int32_t intError = mDevice.mGetActiveConfig(mDevice.mHwcDevice, mId,
&configId);
+#else
+ auto intError = mDevice.mComposer->getActiveConfig(mId, configId);
+#endif
auto error = static_cast<Error>(intError);
if (error != Error::None) {
@@ -546,6 +633,7 @@
Error Display::getChangedCompositionTypes(
std::unordered_map<std::shared_ptr<Layer>, Composition>* outTypes)
{
+#ifdef BYPASS_IHWC
uint32_t numElements = 0;
int32_t intError = mDevice.mGetChangedCompositionTypes(mDevice.mHwcDevice,
mId, &numElements, nullptr, nullptr);
@@ -558,6 +646,14 @@
std::vector<int32_t> types(numElements);
intError = mDevice.mGetChangedCompositionTypes(mDevice.mHwcDevice, mId,
&numElements, layerIds.data(), types.data());
+#else
+ std::vector<Hwc2::Layer> layerIds;
+ std::vector<Hwc2::IComposer::Composition> types;
+ auto intError = mDevice.mComposer->getChangedCompositionTypes(mId,
+ layerIds, types);
+ uint32_t numElements = layerIds.size();
+ auto error = static_cast<Error>(intError);
+#endif
error = static_cast<Error>(intError);
if (error != Error::None) {
return error;
@@ -583,6 +679,7 @@
Error Display::getColorModes(std::vector<android_color_mode_t>* outModes) const
{
+#ifdef BYPASS_IHWC
uint32_t numModes = 0;
int32_t intError = mDevice.mGetColorModes(mDevice.mHwcDevice, mId,
&numModes, nullptr);
@@ -595,6 +692,12 @@
intError = mDevice.mGetColorModes(mDevice.mHwcDevice, mId, &numModes,
modes.data());
error = static_cast<Error>(intError);
+#else
+ std::vector<Hwc2::ColorMode> modes;
+ auto intError = mDevice.mComposer->getColorModes(mId, modes);
+ uint32_t numModes = modes.size();
+ auto error = static_cast<Error>(intError);
+#endif
if (error != Error::None) {
return error;
}
@@ -617,6 +720,7 @@
Error Display::getName(std::string* outName) const
{
+#ifdef BYPASS_IHWC
uint32_t size;
int32_t intError = mDevice.mGetDisplayName(mDevice.mHwcDevice, mId, &size,
nullptr);
@@ -635,12 +739,17 @@
*outName = std::string(rawName.cbegin(), rawName.cend());
return Error::None;
+#else
+ auto intError = mDevice.mComposer->getDisplayName(mId, *outName);
+ return static_cast<Error>(intError);
+#endif
}
Error Display::getRequests(HWC2::DisplayRequest* outDisplayRequests,
std::unordered_map<std::shared_ptr<Layer>, LayerRequest>*
outLayerRequests)
{
+#ifdef BYPASS_IHWC
int32_t intDisplayRequests = 0;
uint32_t numElements = 0;
int32_t intError = mDevice.mGetDisplayRequests(mDevice.mHwcDevice, mId,
@@ -656,6 +765,15 @@
&intDisplayRequests, &numElements, layerIds.data(),
layerRequests.data());
error = static_cast<Error>(intError);
+#else
+ uint32_t intDisplayRequests;
+ std::vector<Hwc2::Layer> layerIds;
+ std::vector<uint32_t> layerRequests;
+ auto intError = mDevice.mComposer->getDisplayRequests(mId,
+ intDisplayRequests, layerIds, layerRequests);
+ uint32_t numElements = layerIds.size();
+ auto error = static_cast<Error>(intError);
+#endif
if (error != Error::None) {
return error;
}
@@ -680,9 +798,15 @@
Error Display::getType(DisplayType* outType) const
{
+#ifdef BYPASS_IHWC
int32_t intType = 0;
int32_t intError = mDevice.mGetDisplayType(mDevice.mHwcDevice, mId,
&intType);
+#else
+ Hwc2::IComposer::DisplayType intType =
+ Hwc2::IComposer::DisplayType::INVALID;
+ auto intError = mDevice.mComposer->getDisplayType(mId, intType);
+#endif
auto error = static_cast<Error>(intError);
if (error != Error::None) {
return error;
@@ -694,9 +818,14 @@
Error Display::supportsDoze(bool* outSupport) const
{
+#ifdef BYPASS_IHWC
int32_t intSupport = 0;
int32_t intError = mDevice.mGetDozeSupport(mDevice.mHwcDevice, mId,
&intSupport);
+#else
+ bool intSupport = false;
+ auto intError = mDevice.mComposer->getDozeSupport(mId, intSupport);
+#endif
auto error = static_cast<Error>(intError);
if (error != Error::None) {
return error;
@@ -712,6 +841,7 @@
float maxLuminance = -1.0f;
float maxAverageLuminance = -1.0f;
float minLuminance = -1.0f;
+#ifdef BYPASS_IHWC
int32_t intError = mDevice.mGetHdrCapabilities(mDevice.mHwcDevice, mId,
&numTypes, nullptr, &maxLuminance, &maxAverageLuminance,
&minLuminance);
@@ -724,6 +854,18 @@
intError = mDevice.mGetHdrCapabilities(mDevice.mHwcDevice, mId, &numTypes,
types.data(), &maxLuminance, &maxAverageLuminance, &minLuminance);
error = static_cast<HWC2::Error>(intError);
+#else
+ std::vector<Hwc2::Hdr> intTypes;
+ auto intError = mDevice.mComposer->getHdrCapabilities(mId, intTypes,
+ maxLuminance, maxAverageLuminance, minLuminance);
+ auto error = static_cast<HWC2::Error>(intError);
+
+ std::vector<int32_t> types;
+ for (auto type : intTypes) {
+ types.push_back(static_cast<int32_t>(type));
+ }
+ numTypes = types.size();
+#endif
if (error != Error::None) {
return error;
}
@@ -736,6 +878,7 @@
Error Display::getReleaseFences(
std::unordered_map<std::shared_ptr<Layer>, sp<Fence>>* outFences) const
{
+#ifdef BYPASS_IHWC
uint32_t numElements = 0;
int32_t intError = mDevice.mGetReleaseFences(mDevice.mHwcDevice, mId,
&numElements, nullptr, nullptr);
@@ -749,6 +892,14 @@
intError = mDevice.mGetReleaseFences(mDevice.mHwcDevice, mId, &numElements,
layerIds.data(), fenceFds.data());
error = static_cast<Error>(intError);
+#else
+ std::vector<Hwc2::Layer> layerIds;
+ std::vector<int> fenceFds;
+ auto intError = mDevice.mComposer->getReleaseFences(mId,
+ layerIds, fenceFds);
+ auto error = static_cast<Error>(intError);
+ uint32_t numElements = layerIds.size();
+#endif
if (error != Error::None) {
return error;
}
@@ -774,8 +925,12 @@
Error Display::present(sp<Fence>* outRetireFence)
{
int32_t retireFenceFd = 0;
+#ifdef BYPASS_IHWC
int32_t intError = mDevice.mPresentDisplay(mDevice.mHwcDevice, mId,
&retireFenceFd);
+#else
+ auto intError = mDevice.mComposer->presentDisplay(mId, retireFenceFd);
+#endif
auto error = static_cast<Error>(intError);
if (error != Error::None) {
return error;
@@ -793,8 +948,12 @@
config->getDisplayId(), mId);
return Error::BadConfig;
}
+#ifdef BYPASS_IHWC
int32_t intError = mDevice.mSetActiveConfig(mDevice.mHwcDevice, mId,
config->getId());
+#else
+ auto intError = mDevice.mComposer->setActiveConfig(mId, config->getId());
+#endif
return static_cast<Error>(intError);
}
@@ -803,22 +962,38 @@
{
// TODO: Properly encode client target surface damage
int32_t fenceFd = acquireFence->dup();
+#ifdef BYPASS_IHWC
int32_t intError = mDevice.mSetClientTarget(mDevice.mHwcDevice, mId, target,
fenceFd, static_cast<int32_t>(dataspace), {0, nullptr});
+#else
+ auto intError = mDevice.mComposer->setClientTarget(mId, target, fenceFd,
+ static_cast<Hwc2::Dataspace>(dataspace),
+ std::vector<Hwc2::IComposer::Rect>());
+#endif
return static_cast<Error>(intError);
}
Error Display::setColorMode(android_color_mode_t mode)
{
+#ifdef BYPASS_IHWC
int32_t intError = mDevice.mSetColorMode(mDevice.mHwcDevice, mId, mode);
+#else
+ auto intError = mDevice.mComposer->setColorMode(mId,
+ static_cast<Hwc2::ColorMode>(mode));
+#endif
return static_cast<Error>(intError);
}
Error Display::setColorTransform(const android::mat4& matrix,
android_color_transform_t hint)
{
+#ifdef BYPASS_IHWC
int32_t intError = mDevice.mSetColorTransform(mDevice.mHwcDevice, mId,
matrix.asArray(), static_cast<int32_t>(hint));
+#else
+ auto intError = mDevice.mComposer->setColorTransform(mId,
+ matrix.asArray(), static_cast<Hwc2::ColorTransform>(hint));
+#endif
return static_cast<Error>(intError);
}
@@ -827,24 +1002,38 @@
{
int32_t fenceFd = releaseFence->dup();
auto handle = buffer->getNativeBuffer()->handle;
+#ifdef BYPASS_IHWC
int32_t intError = mDevice.mSetOutputBuffer(mDevice.mHwcDevice, mId, handle,
fenceFd);
+#else
+ auto intError = mDevice.mComposer->setOutputBuffer(mId, handle, fenceFd);
+#endif
close(fenceFd);
return static_cast<Error>(intError);
}
Error Display::setPowerMode(PowerMode mode)
{
+#ifdef BYPASS_IHWC
auto intMode = static_cast<int32_t>(mode);
int32_t intError = mDevice.mSetPowerMode(mDevice.mHwcDevice, mId, intMode);
+#else
+ auto intMode = static_cast<Hwc2::IComposer::PowerMode>(mode);
+ auto intError = mDevice.mComposer->setPowerMode(mId, intMode);
+#endif
return static_cast<Error>(intError);
}
Error Display::setVsyncEnabled(Vsync enabled)
{
+#ifdef BYPASS_IHWC
auto intEnabled = static_cast<int32_t>(enabled);
int32_t intError = mDevice.mSetVsyncEnabled(mDevice.mHwcDevice, mId,
intEnabled);
+#else
+ auto intEnabled = static_cast<Hwc2::IComposer::Vsync>(enabled);
+ auto intError = mDevice.mComposer->setVsyncEnabled(mId, intEnabled);
+#endif
return static_cast<Error>(intError);
}
@@ -852,8 +1041,13 @@
{
uint32_t numTypes = 0;
uint32_t numRequests = 0;
+#ifdef BYPASS_IHWC
int32_t intError = mDevice.mValidateDisplay(mDevice.mHwcDevice, mId,
&numTypes, &numRequests);
+#else
+ auto intError = mDevice.mComposer->validateDisplay(mId,
+ numTypes, numRequests);
+#endif
auto error = static_cast<Error>(intError);
if (error != Error::None && error != Error::HasChanges) {
return error;
@@ -869,8 +1063,14 @@
int32_t Display::getAttribute(hwc2_config_t configId, Attribute attribute)
{
int32_t value = 0;
+#ifdef BYPASS_IHWC
int32_t intError = mDevice.mGetDisplayAttribute(mDevice.mHwcDevice, mId,
configId, static_cast<int32_t>(attribute), &value);
+#else
+ auto intError = mDevice.mComposer->getDisplayAttribute(mId,
+ configId, static_cast<Hwc2::IComposer::Attribute>(attribute),
+ value);
+#endif
auto error = static_cast<Error>(intError);
if (error != Error::None) {
ALOGE("getDisplayAttribute(%" PRIu64 ", %u, %s) failed: %s (%d)", mId,
@@ -899,6 +1099,7 @@
{
ALOGV("[%" PRIu64 "] loadConfigs", mId);
+#ifdef BYPASS_IHWC
uint32_t numConfigs = 0;
int32_t intError = mDevice.mGetDisplayConfigs(mDevice.mHwcDevice, mId,
&numConfigs, nullptr);
@@ -913,6 +1114,11 @@
intError = mDevice.mGetDisplayConfigs(mDevice.mHwcDevice, mId, &numConfigs,
configIds.data());
error = static_cast<Error>(intError);
+#else
+ std::vector<Hwc2::Config> configIds;
+ auto intError = mDevice.mComposer->getDisplayConfigs(mId, configIds);
+ auto error = static_cast<Error>(intError);
+#endif
if (error != Error::None) {
ALOGE("[%" PRIu64 "] getDisplayConfigs [2] failed: %s (%d)", mId,
to_string(error).c_str(), intError);
@@ -928,7 +1134,11 @@
void Display::destroyLayer(hwc2_layer_t layerId)
{
+#ifdef BYPASS_IHWC
int32_t intError = mDevice.mDestroyLayer(mDevice.mHwcDevice, mId, layerId);
+#else
+ auto intError =mDevice.mComposer->destroyLayer(mId, layerId);
+#endif
auto error = static_cast<Error>(intError);
ALOGE_IF(error != Error::None, "destroyLayer(%" PRIu64 ", %" PRIu64 ")"
" failed: %s (%d)", mId, layerId, to_string(error).c_str(),
@@ -970,8 +1180,13 @@
Error Layer::setCursorPosition(int32_t x, int32_t y)
{
+#ifdef BYPASS_IHWC
int32_t intError = mDevice.mSetCursorPosition(mDevice.mHwcDevice,
mDisplayId, mId, x, y);
+#else
+ auto intError = mDevice.mComposer->setCursorPosition(mDisplayId,
+ mId, x, y);
+#endif
return static_cast<Error>(intError);
}
@@ -979,8 +1194,13 @@
const sp<Fence>& acquireFence)
{
int32_t fenceFd = acquireFence->dup();
+#ifdef BYPASS_IHWC
int32_t intError = mDevice.mSetLayerBuffer(mDevice.mHwcDevice, mDisplayId,
mId, buffer, fenceFd);
+#else
+ auto intError = mDevice.mComposer->setLayerBuffer(mDisplayId,
+ mId, buffer, fenceFd);
+#endif
return static_cast<Error>(intError);
}
@@ -988,26 +1208,44 @@
{
// We encode default full-screen damage as INVALID_RECT upstream, but as 0
// rects for HWC
+#ifdef BYPASS_IHWC
int32_t intError = 0;
+#else
+ Hwc2::Error intError = Hwc2::Error::NONE;
+#endif
if (damage.isRect() && damage.getBounds() == Rect::INVALID_RECT) {
+#ifdef BYPASS_IHWC
intError = mDevice.mSetLayerSurfaceDamage(mDevice.mHwcDevice,
mDisplayId, mId, {0, nullptr});
+#else
+ intError = mDevice.mComposer->setLayerSurfaceDamage(mDisplayId,
+ mId, std::vector<Hwc2::IComposer::Rect>());
+#endif
} else {
size_t rectCount = 0;
auto rectArray = damage.getArray(&rectCount);
+#ifdef BYPASS_IHWC
std::vector<hwc_rect_t> hwcRects;
+#else
+ std::vector<Hwc2::IComposer::Rect> hwcRects;
+#endif
for (size_t rect = 0; rect < rectCount; ++rect) {
hwcRects.push_back({rectArray[rect].left, rectArray[rect].top,
rectArray[rect].right, rectArray[rect].bottom});
}
+#ifdef BYPASS_IHWC
hwc_region_t hwcRegion = {};
hwcRegion.numRects = rectCount;
hwcRegion.rects = hwcRects.data();
intError = mDevice.mSetLayerSurfaceDamage(mDevice.mHwcDevice,
mDisplayId, mId, hwcRegion);
+#else
+ intError = mDevice.mComposer->setLayerSurfaceDamage(mDisplayId,
+ mId, hwcRects);
+#endif
}
return static_cast<Error>(intError);
@@ -1015,47 +1253,83 @@
Error Layer::setBlendMode(BlendMode mode)
{
+#ifdef BYPASS_IHWC
auto intMode = static_cast<int32_t>(mode);
int32_t intError = mDevice.mSetLayerBlendMode(mDevice.mHwcDevice,
mDisplayId, mId, intMode);
+#else
+ auto intMode = static_cast<Hwc2::IComposer::BlendMode>(mode);
+ auto intError = mDevice.mComposer->setLayerBlendMode(mDisplayId,
+ mId, intMode);
+#endif
return static_cast<Error>(intError);
}
Error Layer::setColor(hwc_color_t color)
{
+#ifdef BYPASS_IHWC
int32_t intError = mDevice.mSetLayerColor(mDevice.mHwcDevice, mDisplayId,
mId, color);
+#else
+ Hwc2::IComposer::Color hwcColor{color.r, color.g, color.b, color.a};
+ auto intError = mDevice.mComposer->setLayerColor(mDisplayId,
+ mId, hwcColor);
+#endif
return static_cast<Error>(intError);
}
Error Layer::setCompositionType(Composition type)
{
+#ifdef BYPASS_IHWC
auto intType = static_cast<int32_t>(type);
int32_t intError = mDevice.mSetLayerCompositionType(mDevice.mHwcDevice,
mDisplayId, mId, intType);
+#else
+ auto intType = static_cast<Hwc2::IComposer::Composition>(type);
+ auto intError = mDevice.mComposer->setLayerCompositionType(mDisplayId,
+ mId, intType);
+#endif
return static_cast<Error>(intError);
}
Error Layer::setDataspace(android_dataspace_t dataspace)
{
+#ifdef BYPASS_IHWC
auto intDataspace = static_cast<int32_t>(dataspace);
int32_t intError = mDevice.mSetLayerDataspace(mDevice.mHwcDevice,
mDisplayId, mId, intDataspace);
+#else
+ auto intDataspace = static_cast<Hwc2::Dataspace>(dataspace);
+ auto intError = mDevice.mComposer->setLayerDataspace(mDisplayId,
+ mId, intDataspace);
+#endif
return static_cast<Error>(intError);
}
Error Layer::setDisplayFrame(const Rect& frame)
{
+#ifdef BYPASS_IHWC
hwc_rect_t hwcRect{frame.left, frame.top, frame.right, frame.bottom};
int32_t intError = mDevice.mSetLayerDisplayFrame(mDevice.mHwcDevice,
mDisplayId, mId, hwcRect);
+#else
+ Hwc2::IComposer::Rect hwcRect{frame.left, frame.top,
+ frame.right, frame.bottom};
+ auto intError = mDevice.mComposer->setLayerDisplayFrame(mDisplayId,
+ mId, hwcRect);
+#endif
return static_cast<Error>(intError);
}
Error Layer::setPlaneAlpha(float alpha)
{
+#ifdef BYPASS_IHWC
int32_t intError = mDevice.mSetLayerPlaneAlpha(mDevice.mHwcDevice,
mDisplayId, mId, alpha);
+#else
+ auto intError = mDevice.mComposer->setLayerPlaneAlpha(mDisplayId,
+ mId, alpha);
+#endif
return static_cast<Error>(intError);
}
@@ -1066,24 +1340,42 @@
"device supports sideband streams");
return Error::Unsupported;
}
+#ifdef BYPASS_IHWC
int32_t intError = mDevice.mSetLayerSidebandStream(mDevice.mHwcDevice,
mDisplayId, mId, stream);
+#else
+ auto intError = mDevice.mComposer->setLayerSidebandStream(mDisplayId,
+ mId, stream);
+#endif
return static_cast<Error>(intError);
}
Error Layer::setSourceCrop(const FloatRect& crop)
{
+#ifdef BYPASS_IHWC
hwc_frect_t hwcRect{crop.left, crop.top, crop.right, crop.bottom};
int32_t intError = mDevice.mSetLayerSourceCrop(mDevice.mHwcDevice,
mDisplayId, mId, hwcRect);
+#else
+ Hwc2::IComposer::FRect hwcRect{
+ crop.left, crop.top, crop.right, crop.bottom};
+ auto intError = mDevice.mComposer->setLayerSourceCrop(mDisplayId,
+ mId, hwcRect);
+#endif
return static_cast<Error>(intError);
}
Error Layer::setTransform(Transform transform)
{
+#ifdef BYPASS_IHWC
auto intTransform = static_cast<int32_t>(transform);
int32_t intError = mDevice.mSetLayerTransform(mDevice.mHwcDevice,
mDisplayId, mId, intTransform);
+#else
+ auto intTransform = static_cast<Hwc2::Transform>(transform);
+ auto intError = mDevice.mComposer->setLayerTransform(mDisplayId,
+ mId, intTransform);
+#endif
return static_cast<Error>(intError);
}
@@ -1092,25 +1384,38 @@
size_t rectCount = 0;
auto rectArray = region.getArray(&rectCount);
+#ifdef BYPASS_IHWC
std::vector<hwc_rect_t> hwcRects;
+#else
+ std::vector<Hwc2::IComposer::Rect> hwcRects;
+#endif
for (size_t rect = 0; rect < rectCount; ++rect) {
hwcRects.push_back({rectArray[rect].left, rectArray[rect].top,
rectArray[rect].right, rectArray[rect].bottom});
}
+#ifdef BYPASS_IHWC
hwc_region_t hwcRegion = {};
hwcRegion.numRects = rectCount;
hwcRegion.rects = hwcRects.data();
int32_t intError = mDevice.mSetLayerVisibleRegion(mDevice.mHwcDevice,
mDisplayId, mId, hwcRegion);
+#else
+ auto intError = mDevice.mComposer->setLayerVisibleRegion(mDisplayId,
+ mId, hwcRects);
+#endif
return static_cast<Error>(intError);
}
Error Layer::setZOrder(uint32_t z)
{
+#ifdef BYPASS_IHWC
int32_t intError = mDevice.mSetLayerZOrder(mDevice.mHwcDevice, mDisplayId,
mId, z);
+#else
+ auto intError = mDevice.mComposer->setLayerZOrder(mDisplayId, mId, z);
+#endif
return static_cast<Error>(intError);
}
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.h b/services/surfaceflinger/DisplayHardware/HWC2.h
index 32a9de0..1145ba1 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.h
+++ b/services/surfaceflinger/DisplayHardware/HWC2.h
@@ -17,6 +17,10 @@
#ifndef ANDROID_SF_HWC2_H
#define ANDROID_SF_HWC2_H
+#ifndef USE_HWC2
+#define BYPASS_IHWC
+#endif
+
#define HWC2_INCLUDE_STRINGIFICATION
#define HWC2_USE_CPP11
#include <hardware/hwcomposer2.h>
@@ -42,6 +46,9 @@
class GraphicBuffer;
class Rect;
class Region;
+ namespace Hwc2 {
+ class Composer;
+ };
}
namespace HWC2 {
@@ -57,7 +64,11 @@
class Device
{
public:
+#ifdef BYPASS_IHWC
explicit Device(hwc2_device_t* device);
+#else
+ Device();
+#endif
~Device();
friend class HWC2::Display;
@@ -98,6 +109,7 @@
private:
// Initialization methods
+#ifdef BYPASS_IHWC
template <typename PFN>
[[clang::warn_unused_result]] bool loadFunctionPointer(
FunctionDescriptor desc, PFN& outPFN) {
@@ -121,6 +133,7 @@
auto pfn = reinterpret_cast<hwc2_function_pointer_t>(hook);
mRegisterCallback(mHwcDevice, intCallback, callbackData, pfn);
}
+#endif
void loadCapabilities();
void loadFunctionPointers();
@@ -132,6 +145,7 @@
// Member variables
+#ifdef BYPASS_IHWC
hwc2_device_t* mHwcDevice;
// Device function pointers
@@ -181,6 +195,9 @@
HWC2_PFN_SET_LAYER_TRANSFORM mSetLayerTransform;
HWC2_PFN_SET_LAYER_VISIBLE_REGION mSetLayerVisibleRegion;
HWC2_PFN_SET_LAYER_Z_ORDER mSetLayerZOrder;
+#else
+ std::unique_ptr<android::Hwc2::Composer> mComposer;
+#endif // BYPASS_IHWC
std::unordered_set<Capability> mCapabilities;
std::unordered_map<hwc2_display_t, std::weak_ptr<Display>> mDisplays;
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index c87ba72..bb2e45a 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -109,6 +109,7 @@
{
ALOGV("loadHwcModule");
+#ifdef BYPASS_IHWC
hw_module_t const* module;
if (hw_get_module(HWC_HARDWARE_MODULE_ID, &module) != 0) {
@@ -140,6 +141,9 @@
mHwcDevice = std::make_unique<HWC2::Device>(
static_cast<hwc2_device_t*>(mAdapter.get()));
}
+#else
+ mHwcDevice = std::make_unique<HWC2::Device>();
+#endif
mRemainingHwcVirtualDisplays = mHwcDevice->getMaxVirtualDisplayCount();
}
diff --git a/services/surfaceflinger/DisplayHardware/PowerHAL.cpp b/services/surfaceflinger/DisplayHardware/PowerHAL.cpp
index bd50b4a..1c0a1fe 100644
--- a/services/surfaceflinger/DisplayHardware/PowerHAL.cpp
+++ b/services/surfaceflinger/DisplayHardware/PowerHAL.cpp
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#include <android/hardware/power/1.0/IPower.h>
#include <stdint.h>
#include <sys/types.h>
@@ -26,6 +27,7 @@
#include "PowerHAL.h"
+using android::hardware::power::V1_0::PowerHint;
namespace android {
// ---------------------------------------------------------------------------
@@ -39,7 +41,9 @@
}
mPowerManager = interface_cast<IPowerManager>(bs);
}
- status_t status = mPowerManager->powerHint(POWER_HINT_VSYNC, enabled ? 1 : 0);
+ status_t status;
+ status = mPowerManager->powerHint(static_cast<int>(PowerHint::VSYNC),
+ enabled ? 1 : 0);
if(status == DEAD_OBJECT) {
mPowerManager = NULL;
}
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 6a3d62b..d420f0f 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -1803,127 +1803,81 @@
}
Region outDirtyRegion;
- if (mQueuedFrames > 0 || mAutoRefresh) {
+ if (mQueuedFrames <= 0 && !mAutoRefresh) {
+ return outDirtyRegion;
+ }
- // if we've already called updateTexImage() without going through
- // a composition step, we have to skip this layer at this point
- // because we cannot call updateTeximage() without a corresponding
- // compositionComplete() call.
- // we'll trigger an update in onPreComposition().
- if (mRefreshPending) {
- return outDirtyRegion;
+ // if we've already called updateTexImage() without going through
+ // a composition step, we have to skip this layer at this point
+ // because we cannot call updateTeximage() without a corresponding
+ // compositionComplete() call.
+ // we'll trigger an update in onPreComposition().
+ if (mRefreshPending) {
+ return outDirtyRegion;
+ }
+
+ // If the head buffer's acquire fence hasn't signaled yet, return and
+ // try again later
+ if (!headFenceHasSignaled()) {
+ mFlinger->signalLayerUpdate();
+ return outDirtyRegion;
+ }
+
+ // Capture the old state of the layer for comparisons later
+ const State& s(getDrawingState());
+ const bool oldOpacity = isOpaque(s);
+ sp<GraphicBuffer> oldActiveBuffer = mActiveBuffer;
+
+ struct Reject : public SurfaceFlingerConsumer::BufferRejecter {
+ Layer::State& front;
+ Layer::State& current;
+ bool& recomputeVisibleRegions;
+ bool stickyTransformSet;
+ const char* name;
+ int32_t overrideScalingMode;
+ bool& freezePositionUpdates;
+
+ Reject(Layer::State& front, Layer::State& current,
+ bool& recomputeVisibleRegions, bool stickySet,
+ const char* name,
+ int32_t overrideScalingMode,
+ bool& freezePositionUpdates)
+ : front(front), current(current),
+ recomputeVisibleRegions(recomputeVisibleRegions),
+ stickyTransformSet(stickySet),
+ name(name),
+ overrideScalingMode(overrideScalingMode),
+ freezePositionUpdates(freezePositionUpdates) {
}
- // If the head buffer's acquire fence hasn't signaled yet, return and
- // try again later
- if (!headFenceHasSignaled()) {
- mFlinger->signalLayerUpdate();
- return outDirtyRegion;
- }
-
- // Capture the old state of the layer for comparisons later
- const State& s(getDrawingState());
- const bool oldOpacity = isOpaque(s);
- sp<GraphicBuffer> oldActiveBuffer = mActiveBuffer;
-
- struct Reject : public SurfaceFlingerConsumer::BufferRejecter {
- Layer::State& front;
- Layer::State& current;
- bool& recomputeVisibleRegions;
- bool stickyTransformSet;
- const char* name;
- int32_t overrideScalingMode;
- bool& freezePositionUpdates;
-
- Reject(Layer::State& front, Layer::State& current,
- bool& recomputeVisibleRegions, bool stickySet,
- const char* name,
- int32_t overrideScalingMode,
- bool& freezePositionUpdates)
- : front(front), current(current),
- recomputeVisibleRegions(recomputeVisibleRegions),
- stickyTransformSet(stickySet),
- name(name),
- overrideScalingMode(overrideScalingMode),
- freezePositionUpdates(freezePositionUpdates) {
+ virtual bool reject(const sp<GraphicBuffer>& buf,
+ const BufferItem& item) {
+ if (buf == NULL) {
+ return false;
}
- virtual bool reject(const sp<GraphicBuffer>& buf,
- const BufferItem& item) {
- if (buf == NULL) {
- return false;
- }
+ uint32_t bufWidth = buf->getWidth();
+ uint32_t bufHeight = buf->getHeight();
- uint32_t bufWidth = buf->getWidth();
- uint32_t bufHeight = buf->getHeight();
+ // check that we received a buffer of the right size
+ // (Take the buffer's orientation into account)
+ if (item.mTransform & Transform::ROT_90) {
+ swap(bufWidth, bufHeight);
+ }
- // check that we received a buffer of the right size
- // (Take the buffer's orientation into account)
- if (item.mTransform & Transform::ROT_90) {
- swap(bufWidth, bufHeight);
- }
+ int actualScalingMode = overrideScalingMode >= 0 ?
+ overrideScalingMode : item.mScalingMode;
+ bool isFixedSize = actualScalingMode != NATIVE_WINDOW_SCALING_MODE_FREEZE;
+ if (front.active != front.requested) {
- int actualScalingMode = overrideScalingMode >= 0 ?
- overrideScalingMode : item.mScalingMode;
- bool isFixedSize = actualScalingMode != NATIVE_WINDOW_SCALING_MODE_FREEZE;
- if (front.active != front.requested) {
-
- if (isFixedSize ||
- (bufWidth == front.requested.w &&
- bufHeight == front.requested.h))
- {
- // Here we pretend the transaction happened by updating the
- // current and drawing states. Drawing state is only accessed
- // in this thread, no need to have it locked
- front.active = front.requested;
-
- // We also need to update the current state so that
- // we don't end-up overwriting the drawing state with
- // this stale current state during the next transaction
- //
- // NOTE: We don't need to hold the transaction lock here
- // because State::active is only accessed from this thread.
- current.active = front.active;
- current.modified = true;
-
- // recompute visible region
- recomputeVisibleRegions = true;
- }
-
- ALOGD_IF(DEBUG_RESIZE,
- "[%s] latchBuffer/reject: buffer (%ux%u, tr=%02x), scalingMode=%d\n"
- " drawing={ active ={ wh={%4u,%4u} crop={%4d,%4d,%4d,%4d} (%4d,%4d) }\n"
- " requested={ wh={%4u,%4u} }}\n",
- name,
- bufWidth, bufHeight, item.mTransform, item.mScalingMode,
- front.active.w, front.active.h,
- front.crop.left,
- front.crop.top,
- front.crop.right,
- front.crop.bottom,
- front.crop.getWidth(),
- front.crop.getHeight(),
- front.requested.w, front.requested.h);
- }
-
- if (!isFixedSize && !stickyTransformSet) {
- if (front.active.w != bufWidth ||
- front.active.h != bufHeight) {
- // reject this buffer
- ALOGE("[%s] rejecting buffer: "
- "bufWidth=%d, bufHeight=%d, front.active.{w=%d, h=%d}",
- name, bufWidth, bufHeight, front.active.w, front.active.h);
- return true;
- }
- }
-
- // if the transparent region has changed (this test is
- // conservative, but that's fine, worst case we're doing
- // a bit of extra work), we latch the new one and we
- // trigger a visible-region recompute.
- if (!front.activeTransparentRegion.isTriviallyEqual(
- front.requestedTransparentRegion)) {
- front.activeTransparentRegion = front.requestedTransparentRegion;
+ if (isFixedSize ||
+ (bufWidth == front.requested.w &&
+ bufHeight == front.requested.h))
+ {
+ // Here we pretend the transaction happened by updating the
+ // current and drawing states. Drawing state is only accessed
+ // in this thread, no need to have it locked
+ front.active = front.requested;
// We also need to update the current state so that
// we don't end-up overwriting the drawing state with
@@ -1931,206 +1885,254 @@
//
// NOTE: We don't need to hold the transaction lock here
// because State::active is only accessed from this thread.
- current.activeTransparentRegion = front.activeTransparentRegion;
+ current.active = front.active;
+ current.modified = true;
// recompute visible region
recomputeVisibleRegions = true;
}
- if (front.crop != front.requestedCrop) {
- front.crop = front.requestedCrop;
- current.crop = front.requestedCrop;
- recomputeVisibleRegions = true;
+ ALOGD_IF(DEBUG_RESIZE,
+ "[%s] latchBuffer/reject: buffer (%ux%u, tr=%02x), scalingMode=%d\n"
+ " drawing={ active ={ wh={%4u,%4u} crop={%4d,%4d,%4d,%4d} (%4d,%4d) }\n"
+ " requested={ wh={%4u,%4u} }}\n",
+ name,
+ bufWidth, bufHeight, item.mTransform, item.mScalingMode,
+ front.active.w, front.active.h,
+ front.crop.left,
+ front.crop.top,
+ front.crop.right,
+ front.crop.bottom,
+ front.crop.getWidth(),
+ front.crop.getHeight(),
+ front.requested.w, front.requested.h);
+ }
+
+ if (!isFixedSize && !stickyTransformSet) {
+ if (front.active.w != bufWidth ||
+ front.active.h != bufHeight) {
+ // reject this buffer
+ ALOGE("[%s] rejecting buffer: "
+ "bufWidth=%d, bufHeight=%d, front.active.{w=%d, h=%d}",
+ name, bufWidth, bufHeight, front.active.w, front.active.h);
+ return true;
}
- freezePositionUpdates = false;
-
- return false;
- }
- };
-
- Reject r(mDrawingState, getCurrentState(), recomputeVisibleRegions,
- getProducerStickyTransform() != 0, mName.string(),
- mOverrideScalingMode, mFreezePositionUpdates);
-
-
- // Check all of our local sync points to ensure that all transactions
- // which need to have been applied prior to the frame which is about to
- // be latched have signaled
-
- auto headFrameNumber = getHeadFrameNumber();
- bool matchingFramesFound = false;
- bool allTransactionsApplied = true;
- {
- Mutex::Autolock lock(mLocalSyncPointMutex);
- for (auto& point : mLocalSyncPoints) {
- if (point->getFrameNumber() > headFrameNumber) {
- break;
- }
-
- matchingFramesFound = true;
-
- if (!point->frameIsAvailable()) {
- // We haven't notified the remote layer that the frame for
- // this point is available yet. Notify it now, and then
- // abort this attempt to latch.
- point->setFrameAvailable();
- allTransactionsApplied = false;
- break;
- }
-
- allTransactionsApplied &= point->transactionIsApplied();
- }
- }
-
- if (matchingFramesFound && !allTransactionsApplied) {
- mFlinger->signalLayerUpdate();
- return outDirtyRegion;
- }
-
- // This boolean is used to make sure that SurfaceFlinger's shadow copy
- // of the buffer queue isn't modified when the buffer queue is returning
- // BufferItem's that weren't actually queued. This can happen in shared
- // buffer mode.
- bool queuedBuffer = false;
- status_t updateResult = mSurfaceFlingerConsumer->updateTexImage(&r,
- mFlinger->mPrimaryDispSync, &mAutoRefresh, &queuedBuffer,
- mLastFrameNumberReceived);
- if (updateResult == BufferQueue::PRESENT_LATER) {
- // Producer doesn't want buffer to be displayed yet. Signal a
- // layer update so we check again at the next opportunity.
- mFlinger->signalLayerUpdate();
- return outDirtyRegion;
- } else if (updateResult == SurfaceFlingerConsumer::BUFFER_REJECTED) {
- // If the buffer has been rejected, remove it from the shadow queue
- // and return early
- if (queuedBuffer) {
- Mutex::Autolock lock(mQueueItemLock);
- mQueueItems.removeAt(0);
- android_atomic_dec(&mQueuedFrames);
- }
- return outDirtyRegion;
- } else if (updateResult != NO_ERROR || mUpdateTexImageFailed) {
- // This can occur if something goes wrong when trying to create the
- // EGLImage for this buffer. If this happens, the buffer has already
- // been released, so we need to clean up the queue and bug out
- // early.
- if (queuedBuffer) {
- Mutex::Autolock lock(mQueueItemLock);
- mQueueItems.clear();
- android_atomic_and(0, &mQueuedFrames);
}
- // Once we have hit this state, the shadow queue may no longer
- // correctly reflect the incoming BufferQueue's contents, so even if
- // updateTexImage starts working, the only safe course of action is
- // to continue to ignore updates.
- mUpdateTexImageFailed = true;
+ // if the transparent region has changed (this test is
+ // conservative, but that's fine, worst case we're doing
+ // a bit of extra work), we latch the new one and we
+ // trigger a visible-region recompute.
+ if (!front.activeTransparentRegion.isTriviallyEqual(
+ front.requestedTransparentRegion)) {
+ front.activeTransparentRegion = front.requestedTransparentRegion;
- return outDirtyRegion;
- }
+ // We also need to update the current state so that
+ // we don't end-up overwriting the drawing state with
+ // this stale current state during the next transaction
+ //
+ // NOTE: We don't need to hold the transaction lock here
+ // because State::active is only accessed from this thread.
+ current.activeTransparentRegion = front.activeTransparentRegion;
- if (queuedBuffer) {
- // Autolock scope
- auto currentFrameNumber = mSurfaceFlingerConsumer->getFrameNumber();
-
- Mutex::Autolock lock(mQueueItemLock);
-
- // Remove any stale buffers that have been dropped during
- // updateTexImage
- while (mQueueItems[0].mFrameNumber != currentFrameNumber) {
- mQueueItems.removeAt(0);
- android_atomic_dec(&mQueuedFrames);
- }
-
- mQueueItems.removeAt(0);
- }
-
-
- // Decrement the queued-frames count. Signal another event if we
- // have more frames pending.
- if ((queuedBuffer && android_atomic_dec(&mQueuedFrames) > 1)
- || mAutoRefresh) {
- mFlinger->signalLayerUpdate();
- }
-
- if (updateResult != NO_ERROR) {
- // something happened!
- recomputeVisibleRegions = true;
- return outDirtyRegion;
- }
-
- // update the active buffer
- mActiveBuffer = mSurfaceFlingerConsumer->getCurrentBuffer();
- if (mActiveBuffer == NULL) {
- // this can only happen if the very first buffer was rejected.
- return outDirtyRegion;
- }
-
- mRefreshPending = true;
- mFrameLatencyNeeded = true;
- if (oldActiveBuffer == NULL) {
- // the first time we receive a buffer, we need to trigger a
- // geometry invalidation.
- recomputeVisibleRegions = true;
- }
-
- Rect crop(mSurfaceFlingerConsumer->getCurrentCrop());
- const uint32_t transform(mSurfaceFlingerConsumer->getCurrentTransform());
- const uint32_t scalingMode(mSurfaceFlingerConsumer->getCurrentScalingMode());
- if ((crop != mCurrentCrop) ||
- (transform != mCurrentTransform) ||
- (scalingMode != mCurrentScalingMode))
- {
- mCurrentCrop = crop;
- mCurrentTransform = transform;
- mCurrentScalingMode = scalingMode;
- recomputeVisibleRegions = true;
- }
-
- if (oldActiveBuffer != NULL) {
- uint32_t bufWidth = mActiveBuffer->getWidth();
- uint32_t bufHeight = mActiveBuffer->getHeight();
- if (bufWidth != uint32_t(oldActiveBuffer->width) ||
- bufHeight != uint32_t(oldActiveBuffer->height)) {
+ // recompute visible region
recomputeVisibleRegions = true;
}
+
+ if (front.crop != front.requestedCrop) {
+ front.crop = front.requestedCrop;
+ current.crop = front.requestedCrop;
+ recomputeVisibleRegions = true;
+ }
+ freezePositionUpdates = false;
+
+ return false;
+ }
+ };
+
+ Reject r(mDrawingState, getCurrentState(), recomputeVisibleRegions,
+ getProducerStickyTransform() != 0, mName.string(),
+ mOverrideScalingMode, mFreezePositionUpdates);
+
+
+ // Check all of our local sync points to ensure that all transactions
+ // which need to have been applied prior to the frame which is about to
+ // be latched have signaled
+
+ auto headFrameNumber = getHeadFrameNumber();
+ bool matchingFramesFound = false;
+ bool allTransactionsApplied = true;
+ {
+ Mutex::Autolock lock(mLocalSyncPointMutex);
+ for (auto& point : mLocalSyncPoints) {
+ if (point->getFrameNumber() > headFrameNumber) {
+ break;
+ }
+
+ matchingFramesFound = true;
+
+ if (!point->frameIsAvailable()) {
+ // We haven't notified the remote layer that the frame for
+ // this point is available yet. Notify it now, and then
+ // abort this attempt to latch.
+ point->setFrameAvailable();
+ allTransactionsApplied = false;
+ break;
+ }
+
+ allTransactionsApplied &= point->transactionIsApplied();
+ }
+ }
+
+ if (matchingFramesFound && !allTransactionsApplied) {
+ mFlinger->signalLayerUpdate();
+ return outDirtyRegion;
+ }
+
+ // This boolean is used to make sure that SurfaceFlinger's shadow copy
+ // of the buffer queue isn't modified when the buffer queue is returning
+ // BufferItem's that weren't actually queued. This can happen in shared
+ // buffer mode.
+ bool queuedBuffer = false;
+ status_t updateResult = mSurfaceFlingerConsumer->updateTexImage(&r,
+ mFlinger->mPrimaryDispSync, &mAutoRefresh, &queuedBuffer,
+ mLastFrameNumberReceived);
+ if (updateResult == BufferQueue::PRESENT_LATER) {
+ // Producer doesn't want buffer to be displayed yet. Signal a
+ // layer update so we check again at the next opportunity.
+ mFlinger->signalLayerUpdate();
+ return outDirtyRegion;
+ } else if (updateResult == SurfaceFlingerConsumer::BUFFER_REJECTED) {
+ // If the buffer has been rejected, remove it from the shadow queue
+ // and return early
+ if (queuedBuffer) {
+ Mutex::Autolock lock(mQueueItemLock);
+ mQueueItems.removeAt(0);
+ android_atomic_dec(&mQueuedFrames);
+ }
+ return outDirtyRegion;
+ } else if (updateResult != NO_ERROR || mUpdateTexImageFailed) {
+ // This can occur if something goes wrong when trying to create the
+ // EGLImage for this buffer. If this happens, the buffer has already
+ // been released, so we need to clean up the queue and bug out
+ // early.
+ if (queuedBuffer) {
+ Mutex::Autolock lock(mQueueItemLock);
+ mQueueItems.clear();
+ android_atomic_and(0, &mQueuedFrames);
}
- mCurrentOpacity = getOpacityForFormat(mActiveBuffer->format);
- if (oldOpacity != isOpaque(s)) {
+ // Once we have hit this state, the shadow queue may no longer
+ // correctly reflect the incoming BufferQueue's contents, so even if
+ // updateTexImage starts working, the only safe course of action is
+ // to continue to ignore updates.
+ mUpdateTexImageFailed = true;
+
+ return outDirtyRegion;
+ }
+
+ if (queuedBuffer) {
+ // Autolock scope
+ auto currentFrameNumber = mSurfaceFlingerConsumer->getFrameNumber();
+
+ Mutex::Autolock lock(mQueueItemLock);
+
+ // Remove any stale buffers that have been dropped during
+ // updateTexImage
+ while (mQueueItems[0].mFrameNumber != currentFrameNumber) {
+ mQueueItems.removeAt(0);
+ android_atomic_dec(&mQueuedFrames);
+ }
+
+ mQueueItems.removeAt(0);
+ }
+
+
+ // Decrement the queued-frames count. Signal another event if we
+ // have more frames pending.
+ if ((queuedBuffer && android_atomic_dec(&mQueuedFrames) > 1)
+ || mAutoRefresh) {
+ mFlinger->signalLayerUpdate();
+ }
+
+ if (updateResult != NO_ERROR) {
+ // something happened!
+ recomputeVisibleRegions = true;
+ return outDirtyRegion;
+ }
+
+ // update the active buffer
+ mActiveBuffer = mSurfaceFlingerConsumer->getCurrentBuffer();
+ if (mActiveBuffer == NULL) {
+ // this can only happen if the very first buffer was rejected.
+ return outDirtyRegion;
+ }
+
+ mRefreshPending = true;
+ mFrameLatencyNeeded = true;
+ if (oldActiveBuffer == NULL) {
+ // the first time we receive a buffer, we need to trigger a
+ // geometry invalidation.
+ recomputeVisibleRegions = true;
+ }
+
+ Rect crop(mSurfaceFlingerConsumer->getCurrentCrop());
+ const uint32_t transform(mSurfaceFlingerConsumer->getCurrentTransform());
+ const uint32_t scalingMode(mSurfaceFlingerConsumer->getCurrentScalingMode());
+ if ((crop != mCurrentCrop) ||
+ (transform != mCurrentTransform) ||
+ (scalingMode != mCurrentScalingMode))
+ {
+ mCurrentCrop = crop;
+ mCurrentTransform = transform;
+ mCurrentScalingMode = scalingMode;
+ recomputeVisibleRegions = true;
+ }
+
+ if (oldActiveBuffer != NULL) {
+ uint32_t bufWidth = mActiveBuffer->getWidth();
+ uint32_t bufHeight = mActiveBuffer->getHeight();
+ if (bufWidth != uint32_t(oldActiveBuffer->width) ||
+ bufHeight != uint32_t(oldActiveBuffer->height)) {
recomputeVisibleRegions = true;
}
+ }
- mCurrentFrameNumber = mSurfaceFlingerConsumer->getFrameNumber();
+ mCurrentOpacity = getOpacityForFormat(mActiveBuffer->format);
+ if (oldOpacity != isOpaque(s)) {
+ recomputeVisibleRegions = true;
+ }
- // Remove any sync points corresponding to the buffer which was just
- // latched
- {
- Mutex::Autolock lock(mLocalSyncPointMutex);
- auto point = mLocalSyncPoints.begin();
- while (point != mLocalSyncPoints.end()) {
- if (!(*point)->frameIsAvailable() ||
- !(*point)->transactionIsApplied()) {
- // This sync point must have been added since we started
- // latching. Don't drop it yet.
- ++point;
- continue;
- }
+ mCurrentFrameNumber = mSurfaceFlingerConsumer->getFrameNumber();
- if ((*point)->getFrameNumber() <= mCurrentFrameNumber) {
- point = mLocalSyncPoints.erase(point);
- } else {
- ++point;
- }
+ // Remove any sync points corresponding to the buffer which was just
+ // latched
+ {
+ Mutex::Autolock lock(mLocalSyncPointMutex);
+ auto point = mLocalSyncPoints.begin();
+ while (point != mLocalSyncPoints.end()) {
+ if (!(*point)->frameIsAvailable() ||
+ !(*point)->transactionIsApplied()) {
+ // This sync point must have been added since we started
+ // latching. Don't drop it yet.
+ ++point;
+ continue;
+ }
+
+ if ((*point)->getFrameNumber() <= mCurrentFrameNumber) {
+ point = mLocalSyncPoints.erase(point);
+ } else {
+ ++point;
}
}
-
- // FIXME: postedRegion should be dirty & bounds
- Region dirtyRegion(Rect(s.active.w, s.active.h));
-
- // transform the dirty region to window-manager space
- outDirtyRegion = (s.active.transform.transform(dirtyRegion));
}
+
+ // FIXME: postedRegion should be dirty & bounds
+ Region dirtyRegion(Rect(s.active.w, s.active.h));
+
+ // transform the dirty region to window-manager space
+ outDirtyRegion = (s.active.transform.transform(dirtyRegion));
+
return outDirtyRegion;
}
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index a0e040b..e5b57f5 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -1836,9 +1836,12 @@
void SurfaceFlinger::commitTransaction()
{
- if (!mLayersPendingRemoval.isEmpty()) {
+ sp<const DisplayDevice> hw = getDefaultDisplayDevice();
+
+ if (!mLayersPendingRemoval.isEmpty() && hw->isDisplayOn()) {
// Notify removed layers now that they can't be drawn from
for (size_t i = 0; i < mLayersPendingRemoval.size(); i++) {
+ mCurrentState.layersSortedByZ.remove(mLayersPendingRemoval[i]);
recordBufferingStats(mLayersPendingRemoval[i]->getName().string(),
mLayersPendingRemoval[i]->getOccupancyHistory(true));
mLayersPendingRemoval[i]->onRemoved();
@@ -2285,14 +2288,10 @@
return NO_ERROR;
}
- ssize_t index = mCurrentState.layersSortedByZ.remove(layer);
- if (index >= 0) {
- mLayersPendingRemoval.push(layer);
- mLayersRemoved = true;
- setTransactionFlags(eTransactionNeeded);
- return NO_ERROR;
- }
- return status_t(index);
+ mLayersPendingRemoval.push(layer);
+ mLayersRemoved = true;
+ setTransactionFlags(eTransactionNeeded);
+ return NO_ERROR;
}
uint32_t SurfaceFlinger::peekTransactionFlags(uint32_t /* flags */) {
diff --git a/services/surfaceflinger/SurfaceFlingerConsumer.cpp b/services/surfaceflinger/SurfaceFlingerConsumer.cpp
index e0e4c61..6f2520b 100644
--- a/services/surfaceflinger/SurfaceFlingerConsumer.cpp
+++ b/services/surfaceflinger/SurfaceFlingerConsumer.cpp
@@ -70,6 +70,14 @@
return err;
}
+ if (autoRefresh) {
+ *autoRefresh = item.mAutoRefresh;
+ }
+
+ if (queuedBuffer) {
+ *queuedBuffer = item.mQueuedBuffer;
+ }
+
// We call the rejecter here, in case the caller has a reason to
// not accept this buffer. This is used by SurfaceFlinger to
// reject buffers which have the wrong size
@@ -79,14 +87,6 @@
return BUFFER_REJECTED;
}
- if (autoRefresh) {
- *autoRefresh = item.mAutoRefresh;
- }
-
- if (queuedBuffer) {
- *queuedBuffer = item.mQueuedBuffer;
- }
-
// Release the previous buffer.
#ifdef USE_HWC2
err = updateAndReleaseLocked(item, &mPendingRelease);
diff --git a/services/surfaceflinger/tests/Android.mk b/services/surfaceflinger/tests/Android.mk
index e5dffe5..4f1a8e6 100644
--- a/services/surfaceflinger/tests/Android.mk
+++ b/services/surfaceflinger/tests/Android.mk
@@ -3,8 +3,6 @@
include $(CLEAR_VARS)
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-LOCAL_CFLAGS := -std=c++14
-
LOCAL_MODULE := SurfaceFlinger_test
LOCAL_MODULE_TAGS := tests