vlambda博客
学习文章列表

编程开发,用个安卓手机当linux服务器就行

旧的安卓手机不要扔,可以拿来做一个微型的linux服务器,编程开发,跑服务都不在话下!本文就以6年前发布的小米2s为例,亲自带大家一起体验一下这种手机服务器并简单分析其中的一些原理。

一、升级最新安卓操作系统

像小米2s这样已经发布6年多的手机,配置已经不够用了。但是我们知道,谷歌每年发布的新安卓系统版本都有性能的优化,所以旧手机如果能升级系统,自然也能改善性能。工欲善其事必先利其器,我们先把旧手机升级一把再说。

魔趣ROM介绍

编程开发,用个安卓手机当linux服务器就行

这是一个国内团队维护ROM,开源并且支持多款安卓设备。最主要的是他跟随谷歌的脚步,当有新的安卓版本发行后,魔趣ROM很快就能为多款安卓设备适配。

例如我的小米2s手机,选品牌和型号

编程开发,用个安卓手机当linux服务器就行

选安卓的版本,我选的是8.1版本:

编程开发,用个安卓手机当linux服务器就行

怎么刷机不是我们关注的重点,需要的请到魔趣论坛或百度搜索。刷机后,我那6年前的破手机用上了androd 8.1:

编程开发,用个安卓手机当linux服务器就行

魔趣ROM的是开源的,这意味着:只要我们愿意,随时可以下载代码下来定制自己的ROM,这非常符合开发人员的胃口!

二、将安卓手机打造成linux服务器

理解linux与安卓的关系

  • 首先,安卓操作系统的内核是基于linux的,谷歌为安卓系统做了特殊的定制,如增加了binder驱动,适合手机的电源管理驱动,Low Memory Killer驱动等等。

  • 其次,安卓系统和普通的linux的libc库不一样,可执行程序需要专门的android编译器(arm-linux-androideabi-gcc/g++)编译,用专门的链接器(arm-linux-androideabi-ld)链接专用于安卓的libc.so才能运行。

为什么我们只关注C/C++,不是有那么多语言编写的程序吗?

因为c/c++是基础,离开它们基本没什么能跑的了。java虚拟机是c++编写的,python的解析器是c写的,js的解析执行引擎也是c/c++写的。。。

本文的主角---termux简介

termux 是一个安卓平台下的app, 它能够在安卓上实现一个微型的linux,具有命令行界面,可以以apt方式简单的安装各种软件。

termux的安装与使用

软件下载地址

https://f-droid.org/packages/com.termux/

软件界面

软件安装后,在手机上展现的界面如下所示,与我们平时操作的linux终端长得一样:

编程开发,用个安卓手机当linux服务器就行

安装openssh,并从PC端访问

终端界面在手机上操作不方便,所以我们安装一个ssh服务,然后用PC来操作它。

  1. 更新软件源

1apt update
  1. 安装openssh-server

1pkg install openssh
  1. 给termux对应的用户设置一个密码

1$passwd
2
3#
根据提示设置一个密码
4New password:
  1. 安装后,需要手动启动sshd

1sshd &

注意:termux的ssh服务默认端口为8022

  1. 测试连接

在PC端,我在windows上用secure crt连接手机的sshd,设置端口为8022,连接似成功的。连接成功后,你就真正拥有一个微型的linux服务器,可以将手机息屏,为所欲为啦。

编程开发,用个安卓手机当linux服务器就行

termux的简单分析

termux在android系统中运行,与普通的app没有什么两样,在apk安装时,系统为其分配一个用户,例如我的分配的用户为u0_a79。我在手机上点击termux这个app后,其实termux会以u0_a79这个用户身份创建一个新的bash进程,然后所有的命令都在这个bash进程里解析执行。

在termux的界面输入export命令,结果如下:

 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"
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"

我们就可以看到如下端倪:

  1. 当前shell其实为

    /data/data/com.termux/files/usr/bin/bash

  2. 当前用户为u0_a79,与安卓系统给termux 分配的的uid一致。

  3. LD_LIBRARY_PATH为

    /data/data/com.termux/files/usr/lib,当前shell执行的程序链接的是termux自己的库文件,与安卓系统/system/lib下的无关。

  4. LD_PRELOAD加入了一个libtermux-exec.so,说明应该termux hook了一些系统API接口。

  5. PATH环境变量不包含/system/bin目录,所有命令都与android系统自带的命令了无关,termux的shell是一个独立的shell环境。

    termux shell里也有am等android命令,但是它自带的,与用/system/bin下的am无关。

  6. HOME目录为

    /data/data/com.termux/files/home

通过ps命令,我们就可以更清楚的知道,它其实是termux 创建的一个子进程:

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,编译器应该是arm-linux-androideabi-gcc/g++。

三、玩termux

打造个人编程环境

我们已经拥有一个微型linux服务器了,现在我们尝试在里边编程开发。

安装c/c++编译器:

1apt install clang

测试

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的编译器。经过测试,用这个编译器编译的程序是可以直接放到android shell中执行的。

