通过Seekable Pipe或Stream与另一个Android应用程序共享?

 广东神秘地址 发布于 2023-01-29 16:07

很多Intent动作,例如ACTION_VIEW,Uri指向应该执行动作的内容.如果内容由文件支持 - 无论是Uri直接指向文件还是ContentProvider服务文件(请参阅参考资料FileProvider) - 这通常都有效.

在某些情况下,开发人员不希望将内容驻留在文件中以与其他应用程序共享.一种常见的情况是加密:解密的数据应该驻留在RAM中,而不是磁盘上,以最大限度地降低某人获取该解密数据的风险.

我从RAM共享的经典解决方案是使用ParcelFileDescriptorcreatePipe().但是,当响应ACTION_VIEW(或其他)的活动获得InputStream该管道时,与ContentProvider从文件提供内容时获得的流相比,生成的流受到限制.例如,此示例应用程序适用于Adobe Reader并崩溃QuickOffice.

基于过去的 相关问题,我的假设是createPipe()真正创建一个管道,并且管道是不可寻找的.试图"倒带"或"快进"的客户因此遇到问题.

我正在寻找一种可靠的解决方案,用于与第三方应用程序共享内存内容,以解决此限制.特别:

它必须使用Uri可能被客户端应用程序(即ACTION_VIEW实现者)尊重的语法; 涉及客户端应用程序不太可能识别的某些麻烦的解决方案(例如,通过Intent额外的方式传递某些内容)不符合条件

要共享的数据不能作为共享的一部分写入文件(当然,客户端应用程序最终可以将收到的字节保存到磁盘,但暂时忽略该风险)

理想情况下,它不涉及应用程序寻求共享数据开放ServerSocket或以其他方式加剧安全风险

可能建议的想法包括:

某种重新配置的方法会导致可createPipe()搜索的管道

某种使用基于套接字的方法FileDescriptor可以产生可搜索的管道

某种RAM磁盘或其他东西,感觉像Android的其余部分的文件,但不是持久的

如果你愿意的话,一个关键的工作解决方案就是如果我可以从RAM中获得QuickOffice可以读取的PDF.

有什么建议?

谢谢!

1 个回答
  • 你提出了一个非常困难的要求组合.

    让我们看看你的解决方案的想法:

    可能建议的想法包括:

    某种方法来重新配置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缓冲数据.核心应用程序可以随意查找和重置它.

    2023-01-29 16:10 回答
撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有