Plausible fix for crash in GetCertificateChain.

The call to get the certificate chain from native assumes a valid
ContentViewCore. Switch to using WebContents which will get properly
invalidated/handled if the tab which launches this dialog closes before
the dialog is presented.

Also includes a slight change to avoid bouncing Java->native->Java by
allowing the dialog to be created from Java.

BUG=379928

Review URL: https://codereview.chromium.org/330583002

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@276653 0039d316-1c4b-4281-b951-d872f2087c98
parent 203afa5b
...@@ -24,42 +24,45 @@ import android.widget.TextView; ...@@ -24,42 +24,45 @@ import android.widget.TextView;
import org.chromium.base.CalledByNative; import org.chromium.base.CalledByNative;
import org.chromium.chrome.R; import org.chromium.chrome.R;
import org.chromium.content.browser.ContentViewCore; import org.chromium.content_public.browser.WebContents;
import java.net.URISyntaxException; import java.net.URISyntaxException;
/** /**
* Java side of Android implementation of the website settings UI. * Java side of Android implementation of the website settings UI.
*/ */
class WebsiteSettingsPopup implements OnClickListener { public class WebsiteSettingsPopup implements OnClickListener {
private static final String HELP_URL = private static final String HELP_URL =
"http://www.google.com/support/chrome/bin/answer.py?answer=95617"; "http://www.google.com/support/chrome/bin/answer.py?answer=95617";
private final Context mContext; private final Context mContext;
private final Dialog mDialog; private final Dialog mDialog;
private final LinearLayout mContainer; private final LinearLayout mContainer;
private final ContentViewCore mContentViewCore; private final WebContents mWebContents;
private final int mPadding; private final int mPadding;
private TextView mCertificateViewer, mMoreInfoLink; private TextView mCertificateViewer, mMoreInfoLink;
private String mLinkUrl; private String mLinkUrl;
private WebsiteSettingsPopup(Context context, ContentViewCore contentViewCore, private WebsiteSettingsPopup(Context context, WebContents webContents) {
final long nativeWebsiteSettingsPopup) {
mContext = context; mContext = context;
mWebContents = webContents;
mContainer = new LinearLayout(mContext);
mContainer.setOrientation(LinearLayout.VERTICAL);
mPadding = (int) context.getResources().getDimension(R.dimen.certificate_viewer_padding);
mContainer.setPadding(mPadding, 0, mPadding, 0);
mDialog = new Dialog(mContext); mDialog = new Dialog(mContext);
mDialog.requestWindowFeature(Window.FEATURE_NO_TITLE); mDialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
mDialog.setCanceledOnTouchOutside(true); mDialog.setCanceledOnTouchOutside(true);
mDialog.setOnCancelListener(new DialogInterface.OnCancelListener() { // This needs to come after other member initialization.
final long nativeWebsiteSettingsPopup = nativeInit(this, webContents);
mDialog.setOnDismissListener(new DialogInterface.OnDismissListener() {
@Override @Override
public void onCancel(DialogInterface dialogInterface) { public void onDismiss(DialogInterface dialog) {
assert nativeWebsiteSettingsPopup != 0; assert nativeWebsiteSettingsPopup != 0;
nativeDestroy(nativeWebsiteSettingsPopup); nativeDestroy(nativeWebsiteSettingsPopup);
} }
}); });
mContainer = new LinearLayout(mContext);
mContainer.setOrientation(LinearLayout.VERTICAL);
mContentViewCore = contentViewCore;
mPadding = (int) context.getResources().getDimension(R.dimen.certificate_viewer_padding);
mContainer.setPadding(mPadding, 0, mPadding, 0);
} }
/** Adds a section, which contains an icon, a headline, and a description. */ /** Adds a section, which contains an icon, a headline, and a description. */
...@@ -118,7 +121,7 @@ class WebsiteSettingsPopup implements OnClickListener { ...@@ -118,7 +121,7 @@ class WebsiteSettingsPopup implements OnClickListener {
/** Displays the WebsiteSettingsPopup. */ /** Displays the WebsiteSettingsPopup. */
@CalledByNative @CalledByNative
private void show() { private void showDialog() {
ScrollView scrollView = new ScrollView(mContext); ScrollView scrollView = new ScrollView(mContext);
scrollView.addView(mContainer); scrollView.addView(mContainer);
mDialog.addContentView(scrollView, mDialog.addContentView(scrollView,
...@@ -131,7 +134,12 @@ class WebsiteSettingsPopup implements OnClickListener { ...@@ -131,7 +134,12 @@ class WebsiteSettingsPopup implements OnClickListener {
public void onClick(View v) { public void onClick(View v) {
mDialog.dismiss(); mDialog.dismiss();
if (mCertificateViewer == v) { if (mCertificateViewer == v) {
byte[][] certChain = nativeGetCertificateChain(mContentViewCore); byte[][] certChain = nativeGetCertificateChain(mWebContents);
if (certChain == null) {
// The WebContents may have been destroyed/invalidated. If so,
// ignore this request.
return;
}
CertificateViewer.showCertificateChain(mContext, certChain); CertificateViewer.showCertificateChain(mContext, certChain);
} else if (mMoreInfoLink == v) { } else if (mMoreInfoLink == v) {
try { try {
...@@ -143,12 +151,22 @@ class WebsiteSettingsPopup implements OnClickListener { ...@@ -143,12 +151,22 @@ class WebsiteSettingsPopup implements OnClickListener {
} }
} }
@CalledByNative /**
private static WebsiteSettingsPopup create(Context context, ContentViewCore contentViewCore, * Shows a WebsiteSettings dialog for the provided WebContents.
long nativeWebsiteSettingsPopup) { *
return new WebsiteSettingsPopup(context, contentViewCore, nativeWebsiteSettingsPopup); * The popup adds itself to the view hierarchy which owns the reference while it's
* visible.
*
* @param context Context which is used for launching a dialog.
* @param webContents The WebContents for which to show Website information. This
* information is retrieved for the visible entry.
*/
@SuppressWarnings("unused")
public static void show(Context context, WebContents webContents) {
new WebsiteSettingsPopup(context, webContents);
} }
private static native long nativeInit(WebsiteSettingsPopup popup, WebContents webContents);
private native void nativeDestroy(long nativeWebsiteSettingsPopupAndroid); private native void nativeDestroy(long nativeWebsiteSettingsPopupAndroid);
private native byte[][] nativeGetCertificateChain(ContentViewCore contentViewCore); private native byte[][] nativeGetCertificateChain(WebContents webContents);
} }
\ No newline at end of file
...@@ -11,7 +11,6 @@ ...@@ -11,7 +11,6 @@
#include "chrome/browser/infobars/infobar_service.h" #include "chrome/browser/infobars/infobar_service.h"
#include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/website_settings/website_settings.h" #include "chrome/browser/ui/website_settings/website_settings.h"
#include "content/public/browser/android/content_view_core.h"
#include "content/public/browser/cert_store.h" #include "content/public/browser/cert_store.h"
#include "content/public/browser/navigation_controller.h" #include "content/public/browser/navigation_controller.h"
#include "content/public/browser/navigation_entry.h" #include "content/public/browser/navigation_entry.h"
...@@ -32,11 +31,14 @@ using content::WebContents; ...@@ -32,11 +31,14 @@ using content::WebContents;
static jobjectArray GetCertificateChain(JNIEnv* env, static jobjectArray GetCertificateChain(JNIEnv* env,
jobject obj, jobject obj,
jobject view) { jobject java_web_contents) {
content::WebContents* contents = content::WebContents* web_contents =
content::ContentViewCore::GetNativeContentViewCore(env, view)-> content::WebContents::FromJavaWebContents(java_web_contents);
GetWebContents(); if (!web_contents)
int cert_id = contents->GetController().GetVisibleEntry()->GetSSL().cert_id; return NULL;
int cert_id =
web_contents->GetController().GetVisibleEntry()->GetSSL().cert_id;
scoped_refptr<net::X509Certificate> cert; scoped_refptr<net::X509Certificate> cert;
bool ok = CertStore::GetInstance()->RetrieveCert(cert_id, &cert); bool ok = CertStore::GetInstance()->RetrieveCert(cert_id, &cert);
CHECK(ok); CHECK(ok);
...@@ -64,18 +66,20 @@ static jobjectArray GetCertificateChain(JNIEnv* env, ...@@ -64,18 +66,20 @@ static jobjectArray GetCertificateChain(JNIEnv* env,
} }
// static // static
void WebsiteSettingsPopupAndroid::Show(JNIEnv* env, static jlong Init(JNIEnv* env,
jobject context, jclass clazz,
jobject java_content_view, jobject obj,
WebContents* web_contents) { jobject java_web_contents) {
new WebsiteSettingsPopupAndroid(env, context, java_content_view, content::WebContents* web_contents =
web_contents); content::WebContents::FromJavaWebContents(java_web_contents);
return reinterpret_cast<intptr_t>(
new WebsiteSettingsPopupAndroid(env, obj, web_contents));
} }
WebsiteSettingsPopupAndroid::WebsiteSettingsPopupAndroid( WebsiteSettingsPopupAndroid::WebsiteSettingsPopupAndroid(
JNIEnv* env, JNIEnv* env,
jobject context, jobject java_website_settings_pop,
jobject java_content_view,
WebContents* web_contents) { WebContents* web_contents) {
// Important to use GetVisibleEntry to match what's showing in the omnibox. // Important to use GetVisibleEntry to match what's showing in the omnibox.
content::NavigationEntry* nav_entry = content::NavigationEntry* nav_entry =
...@@ -83,9 +87,7 @@ WebsiteSettingsPopupAndroid::WebsiteSettingsPopupAndroid( ...@@ -83,9 +87,7 @@ WebsiteSettingsPopupAndroid::WebsiteSettingsPopupAndroid(
if (nav_entry == NULL) if (nav_entry == NULL)
return; return;
popup_jobject_.Reset( popup_jobject_.Reset(env, java_website_settings_pop);
Java_WebsiteSettingsPopup_create(env, context, java_content_view,
reinterpret_cast<intptr_t>(this)));
presenter_.reset(new WebsiteSettings( presenter_.reset(new WebsiteSettings(
this, this,
...@@ -152,7 +154,7 @@ void WebsiteSettingsPopupAndroid::SetIdentityInfo( ...@@ -152,7 +154,7 @@ void WebsiteSettingsPopupAndroid::SetIdentityInfo(
Java_WebsiteSettingsPopup_addMoreInfoLink(env, popup_jobject_.obj(), Java_WebsiteSettingsPopup_addMoreInfoLink(env, popup_jobject_.obj(),
ConvertUTF8ToJavaString( ConvertUTF8ToJavaString(
env, l10n_util::GetStringUTF8(IDS_PAGE_INFO_HELP_CENTER_LINK)).obj()); env, l10n_util::GetStringUTF8(IDS_PAGE_INFO_HELP_CENTER_LINK)).obj());
Java_WebsiteSettingsPopup_show(env, popup_jobject_.obj()); Java_WebsiteSettingsPopup_showDialog(env, popup_jobject_.obj());
} }
void WebsiteSettingsPopupAndroid::SetCookieInfo( void WebsiteSettingsPopupAndroid::SetCookieInfo(
......
...@@ -16,14 +16,12 @@ namespace content { ...@@ -16,14 +16,12 @@ namespace content {
class WebContents; class WebContents;
} }
// Androidimplementation of the website settings UI. // Android implementation of the website settings UI.
class WebsiteSettingsPopupAndroid : public WebsiteSettingsUI { class WebsiteSettingsPopupAndroid : public WebsiteSettingsUI {
public: public:
static void Show(JNIEnv* env, WebsiteSettingsPopupAndroid(JNIEnv* env,
jobject context, jobject java_website_settings,
jobject java_content_view, content::WebContents* web_contents);
content::WebContents* web_contents);
virtual ~WebsiteSettingsPopupAndroid(); virtual ~WebsiteSettingsPopupAndroid();
void Destroy(JNIEnv* env, jobject obj); void Destroy(JNIEnv* env, jobject obj);
...@@ -38,11 +36,6 @@ class WebsiteSettingsPopupAndroid : public WebsiteSettingsUI { ...@@ -38,11 +36,6 @@ class WebsiteSettingsPopupAndroid : public WebsiteSettingsUI {
static bool RegisterWebsiteSettingsPopupAndroid(JNIEnv* env); static bool RegisterWebsiteSettingsPopupAndroid(JNIEnv* env);
private: private:
WebsiteSettingsPopupAndroid(JNIEnv* env,
jobject context,
jobject java_content_view,
content::WebContents* web_contents);
// The presenter that controlls the Website Settings UI. // The presenter that controlls the Website Settings UI.
scoped_ptr<WebsiteSettings> presenter_; scoped_ptr<WebsiteSettings> presenter_;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment