// Copyright 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "android_webview/browser/aw_contents.h" #include #include #include #include #include "android_webview/browser/aw_autofill_client.h" #include "android_webview/browser/aw_browser_context.h" #include "android_webview/browser/aw_browser_main_parts.h" #include "android_webview/browser/aw_contents_client_bridge.h" #include "android_webview/browser/aw_contents_io_thread_client.h" #include "android_webview/browser/aw_pdf_exporter.h" #include "android_webview/browser/aw_render_process.h" #include "android_webview/browser/aw_renderer_priority.h" #include "android_webview/browser/aw_resource_context.h" #include "android_webview/browser/aw_settings.h" #include "android_webview/browser/aw_web_contents_delegate.h" #include "android_webview/browser/gfx/aw_gl_functor.h" #include "android_webview/browser/gfx/aw_picture.h" #include "android_webview/browser/gfx/browser_view_renderer.h" #include "android_webview/browser/gfx/child_frame.h" #include "android_webview/browser/gfx/gpu_service_webview.h" #include "android_webview/browser/gfx/java_browser_view_renderer_helper.h" #include "android_webview/browser/gfx/render_thread_manager.h" #include "android_webview/browser/gfx/scoped_app_gl_state_restore.h" #include "android_webview/browser/js_java_interaction/aw_web_message_host_factory.h" #include "android_webview/browser/lifecycle/aw_contents_lifecycle_notifier.h" #include "android_webview/browser/page_load_metrics/page_load_metrics_initialize.h" #include "android_webview/browser/permission/aw_permission_request.h" #include "android_webview/browser/permission/permission_request_handler.h" #include "android_webview/browser/permission/simple_permission_request.h" #include "android_webview/browser/state_serializer.h" #include "android_webview/browser_jni_headers/AwContents_jni.h" #include "android_webview/common/aw_switches.h" #include "android_webview/common/devtools_instrumentation.h" #include "android_webview/common/mojom/frame.mojom.h" #include "base/android/jni_android.h" #include "base/android/jni_array.h" #include "base/android/jni_string.h" #include "base/android/locale_utils.h" #include "base/android/scoped_java_ref.h" #include "base/atomicops.h" #include "base/bind.h" #include "base/callback.h" #include "base/callback_helpers.h" #include "base/command_line.h" #include "base/feature_list.h" #include "base/i18n/rtl.h" #include "base/json/json_writer.h" #include "base/location.h" #include "base/memory/memory_pressure_listener.h" #include "base/memory/raw_ptr.h" #include "base/no_destructor.h" #include "base/pickle.h" #include "base/supports_user_data.h" #include "base/task/single_thread_task_runner.h" #include "base/threading/thread_restrictions.h" #include "base/threading/thread_task_runner_handle.h" #include "components/android_autofill/browser/android_autofill_manager.h" #include "components/android_autofill/browser/autofill_provider_android.h" #include "components/autofill/content/browser/content_autofill_driver_factory.h" #include "components/autofill/core/browser/webdata/autofill_webdata_service.h" #include "components/autofill/core/common/autofill_features.h" #include "components/navigation_interception/intercept_navigation_delegate.h" #include "components/safe_browsing/core/common/features.h" #include "components/security_interstitials/content/security_interstitial_tab_helper.h" #include "components/viz/common/surfaces/frame_sink_id.h" #include "content/public/browser/android/child_process_importance.h" #include "content/public/browser/android/synchronous_compositor.h" #include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/browsing_data_remover.h" #include "content/public/browser/child_process_security_policy.h" #include "content/public/browser/favicon_status.h" #include "content/public/browser/navigation_entry.h" #include "content/public/browser/navigation_handle.h" #include "content/public/browser/page.h" #include "content/public/browser/render_frame_host.h" #include "content/public/browser/render_process_host.h" #include "content/public/browser/render_view_host.h" #include "content/public/browser/render_widget_host.h" #include "content/public/browser/render_widget_host_iterator.h" #include "content/public/browser/ssl_status.h" #include "content/public/browser/web_contents.h" #include "content/public/common/mhtml_generation_params.h" #include "net/base/auth.h" #include "net/base/registry_controlled_domains/registry_controlled_domain.h" #include "net/cert/x509_certificate.h" #include "net/cert/x509_util.h" #include "third_party/skia/include/core/SkPicture.h" #include "ui/gfx/android/java_bitmap.h" #include "ui/gfx/geometry/rect_f.h" #include "ui/gfx/geometry/size.h" #include "ui/gfx/image/image.h" #include "url/origin.h" #include "url/url_constants.h" struct AwDrawSWFunctionTable; using autofill::ContentAutofillDriverFactory; using base::android::AttachCurrentThread; using base::android::ConvertJavaStringToUTF16; using base::android::ConvertJavaStringToUTF8; using base::android::ConvertUTF16ToJavaString; using base::android::ConvertUTF8ToJavaString; using base::android::HasException; using base::android::JavaParamRef; using base::android::JavaRef; using base::android::ScopedJavaGlobalRef; using base::android::ScopedJavaLocalRef; using content::BrowserThread; using content::RenderFrameHost; using content::WebContents; using js_injection::JsCommunicationHost; using navigation_interception::InterceptNavigationDelegate; namespace android_webview { class CompositorFrameConsumer; namespace { bool g_should_download_favicons = false; std::string* g_locale() { static base::NoDestructor locale; return locale.get(); } std::string* g_locale_list() { static base::NoDestructor locale_list; return locale_list.get(); } const void* const kAwContentsUserDataKey = &kAwContentsUserDataKey; const void* const kComputedRendererPriorityUserDataKey = &kComputedRendererPriorityUserDataKey; class AwContentsUserData : public base::SupportsUserData::Data { public: explicit AwContentsUserData(AwContents* ptr) : contents_(ptr) {} static AwContents* GetContents(WebContents* web_contents) { if (!web_contents) return NULL; AwContentsUserData* data = static_cast( web_contents->GetUserData(kAwContentsUserDataKey)); return data ? data->contents_.get() : NULL; } private: raw_ptr contents_; }; base::subtle::Atomic32 g_instance_count = 0; } // namespace class ScopedAllowInitGLBindings { public: ScopedAllowInitGLBindings() {} ~ScopedAllowInitGLBindings() {} private: base::ScopedAllowBlocking allow_blocking_; }; // static AwContents* AwContents::FromWebContents(WebContents* web_contents) { DCHECK_CURRENTLY_ON(BrowserThread::UI); return AwContentsUserData::GetContents(web_contents); } // static void JNI_AwContents_UpdateDefaultLocale( JNIEnv* env, const JavaParamRef& locale, const JavaParamRef& locale_list) { *g_locale() = ConvertJavaStringToUTF8(env, locale); *g_locale_list() = ConvertJavaStringToUTF8(env, locale_list); } // static std::string AwContents::GetLocale() { return *g_locale(); } // static std::string AwContents::GetLocaleList() { return *g_locale_list(); } // static AwBrowserPermissionRequestDelegate* AwBrowserPermissionRequestDelegate::FromID( int render_process_id, int render_frame_id) { AwContents* aw_contents = AwContents::FromWebContents(content::WebContents::FromRenderFrameHost( content::RenderFrameHost::FromID(render_process_id, render_frame_id))); return aw_contents; } // static AwSafeBrowsingUIManager::UIManagerClient* AwSafeBrowsingUIManager::UIManagerClient::FromWebContents( WebContents* web_contents) { return AwContents::FromWebContents(web_contents); } // static AwRenderProcessGoneDelegate* AwRenderProcessGoneDelegate::FromWebContents( content::WebContents* web_contents) { return AwContents::FromWebContents(web_contents); } AwContents::AwContents(std::unique_ptr web_contents) : content::WebContentsObserver(web_contents.get()), browser_view_renderer_(this, content::GetUIThreadTaskRunner({})), web_contents_(std::move(web_contents)) { base::subtle::NoBarrier_AtomicIncrement(&g_instance_count, 1); icon_helper_ = std::make_unique(web_contents_.get()); icon_helper_->SetListener(this); web_contents_->SetUserData(android_webview::kAwContentsUserDataKey, std::make_unique(this)); browser_view_renderer_.RegisterWithWebContents(web_contents_.get()); viz::FrameSinkId frame_sink_id; if (web_contents_->GetRenderViewHost()) { frame_sink_id = web_contents_->GetRenderViewHost()->GetWidget()->GetFrameSinkId(); } browser_view_renderer_.SetActiveFrameSinkId(frame_sink_id); render_view_host_ext_ = std::make_unique(this, web_contents_.get()); InitializePageLoadMetricsForWebContents(web_contents_.get()); permission_request_handler_ = std::make_unique(this, web_contents_.get()); AwAutofillClient* browser_autofill_manager_delegate = AwAutofillClient::FromWebContents(web_contents_.get()); if (browser_autofill_manager_delegate) { InitAutofillIfNecessary( browser_autofill_manager_delegate->GetSaveFormData()); } content::SynchronousCompositor::SetClientForWebContents( web_contents_.get(), &browser_view_renderer_); AwContentsLifecycleNotifier::GetInstance().OnWebViewCreated(this); AwBrowserProcess::GetInstance()->visibility_metrics_logger()->AddClient(this); } void AwContents::SetJavaPeers( JNIEnv* env, const JavaParamRef& aw_contents, const JavaParamRef& web_contents_delegate, const JavaParamRef& contents_client_bridge, const JavaParamRef& io_thread_client, const JavaParamRef& intercept_navigation_delegate) { DCHECK_CURRENTLY_ON(BrowserThread::UI); // The |aw_content| param is technically spurious as it duplicates |obj| but // is passed over anyway to make the binding more explicit. java_ref_ = JavaObjectWeakGlobalRef(env, aw_contents); web_contents_delegate_ = std::make_unique(env, web_contents_delegate); web_contents_->SetDelegate(web_contents_delegate_.get()); contents_client_bridge_ = std::make_unique(env, contents_client_bridge); AwContentsClientBridge::Associate(web_contents_.get(), contents_client_bridge_.get()); AwContentsIoThreadClient::Associate(web_contents_.get(), io_thread_client); InterceptNavigationDelegate::Associate( web_contents_.get(), std::make_unique( env, intercept_navigation_delegate)); } void AwContents::InitializeAndroidAutofill(JNIEnv* env) { // Initialize Android Autofill, this method shall only be called in Android O // and beyond. // AutofillProvider shall already be created for |web_contents_| from // AutofillProvider java. DCHECK(autofill::AutofillProvider::FromWebContents(web_contents_.get())); // Autocomplete is only supported for Android pre-O, disable it if Android // autofill is enabled. InitAutofillIfNecessary(/*autocomplete_enabled=*/false); } void AwContents::SetSaveFormData(bool enabled) { DCHECK_CURRENTLY_ON(BrowserThread::UI); InitAutofillIfNecessary(enabled); // We need to check for the existence, since browser_autofill_manager_delegate // may not be created when the setting is false. if (AwAutofillClient::FromWebContents(web_contents_.get())) { AwAutofillClient::FromWebContents(web_contents_.get()) ->SetSaveFormData(enabled); } } void AwContents::InitAutofillIfNecessary(bool autocomplete_enabled) { DCHECK_CURRENTLY_ON(BrowserThread::UI); // This method initializes either Android autofill or Chrome autocomplete: // - If autofill_provider is available, Android autofill shall be initialized. // - Otherwise, initialize Chrome autocomplete if autocomplete_enabled. // Check if the autofill driver factory already exists. content::WebContents* web_contents = web_contents_.get(); if (ContentAutofillDriverFactory::FromWebContents(web_contents)) return; // The autofill_provider object shall already be created by the // AutofillProvider Java object in Android O and beyond. auto* autofill_provider = autofill::AutofillProvider::FromWebContents(web_contents); // Just return, if the app neither runs on O sdk nor enables autocomplete. if (!autofill_provider && !autocomplete_enabled) return; autofill::AutofillManager::EnableDownloadManager enable_download_manager( !autofill::AutofillProvider::is_download_manager_disabled_for_testing()); AwAutofillClient::CreateForWebContents(web_contents); // WebView browser tests may shall use BrowserAutofillManager if // `!autofill_provider`. ContentAutofillDriverFactory::DriverInitCallback driver_init_hook = autofill_provider ? base::BindRepeating(&autofill::AndroidDriverInitHook, AwAutofillClient::FromWebContents(web_contents), enable_download_manager) : base::BindRepeating(&autofill::BrowserDriverInitHook, AwAutofillClient::FromWebContents(web_contents), base::android::GetDefaultLocaleString()); ContentAutofillDriverFactory::CreateForWebContentsAndDelegate( web_contents, AwAutofillClient::FromWebContents(web_contents), std::move(driver_init_hook)); } void AwContents::SetAwAutofillClient(const JavaRef& client) { DCHECK_CURRENTLY_ON(BrowserThread::UI); JNIEnv* env = AttachCurrentThread(); ScopedJavaLocalRef obj = java_ref_.get(env); if (!obj) return; Java_AwContents_setAwAutofillClient(env, obj, client); } AwContents::~AwContents() { DCHECK_EQ(this, AwContents::FromWebContents(web_contents_.get())); web_contents_->RemoveUserData(kAwContentsUserDataKey); AwContentsClientBridge::Dissociate(web_contents_.get()); if (find_helper_.get()) find_helper_->SetListener(NULL); if (icon_helper_.get()) icon_helper_->SetListener(NULL); base::subtle::Atomic32 instance_count = base::subtle::NoBarrier_AtomicIncrement(&g_instance_count, -1); // When the last WebView is destroyed free all discardable memory allocated by // Chromium, because the app process may continue to run for a long time // without ever using another WebView. if (instance_count == 0) { // TODO(timvolodine): consider moving NotifyMemoryPressure to // AwContentsLifecycleNotifier (crbug.com/522988). base::MemoryPressureListener::NotifyMemoryPressure( base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL); } browser_view_renderer_.SetCurrentCompositorFrameConsumer(nullptr); AwContentsLifecycleNotifier::GetInstance().OnWebViewDestroyed(this); WebContentsObserver::Observe(nullptr); AwBrowserProcess::GetInstance()->visibility_metrics_logger()->RemoveClient( this); } base::android::ScopedJavaLocalRef AwContents::GetWebContents( JNIEnv* env) { DCHECK_CURRENTLY_ON(BrowserThread::UI); DCHECK(web_contents_); if (!web_contents_) return base::android::ScopedJavaLocalRef(); return web_contents_->GetJavaWebContents(); } base::android::ScopedJavaLocalRef AwContents::GetBrowserContext( JNIEnv* env) { if (!web_contents_) return base::android::ScopedJavaLocalRef(); return AwBrowserContext::FromWebContents(web_contents_.get()) ->GetJavaBrowserContext(); } void AwContents::SetCompositorFrameConsumer(JNIEnv* env, jlong compositor_frame_consumer) { browser_view_renderer_.SetCurrentCompositorFrameConsumer( reinterpret_cast(compositor_frame_consumer)); } ScopedJavaLocalRef AwContents::GetRenderProcess(JNIEnv* env) { DCHECK_CURRENTLY_ON(BrowserThread::UI); content::RenderProcessHost* host = web_contents_->GetPrimaryMainFrame()->GetProcess(); if (host->run_renderer_in_process()) { return ScopedJavaLocalRef(); } AwRenderProcess* render_process = AwRenderProcess::GetInstanceForRenderProcessHost(host); return render_process->GetJavaObject(); } void AwContents::Destroy(JNIEnv* env) { java_ref_.reset(); delete this; } static jlong JNI_AwContents_Init(JNIEnv* env, jlong browser_context_pointer) { AwBrowserContext* browser_context = reinterpret_cast(browser_context_pointer); std::unique_ptr web_contents(content::WebContents::Create( content::WebContents::CreateParams(browser_context))); // Return an 'uninitialized' instance; most work is deferred until the // subsequent SetJavaPeers() call. return reinterpret_cast(new AwContents(std::move(web_contents))); } static jboolean JNI_AwContents_HasRequiredHardwareExtensions(JNIEnv* env) { ScopedAllowInitGLBindings scoped_allow_init_gl_bindings; // Make sure GPUInfo is collected. This will initialize GL bindings, // collect GPUInfo, and compute GpuFeatureInfo if they have not been // already done. return GpuServiceWebView::GetInstance() ->gpu_info() .can_support_threaded_texture_mailbox; } static void JNI_AwContents_SetAwDrawSWFunctionTable(JNIEnv* env, jlong function_table) { RasterHelperSetAwDrawSWFunctionTable( reinterpret_cast(function_table)); } static void JNI_AwContents_SetAwDrawGLFunctionTable(JNIEnv* env, jlong function_table) {} static void JNI_AwContents_UpdateScreenCoverage( JNIEnv* env, jint global_percentage, const base::android::JavaParamRef& jschemes, const base::android::JavaParamRef& jscheme_percentages) { std::vector schemes; AppendJavaStringArrayToStringVector(env, jschemes, &schemes); std::vector scheme_percentages; JavaIntArrayToIntVector(env, jscheme_percentages, &scheme_percentages); DCHECK(schemes.size() == scheme_percentages.size()); std::vector scheme_enums(schemes.size()); for (size_t i = 0; i < schemes.size(); i++) { scheme_enums[i] = VisibilityMetricsLogger::SchemeStringToEnum(schemes[i]); } AwBrowserProcess::GetInstance() ->visibility_metrics_logger() ->UpdateScreenCoverage(global_percentage, scheme_enums, scheme_percentages); } // static jint JNI_AwContents_GetNativeInstanceCount(JNIEnv* env) { return base::subtle::NoBarrier_Load(&g_instance_count); } // static ScopedJavaLocalRef JNI_AwContents_GetSafeBrowsingLocaleForTesting( JNIEnv* env) { ScopedJavaLocalRef locale = ConvertUTF8ToJavaString(env, base::i18n::GetConfiguredLocale()); return locale; } namespace { void DocumentHasImagesCallback(const ScopedJavaGlobalRef& message, bool has_images) { Java_AwContents_onDocumentHasImagesResponse(AttachCurrentThread(), has_images, message); } } // namespace void AwContents::DocumentHasImages(JNIEnv* env, const JavaParamRef& message) { DCHECK_CURRENTLY_ON(BrowserThread::UI); ScopedJavaGlobalRef j_message; j_message.Reset(env, message); render_view_host_ext_->DocumentHasImages( base::BindOnce(&DocumentHasImagesCallback, j_message)); } namespace { void GenerateMHTMLCallback(const JavaRef& callback, const base::FilePath& path, int64_t size) { JNIEnv* env = AttachCurrentThread(); // Android files are UTF8, so the path conversion below is safe. Java_AwContents_generateMHTMLCallback( env, ConvertUTF8ToJavaString(env, path.AsUTF8Unsafe()), size, callback); } } // namespace void AwContents::GenerateMHTML(JNIEnv* env, const JavaParamRef& jpath, const JavaParamRef& callback) { DCHECK_CURRENTLY_ON(BrowserThread::UI); base::FilePath target_path(ConvertJavaStringToUTF8(env, jpath)); web_contents_->GenerateMHTML( content::MHTMLGenerationParams(target_path), base::BindOnce(&GenerateMHTMLCallback, ScopedJavaGlobalRef(env, callback), target_path)); } void AwContents::CreatePdfExporter(JNIEnv* env, const JavaParamRef& pdfExporter) { pdf_exporter_ = std::make_unique(env, pdfExporter, web_contents_.get()); } bool AwContents::OnReceivedHttpAuthRequest(const JavaRef& handler, const std::string& host, const std::string& realm) { DCHECK_CURRENTLY_ON(BrowserThread::UI); JNIEnv* env = AttachCurrentThread(); ScopedJavaLocalRef obj = java_ref_.get(env); if (!obj) return false; ScopedJavaLocalRef jhost = ConvertUTF8ToJavaString(env, host); ScopedJavaLocalRef jrealm = ConvertUTF8ToJavaString(env, realm); devtools_instrumentation::ScopedEmbedderCallbackTask embedder_callback( "onReceivedHttpAuthRequest"); Java_AwContents_onReceivedHttpAuthRequest(env, obj, handler, jhost, jrealm); return true; } void AwContents::SetOffscreenPreRaster(bool enabled) { DCHECK_CURRENTLY_ON(BrowserThread::UI); browser_view_renderer_.SetOffscreenPreRaster(enabled); } void AwContents::AddVisitedLinks( JNIEnv* env, const JavaParamRef& jvisited_links) { DCHECK_CURRENTLY_ON(BrowserThread::UI); std::vector visited_link_strings; base::android::AppendJavaStringArrayToStringVector(env, jvisited_links, &visited_link_strings); std::vector visited_link_gurls; std::vector::const_iterator itr; for (itr = visited_link_strings.begin(); itr != visited_link_strings.end(); ++itr) { visited_link_gurls.push_back(GURL(*itr)); } AwBrowserContext::FromWebContents(web_contents_.get()) ->AddVisitedURLs(visited_link_gurls); } namespace { void ShowGeolocationPromptHelperTask(const JavaObjectWeakGlobalRef& java_ref, const GURL& origin) { JNIEnv* env = AttachCurrentThread(); ScopedJavaLocalRef j_ref = java_ref.get(env); if (j_ref.obj()) { ScopedJavaLocalRef j_origin( ConvertUTF8ToJavaString(env, origin.spec())); devtools_instrumentation::ScopedEmbedderCallbackTask embedder_callback( "onGeolocationPermissionsShowPrompt"); Java_AwContents_onGeolocationPermissionsShowPrompt(env, j_ref, j_origin); } } void ShowGeolocationPromptHelper(const JavaObjectWeakGlobalRef& java_ref, const GURL& origin) { JNIEnv* env = AttachCurrentThread(); if (java_ref.get(env).obj()) { content::GetUIThreadTaskRunner({})->PostTask( FROM_HERE, base::BindOnce(&ShowGeolocationPromptHelperTask, java_ref, origin)); } } } // anonymous namespace void AwContents::ShowGeolocationPrompt(const GURL& requesting_frame, PermissionCallback callback) { DCHECK_CURRENTLY_ON(BrowserThread::UI); GURL origin = requesting_frame.DeprecatedGetOriginAsURL(); bool show_prompt = pending_geolocation_prompts_.empty(); pending_geolocation_prompts_.emplace_back(origin, std::move(callback)); if (show_prompt) { ShowGeolocationPromptHelper(java_ref_, origin); } } // Invoked from Java void AwContents::InvokeGeolocationCallback( JNIEnv* env, jboolean value, const JavaParamRef& origin) { DCHECK_CURRENTLY_ON(BrowserThread::UI); if (pending_geolocation_prompts_.empty()) return; GURL callback_origin(base::android::ConvertJavaStringToUTF16(env, origin)); if (callback_origin.DeprecatedGetOriginAsURL() == pending_geolocation_prompts_.front().first) { std::move(pending_geolocation_prompts_.front().second).Run(value); pending_geolocation_prompts_.pop_front(); if (!pending_geolocation_prompts_.empty()) { ShowGeolocationPromptHelper(java_ref_, pending_geolocation_prompts_.front().first); } } } void AwContents::HideGeolocationPrompt(const GURL& origin) { DCHECK_CURRENTLY_ON(BrowserThread::UI); bool removed_current_outstanding_callback = false; std::list::iterator it = pending_geolocation_prompts_.begin(); while (it != pending_geolocation_prompts_.end()) { if ((*it).first == origin.DeprecatedGetOriginAsURL()) { if (it == pending_geolocation_prompts_.begin()) { removed_current_outstanding_callback = true; } it = pending_geolocation_prompts_.erase(it); } else { ++it; } } if (removed_current_outstanding_callback) { JNIEnv* env = AttachCurrentThread(); ScopedJavaLocalRef j_ref = java_ref_.get(env); if (j_ref.obj()) { devtools_instrumentation::ScopedEmbedderCallbackTask embedder_callback( "onGeolocationPermissionsHidePrompt"); Java_AwContents_onGeolocationPermissionsHidePrompt(env, j_ref); } if (!pending_geolocation_prompts_.empty()) { ShowGeolocationPromptHelper(java_ref_, pending_geolocation_prompts_.front().first); } } } void AwContents::OnPermissionRequest( base::android::ScopedJavaLocalRef j_request, AwPermissionRequest* request) { DCHECK(j_request); DCHECK(request); JNIEnv* env = AttachCurrentThread(); ScopedJavaLocalRef j_ref = java_ref_.get(env); if (!j_ref) { permission_request_handler_->CancelRequest(request->GetOrigin(), request->GetResources()); return; } Java_AwContents_onPermissionRequest(env, j_ref, j_request); } void AwContents::OnPermissionRequestCanceled(AwPermissionRequest* request) { JNIEnv* env = AttachCurrentThread(); ScopedJavaLocalRef j_request = request->GetJavaObject(); ScopedJavaLocalRef j_ref = java_ref_.get(env); if (!j_request || !j_ref) return; Java_AwContents_onPermissionRequestCanceled(env, j_ref, j_request); } void AwContents::PreauthorizePermission(JNIEnv* env, const JavaParamRef& origin, jlong resources) { permission_request_handler_->PreauthorizePermission( GURL(base::android::ConvertJavaStringToUTF8(env, origin)), resources); } void AwContents::RequestProtectedMediaIdentifierPermission( const GURL& origin, PermissionCallback callback) { permission_request_handler_->SendRequest( std::make_unique( origin, AwPermissionRequest::ProtectedMediaId, std::move(callback))); } void AwContents::CancelProtectedMediaIdentifierPermissionRequests( const GURL& origin) { permission_request_handler_->CancelRequest( origin, AwPermissionRequest::ProtectedMediaId); } void AwContents::RequestGeolocationPermission(const GURL& origin, PermissionCallback callback) { JNIEnv* env = AttachCurrentThread(); ScopedJavaLocalRef obj = java_ref_.get(env); if (!obj) return; if (Java_AwContents_useLegacyGeolocationPermissionAPI(env, obj)) { ShowGeolocationPrompt(origin, std::move(callback)); return; } permission_request_handler_->SendRequest( std::make_unique( origin, AwPermissionRequest::Geolocation, std::move(callback))); } void AwContents::CancelGeolocationPermissionRequests(const GURL& origin) { JNIEnv* env = AttachCurrentThread(); ScopedJavaLocalRef obj = java_ref_.get(env); if (!obj) return; if (Java_AwContents_useLegacyGeolocationPermissionAPI(env, obj)) { HideGeolocationPrompt(origin); return; } permission_request_handler_->CancelRequest(origin, AwPermissionRequest::Geolocation); } void AwContents::RequestMIDISysexPermission(const GURL& origin, PermissionCallback callback) { permission_request_handler_->SendRequest( std::make_unique( origin, AwPermissionRequest::MIDISysex, std::move(callback))); } void AwContents::CancelMIDISysexPermissionRequests(const GURL& origin) { permission_request_handler_->CancelRequest( origin, AwPermissionRequest::AwPermissionRequest::MIDISysex); } void AwContents::FindAllAsync(JNIEnv* env, const JavaParamRef& search_string) { DCHECK_CURRENTLY_ON(BrowserThread::UI); GetFindHelper()->FindAllAsync(ConvertJavaStringToUTF16(env, search_string)); } void AwContents::FindNext(JNIEnv* env, jboolean forward) { DCHECK_CURRENTLY_ON(BrowserThread::UI); GetFindHelper()->FindNext(forward); } void AwContents::ClearMatches(JNIEnv* env) { DCHECK_CURRENTLY_ON(BrowserThread::UI); GetFindHelper()->ClearMatches(); } void AwContents::ClearCache(JNIEnv* env, jboolean include_disk_files) { DCHECK_CURRENTLY_ON(BrowserThread::UI); AwRenderProcess* aw_render_process = AwRenderProcess::GetInstanceForRenderProcessHost( web_contents_->GetPrimaryMainFrame()->GetProcess()); aw_render_process->ClearCache(); if (include_disk_files) { content::BrowsingDataRemover* remover = web_contents_->GetBrowserContext()->GetBrowsingDataRemover(); remover->Remove( base::Time(), base::Time::Max(), content::BrowsingDataRemover::DATA_TYPE_CACHE, content::BrowsingDataRemover::ORIGIN_TYPE_UNPROTECTED_WEB | content::BrowsingDataRemover::ORIGIN_TYPE_PROTECTED_WEB); } } FindHelper* AwContents::GetFindHelper() { DCHECK_CURRENTLY_ON(BrowserThread::UI); if (!find_helper_.get()) { find_helper_ = std::make_unique(web_contents_.get()); find_helper_->SetListener(this); } return find_helper_.get(); } bool AwContents::AllowThirdPartyCookies() { DCHECK_CURRENTLY_ON(BrowserThread::UI); AwSettings* aw_settings = AwSettings::FromWebContents(web_contents_.get()); return aw_settings->GetAllowThirdPartyCookies(); } void AwContents::OnFindResultReceived(int active_ordinal, int match_count, bool finished) { DCHECK_CURRENTLY_ON(BrowserThread::UI); JNIEnv* env = AttachCurrentThread(); ScopedJavaLocalRef obj = java_ref_.get(env); if (!obj) return; Java_AwContents_onFindResultReceived(env, obj, active_ordinal, match_count, finished); } bool AwContents::ShouldDownloadFavicon(const GURL& icon_url) { return g_should_download_favicons; } void AwContents::OnReceivedIcon(const GURL& icon_url, const SkBitmap& bitmap) { DCHECK_CURRENTLY_ON(BrowserThread::UI); JNIEnv* env = AttachCurrentThread(); ScopedJavaLocalRef obj = java_ref_.get(env); if (!obj) return; content::NavigationEntry* entry = web_contents_->GetController().GetLastCommittedEntry(); if (entry) { entry->GetFavicon().valid = true; entry->GetFavicon().url = icon_url; entry->GetFavicon().image = gfx::Image::CreateFrom1xBitmap(bitmap); } ScopedJavaLocalRef java_bitmap = gfx::ConvertToJavaBitmap(bitmap, gfx::OomBehavior::kReturnNullOnOom); if (!java_bitmap) { LOG(WARNING) << "Skipping onReceivedIcon; Not enough memory to convert " "icon to Bitmap."; return; } Java_AwContents_onReceivedIcon(env, obj, java_bitmap); } void AwContents::OnReceivedTouchIconUrl(const std::string& url, bool precomposed) { DCHECK_CURRENTLY_ON(BrowserThread::UI); JNIEnv* env = AttachCurrentThread(); ScopedJavaLocalRef obj = java_ref_.get(env); if (!obj) return; Java_AwContents_onReceivedTouchIconUrl( env, obj, ConvertUTF8ToJavaString(env, url), precomposed); } void AwContents::PostInvalidate(bool inside_vsync) { DCHECK_CURRENTLY_ON(BrowserThread::UI); JNIEnv* env = AttachCurrentThread(); ScopedJavaLocalRef obj = java_ref_.get(env); if (obj) Java_AwContents_postInvalidate(env, obj, inside_vsync); } void AwContents::OnNewPicture() { DCHECK_CURRENTLY_ON(BrowserThread::UI); JNIEnv* env = AttachCurrentThread(); ScopedJavaLocalRef obj = java_ref_.get(env); if (obj) { devtools_instrumentation::ScopedEmbedderCallbackTask embedder_callback( "onNewPicture"); Java_AwContents_onNewPicture(env, obj); } } void AwContents::OnViewTreeForceDarkStateChanged( bool view_tree_force_dark_state) { view_tree_force_dark_state_ = view_tree_force_dark_state; web_contents_->NotifyPreferencesChanged(); } base::android::ScopedJavaLocalRef AwContents::GetCertificate( JNIEnv* env) { DCHECK_CURRENTLY_ON(BrowserThread::UI); content::NavigationEntry* entry = web_contents_->GetController().GetLastCommittedEntry(); if (!entry || entry->IsInitialEntry() || !entry->GetSSL().certificate) { return ScopedJavaLocalRef(); } // Convert the certificate and return it base::StringPiece der_string = net::x509_util::CryptoBufferAsStringPiece( entry->GetSSL().certificate->cert_buffer()); return base::android::ToJavaByteArray( env, reinterpret_cast(der_string.data()), der_string.length()); } void AwContents::RequestNewHitTestDataAt(JNIEnv* env, jfloat x, jfloat y, jfloat touch_major) { DCHECK_CURRENTLY_ON(BrowserThread::UI); gfx::PointF touch_center(x, y); gfx::SizeF touch_area(touch_major, touch_major); render_view_host_ext_->RequestNewHitTestDataAt(touch_center, touch_area); } void AwContents::UpdateLastHitTestData(JNIEnv* env) { DCHECK_CURRENTLY_ON(BrowserThread::UI); ScopedJavaLocalRef obj = java_ref_.get(env); if (!obj) return; android_webview::mojom::HitTestDataPtr data = render_view_host_ext_->TakeLastHitTestData(); if (!data) return; // Make sure to null the Java object if data is empty/invalid. ScopedJavaLocalRef extra_data_for_type; if (data->extra_data_for_type.length()) extra_data_for_type = ConvertUTF8ToJavaString(env, data->extra_data_for_type); ScopedJavaLocalRef href; if (data->href.length()) href = ConvertUTF16ToJavaString(env, data->href); ScopedJavaLocalRef anchor_text; if (data->anchor_text.length()) anchor_text = ConvertUTF16ToJavaString(env, data->anchor_text); ScopedJavaLocalRef img_src; if (data->img_src.is_valid()) img_src = ConvertUTF8ToJavaString(env, data->img_src.spec()); Java_AwContents_updateHitTestData(env, obj, static_cast(data->type), extra_data_for_type, href, anchor_text, img_src); } void AwContents::OnSizeChanged(JNIEnv* env, int w, int h, int ow, int oh) { DCHECK_CURRENTLY_ON(BrowserThread::UI); gfx::Size size(w, h); web_contents_->GetNativeView()->OnPhysicalBackingSizeChanged(size); web_contents_->GetNativeView()->OnSizeChanged(w, h); browser_view_renderer_.OnSizeChanged(w, h); AwBrowserProcess::GetInstance() ->visibility_metrics_logger() ->ClientVisibilityChanged(this); } void AwContents::OnConfigurationChanged(JNIEnv* env) { DCHECK_CURRENTLY_ON(BrowserThread::UI); web_contents()->OnWebPreferencesChanged(); } void AwContents::SetViewVisibility(JNIEnv* env, bool visible) { DCHECK_CURRENTLY_ON(BrowserThread::UI); browser_view_renderer_.SetViewVisibility(visible); AwBrowserProcess::GetInstance() ->visibility_metrics_logger() ->ClientVisibilityChanged(this); } void AwContents::SetWindowVisibility(JNIEnv* env, bool visible) { DCHECK_CURRENTLY_ON(BrowserThread::UI); browser_view_renderer_.SetWindowVisibility(visible); if (visible) AwContentsLifecycleNotifier::GetInstance().OnWebViewWindowBeVisible(this); else AwContentsLifecycleNotifier::GetInstance().OnWebViewWindowBeInvisible(this); AwBrowserProcess::GetInstance() ->visibility_metrics_logger() ->ClientVisibilityChanged(this); } void AwContents::SetIsPaused(JNIEnv* env, bool paused) { DCHECK_CURRENTLY_ON(BrowserThread::UI); browser_view_renderer_.SetIsPaused(paused); } void AwContents::OnAttachedToWindow(JNIEnv* env, int w, int h) { DCHECK_CURRENTLY_ON(BrowserThread::UI); browser_view_renderer_.OnAttachedToWindow(w, h); AwContentsLifecycleNotifier::GetInstance().OnWebViewAttachedToWindow(this); AwBrowserProcess::GetInstance() ->visibility_metrics_logger() ->ClientVisibilityChanged(this); } void AwContents::OnDetachedFromWindow(JNIEnv* env) { DCHECK_CURRENTLY_ON(BrowserThread::UI); browser_view_renderer_.OnDetachedFromWindow(); AwContentsLifecycleNotifier::GetInstance().OnWebViewDetachedFromWindow(this); AwBrowserProcess::GetInstance() ->visibility_metrics_logger() ->ClientVisibilityChanged(this); } bool AwContents::IsVisible(JNIEnv* env) { return browser_view_renderer_.IsClientVisible(); } bool AwContents::IsDisplayingInterstitialForTesting(JNIEnv* env) { security_interstitials::SecurityInterstitialTabHelper* security_interstitial_tab_helper = security_interstitials:: SecurityInterstitialTabHelper::FromWebContents(web_contents_.get()); return security_interstitial_tab_helper && security_interstitial_tab_helper->IsDisplayingInterstitial(); } base::android::ScopedJavaLocalRef AwContents::GetOpaqueState( JNIEnv* env) { DCHECK_CURRENTLY_ON(BrowserThread::UI); // Required optimization in WebViewClassic to not save any state if // there has been no navigations. if (!web_contents_->GetController().GetLastCommittedEntry() || web_contents_->GetController() .GetLastCommittedEntry() ->IsInitialEntry()) { return ScopedJavaLocalRef(); } base::Pickle pickle; WriteToPickle(*web_contents_, &pickle); return base::android::ToJavaByteArray( env, reinterpret_cast(pickle.data()), pickle.size()); } jboolean AwContents::RestoreFromOpaqueState( JNIEnv* env, const JavaParamRef& state) { DCHECK_CURRENTLY_ON(BrowserThread::UI); // TODO(boliu): This copy can be optimized out if this is a performance // problem. std::vector state_vector; base::android::JavaByteArrayToByteVector(env, state, &state_vector); base::Pickle pickle(reinterpret_cast(state_vector.data()), state_vector.size()); base::PickleIterator iterator(pickle); return RestoreFromPickle(&iterator, web_contents_.get()); } bool AwContents::OnDraw(JNIEnv* env, const JavaParamRef& canvas, jboolean is_hardware_accelerated, jint scroll_x, jint scroll_y, jint visible_left, jint visible_top, jint visible_right, jint visible_bottom, jboolean force_auxiliary_bitmap_rendering) { DCHECK_CURRENTLY_ON(BrowserThread::UI); gfx::Point scroll(scroll_x, scroll_y); browser_view_renderer_.PrepareToDraw( scroll, gfx::Rect(visible_left, visible_top, visible_right - visible_left, visible_bottom - visible_top)); if (is_hardware_accelerated && browser_view_renderer_.attached_to_window() && !force_auxiliary_bitmap_rendering) { return browser_view_renderer_.OnDrawHardware(); } gfx::Size view_size = browser_view_renderer_.size(); if (view_size.IsEmpty()) { TRACE_EVENT_INSTANT0("android_webview", "EarlyOut_EmptySize", TRACE_EVENT_SCOPE_THREAD); return false; } // TODO(hush): Right now webview size is passed in as the auxiliary bitmap // size, which might hurt performance (only for software draws with auxiliary // bitmap). For better performance, get global visible rect, transform it // from screen space to view space, then intersect with the webview in // viewspace. Use the resulting rect as the auxiliary bitmap. std::unique_ptr canvas_holder = SoftwareCanvasHolder::Create(canvas, scroll, view_size, force_auxiliary_bitmap_rendering); if (!canvas_holder || !canvas_holder->GetCanvas()) { TRACE_EVENT_INSTANT0("android_webview", "EarlyOut_NoSoftwareCanvas", TRACE_EVENT_SCOPE_THREAD); return false; } return browser_view_renderer_.OnDrawSoftware(canvas_holder->GetCanvas()); } bool AwContents::NeedToDrawBackgroundColor(JNIEnv* env) { return browser_view_renderer_.NeedToDrawBackgroundColor(); } void AwContents::SetPendingWebContentsForPopup( std::unique_ptr pending) { DCHECK_CURRENTLY_ON(BrowserThread::UI); if (pending_contents_.get()) { // TODO(benm): Support holding multiple pop up window requests. LOG(WARNING) << "Blocking popup window creation as an outstanding " << "popup window is still pending."; base::ThreadTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE, pending.release()); return; } pending_contents_ = std::make_unique(std::move(pending)); // Set dip_scale for pending contents, which is necessary for the later // SynchronousCompositor and InputHandler setup. pending_contents_->SetDipScaleInternal(browser_view_renderer_.dip_scale()); } void AwContents::FocusFirstNode(JNIEnv* env) { DCHECK_CURRENTLY_ON(BrowserThread::UI); web_contents_->FocusThroughTabTraversal(false); } void AwContents::SetBackgroundColor(JNIEnv* env, jint color) { DCHECK_CURRENTLY_ON(BrowserThread::UI); web_contents_->SetPageBaseBackgroundColor(color); } void AwContents::ZoomBy(JNIEnv* env, jfloat delta) { DCHECK_CURRENTLY_ON(BrowserThread::UI); browser_view_renderer_.ZoomBy(delta); } void AwContents::OnComputeScroll(JNIEnv* env, jlong animation_time_millis) { DCHECK_CURRENTLY_ON(BrowserThread::UI); browser_view_renderer_.OnComputeScroll( base::TimeTicks() + base::Milliseconds(animation_time_millis)); } jlong AwContents::ReleasePopupAwContents(JNIEnv* env) { DCHECK_CURRENTLY_ON(BrowserThread::UI); return reinterpret_cast(pending_contents_.release()); } gfx::Point AwContents::GetLocationOnScreen() { DCHECK_CURRENTLY_ON(BrowserThread::UI); JNIEnv* env = AttachCurrentThread(); ScopedJavaLocalRef obj = java_ref_.get(env); if (!obj) return gfx::Point(); std::vector location; base::android::JavaIntArrayToIntVector( env, Java_AwContents_getLocationOnScreen(env, obj), &location); return gfx::Point(location[0], location[1]); } void AwContents::ScrollContainerViewTo(const gfx::Point& new_value) { DCHECK_CURRENTLY_ON(BrowserThread::UI); JNIEnv* env = AttachCurrentThread(); ScopedJavaLocalRef obj = java_ref_.get(env); if (!obj) return; Java_AwContents_scrollContainerViewTo(env, obj, new_value.x(), new_value.y()); } void AwContents::UpdateScrollState(const gfx::Point& max_scroll_offset, const gfx::SizeF& contents_size_dip, float page_scale_factor, float min_page_scale_factor, float max_page_scale_factor) { DCHECK_CURRENTLY_ON(BrowserThread::UI); JNIEnv* env = AttachCurrentThread(); ScopedJavaLocalRef obj = java_ref_.get(env); if (!obj) return; Java_AwContents_updateScrollState( env, obj, max_scroll_offset.x(), max_scroll_offset.y(), contents_size_dip.width(), contents_size_dip.height(), page_scale_factor, min_page_scale_factor, max_page_scale_factor); } void AwContents::DidOverscroll(const gfx::Vector2d& overscroll_delta, const gfx::Vector2dF& overscroll_velocity, bool inside_vsync) { DCHECK_CURRENTLY_ON(BrowserThread::UI); JNIEnv* env = AttachCurrentThread(); ScopedJavaLocalRef obj = java_ref_.get(env); if (!obj) return; Java_AwContents_didOverscroll(env, obj, overscroll_delta.x(), overscroll_delta.y(), overscroll_velocity.x(), overscroll_velocity.y(), inside_vsync); } ui::TouchHandleDrawable* AwContents::CreateDrawable() { JNIEnv* env = AttachCurrentThread(); const ScopedJavaLocalRef obj = java_ref_.get(env); if (!obj) return nullptr; return reinterpret_cast( Java_AwContents_onCreateTouchHandle(env, obj)); } void AwContents::SetDipScale(JNIEnv* env, jfloat dip_scale) { DCHECK_CURRENTLY_ON(BrowserThread::UI); SetDipScaleInternal(dip_scale); } base::android::ScopedJavaLocalRef AwContents::GetScheme(JNIEnv* env) { return ConvertUTF8ToJavaString(env, scheme_); } void AwContents::OnInputEvent(JNIEnv* env) { browser_view_renderer_.OnInputEvent(); } void AwContents::SetDipScaleInternal(float dip_scale) { browser_view_renderer_.SetDipScale(dip_scale); } void AwContents::ScrollTo(JNIEnv* env, jint x, jint y) { DCHECK_CURRENTLY_ON(BrowserThread::UI); browser_view_renderer_.ScrollTo(gfx::Point(x, y)); } void AwContents::RestoreScrollAfterTransition(JNIEnv* env, jint x, jint y) { DCHECK_CURRENTLY_ON(BrowserThread::UI); browser_view_renderer_.RestoreScrollAfterTransition(gfx::Point(x, y)); } void AwContents::SmoothScroll(JNIEnv* env, jint target_x, jint target_y, jlong duration_ms) { DCHECK_CURRENTLY_ON(BrowserThread::UI); float scale = browser_view_renderer_.page_scale_factor(); DCHECK_GE(duration_ms, 0); render_view_host_ext_->SmoothScroll(target_x / scale, target_y / scale, base::Milliseconds(duration_ms)); } void AwContents::OnWebLayoutPageScaleFactorChanged(float page_scale_factor) { DCHECK_CURRENTLY_ON(BrowserThread::UI); JNIEnv* env = AttachCurrentThread(); ScopedJavaLocalRef obj = java_ref_.get(env); if (!obj) return; Java_AwContents_onWebLayoutPageScaleFactorChanged(env, obj, page_scale_factor); } void AwContents::OnWebLayoutContentsSizeChanged( const gfx::Size& contents_size) { DCHECK_CURRENTLY_ON(BrowserThread::UI); JNIEnv* env = AttachCurrentThread(); ScopedJavaLocalRef obj = java_ref_.get(env); if (!obj) return; gfx::Size contents_size_css = ScaleToRoundedSize(contents_size, 1 / browser_view_renderer_.dip_scale()); Java_AwContents_onWebLayoutContentsSizeChanged( env, obj, contents_size_css.width(), contents_size_css.height()); } jlong AwContents::CapturePicture(JNIEnv* env, int width, int height) { DCHECK_CURRENTLY_ON(BrowserThread::UI); return reinterpret_cast( new AwPicture(browser_view_renderer_.CapturePicture(width, height))); } void AwContents::EnableOnNewPicture(JNIEnv* env, jboolean enabled) { DCHECK_CURRENTLY_ON(BrowserThread::UI); browser_view_renderer_.EnableOnNewPicture(enabled); } namespace { void InvokeVisualStateCallback(const JavaObjectWeakGlobalRef& java_ref, jlong request_id, const JavaRef& callback, bool result) { JNIEnv* env = AttachCurrentThread(); ScopedJavaLocalRef obj = java_ref.get(env); if (!obj) return; Java_AwContents_invokeVisualStateCallback(env, obj, callback, request_id); } } // namespace void AwContents::InsertVisualStateCallback( JNIEnv* env, jlong request_id, const JavaParamRef& callback) { DCHECK_CURRENTLY_ON(BrowserThread::UI); web_contents_->GetPrimaryMainFrame()->InsertVisualStateCallback( base::BindOnce(&InvokeVisualStateCallback, java_ref_, request_id, ScopedJavaGlobalRef(env, callback))); } jint AwContents::GetEffectivePriority(JNIEnv* env) { switch (web_contents_->GetPrimaryMainFrame() ->GetProcess() ->GetEffectiveImportance()) { case content::ChildProcessImportance::NORMAL: return static_cast(RendererPriority::WAIVED); case content::ChildProcessImportance::MODERATE: return static_cast(RendererPriority::LOW); case content::ChildProcessImportance::IMPORTANT: return static_cast(RendererPriority::HIGH); } NOTREACHED(); return 0; } JsCommunicationHost* AwContents::GetJsCommunicationHost() { DCHECK_CURRENTLY_ON(BrowserThread::UI); if (!js_communication_host_.get()) { js_communication_host_ = std::make_unique(web_contents_.get()); } return js_communication_host_.get(); } jint AwContents::AddDocumentStartJavaScript( JNIEnv* env, const base::android::JavaParamRef& script, const base::android::JavaParamRef& allowed_origin_rules) { std::vector native_allowed_origin_rule_strings; AppendJavaStringArrayToStringVector(env, allowed_origin_rules, &native_allowed_origin_rule_strings); auto result = GetJsCommunicationHost()->AddDocumentStartJavaScript( base::android::ConvertJavaStringToUTF16(env, script), native_allowed_origin_rule_strings); if (result.error_message) { env->ThrowNew(env->FindClass("java/lang/IllegalArgumentException"), result.error_message->data()); return -1; } DCHECK(result.script_id); return result.script_id.value(); } void AwContents::RemoveDocumentStartJavaScript(JNIEnv* env, jint script_id) { GetJsCommunicationHost()->RemoveDocumentStartJavaScript(script_id); } base::android::ScopedJavaLocalRef AwContents::AddWebMessageListener( JNIEnv* env, const base::android::JavaParamRef& listener, const base::android::JavaParamRef& js_object_name, const base::android::JavaParamRef& allowed_origin_rules) { std::u16string native_js_object_name = base::android::ConvertJavaStringToUTF16(env, js_object_name); std::vector native_allowed_origin_rule_strings; AppendJavaStringArrayToStringVector(env, allowed_origin_rules, &native_allowed_origin_rule_strings); const std::u16string error_message = GetJsCommunicationHost()->AddWebMessageHostFactory( std::make_unique(listener), native_js_object_name, native_allowed_origin_rule_strings); if (error_message.empty()) return nullptr; return base::android::ConvertUTF16ToJavaString(env, error_message); } void AwContents::RemoveWebMessageListener( JNIEnv* env, const base::android::JavaParamRef& js_object_name) { GetJsCommunicationHost()->RemoveWebMessageHostFactory( ConvertJavaStringToUTF16(env, js_object_name)); } base::android::ScopedJavaLocalRef AwContents::GetJsObjectsInfo( JNIEnv* env, const base::android::JavaParamRef& clazz) { if (js_communication_host_.get()) { return AwWebMessageHostFactory::GetWebMessageListenerInfo( GetJsCommunicationHost(), env, clazz); } return nullptr; } void AwContents::ClearView(JNIEnv* env) { DCHECK_CURRENTLY_ON(BrowserThread::UI); browser_view_renderer_.ClearView(); } void AwContents::SetExtraHeadersForUrl( JNIEnv* env, const JavaParamRef& url, const JavaParamRef& jextra_headers) { std::string extra_headers; if (jextra_headers) extra_headers = ConvertJavaStringToUTF8(env, jextra_headers); AwResourceContext* resource_context = static_cast( AwBrowserContext::FromWebContents(web_contents_.get()) ->GetResourceContext()); resource_context->SetExtraHeaders(GURL(ConvertJavaStringToUTF8(env, url)), extra_headers); } void AwContents::SetJsOnlineProperty(JNIEnv* env, jboolean network_up) { DCHECK_CURRENTLY_ON(BrowserThread::UI); AwRenderProcess* aw_render_process = AwRenderProcess::GetInstanceForRenderProcessHost( web_contents_->GetPrimaryMainFrame()->GetProcess()); aw_render_process->SetJsOnlineProperty(network_up); } void AwContents::TrimMemory(JNIEnv* env, jint level, jboolean visible) { DCHECK_CURRENTLY_ON(BrowserThread::UI); // Constants from Android ComponentCallbacks2. enum { TRIM_MEMORY_RUNNING_LOW = 10, TRIM_MEMORY_UI_HIDDEN = 20, TRIM_MEMORY_BACKGROUND = 40, TRIM_MEMORY_MODERATE = 60, }; // Not urgent enough. TRIM_MEMORY_UI_HIDDEN is treated specially because // it does not indicate memory pressure, but merely that the app is // backgrounded. if (level < TRIM_MEMORY_RUNNING_LOW || level == TRIM_MEMORY_UI_HIDDEN) return; // Do not release resources on view we expect to get DrawGL soon. if (level < TRIM_MEMORY_BACKGROUND && visible) return; browser_view_renderer_.TrimMemory(); } void AwContents::GrantFileSchemeAccesstoChildProcess(JNIEnv* env) { content::ChildProcessSecurityPolicy::GetInstance()->GrantRequestScheme( web_contents_->GetPrimaryMainFrame()->GetProcess()->GetID(), url::kFileScheme); } void AwContents::ResumeLoadingCreatedPopupWebContents(JNIEnv* env) { web_contents_->ResumeLoadingCreatedWebContents(); } void JNI_AwContents_SetShouldDownloadFavicons(JNIEnv* env) { g_should_download_favicons = true; } void AwContents::RenderViewHostChanged(content::RenderViewHost* old_host, content::RenderViewHost* new_host) { DCHECK(new_host); // At this point, the current RVH may or may not contain a compositor. So // compositor_ may be nullptr, in which case // BrowserViewRenderer::DidInitializeCompositor() callback is time when the // new compositor is constructed. browser_view_renderer_.SetActiveFrameSinkId( new_host->GetWidget()->GetFrameSinkId()); } void AwContents::PrimaryPageChanged(content::Page& page) { const url::Origin& origin = page.GetMainDocument().GetLastCommittedOrigin(); const std::string& scheme = origin.scheme(); const std::string& etld_plus1 = net::registry_controlled_domains::GetDomainAndRegistry( origin, net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES); if (scheme_ != scheme) { scheme_ = scheme; AwBrowserProcess::GetInstance() ->visibility_metrics_logger() ->ClientVisibilityChanged(this); } if (scheme == url::kHttpsScheme || scheme == url::kHttpScheme) { JNIEnv* env = AttachCurrentThread(); ScopedJavaLocalRef j_ref = java_ref_.get(env); if (j_ref) { uint32_t origin_hash = base::PersistentHash(origin.Serialize()); uint32_t etld_plus1_hash = base::PersistentHash(etld_plus1); jlong j_origin_hash = static_cast(origin_hash); jlong j_etld_plus1_hash = static_cast(etld_plus1_hash); Java_AwContents_logOriginVisit(env, j_ref, j_origin_hash); Java_AwContents_logSiteVisit(env, j_ref, j_etld_plus1_hash); } } } void AwContents::DidFinishNavigation( content::NavigationHandle* navigation_handle) { // If this request was blocked in any way, broadcast an error. net::Error error_code = navigation_handle->GetNetErrorCode(); if (!net::IsRequestBlockedError(error_code) && error_code != net::ERR_ABORTED) { return; } // We do not call OnReceivedError for requests that were blocked due to an // interstitial showing. OnReceivedError is handled directly by the blocking // page for interstitials. if (web_contents_) { // We can't be showing an interstitial if there is no web_contents. security_interstitials::SecurityInterstitialTabHelper* security_interstitial_tab_helper = security_interstitials:: SecurityInterstitialTabHelper::FromWebContents(web_contents_.get()); if (security_interstitial_tab_helper && (security_interstitial_tab_helper->IsInterstitialPendingForNavigation( navigation_handle->GetNavigationId()) || security_interstitial_tab_helper->IsDisplayingInterstitial())) { return; } } AwContentsClientBridge* client = AwContentsClientBridge::FromWebContents(web_contents_.get()); if (!client) return; AwWebResourceRequest request(navigation_handle->GetURL().spec(), navigation_handle->IsPost() ? "POST" : "GET", navigation_handle->IsInPrimaryMainFrame(), navigation_handle->HasUserGesture(), net::HttpRequestHeaders()); request.is_renderer_initiated = navigation_handle->IsRendererInitiated(); client->OnReceivedError(request, error_code, false, false); } bool AwContents::CanShowInterstitial() { JNIEnv* env = AttachCurrentThread(); const ScopedJavaLocalRef obj = java_ref_.get(env); if (!obj) return false; return Java_AwContents_canShowInterstitial(env, obj); } int AwContents::GetErrorUiType() { JNIEnv* env = AttachCurrentThread(); const ScopedJavaLocalRef obj = java_ref_.get(env); if (!obj) return false; return Java_AwContents_getErrorUiType(env, obj); } VisibilityMetricsLogger::VisibilityInfo AwContents::GetVisibilityInfo() { return VisibilityMetricsLogger::VisibilityInfo{ browser_view_renderer_.attached_to_window(), browser_view_renderer_.view_visible(), browser_view_renderer_.window_visible(), VisibilityMetricsLogger::SchemeStringToEnum(scheme_)}; } void AwContents::RendererUnresponsive( content::RenderProcessHost* render_process_host) { DCHECK_CURRENTLY_ON(BrowserThread::UI); JNIEnv* env = AttachCurrentThread(); ScopedJavaLocalRef obj = java_ref_.get(env); if (!obj) return; AwRenderProcess* aw_render_process = AwRenderProcess::GetInstanceForRenderProcessHost(render_process_host); Java_AwContents_onRendererUnresponsive(env, obj, aw_render_process->GetJavaObject()); } void AwContents::RendererResponsive( content::RenderProcessHost* render_process_host) { DCHECK_CURRENTLY_ON(BrowserThread::UI); JNIEnv* env = AttachCurrentThread(); ScopedJavaLocalRef obj = java_ref_.get(env); if (!obj) return; AwRenderProcess* aw_render_process = AwRenderProcess::GetInstanceForRenderProcessHost(render_process_host); Java_AwContents_onRendererResponsive(env, obj, aw_render_process->GetJavaObject()); } AwContents::RenderProcessGoneResult AwContents::OnRenderProcessGone( int child_process_id, bool crashed) { DCHECK_CURRENTLY_ON(BrowserThread::UI); JNIEnv* env = AttachCurrentThread(); ScopedJavaLocalRef obj = java_ref_.get(env); if (!obj) return RenderProcessGoneResult::kHandled; bool result = Java_AwContents_onRenderProcessGone(env, obj, child_process_id, crashed); if (HasException(env)) return RenderProcessGoneResult::kException; return result ? RenderProcessGoneResult::kHandled : RenderProcessGoneResult::kUnhandled; } } // namespace android_webview