Commit feabeebb authored by jdduke's avatar jdduke Committed by Commit bot

[Android] Mark posted UI thread tasks as asynchronous

Chromium shares a message loop with Android on the browser UI thread.
This can cause problems when the associated Looper has a sync barrier,
preventing posted Chromium tasks from being dispatched until the
barrier is removed. Make this sharing more fair by marking all Chromium
Message tasks as asynchronous, avoiding stalls when there is a sync
barrier.

Note: This change is for gathering data about the perf impact and we'll
revert it before cutting a release branch.

BUG=407149,380781,407133

Review URL: https://codereview.chromium.org/512333002

Cr-Commit-Position: refs/heads/master@{#292551}
parent ae185652
......@@ -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);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment