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 |