'SecurityException using scoped storage in some devices

Im looking in google play crashes in some devices, like Samsung and Nokia, api 29 and 30.

Logs:

  Caused by: java.lang.SecurityException: 
  at android.os.Parcel.createExceptionOrNull (Parcel.java:2385)
  at android.os.Parcel.createException (Parcel.java:2369)
  at android.os.Parcel.readException (Parcel.java:2352)
  at android.os.Parcel.readException (Parcel.java:2294)
  at android.app.IActivityManager$Stub$Proxy.getContentProvider (IActivityManager.java:6680)
  at android.app.ActivityThread.acquireProvider (ActivityThread.java:7643)
  at android.app.ContextImpl$ApplicationContentResolver.acquireUnstableProvider (ContextImpl.java:3090)
  at android.content.ContentResolver.acquireUnstableProvider (ContentResolver.java:2484)
  at android.content.ContentResolver.query (ContentResolver.java:1170)
  at android.content.ContentResolver.query (ContentResolver.java:1118)
  at android.content.ContentResolver.query (ContentResolver.java:1074)
  at FileUtils.getFileName (FileUtils.java:69)
  at MainActivity.onCreate (MainActivity.java:88)
  at android.app.Activity.performCreate (Activity.java:8198)
  at android.app.Activity.performCreate (Activity.java:8182)
  at android.app.Instrumentation.callActivityOnCreate (Instrumentation.java:1309)
  at android.app.ActivityThread.performLaunchActivity (ActivityThread.java:3765)
Caused by: android.os.RemoteException: 
  at com.android.server.am.ActivityManagerService.getContentProviderImpl (ActivityManagerService.java:8965)
  at com.android.server.am.ActivityManagerService.getContentProviderImpl (ActivityManagerService.java:8804)
  at com.android.server.am.ActivityManagerService.getContentProvider (ActivityManagerService.java:9505)
  at android.app.IActivityManager$Stub.onTransact (IActivityManager.java:2840)
  at com.android.server.am.ActivityManagerService.onTransact (ActivityManagerService.java:3617)

Permissions only for android < 28:

<uses-permission
    android:name="android.permission.WRITE_EXTERNAL_STORAGE"
    android:maxSdkVersion="28"
    tools:ignore="ScopedStorage" />
<uses-permission
    android:name="android.permission.READ_EXTERNAL_STORAGE"
    android:maxSdkVersion="28" />

The crash code:

 public static String getFileName(Context context, Uri uri) {
        String result = null;
        if (uri.getScheme().equals("content")) {
            Cursor cursor = context.getContentResolver().query(uri, null, null, null, null);
            try {
                if (cursor != null && cursor.moveToFirst()) {
                    result = cursor.getString(cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME));
                }
            } finally {
                cursor.close();
            }
        }
        if (result == null) {
            result = uri.getPath();
            int cut = result.lastIndexOf('/');
            if (cut != -1) {
                result = result.substring(cut + 1);
            }
        }
        return result;
    }

Manifest:

        <provider
                android:name="androidx.core.content.FileProvider"
                android:authorities="${applicationId}.provider"
                android:exported="false"
                android:grantUriPermissions="true">
            <meta-data
                    android:name="android.support.FILE_PROVIDER_PATHS"
                    android:resource="@xml/provider_paths"/>
        </provider>

  <activity
                android:name=".presentation.MainActivity"
                android:exported="true"
                android:theme="@style/Theme.MaterialComponents.Light.NoActionBar">

            <intent-filter tools:ignore="AppLinkUrlError">
                <action android:name="android.intent.action.VIEW"/>
                <category android:name="android.intent.category.DEFAULT"/>
                <data android:mimeType="application/pdf"/>
            </intent-filter>
            <intent-filter>
                <action android:name="android.intent.action.SEND"/>
                <category android:name="android.intent.category.DEFAULT"/>
                <data android:mimeType="application/pdf"/>
            </intent-filter>
        </activity>

provider_paths.xml:

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <external-path name="external_files" path="."/>
    <cache-path name="cache" path="." />
</paths>

This is working well in the 90% of the devices. Any idea why is crashing? I think that can be for open some file without permissions, but I'm unable to reproduce it



Solution 1:[1]

The app that owns the file that triggers the intent to open a document may have not granted READ permissions. For example

Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(uri);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); // user's app may not have specified this

Your app needs to do the following for Android 10 and above:

  1. Following the best practices outlined in Request App Permissions, request the READ_EXTERNAL_STORAGE permission.

  2. If the URI points to files in restricted locations like Android/data and Android/obb, your app would not be able to READ it even if it has the READ_EXTERNAL_STORAGE permission. In this case, your app should catch the Exception and show an appropriate error message to the user.

So in your MainActivity's onCreate do something like the following

    protected void onCreate(Bundle savedInstanceState) {

        // on Android 10+ request READ_EXTERNAL_STORAGE permission
        if (hasPermissions(READ_EXTERNAL_STORAGE)) {
            try {
                String name = FileUtils.getFileName(this, URI);
            } catch (Exception e) {
                showToast("Error loading file");
            }
        } else {
            requestPermission(READ_EXTERNAL_STORAGE);
        }

    }

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 cyberman