12a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Copyright (c) 2013 The Chromium Authors. All rights reserved.
22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// found in the LICENSE file.
42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "android_webview/native/aw_contents_client_bridge.h"
62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "android_webview/common/devtools_instrumentation.h"
8f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "android_webview/native/aw_contents.h"
92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/android/jni_android.h"
102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/android/jni_array.h"
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/android/jni_string.h"
120529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch#include "base/callback_helpers.h"
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/public/browser/browser_thread.h"
14f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "content/public/browser/render_process_host.h"
15f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "content/public/browser/render_view_host.h"
16f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "content/public/browser/web_contents.h"
17116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "crypto/scoped_openssl_types.h"
182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "jni/AwContentsClientBridge_jni.h"
190529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch#include "net/android/keystore_openssl.h"
20c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "net/cert/x509_certificate.h"
210529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch#include "net/ssl/openssl_client_key_store.h"
220529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch#include "net/ssl/ssl_cert_request_info.h"
230529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch#include "net/ssl/ssl_client_cert_type.h"
247dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "url/gurl.h"
252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)using base::android::AttachCurrentThread;
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)using base::android::ConvertJavaStringToUTF16;
282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)using base::android::ConvertUTF8ToJavaString;
29c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)using base::android::ConvertUTF16ToJavaString;
302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)using base::android::JavaRef;
312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)using base::android::ScopedJavaLocalRef;
322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)using content::BrowserThread;
332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace android_webview {
352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
360529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochnamespace {
370529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
380529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch// Must be called on the I/O thread to record a client certificate
390529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch// and its private key in the OpenSSLClientKeyStore.
400529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochvoid RecordClientCertificateKey(
410529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    const scoped_refptr<net::X509Certificate>& client_cert,
42116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    crypto::ScopedEVP_PKEY private_key) {
430529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
440529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  net::OpenSSLClientKeyStore::GetInstance()->RecordClientCertPrivateKey(
450529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      client_cert.get(), private_key.get());
460529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch}
470529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
480529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch}  // namespace
490529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)AwContentsClientBridge::AwContentsClientBridge(JNIEnv* env, jobject obj)
512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    : java_ref_(env, obj) {
522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(obj);
53c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  Java_AwContentsClientBridge_setNativeContentsClientBridge(
54a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      env, obj, reinterpret_cast<intptr_t>(this));
552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)AwContentsClientBridge::~AwContentsClientBridge() {
582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  JNIEnv* env = AttachCurrentThread();
592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (obj.is_null())
622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Clear the weak reference from the java peer to the native object since
642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // it is possible that java object lifetime can exceed the AwContens.
652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Java_AwContentsClientBridge_setNativeContentsClientBridge(env, obj.obj(), 0);
662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void AwContentsClientBridge::AllowCertificateError(
692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int cert_error,
702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    net::X509Certificate* cert,
712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const GURL& request_url,
722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const base::Callback<void(bool)>& callback,
732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    bool* cancel_request) {
742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
750529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  DCHECK_CURRENTLY_ON(BrowserThread::UI);
762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  JNIEnv* env = AttachCurrentThread();
772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (obj.is_null())
802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string der_string;
832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  net::X509Certificate::GetDEREncoded(cert->os_cert_handle(), &der_string);
84c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ScopedJavaLocalRef<jbyteArray> jcert = base::android::ToJavaByteArray(
85c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      env,
86c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      reinterpret_cast<const uint8*>(der_string.data()),
87c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      der_string.length());
882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ScopedJavaLocalRef<jstring> jurl(ConvertUTF8ToJavaString(
892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      env, request_url.spec()));
902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // We need to add the callback before making the call to java side,
912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // as it may do a synchronous callback prior to returning.
922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int request_id = pending_cert_error_callbacks_.Add(
932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      new CertErrorCallback(callback));
94c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  *cancel_request = !Java_AwContentsClientBridge_allowCertificateError(
95c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      env, obj.obj(), cert_error, jcert.obj(), jurl.obj(), request_id);
962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // if the request is cancelled, then cancel the stored callback
972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (*cancel_request) {
982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    pending_cert_error_callbacks_.Remove(request_id);
990529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  }
1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void AwContentsClientBridge::ProceedSslError(JNIEnv* env, jobject obj,
1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                             jboolean proceed, jint id) {
1040529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  DCHECK_CURRENTLY_ON(BrowserThread::UI);
1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  CertErrorCallback* callback = pending_cert_error_callbacks_.Lookup(id);
1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!callback || callback->is_null()) {
1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    LOG(WARNING) << "Ignoring unexpected ssl error proceed callback";
1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  callback->Run(proceed);
1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  pending_cert_error_callbacks_.Remove(id);
1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1140529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch// This method is inspired by SelectClientCertificate() in
1150529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch// chrome/browser/ui/android/ssl_client_certificate_request.cc
1160529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochvoid AwContentsClientBridge::SelectClientCertificate(
1170529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      net::SSLCertRequestInfo* cert_request_info,
1180529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      const SelectCertificateCallback& callback) {
1190529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  DCHECK_CURRENTLY_ON(BrowserThread::UI);
1200529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
1210529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  // Add the callback to id map.
1220529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  int request_id = pending_client_cert_request_callbacks_.Add(
1230529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      new SelectCertificateCallback(callback));
1240529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  // Make sure callback is run on error.
1250529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  base::ScopedClosureRunner guard(base::Bind(
1260529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      &AwContentsClientBridge::HandleErrorInClientCertificateResponse,
1270529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      base::Unretained(this),
1280529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      request_id));
1290529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
1300529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  JNIEnv* env = base::android::AttachCurrentThread();
1310529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
1320529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (obj.is_null())
1330529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    return;
1340529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
1350529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  // Build the |key_types| JNI parameter, as a String[]
1360529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  std::vector<std::string> key_types;
1370529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  for (size_t i = 0; i < cert_request_info->cert_key_types.size(); ++i) {
1380529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    switch (cert_request_info->cert_key_types[i]) {
1390529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      case net::CLIENT_CERT_RSA_SIGN:
1400529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        key_types.push_back("RSA");
1410529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        break;
1420529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      case net::CLIENT_CERT_DSS_SIGN:
1430529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        key_types.push_back("DSA");
1440529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        break;
1450529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      case net::CLIENT_CERT_ECDSA_SIGN:
1460529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        key_types.push_back("ECDSA");
1470529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        break;
1480529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      default:
1490529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        // Ignore unknown types.
1500529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        break;
1510529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    }
1520529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  }
1530529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
1540529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  ScopedJavaLocalRef<jobjectArray> key_types_ref =
1550529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      base::android::ToJavaArrayOfStrings(env, key_types);
1560529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (key_types_ref.is_null()) {
1570529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    LOG(ERROR) << "Could not create key types array (String[])";
1580529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    return;
1590529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  }
1600529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
1610529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  // Build the |encoded_principals| JNI parameter, as a byte[][]
1620529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  ScopedJavaLocalRef<jobjectArray> principals_ref =
1630529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      base::android::ToJavaArrayOfByteArray(
1640529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch          env, cert_request_info->cert_authorities);
1650529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (principals_ref.is_null()) {
1660529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    LOG(ERROR) << "Could not create principals array (byte[][])";
1670529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    return;
1680529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  }
1690529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
1700529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  // Build the |host_name| and |port| JNI parameters, as a String and
1710529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  // a jint.
1720529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  ScopedJavaLocalRef<jstring> host_name_ref =
1730529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      base::android::ConvertUTF8ToJavaString(
1740529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch          env, cert_request_info->host_and_port.host());
1750529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
1760529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  Java_AwContentsClientBridge_selectClientCertificate(
1770529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      env,
1780529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      obj.obj(),
1790529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      request_id,
1800529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      key_types_ref.obj(),
1810529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      principals_ref.obj(),
1820529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      host_name_ref.obj(),
1830529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      cert_request_info->host_and_port.port());
1840529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
1850529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  // Release the guard.
1860529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  ignore_result(guard.Release());
1870529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch}
1880529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
1890529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch// This method is inspired by OnSystemRequestCompletion() in
1900529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch// chrome/browser/ui/android/ssl_client_certificate_request.cc
1910529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochvoid AwContentsClientBridge::ProvideClientCertificateResponse(
1920529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    JNIEnv* env,
1930529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    jobject obj,
1940529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    int request_id,
1950529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    jobjectArray encoded_chain_ref,
1960529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    jobject private_key_ref) {
1970529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  DCHECK_CURRENTLY_ON(BrowserThread::UI);
1980529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
1990529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  SelectCertificateCallback* callback =
2000529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      pending_client_cert_request_callbacks_.Lookup(request_id);
2010529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  DCHECK(callback);
2020529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
2030529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  // Make sure callback is run on error.
2040529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  base::ScopedClosureRunner guard(base::Bind(
2050529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      &AwContentsClientBridge::HandleErrorInClientCertificateResponse,
2060529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      base::Unretained(this),
2070529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      request_id));
2080529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (encoded_chain_ref == NULL || private_key_ref == NULL) {
2090529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    LOG(ERROR) << "Client certificate request cancelled";
2100529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    return;
2110529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  }
2120529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  // Convert the encoded chain to a vector of strings.
2130529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  std::vector<std::string> encoded_chain_strings;
2140529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (encoded_chain_ref) {
2150529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    base::android::JavaArrayOfByteArrayToStringVector(
2160529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        env, encoded_chain_ref, &encoded_chain_strings);
2170529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  }
2180529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
2190529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  std::vector<base::StringPiece> encoded_chain;
2200529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  for (size_t i = 0; i < encoded_chain_strings.size(); ++i)
2210529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    encoded_chain.push_back(encoded_chain_strings[i]);
2220529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
2230529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  // Create the X509Certificate object from the encoded chain.
2240529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  scoped_refptr<net::X509Certificate> client_cert(
2250529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      net::X509Certificate::CreateFromDERCertChain(encoded_chain));
2260529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (!client_cert.get()) {
2270529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    LOG(ERROR) << "Could not decode client certificate chain";
2280529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    return;
2290529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  }
2300529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
2310529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  // Create an EVP_PKEY wrapper for the private key JNI reference.
232116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  crypto::ScopedEVP_PKEY private_key(
2330529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      net::android::GetOpenSSLPrivateKeyWrapper(private_key_ref));
2340529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (!private_key.get()) {
2350529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    LOG(ERROR) << "Could not create OpenSSL wrapper for private key";
2360529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    return;
2370529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  }
2380529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
2390529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  // RecordClientCertificateKey() must be called on the I/O thread,
2400529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  // before the callback is called with the selected certificate on
2410529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  // the UI thread.
2420529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  content::BrowserThread::PostTaskAndReply(
2430529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      content::BrowserThread::IO,
2440529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      FROM_HERE,
2450529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      base::Bind(&RecordClientCertificateKey,
2460529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                 client_cert,
2470529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                 base::Passed(&private_key)),
2480529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      base::Bind(*callback, client_cert));
2490529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  pending_client_cert_request_callbacks_.Remove(request_id);
2500529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
2510529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  // Release the guard.
2520529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  ignore_result(guard.Release());
2530529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch}
2540529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
255c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void AwContentsClientBridge::RunJavaScriptDialog(
256c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    content::JavaScriptMessageType message_type,
257c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const GURL& origin_url,
2585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const base::string16& message_text,
2595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const base::string16& default_prompt_text,
260c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const content::JavaScriptDialogManager::DialogClosedCallback& callback) {
261c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
262c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  JNIEnv* env = AttachCurrentThread();
263c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
264c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
2651320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (obj.is_null()) {
2661320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    callback.Run(false, base::string16());
267c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return;
2681320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
269c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
270c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  int callback_id = pending_js_dialog_callbacks_.Add(
271c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      new content::JavaScriptDialogManager::DialogClosedCallback(callback));
272c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ScopedJavaLocalRef<jstring> jurl(
273c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      ConvertUTF8ToJavaString(env, origin_url.spec()));
274c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ScopedJavaLocalRef<jstring> jmessage(
275c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      ConvertUTF16ToJavaString(env, message_text));
276c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
277c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  switch (message_type) {
278a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    case content::JAVASCRIPT_MESSAGE_TYPE_ALERT: {
279a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      devtools_instrumentation::ScopedEmbedderCallbackTask("onJsAlert");
280c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      Java_AwContentsClientBridge_handleJsAlert(
281c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          env, obj.obj(), jurl.obj(), jmessage.obj(), callback_id);
282c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      break;
283a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    }
284a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    case content::JAVASCRIPT_MESSAGE_TYPE_CONFIRM: {
285a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      devtools_instrumentation::ScopedEmbedderCallbackTask("onJsConfirm");
286c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      Java_AwContentsClientBridge_handleJsConfirm(
287c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          env, obj.obj(), jurl.obj(), jmessage.obj(), callback_id);
288c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      break;
289a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    }
290c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    case content::JAVASCRIPT_MESSAGE_TYPE_PROMPT: {
291c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      ScopedJavaLocalRef<jstring> jdefault_value(
292c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          ConvertUTF16ToJavaString(env, default_prompt_text));
293a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      devtools_instrumentation::ScopedEmbedderCallbackTask("onJsPrompt");
294c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      Java_AwContentsClientBridge_handleJsPrompt(env,
295c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                                 obj.obj(),
296c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                                 jurl.obj(),
297c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                                 jmessage.obj(),
298c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                                 jdefault_value.obj(),
299c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                                 callback_id);
300c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      break;
301c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
302c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    default:
303c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)       NOTREACHED();
304c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
305c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
306c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
307c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void AwContentsClientBridge::RunBeforeUnloadDialog(
308c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const GURL& origin_url,
3095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const base::string16& message_text,
310c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const content::JavaScriptDialogManager::DialogClosedCallback& callback) {
311c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
312c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  JNIEnv* env = AttachCurrentThread();
313c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
314c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
3151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (obj.is_null()) {
3161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    callback.Run(false, base::string16());
317c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return;
3181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
319c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
320c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  int callback_id = pending_js_dialog_callbacks_.Add(
321c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      new content::JavaScriptDialogManager::DialogClosedCallback(callback));
322c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ScopedJavaLocalRef<jstring> jurl(
323c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      ConvertUTF8ToJavaString(env, origin_url.spec()));
324c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ScopedJavaLocalRef<jstring> jmessage(
325c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      ConvertUTF16ToJavaString(env, message_text));
326c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
327a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  devtools_instrumentation::ScopedEmbedderCallbackTask("onJsBeforeUnload");
328c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  Java_AwContentsClientBridge_handleJsBeforeUnload(
329c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      env, obj.obj(), jurl.obj(), jmessage.obj(), callback_id);
330c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
331c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
332a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)bool AwContentsClientBridge::ShouldOverrideUrlLoading(
333a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    const base::string16& url) {
334a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  JNIEnv* env = AttachCurrentThread();
335a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
336a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  if (obj.is_null())
337a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    return false;
338a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  ScopedJavaLocalRef<jstring> jurl = ConvertUTF16ToJavaString(env, url);
339a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  devtools_instrumentation::ScopedEmbedderCallbackTask(
340a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      "shouldOverrideUrlLoading");
341a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  return Java_AwContentsClientBridge_shouldOverrideUrlLoading(
342a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      env, obj.obj(),
343a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      jurl.obj());
344a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
345a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
346c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void AwContentsClientBridge::ConfirmJsResult(JNIEnv* env,
347c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                             jobject,
348c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                             int id,
349c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                             jstring prompt) {
350c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
351c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  content::JavaScriptDialogManager::DialogClosedCallback* callback =
352c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      pending_js_dialog_callbacks_.Lookup(id);
353ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  if (!callback) {
354ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    LOG(WARNING) << "Unexpected JS dialog confirm. " << id;
355ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    return;
356ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  }
3575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::string16 prompt_text;
358c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (prompt) {
359c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    prompt_text = ConvertJavaStringToUTF16(env, prompt);
360c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
361ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  callback->Run(true, prompt_text);
362c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  pending_js_dialog_callbacks_.Remove(id);
363c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
364c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
365c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void AwContentsClientBridge::CancelJsResult(JNIEnv*, jobject, int id) {
366c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
367c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  content::JavaScriptDialogManager::DialogClosedCallback* callback =
368c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      pending_js_dialog_callbacks_.Lookup(id);
369ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  if (!callback) {
370ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    LOG(WARNING) << "Unexpected JS dialog cancel. " << id;
371ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    return;
372ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  }
3735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  callback->Run(false, base::string16());
374c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  pending_js_dialog_callbacks_.Remove(id);
375c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
376c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
3770529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch// Use to cleanup if there is an error in client certificate response.
3780529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochvoid AwContentsClientBridge::HandleErrorInClientCertificateResponse(
3790529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    int request_id) {
3800529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  SelectCertificateCallback* callback =
3810529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      pending_client_cert_request_callbacks_.Lookup(request_id);
3820529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  callback->Run(scoped_refptr<net::X509Certificate>());
3830529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  pending_client_cert_request_callbacks_.Remove(request_id);
3840529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch}
3850529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
3862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool RegisterAwContentsClientBridge(JNIEnv* env) {
3870529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  return RegisterNativesImpl(env);
3882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace android_webview
391