最近遇到一个让人晕头转向的问题:
我们工作是把 Android port到其他系统中,由于常用mips 架构的 CPU , 我们的code base 基于 mips-android (http://www.imgtec.com/mips/developers/mips-android.asp)
就是别人已经把 Android 系统改到 mips CPU 上了,能编译通过,但是要 运行起来,还需要对 INPUT, DISPLAY 视频播放,3D等进行 porting
以前我们做的 Android 系统是基于 glibc ,系统运行正常,但有 NDK apk 的不能跑起来,这是因为 NDK 的apk 有 so, 而这些 so 是基于 bionic, 现在我们做出基于 bionic 的系统,但是却出现了问题: CTS 跑不起来了,后来发现 CTS 需要调用 adb shell 执行命令, 最后调用 system/bin/sh ( 执行 system/bin/mksh), 用 gdb追踪,发现死锁在 sissuspend。
后来直接就用 adb shell am ... , 也是 mksh 有问题,但是最让人迷惑是问题不是每次都出现。又经过几天调试终于找到 rootcause
可以由于kernel 的差异, mips 可以用 128bits 的 sigmask,所以对 __NR_sigsuspend 的system call,MIPS linux 要求传指针,但 other linux只要 unsigned int data.
在做 mips bionic 的人,只针对 mips linux,没有考虑其他情况。
但做mips bionic 的人就犯错了,他们的代码把 mips 应用到 x86, arm, 直接给这些 kernel 传递指针
正是因为对 x86 linux 传递的是指针,指针的值被当做是数据,所以每次结果随机。
看一下 google 的 fixed 就知道了
https://android.googlesource.com/platform/bionic/+/abd10011a7a6066df76de7acf5eecb2cc870b0c4%5E%21/
diff --git a/libc/unistd/sigsuspend.c b/libc/unistd/sigsuspend.c
index 0db05ed..fd08631 100644
--- a/libc/unistd/sigsuspend.c
+++ b/libc/unistd/sigsuspend.c
@@ -26,12 +26,18 @@
* SUCH DAMAGE.
*/
#include <signal.h>
-
+#ifdef __mips__
+extern int __sigsuspend(const sigset_t *);
+#else
extern int __sigsuspend(int, int, unsigned int);
+#endif
int sigsuspend(const sigset_t *_mask)
{
- unsigned int mask = (unsigned int)*_mask;
-
- return __sigsuspend(0, 0, mask);
+#ifdef __mips__
+ return __sigsuspend(_mask);
+#else
+ unsigned int mask = (unsigned int)*_mask;
+ return __sigsuspend(0, 0, mask);
+#endif
}
在 Android 4.1 的还没有引入对 mips 的支持, 到4.1.2 的引入对mips 的支持,而 mips 的那个错误,也通过上面的 change 被在4.1.2 中被fix了
http://androidxref.com/4.1.2/xref/bionic/libc/unistd/sigsuspend.c
http://androidxref.com/4.2_r1/xref/bionic/libc/unistd/sigsuspend.c