Merge "Add input device property for buttons under touchpads"
diff --git a/cmds/dumpstate/dumpstate.c b/cmds/dumpstate/dumpstate.c
index 38b0b24..7710c5b 100644
--- a/cmds/dumpstate/dumpstate.c
+++ b/cmds/dumpstate/dumpstate.c
@@ -95,6 +95,7 @@
run_command("PROCESSES", 10, "ps", "-P", NULL);
run_command("PROCESSES AND THREADS", 10, "ps", "-t", "-p", "-P", NULL);
+ run_command("PROCESSES (SELINUX LABELS)", 10, "ps", "-Z", NULL);
run_command("LIBRANK", 10, "librank", NULL);
do_dmesg();
@@ -285,7 +286,7 @@
run_command("CHECKIN MEMINFO", 30, "dumpsys", "meminfo", "--checkin", NULL);
run_command("CHECKIN NETSTATS", 30, "dumpsys", "netstats", "--checkin", NULL);
run_command("CHECKIN PROCSTATS", 30, "dumpsys", "procstats", "-c", NULL);
- run_command("CHECKIN USAGESTATS", 30, "dumpsys", "usagestats", "--c", NULL);
+ run_command("CHECKIN USAGESTATS", 30, "dumpsys", "usagestats", "-c", NULL);
printf("========================================================\n");
printf("== Running Application Activities\n");
diff --git a/cmds/flatland/GLHelper.cpp b/cmds/flatland/GLHelper.cpp
index 4f7697f..89eb95f 100644
--- a/cmds/flatland/GLHelper.cpp
+++ b/cmds/flatland/GLHelper.cpp
@@ -199,8 +199,8 @@
bool GLHelper::createNamedSurfaceTexture(GLuint name, uint32_t w, uint32_t h,
sp<GLConsumer>* glConsumer, EGLSurface* surface) {
sp<BufferQueue> bq = new BufferQueue(true, mGraphicBufferAlloc);
- sp<GLConsumer> glc = new GLConsumer(name, true,
- GL_TEXTURE_EXTERNAL_OES, false, bq);
+ sp<GLConsumer> glc = new GLConsumer(bq, name,
+ GL_TEXTURE_EXTERNAL_OES, false);
glc->setDefaultBufferSize(w, h);
glc->setDefaultMaxBufferCount(3);
glc->setConsumerUsageBits(GRALLOC_USAGE_HW_COMPOSER);
diff --git a/cmds/inputflinger/Android.mk b/cmds/inputflinger/Android.mk
new file mode 100644
index 0000000..b44de44
--- /dev/null
+++ b/cmds/inputflinger/Android.mk
@@ -0,0 +1,28 @@
+# Copyright (C) 2013 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ main.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+ libbinder \
+ libinputflinger \
+ libutils
+
+LOCAL_MODULE := inputflinger
+
+include $(BUILD_EXECUTABLE)
diff --git a/cmds/inputflinger/main.cpp b/cmds/inputflinger/main.cpp
new file mode 100644
index 0000000..6de7b24
--- /dev/null
+++ b/cmds/inputflinger/main.cpp
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <binder/BinderService.h>
+#include <InputFlinger.h>
+
+using namespace android;
+
+int main(int argc, char** argv) {
+ ProcessState::self()->setThreadPoolMaxThreadCount(4);
+ BinderService<InputFlinger>::publishAndJoinThreadPool(true);
+ return 0;
+}
diff --git a/cmds/installd/commands.c b/cmds/installd/commands.c
index 27580f3..84ad204 100644
--- a/cmds/installd/commands.c
+++ b/cmds/installd/commands.c
@@ -108,11 +108,11 @@
return 0;
}
-int uninstall(const char *pkgname, uid_t persona)
+int uninstall(const char *pkgname, userid_t userid)
{
char pkgdir[PKG_PATH_MAX];
- if (create_pkg_path(pkgdir, pkgname, PKG_DIR_POSTFIX, persona))
+ if (create_pkg_path(pkgdir, pkgname, PKG_DIR_POSTFIX, userid))
return -1;
/* delete contents AND directory, no exceptions */
@@ -173,18 +173,18 @@
return 0;
}
-int delete_user_data(const char *pkgname, uid_t persona)
+int delete_user_data(const char *pkgname, userid_t userid)
{
char pkgdir[PKG_PATH_MAX];
- if (create_pkg_path(pkgdir, pkgname, PKG_DIR_POSTFIX, persona))
+ if (create_pkg_path(pkgdir, pkgname, PKG_DIR_POSTFIX, userid))
return -1;
/* delete contents, excluding "lib", but not the directory itself */
return delete_dir_contents(pkgdir, 0, "lib");
}
-int make_user_data(const char *pkgname, uid_t uid, uid_t persona)
+int make_user_data(const char *pkgname, uid_t uid, userid_t userid)
{
char pkgdir[PKG_PATH_MAX];
char applibdir[PKG_PATH_MAX];
@@ -192,10 +192,10 @@
struct stat libStat;
// Create the data dir for the package
- if (create_pkg_path(pkgdir, pkgname, PKG_DIR_POSTFIX, persona)) {
+ if (create_pkg_path(pkgdir, pkgname, PKG_DIR_POSTFIX, userid)) {
return -1;
}
- if (create_pkg_path(libsymlink, pkgname, PKG_LIB_POSTFIX, persona)) {
+ if (create_pkg_path(libsymlink, pkgname, PKG_LIB_POSTFIX, userid)) {
ALOGE("cannot create package lib symlink origin path\n");
return -1;
}
@@ -262,10 +262,10 @@
return 0;
}
-int delete_persona(uid_t persona)
+int delete_user(userid_t userid)
{
char data_path[PKG_PATH_MAX];
- if (create_persona_path(data_path, persona)) {
+ if (create_user_path(data_path, userid)) {
return -1;
}
if (delete_dir_contents(data_path, 1, NULL)) {
@@ -273,7 +273,7 @@
}
char media_path[PATH_MAX];
- if (create_persona_media_path(media_path, (userid_t) persona) == -1) {
+ if (create_user_media_path(media_path, userid) == -1) {
return -1;
}
if (delete_dir_contents(media_path, 1, NULL) == -1) {
@@ -283,11 +283,11 @@
return 0;
}
-int delete_cache(const char *pkgname, uid_t persona)
+int delete_cache(const char *pkgname, userid_t userid)
{
char cachedir[PKG_PATH_MAX];
- if (create_pkg_path(cachedir, pkgname, CACHE_DIR_POSTFIX, persona))
+ if (create_pkg_path(cachedir, pkgname, CACHE_DIR_POSTFIX, userid))
return -1;
/* delete contents, not the directory, no exceptions */
@@ -319,7 +319,7 @@
cache = start_cache_collection();
// Collect cache files for primary user.
- if (create_persona_path(tmpdir, 0) == 0) {
+ if (create_user_path(tmpdir, 0) == 0) {
//ALOGI("adding cache files from %s\n", tmpdir);
add_cache_files(cache, tmpdir, "cache");
}
@@ -420,7 +420,7 @@
}
}
-int get_size(const char *pkgname, int persona, const char *apkpath,
+int get_size(const char *pkgname, userid_t userid, const char *apkpath,
const char *libdirpath, const char *fwdlock_apkpath, const char *asecpath,
int64_t *_codesize, int64_t *_datasize, int64_t *_cachesize,
int64_t* _asecsize)
@@ -477,7 +477,7 @@
}
}
- if (create_pkg_path(path, pkgname, PKG_DIR_POSTFIX, persona)) {
+ if (create_pkg_path(path, pkgname, PKG_DIR_POSTFIX, userid)) {
goto done;
}
diff --git a/cmds/installd/installd.c b/cmds/installd/installd.c
index 87f900a..1904408 100644
--- a/cmds/installd/installd.c
+++ b/cmds/installd/installd.c
@@ -83,7 +83,7 @@
int64_t asecsize = 0;
int res = 0;
- /* pkgdir, persona, apkpath */
+ /* pkgdir, userid, apkpath */
res = get_size(arg[0], atoi(arg[1]), arg[2], arg[3], arg[4], arg[5],
&codesize, &datasize, &cachesize, &asecsize);
@@ -108,7 +108,7 @@
static int do_rm_user(char **arg, char reply[REPLY_MAX])
{
- return delete_persona(atoi(arg[0])); /* userid */
+ return delete_user(atoi(arg[0])); /* userid */
}
static int do_movefiles(char **arg, char reply[REPLY_MAX])
diff --git a/cmds/installd/installd.h b/cmds/installd/installd.h
index fbfc876..635b07c 100644
--- a/cmds/installd/installd.h
+++ b/cmds/installd/installd.h
@@ -78,9 +78,6 @@
#define PKG_NAME_MAX 128 /* largest allowed package name */
#define PKG_PATH_MAX 256 /* max size of any path we use */
-#define PER_USER_RANGE ((uid_t)100000) /* range of uids per user
- uid = persona * PER_USER_RANGE + appid */
-
/* data structures */
typedef struct {
@@ -138,17 +135,17 @@
int create_pkg_path(char path[PKG_PATH_MAX],
const char *pkgname,
const char *postfix,
- uid_t persona);
+ userid_t userid);
-int create_persona_path(char path[PKG_PATH_MAX],
- uid_t persona);
+int create_user_path(char path[PKG_PATH_MAX],
+ userid_t userid);
-int create_persona_media_path(char path[PKG_PATH_MAX], userid_t userid);
+int create_user_media_path(char path[PKG_PATH_MAX], userid_t userid);
int create_move_path(char path[PKG_PATH_MAX],
const char* pkgname,
const char* leaf,
- uid_t persona);
+ userid_t userid);
int is_valid_package_name(const char* pkgname);
@@ -193,17 +190,17 @@
/* commands.c */
int install(const char *pkgname, uid_t uid, gid_t gid, const char *seinfo);
-int uninstall(const char *pkgname, uid_t persona);
+int uninstall(const char *pkgname, userid_t userid);
int renamepkg(const char *oldpkgname, const char *newpkgname);
int fix_uid(const char *pkgname, uid_t uid, gid_t gid);
-int delete_user_data(const char *pkgname, uid_t persona);
-int make_user_data(const char *pkgname, uid_t uid, uid_t persona);
-int delete_persona(uid_t persona);
-int delete_cache(const char *pkgname, uid_t persona);
+int delete_user_data(const char *pkgname, userid_t userid);
+int make_user_data(const char *pkgname, uid_t uid, userid_t userid);
+int delete_user(userid_t userid);
+int delete_cache(const char *pkgname, userid_t userid);
int move_dex(const char *src, const char *dst);
int rm_dex(const char *path);
int protect(char *pkgname, gid_t gid);
-int get_size(const char *pkgname, int persona, const char *apkpath, const char *libdirpath,
+int get_size(const char *pkgname, userid_t userid, const char *apkpath, const char *libdirpath,
const char *fwdlock_apkpath, const char *asecpath, int64_t *codesize,
int64_t *datasize, int64_t *cachesize, int64_t *asecsize);
int free_cache(int64_t free_size);
diff --git a/cmds/installd/tests/installd_utils_test.cpp b/cmds/installd/tests/installd_utils_test.cpp
index 7cb9b37..0b182af 100644
--- a/cmds/installd/tests/installd_utils_test.cpp
+++ b/cmds/installd/tests/installd_utils_test.cpp
@@ -340,7 +340,7 @@
TEST_F(UtilsTest, CreatePersonaPath_Primary) {
char path[PKG_PATH_MAX];
- EXPECT_EQ(0, create_persona_path(path, 0))
+ EXPECT_EQ(0, create_user_path(path, 0))
<< "Should successfully build primary user path.";
EXPECT_STREQ("/data/data/", path)
@@ -350,7 +350,7 @@
TEST_F(UtilsTest, CreatePersonaPath_Secondary) {
char path[PKG_PATH_MAX];
- EXPECT_EQ(0, create_persona_path(path, 1))
+ EXPECT_EQ(0, create_user_path(path, 1))
<< "Should successfully build primary user path.";
EXPECT_STREQ("/data/user/1/", path)
diff --git a/cmds/installd/utils.c b/cmds/installd/utils.c
index 625a35e..ef634c6 100644
--- a/cmds/installd/utils.c
+++ b/cmds/installd/utils.c
@@ -53,38 +53,39 @@
/**
* Create the package path name for a given package name with a postfix for
- * a certain persona. Returns 0 on success, and -1 on failure.
+ * a certain userid. Returns 0 on success, and -1 on failure.
*/
int create_pkg_path(char path[PKG_PATH_MAX],
const char *pkgname,
const char *postfix,
- uid_t persona)
+ userid_t userid)
{
- size_t uid_len;
- char* persona_prefix;
- if (persona == 0) {
- persona_prefix = PRIMARY_USER_PREFIX;
- uid_len = 0;
+ size_t userid_len;
+ char* userid_prefix;
+ if (userid == 0) {
+ userid_prefix = PRIMARY_USER_PREFIX;
+ userid_len = 0;
} else {
- persona_prefix = SECONDARY_USER_PREFIX;
- uid_len = snprintf(NULL, 0, "%d", persona);
+ userid_prefix = SECONDARY_USER_PREFIX;
+ userid_len = snprintf(NULL, 0, "%d", userid);
}
- const size_t prefix_len = android_data_dir.len + strlen(persona_prefix) + uid_len + 1 /*slash*/;
+ const size_t prefix_len = android_data_dir.len + strlen(userid_prefix)
+ + userid_len + 1 /*slash*/;
char prefix[prefix_len + 1];
char *dst = prefix;
size_t dst_size = sizeof(prefix);
if (append_and_increment(&dst, android_data_dir.path, &dst_size) < 0
- || append_and_increment(&dst, persona_prefix, &dst_size) < 0) {
+ || append_and_increment(&dst, userid_prefix, &dst_size) < 0) {
ALOGE("Error building prefix for APK path");
return -1;
}
- if (persona != 0) {
- int ret = snprintf(dst, dst_size, "%d/", persona);
- if (ret < 0 || (size_t) ret != uid_len + 1) {
+ if (userid != 0) {
+ int ret = snprintf(dst, dst_size, "%d/", userid);
+ if (ret < 0 || (size_t) ret != userid_len + 1) {
ALOGW("Error appending UID to APK path");
return -1;
}
@@ -98,39 +99,39 @@
}
/**
- * Create the path name for user data for a certain persona.
+ * Create the path name for user data for a certain userid.
* Returns 0 on success, and -1 on failure.
*/
-int create_persona_path(char path[PKG_PATH_MAX],
- uid_t persona)
+int create_user_path(char path[PKG_PATH_MAX],
+ userid_t userid)
{
- size_t uid_len;
- char* persona_prefix;
- if (persona == 0) {
- persona_prefix = PRIMARY_USER_PREFIX;
- uid_len = 0;
+ size_t userid_len;
+ char* userid_prefix;
+ if (userid == 0) {
+ userid_prefix = PRIMARY_USER_PREFIX;
+ userid_len = 0;
} else {
- persona_prefix = SECONDARY_USER_PREFIX;
- uid_len = snprintf(NULL, 0, "%d/", persona);
+ userid_prefix = SECONDARY_USER_PREFIX;
+ userid_len = snprintf(NULL, 0, "%d/", userid);
}
char *dst = path;
size_t dst_size = PKG_PATH_MAX;
if (append_and_increment(&dst, android_data_dir.path, &dst_size) < 0
- || append_and_increment(&dst, persona_prefix, &dst_size) < 0) {
+ || append_and_increment(&dst, userid_prefix, &dst_size) < 0) {
ALOGE("Error building prefix for user path");
return -1;
}
- if (persona != 0) {
- if (dst_size < uid_len + 1) {
+ if (userid != 0) {
+ if (dst_size < userid_len + 1) {
ALOGE("Error building user path");
return -1;
}
- int ret = snprintf(dst, dst_size, "%d/", persona);
- if (ret < 0 || (size_t) ret != uid_len) {
- ALOGE("Error appending persona id to path");
+ int ret = snprintf(dst, dst_size, "%d/", userid);
+ if (ret < 0 || (size_t) ret != userid_len) {
+ ALOGE("Error appending userid to path");
return -1;
}
}
@@ -138,10 +139,10 @@
}
/**
- * Create the path name for media for a certain persona.
+ * Create the path name for media for a certain userid.
* Returns 0 on success, and -1 on failure.
*/
-int create_persona_media_path(char path[PATH_MAX], userid_t userid) {
+int create_user_media_path(char path[PATH_MAX], userid_t userid) {
if (snprintf(path, PATH_MAX, "%s%d", android_media_dir.path, userid) > PATH_MAX) {
return -1;
}
@@ -151,7 +152,7 @@
int create_move_path(char path[PKG_PATH_MAX],
const char* pkgname,
const char* leaf,
- uid_t persona)
+ userid_t userid)
{
if ((android_data_dir.len + strlen(PRIMARY_USER_PREFIX) + strlen(pkgname) + strlen(leaf) + 1)
>= PKG_PATH_MAX) {
@@ -997,7 +998,7 @@
char path[PATH_MAX];
// Ensure /data/media/<userid> exists
- create_persona_media_path(media_user_path, userid);
+ create_user_media_path(media_user_path, userid);
if (fs_prepare_dir(media_user_path, 0770, AID_MEDIA_RW, AID_MEDIA_RW) == -1) {
return -1;
}
diff --git a/include/android/keycodes.h b/include/android/keycodes.h
index cf38d1a..1ca1332 100644
--- a/include/android/keycodes.h
+++ b/include/android/keycodes.h
@@ -265,6 +265,7 @@
AKEYCODE_ASSIST = 219,
AKEYCODE_BRIGHTNESS_DOWN = 220,
AKEYCODE_BRIGHTNESS_UP = 221,
+ AKEYCODE_MEDIA_AUDIO_TRACK = 222,
// NOTE: If you add a new keycode here you must also add it to several other files.
// Refer to frameworks/base/core/java/android/view/KeyEvent.java for the full list.
diff --git a/include/binder/IAppOpsService.h b/include/binder/IAppOpsService.h
index 7cb55e5..193e9cc 100644
--- a/include/binder/IAppOpsService.h
+++ b/include/binder/IAppOpsService.h
@@ -32,11 +32,14 @@
virtual int32_t checkOperation(int32_t code, int32_t uid, const String16& packageName) = 0;
virtual int32_t noteOperation(int32_t code, int32_t uid, const String16& packageName) = 0;
- virtual int32_t startOperation(int32_t code, int32_t uid, const String16& packageName) = 0;
- virtual void finishOperation(int32_t code, int32_t uid, const String16& packageName) = 0;
+ virtual int32_t startOperation(const sp<IBinder>& token, int32_t code, int32_t uid,
+ const String16& packageName) = 0;
+ virtual void finishOperation(const sp<IBinder>& token, int32_t code, int32_t uid,
+ const String16& packageName) = 0;
virtual void startWatchingMode(int32_t op, const String16& packageName,
const sp<IAppOpsCallback>& callback) = 0;
virtual void stopWatchingMode(const sp<IAppOpsCallback>& callback) = 0;
+ virtual sp<IBinder> getToken(const sp<IBinder>& clientToken) = 0;
enum {
CHECK_OPERATION_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION,
@@ -44,7 +47,8 @@
START_OPERATION_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+2,
FINISH_OPERATION_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+3,
START_WATCHING_MODE_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+4,
- STOP_WATCHING_MODE_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+5
+ STOP_WATCHING_MODE_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+5,
+ GET_TOKEN_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+6,
};
enum {
diff --git a/include/binder/IPCThreadState.h b/include/binder/IPCThreadState.h
index ad0daee..5bc123e 100644
--- a/include/binder/IPCThreadState.h
+++ b/include/binder/IPCThreadState.h
@@ -39,8 +39,8 @@
status_t clearLastError();
- int getCallingPid();
- int getCallingUid();
+ int getCallingPid() const;
+ int getCallingUid() const;
void setStrictModePolicy(int32_t policy);
int32_t getStrictModePolicy() const;
diff --git a/include/gui/BufferItemConsumer.h b/include/gui/BufferItemConsumer.h
index 98b450c..0af6f8e 100644
--- a/include/gui/BufferItemConsumer.h
+++ b/include/gui/BufferItemConsumer.h
@@ -29,6 +29,8 @@
namespace android {
+class BufferQueue;
+
/**
* BufferItemConsumer is a BufferQueue consumer endpoint that allows clients
* access to the whole BufferItem entry from BufferQueue. Multiple buffers may
@@ -49,7 +51,7 @@
// the consumer usage flags passed to the graphics allocator. The
// bufferCount parameter specifies how many buffers can be locked for user
// access at the same time.
- BufferItemConsumer(uint32_t consumerUsage,
+ BufferItemConsumer(const sp<BufferQueue>& bq, uint32_t consumerUsage,
int bufferCount = BufferQueue::MIN_UNDEQUEUED_BUFFERS,
bool synchronousMode = false);
@@ -71,7 +73,8 @@
//
// If waitForFence is true, and the acquired BufferItem has a valid fence object,
// acquireBuffer will wait on the fence with no timeout before returning.
- status_t acquireBuffer(BufferItem *item, bool waitForFence = true);
+ status_t acquireBuffer(BufferItem *item, nsecs_t presentWhen,
+ bool waitForFence = true);
// Returns an acquired buffer to the queue, allowing it to be reused. Since
// only a fixed number of buffers may be acquired at a time, old buffers
diff --git a/include/gui/BufferQueue.h b/include/gui/BufferQueue.h
index 766fa0f..0143be3 100644
--- a/include/gui/BufferQueue.h
+++ b/include/gui/BufferQueue.h
@@ -39,7 +39,7 @@
enum { NUM_BUFFER_SLOTS = 32 };
enum { NO_CONNECTED_API = 0 };
enum { INVALID_BUFFER_SLOT = -1 };
- enum { STALE_BUFFER_SLOT = 1, NO_BUFFER_AVAILABLE };
+ enum { STALE_BUFFER_SLOT = 1, NO_BUFFER_AVAILABLE, PRESENT_LATER };
// When in async mode we reserve two slots in order to guarantee that the
// producer and consumer can run asynchronously.
@@ -284,7 +284,13 @@
// acquired then the BufferItem::mGraphicBuffer field of buffer is set to
// NULL and it is assumed that the consumer still holds a reference to the
// buffer.
- status_t acquireBuffer(BufferItem *buffer);
+ //
+ // If presentWhen is nonzero, it indicates the time when the buffer will
+ // be displayed on screen. If the buffer's timestamp is farther in the
+ // future, the buffer won't be acquired, and PRESENT_LATER will be
+ // returned. The presentation time is in nanoseconds, and the time base
+ // is CLOCK_MONOTONIC.
+ status_t acquireBuffer(BufferItem *buffer, nsecs_t presentWhen);
// releaseBuffer releases a buffer slot from the consumer back to the
// BufferQueue. This may be done while the buffer's contents are still
diff --git a/include/gui/ConsumerBase.h b/include/gui/ConsumerBase.h
index 1d51bc9..42b84cc 100644
--- a/include/gui/ConsumerBase.h
+++ b/include/gui/ConsumerBase.h
@@ -152,7 +152,8 @@
// initialization that must take place the first time a buffer is assigned
// to a slot. If it is overridden the derived class's implementation must
// call ConsumerBase::acquireBufferLocked.
- virtual status_t acquireBufferLocked(BufferQueue::BufferItem *item);
+ virtual status_t acquireBufferLocked(BufferQueue::BufferItem *item,
+ nsecs_t presentWhen);
// releaseBufferLocked relinquishes control over a buffer, returning that
// control to the BufferQueue.
diff --git a/include/gui/CpuConsumer.h b/include/gui/CpuConsumer.h
index 3c178ef..5f1e369 100644
--- a/include/gui/CpuConsumer.h
+++ b/include/gui/CpuConsumer.h
@@ -28,6 +28,8 @@
namespace android {
+class BufferQueue;
+
/**
* CpuConsumer is a BufferQueue consumer endpoint that allows direct CPU
* access to the underlying gralloc buffers provided by BufferQueue. Multiple
@@ -64,7 +66,8 @@
// Create a new CPU consumer. The maxLockedBuffers parameter specifies
// how many buffers can be locked for user access at the same time.
- CpuConsumer(uint32_t maxLockedBuffers, bool synchronousMode = true);
+ CpuConsumer(const sp<BufferQueue>& bq,
+ uint32_t maxLockedBuffers, bool synchronousMode = true);
virtual ~CpuConsumer();
diff --git a/include/gui/GLConsumer.h b/include/gui/GLConsumer.h
index 031684e..65544bd 100644
--- a/include/gui/GLConsumer.h
+++ b/include/gui/GLConsumer.h
@@ -85,9 +85,9 @@
// purely to allow a GLConsumer to be transferred from one consumer
// context to another. If such a transfer is not needed there is no
// requirement that either of these methods be called.
- GLConsumer(GLuint tex, bool allowSynchronousMode = true,
- GLenum texTarget = GL_TEXTURE_EXTERNAL_OES, bool useFenceSync = true,
- const sp<BufferQueue> &bufferQueue = 0);
+ GLConsumer(const sp<BufferQueue>& bq,
+ GLuint tex, GLenum texTarget = GL_TEXTURE_EXTERNAL_OES,
+ bool useFenceSync = true);
// updateTexImage acquires the most recently queued buffer, and sets the
// image contents of the target texture to it.
@@ -237,7 +237,8 @@
// acquireBufferLocked overrides the ConsumerBase method to update the
// mEglSlots array in addition to the ConsumerBase behavior.
- virtual status_t acquireBufferLocked(BufferQueue::BufferItem *item);
+ virtual status_t acquireBufferLocked(BufferQueue::BufferItem *item,
+ nsecs_t presentWhen);
// releaseBufferLocked overrides the ConsumerBase method to update the
// mEglSlots array in addition to the ConsumerBase.
diff --git a/include/input/IInputFlinger.h b/include/input/IInputFlinger.h
new file mode 100644
index 0000000..79ff12a
--- /dev/null
+++ b/include/input/IInputFlinger.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2013 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 _LIBINPUT_IINPUT_FLINGER_H
+#define _LIBINPUT_IINPUT_FLINGER_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <binder/IInterface.h>
+
+namespace android {
+
+/*
+ * This class defines the Binder IPC interface for accessing various
+ * InputFlinger features.
+ */
+class IInputFlinger : public IInterface {
+public:
+ DECLARE_META_INTERFACE(InputFlinger);
+
+ virtual status_t doSomething() = 0;
+};
+
+
+/**
+ * Binder implementation.
+ */
+class BnInputFlinger : public BnInterface<IInputFlinger> {
+public:
+ enum {
+ DO_SOMETHING_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION,
+ };
+
+ virtual status_t onTransact(uint32_t code, const Parcel& data,
+ Parcel* reply, uint32_t flags = 0);
+};
+
+} // namespace android
+
+#endif // _LIBINPUT_IINPUT_FLINGER_H
diff --git a/include/input/Input.h b/include/input/Input.h
index 6d49b18..e778076 100644
--- a/include/input/Input.h
+++ b/include/input/Input.h
@@ -28,10 +28,6 @@
#include <utils/RefBase.h>
#include <utils/String8.h>
-#ifdef HAVE_ANDROID_OS
-class SkMatrix;
-#endif
-
/*
* Additional private constants not defined in ndk/ui/input.h.
*/
@@ -529,9 +525,11 @@
void scale(float scaleFactor);
-#ifdef HAVE_ANDROID_OS
- void transform(const SkMatrix* matrix);
+ // Apply 3x3 perspective matrix transformation.
+ // Matrix is in row-major form and compatible with SkMatrix.
+ void transform(const float matrix[9]);
+#ifdef HAVE_ANDROID_OS
status_t readFromParcel(Parcel* parcel);
status_t writeToParcel(Parcel* parcel) const;
#endif
diff --git a/include/input/KeycodeLabels.h b/include/input/KeycodeLabels.h
index c76ba12..c64c5d8 100644
--- a/include/input/KeycodeLabels.h
+++ b/include/input/KeycodeLabels.h
@@ -246,6 +246,7 @@
{ "ASSIST", 219 },
{ "BRIGHTNESS_DOWN", 220 },
{ "BRIGHTNESS_UP", 221 },
+ { "MEDIA_AUDIO_TRACK", 222 },
// NOTE: If you add a new keycode here you must also add it to several other files.
// Refer to frameworks/base/core/java/android/view/KeyEvent.java for the full list.
diff --git a/include/media/hardware/HardwareAPI.h b/include/media/hardware/HardwareAPI.h
index a6a849d..ac67f94 100644
--- a/include/media/hardware/HardwareAPI.h
+++ b/include/media/hardware/HardwareAPI.h
@@ -38,9 +38,13 @@
//
// When Android native buffer use has been enabled for a given port, the video
// color format for the port is to be interpreted as an Android pixel format
-// rather than an OMX color format. The node should then expect to receive
-// UseAndroidNativeBuffer calls (via OMX_SetParameter) rather than UseBuffer
-// calls for that port.
+// rather than an OMX color format. Enabling Android native buffers may also
+// change how the component receives the native buffers. If store-metadata-mode
+// is enabled on the port, the component will receive the buffers as specified
+// in the section below. Otherwise, unless the node supports the
+// 'OMX.google.android.index.useAndroidNativeBuffer2' extension, it should
+// expect to receive UseAndroidNativeBuffer calls (via OMX_SetParameter) rather
+// than UseBuffer calls for that port.
struct EnableAndroidNativeBuffersParams {
OMX_U32 nSize;
OMX_VERSIONTYPE nVersion;
@@ -62,11 +66,15 @@
//
// Currently, this is specifically used to pass meta data from video source
// (camera component, for instance) to video encoder to avoid memcpying of
-// input video frame data. To do this, bStoreMetaDta is set to OMX_TRUE.
+// input video frame data. To do this, bStoreMetaData is set to OMX_TRUE.
// If bStoreMetaData is set to false, real YUV frame data will be stored
// in the buffers. In addition, if no OMX_SetParameter() call is made
// with the corresponding extension index, real YUV data is stored
// in the buffers.
+//
+// For video decoder output port, the metadata buffer layout is defined below.
+//
+// Metadata buffers are registered with the component using UseBuffer calls.
struct StoreMetaDataInBuffersParams {
OMX_U32 nSize;
OMX_VERSIONTYPE nVersion;
diff --git a/libs/binder/AppOpsManager.cpp b/libs/binder/AppOpsManager.cpp
index 7ac1b11..99c2747 100644
--- a/libs/binder/AppOpsManager.cpp
+++ b/libs/binder/AppOpsManager.cpp
@@ -15,6 +15,7 @@
*/
#include <binder/AppOpsManager.h>
+#include <binder/Binder.h>
#include <binder/IServiceManager.h>
#include <utils/SystemClock.h>
@@ -22,6 +23,16 @@
namespace android {
static String16 _appops("appops");
+static pthread_mutex_t gTokenMutex = PTHREAD_MUTEX_INITIALIZER;
+static sp<IBinder> gToken;
+
+static const sp<IBinder>& getToken(const sp<IAppOpsService>& service) {
+ pthread_mutex_lock(&gTokenMutex);
+ if (gToken == NULL) {
+ gToken = service->getToken(new BBinder());
+ }
+ return gToken;
+}
AppOpsManager::AppOpsManager()
{
@@ -66,13 +77,14 @@
int32_t AppOpsManager::startOp(int32_t op, int32_t uid, const String16& callingPackage) {
sp<IAppOpsService> service = getService();
- return service != NULL ? service->startOperation(op, uid, callingPackage) : MODE_IGNORED;
+ return service != NULL ? service->startOperation(getToken(service), op, uid, callingPackage)
+ : MODE_IGNORED;
}
void AppOpsManager::finishOp(int32_t op, int32_t uid, const String16& callingPackage) {
sp<IAppOpsService> service = getService();
if (service != NULL) {
- service->finishOperation(op, uid, callingPackage);
+ service->finishOperation(getToken(service), op, uid, callingPackage);
}
}
diff --git a/libs/binder/IAppOpsService.cpp b/libs/binder/IAppOpsService.cpp
index 282b30f..471e3e9 100644
--- a/libs/binder/IAppOpsService.cpp
+++ b/libs/binder/IAppOpsService.cpp
@@ -61,9 +61,11 @@
return reply.readInt32();
}
- virtual int32_t startOperation(int32_t code, int32_t uid, const String16& packageName) {
+ virtual int32_t startOperation(const sp<IBinder>& token, int32_t code, int32_t uid,
+ const String16& packageName) {
Parcel data, reply;
data.writeInterfaceToken(IAppOpsService::getInterfaceDescriptor());
+ data.writeStrongBinder(token);
data.writeInt32(code);
data.writeInt32(uid);
data.writeString16(packageName);
@@ -73,9 +75,11 @@
return reply.readInt32();
}
- virtual void finishOperation(int32_t code, int32_t uid, const String16& packageName) {
+ virtual void finishOperation(const sp<IBinder>& token, int32_t code, int32_t uid,
+ const String16& packageName) {
Parcel data, reply;
data.writeInterfaceToken(IAppOpsService::getInterfaceDescriptor());
+ data.writeStrongBinder(token);
data.writeInt32(code);
data.writeInt32(uid);
data.writeString16(packageName);
@@ -98,6 +102,16 @@
data.writeStrongBinder(callback->asBinder());
remote()->transact(STOP_WATCHING_MODE_TRANSACTION, data, &reply);
}
+
+ virtual sp<IBinder> getToken(const sp<IBinder>& clientToken) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAppOpsService::getInterfaceDescriptor());
+ data.writeStrongBinder(clientToken);
+ remote()->transact(GET_TOKEN_TRANSACTION, data, &reply);
+ // fail on exception
+ if (reply.readExceptionCode() != 0) return NULL;
+ return reply.readStrongBinder();
+ }
};
IMPLEMENT_META_INTERFACE(AppOpsService, "com.android.internal.app.IAppOpsService");
@@ -131,20 +145,22 @@
} break;
case START_OPERATION_TRANSACTION: {
CHECK_INTERFACE(IAppOpsService, data, reply);
+ sp<IBinder> token = data.readStrongBinder();
int32_t code = data.readInt32();
int32_t uid = data.readInt32();
String16 packageName = data.readString16();
- int32_t res = startOperation(code, uid, packageName);
+ int32_t res = startOperation(token, code, uid, packageName);
reply->writeNoException();
reply->writeInt32(res);
return NO_ERROR;
} break;
case FINISH_OPERATION_TRANSACTION: {
CHECK_INTERFACE(IAppOpsService, data, reply);
+ sp<IBinder> token = data.readStrongBinder();
int32_t code = data.readInt32();
int32_t uid = data.readInt32();
String16 packageName = data.readString16();
- finishOperation(code, uid, packageName);
+ finishOperation(token, code, uid, packageName);
reply->writeNoException();
return NO_ERROR;
} break;
@@ -164,6 +180,14 @@
reply->writeNoException();
return NO_ERROR;
} break;
+ case GET_TOKEN_TRANSACTION: {
+ CHECK_INTERFACE(IAppOpsService, data, reply);
+ sp<IBinder> clientToken = data.readStrongBinder();
+ sp<IBinder> token = getToken(clientToken);
+ reply->writeNoException();
+ reply->writeStrongBinder(token);
+ return NO_ERROR;
+ } break;
default:
return BBinder::onTransact(code, data, reply, flags);
}
diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp
index 5a38b95..5951a3f 100644
--- a/libs/binder/IPCThreadState.cpp
+++ b/libs/binder/IPCThreadState.cpp
@@ -362,12 +362,12 @@
return err;
}
-int IPCThreadState::getCallingPid()
+int IPCThreadState::getCallingPid() const
{
return mCallingPid;
}
-int IPCThreadState::getCallingUid()
+int IPCThreadState::getCallingUid() const
{
return mCallingUid;
}
diff --git a/libs/binder/MemoryBase.cpp b/libs/binder/MemoryBase.cpp
index 5c82330..033066b 100644
--- a/libs/binder/MemoryBase.cpp
+++ b/libs/binder/MemoryBase.cpp
@@ -14,7 +14,6 @@
* limitations under the License.
*/
-#define LOG_TAG "MemoryBase"
#include <stdlib.h>
#include <stdint.h>
@@ -45,11 +44,3 @@
// ---------------------------------------------------------------------------
}; // namespace android
-
-// Backwards compatibility for libdatabase_sqlcipher (http://b/8253769).
-extern "C" void _ZN7android10MemoryBaseC1ERKNS_2spINS_11IMemoryHeapEEEij(void*, void*, ssize_t, size_t);
-extern "C" void _ZN7android10MemoryBaseC1ERKNS_2spINS_11IMemoryHeapEEElj(void* obj, void* h, long o, unsigned int size) {
- _ZN7android10MemoryBaseC1ERKNS_2spINS_11IMemoryHeapEEEij(obj, h, o, size);
- ALOGW("Using temporary compatibility workaround for usage of MemoryBase "
- "private API. Please fix your application!");
-}
diff --git a/libs/gui/BufferItemConsumer.cpp b/libs/gui/BufferItemConsumer.cpp
index ba04bdf..f5b2c7e 100644
--- a/libs/gui/BufferItemConsumer.cpp
+++ b/libs/gui/BufferItemConsumer.cpp
@@ -29,9 +29,9 @@
namespace android {
-BufferItemConsumer::BufferItemConsumer(uint32_t consumerUsage,
- int bufferCount, bool synchronousMode) :
- ConsumerBase(new BufferQueue(true) )
+BufferItemConsumer::BufferItemConsumer(const sp<BufferQueue>& bq,
+ uint32_t consumerUsage, int bufferCount, bool synchronousMode) :
+ ConsumerBase(bq)
{
mBufferQueue->setConsumerUsageBits(consumerUsage);
mBufferQueue->setSynchronousMode(synchronousMode);
@@ -47,14 +47,15 @@
mBufferQueue->setConsumerName(name);
}
-status_t BufferItemConsumer::acquireBuffer(BufferItem *item, bool waitForFence) {
+status_t BufferItemConsumer::acquireBuffer(BufferItem *item,
+ nsecs_t presentWhen, bool waitForFence) {
status_t err;
if (!item) return BAD_VALUE;
Mutex::Autolock _l(mMutex);
- err = acquireBufferLocked(item);
+ err = acquireBufferLocked(item, presentWhen);
if (err != OK) {
if (err != NO_BUFFER_AVAILABLE) {
BI_LOGE("Error acquiring buffer: %s (%d)", strerror(err), err);
diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp
index 0dab864..8d4b174 100644
--- a/libs/gui/BufferQueue.cpp
+++ b/libs/gui/BufferQueue.cpp
@@ -807,7 +807,7 @@
}
}
-status_t BufferQueue::acquireBuffer(BufferItem *buffer) {
+status_t BufferQueue::acquireBuffer(BufferItem *buffer, nsecs_t presentWhen) {
ATRACE_CALL();
Mutex::Autolock _l(mMutex);
@@ -830,38 +830,68 @@
// check if queue is empty
// In asynchronous mode the list is guaranteed to be one buffer
// deep, while in synchronous mode we use the oldest buffer.
- if (!mQueue.empty()) {
- Fifo::iterator front(mQueue.begin());
- int buf = front->mBuf;
- *buffer = *front;
- ATRACE_BUFFER_INDEX(buf);
-
- ST_LOGV("acquireBuffer: acquiring { slot=%d/%llu, buffer=%p }",
- front->mBuf, front->mFrameNumber,
- front->mGraphicBuffer->handle);
- // if front buffer still being tracked update slot state
- if (stillTracking(front)) {
- mSlots[buf].mAcquireCalled = true;
- mSlots[buf].mNeedsCleanupOnRelease = false;
- mSlots[buf].mBufferState = BufferSlot::ACQUIRED;
- mSlots[buf].mFence = Fence::NO_FENCE;
- }
-
- // If the buffer has previously been acquired by the consumer, set
- // mGraphicBuffer to NULL to avoid unnecessarily remapping this
- // buffer on the consumer side.
- if (buffer->mAcquireCalled) {
- buffer->mGraphicBuffer = NULL;
- }
-
- mQueue.erase(front);
- mDequeueCondition.broadcast();
-
- ATRACE_INT(mConsumerName.string(), mQueue.size());
- } else {
+ if (mQueue.empty()) {
return NO_BUFFER_AVAILABLE;
}
+ Fifo::iterator front(mQueue.begin());
+ int buf = front->mBuf;
+
+ // Compare the buffer's desired presentation time to the predicted
+ // actual display time.
+ //
+ // The "presentWhen" argument indicates when the buffer is expected
+ // to be presented on-screen. If the buffer's desired-present time
+ // is earlier (less) than presentWhen, meaning it'll be displayed
+ // on time or possibly late, we acquire and return it. If we don't want
+ // to display it until after the presentWhen time, we return PRESENT_LATER
+ // without acquiring it.
+ //
+ // To be safe, we don't refuse to acquire the buffer if presentWhen is
+ // more than one second in the future beyond the desired present time
+ // (i.e. we'd be holding the buffer for a really long time).
+ const int MAX_FUTURE_NSEC = 1000000000ULL;
+ nsecs_t desiredPresent = front->mTimestamp;
+ if (presentWhen != 0 && desiredPresent > presentWhen &&
+ desiredPresent - presentWhen < MAX_FUTURE_NSEC)
+ {
+ ALOGV("pts defer: des=%lld when=%lld (%lld) now=%lld",
+ desiredPresent, presentWhen, desiredPresent - presentWhen,
+ systemTime(CLOCK_MONOTONIC));
+ return PRESENT_LATER;
+ }
+ if (presentWhen != 0) {
+ ALOGV("pts accept: %p[%d] sig=%lld des=%lld when=%lld (%lld)",
+ mSlots, buf, mSlots[buf].mFence->getSignalTime(),
+ desiredPresent, presentWhen, desiredPresent - presentWhen);
+ }
+
+ *buffer = *front;
+ ATRACE_BUFFER_INDEX(buf);
+
+ ST_LOGV("acquireBuffer: acquiring { slot=%d/%llu, buffer=%p }",
+ front->mBuf, front->mFrameNumber,
+ front->mGraphicBuffer->handle);
+ // if front buffer still being tracked update slot state
+ if (stillTracking(front)) {
+ mSlots[buf].mAcquireCalled = true;
+ mSlots[buf].mNeedsCleanupOnRelease = false;
+ mSlots[buf].mBufferState = BufferSlot::ACQUIRED;
+ mSlots[buf].mFence = Fence::NO_FENCE;
+ }
+
+ // If the buffer has previously been acquired by the consumer, set
+ // mGraphicBuffer to NULL to avoid unnecessarily remapping this
+ // buffer on the consumer side.
+ if (buffer->mAcquireCalled) {
+ buffer->mGraphicBuffer = NULL;
+ }
+
+ mQueue.erase(front);
+ mDequeueCondition.broadcast();
+
+ ATRACE_INT(mConsumerName.string(), mQueue.size());
+
return NO_ERROR;
}
diff --git a/libs/gui/ConsumerBase.cpp b/libs/gui/ConsumerBase.cpp
index fd9d153..deb2646 100644
--- a/libs/gui/ConsumerBase.cpp
+++ b/libs/gui/ConsumerBase.cpp
@@ -182,8 +182,9 @@
}
}
-status_t ConsumerBase::acquireBufferLocked(BufferQueue::BufferItem *item) {
- status_t err = mBufferQueue->acquireBuffer(item);
+status_t ConsumerBase::acquireBufferLocked(BufferQueue::BufferItem *item,
+ nsecs_t presentWhen) {
+ status_t err = mBufferQueue->acquireBuffer(item, presentWhen);
if (err != NO_ERROR) {
return err;
}
diff --git a/libs/gui/CpuConsumer.cpp b/libs/gui/CpuConsumer.cpp
index 123b470..adddfc2 100644
--- a/libs/gui/CpuConsumer.cpp
+++ b/libs/gui/CpuConsumer.cpp
@@ -30,8 +30,9 @@
namespace android {
-CpuConsumer::CpuConsumer(uint32_t maxLockedBuffers, bool synchronousMode) :
- ConsumerBase(new BufferQueue(true) ),
+CpuConsumer::CpuConsumer(const sp<BufferQueue>& bq,
+ uint32_t maxLockedBuffers, bool synchronousMode) :
+ ConsumerBase(bq),
mMaxLockedBuffers(maxLockedBuffers),
mCurrentLockedBuffers(0)
{
@@ -79,7 +80,7 @@
Mutex::Autolock _l(mMutex);
- err = acquireBufferLocked(&b);
+ err = acquireBufferLocked(&b, 0);
if (err != OK) {
if (err == BufferQueue::NO_BUFFER_AVAILABLE) {
return BAD_VALUE;
diff --git a/libs/gui/GLConsumer.cpp b/libs/gui/GLConsumer.cpp
index 6d29edc..07f27c3 100644
--- a/libs/gui/GLConsumer.cpp
+++ b/libs/gui/GLConsumer.cpp
@@ -78,9 +78,9 @@
static void mtxMul(float out[16], const float a[16], const float b[16]);
-GLConsumer::GLConsumer(GLuint tex, bool allowSynchronousMode,
- GLenum texTarget, bool useFenceSync, const sp<BufferQueue> &bufferQueue) :
- ConsumerBase(bufferQueue == 0 ? new BufferQueue(allowSynchronousMode) : bufferQueue),
+GLConsumer::GLConsumer(const sp<BufferQueue>& bq, GLuint tex,
+ GLenum texTarget, bool useFenceSync) :
+ ConsumerBase(bq),
mCurrentTransform(0),
mCurrentScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE),
mCurrentFence(Fence::NO_FENCE),
@@ -139,7 +139,7 @@
// Acquire the next buffer.
// In asynchronous mode the list is guaranteed to be one buffer
// deep, while in synchronous mode we use the oldest buffer.
- err = acquireBufferLocked(&item);
+ err = acquireBufferLocked(&item, 0);
if (err != NO_ERROR) {
if (err == BufferQueue::NO_BUFFER_AVAILABLE) {
// We always bind the texture even if we don't update its contents.
@@ -165,8 +165,9 @@
return bindTextureImageLocked();
}
-status_t GLConsumer::acquireBufferLocked(BufferQueue::BufferItem *item) {
- status_t err = ConsumerBase::acquireBufferLocked(item);
+status_t GLConsumer::acquireBufferLocked(BufferQueue::BufferItem *item,
+ nsecs_t presentWhen) {
+ status_t err = ConsumerBase::acquireBufferLocked(item, presentWhen);
if (err != NO_ERROR) {
return err;
}
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index f345df8..94f21b6 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -633,7 +633,8 @@
sp<CpuConsumer> ScreenshotClient::getCpuConsumer() const {
if (mCpuConsumer == NULL) {
- mCpuConsumer = new CpuConsumer(1);
+ sp<BufferQueue> bq = new BufferQueue();
+ mCpuConsumer = new CpuConsumer(bq, 1);
mCpuConsumer->setName(String8("ScreenshotClient"));
}
return mCpuConsumer;
diff --git a/libs/gui/tests/BufferQueue_test.cpp b/libs/gui/tests/BufferQueue_test.cpp
index 62d215b..9682987 100644
--- a/libs/gui/tests/BufferQueue_test.cpp
+++ b/libs/gui/tests/BufferQueue_test.cpp
@@ -80,7 +80,7 @@
GRALLOC_USAGE_SW_READ_OFTEN));
ASSERT_EQ(OK, mBQ->requestBuffer(slot, &buf));
ASSERT_EQ(OK, mBQ->queueBuffer(slot, qbi, &qbo));
- ASSERT_EQ(OK, mBQ->acquireBuffer(&item));
+ ASSERT_EQ(OK, mBQ->acquireBuffer(&item, 0));
}
ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
@@ -90,7 +90,7 @@
ASSERT_EQ(OK, mBQ->queueBuffer(slot, qbi, &qbo));
// Acquire the third buffer, which should fail.
- ASSERT_EQ(INVALID_OPERATION, mBQ->acquireBuffer(&item));
+ ASSERT_EQ(INVALID_OPERATION, mBQ->acquireBuffer(&item, 0));
}
TEST_F(BufferQueueTest, SetMaxAcquiredBufferCountWithIllegalValues_ReturnsError) {
diff --git a/libs/gui/tests/CpuConsumer_test.cpp b/libs/gui/tests/CpuConsumer_test.cpp
index 73fdd04..f8a35b4 100644
--- a/libs/gui/tests/CpuConsumer_test.cpp
+++ b/libs/gui/tests/CpuConsumer_test.cpp
@@ -66,7 +66,8 @@
test_info->name(),
params.width, params.height,
params.maxLockedBuffers, params.format);
- mCC = new CpuConsumer(params.maxLockedBuffers);
+ sp<BufferQueue> bq = new BufferQueue();
+ mCC = new CpuConsumer(bq, params.maxLockedBuffers);
String8 name("CpuConsumer_Under_Test");
mCC->setName(name);
mSTC = new Surface(mCC->getProducerInterface());
diff --git a/libs/gui/tests/SurfaceTextureClient_test.cpp b/libs/gui/tests/SurfaceTextureClient_test.cpp
index 7376b4c..46bcb22 100644
--- a/libs/gui/tests/SurfaceTextureClient_test.cpp
+++ b/libs/gui/tests/SurfaceTextureClient_test.cpp
@@ -40,7 +40,8 @@
ALOGV("Begin test: %s.%s", testInfo->test_case_name(),
testInfo->name());
- mST = new GLConsumer(123);
+ sp<BufferQueue> bq = new BufferQueue();
+ mST = new GLConsumer(bq, 123);
mSTC = new Surface(mST->getBufferQueue());
mANW = mSTC;
@@ -715,7 +716,8 @@
ASSERT_NE(EGL_NO_CONTEXT, mEglContext);
for (int i = 0; i < NUM_SURFACE_TEXTURES; i++) {
- sp<GLConsumer> st(new GLConsumer(i));
+ sp<BufferQueue> bq = new BufferQueue();
+ sp<GLConsumer> st(new GLConsumer(bq, i));
sp<Surface> stc(new Surface(st->getBufferQueue()));
mEglSurfaces[i] = eglCreateWindowSurface(mEglDisplay, myConfig,
static_cast<ANativeWindow*>(stc.get()), NULL);
diff --git a/libs/gui/tests/SurfaceTexture_test.cpp b/libs/gui/tests/SurfaceTexture_test.cpp
index dd6c435..d97521a 100644
--- a/libs/gui/tests/SurfaceTexture_test.cpp
+++ b/libs/gui/tests/SurfaceTexture_test.cpp
@@ -385,7 +385,8 @@
virtual void SetUp() {
GLTest::SetUp();
- mGlConsumer = new GLConsumer(TEX_ID);
+ sp<BufferQueue> bq = new BufferQueue();
+ mGlConsumer = new GLConsumer(bq, TEX_ID);
mSurface = new Surface(mGlConsumer->getBufferQueue());
mANW = mSurface.get();
@@ -479,7 +480,8 @@
virtual void SetUp() {
GLTest::SetUp();
- mST = new GLConsumer(TEX_ID);
+ sp<BufferQueue> bq = new BufferQueue();
+ mST = new GLConsumer(bq, TEX_ID);
mSTC = new Surface(mST->getBufferQueue());
mANW = mSTC;
mTextureRenderer = new TextureRenderer(TEX_ID, mST);
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index 429becf..953f6f9 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -87,7 +87,8 @@
sp<ANativeWindow> anw(mSurface);
// Verify the screenshot works with no protected buffers.
- sp<CpuConsumer> consumer = new CpuConsumer(1);
+ sp<BufferQueue> bq = new BufferQueue();
+ sp<CpuConsumer> consumer = new CpuConsumer(bq, 1);
sp<ISurfaceComposer> sf(ComposerService::getComposerService());
sp<IBinder> display(sf->getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
ASSERT_EQ(NO_ERROR, sf->captureScreen(display, consumer->getBufferQueue(),
diff --git a/libs/input/Android.mk b/libs/input/Android.mk
index 2a1e762..944ac7f 100644
--- a/libs/input/Android.mk
+++ b/libs/input/Android.mk
@@ -12,8 +12,6 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-ifneq ($(TARGET_BUILD_PDK),true)
-
LOCAL_PATH:= $(call my-dir)
# libinput is partially built for the host (used by build time keymap validation tool)
@@ -29,6 +27,7 @@
deviceSources := \
$(commonSources) \
+ IInputFlinger.cpp \
InputTransport.cpp \
VelocityControl.cpp \
VelocityTracker.cpp
@@ -61,14 +60,7 @@
liblog \
libcutils \
libutils \
- libbinder \
- libskia \
- libz
-
-LOCAL_C_INCLUDES := \
- external/skia/include/core \
- external/icu4c/common \
- external/zlib
+ libbinder
LOCAL_MODULE:= libinput
@@ -85,5 +77,3 @@
ifeq (,$(ONE_SHOT_MAKEFILE))
include $(call first-makefiles-under,$(LOCAL_PATH))
endif
-
-endif #!PDK
diff --git a/libs/input/IInputFlinger.cpp b/libs/input/IInputFlinger.cpp
new file mode 100644
index 0000000..e009731
--- /dev/null
+++ b/libs/input/IInputFlinger.cpp
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2013 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 <stdint.h>
+#include <sys/types.h>
+
+#include <binder/Parcel.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+
+#include <input/IInputFlinger.h>
+
+
+namespace android {
+
+class BpInputFlinger : public BpInterface<IInputFlinger> {
+public:
+ BpInputFlinger(const sp<IBinder>& impl) :
+ BpInterface<IInputFlinger>(impl) { }
+
+ virtual status_t doSomething() {
+ Parcel data, reply;
+ data.writeInterfaceToken(IInputFlinger::getInterfaceDescriptor());
+ remote()->transact(BnInputFlinger::DO_SOMETHING_TRANSACTION, data, &reply);
+ return reply.readInt32();
+ }
+};
+
+IMPLEMENT_META_INTERFACE(InputFlinger, "android.input.IInputFlinger");
+
+
+status_t BnInputFlinger::onTransact(
+ uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) {
+ switch(code) {
+ case DO_SOMETHING_TRANSACTION: {
+ CHECK_INTERFACE(IInputFlinger, data, reply);
+ reply->writeInt32(0);
+ break;
+ }
+ default:
+ return BBinder::onTransact(code, data, reply, flags);
+ }
+ return NO_ERROR;
+}
+
+};
diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp
index 7a217c3..6f53996 100644
--- a/libs/input/Input.cpp
+++ b/libs/input/Input.cpp
@@ -24,10 +24,6 @@
#ifdef HAVE_ANDROID_OS
#include <binder/Parcel.h>
-
-#include "SkPoint.h"
-#include "SkMatrix.h"
-#include "SkScalar.h"
#endif
namespace android {
@@ -74,6 +70,7 @@
case AKEYCODE_MUTE:
case AKEYCODE_BRIGHTNESS_DOWN:
case AKEYCODE_BRIGHTNESS_UP:
+ case AKEYCODE_MEDIA_AUDIO_TRACK:
return true;
}
@@ -112,6 +109,7 @@
case AKEYCODE_SEARCH:
case AKEYCODE_BRIGHTNESS_DOWN:
case AKEYCODE_BRIGHTNESS_UP:
+ case AKEYCODE_MEDIA_AUDIO_TRACK:
return true;
}
@@ -421,17 +419,30 @@
}
}
-#ifdef HAVE_ANDROID_OS
-static inline float transformAngle(const SkMatrix* matrix, float angleRadians) {
+static void transformPoint(const float matrix[9], float x, float y, float *outX, float *outY) {
+ // Apply perspective transform like Skia.
+ float newX = matrix[0] * x + matrix[1] * y + matrix[2];
+ float newY = matrix[3] * x + matrix[4] * y + matrix[5];
+ float newZ = matrix[6] * x + matrix[7] * y + matrix[8];
+ if (newZ) {
+ newZ = 1.0f / newZ;
+ }
+ *outX = newX * newZ;
+ *outY = newY * newZ;
+}
+
+static float transformAngle(const float matrix[9], float angleRadians,
+ float originX, float originY) {
// Construct and transform a vector oriented at the specified clockwise angle from vertical.
// Coordinate system: down is increasing Y, right is increasing X.
- SkPoint vector;
- vector.fX = SkFloatToScalar(sinf(angleRadians));
- vector.fY = SkFloatToScalar(-cosf(angleRadians));
- matrix->mapVectors(& vector, 1);
+ float x = sinf(angleRadians);
+ float y = -cosf(angleRadians);
+ transformPoint(matrix, x, y, &x, &y);
+ x -= originX;
+ y -= originY;
// Derive the transformed vector's clockwise angle from vertical.
- float result = atan2f(SkScalarToFloat(vector.fX), SkScalarToFloat(-vector.fY));
+ float result = atan2f(x, -y);
if (result < - M_PI_2) {
result += M_PI;
} else if (result > M_PI_2) {
@@ -440,25 +451,24 @@
return result;
}
-void MotionEvent::transform(const SkMatrix* matrix) {
- float oldXOffset = mXOffset;
- float oldYOffset = mYOffset;
-
+void MotionEvent::transform(const float matrix[9]) {
// The tricky part of this implementation is to preserve the value of
// rawX and rawY. So we apply the transformation to the first point
- // then derive an appropriate new X/Y offset that will preserve rawX and rawY.
- SkPoint point;
+ // then derive an appropriate new X/Y offset that will preserve rawX
+ // and rawY for that point.
+ float oldXOffset = mXOffset;
+ float oldYOffset = mYOffset;
+ float newX, newY;
float rawX = getRawX(0);
float rawY = getRawY(0);
- matrix->mapXY(SkFloatToScalar(rawX + oldXOffset), SkFloatToScalar(rawY + oldYOffset),
- & point);
- float newX = SkScalarToFloat(point.fX);
- float newY = SkScalarToFloat(point.fY);
- float newXOffset = newX - rawX;
- float newYOffset = newY - rawY;
+ transformPoint(matrix, rawX + oldXOffset, rawY + oldYOffset, &newX, &newY);
+ mXOffset = newX - rawX;
+ mYOffset = newY - rawY;
- mXOffset = newXOffset;
- mYOffset = newYOffset;
+ // Determine how the origin is transformed by the matrix so that we
+ // can transform orientation vectors.
+ float originX, originY;
+ transformPoint(matrix, 0, 0, &originX, &originY);
// Apply the transformation to all samples.
size_t numSamples = mSamplePointerCoords.size();
@@ -466,15 +476,17 @@
PointerCoords& c = mSamplePointerCoords.editItemAt(i);
float x = c.getAxisValue(AMOTION_EVENT_AXIS_X) + oldXOffset;
float y = c.getAxisValue(AMOTION_EVENT_AXIS_Y) + oldYOffset;
- matrix->mapXY(SkFloatToScalar(x), SkFloatToScalar(y), &point);
- c.setAxisValue(AMOTION_EVENT_AXIS_X, SkScalarToFloat(point.fX) - newXOffset);
- c.setAxisValue(AMOTION_EVENT_AXIS_Y, SkScalarToFloat(point.fY) - newYOffset);
+ transformPoint(matrix, x, y, &x, &y);
+ c.setAxisValue(AMOTION_EVENT_AXIS_X, x - mXOffset);
+ c.setAxisValue(AMOTION_EVENT_AXIS_Y, y - mYOffset);
float orientation = c.getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION);
- c.setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, transformAngle(matrix, orientation));
+ c.setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION,
+ transformAngle(matrix, orientation, originX, originY));
}
}
+#ifdef HAVE_ANDROID_OS
status_t MotionEvent::readFromParcel(Parcel* parcel) {
size_t pointerCount = parcel->readInt32();
size_t sampleCount = parcel->readInt32();
diff --git a/libs/input/tests/Android.mk b/libs/input/tests/Android.mk
index 4292741..c62dff1 100644
--- a/libs/input/tests/Android.mk
+++ b/libs/input/tests/Android.mk
@@ -14,8 +14,7 @@
libutils \
libbinder \
libui \
- libstlport \
- libskia
+ libstlport
static_libraries := \
libgtest \
diff --git a/libs/input/tests/InputEvent_test.cpp b/libs/input/tests/InputEvent_test.cpp
index ab1feb3..78ea98e 100644
--- a/libs/input/tests/InputEvent_test.cpp
+++ b/libs/input/tests/InputEvent_test.cpp
@@ -17,7 +17,6 @@
#include <math.h>
#include <binder/Parcel.h>
-#include <core/SkMatrix.h>
#include <gtest/gtest.h>
#include <input/Input.h>
@@ -519,6 +518,20 @@
ASSERT_NO_FATAL_FAILURE(assertEqualsEventWithHistory(&outEvent));
}
+static void setRotationMatrix(float matrix[9], float angle) {
+ float sin = sinf(angle);
+ float cos = cosf(angle);
+ matrix[0] = cos;
+ matrix[1] = -sin;
+ matrix[2] = 0;
+ matrix[3] = sin;
+ matrix[4] = cos;
+ matrix[5] = 0;
+ matrix[6] = 0;
+ matrix[7] = 0;
+ matrix[8] = 1.0f;
+}
+
TEST_F(MotionEventTest, Transform) {
// Generate some points on a circle.
// Each point 'i' is a point on a circle of radius ROTATION centered at (3,2) at an angle
@@ -561,9 +574,9 @@
ASSERT_NEAR(originalRawY, event.getRawY(0), 0.001);
// Apply a rotation about the origin by ROTATION degrees clockwise.
- SkMatrix matrix;
- matrix.setRotate(ROTATION);
- event.transform(&matrix);
+ float matrix[9];
+ setRotationMatrix(matrix, ROTATION * PI_180);
+ event.transform(matrix);
// Check the points.
for (size_t i = 0; i < pointerCount; i++) {
diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp
index c02a85f..beaa560 100644
--- a/opengl/libs/EGL/Loader.cpp
+++ b/opengl/libs/EGL/Loader.cpp
@@ -1,16 +1,16 @@
-/*
+/*
** Copyright 2007, 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
+ ** 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
+ ** 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
+ ** 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.
*/
@@ -56,9 +56,9 @@
*
* For backward compatibility and to facilitate the transition to
* this new naming scheme, the loader will additionally look for:
- *
+ *
* /{vendor|system}/lib/egl/lib{GLES | [EGL|GLESv1_CM|GLESv2]}_*.so
- *
+ *
*/
ANDROID_SINGLETON_STATIC_INSTANCE( Loader )
@@ -116,14 +116,14 @@
// ----------------------------------------------------------------------------
-Loader::driver_t::driver_t(void* gles)
+Loader::driver_t::driver_t(void* gles)
{
dso[0] = gles;
for (size_t i=1 ; i<NELEM(dso) ; i++)
dso[i] = 0;
}
-Loader::driver_t::~driver_t()
+Loader::driver_t::~driver_t()
{
for (size_t i=0 ; i<NELEM(dso) ; i++) {
if (dso[i]) {
@@ -161,11 +161,17 @@
GLTrace_stop();
}
+static void* load_wrapper(const char* path) {
+ void* so = dlopen(path, RTLD_NOW | RTLD_LOCAL);
+ ALOGE_IF(!so, "dlopen(\"%s\") failed: %s", path, dlerror());
+ return so;
+}
+
void* Loader::open(egl_connection_t* cnx)
{
void* dso;
driver_t* hnd = 0;
-
+
dso = load_driver("GLES", cnx, EGL | GLESv1_CM | GLESv2);
if (dso) {
hnd = new driver_t(dso);
@@ -180,7 +186,12 @@
}
LOG_ALWAYS_FATAL_IF(!hnd, "couldn't find an OpenGL ES implementation");
-
+
+ cnx->libGles2 = load_wrapper("/system/lib/libGLESv2.so");
+ cnx->libGles1 = load_wrapper("/system/lib/libGLESv1_CM.so");
+ LOG_ALWAYS_FATAL_IF(!cnx->libGles2 || !cnx->libGles1,
+ "couldn't load system OpenGL ES wrapper libraries");
+
return (void*)hnd;
}
@@ -191,16 +202,16 @@
return NO_ERROR;
}
-void Loader::init_api(void* dso,
- char const * const * api,
- __eglMustCastToProperFunctionPointerType* curr,
- getProcAddressType getProcAddress)
+void Loader::init_api(void* dso,
+ char const * const * api,
+ __eglMustCastToProperFunctionPointerType* curr,
+ getProcAddressType getProcAddress)
{
const ssize_t SIZE = 256;
char scrap[SIZE];
while (*api) {
char const * name = *api;
- __eglMustCastToProperFunctionPointerType f =
+ __eglMustCastToProperFunctionPointerType f =
(__eglMustCastToProperFunctionPointerType)dlsym(dso, name);
if (f == NULL) {
// couldn't find the entry-point, use eglGetProcAddress()
@@ -360,7 +371,7 @@
if (mask & EGL) {
getProcAddress = (getProcAddressType)dlsym(dso, "eglGetProcAddress");
- ALOGE_IF(!getProcAddress,
+ ALOGE_IF(!getProcAddress,
"can't find eglGetProcAddress() in %s", driver_absolute_path);
#ifdef SYSTEMUI_PBSIZE_HACK
@@ -398,7 +409,7 @@
char const * const * api = egl_names;
while (*api) {
char const * name = *api;
- __eglMustCastToProperFunctionPointerType f =
+ __eglMustCastToProperFunctionPointerType f =
(__eglMustCastToProperFunctionPointerType)dlsym(dso, name);
if (f == NULL) {
// couldn't find the entry-point, use eglGetProcAddress()
@@ -411,7 +422,7 @@
api++;
}
}
-
+
if (mask & GLESv1_CM) {
init_api(dso, gl_names,
(__eglMustCastToProperFunctionPointerType*)
@@ -425,7 +436,7 @@
&cnx->hooks[egl_connection_t::GLESv2_INDEX]->gl,
getProcAddress);
}
-
+
return dso;
}
diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp
index 0358fcc..6c285d3 100644
--- a/opengl/libs/EGL/eglApi.cpp
+++ b/opengl/libs/EGL/eglApi.cpp
@@ -16,6 +16,7 @@
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+#include <dlfcn.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
@@ -372,7 +373,7 @@
if (native_window_api_connect(window, NATIVE_WINDOW_API_EGL) != OK) {
ALOGE("EGLNativeWindowType %p already connected to another API",
window);
- return setError(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE);
+ return setError(EGL_BAD_ALLOC, EGL_NO_SURFACE);
}
// set the native window's buffers format to match this config
@@ -777,6 +778,20 @@
return err;
}
+static __eglMustCastToProperFunctionPointerType findBuiltinGLWrapper(
+ const char* procname) {
+ const egl_connection_t* cnx = &gEGLImpl;
+ void* proc = NULL;
+
+ proc = dlsym(cnx->libGles2, procname);
+ if (proc) return (__eglMustCastToProperFunctionPointerType)proc;
+
+ proc = dlsym(cnx->libGles1, procname);
+ if (proc) return (__eglMustCastToProperFunctionPointerType)proc;
+
+ return NULL;
+}
+
__eglMustCastToProperFunctionPointerType eglGetProcAddress(const char *procname)
{
// eglGetProcAddress() could be the very first function called
@@ -798,6 +813,8 @@
addr = findProcAddress(procname, sExtensionMap, NELEM(sExtensionMap));
if (addr) return addr;
+ addr = findBuiltinGLWrapper(procname);
+ if (addr) return addr;
// this protects accesses to sGLExtentionMap and sGLExtentionSlot
pthread_mutex_lock(&sExtensionMapMutex);
diff --git a/opengl/libs/EGL/egldefs.h b/opengl/libs/EGL/egldefs.h
index 1cfe561..b905ea0 100644
--- a/opengl/libs/EGL/egldefs.h
+++ b/opengl/libs/EGL/egldefs.h
@@ -43,6 +43,9 @@
EGLint major;
EGLint minor;
egl_t egl;
+
+ void* libGles1;
+ void* libGles2;
};
// ----------------------------------------------------------------------------
diff --git a/services/inputflinger/Android.mk b/services/inputflinger/Android.mk
new file mode 100644
index 0000000..7148db8
--- /dev/null
+++ b/services/inputflinger/Android.mk
@@ -0,0 +1,35 @@
+# Copyright (C) 2013 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ InputFlinger.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+ libbinder \
+ libcutils \
+ libinput \
+ liblog \
+ libutils
+
+LOCAL_CFLAGS += -fvisibility=hidden
+
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)
+
+LOCAL_MODULE := libinputflinger
+
+include $(BUILD_SHARED_LIBRARY)
+
diff --git a/services/inputflinger/InputFlinger.cpp b/services/inputflinger/InputFlinger.cpp
new file mode 100644
index 0000000..9ea6ce5
--- /dev/null
+++ b/services/inputflinger/InputFlinger.cpp
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "InputFlinger"
+
+#include "InputFlinger.h"
+
+#include <stdint.h>
+#include <unistd.h>
+
+#include <sys/types.h>
+
+#include <binder/IPCThreadState.h>
+#include <binder/PermissionCache.h>
+#include <cutils/log.h>
+#include <private/android_filesystem_config.h>
+
+namespace android {
+
+const String16 sAccessInputFlingerPermission("android.permission.ACCESS_INPUT_FLINGER");
+const String16 sDumpPermission("android.permission.DUMP");
+
+
+InputFlinger::InputFlinger() :
+ BnInputFlinger() {
+ ALOGI("InputFlinger is starting");
+}
+
+InputFlinger::~InputFlinger() {
+}
+
+status_t InputFlinger::onTransact(
+ uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) {
+ switch (code) {
+ case DO_SOMETHING_TRANSACTION:
+ const IPCThreadState* ipc = IPCThreadState::self();
+ const int pid = ipc->getCallingPid();
+ const int uid = ipc->getCallingUid();
+ if (!PermissionCache::checkPermission(sAccessInputFlingerPermission, pid, uid)) {
+ ALOGE("Permission Denial: "
+ "can't access InputFlinger from pid=%d, uid=%d", pid, uid);
+ return PERMISSION_DENIED;
+ }
+ break;
+ }
+
+ return BnInputFlinger::onTransact(code, data, reply, flags);
+}
+
+status_t InputFlinger::dump(int fd, const Vector<String16>& args) {
+ String8 result;
+ const IPCThreadState* ipc = IPCThreadState::self();
+ const int pid = ipc->getCallingPid();
+ const int uid = ipc->getCallingUid();
+ if ((uid != AID_SHELL)
+ && !PermissionCache::checkPermission(sDumpPermission, pid, uid)) {
+ result.appendFormat("Permission Denial: "
+ "can't dump SurfaceFlinger from pid=%d, uid=%d\n", pid, uid);
+ } else {
+ dumpInternal(result);
+ }
+ write(fd, result.string(), result.size());
+ return OK;
+}
+
+void InputFlinger::dumpInternal(String8& result) {
+ result.append("INPUT FLINGER (dumpsys inputflinger)\n");
+ result.append("... nothing here yet...\n");
+}
+
+status_t InputFlinger::doSomething() {
+ ALOGI("Did something...");
+ return OK;
+}
+
+}; // namespace android
diff --git a/services/inputflinger/InputFlinger.h b/services/inputflinger/InputFlinger.h
new file mode 100644
index 0000000..731ab17
--- /dev/null
+++ b/services/inputflinger/InputFlinger.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2013 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_INPUT_FLINGER_H
+#define ANDROID_INPUT_FLINGER_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <cutils/compiler.h>
+#include <input/IInputFlinger.h>
+#include <utils/String8.h>
+#include <utils/String16.h>
+
+namespace android {
+
+class InputFlinger : public BnInputFlinger {
+public:
+ static char const* getServiceName() ANDROID_API {
+ return "inputflinger";
+ }
+
+ InputFlinger() ANDROID_API;
+
+ // IBinder interface
+ virtual status_t onTransact(uint32_t code,
+ const Parcel& data, Parcel* reply, uint32_t flags);
+ virtual status_t dump(int fd, const Vector<String16>& args);
+
+ // IInputFlinger interface
+ virtual status_t doSomething();
+
+private:
+ virtual ~InputFlinger();
+
+ void dumpInternal(String8& result);
+};
+
+} // namespace android
+
+#endif // ANDROID_INPUT_FLINGER_H
diff --git a/services/sensorservice/BatteryService.cpp b/services/sensorservice/BatteryService.cpp
index 70b65ab..38dc749 100644
--- a/services/sensorservice/BatteryService.cpp
+++ b/services/sensorservice/BatteryService.cpp
@@ -33,7 +33,7 @@
BatteryService::BatteryService() {
const sp<IServiceManager> sm(defaultServiceManager());
if (sm != NULL) {
- const String16 name("batteryinfo");
+ const String16 name("batterystats");
mBatteryStatService = sm->getService(name);
}
}
diff --git a/services/sensorservice/SensorDevice.cpp b/services/sensorservice/SensorDevice.cpp
index 18a1523..2fa5dbd 100644
--- a/services/sensorservice/SensorDevice.cpp
+++ b/services/sensorservice/SensorDevice.cpp
@@ -107,13 +107,10 @@
return c;
}
-status_t SensorDevice::resetStateWithoutActuatingHardware(void *ident, int handle)
-{
- if (!mSensorDevice) return NO_INIT;
- Info& info( mActivationCount.editValueFor(handle));
+void SensorDevice::autoDisable(void *ident, int handle) {
+ Info& info( mActivationCount.editValueFor(handle) );
Mutex::Autolock _l(mLock);
info.rates.removeItem(ident);
- return NO_ERROR;
}
status_t SensorDevice::activate(void* ident, int handle, int enabled)
@@ -164,6 +161,15 @@
ALOGE_IF(err, "Error %s sensor %d (%s)",
enabled ? "activating" : "disabling",
handle, strerror(-err));
+
+ if (err != NO_ERROR) {
+ // clean-up on failure
+ if (enabled) {
+ // failure when enabling the sensor
+ Mutex::Autolock _l(mLock);
+ info.rates.removeItem(ident);
+ }
+ }
}
{ // scope for the lock
diff --git a/services/sensorservice/SensorDevice.h b/services/sensorservice/SensorDevice.h
index ca67ce2..b50e205 100644
--- a/services/sensorservice/SensorDevice.h
+++ b/services/sensorservice/SensorDevice.h
@@ -56,7 +56,7 @@
ssize_t poll(sensors_event_t* buffer, size_t count);
status_t activate(void* ident, int handle, int enabled);
status_t setDelay(void* ident, int handle, int64_t ns);
- status_t resetStateWithoutActuatingHardware(void *ident, int handle);
+ void autoDisable(void *ident, int handle);
void dump(String8& result);
};
diff --git a/services/sensorservice/SensorInterface.cpp b/services/sensorservice/SensorInterface.cpp
index cf0a11d..b483b75 100644
--- a/services/sensorservice/SensorInterface.cpp
+++ b/services/sensorservice/SensorInterface.cpp
@@ -54,8 +54,8 @@
return mSensorDevice.setDelay(ident, handle, ns);
}
-status_t HardwareSensor::resetStateWithoutActuatingHardware(void *ident, int handle) {
- return mSensorDevice.resetStateWithoutActuatingHardware(ident, handle);
+void HardwareSensor::autoDisable(void *ident, int handle) {
+ mSensorDevice.autoDisable(ident, handle);
}
Sensor HardwareSensor::getSensor() const {
diff --git a/services/sensorservice/SensorInterface.h b/services/sensorservice/SensorInterface.h
index 2e709ae..2e14e57 100644
--- a/services/sensorservice/SensorInterface.h
+++ b/services/sensorservice/SensorInterface.h
@@ -40,11 +40,7 @@
virtual status_t setDelay(void* ident, int handle, int64_t ns) = 0;
virtual Sensor getSensor() const = 0;
virtual bool isVirtual() const = 0;
- virtual status_t resetStateWithoutActuatingHardware(void *ident, int handle) {
- // Override when you want to clean up for sensors which auto disable
- // after trigger, or when enabling sensors fail.
- return INVALID_OPERATION;
- }
+ virtual void autoDisable(void *ident, int handle) { }
};
// ---------------------------------------------------------------------------
@@ -66,7 +62,7 @@
virtual status_t setDelay(void* ident, int handle, int64_t ns);
virtual Sensor getSensor() const;
virtual bool isVirtual() const { return false; }
- virtual status_t resetStateWithoutActuatingHardware(void *ident, int handle);
+ virtual void autoDisable(void *ident, int handle);
};
diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
index 99993ba..e3d2a60 100644
--- a/services/sensorservice/SensorService.cpp
+++ b/services/sensorservice/SensorService.cpp
@@ -274,10 +274,8 @@
if (type == SENSOR_TYPE_SIGNIFICANT_MOTION) {
if (connection->hasSensor(handle)) {
sensor = mSensorMap.valueFor(handle);
- err = sensor ?sensor->resetStateWithoutActuatingHardware(connection.get(), handle)
- : status_t(BAD_VALUE);
- if (err != NO_ERROR) {
- ALOGE("Sensor Inteface: Resetting state failed with err: %d", err);
+ if (sensor != NULL) {
+ sensor->autoDisable(connection.get(), handle);
}
cleanupWithoutDisable(connection, handle);
}
@@ -509,8 +507,12 @@
if (mInitCheck != NO_ERROR)
return mInitCheck;
- Mutex::Autolock _l(mLock);
SensorInterface* sensor = mSensorMap.valueFor(handle);
+ if (sensor == NULL) {
+ return BAD_VALUE;
+ }
+
+ Mutex::Autolock _l(mLock);
SensorRecord* rec = mActiveSensors.valueFor(handle);
if (rec == 0) {
rec = new SensorRecord(connection);
@@ -546,16 +548,11 @@
handle, connection.get());
}
-
// we are setup, now enable the sensor.
- status_t err = sensor ? sensor->activate(connection.get(), true) : status_t(BAD_VALUE);
-
+ status_t err = sensor->activate(connection.get(), true);
if (err != NO_ERROR) {
- // enable has failed, reset state in SensorDevice.
- status_t resetErr = sensor ? sensor->resetStateWithoutActuatingHardware(connection.get(),
- handle) : status_t(BAD_VALUE);
// enable has failed, reset our state.
- cleanupWithoutDisable(connection, handle);
+ cleanupWithoutDisableLocked(connection, handle);
}
return err;
}
@@ -566,7 +563,8 @@
if (mInitCheck != NO_ERROR)
return mInitCheck;
- status_t err = cleanupWithoutDisable(connection, handle);
+ Mutex::Autolock _l(mLock);
+ status_t err = cleanupWithoutDisableLocked(connection, handle);
if (err == NO_ERROR) {
SensorInterface* sensor = mSensorMap.valueFor(handle);
err = sensor ? sensor->activate(connection.get(), false) : status_t(BAD_VALUE);
@@ -574,9 +572,14 @@
return err;
}
-status_t SensorService::cleanupWithoutDisable(const sp<SensorEventConnection>& connection,
- int handle) {
+status_t SensorService::cleanupWithoutDisable(
+ const sp<SensorEventConnection>& connection, int handle) {
Mutex::Autolock _l(mLock);
+ return cleanupWithoutDisableLocked(connection, handle);
+}
+
+status_t SensorService::cleanupWithoutDisableLocked(
+ const sp<SensorEventConnection>& connection, int handle) {
SensorRecord* rec = mActiveSensors.valueFor(handle);
if (rec) {
// see if this connection becomes inactive
diff --git a/services/sensorservice/SensorService.h b/services/sensorservice/SensorService.h
index 56b0a3e..69e5dbb 100644
--- a/services/sensorservice/SensorService.h
+++ b/services/sensorservice/SensorService.h
@@ -115,8 +115,10 @@
static void sortEventBuffer(sensors_event_t* buffer, size_t count);
Sensor registerSensor(SensorInterface* sensor);
Sensor registerVirtualSensor(SensorInterface* sensor);
- status_t cleanupWithoutDisable(const sp<SensorEventConnection>& connection,
- int handle);
+ status_t cleanupWithoutDisable(
+ const sp<SensorEventConnection>& connection, int handle);
+ status_t cleanupWithoutDisableLocked(
+ const sp<SensorEventConnection>& connection, int handle);
void cleanupAutoDisabledSensor(const sp<SensorEventConnection>& connection,
sensors_event_t const* buffer, const int count);
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index 2eae9c2..c67f4d8 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -188,6 +188,25 @@
mPageFlipCount++;
}
+status_t DisplayDevice::prepareFrame(const HWComposer& hwc) const {
+ DisplaySurface::CompositionType compositionType;
+ bool haveGles = hwc.hasGlesComposition(mHwcDisplayId);
+ bool haveHwc = hwc.hasHwcComposition(mHwcDisplayId);
+ if (haveGles && haveHwc) {
+ compositionType = DisplaySurface::COMPOSITION_MIXED;
+ } else if (haveGles) {
+ compositionType = DisplaySurface::COMPOSITION_GLES;
+ } else if (haveHwc) {
+ compositionType = DisplaySurface::COMPOSITION_HWC;
+ } else {
+ // Nothing to do -- when turning the screen off we get a frame like
+ // this. Call it a HWC frame since we won't be doing any GLES work but
+ // will do a prepare/set cycle.
+ compositionType = DisplaySurface::COMPOSITION_HWC;
+ }
+ return mDisplaySurface->prepareFrame(compositionType);
+}
+
void DisplayDevice::swapBuffers(HWComposer& hwc) const {
// We need to call eglSwapBuffers() unless:
// (a) there was no GLES composition this frame, or
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index eefc107..748be1a 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -119,6 +119,8 @@
int32_t getHwcDisplayId() const { return mHwcDisplayId; }
const wp<IBinder>& getDisplayToken() const { return mDisplayToken; }
+ status_t prepareFrame(const HWComposer& hwc) const;
+
void swapBuffers(HWComposer& hwc) const;
status_t compositionComplete() const;
diff --git a/services/surfaceflinger/DisplayHardware/DisplaySurface.h b/services/surfaceflinger/DisplayHardware/DisplaySurface.h
index 2eca3cb..b0f460d 100644
--- a/services/surfaceflinger/DisplayHardware/DisplaySurface.h
+++ b/services/surfaceflinger/DisplayHardware/DisplaySurface.h
@@ -32,6 +32,18 @@
public:
virtual sp<IGraphicBufferProducer> getIGraphicBufferProducer() const = 0;
+ // prepareFrame is called after the composition configuration is known but
+ // before composition takes place. The DisplaySurface can use the
+ // composition type to decide how to manage the flow of buffers between
+ // GLES and HWC for this frame.
+ enum CompositionType {
+ COMPOSITION_UNKNOWN = 0,
+ COMPOSITION_GLES = 1,
+ COMPOSITION_HWC = 2,
+ COMPOSITION_MIXED = COMPOSITION_GLES | COMPOSITION_HWC
+ };
+ virtual status_t prepareFrame(CompositionType compositionType) = 0;
+
// Should be called when composition rendering is complete for a frame (but
// eglSwapBuffers hasn't necessarily been called). Required by certain
// older drivers for synchronization.
diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
index 10bca38..7987da3 100644
--- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
@@ -72,6 +72,10 @@
return getBufferQueue();
}
+status_t FramebufferSurface::prepareFrame(CompositionType compositionType) {
+ return NO_ERROR;
+}
+
status_t FramebufferSurface::advanceFrame() {
// Once we remove FB HAL support, we can call nextBuffer() from here
// instead of using onFrameAvailable(). No real benefit, except it'll be
@@ -83,7 +87,7 @@
Mutex::Autolock lock(mMutex);
BufferQueue::BufferItem item;
- status_t err = acquireBufferLocked(&item);
+ status_t err = acquireBufferLocked(&item, 0);
if (err == BufferQueue::NO_BUFFER_AVAILABLE) {
outBuffer = mCurrentBuffer;
return NO_ERROR;
diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.h b/services/surfaceflinger/DisplayHardware/FramebufferSurface.h
index c86e9ae..92a7f9b 100644
--- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.h
+++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.h
@@ -41,6 +41,7 @@
virtual sp<IGraphicBufferProducer> getIGraphicBufferProducer() const;
+ virtual status_t prepareFrame(CompositionType compositionType);
virtual status_t compositionComplete();
virtual status_t advanceFrame();
virtual void onFrameCommitted();
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 1cdabc4..f6256f9 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -16,9 +16,6 @@
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
-// Uncomment this to remove support for HWC_DEVICE_API_VERSION_0_3 and older
-#define HWC_REMOVE_DEPRECATED_VERSIONS 1
-
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
@@ -51,9 +48,9 @@
namespace android {
-// This is not a real HWC version. It's used for in-development features that
-// haven't been committed to a specific real HWC version.
-#define HWC_DEVICE_API_VERSION_1_EXP HARDWARE_DEVICE_API_VERSION_2(1, 0xFF, HWC_HEADER_VERSION)
+#ifndef HWC_DEVICE_API_VERSION_1_3
+#define HWC_DEVICE_API_VERSION_1_3 HARDWARE_DEVICE_API_VERSION_2(1, 3, HWC_HEADER_VERSION)
+#endif
#define MIN_HWC_HEADER_VERSION HWC_HEADER_VERSION
@@ -157,8 +154,8 @@
// the number of displays we actually have depends on the
// hw composer version
- if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_EXP)) {
- // 1.?? adds support for virtual displays
+ if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_3)) {
+ // 1.3 adds support for virtual displays
mNumDisplays = MAX_DISPLAYS;
} else if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) {
// 1.1 adds support for multiple displays
@@ -583,7 +580,7 @@
}
mLists[i] = disp.list;
if (mLists[i]) {
- if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_EXP)) {
+ if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_3)) {
mLists[i]->outbuf = NULL;
mLists[i]->outbufAcquireFenceFd = -1;
} else if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) {
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
index 2838b23..a324e94 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
@@ -14,27 +14,89 @@
* limitations under the License.
*/
+// #define LOG_NDEBUG 0
#include "VirtualDisplaySurface.h"
-
-#include <cutils/log.h>
-#include <gui/IGraphicBufferProducer.h>
+#include "HWComposer.h"
// ---------------------------------------------------------------------------
namespace android {
// ---------------------------------------------------------------------------
+#define VDS_LOGE(msg, ...) ALOGE("[%s] "msg, \
+ mDisplayName.string(), ##__VA_ARGS__)
+#define VDS_LOGW_IF(cond, msg, ...) ALOGW_IF(cond, "[%s] "msg, \
+ mDisplayName.string(), ##__VA_ARGS__)
+#define VDS_LOGV(msg, ...) ALOGV("[%s] "msg, \
+ mDisplayName.string(), ##__VA_ARGS__)
+
+static const char* dbgCompositionTypeStr(DisplaySurface::CompositionType type) {
+ switch (type) {
+ case DisplaySurface::COMPOSITION_UNKNOWN: return "UNKNOWN";
+ case DisplaySurface::COMPOSITION_GLES: return "GLES";
+ case DisplaySurface::COMPOSITION_HWC: return "HWC";
+ case DisplaySurface::COMPOSITION_MIXED: return "MIXED";
+ default: return "<INVALID>";
+ }
+}
+
VirtualDisplaySurface::VirtualDisplaySurface(HWComposer& hwc, int32_t dispId,
const sp<IGraphicBufferProducer>& sink, const String8& name)
-: mSink(sink)
+: ConsumerBase(new BufferQueue(true)),
+ mHwc(hwc),
+ mDisplayId(dispId),
+ mDisplayName(name),
+ mProducerUsage(GRALLOC_USAGE_HW_COMPOSER),
+ mProducerSlotSource(0),
+ mDbgState(DBG_STATE_IDLE),
+ mDbgLastCompositionType(COMPOSITION_UNKNOWN)
{
- LOG_ALWAYS_FATAL_IF(dispId >= 0);
+ mSource[SOURCE_SINK] = sink;
+ mSource[SOURCE_SCRATCH] = mBufferQueue;
+
+ resetPerFrameState();
+
+ int sinkWidth, sinkHeight;
+ mSource[SOURCE_SINK]->query(NATIVE_WINDOW_WIDTH, &sinkWidth);
+ mSource[SOURCE_SINK]->query(NATIVE_WINDOW_HEIGHT, &sinkHeight);
+
+ ConsumerBase::mName = String8::format("VDS: %s", mDisplayName.string());
+ mBufferQueue->setConsumerName(ConsumerBase::mName);
+ mBufferQueue->setConsumerUsageBits(GRALLOC_USAGE_HW_COMPOSER);
+ mBufferQueue->setDefaultBufferSize(sinkWidth, sinkHeight);
+ mBufferQueue->setDefaultMaxBufferCount(2);
}
VirtualDisplaySurface::~VirtualDisplaySurface() {
}
sp<IGraphicBufferProducer> VirtualDisplaySurface::getIGraphicBufferProducer() const {
- return mSink;
+ if (mDisplayId >= 0) {
+ return static_cast<IGraphicBufferProducer*>(
+ const_cast<VirtualDisplaySurface*>(this));
+ } else {
+ // There won't be any interaction with HWC for this virtual display,
+ // so the GLES driver can pass buffers directly to the sink.
+ return mSource[SOURCE_SINK];
+ }
+}
+
+status_t VirtualDisplaySurface::prepareFrame(CompositionType compositionType) {
+ if (mDisplayId < 0)
+ return NO_ERROR;
+
+ VDS_LOGW_IF(mDbgState != DBG_STATE_IDLE,
+ "Unexpected prepareFrame() in %s state", dbgStateStr());
+ mDbgState = DBG_STATE_PREPARED;
+
+ mCompositionType = compositionType;
+
+ if (mCompositionType != mDbgLastCompositionType) {
+ VDS_LOGV("prepareFrame: composition type changed to %s",
+ dbgCompositionTypeStr(mCompositionType));
+ mDbgLastCompositionType = mCompositionType;
+ }
+
+ return NO_ERROR;
}
status_t VirtualDisplaySurface::compositionComplete() {
@@ -42,15 +104,319 @@
}
status_t VirtualDisplaySurface::advanceFrame() {
- return NO_ERROR;
+ if (mDisplayId < 0)
+ return NO_ERROR;
+
+ if (mCompositionType == COMPOSITION_HWC) {
+ VDS_LOGW_IF(mDbgState != DBG_STATE_PREPARED,
+ "Unexpected advanceFrame() in %s state on HWC frame",
+ dbgStateStr());
+ } else {
+ VDS_LOGW_IF(mDbgState != DBG_STATE_GLES_DONE,
+ "Unexpected advanceFrame() in %s state on GLES/MIXED frame",
+ dbgStateStr());
+ }
+ mDbgState = DBG_STATE_HWC;
+
+ status_t result;
+ sp<Fence> outFence;
+ if (mCompositionType != COMPOSITION_GLES) {
+ // Dequeue an output buffer from the sink
+ uint32_t transformHint, numPendingBuffers;
+ mQueueBufferOutput.deflate(&mSinkBufferWidth, &mSinkBufferHeight,
+ &transformHint, &numPendingBuffers);
+ int sslot;
+ result = dequeueBuffer(SOURCE_SINK, 0, &sslot, &outFence);
+ if (result < 0)
+ return result;
+ mOutputProducerSlot = mapSource2ProducerSlot(SOURCE_SINK, sslot);
+ }
+
+ if (mCompositionType == COMPOSITION_HWC) {
+ // We just dequeued the output buffer, use it for FB as well
+ mFbProducerSlot = mOutputProducerSlot;
+ mFbFence = outFence;
+ } else if (mCompositionType == COMPOSITION_GLES) {
+ mOutputProducerSlot = mFbProducerSlot;
+ outFence = mFbFence;
+ } else {
+ // mFbFence and mFbProducerSlot were set in queueBuffer,
+ // and mOutputProducerSlot and outFence were set above when dequeueing
+ // the sink buffer.
+ }
+
+ if (mFbProducerSlot < 0 || mOutputProducerSlot < 0) {
+ // Last chance bailout if something bad happened earlier. For example,
+ // in a GLES configuration, if the sink disappears then dequeueBuffer
+ // will fail, the GLES driver won't queue a buffer, but SurfaceFlinger
+ // will soldier on. So we end up here without a buffer. There should
+ // be lots of scary messages in the log just before this.
+ VDS_LOGE("advanceFrame: no buffer, bailing out");
+ return NO_MEMORY;
+ }
+
+ sp<GraphicBuffer> fbBuffer = mProducerBuffers[mFbProducerSlot];
+ sp<GraphicBuffer> outBuffer = mProducerBuffers[mOutputProducerSlot];
+ VDS_LOGV("advanceFrame: fb=%d(%p) out=%d(%p)",
+ mFbProducerSlot, fbBuffer.get(),
+ mOutputProducerSlot, outBuffer.get());
+
+ result = mHwc.fbPost(mDisplayId, mFbFence, fbBuffer);
+ if (result == NO_ERROR) {
+ result = mHwc.setOutputBuffer(mDisplayId, outFence, outBuffer);
+ }
+
+ return result;
}
void VirtualDisplaySurface::onFrameCommitted() {
+ if (mDisplayId < 0)
+ return;
+
+ VDS_LOGW_IF(mDbgState != DBG_STATE_HWC,
+ "Unexpected onFrameCommitted() in %s state", dbgStateStr());
+ mDbgState = DBG_STATE_IDLE;
+
+ sp<Fence> fbFence = mHwc.getAndResetReleaseFence(mDisplayId);
+ if (mCompositionType == COMPOSITION_MIXED && mFbProducerSlot >= 0) {
+ // release the scratch buffer back to the pool
+ Mutex::Autolock lock(mMutex);
+ int sslot = mapProducer2SourceSlot(SOURCE_SCRATCH, mFbProducerSlot);
+ VDS_LOGV("onFrameCommitted: release scratch sslot=%d", sslot);
+ addReleaseFenceLocked(sslot, mProducerBuffers[mFbProducerSlot], fbFence);
+ releaseBufferLocked(sslot, mProducerBuffers[mFbProducerSlot],
+ EGL_NO_DISPLAY, EGL_NO_SYNC_KHR);
+ }
+
+ if (mOutputProducerSlot >= 0) {
+ int sslot = mapProducer2SourceSlot(SOURCE_SINK, mOutputProducerSlot);
+ QueueBufferOutput qbo;
+ sp<Fence> outFence = mHwc.getLastRetireFence(mDisplayId);
+ VDS_LOGV("onFrameCommitted: queue sink sslot=%d", sslot);
+ status_t result = mSource[SOURCE_SINK]->queueBuffer(sslot,
+ QueueBufferInput(systemTime(),
+ Rect(mSinkBufferWidth, mSinkBufferHeight),
+ NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, outFence),
+ &qbo);
+ if (result == NO_ERROR) {
+ updateQueueBufferOutput(qbo);
+ }
+ }
+
+ resetPerFrameState();
}
void VirtualDisplaySurface::dump(String8& result) const {
}
+status_t VirtualDisplaySurface::requestBuffer(int pslot,
+ sp<GraphicBuffer>* outBuf) {
+ VDS_LOGW_IF(mDbgState != DBG_STATE_GLES,
+ "Unexpected requestBuffer pslot=%d in %s state",
+ pslot, dbgStateStr());
+
+ *outBuf = mProducerBuffers[pslot];
+ return NO_ERROR;
+}
+
+status_t VirtualDisplaySurface::setBufferCount(int bufferCount) {
+ return mSource[SOURCE_SINK]->setBufferCount(bufferCount);
+}
+
+status_t VirtualDisplaySurface::dequeueBuffer(Source source,
+ uint32_t format, int* sslot, sp<Fence>* fence) {
+ status_t result = mSource[source]->dequeueBuffer(sslot, fence,
+ mSinkBufferWidth, mSinkBufferHeight, format, mProducerUsage);
+ if (result < 0)
+ return result;
+ int pslot = mapSource2ProducerSlot(source, *sslot);
+ VDS_LOGV("dequeueBuffer(%s): sslot=%d pslot=%d result=%d",
+ dbgSourceStr(source), *sslot, pslot, result);
+ uint32_t sourceBit = static_cast<uint32_t>(source) << pslot;
+
+ if ((mProducerSlotSource & (1u << pslot)) != sourceBit) {
+ // This slot was previously dequeued from the other source; must
+ // re-request the buffer.
+ result |= BUFFER_NEEDS_REALLOCATION;
+ mProducerSlotSource &= ~(1u << pslot);
+ mProducerSlotSource |= sourceBit;
+ }
+
+ if (result & RELEASE_ALL_BUFFERS) {
+ for (uint32_t i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) {
+ if ((mProducerSlotSource & (1u << i)) == sourceBit)
+ mProducerBuffers[i].clear();
+ }
+ }
+ if (result & BUFFER_NEEDS_REALLOCATION) {
+ mSource[source]->requestBuffer(*sslot, &mProducerBuffers[pslot]);
+ VDS_LOGV("dequeueBuffer(%s): buffers[%d]=%p",
+ dbgSourceStr(source), pslot, mProducerBuffers[pslot].get());
+ }
+
+ return result;
+}
+
+status_t VirtualDisplaySurface::dequeueBuffer(int* pslot, sp<Fence>* fence,
+ uint32_t w, uint32_t h, uint32_t format, uint32_t usage) {
+ VDS_LOGW_IF(mDbgState != DBG_STATE_PREPARED,
+ "Unexpected dequeueBuffer() in %s state", dbgStateStr());
+ mDbgState = DBG_STATE_GLES;
+
+ VDS_LOGV("dequeueBuffer %dx%d fmt=%d usage=%#x", w, h, format, usage);
+
+ mProducerUsage = usage | GRALLOC_USAGE_HW_COMPOSER;
+ Source source = fbSourceForCompositionType(mCompositionType);
+ if (source == SOURCE_SINK) {
+ mSinkBufferWidth = w;
+ mSinkBufferHeight = h;
+ }
+
+ int sslot;
+ status_t result = dequeueBuffer(source, format, &sslot, fence);
+ if (result >= 0) {
+ *pslot = mapSource2ProducerSlot(source, sslot);
+ }
+ return result;
+}
+
+status_t VirtualDisplaySurface::queueBuffer(int pslot,
+ const QueueBufferInput& input, QueueBufferOutput* output) {
+ VDS_LOGW_IF(mDbgState != DBG_STATE_GLES,
+ "Unexpected queueBuffer(pslot=%d) in %s state", pslot,
+ dbgStateStr());
+ mDbgState = DBG_STATE_GLES_DONE;
+
+ VDS_LOGV("queueBuffer pslot=%d", pslot);
+
+ status_t result;
+ if (mCompositionType == COMPOSITION_MIXED) {
+ // Queue the buffer back into the scratch pool
+ QueueBufferOutput scratchQBO;
+ int sslot = mapProducer2SourceSlot(SOURCE_SCRATCH, pslot);
+ result = mBufferQueue->queueBuffer(sslot, input, &scratchQBO);
+ if (result != NO_ERROR)
+ return result;
+
+ // Now acquire the buffer from the scratch pool -- should be the same
+ // slot and fence as we just queued.
+ Mutex::Autolock lock(mMutex);
+ BufferQueue::BufferItem item;
+ result = acquireBufferLocked(&item, 0);
+ if (result != NO_ERROR)
+ return result;
+ VDS_LOGW_IF(item.mBuf != sslot,
+ "queueBuffer: acquired sslot %d from SCRATCH after queueing sslot %d",
+ item.mBuf, sslot);
+ mFbProducerSlot = mapSource2ProducerSlot(SOURCE_SCRATCH, item.mBuf);
+ mFbFence = mSlots[item.mBuf].mFence;
+
+ } else {
+ LOG_FATAL_IF(mCompositionType != COMPOSITION_GLES,
+ "Unexpected queueBuffer in state %s for compositionType %s",
+ dbgStateStr(), dbgCompositionTypeStr(mCompositionType));
+
+ // Extract the GLES release fence for HWC to acquire
+ int64_t timestamp;
+ Rect crop;
+ int scalingMode;
+ uint32_t transform;
+ input.deflate(×tamp, &crop, &scalingMode, &transform,
+ &mFbFence);
+
+ mFbProducerSlot = pslot;
+ }
+
+ *output = mQueueBufferOutput;
+ return NO_ERROR;
+}
+
+void VirtualDisplaySurface::cancelBuffer(int pslot, const sp<Fence>& fence) {
+ VDS_LOGW_IF(mDbgState != DBG_STATE_GLES,
+ "Unexpected cancelBuffer(pslot=%d) in %s state", pslot,
+ dbgStateStr());
+ VDS_LOGV("cancelBuffer pslot=%d", pslot);
+ Source source = fbSourceForCompositionType(mCompositionType);
+ return mSource[source]->cancelBuffer(
+ mapProducer2SourceSlot(source, pslot), fence);
+}
+
+int VirtualDisplaySurface::query(int what, int* value) {
+ return mSource[SOURCE_SINK]->query(what, value);
+}
+
+status_t VirtualDisplaySurface::setSynchronousMode(bool enabled) {
+ return mSource[SOURCE_SINK]->setSynchronousMode(enabled);
+}
+
+status_t VirtualDisplaySurface::connect(int api, QueueBufferOutput* output) {
+ QueueBufferOutput qbo;
+ status_t result = mSource[SOURCE_SINK]->connect(api, &qbo);
+ if (result == NO_ERROR) {
+ updateQueueBufferOutput(qbo);
+ *output = mQueueBufferOutput;
+ }
+ return result;
+}
+
+status_t VirtualDisplaySurface::disconnect(int api) {
+ return mSource[SOURCE_SINK]->disconnect(api);
+}
+
+void VirtualDisplaySurface::updateQueueBufferOutput(
+ const QueueBufferOutput& qbo) {
+ uint32_t w, h, transformHint, numPendingBuffers;
+ qbo.deflate(&w, &h, &transformHint, &numPendingBuffers);
+ mQueueBufferOutput.inflate(w, h, 0, numPendingBuffers);
+}
+
+void VirtualDisplaySurface::resetPerFrameState() {
+ mCompositionType = COMPOSITION_UNKNOWN;
+ mSinkBufferWidth = 0;
+ mSinkBufferHeight = 0;
+ mFbFence = Fence::NO_FENCE;
+ mFbProducerSlot = -1;
+ mOutputProducerSlot = -1;
+}
+
+// This slot mapping function is its own inverse, so two copies are unnecessary.
+// Both are kept to make the intent clear where the function is called, and for
+// the (unlikely) chance that we switch to a different mapping function.
+int VirtualDisplaySurface::mapSource2ProducerSlot(Source source, int sslot) {
+ if (source == SOURCE_SCRATCH) {
+ return BufferQueue::NUM_BUFFER_SLOTS - sslot - 1;
+ } else {
+ return sslot;
+ }
+}
+int VirtualDisplaySurface::mapProducer2SourceSlot(Source source, int pslot) {
+ return mapSource2ProducerSlot(source, pslot);
+}
+
+VirtualDisplaySurface::Source
+VirtualDisplaySurface::fbSourceForCompositionType(CompositionType type) {
+ return type == COMPOSITION_MIXED ? SOURCE_SCRATCH : SOURCE_SINK;
+}
+
+const char* VirtualDisplaySurface::dbgStateStr() const {
+ switch (mDbgState) {
+ case DBG_STATE_IDLE: return "IDLE";
+ case DBG_STATE_PREPARED: return "PREPARED";
+ case DBG_STATE_GLES: return "GLES";
+ case DBG_STATE_GLES_DONE: return "GLES_DONE";
+ case DBG_STATE_HWC: return "HWC";
+ default: return "INVALID";
+ }
+}
+
+const char* VirtualDisplaySurface::dbgSourceStr(Source s) {
+ switch (s) {
+ case SOURCE_SINK: return "SINK";
+ case SOURCE_SCRATCH: return "SCRATCH";
+ default: return "INVALID";
+ }
+}
+
// ---------------------------------------------------------------------------
} // namespace android
// ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
index f321795..2b4cf8f 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
@@ -17,6 +17,9 @@
#ifndef ANDROID_SF_VIRTUAL_DISPLAY_SURFACE_H
#define ANDROID_SF_VIRTUAL_DISPLAY_SURFACE_H
+#include <gui/ConsumerBase.h>
+#include <gui/IGraphicBufferProducer.h>
+
#include "DisplaySurface.h"
// ---------------------------------------------------------------------------
@@ -25,26 +28,187 @@
class HWComposer;
-/* This DisplaySurface implementation is a stub used for developing HWC
- * virtual display support. It is currently just a passthrough.
+/* This DisplaySurface implementation supports virtual displays, where GLES
+ * and/or HWC compose into a buffer that is then passed to an arbitrary
+ * consumer (the sink) running in another process.
+ *
+ * The simplest case is when the virtual display will never use the h/w
+ * composer -- either the h/w composer doesn't support writing to buffers, or
+ * there are more virtual displays than it supports simultaneously. In this
+ * case, the GLES driver works directly with the output buffer queue, and
+ * calls to the VirtualDisplay from SurfaceFlinger and DisplayHardware do
+ * nothing.
+ *
+ * If h/w composer might be used, then each frame will fall into one of three
+ * configurations: GLES-only, HWC-only, and MIXED composition. In all of these,
+ * we must provide a FB target buffer and output buffer for the HWC set() call.
+ *
+ * In GLES-only composition, the GLES driver is given a buffer from the sink to
+ * render into. When the GLES driver queues the buffer to the
+ * VirtualDisplaySurface, the VirtualDisplaySurface holds onto it instead of
+ * immediately queueing it to the sink. The buffer is used as both the FB
+ * target and output buffer for HWC, though on these frames the HWC doesn't
+ * do any work for this display and doesn't write to the output buffer. After
+ * composition is complete, the buffer is queued to the sink.
+ *
+ * In HWC-only composition, the VirtualDisplaySurface dequeues a buffer from
+ * the sink and passes it to HWC as both the FB target buffer and output
+ * buffer. The HWC doesn't need to read from the FB target buffer, but does
+ * write to the output buffer. After composition is complete, the buffer is
+ * queued to the sink.
+ *
+ * On MIXED frames, things become more complicated, since some h/w composer
+ * implementations can't read from and write to the same buffer. This class has
+ * an internal BufferQueue that it uses as a scratch buffer pool. The GLES
+ * driver is given a scratch buffer to render into. When it finishes rendering,
+ * the buffer is queued and then immediately acquired by the
+ * VirtualDisplaySurface. The scratch buffer is then used as the FB target
+ * buffer for HWC, and a separate buffer is dequeued from the sink and used as
+ * the HWC output buffer. When HWC composition is complete, the scratch buffer
+ * is released and the output buffer is queued to the sink.
*/
-class VirtualDisplaySurface : public DisplaySurface {
+class VirtualDisplaySurface : public DisplaySurface,
+ private BnGraphicBufferProducer,
+ private ConsumerBase {
public:
VirtualDisplaySurface(HWComposer& hwc, int32_t dispId,
const sp<IGraphicBufferProducer>& sink,
const String8& name);
+ //
+ // DisplaySurface interface
+ //
virtual sp<IGraphicBufferProducer> getIGraphicBufferProducer() const;
-
+ virtual status_t prepareFrame(CompositionType compositionType);
virtual status_t compositionComplete();
virtual status_t advanceFrame();
virtual void onFrameCommitted();
virtual void dump(String8& result) const;
private:
+ enum Source {SOURCE_SINK = 0, SOURCE_SCRATCH = 1};
+
virtual ~VirtualDisplaySurface();
- sp<IGraphicBufferProducer> mSink;
+ //
+ // IGraphicBufferProducer interface, used by the GLES driver.
+ //
+ virtual status_t requestBuffer(int pslot, sp<GraphicBuffer>* outBuf);
+ virtual status_t setBufferCount(int bufferCount);
+ virtual status_t dequeueBuffer(int* pslot, sp<Fence>* fence,
+ uint32_t w, uint32_t h, uint32_t format, uint32_t usage);
+ virtual status_t queueBuffer(int pslot,
+ const QueueBufferInput& input, QueueBufferOutput* output);
+ virtual void cancelBuffer(int pslot, const sp<Fence>& fence);
+ virtual int query(int what, int* value);
+ virtual status_t setSynchronousMode(bool enabled);
+ virtual status_t connect(int api, QueueBufferOutput* output);
+ virtual status_t disconnect(int api);
+
+ //
+ // Utility methods
+ //
+ static Source fbSourceForCompositionType(CompositionType type);
+ status_t dequeueBuffer(Source source, uint32_t format,
+ int* sslot, sp<Fence>* fence);
+ void updateQueueBufferOutput(const QueueBufferOutput& qbo);
+ void resetPerFrameState();
+
+ // Both the sink and scratch buffer pools have their own set of slots
+ // ("source slots", or "sslot"). We have to merge these into the single
+ // set of slots used by the GLES producer ("producer slots" or "pslot") and
+ // internally in the VirtualDisplaySurface. To minimize the number of times
+ // a producer slot switches which source it comes from, we map source slot
+ // numbers to producer slot numbers differently for each source.
+ static int mapSource2ProducerSlot(Source source, int sslot);
+ static int mapProducer2SourceSlot(Source source, int pslot);
+
+ //
+ // Immutable after construction
+ //
+ HWComposer& mHwc;
+ const int32_t mDisplayId;
+ const String8 mDisplayName;
+ sp<IGraphicBufferProducer> mSource[2]; // indexed by SOURCE_*
+
+ //
+ // Inter-frame state
+ //
+
+ // To avoid buffer reallocations, we track the buffer usage requested by
+ // the GLES driver in dequeueBuffer so we can use the same flags on
+ // HWC-only frames.
+ uint32_t mProducerUsage;
+
+ // Since we present a single producer interface to the GLES driver, but
+ // are internally muxing between the sink and scratch producers, we have
+ // to keep track of which source last returned each producer slot from
+ // dequeueBuffer. Each bit in mLastSlotSource corresponds to a producer
+ // slot. Both mProducerSlotSource and mProducerBuffers are indexed by a
+ // "producer slot"; see the mapSlot*() functions.
+ uint32_t mProducerSlotSource;
+ sp<GraphicBuffer> mProducerBuffers[BufferQueue::NUM_BUFFER_SLOTS];
+
+ // The QueueBufferOutput with the latest info from the sink, and with the
+ // transform hint cleared. Since we defer queueBuffer from the GLES driver
+ // to the sink, we have to return the previous version.
+ QueueBufferOutput mQueueBufferOutput;
+
+ //
+ // Intra-frame state
+ //
+
+ // Composition type and GLES buffer source for the current frame.
+ // Valid after prepareFrame(), cleared in onFrameCommitted.
+ CompositionType mCompositionType;
+
+ // Details of the current sink buffer. These become valid when a buffer is
+ // dequeued from the sink, and are used when queueing the buffer.
+ uint32_t mSinkBufferWidth, mSinkBufferHeight;
+
+ // mFbFence is the fence HWC should wait for before reading the framebuffer
+ // target buffer.
+ sp<Fence> mFbFence;
+
+ // Producer slot numbers for the buffers to use for HWC framebuffer target
+ // and output.
+ int mFbProducerSlot;
+ int mOutputProducerSlot;
+
+ // Debug only -- track the sequence of events in each frame so we can make
+ // sure they happen in the order we expect. This class implicitly models
+ // a state machine; this enum/variable makes it explicit.
+ //
+ // +-----------+-------------------+-------------+
+ // | State | Event || Next State |
+ // +-----------+-------------------+-------------+
+ // | IDLE | prepareFrame || PREPARED |
+ // | PREPARED | dequeueBuffer [1] || GLES |
+ // | PREPARED | advanceFrame [2] || HWC |
+ // | GLES | queueBuffer || GLES_DONE |
+ // | GLES_DONE | advanceFrame || HWC |
+ // | HWC | onFrameCommitted || IDLE |
+ // +-----------+-------------------++------------+
+ // [1] COMPOSITION_GLES and COMPOSITION_MIXED frames.
+ // [2] COMPOSITION_HWC frames.
+ //
+ enum DbgState {
+ // no buffer dequeued, don't know anything about the next frame
+ DBG_STATE_IDLE,
+ // no buffer dequeued, but we know the buffer source for the frame
+ DBG_STATE_PREPARED,
+ // GLES driver has a buffer dequeued
+ DBG_STATE_GLES,
+ // GLES driver has queued the buffer, we haven't sent it to HWC yet
+ DBG_STATE_GLES_DONE,
+ // HWC has the buffer for this frame
+ DBG_STATE_HWC,
+ };
+ DbgState mDbgState;
+ CompositionType mDbgLastCompositionType;
+
+ const char* dbgStateStr() const;
+ static const char* dbgSourceStr(Source s);
};
// ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/EventThread.h b/services/surfaceflinger/EventThread.h
index f6bd676..35ac0c8 100644
--- a/services/surfaceflinger/EventThread.h
+++ b/services/surfaceflinger/EventThread.h
@@ -104,7 +104,7 @@
// protected by mLock
SortedVector< wp<Connection> > mDisplayEventConnections;
Vector< DisplayEventReceiver::Event > mPendingEvents;
- DisplayEventReceiver::Event mVSyncEvent[HWC_DISPLAY_TYPES_SUPPORTED];
+ DisplayEventReceiver::Event mVSyncEvent[HWC_NUM_DISPLAY_TYPES];
bool mUseSoftwareVSync;
// for debugging
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 34003b8..2962115 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -110,8 +110,8 @@
{
// Creates a custom BufferQueue for SurfaceFlingerConsumer to use
sp<BufferQueue> bq = new SurfaceTextureLayer(mFlinger);
- mSurfaceFlingerConsumer = new SurfaceFlingerConsumer(mTextureName, true,
- GL_TEXTURE_EXTERNAL_OES, false, bq);
+ mSurfaceFlingerConsumer = new SurfaceFlingerConsumer(bq, mTextureName,
+ GL_TEXTURE_EXTERNAL_OES, false);
mSurfaceFlingerConsumer->setConsumerUsageBits(getEffectiveUsage(0));
mSurfaceFlingerConsumer->setFrameAvailableListener(this);
@@ -917,11 +917,6 @@
const bool oldOpacity = isOpaque();
sp<GraphicBuffer> oldActiveBuffer = mActiveBuffer;
- // signal another event if we have more frames pending
- if (android_atomic_dec(&mQueuedFrames) > 1) {
- mFlinger->signalLayerUpdate();
- }
-
struct Reject : public SurfaceFlingerConsumer::BufferRejecter {
Layer::State& front;
Layer::State& current;
@@ -1027,7 +1022,21 @@
Reject r(mDrawingState, getCurrentState(), recomputeVisibleRegions);
- if (mSurfaceFlingerConsumer->updateTexImage(&r) != NO_ERROR) {
+ status_t updateResult = mSurfaceFlingerConsumer->updateTexImage(&r);
+ if (updateResult == BufferQueue::PRESENT_LATER) {
+ // Producer doesn't want buffer to be displayed yet. Signal a
+ // layer update so we check again at the next opportunity.
+ mFlinger->signalLayerUpdate();
+ return outDirtyRegion;
+ }
+
+ // Decrement the queued-frames count. Signal another event if we
+ // have more frames pending.
+ if (android_atomic_dec(&mQueuedFrames) > 1) {
+ mFlinger->signalLayerUpdate();
+ }
+
+ if (updateResult != NO_ERROR) {
// something happened!
recomputeVisibleRegions = true;
return outDirtyRegion;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index ecf9fa7..9adabe8 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -895,6 +895,11 @@
status_t err = hwc.prepare();
ALOGE_IF(err, "HWComposer::prepare failed (%s)", strerror(-err));
+
+ for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
+ sp<const DisplayDevice> hw(mDisplays[dpy]);
+ hw->prepareFrame(hwc);
+ }
}
}
diff --git a/services/surfaceflinger/SurfaceFlingerConsumer.cpp b/services/surfaceflinger/SurfaceFlingerConsumer.cpp
index 7ac5c60..b181b60 100644
--- a/services/surfaceflinger/SurfaceFlingerConsumer.cpp
+++ b/services/surfaceflinger/SurfaceFlingerConsumer.cpp
@@ -50,12 +50,14 @@
// Acquire the next buffer.
// In asynchronous mode the list is guaranteed to be one buffer
// deep, while in synchronous mode we use the oldest buffer.
- err = acquireBufferLocked(&item);
+ err = acquireBufferLocked(&item, computeExpectedPresent());
if (err != NO_ERROR) {
if (err == BufferQueue::NO_BUFFER_AVAILABLE) {
// This variant of updateTexImage does not guarantee that the
// texture is bound, so no need to call glBindTexture.
err = NO_ERROR;
+ } else if (err == BufferQueue::PRESENT_LATER) {
+ // return the error, without logging
} else {
ALOGE("updateTexImage: acquire failed: %s (%d)",
strerror(-err), err);
@@ -99,6 +101,48 @@
return bindTextureImageLocked();
}
+// We need to determine the time when a buffer acquired now will be
+// displayed. This can be calculated:
+// time when previous buffer's actual-present fence was signaled
+// + current display refresh rate * HWC latency
+// + a little extra padding
+//
+// Buffer producers are expected to set their desired presentation time
+// based on choreographer time stamps, which (coming from vsync events)
+// will be slightly later then the actual-present timing. If we get a
+// desired-present time that is unintentionally a hair after the next
+// vsync, we'll hold the frame when we really want to display it. We
+// want to use an expected-presentation time that is slightly late to
+// avoid this sort of edge case.
+nsecs_t SurfaceFlingerConsumer::computeExpectedPresent()
+{
+ // Don't yet have an easy way to get actual buffer flip time for
+ // the specific display, so use the current time. This is typically
+ // 1.3ms past the vsync event time.
+ const nsecs_t prevVsync = systemTime(CLOCK_MONOTONIC);
+
+ // Given a SurfaceFlinger reference, and information about what display
+ // we're destined for, we could query the HWC for the refresh rate. This
+ // could change over time, e.g. we could switch to 24fps for a movie.
+ // For now, assume 60fps.
+ //const nsecs_t vsyncPeriod =
+ // getHwComposer().getRefreshPeriod(HWC_DISPLAY_PRIMARY);
+ const nsecs_t vsyncPeriod = 16700000;
+
+ // The HWC doesn't currently have a way to report additional latency.
+ // Assume that whatever we submit now will appear on the next flip,
+ // i.e. 1 frame of latency w.r.t. the previous flip.
+ const uint32_t hwcLatency = 1;
+
+ // A little extra padding to compensate for slack between actual vsync
+ // time and vsync event receipt. Currently not needed since we're
+ // using "now" instead of a vsync time.
+ const nsecs_t extraPadding = 0;
+
+ // Total it up.
+ return prevVsync + hwcLatency * vsyncPeriod + extraPadding;
+}
+
// ---------------------------------------------------------------------------
}; // namespace android
diff --git a/services/surfaceflinger/SurfaceFlingerConsumer.h b/services/surfaceflinger/SurfaceFlingerConsumer.h
index 22eec81..5de6d12 100644
--- a/services/surfaceflinger/SurfaceFlingerConsumer.h
+++ b/services/surfaceflinger/SurfaceFlingerConsumer.h
@@ -27,11 +27,10 @@
*/
class SurfaceFlingerConsumer : public GLConsumer {
public:
- SurfaceFlingerConsumer(GLuint tex, bool allowSynchronousMode = true,
- GLenum texTarget = GL_TEXTURE_EXTERNAL_OES, bool useFenceSync = true,
- const sp<BufferQueue> &bufferQueue = 0)
- : GLConsumer(tex, allowSynchronousMode, texTarget, useFenceSync,
- bufferQueue)
+ SurfaceFlingerConsumer(const sp<BufferQueue>& bq, GLuint tex,
+ GLenum texTarget = GL_TEXTURE_EXTERNAL_OES,
+ bool useFenceSync = true)
+ : GLConsumer(bq, tex, texTarget, useFenceSync)
{}
class BufferRejecter {
@@ -51,6 +50,9 @@
// See GLConsumer::bindTextureImageLocked().
status_t bindTextureImage();
+
+private:
+ nsecs_t computeExpectedPresent();
};
// ----------------------------------------------------------------------------