| Index: android_webview/java/src/org/chromium/android_webview/PostMessageSender.java
|
| diff --git a/android_webview/java/src/org/chromium/android_webview/PostMessageSender.java b/android_webview/java/src/org/chromium/android_webview/PostMessageSender.java
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..1a01f5e7d6c8845452f20de873729ba67eb24af2
|
| --- /dev/null
|
| +++ b/android_webview/java/src/org/chromium/android_webview/PostMessageSender.java
|
| @@ -0,0 +1,150 @@
|
| +// Copyright 2015 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +package org.chromium.android_webview;
|
| +
|
| +import java.util.ArrayDeque;
|
| +
|
| +/**
|
| + * Sanity checks and sends post messages to web. Queues messages if necessary.
|
| + */
|
| +public class PostMessageSender implements AwMessagePortService.MessageChannelObserver {
|
| +
|
| + /**
|
| + * The interface for message handler.
|
| + */
|
| + public static interface PostMessageSenderDelegate {
|
| +
|
| + /*
|
| + * Posts a message to the destination frame for real. The unique message port
|
| + * id of any transferred port should be known at this time.
|
| + */
|
| + void postMessageToWeb(String frameName, String message, String sourceOrigin,
|
| + String targetOrigin, int[] sentPortIds);
|
| + };
|
| +
|
| + // A struct to store Message parameters that are sent from App to Web.
|
| + private static class PostMessageParams {
|
| + public String frameName;
|
| + public String message;
|
| + public String sourceOrigin;
|
| + public String targetOrigin;
|
| + public MessagePort[] sentPorts;
|
| +
|
| + public PostMessageParams(String frameName, String message, String sourceOrigin,
|
| + String targetOrigin, MessagePort[] sentPorts) {
|
| + this.frameName = frameName;
|
| + this.message = message;
|
| + this.sourceOrigin = sourceOrigin;
|
| + this.targetOrigin = targetOrigin;
|
| + this.sentPorts = sentPorts;
|
| + }
|
| + }
|
| +
|
| + private PostMessageSenderDelegate mDelegate;
|
| + private AwMessagePortService mService;
|
| +
|
| + // If a message that is sent from android webview to web has a pending port (a port that
|
| + // is not internally created yet), this message, and any following messages will be
|
| + // queued until the transferred port becomes ready. This is necessary to prevent any
|
| + // reordering.
|
| + private ArrayDeque<PostMessageParams> mMessageQueue = new ArrayDeque<PostMessageParams>();
|
| +
|
| + public PostMessageSender(PostMessageSenderDelegate delegate, AwMessagePortService service) {
|
| + mDelegate = delegate;
|
| + mService = service;
|
| + }
|
| +
|
| + // Return true if any sent port is pending.
|
| + private boolean anySentPortIsPending(MessagePort[] sentPorts) {
|
| + if (sentPorts != null) {
|
| + for (MessagePort port : sentPorts) {
|
| + if (!port.isReady()) {
|
| + return true;
|
| + }
|
| + }
|
| + }
|
| + return false;
|
| + }
|
| +
|
| + // By default the sender is always ready.
|
| + protected boolean senderIsReady() {
|
| + return true;
|
| + }
|
| +
|
| + // A message to a frame is queued if:
|
| + // 1. Sender is not ready to post. When posting messages to frames, sender is always
|
| + // ready. However, when posting messages using message channels, sender may be in
|
| + // a pending state.
|
| + // 2. There are already queued messages
|
| + // 3. The message includes a port that is not ready yet.
|
| + private boolean shouldQueueMessage(MessagePort[] sentPorts) {
|
| + // if messages to frames are already in queue mode, simply queue it, no need to
|
| + // check ports.
|
| + if (mMessageQueue.size() > 0 || !senderIsReady()) {
|
| + return true;
|
| + }
|
| + if (anySentPortIsPending(sentPorts)) {
|
| + return true;
|
| + }
|
| + return false;
|
| + }
|
| +
|
| + private void postMessageToWeb(String frameName, String message, String sourceOrigin,
|
| + String targetOrigin, MessagePort[] sentPorts) {
|
| + int[] portIds = null;
|
| + if (sentPorts != null) {
|
| + portIds = new int[sentPorts.length];
|
| + for (int i = 0; i < sentPorts.length; i++) {
|
| + portIds[i] = sentPorts[i].portId();
|
| + }
|
| + mService.removeSentPorts(portIds);
|
| + }
|
| + mDelegate.postMessageToWeb(frameName, message, sourceOrigin, targetOrigin, portIds);
|
| + }
|
| +
|
| + /*
|
| + * Sanity checks the message and queues it if necessary. Posts the message to delegate
|
| + * when message can be sent.
|
| + */
|
| + public void postMessage(String frameName, String message, String sourceOrigin,
|
| + String targetOrigin, MessagePort[] sentPorts) throws IllegalStateException {
|
| + // Sanity check all the ports that are being transferred.
|
| + if (sentPorts != null) {
|
| + for (MessagePort p : sentPorts) {
|
| + if (p.isClosed() || p.isTransferred()) {
|
| + throw new IllegalStateException("Port cannot be transferred");
|
| + }
|
| + p.setTransferred();
|
| + }
|
| + }
|
| + if (shouldQueueMessage(sentPorts)) {
|
| + mMessageQueue.add(new PostMessageParams(frameName, message, sourceOrigin,
|
| + targetOrigin, sentPorts));
|
| + } else {
|
| + postMessageToWeb(frameName, message, sourceOrigin, targetOrigin, sentPorts);
|
| + }
|
| + }
|
| +
|
| + /*
|
| + * Starts posting any messages that are queued.
|
| + */
|
| + public void onMessageChannelCreated() {
|
| + PostMessageParams msg;
|
| +
|
| + if (!senderIsReady()) {
|
| + return;
|
| + }
|
| +
|
| + while ((msg = mMessageQueue.peek()) != null) {
|
| + // If there are still pending ports, message cannot be posted.
|
| + if (anySentPortIsPending(msg.sentPorts)) {
|
| + return;
|
| + }
|
| + mMessageQueue.remove();
|
| + postMessageToWeb(msg.frameName, msg.message, msg.sourceOrigin, msg.targetOrigin,
|
| + msg.sentPorts);
|
| + }
|
| + }
|
| +}
|
|
|