【原创】如何检测Android应用是32位还是64位

时间:2024-10-18 07:04:18
本文为个人原创,欢迎转载,但请务必在明显位置注明出处!

/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 
u0_a85    3407  2759  1564856 88740          0 0000000000 S 
u0_a20    3422  2759  1970228 167288          0 0000000000 S 
u0_a7     3769  2759  1548288 63384          0 0000000000 S 
u0_a13    3958  2759  1896704 131832          0 0000000000 S .launcher3
u0_a6     3989  2759  1562416 94060          0 0000000000 S 
u0_a17    4046  2759  1563300 88504          0 0000000000 S 
u0_a28    4112  2759  1555640 82004          0 0000000000 S 
u0_a64    4157  2759  1554484 72944          0 0000000000 S 
u0_a57    4215  2759  1572160 83532          0 0000000000 S 
u0_a77    4231  2759  1554408 67192          0 0000000000 S 
u0_a5     4279  2759  1549136 66072          0 0000000000 S 
u0_a10    4299  2759  1552472 74088          0 0000000000 S 
u0_a94    4325  2759  1869948 112984          0 0000000000 S 
system    4345  2759  1561180 73680          0 0000000000 S 
u0_a15    4887  2759  1874612 106196          0 0000000000 S 
u0_a73    5133  2759  2425904 205912          0 0000000000 S 

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位检测。这里以为例,从上一章节的进程列表打印可以看到,的PID为4215。

u0_a57    4215  2759  1572160 83532          0 0000000000 S 

然后,通过proc文件系统便可查询到PID=4215的内存映射列表 (截取片段)

$adb root
$adb shell cat /proc/4215/maps
......
71ebcb1000-71ebcb3000 r-xp 00000000 103:15 1453                          /system/lib64/
71ebcb3000-71ebcb4000 r--p 00001000 103:15 1453                          /system/lib64/
71ebcb4000-71ebcb5000 rw-p 00002000 103:15 1453                          /system/lib64/
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/
71ebcfb000-71ebcfc000 r--p 00001000 103:15 1452                          /system/lib64/
71ebcfc000-71ebcfd000 rw-p 00002000 103:15 1452                          /system/lib64/
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/
71ebd00000-71ebd01000 r--p 00000000 103:15 1565                          /system/lib64/
71ebd01000-71ebd02000 rw-p 00001000 103:15 1565                          /system/lib64/
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/
71ebd05000-71ebd06000 r--p 00000000 103:15 1644                          /system/lib64/
71ebd06000-71ebd07000 rw-p 00001000 103:15 1644                          /system/lib64/
......

从上面的打印中可以看出,加载的动态链接库均位于/system/lib64。由此便可判断运行于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位检测的方法进行了介绍,希望对大家的学习开发工作有所帮助。