Add global and per-WebContents java InterfaceRegistries.

BUG=634568, 637174

Review-Url: https://codereview.chromium.org/2217813003
Cr-Commit-Position: refs/heads/master@{#419886}
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn
index 9c35476..4984e4d6 100644
--- a/content/browser/BUILD.gn
+++ b/content/browser/BUILD.gn
@@ -203,6 +203,8 @@
     "android/interface_provider_android_impl.h",
     "android/interface_registry_android_impl.cc",
     "android/interface_registry_android_impl.h",
+    "android/java_interfaces_impl.cc",
+    "android/java_interfaces_impl.h",
     "android/url_request_content_job.cc",
     "android/url_request_content_job.h",
     "appcache/appcache.cc",
diff --git a/content/browser/android/java_interfaces_impl.cc b/content/browser/android/java_interfaces_impl.cc
new file mode 100644
index 0000000..df2d8d6
--- /dev/null
+++ b/content/browser/android/java_interfaces_impl.cc
@@ -0,0 +1,61 @@
+// Copyright 2016 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.
+
+#include "content/browser/android/java_interfaces_impl.h"
+
+#include <jni.h>
+
+#include <utility>
+
+#include "base/android/context_utils.h"
+#include "base/android/jni_android.h"
+#include "base/memory/singleton.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/web_contents.h"
+#include "jni/InterfaceRegistrarImpl_jni.h"
+#include "mojo/public/cpp/system/message_pipe.h"
+#include "services/shell/public/cpp/interface_provider.h"
+
+namespace content {
+
+namespace {
+
+class JavaInterfaceProviderHolder {
+ public:
+  JavaInterfaceProviderHolder() {
+    shell::mojom::InterfaceProviderPtr provider;
+    JNIEnv* env = base::android::AttachCurrentThread();
+    Java_InterfaceRegistrarImpl_createInterfaceRegistryForContext(
+        env, mojo::GetProxy(&provider).PassMessagePipe().release().value(),
+        base::android::GetApplicationContext());
+    interface_provider_.Bind(std::move(provider));
+  }
+
+  static JavaInterfaceProviderHolder* GetInstance() {
+    DCHECK_CURRENTLY_ON(BrowserThread::UI);
+    return base::Singleton<JavaInterfaceProviderHolder>::get();
+  }
+
+  shell::InterfaceProvider* GetJavaInterfaces() { return &interface_provider_; }
+
+ private:
+  shell::InterfaceProvider interface_provider_;
+};
+
+}  // namespace
+
+shell::InterfaceProvider* GetGlobalJavaInterfaces() {
+  return JavaInterfaceProviderHolder::GetInstance()->GetJavaInterfaces();
+}
+
+void BindInterfaceRegistryForWebContents(
+    shell::mojom::InterfaceProviderRequest request,
+    WebContents* web_contents) {
+  JNIEnv* env = base::android::AttachCurrentThread();
+  Java_InterfaceRegistrarImpl_createInterfaceRegistryForWebContents(
+      env, request.PassMessagePipe().release().value(),
+      web_contents->GetJavaWebContents().obj());
+}
+
+}  // namespace content
diff --git a/content/browser/android/java_interfaces_impl.h b/content/browser/android/java_interfaces_impl.h
new file mode 100644
index 0000000..e49ddcd
--- /dev/null
+++ b/content/browser/android/java_interfaces_impl.h
@@ -0,0 +1,20 @@
+// Copyright 2016 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.
+
+#ifndef CONTENT_BROWSER_ANDROID_JAVA_INTERFACES_IMPL_H_
+#define CONTENT_BROWSER_ANDROID_JAVA_INTERFACES_IMPL_H_
+
+#include "content/public/browser/android/java_interfaces.h"
+#include "services/shell/public/interfaces/interface_provider.mojom.h"
+
+namespace content {
+class WebContents;
+
+void BindInterfaceRegistryForWebContents(
+    shell::mojom::InterfaceProviderRequest request,
+    WebContents* web_contents);
+
+}  // namespace content
+
+#endif  // CONTENT_BROWSER_ANDROID_JAVA_INTERFACES_IMPL_H_
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index 4d9458af..10187d1 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -123,6 +123,7 @@
 #include "net/http/http_transaction_factory.h"
 #include "net/url_request/url_request_context.h"
 #include "net/url_request/url_request_context_getter.h"
+#include "services/shell/public/cpp/interface_provider.h"
 #include "third_party/WebKit/public/web/WebSandboxFlags.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "ui/accessibility/ax_tree_combiner.h"
@@ -133,6 +134,7 @@
 #if defined(OS_ANDROID)
 #include "content/browser/android/content_video_view.h"
 #include "content/browser/android/date_time_chooser_android.h"
+#include "content/browser/android/java_interfaces_impl.h"
 #include "content/browser/media/android/media_web_contents_observer_android.h"
 #include "content/browser/web_contents/web_contents_android.h"
 #endif  // OS_ANDROID
@@ -4979,6 +4981,16 @@
       frame_tree_.root()->current_replication_state());
 }
 