经过测试,c、c++、python、node.js等语言在这个微型服务器里都正常运行;搭建tomcat之类的服务也没问题。

如何打造java编程环境?

从前面的分析我们知道,termux shell和android shell一样,执行java字节码的是ART虚拟机,而不是普通的java虚拟机,所以javac编译的.class是无法运行的。

如果一定要执行java字节码,需要通过dx工具将字节码转换成dex文件,然后art虚拟机才能执行。

 1#termux下不能用openjdk,可以用ecj
2apt install ecj
3#adroid的.class转.dex工具
4apt install dx
5
6apt install termux-tools
7
8#
编译
9ecj HelloWorld.java
10dx --dex --output=HelloWorld.dex HelloWorld.class
11
12#
执行
13#参照/system/bin/pm 的内容执行即可

很多人肯定会说,这个java环境不爽。那么想打造一个像普通服务器那样的java环境怎么做呢,可以“安装”一个操作系统,后边会介绍。

如何在PC与termux之间传输文件?

我们在服务器内写代码,都在/data/data/com.termux/files/home这个目录里,手机没有root的话,我们是无法访问这个目录的。 我本来想安装一个samba服务器,发现没有这个软件包,所以只能借助网络传输文件:

通过scp工具(windows下用winscp)传输文件,虽然没有直接用samba那么方便但起码可用。

编程开发,用个安卓手机当linux服务器就行

在termux中“安装”ubuntu

termux的linux环境对很多人来说基本是够用的,但是依然是一种android定制版linux,与普通嵌入式linux系统还是有差异的,例如没有普通的java虚拟机

下面介绍如何在termux shell里搭建一个ubuntu系统环境:

安装wget

用于下载文件

1pkg install wget
安装proot

在linux中,chroot是一个需要root权限的操作,它允许将当前根文件系统切换到另外一个目录。

例如手机中的进程对应的根目录为/,  我们弄一个/data/local/tmp/xxxx文件夹, 里边有ubuntu的根文件系统,我们chroot到这个文件夹后,在shell界面里看到的/则切换到/data/local/tmp/xxxx了。

我们说的安装ubuntu其实只是chroot到一个ubuntu的根文件系统文件夹里而已。

proot是一个无需root权限就能执行chroot操作的工具。用于在ubuntu里模拟需要sudo的权限(否则没法安装软件)。

1pkg install proot
下载atilo脚本
1wget https://raw.githubusercontent.com/YadominJinta/atilo/master/atilo
下载ubuntu根文件系统并chroot
1chmod +x ./atilo
2./atilo install ubuntu
3
4#
这个命令会执行proot,chroot到所下载的ubuntu根文件系统
5startubuntu

执行startubuntu后,根目变到 --> data/data/com.termux/files/home/.atilo/ubuntu去了, 我们就感觉进入了ubuntu系统了。

我们再来对比一下这个ubuntu shell与termux shell不一样的地方:

  • termux shell里,根目录与android的是一样的,你还可以访问/system, /sdcard目录等原始android系统目录

  • startubuntu后,就像执行了chroot操作一样,根目录都变了,已经看不到/system 这种分区了(除非mount --bind过来)。

简单分析和测试我们“安装”的这个ubuntu系统

  1. 这个系统用的是通用的libc,android系统下的可执行程序无法在这个系统中运行。

    我们可以通过查看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了。

  2. 我们并没有以root身份运行

通过shell界面我们看到,我们似乎在以root权限运行,但是其实是模拟出来的,所以你别想写个内核模块安装到真正的内核里边去。

  1. 在ubuntu中,运行sshd, samba都失败了

    sshd进程一运行就没了,通过gdb运行我们发现它其实段错误了:

    同样,smbd进程也奔溃了,报了一个无权限bind socket的错误。

似乎这种chroot后的系统没有直接用termux稳定。对于已经root的系统,可能不需要proot,也许兼容性会更好,感兴趣的可以自行进行尝试。

  1. samba服务没法用让我很失望,但其日志中报的socket bind权限问题是怎么回事?

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

经过验证,自己写一个tcp server运行是没有问题的,只是不支持SO_REUSEPORT这个套接字选项。但是ubuntu系统中绑定的端口号与实际在android中的端口是不一样的,具体的端口号需要到外部termux的shell才能看出来。

例如:我在ubuntu shell中写了一个服务,监听的是9999端口,而你外部要访问这个服务时,确要连接3456端口。

四、写在最后

通过亲自体验,在小米2s上使用termux基本能满足对一个微型linux服务器的需求,我甚至想在我的新手机上也弄一个。对于需要用ndk编译android native可执行程序的人来说,直接在android中编译程序并立马可以执行,而不需要每次adb push到机器里,也是非常不错的体验。

termux拥有比较完备的软件源,开发环境支持得很完善,可玩性非常高。随着arm芯片的性能的不断提升,运行内存都赶超PC了,完全可以把你的手机当成一个随身linux服务器,推荐喜爱技术的朋友去尝试一下。