Z.OOL.ネット信託統治領 はてな諸島

こちらは "Z.OOL.ネット信託統治領 はてな諸島" です。

Debian noroot 環境の起動プロセスについて

最近は冬の寒さが身に沁みる。
鉛色の空を眺めながら、強い寒気を体に受けて激しく凍える思いをする。
兎に角、現状の問題点を整理しようか。


[BGM]: New Order - The Perfect Kiss (Official Music Video)

追記 (2016/07/05)

本記事を大幅に加筆修正して Qiita に投稿しました。以降は、本記事の修正及び更新等は "Debian noroot 環境の動作原理について - Qiita" にて行いますので、どうか宜しく御願い致します。

qiita.com

はじめに

Debian noroot とは、 Android 上において root 権限を取ることなく Debian 環境を構築するためのアプリケーションです。

ここでは、 Android 上から Debian noroot アプリを起動させてから、 Debian noroot 環境上のデスクトップマネージャが起動するまでの一連の過程について簡潔にまとめます。

XserverSDL の起動

Debian noroot 環境は、 X サーバに XserverSDL を用いています。

Android OS より Debian noroot アプリを起動した直後に、画面上部の "Change device config" ボタンをクリックすると、 "Change device config" なるタイトルのメニューが表示されます。

次に、 "Change device config" メニューより "Data installation location" を選択した後、"Data installation location" メニューより "Specify directory" を選択します。

ここで、ディレクトリの変更を促されますが、このまま何もせずに "OK" ボタンを押すと、 以下のコマンドラインが表示されます。これが XserverSDL を起動するときにコマンドラインに渡される引数であることが判ります。

XSDL -nohelp -screenbuttons -warndiskspacemb 900 -exec $SECURE_STORAGE_DIR/usr/bin/xli -onroot -border black -center $UNSECURE_STORAGE_DIR/loading.gif ; $SECURE_STORAGE_DIR/img/proot.sh ./startx.sh

ここで、 Android 端末に XserverSDL アプリをインストールし、 XserverSDL に同様な引数を渡して挙動を比較して調査したところ、各引数の意味は凡そ以下の通りであると判ります。

  • -nohelp … X サーバ画面起動後にヘルプ画面を表示せず、全体を黒い画面のままにする。
  • -screenbuttons … X サーバ画面上に "Ctrl", "Shift", "Alt" キーの働きをするボタンを表示する。
  • -warndiskspacemb [n] … ストレージ領域の残りが [n] MB 以下の状態ならば警告を表示する。
  • -exec-exec オプション以降の引数を shell に渡してプロセスを実行する。

また、 Debian noroot 環境から printenv コマンドを実行した結果から、環境変数 $UNSECURE_STORAGE_DIR, $SECURE_STORAGE_DIR はそれぞれ、ディレクト/sdcard/Android/com.cuntubuntu/files, /data/data/com.cuntubuntu/files を指していることも判ります。

以上のことより、 Debian noroot アプリでは、以下のプロセスで XserverSDL が起動されることが判ります。

  • X サーバをヘルプ画面を表示させずに起動する。
  • X サーバの画面上に "Ctrl", "Shift", "Alt" キーの働きをするボタンを表示する。
  • X サーバの画面中央に "Loading Please wait This may take up to one minute." と書かれた画像 (/sdcard/Android/com.cuntubuntu/files/loading.gif) を表示する。
  • Android NDK 環境下で、シェルスクリプト /data/data/com.cuntubuntu/files/img/proot.sh./startx.sh を引数にして実行する。

proot.sh スクリプトの実行

ここで、 シェルスクリプト /data/data/com.cuntubuntu/files/img/proot.sh は、 Debian noroot 環境からは /proot.sh として見ることが出来ます。 /proot.sh の内容は以下の通りです。

#!/system/bin/sh

case x$SDCARD in x ) SDCARD=/sdcard;; esac

case x$SECURE_STORAGE_DIR in x ) echo > /dev/null;; * ) cd $SECURE_STORAGE_DIR/img;; esac

case x$SDCARD in x ) export SDCARD=$EXTERNAL_STORAGE;; esac

SDCARD=`../busybox realpath $SDCARD`
STORAGE="-b $SDCARD"
for F in 0 1 2 3 4 5 6 7 8 9; do
    DIR=`eval echo \\$UNSECURE_STORAGE_DIR_$F`
    case x$DIR in x ) echo > /dev/null;; * ) STORAGE="$STORAGE -b $DIR" ; mkdir -p $DIR ;; esac
done
echo "STORAGE $STORAGE"

