Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

depends: Add Android NDK support #16110

Merged
merged 13 commits into from Nov 4, 2019
Merged

Conversation

icota
Copy link
Contributor

@icota icota commented May 28, 2019

This allows one to build the dependencies with the Android SDK and goes towards fixing #11844. It has been tested to work with:
make HOST=aarch64-linux-android ANDROID_API_LEVEL=28 ANDROID_TOOLCHAIN_BIN=/home/user/Android/Sdk/ndk-bundle/toolchains/llvm/prebuilt/linux-x86_64/bin NO_QT=1 NO_WALLET=1

@icota icota changed the title Scripts and tools: Add Android NDK support to depends depends: Add Android NDK support May 28, 2019
@laanwj
Copy link
Member

laanwj commented May 28, 2019

Very cool, concept ACK

@fanquake
Copy link
Member

Concept ACK

@fanquake
Copy link
Member

@greenaddress You might be interested in taking a look at this?

@laanwj
Copy link
Member

laanwj commented Jun 13, 2019

Would be awesome if someone who is building bitcoin core for Android would review and test this. This change is pretty minimal.

I'd love to have a arm64-android gitian build at some point so that software such as abcore can include that instead of having to build it out of band with additional patch-sets.

@greenaddress
Copy link
Contributor

Google now mandates that all ndk based application ship all 4 binaries armv7a/aarch64/x86/amd64 - should be tested on all (and ideally added to the CI to prevent breakage). Specifically you may have some issue on 32 bit without some extra flags. See https://GitHub.com/GreenAddress/bitcoin_ndk for what's currently required to build core with NDK

Haven't reviewed the PR patches yet, will have a look later

@fanquake
Copy link
Member

I had a quick test of this. Installed the Mac ndk from https://developer.android.com/ndk/downloads/.

Couldn't get Boost 1.70.0 to build correctly, but reverting to 1.64.0 seemed to work.
I also had to add andriod_RANLIB=$(ANDROID_TOOLCHAIN_BIN)/$(HOST)-ranlib to the android host for the build to complete. I was using a command like:

NO_QT=1 NO_WALLET=1 ANDROID_API_LEVEL=29 ANDROID_TOOLCHAIN_BIN=/Users/michael/Library/Android/macOS-ndk-bundle/toolchains/llvm/prebuilt/darwin-x86_64/bin make HOST=aarch64-linux-android

@icota icota force-pushed the add-android-to-depends branch 2 times, most recently from 4d27cd2 to 11e2173 Compare July 10, 2019 11:56
@icota
Copy link
Contributor Author

icota commented Jul 10, 2019

Thanks @fanquake, after adding the ranlib line I was able to build on macOS High Sierra (with Boost 1.64.0) by running:
make HOST=aarch64-linux-android ANDROID_API_LEVEL=29 ANDROID_TOOLCHAIN_BIN=/Users/igor/Library/Android/sdk/ndk-bundle/toolchains/llvm/prebuilt/darwin-x86_64/bin/ NO_QT=1 NO_WALLET=1

@greenaddress I believe Google only mandates 64-bit in addition to 32-bit. Pure 64-bit native packages are fine. Going forward I don't personally see much demand for 32-bit since Android is moving to 64-bit so those devices are going to be increasingly rare and most likely underpowered.

@BlockMechanic
Copy link
Contributor

This seems to configure a build that has QT disabled, am I correct ? Also doesnt this :- #13696 resolve the QT issue?

@icota
Copy link
Contributor Author

icota commented Aug 6, 2019

@BlockMechanic, this is built without Qt. You probably don't want it anyway as the Qt Widgets approach Bitcoin-Qt uses is not really optimised for Android. Qt Quick OTOH would be grand as an official mobile UI but that's a topic for another PR.

@BlockMechanic
Copy link
Contributor

@icota thanks for the response. I'll still try to build it with QT as is though if a project to make it mobile friendly is started, i'd be happy to help

@BlockMechanic
Copy link
Contributor

Finally got down to it last night , only to see that the example also stipulates NO_WALLET=1 ... why is this ?

@icota
Copy link
Contributor Author

icota commented Aug 7, 2019