+shell::InterfaceProvider* WebContentsImpl::GetJavaInterfaces() {
+  if (!java_interfaces_) {
+    shell::mojom::InterfaceProviderPtr provider;
+    BindInterfaceRegistryForWebContents(mojo::GetProxy(&provider), this);
+    java_interfaces_.reset(new shell::InterfaceProvider);
+    java_interfaces_->Bind(std::move(provider));
+  }
+  return java_interfaces_.get();
+}
+
 #elif defined(OS_MACOSX)
 
 void WebContentsImpl::SetAllowOtherViews(bool allow) {
diff --git a/content/browser/web_contents/web_contents_impl.h b/content/browser/web_contents/web_contents_impl.h
index e4b786f..935dc7d 100644
--- a/content/browser/web_contents/web_contents_impl.h
+++ b/content/browser/web_contents/web_contents_impl.h
@@ -51,6 +51,10 @@
 
 struct ViewHostMsg_DateTimeDialogValue_Params;
 
+namespace shell {
+class InterfaceProvider;
+}
+
 namespace content {
 class BrowserPluginEmbedder;
 class BrowserPluginGuest;
@@ -415,6 +419,7 @@
   virtual WebContentsAndroid* GetWebContentsAndroid();
   void ActivateNearestFindResult(float x, float y) override;
   void RequestFindMatchRects(int current_version) override;
+  shell::InterfaceProvider* GetJavaInterfaces() override;
 #elif defined(OS_MACOSX)
   void SetAllowOtherViews(bool allow) override;
   bool GetAllowOtherViews() override;
@@ -1448,6 +1453,10 @@
   // there's no RenderWidgetHost holding a lock.
   RenderWidgetHostImpl* mouse_lock_widget_;
 
+#if defined(OS_ANDROID)
+  std::unique_ptr<shell::InterfaceProvider> java_interfaces_;
+#endif
+
   base::WeakPtrFactory<WebContentsImpl> loading_weak_factory_;
   base::WeakPtrFactory<WebContentsImpl> weak_factory_;
 
diff --git a/content/public/android/BUILD.gn b/content/public/android/BUILD.gn
index ea07710..b8bf208 100644
--- a/content/public/android/BUILD.gn
+++ b/content/public/android/BUILD.gn
@@ -46,6 +46,8 @@
     "//mojo/public/java:bindings",
     "//mojo/public/java:system",
     "//net/android:net_java",
+    "//services/shell/public/interfaces:interfaces_java",
+    "//services/shell/public/java:shell_java",
     "//third_party/WebKit/public:blink_headers_java",
     "//third_party/android_tools:android_support_annotations_java",
     "//third_party/jsr-305:jsr_305_javalib",
@@ -121,6 +123,7 @@
     "java/src/org/chromium/content/browser/FloatingWebActionModeCallback.java",
     "java/src/org/chromium/content/browser/InterfaceProvider.java",
     "java/src/org/chromium/content/browser/InterfaceRegistrar.java",
+    "java/src/org/chromium/content/browser/InterfaceRegistrarImpl.java",
     "java/src/org/chromium/content/browser/InterfaceRegistry.java",
     "java/src/org/chromium/content/browser/InterstitialPageDelegateAndroid.java",
     "java/src/org/chromium/content/browser/JavascriptInterface.java",
@@ -193,6 +196,7 @@
     "java/src/org/chromium/content_public/browser/ContentBitmapCallback.java",
     "java/src/org/chromium/content_public/browser/GestureStateListener.java",
     "java/src/org/chromium/content_public/browser/ImageDownloadCallback.java",
+    "java/src/org/chromium/content_public/browser/InterfaceRegistrar.java",
     "java/src/org/chromium/content_public/browser/JavaScriptCallback.java",
     "java/src/org/chromium/content_public/browser/LoadUrlParams.java",
     "java/src/org/chromium/content_public/browser/NavigationController.java",
@@ -298,6 +302,7 @@
     "java/src/org/chromium/content/browser/DeviceSensors.java",
     "java/src/org/chromium/content/browser/InterfaceProvider.java",
     "java/src/org/chromium/content/browser/InterfaceRegistrar.java",
+    "java/src/org/chromium/content/browser/InterfaceRegistrarImpl.java",
     "java/src/org/chromium/content/browser/InterfaceRegistry.java",
     "java/src/org/chromium/content/browser/InterstitialPageDelegateAndroid.java",
     "java/src/org/chromium/content/browser/MediaResourceGetter.java",
diff --git a/content/public/android/java/src/org/chromium/content/browser/InterfaceRegistrarImpl.java b/content/public/android/java/src/org/chromium/content/browser/InterfaceRegistrarImpl.java
new file mode 100644
index 0000000..b1d920a
--- /dev/null
+++ b/content/public/android/java/src/org/chromium/content/browser/InterfaceRegistrarImpl.java
@@ -0,0 +1,31 @@
+// Copyright 2016 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.content.browser;
+
+import android.content.Context;
+
+import org.chromium.base.annotations.CalledByNative;
+import org.chromium.base.annotations.JNINamespace;
+import org.chromium.content_public.browser.InterfaceRegistrar;
+import org.chromium.content_public.browser.WebContents;
+import org.chromium.mojo.system.impl.CoreImpl;
+import org.chromium.services.shell.InterfaceRegistry;
+
+@JNINamespace("content")
+class InterfaceRegistrarImpl {
+    @CalledByNative
+    static void createInterfaceRegistryForContext(int nativeHandle, Context applicationContext) {
+        InterfaceRegistry registry = InterfaceRegistry.create(
+                CoreImpl.getInstance().acquireNativeHandle(nativeHandle).toMessagePipeHandle());
+        InterfaceRegistrar.Registry.applyContextRegistrars(registry, applicationContext);
+    }
+
+    @CalledByNative
+    static void createInterfaceRegistryForWebContents(int nativeHandle, WebContents webContents) {
+        InterfaceRegistry registry = InterfaceRegistry.create(
+                CoreImpl.getInstance().acquireNativeHandle(nativeHandle).toMessagePipeHandle());
+        InterfaceRegistrar.Registry.applyWebContentsRegistrars(registry, webContents);
+    }
+}
diff --git a/content/public/android/java/src/org/chromium/content_public/browser/InterfaceRegistrar.java b/content/public/android/java/src/org/chromium/content_public/browser/InterfaceRegistrar.java
new file mode 100644
index 0000000..e76061d
--- /dev/null
+++ b/content/public/android/java/src/org/chromium/content_public/browser/InterfaceRegistrar.java
@@ -0,0 +1,74 @@
+// Copyright 2016 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.content_public.browser;
+
+import android.content.Context;
+
+import org.chromium.services.shell.InterfaceRegistry;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A registrar for mojo interface implementations to provide to an InterfaceRegistry.
+ *
+ * @param <ParamType> the type of parameter to pass to the InterfaceRegistrar when adding its
+ *     interfaces to an InterfaceRegistry
+ */
+public interface InterfaceRegistrar<ParamType> {
+    /** Invoked to register interfaces on |registry|, parametrized by |paramValue|. */
+    public void registerInterfaces(InterfaceRegistry registry, ParamType paramValue);
+
+    /** A registry of InterfaceRegistrars. */
+    public static class Registry<ParamType> {
+        private static Registry<Context> sContextRegistry = null;
+        private static Registry<WebContents> sWebContentsRegistry = null;
+
+        private List<InterfaceRegistrar<ParamType>> mRegistrars =
+                new ArrayList<InterfaceRegistrar<ParamType>>();
+
+        public static void applyContextRegistrars(
+                InterfaceRegistry interfaceRegistry, Context context) {
+            if (sContextRegistry == null) {
+                return;
+            }
+            sContextRegistry.applyRegistrars(interfaceRegistry, context);
+        }
+
+        public static void applyWebContentsRegistrars(
+                InterfaceRegistry interfaceRegistry, WebContents webContents) {
+            if (sWebContentsRegistry == null) {
+                return;
+            }
+            sWebContentsRegistry.applyRegistrars(interfaceRegistry, webContents);
+        }
+
+        public static void addContextRegistrar(InterfaceRegistrar<Context> registrar) {
+            if (sContextRegistry == null) {
+                sContextRegistry = new Registry<Context>();
+            }
+            sContextRegistry.addRegistrar(registrar);
+        }
+
+        public static void addWebContentsRegistrar(InterfaceRegistrar<WebContents> registrar) {
+            if (sWebContentsRegistry == null) {
+                sWebContentsRegistry = new Registry<WebContents>();
+            }
+            sWebContentsRegistry.addRegistrar(registrar);
+        }
+
+        private Registry() {}
+
+        private void addRegistrar(InterfaceRegistrar<ParamType> registrar) {
+            mRegistrars.add(registrar);
+        }
+
+        private void applyRegistrars(InterfaceRegistry interfaceRegistry, ParamType param) {
+            for (InterfaceRegistrar<ParamType> registrar : mRegistrars) {
+                registrar.registerInterfaces(interfaceRegistry, param);
+            }
+        }
+    }
+}
diff --git a/content/public/browser/BUILD.gn b/content/public/browser/BUILD.gn
index ef23893..1041c8c4 100644
--- a/content/public/browser/BUILD.gn
+++ b/content/public/browser/BUILD.gn
@@ -33,6 +33,7 @@
     "android/external_video_surface_container.h",
     "android/interface_provider_android.h",
     "android/interface_registry_android.h",
+    "android/java_interfaces.h",
     "android/synchronous_compositor.cc",
     "android/synchronous_compositor.h",
     "android/synchronous_compositor_client.h",
diff --git a/content/public/browser/android/java_interfaces.h b/content/public/browser/android/java_interfaces.h
new file mode 100644
index 0000000..aa4973d3
--- /dev/null
+++ b/content/public/browser/android/java_interfaces.h
@@ -0,0 +1,24 @@
+// Copyright 2016 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.
+
+#ifndef CONTENT_PUBLIC_BROWSER_ANDROID_JAVA_INTERFACES_H_
+#define CONTENT_PUBLIC_BROWSER_ANDROID_JAVA_INTERFACES_H_
+
+#include "content/common/content_export.h"
+
+namespace shell {
+class InterfaceProvider;
+}
+
+namespace content {
+
+// Returns an InterfaceProvider for global Java-implemented interfaces.
+// This provides access to interfaces implemented in Java in the browser process
+// to C++ code in the browser process. This and the returned InterfaceProvider
+// may only be used on the UI thread.
+CONTENT_EXPORT shell::InterfaceProvider* GetGlobalJavaInterfaces();
+
+}  // namespace content
+
+#endif  // CONTENT_PUBLIC_BROWSER_ANDROID_JAVA_INTERFACES_H_
diff --git a/content/public/browser/web_contents.h b/content/public/browser/web_contents.h
index 163a2ad..37b3bf2 100644
--- a/content/public/browser/web_contents.h
+++ b/content/public/browser/web_contents.h
@@ -46,6 +46,10 @@
 struct LoadStateWithParam;
 }
 
+namespace shell {
+class InterfaceProvider;
+}
+
 namespace content {
 
 class BrowserContext;
@@ -727,6 +731,11 @@
   // TODO(paulmeyer): This process will change slightly once multi-process
   // find-in-page is implemented. This comment should be updated at that time.
   virtual void RequestFindMatchRects(int current_version) = 0;
+
+  // Returns an InterfaceProvider for Java-implemented interfaces that are
+  // scoped to this WebContents. This provides access to interfaces implemented
+  // in Java in the browser process to C++ code in the browser process.
+  virtual shell::InterfaceProvider* GetJavaInterfaces() = 0;
 #elif defined(OS_MACOSX)
   // Allowing other views disables optimizations which assume that only a single
   // WebContents is present.