了解一下Android调试
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了了解一下Android调试相关的知识,希望对你有一定的参考价值。
今天我要分享的是Framework的学习和调试的方法。首先,android是一种基于Linux的开放源代码软件栈,为广泛的设备和机型而创建。下图是Android平台的主要组件。
从图中你可以看到主要有以下几部分组成:
- Linux内核
- Android Runtime
- 原生C/C++库
- Java API框架(后面我称之为Framework框架层)
- 系统应用
在各个应用市场看到的,大多是第三方应用,也就是安装在data区域的应用,它们可以卸载,并且权限也受到一些限制,比如不能直接设置时间日期,需要调用到系统应用设置里面再进行操作。
在应用开发过程中使用的四大组件,便是在Framework框架层进行实现,应用通过约定俗成的规则,在AndroidMainfest.xml中进行配置,然后继承对应的基类进行复写。系统在启动过程中解析AndroidMainfest.xml,将应用的信息存储下来,随后根据用户的操作,或者系统的广播触发,启动对应的应用。
framwork 到底又那些东西?
Framework框架层是应用开发过程中,调用的系统方法的内部实现,比如我们使用的TextView、Button控件,都是在这里实现的。再举几个例子,我们调用ActivityManager的getRunningAppProcesses方法查看当前运行的进程列表,还有我们使用NotificationManager的notify发送一个系统通知。
代码 | 源码目录 | 编译目录 |
---|---|---|
系统的相关Widget | frameworks/base/core/java/android, frameworks/base/core/java/android/view | /system/framework/framework.jar |
系统中的AMS/PMS | frameworks/base/services/core/java/com/android/server | /system/framework/services.jar |
系统中内置的资源文件,比如Button的背景图、属性值之类 | frameworks/base/core/res | /system/framework/framework-res.apk |
在系统开发中还会涉及到服务的对应本地实现部分,比如 | frameworks/base/core/jni, frameworks/base/services/core/jni | 视情况 |
如何快速地学习、梳理Framework知识体系呢?常见的学习方法有下面几种:
- 阅读书籍(方便梳理知识体系,但对于解决问题只能提供方向)。
- 直接阅读源码(效率低,挑战难度大)。
- 打Log和打堆栈 (效率有所提升,但需要反复编译,添加Log和堆栈代码)。
- 直接联调,实时便捷(需要调试版本)。
首先可以通过购买相关的书籍进行学习,其中主要的知识体系有Linux操作系统,比如进程、线程、进程间通信、虚拟内存,建立起自己的软件架构。在此基础上学习Android的启动过程、服务进程SystemServer的创建、各个服务线程(AMS/PMS等)的创建过程,以及Launcher的启动过程。熟悉了这些之后,你还要了解ART虚拟机的主要工作原理,以及init和Zygote的主要工作原理。之后随着在工作和实践过程中你会发现,Framework主要是围绕应用启动、显示、广播消息、按键传递、添加服务等开展,这些代码的实现主要使用的是Java和C++这两种语言。
通过书籍或者网络资料学习一段时间后,你会发现很多问题都没有现成的解决方案,而此时就需要我们深入源码中进行挖掘和学习。但是除了阅读官方文档外,别忘了调试Framework也是一把利刃,可以让你游刃有余快速定位和分析源码。
下面我们来看看调试Framework的Java部分:
这里使用 Android Studio 进行调试,在调试前我们要先掌握一些知识。Java代码的调试,主要依据两个因素,一个是你要调试的进程;一个是调试的类对应的包名路径,同时还要保证你所运行的手机环境和你要调试的代码是匹配的。只要这两个信息匹配,编译不通过也是可以进行调试的。
我们调试的系统服务是在SystemServer进程中,可以使用下面的命令验证
ps -A | grep system_server 查看系统服务进程pid
cat /proc/pid/maps |grep services 通过cat查看此进程的内存映射,看看是否services映射到内存里面。
这里我们看到信息:/system/framework/oat/x86/services.odex 。odex是Android系统对于dex的进一步优化,目的是为了提升执行效率。从这个信息便可以确定,我们的services.jar确实是跑到这里了,也就是我们的系统服务相关联的代码,可以通过调试SystemServer进程进行跟踪。
下来我们来建立调试环境。
- 打开Genymotion,选择下载好Android 9.0的镜像文件,启动模拟器。
- 找到模拟器对应的ActivityManagerService.java代码。 我是从http://androidxref.com/下载Android 9.0对应的代码。
- 打开Android Studio,File -> New -> New Project然后直接Next直到完成就行。
- 新建一个包名,从ActivityManagerService.java文件中找到它,这里为com.android.server.am,然后把ActivityManagerService.java放到里面即可。
- 在ActivityManagerService.java的startActivity方法上面设置断点,然后找到菜单的Run -> Attach debugger to Android process勾选Show all process,选中system_server进程确定。
这时候我们点击Genymotion模拟器中桌面的一个图标,启动新的界面。会发现这时候我们设定的断点已经生效。
你可以看到断下来的堆栈信息,以及一些变量值,然后我们可以一步步调试下去,跟踪启动的流程。
对于学习系统服务线程来讲,通过调试可以快速掌握流程,再结合阅读源码,便可以快速学习,掌握系统框架的整个逻辑,从而节省学习的时间成本。
以上我们验证了系统服务AMS服务代码的调试,其他服务调试方法也是一样,具体的线程信息,可以使用下面的命令查看。
ps -T 353
这里353是使用ps -A |grep system_server查出 SystemServer的进程号
以上是关于了解一下Android调试的主要内容,如果未能解决你的问题,请参考以下文章