Android模拟器知识以及改造

1. 我们做了个什么东西?

   提供了一个Android模拟器,运行流畅度可以类比真机,可以正常运行市面上的大部分应用,比如应用宝,手机管家等。在功能性测试的场景下,比真机节约成本,维护更方便。

 

2. 原生安卓模拟器的缺点?

Android模拟器慢其实是指早期Google提供的只能用于在Arm架构上运行的Android镜像在模拟器上运行慢。与此对照的是,iOS模拟器运行非常流畅。其实,iOS提供的叫 Simulator(模拟器),Android提供的叫Emulator(仿真器)。

事实上 iOS Simulator 仅仅是 API 级别的模拟,并不是完整的运行了一个系统,可以说 iOS Simulator 就是一个特殊的软件,通过一定的 IPC 机制实现的一个高度模拟 iOS Mac app。可以作为验证的是,iOS Simulator上只是能够运行在x86环境下编译的非签名程序(Developer Account),并不能安装发布到App Store上的只提供了针对ARM指令集的签名程序。

Android Emulator,是提供了虚拟机。从硬件(主要指 CPU 架构)到软件(完整 Linux 内核和 ROM)在原理上完全拟真。

对于ARM 版的Android镜像在Emulator上运行,需要Emulator模拟出一个arm的处理器,可以想象,系统本来是针对ARM指令集的,所有的指令都需要虚拟机模拟出来的arm处理器执来执行,效率必然打了很大折扣,所以就慢了。

后来,Google提供了x86版本的Android镜像,这时候就不用模拟异构处理器了,也就不用去做动态指令集翻译的活了,借助KVMlinux内核模块,属于硬件虚拟化技术,负责借助于硬件VT加速特性实现虚拟机的CPU虚拟化,内存虚拟化等),运行速度就大大加快了,在主机性能良好的情况下,Emulator流程程度甚至比真机还要好。但是,实际使用的话,会发现市面上大部分应用是安装不进去的。

因为习惯上都叫Android模拟器,所以后面描述里的Emulator、模拟器、仿真器不再区分,都是指Android Emulator。   

 

2.  模拟器的启动流程?

AS提供了AVD Manager可以可视化的管理模拟器的创建创建和启动。

创建过程里需要指定使用的Android镜像(分arm版和x86版),选择arm版时AS会提示选择x86版本能提高10倍的性能。还可以设定分辨率、数据分区大小等。这些设定会创建一个config.ini的配置文件和设定大小的userdata.imgsdcard.imgconfig.ini里配置了系统镜像的路径system.img.

查看下载的镜像文件夹,除了system.img, 还有一个很重要的文件ramdisk.img, ramdisk是根文件系统,包含一些对于启动android很重要的文件,比如内核启动完后加载的第一个进程init、一些重要的配置文件等,总之它控制着整个android的启动。根据 init.rc, init.ranchu.rc来初始化并装载系统库、程序等直到开机完成。system.img会挂载到/system目录下。userdata.img是用来存放用户数据的,会被挂载到/data目录下,实际在虚拟机运行时,生成使用的是userdata-qemu.img,可读写。当在模拟器上安装和运行应用时,就是在/data目录下复制和产生了文件,所以设定的userdata.img不能太小,userdata.img大小可以直接认为等同真机的ROM大小。

 Android模拟器知识以及改造_第1张图片

 

 

创建avd界面

 Android模拟器知识以及改造_第2张图片

 

生成的avd目录

 Android模拟器知识以及改造_第3张图片

Avdconfig.ini文件内容

得到avd之后可以通过命令行的方式启动:

emulator -avd AVD_NAME -verbose, verbose查看日志。

 

    通过日志可以看出内部调用的是qemu-system-i386

    查看emulator/qemu目录可以看到这里有qemu-system-armel等多个文件,分别对应不同的架构,调用哪个取决于AVD里设置的target-arch, 我们创建的模拟器target-archx86, 所以调用的就是qemu-system-i386

TMOS中使用的avd是通过脚本的方式生成这些文件来实现创建的。需要注意的是,一个AVD代表一个模拟器实例,只能启动一次。

 

