diff --git a/chrome/browser/ui/android/exclusive_access/exclusive_access_context_android.cc b/chrome/browser/ui/android/exclusive_access/exclusive_access_context_android.cc --- a/chrome/browser/ui/android/exclusive_access/exclusive_access_context_android.cc +++ b/chrome/browser/ui/android/exclusive_access/exclusive_access_context_android.cc @@ -22,7 +22,13 @@ ExclusiveAccessContextAndroid::ExclusiveAccessContextAndroid( j_activity_tab_provider)); } -ExclusiveAccessContextAndroid::~ExclusiveAccessContextAndroid() = default; +ExclusiveAccessContextAndroid::~ExclusiveAccessContextAndroid() { + // Notify the Java peer so it nulls its native pointer and unregisters its + // ActivityTabTabObserver. Without this, a surviving Tab can deliver + // onTouchDown() to the leaked observer and call back into freed |this|. + JNIEnv* env = jni_zero::AttachCurrentThread(); + Java_ExclusiveAccessContext_destroy(env, java_context_); +} void ExclusiveAccessContextAndroid::Destroy(JNIEnv* env) { Java_ExclusiveAccessContext_destroy(env, java_context_);