买(?)一送一,惊不惊喜意不意外?
虽然……
虽然汝可能从哪里听说过 Android 是基于 Linux 内核的啦,不过大多数时候汝大概没办法直接把汝爱用的 GNU/Linux 发行版上的 工具直接拿过来用,为啥咧?
- 手机和电脑不是一种 CPU(PC 常见的就是 x86_64 , 手机上比较常见的是 arm64(有时也称作 aarch64)),因此 两边的二进制文件并不能直接拿来换着用。
- 虽然 Android 用了 Linux 内核,但是和普通的 GNU/Linux 发行版还是有很大的区别的。例如以 bionic 取代glibc (C 函数库)、以 Skia 取代 Cairo (用于向量图形绘图)、再以 OpenCORE 取代 FFmpeg(常用于音视频的录影和转换)。 于是不少依赖它们的软件不好运行。
- 以及随着越来越多的 GNU/Linux 发行版开始用 Systemd 作为初始化程序,很多程序或多或少就和 Systemd 有了些关联(或者依赖)。 不巧的是……
所以 Android 应用们不好用了么?
STAGE 0 - Android 上的终端(模拟器)
如果汝有用过一些需要在电脑上运行一个辅助程序的 Android 应用(像是 AppOps 这样的),汝其实已经离 Shell 很近了。
在手机和电脑连接以后,可以运行 adb shell 命令获得一个 shell:
(PC) $ adb shell
walleye:/ $
接下来就可以 cd ls 乱出了…… (啥?) 因为别的汝也干不了啊……
如果汝的手机有 root 权限的话,在 Shell 里运行 su 试试?第一次的话汝的手机上的 root 权限管理程序应该会提示汝授予权限什么的。
要想在手机上试试的话,也有差不多的终端模拟器程序可以选择。 例如这个?
STAGE 1 - 在 Android 上使用(部份) GNU/Linux 程序
正好也有一群人这么想,于是它们把终端模拟器和一些常用的 GNU/Linux 应用程序组合起来,创造出了 Termux。
(这个在电脑上显示 Android 设备画面的程序是 scrcpy 啦~)
这里面提到的 pkg 其实就是有点小包装的 apt 啦,熟悉 Debian / Ubuntu 的话应该不会陌生。
下面的 root / Unstable / x11 是额外的仓库,需要使用要求 root 权限或者图形界面的软件在里面。
- Play 商店上也有几个 Termux 使用的插件,可以实现自定义字体、浮动窗口、快速运行脚本、访问手机内存设备 等功能。有几个是收费的,不过有别的地方可以免费下载(小声)
- 键盘上面的特殊按键可以通过编辑 ~/.termux/termux.properties 文件中的 extra-keys 属性来修改, 特殊键的定义在这里。。
- 偷懒的话也可以直接安装一个有这些特殊键的输入法,例如 Hacker's Keyboard
- 当然外接键盘也是可以的。
以及大概有人踩过了不少的坑的样子……
STAGE 2 - 在 Android 上运行(部份) GNU/Linux 容器
怀念汝习惯的 GNU/Linux 发行版的原汁原味的包管理器和其它工具?可以考虑运行一个容器来解馋(?)
Linux® 容器是与系统其他部分隔离开的一系列进程。运行这些进程所需的所有文件都由另一个镜像提供, 这意味着从开发到测试再到生产的整个过程中,Linux 容器都具有可移植性和一致性。
—RedHat : 什么是 Linux 容器?
实现这种操作的关键要素就是 chroot ,它针对正在运作的软件行程和它的子进程,改变它外显的根目录。 在使用 chroot 之后,进程就会认为设置的目录是根目录,就可以进行各种操作啦,例如隔离访问或者修复系统什么的。
当然这操作是要 root 权限的,至于后来有人写出用户空间中的 proot ,就是另一个故事啦……
- 手机有 root 权限的话,可以用 chroot 安装一个 GNU/Linux 容器。也有像是 Linux Deploy 这样的应用可以简化这一过程。
- 没有 root 权限的话,借助前面提起的 proot 也能实现差不多的操作。也有像是 UserLAnd 和 TermuxArch 这样的工具帮忙简化这一过程。
以及大概也有人踩过了不少的坑的样子……
那这次再说吧……
再一次提醒没有耐心和同理心的家伙们去用其它即用的工具像是 TermuxArch 和 Linux Deploy ……
所以这回咱们要干什么?
由于咱不可能把所有发行版都装一次,也不可能在各种手机上都测试一遍,于是咱只能拿 咱手边的家伙举个例子,例如咱手上的小米平板4 ……
现在的手机 CPU 基本上都是 64 位了吧,不知道的话搜索一下手上 CPU 的型号应该就能看个大概。
- 比较新的 Android 系统,最好有 root 权限和完整 busybox 支持。
如果汝已经动手给手机安装了第三方 ROM,那应该不是什么难事。 某蓝绿海厂等受害者可以尝试 UserLAnd……
- 一些剩余存储空间 (这不是废话么)
- 安装好终端模拟器和合适的键盘。
或者 Termux 也可以,在里面装上 tsu 以后可以让 Termux 里的 Bash 以 root 用户运行。
作为好几年的 Arch Linux 受害 爱好者,咱当然就装一个 ArchLinux ARM 试试看啦 (虽然这不是官方分支,以及不是有 TermuxArch 了么……)
那么我们的目标是,没有蛀牙 ……
例如正常的使用包管理器、安装软件以及用它们等等。
- 能够访问网络和内存设备 (踩坑警告)
- 能够通过外部访问 (ssh 或者 vnc 啥的)
如有任何不适还请装作没事
天降大坑 nosuid ……(?)
某些手机上的 /data 挂载的时候加上了 nosuid 选项,于是 sudo 就炸了……
sudo: effective uid is not 0, is /sbin/sudo on a file system with the 'nosuid' option set or an NFS file system without root privileges?
这种情况可以考虑创建一个磁盘映像把容器放进去(大概吧……)
# 找个地方创建一个映像文件
dd if=/dev/zero of=/path/to/root.img bs=1048576 count=4096
# 给映像创建文件系统和挂载
mke2fs -t ext4 -F /path/to/root.img
mkdir -p /data/linux/arch
mount -t ext4 -o loop /path/to/root.img /data/linux/arch
如果肯定不用 sudo 的话能不能当做没事……
要有空间,于是……
丢了个 tarball 下来让汝自己 bootstrap 去(啥?)
安装 GNU/Linux 发行版的过程,其实就是在解决一个先有鸡还是先有蛋的问题,这个过程就是 bootstrap。 大概就是……
- 从别的什么可以启动的地方把要安装的 GNU/Linux 发行版的最小的部份下载回来,安装上。
- 通过一些方法进入这个最小的部份中(例如 chroot ),为目标设备特化配置。
只不过大部分发行版的安装过程中被自动化了(Arch / Gentoo 等用户表示情绪稳定。)。 在 Android 上安装,同样要经过这个过程。
于是,首先咱们要下载 Arch Linux ARM 的 tarball ,可以在电脑上下载下来发送到手机上,也可以用手机 的浏览器直接下载,也可以用 curl 或者 wget:
如果直接从官方仓库下载不够快的话,可以通过镜像网站下载,例如:
https://mirrors.tuna.tsinghua.edu.cn/archlinuxarm/os/ArchLinuxARM-aarch64-latest.tar.gz
然后创建一个目录存放解压出来的基本系统,再解压出来刚下载的 tarball:
# 因为 SD 卡可能放不下权限等神奇的原因,就放在内存设备上好了……
# mkdir -p /data/linux/arch
# 以及 Arch Linux ARM 官方是建议用 bsdtar 的,要是汝的手机上凑巧有(不管是
# 系统里的还是 Termux 的),就用上吧……
# bsdtar -xpf /path/to/ArchLinuxARM-aarch64-latest.tar.gz -C /path/to/mountpoint
# 不然 tar 也是可以的。
# tar -xzvf /path/to/ArchLinuxARM-aarch64-latest.tar.gz -C /path/to/mountpoint
Chroot on Android
在普通的 GNU/Linux 发行版上 chroot 时,咱们大抵会这么做:
# 切换到 chroot 的目标目录并挂载上 /dev /sys 这样的伪文件系统
# cd /location/of/new/root
# mount -t proc proc proc/
# mount --rbind /sys sys/
# mount --rbind /dev dev/
# 通过给定的 shell 进入 chroot
# chroot /location/of/new/root /bin/bash
在 Android 上其实也差不多:
# mount -o bind /dev /data/linux/arch
# mount -o bind /sys /data/linux/arch/sys
# mount -o bind /proc /data/linux/arch/proc
# mount -t tmpfs tmpfs /data/linux/arch/tmp
以及记得修改一下 chroot 里面的 /etc/resolv.conf , Arch 这个默认是到 /run/systemd/resolve/resolv.conf 的软链接。 反正里面也没有 systemd 用 ,于是 删掉重建好了……
# /data/linux/arch/etc/resolv.conf
nameserver 8.8.8.8
nameserver 8.8.4.4
如果有必要的话,可以同时修改里面的镜像仓库地址。
# /data/linux/arch/etc/pacman.d/mirrorlist
Server = https://mirrors.ustc.edu.cn/archlinuxarm/$arch/$repo
然后就和平常一样 chroot 进去咯~
clover:/data/linux # chroot /data/linux/arch /bin/bash
[root@localhost /]#
起始配置
The bootstrap environment is really barebones (no nano or lvm2). Therefore, we need to set up pacman in order to download other necessary packages.
这下知道为啥要在外面改 /etc/resolv.conf 了吧(当然汝要是独辟蹊径的话那当咱没说……)
正如 官方说明提示的一样 ,初始化 pacman 密钥环和获得密钥:
[root@localhost /]# pacman-key --init
gpg: /etc/pacman.d/gnupg/trustdb.gpg: trustdb created
gpg: no ultimately trusted keys found
gpg: starting migration from earlier GnuPG versions
gpg: porting secret keys from '/etc/pacman.d/gnupg/secring.gpg' to gpg-agent
gpg: migration succeeded
gpg: Generating pacman keyring master key...
gpg: key 56753AA14274D5A7 marked as ultimately trusted
gpg: directory '/etc/pacman.d/gnupg/openpgp-revocs.d' created
gpg: revocation certificate stored as '/etc/pacman.d/gnupg/openpgp-revocs.d/46C9147EE071F7E5D16A085856753AA14274D5A7.rev'
gpg: Done
==> Updating trust database...
gpg: marginals needed: 3 completes needed: 1 trust model: pgp
gpg: depth: 0 valid: 1 signed: 0 trust: 0-, 0q, 0n, 0m, 0f, 1u
[root@localhost /]# pacman-key --populate archlinuxarm
==> Appending keys from archlinuxarm.gpg...
==> Locally signing trusted keys in keyring...
-> Locally signing key 69DD6C8FD314223E14362848BF7EEF7A9C6B5765...
-> Locally signing key 02922214DE8981D14DC2ACABBC704E86B823CD25...
-> Locally signing key 9D22B7BB678DC056B1F7723CB55C5315DCD9EE1A...
==> Importing owner trust values...
gpg: setting ownertrust to 4
gpg: inserting ownertrust of 4
gpg: setting ownertrust to 4
==> Updating trust database...
gpg: marginals needed: 3 completes needed: 1 trust model: pgp
gpg: depth: 0 valid: 1 signed: 3 trust: 0-, 0q, 0n, 0m, 0f, 1u
gpg: depth: 1 valid: 3 signed: 1 trust: 0-, 0q, 0n, 3m, 0f, 0u
gpg: depth: 2 valid: 1 signed: 0 trust: 1-, 0q, 0n, 0m, 0f, 0u
[root@localhost /]#
接下来安装(和更新)基本系统,如果有别的需要的话也可以装别的。
[[root@localhost](mailto:root@localhost) /]# pacman -Syu base base-devel nano --needed
如果不幸遇到了像是 error: could not determine cachedir mount point /var/cache/pacman/pkg 这样的错误, 那在 /etc/pacman.conf 里把 Misc options 下面的 CheckSpace 注释掉应该能绕过 (于是有别的方法嘛)
基于正经的 GNU/Linux 用户不会日用 root 账户这一指导原则(啥?),咱们也要新建一个用户:
[root@localhost /]# useradd -m -s /bin/bash horo
[root@localhost /]# passwd horo
有必要的话也可以修改 sudoers 文件(记得用 visudo),把汝刚刚创建的用户添加到 sudoers 中。
以及介于 Android 的魔改属性,只有特定的组可以进行像是访问网络或者访问 SD 卡等操作,于是 还要在 chroot 里新建相应的组,并把新建的用户加到这些组去:
# groupadd 可以用 -g 参数制定新增组的 id ,至于这些组分别是啥
# 看后面的组名应该就知道了吧……
groupadd -g 3001 android_bt
groupadd -g 3002 android_bt-net
groupadd -g 3003 android_inet
groupadd -g 3004 android_net-raw
groupadd -g 1015 sdcard-rw
groupadd -g 1028 sdcard-r
# 然后把新建的用户添加到合适的组中
gpasswd -a horo android_bt
gpasswd -a horo android_bt-net
gpasswd -a horo android_inet
gpasswd -a horo android_net-raw
gpasswd -a horo sdcard-rw
gpasswd -a horo sdcard-r
最后(?),因为没有 systemd,所以请像新装 Arch Linux 的时候一样手动设置一下 locales:
- /etc/locale.gen 是一个仅包含注释文档的文本文件。指定您需要的本地化类型,去掉对应行前面的注释符号(#)就可以啦,还是用 nano 打开,建议选择帶UTF-8的項:
# nano /etc/locale.gen
en_US.UTF-8 UTF-8
- 执行 locale-gen 以生成 locale 讯息:
# locale-gen
# echo 用来输出某些文字,后面的大于号表示把输出保存到某个文件里啦~
# 或者可以用文字编辑器新建这个文件加上这一行。
# echo LANG=en_US.UTF-8 > /etc/locale.conf
用 su 切换到刚建立的用户,然后编辑 ~/.bashrc 修改自己的 Locale ,例如:
LANG=en_US.UTF-8
LC_CTYPE="en_US.UTF-8"
LC_NUMERIC="en_US.UTF-8"
LC_TIME="en_US.UTF-8"
LC_COLLATE="en_US.UTF-8"
LC_MONETARY="en_US.UTF-8"
LC_MESSAGES="en_US.UTF-8"
LC_PAPER="en_US.UTF-8"
LC_NAME="en_US.UTF-8"
LC_ADDRESS="en_US.UTF-8"
LC_TELEPHONE="en_US.UTF-8"
LC_MEASUREMENT="en_US.UTF-8"
LC_IDENTIFICATION="en_US.UTF-8"
LC_ALL=
(为啥不是 ~/.config/locale.conf 了啊…… 其实咱也不知道…… )
于是现在大概就有了这个样子:
(这个在终端里显示发行版等信息的软件是 screenfetch 啦,也有人喜欢另一个 小修改版 neofetch )
设置 SSH 和 SD 卡访问
SSH 的话,生成好主机密钥然后再启动 sshd 就可以:
## 在有 systemd 这样的 init 系统的发行版上启动 sshd 时会帮汝运行这一步,
## 不过这里就只有自己代劳啦……
# ssh-keygen -A
## 这里一定要是绝对路径,不然就会出 "sshd re-exec requires execution with an absolute path" 错误。
# /usr/bin/sshd
然后就可以用一个新的终端模拟器窗口通过 ssh 连接进来啦……
clover:/ $ ssh horo@127.0.0.1
The authenticity of host '127.0.0.1 (127.0.0.1)' can't be established.
ECDSA key fingerprint is SHA256: .
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
horo@127.0.0.1's password:
[horo@localhost ~]$
要是汝在登录时遇到了 PTY allocation failed on channel 0 这样的错误,在 chroot 里(重新) 挂载一下 /dev/pts 试试?
# umount /dev/pts
# mount -t devpts devpts /dev/pts
以及可以的话记得修改 /etc/sshd_config 把 sshd 限定到只允许本地连接?
要把 SD 卡挂载到哪里的话,在 chroot 的外面运行:
## 当然汝的 /sdcard 可能是汝的内存设备什么的,别忘了自己调整路径……
# mkdir /data/linux/arch/mnt/sdcard
# mount -o bind /sdcard /data/linux/arch/mnt/sdcard
总结?
所以有 Linux Deploy 那样好用(?)的工具了为啥不直接拿来用呢(划掉)
以及纯粹是闲的,找一台正经的电脑装正经的 GNU/Linux 不好么 (x)