Bug 769520 - Part 2: In debug builds, assert IME code is running on UI thread. r=blassey

This commit is contained in:
Chris Peterson 2012-06-29 15:49:48 -07:00
parent 512dd48b54
commit ad761ffffb
2 changed files with 79 additions and 24 deletions

View File

@ -6,19 +6,12 @@
package org.mozilla.gecko;
import org.mozilla.gecko.db.BrowserDB;
import org.mozilla.gecko.gfx.CairoImage;
import org.mozilla.gecko.gfx.BufferedCairoImage;
import org.mozilla.gecko.gfx.FloatSize;
import org.mozilla.gecko.gfx.GeckoLayerClient;
import org.mozilla.gecko.gfx.IntSize;
import org.mozilla.gecko.gfx.Layer;
import org.mozilla.gecko.gfx.LayerController;
import org.mozilla.gecko.gfx.LayerView;
import org.mozilla.gecko.gfx.PluginLayer;
import org.mozilla.gecko.gfx.RectUtils;
import org.mozilla.gecko.gfx.SurfaceTextureLayer;
import org.mozilla.gecko.gfx.ViewportMetrics;
import org.mozilla.gecko.gfx.ImmutableViewportMetrics;
import java.io.*;
import java.util.*;
@ -27,7 +20,6 @@ import java.util.regex.Matcher;
import java.util.zip.*;
import java.net.URL;
import java.nio.*;
import java.nio.channels.FileChannel;
import java.util.concurrent.*;
import java.lang.reflect.*;
import java.net.*;
@ -40,7 +32,6 @@ import android.text.*;
import android.text.format.Time;
import android.view.*;
import android.view.inputmethod.*;
import android.view.ViewGroup.LayoutParams;
import android.content.*;
import android.content.res.*;
import android.graphics.*;
@ -94,7 +85,7 @@ abstract public class GeckoApp
public static boolean mDOMFullScreen = false;
protected MenuPanel mMenuPanel;
protected Menu mMenu;
private static GeckoThread sGeckoThread = null;
private static GeckoThread sGeckoThread;
public Handler mMainHandler;
private GeckoProfile mProfile;
public static boolean sIsGeckoReady = false;
@ -3220,6 +3211,28 @@ abstract public class GeckoApp
return false;
}
public static void assertOnUiThread() {
Thread uiThread = mAppContext.getMainLooper().getThread();
assertOnThread(uiThread);
}
public static void assertOnGeckoThread() {
assertOnThread(sGeckoThread);
}
private static void assertOnThread(Thread expectedThread) {
Thread currentThread = Thread.currentThread();
long currentThreadId = currentThread.getId();
long expectedThreadId = expectedThread.getId();
if (currentThreadId != expectedThreadId) {
throw new IllegalThreadStateException("Expected thread " + expectedThreadId + " (\""
+ expectedThread.getName()
+ "\"), but running on thread " + currentThreadId
+ " (\"" + currentThread.getName() + ")");
}
}
// SDK version 15 accessibility methods retrieved through reflection.
private static class AccessibilityCompat {
private static boolean mInitialized = false;

View File

@ -134,7 +134,8 @@ public class GeckoInputConnection
@Override
public boolean commitText(CharSequence text, int newCursorPosition) {
if (mCommittingText)
Log.e(LOGTAG, "Please report this bug:", new IllegalStateException("commitText, but already committing text?!"));
Log.e(LOGTAG, "Please report this bug:",
new IllegalStateException("commitText, but already committing text?!"));
mCommittingText = true;
replaceText(text, newCursorPosition, false);
@ -321,6 +322,7 @@ public class GeckoInputConnection
if (DEBUG) {
Log.d(LOGTAG, String.format("IME: replaceText(\"%s\", %d, %b)",
text, newCursorPosition, composing));
GeckoApp.assertOnUiThread();
}
if (text == null)
@ -699,10 +701,14 @@ public class GeckoInputConnection
}
private void endComposition() {
if (DEBUG) Log.d(LOGTAG, "IME: endComposition: IME_COMPOSITION_END");
if (DEBUG) {
Log.d(LOGTAG, "IME: endComposition: IME_COMPOSITION_END");
GeckoApp.assertOnUiThread();
}
if (!hasCompositionString())
Log.e(LOGTAG, "Please report this bug:", new IllegalStateException("endComposition, but not composing text?!"));
Log.e(LOGTAG, "Please report this bug:",
new IllegalStateException("endComposition, but not composing text?!"));
GeckoAppShell.sendEventToGecko(
GeckoEvent.createIMEEvent(GeckoEvent.IME_COMPOSITION_END, 0, 0));
@ -711,7 +717,10 @@ public class GeckoInputConnection
}
private void sendTextToGecko(CharSequence text, int caretPos) {
if (DEBUG) Log.d(LOGTAG, "IME: sendTextToGecko(\"" + text + "\")");
if (DEBUG) {
Log.d(LOGTAG, "IME: sendTextToGecko(\"" + text + "\")");
GeckoApp.assertOnUiThread();
}
// Handle composition text styles
if (text != null && text instanceof Spanned) {
@ -809,19 +818,19 @@ public class GeckoInputConnection
outAttrs.inputType = InputType.TYPE_CLASS_PHONE;
else if (mIMETypeHint.equalsIgnoreCase("number") ||
mIMETypeHint.equalsIgnoreCase("range"))
outAttrs.inputType = InputType.TYPE_CLASS_NUMBER |
InputType.TYPE_NUMBER_FLAG_SIGNED |
InputType.TYPE_NUMBER_FLAG_DECIMAL;
outAttrs.inputType = InputType.TYPE_CLASS_NUMBER
| InputType.TYPE_NUMBER_FLAG_SIGNED
| InputType.TYPE_NUMBER_FLAG_DECIMAL;
else if (mIMETypeHint.equalsIgnoreCase("datetime") ||
mIMETypeHint.equalsIgnoreCase("datetime-local"))
outAttrs.inputType = InputType.TYPE_CLASS_DATETIME |
InputType.TYPE_DATETIME_VARIATION_NORMAL;
outAttrs.inputType = InputType.TYPE_CLASS_DATETIME
| InputType.TYPE_DATETIME_VARIATION_NORMAL;
else if (mIMETypeHint.equalsIgnoreCase("date"))
outAttrs.inputType = InputType.TYPE_CLASS_DATETIME |
InputType.TYPE_DATETIME_VARIATION_DATE;
outAttrs.inputType = InputType.TYPE_CLASS_DATETIME
| InputType.TYPE_DATETIME_VARIATION_DATE;
else if (mIMETypeHint.equalsIgnoreCase("time"))
outAttrs.inputType = InputType.TYPE_CLASS_DATETIME |
InputType.TYPE_DATETIME_VARIATION_TIME;
outAttrs.inputType = InputType.TYPE_CLASS_DATETIME
| InputType.TYPE_DATETIME_VARIATION_TIME;
if (mIMEActionHint.equalsIgnoreCase("go"))
outAttrs.imeOptions = EditorInfo.IME_ACTION_GO;
@ -875,6 +884,7 @@ public class GeckoInputConnection
if (DEBUG) {
Log.d(LOGTAG, "IME: processKeyDown(keyCode=" + keyCode + ", event=" + event + ", "
+ isPreIme + ")");
GeckoApp.assertOnUiThread();
}
if (keyCode > KeyEvent.getMaxKeyCode())
@ -937,6 +947,7 @@ public class GeckoInputConnection
if (DEBUG) {
Log.d(LOGTAG, "IME: processKeyUp(keyCode=" + keyCode + ", event=" + event + ", "
+ isPreIme + ")");
GeckoApp.assertOnUiThread();
}
if (keyCode > KeyEvent.getMaxKeyCode())
@ -1104,7 +1115,6 @@ public class GeckoInputConnection
postToUiThread(new Runnable() {
public void run() {
final View v = GeckoApp.mAppContext.getLayerController().getView();
if (DEBUG) Log.d(LOGTAG, "IME: v=" + v);
final InputMethodManager imm = getInputMethodManager();
if (imm == null)
@ -1205,29 +1215,34 @@ public class GeckoInputConnection
private static final class DebugGeckoInputConnection extends GeckoInputConnection {
public DebugGeckoInputConnection(View targetView) {
super(targetView);
GeckoApp.assertOnUiThread();
}
@Override
public boolean beginBatchEdit() {
Log.d(LOGTAG, "IME: beginBatchEdit");
GeckoApp.assertOnUiThread();
return super.beginBatchEdit();
}
@Override
public boolean endBatchEdit() {
Log.d(LOGTAG, "IME: endBatchEdit");
GeckoApp.assertOnUiThread();
return super.endBatchEdit();
}
@Override
public boolean commitCompletion(CompletionInfo text) {
Log.d(LOGTAG, "IME: commitCompletion");
GeckoApp.assertOnUiThread();
return super.commitCompletion(text);
}
@Override
public boolean commitText(CharSequence text, int newCursorPosition) {
Log.d(LOGTAG, String.format("IME: commitText(\"%s\", %d)", text, newCursorPosition));
GeckoApp.assertOnUiThread();
return super.commitText(text, newCursorPosition);
}
@ -1235,12 +1250,14 @@ private static final class DebugGeckoInputConnection extends GeckoInputConnectio
public boolean deleteSurroundingText(int leftLength, int rightLength) {
Log.d(LOGTAG, "IME: deleteSurroundingText(leftLen=" + leftLength + ", rightLen="
+ rightLength + ")");
GeckoApp.assertOnUiThread();
return super.deleteSurroundingText(leftLength, rightLength);
}
@Override
public boolean finishComposingText() {
Log.d(LOGTAG, "IME: finishComposingText");
GeckoApp.assertOnUiThread();
return super.finishComposingText();
}
@ -1248,18 +1265,21 @@ private static final class DebugGeckoInputConnection extends GeckoInputConnectio
public Editable getEditable() {
Editable editable = super.getEditable();
Log.d(LOGTAG, "IME: getEditable -> " + editable);
GeckoApp.assertOnUiThread();
return editable;
}
@Override
public boolean performContextMenuAction(int id) {
Log.d(LOGTAG, "IME: performContextMenuAction");
GeckoApp.assertOnUiThread();
return super.performContextMenuAction(id);
}
@Override
public ExtractedText getExtractedText(ExtractedTextRequest req, int flags) {
Log.d(LOGTAG, "IME: getExtractedText");
GeckoApp.assertOnUiThread();
ExtractedText extract = super.getExtractedText(req, flags);
if (extract != null)
Log.d(LOGTAG, String.format(
@ -1271,6 +1291,7 @@ private static final class DebugGeckoInputConnection extends GeckoInputConnectio
@Override
public CharSequence getTextAfterCursor(int length, int flags) {
Log.d(LOGTAG, "IME: getTextAfterCursor(length=" + length + ", flags=" + flags + ")");
GeckoApp.assertOnUiThread();
CharSequence s = super.getTextAfterCursor(length, flags);
Log.d(LOGTAG, ". . . getTextAfterCursor returns \"" + s + "\"");
return s;
@ -1279,6 +1300,7 @@ private static final class DebugGeckoInputConnection extends GeckoInputConnectio
@Override
public CharSequence getTextBeforeCursor(int length, int flags) {
Log.d(LOGTAG, "IME: getTextBeforeCursor");
GeckoApp.assertOnUiThread();
CharSequence s = super.getTextBeforeCursor(length, flags);
Log.d(LOGTAG, ". . . getTextBeforeCursor returns \"" + s + "\"");
return s;
@ -1287,24 +1309,28 @@ private static final class DebugGeckoInputConnection extends GeckoInputConnectio
@Override
public boolean setComposingText(CharSequence text, int newCursorPosition) {
Log.d(LOGTAG, String.format("IME: setComposingText(\"%s\", %d)", text, newCursorPosition));
GeckoApp.assertOnUiThread();
return super.setComposingText(text, newCursorPosition);
}
@Override
public boolean setComposingRegion(int start, int end) {
Log.d(LOGTAG, "IME: setComposingRegion(start=" + start + ", end=" + end + ")");
GeckoApp.assertOnUiThread();
return super.setComposingRegion(start, end);
}
@Override
public boolean setSelection(int start, int end) {
Log.d(LOGTAG, "IME: setSelection(start=" + start + ", end=" + end + ")");
GeckoApp.assertOnUiThread();
return super.setSelection(start, end);
}
@Override
public String getComposingText() {
Log.d(LOGTAG, "IME: getComposingText");
GeckoApp.assertOnUiThread();
String s = super.getComposingText();
Log.d(LOGTAG, ". . . getComposingText: Composing text = \"" + s + "\"");
return s;
@ -1313,12 +1339,15 @@ private static final class DebugGeckoInputConnection extends GeckoInputConnectio
@Override
public boolean onKeyDel() {
Log.d(LOGTAG, "IME: onKeyDel");
GeckoApp.assertOnUiThread();
return super.onKeyDel();
}
@Override
protected void notifyTextChange(InputMethodManager imm, String text,
int start, int oldEnd, int newEnd) {
// notifyTextChange() call is posted to UI thread from notifyIMEChange().
GeckoApp.assertOnUiThread();
Log.d(LOGTAG, String.format(
"IME: >notifyTextChange(\"%s\", start=%d, oldEnd=%d, newEnd=%d)",
text, start, oldEnd, newEnd));
@ -1327,6 +1356,8 @@ private static final class DebugGeckoInputConnection extends GeckoInputConnectio
@Override
protected void notifySelectionChange(InputMethodManager imm, int start, int end) {
// notifySelectionChange() call is posted to UI thread from notifyIMEChange().
GeckoApp.assertOnUiThread();
Log.d(LOGTAG, String.format("IME: >notifySelectionChange(start=%d, end=%d)", start, end));
super.notifySelectionChange(imm, start, end);
}
@ -1334,6 +1365,7 @@ private static final class DebugGeckoInputConnection extends GeckoInputConnectio
@Override
protected void resetCompositionState() {
Log.d(LOGTAG, "IME: resetCompositionState");
GeckoApp.assertOnUiThread();
if (hasCompositionString()) {
Log.d(LOGTAG, "resetCompositionState() is abandoning an active composition string");
}
@ -1344,12 +1376,14 @@ private static final class DebugGeckoInputConnection extends GeckoInputConnectio
public void onTextChanged(CharSequence s, int start, int before, int count) {
Log.d(LOGTAG, String.format("IME: onTextChanged(\"%s\" start=%d, before=%d, count=%d)",
s, start, before, count));
GeckoApp.assertOnUiThread();
super.onTextChanged(s, start, before, count);
}
@Override
public void afterTextChanged(Editable s) {
Log.d(LOGTAG, "IME: afterTextChanged(\"" + s + "\")");
GeckoApp.assertOnUiThread();
super.afterTextChanged(s);
}
@ -1357,30 +1391,35 @@ private static final class DebugGeckoInputConnection extends GeckoInputConnectio
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
Log.d(LOGTAG, String.format("IME: beforeTextChanged(\"%s\", start=%d, count=%d, after=%d)",
s, start, count, after));
GeckoApp.assertOnUiThread();
super.beforeTextChanged(s, start, count, after);
}
@Override
public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
Log.d(LOGTAG, "IME: onCreateInputConnection called");
GeckoApp.assertOnUiThread();
return super.onCreateInputConnection(outAttrs);
}
@Override
public boolean onKeyPreIme(int keyCode, KeyEvent event) {
Log.d(LOGTAG, "IME: onKeyPreIme(keyCode=" + keyCode + ", event=" + event + ")");
GeckoApp.assertOnUiThread();
return super.onKeyPreIme(keyCode, event);
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
Log.d(LOGTAG, "IME: onKeyDown(keyCode=" + keyCode + ", event=" + event + ")");
GeckoApp.assertOnUiThread();
return super.onKeyDown(keyCode, event);
}
@Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
Log.d(LOGTAG, "IME: onKeyUp(keyCode=" + keyCode + ", event=" + event + ")");
GeckoApp.assertOnUiThread();
return super.onKeyUp(keyCode, event);
}
@ -1388,18 +1427,21 @@ private static final class DebugGeckoInputConnection extends GeckoInputConnectio
public boolean onKeyMultiple(int keyCode, int repeatCount, KeyEvent event) {
Log.d(LOGTAG, "IME: onKeyMultiple(keyCode=" + keyCode + ", repeatCount=" + repeatCount
+ ", event=" + event + ")");
GeckoApp.assertOnUiThread();
return super.onKeyMultiple(keyCode, repeatCount, event);
}
@Override
public boolean onKeyLongPress(int keyCode, KeyEvent event) {
Log.d(LOGTAG, "IME: onKeyLongPress(keyCode=" + keyCode + ", event=" + event + ")");
GeckoApp.assertOnUiThread();
return super.onKeyLongPress(keyCode, event);
}
@Override
public void notifyIME(int type, int state) {
Log.d(LOGTAG, String.format("IME: >notifyIME(type=%d, state=%d)", type, state));
GeckoApp.assertOnGeckoThread();
super.notifyIME(type, state);
}
}