Java JNI中的ParcelFileDescriptor.createPipe
我正在试图找出如何在Java JNI中的ParcelFileDescriptor.createPipe,java,android,java-native-interface,Java,Android,Java Native Interface,我正在试图找出如何在ContentProvider.openFile中传递数据流。要发送的数据是在JNI中创建的。我尝试了createPipe,使用了一个传输线程,但我遇到了大量管道破裂的问题。所以我想我可以将“写入”管道传递给JNI,并将数据直接写入它 爪哇: C: 当我转换为byte[]时,一切正常,只是不在ContentProvider中显然: jbyteArray thumb = env->NewByteArray(jpegSize); env->SetByteArrayRe
ContentProvider.openFile
中传递数据流。要发送的数据是在JNI中创建的。我尝试了createPipe
,使用了一个传输线程,但我遇到了大量管道破裂的问题。所以我想我可以将“写入”管道传递给JNI,并将数据直接写入它
爪哇:
C:
当我转换为byte[]时,一切正常,只是不在ContentProvider中
显然:
jbyteArray thumb = env->NewByteArray(jpegSize);
env->SetByteArrayRegion(thumb, 0, jpegSize, (jbyte *) jpeg);
free(jpeg);
return thumb;
当我调试到fwrite
时,堆栈跟踪似乎消失了。从不点击返回TRUE
或返回管道[0]
,但也不会崩溃或抛出。很奇怪
有人做过类似的事情吗?只需将二进制文件写入“写入”管道就足够了吗?我在这里做错了什么吗?谢谢
更新(与@pskink讨论后)
我尝试实现了PipeDataWriter
。我举了一个例子
@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);
}
}
但是,当我使用上面的传输线程时,我得到了相同的错误: java.io.IOException:写入失败:EBADF(错误的文件描述符)
在libcore.io.IoBridge.write中(IoBridge.java:498)
在java.io.FileOutputStream.write(FileOutputStream.java:186)处
在 anthonymandra.content.MetaProvider.WriteDataOppe(MetaProvider.java:273) 及 java.io.IOException:写入失败:EPIPE(断管)
在libcore.io.IoBridge.write中(IoBridge.java:498)
在java.io.FileOutputStream.write(FileOutputStream.java:186)处
在 anthonymandra.content.MetaProvider.WriteDataOppe(MetaProvider.java:273)
当我仔细检查以确保图像的数据是正确的时,我发现加载的一切都是正确的。在我看来,这实际上是一个线程安全问题。事实上,有一大堆事情出了问题,所有这些都陷入了混乱:
ParcelFileDescriptor
Uri
时,它使用两个抓取器,这意味着openFile
正在加载StrictMode
因为(1)而终止了该应用程序,我在(3)的一系列错误中错过了它事实上,有很多事情都出了问题,最终导致了混乱:
ParcelFileDescriptor
Uri
时,它使用两个抓取器,这意味着openFile
正在加载StrictMode
因为(1)而终止了该应用程序,我在(3)的一系列错误中错过了它你的意思是?好的,所以仍然需要一个转移线程。这是有道理的。我对自己所做的“神奇记忆支持”假设表示怀疑。这也可能意味着我会遇到同样的管道破裂问题,但我会尽快解决。请参阅
ContentProvider\openPipeHelper
然后我没有尝试将openPipeHelper
与jni“结婚”,但我99.99%确定您可以调用ImageProcessor.getThumb(fd/*source fd*/,pipe[1].getFd())
在PipeDataWriter#writedatatoppe
方法中您可以传递args
中的任何内容(openPipeHelper的最后一个参数),您的意思是?好的,因此仍然需要传输线程。这是有道理的。我对自己所做的“神奇记忆支持”假设表示怀疑。这也可能意味着我会遇到同样的管道破裂问题,但我会尽快解决。请参阅ContentProvider\openPipeHelper
然后我没有尝试将openPipeHelper
与jni“结婚”,但我99.99%确定您可以调用ImageProcessor.getThumb(fd/*source fd*/,pipe[1].getFd())
内部PipeDataWriter#writedatatoppe
方法您可以在args
中传递任何内容(openPipeHelper的最后一个参数)很好,但实际上使用PipeDataWriter
时,您不必关闭ParcelFileDescriptor
,因为“写入端”已关闭,“读取端”正在关闭(当关闭由ContentResolver\openInputStream()
方法创建的InputStream
时),实际上涉及到另一个pfd。拇指数据(通过管道传输)是从原始图像中提取的数据,该原始图像作为PFD通过SAF获取。如果出现错误(坏管道),导致StrictMode
终止应用程序(并在一系列错误消息中丢失),则需要正确关闭。很好,但实际上,当使用PipeDataWriter
时,您不必关闭ParcelFileDescriptor
,因为“写入端”已关闭,“读取端”已关闭(当关闭由ContentResolver#openInputStream()
方法创建的InputStream
时,实际上涉及到另一个pfd。拇指数据(通过管道传输)是从原始图像中提取的,该图像作为pfd通过可怕的SAF获取。在出现错误时需要正确关闭(坏管道)这导致StrictMode
终止应用程序(并在一系列错误消息中丢失)。
jbyteArray thumb = env->NewByteArray(jpegSize);
env->SetByteArrayRegion(thumb, 0, jpegSize, (jbyte *) jpeg);
free(jpeg);
return thumb;
@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);