Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(69)

Side by Side Diff: content/browser/android/java/gin_java_bridge_dispatcher_host.cc

Issue 772123002: [Android] Java Bridge: handle requests from Java Script on the background thread (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fixed remaining crashes, added 2 WebViews test, made it pass Created 6 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "content/browser/android/java/gin_java_bridge_dispatcher_host.h" 5 #include "content/browser/android/java/gin_java_bridge_dispatcher_host.h"
6 6
7 #include "base/android/java_handler_thread.h" 7 #include "base/android/java_handler_thread.h"
8 #include "base/android/jni_android.h" 8 #include "base/android/jni_android.h"
9 #include "base/android/scoped_java_ref.h" 9 #include "base/android/scoped_java_ref.h"
10 #include "base/atomic_sequence_num.h"
10 #include "base/lazy_instance.h" 11 #include "base/lazy_instance.h"
12 #include "base/pickle.h"
11 #include "base/strings/string_number_conversions.h" 13 #include "base/strings/string_number_conversions.h"
12 #include "base/strings/utf_string_conversions.h" 14 #include "base/strings/utf_string_conversions.h"
13 #include "base/task_runner_util.h" 15 #include "base/task_runner_util.h"
14 #include "content/browser/android/java/gin_java_bound_object_delegate.h" 16 #include "content/browser/android/java/gin_java_bound_object_delegate.h"
15 #include "content/browser/android/java/jni_helper.h" 17 #include "content/browser/android/java/jni_helper.h"
16 #include "content/common/android/gin_java_bridge_value.h" 18 #include "content/common/android/gin_java_bridge_value.h"
17 #include "content/common/android/hash_set.h" 19 #include "content/common/android/hash_set.h"
18 #include "content/common/gin_java_bridge_messages.h" 20 #include "content/common/gin_java_bridge_messages.h"
19 #include "content/public/browser/browser_thread.h" 21 #include "content/public/browser/browser_thread.h"
22 #include "content/public/browser/notification_service.h"
23 #include "content/public/browser/notification_types.h"
20 #include "content/public/browser/render_frame_host.h" 24 #include "content/public/browser/render_frame_host.h"
25 #include "content/public/browser/render_process_host.h"
21 #include "content/public/browser/web_contents.h" 26 #include "content/public/browser/web_contents.h"
22 #include "ipc/ipc_message_utils.h" 27 #include "ipc/ipc_message_utils.h"
23 28
24 #if !defined(OS_ANDROID) 29 #if !defined(OS_ANDROID)
25 #error "JavaBridge only supports OS_ANDROID" 30 #error "JavaBridge only supports OS_ANDROID"
26 #endif 31 #endif
27 32
28 namespace content { 33 namespace content {
29 34
30 namespace { 35 namespace {
31 // The JavaBridge needs to use a Java thread so the callback 36 // The JavaBridge needs to use a Java thread so the callback
32 // will happen on a thread with a prepared Looper. 37 // will happen on a thread with a prepared Looper.
33 class JavaBridgeThread : public base::android::JavaHandlerThread { 38 class JavaBridgeThread : public base::android::JavaHandlerThread {
34 public: 39 public:
35 JavaBridgeThread() : base::android::JavaHandlerThread("JavaBridge") { 40 JavaBridgeThread() : base::android::JavaHandlerThread("JavaBridge") {
36 Start(); 41 Start();
37 } 42 }
38 virtual ~JavaBridgeThread() { 43 virtual ~JavaBridgeThread() {
39 Stop(); 44 Stop();
40 } 45 }
46 static bool CurrentlyOn();
41 }; 47 };
42 48
43 base::LazyInstance<JavaBridgeThread> g_background_thread = 49 base::LazyInstance<JavaBridgeThread> g_background_thread =
44 LAZY_INSTANCE_INITIALIZER; 50 LAZY_INSTANCE_INITIALIZER;
45 51
52 // static
53 bool JavaBridgeThread::CurrentlyOn() {
54 return base::MessageLoop::current() ==
55 g_background_thread.Get().message_loop();
56 }
57
58 // Object IDs are globally unique, so we can figure out the right
59 // GinJavaBridgeDispatcherHost when dispatching messages on the background
60 // thread.
61 base::StaticAtomicSequenceNumber g_next_object_id;
62
46 } // namespace 63 } // namespace
47 64
48 GinJavaBridgeDispatcherHost::GinJavaBridgeDispatcherHost( 65 GinJavaBridgeDispatcherHost::GinJavaBridgeDispatcherHost(
49 WebContents* web_contents, 66 WebContents* web_contents,
50 jobject retained_object_set) 67 jobject retained_object_set)
51 : WebContentsObserver(web_contents), 68 : WebContentsObserver(web_contents),
69 BrowserMessageFilter(GinJavaBridgeMsgStart),
52 retained_object_set_(base::android::AttachCurrentThread(), 70 retained_object_set_(base::android::AttachCurrentThread(),
53 retained_object_set), 71 retained_object_set),
54 allow_object_contents_inspection_(true) { 72 allow_object_contents_inspection_(true),
73 current_routing_id_(MSG_ROUTING_NONE) {
55 DCHECK(retained_object_set); 74 DCHECK(retained_object_set);
75 // GinJavaBridgeDispatcherHost gets created earlier than RenderProcessHost
76 // is initalized. So we postpone installing the message filter until we know
77 // that RPH is in a good shape.
78 notifications_registrar_.Add(
79 this, content::NOTIFICATION_RENDERER_PROCESS_CREATED,
80 content::NotificationService::AllBrowserContextsAndSources());
56 } 81 }
57 82
58 GinJavaBridgeDispatcherHost::~GinJavaBridgeDispatcherHost() { 83 GinJavaBridgeDispatcherHost::~GinJavaBridgeDispatcherHost() {
59 DCHECK(pending_replies_.empty()); 84 }
85
86 void GinJavaBridgeDispatcherHost::Observe(
87 int type,
88 const content::NotificationSource& source,
89 const content::NotificationDetails& details) {
90 switch (type) {
91 case content::NOTIFICATION_RENDERER_PROCESS_CREATED:
92 if (Source<content::RenderProcessHost>(source)->GetID() ==
93 web_contents()->GetRenderProcessHost()->GetID()) {
94 web_contents()->GetRenderProcessHost()->AddFilter(this);
95 // We only need to add the filter once.
96 notifications_registrar_.RemoveAll();
97 }
98 break;
99 default:
100 NOTREACHED();
101 break;
102 }
60 } 103 }
61 104
62 void GinJavaBridgeDispatcherHost::RenderFrameCreated( 105 void GinJavaBridgeDispatcherHost::RenderFrameCreated(
63 RenderFrameHost* render_frame_host) { 106 RenderFrameHost* render_frame_host) {
107 DCHECK_CURRENTLY_ON(BrowserThread::UI);
64 for (NamedObjectMap::const_iterator iter = named_objects_.begin(); 108 for (NamedObjectMap::const_iterator iter = named_objects_.begin();
65 iter != named_objects_.end(); 109 iter != named_objects_.end();
66 ++iter) { 110 ++iter) {
67 render_frame_host->Send(new GinJavaBridgeMsg_AddNamedObject( 111 render_frame_host->Send(new GinJavaBridgeMsg_AddNamedObject(
68 render_frame_host->GetRoutingID(), iter->first, iter->second)); 112 render_frame_host->GetRoutingID(), iter->first, iter->second));
69 } 113 }
70 } 114 }
71 115
72 void GinJavaBridgeDispatcherHost::RenderFrameDeleted( 116 void GinJavaBridgeDispatcherHost::RenderFrameDeleted(
73 RenderFrameHost* render_frame_host) { 117 RenderFrameHost* render_frame_host) {
74 DCHECK_CURRENTLY_ON(BrowserThread::UI); 118 DCHECK_CURRENTLY_ON(BrowserThread::UI);
75 IPC::Message* reply_msg = TakePendingReply(render_frame_host); 119 base::AutoLock locker(objects_lock_);
76 if (reply_msg != NULL) { 120 auto iter = objects_.begin();
77 base::ListValue result; 121 while (iter != objects_.end()) {
78 result.Append(base::Value::CreateNullValue()); 122 JavaObjectWeakGlobalRef ref =
79 IPC::WriteParam(reply_msg, result); 123 RemoveHolderAndAdvanceLocked(render_frame_host->GetRoutingID(), &iter);
80 IPC::WriteParam(reply_msg, kGinJavaBridgeRenderFrameDeleted); 124 if (!ref.is_empty()) {
81 render_frame_host->Send(reply_msg); 125 RemoveFromRetainedObjectSetLocked(ref);
126 }
82 } 127 }
83 RemoveHolder(render_frame_host,
84 GinJavaBoundObject::ObjectMap::iterator(&objects_),
85 objects_.size());
86 } 128 }
87 129
88 GinJavaBoundObject::ObjectID GinJavaBridgeDispatcherHost::AddObject( 130 GinJavaBoundObject::ObjectID GinJavaBridgeDispatcherHost::AddObject(
89 const base::android::JavaRef<jobject>& object, 131 const base::android::JavaRef<jobject>& object,
90 const base::android::JavaRef<jclass>& safe_annotation_clazz, 132 const base::android::JavaRef<jclass>& safe_annotation_clazz,
91 bool is_named, 133 bool is_named,
92 RenderFrameHost* holder) { 134 int32 holder) {
135 // Can be called on any thread.
benm (inactive) 2014/12/05 17:09:33 maybe mention the sources of this call.
mnaganov (inactive) 2014/12/05 18:07:40 Done.
93 DCHECK(is_named || holder); 136 DCHECK(is_named || holder);
94 GinJavaBoundObject::ObjectID object_id;
95 JNIEnv* env = base::android::AttachCurrentThread(); 137 JNIEnv* env = base::android::AttachCurrentThread();
96 JavaObjectWeakGlobalRef ref(env, object.obj()); 138 JavaObjectWeakGlobalRef ref(env, object.obj());
97 if (is_named) { 139 scoped_refptr<GinJavaBoundObject> new_object =
98 object_id = objects_.Add(new scoped_refptr<GinJavaBoundObject>( 140 is_named ? GinJavaBoundObject::CreateNamed(ref, safe_annotation_clazz)
99 GinJavaBoundObject::CreateNamed(ref, safe_annotation_clazz))); 141 : GinJavaBoundObject::CreateTransient(ref, safe_annotation_clazz,
100 } else { 142 holder);
101 object_id = objects_.Add(new scoped_refptr<GinJavaBoundObject>( 143 // Note that we are abusing the fact that StaticAtomicSequenceNumber
102 GinJavaBoundObject::CreateTransient( 144 // uses Atomic32 as a counter, so it is guaranteed that it will not
103 ref, safe_annotation_clazz, holder))); 145 // overflow our int32 IDs. IDs start from 1.
146 GinJavaBoundObject::ObjectID object_id = g_next_object_id.GetNext() + 1;
147 {
148 base::AutoLock locker(objects_lock_);
149 objects_[object_id] = new_object;
104 } 150 }
105 #if DCHECK_IS_ON 151 #if DCHECK_IS_ON
106 { 152 {
107 GinJavaBoundObject::ObjectID added_object_id; 153 GinJavaBoundObject::ObjectID added_object_id;
108 DCHECK(FindObjectId(object, &added_object_id)); 154 DCHECK(FindObjectId(object, &added_object_id));
109 DCHECK_EQ(object_id, added_object_id); 155 DCHECK_EQ(object_id, added_object_id);
110 } 156 }
111 #endif // DCHECK_IS_ON 157 #endif // DCHECK_IS_ON
112 base::android::ScopedJavaLocalRef<jobject> retained_object_set = 158 base::android::ScopedJavaLocalRef<jobject> retained_object_set =
113 retained_object_set_.get(env); 159 retained_object_set_.get(env);
114 if (!retained_object_set.is_null()) { 160 if (!retained_object_set.is_null()) {
161 base::AutoLock locker(objects_lock_);
115 JNI_Java_HashSet_add(env, retained_object_set, object); 162 JNI_Java_HashSet_add(env, retained_object_set, object);
116 } 163 }
117 return object_id; 164 return object_id;
118 } 165 }
119 166
120 bool GinJavaBridgeDispatcherHost::FindObjectId( 167 bool GinJavaBridgeDispatcherHost::FindObjectId(
121 const base::android::JavaRef<jobject>& object, 168 const base::android::JavaRef<jobject>& object,
122 GinJavaBoundObject::ObjectID* object_id) { 169 GinJavaBoundObject::ObjectID* object_id) {
170 // Can be called on any thread.
123 JNIEnv* env = base::android::AttachCurrentThread(); 171 JNIEnv* env = base::android::AttachCurrentThread();
124 for (GinJavaBoundObject::ObjectMap::iterator it(&objects_); !it.IsAtEnd(); 172 base::AutoLock locker(objects_lock_);
125 it.Advance()) { 173 for (auto pair : objects_) {
126 if (env->IsSameObject( 174 if (env->IsSameObject(
127 object.obj(), 175 object.obj(),
128 it.GetCurrentValue()->get()->GetLocalRef(env).obj())) { 176 pair.second->GetLocalRef(env).obj())) {
129 *object_id = it.GetCurrentKey(); 177 *object_id = pair.first;
130 return true; 178 return true;
131 } 179 }
132 } 180 }
133 return false; 181 return false;
134 } 182 }
135 183
136 JavaObjectWeakGlobalRef GinJavaBridgeDispatcherHost::GetObjectWeakRef( 184 JavaObjectWeakGlobalRef GinJavaBridgeDispatcherHost::GetObjectWeakRef(
137 GinJavaBoundObject::ObjectID object_id) { 185 GinJavaBoundObject::ObjectID object_id) {
138 scoped_refptr<GinJavaBoundObject>* result = objects_.Lookup(object_id); 186 scoped_refptr<GinJavaBoundObject> object = FindObject(object_id);
139 scoped_refptr<GinJavaBoundObject> object(result ? *result : NULL);
140 if (object.get()) 187 if (object.get())
141 return object->GetWeakRef(); 188 return object->GetWeakRef();
142 else 189 else
143 return JavaObjectWeakGlobalRef(); 190 return JavaObjectWeakGlobalRef();
144 } 191 }
145 192
146 void GinJavaBridgeDispatcherHost::RemoveHolder( 193 JavaObjectWeakGlobalRef
147 RenderFrameHost* holder, 194 GinJavaBridgeDispatcherHost::RemoveHolderAndAdvanceLocked(
148 const GinJavaBoundObject::ObjectMap::iterator& from, 195 int32 holder,
149 size_t count) { 196 ObjectMap::iterator* iter_ptr) {
197 objects_lock_.AssertAcquired();
198 JavaObjectWeakGlobalRef result;
199 scoped_refptr<GinJavaBoundObject> object((*iter_ptr)->second);
200 if (!object->IsNamed()) {
201 object->RemoveHolder(holder);
202 if (!object->HasHolders()) {
203 result = object->GetWeakRef();
204 objects_.erase((*iter_ptr)++);
205 }
206 } else {
207 ++(*iter_ptr);
208 }
209 return result;
210 }
211
212 void GinJavaBridgeDispatcherHost::RemoveFromRetainedObjectSetLocked(
213 const JavaObjectWeakGlobalRef& ref) {
214 objects_lock_.AssertAcquired();
150 JNIEnv* env = base::android::AttachCurrentThread(); 215 JNIEnv* env = base::android::AttachCurrentThread();
151 base::android::ScopedJavaLocalRef<jobject> retained_object_set = 216 base::android::ScopedJavaLocalRef<jobject> retained_object_set =
152 retained_object_set_.get(env); 217 retained_object_set_.get(env);
153 size_t i = 0; 218 if (!retained_object_set.is_null()) {
154 for (GinJavaBoundObject::ObjectMap::iterator it(from); 219 JNI_Java_HashSet_remove(env, retained_object_set, ref.get(env));
155 !it.IsAtEnd() && i < count;
156 it.Advance(), ++i) {
157 scoped_refptr<GinJavaBoundObject> object(*it.GetCurrentValue());
158 if (object->IsNamed())
159 continue;
160 object->RemoveHolder(holder);
161 if (!object->HasHolders()) {
162 if (!retained_object_set.is_null()) {
163 JNI_Java_HashSet_remove(
164 env, retained_object_set, object->GetLocalRef(env));
165 }
166 objects_.Remove(it.GetCurrentKey());
167 }
168 } 220 }
169 } 221 }
170 222
171 void GinJavaBridgeDispatcherHost::AddNamedObject( 223 void GinJavaBridgeDispatcherHost::AddNamedObject(
172 const std::string& name, 224 const std::string& name,
173 const base::android::JavaRef<jobject>& object, 225 const base::android::JavaRef<jobject>& object,
174 const base::android::JavaRef<jclass>& safe_annotation_clazz) { 226 const base::android::JavaRef<jclass>& safe_annotation_clazz) {
175 DCHECK_CURRENTLY_ON(BrowserThread::UI); 227 DCHECK_CURRENTLY_ON(BrowserThread::UI);
176 GinJavaBoundObject::ObjectID object_id; 228 GinJavaBoundObject::ObjectID object_id;
177 NamedObjectMap::iterator iter = named_objects_.find(name); 229 NamedObjectMap::iterator iter = named_objects_.find(name);
178 bool existing_object = FindObjectId(object, &object_id); 230 bool existing_object = FindObjectId(object, &object_id);
179 if (existing_object && iter != named_objects_.end() && 231 if (existing_object && iter != named_objects_.end() &&
180 iter->second == object_id) { 232 iter->second == object_id) {
181 // Nothing to do. 233 // Nothing to do.
182 return; 234 return;
183 } 235 }
184 if (iter != named_objects_.end()) { 236 if (iter != named_objects_.end()) {
185 RemoveNamedObject(iter->first); 237 RemoveNamedObject(iter->first);
186 } 238 }
187 if (existing_object) { 239 if (existing_object) {
188 (*objects_.Lookup(object_id))->AddName(); 240 base::AutoLock locker(objects_lock_);
241 objects_[object_id]->AddName();
189 } else { 242 } else {
190 object_id = AddObject(object, safe_annotation_clazz, true, NULL); 243 object_id = AddObject(object, safe_annotation_clazz, true, 0);
191 } 244 }
192 named_objects_[name] = object_id; 245 named_objects_[name] = object_id;
193 246
194 web_contents()->SendToAllFrames( 247 web_contents()->SendToAllFrames(
195 new GinJavaBridgeMsg_AddNamedObject(MSG_ROUTING_NONE, name, object_id)); 248 new GinJavaBridgeMsg_AddNamedObject(MSG_ROUTING_NONE, name, object_id));
196 } 249 }
197 250
198 void GinJavaBridgeDispatcherHost::RemoveNamedObject( 251 void GinJavaBridgeDispatcherHost::RemoveNamedObject(
199 const std::string& name) { 252 const std::string& name) {
200 DCHECK_CURRENTLY_ON(BrowserThread::UI); 253 DCHECK_CURRENTLY_ON(BrowserThread::UI);
201 NamedObjectMap::iterator iter = named_objects_.find(name); 254 NamedObjectMap::iterator iter = named_objects_.find(name);
202 if (iter == named_objects_.end()) 255 if (iter == named_objects_.end())
203 return; 256 return;
204 257
205 // |name| may come from |named_objects_|. Make a copy of name so that if 258 // |name| may come from |named_objects_|. Make a copy of name so that if
206 // |name| is from |named_objects_| it'll be valid after the remove below. 259 // |name| is from |named_objects_| it'll be valid after the remove below.
207 const std::string copied_name(name); 260 const std::string copied_name(name);
208 261
209 scoped_refptr<GinJavaBoundObject> object(*objects_.Lookup(iter->second)); 262 {
263 base::AutoLock locker(objects_lock_);
264 objects_[iter->second]->RemoveName();
265 }
210 named_objects_.erase(iter); 266 named_objects_.erase(iter);
211 object->RemoveName();
212 267
213 // As the object isn't going to be removed from the JavaScript side until the 268 // As the object isn't going to be removed from the JavaScript side until the
214 // next page reload, calls to it must still work, thus we should continue to 269 // next page reload, calls to it must still work, thus we should continue to
215 // hold it. All the transient objects and removed named objects will be purged 270 // hold it. All the transient objects and removed named objects will be purged
216 // during the cleansing caused by DocumentAvailableInMainFrame event. 271 // during the cleansing caused by DocumentAvailableInMainFrame event.
217 272
218 web_contents()->SendToAllFrames( 273 web_contents()->SendToAllFrames(
219 new GinJavaBridgeMsg_RemoveNamedObject(MSG_ROUTING_NONE, copied_name)); 274 new GinJavaBridgeMsg_RemoveNamedObject(MSG_ROUTING_NONE, copied_name));
220 } 275 }
221 276
222 void GinJavaBridgeDispatcherHost::SetAllowObjectContentsInspection(bool allow) { 277 void GinJavaBridgeDispatcherHost::SetAllowObjectContentsInspection(bool allow) {
278 if (!JavaBridgeThread::CurrentlyOn()) {
279 g_background_thread.Get().message_loop()->task_runner()->PostTask(
benm (inactive) 2014/12/05 17:09:33 have we introduced a potential race here now?
mnaganov (inactive) 2014/12/05 18:07:40 Potentially, yes. But in production, this method i
280 FROM_HERE,
281 base::Bind(
282 &GinJavaBridgeDispatcherHost::SetAllowObjectContentsInspection,
283 this, allow));
284 return;
285 }
223 allow_object_contents_inspection_ = allow; 286 allow_object_contents_inspection_ = allow;
224 } 287 }
225 288
226 void GinJavaBridgeDispatcherHost::DocumentAvailableInMainFrame() { 289 void GinJavaBridgeDispatcherHost::DocumentAvailableInMainFrame() {
227 DCHECK_CURRENTLY_ON(BrowserThread::UI); 290 DCHECK_CURRENTLY_ON(BrowserThread::UI);
228 // Called when the window object has been cleared in the main frame. 291 // Called when the window object has been cleared in the main frame.
229 // That means, all sub-frames have also been cleared, so only named 292 // That means, all sub-frames have also been cleared, so only named
230 // objects survived. 293 // objects survived.
231 JNIEnv* env = base::android::AttachCurrentThread(); 294 JNIEnv* env = base::android::AttachCurrentThread();
232 base::android::ScopedJavaLocalRef<jobject> retained_object_set = 295 base::android::ScopedJavaLocalRef<jobject> retained_object_set =
233 retained_object_set_.get(env); 296 retained_object_set_.get(env);
297 base::AutoLock locker(objects_lock_);
234 if (!retained_object_set.is_null()) { 298 if (!retained_object_set.is_null()) {
235 JNI_Java_HashSet_clear(env, retained_object_set); 299 JNI_Java_HashSet_clear(env, retained_object_set);
236 } 300 }
237 301 auto iter = objects_.begin();
238 // We also need to add back the named objects we have so far as they 302 while (iter != objects_.end()) {
239 // should survive navigations. 303 if (iter->second->IsNamed()) {
240 for (GinJavaBoundObject::ObjectMap::iterator it(&objects_); !it.IsAtEnd();
241 it.Advance()) {
242 scoped_refptr<GinJavaBoundObject> object(*it.GetCurrentValue());
243 if (object->IsNamed()) {
244 if (!retained_object_set.is_null()) { 304 if (!retained_object_set.is_null()) {
245 JNI_Java_HashSet_add( 305 JNI_Java_HashSet_add(
246 env, retained_object_set, object->GetLocalRef(env)); 306 env, retained_object_set, iter->second->GetLocalRef(env));
247 } 307 }
308 ++iter;
248 } else { 309 } else {
249 objects_.Remove(it.GetCurrentKey()); 310 objects_.erase(iter++);
250 } 311 }
251 } 312 }
252 } 313 }
253 314
254 namespace { 315 base::TaskRunner* GinJavaBridgeDispatcherHost::OverrideTaskRunnerForMessage(
255 316 const IPC::Message& message) {
256 // TODO(mnaganov): Implement passing of a parameter into sync message handlers. 317 GinJavaBoundObject::ObjectID object_id = 0;
257 class MessageForwarder : public IPC::Sender { 318 // TODO(mnaganov): It's very sad that we have a BrowserMessageFilter per
258 public: 319 // WebView instance. We should redesign to have a filter per RPH.
259 MessageForwarder(GinJavaBridgeDispatcherHost* gjbdh, 320 // Check, if the object ID in the message is known to this host. If not,
260 RenderFrameHost* render_frame_host) 321 // this is a message for some other host. As all our IPC messages from the
261 : gjbdh_(gjbdh), render_frame_host_(render_frame_host) {} 322 // renderer start with object ID, we just fetch it directly from the
262 void OnGetMethods(GinJavaBoundObject::ObjectID object_id, 323 // message, considering sync and async messages separately.
263 IPC::Message* reply_msg) { 324 switch (message.type()) {
264 gjbdh_->OnGetMethods(render_frame_host_, 325 case GinJavaBridgeHostMsg_GetMethods::ID:
265 object_id, 326 case GinJavaBridgeHostMsg_HasMethod::ID:
266 reply_msg); 327 case GinJavaBridgeHostMsg_InvokeMethod::ID: {
328 DCHECK(message.is_sync());
329 PickleIterator message_reader =
330 IPC::SyncMessage::GetDataIterator(&message);
331 if (!IPC::ReadParam(&message, &message_reader, &object_id))
332 return NULL;
333 break;
334 }
335 case GinJavaBridgeHostMsg_ObjectWrapperDeleted::ID: {
336 DCHECK(!message.is_sync());
337 PickleIterator message_reader(message);
338 if (!IPC::ReadParam(&message, &message_reader, &object_id))
339 return NULL;
340 break;
341 }
267 } 342 }
268 void OnHasMethod(GinJavaBoundObject::ObjectID object_id, 343 {
269 const std::string& method_name, 344 base::AutoLock locker(objects_lock_);
270 IPC::Message* reply_msg) { 345 if (objects_.find(object_id) != objects_.end()) {
271 gjbdh_->OnHasMethod(render_frame_host_, 346 return g_background_thread.Get().message_loop()->task_runner().get();
272 object_id, 347 }
273 method_name,
274 reply_msg);
275 } 348 }
276 void OnInvokeMethod(GinJavaBoundObject::ObjectID object_id, 349 return NULL;
277 const std::string& method_name,
278 const base::ListValue& arguments,
279 IPC::Message* reply_msg) {
280 gjbdh_->OnInvokeMethod(render_frame_host_,
281 object_id,
282 method_name,
283 arguments,
284 reply_msg);
285 }
286 virtual bool Send(IPC::Message* msg) override {
287 NOTREACHED();
288 return false;
289 }
290 private:
291 GinJavaBridgeDispatcherHost* gjbdh_;
292 RenderFrameHost* render_frame_host_;
293 };
294
295 } 350 }
296 351
297 bool GinJavaBridgeDispatcherHost::OnMessageReceived( 352 bool GinJavaBridgeDispatcherHost::OnMessageReceived(
298 const IPC::Message& message, 353 const IPC::Message& message) {
299 RenderFrameHost* render_frame_host) { 354 // We can get here As WebContentsObserver also has OnMessageReceived,
300 DCHECK(render_frame_host); 355 // or because we have not provided a task runner in
356 // OverrideTaskRunnerForMessage. In either case, just bail out.
357 if (!JavaBridgeThread::CurrentlyOn())
358 return false;
359 SetCurrentRoutingID(message.routing_id());
301 bool handled = true; 360 bool handled = true;
302 MessageForwarder forwarder(this, render_frame_host); 361 IPC_BEGIN_MESSAGE_MAP(GinJavaBridgeDispatcherHost, message)
303 IPC_BEGIN_MESSAGE_MAP_WITH_PARAM(GinJavaBridgeDispatcherHost, message, 362 IPC_MESSAGE_HANDLER(GinJavaBridgeHostMsg_GetMethods, OnGetMethods)
304 render_frame_host) 363 IPC_MESSAGE_HANDLER(GinJavaBridgeHostMsg_HasMethod, OnHasMethod)
305 IPC_MESSAGE_FORWARD_DELAY_REPLY(GinJavaBridgeHostMsg_GetMethods, 364 IPC_MESSAGE_HANDLER(GinJavaBridgeHostMsg_InvokeMethod, OnInvokeMethod)
306 &forwarder,
307 MessageForwarder::OnGetMethods)
308 IPC_MESSAGE_FORWARD_DELAY_REPLY(GinJavaBridgeHostMsg_HasMethod,
309 &forwarder,
310 MessageForwarder::OnHasMethod)
311 IPC_MESSAGE_FORWARD_DELAY_REPLY(GinJavaBridgeHostMsg_InvokeMethod,
312 &forwarder,
313 MessageForwarder::OnInvokeMethod)
314 IPC_MESSAGE_HANDLER(GinJavaBridgeHostMsg_ObjectWrapperDeleted, 365 IPC_MESSAGE_HANDLER(GinJavaBridgeHostMsg_ObjectWrapperDeleted,
315 OnObjectWrapperDeleted) 366 OnObjectWrapperDeleted)
316 IPC_MESSAGE_UNHANDLED(handled = false) 367 IPC_MESSAGE_UNHANDLED(handled = false)
317 IPC_END_MESSAGE_MAP() 368 IPC_END_MESSAGE_MAP()
369 SetCurrentRoutingID(MSG_ROUTING_NONE);
318 return handled; 370 return handled;
319 } 371 }
320 372
321 namespace { 373 void GinJavaBridgeDispatcherHost::OnDestruct() const {
benm (inactive) 2014/12/05 17:09:33 how was lifetime managed previously?
mnaganov (inactive) 2014/12/05 18:07:40 Previously ContentViewCore was holding GinJavaBrid
374 if (BrowserThread::CurrentlyOn(BrowserThread::UI)) {
375 delete this;
376 } else {
377 BrowserThread::DeleteSoon(BrowserThread::UI, FROM_HERE, this);
378 }
379 }
322 380
323 class IsValidRenderFrameHostHelper 381 int GinJavaBridgeDispatcherHost::GetCurrentRoutingID() {
324 : public base::RefCounted<IsValidRenderFrameHostHelper> { 382 DCHECK(JavaBridgeThread::CurrentlyOn());
325 public: 383 return current_routing_id_;
326 explicit IsValidRenderFrameHostHelper(RenderFrameHost* rfh_to_match) 384 }
327 : rfh_to_match_(rfh_to_match), rfh_found_(false) {}
328 385
329 bool rfh_found() { return rfh_found_; } 386 void GinJavaBridgeDispatcherHost::SetCurrentRoutingID(int32 routing_id) {
387 DCHECK(JavaBridgeThread::CurrentlyOn());
388 current_routing_id_ = routing_id;
389 }
330 390
331 void OnFrame(RenderFrameHost* rfh) { 391 scoped_refptr<GinJavaBoundObject> GinJavaBridgeDispatcherHost::FindObject(
332 if (rfh_to_match_ == rfh) rfh_found_ = true; 392 GinJavaBoundObject::ObjectID object_id) {
333 } 393 // Can be called on any thread.
334 394 base::AutoLock locker(objects_lock_);
335 private: 395 auto iter = objects_.find(object_id);
336 friend class base::RefCounted<IsValidRenderFrameHostHelper>; 396 if (iter != objects_.end())
337 397 return iter->second;
338 ~IsValidRenderFrameHostHelper() {} 398 return NULL;
339
340 RenderFrameHost* rfh_to_match_;
341 bool rfh_found_;
342
343 DISALLOW_COPY_AND_ASSIGN(IsValidRenderFrameHostHelper);
344 };
345
346 } // namespace
347
348 bool GinJavaBridgeDispatcherHost::IsValidRenderFrameHost(
349 RenderFrameHost* render_frame_host) {
350 scoped_refptr<IsValidRenderFrameHostHelper> helper =
351 new IsValidRenderFrameHostHelper(render_frame_host);
352 web_contents()->ForEachFrame(
353 base::Bind(&IsValidRenderFrameHostHelper::OnFrame, helper));
354 return helper->rfh_found();
355 } 399 }
356 400
357 void GinJavaBridgeDispatcherHost::OnGetMethods( 401 void GinJavaBridgeDispatcherHost::OnGetMethods(
358 RenderFrameHost* render_frame_host,
359 GinJavaBoundObject::ObjectID object_id, 402 GinJavaBoundObject::ObjectID object_id,
360 IPC::Message* reply_msg) { 403 std::set<std::string>* returned_method_names) {
361 DCHECK_CURRENTLY_ON(BrowserThread::UI); 404 DCHECK(JavaBridgeThread::CurrentlyOn());
362 DCHECK(render_frame_host); 405 if (!allow_object_contents_inspection_)
363 if (!allow_object_contents_inspection_) {
364 IPC::WriteParam(reply_msg, std::set<std::string>());
365 render_frame_host->Send(reply_msg);
366 return; 406 return;
407 scoped_refptr<GinJavaBoundObject> object = FindObject(object_id);
408 if (object.get()) {
409 *returned_method_names = object->GetMethodNames();
410 } else {
411 LOG(ERROR) << "WebView: Unknown object: " << object_id;
367 } 412 }
368 scoped_refptr<GinJavaBoundObject> object(*objects_.Lookup(object_id));
369 if (!object.get()) {
370 LOG(ERROR) << "WebView: Unknown object: " << object_id;
371 IPC::WriteParam(reply_msg, std::set<std::string>());
372 render_frame_host->Send(reply_msg);
373 return;
374 }
375 DCHECK(!HasPendingReply(render_frame_host));
376 pending_replies_[render_frame_host] = reply_msg;
377 base::PostTaskAndReplyWithResult(
378 g_background_thread.Get().message_loop()->message_loop_proxy().get(),
379 FROM_HERE,
380 base::Bind(&GinJavaBoundObject::GetMethodNames, object),
381 base::Bind(&GinJavaBridgeDispatcherHost::SendMethods,
382 AsWeakPtr(),
383 render_frame_host));
384 }
385
386 void GinJavaBridgeDispatcherHost::SendMethods(
387 RenderFrameHost* render_frame_host,
388 const std::set<std::string>& method_names) {
389 IPC::Message* reply_msg = TakePendingReply(render_frame_host);
390 if (!reply_msg) {
391 return;
392 }
393 IPC::WriteParam(reply_msg, method_names);
394 render_frame_host->Send(reply_msg);
395 } 413 }
396 414
397 void GinJavaBridgeDispatcherHost::OnHasMethod( 415 void GinJavaBridgeDispatcherHost::OnHasMethod(
398 RenderFrameHost* render_frame_host,
399 GinJavaBoundObject::ObjectID object_id, 416 GinJavaBoundObject::ObjectID object_id,
400 const std::string& method_name, 417 const std::string& method_name,
401 IPC::Message* reply_msg) { 418 bool* result) {
402 DCHECK_CURRENTLY_ON(BrowserThread::UI); 419 DCHECK(JavaBridgeThread::CurrentlyOn());
403 DCHECK(render_frame_host); 420 scoped_refptr<GinJavaBoundObject> object = FindObject(object_id);
404 scoped_refptr<GinJavaBoundObject> object(*objects_.Lookup(object_id)); 421 if (object.get()) {
405 if (!object.get()) { 422 *result = object->HasMethod(method_name);
423 } else {
406 LOG(ERROR) << "WebView: Unknown object: " << object_id; 424 LOG(ERROR) << "WebView: Unknown object: " << object_id;
407 IPC::WriteParam(reply_msg, false);
408 render_frame_host->Send(reply_msg);
409 return;
410 } 425 }
411 DCHECK(!HasPendingReply(render_frame_host));
412 pending_replies_[render_frame_host] = reply_msg;
413 base::PostTaskAndReplyWithResult(
414 g_background_thread.Get().message_loop()->message_loop_proxy().get(),
415 FROM_HERE,
416 base::Bind(&GinJavaBoundObject::HasMethod, object, method_name),
417 base::Bind(&GinJavaBridgeDispatcherHost::SendHasMethodReply,
418 AsWeakPtr(),
419 render_frame_host));
420 }
421
422 void GinJavaBridgeDispatcherHost::SendHasMethodReply(
423 RenderFrameHost* render_frame_host,
424 bool result) {
425 IPC::Message* reply_msg = TakePendingReply(render_frame_host);
426 if (!reply_msg) {
427 return;
428 }
429 IPC::WriteParam(reply_msg, result);
430 render_frame_host->Send(reply_msg);
431 } 426 }
432 427
433 void GinJavaBridgeDispatcherHost::OnInvokeMethod( 428 void GinJavaBridgeDispatcherHost::OnInvokeMethod(
434 RenderFrameHost* render_frame_host,
435 GinJavaBoundObject::ObjectID object_id, 429 GinJavaBoundObject::ObjectID object_id,
436 const std::string& method_name, 430 const std::string& method_name,
437 const base::ListValue& arguments, 431 const base::ListValue& arguments,
438 IPC::Message* reply_msg) { 432 base::ListValue* wrapped_result,
439 DCHECK_CURRENTLY_ON(BrowserThread::UI); 433 content::GinJavaBridgeError* error_code) {
440 DCHECK(render_frame_host); 434 DCHECK(JavaBridgeThread::CurrentlyOn());
441 scoped_refptr<GinJavaBoundObject> object(*objects_.Lookup(object_id)); 435 scoped_refptr<GinJavaBoundObject> object = FindObject(object_id);
442 if (!object.get()) { 436 if (!object.get()) {
443 LOG(ERROR) << "WebView: Unknown object: " << object_id; 437 LOG(ERROR) << "WebView: Unknown object: " << object_id;
444 base::ListValue result; 438 wrapped_result->Append(base::Value::CreateNullValue());
445 result.Append(base::Value::CreateNullValue()); 439 *error_code = kGinJavaBridgeUnknownObjectId;
446 IPC::WriteParam(reply_msg, result);
447 IPC::WriteParam(reply_msg, kGinJavaBridgeUnknownObjectId);
448 render_frame_host->Send(reply_msg);
449 return; 440 return;
450 } 441 }
451 DCHECK(!HasPendingReply(render_frame_host));
452 pending_replies_[render_frame_host] = reply_msg;
453 scoped_refptr<GinJavaMethodInvocationHelper> result = 442 scoped_refptr<GinJavaMethodInvocationHelper> result =
454 new GinJavaMethodInvocationHelper( 443 new GinJavaMethodInvocationHelper(
455 make_scoped_ptr(new GinJavaBoundObjectDelegate(object)), 444 make_scoped_ptr(new GinJavaBoundObjectDelegate(object)),
456 method_name, 445 method_name,
457 arguments); 446 arguments);
458 result->Init(this); 447 result->Init(this);
459 g_background_thread.Get() 448 result->Invoke();
460 .message_loop() 449 *error_code = result->GetInvocationError();
461 ->message_loop_proxy()
462 ->PostTaskAndReply(
463 FROM_HERE,
464 base::Bind(&GinJavaMethodInvocationHelper::Invoke, result),
465 base::Bind(
466 &GinJavaBridgeDispatcherHost::ProcessMethodInvocationResult,
467 AsWeakPtr(),
468 render_frame_host,
469 result));
470 }
471
472 void GinJavaBridgeDispatcherHost::ProcessMethodInvocationResult(
473 RenderFrameHost* render_frame_host,
474 scoped_refptr<GinJavaMethodInvocationHelper> result) {
475 if (result->HoldsPrimitiveResult()) { 450 if (result->HoldsPrimitiveResult()) {
476 IPC::Message* reply_msg = TakePendingReply(render_frame_host); 451 scoped_ptr<base::ListValue> result_copy(
477 if (!reply_msg) { 452 result->GetPrimitiveResult().DeepCopy());
478 return; 453 wrapped_result->Swap(result_copy.get());
479 } 454 } else if (!result->GetObjectResult().is_null()) {
480 IPC::WriteParam(reply_msg, result->GetPrimitiveResult());
481 IPC::WriteParam(reply_msg, result->GetInvocationError());
482 render_frame_host->Send(reply_msg);
483 } else {
484 ProcessMethodInvocationObjectResult(render_frame_host, result);
485 }
486 }
487
488 void GinJavaBridgeDispatcherHost::ProcessMethodInvocationObjectResult(
489 RenderFrameHost* render_frame_host,
490 scoped_refptr<GinJavaMethodInvocationHelper> result) {
491 DCHECK_CURRENTLY_ON(BrowserThread::UI);
492
493 if (!IsValidRenderFrameHost(render_frame_host)) {
494 // In this case, we must've already sent the reply when the render frame
495 // was destroyed.
496 DCHECK(!HasPendingReply(render_frame_host));
497 return;
498 }
499
500 base::ListValue wrapped_result;
501 if (!result->GetObjectResult().is_null()) {
502 GinJavaBoundObject::ObjectID returned_object_id; 455 GinJavaBoundObject::ObjectID returned_object_id;
503 if (FindObjectId(result->GetObjectResult(), &returned_object_id)) { 456 if (FindObjectId(result->GetObjectResult(), &returned_object_id)) {
504 (*objects_.Lookup(returned_object_id))->AddHolder(render_frame_host); 457 base::AutoLock locker(objects_lock_);
458 objects_[returned_object_id]->AddHolder(GetCurrentRoutingID());
505 } else { 459 } else {
506 returned_object_id = AddObject(result->GetObjectResult(), 460 returned_object_id = AddObject(result->GetObjectResult(),
507 result->GetSafeAnnotationClass(), 461 result->GetSafeAnnotationClass(),
508 false, 462 false,
509 render_frame_host); 463 GetCurrentRoutingID());
510 } 464 }
511 wrapped_result.Append( 465 wrapped_result->Append(
512 GinJavaBridgeValue::CreateObjectIDValue( 466 GinJavaBridgeValue::CreateObjectIDValue(
513 returned_object_id).release()); 467 returned_object_id).release());
514 } else { 468 } else {
515 wrapped_result.Append(base::Value::CreateNullValue()); 469 wrapped_result->Append(base::Value::CreateNullValue());
516 } 470 }
517 IPC::Message* reply_msg = TakePendingReply(render_frame_host);
518 if (!reply_msg) {
519 return;
520 }
521 IPC::WriteParam(reply_msg, wrapped_result);
522 IPC::WriteParam(reply_msg, result->GetInvocationError());
523 render_frame_host->Send(reply_msg);
524 } 471 }
525 472
526 void GinJavaBridgeDispatcherHost::OnObjectWrapperDeleted( 473 void GinJavaBridgeDispatcherHost::OnObjectWrapperDeleted(
527 RenderFrameHost* render_frame_host,
528 GinJavaBoundObject::ObjectID object_id) { 474 GinJavaBoundObject::ObjectID object_id) {
529 DCHECK_CURRENTLY_ON(BrowserThread::UI); 475 base::AutoLock locker(objects_lock_);
530 DCHECK(render_frame_host); 476 auto iter = objects_.find(object_id);
531 if (objects_.Lookup(object_id)) { 477 if (iter == objects_.end())
532 GinJavaBoundObject::ObjectMap::iterator iter(&objects_); 478 return;
533 while (!iter.IsAtEnd() && iter.GetCurrentKey() != object_id) 479 JavaObjectWeakGlobalRef ref =
534 iter.Advance(); 480 RemoveHolderAndAdvanceLocked(GetCurrentRoutingID(), &iter);
535 DCHECK(!iter.IsAtEnd()); 481 if (!ref.is_empty()) {
536 RemoveHolder(render_frame_host, iter, 1); 482 RemoveFromRetainedObjectSetLocked(ref);
537 } 483 }
538 } 484 }
539 485
540 IPC::Message* GinJavaBridgeDispatcherHost::TakePendingReply(
541 RenderFrameHost* render_frame_host) {
542 if (!IsValidRenderFrameHost(render_frame_host)) {
543 DCHECK(!HasPendingReply(render_frame_host));
544 return NULL;
545 }
546
547 PendingReplyMap::iterator it = pending_replies_.find(render_frame_host);
548 // There may be no pending reply if we're called from RenderFrameDeleted and
549 // we already sent the reply through the regular route.
550 if (it == pending_replies_.end()) {
551 return NULL;
552 }
553
554 IPC::Message* reply_msg = it->second;
555 pending_replies_.erase(it);
556 return reply_msg;
557 }
558
559 bool GinJavaBridgeDispatcherHost::HasPendingReply(
560 RenderFrameHost* render_frame_host) const {
561 return pending_replies_.find(render_frame_host) != pending_replies_.end();
562 }
563
564 } // namespace content 486 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698