| OLD | NEW |
| (Empty) |
| 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 | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 package org.chromium.android_webview; | |
| 6 | |
| 7 import android.util.SparseArray; | |
| 8 | |
| 9 import org.chromium.base.ObserverList; | |
| 10 import org.chromium.base.ThreadUtils; | |
| 11 import org.chromium.base.annotations.CalledByNative; | |
| 12 import org.chromium.base.annotations.JNINamespace; | |
| 13 | |
| 14 /** | |
| 15 * Provides the Message Channel functionality for Android Webview. Specifically | |
| 16 * manages the message ports that are associated with a message channel and | |
| 17 * handles posting/receiving messages to/from them. | |
| 18 * See https://html.spec.whatwg.org/multipage/comms.html#messagechannel for | |
| 19 * further information on message channels. | |
| 20 * | |
| 21 * The message ports have unique IDs. In Android webview implementation, | |
| 22 * the message ports are only known by their IDs at the native side. | |
| 23 * At the java side, the embedder deals with MessagePort objects. The mapping | |
| 24 * from an ID to an object is in AwMessagePortService. AwMessagePortService | |
| 25 * keeps a strong ref to MessagePort objects until they are closed. | |
| 26 * | |
| 27 * Ownership: The Java AwMessagePortService is owned by Java AwBrowserContext. | |
| 28 * The native AwMessagePortService is owned by native AwBrowserContext. The | |
| 29 * native peer maintains a weak ref to the java object and deregisters itself | |
| 30 * before being deleted. | |
| 31 * | |
| 32 * All methods are called on UI thread except as noted. | |
| 33 */ | |
| 34 @JNINamespace("android_webview") | |
| 35 public class AwMessagePortService { | |
| 36 | |
| 37 private static final String TAG = "AwMessagePortService"; | |
| 38 | |
| 39 /** | |
| 40 * Observer for MessageChannel events. | |
| 41 */ | |
| 42 public static interface MessageChannelObserver { | |
| 43 void onMessageChannelCreated(); | |
| 44 } | |
| 45 | |
| 46 // A thread safe storage for Message Ports. | |
| 47 private static class MessagePortStorage { | |
| 48 private SparseArray<AwMessagePort> mMessagePorts = new SparseArray<AwMes
sagePort>(); | |
| 49 private final Object mLock = new Object(); | |
| 50 | |
| 51 public void remove(int portId) { | |
| 52 synchronized (mLock) { | |
| 53 mMessagePorts.remove(portId); | |
| 54 } | |
| 55 } | |
| 56 | |
| 57 public void put(int portId, AwMessagePort m) { | |
| 58 synchronized (mLock) { | |
| 59 mMessagePorts.put(portId, m); | |
| 60 } | |
| 61 } | |
| 62 public AwMessagePort get(int portId) { | |
| 63 synchronized (mLock) { | |
| 64 return mMessagePorts.get(portId); | |
| 65 } | |
| 66 } | |
| 67 } | |
| 68 | |
| 69 private long mNativeMessagePortService; | |
| 70 private MessagePortStorage mPortStorage = new MessagePortStorage(); | |
| 71 private ObserverList<MessageChannelObserver> mObserverList = | |
| 72 new ObserverList<MessageChannelObserver>(); | |
| 73 | |
| 74 AwMessagePortService() { | |
| 75 mNativeMessagePortService = nativeInitAwMessagePortService(); | |
| 76 } | |
| 77 | |
| 78 public void addObserver(MessageChannelObserver observer) { | |
| 79 mObserverList.addObserver(observer); | |
| 80 } | |
| 81 | |
| 82 public void removeObserver(MessageChannelObserver observer) { | |
| 83 mObserverList.removeObserver(observer); | |
| 84 } | |
| 85 | |
| 86 public void closePort(int messagePortId) { | |
| 87 mPortStorage.remove(messagePortId); | |
| 88 if (mNativeMessagePortService == 0) return; | |
| 89 nativeClosePort(mNativeMessagePortService, messagePortId); | |
| 90 } | |
| 91 | |
| 92 public void postMessage(int senderId, String message, int[] sentPorts) { | |
| 93 // verify that webview still owns the port (not transferred) | |
| 94 if (mPortStorage.get(senderId) == null) { | |
| 95 throw new IllegalStateException("Cannot post to unknown port " + sen
derId); | |
| 96 } | |
| 97 if (mNativeMessagePortService == 0) return; | |
| 98 nativePostAppToWebMessage(mNativeMessagePortService, senderId, message,
sentPorts); | |
| 99 } | |
| 100 | |
| 101 public void removeSentPorts(int[] sentPorts) { | |
| 102 // verify that webview owns all the ports that are transferred | |
| 103 if (sentPorts != null) { | |
| 104 for (int port : sentPorts) { | |
| 105 AwMessagePort p = mPortStorage.get(port); | |
| 106 if (p == null) { | |
| 107 throw new IllegalStateException("Cannot transfer unknown por
t " + port); | |
| 108 } | |
| 109 mPortStorage.remove(port); | |
| 110 } | |
| 111 } | |
| 112 } | |
| 113 | |
| 114 public AwMessagePort[] createMessageChannel() { | |
| 115 return new AwMessagePort[]{new AwMessagePort(this), new AwMessagePort(th
is)}; | |
| 116 } | |
| 117 | |
| 118 // Called on UI thread. | |
| 119 public void releaseMessages(int portId) { | |
| 120 if (mNativeMessagePortService == 0) return; | |
| 121 nativeReleaseMessages(mNativeMessagePortService, portId); | |
| 122 } | |
| 123 | |
| 124 private AwMessagePort addPort(AwMessagePort m, int portId) { | |
| 125 if (mPortStorage.get(portId) != null) { | |
| 126 throw new IllegalStateException("Port already exists"); | |
| 127 } | |
| 128 m.setPortId(portId); | |
| 129 mPortStorage.put(portId, m); | |
| 130 return m; | |
| 131 } | |
| 132 | |
| 133 @CalledByNative | |
| 134 private void onMessageChannelCreated(int portId1, int portId2, | |
| 135 AwMessagePort[] ports) { | |
| 136 ThreadUtils.assertOnUiThread(); | |
| 137 addPort(ports[0], portId1); | |
| 138 addPort(ports[1], portId2); | |
| 139 for (MessageChannelObserver observer : mObserverList) { | |
| 140 observer.onMessageChannelCreated(); | |
| 141 } | |
| 142 } | |
| 143 | |
| 144 // Called on IO thread. | |
| 145 @CalledByNative | |
| 146 private void onReceivedMessage(int portId, String message, int[] ports) { | |
| 147 AwMessagePort[] messagePorts = null; | |
| 148 for (int i = 0; i < ports.length; i++) { | |
| 149 if (messagePorts == null) { | |
| 150 messagePorts = new AwMessagePort[ports.length]; | |
| 151 } | |
| 152 messagePorts[i] = addPort(new AwMessagePort(this), ports[i]); | |
| 153 } | |
| 154 mPortStorage.get(portId).onReceivedMessage(message, messagePorts); | |
| 155 } | |
| 156 | |
| 157 @CalledByNative | |
| 158 private void unregisterNativeAwMessagePortService() { | |
| 159 mNativeMessagePortService = 0; | |
| 160 } | |
| 161 | |
| 162 private native long nativeInitAwMessagePortService(); | |
| 163 private native void nativePostAppToWebMessage(long nativeAwMessagePortServic
eImpl, | |
| 164 int senderId, String message, int[] portIds); | |
| 165 private native void nativeClosePort(long nativeAwMessagePortServiceImpl, | |
| 166 int messagePortId); | |
| 167 private native void nativeReleaseMessages(long nativeAwMessagePortServiceImp
l, | |
| 168 int messagePortId); | |
| 169 } | |
| OLD | NEW |