@BlockMechanic, there is no particular reason. It's just an example. I haven't tested it myself, but I guess you can build with wallet if you wish so.

@icota
Copy link
Contributor Author

icota commented Sep 16, 2019

Rebased on top of master and added config options and a patch file enabling Android build of Qt. Thanks @BlockMechanic!

Copy link
Member

@Sjors Sjors left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried to build f2d33de on macOS 10.14:

$ make HOST=aarch64-linux-android ANDROID_API_LEVEL=28 ANDROID_TOOLCHAIN_BIN=/Users/sjors/dev/android-ndk-r20/toolchains/llvm/prebuilt/darwin-x86_64/bin
...
Building zlib...
/Users/sjors/dev/android-ndk-r20/toolchains/llvm/prebuilt/darwin-x86_64/bin/aarch64-linux-android-ar -o libz.a adler32.o crc32.o deflate.o infback.o inffast.o inflate.o inftrees.o trees.o zutil.o compress.o uncompr.o gzclose.o gzlib.o gzread.o gzwrite.o 
/Users/sjors/dev/android-ndk-r20/toolchains/llvm/prebuilt/darwin-x86_64/bin/aarch64-linux-android-ar: no operation specified
make[1]: *** [libz.a] Error 1
make: *** [/Users/sjors/dev/bitcoin/depends/work/build/aarch64-linux-android/zlib/1.2.11-d7483e8fc2d/./.stamp_built] Error 2

Building depends with NO_QT=1 does work.

Building the project fails:

./configure --prefix=/Users/sjors/dev/bitcoin/depends/aarch64-linux-android
make
...
  AR       leveldb/libleveldb.a
/Users/sjors/dev/bitcoin/depends/aarch64-linux-android/share/../lib/libevent.a(evutil_rand.o): In function `evutil_secure_rng_add_bytes':
/Users/sjors/dev/bitcoin/depends/work/build/aarch64-linux-android/libevent/2.1.8-stable-254609abc4b/evutil_rand.c:198: undefined reference to `arc4random_addrandom'
clang++: error: linker command failed with exit code 1 (use -v to see invocation)

