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 CF-Auto-Root-flo-razor-nexus7.zip from https://download.chainfire.eu/347/CF-Root/CF-Auto-Root/CF-Auto-Root-flo-razor-nexus7.zip 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:

/system/bin/sefs

    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
BasicDreams
Bluetooth
BluetoothMidiService
CalculatorGoogle
CalendarGooglePrebuilt
CaptivePortalLogin
CertInstaller
CloudPrint2
DMAgent
DocumentsUI
DownloadProviderUi
EditorsDocsStub
EditorsSheetsStub
EditorsSlidesStub
FaceLock
GoogleContactsSyncAdapter
GoogleEars
HoloSpiralWallpaper
HTMLViewer
iWnnIME
KeyChain
LiveWallpapers
LiveWallpapersPicker
MediaShortcuts
NfcNci
NoiseField
PacProcessor
PhaseBeam
PrebuiltDeskClockGoogle
PrebuiltKeepStub
PrintSpooler
UserDictionaryProvider
WebViewGoogle
XT9IME


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:

    IMG=/dev/block/mmcblk0p22



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

bootimg.cfg

    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)
fbterm-login

    #!/bin/bash
# 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 graphical.target)

    systemctl set-default multi-user.target


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)

    pts/0


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)
firmware.service

    [Unit]
Description=Load wlan firmware
Wants=network.target
Before=network.target
 
[Service]
Type=oneshot
ExecStart=/sbin/modprobe wlan
ExecStart=/bin/bash -c 'echo 1 > /sys/module/hci_smd/parameters/hcismd_set'
 
[Install]
WantedBy=multi-user.target


The firmware.sh 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/wlan.network as:

    [Match]
Name=wlan0
[Network]
DHCP=yes


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.

    allowed_users=anybody


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/system.pa

    ### Automatically load driver modules for Bluetooth hardware
.ifexists module-bluetooth-policy.so
load-module module-bluetooth-policy
.endif
 
.ifexists module-bluetooth-discover.so
load-module module-bluetooth-discover
.endif


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
/etc/fstab

    # 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


Additional:

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

Comments

blog comments powered by Disqus