本文为个人原创,欢迎转载,但请务必在明显位置注明出处!
http://www.jianshu.com/p/8686931d31f0
1、前言
从Android 4.4宣布支持64位系统以来,各终端方案厂商逐步推出了各自的64位soc解决方案。Google为了兼容之前32位系统的应用,在64位系统上也实现了对32位应用的支持。那么问题就来了,在一个64位系统的Android手机上如何检测应用是运行在32位还是64位环境?本博文将为大家解答这个问题。
本文会分别对Android系统中的App、Native进程以及动态链接库的32/64位检测方法进行介绍。
2、检测App
任何一个Android手机用户对APK文件肯定不会陌生,它是一个Android应用资源的封装文件。当你下载安装一个App之后,从Launcher启动该应用,系统会由Zygote分叉出一个子进程来提供App运行的虚拟机和Runtime环境。与32位系统不同的是,在64系统中会同时存在两个Zygote进程——zygote和zygote64,分别对应32位和64位应用。所以,要进行App的32/64位检测,只需要看它的父进程是哪个Zygote即可。
下面的例子通过App的PPID信息——2759,检测出了终端系统中所有的64位应用,且该方式无需root权限。
$ adb shell ps |grep zygote
root 2759 1 2131692 87052 0 0000000000 S zygote64
root 2760 1 1574048 53740 0 0000000000 S zygote
$ adb shell ps|grep 2759
root 2759 1 2131692 87052 0 0000000000 S zygote64
system 3257 2759 2339956 158936 0 0000000000 S system_server
radio 3393 2759 1601272 96220 0 0000000000 S com.android.phone
u0_a85 3407 2759 1564856 88740 0 0000000000 S com.android.inputmethod.latin
u0_a20 3422 2759 1970228 167288 0 0000000000 S com.android.systemui
u0_a7 3769 2759 1548288 63384 0 0000000000 S android.ext.services
u0_a13 3958 2759 1896704 131832 0 0000000000 S com.android.launcher3
u0_a6 3989 2759 1562416 94060 0 0000000000 S android.process.acore
u0_a17 4046 2759 1563300 88504 0 0000000000 S android.process.media
u0_a28 4112 2759 1555640 82004 0 0000000000 S com.android.quicksearchbox
u0_a64 4157 2759 1554484 72944 0 0000000000 S com.android.calendar
u0_a57 4215 2759 1572160 83532 0 0000000000 S com.android.email
u0_a77 4231 2759 1554408 67192 0 0000000000 S com.android.exchange
u0_a5 4279 2759 1549136 66072 0 0000000000 S com.android.onetimeinitializer
u0_a10 4299 2759 1552472 74088 0 0000000000 S com.android.providers.calendar
u0_a94 4325 2759 1869948 112984 0 0000000000 S com.android.soundrecorder
system 4345 2759 1561180 73680 0 0000000000 S com.sprd.engineermode
u0_a15 4887 2759 1874612 106196 0 0000000000 S com.android.packageinstaller
u0_a73 5133 2759 2425904 205912 0 0000000000 S com.android.browser
3、检测Native进程
Andorid手机开机启动之后,init进程会启动一些后台守护进程。通常,这些进程会对整个Android系统起到重要作用,例如Zygote、MediaServer和ServiceManager等。因为这些Native进程并不是通过安装APK获得,所以上一章节的方法在这里并不适用。我们知道Andorid Framework层以下都是继承自Linux,因此可以采用Linux系统的一些工具和方法来对Native进程进行32/64位系统的检测。
方法一,通过readelf工具来分析Native进程对应的bin文件,下面以mediaserver为例
$readelf -h mediaserver
ELF Header:
Magic: 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00
Class: ELF32
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: DYN (Shared object file)
Machine: ARM
Version: 0x1
Entry point address: 0x1e24
Start of program headers: 52 (bytes into file)
Start of section headers: 20980 (bytes into file)
Flags: 0x5000000, Version5 EABI
Size of this header: 52 (bytes)
Size of program headers: 32 (bytes)
Number of program headers: 9
Size of section headers: 40 (bytes)
Number of section headers: 29
Section header string table index: 28
从上面的信息中我们看到mediaserver文件的Class字段为ELF32,Machine字段为ARM。由此可知,在Android 64位系统中,mediaserver运行在32位环境中。
方法二,在运行时通过打印Native进程的内存映射列表(maps)来检测32/64位,这个方法同样也适用于App的32/64位检测。这里以com.android.email为例,从上一章节的进程列表打印可以看到,com.android.email的PID为4215。
u0_a57 4215 2759 1572160 83532 0 0000000000 S com.android.email
然后,通过proc文件系统便可查询到PID=4215的内存映射列表 (截取片段)
$adb root
$adb shell cat /proc/4215/maps
......
71ebcb1000-71ebcb3000 r-xp 00000000 103:15 1453 /system/lib64/libOpenSLES.so
71ebcb3000-71ebcb4000 r--p 00001000 103:15 1453 /system/lib64/libOpenSLES.so
71ebcb4000-71ebcb5000 rw-p 00002000 103:15 1453 /system/lib64/libOpenSLES.so
71ebcb5000-71ebcd5000 r--s 00000000 00:12 282 /dev/__properties__/u:object_r:logd_prop:s0
71ebcd5000-71ebcf5000 r--s 00000000 00:12 287 /dev/__properties__/u:object_r:log_tag_prop:s0
71ebcf5000-71ebcf6000 r--p 00000000 00:00 0 [anon:linker_alloc]
71ebcf6000-71ebcf7000 rw-p 00000000 00:00 0 [anon:linker_alloc_vector]
71ebcf7000-71ebcf8000 r--p 00000000 00:00 0 [anon:linker_alloc]
71ebcf8000-71ebcf9000 rw-p 00000000 00:00 0 [anon:linker_alloc]
71ebcf9000-71ebcfb000 r-xp 00000000 103:15 1452 /system/lib64/libOpenMAXAL.so
71ebcfb000-71ebcfc000 r--p 00001000 103:15 1452 /system/lib64/libOpenMAXAL.so
71ebcfc000-71ebcfd000 rw-p 00002000 103:15 1452 /system/lib64/libOpenMAXAL.so
71ebcfd000-71ebcff000 rw-p 00000000 00:01 22281 /dev/ashmem/dalvik-indirect ref table (deleted)
71ebcff000-71ebd00000 r-xp 00000000 103:15 1565 /system/lib64/libjnigraphics.so
71ebd00000-71ebd01000 r--p 00000000 103:15 1565 /system/lib64/libjnigraphics.so
71ebd01000-71ebd02000 rw-p 00001000 103:15 1565 /system/lib64/libjnigraphics.so
71ebd02000-71ebd04000 rw-p 00000000 00:01 22280 /dev/ashmem/dalvik-indirect ref table (deleted)
71ebd04000-71ebd05000 r-xp 00000000 103:15 1644 /system/lib64/libsigchain.so
71ebd05000-71ebd06000 r--p 00000000 103:15 1644 /system/lib64/libsigchain.so
71ebd06000-71ebd07000 rw-p 00001000 103:15 1644 /system/lib64/libsigchain.so
......
从上面的打印中可以看出,com.android.email加载的动态链接库均位于/system/lib64。由此便可判断com.android.email运行于64位环境。需要注意的是这个方法要root权限才能检测。
4、检测动态链接库(*.so文件)
如果想要对一个.so文件的进行32/64位检测,那么采用上一章节中的方法一就可以做到。但是,有native开发经验的读者应该知道,64位系统中动态链接库通常会同时存在32位和64位两个版本,它们分别位于/system/lib和/system/lib64路径中。所以,孤立地对某一个.so文件进行32位/64位检测并没有现实意义,应该将其与加载该.so文件的App或Native进程作为一个整体来分析。
5、后语
本文分别对Android系统中App、Native进程和动态链接库进行32/64位检测的方法进行了介绍,希望对大家的学习开发工作有所帮助。