Contents
Creating Android apps natively on your phone
You can build APKs directly in a Debian chroot on your ARM-based phone. I have successfully done this using qemu-i386-static on my phone.
English translation: You can have a fully portable development environment right on your phone, using the Android SDK.
Prerequisites:
- You have a Debian chroot installation on your phone.
-
Here is one way to get one.
-
- You have an X desktop within your chroot and can VNC/XRDP into it.
- You know what Debian’s “debootstrap” is.
Steps:
- Install a debian chroot environment on your phone.
- Make sure you have qemu-user-static, openjdk-6, ant, and libswt-gtk-3-java installed
- The section “My Debian chroot environment” below has my working setup, in case I am leaving out any dependencies.
- Install an i386 chroot within your Debian chroot.
- debootstrap –arch=i386 –variant=minbase –include=zlib1g –foreign sid .
- With the “normal qemu-i386-static” you won’t be able to chroot into this environment to run debootstrap –second-stage. It seems to work fine without running the second stage, but if you want to do that, then see the notes below.
- Download the Android SDK for Linux i386 and extract it.
-
Run export ANDROID_SWT=/usr/share/java/swt.jar
- I added this line to the beginning of the android-sdk-linux/tools/android script.
- cd to your android-sdk-linux/tools and run ./android
- Install at least one API.
- Install the two scripts below run-i386 and run-i386-link into a bin folder within your path.
- I created a bin folder under my username, and added it to my path in my .bashrc file.
-
In android-sdk-linux/tools, run run-i386 mklinks
- This runs the supplied Android tools in the Qemu emulator each time one is called.
-
In android-sdk-linux/platform-tools run run-i386 mklinks
- If android-sdk-linux/tools is in your PATH, you should now be able to run “android create project” to create a new Android project:
-
android create project -n hello -t android-10 -p pwd -k com.fieldeffect.hello -a Hello
-
- Now you can:
-
cd <project folder>
- ant debug
- And, if all goes well, you should have a hello-debug.apk in your folder.
- Copy it into your Android environment and install.
-
Enjoy!
—
Scripts:
run-i386 (Change the QEMU and I386CHROOT parameters to your own directories):
#!/bin/bash QEMU=/usr/bin/qemu-i386-static I386CHROOT=~/Dev/chroot-i386 case "$1" in mklinks) if [ ! -e "./I386" ]; then mkdir ./I386 fi for i in $(file ./* | grep "ELF 32" | awk '{print $1}' | sed s/://g | sed s/[./]//g); do echo "Moving $i..." mv $i ./I386 ln -s ~/bin/run-i386-link $i done ;; *) $QEMU $I386CHROOT/lib/ld-linux.so.2 --library-path $I386CHROOT/lib:$I386CHROOT/usr/lib:$I386CHROOT/usr/share/perl/5.12.4/unicore/lib:$I386CHROOT/var/lib:$I386CHROOT/lib/i386-linux-gnu:$I386CHROOT/usr/lib/i386-linux-gnu $@ ;; esac
run-i386-link:
echo $(dirname $0)/I386/$(basename $0) $@ ~/bin/run-i386 $(dirname $0)/I386/$(basename $0) $@
Appendix A: My Debian chroot environment
To run exactly the environment I currently have on my Android phone, on my 4GB sdcard.
cd <working-directory> debootstrap --arch=armel --variant=minbase --foreign --include adduser,ant,ant-optional,apt,apt-utils,apt-xapian-index,aptitude,aptitude-doc-en,aspell,aspell-en,base-files,base-passwd,bash,binfmt-support,binutils,bsdmainutils,bsdutils,build-essential,bzip2,ca-certificates,ca-certificates-java,coreutils,cpp,cpp-4.6,dash,dbus,dbus-x11,dconf-gsettings-backend,debconf,debconf-i18n,debian-archive-keyring,debianutils,debootstrap,defoma,dialog,dictionaries-common,diffutils,dillo,dos2unix,dpkg,dpkg-dev,dropbear,dselect,e2fslibs,e2fsprogs,esound-common,fakeroot,file,findutils,fontconfig,fontconfig-config,g++,g++-4.6,gcc,gcc-4.4-base,gcc-4.5-base,gcc-4.6,gcc-4.6-base,gconf2,gconf2-common,geany,glib-networking,gnome-icon-theme,gnupg,gpgv,grep,groff-base,gsettings-desktop-schemas,gzip,hdparm,hicolor-icon-theme,hostname,hunspell-en-us,icedtea-6-jre-cacao,icedtea-6-jre-jamvm,icedtea-netx,icedtea-netx-common,icewm,icewm-common,icewm-themes,ifupdown,initscripts,insserv,iso-codes,java-common,keyboard-configuration,less,libaccess-bridge-java,libaccess-bridge-java-jni,libacl1,libalgorithm-diff-perl,libalgorithm-diff-xs-perl,libalgorithm-merge-perl,libasound2,libaspell15,libasyncns0,libatk1.0-0,libatk1.0-data,libattr1,libaudiofile0,libaudit0,libauthen-ntlm-perl,libavahi-client3,libavahi-common-data,libavahi-common3,libblkid1,libboost-iostreams1.46.1,libbsd0,libbz2-1.0,libc-bin,libc-dev-bin,libc6,libc6-dev,libcairo-gobject2,libcairo2,libcanberra-gtk3-0,libcanberra-gtk3-module,libcanberra0,libcap2,libclass-accessor-perl,libcomerr2,libcroco3,libcups2,libcwidget3,libdatrie1,libdb4.8,libdb5.1,libdbus-1-3,libdbus-glib-1-2,libdigest-hmac-perl,libdpkg-perl,libdrm-radeon1,libdrm2,libedit2,libenchant1c2a,libencode-locale-perl,libept1,libesd0,libexpat1,libfile-listing-perl,libflac8,libfltk1.3,libfont-afm-perl,libfont-freetype-perl,libfontconfig1,libfontenc1,libfreetype6,libgail18,libgc1c2,libgcc1,libgconf2-4,libgcrypt11,libgdbm3,libgdk-pixbuf2.0-0,libgeoclue0,libgif4,libgl1-mesa-dri,libgl1-mesa-glx,libglapi-mesa,libglib2.0-0,libglib2.0-data,libgmp10,libgnutls26,libgomp1,libgpg-error0,libgpm2,libgssapi-krb5-2,libgstreamer-plugins-base0.10-0,libgstreamer0.10-0,libgtk-3-0,libgtk-3-bin,libgtk-3-common,libgtk2.0-0,libgtk2.0-bin,libgtk2.0-common,libhtml-form-perl,libhtml-format-perl,libhtml-parser-perl,libhtml-tagset-perl,libhtml-template-perl,libhtml-tree-perl,libhttp-cookies-perl,libhttp-daemon-perl,libhttp-date-perl,libhttp-message-perl,libhttp-negotiate-perl,libhunspell-1.3-0,libice-dev,libice6,libicu44,libidl0,libidn11,libio-socket-inet6-perl,libio-socket-ssl-perl,libio-string-perl,libjasper1,libjpeg62,libjpeg8,libjson0,libk5crypto3,libkeyutils1,libkrb5-3,libkrb5support0,liblcms1,libldap-2.4-2,liblocale-gettext-perl,libltdl7,liblwp-mediatypes-perl,liblwp-protocol-https-perl,liblzma2,liblzma5,libmagic1,libmailtools-perl,libmount1,libmpc2,libmpfr4,libncurses5,libncursesw5,libnet-http-perl,libnet-ssleay-perl,libnotify4,libnspr4-0d,libnss3-1d,libogg0,liborbit2,libp11-kit0,libpam-modules,libpam-modules-bin,libpam-runtime,libpam0g,libpango1.0-0,libparse-debianchangelog-perl,libpci3,libpciaccess0,libpcre3,libpipeline1,libpixman-1-0,libpng12-0,libproxy0,libpthread-stubs0,libpthread-stubs0-dev,libpulse0,libreadline5,libreadline6,librsvg2-2,librsvg2-common,libsamplerate0,libsasl2-2,libsasl2-modules,libselinux1,libsepol1,libsigc++-2.0-0c2a,libslang2,libsm-dev,libsm6,libsndfile1,libsocket6-perl,libsoup2.4-1,libsqlite3-0,libss2,libssl1.0.0,libstdc++6,libstdc++6-4.6-dev,libsub-name-perl,libswt-gtk-3-java,libswt-gtk-3-jni,libtasn1-3,libtdb1,libtext-charwidth-perl,libtext-iconv-perl,libtext-wrapi18n-perl,libthai-data,libthai0,libtiff4,libtimedate-perl,libtinfo5,libudev0,libunique-1.0-0,liburi-perl,libusb-0.1-4,libusb-1.0-0,libutempter0,libuuid1,libvorbis0a,libvorbisenc2,libvorbisfile3,libvte-common,libvte9,libwebkitgtk-1.0-0,libwebkitgtk-1.0-common,libwrap0,libwww-perl,libwww-robotrules-perl,libx11-6,libx11-data,libx11-dev,libx11-xcb1,libxapian22,libxau-dev,libxau6,libxaw7,libxcb-render0,libxcb-shape0,libxcb-shm0,libxcb1,libxcb1-dev,libxcomposite1,libxcursor1,libxdamage1,libxdmcp-dev,libxdmcp6,libxerces2-java,libxext6,libxfixes3,libxfont1,libxft2,libxi6,libxinerama1,libxkbfile1,libxml-commons-external-java,libxml-commons-resolver1.1-java,libxml-namespacesupport-perl,libxml-parser-perl,libxml-sax-base-perl,libxml-sax-expat-perl,libxml-sax-perl,libxml-simple-perl,libxml2,libxmu6,libxmuu1,libxpm4,libxrandr2,libxrender1,libxslt1.1,libxss1,libxt-dev,libxt6,libxtst6,libxv1,libxxf86dga1,libxxf86vm1,linux-libc-dev,login,lsb-base,lsb-release,lsof,lxterminal,make,man-db,manpages,manpages-dev,mawk,menu,midori,mime-support,mount,multiarch-support,ncurses-base,ncurses-bin,net-tools,netbase,netcat,netcat-traditional,notification-daemon,openjdk-6-jdk,openjdk-6-jre,openjdk-6-jre-headless,openjdk-6-jre-lib,openssh-blacklist,openssh-blacklist-extra,openssh-client,openssl,passwd,patch,pciutils,perl,perl-base,perl-modules,procps,psmisc,python,python-apt,python-apt-common,python-chardet,python-debian,python-minimal,python-support,python-xapian,python2.6,python2.6-minimal,python2.7,python2.7-minimal,qemu-user-static,readline-common,screen,sed,sensible-utils,sgml-base,shared-mime-info,socat,sqlite3,sysv-rc,sysvinit,sysvinit-utils,tar,tcpd,tightvncserver,ttf-bitstream-vera,ttf-dejavu-core,ttf-dejavu-extra,tzdata,tzdata-java,ucf,udev,usbutils,util-linux,vim-common,vim-tiny,w3m,wget,x-ttcidfont-conf,x11-common,x11-utils,x11-xkb-utils,x11-xserver-utils,x11proto-core-dev,x11proto-input-dev,x11proto-kb-dev,xauth,xbitmaps,xfonts-100dpi,xfonts-75dpi,xfonts-base,xfonts-encodings,xfonts-scalable,xfonts-utils,xkb-data,xml-core,xorg-sgml-doctools,xrdp,xserver-common,xserver-xorg-core,xserver-xorg-video-dummy,xterm,xtrans-dev,xz-utils,zlib1g,zlib1g-dev sid .
APPENDIX B: Notes
Notes on QEMU i386 chroot environment:
You currently can’t do an i386 chroot on an ARM device with qemu-i386-static. A user has submitted a patch to allow you to do this, but you must compile QEMU from source, and it only works with qemu-0.14.1. The above process to run the SDK is confirmed to work without running a –second-stage on the debootstrap; however, if you do want to complete the i386 chroot installation you will currently have to use the below.
Furthermore, I would only use this particular binary for the chroot, and not for the SDK process above — for that I would use qemu-user-static 0.15+. I got a Segmentation Fault when trying to use it for the Android SDK tools.
apt-get install build-essential wget http://download.savannah.gnu.org/releases/qemu/qemu-0.14.1.tar.gz #Copy and paste patch from here: http://patchwork.ozlabs.org/patch/45206/ # ... into patch.txt #Untar and apply patch to qemu source code tar xzf qemu-0.14.1.tar.gz cd qemu-0.14.1 patch -p1 < ../patch.txt #Native compiling ./configure --target-list="i386-softmmu i386-linux-user" --static make -j2
Ozwork labs patch:
diff --git a/configure b/configure index 0a84b0e..69ccb13 100755 --- a/configure +++ b/configure @@ -2342,6 +2342,7 @@ TARGET_ABI_DIR="" case "$target_arch2" in i386) target_phys_bits=32 + target_nptl="yes" ;; x86_64) TARGET_BASE_ARCH=i386 diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 9fb493f..38f2067 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -3426,6 +3426,13 @@ static abi_long do_get_thread_area(CPUX86State *env, abi_ulong ptr) unlock_user_struct(target_ldt_info, ptr, 1); return 0; } + +static inline void cpu_set_tls(CPUState *env, target_ulong newtls) +{ + do_set_thread_area(env, newtls); + /* reload gs */ + cpu_x86_load_seg(env, R_GS, env->segs[R_GS].selector); +} #endif /* TARGET_I386 && TARGET_ABI32 */ #ifndef TARGET_ABI32 @@ -3554,7 +3561,16 @@ static int do_fork(CPUState *env, unsigned int flags, abi_ulong newsp, new_stack = ts->stack; /* we create a new CPU instance. */ new_env = cpu_copy(env); -#if defined(TARGET_I386) || defined(TARGET_SPARC) || defined(TARGET_PPC) +#if defined(TARGET_I386) + new_env->idt.base = target_mmap(0, sizeof(uint64_t) * (env->idt.limit + 1), + PROT_READ|PROT_WRITE, + MAP_ANONYMOUS|MAP_PRIVATE, -1, 0); + memcpy(g2h(new_env->idt.base), g2h(env->idt.base), sizeof(uint64_t) * (env->idt.limit + 1)); + new_env->gdt.base = target_mmap(0, sizeof(uint64_t) * TARGET_GDT_ENTRIES, + PROT_READ|PROT_WRITE, + MAP_ANONYMOUS|MAP_PRIVATE, -1, 0); + memcpy(g2h(new_env->gdt.base), g2h(env->gdt.base), sizeof(uint64_t) * TARGET_GDT_ENTRIES); +#elif defined(TARGET_SPARC) || defined(TARGET_PPC) cpu_reset(new_env); #endif /* Init regs that differ from the parent. */