由Ctrl+Z引发的系统卡死重启问题分析

简介: 起因JT同学拿着手机来找我说用着用着自动重启了,让我看一下,我抓出bugreport一看是system server发生watchdog重启了,然后接着看了一下traces,发现traces比较诡异。

起因

JT同学拿着手机来找我说用着用着自动重启了,让我看一下,我抓出bugreport一看是system server发生watchdog重启了,然后接着看了一下traces,发现traces比较诡异。

初步分析

为什么说traces诡异?暂且一看

traces中的线程状态

都被thread 31持有的锁给block了,那就看看thread 31在搞什么飞机?

"InputDispatcher" prio=10 tid=31 Native
  | group="main" sCount=1 dsCount=0 obj=0x133d90a0 self=0x7f73f8c800
  | sysTid=1662 nice=-8 cgrp=default sched=0/0 handle=0x7f5f80b440
  | state=S schedstat=( 1388341757 1177043722 12975 ) utm=81 stm=57 core=2 HZ=100
  | stack=0x7f5f70f000-0x7f5f711000 stackSize=1013KB
  | held mutexes=
  kernel: (couldn't read /proc/self/task/1662/stack)
  native: #00 pc 00000000000684e0  /system/lib64/libc.so (__ioctl+4)
  native: #01 pc 0000000000072508  /system/lib64/libc.so (ioctl+100)
  native: #02 pc 000000000002d584  /system/lib64/libbinder.so (_ZN7android14IPCThreadState14talkWithDriverEb+164)
  native: #03 pc 000000000002e050  /system/lib64/libbinder.so (_ZN7android14IPCThreadState15waitForResponseEPNS_6ParcelEPi+104)
  native: #04 pc 000000000002e2c4  /system/lib64/libbinder.so (_ZN7android14IPCThreadState8transactEijRKNS_6ParcelEPS1_j+176)
  native: #05 pc 0000000000025654  /system/lib64/libbinder.so (_ZN7android8BpBinder8transactEjRKNS_6ParcelEPS1_j+64)
  native: #06 pc 00000000000e02cc  /system/lib64/libandroid_runtime.so (???)
  native: #07 pc 0000000000505e64  /data/dalvik-cache/arm64/system@framework@boot.oat (Java_android_os_BinderProxy_transactNative__ILandroid_os_Parcel_2Landroid_os_Parcel_2I+200)
  at android.os.BinderProxy.transactNative(Native method)
  at android.os.BinderProxy.transact(Binder.java:503)
  at android.app.IActivityController$Stub$Proxy.activityStarting(IActivityController.java:172)
  at com.android.server.am.ExtraActivityManagerService.checkStartActivityLocked(ExtraActivityManagerService.java:259)
  at com.android.server.am.ExtraActivityManagerService.checkStartActivityPermission(ExtraActivityManagerService.java:207)
  - locked <0x025805bb> (a com.android.server.am.ActivityManagerService)
  at com.android.server.am.ActivityStackSupervisor.startActivityMayWait(ActivityStackSupervisor.java:983)
  at com.android.server.am.ActivityManagerService.startActivityAsUser(ActivityManagerService.java:3962)
  at android.app.ContextImpl.startActivityAsUser(ContextImpl.java:696)
  at android.app.ContextImpl.startActivityAsUser(ContextImpl.java:675)
  at com.android.server.policy.PhoneWindowManager.startActivityAsUser(PhoneWindowManager.java:3250)
  at com.android.server.policy.PhoneWindowManager.startDockOrHome(PhoneWindowManager.java:6545)
  at com.android.server.policy.PhoneWindowManager.launchHomeFromHotKey(PhoneWindowManager.java:3391)
  at com.android.server.policy.PhoneWindowManager.launchHomeFromHotKey(PhoneWindowManager.java:3342)
  at com.android.server.policy.BaseMiuiPhoneWindowManager.interceptKeyBeforeDispatching(BaseMiuiPhoneWindowManager.java:643)
  at com.android.server.wm.InputMonitor.interceptKeyBeforeDispatching(InputMonitor.java:375)
  at com.android.server.input.InputManagerService.interceptKeyBeforeDispatching(InputManagerService.java:1751)

调用ActivityController的activityStarting接口时阻塞了?

这里说明一下,通过名字我们大概能猜到ActivityController的作用,简单来说就是一个监控器,提供的接口如下:

/**
 * Testing interface to monitor what is happening in the activity manager
 * while tests are running.  Not for normal application development.
 * {@hide}
 */
interface IActivityController
{
    /**
     * The system is trying to start an activity.  Return true to allow
     * it to be started as normal, or false to cancel/reject this activity.
     */
    boolean activityStarting(in Intent intent, String pkg);

    /**
     * The system is trying to return to an activity.  Return true to allow
     * it to be resumed as normal, or false to cancel/reject this activity.
     */
    boolean activityResuming(String pkg);

    /**
     * An application process has crashed (in Java).  Return true for the
     * normal error recovery (app crash dialog) to occur, false to kill
     * it immediately.
     */
    boolean appCrashed(String processName, int pid,
            String shortMsg, String longMsg,
            long timeMillis, String stackTrace);

    /**
     * Early call as soon as an ANR is detected.
     */
    int appEarlyNotResponding(String processName, int pid, String annotation);

    /**
     * An application process is not responding.  Return 0 to show the "app
     * not responding" dialog, 1 to continue waiting, or -1 to kill it
     * immediately.
     */
    int appNotResponding(String processName, int pid, String processStats);

    /**
     * The system process watchdog has detected that the system seems to be
     * hung.  Return 1 to continue waiting, or -1 to let it continue with its
     * normal kill.
     */
    int systemNotResponding(String msg);
}

为什么调用一下这个ActivityController的activityStarting就被block了呢?这个ActivityController是谁?在那个进程中?

继续往下分析,看看都有谁实现了ActivityController
ActivityController

比较可疑的有两个,一个是monkey的,一个是Am的,然后就问了一下JT同学问题发生的场景,是不是在做monkey测试或者执行adb shell am相关的命令操作?他说是的,问题发生当时在执行am命令。

好,问题有了一点眉目,但是为什么执行am命令会导致阻塞并重启呢?继续看代码

        @Override
        public boolean activityStarting(Intent intent, String pkg) {
            synchronized (this) {
                System.out.println("** Activity starting: " + pkg);
            }
            return true;
        }

执行activityStarting需要ActivityController自己本身的锁,如果这个时候拿不到锁就会block system server,那就继续看看这个锁还会被谁用,看了一圈代码,发现锁的粒度都非常小,不像会block的样子,这就是上面为什么说traces比较诡异的原因,block在了不应该block的地方,那接下来怎么办呢?

深入分析

通过初步分析我们觉得调用ActivityController的activityStarting不应该被block,而这次调用是一个binder call,跨进程的,有没有可能没有到达am进程那边?或者am进程出了什么问题?或者另有隐情?赶紧再问问JT同学当时的操作步骤,看能不能重现问题,然后dump一下相关信息,JT同学不愧是专业的测试,操作现场还保留着,执行的一堆命令也还在终端上,赶紧再操作一遍

ps | grep ^u
am monitor
ctrl+z

问题奇迹复现了,点击一个icon去startactivity之后系统就卡死了,赶紧在一分钟内看看am进程的信息

ps | grep am

没有am的信息?那就看看app_process

ps | grep app_process

原来am小伙通过app_process起来之后连名字都没改。。。。

等等,我好像擦觉到了一丝异常?上面为什么要用ctrl+z?赶紧问JT同学,他说这是HH同学敲的命令,难道HH同学是想停止am monitor继续在终端里面输命令吗?如果同样的需求我都是用ctrl+c的啊?他为啥要用ctrl+z,有特别的含义吗?赶紧去问一下HH同学,他说他只是想停止am monitor继续在终端里面输命令,没有特殊含义,而且他都是这么用的?这下问题就看到曙光了,这两个组合键操作虽然都能满足停止当前任务继续输入其他命令的需求,但是ctrl+z和ctrl+c是有本质区别的,在Linux下区别是什么呢?

ctrl-c: ( kill foreground process ) 发送 SIGINT 信号给前台进程组中的所有进程,强制终止程序的执行
ctrl-z: ( suspend foreground process ) 发送 SIGTSTP 信号给前台进程组中的所有进程,常用于挂起一个进程,而并
            非结束进程,用户可以使用使用fg/bg操作恢复执行前台或后台的进程。fg命令在前台恢复执行被挂起的进
            程,此时可以使用ctrl-z再次挂起该进程,bg命令在后台恢复执行被挂起的进程,而此时将无法使用ctrl-z
            再次挂起该进程;
            一个比较常用的功能:
                   正在使用vi编辑一个文件时,需要执行shell命令查询一些需要的信息,可以使用ctrl-z挂起vi,等执行                   完shell命令后再使用fg恢复vi继续编辑你的文件(当然,也可以在vi中使用!command方式执行shell命令,
            但是没有该方法方便)。
ctrl-d: ( Terminate input, or exit shell ) 一个特殊的二进制值,表示 EOF,作用相当于在终端中输入exit后回车;

类似的组合键操作还有以下几个:

ctrl-/    发送 SIGQUIT 信号给前台进程组中的所有进程,终止前台进程并生成 core 文件
ctrl-s   中断控制台输出
ctrl-q   恢复控制台输出
ctrl-l    清屏

看到这里我想有些同学可能已经知道问题的原因了,am monitor执行之后,am进程会向AMS注册一个ActivityController,启动一个activity的时候会回调ActivityController的activityStarting接口,但是HH同学用Ctrl+Z挂起am进程之后,AMS在通过binder call activityStarting的时候就被block了,因为activityStarting是同步调用,虽然binder driver把这次调用的transaction放到了am进程的todo list里面,但是am进程因为是STOPED状态所以不会拿到时间片去执行todo list里面的transaction,进而也不会有reply,就这样system server就被卡住了,瞬间又加重了Android系统的脆弱感。。。

到这就结束了吗?当然没有,我们细心的JT同学又发现说好的一分钟watchdog重启,都等了好几分钟了怎么还没有重启?好问题,继续看代码
watchdog

代码是最清晰、最好的解释,原来watchdog线程也依赖ActivityController,会调用ActivityController的systemNotResponding,从而导致连watchdog线程也被卡住了,本来说好的一分钟重启就做不到了,近在咫尺的重启代码执行不了,连GOODBYE也没出来就死了,哎,生活就是这样,这就是生活。。。。

                Slog.w(TAG, "*** GOODBYE!");
                Process.killProcess(Process.myPid());
                System.exit(10);

下一步动作

虽然生活总让人无奈,但我们还是要想办法做的更好,接下来会尝试改善watchdog线程依赖ActivityController的机制,不能因为ActivityController出了问题就永远卡住系统,之前就分析过一个monkey导致的系统永远卡住的问题,也是因为在调用ActivityController的systemNotResponding时候卡住:由MONKEY测试引发的跨多个进程的ANDROID系统死锁问题分析

通过下面的步骤可以在所有Android手机上复现这个问题:

am monitor
ctrl+z
随便点击一个桌面图标或者按下home键
目录
相关文章
|
20天前
|
存储 人工智能 测试技术
小鱼深度评测 | 通义灵码2.0,不仅可跨语言编码,自动生成单元测试,更炸裂的是集成DeepSeek模型且免费使用,太炸裂了。
小鱼深度评测 | 通义灵码2.0,不仅可跨语言编码,自动生成单元测试,更炸裂的是集成DeepSeek模型且免费使用,太炸裂了。
141061 20
小鱼深度评测 | 通义灵码2.0,不仅可跨语言编码,自动生成单元测试,更炸裂的是集成DeepSeek模型且免费使用,太炸裂了。
|
19天前
|
人工智能 运维 前端开发
基于阿里百炼的DeepSeek-R1满血版模型调用【零门槛保姆级2084小游戏开发实战】
本文介绍基于阿里百炼的DeepSeek-R1满血版模型调用,提供零门槛保姆级2048小游戏开发实战。文章分为三部分:定位与核心优势、实战部署操作指南、辅助实战开发。通过详细步骤和案例展示,帮助开发者高效利用DeepSeek-R1的强大推理能力,优化游戏逻辑与视觉效果,解决官网响应延迟问题,提升开发效率和用户体验。适合企业开发者、教育行业及多模态探索者使用。
70896 17
基于阿里百炼的DeepSeek-R1满血版模型调用【零门槛保姆级2084小游戏开发实战】
|
27天前
|
人工智能 自然语言处理 Shell
深度评测 | 仅用3分钟,百炼调用满血版 Deepseek-r1 API,百万Token免费用,简直不要太爽。
仅用3分钟,百炼调用满血版Deepseek-r1 API,享受百万免费Token。阿里云提供零门槛、快速部署的解决方案,支持云控制台和Cloud Shell两种方式,操作简便。Deepseek-r1满血版在推理能力上表现出色,尤其擅长数学、代码和自然语言处理任务,使用过程中无卡顿,体验丝滑。结合Chatbox工具,用户可轻松掌控模型,提升工作效率。阿里云大模型服务平台百炼不仅速度快,还确保数据安全,值得信赖。
358010 62
深度评测 | 仅用3分钟,百炼调用满血版 Deepseek-r1 API,百万Token免费用,简直不要太爽。
|
23天前
|
人工智能 自然语言处理 API
快速使用 DeepSeek-R1 满血版
DeepSeek是一款基于Transformer架构的先进大语言模型,以其强大的自然语言处理能力和高效的推理速度著称。近年来,DeepSeek不断迭代,从DeepSeek-V2到参数达6710亿的DeepSeek-V3,再到性能比肩GPT-4的DeepSeek-R1,每次都带来重大技术突破。其开源策略降低了AI应用门槛,推动了AI普惠化。通过阿里云百炼调用满血版API,用户可以快速部署DeepSeek,享受高效、低成本的云端服务,最快10分钟完成部署,且提供免费token,极大简化了开发流程。
191010 23
快速使用 DeepSeek-R1 满血版
|
8天前
|
人工智能 搜索推荐 数据可视化
Manus:或将成为AI Agent领域的标杆
随着人工智能技术的飞速发展,AI Agent(智能体)作为人工智能领域的重要分支,正逐渐从概念走向现实,并在各行各业展现出巨大的应用潜力。在众多AI Agent产品中,Manus以其独特的技术优势和市场表现,有望成为该领域的标杆。作为资深AI工程师,本文将深入探讨Manus的背景知识、主要业务场景、底层原理、功能的优缺点,并尝试使用Java搭建一个属于自己的Manus助手,以期为AI Agent技术的发展和应用提供参考。
11070 13
|
8天前
|
机器学习/深度学习 人工智能 测试技术
阿里云百炼已上线超强推理开源模型QwQ-32B,尺寸更小,性能比肩DeepSeek满血版
通义千问团队推出了320亿参数的QwQ-32B模型,通过大规模强化学习和多阶段训练,在数学、编程及通用能力上达到或超越了DeepSeek-R1等先进模型。QwQ-32B模型已在阿里云百炼上线,支持API调用,用户可通过官方文档了解详细使用方法。未来,团队将继续探索智能体与RL集成,推动人工通用智能的发展。
|
25天前
|
机器学习/深度学习 人工智能 自然语言处理
快来零门槛、即刻拥有 DeepSeek-R1 满血版
随着人工智能技术的发展,DeepSeek作为一款新兴推理模型,凭借强大的技术实力和广泛的应用场景崭露头角。本文基于阿里云提供的零门槛解决方案,评测DeepSeek的部署与使用。该方案支持多模态任务,涵盖文本生成、代码补全等,融合NLP、IR和ML技术,提供快速实现AI应用的便利。用户无需编码,最快5分钟、最低0元即可部署DeepSeek模型。阿里云还提供100万免费Token,适合预算有限的个人或小型团队试用。通过Chatbox客户端配置API,用户可轻松体验智能交互功能,如数学提问和代码书写等。
37603 5
|
20天前
|
人工智能 编解码 算法
DeepSeek加持的通义灵码2.0 AI程序员实战案例:助力嵌入式开发中的算法生成革新
本文介绍了通义灵码2.0 AI程序员在嵌入式开发中的实战应用。通过安装VS Code插件并登录阿里云账号,用户可切换至DeepSeek V3模型,利用其强大的代码生成能力。实战案例中,AI程序员根据自然语言描述快速生成了C语言的base64编解码算法,包括源代码、头文件、测试代码和CMake编译脚本。即使在编译错误和需求迭代的情况下,AI程序员也能迅速分析问题并修复代码,最终成功实现功能。作者认为,通义灵码2.0显著提升了开发效率,打破了编程语言限制,是AI编程从辅助工具向工程级协同开发转变的重要标志,值得开发者广泛使用。
7908 68
DeepSeek加持的通义灵码2.0 AI程序员实战案例:助力嵌入式开发中的算法生成革新
|
7天前
|
机器学习/深度学习 弹性计算 搜索推荐
真正的0代码,0脚本,0门槛,QwQ-32B一键部署!
阿里云最新发布的QwQ-32B模型通过强化学习显著提升了推理能力,在多个核心指标上达到DeepSeek-R1满血版水平,超越了DeepSeek-R1-Distill-Qwen-32B。用户可通过阿里云系统运维管理(OOS)的公共扩展功能,一键部署OpenWebUI+Ollama至ECS,轻松运行QwQ-32B模型。该方案支持本地部署和连接阿里云百炼在线模型,无需编写代码,操作简便,适合新手尝试。具体步骤包括:在阿里云控制台安装OpenWebUI扩展、选择ECS实例并创建、等待几分钟后获取URL链接,即可开始使用。此外,还提供了详细的配置指南和高级玩法介绍,帮助用户更好地利用该模型。
|
10天前
|
开发者 异构计算
高效部署通义万相Wan2.1:ComfyUI文生/图生视频实战,工作流直取!
通义万相Wan2.1开源不到一周,已登顶HuggingFace Model 和 Space 榜双榜首,在HuggingFace和ModelScope平台的累计下载量突破100万次,社区热度持续攀升!为响应小伙伴们对ComfyUI工作流运行Wan2.1的强烈需求,社区开发者整理了实战教程👇
1283 21
高效部署通义万相Wan2.1:ComfyUI文生/图生视频实战,工作流直取!