本文是 Systrace 系列文章的第十篇,主要是对 Systrace 中的 Binder 和锁信息进行简单介绍,简单介绍了 Binder 的情况,介绍了 Systrace 中 Binder 通信的表现形式,以及 Binder 信息查看,SystemServer 锁竞争分析等

本系列的目的是通过 Systrace 这个工具,从另外一个角度来看待 Android 系统整体的运行,同时也从另外一个角度来对 Framework 进行学习。也许你看了很多讲 Framework 的文章,但是总是记不住代码,或者不清楚其运行的流程,也许从 Systrace 这个图形化的角度,你可以理解的更深入一些。

系列文章目录

  1. Systrace 简介[1]

  2. Systrace 基础知识 - Systrace 预备知识[2]

  3. Systrace 基础知识 - Why 60 fps ?[3]

  4. Systrace 基础知识 - SystemServer 解读[4]

  5. Systrace 基础知识 - SurfaceFlinger 解读[5]

  6. Systrace 基础知识 - Input 解读[6]

  7. Systrace 基础知识 - Vsync 解读[7]

  8. Systrace 基础知识 - Vsync-App :基于 Choreographer 的渲染机制详解[8]

  9. Systrace 基础知识 - MainThread 和 RenderThread 解读[9]

  10. Systrace 基础知识 - Binder 和锁竞争解读[10]

  11. Systrace 基础知识 - Triple Buffer 解读[11]

  12. Systrace 基础知识 - CPU Info 解读[12]

Binder 概述

Android 的大部分进程间通信都使用 Binder,这里对 Binder 不做过多的解释,想对 Binder 的实现有一个比较深入的了解的话,推荐你阅读下面三篇文章

  1. 理解 Android Binder 机制 1/3:驱动篇[13]

  2. 理解 Android Binder 机制 2/3:C++层[14]

  3. 理解 Android Binder 机制 3/3:Java 层[15]

「之所以要单独讲 Systrace 中的 Binder 和锁,是因为很多卡顿问题和响应速度的问题,是因为跨进程 binder 通信的时候,锁竞争导致 binder 通信事件变长,影响了调用端。最常见的就是应用渲染线程 dequeueBuffer 的时候 SurfaceFlinger 主线程阻塞导致 dequeueBuffer 耗时,从而导致应用渲染出现卡顿; 或者 SystemServer 中的 AMS 或者 WMS 持锁方法等待太多, 导致应用调用的时候等待时间比较长导致主线程卡顿」

这里放一张文章里面的 Binder 架构图 , 本文主要是以 Systrace 为主,所以会讲 Systrace 中的 Binder 表现,不涉及 Binder 的实现

Binder 调用图例

Binder 主要是用来跨进程进行通信,可以看下面这张图,简单显示了在 Systrace 中 ,Binder 通信是如何显示的

Binder 调用

图中主要是 SystemServer 进程和 高通的 perf 进程通信,Systrace 中右上角 ViewOption 里面勾选 Flow Events 就可以看到 Binder 的信息

Binder

点击 Binder 可以查看其详细信息,其中有的信息在分析问题的时候可以用到

Binder 详细信息

对于 Binder,这里主要介绍如何在 Systrace 中查看 Binder 「锁信息」「锁等待」这两个部分,很多卡顿和响应问题的分析,都离不开这两部分信息的解读,不过最后还是要回归代码,找到问题后,要读源码来理顺其代码逻辑,以方便做相应的优化工作

Systrace 显示的锁的信息

「monitor contention with owner Binder:1605_B (4667) at void com.android.server.wm.ActivityTaskManagerService.activityPaused(android.os.IBinder)(ActivityTaskManagerService.java:1733) waiters=2 blocking from android.app.ActivityManager$StackInfo com.android.server.wm.ActivityTaskManagerService.getFocusedStackInfo()(ActivityTaskManagerService.java:2064)」

上面的话分两段来看,以 「blocking」 为分界线

第一段信息解读

「monitor contention with owner Binder:1605_B (4667) at void com.android.server.wm.ActivityTaskManagerService.activityPaused(android.os.IBinder)(ActivityTaskManagerService.java:1733) waiters=2」

「Monitor」 指的是当前锁对象的池,在 Java 中,每个对象都有两个池,锁(monitor)池和等待池:

「锁池」(同步队列 SynchronizedQueue ):假设线程 A 已经拥有了某个对象(注意:不是类 )的锁,而其它的线程想要调用这个对象的某个 synchronized 方法(或者 synchronized 块),由于这些线程在进入对象的 synchronized 方法之前必须先获得该对象的锁的拥有权,但是该对象的锁目前正被线程 A 拥有,所以这些线程就进入了该对象的锁池中。

这里用了争夺(contention)这个词,意思是这里由于在和目前对象的锁正被其他对象(Owner)所持有,所以没法得到该对象的锁的拥有权,所以进入该对象的锁池

「Owner」 : 指的是当前「拥有」这个对象的锁的对象。这里是 Binder:1605_B,4667 是其线程 ID。

「at」 后面跟的是「拥有」这个对象的锁的对象正在做什么。这里是在执行 void com.android.server.wm.ActivityTaskManagerService.activityPaused 这个方法,其代码位置是 :ActivityTaskManagerService.java:1733 其对应的代码如下:

com/android/server/wm/ActivityTaskManagerService.java

@Override
public final void activityPaused(IBinder token) {final long origId = Binder.clearCallingIdentity();synchronized (mGlobalLock) { // 1733 是这一行ActivityStack stack = ActivityRecord.getStackLocked(token);if (stack != null) {stack.activityPausedLocked(token, false);}}Binder.restoreCallingIdentity(origId);
}

可以看到这里 synchronized (mGlobalLock) ,获取了 mGlobalLock 锁的拥有权,在他释放这个对象的锁之前,任何其他的调用 synchronized (mGlobalLock) 的地方都得在锁池中等待

「waiters」 值得是锁池里面正在等待锁的操作的个数;这里 waiters=2 表示目前锁池里面已经有一个操作在等待这个对象的锁释放了,加上这个的话就是 3 个了

第二段信息解读

「blocking from android.app.ActivityManager$StackInfo com.android.server.wm.ActivityTaskManagerService.getFocusedStackInfo()(ActivityTaskManagerService.java:2064)」

第二段信息相对来说简单一些,就是标识了当前被阻塞等锁的方法 , 这里是 ActivityManager 的 getFocusedStackInfo 被阻塞,其对应的代码

com/android/server/wm/ActivityTaskManagerService.java

@Override
public ActivityManager.StackInfo getFocusedStackInfo() throws RemoteException {enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "getStackInfo()");long ident = Binder.clearCallingIdentity();try {synchronized (mGlobalLock) { // 2064 是这一行ActivityStack focusedStack = getTopDisplayFocusedStack();if (focusedStack != null) {return mRootActivityContainer.getStackInfo(focusedStack.mStackId);}return null;}} finally {Binder.restoreCallingIdentity(ident);}
}

可以看到这里也是调用了 synchronized (ActivityManagerService.this) ,从而需要等待获取 ams 对象的锁拥有权

总结

上面这段话翻译过来就是

「ActivityTaskManagerService 的 getFocusedStackInfo 方法在执行过程中被阻塞,原因是因为执行同步方法块的时候,没有拿到同步对象的锁的拥有权;需要等待拥有同步对象的锁拥有权的另外一个方法 ActivityTaskManagerService.activityPaused 执行完成后,才能拿到同步对象的锁的拥有权,然后继续执行」

可以对照原文看上面的翻译

「monitor contention with owner Binder:1605_B (4667) at void com.android.server.wm.ActivityTaskManagerService.activityPaused(android.os.IBinder)(ActivityTaskManagerService.java:1733) waiters=2 blocking from android.app.ActivityManager$StackInfo com.android.server.wm.ActivityTaskManagerService.getFocusedStackInfo()(ActivityTaskManagerService.java:2064)」

等锁分析

还是上面那个 Systrace,Binder 信息里面显示 waiters=2,意味着前面还有两个操作在等锁释放,也就是说总共有三个操作都在等待 Binder:1605_B (4667)  释放锁,我们来看一下 Binder:1605_B 的执行情况

等锁分析

从上图可以看到,Binder:1605_B 正在执行 activityPaused,中间也有一些其他的 Binder 操作,最终 activityPaused 执行完成后,释放锁

下面我们就把这个逻辑里面的执行顺序理顺,包括两个 「waiters」

锁等待

file:///Users/gaojack/blog/source/images/15756309922668.jpg

上图中可以看到 mGlobalLock 这个对象锁的争夺情况

  1. Binder_1605_B 首先开始执行 「activityPaused」,这个方法中是要获取 mGlobalLock 对象锁的,由于此时 mGlobalLock 没有竞争,所以 activityPaused 获取对象锁之后开始执行

  2. android.display 线程开始执行 「checkVisibility」 方法,这个方法也是要获取 mGlobalLock 对象锁的,但是此时 Binder_1605_B 的 activityPaused 持有 mGlobalLock 对象锁 ,所以这里 android.display 的 checkVisibility 开始等待,进入 sleep 状态

  3. android.anim 线程开始执行 「relayoutWindow」 方法,这个方法也是要获取 mGlobalLock 对象锁的,但是此时 Binder_1605_B 的 activityPaused 持有 mGlobalLock 对象锁 ,所以这里 android.display 的 checkVisibility 开始等待,进入 sleep 状态

  4. android.bg 线程开始执行 「getFocusedStackInfo」 方法,这个方法也是要获取 mGlobalLock 对象锁的,但是此时 Binder_1605_B 的 activityPaused 持有 mGlobalLock 对象锁 ,所以这里 android.display 的 checkVisibility 开始等待,进入 sleep 状态

经过上面四步,就形成了 Binder_1605_B 线程在运行,其他三个争夺 mGlobalLock 对象锁失败的线程分别进入 sleep 状态,等待 Binder_1605_B 执行结束后释放 mGlobalLock 对象锁

锁释放

锁释放

上图可以看到 mGlobalLock 锁的释放和后续的流程

  1. Binder_1605_B 线程的 「activityPaused」 执行结束,mGlobalLock 对象锁释放

  2. 第一个进入等待的 android.display 线程开始执行 「checkVisibility」 方法 ,这里从 android.display 线程的唤醒信息可以看到,是被 Binder_1605_B(4667) 唤醒的

  3. android.display 线程的 「checkVisibility」 执行结束,mGlobalLock 对象锁释放

  4. 第二个进入等待的 android.anim 线程开始执行 「relayoutWindow」 方法 ,这里从 android.anim 线程的唤醒信息可以看到,是被 android.display(1683) 唤醒的

  5. android.anim 线程的 「relayoutWindow」 执行结束,mGlobalLock 对象锁释放

  6. 第三个进入等待的 android.bg 线程开始执行 「getFocusedStackInfo」 方法 ,这里从 android.bg 线程的唤醒信息可以看到,是被 android.anim(1684) 唤醒的

经过上面 6 步,这一轮由于 mGlobalLock 对象锁引起的等锁现象结束。这里只是一个简单的例子,在实际情况下,SystemServer 中的 Binder 等锁情况会非常严重,经常 waiter 会到达 7 - 10 个,非常恐怖,比如下面这种:

大量的锁等待

这也就可以解释为什么 Android 手机 App 安装多了、用的久了之后,系统就会卡的一个原因;另外重启后也会有短暂的时候出现这种情况

如果不知道怎么查看唤醒信息,可以查看:Systrace 中查看进程信息唤醒[16] 这篇文章

相关代码

Monitor 信息

art/runtime/monitor.cc

std::string Monitor::PrettyContentionInfo(const std::string& owner_name,pid_t owner_tid,ArtMethod* owners_method,uint32_t owners_dex_pc,size_t num_waiters) {Locks::mutator_lock_->AssertSharedHeld(Thread::Current());const char* owners_filename;int32_t owners_line_number = 0;if (owners_method != nullptr) {TranslateLocation(owners_method, owners_dex_pc, &owners_filename, &owners_line_number);}std::ostringstream oss;oss << "monitor contention with owner " << owner_name << " (" << owner_tid << ")";if (owners_method != nullptr) {oss << " at " << owners_method->PrettyMethod();oss << "(" << owners_filename << ":" << owners_line_number << ")";}oss << " waiters=" << num_waiters;return oss.str();
}

Block 信息

art/runtime/monitor.cc

if (ATRACE_ENABLED()) {if (owner_ != nullptr) {  // Did the owner_ give the lock up?std::ostringstream oss;std::string name;owner_->GetThreadName(name);oss << PrettyContentionInfo(name,owner_->GetTid(),owners_method,owners_dex_pc,num_waiters);// Add info for contending thread.uint32_t pc;ArtMethod* m = self->GetCurrentMethod(&pc);const char* filename;int32_t line_number;TranslateLocation(m, pc, &filename, &line_number);oss << " blocking from "<< ArtMethod::PrettyMethod(m) << "(" << (filename != nullptr ? filename : "null")<< ":" << line_number << ")";ATRACE_BEGIN(oss.str().c_str());started_trace = true;}
}

参考

  1. 理解 Android Binder 机制 1/3:驱动篇[17]

  2. 理解 Android Binder 机制 2/3:C++层[18]

  3. 理解 Android Binder 机制 3/3:Java 层[19]

附件

本文涉及到的附件也上传了,各位下载后解压,使用 「Chrome」 浏览器打开即可点此链接下载文章所涉及到的 Systrace 附件[20]

关于我 && 博客

  1. 关于我[21] , 非常希望和大家一起交流 , 共同进步 .

  2. 博客内容导航[22]

  3. 优秀博客文章记录 - Android 性能优化必知必会[23]

「一个人可以走的更快 , 一群人可以走的更远」

Reference

[1]

Systrace 简介:https://www.androidperformance.com/2019/05/28/Android-Systrace-About/

[2]

Systrace 基础知识 - Systrace 预备知识:https://www.androidperformance.com/2019/07/23/Android-Systrace-Pre/

[3]

Systrace 基础知识 - Why 60 fps ?:https://www.androidperformance.com/2019/05/27/why-60-fps/

[4]

Systrace 基础知识 - SystemServer 解读:https://www.androidperformance.com/2019/06/29/Android-Systrace-SystemServer/

[5]

Systrace 基础知识 - SurfaceFlinger 解读:https://www.androidperformance.com/2020/02/14/Android-Systrace-SurfaceFlinger/

[6]

Systrace 基础知识 - Input 解读:https://www.androidperformance.com/2019/11/04/Android-Systrace-Input/

[7]

Systrace 基础知识 - Vsync 解读:https://www.androidperformance.com/2019/12/01/Android-Systrace-Vsync/

[8]

Systrace 基础知识 - Vsync-App :基于 Choreographer 的渲染机制详解:https://androidperformance.com/2019/10/22/Android-Choreographer/

[9]

Systrace 基础知识 - MainThread 和 RenderThread 解读:https://www.androidperformance.com/2019/11/06/Android-Systrace-MainThread-And-RenderThread/

[10]

Systrace 基础知识 - Binder 和锁竞争解读:https://www.androidperformance.com/2019/12/06/Android-Systrace-Binder/

[11]

Systrace 基础知识 - Triple Buffer 解读:https://www.androidperformance.com/2019/12/15/Android-Systrace-Triple-Buffer

[12]

Systrace 基础知识 - CPU Info 解读:https://www.androidperformance.com/2019/12/21/Android-Systrace-CPU

[13]

理解 Android Binder 机制 1/3:驱动篇:https://paul.pub/android-binder-driver/

[14]

理解 Android Binder 机制 2/3:C++层:https://paul.pub/android-binder-cpp/

[15]

理解 Android Binder 机制 3/3:Java 层:https://paul.pub/android-binder-java/

[16]

Systrace 中查看进程信息唤醒:https://www.androidperformance.com/2019/07/23/Android-Systrace-Pre/#%E8%BF%9B%E7%A8%8B%E5%94%A4%E9%86%92%E4%BF%A1%E6%81%AF%E5%88%86%E6%9E%90

[17]

理解 Android Binder 机制 1/3:驱动篇:https://paul.pub/android-binder-driver/

[18]

理解 Android Binder 机制 2/3:C++层:https://paul.pub/android-binder-cpp/

[19]

理解 Android Binder 机制 3/3:Java 层:https://paul.pub/android-binder-java/

[20]

点此链接下载文章所涉及到的 Systrace 附件:https://github.com/Gracker/SystraceForBlog/tree/master/Android_Systrace_Binder

[21]

关于我:https://www.androidperformance.com/about/

[22]

博客内容导航:https://androidperformance.com/2019/12/01/BlogMap/

[23]

优秀博客文章记录 - Android 性能优化必知必会:https://androidperformance.com/2018/05/07/Android-performance-optimization-skills-and-tools/

Android Systrace 基础知识(10) - Binder 和锁竞争解读相关推荐

  1. Android Systrace 基础知识(9)-MainThread 和 RenderThread 解读

    本文是 Systrace 系列文章的第九篇,主要是是介绍 Android App 中的 MainThread 和 RenderThread,也就是大家熟悉的「主线程」和「渲染线程」.文章会从 Syst ...

  2. android培训总结范文,android培训基础知识总结

    android培训基础知识总结,有需要的朋友可以参考下. android培训之1. Android的四大组件是哪些,它们的作用? Activity:Activity是Android程序与用户交互的窗口 ...

  3. android系统知识,Android系统基础知识百科

    Android系统基础知识百科 2015-12-16 17:58:31 954浏览 Android系统作为一款功能强大的移动计算平台,在保持开放性的同时,必须提供强健的安全保障.Android的系统安 ...

  4. Systrace 基础知识 - 锁竞争解读

    参考连接:https://www.androidperformance.com/2019/12/06/Android-Systrace-Binder/ 1.Systrace 显示的锁的信息 monit ...

  5. 第四章 Android WiFi基础知识

    系列文章目录 第一章 国内下载AOSP最新源码的方法 第二章 下载AOSP WiFi相关的代码 第三章 将源码导入Android Studio(无需编译idegen) 文章目录 系列文章目录 前言 一 ...

  6. Android.mk基础知识

    一.基础知识 1.Android.mk文件可以将源码打包成模块,模块可以是apk,jar包,c/c++应用程序,静态库和动态库.动态库可以被以到应用程序包apk,静态库可以被连接入动态库. 2.And ...

  7. Appium+python自动化(十五)- Android 这些基础知识,你知多少???(超详解)...

    简介 前边具体操作和实战已经讲解和分享了很多了,但是一些android的一些基础知识,你又知道多少了,你都掌握了吗?这篇就由宏哥给小伙伴们既是一个分享,又是对前边的一次总结.为什么要对这些做一个简单的 ...

  8. C/C++基础知识10道题,你都会吗?

    题目1:指针基础知识 题述:描述指针数组和数组指针(指向数组的指针)的区别并举例 考察点:C指针的基础知识 答案:考虑如下 char *q[] = {"xxx", "xx ...

  9. Android 应用基础知识和应用组件

    应用基础知识 安装到设备后,每个 Android 应用都运行在自己的安全沙箱内: Android 操作系统是一种多用户 Linux 系统,其中的每个应用都是一个不同的用户: 默认情况下,系统会为每个应 ...

最新文章

  1. 值得总结!认真安利7个让人眼前一亮的神仙软件和网站!
  2. PostMessage()
  3. pythonsuper函数_怎么使用python super函数调用父类
  4. python_10_文件操作
  5. 名为 cursor_jinserted 的游标不存在_你还在买丑橘吗?知道的人不多,看完后记得告诉身边人...
  6. MFC如何让输入框只能输入数字
  7. php 图片水印删除,PHP图片水印
  8. android can为啥能发收不到数据_大数据显示:报读MBA已是未来竞争力提升的必然趋势...
  9. 安装Eclipse的中文语言包
  10. 「职业解读」软件测试工程师
  11. 奔图打印机linux驱动rpm,奔图P2500打印机驱动
  12. Java学习笔记-不定时更新
  13. 计算机目录的制作步骤,怎么用word2003制作目录
  14. ‘\t‘和“\t“的区别
  15. RAID的概念和RAID对于SQL性能的影响
  16. 开始报名啦!——第二届融360“天机”金融风控大数据竞赛火热来袭
  17. 2018蓝桥杯C/C++ A组C组题目汇总
  18. 利用FME PythonCaller调用7z解压压缩包
  19. MySQL创建民族表
  20. 模拟卷Leetcode【普通】377. 组合总和 Ⅳ

热门文章

  1. 多个div在同一行显示
  2. 阮一峰访谈问题有奖征集(图灵访谈)
  3. 淘宝客引流玩法介绍(一)
  4. LruCache的深入解析
  5. 三个等于号===与两个等于号==
  6. Java和JDK版本的关系
  7. Arduino基础入门篇12—火焰报警器
  8. 戏精程序员凌晨三点半发周报,真的很做作!
  9. IIS + PHP 配置
  10. 大小限制_微信突破九张照片,视频大小限制