Android 框架问题分析案例 - 谁杀了桌面?

2023-05-16

写这篇文章的契机是因为一个实际遇到的问题 , 这个问题其实不难 , 不过在分析了这个问题然后写日记的时候 , 我突然觉得这个问题分析的过程有必要记录一下 , 分享给大家。分析过程中有用到一些工具 , 一些方法 , 也从另外一个聪明的小伙伴那里学到了一些分析技巧和工具的使用技巧

这篇文章中分析过程包括我之前在 Android 中的卡顿丢帧原因概述 - 方法论 里面提到的一些工具 , 包括 : 复现视频 \ Event Log \ Android Studio 源码和 App Debug \ Android Studio Profile \ Systrace \ Dumpsys \ PS 等 . 大多数工具大家都在开发过程中使用过 , 这次分析正是使用了这些工具相互配合 , 最终找到的问题的原因。

大家看下来可能会觉得 , 这么简单一个问题还需要写一篇文章 ? 我写这篇文章的目的一是为了记录给自己 , 二是觉得分析过程比较有普遍性 , 包括分析思路和工具的使用 , 如果可以帮助到大家 , 那么最好不过了 , 如果你也有好的思路或者独家调试技巧 , 欢迎大家扫描关于我 里面的讨论群二维码加入群聊 , 共同进步!

现象

这个问题是测试直接报过来的 , Bug 描述是典型的按现象描述 : “ 从应用返回桌面 , 桌面图标加载慢 “. 测试这边提供了录制的视频和抓取的 Log , 以及对应的 Systrace 等. 既然现象和 Log 都在 , 那么就开始分析吧.

分析过程

确定问题发生的时间点

1.由于测试提供的复现视频 , 首先看复现视频 , 确定时间发生的时间
2.根据视频里面的大概时间(精确到分) , 查看对应的 EventLog ,跟视频比对,确定发生的确切时间点 (精确到秒)
3.查看 EventLog 和 MainLog , 还原发生时候的用户操作 ,这个例子里面就发现启动和我信这个 App 之后,Launcher 被杀了.

EventLog 
// 启动 com.jx.cmcc.ict.ibelieve 这个 App 
09-10 10:14:48.877  1456  2269 I am_set_resumed_activity: [0,com.jx.cmcc.ict.ibelieve/.ui.MainTabActivity,resumeTopActivityInnerLocked] 
09-10 10:14:48.886  1456  2269 I am_resume_activity: [0,80317506,54938,com.jx.cmcc.ict.ibelieve/.ui.MainTabActivity] 
09-10 10:14:48.891  1456  1485 I sysui_count: [window_time_0,0] 
09-10 10:14:48.891  1456  1485 I sysui_multi_action: [757,803,799,window_time_0,802,0] 
09-10 10:14:48.902  1456  2269 I am_uid_stopped: 10021 
 
// 这里桌面被杀 
09-10 10:14:48.903  1456  2269 I am_kill : [0,13509,com.meizu.flyme.launcher,600,kill background] 
 
// 这里开始从 App 返回桌面 
09-10 10:14:51.990  1456  1791 I am_pause_activity: [0,80317506,com.jx.cmcc.ict.ibelieve/.ui.MainTabActivity] 
09-10 10:14:51.994  1456  1791 I am_task_to_front: [0,54923] 
09-10 10:14:51.996 13674 13674 I am_on_paused_called: [0,com.jx.cmcc.ict.ibelieve.ui.MainTabActivity,handlePauseActivity] 
09-10 10:14:52.013  1456  2270 I am_uid_running: 10021 
 
// 重新创建桌面进程 
09-10 10:14:52.025  1456  2270 I am_proc_start: [0,14013,10021,com.meizu.flyme.launcher,activity,com.meizu.flyme.launcher/.Launcher] 
09-10 10:14:52.045  1456  2270 I am_proc_bound: [0,14013,com.meizu.flyme.launcher] 
09-10 10:14:52.069  1456  2270 I am_uid_active: 10021 
09-10 10:14:52.069  1456  2270 I am_restart_activity: [0,238217861,54923,com.meizu.flyme.launcher/.Launcher] 
 
