1 // Copyright (c) 2012 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.
5 #include "android_webview/browser/aw_content_browser_client.h"
7 #include "android_webview/browser/aw_browser_context.h"
8 #include "android_webview/browser/aw_browser_main_parts.h"
9 #include "android_webview/browser/aw_contents_client_bridge_base.h"
10 #include "android_webview/browser/aw_contents_io_thread_client.h"
11 #include "android_webview/browser/aw_cookie_access_policy.h"
12 #include "android_webview/browser/aw_locale_manager.h"
13 #include "android_webview/browser/aw_printing_message_filter.h"
14 #include "android_webview/browser/aw_quota_permission_context.h"
15 #include "android_webview/browser/aw_web_preferences_populater.h"
16 #include "android_webview/browser/jni_dependency_factory.h"
17 #include "android_webview/browser/net/aw_url_request_context_getter.h"
18 #include "android_webview/browser/net_disk_cache_remover.h"
19 #include "android_webview/browser/renderer_host/aw_resource_dispatcher_host_delegate.h"
20 #include "android_webview/common/aw_descriptors.h"
21 #include "android_webview/common/render_view_messages.h"
22 #include "android_webview/common/url_constants.h"
23 #include "base/android/locale_utils.h"
24 #include "base/base_paths_android.h"
25 #include "base/command_line.h"
26 #include "base/path_service.h"
27 #include "components/cdm/browser/cdm_message_filter_android.h"
28 #include "components/navigation_interception/intercept_navigation_delegate.h"
29 #include "content/public/browser/access_token_store.h"
30 #include "content/public/browser/browser_message_filter.h"
31 #include "content/public/browser/child_process_security_policy.h"
32 #include "content/public/browser/client_certificate_delegate.h"
33 #include "content/public/browser/navigation_handle.h"
34 #include "content/public/browser/navigation_throttle.h"
35 #include "content/public/browser/render_frame_host.h"
36 #include "content/public/browser/render_process_host.h"
37 #include "content/public/browser/render_view_host.h"
38 #include "content/public/browser/web_contents.h"
39 #include "content/public/common/content_switches.h"
40 #include "content/public/common/url_constants.h"
41 #include "content/public/common/web_preferences.h"
42 #include "net/android/network_library.h"
43 #include "net/ssl/ssl_cert_request_info.h"
44 #include "net/ssl/ssl_info.h"
45 #include "ui/base/resource/resource_bundle.h"
46 #include "ui/base/resource/resource_bundle_android.h"
47 #include "ui/resources/grit/ui_resources.h"
49 using content::ResourceType
;
51 namespace android_webview
{
54 // TODO(sgurun) move this to its own file.
55 // This class filters out incoming aw_contents related IPC messages for the
56 // renderer process on the IPC thread.
57 class AwContentsMessageFilter
: public content::BrowserMessageFilter
{
59 explicit AwContentsMessageFilter(int process_id
);
61 // BrowserMessageFilter methods.
62 bool OnMessageReceived(const IPC::Message
& message
) override
;
64 void OnSubFrameCreated(int parent_render_frame_id
, int child_render_frame_id
);
67 ~AwContentsMessageFilter() override
;
71 DISALLOW_COPY_AND_ASSIGN(AwContentsMessageFilter
);
74 AwContentsMessageFilter::AwContentsMessageFilter(int process_id
)
75 : BrowserMessageFilter(AndroidWebViewMsgStart
),
76 process_id_(process_id
) {
79 AwContentsMessageFilter::~AwContentsMessageFilter() {
82 bool AwContentsMessageFilter::OnMessageReceived(const IPC::Message
& message
) {
84 IPC_BEGIN_MESSAGE_MAP(AwContentsMessageFilter
, message
)
85 IPC_MESSAGE_HANDLER(AwViewHostMsg_SubFrameCreated
, OnSubFrameCreated
)
86 IPC_MESSAGE_UNHANDLED(handled
= false)
91 void AwContentsMessageFilter::OnSubFrameCreated(int parent_render_frame_id
,
92 int child_render_frame_id
) {
93 AwContentsIoThreadClient::SubFrameCreated(
94 process_id_
, parent_render_frame_id
, child_render_frame_id
);
97 class AwAccessTokenStore
: public content::AccessTokenStore
{
99 AwAccessTokenStore() { }
101 // content::AccessTokenStore implementation
102 void LoadAccessTokens(const LoadAccessTokensCallbackType
& request
) override
{
103 AccessTokenStore::AccessTokenSet access_token_set
;
104 // AccessTokenSet and net::URLRequestContextGetter not used on Android,
105 // but Run needs to be called to finish the geolocation setup.
106 request
.Run(access_token_set
, NULL
);
108 void SaveAccessToken(const GURL
& server_url
,
109 const base::string16
& access_token
) override
{}
112 ~AwAccessTokenStore() override
{}
114 DISALLOW_COPY_AND_ASSIGN(AwAccessTokenStore
);
117 AwLocaleManager
* g_locale_manager
= NULL
;
119 } // anonymous namespace
122 std::string
AwContentBrowserClient::GetAcceptLangsImpl() {
123 // Start with the current locale.
124 std::string langs
= g_locale_manager
->GetLocale();
126 // If we're not en-US, add in en-US which will be
127 // used with a lower q-value.
128 if (base::ToLowerASCII(langs
) != "en-us") {
135 AwBrowserContext
* AwContentBrowserClient::GetAwBrowserContext() {
136 return AwBrowserContext::GetDefault();
139 AwContentBrowserClient::AwContentBrowserClient(
140 JniDependencyFactory
* native_factory
)
141 : native_factory_(native_factory
) {
142 base::FilePath user_data_dir
;
143 if (!PathService::Get(base::DIR_ANDROID_APP_DATA
, &user_data_dir
)) {
144 NOTREACHED() << "Failed to get app data directory for Android WebView";
146 browser_context_
.reset(
147 new AwBrowserContext(user_data_dir
, native_factory_
));
148 g_locale_manager
= native_factory
->CreateAwLocaleManager();
151 AwContentBrowserClient::~AwContentBrowserClient() {
152 delete g_locale_manager
;
153 g_locale_manager
= NULL
;
156 void AwContentBrowserClient::AddCertificate(net::CertificateMimeType cert_type
,
157 const void* cert_data
,
159 int render_process_id
,
160 int render_frame_id
) {
162 net::android::StoreCertificate(cert_type
, cert_data
, cert_size
);
165 content::BrowserMainParts
* AwContentBrowserClient::CreateBrowserMainParts(
166 const content::MainFunctionParams
& parameters
) {
167 return new AwBrowserMainParts(browser_context_
.get());
170 content::WebContentsViewDelegate
*
171 AwContentBrowserClient::GetWebContentsViewDelegate(
172 content::WebContents
* web_contents
) {
173 return native_factory_
->CreateViewDelegate(web_contents
);
176 void AwContentBrowserClient::RenderProcessWillLaunch(
177 content::RenderProcessHost
* host
) {
178 // Grant content: scheme access to the whole renderer process, since we impose
179 // per-view access checks, and access is granted by default (see
180 // AwSettings.mAllowContentUrlAccess).
181 content::ChildProcessSecurityPolicy::GetInstance()->GrantScheme(
182 host
->GetID(), url::kContentScheme
);
184 host
->AddFilter(new AwContentsMessageFilter(host
->GetID()));
185 host
->AddFilter(new cdm::CdmMessageFilterAndroid());
186 host
->AddFilter(new AwPrintingMessageFilter(host
->GetID()));
189 net::URLRequestContextGetter
* AwContentBrowserClient::CreateRequestContext(
190 content::BrowserContext
* browser_context
,
191 content::ProtocolHandlerMap
* protocol_handlers
,
192 content::URLRequestInterceptorScopedVector request_interceptors
) {
193 DCHECK_EQ(browser_context_
.get(), browser_context
);
194 return browser_context_
->CreateRequestContext(protocol_handlers
,
195 request_interceptors
.Pass());
198 net::URLRequestContextGetter
*
199 AwContentBrowserClient::CreateRequestContextForStoragePartition(
200 content::BrowserContext
* browser_context
,
201 const base::FilePath
& partition_path
,
203 content::ProtocolHandlerMap
* protocol_handlers
,
204 content::URLRequestInterceptorScopedVector request_interceptors
) {
205 DCHECK_EQ(browser_context_
.get(), browser_context
);
206 // TODO(mkosiba,kinuko): request_interceptors should be hooked up in the
207 // downstream. (crbug.com/350286)
208 return browser_context_
->CreateRequestContextForStoragePartition(
209 partition_path
, in_memory
, protocol_handlers
,
210 request_interceptors
.Pass());
213 bool AwContentBrowserClient::IsHandledURL(const GURL
& url
) {
214 if (!url
.is_valid()) {
215 // We handle error cases.
219 const std::string scheme
= url
.scheme();
220 DCHECK_EQ(scheme
, base::ToLowerASCII(scheme
));
221 // See CreateJobFactory in aw_url_request_context_getter.cc for the
222 // list of protocols that are handled.
223 // TODO(mnaganov): Make this automatic.
224 static const char* const kProtocolList
[] = {
227 url::kFileSystemScheme
,
228 content::kChromeUIScheme
,
229 content::kChromeDevToolsScheme
,
232 if (scheme
== url::kFileScheme
) {
233 // Return false for the "special" file URLs, so they can be loaded
234 // even if access to file: scheme is not granted to the child process.
235 return !IsAndroidSpecialFileUrl(url
);
237 for (size_t i
= 0; i
< arraysize(kProtocolList
); ++i
) {
238 if (scheme
== kProtocolList
[i
])
241 return net::URLRequest::IsHandledProtocol(scheme
);
244 std::string
AwContentBrowserClient::GetCanonicalEncodingNameByAliasName(
245 const std::string
& alias_name
) {
249 void AwContentBrowserClient::AppendExtraCommandLineSwitches(
250 base::CommandLine
* command_line
,
251 int child_process_id
) {
252 if (command_line
->HasSwitch(switches::kSingleProcess
)) {
253 NOTREACHED() << "Android WebView does not support multi-process yet";
255 // The only kind of a child process WebView can have is renderer.
256 DCHECK_EQ(switches::kRendererProcess
,
257 command_line
->GetSwitchValueASCII(switches::kProcessType
));
261 std::string
AwContentBrowserClient::GetApplicationLocale() {
262 return base::android::GetDefaultLocale();
265 std::string
AwContentBrowserClient::GetAcceptLangs(
266 content::BrowserContext
* context
) {
267 return GetAcceptLangsImpl();
270 const gfx::ImageSkia
* AwContentBrowserClient::GetDefaultFavicon() {
271 ResourceBundle
& rb
= ResourceBundle::GetSharedInstance();
272 // TODO(boliu): Bundle our own default favicon?
273 return rb
.GetImageSkiaNamed(IDR_DEFAULT_FAVICON
);
276 bool AwContentBrowserClient::AllowAppCache(const GURL
& manifest_url
,
277 const GURL
& first_party
,
278 content::ResourceContext
* context
) {
279 // WebView doesn't have a per-site policy for locally stored data,
280 // instead AppCache can be disabled for individual WebViews.
285 bool AwContentBrowserClient::AllowGetCookie(const GURL
& url
,
286 const GURL
& first_party
,
287 const net::CookieList
& cookie_list
,
288 content::ResourceContext
* context
,
289 int render_process_id
,
290 int render_frame_id
) {
291 return AwCookieAccessPolicy::GetInstance()->AllowGetCookie(url
,
299 bool AwContentBrowserClient::AllowSetCookie(const GURL
& url
,
300 const GURL
& first_party
,
301 const std::string
& cookie_line
,
302 content::ResourceContext
* context
,
303 int render_process_id
,
305 net::CookieOptions
* options
) {
306 return AwCookieAccessPolicy::GetInstance()->AllowSetCookie(url
,
315 bool AwContentBrowserClient::AllowWorkerDatabase(
317 const base::string16
& name
,
318 const base::string16
& display_name
,
319 unsigned long estimated_size
,
320 content::ResourceContext
* context
,
321 const std::vector
<std::pair
<int, int> >& render_frames
) {
322 // Android WebView does not yet support web workers.
326 void AwContentBrowserClient::AllowWorkerFileSystem(
328 content::ResourceContext
* context
,
329 const std::vector
<std::pair
<int, int> >& render_frames
,
330 base::Callback
<void(bool)> callback
) {
331 // Android WebView does not yet support web workers.
335 bool AwContentBrowserClient::AllowWorkerIndexedDB(
337 const base::string16
& name
,
338 content::ResourceContext
* context
,
339 const std::vector
<std::pair
<int, int> >& render_frames
) {
340 // Android WebView does not yet support web workers.
344 content::QuotaPermissionContext
*
345 AwContentBrowserClient::CreateQuotaPermissionContext() {
346 return new AwQuotaPermissionContext
;
349 void AwContentBrowserClient::AllowCertificateError(
350 int render_process_id
,
353 const net::SSLInfo
& ssl_info
,
354 const GURL
& request_url
,
355 ResourceType resource_type
,
357 bool strict_enforcement
,
358 bool expired_previous_decision
,
359 const base::Callback
<void(bool)>& callback
,
360 content::CertificateRequestResultType
* result
) {
361 AwContentsClientBridgeBase
* client
=
362 AwContentsClientBridgeBase::FromID(render_process_id
, render_frame_id
);
363 bool cancel_request
= true;
365 client
->AllowCertificateError(cert_error
,
371 *result
= content::CERTIFICATE_REQUEST_RESULT_TYPE_DENY
;
374 void AwContentBrowserClient::SelectClientCertificate(
375 content::WebContents
* web_contents
,
376 net::SSLCertRequestInfo
* cert_request_info
,
377 scoped_ptr
<content::ClientCertificateDelegate
> delegate
) {
378 AwContentsClientBridgeBase
* client
=
379 AwContentsClientBridgeBase::FromWebContents(web_contents
);
381 client
->SelectClientCertificate(cert_request_info
, delegate
.Pass());
384 bool AwContentBrowserClient::CanCreateWindow(
385 const GURL
& opener_url
,
386 const GURL
& opener_top_level_frame_url
,
387 const GURL
& source_origin
,
388 WindowContainerType container_type
,
389 const GURL
& target_url
,
390 const content::Referrer
& referrer
,
391 WindowOpenDisposition disposition
,
392 const blink::WebWindowFeatures
& features
,
394 bool opener_suppressed
,
395 content::ResourceContext
* context
,
396 int render_process_id
,
397 int opener_render_view_id
,
398 int opener_render_frame_id
,
399 bool* no_javascript_access
) {
400 // We unconditionally allow popup windows at this stage and will give
401 // the embedder the opporunity to handle displaying of the popup in
402 // WebContentsDelegate::AddContents (via the
403 // AwContentsClient.onCreateWindow callback).
404 // Note that if the embedder has blocked support for creating popup
405 // windows through AwSettings, then we won't get to this point as
406 // the popup creation will have been blocked at the WebKit level.
407 if (no_javascript_access
) {
408 *no_javascript_access
= false;
413 void AwContentBrowserClient::ResourceDispatcherHostCreated() {
414 AwResourceDispatcherHostDelegate::ResourceDispatcherHostCreated();
417 net::NetLog
* AwContentBrowserClient::GetNetLog() {
418 return browser_context_
->GetAwURLRequestContext()->GetNetLog();
421 content::AccessTokenStore
* AwContentBrowserClient::CreateAccessTokenStore() {
422 return new AwAccessTokenStore();
425 bool AwContentBrowserClient::IsFastShutdownPossible() {
426 NOTREACHED() << "Android WebView is single process, so IsFastShutdownPossible"
427 << " should never be called";
431 void AwContentBrowserClient::ClearCache(content::RenderFrameHost
* rfh
) {
432 RemoveHttpDiskCache(rfh
->GetProcess()->GetBrowserContext(),
433 rfh
->GetProcess()->GetID());
436 void AwContentBrowserClient::ClearCookies(content::RenderFrameHost
* rfh
) {
437 // TODO(boliu): Implement.
441 base::FilePath
AwContentBrowserClient::GetDefaultDownloadDirectory() {
442 // Android WebView does not currently use the Chromium downloads system.
443 // Download requests are cancelled immedately when recognized; see
444 // AwResourceDispatcherHost::CreateResourceHandlerForDownload. However the
445 // download system still tries to start up and calls this before recognizing
446 // the request has been cancelled.
447 return base::FilePath();
450 std::string
AwContentBrowserClient::GetDefaultDownloadName() {
451 NOTREACHED() << "Android WebView does not use chromium downloads";
452 return std::string();
455 void AwContentBrowserClient::DidCreatePpapiPlugin(
456 content::BrowserPpapiHost
* browser_host
) {
457 NOTREACHED() << "Android WebView does not support plugins";
460 bool AwContentBrowserClient::AllowPepperSocketAPI(
461 content::BrowserContext
* browser_context
,
464 const content::SocketPermissionRequest
* params
) {
465 NOTREACHED() << "Android WebView does not support plugins";
469 void AwContentBrowserClient::GetAdditionalMappedFilesForChildProcess(
470 const base::CommandLine
& command_line
,
471 int child_process_id
,
472 content::FileDescriptorInfo
* mappings
,
473 std::map
<int, base::MemoryMappedFile::Region
>* regions
) {
474 int fd
= ui::GetMainAndroidPackFd(
475 &(*regions
)[kAndroidWebViewMainPakDescriptor
]);
476 mappings
->Share(kAndroidWebViewMainPakDescriptor
, fd
);
478 fd
= ui::GetLocalePackFd(&(*regions
)[kAndroidWebViewLocalePakDescriptor
]);
479 mappings
->Share(kAndroidWebViewLocalePakDescriptor
, fd
);
482 void AwContentBrowserClient::OverrideWebkitPrefs(
483 content::RenderViewHost
* rvh
,
484 content::WebPreferences
* web_prefs
) {
485 if (!preferences_populater_
.get()) {
486 preferences_populater_
= make_scoped_ptr(native_factory_
->
487 CreateWebPreferencesPopulater());
489 preferences_populater_
->PopulateFor(
490 content::WebContents::FromRenderViewHost(rvh
), web_prefs
);
493 ScopedVector
<content::NavigationThrottle
>
494 AwContentBrowserClient::CreateThrottlesForNavigation(
495 content::NavigationHandle
* navigation_handle
) {
496 ScopedVector
<content::NavigationThrottle
> throttles
;
497 if (navigation_handle
->IsInMainFrame() ||
498 (!navigation_handle
->GetURL().SchemeIs(url::kHttpScheme
) &&
499 !navigation_handle
->GetURL().SchemeIs(url::kHttpsScheme
) &&
500 !navigation_handle
->GetURL().SchemeIs(url::kAboutScheme
))) {
502 navigation_interception::InterceptNavigationDelegate::CreateThrottleFor(
506 return throttles
.Pass();
509 #if defined(VIDEO_HOLE)
510 content::ExternalVideoSurfaceContainer
*
511 AwContentBrowserClient::OverrideCreateExternalVideoSurfaceContainer(
512 content::WebContents
* web_contents
) {
513 return native_factory_
->CreateExternalVideoSurfaceContainer(web_contents
);
517 } // namespace android_webview