Android调试之Framewrok Native调试

本文详细介绍如何调试Android Framework层的C/C++代码,包括运行中进程(如CameraService)及进程启动(如init进程)。通过gdbserver进行监听,设置端口转发,利用gdb进行远程调试。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

概述

转载请注明出处:https://blog.youkuaiyun.com/wangzaieee/article/details/83895089

我们知道Android Framework层不仅仅是只有java代码,还有许多c/c++代码,比如init进程和MediaPlayerService,CameraService等本地系统服务,都是用c和c++实现的。这个时候我们要分析问题和追踪代码最好的方式就是调试。如果想要了解Framework Java的调试方法,请看本文

今天我们主要讲解两种情况下的native代码调试:

  • 调试运行中的native进程(以CameraService connect方法为例)
  • 调试native进程的启动 (以init进程的启动为例)

调试CameraService connect方法

准备条件

  • 有已经编译好的安卓源码(debug版)
  • 使用上述镜像的debug设备

调试步骤

调试CameraService的connect方法,流程如下:

  • 初始化调试环境(进入源码根目录执行)
# 运行shell脚本,配置环境
$ source build/envsetup.sh 
# 然后选择自己要调试的编译版本
$ lunch
  • 将设备连接上服务器(如果服务器是远程服务器呢?见下面思考1
  • 查看要调试的进程ID
# CameraService运行在mediaserver进程,获得其进程id
$ adb shell ps | grep mediaserver
  • 然后链接gdb调试该进程。
$ adb root #否则gdbserver(64)没有足够的权限attach到mediaserver进程
$ gdbclient [mediaserver的进程id]

# 这个时候进入了gdb调试模式
# 给CameraService的connect方法打断点
# c++方法需要加上前面的命名空间
(gdb) b android::CameraService::connect 
(gdb) i b #查看当前的断点
#打开摄像头,这个时候会黑屏,因为之前打的断点
(gdb) c #运行到断点
(gdb) bt #查看当前函数栈(可以看到栈顶是connect方法)
(gdb) n #单步调试(nexti 单步指令,l 查看当前的代码,p status打印status的值)
(gdb) c #继续执行至下一个断点(没断点就直接执行完成)

以上就是所有的调试步骤。

调试Init进程的启动

init进程是用户空间的第一个进程,init进程的启动流程可以查看这篇文章。接下来我们来看看这么调试init进程呢?

准备条件

  • 有已经编译好的安卓源码(debug版)
  • 使用上述镜像的debug设备

调试步骤

  • 初始化调试环境(同上)
  • 将设备连上服务器(同上)
  • 启动要调试的进程(如果是wifi调试,就在设备端执行)
$ adb root #否则gdbserver(64)没有足够的权限运行init进程
$ adb shell gdbserver(64) :5039 ./init #Init进程会启动,并且会打印对应的进程id

并且init进程在本机的5039的端口监听之下。

  • 转发端口(如果是wifi调试,在服务端执行)
#将设备的端口转发的服务器的端口(6.0以后不用执行,gdbclient的脚本会执行)
$ adb forward tcp:5039 tcp:5039 

这个时候gdb只要连接本地的5039端口,就相当于连接上了设备的5039端口,gdb就间接通过gdbserver连接上init进程。

  • gdb开始调试init进程的启动
$ gdbclient <PID> #<PID>表示init的进程id
  • 进入gdb调试模式
(gdb) b main #给init.c(pp)的main方法打断点
(gdb) c #执行到断点
(gdb) ni #向下走一条指令
(gdb) n #向下走一条代码

step(进入函数体),fin(退出当前函数体),还有很多GDB的指令,有兴趣的可以使用man gdb查看相关参数

思考1: 如果源码在远程服务器上,这个时候应该怎么调试呢?
通过wifi调试,设备连接wifi,保证服务器和设备在同一个局域网内

$ adb tcpip 5555 #在设备端运行
$ adb connect <设备ip地址> #在服务端运行

思考2: gdbclient是什么,做了哪些操作呢?

 #(要求Android 6.0及以上,5.0在build/envsetup.sh中找gdbclient()方法即可)
 $ which gdbclient 
 # 可以看到gdbclient脚本的位置

然后我们查看里面的代码就可以发现,它做了如下几个操作:

1.设置端口转发(adb forward)
2.启动gdbserver,并将gdbserver attach到想要调试的进程
3.gdb 连接上gdbserver进行调试

PS: gdbclient [pid]如果连接过程中报错,也可以分析gdbclient源码来解决哦

总结

调试运行中的进程调试本地进程的启动,操作步骤大致相同,都是先通过gdbserver进行监听,然后设置端口转发,gdb通过gdbserver进行远程调试。调试技巧对于分析源码,了解执行流程都起到了至关重要的作用。

以上就是Framework Native代码的调试流程,如果觉得对你有帮助请留下一个赞吧~ 觉得写的不好也请批评指出~

参考资料:
使用GDB

### 创建和使用弹窗 #### 使用 `PopupWindow` 实现基本弹窗 对于简单的应用内弹窗需求,可以直接利用 `PopupWindow` 类来实现。此方式适用于仅需在当前 Activity 或者 Fragment 上显示的场景。 ```java View popupView = getLayoutInflater().inflate(R.layout.popup_layout, null); final PopupWindow popupWindow = new PopupWindow(popupView, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); popupWindow.showAtLocation(parentView, Gravity.CENTER, 0, 0); // 显示位置设置为中心 ``` 为了使弹窗能够覆盖其他视图并保持顶层状态,可以通过调整窗口布局类型来达到目的[^1]。 #### 系统级弹窗权限申请 针对需要跨越应用程序边界展示的系统级弹窗,则必须先声明相应的权限,并根据不同版本处理不同的参数配置: - 对于 API Level 小于 Oreo (API level 26) 的设备,应请求 `SYSTEM_ALERT_WINDOW` 权限; - 当目标 SDK 版本大于等于 Oreo 时,则应该改为请求 `SYSTEM_OVERLAY_WINDOW` 权限[^3]。 ```xml <!-- AndroidManifest.xml --> <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/> <!-- or for newer versions --> <uses-permission android:name="android.permission.SYSTEM_OVERLAY_WINDOW"/> ``` 接着,在代码逻辑里判断当前系统的 API Level 并相应地设定 WindowManager 参数: ```java if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { params.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; } else { params.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT; } ``` #### 复杂情况下的解决方案 然而,由于不同制造商可能对框架进行了自定义更改,单纯依靠反射调用内部方法可能会遇到兼容性问题。此时建议采用官方推荐的方式构建服务端组件,比如通过继承 `Service` 类并在其中管理浮动窗口生命周期,从而绕过潜在的安全限制[^4]。 另外一种思路是在特定条件下触发广播接收器监听事件,进而动态加载指定 UI 组件作为临时界面呈现给用户查看。这种方式不仅提高了灵活性还增强了安全性[^5]。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值