1 From 225f21f660b943ff9ade13b0d114e8ba3b3036d5 Mon Sep 17 00:00:00 2001 2 From: Luis Hector Chavez <lhchavez (a] google.com> 3 Date: Fri, 20 Jul 2018 09:39:22 -0700 4 Subject: [PATCH] Mojo: Add a way to create thread-safe interfaces in Java 5 6 This change adds Interface.Manager.buildThreadSafeProxy(), which is 7 roughly analogous to mojo::ThreadSafeInterfacePtr<T>. Given that Java 8 does not have move-only semantics, the Proxy object that is passed is 9 unbound and a new object is returned. 10 11 Bug: 810084 12 Test: cheets_ContainerSmokeTest in Chrome OS 13 Change-Id: I6565f9e526e3fa8f8cb222cb8cd11e95bb57f7d3 14 Reviewed-on: https://chromium-review.googlesource.com/1147320 15 Reviewed-by: Ken Rockot <rockot (a] chromium.org> 16 Commit-Queue: Luis Hector Chavez <lhchavez (a] chromium.org> 17 Cr-Commit-Position: refs/heads/master@{#577429} 18 --- 19 .../org/chromium/mojo/bindings/Interface.java | 88 +++++++++++++++++++ 20 1 file changed, 88 insertions(+) 21 22 diff --git a/mojo/public/java/bindings/src/org/chromium/mojo/bindings/Interface.java b/mojo/public/java/bindings/src/org/chromium/mojo/bindings/Interface.java 23 index e3be8b3..f7d3f80 100644 24 --- a/mojo/public/java/bindings/src/org/chromium/mojo/bindings/Interface.java 25 +++ b/mojo/public/java/bindings/src/org/chromium/mojo/bindings/Interface.java 26 @@ -20,6 +20,7 @@ import org.chromium.mojo.system.MojoException; 27 import org.chromium.mojo.system.Pair; 28 29 import java.io.Closeable; 30 +import java.util.concurrent.Executor; 31 32 /** 33 * Base class for mojo generated interfaces. 34 @@ -317,6 +318,67 @@ public interface Interface extends ConnectionErrorHandler, Closeable { 35 36 } 37 38 + /** 39 + * A {@link MessageReceiverWithResponder} implementation that forwards all calls to the thread 40 + * the ThreadSafeForwarder was created. 41 + */ 42 + class ThreadSafeForwarder implements MessageReceiverWithResponder { 43 + 44 + /** 45 + * The {@link MessageReceiverWithResponder} that will receive a serialized message for 46 + * each method call. 47 + */ 48 + private final MessageReceiverWithResponder mMessageReceiver; 49 + 50 + /** 51 + * The {@link Executor} to forward all tasks to. 52 + */ 53 + private final Executor mExecutor; 54 + 55 + /** 56 + * Constructor. 57 + * 58 + * @param core the Core implementation used to create pipes and access the async waiter. 59 + * @param messageReceiver the message receiver to send message to. 60 + */ 61 + public ThreadSafeForwarder(Core core, MessageReceiverWithResponder messageReceiver) { 62 + mMessageReceiver = messageReceiver; 63 + mExecutor = ExecutorFactory.getExecutorForCurrentThread(core); 64 + } 65 + 66 + /** 67 + * @see org.chromium.mojo.bindings.MessageReceiver#close() 68 + */ 69 + @Override 70 + public void close() { 71 + mExecutor.execute(() -> { 72 + mMessageReceiver.close(); 73 + }); 74 + } 75 + 76 + /** 77 + * @see org.chromium.mojo.bindings.MessageReceiver#accept() 78 + */ 79 + @Override 80 + public boolean accept(Message message) { 81 + mExecutor.execute(() -> { 82 + mMessageReceiver.accept(message); 83 + }); 84 + return true; 85 + } 86 + 87 + /** 88 + * @see org.chromium.mojo.bindings.MessageReceiverWithResponder#acceptWithResponder() 89 + */ 90 + @Override 91 + public boolean acceptWithResponder(Message message, MessageReceiver responder) { 92 + mExecutor.execute(() -> { 93 + mMessageReceiver.acceptWithResponder(message, responder); 94 + }); 95 + return true; 96 + } 97 + } 98 + 99 /** 100 * The |Manager| object enables building of proxies and stubs for a given interface. 101 * 102 @@ -385,6 +447,32 @@ public interface Interface extends ConnectionErrorHandler, Closeable { 103 return new InterfaceRequest<I>(handle); 104 } 105 106 + /** 107 + * Constructs a thread-safe Proxy forwarding the calls to the given message receiver. 108 + * All calls can be performed from any thread and are posted to the {@link Executor} that 109 + * is associated with the thread on which this method was called on. 110 + * 111 + * The original Proxy object is unbound. 112 + */ 113 + public final P buildThreadSafeProxy(P proxy) { 114 + HandlerImpl handlerImpl = (HandlerImpl) proxy.getProxyHandler(); 115 + Core core = handlerImpl.getCore(); 116 + int version = handlerImpl.getVersion(); 117 + 118 + Router router = new RouterImpl(handlerImpl.passHandle()); 119 + // Close the original proxy now that its handle has been passed. 120 + proxy.close(); 121 + 122 + proxy = buildProxy( 123 + core, new ThreadSafeForwarder(core, new AutoCloseableRouter(core, router))); 124 + DelegatingConnectionErrorHandler handlers = new DelegatingConnectionErrorHandler(); 125 + handlers.addConnectionErrorHandler(proxy); 126 + router.setErrorHandler(handlers); 127 + router.start(); 128 + ((HandlerImpl) proxy.getProxyHandler()).setVersion(version); 129 + return proxy; 130 + } 131 + 132 /** 133 * Binds the implementation to the given |router|. 134 */ 135 -- 136 2.19.0.605.g01d371f741-goog 137 138