diff --git a/include/binder/Parcel.h b/include/binder/Parcel.h index 7a782f569..c95f297b4 100644 --- a/include/binder/Parcel.h +++ b/include/binder/Parcel.h @@ -101,6 +101,7 @@ public: status_t writeString16(const char16_t* str, size_t len); status_t writeStrongBinder(const sp& val); status_t writeWeakBinder(const wp& val); + status_t writeInt32Array(size_t len, const int32_t *val); template status_t write(const Flattenable& val); diff --git a/include/powermanager/IPowerManager.h b/include/powermanager/IPowerManager.h index 2f4c3c46e..d85003f4a 100644 --- a/include/powermanager/IPowerManager.h +++ b/include/powermanager/IPowerManager.h @@ -35,6 +35,7 @@ public: virtual status_t acquireWakeLockWithUid(int flags, const sp& lock, const String16& tag, const String16& packageName, int uid) = 0; virtual status_t releaseWakeLock(const sp& lock, int flags) = 0; + virtual status_t updateWakeLockUids(const sp& lock, int len, const int *uids) = 0; }; // ---------------------------------------------------------------------------- diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp index 7a5919f43..38e019cb9 100644 --- a/libs/binder/Parcel.cpp +++ b/libs/binder/Parcel.cpp @@ -617,6 +617,16 @@ status_t Parcel::writeInt32(int32_t val) { return writeAligned(val); } +status_t Parcel::writeInt32Array(size_t len, const int32_t *val) { + if (!val) { + return writeAligned(-1); + } + status_t ret = writeAligned(len); + if (ret == NO_ERROR) { + ret = write(val, len * sizeof(*val)); + } + return ret; +} status_t Parcel::writeInt64(int64_t val) { diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp index c165a6820..2aecb6778 100644 --- a/libs/gui/BufferQueue.cpp +++ b/libs/gui/BufferQueue.cpp @@ -644,6 +644,7 @@ status_t BufferQueue::connect(const sp& token, producerControlledByApp ? "true" : "false"); Mutex::Autolock lock(mMutex); +retry: if (mAbandoned) { ST_LOGE("connect: BufferQueue has been abandoned!"); return NO_INIT; @@ -654,29 +655,41 @@ status_t BufferQueue::connect(const sp& token, return NO_INIT; } + if (mConnectedApi != NO_CONNECTED_API) { + ST_LOGE("connect: already connected (cur=%d, req=%d)", + mConnectedApi, api); + return -EINVAL; + } + + // If we disconnect and reconnect quickly, we can be in a state where our slots are + // empty but we have many buffers in the queue. This can cause us to run out of + // memory if we outrun the consumer. Wait here if it looks like we have too many + // buffers queued up. + int maxBufferCount = getMaxBufferCountLocked(false); // worst-case, i.e. largest value + if (mQueue.size() > (size_t) maxBufferCount) { + // TODO: make this bound tighter? + ST_LOGV("queue size is %d, waiting", mQueue.size()); + mDequeueCondition.wait(mMutex); + goto retry; + } + int err = NO_ERROR; switch (api) { case NATIVE_WINDOW_API_EGL: case NATIVE_WINDOW_API_CPU: case NATIVE_WINDOW_API_MEDIA: case NATIVE_WINDOW_API_CAMERA: - if (mConnectedApi != NO_CONNECTED_API) { - ST_LOGE("connect: already connected (cur=%d, req=%d)", - mConnectedApi, api); - err = -EINVAL; - } else { - mConnectedApi = api; - output->inflate(mDefaultWidth, mDefaultHeight, mTransformHint, mQueue.size()); + mConnectedApi = api; + output->inflate(mDefaultWidth, mDefaultHeight, mTransformHint, mQueue.size()); - // set-up a death notification so that we can disconnect - // automatically when/if the remote producer dies. - if (token != NULL && token->remoteBinder() != NULL) { - status_t err = token->linkToDeath(static_cast(this)); - if (err == NO_ERROR) { - mConnectedProducerToken = token; - } else { - ALOGE("linkToDeath failed: %s (%d)", strerror(-err), err); - } + // set-up a death notification so that we can disconnect + // automatically when/if the remote producer dies. + if (token != NULL && token->remoteBinder() != NULL) { + status_t err = token->linkToDeath(static_cast(this)); + if (err == NO_ERROR) { + mConnectedProducerToken = token; + } else { + ALOGE("linkToDeath failed: %s (%d)", strerror(-err), err); } } break; diff --git a/libs/input/InputTransport.cpp b/libs/input/InputTransport.cpp index 9bd7fc6eb..09b2e7c5c 100644 --- a/libs/input/InputTransport.cpp +++ b/libs/input/InputTransport.cpp @@ -511,14 +511,17 @@ status_t InputConsumer::consumeBatch(InputEventFactoryInterface* factory, status_t result; for (size_t i = mBatches.size(); i-- > 0; ) { Batch& batch = mBatches.editItemAt(i); - if (frameTime < 0 || !mResampleTouch) { + if (frameTime < 0) { result = consumeSamples(factory, batch, batch.samples.size(), outSeq, outEvent); mBatches.removeAt(i); return result; } - nsecs_t sampleTime = frameTime - RESAMPLE_LATENCY; + nsecs_t sampleTime = frameTime; + if (mResampleTouch) { + sampleTime -= RESAMPLE_LATENCY; + } ssize_t split = findSampleNoLaterThan(batch, sampleTime); if (split < 0) { continue; @@ -532,7 +535,7 @@ status_t InputConsumer::consumeBatch(InputEventFactoryInterface* factory, } else { next = &batch.samples.itemAt(0); } - if (!result) { + if (!result && mResampleTouch) { resampleTouchState(sampleTime, static_cast(*outEvent), next); } return result; diff --git a/opengl/libs/EGL/trace.cpp b/opengl/libs/EGL/trace.cpp index bac6ba8ec..3e228e45a 100644 --- a/opengl/libs/EGL/trace.cpp +++ b/opengl/libs/EGL/trace.cpp @@ -435,7 +435,7 @@ EGLAPI gl_hooks_t gHooksSystrace = { if (error) { \ CallStack s; \ s.update(); \ - s.dump("glGetError:" #_api); \ + s.log("glGetError:" #_api); \ } \ #define TRACE_GL_VOID(_api, _args, _argList, ...) \ diff --git a/services/powermanager/IPowerManager.cpp b/services/powermanager/IPowerManager.cpp index 9f60e7524..5ecd299a5 100644 --- a/services/powermanager/IPowerManager.cpp +++ b/services/powermanager/IPowerManager.cpp @@ -32,6 +32,7 @@ enum { ACQUIRE_WAKE_LOCK = IBinder::FIRST_CALL_TRANSACTION, ACQUIRE_WAKE_LOCK_UID = IBinder::FIRST_CALL_TRANSACTION + 1, RELEASE_WAKE_LOCK = IBinder::FIRST_CALL_TRANSACTION + 2, + UPDATE_WAKE_LOCK_UIDS = IBinder::FIRST_CALL_TRANSACTION + 3, }; class BpPowerManager : public BpInterface @@ -78,6 +79,16 @@ public: data.writeInt32(flags); return remote()->transact(RELEASE_WAKE_LOCK, data, &reply); } + + virtual status_t updateWakeLockUids(const sp& lock, int len, const int *uids) { + Parcel data, reply; + data.writeInterfaceToken(IPowerManager::getInterfaceDescriptor()); + data.writeStrongBinder(lock); + data.writeInt32Array(len, uids); + // We don't really care too much if this succeeds (there's nothing we can do if it doesn't) + // but it should return ASAP + return remote()->transact(UPDATE_WAKE_LOCK_UIDS, data, &reply, IBinder::FLAG_ONEWAY); + } }; IMPLEMENT_META_INTERFACE(PowerManager, "android.os.IPowerManager"); diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp index 555d84354..a2f433279 100644 --- a/services/sensorservice/SensorService.cpp +++ b/services/sensorservice/SensorService.cpp @@ -480,6 +480,11 @@ String8 SensorService::getSensorName(int handle) const { return result; } +bool SensorService::isVirtualSensor(int handle) const { + SensorInterface* sensor = mSensorMap.valueFor(handle); + return sensor->isVirtual(); +} + Vector SensorService::getSensorList() { char value[PROPERTY_VALUE_MAX]; @@ -858,6 +863,11 @@ status_t SensorService::SensorEventConnection::sendEvents( } } + // Early return if there are no events for this connection. + if (count == 0) { + return status_t(NO_ERROR); + } + // NOTE: ASensorEvent and sensors_event_t are the same type ssize_t size = SensorEventQueue::write(mChannel, reinterpret_cast(scratch), count); @@ -922,7 +932,7 @@ 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); - if (halVersion < SENSORS_DEVICE_API_VERSION_1_1) { + 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); diff --git a/services/sensorservice/SensorService.h b/services/sensorservice/SensorService.h index 6c1691a03..c9683197f 100644 --- a/services/sensorservice/SensorService.h +++ b/services/sensorservice/SensorService.h @@ -130,6 +130,7 @@ class SensorService : DefaultKeyedVector getActiveVirtualSensors() const; String8 getSensorName(int handle) const; + bool isVirtualSensor(int handle) const; void recordLastValue(sensors_event_t const * buffer, size_t count); static void sortEventBuffer(sensors_event_t* buffer, size_t count); Sensor registerSensor(SensorInterface* sensor); diff --git a/services/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk index c3daa64d9..b2bc550c9 100644 --- a/services/surfaceflinger/Android.mk +++ b/services/surfaceflinger/Android.mk @@ -51,6 +51,10 @@ ifeq ($(TARGET_DISABLE_TRIPLE_BUFFERING),true) LOCAL_CFLAGS += -DTARGET_DISABLE_TRIPLE_BUFFERING endif +ifeq ($(TARGET_FORCE_HWC_FOR_VIRTUAL_DISPLAYS),true) + LOCAL_CFLAGS += -DFORCE_HWC_COPY_FOR_VIRTUAL_DISPLAYS +endif + ifneq ($(NUM_FRAMEBUFFER_SURFACE_BUFFERS),) LOCAL_CFLAGS += -DNUM_FRAMEBUFFER_SURFACE_BUFFERS=$(NUM_FRAMEBUFFER_SURFACE_BUFFERS) endif diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp index 2469f0cf6..c7d1a903e 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp +++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp @@ -605,7 +605,7 @@ status_t HWComposer::prepare() { mLists[i] = disp.list; if (mLists[i]) { if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_3)) { - mLists[i]->outbuf = NULL; + mLists[i]->outbuf = disp.outbufHandle; mLists[i]->outbufAcquireFenceFd = -1; } else if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) { // garbage data to catch improper use diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp index c5a14b076..be5cf4a88 100644 --- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp +++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp @@ -22,6 +22,12 @@ namespace android { // --------------------------------------------------------------------------- +#if defined(FORCE_HWC_COPY_FOR_VIRTUAL_DISPLAYS) +static const bool sForceHwcCopy = true; +#else +static const bool sForceHwcCopy = false; +#endif + #define VDS_LOGE(msg, ...) ALOGE("[%s] "msg, \ mDisplayName.string(), ##__VA_ARGS__) #define VDS_LOGW_IF(cond, msg, ...) ALOGW_IF(cond, "[%s] "msg, \ @@ -47,7 +53,7 @@ VirtualDisplaySurface::VirtualDisplaySurface(HWComposer& hwc, int32_t dispId, mHwc(hwc), mDisplayId(dispId), mDisplayName(name), - mProducerUsage(GRALLOC_USAGE_HW_COMPOSER), + mOutputUsage(GRALLOC_USAGE_HW_COMPOSER), mProducerSlotSource(0), mDbgState(DBG_STATE_IDLE), mDbgLastCompositionType(COMPOSITION_UNKNOWN) @@ -58,8 +64,23 @@ VirtualDisplaySurface::VirtualDisplaySurface(HWComposer& hwc, int32_t dispId, resetPerFrameState(); int sinkWidth, sinkHeight; - mSource[SOURCE_SINK]->query(NATIVE_WINDOW_WIDTH, &sinkWidth); - mSource[SOURCE_SINK]->query(NATIVE_WINDOW_HEIGHT, &sinkHeight); + sink->query(NATIVE_WINDOW_WIDTH, &sinkWidth); + sink->query(NATIVE_WINDOW_HEIGHT, &sinkHeight); + + // Pick the buffer format to request from the sink when not rendering to it + // with GLES. If the consumer needs CPU access, use the default format + // set by the consumer. Otherwise allow gralloc to decide the format based + // on usage bits. + int sinkUsage; + sink->query(NATIVE_WINDOW_CONSUMER_USAGE_BITS, &sinkUsage); + if (sinkUsage & (GRALLOC_USAGE_SW_READ_MASK | GRALLOC_USAGE_SW_WRITE_MASK)) { + int sinkFormat; + sink->query(NATIVE_WINDOW_FORMAT, &sinkFormat); + mDefaultOutputFormat = sinkFormat; + } else { + mDefaultOutputFormat = HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED; + } + mOutputFormat = mDefaultOutputFormat; ConsumerBase::mName = String8::format("VDS: %s", mDisplayName.string()); mConsumer->setConsumerName(ConsumerBase::mName); @@ -95,6 +116,17 @@ status_t VirtualDisplaySurface::prepareFrame(CompositionType compositionType) { mDbgState = DBG_STATE_PREPARED; mCompositionType = compositionType; + if (sForceHwcCopy && mCompositionType == COMPOSITION_GLES) { + // Some hardware can do RGB->YUV conversion more efficiently in hardware + // controlled by HWC than in hardware controlled by the video encoder. + // Forcing GLES-composed frames to go through an extra copy by the HWC + // allows the format conversion to happen there, rather than passing RGB + // directly to the consumer. + // + // On the other hand, when the consumer prefers RGB or can consume RGB + // inexpensively, this forces an unnecessary copy. + mCompositionType = COMPOSITION_MIXED; + } if (mCompositionType != mDbgLastCompositionType) { VDS_LOGV("prepareFrame: composition type changed to %s", @@ -102,6 +134,24 @@ status_t VirtualDisplaySurface::prepareFrame(CompositionType compositionType) { mDbgLastCompositionType = mCompositionType; } + if (mCompositionType != COMPOSITION_GLES && + (mOutputFormat != mDefaultOutputFormat || + mOutputUsage != GRALLOC_USAGE_HW_COMPOSER)) { + // We must have just switched from GLES-only to MIXED or HWC + // composition. Stop using the format and usage requested by the GLES + // driver; they may be suboptimal when HWC is writing to the output + // buffer. For example, if the output is going to a video encoder, and + // HWC can write directly to YUV, some hardware can skip a + // memory-to-memory RGB-to-YUV conversion step. + // + // If we just switched *to* GLES-only mode, we'll change the + // format/usage and get a new buffer when the GLES driver calls + // dequeueBuffer(). + mOutputFormat = mDefaultOutputFormat; + mOutputUsage = GRALLOC_USAGE_HW_COMPOSER; + refreshOutputBuffer(); + } + return NO_ERROR; } @@ -124,14 +174,8 @@ status_t VirtualDisplaySurface::advanceFrame() { } mDbgState = DBG_STATE_HWC; - if (mCompositionType == COMPOSITION_HWC) { - // Use the output buffer for the FB as well, though conceptually the - // FB is unused on this frame. - mFbProducerSlot = mOutputProducerSlot; - mFbFence = mOutputFence; - } - - if (mFbProducerSlot < 0 || mOutputProducerSlot < 0) { + if (mOutputProducerSlot < 0 || + (mCompositionType != COMPOSITION_HWC && mFbProducerSlot < 0)) { // Last chance bailout if something bad happened earlier. For example, // in a GLES configuration, if the sink disappears then dequeueBuffer // will fail, the GLES driver won't queue a buffer, but SurfaceFlinger @@ -141,7 +185,8 @@ status_t VirtualDisplaySurface::advanceFrame() { return NO_MEMORY; } - sp fbBuffer = mProducerBuffers[mFbProducerSlot]; + sp fbBuffer = mFbProducerSlot >= 0 ? + mProducerBuffers[mFbProducerSlot] : sp(NULL); sp outBuffer = mProducerBuffers[mOutputProducerSlot]; VDS_LOGV("advanceFrame: fb=%d(%p) out=%d(%p)", mFbProducerSlot, fbBuffer.get(), @@ -151,7 +196,12 @@ status_t VirtualDisplaySurface::advanceFrame() { // so update HWC state with it. mHwc.setOutputBuffer(mDisplayId, mOutputFence, outBuffer); - return mHwc.fbPost(mDisplayId, mFbFence, fbBuffer); + status_t result = NO_ERROR; + if (fbBuffer != NULL) { + result = mHwc.fbPost(mDisplayId, mFbFence, fbBuffer); + } + + return result; } void VirtualDisplaySurface::onFrameCommitted() { @@ -212,12 +262,12 @@ status_t VirtualDisplaySurface::setBufferCount(int bufferCount) { } status_t VirtualDisplaySurface::dequeueBuffer(Source source, - uint32_t format, int* sslot, sp* fence) { + uint32_t format, uint32_t usage, int* sslot, sp* fence) { // Don't let a slow consumer block us bool async = (source == SOURCE_SINK); status_t result = mSource[source]->dequeueBuffer(sslot, fence, async, - mSinkBufferWidth, mSinkBufferHeight, format, mProducerUsage); + mSinkBufferWidth, mSinkBufferHeight, format, usage); if (result < 0) return result; int pslot = mapSource2ProducerSlot(source, *sslot); @@ -241,8 +291,10 @@ status_t VirtualDisplaySurface::dequeueBuffer(Source source, } if (result & BUFFER_NEEDS_REALLOCATION) { mSource[source]->requestBuffer(*sslot, &mProducerBuffers[pslot]); - VDS_LOGV("dequeueBuffer(%s): buffers[%d]=%p", - dbgSourceStr(source), pslot, mProducerBuffers[pslot].get()); + VDS_LOGV("dequeueBuffer(%s): buffers[%d]=%p fmt=%d usage=%#x", + dbgSourceStr(source), pslot, mProducerBuffers[pslot].get(), + mProducerBuffers[pslot]->getPixelFormat(), + mProducerBuffers[pslot]->getUsage()); } return result; @@ -258,7 +310,6 @@ status_t VirtualDisplaySurface::dequeueBuffer(int* pslot, sp* fence, bool VDS_LOGV("dequeueBuffer %dx%d fmt=%d usage=%#x", w, h, format, usage); status_t result = NO_ERROR; - mProducerUsage = usage | GRALLOC_USAGE_HW_COMPOSER; Source source = fbSourceForCompositionType(mCompositionType); if (source == SOURCE_SINK) { @@ -279,13 +330,20 @@ status_t VirtualDisplaySurface::dequeueBuffer(int* pslot, sp* fence, bool // prepare and set, but since we're in GLES-only mode already it // shouldn't matter. + usage |= GRALLOC_USAGE_HW_COMPOSER; const sp& buf = mProducerBuffers[mOutputProducerSlot]; - if ((mProducerUsage & ~buf->getUsage()) != 0 || + if ((usage & ~buf->getUsage()) != 0 || (format != 0 && format != (uint32_t)buf->getPixelFormat()) || (w != 0 && w != mSinkBufferWidth) || (h != 0 && h != mSinkBufferHeight)) { - VDS_LOGV("dequeueBuffer: output buffer doesn't satisfy GLES " - "request, getting a new buffer"); + VDS_LOGV("dequeueBuffer: dequeueing new output buffer: " + "want %dx%d fmt=%d use=%#x, " + "have %dx%d fmt=%d use=%#x", + w, h, format, usage, + mSinkBufferWidth, mSinkBufferHeight, + buf->getPixelFormat(), buf->getUsage()); + mOutputFormat = format; + mOutputUsage = usage; result = refreshOutputBuffer(); if (result < 0) return result; @@ -297,7 +355,7 @@ status_t VirtualDisplaySurface::dequeueBuffer(int* pslot, sp* fence, bool *fence = mOutputFence; } else { int sslot; - result = dequeueBuffer(source, format, &sslot, fence); + result = dequeueBuffer(source, format, usage, &sslot, fence); if (result >= 0) { *pslot = mapSource2ProducerSlot(source, sslot); } @@ -400,9 +458,7 @@ void VirtualDisplaySurface::resetPerFrameState() { mCompositionType = COMPOSITION_UNKNOWN; mSinkBufferWidth = 0; mSinkBufferHeight = 0; - mFbFence = Fence::NO_FENCE; mOutputFence = Fence::NO_FENCE; - mFbProducerSlot = -1; mOutputProducerSlot = -1; } @@ -414,7 +470,8 @@ status_t VirtualDisplaySurface::refreshOutputBuffer() { } int sslot; - status_t result = dequeueBuffer(SOURCE_SINK, 0, &sslot, &mOutputFence); + status_t result = dequeueBuffer(SOURCE_SINK, mOutputFormat, mOutputUsage, + &sslot, &mOutputFence); if (result < 0) return result; mOutputProducerSlot = mapSource2ProducerSlot(SOURCE_SINK, sslot); diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h index 18fb5a7e0..1e85ac4bd 100644 --- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h +++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h @@ -110,7 +110,7 @@ private: // Utility methods // static Source fbSourceForCompositionType(CompositionType type); - status_t dequeueBuffer(Source source, uint32_t format, + status_t dequeueBuffer(Source source, uint32_t format, uint32_t usage, int* sslot, sp* fence); void updateQueueBufferOutput(const QueueBufferOutput& qbo); void resetPerFrameState(); @@ -132,15 +132,18 @@ private: const int32_t mDisplayId; const String8 mDisplayName; sp mSource[2]; // indexed by SOURCE_* + uint32_t mDefaultOutputFormat; // // Inter-frame state // - // To avoid buffer reallocations, we track the buffer usage requested by - // the GLES driver in dequeueBuffer so we can use the same flags on - // HWC-only frames. - uint32_t mProducerUsage; + // To avoid buffer reallocations, we track the buffer usage and format + // we used on the previous frame and use it again on the new frame. If + // the composition type changes or the GLES driver starts requesting + // different usage/format, we'll get a new buffer. + uint32_t mOutputFormat; + uint32_t mOutputUsage; // Since we present a single producer interface to the GLES driver, but // are internally muxing between the sink and scratch producers, we have