| 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.content.browser; | |
| 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 import org.chromium.content_public.browser.MessagePortService; | |
| 14 | |
| 15 /** | |
| 16 * Provides the Message Channel functionality for Android Apps | |
| 17 * (including WebView embedders and Chrome Custom Tabs clients). Specifically | |
| 18 * manages the message ports that are associated with a message channel and | |
| 19 * handles posting/receiving messages to/from them. | |
| 20 * See https://html.spec.whatwg.org/multipage/comms.html#messagechannel for | |
| 21 * further information on message channels. | |
| 22 * | |
| 23 * The message ports have unique IDs. In Android implementation, | |
| 24 * the message ports are only known by their IDs at the native side. | |
| 25 * At the java side, the embedder deals with MessagePort objects. The mapping | |
| 26 * from an ID to an object is in AppWebMessagePortService. AppWebMessagePortServ
ice | |
| 27 * keeps a strong ref to MessagePort objects until they are closed. | |
| 28 * | |
| 29 * Ownership: The Java AppWebMessagePortService has to be owned by Java side glo
bal. | |
| 30 * The native AppWebMessagePortService is a singleton. The | |
| 31 * native peer maintains a weak ref to the java object and deregisters itself | |
| 32 * before being deleted. | |
| 33 * | |
| 34 * All methods are called on UI thread except as noted. | |
| 35 */ | |
| 36 @JNINamespace("content") | |
| 37 public class AppWebMessagePortService implements MessagePortService { | |
| 38 private static final String TAG = "AppWebMessagePortService"; | |
| 39 | |
| 40 /** | |
| 41 * Observer for MessageChannel events. | |
| 42 */ | |
| 43 public static interface MessageChannelObserver { void onMessageChannelCreate
d(); } | |
| 44 | |
| 45 // A thread safe storage for Message Ports. | |
| 46 private static class MessagePortStorage { | |
| 47 private SparseArray<AppWebMessagePort> mMessagePorts = new SparseArray<A
ppWebMessagePort>(); | |
| 48 private final Object mLock = new Object(); | |
| 49 | |
| 50 public void remove(int portId) { | |
| 51 synchronized (mLock) { | |
| 52 mMessagePorts.remove(portId); | |
| 53 } | |
| 54 } | |
| 55 | |
| 56 public void put(int portId, AppWebMessagePort m) { | |
| 57 synchronized (mLock) { | |
| 58 mMessagePorts.put(portId, m); | |
| 59 } | |
| 60 } | |
| 61 public AppWebMessagePort get(int portId) { | |
| 62 synchronized (mLock) { | |
| 63 return mMessagePorts.get(portId); | |
| 64 } | |
| 65 } | |
| 66 } | |
| 67 | |
| 68 private long mNativeMessagePortService; | |
| 69 private MessagePortStorage mPortStorage = new MessagePortStorage(); | |
| 70 private ObserverList<MessageChannelObserver> mObserverList = | |
| 71 new ObserverList<MessageChannelObserver>(); | |
| 72 | |
| 73 public AppWebMessagePortService() { | |
| 74 mNativeMessagePortService = nativeInitAppWebMessagePortService(); | |
| 75 } | |
| 76 | |
| 77 public void addObserver(MessageChannelObserver observer) { | |
| 78 mObserverList.addObserver(observer); | |
| 79 } | |
| 80 | |
| 81 public void removeObserver(MessageChannelObserver observer) { | |
| 82 mObserverList.removeObserver(observer); | |
| 83 } | |
| 84 | |
| 85 public void closePort(int messagePortId) { | |
| 86 mPortStorage.remove(messagePortId); | |
| 87 if (mNativeMessagePortService == 0) return; | |
| 88 nativeClosePort(mNativeMessagePortService, messagePortId); | |
| 89 } | |
| 90 | |
| 91 public void postMessage(int senderId, String message, int[] sentPorts) { | |
| 92 // verify that the port is owned by service still (not transferred). | |
| 93 if (mPortStorage.get(senderId) == null) { | |
| 94 throw new IllegalStateException("Cannot post to unknown port " + sen
derId); | |
| 95 } | |
| 96 if (mNativeMessagePortService == 0) return; | |
| 97 nativePostAppToWebMessage(mNativeMessagePortService, senderId, message,
sentPorts); | |
| 98 } | |
| 99 | |
| 100 public void removeSentPorts(int[] sentPorts) { | |
| 101 // verify that this service still owns all the ports that are transferre
d | |
| 102 if (sentPorts != null) { | |
| 103 for (int port : sentPorts) { | |
| 104 AppWebMessagePort p = mPortStorage.get(port); | |
| 105 if (p == null) { | |
| 106 throw new IllegalStateException("Cannot transfer unknown por
t " + port); | |
| 107 } | |
| 108 mPortStorage.remove(port); | |
| 109 } | |
| 110 } | |
| 111 } | |
| 112 | |
| 113 @Override | |
| 114 public AppWebMessagePort[] createMessageChannel() { | |
| 115 return new AppWebMessagePort[] {new AppWebMessagePort(this), new AppWebM
essagePort(this)}; | |
| 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 AppWebMessagePort addPort(AppWebMessagePort 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, AppWebMessage
Port[] ports) { | |
| 135 ThreadUtils.assertOnUiThread(); | |
| 136 addPort(ports[0], portId1); | |
| 137 addPort(ports[1], portId2); | |
| 138 for (MessageChannelObserver observer : mObserverList) { | |
| 139 observer.onMessageChannelCreated(); | |
| 140 } | |
| 141 } | |
| 142 | |
| 143 // Called on IO thread. | |
| 144 @CalledByNative | |
| 145 private void onReceivedMessage(int portId, String message, int[] ports) { | |
| 146 AppWebMessagePort[] messagePorts = null; | |
| 147 for (int i = 0; i < ports.length; i++) { | |
| 148 if (messagePorts == null) { | |
| 149 messagePorts = new AppWebMessagePort[ports.length]; | |
| 150 } | |
| 151 messagePorts[i] = addPort(new AppWebMessagePort(this), ports[i]); | |
| 152 } | |
| 153 mPortStorage.get(portId).onReceivedMessage(message, messagePorts); | |
| 154 } | |
| 155 | |
| 156 @CalledByNative | |
| 157 private void unregisterNativeAppWebMessagePortService() { | |
| 158 mNativeMessagePortService = 0; | |
| 159 } | |
| 160 | |
| 161 private native long nativeInitAppWebMessagePortService(); | |
| 162 private native void nativePostAppToWebMessage( | |
| 163 long nativeAppWebMessagePortServiceImpl, int senderId, String messag
e, int[] portIds); | |
| 164 private native void nativeClosePort(long nativeAppWebMessagePortServiceImpl,
int messagePortId); | |
| 165 private native void nativeReleaseMessages( | |
| 166 long nativeAppWebMessagePortServiceImpl, int messagePortId); | |
| 167 } | |
| OLD | NEW |