Skip to content

Commit

Permalink
Added fail-safe check to catch MissingWebViewPackage Exception. (#33088)
Browse files Browse the repository at this point in the history
Summary:
The check implemented in PR #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: #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
  • Loading branch information
Kunal-Airtel2022 authored and facebook-github-bot committed Feb 15, 2022
1 parent 9010bfe commit 8c573d9
Showing 1 changed file with 9 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down

0 comments on commit 8c573d9

Please sign in to comment.