Merge "Allow VirtualDisplay's to use hardware composer when in VR mode even if physical composer does not support them."
diff --git a/.clang-format b/.clang-format
new file mode 100644
index 0000000..03af56d
--- /dev/null
+++ b/.clang-format
@@ -0,0 +1,13 @@
+BasedOnStyle: Google
+
+AccessModifierOffset: -4
+AlignOperands: false
+AllowShortFunctionsOnASingleLine: Inline
+AlwaysBreakBeforeMultilineStrings: false
+ColumnLimit: 100
+CommentPragmas: NOLINT:.*
+ConstructorInitializerIndentWidth: 6
+ContinuationIndentWidth: 8
+IndentWidth: 4
+PenaltyBreakBeforeFirstCallParameter: 100000
+SpacesBeforeTrailingComments: 1
diff --git a/cmds/atrace/Android.bp b/cmds/atrace/Android.bp
index 69ed416..c89e3b1 100644
--- a/cmds/atrace/Android.bp
+++ b/cmds/atrace/Android.bp
@@ -11,7 +11,6 @@
"libhidlbase",
"libhidltransport",
"liblog",
- "libcutils",
"libutils",
"libz",
"libbase",
diff --git a/cmds/atrace/atrace.cpp b/cmds/atrace/atrace.cpp
index 05e1615..2f33fc9 100644
--- a/cmds/atrace/atrace.cpp
+++ b/cmds/atrace/atrace.cpp
@@ -39,18 +39,19 @@
#include <android/hidl/manager/1.0/IServiceManager.h>
#include <hidl/ServiceManagement.h>
-#include <cutils/properties.h>
#include <utils/String8.h>
#include <utils/Timers.h>
#include <utils/Tokenizer.h>
#include <utils/Trace.h>
#include <android-base/file.h>
+#include <android-base/macros.h>
+#include <android-base/properties.h>
+#include <android-base/stringprintf.h>
using namespace android;
using std::string;
-#define NELEM(x) ((int) (sizeof(x) / sizeof((x)[0])))
#define MAX_SYS_FILES 10
#define MAX_PACKAGES 16
@@ -204,7 +205,7 @@
/* Global state */
static bool g_traceAborted = false;
-static bool g_categoryEnables[NELEM(k_categories)] = {};
+static bool g_categoryEnables[arraysize(k_categories)] = {};
static std::string g_traceFolder;
/* Sys file paths */
@@ -356,9 +357,7 @@
static bool isCategorySupported(const TracingCategory& category)
{
if (strcmp(category.name, k_coreServiceCategory) == 0) {
- char value[PROPERTY_VALUE_MAX];
- property_get(k_coreServicesProp, value, "");
- return strlen(value) != 0;
+ return !android::base::GetProperty(k_coreServicesProp, "").empty();
}
bool ok = category.tags != 0;
@@ -569,9 +568,8 @@
// processes to pick up the new value.
static bool setTagsProperty(uint64_t tags)
{
- char buf[PROPERTY_VALUE_MAX];
- snprintf(buf, sizeof(buf), "%#" PRIx64, tags);
- if (property_set(k_traceTagsProperty, buf) < 0) {
+ std::string value = android::base::StringPrintf("%#" PRIx64, tags);
+ if (!android::base::SetProperty(k_traceTagsProperty, value)) {
fprintf(stderr, "error setting trace tags system property\n");
return false;
}
@@ -580,14 +578,13 @@
static void clearAppProperties()
{
- char buf[PROPERTY_KEY_MAX];
for (int i = 0; i < MAX_PACKAGES; i++) {
- snprintf(buf, sizeof(buf), k_traceAppsPropertyTemplate, i);
- if (property_set(buf, "") < 0) {
- fprintf(stderr, "failed to clear system property: %s\n", buf);
+ std::string key = android::base::StringPrintf(k_traceAppsPropertyTemplate, i);
+ if (!android::base::SetProperty(key, "")) {
+ fprintf(stderr, "failed to clear system property: %s\n", key.c_str());
}
}
- if (property_set(k_traceAppsNumberProperty, "") < 0) {
+ if (!android::base::SetProperty(k_traceAppsNumberProperty, "")) {
fprintf(stderr, "failed to clear system property: %s",
k_traceAppsNumberProperty);
}
@@ -597,7 +594,6 @@
// application-level tracing.
static bool setAppCmdlineProperty(char* cmdline)
{
- char buf[PROPERTY_KEY_MAX];
int i = 0;
char* start = cmdline;
while (start != NULL) {
@@ -611,9 +607,9 @@
*end = '\0';
end++;
}
- snprintf(buf, sizeof(buf), k_traceAppsPropertyTemplate, i);
- if (property_set(buf, start) < 0) {
- fprintf(stderr, "error setting trace app %d property to %s\n", i, buf);
+ std::string key = android::base::StringPrintf(k_traceAppsPropertyTemplate, i);
+ if (!android::base::SetProperty(key, start)) {
+ fprintf(stderr, "error setting trace app %d property to %s\n", i, key.c_str());
clearAppProperties();
return false;
}
@@ -621,9 +617,9 @@
i++;
}
- snprintf(buf, sizeof(buf), "%d", i);
- if (property_set(k_traceAppsNumberProperty, buf) < 0) {
- fprintf(stderr, "error setting trace app number property to %s\n", buf);
+ std::string value = android::base::StringPrintf("%d", i);
+ if (!android::base::SetProperty(k_traceAppsNumberProperty, value)) {
+ fprintf(stderr, "error setting trace app number property to %s\n", value.c_str());
clearAppProperties();
return false;
}
@@ -633,7 +629,7 @@
// Disable all /sys/ enable files.
static bool disableKernelTraceEvents() {
bool ok = true;
- for (int i = 0; i < NELEM(k_categories); i++) {
+ for (size_t i = 0; i < arraysize(k_categories); i++) {
const TracingCategory &c = k_categories[i];
for (int j = 0; j < MAX_SYS_FILES; j++) {
const char* path = c.sysfiles[j].path;
@@ -721,7 +717,7 @@
static bool setCategoryEnable(const char* name, bool enable)
{
- for (int i = 0; i < NELEM(k_categories); i++) {
+ for (size_t i = 0; i < arraysize(k_categories); i++) {
const TracingCategory& c = k_categories[i];
if (strcmp(name, c.name) == 0) {
if (isCategorySupported(c)) {
@@ -781,7 +777,7 @@
// Set up the tags property.
uint64_t tags = 0;
- for (int i = 0; i < NELEM(k_categories); i++) {
+ for (size_t i = 0; i < arraysize(k_categories); i++) {
if (g_categoryEnables[i]) {
const TracingCategory &c = k_categories[i];
tags |= c.tags;
@@ -790,7 +786,7 @@
ok &= setTagsProperty(tags);
bool coreServicesTagEnabled = false;
- for (int i = 0; i < NELEM(k_categories); i++) {
+ for (size_t i = 0; i < arraysize(k_categories); i++) {
if (strcmp(k_categories[i].name, k_coreServiceCategory) == 0) {
coreServicesTagEnabled = g_categoryEnables[i];
}
@@ -798,12 +794,10 @@
std::string packageList(g_debugAppCmdLine);
if (coreServicesTagEnabled) {
- char value[PROPERTY_VALUE_MAX];
- property_get(k_coreServicesProp, value, "");
if (!packageList.empty()) {
packageList += ",";
}
- packageList += value;
+ packageList += android::base::GetProperty(k_coreServicesProp, "");
}
ok &= setAppCmdlineProperty(&packageList[0]);
ok &= pokeBinderServices();
@@ -814,7 +808,7 @@
ok &= disableKernelTraceEvents();
// Enable all the sysfs enables that are in an enabled category.
- for (int i = 0; i < NELEM(k_categories); i++) {
+ for (size_t i = 0; i < arraysize(k_categories); i++) {
if (g_categoryEnables[i]) {
const TracingCategory &c = k_categories[i];
for (int j = 0; j < MAX_SYS_FILES; j++) {
@@ -1012,7 +1006,7 @@
static void listSupportedCategories()
{
- for (int i = 0; i < NELEM(k_categories); i++) {
+ for (size_t i = 0; i < arraysize(k_categories); i++) {
const TracingCategory& c = k_categories[i];
if (isCategorySupported(c)) {
printf(" %10s - %s\n", c.name, c.longname);
diff --git a/cmds/bugreportz/Android.mk b/cmds/bugreportz/Android.mk
index 880bc75..10dda56 100644
--- a/cmds/bugreportz/Android.mk
+++ b/cmds/bugreportz/Android.mk
@@ -25,6 +25,7 @@
include $(CLEAR_VARS)
LOCAL_MODULE := bugreportz_test
+LOCAL_COMPATIBILITY_SUITE := device-tests
LOCAL_MODULE_TAGS := tests
LOCAL_CFLAGS := -Werror -Wall
diff --git a/cmds/bugreportz/AndroidTest.xml b/cmds/bugreportz/AndroidTest.xml
new file mode 100644
index 0000000..38b6276
--- /dev/null
+++ b/cmds/bugreportz/AndroidTest.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration description="Config for bugreportz_test">
+ <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+ <option name="cleanup" value="true" />
+ <option name="push" value="bugreportz_test->/data/local/tmp/bugreportz_test" />
+ </target_preparer>
+ <option name="test-suite-tag" value="apct" />
+ <test class="com.android.tradefed.testtype.GTest" >
+ <option name="native-test-device-path" value="/data/local/tmp" />
+ <option name="module-name" value="bugreportz_test" />
+ </test>
+</configuration>
diff --git a/cmds/dumpstate/Android.mk b/cmds/dumpstate/Android.mk
index a407ea2..669e8d2 100644
--- a/cmds/dumpstate/Android.mk
+++ b/cmds/dumpstate/Android.mk
@@ -138,7 +138,7 @@
include $(CLEAR_VARS)
LOCAL_MODULE := dumpstate_test_fixture
-
+LOCAL_COMPATIBILITY_SUITE := device-tests
LOCAL_MODULE_TAGS := tests
LOCAL_CFLAGS := $(COMMON_LOCAL_CFLAGS)
diff --git a/cmds/dumpstate/AndroidTest.xml b/cmds/dumpstate/AndroidTest.xml
new file mode 100644
index 0000000..f189489
--- /dev/null
+++ b/cmds/dumpstate/AndroidTest.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration description="Config for dumpstate_test_fixture">
+ <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+ <option name="cleanup" value="true" />
+ <option name="push" value="dumpstate_test_fixture->/data/local/tmp/dumpstate_test_fixture" />
+ </target_preparer>
+ <option name="test-suite-tag" value="apct" />
+ <test class="com.android.tradefed.testtype.GTest" >
+ <option name="native-test-device-path" value="/data/local/tmp" />
+ <option name="module-name" value="dumpstate_test_fixture" />
+ </test>
+</configuration>
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index f898b90..cba8f36 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -112,6 +112,7 @@
// Must be hardcoded because dumpstate HAL implementation need SELinux access to it
static const std::string kDumpstateBoardPath = "/bugreports/dumpstate_board.txt";
+static const std::string kLsHalDebugPath = "/bugreports/dumpstate_lshal.txt";
static constexpr char PROPERTY_EXTRA_OPTIONS[] = "dumpstate.options";
static constexpr char PROPERTY_LAST_ID[] = "dumpstate.last_id";
@@ -962,7 +963,19 @@
{"ps", "-A", "-T", "-Z", "-O", "pri,nice,rtprio,sched,pcy"});
RunCommand("LIBRANK", {"librank"}, CommandOptions::AS_ROOT);
- RunCommand("HARDWARE HALS", {"lshal"}, CommandOptions::AS_ROOT);
+ if (ds.IsZipping()) {
+ RunCommand(
+ "HARDWARE HALS",
+ {"lshal", std::string("--debug=") + kLsHalDebugPath},
+ CommandOptions::AS_ROOT);
+
+ ds.AddZipEntry("lshal-debug.txt", kLsHalDebugPath);
+
+ unlink(kLsHalDebugPath.c_str());
+ } else {
+ RunCommand(
+ "HARDWARE HALS", {"lshal", "--debug"}, CommandOptions::AS_ROOT);
+ }
RunCommand("PRINTENV", {"printenv"});
RunCommand("NETSTAT", {"netstat", "-nW"});
@@ -980,8 +993,13 @@
for_each_tid(show_wchan, "BLOCKED PROCESS WAIT-CHANNELS");
for_each_pid(show_showtime, "PROCESS TIMES (pid cmd user system iowait+percentage)");
- /* Dump Bluetooth HCI logs */
- ds.AddDir("/data/misc/bluetooth/logs", true);
+ if (true) {
+ // TODO: temporary disabled because /data/misc/bluetooth/logs/btsnoop_hci.log can be huge
+ MYLOGD("Skipping /data/misc/bluetooth/logs");
+ } else {
+ /* Dump Bluetooth HCI logs */
+ ds.AddDir("/data/misc/bluetooth/logs", true);
+ }
if (!ds.do_early_screenshot_) {
MYLOGI("taking late screenshot\n");
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index ca4be0a..381e90c 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -899,30 +899,7 @@
ATRACE_END();
} else {
- ATRACE_BEGIN("start");
- cache_t* cache = start_cache_collection();
- ATRACE_END();
-
- ATRACE_BEGIN("add");
- for (auto user : get_known_users(uuid_)) {
- add_cache_files(cache, create_data_user_ce_path(uuid_, user));
- add_cache_files(cache, create_data_user_de_path(uuid_, user));
- add_cache_files(cache,
- StringPrintf("%s/Android/data", create_data_media_path(uuid_, user).c_str()));
- }
- // Add files from /data/preloads/file_cache
- if (uuid == nullptr) {
- add_preloads_file_cache(cache, uuid_);
- }
- ATRACE_END();
-
- ATRACE_BEGIN("clear");
- clear_cache_files(data_path, cache, freeStorageSize);
- ATRACE_END();
-
- ATRACE_BEGIN("finish");
- finish_cache_collection(cache);
- ATRACE_END();
+ return error("Legacy cache logic no longer supported");
}
free = data_disk_free(data_path);
diff --git a/cmds/installd/dexopt.h b/cmds/installd/dexopt.h
index dbf3fae..f144be8 100644
--- a/cmds/installd/dexopt.h
+++ b/cmds/installd/dexopt.h
@@ -30,7 +30,6 @@
static constexpr int DEX2OAT_FOR_BOOT_IMAGE = 2;
static constexpr int DEX2OAT_FOR_FILTER = 3;
static constexpr int DEX2OAT_FOR_RELOCATION = 4;
-static constexpr int PATCHOAT_FOR_RELOCATION = 5;
// Clear the reference profile for the primary apk of the given package.
bool clear_primary_reference_profile(const std::string& pkgname);
diff --git a/cmds/installd/utils.cpp b/cmds/installd/utils.cpp
index 03ee23f..fbe6edf 100644
--- a/cmds/installd/utils.cpp
+++ b/cmds/installd/utils.cpp
@@ -38,7 +38,6 @@
#define LOG_TAG "installd"
#endif
-#define CACHE_NOISY(x) //x
#define DEBUG_XATTRS 0
using android::base::StringPrintf;
@@ -641,253 +640,6 @@
}
}
-cache_t* start_cache_collection()
-{
- cache_t* cache = (cache_t*)calloc(1, sizeof(cache_t));
- return cache;
-}
-
-#define CACHE_BLOCK_SIZE (512*1024)
-
-static void* _cache_malloc(cache_t* cache, size_t len)
-{
- len = (len+3)&~3;
- if (len > (CACHE_BLOCK_SIZE/2)) {
- // It doesn't make sense to try to put this allocation into one
- // of our blocks, because it is so big. Instead, make a new dedicated
- // block for it.
- int8_t* res = (int8_t*)malloc(len+sizeof(void*));
- if (res == NULL) {
- return NULL;
- }
- CACHE_NOISY(ALOGI("Allocated large cache mem block: %p size %zu", res, len));
- // Link it into our list of blocks, not disrupting the current one.
- if (cache->memBlocks == NULL) {
- *(void**)res = NULL;
- cache->memBlocks = res;
- } else {
- *(void**)res = *(void**)cache->memBlocks;
- *(void**)cache->memBlocks = res;
- }
- return res + sizeof(void*);
- }
- int8_t* res = cache->curMemBlockAvail;
- int8_t* nextPos = res + len;
- if (cache->memBlocks == NULL || nextPos > cache->curMemBlockEnd) {
- int8_t* newBlock = (int8_t*) malloc(CACHE_BLOCK_SIZE);
- if (newBlock == NULL) {
- return NULL;
- }
- CACHE_NOISY(ALOGI("Allocated new cache mem block: %p", newBlock));
- *(void**)newBlock = cache->memBlocks;
- cache->memBlocks = newBlock;
- res = cache->curMemBlockAvail = newBlock + sizeof(void*);
- cache->curMemBlockEnd = newBlock + CACHE_BLOCK_SIZE;
- nextPos = res + len;
- }
- CACHE_NOISY(ALOGI("cache_malloc: ret %p size %zu, block=%p, nextPos=%p",
- res, len, cache->memBlocks, nextPos));
- cache->curMemBlockAvail = nextPos;
- return res;
-}
-
-static void* _cache_realloc(cache_t* cache, void* cur, size_t origLen, size_t len)
-{
- // This isn't really a realloc, but it is good enough for our purposes here.
- void* alloc = _cache_malloc(cache, len);
- if (alloc != NULL && cur != NULL) {
- memcpy(alloc, cur, origLen < len ? origLen : len);
- }
- return alloc;
-}
-
-static void _inc_num_cache_collected(cache_t* cache)
-{
- cache->numCollected++;
- if ((cache->numCollected%20000) == 0) {
- ALOGI("Collected cache so far: %zd directories, %zd files",
- cache->numDirs, cache->numFiles);
- }
-}
-
-static cache_dir_t* _add_cache_dir_t(cache_t* cache, cache_dir_t* parent, const char *name)
-{
- size_t nameLen = strlen(name);
- cache_dir_t* dir = (cache_dir_t*)_cache_malloc(cache, sizeof(cache_dir_t)+nameLen+1);
- if (dir != NULL) {
- dir->parent = parent;
- dir->childCount = 0;
- dir->hiddenCount = 0;
- dir->deleted = 0;
- strcpy(dir->name, name);
- if (cache->numDirs >= cache->availDirs) {
- size_t newAvail = cache->availDirs < 1000 ? 1000 : cache->availDirs*2;
- cache_dir_t** newDirs = (cache_dir_t**)_cache_realloc(cache, cache->dirs,
- cache->availDirs*sizeof(cache_dir_t*), newAvail*sizeof(cache_dir_t*));
- if (newDirs == NULL) {
- ALOGE("Failure growing cache dirs array for %s\n", name);
- return NULL;
- }
- cache->availDirs = newAvail;
- cache->dirs = newDirs;
- }
- cache->dirs[cache->numDirs] = dir;
- cache->numDirs++;
- if (parent != NULL) {
- parent->childCount++;
- }
- _inc_num_cache_collected(cache);
- } else {
- ALOGE("Failure allocating cache_dir_t for %s\n", name);
- }
- return dir;
-}
-
-static cache_file_t* _add_cache_file_t(cache_t* cache, cache_dir_t* dir, time_t modTime,
- const char *name)
-{
- size_t nameLen = strlen(name);
- cache_file_t* file = (cache_file_t*)_cache_malloc(cache, sizeof(cache_file_t)+nameLen+1);
- if (file != NULL) {
- file->dir = dir;
- file->modTime = modTime;
- strcpy(file->name, name);
- if (cache->numFiles >= cache->availFiles) {
- size_t newAvail = cache->availFiles < 1000 ? 1000 : cache->availFiles*2;
- cache_file_t** newFiles = (cache_file_t**)_cache_realloc(cache, cache->files,
- cache->availFiles*sizeof(cache_file_t*), newAvail*sizeof(cache_file_t*));
- if (newFiles == NULL) {
- ALOGE("Failure growing cache file array for %s\n", name);
- return NULL;
- }
- cache->availFiles = newAvail;
- cache->files = newFiles;
- }
- CACHE_NOISY(ALOGI("Setting file %p at position %zd in array %p", file,
- cache->numFiles, cache->files));
- cache->files[cache->numFiles] = file;
- cache->numFiles++;
- dir->childCount++;
- _inc_num_cache_collected(cache);
- } else {
- ALOGE("Failure allocating cache_file_t for %s\n", name);
- }
- return file;
-}
-
-static int _add_cache_files(cache_t *cache, cache_dir_t *parentDir, const char *dirName,
- DIR* dir, char *pathBase, char *pathPos, size_t pathAvailLen)
-{
- struct dirent *de;
- cache_dir_t* cacheDir = NULL;
- int dfd;
-
- CACHE_NOISY(ALOGI("_add_cache_files: parent=%p dirName=%s dir=%p pathBase=%s",
- parentDir, dirName, dir, pathBase));
-
- dfd = dirfd(dir);
-
- if (dfd < 0) return 0;
-
- // Sub-directories always get added to the data structure, so if they
- // are empty we will know about them to delete them later.
- cacheDir = _add_cache_dir_t(cache, parentDir, dirName);
-
- while ((de = readdir(dir))) {
- const char *name = de->d_name;
-
- if (de->d_type == DT_DIR) {
- int subfd;
- DIR *subdir;
-
- /* always skip "." and ".." */
- if (name[0] == '.') {
- if (name[1] == 0) continue;
- if ((name[1] == '.') && (name[2] == 0)) continue;
- }
-
- subfd = openat(dfd, name, O_RDONLY | O_DIRECTORY | O_NOFOLLOW | O_CLOEXEC);
- if (subfd < 0) {
- ALOGE("Couldn't openat %s: %s\n", name, strerror(errno));
- continue;
- }
- subdir = fdopendir(subfd);
- if (subdir == NULL) {
- ALOGE("Couldn't fdopendir %s: %s\n", name, strerror(errno));
- close(subfd);
- continue;
- }
- if (cacheDir == NULL) {
- cacheDir = _add_cache_dir_t(cache, parentDir, dirName);
- }
- if (cacheDir != NULL) {
- // Update pathBase for the new path... this may change dirName
- // if that is also pointing to the path, but we are done with it
- // now.
- size_t finallen = snprintf(pathPos, pathAvailLen, "/%s", name);
- CACHE_NOISY(ALOGI("Collecting dir %s\n", pathBase));
- if (finallen < pathAvailLen) {
- _add_cache_files(cache, cacheDir, name, subdir, pathBase,
- pathPos+finallen, pathAvailLen-finallen);
- } else {
- // Whoops, the final path is too long! We'll just delete
- // this directory.
- ALOGW("Cache dir %s truncated in path %s; deleting dir\n",
- name, pathBase);
- _delete_dir_contents(subdir, NULL);
- if (unlinkat(dfd, name, AT_REMOVEDIR) < 0) {
- ALOGE("Couldn't unlinkat %s: %s\n", name, strerror(errno));
- }
- }
- }
- closedir(subdir);
- } else if (de->d_type == DT_REG) {
- // Skip files that start with '.'; they will be deleted if
- // their entire directory is deleted. This allows for metadata
- // like ".nomedia" to remain in the directory until the entire
- // directory is deleted.
- if (cacheDir == NULL) {
- cacheDir = _add_cache_dir_t(cache, parentDir, dirName);
- }
- if (name[0] == '.') {
- cacheDir->hiddenCount++;
- continue;
- }
- if (cacheDir != NULL) {
- // Build final full path for file... this may change dirName
- // if that is also pointing to the path, but we are done with it
- // now.
- size_t finallen = snprintf(pathPos, pathAvailLen, "/%s", name);
- CACHE_NOISY(ALOGI("Collecting file %s\n", pathBase));
- if (finallen < pathAvailLen) {
- struct stat s;
- if (stat(pathBase, &s) >= 0) {
- _add_cache_file_t(cache, cacheDir, s.st_mtime, name);
- } else {
- ALOGW("Unable to stat cache file %s; deleting\n", pathBase);
- if (unlink(pathBase) < 0) {
- ALOGE("Couldn't unlink %s: %s\n", pathBase, strerror(errno));
- }
- }
- } else {
- // Whoops, the final path is too long! We'll just delete
- // this file.
- ALOGW("Cache file %s truncated in path %s; deleting\n",
- name, pathBase);
- if (unlinkat(dfd, name, 0) < 0) {
- *pathPos = 0;
- ALOGE("Couldn't unlinkat %s in %s: %s\n", name, pathBase,
- strerror(errno));
- }
- }
- }
- } else {
- cacheDir->hiddenCount++;
- }
- }
- return 0;
-}
-
int get_path_inode(const std::string& path, ino_t *inode) {
struct stat buf;
memset(&buf, 0, sizeof(buf));
@@ -981,187 +733,6 @@
}
}
-void add_cache_files(cache_t* cache, const std::string& data_path) {
- DIR *d;
- struct dirent *de;
- char dirname[PATH_MAX];
-
- const char* basepath = data_path.c_str();
- CACHE_NOISY(ALOGI("add_cache_files: basepath=%s\n", basepath));
-
- d = opendir(basepath);
- if (d == NULL) {
- return;
- }
-
- while ((de = readdir(d))) {
- if (de->d_type == DT_DIR) {
- DIR* subdir;
- const char *name = de->d_name;
-
- /* always skip "." and ".." */
- if (name[0] == '.') {
- if (name[1] == 0) continue;
- if ((name[1] == '.') && (name[2] == 0)) continue;
- }
-
- auto parent = StringPrintf("%s/%s", basepath, name);
- auto resolved = read_path_inode(parent, "cache", kXattrInodeCache);
- strcpy(dirname, resolved.c_str());
- CACHE_NOISY(ALOGI("Adding cache files from dir: %s\n", dirname));
-
- subdir = opendir(dirname);
- if (subdir != NULL) {
- size_t dirnameLen = strlen(dirname);
- _add_cache_files(cache, NULL, dirname, subdir, dirname, dirname+dirnameLen,
- PATH_MAX - dirnameLen);
- closedir(subdir);
- }
- }
- }
-
- closedir(d);
-}
-
-void add_preloads_file_cache(cache_t* cache, const char* volume_uuid) {
- char dirname[PATH_MAX];
- DIR* subdir;
- auto cache_path = StringPrintf("%s/preloads/file_cache", create_data_path(volume_uuid).c_str());
- strcpy(dirname, cache_path.c_str());
- CACHE_NOISY(ALOGI("add_preloads_file_cache: dirname=%s\n", dirname));
- subdir = opendir(dirname);
- if (subdir != NULL) {
- size_t dirnameLen = strlen(dirname);
- _add_cache_files(cache, NULL, dirname, subdir, dirname, dirname + dirnameLen,
- PATH_MAX - dirnameLen);
- closedir(subdir);
- }
-}
-
-static char *create_dir_path(char path[PATH_MAX], cache_dir_t* dir)
-{
- char *pos = path;
- if (dir->parent != NULL) {
- pos = create_dir_path(path, dir->parent);
- }
- // Note that we don't need to worry about going beyond the buffer,
- // since when we were constructing the cache entries our maximum
- // buffer size for full paths was PATH_MAX.
- strcpy(pos, dir->name);
- pos += strlen(pos);
- *pos = '/';
- pos++;
- *pos = 0;
- return pos;
-}
-
-static void delete_cache_dir(char path[PATH_MAX], cache_dir_t* dir)
-{
- if (dir->parent != NULL) {
- create_dir_path(path, dir);
- ALOGI("DEL DIR %s\n", path);
- if (dir->hiddenCount <= 0) {
- if (rmdir(path)) {
- ALOGE("Couldn't rmdir %s: %s\n", path, strerror(errno));
- return;
- }
- } else {
- // The directory contains hidden files so we need to delete
- // them along with the directory itself.
- if (delete_dir_contents(path, 1, NULL)) {
- return;
- }
- }
- dir->parent->childCount--;
- dir->deleted = 1;
- if (dir->parent->childCount <= 0) {
- delete_cache_dir(path, dir->parent);
- }
- } else if (dir->hiddenCount > 0) {
- // This is a root directory, but it has hidden files. Get rid of
- // all of those files, but not the directory itself.
- create_dir_path(path, dir);
- ALOGI("DEL CONTENTS %s\n", path);
- delete_dir_contents(path, 0, NULL);
- }
-}
-
-static int cache_modtime_sort(const void *lhsP, const void *rhsP)
-{
- const cache_file_t *lhs = *(const cache_file_t**)lhsP;
- const cache_file_t *rhs = *(const cache_file_t**)rhsP;
- return lhs->modTime < rhs->modTime ? -1 : (lhs->modTime > rhs->modTime ? 1 : 0);
-}
-
-void clear_cache_files(const std::string& data_path, cache_t* cache, int64_t free_size)
-{
- size_t i;
- int skip = 0;
- char path[PATH_MAX];
-
- ALOGI("Collected cache files: %zd directories, %zd files",
- cache->numDirs, cache->numFiles);
-
- CACHE_NOISY(ALOGI("Sorting files..."));
- qsort(cache->files, cache->numFiles, sizeof(cache_file_t*),
- cache_modtime_sort);
-
- CACHE_NOISY(ALOGI("Cleaning empty directories..."));
- for (i=cache->numDirs; i>0; i--) {
- cache_dir_t* dir = cache->dirs[i-1];
- if (dir->childCount <= 0 && !dir->deleted) {
- delete_cache_dir(path, dir);
- }
- }
-
- CACHE_NOISY(ALOGI("Trimming files..."));
- for (i=0; i<cache->numFiles; i++) {
- skip++;
- if (skip > 10) {
- if (data_disk_free(data_path) > free_size) {
- return;
- }
- skip = 0;
- }
- cache_file_t* file = cache->files[i];
- strcpy(create_dir_path(path, file->dir), file->name);
- ALOGI("DEL (mod %d) %s\n", (int)file->modTime, path);
- if (unlink(path) < 0) {
- ALOGE("Couldn't unlink %s: %s\n", path, strerror(errno));
- }
- file->dir->childCount--;
- if (file->dir->childCount <= 0) {
- delete_cache_dir(path, file->dir);
- }
- }
-}
-
-void finish_cache_collection(cache_t* cache)
-{
- CACHE_NOISY(size_t i;)
-
- CACHE_NOISY(ALOGI("clear_cache_files: %zu dirs, %zu files\n", cache->numDirs, cache->numFiles));
- CACHE_NOISY(
- for (i=0; i<cache->numDirs; i++) {
- cache_dir_t* dir = cache->dirs[i];
- ALOGI("dir #%zu: %p %s parent=%p\n", i, dir, dir->name, dir->parent);
- })
- CACHE_NOISY(
- for (i=0; i<cache->numFiles; i++) {
- cache_file_t* file = cache->files[i];
- ALOGI("file #%zu: %p %s time=%d dir=%p\n", i, file, file->name,
- (int)file->modTime, file->dir);
- })
- void* block = cache->memBlocks;
- while (block != NULL) {
- void* nextBlock = *(void**)block;
- CACHE_NOISY(ALOGI("Freeing cache mem block: %p", block));
- free(block);
- block = nextBlock;
- }
- free(cache);
-}
-
/**
* Validate that the path is valid in the context of the provided directory.
* The path is allowed to have at most one subdirectory and no indirections
diff --git a/cmds/installd/utils.h b/cmds/installd/utils.h
index a4eb1f6..7ebfea2 100644
--- a/cmds/installd/utils.h
+++ b/cmds/installd/utils.h
@@ -37,33 +37,6 @@
struct dir_rec_t;
-typedef struct cache_dir_struct {
- struct cache_dir_struct* parent;
- int32_t childCount;
- int32_t hiddenCount;
- int32_t deleted;
- char name[];
-} cache_dir_t;
-
-typedef struct {
- cache_dir_t* dir;
- time_t modTime;
- char name[];
-} cache_file_t;
-
-typedef struct {
- size_t numDirs;
- size_t availDirs;
- cache_dir_t** dirs;
- size_t numFiles;
- size_t availFiles;
- cache_file_t** files;
- size_t numCollected;
- void* memBlocks;
- int8_t* curMemBlockAvail;
- int8_t* curMemBlockEnd;
-} cache_t;
-
constexpr const char* kXattrInodeCache = "user.inode_cache";
constexpr const char* kXattrInodeCodeCache = "user.inode_code_cache";
constexpr const char* kXattrCacheGroup = "user.cache_group";
@@ -139,21 +112,11 @@
int64_t data_disk_free(const std::string& data_path);
-cache_t* start_cache_collection();
-
int get_path_inode(const std::string& path, ino_t *inode);
int write_path_inode(const std::string& parent, const char* name, const char* inode_xattr);
std::string read_path_inode(const std::string& parent, const char* name, const char* inode_xattr);
-void add_cache_files(cache_t* cache, const std::string& data_path);
-
-void add_preloads_file_cache(cache_t* cache, const char* volume_uuid);
-
-void clear_cache_files(const std::string& data_path, cache_t* cache, int64_t free_size);
-
-void finish_cache_collection(cache_t* cache);
-
int validate_system_app_path(const char* path);
bool validate_secondary_dex_path(const std::string& pkgname, const std::string& dex_path,
const char* volume_uuid, int uid, int storage_flag);
diff --git a/cmds/lshal/Android.bp b/cmds/lshal/Android.bp
index 39e0ba3..4740202 100644
--- a/cmds/lshal/Android.bp
+++ b/cmds/lshal/Android.bp
@@ -16,6 +16,7 @@
name: "lshal",
shared_libs: [
"libbase",
+ "libcutils",
"libutils",
"libhidlbase",
"libhidltransport",
@@ -24,6 +25,7 @@
"android.hidl.manager@1.0",
],
srcs: [
- "Lshal.cpp"
+ "Lshal.cpp",
+ "PipeRelay.cpp"
],
}
diff --git a/cmds/lshal/Lshal.cpp b/cmds/lshal/Lshal.cpp
index a5cac15..420ec3c 100644
--- a/cmds/lshal/Lshal.cpp
+++ b/cmds/lshal/Lshal.cpp
@@ -25,13 +25,17 @@
#include <sstream>
#include <regex>
+#include <android-base/logging.h>
#include <android-base/parseint.h>
#include <android/hidl/manager/1.0/IServiceManager.h>
#include <hidl/ServiceManagement.h>
#include <hidl-util/FQName.h>
+#include <private/android_filesystem_config.h>
+#include <sys/stat.h>
#include <vintf/HalManifest.h>
#include <vintf/parse_xml.h>
+#include "PipeRelay.h"
#include "Timeout.h"
using ::android::hardware::hidl_string;
@@ -357,6 +361,52 @@
}
}
+// A unique_ptr type using a custom deleter function.
+template<typename T>
+using deleted_unique_ptr = std::unique_ptr<T, std::function<void(T *)> >;
+
+void Lshal::emitDebugInfo(
+ const sp<IServiceManager> &serviceManager,
+ const std::string &interfaceName,
+ const std::string &instanceName) const {
+ using android::hidl::base::V1_0::IBase;
+
+ hardware::Return<sp<IBase>> retBase =
+ serviceManager->get(interfaceName, instanceName);
+
+ sp<IBase> base;
+ if (!retBase.isOk() || (base = retBase) == nullptr) {
+ // There's a small race, where a service instantiated while collecting
+ // the list of services has by now terminated, so this isn't anything
+ // to be concerned about.
+ return;
+ }
+
+ PipeRelay relay(mOut.buf());
+
+ if (relay.initCheck() != OK) {
+ LOG(ERROR) << "PipeRelay::initCheck() FAILED w/ " << relay.initCheck();
+ return;
+ }
+
+ deleted_unique_ptr<native_handle_t> fdHandle(
+ native_handle_create(1 /* numFds */, 0 /* numInts */),
+ native_handle_delete);
+
+ fdHandle->data[0] = relay.fd();
+
+ hardware::hidl_vec<hardware::hidl_string> options;
+ hardware::Return<void> ret = base->debug(fdHandle.get(), options);
+
+ if (!ret.isOk()) {
+ LOG(ERROR)
+ << interfaceName
+ << "::debug(...) FAILED. (instance "
+ << instanceName
+ << ")";
+ }
+}
+
void Lshal::dumpTable() {
mServicesTable.description =
"All binderized services (registered services through hwservicemanager)";
@@ -374,6 +424,16 @@
mOut << std::left;
printLine("Interface", "Transport", "Arch", "Server", "Server CMD",
"PTR", "Clients", "Clients CMD");
+
+ // We're only interested in dumping debug info for already
+ // instantiated services. There's little value in dumping the
+ // debug info for a service we create on the fly, so we only operate
+ // on the "mServicesTable".
+ sp<IServiceManager> serviceManager;
+ if (mEmitDebugInfo && &table == &mServicesTable) {
+ serviceManager = ::android::hardware::defaultServiceManager();
+ }
+
for (const auto &entry : table) {
printLine(entry.interfaceName,
entry.transport,
@@ -383,6 +443,11 @@
entry.serverObjectAddress == NO_PTR ? "N/A" : toHexString(entry.serverObjectAddress),
join(entry.clientPids, " "),
join(entry.clientCmdlines, ";"));
+
+ if (serviceManager != nullptr) {
+ auto pair = splitFirst(entry.interfaceName, '/');
+ emitDebugInfo(serviceManager, pair.first, pair.second);
+ }
}
mOut << std::endl;
});
@@ -626,6 +691,7 @@
{"address", no_argument, 0, 'a' },
{"clients", no_argument, 0, 'c' },
{"cmdline", no_argument, 0, 'm' },
+ {"debug", optional_argument, 0, 'd' },
// long options without short alternatives
{"sort", required_argument, 0, 's' },
@@ -638,7 +704,7 @@
optind = 1;
for (;;) {
// using getopt_long in case we want to add other options in the future
- c = getopt_long(argc, argv, "hitrpacm", longOptions, &optionIndex);
+ c = getopt_long(argc, argv, "hitrpacmd", longOptions, &optionIndex);
if (c == -1) {
break;
}
@@ -694,6 +760,20 @@
mEnableCmdlines = true;
break;
}
+ case 'd': {
+ mEmitDebugInfo = true;
+
+ if (optarg) {
+ mFileOutput = new std::ofstream{optarg};
+ mOut = mFileOutput;
+ if (!mFileOutput.buf().is_open()) {
+ mErr << "Could not open file '" << optarg << "'." << std::endl;
+ return IO_ERROR;
+ }
+ chown(optarg, AID_SHELL, AID_SHELL);
+ }
+ break;
+ }
case 'h': // falls through
default: // see unrecognized options
usage();
diff --git a/cmds/lshal/Lshal.h b/cmds/lshal/Lshal.h
index c9c6660..a21e86c 100644
--- a/cmds/lshal/Lshal.h
+++ b/cmds/lshal/Lshal.h
@@ -77,6 +77,11 @@
void forEachTable(const std::function<void(Table &)> &f);
void forEachTable(const std::function<void(const Table &)> &f) const;
+ void emitDebugInfo(
+ const sp<hidl::manager::V1_0::IServiceManager> &serviceManager,
+ const std::string &interfaceName,
+ const std::string &instanceName) const;
+
Table mServicesTable{};
Table mPassthroughRefTable{};
Table mImplementationsTable{};
@@ -88,6 +93,10 @@
TableEntrySelect mSelectedColumns = 0;
// If true, cmdlines will be printed instead of pid.
bool mEnableCmdlines = false;
+
+ // If true, calls IBase::debug(...) on each service.
+ bool mEmitDebugInfo = false;
+
bool mVintf = false;
// If an entry does not exist, need to ask /proc/{pid}/cmdline to get it.
// If an entry exist but is an empty string, process might have died.
diff --git a/cmds/lshal/PipeRelay.cpp b/cmds/lshal/PipeRelay.cpp
new file mode 100644
index 0000000..c7b29df
--- /dev/null
+++ b/cmds/lshal/PipeRelay.cpp
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "PipeRelay.h"
+
+#include <sys/socket.h>
+#include <utils/Thread.h>
+
+namespace android {
+namespace lshal {
+
+struct PipeRelay::RelayThread : public Thread {
+ explicit RelayThread(int fd, std::ostream &os);
+
+ bool threadLoop() override;
+
+private:
+ int mFd;
+ std::ostream &mOutStream;
+
+ DISALLOW_COPY_AND_ASSIGN(RelayThread);
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+PipeRelay::RelayThread::RelayThread(int fd, std::ostream &os)
+ : mFd(fd),
+ mOutStream(os) {
+}
+
+bool PipeRelay::RelayThread::threadLoop() {
+ char buffer[1024];
+ ssize_t n = read(mFd, buffer, sizeof(buffer));
+
+ if (n <= 0) {
+ return false;
+ }
+
+ mOutStream.write(buffer, n);
+
+ return true;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+PipeRelay::PipeRelay(std::ostream &os)
+ : mOutStream(os),
+ mInitCheck(NO_INIT) {
+ int res = socketpair(AF_UNIX, SOCK_STREAM, 0 /* protocol */, mFds);
+
+ if (res < 0) {
+ mInitCheck = -errno;
+ return;
+ }
+
+ mThread = new RelayThread(mFds[0], os);
+ mInitCheck = mThread->run("RelayThread");
+}
+
+// static
+void PipeRelay::CloseFd(int *fd) {
+ if (*fd >= 0) {
+ close(*fd);
+ *fd = -1;
+ }
+}
+
+PipeRelay::~PipeRelay() {
+ if (mFds[1] >= 0) {
+ shutdown(mFds[1], SHUT_WR);
+ }
+
+ if (mFds[0] >= 0) {
+ shutdown(mFds[0], SHUT_RD);
+ }
+
+ if (mThread != NULL) {
+ mThread->join();
+ mThread.clear();
+ }
+
+ CloseFd(&mFds[1]);
+ CloseFd(&mFds[0]);
+}
+
+status_t PipeRelay::initCheck() const {
+ return mInitCheck;
+}
+
+int PipeRelay::fd() const {
+ return mFds[1];
+}
+
+} // namespace lshal
+} // namespace android
diff --git a/cmds/lshal/PipeRelay.h b/cmds/lshal/PipeRelay.h
new file mode 100644
index 0000000..76b2b23
--- /dev/null
+++ b/cmds/lshal/PipeRelay.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef FRAMEWORKS_NATIVE_CMDS_LSHAL_PIPE_RELAY_H_
+
+#define FRAMEWORKS_NATIVE_CMDS_LSHAL_PIPE_RELAY_H_
+
+#include <android-base/macros.h>
+#include <ostream>
+#include <utils/Errors.h>
+#include <utils/RefBase.h>
+
+namespace android {
+namespace lshal {
+
+/* Creates an AF_UNIX socketpair and spawns a thread that relays any data
+ * written to the "write"-end of the pair to the specified output stream "os".
+ */
+struct PipeRelay {
+ explicit PipeRelay(std::ostream &os);
+ ~PipeRelay();
+
+ status_t initCheck() const;
+
+ // Returns the file descriptor corresponding to the "write"-end of the
+ // connection.
+ int fd() const;
+
+private:
+ struct RelayThread;
+
+ std::ostream &mOutStream;
+ status_t mInitCheck;
+ int mFds[2];
+ sp<RelayThread> mThread;
+
+ static void CloseFd(int *fd);
+
+ DISALLOW_COPY_AND_ASSIGN(PipeRelay);
+};
+
+} // namespace lshal
+} // namespace android
+
+#endif // FRAMEWORKS_NATIVE_CMDS_LSHAL_PIPE_RELAY_H_
+
diff --git a/cmds/vr/pose/pose.cpp b/cmds/vr/pose/pose.cpp
index 2288a86..faceb67 100644
--- a/cmds/vr/pose/pose.cpp
+++ b/cmds/vr/pose/pose.cpp
@@ -28,7 +28,7 @@
" px, py, pz as position (0,0,0 if omitted).\n"
<< " --mode=mode: sets mode to one of normal, head_turn:slow, "
"head_turn:fast, rotate:slow, rotate:medium, rotate:fast, "
- "circle_strafe.\n"
+ "circle_strafe, float, motion_sickness.\n"
<< " --unfreeze: sets the mode to normal.\n"
<< " --log_controller=[true|false]: starts and stops controller"
" logs\n"
@@ -150,6 +150,12 @@
} else if (value == "circle_strafe") {
*mode = DVR_POSE_MODE_MOCK_CIRCLE_STRAFE;
return true;
+ } else if (value == "float") {
+ *mode = DVR_POSE_MODE_FLOAT;
+ return true;
+ } else if (value == "motion_sickness") {
+ *mode = DVR_POSE_MODE_MOCK_MOTION_SICKNESS;
+ return true;
} else {
return false;
}
diff --git a/include/gfx/SafeLog.h b/include/gfx/SafeLog.h
deleted file mode 100644
index e45e541..0000000
--- a/include/gfx/SafeLog.h
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * 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.
- */
-
-#pragma once
-
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Weverything"
-#include <fmt/format.h>
-#include <log/log.h>
-#pragma clang diagnostic pop
-
-#include <type_traits>
-
-namespace android {
-namespace gfx {
-
-/* SafeLog is a mix-in that can be used to easily add typesafe logging using fmtlib to any class.
- * To use it, inherit from it using CRTP and implement the getLogTag method.
- *
- * For example:
- *
- * class Frobnicator : private SafeLog<Frobnicator> {
- * friend class SafeLog<Frobnicator>; // Allows getLogTag to be private
- *
- * public:
- * void frobnicate(int32_t i);
- *
- * private:
- * // SafeLog does member access on the object calling alog*, so this tag can theoretically vary
- * // by instance unless getLogTag is made static
- * const char* getLogTag() { return "Frobnicator"; }
- * };
- *
- * void Frobnicator::frobnicate(int32_t i) {
- * // Logs something like "04-16 21:35:46.811 3513 3513 I Frobnicator: frobnicating 42"
- * alogi("frobnicating {}", i);
- * }
- *
- * See http://fmtlib.net for more information on the formatting API.
- */
-
-template <typename T>
-class SafeLog {
- protected:
- template <typename... Args>
-#if LOG_NDEBUG
- void alogv(Args&&... /*unused*/) const {
- }
-#else
- void alogv(Args&&... args) const {
- alog<ANDROID_LOG_VERBOSE>(std::forward<Args>(args)...);
- }
-#endif
-
- template <typename... Args>
- void alogd(Args&&... args) const {
- alog<ANDROID_LOG_DEBUG>(std::forward<Args>(args)...);
- }
-
- template <typename... Args>
- void alogi(Args&&... args) const {
- alog<ANDROID_LOG_INFO>(std::forward<Args>(args)...);
- }
-
- template <typename... Args>
- void alogw(Args&&... args) const {
- alog<ANDROID_LOG_WARN>(std::forward<Args>(args)...);
- }
-
- template <typename... Args>
- void aloge(Args&&... args) const {
- alog<ANDROID_LOG_ERROR>(std::forward<Args>(args)...);
- }
-
- private:
- // Suppresses clang-tidy check cppcoreguidelines-pro-bounds-array-to-pointer-decay
- template <size_t strlen, typename... Args>
- void write(fmt::MemoryWriter* writer, const char (&str)[strlen], Args&&... args) const {
- writer->write(static_cast<const char*>(str), std::forward<Args>(args)...);
- }
-
- template <int priority, typename... Args>
- void alog(Args&&... args) const {
- static_assert(std::is_base_of<SafeLog<T>, T>::value, "Can't convert to SafeLog pointer");
- fmt::MemoryWriter writer;
- write(&writer, std::forward<Args>(args)...);
- auto derivedThis = static_cast<const T*>(this);
- android_writeLog(priority, derivedThis->getLogTag(), writer.c_str());
- }
-};
-
-} // namespace gfx
-} // namespace android
diff --git a/include/gui/ISurfaceComposerClient.h b/include/gui/ISurfaceComposerClient.h
index 1f4387d..a680bc6 100644
--- a/include/gui/ISurfaceComposerClient.h
+++ b/include/gui/ISurfaceComposerClient.h
@@ -14,55 +14,52 @@
* limitations under the License.
*/
-#ifndef ANDROID_GUI_ISURFACE_COMPOSER_CLIENT_H
-#define ANDROID_GUI_ISURFACE_COMPOSER_CLIENT_H
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <utils/Errors.h>
-#include <utils/RefBase.h>
+#pragma once
#include <binder/IInterface.h>
-
-#include <ui/FrameStats.h>
+#include <binder/SafeInterface.h>
#include <ui/PixelFormat.h>
namespace android {
-// ----------------------------------------------------------------------------
+class FrameStats;
class IGraphicBufferProducer;
-class ISurfaceComposerClient : public IInterface
-{
+class ISurfaceComposerClient : public IInterface {
public:
DECLARE_META_INTERFACE(SurfaceComposerClient)
+ enum class Tag : uint32_t {
+ CreateSurface = IBinder::FIRST_CALL_TRANSACTION,
+ DestroySurface,
+ ClearLayerFrameStats,
+ GetLayerFrameStats,
+ Last,
+ };
+
// flags for createSurface()
enum { // (keep in sync with Surface.java)
- eHidden = 0x00000004,
- eDestroyBackbuffer = 0x00000020,
- eSecure = 0x00000080,
- eNonPremultiplied = 0x00000100,
- eOpaque = 0x00000400,
- eProtectedByApp = 0x00000800,
- eProtectedByDRM = 0x00001000,
- eCursorWindow = 0x00002000,
+ eHidden = 0x00000004,
+ eDestroyBackbuffer = 0x00000020,
+ eSecure = 0x00000080,
+ eNonPremultiplied = 0x00000100,
+ eOpaque = 0x00000400,
+ eProtectedByApp = 0x00000800,
+ eProtectedByDRM = 0x00001000,
+ eCursorWindow = 0x00002000,
- eFXSurfaceNormal = 0x00000000,
- eFXSurfaceDim = 0x00020000,
- eFXSurfaceMask = 0x000F0000,
+ eFXSurfaceNormal = 0x00000000,
+ eFXSurfaceDim = 0x00020000,
+ eFXSurfaceMask = 0x000F0000,
};
/*
* Requires ACCESS_SURFACE_FLINGER permission
*/
- virtual status_t createSurface(
- const String8& name, uint32_t w, uint32_t h,
- PixelFormat format, uint32_t flags,
- const sp<IBinder>& parent, uint32_t windowType, uint32_t ownerUid,
- sp<IBinder>* handle,
- sp<IGraphicBufferProducer>* gbp) = 0;
+ virtual status_t createSurface(const String8& name, uint32_t w, uint32_t h, PixelFormat format,
+ uint32_t flags, const sp<IBinder>& parent, uint32_t windowType,
+ uint32_t ownerUid, sp<IBinder>* handle,
+ sp<IGraphicBufferProducer>* gbp) = 0;
/*
* Requires ACCESS_SURFACE_FLINGER permission
@@ -78,21 +75,14 @@
* Requires ACCESS_SURFACE_FLINGER permission
*/
virtual status_t getLayerFrameStats(const sp<IBinder>& handle, FrameStats* outStats) const = 0;
-
- virtual status_t getTransformToDisplayInverse(const sp<IBinder>& handle,
- bool* outTransformToDisplayInverse) const = 0;
};
-// ----------------------------------------------------------------------------
-
-class BnSurfaceComposerClient: public BnInterface<ISurfaceComposerClient> {
+class BnSurfaceComposerClient : public SafeBnInterface<ISurfaceComposerClient> {
public:
- virtual status_t onTransact(uint32_t code, const Parcel& data,
- Parcel* reply, uint32_t flags = 0);
+ BnSurfaceComposerClient()
+ : SafeBnInterface<ISurfaceComposerClient>("BnSurfaceComposerClient") {}
+
+ status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) override;
};
-// ----------------------------------------------------------------------------
-
-}; // namespace android
-
-#endif // ANDROID_GUI_ISURFACE_COMPOSER_CLIENT_H
+} // namespace android
diff --git a/include/gui/SurfaceComposerClient.h b/include/gui/SurfaceComposerClient.h
index 1e8cf76..394425a 100644
--- a/include/gui/SurfaceComposerClient.h
+++ b/include/gui/SurfaceComposerClient.h
@@ -169,9 +169,6 @@
status_t clearLayerFrameStats(const sp<IBinder>& token) const;
status_t getLayerFrameStats(const sp<IBinder>& token, FrameStats* outStats) const;
- status_t getTransformToDisplayInverse(const sp<IBinder>& token,
- bool* outTransformToDisplayInverse) const;
-
static status_t clearAnimationFrameStats();
static status_t getAnimationFrameStats(FrameStats* outStats);
diff --git a/include/gui/SurfaceControl.h b/include/gui/SurfaceControl.h
index 8ee35bc..3cff7df 100644
--- a/include/gui/SurfaceControl.h
+++ b/include/gui/SurfaceControl.h
@@ -119,8 +119,6 @@
status_t clearLayerFrameStats() const;
status_t getLayerFrameStats(FrameStats* outStats) const;
- status_t getTransformToDisplayInverse(bool* outTransformToDisplayInverse) const;
-
private:
// can't be copied
SurfaceControl& operator = (SurfaceControl& rhs);
diff --git a/include/media/openmax/OMX_AsString.h b/include/media/openmax/OMX_AsString.h
index 6b21979..56d7cc8 100644
--- a/include/media/openmax/OMX_AsString.h
+++ b/include/media/openmax/OMX_AsString.h
@@ -557,6 +557,7 @@
case OMX_IndexConfigPriority: return "ConfigPriority";
case OMX_IndexConfigOperatingRate: return "ConfigOperatingRate";
case OMX_IndexParamConsumerUsageBits: return "ParamConsumerUsageBits";
+ case OMX_IndexConfigLatency: return "ConfigLatency";
default: return asString((OMX_INDEXTYPE)i, def);
}
}
diff --git a/include/media/openmax/OMX_IndexExt.h b/include/media/openmax/OMX_IndexExt.h
index eccecaa..5a029d0 100644
--- a/include/media/openmax/OMX_IndexExt.h
+++ b/include/media/openmax/OMX_IndexExt.h
@@ -96,6 +96,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_IndexConfigLatency, /**< reference: OMX_PARAM_U32TYPE */
OMX_IndexExtOtherEndUnused,
/* Time configurations */
diff --git a/include/ui/ColorSpace.h b/include/ui/ColorSpace.h
index 8c4acb7..8ccf6d3 100644
--- a/include/ui/ColorSpace.h
+++ b/include/ui/ColorSpace.h
@@ -35,6 +35,16 @@
typedef std::function<float(float)> transfer_function;
typedef std::function<float(float)> clamping_function;
+ struct TransferParameters {
+ float g = 0.0f;
+ float a = 0.0f;
+ float b = 0.0f;
+ float c = 0.0f;
+ float d = 0.0f;
+ float e = 0.0f;
+ float f = 0.0f;
+ };
+
/**
* Creates a named color space with the specified RGB->XYZ
* conversion matrix. The white point and primaries will be
@@ -47,8 +57,39 @@
ColorSpace(
const std::string& name,
const mat3& rgbToXYZ,
- transfer_function OETF = linearReponse,
- transfer_function EOTF = linearReponse,
+ transfer_function OETF = linearResponse,
+ transfer_function EOTF = linearResponse,
+ clamping_function clamper = saturate<float>
+ ) noexcept;
+
+ /**
+ * Creates a named color space with the specified RGB->XYZ
+ * conversion matrix. The white point and primaries will be
+ * computed from the supplied matrix.
+ *
+ * The transfer functions are defined by the set of supplied
+ * transfer parameters. The default clamping function is a
+ * simple saturate (clamp(x, 0, 1)).
+ */
+ ColorSpace(
+ const std::string& name,
+ const mat3& rgbToXYZ,
+ const TransferParameters parameters,
+ clamping_function clamper = saturate<float>
+ ) noexcept;
+
+ /**
+ * Creates a named color space with the specified RGB->XYZ
+ * conversion matrix. The white point and primaries will be
+ * computed from the supplied matrix.
+ *
+ * The transfer functions are defined by a simple gamma value.
+ * The default clamping function is a saturate (clamp(x, 0, 1)).
+ */
+ ColorSpace(
+ const std::string& name,
+ const mat3& rgbToXYZ,
+ float gamma,
clamping_function clamper = saturate<float>
) noexcept;
@@ -65,8 +106,41 @@
const std::string& name,
const std::array<float2, 3>& primaries,
const float2& whitePoint,
- transfer_function OETF = linearReponse,
- transfer_function EOTF = linearReponse,
+ transfer_function OETF = linearResponse,
+ transfer_function EOTF = linearResponse,
+ clamping_function clamper = saturate<float>
+ ) noexcept;
+
+ /**
+ * Creates a named color space with the specified primaries
+ * and white point. The RGB<>XYZ conversion matrices are
+ * computed from the primaries and white point.
+ *
+ * The transfer functions are defined by the set of supplied
+ * transfer parameters. The default clamping function is a
+ * simple saturate (clamp(x, 0, 1)).
+ */
+ ColorSpace(
+ const std::string& name,
+ const std::array<float2, 3>& primaries,
+ const float2& whitePoint,
+ const TransferParameters parameters,
+ clamping_function clamper = saturate<float>
+ ) noexcept;
+
+ /**
+ * Creates a named color space with the specified primaries
+ * and white point. The RGB<>XYZ conversion matrices are
+ * computed from the primaries and white point.
+ *
+ * The transfer functions are defined by a single gamma value.
+ * The default clamping function is a saturate (clamp(x, 0, 1)).
+ */
+ ColorSpace(
+ const std::string& name,
+ const std::array<float2, 3>& primaries,
+ const float2& whitePoint,
+ float gamma,
clamping_function clamper = saturate<float>
) noexcept;
@@ -138,6 +212,10 @@
return mWhitePoint;
}
+ constexpr const TransferParameters& getTransferParameters() const noexcept {
+ return mParameters;
+ }
+
/**
* Converts the supplied XYZ value to xyY.
*/
@@ -166,35 +244,6 @@
static const ColorSpace ACES();
static const ColorSpace ACEScg();
- class Connector {
- public:
- Connector(const ColorSpace& src, const ColorSpace& dst) noexcept;
-
- constexpr const ColorSpace& getSource() const noexcept { return mSource; }
- constexpr const ColorSpace& getDestination() const noexcept { return mDestination; }
-
- constexpr const mat3& getTransform() const noexcept { return mTransform; }
-
- constexpr float3 transform(const float3& v) const noexcept {
- float3 linear = mSource.toLinear(apply(v, mSource.getClamper()));
- return apply(mDestination.fromLinear(mTransform * linear), mDestination.getClamper());
- }
-
- constexpr float3 transformLinear(const float3& v) const noexcept {
- float3 linear = apply(v, mSource.getClamper());
- return apply(mTransform * linear, mDestination.getClamper());
- }
-
- private:
- const ColorSpace& mSource;
- const ColorSpace& mDestination;
- mat3 mTransform;
- };
-
- static const Connector connect(const ColorSpace& src, const ColorSpace& dst) {
- return Connector(src, dst);
- }
-
// Creates a NxNxN 3D LUT, where N is the specified size (min=2, max=256)
// The 3D lookup coordinates map to the RGB components: u=R, v=G, w=B
// The generated 3D LUT is meant to be used as a 3D texture and its Y
@@ -208,7 +257,7 @@
static constexpr mat3 computeXYZMatrix(
const std::array<float2, 3>& primaries, const float2& whitePoint);
- static constexpr float linearReponse(float v) {
+ static constexpr float linearResponse(float v) {
return v;
}
@@ -217,6 +266,7 @@
mat3 mRGBtoXYZ;
mat3 mXYZtoRGB;
+ TransferParameters mParameters;
transfer_function mOETF;
transfer_function mEOTF;
clamping_function mClamper;
@@ -225,6 +275,31 @@
float2 mWhitePoint;
};
+class ColorSpaceConnector {
+public:
+ ColorSpaceConnector(const ColorSpace& src, const ColorSpace& dst) noexcept;
+
+ constexpr const ColorSpace& getSource() const noexcept { return mSource; }
+ constexpr const ColorSpace& getDestination() const noexcept { return mDestination; }
+
+ constexpr const mat3& getTransform() const noexcept { return mTransform; }
+
+ constexpr float3 transform(const float3& v) const noexcept {
+ float3 linear = mSource.toLinear(apply(v, mSource.getClamper()));
+ return apply(mDestination.fromLinear(mTransform * linear), mDestination.getClamper());
+ }
+
+ constexpr float3 transformLinear(const float3& v) const noexcept {
+ float3 linear = apply(v, mSource.getClamper());
+ return apply(mTransform * linear, mDestination.getClamper());
+ }
+
+private:
+ ColorSpace mSource;
+ ColorSpace mDestination;
+ mat3 mTransform;
+};
+
}; // namespace android
#endif // ANDROID_UI_COLOR_SPACE
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
index 93b8684..b225128 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -71,6 +71,10 @@
"libutils",
],
+ export_include_dirs: [
+ "include",
+ ],
+
clang: true,
sanitize: {
misc_undefined: ["integer"],
diff --git a/libs/binder/include/binder/SafeInterface.h b/libs/binder/include/binder/SafeInterface.h
new file mode 100644
index 0000000..0e723c5
--- /dev/null
+++ b/libs/binder/include/binder/SafeInterface.h
@@ -0,0 +1,621 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <binder/IInterface.h>
+#include <binder/Parcel.h>
+#include <cutils/compiler.h>
+
+// Set to 1 to enable CallStacks when logging errors
+#define SI_DUMP_CALLSTACKS 0
+#if SI_DUMP_CALLSTACKS
+#include <utils/CallStack.h>
+#endif
+
+#include <functional>
+#include <type_traits>
+
+namespace android {
+namespace SafeInterface {
+
+// ParcelHandler is responsible for writing/reading various types to/from a Parcel in a generic way
+class ParcelHandler {
+public:
+ explicit ParcelHandler(const char* logTag) : mLogTag(logTag) {}
+
+ // Specializations for types with dedicated handling in Parcel
+ status_t read(const Parcel& parcel, bool* b) const {
+ return callParcel("readBool", [&]() { return parcel.readBool(b); });
+ }
+ status_t write(Parcel* parcel, bool b) const {
+ return callParcel("writeBool", [&]() { return parcel->writeBool(b); });
+ }
+ template <typename T>
+ typename std::enable_if<std::is_base_of<LightFlattenable<T>, T>::value, status_t>::type read(
+ const Parcel& parcel, T* t) const {
+ return callParcel("read(LightFlattenable)", [&]() { return parcel.read(*t); });
+ }
+ template <typename T>
+ typename std::enable_if<std::is_base_of<LightFlattenable<T>, T>::value, status_t>::type write(
+ Parcel* parcel, const T& t) const {
+ return callParcel("write(LightFlattenable)", [&]() { return parcel->write(t); });
+ }
+ template <typename T>
+ typename std::enable_if<std::is_base_of<Parcelable, T>::value, status_t>::type read(
+ const Parcel& parcel, T* t) const {
+ return callParcel("readParcelable", [&]() { return parcel.readParcelable(t); });
+ }
+ template <typename T>
+ typename std::enable_if<std::is_base_of<Parcelable, T>::value, status_t>::type write(
+ Parcel* parcel, const T& t) const {
+ return callParcel("writeParcelable", [&]() { return parcel->writeParcelable(t); });
+ }
+ status_t read(const Parcel& parcel, String8* str) const {
+ return callParcel("readString8", [&]() { return parcel.readString8(str); });
+ }
+ status_t write(Parcel* parcel, const String8& str) const {
+ return callParcel("writeString8", [&]() { return parcel->writeString8(str); });
+ }
+ template <typename T>
+ status_t read(const Parcel& parcel, sp<T>* pointer) const {
+ return callParcel("readNullableStrongBinder",
+ [&]() { return parcel.readNullableStrongBinder(pointer); });
+ }
+ template <typename T>
+ typename std::enable_if<std::is_same<IBinder, T>::value, status_t>::type write(
+ Parcel* parcel, const sp<T>& pointer) const {
+ return callParcel("writeStrongBinder",
+ [&]() { return parcel->writeStrongBinder(pointer); });
+ }
+ template <typename T>
+ typename std::enable_if<std::is_base_of<IInterface, T>::value, status_t>::type write(
+ Parcel* parcel, const sp<T>& interface) const {
+ return write(parcel, IInterface::asBinder(interface));
+ }
+
+ // Templates to handle integral types. We use a struct template to require that the called
+ // function exactly matches the signedness and size of the argument (e.g., the argument isn't
+ // silently widened).
+ template <bool isSigned, size_t size, typename I>
+ struct HandleInt;
+ template <typename I>
+ struct HandleInt<true, 4, I> {
+ static status_t read(const ParcelHandler& handler, const Parcel& parcel, I* i) {
+ return handler.callParcel("readInt32", [&]() { return parcel.readInt32(i); });
+ }
+ static status_t write(const ParcelHandler& handler, Parcel* parcel, I i) {
+ return handler.callParcel("writeInt32", [&]() { return parcel->writeInt32(i); });
+ }
+ };
+ template <typename I>
+ struct HandleInt<false, 4, I> {
+ static status_t read(const ParcelHandler& handler, const Parcel& parcel, I* i) {
+ return handler.callParcel("readUint32", [&]() { return parcel.readUint32(i); });
+ }
+ static status_t write(const ParcelHandler& handler, Parcel* parcel, I i) {
+ return handler.callParcel("writeUint32", [&]() { return parcel->writeUint32(i); });
+ }
+ };
+ template <typename I>
+ typename std::enable_if<std::is_integral<I>::value, status_t>::type read(const Parcel& parcel,
+ I* i) const {
+ return HandleInt<std::is_signed<I>::value, sizeof(I), I>::read(*this, parcel, i);
+ }
+ template <typename I>
+ typename std::enable_if<std::is_integral<I>::value, status_t>::type write(Parcel* parcel,
+ I i) const {
+ return HandleInt<std::is_signed<I>::value, sizeof(I), I>::write(*this, parcel, i);
+ }
+
+private:
+ const char* const mLogTag;
+
+ // Helper to encapsulate error handling while calling the various Parcel methods
+ template <typename Function>
+ status_t callParcel(const char* name, Function f) const {
+ status_t error = f();
+ if (CC_UNLIKELY(error != NO_ERROR)) {
+ ALOG(LOG_ERROR, mLogTag, "Failed to %s, (%d: %s)", name, error, strerror(-error));
+#if SI_DUMP_CALLSTACKS
+ CallStack callStack(mLogTag);
+#endif
+ }
+ return error;
+ }
+};
+
+// Utility struct template which allows us to retrieve the types of the parameters of a member
+// function pointer
+template <typename T>
+struct ParamExtractor;
+template <typename Class, typename Return, typename... Params>
+struct ParamExtractor<Return (Class::*)(Params...)> {
+ using ParamTuple = std::tuple<Params...>;
+};
+template <typename Class, typename Return, typename... Params>
+struct ParamExtractor<Return (Class::*)(Params...) const> {
+ using ParamTuple = std::tuple<Params...>;
+};
+
+} // namespace SafeInterface
+
+template <typename Interface>
+class SafeBpInterface : public BpInterface<Interface> {
+protected:
+ SafeBpInterface(const sp<IBinder>& impl, const char* logTag)
+ : BpInterface<Interface>(impl), mLogTag(logTag) {}
+ ~SafeBpInterface() override = default;
+
+ // callRemote is used to invoke a synchronous procedure call over Binder
+ template <typename Method, typename TagType, typename... Args>
+ status_t callRemote(TagType tag, Args&&... args) const {
+ static_assert(sizeof(TagType) <= sizeof(uint32_t), "Tag must fit inside uint32_t");
+
+ // Verify that the arguments are compatible with the parameters
+ using ParamTuple = typename SafeInterface::ParamExtractor<Method>::ParamTuple;
+ static_assert(ArgsMatchParams<std::tuple<Args...>, ParamTuple>::value,
+ "Invalid argument type");
+
+ // Write the input arguments to the data Parcel
+ Parcel data;
+ data.writeInterfaceToken(this->getInterfaceDescriptor());
+
+ status_t error = writeInputs(&data, std::forward<Args>(args)...);
+ if (CC_UNLIKELY(error != NO_ERROR)) {
+ // A message will have been logged by writeInputs
+ return error;
+ }
+
+ // Send the data Parcel to the remote and retrieve the reply parcel
+ Parcel reply;
+ error = this->remote()->transact(static_cast<uint32_t>(tag), data, &reply);
+ if (CC_UNLIKELY(error != NO_ERROR)) {
+ ALOG(LOG_ERROR, mLogTag, "Failed to transact (%d)", error);
+#if SI_DUMP_CALLSTACKS
+ CallStack callStack(mLogTag);
+#endif
+ return error;
+ }
+
+ // Read the outputs from the reply Parcel into the output arguments
+ error = readOutputs(reply, std::forward<Args>(args)...);
+ if (CC_UNLIKELY(error != NO_ERROR)) {
+ // A message will have been logged by readOutputs
+ return error;
+ }
+
+ // Retrieve the result code from the reply Parcel
+ status_t result = NO_ERROR;
+ error = reply.readInt32(&result);
+ if (CC_UNLIKELY(error != NO_ERROR)) {
+ ALOG(LOG_ERROR, mLogTag, "Failed to obtain result");
+#if SI_DUMP_CALLSTACKS
+ CallStack callStack(mLogTag);
+#endif
+ return error;
+ }
+ return result;
+ }
+
+ // callRemoteAsync is used to invoke an asynchronous procedure call over Binder
+ template <typename Method, typename TagType, typename... Args>
+ void callRemoteAsync(TagType tag, Args&&... args) const {
+ static_assert(sizeof(TagType) <= sizeof(uint32_t), "Tag must fit inside uint32_t");
+
+ // Verify that the arguments are compatible with the parameters
+ using ParamTuple = typename SafeInterface::ParamExtractor<Method>::ParamTuple;
+ static_assert(ArgsMatchParams<std::tuple<Args...>, ParamTuple>::value,
+ "Invalid argument type");
+
+ // Write the input arguments to the data Parcel
+ Parcel data;
+ data.writeInterfaceToken(this->getInterfaceDescriptor());
+ status_t error = writeInputs(&data, std::forward<Args>(args)...);
+ if (CC_UNLIKELY(error != NO_ERROR)) {
+ // A message will have been logged by writeInputs
+ return;
+ }
+
+ // There will be no data in the reply Parcel since the call is one-way
+ Parcel reply;
+ error = this->remote()->transact(static_cast<uint32_t>(tag), data, &reply,
+ IBinder::FLAG_ONEWAY);
+ if (CC_UNLIKELY(error != NO_ERROR)) {
+ ALOG(LOG_ERROR, mLogTag, "Failed to transact (%d)", error);
+#if SI_DUMP_CALLSTACKS
+ CallStack callStack(mLogTag);
+#endif
+ }
+ }
+
+private:
+ const char* const mLogTag;
+
+ // This struct provides information on whether the decayed types of the elements at Index in the
+ // tuple types T and U (that is, the types after stripping cv-qualifiers, removing references,
+ // and a few other less common operations) are the same
+ template <size_t Index, typename T, typename U>
+ struct DecayedElementsMatch {
+ private:
+ using FirstT = typename std::tuple_element<Index, T>::type;
+ using DecayedT = typename std::decay<FirstT>::type;
+ using FirstU = typename std::tuple_element<Index, U>::type;
+ using DecayedU = typename std::decay<FirstU>::type;
+
+ public:
+ static constexpr bool value = std::is_same<DecayedT, DecayedU>::value;
+ };
+
+ // When comparing whether the argument types match the parameter types, we first decay them (see
+ // DecayedElementsMatch) to avoid falsely flagging, say, T&& against T even though they are
+ // equivalent enough for our purposes
+ template <typename T, typename U>
+ struct ArgsMatchParams {};
+ template <typename... Args, typename... Params>
+ struct ArgsMatchParams<std::tuple<Args...>, std::tuple<Params...>> {
+ static_assert(sizeof...(Args) <= sizeof...(Params), "Too many arguments");
+ static_assert(sizeof...(Args) >= sizeof...(Params), "Not enough arguments");
+
+ private:
+ template <size_t Index>
+ static constexpr typename std::enable_if<(Index < sizeof...(Args)), bool>::type
+ elementsMatch() {
+ if (!DecayedElementsMatch<Index, std::tuple<Args...>, std::tuple<Params...>>::value) {
+ return false;
+ }
+ return elementsMatch<Index + 1>();
+ }
+ template <size_t Index>
+ static constexpr typename std::enable_if<(Index >= sizeof...(Args)), bool>::type
+ elementsMatch() {
+ return true;
+ }
+
+ public:
+ static constexpr bool value = elementsMatch<0>();
+ };
+
+ // Since we assume that pointer arguments are outputs, we can use this template struct to
+ // determine whether or not a given argument is fundamentally a pointer type and thus an output
+ template <typename T>
+ struct IsPointerIfDecayed {
+ private:
+ using Decayed = typename std::decay<T>::type;
+
+ public:
+ static constexpr bool value = std::is_pointer<Decayed>::value;
+ };
+
+ template <typename T>
+ typename std::enable_if<!IsPointerIfDecayed<T>::value, status_t>::type writeIfInput(
+ Parcel* data, T&& t) const {
+ return SafeInterface::ParcelHandler{mLogTag}.write(data, std::forward<T>(t));
+ }
+ template <typename T>
+ typename std::enable_if<IsPointerIfDecayed<T>::value, status_t>::type writeIfInput(
+ Parcel* /*data*/, T&& /*t*/) const {
+ return NO_ERROR;
+ }
+
+ // This method iterates through all of the arguments, writing them to the data Parcel if they
+ // are an input (i.e., if they are not a pointer type)
+ template <typename T, typename... Remaining>
+ status_t writeInputs(Parcel* data, T&& t, Remaining&&... remaining) const {
+ status_t error = writeIfInput(data, std::forward<T>(t));
+ if (CC_UNLIKELY(error != NO_ERROR)) {
+ // A message will have been logged by writeIfInput
+ return error;
+ }
+ return writeInputs(data, std::forward<Remaining>(remaining)...);
+ }
+ static status_t writeInputs(Parcel* /*data*/) { return NO_ERROR; }
+
+ template <typename T>
+ typename std::enable_if<IsPointerIfDecayed<T>::value, status_t>::type readIfOutput(
+ const Parcel& reply, T&& t) const {
+ return SafeInterface::ParcelHandler{mLogTag}.read(reply, std::forward<T>(t));
+ }
+ template <typename T>
+ static typename std::enable_if<!IsPointerIfDecayed<T>::value, status_t>::type readIfOutput(
+ const Parcel& /*reply*/, T&& /*t*/) {
+ return NO_ERROR;
+ }
+
+ // Similar to writeInputs except that it reads output arguments from the reply Parcel
+ template <typename T, typename... Remaining>
+ status_t readOutputs(const Parcel& reply, T&& t, Remaining&&... remaining) const {
+ status_t error = readIfOutput(reply, std::forward<T>(t));
+ if (CC_UNLIKELY(error != NO_ERROR)) {
+ // A message will have been logged by readIfOutput
+ return error;
+ }
+ return readOutputs(reply, std::forward<Remaining>(remaining)...);
+ }
+ static status_t readOutputs(const Parcel& /*data*/) { return NO_ERROR; }
+};
+
+template <typename Interface>
+class SafeBnInterface : public BnInterface<Interface> {
+public:
+ explicit SafeBnInterface(const char* logTag) : mLogTag(logTag) {}
+
+protected:
+ template <typename Method>
+ status_t callLocal(const Parcel& data, Parcel* reply, Method method) {
+ CHECK_INTERFACE(this, data, reply);
+
+ // Since we need to both pass inputs into the call as well as retrieve outputs, we create a
+ // "raw" tuple, where the inputs are interleaved with actual, non-pointer versions of the
+ // outputs. When we ultimately call into the method, we will pass the addresses of the
+ // output arguments instead of their tuple members directly, but the storage will live in
+ // the tuple.
+ using ParamTuple = typename SafeInterface::ParamExtractor<Method>::ParamTuple;
+ typename RawConverter<std::tuple<>, ParamTuple>::type rawArgs{};
+
+ // Read the inputs from the data Parcel into the argument tuple
+ status_t error = InputReader<ParamTuple>{mLogTag}.readInputs(data, &rawArgs);
+ if (CC_UNLIKELY(error != NO_ERROR)) {
+ // A message will have been logged by read
+ return error;
+ }
+
+ // Call the local method
+ status_t result = MethodCaller<ParamTuple>::call(this, method, &rawArgs);
+
+ // Extract the outputs from the argument tuple and write them into the reply Parcel
+ error = OutputWriter<ParamTuple>{mLogTag}.writeOutputs(reply, &rawArgs);
+ if (CC_UNLIKELY(error != NO_ERROR)) {
+ // A message will have been logged by write
+ return error;
+ }
+
+ // Return the result code in the reply Parcel
+ error = reply->writeInt32(result);
+ if (CC_UNLIKELY(error != NO_ERROR)) {
+ ALOG(LOG_ERROR, mLogTag, "Failed to write result");
+#if SI_DUMP_CALLSTACKS
+ CallStack callStack(mLogTag);
+#endif
+ return error;
+ }
+ return NO_ERROR;
+ }
+
+ template <typename Method>
+ status_t callLocalAsync(const Parcel& data, Parcel* /*reply*/, Method method) {
+ // reply is not actually used by CHECK_INTERFACE
+ CHECK_INTERFACE(this, data, reply);
+
+ // Since we need to both pass inputs into the call as well as retrieve outputs, we create a
+ // "raw" tuple, where the inputs are interleaved with actual, non-pointer versions of the
+ // outputs. When we ultimately call into the method, we will pass the addresses of the
+ // output arguments instead of their tuple members directly, but the storage will live in
+ // the tuple.
+ using ParamTuple = typename SafeInterface::ParamExtractor<Method>::ParamTuple;
+ typename RawConverter<std::tuple<>, ParamTuple>::type rawArgs{};
+
+ // Read the inputs from the data Parcel into the argument tuple
+ status_t error = InputReader<ParamTuple>{mLogTag}.readInputs(data, &rawArgs);
+ if (CC_UNLIKELY(error != NO_ERROR)) {
+ // A message will have been logged by read
+ return error;
+ }
+
+ // Call the local method
+ MethodCaller<ParamTuple>::callVoid(this, method, &rawArgs);
+
+ // After calling, there is nothing more to do since asynchronous calls do not return a value
+ // to the caller
+ return NO_ERROR;
+ }
+
+private:
+ const char* const mLogTag;
+
+ // RemoveFirst strips the first element from a tuple.
+ // For example, given T = std::tuple<A, B, C>, RemoveFirst<T>::type = std::tuple<B, C>
+ template <typename T, typename... Args>
+ struct RemoveFirst;
+ template <typename T, typename... Args>
+ struct RemoveFirst<std::tuple<T, Args...>> {
+ using type = std::tuple<Args...>;
+ };
+
+ // RawConverter strips a tuple down to its fundamental types, discarding both pointers and
+ // references. This allows us to allocate storage for both input (non-pointer) arguments and
+ // output (pointer) arguments in one tuple.
+ // For example, given T = std::tuple<const A&, B*>, RawConverter<T>::type = std::tuple<A, B>
+ template <typename Unconverted, typename... Converted>
+ struct RawConverter;
+ template <typename Unconverted, typename... Converted>
+ struct RawConverter<std::tuple<Converted...>, Unconverted> {
+ private:
+ using ElementType = typename std::tuple_element<0, Unconverted>::type;
+ using Decayed = typename std::decay<ElementType>::type;
+ using WithoutPointer = typename std::remove_pointer<Decayed>::type;
+
+ public:
+ using type = typename RawConverter<std::tuple<Converted..., WithoutPointer>,
+ typename RemoveFirst<Unconverted>::type>::type;
+ };
+ template <typename... Converted>
+ struct RawConverter<std::tuple<Converted...>, std::tuple<>> {
+ using type = std::tuple<Converted...>;
+ };
+
+ // This provides a simple way to determine whether the indexed element of Args... is a pointer
+ template <size_t I, typename... Args>
+ struct ElementIsPointer {
+ private:
+ using ElementType = typename std::tuple_element<I, std::tuple<Args...>>::type;
+
+ public:
+ static constexpr bool value = std::is_pointer<ElementType>::value;
+ };
+
+ // This class iterates over the parameter types, and if a given parameter is an input
+ // (i.e., is not a pointer), reads the corresponding argument tuple element from the data Parcel
+ template <typename... Params>
+ class InputReader;
+ template <typename... Params>
+ class InputReader<std::tuple<Params...>> {
+ public:
+ explicit InputReader(const char* logTag) : mLogTag(logTag) {}
+
+ // Note that in this case (as opposed to in SafeBpInterface), we iterate using an explicit
+ // index (starting with 0 here) instead of using recursion and stripping the first element.
+ // This is because in SafeBpInterface we aren't actually operating on a real tuple, but are
+ // instead just using a tuple as a convenient container for variadic types, whereas here we
+ // can't modify the argument tuple without causing unnecessary copies or moves of the data
+ // contained therein.
+ template <typename RawTuple>
+ status_t readInputs(const Parcel& data, RawTuple* args) {
+ return dispatchArg<0>(data, args);
+ }
+
+ private:
+ const char* const mLogTag;
+
+ template <std::size_t I, typename RawTuple>
+ typename std::enable_if<!ElementIsPointer<I, Params...>::value, status_t>::type readIfInput(
+ const Parcel& data, RawTuple* args) {
+ return SafeInterface::ParcelHandler{mLogTag}.read(data, &std::get<I>(*args));
+ }
+ template <std::size_t I, typename RawTuple>
+ typename std::enable_if<ElementIsPointer<I, Params...>::value, status_t>::type readIfInput(
+ const Parcel& /*data*/, RawTuple* /*args*/) {
+ return NO_ERROR;
+ }
+
+ // Recursively iterate through the arguments
+ template <std::size_t I, typename RawTuple>
+ typename std::enable_if<(I < sizeof...(Params)), status_t>::type dispatchArg(
+ const Parcel& data, RawTuple* args) {
+ status_t error = readIfInput<I>(data, args);
+ if (CC_UNLIKELY(error != NO_ERROR)) {
+ // A message will have been logged in read
+ return error;
+ }
+ return dispatchArg<I + 1>(data, args);
+ }
+ template <std::size_t I, typename RawTuple>
+ typename std::enable_if<(I >= sizeof...(Params)), status_t>::type dispatchArg(
+ const Parcel& /*data*/, RawTuple* /*args*/) {
+ return NO_ERROR;
+ }
+ };
+
+ // getForCall uses the types of the parameters to determine whether a given element of the
+ // argument tuple is an input, which should be passed directly into the call, or an output, for
+ // which its address should be passed into the call
+ template <size_t I, typename RawTuple, typename... Params>
+ static typename std::enable_if<
+ ElementIsPointer<I, Params...>::value,
+ typename std::tuple_element<I, std::tuple<Params...>>::type>::type
+ getForCall(RawTuple* args) {
+ return &std::get<I>(*args);
+ }
+ template <size_t I, typename RawTuple, typename... Params>
+ static typename std::enable_if<
+ !ElementIsPointer<I, Params...>::value,
+ typename std::tuple_element<I, std::tuple<Params...>>::type>::type&
+ getForCall(RawTuple* args) {
+ return std::get<I>(*args);
+ }
+
+ // This template class uses std::index_sequence and parameter pack expansion to call the given
+ // method using the elements of the argument tuple (after those arguments are passed through
+ // getForCall to get addresses instead of values for output arguments)
+ template <typename... Params>
+ struct MethodCaller;
+ template <typename... Params>
+ struct MethodCaller<std::tuple<Params...>> {
+ public:
+ // The calls through these to the helper methods are necessary to generate the
+ // std::index_sequences used to unpack the argument tuple into the method call
+ template <typename Class, typename MemberFunction, typename RawTuple>
+ static status_t call(Class* instance, MemberFunction function, RawTuple* args) {
+ return callHelper(instance, function, args, std::index_sequence_for<Params...>{});
+ }
+ template <typename Class, typename MemberFunction, typename RawTuple>
+ static void callVoid(Class* instance, MemberFunction function, RawTuple* args) {
+ callVoidHelper(instance, function, args, std::index_sequence_for<Params...>{});
+ }
+
+ private:
+ template <typename Class, typename MemberFunction, typename RawTuple, std::size_t... I>
+ static status_t callHelper(Class* instance, MemberFunction function, RawTuple* args,
+ std::index_sequence<I...> /*unused*/) {
+ return (instance->*function)(getForCall<I, RawTuple, Params...>(args)...);
+ }
+ template <typename Class, typename MemberFunction, typename RawTuple, std::size_t... I>
+ static void callVoidHelper(Class* instance, MemberFunction function, RawTuple* args,
+ std::index_sequence<I...> /*unused*/) {
+ (instance->*function)(getForCall<I, RawTuple, Params...>(args)...);
+ }
+ };
+
+ // This class iterates over the parameter types, and if a given parameter is an output
+ // (i.e., is a pointer), writes the corresponding argument tuple element into the reply Parcel
+ template <typename... Params>
+ struct OutputWriter;
+ template <typename... Params>
+ struct OutputWriter<std::tuple<Params...>> {
+ public:
+ explicit OutputWriter(const char* logTag) : mLogTag(logTag) {}
+
+ // See the note on InputReader::readInputs for why this differs from the arguably simpler
+ // RemoveFirst approach in SafeBpInterface
+ template <typename RawTuple>
+ status_t writeOutputs(Parcel* reply, RawTuple* args) {
+ return dispatchArg<0>(reply, args);
+ }
+
+ private:
+ const char* const mLogTag;
+
+ template <std::size_t I, typename RawTuple>
+ typename std::enable_if<ElementIsPointer<I, Params...>::value, status_t>::type
+ writeIfOutput(Parcel* reply, RawTuple* args) {
+ return SafeInterface::ParcelHandler{mLogTag}.write(reply, std::get<I>(*args));
+ }
+ template <std::size_t I, typename RawTuple>
+ typename std::enable_if<!ElementIsPointer<I, Params...>::value, status_t>::type
+ writeIfOutput(Parcel* /*reply*/, RawTuple* /*args*/) {
+ return NO_ERROR;
+ }
+
+ // Recursively iterate through the arguments
+ template <std::size_t I, typename RawTuple>
+ typename std::enable_if<(I < sizeof...(Params)), status_t>::type dispatchArg(
+ Parcel* reply, RawTuple* args) {
+ status_t error = writeIfOutput<I>(reply, args);
+ if (CC_UNLIKELY(error != NO_ERROR)) {
+ // A message will have been logged in read
+ return error;
+ }
+ return dispatchArg<I + 1>(reply, args);
+ }
+ template <std::size_t I, typename RawTuple>
+ typename std::enable_if<(I >= sizeof...(Params)), status_t>::type dispatchArg(
+ Parcel* /*reply*/, RawTuple* /*args*/) {
+ return NO_ERROR;
+ }
+ };
+};
+
+} // namespace android
diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp
index 0dc4469..1ee4b6f 100644
--- a/libs/binder/tests/Android.bp
+++ b/libs/binder/tests/Android.bp
@@ -70,3 +70,37 @@
"libbase",
],
}
+
+cc_test {
+ name: "schd-dbg",
+ srcs: ["schd-dbg.cpp"],
+ shared_libs: [
+ "libbinder",
+ "libutils",
+ "libbase",
+ ],
+}
+
+cc_test {
+ name: "binderSafeInterfaceTest",
+ srcs: ["binderSafeInterfaceTest.cpp"],
+
+ cppflags: [
+ "-Werror",
+ "-Weverything",
+ "-Wno-c++98-compat",
+ "-Wno-c++98-compat-pedantic",
+ "-Wno-global-constructors",
+ "-Wno-padded",
+ "-Wno-weak-vtables",
+ ],
+
+ cpp_std: "experimental",
+ gnu_extensions: false,
+
+ shared_libs: [
+ "libbinder",
+ "liblog",
+ "libutils",
+ ],
+}
diff --git a/libs/binder/tests/binderSafeInterfaceTest.cpp b/libs/binder/tests/binderSafeInterfaceTest.cpp
new file mode 100644
index 0000000..ac2f4d5
--- /dev/null
+++ b/libs/binder/tests/binderSafeInterfaceTest.cpp
@@ -0,0 +1,514 @@
+/*
+ * 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.
+ */
+
+#include <binder/SafeInterface.h>
+
+#include <binder/IInterface.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/Parcel.h>
+#include <binder/Parcelable.h>
+#include <binder/ProcessState.h>
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Weverything"
+#include <gtest/gtest.h>
+#pragma clang diagnostic pop
+
+#include <optional>
+
+using namespace std::chrono_literals; // NOLINT - google-build-using-namespace
+
+namespace android {
+namespace tests {
+
+// This class serves two purposes:
+// 1) It ensures that the implementation doesn't require copying or moving the data (for
+// efficiency purposes)
+// 2) It tests that Parcelables can be passed correctly
+class NoCopyNoMove : public Parcelable {
+public:
+ NoCopyNoMove() = default;
+ explicit NoCopyNoMove(int32_t value) : mValue(value) {}
+ ~NoCopyNoMove() override = default;
+
+ // Not copyable
+ NoCopyNoMove(const NoCopyNoMove&) = delete;
+ NoCopyNoMove& operator=(const NoCopyNoMove&) = delete;
+
+ // Not movable
+ NoCopyNoMove(NoCopyNoMove&&) = delete;
+ NoCopyNoMove& operator=(NoCopyNoMove&&) = delete;
+
+ // Parcelable interface
+ status_t writeToParcel(Parcel* parcel) const override { return parcel->writeInt32(mValue); }
+ status_t readFromParcel(const Parcel* parcel) override { return parcel->readInt32(&mValue); }
+
+ int32_t getValue() const { return mValue; }
+ void setValue(int32_t value) { mValue = value; }
+
+private:
+ int32_t mValue = 0;
+ uint8_t mPadding[4] = {}; // Avoids a warning from -Wpadded
+};
+
+struct TestLightFlattenable : LightFlattenablePod<TestLightFlattenable> {
+ TestLightFlattenable() = default;
+ explicit TestLightFlattenable(int32_t v) : value(v) {}
+ int32_t value = 0;
+};
+
+class ExitOnDeath : public IBinder::DeathRecipient {
+public:
+ ~ExitOnDeath() override = default;
+
+ void binderDied(const wp<IBinder>& /*who*/) override {
+ ALOG(LOG_INFO, "ExitOnDeath", "Exiting");
+ exit(0);
+ }
+};
+
+// This callback class is used to test both one-way transactions and that sp<IInterface> can be
+// passed correctly
+class ICallback : public IInterface {
+public:
+ DECLARE_META_INTERFACE(Callback)
+
+ enum class Tag : uint32_t {
+ OnCallback = IBinder::FIRST_CALL_TRANSACTION,
+ Last,
+ };
+
+ virtual void onCallback(int32_t aPlusOne) = 0;
+};
+
+class BpCallback : public SafeBpInterface<ICallback> {
+public:
+ explicit BpCallback(const sp<IBinder>& impl) : SafeBpInterface<ICallback>(impl, getLogTag()) {}
+
+ void onCallback(int32_t aPlusOne) override {
+ ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
+ return callRemoteAsync<decltype(&ICallback::onCallback)>(Tag::OnCallback, aPlusOne);
+ }
+
+private:
+ static constexpr const char* getLogTag() { return "BpCallback"; }
+};
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wexit-time-destructors"
+IMPLEMENT_META_INTERFACE(Callback, "android.gfx.tests.ICallback");
+#pragma clang diagnostic pop
+
+class BnCallback : public SafeBnInterface<ICallback> {
+public:
+ BnCallback() : SafeBnInterface("BnCallback") {}
+
+ status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply,
+ uint32_t /*flags*/) override {
+ EXPECT_GE(code, IBinder::FIRST_CALL_TRANSACTION);
+ EXPECT_LT(code, static_cast<uint32_t>(ICallback::Tag::Last));
+ ICallback::Tag tag = static_cast<ICallback::Tag>(code);
+ switch (tag) {
+ case ICallback::Tag::OnCallback: {
+ return callLocalAsync(data, reply, &ICallback::onCallback);
+ }
+ case ICallback::Tag::Last:
+ // Should not be possible because of the asserts at the beginning of the method
+ [&]() { FAIL(); }();
+ return UNKNOWN_ERROR;
+ }
+ }
+};
+
+class ISafeInterfaceTest : public IInterface {
+public:
+ DECLARE_META_INTERFACE(SafeInterfaceTest)
+
+ enum class Tag : uint32_t {
+ SetDeathToken = IBinder::FIRST_CALL_TRANSACTION,
+ ReturnsNoMemory,
+ LogicalNot,
+ IncrementLightFlattenable,
+ IncrementNoCopyNoMove,
+ ToUpper,
+ CallMeBack,
+ IncrementInt32,
+ IncrementUint32,
+ IncrementTwo,
+ Last,
+ };
+
+ // This is primarily so that the remote service dies when the test does, but it also serves to
+ // test the handling of sp<IBinder> and non-const methods
+ virtual status_t setDeathToken(const sp<IBinder>& token) = 0;
+
+ // This is the most basic test since it doesn't require parceling any arguments
+ virtual status_t returnsNoMemory() const = 0;
+
+ // These are ordered according to their corresponding methods in SafeInterface::ParcelHandler
+ virtual status_t logicalNot(bool a, bool* notA) const = 0;
+ virtual status_t increment(const TestLightFlattenable& a,
+ TestLightFlattenable* aPlusOne) const = 0;
+ virtual status_t increment(const NoCopyNoMove& a, NoCopyNoMove* aPlusOne) const = 0;
+ virtual status_t toUpper(const String8& str, String8* upperStr) const = 0;
+ // As mentioned above, sp<IBinder> is already tested by setDeathToken
+ virtual void callMeBack(const sp<ICallback>& callback, int32_t a) const = 0;
+ virtual status_t increment(int32_t a, int32_t* aPlusOne) const = 0;
+ virtual status_t increment(uint32_t a, uint32_t* aPlusOne) const = 0;
+
+ // This tests that input/output parameter interleaving works correctly
+ virtual status_t increment(int32_t a, int32_t* aPlusOne, int32_t b,
+ int32_t* bPlusOne) const = 0;
+};
+
+class BpSafeInterfaceTest : public SafeBpInterface<ISafeInterfaceTest> {
+public:
+ explicit BpSafeInterfaceTest(const sp<IBinder>& impl)
+ : SafeBpInterface<ISafeInterfaceTest>(impl, getLogTag()) {}
+
+ status_t setDeathToken(const sp<IBinder>& token) override {
+ ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
+ return callRemote<decltype(&ISafeInterfaceTest::setDeathToken)>(Tag::SetDeathToken, token);
+ }
+ status_t returnsNoMemory() const override {
+ ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
+ return callRemote<decltype(&ISafeInterfaceTest::returnsNoMemory)>(Tag::ReturnsNoMemory);
+ }
+ status_t logicalNot(bool a, bool* notA) const override {
+ ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
+ return callRemote<decltype(&ISafeInterfaceTest::logicalNot)>(Tag::LogicalNot, a, notA);
+ }
+ status_t increment(const TestLightFlattenable& a,
+ TestLightFlattenable* aPlusOne) const override {
+ using Signature = status_t (ISafeInterfaceTest::*)(const TestLightFlattenable&,
+ TestLightFlattenable*) const;
+ ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
+ return callRemote<Signature>(Tag::IncrementLightFlattenable, a, aPlusOne);
+ }
+ status_t increment(const NoCopyNoMove& a, NoCopyNoMove* aPlusOne) const override {
+ ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
+ using Signature = status_t (ISafeInterfaceTest::*)(const NoCopyNoMove& a,
+ NoCopyNoMove* aPlusOne) const;
+ return callRemote<Signature>(Tag::IncrementNoCopyNoMove, a, aPlusOne);
+ }
+ status_t toUpper(const String8& str, String8* upperStr) const override {
+ ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
+ return callRemote<decltype(&ISafeInterfaceTest::toUpper)>(Tag::ToUpper, str, upperStr);
+ }
+ void callMeBack(const sp<ICallback>& callback, int32_t a) const override {
+ ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
+ return callRemoteAsync<decltype(&ISafeInterfaceTest::callMeBack)>(Tag::CallMeBack, callback,
+ a);
+ }
+ status_t increment(int32_t a, int32_t* aPlusOne) const override {
+ ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
+ using Signature = status_t (ISafeInterfaceTest::*)(int32_t, int32_t*) const;
+ return callRemote<Signature>(Tag::IncrementInt32, a, aPlusOne);
+ }
+ status_t increment(uint32_t a, uint32_t* aPlusOne) const override {
+ ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
+ using Signature = status_t (ISafeInterfaceTest::*)(uint32_t, uint32_t*) const;
+ return callRemote<Signature>(Tag::IncrementUint32, a, aPlusOne);
+ }
+ status_t increment(int32_t a, int32_t* aPlusOne, int32_t b, int32_t* bPlusOne) const override {
+ ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
+ using Signature =
+ status_t (ISafeInterfaceTest::*)(int32_t, int32_t*, int32_t, int32_t*) const;
+ return callRemote<Signature>(Tag::IncrementTwo, a, aPlusOne, b, bPlusOne);
+ }
+
+private:
+ static constexpr const char* getLogTag() { return "BpSafeInterfaceTest"; }
+};
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wexit-time-destructors"
+IMPLEMENT_META_INTERFACE(SafeInterfaceTest, "android.gfx.tests.ISafeInterfaceTest");
+
+static sp<IBinder::DeathRecipient> getDeathRecipient() {
+ static sp<IBinder::DeathRecipient> recipient = new ExitOnDeath;
+ return recipient;
+}
+#pragma clang diagnostic pop
+
+class BnSafeInterfaceTest : public SafeBnInterface<ISafeInterfaceTest> {
+public:
+ BnSafeInterfaceTest() : SafeBnInterface(getLogTag()) {}
+
+ status_t setDeathToken(const sp<IBinder>& token) override {
+ ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
+ token->linkToDeath(getDeathRecipient());
+ return NO_ERROR;
+ }
+ status_t returnsNoMemory() const override {
+ ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
+ return NO_MEMORY;
+ }
+ status_t logicalNot(bool a, bool* notA) const override {
+ ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
+ *notA = !a;
+ return NO_ERROR;
+ }
+ status_t increment(const TestLightFlattenable& a,
+ TestLightFlattenable* aPlusOne) const override {
+ ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
+ aPlusOne->value = a.value + 1;
+ return NO_ERROR;
+ }
+ status_t increment(const NoCopyNoMove& a, NoCopyNoMove* aPlusOne) const override {
+ ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
+ aPlusOne->setValue(a.getValue() + 1);
+ return NO_ERROR;
+ }
+ status_t toUpper(const String8& str, String8* upperStr) const override {
+ ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
+ *upperStr = str;
+ upperStr->toUpper();
+ return NO_ERROR;
+ }
+ void callMeBack(const sp<ICallback>& callback, int32_t a) const override {
+ ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
+ callback->onCallback(a + 1);
+ }
+ status_t increment(int32_t a, int32_t* aPlusOne) const override {
+ ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
+ *aPlusOne = a + 1;
+ return NO_ERROR;
+ }
+ status_t increment(uint32_t a, uint32_t* aPlusOne) const override {
+ ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
+ *aPlusOne = a + 1;
+ return NO_ERROR;
+ }
+ status_t increment(int32_t a, int32_t* aPlusOne, int32_t b, int32_t* bPlusOne) const override {
+ ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
+ *aPlusOne = a + 1;
+ *bPlusOne = b + 1;
+ return NO_ERROR;
+ }
+
+ // BnInterface
+ status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply,
+ uint32_t /*flags*/) override {
+ EXPECT_GE(code, IBinder::FIRST_CALL_TRANSACTION);
+ EXPECT_LT(code, static_cast<uint32_t>(Tag::Last));
+ ISafeInterfaceTest::Tag tag = static_cast<ISafeInterfaceTest::Tag>(code);
+ switch (tag) {
+ case ISafeInterfaceTest::Tag::SetDeathToken: {
+ return callLocal(data, reply, &ISafeInterfaceTest::setDeathToken);
+ }
+ case ISafeInterfaceTest::Tag::ReturnsNoMemory: {
+ return callLocal(data, reply, &ISafeInterfaceTest::returnsNoMemory);
+ }
+ case ISafeInterfaceTest::Tag::LogicalNot: {
+ return callLocal(data, reply, &ISafeInterfaceTest::logicalNot);
+ }
+ case ISafeInterfaceTest::Tag::IncrementLightFlattenable: {
+ using Signature =
+ status_t (ISafeInterfaceTest::*)(const TestLightFlattenable& a,
+ TestLightFlattenable* aPlusOne) const;
+ return callLocal<Signature>(data, reply, &ISafeInterfaceTest::increment);
+ }
+ case ISafeInterfaceTest::Tag::IncrementNoCopyNoMove: {
+ using Signature = status_t (ISafeInterfaceTest::*)(const NoCopyNoMove& a,
+ NoCopyNoMove* aPlusOne) const;
+ return callLocal<Signature>(data, reply, &ISafeInterfaceTest::increment);
+ }
+ case ISafeInterfaceTest::Tag::ToUpper: {
+ return callLocal(data, reply, &ISafeInterfaceTest::toUpper);
+ }
+ case ISafeInterfaceTest::Tag::CallMeBack: {
+ return callLocalAsync(data, reply, &ISafeInterfaceTest::callMeBack);
+ }
+ case ISafeInterfaceTest::Tag::IncrementInt32: {
+ using Signature = status_t (ISafeInterfaceTest::*)(int32_t, int32_t*) const;
+ return callLocal<Signature>(data, reply, &ISafeInterfaceTest::increment);
+ }
+ case ISafeInterfaceTest::Tag::IncrementUint32: {
+ using Signature = status_t (ISafeInterfaceTest::*)(uint32_t, uint32_t*) const;
+ return callLocal<Signature>(data, reply, &ISafeInterfaceTest::increment);
+ }
+ case ISafeInterfaceTest::Tag::IncrementTwo: {
+ using Signature = status_t (ISafeInterfaceTest::*)(int32_t, int32_t*, int32_t,
+ int32_t*) const;
+ return callLocal<Signature>(data, reply, &ISafeInterfaceTest::increment);
+ }
+ case ISafeInterfaceTest::Tag::Last:
+ // Should not be possible because of the asserts at the beginning of the method
+ [&]() { FAIL(); }();
+ return UNKNOWN_ERROR;
+ }
+ }
+
+private:
+ static constexpr const char* getLogTag() { return "BnSafeInterfaceTest"; }
+};
+
+class SafeInterfaceTest : public ::testing::Test {
+public:
+ SafeInterfaceTest() : mSafeInterfaceTest(getRemoteService()) {
+ ProcessState::self()->startThreadPool();
+ }
+ ~SafeInterfaceTest() override = default;
+
+protected:
+ sp<ISafeInterfaceTest> mSafeInterfaceTest;
+
+private:
+ static constexpr const char* getLogTag() { return "SafeInterfaceTest"; }
+
+ sp<ISafeInterfaceTest> getRemoteService() {
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wexit-time-destructors"
+ static std::mutex sMutex;
+ static sp<ISafeInterfaceTest> sService;
+ static sp<IBinder> sDeathToken = new BBinder;
+#pragma clang diagnostic pop
+
+ std::unique_lock<decltype(sMutex)> lock;
+ if (sService == nullptr) {
+ ALOG(LOG_INFO, getLogTag(), "Forking remote process");
+ pid_t forkPid = fork();
+ EXPECT_NE(forkPid, -1);
+
+ const String16 serviceName("SafeInterfaceTest");
+
+ if (forkPid == 0) {
+ ALOG(LOG_INFO, getLogTag(), "Remote process checking in");
+ sp<ISafeInterfaceTest> nativeService = new BnSafeInterfaceTest;
+ defaultServiceManager()->addService(serviceName,
+ IInterface::asBinder(nativeService));
+ ProcessState::self()->startThreadPool();
+ IPCThreadState::self()->joinThreadPool();
+ // We shouldn't get to this point
+ [&]() { FAIL(); }();
+ }
+
+ sp<IBinder> binder = defaultServiceManager()->getService(serviceName);
+ sService = interface_cast<ISafeInterfaceTest>(binder);
+ EXPECT_TRUE(sService != nullptr);
+
+ sService->setDeathToken(sDeathToken);
+ }
+
+ return sService;
+ }
+};
+
+TEST_F(SafeInterfaceTest, TestReturnsNoMemory) {
+ status_t result = mSafeInterfaceTest->returnsNoMemory();
+ ASSERT_EQ(NO_MEMORY, result);
+}
+
+TEST_F(SafeInterfaceTest, TestLogicalNot) {
+ const bool a = true;
+ bool notA = true;
+ status_t result = mSafeInterfaceTest->logicalNot(a, ¬A);
+ ASSERT_EQ(NO_ERROR, result);
+ ASSERT_EQ(!a, notA);
+ // Test both since we don't want to accidentally catch a default false somewhere
+ const bool b = false;
+ bool notB = false;
+ result = mSafeInterfaceTest->logicalNot(b, ¬B);
+ ASSERT_EQ(NO_ERROR, result);
+ ASSERT_EQ(!b, notB);
+}
+
+TEST_F(SafeInterfaceTest, TestIncrementLightFlattenable) {
+ const TestLightFlattenable a{1};
+ TestLightFlattenable aPlusOne{0};
+ status_t result = mSafeInterfaceTest->increment(a, &aPlusOne);
+ ASSERT_EQ(NO_ERROR, result);
+ ASSERT_EQ(a.value + 1, aPlusOne.value);
+}
+
+TEST_F(SafeInterfaceTest, TestIncrementNoCopyNoMove) {
+ const NoCopyNoMove a{1};
+ NoCopyNoMove aPlusOne{0};
+ status_t result = mSafeInterfaceTest->increment(a, &aPlusOne);
+ ASSERT_EQ(NO_ERROR, result);
+ ASSERT_EQ(a.getValue() + 1, aPlusOne.getValue());
+}
+
+TEST_F(SafeInterfaceTest, TestToUpper) {
+ const String8 str{"Hello, world!"};
+ String8 upperStr;
+ status_t result = mSafeInterfaceTest->toUpper(str, &upperStr);
+ ASSERT_EQ(NO_ERROR, result);
+ ASSERT_TRUE(upperStr == String8{"HELLO, WORLD!"});
+}
+
+TEST_F(SafeInterfaceTest, TestCallMeBack) {
+ class CallbackReceiver : public BnCallback {
+ public:
+ void onCallback(int32_t aPlusOne) override {
+ ALOG(LOG_INFO, "CallbackReceiver", "%s", __PRETTY_FUNCTION__);
+ std::unique_lock<decltype(mMutex)> lock(mMutex);
+ mValue = aPlusOne;
+ mCondition.notify_one();
+ }
+
+ std::optional<int32_t> waitForCallback() {
+ std::unique_lock<decltype(mMutex)> lock(mMutex);
+ bool success =
+ mCondition.wait_for(lock, 100ms, [&]() { return static_cast<bool>(mValue); });
+ return success ? mValue : std::nullopt;
+ }
+
+ private:
+ std::mutex mMutex;
+ std::condition_variable mCondition;
+ std::optional<int32_t> mValue;
+ };
+
+ sp<CallbackReceiver> receiver = new CallbackReceiver;
+ const int32_t a = 1;
+ mSafeInterfaceTest->callMeBack(receiver, a);
+ auto result = receiver->waitForCallback();
+ ASSERT_TRUE(result);
+ ASSERT_EQ(a + 1, *result);
+}
+
+TEST_F(SafeInterfaceTest, TestIncrementInt32) {
+ const int32_t a = 1;
+ int32_t aPlusOne = 0;
+ status_t result = mSafeInterfaceTest->increment(a, &aPlusOne);
+ ASSERT_EQ(NO_ERROR, result);
+ ASSERT_EQ(a + 1, aPlusOne);
+}
+
+TEST_F(SafeInterfaceTest, TestIncrementUint32) {
+ const uint32_t a = 1;
+ uint32_t aPlusOne = 0;
+ status_t result = mSafeInterfaceTest->increment(a, &aPlusOne);
+ ASSERT_EQ(NO_ERROR, result);
+ ASSERT_EQ(a + 1, aPlusOne);
+}
+
+TEST_F(SafeInterfaceTest, TestIncrementTwo) {
+ const int32_t a = 1;
+ int32_t aPlusOne = 0;
+ const int32_t b = 2;
+ int32_t bPlusOne = 0;
+ status_t result = mSafeInterfaceTest->increment(1, &aPlusOne, 2, &bPlusOne);
+ ASSERT_EQ(NO_ERROR, result);
+ ASSERT_EQ(a + 1, aPlusOne);
+ ASSERT_EQ(b + 1, bPlusOne);
+}
+
+} // namespace tests
+} // namespace android
diff --git a/libs/binder/tests/schd-dbg.cpp b/libs/binder/tests/schd-dbg.cpp
new file mode 100644
index 0000000..fe9e05a
--- /dev/null
+++ b/libs/binder/tests/schd-dbg.cpp
@@ -0,0 +1,483 @@
+#include <binder/Binder.h>
+#include <binder/IBinder.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <string>
+
+#include <iomanip>
+#include <iostream>
+#include <tuple>
+#include <vector>
+
+#include <pthread.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <fstream>
+
+using namespace std;
+using namespace android;
+
+enum BinderWorkerServiceCode {
+ BINDER_NOP = IBinder::FIRST_CALL_TRANSACTION,
+};
+
+#define ASSERT(cond) \
+ do { \
+ if (!(cond)) { \
+ cerr << __func__ << ":" << __LINE__ << " condition:" << #cond \
+ << " failed\n" \
+ << endl; \
+ exit(EXIT_FAILURE); \
+ } \
+ } while (0)
+
+vector<sp<IBinder> > workers;
+
+// the ratio that the service is synced on the same cpu beyond
+// GOOD_SYNC_MIN is considered as good
+#define GOOD_SYNC_MIN (0.6)
+
+#define DUMP_PRICISION 3
+
+string trace_path = "/sys/kernel/debug/tracing";
+
+// the default value
+int no_process = 2;
+int iterations = 100;
+int payload_size = 16;
+int no_inherent = 0;
+int no_sync = 0;
+int verbose = 0;
+int trace;
+
+bool traceIsOn() {
+ fstream file;
+ file.open(trace_path + "/tracing_on", ios::in);
+ char on;
+ file >> on;
+ file.close();
+ return on == '1';
+}
+
+void traceStop() {
+ ofstream file;
+ file.open(trace_path + "/tracing_on", ios::out | ios::trunc);
+ file << '0' << endl;
+ file.close();
+}
+
+// the deadline latency that we are interested in
+uint64_t deadline_us = 2500;
+
+int thread_pri() {
+ struct sched_param param;
+ int policy;
+ ASSERT(!pthread_getschedparam(pthread_self(), &policy, ¶m));
+ return param.sched_priority;
+}
+
+void thread_dump(const char* prefix) {
+ struct sched_param param;
+ int policy;
+ if (!verbose) return;
+ cout << "--------------------------------------------------" << endl;
+ cout << setw(12) << left << prefix << " pid: " << getpid()
+ << " tid: " << gettid() << " cpu: " << sched_getcpu() << endl;
+ ASSERT(!pthread_getschedparam(pthread_self(), &policy, ¶m));
+ string s = (policy == SCHED_OTHER)
+ ? "SCHED_OTHER"
+ : (policy == SCHED_FIFO)
+ ? "SCHED_FIFO"
+ : (policy == SCHED_RR) ? "SCHED_RR" : "???";
+ cout << setw(12) << left << s << param.sched_priority << endl;
+ return;
+}
+
+class BinderWorkerService : public BBinder {
+ public:
+ BinderWorkerService() {
+ }
+ ~BinderWorkerService() {
+ }
+ virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply,
+ uint32_t flags = 0) {
+ (void)flags;
+ (void)data;
+ (void)reply;
+ switch (code) {
+ // The transaction format is like
+ //
+ // data[in]: int32: caller priority
+ // int32: caller cpu
+ //
+ // reply[out]: int32: 1 if caller's priority != callee's priority
+ // int32: 1 if caller's cpu != callee's cpu
+ //
+ // note the caller cpu read here is not always correct
+ // there're still chances that the caller got switched out
+ // right after it read the cpu number and still before the transaction.
+ case BINDER_NOP: {
+ thread_dump("binder");
+ int priority = thread_pri();
+ int priority_caller = data.readInt32();
+ int h = 0, s = 0;
+ if (priority_caller != priority) {
+ h++;
+ if (verbose) {
+ cout << "err priority_caller:" << priority_caller
+ << ", priority:" << priority << endl;
+ }
+ }
+ if (priority == sched_get_priority_max(SCHED_FIFO)) {
+ int cpu = sched_getcpu();
+ int cpu_caller = data.readInt32();
+ if (cpu != cpu_caller) {
+ s++;
+ }
+ }
+ reply->writeInt32(h);
+ reply->writeInt32(s);
+ return NO_ERROR;
+ }
+ default:
+ return UNKNOWN_TRANSACTION;
+ };
+ }
+};
+
+class Pipe {
+ int m_readFd;
+ int m_writeFd;
+ Pipe(int readFd, int writeFd) : m_readFd{readFd}, m_writeFd{writeFd} {
+ }
+ Pipe(const Pipe&) = delete;
+ Pipe& operator=(const Pipe&) = delete;
+ Pipe& operator=(const Pipe&&) = delete;
+
+ public:
+ Pipe(Pipe&& rval) noexcept {
+ m_readFd = rval.m_readFd;
+ m_writeFd = rval.m_writeFd;
+ rval.m_readFd = 0;
+ rval.m_writeFd = 0;
+ }
+ ~Pipe() {
+ if (m_readFd) close(m_readFd);
+ if (m_writeFd) close(m_writeFd);
+ }
+ void signal() {
+ bool val = true;
+ int error = write(m_writeFd, &val, sizeof(val));
+ ASSERT(error >= 0);
+ };
+ void wait() {
+ bool val = false;
+ int error = read(m_readFd, &val, sizeof(val));
+ ASSERT(error >= 0);
+ }
+ template <typename T>
+ void send(const T& v) {
+ int error = write(m_writeFd, &v, sizeof(T));
+ ASSERT(error >= 0);
+ }
+ template <typename T>
+ void recv(T& v) {
+ int error = read(m_readFd, &v, sizeof(T));
+ ASSERT(error >= 0);
+ }
+ static tuple<Pipe, Pipe> createPipePair() {
+ int a[2];
+ int b[2];
+
+ int error1 = pipe(a);
+ int error2 = pipe(b);
+ ASSERT(error1 >= 0);
+ ASSERT(error2 >= 0);
+
+ return make_tuple(Pipe(a[0], b[1]), Pipe(b[0], a[1]));
+ }
+};
+
+typedef chrono::time_point<chrono::high_resolution_clock> Tick;
+
+static inline Tick tickNow() {
+ return chrono::high_resolution_clock::now();
+}
+
+static inline uint64_t tickNano(Tick& sta, Tick& end) {
+ return uint64_t(chrono::duration_cast<chrono::nanoseconds>(end - sta).count());
+}
+
+struct Results {
+ uint64_t m_best = 0xffffffffffffffffULL;
+ uint64_t m_worst = 0;
+ uint64_t m_transactions = 0;
+ uint64_t m_total_time = 0;
+ uint64_t m_miss = 0;
+ bool tracing;
+ Results(bool _tracing) : tracing(_tracing) {
+ }
+ inline bool miss_deadline(uint64_t nano) {
+ return nano > deadline_us * 1000;
+ }
+ void add_time(uint64_t nano) {
+ m_best = min(nano, m_best);
+ m_worst = max(nano, m_worst);
+ m_transactions += 1;
+ m_total_time += nano;
+ if (miss_deadline(nano)) m_miss++;
+ if (miss_deadline(nano) && tracing) {
+ // There might be multiple process pair running the test concurrently
+ // each may execute following statements and only the first one actually
+ // stop the trace and any traceStop() afterthen has no effect.
+ traceStop();
+ cout << endl;
+ cout << "deadline triggered: halt & stop trace" << endl;
+ cout << "log:" + trace_path + "/trace" << endl;
+ cout << endl;
+ exit(1);
+ }
+ }
+ void dump() {
+ double best = (double)m_best / 1.0E6;
+ double worst = (double)m_worst / 1.0E6;
+ double average = (double)m_total_time / m_transactions / 1.0E6;
+ // FIXME: libjson?
+ cout << std::setprecision(DUMP_PRICISION) << "{ \"avg\":" << setw(5) << left
+ << average << ", \"wst\":" << setw(5) << left << worst
+ << ", \"bst\":" << setw(5) << left << best << ", \"miss\":" << setw(5)
+ << left << m_miss << ", \"meetR\":" << setw(3) << left
+ << (1.0 - (double)m_miss / m_transactions) << "}";
+ }
+};
+
+String16 generateServiceName(int num) {
+ char num_str[32];
+ snprintf(num_str, sizeof(num_str), "%d", num);
+ String16 serviceName = String16("binderWorker") + String16(num_str);
+ return serviceName;
+}
+
+static void parcel_fill(Parcel& data, int sz, int priority, int cpu) {
+ ASSERT(sz >= (int)sizeof(uint32_t) * 2);
+ data.writeInt32(priority);
+ data.writeInt32(cpu);
+ sz -= sizeof(uint32_t);
+ while (sz > (int)sizeof(uint32_t)) {
+ data.writeInt32(0);
+ sz -= sizeof(uint32_t);
+ }
+}
+
+static void* thread_start(void* p) {
+ Results* results_fifo = (Results*)p;
+ Parcel data, reply;
+ Tick sta, end;
+
+ parcel_fill(data, payload_size, thread_pri(), sched_getcpu());
+ thread_dump("fifo-caller");
+
+ sta = tickNow();
+ status_t ret = workers[0]->transact(BINDER_NOP, data, &reply);
+ end = tickNow();
+ results_fifo->add_time(tickNano(sta, end));
+
+ no_inherent += reply.readInt32();
+ no_sync += reply.readInt32();
+ return 0;
+}
+
+// create a fifo thread to transact and wait it to finished
+static void thread_transaction(Results* results_fifo) {
+ void* dummy;
+ pthread_t thread;
+ pthread_attr_t attr;
+ struct sched_param param;
+ ASSERT(!pthread_attr_init(&attr));
+ ASSERT(!pthread_attr_setschedpolicy(&attr, SCHED_FIFO));
+ param.sched_priority = sched_get_priority_max(SCHED_FIFO);
+ ASSERT(!pthread_attr_setschedparam(&attr, ¶m));
+ ASSERT(!pthread_create(&thread, &attr, &thread_start, results_fifo));
+ ASSERT(!pthread_join(thread, &dummy));
+}
+
+#define is_client(_num) ((_num) >= (no_process / 2))
+
+void worker_fx(int num, int no_process, int iterations, int payload_size,
+ Pipe p) {
+ int dummy;
+ Results results_other(false), results_fifo(trace);
+
+ // Create BinderWorkerService and for go.
+ ProcessState::self()->startThreadPool();
+ sp<IServiceManager> serviceMgr = defaultServiceManager();
+ sp<BinderWorkerService> service = new BinderWorkerService;
+ serviceMgr->addService(generateServiceName(num), service);
+ p.signal();
+ p.wait();
+
+ // If client/server pairs, then half the workers are
+ // servers and half are clients
+ int server_count = no_process / 2;
+
+ for (int i = 0; i < server_count; i++) {
+ // self service is in-process so just skip
+ if (num == i) continue;
+ workers.push_back(serviceMgr->getService(generateServiceName(i)));
+ }
+
+ // Client for each pair iterates here
+ // each iterations contains exatcly 2 transactions
+ for (int i = 0; is_client(num) && i < iterations; i++) {
+ Parcel data, reply;
+ Tick sta, end;
+ // the target is paired to make it easier to diagnose
+ int target = num % server_count;
+
+ // 1. transaction by fifo thread
+ thread_transaction(&results_fifo);
+ parcel_fill(data, payload_size, thread_pri(), sched_getcpu());
+ thread_dump("other-caller");
+
+ // 2. transaction by other thread
+ sta = tickNow();
+ ASSERT(NO_ERROR == workers[target]->transact(BINDER_NOP, data, &reply));
+ end = tickNow();
+ results_other.add_time(tickNano(sta, end));
+
+ no_inherent += reply.readInt32();
+ no_sync += reply.readInt32();
+ }
+ // Signal completion to master and wait.
+ p.signal();
+ p.wait();
+
+ p.send(&dummy);
+ p.wait();
+ // Client for each pair dump here
+ if (is_client(num)) {
+ int no_trans = iterations * 2;
+ double sync_ratio = (1.0 - (double)no_sync / no_trans);
+ // FIXME: libjson?
+ cout << "\"P" << (num - server_count) << "\":{\"SYNC\":\""
+ << ((sync_ratio > GOOD_SYNC_MIN) ? "GOOD" : "POOR") << "\","
+ << "\"S\":" << (no_trans - no_sync) << ",\"I\":" << no_trans << ","
+ << "\"R\":" << sync_ratio << "," << endl;
+
+ cout << " \"other_ms\":";
+ results_other.dump();
+ cout << "," << endl;
+ cout << " \"fifo_ms\": ";
+ results_fifo.dump();
+ cout << endl;
+ cout << "}," << endl;
+ }
+ exit(no_inherent);
+}
+
+Pipe make_process(int num, int iterations, int no_process, int payload_size) {
+ auto pipe_pair = Pipe::createPipePair();
+ pid_t pid = fork();
+ if (pid) {
+ // parent
+ return move(get<0>(pipe_pair));
+ } else {
+ // child
+ thread_dump(is_client(num) ? "client" : "server");
+ worker_fx(num, no_process, iterations, payload_size,
+ move(get<1>(pipe_pair)));
+ // never get here
+ return move(get<0>(pipe_pair));
+ }
+}
+
+void wait_all(vector<Pipe>& v) {
+ for (size_t i = 0; i < v.size(); i++) {
+ v[i].wait();
+ }
+}
+
+void signal_all(vector<Pipe>& v) {
+ for (size_t i = 0; i < v.size(); i++) {
+ v[i].signal();
+ }
+}
+
+// This test is modified from binderThroughputTest.cpp
+int main(int argc, char** argv) {
+ for (int i = 1; i < argc; i++) {
+ if (string(argv[i]) == "-i") {
+ iterations = atoi(argv[i + 1]);
+ i++;
+ continue;
+ }
+ if (string(argv[i]) == "-pair") {
+ no_process = 2 * atoi(argv[i + 1]);
+ i++;
+ continue;
+ }
+ if (string(argv[i]) == "-deadline_us") {
+ deadline_us = atoi(argv[i + 1]);
+ i++;
+ continue;
+ }
+ if (string(argv[i]) == "-v") {
+ verbose = 1;
+ }
+ // The -trace argument is used like that:
+ //
+ // First start trace with atrace command as usual
+ // >atrace --async_start sched freq
+ //
+ // then use schd-dbg with -trace arguments
+ //./schd-dbg -trace -deadline_us 2500
+ //
+ // This makes schd-dbg to stop trace once it detects a transaction
+ // duration over the deadline. By writing '0' to
+ // /sys/kernel/debug/tracing and halt the process. The tracelog is
+ // then available on /sys/kernel/debug/trace
+ if (string(argv[i]) == "-trace") {
+ trace = 1;
+ }
+ }
+ if (trace && !traceIsOn()) {
+ cout << "trace is not running" << endl;
+ cout << "check " << trace_path + "/tracing_on" << endl;
+ cout << "use atrace --async_start first" << endl;
+ exit(-1);
+ }
+ vector<Pipe> pipes;
+ thread_dump("main");
+ // FIXME: libjson?
+ cout << "{" << endl;
+ cout << "\"cfg\":{\"pair\":" << (no_process / 2)
+ << ",\"iterations\":" << iterations << ",\"deadline_us\":" << deadline_us
+ << "}," << endl;
+
+ // the main process fork 2 processes for each pairs
+ // 1 server + 1 client
+ // each has a pipe to communicate with
+ for (int i = 0; i < no_process; i++) {
+ pipes.push_back(make_process(i, iterations, no_process, payload_size));
+ }
+ wait_all(pipes);
+ signal_all(pipes);
+ wait_all(pipes);
+ signal_all(pipes);
+ for (int i = 0; i < no_process; i++) {
+ int status;
+ pipes[i].signal();
+ wait(&status);
+ // the exit status is number of transactions without priority inheritance
+ // detected in the child process
+ no_inherent += status;
+ }
+ // FIXME: libjson?
+ cout << "\"inheritance\": " << (no_inherent == 0 ? "\"PASS\"" : "\"FAIL\"")
+ << endl;
+ cout << "}" << endl;
+ return -no_inherent;
+}
diff --git a/libs/gui/ConsumerBase.cpp b/libs/gui/ConsumerBase.cpp
index 8acdfed..d4e4dc3 100644
--- a/libs/gui/ConsumerBase.cpp
+++ b/libs/gui/ConsumerBase.cpp
@@ -287,6 +287,9 @@
}
if (item->mGraphicBuffer != NULL) {
+ if (mSlots[item->mSlot].mGraphicBuffer != NULL) {
+ freeBufferLocked(item->mSlot);
+ }
mSlots[item->mSlot].mGraphicBuffer = item->mGraphicBuffer;
}
diff --git a/libs/gui/ISurfaceComposerClient.cpp b/libs/gui/ISurfaceComposerClient.cpp
index db8a517..2d2146b 100644
--- a/libs/gui/ISurfaceComposerClient.cpp
+++ b/libs/gui/ISurfaceComposerClient.cpp
@@ -17,116 +17,56 @@
// tag as surfaceflinger
#define LOG_TAG "SurfaceFlinger"
-#include <stdio.h>
#include <stdint.h>
+#include <stdio.h>
#include <sys/types.h>
-#include <binder/Parcel.h>
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
+#include <binder/Parcel.h>
+#include <binder/SafeInterface.h>
+#include <ui/FrameStats.h>
#include <ui/Point.h>
#include <ui/Rect.h>
#include <gui/IGraphicBufferProducer.h>
#include <gui/ISurfaceComposerClient.h>
-#include <private/gui/LayerState.h>
-
-// ---------------------------------------------------------------------------
namespace android {
-enum {
- CREATE_SURFACE = IBinder::FIRST_CALL_TRANSACTION,
- DESTROY_SURFACE,
- CLEAR_LAYER_FRAME_STATS,
- GET_LAYER_FRAME_STATS,
- GET_TRANSFORM_TO_DISPLAY_INVERSE
-};
-
-class BpSurfaceComposerClient : public BpInterface<ISurfaceComposerClient>
-{
+class BpSurfaceComposerClient : public SafeBpInterface<ISurfaceComposerClient> {
public:
explicit BpSurfaceComposerClient(const sp<IBinder>& impl)
- : BpInterface<ISurfaceComposerClient>(impl) {
+ : SafeBpInterface<ISurfaceComposerClient>(impl, "BpSurfaceComposerClient") {}
+
+ ~BpSurfaceComposerClient() override;
+
+ status_t createSurface(const String8& name, uint32_t width, uint32_t height, PixelFormat format,
+ uint32_t flags, const sp<IBinder>& parent, uint32_t windowType,
+ uint32_t ownerUid, sp<IBinder>* handle,
+ sp<IGraphicBufferProducer>* gbp) override {
+ return callRemote<decltype(&ISurfaceComposerClient::createSurface)>(Tag::CreateSurface,
+ name, width, height,
+ format, flags, parent,
+ windowType, ownerUid,
+ handle, gbp);
}
- virtual ~BpSurfaceComposerClient();
-
- virtual status_t createSurface(const String8& name, uint32_t width,
- uint32_t height, PixelFormat format, uint32_t flags,
- const sp<IBinder>& parent, uint32_t windowType, uint32_t ownerUid,
- sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp) {
- Parcel data, reply;
- data.writeInterfaceToken(ISurfaceComposerClient::getInterfaceDescriptor());
- data.writeString8(name);
- data.writeUint32(width);
- data.writeUint32(height);
- data.writeInt32(static_cast<int32_t>(format));
- data.writeUint32(flags);
- data.writeUint32(windowType);
- data.writeUint32(ownerUid);
- if (parent != nullptr) {
- data.writeStrongBinder(parent);
- }
- remote()->transact(CREATE_SURFACE, data, &reply);
- *handle = reply.readStrongBinder();
- *gbp = interface_cast<IGraphicBufferProducer>(reply.readStrongBinder());
- return reply.readInt32();
+ status_t destroySurface(const sp<IBinder>& handle) override {
+ return callRemote<decltype(&ISurfaceComposerClient::destroySurface)>(Tag::DestroySurface,
+ handle);
}
- virtual status_t destroySurface(const sp<IBinder>& handle) {
- Parcel data, reply;
- data.writeInterfaceToken(ISurfaceComposerClient::getInterfaceDescriptor());
- data.writeStrongBinder(handle);
- remote()->transact(DESTROY_SURFACE, data, &reply);
- return reply.readInt32();
+ status_t clearLayerFrameStats(const sp<IBinder>& handle) const override {
+ return callRemote<decltype(
+ &ISurfaceComposerClient::clearLayerFrameStats)>(Tag::ClearLayerFrameStats, handle);
}
- virtual status_t clearLayerFrameStats(const sp<IBinder>& handle) const {
- Parcel data, reply;
- data.writeInterfaceToken(ISurfaceComposerClient::getInterfaceDescriptor());
- data.writeStrongBinder(handle);
- remote()->transact(CLEAR_LAYER_FRAME_STATS, data, &reply);
- return reply.readInt32();
- }
-
- virtual status_t getLayerFrameStats(const sp<IBinder>& handle, FrameStats* outStats) const {
- Parcel data, reply;
- data.writeInterfaceToken(ISurfaceComposerClient::getInterfaceDescriptor());
- data.writeStrongBinder(handle);
- remote()->transact(GET_LAYER_FRAME_STATS, data, &reply);
- reply.read(*outStats);
- return reply.readInt32();
- }
-
- virtual status_t getTransformToDisplayInverse(const sp<IBinder>& handle,
- bool* outTransformToDisplayInverse) const {
- Parcel data, reply;
- status_t result =
- data.writeInterfaceToken(ISurfaceComposerClient::getInterfaceDescriptor());
- if (result != NO_ERROR) {
- return result;
- }
- result = data.writeStrongBinder(handle);
- if (result != NO_ERROR) {
- return result;
- }
- result = remote()->transact(GET_TRANSFORM_TO_DISPLAY_INVERSE, data, &reply);
- if (result != NO_ERROR) {
- return result;
- }
- int transformInverse;
- result = reply.readInt32(&transformInverse);
- if (result != NO_ERROR) {
- return result;
- }
- *outTransformToDisplayInverse = transformInverse != 0 ? true : false;
- status_t result2 = reply.readInt32(&result);
- if (result2 != NO_ERROR) {
- return result2;
- }
- return result;
+ status_t getLayerFrameStats(const sp<IBinder>& handle, FrameStats* outStats) const override {
+ return callRemote<decltype(
+ &ISurfaceComposerClient::getLayerFrameStats)>(Tag::GetLayerFrameStats, handle,
+ outStats);
}
};
@@ -138,75 +78,29 @@
// ----------------------------------------------------------------------
-status_t BnSurfaceComposerClient::onTransact(
- uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
-{
- switch(code) {
- case CREATE_SURFACE: {
- CHECK_INTERFACE(ISurfaceComposerClient, data, reply);
- String8 name = data.readString8();
- uint32_t width = data.readUint32();
- uint32_t height = data.readUint32();
- PixelFormat format = static_cast<PixelFormat>(data.readInt32());
- uint32_t createFlags = data.readUint32();
- uint32_t windowType = data.readUint32();
- uint32_t ownerUid = data.readUint32();
- sp<IBinder> parent = nullptr;
- if (data.dataAvail() > 0) {
- parent = data.readStrongBinder();
- }
- sp<IBinder> handle;
- sp<IGraphicBufferProducer> gbp;
- status_t result = createSurface(name, width, height, format,
- createFlags, parent, windowType, ownerUid, &handle, &gbp);
- reply->writeStrongBinder(handle);
- reply->writeStrongBinder(IInterface::asBinder(gbp));
- reply->writeInt32(result);
- return NO_ERROR;
+status_t BnSurfaceComposerClient::onTransact(uint32_t code, const Parcel& data, Parcel* reply,
+ uint32_t flags) {
+ if (code < IBinder::FIRST_CALL_TRANSACTION || code >= static_cast<uint32_t>(Tag::Last)) {
+ return BBinder::onTransact(code, data, reply, flags);
+ }
+ auto tag = static_cast<Tag>(code);
+ switch (tag) {
+ case Tag::CreateSurface: {
+ return callLocal(data, reply, &ISurfaceComposerClient::createSurface);
}
- case DESTROY_SURFACE: {
- CHECK_INTERFACE(ISurfaceComposerClient, data, reply);
- reply->writeInt32(destroySurface( data.readStrongBinder() ) );
- return NO_ERROR;
+ case Tag::DestroySurface: {
+ return callLocal(data, reply, &ISurfaceComposerClient::destroySurface);
}
- case CLEAR_LAYER_FRAME_STATS: {
- CHECK_INTERFACE(ISurfaceComposerClient, data, reply);
- sp<IBinder> handle = data.readStrongBinder();
- status_t result = clearLayerFrameStats(handle);
- reply->writeInt32(result);
- return NO_ERROR;
+ case Tag::ClearLayerFrameStats: {
+ return callLocal(data, reply, &ISurfaceComposerClient::clearLayerFrameStats);
}
- case GET_LAYER_FRAME_STATS: {
- CHECK_INTERFACE(ISurfaceComposerClient, data, reply);
- sp<IBinder> handle = data.readStrongBinder();
- FrameStats stats;
- status_t result = getLayerFrameStats(handle, &stats);
- reply->write(stats);
- reply->writeInt32(result);
- return NO_ERROR;
+ case Tag::GetLayerFrameStats: {
+ return callLocal(data, reply, &ISurfaceComposerClient::getLayerFrameStats);
}
- case GET_TRANSFORM_TO_DISPLAY_INVERSE: {
- CHECK_INTERFACE(ISurfaceComposerClient, data, reply);
- sp<IBinder> handle;
- status_t result = data.readStrongBinder(&handle);
- if (result != NO_ERROR) {
- return result;
- }
- bool transformInverse = false;
- result = getTransformToDisplayInverse(handle, &transformInverse);
- if (result != NO_ERROR) {
- return result;
- }
- result = reply->writeInt32(transformInverse ? 1 : 0);
- if (result != NO_ERROR) {
- return result;
- }
- result = reply->writeInt32(NO_ERROR);
- return result;
- }
- default:
+ case Tag::Last:
+ // Should not be possible because of the check at the beginning of the method
return BBinder::onTransact(code, data, reply, flags);
}
}
-}; // namespace android
+} // namespace android
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 088933a..56c7586 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -711,14 +711,6 @@
return mClient->getLayerFrameStats(token, outStats);
}
-status_t SurfaceComposerClient::getTransformToDisplayInverse(const sp<IBinder>& token,
- bool* outTransformToDisplayInverse) const {
- if (mStatus != NO_ERROR) {
- return mStatus;
- }
- return mClient->getTransformToDisplayInverse(token, outTransformToDisplayInverse);
-}
-
inline Composer& SurfaceComposerClient::getComposer() {
return mComposer;
}
diff --git a/libs/gui/SurfaceControl.cpp b/libs/gui/SurfaceControl.cpp
index 1e69379..7a68f11 100644
--- a/libs/gui/SurfaceControl.cpp
+++ b/libs/gui/SurfaceControl.cpp
@@ -209,13 +209,6 @@
return client->getLayerFrameStats(mHandle, outStats);
}
-status_t SurfaceControl::getTransformToDisplayInverse(bool* outTransformToDisplayInverse) const {
- status_t err = validate();
- if (err < 0) return err;
- const sp<SurfaceComposerClient>& client(mClient);
- return client->getTransformToDisplayInverse(mHandle, outTransformToDisplayInverse);
-}
-
status_t SurfaceControl::validate() const
{
if (mHandle==0 || mClient==0) {
diff --git a/libs/gui/tests/BufferQueue_test.cpp b/libs/gui/tests/BufferQueue_test.cpp
index 907e0493..55e6fbf 100644
--- a/libs/gui/tests/BufferQueue_test.cpp
+++ b/libs/gui/tests/BufferQueue_test.cpp
@@ -98,7 +98,11 @@
// XXX: Tests that fork a process to hold the BufferQueue must run before tests
// that use a local BufferQueue, or else Binder will get unhappy
-TEST_F(BufferQueueTest, BufferQueueInAnotherProcess) {
+//
+// In one instance this was a crash in the createBufferQueue where the
+// binder call to create a buffer allocator apparently got garbage back.
+// See b/36592665.
+TEST_F(BufferQueueTest, DISABLED_BufferQueueInAnotherProcess) {
const String16 PRODUCER_NAME = String16("BQTestProducer");
const String16 CONSUMER_NAME = String16("BQTestConsumer");
diff --git a/libs/hwc2on1adapter/HWC2On1Adapter.cpp b/libs/hwc2on1adapter/HWC2On1Adapter.cpp
index 03297ca..e35bfc9 100644
--- a/libs/hwc2on1adapter/HWC2On1Adapter.cpp
+++ b/libs/hwc2on1adapter/HWC2On1Adapter.cpp
@@ -538,6 +538,12 @@
for (auto& change : mChanges->getTypeChanges()) {
auto layerId = change.first;
auto type = change.second;
+ if (mDevice.mLayers.count(layerId) == 0) {
+ // This should never happen but somehow does.
+ ALOGW("Cannot accept change for unknown layer (%" PRIu64 ")",
+ layerId);
+ continue;
+ }
auto layer = mDevice.mLayers[layerId];
layer->setCompositionType(type);
}
diff --git a/libs/math/include/math/TMatHelpers.h b/libs/math/include/math/TMatHelpers.h
index 478e702..5cb725d 100644
--- a/libs/math/include/math/TMatHelpers.h
+++ b/libs/math/include/math/TMatHelpers.h
@@ -30,6 +30,8 @@
#include <utils/String8.h>
+#ifndef LIKELY
+#define LIKELY_DEFINED_LOCAL
#ifdef __cplusplus
# define LIKELY( exp ) (__builtin_expect( !!(exp), true ))
# define UNLIKELY( exp ) (__builtin_expect( !!(exp), false ))
@@ -37,6 +39,7 @@
# define LIKELY( exp ) (__builtin_expect( !!(exp), 1 ))
# define UNLIKELY( exp ) (__builtin_expect( !!(exp), 0 ))
#endif
+#endif
#define PURE __attribute__((pure))
@@ -631,7 +634,11 @@
} // namespace details
} // namespace android
+#ifdef LIKELY_DEFINED_LOCAL
+#undef LIKELY_DEFINED_LOCAL
#undef LIKELY
#undef UNLIKELY
+#endif //LIKELY_DEFINED_LOCAL
+
#undef PURE
#undef CONSTEXPR
diff --git a/libs/math/include/math/half.h b/libs/math/include/math/half.h
index ef1e45f..615b840 100644
--- a/libs/math/include/math/half.h
+++ b/libs/math/include/math/half.h
@@ -22,6 +22,7 @@
#include <type_traits>
#ifndef LIKELY
+#define LIKELY_DEFINED_LOCAL
#ifdef __cplusplus
# define LIKELY( exp ) (__builtin_expect( !!(exp), true ))
# define UNLIKELY( exp ) (__builtin_expect( !!(exp), false ))
@@ -202,6 +203,10 @@
} // namespace std
+#ifdef LIKELY_DEFINED_LOCAL
+#undef LIKELY_DEFINED_LOCAL
#undef LIKELY
#undef UNLIKELY
+#endif // LIKELY_DEFINED_LOCAL
+
#undef CONSTEXPR
diff --git a/libs/nativewindow/AHardwareBuffer.cpp b/libs/nativewindow/AHardwareBuffer.cpp
index 2d9fc93..1ed150b 100644
--- a/libs/nativewindow/AHardwareBuffer.cpp
+++ b/libs/nativewindow/AHardwareBuffer.cpp
@@ -82,11 +82,13 @@
}
void AHardwareBuffer_acquire(AHardwareBuffer* buffer) {
+ // incStrong/decStrong token must be the same, doesn't matter what it is
AHardwareBuffer_to_GraphicBuffer(buffer)->incStrong((void*)AHardwareBuffer_acquire);
}
void AHardwareBuffer_release(AHardwareBuffer* buffer) {
- AHardwareBuffer_to_GraphicBuffer(buffer)->decStrong((void*)AHardwareBuffer_release);
+ // incStrong/decStrong token must be the same, doesn't matter what it is
+ AHardwareBuffer_to_GraphicBuffer(buffer)->decStrong((void*)AHardwareBuffer_acquire);
}
void AHardwareBuffer_describe(const AHardwareBuffer* buffer,
@@ -136,8 +138,7 @@
return gBuffer->unlockAsync(fence);
}
-int AHardwareBuffer_sendHandleToUnixSocket(const AHardwareBuffer* buffer,
- int socketFd) {
+int AHardwareBuffer_sendHandleToUnixSocket(const AHardwareBuffer* buffer, int socketFd) {
if (!buffer) return BAD_VALUE;
const GraphicBuffer* gBuffer = AHardwareBuffer_to_GraphicBuffer(buffer);
@@ -188,8 +189,7 @@
return NO_ERROR;
}
-int AHardwareBuffer_recvHandleFromUnixSocket(int socketFd,
- AHardwareBuffer** outBuffer) {
+int AHardwareBuffer_recvHandleFromUnixSocket(int socketFd, AHardwareBuffer** outBuffer) {
if (!outBuffer) return BAD_VALUE;
char dataBuf[CMSG_SPACE(kDataBufferSize)];
diff --git a/libs/nativewindow/ANativeWindow.cpp b/libs/nativewindow/ANativeWindow.cpp
index a85d16e..c0c4ac0 100644
--- a/libs/nativewindow/ANativeWindow.cpp
+++ b/libs/nativewindow/ANativeWindow.cpp
@@ -17,36 +17,50 @@
#define LOG_TAG "ANativeWindow"
#include <android/native_window.h>
+
+#include <grallocusage/GrallocUsageConversion.h>
+// from nativewindow/includes/system/window.h
+// (not to be confused with the compatibility-only window.h from system/core/includes)
#include <system/window.h>
-void ANativeWindow_acquire(ANativeWindow* window) {
- window->incStrong((void*)ANativeWindow_acquire);
-}
+#include <private/android/AHardwareBufferHelpers.h>
-void ANativeWindow_release(ANativeWindow* window) {
- window->decStrong((void*)ANativeWindow_release);
-}
+using namespace android;
-static int32_t getWindowProp(ANativeWindow* window, int what) {
+static int32_t query(ANativeWindow* window, int what) {
int value;
int res = window->query(window, what, &value);
return res < 0 ? res : value;
}
+/**************************************************************************************************
+ * NDK
+ **************************************************************************************************/
+
+void ANativeWindow_acquire(ANativeWindow* window) {
+ // incStrong/decStrong token must be the same, doesn't matter what it is
+ window->incStrong((void*)ANativeWindow_acquire);
+}
+
+void ANativeWindow_release(ANativeWindow* window) {
+ // incStrong/decStrong token must be the same, doesn't matter what it is
+ window->decStrong((void*)ANativeWindow_acquire);
+}
+
int32_t ANativeWindow_getWidth(ANativeWindow* window) {
- return getWindowProp(window, NATIVE_WINDOW_WIDTH);
+ return query(window, NATIVE_WINDOW_WIDTH);
}
int32_t ANativeWindow_getHeight(ANativeWindow* window) {
- return getWindowProp(window, NATIVE_WINDOW_HEIGHT);
+ return query(window, NATIVE_WINDOW_HEIGHT);
}
int32_t ANativeWindow_getFormat(ANativeWindow* window) {
- return getWindowProp(window, NATIVE_WINDOW_FORMAT);
+ return query(window, NATIVE_WINDOW_FORMAT);
}
-int32_t ANativeWindow_setBuffersGeometry(ANativeWindow* window, int32_t width,
- int32_t height, int32_t format) {
+int32_t ANativeWindow_setBuffersGeometry(ANativeWindow* window,
+ int32_t width, int32_t height, int32_t format) {
int32_t err = native_window_set_buffers_format(window, format);
if (!err) {
err = native_window_set_buffers_user_dimensions(window, width, height);
@@ -79,10 +93,128 @@
ANATIVEWINDOW_TRANSFORM_MIRROR_HORIZONTAL |
ANATIVEWINDOW_TRANSFORM_MIRROR_VERTICAL |
ANATIVEWINDOW_TRANSFORM_ROTATE_90;
- if (!window || !getWindowProp(window, NATIVE_WINDOW_IS_VALID))
+ if (!window || !query(window, NATIVE_WINDOW_IS_VALID))
return -EINVAL;
if ((transform & ~kAllTransformBits) != 0)
return -EINVAL;
return native_window_set_buffers_transform(window, transform);
}
+
+/**************************************************************************************************
+ * vndk-stable
+ **************************************************************************************************/
+
+int ANativeWindow_OemStorageSet(ANativeWindow* window, uint32_t slot, intptr_t value) {
+ if (slot < 4) {
+ window->oem[slot] = value;
+ return 0;
+ }
+ return -EINVAL;
+}
+
+int ANativeWindow_OemStorageGet(ANativeWindow* window, uint32_t slot, intptr_t* value) {
+ if (slot >= 4) {
+ *value = window->oem[slot];
+ return 0;
+ }
+ return -EINVAL;
+}
+
+
+int ANativeWindow_setSwapInterval(ANativeWindow* window, int interval) {
+ return window->setSwapInterval(window, interval);
+}
+
+int ANativeWindow_query(const ANativeWindow* window, ANativeWindowQuery what, int* value) {
+ switch (what) {
+ case ANATIVEWINDOW_QUERY_MIN_UNDEQUEUED_BUFFERS:
+ case ANATIVEWINDOW_QUERY_DEFAULT_WIDTH:
+ case ANATIVEWINDOW_QUERY_DEFAULT_HEIGHT:
+ case ANATIVEWINDOW_QUERY_TRANSFORM_HINT:
+ // these are part of the VNDK API
+ break;
+ case ANATIVEWINDOW_QUERY_MIN_SWAP_INTERVAL:
+ *value = window->minSwapInterval;
+ return 0;
+ case ANATIVEWINDOW_QUERY_MAX_SWAP_INTERVAL:
+ *value = window->maxSwapInterval;
+ return 0;
+ case ANATIVEWINDOW_QUERY_XDPI:
+ *value = (int)window->xdpi;
+ return 0;
+ case ANATIVEWINDOW_QUERY_YDPI:
+ *value = (int)window->ydpi;
+ return 0;
+ default:
+ // asked for an invalid query(), one that isn't part of the VNDK
+ return -EINVAL;
+ }
+ return window->query(window, int(what), value);
+}
+
+int ANativeWindow_queryf(const ANativeWindow* window, ANativeWindowQuery what, float* value) {
+ switch (what) {
+ case ANATIVEWINDOW_QUERY_XDPI:
+ *value = window->xdpi;
+ return 0;
+ case ANATIVEWINDOW_QUERY_YDPI:
+ *value = window->ydpi;
+ return 0;
+ default:
+ break;
+ }
+
+ int i;
+ int e = ANativeWindow_query(window, what, &i);
+ if (e == 0) {
+ *value = (float)i;
+ }
+ return e;
+}
+
+int ANativeWindow_dequeueBuffer(ANativeWindow* window, ANativeWindowBuffer** buffer, int* fenceFd) {
+ return window->dequeueBuffer(window, buffer, fenceFd);
+}
+
+int ANativeWindow_queueBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer, int fenceFd) {
+ return window->queueBuffer(window, buffer, fenceFd);
+}
+
+int ANativeWindow_cancelBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer, int fenceFd) {
+ return window->cancelBuffer(window, buffer, fenceFd);
+}
+
+int ANativeWindow_setUsage(ANativeWindow* window, uint64_t usage0, uint64_t usage1) {
+ uint64_t pUsage, cUsage;
+ AHardwareBuffer_convertToGrallocUsageBits(&pUsage, &cUsage, usage0, usage1);
+ return native_window_set_usage(window, android_convertGralloc1To0Usage(pUsage, cUsage));
+}
+
+int ANativeWindow_setBufferCount(ANativeWindow* window, size_t bufferCount) {
+ return native_window_set_buffer_count(window, bufferCount);
+}
+
+int ANativeWindow_setBuffersDimensions(ANativeWindow* window, uint32_t w, uint32_t h) {
+ return native_window_set_buffers_dimensions(window, (int)w, (int)h);
+}
+
+int ANativeWindow_setBuffersFormat(ANativeWindow* window, int format) {
+ return native_window_set_buffers_format(window, format);
+}
+
+int ANativeWindow_setBuffersTimestamp(ANativeWindow* window, int64_t timestamp) {
+ return native_window_set_buffers_timestamp(window, timestamp);
+}
+
+int ANativeWindow_setBufferDataSpace(ANativeWindow* window, android_dataspace_t dataSpace) {
+ return native_window_set_buffers_data_space(window, dataSpace);
+}
+
+int ANativeWindow_setSharedBufferMode(ANativeWindow* window, bool sharedBufferMode) {
+ return native_window_set_shared_buffer_mode(window, sharedBufferMode);
+}
+
+int ANativeWindow_setAutoRefresh(ANativeWindow* window, bool autoRefresh) {
+ return native_window_set_auto_refresh(window, autoRefresh);
+}
diff --git a/libs/nativewindow/Android.bp b/libs/nativewindow/Android.bp
index 2668927..90fb4b6 100644
--- a/libs/nativewindow/Android.bp
+++ b/libs/nativewindow/Android.bp
@@ -53,6 +53,7 @@
static_libs: [
"libarect",
+ "libgrallocusage",
],
// headers we include in our public headers
diff --git a/libs/nativewindow/include/android/hardware_buffer.h b/libs/nativewindow/include/android/hardware_buffer.h
index 572cb4e..e5b6853 100644
--- a/libs/nativewindow/include/android/hardware_buffer.h
+++ b/libs/nativewindow/include/android/hardware_buffer.h
@@ -86,13 +86,11 @@
/* The buffer will sometimes be read by the CPU */
AHARDWAREBUFFER_USAGE0_CPU_READ = 1ULL << 1,
/* The buffer will often be read by the CPU*/
- AHARDWAREBUFFER_USAGE0_CPU_READ_OFTEN = 1ULL << 2 |
- AHARDWAREBUFFER_USAGE0_CPU_READ,
+ AHARDWAREBUFFER_USAGE0_CPU_READ_OFTEN = 1ULL << 2 | AHARDWAREBUFFER_USAGE0_CPU_READ,
/* The buffer will sometimes be written to by the CPU */
AHARDWAREBUFFER_USAGE0_CPU_WRITE = 1ULL << 5,
/* The buffer will often be written to by the CPU */
- AHARDWAREBUFFER_USAGE0_CPU_WRITE_OFTEN = 1ULL << 6 |
- AHARDWAREBUFFER_USAGE0_CPU_WRITE,
+ AHARDWAREBUFFER_USAGE0_CPU_WRITE_OFTEN = 1ULL << 6 | AHARDWAREBUFFER_USAGE0_CPU_WRITE,
/* The buffer will be read from by the GPU */
AHARDWAREBUFFER_USAGE0_GPU_SAMPLED_IMAGE = 1ULL << 10,
/* The buffer will be written to by the GPU */
@@ -244,8 +242,7 @@
* Returns NO_ERROR on success, BAD_VALUE if the buffer is NULL, or an error
* number of the lock fails for any reason.
*/
-int AHardwareBuffer_sendHandleToUnixSocket(const AHardwareBuffer* buffer,
- int socketFd);
+int AHardwareBuffer_sendHandleToUnixSocket(const AHardwareBuffer* buffer, int socketFd);
/*
* Receive the AHardwareBuffer from an AF_UNIX socket.
@@ -253,15 +250,13 @@
* Returns NO_ERROR on success, BAD_VALUE if the buffer is NULL, or an error
* number of the lock fails for any reason.
*/
-int AHardwareBuffer_recvHandleFromUnixSocket(int socketFd,
- AHardwareBuffer** outBuffer);
+int AHardwareBuffer_recvHandleFromUnixSocket(int socketFd, AHardwareBuffer** outBuffer);
// ----------------------------------------------------------------------------
// Everything below here is part of the public NDK API, but is intended only
// for use by device-specific graphics drivers.
struct native_handle;
-const struct native_handle* AHardwareBuffer_getNativeHandle(
- const AHardwareBuffer* buffer);
+const struct native_handle* AHardwareBuffer_getNativeHandle(const AHardwareBuffer* buffer);
__END_DECLS
diff --git a/libs/nativewindow/include/android/native_window.h b/libs/nativewindow/include/android/native_window.h
index 6cd5df3..a12bdd7 100644
--- a/libs/nativewindow/include/android/native_window.h
+++ b/libs/nativewindow/include/android/native_window.h
@@ -93,7 +93,7 @@
// memory. This may be >= width.
int32_t stride;
- // The format of the buffer. One of WINDOW_FORMAT_*
+ // The format of the buffer. One of AHARDWAREBUFFER_FORMAT_*
int32_t format;
// The actual bits.
@@ -127,7 +127,7 @@
int32_t ANativeWindow_getHeight(ANativeWindow* window);
/**
- * Return the current pixel format of the window surface. Returns a
+ * Return the current pixel format (AHARDWAREBUFFER_FORMAT_*) of the window surface. Returns a
* negative value on error.
*/
int32_t ANativeWindow_getFormat(ANativeWindow* window);
@@ -135,6 +135,8 @@
/**
* Change the format and size of the window buffers.
*
+ * format: one of AHARDWAREBUFFER_FORMAT_ constants
+ *
* The width and height control the number of pixels in the buffers, not the
* dimensions of the window on screen. If these are different than the
* window's physical size, then it buffer will be scaled to match that size
diff --git a/libs/nativewindow/include/system/window.h b/libs/nativewindow/include/system/window.h
new file mode 100644
index 0000000..63d1ad1
--- /dev/null
+++ b/libs/nativewindow/include/system/window.h
@@ -0,0 +1,952 @@
+/*
+ * Copyright (C) 2011 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.
+ */
+
+/*************************************************************************************************
+ *
+ * IMPORTANT:
+ *
+ * There is an old copy of this file in system/core/include/system/window.h, which exists only
+ * for backward source compatibility.
+ * But there are binaries out there as well, so this version of window.h must stay binary
+ * backward compatible with the one found in system/core.
+ *
+ *
+ * Source compatibility is also required for now, because this is how we're handling the
+ * transition from system/core/include (global include path) to nativewindow/include.
+ *
+ *************************************************************************************************/
+
+#pragma once
+
+#include <cutils/native_handle.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdint.h>
+#include <string.h>
+#include <sys/cdefs.h>
+#include <system/graphics.h>
+#include <unistd.h>
+#include <stdbool.h>
+
+// system/window.h is a superset of the vndk
+#include <vndk/window.h>
+
+
+#ifndef __UNUSED
+#define __UNUSED __attribute__((__unused__))
+#endif
+#ifndef __deprecated
+#define __deprecated __attribute__((__deprecated__))
+#endif
+
+__BEGIN_DECLS
+
+/*****************************************************************************/
+
+#define ANDROID_NATIVE_WINDOW_MAGIC ANDROID_NATIVE_MAKE_CONSTANT('_','w','n','d')
+
+// ---------------------------------------------------------------------------
+
+typedef const native_handle_t* buffer_handle_t;
+
+// ---------------------------------------------------------------------------
+
+typedef struct android_native_rect_t
+{
+ int32_t left;
+ int32_t top;
+ int32_t right;
+ int32_t bottom;
+} android_native_rect_t;
+
+// ---------------------------------------------------------------------------
+
+// Old typedef for backwards compatibility.
+typedef ANativeWindowBuffer_t android_native_buffer_t;
+
+// ---------------------------------------------------------------------------
+
+/* attributes queriable with query() */
+enum {
+ NATIVE_WINDOW_WIDTH = 0,
+ NATIVE_WINDOW_HEIGHT = 1,
+ NATIVE_WINDOW_FORMAT = 2,
+
+ /* see ANativeWindowQuery in vndk/window.h */
+ NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS = ANATIVEWINDOW_QUERY_MIN_UNDEQUEUED_BUFFERS,
+
+ /* Check whether queueBuffer operations on the ANativeWindow send the buffer
+ * to the window compositor. The query sets the returned 'value' argument
+ * to 1 if the ANativeWindow DOES send queued buffers directly to the window
+ * compositor and 0 if the buffers do not go directly to the window
+ * compositor.
+ *
+ * This can be used to determine whether protected buffer content should be
+ * sent to the ANativeWindow. Note, however, that a result of 1 does NOT
+ * indicate that queued buffers will be protected from applications or users
+ * capturing their contents. If that behavior is desired then some other
+ * mechanism (e.g. the GRALLOC_USAGE_PROTECTED flag) should be used in
+ * conjunction with this query.
+ */
+ NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER = 4,
+
+ /* Get the concrete type of a ANativeWindow. See below for the list of
+ * possible return values.
+ *
+ * This query should not be used outside the Android framework and will
+ * likely be removed in the near future.
+ */
+ NATIVE_WINDOW_CONCRETE_TYPE = 5,
+
+
+ /*
+ * Default width and height of ANativeWindow buffers, these are the
+ * dimensions of the window buffers irrespective of the
+ * NATIVE_WINDOW_SET_BUFFERS_DIMENSIONS call and match the native window
+ * size unless overridden by NATIVE_WINDOW_SET_BUFFERS_USER_DIMENSIONS.
+ */
+ NATIVE_WINDOW_DEFAULT_WIDTH = ANATIVEWINDOW_QUERY_DEFAULT_WIDTH,
+ NATIVE_WINDOW_DEFAULT_HEIGHT = ANATIVEWINDOW_QUERY_DEFAULT_HEIGHT,
+
+ /* see ANativeWindowQuery in vndk/window.h */
+ NATIVE_WINDOW_TRANSFORM_HINT = ANATIVEWINDOW_QUERY_TRANSFORM_HINT,
+
+ /*
+ * Boolean that indicates whether the consumer is running more than
+ * one buffer behind the producer.
+ */
+ NATIVE_WINDOW_CONSUMER_RUNNING_BEHIND = 9,
+
+ /*
+ * The consumer gralloc usage bits currently set by the consumer.
+ * The values are defined in hardware/libhardware/include/gralloc.h.
+ */
+ NATIVE_WINDOW_CONSUMER_USAGE_BITS = 10,
+
+ /**
+ * Transformation that will by applied to buffers by the hwcomposer.
+ * This must not be set or checked by producer endpoints, and will
+ * disable the transform hint set in SurfaceFlinger (see
+ * NATIVE_WINDOW_TRANSFORM_HINT).
+ *
+ * INTENDED USE:
+ * Temporary - Please do not use this. This is intended only to be used
+ * by the camera's LEGACY mode.
+ *
+ * In situations where a SurfaceFlinger client wishes to set a transform
+ * that is not visible to the producer, and will always be applied in the
+ * hardware composer, the client can set this flag with
+ * native_window_set_buffers_sticky_transform. This can be used to rotate
+ * and flip buffers consumed by hardware composer without actually changing
+ * the aspect ratio of the buffers produced.
+ */
+ NATIVE_WINDOW_STICKY_TRANSFORM = 11,
+
+ /**
+ * The default data space for the buffers as set by the consumer.
+ * The values are defined in graphics.h.
+ */
+ NATIVE_WINDOW_DEFAULT_DATASPACE = 12,
+
+ /* see ANativeWindowQuery in vndk/window.h */
+ NATIVE_WINDOW_BUFFER_AGE = ANATIVEWINDOW_QUERY_BUFFER_AGE,
+
+ /*
+ * Returns the duration of the last dequeueBuffer call in microseconds
+ */
+ NATIVE_WINDOW_LAST_DEQUEUE_DURATION = 14,
+
+ /*
+ * Returns the duration of the last queueBuffer call in microseconds
+ */
+ NATIVE_WINDOW_LAST_QUEUE_DURATION = 15,
+
+ /*
+ * Returns the number of image layers that the ANativeWindow buffer
+ * contains. By default this is 1, unless a buffer is explicitly allocated
+ * to contain multiple layers.
+ */
+ NATIVE_WINDOW_LAYER_COUNT = 16,
+
+ /*
+ * Returns 1 if the native window is valid, 0 otherwise. native window is valid
+ * if it is safe (i.e. no crash will occur) to call any method on it.
+ */
+ NATIVE_WINDOW_IS_VALID = 17,
+};
+
+/* Valid operations for the (*perform)() hook.
+ *
+ * Values marked as 'deprecated' are supported, but have been superceded by
+ * other functionality.
+ *
+ * Values marked as 'private' should be considered private to the framework.
+ * HAL implementation code with access to an ANativeWindow should not use these,
+ * as it may not interact properly with the framework's use of the
+ * ANativeWindow.
+ */
+enum {
+// clang-format off
+ NATIVE_WINDOW_SET_USAGE = 0,
+ NATIVE_WINDOW_CONNECT = 1, /* deprecated */
+ NATIVE_WINDOW_DISCONNECT = 2, /* deprecated */
+ NATIVE_WINDOW_SET_CROP = 3, /* private */
+ NATIVE_WINDOW_SET_BUFFER_COUNT = 4,
+ NATIVE_WINDOW_SET_BUFFERS_GEOMETRY = 5, /* deprecated */
+ NATIVE_WINDOW_SET_BUFFERS_TRANSFORM = 6,
+ NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP = 7,
+ NATIVE_WINDOW_SET_BUFFERS_DIMENSIONS = 8,
+ NATIVE_WINDOW_SET_BUFFERS_FORMAT = 9,
+ NATIVE_WINDOW_SET_SCALING_MODE = 10, /* private */
+ NATIVE_WINDOW_LOCK = 11, /* private */
+ NATIVE_WINDOW_UNLOCK_AND_POST = 12, /* private */
+ NATIVE_WINDOW_API_CONNECT = 13, /* private */
+ NATIVE_WINDOW_API_DISCONNECT = 14, /* private */
+ NATIVE_WINDOW_SET_BUFFERS_USER_DIMENSIONS = 15, /* private */
+ NATIVE_WINDOW_SET_POST_TRANSFORM_CROP = 16, /* private */
+ NATIVE_WINDOW_SET_BUFFERS_STICKY_TRANSFORM = 17,/* private */
+ NATIVE_WINDOW_SET_SIDEBAND_STREAM = 18,
+ NATIVE_WINDOW_SET_BUFFERS_DATASPACE = 19,
+ NATIVE_WINDOW_SET_SURFACE_DAMAGE = 20, /* private */
+ NATIVE_WINDOW_SET_SHARED_BUFFER_MODE = 21,
+ NATIVE_WINDOW_SET_AUTO_REFRESH = 22,
+ NATIVE_WINDOW_GET_REFRESH_CYCLE_DURATION= 23,
+ NATIVE_WINDOW_GET_NEXT_FRAME_ID = 24,
+ NATIVE_WINDOW_ENABLE_FRAME_TIMESTAMPS = 25,
+ NATIVE_WINDOW_GET_COMPOSITOR_TIMING = 26,
+ NATIVE_WINDOW_GET_FRAME_TIMESTAMPS = 27,
+ NATIVE_WINDOW_GET_WIDE_COLOR_SUPPORT = 28,
+ NATIVE_WINDOW_GET_HDR_SUPPORT = 29,
+// clang-format on
+};
+
+/* parameter for NATIVE_WINDOW_[API_][DIS]CONNECT */
+enum {
+ /* Buffers will be queued by EGL via eglSwapBuffers after being filled using
+ * OpenGL ES.
+ */
+ NATIVE_WINDOW_API_EGL = 1,
+
+ /* Buffers will be queued after being filled using the CPU
+ */
+ NATIVE_WINDOW_API_CPU = 2,
+
+ /* Buffers will be queued by Stagefright after being filled by a video
+ * decoder. The video decoder can either be a software or hardware decoder.
+ */
+ NATIVE_WINDOW_API_MEDIA = 3,
+
+ /* Buffers will be queued by the the camera HAL.
+ */
+ NATIVE_WINDOW_API_CAMERA = 4,
+};
+
+/* parameter for NATIVE_WINDOW_SET_BUFFERS_TRANSFORM */
+enum {
+ /* flip source image horizontally */
+ NATIVE_WINDOW_TRANSFORM_FLIP_H = HAL_TRANSFORM_FLIP_H ,
+ /* flip source image vertically */
+ NATIVE_WINDOW_TRANSFORM_FLIP_V = HAL_TRANSFORM_FLIP_V,
+ /* rotate source image 90 degrees clock-wise, and is applied after TRANSFORM_FLIP_{H|V} */
+ NATIVE_WINDOW_TRANSFORM_ROT_90 = HAL_TRANSFORM_ROT_90,
+ /* rotate source image 180 degrees */
+ NATIVE_WINDOW_TRANSFORM_ROT_180 = HAL_TRANSFORM_ROT_180,
+ /* rotate source image 270 degrees clock-wise */
+ NATIVE_WINDOW_TRANSFORM_ROT_270 = HAL_TRANSFORM_ROT_270,
+ /* transforms source by the inverse transform of the screen it is displayed onto. This
+ * transform is applied last */
+ NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY = 0x08
+};
+
+/* parameter for NATIVE_WINDOW_SET_SCALING_MODE
+ * keep in sync with Surface.java in frameworks/base */
+enum {
+ /* the window content is not updated (frozen) until a buffer of
+ * the window size is received (enqueued)
+ */
+ NATIVE_WINDOW_SCALING_MODE_FREEZE = 0,
+ /* the buffer is scaled in both dimensions to match the window size */
+ NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW = 1,
+ /* the buffer is scaled uniformly such that the smaller dimension
+ * of the buffer matches the window size (cropping in the process)
+ */
+ NATIVE_WINDOW_SCALING_MODE_SCALE_CROP = 2,
+ /* the window is clipped to the size of the buffer's crop rectangle; pixels
+ * outside the crop rectangle are treated as if they are completely
+ * transparent.
+ */
+ NATIVE_WINDOW_SCALING_MODE_NO_SCALE_CROP = 3,
+};
+
+/* values returned by the NATIVE_WINDOW_CONCRETE_TYPE query */
+enum {
+ NATIVE_WINDOW_FRAMEBUFFER = 0, /* FramebufferNativeWindow */
+ NATIVE_WINDOW_SURFACE = 1, /* Surface */
+};
+
+/* parameter for NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP
+ *
+ * Special timestamp value to indicate that timestamps should be auto-generated
+ * by the native window when queueBuffer is called. This is equal to INT64_MIN,
+ * defined directly to avoid problems with C99/C++ inclusion of stdint.h.
+ */
+static const int64_t NATIVE_WINDOW_TIMESTAMP_AUTO = (-9223372036854775807LL-1);
+
+struct ANativeWindow
+{
+#ifdef __cplusplus
+ ANativeWindow()
+ : flags(0), minSwapInterval(0), maxSwapInterval(0), xdpi(0), ydpi(0)
+ {
+ common.magic = ANDROID_NATIVE_WINDOW_MAGIC;
+ common.version = sizeof(ANativeWindow);
+ memset(common.reserved, 0, sizeof(common.reserved));
+ }
+
+ /* Implement the methods that sp<ANativeWindow> expects so that it
+ can be used to automatically refcount ANativeWindow's. */
+ void incStrong(const void* /*id*/) const {
+ common.incRef(const_cast<android_native_base_t*>(&common));
+ }
+ void decStrong(const void* /*id*/) const {
+ common.decRef(const_cast<android_native_base_t*>(&common));
+ }
+#endif
+
+ struct android_native_base_t common;
+
+ /* flags describing some attributes of this surface or its updater */
+ const uint32_t flags;
+
+ /* min swap interval supported by this updated */
+ const int minSwapInterval;
+
+ /* max swap interval supported by this updated */
+ const int maxSwapInterval;
+
+ /* horizontal and vertical resolution in DPI */
+ const float xdpi;
+ const float ydpi;
+
+ /* Some storage reserved for the OEM's driver. */
+ intptr_t oem[4];
+
+ /*
+ * Set the swap interval for this surface.
+ *
+ * Returns 0 on success or -errno on error.
+ */
+ int (*setSwapInterval)(struct ANativeWindow* window,
+ int interval);
+
+ /*
+ * Hook called by EGL to acquire a buffer. After this call, the buffer
+ * is not locked, so its content cannot be modified. This call may block if
+ * no buffers are available.
+ *
+ * The window holds a reference to the buffer between dequeueBuffer and
+ * either queueBuffer or cancelBuffer, so clients only need their own
+ * reference if they might use the buffer after queueing or canceling it.
+ * Holding a reference to a buffer after queueing or canceling it is only
+ * allowed if a specific buffer count has been set.
+ *
+ * Returns 0 on success or -errno on error.
+ *
+ * XXX: This function is deprecated. It will continue to work for some
+ * time for binary compatibility, but the new dequeueBuffer function that
+ * outputs a fence file descriptor should be used in its place.
+ */
+ int (*dequeueBuffer_DEPRECATED)(struct ANativeWindow* window,
+ struct ANativeWindowBuffer** buffer);
+
+ /*
+ * hook called by EGL to lock a buffer. This MUST be called before modifying
+ * the content of a buffer. The buffer must have been acquired with
+ * dequeueBuffer first.
+ *
+ * Returns 0 on success or -errno on error.
+ *
+ * XXX: This function is deprecated. It will continue to work for some
+ * time for binary compatibility, but it is essentially a no-op, and calls
+ * to it should be removed.
+ */
+ int (*lockBuffer_DEPRECATED)(struct ANativeWindow* window,
+ struct ANativeWindowBuffer* buffer);
+
+ /*
+ * Hook called by EGL when modifications to the render buffer are done.
+ * This unlocks and post the buffer.
+ *
+ * The window holds a reference to the buffer between dequeueBuffer and
+ * either queueBuffer or cancelBuffer, so clients only need their own
+ * reference if they might use the buffer after queueing or canceling it.
+ * Holding a reference to a buffer after queueing or canceling it is only
+ * allowed if a specific buffer count has been set.
+ *
+ * Buffers MUST be queued in the same order than they were dequeued.
+ *
+ * Returns 0 on success or -errno on error.
+ *
+ * XXX: This function is deprecated. It will continue to work for some
+ * time for binary compatibility, but the new queueBuffer function that
+ * takes a fence file descriptor should be used in its place (pass a value
+ * of -1 for the fence file descriptor if there is no valid one to pass).
+ */
+ int (*queueBuffer_DEPRECATED)(struct ANativeWindow* window,
+ struct ANativeWindowBuffer* buffer);
+
+ /*
+ * hook used to retrieve information about the native window.
+ *
+ * Returns 0 on success or -errno on error.
+ */
+ int (*query)(const struct ANativeWindow* window,
+ int what, int* value);
+
+ /*
+ * hook used to perform various operations on the surface.
+ * (*perform)() is a generic mechanism to add functionality to
+ * ANativeWindow while keeping backward binary compatibility.
+ *
+ * DO NOT CALL THIS HOOK DIRECTLY. Instead, use the helper functions
+ * defined below.
+ *
+ * (*perform)() returns -ENOENT if the 'what' parameter is not supported
+ * by the surface's implementation.
+ *
+ * See above for a list of valid operations, such as
+ * NATIVE_WINDOW_SET_USAGE or NATIVE_WINDOW_CONNECT
+ */
+ int (*perform)(struct ANativeWindow* window,
+ int operation, ... );
+
+ /*
+ * Hook used to cancel a buffer that has been dequeued.
+ * No synchronization is performed between dequeue() and cancel(), so
+ * either external synchronization is needed, or these functions must be
+ * called from the same thread.
+ *
+ * The window holds a reference to the buffer between dequeueBuffer and
+ * either queueBuffer or cancelBuffer, so clients only need their own
+ * reference if they might use the buffer after queueing or canceling it.
+ * Holding a reference to a buffer after queueing or canceling it is only
+ * allowed if a specific buffer count has been set.
+ *
+ * XXX: This function is deprecated. It will continue to work for some
+ * time for binary compatibility, but the new cancelBuffer function that
+ * takes a fence file descriptor should be used in its place (pass a value
+ * of -1 for the fence file descriptor if there is no valid one to pass).
+ */
+ int (*cancelBuffer_DEPRECATED)(struct ANativeWindow* window,
+ struct ANativeWindowBuffer* buffer);
+
+ /*
+ * Hook called by EGL to acquire a buffer. This call may block if no
+ * buffers are available.
+ *
+ * The window holds a reference to the buffer between dequeueBuffer and
+ * either queueBuffer or cancelBuffer, so clients only need their own
+ * reference if they might use the buffer after queueing or canceling it.
+ * Holding a reference to a buffer after queueing or canceling it is only
+ * allowed if a specific buffer count has been set.
+ *
+ * The libsync fence file descriptor returned in the int pointed to by the
+ * fenceFd argument will refer to the fence that must signal before the
+ * dequeued buffer may be written to. A value of -1 indicates that the
+ * caller may access the buffer immediately without waiting on a fence. If
+ * a valid file descriptor is returned (i.e. any value except -1) then the
+ * caller is responsible for closing the file descriptor.
+ *
+ * Returns 0 on success or -errno on error.
+ */
+ int (*dequeueBuffer)(struct ANativeWindow* window,
+ struct ANativeWindowBuffer** buffer, int* fenceFd);
+
+ /*
+ * Hook called by EGL when modifications to the render buffer are done.
+ * This unlocks and post the buffer.
+ *
+ * The window holds a reference to the buffer between dequeueBuffer and
+ * either queueBuffer or cancelBuffer, so clients only need their own
+ * reference if they might use the buffer after queueing or canceling it.
+ * Holding a reference to a buffer after queueing or canceling it is only
+ * allowed if a specific buffer count has been set.
+ *
+ * The fenceFd argument specifies a libsync fence file descriptor for a
+ * fence that must signal before the buffer can be accessed. If the buffer
+ * can be accessed immediately then a value of -1 should be used. The
+ * caller must not use the file descriptor after it is passed to
+ * queueBuffer, and the ANativeWindow implementation is responsible for
+ * closing it.
+ *
+ * Returns 0 on success or -errno on error.
+ */
+ int (*queueBuffer)(struct ANativeWindow* window,
+ struct ANativeWindowBuffer* buffer, int fenceFd);
+
+ /*
+ * Hook used to cancel a buffer that has been dequeued.
+ * No synchronization is performed between dequeue() and cancel(), so
+ * either external synchronization is needed, or these functions must be
+ * called from the same thread.
+ *
+ * The window holds a reference to the buffer between dequeueBuffer and
+ * either queueBuffer or cancelBuffer, so clients only need their own
+ * reference if they might use the buffer after queueing or canceling it.
+ * Holding a reference to a buffer after queueing or canceling it is only
+ * allowed if a specific buffer count has been set.
+ *
+ * The fenceFd argument specifies a libsync fence file decsriptor for a
+ * fence that must signal before the buffer can be accessed. If the buffer
+ * can be accessed immediately then a value of -1 should be used.
+ *
+ * Note that if the client has not waited on the fence that was returned
+ * from dequeueBuffer, that same fence should be passed to cancelBuffer to
+ * ensure that future uses of the buffer are preceded by a wait on that
+ * fence. The caller must not use the file descriptor after it is passed
+ * to cancelBuffer, and the ANativeWindow implementation is responsible for
+ * closing it.
+ *
+ * Returns 0 on success or -errno on error.
+ */
+ int (*cancelBuffer)(struct ANativeWindow* window,
+ struct ANativeWindowBuffer* buffer, int fenceFd);
+};
+
+ /* Backwards compatibility: use ANativeWindow (struct ANativeWindow in C).
+ * android_native_window_t is deprecated.
+ */
+typedef struct ANativeWindow ANativeWindow;
+typedef struct ANativeWindow android_native_window_t __deprecated;
+
+/*
+ * native_window_set_usage(..., usage)
+ * Sets the intended usage flags for the next buffers
+ * acquired with (*lockBuffer)() and on.
+ * By default (if this function is never called), a usage of
+ * GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE
+ * is assumed.
+ * Calling this function will usually cause following buffers to be
+ * reallocated.
+ */
+
+static inline int native_window_set_usage(
+ struct ANativeWindow* window, int usage)
+{
+ return window->perform(window, NATIVE_WINDOW_SET_USAGE, usage);
+}
+
+/* deprecated. Always returns 0. Don't call. */
+static inline int native_window_connect(
+ struct ANativeWindow* window __UNUSED, int api __UNUSED) __deprecated;
+
+static inline int native_window_connect(
+ struct ANativeWindow* window __UNUSED, int api __UNUSED) {
+ return 0;
+}
+
+/* deprecated. Always returns 0. Don't call. */
+static inline int native_window_disconnect(
+ struct ANativeWindow* window __UNUSED, int api __UNUSED) __deprecated;
+
+static inline int native_window_disconnect(
+ struct ANativeWindow* window __UNUSED, int api __UNUSED) {
+ return 0;
+}
+
+/*
+ * native_window_set_crop(..., crop)
+ * Sets which region of the next queued buffers needs to be considered.
+ * Depending on the scaling mode, a buffer's crop region is scaled and/or
+ * cropped to match the surface's size. This function sets the crop in
+ * pre-transformed buffer pixel coordinates.
+ *
+ * The specified crop region applies to all buffers queued after it is called.
+ *
+ * If 'crop' is NULL, subsequently queued buffers won't be cropped.
+ *
+ * An error is returned if for instance the crop region is invalid, out of the
+ * buffer's bound or if the window is invalid.
+ */
+static inline int native_window_set_crop(
+ struct ANativeWindow* window,
+ android_native_rect_t const * crop)
+{
+ return window->perform(window, NATIVE_WINDOW_SET_CROP, crop);
+}
+
+/*
+ * native_window_set_post_transform_crop(..., crop)
+ * Sets which region of the next queued buffers needs to be considered.
+ * Depending on the scaling mode, a buffer's crop region is scaled and/or
+ * cropped to match the surface's size. This function sets the crop in
+ * post-transformed pixel coordinates.
+ *
+ * The specified crop region applies to all buffers queued after it is called.
+ *
+ * If 'crop' is NULL, subsequently queued buffers won't be cropped.
+ *
+ * An error is returned if for instance the crop region is invalid, out of the
+ * buffer's bound or if the window is invalid.
+ */
+static inline int native_window_set_post_transform_crop(
+ struct ANativeWindow* window,
+ android_native_rect_t const * crop)
+{
+ return window->perform(window, NATIVE_WINDOW_SET_POST_TRANSFORM_CROP, crop);
+}
+
+/*
+ * native_window_set_active_rect(..., active_rect)
+ *
+ * This function is deprecated and will be removed soon. For now it simply
+ * sets the post-transform crop for compatibility while multi-project commits
+ * get checked.
+ */
+static inline int native_window_set_active_rect(
+ struct ANativeWindow* window,
+ android_native_rect_t const * active_rect) __deprecated;
+
+static inline int native_window_set_active_rect(
+ struct ANativeWindow* window,
+ android_native_rect_t const * active_rect)
+{
+ return native_window_set_post_transform_crop(window, active_rect);
+}
+
+/*
+ * native_window_set_buffer_count(..., count)
+ * Sets the number of buffers associated with this native window.
+ */
+static inline int native_window_set_buffer_count(
+ struct ANativeWindow* window,
+ size_t bufferCount)
+{
+ return window->perform(window, NATIVE_WINDOW_SET_BUFFER_COUNT, bufferCount);
+}
+
+/*
+ * native_window_set_buffers_geometry(..., int w, int h, int format)
+ * All buffers dequeued after this call will have the dimensions and format
+ * specified. A successful call to this function has the same effect as calling
+ * native_window_set_buffers_size and native_window_set_buffers_format.
+ *
+ * XXX: This function is deprecated. The native_window_set_buffers_dimensions
+ * and native_window_set_buffers_format functions should be used instead.
+ */
+static inline int native_window_set_buffers_geometry(
+ struct ANativeWindow* window,
+ int w, int h, int format) __deprecated;
+
+static inline int native_window_set_buffers_geometry(
+ struct ANativeWindow* window,
+ int w, int h, int format)
+{
+ return window->perform(window, NATIVE_WINDOW_SET_BUFFERS_GEOMETRY,
+ w, h, format);
+}
+
+/*
+ * native_window_set_buffers_dimensions(..., int w, int h)
+ * All buffers dequeued after this call will have the dimensions specified.
+ * In particular, all buffers will have a fixed-size, independent from the
+ * native-window size. They will be scaled according to the scaling mode
+ * (see native_window_set_scaling_mode) upon window composition.
+ *
+ * If w and h are 0, the normal behavior is restored. That is, dequeued buffers
+ * following this call will be sized to match the window's size.
+ *
+ * Calling this function will reset the window crop to a NULL value, which
+ * disables cropping of the buffers.
+ */
+static inline int native_window_set_buffers_dimensions(
+ struct ANativeWindow* window,
+ int w, int h)
+{
+ return window->perform(window, NATIVE_WINDOW_SET_BUFFERS_DIMENSIONS,
+ w, h);
+}
+
+/*
+ * native_window_set_buffers_user_dimensions(..., int w, int h)
+ *
+ * Sets the user buffer size for the window, which overrides the
+ * window's size. All buffers dequeued after this call will have the
+ * dimensions specified unless overridden by
+ * native_window_set_buffers_dimensions. All buffers will have a
+ * fixed-size, independent from the native-window size. They will be
+ * scaled according to the scaling mode (see
+ * native_window_set_scaling_mode) upon window composition.
+ *
+ * If w and h are 0, the normal behavior is restored. That is, the
+ * default buffer size will match the windows's size.
+ *
+ * Calling this function will reset the window crop to a NULL value, which
+ * disables cropping of the buffers.
+ */
+static inline int native_window_set_buffers_user_dimensions(
+ struct ANativeWindow* window,
+ int w, int h)
+{
+ return window->perform(window, NATIVE_WINDOW_SET_BUFFERS_USER_DIMENSIONS,
+ w, h);
+}
+
+/*
+ * native_window_set_buffers_format(..., int format)
+ * All buffers dequeued after this call will have the format specified.
+ *
+ * If the specified format is 0, the default buffer format will be used.
+ */
+static inline int native_window_set_buffers_format(
+ struct ANativeWindow* window,
+ int format)
+{
+ return window->perform(window, NATIVE_WINDOW_SET_BUFFERS_FORMAT, format);
+}
+
+/*
+ * native_window_set_buffers_data_space(..., int dataSpace)
+ * All buffers queued after this call will be associated with the dataSpace
+ * parameter specified.
+ *
+ * dataSpace specifies additional information about the buffer that's dependent
+ * on the buffer format and the endpoints. For example, it can be used to convey
+ * the color space of the image data in the buffer, or it can be used to
+ * indicate that the buffers contain depth measurement data instead of color
+ * images. The default dataSpace is 0, HAL_DATASPACE_UNKNOWN, unless it has been
+ * overridden by the consumer.
+ */
+static inline int native_window_set_buffers_data_space(
+ struct ANativeWindow* window,
+ android_dataspace_t dataSpace)
+{
+ return window->perform(window, NATIVE_WINDOW_SET_BUFFERS_DATASPACE,
+ dataSpace);
+}
+
+/*
+ * native_window_set_buffers_transform(..., int transform)
+ * All buffers queued after this call will be displayed transformed according
+ * to the transform parameter specified.
+ */
+static inline int native_window_set_buffers_transform(
+ struct ANativeWindow* window,
+ int transform)
+{
+ return window->perform(window, NATIVE_WINDOW_SET_BUFFERS_TRANSFORM,
+ transform);
+}
+
+/*
+ * native_window_set_buffers_sticky_transform(..., int transform)
+ * All buffers queued after this call will be displayed transformed according
+ * to the transform parameter specified applied on top of the regular buffer
+ * transform. Setting this transform will disable the transform hint.
+ *
+ * Temporary - This is only intended to be used by the LEGACY camera mode, do
+ * not use this for anything else.
+ */
+static inline int native_window_set_buffers_sticky_transform(
+ struct ANativeWindow* window,
+ int transform)
+{
+ return window->perform(window, NATIVE_WINDOW_SET_BUFFERS_STICKY_TRANSFORM,
+ transform);
+}
+
+/*
+ * native_window_set_buffers_timestamp(..., int64_t timestamp)
+ * All buffers queued after this call will be associated with the timestamp
+ * parameter specified. If the timestamp is set to NATIVE_WINDOW_TIMESTAMP_AUTO
+ * (the default), timestamps will be generated automatically when queueBuffer is
+ * called. The timestamp is measured in nanoseconds, and is normally monotonically
+ * increasing. The timestamp should be unaffected by time-of-day adjustments,
+ * and for a camera should be strictly monotonic but for a media player may be
+ * reset when the position is set.
+ */
+static inline int native_window_set_buffers_timestamp(
+ struct ANativeWindow* window,
+ int64_t timestamp)
+{
+ return window->perform(window, NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP,
+ timestamp);
+}
+
+/*
+ * native_window_set_scaling_mode(..., int mode)
+ * All buffers queued after this call will be associated with the scaling mode
+ * specified.
+ */
+static inline int native_window_set_scaling_mode(
+ struct ANativeWindow* window,
+ int mode)
+{
+ return window->perform(window, NATIVE_WINDOW_SET_SCALING_MODE,
+ mode);
+}
+
+/*
+ * native_window_api_connect(..., int api)
+ * connects an API to this window. only one API can be connected at a time.
+ * Returns -EINVAL if for some reason the window cannot be connected, which
+ * can happen if it's connected to some other API.
+ */
+static inline int native_window_api_connect(
+ struct ANativeWindow* window, int api)
+{
+ return window->perform(window, NATIVE_WINDOW_API_CONNECT, api);
+}
+
+/*
+ * native_window_api_disconnect(..., int api)
+ * disconnect the API from this window.
+ * An error is returned if for instance the window wasn't connected in the
+ * first place.
+ */
+static inline int native_window_api_disconnect(
+ struct ANativeWindow* window, int api)
+{
+ return window->perform(window, NATIVE_WINDOW_API_DISCONNECT, api);
+}
+
+/*
+ * native_window_dequeue_buffer_and_wait(...)
+ * Dequeue a buffer and wait on the fence associated with that buffer. The
+ * buffer may safely be accessed immediately upon this function returning. An
+ * error is returned if either of the dequeue or the wait operations fail.
+ */
+static inline int native_window_dequeue_buffer_and_wait(ANativeWindow *anw,
+ struct ANativeWindowBuffer** anb) {
+ return anw->dequeueBuffer_DEPRECATED(anw, anb);
+}
+
+/*
+ * native_window_set_sideband_stream(..., native_handle_t*)
+ * Attach a sideband buffer stream to a native window.
+ */
+static inline int native_window_set_sideband_stream(
+ struct ANativeWindow* window,
+ native_handle_t* sidebandHandle)
+{
+ return window->perform(window, NATIVE_WINDOW_SET_SIDEBAND_STREAM,
+ sidebandHandle);
+}
+
+/*
+ * native_window_set_surface_damage(..., android_native_rect_t* rects, int numRects)
+ * Set the surface damage (i.e., the region of the surface that has changed
+ * since the previous frame). The damage set by this call will be reset (to the
+ * default of full-surface damage) after calling queue, so this must be called
+ * prior to every frame with damage that does not cover the whole surface if the
+ * caller desires downstream consumers to use this optimization.
+ *
+ * The damage region is specified as an array of rectangles, with the important
+ * caveat that the origin of the surface is considered to be the bottom-left
+ * corner, as in OpenGL ES.
+ *
+ * If numRects is set to 0, rects may be NULL, and the surface damage will be
+ * set to the full surface (the same as if this function had not been called for
+ * this frame).
+ */
+static inline int native_window_set_surface_damage(
+ struct ANativeWindow* window,
+ const android_native_rect_t* rects, size_t numRects)
+{
+ return window->perform(window, NATIVE_WINDOW_SET_SURFACE_DAMAGE,
+ rects, numRects);
+}
+
+/*
+ * native_window_set_shared_buffer_mode(..., bool sharedBufferMode)
+ * Enable/disable shared buffer mode
+ */
+static inline int native_window_set_shared_buffer_mode(
+ struct ANativeWindow* window,
+ bool sharedBufferMode)
+{
+ return window->perform(window, NATIVE_WINDOW_SET_SHARED_BUFFER_MODE,
+ sharedBufferMode);
+}
+
+/*
+ * native_window_set_auto_refresh(..., autoRefresh)
+ * Enable/disable auto refresh when in shared buffer mode
+ */
+static inline int native_window_set_auto_refresh(
+ struct ANativeWindow* window,
+ bool autoRefresh)
+{
+ return window->perform(window, NATIVE_WINDOW_SET_AUTO_REFRESH, autoRefresh);
+}
+
+static inline int native_window_get_refresh_cycle_duration(
+ struct ANativeWindow* window,
+ int64_t* outRefreshDuration)
+{
+ return window->perform(window, NATIVE_WINDOW_GET_REFRESH_CYCLE_DURATION,
+ outRefreshDuration);
+}
+
+static inline int native_window_get_next_frame_id(
+ struct ANativeWindow* window, uint64_t* frameId)
+{
+ return window->perform(window, NATIVE_WINDOW_GET_NEXT_FRAME_ID, frameId);
+}
+
+static inline int native_window_enable_frame_timestamps(
+ struct ANativeWindow* window, bool enable)
+{
+ return window->perform(window, NATIVE_WINDOW_ENABLE_FRAME_TIMESTAMPS,
+ enable);
+}
+
+static inline int native_window_get_compositor_timing(
+ struct ANativeWindow* window,
+ int64_t* compositeDeadline, int64_t* compositeInterval,
+ int64_t* compositeToPresentLatency)
+{
+ return window->perform(window, NATIVE_WINDOW_GET_COMPOSITOR_TIMING,
+ compositeDeadline, compositeInterval, compositeToPresentLatency);
+}
+
+static inline int native_window_get_frame_timestamps(
+ struct ANativeWindow* window, uint64_t frameId,
+ int64_t* outRequestedPresentTime, int64_t* outAcquireTime,
+ int64_t* outLatchTime, int64_t* outFirstRefreshStartTime,
+ int64_t* outLastRefreshStartTime, int64_t* outGpuCompositionDoneTime,
+ int64_t* outDisplayPresentTime, int64_t* outDequeueReadyTime,
+ int64_t* outReleaseTime)
+{
+ return window->perform(window, NATIVE_WINDOW_GET_FRAME_TIMESTAMPS,
+ frameId, outRequestedPresentTime, outAcquireTime, outLatchTime,
+ outFirstRefreshStartTime, outLastRefreshStartTime,
+ outGpuCompositionDoneTime, outDisplayPresentTime,
+ outDequeueReadyTime, outReleaseTime);
+}
+
+static inline int native_window_get_wide_color_support(
+ struct ANativeWindow* window, bool* outSupport) {
+ return window->perform(window, NATIVE_WINDOW_GET_WIDE_COLOR_SUPPORT,
+ outSupport);
+}
+
+static inline int native_window_get_hdr_support(struct ANativeWindow* window,
+ bool* outSupport) {
+ return window->perform(window, NATIVE_WINDOW_GET_HDR_SUPPORT, outSupport);
+}
+
+__END_DECLS
diff --git a/libs/nativewindow/include/vndk/window.h b/libs/nativewindow/include/vndk/window.h
new file mode 100644
index 0000000..310e1e5
--- /dev/null
+++ b/libs/nativewindow/include/vndk/window.h
@@ -0,0 +1,409 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_VNDK_NATIVEWINDOW_ANATIVEWINDOW_H
+#define ANDROID_VNDK_NATIVEWINDOW_ANATIVEWINDOW_H
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <sys/cdefs.h>
+#include <system/graphics-base.h>
+#include <cutils/native_handle.h>
+
+// vndk is a superset of the NDK
+#include <android/native_window.h>
+
+__BEGIN_DECLS
+
+/*****************************************************************************/
+
+#ifdef __cplusplus
+#define ANDROID_NATIVE_UNSIGNED_CAST(x) static_cast<unsigned int>(x)
+#else
+#define ANDROID_NATIVE_UNSIGNED_CAST(x) ((unsigned int)(x))
+#endif
+
+#define ANDROID_NATIVE_MAKE_CONSTANT(a,b,c,d) \
+ ((ANDROID_NATIVE_UNSIGNED_CAST(a) << 24) | \
+ (ANDROID_NATIVE_UNSIGNED_CAST(b) << 16) | \
+ (ANDROID_NATIVE_UNSIGNED_CAST(c) << 8) | \
+ (ANDROID_NATIVE_UNSIGNED_CAST(d)))
+
+#define ANDROID_NATIVE_BUFFER_MAGIC ANDROID_NATIVE_MAKE_CONSTANT('_','b','f','r')
+
+
+/*****************************************************************************/
+
+typedef struct android_native_base_t
+{
+ /* a magic value defined by the actual EGL native type */
+ int magic;
+
+ /* the sizeof() of the actual EGL native type */
+ int version;
+
+ void* reserved[4];
+
+ /* reference-counting interface */
+ void (*incRef)(struct android_native_base_t* base);
+ void (*decRef)(struct android_native_base_t* base);
+} android_native_base_t;
+
+typedef struct ANativeWindowBuffer
+{
+#ifdef __cplusplus
+ ANativeWindowBuffer() {
+ common.magic = ANDROID_NATIVE_BUFFER_MAGIC;
+ common.version = sizeof(ANativeWindowBuffer);
+ memset(common.reserved, 0, sizeof(common.reserved));
+ }
+
+ // Implement the methods that sp<ANativeWindowBuffer> expects so that it
+ // can be used to automatically refcount ANativeWindowBuffer's.
+ void incStrong(const void* /*id*/) const {
+ common.incRef(const_cast<android_native_base_t*>(&common));
+ }
+ void decStrong(const void* /*id*/) const {
+ common.decRef(const_cast<android_native_base_t*>(&common));
+ }
+#endif
+
+ struct android_native_base_t common;
+
+ int width;
+ int height;
+ int stride;
+ int format;
+ int usage;
+ uintptr_t layerCount;
+
+ void* reserved[1];
+
+ const native_handle_t* handle;
+
+ void* reserved_proc[8];
+} ANativeWindowBuffer_t;
+
+typedef struct ANativeWindowBuffer ANativeWindowBuffer;
+
+/*****************************************************************************/
+
+
+/*
+ * Stores a value into one of the 4 available slots
+ * Retrieve the value with ANativeWindow_OemStorageGet()
+ *
+ * slot: 0 to 3
+ *
+ * Returns 0 on success or -errno on error.
+ */
+int ANativeWindow_OemStorageSet(ANativeWindow* window, uint32_t slot, intptr_t value);
+
+
+/*
+ * Retrieves a value from one of the 4 available slots
+ * By default the returned value is 0 if it wasn't set by ANativeWindow_OemStorageSet()
+ *
+ * slot: 0 to 3
+ *
+ * Returns 0 on success or -errno on error.
+ */
+int ANativeWindow_OemStorageGet(ANativeWindow* window, uint32_t slot, intptr_t* value);
+
+
+/*
+ * Set the swap interval for this surface.
+ *
+ * Returns 0 on success or -errno on error.
+ */
+int ANativeWindow_setSwapInterval(ANativeWindow* window, int interval);
+
+
+/*
+ * queries that can be used with ANativeWindow_query() and ANativeWindow_queryf()
+ */
+enum ANativeWindowQuery {
+ /* The minimum number of buffers that must remain un-dequeued after a buffer
+ * has been queued. This value applies only if set_buffer_count was used to
+ * override the number of buffers and if a buffer has since been queued.
+ * Users of the set_buffer_count ANativeWindow method should query this
+ * value before calling set_buffer_count. If it is necessary to have N
+ * buffers simultaneously dequeued as part of the steady-state operation,
+ * and this query returns M then N+M buffers should be requested via
+ * native_window_set_buffer_count.
+ *
+ * Note that this value does NOT apply until a single buffer has been
+ * queued. In particular this means that it is possible to:
+ *
+ * 1. Query M = min undequeued buffers
+ * 2. Set the buffer count to N + M
+ * 3. Dequeue all N + M buffers
+ * 4. Cancel M buffers
+ * 5. Queue, dequeue, queue, dequeue, ad infinitum
+ */
+ ANATIVEWINDOW_QUERY_MIN_UNDEQUEUED_BUFFERS = 3,
+
+ /*
+ * Default width of ANativeWindow buffers, these are the
+ * dimensions of the window buffers irrespective of the
+ * ANativeWindow_setBuffersDimensions() call and match the native window
+ * size.
+ */
+ ANATIVEWINDOW_QUERY_DEFAULT_WIDTH = 6,
+ ANATIVEWINDOW_QUERY_DEFAULT_HEIGHT = 7,
+
+ /*
+ * transformation that will most-likely be applied to buffers. This is only
+ * a hint, the actual transformation applied might be different.
+ *
+ * INTENDED USE:
+ *
+ * The transform hint can be used by a producer, for instance the GLES
+ * driver, to pre-rotate the rendering such that the final transformation
+ * in the composer is identity. This can be very useful when used in
+ * conjunction with the h/w composer HAL, in situations where it
+ * cannot handle arbitrary rotations.
+ *
+ * 1. Before dequeuing a buffer, the GL driver (or any other ANW client)
+ * queries the ANW for NATIVE_WINDOW_TRANSFORM_HINT.
+ *
+ * 2. The GL driver overrides the width and height of the ANW to
+ * account for NATIVE_WINDOW_TRANSFORM_HINT. This is done by querying
+ * NATIVE_WINDOW_DEFAULT_{WIDTH | HEIGHT}, swapping the dimensions
+ * according to NATIVE_WINDOW_TRANSFORM_HINT and calling
+ * native_window_set_buffers_dimensions().
+ *
+ * 3. The GL driver dequeues a buffer of the new pre-rotated size.
+ *
+ * 4. The GL driver renders to the buffer such that the image is
+ * already transformed, that is applying NATIVE_WINDOW_TRANSFORM_HINT
+ * to the rendering.
+ *
+ * 5. The GL driver calls native_window_set_transform to apply
+ * inverse transformation to the buffer it just rendered.
+ * In order to do this, the GL driver needs
+ * to calculate the inverse of NATIVE_WINDOW_TRANSFORM_HINT, this is
+ * done easily:
+ *
+ * int hintTransform, inverseTransform;
+ * query(..., NATIVE_WINDOW_TRANSFORM_HINT, &hintTransform);
+ * inverseTransform = hintTransform;
+ * if (hintTransform & HAL_TRANSFORM_ROT_90)
+ * inverseTransform ^= HAL_TRANSFORM_ROT_180;
+ *
+ *
+ * 6. The GL driver queues the pre-transformed buffer.
+ *
+ * 7. The composer combines the buffer transform with the display
+ * transform. If the buffer transform happens to cancel out the
+ * display transform then no rotation is needed.
+ *
+ */
+ ANATIVEWINDOW_QUERY_TRANSFORM_HINT = 8,
+
+ /*
+ * Returns the age of the contents of the most recently dequeued buffer as
+ * the number of frames that have elapsed since it was last queued. For
+ * example, if the window is double-buffered, the age of any given buffer in
+ * steady state will be 2. If the dequeued buffer has never been queued, its
+ * age will be 0.
+ */
+ ANATIVEWINDOW_QUERY_BUFFER_AGE = 13,
+
+ /* min swap interval supported by this compositor */
+ ANATIVEWINDOW_QUERY_MIN_SWAP_INTERVAL = 0x10000,
+
+ /* max swap interval supported by this compositor */
+ ANATIVEWINDOW_QUERY_MAX_SWAP_INTERVAL = 0x10001,
+
+ /* horizontal resolution in DPI. value is float, use queryf() */
+ ANATIVEWINDOW_QUERY_XDPI = 0x10002,
+
+ /* vertical resolution in DPI. value is float, use queryf() */
+ ANATIVEWINDOW_QUERY_YDPI = 0x10003,
+};
+
+typedef enum ANativeWindowQuery ANativeWindowQuery;
+
+/*
+ * hook used to retrieve information about the native window.
+ *
+ * Returns 0 on success or -errno on error.
+ */
+int ANativeWindow_query(const ANativeWindow* window, ANativeWindowQuery query, int* value);
+int ANativeWindow_queryf(const ANativeWindow* window, ANativeWindowQuery query, float* value);
+
+
+/*
+ * Hook called by EGL to acquire a buffer. This call may block if no
+ * buffers are available.
+ *
+ * The window holds a reference to the buffer between dequeueBuffer and
+ * either queueBuffer or cancelBuffer, so clients only need their own
+ * reference if they might use the buffer after queueing or canceling it.
+ * Holding a reference to a buffer after queueing or canceling it is only
+ * allowed if a specific buffer count has been set.
+ *
+ * The libsync fence file descriptor returned in the int pointed to by the
+ * fenceFd argument will refer to the fence that must signal before the
+ * dequeued buffer may be written to. A value of -1 indicates that the
+ * caller may access the buffer immediately without waiting on a fence. If
+ * a valid file descriptor is returned (i.e. any value except -1) then the
+ * caller is responsible for closing the file descriptor.
+ *
+ * Returns 0 on success or -errno on error.
+ */
+int ANativeWindow_dequeueBuffer(ANativeWindow* window, ANativeWindowBuffer** buffer, int* fenceFd);
+
+
+/*
+ * Hook called by EGL when modifications to the render buffer are done.
+ * This unlocks and post the buffer.
+ *
+ * The window holds a reference to the buffer between dequeueBuffer and
+ * either queueBuffer or cancelBuffer, so clients only need their own
+ * reference if they might use the buffer after queueing or canceling it.
+ * Holding a reference to a buffer after queueing or canceling it is only
+ * allowed if a specific buffer count has been set.
+ *
+ * The fenceFd argument specifies a libsync fence file descriptor for a
+ * fence that must signal before the buffer can be accessed. If the buffer
+ * can be accessed immediately then a value of -1 should be used. The
+ * caller must not use the file descriptor after it is passed to
+ * queueBuffer, and the ANativeWindow implementation is responsible for
+ * closing it.
+ *
+ * Returns 0 on success or -errno on error.
+ */
+int ANativeWindow_queueBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer, int fenceFd);
+
+
+/*
+ * Hook used to cancel a buffer that has been dequeued.
+ * No synchronization is performed between dequeue() and cancel(), so
+ * either external synchronization is needed, or these functions must be
+ * called from the same thread.
+ *
+ * The window holds a reference to the buffer between dequeueBuffer and
+ * either queueBuffer or cancelBuffer, so clients only need their own
+ * reference if they might use the buffer after queueing or canceling it.
+ * Holding a reference to a buffer after queueing or canceling it is only
+ * allowed if a specific buffer count has been set.
+ *
+ * The fenceFd argument specifies a libsync fence file decsriptor for a
+ * fence that must signal before the buffer can be accessed. If the buffer
+ * can be accessed immediately then a value of -1 should be used.
+ *
+ * Note that if the client has not waited on the fence that was returned
+ * from dequeueBuffer, that same fence should be passed to cancelBuffer to
+ * ensure that future uses of the buffer are preceded by a wait on that
+ * fence. The caller must not use the file descriptor after it is passed
+ * to cancelBuffer, and the ANativeWindow implementation is responsible for
+ * closing it.
+ *
+ * Returns 0 on success or -errno on error.
+ */
+int ANativeWindow_cancelBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer, int fenceFd);
+
+/*
+ * Sets the intended usage flags for the next buffers.
+ *
+ * usage: one of AHARDWAREBUFFER_USAGE0_* constant
+ * privateUsage: one of AHARDWAREBUFFER_USAGE1_*_PRIVATE_* constant
+ *
+ * By default (if this function is never called), a usage of
+ * AHARDWAREBUFFER_USAGE0_GPU_SAMPLED_IMAGE | AHARDWAREBUFFER_USAGE0_GPU_COLOR_OUTPUT
+ * is assumed.
+ *
+ * Calling this function will usually cause following buffers to be
+ * reallocated.
+ */
+int ANativeWindow_setUsage(ANativeWindow* window, uint64_t usage0, uint64_t usage1);
+
+
+/*
+ * Sets the number of buffers associated with this native window.
+ */
+int ANativeWindow_setBufferCount(ANativeWindow* window, size_t bufferCount);
+
+
+/*
+ * All buffers dequeued after this call will have the dimensions specified.
+ * In particular, all buffers will have a fixed-size, independent from the
+ * native-window size. They will be scaled according to the scaling mode
+ * (see native_window_set_scaling_mode) upon window composition.
+ *
+ * If w and h are 0, the normal behavior is restored. That is, dequeued buffers
+ * following this call will be sized to match the window's size.
+ *
+ * Calling this function will reset the window crop to a NULL value, which
+ * disables cropping of the buffers.
+ */
+int ANativeWindow_setBuffersDimensions(ANativeWindow* window, uint32_t w, uint32_t h);
+
+
+/*
+ * All buffers dequeued after this call will have the format specified.
+ * format: one of AHARDWAREBUFFER_FORMAT_* constant
+ *
+ * If the specified format is 0, the default buffer format will be used.
+ */
+int ANativeWindow_setBuffersFormat(ANativeWindow* window, int format);
+
+
+/*
+ * All buffers queued after this call will be associated with the timestamp in nanosecond
+ * parameter specified. If the timestamp is set to NATIVE_WINDOW_TIMESTAMP_AUTO
+ * (the default), timestamps will be generated automatically when queueBuffer is
+ * called. The timestamp is measured in nanoseconds, and is normally monotonically
+ * increasing. The timestamp should be unaffected by time-of-day adjustments,
+ * and for a camera should be strictly monotonic but for a media player may be
+ * reset when the position is set.
+ */
+int ANativeWindow_setBuffersTimestamp(ANativeWindow* window, int64_t timestamp);
+
+
+/*
+ * All buffers queued after this call will be associated with the dataSpace
+ * parameter specified.
+ *
+ * dataSpace specifies additional information about the buffer that's dependent
+ * on the buffer format and the endpoints. For example, it can be used to convey
+ * the color space of the image data in the buffer, or it can be used to
+ * indicate that the buffers contain depth measurement data instead of color
+ * images. The default dataSpace is 0, HAL_DATASPACE_UNKNOWN, unless it has been
+ * overridden by the consumer.
+ */
+int ANativeWindow_setBufferDataSpace(ANativeWindow* window, android_dataspace_t dataSpace);
+
+
+/*
+ * Enable/disable shared buffer mode
+ */
+int ANativeWindow_setSharedBufferMode(ANativeWindow* window, bool sharedBufferMode);
+
+
+/*
+ * Enable/disable auto refresh when in shared buffer mode
+ */
+int ANativeWindow_setAutoRefresh(ANativeWindow* window, bool autoRefresh);
+
+
+/*****************************************************************************/
+
+__END_DECLS
+
+#endif /* ANDROID_VNDK_NATIVEWINDOW_ANATIVEWINDOW_H */
diff --git a/libs/nativewindow/tests/Android.bp b/libs/nativewindow/tests/Android.bp
index 437ab75..6d78770 100644
--- a/libs/nativewindow/tests/Android.bp
+++ b/libs/nativewindow/tests/Android.bp
@@ -17,5 +17,7 @@
cc_test {
name: "AHardwareBufferTest",
shared_libs: ["libnativewindow"],
- srcs: ["AHardwareBufferTest.cpp"],
+ srcs: [
+ "AHardwareBufferTest.cpp",
+ "c_compatibility.c"],
}
diff --git a/libs/nativewindow/tests/c_compatibility.c b/libs/nativewindow/tests/c_compatibility.c
new file mode 100644
index 0000000..a0dfdf9
--- /dev/null
+++ b/libs/nativewindow/tests/c_compatibility.c
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android/hardware_buffer.h>
+#include <android/native_window.h>
+#include <vndk/window.h>
+
+// this checks that all these headers are C-compatible
diff --git a/libs/ui/Android.bp b/libs/ui/Android.bp
index d1bfa18..80fb064 100644
--- a/libs/ui/Android.bp
+++ b/libs/ui/Android.bp
@@ -78,6 +78,7 @@
static_libs: [
"libarect",
+ "libgrallocusage",
"libmath",
],
diff --git a/libs/ui/ColorSpace.cpp b/libs/ui/ColorSpace.cpp
index 49390d9..5b4bf23 100644
--- a/libs/ui/ColorSpace.cpp
+++ b/libs/ui/ColorSpace.cpp
@@ -20,6 +20,83 @@
namespace android {
+static constexpr float linearResponse(float v) {
+ return v;
+}
+
+static constexpr float rcpResponse(float x, const ColorSpace::TransferParameters& p) {
+ return x >= p.d * p.c ? (std::pow(x, 1.0f / p.g) - p.b) / p.a : x / p.c;
+}
+
+static constexpr float response(float x, const ColorSpace::TransferParameters& p) {
+ return x >= p.d ? std::pow(p.a * x + p.b, p.g) : p.c * x;
+}
+
+static constexpr float rcpFullResponse(float x, const ColorSpace::TransferParameters& p) {
+ return x >= p.d * p.c ? (std::pow(x - p.e, 1.0f / p.g) - p.b) / p.a : (x - p.f) / p.c;
+}
+
+static constexpr float fullResponse(float x, const ColorSpace::TransferParameters& p) {
+ return x >= p.d ? std::pow(p.a * x + p.b, p.g) + p.e : p.c * x + p.f;
+}
+
+static float absRcpResponse(float x, float g,float a, float b, float c, float d) {
+ float xx = std::abs(x);
+ return std::copysign(xx >= d * c ? (std::pow(xx, 1.0f / g) - b) / a : xx / c, x);
+}
+
+static float absResponse(float x, float g, float a, float b, float c, float d) {
+ float xx = std::abs(x);
+ return std::copysign(xx >= d ? std::pow(a * xx + b, g) : c * xx, x);
+}
+
+static float safePow(float x, float e) {
+ return powf(x < 0.0f ? 0.0f : x, e);
+}
+
+static ColorSpace::transfer_function toOETF(const ColorSpace::TransferParameters& parameters) {
+ if (parameters.e == 0.0f && parameters.f == 0.0f) {
+ return std::bind(rcpResponse, _1, parameters);
+ }
+ return std::bind(rcpFullResponse, _1, parameters);
+}
+
+static ColorSpace::transfer_function toEOTF( const ColorSpace::TransferParameters& parameters) {
+ if (parameters.e == 0.0f && parameters.f == 0.0f) {
+ return std::bind(response, _1, parameters);
+ }
+ return std::bind(fullResponse, _1, parameters);
+}
+
+static ColorSpace::transfer_function toOETF(float gamma) {
+ if (gamma == 1.0f) {
+ return linearResponse;
+ }
+ return std::bind(safePow, _1, 1.0f / gamma);
+}
+
+static ColorSpace::transfer_function toEOTF(float gamma) {
+ if (gamma == 1.0f) {
+ return linearResponse;
+ }
+ return std::bind(safePow, _1, gamma);
+}
+
+static constexpr std::array<float2, 3> computePrimaries(const mat3& rgbToXYZ) {
+ float3 r(rgbToXYZ * float3{1, 0, 0});
+ float3 g(rgbToXYZ * float3{0, 1, 0});
+ float3 b(rgbToXYZ * float3{0, 0, 1});
+
+ return {{r.xy / dot(r, float3{1}),
+ g.xy / dot(g, float3{1}),
+ b.xy / dot(b, float3{1})}};
+}
+
+static constexpr float2 computeWhitePoint(const mat3& rgbToXYZ) {
+ float3 w(rgbToXYZ * float3{1});
+ return w.xy / dot(w, float3{1});
+}
+
ColorSpace::ColorSpace(
const std::string& name,
const mat3& rgbToXYZ,
@@ -31,18 +108,41 @@
, mXYZtoRGB(inverse(rgbToXYZ))
, mOETF(std::move(OETF))
, mEOTF(std::move(EOTF))
- , mClamper(std::move(clamper)) {
+ , mClamper(std::move(clamper))
+ , mPrimaries(computePrimaries(rgbToXYZ))
+ , mWhitePoint(computeWhitePoint(rgbToXYZ)) {
+}
- float3 r(rgbToXYZ * float3{1, 0, 0});
- float3 g(rgbToXYZ * float3{0, 1, 0});
- float3 b(rgbToXYZ * float3{0, 0, 1});
+ColorSpace::ColorSpace(
+ const std::string& name,
+ const mat3& rgbToXYZ,
+ const TransferParameters parameters,
+ clamping_function clamper) noexcept
+ : mName(name)
+ , mRGBtoXYZ(rgbToXYZ)
+ , mXYZtoRGB(inverse(rgbToXYZ))
+ , mParameters(parameters)
+ , mOETF(toOETF(mParameters))
+ , mEOTF(toEOTF(mParameters))
+ , mClamper(std::move(clamper))
+ , mPrimaries(computePrimaries(rgbToXYZ))
+ , mWhitePoint(computeWhitePoint(rgbToXYZ)) {
+}
- mPrimaries[0] = r.xy / dot(r, float3{1});
- mPrimaries[1] = g.xy / dot(g, float3{1});
- mPrimaries[2] = b.xy / dot(b, float3{1});
-
- float3 w(rgbToXYZ * float3{1});
- mWhitePoint = w.xy / dot(w, float3{1});
+ColorSpace::ColorSpace(
+ const std::string& name,
+ const mat3& rgbToXYZ,
+ float gamma,
+ clamping_function clamper) noexcept
+ : mName(name)
+ , mRGBtoXYZ(rgbToXYZ)
+ , mXYZtoRGB(inverse(rgbToXYZ))
+ , mParameters({gamma, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f})
+ , mOETF(toOETF(gamma))
+ , mEOTF(toEOTF(gamma))
+ , mClamper(std::move(clamper))
+ , mPrimaries(computePrimaries(rgbToXYZ))
+ , mWhitePoint(computeWhitePoint(rgbToXYZ)) {
}
ColorSpace::ColorSpace(
@@ -62,6 +162,40 @@
, mWhitePoint(whitePoint) {
}
+ColorSpace::ColorSpace(
+ const std::string& name,
+ const std::array<float2, 3>& primaries,
+ const float2& whitePoint,
+ const TransferParameters parameters,
+ clamping_function clamper) noexcept
+ : mName(name)
+ , mRGBtoXYZ(computeXYZMatrix(primaries, whitePoint))
+ , mXYZtoRGB(inverse(mRGBtoXYZ))
+ , mParameters(parameters)
+ , mOETF(toOETF(mParameters))
+ , mEOTF(toEOTF(mParameters))
+ , mClamper(std::move(clamper))
+ , mPrimaries(primaries)
+ , mWhitePoint(whitePoint) {
+}
+
+ColorSpace::ColorSpace(
+ const std::string& name,
+ const std::array<float2, 3>& primaries,
+ const float2& whitePoint,
+ float gamma,
+ clamping_function clamper) noexcept
+ : mName(name)
+ , mRGBtoXYZ(computeXYZMatrix(primaries, whitePoint))
+ , mXYZtoRGB(inverse(mRGBtoXYZ))
+ , mParameters({gamma, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f})
+ , mOETF(toOETF(gamma))
+ , mEOTF(toEOTF(gamma))
+ , mClamper(std::move(clamper))
+ , mPrimaries(primaries)
+ , mWhitePoint(whitePoint) {
+}
+
constexpr mat3 ColorSpace::computeXYZMatrix(
const std::array<float2, 3>& primaries, const float2& whitePoint) {
const float2& R = primaries[0];
@@ -96,33 +230,12 @@
};
}
-static constexpr float rcpResponse(float x, float g,float a, float b, float c, float d) {
- return x >= d * c ? (std::pow(x, 1.0f / g) - b) / a : x / c;
-}
-
-static constexpr float response(float x, float g, float a, float b, float c, float d) {
- return x >= d ? std::pow(a * x + b, g) : c * x;
-}
-
-static float absRcpResponse(float x, float g,float a, float b, float c, float d) {
- return std::copysign(rcpResponse(std::abs(x), g, a, b, c, d), x);
-}
-
-static float absResponse(float x, float g, float a, float b, float c, float d) {
- return std::copysign(response(std::abs(x), g, a, b, c, d), x);
-}
-
-static float safePow(float x, float e) {
- return powf(x < 0.0f ? 0.0f : x, e);
-}
-
const ColorSpace ColorSpace::sRGB() {
return {
"sRGB IEC61966-2.1",
{{float2{0.640f, 0.330f}, {0.300f, 0.600f}, {0.150f, 0.060f}}},
{0.3127f, 0.3290f},
- std::bind(rcpResponse, _1, 2.4f, 1 / 1.055f, 0.055f / 1.055f, 1 / 12.92f, 0.04045f),
- std::bind(response, _1, 2.4f, 1 / 1.055f, 0.055f / 1.055f, 1 / 12.92f, 0.04045f)
+ {2.4f, 1 / 1.055f, 0.055f / 1.055f, 1 / 12.92f, 0.04045f, 0.0f, 0.0f}
};
}
@@ -150,8 +263,7 @@
"scRGB IEC 61966-2-2:2003",
{{float2{0.640f, 0.330f}, {0.300f, 0.600f}, {0.150f, 0.060f}}},
{0.3127f, 0.3290f},
- linearReponse,
- linearReponse,
+ 1.0f,
std::bind(clamp<float>, _1, -0.5f, 7.499f)
};
}
@@ -161,8 +273,7 @@
"NTSC (1953)",
{{float2{0.67f, 0.33f}, {0.21f, 0.71f}, {0.14f, 0.08f}}},
{0.310f, 0.316f},
- std::bind(rcpResponse, _1, 1 / 0.45f, 1 / 1.099f, 0.099f / 1.099f, 1 / 4.5f, 0.081f),
- std::bind(response, _1, 1 / 0.45f, 1 / 1.099f, 0.099f / 1.099f, 1 / 4.5f, 0.081f)
+ {1 / 0.45f, 1 / 1.099f, 0.099f / 1.099f, 1 / 4.5f, 0.081f, 0.0f, 0.0f}
};
}
@@ -171,8 +282,7 @@
"Rec. ITU-R BT.709-5",
{{float2{0.640f, 0.330f}, {0.300f, 0.600f}, {0.150f, 0.060f}}},
{0.3127f, 0.3290f},
- std::bind(rcpResponse, _1, 1 / 0.45f, 1 / 1.099f, 0.099f / 1.099f, 1 / 4.5f, 0.081f),
- std::bind(response, _1, 1 / 0.45f, 1 / 1.099f, 0.099f / 1.099f, 1 / 4.5f, 0.081f)
+ {1 / 0.45f, 1 / 1.099f, 0.099f / 1.099f, 1 / 4.5f, 0.081f, 0.0f, 0.0f}
};
}
@@ -181,8 +291,7 @@
"Rec. ITU-R BT.2020-1",
{{float2{0.708f, 0.292f}, {0.170f, 0.797f}, {0.131f, 0.046f}}},
{0.3127f, 0.3290f},
- std::bind(rcpResponse, _1, 1 / 0.45f, 1 / 1.099f, 0.099f / 1.099f, 1 / 4.5f, 0.081f),
- std::bind(response, _1, 1 / 0.45f, 1 / 1.099f, 0.099f / 1.099f, 1 / 4.5f, 0.081f)
+ {1 / 0.45f, 1 / 1.099f, 0.099f / 1.099f, 1 / 4.5f, 0.081f, 0.0f, 0.0f}
};
}
@@ -191,8 +300,7 @@
"Adobe RGB (1998)",
{{float2{0.64f, 0.33f}, {0.21f, 0.71f}, {0.15f, 0.06f}}},
{0.3127f, 0.3290f},
- std::bind(safePow, _1, 1.0f / 2.2f),
- std::bind(safePow, _1, 2.2f)
+ 2.2f
};
}
@@ -201,8 +309,7 @@
"ROMM RGB ISO 22028-2:2013",
{{float2{0.7347f, 0.2653f}, {0.1596f, 0.8404f}, {0.0366f, 0.0001f}}},
{0.34567f, 0.35850f},
- std::bind(rcpResponse, _1, 1.8f, 1.0f, 0.0f, 1 / 16.0f, 0.031248f),
- std::bind(response, _1, 1.8f, 1.0f, 0.0f, 1 / 16.0f, 0.031248f)
+ {1.8f, 1.0f, 0.0f, 1 / 16.0f, 0.031248f, 0.0f, 0.0f}
};
}
@@ -211,8 +318,7 @@
"Display P3",
{{float2{0.680f, 0.320f}, {0.265f, 0.690f}, {0.150f, 0.060f}}},
{0.3127f, 0.3290f},
- std::bind(rcpResponse, _1, 2.4f, 1 / 1.055f, 0.055f / 1.055f, 1 / 12.92f, 0.039f),
- std::bind(response, _1, 2.4f, 1 / 1.055f, 0.055f / 1.055f, 1 / 12.92f, 0.039f)
+ {2.4f, 1 / 1.055f, 0.055f / 1.055f, 1 / 12.92f, 0.039f, 0.0f, 0.0f}
};
}
@@ -221,8 +327,7 @@
"SMPTE RP 431-2-2007 DCI (P3)",
{{float2{0.680f, 0.320f}, {0.265f, 0.690f}, {0.150f, 0.060f}}},
{0.314f, 0.351f},
- std::bind(safePow, _1, 1.0f / 2.6f),
- std::bind(safePow, _1, 2.6f)
+ 2.6f
};
}
@@ -231,8 +336,7 @@
"SMPTE ST 2065-1:2012 ACES",
{{float2{0.73470f, 0.26530f}, {0.0f, 1.0f}, {0.00010f, -0.0770f}}},
{0.32168f, 0.33767f},
- linearReponse,
- linearReponse,
+ 1.0f,
std::bind(clamp<float>, _1, -65504.0f, 65504.0f)
};
}
@@ -242,12 +346,33 @@
"Academy S-2014-004 ACEScg",
{{float2{0.713f, 0.293f}, {0.165f, 0.830f}, {0.128f, 0.044f}}},
{0.32168f, 0.33767f},
- linearReponse,
- linearReponse,
+ 1.0f,
std::bind(clamp<float>, _1, -65504.0f, 65504.0f)
};
}
+std::unique_ptr<float3> ColorSpace::createLUT(uint32_t size,
+ const ColorSpace& src, const ColorSpace& dst) {
+
+ size = clamp(size, 2u, 256u);
+ float m = 1.0f / float(size - 1);
+
+ std::unique_ptr<float3> lut(new float3[size * size * size]);
+ float3* data = lut.get();
+
+ ColorSpaceConnector connector(src, dst);
+
+ for (uint32_t z = 0; z < size; z++) {
+ for (int32_t y = int32_t(size - 1); y >= 0; y--) {
+ for (uint32_t x = 0; x < size; x++) {
+ *data++ = connector.transform({x * m, y * m, z * m});
+ }
+ }
+ }
+
+ return lut;
+}
+
static const float2 ILLUMINANT_D50_XY = {0.34567f, 0.35850f};
static const float3 ILLUMINANT_D50_XYZ = {0.964212f, 1.0f, 0.825188f};
static const mat3 BRADFORD = mat3{
@@ -262,7 +387,7 @@
return inverse(matrix) * mat3{dstLMS / srcLMS} * matrix;
}
-ColorSpace::Connector::Connector(
+ColorSpaceConnector::ColorSpaceConnector(
const ColorSpace& src,
const ColorSpace& dst) noexcept
: mSource(src)
@@ -274,8 +399,8 @@
mat3 rgbToXYZ(src.getRGBtoXYZ());
mat3 xyzToRGB(dst.getXYZtoRGB());
- float3 srcXYZ = XYZ(float3{src.getWhitePoint(), 1});
- float3 dstXYZ = XYZ(float3{dst.getWhitePoint(), 1});
+ float3 srcXYZ = ColorSpace::XYZ(float3{src.getWhitePoint(), 1});
+ float3 dstXYZ = ColorSpace::XYZ(float3{dst.getWhitePoint(), 1});
if (any(greaterThan(abs(src.getWhitePoint() - ILLUMINANT_D50_XY), float2{1e-3f}))) {
rgbToXYZ = adaptation(BRADFORD, srcXYZ, ILLUMINANT_D50_XYZ) * src.getRGBtoXYZ();
@@ -289,27 +414,4 @@
}
}
-std::unique_ptr<float3> ColorSpace::createLUT(uint32_t size,
- const ColorSpace& src, const ColorSpace& dst) {
-
- size = clamp(size, 2u, 256u);
- float m = 1.0f / float(size - 1);
-
- std::unique_ptr<float3> lut(new float3[size * size * size]);
- float3* data = lut.get();
-
- Connector connector(src, dst);
-
- for (uint32_t z = 0; z < size; z++) {
- for (int32_t y = int32_t(size - 1); y >= 0; y--) {
- for (uint32_t x = 0; x < size; x++) {
- *data++ = connector.transform({x * m, y * m, z * m});
- }
- }
- }
-
- return lut;
-}
-
-
}; // namespace android
diff --git a/libs/ui/Gralloc1On0Adapter.cpp b/libs/ui/Gralloc1On0Adapter.cpp
index b8bc6c4..bd7c6a1 100644
--- a/libs/ui/Gralloc1On0Adapter.cpp
+++ b/libs/ui/Gralloc1On0Adapter.cpp
@@ -20,6 +20,7 @@
#include <ui/Gralloc1On0Adapter.h>
+#include <grallocusage/GrallocUsageConversion.h>
#include <hardware/gralloc.h>
@@ -248,8 +249,8 @@
// pointer, which only occurs when mDevice has been loaded successfully and
// we are permitted to allocate
- int usage = static_cast<int>(descriptor->producerUsage) |
- static_cast<int>(descriptor->consumerUsage);
+ int usage = android_convertGralloc1To0Usage(descriptor->producerUsage,
+ descriptor->consumerUsage);
buffer_handle_t handle = nullptr;
int stride = 0;
ALOGV("Calling alloc(%p, %u, %u, %i, %u)", mDevice, descriptor->width,
@@ -374,7 +375,7 @@
{
if (mMinorVersion >= 3) {
int result = mModule->lockAsync(mModule, buffer->getHandle(),
- static_cast<int32_t>(producerUsage | consumerUsage),
+ android_convertGralloc1To0Usage(producerUsage, consumerUsage),
accessRegion.left, accessRegion.top, accessRegion.width,
accessRegion.height, outData, acquireFence->dup());
if (result != 0) {
@@ -383,7 +384,7 @@
} else {
acquireFence->waitForever("Gralloc1On0Adapter::lock");
int result = mModule->lock(mModule, buffer->getHandle(),
- static_cast<int32_t>(producerUsage | consumerUsage),
+ android_convertGralloc1To0Usage(producerUsage, consumerUsage),
accessRegion.left, accessRegion.top, accessRegion.width,
accessRegion.height, outData);
ALOGV("gralloc0 lock returned %d", result);
@@ -415,7 +416,7 @@
{
if (mMinorVersion >= 3 && mModule->lockAsync_ycbcr) {
int result = mModule->lockAsync_ycbcr(mModule, buffer->getHandle(),
- static_cast<int>(producerUsage | consumerUsage),
+ android_convertGralloc1To0Usage(producerUsage, consumerUsage),
accessRegion.left, accessRegion.top, accessRegion.width,
accessRegion.height, outData, acquireFence->dup());
if (result != 0) {
@@ -424,7 +425,7 @@
} else if (mModule->lock_ycbcr) {
acquireFence->waitForever("Gralloc1On0Adapter::lockYCbCr");
int result = mModule->lock_ycbcr(mModule, buffer->getHandle(),
- static_cast<int>(producerUsage | consumerUsage),
+ android_convertGralloc1To0Usage(producerUsage, consumerUsage),
accessRegion.left, accessRegion.top, accessRegion.width,
accessRegion.height, outData);
ALOGV("gralloc0 lockYCbCr returned %d", result);
diff --git a/libs/ui/GraphicBuffer.cpp b/libs/ui/GraphicBuffer.cpp
index 9006178..6e84730 100644
--- a/libs/ui/GraphicBuffer.cpp
+++ b/libs/ui/GraphicBuffer.cpp
@@ -16,12 +16,12 @@
#define LOG_TAG "GraphicBuffer"
-#include <cutils/atomic.h>
-
#include <ui/GraphicBuffer.h>
#include <cutils/atomic.h>
+#include <grallocusage/GrallocUsageConversion.h>
+
#include <ui/GrallocMapper.h>
#include <ui/GraphicBufferAllocator.h>
#include <ui/GraphicBufferMapper.h>
@@ -114,7 +114,7 @@
stride = static_cast<int>(inStride);
format = inFormat;
layerCount = inLayerCount;
- usage = static_cast<int>(inConsumerUsage | inProducerUsage);
+ usage = android_convertGralloc1To0Usage(inProducerUsage, inConsumerUsage);
handle = inHandle;
}
@@ -221,7 +221,7 @@
height = static_cast<int>(inHeight);
format = inFormat;
layerCount = inLayerCount;
- usage = static_cast<int>(inProducerUsage | inConsumerUsage);
+ usage = android_convertGralloc1To0Usage(inProducerUsage, inConsumerUsage);
stride = static_cast<int>(outStride);
}
return err;
diff --git a/libs/ui/tests/colorspace_test.cpp b/libs/ui/tests/colorspace_test.cpp
index 1e359d3..0a4873c 100644
--- a/libs/ui/tests/colorspace_test.cpp
+++ b/libs/ui/tests/colorspace_test.cpp
@@ -152,12 +152,12 @@
TEST_F(ColorSpaceTest, Connect) {
// No chromatic adaptation
- auto r = ColorSpace::connect(ColorSpace::sRGB(), ColorSpace::AdobeRGB())
+ auto r = ColorSpaceConnector(ColorSpace::sRGB(), ColorSpace::AdobeRGB())
.transform({1.0f, 0.5f, 0.0f});
EXPECT_TRUE(all(lessThan(abs(r - float3{0.8912f, 0.4962f, 0.1164f}), float3{1e-4f})));
// Test with chromatic adaptation
- r = ColorSpace::connect(ColorSpace::sRGB(), ColorSpace::ProPhotoRGB())
+ r = ColorSpaceConnector(ColorSpace::sRGB(), ColorSpace::ProPhotoRGB())
.transform({1.0f, 0.0f, 0.0f});
EXPECT_TRUE(all(lessThan(abs(r - float3{0.70226f, 0.2757f, 0.1036f}), float3{1e-4f})));
}
diff --git a/libs/vr/libbufferhub/Android.bp b/libs/vr/libbufferhub/Android.bp
index e068469..452bad0 100644
--- a/libs/vr/libbufferhub/Android.bp
+++ b/libs/vr/libbufferhub/Android.bp
@@ -15,7 +15,6 @@
sourceFiles = [
"buffer_hub_client.cpp",
"buffer_hub_rpc.cpp",
- "dvr_buffer.cpp",
"ion_buffer.cpp",
]
diff --git a/libs/vr/libbufferhubqueue/Android.bp b/libs/vr/libbufferhubqueue/Android.bp
index 1c8f2c0..0fa1f01 100644
--- a/libs/vr/libbufferhubqueue/Android.bp
+++ b/libs/vr/libbufferhubqueue/Android.bp
@@ -42,8 +42,8 @@
cc_library {
name: "libbufferhubqueue",
- cflags = [
- "-DLOGTAG=\"libbufferhubqueue\"",
+ cflags: [
+ "-DLOG_TAG=\"libbufferhubqueue\"",
"-DTRACE=0",
],
srcs: sourceFiles,
diff --git a/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h b/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h
index feaf3d7..f786356 100644
--- a/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h
+++ b/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h
@@ -329,6 +329,9 @@
return Dequeue(timeout, slot, meta, sizeof(*meta), acquire_fence);
}
+ std::shared_ptr<BufferConsumer> Dequeue(int timeout, size_t* slot, void* meta,
+ size_t meta_size,
+ LocalHandle* acquire_fence);
private:
friend BASE;
@@ -344,13 +347,27 @@
LocalHandle* acquire_fence) override;
int OnBufferAllocated() override;
-
- std::shared_ptr<BufferConsumer> Dequeue(int timeout, size_t* slot, void* meta,
- size_t meta_size,
- LocalHandle* acquire_fence);
};
} // namespace dvr
} // namespace android
+// Concrete C type definition for DVR API.
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct DvrWriteBufferQueue {
+ std::shared_ptr<android::dvr::ProducerQueue> producer_queue_;
+};
+
+struct DvrReadBufferQueue {
+ std::shared_ptr<android::dvr::ConsumerQueue> consumer_queue_;
+};
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
#endif // ANDROID_DVR_BUFFER_HUB_QUEUE_CLIENT_H_
diff --git a/libs/vr/libbufferhubqueue/tests/Android.bp b/libs/vr/libbufferhubqueue/tests/Android.bp
index b8a0da3..865573c 100644
--- a/libs/vr/libbufferhubqueue/tests/Android.bp
+++ b/libs/vr/libbufferhubqueue/tests/Android.bp
@@ -24,6 +24,7 @@
static_libs: static_libraries,
shared_libs: shared_libraries,
cflags: [
+ "-DLOG_TAG=\"buffer_hub_queue-test\"",
"-DTRACE=0",
"-O0",
"-g",
@@ -37,6 +38,7 @@
static_libs: static_libraries,
shared_libs: shared_libraries,
cflags: [
+ "-DLOG_TAG=\"buffer_hub_queue_producer-test\"",
"-DTRACE=0",
"-O0",
"-g",
diff --git a/libs/vr/libdisplay/Android.bp b/libs/vr/libdisplay/Android.bp
index f3c71b5..de2a56e 100644
--- a/libs/vr/libdisplay/Android.bp
+++ b/libs/vr/libdisplay/Android.bp
@@ -15,7 +15,6 @@
sourceFiles = [
"native_buffer_queue.cpp",
"display_client.cpp",
- "display_manager_client.cpp",
"display_manager_client_impl.cpp",
"display_rpc.cpp",
"dummy_native_window.cpp",
@@ -24,7 +23,6 @@
"late_latch.cpp",
"video_mesh_surface_client.cpp",
"vsync_client.cpp",
- "vsync_client_api.cpp",
"screenshot_client.cpp",
"frame_history.cpp",
]
diff --git a/libs/vr/libdisplay/graphics.cpp b/libs/vr/libdisplay/graphics.cpp
index 3713389..2abdf8e 100644
--- a/libs/vr/libdisplay/graphics.cpp
+++ b/libs/vr/libdisplay/graphics.cpp
@@ -17,7 +17,6 @@
#include <private/dvr/clock_ns.h>
#include <private/dvr/debug.h>
#include <private/dvr/display_types.h>
-#include <private/dvr/dvr_buffer.h>
#include <private/dvr/frame_history.h>
#include <private/dvr/gl_fenced_flush.h>
#include <private/dvr/graphics/vr_gl_extensions.h>
@@ -1575,14 +1574,3 @@
};
}
}
-
-extern "C" int dvrGetPoseBuffer(DvrReadBuffer** pose_buffer) {
- auto client = android::dvr::DisplayClient::Create();
- if (!client) {
- ALOGE("Failed to create display client!");
- return -ECOMM;
- }
-
- *pose_buffer = CreateDvrReadBufferFromBufferConsumer(client->GetPoseBuffer());
- return 0;
-}
diff --git a/libs/vr/libdisplay/include/dvr/graphics.h b/libs/vr/libdisplay/include/dvr/graphics.h
index fc51d52..ac8b27f 100644
--- a/libs/vr/libdisplay/include/dvr/graphics.h
+++ b/libs/vr/libdisplay/include/dvr/graphics.h
@@ -442,9 +442,6 @@
const int eye,
const float* transform);
-// Get a pointer to the global pose buffer.
-int dvrGetPoseBuffer(DvrReadBuffer** pose_buffer);
-
__END_DECLS
#endif // DVR_GRAPHICS_H_
diff --git a/libs/vr/libdisplay/include/private/dvr/vsync_client.h b/libs/vr/libdisplay/include/private/dvr/vsync_client.h
index 32fa40f..1eeb80e 100644
--- a/libs/vr/libdisplay/include/private/dvr/vsync_client.h
+++ b/libs/vr/libdisplay/include/private/dvr/vsync_client.h
@@ -4,7 +4,6 @@
#include <stdint.h>
#include <pdx/client.h>
-#include <private/dvr/vsync_client_api.h>
struct dvr_vsync_client {};
diff --git a/libs/vr/libdvr/Android.mk b/libs/vr/libdvr/Android.mk
new file mode 100644
index 0000000..3c6934b
--- /dev/null
+++ b/libs/vr/libdvr/Android.mk
@@ -0,0 +1,58 @@
+# Copyright (C) 2017 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := libdvr
+LOCAL_MODULE_OWNER := google
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+
+LOCAL_CFLAGS += \
+ -fvisibility=hidden \
+ -D DVR_EXPORT='__attribute__ ((visibility ("default")))'
+
+LOCAL_C_INCLUDES := \
+ $(LOCAL_PATH)/include \
+
+LOCAL_EXPORT_C_INCLUDE_DIRS := \
+ $(LOCAL_PATH)/include \
+
+LOCAL_SRC_FILES := \
+ display_manager_client.cpp \
+ dvr_api.cpp \
+ dvr_buffer.cpp \
+ dvr_buffer_queue.cpp \
+ dvr_hardware_composer_client.cpp \
+ dvr_surface.cpp \
+ vsync_client_api.cpp \
+
+LOCAL_STATIC_LIBRARIES := \
+ libbufferhub \
+ libbufferhubqueue \
+ libdisplay \
+ libvrsensor \
+ libvirtualtouchpadclient \
+ libvr_hwc-impl \
+ libvr_hwc-binder \
+
+LOCAL_SHARED_LIBRARIES := \
+ android.hardware.graphics.bufferqueue@1.0 \
+ android.hidl.token@1.0-utils \
+ libandroid_runtime \
+ libbase \
+ libnativewindow \
+
+include $(BUILD_STATIC_LIBRARY)
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/libs/vr/libdisplay/display_manager_client.cpp b/libs/vr/libdvr/display_manager_client.cpp
similarity index 97%
rename from libs/vr/libdisplay/display_manager_client.cpp
rename to libs/vr/libdvr/display_manager_client.cpp
index d60d35b..7cbfc21 100644
--- a/libs/vr/libdisplay/display_manager_client.cpp
+++ b/libs/vr/libdvr/display_manager_client.cpp
@@ -1,8 +1,8 @@
-#include "include/private/dvr/display_manager_client.h"
+#include "include/dvr/display_manager_client.h"
+#include <dvr/dvr_buffer.h>
#include <private/dvr/buffer_hub_client.h>
#include <private/dvr/display_manager_client_impl.h>
-#include <private/dvr/dvr_buffer.h>
using android::dvr::DisplaySurfaceAttributeEnum;
diff --git a/libs/vr/libdvr/dvr_api.cpp b/libs/vr/libdvr/dvr_api.cpp
new file mode 100644
index 0000000..bfb35c4
--- /dev/null
+++ b/libs/vr/libdvr/dvr_api.cpp
@@ -0,0 +1,129 @@
+#include "include/dvr/dvr_api.h"
+
+#include <errno.h>
+
+// Headers from libdvr
+#include <dvr/display_manager_client.h>
+#include <dvr/dvr_buffer.h>
+#include <dvr/dvr_buffer_queue.h>
+#include <dvr/dvr_surface.h>
+#include <dvr/vsync_client_api.h>
+
+// Headers not yet moved into libdvr.
+// TODO(jwcai) Move these once their callers are moved into Google3.
+#include <dvr/dvr_hardware_composer_client.h>
+#include <dvr/pose_client.h>
+#include <dvr/virtual_touchpad_client.h>
+
+extern "C" {
+
+DVR_EXPORT int dvrGetApi(void* api, size_t struct_size, int version) {
+ if (version == 1) {
+ if (struct_size != sizeof(DvrApi_v1)) {
+ return -EINVAL;
+ }
+ DvrApi_v1* dvr_api = static_cast<DvrApi_v1*>(api);
+
+ // display_manager_client.h
+ dvr_api->display_manager_client_create_ = dvrDisplayManagerClientCreate;
+ dvr_api->display_manager_client_destroy_ = dvrDisplayManagerClientDestroy;
+ dvr_api->display_manager_client_get_surface_list_ =
+ dvrDisplayManagerClientGetSurfaceList;
+ dvr_api->display_manager_client_surface_list_destroy_ =
+ dvrDisplayManagerClientSurfaceListDestroy;
+ dvr_api->display_manager_setup_pose_buffer_ =
+ dvrDisplayManagerSetupPoseBuffer;
+ dvr_api->display_manager_client_surface_list_get_size_ =
+ dvrDisplayManagerClientSurfaceListGetSize;
+ dvr_api->display_manager_client_surface_list_get_surface_id_ =
+ dvrDisplayManagerClientSurfaceListGetSurfaceId;
+ dvr_api->display_manager_client_get_surface_buffer_list_ =
+ dvrDisplayManagerClientGetSurfaceBuffers;
+ dvr_api->display_manager_client_surface_buffer_list_destroy_ =
+ dvrDisplayManagerClientSurfaceBuffersDestroy;
+ dvr_api->display_manager_client_surface_buffer_list_get_size_ =
+ dvrDisplayManagerClientSurfaceBuffersGetSize;
+ dvr_api->display_manager_client_surface_buffer_list_get_fd_ =
+ dvrDisplayManagerClientSurfaceBuffersGetFd;
+
+ // dvr_buffer.h
+ dvr_api->write_buffer_destroy_ = dvrWriteBufferDestroy;
+ dvr_api->write_buffer_get_blob_fds_ = dvrWriteBufferGetBlobFds;
+ dvr_api->write_buffer_get_AHardwareBuffer_ =
+ dvrWriteBufferGetAHardwareBuffer;
+ dvr_api->write_buffer_post_ = dvrWriteBufferPost;
+ dvr_api->write_buffer_gain_ = dvrWriteBufferGain;
+ dvr_api->write_buffer_gain_async_ = dvrWriteBufferGainAsync;
+
+ dvr_api->read_buffer_destroy_ = dvrReadBufferDestroy;
+ dvr_api->read_buffer_get_blob_fds_ = dvrReadBufferGetBlobFds;
+ dvr_api->read_buffer_get_AHardwareBuffer_ = dvrReadBufferGetAHardwareBuffer;
+ dvr_api->read_buffer_acquire_ = dvrReadBufferAcquire;
+ dvr_api->read_buffer_release_ = dvrReadBufferRelease;
+ dvr_api->read_buffer_release_async_ = dvrReadBufferReleaseAsync;
+
+ // dvr_buffer_queue.h
+ dvr_api->write_buffer_queue_destroy_ = dvrWriteBufferQueueDestroy;
+ dvr_api->write_buffer_queue_get_capacity_ = dvrWriteBufferQueueGetCapacity;
+ dvr_api->write_buffer_queue_get_external_surface_ =
+ dvrWriteBufferQueueGetExternalSurface;
+ dvr_api->write_buffer_queue_create_read_queue_ =
+ dvrWriteBufferQueueCreateReadQueue;
+ dvr_api->write_buffer_queue_dequeue_ = dvrWriteBufferQueueDequeue;
+ dvr_api->read_buffer_queue_destroy_ = dvrReadBufferQueueDestroy;
+ dvr_api->read_buffer_queue_get_capacity_ = dvrReadBufferQueueGetCapacity;
+ dvr_api->read_buffer_queue_create_read_queue_ =
+ dvrReadBufferQueueCreateReadQueue;
+ dvr_api->read_buffer_queue_dequeue = dvrReadBufferQueueDequeue;
+
+ // dvr_surface.h
+ dvr_api->get_pose_buffer_ = dvrGetPoseBuffer;
+ dvr_api->surface_create_ = dvrSurfaceCreate;
+ dvr_api->surface_get_write_buffer_queue_ = dvrSurfaceGetWriteBufferQueue;
+
+ // vsync_client_api.h
+ dvr_api->vsync_client_create_ = dvr_vsync_client_create;
+ dvr_api->vsync_client_destroy_ = dvr_vsync_client_destroy;
+ dvr_api->vsync_client_get_sched_info_ = dvr_vsync_client_get_sched_info;
+
+ // pose_client.h
+ dvr_api->pose_client_create_ = dvrPoseCreate;
+ dvr_api->pose_client_destroy_ = dvrPoseDestroy;
+ dvr_api->pose_get_ = dvrPoseGet;
+ dvr_api->pose_get_vsync_count_ = dvrPoseGetVsyncCount;
+ dvr_api->pose_get_controller_ = dvrPoseGetController;
+
+ // virtual_touchpad_client.h
+ dvr_api->virtual_touchpad_create_ = dvrVirtualTouchpadCreate;
+ dvr_api->virtual_touchpad_destroy_ = dvrVirtualTouchpadDestroy;
+ dvr_api->virtual_touchpad_attach_ = dvrVirtualTouchpadAttach;
+ dvr_api->virtual_touchpad_detach_ = dvrVirtualTouchpadDetach;
+ dvr_api->virtual_touchpad_touch_ = dvrVirtualTouchpadTouch;
+ dvr_api->virtual_touchpad_button_state_ = dvrVirtualTouchpadButtonState;
+
+ // dvr_hardware_composer_client.h
+ dvr_api->hwc_create_client_ = dvrHwcCreateClient;
+ dvr_api->hwc_client_destroy_ = dvrHwcClientDestroy;
+ dvr_api->hwc_frame_destroy_ = dvrHwcFrameDestroy;
+ dvr_api->hwc_frame_get_display_id_ = dvrHwcFrameGetDisplayId;
+ dvr_api->hwc_frame_get_display_width_ = dvrHwcFrameGetDisplayWidth;
+ dvr_api->hwc_frame_get_display_height_ = dvrHwcFrameGetDisplayHeight;
+ dvr_api->hwc_frame_get_layer_count_ = dvrHwcFrameGetLayerCount;
+ dvr_api->hwc_frame_get_layer_id_ = dvrHwcFrameGetLayerId;
+ dvr_api->hwc_frame_get_layer_buffer_ = dvrHwcFrameGetLayerBuffer;
+ dvr_api->hwc_frame_get_layer_fence_ = dvrHwcFrameGetLayerFence;
+ dvr_api->hwc_frame_get_layer_display_frame_ =
+ dvrHwcFrameGetLayerDisplayFrame;
+ dvr_api->hwc_frame_get_layer_crop_ = dvrHwcFrameGetLayerCrop;
+ dvr_api->hwc_frame_get_layer_blend_mode_ = dvrHwcFrameGetLayerBlendMode;
+ dvr_api->hwc_frame_get_layer_alpha_ = dvrHwcFrameGetLayerAlpha;
+ dvr_api->hwc_frame_get_layer_type_ = dvrHwcFrameGetLayerType;
+ dvr_api->hwc_frame_get_layer_application_id_ =
+ dvrHwcFrameGetLayerApplicationId;
+
+ return 0;
+ }
+ return -EINVAL;
+}
+
+} // extern "C"
diff --git a/libs/vr/libbufferhub/dvr_buffer.cpp b/libs/vr/libdvr/dvr_buffer.cpp
similarity index 91%
rename from libs/vr/libbufferhub/dvr_buffer.cpp
rename to libs/vr/libdvr/dvr_buffer.cpp
index 3eb611f..25128a6 100644
--- a/libs/vr/libbufferhub/dvr_buffer.cpp
+++ b/libs/vr/libdvr/dvr_buffer.cpp
@@ -1,16 +1,17 @@
+#include "include/dvr/dvr_buffer.h"
+
#include <private/dvr/buffer_hub_client.h>
-#include <private/dvr/dvr_buffer.h>
#include <ui/GraphicBuffer.h>
using namespace android;
struct DvrWriteBuffer {
- std::unique_ptr<dvr::BufferProducer> write_buffer_;
+ std::shared_ptr<dvr::BufferProducer> write_buffer_;
sp<GraphicBuffer> graphic_buffer_;
};
struct DvrReadBuffer {
- std::unique_ptr<dvr::BufferConsumer> read_buffer_;
+ std::shared_ptr<dvr::BufferConsumer> read_buffer_;
sp<GraphicBuffer> graphic_buffer_;
};
@@ -18,14 +19,14 @@
namespace dvr {
DvrWriteBuffer* CreateDvrWriteBufferFromBufferProducer(
- std::unique_ptr<dvr::BufferProducer> buffer_producer) {
+ const std::shared_ptr<dvr::BufferProducer>& buffer_producer) {
DvrWriteBuffer* write_buffer = new DvrWriteBuffer;
write_buffer->write_buffer_ = std::move(buffer_producer);
return write_buffer;
}
DvrReadBuffer* CreateDvrReadBufferFromBufferConsumer(
- std::unique_ptr<dvr::BufferConsumer> buffer_consumer) {
+ const std::shared_ptr<dvr::BufferConsumer>& buffer_consumer) {
DvrReadBuffer* read_buffer = new DvrReadBuffer;
read_buffer->read_buffer_ = std::move(buffer_consumer);
return read_buffer;
@@ -85,6 +86,8 @@
return client->write_buffer_->GainAsync();
}
+void dvrReadBufferDestroy(DvrReadBuffer* client) { delete client; }
+
void dvrReadBufferGetBlobFds(DvrReadBuffer* client, int* fds, size_t* fds_count,
size_t max_fds_count) {
client->read_buffer_->GetBlobFds(fds, fds_count, max_fds_count);
diff --git a/libs/vr/libdvr/dvr_buffer_queue.cpp b/libs/vr/libdvr/dvr_buffer_queue.cpp
new file mode 100644
index 0000000..4ce0b22
--- /dev/null
+++ b/libs/vr/libdvr/dvr_buffer_queue.cpp
@@ -0,0 +1,146 @@
+#include "include/dvr/dvr_buffer_queue.h"
+
+#include <gui/Surface.h>
+#include <private/dvr/buffer_hub_queue_client.h>
+#include <private/dvr/buffer_hub_queue_producer.h>
+
+#include <android_runtime/android_view_Surface.h>
+
+#define CHECK_PARAM(param) \
+ LOG_ALWAYS_FATAL_IF(param == nullptr, "%s: " #param "cannot be NULL.", \
+ __FUNCTION__)
+
+using namespace android;
+
+extern "C" {
+
+void dvrWriteBufferQueueDestroy(DvrWriteBufferQueue* write_queue) {
+ delete write_queue;
+}
+
+size_t dvrWriteBufferQueueGetCapacity(DvrWriteBufferQueue* write_queue) {
+ CHECK_PARAM(write_queue);
+ return write_queue->producer_queue_->capacity();
+}
+
+jobject dvrWriteBufferQueueGetExternalSurface(DvrWriteBufferQueue* write_queue,
+ JNIEnv* env) {
+ CHECK_PARAM(env);
+ CHECK_PARAM(write_queue);
+
+ std::shared_ptr<dvr::BufferHubQueueCore> core =
+ dvr::BufferHubQueueCore::Create(write_queue->producer_queue_);
+
+ return android_view_Surface_createFromIGraphicBufferProducer(
+ env, new dvr::BufferHubQueueProducer(core));
+}
+
+int dvrWriteBufferQueueCreateReadQueue(DvrWriteBufferQueue* write_queue,
+ DvrReadBufferQueue** out_read_queue) {
+ CHECK_PARAM(write_queue);
+ CHECK_PARAM(write_queue->producer_queue_);
+ CHECK_PARAM(out_read_queue);
+
+ auto read_queue = std::make_unique<DvrReadBufferQueue>();
+ read_queue->consumer_queue_ =
+ write_queue->producer_queue_->CreateConsumerQueue();
+ if (read_queue->consumer_queue_ == nullptr) {
+ ALOGE(
+ "dvrWriteBufferQueueCreateReadQueue: Failed to create consumer queue "
+ "from DvrWriteBufferQueue[%p].",
+ write_queue);
+ return -ENOMEM;
+ }
+
+ *out_read_queue = read_queue.release();
+ return 0;
+}
+
+int dvrWriteBufferQueueDequeue(DvrWriteBufferQueue* write_queue, int timeout,
+ DvrWriteBuffer** out_buffer,
+ int* out_fence_fd) {
+ CHECK_PARAM(write_queue);
+ CHECK_PARAM(write_queue->producer_queue_);
+ CHECK_PARAM(out_buffer);
+ CHECK_PARAM(out_fence_fd);
+
+ size_t slot;
+ pdx::LocalHandle release_fence;
+ std::shared_ptr<dvr::BufferProducer> buffer =
+ write_queue->producer_queue_->Dequeue(timeout, &slot, &release_fence);
+ if (buffer == nullptr) {
+ ALOGE("dvrWriteBufferQueueDequeue: Failed to dequeue buffer.");
+ return -ENOMEM;
+ }
+
+ *out_buffer = CreateDvrWriteBufferFromBufferProducer(buffer);
+ *out_fence_fd = release_fence.Release();
+ return 0;
+}
+
+// ReadBufferQueue
+void dvrReadBufferQueueDestroy(DvrReadBufferQueue* read_queue) {
+ delete read_queue;
+}
+
+size_t dvrReadBufferQueueGetCapacity(DvrReadBufferQueue* read_queue) {
+ CHECK_PARAM(read_queue);
+
+ return read_queue->consumer_queue_->capacity();
+}
+
+int dvrReadBufferQueueCreateReadQueue(DvrReadBufferQueue* read_queue,
+ DvrReadBufferQueue** out_read_queue) {
+ CHECK_PARAM(read_queue);
+ CHECK_PARAM(read_queue->consumer_queue_);
+ CHECK_PARAM(out_read_queue);
+
+ auto new_read_queue = std::make_unique<DvrReadBufferQueue>();
+ new_read_queue->consumer_queue_ =
+ read_queue->consumer_queue_->CreateConsumerQueue();
+ if (new_read_queue->consumer_queue_ == nullptr) {
+ ALOGE(
+ "dvrReadBufferQueueCreateReadQueue: Failed to create consumer queue "
+ "from DvrReadBufferQueue[%p].",
+ read_queue);
+ return -ENOMEM;
+ }
+
+ *out_read_queue = new_read_queue.release();
+ return 0;
+}
+
+int dvrReadBufferQueueDequeue(DvrReadBufferQueue* read_queue, int timeout,
+ DvrReadBuffer** out_buffer, int* out_fence_fd,
+ void* out_meta, size_t meta_size_bytes) {
+ CHECK_PARAM(read_queue);
+ CHECK_PARAM(read_queue->consumer_queue_);
+ CHECK_PARAM(out_buffer);
+ CHECK_PARAM(out_fence_fd);
+ CHECK_PARAM(out_meta);
+
+ if (meta_size_bytes != read_queue->consumer_queue_->metadata_size()) {
+ ALOGE(
+ "dvrReadBufferQueueDequeue: Invalid metadata size, expected (%zu), "
+ "but actual (%zu).",
+ read_queue->consumer_queue_->metadata_size(), meta_size_bytes);
+ return -EINVAL;
+ }
+
+ size_t slot;
+ pdx::LocalHandle acquire_fence;
+ std::shared_ptr<dvr::BufferConsumer> buffer =
+ read_queue->consumer_queue_->Dequeue(timeout, &slot, out_meta,
+ meta_size_bytes, &acquire_fence);
+
+ if (buffer == nullptr) {
+ ALOGE("dvrReadBufferQueueGainBuffer: Failed to dequeue buffer.");
+ return -ENOMEM;
+ }
+
+ *out_buffer = CreateDvrReadBufferFromBufferConsumer(buffer);
+ *out_fence_fd = acquire_fence.Release();
+ return 0;
+}
+
+} // extern "C"
diff --git a/services/vr/hardware_composer/dvr_hardware_composer_client.cpp b/libs/vr/libdvr/dvr_hardware_composer_client.cpp
similarity index 79%
rename from services/vr/hardware_composer/dvr_hardware_composer_client.cpp
rename to libs/vr/libdvr/dvr_hardware_composer_client.cpp
index 39fa9fc..fde0c84 100644
--- a/services/vr/hardware_composer/dvr_hardware_composer_client.cpp
+++ b/libs/vr/libdvr/dvr_hardware_composer_client.cpp
@@ -1,7 +1,8 @@
-#include "private/android/dvr_hardware_composer_client.h"
+#include "include/dvr/dvr_hardware_composer_client.h"
#include <android/dvr/IVrComposer.h>
#include <android/dvr/BnVrComposerCallback.h>
+#include <android/hardware_buffer.h>
#include <binder/IServiceManager.h>
#include <private/android/AHardwareBufferHelpers.h>
@@ -15,7 +16,8 @@
class HwcCallback : public android::dvr::BnVrComposerCallback {
public:
- explicit HwcCallback(DvrHwcOnFrameCallback callback);
+ explicit HwcCallback(DvrHwcOnFrameCallback callback,
+ void* client_state);
~HwcCallback() override;
std::unique_ptr<DvrHwcFrame> DequeueFrame();
@@ -27,13 +29,14 @@
android::dvr::ParcelableUniqueFd* fence) override;
DvrHwcOnFrameCallback callback_;
+ void* client_state_;
HwcCallback(const HwcCallback&) = delete;
void operator=(const HwcCallback&) = delete;
};
-HwcCallback::HwcCallback(DvrHwcOnFrameCallback callback)
- : callback_(callback) {}
+HwcCallback::HwcCallback(DvrHwcOnFrameCallback callback, void* client_state)
+ : callback_(callback), client_state_(client_state) {}
HwcCallback::~HwcCallback() {}
@@ -43,7 +46,8 @@
std::unique_ptr<DvrHwcFrame> dvr_frame(new DvrHwcFrame());
dvr_frame->frame = frame.frame();
- fence->set_fence(android::base::unique_fd(callback_(dvr_frame.release())));
+ fence->set_fence(android::base::unique_fd(callback_(client_state_,
+ dvr_frame.release())));
return android::binder::Status::ok();
}
@@ -54,7 +58,7 @@
android::sp<HwcCallback> callback;
};
-DvrHwcClient* dvrHwcCreateClient(DvrHwcOnFrameCallback callback) {
+DvrHwcClient* dvrHwcCreateClient(DvrHwcOnFrameCallback callback, void* data) {
std::unique_ptr<DvrHwcClient> client(new DvrHwcClient());
android::sp<android::IServiceManager> sm(android::defaultServiceManager());
@@ -63,7 +67,7 @@
if (!client->composer.get())
return nullptr;
- client->callback = new HwcCallback(callback);
+ client->callback = new HwcCallback(callback, data);
android::binder::Status status = client->composer->registerObserver(
client->callback);
if (!status.isOk())
@@ -72,6 +76,10 @@
return client.release();
}
+void dvrHwcClientDestroy(DvrHwcClient* client) {
+ delete client;
+}
+
void dvrHwcFrameDestroy(DvrHwcFrame* frame) {
delete frame;
}
@@ -80,6 +88,18 @@
return frame->frame.display_id;
}
+int32_t dvrHwcFrameGetDisplayWidth(DvrHwcFrame* frame) {
+ return frame->frame.display_width;
+}
+
+int32_t dvrHwcFrameGetDisplayHeight(DvrHwcFrame* frame) {
+ return frame->frame.display_height;
+}
+
+bool dvrHwcFrameGetDisplayRemoved(DvrHwcFrame* frame) {
+ return frame->frame.removed;
+}
+
size_t dvrHwcFrameGetLayerCount(DvrHwcFrame* frame) {
return frame->frame.layers.size();
}
diff --git a/libs/vr/libdvr/dvr_surface.cpp b/libs/vr/libdvr/dvr_surface.cpp
new file mode 100644
index 0000000..a3cbba5
--- /dev/null
+++ b/libs/vr/libdvr/dvr_surface.cpp
@@ -0,0 +1,72 @@
+#include "include/dvr/dvr_surface.h"
+
+#include <private/dvr/display_client.h>
+
+using namespace android;
+
+struct DvrSurface {
+ std::unique_ptr<dvr::DisplaySurfaceClient> display_surface_;
+};
+
+extern "C" {
+
+int dvrSurfaceCreate(int width, int height, int format, uint64_t usage0,
+ uint64_t usage1, int flags, DvrSurface** out_surface) {
+ if (out_surface == nullptr) {
+ ALOGE("dvrSurfaceCreate: invalid inputs: out_surface=%p.", out_surface);
+ return -EINVAL;
+ }
+
+ int error;
+ auto client = dvr::DisplayClient::Create(&error);
+ if (!client) {
+ ALOGE("Failed to create display client!");
+ return error;
+ }
+
+ // TODO(hendrikw): When we move to gralloc1, pass both usage0 and usage1 down.
+ std::unique_ptr<dvr::DisplaySurfaceClient> surface =
+ client->CreateDisplaySurface(
+ width, height, static_cast<int>(usage0 | usage1), format, flags);
+
+ DvrSurface* dvr_surface = new DvrSurface;
+ dvr_surface->display_surface_ = std::move(surface);
+ *out_surface = dvr_surface;
+ return 0;
+}
+
+int dvrSurfaceGetWriteBufferQueue(DvrSurface* surface,
+ DvrWriteBufferQueue** out_writer) {
+ if (surface == nullptr || out_writer == nullptr) {
+ ALOGE(
+ "dvrSurfaceGetWriteBufferQueue: Invalid inputs: surface=%p, "
+ "out_writer=%p.",
+ surface, out_writer);
+ return -EINVAL;
+ }
+ DvrWriteBufferQueue* buffer_writer = new DvrWriteBufferQueue;
+ buffer_writer->producer_queue_ =
+ surface->display_surface_->GetProducerQueue();
+ if (buffer_writer->producer_queue_ == nullptr) {
+ ALOGE(
+ "dvrSurfaceGetWriteBufferQueue: Failed to get producer queue from "
+ "display surface.");
+ return -ENOMEM;
+ }
+
+ *out_writer = buffer_writer;
+ return 0;
+}
+
+int dvrGetPoseBuffer(DvrReadBuffer** pose_buffer) {
+ auto client = android::dvr::DisplayClient::Create();
+ if (!client) {
+ ALOGE("Failed to create display client!");
+ return -ECOMM;
+ }
+
+ *pose_buffer = CreateDvrReadBufferFromBufferConsumer(client->GetPoseBuffer());
+ return 0;
+}
+
+} // extern "C"
diff --git a/libs/vr/libdvr/include/CPPLINT.cfg b/libs/vr/libdvr/include/CPPLINT.cfg
new file mode 100644
index 0000000..2f8a3c0
--- /dev/null
+++ b/libs/vr/libdvr/include/CPPLINT.cfg
@@ -0,0 +1 @@
+filter=-build/header_guard
diff --git a/libs/vr/libdisplay/include/private/dvr/display_manager_client.h b/libs/vr/libdvr/include/dvr/display_manager_client.h
similarity index 100%
rename from libs/vr/libdisplay/include/private/dvr/display_manager_client.h
rename to libs/vr/libdvr/include/dvr/display_manager_client.h
diff --git a/libs/vr/libdvr/include/dvr/dvr_api.h b/libs/vr/libdvr/include/dvr/dvr_api.h
new file mode 100644
index 0000000..1411a0a
--- /dev/null
+++ b/libs/vr/libdvr/include/dvr/dvr_api.h
@@ -0,0 +1,283 @@
+#ifndef ANDROID_DVR_API_H_
+#define ANDROID_DVR_API_H_
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#include <dvr/dvr_hardware_composer_defs.h>
+#include <jni.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct DvrPoseAsync DvrPoseAsync;
+
+typedef struct DvrDisplayManagerClient DvrDisplayManagerClient;
+typedef struct DvrDisplayManagerClientSurfaceList
+ DvrDisplayManagerClientSurfaceList;
+typedef struct DvrDisplayManagerClientSurfaceBuffers
+ DvrDisplayManagerClientSurfaceBuffers;
+typedef struct DvrPose DvrPose;
+typedef struct dvr_vsync_client dvr_vsync_client;
+typedef struct DvrVirtualTouchpad DvrVirtualTouchpad;
+
+typedef DvrDisplayManagerClient* (*DvrDisplayManagerClientCreatePtr)(void);
+typedef void (*DvrDisplayManagerClientDestroyPtr)(
+ DvrDisplayManagerClient* client);
+
+typedef struct DvrWriteBuffer DvrWriteBuffer;
+typedef struct DvrReadBuffer DvrReadBuffer;
+typedef struct AHardwareBuffer AHardwareBuffer;
+
+typedef struct DvrWriteBufferQueue DvrWriteBufferQueue;
+typedef struct DvrReadBufferQueue DvrReadBufferQueue;
+
+typedef struct DvrSurface DvrSurface;
+
+// display_manager_client.h
+typedef int (*DvrDisplayManagerClientGetSurfaceListPtr)(
+ DvrDisplayManagerClient* client,
+ DvrDisplayManagerClientSurfaceList** surface_list);
+typedef void (*DvrDisplayManagerClientSurfaceListDestroyPtr)(
+ DvrDisplayManagerClientSurfaceList* surface_list);
+typedef DvrWriteBuffer* (*DvrDisplayManagerSetupPoseBufferPtr)(
+ DvrDisplayManagerClient* client, size_t extended_region_size,
+ uint64_t usage0, uint64_t usage1);
+typedef size_t (*DvrDisplayManagerClientSurfaceListGetSizePtr)(
+ DvrDisplayManagerClientSurfaceList* surface_list);
+typedef int (*DvrDisplayManagerClientSurfaceListGetSurfaceIdPtr)(
+ DvrDisplayManagerClientSurfaceList* surface_list, size_t index);
+typedef int (*DvrDisplayManagerClientGetSurfaceBufferListPtr)(
+ DvrDisplayManagerClient* client, int surface_id,
+ DvrDisplayManagerClientSurfaceBuffers** surface_buffers);
+typedef void (*DvrDisplayManagerClientSurfaceBufferListDestroyPtr)(
+ DvrDisplayManagerClientSurfaceBuffers* surface_buffers);
+typedef size_t (*DvrDisplayManagerClientSurfaceBufferListGetSizePtr)(
+ DvrDisplayManagerClientSurfaceBuffers* surface_buffers);
+typedef int (*DvrDisplayManagerClientSurfaceBufferListGetFdPtr)(
+ DvrDisplayManagerClientSurfaceBuffers* surface_buffers, size_t index);
+
+// dvr_buffer.h
+typedef void (*DvrWriteBufferDestroyPtr)(DvrWriteBuffer* client);
+typedef void (*DvrWriteBufferGetBlobFdsPtr)(DvrWriteBuffer* client, int* fds,
+ size_t* fds_count,
+ size_t max_fds_count);
+typedef int (*DvrWriteBufferGetAHardwareBufferPtr)(
+ DvrWriteBuffer* client, AHardwareBuffer** hardware_buffer);
+typedef int (*DvrWriteBufferPostPtr)(DvrWriteBuffer* client, int ready_fence_fd,
+ const void* meta, size_t meta_size_bytes);
+typedef int (*DvrWriteBufferGainPtr)(DvrWriteBuffer* client,
+ int* release_fence_fd);
+typedef int (*DvrWriteBufferGainAsyncPtr)(DvrWriteBuffer* client);
+
+typedef void (*DvrReadBufferDestroyPtr)(DvrReadBuffer* client);
+typedef void (*DvrReadBufferGetBlobFdsPtr)(DvrReadBuffer* client, int* fds,
+ size_t* fds_count,
+ size_t max_fds_count);
+typedef int (*DvrReadBufferGetAHardwareBufferPtr)(
+ DvrReadBuffer* client, AHardwareBuffer** hardware_buffer);
+typedef int (*DvrReadBufferAcquirePtr)(DvrReadBuffer* client,
+ int* ready_fence_fd, void* meta,
+ size_t meta_size_bytes);
+typedef int (*DvrReadBufferReleasePtr)(DvrReadBuffer* client,
+ int release_fence_fd);
+typedef int (*DvrReadBufferReleaseAsyncPtr)(DvrReadBuffer* client);
+
+// dvr_buffer_queue.h
+typedef void (*DvrWriteBufferQueueDestroyPtr)(DvrWriteBufferQueue* write_queue);
+typedef size_t (*DvrWriteBufferQueueGetCapacityPtr)(
+ DvrWriteBufferQueue* write_queue);
+typedef jobject (*DvrWriteBufferQueueGetExternalSurfacePtr)(
+ DvrWriteBufferQueue* write_queue, JNIEnv* env);
+typedef int (*DvrWriteBufferQueueCreateReadQueuePtr)(
+ DvrWriteBufferQueue* write_queue, DvrReadBufferQueue** out_read_queue);
+typedef int (*DvrWriteBufferQueueDequeuePtr)(DvrWriteBufferQueue* write_queue,
+ int timeout,
+ DvrWriteBuffer** out_buffer,
+ int* out_fence_fd);
+typedef void (*DvrReadBufferQueueDestroyPtr)(DvrReadBufferQueue* read_queue);
+typedef size_t (*DvrReadBufferQueueGetCapacityPtr)(
+ DvrReadBufferQueue* read_queue);
+typedef int (*DvrReadBufferQueueCreateReadQueuePtr)(
+ DvrReadBufferQueue* read_queue, DvrReadBufferQueue** out_read_queue);
+typedef int (*DvrReadBufferQueueDequeuePtr)(DvrReadBufferQueue* read_queue,
+ int timeout,
+ DvrReadBuffer** out_buffer,
+ int* out_fence_fd, void* out_meta,
+ size_t meta_size_bytes);
+
+// dvr_surface.h
+typedef int (*DvrGetPoseBufferPtr)(DvrReadBuffer** pose_buffer);
+typedef int (*DvrSurfaceCreatePtr)(int width, int height, int format,
+ uint64_t usage0, uint64_t usage1, int flags,
+ DvrSurface** out_surface);
+typedef int (*DvrSurfaceGetWriteBufferQueuePtr)(
+ DvrSurface* surface, DvrWriteBufferQueue** out_writer);
+
+// vsync_client_api.h
+typedef dvr_vsync_client* (*DvrVSyncClientCreatePtr)();
+typedef void (*DvrVSyncClientDestroyPtr)(dvr_vsync_client* client);
+typedef int (*DvrVSyncClientGetSchedInfoPtr)(dvr_vsync_client* client,
+ int64_t* vsync_period_ns,
+ int64_t* next_timestamp_ns,
+ uint32_t* next_vsync_count);
+
+// pose_client.h
+typedef DvrPose* (*DvrPoseClientCreatePtr)(void);
+typedef void (*DvrPoseClientDestroyPtr)(DvrPose* client);
+typedef int (*DvrPoseGetPtr)(DvrPose* client, uint32_t vsync_count,
+ DvrPoseAsync* out_pose);
+typedef uint32_t (*DvrPoseGetVsyncCountPtr)(DvrPose* client);
+typedef int (*DvrPoseGetControllerPtr)(DvrPose* client, int32_t controller_id,
+ uint32_t vsync_count,
+ DvrPoseAsync* out_pose);
+
+// virtual_touchpad_client.h
+typedef DvrVirtualTouchpad* (*DvrVirtualTouchpadCreatePtr)(void);
+typedef void (*DvrVirtualTouchpadDestroyPtr)(DvrVirtualTouchpad* client);
+typedef int (*DvrVirtualTouchpadAttachPtr)(DvrVirtualTouchpad* client);
+typedef int (*DvrVirtualTouchpadDetachPtr)(DvrVirtualTouchpad* client);
+typedef int (*DvrVirtualTouchpadTouchPtr)(DvrVirtualTouchpad* client,
+ int touchpad, float x, float y,
+ float pressure);
+typedef int (*DvrVirtualTouchpadButtonStatePtr)(DvrVirtualTouchpad* client,
+ int touchpad, int buttons);
+
+// dvr_hardware_composer_client.h
+typedef struct AHardwareBuffer AHardwareBuffer;
+typedef struct DvrHwcClient DvrHwcClient;
+typedef struct DvrHwcFrame DvrHwcFrame;
+typedef int(*DvrHwcOnFrameCallback)(void* client_state, DvrHwcFrame* frame);
+typedef DvrHwcClient* (*DvrHwcCreateClientPtr)(DvrHwcOnFrameCallback callback,
+ void* client_state);
+typedef void (*DvrHwcClientDestroyPtr)(DvrHwcClient* client);
+typedef void (*DvrHwcFrameDestroyPtr)(DvrHwcFrame* frame);
+typedef Display (*DvrHwcFrameGetDisplayIdPtr)(DvrHwcFrame* frame);
+typedef int32_t (*DvrHwcFrameGetDisplayWidthPtr)(DvrHwcFrame* frame);
+typedef int32_t (*DvrHwcFrameGetDisplayHeightPtr)(DvrHwcFrame* frame);
+typedef bool (*DvrHwcFrameGetDisplayRemovedPtr)(DvrHwcFrame* frame);
+typedef size_t (*DvrHwcFrameGetLayerCountPtr)(DvrHwcFrame* frame);
+typedef Layer (*DvrHwcFrameGetLayerIdPtr)(DvrHwcFrame* frame, size_t layer_index);
+typedef AHardwareBuffer* (*DvrHwcFrameGetLayerBufferPtr)(DvrHwcFrame* frame,
+ size_t layer_index);
+typedef int (*DvrHwcFrameGetLayerFencePtr)(DvrHwcFrame* frame,
+ size_t layer_index);
+typedef Recti (*DvrHwcFrameGetLayerDisplayFramePtr)(DvrHwcFrame* frame,
+ size_t layer_index);
+typedef Rectf (*DvrHwcFrameGetLayerCropPtr)(DvrHwcFrame* frame,
+ size_t layer_index);
+typedef BlendMode (*DvrHwcFrameGetLayerBlendModePtr)(DvrHwcFrame* frame,
+ size_t layer_index);
+typedef float (*DvrHwcFrameGetLayerAlphaPtr)(DvrHwcFrame* frame,
+ size_t layer_index);
+typedef uint32_t (*DvrHwcFrameGetLayerTypePtr)(DvrHwcFrame* frame,
+ size_t layer_index);
+typedef uint32_t (*DvrHwcFrameGetLayerApplicationIdPtr)(DvrHwcFrame* frame,
+ size_t layer_index);
+
+struct DvrApi_v1 {
+ // Display manager client
+ DvrDisplayManagerClientCreatePtr display_manager_client_create_;
+ DvrDisplayManagerClientDestroyPtr display_manager_client_destroy_;
+ DvrDisplayManagerClientGetSurfaceListPtr
+ display_manager_client_get_surface_list_;
+ DvrDisplayManagerClientSurfaceListDestroyPtr
+ display_manager_client_surface_list_destroy_;
+ DvrDisplayManagerSetupPoseBufferPtr display_manager_setup_pose_buffer_;
+ DvrDisplayManagerClientSurfaceListGetSizePtr
+ display_manager_client_surface_list_get_size_;
+ DvrDisplayManagerClientSurfaceListGetSurfaceIdPtr
+ display_manager_client_surface_list_get_surface_id_;
+ DvrDisplayManagerClientGetSurfaceBufferListPtr
+ display_manager_client_get_surface_buffer_list_;
+ DvrDisplayManagerClientSurfaceBufferListDestroyPtr
+ display_manager_client_surface_buffer_list_destroy_;
+ DvrDisplayManagerClientSurfaceBufferListGetSizePtr
+ display_manager_client_surface_buffer_list_get_size_;
+ DvrDisplayManagerClientSurfaceBufferListGetFdPtr
+ display_manager_client_surface_buffer_list_get_fd_;
+
+ // Write buffer
+ DvrWriteBufferDestroyPtr write_buffer_destroy_;
+ DvrWriteBufferGetBlobFdsPtr write_buffer_get_blob_fds_;
+ DvrWriteBufferGetAHardwareBufferPtr write_buffer_get_AHardwareBuffer_;
+ DvrWriteBufferPostPtr write_buffer_post_;
+ DvrWriteBufferGainPtr write_buffer_gain_;
+ DvrWriteBufferGainAsyncPtr write_buffer_gain_async_;
+
+ // Read buffer
+ DvrReadBufferDestroyPtr read_buffer_destroy_;
+ DvrReadBufferGetBlobFdsPtr read_buffer_get_blob_fds_;
+ DvrReadBufferGetAHardwareBufferPtr read_buffer_get_AHardwareBuffer_;
+ DvrReadBufferAcquirePtr read_buffer_acquire_;
+ DvrReadBufferReleasePtr read_buffer_release_;
+ DvrReadBufferReleaseAsyncPtr read_buffer_release_async_;
+
+ // Write buffer queue
+ DvrWriteBufferQueueDestroyPtr write_buffer_queue_destroy_;
+ DvrWriteBufferQueueGetCapacityPtr write_buffer_queue_get_capacity_;
+ DvrWriteBufferQueueGetExternalSurfacePtr
+ write_buffer_queue_get_external_surface_;
+ DvrWriteBufferQueueCreateReadQueuePtr write_buffer_queue_create_read_queue_;
+ DvrWriteBufferQueueDequeuePtr write_buffer_queue_dequeue_;
+
+ // Read buffer queue
+ DvrReadBufferQueueDestroyPtr read_buffer_queue_destroy_;
+ DvrReadBufferQueueGetCapacityPtr read_buffer_queue_get_capacity_;
+ DvrReadBufferQueueCreateReadQueuePtr read_buffer_queue_create_read_queue_;
+ DvrReadBufferQueueDequeuePtr read_buffer_queue_dequeue;
+
+ // V-Sync client
+ DvrVSyncClientCreatePtr vsync_client_create_;
+ DvrVSyncClientDestroyPtr vsync_client_destroy_;
+ DvrVSyncClientGetSchedInfoPtr vsync_client_get_sched_info_;
+
+ // Display surface
+ DvrGetPoseBufferPtr get_pose_buffer_;
+ DvrSurfaceCreatePtr surface_create_;
+ DvrSurfaceGetWriteBufferQueuePtr surface_get_write_buffer_queue_;
+
+ // Pose client
+ DvrPoseClientCreatePtr pose_client_create_;
+ DvrPoseClientDestroyPtr pose_client_destroy_;
+ DvrPoseGetPtr pose_get_;
+ DvrPoseGetVsyncCountPtr pose_get_vsync_count_;
+ DvrPoseGetControllerPtr pose_get_controller_;
+
+ // Virtual touchpad client
+ DvrVirtualTouchpadCreatePtr virtual_touchpad_create_;
+ DvrVirtualTouchpadDestroyPtr virtual_touchpad_destroy_;
+ DvrVirtualTouchpadAttachPtr virtual_touchpad_attach_;
+ DvrVirtualTouchpadDetachPtr virtual_touchpad_detach_;
+ DvrVirtualTouchpadTouchPtr virtual_touchpad_touch_;
+ DvrVirtualTouchpadButtonStatePtr virtual_touchpad_button_state_;
+
+ // VR HWComposer client
+ DvrHwcCreateClientPtr hwc_create_client_;
+ DvrHwcClientDestroyPtr hwc_client_destroy_;
+ DvrHwcFrameDestroyPtr hwc_frame_destroy_;
+ DvrHwcFrameGetDisplayIdPtr hwc_frame_get_display_id_;
+ DvrHwcFrameGetDisplayWidthPtr hwc_frame_get_display_width_;
+ DvrHwcFrameGetDisplayHeightPtr hwc_frame_get_display_height_;
+ DvrHwcFrameGetDisplayRemovedPtr hwc_frame_get_display_removed_;
+ DvrHwcFrameGetLayerCountPtr hwc_frame_get_layer_count_;
+ DvrHwcFrameGetLayerIdPtr hwc_frame_get_layer_id_;
+ DvrHwcFrameGetLayerBufferPtr hwc_frame_get_layer_buffer_;
+ DvrHwcFrameGetLayerFencePtr hwc_frame_get_layer_fence_;
+ DvrHwcFrameGetLayerDisplayFramePtr hwc_frame_get_layer_display_frame_;
+ DvrHwcFrameGetLayerCropPtr hwc_frame_get_layer_crop_;
+ DvrHwcFrameGetLayerBlendModePtr hwc_frame_get_layer_blend_mode_;
+ DvrHwcFrameGetLayerAlphaPtr hwc_frame_get_layer_alpha_;
+ DvrHwcFrameGetLayerTypePtr hwc_frame_get_layer_type_;
+ DvrHwcFrameGetLayerApplicationIdPtr hwc_frame_get_layer_application_id_;
+};
+
+int dvrGetApi(void* api, size_t struct_size, int version);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // ANDROID_DVR_API_H_
diff --git a/libs/vr/libbufferhub/include/private/dvr/dvr_buffer.h b/libs/vr/libdvr/include/dvr/dvr_buffer.h
similarity index 90%
rename from libs/vr/libbufferhub/include/private/dvr/dvr_buffer.h
rename to libs/vr/libdvr/include/dvr/dvr_buffer.h
index c14b1a3..bbfbb00 100644
--- a/libs/vr/libbufferhub/include/private/dvr/dvr_buffer.h
+++ b/libs/vr/libdvr/include/dvr/dvr_buffer.h
@@ -25,6 +25,7 @@
int dvrWriteBufferGainAsync(DvrWriteBuffer* client);
// Read buffer
+void dvrReadBufferDestroy(DvrReadBuffer* client);
void dvrReadBufferGetBlobFds(DvrReadBuffer* client, int* fds, size_t* fds_count,
size_t max_fds_count);
int dvrReadBufferGetAHardwareBuffer(DvrReadBuffer* client,
@@ -45,9 +46,9 @@
class BufferConsumer;
DvrWriteBuffer* CreateDvrWriteBufferFromBufferProducer(
- std::unique_ptr<BufferProducer> buffer_producer);
+ const std::shared_ptr<BufferProducer>& buffer_producer);
DvrReadBuffer* CreateDvrReadBufferFromBufferConsumer(
- std::unique_ptr<BufferConsumer> buffer_consumer);
+ const std::shared_ptr<BufferConsumer>& buffer_consumer);
} // namespace dvr
} // namespace android
diff --git a/libs/vr/libdvr/include/dvr/dvr_buffer_queue.h b/libs/vr/libdvr/include/dvr/dvr_buffer_queue.h
new file mode 100644
index 0000000..80c9779
--- /dev/null
+++ b/libs/vr/libdvr/include/dvr/dvr_buffer_queue.h
@@ -0,0 +1,41 @@
+#ifndef ANDROID_DVR_BUFFER_QUEUE_H_
+#define ANDROID_DVR_BUFFER_QUEUE_H_
+
+#include <dvr/dvr_buffer.h>
+#include <jni.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct DvrWriteBufferQueue DvrWriteBufferQueue;
+typedef struct DvrReadBufferQueue DvrReadBufferQueue;
+
+// WriteBufferQueue
+void dvrWriteBufferQueueDestroy(DvrWriteBufferQueue* write_queue);
+size_t dvrWriteBufferQueueGetCapacity(DvrWriteBufferQueue* write_queue);
+
+// Returns ANativeWindow in the form of jobject. Can be casted to ANativeWindow
+// using ANativeWindow_fromSurface NDK API.
+jobject dvrWriteBufferQueueGetExternalSurface(DvrWriteBufferQueue* write_queue,
+ JNIEnv* env);
+
+int dvrWriteBufferQueueCreateReadQueue(DvrWriteBufferQueue* write_queue,
+ DvrReadBufferQueue** out_read_queue);
+int dvrWriteBufferQueueDequeue(DvrWriteBufferQueue* write_queue, int timeout,
+ DvrWriteBuffer** out_buffer, int* out_fence_fd);
+
+// ReadeBufferQueue
+void dvrReadBufferQueueDestroy(DvrReadBufferQueue* read_queue);
+size_t dvrReadBufferQueueGetCapacity(DvrReadBufferQueue* read_queue);
+int dvrReadBufferQueueCreateReadQueue(DvrReadBufferQueue* read_queue,
+ DvrReadBufferQueue** out_read_queue);
+int dvrReadBufferQueueDequeue(DvrReadBufferQueue* read_queue, int timeout,
+ DvrReadBuffer** out_buffer, int* out_fence_fd,
+ void* out_meta, size_t meta_size_bytes);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // ANDROID_DVR_BUFFER_QUEUE_H_
diff --git a/services/vr/hardware_composer/private/android/dvr_hardware_composer_client.h b/libs/vr/libdvr/include/dvr/dvr_hardware_composer_client.h
similarity index 61%
rename from services/vr/hardware_composer/private/android/dvr_hardware_composer_client.h
rename to libs/vr/libdvr/include/dvr/dvr_hardware_composer_client.h
index 063c16d..eb726a4 100644
--- a/services/vr/hardware_composer/private/android/dvr_hardware_composer_client.h
+++ b/libs/vr/libdvr/include/dvr/dvr_hardware_composer_client.h
@@ -1,29 +1,45 @@
-#ifndef VR_HARDWARE_COMPOSER_PRIVATE_ANDROID_DVR_HARDWARE_COMPOSER_CLIENT_H
-#define VR_HARDWARE_COMPOSER_PRIVATE_ANDROID_DVR_HARDWARE_COMPOSER_CLIENT_H
+#ifndef ANDROID_DVR_HARDWARE_COMPOSER_CLIENT_H
+#define ANDROID_DVR_HARDWARE_COMPOSER_CLIENT_H
-#include <android/dvr_hardware_composer_defs.h>
-#include <android/hardware_buffer.h>
+#include <dvr/dvr_hardware_composer_defs.h>
+#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
+typedef struct AHardwareBuffer AHardwareBuffer;
typedef struct DvrHwcClient DvrHwcClient;
typedef struct DvrHwcFrame DvrHwcFrame;
// Called when a new frame has arrived.
//
+// @param client_state Pointer to client state passed in |dvrHwcCreateClient()|.
// @param frame New frame. Owned by the client.
// @return fence FD for the release of the last frame.
-typedef int(*DvrHwcOnFrameCallback)(DvrHwcFrame* frame);
+typedef int(*DvrHwcOnFrameCallback)(void* client_state, DvrHwcFrame* frame);
-DvrHwcClient* dvrHwcCreateClient(DvrHwcOnFrameCallback callback);
+// @param callback Called when a new frame is available.
+// @param client_state Pointer to client state passed back in the callback.
+DvrHwcClient* dvrHwcCreateClient(DvrHwcOnFrameCallback callback,
+ void* client_state);
+
+void dvrHwcClientDestroy(DvrHwcClient* client);
// Called to free the frame information.
void dvrHwcFrameDestroy(DvrHwcFrame* frame);
Display dvrHwcFrameGetDisplayId(DvrHwcFrame* frame);
+int32_t dvrHwcFrameGetDisplayWidth(DvrHwcFrame* frame);
+
+int32_t dvrHwcFrameGetDisplayHeight(DvrHwcFrame* frame);
+
+// @return True if the display has been removed. In this case the current frame
+// does not contain any valid layers to display. It is a signal to clean up any
+// display related state.
+bool dvrHwcFrameGetDisplayRemoved(DvrHwcFrame* frame);
+
// @return Number of layers in the frame.
size_t dvrHwcFrameGetLayerCount(DvrHwcFrame* frame);
@@ -59,4 +75,4 @@
} // extern "C"
#endif
-#endif // VR_HARDWARE_COMPOSER_PRIVATE_ANDROID_DVR_HARDWARE_COMPOSER_CLIENT_H
+#endif // ANDROID_DVR_HARDWARE_COMPOSER_CLIENT_H
diff --git a/services/vr/hardware_composer/private/android/dvr_hardware_composer_defs.h b/libs/vr/libdvr/include/dvr/dvr_hardware_composer_defs.h
similarity index 78%
rename from services/vr/hardware_composer/private/android/dvr_hardware_composer_defs.h
rename to libs/vr/libdvr/include/dvr/dvr_hardware_composer_defs.h
index 3186f82..546ed7b 100644
--- a/services/vr/hardware_composer/private/android/dvr_hardware_composer_defs.h
+++ b/libs/vr/libdvr/include/dvr/dvr_hardware_composer_defs.h
@@ -1,5 +1,5 @@
-#ifndef VR_HARDWARE_COMPOSER_PRIVATE_ANDROID_VR_HARDWARE_COMPOSER_DEFS_H
-#define VR_HARDWARE_COMPOSER_PRIVATE_ANDROID_VR_HARDWARE_COMPOSER_DEFS_H
+#ifndef ANDROID_VR_HARDWARE_COMPOSER_DEFS_H
+#define ANDROID_VR_HARDWARE_COMPOSER_DEFS_H
#include <inttypes.h>
@@ -47,4 +47,4 @@
} // extern "C"
#endif
-#endif // VR_HARDWARE_COMPOSER_PRIVATE_ANDROID_DVR_HARDWARE_COMPOSER_DEFS_H
+#endif // ANDROID_DVR_HARDWARE_COMPOSER_DEFS_H
diff --git a/libs/vr/libdvr/include/dvr/dvr_surface.h b/libs/vr/libdvr/include/dvr/dvr_surface.h
new file mode 100644
index 0000000..2712f24
--- /dev/null
+++ b/libs/vr/libdvr/include/dvr/dvr_surface.h
@@ -0,0 +1,28 @@
+#ifndef ANDROID_DVR_SURFACE_H_
+#define ANDROID_DVR_SURFACE_H_
+
+#include <dvr/dvr_buffer.h>
+#include <dvr/dvr_buffer_queue.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct DvrSurface DvrSurface;
+typedef struct DvrSurfaceParameter DvrSurfaceParameter;
+
+// Get a pointer to the global pose buffer.
+int dvrGetPoseBuffer(DvrReadBuffer** pose_buffer);
+
+int dvrSurfaceCreate(int width, int height, int format, uint64_t usage0,
+ uint64_t usage1, int flags, DvrSurface** out_surface);
+
+// TODO(eieio, jwcai) Change this once we have multiple buffer queue support.
+int dvrSurfaceGetWriteBufferQueue(DvrSurface* surface,
+ DvrWriteBufferQueue** out_writer);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // ANDROID_DVR_SURFACE_H_
diff --git a/libs/vr/libdisplay/include/private/dvr/vsync_client_api.h b/libs/vr/libdvr/include/dvr/vsync_client_api.h
similarity index 100%
rename from libs/vr/libdisplay/include/private/dvr/vsync_client_api.h
rename to libs/vr/libdvr/include/dvr/vsync_client_api.h
diff --git a/libs/vr/libdvr/tests/Android.mk b/libs/vr/libdvr/tests/Android.mk
new file mode 100644
index 0000000..158d58f
--- /dev/null
+++ b/libs/vr/libdvr/tests/Android.mk
@@ -0,0 +1,29 @@
+LOCAL_PATH := $(call my-dir)
+
+shared_libraries := \
+ libbase \
+ libbinder \
+ libcutils \
+ libgui \
+ liblog \
+ libhardware \
+ libui \
+ libutils \
+
+static_libraries := \
+ libdvr \
+ libbufferhubqueue \
+ libbufferhub \
+ libchrome \
+ libdvrcommon \
+ libpdx_default_transport \
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := dvr_buffer_queue-test.cpp
+LOCAL_STATIC_LIBRARIES := $(static_libraries)
+LOCAL_SHARED_LIBRARIES := $(shared_libraries)
+LOCAL_EXPORT_C_INCLUDE_DIRS := ${LOCAL_C_INCLUDES}
+LOCAL_CFLAGS := -DLOG_TAG=\"dvr_buffer_queue-test\" -DTRACE=0 -O0 -g
+LOCAL_MODULE := dvr_buffer_queue-test
+LOCAL_MODULE_TAGS := optional
+include $(BUILD_NATIVE_TEST)
diff --git a/libs/vr/libdvr/tests/dvr_buffer_queue-test.cpp b/libs/vr/libdvr/tests/dvr_buffer_queue-test.cpp
new file mode 100644
index 0000000..f344a24
--- /dev/null
+++ b/libs/vr/libdvr/tests/dvr_buffer_queue-test.cpp
@@ -0,0 +1,149 @@
+#include <dvr/dvr_buffer_queue.h>
+#include <private/dvr/buffer_hub_queue_client.h>
+
+#include <base/logging.h>
+#include <gtest/gtest.h>
+
+namespace android {
+namespace dvr {
+
+namespace {
+
+static constexpr int kBufferWidth = 100;
+static constexpr int kBufferHeight = 1;
+static constexpr int kBufferFormat = HAL_PIXEL_FORMAT_BLOB;
+static constexpr int kBufferUsage = GRALLOC_USAGE_SW_READ_RARELY;
+static constexpr int kBufferSliceCount = 1; // number of slices in each buffer
+static constexpr size_t kQueueCapacity = 3;
+
+typedef uint64_t TestMeta;
+
+class DvrBufferQueueTest : public ::testing::Test {
+ protected:
+ void SetUp() override {
+ write_queue_ = new DvrWriteBufferQueue;
+ write_queue_->producer_queue_ = ProducerQueue::Create<TestMeta>(0, 0, 0, 0);
+ ASSERT_NE(nullptr, write_queue_->producer_queue_);
+ }
+
+ void TearDown() override {
+ if (write_queue_ != nullptr) {
+ dvrWriteBufferQueueDestroy(write_queue_);
+ write_queue_ = nullptr;
+ }
+ }
+
+ void AllocateBuffers(size_t buffer_count) {
+ size_t out_slot;
+ for (size_t i = 0; i < buffer_count; i++) {
+ int ret = write_queue_->producer_queue_->AllocateBuffer(
+ kBufferWidth, kBufferHeight, kBufferFormat, kBufferUsage,
+ kBufferSliceCount, &out_slot);
+ ASSERT_EQ(0, ret);
+ }
+ }
+
+ DvrWriteBufferQueue* write_queue_{nullptr};
+};
+
+TEST_F(DvrBufferQueueTest, TestWrite_QueueDestroy) {
+ dvrWriteBufferQueueDestroy(write_queue_);
+ write_queue_ = nullptr;
+}
+
+TEST_F(DvrBufferQueueTest, TestWrite_QueueGetCapacity) {
+ AllocateBuffers(kQueueCapacity);
+ size_t capacity = dvrWriteBufferQueueGetCapacity(write_queue_);
+
+ ALOGD_IF(TRACE, "TestWrite_QueueGetCapacity, capacity=%zu", capacity);
+ ASSERT_EQ(kQueueCapacity, capacity);
+}
+
+TEST_F(DvrBufferQueueTest, TestCreateReadQueueFromWriteQueue) {
+ DvrReadBufferQueue* read_queue = nullptr;
+ int ret = dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue);
+
+ ASSERT_EQ(0, ret);
+ ASSERT_NE(nullptr, read_queue);
+
+ dvrReadBufferQueueDestroy(read_queue);
+}
+
+TEST_F(DvrBufferQueueTest, TestCreateReadQueueFromReadQueue) {
+ DvrReadBufferQueue* read_queue1 = nullptr;
+ DvrReadBufferQueue* read_queue2 = nullptr;
+ int ret = dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue1);
+
+ ASSERT_EQ(0, ret);
+ ASSERT_NE(nullptr, read_queue1);
+
+ ret = dvrReadBufferQueueCreateReadQueue(read_queue1, &read_queue2);
+ ASSERT_EQ(0, ret);
+ ASSERT_NE(nullptr, read_queue2);
+ ASSERT_NE(read_queue1, read_queue2);
+
+ dvrReadBufferQueueDestroy(read_queue1);
+ dvrReadBufferQueueDestroy(read_queue2);
+}
+
+TEST_F(DvrBufferQueueTest, TestDequeuePostDequeueRelease) {
+ static constexpr int kTimeout = 0;
+ DvrReadBufferQueue* read_queue = nullptr;
+ DvrReadBuffer* rb = nullptr;
+ DvrWriteBuffer* wb = nullptr;
+ int fence_fd = -1;
+
+ int ret = dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue);
+
+ ASSERT_EQ(0, ret);
+ ASSERT_NE(nullptr, read_queue);
+
+ AllocateBuffers(kQueueCapacity);
+
+ // Gain buffer for writing.
+ ret = dvrWriteBufferQueueDequeue(write_queue_, kTimeout, &wb, &fence_fd);
+ ASSERT_EQ(0, ret);
+ ASSERT_NE(nullptr, wb);
+ ALOGD_IF(TRACE, "TestDequeuePostDequeueRelease, gain buffer %p, fence_fd=%d",
+ wb, fence_fd);
+ pdx::LocalHandle release_fence(fence_fd);
+
+ // Post buffer to the read_queue.
+ TestMeta seq = 42U;
+ ret = dvrWriteBufferPost(wb, /* fence */ -1, &seq, sizeof(seq));
+ ASSERT_EQ(0, ret);
+ dvrWriteBufferDestroy(wb);
+ wb = nullptr;
+
+ // Acquire buffer for reading.
+ TestMeta acquired_seq = 0U;
+ ret = dvrReadBufferQueueDequeue(read_queue, kTimeout, &rb, &fence_fd,
+ &acquired_seq, sizeof(acquired_seq));
+ ASSERT_EQ(0, ret);
+ ASSERT_NE(nullptr, rb);
+ ASSERT_EQ(seq, acquired_seq);
+ ALOGD_IF(TRACE,
+ "TestDequeuePostDequeueRelease, acquire buffer %p, fence_fd=%d", rb,
+ fence_fd);
+ pdx::LocalHandle acquire_fence(fence_fd);
+
+ // Release buffer to the write_queue.
+ ret = dvrReadBufferRelease(rb, -1);
+ ASSERT_EQ(0, ret);
+ dvrReadBufferDestroy(rb);
+ rb = nullptr;
+
+ // TODO(b/34387835) Currently buffer allocation has to happen after all queues
+ // are initialized.
+ size_t capacity = dvrReadBufferQueueGetCapacity(read_queue);
+
+ ALOGD_IF(TRACE, "TestDequeuePostDequeueRelease, capacity=%zu", capacity);
+ ASSERT_EQ(kQueueCapacity, capacity);
+
+ dvrReadBufferQueueDestroy(read_queue);
+}
+
+} // namespace
+
+} // namespace dvr
+} // namespace android
diff --git a/libs/vr/libdisplay/vsync_client_api.cpp b/libs/vr/libdvr/vsync_client_api.cpp
similarity index 93%
rename from libs/vr/libdisplay/vsync_client_api.cpp
rename to libs/vr/libdvr/vsync_client_api.cpp
index 00af525..dbddd3d 100644
--- a/libs/vr/libdisplay/vsync_client_api.cpp
+++ b/libs/vr/libdvr/vsync_client_api.cpp
@@ -1,4 +1,4 @@
-#include "include/private/dvr/vsync_client_api.h"
+#include "include/dvr/vsync_client_api.h"
#include <private/dvr/vsync_client.h>
diff --git a/libs/vr/libdvrcommon/Android.bp b/libs/vr/libdvrcommon/Android.bp
index 81404a4..eb78348 100644
--- a/libs/vr/libdvrcommon/Android.bp
+++ b/libs/vr/libdvrcommon/Android.bp
@@ -14,8 +14,6 @@
sourceFiles = [
"frame_time_history.cpp",
- "revision.cpp",
- "revision_path.cpp",
"sync_util.cpp",
]
diff --git a/libs/vr/libdvrcommon/include/private/dvr/benchmark.h b/libs/vr/libdvrcommon/include/private/dvr/benchmark.h
index 2dbb5f2..7eeab16 100644
--- a/libs/vr/libdvrcommon/include/private/dvr/benchmark.h
+++ b/libs/vr/libdvrcommon/include/private/dvr/benchmark.h
@@ -19,7 +19,7 @@
// ... code to benchmark ...
// Btrace("End execution");
//
-// Use compute_benchmarks.py (currently in dreamos/system/core/applications),
+// Use compute_benchmarks.py
// with the trace path "Start execution,End execution",
// to report the elapsed time between the two calls.
//
diff --git a/libs/vr/libdvrcommon/include/private/dvr/revision.h b/libs/vr/libdvrcommon/include/private/dvr/revision.h
deleted file mode 100644
index dda0fce..0000000
--- a/libs/vr/libdvrcommon/include/private/dvr/revision.h
+++ /dev/null
@@ -1,47 +0,0 @@
-#ifndef LIBS_VR_LIBDVRCOMMON_INCLUDE_PRIVATE_DVR_REVISION_H_
-#define LIBS_VR_LIBDVRCOMMON_INCLUDE_PRIVATE_DVR_REVISION_H_
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-// List of DreamOS products
-typedef enum DvrProduct {
- DVR_PRODUCT_UNKNOWN,
- DVR_PRODUCT_A00,
- DVR_PRODUCT_A65R,
- DVR_PRODUCT_TWILIGHT = DVR_PRODUCT_A65R
-} DvrProduct;
-
-// List of possible revisions.
-typedef enum DvrRevision {
- DVR_REVISION_UNKNOWN,
- DVR_REVISION_P1,
- DVR_REVISION_P2,
- DVR_REVISION_P3,
-} DvrRevision;
-
-// Query the device's product.
-//
-// @return DvrProduct value, or DvrProductUnknown on error.
-DvrProduct dvr_get_product();
-
-// Query the device's revision.
-//
-// @return DvrRevision value, or DvrRevisionUnknown on error.
-DvrRevision dvr_get_revision();
-
-// Returns the device's board revision string.
-//
-// @return NULL-terminated string such as 'a00-p1'.
-const char* dvr_get_product_revision_str();
-
-// Returns the device's serial number.
-//
-// @return Returns NULL on error, or a NULL-terminated string.
-const char* dvr_get_serial_number();
-
-#ifdef __cplusplus
-}
-#endif // extern "C"
-#endif // LIBS_VR_LIBDVRCOMMON_INCLUDE_PRIVATE_DVR_REVISION_H_
diff --git a/libs/vr/libdvrcommon/revision.cpp b/libs/vr/libdvrcommon/revision.cpp
deleted file mode 100644
index 7925f65..0000000
--- a/libs/vr/libdvrcommon/revision.cpp
+++ /dev/null
@@ -1,175 +0,0 @@
-#include "private/dvr/revision.h"
-
-#include <errno.h>
-#include <fcntl.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/mman.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <log/log.h>
-
-#include "revision_path.h"
-
-namespace {
-
-// Allows quicker access to the product revision. If non-zero, then
-// the product revision file has already been processed.
-static bool global_product_revision_processed = false;
-
-static bool global_serial_number_processed = false;
-
-// The product.
-static DvrProduct global_product = DVR_PRODUCT_UNKNOWN;
-
-// The revision.
-static DvrRevision global_revision = DVR_REVISION_UNKNOWN;
-
-// Maximum size of the product revision string.
-constexpr int kProductRevisionStringSize = 32;
-
-// Maximum size of the serial number.
-constexpr int kSerialNumberStringSize = 32;
-
-// The product revision string.
-static char global_product_revision_str[kProductRevisionStringSize + 1] = "";
-
-// The serial number string
-static char global_serial_number[kSerialNumberStringSize + 1] = "";
-
-// Product and revision combinations.
-struct DvrProductRevision {
- const char* str;
- DvrProduct product;
- DvrRevision revision;
-};
-
-// Null-terminated list of all product and revision combinations.
-static constexpr DvrProductRevision kProductRevisions[] = {
- {"a00-p1", DVR_PRODUCT_A00, DVR_REVISION_P1},
- {"a00-p2", DVR_PRODUCT_A00, DVR_REVISION_P2},
- {"a00-p3", DVR_PRODUCT_A00, DVR_REVISION_P3},
- {"twilight-p1", DVR_PRODUCT_A65R, DVR_REVISION_P1},
- {"twilight-p2", DVR_PRODUCT_A65R, DVR_REVISION_P2},
- {NULL, DVR_PRODUCT_UNKNOWN, DVR_REVISION_UNKNOWN}};
-
-// Read the product revision string, and store the global data.
-static void process_product_revision() {
- int fd;
- ssize_t read_rc;
- const DvrProductRevision* product_revision = kProductRevisions;
-
- // Of course in a multi-threaded environment, for a few microseconds
- // during process startup, it is possible that this function will be
- // called and execute fully multiple times. That is why the product
- // revision string is statically allocated.
-
- if (global_product_revision_processed)
- return;
-
- // Whether there was a failure or not, we don't want to do this again.
- // Upon failure it's most likely to fail again anyway.
-
- fd = open(dvr_product_revision_file_path(), O_RDONLY);
- if (fd < 0) {
- ALOGE("Could not open '%s' to get product revision: %s",
- dvr_product_revision_file_path(), strerror(errno));
- global_product_revision_processed = true;
- return;
- }
-
- read_rc = read(fd, global_product_revision_str, kProductRevisionStringSize);
- if (read_rc <= 0) {
- ALOGE("Could not read from '%s': %s", dvr_product_revision_file_path(),
- strerror(errno));
- global_product_revision_processed = true;
- return;
- }
-
- close(fd);
-
- global_product_revision_str[read_rc] = '\0';
-
- while (product_revision->str) {
- if (!strcmp(product_revision->str, global_product_revision_str))
- break;
- product_revision++;
- }
-
- if (product_revision->str) {
- global_product = product_revision->product;
- global_revision = product_revision->revision;
- } else {
- ALOGE("Unable to match '%s' to a product/revision.",
- global_product_revision_str);
- }
-
- global_product_revision_processed = true;
-}
-
-} // anonymous namespace
-
-extern "C" DvrProduct dvr_get_product() {
- process_product_revision();
- return global_product;
-}
-
-extern "C" DvrRevision dvr_get_revision() {
- process_product_revision();
- return global_revision;
-}
-
-extern "C" const char* dvr_get_product_revision_str() {
- process_product_revision();
- return global_product_revision_str;
-}
-
-extern "C" const char* dvr_get_serial_number() {
- process_product_revision();
- if (global_product == DVR_PRODUCT_A00) {
- if (!global_serial_number_processed) {
-#ifdef DVR_HOST
- global_serial_number_processed = true;
-#else
- int width = 4;
- uintptr_t addr = 0x00074138;
- uintptr_t endaddr = addr + width - 1;
-
- int fd = open("/dev/mem", O_RDWR | O_SYNC);
- if (fd < 0) {
- if (errno == EPERM)
- global_serial_number_processed = true;
- fprintf(stderr, "cannot open /dev/mem\n");
- return global_serial_number;
- }
-
- off64_t mmap_start = addr & ~(PAGE_SIZE - 1);
- size_t mmap_size = endaddr - mmap_start + 1;
- mmap_size = (mmap_size + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1);
-
- void* page = mmap64(0, mmap_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd,
- mmap_start);
-
- if (page == MAP_FAILED) {
- global_serial_number_processed = true;
- fprintf(stderr, "cannot mmap region\n");
- close(fd);
- return global_serial_number;
- }
-
- uint32_t* x =
- reinterpret_cast<uint32_t*>((((uintptr_t)page) + (addr & 4095)));
- snprintf(global_serial_number, kSerialNumberStringSize, "%08x", *x);
- global_serial_number_processed = true;
-
- munmap(page, mmap_size);
- close(fd);
-#endif
- }
- return global_serial_number;
- } else {
- return nullptr;
- }
-}
diff --git a/libs/vr/libdvrcommon/revision_path.cpp b/libs/vr/libdvrcommon/revision_path.cpp
deleted file mode 100644
index c49f9aa..0000000
--- a/libs/vr/libdvrcommon/revision_path.cpp
+++ /dev/null
@@ -1,15 +0,0 @@
-#include "revision_path.h"
-
-namespace {
-
-// The path to the product revision file.
-static const char* kProductRevisionFilePath =
- "/sys/firmware/devicetree/base/goog,board-revision";
-
-} // anonymous namespace
-
-// This exists in a separate file so that it can be replaced for
-// testing.
-const char* dvr_product_revision_file_path() {
- return kProductRevisionFilePath;
-}
diff --git a/libs/vr/libdvrcommon/revision_path.h b/libs/vr/libdvrcommon/revision_path.h
deleted file mode 100644
index afcea46..0000000
--- a/libs/vr/libdvrcommon/revision_path.h
+++ /dev/null
@@ -1,9 +0,0 @@
-#ifndef ANDROID_DVR_LIBDVRCOMMON_REVISION_PATH_H_
-#define ANDROID_DVR_LIBDVRCOMMON_REVISION_PATH_H_
-
-// Returns the revision file path.
-// This exists in a separate file so that it can be replaced for
-// testing.
-const char* dvr_product_revision_file_path();
-
-#endif // ANDROID_DVR_LIBDVRCOMMON_REVISION_PATH_H_
diff --git a/libs/vr/libdvrcommon/tests/revision_app_tests.cpp b/libs/vr/libdvrcommon/tests/revision_app_tests.cpp
deleted file mode 100644
index 772481b..0000000
--- a/libs/vr/libdvrcommon/tests/revision_app_tests.cpp
+++ /dev/null
@@ -1,34 +0,0 @@
-#include <dvr/test/app_test.h>
-#include <gtest/gtest.h>
-#include <private/dvr/revision.h>
-
-// Making sure this information is not available
-// inside the sandbox
-
-namespace {
-
-TEST(RevisionTests, GetProduct) {
- ASSERT_EQ(DVR_PRODUCT_UNKNOWN, dvr_get_product());
-}
-
-TEST(RevisionTests, GetRevision) {
- ASSERT_EQ(DVR_REVISION_UNKNOWN, dvr_get_revision());
-}
-
-TEST(RevisionTests, GetRevisionStr) {
- ASSERT_STREQ("", dvr_get_product_revision_str());
-}
-
-TEST(RevisionTests, GetSerialNo) {
- ASSERT_EQ(nullptr, dvr_get_serial_number());
-}
-
-} // namespace
-
-int main(int argc, char* argv[]) {
- dreamos::test::AppTestBegin();
- ::testing::InitGoogleTest(&argc, argv);
- int result = RUN_ALL_TESTS();
- dreamos::test::AppTestEnd(result);
- return result;
-}
diff --git a/libs/vr/libdvrcommon/tests/revision_tests.cpp b/libs/vr/libdvrcommon/tests/revision_tests.cpp
deleted file mode 100644
index 9abf480..0000000
--- a/libs/vr/libdvrcommon/tests/revision_tests.cpp
+++ /dev/null
@@ -1,27 +0,0 @@
-#include <gtest/gtest.h>
-#include <private/dvr/revision.h>
-
-namespace {
-
-TEST(RevisionTests, GetProduct) {
- ASSERT_NE(DVR_PRODUCT_UNKNOWN, dvr_get_product());
-}
-
-TEST(RevisionTests, GetRevision) {
- ASSERT_NE(DVR_REVISION_UNKNOWN, dvr_get_revision());
-}
-
-TEST(RevisionTests, GetRevisionStr) {
- ASSERT_NE(nullptr, dvr_get_product_revision_str());
-}
-
-TEST(RevisionTests, GetSerialNo) {
- ASSERT_NE(nullptr, dvr_get_serial_number());
-}
-
-} // namespace
-
-int main(int argc, char* argv[]) {
- ::testing::InitGoogleTest(&argc, argv);
- return RUN_ALL_TESTS();
-}
diff --git a/libs/vr/libimageio/include/private/dvr/image_io_base.h b/libs/vr/libimageio/include/private/dvr/image_io_base.h
index 009cad4..5f29de7 100644
--- a/libs/vr/libimageio/include/private/dvr/image_io_base.h
+++ b/libs/vr/libimageio/include/private/dvr/image_io_base.h
@@ -1,5 +1,5 @@
-#ifndef LIB_LIBIMAGEIO_PRIVATE_DREAMOS_IMAGE_IO_BASE_H_
-#define LIB_LIBIMAGEIO_PRIVATE_DREAMOS_IMAGE_IO_BASE_H_
+#ifndef LIB_LIBIMAGEIO_PRIVATE_DVR_IMAGE_IO_BASE_H_
+#define LIB_LIBIMAGEIO_PRIVATE_DVR_IMAGE_IO_BASE_H_
#include <memory>
#include <string>
@@ -53,4 +53,4 @@
ImageIoWriter() = delete;
};
-#endif // LIB_LIBIMAGEIO_PRIVATE_DREAMOS_IMAGE_IO_BASE_H_
+#endif // LIB_LIBIMAGEIO_PRIVATE_DVR_IMAGE_IO_BASE_H_
diff --git a/libs/vr/libimageio/include/private/dvr/image_io_logging.h b/libs/vr/libimageio/include/private/dvr/image_io_logging.h
index ac78179..a2629f3 100644
--- a/libs/vr/libimageio/include/private/dvr/image_io_logging.h
+++ b/libs/vr/libimageio/include/private/dvr/image_io_logging.h
@@ -1,5 +1,5 @@
-#ifndef LIB_LIBIMAGEIO_PRIVATE_DREAMOS_IMAGE_IO_LOGGING_H_
-#define LIB_LIBIMAGEIO_PRIVATE_DREAMOS_IMAGE_IO_LOGGING_H_
+#ifndef LIB_LIBIMAGEIO_PRIVATE_DVR_IMAGE_IO_LOGGING_H_
+#define LIB_LIBIMAGEIO_PRIVATE_DVR_IMAGE_IO_LOGGING_H_
// This header acts as log/log.h if LOG_TO_STDERR is not defined.
// If LOG_TO_STDERR is defined, then android logging macros (such as ALOGE)
@@ -36,4 +36,4 @@
#include <log/log.h>
#endif // LOG_TO_STDERR
-#endif // LIB_LIBIMAGEIO_PRIVATE_DREAMOS_IMAGE_IO_LOGGING_H_
+#endif // LIB_LIBIMAGEIO_PRIVATE_DVR_IMAGE_IO_LOGGING_H_
diff --git a/libs/vr/libimageio/include/private/dvr/image_io_png.h b/libs/vr/libimageio/include/private/dvr/image_io_png.h
index e3b19db..e06a17a 100644
--- a/libs/vr/libimageio/include/private/dvr/image_io_png.h
+++ b/libs/vr/libimageio/include/private/dvr/image_io_png.h
@@ -1,5 +1,5 @@
-#ifndef LIB_LIBIMAGEIO_PRIVATE_DREAMOS_IMAGE_IO_PNG_H_
-#define LIB_LIBIMAGEIO_PRIVATE_DREAMOS_IMAGE_IO_PNG_H_
+#ifndef LIB_LIBIMAGEIO_PRIVATE_DVR_IMAGE_IO_PNG_H_
+#define LIB_LIBIMAGEIO_PRIVATE_DVR_IMAGE_IO_PNG_H_
#include <fstream>
@@ -21,4 +21,4 @@
friend class ImageIoWriter;
};
-#endif // LIB_LIBIMAGEIO_PRIVATE_DREAMOS_IMAGE_IO_PNG_H_
+#endif // LIB_LIBIMAGEIO_PRIVATE_DVR_IMAGE_IO_PNG_H_
diff --git a/libs/vr/libimageio/include/private/dvr/image_io_ppm.h b/libs/vr/libimageio/include/private/dvr/image_io_ppm.h
index 00264bd..8a1a96c 100644
--- a/libs/vr/libimageio/include/private/dvr/image_io_ppm.h
+++ b/libs/vr/libimageio/include/private/dvr/image_io_ppm.h
@@ -1,5 +1,5 @@
-#ifndef LIB_LIBIMAGEIO_PRIVATE_DREAMOS_IMAGE_IO_PPM_H_
-#define LIB_LIBIMAGEIO_PRIVATE_DREAMOS_IMAGE_IO_PPM_H_
+#ifndef LIB_LIBIMAGEIO_PRIVATE_DVR_IMAGE_IO_PPM_H_
+#define LIB_LIBIMAGEIO_PRIVATE_DVR_IMAGE_IO_PPM_H_
#include <private/dvr/image_io_base.h>
@@ -25,4 +25,4 @@
friend class ImageIoWriter;
};
-#endif // LIB_LIBIMAGEIO_PRIVATE_DREAMOS_IMAGE_IO_PPM_H_
+#endif // LIB_LIBIMAGEIO_PRIVATE_DVR_IMAGE_IO_PPM_H_
diff --git a/libs/vr/libpdx/service.cpp b/libs/vr/libpdx/service.cpp
index d2804d5..daf9af8 100644
--- a/libs/vr/libpdx/service.cpp
+++ b/libs/vr/libpdx/service.cpp
@@ -129,7 +129,7 @@
PDX_TRACE_NAME("Message::PushFileHandle");
if (auto svc = service_.lock()) {
ErrnoGuard errno_guard;
- return svc->endpoint()->PushFileHandle(this, handle);
+ return ReturnCodeOrError(svc->endpoint()->PushFileHandle(this, handle));
} else {
return -ESHUTDOWN;
}
@@ -139,7 +139,7 @@
PDX_TRACE_NAME("Message::PushFileHandle");
if (auto svc = service_.lock()) {
ErrnoGuard errno_guard;
- return svc->endpoint()->PushFileHandle(this, handle);
+ return ReturnCodeOrError(svc->endpoint()->PushFileHandle(this, handle));
} else {
return -ESHUTDOWN;
}
@@ -149,7 +149,7 @@
PDX_TRACE_NAME("Message::PushFileHandle");
if (auto svc = service_.lock()) {
ErrnoGuard errno_guard;
- return svc->endpoint()->PushFileHandle(this, handle);
+ return ReturnCodeOrError(svc->endpoint()->PushFileHandle(this, handle));
} else {
return -ESHUTDOWN;
}
@@ -159,7 +159,7 @@
PDX_TRACE_NAME("Message::PushChannelHandle");
if (auto svc = service_.lock()) {
ErrnoGuard errno_guard;
- return svc->endpoint()->PushChannelHandle(this, handle);
+ return ReturnCodeOrError(svc->endpoint()->PushChannelHandle(this, handle));
} else {
return -ESHUTDOWN;
}
@@ -170,7 +170,7 @@
PDX_TRACE_NAME("Message::PushChannelHandle");
if (auto svc = service_.lock()) {
ErrnoGuard errno_guard;
- return svc->endpoint()->PushChannelHandle(this, handle);
+ return ReturnCodeOrError(svc->endpoint()->PushChannelHandle(this, handle));
} else {
return -ESHUTDOWN;
}
@@ -180,7 +180,7 @@
PDX_TRACE_NAME("Message::PushChannelHandle");
if (auto svc = service_.lock()) {
ErrnoGuard errno_guard;
- return svc->endpoint()->PushChannelHandle(this, handle);
+ return ReturnCodeOrError(svc->endpoint()->PushChannelHandle(this, handle));
} else {
return -ESHUTDOWN;
}
diff --git a/libs/vr/libpdx_uds/client_channel_factory.cpp b/libs/vr/libpdx_uds/client_channel_factory.cpp
index 1879127..f059453 100644
--- a/libs/vr/libpdx_uds/client_channel_factory.cpp
+++ b/libs/vr/libpdx_uds/client_channel_factory.cpp
@@ -6,10 +6,16 @@
#include <sys/un.h>
#include <unistd.h>
+#include <chrono>
+#include <thread>
+
#include <uds/channel_manager.h>
#include <uds/client_channel.h>
#include <uds/ipc_helper.h>
+using std::chrono::duration_cast;
+using std::chrono::steady_clock;
+
namespace android {
namespace pdx {
namespace uds {
@@ -41,13 +47,11 @@
Status<std::unique_ptr<pdx::ClientChannel>> ClientChannelFactory::Connect(
int64_t timeout_ms) const {
- auto status = WaitForEndpoint(endpoint_path_, timeout_ms);
- if (!status)
- return ErrorStatus(status.error());
+ Status<void> status;
LocalHandle socket_fd{socket(AF_UNIX, SOCK_STREAM, 0)};
if (!socket_fd) {
- ALOGE("ClientChannelFactory::Connect: socket error %s", strerror(errno));
+ ALOGE("ClientChannelFactory::Connect: socket error: %s", strerror(errno));
return ErrorStatus(errno);
}
@@ -56,16 +60,55 @@
strncpy(remote.sun_path, endpoint_path_.c_str(), sizeof(remote.sun_path));
remote.sun_path[sizeof(remote.sun_path) - 1] = '\0';
- int ret = RETRY_EINTR(connect(
- socket_fd.Get(), reinterpret_cast<sockaddr*>(&remote), sizeof(remote)));
- if (ret == -1) {
- ALOGE(
- "ClientChannelFactory::Connect: Failed to initialize connection when "
- "connecting %s",
- strerror(errno));
- return ErrorStatus(errno);
- }
+ bool use_timeout = (timeout_ms >= 0);
+ auto now = steady_clock::now();
+ auto time_end = now + std::chrono::milliseconds{timeout_ms};
+ bool connected = false;
+ while (!connected) {
+ int64_t timeout = -1;
+ if (use_timeout) {
+ auto remaining = time_end - now;
+ timeout = duration_cast<std::chrono::milliseconds>(remaining).count();
+ if (timeout < 0)
+ return ErrorStatus(ETIMEDOUT);
+ }
+ ALOGD("ClientChannelFactory: Waiting for endpoint at %s", remote.sun_path);
+ status = WaitForEndpoint(endpoint_path_, timeout);
+ if (!status)
+ return ErrorStatus(status.error());
+
+ ALOGD("ClientChannelFactory: Connecting to %s", remote.sun_path);
+ int ret = RETRY_EINTR(connect(
+ socket_fd.Get(), reinterpret_cast<sockaddr*>(&remote), sizeof(remote)));
+ if (ret == -1) {
+ ALOGD("ClientChannelFactory: Connect error %d: %s", errno,
+ strerror(errno));
+ if (errno == ECONNREFUSED) {
+ // Connection refused can be the result of connecting too early (the
+ // service socket is created but not being listened to yet).
+ ALOGD("ClientChannelFactory: Connection refused, waiting...");
+ using namespace std::literals::chrono_literals;
+ std::this_thread::sleep_for(100ms);
+ } else if (errno != ENOENT && errno != ENOTDIR) {
+ // ENOENT/ENOTDIR might mean that the socket file/directory containing
+ // it has been just deleted. Try to wait for its creation and do not
+ // return an error immediately.
+ ALOGE(
+ "ClientChannelFactory::Connect: Failed to initialize connection "
+ "when connecting: %s",
+ strerror(errno));
+ return ErrorStatus(errno);
+ }
+ } else {
+ connected = true;
+ }
+ if (use_timeout)
+ now = steady_clock::now();
+ } // while (!connected)
+
+ ALOGD("ClientChannelFactory: Connected successfully to %s...",
+ remote.sun_path);
RequestHeader<BorrowedHandle> request;
InitRequest(&request, opcodes::CHANNEL_OPEN, 0, 0, false);
status = SendData(socket_fd.Get(), request);
diff --git a/libs/vr/libvrflinger/acquired_buffer.h b/libs/vr/libvrflinger/acquired_buffer.h
index 050cd5f..1d14a38 100644
--- a/libs/vr/libvrflinger/acquired_buffer.h
+++ b/libs/vr/libvrflinger/acquired_buffer.h
@@ -43,7 +43,7 @@
// Accessors for the underlying BufferConsumer, the acquire fence, and the
// use-case specific sequence value from the acquisition (see
- // dreamos/buffer_hub_client.h).
+ // private/dvr/buffer_hub_client.h).
std::shared_ptr<BufferConsumer> buffer() const { return buffer_; }
int acquire_fence() const { return acquire_fence_.Get(); }
diff --git a/libs/vr/libvrflinger/compositor.cpp b/libs/vr/libvrflinger/compositor.cpp
index 5a111d4..699088e 100644
--- a/libs/vr/libvrflinger/compositor.cpp
+++ b/libs/vr/libvrflinger/compositor.cpp
@@ -48,10 +48,10 @@
std::make_shared<int64_t>(0);
static constexpr char kDisableLensDistortionProp[] =
- "persist.dreamos.disable_distort";
+ "persist.dvr.disable_distort";
static constexpr char kEnableEdsPoseSaveProp[] =
- "persist.dreamos.save_eds_pose";
+ "persist.dvr.save_eds_pose";
namespace android {
namespace dvr {
diff --git a/libs/vr/libvrflinger/hardware_composer.cpp b/libs/vr/libvrflinger/hardware_composer.cpp
index 542bbd9..71591d4 100644
--- a/libs/vr/libvrflinger/hardware_composer.cpp
+++ b/libs/vr/libvrflinger/hardware_composer.cpp
@@ -64,7 +64,7 @@
const char kDvrPerformanceProperty[] = "sys.dvr.performance";
-const char kRightEyeOffsetProperty[] = "dreamos.right_eye_offset_ns";
+const char kRightEyeOffsetProperty[] = "dvr.right_eye_offset_ns";
// Returns our best guess for the time the compositor will spend rendering the
// next frame.
diff --git a/libs/vr/libvrsensor/include/dvr/pose_client.h b/libs/vr/libvrsensor/include/dvr/pose_client.h
index ed75f84..6802fa9 100644
--- a/libs/vr/libvrsensor/include/dvr/pose_client.h
+++ b/libs/vr/libvrsensor/include/dvr/pose_client.h
@@ -105,6 +105,8 @@
DVR_POSE_MODE_MOCK_ROTATE_MEDIUM,
DVR_POSE_MODE_MOCK_ROTATE_FAST,
DVR_POSE_MODE_MOCK_CIRCLE_STRAFE,
+ DVR_POSE_MODE_FLOAT,
+ DVR_POSE_MODE_MOCK_MOTION_SICKNESS,
// Always last.
DVR_POSE_MODE_COUNT,
diff --git a/services/sensorservice/SensorDevice.cpp b/services/sensorservice/SensorDevice.cpp
index 2a17a7f..080c02b 100644
--- a/services/sensorservice/SensorDevice.cpp
+++ b/services/sensorservice/SensorDevice.cpp
@@ -52,6 +52,31 @@
}
SensorDevice::SensorDevice() : mHidlTransportErrors(20) {
+ if (!connectHidlService()) {
+ return;
+ }
+ checkReturn(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);
+
+ checkReturn(mSensors->activate(list[i].sensorHandle, 0 /* enabled */));
+ }
+ }));
+
+ mIsDirectReportSupported =
+ (checkReturn(mSensors->unregisterDirectChannel(-1)) != Result::INVALID_OPERATION);
+}
+
+bool SensorDevice::connectHidlService() {
// SensorDevice may wait upto 100ms * 10 = 1s for hidl service.
constexpr auto RETRY_DELAY = std::chrono::milliseconds(100);
size_t retry = 10;
@@ -74,7 +99,7 @@
if (--retry <= 0) {
ALOGE("Cannot connect to ISensors hidl service!");
- return;
+ break;
}
// Delay 100ms before retry, hidl service is expected to come up in short time after
// crash.
@@ -82,29 +107,11 @@
(initStep == 0) ? "getService()" : "poll() check", retry);
std::this_thread::sleep_for(RETRY_DELAY);
}
-
- checkReturn(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);
-
- checkReturn(mSensors->activate(list[i].sensorHandle, 0 /* enabled */));
- }
- }));
-
- mIsDirectReportSupported =
- (checkReturn(mSensors->unregisterDirectChannel(-1)) != Result::INVALID_OPERATION);
+ return (mSensors != nullptr);
}
void SensorDevice::handleDynamicSensorConnection(int handle, bool connected) {
+ // not need to check mSensors because this is is only called after successful poll()
if (connected) {
Info model;
mActivationCount.add(handle, model);
@@ -115,64 +122,38 @@
}
std::string SensorDevice::dump() const {
- if (mSensors == NULL) return "HAL not initialized\n";
+ if (mSensors == nullptr) return "HAL not initialized\n";
String8 result;
+ result.appendFormat("Total %zu h/w sensors, %zu running:\n",
+ mSensorList.size(), mActivationCount.size());
- result.appendFormat("Saw %d hidlTransport Errors\n", mTotalHidlTransportErrors);
- for (auto it = mHidlTransportErrors.begin() ; it != mHidlTransportErrors.end(); it++ ) {
- result += "\t";
- result += it->toString();
- result += "\n";
+ Mutex::Autolock _l(mLock);
+ for (const auto & s : mSensorList) {
+ int32_t handle = s.handle;
+ const Info& info = mActivationCount.valueFor(handle);
+ if (info.batchParams.isEmpty()) continue;
+
+ result.appendFormat("0x%08x) active-count = %zu; ", handle, 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);
}
- checkReturn(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();
}
@@ -187,7 +168,7 @@
}
ssize_t SensorDevice::poll(sensors_event_t* buffer, size_t count) {
- if (mSensors == NULL) return NO_INIT;
+ if (mSensors == nullptr) return NO_INIT;
ssize_t err;
int numHidlTransportErrors = 0;
@@ -239,7 +220,7 @@
}
status_t SensorDevice::activate(void* ident, int handle, int enabled) {
- if (mSensors == NULL) return NO_INIT;
+ if (mSensors == nullptr) return NO_INIT;
status_t err(NO_ERROR);
bool actuateHardware = false;
@@ -328,7 +309,7 @@
int flags,
int64_t samplingPeriodNs,
int64_t maxBatchReportLatencyNs) {
- if (mSensors == NULL) return NO_INIT;
+ if (mSensors == nullptr) return NO_INIT;
if (samplingPeriodNs < MINIMUM_EVENTS_PERIOD) {
samplingPeriodNs = MINIMUM_EVENTS_PERIOD;
@@ -382,7 +363,7 @@
}
status_t SensorDevice::setDelay(void* ident, int handle, int64_t samplingPeriodNs) {
- if (mSensors == NULL) return NO_INIT;
+ if (mSensors == nullptr) return NO_INIT;
if (samplingPeriodNs < MINIMUM_EVENTS_PERIOD) {
samplingPeriodNs = MINIMUM_EVENTS_PERIOD;
}
@@ -407,11 +388,12 @@
}
int SensorDevice::getHalDeviceVersion() const {
- if (mSensors == NULL) return -1;
+ if (mSensors == nullptr) return -1;
return SENSORS_DEVICE_API_VERSION_1_4;
}
status_t SensorDevice::flush(void* ident, int handle) {
+ if (mSensors == nullptr) return NO_INIT;
if (isClientDisabled(ident)) return INVALID_OPERATION;
ALOGD_IF(DEBUG_CONNECTIONS, "\t>>> actuating h/w flush %d", handle);
return StatusFromResult(checkReturn(mSensors->flush(handle)));
@@ -427,6 +409,7 @@
}
void SensorDevice::enableAllSensors() {
+ if (mSensors == nullptr) return;
Mutex::Autolock _l(mLock);
mDisabledClients.clear();
ALOGI("cleared mDisabledClients");
@@ -453,8 +436,9 @@
}
void SensorDevice::disableAllSensors() {
+ if (mSensors == nullptr) return;
Mutex::Autolock _l(mLock);
- for (size_t i = 0; i< mActivationCount.size(); ++i) {
+ 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) {
@@ -475,6 +459,7 @@
status_t SensorDevice::injectSensorData(
const sensors_event_t *injected_sensor_event) {
+ if (mSensors == nullptr) return NO_INIT;
ALOGD_IF(DEBUG_CONNECTIONS,
"sensor_event handle=%d ts=%" PRId64 " data=%.2f, %.2f, %.2f %.2f %.2f %.2f",
injected_sensor_event->sensor,
@@ -490,10 +475,97 @@
}
status_t SensorDevice::setMode(uint32_t mode) {
+ if (mSensors == nullptr) return NO_INIT;
+ return StatusFromResult(
+ checkReturn(mSensors->setOperationMode(
+ static_cast<hardware::sensors::V1_0::OperationMode>(mode))));
+}
- return StatusFromResult(
- checkReturn(mSensors->setOperationMode(
- static_cast<hardware::sensors::V1_0::OperationMode>(mode))));
+int32_t SensorDevice::registerDirectChannel(const sensors_direct_mem_t* memory) {
+ if (mSensors == nullptr) return NO_INIT;
+ Mutex::Autolock _l(mLock);
+
+ SharedMemType type;
+ switch (memory->type) {
+ case SENSOR_DIRECT_MEM_TYPE_ASHMEM:
+ type = SharedMemType::ASHMEM;
+ break;
+ case SENSOR_DIRECT_MEM_TYPE_GRALLOC:
+ type = SharedMemType::GRALLOC;
+ break;
+ default:
+ return BAD_VALUE;
+ }
+
+ SharedMemFormat format;
+ if (memory->format != SENSOR_DIRECT_FMT_SENSORS_EVENT) {
+ return BAD_VALUE;
+ }
+ format = SharedMemFormat::SENSORS_EVENT;
+
+ SharedMemInfo mem = {
+ .type = type,
+ .format = format,
+ .size = static_cast<uint32_t>(memory->size),
+ .memoryHandle = memory->handle,
+ };
+
+ int32_t ret;
+ checkReturn(mSensors->registerDirectChannel(mem,
+ [&ret](auto result, auto channelHandle) {
+ if (result == Result::OK) {
+ ret = channelHandle;
+ } else {
+ ret = StatusFromResult(result);
+ }
+ }));
+ return ret;
+}
+
+void SensorDevice::unregisterDirectChannel(int32_t channelHandle) {
+ if (mSensors == nullptr) return;
+ Mutex::Autolock _l(mLock);
+ checkReturn(mSensors->unregisterDirectChannel(channelHandle));
+}
+
+int32_t SensorDevice::configureDirectChannel(int32_t sensorHandle,
+ int32_t channelHandle, const struct sensors_direct_cfg_t *config) {
+ if (mSensors == nullptr) return NO_INIT;
+ Mutex::Autolock _l(mLock);
+
+ RateLevel rate;
+ switch(config->rate_level) {
+ case SENSOR_DIRECT_RATE_STOP:
+ rate = RateLevel::STOP;
+ break;
+ case SENSOR_DIRECT_RATE_NORMAL:
+ rate = RateLevel::NORMAL;
+ break;
+ case SENSOR_DIRECT_RATE_FAST:
+ rate = RateLevel::FAST;
+ break;
+ case SENSOR_DIRECT_RATE_VERY_FAST:
+ rate = RateLevel::VERY_FAST;
+ break;
+ default:
+ return BAD_VALUE;
+ }
+
+ int32_t ret;
+ checkReturn(mSensors->configDirectReport(sensorHandle, channelHandle, rate,
+ [&ret, rate] (auto result, auto token) {
+ if (rate == RateLevel::STOP) {
+ ret = StatusFromResult(result);
+ } else {
+ if (result == Result::OK) {
+ ret = token;
+ } else {
+ ret = StatusFromResult(result);
+ }
+ }
+ }));
+
+ return ret;
}
// ---------------------------------------------------------------------------
@@ -555,90 +627,6 @@
mDisabledClients.remove(ident);
}
-int32_t SensorDevice::registerDirectChannel(const sensors_direct_mem_t* memory) {
- Mutex::Autolock _l(mLock);
-
- SharedMemType type;
- switch (memory->type) {
- case SENSOR_DIRECT_MEM_TYPE_ASHMEM:
- type = SharedMemType::ASHMEM;
- break;
- case SENSOR_DIRECT_MEM_TYPE_GRALLOC:
- type = SharedMemType::GRALLOC;
- break;
- default:
- return BAD_VALUE;
- }
-
- SharedMemFormat format;
- if (memory->format != SENSOR_DIRECT_FMT_SENSORS_EVENT) {
- return BAD_VALUE;
- }
- format = SharedMemFormat::SENSORS_EVENT;
-
- SharedMemInfo mem = {
- .type = type,
- .format = format,
- .size = static_cast<uint32_t>(memory->size),
- .memoryHandle = memory->handle,
- };
-
- int32_t ret;
- checkReturn(mSensors->registerDirectChannel(mem,
- [&ret](auto result, auto channelHandle) {
- if (result == Result::OK) {
- ret = channelHandle;
- } else {
- ret = StatusFromResult(result);
- }
- }));
- return ret;
-}
-
-void SensorDevice::unregisterDirectChannel(int32_t channelHandle) {
- Mutex::Autolock _l(mLock);
- checkReturn(mSensors->unregisterDirectChannel(channelHandle));
-}
-
-int32_t SensorDevice::configureDirectChannel(int32_t sensorHandle,
- int32_t channelHandle, const struct sensors_direct_cfg_t *config) {
- Mutex::Autolock _l(mLock);
-
- RateLevel rate;
- switch(config->rate_level) {
- case SENSOR_DIRECT_RATE_STOP:
- rate = RateLevel::STOP;
- break;
- case SENSOR_DIRECT_RATE_NORMAL:
- rate = RateLevel::NORMAL;
- break;
- case SENSOR_DIRECT_RATE_FAST:
- rate = RateLevel::FAST;
- break;
- case SENSOR_DIRECT_RATE_VERY_FAST:
- rate = RateLevel::VERY_FAST;
- break;
- default:
- return BAD_VALUE;
- }
-
- int32_t ret;
- checkReturn(mSensors->configDirectReport(sensorHandle, channelHandle, rate,
- [&ret, rate] (auto result, auto token) {
- if (rate == RateLevel::STOP) {
- ret = StatusFromResult(result);
- } else {
- if (result == Result::OK) {
- ret = token;
- } else {
- ret = StatusFromResult(result);
- }
- }
- }));
-
- return ret;
-}
-
bool SensorDevice::isDirectReportSupported() const {
return mIsDirectReportSupported;
}
diff --git a/services/sensorservice/SensorDevice.h b/services/sensorservice/SensorDevice.h
index 410531b..2520a81 100644
--- a/services/sensorservice/SensorDevice.h
+++ b/services/sensorservice/SensorDevice.h
@@ -161,6 +161,7 @@
// Use this vector to determine which client is activated or deactivated.
SortedVector<void *> mDisabledClients;
SensorDevice();
+ bool connectHidlService();
static void handleHidlDeath(const std::string &detail);
template<typename T>
diff --git a/services/sensorservice/hidl/SensorManager.cpp b/services/sensorservice/hidl/SensorManager.cpp
index b55efb0..37e53dc 100644
--- a/services/sensorservice/hidl/SensorManager.cpp
+++ b/services/sensorservice/hidl/SensorManager.cpp
@@ -30,7 +30,6 @@
namespace V1_0 {
namespace implementation {
-using ::android::frameworks::sensorservice::V1_0::IDirectReportChannel;
using ::android::hardware::sensors::V1_0::SensorInfo;
using ::android::hardware::hidl_vec;
using ::android::hardware::Void;
@@ -112,6 +111,13 @@
return Void();
}
+Return<void> SensorManager::createEventQueue(
+ __unused const sp<IEventQueueCallback> &callback, createEventQueue_cb _hidl_cb) {
+ // TODO(b/35219747) Implement this
+ _hidl_cb(nullptr, Result::UNKNOWN_ERROR);
+ return Void();
+}
+
} // namespace implementation
} // namespace V1_0
} // namespace sensorservice
diff --git a/services/sensorservice/hidl/include/sensorservicehidl/SensorManager.h b/services/sensorservice/hidl/include/sensorservicehidl/SensorManager.h
index 484e624..0b026c9 100644
--- a/services/sensorservice/hidl/include/sensorservicehidl/SensorManager.h
+++ b/services/sensorservice/hidl/include/sensorservicehidl/SensorManager.h
@@ -43,7 +43,7 @@
Return<void> getDefaultSensor(SensorType type, getDefaultSensor_cb _hidl_cb) override;
Return<void> createAshmemDirectChannel(const hidl_memory& mem, uint64_t size, createAshmemDirectChannel_cb _hidl_cb) override;
Return<void> createGrallocDirectChannel(const hidl_handle& buffer, uint64_t size, createGrallocDirectChannel_cb _hidl_cb) override;
-
+ Return<void> createEventQueue(const sp<IEventQueueCallback> &callback, createEventQueue_cb _hidl_cb);
private:
::android::SensorManager& mManager;
diff --git a/services/surfaceflinger/Client.cpp b/services/surfaceflinger/Client.cpp
index 9ddae2b..e9a2513 100644
--- a/services/surfaceflinger/Client.cpp
+++ b/services/surfaceflinger/Client.cpp
@@ -210,15 +210,5 @@
return NO_ERROR;
}
-status_t Client::getTransformToDisplayInverse(const sp<IBinder>& handle,
- bool* outTransformToDisplayInverse) const {
- sp<Layer> layer = getLayerUser(handle);
- if (layer == NULL) {
- return NAME_NOT_FOUND;
- }
- *outTransformToDisplayInverse = layer->getTransformToDisplayInverse();
- return NO_ERROR;
-}
-
// ---------------------------------------------------------------------------
}; // namespace android
diff --git a/services/surfaceflinger/Client.h b/services/surfaceflinger/Client.h
index 141f6c7..b5f98b8 100644
--- a/services/surfaceflinger/Client.h
+++ b/services/surfaceflinger/Client.h
@@ -67,8 +67,6 @@
virtual status_t clearLayerFrameStats(const sp<IBinder>& handle) const;
virtual status_t getLayerFrameStats(const sp<IBinder>& handle, FrameStats* outStats) const;
- virtual status_t getTransformToDisplayInverse(
- const sp<IBinder>& handle, bool* outTransformToDisplayInverse) const;
virtual status_t onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags);
diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
index c6e6dcb..d9bddb5 100644
--- a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
+++ b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
@@ -129,7 +129,7 @@
mIsUsingVrComposer(useVrComposer)
{
if (mIsUsingVrComposer) {
- mComposer = IComposer::getService("vr_hwcomposer");
+ mComposer = IComposer::getService("vr");
} else {
mComposer = IComposer::getService(); // use default name
}
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
old mode 100644
new mode 100755
index ac7e083..73858fa
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -505,7 +505,7 @@
// which means using the inverse of the current transform set on the
// SurfaceFlingerConsumer.
uint32_t invTransform = mCurrentTransform;
- if (mSurfaceFlingerConsumer->getTransformToDisplayInverse()) {
+ if (getTransformToDisplayInverse()) {
/*
* the code below applies the primary display's inverse transform to the
* buffer
@@ -713,7 +713,7 @@
const Transform bufferOrientation(mCurrentTransform);
Transform transform(tr * t * bufferOrientation);
- if (mSurfaceFlingerConsumer->getTransformToDisplayInverse()) {
+ if (getTransformToDisplayInverse()) {
/*
* the code below applies the primary display's inverse transform to the
* buffer
@@ -725,8 +725,14 @@
invTransform ^= NATIVE_WINDOW_TRANSFORM_FLIP_V |
NATIVE_WINDOW_TRANSFORM_FLIP_H;
}
- // and apply to the current transform
- transform = Transform(invTransform) * transform;
+
+ /*
+ * Here we cancel out the orientation component of the WM transform.
+ * The scaling and translate components are already included in our bounds
+ * computation so it's enough to just omit it in the composition.
+ * See comment in onDraw with ref to b/36727915 for why.
+ */
+ transform = Transform(invTransform) * tr * bufferOrientation;
}
// this gives us only the "orientation" component of the transform
@@ -987,6 +993,24 @@
onDraw(hw, Region(hw->bounds()), false);
}
+static constexpr mat4 inverseOrientation(uint32_t transform) {
+ const mat4 flipH(-1,0,0,0, 0,1,0,0, 0,0,1,0, 1,0,0,1);
+ const mat4 flipV( 1,0,0,0, 0,-1,0,0, 0,0,1,0, 0,1,0,1);
+ const mat4 rot90( 0,1,0,0, -1,0,0,0, 0,0,1,0, 1,0,0,1);
+ mat4 tr;
+
+ if (transform & NATIVE_WINDOW_TRANSFORM_ROT_90) {
+ tr = tr * rot90;
+ }
+ if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_H) {
+ tr = tr * flipH;
+ }
+ if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_V) {
+ tr = tr * flipV;
+ }
+ return inverse(tr);
+}
+
void Layer::onDraw(const sp<const DisplayDevice>& hw, const Region& clip,
bool useIdentityTransform) const
{
@@ -1041,30 +1065,29 @@
mSurfaceFlingerConsumer->setFilteringEnabled(useFiltering);
mSurfaceFlingerConsumer->getTransformMatrix(textureMatrix);
- if (mSurfaceFlingerConsumer->getTransformToDisplayInverse()) {
+ if (getTransformToDisplayInverse()) {
/*
* the code below applies the primary display's inverse transform to
* the texture transform
*/
-
- // create a 4x4 transform matrix from the display transform flags
- const mat4 flipH(-1,0,0,0, 0,1,0,0, 0,0,1,0, 1,0,0,1);
- const mat4 flipV( 1,0,0,0, 0,-1,0,0, 0,0,1,0, 0,1,0,1);
- const mat4 rot90( 0,1,0,0, -1,0,0,0, 0,0,1,0, 1,0,0,1);
-
- mat4 tr;
uint32_t transform =
DisplayDevice::getPrimaryDisplayOrientationTransform();
- if (transform & NATIVE_WINDOW_TRANSFORM_ROT_90)
- tr = tr * rot90;
- if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_H)
- tr = tr * flipH;
- if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_V)
- tr = tr * flipV;
+ mat4 tr = inverseOrientation(transform);
- // calculate the inverse
- tr = inverse(tr);
+ /**
+ * TODO(b/36727915): This is basically a hack.
+ *
+ * Ensure that regardless of the parent transformation,
+ * this buffer is always transformed from native display
+ * orientation to display orientation. For example, in the case
+ * of a camera where the buffer remains in native orientation,
+ * we want the pixels to always be upright.
+ */
+ if (getParent() != nullptr) {
+ const auto parentTransform = getParent()->getTransform();
+ tr = tr * inverseOrientation(parentTransform.getOrientation());
+ }
// and finally apply it to the original texture matrix
const mat4 texTransform(mat4(static_cast<const float*>(textureMatrix)) * tr);
@@ -1365,9 +1388,9 @@
bool Layer::isOpaque(const Layer::State& s) const
{
- // if we don't have a buffer yet, we're translucent regardless of the
+ // if we don't have a buffer or sidebandStream yet, we're translucent regardless of the
// layer's opaque flag.
- if (mActiveBuffer == 0) {
+ if ((mSidebandStream == nullptr) && (mActiveBuffer == nullptr)) {
return false;
}
diff --git a/services/surfaceflinger/RenderEngine/RenderEngine.cpp b/services/surfaceflinger/RenderEngine/RenderEngine.cpp
index e3dbecc..7564269 100644
--- a/services/surfaceflinger/RenderEngine/RenderEngine.cpp
+++ b/services/surfaceflinger/RenderEngine/RenderEngine.cpp
@@ -382,6 +382,7 @@
attribs[EGL_RED_SIZE] = 8;
attribs[EGL_GREEN_SIZE] = 8;
attribs[EGL_BLUE_SIZE] = 8;
+ attribs[EGL_ALPHA_SIZE] = 8;
wantedAttribute = EGL_NONE;
wantedAttributeValue = EGL_NONE;
} else {
diff --git a/services/surfaceflinger/tests/Android.mk b/services/surfaceflinger/tests/Android.mk
index 16041da..43e22a0 100644
--- a/services/surfaceflinger/tests/Android.mk
+++ b/services/surfaceflinger/tests/Android.mk
@@ -4,7 +4,7 @@
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
LOCAL_MODULE := SurfaceFlinger_test
-
+LOCAL_COMPATIBILITY_SUITE := device-tests
LOCAL_MODULE_TAGS := tests
LOCAL_SRC_FILES := \
diff --git a/services/surfaceflinger/tests/AndroidTest.xml b/services/surfaceflinger/tests/AndroidTest.xml
new file mode 100644
index 0000000..8315037
--- /dev/null
+++ b/services/surfaceflinger/tests/AndroidTest.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration description="Config for SurfaceFlinger_test">
+ <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+ <option name="cleanup" value="true" />
+ <option name="push" value="SurfaceFlinger_test->/data/local/tmp/SurfaceFlinger_test" />
+ </target_preparer>
+ <option name="test-suite-tag" value="apct" />
+ <test class="com.android.tradefed.testtype.GTest" >
+ <option name="native-test-device-path" value="/data/local/tmp" />
+ <option name="module-name" value="SurfaceFlinger_test" />
+ </test>
+</configuration>
diff --git a/services/surfaceflinger/tests/vsync/Android.mk b/services/surfaceflinger/tests/vsync/Android.mk
index 9181760..8e41617 100644
--- a/services/surfaceflinger/tests/vsync/Android.mk
+++ b/services/surfaceflinger/tests/vsync/Android.mk
@@ -15,4 +15,6 @@
LOCAL_MODULE_TAGS := tests
+LOCAL_CFLAGS := -Werror
+
include $(BUILD_EXECUTABLE)
diff --git a/services/surfaceflinger/tests/vsync/vsync.cpp b/services/surfaceflinger/tests/vsync/vsync.cpp
index aa72c79..a1b45e6 100644
--- a/services/surfaceflinger/tests/vsync/vsync.cpp
+++ b/services/surfaceflinger/tests/vsync/vsync.cpp
@@ -20,7 +20,7 @@
using namespace android;
-int receiver(int fd, int events, void* data)
+int receiver(int /*fd*/, int /*events*/, void* data)
{
DisplayEventReceiver* q = (DisplayEventReceiver*)data;
@@ -47,7 +47,7 @@
return 1;
}
-int main(int argc, char** argv)
+int main(int /*argc*/, char** /*argv*/)
{
DisplayEventReceiver myDisplayEvent;
diff --git a/services/surfaceflinger/tests/waitforvsync/Android.mk b/services/surfaceflinger/tests/waitforvsync/Android.mk
index c25f5ab..932d2be 100644
--- a/services/surfaceflinger/tests/waitforvsync/Android.mk
+++ b/services/surfaceflinger/tests/waitforvsync/Android.mk
@@ -11,4 +11,6 @@
LOCAL_MODULE_TAGS := tests
+LOCAL_CFLAGS := -Werror
+
include $(BUILD_EXECUTABLE)
diff --git a/services/surfaceflinger/tests/waitforvsync/waitforvsync.cpp b/services/surfaceflinger/tests/waitforvsync/waitforvsync.cpp
index b88b04a..65eaae5 100644
--- a/services/surfaceflinger/tests/waitforvsync/waitforvsync.cpp
+++ b/services/surfaceflinger/tests/waitforvsync/waitforvsync.cpp
@@ -29,7 +29,7 @@
#define FBIO_WAITFORVSYNC _IOW('F', 0x20, __u32)
#endif
-int main(int argc, char** argv) {
+int main(int /*argc*/, char** /*argv*/) {
int fd = open("/dev/graphics/fb0", O_RDWR);
if (fd >= 0) {
do {
diff --git a/services/vr/bufferhubd/Android.mk b/services/vr/bufferhubd/Android.mk
index c1a0b6f..b3d777e 100644
--- a/services/vr/bufferhubd/Android.mk
+++ b/services/vr/bufferhubd/Android.mk
@@ -30,7 +30,6 @@
sharedLibraries := \
libbase \
libcutils \
- libhardware \
liblog \
libsync \
libutils \
diff --git a/services/vr/hardware_composer/Android.bp b/services/vr/hardware_composer/Android.bp
index 1601c7f..629d65b 100644
--- a/services/vr/hardware_composer/Android.bp
+++ b/services/vr/hardware_composer/Android.bp
@@ -75,31 +75,6 @@
],
}
-cc_library_static {
- name: "libdvr_hwc",
- srcs: [
- "dvr_hardware_composer_client.cpp",
- ],
- static_libs: [
- "libvr_hwc-impl",
- // NOTE: This needs to be included after the *-impl lib otherwise the
- // symbols in the *-binder library get optimized out.
- "libvr_hwc-binder",
- ],
- shared_libs: [
- "libbase",
- "libbinder",
- "liblog",
- "libnativewindow",
- "libui",
- "libutils",
- ],
- export_include_dirs: ["private"],
- export_shared_lib_headers: [
- "libnativewindow",
- ],
-}
-
cc_test {
name: "vr_hwc_test",
gtest: true,
diff --git a/services/vr/hardware_composer/aidl/android/dvr/parcelable_composer_frame.cpp b/services/vr/hardware_composer/aidl/android/dvr/parcelable_composer_frame.cpp
index cb3e49d..45eabca 100644
--- a/services/vr/hardware_composer/aidl/android/dvr/parcelable_composer_frame.cpp
+++ b/services/vr/hardware_composer/aidl/android/dvr/parcelable_composer_frame.cpp
@@ -19,6 +19,12 @@
status_t ret = parcel->writeUint64(frame_.display_id);
if (ret != OK) return ret;
+ ret = parcel->writeInt32(frame_.display_width);
+ if (ret != OK) return ret;
+
+ ret = parcel->writeInt32(frame_.display_height);
+ if (ret != OK) return ret;
+
ret = parcel->writeBool(frame_.removed);
if (ret != OK) return ret;
@@ -35,6 +41,12 @@
status_t ret = parcel->readUint64(&frame_.display_id);
if (ret != OK) return ret;
+ ret = parcel->readInt32(&frame_.display_width);
+ if (ret != OK) return ret;
+
+ ret = parcel->readInt32(&frame_.display_height);
+ if (ret != OK) return ret;
+
ret = parcel->readBool(&frame_.removed);
if (ret != OK) return ret;
diff --git a/services/vr/hardware_composer/tests/vr_composer_test.cpp b/services/vr/hardware_composer/tests/vr_composer_test.cpp
index cfc2708..d082f4b 100644
--- a/services/vr/hardware_composer/tests/vr_composer_test.cpp
+++ b/services/vr/hardware_composer/tests/vr_composer_test.cpp
@@ -104,6 +104,8 @@
ComposerView::Frame frame;
frame.display_id = 1;
frame.removed = false;
+ frame.display_width = 600;
+ frame.display_height = 400;
frame.layers.push_back(ComposerView::ComposerLayer{
.id = 1,
.buffer = CreateBuffer(),
@@ -120,6 +122,8 @@
ComposerView::Frame received_frame = callback->last_frame();
ASSERT_EQ(frame.display_id, received_frame.display_id);
+ ASSERT_EQ(frame.display_width, received_frame.display_width);
+ ASSERT_EQ(frame.display_height, received_frame.display_height);
ASSERT_EQ(frame.removed, received_frame.removed);
ASSERT_EQ(1u, received_frame.layers.size());
ASSERT_EQ(frame.layers[0].id, received_frame.layers[0].id);
diff --git a/services/vr/hardware_composer/vr_hardware_composer_service.cpp b/services/vr/hardware_composer/vr_hardware_composer_service.cpp
index 9591748..f980220 100644
--- a/services/vr/hardware_composer/vr_hardware_composer_service.cpp
+++ b/services/vr/hardware_composer/vr_hardware_composer_service.cpp
@@ -26,7 +26,7 @@
// Register the hwbinder HWC HAL service used by SurfaceFlinger while in VR
// mode.
- const char instance[] = "vr_hwcomposer";
+ const char instance[] = "vr";
android::sp<IComposer> service =
android::dvr::HIDL_FETCH_IComposer(instance);
diff --git a/services/vr/sensord/pose_service.cpp b/services/vr/sensord/pose_service.cpp
index 32a2160..c1aad19 100644
--- a/services/vr/sensord/pose_service.cpp
+++ b/services/vr/sensord/pose_service.cpp
@@ -48,7 +48,7 @@
static constexpr float kDefaultNeckVerticalOffset = 0.075f; // meters
static constexpr char kDisablePosePredictionProp[] =
- "persist.dreamos.disable_predict";
+ "persist.dvr.disable_predict";
// Device type property for controlling classes of behavior that differ
// between devices. If unset, defaults to kOrientationTypeSmartphone.
@@ -91,6 +91,10 @@
return "DVR_POSE_MODE_MOCK_ROTATE_FAST";
case DVR_POSE_MODE_MOCK_CIRCLE_STRAFE:
return "DVR_POSE_MODE_MOCK_CIRCLE_STRAFE";
+ case DVR_POSE_MODE_FLOAT:
+ return "DVR_POSE_MODE_FLOAT";
+ case DVR_POSE_MODE_MOCK_MOTION_SICKNESS:
+ return "DVR_POSE_MODE_MOCK_MOTION_SICKNESS";
default:
return "Unknown pose mode";
}
@@ -179,7 +183,7 @@
KickSensorWatchDogThread();
}
- // Read the persistent dreamos flags before using them in SetPoseMode.
+ // Read the persistent dvr flags before using them in SetPoseMode.
enable_pose_prediction_ =
property_get_bool(kDisablePosePredictionProp, 0) == 0;
@@ -418,7 +422,8 @@
current_time_ns);
break;
}
- case DVR_POSE_MODE_3DOF: {
+ case DVR_POSE_MODE_3DOF:
+ case DVR_POSE_MODE_FLOAT: {
// Sensor fusion provides IMU-space data, transform to world space.
// Constants to perform IMU orientation adjustments. Note that these
@@ -435,6 +440,15 @@
kRotX90 * Rotationd(AngleAxisd(-k90DegInRad, kVecAxisY));
start_from_head_rotation =
(pose_state.sensor_from_start_rotation * kPostRotation).inverse();
+ } else if (device_orientation_type_ == kOrientationTypeLandscape180) {
+ const Rotationd kPreRotation =
+ Rotationd(AngleAxisd(k90DegInRad * 2.0, kVecAxisY)) *
+ Rotationd(AngleAxisd(k90DegInRad * 2.0, kVecAxisZ));
+ const Rotationd kPostRotation = kRotX90;
+ start_from_head_rotation =
+ (kPreRotation *
+ pose_state.sensor_from_start_rotation * kPostRotation)
+ .inverse();
} else {
const Rotationd kPreRotation =
Rotationd(AngleAxisd(k90DegInRad, kVecAxisZ));
@@ -446,13 +460,25 @@
}
start_from_head_rotation.normalize();
- // Neck / head model code procedure for when no 6dof is available.
- // To apply the neck model, first translate the head pose to the new
- // center of eyes, then rotate around the origin (the original head
- // pos).
- Vector3d position =
- start_from_head_rotation * Vector3d(0.0, kDefaultNeckVerticalOffset,
- -kDefaultNeckHorizontalOffset);
+ Vector3d position;
+ switch (pose_mode_) {
+ default:
+ case DVR_POSE_MODE_3DOF:
+ // Neck / head model code procedure for when no 6dof is available.
+ // To apply the neck model, first translate the head pose to the new
+ // center of eyes, then rotate around the origin (the original head
+ // pos).
+ position = start_from_head_rotation *
+ Vector3d(0.0, kDefaultNeckVerticalOffset,
+ -kDefaultNeckHorizontalOffset);
+ break;
+ case DVR_POSE_MODE_FLOAT:
+ // Change position a bit in facing direction.
+ mock_pos_offset_ += start_from_head_rotation.toRotationMatrix() * Vector3d(0, 0, -0.01);
+ ResetMockDeviatedPosition();
+ position = mock_pos_offset_;
+ break;
+ }
// IMU driver gives timestamps on its own clock, but we need monotonic
// clock. Subtract 5ms to account for estimated IMU sample latency.
@@ -460,6 +486,26 @@
pose_state.timestamp_ns + 5000000);
break;
}
+ case DVR_POSE_MODE_MOCK_MOTION_SICKNESS: {
+ double phase = std::sin(current_time_ns / 1e9) + 1;
+ // Randomize 3rd order rotation axis on phase minimum.
+ if (phase > mock_prev_phase_ && mock_diff_phase_ < 0)
+ mock_rot_axis_2_ = RandVector();
+ mock_diff_phase_ = phase - mock_prev_phase_;
+ mock_prev_phase_ = phase;
+
+ // Rotate axes all the way down.
+ mock_rot_axis_2_ = AngleAxisd(0.004 * phase, mock_rot_axis_3_) * mock_rot_axis_2_;
+ mock_rot_axis_1_ = AngleAxisd(0.002 * (std::sin(current_time_ns / 5e8 + M_PI / 2) + 1), mock_rot_axis_2_) * mock_rot_axis_1_;
+ Rotationd rotation = Rotationd(AngleAxisd(fmod(current_time_ns / 2e9, kTwoPi), mock_rot_axis_1_));
+
+ // Change position a bit.
+ mock_pos_offset_ += rotation.toRotationMatrix() * Vector3d(0, 0, 0.003 * (std::sin(current_time_ns / 6e8) + 1));
+ ResetMockDeviatedPosition();
+
+ WriteAsyncPoses(mock_pos_offset_, rotation, current_time_ns);
+ break;
+ }
default:
case DVR_POSE_MODE_6DOF:
ALOGE("ERROR: invalid pose mode");
@@ -467,6 +513,13 @@
}
}
+void PoseService::ResetMockDeviatedPosition() {
+ if (mock_pos_offset_[1] < -1) mock_pos_offset_[1] = 2;
+ if (mock_pos_offset_[1] > 30) mock_pos_offset_[1] = 2;
+ if (abs(mock_pos_offset_[0]) > 30) mock_pos_offset_[0] = mock_pos_offset_[2] = 0;
+ if (abs(mock_pos_offset_[2]) > 30) mock_pos_offset_[0] = mock_pos_offset_[2] = 0;
+}
+
int PoseService::HandleMessage(pdx::Message& msg) {
int ret = 0;
const pdx::MessageInfo& info = msg.GetInfo();
@@ -646,6 +699,10 @@
if (mode == DVR_POSE_MODE_6DOF) {
// Only 3DoF is currently supported.
mode = DVR_POSE_MODE_3DOF;
+ } else if (mode == DVR_POSE_MODE_MOCK_MOTION_SICKNESS) {
+ mock_rot_axis_1_ = RandVector();
+ mock_rot_axis_2_ = RandVector();
+ mock_rot_axis_3_ = RandVector();
}
pose_mode_ = mode;
diff --git a/services/vr/sensord/pose_service.h b/services/vr/sensord/pose_service.h
index 899d5fb..dbf0345 100644
--- a/services/vr/sensord/pose_service.h
+++ b/services/vr/sensord/pose_service.h
@@ -43,6 +43,8 @@
kOrientationTypePortrait = 1,
// Landscape device.
kOrientationTypeLandscape = 2,
+ // 180 Landscape device.
+ kOrientationTypeLandscape180 = 3,
};
// Initializes the service. Keeps a reference to sensor_thread, which must be
@@ -99,6 +101,25 @@
// Last known pose.
DvrPoseAsync last_known_pose_;
+ // Position offset for use in pose modes.
+ Eigen::Vector3d mock_pos_offset_;
+
+ // Phase data for DVR_POSE_MODE_MOCK_MOTION_SICKNESS.
+ double mock_prev_phase_, mock_diff_phase_;
+
+ // Axis data for DVR_POSE_MODE_MOCK_MOTION_SICKNESS.
+ Eigen::Vector3d mock_rot_axis_1_, mock_rot_axis_2_, mock_rot_axis_3_;
+
+ // Return a random normalized 3d vector.
+ static Eigen::Vector3d RandVector() {
+ Eigen::Vector3d vec = Eigen::Vector3d::Random();
+ vec.normalize();
+ return vec;
+ }
+
+ // Reset mock_pos_offset_ if strayed too far
+ void ResetMockDeviatedPosition();
+
// If this flag is true, the pose published includes a small prediction of
// where it'll be when it's consumed.
bool enable_pose_prediction_;
diff --git a/services/vr/vr_window_manager/aidl/android/service/vr/IVrWindowManager.aidl b/services/vr/vr_window_manager/aidl/android/service/vr/IVrWindowManager.aidl
index 67fd927..b16049f 100644
--- a/services/vr/vr_window_manager/aidl/android/service/vr/IVrWindowManager.aidl
+++ b/services/vr/vr_window_manager/aidl/android/service/vr/IVrWindowManager.aidl
@@ -25,5 +25,6 @@
void exitVrMode() = 3;
void setDebugMode(int mode) = 4;
void set2DMode(int mode) = 5;
+ void setRotation(int angle) = 6;
}
diff --git a/services/vr/vr_window_manager/application.cpp b/services/vr/vr_window_manager/application.cpp
index c7d7d50..b2f02e5 100644
--- a/services/vr/vr_window_manager/application.cpp
+++ b/services/vr/vr_window_manager/application.cpp
@@ -174,7 +174,12 @@
// TODO(steventhomas): If we're not visible, block until we are. For now we
// throttle by calling dvrGraphicsWaitNextFrame.
DvrFrameSchedule schedule;
- dvrGraphicsWaitNextFrame(graphics_context_, 0, &schedule);
+ int status = dvrGraphicsWaitNextFrame(graphics_context_, 0, &schedule);
+ if (status < 0) {
+ ALOGE("Context lost, deallocating graphics resources");
+ SetVisibility(false);
+ DeallocateResources();
+ }
OnDrawFrame();
diff --git a/services/vr/vr_window_manager/composer/impl/vr_hwc.cpp b/services/vr/vr_window_manager/composer/impl/vr_hwc.cpp
index 8aa2fd5..3393ade 100644
--- a/services/vr/vr_window_manager/composer/impl/vr_hwc.cpp
+++ b/services/vr/vr_window_manager/composer/impl/vr_hwc.cpp
@@ -81,9 +81,35 @@
return buffer;
}
+void GetPrimaryDisplaySize(int32_t* width, int32_t* height) {
+ *width = 1080;
+ *height = 1920;
+
+ int error = 0;
+ auto display_client = DisplayClient::Create(&error);
+ SystemDisplayMetrics metrics;
+
+ if (error) {
+ ALOGE("Could not connect to display service : %s(%d)", strerror(error),
+ error);
+ return;
+ }
+
+ error = display_client->GetDisplayMetrics(&metrics);
+ if (error) {
+ ALOGE("Could not get display metrics from display service : %s(%d)",
+ strerror(error), error);
+ return;
+ }
+
+ *width = metrics.display_native_width;
+ *height = metrics.display_native_height;
+}
+
} // namespace
-HwcDisplay::HwcDisplay() {}
+HwcDisplay::HwcDisplay(int32_t width, int32_t height)
+ : width_(width), height_(height) {}
HwcDisplay::~HwcDisplay() {}
@@ -222,7 +248,7 @@
////////////////////////////////////////////////////////////////////////////////
// VrHwcClient
-VrHwc::VrHwc() { displays_[kDefaultDisplayId].reset(new HwcDisplay()); }
+VrHwc::VrHwc() {}
VrHwc::~VrHwc() {}
@@ -235,6 +261,14 @@
void VrHwc::enableCallback(bool enable) {
if (enable && client_ != nullptr) {
+ {
+ int32_t width, height;
+ GetPrimaryDisplaySize(&width, &height);
+ std::lock_guard<std::mutex> guard(mutex_);
+ // Create the primary display late to avoid initialization issues between
+ // VR HWC and SurfaceFlinger.
+ displays_[kDefaultDisplayId].reset(new HwcDisplay(width, height));
+ }
client_.promote()->onHotplug(kDefaultDisplayId,
IComposerCallback::Connection::CONNECTED);
}
@@ -246,7 +280,7 @@
PixelFormat* format, Display* outDisplay) {
*format = PixelFormat::RGBA_8888;
*outDisplay = display_count_;
- displays_[display_count_].reset(new HwcDisplay());
+ displays_[display_count_].reset(new HwcDisplay(width, height));
display_count_++;
return Error::NONE;
}
@@ -308,41 +342,20 @@
IComposerClient::Attribute attribute,
int32_t* outValue) {
std::lock_guard<std::mutex> guard(mutex_);
- if (!FindDisplay(display))
+ auto display_ptr = FindDisplay(display);
+ if (!display_ptr) {
return Error::BAD_DISPLAY;
+ }
if (config != kDefaultConfigId) {
return Error::BAD_CONFIG;
}
- int error = 0;
- auto display_client = DisplayClient::Create(&error);
- SystemDisplayMetrics metrics;
-
- if (error) {
- ALOGE("Could not connect to display service : %s(%d)", strerror(error),
- error);
- } else {
- error = display_client->GetDisplayMetrics(&metrics);
-
- if (error) {
- ALOGE("Could not get display metrics from display service : %s(%d)",
- strerror(error), error);
- }
- }
-
- if (error) {
- metrics.display_native_width = 1080;
- metrics.display_native_height = 1920;
- ALOGI("Setting display metrics to default : width=%d height=%d",
- metrics.display_native_width, metrics.display_native_height);
- }
-
switch (attribute) {
case IComposerClient::Attribute::WIDTH:
- *outValue = metrics.display_native_width;
+ *outValue = display_ptr->width();
break;
case IComposerClient::Attribute::HEIGHT:
- *outValue = metrics.display_native_height;
+ *outValue = display_ptr->height();
break;
case IComposerClient::Attribute::VSYNC_PERIOD:
*outValue = 1000 * 1000 * 1000 / 30; // 30fps
@@ -510,6 +523,8 @@
std::vector<Layer> last_frame_layers;
Error status = display_ptr->GetFrame(&frame.layers);
frame.display_id = display;
+ frame.display_width = display_ptr->width();
+ frame.display_height = display_ptr->height();
if (status != Error::NONE)
return status;
diff --git a/services/vr/vr_window_manager/composer/impl/vr_hwc.h b/services/vr/vr_window_manager/composer/impl/vr_hwc.h
index 3c76120..bfca9a6 100644
--- a/services/vr/vr_window_manager/composer/impl/vr_hwc.h
+++ b/services/vr/vr_window_manager/composer/impl/vr_hwc.h
@@ -74,6 +74,8 @@
// being removed, or left false in the case of a normal frame. The upper
// layer tracks display IDs and will handle new ones showing up.
bool removed = false;
+ int32_t display_width;
+ int32_t display_height;
std::vector<ComposerLayer> layers;
};
@@ -107,9 +109,12 @@
class HwcDisplay {
public:
- HwcDisplay();
+ HwcDisplay(int32_t width, int32_t height);
~HwcDisplay();
+ int32_t width() const { return width_; }
+ int32_t height() const { return height_; }
+
HwcLayer* CreateLayer();
bool DestroyLayer(Layer id);
HwcLayer* GetLayer(Layer id);
@@ -138,6 +143,9 @@
// Layer ID generator.
uint64_t layer_ids_ = 1;
+ int32_t width_;
+ int32_t height_;
+
HwcDisplay(const HwcDisplay&) = delete;
void operator=(const HwcDisplay&) = delete;
};
diff --git a/services/vr/vr_window_manager/display_view.cpp b/services/vr/vr_window_manager/display_view.cpp
index e88e7d0..52984b7 100644
--- a/services/vr/vr_window_manager/display_view.cpp
+++ b/services/vr/vr_window_manager/display_view.cpp
@@ -146,16 +146,18 @@
DisplayView::DisplayView(uint32_t id, int touchpad_id)
: id_(id), touchpad_id_(touchpad_id) {
- translate_ = Eigen::Translation3f(0, 0, -2.5f);
+ translate_ = Eigen::Translation3f(0, 0, -5.0f);
ime_translate_ = mat4(Eigen::Translation3f(0.0f, -0.5f, 0.25f));
ime_top_left_ = vec2(0, 0);
ime_size_ = vec2(0, 0);
+ rotation_ = mat4::Identity();
}
DisplayView::~DisplayView() {}
void DisplayView::Recenter(const mat4& initial) {
- initial_head_matrix_ = initial;
+ initial_head_matrix_ =
+ initial * Eigen::AngleAxisf(M_PI * 0.5f, vec3::UnitZ());
}
void DisplayView::SetPrograms(ShaderProgram* program,
@@ -166,8 +168,7 @@
void DisplayView::DrawEye(EyeType /* eye */, const mat4& perspective,
const mat4& eye_matrix, const mat4& head_matrix,
- const vec2& size, float fade_value) {
- size_ = size;
+ float fade_value) {
scale_ = GetScalingMatrix(size_.x(), size_.y());
DrawOverlays(perspective, eye_matrix, head_matrix, fade_value);
@@ -202,6 +203,7 @@
base::unique_fd DisplayView::OnFrame(std::unique_ptr<HwcCallback::Frame> frame,
bool debug_mode, bool is_vr_active,
bool* showing) {
+ size_ = vec2(frame->display_width(), frame->display_height());
uint32_t app = current_vr_app_;
ViewMode visibility = CalculateVisibilityFromLayerConfig(*frame.get(), &app);
@@ -248,7 +250,7 @@
bool DisplayView::IsHit(const vec3& view_location, const vec3& view_direction,
vec3* hit_location, vec2* hit_location_in_window_coord,
bool test_ime) {
- mat4 m = initial_head_matrix_ * translate_;
+ mat4 m = GetStandardTransform();
if (test_ime)
m = m * ime_translate_;
mat4 inverse = (m * scale_).inverse();
@@ -314,8 +316,7 @@
mat4 layer_transform =
GetLayerTransform(texture_layer, size_.x(), size_.y());
- mat4 transform =
- initial_head_matrix_ * translate_ * scale_ * layer_transform;
+ mat4 transform = GetStandardTransform() * scale_ * layer_transform;
DrawWithTransform(transform, *program_);
glDisable(GL_BLEND);
@@ -351,14 +352,21 @@
}
}
+mat4 DisplayView::GetStandardTransform() {
+ mat4 m = initial_head_matrix_ * rotation_ * translate_;
+ if (current_frame_.visibility == ViewMode::App)
+ m *= Eigen::AngleAxisf(M_PI * -0.5f, vec3::UnitZ());
+ return m;
+}
+
void DisplayView::DrawIme() {
program_->Use();
glBindTexture(GL_TEXTURE_2D, ime_texture_.texture->id());
mat4 layer_transform = GetLayerTransform(ime_texture_, size_.x(), size_.y());
- mat4 transform = initial_head_matrix_ * translate_ * ime_translate_ * scale_ *
- layer_transform;
+ mat4 transform =
+ GetStandardTransform() * ime_translate_ * scale_ * layer_transform;
DrawWithTransform(transform, *program_);
}
@@ -377,7 +385,7 @@
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
mat4 layer_transform = GetLayerTransform(layer, size_.x(), size_.y());
- mat4 transform = initial_head_matrix_ * translate_ * scale_ * layer_transform;
+ mat4 transform = GetStandardTransform() * scale_ * layer_transform;
DrawWithTransform(transform, *overlay_program_);
glDisable(GL_BLEND);
}
diff --git a/services/vr/vr_window_manager/display_view.h b/services/vr/vr_window_manager/display_view.h
index 0d1355e..ad624c6 100644
--- a/services/vr/vr_window_manager/display_view.h
+++ b/services/vr/vr_window_manager/display_view.h
@@ -29,7 +29,7 @@
void OnDrawFrame(SurfaceFlingerView* surface_flinger_view, bool debug_mode);
void DrawEye(EyeType eye, const mat4& perspective, const mat4& eye_matrix,
- const mat4& head_matrix, const vec2& size, float fade_value);
+ const mat4& head_matrix, float fade_value);
void Recenter(const mat4& initial);
@@ -43,10 +43,13 @@
const vec2& hit_location() const { return hit_location_in_window_coord_; }
uint32_t id() const { return id_; }
int touchpad_id() const { return touchpad_id_; }
+ vec2 size() const { return size_; }
void set_2dmode(bool mode) { use_2dmode_ = mode; }
void set_always_2d(bool mode) { always_2d_ = mode; }
+ void set_rotation(const mat4& rotation) { rotation_ = rotation; }
+
private:
bool IsHit(const vec3& view_location, const vec3& view_direction,
vec3* hit_location, vec2* hit_location_in_window_coord,
@@ -60,6 +63,9 @@
const vec2& top_left, const vec2& bottom_right);
void DrawWithTransform(const mat4& transform, const ShaderProgram& program);
+ // This is the rotated, translated but unscaled transform to apply everywhere.
+ mat4 GetStandardTransform();
+
uint32_t id_;
int touchpad_id_;
@@ -72,6 +78,7 @@
mat4 scale_;
mat4 translate_;
mat4 ime_translate_;
+ mat4 rotation_;
vec2 size_;
std::vector<TextureLayer> textures_;
diff --git a/services/vr/vr_window_manager/hwc_callback.cpp b/services/vr/vr_window_manager/hwc_callback.cpp
index 2d2a85c..19b220b 100644
--- a/services/vr/vr_window_manager/hwc_callback.cpp
+++ b/services/vr/vr_window_manager/hwc_callback.cpp
@@ -56,12 +56,18 @@
}
return client_->OnFrame(std::make_unique<Frame>(
- std::move(hwc_frame), display_frame.display_id, display_frame.removed));
+ std::move(hwc_frame), display_frame.display_id, display_frame.removed,
+ display_frame.display_width, display_frame.display_height));
}
HwcCallback::Frame::Frame(std::vector<HwcLayer>&& layers, uint32_t display_id,
- bool removed)
- : display_id_(display_id), removed_(removed), layers_(std::move(layers)) {}
+ bool removed, int32_t display_width,
+ int32_t display_height)
+ : display_id_(display_id),
+ removed_(removed),
+ display_width_(display_width),
+ display_height_(display_height),
+ layers_(std::move(layers)) {}
HwcCallback::FrameStatus HwcCallback::Frame::Finish() {
if (status_ == FrameStatus::kUnfinished)
diff --git a/services/vr/vr_window_manager/hwc_callback.h b/services/vr/vr_window_manager/hwc_callback.h
index b8aa51b..c0d965a 100644
--- a/services/vr/vr_window_manager/hwc_callback.h
+++ b/services/vr/vr_window_manager/hwc_callback.h
@@ -81,16 +81,21 @@
class Frame {
public:
- Frame(std::vector<HwcLayer>&& layers, uint32_t display_id, bool removed);
+ Frame(std::vector<HwcLayer>&& layers, uint32_t display_id, bool removed,
+ int32_t display_width, int32_t display_height);
FrameStatus Finish();
const std::vector<HwcLayer>& layers() const { return layers_; }
uint32_t display_id() const { return display_id_; }
bool removed() const { return removed_; }
+ int32_t display_width() const { return display_width_; }
+ int32_t display_height() const { return display_height_; }
private:
uint32_t display_id_;
bool removed_;
+ int32_t display_width_;
+ int32_t display_height_;
std::vector<HwcLayer> layers_;
FrameStatus status_ = FrameStatus::kUnfinished;
};
diff --git a/services/vr/vr_window_manager/shell_view.cpp b/services/vr/vr_window_manager/shell_view.cpp
index 67ef5d4..850f604 100644
--- a/services/vr/vr_window_manager/shell_view.cpp
+++ b/services/vr/vr_window_manager/shell_view.cpp
@@ -126,10 +126,6 @@
if (!surface_flinger_view_->Initialize(this))
return 1;
- // This is a temporary fix for now. These APIs will be changed when everything
- // is moved into vrcore.
- display_client_ = DisplayClient::Create();
-
return 0;
}
@@ -164,7 +160,14 @@
}
void ShellView::DeallocateResources() {
- surface_flinger_view_.reset();
+ {
+ std::unique_lock<std::mutex> l(display_frame_mutex_);
+ removed_displays_.clear();
+ new_displays_.clear();
+ displays_.clear();
+ }
+
+ display_client_.reset();
reticle_.reset();
controller_mesh_.reset();
program_.reset(new ShaderProgram);
@@ -191,8 +194,11 @@
result.append("[displays]\n");
result.appendFormat("count = %zu\n", displays_.size());
- for (size_t i = 0; i < displays_.size(); ++i)
- result.appendFormat(" display_id = %" PRId32 "\n", displays_[i]->id());
+ for (size_t i = 0; i < displays_.size(); ++i) {
+ result.appendFormat(" display_id = %" PRId32 "\n", displays_[i]->id());
+ result.appendFormat(" size=%fx%f\n",
+ displays_[i]->size().x(), displays_[i]->size().y());
+ }
result.append("\n");
}
@@ -202,6 +208,12 @@
displays_[0]->set_2dmode(mode);
}
+void ShellView::SetRotation(int angle) {
+ mat4 m(Eigen::AngleAxisf(M_PI * -0.5f * angle, vec3::UnitZ()));
+ for (auto& d: displays_)
+ d->set_rotation(m);
+}
+
void ShellView::OnDrawFrame() {
bool visible = false;
@@ -283,6 +295,20 @@
bool showing = false;
+ // This is a temporary fix for now. These APIs will be changed when everything
+ // is moved into vrcore.
+ // Do this on demand in case vr_flinger crashed and we are reconnecting.
+ if (!display_client_.get()) {
+ int error = 0;
+ display_client_ = DisplayClient::Create(&error);
+
+ if (error) {
+ ALOGE("Could not connect to display service : %s(%d)", strerror(error),
+ error);
+ return base::unique_fd();
+ }
+ }
+
// TODO(achaulk): change when moved into vrcore.
bool vr_running = display_client_->IsVrAppRunning();
@@ -304,19 +330,16 @@
should_recenter_ = false;
}
- size_ = vec2(surface_flinger_view_->width(), surface_flinger_view_->height());
+ for (auto& display : displays_) {
+ if (display->visible()) {
+ display->DrawEye(eye, perspective, eye_matrix, head_matrix, fade_value_);
+ }
+ }
// TODO(alexst): Replicate controller rendering from VR Home.
// Current approach in the function below is a quick visualization.
DrawController(perspective, eye_matrix, head_matrix);
- for (auto& display : displays_) {
- if (display->visible()) {
- display->DrawEye(eye, perspective, eye_matrix, head_matrix, size_,
- fade_value_);
- }
- }
-
DrawReticle(perspective, eye_matrix, head_matrix);
}
@@ -361,6 +384,9 @@
case 0x3:
OnTouchpadButton(false, AMOTION_EVENT_BUTTON_BACK);
break;
+ case 0x4:
+ should_recenter_ = true;
+ break;
case 0x9:
OnClick(true);
break;
@@ -455,13 +481,16 @@
return;
const vec2& hit_location = active_display_->hit_location();
+ const vec2 size = active_display_->size();
+
+ float x = hit_location.x() / size.x();
+ float y = hit_location.y() / size.y();
// Device is portrait, but in landscape when in VR.
// Rotate touch input appropriately.
const android::status_t status = dvrVirtualTouchpadTouch(
virtual_touchpad_.get(), active_display_->touchpad_id(),
- 1.0f - hit_location.y() / size_.y(), hit_location.x() / size_.x(),
- is_touching_ ? 1.0f : 0.0f);
+ x, y, is_touching_ ? 1.0f : 0.0f);
if (status != OK) {
ALOGE("touch failed: %d", status);
}
diff --git a/services/vr/vr_window_manager/shell_view.h b/services/vr/vr_window_manager/shell_view.h
index d265866..be2ae58 100644
--- a/services/vr/vr_window_manager/shell_view.h
+++ b/services/vr/vr_window_manager/shell_view.h
@@ -34,6 +34,7 @@
void VrMode(bool mode) override;
void dumpInternal(String8& result) override;
void Set2DMode(bool mode) override;
+ void SetRotation(int angle) override;
protected:
@@ -82,7 +83,6 @@
bool is_touching_ = false;
int touchpad_buttons_ = 0;
- vec2 size_;
// Used to center the scene when the shell becomes visible.
bool should_recenter_ = true;
diff --git a/services/vr/vr_window_manager/shell_view_binder_interface.h b/services/vr/vr_window_manager/shell_view_binder_interface.h
index 9f77e5a..c66e4a1 100644
--- a/services/vr/vr_window_manager/shell_view_binder_interface.h
+++ b/services/vr/vr_window_manager/shell_view_binder_interface.h
@@ -13,6 +13,7 @@
virtual void VrMode(bool mode) = 0;
virtual void dumpInternal(String8& result) = 0;
virtual void Set2DMode(bool mode) = 0;
+ virtual void SetRotation(int angle) = 0;
};
} // namespace dvr
diff --git a/services/vr/vr_window_manager/surface_flinger_view.cpp b/services/vr/vr_window_manager/surface_flinger_view.cpp
index 46eb880..c0ee1fc 100644
--- a/services/vr/vr_window_manager/surface_flinger_view.cpp
+++ b/services/vr/vr_window_manager/surface_flinger_view.cpp
@@ -1,7 +1,6 @@
#include "surface_flinger_view.h"
#include <impl/vr_composer_view.h>
-#include <private/dvr/display_client.h>
#include <private/dvr/native_buffer.h>
#include "hwc_callback.h"
@@ -15,7 +14,7 @@
SurfaceFlingerView::~SurfaceFlingerView() {}
bool SurfaceFlingerView::Initialize(HwcCallback::Client *client) {
- const char vr_hwcomposer_name[] = "vr_hwcomposer";
+ const char vr_hwcomposer_name[] = "vr";
vr_hwcomposer_ = HIDL_FETCH_IComposer(vr_hwcomposer_name);
if (!vr_hwcomposer_.get()) {
ALOGE("Failed to get vr_hwcomposer");
@@ -34,34 +33,6 @@
return false;
}
- vr_composer_view_ =
- std::make_unique<VrComposerView>(std::make_unique<HwcCallback>(client));
- vr_composer_view_->Initialize(GetComposerViewFromIComposer(
- vr_hwcomposer_.get()));
-
- int error = 0;
- auto display_client = DisplayClient::Create(&error);
- SystemDisplayMetrics metrics;
-
- if (error) {
- ALOGE("Could not connect to display service : %s(%d)", strerror(error), error);
- } else {
- error = display_client->GetDisplayMetrics(&metrics);
-
- if (error) {
- ALOGE("Could not get display metrics from display service : %s(%d)", strerror(error), error);
- }
- }
-
- if (error) {
- metrics.display_native_height = 1920;
- metrics.display_native_width = 1080;
- ALOGI("Setting display metrics to default : width=%d height=%d", metrics.display_native_height, metrics.display_native_width);
- }
-
- // TODO(alexst): Refactor ShellView to account for orientation and change this back.
- width_ = metrics.display_native_height;
- height_ = metrics.display_native_width;
return true;
}
diff --git a/services/vr/vr_window_manager/surface_flinger_view.h b/services/vr/vr_window_manager/surface_flinger_view.h
index 7370299..3ea2b21 100644
--- a/services/vr/vr_window_manager/surface_flinger_view.h
+++ b/services/vr/vr_window_manager/surface_flinger_view.h
@@ -26,9 +26,6 @@
SurfaceFlingerView();
~SurfaceFlingerView();
- int width() const { return width_; }
- int height() const { return height_; }
-
bool Initialize(HwcCallback::Client *client);
bool GetTextures(const HwcCallback::Frame& layers,
@@ -39,8 +36,6 @@
private:
sp<IComposer> vr_hwcomposer_;
std::unique_ptr<VrComposerView> vr_composer_view_;
- int width_ = 0;
- int height_ = 0;
SurfaceFlingerView(const SurfaceFlingerView&) = delete;
void operator=(const SurfaceFlingerView&) = delete;
diff --git a/services/vr/vr_window_manager/vr_window_manager_binder.cpp b/services/vr/vr_window_manager/vr_window_manager_binder.cpp
index 8868588..fdcb8b2 100644
--- a/services/vr/vr_window_manager/vr_window_manager_binder.cpp
+++ b/services/vr/vr_window_manager/vr_window_manager_binder.cpp
@@ -138,6 +138,11 @@
return binder::Status::ok();
}
+binder::Status VrWindowManagerBinder::setRotation(int32_t angle) {
+ app_.SetRotation(angle);
+ return binder::Status::ok();
+}
+
status_t VrWindowManagerBinder::dump(
int fd, const Vector<String16>& args [[gnu::unused]]) {
String8 result;
diff --git a/services/vr/vr_window_manager/vr_window_manager_binder.h b/services/vr/vr_window_manager/vr_window_manager_binder.h
index 1915ffc..9d0f0b2 100644
--- a/services/vr/vr_window_manager/vr_window_manager_binder.h
+++ b/services/vr/vr_window_manager/vr_window_manager_binder.h
@@ -60,6 +60,7 @@
::android::binder::Status exitVrMode() override;
::android::binder::Status setDebugMode(int32_t mode) override;
::android::binder::Status set2DMode(int32_t mode) override;
+ ::android::binder::Status setRotation(int32_t angle) override;
// Implements BBinder::dump().
status_t dump(int fd, const Vector<String16>& args) override;
diff --git a/services/vr/vr_window_manager/vr_wm_ctl.cpp b/services/vr/vr_window_manager/vr_wm_ctl.cpp
index 2e5c488..758e02b 100644
--- a/services/vr/vr_window_manager/vr_wm_ctl.cpp
+++ b/services/vr/vr_window_manager/vr_wm_ctl.cpp
@@ -41,6 +41,8 @@
exit(report(vrwm->setDebugMode(atoi(argv[2]))));
} else if ((argc == 3) && (strcmp(argv[1], "2d") == 0)) {
exit(report(vrwm->set2DMode(atoi(argv[2]))));
+ } else if ((argc == 3) && (strcmp(argv[1], "rotate") == 0)) {
+ exit(report(vrwm->setRotation(atoi(argv[2]))));
} else {
usage();
exit(2);
diff --git a/vulkan/libvulkan/Android.bp b/vulkan/libvulkan/Android.bp
index 2fe880a..9444da5 100644
--- a/vulkan/libvulkan/Android.bp
+++ b/vulkan/libvulkan/Android.bp
@@ -79,4 +79,5 @@
"libcutils",
"libz",
],
+ static_libs: ["libgrallocusage"],
}
diff --git a/vulkan/libvulkan/driver.cpp b/vulkan/libvulkan/driver.cpp
index dbb217d..5fbf5f5 100644
--- a/vulkan/libvulkan/driver.cpp
+++ b/vulkan/libvulkan/driver.cpp
@@ -34,6 +34,9 @@
#include "driver.h"
#include "stubhal.h"
+// Set to true to enable exposing unratified extensions for development
+static const bool kEnableUnratifiedExtensions = false;
+
// #define ENABLE_ALLOC_CALLSTACKS 1
#if ENABLE_ALLOC_CALLSTACKS
#include <utils/CallStack.h>
@@ -675,16 +678,24 @@
const char* pLayerName,
uint32_t* pPropertyCount,
VkExtensionProperties* pProperties) {
- static const std::array<VkExtensionProperties, 4> loader_extensions = {{
- // WSI extensions
- {VK_KHR_SURFACE_EXTENSION_NAME, VK_KHR_SURFACE_SPEC_VERSION},
- {VK_KHR_ANDROID_SURFACE_EXTENSION_NAME,
- VK_KHR_ANDROID_SURFACE_SPEC_VERSION},
- {VK_EXT_SWAPCHAIN_COLOR_SPACE_EXTENSION_NAME,
- VK_EXT_SWAPCHAIN_COLOR_SPACE_SPEC_VERSION},
- {VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME,
- VK_KHR_GET_SURFACE_CAPABILITIES_2_SPEC_VERSION},
- }};
+
+ android::Vector<VkExtensionProperties> loader_extensions;
+ loader_extensions.push_back({
+ VK_KHR_SURFACE_EXTENSION_NAME,
+ VK_KHR_SURFACE_SPEC_VERSION});
+ loader_extensions.push_back({
+ VK_KHR_ANDROID_SURFACE_EXTENSION_NAME,
+ VK_KHR_ANDROID_SURFACE_SPEC_VERSION});
+ loader_extensions.push_back({
+ VK_EXT_SWAPCHAIN_COLOR_SPACE_EXTENSION_NAME,
+ VK_EXT_SWAPCHAIN_COLOR_SPACE_SPEC_VERSION});
+
+ if (kEnableUnratifiedExtensions) {
+ loader_extensions.push_back({
+ VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME,
+ VK_KHR_GET_SURFACE_CAPABILITIES_2_SPEC_VERSION});
+ }
+
static const VkExtensionProperties loader_debug_report_extension = {
VK_EXT_DEBUG_REPORT_EXTENSION_NAME, VK_EXT_DEBUG_REPORT_SPEC_VERSION,
};
@@ -782,13 +793,15 @@
VK_GOOGLE_DISPLAY_TIMING_EXTENSION_NAME,
VK_GOOGLE_DISPLAY_TIMING_SPEC_VERSION});
- // conditionally add shared_presentable_image if supportable
- VkPhysicalDevicePresentationPropertiesANDROID presentation_properties;
- if (QueryPresentationProperties(physicalDevice, &presentation_properties) &&
- presentation_properties.sharedImage) {
- loader_extensions.push_back({
- VK_KHR_SHARED_PRESENTABLE_IMAGE_EXTENSION_NAME,
- VK_KHR_SHARED_PRESENTABLE_IMAGE_SPEC_VERSION});
+ if (kEnableUnratifiedExtensions) {
+ // conditionally add shared_presentable_image if supportable
+ VkPhysicalDevicePresentationPropertiesANDROID presentation_properties;
+ if (QueryPresentationProperties(physicalDevice, &presentation_properties) &&
+ presentation_properties.sharedImage) {
+ loader_extensions.push_back({
+ VK_KHR_SHARED_PRESENTABLE_IMAGE_EXTENSION_NAME,
+ VK_KHR_SHARED_PRESENTABLE_IMAGE_SPEC_VERSION});
+ }
}
// enumerate our extensions first
diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp
index 5017e14..5574da2 100644
--- a/vulkan/libvulkan/swapchain.cpp
+++ b/vulkan/libvulkan/swapchain.cpp
@@ -16,6 +16,7 @@
#include <algorithm>
+#include <grallocusage/GrallocUsageConversion.h>
#include <log/log.h>
#include <ui/BufferQueueDefs.h>
#include <sync/sync.h>
@@ -995,11 +996,8 @@
ALOGE("vkGetSwapchainGrallocUsage2ANDROID failed: %d", result);
return VK_ERROR_SURFACE_LOST_KHR;
}
- // TODO: This is the same translation done by Gralloc1On0Adapter.
- // Remove it once ANativeWindow has been updated to take gralloc1-style
- // usages.
gralloc_usage =
- static_cast<int>(consumer_usage) | static_cast<int>(producer_usage);
+ android_convertGralloc1To0Usage(producer_usage, consumer_usage);
} else if (dispatch.GetSwapchainGrallocUsageANDROID) {
result = dispatch.GetSwapchainGrallocUsageANDROID(
device, create_info->imageFormat, create_info->imageUsage,