作者:admin 日期:2023-09-12 瀏覽: 次
編程開發(fā),用個(gè)安卓手機(jī)當(dāng)linux服務(wù)器就行
舊的安卓手機(jī)不要扔,可以拿來做一個(gè)微型的linux服務(wù)器,編程開發(fā),跑服務(wù)都不在話下!本文就以6年前發(fā)布的小米2s為例,親自帶大家一起體驗(yàn)一下這種手機(jī)服務(wù)器并簡(jiǎn)單分析其中的一些原理。
像小米2s這樣已經(jīng)發(fā)布6年多的手機(jī),配置已經(jīng)不夠用了。但是我們知道,谷歌每年發(fā)布的新安卓系統(tǒng)版本都有性能的優(yōu)化,所以舊手機(jī)如果能升級(jí)系統(tǒng),自然也能改善性能。工欲善其事必先利其器,我們先把舊手機(jī)升級(jí)一把再說。
魔趣ROM介紹
這是一個(gè)國(guó)內(nèi)團(tuán)隊(duì)維護(hù)ROM,開源并且支持多款安卓設(shè)備。最主要的是他跟隨谷歌的腳步,當(dāng)有新的安卓版本發(fā)行后,魔趣ROM很快就能為多款安卓設(shè)備適配。
魔趣ROM下載地址:https://download.mokeedev.com/,需要的朋友可根據(jù)自己的手機(jī)型號(hào)選擇下載并刷機(jī)使用。
例如我的小米2s手機(jī),選品牌和型號(hào)
選安卓的版本,我選的是8.1版本:
怎么刷機(jī)不是我們關(guān)注的重點(diǎn),需要的請(qǐng)到魔趣論壇或百度搜索。刷機(jī)后,我那6年前的破手機(jī)用上了androd 8.1:
魔趣ROM的是開源的,這意味著:只要我們?cè)敢猓S時(shí)可以下載代碼下來定制自己的ROM,這非常符合開發(fā)人員的胃口!
理解linux與安卓的關(guān)系
首先,安卓操作系統(tǒng)的內(nèi)核是基于linux的,谷歌為安卓系統(tǒng)做了特殊的定制,如增加了binder驅(qū)動(dòng),適合手機(jī)的電源管理驅(qū)動(dòng),Low Memory Killer驅(qū)動(dòng)等等。
其次,安卓系統(tǒng)和普通的linux的libc庫(kù)不一樣,可執(zhí)行程序需要專門的android編譯器(arm-linux-androideabi-gcc/g++)編譯,用專門的鏈接器(arm-linux-androideabi-ld)鏈接專用于安卓的libc.so才能運(yùn)行。
為什么我們只關(guān)注C/C++,不是有那么多語言編寫的程序嗎?
因?yàn)閏/c++是基礎(chǔ),離開它們基本沒什么能跑的了。java虛擬機(jī)是c++編寫的,python的解析器是c寫的,js的解析執(zhí)行引擎也是c/c++寫的。。。
本文的主角---termux簡(jiǎn)介
termux 是一個(gè)安卓平臺(tái)下的app, 它能夠在安卓上實(shí)現(xiàn)一個(gè)微型的linux,具有命令行界面,可以以apt方式簡(jiǎn)單的安裝各種軟件。
termux的安裝與使用
軟件下載地址
https://f-droid.org/packages/com.termux/
軟件界面
軟件安裝后,在手機(jī)上展現(xiàn)的界面如下所示,與我們平時(shí)操作的linux終端長(zhǎng)得一樣:
安裝openssh,并從PC端訪問
終端界面在手機(jī)上操作不方便,所以我們安裝一個(gè)ssh服務(wù),然后用PC來操作它。
更新軟件源
1apt update
安裝openssh-server
1pkg install openssh
給termux對(duì)應(yīng)的用戶設(shè)置一個(gè)密碼
1$passwd
2
3#根據(jù)提示設(shè)置一個(gè)密碼
4New password:
安裝后,需要手動(dòng)啟動(dòng)sshd
1sshd &
注意:termux的ssh服務(wù)默認(rèn)端口為8022
測(cè)試連接
在PC端,我在windows上用secure crt連接手機(jī)的sshd,設(shè)置端口為8022,連接似成功的。連接成功后,你就真正擁有一個(gè)微型的linux服務(wù)器,可以將手機(jī)息屏,為所欲為啦。
termux的簡(jiǎn)單分析
termux在android系統(tǒng)中運(yùn)行,與普通的app沒有什么兩樣,在apk安裝時(shí),系統(tǒng)為其分配一個(gè)用戶,例如我的分配的用戶為u0_a79。我在手機(jī)上點(diǎn)擊termux這個(gè)app后,其實(shí)termux會(huì)以u(píng)0_a79這個(gè)用戶身份創(chuàng)建一個(gè)新的bash進(jìn)程,然后所有的命令都在這個(gè)bash進(jìn)程里解析執(zhí)行。
在termux的界面輸入export命令,結(jié)果如下:
1$ export
2declare -x ANDROID_DATA="/data"
3declare -x ANDROID_ROOT="/system"
4declare -x EXTERNAL_STORAGE="/sdcard"
5declare -x HOME="/data/data/com.termux/files/home"
鹽城數(shù)據(jù)恢復(fù) 6declare -x LANG="en_US.UTF-8"
7declare -x LD_LIBRARY_PATH="/data/data/com.termux/files/usr/lib"
8declare -x LD_PRELOAD="/data/data/com.termux/files/usr/lib/libtermux-exec.so"
9declare -x LOGNAME="u0_a79"
10declare -x OLDPWD
11declare -x PATH="/data/data/com.termux/files/usr/bin:/data/data/com.termux/files/usr/bin/applets"
12declare -x PREFIX="/data/data/com.termux/files/usr"
13declare -x PWD="/data/data/com.termux/files/home"
14declare -x SHELL="/data/data/com.termux/files/usr/bin/bash"
15declare -x SHLVL="1"
16declare -x TERM="vt100"
17declare -x USER="u0_a79"
我們就可以看到如下端倪:
當(dāng)前shell其實(shí)為
/data/data/com.termux/files/usr/bin/bash
當(dāng)前用戶為u0_a79,與安卓系統(tǒng)給termux 分配的的uid一致。
LD_LIBRARY_PATH為
/data/data/com.termux/files/usr/lib,當(dāng)前shell執(zhí)行的程序鏈接的是termux自己的庫(kù)文件,與安卓系統(tǒng)/system/lib下的無關(guān)。
LD_PRELOAD加入了一個(gè)libtermux-exec.so,說明應(yīng)該termux hook了一些系統(tǒng)API接口。
PATH環(huán)境變量不包含/system/bin目錄,所有命令都與android系統(tǒng)自帶的命令了無關(guān),termux的shell是一個(gè)獨(dú)立的shell環(huán)境。
termux shell里也有am等android命令,但是它自帶的,與用/system/bin下的am無關(guān)。
HOME目錄為
/data/data/com.termux/files/home
通過ps命令,我們就可以更清楚的知道,它其實(shí)是termux 創(chuàng)建的一個(gè)子進(jìn)程:

