那么这里就可以简单还原问题了 , 测试报的是 从应用返回桌面 , 桌面图标加载慢 , 从 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
@RequiresPermission(Manifest.permission.KILL_BACKGROUND_PROCESSES)
public
《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》
【docs.qq.com/doc/DSkNLaERkbnFoS0ZF】 完整内容开源分享
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 的生死存亡).
过令我感到意外的是 android.permission.KILL_BACKGROUND_PROCESSES 这个权限 Google 居然放的这么松 , 我一直以为这个权限是要专门申请以防止 App 滥用或者卵用的(毕竟涉及到其他 App 的生死存亡).
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)