summaryrefslogtreecommitdiffstats
path: root/libs/gui
diff options
context:
space:
mode:
Diffstat (limited to 'libs/gui')
-rw-r--r--libs/gui/Android.mk11
-rw-r--r--libs/gui/IGraphicBufferAlloc.cpp108
-rw-r--r--libs/gui/ISurface.cpp101
-rw-r--r--libs/gui/ISurfaceComposer.cpp326
-rw-r--r--libs/gui/ISurfaceComposerClient.cpp231
-rw-r--r--libs/gui/LayerState.cpp61
-rw-r--r--libs/gui/SharedBufferStack.cpp714
-rw-r--r--libs/gui/Surface.cpp1152
-rw-r--r--libs/gui/SurfaceComposerClient.cpp611
-rw-r--r--libs/gui/tests/Android.mk2
-rw-r--r--libs/gui/tests/Surface_test.cpp141
11 files changed, 3455 insertions, 3 deletions
diff --git a/libs/gui/Android.mk b/libs/gui/Android.mk
index d1a6af1..58bb0d3 100644
--- a/libs/gui/Android.mk
+++ b/libs/gui/Android.mk
@@ -10,7 +10,15 @@ LOCAL_SRC_FILES:= \
SensorEventQueue.cpp \
SensorManager.cpp \
SurfaceTexture.cpp \
- SurfaceTextureClient.cpp
+ SurfaceTextureClient.cpp \
+ ISurfaceComposer.cpp \
+ ISurface.cpp \
+ ISurfaceComposerClient.cpp \
+ IGraphicBufferAlloc.cpp \
+ LayerState.cpp \
+ SharedBufferStack.cpp \
+ Surface.cpp \
+ SurfaceComposerClient.cpp \
LOCAL_SHARED_LIBRARIES := \
libcutils \
@@ -21,7 +29,6 @@ LOCAL_SHARED_LIBRARIES := \
libui \
libEGL \
libGLESv2 \
- libsurfaceflinger_client
LOCAL_MODULE:= libgui
diff --git a/libs/gui/IGraphicBufferAlloc.cpp b/libs/gui/IGraphicBufferAlloc.cpp
new file mode 100644
index 0000000..e05da72
--- /dev/null
+++ b/libs/gui/IGraphicBufferAlloc.cpp
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2011 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.
+ */
+
+// tag as surfaceflinger
+#define LOG_TAG "SurfaceFlinger"
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <binder/Parcel.h>
+
+#include <ui/GraphicBuffer.h>
+
+#include <surfaceflinger/IGraphicBufferAlloc.h>
+
+// ---------------------------------------------------------------------------
+
+namespace android {
+
+enum {
+ CREATE_GRAPHIC_BUFFER = IBinder::FIRST_CALL_TRANSACTION,
+ FREE_ALL_GRAPHIC_BUFFERS_EXCEPT,
+};
+
+class BpGraphicBufferAlloc : public BpInterface<IGraphicBufferAlloc>
+{
+public:
+ BpGraphicBufferAlloc(const sp<IBinder>& impl)
+ : BpInterface<IGraphicBufferAlloc>(impl)
+ {
+ }
+
+ virtual sp<GraphicBuffer> createGraphicBuffer(uint32_t w, uint32_t h,
+ PixelFormat format, uint32_t usage) {
+ Parcel data, reply;
+ data.writeInterfaceToken(
+ IGraphicBufferAlloc::getInterfaceDescriptor());
+ data.writeInt32(w);
+ data.writeInt32(h);
+ data.writeInt32(format);
+ data.writeInt32(usage);
+ remote()->transact(CREATE_GRAPHIC_BUFFER, data, &reply);
+ sp<GraphicBuffer> graphicBuffer;
+ bool nonNull = (bool)reply.readInt32();
+ if (nonNull) {
+ graphicBuffer = new GraphicBuffer();
+ reply.read(*graphicBuffer);
+ }
+ return graphicBuffer;
+ }
+
+ virtual void freeAllGraphicBuffersExcept(int bufIdx) {
+ Parcel data, reply;
+ data.writeInterfaceToken(
+ IGraphicBufferAlloc::getInterfaceDescriptor());
+ data.writeInt32(bufIdx);
+ remote()->transact(FREE_ALL_GRAPHIC_BUFFERS_EXCEPT, data, &reply);
+ }
+};
+
+IMPLEMENT_META_INTERFACE(GraphicBufferAlloc, "android.ui.IGraphicBufferAlloc");
+
+// ----------------------------------------------------------------------
+
+status_t BnGraphicBufferAlloc::onTransact(
+ uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+ // codes that don't require permission check
+
+ switch(code) {
+ case CREATE_GRAPHIC_BUFFER: {
+ CHECK_INTERFACE(IGraphicBufferAlloc, data, reply);
+ uint32_t w = data.readInt32();
+ uint32_t h = data.readInt32();
+ PixelFormat format = data.readInt32();
+ uint32_t usage = data.readInt32();
+ sp<GraphicBuffer> result(createGraphicBuffer(w, h, format, usage));
+ reply->writeInt32(result != 0);
+ if (result != 0) {
+ reply->write(*result);
+ }
+ return NO_ERROR;
+ } break;
+ case FREE_ALL_GRAPHIC_BUFFERS_EXCEPT: {
+ CHECK_INTERFACE(IGraphicBufferAlloc, data, reply);
+ int bufIdx = data.readInt32();
+ freeAllGraphicBuffersExcept(bufIdx);
+ return NO_ERROR;
+ } break;
+ default:
+ return BBinder::onTransact(code, data, reply, flags);
+ }
+}
+
+}; // namespace android
diff --git a/libs/gui/ISurface.cpp b/libs/gui/ISurface.cpp
new file mode 100644
index 0000000..23b90af
--- /dev/null
+++ b/libs/gui/ISurface.cpp
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "ISurface"
+
+#include <stdio.h>
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <binder/Parcel.h>
+
+#include <ui/GraphicBuffer.h>
+
+#include <surfaceflinger/Surface.h>
+#include <surfaceflinger/ISurface.h>
+
+namespace android {
+
+// ----------------------------------------------------------------------
+
+class BpSurface : public BpInterface<ISurface>
+{
+public:
+ BpSurface(const sp<IBinder>& impl)
+ : BpInterface<ISurface>(impl)
+ {
+ }
+
+ virtual sp<GraphicBuffer> requestBuffer(int bufferIdx,
+ uint32_t w, uint32_t h, uint32_t format, uint32_t usage)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(ISurface::getInterfaceDescriptor());
+ data.writeInt32(bufferIdx);
+ data.writeInt32(w);
+ data.writeInt32(h);
+ data.writeInt32(format);
+ data.writeInt32(usage);
+ remote()->transact(REQUEST_BUFFER, data, &reply);
+ sp<GraphicBuffer> buffer = new GraphicBuffer();
+ reply.read(*buffer);
+ return buffer;
+ }
+
+ virtual status_t setBufferCount(int bufferCount)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(ISurface::getInterfaceDescriptor());
+ data.writeInt32(bufferCount);
+ remote()->transact(SET_BUFFER_COUNT, data, &reply);
+ status_t err = reply.readInt32();
+ return err;
+ }
+};
+
+IMPLEMENT_META_INTERFACE(Surface, "android.ui.ISurface");
+
+// ----------------------------------------------------------------------
+
+status_t BnSurface::onTransact(
+ uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+ switch(code) {
+ case REQUEST_BUFFER: {
+ CHECK_INTERFACE(ISurface, data, reply);
+ int bufferIdx = data.readInt32();
+ uint32_t w = data.readInt32();
+ uint32_t h = data.readInt32();
+ uint32_t format = data.readInt32();
+ uint32_t usage = data.readInt32();
+ sp<GraphicBuffer> buffer(requestBuffer(bufferIdx, w, h, format, usage));
+ if (buffer == NULL)
+ return BAD_VALUE;
+ return reply->write(*buffer);
+ }
+ case SET_BUFFER_COUNT: {
+ CHECK_INTERFACE(ISurface, data, reply);
+ int bufferCount = data.readInt32();
+ status_t err = setBufferCount(bufferCount);
+ reply->writeInt32(err);
+ return NO_ERROR;
+ }
+ default:
+ return BBinder::onTransact(code, data, reply, flags);
+ }
+}
+
+}; // namespace android
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
new file mode 100644
index 0000000..8951c3f
--- /dev/null
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -0,0 +1,326 @@
+/*
+ * Copyright (C) 2007 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.
+ */
+
+// tag as surfaceflinger
+#define LOG_TAG "SurfaceFlinger"
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <binder/Parcel.h>
+#include <binder/IMemory.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+
+#include <surfaceflinger/ISurfaceComposer.h>
+
+#include <ui/DisplayInfo.h>
+
+#include <utils/Log.h>
+
+// ---------------------------------------------------------------------------
+
+#define LIKELY( exp ) (__builtin_expect( (exp) != 0, true ))
+#define UNLIKELY( exp ) (__builtin_expect( (exp) != 0, false ))
+
+// ---------------------------------------------------------------------------
+
+namespace android {
+
+class BpSurfaceComposer : public BpInterface<ISurfaceComposer>
+{
+public:
+ BpSurfaceComposer(const sp<IBinder>& impl)
+ : BpInterface<ISurfaceComposer>(impl)
+ {
+ }
+
+ virtual sp<ISurfaceComposerClient> createConnection()
+ {
+ uint32_t n;
+ Parcel data, reply;
+ data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+ remote()->transact(BnSurfaceComposer::CREATE_CONNECTION, data, &reply);
+ return interface_cast<ISurfaceComposerClient>(reply.readStrongBinder());
+ }
+
+ virtual sp<ISurfaceComposerClient> createClientConnection()
+ {
+ uint32_t n;
+ Parcel data, reply;
+ data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+ remote()->transact(BnSurfaceComposer::CREATE_CLIENT_CONNECTION, data, &reply);
+ return interface_cast<ISurfaceComposerClient>(reply.readStrongBinder());
+ }
+
+ virtual sp<IGraphicBufferAlloc> createGraphicBufferAlloc()
+ {
+ uint32_t n;
+ Parcel data, reply;
+ data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+ remote()->transact(BnSurfaceComposer::CREATE_GRAPHIC_BUFFER_ALLOC, data, &reply);
+ return interface_cast<IGraphicBufferAlloc>(reply.readStrongBinder());
+ }
+
+ virtual sp<IMemoryHeap> getCblk() const
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+ remote()->transact(BnSurfaceComposer::GET_CBLK, data, &reply);
+ return interface_cast<IMemoryHeap>(reply.readStrongBinder());
+ }
+
+ virtual void openGlobalTransaction()
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+ remote()->transact(BnSurfaceComposer::OPEN_GLOBAL_TRANSACTION, data, &reply);
+ }
+
+ virtual void closeGlobalTransaction()
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+ remote()->transact(BnSurfaceComposer::CLOSE_GLOBAL_TRANSACTION, data, &reply);
+ }
+
+ virtual status_t freezeDisplay(DisplayID dpy, uint32_t flags)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+ data.writeInt32(dpy);
+ data.writeInt32(flags);
+ remote()->transact(BnSurfaceComposer::FREEZE_DISPLAY, data, &reply);
+ return reply.readInt32();
+ }
+
+ virtual status_t unfreezeDisplay(DisplayID dpy, uint32_t flags)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+ data.writeInt32(dpy);
+ data.writeInt32(flags);
+ remote()->transact(BnSurfaceComposer::UNFREEZE_DISPLAY, data, &reply);
+ return reply.readInt32();
+ }
+
+ virtual int setOrientation(DisplayID dpy, int orientation, uint32_t flags)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+ data.writeInt32(dpy);
+ data.writeInt32(orientation);
+ data.writeInt32(flags);
+ remote()->transact(BnSurfaceComposer::SET_ORIENTATION, data, &reply);
+ return reply.readInt32();
+ }
+
+ virtual void bootFinished()
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+ remote()->transact(BnSurfaceComposer::BOOT_FINISHED, data, &reply);
+ }
+
+ virtual status_t captureScreen(DisplayID dpy,
+ sp<IMemoryHeap>* heap,
+ uint32_t* width, uint32_t* height, PixelFormat* format,
+ uint32_t reqWidth, uint32_t reqHeight,
+ uint32_t minLayerZ, uint32_t maxLayerZ)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+ data.writeInt32(dpy);
+ data.writeInt32(reqWidth);
+ data.writeInt32(reqHeight);
+ data.writeInt32(minLayerZ);
+ data.writeInt32(maxLayerZ);
+ remote()->transact(BnSurfaceComposer::CAPTURE_SCREEN, data, &reply);
+ *heap = interface_cast<IMemoryHeap>(reply.readStrongBinder());
+ *width = reply.readInt32();
+ *height = reply.readInt32();
+ *format = reply.readInt32();
+ return reply.readInt32();
+ }
+
+ virtual status_t turnElectronBeamOff(int32_t mode)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+ data.writeInt32(mode);
+ remote()->transact(BnSurfaceComposer::TURN_ELECTRON_BEAM_OFF, data, &reply);
+ return reply.readInt32();
+ }
+
+ virtual status_t turnElectronBeamOn(int32_t mode)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+ data.writeInt32(mode);
+ remote()->transact(BnSurfaceComposer::TURN_ELECTRON_BEAM_ON, data, &reply);
+ return reply.readInt32();
+ }
+
+ virtual void signal() const
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+ remote()->transact(BnSurfaceComposer::SIGNAL, data, &reply, IBinder::FLAG_ONEWAY);
+ }
+
+ virtual bool authenticateSurface(const sp<ISurface>& surface) const
+ {
+ Parcel data, reply;
+ int err = NO_ERROR;
+ err = data.writeInterfaceToken(
+ ISurfaceComposer::getInterfaceDescriptor());
+ if (err != NO_ERROR) {
+ LOGE("ISurfaceComposer::authenticateSurface: error writing "
+ "interface descriptor: %s (%d)", strerror(-err), -err);
+ return false;
+ }
+ err = data.writeStrongBinder(surface->asBinder());
+ if (err != NO_ERROR) {
+ LOGE("ISurfaceComposer::authenticateSurface: error writing strong "
+ "binder to parcel: %s (%d)", strerror(-err), -err);
+ return false;
+ }
+ err = remote()->transact(BnSurfaceComposer::AUTHENTICATE_SURFACE, data,
+ &reply);
+ if (err != NO_ERROR) {
+ LOGE("ISurfaceComposer::authenticateSurface: error performing "
+ "transaction: %s (%d)", strerror(-err), -err);
+ return false;
+ }
+ int32_t result = 0;
+ err = reply.readInt32(&result);
+ if (err != NO_ERROR) {
+ LOGE("ISurfaceComposer::authenticateSurface: error retrieving "
+ "result: %s (%d)", strerror(-err), -err);
+ return false;
+ }
+ return result != 0;
+ }
+};
+
+IMPLEMENT_META_INTERFACE(SurfaceComposer, "android.ui.ISurfaceComposer");
+
+// ----------------------------------------------------------------------
+
+status_t BnSurfaceComposer::onTransact(
+ uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+ switch(code) {
+ case CREATE_CONNECTION: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
+ sp<IBinder> b = createConnection()->asBinder();
+ reply->writeStrongBinder(b);
+ } break;
+ case CREATE_CLIENT_CONNECTION: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
+ sp<IBinder> b = createClientConnection()->asBinder();
+ reply->writeStrongBinder(b);
+ } break;
+ case CREATE_GRAPHIC_BUFFER_ALLOC: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
+ sp<IBinder> b = createGraphicBufferAlloc()->asBinder();
+ reply->writeStrongBinder(b);
+ } break;
+ case OPEN_GLOBAL_TRANSACTION: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
+ openGlobalTransaction();
+ } break;
+ case CLOSE_GLOBAL_TRANSACTION: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
+ closeGlobalTransaction();
+ } break;
+ case SET_ORIENTATION: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
+ DisplayID dpy = data.readInt32();
+ int orientation = data.readInt32();
+ uint32_t flags = data.readInt32();
+ reply->writeInt32( setOrientation(dpy, orientation, flags) );
+ } break;
+ case FREEZE_DISPLAY: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
+ DisplayID dpy = data.readInt32();
+ uint32_t flags = data.readInt32();
+ reply->writeInt32( freezeDisplay(dpy, flags) );
+ } break;
+ case UNFREEZE_DISPLAY: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
+ DisplayID dpy = data.readInt32();
+ uint32_t flags = data.readInt32();
+ reply->writeInt32( unfreezeDisplay(dpy, flags) );
+ } break;
+ case BOOT_FINISHED: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
+ bootFinished();
+ } break;
+ case SIGNAL: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
+ signal();
+ } break;
+ case GET_CBLK: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
+ sp<IBinder> b = getCblk()->asBinder();
+ reply->writeStrongBinder(b);
+ } break;
+ case CAPTURE_SCREEN: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
+ DisplayID dpy = data.readInt32();
+ uint32_t reqWidth = data.readInt32();
+ uint32_t reqHeight = data.readInt32();
+ uint32_t minLayerZ = data.readInt32();
+ uint32_t maxLayerZ = data.readInt32();
+ sp<IMemoryHeap> heap;
+ uint32_t w, h;
+ PixelFormat f;
+ status_t res = captureScreen(dpy, &heap, &w, &h, &f,
+ reqWidth, reqHeight, minLayerZ, maxLayerZ);
+ reply->writeStrongBinder(heap->asBinder());
+ reply->writeInt32(w);
+ reply->writeInt32(h);
+ reply->writeInt32(f);
+ reply->writeInt32(res);
+ } break;
+ case TURN_ELECTRON_BEAM_OFF: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
+ int32_t mode = data.readInt32();
+ status_t res = turnElectronBeamOff(mode);
+ reply->writeInt32(res);
+ } break;
+ case TURN_ELECTRON_BEAM_ON: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
+ int32_t mode = data.readInt32();
+ status_t res = turnElectronBeamOn(mode);
+ reply->writeInt32(res);
+ } break;
+ case AUTHENTICATE_SURFACE: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
+ sp<ISurface> surface = interface_cast<ISurface>(data.readStrongBinder());
+ int32_t result = authenticateSurface(surface) ? 1 : 0;
+ reply->writeInt32(result);
+ } break;
+ default:
+ return BBinder::onTransact(code, data, reply, flags);
+ }
+ return NO_ERROR;
+}
+
+// ----------------------------------------------------------------------------
+
+};
diff --git a/libs/gui/ISurfaceComposerClient.cpp b/libs/gui/ISurfaceComposerClient.cpp
new file mode 100644
index 0000000..7730eb1
--- /dev/null
+++ b/libs/gui/ISurfaceComposerClient.cpp
@@ -0,0 +1,231 @@
+/*
+ * Copyright (C) 2007 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.
+ */
+
+// tag as surfaceflinger
+#define LOG_TAG "SurfaceFlinger"
+
+#include <stdio.h>
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <binder/Parcel.h>
+#include <binder/IMemory.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+
+#include <ui/Point.h>
+#include <ui/Rect.h>
+
+#include <surfaceflinger/ISurface.h>
+#include <surfaceflinger/ISurfaceComposerClient.h>
+#include <private/surfaceflinger/LayerState.h>
+
+// ---------------------------------------------------------------------------
+
+/* ideally AID_GRAPHICS would be in a semi-public header
+ * or there would be a way to map a user/group name to its id
+ */
+#ifndef AID_GRAPHICS
+#define AID_GRAPHICS 1003
+#endif
+
+#define LIKELY( exp ) (__builtin_expect( (exp) != 0, true ))
+#define UNLIKELY( exp ) (__builtin_expect( (exp) != 0, false ))
+
+// ---------------------------------------------------------------------------
+
+namespace android {
+
+enum {
+ GET_CBLK = IBinder::FIRST_CALL_TRANSACTION,
+ GET_TOKEN,
+ CREATE_SURFACE,
+ DESTROY_SURFACE,
+ SET_STATE
+};
+
+class BpSurfaceComposerClient : public BpInterface<ISurfaceComposerClient>
+{
+public:
+ BpSurfaceComposerClient(const sp<IBinder>& impl)
+ : BpInterface<ISurfaceComposerClient>(impl)
+ {
+ }
+
+ virtual sp<IMemoryHeap> getControlBlock() const
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(ISurfaceComposerClient::getInterfaceDescriptor());
+ remote()->transact(GET_CBLK, data, &reply);
+ return interface_cast<IMemoryHeap>(reply.readStrongBinder());
+ }
+
+ virtual ssize_t getTokenForSurface(const sp<ISurface>& sur) const
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(ISurfaceComposerClient::getInterfaceDescriptor());
+ data.writeStrongBinder(sur->asBinder());
+ remote()->transact(GET_TOKEN, data, &reply);
+ return reply.readInt32();
+ }
+
+ virtual sp<ISurface> createSurface( surface_data_t* params,
+ int pid,
+ const String8& name,
+ DisplayID display,
+ uint32_t w,
+ uint32_t h,
+ PixelFormat format,
+ uint32_t flags)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(ISurfaceComposerClient::getInterfaceDescriptor());
+ data.writeInt32(pid);
+ data.writeString8(name);
+ data.writeInt32(display);
+ data.writeInt32(w);
+ data.writeInt32(h);
+ data.writeInt32(format);
+ data.writeInt32(flags);
+ remote()->transact(CREATE_SURFACE, data, &reply);
+ params->readFromParcel(reply);
+ return interface_cast<ISurface>(reply.readStrongBinder());
+ }
+
+ virtual status_t destroySurface(SurfaceID sid)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(ISurfaceComposerClient::getInterfaceDescriptor());
+ data.writeInt32(sid);
+ remote()->transact(DESTROY_SURFACE, data, &reply);
+ return reply.readInt32();
+ }
+
+ virtual status_t setState(int32_t count, const layer_state_t* states)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(ISurfaceComposerClient::getInterfaceDescriptor());
+ data.writeInt32(count);
+ for (int i=0 ; i<count ; i++)
+ states[i].write(data);
+ remote()->transact(SET_STATE, data, &reply);
+ return reply.readInt32();
+ }
+};
+
+IMPLEMENT_META_INTERFACE(SurfaceComposerClient, "android.ui.ISurfaceComposerClient");
+
+// ----------------------------------------------------------------------
+
+status_t BnSurfaceComposerClient::onTransact(
+ uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+ // codes that don't require permission check
+
+ switch(code) {
+ case GET_CBLK: {
+ CHECK_INTERFACE(ISurfaceComposerClient, data, reply);
+ sp<IMemoryHeap> ctl(getControlBlock());
+ reply->writeStrongBinder(ctl->asBinder());
+ return NO_ERROR;
+ } break;
+ case GET_TOKEN: {
+ CHECK_INTERFACE(ISurfaceComposerClient, data, reply);
+ sp<ISurface> sur = interface_cast<ISurface>(data.readStrongBinder());
+ ssize_t token = getTokenForSurface(sur);
+ reply->writeInt32(token);
+ return NO_ERROR;
+ } break;
+ }
+
+ // these must be checked
+
+ IPCThreadState* ipc = IPCThreadState::self();
+ const int pid = ipc->getCallingPid();
+ const int uid = ipc->getCallingUid();
+ const int self_pid = getpid();
+ if (UNLIKELY(pid != self_pid && uid != AID_GRAPHICS && uid != 0)) {
+ // we're called from a different process, do the real check
+ if (!checkCallingPermission(
+ String16("android.permission.ACCESS_SURFACE_FLINGER")))
+ {
+ LOGE("Permission Denial: "
+ "can't openGlobalTransaction pid=%d, uid=%d", pid, uid);
+ return PERMISSION_DENIED;
+ }
+ }
+
+ switch(code) {
+ case CREATE_SURFACE: {
+ CHECK_INTERFACE(ISurfaceComposerClient, data, reply);
+ surface_data_t params;
+ int32_t pid = data.readInt32();
+ String8 name = data.readString8();
+ DisplayID display = data.readInt32();
+ uint32_t w = data.readInt32();
+ uint32_t h = data.readInt32();
+ PixelFormat format = data.readInt32();
+ uint32_t flags = data.readInt32();
+ sp<ISurface> s = createSurface(&params, pid, name, display, w, h,
+ format, flags);
+ params.writeToParcel(reply);
+ reply->writeStrongBinder(s->asBinder());
+ return NO_ERROR;
+ } break;
+ case DESTROY_SURFACE: {
+ CHECK_INTERFACE(ISurfaceComposerClient, data, reply);
+ reply->writeInt32( destroySurface( data.readInt32() ) );
+ return NO_ERROR;
+ } break;
+ case SET_STATE: {
+ CHECK_INTERFACE(ISurfaceComposerClient, data, reply);
+ int32_t count = data.readInt32();
+ layer_state_t* states = new layer_state_t[count];
+ for (int i=0 ; i<count ; i++)
+ states[i].read(data);
+ status_t err = setState(count, states);
+ delete [] states;
+ reply->writeInt32(err);
+ return NO_ERROR;
+ } break;
+ default:
+ return BBinder::onTransact(code, data, reply, flags);
+ }
+}
+
+// ----------------------------------------------------------------------
+
+status_t ISurfaceComposerClient::surface_data_t::readFromParcel(const Parcel& parcel)
+{
+ token = parcel.readInt32();
+ identity = parcel.readInt32();
+ width = parcel.readInt32();
+ height = parcel.readInt32();
+ format = parcel.readInt32();
+ return NO_ERROR;
+}
+
+status_t ISurfaceComposerClient::surface_data_t::writeToParcel(Parcel* parcel) const
+{
+ parcel->writeInt32(token);
+ parcel->writeInt32(identity);
+ parcel->writeInt32(width);
+ parcel->writeInt32(height);
+ parcel->writeInt32(format);
+ return NO_ERROR;
+}
+
+}; // namespace android
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
new file mode 100644
index 0000000..01c4c7e
--- /dev/null
+++ b/libs/gui/LayerState.cpp
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <utils/Errors.h>
+#include <binder/Parcel.h>
+#include <private/surfaceflinger/LayerState.h>
+
+namespace android {
+
+status_t layer_state_t::write(Parcel& output) const
+{
+ status_t err;
+
+ size_t len = transparentRegion.write(NULL, 0);
+ err = output.writeInt32(len);
+ if (err < NO_ERROR) return err;
+
+ void* buf = output.writeInplace(len);
+ if (buf == NULL) return NO_MEMORY;
+
+ err = transparentRegion.write(buf, len);
+ if (err < NO_ERROR) return err;
+
+ // NOTE: regions are at the end of the structure
+ size_t size = sizeof(layer_state_t);
+ size -= sizeof(transparentRegion);
+ err = output.write(this, size);
+ return err;
+}
+
+status_t layer_state_t::read(const Parcel& input)
+{
+ status_t err;
+ size_t len = input.readInt32();
+ void const* buf = input.readInplace(len);
+ if (buf == NULL) return NO_MEMORY;
+
+ err = transparentRegion.read(buf);
+ if (err < NO_ERROR) return err;
+
+ // NOTE: regions are at the end of the structure
+ size_t size = sizeof(layer_state_t);
+ size -= sizeof(transparentRegion);
+ input.read(this, size);
+ return NO_ERROR;
+}
+
+}; // namespace android
diff --git a/libs/gui/SharedBufferStack.cpp b/libs/gui/SharedBufferStack.cpp
new file mode 100644
index 0000000..7505d53
--- /dev/null
+++ b/libs/gui/SharedBufferStack.cpp
@@ -0,0 +1,714 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "SharedBufferStack"
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Debug.h>
+#include <utils/Log.h>
+#include <utils/threads.h>
+
+#include <private/surfaceflinger/SharedBufferStack.h>
+
+#include <ui/Rect.h>
+#include <ui/Region.h>
+
+#define DEBUG_ATOMICS 0
+
+namespace android {
+// ----------------------------------------------------------------------------
+
+SharedClient::SharedClient()
+ : lock(Mutex::SHARED), cv(Condition::SHARED)
+{
+}
+
+SharedClient::~SharedClient() {
+}
+
+
+// these functions are used by the clients
+status_t SharedClient::validate(size_t i) const {
+ if (uint32_t(i) >= uint32_t(SharedBufferStack::NUM_LAYERS_MAX))
+ return BAD_INDEX;
+ return surfaces[i].status;
+}
+
+// ----------------------------------------------------------------------------
+
+
+SharedBufferStack::SharedBufferStack()
+{
+}
+
+void SharedBufferStack::init(int32_t i)
+{
+ status = NO_ERROR;
+ identity = i;
+}
+
+status_t SharedBufferStack::setCrop(int buffer, const Rect& crop)
+{
+ if (uint32_t(buffer) >= NUM_BUFFER_MAX)
+ return BAD_INDEX;
+
+ buffers[buffer].crop.l = uint16_t(crop.left);
+ buffers[buffer].crop.t = uint16_t(crop.top);
+ buffers[buffer].crop.r = uint16_t(crop.right);
+ buffers[buffer].crop.b = uint16_t(crop.bottom);
+ return NO_ERROR;
+}
+
+status_t SharedBufferStack::setTransform(int buffer, uint8_t transform)
+{
+ if (uint32_t(buffer) >= NUM_BUFFER_MAX)
+ return BAD_INDEX;
+ buffers[buffer].transform = transform;
+ return NO_ERROR;
+}
+
+status_t SharedBufferStack::setDirtyRegion(int buffer, const Region& dirty)
+{
+ if (uint32_t(buffer) >= NUM_BUFFER_MAX)
+ return BAD_INDEX;
+
+ FlatRegion& reg(buffers[buffer].dirtyRegion);
+ if (dirty.isEmpty()) {
+ reg.count = 0;
+ return NO_ERROR;
+ }
+
+ size_t count;
+ Rect const* r = dirty.getArray(&count);
+ if (count > FlatRegion::NUM_RECT_MAX) {
+ const Rect bounds(dirty.getBounds());
+ reg.count = 1;
+ reg.rects[0].l = uint16_t(bounds.left);
+ reg.rects[0].t = uint16_t(bounds.top);
+ reg.rects[0].r = uint16_t(bounds.right);
+ reg.rects[0].b = uint16_t(bounds.bottom);
+ } else {
+ reg.count = count;
+ for (size_t i=0 ; i<count ; i++) {
+ reg.rects[i].l = uint16_t(r[i].left);
+ reg.rects[i].t = uint16_t(r[i].top);
+ reg.rects[i].r = uint16_t(r[i].right);
+ reg.rects[i].b = uint16_t(r[i].bottom);
+ }
+ }
+ return NO_ERROR;
+}
+
+Region SharedBufferStack::getDirtyRegion(int buffer) const
+{
+ Region res;
+ if (uint32_t(buffer) >= NUM_BUFFER_MAX)
+ return res;
+
+ const FlatRegion& reg(buffers[buffer].dirtyRegion);
+ if (reg.count > FlatRegion::NUM_RECT_MAX)
+ return res;
+
+ if (reg.count == 1) {
+ const Rect r(
+ reg.rects[0].l,
+ reg.rects[0].t,
+ reg.rects[0].r,
+ reg.rects[0].b);
+ res.set(r);
+ } else {
+ for (size_t i=0 ; i<reg.count ; i++) {
+ const Rect r(
+ reg.rects[i].l,
+ reg.rects[i].t,
+ reg.rects[i].r,
+ reg.rects[i].b);
+ res.orSelf(r);
+ }
+ }
+ return res;
+}
+
+Rect SharedBufferStack::getCrop(int buffer) const
+{
+ Rect res(-1, -1);
+ if (uint32_t(buffer) >= NUM_BUFFER_MAX)
+ return res;
+ res.left = buffers[buffer].crop.l;
+ res.top = buffers[buffer].crop.t;
+ res.right = buffers[buffer].crop.r;
+ res.bottom = buffers[buffer].crop.b;
+ return res;
+}
+
+uint32_t SharedBufferStack::getTransform(int buffer) const
+{
+ if (uint32_t(buffer) >= NUM_BUFFER_MAX)
+ return 0;
+ return buffers[buffer].transform;
+}
+
+
+// ----------------------------------------------------------------------------
+
+SharedBufferBase::SharedBufferBase(SharedClient* sharedClient,
+ int surface, int32_t identity)
+ : mSharedClient(sharedClient),
+ mSharedStack(sharedClient->surfaces + surface),
+ mIdentity(identity)
+{
+}
+
+SharedBufferBase::~SharedBufferBase()
+{
+}
+
+status_t SharedBufferBase::getStatus() const
+{
+ SharedBufferStack& stack( *mSharedStack );
+ return stack.status;
+}
+
+int32_t SharedBufferBase::getIdentity() const
+{
+ SharedBufferStack& stack( *mSharedStack );
+ return stack.identity;
+}
+
+String8 SharedBufferBase::dump(char const* prefix) const
+{
+ const size_t SIZE = 1024;
+ char buffer[SIZE];
+ String8 result;
+ SharedBufferStack& stack( *mSharedStack );
+ snprintf(buffer, SIZE,
+ "%s[ head=%2d, available=%2d, queued=%2d ] "
+ "reallocMask=%08x, identity=%d, status=%d",
+ prefix, stack.head, stack.available, stack.queued,
+ stack.reallocMask, stack.identity, stack.status);
+ result.append(buffer);
+ result.append("\n");
+ return result;
+}
+
+status_t SharedBufferBase::waitForCondition(const ConditionBase& condition)
+{
+ const SharedBufferStack& stack( *mSharedStack );
+ SharedClient& client( *mSharedClient );
+ const nsecs_t TIMEOUT = s2ns(1);
+ const int identity = mIdentity;
+
+ Mutex::Autolock _l(client.lock);
+ while ((condition()==false) &&
+ (stack.identity == identity) &&
+ (stack.status == NO_ERROR))
+ {
+ status_t err = client.cv.waitRelative(client.lock, TIMEOUT);
+ // handle errors and timeouts
+ if (CC_UNLIKELY(err != NO_ERROR)) {
+ if (err == TIMED_OUT) {
+ if (condition()) {
+ LOGE("waitForCondition(%s) timed out (identity=%d), "
+ "but condition is true! We recovered but it "
+ "shouldn't happen." , condition.name(), stack.identity);
+ break;
+ } else {
+ LOGW("waitForCondition(%s) timed out "
+ "(identity=%d, status=%d). "
+ "CPU may be pegged. trying again.", condition.name(),
+ stack.identity, stack.status);
+ }
+ } else {
+ LOGE("waitForCondition(%s) error (%s) ",
+ condition.name(), strerror(-err));
+ return err;
+ }
+ }
+ }
+ return (stack.identity != mIdentity) ? status_t(BAD_INDEX) : stack.status;
+}
+// ============================================================================
+// conditions and updates
+// ============================================================================
+
+SharedBufferClient::DequeueCondition::DequeueCondition(
+ SharedBufferClient* sbc) : ConditionBase(sbc) {
+}
+bool SharedBufferClient::DequeueCondition::operator()() const {
+ return stack.available > 0;
+}
+
+SharedBufferClient::LockCondition::LockCondition(
+ SharedBufferClient* sbc, int buf) : ConditionBase(sbc), buf(buf) {
+}
+bool SharedBufferClient::LockCondition::operator()() const {
+ // NOTE: if stack.head is messed up, we could crash the client
+ // or cause some drawing artifacts. This is okay, as long as it is
+ // limited to the client.
+ return (buf != stack.index[stack.head]);
+}
+
+SharedBufferServer::BuffersAvailableCondition::BuffersAvailableCondition(
+ SharedBufferServer* sbs, int numBuffers) : ConditionBase(sbs),
+ mNumBuffers(numBuffers) {
+}
+bool SharedBufferServer::BuffersAvailableCondition::operator()() const {
+ return stack.available == mNumBuffers;
+}
+
+// ----------------------------------------------------------------------------
+
+SharedBufferClient::QueueUpdate::QueueUpdate(SharedBufferBase* sbb)
+ : UpdateBase(sbb) {
+}
+ssize_t SharedBufferClient::QueueUpdate::operator()() {
+ android_atomic_inc(&stack.queued);
+ return NO_ERROR;
+}
+
+SharedBufferClient::DequeueUpdate::DequeueUpdate(SharedBufferBase* sbb)
+ : UpdateBase(sbb) {
+}
+ssize_t SharedBufferClient::DequeueUpdate::operator()() {
+ if (android_atomic_dec(&stack.available) == 0) {
+ LOGW("dequeue probably called from multiple threads!");
+ }
+ return NO_ERROR;
+}
+
+SharedBufferClient::CancelUpdate::CancelUpdate(SharedBufferBase* sbb,
+ int tail, int buf)
+ : UpdateBase(sbb), tail(tail), buf(buf) {
+}
+ssize_t SharedBufferClient::CancelUpdate::operator()() {
+ stack.index[tail] = buf;
+ android_atomic_inc(&stack.available);
+ return NO_ERROR;
+}
+
+SharedBufferServer::RetireUpdate::RetireUpdate(
+ SharedBufferBase* sbb, int numBuffers)
+ : UpdateBase(sbb), numBuffers(numBuffers) {
+}
+ssize_t SharedBufferServer::RetireUpdate::operator()() {
+ int32_t head = stack.head;
+ if (uint32_t(head) >= SharedBufferStack::NUM_BUFFER_MAX)
+ return BAD_VALUE;
+
+ // Decrement the number of queued buffers
+ int32_t queued;
+ do {
+ queued = stack.queued;
+ if (queued == 0) {
+ return NOT_ENOUGH_DATA;
+ }
+ } while (android_atomic_cmpxchg(queued, queued-1, &stack.queued));
+
+ // lock the buffer before advancing head, which automatically unlocks
+ // the buffer we preventively locked upon entering this function
+
+ head = (head + 1) % numBuffers;
+ const int8_t headBuf = stack.index[head];
+ stack.headBuf = headBuf;
+
+ // head is only modified here, so we don't need to use cmpxchg
+ android_atomic_write(head, &stack.head);
+
+ // now that head has moved, we can increment the number of available buffers
+ android_atomic_inc(&stack.available);
+ return head;
+}
+
+SharedBufferServer::StatusUpdate::StatusUpdate(
+ SharedBufferBase* sbb, status_t status)
+ : UpdateBase(sbb), status(status) {
+}
+
+ssize_t SharedBufferServer::StatusUpdate::operator()() {
+ android_atomic_write(status, &stack.status);
+ return NO_ERROR;
+}
+
+// ============================================================================
+
+SharedBufferClient::SharedBufferClient(SharedClient* sharedClient,
+ int surface, int num, int32_t identity)
+ : SharedBufferBase(sharedClient, surface, identity),
+ mNumBuffers(num), tail(0)
+{
+ SharedBufferStack& stack( *mSharedStack );
+ tail = computeTail();
+ queued_head = stack.head;
+}
+
+int32_t SharedBufferClient::computeTail() const
+{
+ SharedBufferStack& stack( *mSharedStack );
+ return (mNumBuffers + stack.head - stack.available + 1) % mNumBuffers;
+}
+
+ssize_t SharedBufferClient::dequeue()
+{
+ SharedBufferStack& stack( *mSharedStack );
+
+ RWLock::AutoRLock _rd(mLock);
+
+ const nsecs_t dequeueTime = systemTime(SYSTEM_TIME_THREAD);
+
+ //LOGD("[%d] about to dequeue a buffer",
+ // mSharedStack->identity);
+ DequeueCondition condition(this);
+ status_t err = waitForCondition(condition);
+ if (err != NO_ERROR)
+ return ssize_t(err);
+
+ DequeueUpdate update(this);
+ updateCondition( update );
+
+ int dequeued = stack.index[tail];
+ tail = ((tail+1 >= mNumBuffers) ? 0 : tail+1);
+ LOGD_IF(DEBUG_ATOMICS, "dequeued=%d, tail++=%d, %s",
+ dequeued, tail, dump("").string());
+
+ mDequeueTime[dequeued] = dequeueTime;
+
+ return dequeued;
+}
+
+status_t SharedBufferClient::undoDequeue(int buf)
+{
+ return cancel(buf);
+}
+
+status_t SharedBufferClient::cancel(int buf)
+{
+ RWLock::AutoRLock _rd(mLock);
+
+ // calculate the new position of the tail index (essentially tail--)
+ int localTail = (tail + mNumBuffers - 1) % mNumBuffers;
+ CancelUpdate update(this, localTail, buf);
+ status_t err = updateCondition( update );
+ if (err == NO_ERROR) {
+ tail = localTail;
+ }
+ return err;
+}
+
+status_t SharedBufferClient::lock(int buf)
+{
+ RWLock::AutoRLock _rd(mLock);
+
+ SharedBufferStack& stack( *mSharedStack );
+ LockCondition condition(this, buf);
+ status_t err = waitForCondition(condition);
+ return err;
+}
+
+status_t SharedBufferClient::queue(int buf)
+{
+ RWLock::AutoRLock _rd(mLock);
+
+ SharedBufferStack& stack( *mSharedStack );
+
+ queued_head = (queued_head + 1) % mNumBuffers;
+ stack.index[queued_head] = buf;
+
+ QueueUpdate update(this);
+ status_t err = updateCondition( update );
+ LOGD_IF(DEBUG_ATOMICS, "queued=%d, %s", buf, dump("").string());
+
+ const nsecs_t now = systemTime(SYSTEM_TIME_THREAD);
+ stack.stats.totalTime = ns2us(now - mDequeueTime[buf]);
+
+ return err;
+}
+
+bool SharedBufferClient::needNewBuffer(int buf) const
+{
+ SharedBufferStack& stack( *mSharedStack );
+ const uint32_t mask = 1<<(31-buf);
+ return (android_atomic_and(~mask, &stack.reallocMask) & mask) != 0;
+}
+
+status_t SharedBufferClient::setCrop(int buf, const Rect& crop)
+{
+ SharedBufferStack& stack( *mSharedStack );
+ return stack.setCrop(buf, crop);
+}
+
+status_t SharedBufferClient::setTransform(int buf, uint32_t transform)
+{
+ SharedBufferStack& stack( *mSharedStack );
+ return stack.setTransform(buf, uint8_t(transform));
+}
+
+status_t SharedBufferClient::setDirtyRegion(int buf, const Region& reg)
+{
+ SharedBufferStack& stack( *mSharedStack );
+ return stack.setDirtyRegion(buf, reg);
+}
+
+status_t SharedBufferClient::setBufferCount(
+ int bufferCount, const SetBufferCountCallback& ipc)
+{
+ SharedBufferStack& stack( *mSharedStack );
+ if (uint32_t(bufferCount) >= SharedBufferStack::NUM_BUFFER_MAX)
+ return BAD_VALUE;
+
+ if (uint32_t(bufferCount) < SharedBufferStack::NUM_BUFFER_MIN)
+ return BAD_VALUE;
+
+ RWLock::AutoWLock _wr(mLock);
+
+ status_t err = ipc(bufferCount);
+ if (err == NO_ERROR) {
+ mNumBuffers = bufferCount;
+ queued_head = (stack.head + stack.queued) % mNumBuffers;
+ tail = computeTail();
+ }
+ return err;
+}
+
+// ----------------------------------------------------------------------------
+
+SharedBufferServer::SharedBufferServer(SharedClient* sharedClient,
+ int surface, int num, int32_t identity)
+ : SharedBufferBase(sharedClient, surface, identity),
+ mNumBuffers(num)
+{
+ mSharedStack->init(identity);
+ mSharedStack->token = surface;
+ mSharedStack->head = num-1;
+ mSharedStack->available = num;
+ mSharedStack->queued = 0;
+ mSharedStack->reallocMask = 0;
+ memset(mSharedStack->buffers, 0, sizeof(mSharedStack->buffers));
+ for (int i=0 ; i<num ; i++) {
+ mBufferList.add(i);
+ mSharedStack->index[i] = i;
+ }
+}
+
+SharedBufferServer::~SharedBufferServer()
+{
+}
+
+ssize_t SharedBufferServer::retireAndLock()
+{
+ RWLock::AutoRLock _l(mLock);
+
+ RetireUpdate update(this, mNumBuffers);
+ ssize_t buf = updateCondition( update );
+ if (buf >= 0) {
+ if (uint32_t(buf) >= SharedBufferStack::NUM_BUFFER_MAX)
+ return BAD_VALUE;
+ SharedBufferStack& stack( *mSharedStack );
+ buf = stack.index[buf];
+ LOGD_IF(DEBUG_ATOMICS && buf>=0, "retire=%d, %s",
+ int(buf), dump("").string());
+ }
+ return buf;
+}
+
+void SharedBufferServer::setStatus(status_t status)
+{
+ if (status < NO_ERROR) {
+ StatusUpdate update(this, status);
+ updateCondition( update );
+ }
+}
+
+status_t SharedBufferServer::reallocateAll()
+{
+ RWLock::AutoRLock _l(mLock);
+
+ SharedBufferStack& stack( *mSharedStack );
+ uint32_t mask = mBufferList.getMask();
+ android_atomic_or(mask, &stack.reallocMask);
+ return NO_ERROR;
+}
+
+status_t SharedBufferServer::reallocateAllExcept(int buffer)
+{
+ RWLock::AutoRLock _l(mLock);
+
+ SharedBufferStack& stack( *mSharedStack );
+ BufferList temp(mBufferList);
+ temp.remove(buffer);
+ uint32_t mask = temp.getMask();
+ android_atomic_or(mask, &stack.reallocMask);
+ return NO_ERROR;
+}
+
+int32_t SharedBufferServer::getQueuedCount() const
+{
+ SharedBufferStack& stack( *mSharedStack );
+ return stack.queued;
+}
+
+Region SharedBufferServer::getDirtyRegion(int buf) const
+{
+ SharedBufferStack& stack( *mSharedStack );
+ return stack.getDirtyRegion(buf);
+}
+
+Rect SharedBufferServer::getCrop(int buf) const
+{
+ SharedBufferStack& stack( *mSharedStack );
+ return stack.getCrop(buf);
+}
+
+uint32_t SharedBufferServer::getTransform(int buf) const
+{
+ SharedBufferStack& stack( *mSharedStack );
+ return stack.getTransform(buf);
+}
+
+/*
+ * NOTE: this is not thread-safe on the server-side, meaning
+ * 'head' cannot move during this operation. The client-side
+ * can safely operate an usual.
+ *
+ */
+status_t SharedBufferServer::resize(int newNumBuffers)
+{
+ if ((unsigned int)(newNumBuffers) < SharedBufferStack::NUM_BUFFER_MIN ||
+ (unsigned int)(newNumBuffers) > SharedBufferStack::NUM_BUFFER_MAX) {
+ return BAD_VALUE;
+ }
+
+ RWLock::AutoWLock _l(mLock);
+
+ if (newNumBuffers < mNumBuffers) {
+ return shrink(newNumBuffers);
+ } else {
+ return grow(newNumBuffers);
+ }
+}
+
+status_t SharedBufferServer::grow(int newNumBuffers)
+{
+ SharedBufferStack& stack( *mSharedStack );
+ const int numBuffers = mNumBuffers;
+ const int extra = newNumBuffers - numBuffers;
+
+ // read the head, make sure it's valid
+ int32_t head = stack.head;
+ if (uint32_t(head) >= SharedBufferStack::NUM_BUFFER_MAX)
+ return BAD_VALUE;
+
+ int base = numBuffers;
+ int32_t avail = stack.available;
+ int tail = head - avail + 1;
+
+ if (tail >= 0) {
+ int8_t* const index = const_cast<int8_t*>(stack.index);
+ const int nb = numBuffers - head;
+ memmove(&index[head + extra], &index[head], nb);
+ base = head;
+ // move head 'extra' ahead, this doesn't impact stack.index[head];
+ stack.head = head + extra;
+ }
+ stack.available += extra;
+
+ // fill the new free space with unused buffers
+ BufferList::const_iterator curr(mBufferList.free_begin());
+ for (int i=0 ; i<extra ; i++) {
+ stack.index[base+i] = *curr;
+ mBufferList.add(*curr);
+ ++curr;
+ }
+
+ mNumBuffers = newNumBuffers;
+ return NO_ERROR;
+}
+
+status_t SharedBufferServer::shrink(int newNumBuffers)
+{
+ SharedBufferStack& stack( *mSharedStack );
+
+ // Shrinking is only supported if there are no buffers currently dequeued.
+ int32_t avail = stack.available;
+ int32_t queued = stack.queued;
+ if (avail + queued != mNumBuffers) {
+ return INVALID_OPERATION;
+ }
+
+ // Wait for any queued buffers to be displayed.
+ BuffersAvailableCondition condition(this, mNumBuffers);
+ status_t err = waitForCondition(condition);
+ if (err < 0) {
+ return err;
+ }
+
+ // Reset head to index 0 and make it refer to buffer 0. The same renaming
+ // (head -> 0) is done in the BufferManager.
+ int32_t head = stack.head;
+ int8_t* index = const_cast<int8_t*>(stack.index);
+ for (int8_t i = 0; i < newNumBuffers; i++) {
+ index[i] = i;
+ }
+ stack.head = 0;
+ stack.headBuf = 0;
+
+ // Free the buffers from the end of the list that are no longer needed.
+ for (int i = newNumBuffers; i < mNumBuffers; i++) {
+ mBufferList.remove(i);
+ }
+
+ // Tell the client to reallocate all the buffers.
+ reallocateAll();
+
+ mNumBuffers = newNumBuffers;
+ stack.available = newNumBuffers;
+
+ return NO_ERROR;
+}
+
+SharedBufferStack::Statistics SharedBufferServer::getStats() const
+{
+ SharedBufferStack& stack( *mSharedStack );
+ return stack.stats;
+}
+
+// ---------------------------------------------------------------------------
+status_t SharedBufferServer::BufferList::add(int value)
+{
+ if (uint32_t(value) >= mCapacity)
+ return BAD_VALUE;
+ uint32_t mask = 1<<(31-value);
+ if (mList & mask)
+ return ALREADY_EXISTS;
+ mList |= mask;
+ return NO_ERROR;
+}
+
+status_t SharedBufferServer::BufferList::remove(int value)
+{
+ if (uint32_t(value) >= mCapacity)
+ return BAD_VALUE;
+ uint32_t mask = 1<<(31-value);
+ if (!(mList & mask))
+ return NAME_NOT_FOUND;
+ mList &= ~mask;
+ return NO_ERROR;
+}
+
+
+// ---------------------------------------------------------------------------
+}; // namespace android
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
new file mode 100644
index 0000000..0dfbf01
--- /dev/null
+++ b/libs/gui/Surface.cpp
@@ -0,0 +1,1152 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "Surface"
+
+#include <stdint.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <utils/Errors.h>
+#include <utils/threads.h>
+#include <utils/CallStack.h>
+#include <utils/Log.h>
+
+#include <binder/IPCThreadState.h>
+#include <binder/IMemory.h>
+
+#include <ui/DisplayInfo.h>
+#include <ui/GraphicBuffer.h>
+#include <ui/GraphicBufferMapper.h>
+#include <ui/GraphicLog.h>
+#include <ui/Rect.h>
+
+#include <surfaceflinger/Surface.h>
+#include <surfaceflinger/ISurface.h>
+#include <surfaceflinger/ISurfaceComposer.h>
+#include <surfaceflinger/SurfaceComposerClient.h>
+
+#include <private/surfaceflinger/SharedBufferStack.h>
+#include <private/surfaceflinger/LayerState.h>
+
+namespace android {
+
+// ----------------------------------------------------------------------
+
+static status_t copyBlt(
+ const sp<GraphicBuffer>& dst,
+ const sp<GraphicBuffer>& src,
+ const Region& reg)
+{
+ // src and dst with, height and format must be identical. no verification
+ // is done here.
+ status_t err;
+ uint8_t const * src_bits = NULL;
+ err = src->lock(GRALLOC_USAGE_SW_READ_OFTEN, reg.bounds(), (void**)&src_bits);
+ LOGE_IF(err, "error locking src buffer %s", strerror(-err));
+
+ uint8_t* dst_bits = NULL;
+ err = dst->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, reg.bounds(), (void**)&dst_bits);
+ LOGE_IF(err, "error locking dst buffer %s", strerror(-err));
+
+ Region::const_iterator head(reg.begin());
+ Region::const_iterator tail(reg.end());
+ if (head != tail && src_bits && dst_bits) {
+ const size_t bpp = bytesPerPixel(src->format);
+ const size_t dbpr = dst->stride * bpp;
+ const size_t sbpr = src->stride * bpp;
+
+ while (head != tail) {
+ const Rect& r(*head++);
+ ssize_t h = r.height();
+ if (h <= 0) continue;
+ size_t size = r.width() * bpp;
+ uint8_t const * s = src_bits + (r.left + src->stride * r.top) * bpp;
+ uint8_t * d = dst_bits + (r.left + dst->stride * r.top) * bpp;
+ if (dbpr==sbpr && size==sbpr) {
+ size *= h;
+ h = 1;
+ }
+ do {
+ memcpy(d, s, size);
+ d += dbpr;
+ s += sbpr;
+ } while (--h > 0);
+ }
+ }
+
+ if (src_bits)
+ src->unlock();
+
+ if (dst_bits)
+ dst->unlock();
+
+ return err;
+}
+
+// ============================================================================
+// SurfaceControl
+// ============================================================================
+
+SurfaceControl::SurfaceControl(
+ const sp<SurfaceComposerClient>& client,
+ const sp<ISurface>& surface,
+ const ISurfaceComposerClient::surface_data_t& data,
+ uint32_t w, uint32_t h, PixelFormat format, uint32_t flags)
+ : mClient(client), mSurface(surface),
+ mToken(data.token), mIdentity(data.identity),
+ mWidth(data.width), mHeight(data.height), mFormat(data.format),
+ mFlags(flags)
+{
+}
+
+SurfaceControl::~SurfaceControl()
+{
+ destroy();
+}
+
+void SurfaceControl::destroy()
+{
+ if (isValid()) {
+ mClient->destroySurface(mToken);
+ }
+
+ // clear all references and trigger an IPC now, to make sure things
+ // happen without delay, since these resources are quite heavy.
+ mClient.clear();
+ mSurface.clear();
+ IPCThreadState::self()->flushCommands();
+}
+
+void SurfaceControl::clear()
+{
+ // here, the window manager tells us explicitly that we should destroy
+ // the surface's resource. Soon after this call, it will also release
+ // its last reference (which will call the dtor); however, it is possible
+ // that a client living in the same process still holds references which
+ // would delay the call to the dtor -- that is why we need this explicit
+ // "clear()" call.
+ destroy();
+}
+
+bool SurfaceControl::isSameSurface(
+ const sp<SurfaceControl>& lhs, const sp<SurfaceControl>& rhs)
+{
+ if (lhs == 0 || rhs == 0)
+ return false;
+ return lhs->mSurface->asBinder() == rhs->mSurface->asBinder();
+}
+
+status_t SurfaceControl::setLayer(int32_t layer) {
+ status_t err = validate();
+ if (err < 0) return err;
+ const sp<SurfaceComposerClient>& client(mClient);
+ return client->setLayer(mToken, layer);
+}
+status_t SurfaceControl::setPosition(int32_t x, int32_t y) {
+ status_t err = validate();
+ if (err < 0) return err;
+ const sp<SurfaceComposerClient>& client(mClient);
+ return client->setPosition(mToken, x, y);
+}
+status_t SurfaceControl::setSize(uint32_t w, uint32_t h) {
+ status_t err = validate();
+ if (err < 0) return err;
+ const sp<SurfaceComposerClient>& client(mClient);
+ return client->setSize(mToken, w, h);
+}
+status_t SurfaceControl::hide() {
+ status_t err = validate();
+ if (err < 0) return err;
+ const sp<SurfaceComposerClient>& client(mClient);
+ return client->hide(mToken);
+}
+status_t SurfaceControl::show(int32_t layer) {
+ status_t err = validate();
+ if (err < 0) return err;
+ const sp<SurfaceComposerClient>& client(mClient);
+ return client->show(mToken, layer);
+}
+status_t SurfaceControl::freeze() {
+ status_t err = validate();
+ if (err < 0) return err;
+ const sp<SurfaceComposerClient>& client(mClient);
+ return client->freeze(mToken);
+}
+status_t SurfaceControl::unfreeze() {
+ status_t err = validate();
+ if (err < 0) return err;
+ const sp<SurfaceComposerClient>& client(mClient);
+ return client->unfreeze(mToken);
+}
+status_t SurfaceControl::setFlags(uint32_t flags, uint32_t mask) {
+ status_t err = validate();
+ if (err < 0) return err;
+ const sp<SurfaceComposerClient>& client(mClient);
+ return client->setFlags(mToken, flags, mask);
+}
+status_t SurfaceControl::setTransparentRegionHint(const Region& transparent) {
+ status_t err = validate();
+ if (err < 0) return err;
+ const sp<SurfaceComposerClient>& client(mClient);
+ return client->setTransparentRegionHint(mToken, transparent);
+}
+status_t SurfaceControl::setAlpha(float alpha) {
+ status_t err = validate();
+ if (err < 0) return err;
+ const sp<SurfaceComposerClient>& client(mClient);
+ return client->setAlpha(mToken, alpha);
+}
+status_t SurfaceControl::setMatrix(float dsdx, float dtdx, float dsdy, float dtdy) {
+ status_t err = validate();
+ if (err < 0) return err;
+ const sp<SurfaceComposerClient>& client(mClient);
+ return client->setMatrix(mToken, dsdx, dtdx, dsdy, dtdy);
+}
+status_t SurfaceControl::setFreezeTint(uint32_t tint) {
+ status_t err = validate();
+ if (err < 0) return err;
+ const sp<SurfaceComposerClient>& client(mClient);
+ return client->setFreezeTint(mToken, tint);
+}
+
+status_t SurfaceControl::validate() const
+{
+ if (mToken<0 || mClient==0) {
+ LOGE("invalid token (%d, identity=%u) or client (%p)",
+ mToken, mIdentity, mClient.get());
+ return NO_INIT;
+ }
+ return NO_ERROR;
+}
+
+status_t SurfaceControl::writeSurfaceToParcel(
+ const sp<SurfaceControl>& control, Parcel* parcel)
+{
+ sp<ISurface> sur;
+ uint32_t identity = 0;
+ uint32_t width = 0;
+ uint32_t height = 0;
+ uint32_t format = 0;
+ uint32_t flags = 0;
+ if (SurfaceControl::isValid(control)) {
+ sur = control->mSurface;
+ identity = control->mIdentity;
+ width = control->mWidth;
+ height = control->mHeight;
+ format = control->mFormat;
+ flags = control->mFlags;
+ }
+ parcel->writeStrongBinder(sur!=0 ? sur->asBinder() : NULL);
+ parcel->writeInt32(identity);
+ parcel->writeInt32(width);
+ parcel->writeInt32(height);
+ parcel->writeInt32(format);
+ parcel->writeInt32(flags);
+ return NO_ERROR;
+}
+
+sp<Surface> SurfaceControl::getSurface() const
+{
+ Mutex::Autolock _l(mLock);
+ if (mSurfaceData == 0) {
+ mSurfaceData = new Surface(const_cast<SurfaceControl*>(this));
+ }
+ return mSurfaceData;
+}
+
+// ============================================================================
+// Surface
+// ============================================================================
+
+class SurfaceClient : public Singleton<SurfaceClient>
+{
+ // all these attributes are constants
+ sp<ISurfaceComposer> mComposerService;
+ sp<ISurfaceComposerClient> mClient;
+ status_t mStatus;
+ SharedClient* mControl;
+ sp<IMemoryHeap> mControlMemory;
+
+ SurfaceClient()
+ : Singleton<SurfaceClient>(), mStatus(NO_INIT)
+ {
+ sp<ISurfaceComposer> sf(ComposerService::getComposerService());
+ mComposerService = sf;
+ mClient = sf->createClientConnection();
+ if (mClient != NULL) {
+ mControlMemory = mClient->getControlBlock();
+ if (mControlMemory != NULL) {
+ mControl = static_cast<SharedClient *>(
+ mControlMemory->getBase());
+ if (mControl) {
+ mStatus = NO_ERROR;
+ }
+ }
+ }
+ }
+ friend class Singleton<SurfaceClient>;
+public:
+ status_t initCheck() const {
+ return mStatus;
+ }
+ SharedClient* getSharedClient() const {
+ return mControl;
+ }
+ ssize_t getTokenForSurface(const sp<ISurface>& sur) const {
+ // TODO: we could cache a few tokens here to avoid an IPC
+ return mClient->getTokenForSurface(sur);
+ }
+ void signalServer() const {
+ mComposerService->signal();
+ }
+};
+
+ANDROID_SINGLETON_STATIC_INSTANCE(SurfaceClient);
+
+// ---------------------------------------------------------------------------
+
+Surface::Surface(const sp<SurfaceControl>& surface)
+ : mBufferMapper(GraphicBufferMapper::get()),
+ mClient(SurfaceClient::getInstance()),
+ mSharedBufferClient(NULL),
+ mInitCheck(NO_INIT),
+ mSurface(surface->mSurface),
+ mIdentity(surface->mIdentity),
+ mFormat(surface->mFormat), mFlags(surface->mFlags),
+ mWidth(surface->mWidth), mHeight(surface->mHeight)
+{
+ init();
+}
+
+Surface::Surface(const Parcel& parcel, const sp<IBinder>& ref)
+ : mBufferMapper(GraphicBufferMapper::get()),
+ mClient(SurfaceClient::getInstance()),
+ mSharedBufferClient(NULL),
+ mInitCheck(NO_INIT)
+{
+ mSurface = interface_cast<ISurface>(ref);
+ mIdentity = parcel.readInt32();
+ mWidth = parcel.readInt32();
+ mHeight = parcel.readInt32();
+ mFormat = parcel.readInt32();
+ mFlags = parcel.readInt32();
+ init();
+}
+
+status_t Surface::writeToParcel(
+ const sp<Surface>& surface, Parcel* parcel)
+{
+ sp<ISurface> sur;
+ uint32_t identity = 0;
+ uint32_t width = 0;
+ uint32_t height = 0;
+ uint32_t format = 0;
+ uint32_t flags = 0;
+ if (Surface::isValid(surface)) {
+ sur = surface->mSurface;
+ identity = surface->mIdentity;
+ width = surface->mWidth;
+ height = surface->mHeight;
+ format = surface->mFormat;
+ flags = surface->mFlags;
+ } else if (surface != 0 && surface->mSurface != 0) {
+ LOGW("Parceling invalid surface with non-NULL ISurface as NULL: "
+ "mSurface = %p, mIdentity = %d, mWidth = %d, mHeight = %d, "
+ "mFormat = %d, mFlags = 0x%08x, mInitCheck = %d",
+ surface->mSurface.get(), surface->mIdentity, surface->mWidth,
+ surface->mHeight, surface->mFormat, surface->mFlags,
+ surface->mInitCheck);
+ }
+ parcel->writeStrongBinder(sur!=0 ? sur->asBinder() : NULL);
+ parcel->writeInt32(identity);
+ parcel->writeInt32(width);
+ parcel->writeInt32(height);
+ parcel->writeInt32(format);
+ parcel->writeInt32(flags);
+ return NO_ERROR;
+
+}
+
+
+Mutex Surface::sCachedSurfacesLock;
+DefaultKeyedVector<wp<IBinder>, wp<Surface> > Surface::sCachedSurfaces;
+
+sp<Surface> Surface::readFromParcel(const Parcel& data) {
+ Mutex::Autolock _l(sCachedSurfacesLock);
+ sp<IBinder> binder(data.readStrongBinder());
+ sp<Surface> surface = sCachedSurfaces.valueFor(binder).promote();
+ if (surface == 0) {
+ surface = new Surface(data, binder);
+ sCachedSurfaces.add(binder, surface);
+ }
+ if (surface->mSurface == 0) {
+ surface = 0;
+ }
+ cleanCachedSurfacesLocked();
+ return surface;
+}
+
+// Remove the stale entries from the surface cache. This should only be called
+// with sCachedSurfacesLock held.
+void Surface::cleanCachedSurfacesLocked() {
+ for (int i = sCachedSurfaces.size()-1; i >= 0; --i) {
+ wp<Surface> s(sCachedSurfaces.valueAt(i));
+ if (s == 0 || s.promote() == 0) {
+ sCachedSurfaces.removeItemsAt(i);
+ }
+ }
+}
+
+void Surface::init()
+{
+ ANativeWindow::setSwapInterval = setSwapInterval;
+ ANativeWindow::dequeueBuffer = dequeueBuffer;
+ ANativeWindow::cancelBuffer = cancelBuffer;
+ ANativeWindow::lockBuffer = lockBuffer;
+ ANativeWindow::queueBuffer = queueBuffer;
+ ANativeWindow::query = query;
+ ANativeWindow::perform = perform;
+
+ DisplayInfo dinfo;
+ SurfaceComposerClient::getDisplayInfo(0, &dinfo);
+ const_cast<float&>(ANativeWindow::xdpi) = dinfo.xdpi;
+ const_cast<float&>(ANativeWindow::ydpi) = dinfo.ydpi;
+ // FIXME: set real values here
+ const_cast<int&>(ANativeWindow::minSwapInterval) = 1;
+ const_cast<int&>(ANativeWindow::maxSwapInterval) = 1;
+ const_cast<uint32_t&>(ANativeWindow::flags) = 0;
+
+ mNextBufferTransform = 0;
+ mConnected = 0;
+ mSwapRectangle.makeInvalid();
+ mNextBufferCrop = Rect(0,0);
+ // two buffers by default
+ mBuffers.setCapacity(2);
+ mBuffers.insertAt(0, 2);
+
+ if (mSurface != 0 && mClient.initCheck() == NO_ERROR) {
+ int32_t token = mClient.getTokenForSurface(mSurface);
+ if (token >= 0) {
+ mSharedBufferClient = new SharedBufferClient(
+ mClient.getSharedClient(), token, 2, mIdentity);
+ mInitCheck = mClient.getSharedClient()->validate(token);
+ } else {
+ LOGW("Not initializing the shared buffer client because token = %d",
+ token);
+ }
+ }
+}
+
+Surface::~Surface()
+{
+ // clear all references and trigger an IPC now, to make sure things
+ // happen without delay, since these resources are quite heavy.
+ mBuffers.clear();
+ mSurface.clear();
+ delete mSharedBufferClient;
+ IPCThreadState::self()->flushCommands();
+}
+
+bool Surface::isValid() {
+ return mInitCheck == NO_ERROR;
+}
+
+status_t Surface::validate(bool inCancelBuffer) const
+{
+ // check that we initialized ourself properly
+ if (mInitCheck != NO_ERROR) {
+ LOGE("invalid token (identity=%u)", mIdentity);
+ return mInitCheck;
+ }
+
+ // verify the identity of this surface
+ uint32_t identity = mSharedBufferClient->getIdentity();
+ if (mIdentity != identity) {
+ LOGE("[Surface] using an invalid surface, "
+ "identity=%u should be %d",
+ mIdentity, identity);
+ CallStack stack;
+ stack.update();
+ stack.dump("Surface");
+ return BAD_INDEX;
+ }
+
+ // check the surface didn't become invalid
+ status_t err = mSharedBufferClient->getStatus();
+ if (err != NO_ERROR) {
+ if (!inCancelBuffer) {
+ LOGE("surface (identity=%u) is invalid, err=%d (%s)",
+ mIdentity, err, strerror(-err));
+ CallStack stack;
+ stack.update();
+ stack.dump("Surface");
+ }
+ return err;
+ }
+
+ return NO_ERROR;
+}
+
+sp<ISurface> Surface::getISurface() const {
+ return mSurface;
+}
+
+// ----------------------------------------------------------------------------
+
+int Surface::setSwapInterval(ANativeWindow* window, int interval) {
+ return 0;
+}
+
+int Surface::dequeueBuffer(ANativeWindow* window,
+ android_native_buffer_t** buffer) {
+ Surface* self = getSelf(window);
+ return self->dequeueBuffer(buffer);
+}
+
+int Surface::cancelBuffer(ANativeWindow* window,
+ android_native_buffer_t* buffer) {
+ Surface* self = getSelf(window);
+ return self->cancelBuffer(buffer);
+}
+
+int Surface::lockBuffer(ANativeWindow* window,
+ android_native_buffer_t* buffer) {
+ Surface* self = getSelf(window);
+ return self->lockBuffer(buffer);
+}
+
+int Surface::queueBuffer(ANativeWindow* window,
+ android_native_buffer_t* buffer) {
+ Surface* self = getSelf(window);
+ return self->queueBuffer(buffer);
+}
+
+int Surface::query(ANativeWindow* window,
+ int what, int* value) {
+ Surface* self = getSelf(window);
+ return self->query(what, value);
+}
+
+int Surface::perform(ANativeWindow* window,
+ int operation, ...) {
+ va_list args;
+ va_start(args, operation);
+ Surface* self = getSelf(window);
+ int res = self->perform(operation, args);
+ va_end(args);
+ return res;
+}
+
+// ----------------------------------------------------------------------------
+
+bool Surface::needNewBuffer(int bufIdx,
+ uint32_t *pWidth, uint32_t *pHeight,
+ uint32_t *pFormat, uint32_t *pUsage) const
+{
+ Mutex::Autolock _l(mSurfaceLock);
+
+ // Always call needNewBuffer(), since it clears the needed buffers flags
+ bool needNewBuffer = mSharedBufferClient->needNewBuffer(bufIdx);
+ bool validBuffer = mBufferInfo.validateBuffer(mBuffers[bufIdx]);
+ bool newNeewBuffer = needNewBuffer || !validBuffer;
+ if (newNeewBuffer) {
+ mBufferInfo.get(pWidth, pHeight, pFormat, pUsage);
+ }
+ return newNeewBuffer;
+}
+
+int Surface::dequeueBuffer(android_native_buffer_t** buffer)
+{
+ status_t err = validate();
+ if (err != NO_ERROR)
+ return err;
+
+ GraphicLog& logger(GraphicLog::getInstance());
+ logger.log(GraphicLog::SF_APP_DEQUEUE_BEFORE, mIdentity, -1);
+
+ ssize_t bufIdx = mSharedBufferClient->dequeue();
+
+ logger.log(GraphicLog::SF_APP_DEQUEUE_AFTER, mIdentity, bufIdx);
+
+ if (bufIdx < 0) {
+ LOGE("error dequeuing a buffer (%s)", strerror(bufIdx));
+ return bufIdx;
+ }
+
+ // grow the buffer array if needed
+ const size_t size = mBuffers.size();
+ const size_t needed = bufIdx+1;
+ if (size < needed) {
+ mBuffers.insertAt(size, needed-size);
+ }
+
+ uint32_t w, h, format, usage;
+ if (needNewBuffer(bufIdx, &w, &h, &format, &usage)) {
+ err = getBufferLocked(bufIdx, w, h, format, usage);
+ LOGE_IF(err, "getBufferLocked(%ld, %u, %u, %u, %08x) failed (%s)",
+ bufIdx, w, h, format, usage, strerror(-err));
+ if (err == NO_ERROR) {
+ // reset the width/height with the what we get from the buffer
+ const sp<GraphicBuffer>& backBuffer(mBuffers[bufIdx]);
+ mWidth = uint32_t(backBuffer->width);
+ mHeight = uint32_t(backBuffer->height);
+ }
+ }
+
+ // if we still don't have a buffer here, we probably ran out of memory
+ const sp<GraphicBuffer>& backBuffer(mBuffers[bufIdx]);
+ if (!err && backBuffer==0) {
+ err = NO_MEMORY;
+ }
+
+ if (err == NO_ERROR) {
+ mDirtyRegion.set(backBuffer->width, backBuffer->height);
+ *buffer = backBuffer.get();
+ } else {
+ mSharedBufferClient->undoDequeue(bufIdx);
+ }
+
+ return err;
+}
+
+int Surface::cancelBuffer(android_native_buffer_t* buffer)
+{
+ status_t err = validate(true);
+ switch (err) {
+ case NO_ERROR:
+ // no error, common case
+ break;
+ case BAD_INDEX:
+ // legitimate errors here
+ return err;
+ default:
+ // other errors happen because the surface is now invalid,
+ // for instance because it has been destroyed. In this case,
+ // we just fail silently (canceling a buffer is not technically
+ // an error at this point)
+ return NO_ERROR;
+ }
+
+ int32_t bufIdx = getBufferIndex(GraphicBuffer::getSelf(buffer));
+
+ err = mSharedBufferClient->cancel(bufIdx);
+
+ LOGE_IF(err, "error canceling buffer %d (%s)", bufIdx, strerror(-err));
+ return err;
+}
+
+
+int Surface::lockBuffer(android_native_buffer_t* buffer)
+{
+ status_t err = validate();
+ if (err != NO_ERROR)
+ return err;
+
+ int32_t bufIdx = getBufferIndex(GraphicBuffer::getSelf(buffer));
+
+ GraphicLog& logger(GraphicLog::getInstance());
+ logger.log(GraphicLog::SF_APP_LOCK_BEFORE, mIdentity, bufIdx);
+
+ err = mSharedBufferClient->lock(bufIdx);
+
+ logger.log(GraphicLog::SF_APP_LOCK_AFTER, mIdentity, bufIdx);
+
+ LOGE_IF(err, "error locking buffer %d (%s)", bufIdx, strerror(-err));
+ return err;
+}
+
+int Surface::queueBuffer(android_native_buffer_t* buffer)
+{
+ status_t err = validate();
+ if (err != NO_ERROR)
+ return err;
+
+ if (mSwapRectangle.isValid()) {
+ mDirtyRegion.set(mSwapRectangle);
+ }
+
+ int32_t bufIdx = getBufferIndex(GraphicBuffer::getSelf(buffer));
+
+ GraphicLog::getInstance().log(GraphicLog::SF_APP_QUEUE, mIdentity, bufIdx);
+
+ mSharedBufferClient->setTransform(bufIdx, mNextBufferTransform);
+ mSharedBufferClient->setCrop(bufIdx, mNextBufferCrop);
+ mSharedBufferClient->setDirtyRegion(bufIdx, mDirtyRegion);
+ err = mSharedBufferClient->queue(bufIdx);
+ LOGE_IF(err, "error queuing buffer %d (%s)", bufIdx, strerror(-err));
+
+ if (err == NO_ERROR) {
+ // TODO: can we avoid this IPC if we know there is one pending?
+ mClient.signalServer();
+ }
+ return err;
+}
+
+int Surface::query(int what, int* value)
+{
+ switch (what) {
+ case NATIVE_WINDOW_WIDTH:
+ *value = int(mWidth);
+ return NO_ERROR;
+ case NATIVE_WINDOW_HEIGHT:
+ *value = int(mHeight);
+ return NO_ERROR;
+ case NATIVE_WINDOW_FORMAT:
+ *value = int(mFormat);
+ return NO_ERROR;
+ case NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS:
+ *value = MIN_UNDEQUEUED_BUFFERS;
+ return NO_ERROR;
+ case NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER: {
+ sp<ISurfaceComposer> sf(ComposerService::getComposerService());
+ *value = sf->authenticateSurface(mSurface) ? 1 : 0;
+ return NO_ERROR;
+ }
+ case NATIVE_WINDOW_CONCRETE_TYPE:
+ *value = NATIVE_WINDOW_SURFACE;
+ return NO_ERROR;
+ }
+ return BAD_VALUE;
+}
+
+int Surface::perform(int operation, va_list args)
+{
+ status_t err = validate();
+ if (err != NO_ERROR)
+ return err;
+
+ int res = NO_ERROR;
+ switch (operation) {
+ case NATIVE_WINDOW_SET_USAGE:
+ dispatch_setUsage( args );
+ break;
+ case NATIVE_WINDOW_CONNECT:
+ res = dispatch_connect( args );
+ break;
+ case NATIVE_WINDOW_DISCONNECT:
+ res = dispatch_disconnect( args );
+ break;
+ case NATIVE_WINDOW_SET_CROP:
+ res = dispatch_crop( args );
+ break;
+ case NATIVE_WINDOW_SET_BUFFER_COUNT:
+ res = dispatch_set_buffer_count( args );
+ break;
+ case NATIVE_WINDOW_SET_BUFFERS_GEOMETRY:
+ res = dispatch_set_buffers_geometry( args );
+ break;
+ case NATIVE_WINDOW_SET_BUFFERS_TRANSFORM:
+ res = dispatch_set_buffers_transform( args );
+ break;
+ case NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP:
+ res = dispatch_set_buffers_timestamp( args );
+ break;
+ default:
+ res = NAME_NOT_FOUND;
+ break;
+ }
+ return res;
+}
+
+void Surface::dispatch_setUsage(va_list args) {
+ int usage = va_arg(args, int);
+ setUsage( usage );
+}
+int Surface::dispatch_connect(va_list args) {
+ int api = va_arg(args, int);
+ return connect( api );
+}
+int Surface::dispatch_disconnect(va_list args) {
+ int api = va_arg(args, int);
+ return disconnect( api );
+}
+int Surface::dispatch_crop(va_list args) {
+ android_native_rect_t const* rect = va_arg(args, android_native_rect_t*);
+ return crop( reinterpret_cast<Rect const*>(rect) );
+}
+int Surface::dispatch_set_buffer_count(va_list args) {
+ size_t bufferCount = va_arg(args, size_t);
+ return setBufferCount(bufferCount);
+}
+int Surface::dispatch_set_buffers_geometry(va_list args) {
+ int w = va_arg(args, int);
+ int h = va_arg(args, int);
+ int f = va_arg(args, int);
+ return setBuffersGeometry(w, h, f);
+}
+
+int Surface::dispatch_set_buffers_transform(va_list args) {
+ int transform = va_arg(args, int);
+ return setBuffersTransform(transform);
+}
+
+int Surface::dispatch_set_buffers_timestamp(va_list args) {
+ int64_t timestamp = va_arg(args, int64_t);
+ return setBuffersTimestamp(timestamp);
+}
+
+void Surface::setUsage(uint32_t reqUsage)
+{
+ Mutex::Autolock _l(mSurfaceLock);
+ mBufferInfo.set(reqUsage);
+}
+
+int Surface::connect(int api)
+{
+ Mutex::Autolock _l(mSurfaceLock);
+ int err = NO_ERROR;
+ switch (api) {
+ case NATIVE_WINDOW_API_EGL:
+ if (mConnected) {
+ err = -EINVAL;
+ } else {
+ mConnected = api;
+ }
+ break;
+ default:
+ err = -EINVAL;
+ break;
+ }
+ return err;
+}
+
+int Surface::disconnect(int api)
+{
+ Mutex::Autolock _l(mSurfaceLock);
+ int err = NO_ERROR;
+ switch (api) {
+ case NATIVE_WINDOW_API_EGL:
+ if (mConnected == api) {
+ mConnected = 0;
+ } else {
+ err = -EINVAL;
+ }
+ break;
+ default:
+ err = -EINVAL;
+ break;
+ }
+ return err;
+}
+
+int Surface::crop(Rect const* rect)
+{
+ Mutex::Autolock _l(mSurfaceLock);
+ // TODO: validate rect size
+
+ if (rect == NULL || rect->isEmpty()) {
+ mNextBufferCrop = Rect(0,0);
+ } else {
+ mNextBufferCrop = *rect;
+ }
+
+ return NO_ERROR;
+}
+
+int Surface::setBufferCount(int bufferCount)
+{
+ sp<ISurface> s(mSurface);
+ if (s == 0) return NO_INIT;
+
+ class SetBufferCountIPC : public SharedBufferClient::SetBufferCountCallback {
+ sp<ISurface> surface;
+ virtual status_t operator()(int bufferCount) const {
+ return surface->setBufferCount(bufferCount);
+ }
+ public:
+ SetBufferCountIPC(const sp<ISurface>& surface) : surface(surface) { }
+ } ipc(s);
+
+ status_t err = mSharedBufferClient->setBufferCount(bufferCount, ipc);
+ LOGE_IF(err, "ISurface::setBufferCount(%d) returned %s",
+ bufferCount, strerror(-err));
+
+ if (err == NO_ERROR) {
+ // Clear out any references to the old buffers.
+ mBuffers.clear();
+ }
+
+ return err;
+}
+
+int Surface::setBuffersGeometry(int w, int h, int format)
+{
+ if (w<0 || h<0 || format<0)
+ return BAD_VALUE;
+
+ if ((w && !h) || (!w && h))
+ return BAD_VALUE;
+
+ Mutex::Autolock _l(mSurfaceLock);
+ if (mConnected == NATIVE_WINDOW_API_EGL) {
+ return INVALID_OPERATION;
+ }
+
+ mBufferInfo.set(w, h, format);
+ if (format != 0) {
+ // we update the format of the surface as reported by query().
+ // this is to allow applications to change the format of a surface's
+ // buffer, and have it reflected in EGL; which is needed for
+ // EGLConfig validation.
+ mFormat = format;
+ }
+
+ mNextBufferCrop = Rect(0,0);
+
+ return NO_ERROR;
+}
+
+int Surface::setBuffersTransform(int transform)
+{
+ Mutex::Autolock _l(mSurfaceLock);
+ mNextBufferTransform = transform;
+ return NO_ERROR;
+}
+
+int Surface::setBuffersTimestamp(int64_t timestamp)
+{
+ // Surface doesn't really have anything meaningful to do with timestamps
+ // so they'll just be dropped here.
+ return NO_ERROR;
+}
+
+// ----------------------------------------------------------------------------
+
+int Surface::getConnectedApi() const
+{
+ Mutex::Autolock _l(mSurfaceLock);
+ return mConnected;
+}
+
+// ----------------------------------------------------------------------------
+
+status_t Surface::lock(SurfaceInfo* info, bool blocking) {
+ return Surface::lock(info, NULL, blocking);
+}
+
+status_t Surface::lock(SurfaceInfo* other, Region* dirtyIn, bool blocking)
+{
+ if (getConnectedApi()) {
+ LOGE("Surface::lock(%p) failed. Already connected to another API",
+ (ANativeWindow*)this);
+ CallStack stack;
+ stack.update();
+ stack.dump("");
+ return INVALID_OPERATION;
+ }
+
+ if (mApiLock.tryLock() != NO_ERROR) {
+ LOGE("calling Surface::lock from different threads!");
+ CallStack stack;
+ stack.update();
+ stack.dump("");
+ return WOULD_BLOCK;
+ }
+
+ /* Here we're holding mApiLock */
+
+ if (mLockedBuffer != 0) {
+ LOGE("Surface::lock failed, already locked");
+ mApiLock.unlock();
+ return INVALID_OPERATION;
+ }
+
+ // we're intending to do software rendering from this point
+ setUsage(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN);
+
+ android_native_buffer_t* out;
+ status_t err = dequeueBuffer(&out);
+ LOGE_IF(err, "dequeueBuffer failed (%s)", strerror(-err));
+ if (err == NO_ERROR) {
+ sp<GraphicBuffer> backBuffer(GraphicBuffer::getSelf(out));
+ err = lockBuffer(backBuffer.get());
+ LOGE_IF(err, "lockBuffer (idx=%d) failed (%s)",
+ getBufferIndex(backBuffer), strerror(-err));
+ if (err == NO_ERROR) {
+ const Rect bounds(backBuffer->width, backBuffer->height);
+ const Region boundsRegion(bounds);
+ Region scratch(boundsRegion);
+ Region& newDirtyRegion(dirtyIn ? *dirtyIn : scratch);
+ newDirtyRegion &= boundsRegion;
+
+ // figure out if we can copy the frontbuffer back
+ const sp<GraphicBuffer>& frontBuffer(mPostedBuffer);
+ const bool canCopyBack = (frontBuffer != 0 &&
+ backBuffer->width == frontBuffer->width &&
+ backBuffer->height == frontBuffer->height &&
+ backBuffer->format == frontBuffer->format &&
+ !(mFlags & ISurfaceComposer::eDestroyBackbuffer));
+
+ // the dirty region we report to surfaceflinger is the one
+ // given by the user (as opposed to the one *we* return to the
+ // user).
+ mDirtyRegion = newDirtyRegion;
+
+ if (canCopyBack) {
+ // copy the area that is invalid and not repainted this round
+ const Region copyback(mOldDirtyRegion.subtract(newDirtyRegion));
+ if (!copyback.isEmpty())
+ copyBlt(backBuffer, frontBuffer, copyback);
+ } else {
+ // if we can't copy-back anything, modify the user's dirty
+ // region to make sure they redraw the whole buffer
+ newDirtyRegion = boundsRegion;
+ }
+
+ // keep track of the are of the buffer that is "clean"
+ // (ie: that will be redrawn)
+ mOldDirtyRegion = newDirtyRegion;
+
+ void* vaddr;
+ status_t res = backBuffer->lock(
+ GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
+ newDirtyRegion.bounds(), &vaddr);
+
+ LOGW_IF(res, "failed locking buffer (handle = %p)",
+ backBuffer->handle);
+
+ mLockedBuffer = backBuffer;
+ other->w = backBuffer->width;
+ other->h = backBuffer->height;
+ other->s = backBuffer->stride;
+ other->usage = backBuffer->usage;
+ other->format = backBuffer->format;
+ other->bits = vaddr;
+ }
+ }
+ mApiLock.unlock();
+ return err;
+}
+
+status_t Surface::unlockAndPost()
+{
+ if (mLockedBuffer == 0) {
+ LOGE("Surface::unlockAndPost failed, no locked buffer");
+ return INVALID_OPERATION;
+ }
+
+ status_t err = mLockedBuffer->unlock();
+ LOGE_IF(err, "failed unlocking buffer (%p)", mLockedBuffer->handle);
+
+ err = queueBuffer(mLockedBuffer.get());
+ LOGE_IF(err, "queueBuffer (idx=%d) failed (%s)",
+ getBufferIndex(mLockedBuffer), strerror(-err));
+
+ mPostedBuffer = mLockedBuffer;
+ mLockedBuffer = 0;
+ return err;
+}
+
+void Surface::setSwapRectangle(const Rect& r) {
+ Mutex::Autolock _l(mSurfaceLock);
+ mSwapRectangle = r;
+}
+
+int Surface::getBufferIndex(const sp<GraphicBuffer>& buffer) const
+{
+ int idx = buffer->getIndex();
+ if (idx < 0) {
+ // The buffer doesn't have an index set. See if the handle the same as
+ // one of the buffers for which we do know the index. This can happen
+ // e.g. if GraphicBuffer is used to wrap an android_native_buffer_t that
+ // was dequeued from an ANativeWindow.
+ for (size_t i = 0; i < mBuffers.size(); i++) {
+ if (mBuffers[i] != 0 && buffer->handle == mBuffers[i]->handle) {
+ idx = mBuffers[i]->getIndex();
+ break;
+ }
+ }
+ }
+ return idx;
+}
+
+status_t Surface::getBufferLocked(int index,
+ uint32_t w, uint32_t h, uint32_t format, uint32_t usage)
+{
+ sp<ISurface> s(mSurface);
+ if (s == 0) return NO_INIT;
+
+ status_t err = NO_MEMORY;
+
+ // free the current buffer
+ sp<GraphicBuffer>& currentBuffer(mBuffers.editItemAt(index));
+ if (currentBuffer != 0) {
+ currentBuffer.clear();
+ }
+
+ sp<GraphicBuffer> buffer = s->requestBuffer(index, w, h, format, usage);
+ LOGE_IF(buffer==0,
+ "ISurface::getBuffer(%d, %08x) returned NULL",
+ index, usage);
+ if (buffer != 0) { // this should always happen by construction
+ LOGE_IF(buffer->handle == NULL,
+ "Surface (identity=%d) requestBuffer(%d, %u, %u, %u, %08x) "
+ "returned a buffer with a null handle",
+ mIdentity, index, w, h, format, usage);
+ err = mSharedBufferClient->getStatus();
+ LOGE_IF(err, "Surface (identity=%d) state = %d", mIdentity, err);
+ if (!err && buffer->handle != NULL) {
+ currentBuffer = buffer;
+ currentBuffer->setIndex(index);
+ } else {
+ err = err<0 ? err : status_t(NO_MEMORY);
+ }
+ }
+ return err;
+}
+
+// ----------------------------------------------------------------------------
+Surface::BufferInfo::BufferInfo()
+ : mWidth(0), mHeight(0), mFormat(0),
+ mUsage(GRALLOC_USAGE_HW_RENDER), mDirty(0)
+{
+}
+
+void Surface::BufferInfo::set(uint32_t w, uint32_t h, uint32_t format) {
+ if ((mWidth != w) || (mHeight != h) || (mFormat != format)) {
+ mWidth = w;
+ mHeight = h;
+ mFormat = format;
+ mDirty |= GEOMETRY;
+ }
+}
+
+void Surface::BufferInfo::set(uint32_t usage) {
+ mUsage = usage;
+}
+
+void Surface::BufferInfo::get(uint32_t *pWidth, uint32_t *pHeight,
+ uint32_t *pFormat, uint32_t *pUsage) const {
+ *pWidth = mWidth;
+ *pHeight = mHeight;
+ *pFormat = mFormat;
+ *pUsage = mUsage;
+}
+
+bool Surface::BufferInfo::validateBuffer(const sp<GraphicBuffer>& buffer) const {
+ // make sure we AT LEAST have the usage flags we want
+ if (mDirty || buffer==0 ||
+ ((buffer->usage & mUsage) != mUsage)) {
+ mDirty = 0;
+ return false;
+ }
+ return true;
+}
+
+// ----------------------------------------------------------------------------
+}; // namespace android
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
new file mode 100644
index 0000000..d336724
--- /dev/null
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -0,0 +1,611 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "SurfaceComposerClient"
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Errors.h>
+#include <utils/threads.h>
+#include <utils/SortedVector.h>
+#include <utils/Log.h>
+#include <utils/Singleton.h>
+
+#include <binder/IServiceManager.h>
+#include <binder/IMemory.h>
+
+#include <ui/DisplayInfo.h>
+
+#include <surfaceflinger/ISurfaceComposer.h>
+#include <surfaceflinger/ISurfaceComposerClient.h>
+#include <surfaceflinger/ISurface.h>
+#include <surfaceflinger/SurfaceComposerClient.h>
+
+#include <private/surfaceflinger/LayerState.h>
+#include <private/surfaceflinger/SharedBufferStack.h>
+
+
+namespace android {
+// ---------------------------------------------------------------------------
+
+ANDROID_SINGLETON_STATIC_INSTANCE(ComposerService);
+
+ComposerService::ComposerService()
+: Singleton<ComposerService>() {
+ const String16 name("SurfaceFlinger");
+ while (getService(name, &mComposerService) != NO_ERROR) {
+ usleep(250000);
+ }
+ mServerCblkMemory = mComposerService->getCblk();
+ mServerCblk = static_cast<surface_flinger_cblk_t volatile *>(
+ mServerCblkMemory->getBase());
+}
+
+sp<ISurfaceComposer> ComposerService::getComposerService() {
+ return ComposerService::getInstance().mComposerService;
+}
+
+surface_flinger_cblk_t const volatile * ComposerService::getControlBlock() {
+ return ComposerService::getInstance().mServerCblk;
+}
+
+static inline sp<ISurfaceComposer> getComposerService() {
+ return ComposerService::getComposerService();
+}
+
+static inline surface_flinger_cblk_t const volatile * get_cblk() {
+ return ComposerService::getControlBlock();
+}
+
+// ---------------------------------------------------------------------------
+
+class Composer : public Singleton<Composer>
+{
+ Mutex mLock;
+ SortedVector< wp<SurfaceComposerClient> > mActiveConnections;
+ SortedVector<sp<SurfaceComposerClient> > mOpenTransactions;
+
+ Composer() : Singleton<Composer>() {
+ }
+
+ void addClientImpl(const sp<SurfaceComposerClient>& client) {
+ Mutex::Autolock _l(mLock);
+ mActiveConnections.add(client);
+ }
+
+ void removeClientImpl(const sp<SurfaceComposerClient>& client) {
+ Mutex::Autolock _l(mLock);
+ mActiveConnections.remove(client);
+ }
+
+ void openGlobalTransactionImpl()
+ {
+ Mutex::Autolock _l(mLock);
+ if (mOpenTransactions.size()) {
+ LOGE("openGlobalTransaction() called more than once. skipping.");
+ return;
+ }
+ const size_t N = mActiveConnections.size();
+ for (size_t i=0; i<N; i++) {
+ sp<SurfaceComposerClient> client(mActiveConnections[i].promote());
+ if (client != 0 && mOpenTransactions.indexOf(client) < 0) {
+ if (client->openTransaction() == NO_ERROR) {
+ mOpenTransactions.add(client);
+ } else {
+ LOGE("openTransaction on client %p failed", client.get());
+ // let it go, it'll fail later when the user
+ // tries to do something with the transaction
+ }
+ }
+ }
+ }
+
+ void closeGlobalTransactionImpl()
+ {
+ mLock.lock();
+ SortedVector< sp<SurfaceComposerClient> > clients(mOpenTransactions);
+ mOpenTransactions.clear();
+ mLock.unlock();
+
+ sp<ISurfaceComposer> sm(getComposerService());
+ sm->openGlobalTransaction();
+ const size_t N = clients.size();
+ for (size_t i=0; i<N; i++) {
+ clients[i]->closeTransaction();
+ }
+ sm->closeGlobalTransaction();
+ }
+
+ friend class Singleton<Composer>;
+
+public:
+ static void addClient(const sp<SurfaceComposerClient>& client) {
+ Composer::getInstance().addClientImpl(client);
+ }
+ static void removeClient(const sp<SurfaceComposerClient>& client) {
+ Composer::getInstance().removeClientImpl(client);
+ }
+ static void openGlobalTransaction() {
+ Composer::getInstance().openGlobalTransactionImpl();
+ }
+ static void closeGlobalTransaction() {
+ Composer::getInstance().closeGlobalTransactionImpl();
+ }
+};
+
+ANDROID_SINGLETON_STATIC_INSTANCE(Composer);
+
+// ---------------------------------------------------------------------------
+
+static inline int compare_type( const layer_state_t& lhs,
+ const layer_state_t& rhs) {
+ if (lhs.surface < rhs.surface) return -1;
+ if (lhs.surface > rhs.surface) return 1;
+ return 0;
+}
+
+SurfaceComposerClient::SurfaceComposerClient()
+ : mTransactionOpen(0), mPrebuiltLayerState(0), mStatus(NO_INIT)
+{
+}
+
+void SurfaceComposerClient::onFirstRef()
+{
+ sp<ISurfaceComposer> sm(getComposerService());
+ if (sm != 0) {
+ sp<ISurfaceComposerClient> conn = sm->createConnection();
+ if (conn != 0) {
+ mClient = conn;
+ Composer::addClient(this);
+ mPrebuiltLayerState = new layer_state_t;
+ mStatus = NO_ERROR;
+ }
+ }
+}
+
+SurfaceComposerClient::~SurfaceComposerClient()
+{
+ delete mPrebuiltLayerState;
+ dispose();
+}
+
+status_t SurfaceComposerClient::initCheck() const
+{
+ return mStatus;
+}
+
+sp<IBinder> SurfaceComposerClient::connection() const
+{
+ return (mClient != 0) ? mClient->asBinder() : 0;
+}
+
+status_t SurfaceComposerClient::linkToComposerDeath(
+ const sp<IBinder::DeathRecipient>& recipient,
+ void* cookie, uint32_t flags)
+{
+ sp<ISurfaceComposer> sm(getComposerService());
+ return sm->asBinder()->linkToDeath(recipient, cookie, flags);
+}
+
+void SurfaceComposerClient::dispose()
+{
+ // this can be called more than once.
+ sp<ISurfaceComposerClient> client;
+ Mutex::Autolock _lm(mLock);
+ if (mClient != 0) {
+ Composer::removeClient(this);
+ client = mClient; // hold ref while lock is held
+ mClient.clear();
+ }
+ mStatus = NO_INIT;
+}
+
+status_t SurfaceComposerClient::getDisplayInfo(
+ DisplayID dpy, DisplayInfo* info)
+{
+ if (uint32_t(dpy)>=SharedBufferStack::NUM_DISPLAY_MAX)
+ return BAD_VALUE;
+
+ volatile surface_flinger_cblk_t const * cblk = get_cblk();
+ volatile display_cblk_t const * dcblk = cblk->displays + dpy;
+
+ info->w = dcblk->w;
+ info->h = dcblk->h;
+ info->orientation = dcblk->orientation;
+ info->xdpi = dcblk->xdpi;
+ info->ydpi = dcblk->ydpi;
+ info->fps = dcblk->fps;
+ info->density = dcblk->density;
+ return getPixelFormatInfo(dcblk->format, &(info->pixelFormatInfo));
+}
+
+ssize_t SurfaceComposerClient::getDisplayWidth(DisplayID dpy)
+{
+ if (uint32_t(dpy)>=SharedBufferStack::NUM_DISPLAY_MAX)
+ return BAD_VALUE;
+ volatile surface_flinger_cblk_t const * cblk = get_cblk();
+ volatile display_cblk_t const * dcblk = cblk->displays + dpy;
+ return dcblk->w;
+}
+
+ssize_t SurfaceComposerClient::getDisplayHeight(DisplayID dpy)
+{
+ if (uint32_t(dpy)>=SharedBufferStack::NUM_DISPLAY_MAX)
+ return BAD_VALUE;
+ volatile surface_flinger_cblk_t const * cblk = get_cblk();
+ volatile display_cblk_t const * dcblk = cblk->displays + dpy;
+ return dcblk->h;
+}
+
+ssize_t SurfaceComposerClient::getDisplayOrientation(DisplayID dpy)
+{
+ if (uint32_t(dpy)>=SharedBufferStack::NUM_DISPLAY_MAX)
+ return BAD_VALUE;
+ volatile surface_flinger_cblk_t const * cblk = get_cblk();
+ volatile display_cblk_t const * dcblk = cblk->displays + dpy;
+ return dcblk->orientation;
+}
+
+ssize_t SurfaceComposerClient::getNumberOfDisplays()
+{
+ volatile surface_flinger_cblk_t const * cblk = get_cblk();
+ uint32_t connected = cblk->connected;
+ int n = 0;
+ while (connected) {
+ if (connected&1) n++;
+ connected >>= 1;
+ }
+ return n;
+}
+
+sp<SurfaceControl> SurfaceComposerClient::createSurface(
+ int pid,
+ DisplayID display,
+ uint32_t w,
+ uint32_t h,
+ PixelFormat format,
+ uint32_t flags)
+{
+ String8 name;
+ const size_t SIZE = 128;
+ char buffer[SIZE];
+ snprintf(buffer, SIZE, "<pid_%d>", getpid());
+ name.append(buffer);
+
+ return SurfaceComposerClient::createSurface(pid, name, display,
+ w, h, format, flags);
+}
+
+sp<SurfaceControl> SurfaceComposerClient::createSurface(
+ int pid,
+ const String8& name,
+ DisplayID display,
+ uint32_t w,
+ uint32_t h,
+ PixelFormat format,
+ uint32_t flags)
+{
+ sp<SurfaceControl> result;
+ if (mStatus == NO_ERROR) {
+ ISurfaceComposerClient::surface_data_t data;
+ sp<ISurface> surface = mClient->createSurface(&data, pid, name,
+ display, w, h, format, flags);
+ if (surface != 0) {
+ result = new SurfaceControl(this, surface, data, w, h, format, flags);
+ }
+ }
+ return result;
+}
+
+status_t SurfaceComposerClient::destroySurface(SurfaceID sid)
+{
+ if (mStatus != NO_ERROR)
+ return mStatus;
+
+ // it's okay to destroy a surface while a transaction is open,
+ // (transactions really are a client-side concept)
+ // however, this indicates probably a misuse of the API or a bug
+ // in the client code.
+ LOGW_IF(mTransactionOpen,
+ "Destroying surface while a transaction is open. "
+ "Client %p: destroying surface %d, mTransactionOpen=%d",
+ this, sid, mTransactionOpen);
+
+ status_t err = mClient->destroySurface(sid);
+ return err;
+}
+
+void SurfaceComposerClient::openGlobalTransaction()
+{
+ Composer::openGlobalTransaction();
+}
+
+void SurfaceComposerClient::closeGlobalTransaction()
+{
+ Composer::closeGlobalTransaction();
+}
+
+status_t SurfaceComposerClient::freezeDisplay(DisplayID dpy, uint32_t flags)
+{
+ sp<ISurfaceComposer> sm(getComposerService());
+ return sm->freezeDisplay(dpy, flags);
+}
+
+status_t SurfaceComposerClient::unfreezeDisplay(DisplayID dpy, uint32_t flags)
+{
+ sp<ISurfaceComposer> sm(getComposerService());
+ return sm->unfreezeDisplay(dpy, flags);
+}
+
+int SurfaceComposerClient::setOrientation(DisplayID dpy,
+ int orientation, uint32_t flags)
+{
+ sp<ISurfaceComposer> sm(getComposerService());
+ return sm->setOrientation(dpy, orientation, flags);
+}
+
+status_t SurfaceComposerClient::openTransaction()
+{
+ if (mStatus != NO_ERROR)
+ return mStatus;
+ Mutex::Autolock _l(mLock);
+ mTransactionOpen++;
+ return NO_ERROR;
+}
+
+status_t SurfaceComposerClient::closeTransaction()
+{
+ if (mStatus != NO_ERROR)
+ return mStatus;
+
+ Mutex::Autolock _l(mLock);
+ if (mTransactionOpen <= 0) {
+ LOGE( "closeTransaction (client %p, mTransactionOpen=%d) "
+ "called more times than openTransaction()",
+ this, mTransactionOpen);
+ return INVALID_OPERATION;
+ }
+
+ if (mTransactionOpen >= 2) {
+ mTransactionOpen--;
+ return NO_ERROR;
+ }
+
+ mTransactionOpen = 0;
+ const ssize_t count = mStates.size();
+ if (count) {
+ mClient->setState(count, mStates.array());
+ mStates.clear();
+ }
+ return NO_ERROR;
+}
+
+layer_state_t* SurfaceComposerClient::get_state_l(SurfaceID index)
+{
+ // API usage error, do nothing.
+ if (mTransactionOpen<=0) {
+ LOGE("Not in transaction (client=%p, SurfaceID=%d, mTransactionOpen=%d",
+ this, int(index), mTransactionOpen);
+ return 0;
+ }
+
+ // use mPrebuiltLayerState just to find out if we already have it
+ layer_state_t& dummy(*mPrebuiltLayerState);
+ dummy.surface = index;
+ ssize_t i = mStates.indexOf(dummy);
+ if (i < 0) {
+ // we don't have it, add an initialized layer_state to our list
+ i = mStates.add(dummy);
+ }
+ return mStates.editArray() + i;
+}
+
+layer_state_t* SurfaceComposerClient::lockLayerState(SurfaceID id)
+{
+ layer_state_t* s;
+ mLock.lock();
+ s = get_state_l(id);
+ if (!s) mLock.unlock();
+ return s;
+}
+
+void SurfaceComposerClient::unlockLayerState()
+{
+ mLock.unlock();
+}
+
+status_t SurfaceComposerClient::setPosition(SurfaceID id, int32_t x, int32_t y)
+{
+ layer_state_t* s = lockLayerState(id);
+ if (!s) return BAD_INDEX;
+ s->what |= ISurfaceComposer::ePositionChanged;
+ s->x = x;
+ s->y = y;
+ unlockLayerState();
+ return NO_ERROR;
+}
+
+status_t SurfaceComposerClient::setSize(SurfaceID id, uint32_t w, uint32_t h)
+{
+ layer_state_t* s = lockLayerState(id);
+ if (!s) return BAD_INDEX;
+ s->what |= ISurfaceComposer::eSizeChanged;
+ s->w = w;
+ s->h = h;
+ unlockLayerState();
+ return NO_ERROR;
+}
+
+status_t SurfaceComposerClient::setLayer(SurfaceID id, int32_t z)
+{
+ layer_state_t* s = lockLayerState(id);
+ if (!s) return BAD_INDEX;
+ s->what |= ISurfaceComposer::eLayerChanged;
+ s->z = z;
+ unlockLayerState();
+ return NO_ERROR;
+}
+
+status_t SurfaceComposerClient::hide(SurfaceID id)
+{
+ return setFlags(id, ISurfaceComposer::eLayerHidden,
+ ISurfaceComposer::eLayerHidden);
+}
+
+status_t SurfaceComposerClient::show(SurfaceID id, int32_t)
+{
+ return setFlags(id, 0, ISurfaceComposer::eLayerHidden);
+}
+
+status_t SurfaceComposerClient::freeze(SurfaceID id)
+{
+ return setFlags(id, ISurfaceComposer::eLayerFrozen,
+ ISurfaceComposer::eLayerFrozen);
+}
+
+status_t SurfaceComposerClient::unfreeze(SurfaceID id)
+{
+ return setFlags(id, 0, ISurfaceComposer::eLayerFrozen);
+}
+
+status_t SurfaceComposerClient::setFlags(SurfaceID id,
+ uint32_t flags, uint32_t mask)
+{
+ layer_state_t* s = lockLayerState(id);
+ if (!s) return BAD_INDEX;
+ s->what |= ISurfaceComposer::eVisibilityChanged;
+ s->flags &= ~mask;
+ s->flags |= (flags & mask);
+ s->mask |= mask;
+ unlockLayerState();
+ return NO_ERROR;
+}
+
+status_t SurfaceComposerClient::setTransparentRegionHint(
+ SurfaceID id, const Region& transparentRegion)
+{
+ layer_state_t* s = lockLayerState(id);
+ if (!s) return BAD_INDEX;
+ s->what |= ISurfaceComposer::eTransparentRegionChanged;
+ s->transparentRegion = transparentRegion;
+ unlockLayerState();
+ return NO_ERROR;
+}
+
+status_t SurfaceComposerClient::setAlpha(SurfaceID id, float alpha)
+{
+ layer_state_t* s = lockLayerState(id);
+ if (!s) return BAD_INDEX;
+ s->what |= ISurfaceComposer::eAlphaChanged;
+ s->alpha = alpha;
+ unlockLayerState();
+ return NO_ERROR;
+}
+
+status_t SurfaceComposerClient::setMatrix(
+ SurfaceID id,
+ float dsdx, float dtdx,
+ float dsdy, float dtdy )
+{
+ layer_state_t* s = lockLayerState(id);
+ if (!s) return BAD_INDEX;
+ s->what |= ISurfaceComposer::eMatrixChanged;
+ layer_state_t::matrix22_t matrix;
+ matrix.dsdx = dsdx;
+ matrix.dtdx = dtdx;
+ matrix.dsdy = dsdy;
+ matrix.dtdy = dtdy;
+ s->matrix = matrix;
+ unlockLayerState();
+ return NO_ERROR;
+}
+
+status_t SurfaceComposerClient::setFreezeTint(SurfaceID id, uint32_t tint)
+{
+ layer_state_t* s = lockLayerState(id);
+ if (!s) return BAD_INDEX;
+ s->what |= ISurfaceComposer::eFreezeTintChanged;
+ s->tint = tint;
+ unlockLayerState();
+ return NO_ERROR;
+}
+
+// ----------------------------------------------------------------------------
+
+ScreenshotClient::ScreenshotClient()
+ : mWidth(0), mHeight(0), mFormat(PIXEL_FORMAT_NONE) {
+}
+
+status_t ScreenshotClient::update() {
+ sp<ISurfaceComposer> s(ComposerService::getComposerService());
+ if (s == NULL) return NO_INIT;
+ mHeap = 0;
+ return s->captureScreen(0, &mHeap,
+ &mWidth, &mHeight, &mFormat, 0, 0,
+ 0, -1UL);
+}
+
+status_t ScreenshotClient::update(uint32_t reqWidth, uint32_t reqHeight) {
+ sp<ISurfaceComposer> s(ComposerService::getComposerService());
+ if (s == NULL) return NO_INIT;
+ mHeap = 0;
+ return s->captureScreen(0, &mHeap,
+ &mWidth, &mHeight, &mFormat, reqWidth, reqHeight,
+ 0, -1UL);
+}
+
+status_t ScreenshotClient::update(uint32_t reqWidth, uint32_t reqHeight,
+ uint32_t minLayerZ, uint32_t maxLayerZ) {
+ sp<ISurfaceComposer> s(ComposerService::getComposerService());
+ if (s == NULL) return NO_INIT;
+ mHeap = 0;
+ return s->captureScreen(0, &mHeap,
+ &mWidth, &mHeight, &mFormat, reqWidth, reqHeight,
+ minLayerZ, maxLayerZ);
+}
+
+void ScreenshotClient::release() {
+ mHeap = 0;
+}
+
+void const* ScreenshotClient::getPixels() const {
+ return mHeap->getBase();
+}
+
+uint32_t ScreenshotClient::getWidth() const {
+ return mWidth;
+}
+
+uint32_t ScreenshotClient::getHeight() const {
+ return mHeight;
+}
+
+PixelFormat ScreenshotClient::getFormat() const {
+ return mFormat;
+}
+
+uint32_t ScreenshotClient::getStride() const {
+ return mWidth;
+}
+
+size_t ScreenshotClient::getSize() const {
+ return mHeap->getSize();
+}
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+
diff --git a/libs/gui/tests/Android.mk b/libs/gui/tests/Android.mk
index 7516299..ecd0995 100644
--- a/libs/gui/tests/Android.mk
+++ b/libs/gui/tests/Android.mk
@@ -9,6 +9,7 @@ LOCAL_MODULE := SurfaceTexture_test
LOCAL_MODULE_TAGS := tests
LOCAL_SRC_FILES := \
+ Surface_test.cpp \
SurfaceTextureClient_test.cpp \
SurfaceTexture_test.cpp \
@@ -20,7 +21,6 @@ LOCAL_SHARED_LIBRARIES := \
libcutils \
libgui \
libstlport \
- libsurfaceflinger_client \
libui \
libutils \
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
new file mode 100644
index 0000000..fd07479
--- /dev/null
+++ b/libs/gui/tests/Surface_test.cpp
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+
+#include <binder/IMemory.h>
+#include <surfaceflinger/ISurfaceComposer.h>
+#include <surfaceflinger/Surface.h>
+#include <surfaceflinger/SurfaceComposerClient.h>
+#include <utils/String8.h>
+
+namespace android {
+
+class SurfaceTest : public ::testing::Test {
+protected:
+ virtual void SetUp() {
+ mComposerClient = new SurfaceComposerClient;
+ ASSERT_EQ(NO_ERROR, mComposerClient->initCheck());
+
+ mSurfaceControl = mComposerClient->createSurface(getpid(),
+ String8("Test Surface"), 0, 32, 32, PIXEL_FORMAT_RGB_888, 0);
+
+ ASSERT_TRUE(mSurfaceControl != NULL);
+ ASSERT_TRUE(mSurfaceControl->isValid());
+
+ ASSERT_EQ(NO_ERROR, mComposerClient->openTransaction());
+ ASSERT_EQ(NO_ERROR, mSurfaceControl->setLayer(30000));
+ ASSERT_EQ(NO_ERROR, mSurfaceControl->show());
+ ASSERT_EQ(NO_ERROR, mComposerClient->closeTransaction());
+
+ mSurface = mSurfaceControl->getSurface();
+ ASSERT_TRUE(mSurface != NULL);
+ }
+
+ virtual void TearDown() {
+ mComposerClient->dispose();
+ }
+
+ sp<Surface> mSurface;
+ sp<SurfaceComposerClient> mComposerClient;
+ sp<SurfaceControl> mSurfaceControl;
+};
+
+TEST_F(SurfaceTest, QueuesToWindowComposerIsTrueWhenVisible) {
+ sp<ANativeWindow> anw(mSurface);
+ int result = -123;
+ int err = anw->query(anw.get(), NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER,
+ &result);
+ EXPECT_EQ(NO_ERROR, err);
+ EXPECT_EQ(1, result);
+}
+
+TEST_F(SurfaceTest, QueuesToWindowComposerIsTrueWhenPurgatorized) {
+ mSurfaceControl.clear();
+
+ sp<ANativeWindow> anw(mSurface);
+ int result = -123;
+ int err = anw->query(anw.get(), NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER,
+ &result);
+ EXPECT_EQ(NO_ERROR, err);
+ EXPECT_EQ(1, result);
+}
+
+// This test probably doesn't belong here.
+TEST_F(SurfaceTest, ScreenshotsOfProtectedBuffersFail) {
+ sp<ANativeWindow> anw(mSurface);
+
+ // Verify the screenshot works with no protected buffers.
+ sp<IMemoryHeap> heap;
+ uint32_t w=0, h=0;
+ PixelFormat fmt=0;
+ sp<ISurfaceComposer> sf(ComposerService::getComposerService());
+ ASSERT_EQ(NO_ERROR, sf->captureScreen(0, &heap, &w, &h, &fmt, 64, 64, 0,
+ 40000));
+ ASSERT_TRUE(heap != NULL);
+
+ // Set the PROTECTED usage bit and verify that the screenshot fails. Note
+ // that we need to dequeue a buffer in order for it to actually get
+ // allocated in SurfaceFlinger.
+ ASSERT_EQ(NO_ERROR, native_window_set_usage(anw.get(),
+ GRALLOC_USAGE_PROTECTED));
+ ASSERT_EQ(NO_ERROR, native_window_set_buffer_count(anw.get(), 3));
+ android_native_buffer_t* buf = 0;
+ for (int i = 0; i < 4; i++) {
+ // Loop to make sure SurfaceFlinger has retired a protected buffer.
+ ASSERT_EQ(NO_ERROR, anw->dequeueBuffer(anw.get(), &buf));
+ ASSERT_EQ(NO_ERROR, anw->lockBuffer(anw.get(), buf));
+ ASSERT_EQ(NO_ERROR, anw->queueBuffer(anw.get(), buf));
+ }
+ heap = 0;
+ w = h = fmt = 0;
+ ASSERT_EQ(INVALID_OPERATION, sf->captureScreen(0, &heap, &w, &h, &fmt,
+ 64, 64, 0, 40000));
+ ASSERT_TRUE(heap == NULL);
+
+ // XXX: This should not be needed, but it seems that the new buffers don't
+ // correctly show up after the upcoming dequeue/lock/queue loop without it.
+ // We should look into this at some point.
+ ASSERT_EQ(NO_ERROR, native_window_set_buffer_count(anw.get(), 3));
+
+ // Un-set the PROTECTED usage bit and verify that the screenshot works
+ // again. Note that we have to change the buffers geometry to ensure that
+ // the buffers get reallocated, as the new usage bits are a subset of the
+ // old.
+ ASSERT_EQ(NO_ERROR, native_window_set_usage(anw.get(), 0));
+ ASSERT_EQ(NO_ERROR, native_window_set_buffers_geometry(anw.get(), 32, 32, 0));
+ for (int i = 0; i < 4; i++) {
+ // Loop to make sure SurfaceFlinger has retired a protected buffer.
+ ASSERT_EQ(NO_ERROR, anw->dequeueBuffer(anw.get(), &buf));
+ ASSERT_EQ(NO_ERROR, anw->lockBuffer(anw.get(), buf));
+ ASSERT_EQ(NO_ERROR, anw->queueBuffer(anw.get(), buf));
+ }
+ heap = 0;
+ w = h = fmt = 0;
+ ASSERT_EQ(NO_ERROR, sf->captureScreen(0, &heap, &w, &h, &fmt, 64, 64, 0,
+ 40000));
+ ASSERT_TRUE(heap != NULL);
+}
+
+TEST_F(SurfaceTest, ConcreteTypeIsSurface) {
+ sp<ANativeWindow> anw(mSurface);
+ int result = -123;
+ int err = anw->query(anw.get(), NATIVE_WINDOW_CONCRETE_TYPE, &result);
+ EXPECT_EQ(NO_ERROR, err);
+ EXPECT_EQ(NATIVE_WINDOW_SURFACE, result);
+}
+
+}