Android Development in C
This article just describes how to build a simple terminal application in C and C++ that finally runs on an Android device. GUI development is not addressed.
Prerequisites
Packages required/recommended for ARM development in C
Most Android devices are equipped with a APU utilizing ARM architecture. Therefore, binaries for ARM must be created. The following packages must be used on Debian systems to install compilers for C and C++:
- gcc-arm-linux-gnueabi
- g++-arm-linux-gnueabi
- binutils-arm-linux-gnueabi (recommended)
The program adb is required for communicating with the Android device. Package: android-tools-adb - Documentation can be found here.
Troubleshooting adb
If "adb devices" returns "???????????? no permissions", the following commands can help:
adb kill-server && adb start-server
This should be executed as root.
Mounting /system read-write
That's required to write binaries to /system/bin so they can be executed. Normally, /sdcard is mounted with noexec option, hence it doesn't qualify for starting binaries from there.
mount -o rw,remount /system
Terminal emulator on Android device
A terminal emulator can be used on the device to start programs.
- Android Terminal Emulator by Jack Palevich in Google Play Store
- Android Terminal Emulator by Jack Palevich in F-Droid Repo
Hello World example in C
helloworld.c
#include <stdio.h> int main(int argc, char** argv) { printf("Hello world!\n"); return 0; }
Building and deploying
arm-linux-gnueabi-gcc helloworld.c -o helloworld
This requires the destination system to have a symbol link /lib to /system/lib. If this is not yet the case and can be done (i.e., root access is available):
mount -o rw,remount / ln -s /system/lib/ lib
Otherwise the program can be linked statically:
arm-linux-gnueabi-gcc -static helloworld.c -o helloworld
The size difference is 8040 bytes for the dynamically linked version and 589 534 bytes (576 KiB) for the statically linked version.
Finally, the binary can be stored on the destination system:
adb push helloworld /system/bin
Running
Either with adb shell /system/bin/helloworld
or by executing it on the device using a terminal emulator.
Hello World example in C++
helloworldcpp.c++
#include <iostream>
using namespace std;
int main (int argc, char **argv) { cout << "Hello World from C++!" << endl; }
Building and deploying
arm-linux-gnueabi-g++ -static helloworldcpp.c++ -o helloworldcpp adb shell /system/bin/helloworldcpp
Compiling GNU coreutils
Downloading
I am developing on Ubuntu 18.04 Bionic which ships with coreutils 8.28. coreutils have a lot of dependencies (like autoconf, autopoint, patch...), so to keep things simple, I grab the sources that match my operating system's version: coreutils_8.28.orig.tar.xz 5.0 MiB Download page
Customizing
After extracting the files from that archive, I do a "./configure" in the directory that contains the files. This process takes about 1 min 45 sec. After that it is important to customize the "Makefile": Search for a line containing
CC = gcc -std=gnu99
and replace it by
CC = arm-linux-gnueabi-gcc -std=gnu99 -static
Why "-static"? Otherwise the programs get linked dynamically, so they depend on the loader to resolve linked libraries. When testing on my Ubuntu machine, it was no problem:
qemu-arm -L /usr/arm-linux-gnueabi/ program
However, on my destination device running Cyanogenmod 9, I always get a "No such file or directory" error when trying to run those files.
Building
After doing a "make" - which runs about 2 min 30 sec - everything works fine. If you want to test if a program was linked statically or dynamically, use the file program:
file program
Example output:
$ file src/sleep src/sleep: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), statically linked, for GNU/Linux 2.6.32, BuildID[sha1]=06a81ace0e2dabd5491dea6923ce0832295ba3f8, not stripped