How does android build system work? - android

I like to have a high level understanding of how the android build system work. That is when does it complement the GNU make and the Linux build system and when and how does it differ? What I mean by this is how come sometimes we use make files to add functionality to the final image, and sometimes we use Andoroid.mk? Then again sometimes we use both. Does anyone have a good grasp of how these components work together?
For example, I used just a make file to add a simple program as a module. On the other hand, looking at the /external directory some of the modules have Android.mk file and some have a make file also. Then there is the bionic directory. Can anyone elaborate please?
# arkascha- I appreciate this but I think there is a little more to it. It seems to me that GNU make has control over the Linux kernel directories and Android.mk over the Android folders; this sounds intuitive doesn't it? I was looking for a comment that would take this further and elaborate on which files need to be updated in order to add functionality. ie. looking at my build environment I have:
0628Samsung build.sh Documentation include Makefile packages sound
abi config-backup drivers init Makefile.bak pdk system
AndroidKernel.mk COPYING drivres ipc Makefile-original Platform.tar.gz tools
arch CREDITS dtbTool Kbuild mkbootimg prebuilts usr
art crypto external Kconfig mm README vendor
bin cts files kernel modules.order REPORTING-BUGS virt
bionic dalvik firmware Kernel.tar.gz ndk samples
block developers frameworks lib net scripts
bootable development fs libcore note3 sdk
build device github-repo libnativehelper out security
build_msm8974pro_kernel.sh docs hardware MAINTAINERS output
I ask this question since there does not seem to be clear understanding of the AOSP environment. For instance, this link has a section called steps for adding a new program to the Android source tree. In it they advise updating the core/main.mk file. But my environment does not really have the lines they mention. Also sometimes one does not really have a choice of using one, make file vs. android.mk, or the other. At least that has been my experience. Maybe I missed something, but what I did was to add a sample program to the external directory. I was able to compile it with the same toolchain I used to create an image and flash my phone. But the executable did not run on my phone, which led me to believe that perhaps I needed to issue other switches and set various environment variables. So I kept trying to build the image with the program included, but the build environment did not go in that directory. After looking through other directories, I realized that most of them had an Android.mk file so I added one in, and it is chugging along right now. I'll let you know how it turns out. That is why I am asking this question. Maybe I am not looking at the right place, there is no clear stable content about how to add functionality to the final image and what are the differences between what resides in each folder. There is a high level description but no discussion on here is how you add a module to this /external, /bionic, ...and here is what the end result would be.
#Dan Albert- Thanks. I am trying to map what is in the /external directory with what is on my device in an effort to get my code into the image. I am not having much luck. I followed a set of procedures to get a simple kernel module in. But I just used a simple make file as follows:
lib_src := src
lib_headers := headers
.PHONY: all $(lib_src) $(lib_headers)
$(lib_src) :
$(MAKE) --directory=$#
$(lib_*): $(MAKE) --directory=$#
obj-$(CONFIG_TOS) += examples.o
So when you say Android just uses Android.mk, I wonder. The reason being, here I just used a make file and I was able to see the resulting code in my image. Further, I'll share another example with you. Within the Android Studio projects, in order to get some native project in, you have to create a make file as well as an Android.mk. So....? There has to be more; no? Each file does have some unique functionality within the build system; don't you agree?
Please note, I am just making this argument in an effort to get my code into the finale image.
I believe I heard what is in /external directory just goes into the /system folder of the final image. But I can not validate that. Here is what is in my external directory:
aac droiddriver hyphenation libpng nist-sip sonivox
android-clat dropbear icu4c libppp noto-fonts speex
android-mock e2fsprogs iproute2 libselinux oauth sqlite
ant-glob easymock ipsec-tools libsepol objenesis srec
antlr ebtables iptables libusb okhttp srtp
apache-harmony eclipse-basebuilder iputils libusb-compat opencv stlport
apache-http eclipse-windowbuilder jack libvorbis openfst strace
apache-qp eigen javasqlite libvpx openssh stressapptest
apache-xml elfutils javassist libxml2 openssl svox
arduino embunit jdiff libxslt open-vcdiff tagsoup
bison emma jhead libyuv oprofile tcpdump
blktrace esd jmdns linux-tools-perf pixman temp
bluetooth expat jmonkeyengine littlemock ppp timezonepicker-support
bouncycastle eyes-free jpeg llvm proguard tinyalsa
brctl fdlibm jsilver lzma protobuf tinycompress
bsdiff flac jsr305 marisa-trie qemu tinyxml
bzip2 freetype junit markdown qemu-pc-bios tinyxml2
ceres-solver fsck_msdos kernel-headers mdnsresponder regex-re2 tremolo
checkpolicy ganymed-ssh2 libcap-ng mesa3d replicaisland v8
chromium gcc-demangle libffi mksh robolectric valgrind
chromium-libpac genext2fs libgsm mockito safe-iop webkit
chromium_org giflib liblzf mockwebserver scrypt webp
chromium-trace google-diff-match-patch libmtp mp4parser sepolicy webrtc
clang grub libnfc-nci mtpd sfntly wpa_supplicant_8
compiler-rt gtest libnfc-nxp naver-fonts shahin xmlwriter
dexmaker guava libnl-headers netcat sil-fonts xmp_toolkit
dhcpcd hamcrest libogg netperf skia yaffs2
dnsmasq harfbuzz libpcap neven smack zlib
doclava harfbuzz_ng libphonenumber nist-pkits smali zxing
This is basically what I have in the external/shahin directory:
sansari#ubuntu:~/WORKING_DIRECTORY/external/shahin$ more Android.mk
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= hello_world.S
LOCAL_MODULE := shahin
include $(BUILD_EXECUTABLE)
sansari#ubuntu:~/WORKING_DIRECTORY/external/shahin$ more hello_world.S
.syntax unified
.global main
main:
push {ip, lr}
ldr r0, =message
bl printf
mov r0, #0 # Return 0.
pop {ip, pc}
message:
.asciz "Hello, world.\n"
A simple assembly code and an Android.mk file. But when I issue make from the root of the project I am not sure if this is added to the final image. I don't see any object file created afterwards in this directory. Am I mistaken perhaps? My question is how do I get this into the final image?

