Linux Deploy
这是一款借助于安卓的Linux层运行的chroot上类似于容器的一种运行环境。要使用它时必须对手机进行root。
由于root操作在各手机的实际情况不同,这里先暂时略过
GNU/LINUX选择
在安装好Linux Deploy之后,对配置文件进行更改时,可以选择当下流行的多个GNU/LINUX发行版本。这里我只尝试了Ubuntu和Debian,架构选择的arm64架构。
然而Linux Deploy上提供的最新Ubuntu发行版是18.04版本的(代号bionic);因此某些软件没有维护。如果想使用较新的系统的话建议选择Debian(CentOS已经即将停止维护,故不建议)
点击安装操作后,容器进行一段时间的文件下载和安装。等待一段时间后,容器成功挂载(出现 deployed提示后表示装载成功),再点击start便成能启动debian系统。然而Linux Deploy提供的ssh服务有可能会失败,需要通过TELNETD服务进行远程连接,进入5053端口,再进入linuxdeploy su,能连上终端。
在终端内部,进行apt包的修补,然后安装ssh服务。
sudo apt install ssh
等待一段时间的自动下载后,ssh服务下载完毕
输入
service --status-all
进行服务状态的查看,启动ssh服务并自启;默认端口22的ssh端口就可以建立了。
(此时便能断开telnet连接,对22端口进行ssh连接)
Linux Deploy环境下的一些服务部署及操作
由于在chroot环境下,与普通linux环境还是有一点区别,比如systemd就无法正常调用和查看权限(systemctl的一系列命令都会被忽略);目前我在使用中还发现(journalctl系列的)日志也没法正常进行读取和记录;
若要在上述linux环境调用安卓中的命令,可以利用unchroot,比较实用的一个方式就是unchroot /sys/bin/stop和 /sys/bin/start指令,前者能停止安卓层(chroot环境不会停止),使安卓手机变得像砖一样;后者是重启安卓设备(chroot也会重新启动)
假如想写一个脚本控制手机自行进行充电和放电的话,需要寻找手机/system//class/power_supply下是否有相关接口;我的mate9里面就没有,找了半天无法找到相关文件,只好作罢。(自己写充电控制的内容的话可能需要对内核及操作系统进行更改了,暂时没找到解决方案)
10月8日更新:已找到解决方案,请看下文充放电策略
Cpolar
借助cpolar内网穿透工具,便能使设备的设定端口暴露在公网之中。
安装cpolar
官方提供了一个安装cpolar的脚本,我们直接下载下来进行运行即可。
(注意在使用curl之前可能需要先利用apt安装一下curl)
curl -L https://www.cpolar.com/static/downloads/install-release-cpolar.sh | sudo bash
输入
cpolar version
若正常显示相关命令帮助即安装成功。
#再执行以下命令启动服务和开机自启
cpolar service install
cpolar service start
可以再利用以下指令来查看服务是否安装及运行
service --status-all
(若还是不行,可以试一下systemctl enable cpolar)
至此,cpolar服务便成功启动,并且能登陆其官网查看隧道列表。
由于标题写的是免费版,因此cpolar仅提供外部访问的方式,不提供固定域名的手段;这导致我们在外网想访问服务器时可能会遇到域名变化等不方便问题。我在下文中给出了我自己的解决方案。
cpolar服务自启时会固定开设3条通道,我们只需关注那条映射到tcp的ssh通道。
我利用python,写了一个简易的脚本,用来获取当前系统开放的ssh链接的公网通道。
然后利用一个固定域名,其中利用它的TXT Record,使得随时能通过解析这个固定域名来获得动态的cpolar域名;
具体脚本不再给出,避免该方法失效。
(更好的方法)公网IPV6地址
最让我苦恼的便是没有办法直接访问任一设备,但ipv6解决了这一困境。我在偶然间尝试了一下,发现ipv6是多么地令人舒适,唯一可惜的是有一小部分软件还不太兼容。在路由器配置好Ipv6相关设置,配置防火墙规则后,便能直接访问手机。这里又遇到了新的问题:
尽管我将华为手机的"休眠时不断开网络连接"选项打开了,但它仅仅对ipv4生效(我在内网以及cpolar方法随便连接手机服务器,但在外网ipv6非常容易断开连接,且短时间无法再连上。后来经排查是手机休眠策略的问题)。于是我便思考起如何使手机“不休眠“,或者保证ipv6连接不断。
最后发现有大佬提议的unchroot stop指令,能将安卓层的一切都关闭(手机变成跟砖一样了,但ssh还能连接),这里又有个问题:如果我在关屏状态下stop手机的话,后台还是执行的省电策略,依然达不到我想要的效果;如果我在开屏状态下stop的话,屏幕就一直不会关,会锁死在stop前的最后一刻(电源键、屏幕触摸都没反应,用adb关屏也没用,会显示被Kill了)
经过折腾,我发现了/sys/class/leds/lcd_backlight0/brightness这个文件,在开屏stop的情况下,利用echo向其输入0
echo 0 > /sys/class/leds/lcd_backlight0/brightness
手机屏幕立刻变成黑屏状态,我们的目标也就达成了。(这个不是假黑屏,不是那种下个app设置黑壁纸,调低亮度的那种,是一点亮都没有)完成
25年1月28日更新
上述状态下,虽说能够保证一段时间的网络连接;但由于关闭了安卓层,使得安卓自带的wifi检测与连接也随之下线。一旦网络出现错误/租期到期,便会导致手机断开连接,无法访问。经过一两个多月的实际调试与纠误,终于发现了一个稳定的解决方案。
我的mate9自带的方案是基于安卓层的wpa_supplicant来控制的。从容器中访问的wpa_cli是无法连接的。因此,一旦失去连接,我们应在容器内配置一个相应的wpa_supplicant。
1.安装wpa_supplicant
输入apt install wpa_suppplicant
,便能安装相关工具。
2.配置wpa_supplicant.conf
编辑/etc/wpa_supplicant.conf文件,新建一个network块,将sid设置为wifi名称,将psk设置为wifi密码。
3.运行wpa_supplicant
紧接着,将华为自带的wpa_supplicant kill掉。(两种方法,1.先ps -aux | grep wpa_supplicant,观察pid,然后利用kill指令即可;2.直接调用killall wpa_supplicant)随后,再调用wpa_supplicant指令。我这里的指令是wpa_supplicant -i wlan0 -c /etc/wpa_supplicant.conf
,便能成功运行。随后,为了动态获得准确的ip地址,可以调用dhclient指令,来获得相应的ip地址。
编写自动连接脚本
新建checkWlanStatus.sh,并在其中输入以下代码
#!/bin/bash
INTERFACE="wlan0"
LOG_FILE="/server/logs/wifi-monitor.log"
echo "[$(date)] Checking network......" >> $LOG_FILE
if ! ping -c 1 8.8.8.8 &> /dev/null; then
echo "[$(date)] Network down! Restarting wpa_supplicant..." >> $LOG_FILE
killall wpa_supplicant
wpa_supplicant -B -i $INTERFACE -c /etc/wpa_supplicant/wpa_supplicant.conf -D nl80211
dhclient -v $INTERFACE >> $LOG_FILE 2>&1
fi
这样的话,一旦无法访问互联网,就会尝试重启wpa_supplicant服务,并连接相应wifi。
自动充放电策略
经过折腾,网上的大部分教程也试过,一开始没找到Mate9的充电控制开关;后来找到后向其输入参数却发现无效;最终与上方关掉安卓层后猛然发现,居然修改有用了。
文件地址是:/sys/class/hw_power/charger/charge_data/enable_charger
一定要确保安卓层关闭的情况下修改文件才有用,若不关闭的话,你在插入了充电线的状态下他会自行不停地变成1
crsf
自动登录脚本的开发过程中,会遇到crsf验证。一般的crsf验证有两种,第一种存在于响应头的set-cookie当中;第二种存在于网页当中提交表单的地方,一般是隐藏在meta之中的。
Crontab
linux中自带有定时任务,其中crontab便是定时任务的管理者。对于它的配置和格式便不再赘述,主要讲一下我踩的坑:
当你通过定时运行脚本文件时,一定要注意脚本里面写的命令需要标注好绝对路径,不能携程相对路径:第一次被坑就是写的相对路径,结果找半天找不到错,日志文件(journalctl)在linux deploy的环境下为空,使得我久久不能定位错误。直到看到某位博主写的文章,才解答了我的困惑之处:脚本下写相对路径是可以的,执行的时候他会自动到该目录下执行;可是利用cron进行执行时,他会在cron的运行目录下进行相对路径的寻找,最终便失败了。
还有几个需要注意的点
1.在bash脚本中,if条件控制语句的语法是
if [ 条件1 ] ; then
第一个代码块
elif [ 条件2 ] ; then
第二个代码块
else
第三个代码块
fi
问题就出在[条件1]中,首先,单独的一个中括号是不支持==、>=、<=这些符号的,相对应的,应该是-eq、-ge、-le。其次,在条件1中,要与前后的中括号隔开,并不能写在一起。这个坑卡了我有半个小时。
Docker
有时候在想,是不是有些繁琐的配置和安装操作令人恼怒,想引入docker来解决这个问题。遗憾的是,安卓系统的内核是阉割版的linux系统,就算是借助了linux deploy,也无法解决安卓环境下内核缺失的功能。在借助docker官方提供的一个教程之后,我们可以得到一个脚本,能查看自己手机上缺失的功能。在折腾了一段时间后,我明白需要自己编译一个相应机型的内核并进行刷入。但我暂时没在网上找到mate9对应的OS内核,我就没多倒腾了。如果想要在安卓上装docker的话需要去再参考一下其他博主的文章,理论上是可行的。
番外篇:
由于华为已经在18年关闭了获取root权限的通道,所以通过一般手段自行解bl及root较为困难,可以在pdd或tb寻求大哥帮助。经过我自己的一番折腾,把手机干成砖了。。最后还得是通过短接进入高通9008模式,再刷入recovery及ROM,重新恢复系统的。尝试自行root和解bl锁之前建议有一定刷机基础,以及请做好备份和线刷的准备。
刷入内核(9.26日更新)
折腾过程中,在网上找到一个盘古麒麟960内核,基于它的源码,利用 make menuconfig
将docker的依赖模块打开,然后编译内核并进入手机的fastboot模式,用fastboot flash kernel ***.img
刷入手机。经过多次的测试和编译,在上述必要的模块之中,一旦打开bridge_netfilter配置手机就无法开机。因此docker会有莫名奇妙的问题。且一旦打开后续可选项服务时,编译也会出问题…
经过一些手段之后,dockerd能够有报错地程序启动。但在执行docker run hello-world
测试程序时却又开始报cgroup的错。折腾来折腾去,也不知道哪个地方什么服务没开,或者哪个地方没挂载好;手机也非常不稳定,一时半会儿就要重启一下,重启之后还会导致root失效,又得重新root一下…总之试错成本太高,且进展不顺利,只好暂时放弃搭建docker的做法(如果机型是其他品牌如小米可能会更开放一点,网上也有质量更加可靠的内核或操作系统的版本来选择,估计成功率会高点)
QEMU
既然docker不行,而有的程序并没有开发arm版本;因此考虑使用qemu来进行x86的模拟,并在这上面安装软件,再测试一下性能。经过一番折腾,下载了alpine虚拟机,并成功运行;美中不足的是hostfwd不支持ipv6端口转发,性能也会受到很大的损失。
折腾的结局(9.28日更新)
经过大量时间的内核编译和反复尝试刷入,终于发现华为的服务有个HW_NETFILTER_MODULE的模块,将它关闭之后才能正确打开bridge_netfilter模块…
最终成功开机,并挂载cgroup;docker也能正常开启服务了。
运行一下hello-world试试水
成功运行。
可是有出现了新的问题,刷入内核后的系统非常不稳定,用着用着就重启一下,特别是当docker开启一些特定的服务时最严重。可能还是需要去看看日志进行debug吧,先溜了(逃)