Cherry-pick: [Android] Fix a subtle issue in Java Bridge regarding interfaces removal

Required for the main patch fixing b/18520475.

Bug: 18520475

Original description:

commit 4d4182c4af0a11a1ad5acae88f9abe2b76853fe1
Author: mnaganov <mnaganov@chromium.org>
Date: Mon Dec 01 11:59:14 2014

[Android] Fix a subtle issue in Java Bridge regarding interfaces removal

Update JavaBridgeBasicsTest.testRemovalNotReflectedUntilReload to actually
call Java GC after removing the interface, and verify that the Java object
is still callable from the page side. Fix the code to make the test pass.

BUG=437761

Review URL: https://codereview.chromium.org/767453003

Cr-Commit-Position: refs/heads/master@{#306176}

Change-Id: If12d53e3aad721e5822d8e12c85f1240e1aac5e6
diff --git a/content/browser/android/java/gin_java_bridge_dispatcher_host.cc b/content/browser/android/java/gin_java_bridge_dispatcher_host.cc
index ca63276..81f49c1 100644
--- a/content/browser/android/java/gin_java_bridge_dispatcher_host.cc
+++ b/content/browser/android/java/gin_java_bridge_dispatcher_host.cc
@@ -210,18 +210,10 @@
   named_objects_.erase(iter);
   object->RemoveName();
 
-  // Not erasing from the objects map, as we can still receive method
-  // invocation requests for this object, and they should work until the
-  // java object is gone.
-  if (!object->IsNamed()) {
-    JNIEnv* env = base::android::AttachCurrentThread();
-    base::android::ScopedJavaLocalRef<jobject> retained_object_set =
-        retained_object_set_.get(env);
-    if (!retained_object_set.is_null()) {
-      JNI_Java_HashSet_remove(
-          env, retained_object_set, object->GetLocalRef(env));
-    }
-  }
+  // As the object isn't going to be removed from the JavaScript side until the
+  // next page reload, calls to it must still work, thus we should continue to
+  // hold it. All the transient objects and removed named objects will be purged
+  // during the cleansing caused by DocumentAvailableInMainFrame event.
 
   web_contents()->SendToAllFrames(
       new GinJavaBridgeMsg_RemoveNamedObject(MSG_ROUTING_NONE, copied_name));
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeBasicsTest.java b/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeBasicsTest.java
index a2d5ad8..b19a6b2 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeBasicsTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeBasicsTest.java
@@ -172,15 +172,27 @@
     @SmallTest
     @Feature({"AndroidWebView", "Android-JavaBridge"})
     public void testRemovalNotReflectedUntilReload() throws Throwable {
-        injectObjectAndReload(new Object(), "testObject");
+        injectObjectAndReload(new Object() {
+            public void method() {
+                mTestController.setStringValue("I'm here");
+            }
+        }, "testObject");
         assertEquals("object", executeJavaScriptAndGetStringResult("typeof testObject"));
+        executeJavaScript("testObject.method()");
+        assertEquals("I'm here", mTestController.waitForStringValue());
         runTestOnUiThread(new Runnable() {
             @Override
             public void run() {
                 getContentViewCore().removeJavascriptInterface("testObject");
             }
         });
+        // Check that the Java object is being held by the Java bridge, thus it's not
+        // collected. Note that despite that what JavaDoc says about invoking "gc()", both Dalvik
+        // and ART actually run the collector if called via Runtime.
+        Runtime.getRuntime().gc();
         assertEquals("object", executeJavaScriptAndGetStringResult("typeof testObject"));
+        executeJavaScript("testObject.method()");
+        assertEquals("I'm here", mTestController.waitForStringValue());
         synchronousPageReload();
         assertEquals("undefined", executeJavaScriptAndGetStringResult("typeof testObject"));
     }