NestedSystemMessageHandler.java revision 6e8cce623b6e4fe0c9e4af605d675dd9d0338c38
1// Copyright 2013 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5package org.chromium.content.browser.test; 6 7import android.os.Handler; 8import android.os.Looper; 9import android.os.Message; 10import android.os.MessageQueue; 11 12import org.chromium.base.CalledByNative; 13import org.chromium.base.JNINamespace; 14 15import java.lang.reflect.Field; 16import java.lang.reflect.InvocationTargetException; 17import java.lang.reflect.Method; 18 19/** 20 * Handles processing messages in nested run loops. 21 * 22 * Android does not support nested message loops by default. While running 23 * in nested mode, we use reflection to retreive messages from the MessageQueue 24 * and dispatch them. 25 */ 26@JNINamespace("content") 27class NestedSystemMessageHandler { 28 // See org.chromium.base.SystemMessageHandler for more message ids. 29 // The id here should not conflict with the ones in SystemMessageHandler. 30 private static final int QUIT_MESSAGE = 10; 31 private static final Handler sHandler = new Handler(); 32 33 private NestedSystemMessageHandler() { 34 } 35 36 /** 37 * Processes messages from the current MessageQueue till the queue becomes idle. 38 */ 39 @SuppressWarnings("unused") 40 @CalledByNative 41 private boolean runNestedLoopTillIdle() { 42 boolean quitLoop = false; 43 44 MessageQueue queue = Looper.myQueue(); 45 queue.addIdleHandler(new MessageQueue.IdleHandler() { 46 @Override 47 public boolean queueIdle() { 48 sHandler.sendMessage(sHandler.obtainMessage(QUIT_MESSAGE)); 49 return false; 50 } 51 }); 52 53 Class<?> messageQueueClazz = queue.getClass(); 54 Method nextMethod = null; 55 try { 56 nextMethod = messageQueueClazz.getDeclaredMethod("next"); 57 } catch (SecurityException e) { 58 e.printStackTrace(); 59 return false; 60 } catch (NoSuchMethodException e) { 61 e.printStackTrace(); 62 return false; 63 } 64 nextMethod.setAccessible(true); 65 66 while (!quitLoop) { 67 Message msg = null; 68 try { 69 msg = (Message) nextMethod.invoke(queue); 70 } catch (IllegalArgumentException e) { 71 e.printStackTrace(); 72 return false; 73 } catch (IllegalAccessException e) { 74 e.printStackTrace(); 75 return false; 76 } catch (InvocationTargetException e) { 77 e.printStackTrace(); 78 return false; 79 } 80 81 if (msg != null) { 82 if (msg.what == QUIT_MESSAGE) { 83 quitLoop = true; 84 } 85 Class messageClazz = msg.getClass(); 86 Field targetFiled = null; 87 try { 88 targetFiled = messageClazz.getDeclaredField("target"); 89 } catch (SecurityException e) { 90 e.printStackTrace(); 91 return false; 92 } catch (NoSuchFieldException e) { 93 e.printStackTrace(); 94 return false; 95 } 96 targetFiled.setAccessible(true); 97 98 Handler target = null; 99 try { 100 target = (Handler) targetFiled.get(msg); 101 } catch (IllegalArgumentException e) { 102 e.printStackTrace(); 103 return false; 104 } catch (IllegalAccessException e) { 105 e.printStackTrace(); 106 return false; 107 } 108 109 if (target == null) { 110 // No target is a magic identifier for the quit message. 111 quitLoop = true; 112 } else { 113 target.dispatchMessage(msg); 114 } 115 116 // Unset in-use flag. 117 Field flagsField = null; 118 try { 119 flagsField = messageClazz.getDeclaredField("flags"); 120 } catch (IllegalArgumentException e) { 121 e.printStackTrace(); 122 return false; 123 } catch (SecurityException e) { 124 e.printStackTrace(); 125 return false; 126 } catch (NoSuchFieldException e) { 127 e.printStackTrace(); 128 return false; 129 } 130 flagsField.setAccessible(true); 131 132 try { 133 Integer oldFlags = (Integer) flagsField.get(msg); 134 flagsField.set(msg, oldFlags & ~(1 << 0 /* FLAG_IN_USE */)); 135 } catch (IllegalArgumentException e) { 136 e.printStackTrace(); 137 return false; 138 } catch (IllegalAccessException e) { 139 e.printStackTrace(); 140 return false; 141 } 142 143 msg.recycle(); 144 } else { 145 quitLoop = true; 146 } 147 } 148 return true; 149 } 150 151 @SuppressWarnings("unused") 152 @CalledByNative 153 private static NestedSystemMessageHandler create() { 154 return new NestedSystemMessageHandler(); 155 } 156} 157