From a2910d0abbbe18ba1710dfd4a31af45769632255 Mon Sep 17 00:00:00 2001 From: Jeff Brown Date: Sat, 25 Aug 2012 12:29:46 -0700 Subject: [PATCH] Make it easier to create asynchronous Handlers. There are potentially very many Handlers owned by services that should not be blocked by barriers introduced by UI traversals occurring on the same thread (if that ever happens). Add some convenience constructors to make it easy to switch these Handlers over to being async. Bug: 7057752 Change-Id: I64d9bffe81e7c52ada4cfad4e89d4340153f4688 --- core/java/android/os/Handler.java | 118 +++++++++++------- .../policy/impl/KeyguardViewMediator.java | 2 +- .../java/com/android/server/DockObserver.java | 2 +- .../server/input/InputManagerService.java | 4 + .../server/power/DisplayPowerController.java | 2 +- .../com/android/server/power/Notifier.java | 2 +- .../server/power/PowerManagerService.java | 2 +- 7 files changed, 84 insertions(+), 48 deletions(-) diff --git a/core/java/android/os/Handler.java b/core/java/android/os/Handler.java index 77853683b2e50..4e2b5c0a892d7 100644 --- a/core/java/android/os/Handler.java +++ b/core/java/android/os/Handler.java @@ -101,37 +101,88 @@ public class Handler { } /** - * Default constructor associates this handler with the queue for the + * Default constructor associates this handler with the {@link Looper} for the * current thread. * - * If there isn't one, this handler won't be able to receive messages. + * If this thread does not have a looper, this handler won't be able to receive messages + * so an exception is thrown. */ public Handler() { - if (FIND_POTENTIAL_LEAKS) { - final Class klass = getClass(); - if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) && - (klass.getModifiers() & Modifier.STATIC) == 0) { - Log.w(TAG, "The following Handler class should be static or leaks might occur: " + - klass.getCanonicalName()); - } - } - - mLooper = Looper.myLooper(); - if (mLooper == null) { - throw new RuntimeException( - "Can't create handler inside thread that has not called Looper.prepare()"); - } - mQueue = mLooper.mQueue; - mCallback = null; - mAsynchronous = false; + this(null, false); } /** - * Constructor associates this handler with the queue for the + * Constructor associates this handler with the {@link Looper} for the * current thread and takes a callback interface in which you can handle * messages. + * + * If this thread does not have a looper, this handler won't be able to receive messages + * so an exception is thrown. + * + * @param callback The callback interface in which to handle messages, or null. */ public Handler(Callback callback) { + this(callback, false); + } + + /** + * Use the provided {@link Looper} instead of the default one. + * + * @param looper The looper, must not be null. + */ + public Handler(Looper looper) { + this(looper, null, false); + } + + /** + * Use the provided {@link Looper} instead of the default one and take a callback + * interface in which to handle messages. + * + * @param looper The looper, must not be null. + * @param callback The callback interface in which to handle messages, or null. + */ + public Handler(Looper looper, Callback callback) { + this(looper, callback, false); + } + + /** + * Use the {@link Looper} for the current thread + * and set whether the handler should be asynchronous. + * + * Handlers are synchronous by default unless this constructor is used to make + * one that is strictly asynchronous. + * + * Asynchronous messages represent interrupts or events that do not require global ordering + * with represent to synchronous messages. Asynchronous messages are not subject to + * the synchronization barriers introduced by {@link MessageQueue#enqueueSyncBarrier(long)}. + * + * @param async If true, the handler calls {@link Message#setAsynchronous(boolean)} for + * each {@link Message} that is sent to it or {@link Runnable} that is posted to it. + * + * @hide + */ + public Handler(boolean async) { + this(null, async); + } + + /** + * Use the {@link Looper} for the current thread with the specified callback interface + * and set whether the handler should be asynchronous. + * + * Handlers are synchronous by default unless this constructor is used to make + * one that is strictly asynchronous. + * + * Asynchronous messages represent interrupts or events that do not require global ordering + * with represent to synchronous messages. Asynchronous messages are not subject to + * the synchronization barriers introduced by {@link MessageQueue#enqueueSyncBarrier(long)}. + * + * @param callback The callback interface in which to handle messages, or null. + * @param async If true, the handler calls {@link Message#setAsynchronous(boolean)} for + * each {@link Message} that is sent to it or {@link Runnable} that is posted to it. + * + * @hide + */ + public Handler(Callback callback, boolean async) { if (FIND_POTENTIAL_LEAKS) { final Class klass = getClass(); if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) && @@ -148,32 +199,11 @@ public class Handler { } mQueue = mLooper.mQueue; mCallback = callback; - mAsynchronous = false; + mAsynchronous = async; } /** - * Use the provided queue instead of the default one. - */ - public Handler(Looper looper) { - mLooper = looper; - mQueue = looper.mQueue; - mCallback = null; - mAsynchronous = false; - } - - /** - * Use the provided queue instead of the default one and take a callback - * interface in which to handle messages. - */ - public Handler(Looper looper, Callback callback) { - mLooper = looper; - mQueue = looper.mQueue; - mCallback = callback; - mAsynchronous = false; - } - - /** - * Use the provided queue instead of the default one and take a callback + * Use the provided {@link Looper} instead of the default one and take a callback * interface in which to handle messages. Also set whether the handler * should be asynchronous. * @@ -184,6 +214,8 @@ public class Handler { * with represent to synchronous messages. Asynchronous messages are not subject to * the synchronization barriers introduced by {@link MessageQueue#enqueueSyncBarrier(long)}. * + * @param looper The looper, must not be null. + * @param callback The callback interface in which to handle messages, or null. * @param async If true, the handler calls {@link Message#setAsynchronous(boolean)} for * each {@link Message} that is sent to it or {@link Runnable} that is posted to it. * diff --git a/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java b/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java index 3ea50201502fd..236a4ea48350f 100644 --- a/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java +++ b/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java @@ -971,7 +971,7 @@ public class KeyguardViewMediator implements KeyguardViewCallback { * interacts with the keyguard ui should be posted to this handler, rather * than called directly. */ - private Handler mHandler = new Handler(Looper.myLooper(), null, true /*async*/) { + private Handler mHandler = new Handler(true /*async*/) { @Override public void handleMessage(Message msg) { switch (msg.what) { diff --git a/services/java/com/android/server/DockObserver.java b/services/java/com/android/server/DockObserver.java index 2bed95732a290..f1ff27ff351b5 100644 --- a/services/java/com/android/server/DockObserver.java +++ b/services/java/com/android/server/DockObserver.java @@ -241,7 +241,7 @@ final class DockObserver extends UEventObserver { SCREENSAVER_ACTIVATE_ON_DOCK, DEFAULT_SCREENSAVER_ACTIVATED_ON_DOCK) != 0; } - private final Handler mHandler = new Handler(Looper.myLooper(), null, true) { + private final Handler mHandler = new Handler(true /*async*/) { @Override public void handleMessage(Message msg) { switch (msg.what) { diff --git a/services/java/com/android/server/input/InputManagerService.java b/services/java/com/android/server/input/InputManagerService.java index 0b8ff620c4cc4..29c68ebf04247 100644 --- a/services/java/com/android/server/input/InputManagerService.java +++ b/services/java/com/android/server/input/InputManagerService.java @@ -1438,6 +1438,10 @@ public class InputManagerService extends IInputManager.Stub implements Watchdog. * Private handler for the input manager. */ private final class InputManagerHandler extends Handler { + public InputManagerHandler() { + super(true /*async*/); + } + @Override public void handleMessage(Message msg) { switch (msg.what) { diff --git a/services/java/com/android/server/power/DisplayPowerController.java b/services/java/com/android/server/power/DisplayPowerController.java index 5f917af174efc..cd211da099734 100644 --- a/services/java/com/android/server/power/DisplayPowerController.java +++ b/services/java/com/android/server/power/DisplayPowerController.java @@ -1112,7 +1112,7 @@ final class DisplayPowerController { private final class DisplayControllerHandler extends Handler { public DisplayControllerHandler(Looper looper) { - super(looper); + super(looper, null, true /*async*/); } @Override diff --git a/services/java/com/android/server/power/Notifier.java b/services/java/com/android/server/power/Notifier.java index 9d928e503420d..75f84457a143f 100644 --- a/services/java/com/android/server/power/Notifier.java +++ b/services/java/com/android/server/power/Notifier.java @@ -422,7 +422,7 @@ final class Notifier { private final class NotifierHandler extends Handler { public NotifierHandler(Looper looper) { - super(looper); + super(looper, null, true /*async*/); } @Override diff --git a/services/java/com/android/server/power/PowerManagerService.java b/services/java/com/android/server/power/PowerManagerService.java index 9f2b247d31061..cbb5b6df16779 100644 --- a/services/java/com/android/server/power/PowerManagerService.java +++ b/services/java/com/android/server/power/PowerManagerService.java @@ -1952,7 +1952,7 @@ public final class PowerManagerService extends IPowerManager.Stub */ private final class PowerManagerHandler extends Handler { public PowerManagerHandler(Looper looper) { - super(looper); + super(looper, null, true /*async*/); } @Override