Run with scissors.
Add a useful (if somewhat dangerous) method which will help
replace similarly dangerous code patterns in a few different places.
Change-Id: If1295f7ab9652c906ce718d94eb7914d143e1939
diff --git a/core/java/android/os/Handler.java b/core/java/android/os/Handler.java
index 4e2b5c0..0f9be9c 100644
--- a/core/java/android/os/Handler.java
+++ b/core/java/android/os/Handler.java
@@ -412,6 +412,50 @@
}
/**
+ * Runs the specified task synchronously.
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * @param r The Runnable that will be executed synchronously.
+ *
+ * @return Returns true if the Runnable was successfully executed.
+ * Returns false on failure, usually because the
+ * looper processing the message queue is exiting.
+ *
+ * @hide This method is prone to abuse and should probably not be in the API.
+ * If we ever do make it part of the API, we might want to rename it to something
+ * less funny like runUnsafe().
+ */
+ public final boolean runWithScissors(final Runnable r) {
+ if (r == null) {
+ throw new IllegalArgumentException("runnable must not be null");
+ }
+
+ if (Looper.myLooper() == mLooper) {
+ r.run();
+ return true;
+ }
+
+ BlockingRunnable br = new BlockingRunnable(r);
+ return br.postAndWait(this);
+ }
+
+ /**
* Remove any pending posts of Runnable r that are in the message queue.
*/
public final void removeCallbacks(Runnable r)
@@ -678,4 +722,41 @@
final Callback mCallback;
final boolean mAsynchronous;
IMessenger mMessenger;
+
+ private static final class BlockingRunnable implements Runnable {
+ private final Runnable mTask;
+ private boolean mDone;
+
+ public BlockingRunnable(Runnable task) {
+ mTask = task;
+ }
+
+ @Override
+ public void run() {
+ try {
+ mTask.run();
+ } finally {
+ synchronized (this) {
+ mDone = true;
+ notifyAll();
+ }
+ }
+ }
+
+ public boolean postAndWait(Handler handler) {
+ if (!handler.post(this)) {
+ return false;
+ }
+
+ synchronized (this) {
+ while (!mDone) {
+ try {
+ wait();
+ } catch (InterruptedException ex) {
+ }
+ }
+ }
+ return true;
+ }
+ }
}