Home > Mobile >  takePersistableUriPermission via ACTION_OPEN_DOCUMENT fails when trying to get many documents
takePersistableUriPermission via ACTION_OPEN_DOCUMENT fails when trying to get many documents

Time:11-18

For over a week I try to solve weird problem. When i try to get file uri's using SAF and ACTION_OPEN_DOCUMENT and use takePersistableUriPermission() method on them I get SecurityException :

java.lang.SecurityException: UID 10384 does not have permission to content://com.android.externalstorage.documents/document/primary:big mock playlist/Bądź moją królową.pdf [user 0]; you could obtain access using ACTION_OPEN_DOCUMENT or related APIs
    at android.os.Parcel.createException(Parcel.java:1953)
    at android.os.Parcel.readException(Parcel.java:1921)
    at android.os.Parcel.readException(Parcel.java:1871)
    at android.app.IActivityManager$Stub$Proxy.grantUriPermission(IActivityManager.java:4757)
    at android.app.ContextImpl.grantUriPermission(ContextImpl.java:2084)
    at android.content.ContextWrapper.grantUriPermission(ContextWrapper.java:781)
    at android.content.ContextWrapper.grantUriPermission(ContextWrapper.java:781)
    at com.example.weddkit20.util.UriHelper$Companion.grantReadPermissionToUri(UriHelper.kt:27)
    at com.example.weddkit20.view.songbook.PlaylistActivity$setResultLaunchers$1.onActivityResult(PlaylistActivity.kt:123)
    at com.example.weddkit20.view.songbook.PlaylistActivity$setResultLaunchers$1.onActivityResult(PlaylistActivity.kt:41)
    at androidx.activity.result.ActivityResultRegistry$1.onStateChanged(ActivityResultRegistry.java:148)
    at androidx.lifecycle.LifecycleRegistry$ObserverWithState.dispatchEvent(LifecycleRegistry.java:354)
    at androidx.lifecycle.LifecycleRegistry.forwardPass(LifecycleRegistry.java:265)
    at androidx.lifecycle.LifecycleRegistry.sync(LifecycleRegistry.java:307)
    at androidx.lifecycle.LifecycleRegistry.moveToState(LifecycleRegistry.java:148)
    at androidx.lifecycle.LifecycleRegistry.handleLifecycleEvent(LifecycleRegistry.java:134)
    at androidx.lifecycle.ReportFragment.dispatch(ReportFragment.java:68)
    at androidx.lifecycle.ReportFragment.dispatch(ReportFragment.java:144)
    at androidx.lifecycle.ReportFragment.onStart(ReportFragment.java:109)
    at android.app.Fragment.performStart(Fragment.java:2568)
    at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:1339)
    at android.app.FragmentManagerImpl.moveFragmentToExpectedState(FragmentManager.java:1581)
    at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:1643)
    at android.app.FragmentManagerImpl.dispatchMoveToState(FragmentManager.java:3054)
    at android.app.FragmentManagerImpl.dispatchStart(FragmentManager.java:3011)
    at android.app.FragmentController.dispatchStart(FragmentController.java:193)
    at android.app.Activity.performStart(Activity.java:7487)
    at android.app.ActivityThread.handleStartActivity(ActivityThread.java:3454)
    at android.app.servertransaction.TransactionExecutor.performLifecycleSequence(TransactionExecutor.java:180)
    at android.app.servertransaction.TransactionExecutor.cycleToPath(TransactionExecutor.java:165)
    at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:142)
    at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:70)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2199)
    at android.os.Handler.dispatchMessage(Handler.java:112)
    at android.os.Looper.loop(Looper.java:216)
    at android.app.ActivityThread.main(ActivityThread.java:7625)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:524)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:987)
 Caused by: android.os.RemoteException: Remote stack trace:
    at com.android.server.am.ActivityManagerService.checkGrantUriPermissionLocked(ActivityManagerService.java:10930)
    at com.android.server.am.ActivityManagerService.grantUriPermissionLocked(ActivityManagerService.java:11001)
    at com.android.server.am.ActivityManagerService.grantUriPermission(ActivityManagerService.java:11178)
    at android.app.IActivityManager$Stub.onTransact(IActivityManager.java:691)
    at com.android.server.am.ActivityManagerService.onTransact(ActivityManagerService.java:3648)

The weird thing is I get this error only if I try to load large amount of files (100 or more). If I load smaller amount of files all permissions are granted, uri's are saved in local database and there is no problem in fetching file's content using these uri's (in another activity UI shows content of PDF files). Error clearly says than i should use ACTION_OPEN_DOCUMENT which I actually do.

Code used for loading files from file browser :

PlaylistActivity :

private fun showFileBrowser() {

    val intent = Intent(Intent.ACTION_OPEN_DOCUMENT).apply {
        type = "application/pdf"
        addCategory(Intent.CATEGORY_OPENABLE)
        putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true)
        addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION)
        addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
    }
    fileResultLauncher.launch(intent)
}

private fun setResultLaunchers() {
    fileResultLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
        if (result.resultCode == Activity.RESULT_OK) {
            Log.d(TAG, "Success callback from file browser fired off!")
            val uriList : MutableList<Uri>  = arrayListOf()
            val uriClipData = result.data!!.clipData
            if(uriClipData != null) {
                //if user picked multiple files
                for(i in 0 until uriClipData.itemCount) { uriList.add(uriClipData.getItemAt(i).uri!!) }
            } else {
                //if user picked one file
                uriList.add(result.data!!.data!!)
            }

            //granting permissions
            uriList.forEach { uri ->
                UriHelper.grantReadPermissionToUri(this, uri)
            }

            //business logic
            val songList : List<Song> = uriList.map {
                val fullFilename = UriHelper.getFileName(contentResolver, it)
                val filename = StringHelper.stripExtensionFromFilename(fullFilename)
                val extension = StringHelper.getExtensionFromFilename(fullFilename)
                val song = Song(it, filename, extension)
                song.isOnPlaylist = false
                song
            }
            availableSongsAdapter.submitList(songList)
            createPlaylistAdapter.submitList(arrayListOf())
            createPlaylistViewModel.getStoredCloudSongs(this)
        }
    }
}

UriHelper :

    @Throws(Exception::class)
    fun grantReadPermissionToUri(context: Context, uri: Uri) {
        context.grantUriPermission(
            context.packageName,
            uri,
            Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION
        )
        context.contentResolver.takePersistableUriPermission(
            uri,
            Intent.FLAG_GRANT_READ_URI_PERMISSION
        )
    }

Any hint what could be wrong will be appreciated. Please help me cuz this problem is driving me crazy :/

CodePudding user response:

On Android 10 and lower, there is a limit of 128 persisted permission grants: https://issuetracker.google.com/issues/149315521

That limit was raised to 512 for Android 11; I do not know if Android 12 raised it further.

CodePudding user response:

I am using this to open PDF files on my project and have no problems, give it a try.

val uri: Uri = Uri.parse(url)
val typeFile = "application/pdf"

val intent = Intent()
intent.action = Intent.ACTION_VIEW
intent.setDataAndType(uri, typeFile)
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
startActivity(intent)
  • Related