手头上的旧手机为小米 6, 本文可能部分内容只在小米 6 上适用 [xiaomi 6 sagit]
且本文主要讨论 LinuxDeploy (需要 root) 的方式, 非 root 用户可使用 Termux 方式
1 方案选择
前后测试了 3 种方法,最推荐使用 LinuxDeploy (chroot)
- Ubuntu touch 原生 Linux 系统,但是为了驱动手机设备,需要做很多工作,
社区上适用于 xiaomi6 的 ubuntu touch 已经停止开发了,使用起来还有很多不足,
apt update && apt upgrade
一下, 可能设备就无法启动了 - Termux (proot), Termux 本身的文件结构与 linux 系统不同, 使用 proot 方式运行 linux, 性能有损耗 (但是并不多), 对于非 root 用户该方式非常不错,而且可以通过 Termux-boot 插件实现自启动
- LinuxDeploy (chroot), 需要 root 权限,初略了解, 它应该比 proot 方式性能更好,原本的 Android 系统负责驱动设备硬件, 维护设备运行,而 chroot 中的 linux 并行于 Android 系统运行, 不必关心硬件设备的驱动
使用 LinuxDeploy 的同时将系统刷为 lineageos, 使用原生安卓系统驱动设备, 保证手机正常工作,同时尽量少的占用资源,不安装不开启不必要的应用, 不过刷系统是个可选项,使用原生系统也问题不大
chroot (change root) 是一种非常原始的容器技术, 仅仅是将一个进程的根目录更改到一个指定目录,限制访问和可见性, 其余的硬件资源,网络资源等则还是和宿主系统共享,chroot 本身运行在内核态, 需要 root 权限
小结:
- 对于没有 Root 权限的 Android 设备, 使用 Termux+proot 方式安装完整 linux 是最佳方案,proot 是用户空间的 chroot, 系统调用会拦截一层,有一些性能损失,但是这种隔离远不如容器的隔离, 性能损失比较小,是完全可以接受的 参考: Termux Wiki
- 对于有 Root 权限的 Android 设备,使用 LinuxDeploy (LinuxDeploy-Pro 原作者 meefik 的 github 库貌似已经没有更新,且安装时有一些问题), LinuxDeploy 使用 Chroot 实现,需要 Root 权限,相对于 Proot, 其系统调用没有转换操作,性能更好,适合长期运行
2 前置准备
bootloader 解锁
驱动安装,小米手机可以用 miflash 安装驱动
解决 Windows 上 usb3 使用 fastboot 时卡住的问题
1
2
3
4
5
6@echo off
reg add "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\usbflags\18D1D00D0100" /v "osvc" /t REG_BINARY /d "0000" /f
reg add "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\usbflags\18D1D00D0100" /v "SkipContainerIdQuery" /t REG_BINARY /d "01000000" /f
reg add "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\usbflags\18D1D00D0100" /v "SkipBOSDescriptorQuery" /t REG_BINARY /d "01000000" /f
pause(刷系统为可选项) 系统刷为 LineageOS 参考: https://wiki.lineageos.org/devices/sagit/install
刷入 twrp, 参考: https://twrp.me/xiaomi/xiaomimi6.html, img 下载: https://dl.twrp.me/sagit/
fastboot flash recovery ./twrp-xxx.img
刷入 magisk (可以先刷入 twrp, 参考 https://dl.twrp.me/sagit/) https://github.com/topjohnwu/Magisk
- 下载最新的 magisk apk 文件,后缀改为 zip
- 在 twrp 中选择对应的 zip 文件刷入,如果是 LineageOS 的 recovery, 可以适用 adb sideload 刷入
- 重启后打开 magisk, 按照提示进行后续操作,按推荐步骤执行即可
给 shell 赋予 root 权限,打开开发者模式,打开 USB 调试,打开 USB root 调试
adb shell
连接手机su
如果执行失败,去 magisk 的 root 权限管理中打开 com.android.shell 包的 root 权限- 再次尝试
su
3 LinuxDeploy 安装部署和配置
LinuxDeploy 应用安装
- 官方的 LinuxDeploy, 可以先尝试一下,小米 6 使用官网的 app 一直安装有问题, 所以最终没有使用官方的 apk
- 我的小米 6 使用 LinuxDeploy-Pro, 看维护时间还比较新,官方地址貌似停止维护了
- 下载 apk 安装,打开时授予 root 权限
LinuxDeploy 配置
应用右下角按钮设置安装选项,这里列一下我的选择, 可以根据喜好或者实际安装情况决定
- chroot 不用改
- Debian
- arm64
- stable
- http://mirrors.ustc.edu.cn/debian 小米 6 这里设置 https 连不上 , 只有 http 能用
- file
${EXETERNAL_STORAGE}/debian.img
- 81920 镜像大小我给了 80G, 开始只给 10G, 后面软件安装发现不够用了, 不过之后也可以扩容,只是费时间
- ext4 不用改
- 用户名和密码自由设置
- en_US.UTF-8
- Auto DNS 设置可以改为好用的地址,我这里选的自动
- 勾选 INIT, 小米 6 上 run-parts 我没有调教好,这里选的 sysv, 用于开启容器时自动执行一些任务
- 勾选 MOUNTS,
/sdcard:/sdcard
主要是将安卓内部存储挂载到 Linux 系统内 - 勾选 SSH, 该步骤是必须的,否则安装的 Linux 不好访问
部署 Linux
按照上述配置完成后,返回主界面,点击右上 "三点", 选择 "install", 开始安装部署
- 若提示联网问题,先检查设备是否联网,镜像配置是否正确, 是否使用 http 协议
- 更改配置后,先点 stop 按钮卸载分区,之后再次点 install 安装
- 安装过程必须保证没有报错,若有报错,可能需要搜索相关问题, 解决后重新安装
- 若使用该方法怎样都安装不成功,可以参考 ((20230730133322-tx8cs9x ' 备份与恢复 ')) 一节的方法,直接导入合适架构的备份包即可
启动容器,ssh 连接
- 点击 start 即可启动容器
- 启动成功后可以通过 ssh 连接到 Linux
- 可以局域网的 PC 通过 IP 连接
- 也可以手机上安装 JuiceSSH, 通过 localhost 或者 127.0.0.1 连接
- 启动容器后,最好 sudo su 切换到 root 用户操作, 之后所有操作都基于 root 用户
开机自启动,CPU 锁,Wi-Fi 锁
打开 LinuxDeploy 左上角菜单
- Lock Wi-Fi 应用运行时保持 WiFi 打开
- Wake lock 应用运行时保持 CPU 运转,即使锁屏
- Autostart 当 Android 启动后自动运行应用,并运行默认配置的容器, 非常有用
- Autostart delay 自启动延时 我设置了 10 秒
备份与恢复
Telnet 服务: LinuxDeploy 左上角菜单设置,Services, TELNET 和 HTTP 都打开, 取消勾选 TELNET 中的 Localhost, HTTP 服务的 Access restriction 中 A 之后设置允许连接的 IP 地址 比如
A:192.168.31.27 D:*
这里的 HTTP 服务是由 httpd 提供, 支持配置多个
A:xxx
添加多个可以访问的 IP 地址浏览器访问
http://ip:5080
打开 Linux Deploy Terminal 的 Telnet 终端备份与恢复命令
1
2
3
4
5
6su # 切换为root
cd /sdcard
linuxdeploy stop -u # 停止容器并卸载分区
linuxdeploy export /sdcard/debian-rootfs-20230729.tgz # 等待完成即可, 之后可以拷贝一份到电脑上
linuxdeploy import /sdcard/debian-rootfs-20230729.tgz # 导入操作
linuxdeploy start # 运行容器如果上述的安装不成功,也可以下载合适架构的备份包,直接导入 [小米 6 的架构为 arm64 (aarch64)]
- ubuntu 18 LTS arm64 (http://hub.meefik.ru/rootfs/ubuntu_arm64.tgz)
- debian 10 arm64 (http://hub.meefik.ru/rootfs/debian_arm64.tgz)
镜像扩容
先打开 telnet 访问,切 root 用户
1
2
3
4
5
6
7
8# 从/dev/zero取二进制0, 块大小为1M, 一共4096个块, 追加到debian.img (扩容4GB)
dd if=/dev/zero bs=1048576 count=4096 >> /sdcard/debian.img
# 强制检查(修复)镜像的硬盘分区
e2fsck -f /sdcard/debian.img
# 调整分区大小, 同步文件系统容量?
resize2fs /sdcard/debian.imgLinuxDeploy 中的一些限制
- 不是基于 systemd 运行的,systemctl, service 等命令无法正常工作
- 不支持 docker, 如果想要支持,需要自己编译 android 内核,修改编译选项, 相当麻烦
4 Linux 系统配置
我的小米 6 系统部署启动成功后,发现 ssh 连接正常,apt 更新也正常, 但是 ping 不通任何域名和地址,包括 127.0.0.1, curl 和 wget 等应用也无法使用
解决联网问题 尝试了很多方法,只能让 root 用户正常联网
编辑
/etc/group
在 aid_inet (3003), aid_net_raw (3004) 的分组中添加需要的用户名,多个用户名用逗号分开1
2aid_inet:x:3003:fetasty,root
aid_net_raw:x:3004:fetasty,root
解决 ssh 连接后,无法 tab 补全,无法查看历史命令, 没有颜色显示问题
编辑 /etc/passwd 在对应用户名后将 sh 更改为 bash
1
fetasty:x:60000:60000::/home/fetasty:/bin/bash
编辑~/.bashrc 取消注释其中要显示颜色的行
1
source ~/.bashrc
supervisor 自启动服务配置 (chroot 中的 Linux, systemd, systemctl, service 等命令并不好用,不好设置自启动)
这里我们使用 supervisor 管理其余服务进程, 主要设置好 supervisor 自启动和配置
apt-get install supervisor
安装 supervisor, 用于管理自启动进程 (按照官网的意思,应该使用 pip 安装, 但是我实际使用时并不太顺利)1
2
3
4
5
6
7
8cd ~
# curl -O https://bootstrap.pypa.io/get-pip.py
# python3 get-pip.py # 运行失败, 安装pip失败, 提示应该使用apt install python3-xxx来安装
apt install python3-pip # 安装成功
pip3 config set global.index-url https://pypi.mirrors.ustc.edu.cn/simple
pip3 config list
# pip3 install supervisor # 失败 https://stackoverflow.com/questions/75608323/how-do-i-solve-error-externally-managed-environment-everytime-i-use-pip3
pip3 install supervisor --break-system-packages # 命令行提示最好先venv创建一个环境再安装, 太麻烦了, 不如apt直接装确认容器启动配置中为 sysv, 小米 6 上测试了 run-parts 方式的自启动无效 参考 Linux Deploy 应用自启动
~~nano /etc/init.d/supervisord.sh~~
~~ 编辑 supervisord 应用的启动脚本,该脚本必须按照编写~~规范1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
### BEGIN INIT INFO
# Provides: supervisord
# Required-Start: $network $remote_fs $local_fs
# Required-Stop: $network $remote_fs $local_fs
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: supervisord start
# Description: supervisord run script
### END INIT INFO
/usr/bin/supervisord -c /etc/supervisor/supervisord.conf
exit 0chmod +x /etc/init.d/supervisord.sh
赋予执行权限update-rc.d supervisord.sh defaults
设置开机自启动update-rc.d -f supervisord.sh remove
移除开机自启动
后续发现 apt 安装 supervisor 后,
/etc/init.d
目录下存在一个 supervisor 文件,但是并未成功自启动 (lighttpd 安装后可正常自启动)给该文件添加运行权限
该文件前面有一段注释,不知道是否符合规范 , 删除了
### BEGIN INIT INFO
之前的一段注释执行 update-rc.d 命令
1
2update-rc.d supervisor defaults
update-rc.d supervisor enable
-
1
echo_supervisord_conf > /etc/supervisor/supervisord.conf # 生成配置模板
修改配置,小米 6 上的 supervisord 使用 sock 文件一直有报错, 我修改成了 http 方式,注释了 unix_http_server 部分, 打开了 inet_http_server 部分 (可能与之前的分组有同样关系?)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18;[unix_http_server]
;file=/tmp/supervisor.sock ; the path to the socket file
;chmod=0777 ; socket file mode (default 0700)
;chown=root:root ; socket file uid:gid owner
;username=user ; default is no username (open server)
;password=123 ; default is no password (open server)
[inet_http_server] ; inet (TCP) server disabled by default
port=*:9001 ; ip_address:port specifier, *:port for all iface
;username=user ; default is no username (open server)
;password=123 ; default is no password (open server)
[supervisorctl]
;serverurl=unix:///tmp/supervisor.sock ; use a unix:// URL for a unix socket
serverurl=http://127.0.0.1:9001 ; use an http:// url to specify an inet socket
[include]
files = /etc/supervisor/conf.d/*.conf 设置好 supervisor 的自启动后,stop 再 start, 看命令行中是否有 supervisor 的运行提示,若设置成功, 其余需要自启动的进程就可以交给 supervisor 来管理
supervisord 服务启动后,会监听 9001 端口, 用于控制和查看进程的状态
添加新的进程配置文件后 执行
supervisorctl reload
刷新,再访问 9001 的 http 服务,就可以查看进程状态supervisorctl reload
命令会重启所有管理的进程, 如果只是加载新添加的配置可以运行以下指令1
2supervisorctl reread # 重新读取配置文件
supervisorctl update # 刷新配置到进程组之后可以在 supervisor 管理页面看到对应的进程配置
如果需要配置多个环境变量,可以在 Environment 字段这样填写
1
environment=KEY="val:123",KEY2="val,456"
常用命令
1 | free -h # 查看内存占用 |
5 常用软件
5.1 lighttpd 轻量 Web 服务
1 | apt install lighttpd |
安装完成后已经自动在 /etc/init.d 目录下创建自启动配置,
运行配置在 /etc/lighttpd/lighttpd.conf
,
默认网站路径为 /var/www/html/
默认配置我没有改动,监听 80 端口,主要用于展示一个所有服务的导航页面, 因为且换网络环境时服务器 IP 会变,想弄个方便的导航页, 根据 hostname 值自动调整导航链接
index.html 源码,使用 bootstrap 稍微修饰了一下,其实没啥必要
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
<html lang="en-US">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="shortcut icon" href="#" />
<title>Services List</title>
</head>
<body>
<div class="container">
<h1>Services List</h1>
<div id="services" class="list-group">
</div>
</div>
<script>
let services = [
["Supervisor", 9001, ""],
["Siyuan", 6806, ""],
["Cloudreve", 5212, ""],
["Cloudreve Admin", 5212, "/admin"],
["V2raya", 2017, ""]
];
let container = document.querySelector("#services");
let hostname = window.location.hostname;
let content = "";
services.forEach((service) => {
content += "<a class=\"list-group-item list-group-item-action\" "
+ "target=\"_blank\" "
+ "href=\"http://"
+ hostname + ":"
+ service[1]
+ service[2]
+ "\">"
+ service[0]
+ "</a>\n";
})
container.innerHTML = content;
</script>
<link href="/bootstrap.min.css" rel="stylesheet">
<script src="/bootstrap.bundle.min.js"></script>
</body>
</html>
5.2 开发编译环境
rust 最好开代理安装 参考官网安装说明 (可以参考字节镜像源中的说明安装,无需代理)
1
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
设置 cargo 镜像源 这里使用字节镜像源 , 其实安装也可以参考这里,还可以加快安装速度
编辑
$HOME/.cargo/config
1
2
3
4
5
6
7
8
9
10[source.crates-io]
replace-with = 'rsproxy-sparse'
[source.rsproxy]
registry = "https://rsproxy.cn/crates.io-index"
[source.rsproxy-sparse]
registry = "sparse+https://rsproxy.cn/index/"
[registries.rsproxy]
index = "https://rsproxy.cn/crates.io-index"
[net]
git-fetch-with-cli = truegolang 参考官方文档 , 下载压缩包之后运行对应命令安装 (apt 直接安装的无法正常使用)
- 在
$HOME/.bashrc
中添加export PATH="$PATH:/usr/local/go/bin"
- 在
缓存清理方法 (备份系统前最好先清理缓存)
- golang 清理缓存
go clean -cache
go clean -modcache
可以极大减小$HOME/go
目录大小 - cargo 清理缓存 安装 cargo-cache, 运行 cargo-cache, .rustup 目录貌似无法精简
- yarn 清理缓存
yarn cache clean
极大减小/usr/local/share/.cache/yarn
目录大小
- golang 清理缓存
5.3 cloudreve 网盘
官网下载 arm64 版本二进制运行文件 https://github.com/cloudreve/Cloudreve
创建 /etc/supervisor/conf.d/cloudreve.conf
1 | [program:cloudreve] |
5.4 siyuan 笔记
后端 core 程序编译
siyuan 笔记我只想使用后端服务,使用浏览器访问, 但是官方只提供 docker 方式的服务端部署方式,且只提供了 linux amd64 的包, 需要自己编译
1 | cd /home |
修改 scripts/linux-build.sh
编译脚本
编译 siyuan-kernel, 其中的 GOARCH 需要从 amd64 改为 arm64,
goproxy 可以更改为 https://goproxy.cn
执行 scripts/linux-build.sh
, 编译内核
官网下载对应版本号的 linux.tar.gz, 解压后将 kernel 目录中的 siyuan-kernel 文件替换为我们自己编译生成的二进制文件
创建 /etc/supervisor/conf.d/siyuan.conf
其中的 RUN_IN_CONTAINER
环境变量配置非常重要,
否则它默认以为是客户端模式运行,会定时检测 Electron 前端程序是否存在,
若不存在,则一定时间后自动退出
1 | [program:siyuan] |
前端资源编译
安装 nodejs, 去官网看看包管理器安装方法 , 提示 Debian 的安装可以按照以下方式进行 (参考: https://github.com/nodesource/distributions)
Download and import the Nodesource GPG key
1
2
3
4sudo apt-get update
sudo apt-get install -y ca-certificates curl gnupg
sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | sudo gpg --dearmor -o /etc/apt/keyrings/nodesource.gpgCreate deb repository (
NODE_MAJOR
can be changed depending on the version you need.) 16, 18, 201
2NODE_MAJOR=20
echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_$NODE_MAJOR.x nodistro main" | sudo tee /etc/apt/sources.list.d/nodesource.listRun Update and Install
1
2sudo apt-get update
sudo apt-get install nodejs -yUninstall
1
2
3apt-get purge nodejs &&\
rm -r /etc/apt/sources.list.d/nodesource.list &&\
rm -r /etc/apt/keyrings/nodesource.gpg
我选择了安装 18 的 LTS 版本
设置 npm 镜像源 (后面两个提示不支持,按照下一步操作)
1 | # 设置阿里镜像 |
设置失败可以直接修改文件 nano ~/.npmrc
1 | registry=https://registry.npmmirror.com |
安装 yarn, pnpm
1 | npm install -g yarn |
在 siyuan 根目录运行./scripts/linux-build.sh
即可
5.5 v2raya 代理
安装 v2raya 参考官方文档
1 | # 添加软件源安装 |
下载 v2fly/v2ray-core v2ray-linux-arm64-v8a
编辑 /etc/supervisor/conf.d/v2raya.conf
其中的
--v2ray-bin
选项用于配置 v2ray-core 文件路径
1 | [program:v2raya] |
这里没有设置为自启动,根据需求配置
打开进程后默认监听 2017 端口,访问可以配置选项,"port sharing" 打开后, 可以将代理端口共享到局域网中,供其他设备使用
5.6 code-server
自部署,可以通过浏览器访问的 VS Code
安装参考官方文档
1 | export http_proxy=http://xxxx:xxx |
使用方式参考官方文档
1 | # Replaces "auth: password" with "auth: none" in the code-server config. |
编辑 /etc/supervisor/conf.d/code-server.conf
1 | [program:code-server] |
暴露服务端口,这部分最简单的方式是按照官方提示,使用 SSH Forwarding, 不然比较麻烦,直接暴露 HTTP 端口,使用会提示不安全,且很多功能会失效
1 | # -N disables executing a remote shell |
6 CPU 调度问题探究
使用 lineageos 时关闭屏幕会自动开启 doze 模式,目前只能是 usb 默认文件传输, 接上电脑使用 [或者刷系统看看,honor v10 没有刷 lineageos 没有该问题]
刷回小米的 MIUI 系统并禁用一部分系统应用, 效果还可以
以下内容是探索该问题的一些思路历程
问题定位: https://blog.csdn.net/wenzhi20102321/article/details/130977176
查看安卓日志
1 | adb shell |
注意到以下日志
1 | 09-28 22:22:47.166 1664 1664 I FingerprintManager: onPowerPressed |
可能和 doze 模式打开相关
搜索如何关闭 doze 模式,参考 https://forum.xda-developers.com/t/disable-doze.4407685/, 以及 GPT 中询问 "怎样在 adb 中使用命令禁止 doze 模式"
1 | adb shell dumpsys deviceidle disable # 使用该命令可以禁用doze模式 |
实测在 LinuxDeploy 中设置中打开 Lock screen
和 Wake lock
,
并接通电源使用,可以保持较为流畅的体验,"Kernel
adiutor"并不能解决 CPU" 睡眠 " 问题
实际上打开Lock screen
开关之后,
并不会导致屏幕常亮,而且可以照常锁屏,不会导致睡眠问题
但是打开Lock screen
开关后电量会掉的比较快,
所以使用时打开该开关,待机时关闭该开关即可
(当然,也有可能是将 USB 默认配置改成了文件传输,才让它保持 CPU), 按照上述设置,打开 Lock Screen 但是接手机充电器试试,出现睡眠问题
开发者选项中开启 "Stay awake", 之后关闭屏幕,还是卡顿
参考: https://stackoverflow.com/questions/7617459/how-to-keep-cpu-from-sleeping-when-screen-is-turned-off-in-android
参考: https://developer.android.com/training/scheduling/wakelock
可能是 LinuxDeploy 中的 CPU 锁没有生效
现象:实际使用的时候,
已经在 LinuxDeploy 中打开了 Wifi Lock
和 CPU Wake Lock
,
但是有时候还是发现打开笔记会卡顿,刷新会卡 LOGO 界面,
但是点亮屏幕就会非常快刷新页面,不存在卡顿
这很有可能是 CPU 调度策略引起的问题, 锁屏后 CPU 进入了 "Deep Sleep" 状态
通过以下命令可以看到 CPU 核心的运行情况,但是当卡顿情况发生时, 命令的输入都会变得卡顿
1 | lscpu -e |
注意: 使用 Kernel adiutor 设置后还是无法避免锁屏后手机进入 "睡眠" 模式导致卡顿, 以下内容可以选择性忽略
通过 Kernel adiutor
可以调整 CPU 运行策略
下载地址: https://f-droid.org/en/packages/com.nhellfire.kerneladiutor
在 CPU 选项中,更改 CPU Govemor
以下内容引用自 ChatGPT
1 | Performance(性能): |
可以考虑将小核设置为 Performance, 大核保持 Interactive 不变, 看是否会减少卡顿 (貌似不行)
将大小核都设置为 Performance