• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2014 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.mojo.bindings;
6 
7 import org.chromium.mojo.system.Core;
8 import org.chromium.mojo.system.MessagePipeHandle;
9 import org.chromium.mojo.system.MessagePipeHandle.ReadMessageResult;
10 import org.chromium.mojo.system.MojoException;
11 import org.chromium.mojo.system.MojoResult;
12 import org.chromium.mojo.system.ResultAnd;
13 import org.chromium.mojo.system.Watcher;
14 
15 import java.nio.ByteBuffer;
16 
17 /**
18  * A {@link Connector} owns a {@link MessagePipeHandle} and will send any received messages to the
19  * registered {@link MessageReceiver}. It also acts as a {@link MessageReceiver} and will send any
20  * message through the handle.
21  * <p>
22  * The method |start| must be called before the {@link Connector} will start listening to incoming
23  * messages.
24  */
25 public class Connector implements MessageReceiver, HandleOwner<MessagePipeHandle> {
26 
27     /**
28      * The callback that is notified when the state of the owned handle changes.
29      */
30     private final WatcherCallback mWatcherCallback = new WatcherCallback();
31 
32     /**
33      * The owned message pipe.
34      */
35     private final MessagePipeHandle mMessagePipeHandle;
36 
37     /**
38      * A watcher which is notified when a new message is available on the owned message pipe.
39      */
40     private final Watcher mWatcher;
41 
42     /**
43      * The {@link MessageReceiver} to which received messages are sent.
44      */
45     private MessageReceiver mIncomingMessageReceiver;
46 
47     /**
48      * The error handler to notify of errors.
49      */
50     private ConnectionErrorHandler mErrorHandler;
51 
52     /**
53      * Create a new connector over a |messagePipeHandle|. The created connector will use the default
54      * {@link AsyncWaiter} from the {@link Core} implementation of |messagePipeHandle|.
55      */
Connector(MessagePipeHandle messagePipeHandle)56     public Connector(MessagePipeHandle messagePipeHandle) {
57         this(messagePipeHandle, BindingsHelper.getWatcherForHandle(messagePipeHandle));
58     }
59 
60     /**
61      * Create a new connector over a |messagePipeHandle| using the given {@link AsyncWaiter} to get
62      * notified of changes on the handle.
63      */
Connector(MessagePipeHandle messagePipeHandle, Watcher watcher)64     public Connector(MessagePipeHandle messagePipeHandle, Watcher watcher) {
65         mMessagePipeHandle = messagePipeHandle;
66         mWatcher = watcher;
67     }
68 
69     /**
70      * Set the {@link MessageReceiver} that will receive message from the owned message pipe.
71      */
setIncomingMessageReceiver(MessageReceiver incomingMessageReceiver)72     public void setIncomingMessageReceiver(MessageReceiver incomingMessageReceiver) {
73         mIncomingMessageReceiver = incomingMessageReceiver;
74     }
75 
76     /**
77      * Set the {@link ConnectionErrorHandler} that will be notified of errors on the owned message
78      * pipe.
79      */
setErrorHandler(ConnectionErrorHandler errorHandler)80     public void setErrorHandler(ConnectionErrorHandler errorHandler) {
81         mErrorHandler = errorHandler;
82     }
83 
84     /**
85      * Start listening for incoming messages.
86      */
start()87     public void start() {
88         mWatcher.start(mMessagePipeHandle, Core.HandleSignals.READABLE, mWatcherCallback);
89     }
90 
91     /**
92      * @see MessageReceiver#accept(Message)
93      */
94     @Override
accept(Message message)95     public boolean accept(Message message) {
96         try {
97             mMessagePipeHandle.writeMessage(message.getData(),
98                     message.getHandles(), MessagePipeHandle.WriteFlags.NONE);
99             return true;
100         } catch (MojoException e) {
101             onError(e);
102             return false;
103         }
104     }
105 
106     /**
107      * Pass the owned handle of the connector. After this, the connector is disconnected. It cannot
108      * accept new message and it isn't listening to the handle anymore.
109      *
110      * @see org.chromium.mojo.bindings.HandleOwner#passHandle()
111      */
112     @Override
passHandle()113     public MessagePipeHandle passHandle() {
114         cancelIfActive();
115         MessagePipeHandle handle = mMessagePipeHandle.pass();
116         if (mIncomingMessageReceiver != null) {
117             mIncomingMessageReceiver.close();
118         }
119         return handle;
120     }
121 
122     /**
123      * @see java.io.Closeable#close()
124      */
125     @Override
close()126     public void close() {
127         cancelIfActive();
128         mMessagePipeHandle.close();
129         if (mIncomingMessageReceiver != null) {
130             MessageReceiver incomingMessageReceiver = mIncomingMessageReceiver;
131             mIncomingMessageReceiver = null;
132             incomingMessageReceiver.close();
133         }
134     }
135 
136     private class WatcherCallback implements Watcher.Callback {
137         /**
138          * @see org.chromium.mojo.system.Watcher.Callback#onResult(int)
139          */
140         @Override
onResult(int result)141         public void onResult(int result) {
142             Connector.this.onWatcherResult(result);
143         }
144 
145     }
146 
147     /**
148      * @see org.chromium.mojo.system.Watcher.Callback#onResult(int)
149      */
onWatcherResult(int result)150     private void onWatcherResult(int result) {
151         if (result == MojoResult.OK) {
152             readOutstandingMessages();
153         } else {
154             onError(new MojoException(result));
155         }
156     }
157 
onError(MojoException exception)158     private void onError(MojoException exception) {
159         close();
160         if (mErrorHandler != null) {
161             mErrorHandler.onConnectionError(exception);
162         }
163     }
164 
165     /**
166      * Read all available messages on the owned message pipe.
167      */
readOutstandingMessages()168     private void readOutstandingMessages() {
169         ResultAnd<Boolean> result;
170         do {
171             try {
172                 result = readAndDispatchMessage(mMessagePipeHandle, mIncomingMessageReceiver);
173             } catch (MojoException e) {
174                 onError(e);
175                 return;
176             }
177         } while (result.getValue());
178         if (result.getMojoResult() != MojoResult.SHOULD_WAIT) {
179             onError(new MojoException(result.getMojoResult()));
180         }
181     }
182 
cancelIfActive()183     private void cancelIfActive() {
184         mWatcher.cancel();
185         mWatcher.destroy();
186     }
187 
188     /**
189      * Read a message, and pass it to the given |MessageReceiver| if not null. If the
190      * |MessageReceiver| is null, the message is lost.
191      *
192      * @param receiver The {@link MessageReceiver} that will receive the read {@link Message}. Can
193      *            be <code>null</code>, in which case the message is discarded.
194      */
readAndDispatchMessage( MessagePipeHandle handle, MessageReceiver receiver)195     static ResultAnd<Boolean> readAndDispatchMessage(
196             MessagePipeHandle handle, MessageReceiver receiver) {
197         ResultAnd<ReadMessageResult> result = handle.readMessage(MessagePipeHandle.ReadFlags.NONE);
198         if (result.getMojoResult() != MojoResult.OK) {
199             return new ResultAnd<Boolean>(result.getMojoResult(), false);
200         }
201         ReadMessageResult readResult = result.getValue();
202         assert readResult != null;
203         if (receiver != null) {
204             boolean accepted;
205             try {
206                 accepted = receiver.accept(
207                         new Message(ByteBuffer.wrap(readResult.mData), readResult.mHandles));
208             } catch (RuntimeException e) {
209                 // The DefaultExceptionHandler will decide whether any uncaught exception will
210                 // close the connection or not.
211                 accepted =
212                         ExceptionHandler.DefaultExceptionHandler.getInstance().handleException(e);
213             }
214             return new ResultAnd<Boolean>(result.getMojoResult(), accepted);
215         }
216         return new ResultAnd<Boolean>(result.getMojoResult(), false);
217     }
218 }
219