Debian on Nexus 7 2013

My nexus 7 2013 is a wifi model (Android 6.0). Recently, its touchscreen begins to malfunction, such that the screen only reacts to touch on its right edge, making the device unusable. Worse still, the touchscreen can suddenly generate a lot of random touches by itself, so that it jumps from one random app to another.

Instead of a premature death, I decide to install Debian on the nexus 7, and to use it with a usb keyboard.

For users who want to run native Debian on nexus 7, the easiest way is to download and install Debian jessie multirom by xda user Szybol.

The following is a brief account of the different stages I went through, and the many references and resources available on the web that makes this possible. (Thanks!)

In general, all commands below are run by root user. And, I use a Linux computer to root, and to run adb and fastboot commands.

  1. Root nexus 7 2013
  2. Install debian kit, upgrade it to jessie
  3. Install systemd
  4. Shifting partitions
  5. Moving debian to partition
  6. Boot debian
  7. fbterm login
  8. Setup wifi
  9. Setup X server
  10. Setup pulseaudio
  11. Swap boot partitions

Root nexus 7 2013

chainfire auto-root makes rooting easy on nexus 7 2013. Download from for nexus 7 2013 wifi.

Unzip and run the provided root script.

Once rooting is successful, on booting back to Android, the SuperSu app should be available.

Install debian kit

For installing debian kit: see Running Debian Armhf alongside Android

Then, upgrade debian to jessie.

Modify /etc/apt/sources.list.d/sources.list to use jessie.

    apt-get update
apt-get upgrade
apt-get dist-upgrade

There are some issues when installing debian packages on Android due to selinux security.

    setenforce 0
mount -o remount,ro /sys/fs/selinux
apt-get install ...
mount -o remount,rw /sys/fs/selinux

apt-get can report errors when /sys/fs/selinux is mounted rw , which is default and required in Android.

To simplify typing, create a script for the mount command as:


    mount -o remount,"$1" /sys/fs/selinux

Then, apt-get can be run in one line like,

    sefs ro ; apt-get upgrade ; sefs rw

Install systemd

After the upgrade to jessie, systemd and systemd-sysv should probably be installed. If not, then install both:

    sefs ro ; apt-get install systemd systemd-sysv ; sefs rw

systemd-sysv installs a symlink /sbin/init -> /lib/systemd/systemd

However, the debian initramfs cannot proceed to boot the /sbin/init with the absolute symlink. (It cannot find?)

To boot up properly, change it to a relative link as:

    cd /sbin
rm init
ln -s ../lib/systemd/systemd init

Warning: after every upgrade to systemd, inspect the symlink /sbin/init , and change it to a relative link.

Shifting partitions

I like to allocate debian to use a partition. (optional)

The 2nd largest partition on nexus 7 is the system partition. (less than 1 GB)

The easiest is to move the system partition to use the cache partition, and to move the cache partition to use a smaller partition.

And, for nexus 7 2013 wifi model, it happens to have an unused partition, the radio partition. (possibly the 3G model use it?)

To use it, re-format the radio partition to ext4. Copy the cache partition contents over (?)

Modify the Android /fstab.flo , change the line from

/dev/block/platform/msm_sdcc.1/by-name/cache        /cache          ext4    noatime,nosuid,nodev,barrier=1,data=ordered,nomblk_io_submit,errors=panic    wait,check

to mount the radio partition as /cache instead:

/dev/block/platform/msm_sdcc.1/by-name/radio        /cache          ext4    noatime,nosuid,nodev,barrier=1,data=ordered,nomblk_io_submit,errors=panic    wait,check

For reference, see Transformer: Booting Android experiment.

Once, the boot.img is repacked, test it first with fastboot boot boot.img

When the Android can boot up successfully, then the boot.img can be written or flash to the boot partition.

With the cache partition freed, we can move the system partition to use the cache partition. This will require us to delete files so as to make it fit inside the smaller cache partition.

As I remember, I delete most of the larger system apps (as long as Android can still boot up), below is the list of system apps remaining:

    $ ls /system/app

As I remember, I delete velvet from /system/priv-app/ .

Also, I perform the steps as answered in Remove google app-velvet from android marshmallow.

I re-format the cache partition before copying the system partition contents over to it.

    mkdir /mnt/system
