Whiteboard Web |
Android »
How to run Debian or Ubuntu GNU/Linux on your AndroidIntegrating GNU/Linux with Android The Matrix WayThe most seamless way extending your Android device with a full blown GNU/Linux such as Debian (or Ubuntu) is running the Android system in a chroot environment in the Debian file system. This way you can access the Android system from Debian without restrictions at the same time no modifications to the Android system itself are needed. This description requires general computer skills such as GNU/Linux but not necessary specific knowledge about Android - but it sure helps. You will have to install the Android SDK toolkit, and if you are not comfortable running pre-compiled binaries from dubious sources, you may have to get at least parts of the Android OS source code as well. A new init procedure mounting a new root file system, transferring control to the Android init in a chroot environment is implemented as described here below. The pros compared to other methods are many. Features
Requirements (click on each topic for more info)
Steps
Disclaimer - The instructions here are not for your device explicit, and you can not follow them by the letter, but have to adjust them for your telephone or tablet. Most often I've highlighted what you may need to change. If you're not experienced flashing you phone there's also a risk you render it useless, becoming the proud owner of an expensive brick. This solution is primary intended for the experienced GNU/Linux hacker, system administrator or app developer wanting full control over the Android device using a standard GNU/Linux environment. For the novice wanting to run GNU/Linux on his mobile device for the fun of it, there are other less powerful solutions I'd recommend before this one. Partition the SDcardGet a large capacity SDcard and create two partitions. Make sure it's fast as well (class 10). Make the first partition the standard FAT file system used by various apps. Make the second a GNU/Linux partition for the Debian root filesystem. Use ext4 if your Android kernel supports it, else chose the best supported. Look in At your desktop computer root@workstation:~# fdisk -cu /dev/sdf Command (m for help): p Disk /dev/sdf: 32.0 GB, 32018268160 bytes 170 heads, 53 sectors/track, 6940 cylinders, total 62535680 sectors Units = sectors of 1 * 512 = 512 bytes Sector size (logical/physical): 512 bytes / 512 bytes I/O size (minimum/optimal): 512 bytes / 512 bytes Disk identifier: 0x00000000 Device Boot Start End Blocks Id System /dev/sdf1 53 13839359 6919653+ c W95 FAT32 (LBA) /dev/sdf2 13839360 62529399 24345020 83 Linux Here the alignment is 53 sectors, i.e. even tracks, so I make sure the start sector of both partitions is a multiple of this. I chose to split 32G into 8G FAT plus 24G ext4. The Debian base environment including X11 is just above 1GB in size, so 24G may be overkill. Create new file systems with mkfs. At your desktop computer # mkfs -t vfat /dev/sdf1 # mkfs -t ext4 /dev/sdf2 Creating the initramfsReplace the initramfs shipped with your device with your own modified. Use an init mounting a new root file system from the SDcards GNU/Linux partition and transfer control to this. Below is an example of the /init of the initramfs file system. It must be named /init because this is hardcoded into the Android kernel to execute upon boot. You most certainly need to change On The ASUS Transformer TF101 the second partition is named From your desktop shell to your Android device $ adb shell $ mount rootfs / rootfs ro,relatime 0 0 tmpfs /dev tmpfs rw,relatime,mode=755 0 0 devpts /dev/pts devpts rw,relatime,mode=600 0 0 proc /proc proc rw,relatime 0 0 sysfs /sys sysfs rw,relatime 0 0 tmpfs /mnt/asec tmpfs rw,relatime,mode=755,gid=1000 0 0 tmpfs /mnt/obb tmpfs rw,relatime,mode=755,gid=1000 0 0 /dev/block/mtdblock0 /system yaffs2 ro,relatime 0 0 /dev/block/mtdblock3 /data yaffs2 rw,nosuid,nodev,relatime 0 0 /dev/block/mtdblock2 /cache yaffs2 rw,nosuid,nodev,relatime 0 0 /dev/block/mtdblock1 /data/idd yaffs2 rw,nosuid,nodev,relatime 0 0 /dev/block/vold/179:1 /mnt/sdcard vfat rw,dirsync,nosuid,nodev,noexe ... /dev/block/vold/179:1 /mnt/secure/asec vfat rw,dirsync,nosuid,nodev,noexec ... tmpfs /mnt/sdcard/.android_secure tmpfs ro,relatime,size=0k,mode=000 0 0 $ ls -l /dev/block drwxr-xr-x root root 2012-06-18 22:41 vold brw------- root root 179, 2 2012-06-18 22:41 mmcblk0p2 brw------- root root 179, 1 2012-06-18 22:41 mmcblk0p1 drwxr-xr-x root root 2012-06-18 22:41 platform brw------- root root 179, 0 2012-06-18 22:41 mmcblk0 brw------- root root 31, 3 2012-06-18 22:41 mtdblock3 brw------- root root 31, 2 2012-06-18 22:41 mtdblock2 brw------- root root 31, 1 2012-06-18 22:41 mtdblock1 brw------- root root 31, 0 2012-06-18 22:41 mtdblock0 Ok, here on the Sony Ericsson Xperia Active we see the FAT partition #!/sbin/busybox sh # initramfs pre-boot init script # Mount the /proc and /sys filesystems /sbin/busybox mount -t proc none /proc /sbin/busybox mount -t sysfs none /sys /sbin/busybox mount -t tmpfs none /dev # Something (what?) needs a few cycles here /sbin/busybox sleep 1 # Populate /dev /sbin/busybox mdev -s # Mount the root filesystem, second partition on micro SDcard
# Clean up /sbin/busybox umount /proc /sbin/busybox umount /sys /sbin/busybox umount /dev # Transfer root to SDcard exec /sbin/busybox switch_root /mnt/root /etc/init
The file system of this initramfs is very minimalistic and only contains the
We'll need the systems base address, i.e. where the RAM begins. To get it from your original kernel $ extract-ikconfig zImage | grep PHYS_OFFSET CONFIG_PHYS_OFFSET=0x00200000 Looking for "System RAM" in Now we can create the new boot image. At your desktop computer # mkdir my-initramfs # cd my-initramfs # mkdir -p proc sys dev mnt/root sbin # cp /my/arm/busybox sbin/busybox # cp /above/init init # chmod a+x init sbin/busybox # find . | cpio --quiet -H newc -o | gzip > ../initramfs.cpio.gz # cd ..
The kernel If you prefer running a custom ROM (e.g. CyanogenMod), you can of course use its boot image instead of the device's original ROM.
We sit on our newly created image Creating the Debian root file systemMount your SDcard, if not already mounted. I assume you've mounted it as Chose a Debian mirror close to you, and begin to create the Debian root filesystem. At your desktop computer # apt-get install debootstrap # mkdir /mnt/debian # mount -t ext4 /dev/sdf2 /mnt/debian # debootstrap --verbose --arch armel --foreign squeeze /mnt/debian http://ftp.se.debian.org/debian # umount /mnt/debian This is only half of the Debian installation. Now we need to complete the other half. Either run this in an emulator ( On your Android device # mount /dev/block/mmcblk1p2 /root # export PATH=/sbin:/usr/sbin:/bin:/usr/bin:/system/bin # busybox chroot /root /debootstrap/debootstrap --second-stage # echo 'deb http://ftp.se.debian.org/debian squeeze main' >/root/etc/apt/sources.list # mount -t proc none /root/proc # mount -t sysfs none /root/sys # mount -o bind /dev /root/dev # mount -t devpts none /root/dev/pts # export TMPDIR=/tmp # busybox chroot /root /bin/bash # apt-get update # apt-get install openssh-server # passwd root # exit # sync Now shutdown your device and remove the SDcard. Here you'd actually ran Debian on your device! But chroot:ed below Android, we want the reverse. But now we got a complete GNU/Linux system with SSH server and all. Still some tinkering needs to be done. If Here below you find a ready-made root file system up to this point described, i.e. with a ssh-server installed. The root password is "root". Feel free to change it. ;-)
Note that this file system is as of up to this point in this tutorial. It still needs work, e.g. installing your Android root in /android, adding the init scripts etc. This can't be pre-made, since they differs from device to device. Creating the new Android root file systemMount the SDcard in your ordinary GNU/Linux machine again. Unpack the original boot image initramfs to /android on SDcard GNU/Linux partition. This is the new Android root. Create directory Android normally only accepts four partitions on the SDcard (vold limitation). If you don't want to waste one of them for the small root file system, you can loopback mount (--bind) /android to /mnt/android making it a mount point. This mount point you then can set to read-only using remount. Note that you must do a remount, because a bind-mount can not change the flags of the original file system initially. You'll have to do this remount explicit yourself in init.stage2 using /bin/mount in this case. But initially I suggest you just let the root be writeable until you get everything up and running. This can be done later -- or not at all. Making a boot image is done with the Android OS build kit Some finishing scripts to tie all togetherOur new initramfs transfer init control to
#!/sbin/busybox sh # # Debian environment boot init script # # Leave all the initialization process to the Android init to handle # # Launch delayed init script /etc/init.stage2 >/android/log/boot.log 2>&1 & # Transfer control to Android init - never returns exec /sbin/busybox chroot /android /init Also make sure you copy the busybox to /sbin in this file system as well. Note that log from init.stage2 is stored in the Android file tree so you can access in from Android in case the Debian-level ssh server didn't start due to some mistake done in for example What this script does, is forking of a secondary delayed script the Debian environment executes once the Android init is done. It then transfers control to the Android original init, still running as pid 1 of course. The secondary script
#!/sbin/busybox sh # # Delayed Debian environment boot init script # Not really init (not pid 1) but a fork of it. # The real init is right now executing in Android chroot # /sbin/busybox echo "`/sbin/busybox date` Debian init stage2 started" # Wait for Android init to set up everything # wait for dev to be mounted by Android init /sbin/busybox echo "`/sbin/busybox date` Waiting on Android to mount /dev" while [ ! -e /android/dev/.coldboot_done ]; do /sbin/busybox sleep 1 done # wait for Android init to signal all done /sbin/busybox echo "`/sbin/busybox date` Waiting on Android init to finish" while [ -e /android/dev/.booting ]; do /sbin/busybox sleep 1 done # Mount the /proc, /sys etc filesystems /sbin/busybox echo "`/sbin/busybox date` Mounting /proc /sys and /dev" /sbin/busybox mount -t proc none /proc /sbin/busybox mount -t sysfs none /sys # Mount /dev from the Android world /sbin/busybox mount -o bind /android/dev /dev /sbin/busybox mount -o bind /android/dev/pts /dev/pts /sbin/busybox mount -o bind /android/dev/socket /dev/socket # All done, now we can start stuff export PATH=/sbin:/usr/sbin:/bin:/usr/bin /sbin/busybox echo "`/sbin/busybox date` Running /etc/rc.local" # Start selected servers /etc/init.d/rc.local start /sbin/busybox echo "`/sbin/busybox date` All done" exit 0 Basically this only waits on Android init, then sets up everything nessesary for Debian such as devices, proc and sys mounts, and executes /etc/rc.local. You see we mount /dev loopback from the Android root. Because of this, you must remove any devices in /dev populated by debootstrap, or else this mount will fail. My
#!/bin/sh -e # # rc.local # # This script is executed at the end of each multiuser runlevel. # Make sure that the script will "exit 0" on success or any other # value on error. # # In order to enable or disable this script just change the execution # bits. # # By default this script does nothing. /etc/init.d/hostname.sh start /etc/init.d/ssh start exit 0 Note that init make sure everything here is logged to Install itIf everything went well so far, it's time to install your customised boot image. Here below I assume you have an unlocked bootloader supporting First enter fastboot mode on your Android device. This is done with some magic key combination during power off and is phone specific. You may try VolumeUp or VolumeDown as you either turn on the phone or connect its USB cord to the computer - or Google your phone model plus "fastboot". On you desktop computer
The marked " All done, you now run Debian integrated with Android The Matrix Way. Run ssh to it as user Additional tinkering/etc/groupThe Android environment is quite restricted. If you plan to run as non-root in the Debian environment, you'll need to add yourself to some Android groups to get access to network and such. The groups of the Android user On an android device as user shell@android:/ $ id uid=2000(shell) gid=2000(shell) groups=1003(graphics),1004(input),1007(log),1009(mount), 1011(adb),1015(sdcard_rw),3001(net_bt_admin),3002(net_bt),3003(inet),3006(net_bw_stats) The complete set of Android user uid and group gid can by found in system/core/include/private/android_filesystem_config.h (yes, it's hard-coded). /etc/mtabTo make df happy, make this a symlink to /proc/mounts
Still, df will produce a somewhat confusing output due to the double mounts of devices in the different roots. Not to worry, this is only cosmetic. localesYou don't get any localised locale installed by default. If you'd like that, Setting the system default time zone# dpkg-reconfigure tzdata Using the GNU/Linux Debian environmentConnectivityTo get a Debian terminal, download the ConnectBot from Google Play and ssh-connect to localhost. Note that if you use the "local" connection in ConnectBot, you'll enter The Matrix, i.e. the chroot Android environment, and can see no signs of the Debian environment whatsoever.
X11 WindowsIf you want to run X11 on your device, apt-get tightvncserver and get the free android app android-vnc-viewer from Google Play. First apt-get some desktop environment. You can use On your Android device in the Debian system via SSH $ sudo apt-get install tightvncserver $ vncserver -geometry 1280x752 -display :1 Running Debian GNU/Linux with Gnome on Android using the android-vnc-viewer app (click to enlarge) For better ergonomics, run ssh (optionally with X11 forwarding) from your favourite computer. Running the mouse pointer with the index finger over the touch screen, can be somewhat challenging. :-) Still, Gnome on the ASUS Transformer TF101 runs surprisingly well. File accessOne of the reasons motivating me to implement this is the ability to access the Android files without have to unmount/remount the SDcard. In Gnome (Nautilus) at my workstation As a user in the The Android Media Scanner normally runs automatically each time Android remounts the SDcard. Since you are now transferring the media to the SDcard using ssh/sftp, not remounting the card, the media scanner won't run except for at boot. Download an app to start the Media Scanner manually from Google Play if you need - there are lots of them. The Media Scanner is an index service used to catalogue media files such as MP3's and images for Android apps. If you transfer a media file using ssh/sftp but can't find it in your app, initiate a Media Scan. Modifying the systemWith the real GNU/Linux distribution on top, it's trivial to customize the device to your likings. For example the Sony Xperia Active only got 420MB internal storage for apps and data. This we'll change simply by moving /data from the internal partition to a new partition we create on the SDcard. Create the partition, copy /data to it, edit Androids
Total space from 420MB to 4.66GB - not bad at all. Just keep in mind Androids vold does not like more than four partitions on the SDcard by default. RootedPlease note that this way, the Android environment is not "rooted". This is trivial to achieve, but very much less needed, unless you have some app needing root privileges you still need to use. Myself I find giving away root privileges to apps far too dangerous. To enter the Android Matrix from the Debian world, use chroot. root@tf101:/home/kuisma# PATH=/system/bin /usr/sbin/chroot /android sh root@android:/ # This is seldom needed, since you'll perform all the work (e.g. edits) of the Android file system directly from the Debian environment, using the full set of tools GNU/Linux provides you. Happy hacking! CaveatsEnvironment variables and file descriptorsWhen ssh:ing into the device, remember that neither the ssh server nor your login shell is a child of Android's init. Therefore you've got no access to neither file descriptors nor environment variables created by init, especially not ANDROID_PROPERTY_WORKSPACE with corresponding file descriptor. Because of this, you can't use getprop/setprop or any command relying Android properties from the ssh session (e.g. restart adbd). To do this, you must enter the Android world via a child of init, e.g. adbd or a local ssh-server in the Android root (e.g. dropbear). You can always enter the Android world only to adb shell back to itself. root@tf101:/home/kuisma# chroot /android /system/bin/adb shell shell@android:/ $ Note that this device is not rooted (ro.secure is 1), hence me ending up as the apt-get upgradeRunning apt-get upgrade, many installations scripts restarts their corresponding daemons. Since no daemons except for them you start in rc.local are supposed to be running in the Debian environment, it might be a good idea to restart the system after the upgrade. Some warningsAlthough Debian is the root, both systems are heavily dependent on the Android system and its init, since it is the "owner" of the hardware (i.e. runs init). If Android init fails, you will not be able to ssh into the Debian machine. Even if the root is transferred to the SDcard, the Android init mounts internal partitions, /system most important. If you do some change on this partition, you might lock yourself out. This can be solved by a backup copy of the Android environment so you can restore it to the SDcard and edit /android/init.*.rc to not mount /system from internal flash but use the one you restored to the SDcard instead. Running /system from the SDcard to begin with may be a good idea if you plan to change it frequently. This way the original system partition can be left untouched. This of course goes for all the Android partitions. Use can easy increase the size for your apps by changing /data to a partition on the SDcard of whatever size you like. Or to conclude, always keep a backup. Of course you can implement some fail-safe in the init scripts, populating /dev, mounting /proc, /sys, setting IP address etc if the Android init fails, but I find it more practical to run /system from SDcard instead. The Android Java machine (Dalvik) on the other hand is quite non-critical at the operating system level, so removing bundled apps (bloatware) on the /data partition is quite harmless. If you happen to remove e.g. the Home Application, you'll still be able to ssh into the Debian system restoring it from your backup. Common mistakes
About PerformanceNote that this is not emulation or virtualization but a runtime environment. Because of this no performance penalty whatsoever occur in neither the Android nor the Debian environment, not counting the extra one and a half second to boot the device. If moving partitions (eg. /system and/or /data) to the SDcard for safety or to increase the size, the speed of the SDcard may affect the performance. My benchmarks shows that a class 10 card gives about the same I/O performance as the internal nand disk, though. Don't except more than 15-20 MB/s. USB disks may give you more. Don't expect laptop performance, though. If it's primarily a GNU/Linux workstation you want, get an x86 based machine instead. The Android platform is design with resource conservation in mind, not high performance. pstreeA typical ps tree showing the process hierarchy. Note the sshd running this pstree and a sftp server in the Debian root. All the other processes are chroot:ed to the Android root. init─┬─adbd───{adbd} ├─dbus-daemon ├─debuggerd ├─dhcpcd ├─drmserver───{drmserver} ├─dropbear ├─glgps ├─installd ├─keystore ├─mediaserver───6*[{mediaserver}] ├─netd───4*[{netd}] ├─sdcard ├─servicemanager ├─sshd─┬─sshd───sshd───sftp-server │ └─sshd───sshd───bash───pstree ├─surfaceflinger───5*[{surfaceflinger}] ├─ueventd ├─vold───2*[{vold}] ├─wpa_supplicant2 └─zygote─┬─LocationService───18*[{LocationServic}] ├─android.browser───14*[{android.browse}] ├─android.vending───26*[{android.vendin}] ├─com.asus.cm───9*[{com.asus.cm}] ├─d.process.acore───8*[{d.process.acor}] ├─d.process.media───9*[{d.process.medi}] ├─droid.apps.maps───31*[{droid.apps.map}] ├─droid.gallery3d───9*[{droid.gallery3}] ├─droid.gsf.login───11*[{droid.gsf.logi}] ├─e.process.gapps───35*[{e.process.gapp}] ├─ing.android.tsm───16*[{ing.android.ts}] ├─m.android.phone───16*[{m.android.phon}] ├─m.asus.keyboard───8*[{m.asus.keyboar}] ├─ndroid.launcher───15*[{ndroid.launche}] ├─ndroid.settings───16*[{ndroid.setting}] ├─ndroid.systemui───11*[{ndroid.systemu}] ├─oid.hostmonitor───8*[{oid.hostmonito}] ├─onFriendService───11*[{onFriendServic}] ├─putmethod.latin───9*[{putmethod.lati}] ├─s:FriendService───8*[{s:FriendServic}] ├─system_server───67*[{system_server}] ├─uance.xt9.input───12*[{uance.xt9.inpu}] └─3*[{zygote}] Realize there's no connection between the process tree and the chroot file system structure. Here the Devices verifiedImplemented successfully on the following Android devices.
Got it up on some other device? Send me a mail and I'll add it to this list. Feedback? Questions? Suggestions?This tutorial too basic? Too complicated? Please feel free to send me a mail! /By Mikael Q Kuisma |
|
Page last modified 2016-01-23 07:54Z |