Bug 802130 - Move assertOnThread functions to a new ThreadUtils class. r=mfinkle

This commit is contained in:
Kartikaya Gupta 2013-03-15 11:52:52 +01:00
parent 6346303910
commit 48ba402f28
8 changed files with 98 additions and 50 deletions

View File

@ -18,6 +18,7 @@ import org.mozilla.gecko.updater.UpdateServiceHelper;
import org.mozilla.gecko.util.GeckoBackgroundThread;
import org.mozilla.gecko.util.GeckoEventListener;
import org.mozilla.gecko.util.GeckoEventResponder;
import org.mozilla.gecko.util.ThreadUtils;
import org.mozilla.gecko.util.UiAsyncTask;
import org.json.JSONArray;
@ -1372,6 +1373,8 @@ abstract public class GeckoApp
((GeckoApplication)getApplication()).initialize();
mAppContext = this;
ThreadUtils.setUiThread(Thread.currentThread());
Tabs.getInstance().attachToActivity(this);
Favicons.getInstance().attachToContext(this);
@ -1632,6 +1635,7 @@ abstract public class GeckoApp
if (!mIsRestoringActivity) {
sGeckoThread = new GeckoThread(intent, passedUri);
ThreadUtils.setGeckoThread(sGeckoThread);
}
if (!ACTION_DEBUG.equals(action) &&
GeckoThread.checkAndSetLaunchState(GeckoThread.LaunchState.Launching, GeckoThread.LaunchState.Launched)) {
@ -2638,26 +2642,4 @@ abstract public class GeckoApp
}
return false;
}
public static void assertOnUiThread() {
Thread uiThread = mAppContext.getMainLooper().getThread();
assertOnThread(uiThread);
}
public static void assertOnGeckoThread() {
assertOnThread(sGeckoThread);
}
public 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() + ")");
}
}
}

View File

