1116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// Copyright 2014 The Chromium Authors. All rights reserved.
2116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// Use of this source code is governed by a BSD-style license that can be
3116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// found in the LICENSE file.
4116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
5116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "content/browser/android/java/gin_java_bridge_dispatcher_host.h"
6116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
7116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "base/android/java_handler_thread.h"
8116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "base/android/jni_android.h"
9116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "base/android/scoped_java_ref.h"
10c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov#include "base/atomic_sequence_num.h"
11116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "base/lazy_instance.h"
12c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov#include "base/pickle.h"
13116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "base/strings/string_number_conversions.h"
14116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "base/strings/utf_string_conversions.h"
15116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "base/task_runner_util.h"
16116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "content/browser/android/java/gin_java_bound_object_delegate.h"
17116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "content/browser/android/java/jni_helper.h"
18116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "content/common/android/gin_java_bridge_value.h"
19116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "content/common/android/hash_set.h"
20116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "content/common/gin_java_bridge_messages.h"
21116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "content/public/browser/browser_thread.h"
22116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "content/public/browser/render_frame_host.h"
23c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov#include "content/public/browser/render_process_host.h"
24116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "content/public/browser/web_contents.h"
25116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "ipc/ipc_message_utils.h"
26116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
27116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#if !defined(OS_ANDROID)
28116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#error "JavaBridge only supports OS_ANDROID"
29116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#endif
30116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
31116680a4aac90f2aa7413d9095a592090648e557Ben Murdochnamespace content {
32116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
33116680a4aac90f2aa7413d9095a592090648e557Ben Murdochnamespace {
34116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// The JavaBridge needs to use a Java thread so the callback
35116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// will happen on a thread with a prepared Looper.
36116680a4aac90f2aa7413d9095a592090648e557Ben Murdochclass JavaBridgeThread : public base::android::JavaHandlerThread {
37116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch public:
38116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  JavaBridgeThread() : base::android::JavaHandlerThread("JavaBridge") {
39116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    Start();
40116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
41116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  virtual ~JavaBridgeThread() {
42116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    Stop();
43116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
44c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov  static bool CurrentlyOn();
45116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch};
46116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
47116680a4aac90f2aa7413d9095a592090648e557Ben Murdochbase::LazyInstance<JavaBridgeThread> g_background_thread =
48116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    LAZY_INSTANCE_INITIALIZER;
49116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
50c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov// static
51c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganovbool JavaBridgeThread::CurrentlyOn() {
52c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov  return base::MessageLoop::current() ==
53c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov         g_background_thread.Get().message_loop();
54c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov}
55c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov
56c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov// Object IDs are globally unique, so we can figure out the right
57c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov// GinJavaBridgeDispatcherHost when dispatching messages on the background
58c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov// thread.
59c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganovbase::StaticAtomicSequenceNumber g_next_object_id;
60c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov
61116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}  // namespace
62116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
63116680a4aac90f2aa7413d9095a592090648e557Ben MurdochGinJavaBridgeDispatcherHost::GinJavaBridgeDispatcherHost(
64116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    WebContents* web_contents,
65116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    jobject retained_object_set)
66116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    : WebContentsObserver(web_contents),
67c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov      BrowserMessageFilter(GinJavaBridgeMsgStart),
68c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov      browser_filter_added_(false),
69116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      retained_object_set_(base::android::AttachCurrentThread(),
70116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                           retained_object_set),
71c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov      allow_object_contents_inspection_(true),
72c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov      current_routing_id_(MSG_ROUTING_NONE) {
73116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  DCHECK(retained_object_set);
74116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
75116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
76116680a4aac90f2aa7413d9095a592090648e557Ben MurdochGinJavaBridgeDispatcherHost::~GinJavaBridgeDispatcherHost() {
77c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov}
78c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov
79c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov// GinJavaBridgeDispatcherHost gets created earlier than RenderProcessHost
80c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov// is initialized. So we postpone installing the message filter until we know
81c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov// that the RPH is in a good shape. Currently this means that we are calling
82c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov// this function from any UI thread function that is about to communicate
83c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov// with the renderer.
84c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov// TODO(mnaganov): Redesign, so we only have a single filter for all hosts.
85c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganovvoid GinJavaBridgeDispatcherHost::AddBrowserFilterIfNeeded() {
86c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov  DCHECK_CURRENTLY_ON(BrowserThread::UI);
87c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov  // Transient objects can only appear after named objects were added. Thus,
88c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov  // we can wait until we have one, to avoid installing unnecessary filters.
89c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov  if (!browser_filter_added_ &&
90c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov      web_contents()->GetRenderProcessHost()->GetChannel() &&
91c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov      !named_objects_.empty()) {
92c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov    web_contents()->GetRenderProcessHost()->AddFilter(this);
93c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov    browser_filter_added_ = true;
94c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov  }
95116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
96116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
97116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid GinJavaBridgeDispatcherHost::RenderFrameCreated(
98116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    RenderFrameHost* render_frame_host) {
99c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov  DCHECK_CURRENTLY_ON(BrowserThread::UI);
100c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov  AddBrowserFilterIfNeeded();
101116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  for (NamedObjectMap::const_iterator iter = named_objects_.begin();
102116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch       iter != named_objects_.end();
103116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch       ++iter) {
104116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    render_frame_host->Send(new GinJavaBridgeMsg_AddNamedObject(
105116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        render_frame_host->GetRoutingID(), iter->first, iter->second));
106116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
107116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
108116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
109116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid GinJavaBridgeDispatcherHost::RenderFrameDeleted(
110116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    RenderFrameHost* render_frame_host) {
1111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  DCHECK_CURRENTLY_ON(BrowserThread::UI);
112c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov  AddBrowserFilterIfNeeded();
113c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov  base::AutoLock locker(objects_lock_);
114c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov  auto iter = objects_.begin();
115c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov  while (iter != objects_.end()) {
116c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov    JavaObjectWeakGlobalRef ref =
117c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov        RemoveHolderAndAdvanceLocked(render_frame_host->GetRoutingID(), &iter);
118c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov    if (!ref.is_empty()) {
119c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov      RemoveFromRetainedObjectSetLocked(ref);
120c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov    }
1211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
122116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
123116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
124116680a4aac90f2aa7413d9095a592090648e557Ben MurdochGinJavaBoundObject::ObjectID GinJavaBridgeDispatcherHost::AddObject(
125116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    const base::android::JavaRef<jobject>& object,
126116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    const base::android::JavaRef<jclass>& safe_annotation_clazz,
127116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    bool is_named,
128c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov    int32 holder) {
129c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov  // Can be called on any thread. Calls come from the UI thread via
130c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov  // AddNamedObject, and from the background thread, when injected Java
131c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov  // object's method returns a Java object.
132116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  DCHECK(is_named || holder);
133116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  JNIEnv* env = base::android::AttachCurrentThread();
134116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  JavaObjectWeakGlobalRef ref(env, object.obj());
135c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov  scoped_refptr<GinJavaBoundObject> new_object =
136c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov      is_named ? GinJavaBoundObject::CreateNamed(ref, safe_annotation_clazz)
137c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov               : GinJavaBoundObject::CreateTransient(ref, safe_annotation_clazz,
138c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov                                                     holder);
139c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov  // Note that we are abusing the fact that StaticAtomicSequenceNumber
140c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov  // uses Atomic32 as a counter, so it is guaranteed that it will not
141c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov  // overflow our int32 IDs. IDs start from 1.
142c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov  GinJavaBoundObject::ObjectID object_id = g_next_object_id.GetNext() + 1;
143c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov  {
144c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov    base::AutoLock locker(objects_lock_);
145c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov    objects_[object_id] = new_object;
146116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
147116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#if DCHECK_IS_ON
148116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  {
149116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    GinJavaBoundObject::ObjectID added_object_id;
150116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    DCHECK(FindObjectId(object, &added_object_id));
151116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    DCHECK_EQ(object_id, added_object_id);
152116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
153116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#endif  // DCHECK_IS_ON
154116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  base::android::ScopedJavaLocalRef<jobject> retained_object_set =
155116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        retained_object_set_.get(env);
156116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (!retained_object_set.is_null()) {
157c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov    base::AutoLock locker(objects_lock_);
158116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    JNI_Java_HashSet_add(env, retained_object_set, object);
159116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
160116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  return object_id;
161116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
162116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
163116680a4aac90f2aa7413d9095a592090648e557Ben Murdochbool GinJavaBridgeDispatcherHost::FindObjectId(
164116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    const base::android::JavaRef<jobject>& object,
165116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    GinJavaBoundObject::ObjectID* object_id) {
166c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov  // Can be called on any thread.
167116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  JNIEnv* env = base::android::AttachCurrentThread();
168c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov  base::AutoLock locker(objects_lock_);
169c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov  for (const auto& pair : objects_) {
170116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    if (env->IsSameObject(
171116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch            object.obj(),
172c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov            pair.second->GetLocalRef(env).obj())) {
173c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov      *object_id = pair.first;
174116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      return true;
175116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    }
176116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
177116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  return false;
178116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
179116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
180116680a4aac90f2aa7413d9095a592090648e557Ben MurdochJavaObjectWeakGlobalRef GinJavaBridgeDispatcherHost::GetObjectWeakRef(
181116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    GinJavaBoundObject::ObjectID object_id) {
182c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov  scoped_refptr<GinJavaBoundObject> object = FindObject(object_id);
183116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (object.get())
184116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    return object->GetWeakRef();
185116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  else
186116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    return JavaObjectWeakGlobalRef();
187116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
188116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
189c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail NaganovJavaObjectWeakGlobalRef
190c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail NaganovGinJavaBridgeDispatcherHost::RemoveHolderAndAdvanceLocked(
191c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov    int32 holder,
192c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov    ObjectMap::iterator* iter_ptr) {
193c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov  objects_lock_.AssertAcquired();
194c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov  JavaObjectWeakGlobalRef result;
195c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov  scoped_refptr<GinJavaBoundObject> object((*iter_ptr)->second);
196c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov  if (!object->IsNamed()) {
197116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    object->RemoveHolder(holder);
198116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    if (!object->HasHolders()) {
199c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov      result = object->GetWeakRef();
200c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov      objects_.erase((*iter_ptr)++);
201116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    }
202c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov  } else {
203c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov    ++(*iter_ptr);
204c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov  }
205c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov  return result;
206c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov}
207c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov
208c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganovvoid GinJavaBridgeDispatcherHost::RemoveFromRetainedObjectSetLocked(
209c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov    const JavaObjectWeakGlobalRef& ref) {
210c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov  objects_lock_.AssertAcquired();
211c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov  JNIEnv* env = base::android::AttachCurrentThread();
212c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov  base::android::ScopedJavaLocalRef<jobject> retained_object_set =
213c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov      retained_object_set_.get(env);
214c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov  if (!retained_object_set.is_null()) {
215c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov    JNI_Java_HashSet_remove(env, retained_object_set, ref.get(env));
216116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
217116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
218116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
219116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid GinJavaBridgeDispatcherHost::AddNamedObject(
220116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    const std::string& name,
221116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    const base::android::JavaRef<jobject>& object,
222116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    const base::android::JavaRef<jclass>& safe_annotation_clazz) {
223116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  DCHECK_CURRENTLY_ON(BrowserThread::UI);
224116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  GinJavaBoundObject::ObjectID object_id;
225116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  NamedObjectMap::iterator iter = named_objects_.find(name);
226116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  bool existing_object = FindObjectId(object, &object_id);
227116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (existing_object && iter != named_objects_.end() &&
228116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      iter->second == object_id) {
229116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    // Nothing to do.
230116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    return;
231116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
232116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (iter != named_objects_.end()) {
233116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    RemoveNamedObject(iter->first);
234116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
235116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (existing_object) {
236c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov    base::AutoLock locker(objects_lock_);
237c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov    objects_[object_id]->AddName();
238116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  } else {
239c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov    object_id = AddObject(object, safe_annotation_clazz, true, 0);
240116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
241116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  named_objects_[name] = object_id;
242116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
243c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov  AddBrowserFilterIfNeeded();
244116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  web_contents()->SendToAllFrames(
245116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      new GinJavaBridgeMsg_AddNamedObject(MSG_ROUTING_NONE, name, object_id));
246116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
247116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
248116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid GinJavaBridgeDispatcherHost::RemoveNamedObject(
249116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    const std::string& name) {
250116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  DCHECK_CURRENTLY_ON(BrowserThread::UI);
251116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  NamedObjectMap::iterator iter = named_objects_.find(name);
252116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (iter == named_objects_.end())
253116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    return;
254116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
2556e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // |name| may come from |named_objects_|. Make a copy of name so that if
2566e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // |name| is from |named_objects_| it'll be valid after the remove below.
2576e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  const std::string copied_name(name);
2586e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
259c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov  {
260c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov    base::AutoLock locker(objects_lock_);
261c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov    objects_[iter->second]->RemoveName();
262c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov  }
263116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  named_objects_.erase(iter);
264116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
26583eff5096b2d7faaad5ebabc0a49f34aeb850acdMikhail Naganov  // As the object isn't going to be removed from the JavaScript side until the
26683eff5096b2d7faaad5ebabc0a49f34aeb850acdMikhail Naganov  // next page reload, calls to it must still work, thus we should continue to
26783eff5096b2d7faaad5ebabc0a49f34aeb850acdMikhail Naganov  // hold it. All the transient objects and removed named objects will be purged
26883eff5096b2d7faaad5ebabc0a49f34aeb850acdMikhail Naganov  // during the cleansing caused by DocumentAvailableInMainFrame event.
269116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
270116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  web_contents()->SendToAllFrames(
2716e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      new GinJavaBridgeMsg_RemoveNamedObject(MSG_ROUTING_NONE, copied_name));
272116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
273116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
274116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid GinJavaBridgeDispatcherHost::SetAllowObjectContentsInspection(bool allow) {
275c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov  if (!JavaBridgeThread::CurrentlyOn()) {
276c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov    g_background_thread.Get().message_loop()->task_runner()->PostTask(
277c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov        FROM_HERE,
278c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov        base::Bind(
279c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov            &GinJavaBridgeDispatcherHost::SetAllowObjectContentsInspection,
280c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov            this, allow));
281c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov    return;
282c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov  }
283116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  allow_object_contents_inspection_ = allow;
284116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
285116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
286116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid GinJavaBridgeDispatcherHost::DocumentAvailableInMainFrame() {
287116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  DCHECK_CURRENTLY_ON(BrowserThread::UI);
288116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // Called when the window object has been cleared in the main frame.
289116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // That means, all sub-frames have also been cleared, so only named
290116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // objects survived.
291c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov  AddBrowserFilterIfNeeded();
292116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  JNIEnv* env = base::android::AttachCurrentThread();
293116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  base::android::ScopedJavaLocalRef<jobject> retained_object_set =
294116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      retained_object_set_.get(env);
295c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov  base::AutoLock locker(objects_lock_);
296116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (!retained_object_set.is_null()) {
297116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    JNI_Java_HashSet_clear(env, retained_object_set);
298116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
299c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov  auto iter = objects_.begin();
300c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov  while (iter != objects_.end()) {
301c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov    if (iter->second->IsNamed()) {
302116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      if (!retained_object_set.is_null()) {
303116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        JNI_Java_HashSet_add(
304c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov            env, retained_object_set, iter->second->GetLocalRef(env));
305116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      }
306c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov      ++iter;
307116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    } else {
308c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov      objects_.erase(iter++);
309116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    }
310116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
311116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
312116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
313c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganovbase::TaskRunner* GinJavaBridgeDispatcherHost::OverrideTaskRunnerForMessage(
314c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov    const IPC::Message& message) {
315c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov  GinJavaBoundObject::ObjectID object_id = 0;
316c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov  // TODO(mnaganov): It's very sad that we have a BrowserMessageFilter per
317c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov  // WebView instance. We should redesign to have a filter per RPH.
318c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov  // Check, if the object ID in the message is known to this host. If not,
319c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov  // this is a message for some other host. As all our IPC messages from the
320c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov  // renderer start with object ID, we just fetch it directly from the
321c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov  // message, considering sync and async messages separately.
322c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov  switch (message.type()) {
323c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov    case GinJavaBridgeHostMsg_GetMethods::ID:
324c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov    case GinJavaBridgeHostMsg_HasMethod::ID:
325c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov    case GinJavaBridgeHostMsg_InvokeMethod::ID: {
326c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov      DCHECK(message.is_sync());
327c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov      PickleIterator message_reader =
328c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov          IPC::SyncMessage::GetDataIterator(&message);
329c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov      if (!IPC::ReadParam(&message, &message_reader, &object_id))
330c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov        return NULL;
331c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov      break;
332c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov    }
333c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov    case GinJavaBridgeHostMsg_ObjectWrapperDeleted::ID: {
334c64ad5c2e063cde757eba7f9499a8e748b57cbdcMikhail Naganov      DCHECK(!message.is_sync());
335