// 桌面显示 
09-10 10:14:52.071  1456  2270 I am_set_resumed_activity: [0,com.meizu.flyme.launcher/.Launcher,minimalResumeActivityLocked] 
09-10 10:14:52.335 14013 14013 I am_on_resume_called: [0,com.meizu.flyme.launcher.Launcher,LAUNCH_ACTIVITY] 
09-10 10:14:52.437  1456  1504 I am_activity_launch_time: [0,238217861,com.meizu.flyme.launcher/.Launcher,413,413] 

那么这里就可以简单还原问题了 , 测试报的是 从应用返回桌面 , 桌面图标加载慢 , 从 Event Log 来看 , 桌面显示慢 , 是因为 桌面被杀了, 所以从 App 返回的时候 , 桌面需要重新加载 , 从桌面进程创建到桌面完全显示 , 花费了 413ms(实际到桌面完全显示,花费了至少 2s 左右,因为 Launcher 冷启动还要重新加载内容).

分析被杀原因

从上面的分析来看 , 我们需要找到 Launcher 被杀的原因 , 从现象上来看 , 似乎是和 com.jx.cmcc.ict.ibelieve 这个进程有关系 , 但是我们目前是没有办法确认的 .

这里我们重点看这个这个 Event Log

am_kill : [0,13509,com.meizu.flyme.launcher,600,kill background] 

这里可以看到 Launcher 被杀的原因是 kill background , 查看对应的源码可知,reason = kill background 是 AMS.killBackgroundProcesses 这里发出的.ActivityManagerService.killBackgroundProcesses

public void killBackgroundProcesses(final String packageName, int userId) { 
...... 
            synchronized (this) { 
                killPackageProcessesLocked(packageName, appId, targetUserId, 
                        ProcessList.SERVICE_ADJ, false, true, true, false, "kill background"); 
            } 
} 

对源码比较熟悉的同学可以很快知道 , AMS.killBackgroundProcesses 这个接口会提供给三方应用去调用 , 其 Binder 的客户端在 ActivityManager.killBackgroundProcesses 这里

ActivityManager.killBackgroundProcesses

/** 
 * Have the system immediately kill all background processes associated 
 * with the given package.  This is the same as the kernel killing those 
 * processes to reclaim memory; the system will take care of restarting 
 * these processes in the future as needed. 
 * 
 * @param packageName The name of the package whose processes are to 
 * be killed. 
 */ 
@RequiresPermission(Manifest.permission.KILL_BACKGROUND_PROCESSES) 
public void killBackgroundProcesses(String packageName) { 
    try { 
        getService().killBackgroundProcesses(packageName, 
                mContext.getUserId()); 
    } catch (RemoteException e) { 
        throw e.rethrowFromSystemServer(); 
    } 
} 

对 SystemServer 进程进行断点 Debug

知道了上面的代码逻辑 , 我们需要做的就是找到在这个场景下 , 是哪个应用调用 ActivityManager.killBackgroundProcesses 杀掉了桌面. 由于不知道具体是哪个应用(这里虽然我们怀疑是 com.jx.cmcc.ict.ibelieve , 但是没有证据) , 我们先对 SystemServer 进程进行 Debug .

1.首先对源码进行 debug , 首先在 Android 中点击 debug 按钮 , 选择 system_process 这个进程(就是我们所说的 SystemServer) , 然后点击 OK . 代码的断点我们打在上面列出的 ActivityManagerService.killBackgroundProcesses 方法里面。

