From 8c573d933652ae4da1008502c53fce93057101c0 Mon Sep 17 00:00:00 2001 From: Kunal Farmah Date: Tue, 15 Feb 2022 04:49:10 -0800 Subject: [PATCH] Added fail-safe check to catch MissingWebViewPackage Exception. (#33088) Summary: The check implemented in PR https://github.com/facebook/react-native/issues/29089 is flawed as the exception class name and message depends on the OS version as well as the OEM. In OxygenOS running android 11, it comes out as RuntimeException and the check fails and hence the crash occurs again. But on observing closely, its clear that the exception message is consistent across OEMs with similar strings appearing in them that have been included in the if check. Hence there is a simple fix to this issue, by checking the message instead of the exception class. Here is the snippet: ``` private Nullable CookieManager getCookieManager() { if (mCookieManager == null) { possiblyWorkaroundSyncManager(mContext); try { mCookieManager = CookieManager.getInstance(); } catch (IllegalArgumentException ex) { // https://bugs.chromium.org/p/chromium/issues/detail?id=559720 return null; } catch (Exception exception) { String message = exception.getMessage(); // We cannot catch MissingWebViewPackageException as it is in a private / system API // class. This validates the exception's message to ensure we are only handling this // specific exception. // The exception class doesn't always contain the correct name as it depends on the OEM // and OS version. It is better to check the message for clues regarding the exception // as that is somewhat consistent across OEMs. // For instance, the Exception thrown on OxygenOS 11 is a RuntimeException but the message contains the required strings. // https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/webkit/WebViewFactory.java#348 if (exception.getClass().getCanonicalName().contains("MissingWebViewPackageException") || (message!=null && (message.contains("WebView provider") || message.contains("No WebView installed")))){ return null; } else { throw exception; } } } return mCookieManager; } ``` ## Changelog [General] [Added] - A fail proof check to catch any crash involving webview: if (exception.getClass().getCanonicalName().contains("MissingWebViewPackageException") || (message!=null && (message.contains("WebView provider") || message.contains("No WebView installed")))) [General] [Removed] - Flawed check to catch WebViewProvider crash: if (message != null && exception.getClass().getCanonicalName().contains("MissingWebViewPackageException")) Pull Request resolved: https://github.com/facebook/react-native/pull/33088 Test Plan: This code has been tested rigorously on OnePlus Nord CE 5G (Oxygen OS 11.0) and Realme X (Realme UI 2.0) both running on Android 11 and reproducing the crash on a hybrid (Native android + ReactNative) app that showed this crash in production being dependent on WebViews. I have implemented an entire patched fork of 0.67.2 to fix this issue in our app. How to test: Launch any app that has a webview. Go to settings->apps->Android System Webview -> disable. Resume/Restart the app. In this fix: Open a webview and notice that the app will not crash. In current version: App crashes on startup as the exception escapes the catch block. Even if it survives startup (did on Realme X), it will crash once you try to open a webview. Reviewed By: rh389 Differential Revision: D34240097 Pulled By: cortinico fbshipit-source-id: 0f1f9a3b078c0ad3074c7841392892cb70b427eb --- .../modules/network/ForwardingCookieHandler.java | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/network/ForwardingCookieHandler.java b/ReactAndroid/src/main/java/com/facebook/react/modules/network/ForwardingCookieHandler.java index b48563b3fe34a0..ecc92ac69b0cbe 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/network/ForwardingCookieHandler.java +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/network/ForwardingCookieHandler.java @@ -142,9 +142,16 @@ protected void doInBackgroundGuarded(Void... params) { // We cannot catch MissingWebViewPackageException as it is in a private / system API // class. This validates the exception's message to ensure we are only handling this // specific exception. + // The exception class doesn't always contain the correct name as it depends on the OEM + // and OS version. It is better to check the message for clues regarding the exception + // as that is somewhat consistent across OEMs. + // For instance, the Exception thrown on OxygenOS 11 is a RuntimeException but the message + // contains the required strings. // https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/webkit/WebViewFactory.java#348 - if (message != null - && exception.getClass().getCanonicalName().contains("MissingWebViewPackageException")) { + if (exception.getClass().getCanonicalName().contains("MissingWebViewPackageException") + || (message != null + && (message.contains("WebView provider") + || message.contains("No WebView installed")))) { return null; } else { throw exception;