Merge "Add C++ library for ConnectivityManager"
diff --git a/cmds/dumpstate/dumpstate.c b/cmds/dumpstate/dumpstate.c
index 8e6998f..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();
diff --git a/cmds/flatland/GLHelper.cpp b/cmds/flatland/GLHelper.cpp
index 4f7697f..3928039 100644
--- a/cmds/flatland/GLHelper.cpp
+++ b/cmds/flatland/GLHelper.cpp
@@ -198,9 +198,9 @@
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<BufferQueue> bq = new BufferQueue(mGraphicBufferAlloc);
+ 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/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/cmds/sensorservice/Android.mk b/cmds/sensorservice/Android.mk
deleted file mode 100644
index 0811be5..0000000
--- a/cmds/sensorservice/Android.mk
+++ /dev/null
@@ -1,19 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
- main_sensorservice.cpp
-
-LOCAL_SHARED_LIBRARIES := \
- libsensorservice \
- libbinder \
- libutils
-
-LOCAL_C_INCLUDES := \
- $(LOCAL_PATH)/../../services/sensorservice
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_MODULE:= sensorservice
-
-include $(BUILD_EXECUTABLE)
diff --git a/cmds/surfaceflinger/Android.mk b/cmds/surfaceflinger/Android.mk
deleted file mode 100644
index 1df32bb..0000000
--- a/cmds/surfaceflinger/Android.mk
+++ /dev/null
@@ -1,17 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
- main_surfaceflinger.cpp
-
-LOCAL_SHARED_LIBRARIES := \
- libsurfaceflinger \
- libbinder \
- libutils
-
-LOCAL_C_INCLUDES := \
- $(LOCAL_PATH)/../../services/surfaceflinger
-
-LOCAL_MODULE:= surfaceflinger
-
-include $(BUILD_EXECUTABLE)
diff --git a/data/etc/android.hardware.nfc.hce.xml b/data/etc/android.hardware.nfc.hce.xml
new file mode 100644
index 0000000..10b96b1
--- /dev/null
+++ b/data/etc/android.hardware.nfc.hce.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<!-- This feature indicates that the device supports host-based
+ NFC card emulation -->
+<permissions>
+ <feature name="android.hardware.nfc.hce" />
+</permissions>
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 5bf9acb..9370e81 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,9 +51,11 @@
// 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,
+ // controlledByApp tells whether this consumer is controlled by the
+ // application.
+ BufferItemConsumer(const sp<BufferQueue>& bq, uint32_t consumerUsage,
int bufferCount = BufferQueue::MIN_UNDEQUEUED_BUFFERS,
- bool synchronousMode = false);
+ bool controlledByApp = false);
virtual ~BufferItemConsumer();
diff --git a/include/gui/BufferQueue.h b/include/gui/BufferQueue.h
index 0143be3..628678f 100644
--- a/include/gui/BufferQueue.h
+++ b/include/gui/BufferQueue.h
@@ -97,11 +97,9 @@
// BufferQueue manages a pool of gralloc memory slots to be used by
- // producers and consumers. allowSynchronousMode specifies whether or not
- // synchronous mode can be enabled by the producer. allocator is used to
- // allocate all the needed gralloc buffers.
- BufferQueue(bool allowSynchronousMode = true,
- const sp<IGraphicBufferAlloc>& allocator = NULL);
+ // producers and consumers. allocator is used to allocate all the
+ // needed gralloc buffers.
+ BufferQueue(const sp<IGraphicBufferAlloc>& allocator = NULL);
virtual ~BufferQueue();
// Query native window attributes. The "what" values are enumerated in
@@ -169,7 +167,7 @@
//
// In both cases, the producer will need to call requestBuffer to get a
// GraphicBuffer handle for the returned slot.
- virtual status_t dequeueBuffer(int *buf, sp<Fence>* fence,
+ virtual status_t dequeueBuffer(int *buf, sp<Fence>* fence, bool async,
uint32_t width, uint32_t height, uint32_t format, uint32_t usage);
// queueBuffer returns a filled buffer to the BufferQueue.
@@ -197,15 +195,6 @@
// will usually be the one obtained from dequeueBuffer.
virtual void cancelBuffer(int buf, const sp<Fence>& fence);
- // setSynchronousMode sets whether dequeueBuffer is synchronous or
- // asynchronous. In synchronous mode, dequeueBuffer blocks until
- // a buffer is available, the currently bound buffer can be dequeued and
- // queued buffers will be acquired in order. In asynchronous mode,
- // a queued buffer may be replaced by a subsequently queued buffer.
- //
- // The default mode is asynchronous.
- virtual status_t setSynchronousMode(bool enabled);
-
// connect attempts to connect a producer API to the BufferQueue. This
// must be called before any other IGraphicBufferProducer methods are
// called except for getAllocator. A consumer must already be connected.
@@ -215,7 +204,7 @@
// it's still connected to a producer).
//
// APIs are enumerated in window.h (e.g. NATIVE_WINDOW_API_CPU).
- virtual status_t connect(int api, QueueBufferOutput* output);
+ virtual status_t connect(int api, bool producerControlledByApp, QueueBufferOutput* output);
// disconnect attempts to disconnect a producer API from the BufferQueue.
// Calling this method will cause any subsequent calls to other
@@ -234,13 +223,13 @@
// public facing structure for BufferSlot
struct BufferItem {
- BufferItem()
- :
+ BufferItem() :
mTransform(0),
mScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE),
mTimestamp(0),
mFrameNumber(0),
mBuf(INVALID_BUFFER_SLOT),
+ mIsDroppable(false),
mAcquireCalled(false) {
mCrop.makeInvalid();
}
@@ -271,6 +260,13 @@
// mFence is a fence that will signal when the buffer is idle.
sp<Fence> mFence;
+ // mIsDroppable whether this buffer was queued with the
+ // property that it can be replaced by a new buffer for the purpose of
+ // making sure dequeueBuffer() won't block.
+ // i.e.: was the BufferQueue in "mDequeueBufferCannotBlock" when this buffer
+ // was queued.
+ bool mIsDroppable;
+
// Indicates whether this buffer has been seen by a consumer yet
bool mAcquireCalled;
};
@@ -312,9 +308,11 @@
// consumer may be connected, and when that consumer disconnects the
// BufferQueue is placed into the "abandoned" state, causing most
// interactions with the BufferQueue by the producer to fail.
+ // controlledByApp indicates whether the consumer is controlled by
+ // the application.
//
// consumer may not be NULL.
- status_t consumerConnect(const sp<ConsumerListener>& consumer);
+ status_t consumerConnect(const sp<ConsumerListener>& consumer, bool controlledByApp);
// consumerDisconnect disconnects a consumer from the BufferQueue. All
// buffers will be freed and the BufferQueue is placed in the "abandoned"
@@ -347,10 +345,6 @@
// fail if a producer is connected to the BufferQueue.
status_t setMaxAcquiredBufferCount(int maxAcquiredBuffers);
- // isSynchronousMode returns whether the BufferQueue is currently in
- // synchronous mode.
- bool isSynchronousMode() const;
-
// setConsumerName sets the name used in logging
void setConsumerName(const String8& name);
@@ -379,43 +373,35 @@
// all slots.
void freeAllBuffersLocked();
- // drainQueueLocked waits for the buffer queue to empty if we're in
- // synchronous mode, or returns immediately otherwise. It returns NO_INIT
- // if the BufferQueue is abandoned (consumer disconnected) or disconnected
- // (producer disconnected) during the call.
- status_t drainQueueLocked();
-
- // drainQueueAndFreeBuffersLocked drains the buffer queue if we're in
- // synchronous mode and free all buffers. In asynchronous mode, all buffers
- // are freed except the currently queued buffer (if it exists).
- status_t drainQueueAndFreeBuffersLocked();
-
// setDefaultMaxBufferCountLocked sets the maximum number of buffer slots
// that will be used if the producer does not override the buffer slot
// count. The count must be between 2 and NUM_BUFFER_SLOTS, inclusive.
// The initial default is 2.
status_t setDefaultMaxBufferCountLocked(int count);
+ // getMinUndequeuedBufferCount returns the minimum number of buffers
+ // that must remain in a state other than DEQUEUED.
+ // The async parameter tells whether we're in asynchronous mode.
+ int getMinUndequeuedBufferCount(bool async) const;
+
// getMinBufferCountLocked returns the minimum number of buffers allowed
// given the current BufferQueue state.
- int getMinMaxBufferCountLocked() const;
-
- // getMinUndequeuedBufferCountLocked returns the minimum number of buffers
- // that must remain in a state other than DEQUEUED.
- int getMinUndequeuedBufferCountLocked() const;
+ // The async parameter tells whether we're in asynchronous mode.
+ int getMinMaxBufferCountLocked(bool async) const;
// getMaxBufferCountLocked returns the maximum number of buffers that can
// be allocated at once. This value depends upon the following member
// variables:
//
- // mSynchronousMode
+ // mDequeueBufferCannotBlock
// mMaxAcquiredBufferCount
// mDefaultMaxBufferCount
// mOverrideMaxBufferCount
+ // async parameter
//
// Any time one of these member variables is changed while a producer is
// connected, mDequeueCondition must be broadcast.
- int getMaxBufferCountLocked() const;
+ int getMaxBufferCountLocked(bool async) const;
// stillTracking returns true iff the buffer item is still being tracked
// in one of the slots.
@@ -568,12 +554,14 @@
// to NULL and is written by consumerConnect and consumerDisconnect.
sp<ConsumerListener> mConsumerListener;
- // mSynchronousMode whether we're in synchronous mode or not
- bool mSynchronousMode;
+ // mConsumerControlledByApp whether the connected consumer is controlled by the
+ // application.
+ bool mConsumerControlledByApp;
- // mAllowSynchronousMode whether we allow synchronous mode or not. Set
- // when the BufferQueue is created (by the consumer).
- const bool mAllowSynchronousMode;
+ // mDequeueBufferCannotBlock whether dequeueBuffer() isn't allowed to block.
+ // this flag is set durring connect() when both consumer and producer are controlled
+ // by the application.
+ bool mDequeueBufferCannotBlock;
// mConnectedApi indicates the producer API that is currently connected
// to this BufferQueue. It defaults to NO_CONNECTED_API (= 0), and gets
diff --git a/include/gui/ConsumerBase.h b/include/gui/ConsumerBase.h
index 42b84cc..7b58bc5 100644
--- a/include/gui/ConsumerBase.h
+++ b/include/gui/ConsumerBase.h
@@ -87,7 +87,9 @@
// ConsumerBase constructs a new ConsumerBase object to consume image
// buffers from the given BufferQueue.
- ConsumerBase(const sp<BufferQueue> &bufferQueue);
+ // The controlledByApp flag indicates that this consumer is under the application's
+ // control.
+ ConsumerBase(const sp<BufferQueue> &bufferQueue, bool controlledByApp = false);
// onLastStrongRef gets called by RefBase just before the dtor of the most
// derived class. It is used to clean up the buffers so that ConsumerBase
diff --git a/include/gui/CpuConsumer.h b/include/gui/CpuConsumer.h
index 3c178ef..2890350 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 controlledByApp = false);
virtual ~CpuConsumer();
diff --git a/include/gui/DummyConsumer.h b/include/gui/DummyConsumer.h
deleted file mode 100644
index 08e8ec8..0000000
--- a/include/gui/DummyConsumer.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_GUI_DUMMYCONSUMER_H
-#define ANDROID_GUI_DUMMYCONSUMER_H
-
-#include <gui/BufferQueue.h>
-
-namespace android {
-// ----------------------------------------------------------------------------
-
-
-// The DummyConsumer does not keep a reference to BufferQueue
-// unlike GLConsumer. This prevents a circular reference from
-// forming without having to use a ProxyConsumerListener
-class DummyConsumer : public BufferQueue::ConsumerListener {
-public:
- DummyConsumer();
- virtual ~DummyConsumer();
-protected:
-
- // Implementation of the BufferQueue::ConsumerListener interface. These
- // calls are used to notify the GLConsumer of asynchronous events in the
- // BufferQueue.
- virtual void onFrameAvailable();
- virtual void onBuffersReleased();
-
-};
-
-// ----------------------------------------------------------------------------
-}; // namespace android
-
-#endif // ANDROID_GUI_DUMMYCONSUMER_H
diff --git a/include/gui/GLConsumer.h b/include/gui/GLConsumer.h
index fbc8840..1df5b42 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, bool isControlledByApp = false);
// updateTexImage acquires the most recently queued buffer, and sets the
// image contents of the target texture to it.
@@ -177,10 +177,6 @@
// current texture buffer.
status_t doGLFenceWait() const;
- // isSynchronousMode returns whether the GLConsumer is currently in
- // synchronous mode.
- bool isSynchronousMode() const;
-
// set the name of the GLConsumer that will be used to identify it in
// log messages.
void setName(const String8& name);
@@ -190,7 +186,6 @@
status_t setDefaultBufferFormat(uint32_t defaultFormat);
status_t setConsumerUsageBits(uint32_t usage);
status_t setTransformHint(uint32_t hint);
- virtual status_t setSynchronousMode(bool enabled);
// getBufferQueue returns the BufferQueue object to which this
// GLConsumer is connected.
diff --git a/include/gui/IGraphicBufferProducer.h b/include/gui/IGraphicBufferProducer.h
index 29c7ff3..9677962 100644
--- a/include/gui/IGraphicBufferProducer.h
+++ b/include/gui/IGraphicBufferProducer.h
@@ -84,7 +84,10 @@
// the buffer. The contents of the buffer must not be overwritten until the
// fence signals. If the fence is NULL, the buffer may be written
// immediately.
- virtual status_t dequeueBuffer(int *slot, sp<Fence>* fence,
+ //
+ // The async parameter sets whether we're in asynchrnous mode for this
+ // deququeBuffer() call.
+ virtual status_t dequeueBuffer(int *slot, sp<Fence>* fence, bool async,
uint32_t w, uint32_t h, uint32_t format, uint32_t usage) = 0;
// queueBuffer indicates that the client has finished filling in the
@@ -96,6 +99,8 @@
// must be monotonically increasing. Its other properties (zero point, etc)
// are client-dependent, and should be documented by the client.
//
+ // The async parameter sets whether we're queuing a buffer in asynchronous mode.
+ //
// outWidth, outHeight and outTransform are filled with the default width
// and height of the window and current transform applied to buffers,
// respectively.
@@ -103,17 +108,18 @@
struct QueueBufferInput : public Flattenable {
inline QueueBufferInput(const Parcel& parcel);
inline QueueBufferInput(int64_t timestamp,
- const Rect& crop, int scalingMode, uint32_t transform,
- sp<Fence> fence)
+ const Rect& crop, int scalingMode, uint32_t transform, bool async,
+ const sp<Fence>& fence)
: timestamp(timestamp), crop(crop), scalingMode(scalingMode),
- transform(transform), fence(fence) { }
+ transform(transform), async(async), fence(fence) { }
inline void deflate(int64_t* outTimestamp, Rect* outCrop,
- int* outScalingMode, uint32_t* outTransform,
+ int* outScalingMode, uint32_t* outTransform, bool* outAsync,
sp<Fence>* outFence) const {
*outTimestamp = timestamp;
*outCrop = crop;
*outScalingMode = scalingMode;
*outTransform = transform;
+ *outAsync = bool(async);
*outFence = fence;
}
@@ -130,6 +136,7 @@
Rect crop;
int scalingMode;
uint32_t transform;
+ int async;
sp<Fence> fence;
};
@@ -171,13 +178,6 @@
// 'what' tokens allowed are that of android_natives.h
virtual int query(int what, int* value) = 0;
- // setSynchronousMode set whether dequeueBuffer is synchronous or
- // asynchronous. In synchronous mode, dequeueBuffer blocks until
- // a buffer is available, the currently bound buffer can be dequeued and
- // queued buffers will be retired in order.
- // The default mode is asynchronous.
- virtual status_t setSynchronousMode(bool enabled) = 0;
-
// connect attempts to connect a client API to the IGraphicBufferProducer.
// This must be called before any other IGraphicBufferProducer methods are
// called except for getAllocator.
@@ -188,7 +188,7 @@
// outWidth, outHeight and outTransform are filled with the default width
// and height of the window and current transform applied to buffers,
// respectively.
- virtual status_t connect(int api, QueueBufferOutput* output) = 0;
+ virtual status_t connect(int api, bool producerControlledByApp, QueueBufferOutput* output) = 0;
// disconnect attempts to disconnect a client API from the
// IGraphicBufferProducer. Calling this method will cause any subsequent
diff --git a/include/gui/Surface.h b/include/gui/Surface.h
index c25847c..2f7406e 100644
--- a/include/gui/Surface.h
+++ b/include/gui/Surface.h
@@ -61,8 +61,11 @@
* However, once a Surface is connected, it'll prevent other Surfaces
* referring to the same IGraphicBufferProducer to become connected and
* therefore prevent them to be used as actual producers of buffers.
+ *
+ * the controlledByApp flag indicates that this Surface (producer) is
+ * controlled by the application. This flag is used at connect time.
*/
- Surface(const sp<IGraphicBufferProducer>& bufferProducer);
+ Surface(const sp<IGraphicBufferProducer>& bufferProducer, bool controlledByApp = false);
/* getIGraphicBufferProducer() returns the IGraphicBufferProducer this
* Surface was created with. Usually it's an error to use the
@@ -228,6 +231,14 @@
// window. this is only a hint, actual transform may differ.
uint32_t mTransformHint;
+ // mProducerControlledByApp whether this buffer producer is controlled
+ // by the application
+ bool mProducerControlledByApp;
+
+ // mSwapIntervalZero set if we should drop buffers at queue() time to
+ // achieve an asynchronous swap interval
+ bool mSwapIntervalZero;
+
// mConsumerRunningBehind whether the consumer is running more than
// one buffer behind the producer.
mutable bool mConsumerRunningBehind;
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/InputDevice.h b/include/input/InputDevice.h
index 4672ad4..d8256c1 100644
--- a/include/input/InputDevice.h
+++ b/include/input/InputDevice.h
@@ -101,6 +101,9 @@
inline void setVibrator(bool hasVibrator) { mHasVibrator = hasVibrator; }
inline bool hasVibrator() const { return mHasVibrator; }
+ inline void setButtonUnderPad(bool hasButton) { mHasButtonUnderPad = hasButton; }
+ inline bool hasButtonUnderPad() const { return mHasButtonUnderPad; }
+
inline const Vector<MotionRange>& getMotionRanges() const {
return mMotionRanges;
}
@@ -115,6 +118,7 @@
int32_t mKeyboardType;
sp<KeyCharacterMap> mKeyCharacterMap;
bool mHasVibrator;
+ bool mHasButtonUnderPad;
Vector<MotionRange> mMotionRanges;
};
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..61b4f7d 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,17 @@
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());
+ }
+ pthread_mutex_unlock(&gTokenMutex);
+ return gToken;
+}
AppOpsManager::AppOpsManager()
{
@@ -66,13 +78,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/gui/Android.mk b/libs/gui/Android.mk
index c080f47..f627e5d 100644
--- a/libs/gui/Android.mk
+++ b/libs/gui/Android.mk
@@ -8,7 +8,6 @@
ConsumerBase.cpp \
CpuConsumer.cpp \
DisplayEventReceiver.cpp \
- DummyConsumer.cpp \
GLConsumer.cpp \
GraphicBufferAlloc.cpp \
GuiConfig.cpp \
diff --git a/libs/gui/BufferItemConsumer.cpp b/libs/gui/BufferItemConsumer.cpp
index 8d86c59..0f818b7 100644
--- a/libs/gui/BufferItemConsumer.cpp
+++ b/libs/gui/BufferItemConsumer.cpp
@@ -29,12 +29,11 @@
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 controlledByApp) :
+ ConsumerBase(bq, controlledByApp)
{
mBufferQueue->setConsumerUsageBits(consumerUsage);
- mBufferQueue->setSynchronousMode(synchronousMode);
mBufferQueue->setMaxAcquiredBufferCount(bufferCount);
}
diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp
index 8d4b174..ad2f1bb 100644
--- a/libs/gui/BufferQueue.cpp
+++ b/libs/gui/BufferQueue.cpp
@@ -30,6 +30,7 @@
#include <utils/Log.h>
#include <utils/Trace.h>
+#include <utils/CallStack.h>
// Macros for including the BufferQueue name in log messages
#define ST_LOGV(x, ...) ALOGV("[%s] "x, mConsumerName.string(), ##__VA_ARGS__)
@@ -63,15 +64,14 @@
}
}
-BufferQueue::BufferQueue(bool allowSynchronousMode,
- const sp<IGraphicBufferAlloc>& allocator) :
+BufferQueue::BufferQueue(const sp<IGraphicBufferAlloc>& allocator) :
mDefaultWidth(1),
mDefaultHeight(1),
mMaxAcquiredBufferCount(1),
mDefaultMaxBufferCount(2),
mOverrideMaxBufferCount(0),
- mSynchronousMode(false),
- mAllowSynchronousMode(allowSynchronousMode),
+ mConsumerControlledByApp(false),
+ mDequeueBufferCannotBlock(false),
mConnectedApi(NO_CONNECTED_API),
mAbandoned(false),
mFrameCounter(0),
@@ -109,11 +109,6 @@
return NO_ERROR;
}
-bool BufferQueue::isSynchronousMode() const {
- Mutex::Autolock lock(mMutex);
- return mSynchronousMode;
-}
-
void BufferQueue::setConsumerName(const String8& name) {
Mutex::Autolock lock(mMutex);
mConsumerName = name;
@@ -156,21 +151,21 @@
}
// Error out if the user has dequeued buffers
- int maxBufferCount = getMaxBufferCountLocked();
- for (int i=0 ; i<maxBufferCount; i++) {
+ for (int i=0 ; i<NUM_BUFFER_SLOTS; i++) {
if (mSlots[i].mBufferState == BufferSlot::DEQUEUED) {
ST_LOGE("setBufferCount: client owns some buffers");
return -EINVAL;
}
}
- const int minBufferSlots = getMinMaxBufferCountLocked();
if (bufferCount == 0) {
mOverrideMaxBufferCount = 0;
mDequeueCondition.broadcast();
return NO_ERROR;
}
+ // fine to assume async to false before we're setting the buffer count
+ const int minBufferSlots = getMinMaxBufferCountLocked(false);
if (bufferCount < minBufferSlots) {
ST_LOGE("setBufferCount: requested buffer count (%d) is less than "
"minimum (%d)", bufferCount, minBufferSlots);
@@ -215,7 +210,7 @@
value = mDefaultBufferFormat;
break;
case NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS:
- value = getMinUndequeuedBufferCountLocked();
+ value = getMinUndequeuedBufferCount(false);
break;
case NATIVE_WINDOW_CONSUMER_RUNNING_BEHIND:
value = (mQueue.size() >= 2);
@@ -235,15 +230,11 @@
ST_LOGE("requestBuffer: BufferQueue has been abandoned!");
return NO_INIT;
}
- int maxBufferCount = getMaxBufferCountLocked();
- if (slot < 0 || maxBufferCount <= slot) {
+ if (slot < 0 || slot >= NUM_BUFFER_SLOTS) {
ST_LOGE("requestBuffer: slot index out of range [0, %d]: %d",
- maxBufferCount, slot);
+ NUM_BUFFER_SLOTS, slot);
return BAD_VALUE;
} else if (mSlots[slot].mBufferState != BufferSlot::DEQUEUED) {
- // XXX: I vaguely recall there was some reason this can be valid, but
- // for the life of me I can't recall under what circumstances that's
- // the case.
ST_LOGE("requestBuffer: slot %d is not owned by the client (state=%d)",
slot, mSlots[slot].mBufferState);
return BAD_VALUE;
@@ -253,7 +244,7 @@
return NO_ERROR;
}
-status_t BufferQueue::dequeueBuffer(int *outBuf, sp<Fence>* outFence,
+status_t BufferQueue::dequeueBuffer(int *outBuf, sp<Fence>* outFence, bool async,
uint32_t w, uint32_t h, uint32_t format, uint32_t usage) {
ATRACE_CALL();
ST_LOGV("dequeueBuffer: w=%d h=%d fmt=%#x usage=%#x", w, h, format, usage);
@@ -285,7 +276,16 @@
return NO_INIT;
}
- const int maxBufferCount = getMaxBufferCountLocked();
+ const int maxBufferCount = getMaxBufferCountLocked(async);
+ if (async && mOverrideMaxBufferCount) {
+ // FIXME: some drivers are manually setting the buffer-count (which they
+ // shouldn't), so we do this extra test here to handle that case.
+ // This is TEMPORARY, until we get this fixed.
+ if (mOverrideMaxBufferCount < maxBufferCount) {
+ ST_LOGE("dequeueBuffer: async mode is invalid with buffercount override");
+ return BAD_VALUE;
+ }
+ }
// Free up any buffers that are in slots beyond the max buffer
// count.
@@ -334,7 +334,7 @@
// make sure the client is not trying to dequeue more buffers
// than allowed.
const int newUndequeuedCount = maxBufferCount - (dequeuedCount+1);
- const int minUndequeuedCount = getMinUndequeuedBufferCountLocked();
+ const int minUndequeuedCount = getMinUndequeuedBufferCount(async);
if (newUndequeuedCount < minUndequeuedCount) {
ST_LOGE("dequeueBuffer: min undequeued buffer count (%d) "
"exceeded (dequeued=%d undequeudCount=%d)",
@@ -348,6 +348,10 @@
// the max buffer count to change.
tryAgain = found == INVALID_BUFFER_SLOT;
if (tryAgain) {
+ if (mDequeueBufferCannotBlock) {
+ ST_LOGE("dequeueBuffer: would block! returning an error instead.");
+ return WOULD_BLOCK;
+ }
mDequeueCondition.wait(mMutex);
}
}
@@ -441,38 +445,6 @@
return returnFlags;
}
-status_t BufferQueue::setSynchronousMode(bool enabled) {
- ATRACE_CALL();
- ST_LOGV("setSynchronousMode: enabled=%d", enabled);
- Mutex::Autolock lock(mMutex);
-
- if (mAbandoned) {
- ST_LOGE("setSynchronousMode: BufferQueue has been abandoned!");
- return NO_INIT;
- }
-
- status_t err = OK;
- if (!mAllowSynchronousMode && enabled)
- return err;
-
- if (!enabled) {
- // going to asynchronous mode, drain the queue
- err = drainQueueLocked();
- if (err != NO_ERROR)
- return err;
- }
-
- if (mSynchronousMode != enabled) {
- // - if we're going to asynchronous mode, the queue is guaranteed to be
- // empty here
- // - if the client set the number of buffers, we're guaranteed that
- // we have at least 3 (because we don't allow less)
- mSynchronousMode = enabled;
- mDequeueCondition.broadcast();
- }
- return err;
-}
-
status_t BufferQueue::queueBuffer(int buf,
const QueueBufferInput& input, QueueBufferOutput* output) {
ATRACE_CALL();
@@ -482,9 +454,10 @@
uint32_t transform;
int scalingMode;
int64_t timestamp;
+ bool async;
sp<Fence> fence;
- input.deflate(×tamp, &crop, &scalingMode, &transform, &fence);
+ input.deflate(×tamp, &crop, &scalingMode, &transform, &async, &fence);
if (fence == NULL) {
ST_LOGE("queueBuffer: fence is NULL");
@@ -511,7 +484,17 @@
ST_LOGE("queueBuffer: BufferQueue has been abandoned!");
return NO_INIT;
}
- int maxBufferCount = getMaxBufferCountLocked();
+
+ const int maxBufferCount = getMaxBufferCountLocked(async);
+ if (async && mOverrideMaxBufferCount) {
+ // FIXME: some drivers are manually setting the buffer-count (which they
+ // shouldn't), so we do this extra test here to handle that case.
+ // This is TEMPORARY, until we get this fixed.
+ if (mOverrideMaxBufferCount < maxBufferCount) {
+ ST_LOGE("queueBuffer: async mode is invalid with buffercount override");
+ return BAD_VALUE;
+ }
+ }
if (buf < 0 || buf >= maxBufferCount) {
ST_LOGE("queueBuffer: slot index out of range [0, %d]: %d",
maxBufferCount, buf);
@@ -557,31 +540,30 @@
item.mFrameNumber = mFrameCounter;
item.mBuf = buf;
item.mFence = fence;
+ item.mIsDroppable = mDequeueBufferCannotBlock || async;
- if (mSynchronousMode) {
- // In synchronous mode we queue all buffers in a FIFO.
+ if (mQueue.empty()) {
+ // when the queue is empty, we can ignore "mDequeueBufferCannotBlock", and
+ // simply queue this buffer.
mQueue.push_back(item);
-
- // Synchronous mode always signals that an additional frame should
- // be consumed.
listener = mConsumerListener;
} else {
- // In asynchronous mode we only keep the most recent buffer.
- if (mQueue.empty()) {
- mQueue.push_back(item);
-
- // Asynchronous mode only signals that a frame should be
- // consumed if no previous frame was pending. If a frame were
- // pending then the consumer would have already been notified.
- listener = mConsumerListener;
- } else {
- Fifo::iterator front(mQueue.begin());
+ // when the queue is not empty, we need to look at the front buffer
+ // state and see if we need to replace it.
+ Fifo::iterator front(mQueue.begin());
+ if (front->mIsDroppable) {
// buffer slot currently queued is marked free if still tracked
if (stillTracking(front)) {
mSlots[front->mBuf].mBufferState = BufferSlot::FREE;
+ // reset the frame number of the freed buffer so that it is the first in
+ // line to be dequeued again.
+ mSlots[front->mBuf].mFrameNumber = 0;
}
- // and we record the new buffer index in the queued list
+ // and we record the new buffer in the queued list
*front = item;
+ } else {
+ mQueue.push_back(item);
+ listener = mConsumerListener;
}
}
@@ -611,10 +593,9 @@
return;
}
- int maxBufferCount = getMaxBufferCountLocked();
- if (buf < 0 || buf >= maxBufferCount) {
+ if (buf < 0 || buf >= NUM_BUFFER_SLOTS) {
ST_LOGE("cancelBuffer: slot index out of range [0, %d]: %d",
- maxBufferCount, buf);
+ NUM_BUFFER_SLOTS, buf);
return;
} else if (mSlots[buf].mBufferState != BufferSlot::DEQUEUED) {
ST_LOGE("cancelBuffer: slot %d is not owned by the client (state=%d)",
@@ -630,7 +611,7 @@
mDequeueCondition.broadcast();
}
-status_t BufferQueue::connect(int api, QueueBufferOutput* output) {
+status_t BufferQueue::connect(int api, bool producerControlledByApp, QueueBufferOutput* output) {
ATRACE_CALL();
ST_LOGV("connect: api=%d", api);
Mutex::Autolock lock(mMutex);
@@ -667,6 +648,7 @@
}
mBufferHasBeenQueued = false;
+ mDequeueBufferCannotBlock = mConsumerControlledByApp && producerControlledByApp;
return err;
}
@@ -693,7 +675,7 @@
case NATIVE_WINDOW_API_MEDIA:
case NATIVE_WINDOW_API_CAMERA:
if (mConnectedApi == api) {
- drainQueueAndFreeBuffersLocked();
+ freeAllBuffersLocked();
mConnectedApi = NO_CONNECTED_API;
mDequeueCondition.broadcast();
listener = mConsumerListener;
@@ -739,12 +721,11 @@
fifoSize++;
}
- int maxBufferCount = getMaxBufferCountLocked();
result.appendFormat(
- "%s-BufferQueue maxBufferCount=%d, mSynchronousMode=%d, default-size=[%dx%d], "
+ "%s-BufferQueue mMaxAcquiredBufferCount=%d, mDequeueBufferCannotBlock=%d, default-size=[%dx%d], "
"default-format=%d, transform-hint=%02x, FIFO(%d)={%s}\n",
- prefix, maxBufferCount, mSynchronousMode, mDefaultWidth,
+ prefix, mMaxAcquiredBufferCount, mDequeueBufferCannotBlock, mDefaultWidth,
mDefaultHeight, mDefaultBufferFormat, mTransformHint,
fifoSize, fifo.string());
@@ -760,16 +741,25 @@
}
} stateName;
+ // just trim the free buffers to not spam the dump
+ int maxBufferCount = 0;
+ for (int i=NUM_BUFFER_SLOTS-1 ; i>=0 ; i--) {
+ const BufferSlot& slot(mSlots[i]);
+ if ((slot.mBufferState != BufferSlot::FREE) || (slot.mGraphicBuffer != NULL)) {
+ maxBufferCount = i+1;
+ break;
+ }
+ }
+
for (int i=0 ; i<maxBufferCount ; i++) {
const BufferSlot& slot(mSlots[i]);
+ const sp<GraphicBuffer>& buf(slot.mGraphicBuffer);
result.appendFormat(
"%s%s[%02d:%p] state=%-8s",
- prefix, (slot.mBufferState == BufferSlot::ACQUIRED)?">":" ", i,
- slot.mGraphicBuffer.get(),
+ prefix, (slot.mBufferState == BufferSlot::ACQUIRED)?">":" ", i, buf.get(),
stateName(slot.mBufferState)
);
- const sp<GraphicBuffer>& buf(slot.mGraphicBuffer);
if (buf != NULL) {
result.appendFormat(
", %p [%4ux%4u:%4u,%3X]",
@@ -799,8 +789,6 @@
}
void BufferQueue::freeAllBuffersLocked() {
- ALOGD_IF(!mQueue.isEmpty(),
- "freeAllBuffersLocked called with non-empty mQueue");
mBufferHasBeenQueued = false;
for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
freeBufferLocked(i);
@@ -855,13 +843,13 @@
if (presentWhen != 0 && desiredPresent > presentWhen &&
desiredPresent - presentWhen < MAX_FUTURE_NSEC)
{
- ALOGV("pts defer: des=%lld when=%lld (%lld) now=%lld",
+ ST_LOGV("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)",
+ ST_LOGV("pts accept: %p[%d] sig=%lld des=%lld when=%lld (%lld)",
mSlots, buf, mSlots[buf].mFence->getSignalTime(),
desiredPresent, presentWhen, desiredPresent - presentWhen);
}
@@ -901,35 +889,31 @@
ATRACE_CALL();
ATRACE_BUFFER_INDEX(buf);
- Mutex::Autolock _l(mMutex);
-
if (buf == INVALID_BUFFER_SLOT || fence == NULL) {
return BAD_VALUE;
}
- // Check if this buffer slot is on the queue
- bool slotQueued = false;
- Fifo::iterator front(mQueue.begin());
- while (front != mQueue.end() && !slotQueued) {
- if (front->mBuf == buf)
- slotQueued = true;
- front++;
- }
+ Mutex::Autolock _l(mMutex);
// If the frame number has changed because buffer has been reallocated,
// we can ignore this releaseBuffer for the old buffer.
if (frameNumber != mSlots[buf].mFrameNumber) {
- // This should only occur if new buffer is still in the queue
- ALOGE_IF(!slotQueued,
- "received old buffer(#%lld) after new buffer(#%lld) on same "
- "slot #%d already acquired", frameNumber,
- mSlots[buf].mFrameNumber, buf);
return STALE_BUFFER_SLOT;
}
- // this should never happen
- ALOGE_IF(slotQueued,
- "received new buffer(#%lld) on slot #%d that has not yet been "
- "acquired", frameNumber, buf);
+
+
+ // Internal state consistency checks:
+ // Make sure this buffers hasn't been queued while we were owning it (acquired)
+ Fifo::iterator front(mQueue.begin());
+ Fifo::const_iterator const end(mQueue.end());
+ while (front != end) {
+ if (front->mBuf == buf) {
+ LOG_ALWAYS_FATAL("[%s] received new buffer(#%lld) on slot #%d that has not yet been "
+ "acquired", mConsumerName.string(), frameNumber, buf);
+ break; // never reached
+ }
+ front++;
+ }
// The buffer can now only be released if its in the acquired state
if (mSlots[buf].mBufferState == BufferSlot::ACQUIRED) {
@@ -950,7 +934,8 @@
return NO_ERROR;
}
-status_t BufferQueue::consumerConnect(const sp<ConsumerListener>& consumerListener) {
+status_t BufferQueue::consumerConnect(const sp<ConsumerListener>& consumerListener,
+ bool controlledByApp) {
ST_LOGV("consumerConnect");
Mutex::Autolock lock(mMutex);
@@ -964,6 +949,7 @@
}
mConsumerListener = consumerListener;
+ mConsumerControlledByApp = controlledByApp;
return NO_ERROR;
}
@@ -1017,8 +1003,7 @@
return NO_ERROR;
}
-status_t BufferQueue::setDefaultBufferSize(uint32_t w, uint32_t h)
-{
+status_t BufferQueue::setDefaultBufferSize(uint32_t w, uint32_t h) {
ST_LOGV("setDefaultBufferSize: w=%d, h=%d", w, h);
if (!w || !h) {
ST_LOGE("setDefaultBufferSize: dimensions cannot be 0 (w=%d, h=%d)",
@@ -1053,40 +1038,17 @@
return NO_ERROR;
}
-status_t BufferQueue::drainQueueLocked() {
- while (mSynchronousMode && mQueue.size() > 1) {
- mDequeueCondition.wait(mMutex);
- if (mAbandoned) {
- ST_LOGE("drainQueueLocked: BufferQueue has been abandoned!");
- return NO_INIT;
- }
- if (mConnectedApi == NO_CONNECTED_API) {
- ST_LOGE("drainQueueLocked: BufferQueue is not connected!");
- return NO_INIT;
- }
- }
- return NO_ERROR;
+int BufferQueue::getMinUndequeuedBufferCount(bool async) const {
+ return (mDequeueBufferCannotBlock || async) ?
+ mMaxAcquiredBufferCount+1 : mMaxAcquiredBufferCount;
}
-status_t BufferQueue::drainQueueAndFreeBuffersLocked() {
- status_t err = drainQueueLocked();
- if (err == NO_ERROR) {
- freeAllBuffersLocked();
- }
- return err;
+int BufferQueue::getMinMaxBufferCountLocked(bool async) const {
+ return getMinUndequeuedBufferCount(async) + 1;
}
-int BufferQueue::getMinMaxBufferCountLocked() const {
- return getMinUndequeuedBufferCountLocked() + 1;
-}
-
-int BufferQueue::getMinUndequeuedBufferCountLocked() const {
- return mSynchronousMode ? mMaxAcquiredBufferCount :
- mMaxAcquiredBufferCount + 1;
-}
-
-int BufferQueue::getMaxBufferCountLocked() const {
- int minMaxBufferCount = getMinMaxBufferCountLocked();
+int BufferQueue::getMaxBufferCountLocked(bool async) const {
+ int minMaxBufferCount = getMinMaxBufferCountLocked(async);
int maxBufferCount = mDefaultMaxBufferCount;
if (maxBufferCount < minMaxBufferCount) {
diff --git a/libs/gui/ConsumerBase.cpp b/libs/gui/ConsumerBase.cpp
index deb2646..cd94ce1 100644
--- a/libs/gui/ConsumerBase.cpp
+++ b/libs/gui/ConsumerBase.cpp
@@ -51,7 +51,7 @@
return android_atomic_inc(&globalCounter);
}
-ConsumerBase::ConsumerBase(const sp<BufferQueue>& bufferQueue) :
+ConsumerBase::ConsumerBase(const sp<BufferQueue>& bufferQueue, bool controlledByApp) :
mAbandoned(false),
mBufferQueue(bufferQueue) {
// Choose a name using the PID and a process-unique ID.
@@ -66,7 +66,7 @@
listener = static_cast<BufferQueue::ConsumerListener*>(this);
proxy = new BufferQueue::ProxyConsumerListener(listener);
- status_t err = mBufferQueue->consumerConnect(proxy);
+ status_t err = mBufferQueue->consumerConnect(proxy, controlledByApp);
if (err != NO_ERROR) {
CB_LOGE("ConsumerBase: error connecting to BufferQueue: %s (%d)",
strerror(-err), err);
diff --git a/libs/gui/CpuConsumer.cpp b/libs/gui/CpuConsumer.cpp
index 56bc7c6..b8c00af 100644
--- a/libs/gui/CpuConsumer.cpp
+++ b/libs/gui/CpuConsumer.cpp
@@ -30,15 +30,15 @@
namespace android {
-CpuConsumer::CpuConsumer(uint32_t maxLockedBuffers, bool synchronousMode) :
- ConsumerBase(new BufferQueue(true) ),
+CpuConsumer::CpuConsumer(const sp<BufferQueue>& bq,
+ uint32_t maxLockedBuffers, bool controlledByApp) :
+ ConsumerBase(bq, controlledByApp),
mMaxLockedBuffers(maxLockedBuffers),
mCurrentLockedBuffers(0)
{
// Create tracking entries for locked buffers
mAcquiredBuffers.insertAt(0, maxLockedBuffers);
- mBufferQueue->setSynchronousMode(synchronousMode);
mBufferQueue->setConsumerUsageBits(GRALLOC_USAGE_SW_READ_OFTEN);
mBufferQueue->setMaxAcquiredBufferCount(maxLockedBuffers);
}
diff --git a/libs/gui/DummyConsumer.cpp b/libs/gui/DummyConsumer.cpp
deleted file mode 100644
index be47e0e..0000000
--- a/libs/gui/DummyConsumer.cpp
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "DummyConsumer"
-// #define LOG_NDEBUG 0
-
-#include <gui/DummyConsumer.h>
-
-#include <utils/Log.h>
-#include <utils/String8.h>
-
-namespace android {
-
-DummyConsumer::DummyConsumer() {
- ALOGV("DummyConsumer");
-}
-
-DummyConsumer::~DummyConsumer() {
- ALOGV("~DummyConsumer");
-}
-
-void DummyConsumer::onFrameAvailable() {
- ALOGV("onFrameAvailable");
-}
-
-void DummyConsumer::onBuffersReleased() {
- ALOGV("onBuffersReleased");
-}
-
-}; // namespace android
diff --git a/libs/gui/GLConsumer.cpp b/libs/gui/GLConsumer.cpp
index d12083f..92f07eb 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, bool isControlledByApp) :
+ ConsumerBase(bq, isControlledByApp),
mCurrentTransform(0),
mCurrentScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE),
mCurrentFence(Fence::NO_FENCE),
@@ -844,11 +844,6 @@
return NO_ERROR;
}
-bool GLConsumer::isSynchronousMode() const {
- Mutex::Autolock lock(mMutex);
- return mBufferQueue->isSynchronousMode();
-}
-
void GLConsumer::freeBufferLocked(int slotIndex) {
ST_LOGV("freeBufferLocked: slotIndex=%d", slotIndex);
if (slotIndex == mCurrentTexture) {
@@ -891,13 +886,6 @@
return mBufferQueue->setTransformHint(hint);
}
-// Used for refactoring BufferQueue from GLConsumer
-// Should not be in final interface once users of GLConsumer are clean up.
-status_t GLConsumer::setSynchronousMode(bool enabled) {
- Mutex::Autolock lock(mMutex);
- return mBufferQueue->setSynchronousMode(enabled);
-}
-
void GLConsumer::dumpLocked(String8& result, const char* prefix) const
{
result.appendFormat(
diff --git a/libs/gui/IGraphicBufferProducer.cpp b/libs/gui/IGraphicBufferProducer.cpp
index 63d7628..2e561df 100644
--- a/libs/gui/IGraphicBufferProducer.cpp
+++ b/libs/gui/IGraphicBufferProducer.cpp
@@ -37,7 +37,6 @@
QUEUE_BUFFER,
CANCEL_BUFFER,
QUERY,
- SET_SYNCHRONOUS_MODE,
CONNECT,
DISCONNECT,
};
@@ -81,10 +80,11 @@
return result;
}
- virtual status_t dequeueBuffer(int *buf, sp<Fence>* fence,
+ virtual status_t dequeueBuffer(int *buf, sp<Fence>* fence, bool async,
uint32_t w, uint32_t h, uint32_t format, uint32_t usage) {
Parcel data, reply;
data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor());
+ data.writeInt32(async);
data.writeInt32(w);
data.writeInt32(h);
data.writeInt32(format);
@@ -142,22 +142,11 @@
return result;
}
- virtual status_t setSynchronousMode(bool enabled) {
- Parcel data, reply;
- data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor());
- data.writeInt32(enabled);
- status_t result = remote()->transact(SET_SYNCHRONOUS_MODE, data, &reply);
- if (result != NO_ERROR) {
- return result;
- }
- result = reply.readInt32();
- return result;
- }
-
- virtual status_t connect(int api, QueueBufferOutput* output) {
+ virtual status_t connect(int api, bool producerControlledByApp, QueueBufferOutput* output) {
Parcel data, reply;
data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor());
data.writeInt32(api);
+ data.writeInt32(producerControlledByApp);
status_t result = remote()->transact(CONNECT, data, &reply);
if (result != NO_ERROR) {
return result;
@@ -209,13 +198,14 @@
} break;
case DEQUEUE_BUFFER: {
CHECK_INTERFACE(IGraphicBufferProducer, data, reply);
+ bool async = data.readInt32();
uint32_t w = data.readInt32();
uint32_t h = data.readInt32();
uint32_t format = data.readInt32();
uint32_t usage = data.readInt32();
int buf;
sp<Fence> fence;
- int result = dequeueBuffer(&buf, &fence, w, h, format, usage);
+ int result = dequeueBuffer(&buf, &fence, async, w, h, format, usage);
reply->writeInt32(buf);
reply->writeInt32(fence != NULL);
if (fence != NULL) {
@@ -252,20 +242,14 @@
reply->writeInt32(res);
return NO_ERROR;
} break;
- case SET_SYNCHRONOUS_MODE: {
- CHECK_INTERFACE(IGraphicBufferProducer, data, reply);
- bool enabled = data.readInt32();
- status_t res = setSynchronousMode(enabled);
- reply->writeInt32(res);
- return NO_ERROR;
- } break;
case CONNECT: {
CHECK_INTERFACE(IGraphicBufferProducer, data, reply);
int api = data.readInt32();
+ bool producerControlledByApp = data.readInt32();
QueueBufferOutput* const output =
reinterpret_cast<QueueBufferOutput *>(
reply->writeInplace(sizeof(QueueBufferOutput)));
- status_t res = connect(api, output);
+ status_t res = connect(api, producerControlledByApp, output);
reply->writeInt32(res);
return NO_ERROR;
} break;
@@ -292,6 +276,7 @@
+ sizeof(crop)
+ sizeof(scalingMode)
+ sizeof(transform)
+ + sizeof(async)
+ fence->getFlattenedSize();
}
@@ -309,6 +294,7 @@
memcpy(p, &crop, sizeof(crop)); p += sizeof(crop);
memcpy(p, &scalingMode, sizeof(scalingMode)); p += sizeof(scalingMode);
memcpy(p, &transform, sizeof(transform)); p += sizeof(transform);
+ memcpy(p, &async, sizeof(async)); p += sizeof(async);
err = fence->flatten(p, size - (p - (char*)buffer), fds, count);
return err;
}
@@ -322,6 +308,7 @@
memcpy(&crop, p, sizeof(crop)); p += sizeof(crop);
memcpy(&scalingMode, p, sizeof(scalingMode)); p += sizeof(scalingMode);
memcpy(&transform, p, sizeof(transform)); p += sizeof(transform);
+ memcpy(&async, p, sizeof(async)); p += sizeof(async);
fence = new Fence();
err = fence->unflatten(p, size - (p - (const char*)buffer), fds, count);
return err;
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index a616c1e..998ea8a 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -37,7 +37,8 @@
namespace android {
Surface::Surface(
- const sp<IGraphicBufferProducer>& bufferProducer)
+ const sp<IGraphicBufferProducer>& bufferProducer,
+ bool controlledByApp)
: mGraphicBufferProducer(bufferProducer)
{
// Initialize the ANativeWindow function pointers.
@@ -71,6 +72,8 @@
mTransformHint = 0;
mConsumerRunningBehind = false;
mConnectedToCpu = false;
+ mProducerControlledByApp = true;
+ mSwapIntervalZero = false;
}
Surface::~Surface() {
@@ -160,7 +163,6 @@
// EGL specification states:
// interval is silently clamped to minimum and maximum implementation
// dependent values before being stored.
- // Although we don't have to, we apply the same logic here.
if (interval < minSwapInterval)
interval = minSwapInterval;
@@ -168,9 +170,9 @@
if (interval > maxSwapInterval)
interval = maxSwapInterval;
- status_t res = mGraphicBufferProducer->setSynchronousMode(interval ? true : false);
+ mSwapIntervalZero = (interval == 0);
- return res;
+ return NO_ERROR;
}
int Surface::dequeueBuffer(android_native_buffer_t** buffer,
@@ -182,7 +184,7 @@
int reqW = mReqWidth ? mReqWidth : mUserWidth;
int reqH = mReqHeight ? mReqHeight : mUserHeight;
sp<Fence> fence;
- status_t result = mGraphicBufferProducer->dequeueBuffer(&buf, &fence,
+ status_t result = mGraphicBufferProducer->dequeueBuffer(&buf, &fence, mSwapIntervalZero,
reqW, reqH, mReqFormat, mReqUsage);
if (result < 0) {
ALOGV("dequeueBuffer: IGraphicBufferProducer::dequeueBuffer(%d, %d, %d, %d)"
@@ -278,7 +280,7 @@
sp<Fence> fence(fenceFd >= 0 ? new Fence(fenceFd) : Fence::NO_FENCE);
IGraphicBufferProducer::QueueBufferOutput output;
IGraphicBufferProducer::QueueBufferInput input(timestamp, crop, mScalingMode,
- mTransform, fence);
+ mTransform, mSwapIntervalZero, fence);
status_t err = mGraphicBufferProducer->queueBuffer(i, input, &output);
if (err != OK) {
ALOGE("queueBuffer: error queuing buffer to SurfaceTexture, %d", err);
@@ -486,7 +488,7 @@
ALOGV("Surface::connect");
Mutex::Autolock lock(mMutex);
IGraphicBufferProducer::QueueBufferOutput output;
- int err = mGraphicBufferProducer->connect(api, &output);
+ int err = mGraphicBufferProducer->connect(api, mProducerControlledByApp, &output);
if (err == NO_ERROR) {
uint32_t numPendingBuffers = 0;
output.deflate(&mDefaultWidth, &mDefaultHeight, &mTransformHint,
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 9682987..b691fc1 100644
--- a/libs/gui/tests/BufferQueue_test.cpp
+++ b/libs/gui/tests/BufferQueue_test.cpp
@@ -62,21 +62,21 @@
TEST_F(BufferQueueTest, AcquireBuffer_ExceedsMaxAcquireCount_Fails) {
sp<DummyConsumer> dc(new DummyConsumer);
- mBQ->consumerConnect(dc);
+ mBQ->consumerConnect(dc, false);
IGraphicBufferProducer::QueueBufferOutput qbo;
- mBQ->connect(NATIVE_WINDOW_API_CPU, &qbo);
+ mBQ->connect(NATIVE_WINDOW_API_CPU, false, &qbo);
mBQ->setBufferCount(4);
int slot;
sp<Fence> fence;
sp<GraphicBuffer> buf;
IGraphicBufferProducer::QueueBufferInput qbi(0, Rect(0, 0, 1, 1),
- NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, Fence::NO_FENCE);
+ NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, false, Fence::NO_FENCE);
BufferQueue::BufferItem item;
for (int i = 0; i < 2; i++) {
ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
- mBQ->dequeueBuffer(&slot, &fence, 1, 1, 0,
+ mBQ->dequeueBuffer(&slot, &fence, false, 1, 1, 0,
GRALLOC_USAGE_SW_READ_OFTEN));
ASSERT_EQ(OK, mBQ->requestBuffer(slot, &buf));
ASSERT_EQ(OK, mBQ->queueBuffer(slot, qbi, &qbo));
@@ -84,7 +84,7 @@
}
ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
- mBQ->dequeueBuffer(&slot, &fence, 1, 1, 0,
+ mBQ->dequeueBuffer(&slot, &fence, false, 1, 1, 0,
GRALLOC_USAGE_SW_READ_OFTEN));
ASSERT_EQ(OK, mBQ->requestBuffer(slot, &buf));
ASSERT_EQ(OK, mBQ->queueBuffer(slot, qbi, &qbo));
@@ -95,7 +95,7 @@
TEST_F(BufferQueueTest, SetMaxAcquiredBufferCountWithIllegalValues_ReturnsError) {
sp<DummyConsumer> dc(new DummyConsumer);
- mBQ->consumerConnect(dc);
+ mBQ->consumerConnect(dc, false);
ASSERT_EQ(BAD_VALUE, mBQ->setMaxAcquiredBufferCount(0));
ASSERT_EQ(BAD_VALUE, mBQ->setMaxAcquiredBufferCount(-3));
@@ -106,7 +106,7 @@
TEST_F(BufferQueueTest, SetMaxAcquiredBufferCountWithLegalValues_Succeeds) {
sp<DummyConsumer> dc(new DummyConsumer);
- mBQ->consumerConnect(dc);
+ mBQ->consumerConnect(dc, false);
ASSERT_EQ(OK, mBQ->setMaxAcquiredBufferCount(1));
ASSERT_EQ(OK, mBQ->setMaxAcquiredBufferCount(2));
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..158c94b 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;
@@ -337,7 +338,7 @@
TEST_F(SurfaceTextureClientTest, SurfaceTextureTooManyUpdateTexImage) {
android_native_buffer_t* buf[3];
- ASSERT_EQ(OK, mST->setSynchronousMode(false));
+ ASSERT_EQ(OK, mANW->setSwapInterval(mANW.get(), 0));
ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 4));
ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[0]));
@@ -345,7 +346,7 @@
EXPECT_EQ(OK, mST->updateTexImage());
EXPECT_EQ(OK, mST->updateTexImage());
- ASSERT_EQ(OK, mST->setSynchronousMode(true));
+ ASSERT_EQ(OK, mANW->setSwapInterval(mANW.get(), 1));
ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 3));
ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[0]));
@@ -360,7 +361,6 @@
TEST_F(SurfaceTextureClientTest, SurfaceTextureSyncModeSlowRetire) {
android_native_buffer_t* buf[3];
- ASSERT_EQ(OK, mST->setSynchronousMode(true));
ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 4));
ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[0]));
ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[1]));
@@ -381,7 +381,6 @@
TEST_F(SurfaceTextureClientTest, SurfaceTextureSyncModeFastRetire) {
android_native_buffer_t* buf[3];
- ASSERT_EQ(OK, mST->setSynchronousMode(true));
ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 4));
ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[0]));
ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[1]));
@@ -402,7 +401,6 @@
TEST_F(SurfaceTextureClientTest, SurfaceTextureSyncModeDQQR) {
android_native_buffer_t* buf[3];
- ASSERT_EQ(OK, mST->setSynchronousMode(true));
ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 3));
ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[0]));
@@ -428,7 +426,6 @@
TEST_F(SurfaceTextureClientTest, DISABLED_SurfaceTextureSyncModeDequeueCurrent) {
android_native_buffer_t* buf[3];
android_native_buffer_t* firstBuf;
- ASSERT_EQ(OK, mST->setSynchronousMode(true));
ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 3));
ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &firstBuf));
ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), firstBuf, -1));
@@ -448,7 +445,6 @@
TEST_F(SurfaceTextureClientTest, SurfaceTextureSyncModeMinUndequeued) {
android_native_buffer_t* buf[3];
- ASSERT_EQ(OK, mST->setSynchronousMode(true));
ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 3));
// We should be able to dequeue all the buffers before we've queued mANWy.
@@ -527,7 +523,6 @@
};
android_native_buffer_t* buf[3];
- ASSERT_EQ(OK, mST->setSynchronousMode(true));
ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 3));
// dequeue/queue/update so we have a current buffer
ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[0]));
@@ -715,7 +710,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..e6d87db 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);
@@ -942,7 +944,6 @@
enum { texHeight = 16 };
enum { numFrames = 1024 };
- ASSERT_EQ(NO_ERROR, mST->setSynchronousMode(true));
ASSERT_EQ(NO_ERROR, mST->setDefaultMaxBufferCount(2));
ASSERT_EQ(NO_ERROR, native_window_set_buffers_geometry(mANW.get(),
texWidth, texHeight, HAL_PIXEL_FORMAT_YV12));
@@ -1209,10 +1210,8 @@
sp<ANativeWindow> mANW;
};
- ASSERT_EQ(OK, mST->setSynchronousMode(true));
-
sp<DisconnectWaiter> dw(new DisconnectWaiter());
- mST->getBufferQueue()->consumerConnect(dw);
+ mST->getBufferQueue()->consumerConnect(dw, false);
sp<Thread> pt(new ProducerThread(mANW));
@@ -1235,8 +1234,6 @@
// when it is disconnected and reconnected. Otherwise it will
// attempt to release a buffer that it does not owned
TEST_F(SurfaceTextureGLTest, DisconnectClearsCurrentTexture) {
- ASSERT_EQ(OK, mST->setSynchronousMode(true));
-
ASSERT_EQ(OK, native_window_api_connect(mANW.get(),
NATIVE_WINDOW_API_EGL));
@@ -1256,8 +1253,6 @@
ASSERT_EQ(OK, native_window_api_connect(mANW.get(),
NATIVE_WINDOW_API_EGL));
- ASSERT_EQ(OK, mST->setSynchronousMode(true));
-
EXPECT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &anb));
EXPECT_EQ(OK, mANW->queueBuffer(mANW.get(), anb, -1));
@@ -1270,8 +1265,6 @@
}
TEST_F(SurfaceTextureGLTest, ScaleToWindowMode) {
- ASSERT_EQ(OK, mST->setSynchronousMode(true));
-
ASSERT_EQ(OK, native_window_set_scaling_mode(mANW.get(),
NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW));
@@ -1304,8 +1297,6 @@
// the image such that it has the same aspect ratio as the
// default buffer size
TEST_F(SurfaceTextureGLTest, CroppedScalingMode) {
- ASSERT_EQ(OK, mST->setSynchronousMode(true));
-
ASSERT_EQ(OK, native_window_set_scaling_mode(mANW.get(),
NATIVE_WINDOW_SCALING_MODE_SCALE_CROP));
@@ -1415,7 +1406,6 @@
Mutex mMutex;
};
- ASSERT_EQ(OK, mST->setSynchronousMode(true));
ASSERT_EQ(OK, mST->setDefaultMaxBufferCount(2));
sp<Thread> pt(new ProducerThread(mANW));
@@ -1808,32 +1798,6 @@
EXPECT_EQ(1, buffer->getStrongCount());
}
-
-TEST_F(SurfaceTextureGLToGLTest, EglSurfaceDefaultsToSynchronousMode) {
- // This test requires 3 buffers to run on a single thread.
- mST->setDefaultMaxBufferCount(3);
-
- ASSERT_TRUE(mST->isSynchronousMode());
-
- for (int i = 0; i < 10; i++) {
- // Produce a frame
- EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mProducerEglSurface,
- mProducerEglSurface, mProducerEglContext));
- ASSERT_EQ(EGL_SUCCESS, eglGetError());
- glClear(GL_COLOR_BUFFER_BIT);
- EXPECT_TRUE(eglSwapBuffers(mEglDisplay, mProducerEglSurface));
- ASSERT_EQ(EGL_SUCCESS, eglGetError());
-
- // Consume a frame
- EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface,
- mEglContext));
- ASSERT_EQ(EGL_SUCCESS, eglGetError());
- ASSERT_EQ(NO_ERROR, mST->updateTexImage());
- }
-
- ASSERT_TRUE(mST->isSynchronousMode());
-}
-
TEST_F(SurfaceTextureGLToGLTest, TexturingFromUserSizedGLFilledBuffer) {
enum { texWidth = 64 };
enum { texHeight = 64 };
@@ -2283,7 +2247,6 @@
}
};
- ASSERT_EQ(OK, mST->setSynchronousMode(true));
ASSERT_EQ(OK, mST->setDefaultMaxBufferCount(2));
runProducerThread(new PT());
@@ -2824,7 +2787,6 @@
TEST_F(SurfaceTextureMultiContextGLTest,
UpdateTexImageSucceedsForBufferConsumedBeforeDetach) {
- ASSERT_EQ(NO_ERROR, mST->setSynchronousMode(true));
ASSERT_EQ(NO_ERROR, mST->setDefaultMaxBufferCount(2));
// produce two frames and consume them both on the primary context
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/InputDevice.cpp b/libs/input/InputDevice.cpp
index 77fa49d..54703d4 100644
--- a/libs/input/InputDevice.cpp
+++ b/libs/input/InputDevice.cpp
@@ -136,6 +136,7 @@
mKeyboardType(other.mKeyboardType),
mKeyCharacterMap(other.mKeyCharacterMap),
mHasVibrator(other.mHasVibrator),
+ mHasButtonUnderPad(other.mHasButtonUnderPad),
mMotionRanges(other.mMotionRanges) {
}
@@ -152,6 +153,7 @@
mSources = 0;
mKeyboardType = AINPUT_KEYBOARD_TYPE_NONE;
mHasVibrator = false;
+ mHasButtonUnderPad = false;
mMotionRanges.clear();
}
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/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp
index 015740a..6c285d3 100644
--- a/opengl/libs/EGL/eglApi.cpp
+++ b/opengl/libs/EGL/eglApi.cpp
@@ -373,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
diff --git a/opengl/tests/EGLTest/EGL_test.cpp b/opengl/tests/EGLTest/EGL_test.cpp
index c0daba2..86bbb84 100644
--- a/opengl/tests/EGLTest/EGL_test.cpp
+++ b/opengl/tests/EGLTest/EGL_test.cpp
@@ -20,7 +20,6 @@
#include <EGL/egl.h>
#include <gui/Surface.h>
-#include <gui/DummyConsumer.h>
namespace android {
@@ -101,9 +100,14 @@
};
EXPECT_TRUE(eglChooseConfig(mEglDisplay, attrs, &config, 1, &numConfigs));
+ struct DummyConsumer : public BufferQueue::ConsumerListener {
+ virtual void onFrameAvailable() {}
+ virtual void onBuffersReleased() {}
+ };
+
// Create a EGLSurface
sp<BufferQueue> bq = new BufferQueue();
- bq->consumerConnect(new DummyConsumer());
+ bq->consumerConnect(new DummyConsumer, false);
sp<Surface> mSTC = new Surface(static_cast<sp<IGraphicBufferProducer> >( bq));
sp<ANativeWindow> mANW = mSTC;
diff --git a/services/inputflinger/Android.mk b/services/inputflinger/Android.mk
new file mode 100644
index 0000000..e32d38a
--- /dev/null
+++ b/services/inputflinger/Android.mk
@@ -0,0 +1,50 @@
+# 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)
+
+########################################################################
+# build input flinger executable
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ main.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+ libbinder \
+ libinputflinger \
+ libutils
+
+LOCAL_MODULE := inputflinger
+
+include $(BUILD_EXECUTABLE)
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/cmds/sensorservice/main_sensorservice.cpp b/services/inputflinger/main.cpp
similarity index 76%
copy from cmds/sensorservice/main_sensorservice.cpp
copy to services/inputflinger/main.cpp
index 8610627..3209a62 100644
--- a/cmds/sensorservice/main_sensorservice.cpp
+++ b/services/inputflinger/main.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011 The Android Open Source Project
+ * 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.
@@ -15,11 +15,12 @@
*/
#include <binder/BinderService.h>
-#include <SensorService.h>
+#include "InputFlinger.h"
using namespace android;
int main(int argc, char** argv) {
- SensorService::publishAndJoinThreadPool();
+ ProcessState::self()->setThreadPoolMaxThreadCount(4);
+ BinderService<InputFlinger>::publishAndJoinThreadPool(true);
return 0;
}
diff --git a/services/sensorservice/Android.mk b/services/sensorservice/Android.mk
index 14a4e55..4f24ddc 100644
--- a/services/sensorservice/Android.mk
+++ b/services/sensorservice/Android.mk
@@ -31,3 +31,21 @@
LOCAL_MODULE:= libsensorservice
include $(BUILD_SHARED_LIBRARY)
+
+#####################################################################
+# build executable
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ main_sensorservice.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+ libsensorservice \
+ libbinder \
+ libutils
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_MODULE:= sensorservice
+
+include $(BUILD_EXECUTABLE)
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/cmds/sensorservice/main_sensorservice.cpp b/services/sensorservice/main_sensorservice.cpp
similarity index 96%
rename from cmds/sensorservice/main_sensorservice.cpp
rename to services/sensorservice/main_sensorservice.cpp
index 8610627..303b65f 100644
--- a/cmds/sensorservice/main_sensorservice.cpp
+++ b/services/sensorservice/main_sensorservice.cpp
@@ -15,7 +15,7 @@
*/
#include <binder/BinderService.h>
-#include <SensorService.h>
+#include "SensorService.h"
using namespace android;
diff --git a/services/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk
index 2ec575e..8dbb9c5 100644
--- a/services/surfaceflinger/Android.mk
+++ b/services/surfaceflinger/Android.mk
@@ -36,7 +36,6 @@
endif
ifeq ($(TARGET_BOARD_PLATFORM),s5pc110)
LOCAL_CFLAGS += -DHAS_CONTEXT_PRIORITY
- LOCAL_CFLAGS += -DNEVER_DEFAULT_TO_ASYNC_MODE
endif
ifeq ($(TARGET_DISABLE_TRIPLE_BUFFERING),true)
@@ -66,6 +65,22 @@
include $(BUILD_SHARED_LIBRARY)
###############################################################
+# build surfaceflinger's executable
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ main_surfaceflinger.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+ libsurfaceflinger \
+ libbinder \
+ libutils
+
+LOCAL_MODULE:= surfaceflinger
+
+include $(BUILD_EXECUTABLE)
+
+###############################################################
# uses jni which may not be available in PDK
ifneq ($(wildcard libnativehelper/include),)
include $(CLEAR_VARS)
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 938459e..bd2f5f3 100644
--- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
@@ -51,7 +51,7 @@
*/
FramebufferSurface::FramebufferSurface(HWComposer& hwc, int disp) :
- ConsumerBase(new BufferQueue(true, new GraphicBufferAlloc())),
+ ConsumerBase(new BufferQueue(new GraphicBufferAlloc())),
mDisplayType(disp),
mCurrentBufferSlot(-1),
mCurrentBuffer(0),
@@ -64,7 +64,6 @@
GRALLOC_USAGE_HW_COMPOSER);
mBufferQueue->setDefaultBufferFormat(mHwc.getFormat(disp));
mBufferQueue->setDefaultBufferSize(mHwc.getWidth(disp), mHwc.getHeight(disp));
- mBufferQueue->setSynchronousMode(true);
mBufferQueue->setDefaultMaxBufferCount(NUM_FRAMEBUFFER_SURFACE_BUFFERS);
}
@@ -72,6 +71,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
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..57cb361 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()),
+ 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,317 @@
}
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, false);
+ 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, false, 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, bool async) {
+ status_t result = mSource[source]->dequeueBuffer(sslot, fence, async,
+ 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, bool async,
+ 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, async);
+ 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;
+ bool async;
+ input.deflate(×tamp, &crop, &scalingMode, &transform,
+ &async, &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::connect(int api, bool producerControlledByApp,
+ QueueBufferOutput* output) {
+ QueueBufferOutput qbo;
+ status_t result = mSource[SOURCE_SINK]->connect(api, producerControlledByApp, &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..dc9655b 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,186 @@
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, bool async,
+ 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 connect(int api, bool producerControlledByApp, 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, bool async);
+ 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 f31d650..52211c2 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -110,12 +110,11 @@
{
// 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);
- mSurfaceFlingerConsumer->setSynchronousMode(true);
mSurfaceFlingerConsumer->setName(mName);
#ifdef TARGET_DISABLE_TRIPLE_BUFFERING
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.h b/services/surfaceflinger/SurfaceFlingerConsumer.h
index d774c33..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 {
diff --git a/services/surfaceflinger/SurfaceTextureLayer.cpp b/services/surfaceflinger/SurfaceTextureLayer.cpp
index d0f0dae..b76dc0c 100644
--- a/services/surfaceflinger/SurfaceTextureLayer.cpp
+++ b/services/surfaceflinger/SurfaceTextureLayer.cpp
@@ -28,7 +28,7 @@
SurfaceTextureLayer::SurfaceTextureLayer(const sp<SurfaceFlinger>& flinger)
- : BufferQueue(true), flinger(flinger) {
+ : BufferQueue(), flinger(flinger) {
}
SurfaceTextureLayer::~SurfaceTextureLayer() {
@@ -51,32 +51,5 @@
flinger->postMessageAsync( new MessageCleanUpList(flinger, this) );
}
-status_t SurfaceTextureLayer::connect(int api, QueueBufferOutput* output) {
- status_t err = BufferQueue::connect(api, output);
- if (err == NO_ERROR) {
- switch(api) {
- case NATIVE_WINDOW_API_MEDIA:
- case NATIVE_WINDOW_API_CAMERA:
- // Camera preview and videos are rate-limited on the producer
- // side. If enabled for this build, we use async mode to always
- // show the most recent frame at the cost of requiring an
- // additional buffer.
-#ifndef NEVER_DEFAULT_TO_ASYNC_MODE
- err = setSynchronousMode(false);
- break;
-#endif
- // fall through to set synchronous mode when not defaulting to
- // async mode.
- default:
- err = setSynchronousMode(true);
- break;
- }
- if (err != NO_ERROR) {
- disconnect(api);
- }
- }
- return err;
-}
-
// ---------------------------------------------------------------------------
}; // namespace android
diff --git a/services/surfaceflinger/SurfaceTextureLayer.h b/services/surfaceflinger/SurfaceTextureLayer.h
index 13cff2f..5f5e4ef 100644
--- a/services/surfaceflinger/SurfaceTextureLayer.h
+++ b/services/surfaceflinger/SurfaceTextureLayer.h
@@ -38,10 +38,6 @@
public:
SurfaceTextureLayer(const sp<SurfaceFlinger>& flinger);
virtual ~SurfaceTextureLayer();
-
- // After calling the superclass connect(), set or clear synchronous
- // mode appropriately for the specified API.
- virtual status_t connect(int api, QueueBufferOutput* output);
};
// ---------------------------------------------------------------------------
diff --git a/cmds/surfaceflinger/main_surfaceflinger.cpp b/services/surfaceflinger/main_surfaceflinger.cpp
similarity index 96%
rename from cmds/surfaceflinger/main_surfaceflinger.cpp
rename to services/surfaceflinger/main_surfaceflinger.cpp
index ce7fde0..8503d4e 100644
--- a/cmds/surfaceflinger/main_surfaceflinger.cpp
+++ b/services/surfaceflinger/main_surfaceflinger.cpp
@@ -15,7 +15,7 @@
*/
#include <binder/BinderService.h>
-#include <SurfaceFlinger.h>
+#include "SurfaceFlinger.h"
using namespace android;