Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 Loading... | |
| 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 } |
| OLD | NEW |