AssetFileDescriptor.CreateInputStream/CreateOutputStream hide FileInputStream/FileOutputStream channel access
- Dominant language
- C#
- Stars
- 2.1k
- Forks
- 579
- Avg merge
- 1d 20h
- Merged PRs (30d)
- 257
Description
### Android framework version
net10.0-android
### Affected platform version
Microsoft.Android.Ref.36 36.1.53 + Microsoft.Android.Runtime.36.android 36.1.53
### Description
`Android.Content.Res.AssetFileDescriptor.CreateInputStream()` and `CreateOutputStream()` hide the concrete Java stream types.
The Android Java API returns:
```java
public FileInputStream createInputStream() throws IOException
public FileOutputStream createOutputStream() throws IOException
```
AOSP source:
https://android.googlesource.com/platform/frameworks/base/+/refs/heads/master/core/java/android/content/res/AssetFileDescriptor.java
The .NET Android binding invokes the correct Java methods/signatures:
```text
createInputStream.()Ljava/io/FileInputStream;
createOutputStream.()Ljava/io/FileOutputStream;
```
but exposes both methods as:
```csharp
System.IO.Stream AssetFileDescriptor.CreateInputStream()
System.IO.Stream AssetFileDescriptor.CreateOutputStream()
```
The returned stream is wrapped through:
```csharp
Android.Runtime.InputStreamInvoker.FromJniHandle(...)
Android.Runtime.OutputStreamInvoker.FromJniHandle(...)
```
This loses access to the concrete `Java.IO.FileInputStream` / `Java.IO.FileOutputStream` APIs.
This matters for large file copies, especially SAF/content URI copies, because the concrete Java stream types expose `Channel`. With the current binding, code using the auto-close `AssetFileDescriptor.CreateInputStream()` / `CreateOutputStream()` APIs cannot use:
```csharp
FileInputStream.Channel.TransferTo(..., FileOutputStream.Channel)
```
Changing the existing return type would probably be breaking, but would it be possible to expose strongly typed alternatives or otherwise make the underlying `Java.IO.FileInputStream` / `Java.IO.FileOutputStream` accessible without reflection?
### Steps to Reproduce
1. Open an `AssetFileDescriptor` for a content URI:
```csharp
using var afd = Application.Context.ContentResolver.OpenAssetFileDescriptor(uri, "w");
```
2. Call `CreateOutputStream()`:
```csharp
using var stream = afd.CreateOutputStream();
```
3. Observe that the returned type is `System.IO.Stream`, not `Java.IO.FileOutputStream`, even though the Android API method returns `FileOutputStream`.
4. Try to use `FileOutputStream.Channel` for a large file copy:
```csharp
var output = (Java.IO.FileOutputStream)stream; // not possible
```
The only practical workaround is to bypass `CreateOutputStream()`:
```csharp
using var output = new Java.IO.FileOutputStream(afd.FileDescriptor);
```
but then the caller must explicitly close the `AssetFileDescriptor`.
### Did you find any workaround?
Yes. The workaround is to avoid `AssetFileDescriptor.CreateInputStream()` / `CreateOutputStream()` and create Java file streams from the raw file descriptor:
```csharp
using var afd = Application.Context.ContentResolver.OpenAssetFileDescriptor(uri, "w");
try
{
using var output = new Java.IO.FileOutputStream(afd.FileDescriptor);
// use output.Channel here
}
finally
{
afd.Close();
}
```
This preserves access to `FileOutputStream.Channel`, but it bypasses the Android auto-close stream APIs and requires explicit `AssetFileDescriptor.Close()` handling.
### Relevant log output
```shell
```
Contributor guide
No contributing guide indexed for this repository
Research direction
Start by comparing AssetFileDescriptor.CreateInputStream() and CreateOutputStream() with the AOSP AssetFileDescriptor methods and their Java signatures. Trace the binding wrappers through InputStreamInvoker.FromJniHandle and OutputStreamInvoker.FromJniHandle, then determine an API that exposes FileInputStream/FileOutputStream channel access without changing the existing return types or auto-close behavior.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- android, csharp
- Domain
- api, mobile-dev
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 52/100