@ -7,6 +7,7 @@ package org.mozilla.gecko;
import org.mozilla.gecko.gfx.InputConnectionHandler;
import org.mozilla.gecko.gfx.LayerView;
import org.mozilla.gecko.util.ThreadUtils;
import android.os.Build;
import android.os.Handler;
@ -233,7 +234,7 @@ final class GeckoEditable
void poll() {
if (DEBUG) {
GeckoApp.assertOnGeckoThread();
ThreadUtils.assertOnGeckoThread();
}
if (mActions.isEmpty()) {
throw new IllegalStateException("empty actions queue");
@ -251,7 +252,7 @@ final class GeckoEditable
Action peek() {
if (DEBUG) {
GeckoApp.assertOnGeckoThread();
ThreadUtils.assertOnGeckoThread();
}
if (mActions.isEmpty()) {
throw new IllegalStateException("empty actions queue");
@ -304,7 +305,7 @@ final class GeckoEditable
}
private void assertOnIcThread() {
GeckoApp.assertOnThread(mIcRunHandler.getLooper().getThread());
ThreadUtils.assertOnThread(mIcRunHandler.getLooper().getThread());
}
private void geckoPostToIc(Runnable runnable) {
@ -598,7 +599,7 @@ final class GeckoEditable
private void geckoActionReply() {
if (DEBUG) {
// GeckoEditableListener methods should all be called from the Gecko thread
GeckoApp.assertOnGeckoThread();
ThreadUtils.assertOnGeckoThread();
}
final Action action = mActionQueue.peek();
@ -650,7 +651,7 @@ final class GeckoEditable
public void notifyIME(final int type, final int state) {
if (DEBUG) {
// GeckoEditableListener methods should all be called from the Gecko thread
GeckoApp.assertOnGeckoThread();
ThreadUtils.assertOnGeckoThread();
// NOTIFY_IME_REPLY_EVENT is logged separately, inside geckoActionReply()
if (type != NOTIFY_IME_REPLY_EVENT) {
Log.d(LOGTAG, "notifyIME(" +
@ -727,7 +728,7 @@ final class GeckoEditable
public void onSelectionChange(final int start, final int end) {
if (DEBUG) {
// GeckoEditableListener methods should all be called from the Gecko thread
GeckoApp.assertOnGeckoThread();
ThreadUtils.assertOnGeckoThread();
Log.d(LOGTAG, "onSelectionChange(" + start + ", " + end + ")");
}
if (start < 0 || start > mText.length() || end < 0 || end > mText.length()) {
@ -777,7 +778,7 @@ final class GeckoEditable
final int unboundedOldEnd, final int unboundedNewEnd) {
if (DEBUG) {
// GeckoEditableListener methods should all be called from the Gecko thread
GeckoApp.assertOnGeckoThread();
ThreadUtils.assertOnGeckoThread();
Log.d(LOGTAG, "onTextChange(\"" + text + "\", " + start + ", " +
unboundedOldEnd + ", " + unboundedNewEnd + ")");
}

View File

@ -6,6 +6,7 @@
package org.mozilla.gecko;
import org.mozilla.gecko.gfx.InputConnectionHandler;
import org.mozilla.gecko.util.ThreadUtils;
import android.R;
import android.content.Context;
@ -45,14 +46,14 @@ class GeckoInputConnection
private static Handler sBackgroundHandler;
private class ThreadUtils {
private class InputThreadUtils {
private Editable mUiEditable;
private Object mUiEditableReturn;
private Exception mUiEditableException;
private final SynchronousQueue<Runnable> mIcRunnableSync;
private final Runnable mIcSignalRunnable;
public ThreadUtils() {
public InputThreadUtils() {
mIcRunnableSync = new SynchronousQueue<Runnable>();
mIcSignalRunnable = new Runnable() {
@Override public void run() {
@ -62,7 +63,7 @@ class GeckoInputConnection
private void runOnIcThread(Handler icHandler, final Runnable runnable) {
if (DEBUG) {
GeckoApp.assertOnUiThread();
ThreadUtils.assertOnUiThread();
Log.d(LOGTAG, "runOnIcThread() on thread " +
icHandler.getLooper().getThread().getName());
}
@ -92,7 +93,7 @@ class GeckoInputConnection
public void endWaitForUiThread() {
if (DEBUG) {
GeckoApp.assertOnUiThread();
ThreadUtils.assertOnUiThread();
Log.d(LOGTAG, "endWaitForUiThread()");
}
try {
@ -103,7 +104,7 @@ class GeckoInputConnection
public void waitForUiThread(Handler icHandler) {
if (DEBUG) {
GeckoApp.assertOnThread(icHandler.getLooper().getThread());
ThreadUtils.assertOnThread(icHandler.getLooper().getThread());
Log.d(LOGTAG, "waitForUiThread() blocking on thread " +
icHandler.getLooper().getThread().getName());
}
@ -120,7 +121,7 @@ class GeckoInputConnection
public Editable getEditableForUiThread(final Handler uiHandler,
final Handler icHandler) {
if (DEBUG) {
GeckoApp.assertOnThread(uiHandler.getLooper().getThread());
ThreadUtils.assertOnThread(uiHandler.getLooper().getThread());
}
if (icHandler.getLooper() == uiHandler.getLooper()) {
// IC thread is UI thread; safe to use Editable directly
@ -136,7 +137,7 @@ class GeckoInputConnection
final Method method,
final Object[] args) throws Throwable {
if (DEBUG) {
GeckoApp.assertOnThread(uiHandler.getLooper().getThread());
ThreadUtils.assertOnThread(uiHandler.getLooper().getThread());
Log.d(LOGTAG, "UiEditable." + method.getName() + "() blocking");
}
synchronized (icHandler) {
@ -177,7 +178,7 @@ class GeckoInputConnection
}
}
private final ThreadUtils mThreadUtils = new ThreadUtils();
private final InputThreadUtils mThreadUtils = new InputThreadUtils();
// Managed only by notifyIMEEnabled; see comments in notifyIMEEnabled
private int mIMEState;

View File

@ -37,6 +37,7 @@ UTIL_JAVA_FILES := \
util/INIParser.java \
util/INISection.java \
util/StringUtils.java \
util/ThreadUtils.java \
util/UiAsyncTask.java \
$(NULL)

View File

@ -6,6 +6,7 @@
package org.mozilla.gecko;
import org.mozilla.gecko.util.GeckoEventResponder;
import org.mozilla.gecko.util.ThreadUtils;
import org.mozilla.gecko.widget.DateTimePicker;
import org.json.JSONArray;
@ -298,7 +299,7 @@ public class PromptService implements OnClickListener, OnCancelListener, OnItemC
}
public void show(String aTitle, String aText, PromptListItem[] aMenuList, boolean aMultipleSelection) {
GeckoApp.assertOnUiThread();
ThreadUtils.assertOnUiThread();
// treat actions that show a dialog as if preventDefault by content to prevent panning
GeckoApp.mAppContext.getLayerView().abortPanning();
@ -394,7 +395,7 @@ public class PromptService implements OnClickListener, OnCancelListener, OnItemC
@Override
public void onClick(DialogInterface aDialog, int aWhich) {
GeckoApp.assertOnUiThread();
ThreadUtils.assertOnUiThread();
JSONObject ret = new JSONObject();
try {
int button = -1;
@ -436,13 +437,13 @@ public class PromptService implements OnClickListener, OnCancelListener, OnItemC
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
GeckoApp.assertOnUiThread();
ThreadUtils.assertOnUiThread();
mSelected[position] = !mSelected[position];
}
@Override
public void onCancel(DialogInterface aDialog) {
GeckoApp.assertOnUiThread();
ThreadUtils.assertOnUiThread();
JSONObject ret = new JSONObject();
try {
ret.put("button", -1);

View File

@ -5,10 +5,10 @@
package org.mozilla.gecko.gfx;
import org.mozilla.gecko.GeckoApp;
import org.mozilla.gecko.GeckoAppShell;
import org.mozilla.gecko.GeckoEvent;
import org.mozilla.gecko.GeckoThread;
import org.mozilla.gecko.util.ThreadUtils;
import android.util.Log;
@ -75,7 +75,7 @@ public class GLController {
}
synchronized void surfaceDestroyed() {
GeckoApp.assertOnUiThread();
ThreadUtils.assertOnUiThread();
mSurfaceValid = false;
mEGLSurface = null;
@ -94,7 +94,7 @@ public class GLController {
}
synchronized void surfaceChanged(int newWidth, int newHeight) {
GeckoApp.assertOnUiThread();
ThreadUtils.assertOnUiThread();
mWidth = newWidth;
mHeight = newHeight;
@ -161,7 +161,7 @@ public class GLController {
}
void createCompositor() {
GeckoApp.assertOnUiThread();
ThreadUtils.assertOnUiThread();
if (mCompositorCreated) {
// If the compositor has already been created, just resume it instead. We don't need

View File

@ -35,11 +35,12 @@ public final class GeckoBackgroundThread extends Thread {
// Get a Handler for a looper thread, or create one if it doesn't yet exist.
public static synchronized Handler getHandler() {
if (sHandler == null) {
GeckoBackgroundThread lt = new GeckoBackgroundThread();
lt.start();
try {
sHandler = lt.mHandlerQueue.take();
} catch (InterruptedException ie) {}
GeckoBackgroundThread lt = new GeckoBackgroundThread();
ThreadUtils.setBackgroundThread(lt);
lt.start();
try {
sHandler = lt.mHandlerQueue.take();
} catch (InterruptedException ie) {}
}
return sHandler;
}

View File

@ -0,0 +1,61 @@
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.mozilla.gecko.util;
public final class ThreadUtils {
private static Thread sUiThread;
private static Thread sGeckoThread;
private static Thread sBackgroundThread;
public static void setUiThread(Thread thread) {
sUiThread = thread;
}
public static void setGeckoThread(Thread thread) {
sGeckoThread = thread;
}
public static void setBackgroundThread(Thread thread) {
sBackgroundThread = thread;
}
public static Thread getUiThread() {
return sUiThread;
}
public static Thread getGeckoThread() {
return sGeckoThread;
}
public static Thread getBackgroundThread() {
return sBackgroundThread;
}
public static void assertOnUiThread() {
assertOnThread(getUiThread());
}
public static void assertOnGeckoThread() {
assertOnThread(getGeckoThread());
}
public static void assertOnBackgroundThread() {
assertOnThread(getBackgroundThread());
}
public 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() + ")");
}
}
}