很多Intent
动作,例如ACTION_VIEW
,Uri
指向应该执行动作的内容.如果内容由文件支持 - 无论是Uri
直接指向文件还是ContentProvider
服务文件(请参阅参考资料FileProvider
) - 这通常都有效.
在某些情况下,开发人员不希望将内容驻留在文件中以与其他应用程序共享.一种常见的情况是加密:解密的数据应该驻留在RAM中,而不是磁盘上,以最大限度地降低某人获取该解密数据的风险.
我从RAM共享的经典解决方案是使用ParcelFileDescriptor
和createPipe()
.但是,当响应ACTION_VIEW
(或其他)的活动获得InputStream
该管道时,与ContentProvider
从文件提供内容时获得的流相比,生成的流受到限制.例如,此示例应用程序适用于Adobe Reader并崩溃QuickOffice.
基于过去的 相关问题,我的假设是createPipe()
真正创建一个管道,并且管道是不可寻找的.试图"倒带"或"快进"的客户因此遇到问题.
我正在寻找一种可靠的解决方案,用于与第三方应用程序共享内存内容,以解决此限制.特别:
它必须使用Uri
可能被客户端应用程序(即ACTION_VIEW
实现者)尊重的语法; 涉及客户端应用程序不太可能识别的某些麻烦的解决方案(例如,通过Intent
额外的方式传递某些内容)不符合条件
要共享的数据不能作为共享的一部分写入文件(当然,客户端应用程序最终可以将收到的字节保存到磁盘,但暂时忽略该风险)
理想情况下,它不涉及应用程序寻求共享数据开放ServerSocket
或以其他方式加剧安全风险
可能建议的想法包括:
某种重新配置的方法会导致可createPipe()
搜索的管道
某种使用基于套接字的方法FileDescriptor
可以产生可搜索的管道
某种RAM磁盘或其他东西,感觉像Android的其余部分的文件,但不是持久的
如果你愿意的话,一个关键的工作解决方案就是如果我可以从RAM中获得QuickOffice可以读取的PDF.
有什么建议?
谢谢!
你提出了一个非常困难的要求组合.
让我们看看你的解决方案的想法:
可能建议的想法包括:
某种方法来重新配置createPipe(),导致可搜索的管道
某种方式使用基于套接字的FileDescriptor导致可搜索的管道
某种RAM磁盘或其他东西,感觉像Android的其余部分的文件,但不是持久的
第一个不起作用.这个问题是操作系统实现的管道原语从根本上说是不可寻找的.原因是支持搜索需要操作系统缓冲整个管道"内容"......直到读取结束.这是无法实现的......除非您对可以通过管道发送的数据量进行限制.
第二个也不会起作用,原因几乎相同.操作系统级别的套接字不可搜索.
在一个层面上,最终的想法(一个RAM文件系统)工作,模拟Android OS支持这样的功能.(毕竟,Ramfs文件是可以搜索的.)但是,文件流不是管道.特别是对于文件流和管道,文件结尾的行为是不同的.从读者的角度来看,文件流看起来像一个管道流,这将需要一些特殊的代码.(问题类似于tail -f
在日志文件上运行的问题......)
不幸的是,我认为没有任何其他方法可以获得文件描述符,其行为类似于文件末尾的管道,并且也是可搜索的......没有从根本上修改操作系统.
如果您可以更改从流中读取的应用程序,则可以解决此问题.fd需要由QuickOffice读取和搜索这一事实(我假设您无法修改)这一事实排除了这一点.(但如果你可以改变应用程序,有办法让这项工作...)
顺便说一句,我认为你在Linux或Windows上遇到了这些要求的一些问题.它们不是特定于Java的.
UPDATE
关于这一点有各种有趣的评论,我想在这里解决一些问题:
OP已经解释了激发他的问题的用例.基本上,他想要一种方案,其中在应用程序实际运行时用户设备被盗(或没收)的情况下,通过应用程序之间的"通道"的数据不会易受攻击.
这可以实现吗?
从理论上讲,没有.如果假设一个高度技术复杂性(以及公众可能不知道的技术......)那么"坏人"可能会闯入操作系统并从共享内存中读取数据,同时"通道"保持活动状态.
我怀疑这种攻击(目前)在实践中是可行的.
然而,即使我们假设"通道"没有向"盘"写入任何内容,在内存中仍然可能存在通道的痕迹:例如
仍然挂载的RAMfs或仍然活动的共享内存段,或
先前RAMfs /共享内存的残余.
从理论上讲,如果"坏人"没有关闭或重启设备,理论上可以检索这些数据.
有人建议ashmem
可以在这种情况下使用:
可以解决没有公共Java API的问题(例如,通过编写第三方API)
真正的障碍是需要流API.根据"ashmem"文档,它们具有类似文件的API.但我认为这只意味着它们符合"文件描述符"模型.这些FD可以从一个应用程序传递到另一个应用程序(通过fork/exec),并使用"ioctl"对它们进行操作.但没有迹象表明他们实施"阅读"和"写作"......更不用说"寻求"了.
现在,您可以在ashmem上实现读/写/可搜索流,在通道的两端使用本机和Java库.但是这两个应用程序都需要"了解"此过程,可能需要提供命令行选项来设置通道.
这些问题也适用于旧式shmem
......除了频道设置可能更难.
另一个可能的选择是使用RAM fs.
这更容易实现.RAMfs中的文件将表现得像"普通"文件; 当由应用程序打开时,您将获得可以读取,写入和搜索的文件描述符...取决于它是如何打开的.并且(我认为)您应该能够通过fork/exec为RAMfs文件传递可搜索的FD.
问题是RAMfs需要由操作系统"安装"才能使用它.安装时,另一个(特权)应用程序也可以打开和读取文件.当某些应用程序为RAMfs文件打开fds时,操作系统不会让你卸载RAMfs.
有一种(假设的)方案可以部分地减轻上述情况.
源应用程序创建并安装"私有"RAMfs.
源应用程序创建/打开文件以进行读/写,然后取消链接.
源应用程序使用打开的fd写入文件.
源应用程序分叉/执行接收器应用程序,传递fd.
接收器应用程序从(我认为)仍然可搜索的fd读取,根据需要寻找.
当源应用程序注意到(子)接收器应用程序进程已退出时,它会卸载并销毁RAMfs.
这不需要修改读取(接收器)应用程序.
但是,第三个(特权)应用程序仍然可能进入RAMfs,将未链接的文件放在内存中并读取它.
但是,重新审阅了上述所有内容后,最实用的解决方案仍然是修改读取(sink)应用程序,将整个输入流读入a byte[]
,然后打开一个ByteArrayInputStream
缓冲数据.核心应用程序可以随意查找和重置它.