Loading tests/src/com/android/inputmethod/latin/InputTestsBase.java +12 −8 Original line number Original line Diff line number Diff line Loading @@ -181,17 +181,21 @@ public class InputTestsBase extends ServiceTestCase<LatinIME> { // a message that calls it instead of calling it directly. // a message that calls it instead of calling it directly. Looper.loop(); Looper.loop(); // Once #quit() has been called, the message queue has an "mQuiting" field that prevents // Once #quit() has been called, the looper is not functional any more (it used to be, // any subsequent post in this queue. However the queue itself is still fully functional! // but now it SIGSEGV's if it's used again). // If we have a way of resetting "queue.mQuiting" then we can continue using it as normal, // It won't accept creating a new looper for this thread and switching to it... // coming back to this method to run the messages. // ...unless we can trick it into throwing out the old looper and believing it hasn't // been initialized before. MessageQueue queue = Looper.myQueue(); MessageQueue queue = Looper.myQueue(); try { try { // However there is no way of doing it externally, and mQuiting is private. // However there is no way of doing it externally, and the static ThreadLocal // field into which it's stored is private. // So... get out the big guns. // So... get out the big guns. java.lang.reflect.Field f = MessageQueue.class.getDeclaredField("mQuiting"); java.lang.reflect.Field f = Looper.class.getDeclaredField("sThreadLocal"); f.setAccessible(true); // What do you mean "private"? f.setAccessible(true); // private lolwut f.setBoolean(queue, false); final ThreadLocal<Looper> a = (ThreadLocal<Looper>) f.get(looper); a.set(null); looper.prepare(); } catch (NoSuchFieldException e) { } catch (NoSuchFieldException e) { throw new RuntimeException(e); throw new RuntimeException(e); } catch (IllegalAccessException e) { } catch (IllegalAccessException e) { Loading Loading
tests/src/com/android/inputmethod/latin/InputTestsBase.java +12 −8 Original line number Original line Diff line number Diff line Loading @@ -181,17 +181,21 @@ public class InputTestsBase extends ServiceTestCase<LatinIME> { // a message that calls it instead of calling it directly. // a message that calls it instead of calling it directly. Looper.loop(); Looper.loop(); // Once #quit() has been called, the message queue has an "mQuiting" field that prevents // Once #quit() has been called, the looper is not functional any more (it used to be, // any subsequent post in this queue. However the queue itself is still fully functional! // but now it SIGSEGV's if it's used again). // If we have a way of resetting "queue.mQuiting" then we can continue using it as normal, // It won't accept creating a new looper for this thread and switching to it... // coming back to this method to run the messages. // ...unless we can trick it into throwing out the old looper and believing it hasn't // been initialized before. MessageQueue queue = Looper.myQueue(); MessageQueue queue = Looper.myQueue(); try { try { // However there is no way of doing it externally, and mQuiting is private. // However there is no way of doing it externally, and the static ThreadLocal // field into which it's stored is private. // So... get out the big guns. // So... get out the big guns. java.lang.reflect.Field f = MessageQueue.class.getDeclaredField("mQuiting"); java.lang.reflect.Field f = Looper.class.getDeclaredField("sThreadLocal"); f.setAccessible(true); // What do you mean "private"? f.setAccessible(true); // private lolwut f.setBoolean(queue, false); final ThreadLocal<Looper> a = (ThreadLocal<Looper>) f.get(looper); a.set(null); looper.prepare(); } catch (NoSuchFieldException e) { } catch (NoSuchFieldException e) { throw new RuntimeException(e); throw new RuntimeException(e); } catch (IllegalAccessException e) { } catch (IllegalAccessException e) { Loading