2.点击启动怀疑的 App ( 可以从 EventLog 和视频里面倒推,找到比较可疑的 App , 安装后进行本地测试复现 , 这里选择了视频中出现的几个应用,包括我们之前怀疑的 com.jx.cmcc.ict.ibelieve- 和我信 ) , 点击其他的应用都不会进入到这个断点, 而在点击 和我信 这个 App 启动后走到的断点。

3.这里我们可以看到调用栈是一个 Binder 调用 , 我们需要找到这个 Binder 调用的客户端. 在 AS 里面继续操作 , 点击如下图的计算器按钮 , 输入 getRealCallingPid() 点击下面的 Evaluate , 就可以看到结果. result = 29771

4.通过 PS 命令 , 查看这个 pid 对应的 app。

可以看到就是这个应用调用的 killBackgroundProcesses。

对 App 进程进行断点 Debug

为了进一步调查,我们对这个 app 进行 debug , 由于没有源码,我们直接把断点打到 android/app/ActivityManager.killBackgroundProcesses 这里(因为这里是客户端代码 , 所以调试 App 进程的时候 , 可以直接打断点 )。

本地安装这个应用进行调试, 发现登录后,再次启动, 桌面必会被杀 ,确定就是这个 App 的问题

到了这一步我们已经基本上确定问题就是这个 App 引起的了 , 不过如果我们想看比较详细的调用情况 , 可以使用 Android Studio Profile。

使用 Android Studio Profiler 工具

打开 Android Studio , 点击 Profiler 按钮 , 点击 + 号 , 选择 com.jx.cmcc.ict.ibelieve 这个进程 , 然后点击 CPU 这一栏。

这里选择了 Trace Java Methods , 然后点击旁边的 Record , 就可以开始进行操作 , 操作结束后 , 点击 Stop , AS 会自动开始解析。

解析结果我们可以看这里:


最下面就是刚刚操作所对应的详细函数调用栈 , 以真正运行的顺序展示在我们面前(我经常会用这个工具来查看源码逻辑和三方应用的代码逻辑 , 不管是学习还是解决问题 , 都是一个非常好的方法)。

我们使用 ctrl+f 进行搜索 killBackgroundProcesses , 如果有的话 , 会以高亮显示, 我们只需要用鼠标放大就可以看到详细的调用栈。


可以看到这个 App 在 loadComplete 回调里面执行了 killBackground 方法.(到了这里,应用开发者就已经知道是哪里的问题了,修复起来飞快)。

权限问题分析

如上面所示 , 调用 killBackgroundProcesses 是需要Manifest.permission.KILL_BACKGROUND_PROCESSES 这个权限的。

@RequiresPermission(Manifest.permission.KILL_BACKGROUND_PROCESSES) 
public void killBackgroundProcesses(String packageName) { 
} 

执行 adb shell dumpsys package com.jx.cmcc.ict.ibelieve 查看 com.jx.cmcc.ict.ibelieve 这个进程所申请的权限 , 发现这个应用在安装的时候就申请了KILL_BACKGROUND_PROCESSES 这个权限 , 且默认是授予的。

install permissions: 
  ...... 
  android.permission.ACCESS_NETWORK_STATE: granted=true 
  android.permission.KILL_BACKGROUND_PROCESSES: granted=true 
  android.permission.WRITE_USER_DICTIONARY: granted=true 
  ...... 

对应的权限级别为 normal。

也就是说 , 所有的第三方应用都可以默认有这个权限 , 只要你申请 . 这个案例里面 , 就是因为这个 App 申请了这个权限 , 且执行了错误的行为 , 导致把桌面杀掉 , 严重影响用户体验. Sad !

Systrace 工具可以找出来 Kill 桌面的元凶么?

由于经常使用 Systrace , 那么 Systrace 是否可以找到元凶呢? 答案是可以 (这里如果对如何在 Systrace 上查看唤醒信息不了解 , 可以看一下这篇文章 分析 Systrace 预备知识 ). 我们录制一段 Systrace , 安装下面的顺序去看

