Merge "Fix change of behavior in Looper.quit()." into jb-mr2-dev
This commit is contained in:
@@ -17121,6 +17121,7 @@ package android.os {
|
||||
method public int getThreadId();
|
||||
method protected void onLooperPrepared();
|
||||
method public boolean quit();
|
||||
method public boolean quitSafely();
|
||||
}
|
||||
|
||||
public abstract interface IBinder {
|
||||
@@ -17161,6 +17162,7 @@ package android.os {
|
||||
method public static void prepare();
|
||||
method public static void prepareMainLooper();
|
||||
method public void quit();
|
||||
method public void quitSafely();
|
||||
method public void setMessageLogging(android.util.Printer);
|
||||
}
|
||||
|
||||
|
||||
@@ -413,27 +413,32 @@ public class Handler {
|
||||
|
||||
/**
|
||||
* Runs the specified task synchronously.
|
||||
*
|
||||
* <p>
|
||||
* If the current thread is the same as the handler thread, then the runnable
|
||||
* runs immediately without being enqueued. Otherwise, posts the runnable
|
||||
* to the handler and waits for it to complete before returning.
|
||||
*
|
||||
* </p><p>
|
||||
* This method is dangerous! Improper use can result in deadlocks.
|
||||
* Never call this method while any locks are held or use it in a
|
||||
* possibly re-entrant manner.
|
||||
*
|
||||
* </p><p>
|
||||
* This method is occasionally useful in situations where a background thread
|
||||
* must synchronously await completion of a task that must run on the
|
||||
* handler's thread. However, this problem is often a symptom of bad design.
|
||||
* Consider improving the design (if possible) before resorting to this method.
|
||||
*
|
||||
* </p><p>
|
||||
* One example of where you might want to use this method is when you just
|
||||
* set up a Handler thread and need to perform some initialization steps on
|
||||
* it before continuing execution.
|
||||
*
|
||||
* </p><p>
|
||||
* If timeout occurs then this method returns <code>false</code> but the runnable
|
||||
* will remain posted on the handler and may already be in progress or
|
||||
* complete at a later time.
|
||||
* </p><p>
|
||||
* When using this method, be sure to use {@link Looper#quitSafely} when
|
||||
* quitting the looper. Otherwise {@link #runWithScissors} may hang indefinitely.
|
||||
* (TODO: We should fix this by making MessageQueue aware of blocking runnables.)
|
||||
* </p>
|
||||
*
|
||||
* @param r The Runnable that will be executed synchronously.
|
||||
* @param timeout The timeout in milliseconds, or 0 to wait indefinitely.
|
||||
|
||||
@@ -48,6 +48,7 @@ public class HandlerThread extends Thread {
|
||||
protected void onLooperPrepared() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
mTid = Process.myTid();
|
||||
Looper.prepare();
|
||||
@@ -83,12 +84,25 @@ public class HandlerThread extends Thread {
|
||||
}
|
||||
return mLooper;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Ask the currently running looper to quit. If the thread has not
|
||||
* been started or has finished (that is if {@link #getLooper} returns
|
||||
* null), then false is returned. Otherwise the looper is asked to
|
||||
* quit and true is returned.
|
||||
* Quits the handler thread's looper.
|
||||
* <p>
|
||||
* Causes the handler thread's looper to terminate without processing any
|
||||
* more messages in the message queue.
|
||||
* </p><p>
|
||||
* Any attempt to post messages to the queue after the looper is asked to quit will fail.
|
||||
* For example, the {@link Handler#sendMessage(Message)} method will return false.
|
||||
* </p><p class="note">
|
||||
* Using this method may be unsafe because some messages may not be delivered
|
||||
* before the looper terminates. Consider using {@link #quitSafely} instead to ensure
|
||||
* that all pending work is completed in an orderly manner.
|
||||
* </p>
|
||||
*
|
||||
* @return True if the looper looper has been asked to quit or false if the
|
||||
* thread had not yet started running.
|
||||
*
|
||||
* @see #quitSafely
|
||||
*/
|
||||
public boolean quit() {
|
||||
Looper looper = getLooper();
|
||||
@@ -98,7 +112,34 @@ public class HandlerThread extends Thread {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Quits the handler thread's looper safely.
|
||||
* <p>
|
||||
* Causes the handler thread's looper to terminate as soon as all remaining messages
|
||||
* in the message queue that are already due to be delivered have been handled.
|
||||
* Pending delayed messages with due times in the future will not be delivered.
|
||||
* </p><p>
|
||||
* Any attempt to post messages to the queue after the looper is asked to quit will fail.
|
||||
* For example, the {@link Handler#sendMessage(Message)} method will return false.
|
||||
* </p><p>
|
||||
* If the thread has not been started or has finished (that is if
|
||||
* {@link #getLooper} returns null), then false is returned.
|
||||
* Otherwise the looper is asked to quit and true is returned.
|
||||
* </p>
|
||||
*
|
||||
* @return True if the looper looper has been asked to quit or false if the
|
||||
* thread had not yet started running.
|
||||
*/
|
||||
public boolean quitSafely() {
|
||||
Looper looper = getLooper();
|
||||
if (looper != null) {
|
||||
looper.quitSafely();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the identifier of this thread. See Process.myTid().
|
||||
*/
|
||||
|
||||
@@ -202,18 +202,37 @@ public final class Looper {
|
||||
/**
|
||||
* Quits the looper.
|
||||
* <p>
|
||||
* Causes the {@link #loop} method to terminate as soon as all remaining messages
|
||||
* in the message queue that are already due to be delivered have been handled.
|
||||
* However delayed messages with due times in the future may not be handled before
|
||||
* the loop terminates.
|
||||
* Causes the {@link #loop} method to terminate without processing any
|
||||
* more messages in the message queue.
|
||||
* </p><p>
|
||||
* Any attempt to post messages to the queue after {@link #quit} has been called
|
||||
* will fail. For example, the {@link Handler#sendMessage(Message)} method will
|
||||
* return false when the looper is being terminated.
|
||||
* Any attempt to post messages to the queue after the looper is asked to quit will fail.
|
||||
* For example, the {@link Handler#sendMessage(Message)} method will return false.
|
||||
* </p><p class="note">
|
||||
* Using this method may be unsafe because some messages may not be delivered
|
||||
* before the looper terminates. Consider using {@link #quitSafely} instead to ensure
|
||||
* that all pending work is completed in an orderly manner.
|
||||
* </p>
|
||||
*
|
||||
* @see #quitSafely
|
||||
*/
|
||||
public void quit() {
|
||||
mQueue.quit();
|
||||
mQueue.quit(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Quits the looper safely.
|
||||
* <p>
|
||||
* Causes the {@link #loop} method to terminate as soon as all remaining messages
|
||||
* in the message queue that are already due to be delivered have been handled.
|
||||
* However pending delayed messages with due times in the future will not be
|
||||
* delivered before the loop terminates.
|
||||
* </p><p>
|
||||
* Any attempt to post messages to the queue after the looper is asked to quit will fail.
|
||||
* For example, the {@link Handler#sendMessage(Message)} method will return false.
|
||||
* </p>
|
||||
*/
|
||||
public void quitSafely() {
|
||||
mQueue.quit(true);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -219,7 +219,7 @@ public final class MessageQueue {
|
||||
}
|
||||
}
|
||||
|
||||
void quit() {
|
||||
void quit(boolean safe) {
|
||||
if (!mQuitAllowed) {
|
||||
throw new RuntimeException("Main thread not allowed to quit.");
|
||||
}
|
||||
@@ -229,6 +229,12 @@ public final class MessageQueue {
|
||||
return;
|
||||
}
|
||||
mQuiting = true;
|
||||
|
||||
if (safe) {
|
||||
removeAllFutureMessagesLocked();
|
||||
} else {
|
||||
removeAllMessagesLocked();
|
||||
}
|
||||
}
|
||||
nativeWake(mPtr);
|
||||
}
|
||||
@@ -473,4 +479,42 @@ public final class MessageQueue {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void removeAllMessagesLocked() {
|
||||
Message p = mMessages;
|
||||
while (p != null) {
|
||||
Message n = p.next;
|
||||
p.recycle();
|
||||
p = n;
|
||||
}
|
||||
mMessages = null;
|
||||
}
|
||||
|
||||
private void removeAllFutureMessagesLocked() {
|
||||
final long now = SystemClock.uptimeMillis();
|
||||
Message p = mMessages;
|
||||
if (p != null) {
|
||||
if (p.when > now) {
|
||||
removeAllMessagesLocked();
|
||||
} else {
|
||||
Message n;
|
||||
for (;;) {
|
||||
n = p.next;
|
||||
if (n == null) {
|
||||
return;
|
||||
}
|
||||
if (n.when > now) {
|
||||
break;
|
||||
}
|
||||
p = n;
|
||||
}
|
||||
p.next = null;
|
||||
do {
|
||||
p = n;
|
||||
n = p.next;
|
||||
p.recycle();
|
||||
} while (n != null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -245,7 +245,7 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
|
||||
if (mGLThread != null) {
|
||||
// GLThread may still be running if this view was never
|
||||
// attached to a window.
|
||||
mGLThread.requestExitAndWait();
|
||||
mGLThread.quitSafely();
|
||||
}
|
||||
} finally {
|
||||
super.finalize();
|
||||
@@ -628,7 +628,11 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
|
||||
Log.d(TAG, "onDetachedFromWindow");
|
||||
}
|
||||
if (mGLThread != null) {
|
||||
mGLThread.requestExitAndWait();
|
||||
mGLThread.quitSafely();
|
||||
try {
|
||||
mGLThread.join();
|
||||
} catch (InterruptedException ex) {
|
||||
}
|
||||
}
|
||||
mDetached = true;
|
||||
super.onDetachedFromWindow();
|
||||
@@ -1627,14 +1631,6 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
|
||||
mGLHandler.runWithScissors(mGetRenderModeRunnable, 0);
|
||||
return mGetRenderModeRunnable.renderMode;
|
||||
}
|
||||
|
||||
public void requestExitAndWait() {
|
||||
getLooper().quit();
|
||||
try {
|
||||
this.join();
|
||||
} catch (InterruptedException e) {
|
||||
}
|
||||
}
|
||||
} // class GLThread
|
||||
|
||||
static class LogWriter extends Writer {
|
||||
|
||||
Reference in New Issue
Block a user