Swift 3 Android hangs & crashes

android

(Eric Wing) #1

Hello, I've been trying to get Swift 3 working on Android. (I
previously had Swift 2.x working.)

I have the baseline components built following the standard
Android/Swift instructions.

But when I go to make a trivial, but real Android
app (i.e. start in Java Activity and use JNI/LoadLibrary to get to
Swift), the Swift code seems to hang (freeze?) whenever my Swift code
calls print("foo").

Removing all print calls, allows my trivial code to run correctly. But in
slightly more complicated test programs (which call into other C
libraries), I'm getting program crashes. It looks like libc triggers
some kind of abort call in these cases. I know these C libraries work
in non-Swift cases.

My best guess right now is since Swift print() is also broken, I think
there might be some problem related to libc++ (and maybe its
interaction with libc) which is used in the build process. (The
Android NDK docs warn about std::cout buffering breaking if you have
multiple static linked libc++, but I'm not statically linking it.)

I'm currently using libc++_shared.
I updated my repo a few days ago which includes a fix for NDK r13
which I am using.

Does this problem ring a bell for anybody?
Or can somebody help me figure out how to start debugging this? I've
been trying a lot of different things behind the scenes, but I'm
starting to run out of ideas.

Thanks,
Eric


(Eric Wing) #2

I discovered there is a serious deadlock bug in Android 5.0. flockfile
on stdout/stderr causes a deadlock. Swift print() ultimately calls
flockfile, which in turn causes a deadlock. I verified this by first
commenting out the lock functions in the print function, and then
later by commenting out the flockfile/funlockfile implementations in
the Stubs.cpp.

One of the comments here mentions this bug:
https://chengyihe.wordpress.com/2015/10/31/android-child-process-hits-mutex-deadlock-in-printf-after-fork/

The workaround seems to be either to remove the call to flockfile() or
update to Android 5.1. I upgraded my device to 5.1 and the problem
disappeared.

But thanks to Android fragmentation, going to 5.1 this means we lose
another 13.1% of devices, leaving us only 40.6% of devices.

This does bring up another issue though, at least for print() and
anything stdout/stderr related on Android. On Android, sending
anything to stdout/stderr via the NDK is effectively useless because
they are effectively sent to /dev/null. (The ‘adb shell setprop
log.redirect-stdio true’ trick doesn’t work for the NDK. There is one
convoluted trick to redirect using pipes in your codebase, but that is
a different can of worms.)

In general, print() statements need to go through
__android_log_write() and __android_log_print() on Android for anybody
to see anything. Is this something we should implement in Swift?

Thanks,
Eric

···

On 10/31/16, Eric Wing <ewmailing@gmail.com> wrote:

Hello, I've been trying to get Swift 3 working on Android. (I
previously had Swift 2.x working.)

I have the baseline components built following the standard
Android/Swift instructions.

But when I go to make a trivial, but real Android
app (i.e. start in Java Activity and use JNI/LoadLibrary to get to
Swift), the Swift code seems to hang (freeze?) whenever my Swift code
calls print("foo").

Removing all print calls, allows my trivial code to run correctly. But in
slightly more complicated test programs (which call into other C
libraries), I'm getting program crashes. It looks like libc triggers
some kind of abort call in these cases. I know these C libraries work
in non-Swift cases.

My best guess right now is since Swift print() is also broken, I think
there might be some problem related to libc++ (and maybe its
interaction with libc) which is used in the build process. (The
Android NDK docs warn about std::cout buffering breaking if you have
multiple static linked libc++, but I'm not statically linking it.)

I'm currently using libc++_shared.
I updated my repo a few days ago which includes a fix for NDK r13
which I am using.

Does this problem ring a bell for anybody?
Or can somebody help me figure out how to start debugging this? I've
been trying a lot of different things behind the scenes, but I'm
starting to run out of ideas.

Thanks,
Eric


(Brian Gesiak) #3

Yikes, sounds like a nasty bug. Thanks for investigating, Eric!

I'm all for a fix. You may have already considered this, but perhaps the
Android-specific workaround could be put into swift-corelibs-foundation? I
wonder which the core team would prefer?

- Brian Gesiak

···

On Sun, Nov 6, 2016 at 6:58 PM, Eric Wing via swift-users < swift-users@swift.org> wrote:

On 10/31/16, Eric Wing <ewmailing@gmail.com> wrote:
> Hello, I've been trying to get Swift 3 working on Android. (I
> previously had Swift 2.x working.)
>
> I have the baseline components built following the standard
> Android/Swift instructions.
>
> But when I go to make a trivial, but real Android
> app (i.e. start in Java Activity and use JNI/LoadLibrary to get to
> Swift), the Swift code seems to hang (freeze?) whenever my Swift code
> calls print("foo").
>
> Removing all print calls, allows my trivial code to run correctly. But in
> slightly more complicated test programs (which call into other C
> libraries), I'm getting program crashes. It looks like libc triggers
> some kind of abort call in these cases. I know these C libraries work
> in non-Swift cases.
>
> My best guess right now is since Swift print() is also broken, I think
> there might be some problem related to libc++ (and maybe its
> interaction with libc) which is used in the build process. (The
> Android NDK docs warn about std::cout buffering breaking if you have
> multiple static linked libc++, but I'm not statically linking it.)
>
> I'm currently using libc++_shared.
> I updated my repo a few days ago which includes a fix for NDK r13
> which I am using.
>
>
> Does this problem ring a bell for anybody?
> Or can somebody help me figure out how to start debugging this? I've
> been trying a lot of different things behind the scenes, but I'm
> starting to run out of ideas.
>
> Thanks,
> Eric
>

I discovered there is a serious deadlock bug in Android 5.0. flockfile
on stdout/stderr causes a deadlock. Swift print() ultimately calls
flockfile, which in turn causes a deadlock. I verified this by first
commenting out the lock functions in the print function, and then
later by commenting out the flockfile/funlockfile implementations in
the Stubs.cpp.

One of the comments here mentions this bug:
https://chengyihe.wordpress.com/2015/10/31/android-child-
process-hits-mutex-deadlock-in-printf-after-fork/

The workaround seems to be either to remove the call to flockfile() or
update to Android 5.1. I upgraded my device to 5.1 and the problem
disappeared.

But thanks to Android fragmentation, going to 5.1 this means we lose
another 13.1% of devices, leaving us only 40.6% of devices.

This does bring up another issue though, at least for print() and
anything stdout/stderr related on Android. On Android, sending
anything to stdout/stderr via the NDK is effectively useless because
they are effectively sent to /dev/null. (The ‘adb shell setprop
log.redirect-stdio true’ trick doesn’t work for the NDK. There is one
convoluted trick to redirect using pipes in your codebase, but that is
a different can of worms.)

In general, print() statements need to go through
__android_log_write() and __android_log_print() on Android for anybody
to see anything. Is this something we should implement in Swift?

Thanks,
Eric
_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users