在Android NDK上使用popen

4

安卓NDK不支持popen吗?

我看到这个页面,想知道这是否为真。

可以使用POSIX popen()实现相同的功能,但目前bionic不支持该函数,因此您无法在Android JNI中使用它。相反,您可以使用system()并将输出管道到文件中,然后稍后读取该文件。如果您将在Java中进行渲染,则使用Java方法可能更加清晰。

但我也看到有人建议使用popen。我自己也尝试过,但有时我的应用程序会崩溃,我不知道原因。

在安卓NDK中,popen是否安全使用?

2个回答

7

我认为这取决于您使用的NDK版本。

此外,在gingerbread源代码树中查找bionic时,我发现了一个popen的实现。 该实现可能不是完全符合libc posix标准的,但至少在某种程度上是可用的。

使用NDK v6,以下示例可以编译而无任何问题,并且可以在我的Android设备上运行。

#include <stdio.h>
#include <stdlib.h>
int main()
{
 FILE *fpipe;
 char *command="/system/bin/ps";
 char line[256];
 if ( !(fpipe = (FILE*)popen(command,"r")) ) exit(1)
 while ( fgets( line, sizeof line, fpipe))
 {
   puts(line);
 }
 pclose(fpipe);
}

更新: 似乎在ICS版本之前,popen使用的是vfork()而不是fork(),而这些vfork()已知会导致堆栈损坏。

因此,从ICS开始,popen应该是安全的,但在早期的Android版本中,虽然可用,但非常不稳定。


4

实际上,popen() 在 Android 上无法使用。根据 GLIBC 描述,任何 UNIX 操作系统都需要一个 C 库来进行所有系统调用,包括线程内存分配、文件操作等。因为 Android 基于 Linux,所以需要实现这样的库,但是由于它是一个小型移动操作系统,Google 决定编写一个名为 bionic 的“精简版” libc。该库不包括 popen(),因此无法使用。在 NDK 文档中有关于 bionic 库的描述,该文档位于您的 NDK 目录中(由于某种原因,它不在线上)。希望这可以帮到您。


谢谢。我只是想知道为什么它在我的示例应用程序上可以工作?我相信如果它没有被包含,那么它根本不应该工作。 - kuchi
1
是的,这是正确的。虽然在Android上可用popen()函数,但实际上它会破坏堆栈,因为使用了vfork()方法。 - Ales Teska
对我来说,当我调用popen/pclose不到4-5次时,它们是有效的。我在这上面浪费了很多时间。 - Paschalis
@ales-teska 你知道这是否仍然是个问题吗?因为我在安卓上使用popen()时遇到了非常奇怪的错误,而现在已经是2019年了... - Slava
@Slava - 不,我们在Android上不使用那个。 - Ales Teska

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接