diff options
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. */ |