Cross-compiling from macOS is generally a pain, so I don't mind if it doesn't work (as long as that's documented).

I also tried cross-compiling on Ubuntu 18.04. This also failed for me:

make HOST=aarch64-linux-android ANDROID_API_LEVEL=28 ANDROID_TOOLCHAIN_BIN=/home/dev/android-ndk-r20/toolchains/llvm/prebuilt/linux-x86_64/bin
...
Info: creating cache file /home/dev/bitcoin/depends/work/build/aarch64-linux-android/qt/5.9.8-feb0561b74d/qtbase/.qmake.cache
ERROR: No value supplied to command line option 'android-sdk'.
funcs.mk:251: recipe for target '/home/dev/bitcoin/depends/work/build/aarch64-linux-android/qt/5.9.8-feb0561b74d/qtbase/.stamp_configured' failed
make: *** [/home/dev/bitcoin/depends/work/build/aarch64-linux-android/qt/5.9.8-feb0561b74d/qtbase/.stamp_configured] Error 3

Similarly it's happy with NO_QT=1. I run into the same arc4random_addrandom error when trying to build bitcoind though.

Can you add or link to instructions on how to produce an APK? I'll try an IBD on my Xiaomi Mi A1 (which works with ABCore). Is it possible to create an APK for test/test_bitcoin as well?

In a followup we can figure out how to run the functional test suite on the device; that's probably a lot more involved.

depends/README.md Outdated Show resolved Hide resolved
depends/README.md Outdated Show resolved Hide resolved
depends/README.md Outdated Show resolved Hide resolved
@icota
Copy link
Contributor Author

icota commented Sep 16, 2019

Thanks for testing @Sjors. The line I'm using to build (with Qt) is:

ANDROID_SDK=/home/user/Android/Sdk ANDROID_NDK=/home/user/Android/Sdk/ndk-bundle make HOST=aarch64-linux-android ANDROID_API_LEVEL=28 ANDROID_TOOLCHAIN_BIN=/home/user/Android/Sdk/ndk-bundle/toolchains/llvm/prebuilt/linux-x86_64/bin

I'd be thankful if you could retry the build on both Ubuntu and Mac (mine is out of commision right now). I will make sure to update the docs with this command and your suggestions.

@Sjors
Copy link
Member

Sjors commented Sep 16, 2019

I downloaded the sdk-tools from https://developer.android.com/studio#downloads, extract it to ~/dev/android-tools. I installed Java 8 (instead of 12):

brew tap adoptopenjdk/openjdk
brew cask install adoptopenjdk8

I used ~/dev/android-tools to download the SDK: bin/sdkmanager "build-tools;28.0.3"

I then added the ANDROID_SDK and ANDROID_NDK bits:

ANDROID_SDK=/Users/sjors/dev/android-tools ANDROID_NDK=/Users/sjors/dev/android-ndk-r20 make HOST=aarch64-linux-android ANDROID_API_LEVEL=28 ANDROID_TOOLCHAIN_BIN=/Users/sjors/dev/android-ndk-r20/toolchains/llvm/prebuilt/darwin-x86_64/bin

I still get the same error with zlib. Maybe I'm pointing to the wrong places?

@BlockMechanic
Copy link
Contributor

To get an actual APK there are additional files required such as AndroidManifest.xml and gradle files. Also the final APK in my case was built using androiddeployqt. I'll work a clean PR that highlights this and has appropriate code and notes

@icota
Copy link
Contributor Author

icota commented Sep 17, 2019

I've updated the docs to make it clear where to get the SDK/NDK/Platform packages and what ANDROID_API_LEVEL and other options mean. Personally, I targeted and used as an example API level 28 because that was the latest at the time.

@Sjors
Copy link
Member

Sjors commented Sep 17, 2019

I was missing some pieces: bin/sdkmanager "ndk-bundle" "platform-tools" "platforms;android-28". So I guess I didn't have to download this NDK seperately.

It also looks like it installed the SDK at ~/dev/platforms/android-28, not in ~/Library/Android as some articles suggest, in other words in ../platforms relative to where I extract the SDK tools. Similary I put ndk-bundle in ~/dev, not nested under the SDK.

I ended up with this incantation:

ANDROID_SDK=/Users/sjors/dev/platforms/android-28 ANDROID_NDK=/Users/sjors/dev/ndk-bundle make HOST=aarch64-linux-android ANDROID_API_LEVEL=28 ANDROID_TOOLCHAIN_BIN=/Users/sjors/dev/ndk-bundle/toolchains/llvm/prebuilt/darwin-x86_64/bin

Which results in the same zlib error. Not sure what I'm doing wrong here.

I guess I don't need an APK to test, but could use the Android debugger directly? No idea how that works though.

@Sjors
Copy link
Member

Sjors commented Oct 14, 2019

I upgraded to macOS Catalina in the mean time.

I can build depends:

cd depends
ANDROID_SDK=/Users/sjors/dev ANDROID_NDK=/Users/sjors/dev/ndk-bundle make HOST=aarch64-linux-android ANDROID_API_LEVEL=29 ANDROID_TOOLCHAIN_BIN=/Users/sjors/dev/ndk-bundle/toolchains/llvm/prebuilt/darwin-x86_64/bin

And then build QT:

./configure --prefix=$PWD/depends/aarch64-linux-android
make
file src/qt/bitcoin-qt 
src/qt/bitcoin-qt: ELF 64-bit LSB shared object, ARM aarch64, version 1 (SYSV), dynamically linked, interpreter /system/bin/linker64, with debug_info, not stripped

@BlockMechanic I'll try with older SDK versions after I get the most recent version to work on a device.

@greenaddress
Copy link
Contributor

Unless the qt gui as currently in repo can be used on android i think this PR should limit itself to NDK support in the depends builds system without qt support. Even if the QT current GUI worked on android i would argue it wouldn't be very useful.

I am aware of a QML PR but I imagine this PR needs to go first anyway and I'd like to think of this PR in the context of master.

Qt build support IMHO should come when there's something usable on android as a separate PR.

Also I think support for Android needs to be for all 4 currently supported targets (i686-linux-android, x86_64-linux-android, aarch64-linux-android and arm-linux-androideabi). As a note a lot of emulators images are i686.

Android support should also be better than just android 29. I suggest android 19 as minimum for 32 bit and 21 as minimum for 64 bit (64 bit afaik was introduced at 21) or both android 21 should also be reasonable at this point (although declining, lose 6.9% of android market)

Note that the libevent patch from bitcoin_ndk but it's actually to patch libevent code with code from a newer version of libevent - once core updates libevent it won't be necessary.

@icota
Copy link
Contributor Author

icota commented Oct 15, 2019

The Qt Widgets GUI as is in master does indeed work. It's a weird look on mobile but it does work and I'd argue it might even be useful for some people:
Screenshot_2019-10-12-16-01-32-666_org bitcoin core

I'm working on a PR that I hope will make packaging as easy as make apk. So even though I initially intended this PR to be without Qt if it works I'd argue it should stay.

Supporting all the architectures and old API levels I'm a bit more ambivalent about. I just checked on geizhals.eu and out of 3186 Android phones out there only 2 run x86, that's 0.06% marketshare. 32-bit ARM is probably not going to run Core all that well. Android API 19 was released 6 years ago.

In my mind running Bitcoin Core is a flagship device game so that's what I focus on. But like I said patches for supporting other arch or lower API levels are welcome. I'll even concede that x86_64 is useful because of the emulators.

@BlockMechanic
Copy link
Contributor

BlockMechanic commented Oct 15, 2019

@icota Supporting all abis in this PR can be done by cherry picking from the one i built atop yours.

I have been using API level 24 specifically because starting from Android API level 24 (Android 7.0 Nougat) ifaddrs.h is supported officially, so the need to use custom implementations as was done for earlier versions is removed. In as far as i can tell API level 24 is the earliest version that can compile core as is without modifications to core's code.

While indeed android devices vary, flagship devices from 3-4 years ago, hardware which by today's standards is considered mid-range are perfectly capable of running it. Today's flagship devices would not be bothered.

A mobile device user's only issues are storage (if they do not prune) and data use, which is easily resolved by setting the app's use to wifi only.

I fully support the inclusion of QT in the android depends builds. And on top of the previous points in favour of keeping the changes, i'd like to again point out that android is now by far the most dominant OS, and I strongly believe that our efforts to enable FULL support of it are on the right track.

@icota
Copy link
Contributor Author

icota commented Oct 15, 2019

@icota Supporting all abis in this PR can be done by cherry picking from the one i built atop yours.

Looking at the commits in #17078 I think they are going to conflict. It's probably better you make a PR to icota:add-android-to-depends like we agreed there.

@greenaddress
Copy link
Contributor

@icota if the gui is not pretty but otherwise 'usable' then linking qt makes sense - AFAIK 32bit requires some extra flags I think so I think makes sense to covered by this PR (and in CI and gitian ideally)

@BlockMechanic as far as i know you don't need to provide ifaddrs even on lower android versions - see master of https://github.com/greenaddress/bitcoin_ndk and supports android 19 as min version for 32bit and 21 for 64 bit https://github.com/greenaddress/bitcoin_ndk/blob/3023f04ea21f7f4cd0cee456f4ccf6795cc83f15/fetchbuild.sh#L41 and doesn't provide ifaddrs (using latest ndk, r20)

@BlockMechanic
Copy link
Contributor

@greenaddress during my attempts to produce and test an apk, at first it would not compile properly, then the apk would not start , then it would crash immediately after sync. A lot of the time (using gdb) I kept getting traces to various aspects of threads and networking. Eventually after a lot of google searches and reading comments across github and stackoverflow, i used api 24 and I got a stable build without need to mod core. It is possible we could go lower, but i haven't tried. Another part of why i am fine with 24 is that according to the distro map on https://developer.android.com/about/dashboards , it covers ~60% of known active android devices and IMO devices running lower versions of android are also likely to be underpowered and will have difficulty running core.

Add support for armv7a, i686 and x86_64 archs to android.mk
Add -fPIC to depends file as anddroid requires it see https://stackoverflow.com/questions/30498776/position-independent-executables-and-android
@icota
Copy link
Contributor Author

icota commented Oct 23, 2019

With the latest changes (thanks @BlockMechanic) you can build a prefix for any of the supported Android ABIs (armv7a-linux-android, x86_64-linux-android, i686-linux-android or aarch64-linux-android).

To test the CLI binaries push to a device and run. bitcoin-qt however requires 629db61 and make apk. Take a look at #17227.

@ryanofsky
Copy link
Contributor

@dongcarl @theuni do you want to weigh in in the build changes here and maybe concept ACK?

The changes required are surprisingly small and sensible, and currently let you build for android from both linux and macos, and we should be able to add a travis target too #16110 (comment)

@laanwj laanwj added this to the 0.20.0 milestone Oct 26, 2019
@laanwj
Copy link
Member

laanwj commented Oct 28, 2019

@dongcarl @theuni do you want to weigh in in the build changes here and maybe concept ACK?

Agree, it's also early enough in the merge window of 0.20 to be able to find more subtle problems before release.

@cryptozeny
Copy link

AWESOME

Copy link
Member

@Sjors Sjors left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ACK f9af3ce. I'm OK with merging and then improving later.

I built depends for one of the four triplets (64 bit ARM) on macOS 10.15.1 using SDK version 24 which is the minimum for now, as discussed above. We can try to support older versions in a followup PR, though generally we don't (actively) support end-of-life distros.

Tested bitcoind on a Xiaomi Mi A1 (64 bit, Android 9). First I turned on developer mode, and enabled USB debugging. I then used ABD:

adb devices
add push src/bitcoind /data/local/tmp
add push src/bitcoin-cli /data/local/tmp
add push src/test/test_bitcoin /data/local/tmp
adb shell
cd /data/local/tmp
mkdir .bitcoin
./bitcoind -datadir=.bitcoin

Initially I got a CANNOT LINK EXECUTABLE "./bitcoin-cli": library "libc++_shared.so" not found error. I tried SDK version 29 instead, but that didn't help. Using make LDFLAGS="-static-libstdc++" did the trick. IDB in progress... :-)

I also ran ./test_bitcoin.

Nit: in b68f2a6 you add _config_opts_aarch64_android which you then remove in e4c319e. You can use git interactive rebase to edit that first commit and drop the second.

Fun fact: if you have ABCore installed, it will try to mess with bitcoind via RPC :-) And if you unplug USB even a daemon will stop.