1```shell
2$ ps
3PID USER TIME COMMAND
429893 u0_a79 0:00 /data/data/com.termux/files/usr/bin/bash -l
5```
因此我們可以確定:
termux的shell是與/system/bin/下的程序一樣,用的都是android的libc,編譯器應(yīng)該是arm-linux-androideabi-gcc/g++。
打造個(gè)人編程環(huán)境
我們已經(jīng)擁有一個(gè)微型linux服務(wù)器了,現(xiàn)在我們嘗試在里邊編程開發(fā)。
安裝c/c++編譯器:
1apt install clang
測(cè)試
1$ gcc -v
2clang version 8.0.0 (tags/RELEASE_800/final)
3Target: arm-unknown-linux-android
4Thread model: posix
5InstalledDir: /data/data/com.termux/files/usr/bin
可以看到打印的arm-unknown-linux-android,的確就是android的編譯器。經(jīng)過測(cè)試,用這個(gè)編譯器編譯的程序是可以直接放到android shell中執(zhí)行的。
經(jīng)過測(cè)試,c、c++、python、node.js等語言在這個(gè)微型服務(wù)器里都正常運(yùn)行;搭建tomcat之類的服務(wù)也沒問題。
如何打造java編程環(huán)境?
從前面的分析我們知道,termux shell和android shell一樣,執(zhí)行java字節(jié)碼的是ART虛擬機(jī),而不是普通的java虛擬機(jī),所以javac編譯的.class是無法運(yùn)行的。
如果一定要執(zhí)行java字節(jié)碼,需要通過dx工具將字節(jié)碼轉(zhuǎn)換成dex文件,然后art虛擬機(jī)才能執(zhí)行。
1#termux下不能用openjdk,可以用ecj
2apt install ecj
3#adroid的.class轉(zhuǎn).dex工具
4apt install dx
5
6apt install termux-tools
7
8#編譯
9ecj HelloWorld.java
10dx --dex --output=HelloWorld.dex HelloWorld.class
11
12#執(zhí)行
13#參照/system/bin/pm 的內(nèi)容執(zhí)行即可
很多人肯定會(huì)說,這個(gè)java環(huán)境不爽。那么想打造一個(gè)像普通服務(wù)器那樣的java環(huán)境怎么做呢,可以“安裝”一個(gè)操作系統(tǒng),后邊會(huì)介紹。
如何在PC與termux之間傳輸文件?
我們?cè)诜?wù)器內(nèi)寫代碼,都在/data/data/com.termux/files/home這個(gè)目錄里,手機(jī)沒有root的話,我們是無法訪問這個(gè)目錄的。 我本來想安裝一個(gè)samba服務(wù)器,發(fā)現(xiàn)沒有這個(gè)軟件包,所以只能借助網(wǎng)絡(luò)傳輸文件:
通過scp工具(windows下用winscp)傳輸文件,雖然沒有直接用samba那么方便但起碼可用。
在termux中“安裝”ubuntu
termux的linux環(huán)境對(duì)很多人來說基本是夠用的,但是依然是一種android定制版linux,與普通嵌入式linux系統(tǒng)還是有差異的,例如沒有普通的java虛擬機(jī)。
下面介紹如何在termux shell里搭建一個(gè)ubuntu系統(tǒng)環(huán)境:
安裝wget
用于下載文件
1pkg install wget
安裝proot
在linux中,chroot是一個(gè)需要root權(quán)限的操作,它允許將當(dāng)前根文件系統(tǒng)切換到另外一個(gè)目錄。
例如手機(jī)中的進(jìn)程對(duì)應(yīng)的根目錄為/, 我們弄一個(gè)/data/local/tmp/xxxx文件夾, 里邊有ubuntu的根文件系統(tǒng),我們chroot到這個(gè)文件夾后,在shell界面里看到的/則切換到/data/local/tmp/xxxx了。
我們說的安裝ubuntu其實(shí)只是chroot到一個(gè)ubuntu的根文件系統(tǒng)文件夾里而已。
proot是一個(gè)無需root權(quán)限就能執(zhí)行chroot操作的工具。用于在ubuntu里模擬需要sudo的權(quán)限(否則沒法安裝軟件)。
1pkg install proot
下載atilo腳本
1wget https://raw.githubusercontent.com/YadominJinta/atilo/master/atilo
下載ubuntu根文件系統(tǒng)并chroot
1chmod +x https://mp.weixin.qq.com/atilo
2https://mp.weixin.qq.com/atilo install ubuntu
3
4#這個(gè)命令會(huì)執(zhí)行proot,chroot到所下載的ubuntu根文件系統(tǒng)
5startubuntu
執(zhí)行startubuntu后,根目變到 --> data/data/com.termux/files/home/.atilo/ubuntu去了, 我們就感覺進(jìn)入了ubuntu系統(tǒng)了。
我們?cè)賮韺?duì)比一下這個(gè)ubuntu shell與termux shell不一樣的地方:
termux shell里,根目錄與android的是一樣的,你還可以訪問/system, /sdcard目錄等原始android系統(tǒng)目錄
startubuntu后,就像執(zhí)行了chroot操作一樣,根目錄都變了,已經(jīng)看不到/system 這種分區(qū)了(除非mount --bind過來)。
簡(jiǎn)單分析和測(cè)試我們“安裝”的這個(gè)ubuntu系統(tǒng)
這個(gè)系統(tǒng)用的是通用的libc,android系統(tǒng)下的可執(zhí)行程序無法在這個(gè)系統(tǒng)中運(yùn)行。
我們可以通過查看gcc的版本:
1root@localhost:~/workspace# gcc -v
2Using built-in specs.
3COLLECT_GCC=gcc
4COLLECT_LTO_WRAPPER=/usr/lib/gcc/arm-linux-gnueabihf/8/lto-wrapper
5Target: arm-linux-gnueabihf
可見用的是arm-linux-gnueabihf,而不是arm-linux-androideabi了。
我們并沒有以root身份運(yùn)行
通過shell界面我們看到,我們似乎在以root權(quán)限運(yùn)行,但是其實(shí)是模擬出來的,所以你別想寫個(gè)內(nèi)核模塊安裝到真正的內(nèi)核里邊去。
在ubuntu中,運(yùn)行sshd, samba都失敗了
sshd進(jìn)程一運(yùn)行就沒了,通過gdb運(yùn)行我們發(fā)現(xiàn)它其實(shí)段錯(cuò)誤了:
同樣,smbd進(jìn)程也奔潰了,報(bào)了一個(gè)無權(quán)限bind socket的錯(cuò)誤。
似乎這種chroot后的系統(tǒng)沒有直接用termux穩(wěn)定。對(duì)于已經(jīng)root的系統(tǒng),可能不需要proot,也許兼容性會(huì)更好,感興趣的可以自行進(jìn)行嘗試。
samba服務(wù)沒法用讓我很失望,但其日志中報(bào)的socket bind權(quán)限問題是怎么回事?
1[2019/05/23 01:00:34.679242, 0] /source3/lib/util_sock.c:357(open_socket_in)
2 open_socket_in(): setsockopt: SO_REUSEPORT = true on port 139 failed with error = Protocol not available
3[2019/05/23 01:00:34.680860, 0] /source3/lib/util_sock.c:396(open_socket_in)
4 bind failed on port 139 socket_addr = 0.0.0.0.
5 Error = Permission denied
經(jīng)過驗(yàn)證,自己寫一個(gè)tcp server運(yùn)行是沒有問題的,只是不支持SO_REUSEPORT這個(gè)套接字選項(xiàng)。但是ubuntu系統(tǒng)中綁定的端口號(hào)與實(shí)際在android中的端口是不一樣的,具體的端口號(hào)需要到外部termux的shell才能看出來。
例如:我在ubuntu shell中寫了一個(gè)服務(wù),監(jiān)聽的是9999端口,而你外部要訪問這個(gè)服務(wù)時(shí),確要連接3456端口。
通過親自體驗(yàn),在小米2s上使用termux基本能滿足對(duì)一個(gè)微型linux服務(wù)器的需求,我甚至想在我的新手機(jī)上也弄一個(gè)。對(duì)于需要用ndk編譯android native可執(zhí)行程序的人來說,直接在android中編譯程序并立馬可以執(zhí)行,而不需要每次adb push到機(jī)器里,也是非常不錯(cuò)的體驗(yàn)。
termux擁有比較完備的軟件源,開發(fā)環(huán)境支持得很完善,可玩性非常高。隨著arm芯片的性能的不斷提升,運(yùn)行內(nèi)存都趕超PC了,完全可以把你的手機(jī)當(dāng)成一個(gè)隨身linux服務(wù)器,推薦喜愛技術(shù)的朋友去嘗試一下。
歡迎關(guān)注我們的公眾號(hào)