summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--cmds/dumpstate/dumpstate.c59
-rw-r--r--cmds/dumpstate/dumpstate.h7
-rw-r--r--cmds/dumpstate/utils.c10
-rw-r--r--data/etc/android.hardware.opengles.aep.xml22
-rw-r--r--include/binder/IBatteryStats.h12
-rw-r--r--include/gui/BitTube.h3
-rw-r--r--include/gui/BufferQueueCore.h12
-rw-r--r--include/gui/GLConsumer.h83
-rw-r--r--include/gui/ISensorEventConnection.h1
-rw-r--r--include/gui/ISurfaceComposerClient.h1
-rw-r--r--include/media/hardware/HardwareAPI.h57
-rw-r--r--include/media/openmax/OMX_IVCommon.h7
-rw-r--r--include/ui/GraphicBuffer.h4
-rw-r--r--libs/binder/IBatteryStats.cpp80
-rw-r--r--libs/gui/BitTube.cpp5
-rw-r--r--libs/gui/BufferQueueCore.cpp11
-rw-r--r--libs/gui/BufferQueueProducer.cpp131
-rw-r--r--libs/gui/GLConsumer.cpp324
-rw-r--r--libs/gui/ISensorEventConnection.cpp15
-rw-r--r--libs/gui/Sensor.cpp81
-rw-r--r--libs/gui/SensorEventQueue.cpp10
-rw-r--r--libs/ui/GraphicBuffer.cpp1
-rw-r--r--opengl/libs/Android.mk19
-rw-r--r--opengl/libs/GLES_trace/src/gltrace_fixup.cpp12
-rw-r--r--services/sensorservice/SensorService.cpp335
-rw-r--r--services/sensorservice/SensorService.h51
-rw-r--r--services/surfaceflinger/DisplayHardware/HWComposer.cpp25
-rw-r--r--services/surfaceflinger/DisplayHardware/HWComposer.h3
-rw-r--r--services/surfaceflinger/Layer.cpp29
-rw-r--r--services/surfaceflinger/Layer.h7
-rw-r--r--services/surfaceflinger/SurfaceFlinger.cpp49
-rw-r--r--services/surfaceflinger/SurfaceFlinger.h2
32 files changed, 1038 insertions, 430 deletions
diff --git a/cmds/dumpstate/dumpstate.c b/cmds/dumpstate/dumpstate.c
index 36d11fb..d2f99df 100644
--- a/cmds/dumpstate/dumpstate.c
+++ b/cmds/dumpstate/dumpstate.c
@@ -20,13 +20,13 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <sys/capability.h>
+#include <sys/prctl.h>
#include <sys/resource.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/wait.h>
#include <unistd.h>
-#include <sys/capability.h>
-#include <linux/prctl.h>
#include <cutils/properties.h>
@@ -45,6 +45,36 @@ static char screenshot_path[PATH_MAX] = "";
#define PSTORE_LAST_KMSG "/sys/fs/pstore/console-ramoops"
+#define TOMBSTONE_DIR "/data/tombstones"
+#define TOMBSTONE_FILE_PREFIX TOMBSTONE_DIR "/tombstone_"
+/* Can accomodate a tombstone number up to 9999. */
+#define TOMBSTONE_MAX_LEN (sizeof(TOMBSTONE_FILE_PREFIX) + 4)
+#define NUM_TOMBSTONES 10
+
+typedef struct {
+ char name[TOMBSTONE_MAX_LEN];
+ int fd;
+} tombstone_data_t;
+
+static tombstone_data_t tombstone_data[NUM_TOMBSTONES];
+
+/* Get the fds of any tombstone that was modified in the last half an hour. */
+static void get_tombstone_fds(tombstone_data_t data[NUM_TOMBSTONES]) {
+ time_t thirty_minutes_ago = time(NULL) - 60*30;
+ for (size_t i = 0; i < NUM_TOMBSTONES; i++) {
+ snprintf(data[i].name, sizeof(data[i].name), "%s%02zu", TOMBSTONE_FILE_PREFIX, i);
+ int fd = open(data[i].name, O_RDONLY | O_CLOEXEC | O_NOFOLLOW);
+ struct stat st;
+ if (fstat(fd, &st) == 0 && S_ISREG(st.st_mode) &&
+ (time_t) st.st_mtime >= thirty_minutes_ago) {
+ data[i].fd = fd;
+ } else {
+ close(fd);
+ data[i].fd = -1;
+ }
+ }
+}
+
/* dumps the current system state to stdout */
static void dumpstate() {
time_t now = time(NULL);
@@ -119,7 +149,6 @@ static void dumpstate() {
run_command("EVENT LOG", 20, "logcat", "-b", "events", "-v", "threadtime", "-d", "*:v", NULL);
run_command("RADIO LOG", 20, "logcat", "-b", "radio", "-v", "threadtime", "-d", "*:v", NULL);
-
/* show the traces we collected in main(), if that was done */
if (dump_traces_path != NULL) {
dump_file("VM TRACES JUST NOW", dump_traces_path);
@@ -131,10 +160,13 @@ static void dumpstate() {
property_get("dalvik.vm.stack-trace-file", anr_traces_path, "");
if (!anr_traces_path[0]) {
printf("*** NO VM TRACES FILE DEFINED (dalvik.vm.stack-trace-file)\n\n");
- } else if (stat(anr_traces_path, &st)) {
- printf("*** NO ANR VM TRACES FILE (%s): %s\n\n", anr_traces_path, strerror(errno));
} else {
- dump_file("VM TRACES AT LAST ANR", anr_traces_path);
+ int fd = open(anr_traces_path, O_RDONLY | O_CLOEXEC | O_NOFOLLOW);
+ if (fd < 0) {
+ printf("*** NO ANR VM TRACES FILE (%s): %s\n\n", anr_traces_path, strerror(errno));
+ } else {
+ dump_file_from_fd("VM TRACES AT LAST ANR", anr_traces_path, fd);
+ }
}
/* slow traces for slow operations */
@@ -155,6 +187,18 @@ static void dumpstate() {
}
}
+ int dumped = 0;
+ for (size_t i = 0; i < NUM_TOMBSTONES; i++) {
+ if (tombstone_data[i].fd != -1) {
+ dumped = 1;
+ dump_file_from_fd("TOMBSTONE", tombstone_data[i].name, tombstone_data[i].fd);
+ tombstone_data[i].fd = -1;
+ }
+ }
+ if (!dumped) {
+ printf("*** NO TOMBSTONES to dump in %s\n\n", TOMBSTONE_DIR);
+ }
+
dump_file("NETWORK DEV INFO", "/proc/net/dev");
dump_file("QTAGUID NETWORK INTERFACES INFO", "/proc/net/xt_qtaguid/iface_stat_all");
dump_file("QTAGUID NETWORK INTERFACES INFO (xt)", "/proc/net/xt_qtaguid/iface_stat_fmt");
@@ -411,6 +455,9 @@ int main(int argc, char *argv[]) {
return -1;
}
+ /* Get the tombstone fds here while we are running as root. */
+ get_tombstone_fds(tombstone_data);
+
/* switch to non-root user and group */
gid_t groups[] = { AID_LOG, AID_SDCARD_R, AID_SDCARD_RW,
AID_MOUNT, AID_INET, AID_NET_BW_STATS };
diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h
index 111bda6..53bfff6 100644
--- a/cmds/dumpstate/dumpstate.h
+++ b/cmds/dumpstate/dumpstate.h
@@ -29,7 +29,10 @@ typedef void (for_each_tid_func)(int, int, const char *);
typedef void (for_each_userid_func)(int);
/* prints the contents of a file */
-int dump_file(const char *title, const char* path);
+int dump_file(const char *title, const char *path);
+
+/* prints the contents of the fd */
+int dump_file_from_fd(const char *title, const char *path, int fd);
/* forks a command and waits for it to finish -- terminate args with NULL */
int run_command(const char *title, int timeout_seconds, const char *command, ...);
@@ -71,7 +74,7 @@ void do_dump_settings(int userid);
void dump_route_tables();
/* Play a sound via Stagefright */
-void play_sound(const char* path);
+void play_sound(const char *path);
/* Implemented by libdumpstate_board to dump board-specific info */
void dumpstate_board();
diff --git a/cmds/dumpstate/utils.c b/cmds/dumpstate/utils.c
index 7694adb..a6d9ef6 100644
--- a/cmds/dumpstate/utils.c
+++ b/cmds/dumpstate/utils.c
@@ -249,8 +249,7 @@ void do_showmap(int pid, const char *name) {
}
/* prints the contents of a file */
-int dump_file(const char *title, const char* path) {
- char buffer[32768];
+int dump_file(const char *title, const char *path) {
int fd = open(path, O_RDONLY);
if (fd < 0) {
int err = errno;
@@ -259,6 +258,11 @@ int dump_file(const char *title, const char* path) {
if (title) printf("\n");
return -1;
}
+ return dump_file_from_fd(title, path, fd);
+}
+
+int dump_file_from_fd(const char *title, const char *path, int fd) {
+ char buffer[32768];
if (title) printf("------ %s (%s", title, path);
@@ -282,8 +286,8 @@ int dump_file(const char *title, const char* path) {
}
if (ret <= 0) break;
}
-
close(fd);
+
if (!newline) printf("\n");
if (title) printf("\n");
return 0;
diff --git a/data/etc/android.hardware.opengles.aep.xml b/data/etc/android.hardware.opengles.aep.xml
new file mode 100644
index 0000000..055fa7a
--- /dev/null
+++ b/data/etc/android.hardware.opengles.aep.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 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 is the standard feature indicating that the device supports the
+ Android Extension Pack features. -->
+<permissions>
+ <feature name="android.hardware.opengles.aep" />
+</permissions>
+
diff --git a/include/binder/IBatteryStats.h b/include/binder/IBatteryStats.h
index f4a8aa3..7ddac57 100644
--- a/include/binder/IBatteryStats.h
+++ b/include/binder/IBatteryStats.h
@@ -30,10 +30,22 @@ public:
virtual void noteStartSensor(int uid, int sensor) = 0;
virtual void noteStopSensor(int uid, int sensor) = 0;
+ virtual void noteStartVideo(int uid) = 0;
+ virtual void noteStopVideo(int uid) = 0;
+ virtual void noteStartAudio(int uid) = 0;
+ virtual void noteStopAudio(int uid) = 0;
+ virtual void noteResetVideo() = 0;
+ virtual void noteResetAudio() = 0;
enum {
NOTE_START_SENSOR_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION,
NOTE_STOP_SENSOR_TRANSACTION,
+ NOTE_START_VIDEO_TRANSACTION,
+ NOTE_STOP_VIDEO_TRANSACTION,
+ NOTE_START_AUDIO_TRANSACTION,
+ NOTE_STOP_AUDIO_TRANSACTION,
+ NOTE_RESET_VIDEO_TRANSACTION,
+ NOTE_RESET_AUDIO_TRANSACTION,
};
};
diff --git a/include/gui/BitTube.h b/include/gui/BitTube.h
index d32df84..3ecac52 100644
--- a/include/gui/BitTube.h
+++ b/include/gui/BitTube.h
@@ -48,6 +48,9 @@ public:
// get receive file-descriptor
int getFd() const;
+ // get the send file-descriptor.
+ int getSendFd() const;
+
// send objects (sized blobs). All objects are guaranteed to be written or the call fails.
template <typename T>
static ssize_t sendObjects(const sp<BitTube>& tube,
diff --git a/include/gui/BufferQueueCore.h b/include/gui/BufferQueueCore.h
index cfcb7a5..1050e3b 100644
--- a/include/gui/BufferQueueCore.h
+++ b/include/gui/BufferQueueCore.h
@@ -120,6 +120,9 @@ private:
// in one of the slots.
bool stillTracking(const BufferItem* item) const;
+ // waitWhileAllocatingLocked blocks until mIsAllocating is false.
+ void waitWhileAllocatingLocked() const;
+
// mAllocator is the connection to SurfaceFlinger that is used to allocate
// new GraphicBuffer objects.
sp<IGraphicBufferAlloc> mAllocator;
@@ -234,6 +237,15 @@ private:
// mSidebandStream is a handle to the sideband buffer stream, if any
sp<NativeHandle> mSidebandStream;
+ // mIsAllocating indicates whether a producer is currently trying to allocate buffers (which
+ // releases mMutex while doing the allocation proper). Producers should not modify any of the
+ // FREE slots while this is true. mIsAllocatingCondition is signaled when this value changes to
+ // false.
+ bool mIsAllocating;
+
+ // mIsAllocatingCondition is a condition variable used by producers to wait until mIsAllocating
+ // becomes false.
+ mutable Condition mIsAllocatingCondition;
}; // class BufferQueueCore
} // namespace android
diff --git a/include/gui/GLConsumer.h b/include/gui/GLConsumer.h
index 1aacee9..37530db 100644
--- a/include/gui/GLConsumer.h
+++ b/include/gui/GLConsumer.h
@@ -231,7 +231,7 @@ public:
protected:
// abandonLocked overrides the ConsumerBase method to clear
- // mCurrentTextureBuf in addition to the ConsumerBase behavior.
+ // mCurrentTextureImage in addition to the ConsumerBase behavior.
virtual void abandonLocked();
// dumpLocked overrides the ConsumerBase method to dump GLConsumer-
@@ -262,7 +262,7 @@ protected:
status_t updateAndReleaseLocked(const BufferQueue::BufferItem& item);
// Binds mTexName and the current buffer to mTexTarget. Uses
- // mCurrentTexture if it's set, mCurrentTextureBuf if not. If the
+ // mCurrentTexture if it's set, mCurrentTextureImage if not. If the
// bind succeeds, this calls doGLFenceWait.
status_t bindTextureImageLocked();
@@ -275,11 +275,57 @@ protected:
status_t checkAndUpdateEglStateLocked(bool contextCheck = false);
private:
- // createImage creates a new EGLImage from a GraphicBuffer.
- EGLImageKHR createImage(EGLDisplay dpy,
- const sp<GraphicBuffer>& graphicBuffer, const Rect& crop);
+ // EglImage is a utility class for tracking and creating EGLImageKHRs. There
+ // is primarily just one image per slot, but there is also special cases:
+ // - For releaseTexImage, we use a debug image (mReleasedTexImage)
+ // - After freeBuffer, we must still keep the current image/buffer
+ // Reference counting EGLImages lets us handle all these cases easily while
+ // also only creating new EGLImages from buffers when required.
+ class EglImage : public LightRefBase<EglImage> {
+ public:
+ EglImage(sp<GraphicBuffer> graphicBuffer);
+
+ // createIfNeeded creates an EGLImage if required (we haven't created
+ // one yet, or the EGLDisplay or crop-rect has changed).
+ status_t createIfNeeded(EGLDisplay display, const Rect& cropRect);
+
+ // This calls glEGLImageTargetTexture2DOES to bind the image to the
+ // texture in the specified texture target.
+ void bindToTextureTarget(uint32_t texTarget);
+
+ const sp<GraphicBuffer>& graphicBuffer() { return mGraphicBuffer; }
+ const native_handle* graphicBufferHandle() {
+ return mGraphicBuffer == NULL ? NULL : mGraphicBuffer->handle;
+ }
+
+ private:
+ // Only allow instantiation using ref counting.
+ friend class LightRefBase<EglImage>;
+ virtual ~EglImage();
+
+ // createImage creates a new EGLImage from a GraphicBuffer.
+ EGLImageKHR createImage(EGLDisplay dpy,
+ const sp<GraphicBuffer>& graphicBuffer, const Rect& crop);
+
+ // Disallow copying
+ EglImage(const EglImage& rhs);
+ void operator = (const EglImage& rhs);
+
+ // mGraphicBuffer is the buffer that was used to create this image.
+ sp<GraphicBuffer> mGraphicBuffer;
+
+ // mEglImage is the EGLImage created from mGraphicBuffer.
+ EGLImageKHR mEglImage;
+
+ // mEGLDisplay is the EGLDisplay that was used to create mEglImage.
+ EGLDisplay mEglDisplay;
- // freeBufferLocked frees up the given buffer slot. If the slot has been
+ // mCropRect is the crop rectangle passed to EGL when mEglImage
+ // was created.
+ Rect mCropRect;
+ };
+
+ // freeBufferLocked frees up the given buffer slot. If the slot has been
// initialized this will release the reference to the GraphicBuffer in that
// slot and destroy the EGLImage in that slot. Otherwise it has no effect.
//
@@ -289,7 +335,7 @@ private:
// computeCurrentTransformMatrixLocked computes the transform matrix for the
// current texture. It uses mCurrentTransform and the current GraphicBuffer
// to compute this matrix and stores it in mCurrentTransformMatrix.
- // mCurrentTextureBuf must not be NULL.
+ // mCurrentTextureImage must not be NULL.
void computeCurrentTransformMatrixLocked();
// doGLFenceWaitLocked inserts a wait command into the OpenGL ES command
@@ -303,13 +349,6 @@ private:
// before the outstanding accesses have completed.
status_t syncForReleaseLocked(EGLDisplay dpy);
- // Normally, when we bind a buffer to a texture target, we bind a buffer
- // that is referenced by an entry in mEglSlots. In some situations we
- // have a buffer in mCurrentTextureBuf, but no corresponding entry for
- // it in our slot array. bindUnslottedBuffer handles that situation by
- // binding the buffer without touching the EglSlots.
- status_t bindUnslottedBufferLocked(EGLDisplay dpy);
-
// returns a graphic buffer used when the texture image has been released
static sp<GraphicBuffer> getDebugTexImageBuffer();
@@ -319,10 +358,10 @@ private:
// consume buffers as hardware textures.
static const uint32_t DEFAULT_USAGE_FLAGS = GraphicBuffer::USAGE_HW_TEXTURE;
- // mCurrentTextureBuf is the graphic buffer of the current texture. It's
+ // mCurrentTextureImage is the EglImage/buffer of the current texture. It's
// possible that this buffer is not associated with any buffer slot, so we
// must track it separately in order to support the getCurrentBuffer method.
- sp<GraphicBuffer> mCurrentTextureBuf;
+ sp<EglImage> mCurrentTextureImage;
// mCurrentCrop is the crop rectangle that applies to the current texture.
// It gets set each time updateTexImage is called.
@@ -382,17 +421,10 @@ private:
// EGLSlot contains the information and object references that
// GLConsumer maintains about a BufferQueue buffer slot.
struct EglSlot {
- EglSlot()
- : mEglImage(EGL_NO_IMAGE_KHR),
- mEglFence(EGL_NO_SYNC_KHR) {
- }
+ EglSlot() : mEglFence(EGL_NO_SYNC_KHR) {}
// mEglImage is the EGLImage created from mGraphicBuffer.
- EGLImageKHR mEglImage;
-
- // mCropRect is the crop rectangle passed to EGL when mEglImage was
- // created.
- Rect mCropRect;
+ sp<EglImage> mEglImage;
// mFence is the EGL sync object that must signal before the buffer
// associated with this buffer slot may be dequeued. It is initialized
@@ -444,6 +476,7 @@ private:
// mReleasedTexImageBuffer is a dummy buffer used when in single buffer
// mode and releaseTexImage() has been called
static sp<GraphicBuffer> sReleasedTexImageBuffer;
+ sp<EglImage> mReleasedTexImage;
};
// ----------------------------------------------------------------------------
diff --git a/include/gui/ISensorEventConnection.h b/include/gui/ISensorEventConnection.h
index b296797..f64c6b8 100644
--- a/include/gui/ISensorEventConnection.h
+++ b/include/gui/ISensorEventConnection.h
@@ -40,7 +40,6 @@ public:
nsecs_t maxBatchReportLatencyNs, int reservedFlags) = 0;
virtual status_t setEventRate(int handle, nsecs_t ns) = 0;
virtual status_t flush() = 0;
- virtual void decreaseWakeLockRefCount() = 0;
};
// ----------------------------------------------------------------------------
diff --git a/include/gui/ISurfaceComposerClient.h b/include/gui/ISurfaceComposerClient.h
index 58c1f6a..bb79bd0 100644
--- a/include/gui/ISurfaceComposerClient.h
+++ b/include/gui/ISurfaceComposerClient.h
@@ -47,6 +47,7 @@ public:
eOpaque = 0x00000400,
eProtectedByApp = 0x00000800,
eProtectedByDRM = 0x00001000,
+ eCursorWindow = 0x00002000,
eFXSurfaceNormal = 0x00000000,
eFXSurfaceDim = 0x00020000,
diff --git a/include/media/hardware/HardwareAPI.h b/include/media/hardware/HardwareAPI.h
index de3aeb1..88e7ad3 100644
--- a/include/media/hardware/HardwareAPI.h
+++ b/include/media/hardware/HardwareAPI.h
@@ -157,6 +157,63 @@ struct PrependSPSPPSToIDRFramesParams {
OMX_BOOL bEnable;
};
+// Structure describing a media image (frame)
+// Currently only supporting YUV
+struct MediaImage {
+ enum Type {
+ MEDIA_IMAGE_TYPE_UNKNOWN = 0,
+ MEDIA_IMAGE_TYPE_YUV,
+ };
+
+ enum PlaneIndex {
+ Y = 0,
+ U,
+ V,
+ MAX_NUM_PLANES
+ };
+
+ Type mType;
+ size_t mNumPlanes; // number of planes
+ size_t mWidth; // width of largest plane
+ size_t mHeight; // height of largest plane
+ size_t mBitDepth; // useable bit depth
+ struct PlaneInfo {
+ size_t mOffset; // offset of first pixel of the plane in bytes
+ // from buffer offset
+ size_t mColInc; // column increment in bytes
+ size_t mRowInc; // row increment in bytes
+ size_t mHorizSubsampling; // subsampling compared to the largest plane
+ size_t mVertSubsampling; // subsampling compared to the largest plane
+ };
+ PlaneInfo mPlane[MAX_NUM_PLANES];
+};
+
+// A pointer to this struct is passed to OMX_GetParameter when the extension
+// index for the 'OMX.google.android.index.describeColorFormat'
+// extension is given. This method can be called from any component state
+// other than invalid. The color-format, frame width/height, and stride/
+// slice-height parameters are ones that are associated with a raw video
+// port (input or output), but the stride/slice height parameters may be
+// incorrect. The component shall fill out the MediaImage structure that
+// corresponds to the described raw video format, and the potentially corrected
+// stride and slice-height info.
+//
+// For non-YUV packed planar/semiplanar image formats, the component shall set
+// mNumPlanes to 0, and mType to MEDIA_IMAGE_TYPE_UNKNOWN.
+struct DescribeColorFormatParams {
+ OMX_U32 nSize;
+ OMX_VERSIONTYPE nVersion;
+ // input: parameters from OMX_VIDEO_PORTDEFINITIONTYPE
+ OMX_COLOR_FORMATTYPE eColorFormat;
+ OMX_U32 nFrameWidth;
+ OMX_U32 nFrameHeight;
+ OMX_U32 nStride;
+ OMX_U32 nSliceHeight;
+
+ // output: fill out the MediaImage fields
+ MediaImage sMediaImage;
+};
+
} // namespace android
extern android::OMXPluginBase *createOMXPlugin();
diff --git a/include/media/openmax/OMX_IVCommon.h b/include/media/openmax/OMX_IVCommon.h
index 96a4396..5f9e9b6 100644
--- a/include/media/openmax/OMX_IVCommon.h
+++ b/include/media/openmax/OMX_IVCommon.h
@@ -157,6 +157,13 @@ typedef enum OMX_COLOR_FORMATTYPE {
* an acceptable range once that is done.
* */
OMX_COLOR_FormatAndroidOpaque = 0x7F000789,
+ /** Flexible 8-bit YUV format. Codec should report this format
+ * as being supported if it supports any YUV420 packed planar
+ * or semiplanar formats. When port is set to use this format,
+ * codec can substitute any YUV420 packed planar or semiplanar
+ * format for it. */
+ OMX_COLOR_FormatYUV420Flexible = 0x7F420888,
+
OMX_TI_COLOR_FormatYUV420PackedSemiPlanar = 0x7F000100,
OMX_QCOM_COLOR_FormatYVU420SemiPlanar = 0x7FA30C00,
OMX_QCOM_COLOR_FormatYUV420PackedSemiPlanar64x32Tile2m8ka = 0x7FA30C03,
diff --git a/include/ui/GraphicBuffer.h b/include/ui/GraphicBuffer.h
index ddc4635..7630faa 100644
--- a/include/ui/GraphicBuffer.h
+++ b/include/ui/GraphicBuffer.h
@@ -64,7 +64,9 @@ public:
USAGE_HW_2D = GRALLOC_USAGE_HW_2D,
USAGE_HW_COMPOSER = GRALLOC_USAGE_HW_COMPOSER,
USAGE_HW_VIDEO_ENCODER = GRALLOC_USAGE_HW_VIDEO_ENCODER,
- USAGE_HW_MASK = GRALLOC_USAGE_HW_MASK
+ USAGE_HW_MASK = GRALLOC_USAGE_HW_MASK,
+
+ USAGE_CURSOR = GRALLOC_USAGE_CURSOR,
};
GraphicBuffer();
diff --git a/libs/binder/IBatteryStats.cpp b/libs/binder/IBatteryStats.cpp
index 5702151..8f3b7b4 100644
--- a/libs/binder/IBatteryStats.cpp
+++ b/libs/binder/IBatteryStats.cpp
@@ -49,6 +49,46 @@ public:
data.writeInt32(sensor);
remote()->transact(NOTE_STOP_SENSOR_TRANSACTION, data, &reply);
}
+
+ virtual void noteStartVideo(int uid) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IBatteryStats::getInterfaceDescriptor());
+ data.writeInt32(uid);
+ remote()->transact(NOTE_START_VIDEO_TRANSACTION, data, &reply);
+ }
+
+ virtual void noteStopVideo(int uid) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IBatteryStats::getInterfaceDescriptor());
+ data.writeInt32(uid);
+ remote()->transact(NOTE_STOP_VIDEO_TRANSACTION, data, &reply);
+ }
+
+ virtual void noteStartAudio(int uid) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IBatteryStats::getInterfaceDescriptor());
+ data.writeInt32(uid);
+ remote()->transact(NOTE_START_AUDIO_TRANSACTION, data, &reply);
+ }
+
+ virtual void noteStopAudio(int uid) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IBatteryStats::getInterfaceDescriptor());
+ data.writeInt32(uid);
+ remote()->transact(NOTE_STOP_AUDIO_TRANSACTION, data, &reply);
+ }
+
+ virtual void noteResetVideo() {
+ Parcel data, reply;
+ data.writeInterfaceToken(IBatteryStats::getInterfaceDescriptor());
+ remote()->transact(NOTE_RESET_VIDEO_TRANSACTION, data, &reply);
+ }
+
+ virtual void noteResetAudio() {
+ Parcel data, reply;
+ data.writeInterfaceToken(IBatteryStats::getInterfaceDescriptor());
+ remote()->transact(NOTE_RESET_AUDIO_TRANSACTION, data, &reply);
+ }
};
IMPLEMENT_META_INTERFACE(BatteryStats, "com.android.internal.app.IBatteryStats");
@@ -75,6 +115,46 @@ status_t BnBatteryStats::onTransact(
reply->writeNoException();
return NO_ERROR;
} break;
+ case NOTE_START_VIDEO_TRANSACTION: {
+ CHECK_INTERFACE(IBatteryStats, data, reply);
+ int uid = data.readInt32();
+ noteStartVideo(uid);
+ reply->writeNoException();
+ return NO_ERROR;
+ } break;
+ case NOTE_STOP_VIDEO_TRANSACTION: {
+ CHECK_INTERFACE(IBatteryStats, data, reply);
+ int uid = data.readInt32();
+ noteStopVideo(uid);
+ reply->writeNoException();
+ return NO_ERROR;
+ } break;
+ case NOTE_START_AUDIO_TRANSACTION: {
+ CHECK_INTERFACE(IBatteryStats, data, reply);
+ int uid = data.readInt32();
+ noteStartAudio(uid);
+ reply->writeNoException();
+ return NO_ERROR;
+ } break;
+ case NOTE_STOP_AUDIO_TRANSACTION: {
+ CHECK_INTERFACE(IBatteryStats, data, reply);
+ int uid = data.readInt32();
+ noteStopAudio(uid);
+ reply->writeNoException();
+ return NO_ERROR;
+ } break;
+ case NOTE_RESET_VIDEO_TRANSACTION: {
+ CHECK_INTERFACE(IBatteryStats, data, reply);
+ noteResetVideo();
+ reply->writeNoException();
+ return NO_ERROR;
+ } break;
+ case NOTE_RESET_AUDIO_TRANSACTION: {
+ CHECK_INTERFACE(IBatteryStats, data, reply);
+ noteResetAudio();
+ reply->writeNoException();
+ return NO_ERROR;
+ } break;
default:
return BBinder::onTransact(code, data, reply, flags);
}
diff --git a/libs/gui/BitTube.cpp b/libs/gui/BitTube.cpp
index 0282834..3ed1f37 100644
--- a/libs/gui/BitTube.cpp
+++ b/libs/gui/BitTube.cpp
@@ -99,6 +99,11 @@ int BitTube::getFd() const
return mReceiveFd;
}
+int BitTube::getSendFd() const
+{
+ return mSendFd;
+}
+
ssize_t BitTube::write(void const* vaddr, size_t size)
{
ssize_t err, len;
diff --git a/libs/gui/BufferQueueCore.cpp b/libs/gui/BufferQueueCore.cpp
index 40e6884..ec1e631 100644
--- a/libs/gui/BufferQueueCore.cpp
+++ b/libs/gui/BufferQueueCore.cpp
@@ -64,7 +64,9 @@ BufferQueueCore::BufferQueueCore(const sp<IGraphicBufferAlloc>& allocator) :
mMaxAcquiredBufferCount(1),
mBufferHasBeenQueued(false),
mFrameCounter(0),
- mTransformHint(0)
+ mTransformHint(0),
+ mIsAllocating(false),
+ mIsAllocatingCondition()
{
if (allocator == NULL) {
sp<ISurfaceComposer> composer(ComposerService::getComposerService());
@@ -226,4 +228,11 @@ bool BufferQueueCore::stillTracking(const BufferItem* item) const {
(item->mGraphicBuffer->handle == slot.mGraphicBuffer->handle);
}
+void BufferQueueCore::waitWhileAllocatingLocked() const {
+ ATRACE_CALL();
+ while (mIsAllocating) {
+ mIsAllocatingCondition.wait(mMutex);
+ }
+}
+
} // namespace android
diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp
index 849a12b..cbca3ac 100644
--- a/libs/gui/BufferQueueProducer.cpp
+++ b/libs/gui/BufferQueueProducer.cpp
@@ -74,6 +74,7 @@ status_t BufferQueueProducer::setBufferCount(int bufferCount) {
sp<IConsumerListener> listener;
{ // Autolock scope
Mutex::Autolock lock(mCore->mMutex);
+ mCore->waitWhileAllocatingLocked();
if (mCore->mIsAbandoned) {
BQ_LOGE("setBufferCount: BufferQueue has been abandoned");
@@ -266,6 +267,7 @@ status_t BufferQueueProducer::dequeueBuffer(int *outSlot,
{ // Autolock scope
Mutex::Autolock lock(mCore->mMutex);
+ mCore->waitWhileAllocatingLocked();
if (format == 0) {
format = mCore->mDefaultBufferFormat;
@@ -424,6 +426,7 @@ status_t BufferQueueProducer::detachNextBuffer(sp<GraphicBuffer>* outBuffer,
}
Mutex::Autolock lock(mCore->mMutex);
+ mCore->waitWhileAllocatingLocked();
if (mCore->mIsAbandoned) {
BQ_LOGE("detachNextBuffer: BufferQueue has been abandoned");
@@ -468,6 +471,7 @@ status_t BufferQueueProducer::attachBuffer(int* outSlot,
}
Mutex::Autolock lock(mCore->mMutex);
+ mCore->waitWhileAllocatingLocked();
status_t returnFlags = NO_ERROR;
int found;
@@ -796,6 +800,7 @@ status_t BufferQueueProducer::disconnect(int api) {
sp<IConsumerListener> listener;
{ // Autolock scope
Mutex::Autolock lock(mCore->mMutex);
+ mCore->waitWhileAllocatingLocked();
if (mCore->mIsAbandoned) {
// It's not really an error to disconnect after the surface has
@@ -862,55 +867,101 @@ status_t BufferQueueProducer::setSidebandStream(const sp<NativeHandle>& stream)
void BufferQueueProducer::allocateBuffers(bool async, uint32_t width,
uint32_t height, uint32_t format, uint32_t usage) {
- Vector<int> freeSlots;
+ ATRACE_CALL();
+ while (true) {
+ Vector<int> freeSlots;
+ size_t newBufferCount = 0;
+ uint32_t allocWidth = 0;
+ uint32_t allocHeight = 0;
+ uint32_t allocFormat = 0;
+ uint32_t allocUsage = 0;
+ { // Autolock scope
+ Mutex::Autolock lock(mCore->mMutex);
+ mCore->waitWhileAllocatingLocked();
+
+ int currentBufferCount = 0;
+ for (int slot = 0; slot < BufferQueueDefs::NUM_BUFFER_SLOTS; ++slot) {
+ if (mSlots[slot].mGraphicBuffer != NULL) {
+ ++currentBufferCount;
+ } else {
+ if (mSlots[slot].mBufferState != BufferSlot::FREE) {
+ BQ_LOGE("allocateBuffers: slot %d without buffer is not FREE",
+ slot);
+ continue;
+ }
- Mutex::Autolock lock(mCore->mMutex);
+ freeSlots.push_back(slot);
+ }
+ }
- int currentBufferCount = 0;
- for (int slot = 0; slot < BufferQueueDefs::NUM_BUFFER_SLOTS; ++slot) {
- if (mSlots[slot].mGraphicBuffer != NULL) {
- ++currentBufferCount;
- } else {
- if (mSlots[slot].mBufferState != BufferSlot::FREE) {
- BQ_LOGE("allocateBuffers: slot %d without buffer is not FREE",
- slot);
- continue;
+ int maxBufferCount = mCore->getMaxBufferCountLocked(async);
+ BQ_LOGV("allocateBuffers: allocating from %d buffers up to %d buffers",
+ currentBufferCount, maxBufferCount);
+ if (maxBufferCount <= currentBufferCount)
+ return;
+ newBufferCount = maxBufferCount - currentBufferCount;
+ if (freeSlots.size() < newBufferCount) {
+ BQ_LOGE("allocateBuffers: ran out of free slots");
+ return;
}
+ allocWidth = width > 0 ? width : mCore->mDefaultWidth;
+ allocHeight = height > 0 ? height : mCore->mDefaultHeight;
+ allocFormat = format != 0 ? format : mCore->mDefaultBufferFormat;
+ allocUsage = usage | mCore->mConsumerUsageBits;
- freeSlots.push_front(slot);
- }
- }
+ mCore->mIsAllocating = true;
+ } // Autolock scope
- int maxBufferCount = mCore->getMaxBufferCountLocked(async);
- BQ_LOGV("allocateBuffers: allocating from %d buffers up to %d buffers",
- currentBufferCount, maxBufferCount);
- for (; currentBufferCount < maxBufferCount; ++currentBufferCount) {
- if (freeSlots.empty()) {
- BQ_LOGE("allocateBuffers: ran out of free slots");
- return;
+ Vector<sp<GraphicBuffer> > buffers;
+ for (size_t i = 0; i < newBufferCount; ++i) {
+ status_t result = NO_ERROR;
+ sp<GraphicBuffer> graphicBuffer(mCore->mAllocator->createGraphicBuffer(
+ allocWidth, allocHeight, allocFormat, allocUsage, &result));
+ if (result != NO_ERROR) {
+ BQ_LOGE("allocateBuffers: failed to allocate buffer (%u x %u, format"
+ " %u, usage %u)", width, height, format, usage);
+ Mutex::Autolock lock(mCore->mMutex);
+ mCore->mIsAllocating = false;
+ mCore->mIsAllocatingCondition.broadcast();
+ return;
+ }
+ buffers.push_back(graphicBuffer);
}
- width = width > 0 ? width : mCore->mDefaultWidth;
- height = height > 0 ? height : mCore->mDefaultHeight;
- format = format != 0 ? format : mCore->mDefaultBufferFormat;
- usage |= mCore->mConsumerUsageBits;
+ { // Autolock scope
+ Mutex::Autolock lock(mCore->mMutex);
+ uint32_t checkWidth = width > 0 ? width : mCore->mDefaultWidth;
+ uint32_t checkHeight = height > 0 ? height : mCore->mDefaultHeight;
+ uint32_t checkFormat = format != 0 ? format : mCore->mDefaultBufferFormat;
+ uint32_t checkUsage = usage | mCore->mConsumerUsageBits;
+ if (checkWidth != allocWidth || checkHeight != allocHeight ||
+ checkFormat != allocFormat || checkUsage != allocUsage) {
+ // Something changed while we released the lock. Retry.
+ BQ_LOGV("allocateBuffers: size/format/usage changed while allocating. Retrying.");
+ mCore->mIsAllocating = false;
+ mCore->mIsAllocatingCondition.broadcast();
+ continue;
+ }
- status_t result = NO_ERROR;
- sp<GraphicBuffer> graphicBuffer(mCore->mAllocator->createGraphicBuffer(
- width, height, format, usage, &result));
- if (result != NO_ERROR) {
- BQ_LOGE("allocateBuffers: failed to allocate buffer (%u x %u, format"
- " %u, usage %u)", width, height, format, usage);
- return;
- }
+ for (size_t i = 0; i < newBufferCount; ++i) {
+ int slot = freeSlots[i];
+ if (mSlots[slot].mBufferState != BufferSlot::FREE) {
+ // A consumer allocated the FREE slot with attachBuffer. Discard the buffer we
+ // allocated.
+ BQ_LOGV("allocateBuffers: slot %d was acquired while allocating. "
+ "Dropping allocated buffer.", slot);
+ continue;
+ }
+ mCore->freeBufferLocked(slot); // Clean up the slot first
+ mSlots[slot].mGraphicBuffer = buffers[i];
+ mSlots[slot].mFrameNumber = 0;
+ mSlots[slot].mFence = Fence::NO_FENCE;
+ BQ_LOGV("allocateBuffers: allocated a new buffer in slot %d", slot);
+ }
- int slot = freeSlots[freeSlots.size() - 1];
- mCore->freeBufferLocked(slot); // Clean up the slot first
- mSlots[slot].mGraphicBuffer = graphicBuffer;
- mSlots[slot].mFrameNumber = 0;
- mSlots[slot].mFence = Fence::NO_FENCE;
- BQ_LOGV("allocateBuffers: allocated a new buffer in slot %d", slot);
- freeSlots.pop();
+ mCore->mIsAllocating = false;
+ mCore->mIsAllocatingCondition.broadcast();
+ } // Autolock scope
}
}
diff --git a/libs/gui/GLConsumer.cpp b/libs/gui/GLConsumer.cpp
index 924fc0d..939c4a9 100644
--- a/libs/gui/GLConsumer.cpp
+++ b/libs/gui/GLConsumer.cpp
@@ -279,8 +279,12 @@ status_t GLConsumer::releaseTexImage() {
return err;
}
+ if (mReleasedTexImage == NULL) {
+ mReleasedTexImage = new EglImage(getDebugTexImageBuffer());
+ }
+
mCurrentTexture = BufferQueue::INVALID_BUFFER_SLOT;
- mCurrentTextureBuf = getDebugTexImageBuffer();
+ mCurrentTextureImage = mReleasedTexImage;
mCurrentCrop.makeInvalid();
mCurrentTransform = 0;
mCurrentScalingMode = NATIVE_WINDOW_SCALING_MODE_FREEZE;
@@ -288,9 +292,11 @@ status_t GLConsumer::releaseTexImage() {
mCurrentFence = Fence::NO_FENCE;
if (mAttached) {
- // bind a dummy texture
- glBindTexture(mTexTarget, mTexName);
- bindUnslottedBufferLocked(mEglDisplay);
+ // This binds a dummy buffer (mReleasedTexImage).
+ status_t err = bindTextureImageLocked();
+ if (err != NO_ERROR) {
+ return err;
+ }
} else {
// detached, don't touch the texture (and we may not even have an
// EGLDisplay here.
@@ -332,29 +338,12 @@ status_t GLConsumer::acquireBufferLocked(BufferQueue::BufferItem *item,
return err;
}
- int slot = item->mBuf;
- bool destroyEglImage = false;
-
- if (mEglSlots[slot].mEglImage != EGL_NO_IMAGE_KHR) {
- if (item->mGraphicBuffer != NULL) {
- // This buffer has not been acquired before, so we must assume
- // that any EGLImage in mEglSlots is stale.
- destroyEglImage = true;
- } else if (mEglSlots[slot].mCropRect != item->mCrop) {
- // We've already seen this buffer before, but it now has a
- // different crop rect, so we'll need to recreate the EGLImage if
- // we're using the EGL_ANDROID_image_crop extension.
- destroyEglImage = hasEglAndroidImageCrop();
- }
- }
-
- if (destroyEglImage) {
- if (!eglDestroyImageKHR(mEglDisplay, mEglSlots[slot].mEglImage)) {
- ST_LOGW("acquireBufferLocked: eglDestroyImageKHR failed for slot=%d",
- slot);
- // keep going
- }
- mEglSlots[slot].mEglImage = EGL_NO_IMAGE_KHR;
+ // If item->mGraphicBuffer is not null, this buffer has not been acquired
+ // before, so any prior EglImage created is using a stale buffer. This
+ // replaces any old EglImage with a new one (using the new buffer).
+ if (item->mGraphicBuffer != NULL) {
+ int slot = item->mBuf;
+ mEglSlots[slot].mEglImage = new EglImage(item->mGraphicBuffer);
}
return NO_ERROR;
@@ -395,29 +384,18 @@ status_t GLConsumer::updateAndReleaseLocked(const BufferQueue::BufferItem& item)
return err;
}
- // If the mEglSlot entry is empty, create an EGLImage for the gralloc
- // buffer currently in the slot in ConsumerBase.
- //
+ // Ensure we have a valid EglImageKHR for the slot, creating an EglImage
+ // if nessessary, for the gralloc buffer currently in the slot in
+ // ConsumerBase.
// We may have to do this even when item.mGraphicBuffer == NULL (which
- // means the buffer was previously acquired), if we destroyed the
- // EGLImage when detaching from a context but the buffer has not been
- // re-allocated.
- if (mEglSlots[buf].mEglImage == EGL_NO_IMAGE_KHR) {
- EGLImageKHR image = createImage(mEglDisplay,
- mSlots[buf].mGraphicBuffer, item.mCrop);
- if (image == EGL_NO_IMAGE_KHR) {
- ST_LOGW("updateAndRelease: unable to createImage on display=%p slot=%d",
- mEglDisplay, buf);
- const sp<GraphicBuffer>& gb = mSlots[buf].mGraphicBuffer;
- ST_LOGW("buffer size=%ux%u st=%u usage=0x%x fmt=%d",
- gb->getWidth(), gb->getHeight(), gb->getStride(),
- gb->getUsage(), gb->getPixelFormat());
- releaseBufferLocked(buf, mSlots[buf].mGraphicBuffer,
- mEglDisplay, EGL_NO_SYNC_KHR);
- return UNKNOWN_ERROR;
- }
- mEglSlots[buf].mEglImage = image;
- mEglSlots[buf].mCropRect = item.mCrop;
+ // means the buffer was previously acquired).
+ err = mEglSlots[buf].mEglImage->createIfNeeded(mEglDisplay, item.mCrop);
+ if (err != NO_ERROR) {
+ ST_LOGW("updateAndRelease: unable to createImage on display=%p slot=%d",
+ mEglDisplay, buf);
+ releaseBufferLocked(buf, mSlots[buf].mGraphicBuffer,
+ mEglDisplay, EGL_NO_SYNC_KHR);
+ return UNKNOWN_ERROR;
}
// Do whatever sync ops we need to do before releasing the old slot.
@@ -433,15 +411,15 @@ status_t GLConsumer::updateAndReleaseLocked(const BufferQueue::BufferItem& item)
}
ST_LOGV("updateAndRelease: (slot=%d buf=%p) -> (slot=%d buf=%p)",
- mCurrentTexture,
- mCurrentTextureBuf != NULL ? mCurrentTextureBuf->handle : 0,
+ mCurrentTexture, mCurrentTextureImage != NULL ?
+ mCurrentTextureImage->graphicBufferHandle() : 0,
buf, mSlots[buf].mGraphicBuffer->handle);
// release old buffer
if (mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) {
status_t status = releaseBufferLocked(
- mCurrentTexture, mCurrentTextureBuf, mEglDisplay,
- mEglSlots[mCurrentTexture].mEglFence);
+ mCurrentTexture, mCurrentTextureImage->graphicBuffer(),
+ mEglDisplay, mEglSlots[mCurrentTexture].mEglFence);
if (status < NO_ERROR) {
ST_LOGE("updateAndRelease: failed to release buffer: %s (%d)",
strerror(-status), status);
@@ -452,7 +430,7 @@ status_t GLConsumer::updateAndReleaseLocked(const BufferQueue::BufferItem& item)
// Update the GLConsumer state.
mCurrentTexture = buf;
- mCurrentTextureBuf = mSlots[buf].mGraphicBuffer;
+ mCurrentTextureImage = mEglSlots[buf].mEglImage;
mCurrentCrop = item.mCrop;
mCurrentTransform = item.mTransform;
mCurrentScalingMode = item.mScalingMode;
@@ -477,25 +455,26 @@ status_t GLConsumer::bindTextureImageLocked() {
}
glBindTexture(mTexTarget, mTexName);
- if (mCurrentTexture == BufferQueue::INVALID_BUFFER_SLOT) {
- if (mCurrentTextureBuf == NULL) {
- ST_LOGE("bindTextureImage: no currently-bound texture");
- return NO_INIT;
- }
- status_t err = bindUnslottedBufferLocked(mEglDisplay);
- if (err != NO_ERROR) {
- return err;
- }
- } else {
- EGLImageKHR image = mEglSlots[mCurrentTexture].mEglImage;
+ if (mCurrentTexture == BufferQueue::INVALID_BUFFER_SLOT &&
+ mCurrentTextureImage == NULL) {
+ ST_LOGE("bindTextureImage: no currently-bound texture");
+ return NO_INIT;
+ }
- glEGLImageTargetTexture2DOES(mTexTarget, (GLeglImageOES)image);
+ status_t err = mCurrentTextureImage->createIfNeeded(mEglDisplay,
+ mCurrentCrop);
- while ((error = glGetError()) != GL_NO_ERROR) {
- ST_LOGE("bindTextureImage: error binding external texture image %p"
- ": %#04x", image, error);
- return UNKNOWN_ERROR;
- }
+ if (err != NO_ERROR) {
+ ST_LOGW("bindTextureImage: can't create image on display=%p slot=%d",
+ mEglDisplay, mCurrentTexture);
+ return UNKNOWN_ERROR;
+ }
+
+ mCurrentTextureImage->bindToTextureTarget(mTexTarget);
+
+ while ((error = glGetError()) != GL_NO_ERROR) {
+ ST_LOGE("bindTextureImage: error binding external image: %#04x", error);
+ return UNKNOWN_ERROR;
}
// Wait for the new buffer to be ready.
@@ -537,7 +516,7 @@ void GLConsumer::setReleaseFence(const sp<Fence>& fence) {
if (fence->isValid() &&
mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) {
status_t err = addReleaseFence(mCurrentTexture,
- mCurrentTextureBuf, fence);
+ mCurrentTextureImage->graphicBuffer(), fence);
if (err != OK) {
ST_LOGE("setReleaseFence: failed to add the fence: %s (%d)",
strerror(-err), err);
@@ -583,18 +562,6 @@ status_t GLConsumer::detachFromContext() {
glDeleteTextures(1, &mTexName);
}
- // Because we're giving up the EGLDisplay we need to free all the EGLImages
- // that are associated with it. They'll be recreated when the
- // GLConsumer gets attached to a new OpenGL ES context (and thus gets a
- // new EGLDisplay).
- for (int i =0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) {
- EGLImageKHR img = mEglSlots[i].mEglImage;
- if (img != EGL_NO_IMAGE_KHR) {
- eglDestroyImageKHR(mEglDisplay, img);
- mEglSlots[i].mEglImage = EGL_NO_IMAGE_KHR;
- }
- }
-
mEglDisplay = EGL_NO_DISPLAY;
mEglContext = EGL_NO_CONTEXT;
mAttached = false;
@@ -635,54 +602,23 @@ status_t GLConsumer::attachToContext(uint32_t tex) {
// buffer.
glBindTexture(mTexTarget, GLuint(tex));
- if (mCurrentTextureBuf != NULL) {
- // The EGLImageKHR that was associated with the slot was destroyed when
- // the GLConsumer was detached from the old context, so we need to
- // recreate it here.
- status_t err = bindUnslottedBufferLocked(dpy);
- if (err != NO_ERROR) {
- return err;
- }
- }
-
mEglDisplay = dpy;
mEglContext = ctx;
mTexName = tex;
mAttached = true;
- return OK;
-}
-
-status_t GLConsumer::bindUnslottedBufferLocked(EGLDisplay dpy) {
- ST_LOGV("bindUnslottedBuffer ct=%d ctb=%p",
- mCurrentTexture, mCurrentTextureBuf.get());
-
- // Create a temporary EGLImageKHR.
- Rect crop;
- EGLImageKHR image = createImage(dpy, mCurrentTextureBuf, mCurrentCrop);
- if (image == EGL_NO_IMAGE_KHR) {
- return UNKNOWN_ERROR;
- }
-
- // Attach the current buffer to the GL texture.
- glEGLImageTargetTexture2DOES(mTexTarget, (GLeglImageOES)image);
-
- GLint error;
- status_t err = OK;
- while ((error = glGetError()) != GL_NO_ERROR) {
- ST_LOGE("bindUnslottedBuffer: error binding external texture image %p "
- "(slot %d): %#04x", image, mCurrentTexture, error);
- err = UNKNOWN_ERROR;
+ if (mCurrentTextureImage != NULL) {
+ // This may wait for a buffer a second time. This is likely required if
+ // this is a different context, since otherwise the wait could be skipped
+ // by bouncing through another context. For the same context the extra
+ // wait is redundant.
+ status_t err = bindTextureImageLocked();
+ if (err != NO_ERROR) {
+ return err;
+ }
}
- // We destroy the EGLImageKHR here because the current buffer may no
- // longer be associated with one of the buffer slots, so we have
- // nowhere to to store it. If the buffer is still associated with a
- // slot then another EGLImageKHR will be created next time that buffer
- // gets acquired in updateTexImage.
- eglDestroyImageKHR(dpy, image);
-
- return err;
+ return OK;
}
@@ -708,7 +644,7 @@ status_t GLConsumer::syncForReleaseLocked(EGLDisplay dpy) {
}
sp<Fence> fence(new Fence(fenceFd));
status_t err = addReleaseFenceLocked(mCurrentTexture,
- mCurrentTextureBuf, fence);
+ mCurrentTextureImage->graphicBuffer(), fence);
if (err != OK) {
ST_LOGE("syncForReleaseLocked: error adding release fence: "
"%s (%d)", strerror(-err), err);
@@ -787,11 +723,11 @@ void GLConsumer::setFilteringEnabled(bool enabled) {
bool needsRecompute = mFilteringEnabled != enabled;
mFilteringEnabled = enabled;
- if (needsRecompute && mCurrentTextureBuf==NULL) {
- ST_LOGD("setFilteringEnabled called with mCurrentTextureBuf == NULL");
+ if (needsRecompute && mCurrentTextureImage==NULL) {
+ ST_LOGD("setFilteringEnabled called with mCurrentTextureImage == NULL");
}
- if (needsRecompute && mCurrentTextureBuf != NULL) {
+ if (needsRecompute && mCurrentTextureImage != NULL) {
computeCurrentTransformMatrixLocked();
}
}
@@ -825,10 +761,11 @@ void GLConsumer::computeCurrentTransformMatrixLocked() {
}
}
- sp<GraphicBuffer>& buf(mCurrentTextureBuf);
+ sp<GraphicBuffer> buf = (mCurrentTextureImage == NULL) ?
+ NULL : mCurrentTextureImage->graphicBuffer();
if (buf == NULL) {
- ST_LOGD("computeCurrentTransformMatrixLocked: mCurrentTextureBuf is NULL");
+ ST_LOGD("computeCurrentTransformMatrixLocked: mCurrentTextureImage is NULL");
}
float mtxBeforeFlipV[16];
@@ -911,39 +848,10 @@ nsecs_t GLConsumer::getFrameNumber() {
return mCurrentFrameNumber;
}
-EGLImageKHR GLConsumer::createImage(EGLDisplay dpy,
- const sp<GraphicBuffer>& graphicBuffer, const Rect& crop) {
- EGLClientBuffer cbuf = (EGLClientBuffer)graphicBuffer->getNativeBuffer();
- EGLint attrs[] = {
- EGL_IMAGE_PRESERVED_KHR, EGL_TRUE,
- EGL_IMAGE_CROP_LEFT_ANDROID, crop.left,
- EGL_IMAGE_CROP_TOP_ANDROID, crop.top,
- EGL_IMAGE_CROP_RIGHT_ANDROID, crop.right,
- EGL_IMAGE_CROP_BOTTOM_ANDROID, crop.bottom,
- EGL_NONE,
- };
- if (!crop.isValid()) {
- // No crop rect to set, so terminate the attrib array before the crop.
- attrs[2] = EGL_NONE;
- } else if (!isEglImageCroppable(crop)) {
- // The crop rect is not at the origin, so we can't set the crop on the
- // EGLImage because that's not allowed by the EGL_ANDROID_image_crop
- // extension. In the future we can add a layered extension that
- // removes this restriction if there is hardware that can support it.
- attrs[2] = EGL_NONE;
- }
- EGLImageKHR image = eglCreateImageKHR(dpy, EGL_NO_CONTEXT,
- EGL_NATIVE_BUFFER_ANDROID, cbuf, attrs);
- if (image == EGL_NO_IMAGE_KHR) {
- EGLint error = eglGetError();
- ST_LOGE("error creating EGLImage: %#x", error);
- }
- return image;
-}
-
sp<GraphicBuffer> GLConsumer::getCurrentBuffer() const {
Mutex::Autolock lock(mMutex);
- return mCurrentTextureBuf;
+ return (mCurrentTextureImage == NULL) ?
+ NULL : mCurrentTextureImage->graphicBuffer();
}
Rect GLConsumer::getCurrentCrop() const {
@@ -1067,18 +975,13 @@ void GLConsumer::freeBufferLocked(int slotIndex) {
if (slotIndex == mCurrentTexture) {
mCurrentTexture = BufferQueue::INVALID_BUFFER_SLOT;
}
- EGLImageKHR img = mEglSlots[slotIndex].mEglImage;
- if (img != EGL_NO_IMAGE_KHR) {
- ST_LOGV("destroying EGLImage dpy=%p img=%p", mEglDisplay, img);
- eglDestroyImageKHR(mEglDisplay, img);
- }
- mEglSlots[slotIndex].mEglImage = EGL_NO_IMAGE_KHR;
+ mEglSlots[slotIndex].mEglImage.clear();
ConsumerBase::freeBufferLocked(slotIndex);
}
void GLConsumer::abandonLocked() {
ST_LOGV("abandonLocked");
- mCurrentTextureBuf.clear();
+ mCurrentTextureImage.clear();
ConsumerBase::abandonLocked();
}
@@ -1138,4 +1041,87 @@ static void mtxMul(float out[16], const float a[16], const float b[16]) {
out[15] = a[3]*b[12] + a[7]*b[13] + a[11]*b[14] + a[15]*b[15];
}
+GLConsumer::EglImage::EglImage(sp<GraphicBuffer> graphicBuffer) :
+ mGraphicBuffer(graphicBuffer),
+ mEglImage(EGL_NO_IMAGE_KHR),
+ mEglDisplay(EGL_NO_DISPLAY) {
+}
+
+GLConsumer::EglImage::~EglImage() {
+ if (mEglImage != EGL_NO_IMAGE_KHR) {
+ if (!eglDestroyImageKHR(mEglDisplay, mEglImage)) {
+ ALOGE("~EglImage: eglDestroyImageKHR failed");
+ }
+ }
+}
+
+status_t GLConsumer::EglImage::createIfNeeded(EGLDisplay eglDisplay,
+ const Rect& cropRect) {
+ // If there's an image and it's no longer valid, destroy it.
+ bool haveImage = mEglImage != EGL_NO_IMAGE_KHR;
+ bool displayInvalid = mEglDisplay != eglDisplay;
+ bool cropInvalid = hasEglAndroidImageCrop() && mCropRect != cropRect;
+ if (haveImage && (displayInvalid || cropInvalid)) {
+ if (!eglDestroyImageKHR(mEglDisplay, mEglImage)) {
+ ALOGE("createIfNeeded: eglDestroyImageKHR failed");
+ }
+ mEglImage = EGL_NO_IMAGE_KHR;
+ mEglDisplay = EGL_NO_DISPLAY;
+ }
+
+ // If there's no image, create one.
+ if (mEglImage == EGL_NO_IMAGE_KHR) {
+ mEglDisplay = eglDisplay;
+ mCropRect = cropRect;
+ mEglImage = createImage(mEglDisplay, mGraphicBuffer, mCropRect);
+ }
+
+ // Fail if we can't create a valid image.
+ if (mEglImage == EGL_NO_IMAGE_KHR) {
+ mEglDisplay = EGL_NO_DISPLAY;
+ mCropRect.makeInvalid();
+ const sp<GraphicBuffer>& buffer = mGraphicBuffer;
+ ALOGE("Failed to create image. size=%ux%u st=%u usage=0x%x fmt=%d",
+ buffer->getWidth(), buffer->getHeight(), buffer->getStride(),
+ buffer->getUsage(), buffer->getPixelFormat());
+ return UNKNOWN_ERROR;
+ }
+
+ return OK;
+}
+
+void GLConsumer::EglImage::bindToTextureTarget(uint32_t texTarget) {
+ glEGLImageTargetTexture2DOES(texTarget, (GLeglImageOES)mEglImage);
+}
+
+EGLImageKHR GLConsumer::EglImage::createImage(EGLDisplay dpy,
+ const sp<GraphicBuffer>& graphicBuffer, const Rect& crop) {
+ EGLClientBuffer cbuf = (EGLClientBuffer)graphicBuffer->getNativeBuffer();
+ EGLint attrs[] = {
+ EGL_IMAGE_PRESERVED_KHR, EGL_TRUE,
+ EGL_IMAGE_CROP_LEFT_ANDROID, crop.left,
+ EGL_IMAGE_CROP_TOP_ANDROID, crop.top,
+ EGL_IMAGE_CROP_RIGHT_ANDROID, crop.right,
+ EGL_IMAGE_CROP_BOTTOM_ANDROID, crop.bottom,
+ EGL_NONE,
+ };
+ if (!crop.isValid()) {
+ // No crop rect to set, so terminate the attrib array before the crop.
+ attrs[2] = EGL_NONE;
+ } else if (!isEglImageCroppable(crop)) {
+ // The crop rect is not at the origin, so we can't set the crop on the
+ // EGLImage because that's not allowed by the EGL_ANDROID_image_crop
+ // extension. In the future we can add a layered extension that
+ // removes this restriction if there is hardware that can support it.
+ attrs[2] = EGL_NONE;
+ }
+ EGLImageKHR image = eglCreateImageKHR(dpy, EGL_NO_CONTEXT,
+ EGL_NATIVE_BUFFER_ANDROID, cbuf, attrs);
+ if (image == EGL_NO_IMAGE_KHR) {
+ EGLint error = eglGetError();
+ ALOGE("error creating EGLImage: %#x", error);
+ }
+ return image;
+}
+
}; // namespace android
diff --git a/libs/gui/ISensorEventConnection.cpp b/libs/gui/ISensorEventConnection.cpp
index 8f88141..28fcb53 100644
--- a/libs/gui/ISensorEventConnection.cpp
+++ b/libs/gui/ISensorEventConnection.cpp
@@ -34,8 +34,7 @@ enum {
GET_SENSOR_CHANNEL = IBinder::FIRST_CALL_TRANSACTION,
ENABLE_DISABLE,
SET_EVENT_RATE,
- FLUSH_SENSOR,
- DECREASE_WAKE_LOCK_REFCOUNT
+ FLUSH_SENSOR
};
class BpSensorEventConnection : public BpInterface<ISensorEventConnection>
@@ -84,13 +83,6 @@ public:
remote()->transact(FLUSH_SENSOR, data, &reply);
return reply.readInt32();
}
-
- virtual void decreaseWakeLockRefCount() {
- Parcel data, reply;
- data.writeInterfaceToken(ISensorEventConnection::getInterfaceDescriptor());
- remote()->transact(DECREASE_WAKE_LOCK_REFCOUNT, data, &reply, IBinder::FLAG_ONEWAY);
- return;
- }
};
IMPLEMENT_META_INTERFACE(SensorEventConnection, "android.gui.SensorEventConnection");
@@ -133,11 +125,6 @@ status_t BnSensorEventConnection::onTransact(
reply->writeInt32(result);
return NO_ERROR;
} break;
- case DECREASE_WAKE_LOCK_REFCOUNT: {
- CHECK_INTERFACE(ISensorEventConnection, data, reply);
- decreaseWakeLockRefCount();
- return NO_ERROR;
- } break;
}
return BBinder::onTransact(code, data, reply, flags);
}
diff --git a/libs/gui/Sensor.cpp b/libs/gui/Sensor.cpp
index 2103a95..613b8e2 100644
--- a/libs/gui/Sensor.cpp
+++ b/libs/gui/Sensor.cpp
@@ -166,83 +166,6 @@ Sensor::Sensor(struct sensor_t const* hwSensor, int halVersion)
mStringType = SENSOR_STRING_TYPE_TEMPERATURE;
mFlags |= SENSOR_FLAG_ON_CHANGE_MODE;
break;
- case SENSOR_TYPE_NON_WAKE_UP_PROXIMITY_SENSOR:
- mStringType = SENSOR_STRING_TYPE_NON_WAKE_UP_PROXIMITY_SENSOR;
- mFlags |= SENSOR_FLAG_ON_CHANGE_MODE;
- break;
- case SENSOR_TYPE_WAKE_UP_ACCELEROMETER:
- mStringType = SENSOR_STRING_TYPE_WAKE_UP_ACCELEROMETER;
- mFlags |= (SENSOR_FLAG_CONTINUOUS_MODE | SENSOR_FLAG_WAKE_UP);
- break;
- case SENSOR_TYPE_WAKE_UP_MAGNETIC_FIELD:
- mStringType = SENSOR_STRING_TYPE_WAKE_UP_MAGNETIC_FIELD;
- mFlags |= (SENSOR_FLAG_CONTINUOUS_MODE | SENSOR_FLAG_WAKE_UP);
- break;
- case SENSOR_TYPE_WAKE_UP_ORIENTATION:
- mStringType = SENSOR_STRING_TYPE_WAKE_UP_ORIENTATION;
- mFlags |= (SENSOR_FLAG_CONTINUOUS_MODE | SENSOR_FLAG_WAKE_UP);
- break;
- case SENSOR_TYPE_WAKE_UP_GYROSCOPE:
- mStringType = SENSOR_STRING_TYPE_WAKE_UP_GYROSCOPE;
- mFlags |= (SENSOR_FLAG_CONTINUOUS_MODE | SENSOR_FLAG_WAKE_UP);
- break;
- case SENSOR_TYPE_WAKE_UP_LIGHT:
- mStringType = SENSOR_STRING_TYPE_WAKE_UP_LIGHT;
- mFlags |= (SENSOR_FLAG_ON_CHANGE_MODE | SENSOR_FLAG_WAKE_UP);
- break;
- case SENSOR_TYPE_WAKE_UP_PRESSURE:
- mStringType = SENSOR_STRING_TYPE_WAKE_UP_PRESSURE;
- mFlags |= (SENSOR_FLAG_CONTINUOUS_MODE | SENSOR_FLAG_WAKE_UP);
- break;
- case SENSOR_TYPE_WAKE_UP_GRAVITY:
- mStringType = SENSOR_STRING_TYPE_WAKE_UP_GRAVITY;
- mFlags |= (SENSOR_FLAG_CONTINUOUS_MODE | SENSOR_FLAG_WAKE_UP);
- break;
- case SENSOR_TYPE_WAKE_UP_LINEAR_ACCELERATION:
- mStringType = SENSOR_STRING_TYPE_WAKE_UP_LINEAR_ACCELERATION;
- mFlags |= (SENSOR_FLAG_CONTINUOUS_MODE | SENSOR_FLAG_WAKE_UP);
- break;
- case SENSOR_TYPE_WAKE_UP_ROTATION_VECTOR:
- mStringType = SENSOR_STRING_TYPE_WAKE_UP_ROTATION_VECTOR;
- mFlags |= (SENSOR_FLAG_CONTINUOUS_MODE | SENSOR_FLAG_WAKE_UP);
- break;
- case SENSOR_TYPE_WAKE_UP_RELATIVE_HUMIDITY:
- mStringType = SENSOR_STRING_TYPE_WAKE_UP_RELATIVE_HUMIDITY;
- mFlags |= (SENSOR_FLAG_SPECIAL_REPORTING_MODE | SENSOR_FLAG_WAKE_UP);
- break;
- case SENSOR_TYPE_WAKE_UP_AMBIENT_TEMPERATURE:
- mStringType = SENSOR_STRING_TYPE_WAKE_UP_AMBIENT_TEMPERATURE;
- mFlags |= (SENSOR_FLAG_ON_CHANGE_MODE | SENSOR_FLAG_WAKE_UP);
- break;
- case SENSOR_TYPE_WAKE_UP_MAGNETIC_FIELD_UNCALIBRATED:
- mStringType = SENSOR_STRING_TYPE_WAKE_UP_MAGNETIC_FIELD_UNCALIBRATED;
- mFlags |= (SENSOR_FLAG_CONTINUOUS_MODE | SENSOR_FLAG_WAKE_UP);
- break;
- case SENSOR_TYPE_WAKE_UP_GAME_ROTATION_VECTOR:
- mStringType = SENSOR_STRING_TYPE_WAKE_UP_GAME_ROTATION_VECTOR;
- mFlags |= (SENSOR_FLAG_CONTINUOUS_MODE | SENSOR_FLAG_WAKE_UP);
- break;
- case SENSOR_TYPE_WAKE_UP_GYROSCOPE_UNCALIBRATED:
- mStringType = SENSOR_STRING_TYPE_WAKE_UP_GYROSCOPE_UNCALIBRATED;
- mFlags |= (SENSOR_FLAG_CONTINUOUS_MODE | SENSOR_FLAG_WAKE_UP);
- break;
- case SENSOR_TYPE_WAKE_UP_STEP_DETECTOR:
- mStringType = SENSOR_STRING_TYPE_WAKE_UP_STEP_DETECTOR;
- mFlags |= (SENSOR_FLAG_SPECIAL_REPORTING_MODE | SENSOR_FLAG_WAKE_UP);
- break;
- case SENSOR_TYPE_WAKE_UP_STEP_COUNTER:
- mStringType = SENSOR_STRING_TYPE_WAKE_UP_STEP_COUNTER;
- mFlags |= (SENSOR_FLAG_ON_CHANGE_MODE | SENSOR_FLAG_WAKE_UP);
- break;
- case SENSOR_TYPE_WAKE_UP_GEOMAGNETIC_ROTATION_VECTOR:
- mStringType = SENSOR_STRING_TYPE_WAKE_UP_GEOMAGNETIC_ROTATION_VECTOR;
- mFlags |= (SENSOR_FLAG_CONTINUOUS_MODE | SENSOR_FLAG_WAKE_UP);
- break;
- case SENSOR_TYPE_WAKE_UP_HEART_RATE:
- mStringType = SENSOR_STRING_TYPE_WAKE_UP_HEART_RATE;
- mRequiredPermission = SENSOR_PERMISSION_BODY_SENSORS;
- mFlags |= (SENSOR_FLAG_ON_CHANGE_MODE | SENSOR_FLAG_WAKE_UP);
- break;
case SENSOR_TYPE_WAKE_UP_TILT_DETECTOR:
mStringType = SENSOR_STRING_TYPE_WAKE_UP_TILT_DETECTOR;
mFlags |= (SENSOR_FLAG_SPECIAL_REPORTING_MODE | SENSOR_FLAG_WAKE_UP);
@@ -255,6 +178,10 @@ Sensor::Sensor(struct sensor_t const* hwSensor, int halVersion)
mStringType = SENSOR_STRING_TYPE_GLANCE_GESTURE;
mFlags |= (SENSOR_FLAG_ONE_SHOT_MODE | SENSOR_FLAG_WAKE_UP);
break;
+ case SENSOR_TYPE_PICK_UP_GESTURE:
+ mStringType = SENSOR_STRING_TYPE_PICK_UP_GESTURE;
+ mFlags |= (SENSOR_FLAG_ONE_SHOT_MODE | SENSOR_FLAG_WAKE_UP);
+ break;
default:
// Only pipe the stringType, requiredPermission and flags for custom sensors.
if (halVersion >= SENSORS_DEVICE_API_VERSION_1_2 && hwSensor->stringType) {
diff --git a/libs/gui/SensorEventQueue.cpp b/libs/gui/SensorEventQueue.cpp
index c2eaf4e..842502d 100644
--- a/libs/gui/SensorEventQueue.cpp
+++ b/libs/gui/SensorEventQueue.cpp
@@ -18,6 +18,7 @@
#include <stdint.h>
#include <sys/types.h>
+#include <sys/socket.h>
#include <utils/Errors.h>
#include <utils/RefBase.h>
@@ -147,7 +148,14 @@ status_t SensorEventQueue::setEventRate(Sensor const* sensor, nsecs_t ns) const
void SensorEventQueue::sendAck(const ASensorEvent* events, int count) {
for (int i = 0; i < count; ++i) {
if (events[i].flags & WAKE_UP_SENSOR_EVENT_NEEDS_ACK) {
- mSensorEventConnection->decreaseWakeLockRefCount();
+ // Send just a byte of data to acknowledge for the wake up sensor events
+ // received
+ char buf = '1';
+ ssize_t size = ::send(mSensorChannel->getFd(), &buf, sizeof(buf),
+ MSG_DONTWAIT | MSG_NOSIGNAL);
+ if (size < 0) {
+ ALOGE("sendAck failure %d", size);
+ }
}
}
return;
diff --git a/libs/ui/GraphicBuffer.cpp b/libs/ui/GraphicBuffer.cpp
index e21dc53..9b0bd60 100644
--- a/libs/ui/GraphicBuffer.cpp
+++ b/libs/ui/GraphicBuffer.cpp
@@ -126,6 +126,7 @@ void GraphicBuffer::dumpAllocationsToSystemLog()
ANativeWindowBuffer* GraphicBuffer::getNativeBuffer() const
{
+ LOG_ALWAYS_FATAL_IF(this == NULL, "getNativeBuffer() called on NULL GraphicBuffer");
return static_cast<ANativeWindowBuffer*>(
const_cast<GraphicBuffer*>(this));
}
diff --git a/opengl/libs/Android.mk b/opengl/libs/Android.mk
index 6b90243..cc5d544 100644
--- a/opengl/libs/Android.mk
+++ b/opengl/libs/Android.mk
@@ -112,21 +112,16 @@ LOCAL_CFLAGS += -DLOG_TAG=\"libGLESv2\"
LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
LOCAL_CFLAGS += -fvisibility=hidden
-include $(BUILD_SHARED_LIBRARY)
-
# Symlink libGLESv3.so -> libGLESv2.so
# Platform modules should link against libGLESv2.so (-lGLESv2), but NDK apps
# will be linked against libGLESv3.so.
-LIBGLESV2 := $(LOCAL_INSTALLED_MODULE)
-LIBGLESV3 := $(subst libGLESv2,libGLESv3,$(LIBGLESV2))
-$(LIBGLESV3): $(LIBGLESV2)
- @echo "Symlink: $@ -> $(notdir $<)"
- @mkdir -p $(dir $@)
- $(hide) ln -sf $(notdir $<) $@
-ALL_MODULES.$(LOCAL_MODULE).INSTALLED := \
- $(ALL_MODULES.$(LOCAL_MODULE).INSTALLED) $(LIBGLESV3)
-LIBGLESV2 :=
-LIBGLESV3 :=
+# Note we defer the evaluation of the LOCAL_POST_INSTALL_CMD,
+# so $(LOCAL_INSTALLED_MODULE) will be expanded to correct value,
+# even for both 32-bit and 64-bit installed files in multilib build.
+LOCAL_POST_INSTALL_CMD = \
+ $(hide) ln -sf $(notdir $(LOCAL_INSTALLED_MODULE)) $(dir $(LOCAL_INSTALLED_MODULE))libGLESv3.so
+
+include $(BUILD_SHARED_LIBRARY)
###############################################################################
# Build the ETC1 host static library
diff --git a/opengl/libs/GLES_trace/src/gltrace_fixup.cpp b/opengl/libs/GLES_trace/src/gltrace_fixup.cpp
index 2e7aa20..e6d0062 100644
--- a/opengl/libs/GLES_trace/src/gltrace_fixup.cpp
+++ b/opengl/libs/GLES_trace/src/gltrace_fixup.cpp
@@ -297,14 +297,18 @@ void fixup_glShaderSource(GLMessage *glmsg, void *pointersToFixup[]) {
arg_strpp->add_charvalue(src);
}
-void fixup_glUniformGenericInteger(int argIndex, int nIntegers, GLMessage *glmsg,
+void fixup_glUniformGenericInteger(int argIndex, int nElemsPerVector, GLMessage *glmsg,
void *pointersToFixup[]) {
/* void glUniform?iv(GLint location, GLsizei count, const GLint *value); */
- fixup_GenericIntArray(argIndex, nIntegers, glmsg, pointersToFixup[0]);
+ GLMessage_DataType arg_count = glmsg->args(1);
+ int n_vectors = arg_count.intvalue(0);
+ fixup_GenericIntArray(argIndex, nElemsPerVector * n_vectors, glmsg, pointersToFixup[0]);
}
-void fixup_glUniformGeneric(int argIndex, int nFloats, GLMessage *glmsg, void *src) {
- fixup_GenericFloatArray(argIndex, nFloats, glmsg, src);
+void fixup_glUniformGeneric(int argIndex, int nElemsPerVector, GLMessage *glmsg, void *src) {
+ GLMessage_DataType arg_count = glmsg->args(1);
+ int n_vectors = arg_count.intvalue(0);
+ fixup_GenericFloatArray(argIndex, nElemsPerVector * n_vectors, glmsg, src);
}
void fixup_glUniformMatrixGeneric(int matrixSize, GLMessage *glmsg, void *pointersToFixup[]) {
diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
index 6468017..8fe79d0 100644
--- a/services/sensorservice/SensorService.cpp
+++ b/services/sensorservice/SensorService.cpp
@@ -18,6 +18,7 @@
#include <math.h>
#include <stdint.h>
#include <sys/types.h>
+#include <sys/socket.h>
#include <cutils/properties.h>
@@ -165,6 +166,7 @@ void SensorService::onFirstRef()
mWakeLockAcquired = false;
run("SensorService", PRIORITY_URGENT_DISPLAY);
+ mLooper = new Looper(false);
mInitCheck = NO_ERROR;
}
}
@@ -340,6 +342,8 @@ bool SensorService::threadLoop()
SensorDevice& device(SensorDevice::getInstance());
const size_t vcount = mVirtualSensorList.size();
+ SensorEventAckReceiver sender(this);
+ sender.run("SensorEventAckReceiver", PRIORITY_URGENT_DISPLAY);
ssize_t count;
const int halVersion = device.getHalDeviceVersion();
do {
@@ -348,6 +352,11 @@ bool SensorService::threadLoop()
ALOGE("sensor poll failed (%s)", strerror(-count));
break;
}
+
+ // Reset sensors_event_t.flags to zero for all events in the buffer.
+ for (int i = 0; i < count; i++) {
+ buffer[i].flags = 0;
+ }
Mutex::Autolock _l(mLock);
// Poll has returned. Hold a wakelock if one of the events is from a wake up sensor. The
// rest of this loop is under a critical section protected by mLock. Acquiring a wakeLock,
@@ -443,6 +452,19 @@ bool SensorService::threadLoop()
return false;
}
+sp<Looper> SensorService::getLooper() const {
+ return mLooper;
+}
+
+bool SensorService::SensorEventAckReceiver::threadLoop() {
+ ALOGD("new thread SensorEventAckReceiver");
+ do {
+ sp<Looper> looper = mService->getLooper();
+ looper->pollOnce(-1);
+ } while(!Thread::exitPending());
+ return false;
+}
+
void SensorService::recordLastValueLocked(
const sensors_event_t* buffer, size_t count) {
const sensors_event_t* last = NULL;
@@ -656,6 +678,12 @@ status_t SensorService::enable(const sp<SensorEventConnection>& connection,
err = sensor->activate(connection.get(), true);
}
+ if (err == NO_ERROR && sensor->getSensor().isWakeUpSensor()) {
+ // Add the file descriptor to the Looper for receiving acknowledgments;
+ int ret = mLooper->addFd(connection->getSensorChannel()->getSendFd(), 0,
+ ALOOPER_EVENT_INPUT, connection.get(), NULL);
+ }
+
if (err != NO_ERROR) {
// batch/activate has failed, reset our state.
cleanupWithoutDisableLocked(connection, handle);
@@ -752,9 +780,8 @@ status_t SensorService::flushSensor(const sp<SensorEventConnection>& connection,
bool SensorService::canAccessSensor(const Sensor& sensor) {
- String16 permissionString(sensor.getRequiredPermission());
- return permissionString.size() == 0 ||
- PermissionCache::checkCallingPermission(permissionString);
+ return (sensor.getRequiredPermission().isEmpty()) ||
+ PermissionCache::checkCallingPermission(String16(sensor.getRequiredPermission()));
}
bool SensorService::verifyCanAccessSensor(const Sensor& sensor, const char* operation) {
@@ -797,7 +824,6 @@ void SensorService::checkWakeLockStateLocked() {
}
}
// ---------------------------------------------------------------------------
-
SensorService::SensorRecord::SensorRecord(
const sp<SensorEventConnection>& connection)
{
@@ -828,25 +854,30 @@ bool SensorService::SensorRecord::removeConnection(
SensorService::SensorEventConnection::SensorEventConnection(
const sp<SensorService>& service, uid_t uid)
- : mService(service), mUid(uid), mWakeLockRefCount(0)
-{
+ : mService(service), mUid(uid), mWakeLockRefCount(0), mEventCache(NULL), mCacheSize(0),
+ mMaxCacheSize(0) {
const SensorDevice& device(SensorDevice::getInstance());
if (device.getHalDeviceVersion() >= SENSORS_DEVICE_API_VERSION_1_1) {
- // Increase socket buffer size to 1MB for batching capabilities.
- mChannel = new BitTube(service->mSocketBufferSize);
+ // Increase socket buffer size to a max of 100 KB for batching capabilities.
+ mChannel = new BitTube(mService->mSocketBufferSize);
} else {
mChannel = new BitTube(SOCKET_BUFFER_SIZE_NON_BATCHED);
}
+#if DEBUG_CONNECTIONS
+ mEventsReceived = mEventsSentFromCache = mEventsSent = 0;
+#endif
}
-SensorService::SensorEventConnection::~SensorEventConnection()
-{
+SensorService::SensorEventConnection::~SensorEventConnection() {
ALOGD_IF(DEBUG_CONNECTIONS, "~SensorEventConnection(%p)", this);
+ if (mEventCache != NULL) {
+ delete mEventCache;
+ }
mService->cleanupConnection(this);
}
-void SensorService::SensorEventConnection::onFirstRef()
-{
+void SensorService::SensorEventConnection::onFirstRef() {
+ LooperCallback::onFirstRef();
}
bool SensorService::SensorEventConnection::needsWakeLock() {
@@ -856,15 +887,28 @@ bool SensorService::SensorEventConnection::needsWakeLock() {
void SensorService::SensorEventConnection::dump(String8& result) {
Mutex::Autolock _l(mConnectionLock);
- result.appendFormat("%d WakeLockRefCount\n", mWakeLockRefCount);
+ result.appendFormat("\t %d WakeLockRefCount \n", mWakeLockRefCount);
for (size_t i = 0; i < mSensorInfo.size(); ++i) {
const FlushInfo& flushInfo = mSensorInfo.valueAt(i);
- result.appendFormat("\t %s | status: %s | pending flush events %d | uid %d\n",
+ result.appendFormat("\t %s | status: %s | pending flush events %d | flush calls %d| uid %d|"
+ "cache size: %d max cache size %d\n",
mService->getSensorName(mSensorInfo.keyAt(i)).string(),
flushInfo.mFirstFlushPending ? "First flush pending" :
"active",
flushInfo.mPendingFlushEventsToSend,
- mUid);
+ flushInfo.mNumFlushCalls,
+ mUid,
+ mCacheSize,
+ mMaxCacheSize);
+#if DEBUG_CONNECTIONS
+ result.appendFormat("\t events recvd: %d | sent %d | cache %d | dropped %d\n",
+ mEventsReceived,
+ mEventsSent,
+ mEventsSentFromCache,
+ mEventsReceived - (mEventsSentFromCache +
+ mEventsSent + mCacheSize));
+#endif
+
}
}
@@ -910,8 +954,7 @@ void SensorService::SensorEventConnection::setFirstFlushPending(int32_t handle,
status_t SensorService::SensorEventConnection::sendEvents(
sensors_event_t const* buffer, size_t numEvents,
- sensors_event_t* scratch)
-{
+ sensors_event_t* scratch) {
// filter out events not for this connection
size_t count = 0;
Mutex::Autolock _l(mConnectionLock);
@@ -927,30 +970,127 @@ status_t SensorService::SensorEventConnection::sendEvents(
curr = buffer[i].meta_data.sensor;
}
ssize_t index = mSensorInfo.indexOfKey(curr);
- if (index >= 0 && mSensorInfo[index].mFirstFlushPending == true &&
- buffer[i].type == SENSOR_TYPE_META_DATA) {
- // This is the first flush before activate is called. Events can now be sent for
- // this sensor on this connection.
- ALOGD_IF(DEBUG_CONNECTIONS, "First flush event for sensor==%d ",
- buffer[i].meta_data.sensor);
- mSensorInfo.editValueAt(index).mFirstFlushPending = false;
+ // Check if this connection has registered for this sensor. If not continue to the
+ // next sensor_event.
+ if (index < 0) {
+ ++i;
+ continue;
}
- if (index >= 0 && mSensorInfo[index].mFirstFlushPending == false) {
- do {
- scratch[count++] = buffer[i++];
- } while ((i<numEvents) && ((buffer[i].sensor == curr) ||
- (buffer[i].type == SENSOR_TYPE_META_DATA &&
- buffer[i].meta_data.sensor == curr)));
- } else {
- i++;
+
+ // Check if there is a pending flush_complete event for this sensor on this connection.
+ FlushInfo& flushInfo = mSensorInfo.editValueAt(index);
+ if (buffer[i].type == SENSOR_TYPE_META_DATA) {
+ if (flushInfo.mFirstFlushPending == true) {
+ // This is the first flush before activate is called. Events can now be sent for
+ // this sensor on this connection.
+ ALOGD_IF(DEBUG_CONNECTIONS, "First flush event for sensor==%d ",
+ buffer[i].meta_data.sensor);
+ flushInfo.mFirstFlushPending = false;
+ ++i;
+ continue;
+ }
+ }
+
+ // If there is a pending flush complete event for this sensor on this connection,
+ // ignore the event and proceed to the next.
+ if (flushInfo.mFirstFlushPending) {
+ ++i;
+ continue;
}
+
+ do {
+ if (buffer[i].type == SENSOR_TYPE_META_DATA) {
+ // Send flush complete event only if flush() has been explicitly called by
+ // this app else ignore.
+ if (flushInfo.mNumFlushCalls > 0) {
+ scratch[count++] = buffer[i];
+ flushInfo.mNumFlushCalls--;
+ }
+ ++i;
+ } else {
+ // Regular sensor event, just copy it to the scratch buffer.
+ scratch[count++] = buffer[i++];
+ }
+ } while ((i<numEvents) && ((buffer[i].sensor == curr) ||
+ (buffer[i].type == SENSOR_TYPE_META_DATA &&
+ buffer[i].meta_data.sensor == curr)));
}
} else {
scratch = const_cast<sensors_event_t *>(buffer);
count = numEvents;
}
- // Send pending flush events (if any) before sending events from the cache.
+ // Early return if there are no events for this connection.
+ if (count == 0) {
+ return status_t(NO_ERROR);
+ }
+
+#if DEBUG_CONNECTIONS
+ mEventsReceived += count;
+#endif
+ if (mCacheSize != 0) {
+ // There are some events in the cache which need to be sent first. Copy this buffer to
+ // the end of cache.
+ if (mCacheSize + count <= mMaxCacheSize) {
+ memcpy(&mEventCache[mCacheSize], scratch, count * sizeof(sensors_event_t));
+ mCacheSize += count;
+ } else {
+ // Some events need to be dropped.
+ int remaningCacheSize = mMaxCacheSize - mCacheSize;
+ if (remaningCacheSize != 0) {
+ memcpy(&mEventCache[mCacheSize], scratch,
+ remaningCacheSize * sizeof(sensors_event_t));
+ }
+ int numEventsDropped = count - remaningCacheSize;
+ countFlushCompleteEventsLocked(mEventCache, numEventsDropped);
+ // Drop the first "numEventsDropped" in the cache.
+ memmove(mEventCache, &mEventCache[numEventsDropped],
+ (mCacheSize - numEventsDropped) * sizeof(sensors_event_t));
+
+ // Copy the remainingEvents in scratch buffer to the end of cache.
+ memcpy(&mEventCache[mCacheSize - numEventsDropped], scratch + remaningCacheSize,
+ numEventsDropped * sizeof(sensors_event_t));
+ }
+ return status_t(NO_ERROR);
+ }
+
+ int numWakeUpSensorEvents = countWakeUpSensorEventsLocked(scratch, count);
+ mWakeLockRefCount += numWakeUpSensorEvents;
+
+ // NOTE: ASensorEvent and sensors_event_t are the same type.
+ ssize_t size = SensorEventQueue::write(mChannel,
+ reinterpret_cast<ASensorEvent const*>(scratch), count);
+ if (size < 0) {
+ // Write error, copy events to local cache.
+ mWakeLockRefCount -= numWakeUpSensorEvents;
+ if (mEventCache == NULL) {
+ mMaxCacheSize = computeMaxCacheSizeLocked();
+ mEventCache = new sensors_event_t[mMaxCacheSize];
+ mCacheSize = 0;
+ }
+ memcpy(&mEventCache[mCacheSize], scratch, count * sizeof(sensors_event_t));
+ mCacheSize += count;
+
+ // Add this file descriptor to the looper to get a callback when this fd is available for
+ // writing.
+ mService->getLooper()->addFd(mChannel->getSendFd(), 0,
+ ALOOPER_EVENT_OUTPUT | ALOOPER_EVENT_INPUT, this, NULL);
+ return size;
+ }
+
+#if DEBUG_CONNECTIONS
+ if (size > 0) {
+ mEventsSent += count;
+ }
+#endif
+
+ return size < 0 ? status_t(size) : status_t(NO_ERROR);
+}
+
+void SensorService::SensorEventConnection::writeToSocketFromCacheLocked() {
+ // At a time write at most half the size of the receiver buffer in SensorEventQueue.
+ const int maxWriteSize = SensorEventQueue::MAX_RECEIVE_BUFFER_EVENT_COUNT/2;
+ // Send pending flush events (if any) before sending events from the buffer.
{
ASensorEvent flushCompleteEvent;
flushCompleteEvent.type = SENSOR_TYPE_META_DATA;
@@ -963,35 +1103,44 @@ status_t SensorService::SensorEventConnection::sendEvents(
flushCompleteEvent.meta_data.sensor = mSensorInfo.keyAt(i);
ssize_t size = SensorEventQueue::write(mChannel, &flushCompleteEvent, 1);
if (size < 0) {
- // ALOGW("dropping %d events on the floor", count);
- countFlushCompleteEventsLocked(scratch, count);
- return size;
+ return;
}
ALOGD_IF(DEBUG_CONNECTIONS, "sent dropped flush complete event==%d ",
- flushCompleteEvent.meta_data.sensor);
+ flushCompleteEvent.meta_data.sensor);
flushInfo.mPendingFlushEventsToSend--;
}
}
}
-
- // Early return if there are no events for this connection.
- if (count == 0) {
- return status_t(NO_ERROR);
- }
-
- int numWakeUpSensorEvents = countWakeUpSensorEventsLocked(scratch, count);
- // NOTE: ASensorEvent and sensors_event_t are the same type
- ssize_t size = SensorEventQueue::write(mChannel,
- reinterpret_cast<ASensorEvent const*>(scratch), count);
- if (size == -EAGAIN) {
- // the destination doesn't accept events anymore, it's probably
- // full. For now, we just drop the events on the floor.
- // ALOGW("dropping %d events on the floor", count);
- countFlushCompleteEventsLocked(scratch, count);
- mWakeLockRefCount -= numWakeUpSensorEvents;
- return size;
+ // Write "count" events at a time.
+ for (int numEventsSent = 0; numEventsSent < mCacheSize;) {
+ const int count = (mCacheSize - numEventsSent) < maxWriteSize ?
+ mCacheSize - numEventsSent : maxWriteSize;
+ int numWakeUpSensorEvents =
+ countWakeUpSensorEventsLocked(mEventCache + numEventsSent, count);
+ mWakeLockRefCount += numWakeUpSensorEvents;
+
+ ssize_t size = SensorEventQueue::write(mChannel,
+ reinterpret_cast<ASensorEvent const*>(mEventCache + numEventsSent),
+ count);
+ if (size < 0) {
+ memmove(mEventCache, &mEventCache[numEventsSent],
+ (mCacheSize - numEventsSent) * sizeof(sensors_event_t));
+ ALOGD_IF(DEBUG_CONNECTIONS, "wrote %d events from cache size==%d ",
+ numEventsSent, mCacheSize);
+ mCacheSize -= numEventsSent;
+ mWakeLockRefCount -= numWakeUpSensorEvents;
+ return;
+ }
+ numEventsSent += count;
+#if DEBUG_CONNECTIONS
+ mEventsSentFromCache += count;
+#endif
}
- return size < 0 ? status_t(size) : status_t(NO_ERROR);
+ ALOGD_IF(DEBUG_CONNECTIONS, "wrote all events from cache size=%d ", mCacheSize);
+ // All events from the cache have been sent. Reset cache size to zero.
+ mCacheSize = 0;
+ // Poll only for ALOOPER_EVENT_INPUT(read) on the file descriptor.
+ mService->getLooper()->addFd(mChannel->getSendFd(), 0, ALOOPER_EVENT_INPUT, this, NULL);
}
void SensorService::SensorEventConnection::countFlushCompleteEventsLocked(
@@ -1015,7 +1164,6 @@ int SensorService::SensorEventConnection::countWakeUpSensorEventsLocked(
for (int i = 0; i < count; ++i) {
if (mService->isWakeUpSensorEvent(scratch[i])) {
scratch[i].flags |= WAKE_UP_SENSOR_EVENT_NEEDS_ACK;
- ++mWakeLockRefCount;
return 1;
}
}
@@ -1035,6 +1183,7 @@ status_t SensorService::SensorEventConnection::enableDisable(
if (enabled) {
err = mService->enable(this, handle, samplingPeriodNs, maxBatchReportLatencyNs,
reservedFlags);
+
} else {
err = mService->disable(this, handle);
}
@@ -1055,14 +1204,16 @@ status_t SensorService::SensorEventConnection::flush() {
// Loop through all sensors for this connection and call flush on each of them.
for (size_t i = 0; i < mSensorInfo.size(); ++i) {
const int handle = mSensorInfo.keyAt(i);
+ FlushInfo& flushInfo = mSensorInfo.editValueFor(handle);
if (halVersion < SENSORS_DEVICE_API_VERSION_1_1 || mService->isVirtualSensor(handle)) {
// For older devices just increment pending flush count which will send a trivial
// flush complete event.
- FlushInfo& flushInfo = mSensorInfo.editValueFor(handle);
flushInfo.mPendingFlushEventsToSend++;
} else {
status_t err_flush = mService->flushSensor(this, handle);
- if (err_flush != NO_ERROR) {
+ if (err_flush == NO_ERROR) {
+ flushInfo.mNumFlushCalls++;
+ } else {
ALOGE("Flush error handle=%d %s", handle, strerror(-err_flush));
}
err = (err_flush != NO_ERROR) ? err_flush : err;
@@ -1071,15 +1222,69 @@ status_t SensorService::SensorEventConnection::flush() {
return err;
}
-void SensorService::SensorEventConnection::decreaseWakeLockRefCount() {
- {
- Mutex::Autolock _l(mConnectionLock);
- --mWakeLockRefCount;
+int SensorService::SensorEventConnection::handleEvent(int fd, int events, void* data) {
+ if (events & ALOOPER_EVENT_HANGUP || events & ALOOPER_EVENT_ERROR) {
+ return 0;
}
- // Release the lock before calling checkWakeLockState which also needs the same connectionLock.
- if (mWakeLockRefCount == 0) {
- mService->checkWakeLockState();
+
+ if (events & ALOOPER_EVENT_INPUT) {
+ char buf;
+ ssize_t ret = ::recv(fd, &buf, sizeof(buf), MSG_DONTWAIT);
+
+ {
+ Mutex::Autolock _l(mConnectionLock);
+ --mWakeLockRefCount;
+ }
+ // Check if wakelock can be released by sensorservice. mConnectionLock needs to be released
+ // here as checkWakeLockState() will need it.
+ if (mWakeLockRefCount == 0) {
+ mService->checkWakeLockState();
+ }
+ // continue getting callbacks.
+ return 1;
+ }
+
+ if (events & ALOOPER_EVENT_OUTPUT) {
+ // send sensor data that is stored in mEventCache.
+ Mutex::Autolock _l(mConnectionLock);
+ writeToSocketFromCacheLocked();
}
+ return 1;
+}
+
+int SensorService::SensorEventConnection::computeMaxCacheSizeLocked() const {
+ int fifoWakeUpSensors = 0;
+ int fifoNonWakeUpSensors = 0;
+ for (size_t i = 0; i < mSensorInfo.size(); ++i) {
+ const Sensor& sensor = mService->getSensorFromHandle(mSensorInfo.keyAt(i));
+ if (sensor.getFifoReservedEventCount() == sensor.getFifoMaxEventCount()) {
+ // Each sensor has a reserved fifo. Sum up the fifo sizes for all wake up sensors and
+ // non wake_up sensors.
+ if (sensor.isWakeUpSensor()) {
+ fifoWakeUpSensors += sensor.getFifoReservedEventCount();
+ } else {
+ fifoNonWakeUpSensors += sensor.getFifoReservedEventCount();
+ }
+ } else {
+ // Shared fifo. Compute the max of the fifo sizes for wake_up and non_wake up sensors.
+ if (sensor.isWakeUpSensor()) {
+ fifoWakeUpSensors = fifoWakeUpSensors > sensor.getFifoMaxEventCount() ?
+ fifoWakeUpSensors : sensor.getFifoMaxEventCount();
+
+ } else {
+ fifoNonWakeUpSensors = fifoNonWakeUpSensors > sensor.getFifoMaxEventCount() ?
+ fifoNonWakeUpSensors : sensor.getFifoMaxEventCount();
+
+ }
+ }
+ }
+ if (fifoWakeUpSensors + fifoNonWakeUpSensors == 0) {
+ // It is extremely unlikely that there is a write failure in non batch mode. Return a cache
+ // size of 100.
+ ALOGI("Write failure in non-batch mode");
+ return 100;
+ }
+ return fifoWakeUpSensors + fifoNonWakeUpSensors;
}
// ---------------------------------------------------------------------------
diff --git a/services/sensorservice/SensorService.h b/services/sensorservice/SensorService.h
index 5fd56b8..3cdc825 100644
--- a/services/sensorservice/SensorService.h
+++ b/services/sensorservice/SensorService.h
@@ -24,7 +24,9 @@
#include <utils/SortedVector.h>
#include <utils/KeyedVector.h>
#include <utils/threads.h>
+#include <utils/AndroidThreads.h>
#include <utils/RefBase.h>
+#include <utils/Looper.h>
#include <binder/BinderService.h>
@@ -38,10 +40,11 @@
// ---------------------------------------------------------------------------
#define DEBUG_CONNECTIONS false
-// Max size is 1 MB which is enough to accept a batch of about 10k events.
-#define MAX_SOCKET_BUFFER_SIZE_BATCHED 1024 * 1024
+// Max size is 100 KB which is enough to accept a batch of about 1000 events.
+#define MAX_SOCKET_BUFFER_SIZE_BATCHED 100 * 1024
+// For older HALs which don't support batching, use a smaller socket buffer size.
#define SOCKET_BUFFER_SIZE_NON_BATCHED 4 * 1024
-#define WAKE_UP_SENSOR_EVENT_NEEDS_ACK (1 << 31)
+#define WAKE_UP_SENSOR_EVENT_NEEDS_ACK (1U << 31)
struct sensors_poll_device_t;
struct sensors_module_t;
@@ -72,7 +75,8 @@ class SensorService :
virtual sp<ISensorEventConnection> createSensorEventConnection();
virtual status_t dump(int fd, const Vector<String16>& args);
- class SensorEventConnection : public BnSensorEventConnection {
+ class SensorEventConnection : public BnSensorEventConnection, public LooperCallback {
+ friend class SensorService;
virtual ~SensorEventConnection();
virtual void onFirstRef();
virtual sp<BitTube> getSensorChannel() const;
@@ -80,7 +84,6 @@ class SensorService :
nsecs_t maxBatchReportLatencyNs, int reservedFlags);
virtual status_t setEventRate(int handle, nsecs_t samplingPeriodNs);
virtual status_t flush();
- void decreaseWakeLockRefCount();
// Count the number of flush complete events which are about to be dropped in the buffer.
// Increment mPendingFlushEventsToSend in mSensorInfo. These flush complete events will be
// sent separately before the next batch of events.
@@ -90,7 +93,20 @@ class SensorService :
// Increment it by exactly one unit for each packet sent on the socket. SOCK_SEQPACKET for
// the socket ensures that either the entire packet is read or dropped.
// Return 1 if mWakeLockRefCount has been incremented, zero if not.
- int countWakeUpSensorEventsLocked(sensors_event_t* scratch, const int count);
+ int countWakeUpSensorEventsLocked(sensors_event_t* scratch, int count);
+
+ // Writes events from mEventCache to the socket.
+ void writeToSocketFromCacheLocked();
+
+ // Compute the approximate cache size from the FIFO sizes of various sensors registered for
+ // this connection. Wake up and non-wake up sensors have separate FIFOs but FIFO may be
+ // shared amongst wake-up sensors and non-wake up sensors.
+ int computeMaxCacheSizeLocked() const;
+
+ // LooperCallback method. If there is data to read on this fd, it is an ack from the
+ // app that it has read events from a wake up sensor, decrement mWakeLockRefCount.
+ // If this fd is available for writing send the data from the cache.
+ virtual int handleEvent(int fd, int events, void* data);
sp<SensorService> const mService;
sp<BitTube> mChannel;
@@ -108,10 +124,20 @@ class SensorService :
// Every activate is preceded by a flush. Only after the first flush complete is
// received, the events for the sensor are sent on that *connection*.
bool mFirstFlushPending;
- FlushInfo() : mPendingFlushEventsToSend(0), mFirstFlushPending(false) {}
+ // Number of time flush() was called on this connection. This is incremented every time
+ // flush() is called and decremented when flush_complete_event is received.
+ int mNumFlushCalls;
+ FlushInfo() : mPendingFlushEventsToSend(0), mFirstFlushPending(false),
+ mNumFlushCalls(0) {}
};
// protected by SensorService::mLock. Key for this vector is the sensor handle.
KeyedVector<int, FlushInfo> mSensorInfo;
+ sensors_event_t *mEventCache;
+ int mCacheSize, mMaxCacheSize;
+
+#if DEBUG_CONNECTIONS
+ int mEventsReceived, mEventsSent, mEventsSentFromCache;
+#endif
public:
SensorEventConnection(const sp<SensorService>& service, uid_t uid);
@@ -138,6 +164,13 @@ class SensorService :
size_t getNumConnections() const { return mConnections.size(); }
};
+ class SensorEventAckReceiver : public Thread {
+ sp<SensorService> const mService;
+ public:
+ virtual bool threadLoop();
+ SensorEventAckReceiver(const sp<SensorService>& service): mService(service) {}
+ };
+
String8 getSensorName(int handle) const;
bool isVirtualSensor(int handle) const;
Sensor getSensorFromHandle(int handle) const;
@@ -160,6 +193,9 @@ class SensorService :
void checkWakeLockState();
void checkWakeLockStateLocked();
bool isWakeUpSensorEvent(const sensors_event_t& event) const;
+
+ sp<Looper> getLooper() const;
+
// constants
Vector<Sensor> mSensorList;
Vector<Sensor> mUserSensorListDebug;
@@ -168,6 +204,7 @@ class SensorService :
Vector<SensorInterface *> mVirtualSensorList;
status_t mInitCheck;
size_t mSocketBufferSize;
+ sp<Looper> mLooper;
// protected by mLock
mutable Mutex mLock;
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 185dab2..a8fb5bd 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -681,6 +681,9 @@ status_t HWComposer::prepare() {
if (l.compositionType == HWC_OVERLAY) {
disp.hasOvComp = true;
}
+ if (l.compositionType == HWC_CURSOR_OVERLAY) {
+ disp.hasOvComp = true;
+ }
}
if (disp.list->numHwLayers == (disp.framebufferTarget ? 1 : 0)) {
disp.hasFbComp = true;
@@ -853,6 +856,16 @@ sp<Fence> HWComposer::getLastRetireFence(int32_t id) const {
return mDisplayData[id].lastRetireFence;
}
+status_t HWComposer::setCursorPositionAsync(int32_t id, const Rect& pos)
+{
+ if (mHwc->setCursorPositionAsync) {
+ return (status_t)mHwc->setCursorPositionAsync(mHwc, id, pos.left, pos.top);
+ }
+ else {
+ return NO_ERROR;
+ }
+}
+
/*
* Helper template to implement a concrete HWCLayer
* This holds the pointer to the concrete hwc layer type
@@ -935,6 +948,16 @@ public:
getLayer()->flags &= ~HWC_SKIP_LAYER;
}
}
+ virtual void setIsCursorLayerHint(bool isCursor) {
+ if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_4)) {
+ if (isCursor) {
+ getLayer()->flags |= HWC_IS_CURSOR_LAYER;
+ }
+ else {
+ getLayer()->flags &= ~HWC_IS_CURSOR_LAYER;
+ }
+ }
+ }
virtual void setBlending(uint32_t blending) {
getLayer()->blending = blending;
}
@@ -1122,6 +1145,8 @@ void HWComposer::dump(String8& result) const {
"HWC",
"BKGND",
"FB TARGET",
+ "SIDEBAND",
+ "HWC_CURSOR",
"UNKNOWN"};
if (type >= NELEM(compositionTypeName))
type = NELEM(compositionTypeName) - 1;
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index c62b924..9bd99eb 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -141,6 +141,8 @@ public:
// displays, writes to the output buffer are complete.
sp<Fence> getLastRetireFence(int32_t id) const;
+ status_t setCursorPositionAsync(int32_t id, const Rect &pos);
+
/*
* Interface to hardware composer's layers functionality.
* This abstracts the HAL interface to layers which can evolve in
@@ -157,6 +159,7 @@ public:
virtual sp<Fence> getAndResetReleaseFence() = 0;
virtual void setDefaultState() = 0;
virtual void setSkip(bool skip) = 0;
+ virtual void setIsCursorLayerHint(bool isCursor = true) = 0;
virtual void setBlending(uint32_t blending) = 0;
virtual void setTransform(uint32_t transform) = 0;
virtual void setFrame(const Rect& frame) = 0;
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 4861e34..bbb5cfe 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -79,7 +79,8 @@ Layer::Layer(SurfaceFlinger* flinger, const sp<Client>& client,
mSecure(false),
mProtectedByApp(false),
mHasSurface(false),
- mClientRef(client)
+ mClientRef(client),
+ mPotentialCursor(false)
{
mCurrentCrop.makeInvalid();
mFlinger->getRenderEngine().genTextures(1, &mTextureName);
@@ -200,6 +201,7 @@ status_t Layer::setBuffers( uint32_t w, uint32_t h,
mFormat = format;
+ mPotentialCursor = (flags & ISurfaceComposerClient::eCursorWindow) ? true : false;
mSecure = (flags & ISurfaceComposerClient::eSecure) ? true : false;
mProtectedByApp = (flags & ISurfaceComposerClient::eProtectedByApp) ? true : false;
mCurrentOpacity = getOpacityForFormat(format);
@@ -441,7 +443,7 @@ void Layer::setAcquireFence(const sp<const DisplayDevice>& /* hw */,
// TODO: there is a possible optimization here: we only need to set the
// acquire fence the first time a new buffer is acquired on EACH display.
- if (layer.getCompositionType() == HWC_OVERLAY) {
+ if (layer.getCompositionType() == HWC_OVERLAY || layer.getCompositionType() == HWC_CURSOR_OVERLAY) {
sp<Fence> fence = mSurfaceFlingerConsumer->getCurrentFence();
if (fence->isValid()) {
fenceFd = fence->dup();
@@ -453,6 +455,26 @@ void Layer::setAcquireFence(const sp<const DisplayDevice>& /* hw */,
layer.setAcquireFenceFd(fenceFd);
}
+Rect Layer::getPosition(
+ const sp<const DisplayDevice>& hw)
+{
+ // this gives us only the "orientation" component of the transform
+ const State& s(getCurrentState());
+
+ // apply the layer's transform, followed by the display's global transform
+ // here we're guaranteed that the layer's transform preserves rects
+ Rect win(s.active.w, s.active.h);
+ if (!s.active.crop.isEmpty()) {
+ win.intersect(s.active.crop, &win);
+ }
+ // subtract the transparent region and snap to the bounds
+ Rect bounds = reduce(win, s.activeTransparentRegion);
+ Rect frame(s.transform.transform(bounds));
+ frame.intersect(hw->getViewport(), &frame);
+ const Transform& tr(hw->getTransform());
+ return Rect(tr.transform(frame));
+}
+
// ---------------------------------------------------------------------------
// drawing...
// ---------------------------------------------------------------------------
@@ -1187,6 +1209,9 @@ uint32_t Layer::getEffectiveUsage(uint32_t usage) const
// need a hardware-protected path to external video sink
usage |= GraphicBuffer::USAGE_PROTECTED;
}
+ if (mPotentialCursor) {
+ usage |= GraphicBuffer::USAGE_CURSOR;
+ }
usage |= GraphicBuffer::USAGE_HW_COMPOSER;
return usage;
}
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 2d8084d..e21dd36 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -201,6 +201,8 @@ public:
void setAcquireFence(const sp<const DisplayDevice>& hw,
HWComposer::HWCLayerInterface& layer);
+ Rect getPosition(const sp<const DisplayDevice>& hw);
+
/*
* called after page-flip
*/
@@ -260,6 +262,8 @@ public:
*/
Region latchBuffer(bool& recomputeVisibleRegions);
+ bool isPotentialCursor() const { return mPotentialCursor;}
+
/*
* called with the state lock when the surface is removed from the
* current list
@@ -391,6 +395,9 @@ private:
// Set to true once we've returned this surface's handle
mutable bool mHasSurface;
const wp<Client> mClientRef;
+
+ // This layer can be a cursor on some displays.
+ bool mPotentialCursor;
};
// ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index aeba720..53b0dc4 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -990,6 +990,26 @@ void SurfaceFlinger::setUpHWComposer() {
}
}
+ // If possible, attempt to use the cursor overlay on each display.
+ for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
+ sp<const DisplayDevice> hw(mDisplays[dpy]);
+ const int32_t id = hw->getHwcDisplayId();
+ if (id >= 0) {
+ const Vector< sp<Layer> >& currentLayers(
+ hw->getVisibleLayersSortedByZ());
+ const size_t count = currentLayers.size();
+ HWComposer::LayerListIterator cur = hwc.begin(id);
+ const HWComposer::LayerListIterator end = hwc.end(id);
+ for (size_t i=0 ; cur!=end && i<count ; ++i, ++cur) {
+ const sp<Layer>& layer(currentLayers[i]);
+ if (layer->isPotentialCursor()) {
+ cur->setIsCursorLayerHint();
+ break;
+ }
+ }
+ }
+ }
+
status_t err = hwc.prepare();
ALOGE_IF(err, "HWComposer::prepare failed (%s)", strerror(-err));
@@ -1364,6 +1384,34 @@ void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags)
}
commitTransaction();
+
+ updateCursorAsync();
+}
+
+void SurfaceFlinger::updateCursorAsync()
+{
+ HWComposer& hwc(getHwComposer());
+ for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
+ sp<const DisplayDevice> hw(mDisplays[dpy]);
+ const int32_t id = hw->getHwcDisplayId();
+ if (id < 0) {
+ continue;
+ }
+ const Vector< sp<Layer> >& currentLayers(
+ hw->getVisibleLayersSortedByZ());
+ const size_t count = currentLayers.size();
+ HWComposer::LayerListIterator cur = hwc.begin(id);
+ const HWComposer::LayerListIterator end = hwc.end(id);
+ for (size_t i=0 ; cur!=end && i<count ; ++i, ++cur) {
+ if (cur->getCompositionType() != HWC_CURSOR_OVERLAY) {
+ continue;
+ }
+ const sp<Layer>& layer(currentLayers[i]);
+ Rect cursorPos = layer->getPosition(hw);
+ hwc.setCursorPositionAsync(id, cursorPos);
+ break;
+ }
+ }
}
void SurfaceFlinger::commitTransaction()
@@ -1695,6 +1743,7 @@ void SurfaceFlinger::doComposeSurfaces(const sp<const DisplayDevice>& hw, const
const Region clip(dirty.intersect(tr.transform(layer->visibleRegion)));
if (!clip.isEmpty()) {
switch (cur->getCompositionType()) {
+ case HWC_CURSOR_OVERLAY:
case HWC_OVERLAY: {
const Layer::State& state(layer->getDrawingState());
if ((cur->getHints() & HWC_HINT_CLEAR_FB)
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 996a795..476e549 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -249,6 +249,8 @@ private:
void handleTransaction(uint32_t transactionFlags);
void handleTransactionLocked(uint32_t transactionFlags);
+ void updateCursorAsync();
+
/* handlePageFilp: this is were we latch a new buffer
* if available and compute the dirty region.
*/