diff options
47 files changed, 444 insertions, 169 deletions
diff --git a/cmds/atrace/atrace.cpp b/cmds/atrace/atrace.cpp index 9e5c910..f0a52d8 100644 --- a/cmds/atrace/atrace.cpp +++ b/cmds/atrace/atrace.cpp @@ -77,7 +77,7 @@ static const TracingCategory k_categories[] = { { "webview", "WebView", ATRACE_TAG_WEBVIEW, { } }, { "wm", "Window Manager", ATRACE_TAG_WINDOW_MANAGER, { } }, { "am", "Activity Manager", ATRACE_TAG_ACTIVITY_MANAGER, { } }, - { "sync", "Sync Manager", ATRACE_TAG_SYNC_MANAGER, { } }, + { "sm", "Sync Manager", ATRACE_TAG_SYNC_MANAGER, { } }, { "audio", "Audio", ATRACE_TAG_AUDIO, { } }, { "video", "Video", ATRACE_TAG_VIDEO, { } }, { "camera", "Camera", ATRACE_TAG_CAMERA, { } }, diff --git a/cmds/dumpstate/dumpstate.c b/cmds/dumpstate/dumpstate.c index 1fbcef6..f9942e9 100644 --- a/cmds/dumpstate/dumpstate.c +++ b/cmds/dumpstate/dumpstate.c @@ -14,6 +14,7 @@ * limitations under the License. */ +#include <dirent.h> #include <errno.h> #include <fcntl.h> #include <limits.h> @@ -75,6 +76,28 @@ static void get_tombstone_fds(tombstone_data_t data[NUM_TOMBSTONES]) { } } +static void dump_dev_files(const char *title, const char *driverpath, const char *filename) +{ + DIR *d; + struct dirent *de; + char path[PATH_MAX]; + + d = opendir(driverpath); + if (d == NULL) { + return; + } + + while ((de = readdir(d))) { + if (de->d_type != DT_LNK) { + continue; + } + snprintf(path, sizeof(path), "%s/%s/%s", driverpath, de->d_name, filename); + dump_file(title, path); + } + + closedir(d); +} + /* dumps the current system state to stdout */ static void dumpstate() { time_t now = time(NULL); @@ -107,7 +130,9 @@ static void dumpstate() { printf("Command line: %s\n", strtok(cmdline_buf, "\n")); printf("\n"); + dump_dev_files("TRUSTY VERSION", "/sys/bus/platform/drivers/trusty", "trusty_version"); run_command("UPTIME", 10, "uptime", NULL); + dump_file("MMC PERF", "/sys/block/mmcblk0/stat"); dump_file("MEMORY INFO", "/proc/meminfo"); run_command("CPU INFO", 10, "top", "-n", "1", "-d", "1", "-m", "30", "-t", NULL); run_command("PROCRANK", 20, "procrank", NULL); diff --git a/cmds/installd/commands.c b/cmds/installd/commands.c index 5cd2593..344a5a3 100644 --- a/cmds/installd/commands.c +++ b/cmds/installd/commands.c @@ -20,6 +20,7 @@ #include <cutils/sched_policy.h> #include <diskusage/dirsize.h> #include <selinux/android.h> +#include <system/thread_defs.h> /* Directory records that are used in execution of commands. */ dir_rec_t android_data_dir; @@ -1029,6 +1030,10 @@ int dexopt(const char *apk_path, uid_t uid, bool is_public, ALOGE("set_sched_policy failed: %s\n", strerror(errno)); exit(70); } + if (setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_BACKGROUND) < 0) { + ALOGE("setpriority failed: %s\n", strerror(errno)); + exit(71); + } if (flock(out_fd, LOCK_EX | LOCK_NB) != 0) { ALOGE("flock(%s) failed: %s\n", out_path, strerror(errno)); exit(67); @@ -1076,6 +1081,21 @@ fail: return -1; } +int mark_boot_complete(const char* instruction_set) +{ + char boot_marker_path[PKG_PATH_MAX]; + sprintf(boot_marker_path,"%s%s/.booting", DALVIK_CACHE_PREFIX, instruction_set); + + ALOGV("mark_boot_complete : %s", boot_marker_path); + if (unlink(boot_marker_path) != 0) { + ALOGE("Unable to unlink boot marker at %s, error=%s", boot_marker_path, + strerror(errno)); + return -1; + } + + return 0; +} + void mkinnerdirs(char* path, int basepos, mode_t mode, int uid, int gid, struct stat* statbuf) { diff --git a/cmds/installd/installd.c b/cmds/installd/installd.c index 4864516..86f7468 100644 --- a/cmds/installd/installd.c +++ b/cmds/installd/installd.c @@ -42,6 +42,11 @@ static int do_dexopt(char **arg, char reply[REPLY_MAX] __unused) return dexopt(arg[0], atoi(arg[1]), atoi(arg[2]), arg[3], arg[4], atoi(arg[5]), 0); } +static int do_mark_boot_complete(char **arg, char reply[REPLY_MAX] __unused) +{ + return mark_boot_complete(arg[0] /* instruction set */); +} + static int do_move_dex(char **arg, char reply[REPLY_MAX] __unused) { return move_dex(arg[0], arg[1], arg[2]); /* src, dst, instruction_set */ @@ -160,6 +165,7 @@ struct cmdinfo cmds[] = { { "ping", 0, do_ping }, { "install", 4, do_install }, { "dexopt", 6, do_dexopt }, + { "markbootcomplete", 1, do_mark_boot_complete }, { "movedex", 3, do_move_dex }, { "rmdex", 2, do_rm_dex }, { "remove", 2, do_remove }, diff --git a/cmds/installd/installd.h b/cmds/installd/installd.h index 36c3e8c..a3a5c16 100644 --- a/cmds/installd/installd.h +++ b/cmds/installd/installd.h @@ -221,6 +221,7 @@ int get_size(const char *pkgname, userid_t userid, const char *apkpath, const ch int free_cache(int64_t free_size); int dexopt(const char *apk_path, uid_t uid, bool is_public, const char *pkgName, const char *instruction_set, bool vm_safe_mode, bool should_relocate); +int mark_boot_complete(const char *instruction_set); int movefiles(); int linklib(const char* target, const char* source, int userId); int idmap(const char *target_path, const char *overlay_path, uid_t uid); diff --git a/include/binder/Parcel.h b/include/binder/Parcel.h index 2ee99f8..6a69761 100644 --- a/include/binder/Parcel.h +++ b/include/binder/Parcel.h @@ -205,7 +205,11 @@ public: // Explicitly close all file descriptors in the parcel. void closeFileDescriptors(); - + + // Debugging: get metrics on current allocations. + static size_t getGlobalAllocSize(); + static size_t getGlobalAllocCount(); + private: typedef void (*release_func)(Parcel* parcel, const uint8_t* data, size_t dataSize, diff --git a/include/gui/BufferItem.h b/include/gui/BufferItem.h index 5effd10..01b6ff4 100644 --- a/include/gui/BufferItem.h +++ b/include/gui/BufferItem.h @@ -44,6 +44,7 @@ class BufferItem : public Flattenable<BufferItem> { // The default value of mBuf, used to indicate this doesn't correspond to a slot. enum { INVALID_BUFFER_SLOT = -1 }; BufferItem(); + ~BufferItem(); operator IGraphicBufferConsumer::BufferItem() const; static const char* scalingModeName(uint32_t scalingMode); diff --git a/include/gui/BufferQueue.h b/include/gui/BufferQueue.h index 3297b10..1188837 100644 --- a/include/gui/BufferQueue.h +++ b/include/gui/BufferQueue.h @@ -62,7 +62,7 @@ public: public: ProxyConsumerListener(const wp<ConsumerListener>& consumerListener); virtual ~ProxyConsumerListener(); - virtual void onFrameAvailable(); + virtual void onFrameAvailable(const android::BufferItem& item); virtual void onBuffersReleased(); virtual void onSidebandStreamChanged(); private: diff --git a/include/gui/BufferQueueProducer.h b/include/gui/BufferQueueProducer.h index 3fc5de2..ed1056a 100644 --- a/include/gui/BufferQueueProducer.h +++ b/include/gui/BufferQueueProducer.h @@ -197,6 +197,22 @@ private: uint32_t mStickyTransform; + // This saves the fence from the last queueBuffer, such that the + // next queueBuffer call can throttle buffer production. The prior + // queueBuffer's fence is not nessessarily available elsewhere, + // since the previous buffer might have already been acquired. + sp<Fence> mLastQueueBufferFence; + + // Take-a-ticket system for ensuring that onFrame* callbacks are called in + // the order that frames are queued. While the BufferQueue lock + // (mCore->mMutex) is held, a ticket is retained by the producer. After + // dropping the BufferQueue lock, the producer must wait on the condition + // variable until the current callback ticket matches its retained ticket. + Mutex mCallbackMutex; + int mNextCallbackTicket; // Protected by mCore->mMutex + int mCurrentCallbackTicket; // Protected by mCallbackMutex + Condition mCallbackCondition; + }; // class BufferQueueProducer } // namespace android diff --git a/include/gui/ConsumerBase.h b/include/gui/ConsumerBase.h index 100bb26..f7ab5ac 100644 --- a/include/gui/ConsumerBase.h +++ b/include/gui/ConsumerBase.h @@ -46,7 +46,7 @@ public: // // This is called without any lock held and can be called concurrently // by multiple threads. - virtual void onFrameAvailable() = 0; + virtual void onFrameAvailable(const BufferItem& item) = 0; }; virtual ~ConsumerBase(); @@ -106,7 +106,7 @@ protected: // the ConsumerBase implementation must be called from the derived class. // The ConsumerBase version of onSidebandStreamChanged does nothing and can // be overriden by derived classes if they want the notification. - virtual void onFrameAvailable(); + virtual void onFrameAvailable(const BufferItem& item); virtual void onBuffersReleased(); virtual void onSidebandStreamChanged(); diff --git a/include/gui/IConsumerListener.h b/include/gui/IConsumerListener.h index 260099e..3f39799 100644 --- a/include/gui/IConsumerListener.h +++ b/include/gui/IConsumerListener.h @@ -28,6 +28,8 @@ namespace android { // ---------------------------------------------------------------------------- +class BufferItem; + // ConsumerListener is the interface through which the BufferQueue notifies // the consumer of events that the consumer may wish to react to. Because // the consumer will generally have a mutex that is locked during calls from @@ -43,11 +45,24 @@ public: // frame becomes available for consumption. This means that frames that // are queued while in asynchronous mode only trigger the callback if no // previous frames are pending. Frames queued while in synchronous mode - // always trigger the callback. + // always trigger the callback. The item passed to the callback will contain + // all of the information about the queued frame except for its + // GraphicBuffer pointer, which will always be null. + // + // This is called without any lock held and can be called concurrently + // by multiple threads. + virtual void onFrameAvailable(const BufferItem& item) = 0; /* Asynchronous */ + + // onFrameReplaced is called from queueBuffer if the frame being queued is + // replacing an existing slot in the queue. Any call to queueBuffer that + // doesn't call onFrameAvailable will call this callback instead. The item + // passed to the callback will contain all of the information about the + // queued frame except for its GraphicBuffer pointer, which will always be + // null. // // This is called without any lock held and can be called concurrently // by multiple threads. - virtual void onFrameAvailable() = 0; /* Asynchronous */ + virtual void onFrameReplaced(const BufferItem& /* item */) {} /* Asynchronous */ // onBuffersReleased is called to notify the buffer consumer that the // BufferQueue has released its references to one or more GraphicBuffers diff --git a/include/gui/StreamSplitter.h b/include/gui/StreamSplitter.h index f927953..8f47eb4 100644 --- a/include/gui/StreamSplitter.h +++ b/include/gui/StreamSplitter.h @@ -74,7 +74,7 @@ private: // can block if there are too many outstanding buffers. If it blocks, it // will resume when onBufferReleasedByOutput releases a buffer back to the // input. - virtual void onFrameAvailable(); + virtual void onFrameAvailable(const BufferItem& item); // From IConsumerListener // We don't care about released buffers because we detach each buffer as diff --git a/include/media/drm/DrmAPI.h b/include/media/drm/DrmAPI.h index 4633b7e..49939fd 100644 --- a/include/media/drm/DrmAPI.h +++ b/include/media/drm/DrmAPI.h @@ -209,7 +209,9 @@ namespace android { // confirmed. The persisted record on the client is only removed after positive // confirmation that the server received the message using releaseSecureStops(). virtual status_t getSecureStops(List<Vector<uint8_t> > &secureStops) = 0; + virtual status_t getSecureStop(Vector<uint8_t> const &ssid, Vector<uint8_t> &secureStop) = 0; virtual status_t releaseSecureStops(Vector<uint8_t> const &ssRelease) = 0; + virtual status_t releaseAllSecureStops() = 0; // Read a property value given the device property string. There are a few forms // of property access methods, depending on the data type returned. diff --git a/include/private/binder/Static.h b/include/private/binder/Static.h index 6a03594..eeb37d7 100644 --- a/include/private/binder/Static.h +++ b/include/private/binder/Static.h @@ -34,7 +34,12 @@ extern Vector<int32_t> gTextBuffers; extern Mutex gProcessMutex; extern sp<ProcessState> gProcess; -// For ServiceManager.cpp +// For Parcel.cpp +extern Mutex gParcelGlobalAllocSizeLock; +extern size_t gParcelGlobalAllocSize; +extern size_t gParcelGlobalAllocCount; + +// For IServiceManager.cpp extern Mutex gDefaultServiceManagerLock; extern sp<IServiceManager> gDefaultServiceManager; extern sp<IPermissionController> gPermissionController; diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp index 1dbb06f..98a3dd7 100644 --- a/libs/binder/Parcel.cpp +++ b/libs/binder/Parcel.cpp @@ -26,7 +26,6 @@ #include <binder/TextOutput.h> #include <errno.h> -#include <utils/CallStack.h> #include <utils/Debug.h> #include <utils/Log.h> #include <utils/String8.h> @@ -36,8 +35,8 @@ #include <cutils/ashmem.h> #include <private/binder/binder_module.h> +#include <private/binder/Static.h> -#include <fcntl.h> #include <inttypes.h> #include <stdio.h> #include <stdlib.h> @@ -50,6 +49,8 @@ #define LOG_REFS(...) //#define LOG_REFS(...) ALOG(LOG_DEBUG, "Parcel", __VA_ARGS__) +#define LOG_ALLOC(...) +//#define LOG_ALLOC(...) ALOG(LOG_DEBUG, "Parcel", __VA_ARGS__) // --------------------------------------------------------------------------- @@ -293,12 +294,24 @@ status_t unflatten_binder(const sp<ProcessState>& proc, Parcel::Parcel() { + LOG_ALLOC("Parcel %p: constructing", this); initState(); } Parcel::~Parcel() { freeDataNoInit(); + LOG_ALLOC("Parcel %p: destroyed", this); +} + +size_t Parcel::getGlobalAllocSize() { + AutoMutex _l(gParcelGlobalAllocSizeLock); + return gParcelGlobalAllocSize; +} + +size_t Parcel::getGlobalAllocCount() { + AutoMutex _l(gParcelGlobalAllocSizeLock); + return gParcelGlobalAllocCount; } const uint8_t* Parcel::data() const @@ -768,29 +781,6 @@ status_t Parcel::writeFileDescriptor(int fd, bool takeOwnership) status_t Parcel::writeDupFileDescriptor(int fd) { int dupFd = dup(fd); - - { // Temporary extra debug validation for b/17477219: a Parcel recipient is - // getting a positive but invalid fd unexpectedly. Trying to track down - // where it's coming from. - int dupErrno = dupFd < 0 ? errno : 0; - int fdFlags = fcntl(fd, F_GETFD); - int fdFlagsErrno = fdFlags == -1 ? errno : 0; - int dupFlags = fcntl(dupFd, F_GETFD); - int dupFlagsErrno = dupFlags == -1 ? errno : 0; - if (dupFd < 0 || fdFlags == -1 || dupFlags == -1) { - ALOGE("Parcel::writeDupFileDescriptor failed:\n" - " fd=%d flags=%d err=%d(%s)\n" - " dupFd=%d dupErr=%d(%s) flags=%d err=%d(%s)", - fd, fdFlags, fdFlagsErrno, strerror(fdFlagsErrno), - dupFd, dupErrno, strerror(dupErrno), - dupFlags, dupFlagsErrno, strerror(dupFlagsErrno)); - if (fd < 0 || fdFlags == -1) { - CallStack(LOG_TAG); - } - return -errno; - } - } - if (dupFd < 0) { return -errno; } @@ -1305,23 +1295,11 @@ status_t Parcel::read(FlattenableHelperInterface& val) const status_t err = NO_ERROR; for (size_t i=0 ; i<fd_count && err==NO_ERROR ; i++) { - int oldfd = this->readFileDescriptor(); - fds[i] = dup(oldfd); + fds[i] = dup(this->readFileDescriptor()); if (fds[i] < 0) { - int dupErrno = errno; err = BAD_VALUE; - int flags = fcntl(oldfd, F_GETFD); - int fcntlErrno = errno; - const flat_binder_object* flat = readObject(true); - ALOGE("dup failed in Parcel::read, fd %zu of %zu\n" - " dup(%d) = %d [errno: %d (%s)]\n" - " fcntl(%d, F_GETFD) = %d [errno: %d (%s)]\n" - " flat %p type %d", - i, fd_count, - oldfd, fds[i], dupErrno, strerror(dupErrno), - oldfd, flags, fcntlErrno, strerror(fcntlErrno), - flat, flat ? flat->type : 0); - CallStack(LOG_TAG); + ALOGE("dup() failed in Parcel::read, i is %zu, fds[i] is %d, fd_count is %zu, error: %s", + i, fds[i], fd_count, strerror(errno)); } } @@ -1525,11 +1503,20 @@ void Parcel::freeData() void Parcel::freeDataNoInit() { if (mOwner) { + LOG_ALLOC("Parcel %p: freeing other owner data", this); //ALOGI("Freeing data ref of %p (pid=%d)", this, getpid()); mOwner(this, mData, mDataSize, mObjects, mObjectsSize, mOwnerCookie); } else { + LOG_ALLOC("Parcel %p: freeing allocated data", this); releaseObjects(); - if (mData) free(mData); + if (mData) { + LOG_ALLOC("Parcel %p: freeing with %zu capacity", this, mDataCapacity); + gParcelGlobalAllocSizeLock.lock(); + gParcelGlobalAllocSize -= mDataCapacity; + gParcelGlobalAllocCount--; + gParcelGlobalAllocSizeLock.unlock(); + free(mData); + } if (mObjects) free(mObjects); } } @@ -1558,6 +1545,11 @@ status_t Parcel::restartWrite(size_t desired) releaseObjects(); if (data) { + LOG_ALLOC("Parcel %p: restart from %zu to %zu capacity", this, mDataCapacity, desired); + gParcelGlobalAllocSizeLock.lock(); + gParcelGlobalAllocSize += desired; + gParcelGlobalAllocSize -= mDataCapacity; + gParcelGlobalAllocSizeLock.unlock(); mData = data; mDataCapacity = desired; } @@ -1637,6 +1629,12 @@ status_t Parcel::continueWrite(size_t desired) mOwner(this, mData, mDataSize, mObjects, mObjectsSize, mOwnerCookie); mOwner = NULL; + LOG_ALLOC("Parcel %p: taking ownership of %zu capacity", this, desired); + gParcelGlobalAllocSizeLock.lock(); + gParcelGlobalAllocSize += desired; + gParcelGlobalAllocCount++; + gParcelGlobalAllocSizeLock.unlock(); + mData = data; mObjects = objects; mDataSize = (mDataSize < desired) ? mDataSize : desired; @@ -1671,6 +1669,12 @@ status_t Parcel::continueWrite(size_t desired) if (desired > mDataCapacity) { uint8_t* data = (uint8_t*)realloc(mData, desired); if (data) { + LOG_ALLOC("Parcel %p: continue from %zu to %zu capacity", this, mDataCapacity, + desired); + gParcelGlobalAllocSizeLock.lock(); + gParcelGlobalAllocSize += desired; + gParcelGlobalAllocSize -= mDataCapacity; + gParcelGlobalAllocSizeLock.unlock(); mData = data; mDataCapacity = desired; } else if (desired > mDataCapacity) { @@ -1701,6 +1705,12 @@ status_t Parcel::continueWrite(size_t desired) ALOGE("continueWrite: %zu/%p/%zu/%zu", mDataCapacity, mObjects, mObjectsCapacity, desired); } + LOG_ALLOC("Parcel %p: allocating with %zu capacity", this, desired); + gParcelGlobalAllocSizeLock.lock(); + gParcelGlobalAllocSize += desired; + gParcelGlobalAllocCount++; + gParcelGlobalAllocSizeLock.unlock(); + mData = data; mDataSize = mDataPos = 0; ALOGV("continueWrite Setting data size of %p to %zu", this, mDataSize); @@ -1713,6 +1723,7 @@ status_t Parcel::continueWrite(size_t desired) void Parcel::initState() { + LOG_ALLOC("Parcel %p: initState", this); mError = NO_ERROR; mData = 0; mDataSize = 0; diff --git a/libs/binder/Static.cpp b/libs/binder/Static.cpp index 2062692..b870c34 100644 --- a/libs/binder/Static.cpp +++ b/libs/binder/Static.cpp @@ -90,7 +90,13 @@ public: static LibBinderIPCtStatics gIPCStatics; -// ------------ ServiceManager.cpp +// ------------ Parcel.cpp + +Mutex gParcelGlobalAllocSizeLock; +size_t gParcelGlobalAllocSize = 0; +size_t gParcelGlobalAllocCount = 0; + +// ------------ IServiceManager.cpp Mutex gDefaultServiceManagerLock; sp<IServiceManager> gDefaultServiceManager; diff --git a/libs/binder/TextOutput.cpp b/libs/binder/TextOutput.cpp index db3e858..2ed5188 100644 --- a/libs/binder/TextOutput.cpp +++ b/libs/binder/TextOutput.cpp @@ -116,8 +116,8 @@ TextOutput& operator<<(TextOutput& to, double val) TextOutput& operator<<(TextOutput& to, const void* val) { - char buf[16]; - sprintf(buf, "%p", val); + char buf[32]; + snprintf(buf, sizeof(buf), "%p", val); to.print(buf, strlen(buf)); return to; } diff --git a/libs/gui/BufferItem.cpp b/libs/gui/BufferItem.cpp index d3fa43e..e6fc791 100644 --- a/libs/gui/BufferItem.cpp +++ b/libs/gui/BufferItem.cpp @@ -36,6 +36,8 @@ BufferItem::BufferItem() : mCrop.makeInvalid(); } +BufferItem::~BufferItem() {} + BufferItem::operator IGraphicBufferConsumer::BufferItem() const { IGraphicBufferConsumer::BufferItem bufferItem; bufferItem.mGraphicBuffer = mGraphicBuffer; diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp index c49a886..61fd8c4 100644 --- a/libs/gui/BufferQueue.cpp +++ b/libs/gui/BufferQueue.cpp @@ -31,10 +31,11 @@ BufferQueue::ProxyConsumerListener::ProxyConsumerListener( BufferQueue::ProxyConsumerListener::~ProxyConsumerListener() {} -void BufferQueue::ProxyConsumerListener::onFrameAvailable() { +void BufferQueue::ProxyConsumerListener::onFrameAvailable( + const android::BufferItem& item) { sp<ConsumerListener> listener(mConsumerListener.promote()); if (listener != NULL) { - listener->onFrameAvailable(); + listener->onFrameAvailable(item); } } diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp index d2fd3b0..16b9747 100644 --- a/libs/gui/BufferQueueProducer.cpp +++ b/libs/gui/BufferQueueProducer.cpp @@ -38,7 +38,12 @@ BufferQueueProducer::BufferQueueProducer(const sp<BufferQueueCore>& core) : mCore(core), mSlots(core->mSlots), mConsumerName(), - mStickyTransform(0) {} + mStickyTransform(0), + mLastQueueBufferFence(Fence::NO_FENCE), + mCallbackMutex(), + mNextCallbackTicket(0), + mCurrentCallbackTicket(0), + mCallbackCondition() {} BufferQueueProducer::~BufferQueueProducer() {} @@ -522,12 +527,7 @@ status_t BufferQueueProducer::queueBuffer(int slot, if (fence == NULL) { BQ_LOGE("queueBuffer: fence is NULL"); - // Temporary workaround for b/17946343: soldier-on instead of returning an error. This - // prevents the client from dying, at the risk of visible corruption due to hwcomposer - // reading the buffer before the producer is done rendering it. Unless the buffer is the - // last frame of an animation, the corruption will be transient. - fence = Fence::NO_FENCE; - // return BAD_VALUE; + return BAD_VALUE; } switch (scalingMode) { @@ -541,7 +541,10 @@ status_t BufferQueueProducer::queueBuffer(int slot, return BAD_VALUE; } - sp<IConsumerListener> listener; + sp<IConsumerListener> frameAvailableListener; + sp<IConsumerListener> frameReplacedListener; + int callbackTicket = 0; + BufferItem item; { // Autolock scope Mutex::Autolock lock(mCore->mMutex); @@ -597,7 +600,6 @@ status_t BufferQueueProducer::queueBuffer(int slot, ++mCore->mFrameCounter; mSlots[slot].mFrameNumber = mCore->mFrameCounter; - BufferItem item; item.mAcquireCalled = mSlots[slot].mAcquireCalled; item.mGraphicBuffer = mSlots[slot].mGraphicBuffer; item.mCrop = crop; @@ -618,7 +620,7 @@ status_t BufferQueueProducer::queueBuffer(int slot, // When the queue is empty, we can ignore mDequeueBufferCannotBlock // and simply queue this buffer mCore->mQueue.push_back(item); - listener = mCore->mConsumerListener; + frameAvailableListener = mCore->mConsumerListener; } else { // When the queue is not empty, we need to look at the front buffer // state to see if we need to replace it @@ -634,9 +636,10 @@ status_t BufferQueueProducer::queueBuffer(int slot, } // Overwrite the droppable buffer with the incoming one *front = item; + frameReplacedListener = mCore->mConsumerListener; } else { mCore->mQueue.push_back(item); - listener = mCore->mConsumerListener; + frameAvailableListener = mCore->mConsumerListener; } } @@ -647,11 +650,41 @@ status_t BufferQueueProducer::queueBuffer(int slot, mCore->mTransformHint, mCore->mQueue.size()); ATRACE_INT(mCore->mConsumerName.string(), mCore->mQueue.size()); + + // Take a ticket for the callback functions + callbackTicket = mNextCallbackTicket++; } // Autolock scope - // Call back without lock held - if (listener != NULL) { - listener->onFrameAvailable(); + // Wait without lock held + if (mCore->mConnectedApi == NATIVE_WINDOW_API_EGL) { + // Waiting here allows for two full buffers to be queued but not a + // third. In the event that frames take varying time, this makes a + // small trade-off in favor of latency rather than throughput. + mLastQueueBufferFence->waitForever("Throttling EGL Production"); + mLastQueueBufferFence = fence; + } + + // Don't send the GraphicBuffer through the callback, and don't send + // the slot number, since the consumer shouldn't need it + item.mGraphicBuffer.clear(); + item.mSlot = BufferItem::INVALID_BUFFER_SLOT; + + // Call back without the main BufferQueue lock held, but with the callback + // lock held so we can ensure that callbacks occur in order + { + Mutex::Autolock lock(mCallbackMutex); + while (callbackTicket != mCurrentCallbackTicket) { + mCallbackCondition.wait(mCallbackMutex); + } + + if (frameAvailableListener != NULL) { + frameAvailableListener->onFrameAvailable(item); + } else if (frameReplacedListener != NULL) { + frameReplacedListener->onFrameReplaced(item); + } + + ++mCurrentCallbackTicket; + mCallbackCondition.broadcast(); } return NO_ERROR; diff --git a/libs/gui/ConsumerBase.cpp b/libs/gui/ConsumerBase.cpp index e476c9a..95f5507 100644 --- a/libs/gui/ConsumerBase.cpp +++ b/libs/gui/ConsumerBase.cpp @@ -98,7 +98,7 @@ void ConsumerBase::freeBufferLocked(int slotIndex) { mSlots[slotIndex].mFrameNumber = 0; } -void ConsumerBase::onFrameAvailable() { +void ConsumerBase::onFrameAvailable(const BufferItem& item) { CB_LOGV("onFrameAvailable"); sp<FrameAvailableListener> listener; @@ -109,7 +109,7 @@ void ConsumerBase::onFrameAvailable() { if (listener != NULL) { CB_LOGV("actually calling onFrameAvailable"); - listener->onFrameAvailable(); + listener->onFrameAvailable(item); } } diff --git a/libs/gui/GLConsumer.cpp b/libs/gui/GLConsumer.cpp index 6ba2ef8..b886c5b 100644 --- a/libs/gui/GLConsumer.cpp +++ b/libs/gui/GLConsumer.cpp @@ -505,7 +505,7 @@ status_t GLConsumer::checkAndUpdateEglStateLocked(bool contextCheck) { if (mEglDisplay == EGL_NO_DISPLAY) { mEglDisplay = dpy; } - if (mEglContext == EGL_NO_DISPLAY) { + if (mEglContext == EGL_NO_CONTEXT) { mEglContext = ctx; } } @@ -1065,6 +1065,7 @@ GLConsumer::EglImage::~EglImage() { if (!eglDestroyImageKHR(mEglDisplay, mEglImage)) { ALOGE("~EglImage: eglDestroyImageKHR failed"); } + eglTerminate(mEglDisplay); } } @@ -1079,6 +1080,7 @@ status_t GLConsumer::EglImage::createIfNeeded(EGLDisplay eglDisplay, if (!eglDestroyImageKHR(mEglDisplay, mEglImage)) { ALOGE("createIfNeeded: eglDestroyImageKHR failed"); } + eglTerminate(mEglDisplay); mEglImage = EGL_NO_IMAGE_KHR; mEglDisplay = EGL_NO_DISPLAY; } @@ -1129,11 +1131,13 @@ EGLImageKHR GLConsumer::EglImage::createImage(EGLDisplay dpy, // removes this restriction if there is hardware that can support it. attrs[2] = EGL_NONE; } + eglInitialize(dpy, 0, 0); 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); + eglTerminate(dpy); } return image; } diff --git a/libs/gui/IConsumerListener.cpp b/libs/gui/IConsumerListener.cpp index 4ccf0ac..409dfe4 100644 --- a/libs/gui/IConsumerListener.cpp +++ b/libs/gui/IConsumerListener.cpp @@ -21,6 +21,7 @@ #include <binder/Parcel.h> #include <gui/IConsumerListener.h> +#include <gui/BufferItem.h> // --------------------------------------------------------------------------- namespace android { @@ -39,9 +40,10 @@ public: : BpInterface<IConsumerListener>(impl) { } - virtual void onFrameAvailable() { + virtual void onFrameAvailable(const BufferItem& item) { Parcel data, reply; data.writeInterfaceToken(IConsumerListener::getInterfaceDescriptor()); + data.write(item); remote()->transact(ON_FRAME_AVAILABLE, data, &reply, IBinder::FLAG_ONEWAY); } @@ -66,18 +68,20 @@ status_t BnConsumerListener::onTransact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { switch(code) { - case ON_FRAME_AVAILABLE: + case ON_FRAME_AVAILABLE: { CHECK_INTERFACE(IConsumerListener, data, reply); - onFrameAvailable(); - return NO_ERROR; - case ON_BUFFER_RELEASED: + BufferItem item; + data.read(item); + onFrameAvailable(item); + return NO_ERROR; } + case ON_BUFFER_RELEASED: { CHECK_INTERFACE(IConsumerListener, data, reply); onBuffersReleased(); - return NO_ERROR; - case ON_SIDEBAND_STREAM_CHANGED: + return NO_ERROR; } + case ON_SIDEBAND_STREAM_CHANGED: { CHECK_INTERFACE(IConsumerListener, data, reply); onSidebandStreamChanged(); - return NO_ERROR; + return NO_ERROR; } } return BBinder::onTransact(code, data, reply, flags); } diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp index 81e8336..ebb687a 100644 --- a/libs/gui/ISurfaceComposer.cpp +++ b/libs/gui/ISurfaceComposer.cpp @@ -312,19 +312,29 @@ status_t BnSurfaceComposer::onTransact( case SET_TRANSACTION_STATE: { CHECK_INTERFACE(ISurfaceComposer, data, reply); size_t count = data.readInt32(); + if (count > data.dataSize()) { + return BAD_VALUE; + } ComposerState s; Vector<ComposerState> state; state.setCapacity(count); for (size_t i=0 ; i<count ; i++) { - s.read(data); + if (s.read(data) == BAD_VALUE) { + return BAD_VALUE; + } state.add(s); } count = data.readInt32(); + if (count > data.dataSize()) { + return BAD_VALUE; + } DisplayState d; Vector<DisplayState> displays; displays.setCapacity(count); for (size_t i=0 ; i<count ; i++) { - d.read(data); + if (d.read(data) == BAD_VALUE) { + return BAD_VALUE; + } displays.add(d); } uint32_t flags = data.readInt32(); diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp index 9d3f116..39f8f92 100644 --- a/libs/gui/LayerState.cpp +++ b/libs/gui/LayerState.cpp @@ -55,8 +55,12 @@ status_t layer_state_t::read(const Parcel& input) alpha = input.readFloat(); flags = input.readInt32(); mask = input.readInt32(); - matrix = *reinterpret_cast<layer_state_t::matrix22_t const *>( - input.readInplace(sizeof(layer_state_t::matrix22_t))); + const void* matrix_data = input.readInplace(sizeof(layer_state_t::matrix22_t)); + if (matrix_data) { + matrix = *reinterpret_cast<layer_state_t::matrix22_t const *>(matrix_data); + } else { + return BAD_VALUE; + } input.read(crop); input.read(transparentRegion); return NO_ERROR; diff --git a/libs/gui/StreamSplitter.cpp b/libs/gui/StreamSplitter.cpp index 771b263..5f39905 100644 --- a/libs/gui/StreamSplitter.cpp +++ b/libs/gui/StreamSplitter.cpp @@ -98,7 +98,7 @@ void StreamSplitter::setName(const String8 &name) { mInput->setConsumerName(name); } -void StreamSplitter::onFrameAvailable() { +void StreamSplitter::onFrameAvailable(const BufferItem& /* item */) { ATRACE_CALL(); Mutex::Autolock lock(mMutex); diff --git a/libs/gui/tests/BufferQueue_test.cpp b/libs/gui/tests/BufferQueue_test.cpp index c781366..96de11f 100644 --- a/libs/gui/tests/BufferQueue_test.cpp +++ b/libs/gui/tests/BufferQueue_test.cpp @@ -67,7 +67,7 @@ protected: }; struct DummyConsumer : public BnConsumerListener { - virtual void onFrameAvailable() {} + virtual void onFrameAvailable(const BufferItem& /* item */) {} virtual void onBuffersReleased() {} virtual void onSidebandStreamChanged() {} }; diff --git a/libs/gui/tests/DisconnectWaiter.h b/libs/gui/tests/DisconnectWaiter.h index 56e96c2..6e6915b 100644 --- a/libs/gui/tests/DisconnectWaiter.h +++ b/libs/gui/tests/DisconnectWaiter.h @@ -44,7 +44,7 @@ public: mPendingFrames--; } - virtual void onFrameAvailable() { + virtual void onFrameAvailable(const BufferItem& /* item */) { Mutex::Autolock lock(mMutex); mPendingFrames++; mFrameCondition.signal(); diff --git a/libs/gui/tests/FrameWaiter.h b/libs/gui/tests/FrameWaiter.h index bdedba6..f78fa00 100644 --- a/libs/gui/tests/FrameWaiter.h +++ b/libs/gui/tests/FrameWaiter.h @@ -35,7 +35,7 @@ public: mPendingFrames--; } - virtual void onFrameAvailable() { + virtual void onFrameAvailable(const BufferItem& /* item */) { Mutex::Autolock lock(mMutex); mPendingFrames++; mCondition.signal(); diff --git a/libs/gui/tests/IGraphicBufferProducer_test.cpp b/libs/gui/tests/IGraphicBufferProducer_test.cpp index aadfe61..8d5fd8f 100644 --- a/libs/gui/tests/IGraphicBufferProducer_test.cpp +++ b/libs/gui/tests/IGraphicBufferProducer_test.cpp @@ -65,7 +65,7 @@ const sp<Fence> QUEUE_BUFFER_INPUT_FENCE = Fence::NO_FENCE; }; // namespace anonymous struct DummyConsumer : public BnConsumerListener { - virtual void onFrameAvailable() {} + virtual void onFrameAvailable(const BufferItem& /* item */) {} virtual void onBuffersReleased() {} virtual void onSidebandStreamChanged() {} }; diff --git a/libs/gui/tests/StreamSplitter_test.cpp b/libs/gui/tests/StreamSplitter_test.cpp index 32ec90d..4e63a6f 100644 --- a/libs/gui/tests/StreamSplitter_test.cpp +++ b/libs/gui/tests/StreamSplitter_test.cpp @@ -46,7 +46,7 @@ protected: }; struct DummyListener : public BnConsumerListener { - virtual void onFrameAvailable() {} + virtual void onFrameAvailable(const BufferItem& /* item */) {} virtual void onBuffersReleased() {} virtual void onSidebandStreamChanged() {} }; diff --git a/libs/gui/tests/SurfaceTextureGLThreadToGL.h b/libs/gui/tests/SurfaceTextureGLThreadToGL.h index 6410516..14e42ac 100644 --- a/libs/gui/tests/SurfaceTextureGLThreadToGL.h +++ b/libs/gui/tests/SurfaceTextureGLThreadToGL.h @@ -130,7 +130,7 @@ protected: } // This should be called by GLConsumer on the producer thread. - virtual void onFrameAvailable() { + virtual void onFrameAvailable(const BufferItem& /* item */) { Mutex::Autolock lock(mMutex); ALOGV("+onFrameAvailable"); mFrameAvailable = true; diff --git a/libs/ui/GraphicBuffer.cpp b/libs/ui/GraphicBuffer.cpp index 9b0bd60..e768f13 100644 --- a/libs/ui/GraphicBuffer.cpp +++ b/libs/ui/GraphicBuffer.cpp @@ -310,10 +310,19 @@ status_t GraphicBuffer::unflatten( const size_t numFds = buf[8]; const size_t numInts = buf[9]; + const size_t maxNumber = UINT_MAX / sizeof(int); + if (numFds >= maxNumber || numInts >= (maxNumber - 10)) { + width = height = stride = format = usage = 0; + handle = NULL; + ALOGE("unflatten: numFds or numInts is too large: %d, %d", + numFds, numInts); + return BAD_VALUE; + } + const size_t sizeNeeded = (10 + numInts) * sizeof(int); if (size < sizeNeeded) return NO_MEMORY; - size_t fdCountNeeded = 0; + size_t fdCountNeeded = numFds; if (count < fdCountNeeded) return NO_MEMORY; if (handle) { @@ -328,6 +337,12 @@ status_t GraphicBuffer::unflatten( format = buf[4]; usage = buf[5]; native_handle* h = native_handle_create(numFds, numInts); + if (!h) { + width = height = stride = format = usage = 0; + handle = NULL; + ALOGE("unflatten: native_handle_create failed"); + return NO_MEMORY; + } memcpy(h->data, fds, numFds*sizeof(int)); memcpy(h->data + numFds, &buf[10], numInts*sizeof(int)); handle = h; diff --git a/opengl/tests/EGLTest/EGL_test.cpp b/opengl/tests/EGLTest/EGL_test.cpp index a4364c6..d69a275 100644 --- a/opengl/tests/EGLTest/EGL_test.cpp +++ b/opengl/tests/EGLTest/EGL_test.cpp @@ -101,7 +101,7 @@ TEST_F(EGLTest, EGLTerminateSucceedsWithRemainingObjects) { EXPECT_TRUE(eglChooseConfig(mEglDisplay, attrs, &config, 1, &numConfigs)); struct DummyConsumer : public BnConsumerListener { - virtual void onFrameAvailable() {} + virtual void onFrameAvailable(const BufferItem& /* item */) {} virtual void onBuffersReleased() {} virtual void onSidebandStreamChanged() {} }; diff --git a/services/inputflinger/InputDispatcher.cpp b/services/inputflinger/InputDispatcher.cpp index 02fb6f0..603836a 100644 --- a/services/inputflinger/InputDispatcher.cpp +++ b/services/inputflinger/InputDispatcher.cpp @@ -477,7 +477,6 @@ sp<InputWindowHandle> InputDispatcher::findTouchedWindowAtLocked(int32_t display const InputWindowInfo* windowInfo = windowHandle->getInfo(); if (windowInfo->displayId == displayId) { int32_t flags = windowInfo->layoutParamsFlags; - int32_t privateFlags = windowInfo->layoutParamsPrivateFlags; if (windowInfo->visible) { if (!(flags & InputWindowInfo::FLAG_NOT_TOUCHABLE)) { @@ -489,11 +488,6 @@ sp<InputWindowHandle> InputDispatcher::findTouchedWindowAtLocked(int32_t display } } } - - if (privateFlags & InputWindowInfo::PRIVATE_FLAG_SYSTEM_ERROR) { - // Error window is on top but not visible, so touch is dropped. - return NULL; - } } } return NULL; @@ -1190,7 +1184,6 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, int32_t y = int32_t(entry->pointerCoords[pointerIndex]. getAxisValue(AMOTION_EVENT_AXIS_Y)); sp<InputWindowHandle> newTouchedWindowHandle; - sp<InputWindowHandle> topErrorWindowHandle; bool isTouchModal = false; // Traverse windows from front to back to find touched window and outside targets. @@ -1202,13 +1195,6 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, continue; // wrong display } - int32_t privateFlags = windowInfo->layoutParamsPrivateFlags; - if (privateFlags & InputWindowInfo::PRIVATE_FLAG_SYSTEM_ERROR) { - if (topErrorWindowHandle == NULL) { - topErrorWindowHandle = windowHandle; - } - } - int32_t flags = windowInfo->layoutParamsFlags; if (windowInfo->visible) { if (! (flags & InputWindowInfo::FLAG_NOT_TOUCHABLE)) { @@ -1233,17 +1219,6 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, } } - // If there is an error window but it is not taking focus (typically because - // it is invisible) then wait for it. Any other focused window may in - // fact be in ANR state. - if (topErrorWindowHandle != NULL && newTouchedWindowHandle != topErrorWindowHandle) { - injectionResult = handleTargetsNotReadyLocked(currentTime, entry, - NULL, NULL, nextWakeupTime, - "Waiting because a system error window is about to be displayed."); - injectionPermission = INJECTION_PERMISSION_UNKNOWN; - goto Unresponsive; - } - // Figure out whether splitting will be allowed for this window. if (newTouchedWindowHandle != NULL && newTouchedWindowHandle->getInfo()->supportsSplitTouch()) { diff --git a/services/inputflinger/InputWindow.h b/services/inputflinger/InputWindow.h index 5879c84..42457ce 100644 --- a/services/inputflinger/InputWindow.h +++ b/services/inputflinger/InputWindow.h @@ -64,11 +64,6 @@ struct InputWindowInfo { FLAG_NEEDS_MENU_KEY = 0x40000000, }; - // Private Window flags from WindowManager.LayoutParams - enum { - PRIVATE_FLAG_SYSTEM_ERROR = 0x00000100, - }; - // Window types from WindowManager.LayoutParams enum { FIRST_APPLICATION_WINDOW = 1, @@ -119,7 +114,6 @@ struct InputWindowInfo { sp<InputChannel> inputChannel; String8 name; int32_t layoutParamsFlags; - int32_t layoutParamsPrivateFlags; int32_t layoutParamsType; nsecs_t dispatchingTimeout; int32_t frameLeft; diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp index dc8fa64..c316ef6 100644 --- a/services/sensorservice/SensorService.cpp +++ b/services/sensorservice/SensorService.cpp @@ -191,6 +191,8 @@ void SensorService::onFirstRef() mSensorEventScratch = new sensors_event_t[minBufferSize]; mMapFlushEventsToConnections = new SensorEventConnection const * [minBufferSize]; + mAckReceiver = new SensorEventAckReceiver(this); + mAckReceiver->run("SensorEventAckReceiver", PRIORITY_URGENT_DISPLAY); mInitCheck = NO_ERROR; run("SensorService", PRIORITY_URGENT_DISPLAY); } @@ -386,8 +388,6 @@ bool SensorService::threadLoop() SensorDevice& device(SensorDevice::getInstance()); const size_t vcount = mVirtualSensorList.size(); - SensorEventAckReceiver sender(this); - sender.run("SensorEventAckReceiver", PRIORITY_URGENT_DISPLAY); const int halVersion = device.getHalDeviceVersion(); do { ssize_t count = device.poll(mSensorEventBuffer, numEventMax); @@ -408,16 +408,7 @@ bool SensorService::threadLoop() // result in a deadlock as ~SensorEventConnection() needs to acquire mLock again for // cleanup. So copy all the strongPointers to a vector before the lock is acquired. SortedVector< sp<SensorEventConnection> > activeConnections; - { - Mutex::Autolock _l(mLock); - for (size_t i=0 ; i < mActiveConnections.size(); ++i) { - sp<SensorEventConnection> connection(mActiveConnections[i].promote()); - if (connection != 0) { - activeConnections.add(connection); - } - } - } - + populateActiveConnections(&activeConnections); 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, @@ -433,8 +424,7 @@ bool SensorService::threadLoop() } if (bufferHasWakeUpEvent && !mWakeLockAcquired) { - acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_NAME); - mWakeLockAcquired = true; + setWakeLockAcquiredLocked(true); } recordLastValueLocked(mSensorEventBuffer, count); @@ -522,8 +512,7 @@ bool SensorService::threadLoop() } if (mWakeLockAcquired && !needsWakeLock) { - release_wake_lock(WAKE_LOCK_NAME); - mWakeLockAcquired = false; + setWakeLockAcquiredLocked(false); } } while (!Thread::exitPending()); @@ -536,11 +525,52 @@ sp<Looper> SensorService::getLooper() const { return mLooper; } +void SensorService::resetAllWakeLockRefCounts() { + SortedVector< sp<SensorEventConnection> > activeConnections; + populateActiveConnections(&activeConnections); + { + Mutex::Autolock _l(mLock); + for (size_t i=0 ; i < activeConnections.size(); ++i) { + if (activeConnections[i] != 0) { + activeConnections[i]->resetWakeLockRefCount(); + } + } + setWakeLockAcquiredLocked(false); + } +} + +void SensorService::setWakeLockAcquiredLocked(bool acquire) { + if (acquire) { + if (!mWakeLockAcquired) { + acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_NAME); + mWakeLockAcquired = true; + } + mLooper->wake(); + } else { + if (mWakeLockAcquired) { + release_wake_lock(WAKE_LOCK_NAME); + mWakeLockAcquired = false; + } + } +} + + +bool SensorService::isWakeLockAcquired() { + Mutex::Autolock _l(mLock); + return mWakeLockAcquired; +} + bool SensorService::SensorEventAckReceiver::threadLoop() { ALOGD("new thread SensorEventAckReceiver"); + sp<Looper> looper = mService->getLooper(); do { - sp<Looper> looper = mService->getLooper(); - looper->pollOnce(-1); + bool wakeLockAcquired = mService->isWakeLockAcquired(); + int timeout = -1; + if (wakeLockAcquired) timeout = 5000; + int ret = looper->pollOnce(timeout); + if (ret == ALOOPER_POLL_TIMEOUT) { + mService->resetAllWakeLockRefCounts(); + } } while(!Thread::exitPending()); return false; } @@ -714,10 +744,7 @@ status_t SensorService::enable(const sp<SensorEventConnection>& connection, sensors_event_t& event(mLastEventSeen.editValueFor(handle)); if (event.version == sizeof(sensors_event_t)) { if (isWakeUpSensorEvent(event) && !mWakeLockAcquired) { - acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_NAME); - mWakeLockAcquired = true; - ALOGD_IF(DEBUG_CONNECTIONS, "acquired wakelock for on_change sensor %s", - WAKE_LOCK_NAME); + setWakeLockAcquiredLocked(true); } connection->sendEvents(&event, 1, NULL); if (!connection->needsWakeLock() && mWakeLockAcquired) { @@ -922,8 +949,26 @@ void SensorService::checkWakeLockStateLocked() { } } if (releaseLock) { - release_wake_lock(WAKE_LOCK_NAME); - mWakeLockAcquired = false; + setWakeLockAcquiredLocked(false); + } +} + +void SensorService::sendEventsFromCache(const sp<SensorEventConnection>& connection) { + Mutex::Autolock _l(mLock); + connection->writeToSocketFromCache(); + if (connection->needsWakeLock()) { + setWakeLockAcquiredLocked(true); + } +} + +void SensorService::populateActiveConnections( + SortedVector< sp<SensorEventConnection> >* activeConnections) { + Mutex::Autolock _l(mLock); + for (size_t i=0 ; i < mActiveConnections.size(); ++i) { + sp<SensorEventConnection> connection(mActiveConnections[i].promote()); + if (connection != 0) { + activeConnections->add(connection); + } } } @@ -1013,6 +1058,11 @@ bool SensorService::SensorEventConnection::needsWakeLock() { return !mDead && mWakeLockRefCount > 0; } +void SensorService::SensorEventConnection::resetWakeLockRefCount() { + Mutex::Autolock _l(mConnectionLock); + mWakeLockRefCount = 0; +} + void SensorService::SensorEventConnection::dump(String8& result) { Mutex::Autolock _l(mConnectionLock); result.appendFormat("\t WakeLockRefCount %d | uid %d | cache size %d | max cache size %d\n", @@ -1334,11 +1384,14 @@ void SensorService::SensorEventConnection::sendPendingFlushEventsLocked() { while (flushInfo.mPendingFlushEventsToSend > 0) { const int sensor_handle = mSensorInfo.keyAt(i); flushCompleteEvent.meta_data.sensor = sensor_handle; - if (mService->getSensorFromHandle(sensor_handle).isWakeUpSensor()) { + bool wakeUpSensor = mService->getSensorFromHandle(sensor_handle).isWakeUpSensor(); + if (wakeUpSensor) { + ++mWakeLockRefCount; flushCompleteEvent.flags |= WAKE_UP_SENSOR_EVENT_NEEDS_ACK; } ssize_t size = SensorEventQueue::write(mChannel, &flushCompleteEvent, 1); if (size < 0) { + if (wakeUpSensor) --mWakeLockRefCount; return; } ALOGD_IF(DEBUG_CONNECTIONS, "sent dropped flush complete event==%d ", @@ -1348,11 +1401,12 @@ void SensorService::SensorEventConnection::sendPendingFlushEventsLocked() { } } -void SensorService::SensorEventConnection::writeToSocketFromCacheLocked() { +void SensorService::SensorEventConnection::writeToSocketFromCache() { // At a time write at most half the size of the receiver buffer in SensorEventQueue OR // half the size of the socket buffer allocated in BitTube whichever is smaller. const int maxWriteSize = helpers::min(SensorEventQueue::MAX_RECEIVE_BUFFER_EVENT_COUNT/2, int(mService->mSocketBufferSize/(sizeof(sensors_event_t)*2))); + Mutex::Autolock _l(mConnectionLock); // Send pending flush complete events (if any) sendPendingFlushEventsLocked(); for (int numEventsSent = 0; numEventsSent < mCacheSize;) { @@ -1503,9 +1557,8 @@ int SensorService::SensorEventConnection::handleEvent(int fd, int events, void* } if (events & ALOOPER_EVENT_OUTPUT) { - // send sensor data that is stored in mEventCache. - Mutex::Autolock _l(mConnectionLock); - writeToSocketFromCacheLocked(); + // send sensor data that is stored in mEventCache for this connection. + mService->sendEventsFromCache(this); } return 1; } diff --git a/services/sensorservice/SensorService.h b/services/sensorservice/SensorService.h index 5e3eeb5..8719487 100644 --- a/services/sensorservice/SensorService.h +++ b/services/sensorservice/SensorService.h @@ -101,7 +101,7 @@ class SensorService : void sendPendingFlushEventsLocked(); // Writes events from mEventCache to the socket. - void writeToSocketFromCacheLocked(); + void writeToSocketFromCache(); // 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 @@ -182,6 +182,7 @@ class SensorService : void setFirstFlushPending(int32_t handle, bool value); void dump(String8& result); bool needsWakeLock(); + void resetWakeLockRefCount(); uid_t getUid() const { return mUid; } }; @@ -230,12 +231,29 @@ class SensorService : // corresponding applications, if yes the wakelock is released. void checkWakeLockState(); void checkWakeLockStateLocked(); + bool isWakeLockAcquired(); bool isWakeUpSensorEvent(const sensors_event_t& event) const; SensorRecord * getSensorRecord(int handle); sp<Looper> getLooper() const; + // Reset mWakeLockRefCounts for all SensorEventConnections to zero. This may happen if + // SensorService did not receive any acknowledgements from apps which have registered for + // wake_up sensors. + void resetAllWakeLockRefCounts(); + + // Acquire or release wake_lock. If wake_lock is acquired, set the timeout in the looper to + // 5 seconds and wake the looper. + void setWakeLockAcquiredLocked(bool acquire); + + // Send events from the event cache for this particular connection. + void sendEventsFromCache(const sp<SensorEventConnection>& connection); + + // Promote all weak referecences in mActiveConnections vector to strong references and add them + // to the output vector. + void populateActiveConnections(SortedVector< sp<SensorEventConnection> >* activeConnections); + // constants Vector<Sensor> mSensorList; Vector<Sensor> mUserSensorListDebug; @@ -247,6 +265,7 @@ class SensorService : // supported or not. uint32_t mSocketBufferSize; sp<Looper> mLooper; + sp<SensorEventAckReceiver> mAckReceiver; // protected by mLock mutable Mutex mLock; diff --git a/services/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk index f1ddbe2..3123b63 100644 --- a/services/surfaceflinger/Android.mk +++ b/services/surfaceflinger/Android.mk @@ -83,6 +83,12 @@ else LOCAL_CFLAGS += -DPRESENT_TIME_OFFSET_FROM_VSYNC_NS=0 endif +ifneq ($(MAX_VIRTUAL_DISPLAY_DIMENSION),) + LOCAL_CFLAGS += -DMAX_VIRTUAL_DISPLAY_DIMENSION=$(MAX_VIRTUAL_DISPLAY_DIMENSION) +else + LOCAL_CFLAGS += -DMAX_VIRTUAL_DISPLAY_DIMENSION=0 +endif + LOCAL_CFLAGS += -fvisibility=hidden -Werror=format LOCAL_CFLAGS += -std=c++11 diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp index 342016e..22d3cec 100644 --- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp +++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp @@ -68,7 +68,7 @@ FramebufferSurface::FramebufferSurface(HWComposer& hwc, int disp, mConsumer->setDefaultMaxBufferCount(NUM_FRAMEBUFFER_SURFACE_BUFFERS); } -status_t FramebufferSurface::beginFrame(bool /* mustRecompose */) { +status_t FramebufferSurface::beginFrame(bool /*mustRecompose*/) { return NO_ERROR; } @@ -122,7 +122,7 @@ status_t FramebufferSurface::nextBuffer(sp<GraphicBuffer>& outBuffer, sp<Fence>& } // Overrides ConsumerBase::onFrameAvailable(), does not call base class impl. -void FramebufferSurface::onFrameAvailable() { +void FramebufferSurface::onFrameAvailable(const BufferItem& /* item */) { sp<GraphicBuffer> buf; sp<Fence> acquireFence; status_t err = nextBuffer(buf, acquireFence); diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.h b/services/surfaceflinger/DisplayHardware/FramebufferSurface.h index d0bf22b..8605862 100644 --- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.h +++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.h @@ -56,7 +56,7 @@ public: private: virtual ~FramebufferSurface() { }; // this class cannot be overloaded - virtual void onFrameAvailable(); + virtual void onFrameAvailable(const BufferItem& item); virtual void freeBufferLocked(int slotIndex); virtual void dumpLocked(String8& result, const char* prefix) const; diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 91e9a02..c91f0af 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -158,7 +158,7 @@ void Layer::onLayerDisplayed(const sp<const DisplayDevice>& /* hw */, } } -void Layer::onFrameAvailable() { +void Layer::onFrameAvailable(const BufferItem& /* item */) { android_atomic_inc(&mQueuedFrames); mFlinger->signalLayerUpdate(); } @@ -277,12 +277,17 @@ static Rect reduce(const Rect& win, const Region& exclude) { Rect Layer::computeBounds() const { const Layer::State& s(getDrawingState()); + return computeBounds(s.activeTransparentRegion); +} + +Rect Layer::computeBounds(const Region& activeTransparentRegion) const { + const Layer::State& s(getDrawingState()); 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 - return reduce(win, s.activeTransparentRegion); + return reduce(win, activeTransparentRegion); } FloatRect Layer::computeCrop(const sp<const DisplayDevice>& hw) const { @@ -404,7 +409,22 @@ void Layer::setGeometry( // apply the layer's transform, followed by the display's global transform // here we're guaranteed that the layer's transform preserves rects - Rect frame(s.transform.transform(computeBounds())); + Region activeTransparentRegion(s.activeTransparentRegion); + if (!s.active.crop.isEmpty()) { + Rect activeCrop(s.active.crop); + activeCrop = s.transform.transform(activeCrop); + activeCrop.intersect(hw->getViewport(), &activeCrop); + activeCrop = s.transform.inverse().transform(activeCrop); + // mark regions outside the crop as transparent + activeTransparentRegion.orSelf(Rect(0, 0, s.active.w, activeCrop.top)); + activeTransparentRegion.orSelf(Rect(0, activeCrop.bottom, + s.active.w, s.active.h)); + activeTransparentRegion.orSelf(Rect(0, activeCrop.top, + activeCrop.left, activeCrop.bottom)); + activeTransparentRegion.orSelf(Rect(activeCrop.right, activeCrop.top, + s.active.w, activeCrop.bottom)); + } + Rect frame(s.transform.transform(computeBounds(activeTransparentRegion))); frame.intersect(hw->getViewport(), &frame); const Transform& tr(hw->getTransform()); layer.setFrame(tr.transform(frame)); diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 2ef39e8..b705bc2 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -142,6 +142,7 @@ public: void computeGeometry(const sp<const DisplayDevice>& hw, Mesh& mesh, bool useIdentityTransform) const; + Rect computeBounds(const Region& activeTransparentRegion) const; Rect computeBounds() const; sp<IBinder> getHandle(); @@ -329,7 +330,7 @@ protected: private: // Interface implementation for SurfaceFlingerConsumer::ContentsChangedListener - virtual void onFrameAvailable(); + virtual void onFrameAvailable(const BufferItem& item); virtual void onSidebandStreamChanged(); void commitTransaction(); diff --git a/services/surfaceflinger/LayerDim.h b/services/surfaceflinger/LayerDim.h index 60edd91..a0cfca9 100644 --- a/services/surfaceflinger/LayerDim.h +++ b/services/surfaceflinger/LayerDim.h @@ -28,7 +28,7 @@ namespace android { class LayerDim : public Layer { -public: +public: LayerDim(SurfaceFlinger* flinger, const sp<Client>& client, const String8& name, uint32_t w, uint32_t h, uint32_t flags); virtual ~LayerDim(); @@ -36,8 +36,7 @@ public: virtual const char* getTypeId() const { return "LayerDim"; } virtual void onDraw(const sp<const DisplayDevice>& hw, const Region& clip, bool useIdentityTransform) const; - using Layer::isOpaque; - virtual bool isOpaque() const { return false; } + virtual bool isOpaque(const Layer::State&) const { return false; } virtual bool isSecure() const { return false; } virtual bool isFixedSize() const { return true; } virtual bool isVisible() const; diff --git a/services/surfaceflinger/RenderEngine/RenderEngine.cpp b/services/surfaceflinger/RenderEngine/RenderEngine.cpp index 767b714..7cd42e4 100644 --- a/services/surfaceflinger/RenderEngine/RenderEngine.cpp +++ b/services/surfaceflinger/RenderEngine/RenderEngine.cpp @@ -219,6 +219,10 @@ void RenderEngine::fillRegionWithColor(const Region& region, uint32_t height, drawMesh(mesh); } +void RenderEngine::flush() { + glFlush(); +} + void RenderEngine::clearWithColor(float red, float green, float blue, float alpha) { glClearColor(red, green, blue, alpha); glClear(GL_COLOR_BUFFER_BIT); diff --git a/services/surfaceflinger/RenderEngine/RenderEngine.h b/services/surfaceflinger/RenderEngine/RenderEngine.h index acbff9b..8d7529c 100644 --- a/services/surfaceflinger/RenderEngine/RenderEngine.h +++ b/services/surfaceflinger/RenderEngine/RenderEngine.h @@ -67,6 +67,7 @@ public: virtual void dump(String8& result); // helpers + void flush(); void clearWithColor(float red, float green, float blue, float alpha); void fillRegionWithColor(const Region& region, uint32_t height, float red, float green, float blue, float alpha); diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index e767be2..7d6d7c2 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -506,6 +506,9 @@ status_t SurfaceFlinger::getDisplayConfigs(const sp<IBinder>& display, return BAD_VALUE; } + if (!display.get()) + return NAME_NOT_FOUND; + int32_t type = NAME_NOT_FOUND; for (int i=0 ; i<DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES ; i++) { if (display == mBuiltinDisplays[i]) { @@ -652,7 +655,7 @@ status_t SurfaceFlinger::setActiveConfig(const sp<IBinder>& display, int mode) { virtual bool handler() { Vector<DisplayInfo> configs; mFlinger.getDisplayConfigs(mDisplay, &configs); - if(mMode < 0 || static_cast<size_t>(mMode) >= configs.size()) { + if (mMode < 0 || mMode >= static_cast<int>(configs.size())) { ALOGE("Attempt to set active config = %d for display with %zu configs", mMode, configs.size()); } @@ -1331,7 +1334,22 @@ void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags) // etc.) but no internal state (i.e. a DisplayDevice). if (state.surface != NULL) { - hwcDisplayId = allocateHwcDisplayId(state.type); + int width = 0; + int status = state.surface->query( + NATIVE_WINDOW_WIDTH, &width); + ALOGE_IF(status != NO_ERROR, + "Unable to query width (%d)", status); + int height = 0; + status = state.surface->query( + NATIVE_WINDOW_HEIGHT, &height); + ALOGE_IF(status != NO_ERROR, + "Unable to query height (%d)", status); + if (MAX_VIRTUAL_DISPLAY_DIMENSION == 0 || + (width <= MAX_VIRTUAL_DISPLAY_DIMENSION && + height <= MAX_VIRTUAL_DISPLAY_DIMENSION)) { + hwcDisplayId = allocateHwcDisplayId(state.type); + } + sp<VirtualDisplaySurface> vds = new VirtualDisplaySurface( *mHwc, hwcDisplayId, state.surface, bqProducer, bqConsumer, state.displayName); @@ -3205,6 +3223,8 @@ status_t SurfaceFlinger::captureScreenImplLocked( EGLSyncKHR sync; if (!DEBUG_SCREENSHOTS) { sync = eglCreateSyncKHR(mEGLDisplay, EGL_SYNC_NATIVE_FENCE_ANDROID, NULL); + // native fence fd will not be populated until flush() is done. + getRenderEngine().flush(); } else { sync = EGL_NO_SYNC_KHR; } @@ -3251,10 +3271,8 @@ status_t SurfaceFlinger::captureScreenImplLocked( } else { result = BAD_VALUE; } + // queueBuffer takes ownership of syncFd window->queueBuffer(window, buffer, syncFd); - if (syncFd != -1) { - close(syncFd); - } } } else { result = BAD_VALUE; |