Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 |
| OLD | NEW |