1.首先看 system_server 进程对应的 trace ,找到 killProcessGroup 对应的点 , 查看其唤醒情况 , 可以看到是 19688 这个线程唤醒执行 AMS 的 killProcessGroup。

在 Systrace 中搜索 19688 , 可以看到是 Binder:1295_1E , 1295 就是 SystemServer。

查看对应的 Binder:1295_1E , 看看是哪个线程唤醒这个线程。

搜索 7289这个线程 , 可以看到这个线程就是和我信这个 App 的主线程。

查看 7289 , 确定就是 com.jx.cmcc.ict.ibelieve 这个进程 . 也就是 和我信 这个 App(瘤子)。

这里也可以反推出来这个 Kill 是 和我信 这个 App 发起的 , 进一步确认可以使用上面 AS 的 MethodTrace。

总结

从上面的分析来看 , 这个问题是由于应用申请了不恰当的权限并错误使用对应的函数导致的一个严重影响用户使用的问题. 一般分析到这一步 , 我们的工作就基本上结束了 , 后续只需要和商店沟通 , 跟 App 开发者联系进行修改即可。

不过令我感到意外的是 android.permission.KILL_BACKGROUND_PROCESSES 这个权限 Google 居然放的这么松 , 我一直以为这个权限是要专门申请以防止 App 滥用或者卵用的(毕竟涉及到其他 App 的生死存亡).

关于我

更多信息可以点击关于我 , 非常希望和大家一起交流 , 共同进步

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Android 框架问题分析案例 - 谁杀了桌面? 的相关文章

