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 = -1; | |
|
Yusuf
2017/01/26 22:53:54
in all JNI classes 0 in general is used as the uni
| |
| 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; |
| 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 public AppWebMessagePort() { |
| 129 mMessagePortService = messagePortService; | |
| 130 mPostMessageSender = new PostMessageSender(this, mMessagePortService); | |
| 131 mMessagePortService.addObserver(mPostMessageSender); | |
| 132 } | 117 } |
| 133 | 118 |
| 134 @Override | 119 @Override |
| 135 public boolean isReady() { | 120 public boolean isReady() { |
| 136 return mPortId != PENDING; | 121 return mNativeAppWebMessagePort != UNINITIALIZED_PORT; |
| 137 } | 122 } |
| 138 | 123 |
| 139 public int portId() { | 124 @CalledByNative |
| 140 return mPortId; | 125 private void setNativeAppWebMessagePort(long nativeAppWebMessagePort) { |
| 126 mNativeAppWebMessagePort = nativeAppWebMessagePort; | |
| 141 } | 127 } |
| 142 | 128 |
| 143 public void setPortId(int id) { | 129 @CalledByNative |
| 144 mPortId = id; | 130 private long releaseNativePortForTransfer() { |
| 145 releaseMessages(); | 131 mTransferred = true; |
| 132 long port = mNativeAppWebMessagePort; | |
| 133 mNativeAppWebMessagePort = UNINITIALIZED_PORT; | |
| 134 return port; | |
| 146 } | 135 } |
| 147 | 136 |
| 148 @Override | 137 @Override |
| 149 public void close() { | 138 public void close() { |
| 150 if (mTransferred) { | 139 if (mTransferred) { |
| 151 throw new IllegalStateException("Port is already transferred"); | 140 throw new IllegalStateException("Port is already transferred"); |
| 152 } | 141 } |
| 153 synchronized (mLock) { | 142 synchronized (mLock) { |
| 154 if (mClosed) return; | 143 if (mClosed) return; |
| 155 mClosed = true; | 144 mClosed = true; |
| 156 } | 145 } |
| 157 // If the port is already ready, and no messages are waiting in the | 146 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(); | 147 cleanup(); |
| 163 } | 148 } |
| 164 } | 149 } |
| 165 | 150 |
| 166 @Override | 151 @Override |
| 167 public boolean isClosed() { | 152 public boolean isClosed() { |
| 168 return mClosed; | 153 synchronized (mLock) { |
| 154 return mClosed; | |
| 155 } | |
| 169 } | 156 } |
| 170 | 157 |
| 171 @Override | 158 @Override |
| 172 public boolean isTransferred() { | 159 public boolean isTransferred() { |
| 173 return mTransferred; | 160 return mTransferred; |
| 174 } | 161 } |
| 175 | 162 |
| 176 public void setTransferred() { | |
| 177 mTransferred = true; | |
| 178 } | |
| 179 | |
| 180 @Override | 163 @Override |
| 181 public boolean isStarted() { | 164 public boolean isStarted() { |
| 182 return mStarted; | 165 return mStarted; |
| 183 } | 166 } |
| 184 | 167 |
| 185 // Only called on UI thread | 168 // Only called on UI thread |
| 186 @Override | 169 @Override |
| 187 public void setMessageCallback(MessageCallback messageCallback, Handler hand ler) { | 170 public void setMessageCallback(MessageCallback messageCallback, Handler hand ler) { |
| 188 mStarted = true; | 171 mStarted = true; |
| 189 synchronized (mLock) { | 172 synchronized (mLock) { |
| 190 mMessageCallback = messageCallback; | 173 mMessageCallback = messageCallback; |
| 191 if (handler != null) { | 174 if (handler != null) { |
| 192 mHandler = new MessageHandler(handler.getLooper()); | 175 mHandler = new MessageHandler(handler.getLooper()); |
| 193 } | 176 } |
| 194 } | 177 } |
| 195 releaseMessages(); | 178 nativeStartReceivingMessages(mNativeAppWebMessagePort); |
| 196 } | 179 } |
| 197 | 180 |
| 198 // Only called on IO thread. | 181 // Called on a background thread. |
| 199 public void onReceivedMessage(String message, AppWebMessagePort[] sentPorts) { | 182 @CalledByNative |
| 183 private void onMessagesAvailable() { | |
| 200 synchronized (mLock) { | 184 synchronized (mLock) { |
| 201 PostMessageFromWeb m = new PostMessageFromWeb(this, message, sentPor ts); | |
| 202 Handler handler = mHandler != null ? mHandler : sDefaultHandler; | 185 Handler handler = mHandler != null ? mHandler : sDefaultHandler; |
| 203 Message msg = handler.obtainMessage(POST_MESSAGE, m); | 186 Message msg = handler.obtainMessage(MESSAGES_AVAILABLE, this); |
| 204 handler.sendMessage(msg); | 187 handler.sendMessage(msg); |
| 205 } | 188 } |
| 206 } | 189 } |
| 207 | 190 |
| 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. | 191 // This method may be called on a different thread than UI thread. |
| 217 public void onMessage(String message, AppWebMessagePort[] ports) { | 192 @CalledByNative |
| 193 private void onReceivedMessage(String message, AppWebMessagePort[] ports) { | |
| 218 synchronized (mLock) { | 194 synchronized (mLock) { |
| 219 if (isClosed()) { | 195 if (isClosed()) { |
| 220 Log.w(TAG, "Port [" + mPortId + "] received message in closed st ate"); | 196 Log.w(TAG, "Port [" + mNativeAppWebMessagePort |
| 197 + "] received message in closed state"); | |
| 221 return; | 198 return; |
| 222 } | 199 } |
| 223 if (mMessageCallback == null) { | 200 if (mMessageCallback == null) { |
| 224 Log.w(TAG, | 201 Log.w(TAG, "No handler set for port [" + mNativeAppWebMessagePor t |
| 225 "No handler set for port [" + mPortId + "], dropping mes sage " + message); | 202 + "], dropping message " + message); |
| 226 return; | 203 return; |
| 227 } | 204 } |
| 228 mMessageCallback.onMessage(message, ports); | 205 mMessageCallback.onMessage(message, ports); |
| 229 } | 206 } |
| 230 } | 207 } |
| 231 | 208 |
| 209 public void dispatchReceivedMessages() { | |
|
Yusuf
2017/01/26 22:53:54
javadoc
| |
| 210 nativeDispatchReceivedMessages(mNativeAppWebMessagePort); | |
| 211 } | |
| 212 | |
| 232 @Override | 213 @Override |
| 233 public void postMessage(String message, MessagePort[] sentPorts) throws Ille galStateException { | 214 public void postMessage(String message, MessagePort[] sentPorts) throws Ille galStateException { |
| 234 if (isClosed() || isTransferred()) { | 215 if (isClosed() || isTransferred()) { |
| 235 throw new IllegalStateException("Port is already closed or transferr ed"); | 216 throw new IllegalStateException("Port is already closed or transferr ed"); |
| 236 } | 217 } |
| 237 AppWebMessagePort[] ports = null; | 218 AppWebMessagePort[] ports = null; |
| 238 if (sentPorts != null) { | 219 if (sentPorts != null) { |
| 239 for (MessagePort port : sentPorts) { | 220 for (MessagePort port : sentPorts) { |
| 240 if (port.equals(this)) { | 221 if (port.equals(this)) { |
| 241 throw new IllegalStateException("Source port cannot be trans ferred"); | 222 throw new IllegalStateException("Source port cannot be trans ferred"); |
| 242 } | 223 } |
| 224 if (port.isClosed() || port.isTransferred()) { | |
| 225 throw new IllegalStateException("Port is already closed or t ransferred"); | |
| 226 } | |
| 227 if (port.isStarted()) { | |
| 228 throw new IllegalStateException("Port is already started"); | |
| 229 } | |
| 243 } | 230 } |
| 244 ports = Arrays.copyOf(sentPorts, sentPorts.length, AppWebMessagePort [].class); | 231 ports = Arrays.copyOf(sentPorts, sentPorts.length, AppWebMessagePort [].class); |
| 245 } | 232 } |
| 246 mStarted = true; | 233 mStarted = true; |
| 247 mPostMessageSender.postMessage(null, message, null, ports); | 234 nativePostMessage(mNativeAppWebMessagePort, message, ports); |
| 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 } | 235 } |
| 270 | 236 |
| 271 private void cleanup() { | 237 private void cleanup() { |
| 272 mMessagePortService.removeObserver(mPostMessageSender); | 238 nativeCloseMessagePort(mNativeAppWebMessagePort); |
| 273 mPostMessageSender = null; | 239 mNativeAppWebMessagePort = UNINITIALIZED_PORT; |
| 274 mMessagePortService.closePort(mPortId); | |
| 275 } | 240 } |
| 241 | |
| 242 private native void nativeCloseMessagePort(long nativeAppWebMessagePort); | |
| 243 private native void nativePostMessage(long nativeAppWebMessagePort, String m essage, | |
| 244 AppWebMessagePort[] ports); | |
| 245 private native void nativeDispatchReceivedMessages(long nativeAppWebMessageP ort); | |
| 246 private native void nativeStartReceivingMessages(long nativeAppWebMessagePor t); | |
| 276 } | 247 } |
| OLD | NEW |