Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(86)

Side by Side Diff: content/public/android/java/src/org/chromium/content/browser/AppWebMessagePort.java

Issue 2422793002: HTML MessagePort as mojo::MessagePipeHandle (Closed)
Patch Set: Eliminate unnecessary PostTask Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 package org.chromium.content.browser; 5 package org.chromium.content.browser;
6 6
7 import android.os.Handler; 7 import android.os.Handler;
8 import android.os.Looper; 8 import android.os.Looper;
9 import android.os.Message; 9 import android.os.Message;
10 10
11 import org.chromium.base.Log; 11 import org.chromium.base.Log;
12 import org.chromium.base.annotations.CalledByNative;
13 import org.chromium.base.annotations.JNINamespace;
12 import org.chromium.content_public.browser.MessagePort; 14 import org.chromium.content_public.browser.MessagePort;
13 15
14 import java.util.Arrays; 16 import java.util.Arrays;
15 17
16 /** 18 /**
17 * Represents the MessageChannel MessagePort object. Inspired from 19 * Represents the MessageChannel MessagePort object. Inspired from
18 * http://www.whatwg.org/specs/web-apps/current-work/multipage/web-messaging.htm l#message-channels 20 * http://www.whatwg.org/specs/web-apps/current-work/multipage/web-messaging.htm l#message-channels
19 * 21 *
20 * State management: 22 * State management:
21 * 23 *
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
66 * A port is put to a "started" state if: 68 * A port is put to a "started" state if:
67 * 1. The port is ever used to post a message, or 69 * 1. The port is ever used to post a message, or
68 * 2. The port was ever registered a handler to receive a message. 70 * 2. The port was ever registered a handler to receive a message.
69 * A started port cannot be transferred. 71 * A started port cannot be transferred.
70 * 72 *
71 * This restriction should not impact postmessage functionality in a big way, 73 * This restriction should not impact postmessage functionality in a big way,
72 * because an app can still create as many channels as it wants to and use it fo r 74 * because an app can still create as many channels as it wants to and use it fo r
73 * transferring data. As a return, it simplifies implementation and prevents har d 75 * transferring data. As a return, it simplifies implementation and prevents har d
74 * to debug, racy corner cases while receiving/sending data. 76 * to debug, racy corner cases while receiving/sending data.
75 */ 77 */
76 public class AppWebMessagePort implements MessagePort, PostMessageSender.PostMes sageSenderDelegate { 78 @JNINamespace("content")
77 private static final String TAG = "MessagePort"; 79 public class AppWebMessagePort implements MessagePort {
78 private static final int PENDING = -1; 80 private static final String TAG = "AppWebMessagePort";
81 private static final long UNINITIALIZED_PORT_NATIVE_PTR = 0;
79 82
80 // the what value for POST_MESSAGE 83 // The |what| value for handleMessage.
81 private static final int POST_MESSAGE = 1; 84 private static final int MESSAGES_AVAILABLE = 1;
82
83 private static class PostMessageFromWeb {
84 public AppWebMessagePort port;
85 public String message;
86 public AppWebMessagePort[] sentPorts;
87
88 public PostMessageFromWeb(
89 AppWebMessagePort port, String message, AppWebMessagePort[] sent Ports) {
90 this.port = port;
91 this.message = message;
92 this.sentPorts = sentPorts;
93 }
94 }
95 85
96 // Implements the handler to handle messageport messages received from web. 86 // Implements the handler to handle messageport messages received from web.
97 // These messages are received on IO thread and normally handled in main 87 // These messages are received on IO thread and normally handled in main
98 // thread however, alternatively application can pass a handler to execute t hem. 88 // thread however, alternatively application can pass a handler to execute t hem.
99 private static class MessageHandler extends Handler { 89 private static class MessageHandler extends Handler {
100 public MessageHandler(Looper looper) { 90 public MessageHandler(Looper looper) {
101 super(looper); 91 super(looper);
102 } 92 }
103 @Override 93 @Override
104 public void handleMessage(Message msg) { 94 public void handleMessage(Message msg) {
105 if (msg.what == POST_MESSAGE) { 95 if (msg.what == MESSAGES_AVAILABLE) {
106 PostMessageFromWeb m = (PostMessageFromWeb) msg.obj; 96 AppWebMessagePort port = (AppWebMessagePort) msg.obj;
107 m.port.onMessage(m.message, m.sentPorts); 97 port.dispatchReceivedMessages();
108 return; 98 return;
109 } 99 }
110 throw new IllegalStateException("undefined message"); 100 throw new IllegalStateException("undefined message");
111 } 101 }
112 } 102 }
113 // The default message handler 103 // The default message handler
114 private static final MessageHandler sDefaultHandler = 104 private static final MessageHandler sDefaultHandler =
115 new MessageHandler(Looper.getMainLooper()); 105 new MessageHandler(Looper.getMainLooper());
116 106
117 private int mPortId = PENDING; 107 private long mNativeAppWebMessagePort = UNINITIALIZED_PORT_NATIVE_PTR;
108
118 private MessageCallback mMessageCallback; 109 private MessageCallback mMessageCallback;
119 private AppWebMessagePortService mMessagePortService;
120 private boolean mClosed; 110 private boolean mClosed;
121 private boolean mTransferred; 111 private boolean mTransferred;
122 private boolean mStarted; 112 private boolean mStarted;
123 private boolean mReleasedMessages;
124 private PostMessageSender mPostMessageSender;
125 private MessageHandler mHandler; 113 private MessageHandler mHandler;
126 private final Object mLock = new Object(); 114 private final Object mLock = new Object();
127 115
128 public AppWebMessagePort(AppWebMessagePortService messagePortService) { 116 // Called to create an entangled pair of ports.
129 mMessagePortService = messagePortService; 117 public static AppWebMessagePort[] createPair() {
130 mPostMessageSender = new PostMessageSender(this, mMessagePortService); 118 AppWebMessagePort[] ports =
131 mMessagePortService.addObserver(mPostMessageSender); 119 new AppWebMessagePort[] { new AppWebMessagePort(), new AppWebMessage Port() };
120 nativeInitializeAppWebMessagePortPair(ports);
121 return ports;
132 } 122 }
133 123
134 @Override 124 @Override
135 public boolean isReady() { 125 public boolean isReady() {
136 return mPortId != PENDING; 126 return mNativeAppWebMessagePort != UNINITIALIZED_PORT_NATIVE_PTR;
137 } 127 }
138 128
139 public int portId() { 129 @CalledByNative
140 return mPortId; 130 private void setNativeAppWebMessagePort(long nativeAppWebMessagePort) {
131 mNativeAppWebMessagePort = nativeAppWebMessagePort;
141 } 132 }
142 133
143 public void setPortId(int id) { 134 @CalledByNative
144 mPortId = id; 135 private long releaseNativePortForTransfer() {
sgurun-gerrit only 2017/02/08 21:47:50 who is deleting the native message port after it i
darin (slow to review) 2017/02/09 00:13:17 Thanks, I need to delete the native side from AppW
145 releaseMessages(); 136 mTransferred = true;
137 long port = mNativeAppWebMessagePort;
138 mNativeAppWebMessagePort = UNINITIALIZED_PORT_NATIVE_PTR;
139 return port;
146 } 140 }
147 141
148 @Override 142 @Override
149 public void close() { 143 public void close() {
150 if (mTransferred) { 144 if (mTransferred) {
151 throw new IllegalStateException("Port is already transferred"); 145 throw new IllegalStateException("Port is already transferred");
152 } 146 }
153 synchronized (mLock) { 147 synchronized (mLock) {
154 if (mClosed) return; 148 if (mClosed) return;
155 mClosed = true; 149 mClosed = true;
156 } 150 }
157 // If the port is already ready, and no messages are waiting in the 151 if (isReady()) {
158 // queue to be transferred, onPostMessageQueueEmpty() callback is not
159 // received (it is received only after messages are purged). In this
160 // case do the cleanup here.
161 if (isReady() && mPostMessageSender.isMessageQueueEmpty()) {
162 cleanup(); 152 cleanup();
163 } 153 }
164 } 154 }
165 155
166 @Override 156 @Override
167 public boolean isClosed() { 157 public boolean isClosed() {
168 return mClosed; 158 synchronized (mLock) {
159 return mClosed;
160 }
169 } 161 }
170 162
171 @Override 163 @Override
172 public boolean isTransferred() { 164 public boolean isTransferred() {
173 return mTransferred; 165 return mTransferred;
174 } 166 }
175 167
176 public void setTransferred() {
177 mTransferred = true;
178 }
179
180 @Override 168 @Override
181 public boolean isStarted() { 169 public boolean isStarted() {
182 return mStarted; 170 return mStarted;
183 } 171 }
184 172
185 // Only called on UI thread 173 // Only called on UI thread
186 @Override 174 @Override
187 public void setMessageCallback(MessageCallback messageCallback, Handler hand ler) { 175 public void setMessageCallback(MessageCallback messageCallback, Handler hand ler) {
188 mStarted = true; 176 mStarted = true;
189 synchronized (mLock) { 177 synchronized (mLock) {
190 mMessageCallback = messageCallback; 178 mMessageCallback = messageCallback;
191 if (handler != null) { 179 if (handler != null) {
192 mHandler = new MessageHandler(handler.getLooper()); 180 mHandler = new MessageHandler(handler.getLooper());
193 } 181 }
194 } 182 }
195 releaseMessages(); 183 nativeStartReceivingMessages(mNativeAppWebMessagePort);
196 } 184 }
197 185
198 // Only called on IO thread. 186 // Called on a background thread.
199 public void onReceivedMessage(String message, AppWebMessagePort[] sentPorts) { 187 @CalledByNative
188 private void onMessagesAvailable() {
200 synchronized (mLock) { 189 synchronized (mLock) {
201 PostMessageFromWeb m = new PostMessageFromWeb(this, message, sentPor ts);
202 Handler handler = mHandler != null ? mHandler : sDefaultHandler; 190 Handler handler = mHandler != null ? mHandler : sDefaultHandler;
203 Message msg = handler.obtainMessage(POST_MESSAGE, m); 191 Message msg = handler.obtainMessage(MESSAGES_AVAILABLE, this);
204 handler.sendMessage(msg); 192 handler.sendMessage(msg);
205 } 193 }
206 } 194 }
207 195
208 private void releaseMessages() {
209 if (mReleasedMessages || !isReady() || mMessageCallback == null) {
210 return;
211 }
212 mReleasedMessages = true;
213 mMessagePortService.releaseMessages(mPortId);
214 }
215
216 // This method may be called on a different thread than UI thread. 196 // This method may be called on a different thread than UI thread.
217 public void onMessage(String message, AppWebMessagePort[] ports) { 197 @CalledByNative
198 private void onReceivedMessage(String message, AppWebMessagePort[] ports) {
218 synchronized (mLock) { 199 synchronized (mLock) {
219 if (isClosed()) { 200 if (isClosed()) {
220 Log.w(TAG, "Port [" + mPortId + "] received message in closed st ate"); 201 Log.w(TAG, "Port [" + mNativeAppWebMessagePort
202 + "] received message in closed state");
221 return; 203 return;
222 } 204 }
223 if (mMessageCallback == null) { 205 if (mMessageCallback == null) {
224 Log.w(TAG, 206 Log.w(TAG, "No handler set for port [" + mNativeAppWebMessagePor t
225 "No handler set for port [" + mPortId + "], dropping mes sage " + message); 207 + "], dropping message " + message);
226 return; 208 return;
227 } 209 }
228 mMessageCallback.onMessage(message, ports); 210 mMessageCallback.onMessage(message, ports);
229 } 211 }
230 } 212 }
231 213
214 private void dispatchReceivedMessages() {
215 nativeDispatchReceivedMessages(mNativeAppWebMessagePort);
216 }
217
232 @Override 218 @Override
233 public void postMessage(String message, MessagePort[] sentPorts) throws Ille galStateException { 219 public void postMessage(String message, MessagePort[] sentPorts) throws Ille galStateException {
234 if (isClosed() || isTransferred()) { 220 if (isClosed() || isTransferred()) {
235 throw new IllegalStateException("Port is already closed or transferr ed"); 221 throw new IllegalStateException("Port is already closed or transferr ed");
236 } 222 }
237 AppWebMessagePort[] ports = null; 223 AppWebMessagePort[] ports = null;
238 if (sentPorts != null) { 224 if (sentPorts != null) {
239 for (MessagePort port : sentPorts) { 225 for (MessagePort port : sentPorts) {
240 if (port.equals(this)) { 226 if (port.equals(this)) {
241 throw new IllegalStateException("Source port cannot be trans ferred"); 227 throw new IllegalStateException("Source port cannot be trans ferred");
242 } 228 }
229 if (port.isClosed() || port.isTransferred()) {
230 throw new IllegalStateException("Port is already closed or t ransferred");
231 }
232 if (port.isStarted()) {
233 throw new IllegalStateException("Port is already started");
234 }
243 } 235 }
244 ports = Arrays.copyOf(sentPorts, sentPorts.length, AppWebMessagePort [].class); 236 ports = Arrays.copyOf(sentPorts, sentPorts.length, AppWebMessagePort [].class);
245 } 237 }
246 mStarted = true; 238 mStarted = true;
247 mPostMessageSender.postMessage(null, message, null, ports); 239 nativePostMessage(mNativeAppWebMessagePort, message, ports);
sgurun-gerrit only 2017/02/08 21:47:50 I wonder if these changes create an opportunity fo
darin (slow to review) 2017/02/09 00:13:17 Yeah, exactly. I had the same thoughts. I landed o
248 }
249
250 // Implements PostMessageSender.PostMessageSenderDelegate interface method.
251 @Override
252 public boolean isPostMessageSenderReady() {
253 return isReady();
254 }
255
256 // Implements PostMessageSender.PostMessageSenderDelegate interface method.
257 @Override
258 public void onPostMessageQueueEmpty() {
259 if (isClosed()) {
260 cleanup();
261 }
262 }
263
264 // Implements PostMessageSender.PostMessageSenderDelegate interface method.
265 @Override
266 public void postMessageToWeb(
267 String frameName, String message, String targetOrigin, int[] sentPor tIds) {
268 mMessagePortService.postMessage(mPortId, message, sentPortIds);
269 } 240 }
270 241
271 private void cleanup() { 242 private void cleanup() {
272 mMessagePortService.removeObserver(mPostMessageSender); 243 nativeCloseMessagePort(mNativeAppWebMessagePort);
273 mPostMessageSender = null; 244 mNativeAppWebMessagePort = UNINITIALIZED_PORT_NATIVE_PTR;
274 mMessagePortService.closePort(mPortId);
275 } 245 }
246
247 private static native void nativeInitializeAppWebMessagePortPair(AppWebMessa gePort[] ports);
248
249 private native void nativeCloseMessagePort(long nativeAppWebMessagePort);
250 private native void nativePostMessage(long nativeAppWebMessagePort, String m essage,
251 AppWebMessagePort[] ports);
252 private native void nativeDispatchReceivedMessages(long nativeAppWebMessageP ort);
253 private native void nativeStartReceivingMessages(long nativeAppWebMessagePor t);
276 } 254 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698