4. Android Emulator是怎么实现的?

    通过前面的emulator启动过程日志可以看出,emulator命令后负责启动虚拟机的是qemu-system-i386。实际上Android Emulator就是基于QEMU改写的,Virtual Box也是在QEMU基础上改写的。Android EmulatorQEMU基础上增加了telephonygps等。

    QEMULinux上著名的开源模拟器,能够模拟出不同架构的处理器、硬盘和网卡等。效率上,当模拟的是同构处理器时,借助于KVM能够达到接近主机的性能。Qemu里已经集成了kvm, ubuntu上直接安装qemu-kvmKVM依赖于硬件的虚拟化支持,所以需要在BIOS上开启VT

KVM (Kernel-based Virtual Machine) is a FreeBSD and Linux kernel module that allows a user space program access to the hardware virtualization features of various processors, with which QEMU is able to offer virtualization for x86, PowerPC, and S/390 guests. When the target architecture is the same as the host architecture, QEMU can make use of KVM particular features, such as acceleration.

5. 怎么实现在x86模拟器上运行只提供了arm 库文件的应用?

    Java虚拟机屏蔽了底层处理器的差异,所以对于只有Java代码的apk来说可以充分享受x86模拟器带来的流畅运行速度。

但是很多APK使用了JNI,调用了C语言编写的模块,虽然使用Google提供的NDK工具可以非常方便的生成分别针对x86/arm/MIPS等架构的的库文件,但大部分应用只提供了针对ARM编译的so库,这样的apkx86的处理器上就无法运行了。

安装应用时,PMS会检查ro.product.cpu.abilistro.product.cpu.abilist32的值,x86镜像里这两个值都是x86,表明本系统只有执行x86指令集的能力,这样如果APK里只有针对ARM指令集的动态库,那安装就无法通过,提示ABI不支持。把这两个属性值改为x86,armeabi-v7a,armeabi 标识本系统能支持这些指令集,就能骗过PMS,使应用正常安装。但应用此时并不能运行。

为了解决Atom x86处理器上运行Android系统的问题,Intel提供了一个叫做houdini的模块,提供了动态转换指令集的能力,使得x86 Android系统能够执行针对arm指令集的so库文件。Android5.0后在系统层面提供了NativeBridge,支持接入这样的转换器,所以5.0后要把houdini模块添加到系统里是比较简单的。但Houdini是闭源的,不对外提供使用文档。需要的二进制文件可以从x86 Android官网获取或者从Genymotion获取。集成方法也可以参照这两个实现进行。

系统默认启动是不开启NativeBridge能力的,打开需要把ramdisk.img里的ro.dalvik.vm.native.bridge=0注释。系统启动后,又会读取ro.dalvik.vm.native.bridge的值,默认为0,表示不开启,改为为libhoudini.so, 则会使用libhoudi.so提供的能力进行动态指令集的转换。

 

6. 怎么增加Wifi连接?

原始SDK里的Android镜像启动后是以mobile的方式联网的,无法打开WiFi联网。系统里已经包含了正常开启Wifi需要的Framework部分,但缺少硬件的模拟、HAL的支持以及相关的库和可执行文件。

 

Android模拟器知识以及改造_第4张图片

(外源)

qemu 命令支持增加虚拟网卡参数,模拟出硬件层支持。

增加HAL层的libhardware_legacy.so提供对硬件的操作。

    通过wpa_supplicant-ieth1 -Dwired -c/data/misc/wifi/wpa_supplicant.conf 命令来启动守护进程wpa_supplicant, 提供了wpa_server, 配置文件wpa_supplicant.conf提供wifi热点.                          wpa_cli命令则实现连接热点。具体实现由libwpa_client.so提供。

默认系统启动时是不连接WiFi的,可以通过adb shell svc wifi enable连接到wifisvc命令内部是通过调用WifiManager.enable实现的。启动过程中,观察logcat,可以看到wpa_supplicant服务的启动。

 

7. 怎么实现远程观看界面?

qemu提供了VNC Server的实现,可以通过-qemu -vnc :2打开。然后可以用任何实现了VNC协议的客户端连接到虚拟机上,实现远程控制。

