Index: base/android/java/src/org/chromium/base/SystemMessageHandler.java |
diff --git a/base/android/java/src/org/chromium/base/SystemMessageHandler.java b/base/android/java/src/org/chromium/base/SystemMessageHandler.java |
index e1fbb0f4bed9538212313fdb374e81f0ac37f414..5f0b3d35dd22b9a941b286d169a53f9dcd6be884 100644 |
--- a/base/android/java/src/org/chromium/base/SystemMessageHandler.java |
+++ b/base/android/java/src/org/chromium/base/SystemMessageHandler.java |
@@ -6,18 +6,43 @@ package org.chromium.base; |
import android.os.Handler; |
import android.os.Message; |
+import android.util.Log; |
+ |
+import java.lang.reflect.InvocationTargetException; |
+import java.lang.reflect.Method; |
class SystemMessageHandler extends Handler { |
+ private static final String TAG = "SystemMessageHandler"; |
+ |
private static final int SCHEDULED_WORK = 1; |
private static final int DELAYED_SCHEDULED_WORK = 2; |
+ // Reflected API for marking a message as asynchronous. This is a workaround |
+ // to provide *fair* Chromium task dispatch when served by the Android UI |
+ // thread's Looper, avoiding stalls when the Looper has a sync barrier. |
+ // Note: Use of this API is experimental and demonstrative, and is likely |
+ // to be removed in the near future. |
+ private Method mMessageMethodSetAsynchonous; |
+ |
// Native class pointer set by the constructor of the SharedClient native class. |
private long mMessagePumpDelegateNative = 0; |
private long mDelayedScheduledTimeTicks = 0; |
private SystemMessageHandler(long messagePumpDelegateNative) { |
mMessagePumpDelegateNative = messagePumpDelegateNative; |
+ |
+ try { |
+ Class<?> messageClass = Class.forName("android.os.Message"); |
+ mMessageMethodSetAsynchonous = messageClass.getMethod( |
+ "setAsynchronous", new Class[]{boolean.class}); |
+ } catch (ClassNotFoundException e) { |
+ Log.e(TAG, "Failed to find android.os.Message class:" + e); |
+ } catch (NoSuchMethodException e) { |
+ Log.e(TAG, "Failed to load Message.setAsynchronous method:" + e); |
+ } catch (RuntimeException e) { |
+ Log.e(TAG, "Exception while loading Message.setAsynchronous method: " + e); |
+ } |
} |
@Override |
@@ -31,7 +56,7 @@ class SystemMessageHandler extends Handler { |
@SuppressWarnings("unused") |
@CalledByNative |
private void scheduleWork() { |
- sendEmptyMessage(SCHEDULED_WORK); |
+ sendMessage(obtainAsyncMessage(SCHEDULED_WORK)); |
} |
@SuppressWarnings("unused") |
@@ -41,7 +66,7 @@ class SystemMessageHandler extends Handler { |
removeMessages(DELAYED_SCHEDULED_WORK); |
} |
mDelayedScheduledTimeTicks = delayedTimeTicks; |
- sendEmptyMessageDelayed(DELAYED_SCHEDULED_WORK, millis); |
+ sendMessageDelayed(obtainAsyncMessage(DELAYED_SCHEDULED_WORK), millis); |
} |
@SuppressWarnings("unused") |
@@ -51,6 +76,28 @@ class SystemMessageHandler extends Handler { |
removeMessages(DELAYED_SCHEDULED_WORK); |
} |
+ private Message obtainAsyncMessage(int what) { |
+ Message msg = Message.obtain(); |
+ msg.what = what; |
+ if (mMessageMethodSetAsynchonous != null) { |
+ // If invocation fails, assume this is indicative of future |
+ // failures, and avoid log spam by nulling the reflected method. |
+ try { |
+ mMessageMethodSetAsynchonous.invoke(msg, true); |
+ } catch (IllegalAccessException e) { |
+ Log.e(TAG, "Illegal access to asynchronous message creation, disabling."); |
+ mMessageMethodSetAsynchonous = null; |
+ } catch (IllegalArgumentException e) { |
+ Log.e(TAG, "Illegal argument for asynchronous message creation, disabling."); |
+ mMessageMethodSetAsynchonous = null; |
+ } catch (InvocationTargetException e) { |
+ Log.e(TAG, "Invocation exception during asynchronous message creation, disabling."); |
+ mMessageMethodSetAsynchonous = null; |
+ } |
+ } |
+ return msg; |
+ } |
+ |
@CalledByNative |
private static SystemMessageHandler create(long messagePumpDelegateNative) { |
return new SystemMessageHandler(messagePumpDelegateNative); |