Avi Drissman | 4e1b7bc3 | 2022-09-15 14:03:50 | [diff] [blame] | 1 | // Copyright 2017 The Chromium Authors |
Jinsuk Kim | a6490f8 | 2018-01-02 02:16:14 | [diff] [blame] | 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/javascript_injector.h" |
| 6 | |
Rupert Ben Wiser | b7d1894f | 2025-04-02 19:13:15 | [diff] [blame] | 7 | #include <vector> |
| 8 | |
Jinsuk Kim | a6490f8 | 2018-01-02 02:16:14 | [diff] [blame] | 9 | #include "base/android/jni_string.h" |
Gabriel Charette | 9f60dd1 | 2020-03-06 20:48:04 | [diff] [blame] | 10 | #include "base/memory/ptr_util.h" |
Rupert Ben Wiser | 36b4404d | 2025-06-05 16:15:19 | [diff] [blame] | 11 | #include "components/origin_matcher/origin_matcher.h" |
Jinsuk Kim | a6490f8 | 2018-01-02 02:16:14 | [diff] [blame] | 12 | #include "content/browser/android/java/gin_java_bridge_dispatcher_host.h" |
Hiroki Nakagawa | c1e5801 | 2024-05-07 23:43:41 | [diff] [blame] | 13 | #include "content/browser/preloading/prerender/prerender_final_status.h" |
| 14 | #include "content/browser/preloading/prerender/prerender_host_registry.h" |
| 15 | #include "content/browser/web_contents/web_contents_impl.h" |
Andrew Grieve | ecb885bb | 2024-05-29 18:14:19 | [diff] [blame] | 16 | |
| 17 | // Must come after all headers that specialize FromJniType() / ToJniType(). |
Mohamed Heikal | c09e101 | 2019-06-21 14:47:26 | [diff] [blame] | 18 | #include "content/public/android/content_jni_headers/JavascriptInjectorImpl_jni.h" |
Jinsuk Kim | a6490f8 | 2018-01-02 02:16:14 | [diff] [blame] | 19 | |
| 20 | using base::android::AttachCurrentThread; |
| 21 | using base::android::ConvertJavaStringToUTF8; |
| 22 | using base::android::JavaParamRef; |
| 23 | using base::android::ScopedJavaLocalRef; |
| 24 | |
| 25 | namespace content { |
| 26 | |
Jinsuk Kim | a6490f8 | 2018-01-02 02:16:14 | [diff] [blame] | 27 | JavascriptInjector::JavascriptInjector( |
| 28 | JNIEnv* env, |
| 29 | const base::android::JavaParamRef<jobject>& obj, |
| 30 | const base::android::JavaParamRef<jobject>& retained_objects, |
| 31 | WebContents* web_contents) |
Dave Tapuska | de1f720b | 2021-11-17 15:13:10 | [diff] [blame] | 32 | : WebContentsUserData<JavascriptInjector>(*web_contents), |
| 33 | java_ref_(env, obj) { |
Jinsuk Kim | a6490f8 | 2018-01-02 02:16:14 | [diff] [blame] | 34 | java_bridge_dispatcher_host_ = |
| 35 | new GinJavaBridgeDispatcherHost(web_contents, retained_objects); |
Jinsuk Kim | e376d0d | 2018-01-02 23:23:21 | [diff] [blame] | 36 | web_contents->SetUserData(UserDataKey(), base::WrapUnique(this)); |
Jinsuk Kim | a6490f8 | 2018-01-02 02:16:14 | [diff] [blame] | 37 | } |
| 38 | |
| 39 | JavascriptInjector::~JavascriptInjector() { |
| 40 | JNIEnv* env = AttachCurrentThread(); |
| 41 | ScopedJavaLocalRef<jobject> j_obj = java_ref_.get(env); |
| 42 | if (j_obj.is_null()) |
| 43 | return; |
| 44 | Java_JavascriptInjectorImpl_onDestroy(env, j_obj); |
| 45 | } |
| 46 | |
| 47 | void JavascriptInjector::SetAllowInspection(JNIEnv* env, |
Jinsuk Kim | a6490f8 | 2018-01-02 02:16:14 | [diff] [blame] | 48 | jboolean allow) { |
| 49 | DCHECK(java_bridge_dispatcher_host_); |
| 50 | java_bridge_dispatcher_host_->SetAllowObjectContentsInspection(allow); |
| 51 | } |
| 52 | |
Rupert Ben Wiser | 36b4404d | 2025-06-05 16:15:19 | [diff] [blame] | 53 | void JavascriptInjector::AddInterface( |
Jinsuk Kim | a6490f8 | 2018-01-02 02:16:14 | [diff] [blame] | 54 | JNIEnv* env, |
Jinsuk Kim | a6490f8 | 2018-01-02 02:16:14 | [diff] [blame] | 55 | const JavaParamRef<jobject>& object, |
| 56 | const JavaParamRef<jstring>& name, |
Rupert Ben Wiser | b7d1894f | 2025-04-02 19:13:15 | [diff] [blame] | 57 | const JavaParamRef<jclass>& safe_annotation_clazz, |
Rupert Ben Wiser | 36b4404d | 2025-06-05 16:15:19 | [diff] [blame] | 58 | origin_matcher::OriginMatcher matcher) { |
Jinsuk Kim | a6490f8 | 2018-01-02 02:16:14 | [diff] [blame] | 59 | DCHECK(java_bridge_dispatcher_host_); |
Hiroki Nakagawa | c1e5801 | 2024-05-07 23:43:41 | [diff] [blame] | 60 | |
Hiroki Nakagawa | c1e5801 | 2024-05-07 23:43:41 | [diff] [blame] | 61 | // If a new js object is added or removed when a page is in BFCache or |
| 62 | // prerendered, the change won't apply after activating the page. To avoid |
| 63 | // this behavior difference when these features are involved vs not, |
| 64 | // evict all BFCached and prerendered pages so that we won't activate any |
| 65 | // pages that don't have this object modified. |
Jiacheng Guo | 7117d5c9b | 2024-04-17 23:37:31 | [diff] [blame] | 66 | // Same for RemoveInterface below. |
Jiacheng Guo | 44cb912 | 2024-06-07 14:56:43 | [diff] [blame] | 67 | GetWebContents().GetController().GetBackForwardCache().Flush( |
| 68 | content::BackForwardCache::NotRestoredReason:: |
| 69 | kWebViewJavaScriptObjectChanged); |
Hiroki Nakagawa | c1e5801 | 2024-05-07 23:43:41 | [diff] [blame] | 70 | GetWebContentsImpl().GetPrerenderHostRegistry()->CancelAllHosts( |
| 71 | PrerenderFinalStatus::kJavaScriptInterfaceAdded); |
| 72 | |
Jinsuk Kim | a6490f8 | 2018-01-02 02:16:14 | [diff] [blame] | 73 | java_bridge_dispatcher_host_->AddNamedObject( |
Rupert Ben Wiser | b7d1894f | 2025-04-02 19:13:15 | [diff] [blame] | 74 | ConvertJavaStringToUTF8(env, name), object, safe_annotation_clazz, |
| 75 | std::move(matcher)); |
Jinsuk Kim | a6490f8 | 2018-01-02 02:16:14 | [diff] [blame] | 76 | } |
| 77 | |
| 78 | void JavascriptInjector::RemoveInterface(JNIEnv* env, |
Jinsuk Kim | a6490f8 | 2018-01-02 02:16:14 | [diff] [blame] | 79 | const JavaParamRef<jstring>& name) { |
| 80 | DCHECK(java_bridge_dispatcher_host_); |
Hiroki Nakagawa | c1e5801 | 2024-05-07 23:43:41 | [diff] [blame] | 81 | |
Jiacheng Guo | 44cb912 | 2024-06-07 14:56:43 | [diff] [blame] | 82 | GetWebContents().GetController().GetBackForwardCache().Flush( |
| 83 | content::BackForwardCache::NotRestoredReason:: |
| 84 | kWebViewJavaScriptObjectChanged); |
Hiroki Nakagawa | c1e5801 | 2024-05-07 23:43:41 | [diff] [blame] | 85 | GetWebContentsImpl().GetPrerenderHostRegistry()->CancelAllHosts( |
| 86 | PrerenderFinalStatus::kJavaScriptInterfaceRemoved); |
| 87 | |
Jinsuk Kim | a6490f8 | 2018-01-02 02:16:14 | [diff] [blame] | 88 | java_bridge_dispatcher_host_->RemoveNamedObject( |
| 89 | ConvertJavaStringToUTF8(env, name)); |
| 90 | } |
| 91 | |
Hiroki Nakagawa | c1e5801 | 2024-05-07 23:43:41 | [diff] [blame] | 92 | WebContentsImpl& JavascriptInjector::GetWebContentsImpl() { |
| 93 | return static_cast<WebContentsImpl&>(GetWebContents()); |
| 94 | } |
| 95 | |
Jinsuk Kim | a6490f8 | 2018-01-02 02:16:14 | [diff] [blame] | 96 | jlong JNI_JavascriptInjectorImpl_Init( |
| 97 | JNIEnv* env, |
| 98 | const JavaParamRef<jobject>& obj, |
| 99 | const JavaParamRef<jobject>& jweb_contents, |
| 100 | const JavaParamRef<jobject>& retained_objects) { |
| 101 | auto* web_contents = WebContents::FromJavaWebContents(jweb_contents); |
| 102 | CHECK(web_contents) << "Should be created with a valid WebContents."; |
| 103 | DCHECK(!JavascriptInjector::FromWebContents(web_contents)); |
| 104 | |
| 105 | // Owned by |web_contents|. |
| 106 | auto* injector = |
| 107 | new JavascriptInjector(env, obj, retained_objects, web_contents); |
| 108 | return reinterpret_cast<intptr_t>(injector); |
| 109 | } |
| 110 | |
Daniel Cheng | 383df85 | 2021-10-02 03:28:01 | [diff] [blame] | 111 | WEB_CONTENTS_USER_DATA_KEY_IMPL(JavascriptInjector); |
François Doray | 4f51d5d | 2018-12-03 22:26:24 | [diff] [blame] | 112 | |
Jinsuk Kim | a6490f8 | 2018-01-02 02:16:14 | [diff] [blame] | 113 | } // namespace content |