最近实在是太忙了,抽空更新一问。
想到一个非常有意思的问题:
如果 app 启动了一个 Activity,那么在这个 Activity 展示的情况下,问题来了:
1.上述场景背后至少有多少个线程?
2.每个线程具体的作用是什么?
更多问答 >>
-
每日一问 | 玩转 Gradle,可不能不熟悉 Transform,那么,我要开始问了。
2020-10-26 23:45 -
每日一问 | 关于 RecyclerView$Adapter setHasStableIds(boolean)的一切
2020-10-26 23:44 -
每日一问 | 属性动画与硬件加速的相遇,不是你想的那么简单?
2020-10-26 23:45 -
每日一问 | 当Unsafe遇上final,超神奇的事情发生了?
2020-11-02 00:16 -
每日一问 | Call requires API level 23 (current min is 14) 扫描出来的原理是?
2020-12-27 22:39 -
2020-10-03 11:43
-
2020-09-09 23:54
-
2020-08-26 21:11
-
2020-08-23 23:54
-
每日一问 | apply plugin: 'com.android.application' 背后发生了什么?
2020-08-16 19:56
一个启动了Activity的进程会有多少个线程呢?
可以获取最顶层的线程组递归打印一下:熟悉ThreadGroup的同学会知道,在ThreadGroup下有两个静态成员变量,分别是systemThreadGroup
和mainThreadGroup
,mainThreadGroup
其实也是systemThreadGroup
的子线程组,所以我们只需要通过反射获取到systemThreadGroup
对象然后递归打印就行了,代码如下:日志输出:
可以看到,现在进程内一共有两个线程组:system和main。
Signal Catcher,好像挺眼熟的,但源码中搜不到,好吧,知识盲区了,我投降。接着往下看,有四个Daemon线程,随便选一个全局搜一下:HeapTaskDaemon: 用来释放堆内存的;
ReferenceQueueDaemon: 一些软、弱、虚引用的对象,当它们被回收时,会被添加到对应的ReferenceQueue中,这个操作就由ReferenceQueueDaemon来负责;
FinalizerDaemon: 用来回调【即将被回收的对象】的
finalize
方法;FinalizerWatchdogDaemon: 监视FinalizerDaemon线程,如果在回调【即将被回收的对象】的
finalize
方法时超过了100_0000_0000纳秒(即10秒),那么进程会被强行kill掉;最后一个,Profile Saver,不知道具体是做什么用的。
main线程组中的线程比较多:
main: 不用讲都知道是主线程;
Jit thread pool worker thread 0:不知是在哪里创建的线程池;
Binder:26573_1、Binder:26573_2、Binder:26573_3、Binder:26573_4:Bind通讯线程;
RenderThread:用来同步渲染BlockingGLTextureView的线程;
magnifier pixel copy result handler:不知道为什么会有这个;
queued-work-looper:这是一个HandlerThread(自带Looper);
DefaultDispatcher-worker-123:因为我的测试Demo用了协程,这几个都是coroutines库中的线程池;
拜服大佬
我是弟弟
Signal Catcher 是 art 中用于处理几个特殊信号的线程,比如kill -3这种方式可以dump出anr信息,就是这个线程处理的;Profile Saver这个线程则是和7.0时加的混合 ...查看更多
Signal Catcher 是 art 中用于处理几个特殊信号的线程,比如kill -3这种方式可以dump出anr信息,就是这个线程处理的;Profile Saver这个线程则是和7.0时加的混合编译有关,设备空闲时会根据profile对部分热点方法进行编译以提高运行速度,这个profile就是这个线程负责写入的。
学习了
细化一下四个 Binder 线程,分别是跟谁通信,感觉这个还比较重要。
学到了
哈哈哈,今天去看戏了,很晚才回来,没有看消息,我明天看一下
如果是从源码角度来分析,没我想像中那么简单。。。本来以为直接watch Thread的name再启动debug就能知道具体的调用链(全局搜不到相关代码),但是。。。当断点可用的时候,那四个binder ...查看更多
如果是从源码角度来分析,没我想像中那么简单。。。本来以为直接watch Thread的name再启动debug就能知道具体的调用链(全局搜不到相关代码),但是。。。当断点可用的时候,那四个binder线程早已存在了。我想了下,写一个xposed插件,在进程启动时去hook Thread对象的创建,应该就能拦截到。但是手头上没有安装了xp框架的手机,又不会写magisk插件。。。我今晚又买了台pixel2,打算专门用来做这些测试,等待发货中~
卧槽....你这买手机不是为了答题吧...
应用Binder线程,应该是应用启动的时候,就创建了,看下zygote关于应用启动的代码。。。。嗯,感觉有点费时间...
哈哈哈,不是,我本来是有一台有xposed环境的pixel2的,只是端午节的时候给了发小的妈妈用,没有带下来,迟早都要买的
是的,如果能hook到关键代码,就能省很多时间。AMS提供的am命令,最终也是会走到startActivity,但之前看这部分代码时,没有注意到线程创建这一块,不知道debug一下AMS能不能发现点什 ...查看更多
是的,如果能hook到关键代码,就能省很多时间。AMS提供的am命令,最终也是会走到startActivity,但之前看这部分代码时,没有注意到线程创建这一块,不知道debug一下AMS能不能发现点什么
xposed模块的话,需要注意一点,handleLoadPackage实际上是在handleBindApplication里回调的,太晚了,似乎只能在handleZygoteInit里开始hook ...查看更多
xposed模块的话,需要注意一点,handleLoadPackage实际上是在handleBindApplication里回调的,太晚了,似乎只能在handleZygoteInit里开始hook
是的,多谢提醒,刚刚我看了下XposedBridge的代码,handleLoadPackage确实是在handleBindApplication时才回调的,不过handleZygoteInit也是系统 ...查看更多
是的,多谢提醒,刚刚我看了下XposedBridge的代码,handleLoadPackage确实是在handleBindApplication时才回调的,不过handleZygoteInit也是系统进程才会走,所以对于普通应用来说,这个方法也不行。发现一个IXposedHookCmdInit,这个接口里面有个initCmdApp方法,它同样是在initForZygote之后回调,但在xposed那两个jar包里没找到这个类。。。所以还要看下这个东西要怎么使用
我记得handleZygoteInit是在zygote里回调的,在zygote里hook应该可行不过范围有点太大了;IXposedHookCmdInit这东西只有在直接使用app_process起非z ...查看更多
我记得handleZygoteInit是在zygote里回调的,在zygote里hook应该可行不过范围有点太大了;IXposedHookCmdInit这东西只有在直接使用app_process起非zygote进程的时候会回调,比如命令行里用am/pm之类命令的时候
大佬,能问你个问题吗?产品在其他app上抄了一个功能,屏幕解锁次数,还有通知次数。我下载了好几个app看过了,第一次安装的时候都能读取到数据最近一周的数据,并且几个app的数据都是准确的。所以我想不是 ...查看更多
大佬,能问你个问题吗?产品在其他app上抄了一个功能,屏幕解锁次数,还有通知次数。我下载了好几个app看过了,第一次安装的时候都能读取到数据最近一周的数据,并且几个app的数据都是准确的。所以我想不是通过广播的方式自己记录的。然后也没有找到对应的api。现在在看keyguard里面的源码,不过能力有限,没看出名堂,也不知道看的方向对不对。不知道大佬之前有没有查阅过相关的代码,指点下迷津
小缘已经提了一个遍历 ThreadGroup 的方式查看所有线程的方法,我这边再换个思路,利用 ANR 输出的 trances.txt 文件,查看当前进程的线程信息,会包含一些调用栈信息,信息稍微齐全一点。
原理:触发 ANR 时,会向目标进程发出 SIGNAL_QUIT 信号,Android App 进程跑在 ART 虚拟机之上,ART 虚拟机会捕获这个信号,然后输出当前进程下的线程信息到 traces.txt 中。
我这边用仅包含一个 Activity 的 App 启动后,模拟一个 ANR,再查看 traces.txt 文件。
线程的含义,小缘的回答已经说明白了,我这里不赘述了,仅单独看几个线程的信息。
主线程 - main
Daemon 线程:HeapTaskDaemon
Binder 线程
ps:小缘应该是在 Android 7.0 之后的设备上测试的,所以 Binder 线程的命名是 Binder:< pid >_x 的格式,我跑的模拟器是 Android 6.0 的,还保持之前 Binder_x 的命名。
另外不同 Android 版本的线程数也有差异,大家参考一下即可。
意外发现:
大家都知道,在大多数情况下,app崩溃后,系统会弹出一个 “xxx已停止运行” 的对话框。那系统是怎么知道app是因为异常崩溃了呢?其实是这样的:在进程初始化时,ZygoteInit的main
方法通过zygoteInit
获取ActivityThread.main
入口之前,会先经过commonInit
方法来给当前线程(也就是主线程)set一个UncaughtExceptionHandler,代码:可以看到,在
到最后,还会手动kill进程,退出虚拟机。uncaughtException
方法中,先是打印log,停止MethodTracing,然后调用了ActivityManager的handleApplicationCrash
方法,看注释就知道,这个方法会弹出Crash Dialog。-u 代表指定特定用户
-T 显示线程信息-O 代表在默认属性列的基础上增加要显示的属性列TCNT 代表线程数量
刚刚debug AMS的时候无意中发现system_process进程竟然有一百二十多个线程,快来看看有没有你熟悉的~
emmm,抛出个ANR里面抓一下anr的trace log 里面会有当前所有的线程
好像有个jdk自带自带的Hsdb可以看线程