Merge changes Ib4fb6c27,I9c41b483,I40372758,Ic787ce17
* changes:
vulkan: update Vulkan headers to 1.0.43
vulkan: update Vulkan headers to 1.0.42
vulkan: update Vulkan headers to 1.0.41
vulkan: update Vulkan headers to 1.0.39
diff --git a/cmds/dumpsys/tests/dumpsys_test.cpp b/cmds/dumpsys/tests/dumpsys_test.cpp
index a61cb00..66beb6d 100644
--- a/cmds/dumpsys/tests/dumpsys_test.cpp
+++ b/cmds/dumpsys/tests/dumpsys_test.cpp
@@ -23,6 +23,7 @@
#include <android-base/file.h>
#include <utils/String16.h>
+#include <utils/String8.h>
#include <utils/Vector.h>
using namespace android;
@@ -95,7 +96,7 @@
int i = 0;
std::ostringstream actual_stream, expected_stream;
for (String16 actual : arg) {
- std::string actual_str = String16::std_string(actual);
+ std::string actual_str = String8(actual).c_str();
std::string expected_str = expected[i];
actual_stream << "'" << actual_str << "' ";
expected_stream << "'" << expected_str << "' ";
diff --git a/cmds/flatland/GLHelper.cpp b/cmds/flatland/GLHelper.cpp
index 5c04f6c..dfc3e58 100644
--- a/cmds/flatland/GLHelper.cpp
+++ b/cmds/flatland/GLHelper.cpp
@@ -25,7 +25,6 @@
namespace android {
GLHelper::GLHelper() :
- mGraphicBufferAlloc(new GraphicBufferAlloc()),
mDisplay(EGL_NO_DISPLAY),
mContext(EGL_NO_CONTEXT),
mDummySurface(EGL_NO_SURFACE),
@@ -203,7 +202,7 @@
sp<GLConsumer>* glConsumer, EGLSurface* surface) {
sp<IGraphicBufferProducer> producer;
sp<IGraphicBufferConsumer> consumer;
- BufferQueue::createBufferQueue(&producer, &consumer, mGraphicBufferAlloc);
+ BufferQueue::createBufferQueue(&producer, &consumer);
sp<GLConsumer> glc = new GLConsumer(consumer, name,
GL_TEXTURE_EXTERNAL_OES, false, true);
glc->setDefaultBufferSize(w, h);
diff --git a/cmds/flatland/GLHelper.h b/cmds/flatland/GLHelper.h
index 7a9e9e3..d09463a 100644
--- a/cmds/flatland/GLHelper.h
+++ b/cmds/flatland/GLHelper.h
@@ -14,7 +14,6 @@
* limitations under the License.
*/
-#include <gui/GraphicBufferAlloc.h>
#include <gui/GLConsumer.h>
#include <gui/Surface.h>
#include <gui/SurfaceControl.h>
@@ -75,8 +74,6 @@
bool setUpShaders(const ShaderDesc* shaderDescs, size_t numShaders);
- sp<GraphicBufferAlloc> mGraphicBufferAlloc;
-
EGLDisplay mDisplay;
EGLContext mContext;
EGLSurface mDummySurface;
diff --git a/cmds/flatland/Main.cpp b/cmds/flatland/Main.cpp
index c47b0c8..ec1e543 100644
--- a/cmds/flatland/Main.cpp
+++ b/cmds/flatland/Main.cpp
@@ -16,7 +16,6 @@
#define ATRACE_TAG ATRACE_TAG_ALWAYS
-#include <gui/GraphicBufferAlloc.h>
#include <gui/Surface.h>
#include <gui/SurfaceControl.h>
#include <gui/GLConsumer.h>
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index fbb30db..71595f0 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -426,12 +426,11 @@
CHECK_ARGUMENT_PACKAGE_NAME(packageName);
std::lock_guard<std::recursive_mutex> lock(mLock);
- const char* pkgname = packageName.c_str();
binder::Status res = ok();
- if (!clear_reference_profile(pkgname)) {
+ if (!clear_reference_profile(packageName)) {
res = error("Failed to clear reference profile for " + packageName);
}
- if (!clear_current_profiles(pkgname)) {
+ if (!clear_current_profiles(packageName)) {
res = error("Failed to clear current profiles for " + packageName);
}
return res;
@@ -479,7 +478,7 @@
}
}
if (!only_cache) {
- if (!clear_current_profile(pkgname, userId)) {
+ if (!clear_current_profile(packageName, userId)) {
res = error("Failed to clear current profile for " + packageName);
}
}
@@ -487,13 +486,13 @@
return res;
}
-static int destroy_app_reference_profile(const char *pkgname) {
+static int destroy_app_reference_profile(const std::string& pkgname) {
return delete_dir_contents_and_dir(
create_data_ref_profile_package_path(pkgname),
/*ignore_if_missing*/ true);
}
-static int destroy_app_current_profiles(const char *pkgname, userid_t userid) {
+static int destroy_app_current_profiles(const std::string& pkgname, userid_t userid) {
return delete_dir_contents_and_dir(
create_data_user_profile_package_path(userid, pkgname),
/*ignore_if_missing*/ true);
@@ -504,15 +503,14 @@
CHECK_ARGUMENT_PACKAGE_NAME(packageName);
std::lock_guard<std::recursive_mutex> lock(mLock);
- const char* pkgname = packageName.c_str();
binder::Status res = ok();
std::vector<userid_t> users = get_known_users(/*volume_uuid*/ nullptr);
for (auto user : users) {
- if (destroy_app_current_profiles(pkgname, user) != 0) {
+ if (destroy_app_current_profiles(packageName, user) != 0) {
res = error("Failed to destroy current profiles for " + packageName);
}
}
- if (destroy_app_reference_profile(pkgname) != 0) {
+ if (destroy_app_reference_profile(packageName) != 0) {
res = error("Failed to destroy reference profile for " + packageName);
}
return res;
@@ -540,11 +538,11 @@
if (delete_dir_contents_and_dir(path) != 0) {
res = error("Failed to delete " + path);
}
- destroy_app_current_profiles(pkgname, userId);
+ destroy_app_current_profiles(packageName, userId);
// TODO(calin): If the package is still installed by other users it's probably
// beneficial to keep the reference profile around.
// Verify if it's ok to do that.
- destroy_app_reference_profile(pkgname);
+ destroy_app_reference_profile(packageName);
}
return res;
}
diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp
index 0fb207b..58b9d2c 100644
--- a/cmds/installd/dexopt.cpp
+++ b/cmds/installd/dexopt.cpp
@@ -101,19 +101,19 @@
return truncated;
}
-bool clear_reference_profile(const char* pkgname) {
+bool clear_reference_profile(const std::string& pkgname) {
std::string reference_profile_dir = create_data_ref_profile_package_path(pkgname);
std::string reference_profile = create_primary_profile(reference_profile_dir);
return clear_profile(reference_profile);
}
-bool clear_current_profile(const char* pkgname, userid_t user) {
+bool clear_current_profile(const std::string& pkgname, userid_t user) {
std::string profile_dir = create_data_user_profile_package_path(user, pkgname);
std::string profile = create_primary_profile(profile_dir);
return clear_profile(profile);
}
-bool clear_current_profiles(const char* pkgname) {
+bool clear_current_profiles(const std::string& pkgname) {
bool success = true;
std::vector<userid_t> users = get_known_users(/*volume_uuid*/ nullptr);
for (auto user : users) {
@@ -512,12 +512,12 @@
return profile_fd;
}
-static fd_t open_primary_profile_file(userid_t user, const char* pkgname) {
+static fd_t open_primary_profile_file(userid_t user, const std::string& pkgname) {
std::string profile_dir = create_data_user_profile_package_path(user, pkgname);
return open_primary_profile_file_from_dir(profile_dir, O_RDONLY);
}
-static fd_t open_reference_profile(uid_t uid, const char* pkgname, bool read_write) {
+static fd_t open_reference_profile(uid_t uid, const std::string& pkgname, bool read_write) {
std::string reference_profile_dir = create_data_ref_profile_package_path(pkgname);
int flags = read_write ? O_RDWR | O_CREAT : O_RDONLY;
fd_t fd = open_primary_profile_file_from_dir(reference_profile_dir, flags);
@@ -534,7 +534,7 @@
return fd;
}
-static void open_profile_files(uid_t uid, const char* pkgname,
+static void open_profile_files(uid_t uid, const std::string& pkgname,
/*out*/ std::vector<fd_t>* profiles_fd, /*out*/ fd_t* reference_profile_fd) {
// Open the reference profile in read-write mode as profman might need to save the merge.
*reference_profile_fd = open_reference_profile(uid, pkgname, /*read_write*/ true);
@@ -614,7 +614,7 @@
// a re-compilation of the package.
// If the return value is true all the current profiles would have been merged into
// the reference profiles accessible with open_reference_profile().
-bool analyse_profiles(uid_t uid, const char* pkgname) {
+bool analyse_profiles(uid_t uid, const std::string& pkgname) {
std::vector<fd_t> profiles_fd;
fd_t reference_profile_fd = -1;
open_profile_files(uid, pkgname, &profiles_fd, &reference_profile_fd);
@@ -628,8 +628,6 @@
return false;
}
- ALOGV("PROFMAN (MERGE): --- BEGIN '%s' ---\n", pkgname);
-
pid_t pid = fork();
if (pid == 0) {
/* child -- drop privileges before continuing */
@@ -740,12 +738,10 @@
}
}
-bool dump_profiles(int32_t uid, const char* pkgname, const char* code_paths) {
+bool dump_profiles(int32_t uid, const std::string& pkgname, const char* code_paths) {
std::vector<fd_t> profile_fds;
fd_t reference_profile_fd = -1;
- std::string out_file_name = StringPrintf("/data/misc/profman/%s.txt", pkgname);
-
- ALOGV("PROFMAN (DUMP): --- BEGIN '%s' ---\n", pkgname);
+ std::string out_file_name = StringPrintf("/data/misc/profman/%s.txt", pkgname.c_str());
open_profile_files(uid, pkgname, &profile_fds, &reference_profile_fd);
@@ -753,7 +749,7 @@
const bool has_profiles = !profile_fds.empty();
if (!has_reference_profile && !has_profiles) {
- ALOGE("profman dump: no profiles to dump for '%s'", pkgname);
+ LOG(ERROR) << "profman dump: no profiles to dump for " << pkgname;
return false;
}
@@ -1105,8 +1101,8 @@
// Opens the vdex files and assigns the input fd to in_vdex_wrapper_fd and the output fd to
// out_vdex_wrapper_fd. Returns true for success or false in case of errors.
bool open_vdex_files(const char* apk_path, const char* out_oat_path, int dexopt_needed,
- const char* instruction_set, bool is_public, int uid, bool is_secondary_dex,
- Dex2oatFileWrapper* in_vdex_wrapper_fd,
+ const char* instruction_set, bool is_public, bool profile_guided,
+ int uid, bool is_secondary_dex, Dex2oatFileWrapper* in_vdex_wrapper_fd,
Dex2oatFileWrapper* out_vdex_wrapper_fd) {
CHECK(in_vdex_wrapper_fd != nullptr);
CHECK(out_vdex_wrapper_fd != nullptr);
@@ -1116,7 +1112,9 @@
int dexopt_action = abs(dexopt_needed);
bool is_odex_location = dexopt_needed < 0;
std::string in_vdex_path_str;
- if (dexopt_action != DEX2OAT_FROM_SCRATCH) {
+ // Disable passing an input vdex when the compilation is profile-guided. The dexlayout
+ // optimization in dex2oat is incompatible with it. b/35872504.
+ if (dexopt_action != DEX2OAT_FROM_SCRATCH && !profile_guided) {
// Open the possibly existing vdex. If none exist, we pass -1 to dex2oat for input-vdex-fd.
const char* path = nullptr;
if (is_odex_location) {
@@ -1135,7 +1133,7 @@
return false;
}
if (dexopt_action == DEX2OAT_FOR_BOOT_IMAGE) {
- // When we dex2oat because iof boot image change, we are going to update
+ // When we dex2oat because of boot image change, we are going to update
// in-place the vdex file.
in_vdex_wrapper_fd->reset(open(in_vdex_path_str.c_str(), O_RDWR, 0));
} else {
@@ -1449,8 +1447,8 @@
// Open vdex files.
Dex2oatFileWrapper in_vdex_fd;
Dex2oatFileWrapper out_vdex_fd;
- if (!open_vdex_files(dex_path, out_oat_path, dexopt_needed, instruction_set, is_public, uid,
- is_secondary_dex, &in_vdex_fd, &out_vdex_fd)) {
+ if (!open_vdex_files(dex_path, out_oat_path, dexopt_needed, instruction_set, is_public,
+ profile_guided, uid, is_secondary_dex, &in_vdex_fd, &out_vdex_fd)) {
return -1;
}
diff --git a/cmds/installd/dexopt.h b/cmds/installd/dexopt.h
index 7bb6eee..fab4d94 100644
--- a/cmds/installd/dexopt.h
+++ b/cmds/installd/dexopt.h
@@ -34,14 +34,14 @@
typedef int fd_t;
-bool clear_reference_profile(const char* pkgname);
-bool clear_current_profile(const char* pkgname, userid_t user);
-bool clear_current_profiles(const char* pkgname);
+bool clear_reference_profile(const std::string& pkgname);
+bool clear_current_profile(const std::string& pkgname, userid_t user);
+bool clear_current_profiles(const std::string& pkgname);
bool move_ab(const char* apk_path, const char* instruction_set, const char* output_path);
-bool analyse_profiles(uid_t uid, const char* pkgname);
-bool dump_profiles(int32_t uid, const char* pkgname, const char* code_paths);
+bool analyse_profiles(uid_t uid, const std::string& pkgname);
+bool dump_profiles(int32_t uid, const std::string& pkgname, const char* code_paths);
bool delete_odex(const char* apk_path, const char* instruction_set, const char* output_path);
diff --git a/cmds/installd/tests/installd_utils_test.cpp b/cmds/installd/tests/installd_utils_test.cpp
index 93a1458..850d257 100644
--- a/cmds/installd/tests/installd_utils_test.cpp
+++ b/cmds/installd/tests/installd_utils_test.cpp
@@ -36,6 +36,8 @@
#define TEST_SYSTEM_DIR1 "/system/app/"
#define TEST_SYSTEM_DIR2 "/vendor/app/"
+#define TEST_PROFILE_DIR "/data/misc/profiles"
+
#define REALLY_LONG_APP_NAME "com.example." \
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa." \
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa." \
@@ -78,6 +80,9 @@
android_system_dirs.dirs[1].path = (char*) TEST_SYSTEM_DIR2;
android_system_dirs.dirs[1].len = strlen(TEST_SYSTEM_DIR2);
+
+ android_profiles_dir.path = (char*) TEST_PROFILE_DIR;
+ android_profiles_dir.len = strlen(TEST_PROFILE_DIR);
}
virtual void TearDown() {
@@ -519,5 +524,31 @@
EXPECT_EQ(false, is_valid_package_name("/com.evil"));
}
+TEST_F(UtilsTest, CreateDataUserProfilePath) {
+ EXPECT_EQ("/data/misc/profiles/cur/0", create_data_user_profile_path(0));
+ EXPECT_EQ("/data/misc/profiles/cur/1", create_data_user_profile_path(1));
+}
+
+TEST_F(UtilsTest, CreateDataUserProfilePackagePath) {
+ EXPECT_EQ("/data/misc/profiles/cur/0/com.example",
+ create_data_user_profile_package_path(0, "com.example"));
+ EXPECT_EQ("/data/misc/profiles/cur/1/com.example",
+ create_data_user_profile_package_path(1, "com.example"));
+}
+
+TEST_F(UtilsTest, CreateDataRefProfilePath) {
+ EXPECT_EQ("/data/misc/profiles/ref", create_data_ref_profile_path());
+}
+
+TEST_F(UtilsTest, CreateDataRefProfilePackagePath) {
+ EXPECT_EQ("/data/misc/profiles/ref/com.example",
+ create_data_ref_profile_package_path("com.example"));
+}
+
+TEST_F(UtilsTest, CreatePrimaryProfile) {
+ EXPECT_EQ("/data/misc/profiles/ref/com.example/primary.prof",
+ create_primary_profile("/data/misc/profiles/ref/com.example"));
+}
+
} // namespace installd
} // namespace android
diff --git a/cmds/installd/utils.cpp b/cmds/installd/utils.cpp
index af7a7c6..e5b243a 100644
--- a/cmds/installd/utils.cpp
+++ b/cmds/installd/utils.cpp
@@ -221,18 +221,18 @@
return StringPrintf("%s/cur/%u", android_profiles_dir.path, userid);
}
-std::string create_data_user_profile_package_path(userid_t user, const char* package_name) {
- check_package_name(package_name);
- return StringPrintf("%s/%s",create_data_user_profile_path(user).c_str(), package_name);
+std::string create_data_user_profile_package_path(userid_t user, const std::string& package_name) {
+ check_package_name(package_name.c_str());
+ return StringPrintf("%s/%s",create_data_user_profile_path(user).c_str(), package_name.c_str());
}
std::string create_data_ref_profile_path() {
return StringPrintf("%s/ref", android_profiles_dir.path);
}
-std::string create_data_ref_profile_package_path(const char* package_name) {
- check_package_name(package_name);
- return StringPrintf("%s/ref/%s", android_profiles_dir.path, package_name);
+std::string create_data_ref_profile_package_path(const std::string& package_name) {
+ check_package_name(package_name.c_str());
+ return StringPrintf("%s/ref/%s", android_profiles_dir.path, package_name.c_str());
}
std::string create_data_dalvik_cache_path() {
diff --git a/cmds/installd/utils.h b/cmds/installd/utils.h
index d99b445..1c36a54 100644
--- a/cmds/installd/utils.h
+++ b/cmds/installd/utils.h
@@ -97,10 +97,10 @@
std::string create_data_misc_legacy_path(userid_t userid);
std::string create_data_user_profile_path(userid_t userid);
-std::string create_data_user_profile_package_path(userid_t user, const char* package_name);
+std::string create_data_user_profile_package_path(userid_t user, const std::string& package_name);
std::string create_data_ref_profile_path();
-std::string create_data_ref_profile_package_path(const char* package_name);
+std::string create_data_ref_profile_package_path(const std::string& package_name);
std::string create_data_dalvik_cache_path();
diff --git a/cmds/lshal/Lshal.cpp b/cmds/lshal/Lshal.cpp
index 9e60461..8750147 100644
--- a/cmds/lshal/Lshal.cpp
+++ b/cmds/lshal/Lshal.cpp
@@ -160,14 +160,14 @@
}
void Lshal::forEachTable(const std::function<void(Table &)> &f) {
- for (const Table &table : {mServicesTable, mPassthroughRefTable, mImplementationsTable}) {
- f(const_cast<Table &>(table));
- }
+ f(mServicesTable);
+ f(mPassthroughRefTable);
+ f(mImplementationsTable);
}
void Lshal::forEachTable(const std::function<void(const Table &)> &f) const {
- for (const Table &table : {mServicesTable, mPassthroughRefTable, mImplementationsTable}) {
- f(table);
- }
+ f(mServicesTable);
+ f(mPassthroughRefTable);
+ f(mImplementationsTable);
}
void Lshal::postprocess() {
@@ -183,6 +183,26 @@
}
}
});
+ // use a double for loop here because lshal doesn't care about efficiency.
+ for (TableEntry &packageEntry : mImplementationsTable) {
+ std::string packageName = packageEntry.interfaceName;
+ FQName fqPackageName{packageName.substr(0, packageName.find("::"))};
+ if (!fqPackageName.isValid()) {
+ continue;
+ }
+ for (TableEntry &interfaceEntry : mPassthroughRefTable) {
+ if (interfaceEntry.arch != ARCH_UNKNOWN) {
+ continue;
+ }
+ FQName interfaceName{splitFirst(interfaceEntry.interfaceName, '/').first};
+ if (!interfaceName.isValid()) {
+ continue;
+ }
+ if (interfaceName.getPackageAndVersion() == fqPackageName) {
+ interfaceEntry.arch = packageEntry.arch;
+ }
+ }
+ }
}
void Lshal::printLine(
@@ -247,10 +267,25 @@
&table == &mImplementationsTable ? "" : splittedFqInstanceName.second;
vintf::Transport transport;
+ vintf::Arch arch;
if (entry.transport == "hwbinder") {
transport = vintf::Transport::HWBINDER;
+ arch = vintf::Arch::ARCH_EMPTY;
} else if (entry.transport == "passthrough") {
transport = vintf::Transport::PASSTHROUGH;
+ switch (entry.arch) {
+ case lshal::ARCH32:
+ arch = vintf::Arch::ARCH_32; break;
+ case lshal::ARCH64:
+ arch = vintf::Arch::ARCH_64; break;
+ case lshal::ARCH_BOTH:
+ arch = vintf::Arch::ARCH_32_64; break;
+ case lshal::ARCH_UNKNOWN: // fallthrough
+ default:
+ mErr << "Warning: '" << fqName.package()
+ << "' doesn't have bitness info, assuming 32+64." << std::endl;
+ arch = vintf::Arch::ARCH_32_64;
+ }
} else {
mErr << "Warning: '" << entry.transport << "' is not a valid transport." << std::endl;
continue;
@@ -262,7 +297,7 @@
.format = vintf::HalFormat::HIDL,
.name = fqName.package(),
.impl = {.implLevel = vintf::ImplLevel::GENERIC, .impl = ""},
- .transport = transport
+ .transportArch = {transport, arch}
})) {
mErr << "Warning: cannot add hal '" << fqInstanceName << "'" << std::endl;
continue;
diff --git a/cmds/lshal/TableEntry.h b/cmds/lshal/TableEntry.h
index 2407b42..9ae8f78 100644
--- a/cmds/lshal/TableEntry.h
+++ b/cmds/lshal/TableEntry.h
@@ -37,8 +37,8 @@
enum : unsigned int {
ARCH_UNKNOWN = 0,
- ARCH64 = 1 << 0,
- ARCH32 = 1 << 1,
+ ARCH32 = 1 << 0,
+ ARCH64 = 1 << 1,
ARCH_BOTH = ARCH32 | ARCH64
};
using Architecture = unsigned int;
diff --git a/include/gui/BufferQueue.h b/include/gui/BufferQueue.h
index c95c535..bd62d85 100644
--- a/include/gui/BufferQueue.h
+++ b/include/gui/BufferQueue.h
@@ -23,10 +23,6 @@
#include <gui/IGraphicBufferProducer.h>
#include <gui/IConsumerListener.h>
-// These are only required to keep other parts of the framework with incomplete
-// dependencies building successfully
-#include <gui/IGraphicBufferAlloc.h>
-
namespace android {
class BufferQueue {
@@ -81,11 +77,9 @@
// needed gralloc buffers.
static void createBufferQueue(sp<IGraphicBufferProducer>* outProducer,
sp<IGraphicBufferConsumer>* outConsumer,
- const sp<IGraphicBufferAlloc>& allocator = NULL,
bool consumerIsSurfaceFlinger = false);
-private:
- BufferQueue(); // Create through createBufferQueue
+ BufferQueue() = delete; // Create through createBufferQueue
};
// ----------------------------------------------------------------------------
diff --git a/include/gui/BufferQueueCore.h b/include/gui/BufferQueueCore.h
index b1c730a..1e9585c 100644
--- a/include/gui/BufferQueueCore.h
+++ b/include/gui/BufferQueueCore.h
@@ -51,7 +51,6 @@
namespace android {
class IConsumerListener;
-class IGraphicBufferAlloc;
class IProducerListener;
class BufferQueueCore : public virtual RefBase {
@@ -79,9 +78,8 @@
typedef Vector<BufferItem> Fifo;
// BufferQueueCore manages a pool of gralloc memory slots to be used by
- // producers and consumers. allocator is used to allocate all the needed
- // gralloc buffers.
- BufferQueueCore(const sp<IGraphicBufferAlloc>& allocator = NULL);
+ // producers and consumers.
+ BufferQueueCore();
virtual ~BufferQueueCore();
private:
@@ -143,10 +141,6 @@
void validateConsistencyLocked() const;
#endif
- // mAllocator is the connection to SurfaceFlinger that is used to allocate
- // new GraphicBuffer objects.
- sp<IGraphicBufferAlloc> mAllocator;
-
// mMutex is the mutex used to prevent concurrent access to the member
// variables of BufferQueueCore objects. It must be locked whenever any
// member variable is accessed.
diff --git a/include/gui/GraphicBufferAlloc.h b/include/gui/GraphicBufferAlloc.h
deleted file mode 100644
index 54c9829..0000000
--- a/include/gui/GraphicBufferAlloc.h
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (C) 2012 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_GUI_GRAPHIC_BUFFER_ALLOC_H
-#define ANDROID_GUI_GRAPHIC_BUFFER_ALLOC_H
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <gui/IGraphicBufferAlloc.h>
-#include <ui/PixelFormat.h>
-#include <utils/Errors.h>
-
-namespace android {
-
-class GraphicBuffer;
-
-/*
- * Concrete implementation of the IGraphicBufferAlloc interface.
- *
- * This can create GraphicBuffer instance across processes. This is mainly used
- * by surfaceflinger.
- */
-
-class GraphicBufferAlloc : public BnGraphicBufferAlloc {
-public:
- GraphicBufferAlloc();
- virtual ~GraphicBufferAlloc();
- virtual sp<GraphicBuffer> createGraphicBuffer(uint32_t width,
- uint32_t height, PixelFormat format, uint32_t layerCount,
- uint64_t producerUsage, uint64_t consumerUsage,
- std::string requestorName, status_t* error) override;
-};
-
-
-} // namespace android
-
-#endif // ANDROID_GUI_GRAPHIC_BUFFER_ALLOC_H
diff --git a/include/gui/IGraphicBufferAlloc.h b/include/gui/IGraphicBufferAlloc.h
deleted file mode 100644
index 1e578cc..0000000
--- a/include/gui/IGraphicBufferAlloc.h
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef ANDROID_GUI_IGRAPHIC_BUFFER_ALLOC_H
-#define ANDROID_GUI_IGRAPHIC_BUFFER_ALLOC_H
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <binder/IInterface.h>
-#include <ui/GraphicBuffer.h>
-#include <ui/PixelFormat.h>
-#include <utils/RefBase.h>
-
-#include <string>
-
-namespace android {
-// ----------------------------------------------------------------------------
-
-class IGraphicBufferAlloc : public IInterface
-{
-public:
- DECLARE_META_INTERFACE(GraphicBufferAlloc)
-
- /* Create a new GraphicBuffer for the client to use.
- */
- virtual sp<GraphicBuffer> createGraphicBuffer(uint32_t w, uint32_t h,
- PixelFormat format, uint32_t layerCount, uint64_t producerUsage,
- uint64_t consumerUsage, std::string requestorName,
- status_t* error) = 0;
-
- sp<GraphicBuffer> createGraphicBuffer(uint32_t w, uint32_t h,
- PixelFormat format, uint32_t layerCount, uint32_t usage,
- status_t* error) {
- return createGraphicBuffer(w, h, format, layerCount, usage,
- usage, "<Unknown>", error);
- }
-
- sp<GraphicBuffer> createGraphicBuffer(uint32_t w, uint32_t h,
- PixelFormat format, uint32_t layerCount, uint32_t usage,
- std::string requestorName, status_t* error) {
- return createGraphicBuffer(w, h, format, layerCount, usage,
- usage, requestorName, error);
- }
-
- sp<GraphicBuffer> createGraphicBuffer(uint32_t w, uint32_t h,
- PixelFormat format, uint32_t layerCount, uint64_t producerUsage,
- uint64_t consumerUsage, status_t* error) {
- return createGraphicBuffer(w, h, format, layerCount, producerUsage,
- consumerUsage, "<Unknown>", error);
- }
-};
-
-// ----------------------------------------------------------------------------
-
-class BnGraphicBufferAlloc : public BnInterface<IGraphicBufferAlloc>
-{
-public:
- virtual status_t onTransact(uint32_t code,
- const Parcel& data,
- Parcel* reply,
- uint32_t flags = 0);
-};
-
-// ----------------------------------------------------------------------------
-
-}; // namespace android
-
-#endif // ANDROID_GUI_IGRAPHIC_BUFFER_ALLOC_H
diff --git a/include/gui/ISurfaceComposer.h b/include/gui/ISurfaceComposer.h
index 9870ba0..1112973 100644
--- a/include/gui/ISurfaceComposer.h
+++ b/include/gui/ISurfaceComposer.h
@@ -41,7 +41,6 @@
struct DisplayStatInfo;
class HdrCapabilities;
class IDisplayEventConnection;
-class IGraphicBufferAlloc;
class IGraphicBufferProducer;
class ISurfaceComposerClient;
class Rect;
@@ -89,10 +88,6 @@
virtual sp<ISurfaceComposerClient> createScopedConnection(
const sp<IGraphicBufferProducer>& parent) = 0;
- /* create a graphic buffer allocator
- */
- virtual sp<IGraphicBufferAlloc> createGraphicBufferAlloc() = 0;
-
/* return an IDisplayEventConnection */
virtual sp<IDisplayEventConnection> createDisplayEventConnection() = 0;
@@ -205,7 +200,7 @@
// Java by ActivityManagerService.
BOOT_FINISHED = IBinder::FIRST_CALL_TRANSACTION,
CREATE_CONNECTION,
- CREATE_GRAPHIC_BUFFER_ALLOC,
+ UNUSED, // formerly CREATE_GRAPHIC_BUFFER_ALLOC
CREATE_DISPLAY_EVENT_CONNECTION,
CREATE_DISPLAY,
DESTROY_DISPLAY,
diff --git a/include/private/ui/RegionHelper.h b/include/private/ui/RegionHelper.h
index a22b2cb..a86c586 100644
--- a/include/private/ui/RegionHelper.h
+++ b/include/private/ui/RegionHelper.h
@@ -17,6 +17,7 @@
#ifndef ANDROID_UI_PRIVATE_REGION_HELPER_H
#define ANDROID_UI_PRIVATE_REGION_HELPER_H
+#include <limits>
#include <stdint.h>
#include <sys/types.h>
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp
index a1b4abc..9d2dcb6 100644
--- a/libs/gui/Android.bp
+++ b/libs/gui/Android.bp
@@ -70,11 +70,9 @@
"DisplayEventReceiver.cpp",
"FrameTimestamps.cpp",
"GLConsumer.cpp",
- "GraphicBufferAlloc.cpp",
"GuiConfig.cpp",
"IDisplayEventConnection.cpp",
"IConsumerListener.cpp",
- "IGraphicBufferAlloc.cpp",
"IGraphicBufferConsumer.cpp",
"IGraphicBufferProducer.cpp",
"IProducerListener.cpp",
diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp
index 13692eb..4151212 100644
--- a/libs/gui/BufferQueue.cpp
+++ b/libs/gui/BufferQueue.cpp
@@ -79,14 +79,13 @@
void BufferQueue::createBufferQueue(sp<IGraphicBufferProducer>* outProducer,
sp<IGraphicBufferConsumer>* outConsumer,
- const sp<IGraphicBufferAlloc>& allocator,
bool consumerIsSurfaceFlinger) {
LOG_ALWAYS_FATAL_IF(outProducer == NULL,
"BufferQueue: outProducer must not be NULL");
LOG_ALWAYS_FATAL_IF(outConsumer == NULL,
"BufferQueue: outConsumer must not be NULL");
- sp<BufferQueueCore> core(new BufferQueueCore(allocator));
+ sp<BufferQueueCore> core(new BufferQueueCore());
LOG_ALWAYS_FATAL_IF(core == NULL,
"BufferQueue: failed to create BufferQueueCore");
diff --git a/libs/gui/BufferQueueCore.cpp b/libs/gui/BufferQueueCore.cpp
index 9e3fecb..1b8ffd7 100644
--- a/libs/gui/BufferQueueCore.cpp
+++ b/libs/gui/BufferQueueCore.cpp
@@ -33,9 +33,7 @@
#include <gui/BufferItem.h>
#include <gui/BufferQueueCore.h>
-#include <gui/GraphicBufferAlloc.h>
#include <gui/IConsumerListener.h>
-#include <gui/IGraphicBufferAlloc.h>
#include <gui/IProducerListener.h>
#include <gui/ISurfaceComposer.h>
#include <private/gui/ComposerService.h>
@@ -54,8 +52,7 @@
return id | counter++;
}
-BufferQueueCore::BufferQueueCore(const sp<IGraphicBufferAlloc>& allocator) :
- mAllocator(allocator),
+BufferQueueCore::BufferQueueCore() :
mMutex(),
mIsAbandoned(false),
mConsumerControlledByApp(false),
@@ -97,30 +94,6 @@
mLastQueuedSlot(INVALID_BUFFER_SLOT),
mUniqueId(getUniqueId())
{
- if (allocator == NULL) {
-
-#ifdef HAVE_NO_SURFACE_FLINGER
- // Without a SurfaceFlinger, allocate in-process. This only makes
- // sense in systems with static SELinux configurations and no
- // applications (since applications need dynamic SELinux policy).
- mAllocator = new GraphicBufferAlloc();
-#else
- // Run time check for headless, where we also allocate in-process.
- char value[PROPERTY_VALUE_MAX];
- property_get("config.headless", value, "0");
- if (atoi(value) == 1) {
- mAllocator = new GraphicBufferAlloc();
- } else {
- sp<ISurfaceComposer> composer(ComposerService::getComposerService());
- mAllocator = composer->createGraphicBufferAlloc();
- }
-#endif // HAVE_NO_SURFACE_FLINGER
-
- if (mAllocator == NULL) {
- BQ_LOGE("createGraphicBufferAlloc failed");
- }
- }
-
int numStartingBuffers = getMaxBufferCountLocked();
for (int s = 0; s < numStartingBuffers; s++) {
mFreeSlots.insert(s);
diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp
index 27ced61..b92e895 100644
--- a/libs/gui/BufferQueueProducer.cpp
+++ b/libs/gui/BufferQueueProducer.cpp
@@ -34,7 +34,6 @@
#include <gui/BufferQueueProducer.h>
#include <gui/GLConsumer.h>
#include <gui/IConsumerListener.h>
-#include <gui/IGraphicBufferAlloc.h>
#include <gui/IProducerListener.h>
#include <utils/Log.h>
@@ -454,8 +453,7 @@
mSlots[found].mBufferState.dequeue();
if ((buffer == NULL) ||
- buffer->needsReallocation(width, height, format, BQ_LAYER_COUNT,
- usage))
+ buffer->needsReallocation(width, height, format, BQ_LAYER_COUNT, usage))
{
mSlots[found].mAcquireCalled = false;
mSlots[found].mGraphicBuffer = NULL;
@@ -503,11 +501,13 @@
} // Autolock scope
if (returnFlags & BUFFER_NEEDS_REALLOCATION) {
- status_t error;
BQ_LOGV("dequeueBuffer: allocating a new buffer for slot %d", *outSlot);
- sp<GraphicBuffer> graphicBuffer(mCore->mAllocator->createGraphicBuffer(
- width, height, format, BQ_LAYER_COUNT, usage,
- {mConsumerName.string(), mConsumerName.size()}, &error));
+ sp<GraphicBuffer> graphicBuffer = new GraphicBuffer(
+ width, height, format, BQ_LAYER_COUNT, usage, usage,
+ {mConsumerName.string(), mConsumerName.size()});
+
+ status_t error = graphicBuffer->initCheck();
+
{ // Autolock scope
Mutex::Autolock lock(mCore->mMutex);
@@ -1329,11 +1329,12 @@
Vector<sp<GraphicBuffer>> buffers;
for (size_t i = 0; i < newBufferCount; ++i) {
- status_t result = NO_ERROR;
- sp<GraphicBuffer> graphicBuffer(mCore->mAllocator->createGraphicBuffer(
+ sp<GraphicBuffer> graphicBuffer = new GraphicBuffer(
allocWidth, allocHeight, allocFormat, BQ_LAYER_COUNT,
- allocUsage, {mConsumerName.string(), mConsumerName.size()},
- &result));
+ allocUsage, allocUsage, {mConsumerName.string(), mConsumerName.size()});
+
+ status_t result = graphicBuffer->initCheck();
+
if (result != NO_ERROR) {
BQ_LOGE("allocateBuffers: failed to allocate buffer (%u x %u, format"
" %u, usage %u)", width, height, format, usage);
diff --git a/libs/gui/ConsumerBase.cpp b/libs/gui/ConsumerBase.cpp
index 8acdfed..9d0fa7e 100644
--- a/libs/gui/ConsumerBase.cpp
+++ b/libs/gui/ConsumerBase.cpp
@@ -30,7 +30,6 @@
#include <cutils/atomic.h>
#include <gui/BufferItem.h>
-#include <gui/IGraphicBufferAlloc.h>
#include <gui/ISurfaceComposer.h>
#include <gui/SurfaceComposerClient.h>
#include <gui/ConsumerBase.h>
diff --git a/libs/gui/GLConsumer.cpp b/libs/gui/GLConsumer.cpp
index 55e0d26..c654f08 100644
--- a/libs/gui/GLConsumer.cpp
+++ b/libs/gui/GLConsumer.cpp
@@ -31,7 +31,6 @@
#include <gui/BufferItem.h>
#include <gui/GLConsumer.h>
-#include <gui/IGraphicBufferAlloc.h>
#include <gui/ISurfaceComposer.h>
#include <gui/SurfaceComposerClient.h>
diff --git a/libs/gui/GraphicBufferAlloc.cpp b/libs/gui/GraphicBufferAlloc.cpp
deleted file mode 100644
index cc7d403..0000000
--- a/libs/gui/GraphicBufferAlloc.cpp
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- **
- ** Copyright 2012 The Android Open Source Project
- **
- ** Licensed under the Apache License Version 2.0(the "License");
- ** you may not use this file except in compliance with the License.
- ** You may obtain a copy of the License at
- **
- ** http://www.apache.org/licenses/LICENSE-2.0
- **
- ** Unless required by applicable law or agreed to in writing software
- ** distributed under the License is distributed on an "AS IS" BASIS
- ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND either express or implied.
- ** See the License for the specific language governing permissions and
- ** limitations under the License.
- */
-
-#include <gui/GraphicBufferAlloc.h>
-
-#include <log/log.h>
-
-
-namespace android {
-
-GraphicBufferAlloc::GraphicBufferAlloc() = default;
-GraphicBufferAlloc::~GraphicBufferAlloc() = default;
-
-sp<GraphicBuffer> GraphicBufferAlloc::createGraphicBuffer(uint32_t width,
- uint32_t height, PixelFormat format, uint32_t layerCount,
- uint64_t producerUsage, uint64_t consumerUsage,
- std::string requestorName, status_t* error) {
- sp<GraphicBuffer> graphicBuffer(new GraphicBuffer(
- width, height, format, layerCount, producerUsage, consumerUsage,
- std::move(requestorName)));
- status_t err = graphicBuffer->initCheck();
- *error = err;
- if (err != 0 || graphicBuffer->handle == 0) {
- if (err == NO_MEMORY) {
- GraphicBuffer::dumpAllocationsToSystemLog();
- }
- ALOGE("GraphicBufferAlloc::createGraphicBuffer(w=%u, h=%u, lc=%u) failed (%s), handle=%p",
- width, height, layerCount, strerror(-err),
- graphicBuffer->handle);
- graphicBuffer.clear();
- }
- return graphicBuffer;
-}
-
-} // namespace android
diff --git a/libs/gui/IGraphicBufferAlloc.cpp b/libs/gui/IGraphicBufferAlloc.cpp
deleted file mode 100644
index 21a0dd5..0000000
--- a/libs/gui/IGraphicBufferAlloc.cpp
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
- * 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.
- */
-
-// tag as surfaceflinger
-#define LOG_TAG "SurfaceFlinger"
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <binder/Parcel.h>
-
-#include <ui/GraphicBuffer.h>
-
-#include <gui/IGraphicBufferAlloc.h>
-
-// ---------------------------------------------------------------------------
-
-namespace android {
-
-enum {
- CREATE_GRAPHIC_BUFFER = IBinder::FIRST_CALL_TRANSACTION,
-};
-
-class BpGraphicBufferAlloc : public BpInterface<IGraphicBufferAlloc>
-{
-public:
- explicit BpGraphicBufferAlloc(const sp<IBinder>& impl)
- : BpInterface<IGraphicBufferAlloc>(impl)
- {
- }
-
- virtual ~BpGraphicBufferAlloc();
-
- virtual sp<GraphicBuffer> createGraphicBuffer(uint32_t width,
- uint32_t height, PixelFormat format, uint32_t layerCount,
- uint64_t producerUsage, uint64_t consumerUsage,
- std::string requestorName, status_t* error) {
- Parcel data, reply;
- data.writeInterfaceToken(IGraphicBufferAlloc::getInterfaceDescriptor());
- data.writeUint32(width);
- data.writeUint32(height);
- data.writeInt32(static_cast<int32_t>(format));
- data.writeUint32(layerCount);
- data.writeUint64(producerUsage);
- data.writeUint64(consumerUsage);
- if (requestorName.empty()) {
- requestorName += "[PID ";
- requestorName += std::to_string(getpid());
- requestorName += ']';
- }
- data.writeUtf8AsUtf16(requestorName);
- remote()->transact(CREATE_GRAPHIC_BUFFER, data, &reply);
- sp<GraphicBuffer> graphicBuffer;
- status_t result = reply.readInt32();
- if (result == NO_ERROR) {
- graphicBuffer = new GraphicBuffer();
- result = reply.read(*graphicBuffer);
- if (result != NO_ERROR) {
- graphicBuffer.clear();
- }
- // reply.readStrongBinder();
- // here we don't even have to read the BufferReference from
- // the parcel, it'll die with the parcel.
- }
- *error = result;
- return graphicBuffer;
- }
-};
-
-// Out-of-line virtual method definition to trigger vtable emission in this
-// translation unit (see clang warning -Wweak-vtables)
-BpGraphicBufferAlloc::~BpGraphicBufferAlloc() {}
-
-IMPLEMENT_META_INTERFACE(GraphicBufferAlloc, "android.ui.IGraphicBufferAlloc");
-
-// ----------------------------------------------------------------------
-
-status_t BnGraphicBufferAlloc::onTransact(
- uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
-{
- // codes that don't require permission check
-
- // BufferReference just keeps a strong reference to a GraphicBuffer until it
- // is destroyed (that is, until no local or remote process have a reference
- // to it).
- class BufferReference : public BBinder {
- sp<GraphicBuffer> mBuffer;
- public:
- explicit BufferReference(const sp<GraphicBuffer>& buffer) : mBuffer(buffer) {}
- };
-
-
- switch (code) {
- case CREATE_GRAPHIC_BUFFER: {
- CHECK_INTERFACE(IGraphicBufferAlloc, data, reply);
- uint32_t width = data.readUint32();
- uint32_t height = data.readUint32();
- PixelFormat format = static_cast<PixelFormat>(data.readInt32());
- uint32_t layerCount = data.readUint32();
- uint64_t producerUsage = data.readUint64();
- uint64_t consumerUsage = data.readUint64();
- status_t error = NO_ERROR;
- std::string requestorName;
- data.readUtf8FromUtf16(&requestorName);
- sp<GraphicBuffer> result = createGraphicBuffer(width, height,
- format, layerCount, producerUsage, consumerUsage,
- requestorName, &error);
- reply->writeInt32(error);
- if (result != 0) {
- reply->write(*result);
- // We add a BufferReference to this parcel to make sure the
- // buffer stays alive until the GraphicBuffer object on
- // the other side has been created.
- // This is needed so that the buffer handle can be
- // registered before the buffer is destroyed on implementations
- // that do not use file-descriptors to track their buffers.
- reply->writeStrongBinder( new BufferReference(result) );
- }
- return NO_ERROR;
- }
- default:
- return BBinder::onTransact(code, data, reply, flags);
- }
-}
-
-}; // namespace android
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index 4d2692f..2516fb8 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -25,7 +25,6 @@
#include <binder/IServiceManager.h>
#include <gui/IDisplayEventConnection.h>
-#include <gui/IGraphicBufferAlloc.h>
#include <gui/IGraphicBufferProducer.h>
#include <gui/ISurfaceComposer.h>
#include <gui/ISurfaceComposerClient.h>
@@ -72,14 +71,6 @@
return interface_cast<ISurfaceComposerClient>(reply.readStrongBinder());
}
- virtual sp<IGraphicBufferAlloc> createGraphicBufferAlloc()
- {
- Parcel data, reply;
- data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
- remote()->transact(BnSurfaceComposer::CREATE_GRAPHIC_BUFFER_ALLOC, data, &reply);
- return interface_cast<IGraphicBufferAlloc>(reply.readStrongBinder());
- }
-
virtual void setTransactionState(
const Vector<ComposerState>& state,
const Vector<DisplayState>& displays,
@@ -505,12 +496,6 @@
reply->writeStrongBinder(b);
return NO_ERROR;
}
- case CREATE_GRAPHIC_BUFFER_ALLOC: {
- CHECK_INTERFACE(ISurfaceComposer, data, reply);
- sp<IBinder> b = IInterface::asBinder(createGraphicBufferAlloc());
- reply->writeStrongBinder(b);
- return NO_ERROR;
- }
case SET_TRANSACTION_STATE: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index ad1984a..a2e12f7 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -836,6 +836,10 @@
*value = mFrameTimestampsSupportsRetire ? 1 : 0;
return NO_ERROR;
}
+ case NATIVE_WINDOW_IS_VALID: {
+ *value = mGraphicBufferProducer != nullptr ? 1 : 0;
+ return NO_ERROR;
+ }
}
}
return mGraphicBufferProducer->query(what, value);
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index da6f13d..be48c11 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -366,9 +366,6 @@
const sp<IGraphicBufferProducer>& /* parent */) override {
return nullptr;
}
- sp<IGraphicBufferAlloc> createGraphicBufferAlloc() override {
- return nullptr;
- }
sp<IDisplayEventConnection> createDisplayEventConnection() override {
return nullptr;
}
diff --git a/libs/hwc2on1adapter/Android.bp b/libs/hwc2on1adapter/Android.bp
new file mode 100644
index 0000000..2be3e67
--- /dev/null
+++ b/libs/hwc2on1adapter/Android.bp
@@ -0,0 +1,68 @@
+// Copyright 2010 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_library_shared {
+ name: "libhwc2on1adapter",
+
+ clang: true,
+ cppflags: [
+ "-Weverything",
+ "-Wall",
+ "-Wunused",
+ "-Wunreachable-code",
+
+ // The static constructors and destructors in this library have not been noted to
+ // introduce significant overheads
+ "-Wno-exit-time-destructors",
+ "-Wno-global-constructors",
+
+ // We only care about compiling as C++14
+ "-Wno-c++98-compat-pedantic",
+
+ // android/sensors.h uses nested anonymous unions and anonymous structs
+ "-Wno-nested-anon-types",
+ "-Wno-gnu-anonymous-struct",
+
+ // Don't warn about struct padding
+ "-Wno-padded",
+
+ // hwcomposer2.h features switch covering all cases.
+ "-Wno-covered-switch-default",
+
+ // hwcomposer.h features zero size array.
+ "-Wno-zero-length-array",
+
+ // Disabling warning specific to hwc2on1adapter code
+ "-Wno-double-promotion",
+ "-Wno-sign-conversion",
+ "-Wno-switch-enum",
+ "-Wno-float-equal",
+ ],
+
+ srcs: [
+ "HWC2On1Adapter.cpp",
+ "MiniFence.cpp",
+ ],
+
+ shared_libs: [
+ "libutils",
+ "libcutils",
+ "liblog",
+ "libhardware",
+ ],
+
+ export_include_dirs: ["include"],
+
+ export_shared_lib_headers: ["libutils"],
+}
diff --git a/services/surfaceflinger/DisplayHardware/HWC2On1Adapter.cpp b/libs/hwc2on1adapter/HWC2On1Adapter.cpp
similarity index 99%
rename from services/surfaceflinger/DisplayHardware/HWC2On1Adapter.cpp
rename to libs/hwc2on1adapter/HWC2On1Adapter.cpp
index 13bf0b5..5ad05c7 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2On1Adapter.cpp
+++ b/libs/hwc2on1adapter/HWC2On1Adapter.cpp
@@ -14,13 +14,14 @@
* limitations under the License.
*/
+#include "hwc2on1adapter/HWC2On1Adapter.h"
+
//#define LOG_NDEBUG 0
#undef LOG_TAG
#define LOG_TAG "HWC2On1Adapter"
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
-#include "HWC2On1Adapter.h"
#include <inttypes.h>
@@ -317,15 +318,6 @@
return Error::NoResources;
}
- if (MAX_VIRTUAL_DISPLAY_DIMENSION != 0 &&
- (width > MAX_VIRTUAL_DISPLAY_DIMENSION ||
- height > MAX_VIRTUAL_DISPLAY_DIMENSION)) {
- ALOGE("createVirtualDisplay: Can't create a virtual display with"
- " a dimension > %u (tried %u x %u)",
- MAX_VIRTUAL_DISPLAY_DIMENSION, width, height);
- return Error::NoResources;
- }
-
mHwc1VirtualDisplay = std::make_shared<HWC2On1Adapter::Display>(*this,
HWC2::DisplayType::Virtual);
mHwc1VirtualDisplay->populateConfigs(width, height);
diff --git a/services/surfaceflinger/DisplayHardware/MiniFence.cpp b/libs/hwc2on1adapter/MiniFence.cpp
similarity index 95%
rename from services/surfaceflinger/DisplayHardware/MiniFence.cpp
rename to libs/hwc2on1adapter/MiniFence.cpp
index ecfb063..dfbe4d6 100644
--- a/services/surfaceflinger/DisplayHardware/MiniFence.cpp
+++ b/libs/hwc2on1adapter/MiniFence.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#include "MiniFence.h"
+#include "hwc2on1adapter/MiniFence.h"
#include <unistd.h>
diff --git a/services/surfaceflinger/DisplayHardware/HWC2On1Adapter.h b/libs/hwc2on1adapter/include/hwc2on1adapter/HWC2On1Adapter.h
similarity index 100%
rename from services/surfaceflinger/DisplayHardware/HWC2On1Adapter.h
rename to libs/hwc2on1adapter/include/hwc2on1adapter/HWC2On1Adapter.h
diff --git a/services/surfaceflinger/DisplayHardware/MiniFence.h b/libs/hwc2on1adapter/include/hwc2on1adapter/MiniFence.h
similarity index 100%
rename from services/surfaceflinger/DisplayHardware/MiniFence.h
rename to libs/hwc2on1adapter/include/hwc2on1adapter/MiniFence.h
diff --git a/libs/nativewindow/AHardwareBuffer.cpp b/libs/nativewindow/AHardwareBuffer.cpp
index 3fbab17..e25e909 100644
--- a/libs/nativewindow/AHardwareBuffer.cpp
+++ b/libs/nativewindow/AHardwareBuffer.cpp
@@ -69,7 +69,7 @@
if (err == NO_MEMORY) {
GraphicBuffer::dumpAllocationsToSystemLog();
}
- ALOGE("GraphicBufferAlloc::createGraphicBuffer(w=%u, h=%u, lc=%u) failed (%s), handle=%p",
+ ALOGE("GraphicBuffer(w=%u, h=%u, lc=%u) failed (%s), handle=%p",
desc->width, desc->height, desc->layers, strerror(-err), gbuffer->handle);
return err;
}
@@ -428,6 +428,14 @@
return reinterpret_cast<GraphicBuffer*>(buffer);
}
+const ANativeWindowBuffer* AHardwareBuffer_to_ANativeWindowBuffer(const AHardwareBuffer* buffer) {
+ return AHardwareBuffer_to_GraphicBuffer(buffer)->getNativeBuffer();
+}
+
+ANativeWindowBuffer* AHardwareBuffer_to_ANativeWindowBuffer(AHardwareBuffer* buffer) {
+ return AHardwareBuffer_to_GraphicBuffer(buffer)->getNativeBuffer();
+}
+
AHardwareBuffer* AHardwareBuffer_from_GraphicBuffer(GraphicBuffer* buffer) {
return reinterpret_cast<AHardwareBuffer*>(buffer);
}
diff --git a/libs/nativewindow/include/private/android/AHardwareBufferHelpers.h b/libs/nativewindow/include/private/android/AHardwareBufferHelpers.h
index 612ee80..ee5da84 100644
--- a/libs/nativewindow/include/private/android/AHardwareBufferHelpers.h
+++ b/libs/nativewindow/include/private/android/AHardwareBufferHelpers.h
@@ -28,6 +28,7 @@
#include <stdint.h>
struct AHardwareBuffer;
+struct ANativeWindowBuffer;
namespace android {
@@ -44,8 +45,11 @@
class GraphicBuffer;
const GraphicBuffer* AHardwareBuffer_to_GraphicBuffer(const AHardwareBuffer* buffer);
GraphicBuffer* AHardwareBuffer_to_GraphicBuffer(AHardwareBuffer* buffer);
-AHardwareBuffer* AHardwareBuffer_from_GraphicBuffer(GraphicBuffer* buffer);
+const ANativeWindowBuffer* AHardwareBuffer_to_ANativeWindowBuffer(const AHardwareBuffer* buffer);
+ANativeWindowBuffer* AHardwareBuffer_to_ANativeWindowBuffer(AHardwareBuffer* buffer);
+
+AHardwareBuffer* AHardwareBuffer_from_GraphicBuffer(GraphicBuffer* buffer);
} // namespace android
#endif // ANDROID_PRIVATE_NATIVE_AHARDWARE_BUFFER_HELPERS_H
diff --git a/libs/vr/libdisplay/Android.mk b/libs/vr/libdisplay/Android.mk
index 6a9458c..60f73c6 100644
--- a/libs/vr/libdisplay/Android.mk
+++ b/libs/vr/libdisplay/Android.mk
@@ -15,7 +15,6 @@
LOCAL_PATH := $(call my-dir)
sourceFiles := \
- native_window.cpp \
native_buffer_queue.cpp \
display_client.cpp \
display_manager_client.cpp \
@@ -72,8 +71,7 @@
LOCAL_MODULE := libdisplay
include $(BUILD_STATIC_LIBRARY)
-
-testFiles := \
+graphicsAppTestFiles := \
tests/graphics_app_tests.cpp
include $(CLEAR_VARS)
@@ -81,7 +79,7 @@
LOCAL_MODULE_TAGS := optional
LOCAL_SRC_FILES := \
- $(testFiles) \
+ $(graphicsAppTestFiles) \
LOCAL_C_INCLUDES := \
$(includeFiles) \
@@ -94,3 +92,25 @@
$(staticLibraries) \
include $(BUILD_NATIVE_TEST)
+
+dummyNativeWindowTestFiles := \
+ tests/dummy_native_window_tests.cpp \
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := dummy_native_window_tests
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := \
+ $(dummyNativeWindowTestFiles) \
+
+LOCAL_C_INCLUDES := \
+ $(includeFiles) \
+
+LOCAL_SHARED_LIBRARIES := \
+ $(sharedLibraries) \
+
+LOCAL_STATIC_LIBRARIES := \
+ libdisplay \
+ $(staticLibraries) \
+include $(BUILD_NATIVE_TEST)
+
diff --git a/libs/vr/libdisplay/dummy_native_window.cpp b/libs/vr/libdisplay/dummy_native_window.cpp
index 5547f53..4628b8e 100644
--- a/libs/vr/libdisplay/dummy_native_window.cpp
+++ b/libs/vr/libdisplay/dummy_native_window.cpp
@@ -30,6 +30,11 @@
int DummyNativeWindow::Query(const ANativeWindow*, int what, int* value) {
switch (what) {
+ // This must be 1 in order for eglCreateWindowSurface to not trigger an
+ // error
+ case NATIVE_WINDOW_IS_VALID:
+ *value = 1;
+ return NO_ERROR;
case NATIVE_WINDOW_WIDTH:
case NATIVE_WINDOW_HEIGHT:
case NATIVE_WINDOW_FORMAT:
diff --git a/libs/vr/libdisplay/graphics.cpp b/libs/vr/libdisplay/graphics.cpp
index d0557a9..61f6fea 100644
--- a/libs/vr/libdisplay/graphics.cpp
+++ b/libs/vr/libdisplay/graphics.cpp
@@ -483,25 +483,6 @@
return 0;
}
-extern "C" int dvrGetDisplaySurfaceInfo(EGLNativeWindowType win, int* width,
- int* height, int* format) {
- ANativeWindow* nwin = reinterpret_cast<ANativeWindow*>(win);
- int w, h, f;
-
- nwin->query(nwin, NATIVE_WINDOW_DEFAULT_WIDTH, &w);
- nwin->query(nwin, NATIVE_WINDOW_DEFAULT_HEIGHT, &h);
- nwin->query(nwin, NATIVE_WINDOW_FORMAT, &f);
-
- if (width)
- *width = w;
- if (height)
- *height = h;
- if (format)
- *format = f;
-
- return 0;
-}
-
struct DvrGraphicsContext : public android::ANativeObjectBase<
ANativeWindow, DvrGraphicsContext,
android::LightRefBase<DvrGraphicsContext>> {
diff --git a/libs/vr/libdisplay/include/dvr/graphics.h b/libs/vr/libdisplay/include/dvr/graphics.h
index 50d2754..19deec3 100644
--- a/libs/vr/libdisplay/include/dvr/graphics.h
+++ b/libs/vr/libdisplay/include/dvr/graphics.h
@@ -21,11 +21,6 @@
__BEGIN_DECLS
-// Create a stereo surface that will be lens-warped by the system.
-EGLNativeWindowType dvrCreateWarpedDisplaySurface(int* display_width,
- int* display_height);
-EGLNativeWindowType dvrCreateDisplaySurface(void);
-
// Display surface parameters used to specify display surface options.
enum {
DVR_SURFACE_PARAMETER_NONE = 0,
@@ -163,9 +158,16 @@
float right_fov[4];
};
-// Creates a display surface with the given parameters. The list of parameters
-// is terminated with an entry where key == DVR_SURFACE_PARAMETER_NONE.
-// For example, the parameters array could be built as follows:
+int dvrGetNativeDisplayDimensions(int* native_width, int* native_height);
+
+// Opaque struct that represents a graphics context, the texture swap chain,
+// and surfaces.
+typedef struct DvrGraphicsContext DvrGraphicsContext;
+
+// Create the graphics context. with the given parameters. The list of
+// parameters is terminated with an entry where key ==
+// DVR_SURFACE_PARAMETER_NONE. For example, the parameters array could be built
+// as follows:
// int display_width = 0, display_height = 0;
// int surface_width = 0, surface_height = 0;
// float inter_lens_meters = 0.0f;
@@ -183,38 +185,6 @@
// DVR_SURFACE_PARAMETER_OUT(RIGHT_FOV_LRBT, right_fov),
// DVR_SURFACE_PARAMETER_LIST_END,
// };
-EGLNativeWindowType dvrCreateDisplaySurfaceExtended(
- struct DvrSurfaceParameter* parameters);
-
-int dvrGetNativeDisplayDimensions(int* native_width, int* native_height);
-
-int dvrGetDisplaySurfaceInfo(EGLNativeWindowType win, int* width, int* height,
- int* format);
-
-// NOTE: Only call the functions below on windows created with the API above.
-
-// Sets the display surface visible based on the boolean evaluation of
-// |visible|.
-void dvrDisplaySurfaceSetVisible(EGLNativeWindowType window, int visible);
-
-// Sets the application z-order of the display surface. Higher values display on
-// top of lower values.
-void dvrDisplaySurfaceSetZOrder(EGLNativeWindowType window, int z_order);
-
-// Post the next buffer early. This allows the application to race with either
-// the async EDS process or the scanline for applications that are not using
-// system distortion. When this is called, the next buffer in the queue is
-// posted for display. It is up to the application to kick its GPU rendering
-// work in time. If the rendering is incomplete there will be significant,
-// undesirable tearing artifacts.
-// It is not recommended to use this feature with system distortion.
-void dvrDisplayPostEarly(EGLNativeWindowType window);
-
-// Opaque struct that represents a graphics context, the texture swap chain,
-// and surfaces.
-typedef struct DvrGraphicsContext DvrGraphicsContext;
-
-// Create the graphics context.
int dvrGraphicsContextCreate(struct DvrSurfaceParameter* parameters,
DvrGraphicsContext** return_graphics_context);
diff --git a/libs/vr/libdisplay/native_window.cpp b/libs/vr/libdisplay/native_window.cpp
deleted file mode 100644
index 24ecd8a..0000000
--- a/libs/vr/libdisplay/native_window.cpp
+++ /dev/null
@@ -1,458 +0,0 @@
-#include <EGL/egl.h>
-
-#include <android/native_window.h>
-#include <cutils/native_handle.h>
-#include <errno.h>
-#include <pthread.h>
-#include <semaphore.h>
-#include <stdarg.h>
-#include <string.h>
-#include <sys/timerfd.h>
-#include <system/window.h>
-#include <time.h>
-#include <ui/ANativeObjectBase.h>
-#include <utils/Errors.h>
-
-#define ATRACE_TAG ATRACE_TAG_GRAPHICS
-#include <utils/Trace.h>
-
-#include <log/log.h>
-
-#include <memory>
-#include <mutex>
-
-#include <dvr/graphics.h>
-#include <private/dvr/clock_ns.h>
-#include <private/dvr/display_client.h>
-#include <private/dvr/native_buffer.h>
-#include <private/dvr/native_buffer_queue.h>
-
-namespace {
-
-constexpr int kDefaultDisplaySurfaceUsage =
- GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE;
-constexpr int kDefaultDisplaySurfaceFormat = HAL_PIXEL_FORMAT_RGBA_8888;
-constexpr int kWarpedDisplaySurfaceFlags = 0;
-constexpr int kUnwarpedDisplaySurfaceFlags =
- DVR_DISPLAY_SURFACE_FLAGS_DISABLE_SYSTEM_EDS |
- DVR_DISPLAY_SURFACE_FLAGS_DISABLE_SYSTEM_DISTORTION |
- DVR_DISPLAY_SURFACE_FLAGS_DISABLE_SYSTEM_CAC;
-constexpr int kDefaultBufferCount = 4;
-
-} // anonymous namespace
-
-namespace android {
-namespace dvr {
-
-// NativeWindow is an implementation of ANativeWindow. This class interacts with
-// displayd through the DisplaySurfaceClient and NativeBufferQueue.
-class NativeWindow : public ANativeObjectBase<ANativeWindow, NativeWindow,
- LightRefBase<NativeWindow> > {
- public:
- explicit NativeWindow(const std::shared_ptr<DisplaySurfaceClient>& surface);
-
- void SetVisible(bool visible);
- void SetZOrder(int z_order);
- void PostEarly();
-
- private:
- friend class LightRefBase<NativeWindow>;
-
- void Post(sp<NativeBufferProducer> buffer, int fence_fd);
-
- static int SetSwapInterval(ANativeWindow* window, int interval);
- static int DequeueBuffer(ANativeWindow* window, ANativeWindowBuffer** buffer,
- int* fence_fd);
- static int QueueBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer,
- int fence_fd);
- static int CancelBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer,
- int fence_fd);
- static int Query(const ANativeWindow* window, int what, int* value);
- static int Perform(ANativeWindow* window, int operation, ...);
-
- static int DequeueBuffer_DEPRECATED(ANativeWindow* window,
- ANativeWindowBuffer** buffer);
- static int CancelBuffer_DEPRECATED(ANativeWindow* window,
- ANativeWindowBuffer* buffer);
- static int QueueBuffer_DEPRECATED(ANativeWindow* window,
- ANativeWindowBuffer* buffer);
- static int LockBuffer_DEPRECATED(ANativeWindow* window,
- ANativeWindowBuffer* buffer);
-
- std::shared_ptr<DisplaySurfaceClient> surface_;
-
- std::mutex lock_;
- NativeBufferQueue buffer_queue_;
- sp<NativeBufferProducer> next_post_buffer_;
- bool next_buffer_already_posted_;
-
- NativeWindow(const NativeWindow&) = delete;
- void operator=(NativeWindow&) = delete;
-};
-
-NativeWindow::NativeWindow(const std::shared_ptr<DisplaySurfaceClient>& surface)
- : surface_(surface),
- buffer_queue_(surface, kDefaultBufferCount),
- next_post_buffer_(nullptr),
- next_buffer_already_posted_(false) {
- ANativeWindow::setSwapInterval = SetSwapInterval;
- ANativeWindow::dequeueBuffer = DequeueBuffer;
- ANativeWindow::cancelBuffer = CancelBuffer;
- ANativeWindow::queueBuffer = QueueBuffer;
- ANativeWindow::query = Query;
- ANativeWindow::perform = Perform;
-
- ANativeWindow::dequeueBuffer_DEPRECATED = DequeueBuffer_DEPRECATED;
- ANativeWindow::cancelBuffer_DEPRECATED = CancelBuffer_DEPRECATED;
- ANativeWindow::lockBuffer_DEPRECATED = LockBuffer_DEPRECATED;
- ANativeWindow::queueBuffer_DEPRECATED = QueueBuffer_DEPRECATED;
-}
-
-void NativeWindow::SetVisible(bool visible) { surface_->SetVisible(visible); }
-
-void NativeWindow::SetZOrder(int z_order) { surface_->SetZOrder(z_order); }
-
-void NativeWindow::PostEarly() {
- ATRACE_NAME("NativeWindow::PostEarly");
- ALOGI_IF(TRACE, "NativeWindow::PostEarly");
-
- std::lock_guard<std::mutex> autolock(lock_);
-
- if (!next_buffer_already_posted_) {
- next_buffer_already_posted_ = true;
-
- if (!next_post_buffer_.get()) {
- next_post_buffer_ = buffer_queue_.Dequeue();
- }
- ATRACE_ASYNC_BEGIN("BufferPost", next_post_buffer_->buffer()->id());
- Post(next_post_buffer_, -1);
- }
-}
-
-void NativeWindow::Post(sp<NativeBufferProducer> buffer, int fence_fd) {
- ATRACE_NAME(__PRETTY_FUNCTION__);
- ALOGI_IF(TRACE, "NativeWindow::Post: buffer_id=%d, fence_fd=%d",
- buffer->buffer()->id(), fence_fd);
- ALOGW_IF(!surface_->visible(),
- "NativeWindow::Post: Posting buffer on invisible surface!!!");
- buffer->Post(fence_fd, 0);
-}
-
-int NativeWindow::SetSwapInterval(ANativeWindow* window, int interval) {
- ALOGI_IF(TRACE, "SetSwapInterval: window=%p interval=%d", window, interval);
- return 0;
-}
-
-int NativeWindow::DequeueBuffer(ANativeWindow* window,
- ANativeWindowBuffer** buffer, int* fence_fd) {
- ATRACE_NAME(__PRETTY_FUNCTION__);
-
- NativeWindow* self = getSelf(window);
- std::lock_guard<std::mutex> autolock(self->lock_);
-
- if (!self->next_post_buffer_.get()) {
- self->next_post_buffer_ = self->buffer_queue_.Dequeue();
- }
- ATRACE_ASYNC_BEGIN("BufferDraw", self->next_post_buffer_->buffer()->id());
- *fence_fd = self->next_post_buffer_->ClaimReleaseFence().Release();
- *buffer = self->next_post_buffer_.get();
-
- ALOGI_IF(TRACE, "NativeWindow::DequeueBuffer: fence_fd=%d", *fence_fd);
- return 0;
-}
-
-int NativeWindow::QueueBuffer(ANativeWindow* window,
- ANativeWindowBuffer* buffer, int fence_fd) {
- ATRACE_NAME("NativeWindow::QueueBuffer");
- ALOGI_IF(TRACE, "NativeWindow::QueueBuffer: fence_fd=%d", fence_fd);
-
- NativeWindow* self = getSelf(window);
- std::lock_guard<std::mutex> autolock(self->lock_);
-
- NativeBufferProducer* native_buffer =
- static_cast<NativeBufferProducer*>(buffer);
- ATRACE_ASYNC_END("BufferDraw", native_buffer->buffer()->id());
- bool do_post = true;
- if (self->next_buffer_already_posted_) {
- // Check that the buffer is the one we expect, but handle it if this happens
- // in production by allowing this buffer to post on top of the previous one.
- LOG_FATAL_IF(native_buffer != self->next_post_buffer_.get());
- if (native_buffer == self->next_post_buffer_.get()) {
- do_post = false;
- if (fence_fd >= 0)
- close(fence_fd);
- }
- }
- if (do_post) {
- ATRACE_ASYNC_BEGIN("BufferPost", native_buffer->buffer()->id());
- self->Post(native_buffer, fence_fd);
- }
- self->next_buffer_already_posted_ = false;
- self->next_post_buffer_ = nullptr;
-
- return NO_ERROR;
-}
-
-int NativeWindow::CancelBuffer(ANativeWindow* window,
- ANativeWindowBuffer* buffer, int fence_fd) {
- ATRACE_NAME("NativeWindow::CancelBuffer");
- ALOGI_IF(TRACE, "NativeWindow::CancelBuffer: fence_fd: %d", fence_fd);
-
- NativeWindow* self = getSelf(window);
- std::lock_guard<std::mutex> autolock(self->lock_);
-
- NativeBufferProducer* native_buffer =
- static_cast<NativeBufferProducer*>(buffer);
- ATRACE_ASYNC_END("BufferDraw", native_buffer->buffer()->id());
- ATRACE_INT("CancelBuffer", native_buffer->buffer()->id());
- bool do_enqueue = true;
- if (self->next_buffer_already_posted_) {
- // Check that the buffer is the one we expect, but handle it if this happens
- // in production by returning this buffer to the buffer queue.
- LOG_FATAL_IF(native_buffer != self->next_post_buffer_.get());
- if (native_buffer == self->next_post_buffer_.get()) {
- do_enqueue = false;
- }
- }
- if (do_enqueue) {
- self->buffer_queue_.Enqueue(native_buffer);
- }
- if (fence_fd >= 0)
- close(fence_fd);
- self->next_buffer_already_posted_ = false;
- self->next_post_buffer_ = nullptr;
-
- return NO_ERROR;
-}
-
-int NativeWindow::Query(const ANativeWindow* window, int what, int* value) {
- NativeWindow* self = getSelf(const_cast<ANativeWindow*>(window));
- std::lock_guard<std::mutex> autolock(self->lock_);
-
- switch (what) {
- case NATIVE_WINDOW_WIDTH:
- *value = self->surface_->width();
- return NO_ERROR;
- case NATIVE_WINDOW_HEIGHT:
- *value = self->surface_->height();
- return NO_ERROR;
- case NATIVE_WINDOW_FORMAT:
- *value = self->surface_->format();
- return NO_ERROR;
- case NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS:
- *value = 1;
- return NO_ERROR;
- case NATIVE_WINDOW_CONCRETE_TYPE:
- *value = NATIVE_WINDOW_SURFACE;
- return NO_ERROR;
- case NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER:
- *value = 1;
- return NO_ERROR;
- case NATIVE_WINDOW_DEFAULT_WIDTH:
- *value = self->surface_->width();
- return NO_ERROR;
- case NATIVE_WINDOW_DEFAULT_HEIGHT:
- *value = self->surface_->height();
- return NO_ERROR;
- case NATIVE_WINDOW_TRANSFORM_HINT:
- *value = 0;
- return NO_ERROR;
- }
-
- *value = 0;
- return BAD_VALUE;
-}
-
-int NativeWindow::Perform(ANativeWindow* window, int operation, ...) {
- NativeWindow* self = getSelf(window);
- std::lock_guard<std::mutex> autolock(self->lock_);
-
- va_list args;
- va_start(args, operation);
-
- // TODO(eieio): The following operations are not used at this time. They are
- // included here to help document which operations may be useful and what
- // parameters they take.
- switch (operation) {
- case NATIVE_WINDOW_SET_BUFFERS_DIMENSIONS: {
- int w = va_arg(args, int);
- int h = va_arg(args, int);
- ALOGD_IF(TRACE, "NATIVE_WINDOW_SET_BUFFERS_DIMENSIONS: w=%d h=%d", w, h);
- return NO_ERROR;
- }
-
- case NATIVE_WINDOW_SET_BUFFERS_FORMAT: {
- int format = va_arg(args, int);
- ALOGD_IF(TRACE, "NATIVE_WINDOW_SET_BUFFERS_FORMAT: format=%d", format);
- return NO_ERROR;
- }
-
- case NATIVE_WINDOW_SET_BUFFERS_TRANSFORM: {
- int transform = va_arg(args, int);
- ALOGD_IF(TRACE, "NATIVE_WINDOW_SET_BUFFERS_TRANSFORM: transform=%d",
- transform);
- return NO_ERROR;
- }
-
- case NATIVE_WINDOW_SET_USAGE: {
- int usage = va_arg(args, int);
- ALOGD_IF(TRACE, "NATIVE_WINDOW_SET_USAGE: usage=%d", usage);
- return NO_ERROR;
- }
-
- case NATIVE_WINDOW_CONNECT:
- case NATIVE_WINDOW_DISCONNECT:
- case NATIVE_WINDOW_SET_BUFFERS_GEOMETRY:
- case NATIVE_WINDOW_API_CONNECT:
- case NATIVE_WINDOW_API_DISCONNECT:
- // TODO(eieio): we should implement these
- return NO_ERROR;
-
- case NATIVE_WINDOW_SET_BUFFER_COUNT: {
- int buffer_count = va_arg(args, int);
- ALOGD_IF(TRACE, "NATIVE_WINDOW_SET_BUFFER_COUNT: bufferCount=%d",
- buffer_count);
- return NO_ERROR;
- }
- case NATIVE_WINDOW_SET_BUFFERS_DATASPACE: {
- android_dataspace_t data_space =
- static_cast<android_dataspace_t>(va_arg(args, int));
- ALOGD_IF(TRACE, "NATIVE_WINDOW_SET_BUFFERS_DATASPACE: dataSpace=%d",
- data_space);
- return NO_ERROR;
- }
- case NATIVE_WINDOW_SET_SCALING_MODE: {
- int mode = va_arg(args, int);
- ALOGD_IF(TRACE, "NATIVE_WINDOW_SET_SCALING_MODE: mode=%d", mode);
- return NO_ERROR;
- }
-
- case NATIVE_WINDOW_LOCK:
- case NATIVE_WINDOW_UNLOCK_AND_POST:
- case NATIVE_WINDOW_SET_CROP:
- case NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP:
- return INVALID_OPERATION;
- }
-
- return NAME_NOT_FOUND;
-}
-
-int NativeWindow::DequeueBuffer_DEPRECATED(ANativeWindow* window,
- ANativeWindowBuffer** buffer) {
- int fence_fd = -1;
- int ret = DequeueBuffer(window, buffer, &fence_fd);
-
- // wait for fence
- if (ret == NO_ERROR && fence_fd != -1)
- close(fence_fd);
-
- return ret;
-}
-
-int NativeWindow::CancelBuffer_DEPRECATED(ANativeWindow* window,
- ANativeWindowBuffer* buffer) {
- return CancelBuffer(window, buffer, -1);
-}
-
-int NativeWindow::QueueBuffer_DEPRECATED(ANativeWindow* window,
- ANativeWindowBuffer* buffer) {
- return QueueBuffer(window, buffer, -1);
-}
-
-int NativeWindow::LockBuffer_DEPRECATED(ANativeWindow* /*window*/,
- ANativeWindowBuffer* /*buffer*/) {
- return NO_ERROR;
-}
-
-} // namespace dvr
-} // namespace android
-
-static EGLNativeWindowType CreateDisplaySurface(int* display_width,
- int* display_height, int format,
- int usage, int flags) {
- auto client = android::dvr::DisplayClient::Create();
- if (!client) {
- ALOGE("Failed to create display client!");
- return nullptr;
- }
-
- // TODO(eieio,jbates): Consider passing flags and other parameters to get
- // metrics based on specific surface requirements.
- android::dvr::SystemDisplayMetrics metrics;
- const int ret = client->GetDisplayMetrics(&metrics);
- if (ret < 0) {
- ALOGE("Failed to get display metrics: %s", strerror(-ret));
- return nullptr;
- }
-
- int width, height;
-
- if (flags & DVR_DISPLAY_SURFACE_FLAGS_DISABLE_SYSTEM_DISTORTION) {
- width = metrics.display_native_width;
- height = metrics.display_native_height;
- } else {
- width = metrics.distorted_width;
- height = metrics.distorted_height;
- }
-
- std::shared_ptr<android::dvr::DisplaySurfaceClient> surface =
- client->CreateDisplaySurface(width, height, format, usage, flags);
-
- if (display_width)
- *display_width = metrics.display_native_width;
- if (display_height)
- *display_height = metrics.display_native_height;
-
- // Set the surface visible by default.
- // TODO(eieio,jbates): Remove this from here and set visible somewhere closer
- // to the application to account for situations where the application wants to
- // create surfaces that will be used later or shouldn't be visible yet.
- surface->SetVisible(true);
-
- return new android::dvr::NativeWindow(surface);
-}
-
-std::shared_ptr<android::dvr::DisplaySurfaceClient> CreateDisplaySurfaceClient(
- struct DvrSurfaceParameter* parameters,
- /*out*/ android::dvr::SystemDisplayMetrics* metrics);
-
-extern "C" EGLNativeWindowType dvrCreateDisplaySurfaceExtended(
- struct DvrSurfaceParameter* parameters) {
- android::dvr::SystemDisplayMetrics metrics;
- auto surface = CreateDisplaySurfaceClient(parameters, &metrics);
- if (!surface) {
- ALOGE("Failed to create display surface client");
- return nullptr;
- }
- return new android::dvr::NativeWindow(surface);
-}
-
-extern "C" EGLNativeWindowType dvrCreateDisplaySurface() {
- return CreateDisplaySurface(NULL, NULL, kDefaultDisplaySurfaceFormat,
- kDefaultDisplaySurfaceUsage,
- kUnwarpedDisplaySurfaceFlags);
-}
-
-extern "C" EGLNativeWindowType dvrCreateWarpedDisplaySurface(
- int* display_width, int* display_height) {
- return CreateDisplaySurface(
- display_width, display_height, kDefaultDisplaySurfaceFormat,
- kDefaultDisplaySurfaceUsage, kWarpedDisplaySurfaceFlags);
-}
-
-extern "C" void dvrDisplaySurfaceSetVisible(EGLNativeWindowType window,
- int visible) {
- auto native_window = reinterpret_cast<android::dvr::NativeWindow*>(window);
- native_window->SetVisible(visible);
-}
-
-extern "C" void dvrDisplaySurfaceSetZOrder(EGLNativeWindowType window,
- int z_order) {
- auto native_window = reinterpret_cast<android::dvr::NativeWindow*>(window);
- native_window->SetZOrder(z_order);
-}
-
-extern "C" void dvrDisplayPostEarly(EGLNativeWindowType window) {
- auto native_window = reinterpret_cast<android::dvr::NativeWindow*>(window);
- native_window->PostEarly();
-}
diff --git a/libs/vr/libdisplay/native_window_test.cpp b/libs/vr/libdisplay/native_window_test.cpp
deleted file mode 100644
index 2f3bc33..0000000
--- a/libs/vr/libdisplay/native_window_test.cpp
+++ /dev/null
@@ -1,43 +0,0 @@
-#include <iostream>
-#include <memory>
-
-#include <gmock/gmock.h>
-#include <gtest/gtest.h>
-
-#include <dvr/graphics.h>
-#include <private/dvr/display_client.h>
-
-#include <cpp_free_mock/cpp_free_mock.h>
-
-// Checks querying the VSync of the device on display surface creation.
-TEST(CreateDisplaySurface, QueryVSyncPeriod) {
- using ::testing::_;
-
- const uint64_t kExpectedVSync = 123456;
-
- // We only care about the expected VSync value
- android::dvr::DisplayMetrics metrics;
- metrics.vsync_period_ns = kExpectedVSync;
-
- uint64_t outPeriod;
-
- DvrSurfaceParameter display_params[] = {
- DVR_SURFACE_PARAMETER_IN(WIDTH, 256),
- DVR_SURFACE_PARAMETER_IN(HEIGHT, 256),
- DVR_SURFACE_PARAMETER_OUT(VSYNC_PERIOD, &outPeriod),
- DVR_SURFACE_PARAMETER_LIST_END,
- };
-
- // inject the mocking code to the target method
- auto mocked_function =
- MOCKER(&android::dvr::DisplayClient::GetDisplayMetrics);
-
- // instrument the mock function to return our custom metrics
- EXPECT_CALL(*mocked_function, MOCK_FUNCTION(_, _))
- .WillOnce(::testing::DoAll(::testing::SetArgPointee<1>(metrics),
- ::testing::Return(0)));
-
- ASSERT_NE(nullptr, dvrCreateDisplaySurfaceExtended(display_params));
-
- EXPECT_EQ(kExpectedVSync, outPeriod);
-}
diff --git a/libs/vr/libdisplay/tests/dummy_native_window_tests.cpp b/libs/vr/libdisplay/tests/dummy_native_window_tests.cpp
new file mode 100644
index 0000000..5f3ff53
--- /dev/null
+++ b/libs/vr/libdisplay/tests/dummy_native_window_tests.cpp
@@ -0,0 +1,64 @@
+#include <private/dvr/dummy_native_window.h>
+#include <gtest/gtest.h>
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+#include <GLES2/gl2.h>
+
+class DummyNativeWindowTests : public ::testing::Test {
+ public:
+ EGLDisplay display_;
+ bool initialized_;
+
+ DummyNativeWindowTests()
+ : display_(nullptr)
+ , initialized_(false)
+ {
+ }
+
+ virtual void SetUp() {
+ display_ = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+
+ ASSERT_NE(nullptr, display_);
+ initialized_ = eglInitialize(display_, nullptr, nullptr);
+
+ ASSERT_TRUE(initialized_);
+ }
+
+ virtual void TearDown() {
+ if (display_ && initialized_) {
+ eglTerminate(display_);
+ }
+ }
+};
+
+// Test that eglCreateWindowSurface works with DummyNativeWindow
+TEST_F(DummyNativeWindowTests, TryCreateEglWindow) {
+ EGLint attribs[] = {
+ EGL_NONE,
+ };
+
+ EGLint num_configs;
+ EGLConfig config;
+ ASSERT_TRUE(eglChooseConfig(display_, attribs, &config, 1, &num_configs));
+
+ std::unique_ptr<android::dvr::DummyNativeWindow> dummy_window(
+ new android::dvr::DummyNativeWindow());
+
+ EGLint context_attribs[] = {
+ EGL_NONE,
+ };
+
+ EGLSurface surface = eglCreateWindowSurface(display_, config,
+ dummy_window.get(),
+ context_attribs);
+
+ EXPECT_NE(nullptr, surface);
+
+ bool destroyed = eglDestroySurface(display_, surface);
+
+ EXPECT_TRUE(destroyed);
+}
+
diff --git a/libs/vr/libdisplay/tests/graphics_app_tests.cpp b/libs/vr/libdisplay/tests/graphics_app_tests.cpp
index 7ea3952..f51dd8a 100644
--- a/libs/vr/libdisplay/tests/graphics_app_tests.cpp
+++ b/libs/vr/libdisplay/tests/graphics_app_tests.cpp
@@ -1,55 +1,6 @@
#include <dvr/graphics.h>
#include <gtest/gtest.h>
-TEST(GraphicsAppTests, CreateWarpedDisplaySurfaceParams) {
- int width = 0, height = 0;
- EGLNativeWindowType window = dvrCreateWarpedDisplaySurface(&width, &height);
- EXPECT_GT(width, 0);
- EXPECT_GT(height, 0);
- EXPECT_NE(window, nullptr);
-}
-
-TEST(GraphicsAppTests, CreateDisplaySurface) {
- EGLNativeWindowType window = dvrCreateDisplaySurface();
- EXPECT_NE(window, nullptr);
-}
-
-TEST(GraphicsAppTests, CreateDisplaySurfaceExtended) {
- int display_width = 0, display_height = 0;
- int surface_width = 0, surface_height = 0;
- float inter_lens_meters = 0.0f;
- float left_fov[4] = {0.0f};
- float right_fov[4] = {0.0f};
- int disable_warp = 0;
- DvrSurfaceParameter surface_params[] = {
- DVR_SURFACE_PARAMETER_IN(DISABLE_DISTORTION, disable_warp),
- DVR_SURFACE_PARAMETER_OUT(DISPLAY_WIDTH, &display_width),
- DVR_SURFACE_PARAMETER_OUT(DISPLAY_HEIGHT, &display_height),
- DVR_SURFACE_PARAMETER_OUT(SURFACE_WIDTH, &surface_width),
- DVR_SURFACE_PARAMETER_OUT(SURFACE_HEIGHT, &surface_height),
- DVR_SURFACE_PARAMETER_OUT(INTER_LENS_METERS, &inter_lens_meters),
- DVR_SURFACE_PARAMETER_OUT(LEFT_FOV_LRBT, left_fov),
- DVR_SURFACE_PARAMETER_OUT(RIGHT_FOV_LRBT, right_fov),
- DVR_SURFACE_PARAMETER_LIST_END,
- };
-
- EGLNativeWindowType window = dvrCreateDisplaySurfaceExtended(surface_params);
- EXPECT_NE(window, nullptr);
- EXPECT_GT(display_width, 0);
- EXPECT_GT(display_height, 0);
- EXPECT_GT(surface_width, 0);
- EXPECT_GT(surface_height, 0);
- EXPECT_GT(inter_lens_meters, 0);
- EXPECT_GT(left_fov[0], 0);
- EXPECT_GT(left_fov[1], 0);
- EXPECT_GT(left_fov[2], 0);
- EXPECT_GT(left_fov[3], 0);
- EXPECT_GT(right_fov[0], 0);
- EXPECT_GT(right_fov[1], 0);
- EXPECT_GT(right_fov[2], 0);
- EXPECT_GT(right_fov[3], 0);
-}
-
TEST(GraphicsAppTests, GetNativeDisplayDimensions) {
int width, height;
dvrGetNativeDisplayDimensions(&width, &height);
@@ -57,17 +8,6 @@
EXPECT_GT(height, 0);
}
-TEST(GraphicsAppTests, GetDisplaySurfaceInfo) {
- int ret, width, height, format;
- EGLNativeWindowType window = dvrCreateDisplaySurface();
- ASSERT_NE(window, nullptr);
- ret = dvrGetDisplaySurfaceInfo(window, &width, &height, &format);
- ASSERT_EQ(0, ret);
- ASSERT_GT(width, 0);
- ASSERT_GT(height, 0);
- ASSERT_NE(0, format);
-}
-
// TODO(jpoichet) How to check it worked?
TEST(GraphicsAppTests, GraphicsSurfaceSetVisible) {
DvrSurfaceParameter surface_params[] = {DVR_SURFACE_PARAMETER_LIST_END};
diff --git a/opengl/libs/Android.bp b/opengl/libs/Android.bp
index 4fa6a33..aa67d41 100644
--- a/opengl/libs/Android.bp
+++ b/opengl/libs/Android.bp
@@ -77,7 +77,6 @@
"-DLOG_TAG=\"libEGL\"",
],
shared_libs: [
- "libbinder",
"libutils",
"libui",
"libnativewindow",
@@ -106,9 +105,20 @@
"EGL/egl.cpp",
"EGL/eglApi.cpp",
"EGL/Loader.cpp",
+ "EGL/BlobCache.cpp",
],
static_libs: ["libEGL_getProcAddress"],
ldflags: ["-Wl,--exclude-libs=ALL"],
+ export_include_dirs: ["EGL/include"],
+}
+
+cc_test {
+ name: "libEGL_test",
+ defaults: ["egl_libs_defaults"],
+ srcs: [
+ "EGL/BlobCache.cpp",
+ "EGL/BlobCache_test.cpp",
+ ],
}
cc_defaults {
diff --git a/opengl/libs/EGL/BlobCache.cpp b/opengl/libs/EGL/BlobCache.cpp
new file mode 100644
index 0000000..f1b30c7
--- /dev/null
+++ b/opengl/libs/EGL/BlobCache.cpp
@@ -0,0 +1,373 @@
+/*
+ ** Copyright 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.
+ */
+
+//#define LOG_NDEBUG 0
+
+#include "BlobCache.h"
+
+#include <inttypes.h>
+
+#include <cutils/properties.h>
+#include <log/log.h>
+#include <chrono>
+
+namespace android {
+
+// BlobCache::Header::mMagicNumber value
+static const uint32_t blobCacheMagic = ('_' << 24) + ('B' << 16) + ('b' << 8) + '$';
+
+// BlobCache::Header::mBlobCacheVersion value
+static const uint32_t blobCacheVersion = 3;
+
+// BlobCache::Header::mDeviceVersion value
+static const uint32_t blobCacheDeviceVersion = 1;
+
+BlobCache::BlobCache(size_t maxKeySize, size_t maxValueSize, size_t maxTotalSize):
+ mMaxKeySize(maxKeySize),
+ mMaxValueSize(maxValueSize),
+ mMaxTotalSize(maxTotalSize),
+ mTotalSize(0) {
+ int64_t now = std::chrono::steady_clock::now().time_since_epoch().count();
+#ifdef _WIN32
+ srand(now);
+#else
+ mRandState[0] = (now >> 0) & 0xFFFF;
+ mRandState[1] = (now >> 16) & 0xFFFF;
+ mRandState[2] = (now >> 32) & 0xFFFF;
+#endif
+ ALOGV("initializing random seed using %lld", (unsigned long long)now);
+}
+
+void BlobCache::set(const void* key, size_t keySize, const void* value,
+ size_t valueSize) {
+ if (mMaxKeySize < keySize) {
+ ALOGV("set: not caching because the key is too large: %zu (limit: %zu)",
+ keySize, mMaxKeySize);
+ return;
+ }
+ if (mMaxValueSize < valueSize) {
+ ALOGV("set: not caching because the value is too large: %zu (limit: %zu)",
+ valueSize, mMaxValueSize);
+ return;
+ }
+ if (mMaxTotalSize < keySize + valueSize) {
+ ALOGV("set: not caching because the combined key/value size is too "
+ "large: %zu (limit: %zu)", keySize + valueSize, mMaxTotalSize);
+ return;
+ }
+ if (keySize == 0) {
+ ALOGW("set: not caching because keySize is 0");
+ return;
+ }
+ if (valueSize <= 0) {
+ ALOGW("set: not caching because valueSize is 0");
+ return;
+ }
+
+ std::shared_ptr<Blob> dummyKey(new Blob(key, keySize, false));
+ CacheEntry dummyEntry(dummyKey, NULL);
+
+ while (true) {
+ auto index = std::lower_bound(mCacheEntries.begin(), mCacheEntries.end(), dummyEntry);
+ if (index == mCacheEntries.end() || dummyEntry < *index) {
+ // Create a new cache entry.
+ std::shared_ptr<Blob> keyBlob(new Blob(key, keySize, true));
+ std::shared_ptr<Blob> valueBlob(new Blob(value, valueSize, true));
+ size_t newTotalSize = mTotalSize + keySize + valueSize;
+ if (mMaxTotalSize < newTotalSize) {
+ if (isCleanable()) {
+ // Clean the cache and try again.
+ clean();
+ continue;
+ } else {
+ ALOGV("set: not caching new key/value pair because the "
+ "total cache size limit would be exceeded: %zu "
+ "(limit: %zu)",
+ keySize + valueSize, mMaxTotalSize);
+ break;
+ }
+ }
+ mCacheEntries.insert(index, CacheEntry(keyBlob, valueBlob));
+ mTotalSize = newTotalSize;
+ ALOGV("set: created new cache entry with %zu byte key and %zu byte value",
+ keySize, valueSize);
+ } else {
+ // Update the existing cache entry.
+ std::shared_ptr<Blob> valueBlob(new Blob(value, valueSize, true));
+ std::shared_ptr<Blob> oldValueBlob(index->getValue());
+ size_t newTotalSize = mTotalSize + valueSize - oldValueBlob->getSize();
+ if (mMaxTotalSize < newTotalSize) {
+ if (isCleanable()) {
+ // Clean the cache and try again.
+ clean();
+ continue;
+ } else {
+ ALOGV("set: not caching new value because the total cache "
+ "size limit would be exceeded: %zu (limit: %zu)",
+ keySize + valueSize, mMaxTotalSize);
+ break;
+ }
+ }
+ index->setValue(valueBlob);
+ mTotalSize = newTotalSize;
+ ALOGV("set: updated existing cache entry with %zu byte key and %zu byte "
+ "value", keySize, valueSize);
+ }
+ break;
+ }
+}
+
+size_t BlobCache::get(const void* key, size_t keySize, void* value,
+ size_t valueSize) {
+ if (mMaxKeySize < keySize) {
+ ALOGV("get: not searching because the key is too large: %zu (limit %zu)",
+ keySize, mMaxKeySize);
+ return 0;
+ }
+ std::shared_ptr<Blob> dummyKey(new Blob(key, keySize, false));
+ CacheEntry dummyEntry(dummyKey, NULL);
+ auto index = std::lower_bound(mCacheEntries.begin(), mCacheEntries.end(), dummyEntry);
+ if (index == mCacheEntries.end() || dummyEntry < *index) {
+ ALOGV("get: no cache entry found for key of size %zu", keySize);
+ return 0;
+ }
+
+ // The key was found. Return the value if the caller's buffer is large
+ // enough.
+ std::shared_ptr<Blob> valueBlob(index->getValue());
+ size_t valueBlobSize = valueBlob->getSize();
+ if (valueBlobSize <= valueSize) {
+ ALOGV("get: copying %zu bytes to caller's buffer", valueBlobSize);
+ memcpy(value, valueBlob->getData(), valueBlobSize);
+ } else {
+ ALOGV("get: caller's buffer is too small for value: %zu (needs %zu)",
+ valueSize, valueBlobSize);
+ }
+ return valueBlobSize;
+}
+
+static inline size_t align4(size_t size) {
+ return (size + 3) & ~3;
+}
+
+size_t BlobCache::getFlattenedSize() const {
+ size_t size = align4(sizeof(Header) + PROPERTY_VALUE_MAX);
+ for (const CacheEntry& e : mCacheEntries) {
+ std::shared_ptr<Blob> const& keyBlob = e.getKey();
+ std::shared_ptr<Blob> const& valueBlob = e.getValue();
+ size += align4(sizeof(EntryHeader) + keyBlob->getSize() + valueBlob->getSize());
+ }
+ return size;
+}
+
+int BlobCache::flatten(void* buffer, size_t size) const {
+ // Write the cache header
+ if (size < sizeof(Header)) {
+ ALOGE("flatten: not enough room for cache header");
+ return 0;
+ }
+ Header* header = reinterpret_cast<Header*>(buffer);
+ header->mMagicNumber = blobCacheMagic;
+ header->mBlobCacheVersion = blobCacheVersion;
+ header->mDeviceVersion = blobCacheDeviceVersion;
+ header->mNumEntries = mCacheEntries.size();
+ char buildId[PROPERTY_VALUE_MAX];
+ header->mBuildIdLength = property_get("ro.build.id", buildId, "");
+ memcpy(header->mBuildId, buildId, header->mBuildIdLength);
+
+ // Write cache entries
+ uint8_t* byteBuffer = reinterpret_cast<uint8_t*>(buffer);
+ off_t byteOffset = align4(sizeof(Header) + header->mBuildIdLength);
+ for (const CacheEntry& e : mCacheEntries) {
+ std::shared_ptr<Blob> const& keyBlob = e.getKey();
+ std::shared_ptr<Blob> const& valueBlob = e.getValue();
+ size_t keySize = keyBlob->getSize();
+ size_t valueSize = valueBlob->getSize();
+
+ size_t entrySize = sizeof(EntryHeader) + keySize + valueSize;
+ size_t totalSize = align4(entrySize);
+ if (byteOffset + totalSize > size) {
+ ALOGE("flatten: not enough room for cache entries");
+ return -EINVAL;
+ }
+
+ EntryHeader* eheader = reinterpret_cast<EntryHeader*>(&byteBuffer[byteOffset]);
+ eheader->mKeySize = keySize;
+ eheader->mValueSize = valueSize;
+
+ memcpy(eheader->mData, keyBlob->getData(), keySize);
+ memcpy(eheader->mData + keySize, valueBlob->getData(), valueSize);
+
+ if (totalSize > entrySize) {
+ // We have padding bytes. Those will get written to storage, and contribute to the CRC,
+ // so make sure we zero-them to have reproducible results.
+ memset(eheader->mData + keySize + valueSize, 0, totalSize - entrySize);
+ }
+
+ byteOffset += totalSize;
+ }
+
+ return 0;
+}
+
+int BlobCache::unflatten(void const* buffer, size_t size) {
+ // All errors should result in the BlobCache being in an empty state.
+ mCacheEntries.clear();
+
+ // Read the cache header
+ if (size < sizeof(Header)) {
+ ALOGE("unflatten: not enough room for cache header");
+ return -EINVAL;
+ }
+ const Header* header = reinterpret_cast<const Header*>(buffer);
+ if (header->mMagicNumber != blobCacheMagic) {
+ ALOGE("unflatten: bad magic number: %" PRIu32, header->mMagicNumber);
+ return -EINVAL;
+ }
+ char buildId[PROPERTY_VALUE_MAX];
+ int len = property_get("ro.build.id", buildId, "");
+ if (header->mBlobCacheVersion != blobCacheVersion ||
+ header->mDeviceVersion != blobCacheDeviceVersion ||
+ len != header->mBuildIdLength ||
+ strncmp(buildId, header->mBuildId, len)) {
+ // We treat version mismatches as an empty cache.
+ return 0;
+ }
+
+ // Read cache entries
+ const uint8_t* byteBuffer = reinterpret_cast<const uint8_t*>(buffer);
+ off_t byteOffset = align4(sizeof(Header) + header->mBuildIdLength);
+ size_t numEntries = header->mNumEntries;
+ for (size_t i = 0; i < numEntries; i++) {
+ if (byteOffset + sizeof(EntryHeader) > size) {
+ mCacheEntries.clear();
+ ALOGE("unflatten: not enough room for cache entry headers");
+ return -EINVAL;
+ }
+
+ const EntryHeader* eheader = reinterpret_cast<const EntryHeader*>(
+ &byteBuffer[byteOffset]);
+ size_t keySize = eheader->mKeySize;
+ size_t valueSize = eheader->mValueSize;
+ size_t entrySize = sizeof(EntryHeader) + keySize + valueSize;
+
+ size_t totalSize = align4(entrySize);
+ if (byteOffset + totalSize > size) {
+ mCacheEntries.clear();
+ ALOGE("unflatten: not enough room for cache entry headers");
+ return -EINVAL;
+ }
+
+ const uint8_t* data = eheader->mData;
+ set(data, keySize, data + keySize, valueSize);
+
+ byteOffset += totalSize;
+ }
+
+ return 0;
+}
+
+long int BlobCache::blob_random() {
+#ifdef _WIN32
+ return rand();
+#else
+ return nrand48(mRandState);
+#endif
+}
+
+void BlobCache::clean() {
+ // Remove a random cache entry until the total cache size gets below half
+ // the maximum total cache size.
+ while (mTotalSize > mMaxTotalSize / 2) {
+ size_t i = size_t(blob_random() % (mCacheEntries.size()));
+ const CacheEntry& entry(mCacheEntries[i]);
+ mTotalSize -= entry.getKey()->getSize() + entry.getValue()->getSize();
+ mCacheEntries.erase(mCacheEntries.begin() + i);
+ }
+}
+
+bool BlobCache::isCleanable() const {
+ return mTotalSize > mMaxTotalSize / 2;
+}
+
+BlobCache::Blob::Blob(const void* data, size_t size, bool copyData) :
+ mData(copyData ? malloc(size) : data),
+ mSize(size),
+ mOwnsData(copyData) {
+ if (data != NULL && copyData) {
+ memcpy(const_cast<void*>(mData), data, size);
+ }
+}
+
+BlobCache::Blob::~Blob() {
+ if (mOwnsData) {
+ free(const_cast<void*>(mData));
+ }
+}
+
+bool BlobCache::Blob::operator<(const Blob& rhs) const {
+ if (mSize == rhs.mSize) {
+ return memcmp(mData, rhs.mData, mSize) < 0;
+ } else {
+ return mSize < rhs.mSize;
+ }
+}
+
+const void* BlobCache::Blob::getData() const {
+ return mData;
+}
+
+size_t BlobCache::Blob::getSize() const {
+ return mSize;
+}
+
+BlobCache::CacheEntry::CacheEntry() {
+}
+
+BlobCache::CacheEntry::CacheEntry(
+ const std::shared_ptr<Blob>& key, const std::shared_ptr<Blob>& value):
+ mKey(key),
+ mValue(value) {
+}
+
+BlobCache::CacheEntry::CacheEntry(const CacheEntry& ce):
+ mKey(ce.mKey),
+ mValue(ce.mValue) {
+}
+
+bool BlobCache::CacheEntry::operator<(const CacheEntry& rhs) const {
+ return *mKey < *rhs.mKey;
+}
+
+const BlobCache::CacheEntry& BlobCache::CacheEntry::operator=(const CacheEntry& rhs) {
+ mKey = rhs.mKey;
+ mValue = rhs.mValue;
+ return *this;
+}
+
+std::shared_ptr<BlobCache::Blob> BlobCache::CacheEntry::getKey() const {
+ return mKey;
+}
+
+std::shared_ptr<BlobCache::Blob> BlobCache::CacheEntry::getValue() const {
+ return mValue;
+}
+
+void BlobCache::CacheEntry::setValue(const std::shared_ptr<Blob>& value) {
+ mValue = value;
+}
+
+} // namespace android
diff --git a/opengl/libs/EGL/BlobCache.h b/opengl/libs/EGL/BlobCache.h
new file mode 100644
index 0000000..a0a270a
--- /dev/null
+++ b/opengl/libs/EGL/BlobCache.h
@@ -0,0 +1,245 @@
+/*
+ ** Copyright 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.
+ */
+
+#ifndef ANDROID_BLOB_CACHE_H
+#define ANDROID_BLOB_CACHE_H
+
+#include <stddef.h>
+
+#include <memory>
+#include <vector>
+
+namespace android {
+
+// A BlobCache is an in-memory cache for binary key/value pairs. A BlobCache
+// does NOT provide any thread-safety guarantees.
+//
+// The cache contents can be serialized to an in-memory buffer or mmap'd file
+// and then reloaded in a subsequent execution of the program. This
+// serialization is non-portable and the data should only be used by the device
+// that generated it.
+class BlobCache {
+public:
+ // Create an empty blob cache. The blob cache will cache key/value pairs
+ // with key and value sizes less than or equal to maxKeySize and
+ // maxValueSize, respectively. The total combined size of ALL cache entries
+ // (key sizes plus value sizes) will not exceed maxTotalSize.
+ BlobCache(size_t maxKeySize, size_t maxValueSize, size_t maxTotalSize);
+
+ // set inserts a new binary value into the cache and associates it with the
+ // given binary key. If the key or value are too large for the cache then
+ // the cache remains unchanged. This includes the case where a different
+ // value was previously associated with the given key - the old value will
+ // remain in the cache. If the given key and value are small enough to be
+ // put in the cache (based on the maxKeySize, maxValueSize, and maxTotalSize
+ // values specified to the BlobCache constructor), then the key/value pair
+ // will be in the cache after set returns. Note, however, that a subsequent
+ // call to set may evict old key/value pairs from the cache.
+ //
+ // Preconditions:
+ // key != NULL
+ // 0 < keySize
+ // value != NULL
+ // 0 < valueSize
+ void set(const void* key, size_t keySize, const void* value,
+ size_t valueSize);
+
+ // get retrieves from the cache the binary value associated with a given
+ // binary key. If the key is present in the cache then the length of the
+ // binary value associated with that key is returned. If the value argument
+ // is non-NULL and the size of the cached value is less than valueSize bytes
+ // then the cached value is copied into the buffer pointed to by the value
+ // argument. If the key is not present in the cache then 0 is returned and
+ // the buffer pointed to by the value argument is not modified.
+ //
+ // Note that when calling get multiple times with the same key, the later
+ // calls may fail, returning 0, even if earlier calls succeeded. The return
+ // value must be checked for each call.
+ //
+ // Preconditions:
+ // key != NULL
+ // 0 < keySize
+ // 0 <= valueSize
+ size_t get(const void* key, size_t keySize, void* value, size_t valueSize);
+
+
+ // getFlattenedSize returns the number of bytes needed to store the entire
+ // serialized cache.
+ size_t getFlattenedSize() const;
+
+ // flatten serializes the current contents of the cache into the memory
+ // pointed to by 'buffer'. The serialized cache contents can later be
+ // loaded into a BlobCache object using the unflatten method. The contents
+ // of the BlobCache object will not be modified.
+ //
+ // Preconditions:
+ // size >= this.getFlattenedSize()
+ int flatten(void* buffer, size_t size) const;
+
+ // unflatten replaces the contents of the cache with the serialized cache
+ // contents in the memory pointed to by 'buffer'. The previous contents of
+ // the BlobCache will be evicted from the cache. If an error occurs while
+ // unflattening the serialized cache contents then the BlobCache will be
+ // left in an empty state.
+ //
+ int unflatten(void const* buffer, size_t size);
+
+private:
+ // Copying is disallowed.
+ BlobCache(const BlobCache&);
+ void operator=(const BlobCache&);
+
+ // A random function helper to get around MinGW not having nrand48()
+ long int blob_random();
+
+ // clean evicts a randomly chosen set of entries from the cache such that
+ // the total size of all remaining entries is less than mMaxTotalSize/2.
+ void clean();
+
+ // isCleanable returns true if the cache is full enough for the clean method
+ // to have some effect, and false otherwise.
+ bool isCleanable() const;
+
+ // A Blob is an immutable sized unstructured data blob.
+ class Blob {
+ public:
+ Blob(const void* data, size_t size, bool copyData);
+ ~Blob();
+
+ bool operator<(const Blob& rhs) const;
+
+ const void* getData() const;
+ size_t getSize() const;
+
+ private:
+ // Copying is not allowed.
+ Blob(const Blob&);
+ void operator=(const Blob&);
+
+ // mData points to the buffer containing the blob data.
+ const void* mData;
+
+ // mSize is the size of the blob data in bytes.
+ size_t mSize;
+
+ // mOwnsData indicates whether or not this Blob object should free the
+ // memory pointed to by mData when the Blob gets destructed.
+ bool mOwnsData;
+ };
+
+ // A CacheEntry is a single key/value pair in the cache.
+ class CacheEntry {
+ public:
+ CacheEntry();
+ CacheEntry(const std::shared_ptr<Blob>& key, const std::shared_ptr<Blob>& value);
+ CacheEntry(const CacheEntry& ce);
+
+ bool operator<(const CacheEntry& rhs) const;
+ const CacheEntry& operator=(const CacheEntry&);
+
+ std::shared_ptr<Blob> getKey() const;
+ std::shared_ptr<Blob> getValue() const;
+
+ void setValue(const std::shared_ptr<Blob>& value);
+
+ private:
+
+ // mKey is the key that identifies the cache entry.
+ std::shared_ptr<Blob> mKey;
+
+ // mValue is the cached data associated with the key.
+ std::shared_ptr<Blob> mValue;
+ };
+
+ // A Header is the header for the entire BlobCache serialization format. No
+ // need to make this portable, so we simply write the struct out.
+ struct Header {
+ // mMagicNumber is the magic number that identifies the data as
+ // serialized BlobCache contents. It must always contain 'Blb$'.
+ uint32_t mMagicNumber;
+
+ // mBlobCacheVersion is the serialization format version.
+ uint32_t mBlobCacheVersion;
+
+ // mDeviceVersion is the device-specific version of the cache. This can
+ // be used to invalidate the cache.
+ uint32_t mDeviceVersion;
+
+ // mNumEntries is number of cache entries following the header in the
+ // data.
+ size_t mNumEntries;
+
+ // mBuildId is the build id of the device when the cache was created.
+ // When an update to the build happens (via an OTA or other update) this
+ // is used to invalidate the cache.
+ int mBuildIdLength;
+ char mBuildId[];
+ };
+
+ // An EntryHeader is the header for a serialized cache entry. No need to
+ // make this portable, so we simply write the struct out. Each EntryHeader
+ // is followed imediately by the key data and then the value data.
+ //
+ // The beginning of each serialized EntryHeader is 4-byte aligned, so the
+ // number of bytes that a serialized cache entry will occupy is:
+ //
+ // ((sizeof(EntryHeader) + keySize + valueSize) + 3) & ~3
+ //
+ struct EntryHeader {
+ // mKeySize is the size of the entry key in bytes.
+ size_t mKeySize;
+
+ // mValueSize is the size of the entry value in bytes.
+ size_t mValueSize;
+
+ // mData contains both the key and value data for the cache entry. The
+ // key comes first followed immediately by the value.
+ uint8_t mData[];
+ };
+
+ // mMaxKeySize is the maximum key size that will be cached. Calls to
+ // BlobCache::set with a keySize parameter larger than mMaxKeySize will
+ // simply not add the key/value pair to the cache.
+ const size_t mMaxKeySize;
+
+ // mMaxValueSize is the maximum value size that will be cached. Calls to
+ // BlobCache::set with a valueSize parameter larger than mMaxValueSize will
+ // simply not add the key/value pair to the cache.
+ const size_t mMaxValueSize;
+
+ // mMaxTotalSize is the maximum size that all cache entries can occupy. This
+ // includes space for both keys and values. When a call to BlobCache::set
+ // would otherwise cause this limit to be exceeded, either the key/value
+ // pair passed to BlobCache::set will not be cached or other cache entries
+ // will be evicted from the cache to make room for the new entry.
+ const size_t mMaxTotalSize;
+
+ // mTotalSize is the total combined size of all keys and values currently in
+ // the cache.
+ size_t mTotalSize;
+
+ // mRandState is the pseudo-random number generator state. It is passed to
+ // nrand48 to generate random numbers when needed.
+ unsigned short mRandState[3];
+
+ // mCacheEntries stores all the cache entries that are resident in memory.
+ // Cache entries are added to it by the 'set' method.
+ std::vector<CacheEntry> mCacheEntries;
+};
+
+}
+
+#endif // ANDROID_BLOB_CACHE_H
diff --git a/opengl/libs/EGL/BlobCache_test.cpp b/opengl/libs/EGL/BlobCache_test.cpp
new file mode 100644
index 0000000..edbaaf0
--- /dev/null
+++ b/opengl/libs/EGL/BlobCache_test.cpp
@@ -0,0 +1,434 @@
+/*
+ ** Copyright 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.
+ */
+
+#include <fcntl.h>
+#include <stdio.h>
+
+#include <memory>
+
+#include <gtest/gtest.h>
+
+#include "BlobCache.h"
+
+namespace android {
+
+template<typename T> using sp = std::shared_ptr<T>;
+
+class BlobCacheTest : public ::testing::Test {
+protected:
+
+ enum {
+ OK = 0,
+ BAD_VALUE = -EINVAL
+ };
+
+ enum {
+ MAX_KEY_SIZE = 6,
+ MAX_VALUE_SIZE = 8,
+ MAX_TOTAL_SIZE = 13,
+ };
+
+ virtual void SetUp() {
+ mBC.reset(new BlobCache(MAX_KEY_SIZE, MAX_VALUE_SIZE, MAX_TOTAL_SIZE));
+ }
+
+ virtual void TearDown() {
+ mBC.reset();
+ }
+
+ std::unique_ptr<BlobCache> mBC;
+};
+
+TEST_F(BlobCacheTest, CacheSingleValueSucceeds) {
+ unsigned char buf[4] = { 0xee, 0xee, 0xee, 0xee };
+ mBC->set("abcd", 4, "efgh", 4);
+ ASSERT_EQ(size_t(4), mBC->get("abcd", 4, buf, 4));
+ ASSERT_EQ('e', buf[0]);
+ ASSERT_EQ('f', buf[1]);
+ ASSERT_EQ('g', buf[2]);
+ ASSERT_EQ('h', buf[3]);
+}
+
+TEST_F(BlobCacheTest, CacheTwoValuesSucceeds) {
+ unsigned char buf[2] = { 0xee, 0xee };
+ mBC->set("ab", 2, "cd", 2);
+ mBC->set("ef", 2, "gh", 2);
+ ASSERT_EQ(size_t(2), mBC->get("ab", 2, buf, 2));
+ ASSERT_EQ('c', buf[0]);
+ ASSERT_EQ('d', buf[1]);
+ ASSERT_EQ(size_t(2), mBC->get("ef", 2, buf, 2));
+ ASSERT_EQ('g', buf[0]);
+ ASSERT_EQ('h', buf[1]);
+}
+
+TEST_F(BlobCacheTest, GetOnlyWritesInsideBounds) {
+ unsigned char buf[6] = { 0xee, 0xee, 0xee, 0xee, 0xee, 0xee };
+ mBC->set("abcd", 4, "efgh", 4);
+ ASSERT_EQ(size_t(4), mBC->get("abcd", 4, buf+1, 4));
+ ASSERT_EQ(0xee, buf[0]);
+ ASSERT_EQ('e', buf[1]);
+ ASSERT_EQ('f', buf[2]);
+ ASSERT_EQ('g', buf[3]);
+ ASSERT_EQ('h', buf[4]);
+ ASSERT_EQ(0xee, buf[5]);
+}
+
+TEST_F(BlobCacheTest, GetOnlyWritesIfBufferIsLargeEnough) {
+ unsigned char buf[3] = { 0xee, 0xee, 0xee };
+ mBC->set("abcd", 4, "efgh", 4);
+ ASSERT_EQ(size_t(4), mBC->get("abcd", 4, buf, 3));
+ ASSERT_EQ(0xee, buf[0]);
+ ASSERT_EQ(0xee, buf[1]);
+ ASSERT_EQ(0xee, buf[2]);
+}
+
+TEST_F(BlobCacheTest, GetDoesntAccessNullBuffer) {
+ mBC->set("abcd", 4, "efgh", 4);
+ ASSERT_EQ(size_t(4), mBC->get("abcd", 4, NULL, 0));
+}
+
+TEST_F(BlobCacheTest, MultipleSetsCacheLatestValue) {
+ unsigned char buf[4] = { 0xee, 0xee, 0xee, 0xee };
+ mBC->set("abcd", 4, "efgh", 4);
+ mBC->set("abcd", 4, "ijkl", 4);
+ ASSERT_EQ(size_t(4), mBC->get("abcd", 4, buf, 4));
+ ASSERT_EQ('i', buf[0]);
+ ASSERT_EQ('j', buf[1]);
+ ASSERT_EQ('k', buf[2]);
+ ASSERT_EQ('l', buf[3]);
+}
+
+TEST_F(BlobCacheTest, SecondSetKeepsFirstValueIfTooLarge) {
+ unsigned char buf[MAX_VALUE_SIZE+1] = { 0xee, 0xee, 0xee, 0xee };
+ mBC->set("abcd", 4, "efgh", 4);
+ mBC->set("abcd", 4, buf, MAX_VALUE_SIZE+1);
+ ASSERT_EQ(size_t(4), mBC->get("abcd", 4, buf, 4));
+ ASSERT_EQ('e', buf[0]);
+ ASSERT_EQ('f', buf[1]);
+ ASSERT_EQ('g', buf[2]);
+ ASSERT_EQ('h', buf[3]);
+}
+
+TEST_F(BlobCacheTest, DoesntCacheIfKeyIsTooBig) {
+ char key[MAX_KEY_SIZE+1];
+ unsigned char buf[4] = { 0xee, 0xee, 0xee, 0xee };
+ for (int i = 0; i < MAX_KEY_SIZE+1; i++) {
+ key[i] = 'a';
+ }
+ mBC->set(key, MAX_KEY_SIZE+1, "bbbb", 4);
+ ASSERT_EQ(size_t(0), mBC->get(key, MAX_KEY_SIZE+1, buf, 4));
+ ASSERT_EQ(0xee, buf[0]);
+ ASSERT_EQ(0xee, buf[1]);
+ ASSERT_EQ(0xee, buf[2]);
+ ASSERT_EQ(0xee, buf[3]);
+}
+
+TEST_F(BlobCacheTest, DoesntCacheIfValueIsTooBig) {
+ char buf[MAX_VALUE_SIZE+1];
+ for (int i = 0; i < MAX_VALUE_SIZE+1; i++) {
+ buf[i] = 'b';
+ }
+ mBC->set("abcd", 4, buf, MAX_VALUE_SIZE+1);
+ for (int i = 0; i < MAX_VALUE_SIZE+1; i++) {
+ buf[i] = 0xee;
+ }
+ ASSERT_EQ(size_t(0), mBC->get("abcd", 4, buf, MAX_VALUE_SIZE+1));
+ for (int i = 0; i < MAX_VALUE_SIZE+1; i++) {
+ SCOPED_TRACE(i);
+ ASSERT_EQ(0xee, buf[i]);
+ }
+}
+
+TEST_F(BlobCacheTest, DoesntCacheIfKeyValuePairIsTooBig) {
+ // Check a testing assumptions
+ ASSERT_TRUE(MAX_TOTAL_SIZE < MAX_KEY_SIZE + MAX_VALUE_SIZE);
+ ASSERT_TRUE(MAX_KEY_SIZE < MAX_TOTAL_SIZE);
+
+ enum { bufSize = MAX_TOTAL_SIZE - MAX_KEY_SIZE + 1 };
+
+ char key[MAX_KEY_SIZE];
+ char buf[bufSize];
+ for (int i = 0; i < MAX_KEY_SIZE; i++) {
+ key[i] = 'a';
+ }
+ for (int i = 0; i < bufSize; i++) {
+ buf[i] = 'b';
+ }
+
+ mBC->set(key, MAX_KEY_SIZE, buf, MAX_VALUE_SIZE);
+ ASSERT_EQ(size_t(0), mBC->get(key, MAX_KEY_SIZE, NULL, 0));
+}
+
+TEST_F(BlobCacheTest, CacheMaxKeySizeSucceeds) {
+ char key[MAX_KEY_SIZE];
+ unsigned char buf[4] = { 0xee, 0xee, 0xee, 0xee };
+ for (int i = 0; i < MAX_KEY_SIZE; i++) {
+ key[i] = 'a';
+ }
+ mBC->set(key, MAX_KEY_SIZE, "wxyz", 4);
+ ASSERT_EQ(size_t(4), mBC->get(key, MAX_KEY_SIZE, buf, 4));
+ ASSERT_EQ('w', buf[0]);
+ ASSERT_EQ('x', buf[1]);
+ ASSERT_EQ('y', buf[2]);
+ ASSERT_EQ('z', buf[3]);
+}
+
+TEST_F(BlobCacheTest, CacheMaxValueSizeSucceeds) {
+ char buf[MAX_VALUE_SIZE];
+ for (int i = 0; i < MAX_VALUE_SIZE; i++) {
+ buf[i] = 'b';
+ }
+ mBC->set("abcd", 4, buf, MAX_VALUE_SIZE);
+ for (int i = 0; i < MAX_VALUE_SIZE; i++) {
+ buf[i] = 0xee;
+ }
+ ASSERT_EQ(size_t(MAX_VALUE_SIZE), mBC->get("abcd", 4, buf,
+ MAX_VALUE_SIZE));
+ for (int i = 0; i < MAX_VALUE_SIZE; i++) {
+ SCOPED_TRACE(i);
+ ASSERT_EQ('b', buf[i]);
+ }
+}
+
+TEST_F(BlobCacheTest, CacheMaxKeyValuePairSizeSucceeds) {
+ // Check a testing assumption
+ ASSERT_TRUE(MAX_KEY_SIZE < MAX_TOTAL_SIZE);
+
+ enum { bufSize = MAX_TOTAL_SIZE - MAX_KEY_SIZE };
+
+ char key[MAX_KEY_SIZE];
+ char buf[bufSize];
+ for (int i = 0; i < MAX_KEY_SIZE; i++) {
+ key[i] = 'a';
+ }
+ for (int i = 0; i < bufSize; i++) {
+ buf[i] = 'b';
+ }
+
+ mBC->set(key, MAX_KEY_SIZE, buf, bufSize);
+ ASSERT_EQ(size_t(bufSize), mBC->get(key, MAX_KEY_SIZE, NULL, 0));
+}
+
+TEST_F(BlobCacheTest, CacheMinKeyAndValueSizeSucceeds) {
+ unsigned char buf[1] = { 0xee };
+ mBC->set("x", 1, "y", 1);
+ ASSERT_EQ(size_t(1), mBC->get("x", 1, buf, 1));
+ ASSERT_EQ('y', buf[0]);
+}
+
+TEST_F(BlobCacheTest, CacheSizeDoesntExceedTotalLimit) {
+ for (int i = 0; i < 256; i++) {
+ uint8_t k = i;
+ mBC->set(&k, 1, "x", 1);
+ }
+ int numCached = 0;
+ for (int i = 0; i < 256; i++) {
+ uint8_t k = i;
+ if (mBC->get(&k, 1, NULL, 0) == 1) {
+ numCached++;
+ }
+ }
+ ASSERT_GE(MAX_TOTAL_SIZE / 2, numCached);
+}
+
+TEST_F(BlobCacheTest, ExceedingTotalLimitHalvesCacheSize) {
+ // Fill up the entire cache with 1 char key/value pairs.
+ const int maxEntries = MAX_TOTAL_SIZE / 2;
+ for (int i = 0; i < maxEntries; i++) {
+ uint8_t k = i;
+ mBC->set(&k, 1, "x", 1);
+ }
+ // Insert one more entry, causing a cache overflow.
+ {
+ uint8_t k = maxEntries;
+ mBC->set(&k, 1, "x", 1);
+ }
+ // Count the number of entries in the cache.
+ int numCached = 0;
+ for (int i = 0; i < maxEntries+1; i++) {
+ uint8_t k = i;
+ if (mBC->get(&k, 1, NULL, 0) == 1) {
+ numCached++;
+ }
+ }
+ ASSERT_EQ(maxEntries/2 + 1, numCached);
+}
+
+class BlobCacheFlattenTest : public BlobCacheTest {
+protected:
+ virtual void SetUp() {
+ BlobCacheTest::SetUp();
+ mBC2.reset(new BlobCache(MAX_KEY_SIZE, MAX_VALUE_SIZE, MAX_TOTAL_SIZE));
+ }
+
+ virtual void TearDown() {
+ mBC2.reset();
+ BlobCacheTest::TearDown();
+ }
+
+ void roundTrip() {
+ size_t size = mBC->getFlattenedSize();
+ uint8_t* flat = new uint8_t[size];
+ ASSERT_EQ(OK, mBC->flatten(flat, size));
+ ASSERT_EQ(OK, mBC2->unflatten(flat, size));
+ delete[] flat;
+ }
+
+ sp<BlobCache> mBC2;
+};
+
+TEST_F(BlobCacheFlattenTest, FlattenOneValue) {
+ unsigned char buf[4] = { 0xee, 0xee, 0xee, 0xee };
+ mBC->set("abcd", 4, "efgh", 4);
+ roundTrip();
+ ASSERT_EQ(size_t(4), mBC2->get("abcd", 4, buf, 4));
+ ASSERT_EQ('e', buf[0]);
+ ASSERT_EQ('f', buf[1]);
+ ASSERT_EQ('g', buf[2]);
+ ASSERT_EQ('h', buf[3]);
+}
+
+TEST_F(BlobCacheFlattenTest, FlattenFullCache) {
+ // Fill up the entire cache with 1 char key/value pairs.
+ const int maxEntries = MAX_TOTAL_SIZE / 2;
+ for (int i = 0; i < maxEntries; i++) {
+ uint8_t k = i;
+ mBC->set(&k, 1, &k, 1);
+ }
+
+ roundTrip();
+
+ // Verify the deserialized cache
+ for (int i = 0; i < maxEntries; i++) {
+ uint8_t k = i;
+ uint8_t v = 0xee;
+ ASSERT_EQ(size_t(1), mBC2->get(&k, 1, &v, 1));
+ ASSERT_EQ(k, v);
+ }
+}
+
+TEST_F(BlobCacheFlattenTest, FlattenDoesntChangeCache) {
+ // Fill up the entire cache with 1 char key/value pairs.
+ const int maxEntries = MAX_TOTAL_SIZE / 2;
+ for (int i = 0; i < maxEntries; i++) {
+ uint8_t k = i;
+ mBC->set(&k, 1, &k, 1);
+ }
+
+ size_t size = mBC->getFlattenedSize();
+ uint8_t* flat = new uint8_t[size];
+ ASSERT_EQ(OK, mBC->flatten(flat, size));
+ delete[] flat;
+
+ // Verify the cache that we just serialized
+ for (int i = 0; i < maxEntries; i++) {
+ uint8_t k = i;
+ uint8_t v = 0xee;
+ ASSERT_EQ(size_t(1), mBC->get(&k, 1, &v, 1));
+ ASSERT_EQ(k, v);
+ }
+}
+
+TEST_F(BlobCacheFlattenTest, FlattenCatchesBufferTooSmall) {
+ // Fill up the entire cache with 1 char key/value pairs.
+ const int maxEntries = MAX_TOTAL_SIZE / 2;
+ for (int i = 0; i < maxEntries; i++) {
+ uint8_t k = i;
+ mBC->set(&k, 1, &k, 1);
+ }
+
+ size_t size = mBC->getFlattenedSize() - 1;
+ uint8_t* flat = new uint8_t[size];
+ // ASSERT_EQ(BAD_VALUE, mBC->flatten(flat, size));
+ // TODO: The above fails. I expect this is so because getFlattenedSize()
+ // overstimates the size by using PROPERTY_VALUE_MAX.
+ delete[] flat;
+}
+
+TEST_F(BlobCacheFlattenTest, UnflattenCatchesBadMagic) {
+ unsigned char buf[4] = { 0xee, 0xee, 0xee, 0xee };
+ mBC->set("abcd", 4, "efgh", 4);
+
+ size_t size = mBC->getFlattenedSize();
+ uint8_t* flat = new uint8_t[size];
+ ASSERT_EQ(OK, mBC->flatten(flat, size));
+ flat[1] = ~flat[1];
+
+ // Bad magic should cause an error.
+ ASSERT_EQ(BAD_VALUE, mBC2->unflatten(flat, size));
+ delete[] flat;
+
+ // The error should cause the unflatten to result in an empty cache
+ ASSERT_EQ(size_t(0), mBC2->get("abcd", 4, buf, 4));
+}
+
+TEST_F(BlobCacheFlattenTest, UnflattenCatchesBadBlobCacheVersion) {
+ unsigned char buf[4] = { 0xee, 0xee, 0xee, 0xee };
+ mBC->set("abcd", 4, "efgh", 4);
+
+ size_t size = mBC->getFlattenedSize();
+ uint8_t* flat = new uint8_t[size];
+ ASSERT_EQ(OK, mBC->flatten(flat, size));
+ flat[5] = ~flat[5];
+
+ // Version mismatches shouldn't cause errors, but should not use the
+ // serialized entries
+ ASSERT_EQ(OK, mBC2->unflatten(flat, size));
+ delete[] flat;
+
+ // The version mismatch should cause the unflatten to result in an empty
+ // cache
+ ASSERT_EQ(size_t(0), mBC2->get("abcd", 4, buf, 4));
+}
+
+TEST_F(BlobCacheFlattenTest, UnflattenCatchesBadBlobCacheDeviceVersion) {
+ unsigned char buf[4] = { 0xee, 0xee, 0xee, 0xee };
+ mBC->set("abcd", 4, "efgh", 4);
+
+ size_t size = mBC->getFlattenedSize();
+ uint8_t* flat = new uint8_t[size];
+ ASSERT_EQ(OK, mBC->flatten(flat, size));
+ flat[10] = ~flat[10];
+
+ // Version mismatches shouldn't cause errors, but should not use the
+ // serialized entries
+ ASSERT_EQ(OK, mBC2->unflatten(flat, size));
+ delete[] flat;
+
+ // The version mismatch should cause the unflatten to result in an empty
+ // cache
+ ASSERT_EQ(size_t(0), mBC2->get("abcd", 4, buf, 4));
+}
+
+TEST_F(BlobCacheFlattenTest, UnflattenCatchesBufferTooSmall) {
+ unsigned char buf[4] = { 0xee, 0xee, 0xee, 0xee };
+ mBC->set("abcd", 4, "efgh", 4);
+
+ size_t size = mBC->getFlattenedSize();
+ uint8_t* flat = new uint8_t[size];
+ ASSERT_EQ(OK, mBC->flatten(flat, size));
+
+ // A buffer truncation shouldt cause an error
+ // ASSERT_EQ(BAD_VALUE, mBC2->unflatten(flat, size-1));
+ // TODO: The above appears to fail because getFlattenedSize() is
+ // conservative.
+ delete[] flat;
+
+ // The error should cause the unflatten to result in an empty cache
+ ASSERT_EQ(size_t(0), mBC2->get("abcd", 4, buf, 4));
+}
+
+} // namespace android
diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp
index 9aedc61..683e6ca 100644
--- a/opengl/libs/EGL/Loader.cpp
+++ b/opengl/libs/EGL/Loader.cpp
@@ -19,6 +19,8 @@
#include "Loader.h"
+#include <string>
+
#include <dirent.h>
#include <dlfcn.h>
@@ -26,11 +28,9 @@
#include <cutils/properties.h>
#include <log/log.h>
-#include <utils/String8.h>
-#include <utils/Trace.h>
-
#include <ui/GraphicsEnv.h>
+#include "egl_trace.h"
#include "egldefs.h"
// ----------------------------------------------------------------------------
@@ -61,7 +61,10 @@
*
*/
-ANDROID_SINGLETON_STATIC_INSTANCE( Loader )
+Loader& Loader::getInstance() {
+ static Loader loader;
+ return loader;
+}
/* This function is called to check whether we run inside the emulator,
* and if this is the case whether GLES GPU emulation is supported.
@@ -122,7 +125,7 @@
}
}
-status_t Loader::driver_t::set(void* hnd, int32_t api)
+int Loader::driver_t::set(void* hnd, int32_t api)
{
switch (api) {
case EGL:
@@ -135,9 +138,9 @@
dso[2] = hnd;
break;
default:
- return BAD_INDEX;
+ return -EOVERFLOW;
}
- return NO_ERROR;
+ return 0;
}
// ----------------------------------------------------------------------------
@@ -233,11 +236,10 @@
return (void*)hnd;
}
-status_t Loader::close(void* driver)
+void Loader::close(void* driver)
{
driver_t* hnd = (driver_t*)driver;
delete hnd;
- return NO_ERROR;
}
void Loader::init_api(void* dso,
@@ -302,23 +304,23 @@
ATRACE_CALL();
class MatchFile {
public:
- static String8 find(const char* kind) {
- String8 result;
+ static std::string find(const char* kind) {
+ std::string result;
int emulationStatus = checkGlesEmulationStatus();
switch (emulationStatus) {
case 0:
#if defined(__LP64__)
- result.setTo("/system/lib64/egl/libGLES_android.so");
+ result = "/system/lib64/egl/libGLES_android.so";
#else
- result.setTo("/system/lib/egl/libGLES_android.so");
+ result = "/system/lib/egl/libGLES_android.so";
#endif
return result;
case 1:
// Use host-side OpenGL through the "emulation" library
#if defined(__LP64__)
- result.appendFormat("/system/lib64/egl/lib%s_emulation.so", kind);
+ result = std::string("/system/lib64/egl/lib") + kind + "_emulation.so";
#else
- result.appendFormat("/system/lib/egl/lib%s_emulation.so", kind);
+ result = std::string("/system/lib/egl/lib") + kind + "_emulation.so";
#endif
return result;
default:
@@ -326,8 +328,7 @@
break;
}
- String8 pattern;
- pattern.appendFormat("lib%s", kind);
+ std::string pattern = std::string("lib") + kind;
const char* const searchPaths[] = {
#if defined(__LP64__)
"/vendor/lib64/egl",
@@ -368,12 +369,11 @@
}
private:
- static bool find(String8& result,
- const String8& pattern, const char* const search, bool exact) {
+ static bool find(std::string& result,
+ const std::string& pattern, const char* const search, bool exact) {
if (exact) {
- String8 absolutePath;
- absolutePath.appendFormat("%s/%s.so", search, pattern.string());
- if (!access(absolutePath.string(), R_OK)) {
+ std::string absolutePath = std::string(search) + "/" + pattern;
+ if (!access(absolutePath.c_str(), R_OK)) {
result = absolutePath;
return true;
}
@@ -392,10 +392,9 @@
// always skip the software renderer
continue;
}
- if (strstr(e->d_name, pattern.string()) == e->d_name) {
+ if (strstr(e->d_name, pattern.c_str()) == e->d_name) {
if (!strcmp(e->d_name + strlen(e->d_name) - 3, ".so")) {
- result.clear();
- result.appendFormat("%s/%s", search, e->d_name);
+ result = std::string(search) + "/" + e->d_name;
closedir(d);
return true;
}
@@ -408,17 +407,17 @@
};
- String8 absolutePath = MatchFile::find(kind);
- if (absolutePath.isEmpty()) {
+ std::string absolutePath = MatchFile::find(kind);
+ if (absolutePath.empty()) {
// this happens often, we don't want to log an error
return 0;
}
- const char* const driver_absolute_path = absolutePath.string();
+ const char* const driver_absolute_path = absolutePath.c_str();
void* dso = do_dlopen(driver_absolute_path, RTLD_NOW | RTLD_LOCAL);
if (dso == 0) {
const char* err = dlerror();
- ALOGE("load_driver(%s): %s", driver_absolute_path, err?err:"unknown");
+ ALOGE("load_driver(%s): %s", driver_absolute_path, err ? err : "unknown");
return 0;
}
@@ -447,9 +446,8 @@
char prop[PROPERTY_VALUE_MAX + 1];
for (auto key : HAL_SUBNAME_KEY_PROPERTIES) {
if (property_get(key, prop, nullptr) > 0) {
- String8 name;
- name.appendFormat("lib%s_%s.so", kind, prop);
- so = do_android_dlopen_ext(name.string(), RTLD_LOCAL | RTLD_NOW, &dlextinfo);
+ std::string name = std::string("lib") + kind + "_" + prop + ".so";
+ so = do_android_dlopen_ext(name.c_str(), RTLD_LOCAL | RTLD_NOW, &dlextinfo);
if (so) {
return so;
}
diff --git a/opengl/libs/EGL/Loader.h b/opengl/libs/EGL/Loader.h
index 2dd4206..6a32bb3 100644
--- a/opengl/libs/EGL/Loader.h
+++ b/opengl/libs/EGL/Loader.h
@@ -19,9 +19,6 @@
#include <stdint.h>
-#include <utils/Errors.h>
-#include <utils/Singleton.h>
-
#include <EGL/egl.h>
// ----------------------------------------------------------------------------
@@ -30,9 +27,7 @@
struct egl_connection_t;
-class Loader : public Singleton<Loader> {
- friend class Singleton<Loader>;
-
+class Loader {
typedef __eglMustCastToProperFunctionPointerType (* getProcAddressType)(const char*);
enum {
@@ -43,17 +38,19 @@
struct driver_t {
explicit driver_t(void* gles);
~driver_t();
- status_t set(void* hnd, int32_t api);
+ // returns -errno
+ int set(void* hnd, int32_t api);
void* dso[3];
};
getProcAddressType getProcAddress;
public:
+ static Loader& getInstance();
~Loader();
void* open(egl_connection_t* cnx);
- status_t close(void* driver);
+ void close(void* driver);
private:
Loader();
diff --git a/opengl/libs/EGL/egl.cpp b/opengl/libs/EGL/egl.cpp
index 34b0ba2..f44c1ca 100644
--- a/opengl/libs/EGL/egl.cpp
+++ b/opengl/libs/EGL/egl.cpp
@@ -20,7 +20,6 @@
#include <EGL/egl.h>
-#include <cutils/atomic.h>
#include <cutils/properties.h>
#include <log/log.h>
@@ -128,7 +127,7 @@
if (name != GL_EXTENSIONS)
return NULL;
- return (const GLubyte *)c->gl_extensions.string();
+ return (const GLubyte *)c->gl_extensions.c_str();
}
const GLubyte * egl_get_string_for_current_context(GLenum name, GLuint index) {
@@ -151,7 +150,7 @@
if (index >= c->tokenized_gl_extensions.size())
return NULL;
- return (const GLubyte *)c->tokenized_gl_extensions.itemAt(index).string();
+ return (const GLubyte *)c->tokenized_gl_extensions[index].c_str();
}
GLint egl_get_num_extensions_for_current_context() {
@@ -208,14 +207,14 @@
}
static pthread_mutex_t sLogPrintMutex = PTHREAD_MUTEX_INITIALIZER;
-static nsecs_t sLogPrintTime = 0;
-#define NSECS_DURATION 1000000000
+static std::chrono::steady_clock::time_point sLogPrintTime;
+static constexpr std::chrono::seconds DURATION(1);
void gl_unimplemented() {
bool printLog = false;
- nsecs_t now = systemTime();
+ auto now = std::chrono::steady_clock::now();
pthread_mutex_lock(&sLogPrintMutex);
- if ((now - sLogPrintTime) > NSECS_DURATION) {
+ if ((now - sLogPrintTime) > DURATION) {
sLogPrintTime = now;
printLog = true;
}
diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp
index e52713f..d124c89 100644
--- a/opengl/libs/EGL/eglApi.cpp
+++ b/opengl/libs/EGL/eglApi.cpp
@@ -33,25 +33,19 @@
#include <cutils/properties.h>
#include <log/log.h>
-#include <gui/ISurfaceComposer.h>
-
-#include <ui/GraphicBuffer.h>
-
-
-#include <utils/KeyedVector.h>
-#include <utils/String8.h>
-#include <utils/Trace.h>
-#include <utils/Thread.h>
-
-#include "binder/Binder.h"
-#include "binder/Parcel.h"
-#include "binder/IServiceManager.h"
+#include <condition_variable>
+#include <deque>
+#include <mutex>
+#include <unordered_map>
+#include <string>
+#include <thread>
#include "../egl_impl.h"
#include "egl_display.h"
#include "egl_object.h"
#include "egl_tls.h"
+#include "egl_trace.h"
using namespace android;
@@ -59,6 +53,8 @@
namespace android {
+using nsecs_t = int64_t;
+
struct extention_map_t {
const char* name;
__eglMustCastToProperFunctionPointerType address;
@@ -87,7 +83,6 @@
"EGL_KHR_get_all_proc_addresses "
"EGL_ANDROID_presentation_time "
"EGL_KHR_swap_buffers_with_damage "
- "EGL_ANDROID_create_native_client_buffer "
"EGL_ANDROID_get_native_client_buffer "
"EGL_ANDROID_front_buffer_auto_refresh "
"EGL_ANDROID_get_frame_timestamps "
@@ -184,10 +179,6 @@
{ "eglSwapBuffersWithDamageKHR",
(__eglMustCastToProperFunctionPointerType)&eglSwapBuffersWithDamageKHR },
- // EGL_ANDROID_create_native_client_buffer
- { "eglCreateNativeClientBufferANDROID",
- (__eglMustCastToProperFunctionPointerType)&eglCreateNativeClientBufferANDROID },
-
// EGL_ANDROID_get_native_client_buffer
{ "eglGetNativeClientBufferANDROID",
(__eglMustCastToProperFunctionPointerType)&eglGetNativeClientBufferANDROID },
@@ -247,7 +238,8 @@
// accesses protected by sExtensionMapMutex
-static DefaultKeyedVector<String8, __eglMustCastToProperFunctionPointerType> sGLExtentionMap;
+static std::unordered_map<std::string, __eglMustCastToProperFunctionPointerType> sGLExtentionMap;
+
static int sGLExtentionSlot = 0;
static pthread_mutex_t sExtensionMapMutex = PTHREAD_MUTEX_INITIALIZER;
@@ -478,8 +470,18 @@
if (dp) {
EGLDisplay iDpy = dp->disp.dpy;
+ if (!window) {
+ return setError(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE);
+ }
+
+ int value = 0;
+ window->query(window, NATIVE_WINDOW_IS_VALID, &value);
+ if (!value) {
+ return setError(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE);
+ }
+
int result = native_window_api_connect(window, NATIVE_WINDOW_API_EGL);
- if (result != OK) {
+ if (result < 0) {
ALOGE("eglCreateWindowSurface: native_window_api_connect (win=%p) "
"failed (%#x) (already connected to another API?)",
window, result);
@@ -992,8 +994,11 @@
*
*/
- const String8 name(procname);
- addr = sGLExtentionMap.valueFor(name);
+ const std::string name(procname);
+
+ auto& extentionMap = sGLExtentionMap;
+ auto pos = extentionMap.find(name);
+ addr = (pos != extentionMap.end()) ? pos->second : nullptr;
const int slot = sGLExtentionSlot;
ALOGE_IF(slot >= MAX_NUMBER_OF_GL_EXTENSIONS,
@@ -1015,7 +1020,7 @@
if (found) {
addr = gExtensionForwarders[slot];
- sGLExtentionMap.add(name, addr);
+ extentionMap[name] = addr;
sGLExtentionSlot++;
}
}
@@ -1024,45 +1029,57 @@
return addr;
}
-class FrameCompletionThread : public Thread {
+class FrameCompletionThread {
public:
static void queueSync(EGLSyncKHR sync) {
- static sp<FrameCompletionThread> thread(new FrameCompletionThread);
- static bool running = false;
- if (!running) {
- thread->run("GPUFrameCompletion");
- running = true;
- }
- {
- Mutex::Autolock lock(thread->mMutex);
- ScopedTrace st(ATRACE_TAG, String8::format("kicked off frame %d",
- thread->mFramesQueued).string());
- thread->mQueue.push_back(sync);
- thread->mCondition.signal();
- thread->mFramesQueued++;
- ATRACE_INT("GPU Frames Outstanding", int32_t(thread->mQueue.size()));
- }
+ static FrameCompletionThread thread;
+
+ char name[64];
+
+ std::lock_guard<std::mutex> lock(thread.mMutex);
+ snprintf(name, sizeof(name), "kicked off frame %u", (unsigned int)thread.mFramesQueued);
+ ATRACE_NAME(name);
+
+ thread.mQueue.push_back(sync);
+ thread.mCondition.notify_one();
+ thread.mFramesQueued++;
+ ATRACE_INT("GPU Frames Outstanding", int32_t(thread.mQueue.size()));
}
private:
- FrameCompletionThread() : mFramesQueued(0), mFramesCompleted(0) {}
- virtual bool threadLoop() {
+ FrameCompletionThread() : mFramesQueued(0), mFramesCompleted(0) {
+ std::thread thread(&FrameCompletionThread::loop, this);
+ thread.detach();
+ }
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wmissing-noreturn"
+ void loop() {
+ while (true) {
+ threadLoop();
+ }
+ }
+#pragma clang diagnostic pop
+
+ void threadLoop() {
EGLSyncKHR sync;
uint32_t frameNum;
{
- Mutex::Autolock lock(mMutex);
- while (mQueue.isEmpty()) {
- mCondition.wait(mMutex);
+ std::unique_lock<std::mutex> lock(mMutex);
+ while (mQueue.empty()) {
+ mCondition.wait(lock);
}
sync = mQueue[0];
frameNum = mFramesCompleted;
}
EGLDisplay dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
{
- ScopedTrace st(ATRACE_TAG, String8::format("waiting for frame %d",
- frameNum).string());
+ char name[64];
+ snprintf(name, sizeof(name), "waiting for frame %u", (unsigned int)frameNum);
+ ATRACE_NAME(name);
+
EGLint result = eglClientWaitSyncKHR(dpy, sync, 0, EGL_FOREVER_KHR);
if (result == EGL_FALSE) {
ALOGE("FrameCompletion: error waiting for fence: %#x", eglGetError());
@@ -1072,19 +1089,18 @@
eglDestroySyncKHR(dpy, sync);
}
{
- Mutex::Autolock lock(mMutex);
- mQueue.removeAt(0);
+ std::lock_guard<std::mutex> lock(mMutex);
+ mQueue.pop_front();
mFramesCompleted++;
ATRACE_INT("GPU Frames Outstanding", int32_t(mQueue.size()));
}
- return true;
}
uint32_t mFramesQueued;
uint32_t mFramesCompleted;
- Vector<EGLSyncKHR> mQueue;
- Condition mCondition;
- Mutex mMutex;
+ std::deque<EGLSyncKHR> mQueue;
+ std::condition_variable mCondition;
+ std::mutex mMutex;
};
EGLBoolean eglSwapBuffersWithDamageKHR(EGLDisplay dpy, EGLSurface draw,
@@ -1123,7 +1139,7 @@
return s->cnx->egl.eglSwapBuffers(dp->disp.dpy, s->surface);
}
- Vector<android_native_rect_t> androidRects;
+ std::vector<android_native_rect_t> androidRects((size_t)n_rects);
for (int r = 0; r < n_rects; ++r) {
int offset = r * 4;
int x = rects[offset];
@@ -1137,8 +1153,7 @@
androidRect.bottom = y;
androidRects.push_back(androidRect);
}
- native_window_set_surface_damage(s->win.get(), androidRects.array(),
- androidRects.size());
+ native_window_set_surface_damage(s->getNativeWindow(), androidRects.data(), androidRects.size());
if (s->cnx->egl.eglSwapBuffersWithDamageKHR) {
return s->cnx->egl.eglSwapBuffersWithDamageKHR(dp->disp.dpy, s->surface,
@@ -1242,19 +1257,19 @@
egl_surface_t * const s = get_surface(surface);
if (attribute == EGL_FRONT_BUFFER_AUTO_REFRESH_ANDROID) {
- if (!s->win.get()) {
+ if (!s->getNativeWindow()) {
setError(EGL_BAD_SURFACE, EGL_FALSE);
}
- int err = native_window_set_auto_refresh(s->win.get(), value ? true : false);
- return (err == NO_ERROR) ? EGL_TRUE : setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
+ int err = native_window_set_auto_refresh(s->getNativeWindow(), value != 0);
+ return (err == 0) ? EGL_TRUE : setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
}
if (attribute == EGL_TIMESTAMPS_ANDROID) {
- if (!s->win.get()) {
+ if (!s->getNativeWindow()) {
return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
}
- int err = native_window_enable_frame_timestamps(s->win.get(), value ? true : false);
- return (err == NO_ERROR) ? EGL_TRUE : setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
+ int err = native_window_enable_frame_timestamps(s->getNativeWindow(), value != 0);
+ return (err == 0) ? EGL_TRUE : setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
}
if (s->cnx->egl.eglSurfaceAttrib) {
@@ -1829,169 +1844,15 @@
}
egl_surface_t const * const s = get_surface(surface);
- native_window_set_buffers_timestamp(s->win.get(), time);
+ native_window_set_buffers_timestamp(s->getNativeWindow(), time);
return EGL_TRUE;
}
-EGLClientBuffer eglCreateNativeClientBufferANDROID(const EGLint *attrib_list)
-{
- clearError();
-
- uint64_t producerUsage = 0;
- uint64_t consumerUsage = 0;
- uint32_t width = 0;
- uint32_t height = 0;
- uint32_t format = 0;
- uint32_t layer_count = 1;
- uint32_t red_size = 0;
- uint32_t green_size = 0;
- uint32_t blue_size = 0;
- uint32_t alpha_size = 0;
-
-#define GET_NONNEGATIVE_VALUE(case_name, target) \
- case case_name: \
- if (value >= 0) { \
- target = value; \
- } else { \
- return setError(EGL_BAD_PARAMETER, (EGLClientBuffer)0); \
- } \
- break
-
- if (attrib_list) {
- while (*attrib_list != EGL_NONE) {
- GLint attr = *attrib_list++;
- GLint value = *attrib_list++;
- switch (attr) {
- GET_NONNEGATIVE_VALUE(EGL_WIDTH, width);
- GET_NONNEGATIVE_VALUE(EGL_HEIGHT, height);
- GET_NONNEGATIVE_VALUE(EGL_RED_SIZE, red_size);
- GET_NONNEGATIVE_VALUE(EGL_GREEN_SIZE, green_size);
- GET_NONNEGATIVE_VALUE(EGL_BLUE_SIZE, blue_size);
- GET_NONNEGATIVE_VALUE(EGL_ALPHA_SIZE, alpha_size);
- GET_NONNEGATIVE_VALUE(EGL_LAYER_COUNT_ANDROID, layer_count);
- case EGL_NATIVE_BUFFER_USAGE_ANDROID:
- if (value & EGL_NATIVE_BUFFER_USAGE_PROTECTED_BIT_ANDROID) {
- producerUsage |= GRALLOC1_PRODUCER_USAGE_PROTECTED;
- }
- if (value & EGL_NATIVE_BUFFER_USAGE_RENDERBUFFER_BIT_ANDROID) {
- producerUsage |= GRALLOC1_PRODUCER_USAGE_GPU_RENDER_TARGET;
- }
- if (value & EGL_NATIVE_BUFFER_USAGE_TEXTURE_BIT_ANDROID) {
- consumerUsage |= GRALLOC1_CONSUMER_USAGE_GPU_TEXTURE;
- }
- break;
- default:
- return setError(EGL_BAD_PARAMETER, (EGLClientBuffer)0);
- }
- }
- }
-#undef GET_NONNEGATIVE_VALUE
-
- // Validate format.
- if (red_size == 8 && green_size == 8 && blue_size == 8) {
- if (alpha_size == 8) {
- format = HAL_PIXEL_FORMAT_RGBA_8888;
- } else {
- format = HAL_PIXEL_FORMAT_RGB_888;
- }
- } else if (red_size == 5 && green_size == 6 && blue_size == 5 &&
- alpha_size == 0) {
- format = HAL_PIXEL_FORMAT_RGB_565;
- } else {
- ALOGE("Invalid native pixel format { r=%u, g=%u, b=%u, a=%u }",
- red_size, green_size, blue_size, alpha_size);
- return setError(EGL_BAD_PARAMETER, (EGLClientBuffer)0);
- }
-
-#define CHECK_ERROR_CONDITION(message) \
- if (err != NO_ERROR) { \
- ALOGE(message); \
- goto error_condition; \
- }
-
- // The holder is used to destroy the buffer if an error occurs.
- GraphicBuffer* gBuffer = new GraphicBuffer();
- sp<IServiceManager> sm = defaultServiceManager();
- sp<IBinder> surfaceFlinger = sm->getService(String16("SurfaceFlinger"));
- sp<IBinder> allocator;
- Parcel sc_data, sc_reply, data, reply;
- status_t err = NO_ERROR;
- if (sm == NULL) {
- ALOGE("Unable to connect to ServiceManager");
- goto error_condition;
- }
-
- // Obtain an allocator.
- if (surfaceFlinger == NULL) {
- ALOGE("Unable to connect to SurfaceFlinger");
- goto error_condition;
- }
- sc_data.writeInterfaceToken(String16("android.ui.ISurfaceComposer"));
- err = surfaceFlinger->transact(
- BnSurfaceComposer::CREATE_GRAPHIC_BUFFER_ALLOC, sc_data, &sc_reply);
- CHECK_ERROR_CONDITION("Unable to obtain allocator from SurfaceFlinger");
- allocator = sc_reply.readStrongBinder();
-
- if (allocator == NULL) {
- ALOGE("Unable to obtain an ISurfaceComposer");
- goto error_condition;
- }
- data.writeInterfaceToken(String16("android.ui.IGraphicBufferAlloc"));
- err = data.writeUint32(width);
- CHECK_ERROR_CONDITION("Unable to write width");
- err = data.writeUint32(height);
- CHECK_ERROR_CONDITION("Unable to write height");
- err = data.writeInt32(static_cast<int32_t>(format));
- CHECK_ERROR_CONDITION("Unable to write format");
- err = data.writeUint32(layer_count);
- CHECK_ERROR_CONDITION("Unable to write layer count");
- err = data.writeUint64(producerUsage);
- CHECK_ERROR_CONDITION("Unable to write producer usage");
- err = data.writeUint64(consumerUsage);
- CHECK_ERROR_CONDITION("Unable to write consumer usage");
- err = data.writeUtf8AsUtf16(
- std::string("[eglCreateNativeClientBufferANDROID pid ") +
- std::to_string(getpid()) + ']');
- CHECK_ERROR_CONDITION("Unable to write requestor name");
- err = allocator->transact(IBinder::FIRST_CALL_TRANSACTION, data,
- &reply);
- CHECK_ERROR_CONDITION(
- "Unable to request buffer allocation from surface composer");
- err = reply.readInt32();
- CHECK_ERROR_CONDITION("Unable to obtain buffer from surface composer");
- err = reply.read(*gBuffer);
- CHECK_ERROR_CONDITION("Unable to read buffer from surface composer");
-
- err = gBuffer->initCheck();
- if (err != NO_ERROR) {
- ALOGE("Unable to create native buffer "
- "{ w=%u, h=%u, f=%u, pu=%" PRIx64 " cu=%" PRIx64 ", lc=%u} %#x",
- width, height, format, producerUsage, consumerUsage,
- layer_count, err);
- goto error_condition;
- }
- ALOGV("Created new native buffer %p { w=%u, h=%u, f=%u, pu=%" PRIx64
- " cu=%" PRIx64 ", lc=%u}",
- gBuffer, width, height, format, producerUsage, consumerUsage,
- layer_count);
- return static_cast<EGLClientBuffer>(gBuffer->getNativeBuffer());
-
-#undef CHECK_ERROR_CONDITION
-
-error_condition:
- // Delete the buffer.
- sp<GraphicBuffer> holder(gBuffer);
- return setError(EGL_BAD_ALLOC, (EGLClientBuffer)0);
-}
-
EGLClientBuffer eglGetNativeClientBufferANDROID(const AHardwareBuffer *buffer) {
clearError();
-
if (!buffer) return setError(EGL_BAD_PARAMETER, (EGLClientBuffer)0);
-
- const GraphicBuffer* graphicBuffer = AHardwareBuffer_to_GraphicBuffer(buffer);
- return static_cast<EGLClientBuffer>(graphicBuffer->getNativeBuffer());
+ return const_cast<ANativeWindowBuffer *>(AHardwareBuffer_to_ANativeWindowBuffer(buffer));
}
// ----------------------------------------------------------------------------
@@ -2078,14 +1939,14 @@
egl_surface_t const * const s = get_surface(surface);
- if (!s->win.get()) {
+ if (!s->getNativeWindow()) {
return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
}
uint64_t nextFrameId = 0;
- status_t ret = native_window_get_next_frame_id(s->win.get(), &nextFrameId);
+ int ret = native_window_get_next_frame_id(s->getNativeWindow(), &nextFrameId);
- if (ret != NO_ERROR) {
+ if (ret != 0) {
// This should not happen. Return an error that is not in the spec
// so it's obvious something is very wrong.
ALOGE("eglGetNextFrameId: Unexpected error.");
@@ -2113,7 +1974,7 @@
egl_surface_t const * const s = get_surface(surface);
- if (!s->win.get()) {
+ if (!s->getNativeWindow()) {
return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
}
@@ -2137,13 +1998,13 @@
}
}
- status_t ret = native_window_get_compositor_timing(s->win.get(),
+ int ret = native_window_get_compositor_timing(s->getNativeWindow(),
compositeDeadline, compositeInterval, compositeToPresentLatency);
switch (ret) {
- case NO_ERROR:
+ case 0:
return EGL_TRUE;
- case INVALID_OPERATION:
+ case -ENOSYS:
return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
default:
// This should not happen. Return an error that is not in the spec
@@ -2170,7 +2031,7 @@
egl_surface_t const * const s = get_surface(surface);
- ANativeWindow* window = s->win.get();
+ ANativeWindow* window = s->getNativeWindow();
if (!window) {
return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
}
@@ -2203,7 +2064,7 @@
egl_surface_t const * const s = get_surface(surface);
- if (!s->win.get()) {
+ if (!s->getNativeWindow()) {
return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
}
@@ -2255,19 +2116,19 @@
}
}
- status_t ret = native_window_get_frame_timestamps(s->win.get(), frameId,
+ int ret = native_window_get_frame_timestamps(s->getNativeWindow(), frameId,
requestedPresentTime, acquireTime, latchTime, firstRefreshStartTime,
lastRefreshStartTime, gpuCompositionDoneTime, displayPresentTime,
displayRetireTime, dequeueReadyTime, releaseTime);
switch (ret) {
- case NO_ERROR:
+ case 0:
return EGL_TRUE;
- case NAME_NOT_FOUND:
+ case -ENOENT:
return setError(EGL_BAD_ACCESS, (EGLBoolean)EGL_FALSE);
- case INVALID_OPERATION:
+ case -ENOSYS:
return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
- case BAD_VALUE:
+ case -EINVAL:
return setError(EGL_BAD_PARAMETER, (EGLBoolean)EGL_FALSE);
default:
// This should not happen. Return an error that is not in the spec
@@ -2294,7 +2155,7 @@
egl_surface_t const * const s = get_surface(surface);
- ANativeWindow* window = s->win.get();
+ ANativeWindow* window = s->getNativeWindow();
if (!window) {
return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
}
diff --git a/opengl/libs/EGL/egl_cache.cpp b/opengl/libs/EGL/egl_cache.cpp
index e46716c..dc1a4af 100644
--- a/opengl/libs/EGL/egl_cache.cpp
+++ b/opengl/libs/EGL/egl_cache.cpp
@@ -20,11 +20,16 @@
#include "egl_display.h"
+
+#include <private/EGL/cache.h>
+
#include <inttypes.h>
#include <sys/mman.h>
#include <sys/stat.h>
-#include <utils/Thread.h>
+#include <thread>
+
+#include <log/log.h>
// Cache size limits.
static const size_t maxKeySize = 12 * 1024;
@@ -44,6 +49,11 @@
#define BC_EXT_STR "EGL_ANDROID_blob_cache"
+// called from android_view_ThreadedRenderer.cpp
+void egl_set_cache_filename(const char* filename) {
+ egl_cache_t::get()->setCacheFilename(filename);
+}
+
//
// Callback functions passed to EGL.
//
@@ -61,8 +71,7 @@
// egl_cache_t definition
//
egl_cache_t::egl_cache_t() :
- mInitialized(false),
- mBlobCache(NULL) {
+ mInitialized(false) {
}
egl_cache_t::~egl_cache_t() {
@@ -75,7 +84,7 @@
}
void egl_cache_t::initialize(egl_display_t *display) {
- Mutex::Autolock lock(mMutex);
+ std::lock_guard<std::mutex> lock(mMutex);
egl_connection_t* const cnx = &gEGLImpl;
if (cnx->dso && cnx->major >= 0 && cnx->minor >= 0) {
@@ -113,14 +122,14 @@
}
void egl_cache_t::terminate() {
- Mutex::Autolock lock(mMutex);
+ std::lock_guard<std::mutex> lock(mMutex);
saveBlobCacheLocked();
mBlobCache = NULL;
}
void egl_cache_t::setBlob(const void* key, EGLsizeiANDROID keySize,
const void* value, EGLsizeiANDROID valueSize) {
- Mutex::Autolock lock(mMutex);
+ std::lock_guard<std::mutex> lock(mMutex);
if (keySize < 0 || valueSize < 0) {
ALOGW("EGL_ANDROID_blob_cache set: negative sizes are not allowed");
@@ -128,38 +137,27 @@
}
if (mInitialized) {
- sp<BlobCache> bc = getBlobCacheLocked();
+ BlobCache* bc = getBlobCacheLocked();
bc->set(key, keySize, value, valueSize);
if (!mSavePending) {
- class DeferredSaveThread : public Thread {
- public:
- DeferredSaveThread() : Thread(false) {}
-
- virtual bool threadLoop() {
- sleep(deferredSaveDelay);
- egl_cache_t* c = egl_cache_t::get();
- Mutex::Autolock lock(c->mMutex);
- if (c->mInitialized) {
- c->saveBlobCacheLocked();
- }
- c->mSavePending = false;
- return false;
- }
- };
-
- // The thread will hold a strong ref to itself until it has finished
- // running, so there's no need to keep a ref around.
- sp<Thread> deferredSaveThread(new DeferredSaveThread());
mSavePending = true;
- deferredSaveThread->run("DeferredSaveThread");
+ std::thread deferredSaveThread([this]() {
+ sleep(deferredSaveDelay);
+ std::lock_guard<std::mutex> lock(mMutex);
+ if (mInitialized) {
+ saveBlobCacheLocked();
+ }
+ mSavePending = false;
+ });
+ deferredSaveThread.detach();
}
}
}
EGLsizeiANDROID egl_cache_t::getBlob(const void* key, EGLsizeiANDROID keySize,
void* value, EGLsizeiANDROID valueSize) {
- Mutex::Autolock lock(mMutex);
+ std::lock_guard<std::mutex> lock(mMutex);
if (keySize < 0 || valueSize < 0) {
ALOGW("EGL_ANDROID_blob_cache set: negative sizes are not allowed");
@@ -167,23 +165,23 @@
}
if (mInitialized) {
- sp<BlobCache> bc = getBlobCacheLocked();
+ BlobCache* bc = getBlobCacheLocked();
return bc->get(key, keySize, value, valueSize);
}
return 0;
}
void egl_cache_t::setCacheFilename(const char* filename) {
- Mutex::Autolock lock(mMutex);
+ std::lock_guard<std::mutex> lock(mMutex);
mFilename = filename;
}
-sp<BlobCache> egl_cache_t::getBlobCacheLocked() {
- if (mBlobCache == NULL) {
- mBlobCache = new BlobCache(maxKeySize, maxValueSize, maxTotalSize);
+BlobCache* egl_cache_t::getBlobCacheLocked() {
+ if (mBlobCache == nullptr) {
+ mBlobCache.reset(new BlobCache(maxKeySize, maxValueSize, maxTotalSize));
loadBlobCacheLocked();
}
- return mBlobCache;
+ return mBlobCache.get();
}
static uint32_t crc32c(const uint8_t* buf, size_t len) {
@@ -206,7 +204,7 @@
if (mFilename.length() > 0 && mBlobCache != NULL) {
size_t cacheSize = mBlobCache->getFlattenedSize();
size_t headerSize = cacheFileHeaderSize;
- const char* fname = mFilename.string();
+ const char* fname = mFilename.c_str();
// Try to create the file with no permissions so we can write it
// without anyone trying to read it.
@@ -241,8 +239,8 @@
return;
}
- status_t err = mBlobCache->flatten(buf + headerSize, cacheSize);
- if (err != OK) {
+ int err = mBlobCache->flatten(buf + headerSize, cacheSize);
+ if (err < 0) {
ALOGE("error writing cache contents: %s (%d)", strerror(-err),
-err);
delete [] buf;
@@ -275,10 +273,10 @@
if (mFilename.length() > 0) {
size_t headerSize = cacheFileHeaderSize;
- int fd = open(mFilename.string(), O_RDONLY, 0);
+ int fd = open(mFilename.c_str(), O_RDONLY, 0);
if (fd == -1) {
if (errno != ENOENT) {
- ALOGE("error opening cache file %s: %s (%d)", mFilename.string(),
+ ALOGE("error opening cache file %s: %s (%d)", mFilename.c_str(),
strerror(errno), errno);
}
return;
@@ -323,8 +321,8 @@
return;
}
- status_t err = mBlobCache->unflatten(buf + headerSize, cacheSize);
- if (err != OK) {
+ int err = mBlobCache->unflatten(buf + headerSize, cacheSize);
+ if (err < 0) {
ALOGE("error reading cache contents: %s (%d)", strerror(-err),
-err);
munmap(buf, fileSize);
diff --git a/opengl/libs/EGL/egl_cache.h b/opengl/libs/EGL/egl_cache.h
index e7f1712..56360f0 100644
--- a/opengl/libs/EGL/egl_cache.h
+++ b/opengl/libs/EGL/egl_cache.h
@@ -20,10 +20,11 @@
#include <EGL/egl.h>
#include <EGL/eglext.h>
-#include <utils/BlobCache.h>
-#include <utils/Mutex.h>
-#include <utils/String8.h>
-#include <utils/StrongPointer.h>
+#include "BlobCache.h"
+
+#include <memory>
+#include <mutex>
+#include <string>
// ----------------------------------------------------------------------------
namespace android {
@@ -79,7 +80,7 @@
// key/value blob pairs. If the BlobCache object has not yet been created,
// this will do so, loading the serialized cache contents from disk if
// possible.
- sp<BlobCache> getBlobCacheLocked();
+ BlobCache* getBlobCacheLocked();
// saveBlobCache attempts to save the current contents of mBlobCache to
// disk.
@@ -100,14 +101,14 @@
// mBlobCache is the cache in which the key/value blob pairs are stored. It
// is initially NULL, and will be initialized by getBlobCacheLocked the
// first time it's needed.
- sp<BlobCache> mBlobCache;
+ std::unique_ptr<BlobCache> mBlobCache;
// mFilename is the name of the file for storing cache contents in between
// program invocations. It is initialized to an empty string at
// construction time, and can be set with the setCacheFilename method. An
// empty string indicates that the cache should not be saved to or restored
// from disk.
- String8 mFilename;
+ std::string mFilename;
// mSavePending indicates whether or not a deferred save operation is
// pending. Each time a key/value pair is inserted into the cache via
@@ -118,7 +119,7 @@
// mMutex is the mutex used to prevent concurrent access to the member
// variables. It must be locked whenever the member variables are accessed.
- mutable Mutex mMutex;
+ mutable std::mutex mMutex;
// sCache is the singleton egl_cache_t object.
static egl_cache_t sCache;
diff --git a/opengl/libs/EGL/egl_display.cpp b/opengl/libs/EGL/egl_display.cpp
index c804fa7..b696920 100644
--- a/opengl/libs/EGL/egl_display.cpp
+++ b/opengl/libs/EGL/egl_display.cpp
@@ -21,14 +21,15 @@
#include "../egl_impl.h"
+#include <private/EGL/display.h>
+
#include "egl_cache.h"
#include "egl_object.h"
#include "egl_tls.h"
+#include "egl_trace.h"
#include "Loader.h"
#include <cutils/properties.h>
-#include <utils/Trace.h>
-
// ----------------------------------------------------------------------------
namespace android {
// ----------------------------------------------------------------------------
@@ -55,6 +56,11 @@
return false;
}
+int egl_get_init_count(EGLDisplay dpy) {
+ egl_display_t* eglDisplay = egl_display_t::get(dpy);
+ return eglDisplay ? eglDisplay->getRefsCount() : 0;
+}
+
egl_display_t egl_display_t::sDisplay[NUM_DISPLAYS];
egl_display_t::egl_display_t() :
@@ -75,18 +81,18 @@
}
void egl_display_t::addObject(egl_object_t* object) {
- Mutex::Autolock _l(lock);
- objects.add(object);
+ std::lock_guard<std::mutex> _l(lock);
+ objects.insert(object);
}
void egl_display_t::removeObject(egl_object_t* object) {
- Mutex::Autolock _l(lock);
- objects.remove(object);
+ std::lock_guard<std::mutex> _l(lock);
+ objects.erase(object);
}
bool egl_display_t::getObject(egl_object_t* object) const {
- Mutex::Autolock _l(lock);
- if (objects.indexOf(object) >= 0) {
+ std::lock_guard<std::mutex> _l(lock);
+ if (objects.find(object) != objects.end()) {
if (object->getDisplay() == this) {
object->incRef();
return true;
@@ -104,7 +110,7 @@
EGLDisplay egl_display_t::getDisplay(EGLNativeDisplayType display) {
- Mutex::Autolock _l(lock);
+ std::lock_guard<std::mutex> _l(lock);
ATRACE_CALL();
// get our driver loader
@@ -125,24 +131,26 @@
EGLBoolean egl_display_t::initialize(EGLint *major, EGLint *minor) {
- {
- Mutex::Autolock _rf(refLock);
-
+ { // scope for refLock
+ std::unique_lock<std::mutex> _l(refLock);
refs++;
if (refs > 1) {
if (major != NULL)
*major = VERSION_MAJOR;
if (minor != NULL)
*minor = VERSION_MINOR;
- while(!eglIsInitialized) refCond.wait(refLock);
+ while(!eglIsInitialized) {
+ refCond.wait(_l);
+ }
return EGL_TRUE;
}
-
- while(eglIsInitialized) refCond.wait(refLock);
+ while(eglIsInitialized) {
+ refCond.wait(_l);
+ }
}
- {
- Mutex::Autolock _l(lock);
+ { // scope for lock
+ std::lock_guard<std::mutex> _l(lock);
setGLHooksThreadSpecific(&gHooksNoContext);
@@ -179,20 +187,19 @@
}
// the query strings are per-display
- mVendorString.setTo(sVendorString);
- mVersionString.setTo(sVersionString);
- mClientApiString.setTo(sClientApiString);
+ mVendorString = sVendorString;
+ mVersionString = sVersionString;
+ mClientApiString = sClientApiString;
- mExtensionString.setTo(gBuiltinExtensionString);
+ mExtensionString = gBuiltinExtensionString;
char const* start = gExtensionString;
do {
// length of the extension name
size_t len = strcspn(start, " ");
if (len) {
// NOTE: we could avoid the copy if we had strnstr.
- const String8 ext(start, len);
- if (findExtension(disp.queryString.extensions, ext.string(),
- len)) {
+ const std::string ext(start, len);
+ if (findExtension(disp.queryString.extensions, ext.c_str(), len)) {
mExtensionString.append(ext + " ");
}
// advance to the next extension name, skipping the space.
@@ -220,10 +227,10 @@
*minor = VERSION_MINOR;
}
- {
- Mutex::Autolock _rf(refLock);
+ { // scope for refLock
+ std::unique_lock<std::mutex> _l(refLock);
eglIsInitialized = true;
- refCond.broadcast();
+ refCond.notify_all();
}
return EGL_TRUE;
@@ -231,8 +238,8 @@
EGLBoolean egl_display_t::terminate() {
- {
- Mutex::Autolock _rl(refLock);
+ { // scope for refLock
+ std::unique_lock<std::mutex> _rl(refLock);
if (refs == 0) {
/*
* From the EGL spec (3.2):
@@ -252,8 +259,8 @@
EGLBoolean res = EGL_FALSE;
- {
- Mutex::Autolock _l(lock);
+ { // scope for lock
+ std::lock_guard<std::mutex> _l(lock);
egl_connection_t* const cnx = &gEGLImpl;
if (cnx->dso && disp.state == egl_display_t::INITIALIZED) {
@@ -268,15 +275,14 @@
// Reset the extension string since it will be regenerated if we get
// reinitialized.
- mExtensionString.setTo("");
+ mExtensionString.clear();
// Mark all objects remaining in the list as terminated, unless
// there are no reference to them, it which case, we're free to
// delete them.
size_t count = objects.size();
ALOGW_IF(count, "eglTerminate() called w/ %zu objects remaining", count);
- for (size_t i=0 ; i<count ; i++) {
- egl_object_t* o = objects.itemAt(i);
+ for (auto o : objects) {
o->destroy();
}
@@ -284,10 +290,10 @@
objects.clear();
}
- {
- Mutex::Autolock _rl(refLock);
+ { // scope for refLock
+ std::unique_lock<std::mutex> _rl(refLock);
eglIsInitialized = false;
- refCond.broadcast();
+ refCond.notify_all();
}
return res;
@@ -312,7 +318,7 @@
SurfaceRef _cur_d(cur_c ? get_surface(cur_c->draw) : NULL);
{ // scope for the lock
- Mutex::Autolock _l(lock);
+ std::lock_guard<std::mutex> _l(lock);
cur_c->onLooseCurrent();
}
@@ -338,7 +344,7 @@
SurfaceRef _cur_d(cur_c ? get_surface(cur_c->draw) : NULL);
{ // scope for the lock
- Mutex::Autolock _l(lock);
+ std::lock_guard<std::mutex> _l(lock);
if (c) {
result = c->cnx->egl.eglMakeCurrent(
disp.dpy, impl_draw, impl_read, impl_ctx);
@@ -370,7 +376,7 @@
if (!nameLen) {
nameLen = strlen(name);
}
- return findExtension(mExtensionString.string(), name, nameLen);
+ return findExtension(mExtensionString.c_str(), name, nameLen);
}
// ----------------------------------------------------------------------------
diff --git a/opengl/libs/EGL/egl_display.h b/opengl/libs/EGL/egl_display.h
index f5e7294..661f47e 100644
--- a/opengl/libs/EGL/egl_display.h
+++ b/opengl/libs/EGL/egl_display.h
@@ -21,14 +21,15 @@
#include <stdint.h>
#include <stddef.h>
+#include <condition_variable>
+#include <mutex>
+#include <string>
+#include <unordered_set>
+
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <cutils/compiler.h>
-#include <utils/SortedVector.h>
-#include <utils/Condition.h>
-#include <utils/Mutex.h>
-#include <utils/String8.h>
#include "egldefs.h"
#include "../hooks.h"
@@ -80,10 +81,10 @@
inline bool isValid() const { return magic == '_dpy'; }
inline bool isAlive() const { return isValid(); }
- char const * getVendorString() const { return mVendorString.string(); }
- char const * getVersionString() const { return mVersionString.string(); }
- char const * getClientApiString() const { return mClientApiString.string(); }
- char const * getExtensionString() const { return mExtensionString.string(); }
+ char const * getVendorString() const { return mVendorString.c_str(); }
+ char const * getVersionString() const { return mVersionString.c_str(); }
+ char const * getClientApiString() const { return mClientApiString.c_str(); }
+ char const * getExtensionString() const { return mExtensionString.c_str(); }
bool haveExtension(const char* name, size_t nameLen = 0) const;
@@ -116,13 +117,14 @@
uint32_t refs;
bool eglIsInitialized;
- mutable Mutex lock, refLock;
- mutable Condition refCond;
- SortedVector<egl_object_t*> objects;
- String8 mVendorString;
- String8 mVersionString;
- String8 mClientApiString;
- String8 mExtensionString;
+ mutable std::mutex lock;
+ mutable std::mutex refLock;
+ mutable std::condition_variable refCond;
+ std::unordered_set<egl_object_t*> objects;
+ std::string mVendorString;
+ std::string mVersionString;
+ std::string mClientApiString;
+ std::string mExtensionString;
};
// ----------------------------------------------------------------------------
diff --git a/opengl/libs/EGL/egl_object.cpp b/opengl/libs/EGL/egl_object.cpp
index b553d71..7ed34be 100644
--- a/opengl/libs/EGL/egl_object.cpp
+++ b/opengl/libs/EGL/egl_object.cpp
@@ -60,21 +60,24 @@
egl_connection_t const* cnx) :
egl_object_t(dpy), surface(surface), config(config), win(win), cnx(cnx),
connected(true)
-{}
+{
+ if (win) {
+ win->incStrong(this);
+ }
+}
egl_surface_t::~egl_surface_t() {
- ANativeWindow* const window = win.get();
- if (window != NULL) {
+ if (win != NULL) {
disconnect();
+ win->decStrong(this);
}
}
void egl_surface_t::disconnect() {
- ANativeWindow* const window = win.get();
- if (window != NULL && connected) {
- native_window_set_buffers_format(window, 0);
- if (native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL)) {
- ALOGW("EGLNativeWindowType %p disconnect failed", window);
+ if (win != NULL && connected) {
+ native_window_set_buffers_format(win, 0);
+ if (native_window_api_disconnect(win, NATIVE_WINDOW_API_EGL)) {
+ ALOGW("EGLNativeWindowType %p disconnect failed", win);
}
connected = false;
}
@@ -107,22 +110,20 @@
* add the extensions always handled by the wrapper
*/
- if (gl_extensions.isEmpty()) {
+ if (gl_extensions.empty()) {
// call the implementation's glGetString(GL_EXTENSIONS)
const char* exts = (const char *)gEGLImpl.hooks[version]->gl.glGetString(GL_EXTENSIONS);
- gl_extensions.setTo(exts);
- if (gl_extensions.find("GL_EXT_debug_marker") < 0) {
- String8 temp("GL_EXT_debug_marker ");
- temp.append(gl_extensions);
- gl_extensions.setTo(temp);
+ gl_extensions = exts;
+ if (gl_extensions.find("GL_EXT_debug_marker") != std::string::npos) {
+ gl_extensions.insert(0, "GL_EXT_debug_marker ");
}
// tokenize the supported extensions for the glGetStringi() wrapper
std::stringstream ss;
std::string str;
- ss << gl_extensions.string();
+ ss << gl_extensions;
while (ss >> str) {
- tokenized_gl_extensions.push(String8(str.c_str()));
+ tokenized_gl_extensions.push_back(str);
}
}
}
diff --git a/opengl/libs/EGL/egl_object.h b/opengl/libs/EGL/egl_object.h
index f4012ab..8988905 100644
--- a/opengl/libs/EGL/egl_object.h
+++ b/opengl/libs/EGL/egl_object.h
@@ -17,18 +17,20 @@
#ifndef ANDROID_EGL_OBJECT_H
#define ANDROID_EGL_OBJECT_H
+#include <atomic>
#include <stdint.h>
#include <stddef.h>
+#include <string>
+#include <vector>
+
#include <EGL/egl.h>
#include <EGL/eglext.h>
-#include <utils/StrongPointer.h>
-#include <utils/String8.h>
-#include <utils/Vector.h>
-
#include <system/window.h>
+#include <log/log.h>
+
#include "egl_display.h"
// ----------------------------------------------------------------------------
@@ -133,9 +135,16 @@
EGLNativeWindowType win, EGLSurface surface,
egl_connection_t const* cnx);
+ ANativeWindow* getNativeWindow() { return win; }
+ ANativeWindow* getNativeWindow() const { return win; }
+
+ // Try to keep the order of these fields and size unchanged. It's not public API, but
+ // it's not hard to imagine native games accessing them.
EGLSurface surface;
EGLConfig config;
- sp<ANativeWindow> win;
+private:
+ ANativeWindow* win;
+public:
egl_connection_t const* cnx;
private:
bool connected;
@@ -161,8 +170,8 @@
EGLSurface draw;
egl_connection_t const* cnx;
int version;
- String8 gl_extensions;
- Vector<String8> tokenized_gl_extensions;
+ std::string gl_extensions;
+ std::vector<std::string> tokenized_gl_extensions;
};
// ----------------------------------------------------------------------------
diff --git a/opengl/libs/EGL/egl_trace.h b/opengl/libs/EGL/egl_trace.h
new file mode 100644
index 0000000..7664de2
--- /dev/null
+++ b/opengl/libs/EGL/egl_trace.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#if defined(__ANDROID__)
+
+#include <stdint.h>
+
+#include <cutils/trace.h>
+
+// See <cutils/trace.h> for more ATRACE_* macros.
+
+// ATRACE_NAME traces from its location until the end of its enclosing scope.
+#define _PASTE(x, y) x ## y
+#define PASTE(x, y) _PASTE(x,y)
+#define ATRACE_NAME(name) android::EglScopedTrace PASTE(___tracer, __LINE__) (ATRACE_TAG, name)
+
+// ATRACE_CALL is an ATRACE_NAME that uses the current function name.
+#define ATRACE_CALL() ATRACE_NAME(__FUNCTION__)
+
+namespace android {
+
+class EglScopedTrace {
+public:
+ inline EglScopedTrace(uint64_t tag, const char* name) : mTag(tag) {
+ atrace_begin(mTag, name);
+ }
+
+ inline ~EglScopedTrace() {
+ atrace_end(mTag);
+ }
+
+private:
+ uint64_t mTag;
+};
+
+}; // namespace android
+
+#else // !__ANDROID__
+
+#define ATRACE_NAME(...)
+#define ATRACE_CALL()
+
+#endif // __ANDROID__
diff --git a/services/surfaceflinger/DisplayHardware/MiniFence.cpp b/opengl/libs/EGL/include/private/EGL/cache.h
similarity index 62%
copy from services/surfaceflinger/DisplayHardware/MiniFence.cpp
copy to opengl/libs/EGL/include/private/EGL/cache.h
index ecfb063..0a176a8 100644
--- a/services/surfaceflinger/DisplayHardware/MiniFence.cpp
+++ b/opengl/libs/EGL/include/private/EGL/cache.h
@@ -14,29 +14,12 @@
* limitations under the License.
*/
-#include "MiniFence.h"
+#pragma once
-#include <unistd.h>
+#include <cutils/compiler.h>
namespace android {
-const sp<MiniFence> MiniFence::NO_FENCE = sp<MiniFence>(new MiniFence);
+ANDROID_API void egl_set_cache_filename(const char* filename);
-MiniFence::MiniFence() :
- mFenceFd(-1) {
-}
-
-MiniFence::MiniFence(int fenceFd) :
- mFenceFd(fenceFd) {
-}
-
-MiniFence::~MiniFence() {
- if (mFenceFd != -1) {
- close(mFenceFd);
- }
-}
-
-int MiniFence::dup() const {
- return ::dup(mFenceFd);
-}
-}
+} // namespace android
diff --git a/services/surfaceflinger/DisplayHardware/MiniFence.cpp b/opengl/libs/EGL/include/private/EGL/display.h
similarity index 62%
copy from services/surfaceflinger/DisplayHardware/MiniFence.cpp
copy to opengl/libs/EGL/include/private/EGL/display.h
index ecfb063..9560de2 100644
--- a/services/surfaceflinger/DisplayHardware/MiniFence.cpp
+++ b/opengl/libs/EGL/include/private/EGL/display.h
@@ -14,29 +14,14 @@
* limitations under the License.
*/
-#include "MiniFence.h"
+#pragma once
-#include <unistd.h>
+#include <EGL/egl.h>
+
+#include <cutils/compiler.h>
namespace android {
-const sp<MiniFence> MiniFence::NO_FENCE = sp<MiniFence>(new MiniFence);
+ANDROID_API int egl_get_init_count(EGLDisplay dpy);
-MiniFence::MiniFence() :
- mFenceFd(-1) {
-}
-
-MiniFence::MiniFence(int fenceFd) :
- mFenceFd(fenceFd) {
-}
-
-MiniFence::~MiniFence() {
- if (mFenceFd != -1) {
- close(mFenceFd);
- }
-}
-
-int MiniFence::dup() const {
- return ::dup(mFenceFd);
-}
-}
+} // namespace android
diff --git a/services/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk
index a317ea2..1c1db74 100644
--- a/services/surfaceflinger/Android.mk
+++ b/services/surfaceflinger/Android.mk
@@ -25,8 +25,7 @@
DisplayHardware/ComposerHal.cpp \
DisplayHardware/FramebufferSurface.cpp \
DisplayHardware/HWC2.cpp \
- DisplayHardware/HWC2On1Adapter.cpp \
- DisplayHardware/MiniFence.cpp \
+ DisplayHardware/HWComposerBufferCache.cpp \
DisplayHardware/PowerHAL.cpp \
DisplayHardware/VirtualDisplaySurface.cpp \
Effects/Daltonizer.cpp \
@@ -85,39 +84,6 @@
LOCAL_CFLAGS += -DRUNNING_WITHOUT_SYNC_FRAMEWORK
endif
-# The following two BoardConfig variables define (respectively):
-#
-# - The phase offset between hardware vsync and when apps are woken up by the
-# Choreographer callback
-# - The phase offset between hardware vsync and when SurfaceFlinger wakes up
-# to consume input
-#
-# Their values can be tuned to trade off between display pipeline latency (both
-# overall latency and the lengths of the app --> SF and SF --> display phases)
-# and frame delivery jitter (which typically manifests as "jank" or "jerkiness"
-# while interacting with the device). The default values should produce a
-# relatively low amount of jitter at the expense of roughly two frames of
-# app --> display latency, and unless significant testing is performed to avoid
-# increased display jitter (both manual investigation using systrace [1] and
-# automated testing using dumpsys gfxinfo [2] are recommended), they should not
-# be modified.
-#
-# [1] https://developer.android.com/studio/profile/systrace.html
-# [2] https://developer.android.com/training/testing/performance.html
-
-# These are left just for non-treble devices
-ifneq ($(VSYNC_EVENT_PHASE_OFFSET_NS),)
- LOCAL_CFLAGS += -DVSYNC_EVENT_PHASE_OFFSET_NS=$(VSYNC_EVENT_PHASE_OFFSET_NS)
-else
- LOCAL_CFLAGS += -DVSYNC_EVENT_PHASE_OFFSET_NS=1000000
-endif
-
-ifneq ($(SF_VSYNC_EVENT_PHASE_OFFSET_NS),)
- LOCAL_CFLAGS += -DSF_VSYNC_EVENT_PHASE_OFFSET_NS=$(SF_VSYNC_EVENT_PHASE_OFFSET_NS)
-else
- LOCAL_CFLAGS += -DSF_VSYNC_EVENT_PHASE_OFFSET_NS=1000000
-endif
-
ifneq ($(PRESENT_TIME_OFFSET_FROM_VSYNC_NS),)
LOCAL_CFLAGS += -DPRESENT_TIME_OFFSET_FROM_VSYNC_NS=$(PRESENT_TIME_OFFSET_FROM_VSYNC_NS)
else
@@ -152,6 +118,7 @@
libdl \
libfmq \
libhardware \
+ libhwc2on1adapter \
libhidlbase \
libhidltransport \
libhwbinder \
diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
index ae6e0cc..92a7794 100644
--- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
@@ -32,7 +32,6 @@
#include <hardware/hardware.h>
#include <gui/BufferItem.h>
#include <gui/BufferQueue.h>
-#include <gui/GraphicBufferAlloc.h>
#include <gui/Surface.h>
#include <ui/GraphicBuffer.h>
@@ -138,7 +137,7 @@
status_t err = acquireBufferLocked(&item, 0);
if (err == BufferQueue::NO_BUFFER_AVAILABLE) {
#ifdef USE_HWC2
- mHwcBufferCache->getHwcBuffer(mCurrentBufferSlot, mCurrentBuffer,
+ mHwcBufferCache.getHwcBuffer(mCurrentBufferSlot, mCurrentBuffer,
&outSlot, &outBuffer);
#else
outBuffer = mCurrentBuffer;
@@ -179,7 +178,7 @@
outFence = item.mFence;
#ifdef USE_HWC2
- mHwcBufferCache->getHwcBuffer(mCurrentBufferSlot, mCurrentBuffer,
+ mHwcBufferCache.getHwcBuffer(mCurrentBufferSlot, mCurrentBuffer,
&outSlot, &outBuffer);
outDataspace = item.mDataSpace;
#else
diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.h b/services/surfaceflinger/DisplayHardware/FramebufferSurface.h
index 5eea6b6..69a72d7 100644
--- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.h
+++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.h
@@ -18,14 +18,13 @@
#define ANDROID_SF_FRAMEBUFFER_SURFACE_H
#include "DisplaySurface.h"
+#include "HWComposerBufferCache.h"
#include <stdint.h>
#include <sys/types.h>
#include <gui/ConsumerBase.h>
-#include <memory>
-
// ---------------------------------------------------------------------------
namespace android {
// ---------------------------------------------------------------------------
@@ -33,7 +32,6 @@
class Rect;
class String8;
class HWComposer;
-class HWComposerBufferCache;
// ---------------------------------------------------------------------------
@@ -96,8 +94,7 @@
HWComposer& mHwc;
#ifdef USE_HWC2
- std::unique_ptr<HWComposerBufferCache> mHwcBufferCache =
- std::make_unique<HWComposerBufferCache>();
+ HWComposerBufferCache mHwcBufferCache;
// Previous buffer to release after getting an updated retire fence
bool mHasPendingRelease;
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index f03491f..6644bd9 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -47,7 +47,7 @@
#include <log/log.h>
#include "HWComposer.h"
-#include "HWC2On1Adapter.h"
+#include "hwc2on1adapter/HWC2On1Adapter.h"
#include "HWC2.h"
#include "ComposerHal.h"
@@ -267,6 +267,15 @@
return NO_MEMORY;
}
+ if (MAX_VIRTUAL_DISPLAY_DIMENSION != 0 &&
+ (width > MAX_VIRTUAL_DISPLAY_DIMENSION ||
+ height > MAX_VIRTUAL_DISPLAY_DIMENSION)) {
+ ALOGE("createVirtualDisplay: Can't create a virtual display with"
+ " a dimension > %u (tried %u x %u)",
+ MAX_VIRTUAL_DISPLAY_DIMENSION, width, height);
+ return INVALID_OPERATION;
+ }
+
std::shared_ptr<HWC2::Display> display;
auto error = mHwcDevice->createVirtualDisplay(width, height, format,
&display);
@@ -916,41 +925,5 @@
*this = DisplayData();
}
-void HWComposerBufferCache::clear()
-{
- mBuffers.clear();
-}
-
-void HWComposerBufferCache::getHwcBuffer(int slot,
- const sp<GraphicBuffer>& buffer,
- uint32_t* outSlot, sp<GraphicBuffer>* outBuffer)
-{
-#ifdef BYPASS_IHWC
- *outSlot = slot;
- *outBuffer = buffer;
-#else
- if (slot == BufferQueue::INVALID_BUFFER_SLOT || slot < 0) {
- // default to slot 0
- slot = 0;
- }
-
- if (static_cast<size_t>(slot) >= mBuffers.size()) {
- mBuffers.resize(slot + 1);
- }
-
- *outSlot = slot;
-
- if (mBuffers[slot] == buffer) {
- // already cached in HWC, skip sending the buffer
- *outBuffer = nullptr;
- } else {
- *outBuffer = buffer;
-
- // update cache
- mBuffers[slot] = buffer;
- }
-#endif
-}
-
// ---------------------------------------------------------------------------
}; // namespace android
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index 20cca39..117db4a 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -26,8 +26,6 @@
#include <stdint.h>
#include <sys/types.h>
-#include <gui/BufferQueue.h>
-
#include <ui/Fence.h>
#include <utils/BitSet.h>
@@ -236,19 +234,6 @@
mutable std::atomic<bool> mDumpMayLockUp;
};
-class HWComposerBufferCache {
-public:
- void clear();
-
- void getHwcBuffer(int slot, const sp<GraphicBuffer>& buffer,
- uint32_t* outSlot, sp<GraphicBuffer>* outBuffer);
-
-private:
- // a vector as we expect "slot" to be in the range of [0, 63] (that is,
- // less than BufferQueue::NUM_BUFFER_SLOTS).
- std::vector<sp<GraphicBuffer>> mBuffers;
-};
-
// ---------------------------------------------------------------------------
}; // namespace android
diff --git a/services/surfaceflinger/DisplayHardware/HWComposerBufferCache.cpp b/services/surfaceflinger/DisplayHardware/HWComposerBufferCache.cpp
new file mode 100644
index 0000000..6b91224
--- /dev/null
+++ b/services/surfaceflinger/DisplayHardware/HWComposerBufferCache.cpp
@@ -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.
+ */
+
+#include "HWComposerBufferCache.h"
+
+#include <gui/BufferQueue.h>
+
+namespace android {
+
+HWComposerBufferCache::HWComposerBufferCache()
+{
+ mBuffers.reserve(BufferQueue::NUM_BUFFER_SLOTS);
+}
+
+void HWComposerBufferCache::getHwcBuffer(int slot,
+ const sp<GraphicBuffer>& buffer,
+ uint32_t* outSlot, sp<GraphicBuffer>* outBuffer)
+{
+#ifdef BYPASS_IHWC
+ *outSlot = slot;
+ *outBuffer = buffer;
+#else
+ if (slot == BufferQueue::INVALID_BUFFER_SLOT || slot < 0) {
+ // default to slot 0
+ slot = 0;
+ }
+
+ if (static_cast<size_t>(slot) >= mBuffers.size()) {
+ mBuffers.resize(slot + 1);
+ }
+
+ *outSlot = slot;
+
+ if (mBuffers[slot] == buffer) {
+ // already cached in HWC, skip sending the buffer
+ *outBuffer = nullptr;
+ } else {
+ *outBuffer = buffer;
+
+ // update cache
+ mBuffers[slot] = buffer;
+ }
+#endif
+}
+
+} // namespace android
diff --git a/services/surfaceflinger/DisplayHardware/HWComposerBufferCache.h b/services/surfaceflinger/DisplayHardware/HWComposerBufferCache.h
new file mode 100644
index 0000000..a008ca9
--- /dev/null
+++ b/services/surfaceflinger/DisplayHardware/HWComposerBufferCache.h
@@ -0,0 +1,61 @@
+/*
+ * 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_SF_HWCOMPOSERBUFFERCACHE_H
+#define ANDROID_SF_HWCOMPOSERBUFFERCACHE_H
+
+#include <stdint.h>
+
+#include <utils/StrongPointer.h>
+
+#include <vector>
+
+namespace android {
+// ---------------------------------------------------------------------------
+
+class GraphicBuffer;
+
+// With HIDLized hwcomposer HAL, the HAL can maintain a buffer cache for each
+// HWC display and layer. When updating a display target or a layer buffer,
+// we have the option to send the buffer handle over or to request the HAL to
+// retrieve it from its cache. The latter is cheaper since it eliminates the
+// overhead to transfer the handle over the trasport layer, and the overhead
+// for the HAL to clone and retain the handle.
+//
+// To be able to find out whether a buffer is already in the HAL's cache, we
+// use HWComposerBufferCache to mirror the cache in SF.
+class HWComposerBufferCache {
+public:
+ HWComposerBufferCache();
+
+ // Given a buffer queue slot and buffer, return the HWC cache slot and
+ // buffer to be sent to HWC.
+ //
+ // outBuffer is set to buffer when buffer is not in the HWC cache;
+ // otherwise, outBuffer is set to nullptr.
+ void getHwcBuffer(int slot, const sp<GraphicBuffer>& buffer,
+ uint32_t* outSlot, sp<GraphicBuffer>* outBuffer);
+
+private:
+ // a vector as we expect "slot" to be in the range of [0, 63] (that is,
+ // less than BufferQueue::NUM_BUFFER_SLOTS).
+ std::vector<sp<GraphicBuffer>> mBuffers;
+};
+
+// ---------------------------------------------------------------------------
+}; // namespace android
+
+#endif // ANDROID_SF_HWCOMPOSERBUFFERCACHE_H
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
index c5a4f99..6f253ab 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
@@ -224,7 +224,7 @@
#ifdef USE_HWC2
uint32_t hwcSlot = 0;
sp<GraphicBuffer> hwcBuffer;
- mHwcBufferCache->getHwcBuffer(mFbProducerSlot, fbBuffer,
+ mHwcBufferCache.getHwcBuffer(mFbProducerSlot, fbBuffer,
&hwcSlot, &hwcBuffer);
// TODO: Correctly propagate the dataspace from GL composition
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
index fb5fcc8..ee2772a 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
@@ -18,18 +18,16 @@
#define ANDROID_SF_VIRTUAL_DISPLAY_SURFACE_H
#include "DisplaySurface.h"
+#include "HWComposerBufferCache.h"
#include <gui/ConsumerBase.h>
#include <gui/IGraphicBufferProducer.h>
-#include <memory>
-
// ---------------------------------------------------------------------------
namespace android {
// ---------------------------------------------------------------------------
class HWComposer;
-class HWComposerBufferCache;
class IProducerListener;
/* This DisplaySurface implementation supports virtual displays, where GLES
@@ -255,8 +253,7 @@
bool mMustRecompose;
#ifdef USE_HWC2
- std::unique_ptr<HWComposerBufferCache> mHwcBufferCache =
- std::make_unique<HWComposerBufferCache>();
+ HWComposerBufferCache mHwcBufferCache;
#endif
};
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index c3f8665..51984b7 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -167,7 +167,7 @@
// Creates a custom BufferQueue for SurfaceFlingerConsumer to use
sp<IGraphicBufferProducer> producer;
sp<IGraphicBufferConsumer> consumer;
- BufferQueue::createBufferQueue(&producer, &consumer, nullptr, true);
+ BufferQueue::createBufferQueue(&producer, &consumer, true);
mProducer = new MonitoredProducer(producer, mFlinger, this);
mSurfaceFlingerConsumer = new SurfaceFlingerConsumer(consumer, mTextureName, this);
mSurfaceFlingerConsumer->setConsumerUsageBits(getEffectiveUsage(0));
@@ -276,16 +276,6 @@
}
}
-void Layer::onBuffersReleased() {
-#ifdef USE_HWC2
- Mutex::Autolock lock(mHwcBufferCacheMutex);
-
- for (auto info : mHwcBufferCaches) {
- info.second.clear();
- }
-#endif
-}
-
void Layer::onSidebandStreamChanged() {
if (android_atomic_release_cas(false, true, &mSidebandStreamChanged) == 0) {
// mSidebandStreamChanged was false
@@ -780,7 +770,8 @@
const auto& viewport = displayDevice->getViewport();
Region visible = tr.transform(visibleRegion.intersect(viewport));
auto hwcId = displayDevice->getHwcDisplayId();
- auto& hwcLayer = mHwcLayers[hwcId].layer;
+ auto& hwcInfo = mHwcLayers[hwcId];
+ auto& hwcLayer = hwcInfo.layer;
auto error = hwcLayer->setVisibleRegion(visible);
if (error != HWC2::Error::None) {
ALOGE("[%s] Failed to set visible region: %s (%d)", mName.string(),
@@ -809,7 +800,7 @@
}
// Client layers
- if (mHwcLayers[hwcId].forceClientComposition ||
+ if (hwcInfo.forceClientComposition ||
(mActiveBuffer != nullptr && mActiveBuffer->handle == nullptr)) {
ALOGV("[%s] Requesting Client composition", mName.string());
setCompositionType(hwcId, HWC2::Composition::Client);
@@ -858,11 +849,8 @@
uint32_t hwcSlot = 0;
buffer_handle_t hwcHandle = nullptr;
{
- Mutex::Autolock lock(mHwcBufferCacheMutex);
-
- auto& hwcBufferCache = mHwcBufferCaches[hwcId];
sp<GraphicBuffer> hwcBuffer;
- hwcBufferCache.getHwcBuffer(mActiveBufferSlot, mActiveBuffer,
+ hwcInfo.bufferCache.getHwcBuffer(mActiveBufferSlot, mActiveBuffer,
&hwcSlot, &hwcBuffer);
if (hwcBuffer != nullptr) {
hwcHandle = hwcBuffer->handle;
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 0efdf54..6b228b0 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -47,6 +47,7 @@
#include "Transform.h"
#include "DisplayHardware/HWComposer.h"
+#include "DisplayHardware/HWComposerBufferCache.h"
#include "RenderEngine/Mesh.h"
#include "RenderEngine/Texture.h"
@@ -383,20 +384,13 @@
#ifdef USE_HWC2
// -----------------------------------------------------------------------
- void eraseHwcLayer(int32_t hwcId) {
- mHwcLayers.erase(hwcId);
-
- Mutex::Autolock lock(mHwcBufferCacheMutex);
- mHwcBufferCaches.erase(hwcId);
- }
-
bool hasHwcLayer(int32_t hwcId) {
if (mHwcLayers.count(hwcId) == 0) {
return false;
}
if (mHwcLayers[hwcId].layer->isAbandoned()) {
ALOGI("Erasing abandoned layer %s on %d", mName.string(), hwcId);
- eraseHwcLayer(hwcId);
+ mHwcLayers.erase(hwcId);
return false;
}
return true;
@@ -412,11 +406,8 @@
void setHwcLayer(int32_t hwcId, std::shared_ptr<HWC2::Layer>&& layer) {
if (layer) {
mHwcLayers[hwcId].layer = layer;
-
- Mutex::Autolock lock(mHwcBufferCacheMutex);
- mHwcBufferCaches[hwcId] = HWComposerBufferCache();
} else {
- eraseHwcLayer(hwcId);
+ mHwcLayers.erase(hwcId);
}
}
@@ -511,7 +502,6 @@
// Interface implementation for SurfaceFlingerConsumer::ContentsChangedListener
virtual void onFrameAvailable(const BufferItem& item) override;
virtual void onFrameReplaced(const BufferItem& item) override;
- virtual void onBuffersReleased() override;
virtual void onSidebandStreamChanged() override;
void commitTransaction(const State& stateToCommit);
@@ -703,6 +693,7 @@
bool clearClientTarget;
Rect displayFrame;
FloatRect sourceCrop;
+ HWComposerBufferCache bufferCache;
};
// A layer can be attached to multiple displays when operating in mirror mode
@@ -710,12 +701,6 @@
// case we need to keep track. In non-mirror mode, a layer will have only one
// HWCInfo. This map key is a display layerStack.
std::unordered_map<int32_t, HWCInfo> mHwcLayers;
-
- // We need one HWComposerBufferCache for each HWC display. We cannot have
- // HWComposerBufferCache in HWCInfo because HWCInfo can only be accessed
- // from the main thread.
- Mutex mHwcBufferCacheMutex;
- std::unordered_map<int32_t, HWComposerBufferCache> mHwcBufferCaches;
#else
bool mIsGlesComposition;
#endif
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 46f5a1f..ca6d941 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -44,7 +44,6 @@
#include <gui/GuiConfig.h>
#include <gui/IDisplayEventConnection.h>
#include <gui/Surface.h>
-#include <gui/GraphicBufferAlloc.h>
#include <ui/GraphicBufferAllocator.h>
#include <ui/PixelFormat.h>
@@ -102,33 +101,6 @@
using namespace android::hardware::configstore;
using namespace android::hardware::configstore::V1_0;
-// This is the phase offset in nanoseconds of the software vsync event
-// relative to the vsync event reported by HWComposer. The software vsync
-// event is when SurfaceFlinger and Choreographer-based applications run each
-// frame.
-//
-// This phase offset allows adjustment of the minimum latency from application
-// wake-up (by Choregographer) time to the time at which the resulting window
-// image is displayed. This value may be either positive (after the HW vsync)
-// or negative (before the HW vsync). Setting it to 0 will result in a
-// minimum latency of two vsync periods because the app and SurfaceFlinger
-// will run just after the HW vsync. Setting it to a positive number will
-// result in the minimum latency being:
-//
-// (2 * VSYNC_PERIOD - (vsyncPhaseOffsetNs % VSYNC_PERIOD))
-//
-// Note that reducing this latency makes it more likely for the applications
-// to not have their window content image ready in time. When this happens
-// the latency will end up being an additional vsync period, and animations
-// will hiccup. Therefore, this latency should be tuned somewhat
-// conservatively (or at least with awareness of the trade-off being made).
-static int64_t vsyncPhaseOffsetNs = getInt64<
- ISurfaceFlingerConfigs,
- &ISurfaceFlingerConfigs::vsyncEventPhaseOffsetNs>(1000000);
-
-// This is the phase offset at which SurfaceFlinger's composition runs.
-static constexpr int64_t sfVsyncPhaseOffsetNs = SF_VSYNC_EVENT_PHASE_OFFSET_NS;
-
// ---------------------------------------------------------------------------
const String16 sHardwareTest("android.permission.HARDWARE_TEST");
@@ -137,6 +109,8 @@
const String16 sDump("android.permission.DUMP");
// ---------------------------------------------------------------------------
+int64_t SurfaceFlinger::vsyncPhaseOffsetNs;
+int64_t SurfaceFlinger::sfVsyncPhaseOffsetNs;
SurfaceFlinger::SurfaceFlinger()
: BnSurfaceComposer(),
@@ -180,6 +154,13 @@
,mEnterVrMode(false)
#endif
{
+
+ vsyncPhaseOffsetNs = getInt64< ISurfaceFlingerConfigs,
+ &ISurfaceFlingerConfigs::vsyncEventPhaseOffsetNs>(1000000);
+
+ sfVsyncPhaseOffsetNs = getInt64< ISurfaceFlingerConfigs,
+ &ISurfaceFlingerConfigs::vsyncSfEventPhaseOffsetNs>(1000000);
+
ALOGI("SurfaceFlinger is starting");
// debugging stuff...
@@ -340,12 +321,6 @@
return mBuiltinDisplays[id];
}
-sp<IGraphicBufferAlloc> SurfaceFlinger::createGraphicBufferAlloc()
-{
- sp<GraphicBufferAlloc> gba(new GraphicBufferAlloc());
- return gba;
-}
-
void SurfaceFlinger::bootFinished()
{
if (mStartBootAnimThread->join() != NO_ERROR) {
@@ -750,7 +725,7 @@
// We add an additional 1ms to allow for processing time and
// differences between the ideal and actual refresh rate.
info.presentationDeadline = hwConfig->getVsyncPeriod() -
- SF_VSYNC_EVENT_PHASE_OFFSET_NS + 1000000;
+ sfVsyncPhaseOffsetNs + 1000000;
// All non-virtual displays are currently considered secure.
info.secure = true;
@@ -1151,8 +1126,7 @@
sp<IGraphicBufferProducer> producer;
sp<IGraphicBufferConsumer> consumer;
- BufferQueue::createBufferQueue(&producer, &consumer,
- new GraphicBufferAlloc());
+ BufferQueue::createBufferQueue(&producer, &consumer);
sp<FramebufferSurface> fbs = new FramebufferSurface(*mHwc,
DisplayDevice::DISPLAY_PRIMARY, consumer);
@@ -1913,8 +1887,7 @@
sp<IGraphicBufferProducer> producer;
sp<IGraphicBufferProducer> bqProducer;
sp<IGraphicBufferConsumer> bqConsumer;
- BufferQueue::createBufferQueue(&bqProducer, &bqConsumer,
- new GraphicBufferAlloc());
+ BufferQueue::createBufferQueue(&bqProducer, &bqConsumer);
int32_t hwcId = -1;
if (state.isVirtualDisplay()) {
@@ -2546,6 +2519,8 @@
}
status_t SurfaceFlinger::removeLayer(const sp<Layer>& layer) {
+ Mutex::Autolock _l(mStateLock);
+
const auto& p = layer->getParent();
const ssize_t index = (p != nullptr) ? p->removeChild(layer) :
mCurrentState.layersSortedByZ.remove(layer);
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index d63c0bb..e5aa0bb 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -76,7 +76,6 @@
class Client;
class DisplayEventConnection;
class EventThread;
-class IGraphicBufferAlloc;
class Layer;
class LayerDim;
class Surface;
@@ -104,6 +103,31 @@
private HWComposer::EventHandler
{
public:
+
+
+ // This is the phase offset in nanoseconds of the software vsync event
+ // relative to the vsync event reported by HWComposer. The software vsync
+ // event is when SurfaceFlinger and Choreographer-based applications run each
+ // frame.
+ //
+ // This phase offset allows adjustment of the minimum latency from application
+ // wake-up time (by Choreographer) to the time at which the resulting window
+ // image is displayed. This value may be either positive (after the HW vsync)
+ // or negative (before the HW vsync). Setting it to 0 will result in a lower
+ // latency bound of two vsync periods because the app and SurfaceFlinger
+ // will run just after the HW vsync. Setting it to a positive number will
+ // result in the minimum latency being:
+ //
+ // (2 * VSYNC_PERIOD - (vsyncPhaseOffsetNs % VSYNC_PERIOD))
+ //
+ // Note that reducing this latency makes it more likely for the applications
+ // to not have their window content image ready in time. When this happens
+ // the latency will end up being an additional vsync period, and animations
+ // will hiccup. Therefore, this latency should be tuned somewhat
+ // conservatively (or at least with awareness of the trade-off being made).
+ static int64_t vsyncPhaseOffsetNs;
+ static int64_t sfVsyncPhaseOffsetNs;
+
static char const* getServiceName() ANDROID_API {
return "SurfaceFlinger";
}
@@ -203,7 +227,6 @@
*/
virtual sp<ISurfaceComposerClient> createConnection();
virtual sp<ISurfaceComposerClient> createScopedConnection(const sp<IGraphicBufferProducer>& gbp);
- virtual sp<IGraphicBufferAlloc> createGraphicBufferAlloc();
virtual sp<IBinder> createDisplay(const String8& displayName, bool secure);
virtual void destroyDisplay(const sp<IBinder>& display);
virtual sp<IBinder> getBuiltInDisplay(int32_t id);
@@ -659,7 +682,6 @@
std::atomic<bool> mEnterVrMode;
#endif
};
-
}; // namespace android
#endif // ANDROID_SURFACE_FLINGER_H
diff --git a/services/surfaceflinger/SurfaceFlingerConsumer.cpp b/services/surfaceflinger/SurfaceFlingerConsumer.cpp
index 2fcbdba..01226e0 100644
--- a/services/surfaceflinger/SurfaceFlingerConsumer.cpp
+++ b/services/surfaceflinger/SurfaceFlingerConsumer.cpp
@@ -183,7 +183,7 @@
// we don't need to factor that in here. Pad a little to avoid
// weird effects if apps might be requesting times right on the edge.
nsecs_t extraPadding = 0;
- if (VSYNC_EVENT_PHASE_OFFSET_NS == 0) {
+ if (SurfaceFlinger::vsyncPhaseOffsetNs == 0) {
extraPadding = 1000000; // 1ms (6% of 60Hz)
}
@@ -237,19 +237,6 @@
mContentsChangedListener = listener;
}
-void SurfaceFlingerConsumer::onBuffersReleased() {
- sp<ContentsChangedListener> listener;
- { // scope for the lock
- Mutex::Autolock lock(mMutex);
- ALOG_ASSERT(mFrameAvailableListener.unsafe_get() == mContentsChangedListener.unsafe_get());
- listener = mContentsChangedListener.promote();
- }
-
- if (listener != NULL) {
- listener->onBuffersReleased();
- }
-}
-
void SurfaceFlingerConsumer::onSidebandStreamChanged() {
sp<ContentsChangedListener> listener;
{ // scope for the lock
diff --git a/services/surfaceflinger/SurfaceFlingerConsumer.h b/services/surfaceflinger/SurfaceFlingerConsumer.h
index cfa70ed..1126233 100644
--- a/services/surfaceflinger/SurfaceFlingerConsumer.h
+++ b/services/surfaceflinger/SurfaceFlingerConsumer.h
@@ -35,7 +35,6 @@
static const status_t BUFFER_REJECTED = UNKNOWN_ERROR + 8;
struct ContentsChangedListener: public FrameAvailableListener {
- virtual void onBuffersReleased() = 0;
virtual void onSidebandStreamChanged() = 0;
};
@@ -93,7 +92,6 @@
FrameEventHistoryDelta* outDelta) override;
private:
- virtual void onBuffersReleased();
virtual void onSidebandStreamChanged();
wp<ContentsChangedListener> mContentsChangedListener;
diff --git a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
index 6cd7152..147232c 100644
--- a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
+++ b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
@@ -42,7 +42,6 @@
#include <gui/GuiConfig.h>
#include <gui/IDisplayEventConnection.h>
#include <gui/Surface.h>
-#include <gui/GraphicBufferAlloc.h>
#include <ui/GraphicBufferAllocator.h>
#include <ui/HdrCapabilities.h>
@@ -84,6 +83,9 @@
#include "RenderEngine/RenderEngine.h"
#include <cutils/compiler.h>
+#include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
+#include <configstore/Utils.h>
+
#define DISPLAY_COUNT 1
/*
@@ -95,40 +97,19 @@
EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name);
namespace android {
-
-// This is the phase offset in nanoseconds of the software vsync event
-// relative to the vsync event reported by HWComposer. The software vsync
-// event is when SurfaceFlinger and Choreographer-based applications run each
-// frame.
-//
-// This phase offset allows adjustment of the minimum latency from application
-// wake-up (by Choregographer) time to the time at which the resulting window
-// image is displayed. This value may be either positive (after the HW vsync)
-// or negative (before the HW vsync). Setting it to 0 will result in a
-// minimum latency of two vsync periods because the app and SurfaceFlinger
-// will run just after the HW vsync. Setting it to a positive number will
-// result in the minimum latency being:
-//
-// (2 * VSYNC_PERIOD - (vsyncPhaseOffsetNs % VSYNC_PERIOD))
-//
-// Note that reducing this latency makes it more likely for the applications
-// to not have their window content image ready in time. When this happens
-// the latency will end up being an additional vsync period, and animations
-// will hiccup. Therefore, this latency should be tuned somewhat
-// conservatively (or at least with awareness of the trade-off being made).
-static const int64_t vsyncPhaseOffsetNs = VSYNC_EVENT_PHASE_OFFSET_NS;
-
-// This is the phase offset at which SurfaceFlinger's composition runs.
-static const int64_t sfVsyncPhaseOffsetNs = SF_VSYNC_EVENT_PHASE_OFFSET_NS;
-
// ---------------------------------------------------------------------------
+using namespace android::hardware::configstore;
+using namespace android::hardware::configstore::V1_0;
+
const String16 sHardwareTest("android.permission.HARDWARE_TEST");
const String16 sAccessSurfaceFlinger("android.permission.ACCESS_SURFACE_FLINGER");
const String16 sReadFramebuffer("android.permission.READ_FRAME_BUFFER");
const String16 sDump("android.permission.DUMP");
// ---------------------------------------------------------------------------
+int64_t SurfaceFlinger::vsyncPhaseOffsetNs;
+int64_t SurfaceFlinger::sfVsyncPhaseOffsetNs;
SurfaceFlinger::SurfaceFlinger()
: BnSurfaceComposer(),
@@ -165,6 +146,12 @@
mLastSwapTime(0),
mNumLayers(0)
{
+ vsyncPhaseOffsetNs = getInt64< ISurfaceFlingerConfigs,
+ &ISurfaceFlingerConfigs::vsyncEventPhaseOffsetNs>(1000000);
+
+ sfVsyncPhaseOffsetNs = getInt64< ISurfaceFlingerConfigs,
+ &ISurfaceFlingerConfigs::vsyncSfEventPhaseOffsetNs>(1000000);
+
ALOGI("SurfaceFlinger is starting");
char value[PROPERTY_VALUE_MAX];
@@ -307,12 +294,6 @@
return mBuiltinDisplays[id];
}
-sp<IGraphicBufferAlloc> SurfaceFlinger::createGraphicBufferAlloc()
-{
- sp<GraphicBufferAlloc> gba(new GraphicBufferAlloc());
- return gba;
-}
-
void SurfaceFlinger::bootFinished()
{
if (mStartBootAnimThread->join() != NO_ERROR) {
@@ -549,8 +530,7 @@
sp<IGraphicBufferProducer> producer;
sp<IGraphicBufferConsumer> consumer;
- BufferQueue::createBufferQueue(&producer, &consumer,
- new GraphicBufferAlloc());
+ BufferQueue::createBufferQueue(&producer, &consumer);
sp<FramebufferSurface> fbs = new FramebufferSurface(*mHwc, i,
consumer);
@@ -719,7 +699,7 @@
info.xdpi = xdpi;
info.ydpi = ydpi;
info.fps = float(1e9 / hwConfig.refresh);
- info.appVsyncOffset = VSYNC_EVENT_PHASE_OFFSET_NS;
+ info.appVsyncOffset = vsyncPhaseOffsetNs;
// This is how far in advance a buffer must be queued for
// presentation at a given time. If you want a buffer to appear
@@ -734,7 +714,7 @@
// We add an additional 1ms to allow for processing time and
// differences between the ideal and actual refresh rate.
info.presentationDeadline =
- hwConfig.refresh - SF_VSYNC_EVENT_PHASE_OFFSET_NS + 1000000;
+ hwConfig.refresh - sfVsyncPhaseOffsetNs + 1000000;
// All non-virtual displays are currently considered secure.
info.secure = true;
@@ -1680,8 +1660,7 @@
sp<IGraphicBufferProducer> producer;
sp<IGraphicBufferProducer> bqProducer;
sp<IGraphicBufferConsumer> bqConsumer;
- BufferQueue::createBufferQueue(&bqProducer, &bqConsumer,
- new GraphicBufferAlloc());
+ BufferQueue::createBufferQueue(&bqProducer, &bqConsumer);
int32_t hwcDisplayId = -1;
if (state.isVirtualDisplay()) {
@@ -2317,6 +2296,8 @@
}
status_t SurfaceFlinger::removeLayer(const sp<Layer>& layer) {
+ Mutex::Autolock _l(mStateLock);
+
const auto& p = layer->getParent();
const ssize_t index = (p != nullptr) ? p->removeChild(layer) :
mCurrentState.layersSortedByZ.remove(layer);
diff --git a/services/vr/sensord/Android.mk b/services/vr/sensord/Android.mk
index e213bd6..f86664e 100644
--- a/services/vr/sensord/Android.mk
+++ b/services/vr/sensord/Android.mk
@@ -14,6 +14,8 @@
LOCAL_PATH := $(call my-dir)
+SENSORD_EXTEND ?= libsensordextensionstub
+
sourceFiles := \
pose_service.cpp \
sensord.cpp \
@@ -42,6 +44,7 @@
liblog \
libhardware \
libutils \
+ $(SENSORD_EXTEND) \
cFlags := -DLOG_TAG=\"sensord\" \
-DTRACE=0
@@ -67,3 +70,8 @@
LOCAL_SRC_FILES := test/poselatencytest.cpp
LOCAL_MODULE := poselatencytest
include $(BUILD_EXECUTABLE)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := libsensordextensionstub
+LOCAL_SRC_FILES := sensord_extension.cpp
+include $(BUILD_SHARED_LIBRARY)
diff --git a/services/vr/sensord/sensord.cpp b/services/vr/sensord/sensord.cpp
index 0a75318..db39152 100644
--- a/services/vr/sensord/sensord.cpp
+++ b/services/vr/sensord/sensord.cpp
@@ -14,6 +14,7 @@
#include "sensor_ndk_thread.h"
#include "sensor_service.h"
#include "sensor_thread.h"
+#include "sensord_extension.h"
using android::dvr::PoseService;
using android::dvr::SensorHalThread;
@@ -22,10 +23,13 @@
using android::dvr::SensorThread;
using android::pdx::Service;
using android::pdx::ServiceDispatcher;
+using android::dvr::SensordExtension;
int main(int, char**) {
ALOGI("Starting up...");
+ SensordExtension::run();
+
// We need to be able to create endpoints with full perms.
umask(0000);
diff --git a/services/vr/sensord/sensord_extension.cpp b/services/vr/sensord/sensord_extension.cpp
new file mode 100644
index 0000000..6cd7db3
--- /dev/null
+++ b/services/vr/sensord/sensord_extension.cpp
@@ -0,0 +1,4 @@
+#include "sensord_extension.h"
+
+void android::dvr::SensordExtension::run() {
+}
diff --git a/services/vr/sensord/sensord_extension.h b/services/vr/sensord/sensord_extension.h
new file mode 100644
index 0000000..e553eed
--- /dev/null
+++ b/services/vr/sensord/sensord_extension.h
@@ -0,0 +1,16 @@
+#ifndef ANDROID_DVR_SENSORD_EXTENSION_H_
+#define ANDROID_DVR_SENSORD_EXTENSION_H_
+
+namespace android {
+namespace dvr {
+
+// Allows sensord to be extended with additional code.
+class SensordExtension {
+ public:
+ static void run();
+};
+
+} // namespace dvr
+} // namespace android
+
+#endif // ANDROID_DVR_SENSORD_EXTENSION_H_
diff --git a/services/vr/virtual_touchpad/Android.mk b/services/vr/virtual_touchpad/Android.mk
index b78eb99..88b2dd9 100644
--- a/services/vr/virtual_touchpad/Android.mk
+++ b/services/vr/virtual_touchpad/Android.mk
@@ -9,7 +9,8 @@
VirtualTouchpadEvdev.cpp
shared_libs := \
- libbase
+ libbase \
+ libutils
include $(CLEAR_VARS)
LOCAL_SRC_FILES := $(src)
@@ -24,21 +25,23 @@
# Touchpad unit tests.
-test_src_files := \
- tests/VirtualTouchpad_test.cpp
-
-static_libs := \
+test_static_libs := \
libbase \
libcutils \
- libutils \
libvirtualtouchpad
+test_shared_libs := \
+ libutils
+
+test_src_files := \
+ tests/VirtualTouchpad_test.cpp
+
$(foreach file,$(test_src_files), \
$(eval include $(CLEAR_VARS)) \
$(eval LOCAL_SRC_FILES := $(file)) \
$(eval LOCAL_C_INCLUDES := $(LOCAL_PATH)/include) \
- $(eval LOCAL_STATIC_LIBRARIES := $(static_libs)) \
- $(eval LOCAL_SHARED_LIBRARIES := $(shared_libs)) \
+ $(eval LOCAL_STATIC_LIBRARIES := $(test_static_libs)) \
+ $(eval LOCAL_SHARED_LIBRARIES := $(test_shared_libs)) \
$(eval LOCAL_CPPFLAGS += -std=c++11) \
$(eval LOCAL_LDLIBS := -llog) \
$(eval LOCAL_MODULE := $(notdir $(file:%.cpp=%))) \
@@ -70,7 +73,7 @@
LOCAL_STATIC_LIBRARIES := $(static_libs)
LOCAL_SHARED_LIBRARIES := $(shared_libs)
LOCAL_CPPFLAGS += -std=c++11
-LOCAL_CFLAGS += -DLOG_TAG=\"VrVirtualTouchpad\"
+LOCAL_CFLAGS += -DLOG_TAG=\"VrVirtualTouchpad\" -DSELINUX_ACCESS_CONTROL
LOCAL_LDLIBS := -llog
LOCAL_MODULE := virtual_touchpad
LOCAL_MODULE_TAGS := optional
diff --git a/services/vr/virtual_touchpad/EvdevInjector.cpp b/services/vr/virtual_touchpad/EvdevInjector.cpp
index d8a1dfa..b4c0a52 100644
--- a/services/vr/virtual_touchpad/EvdevInjector.cpp
+++ b/services/vr/virtual_touchpad/EvdevInjector.cpp
@@ -307,5 +307,11 @@
return 0;
}
+void EvdevInjector::dumpInternal(String8& result) {
+ result.append("[injector]\n");
+ result.appendFormat("state = %d\n", static_cast<int>(state_));
+ result.appendFormat("error = %d\n\n", error_);
+}
+
} // namespace dvr
} // namespace android
diff --git a/services/vr/virtual_touchpad/EvdevInjector.h b/services/vr/virtual_touchpad/EvdevInjector.h
index 1b1c4da..c69dbef 100644
--- a/services/vr/virtual_touchpad/EvdevInjector.h
+++ b/services/vr/virtual_touchpad/EvdevInjector.h
@@ -3,6 +3,7 @@
#include <android-base/unique_fd.h>
#include <linux/uinput.h>
+#include <utils/String8.h>
#include <cstdint>
#include <memory>
@@ -99,6 +100,8 @@
int SendMultiTouchXY(int32_t slot, int32_t id, int32_t x, int32_t y);
int SendMultiTouchLift(int32_t slot);
+ void dumpInternal(String8& result);
+
protected:
// Must be called only between construction and ConfigureBegin().
inline void SetUInputForTesting(UInput* uinput) { uinput_ = uinput; }
diff --git a/services/vr/virtual_touchpad/VirtualTouchpadClient.cpp b/services/vr/virtual_touchpad/VirtualTouchpadClient.cpp
index 175173f..782b19c 100644
--- a/services/vr/virtual_touchpad/VirtualTouchpadClient.cpp
+++ b/services/vr/virtual_touchpad/VirtualTouchpadClient.cpp
@@ -10,17 +10,49 @@
class VirtualTouchpadClientImpl : public VirtualTouchpadClient {
public:
- VirtualTouchpadClientImpl(sp<IVirtualTouchpadService> service)
- : service_(service) {}
- ~VirtualTouchpadClientImpl() override {}
+ VirtualTouchpadClientImpl() {}
+ ~VirtualTouchpadClientImpl() override {
+ if (service_ != nullptr) {
+ Detach();
+ }
+ }
- status_t Touch(int touchpad,
- float x, float y, float pressure) override {
+ status_t Attach() {
+ if (service_ != nullptr) {
+ return ALREADY_EXISTS;
+ }
+ sp<IServiceManager> sm = defaultServiceManager();
+ if (sm == nullptr) {
+ ALOGE("no service manager");
+ return NO_INIT;
+ }
+ sp<IVirtualTouchpadService> service =
+ interface_cast<IVirtualTouchpadService>(
+ sm->getService(IVirtualTouchpadService::SERVICE_NAME()));
+ if (service == nullptr) {
+ ALOGE("failed to get service");
+ return NAME_NOT_FOUND;
+ }
+ service_ = service;
+ return service_->attach().transactionError();
+ }
+
+ status_t Detach() {
+ if (service_ == nullptr) {
+ return NO_INIT;
+ }
+ status_t status = service_->detach().transactionError();
+ service_ = nullptr;
+ return status;
+ }
+
+ status_t Touch(int touchpad, float x, float y, float pressure) override {
if (service_ == nullptr) {
return NO_INIT;
}
return service_->touch(touchpad, x, y, pressure).transactionError();
}
+
status_t ButtonState(int touchpad, int buttons) override {
if (service_ == nullptr) {
return NO_INIT;
@@ -28,6 +60,12 @@
return service_->buttonState(touchpad, buttons).transactionError();
}
+ void dumpInternal(String8& result) override {
+ result.append("[virtual touchpad]\n");
+ result.appendFormat("connected = %s\n\n",
+ service_ != nullptr ? "true" : "false");
+ }
+
private:
sp<IVirtualTouchpadService> service_;
};
@@ -35,18 +73,7 @@
} // anonymous namespace
sp<VirtualTouchpad> VirtualTouchpadClient::Create() {
- sp<IServiceManager> sm = defaultServiceManager();
- if (sm == nullptr) {
- ALOGE("no service manager");
- return sp<VirtualTouchpad>();
- }
- sp<IVirtualTouchpadService> service = interface_cast<IVirtualTouchpadService>(
- sm->getService(IVirtualTouchpadService::SERVICE_NAME()));
- if (service == nullptr) {
- ALOGE("failed to get service");
- return sp<VirtualTouchpad>();
- }
- return new VirtualTouchpadClientImpl(service);
+ return new VirtualTouchpadClientImpl();
}
} // namespace dvr
diff --git a/services/vr/virtual_touchpad/VirtualTouchpadEvdev.cpp b/services/vr/virtual_touchpad/VirtualTouchpadEvdev.cpp
index f25a2ad..bc29408 100644
--- a/services/vr/virtual_touchpad/VirtualTouchpadEvdev.cpp
+++ b/services/vr/virtual_touchpad/VirtualTouchpadEvdev.cpp
@@ -32,15 +32,10 @@
sp<VirtualTouchpad> VirtualTouchpadEvdev::Create() {
VirtualTouchpadEvdev* const touchpad = new VirtualTouchpadEvdev();
- const status_t status = touchpad->Initialize();
- if (status) {
- ALOGE("initialization failed: %d", status);
- return sp<VirtualTouchpad>();
- }
return sp<VirtualTouchpad>(touchpad);
}
-int VirtualTouchpadEvdev::Initialize() {
+status_t VirtualTouchpadEvdev::Attach() {
if (!injector_) {
owned_injector_.reset(new EvdevInjector());
injector_ = owned_injector_.get();
@@ -56,9 +51,20 @@
return injector_->GetError();
}
+status_t VirtualTouchpadEvdev::Detach() {
+ injector_->Close();
+ injector_ = nullptr;
+ owned_injector_.reset();
+ last_device_x_ = INT32_MIN;
+ last_device_y_ = INT32_MIN;
+ touches_ = 0;
+ last_motion_event_buttons_ = 0;
+ return OK;
+}
+
int VirtualTouchpadEvdev::Touch(int touchpad, float x, float y,
float pressure) {
- (void)touchpad; // TODO(b/35992608) Support multiple virtual touchpad devices.
+ (void)touchpad; // TODO(b/35992608) Support multiple touchpad devices.
if ((x < 0.0f) || (x >= 1.0f) || (y < 0.0f) || (y >= 1.0f)) {
return EINVAL;
}
@@ -104,7 +110,7 @@
}
int VirtualTouchpadEvdev::ButtonState(int touchpad, int buttons) {
- (void)touchpad; // TODO(b/35992608) Support multiple virtual touchpad devices.
+ (void)touchpad; // TODO(b/35992608) Support multiple touchpad devices.
const int changes = last_motion_event_buttons_ ^ buttons;
if (!changes) {
return 0;
@@ -123,10 +129,26 @@
injector_->SendKey(BTN_BACK, (buttons & AMOTION_EVENT_BUTTON_BACK)
? EvdevInjector::KEY_PRESS
: EvdevInjector::KEY_RELEASE);
+ injector_->SendSynReport();
}
last_motion_event_buttons_ = buttons;
return injector_->GetError();
}
+void VirtualTouchpadEvdev::dumpInternal(String8& result) {
+ result.append("[virtual touchpad]\n");
+ if (!injector_) {
+ result.append("injector = none\n");
+ return;
+ }
+ result.appendFormat("injector = %s\n", owned_injector_ ? "normal" : "test");
+ result.appendFormat("touches = %d\n", touches_);
+ result.appendFormat("last_position = (%" PRId32 ", %" PRId32 ")\n",
+ last_device_x_, last_device_y_);
+ result.appendFormat("last_buttons = 0x%" PRIX32 "\n\n",
+ last_motion_event_buttons_);
+ injector_->dumpInternal(result);
+}
+
} // namespace dvr
} // namespace android
diff --git a/services/vr/virtual_touchpad/VirtualTouchpadEvdev.h b/services/vr/virtual_touchpad/VirtualTouchpadEvdev.h
index ec8006b..b158cec 100644
--- a/services/vr/virtual_touchpad/VirtualTouchpadEvdev.h
+++ b/services/vr/virtual_touchpad/VirtualTouchpadEvdev.h
@@ -18,15 +18,17 @@
static sp<VirtualTouchpad> Create();
// VirtualTouchpad implementation:
+ status_t Attach() override;
+ status_t Detach() override;
status_t Touch(int touchpad, float x, float y, float pressure) override;
status_t ButtonState(int touchpad, int buttons) override;
+ void dumpInternal(String8& result) override;
protected:
VirtualTouchpadEvdev() {}
~VirtualTouchpadEvdev() override {}
- status_t Initialize();
- // Must be called only between construction and Initialize().
+ // Must be called only between construction and Attach().
inline void SetEvdevInjectorForTesting(EvdevInjector* injector) {
injector_ = injector;
}
diff --git a/services/vr/virtual_touchpad/VirtualTouchpadService.cpp b/services/vr/virtual_touchpad/VirtualTouchpadService.cpp
index a1f281c..2e2f622 100644
--- a/services/vr/virtual_touchpad/VirtualTouchpadService.cpp
+++ b/services/vr/virtual_touchpad/VirtualTouchpadService.cpp
@@ -1,22 +1,136 @@
#include "VirtualTouchpadService.h"
+#include <inttypes.h>
+
+#include <binder/IPCThreadState.h>
+#include <binder/PermissionCache.h>
#include <binder/Status.h>
+#include <cutils/log.h>
#include <linux/input.h>
-#include <log/log.h>
+#include <private/android_filesystem_config.h>
#include <utils/Errors.h>
namespace android {
namespace dvr {
-binder::Status VirtualTouchpadService::touch(int touchpad,
- float x, float y, float pressure) {
- const status_t error = touchpad_->Touch(touchpad, x, y, pressure);
- return error ? binder::Status::fromStatusT(error) : binder::Status::ok();
+namespace {
+const String16 kDumpPermission("android.permission.DUMP");
+const String16 kTouchPermission("android.permission.RESTRICTED_VR_ACCESS");
+} // anonymous namespace
+
+VirtualTouchpadService::~VirtualTouchpadService() {
+ if (client_pid_) {
+ client_pid_ = 0;
+ touchpad_->Detach();
+ }
+}
+
+binder::Status VirtualTouchpadService::attach() {
+ pid_t pid;
+ if (!CheckTouchPermission(&pid)) {
+ return binder::Status::fromStatusT(PERMISSION_DENIED);
+ }
+ if (client_pid_ == pid) {
+ // The same client has called attach() twice with no intervening detach().
+ // This indicates a problem with the client, so return an error.
+ // However, since the client is already attached, any touchpad actions
+ // it takes will still work.
+ ALOGE("pid=%ld attached twice", static_cast<long>(pid));
+ return binder::Status::fromStatusT(ALREADY_EXISTS);
+ }
+ if (client_pid_ != 0) {
+ // Attach while another client is attached. This can happen if the client
+ // dies without cleaning up after itself, so move ownership to the current
+ // caller. If two actual clients have connected, the problem will be
+ // reported when the previous client performs any touchpad action.
+ ALOGE("pid=%ld replaces %ld", static_cast<long>(pid),
+ static_cast<long>(client_pid_));
+ }
+ client_pid_ = pid;
+ if (const status_t error = touchpad_->Attach()) {
+ return binder::Status::fromStatusT(error);
+ }
+ return binder::Status::ok();
+}
+
+binder::Status VirtualTouchpadService::detach() {
+ if (!CheckPermissions()) {
+ return binder::Status::fromStatusT(PERMISSION_DENIED);
+ }
+ client_pid_ = 0;
+ if (const status_t error = touchpad_->Detach()) {
+ return binder::Status::fromStatusT(error);
+ }
+ return binder::Status::ok();
+}
+
+binder::Status VirtualTouchpadService::touch(int touchpad, float x, float y,
+ float pressure) {
+ if (!CheckPermissions()) {
+ return binder::Status::fromStatusT(PERMISSION_DENIED);
+ }
+ if (const status_t error = touchpad_->Touch(touchpad, x, y, pressure)) {
+ return binder::Status::fromStatusT(error);
+ }
+ return binder::Status::ok();
}
binder::Status VirtualTouchpadService::buttonState(int touchpad, int buttons) {
- const status_t error = touchpad_->ButtonState(touchpad, buttons);
- return error ? binder::Status::fromStatusT(error) : binder::Status::ok();
+ if (!CheckPermissions()) {
+ return binder::Status::fromStatusT(PERMISSION_DENIED);
+ }
+ if (const status_t error = touchpad_->ButtonState(touchpad, buttons)) {
+ return binder::Status::fromStatusT(error);
+ }
+ return binder::Status::ok();
+}
+
+status_t VirtualTouchpadService::dump(
+ int fd, const Vector<String16>& args[[gnu::unused]]) {
+ String8 result;
+ const android::IPCThreadState* ipc = android::IPCThreadState::self();
+ const pid_t pid = ipc->getCallingPid();
+ const uid_t uid = ipc->getCallingUid();
+ if ((uid != AID_SHELL) &&
+ !PermissionCache::checkPermission(kDumpPermission, pid, uid)) {
+ result.appendFormat("Permission denial: can't dump " LOG_TAG
+ " from pid=%ld, uid=%ld\n",
+ static_cast<long>(pid), static_cast<long>(uid));
+ } else {
+ result.appendFormat("[service]\nclient_pid = %ld\n\n",
+ static_cast<long>(client_pid_));
+ touchpad_->dumpInternal(result);
+ }
+ write(fd, result.string(), result.size());
+ return OK;
+}
+
+bool VirtualTouchpadService::CheckPermissions() {
+ pid_t pid;
+ if (!CheckTouchPermission(&pid)) {
+ return false;
+ }
+ if (client_pid_ != pid) {
+ ALOGE("pid=%ld is not owner", static_cast<long>(pid));
+ return false;
+ }
+ return true;
+}
+
+bool VirtualTouchpadService::CheckTouchPermission(pid_t* out_pid) {
+ const android::IPCThreadState* ipc = android::IPCThreadState::self();
+ *out_pid = ipc->getCallingPid();
+#ifdef SELINUX_ACCESS_CONTROL
+ return true;
+#else
+ const uid_t uid = ipc->getCallingUid();
+ const bool permission = PermissionCache::checkPermission(kTouchPermission, *out_pid, uid);
+ if (!permission) {
+ ALOGE("permission denied to pid=%ld uid=%ld", static_cast<long>(*out_pid),
+ static_cast<long>(uid));
+ }
+ return permission;
+#endif
}
} // namespace dvr
diff --git a/services/vr/virtual_touchpad/VirtualTouchpadService.h b/services/vr/virtual_touchpad/VirtualTouchpadService.h
index 9b880b2..194d787 100644
--- a/services/vr/virtual_touchpad/VirtualTouchpadService.h
+++ b/services/vr/virtual_touchpad/VirtualTouchpadService.h
@@ -14,17 +14,28 @@
class VirtualTouchpadService : public BnVirtualTouchpadService {
public:
VirtualTouchpadService(sp<VirtualTouchpad> touchpad)
- : touchpad_(touchpad) {}
- ~VirtualTouchpadService() override {}
+ : touchpad_(touchpad), client_pid_(0) {}
+ ~VirtualTouchpadService() override;
protected:
// Implements IVirtualTouchpadService.
+ binder::Status attach() override;
+ binder::Status detach() override;
binder::Status touch(int touchpad, float x, float y, float pressure) override;
binder::Status buttonState(int touchpad, int buttons) override;
+ // Implements BBinder::dump().
+ status_t dump(int fd, const Vector<String16>& args) override;
+
private:
+ bool CheckPermissions();
+ bool CheckTouchPermission(pid_t* out_pid);
+
sp<VirtualTouchpad> touchpad_;
+ // Only one client at a time can use the virtual touchpad.
+ pid_t client_pid_;
+
VirtualTouchpadService(const VirtualTouchpadService&) = delete;
void operator=(const VirtualTouchpadService&) = delete;
};
diff --git a/services/vr/virtual_touchpad/aidl/android/dvr/VirtualTouchpadService.aidl b/services/vr/virtual_touchpad/aidl/android/dvr/VirtualTouchpadService.aidl
index 496c5e2..9cfb186 100644
--- a/services/vr/virtual_touchpad/aidl/android/dvr/VirtualTouchpadService.aidl
+++ b/services/vr/virtual_touchpad/aidl/android/dvr/VirtualTouchpadService.aidl
@@ -6,6 +6,16 @@
const String SERVICE_NAME = "virtual_touchpad";
/**
+ * Initialize the virtual touchpad.
+ */
+ void attach() = 0;
+
+ /**
+ * Shut down the virtual touchpad.
+ */
+ void detach() = 1;
+
+ /**
* Generate a simulated touch event.
*
* @param touchpad Selects touchpad.
@@ -15,7 +25,7 @@
*
* Position values in the range [0.0, 1.0) map to the screen.
*/
- void touch(int touchpad, float x, float y, float pressure);
+ void touch(int touchpad, float x, float y, float pressure) = 2;
/**
* Generate a simulated touchpad button state event.
@@ -23,5 +33,5 @@
* @param touchpad Selects touchpad.
* @param buttons A union of MotionEvent BUTTON_* values.
*/
- void buttonState(int touchpad, int buttons);
+ void buttonState(int touchpad, int buttons) = 3;
}
diff --git a/services/vr/virtual_touchpad/include/VirtualTouchpad.h b/services/vr/virtual_touchpad/include/VirtualTouchpad.h
index d24d121..b1ee700 100644
--- a/services/vr/virtual_touchpad/include/VirtualTouchpad.h
+++ b/services/vr/virtual_touchpad/include/VirtualTouchpad.h
@@ -3,6 +3,7 @@
#include <utils/Errors.h>
#include <utils/RefBase.h>
+#include <utils/String8.h>
#include <utils/StrongPointer.h>
namespace android {
@@ -21,10 +22,18 @@
// Implementations should provide this, and hide their constructors.
// For the user, switching implementations should be as simple as changing
// the class whose |Create()| is called.
+ // Implementations should be minimial; major resource allocation should
+ // be performed in Attach().
static sp<VirtualTouchpad> Create() {
return sp<VirtualTouchpad>();
}
+ // Initialize a virtual touchpad.
+ virtual status_t Attach() = 0;
+
+ // Shut down a virtual touchpad.
+ virtual status_t Detach() = 0;
+
// Generate a simulated touch event.
//
// @param touchpad Touchpad selector index.
@@ -49,6 +58,9 @@
//
virtual status_t ButtonState(int touchpad, int buttons) = 0;
+ // Report state for 'dumpsys'.
+ virtual void dumpInternal(String8& result) = 0;
+
protected:
VirtualTouchpad() {}
~VirtualTouchpad() override {}
diff --git a/services/vr/virtual_touchpad/include/VirtualTouchpadClient.h b/services/vr/virtual_touchpad/include/VirtualTouchpadClient.h
index dd9c265..471d9e0 100644
--- a/services/vr/virtual_touchpad/include/VirtualTouchpadClient.h
+++ b/services/vr/virtual_touchpad/include/VirtualTouchpadClient.h
@@ -13,8 +13,11 @@
public:
// VirtualTouchpad implementation:
static sp<VirtualTouchpad> Create();
+ status_t Attach() override;
+ status_t Detach() override;
status_t Touch(int touchpad, float x, float y, float pressure) override;
status_t ButtonState(int touchpad, int buttons) override;
+ void dumpInternal(String8& result) override;
protected:
VirtualTouchpadClient() {}
diff --git a/services/vr/virtual_touchpad/tests/VirtualTouchpad_test.cpp b/services/vr/virtual_touchpad/tests/VirtualTouchpad_test.cpp
index 469a2d0..b11a983 100644
--- a/services/vr/virtual_touchpad/tests/VirtualTouchpad_test.cpp
+++ b/services/vr/virtual_touchpad/tests/VirtualTouchpad_test.cpp
@@ -97,7 +97,6 @@
static sp<VirtualTouchpad> Create(EvdevInjectorForTesting& injector) {
VirtualTouchpadForTesting* const touchpad = new VirtualTouchpadForTesting();
touchpad->SetEvdevInjectorForTesting(&injector);
- touchpad->Initialize();
return sp<VirtualTouchpad>(touchpad);
}
};
@@ -123,6 +122,9 @@
EvdevInjectorForTesting injector(record);
sp<VirtualTouchpad> touchpad(VirtualTouchpadForTesting::Create(injector));
+ status_t touch_status = touchpad->Attach();
+ EXPECT_EQ(0, touch_status);
+
// Check some aspects of uinput_user_dev.
const uinput_user_dev* uidev = injector.GetUiDev();
for (int i = 0; i < ABS_CNT; ++i) {
@@ -151,6 +153,7 @@
// From ConfigureKey(BTN_TOUCH):
expect.IoctlSetInt(UI_SET_EVBIT, EV_KEY);
expect.IoctlSetInt(UI_SET_KEYBIT, BTN_TOUCH);
+ expect.IoctlSetInt(UI_SET_KEYBIT, BTN_BACK);
// From ConfigureEnd():
expect.Write(uidev, sizeof(uinput_user_dev));
expect.IoctlVoid(UI_DEV_CREATE);
@@ -158,7 +161,7 @@
expect.Reset();
record.Reset();
- int touch_status = touchpad->Touch(VirtualTouchpad::PRIMARY, 0, 0, 0);
+ touch_status = touchpad->Touch(VirtualTouchpad::PRIMARY, 0, 0, 0);
EXPECT_EQ(0, touch_status);
expect.WriteInputEvent(EV_ABS, ABS_MT_SLOT, 0);
expect.WriteInputEvent(EV_ABS, ABS_MT_TRACKING_ID, 0);
@@ -180,16 +183,22 @@
expect.Reset();
record.Reset();
- touch_status = touchpad->Touch(VirtualTouchpad::PRIMARY, 1.0f, 1.0f, 1.0f);
+ touch_status = touchpad->Touch(VirtualTouchpad::PRIMARY, 0.99f, 0.99f, 0.99f);
EXPECT_EQ(0, touch_status);
expect.WriteInputEvent(EV_ABS, ABS_MT_TRACKING_ID, 0);
- expect.WriteInputEvent(EV_ABS, ABS_MT_POSITION_X, width);
- expect.WriteInputEvent(EV_ABS, ABS_MT_POSITION_Y, height);
+ expect.WriteInputEvent(EV_ABS, ABS_MT_POSITION_X, 0.99f * width);
+ expect.WriteInputEvent(EV_ABS, ABS_MT_POSITION_Y, 0.99f * height);
expect.WriteInputEvent(EV_SYN, SYN_REPORT, 0);
EXPECT_EQ(expect.GetString(), record.GetString());
expect.Reset();
record.Reset();
+ touch_status = touchpad->Touch(VirtualTouchpad::PRIMARY, 1.0f, 1.0f, 1.0f);
+ EXPECT_EQ(EINVAL, touch_status);
+ EXPECT_EQ(expect.GetString(), record.GetString());
+
+ expect.Reset();
+ record.Reset();
touch_status =
touchpad->Touch(VirtualTouchpad::PRIMARY, 0.25f, 0.75f, -0.01f);
EXPECT_EQ(0, touch_status);
@@ -224,6 +233,10 @@
expect.Reset();
record.Reset();
+ touch_status = touchpad->Detach();
+ EXPECT_EQ(0, touch_status);
+ expect.Close();
+ EXPECT_EQ(expect.GetString(), record.GetString());
}
TEST_F(VirtualTouchpadTest, Badness) {
@@ -232,11 +245,14 @@
EvdevInjectorForTesting injector(record);
sp<VirtualTouchpad> touchpad(VirtualTouchpadForTesting::Create(injector));
+ status_t touch_status = touchpad->Attach();
+ EXPECT_EQ(0, touch_status);
+
// Touch off-screen should return an error,
// and should not result in any system calls.
expect.Reset();
record.Reset();
- status_t touch_status =
+ touch_status =
touchpad->Touch(VirtualTouchpad::PRIMARY, -0.25f, 0.75f, 1.0f);
EXPECT_NE(OK, touch_status);
touch_status =
@@ -256,6 +272,10 @@
AMOTION_EVENT_BUTTON_FORWARD);
EXPECT_NE(OK, touch_status);
EXPECT_EQ(expect.GetString(), record.GetString());
+
+ // Repeated attach is an error.
+ touch_status = touchpad->Attach();
+ EXPECT_NE(0, touch_status);
}
} // namespace dvr
diff --git a/services/vr/vr_window_manager/shell_view.cpp b/services/vr/vr_window_manager/shell_view.cpp
index fae1dd9..10588b7 100644
--- a/services/vr/vr_window_manager/shell_view.cpp
+++ b/services/vr/vr_window_manager/shell_view.cpp
@@ -250,8 +250,12 @@
translate_ = Eigen::Translation3f(0, 0, -2.5f);
- if (!InitializeTouch())
- ALOGE("Failed to initialize virtual touchpad");
+ virtual_touchpad_ = VirtualTouchpadClient::Create();
+ const status_t touchpad_status = virtual_touchpad_->Attach();
+ if (touchpad_status != OK) {
+ ALOGE("Failed to connect to virtual touchpad");
+ return touchpad_status;
+ }
surface_flinger_view_.reset(new SurfaceFlingerView);
if (!surface_flinger_view_->Initialize(this))
@@ -702,22 +706,10 @@
controller_mesh_->Draw();
}
-bool ShellView::InitializeTouch() {
- virtual_touchpad_ = VirtualTouchpadClient::Create();
- if (!virtual_touchpad_.get()) {
- ALOGE("Failed to connect to virtual touchpad");
- return false;
- }
- return true;
-}
-
void ShellView::Touch() {
if (!virtual_touchpad_.get()) {
ALOGE("missing virtual touchpad");
- // Try to reconnect; useful in development.
- if (!InitializeTouch()) {
- return;
- }
+ return;
}
const android::status_t status = virtual_touchpad_->Touch(
diff --git a/services/vr/vr_window_manager/shell_view.h b/services/vr/vr_window_manager/shell_view.h
index c477669..49456c6 100644
--- a/services/vr/vr_window_manager/shell_view.h
+++ b/services/vr/vr_window_manager/shell_view.h
@@ -58,7 +58,6 @@
bool test_ime);
bool IsImeHit(const vec3& view_location, const vec3& view_direction,
vec3 *hit_location);
- bool InitializeTouch();
void Touch();
bool OnTouchpadButton(bool down, int button);
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 c2138b7..bd3f3ee 100644
--- a/services/vr/vr_window_manager/vr_window_manager_binder.cpp
+++ b/services/vr/vr_window_manager/vr_window_manager_binder.cpp
@@ -16,7 +16,8 @@
namespace {
const String16 kDumpPermission("android.permission.DUMP");
-const String16 kSendMeControllerInputPermission("TODO"); // TODO(kpschoedel)
+const String16 kSendMeControllerInputPermission(
+ "android.permission.RESTRICTED_VR_ACCESS");
} // anonymous namespace
constexpr size_t AshmemControllerDataProvider::kRegionLength;
@@ -136,8 +137,8 @@
int fd, const Vector<String16>& args [[gnu::unused]]) {
String8 result;
const android::IPCThreadState* ipc = android::IPCThreadState::self();
- const int pid = ipc->getCallingPid();
- const int uid = ipc->getCallingUid();
+ const pid_t pid = ipc->getCallingPid();
+ const uid_t uid = ipc->getCallingUid();
if ((uid != AID_SHELL) &&
!PermissionCache::checkPermission(kDumpPermission, pid, uid)) {
result.appendFormat("Permission denial: can't dump " LOG_TAG