ParcelFileDescriptor.createPipe in JNI

半世苍凉 提交于 2020-02-23 04:57:27

问题


I'm trying to figure out how I can pass a stream of data within ContentProvider.openFile. The data to be sent is created in JNI. I tried createPipe with a transfer thread but I had a ton of trouble with broken pipes. So I thought I might just pass the 'write' pipe to JNI and write the data directly to it.

Java:

ParcelFileDescriptor[] pipe = ParcelFileDescriptor.createPipe();
boolean result = ImageProcessor.getThumb(fd/*source fd*/, pipe[1].getFd()); //JNI call (formerly returned a byte[])
return pipe[0];

C:

unsigned char* jpeg = NULL;
unsigned long jpegSize = 0;

getThumbnail(env, &jpeg, &jpegSize, rawProcessor); // Populates jpeg thumb, works when converted to byte[] in second segment
FILE* out = fdopen(dest, "wb");
int written = fwrite(jpeg, 1, jpegSize, out);
return TRUE;

When I convert to byte[] everything works fine, just not within a ContentProvider obviously:

jbyteArray thumb = env->NewByteArray(jpegSize);
env->SetByteArrayRegion(thumb, 0, jpegSize, (jbyte *) jpeg);
free(jpeg);
return thumb;

When I debug it gets to fwrite then the stack trace just seems to disappear. Never hits return TRUE or return pipe[0], but also doesn't crash or throw. Very strange...

Has anyone done something similar? Is it sufficient to simply write binary to the "write" pipe? Am I doing anything fundamentally wrong here? Thanks.

Update (after discussion with @pskink)

I tried implementing the PipeDataWriter. I used FileProvider.java as an example.

@Override
public void writeDataToPipe(@NonNull ParcelFileDescriptor output, @NonNull Uri uri, @NonNull String mimeType, @Nullable Bundle opts, @Nullable byte[] args)
{
    try (FileOutputStream fout = new FileOutputStream(output.getFileDescriptor()))
    {
        fout.write(args, 0, args.length);
    }
    catch (IOException e)
    {
        Log.e(TAG, "Failed transferring", e);
    }
}

byte[] rawData = ImageUtil.getRawThumb(fd.getParcelFileDescriptor().getFd());
return openPipeHelper(Uri.parse("invalid"), "image/jpg", null, rawData, this);

However, I'm getting the same errors I got when I used the transfer thread above:

java.io.IOException: write failed: EBADF (Bad file descriptor)
at libcore.io.IoBridge.write(IoBridge.java:498)
at java.io.FileOutputStream.write(FileOutputStream.java:186)
at com.anthonymandra.content.MetaProvider.writeDataToPipe(MetaProvider.java:273)

and

java.io.IOException: write failed: EPIPE (Broken pipe)
at libcore.io.IoBridge.write(IoBridge.java:498)
at java.io.FileOutputStream.write(FileOutputStream.java:186)
at com.anthonymandra.content.MetaProvider.writeDataToPipe(MetaProvider.java:273)

When I stepped through to make sure the data was fine for the images I found that everything loaded fine. It looks to me like this is actually a thread safety issue.


回答1:


There were actually a bunch of things going wrong that all rolled up into a confusing mess:

  1. I wasn't closing the ParcelFileDescriptor in a finally.
  2. I use Glide for an image cache and it uses two fetchers when you load a Uri, meaning openFile was being called twice per file.
  3. (2) caused endless broken pipe errors.
  4. StrictMode was killing the app because of (1) and I missed it in the flurry of errors from (3).


来源:https://stackoverflow.com/questions/42954047/parcelfiledescriptor-createpipe-in-jni

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!