'Is it possible to send Uri using AIDL?

I have two apps, lets say AppClient and AppService. Those apps are communicating between each other using AIDL methods. Right now I would like to send Uri from AppClient to AppService in AIDL method parameter. I can send it without any problems but when I trying to open stream to read file using

context.contentResolver.openInputStream(uriFile)

I'm getting SecurityException. Permission Denial: opening provider androidx.core.content.FileProvider from ProcessRecord{94e65ad 6186:com.app.service/u0a231} (pid=6186, uid=10231) that is not exported from uid 10043

In AppClient before sending Uri via AIDL method I'm granting required permissions first.

val uri = FileProvider.getUriForFile(this,"com.app.client.fileprovider", fontFile)
grantUriPermission("com.app.service", uri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION and Intent.FLAG_GRANT_READ_URI_PERMISSION)

In documentation is see thet Uri is transported to other app using Intents but it I don't want to use Intents. It is possible to send Uri not using Intent e.g. in AIDL parameter ?



Solution 1:[1]

you need to create a wrapper over Uri to remotely open a Uri through AIDL. I do this in send Uri from the main profile to the work profile in Android.

look at Shelter open source project on Github for details. UriForwardProxy

// A wrapper over Uri to remotely open an Uri through AIDL
// This is used to forward Content URIs through the profile
// boundary.
public class UriForwardProxy implements Parcelable {
    public static final Parcelable.Creator<UriForwardProxy> CREATOR = new Parcelable.Creator<UriForwardProxy>() {
        @Override
        public UriForwardProxy[] newArray(int size) {
            return new UriForwardProxy[0];
        }

        @Override
        public UriForwardProxy createFromParcel(Parcel source) {
            IBinder[] arr = new IBinder[1];
            source.readBinderArray(arr);
            IUriOpener opener = IUriOpener.Stub.asInterface(arr[0]);
            return new UriForwardProxy(opener);
        }
    };

    private IUriOpener mOpener;

    private UriForwardProxy(IUriOpener opener) {
        mOpener = opener;
    }

    public UriForwardProxy(Context context, Uri uri) {
        ContentResolver resolver = context.getContentResolver();
        mOpener = new IUriOpener.Stub() {
            @Override
            public ParcelFileDescriptor openFile(String mode) {
                try {
                    return resolver.openFileDescriptor(uri, mode);
                } catch (FileNotFoundException e) {
                    return null;
                }
            }
        };
    }

    public ParcelFileDescriptor open(String mode) {
        try {
            return mOpener.openFile(mode);
        } catch (RemoteException e) {
            return null;
        }
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeBinderArray(new IBinder[]{mOpener.asBinder()});
    }

    @Override
    public int describeContents() {
        return 0;
    }
}

Solution 2:[2]

grantUriPermission("com.app.service", uri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION or Intent.FLAG_GRANT_READ_URI_PERMISSION)

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 Golil
Solution 2 procrastinator