随机推荐

  • 爬虫(一)基础介绍

    文章目录 1 爬虫简介1 1 robots协议1 2 反爬手段1 3 请求组成1 4 响应组成1 5 POST 请求与 GET 请求 2 requests库2 1 GET请求2 2 POST请求2 3 代理 1 爬虫简介 网络爬虫也叫做网络
  • Gradle 和 Gradle Wrapper 到底是什么关系。

    Gradle Wrapper 我们推荐使用 Gradle Wrapper 执行gradle 构建 xff0c xff08 后面简称Wrapper xff09 Wrapper 实质上是一个脚本 xff0c 这个脚本使用申明版本的gradle
  • 【AD16】PCB设计时元器件怎么放到板子背面

    1 首先拖动元器件 2 再按 L 键 3 放置即可
  • C++语言及网络编程书籍整理

    C 43 43 语言及网络编程书籍整理 作者 谢勇 都是我看过或正要看的书 xff0c 晾晾书架 xff0c 希望对后来者也有一点作用 xff0c 当年我也是浪费时间看了一些没有价值的书籍 xff0c 颇为后悔 xff0c 现将精华总结如下
  • Kotlin在Android Studio中安装与配置

    Kotlin的安装与配置 因为本人使用的开发工具是Android Studio xff0c 所以这里只说明一下Kotlin在Android Studio中的安装与配置 Kotli插件的安装 在安装Kotlin插件之前 xff0c Andro
  • Makefile Android.mk 引发的思索(转)

    Makefile Android mk 引发的思索 转至 xff1a https www cnblogs com quansir p 4269951 html 在我们编写 Android 平台 cocos2d x 游戏的时候 xff0c 我
  • Kali Linux Gnome 环境下使用全局菜单

    Kali Linux Gnome 环境下使用全局菜单 2022 09 24 文章目录 Kali Linux Gnome 环境下使用全局菜单1 目标2 预备3 操作3 1 安装3 2 配置3 3 启用3 4 测试3 5 自启 1 目标 Gno
  • 发布jar到本地仓库

    Android Studio 在Module的buill gradle文件中添加插件 apply plugin span class token operator span span class token string 39 maven
  • AOP切面以及@Valid注解执行顺序

    结论 SpringBoot是先执行 64 Valid注解再执行切面 所以无法将AOP的触发位置移动到 64 Valid之前 自定义注解如果想要在 64 Valid校验之前触发 要么通过拦截器 但拦截器对参数的获取较为麻烦 建议使用Contr
  • Android Studio 使用jni调用第三方so

    源码部分 项目需要调用第三方so函数 xff0c 由于需要调用的函数不符合jni规范 xff0c 这里用jni调用编写的native方法 xff0c native方法再调用三方so函数 Android mk LOCAL PATH 61 ca
  • 4年产品点滴心路——谈谈形而上的3个产品素质

    我是一名互联网产品人员 xff0c 曾供职过多家互联网公司 xff0c 包括一些员工数千的老牌龙头企业和一些初创公司 排除老生常谈的产品技能以及方法论 xff0c 我最近对一些大型企业初创项目 新型领域创业公司的产品人员的工作软实力有很大兴
  • 四年产品点滴心路(二)——互联网公司的组织规模与产品特点浅析

    新年伊始 xff0c 让我们放慢脚步 xff0c 回溯互联网服务长河的源头 xff1a 计算机技术 2000年以来 xff0c 国内普通大学里 xff0c 一位只要对计算机 软件有兴趣并打算在此行业长远发展的大学生 xff0c 大都经历过在
  • 云之彼端,牵手未来—— “我思故我在”—我眼中的第四届中国云计算大会

    一 xff0e 满怀激动踏征程 第四届全国云计算大会初体验 2012年5月23日至25日 业界瞩目的第四届中国云计算大会 xff08 以下简称 大会 xff09 在京隆重举行 本次大会由国家发展和改革委员会 工业和信息化部 北京市人民政府及
  • 落花渐欲迷人眼,移动前景看用户

    火红的深秋10月 xff0c 万众瞩目的第三届中国移动开发者大会于19日在北京国家会议中心如期举行 本次大会邀请到了诸多互联网巨头公司中相关项目负责人及移动互联先驱精英 xff0c 百家争艳齐聚一堂 xff0c 共同探讨在移动互联网高速发展
  • 新员工总结

    感谢29 日下午张宁主编为我们移动频道新员工安排的培训 通过本次员工培训 xff0c 在工作目标和方向上有了较为清晰的认识 xff0c 主要总结如下 xff1a 1 明确移动频道工作重心 xff1a 移动 应用 开发 围绕这三点 xff0c
  • 微软Win8开发马拉松感悟

    前几天前往微软win8开发者马拉松大赛 xff0c 对于微软中国有了一些了解 xff0c 也有了一些体悟 xff0c 在这里稍微记录一下 首先一点就是微软对于开发者的态度 在会场看到了许多沙发和抱枕 xff0c 还有毛毯等 xff0c 另外
  • C/C++ | g++ 编译指定了链接库路径,仍报错找不到函数:Undefined reference

    题外话 xff1a 这次是被编译顺序坑了很久 还是基础学的不扎实 实验背景 xff1a 用g 43 43 编译cpp文件 xff0c 依赖于opencv 待编译的cpp文件cv test cpp内容如下 xff1a include 34 o
  • 什么是end-to-end的模型

    端到端的模型目前很流行 xff0c 那么什么是端到端的模型呢 xff0c 有没有一个很比较明确的解释 xff1f 在 1 中 xff0c 作者是这样说的 The entire model is trained jointly from sc
  • 排序算法系列:归并排序(Merge sort)(C语言)

    通俗理解 xff1a 运用分而治之的思想 xff0c 编写递归函数 xff0c 将大数组排序转化为小数组排序 xff0c 最后再将其合并 void merge sort int p int low int high int mid 61 l
  • Android 框架问题分析案例 - 谁杀了桌面?

    写这篇文章的契机是因为一个实际遇到的问题 这个问题其实不难 不过在分析了这个问题然后写日记的时候 我突然觉得这个问题分析的过程有必要记录一下 分享给大家 分析过程中有用到一些工具 一些方法 也从另外一个聪明的小伙伴那里学到了一些分析技巧和工