Home | History | Annotate | Download | only in browser
      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.
      4 
      5 #include "android_webview/browser/aw_content_browser_client.h"
      6 
      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_browser_permission_request_delegate.h"
     10 #include "android_webview/browser/aw_contents_client_bridge_base.h"
     11 #include "android_webview/browser/aw_contents_io_thread_client.h"
     12 #include "android_webview/browser/aw_cookie_access_policy.h"
     13 #include "android_webview/browser/aw_dev_tools_manager_delegate.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/render_view_messages.h"
     21 #include "android_webview/common/url_constants.h"
     22 #include "base/base_paths_android.h"
     23 #include "base/path_service.h"
     24 #include "components/cdm/browser/cdm_message_filter_android.h"
     25 #include "content/public/browser/access_token_store.h"
     26 #include "content/public/browser/browser_message_filter.h"
     27 #include "content/public/browser/browser_thread.h"
     28 #include "content/public/browser/child_process_security_policy.h"
     29 #include "content/public/browser/render_process_host.h"
     30 #include "content/public/browser/render_view_host.h"
     31 #include "content/public/browser/web_contents.h"
     32 #include "content/public/common/url_constants.h"
     33 #include "content/public/common/web_preferences.h"
     34 #include "net/android/network_library.h"
     35 #include "net/ssl/ssl_cert_request_info.h"
     36 #include "net/ssl/ssl_info.h"
     37 #include "ui/base/l10n/l10n_util_android.h"
     38 #include "ui/base/resource/resource_bundle.h"
     39 #include "ui/resources/grit/ui_resources.h"
     40 
     41 using content::BrowserThread;
     42 using content::ResourceType;
     43 
     44 namespace android_webview {
     45 namespace {
     46 
     47 // TODO(sgurun) move this to its own file.
     48 // This class filters out incoming aw_contents related IPC messages for the
     49 // renderer process on the IPC thread.
     50 class AwContentsMessageFilter : public content::BrowserMessageFilter {
     51 public:
     52   explicit AwContentsMessageFilter(int process_id);
     53 
     54   // BrowserMessageFilter methods.
     55   virtual void OverrideThreadForMessage(
     56       const IPC::Message& message,
     57       BrowserThread::ID* thread) OVERRIDE;
     58   virtual bool OnMessageReceived(
     59       const IPC::Message& message) OVERRIDE;
     60 
     61   void OnShouldOverrideUrlLoading(int routing_id,
     62                                   const base::string16& url,
     63                                   bool* ignore_navigation);
     64   void OnSubFrameCreated(int parent_render_frame_id, int child_render_frame_id);
     65 
     66 private:
     67   virtual ~AwContentsMessageFilter();
     68 
     69   int process_id_;
     70 
     71   DISALLOW_COPY_AND_ASSIGN(AwContentsMessageFilter);
     72 };
     73 
     74 AwContentsMessageFilter::AwContentsMessageFilter(int process_id)
     75     : BrowserMessageFilter(AndroidWebViewMsgStart),
     76       process_id_(process_id) {
     77 }
     78 
     79 AwContentsMessageFilter::~AwContentsMessageFilter() {
     80 }
     81 
     82 void AwContentsMessageFilter::OverrideThreadForMessage(
     83     const IPC::Message& message, BrowserThread::ID* thread) {
     84   if (message.type() == AwViewHostMsg_ShouldOverrideUrlLoading::ID) {
     85     *thread = BrowserThread::UI;
     86   }
     87 }
     88 
     89 bool AwContentsMessageFilter::OnMessageReceived(const IPC::Message& message) {
     90   bool handled = true;
     91   IPC_BEGIN_MESSAGE_MAP(AwContentsMessageFilter, message)
     92     IPC_MESSAGE_HANDLER(AwViewHostMsg_ShouldOverrideUrlLoading,
     93                         OnShouldOverrideUrlLoading)
     94     IPC_MESSAGE_HANDLER(AwViewHostMsg_SubFrameCreated, OnSubFrameCreated)
     95     IPC_MESSAGE_UNHANDLED(handled = false)
     96   IPC_END_MESSAGE_MAP()
     97   return handled;
     98 }
     99 
    100 void AwContentsMessageFilter::OnShouldOverrideUrlLoading(
    101     int render_frame_id,
    102     const base::string16& url,
    103     bool* ignore_navigation) {
    104   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    105   *ignore_navigation = false;
    106   AwContentsClientBridgeBase* client =
    107       AwContentsClientBridgeBase::FromID(process_id_, render_frame_id);
    108   if (client) {
    109     *ignore_navigation = client->ShouldOverrideUrlLoading(url);
    110   } else {
    111     LOG(WARNING) << "Failed to find the associated render view host for url: "
    112                  << url;
    113   }
    114 }
    115 
    116 void AwContentsMessageFilter::OnSubFrameCreated(int parent_render_frame_id,
    117                                                 int child_render_frame_id) {
    118   AwContentsIoThreadClient::SubFrameCreated(
    119       process_id_, parent_render_frame_id, child_render_frame_id);
    120 }
    121 
    122 class AwAccessTokenStore : public content::AccessTokenStore {
    123  public:
    124   AwAccessTokenStore() { }
    125 
    126   // content::AccessTokenStore implementation
    127   virtual void LoadAccessTokens(
    128       const LoadAccessTokensCallbackType& request) OVERRIDE {
    129     AccessTokenStore::AccessTokenSet access_token_set;
    130     // AccessTokenSet and net::URLRequestContextGetter not used on Android,
    131     // but Run needs to be called to finish the geolocation setup.
    132     request.Run(access_token_set, NULL);
    133   }
    134   virtual void SaveAccessToken(const GURL& server_url,
    135                                const base::string16& access_token) OVERRIDE { }
    136 
    137  private:
    138   virtual ~AwAccessTokenStore() { }
    139 
    140   DISALLOW_COPY_AND_ASSIGN(AwAccessTokenStore);
    141 };
    142 
    143 void CancelProtectedMediaIdentifierPermissionRequests(
    144     int render_process_id,
    145     int render_view_id,
    146     const GURL& origin) {
    147   AwBrowserPermissionRequestDelegate* delegate =
    148       AwBrowserPermissionRequestDelegate::FromID(render_process_id,
    149                                                  render_view_id);
    150   if (delegate)
    151     delegate->CancelProtectedMediaIdentifierPermissionRequests(origin);
    152 }
    153 
    154 void CancelGeolocationPermissionRequests(
    155     int render_process_id,
    156     int render_view_id,
    157     const GURL& origin) {
    158   AwBrowserPermissionRequestDelegate* delegate =
    159       AwBrowserPermissionRequestDelegate::FromID(render_process_id,
    160                                                  render_view_id);
    161   if (delegate)
    162     delegate->CancelGeolocationPermissionRequests(origin);
    163 }
    164 
    165 }  // namespace
    166 
    167 std::string AwContentBrowserClient::GetAcceptLangsImpl() {
    168   // Start with the currnet locale.
    169   std::string langs = l10n_util::GetDefaultLocale();
    170 
    171   // If we're not en-US, add in en-US which will be
    172   // used with a lower q-value.
    173   if (base::StringToLowerASCII(langs) != "en-us") {
    174     langs += ",en-US";
    175   }
    176   return langs;
    177 }
    178 
    179 AwBrowserContext* AwContentBrowserClient::GetAwBrowserContext() {
    180   return AwBrowserContext::GetDefault();
    181 }
    182 
    183 AwContentBrowserClient::AwContentBrowserClient(
    184     JniDependencyFactory* native_factory)
    185     : native_factory_(native_factory) {
    186   base::FilePath user_data_dir;
    187   if (!PathService::Get(base::DIR_ANDROID_APP_DATA, &user_data_dir)) {
    188     NOTREACHED() << "Failed to get app data directory for Android WebView";
    189   }
    190   browser_context_.reset(
    191       new AwBrowserContext(user_data_dir, native_factory_));
    192 }
    193 
    194 AwContentBrowserClient::~AwContentBrowserClient() {
    195 }
    196 
    197 void AwContentBrowserClient::AddCertificate(net::CertificateMimeType cert_type,
    198                                             const void* cert_data,
    199                                             size_t cert_size,
    200                                             int render_process_id,
    201                                             int render_frame_id) {
    202   if (cert_size > 0)
    203     net::android::StoreCertificate(cert_type, cert_data, cert_size);
    204 }
    205 
    206 content::BrowserMainParts* AwContentBrowserClient::CreateBrowserMainParts(
    207     const content::MainFunctionParams& parameters) {
    208   return new AwBrowserMainParts(browser_context_.get());
    209 }
    210 
    211 content::WebContentsViewDelegate*
    212 AwContentBrowserClient::GetWebContentsViewDelegate(
    213     content::WebContents* web_contents) {
    214   return native_factory_->CreateViewDelegate(web_contents);
    215 }
    216 
    217 void AwContentBrowserClient::RenderProcessWillLaunch(
    218     content::RenderProcessHost* host) {
    219   // If WebView becomes multi-process capable, this may be insecure.
    220   // More benefit can be derived from the ChildProcessSecurotyPolicy by
    221   // deferring the GrantScheme calls until we know that a given child process
    222   // really does need that priviledge. Check here to ensure we rethink this
    223   // when the time comes. See crbug.com/156062.
    224   CHECK(content::RenderProcessHost::run_renderer_in_process());
    225 
    226   // Grant content: and file: scheme to the whole process, since we impose
    227   // per-view access checks.
    228   content::ChildProcessSecurityPolicy::GetInstance()->GrantScheme(
    229       host->GetID(), android_webview::kContentScheme);
    230   content::ChildProcessSecurityPolicy::GetInstance()->GrantScheme(
    231       host->GetID(), url::kFileScheme);
    232 
    233   host->AddFilter(new AwContentsMessageFilter(host->GetID()));
    234   host->AddFilter(new cdm::CdmMessageFilterAndroid());
    235 }
    236 
    237 net::URLRequestContextGetter* AwContentBrowserClient::CreateRequestContext(
    238     content::BrowserContext* browser_context,
    239     content::ProtocolHandlerMap* protocol_handlers,
    240     content::URLRequestInterceptorScopedVector request_interceptors) {
    241   DCHECK_EQ(browser_context_.get(), browser_context);
    242   return browser_context_->CreateRequestContext(protocol_handlers,
    243                                                 request_interceptors.Pass());
    244 }
    245 
    246 net::URLRequestContextGetter*
    247 AwContentBrowserClient::CreateRequestContextForStoragePartition(
    248     content::BrowserContext* browser_context,
    249     const base::FilePath& partition_path,
    250     bool in_memory,
    251     content::ProtocolHandlerMap* protocol_handlers,
    252     content::URLRequestInterceptorScopedVector request_interceptors) {
    253   DCHECK_EQ(browser_context_.get(), browser_context);
    254   // TODO(mkosiba,kinuko): request_interceptors should be hooked up in the
    255   // downstream. (crbug.com/350286)
    256   return browser_context_->CreateRequestContextForStoragePartition(
    257       partition_path, in_memory, protocol_handlers,
    258       request_interceptors.Pass());
    259 }
    260 
    261 std::string AwContentBrowserClient::GetCanonicalEncodingNameByAliasName(
    262     const std::string& alias_name) {
    263   return alias_name;
    264 }
    265 
    266 void AwContentBrowserClient::AppendExtraCommandLineSwitches(
    267     base::CommandLine* command_line,
    268     int child_process_id) {
    269   NOTREACHED() << "Android WebView does not support multi-process yet";
    270 }
    271 
    272 std::string AwContentBrowserClient::GetApplicationLocale() {
    273   return l10n_util::GetDefaultLocale();
    274 }
    275 
    276 std::string AwContentBrowserClient::GetAcceptLangs(
    277     content::BrowserContext* context) {
    278   return GetAcceptLangsImpl();
    279 }
    280 
    281 const gfx::ImageSkia* AwContentBrowserClient::GetDefaultFavicon() {
    282   ResourceBundle& rb = ResourceBundle::GetSharedInstance();
    283   // TODO(boliu): Bundle our own default favicon?
    284   return rb.GetImageSkiaNamed(IDR_DEFAULT_FAVICON);
    285 }
    286 
    287 bool AwContentBrowserClient::AllowAppCache(const GURL& manifest_url,
    288                            const GURL& first_party,
    289                            content::ResourceContext* context) {
    290   // WebView doesn't have a per-site policy for locally stored data,
    291   // instead AppCache can be disabled for individual WebViews.
    292   return true;
    293 }
    294 
    295 
    296 bool AwContentBrowserClient::AllowGetCookie(const GURL& url,
    297                                             const GURL& first_party,
    298                                             const net::CookieList& cookie_list,
    299                                             content::ResourceContext* context,
    300                                             int render_process_id,
    301                                             int render_frame_id) {
    302   return AwCookieAccessPolicy::GetInstance()->AllowGetCookie(url,
    303                                                              first_party,
    304                                                              cookie_list,
    305                                                              context,
    306                                                              render_process_id,
    307                                                              render_frame_id);
    308 }
    309 
    310 bool AwContentBrowserClient::AllowSetCookie(const GURL& url,
    311                                             const GURL& first_party,
    312                                             const std::string& cookie_line,
    313                                             content::ResourceContext* context,
    314                                             int render_process_id,
    315                                             int render_frame_id,
    316                                             net::CookieOptions* options) {
    317   return AwCookieAccessPolicy::GetInstance()->AllowSetCookie(url,
    318                                                              first_party,
    319                                                              cookie_line,
    320                                                              context,
    321                                                              render_process_id,
    322                                                              render_frame_id,
    323                                                              options);
    324 }
    325 
    326 bool AwContentBrowserClient::AllowWorkerDatabase(
    327     const GURL& url,
    328     const base::string16& name,
    329     const base::string16& display_name,
    330     unsigned long estimated_size,
    331     content::ResourceContext* context,
    332     const std::vector<std::pair<int, int> >& render_frames) {
    333   // Android WebView does not yet support web workers.
    334   return false;
    335 }
    336 
    337 void AwContentBrowserClient::AllowWorkerFileSystem(
    338     const GURL& url,
    339     content::ResourceContext* context,
    340     const std::vector<std::pair<int, int> >& render_frames,
    341     base::Callback<void(bool)> callback) {
    342   // Android WebView does not yet support web workers.
    343   callback.Run(false);
    344 }
    345 
    346 bool AwContentBrowserClient::AllowWorkerIndexedDB(
    347     const GURL& url,
    348     const base::string16& name,
    349     content::ResourceContext* context,
    350     const std::vector<std::pair<int, int> >& render_frames) {
    351   // Android WebView does not yet support web workers.
    352   return false;
    353 }
    354 
    355 content::QuotaPermissionContext*
    356 AwContentBrowserClient::CreateQuotaPermissionContext() {
    357   return new AwQuotaPermissionContext;
    358 }
    359 
    360 void AwContentBrowserClient::AllowCertificateError(
    361     int render_process_id,
    362     int render_frame_id,
    363     int cert_error,
    364     const net::SSLInfo& ssl_info,
    365     const GURL& request_url,
    366     ResourceType resource_type,
    367     bool overridable,
    368     bool strict_enforcement,
    369     bool expired_previous_decision,
    370     const base::Callback<void(bool)>& callback,
    371     content::CertificateRequestResultType* result) {
    372   AwContentsClientBridgeBase* client =
    373       AwContentsClientBridgeBase::FromID(render_process_id, render_frame_id);
    374   bool cancel_request = true;
    375   if (client)
    376     client->AllowCertificateError(cert_error,
    377                                   ssl_info.cert.get(),
    378                                   request_url,
    379                                   callback,
    380                                   &cancel_request);
    381   if (cancel_request)
    382     *result = content::CERTIFICATE_REQUEST_RESULT_TYPE_DENY;
    383 }
    384 
    385 void AwContentBrowserClient::SelectClientCertificate(
    386       int render_process_id,
    387       int render_frame_id,
    388       const net::HttpNetworkSession* network_session,
    389       net::SSLCertRequestInfo* cert_request_info,
    390       const base::Callback<void(net::X509Certificate*)>& callback) {
    391   AwContentsClientBridgeBase* client =
    392       AwContentsClientBridgeBase::FromID(render_process_id, render_frame_id);
    393   if (client) {
    394     client->SelectClientCertificate(cert_request_info, callback);
    395   } else {
    396     callback.Run(NULL);
    397   }
    398 }
    399 
    400 blink::WebNotificationPermission
    401     AwContentBrowserClient::CheckDesktopNotificationPermission(
    402         const GURL& source_url,
    403         content::ResourceContext* context,
    404         int render_process_id) {
    405   // Android WebView does not support notifications, so return Denied here.
    406   return blink::WebNotificationPermissionDenied;
    407 }
    408 
    409 void AwContentBrowserClient::ShowDesktopNotification(
    410     const content::ShowDesktopNotificationHostMsgParams& params,
    411     content::RenderFrameHost* render_frame_host,
    412     scoped_ptr<content::DesktopNotificationDelegate> delegate,
    413     base::Closure* cancel_callback) {
    414   NOTREACHED() << "Android WebView does not support desktop notifications.";
    415 }
    416 
    417 void AwContentBrowserClient::RequestGeolocationPermission(
    418     content::WebContents* web_contents,
    419     int bridge_id,
    420     const GURL& requesting_frame,
    421     bool user_gesture,
    422     base::Callback<void(bool)> result_callback,
    423     base::Closure* cancel_callback) {
    424   int render_process_id = web_contents->GetRenderProcessHost()->GetID();
    425   int render_view_id = web_contents->GetRenderViewHost()->GetRoutingID();
    426   AwBrowserPermissionRequestDelegate* delegate =
    427       AwBrowserPermissionRequestDelegate::FromID(render_process_id,
    428                                                  render_view_id);
    429   if (delegate == NULL) {
    430     DVLOG(0) << "Dropping GeolocationPermission request";
    431     result_callback.Run(false);
    432     return;
    433   }
    434 
    435   GURL origin = requesting_frame.GetOrigin();
    436   if (cancel_callback) {
    437     *cancel_callback = base::Bind(
    438         CancelGeolocationPermissionRequests, render_process_id, render_view_id,
    439         origin);
    440   }
    441   delegate->RequestGeolocationPermission(origin, result_callback);
    442 }
    443 
    444 void AwContentBrowserClient::RequestMidiSysExPermission(
    445     content::WebContents* web_contents,
    446     int bridge_id,
    447     const GURL& requesting_frame,
    448     bool user_gesture,
    449     base::Callback<void(bool)> result_callback,
    450     base::Closure* cancel_callback) {
    451   // TODO(toyoshim): Android WebView is not supported yet.
    452   // See http://crbug.com/339767.
    453   result_callback.Run(false);
    454 }
    455 
    456 void AwContentBrowserClient::RequestProtectedMediaIdentifierPermission(
    457     content::WebContents* web_contents,
    458     const GURL& origin,
    459     base::Callback<void(bool)> result_callback,
    460     base::Closure* cancel_callback) {
    461   int render_process_id = web_contents->GetRenderProcessHost()->GetID();
    462   int render_view_id = web_contents->GetRenderViewHost()->GetRoutingID();
    463   AwBrowserPermissionRequestDelegate* delegate =
    464       AwBrowserPermissionRequestDelegate::FromID(render_process_id,
    465                                                  render_view_id);
    466   if (delegate == NULL) {
    467     DVLOG(0) << "Dropping ProtectedMediaIdentifierPermission request";
    468     result_callback.Run(false);
    469     return;
    470   }
    471 
    472   if (cancel_callback) {
    473     *cancel_callback = base::Bind(
    474         CancelProtectedMediaIdentifierPermissionRequests,
    475         render_process_id, render_view_id, origin);
    476   }
    477   delegate->RequestProtectedMediaIdentifierPermission(origin, result_callback);
    478 }
    479 
    480 bool AwContentBrowserClient::CanCreateWindow(
    481     const GURL& opener_url,
    482     const GURL& opener_top_level_frame_url,
    483     const GURL& source_origin,
    484     WindowContainerType container_type,
    485     const GURL& target_url,
    486     const content::Referrer& referrer,
    487     WindowOpenDisposition disposition,
    488     const blink::WebWindowFeatures& features,
    489     bool user_gesture,
    490     bool opener_suppressed,
    491     content::ResourceContext* context,
    492     int render_process_id,
    493     int opener_id,
    494     bool* no_javascript_access) {
    495   // We unconditionally allow popup windows at this stage and will give
    496   // the embedder the opporunity to handle displaying of the popup in
    497   // WebContentsDelegate::AddContents (via the
    498   // AwContentsClient.onCreateWindow callback).
    499   // Note that if the embedder has blocked support for creating popup
    500   // windows through AwSettings, then we won't get to this point as
    501   // the popup creation will have been blocked at the WebKit level.
    502   if (no_javascript_access) {
    503     *no_javascript_access = false;
    504   }
    505   return true;
    506 }
    507 
    508 void AwContentBrowserClient::ResourceDispatcherHostCreated() {
    509   AwResourceDispatcherHostDelegate::ResourceDispatcherHostCreated();
    510 }
    511 
    512 net::NetLog* AwContentBrowserClient::GetNetLog() {
    513   return browser_context_->GetAwURLRequestContext()->GetNetLog();
    514 }
    515 
    516 content::AccessTokenStore* AwContentBrowserClient::CreateAccessTokenStore() {
    517   return new AwAccessTokenStore();
    518 }
    519 
    520 bool AwContentBrowserClient::IsFastShutdownPossible() {
    521   NOTREACHED() << "Android WebView is single process, so IsFastShutdownPossible"
    522                << " should never be called";
    523   return false;
    524 }
    525 
    526 void AwContentBrowserClient::ClearCache(content::RenderViewHost* rvh) {
    527   RemoveHttpDiskCache(rvh->GetProcess()->GetBrowserContext(),
    528                       rvh->GetProcess()->GetID());
    529 }
    530 
    531 void AwContentBrowserClient::ClearCookies(content::RenderViewHost* rvh) {
    532   // TODO(boliu): Implement.
    533   NOTIMPLEMENTED();
    534 }
    535 
    536 base::FilePath AwContentBrowserClient::GetDefaultDownloadDirectory() {
    537   // Android WebView does not currently use the Chromium downloads system.
    538   // Download requests are cancelled immedately when recognized; see
    539   // AwResourceDispatcherHost::CreateResourceHandlerForDownload. However the
    540   // download system still tries to start up and calls this before recognizing
    541   // the request has been cancelled.
    542   return base::FilePath();
    543 }
    544 
    545 std::string AwContentBrowserClient::GetDefaultDownloadName() {
    546   NOTREACHED() << "Android WebView does not use chromium downloads";
    547   return std::string();
    548 }
    549 
    550 void AwContentBrowserClient::DidCreatePpapiPlugin(
    551     content::BrowserPpapiHost* browser_host) {
    552   NOTREACHED() << "Android WebView does not support plugins";
    553 }
    554 
    555 bool AwContentBrowserClient::AllowPepperSocketAPI(
    556     content::BrowserContext* browser_context,
    557     const GURL& url,
    558     bool private_api,
    559     const content::SocketPermissionRequest* params) {
    560   NOTREACHED() << "Android WebView does not support plugins";
    561   return false;
    562 }
    563 
    564 void AwContentBrowserClient::OverrideWebkitPrefs(
    565     content::RenderViewHost* rvh,
    566     const GURL& url,
    567     content::WebPreferences* web_prefs) {
    568   if (!preferences_populater_.get()) {
    569     preferences_populater_ = make_scoped_ptr(native_factory_->
    570         CreateWebPreferencesPopulater());
    571   }
    572   preferences_populater_->PopulateFor(
    573       content::WebContents::FromRenderViewHost(rvh), web_prefs);
    574 }
    575 
    576 #if defined(VIDEO_HOLE)
    577 content::ExternalVideoSurfaceContainer*
    578 AwContentBrowserClient::OverrideCreateExternalVideoSurfaceContainer(
    579     content::WebContents* web_contents) {
    580   return native_factory_->CreateExternalVideoSurfaceContainer(web_contents);
    581 }
    582 #endif
    583 
    584 content::DevToolsManagerDelegate*
    585 AwContentBrowserClient::GetDevToolsManagerDelegate() {
    586   return new AwDevToolsManagerDelegate();
    587 }
    588 
    589 }  // namespace android_webview
    590