Merge "Update Configuration for renaming and fixes"
diff --git a/include/gui/SurfaceTexture.h b/include/gui/SurfaceTexture.h
index 2b31462..9294df6 100644
--- a/include/gui/SurfaceTexture.h
+++ b/include/gui/SurfaceTexture.h
@@ -188,6 +188,11 @@
status_t setBufferCountServerLocked(int bufferCount);
+ // computeCurrentTransformMatrix computes the transform matrix for the
+ // current texture. It uses mCurrentTransform and the current GraphicBuffer
+ // to compute this matrix and stores it in mCurrentTransformMatrix.
+ void computeCurrentTransformMatrix();
+
enum { INVALID_BUFFER_SLOT = -1 };
struct BufferSlot {
@@ -288,9 +293,9 @@
// by calling setBufferCount or setBufferCountServer
int mBufferCount;
- // mRequestedBufferCount is the number of buffer slots requested by the
- // client. The default is zero, which means the client doesn't care how
- // many buffers there is.
+ // mClientBufferCount is the number of buffer slots requested by the client.
+ // The default is zero, which means the client doesn't care how many buffers
+ // there is.
int mClientBufferCount;
// mServerBufferCount buffer count requested by the server-side
@@ -322,6 +327,11 @@
// gets set to mLastQueuedTransform each time updateTexImage is called.
uint32_t mCurrentTransform;
+ // mCurrentTransformMatrix is the transform matrix for the current texture.
+ // It gets computed by computeTransformMatrix each time updateTexImage is
+ // called.
+ float mCurrentTransformMatrix[16];
+
// mCurrentTimestamp is the timestamp for the current texture. It
// gets set to mLastQueuedTimestamp each time updateTexImage is called.
int64_t mCurrentTimestamp;
@@ -362,6 +372,7 @@
// variables of SurfaceTexture objects. It must be locked whenever the
// member variables are accessed.
mutable Mutex mMutex;
+
};
// ----------------------------------------------------------------------------
diff --git a/include/utils/ResourceTypes.h b/include/utils/ResourceTypes.h
index 8a92cd6..612ff93 100644
--- a/include/utils/ResourceTypes.h
+++ b/include/utils/ResourceTypes.h
@@ -1988,7 +1988,8 @@
String16* outName,
const String16* defType = NULL,
const String16* defPackage = NULL,
- const char** outErrorMsg = NULL);
+ const char** outErrorMsg = NULL,
+ bool* outPublicOnly = NULL);
static bool stringToInt(const char16_t* s, size_t len, Res_value* outValue);
static bool stringToFloat(const char16_t* s, size_t len, Res_value* outValue);
diff --git a/include/utils/threads.h b/include/utils/threads.h
index 41e5766..0bd69cf 100644
--- a/include/utils/threads.h
+++ b/include/utils/threads.h
@@ -526,6 +526,7 @@
Thread& operator=(const Thread&);
static int _threadLoop(void* user);
const bool mCanCallJava;
+ // always hold mLock when reading or writing
thread_id_t mThread;
mutable Mutex mLock;
Condition mThreadExitedCondition;
diff --git a/libs/gui/SurfaceTexture.cpp b/libs/gui/SurfaceTexture.cpp
index ee97dcf..2cda4c8 100644
--- a/libs/gui/SurfaceTexture.cpp
+++ b/libs/gui/SurfaceTexture.cpp
@@ -96,6 +96,7 @@
sp<ISurfaceComposer> composer(ComposerService::getComposerService());
mGraphicBufferAlloc = composer->createGraphicBufferAlloc();
mNextCrop.makeInvalid();
+ memcpy(mCurrentTransformMatrix, mtxIdentity, sizeof(mCurrentTransformMatrix));
}
SurfaceTexture::~SurfaceTexture() {
@@ -547,6 +548,7 @@
mCurrentCrop = mSlots[buf].mCrop;
mCurrentTransform = mSlots[buf].mTransform;
mCurrentTimestamp = mSlots[buf].mTimestamp;
+ computeCurrentTransformMatrix();
mDequeueCondition.signal();
} else {
// We always bind the texture even if we don't update its contents.
@@ -596,8 +598,12 @@
}
void SurfaceTexture::getTransformMatrix(float mtx[16]) {
- LOGV("SurfaceTexture::getTransformMatrix");
Mutex::Autolock lock(mMutex);
+ memcpy(mtx, mCurrentTransformMatrix, sizeof(mCurrentTransformMatrix));
+}
+
+void SurfaceTexture::computeCurrentTransformMatrix() {
+ LOGV("SurfaceTexture::computeCurrentTransformMatrix");
float xform[16];
for (int i = 0; i < 16; i++) {
@@ -684,7 +690,7 @@
// coordinate of 0, so SurfaceTexture must behave the same way. We don't
// want to expose this to applications, however, so we must add an
// additional vertical flip to the transform after all the other transforms.
- mtxMul(mtx, mtxFlipV, mtxBeforeFlipV);
+ mtxMul(mCurrentTransformMatrix, mtxFlipV, mtxBeforeFlipV);
}
nsecs_t SurfaceTexture::getTimestamp() {
diff --git a/libs/gui/tests/SurfaceTextureClient_test.cpp b/libs/gui/tests/SurfaceTextureClient_test.cpp
index 2f704c8..da04b4a 100644
--- a/libs/gui/tests/SurfaceTextureClient_test.cpp
+++ b/libs/gui/tests/SurfaceTextureClient_test.cpp
@@ -514,4 +514,112 @@
thread->requestExitAndWait();
}
+TEST_F(SurfaceTextureClientTest, GetTransformMatrixReturnsVerticalFlip) {
+ sp<ANativeWindow> anw(mSTC);
+ sp<SurfaceTexture> st(mST);
+ android_native_buffer_t* buf[3];
+ float mtx[16] = {};
+ ASSERT_EQ(OK, native_window_set_buffer_count(anw.get(), 4));
+ ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf[0]));
+ ASSERT_EQ(OK, anw->queueBuffer(anw.get(), buf[0]));
+ ASSERT_EQ(OK, st->updateTexImage());
+ st->getTransformMatrix(mtx);
+
+ EXPECT_EQ(1.f, 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(-1.f, mtx[5]);
+ EXPECT_EQ(0.f, mtx[6]);
+ EXPECT_EQ(0.f, mtx[7]);
+
+ EXPECT_EQ(0.f, mtx[8]);
+ EXPECT_EQ(0.f, mtx[9]);
+ EXPECT_EQ(1.f, mtx[10]);
+ EXPECT_EQ(0.f, mtx[11]);
+
+ EXPECT_EQ(0.f, mtx[12]);
+ EXPECT_EQ(1.f, mtx[13]);
+ EXPECT_EQ(0.f, mtx[14]);
+ EXPECT_EQ(1.f, mtx[15]);
}
+
+TEST_F(SurfaceTextureClientTest, GetTransformMatrixSucceedsAfterFreeingBuffers) {
+ sp<ANativeWindow> anw(mSTC);
+ sp<SurfaceTexture> st(mST);
+ android_native_buffer_t* buf[3];
+ float mtx[16] = {};
+ ASSERT_EQ(OK, native_window_set_buffer_count(anw.get(), 4));
+ ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf[0]));
+ ASSERT_EQ(OK, anw->queueBuffer(anw.get(), buf[0]));
+ ASSERT_EQ(OK, st->updateTexImage());
+ ASSERT_EQ(OK, native_window_set_buffer_count(anw.get(), 6)); // frees buffers
+ st->getTransformMatrix(mtx);
+
+ EXPECT_EQ(1.f, 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(-1.f, mtx[5]);
+ EXPECT_EQ(0.f, mtx[6]);
+ EXPECT_EQ(0.f, mtx[7]);
+
+ EXPECT_EQ(0.f, mtx[8]);
+ EXPECT_EQ(0.f, mtx[9]);
+ EXPECT_EQ(1.f, mtx[10]);
+ EXPECT_EQ(0.f, mtx[11]);
+
+ EXPECT_EQ(0.f, mtx[12]);
+ EXPECT_EQ(1.f, mtx[13]);
+ EXPECT_EQ(0.f, mtx[14]);
+ EXPECT_EQ(1.f, mtx[15]);
+}
+
+TEST_F(SurfaceTextureClientTest, GetTransformMatrixSucceedsAfterFreeingBuffersWithCrop) {
+ sp<ANativeWindow> anw(mSTC);
+ sp<SurfaceTexture> st(mST);
+ android_native_buffer_t* buf[3];
+ float mtx[16] = {};
+ android_native_rect_t crop;
+ crop.left = 0;
+ crop.top = 0;
+ crop.right = 5;
+ crop.bottom = 5;
+
+ ASSERT_EQ(OK, native_window_set_buffer_count(anw.get(), 4));
+ ASSERT_EQ(OK, native_window_set_buffers_geometry(anw.get(), 8, 8, 0));
+ ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf[0]));
+ ASSERT_EQ(OK, native_window_set_crop(anw.get(), &crop));
+ ASSERT_EQ(OK, anw->queueBuffer(anw.get(), buf[0]));
+ ASSERT_EQ(OK, st->updateTexImage());
+ ASSERT_EQ(OK, native_window_set_buffer_count(anw.get(), 6)); // frees buffers
+ st->getTransformMatrix(mtx);
+
+ // This accounts for the 1 texel shrink for each edge that's included in the
+ // transform matrix to avoid texturing outside the crop region.
+ EXPECT_EQ(.5f, 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(-.5f, mtx[5]);
+ EXPECT_EQ(0.f, mtx[6]);
+ EXPECT_EQ(0.f, mtx[7]);
+
+ EXPECT_EQ(0.f, mtx[8]);
+ EXPECT_EQ(0.f, mtx[9]);
+ EXPECT_EQ(1.f, mtx[10]);
+ EXPECT_EQ(0.f, mtx[11]);
+
+ EXPECT_EQ(0.f, mtx[12]);
+ EXPECT_EQ(.5f, mtx[13]);
+ EXPECT_EQ(0.f, mtx[14]);
+ EXPECT_EQ(1.f, mtx[15]);
+}
+
+} // namespace android
diff --git a/libs/gui/tests/SurfaceTexture_test.cpp b/libs/gui/tests/SurfaceTexture_test.cpp
index 8747ba5..16280d2 100644
--- a/libs/gui/tests/SurfaceTexture_test.cpp
+++ b/libs/gui/tests/SurfaceTexture_test.cpp
@@ -14,11 +14,14 @@
* limitations under the License.
*/
+//#define LOG_NDEBUG 0
+
#include <gtest/gtest.h>
#include <gui/SurfaceTexture.h>
#include <gui/SurfaceTextureClient.h>
#include <ui/GraphicBuffer.h>
#include <utils/String8.h>
+#include <utils/threads.h>
#include <surfaceflinger/ISurfaceComposer.h>
#include <surfaceflinger/Surface.h>
@@ -618,4 +621,269 @@
}
}
+/*
+ * This test is for testing GL -> GL texture streaming via SurfaceTexture. It
+ * contains functionality to create a producer thread that will perform GL
+ * rendering to an ANativeWindow that feeds frames to a SurfaceTexture.
+ * Additionally it supports interlocking the producer and consumer threads so
+ * that a specific sequence of calls can be deterministically created by the
+ * test.
+ *
+ * The intended usage is as follows:
+ *
+ * TEST_F(...) {
+ * class PT : public ProducerThread {
+ * virtual void render() {
+ * ...
+ * swapBuffers();
+ * }
+ * };
+ *
+ * runProducerThread(new PT());
+ *
+ * // The order of these calls will vary from test to test and may include
+ * // multiple frames and additional operations (e.g. GL rendering from the
+ * // texture).
+ * fc->waitForFrame();
+ * mST->updateTexImage();
+ * fc->finishFrame();
+ * }
+ *
+ */
+class SurfaceTextureGLToGLTest : public SurfaceTextureGLTest {
+protected:
+
+ // ProducerThread is an abstract base class to simplify the creation of
+ // OpenGL ES frame producer threads.
+ class ProducerThread : public Thread {
+ public:
+ virtual ~ProducerThread() {
+ }
+
+ void setEglObjects(EGLDisplay producerEglDisplay,
+ EGLSurface producerEglSurface,
+ EGLContext producerEglContext) {
+ mProducerEglDisplay = producerEglDisplay;
+ mProducerEglSurface = producerEglSurface;
+ mProducerEglContext = producerEglContext;
+ }
+
+ virtual bool threadLoop() {
+ eglMakeCurrent(mProducerEglDisplay, mProducerEglSurface,
+ mProducerEglSurface, mProducerEglContext);
+ render();
+ eglMakeCurrent(mProducerEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE,
+ EGL_NO_CONTEXT);
+ return false;
+ }
+
+ protected:
+ virtual void render() = 0;
+
+ void swapBuffers() {
+ eglSwapBuffers(mProducerEglDisplay, mProducerEglSurface);
+ }
+
+ EGLDisplay mProducerEglDisplay;
+ EGLSurface mProducerEglSurface;
+ EGLContext mProducerEglContext;
+ };
+
+ // FrameCondition is a utility class for interlocking between the producer
+ // and consumer threads. The FrameCondition object should be created and
+ // destroyed in the consumer thread only. The consumer thread should set
+ // the FrameCondition as the FrameAvailableListener of the SurfaceTexture,
+ // and should call both waitForFrame and finishFrame once for each expected
+ // frame.
+ //
+ // This interlocking relies on the fact that onFrameAvailable gets called
+ // synchronously from SurfaceTexture::queueBuffer.
+ class FrameCondition : public SurfaceTexture::FrameAvailableListener {
+ public:
+ // waitForFrame waits for the next frame to arrive. This should be
+ // called from the consumer thread once for every frame expected by the
+ // test.
+ void waitForFrame() {
+ LOGV("+waitForFrame");
+ Mutex::Autolock lock(mMutex);
+ status_t result = mFrameAvailableCondition.wait(mMutex);
+ LOGV("-waitForFrame");
+ }
+
+ // Allow the producer to return from its swapBuffers call and continue
+ // on to produce the next frame. This should be called by the consumer
+ // thread once for every frame expected by the test.
+ void finishFrame() {
+ LOGV("+finishFrame");
+ Mutex::Autolock lock(mMutex);
+ mFrameFinishCondition.signal();
+ LOGV("-finishFrame");
+ }
+
+ // This should be called by SurfaceTexture on the producer thread.
+ virtual void onFrameAvailable() {
+ LOGV("+onFrameAvailable");
+ Mutex::Autolock lock(mMutex);
+ mFrameAvailableCondition.signal();
+ mFrameFinishCondition.wait(mMutex);
+ LOGV("-onFrameAvailable");
+ }
+
+ protected:
+ Mutex mMutex;
+ Condition mFrameAvailableCondition;
+ Condition mFrameFinishCondition;
+ };
+
+ SurfaceTextureGLToGLTest():
+ mProducerEglSurface(EGL_NO_SURFACE),
+ mProducerEglContext(EGL_NO_CONTEXT) {
+ }
+
+ virtual void SetUp() {
+ SurfaceTextureGLTest::SetUp();
+
+ EGLConfig myConfig = {0};
+ EGLint numConfigs = 0;
+ EXPECT_TRUE(eglChooseConfig(mEglDisplay, getConfigAttribs(), &myConfig,
+ 1, &numConfigs));
+ ASSERT_EQ(EGL_SUCCESS, eglGetError());
+
+ mProducerEglSurface = eglCreateWindowSurface(mEglDisplay, myConfig,
+ mANW.get(), NULL);
+ ASSERT_EQ(EGL_SUCCESS, eglGetError());
+ ASSERT_NE(EGL_NO_SURFACE, mProducerEglSurface);
+
+ mProducerEglContext = eglCreateContext(mEglDisplay, myConfig,
+ EGL_NO_CONTEXT, getContextAttribs());
+ ASSERT_EQ(EGL_SUCCESS, eglGetError());
+ ASSERT_NE(EGL_NO_CONTEXT, mProducerEglContext);
+
+ mFC = new FrameCondition();
+ mST->setFrameAvailableListener(mFC);
+ }
+
+ virtual void TearDown() {
+ if (mProducerThread != NULL) {
+ mProducerThread->requestExitAndWait();
+ }
+ if (mProducerEglContext != EGL_NO_CONTEXT) {
+ eglDestroyContext(mEglDisplay, mProducerEglContext);
+ }
+ if (mProducerEglSurface != EGL_NO_SURFACE) {
+ eglDestroySurface(mEglDisplay, mProducerEglSurface);
+ }
+ mProducerThread.clear();
+ mFC.clear();
+ }
+
+ void runProducerThread(const sp<ProducerThread> producerThread) {
+ ASSERT_TRUE(mProducerThread == NULL);
+ mProducerThread = producerThread;
+ producerThread->setEglObjects(mEglDisplay, mProducerEglSurface,
+ mProducerEglContext);
+ producerThread->run();
+ }
+
+ EGLSurface mProducerEglSurface;
+ EGLContext mProducerEglContext;
+ sp<ProducerThread> mProducerThread;
+ sp<FrameCondition> mFC;
+};
+
+// XXX: This test is disabled because it causes hangs on some devices.
+TEST_F(SurfaceTextureGLToGLTest, DISABLED_UpdateTexImageBeforeFrameFinishedWorks) {
+ class PT : public ProducerThread {
+ virtual void render() {
+ glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
+ glClear(GL_COLOR_BUFFER_BIT);
+ swapBuffers();
+ }
+ };
+
+ runProducerThread(new PT());
+
+ mFC->waitForFrame();
+ mST->updateTexImage();
+ mFC->finishFrame();
+
+ // TODO: Add frame verification once RGB TEX_EXTERNAL_OES is supported!
}
+
+TEST_F(SurfaceTextureGLToGLTest, UpdateTexImageAfterFrameFinishedWorks) {
+ class PT : public ProducerThread {
+ virtual void render() {
+ glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
+ glClear(GL_COLOR_BUFFER_BIT);
+ swapBuffers();
+ }
+ };
+
+ runProducerThread(new PT());
+
+ mFC->waitForFrame();
+ mFC->finishFrame();
+ mST->updateTexImage();
+
+ // TODO: Add frame verification once RGB TEX_EXTERNAL_OES is supported!
+}
+
+// XXX: This test is disabled because it causes hangs on some devices.
+TEST_F(SurfaceTextureGLToGLTest, DISABLED_RepeatedUpdateTexImageBeforeFrameFinishedWorks) {
+ enum { NUM_ITERATIONS = 1024 };
+
+ class PT : public ProducerThread {
+ virtual void render() {
+ for (int i = 0; i < NUM_ITERATIONS; i++) {
+ glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
+ glClear(GL_COLOR_BUFFER_BIT);
+ LOGV("+swapBuffers");
+ swapBuffers();
+ LOGV("-swapBuffers");
+ }
+ }
+ };
+
+ runProducerThread(new PT());
+
+ for (int i = 0; i < NUM_ITERATIONS; i++) {
+ mFC->waitForFrame();
+ LOGV("+updateTexImage");
+ mST->updateTexImage();
+ LOGV("-updateTexImage");
+ mFC->finishFrame();
+
+ // TODO: Add frame verification once RGB TEX_EXTERNAL_OES is supported!
+ }
+}
+
+// XXX: This test is disabled because it causes hangs on some devices.
+TEST_F(SurfaceTextureGLToGLTest, DISABLED_RepeatedUpdateTexImageAfterFrameFinishedWorks) {
+ enum { NUM_ITERATIONS = 1024 };
+
+ class PT : public ProducerThread {
+ virtual void render() {
+ for (int i = 0; i < NUM_ITERATIONS; i++) {
+ glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
+ glClear(GL_COLOR_BUFFER_BIT);
+ LOGV("+swapBuffers");
+ swapBuffers();
+ LOGV("-swapBuffers");
+ }
+ }
+ };
+
+ runProducerThread(new PT());
+
+ for (int i = 0; i < NUM_ITERATIONS; i++) {
+ mFC->waitForFrame();
+ mFC->finishFrame();
+ LOGV("+updateTexImage");
+ mST->updateTexImage();
+ LOGV("-updateTexImage");
+
+ // TODO: Add frame verification once RGB TEX_EXTERNAL_OES is supported!
+ }
+}
+
+} // namespace android
diff --git a/libs/utils/ResourceTypes.cpp b/libs/utils/ResourceTypes.cpp
index 4a6a3db..cb6c246 100644
--- a/libs/utils/ResourceTypes.cpp
+++ b/libs/utils/ResourceTypes.cpp
@@ -2663,6 +2663,9 @@
goto nope;
}
}
+ if (outTypeSpecFlags) {
+ *outTypeSpecFlags = ResTable_typeSpec::SPEC_PUBLIC;
+ }
return m->id;
nope:
;
@@ -2677,6 +2680,9 @@
index);
return 0;
}
+ if (outTypeSpecFlags) {
+ *outTypeSpecFlags = ResTable_typeSpec::SPEC_PUBLIC;
+ }
return Res_MAKEARRAY(index);
}
}
@@ -2687,6 +2693,8 @@
return 0;
}
+ bool fakePublic = false;
+
// Figure out the package and type we are looking in...
const char16_t* packageEnd = NULL;
@@ -2698,7 +2706,13 @@
else if (*p == '/') typeEnd = p;
p++;
}
- if (*name == '@') name++;
+ if (*name == '@') {
+ name++;
+ if (*name == '*') {
+ fakePublic = true;
+ name++;
+ }
+ }
if (name >= nameEnd) {
return 0;
}
@@ -2803,6 +2817,9 @@
if (dtohl(entry->key.index) == (size_t)ei) {
if (outTypeSpecFlags) {
*outTypeSpecFlags = typeConfigs->typeSpecFlags[i];
+ if (fakePublic) {
+ *outTypeSpecFlags |= ResTable_typeSpec::SPEC_PUBLIC;
+ }
}
return Res_MAKEID(group->id-1, ti, i);
}
@@ -2819,7 +2836,8 @@
String16* outName,
const String16* defType,
const String16* defPackage,
- const char** outErrorMsg)
+ const char** outErrorMsg,
+ bool* outPublicOnly)
{
const char16_t* packageEnd = NULL;
const char16_t* typeEnd = NULL;
@@ -2836,6 +2854,16 @@
p = refStr;
if (*p == '@') p++;
+ if (outPublicOnly != NULL) {
+ *outPublicOnly = true;
+ }
+ if (*p == '*') {
+ p++;
+ if (outPublicOnly != NULL) {
+ *outPublicOnly = false;
+ }
+ }
+
if (packageEnd) {
*outPackage = String16(p, packageEnd-p);
p = packageEnd+1;
diff --git a/libs/utils/Threads.cpp b/libs/utils/Threads.cpp
index 8b5da0e..c748228 100644
--- a/libs/utils/Threads.cpp
+++ b/libs/utils/Threads.cpp
@@ -168,6 +168,9 @@
return 0;
}
+ // Note that *threadID is directly available to the parent only, as it is
+ // assigned after the child starts. Use memory barrier / lock if the child
+ // or other threads also need access.
if (threadId != NULL) {
*threadId = (android_thread_id_t)thread; // XXX: this is not portable
}
@@ -718,7 +721,6 @@
res = androidCreateRawThreadEtc(_threadLoop,
this, name, priority, stack, &mThread);
}
- // The new thread wakes up at _threadLoop, but immediately blocks on mLock
if (res == false) {
mStatus = UNKNOWN_ERROR; // something happened!
@@ -742,11 +744,6 @@
{
Thread* const self = static_cast<Thread*>(user);
- // force a memory barrier before reading any fields, in particular mHoldSelf
- {
- Mutex::Autolock _l(self->mLock);
- }
-
sp<Thread> strong(self->mHoldSelf);
wp<Thread> weak(strong);
self->mHoldSelf.clear();
@@ -816,6 +813,7 @@
status_t Thread::requestExitAndWait()
{
+ Mutex::Autolock _l(mLock);
if (mThread == getThreadId()) {
LOGW(
"Thread (this=%p): don't call waitForExit() from this "
@@ -825,9 +823,8 @@
return WOULD_BLOCK;
}
- requestExit();
+ mExitPending = true;
- Mutex::Autolock _l(mLock);
while (mRunning == true) {
mThreadExitedCondition.wait(mLock);
}