Home | History | Annotate | Download | only in java
      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
      3 // found in the LICENSE file.
      4 
      5 #include "content/browser/android/java/java_bridge_dispatcher_host_manager.h"
      6 
      7 #include "base/android/jni_android.h"
      8 #include "base/android/jni_weak_ref.h"
      9 #include "base/android/scoped_java_ref.h"
     10 #include "base/bind.h"
     11 #include "base/logging.h"
     12 #include "base/strings/utf_string_conversions.h"
     13 #include "content/browser/android/java/java_bound_object.h"
     14 #include "content/browser/android/java/java_bridge_dispatcher_host.h"
     15 #include "content/common/android/hash_set.h"
     16 #include "content/common/java_bridge_messages.h"
     17 #include "content/public/browser/browser_thread.h"
     18 #include "content/public/browser/render_frame_host.h"
     19 #include "third_party/WebKit/public/web/WebBindings.h"
     20 
     21 namespace content {
     22 
     23 JavaBridgeDispatcherHostManager::JavaBridgeDispatcherHostManager(
     24     WebContents* web_contents,
     25     jobject retained_object_set)
     26     : WebContentsObserver(web_contents),
     27       retained_object_set_(base::android::AttachCurrentThread(),
     28                            retained_object_set),
     29       allow_object_contents_inspection_(true) {
     30   DCHECK(retained_object_set);
     31 }
     32 
     33 JavaBridgeDispatcherHostManager::~JavaBridgeDispatcherHostManager() {
     34   for (ObjectMap::iterator iter = objects_.begin(); iter != objects_.end();
     35       ++iter) {
     36     blink::WebBindings::releaseObject(iter->second);
     37   }
     38   DCHECK_EQ(0U, instances_.size());
     39 }
     40 
     41 void JavaBridgeDispatcherHostManager::AddNamedObject(const base::string16& name,
     42                                                      NPObject* object) {
     43   // Record this object in a map so that we can add it into RenderViewHosts
     44   // created later. The JavaBridgeDispatcherHost instances will take a
     45   // reference to the object, but we take one too, because this method can be
     46   // called before there are any such instances.
     47   blink::WebBindings::retainObject(object);
     48   objects_[name] = object;
     49 
     50   for (InstanceMap::iterator iter = instances_.begin();
     51       iter != instances_.end(); ++iter) {
     52     iter->second->AddNamedObject(name, object);
     53   }
     54 }
     55 
     56 void JavaBridgeDispatcherHostManager::RemoveNamedObject(
     57     const base::string16& name) {
     58   ObjectMap::iterator iter = objects_.find(name);
     59   if (iter == objects_.end()) {
     60     return;
     61   }
     62 
     63   blink::WebBindings::releaseObject(iter->second);
     64   objects_.erase(iter);
     65 
     66   for (InstanceMap::iterator iter = instances_.begin();
     67       iter != instances_.end(); ++iter) {
     68     iter->second->RemoveNamedObject(name);
     69   }
     70 }
     71 
     72 void JavaBridgeDispatcherHostManager::RenderFrameCreated(
     73     RenderFrameHost* render_frame_host) {
     74   // Creates a JavaBridgeDispatcherHost for the specified RenderViewHost and
     75   // adds all currently registered named objects to the new instance.
     76   scoped_refptr<JavaBridgeDispatcherHost> instance =
     77       new JavaBridgeDispatcherHost(render_frame_host);
     78 
     79   for (ObjectMap::const_iterator iter = objects_.begin();
     80       iter != objects_.end(); ++iter) {
     81     instance->AddNamedObject(iter->first, iter->second);
     82   }
     83 
     84   instances_[render_frame_host] = instance;
     85 }
     86 
     87 void JavaBridgeDispatcherHostManager::RenderFrameDeleted(
     88     RenderFrameHost* render_frame_host) {
     89   if (!instances_.count(render_frame_host))  // Needed for tests.
     90     return;
     91   instances_[render_frame_host]->RenderFrameDeleted();
     92   instances_.erase(render_frame_host);
     93 }
     94 
     95 void JavaBridgeDispatcherHostManager::DocumentAvailableInMainFrame() {
     96   DCHECK_CURRENTLY_ON(BrowserThread::UI);
     97   // Called when the window object has been cleared in the main frame.
     98   JNIEnv* env = base::android::AttachCurrentThread();
     99   base::android::ScopedJavaLocalRef<jobject> retained_object_set =
    100       retained_object_set_.get(env);
    101   if (!retained_object_set.is_null()) {
    102     JNI_Java_HashSet_clear(env, retained_object_set);
    103 
    104     // We also need to add back the named objects we have so far as they
    105     // should survive navigations.
    106     ObjectMap::iterator it = objects_.begin();
    107     for (; it != objects_.end(); ++it) {
    108       JNI_Java_HashSet_add(env, retained_object_set,
    109                            JavaBoundObject::GetJavaObject(it->second));
    110     }
    111   }
    112 }
    113 
    114 bool JavaBridgeDispatcherHostManager::OnMessageReceived(
    115     const IPC::Message& message,
    116     RenderFrameHost* render_frame_host) {
    117   DCHECK(render_frame_host);
    118   if (!instances_.count(render_frame_host))
    119     return false;
    120   scoped_refptr<JavaBridgeDispatcherHost> instance =
    121       instances_[render_frame_host];
    122   bool handled = true;
    123   IPC_BEGIN_MESSAGE_MAP(JavaBridgeDispatcherHostManager, message)
    124     IPC_MESSAGE_FORWARD_DELAY_REPLY(
    125         JavaBridgeHostMsg_GetChannelHandle,
    126         instance.get(),
    127         JavaBridgeDispatcherHost::OnGetChannelHandle)
    128     IPC_MESSAGE_UNHANDLED(handled = false)
    129   IPC_END_MESSAGE_MAP()
    130   return handled;
    131 }
    132 
    133 void JavaBridgeDispatcherHostManager::JavaBoundObjectCreated(
    134     const base::android::JavaRef<jobject>& object) {
    135   DCHECK_CURRENTLY_ON(BrowserThread::UI);
    136 
    137   JNIEnv* env = base::android::AttachCurrentThread();
    138   base::android::ScopedJavaLocalRef<jobject> retained_object_set =
    139       retained_object_set_.get(env);
    140   if (!retained_object_set.is_null()) {
    141     JNI_Java_HashSet_add(env, retained_object_set, object);
    142   }
    143 }
    144 
    145 void JavaBridgeDispatcherHostManager::JavaBoundObjectDestroyed(
    146     const base::android::JavaRef<jobject>& object) {
    147   DCHECK_CURRENTLY_ON(BrowserThread::UI);
    148 
    149   JNIEnv* env = base::android::AttachCurrentThread();
    150   base::android::ScopedJavaLocalRef<jobject> retained_object_set =
    151       retained_object_set_.get(env);
    152   if (!retained_object_set.is_null()) {
    153     JNI_Java_HashSet_remove(env, retained_object_set, object);
    154   }
    155 }
    156 
    157 void JavaBridgeDispatcherHostManager::SetAllowObjectContentsInspection(
    158     bool allow) {
    159   allow_object_contents_inspection_ = allow;
    160 }
    161 
    162 }  // namespace content
    163