Only Android.mk is used by the Android platform build system. There are normal makefiles in the external/ directory because those projects use make when built outside Android, and we just mirror their source. Still, we only use the Android.mk to build it for Android.
Bionic is no different than the other projects in Android, it just has somewhat more complicated Android.mk structure to deal with the complexity of CPU specific sources and various issues that come along with building low level system libraries.
Android.mk is still just make. Each include $(BUILD_*) gets handled in build/core to eventually be rewritten as a normal make rule.

Related

can I use an elf file as a library for an apk?

I have code I compiled already, and wonder if I can use the resulting executable, which is in elf format as a library in an APK and how please.
#Gabe Sechan; thanks. I did build a JNI project. I am having some issues importing the code from my other project into JNI. I wonder if you can suggest the best way to import it. I can post my Android.mk file if you like. Basically, it seems that project finds the first file, and an associated header file. That file, in turn uses variables, which are defined in another file. But there is no include statement.
You know? I figured if I can use a JAR file as a library, perhaps I could use an executable also. I need to learn more.
# Chris Straton - Thanks. I did edit my post with a comment to address the toolchain issue. But then, I modified it. Regardless, What I stated was if I use the toolchain that is recommended by my target platform, then I should be able to run it on my phone right?
Further; I re-read your comment about ABI and libc compatibility. The two devices are tegra t132 and Samsung S-N900P. So libc should not be an issue since both devices run Android; right? As far as I know both have an arm chip. Is there anything else I need to look into?
Elf is an executable, not a library. What you want to do is get a .so file and link to it via JNI.
You could possibly run it as a command line program and interact with it via its stdin and stdout, but that would be clunky when you can just use it as an actual library.

Much smaller .so file for identical source code

