Merge "Add timeout when waiting for HW vsync" into jb-mr1-dev
diff --git a/include/binder/IPCThreadState.h b/include/binder/IPCThreadState.h
index 691ba2f..3378d97 100644
--- a/include/binder/IPCThreadState.h
+++ b/include/binder/IPCThreadState.h
@@ -41,7 +41,6 @@
int getCallingPid();
int getCallingUid();
- int getOrigCallingUid();
void setStrictModePolicy(int32_t policy);
int32_t getStrictModePolicy() const;
@@ -117,7 +116,6 @@
status_t mLastError;
pid_t mCallingPid;
uid_t mCallingUid;
- uid_t mOrigCallingUid;
int32_t mStrictModePolicy;
int32_t mLastTransactionBinderFlags;
};
diff --git a/include/binder/Parcel.h b/include/binder/Parcel.h
index 877b17c..3ff95d2 100644
--- a/include/binder/Parcel.h
+++ b/include/binder/Parcel.h
@@ -285,9 +285,12 @@
return err;
}
}
- void* buffer = writeInplace(size);
- return buffer == NULL ? NO_MEMORY :
- val.flatten(buffer);
+ if (size) {
+ void* buffer = writeInplace(size);
+ return buffer == NULL ? NO_MEMORY :
+ val.flatten(buffer);
+ }
+ return NO_ERROR;
}
template<typename T>
@@ -303,9 +306,12 @@
}
size = s;
}
- void const* buffer = readInplace(size);
- return buffer == NULL ? NO_MEMORY :
- val.unflatten(buffer, size);
+ if (size) {
+ void const* buffer = readInplace(size);
+ return buffer == NULL ? NO_MEMORY :
+ val.unflatten(buffer, size);
+ }
+ return NO_ERROR;
}
// ---------------------------------------------------------------------------
diff --git a/include/ui/Region.h b/include/ui/Region.h
index f0819af..0049fde 100644
--- a/include/ui/Region.h
+++ b/include/ui/Region.h
@@ -28,6 +28,7 @@
namespace android {
// ---------------------------------------------------------------------------
+class SharedBuffer;
class String8;
// ---------------------------------------------------------------------------
@@ -41,10 +42,10 @@
Region& operator = (const Region& rhs);
- inline bool isEmpty() const { return mBounds.isEmpty(); }
- inline bool isRect() const { return mStorage.isEmpty(); }
+ inline bool isEmpty() const { return getBounds().isEmpty(); }
+ inline bool isRect() const { return mStorage.size() == 1; }
- inline Rect getBounds() const { return mBounds; }
+ inline Rect getBounds() const { return mStorage[mStorage.size() - 1]; }
inline Rect bounds() const { return getBounds(); }
// the region becomes its bounds
@@ -106,18 +107,24 @@
/* various ways to access the rectangle list */
+
+ // STL-like iterators
typedef Rect const* const_iterator;
-
- const_iterator begin() const;
- const_iterator end() const;
+ const_iterator begin() const;
+ const_iterator end() const;
+
+ // returns an array of rect which has the same life-time has this
+ // Region object.
+ Rect const* getArray(size_t* count) const;
+
+ // returns a SharedBuffer as well as the number of rects.
+ // ownership is transfered to the caller.
+ // the caller must call SharedBuffer::release() to free the memory.
+ SharedBuffer const* getSharedBuffer(size_t* count) const;
/* no user serviceable parts here... */
- size_t getRects(Vector<Rect>& rectList) const;
- Rect const* getArray(size_t* count) const;
-
-
// add a rectangle to the internal list. This rectangle must
// be sorted in Y and X and must not make the region invalid.
void addRectUnchecked(int l, int t, int r, int b);
@@ -156,8 +163,11 @@
static bool validate(const Region& reg, const char* name);
- Rect mBounds;
- Vector<Rect> mStorage;
+ // mStorage is a (manually) sorted array of Rects describing the region
+ // with an extra Rect as the last element which is set to the
+ // bounds of the region. However, if the region is
+ // a simple Rect then mStorage contains only that rect.
+ Vector<Rect> mStorage;
};
diff --git a/include/utils/SharedBuffer.h b/include/utils/SharedBuffer.h
index 24508b0..b670953 100644
--- a/include/utils/SharedBuffer.h
+++ b/include/utils/SharedBuffer.h
@@ -44,9 +44,6 @@
* users.
*/
static ssize_t dealloc(const SharedBuffer* released);
-
- //! get the SharedBuffer from the data pointer
- static inline const SharedBuffer* sharedBuffer(const void* data);
//! access the data for read
inline const void* data() const;
@@ -94,9 +91,10 @@
private:
inline SharedBuffer() { }
inline ~SharedBuffer() { }
- inline SharedBuffer(const SharedBuffer&);
+ SharedBuffer(const SharedBuffer&);
+ SharedBuffer& operator = (const SharedBuffer&);
- // 16 bytes. must be sized to preserve correct alingment.
+ // 16 bytes. must be sized to preserve correct alignment.
mutable int32_t mRefs;
size_t mSize;
uint32_t mReserved[2];
@@ -104,10 +102,6 @@
// ---------------------------------------------------------------------------
-const SharedBuffer* SharedBuffer::sharedBuffer(const void* data) {
- return data ? reinterpret_cast<const SharedBuffer *>(data)-1 : 0;
-}
-
const void* SharedBuffer::data() const {
return this + 1;
}
@@ -120,19 +114,16 @@
return mSize;
}
-SharedBuffer* SharedBuffer::bufferFromData(void* data)
-{
- return ((SharedBuffer*)data)-1;
+SharedBuffer* SharedBuffer::bufferFromData(void* data) {
+ return data ? static_cast<SharedBuffer *>(data)-1 : 0;
}
-const SharedBuffer* SharedBuffer::bufferFromData(const void* data)
-{
- return ((const SharedBuffer*)data)-1;
+const SharedBuffer* SharedBuffer::bufferFromData(const void* data) {
+ return data ? static_cast<const SharedBuffer *>(data)-1 : 0;
}
-size_t SharedBuffer::sizeFromData(const void* data)
-{
- return (((const SharedBuffer*)data)-1)->mSize;
+size_t SharedBuffer::sizeFromData(const void* data) {
+ return data ? bufferFromData(data)->mSize : 0;
}
bool SharedBuffer::onlyOwner() const {
diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp
index 7e416b9..6e83faa 100644
--- a/libs/binder/IPCThreadState.cpp
+++ b/libs/binder/IPCThreadState.cpp
@@ -371,11 +371,6 @@
return mCallingUid;
}
-int IPCThreadState::getOrigCallingUid()
-{
- return mOrigCallingUid;
-}
-
int64_t IPCThreadState::clearCallingIdentity()
{
int64_t token = ((int64_t)mCallingUid<<32) | mCallingPid;
@@ -646,7 +641,6 @@
{
pthread_setspecific(gTLS, this);
clearCaller();
- mOrigCallingUid = mCallingUid;
mIn.setDataCapacity(256);
mOut.setDataCapacity(256);
}
@@ -998,7 +992,6 @@
mCallingPid = tr.sender_pid;
mCallingUid = tr.sender_euid;
- mOrigCallingUid = tr.sender_euid;
int curPrio = getpriority(PRIO_PROCESS, mMyThreadId);
if (gDisableBackgroundScheduling) {
@@ -1056,7 +1049,6 @@
mCallingPid = origPid;
mCallingUid = origUid;
- mOrigCallingUid = origUid;
IF_LOG_TRANSACTIONS() {
TextOutput::Bundle _b(alog);
diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp
index db021ff..4640149 100644
--- a/libs/gui/BufferQueue.cpp
+++ b/libs/gui/BufferQueue.cpp
@@ -812,6 +812,23 @@
status_t BufferQueue::acquireBuffer(BufferItem *buffer) {
ATRACE_CALL();
Mutex::Autolock _l(mMutex);
+
+ // Check that the consumer doesn't currently have the maximum number of
+ // buffers acquired. We allow the max buffer count to be exceeded by one
+ // buffer, so that the consumer can successfully set up the newly acquired
+ // buffer before releasing the old one.
+ int numAcquiredBuffers = 0;
+ for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
+ if (mSlots[i].mBufferState == BufferSlot::ACQUIRED) {
+ numAcquiredBuffers++;
+ }
+ }
+ if (numAcquiredBuffers >= mMaxAcquiredBufferCount+1) {
+ ST_LOGE("acquireBuffer: max acquired buffer count reached: %d (max=%d)",
+ numAcquiredBuffers, mMaxAcquiredBufferCount);
+ return INVALID_OPERATION;
+ }
+
// check if queue is empty
// In asynchronous mode the list is guaranteed to be one buffer
// deep, while in synchronous mode we use the oldest buffer.
diff --git a/libs/gui/IGraphicBufferAlloc.cpp b/libs/gui/IGraphicBufferAlloc.cpp
index a70a5e8..139f219 100644
--- a/libs/gui/IGraphicBufferAlloc.cpp
+++ b/libs/gui/IGraphicBufferAlloc.cpp
@@ -55,7 +55,7 @@
status_t result = reply.readInt32();
if (result == NO_ERROR) {
graphicBuffer = new GraphicBuffer();
- reply.read(*graphicBuffer);
+ result = reply.read(*graphicBuffer);
// reply.readStrongBinder();
// here we don't even have to read the BufferReference from
// the parcel, it'll die with the parcel.
diff --git a/libs/gui/SurfaceTexture.cpp b/libs/gui/SurfaceTexture.cpp
index 9ed23be..975eb23 100644
--- a/libs/gui/SurfaceTexture.cpp
+++ b/libs/gui/SurfaceTexture.cpp
@@ -288,7 +288,9 @@
computeCurrentTransformMatrix();
} else {
if (err < 0) {
- ST_LOGE("updateTexImage failed on acquire %d", err);
+ ST_LOGE("updateTexImage: acquire failed: %s (%d)",
+ strerror(-err), err);
+ return err;
}
// We always bind the texture even if we don't update its contents.
glBindTexture(mTexTarget, mTexName);
diff --git a/libs/gui/tests/SurfaceTextureClient_test.cpp b/libs/gui/tests/SurfaceTextureClient_test.cpp
index 59b9efd..ec14a0d 100644
--- a/libs/gui/tests/SurfaceTextureClient_test.cpp
+++ b/libs/gui/tests/SurfaceTextureClient_test.cpp
@@ -241,7 +241,7 @@
EXPECT_EQ(1, buf->height);
EXPECT_EQ(PIXEL_FORMAT_RGB_565, buf->format);
ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf, -1));
- EXPECT_EQ(OK, native_window_set_buffers_geometry(mANW.get(), 16, 8, 0));
+ EXPECT_EQ(OK, native_window_set_buffers_dimensions(mANW.get(), 16, 8));
ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf));
EXPECT_EQ(16, buf->width);
EXPECT_EQ(8, buf->height);
@@ -597,15 +597,15 @@
ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 6)); // frees buffers
mST->getTransformMatrix(mtx);
- // This accounts for the 1 texel shrink for each edge that's included in the
+ // This accounts for the .5 texel shrink for each edge that's included in the
// transform matrix to avoid texturing outside the crop region.
- EXPECT_EQ(.375f, mtx[0]);
+ EXPECT_EQ(0.5, mtx[0]);
EXPECT_EQ(0.f, mtx[1]);
EXPECT_EQ(0.f, mtx[2]);
EXPECT_EQ(0.f, mtx[3]);
EXPECT_EQ(0.f, mtx[4]);
- EXPECT_EQ(-.375f, mtx[5]);
+ EXPECT_EQ(-0.5, mtx[5]);
EXPECT_EQ(0.f, mtx[6]);
EXPECT_EQ(0.f, mtx[7]);
@@ -614,8 +614,8 @@
EXPECT_EQ(1.f, mtx[10]);
EXPECT_EQ(0.f, mtx[11]);
- EXPECT_EQ(.125f, mtx[12]);
- EXPECT_EQ(.5f, mtx[13]);
+ EXPECT_EQ(0.0625f, mtx[12]);
+ EXPECT_EQ(0.5625f, mtx[13]);
EXPECT_EQ(0.f, mtx[14]);
EXPECT_EQ(1.f, mtx[15]);
}
diff --git a/libs/gui/tests/SurfaceTexture_test.cpp b/libs/gui/tests/SurfaceTexture_test.cpp
index 55b5968..212c6a7 100644
--- a/libs/gui/tests/SurfaceTexture_test.cpp
+++ b/libs/gui/tests/SurfaceTexture_test.cpp
@@ -711,7 +711,7 @@
ASSERT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), buf->getNativeBuffer(),
-1));
- mST->updateTexImage();
+ ASSERT_EQ(NO_ERROR, mST->updateTexImage());
glClearColor(0.2, 0.2, 0.2, 0.2);
glClear(GL_COLOR_BUFFER_BIT);
@@ -757,7 +757,7 @@
ASSERT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), buf->getNativeBuffer(),
-1));
- mST->updateTexImage();
+ ASSERT_EQ(NO_ERROR, mST->updateTexImage());
glClearColor(0.2, 0.2, 0.2, 0.2);
glClear(GL_COLOR_BUFFER_BIT);
@@ -817,7 +817,7 @@
ASSERT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(),
buf->getNativeBuffer(), -1));
- mST->updateTexImage();
+ ASSERT_EQ(NO_ERROR, mST->updateTexImage());
glClearColor(0.2, 0.2, 0.2, 0.2);
glClear(GL_COLOR_BUFFER_BIT);
@@ -966,7 +966,7 @@
if (i > 1) {
mFW->waitForFrame();
}
- mST->updateTexImage();
+ ASSERT_EQ(NO_ERROR, mST->updateTexImage());
drawTexture();
for (int j = 0; j < numTestPixels; j++) {
@@ -997,7 +997,7 @@
ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW));
- mST->updateTexImage();
+ ASSERT_EQ(NO_ERROR, mST->updateTexImage());
glClearColor(0.2, 0.2, 0.2, 0.2);
glClear(GL_COLOR_BUFFER_BIT);
@@ -1039,7 +1039,7 @@
ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW));
- mST->updateTexImage();
+ ASSERT_EQ(NO_ERROR, mST->updateTexImage());
glClearColor(0.2, 0.2, 0.2, 0.2);
glClear(GL_COLOR_BUFFER_BIT);
@@ -1196,7 +1196,7 @@
EXPECT_EQ (OK, native_window_dequeue_buffer_and_wait(mANW.get(), &anb));
EXPECT_EQ(OK, mANW->queueBuffer(mANW.get(), anb, -1));
mFW->waitForFrame();
- EXPECT_EQ(OK,mST->updateTexImage());
+ EXPECT_EQ(OK, mST->updateTexImage());
Rect r = mST->getCurrentCrop();
assertRectEq(Rect(23, 78, 123, 477), r);
@@ -1230,7 +1230,7 @@
EXPECT_EQ (OK, native_window_dequeue_buffer_and_wait(mANW.get(), &anb));
EXPECT_EQ(OK, mANW->queueBuffer(mANW.get(), anb, -1));
mFW->waitForFrame();
- EXPECT_EQ(OK,mST->updateTexImage());
+ EXPECT_EQ(OK, mST->updateTexImage());
Rect r = mST->getCurrentCrop();
// crop should be the same as crop (same aspect ratio)
assertRectEq(Rect(10, 20, 330, 200), r);
@@ -1241,7 +1241,7 @@
EXPECT_EQ (OK, native_window_dequeue_buffer_and_wait(mANW.get(), &anb));
EXPECT_EQ(OK, mANW->queueBuffer(mANW.get(), anb, -1));
mFW->waitForFrame();
- EXPECT_EQ(OK,mST->updateTexImage());
+ EXPECT_EQ(OK, mST->updateTexImage());
r = mST->getCurrentCrop();
// crop should be the same height, but have cropped left and right borders
// offset is 30.6 px L+, R-
@@ -1253,7 +1253,7 @@
EXPECT_EQ (OK, native_window_dequeue_buffer_and_wait(mANW.get(), &anb));
EXPECT_EQ(OK, mANW->queueBuffer(mANW.get(), anb, -1));
mFW->waitForFrame();
- EXPECT_EQ(OK,mST->updateTexImage());
+ EXPECT_EQ(OK, mST->updateTexImage());
r = mST->getCurrentCrop();
// crop should be the same width, but have cropped top and bottom borders
// offset is 37.5 px
@@ -1420,6 +1420,9 @@
mST->setDefaultBufferSize(texWidth, texHeight);
+ // This test requires 3 buffers to complete run on a single thread.
+ mST->setDefaultMaxBufferCount(3);
+
// Do the producer side of things
EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mProducerEglSurface,
mProducerEglSurface, mProducerEglContext));
@@ -1453,8 +1456,9 @@
glDisable(GL_SCISSOR_TEST);
- mST->updateTexImage(); // Skip the first frame, which was empty
- mST->updateTexImage();
+ // Skip the first frame, which was empty
+ ASSERT_EQ(NO_ERROR, mST->updateTexImage());
+ ASSERT_EQ(NO_ERROR, mST->updateTexImage());
glClearColor(0.2, 0.2, 0.2, 0.2);
glClear(GL_COLOR_BUFFER_BIT);
@@ -1508,7 +1512,7 @@
mEglContext));
ASSERT_EQ(EGL_SUCCESS, eglGetError());
mFW->waitForFrame();
- mST->updateTexImage();
+ ASSERT_EQ(NO_ERROR, mST->updateTexImage());
buffers[i] = mST->getCurrentBuffer();
}
@@ -1611,6 +1615,9 @@
enum { texWidth = 64 };
enum { texHeight = 64 };
+ // This test requires 3 buffers to complete run on a single thread.
+ mST->setDefaultMaxBufferCount(3);
+
// Set the user buffer size.
native_window_set_buffers_user_dimensions(mANW.get(), texWidth, texHeight);
@@ -1639,8 +1646,9 @@
glDisable(GL_SCISSOR_TEST);
- mST->updateTexImage(); // Skip the first frame, which was empty
- mST->updateTexImage();
+ // Skip the first frame, which was empty
+ ASSERT_EQ(NO_ERROR, mST->updateTexImage());
+ ASSERT_EQ(NO_ERROR, mST->updateTexImage());
glClearColor(0.2, 0.2, 0.2, 0.2);
glClear(GL_COLOR_BUFFER_BIT);
@@ -1664,6 +1672,9 @@
enum { texWidth = 64 };
enum { texHeight = 16 };
+ // This test requires 3 buffers to complete run on a single thread.
+ mST->setDefaultMaxBufferCount(3);
+
// Set the transform hint.
mST->setTransformHint(NATIVE_WINDOW_TRANSFORM_ROT_90);
@@ -1696,8 +1707,9 @@
glDisable(GL_SCISSOR_TEST);
- mST->updateTexImage(); // Skip the first frame, which was empty
- mST->updateTexImage();
+ // Skip the first frame, which was empty
+ ASSERT_EQ(NO_ERROR, mST->updateTexImage());
+ ASSERT_EQ(NO_ERROR, mST->updateTexImage());
glClearColor(0.2, 0.2, 0.2, 0.2);
glClear(GL_COLOR_BUFFER_BIT);
@@ -1721,6 +1733,9 @@
enum { texWidth = 64 };
enum { texHeight = 16 };
+ // This test requires 3 buffers to complete run on a single thread.
+ mST->setDefaultMaxBufferCount(3);
+
// Set the transform hint.
mST->setTransformHint(NATIVE_WINDOW_TRANSFORM_ROT_90);
@@ -1753,8 +1768,9 @@
glDisable(GL_SCISSOR_TEST);
- mST->updateTexImage(); // Skip the first frame, which was empty
- mST->updateTexImage();
+ // Skip the first frame, which was empty
+ ASSERT_EQ(NO_ERROR, mST->updateTexImage());
+ ASSERT_EQ(NO_ERROR, mST->updateTexImage());
glClearColor(0.2, 0.2, 0.2, 0.2);
glClear(GL_COLOR_BUFFER_BIT);
@@ -1944,7 +1960,7 @@
runProducerThread(new PT());
mFC->waitForFrame();
- mST->updateTexImage();
+ ASSERT_EQ(NO_ERROR, mST->updateTexImage());
mFC->finishFrame();
// TODO: Add frame verification once RGB TEX_EXTERNAL_OES is supported!
@@ -1964,7 +1980,7 @@
mFC->waitForFrame();
mFC->finishFrame();
- mST->updateTexImage();
+ ASSERT_EQ(NO_ERROR, mST->updateTexImage());
// TODO: Add frame verification once RGB TEX_EXTERNAL_OES is supported!
}
@@ -1990,7 +2006,7 @@
for (int i = 0; i < NUM_ITERATIONS; i++) {
mFC->waitForFrame();
ALOGV("+updateTexImage");
- mST->updateTexImage();
+ ASSERT_EQ(NO_ERROR, mST->updateTexImage());
ALOGV("-updateTexImage");
mFC->finishFrame();
@@ -2020,7 +2036,7 @@
mFC->waitForFrame();
mFC->finishFrame();
ALOGV("+updateTexImage");
- mST->updateTexImage();
+ ASSERT_EQ(NO_ERROR, mST->updateTexImage());
ALOGV("-updateTexImage");
// TODO: Add frame verification once RGB TEX_EXTERNAL_OES is supported!
@@ -2062,7 +2078,7 @@
// that happens before we call setDefaultMaxBufferCount. It's possible that the
// driver does not dequeue a buffer at EGLSurface creation time, so we
// cannot rely on this to cause the second dequeueBuffer call to block.
- mST->updateTexImage();
+ ASSERT_EQ(NO_ERROR, mST->updateTexImage());
mFC->waitForFrame();
mFC->finishFrame();
@@ -2081,15 +2097,15 @@
}
// Consume the two pending buffers to unblock the producer thread.
- mST->updateTexImage();
- mST->updateTexImage();
+ ASSERT_EQ(NO_ERROR, mST->updateTexImage());
+ ASSERT_EQ(NO_ERROR, mST->updateTexImage());
// Consume the remaining buffers from the producer thread.
for (int i = 0; i < NUM_ITERATIONS-3; i++) {
mFC->waitForFrame();
mFC->finishFrame();
ALOGV("+updateTexImage");
- mST->updateTexImage();
+ ASSERT_EQ(NO_ERROR, mST->updateTexImage());
ALOGV("-updateTexImage");
}
}
diff --git a/libs/ui/GraphicBuffer.cpp b/libs/ui/GraphicBuffer.cpp
index 57063e5..b9cab85 100644
--- a/libs/ui/GraphicBuffer.cpp
+++ b/libs/ui/GraphicBuffer.cpp
@@ -258,7 +258,12 @@
mOwner = ownHandle;
if (handle != 0) {
- mBufferMapper.registerBuffer(handle);
+ status_t err = mBufferMapper.registerBuffer(handle);
+ if (err != NO_ERROR) {
+ ALOGE("unflatten: registerBuffer failed: %s (%d)",
+ strerror(-err), err);
+ return err;
+ }
}
return NO_ERROR;
diff --git a/libs/ui/Region.cpp b/libs/ui/Region.cpp
index a3d8b01..94fb1d5 100644
--- a/libs/ui/Region.cpp
+++ b/libs/ui/Region.cpp
@@ -48,22 +48,20 @@
// ----------------------------------------------------------------------------
-Region::Region()
- : mBounds(0,0)
-{
+Region::Region() {
+ mStorage.add(Rect(0,0));
}
Region::Region(const Region& rhs)
- : mBounds(rhs.mBounds), mStorage(rhs.mStorage)
+ : mStorage(rhs.mStorage)
{
#if VALIDATE_REGIONS
validate(rhs, "rhs copy-ctor");
#endif
}
-Region::Region(const Rect& rhs)
- : mBounds(rhs)
-{
+Region::Region(const Rect& rhs) {
+ mStorage.add(rhs);
}
Region::~Region()
@@ -76,40 +74,46 @@
validate(*this, "this->operator=");
validate(rhs, "rhs.operator=");
#endif
- mBounds = rhs.mBounds;
mStorage = rhs.mStorage;
return *this;
}
Region& Region::makeBoundsSelf()
{
- mStorage.clear();
+ if (mStorage.size() >= 2) {
+ const Rect bounds(getBounds());
+ mStorage.clear();
+ mStorage.add(bounds);
+ }
return *this;
}
void Region::clear()
{
- mBounds.clear();
mStorage.clear();
+ mStorage.add(Rect(0,0));
}
void Region::set(const Rect& r)
{
- mBounds = r;
mStorage.clear();
+ mStorage.add(r);
}
void Region::set(uint32_t w, uint32_t h)
{
- mBounds = Rect(int(w), int(h));
mStorage.clear();
+ mStorage.add(Rect(w,h));
}
// ----------------------------------------------------------------------------
void Region::addRectUnchecked(int l, int t, int r, int b)
{
- mStorage.add(Rect(l,t,r,b));
+ Rect rect(l,t,r,b);
+ size_t where = mStorage.size() - 1;
+ mStorage.insertAt(rect, where, 1);
+
#if VALIDATE_REGIONS
validate(*this, "addRectUnchecked");
#endif
@@ -252,7 +256,7 @@
// to obtain an optimal region.
class Region::rasterizer : public region_operator<Rect>::region_rasterizer
{
- Rect& bounds;
+ Rect bounds;
Vector<Rect>& storage;
Rect* head;
Rect* tail;
@@ -260,10 +264,7 @@
Rect* cur;
public:
rasterizer(Region& reg)
- : bounds(reg.mBounds), storage(reg.mStorage), head(), tail(), cur() {
- bounds.top = bounds.bottom = 0;
- bounds.left = INT_MAX;
- bounds.right = INT_MIN;
+ : bounds(INT_MAX, 0, INT_MIN, 0), storage(reg.mStorage), head(), tail(), cur() {
storage.clear();
}
@@ -281,6 +282,7 @@
bounds.left = 0;
bounds.right = 0;
}
+ storage.add(bounds);
}
virtual void operator()(const Rect& rect) {
@@ -372,6 +374,9 @@
reg.getBounds().left, reg.getBounds().top,
reg.getBounds().right, reg.getBounds().bottom);
}
+ if (reg.mStorage.size() == 2) {
+ ALOGE("mStorage size is 2, which is never valid");
+ }
if (result == false) {
reg.dump(name);
}
@@ -529,11 +534,10 @@
void Region::translate(Region& reg, int dx, int dy)
{
- if (!reg.isEmpty()) {
+ if ((dx || dy) && !reg.isEmpty()) {
#if VALIDATE_REGIONS
validate(reg, "translate (before)");
#endif
- reg.mBounds.translate(dx, dy);
size_t count = reg.mStorage.size();
Rect* rects = reg.mStorage.editArray();
while (count) {
@@ -556,12 +560,11 @@
// ----------------------------------------------------------------------------
size_t Region::getSize() const {
- return (mStorage.size() + 1) * sizeof(Rect);
+ return mStorage.size() * sizeof(Rect);
}
status_t Region::flatten(void* buffer) const {
Rect* rects = reinterpret_cast<Rect*>(buffer);
- *rects++ = mBounds;
memcpy(rects, mStorage.array(), mStorage.size() * sizeof(Rect));
return NO_ERROR;
}
@@ -570,8 +573,6 @@
mStorage.clear();
if (size >= sizeof(Rect)) {
Rect const* rects = reinterpret_cast<Rect const*>(buffer);
- mBounds = *rects++;
- size -= sizeof(Rect);
size_t count = size / sizeof(Rect);
if (count > 0) {
ssize_t err = mStorage.insertAt(0, count);
@@ -581,25 +582,21 @@
memcpy(mStorage.editArray(), rects, count*sizeof(Rect));
}
}
+#if VALIDATE_REGIONS
+ validate(*this, "Region::unflatten");
+#endif
return NO_ERROR;
}
// ----------------------------------------------------------------------------
Region::const_iterator Region::begin() const {
- return isRect() ? &mBounds : mStorage.array();
+ return mStorage.array();
}
Region::const_iterator Region::end() const {
- if (isRect()) {
- if (isEmpty()) {
- return &mBounds;
- } else {
- return &mBounds + 1;
- }
- } else {
- return mStorage.array() + mStorage.size();
- }
+ size_t numRects = isRect() ? 1 : mStorage.size() - 1;
+ return mStorage.array() + numRects;
}
Rect const* Region::getArray(size_t* count) const {
@@ -609,14 +606,16 @@
return b;
}
-size_t Region::getRects(Vector<Rect>& rectList) const
-{
- rectList = mStorage;
- if (rectList.isEmpty()) {
- rectList.clear();
- rectList.add(mBounds);
+SharedBuffer const* Region::getSharedBuffer(size_t* count) const {
+ // We can get to the SharedBuffer of a Vector<Rect> because Rect has
+ // a trivial destructor.
+ SharedBuffer const* sb = SharedBuffer::bufferFromData(mStorage.array());
+ if (count) {
+ size_t numRects = isRect() ? 1 : mStorage.size() - 1;
+ count[0] = numRects;
}
- return rectList.size();
+ sb->acquire();
+ return sb;
}
// ----------------------------------------------------------------------------
diff --git a/libs/utils/VectorImpl.cpp b/libs/utils/VectorImpl.cpp
index 020ec15..8083bba 100644
--- a/libs/utils/VectorImpl.cpp
+++ b/libs/utils/VectorImpl.cpp
@@ -51,7 +51,7 @@
mFlags(rhs.mFlags), mItemSize(rhs.mItemSize)
{
if (mStorage) {
- SharedBuffer::sharedBuffer(mStorage)->acquire();
+ SharedBuffer::bufferFromData(mStorage)->acquire();
}
}
@@ -73,7 +73,7 @@
if (rhs.mCount) {
mStorage = rhs.mStorage;
mCount = rhs.mCount;
- SharedBuffer::sharedBuffer(mStorage)->acquire();
+ SharedBuffer::bufferFromData(mStorage)->acquire();
} else {
mStorage = 0;
mCount = 0;
@@ -85,7 +85,7 @@
void* VectorImpl::editArrayImpl()
{
if (mStorage) {
- SharedBuffer* sb = SharedBuffer::sharedBuffer(mStorage)->attemptEdit();
+ SharedBuffer* sb = SharedBuffer::bufferFromData(mStorage)->attemptEdit();
if (sb == 0) {
sb = SharedBuffer::alloc(capacity() * mItemSize);
if (sb) {
@@ -101,7 +101,7 @@
size_t VectorImpl::capacity() const
{
if (mStorage) {
- return SharedBuffer::sharedBuffer(mStorage)->size() / mItemSize;
+ return SharedBuffer::bufferFromData(mStorage)->size() / mItemSize;
}
return 0;
}
@@ -346,7 +346,7 @@
void VectorImpl::release_storage()
{
if (mStorage) {
- const SharedBuffer* sb = SharedBuffer::sharedBuffer(mStorage);
+ const SharedBuffer* sb = SharedBuffer::bufferFromData(mStorage);
if (sb->release(SharedBuffer::eKeepStorage) == 1) {
_do_destroy(mStorage, mCount);
SharedBuffer::dealloc(sb);
@@ -372,7 +372,7 @@
(mFlags & HAS_TRIVIAL_COPY) &&
(mFlags & HAS_TRIVIAL_DTOR))
{
- const SharedBuffer* cur_sb = SharedBuffer::sharedBuffer(mStorage);
+ const SharedBuffer* cur_sb = SharedBuffer::bufferFromData(mStorage);
SharedBuffer* sb = cur_sb->editResize(new_capacity * mItemSize);
mStorage = sb->data();
} else {
@@ -424,7 +424,7 @@
(mFlags & HAS_TRIVIAL_COPY) &&
(mFlags & HAS_TRIVIAL_DTOR))
{
- const SharedBuffer* cur_sb = SharedBuffer::sharedBuffer(mStorage);
+ const SharedBuffer* cur_sb = SharedBuffer::bufferFromData(mStorage);
SharedBuffer* sb = cur_sb->editResize(new_capacity * mItemSize);
mStorage = sb->data();
} else {
diff --git a/services/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk
index dd0dc16..07002cc 100644
--- a/services/surfaceflinger/Android.mk
+++ b/services/surfaceflinger/Android.mk
@@ -52,3 +52,19 @@
LOCAL_MODULE:= libsurfaceflinger
include $(BUILD_SHARED_LIBRARY)
+
+###############################################################
+# uses jni which may not be available in PDK
+ifneq ($(wildcard libnativehelper/include),)
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES:= \
+ DdmConnection.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+ libcutils \
+ libdl
+
+LOCAL_MODULE:= libsurfaceflinger_ddmconnection
+
+include $(BUILD_SHARED_LIBRARY)
+endif # libnativehelper
diff --git a/services/surfaceflinger/DdmConnection.cpp b/services/surfaceflinger/DdmConnection.cpp
index 433b38e..ece965c 100644
--- a/services/surfaceflinger/DdmConnection.cpp
+++ b/services/surfaceflinger/DdmConnection.cpp
@@ -23,6 +23,10 @@
namespace android {
+void DdmConnection_start(const char* name) {
+ ALOGI("DdmConnection_start");
+ DdmConnection::start(name);
+}
void DdmConnection::start(const char* name) {
JavaVM* vm;
diff --git a/services/surfaceflinger/DdmConnection.h b/services/surfaceflinger/DdmConnection.h
index 91b737c..b6b088b 100644
--- a/services/surfaceflinger/DdmConnection.h
+++ b/services/surfaceflinger/DdmConnection.h
@@ -19,6 +19,9 @@
namespace android {
+// wrapper for dlsym
+extern "C" void DdmConnection_start(const char* name);
+
class DdmConnection {
public:
static void start(const char* name);
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 75c228d..23290e3 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -132,23 +132,21 @@
mCBContext->hwc = this;
mCBContext->procs.invalidate = &hook_invalidate;
mCBContext->procs.vsync = &hook_vsync;
+ if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1))
+ mCBContext->procs.hotplug = &hook_hotplug;
+ else
+ mCBContext->procs.hotplug = NULL;
memset(mCBContext->procs.zero, 0, sizeof(mCBContext->procs.zero));
mHwc->registerProcs(mHwc, &mCBContext->procs);
}
// always turn vsync off when we start
needVSyncThread = false;
- mHwc->eventControl(mHwc, 0, HWC_EVENT_VSYNC, 0);
-
- int period;
- if (mHwc->query(mHwc, HWC_VSYNC_PERIOD, &period) == NO_ERROR) {
- mDisplayData[HWC_DISPLAY_PRIMARY].refresh = nsecs_t(period);
- }
+ mHwc->eventControl(mHwc, HWC_DISPLAY_PRIMARY, HWC_EVENT_VSYNC, 0);
// these IDs are always reserved
for (size_t i=0 ; i<HWC_NUM_DISPLAY_TYPES ; i++) {
mAllocatedDisplayIDs.markBit(i);
- // TODO: we query xdpi / ydpi / refresh
}
// the number of displays we actually have depends on the
@@ -166,7 +164,9 @@
}
if (fbDev) {
- // if we're here it means we are on version 1.0
+ ALOG_ASSERT(!(mHwc && hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)),
+ "should only have fbdev if no hwc or hwc is 1.0");
+
DisplayData& disp(mDisplayData[HWC_DISPLAY_PRIMARY]);
disp.xdpi = fbDev->xdpi;
disp.ydpi = fbDev->ydpi;
@@ -176,8 +176,11 @@
}
if (disp.refresh == 0) {
disp.refresh = nsecs_t(1e9 / 60.0);
- ALOGW("getting VSYNC period thin air: %lld", mDisplayData[HWC_DISPLAY_PRIMARY].refresh);
+ ALOGW("getting VSYNC period from thin air: %lld",
+ mDisplayData[HWC_DISPLAY_PRIMARY].refresh);
}
+ } else if (mHwc) {
+ queryDisplayProperties(HWC_DISPLAY_PRIMARY);
}
if (needVSyncThread) {
@@ -207,24 +210,111 @@
ctx->hwc->invalidate();
}
-void HWComposer::hook_vsync(const struct hwc_procs* procs, int dpy,
+void HWComposer::hook_vsync(const struct hwc_procs* procs, int disp,
int64_t timestamp) {
cb_context* ctx = reinterpret_cast<cb_context*>(
const_cast<hwc_procs_t*>(procs));
- ctx->hwc->vsync(dpy, timestamp);
+ ctx->hwc->vsync(disp, timestamp);
+}
+
+void HWComposer::hook_hotplug(const struct hwc_procs* procs, int disp,
+ int connected) {
+ cb_context* ctx = reinterpret_cast<cb_context*>(
+ const_cast<hwc_procs_t*>(procs));
+ ctx->hwc->hotplug(disp, connected);
}
void HWComposer::invalidate() {
mFlinger->repaintEverything();
}
-void HWComposer::vsync(int dpy, int64_t timestamp) {
+void HWComposer::vsync(int disp, int64_t timestamp) {
ATRACE_INT("VSYNC", ++mVSyncCount&1);
- mEventHandler.onVSyncReceived(dpy, timestamp);
+ mEventHandler.onVSyncReceived(disp, timestamp);
Mutex::Autolock _l(mLock);
mLastHwVSync = timestamp;
}
+void HWComposer::hotplug(int disp, int connected) {
+ if (disp == HWC_DISPLAY_PRIMARY || disp >= HWC_NUM_DISPLAY_TYPES) {
+ ALOGE("hotplug event received for invalid display: disp=%d connected=%d",
+ disp, connected);
+ return;
+ }
+
+ if (connected)
+ queryDisplayProperties(disp);
+
+ // TODO: tell someone else about this
+}
+
+static const uint32_t DISPLAY_ATTRIBUTES[] = {
+ HWC_DISPLAY_VSYNC_PERIOD,
+ HWC_DISPLAY_RESOLUTION_X,
+ HWC_DISPLAY_RESOLUTION_Y,
+ HWC_DISPLAY_DPI_X,
+ HWC_DISPLAY_DPI_Y,
+ HWC_DISPLAY_NO_ATTRIBUTE,
+};
+#define NUM_DISPLAY_ATTRIBUTES (sizeof(DISPLAY_ATTRIBUTES) / sizeof(DISPLAY_ATTRIBUTES)[0])
+
+// http://developer.android.com/reference/android/util/DisplayMetrics.html
+#define ANDROID_DENSITY_TV 213
+#define ANDROID_DENSITY_XHIGH 320
+
+void HWComposer::queryDisplayProperties(int disp) {
+ ALOG_ASSERT(mHwc && hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1));
+
+ int32_t values[NUM_DISPLAY_ATTRIBUTES - 1];
+ memset(values, 0, sizeof(values));
+
+ uint32_t config;
+ size_t numConfigs = 1;
+ status_t err = mHwc->getDisplayConfigs(mHwc, disp, &config, &numConfigs);
+ if (err == NO_ERROR) {
+ mHwc->getDisplayAttributes(mHwc, disp, config, DISPLAY_ATTRIBUTES,
+ values);
+ }
+
+ int32_t w = 0, h = 0;
+ for (size_t i = 0; i < NUM_DISPLAY_ATTRIBUTES - 1; i++) {
+ switch (DISPLAY_ATTRIBUTES[i]) {
+ case HWC_DISPLAY_VSYNC_PERIOD:
+ mDisplayData[disp].refresh = nsecs_t(values[i]);
+ break;
+ case HWC_DISPLAY_RESOLUTION_X:
+ // TODO: we'll probably want to remember this eventually
+ w = values[i];
+ break;
+ case HWC_DISPLAY_RESOLUTION_Y:
+ // TODO: we'll probably want to remember this eventually
+ h = values[i];
+ break;
+ case HWC_DISPLAY_DPI_X:
+ mDisplayData[disp].xdpi = values[i] / 1000.0f;
+ break;
+ case HWC_DISPLAY_DPI_Y:
+ mDisplayData[disp].ydpi = values[i] / 1000.0f;
+ break;
+ default:
+ ALOG_ASSERT(false, "unknown display attribute %#x",
+ DISPLAY_ATTRIBUTES[i]);
+ break;
+ }
+ }
+
+ if (mDisplayData[disp].xdpi == 0.0f || mDisplayData[disp].ydpi == 0.0f) {
+ // is there anything smarter we can do?
+ if (h >= 1080) {
+ mDisplayData[disp].xdpi = ANDROID_DENSITY_XHIGH;
+ mDisplayData[disp].ydpi = ANDROID_DENSITY_XHIGH;
+ } else {
+ mDisplayData[disp].xdpi = ANDROID_DENSITY_TV;
+ mDisplayData[disp].ydpi = ANDROID_DENSITY_TV;
+ }
+ }
+}
+
int32_t HWComposer::allocateDisplayId() {
if (mAllocatedDisplayIDs.count() >= mNumDisplays) {
return NO_MEMORY;
@@ -483,9 +573,12 @@
reinterpret_cast<Rect&>(getLayer()->sourceCrop) = crop;
}
virtual void setVisibleRegionScreen(const Region& reg) {
- getLayer()->visibleRegionScreen.rects =
- reinterpret_cast<hwc_rect_t const *>(
- reg.getArray(&getLayer()->visibleRegionScreen.numRects));
+ // Region::getSharedBuffer creates a reference to the underlying
+ // SharedBuffer of this Region, this reference is freed
+ // in onDisplayed()
+ hwc_region_t& visibleRegion = getLayer()->visibleRegionScreen;
+ SharedBuffer const* sb = reg.getSharedBuffer(&visibleRegion.numRects);
+ visibleRegion.rects = reinterpret_cast<hwc_rect_t const *>(sb->data());
}
virtual void setBuffer(const sp<GraphicBuffer>& buffer) {
if (buffer == 0 || buffer->handle == 0) {
@@ -496,6 +589,16 @@
getLayer()->handle = buffer->handle;
}
}
+ virtual void onDisplayed() {
+ hwc_region_t& visibleRegion = getLayer()->visibleRegionScreen;
+ SharedBuffer const* sb = SharedBuffer::bufferFromData(visibleRegion.rects);
+ if (sb) {
+ sb->release();
+ // not technically needed but safer
+ visibleRegion.numRects = 0;
+ visibleRegion.rects = NULL;
+ }
+ }
};
/*
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index 7b92d2e..a49a023 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -53,7 +53,7 @@
public:
class EventHandler {
friend class HWComposer;
- virtual void onVSyncReceived(int dpy, nsecs_t timestamp) = 0;
+ virtual void onVSyncReceived(int disp, nsecs_t timestamp) = 0;
protected:
virtual ~EventHandler() {}
};
@@ -130,6 +130,7 @@
virtual void setVisibleRegionScreen(const Region& reg) = 0;
virtual void setBuffer(const sp<GraphicBuffer>& buffer) = 0;
virtual void setAcquireFenceFd(int fenceFd) = 0;
+ virtual void onDisplayed() = 0;
};
/*
@@ -242,12 +243,16 @@
struct cb_context;
static void hook_invalidate(const struct hwc_procs* procs);
- static void hook_vsync(const struct hwc_procs* procs, int dpy,
+ static void hook_vsync(const struct hwc_procs* procs, int disp,
int64_t timestamp);
+ static void hook_hotplug(const struct hwc_procs* procs, int disp,
+ int connected);
inline void invalidate();
- inline void vsync(int dpy, int64_t timestamp);
+ inline void vsync(int disp, int64_t timestamp);
+ inline void hotplug(int disp, int connected);
+ void queryDisplayProperties(int disp);
struct DisplayData {
DisplayData() : xdpi(0), ydpi(0), refresh(0),
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index ea1bc54..f928805 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -72,6 +72,7 @@
void Layer::onLayerDisplayed(const sp<const DisplayDevice>& hw,
HWComposer::HWCLayerInterface* layer) {
+ LayerBaseClient::onLayerDisplayed(hw, layer);
if (layer) {
mSurfaceTexture->setReleaseFence(layer->getAndResetReleaseFenceFd());
}
diff --git a/services/surfaceflinger/LayerBase.cpp b/services/surfaceflinger/LayerBase.cpp
index a2513a2..87dc572 100644
--- a/services/surfaceflinger/LayerBase.cpp
+++ b/services/surfaceflinger/LayerBase.cpp
@@ -288,12 +288,16 @@
// scaling is already applied in transformedBounds
layer.setFrame(transformedBounds);
layer.setCrop(transformedBounds.getBounds());
- layer.setVisibleRegionScreen(tr.transform(visibleRegion));
}
void LayerBase::setPerFrameData(const sp<const DisplayDevice>& hw,
HWComposer::HWCLayerInterface& layer) {
layer.setBuffer(0);
+ // we have to set the visible region on every frame because
+ // we currently free it during onLayerDisplayed(), which is called
+ // after HWComposer::commit() -- every frame.
+ const Transform& tr = hw->getTransform();
+ layer.setVisibleRegionScreen(tr.transform(visibleRegion));
}
void LayerBase::setAcquireFence(const sp<const DisplayDevice>& hw,
@@ -301,6 +305,13 @@
layer.setAcquireFenceFd(-1);
}
+void LayerBase::onLayerDisplayed(const sp<const DisplayDevice>& hw,
+ HWComposer::HWCLayerInterface* layer) {
+ if (layer) {
+ layer->onDisplayed();
+ }
+}
+
void LayerBase::setFiltering(bool filtering)
{
mFiltering = filtering;
diff --git a/services/surfaceflinger/LayerBase.h b/services/surfaceflinger/LayerBase.h
index c18f397..4651517 100644
--- a/services/surfaceflinger/LayerBase.h
+++ b/services/surfaceflinger/LayerBase.h
@@ -218,7 +218,7 @@
/** called after page-flip
*/
virtual void onLayerDisplayed(const sp<const DisplayDevice>& hw,
- HWComposer::HWCLayerInterface* layer) { }
+ HWComposer::HWCLayerInterface* layer);
/** called before composition.
* returns true if the layer has pending updates.
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index cd1b336..ee653f3 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -20,6 +20,7 @@
#include <sys/types.h>
#include <errno.h>
#include <math.h>
+#include <dlfcn.h>
#include <EGL/egl.h>
#include <GLES/gl.h>
@@ -108,9 +109,11 @@
property_get("debug.sf.ddms", value, "0");
mDebugDDMS = atoi(value);
if (mDebugDDMS) {
- DdmConnection::start(getServiceName());
+ if (!startDdmConnection()) {
+ // start failed, and DDMS debugging not enabled
+ mDebugDDMS = 0;
+ }
}
-
ALOGI_IF(mDebugRegion, "showupdates enabled");
ALOGI_IF(mDebugDDMS, "DDMS debugging enabled");
}
@@ -1255,8 +1258,9 @@
// FIXME: we need to call eglSwapBuffers() on displays that have
// GL composition and only on those.
// however, currently hwc.commit() already does that for the main
- // display and never for the other ones
- if (hw->getDisplayType() >= DisplayDevice::DISPLAY_VIRTUAL) {
+ // display (if there is a hwc) and never for the other ones
+ if (hw->getDisplayType() >= DisplayDevice::DISPLAY_VIRTUAL ||
+ getHwComposer().initCheck() != NO_ERROR) {
// FIXME: EGL spec says:
// "surface must be bound to the calling thread's current context,
// for the current rendering API."
@@ -2060,6 +2064,24 @@
hw->dump(result);
}
+bool SurfaceFlinger::startDdmConnection()
+{
+ void* libddmconnection_dso =
+ dlopen("libsurfaceflinger_ddmconnection.so", RTLD_NOW);
+ if (!libddmconnection_dso) {
+ return false;
+ }
+ void (*DdmConnection_start)(const char* name);
+ DdmConnection_start =
+ (typeof DdmConnection_start)dlsym(libddmconnection_dso, "DdmConnection_start");
+ if (!DdmConnection_start) {
+ dlclose(libddmconnection_dso);
+ return false;
+ }
+ (*DdmConnection_start)(getServiceName());
+ return true;
+}
+
status_t SurfaceFlinger::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 50fef00..9db6b2d 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -388,6 +388,7 @@
void clearStatsLocked(const Vector<String16>& args, size_t& index,
String8& result, char* buffer, size_t SIZE) const;
void dumpAllLocked(String8& result, char* buffer, size_t SIZE) const;
+ bool startDdmConnection();
/* ------------------------------------------------------------------------
* Attributes