@@ -30,8 +30,17 @@ Common `host-platform-triplets` for cross compilation are:
- `aarch64-linux-gnu` for Linux ARM 64 bit
- `riscv32-linux-gnu` for Linux RISC-V 32 bit
- `riscv64-linux-gnu` for Linux RISC-V 64 bit
- `aarch64-linux-android` for Android ARM 64 bit
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't forget to add the new configurations you added: armv7a-linux-android, x86_64-linux-android, i686-linux-android or aarch64-linux-android

Please also mention the minimum supported version. I believe you tested down to 24?

@laanwj
Copy link
Member

laanwj commented Nov 4, 2019

Agree with @Sjors. Thanks for testing.
The risk of merging this seems to be low, definitely early in the 0.20 release cycle, so going ahead with it.

laanwj added a commit that referenced this pull request Nov 4, 2019
f9af3ce Android: add all arch support (Block Mechanic)
d419ca7 depends: export dynamic JNI symbols from static qtforandroid.a (Igor Cota)
ed30684 Qt: patch androidjnimain.cpp to make sure JNI is initialised when statically compiled (Igor Cota)
e4c319e builds: remove superfluous config_opts_aarch64_android (Igor Cota)
24ffef0 Patch libevent when building for Android (fix arc4random_addrandom) (Igor Cota)
f1e40b3 Update bitcoin_qt.m4 (BlockMechanic)
b4057d8 Define TARGET_OS when host is android (Igor Cota)
80b475f Fix Android zlib cross compilation issue (https://stackoverflow.com/questions/21396988/zlib-build-not-configuring-properly-with-cross-compiler-ignores-ar) (Igor Cota)
45f8219 Add full Android build example command and instructions on getting SDK/NDK (Igor Cota)
b68f2a6 Add config opts and patch for aarch64_android build of Qt (Igor Cota)
9c4cb01 Add ranlib to android.mk hosts file (fix OSX Android NDK build) (Igor Cota)
c2a749c Add example Android host-platform-triplet and options (Igor Cota)
0b0cff3 Add support for building Android dependencies (Igor Cota)

Pull request description:

  This allows one to build the dependencies with the Android SDK and goes towards fixing #11844. It has been tested to work with:
  `make HOST=aarch64-linux-android ANDROID_API_LEVEL=28 ANDROID_TOOLCHAIN_BIN=/home/user/Android/Sdk/ndk-bundle/toolchains/llvm/prebuilt/linux-x86_64/bin NO_QT=1 NO_WALLET=1`

ACKs for top commit:
  Sjors:
    ACK f9af3ce. I'm OK with merging and then improving later.

Tree-SHA512: cb805115ebe5c9e33db2bf3eab8628808fe3f50052053d8877d8b8e4406d6fea1ed9e5c4dff85d777fb99c81be6ffb9d95a0e6d32344e728e5e0da6c653e2ce7
@laanwj laanwj merged commit f9af3ce into bitcoin:master Nov 4, 2019
maflcko pushed a commit to maflcko/bitcoin-core that referenced this pull request Nov 5, 2019
…argets and API levels

3fe1aba depends: move README.md Android instructions to a separate section (Igor Cota)
aa9b84a depends: update README.md with working Android targets and API levels (Igor Cota)

Pull request description:

  Per @Sjors comments in bitcoin#16110 (review)

ACKs for top commit:
  Sjors:
    ACK 3fe1aba

Tree-SHA512: 7a2e676070d51c7a4291b0d4b638f52321c08cc6ebe2bd2c02ba62f6cc3dd8a73227df4693c6ce9201863eb0bf26e0133805347b9016cb0f9a389a49cc9492aa
sidhujag pushed a commit to syscoin/syscoin that referenced this pull request Nov 7, 2019
f9af3ce Android: add all arch support (Block Mechanic)
d419ca7 depends: export dynamic JNI symbols from static qtforandroid.a (Igor Cota)
ed30684 Qt: patch androidjnimain.cpp to make sure JNI is initialised when statically compiled (Igor Cota)
e4c319e builds: remove superfluous config_opts_aarch64_android (Igor Cota)
24ffef0 Patch libevent when building for Android (fix arc4random_addrandom) (Igor Cota)
f1e40b3 Update bitcoin_qt.m4 (BlockMechanic)
b4057d8 Define TARGET_OS when host is android (Igor Cota)
80b475f Fix Android zlib cross compilation issue (https://stackoverflow.com/questions/21396988/zlib-build-not-configuring-properly-with-cross-compiler-ignores-ar) (Igor Cota)
45f8219 Add full Android build example command and instructions on getting SDK/NDK (Igor Cota)
b68f2a6 Add config opts and patch for aarch64_android build of Qt (Igor Cota)
9c4cb01 Add ranlib to android.mk hosts file (fix OSX Android NDK build) (Igor Cota)
c2a749c Add example Android host-platform-triplet and options (Igor Cota)
0b0cff3 Add support for building Android dependencies (Igor Cota)

Pull request description:

  This allows one to build the dependencies with the Android SDK and goes towards fixing bitcoin#11844. It has been tested to work with:
  `make HOST=aarch64-linux-android ANDROID_API_LEVEL=28 ANDROID_TOOLCHAIN_BIN=/home/user/Android/Sdk/ndk-bundle/toolchains/llvm/prebuilt/linux-x86_64/bin NO_QT=1 NO_WALLET=1`

ACKs for top commit:
  Sjors:
    ACK f9af3ce. I'm OK with merging and then improving later.

Tree-SHA512: cb805115ebe5c9e33db2bf3eab8628808fe3f50052053d8877d8b8e4406d6fea1ed9e5c4dff85d777fb99c81be6ffb9d95a0e6d32344e728e5e0da6c653e2ce7
@immense055
Copy link

@bitcoin bitcoin locked and limited conversation to collaborators Jul 26, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet