| // Copyright 2014 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| package org.chromium.mojo.bindings; |
| |
| import org.chromium.mojo.bindings.Callbacks.Callback1; |
| import org.chromium.mojo.bindings.Interface.AbstractProxy.HandlerImpl; |
| import org.chromium.mojo.bindings.interfacecontrol.QueryVersion; |
| import org.chromium.mojo.bindings.interfacecontrol.RequireVersion; |
| import org.chromium.mojo.bindings.interfacecontrol.RunInput; |
| import org.chromium.mojo.bindings.interfacecontrol.RunMessageParams; |
| import org.chromium.mojo.bindings.interfacecontrol.RunOrClosePipeInput; |
| import org.chromium.mojo.bindings.interfacecontrol.RunOrClosePipeMessageParams; |
| import org.chromium.mojo.bindings.interfacecontrol.RunOutput; |
| import org.chromium.mojo.bindings.interfacecontrol.RunResponseMessageParams; |
| import org.chromium.mojo.system.Core; |
| import org.chromium.mojo.system.MessagePipeHandle; |
| import org.chromium.mojo.system.MojoException; |
| import org.chromium.mojo.system.Pair; |
| |
| import java.io.Closeable; |
| |
| /** |
| * Base class for mojo generated interfaces. |
| */ |
| public interface Interface extends ConnectionErrorHandler, Closeable { |
| |
| /** |
| * The close method is called when the connection to the interface is closed. |
| * |
| * @see java.io.Closeable#close() |
| */ |
| @Override |
| public void close(); |
| |
| /** |
| * A proxy to a mojo interface. This is base class for all generated proxies. It implements the |
| * Interface and each time a method is called, the parameters are serialized and sent to the |
| * {@link MessageReceiverWithResponder}, along with the response callback if needed. |
| */ |
| public interface Proxy extends Interface { |
| /** |
| * Class allowing to interact with the proxy itself. |
| */ |
| public interface Handler extends Closeable { |
| /** |
| * Sets the {@link ConnectionErrorHandler} that will be notified of errors. |
| */ |
| public void setErrorHandler(ConnectionErrorHandler errorHandler); |
| |
| /** |
| * Unbinds the proxy and passes the handle. Can return null if the proxy is not bound or |
| * if the proxy is not over a message pipe. |
| */ |
| public MessagePipeHandle passHandle(); |
| |
| /** |
| * Returns the version number of the interface that the remote side supports. |
| */ |
| public int getVersion(); |
| |
| /** |
| * Queries the max version that the remote side supports. On completion, the result will |
| * be returned as the input of |callback|. The version number of this interface pointer |
| * will also be updated. |
| */ |
| public void queryVersion(Callback1<Integer> callback); |
| |
| /** |
| * If the remote side doesn't support the specified version, it will close its end of |
| * the message pipe asynchronously. The call does nothing if |version| is no greater |
| * than getVersion(). |
| * <p> |
| * If you make a call to requireVersion() with a version number X which is not supported |
| * by the remote side, it is guaranteed that all calls to the interface methods after |
| * requireVersion(X) will be ignored. |
| */ |
| public void requireVersion(int version); |
| } |
| |
| /** |
| * Returns the {@link Handler} object allowing to interact with the proxy itself. |
| */ |
| public Handler getProxyHandler(); |
| } |
| |
| /** |
| * Base implementation of {@link Proxy}. |
| */ |
| abstract class AbstractProxy implements Proxy { |
| /** |
| * Implementation of {@link Handler}. |
| */ |
| protected static class HandlerImpl implements Proxy.Handler, ConnectionErrorHandler { |
| /** |
| * The {@link Core} implementation to use. |
| */ |
| private final Core mCore; |
| |
| /** |
| * The {@link MessageReceiverWithResponder} that will receive a serialized message for |
| * each method call. |
| */ |
| private final MessageReceiverWithResponder mMessageReceiver; |
| |
| /** |
| * The {@link ConnectionErrorHandler} that will be notified of errors. |
| */ |
| private ConnectionErrorHandler mErrorHandler; |
| |
| /** |
| * The currently known version of the interface. |
| */ |
| private int mVersion; |
| |
| /** |
| * Constructor. |
| * |
| * @param core the Core implementation used to create pipes and access the async waiter. |
| * @param messageReceiver the message receiver to send message to. |
| */ |
| protected HandlerImpl(Core core, MessageReceiverWithResponder messageReceiver) { |
| this.mCore = core; |
| this.mMessageReceiver = messageReceiver; |
| } |
| |
| void setVersion(int version) { |
| mVersion = version; |
| } |
| |
| /** |
| * Returns the message receiver to send message to. |
| */ |
| public MessageReceiverWithResponder getMessageReceiver() { |
| return mMessageReceiver; |
| } |
| |
| /** |
| * Returns the Core implementation. |
| */ |
| public Core getCore() { |
| return mCore; |
| } |
| |
| /** |
| * Sets the {@link ConnectionErrorHandler} that will be notified of errors. |
| */ |
| @Override |
| public void setErrorHandler(ConnectionErrorHandler errorHandler) { |
| this.mErrorHandler = errorHandler; |
| } |
| |
| /** |
| * @see ConnectionErrorHandler#onConnectionError(MojoException) |
| */ |
| @Override |
| public void onConnectionError(MojoException e) { |
| if (mErrorHandler != null) { |
| mErrorHandler.onConnectionError(e); |
| } |
| } |
| |
| /** |
| * @see Closeable#close() |
| */ |
| @Override |
| public void close() { |
| mMessageReceiver.close(); |
| } |
| |
| /** |
| * @see Interface.Proxy.Handler#passHandle() |
| */ |
| @Override |
| public MessagePipeHandle passHandle() { |
| @SuppressWarnings("unchecked") |
| HandleOwner<MessagePipeHandle> handleOwner = |
| (HandleOwner<MessagePipeHandle>) mMessageReceiver; |
| return handleOwner.passHandle(); |
| } |
| |
| /** |
| * @see Handler#getVersion() |
| */ |
| @Override |
| public int getVersion() { |
| return mVersion; |
| } |
| |
| /** |
| * @see Handler#queryVersion(org.chromium.mojo.bindings.Callbacks.Callback1) |
| */ |
| @Override |
| public void queryVersion(final Callback1<Integer> callback) { |
| RunMessageParams message = new RunMessageParams(); |
| message.input = new RunInput(); |
| message.input.setQueryVersion(new QueryVersion()); |
| |
| InterfaceControlMessagesHelper.sendRunMessage(getCore(), mMessageReceiver, message, |
| new Callback1<RunResponseMessageParams>() { |
| @Override |
| public void call(RunResponseMessageParams response) { |
| if (response.output != null |
| && response.output.which() |
| == RunOutput.Tag.QueryVersionResult) { |
| mVersion = response.output.getQueryVersionResult().version; |
| } |
| try { |
| callback.call(mVersion); |
| } catch (RuntimeException e) { |
| // TODO(lhchavez): Remove this hack. See b/28986534 for details. |
| android.util.Log.wtf("org.chromium.mojo.bindings.Interface", |
| "Uncaught runtime exception", e); |
| } |
| } |
| }); |
| } |
| |
| /** |
| * @see Handler#requireVersion(int) |
| */ |
| @Override |
| public void requireVersion(int version) { |
| if (mVersion >= version) { |
| return; |
| } |
| mVersion = version; |
| RunOrClosePipeMessageParams message = new RunOrClosePipeMessageParams(); |
| message.input = new RunOrClosePipeInput(); |
| message.input.setRequireVersion(new RequireVersion()); |
| message.input.getRequireVersion().version = version; |
| InterfaceControlMessagesHelper.sendRunOrClosePipeMessage( |
| getCore(), mMessageReceiver, message); |
| } |
| } |
| |
| /** |
| * The handler associated with this proxy. |
| */ |
| private final HandlerImpl mHandler; |
| |
| protected AbstractProxy(Core core, MessageReceiverWithResponder messageReceiver) { |
| mHandler = new HandlerImpl(core, messageReceiver); |
| } |
| |
| /** |
| * @see Interface#close() |
| */ |
| @Override |
| public void close() { |
| mHandler.close(); |
| } |
| |
| /** |
| * @see Proxy#getProxyHandler() |
| */ |
| @Override |
| public HandlerImpl getProxyHandler() { |
| return mHandler; |
| } |
| |
| /** |
| * @see ConnectionErrorHandler#onConnectionError(org.chromium.mojo.system.MojoException) |
| */ |
| @Override |
| public void onConnectionError(MojoException e) { |
| mHandler.onConnectionError(e); |
| } |
| } |
| |
| /** |
| * Base implementation of Stub. Stubs are message receivers that deserialize the payload and |
| * call the appropriate method in the implementation. If the method returns result, the stub |
| * serializes the response and sends it back. |
| * |
| * @param <I> the type of the interface to delegate calls to. |
| */ |
| abstract class Stub<I extends Interface> implements MessageReceiverWithResponder { |
| |
| /** |
| * The {@link Core} implementation to use. |
| */ |
| private final Core mCore; |
| |
| /** |
| * The implementation to delegate calls to. |
| */ |
| private final I mImpl; |
| |
| /** |
| * Constructor. |
| * |
| * @param core the {@link Core} implementation to use. |
| * @param impl the implementation to delegate calls to. |
| */ |
| public Stub(Core core, I impl) { |
| mCore = core; |
| mImpl = impl; |
| } |
| |
| /** |
| * Returns the Core implementation. |
| */ |
| protected Core getCore() { |
| return mCore; |
| } |
| |
| /** |
| * Returns the implementation to delegate calls to. |
| */ |
| protected I getImpl() { |
| return mImpl; |
| } |
| |
| /** |
| * @see org.chromium.mojo.bindings.MessageReceiver#close() |
| */ |
| @Override |
| public void close() { |
| mImpl.close(); |
| } |
| |
| } |
| |
| /** |
| * The |Manager| object enables building of proxies and stubs for a given interface. |
| * |
| * @param <I> the type of the interface the manager can handle. |
| * @param <P> the type of the proxy the manager can handle. To be noted, P always extends I. |
| */ |
| abstract class Manager<I extends Interface, P extends Proxy> { |
| |
| /** |
| * Returns the name of the interface. This is an opaque (but human readable) identifier used |
| * by the service provider to identify services. |
| */ |
| public abstract String getName(); |
| |
| /** |
| * Returns the version of the managed interface. |
| */ |
| public abstract int getVersion(); |
| |
| /** |
| * Binds the given implementation to the handle. |
| */ |
| public void bind(I impl, MessagePipeHandle handle) { |
| // The router (and by consequence the handle) is intentionally leaked. It will close |
| // itself when the connected handle is closed and the proxy receives the connection |
| // error. |
| Router router = new RouterImpl(handle); |
| bind(handle.getCore(), impl, router); |
| router.start(); |
| } |
| |
| /** |
| * Binds the given implementation to the InterfaceRequest. |
| */ |
| public final void bind(I impl, InterfaceRequest<I> request) { |
| bind(impl, request.passHandle()); |
| } |
| |
| /** |
| * Returns a Proxy that will send messages to the given |handle|. This implies that the |
| * other end of the handle must be bound to an implementation of the interface. |
| */ |
| public final P attachProxy(MessagePipeHandle handle, int version) { |
| RouterImpl router = new RouterImpl(handle); |
| P proxy = attachProxy(handle.getCore(), router); |
| DelegatingConnectionErrorHandler handlers = new DelegatingConnectionErrorHandler(); |
| handlers.addConnectionErrorHandler(proxy); |
| router.setErrorHandler(handlers); |
| router.start(); |
| ((HandlerImpl) proxy.getProxyHandler()).setVersion(version); |
| return proxy; |
| } |
| |
| /** |
| * Constructs a new |InterfaceRequest| for the interface. This method returns a Pair where |
| * the first element is a proxy, and the second element is the request. The proxy can be |
| * used immediately. |
| */ |
| public final Pair<P, InterfaceRequest<I>> getInterfaceRequest(Core core) { |
| Pair<MessagePipeHandle, MessagePipeHandle> handles = core.createMessagePipe(null); |
| P proxy = attachProxy(handles.first, 0); |
| return Pair.create(proxy, new InterfaceRequest<I>(handles.second)); |
| } |
| |
| public final InterfaceRequest<I> asInterfaceRequest(MessagePipeHandle handle) { |
| return new InterfaceRequest<I>(handle); |
| } |
| |
| /** |
| * Binds the implementation to the given |router|. |
| */ |
| final void bind(Core core, I impl, Router router) { |
| router.setErrorHandler(impl); |
| router.setIncomingMessageReceiver(buildStub(core, impl)); |
| } |
| |
| /** |
| * Returns a Proxy that will send messages to the given |router|. |
| */ |
| final P attachProxy(Core core, Router router) { |
| return buildProxy(core, new AutoCloseableRouter(core, router)); |
| } |
| |
| /** |
| * Creates a new array of the given |size|. |
| */ |
| protected abstract I[] buildArray(int size); |
| |
| /** |
| * Constructs a Stub delegating to the given implementation. |
| */ |
| protected abstract Stub<I> buildStub(Core core, I impl); |
| |
| /** |
| * Constructs a Proxy forwarding the calls to the given message receiver. |
| */ |
| protected abstract P buildProxy(Core core, MessageReceiverWithResponder messageReceiver); |
| |
| } |
| } |