VNC (Virtual Network Computing)虚拟网络计算机的缩写 VNC是把被控制端的屏幕做成图像,经过压缩后传送到控制端,控制端的控制信息(如鼠标信息)传送到被控制端后进入消息队列。这样就实现了远程控制服务端机器的能力。

VNC采用RFB通信协议,RFB ("remote 帧缓存 ") 是一个远程图形用户的简单协议,通过TCP/IP 协议簇连接。VNC控制端和被控制端在连接时会协商彼此支持的编码方式,编码方式已经发展出了很多种,有压缩率高的但编解码算法复杂,有压缩率低一些但编解码算法相对简单的,根据网络情况和客户端计算能力选择合适的。通常的编码方式是当原始的满屏被发送后,只发送变化的方块区域。分块算法和图像压缩技术随不同编码方式变化。目前采用的noVNC是用的Tight编码方式,按照相关测评数据[2],这是一个压缩率高比较节省带宽的编码方式。注:算法实现可以在aosp/6.0/system/external/libvncserver找到,或者在qemu2.4/ui/vnc-enc-xxx.c

 "Hextile" is an encoding that was designed for fast networks, while "Tight" is better suited for low-bandwidth connections. From the other side, "Tight" decoder in the TightVNC Java viewer seems to be more efficient than "Hextile" decoder so it may be ok for fast networks too. "ZRLE" encoding is similar to "Tight", but it does not support JPEG compression and compression levels.

 

8. 怎么给每台模拟器赋予一个imei?

部分应用通过判断IMEI是否是0来甄别模拟器,阻止在模拟器上运行。

 

Qemu/android_qemu/telephony/modem.cCGSN处定义了IMEI的值,所以模拟器里显示的IMEI的值是0000000000。要修改这里获取IMEI的方法

 

 

9. Root的处理

 App里通过su获得root权限代码:

 Android模拟器知识以及改造_第5张图片

需要注意的是,真机adb shell进去的默认是shell用户,模拟器里adb shell进去默认的就是root用户了,可以进行高权限的行为。模拟器镜像里也内置了su, 可以在shell里通过su命令切换shell/root用户,但是原始的su只可以由uidAID_ROOTAID_SHELL的进程调用,所以这些只是可以在PC端通过adb来使用。 第三方apk里是没法通过上面的java代码去切换到root用户的。

    这就需要替换掉原始的su文件,突破进程校验的限制。这里借助了supersu提供的文件进行处理。用supersu提供的su文件替换原始的/system/bin/su,安装supersua.apk来进行权限管理。

    基本原理是将apk层传入的本应放在shell进程中执行的命令,放到daemonsu 创建的进程sush中执行。其中daemonsu 为开机时启动的守护进程(init进程启动,userroot)

     这个过程最重要的为:apksudaemonsusushsupersu.apk 之间的通信。

     通信过程大概为:

     1、三方进程调用susu 通过socket daemonsu 通信,

     2daemonsu 创建sush

     3sush 通过 am 启动 superuser apk ,让用户选择是否授予其root权限。

     4supersu.apk 通过socket 告知 sush 用户选择的结果

     5sush 根据 apk 传过来的结果,选择继续执行或中断执行

 

其他:

1. 有时候会看到goldfish这个名词,按照文档说明,goldfish是专门为了模拟器运行的虚拟硬件平台的名字,早期只提供了模拟arm架构的处理器,现在已经有了x86MIPS的。

'goldfish' is the name of a family of similar virtual hardware platforms, that

mostly differ in the virtual CPU they support. 'goldfish' started as an

ARM-specific platform, but has now been ported to x86 and MIPS virtual CPUs.

 

参考:

1.C语言编译详解

http://www.cnblogs.com/CarpenterLee/p/5994681.html

2.VNC

http://www.tightvnc.com/archive/compare.html

http://www.docin.com/p-1446032132.html

3.android emulator源码

https://android.googlesource.com/platform/external/qemu/+/master/docs/DEVELOPMENT.TXT

4.Houdini

http://blog.csdn.net/roland_sun/article/details/50132175

 

你可能感兴趣的:(Android)