export HOME=/home/$USER
export SHELL=/bin/bash
export LD_LIBRARY_PATH=
# Java doesn't work in PRoot when started from /usr/bin/java symlink, so we have to put a path to java binary into PATH, and Java 6 fails on Samsung devices
JAVA_PATH=/usr/lib/jvm/default-java/jre/bin:/usr/lib/jvm/default-java/bin
ls usr/lib/jvm/java-7-openjdk-*/bin > /dev/null 2>&1 && JAVA_PATH=/`echo usr/lib/jvm/java-7-openjdk-*/jre/bin`:/`echo usr/lib/jvm/java-7-openjdk-*/bin`
export PATH=/usr/local/sbin:/usr/local/bin:$JAVA_PATH:/usr/sbin:/usr/bin:/sbin:/bin
export "LD_PRELOAD=/libdisableselinux.so /libandroid-shmem.so"
export PROOT_TMPDIR=`pwd`/tmp
export PROOT_TMP_DIR=$PROOT_TMPDIR
export TZ="`getprop persist.sys.timezone`"
./proot -r `pwd` -w / -b /dev -b /proc -b /sys -b /system $STORAGE "$@"

上記のシェルスクリプトの内容より、 proot.sh スクリプトは以下のプロセスを実行していることが判ります。

  • Android 端末のストレージ領域の自動検出とストレージ領域のバインドオプションの生成を行う。
  • export HOME=... 以下の処理でHOME, SHELL, LD_PRELOAD 等の主要な環境変数の設定を行う。
  • 最後に proot コマンドを用いて $SECURE_STORAGE_DIR/img (=/data/data/com.cuntubuntu/files/img) をルートディレクトリとして chroot 環境を構築する処理を行う。

なお、 proot とは、 root 権限を取ることなく、 chroot 環境の構築と mount --bind によるディレクトリのバインドを行うためのアプリケーションです。

ここで、 proot.sh の最終行と proot --help の実行結果より、最後の proot コマンドは、ルートディレクトリ上に /dev, /proc, /sys, /system 及び内部ストレージ領域の存在するディレクトリをバインドし、シェルスクリプト proot.sh に渡された引数 (=./startx.sh) をそのまま proot の子プロセスとして実行していることが判ります。

startx.sh スクリプトの実行

次に、シェルスクリプト /data/data/com.cuntubuntu/files/img/proot.sh に渡される引数であるシェルスクリプト ./startx.shDebian noroot 環境からは /startx.sh として見ることが出来ます。ここで、シェルスクリプト /startx.sh の内容は以下の通りです。

#!/bin/sh

rm -f /var/run/dbus/pid
fakeroot-tcp /usr/bin/env PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin dbus-daemon --system

sleep 1
dbus-launch --exit-with-session sh -c 'xfce4-session ; setsid sh -c "cd /proc/ ; for f in [0-9]* ; do [ \$f = \$\$ ] || kill -9 \$f ; done"' &

wait

上記のシェルスクリプトの内容より、 startx.sh は以下のプロセスを実行していることが判ります。

  • fakeroot 権限で dbus-daemon を起動する。
  • dbus-launch 経由で、デスクトップマネージャである xfce4 を起動する。
  • xfce4 が終了した後は、ユーザ権限で起動しているプロセスを強制終了する。
  • 上記の処理を待ってアプリ全体を終了する。

まとめ

上記で述べた内容から、 Debian noroot 環境は以下のプロセスにより起動していることが判りました。

  • Android OS より Debian noroot アプリを起動した時に、以下の手順で XserverSDL を起動する。
    • 画面中央にヘルプメッセージを表示させないようにする。
    • 画面上に "Ctrl", "Shift", "Alt" キーの働きをするボタンを表示する。
    • 画面中央に "Loading Please wait This may take up to one minute." のメッセージを表示する。
  • Android NDK 環境下でシェルスクリプト /data/data/com.cuntubuntu/files/img/proot.sh./startx.sh を引数にして実行し、以下の処理を行う。
    • Android 端末のストレージ領域の自動検出とストレージ領域のバインドオプションの生成を行う。
    • Debian noroot 環境全体に関連する主な環境変数 HOME, SHELL, LD_PRELOAD 等の設定を行う。
    • $SECURE_STORAGE_DIR/img (=/data/data/com.cuntubuntu/files/img) をルートディレクトリとして chroot 環境を構築する処理を行い、 proot.sh の引数として渡された ./startx.sh に制御を移す。
  • /data/data/com.cuntubuntu/files/img をルートディレクトリとした chroot 環境下で /startx.sh を実行し、以下の処理を行う。
    • fakeroot 権限で dbus-daemon を起動する。
    • dbus-launch 経由で、デスクトップマネージャである xfce4 を起動し、一連の起動プロセスが完了する。