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 |