cd /mnt
mount /dev/block/mmcblk0p23 system
cd system
cp -r --preserve=all /system/* .
cd ..
chcon -v u:object_r:system_file:s0 system

chcon change the security context of the root dir of cache partition to the same security context as /system dir. (needed?)

Modify the Android /fstab.flo , change the line from

/dev/block/platform/msm_sdcc.1/by-name/system       /system         ext4    ro,noatime,barrier=1                                                                 wait

to mount the cache partition as /system instead:

/dev/block/platform/msm_sdcc.1/by-name/cache       /system         ext4    ro,noatime,barrier=1                                                                 wait

Again, after the boot.img is repacked, test it first with fastboot boot boot.img

When the Android can boot up successfully, then the boot.img can be written or flash to the boot partition.

Moving debian to partition

Now, that the original system partition is freed, its original data can be removed and replaced by Debian rootfs.

For reference, see Transformer: Booting Debian experiment.

This time, the system partition has sufficient disk space, at least initially.

For subsequent use of debian kit to use system partition as its rootfs,
in /data/local/deb/bootdeb , modify the IMG variable to:


Boot debian

I use the Linux kernel provided in Debian jessie multirom.

Unzip the archive Debian_Jessie_ARMHF.mrom , and extract the rootfs contents into /sdcard/rom/ .

Copy the kernel modules into debian rootfs,

    cp -r /sdcard/rom/lib/modules/3.4.0-flo+ /lib/modules/

Reuse the bootimg.cfg extracted from boot partition via : abootimg -x /dev/block/mmcblk0p14 , but modify the cmdline as


    bootsize = 0x1000000
pagesize = 0x800
kerneladdr = 0x80208000
ramdiskaddr = 0x82200000
secondaddr = 0x81100000
tagsaddr = 0x80200100
name =
cmdline = console=ttyHSL0,115200,n8 root=/dev/mmcblk0p22 rw console=tty1 fbcon=rotate:1 androidboot.hardware=flo user_debug=31 msm_rtb.filter=0x3F ehci-hcd.park=3 selinux=0 fsck.mode=skip

The root=/dev/mmcblk0p22 will mount the system partition to root dir.

Repack the boot.img for debian using the extracted kernel from multirom with abootimg,

    abootimg --create boot.img -f bootimg.cfg -k /sdcard/rom/boot/vmlinuz -r /sdcard/rom/boot/initrd.img

fbterm login

Refer to Arch Linux for Nexus Flo for the details in getting console login, Xserver, wifi to work properly.

To make console login work, it use fbterm (a framebuffer terminal emulator) instead.

Install fbterm, wpasupplicant (for wifi),

    apt-get install fbterm wpasupplicant
apt-get install libpam-systemd

Modify the provided fbterm-login as: (login path is different and I use a bigger font size)

# example: fbterm-login fb1 tty1
export FRAMEBUFFER=/dev/$1
exec /usr/bin/fbterm -r 1 -s 40 -- /bin/login < /dev/$2

Follow the steps provided in Arch Linux for Nexus Flo to enable systemd getty service, also to compile refresher.c and to enable the provided refresher.service . (The refresher is also needed for the console to be displayed)

Set a passwd for the root user if its not set yet.

As I remember, I set systemd default target to multi-user, (default is

    systemctl set-default

I have not installed any display manager, and will start X server manually after login to console.

Modify /etc/securetty to append a line: (Allows root to login via pseudo terminal device used by fbterm)


Now, we can test whether it works with fastboot boot boot.img

Setup wifi

The wifi setup is more problematic.

Follow the steps provided in Arch Linux for Nexus Flo to copy the wlan firmware from Android, and to enable the provided firmware.service .

Modify firmware.service as : (modprobe and bash path are different)

Description=Load wlan firmware
ExecStart=/sbin/modprobe wlan
ExecStart=/bin/bash -c 'echo 1 > /sys/module/hci_smd/parameters/hcismd_set'

The and 50-firmware.rules are not needed.

To setup the systemd wireless service, however, we need to refer to Switching to systemd-networkd by Joachim Breitner

Save the service file to /etc/systemd/system/wpa_supplicant@.service , I modify the ExecStart line as:

    ExecStart=/sbin/wpa_supplicant -c /etc/wpa_supplicant/wpa_supplicant.conf -Dnl80211 -i %i -u -s -O /run/wpa_supplicant

Create the file /etc/systemd/network/ as:


Copy the Android wpa_supplicant.conf to /etc/wpa_supplicant/ , and symlink /lib/firmware to /usr/lib/firmware

    cp /data/misc/wifi/wpa_supplicant.conf /etc/wpa_supplicant/
cd /lib
ln -s /usr/lib/firmware .

Note: the Android wpa_supplicant.conf keeps the passwd in plain text.

Enable systemd wpa_supplicant@wlan0.service and systemd-networkd.service

    systemctl enable systemd-networkd.service
systemctl enable wpa_supplicant@wlan0.service

At this point, if I restart the system and test, the wifi does not work.

The firmware.service modprobe wlan will load the firmware but fail with errors.

It seems that my Android 6.0 wlan firmware is not compatible with wlan kernel module. (maybe a bit old)

So, I copy the wlan firmware from Debian jessie multirom,

    cp /sdcard/rom/lib/firmware/WCNSS* /usr/lib/firmware/wlan/prima/

If I now restart the system and test, the wifi does work.

Setup X server

Once the console login and wifi works, there is less need to return to the Android system.

Install the Xserver and video drivers,

    apt-get install xserver-xorg xserver-xorg-video-freedreno xinit
apt-get install libgl1-mesa-dri

Use the provided xorg.conf from Arch Linux for Nexus Flo.

Modify /etc/X11/Xwrapper.config to allow any user to start Xserver.


That's about it, the rest is optional.

I install i3 as the only window manager, and its related packages. For i3status, installing from i3status.git will fix the battery status.

    apt-get install i3
apt-get install suckless-tools i3status dunst
apt-get install fonts-droid libnotify-bin rxvt-unicode

Then, as normal user, use startx to start the Xserver with i3,

    startx -- -dpi 300 vt1

By default, the display is in portrait mode.

In the next post, Nexus 7 2013 X server in landscape will describe how I startx in landscape.

Setup pulseaudio

To install pulseaudio with bluetooth,

    apt-get install bluez blueman gconf2
apt-get install pulseaudio pulseaudio-utils
apt-get install pulseaudio-module-bluetooth pavucontrol

For pulseaudio system-wide instance setup, refer to How to make Pulseaudio run once at boot for all your users.

But, modify the pulseaudio.service Exec line as:

    ExecStart=/usr/bin/pulseaudio --daemonize=no --system --realtime --disallow-exit --log-target=journal

Also, add the following lines to /etc/pulse/

    ### Automatically load driver modules for Bluetooth hardware
load-module module-bluetooth-policy
load-module module-bluetooth-discover

For reference, see Bluetooth audio with BlueZ 5.

By default, there is the nexus 7 audio speaker, and pulseaudio will play through it. If a bluetooth headset is being connected, one can direct the audio through the headset via pavucontrol.

In my case, I will rather just set the bluetooth headset as the default sink. This can be set via below commands pactl:

    $ pactl list sinks | grep Name
Name: alsa_output.platform-soc-audio.0.HiFihw_apq8064tablasnd_0sink
Name: bluez_sink.00_02_5B_00_8E_82

The second sink name is my bluetooth headset, and pactl set-default-sink is used to set it as default,

    $ pactl set-default-sink bluez_sink.00_02_5B_00_8E_82

Alternately, one can set it in the user pulseaudio client.conf

    default-sink = bluez_sink.00_02_5B_00_8E_82

Swap boot partitions

Finally, I put the Android boot image into recovery partition, and use the boot partition to boot Linux.

Reuse the bootimg.cfg extracted from recovery partition via : abootimg -x /dev/mmcblk0p25 , but used back the original cmdline, zImage, initrd.img for Android boot.

Once, the boot.img is repacked for recovery, test it first with fastboot boot boot.img , before making it permanent with fastboot flash recovery boot.img

Final /etc/fstab also mounts the userdata partition, and I create a symlink /data -> /mnt/data

    # debian
# system
/dev/mmcblk0p22 / ext4 noatime,discard,errors=remount-ro 0 1
# userdata
/dev/mmcblk0p30 /mnt/data ext4 defaults,noatime,discard 0 2
/mnt/data/local/var /var none bind


The nexus 7 is back, after just being a whisker from death.


blog comments powered by Disqus