My Android application (game) uses native C++ code for certain operations. That is, I use the Android NDK. The native C++ code is compiled for armeabi only (to the default, armeabi-v5).
The last time I built my c++ code into nativestuff.so was a few months ago, in another computer (Windows 7 + cygwin, because cygwin is recommended for compiling with Android NDK).
I just installed the NDK on my current PC (Windows 7), along with the newest cygwin, and rebuilt the c++ code for my app.
To my surprise, it generates an .so file of 14KB, while the previous .so file was 37KB. Note that the c++ source files are exactly the same (they haven't changed for a year), my project is under version control, so I'm 100% sure.
I tested the c++ functionality in the game, and it works exactly as before, without any bugs.
My C++ files use only cstring.h and jni.h as includes. My Android.mk is as follows:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := nativestuff
LOCAL_SRC_FILES := nativestuff.cpp
include $(BUILD_SHARED_LIBRARY)
Any idea why the drastic change in .so filesize?
(I added the linux tag as well to this question, because maybe it's a general thing so I want to make sure that linux gurus also check it.)
Run objdump -x file.so on both versions. This will list all the sections and their sizes. That should give you a clue as to where the problem lies. (i.e. is there a new .debug section that's 23KB long? Maybe debug mode got enabled.)
If your code sections are radically different, compare the output of objdump -d file.so. Maybe your compiler automatically inlined more code, which saved a lot of space.
If another section is new/different, post the output in another SO question.
Maybe the previous .so was generated with debugging information.
(compiled with gcc -g option)
You may try one thing: use the command size executable-name. That will give you size of the different areas of your executable code. If the previous build is available do the same to that. You may get an idea where the change is.

What is the standalone toolchain?

I am trying to understand what a standalone toolchain means.
Following are my findings.
A toolchain which is ready to use with all the configuration that is the system headers and libraries in the correct path . For Android it will also have the API headers in the path where the toolchain can look it up. Why the term "standalone"? This probably will be different that the regular toolchain in the sense that the R T will need to be configured and made ready for android use withe sysroot and libc header paths given etc.
Please comment .
Hmm, I was compiling for android and one process was running a script called make-standalone-toolchain.sh a standalone toolchain is created .I was going through this script to understand what this is doing. Not really good at shell scripting. But made out certain things. ""Generate a customized Android toolchain installation that includes a working sysroot. The result is something that can more easily be used as a standalone cross-compiler, e.g. to run configure and make scripts." --toolchain arch ndk-dir package-dir system platform variables are set Compute source sysroot
SRC_SYSROOT="$NDK_DIR/platforms/$PLATFORM arch-$ARCH" Copying sysroot headers and libraries... libstdc++ headers and libraries... prebuilt binaries.all into a temporary folder then a copying from Tmp dir to install
dir creating a tar ie a package file to add the tmpdir wanted to know what exactly is happening here or a link or suggestion where to look.but ofcourse dont want to read very elaborate manuals.
~
This blog posting may answer your question:
http://clseto.mysinablog.com/index.php?op=ViewArticle&articleId=3480794
There is a recommended way to build native C/C++ program on Android: List your source files in a script (Android.mk) and run 'ndk-build'. It may not be a problem if you are writing new programs but if you already have a working build script (like those open source softwares) which can build you program nicely on Linux, it would be a headache to migrate your script to Android.mk. All you need in this situation is a C/C++ cross compiler and then replace the variables in your script (such as CC, CXX, AR, AS, RANLIB, ...) to something like 'arm-linux-androideabi-gcc', 'arm-linux-androideabi-g++', ...
Fortunatley, inside the 'Android NDK Dev Guide', there is a section 'Standalone Toolchain' which just describes what we need....
First of all, the best guide for stand alone toolchains in Android is here: https://developer.android.com/ndk/guides/standalone_toolchain.
I have used it several times for different devices and platform.
You need to download NDK and then run the script 'make-standalone-toolchain.sh' with a few parameters (as said in the link above) that will determine the API levels of your apps, the architecture of the device etc.
The output of the script will be a directory that you can use as a toolchain in order to cross compile native C/C++ code to run on Android devices. You need to put in your Makefile the path to the toolchain directory and add the architecture suffix for the binaries inside (for example 'arm-eabi-'). Something like:
CROSS_COMPILE = /path-to-toolchain-dir/bin/arm-eabi-
There should be files like '/path-to-toolchain-dir/bin/arm-eabi-gcc' in your toolchain directory.
Anyway, this will tell the Makefile to use your toolchain's binaries in order to compile the C/C++ native code and create the compatible executables for your target machine.
For example, this is the commands I used to create a stand alone tool chain for a certaion Android device:
./make-standalone-toolchain.shj --arch=arm --platform=android-21 --install-dir=<dest-dir> --toolchain=arm-linux-androideabi-4.9

NDK build C++ only application

I am trying to build a native daemon on Android. The purpose to to control some specific hardware, and Java applications will be able to communicate to this daemon using sockets.
I have been using cmake meanwhile to compile my libraries, demos and the real daemon (which works fine BTW). I am now trying to do 2 different things:
Build the same apps using ndk-build.
Port the C++ daemon to an Android service, by making JNI calls very similar to the way the c++ daemon works.
As far as I understand, ndk-build cannot make native applications, but only native libraries, which in turn can be loaded by the Java GUI... am I correct? For step1 I don't really need java (and I have proven it already), but I have yet found a way for ndk-build to spit an elf application.
For reference - I am using cmake, as described here: http://opekar.blogspot.com/2011/06/android-cmake-is-much-easier-in-ndk-r5b.html
This way I can have builds for "normal" linux, and also android using out of source builds. Quite nice hack if you ask me.
An alternative is to use the script make-standalone-toolchain.sh bundled with the NDK to create a stand-alone toolchain, then use it to compile your project. The shell code below illustrates how to use it:
# Assumed path to the NDK, change it to suit your environment.
NDK_HOME=$HOME/bin/android-ndk-r8e
# Desired API and NDK versions and destination folder of
# the stand-alone toolchain, change them to suit your needs.
api=14
ver=4.7
folder=$HOME/bin/android-$api-ndk-$ver
# Create folder if it doesn't already exist.
mkdir -p $folder
$NDK_HOME/build/tools/make-standalone-toolchain.sh \
--toolchain=arm-linux-androideabi-$ver \
--platform=android-$api --install-dir=$folder
Running the lines above will generate a new stand-alone toolchain at $HOME/bin/android-14-ndk-4.7, which you can then use as any regular C/C++ cross-compilation toolchain.
The advantage of working with a stand-alone toolchain is that it makes cross-compiling Linux projects to Android a breeze; see for example my port of Valgrind to Android ARMv7.
As mentioned by #Mārtiņš Možeik in one of the comments, this pice of Android.mk will work:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := my_daemon
LOCAL_C_INCLUDES := src
LOCAL_SRC_FILES := src/daemon.c
include $(BUILD_EXECUTABLE)
One thing I do notice is that the binary produced by this "makefile" is 130k, while the binary produced by cmake was ~40 kb. This is because I used -s as a C_FLAG and then gcc will strip the produced object on the fly. This can be done later on by calling $NDK/toolchains/arm-linux-androideabi-4.4.3/prebuilt/linux-x86/bin/arm-linux-androideabi-strip or the corresponding strip for your arch.
As I have not found documentation of this feature on the internet, some more words:
This works quite good, no problem here :)
This must be saved in a file called jni/Android.mk.
The code must be saved inside the JNI directory
If your code is outside of the jni directory this get ugly, but not impossible. You just need to prefix the code with the corresponding prefixes, don't forget to modify also the include path. This is left to the reader as an exercise.
Still unsure why the code generated from Android build system is larger then the code generated by cmake. I previously said that strip is not called - but it is called before the *.so are copied to the lib directory.
Still don't know how to package that binary into an android package, and not even how to run it (for example when the system is up) without modifying the Android code. I assume I can write a Java service that starts on boot and then execvps the daemon.
Your option 2 is the only way to do it AFAIK.

Fully native apps on Android?

Is it possible to develop a native application that runs without relying on the Dalvik runtime and any of the Java libraries?
Basically, I want to make a native binary I can run via a shell that would be able to run without the system_server process running. Ideally, I want to be able to create my own Window Server by rendering stuff via the OpenGL system, instead of relying on SurfaceFlinger (which would also be dead due to the fact that system_server isn't running).
The reason I'm asking this is that I want to experiment with lower level Android development in C/C++ at which Java is simply un-necessary. So basically, I'm trying to develop a standalone app that can render things via OpenGL+Cairo and receive HID input.
PS: I know what the NDK is, and it's not what I'm looking for. I want to create standalone binaries instead of creating stuff that runs inside the Dalvik VM.
There are two possibilities to run native code on your device: either using NDK or embedding your application into the framework. As I understand the first approach is not considered, thus, I think you can have a look at the second. Here is an example how to implement the second approach.
An example of porting existing code to a custom Android device
It is due time for another technical post here on the blog. This post will be about porting existing c-libraries to Android, something I did as part of the dev board demos we are doing here at Enea.
Platform addition or NDK
There are two ways of bringing native code to an Android device, either add it to the platform itself and integrate it with the framework, or include it with an application package. The latter method have evolved a lot and with the release of NDK version 5 even allows you to hook directly into the application lifecycle http://developer.android.com/reference/android/app/NativeActivity.html from the NDK. The NDK is useful for any application where you have need of native performance, have portable C libriaries you want to reuse or just some legacy native code that could be included in your application. The NDK integrates well with the Android SDK and is a great way to include native functionality in your application. It should be the preferred way for any application that needs to be reusable across a lot of Android devices.
The other option is to include your functionality, it may be native or Java, as an API extension for all applications to use. This will only work on devices that implement these extensions and it may be a suitable option for device builders. This is the variant that we aim for here.
Analyze the existing project
Porting native code to Android is not always straight forward, especially if we are talking about C++ code due to the fact that Android uses its own c-runtime with limited support for exceptions among other things. If you want to know more about the details of bionic there is an overview in the NDK docs.
The code I wanted to port for this project was the Enea LINX for Linux framework which is a fast IPC framework. My purpose was to be able to interact with control systems running our OSE real time operating system which also implements this kind of IPC. LINX consists of a couple of kernel driver modules, a user space library and some configuration and control utilities. It is written in C. I had created a small demo with LINX in Android before where I compiled it separately and used static linking but for this project I wanted a complete port to the Android build system. It did not have any issues with bionic compatability so the port should be straight forward.
I just want to add a short disclaimer about LINX. I use it here since it is a good example of integrating a solution into Android from kernel drivers up to the API levels. This particular piece of code does add additional IPC mechanisms to the systems which more or less messes up the security model so do not use it unless you are aware of the implications. The steps needed to port code to Android described in this post are however applicable for any type of driver/framework/library that you may want to include on your product.
Adding kernel driver modules
The first step was to add the kernel modules to the Android build. One way would have built a new kernel and include them directly but for this project I chose to keep them as separate modules. Building for the kernel is not handled by the Android build system meaning that we build them as we would do with any Linux system. The target is an Atmel based development board and in the LINX module build I provide the headers and cross compilation toolchain for that kernel and architecture.
Now for the Android specific parts. We need to add the compiled kernel modules to the platform build system in some way and create an Android.mk file that includes them in the system image when we build. Add a folder in the source tree where your project will go, device or external are suitable candidates. I created a folder called linx that will hold the entire linx port and in that I added a subfolder called modules where I place the prebuilt kernel modules. Now what we need is an Android makefile to copy them to the suitable place in the out folder for system image generation. This will look like:
LOCAL_PATH := $(my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := linx.ko
LOCAL_MODULE_CLASS := SHARED_LIBRARY
# This will copy the file in /system/lib/modules
#
LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/modules
LOCAL_SRC_FILES := $(LOCAL_MODULE)
include $(BUILD_PREBUILT)
The standard location for modules on the Android system image is System/lib/modules so that is where we copy them. If we build the platform now the build system will copy our precompiled module linx.ko to the system image that we use for our device. The next step is to make sure that we have the module installed on the system when we run it. This can either be done manually via the shell or via a script that we run during init.
In this case I have created a shell script to be launched from init.rc with the following content:
#linx init
insmod /lib/modules/linx.ko
insmod /lib/modules/linx_tcp_cm.ko
netcfg eth0 up
ifconfig eth0 192.168.1.12
mktcpcon --ipaddr=192.168.1.21 ControlConn
mklink --connection=tcpcm/ControlConn control_link
This includes installing the modules and configuring the network and LINX-link. We launched this from init.rc by adding:
...
#linx init script
service linx-setup /system/etc/linx_setup.sh
oneshot
...
The setup script is added to the system image in the same way by including it as a prebuilt target.
LOCAL_PATH := $(my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := linx_setup.sh
LOCAL_MODULE_CLASS := ETC
LOCAL_MODULE_PATH := $(TARGET_OUT)/etc
LOCAL_SRC_FILES := $(LOCAL_MODULE)
include $(BUILD_PREBUILT)
Creating Android make files for the user space code
Now that we have the drivers in place the next step is to look at porting the user space libraries. The default LINX build system uses standard GNU make files but we need to create new ones adapted to the Android build system. Start out by adding the source files needed to the linx directory created in the Android source tree. This gives the following structure:
Android.mk
include
liblinx
linx_basic
linxcfg
linx_setup.sh
modules
I have the linx setup script and the main Android.mk file in the top directory and then we have the source files in separate folders and the include files in the include folder. To illustrate how the Android make files for each source component is created we can use liblinx as an example. The Android.mk file looks like:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := linx.c
LOCAL_C_INCLUDES += $(LOCAL_PATH)/../include
LOCAL_MODULE := liblinx
LOCAL_PRELINK_MODULE := false
include $(BUILD_SHARED_LIBRARY)
We set our sources by specifying LOCAL_SRC_FILES and the name of the library by specifying LOCAL_MODULE. We also need to supply the header files in the include directory by specifying LOCAL_C_INCLUDES. Finally this is a shared library that we are porting so use the BUILD_SHARED_LIBRARY template. This will build the library with the Android build system and add it to the system image as a shared library with the name liblinx.so.
The rest of the code is moved to the Android build system in the same way, by creating Android.mk files and specifying type and any dependencies. As another example we may look at the syntax for building the mktcpcon configuration program. This depends on the library we just created and hence the makefile looks entry looks like:
LOCAL_SRC_FILES := mktcpcon.c
LOCAL_C_INCLUDES += $(LOCAL_PATH)/../include
LOCAL_STATIC_LIBRARIES += liblinxcfg
LOCAL_SHARED_LIBRARIES += liblinx
LOCAL_MODULE := mktcpcon
include $(BUILD_EXECUTABLE)
Here we use the BUILD_EXECUTABLE template and we also need to specify static and shared libraries that we link against.
Summary
I hope that provides some insight in how you setup the build for an existing linux project to run on an Android system. The steps to follow are:
Build any kernel related things using the correct kernel build system and config for your device
Add the kernel modules (and/or kernel) to the platform build system and create Android.mk files for them using the prebuilt template.
Create config and intialization services for your drivers if needed and add them to init.
Move the rest of your code (user space) to the Android source tree and create Android.mk files for them.
If you encounter build errors work them out in the source code and see what incompatabilities your code have with the specifics of the Android C-runtime.
That wraps up my post for today. Having done this we are now able to use our added drivers and API:s from native programs running in the shell. The next step is to create a JNI layer and java library to allow regular Android applications to make use of our platform additions.
I have been away for half a year on paternal leave (nice Swedish benefit) but now it is full time Android hacking again and pushing the team to publish things. Hopefully you will see more activity here including a follow up on this post discussing applications APIs.
Yes it is possible to develop native (executable binaries) that can be executable via shell but if you trying to cross compile GNU software using NDK can be pain in ass.
I will suggest you to use CodeSourcery or Linaro toolchain any way you can take a look at my approach https://github.com/DroidPHP/DroidPHP/blob/master/docs/Compiling.md

Categories

Resources