ANR系列之ContentProvider类型原理讲解

news/2024/5/3 8:22:01/文章来源:https://blog.csdn.net/AA5279AA/article/details/128039319

前言:

众所周知,ANR一共有四种类型,如下:

1.输入事件类型ANR

2.广播类型ANR

3.ContentProvider类型ANR

4.Service类型ANR

四种类型的超时时间如下所示:

所以ANR系列文章也会分为5篇文章来进行讲解,本篇是该系列的第三篇文章,主要讲解Provider类型的ANR问题是如何触发的。

本文主要会讲解以下内容:

1.provider类型的ANR在系统侧的处理流程;

2.provider类型的ANR在应用侧如何触发;

3.ContentProviderClient的使用;

4.什么场景下,可以触发provider类型的ANR。

另外,本文和以前讲ANR流程有所不一样,之前的流程,都是正向的,从调用方开始一步一步的往后讲。而本文,则反过来,从ANR触发时刻开始,往前一步一步找寻调用方。

PS:阅读本文前,建议阅读下面的文章,做好知识储备,方便本文的理解。

android源码-ContentProvider实现原理分析_失落夏天的博客-CSDN博客

一.Provider类型ANR如何触发?

1.1 Provider类型ANR的触发点

首先,其实ANR本身是不区分类型,并没有文章开头所说的4种类型。我们之所以人为的去区分ANR类型,是因为有四种场景可以触发ANR并且触发条件和内容都不相同。

所以我们也找一下,Provider类型的ANR是如何触发的,搜遍了整个AOSP的代码,我们发现只有一个地方是ContentProvider类型的ANR,在ContentProviderHelper的appNotRespondingViaProvider方法中,代码如下:

void appNotRespondingViaProvider(IBinder connection) {mService.enforceCallingPermission(android.Manifest.permission.REMOVE_TASKS,"appNotRespondingViaProvider()");...try {final ProcessRecord host = conn.provider.proc;if (host == null) {Slog.w(TAG, "Failed to find hosting ProcessRecord");return;}mService.mAnrHelper.appNotResponding(host, "ContentProvider not responding");} finally {Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);}}

我们可以看到,这里会提示ContentProvider not responding,这就是Provider类型ANR的来源。

1.1 Provider类型ANR的触发流程

为了方面读者理解整个ANR的流程,我画了一张流程图,方便理解,整个流程还是比较简单的。

 

1.1.1应用侧发出信号

首先,ContentProviderClient类中,存在一个内部类对象NotRespondingRunnable,其实现了接口Runnable,我们可以把其当作一个任务。

private class NotRespondingRunnable implements Runnable {@Overridepublic void run() {Log.w(TAG, "Detected provider not responding: " + mContentProvider);mContentResolver.appNotRespondingViaProvider(mContentProvider);}}

等到这个任务执行的时候,就会调用ContentResolver的appNotRespondingViaProvider方法,这里的mContentResolver的实现类是ContentImpl中的ApplicationContentResolver。

所以,我们看一下其中的appNotRespondingViaProvider方法,如下:

        @Overridepublic void appNotRespondingViaProvider(IContentProvider icp) {mMainThread.appNotRespondingViaProvider(icp.asBinder());}

也就是通知到了ActivityThread中的appNotRespondingViaProvider方法,这个方法中的功能就是通知到系统侧的进程,代码如下:

final void appNotRespondingViaProvider(IBinder provider) {synchronized (mProviderMap) {ProviderRefCount prc = mProviderRefCountMap.get(provider);if (prc != null) {try {ActivityManager.getService().appNotRespondingViaProvider(prc.holder.connection);} catch (RemoteException e) {throw e.rethrowFromSystemServer();}}}}

1.1.2系统侧接收

在APP侧的信号发出后,AMS的appNotRespondingViaProvider方法会收到这个通知,然后交给ContentProviderHelper来处理,我们来看一下其中的处理方法appNotRespondingViaProvider。

 void appNotRespondingViaProvider(IBinder connection) {mService.enforceCallingPermission(android.Manifest.permission.REMOVE_TASKS,"appNotRespondingViaProvider()");final ContentProviderConnection conn = (ContentProviderConnection) connection;if (conn == null) {Slog.w(TAG, "ContentProviderConnection is null");return;}ActivityManagerService.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,"appNotRespondingViaProvider: ",(conn.provider != null && conn.provider.info != null? conn.provider.info.authority : ""));try {final ProcessRecord host = conn.provider.proc;if (host == null) {Slog.w(TAG, "Failed to find hosting ProcessRecord");return;}mService.mAnrHelper.appNotResponding(host, "ContentProvider not responding");} finally {Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);}}

首先,会进行一个权限检查,只有拥有REMOVE_TASKS的应用才允许发送。普通应用,是不可能拥有这个权限的,所以,发送ANR超时的,一定是系统应用。

然后,查看binder链接是否还存在,如果不存在,也没有必要进行后续的流程了。

最后,委托给ANRHelper进行后续的ANR流程,这里,也打印出那个象征个Provider类型的日志:ContentProvider not responding。

通过如上的介绍,我们可以知道,Provider类型的ANR区别于点击事件以及广播,它是应用主动发出的ANR通知,而不是系统侧进行的监控。那么,我们接下来就看看,APP是如何触发这种类型的ANR的。

二.APP侧如何触发Provider

讲触发原因之前,我们首先要讲一讲ContentProviderClient的使用。

2.1 ContentProviderClient的使用

上一篇文章中,我们有介绍了ContentProviderClient的使用,为了方便直接阅读本文的读者,我们这里就稍稍赘述一下,内容和上一篇文章是一样的。

使用方式如下:

 ContentValues values = new ContentValues();values.put("key_main", "value_main");String AUTHORITY = "com.xt.client.android_startup.multiple";Uri uri = Uri.parse("content://" + AUTHORITY);ContentProviderClient client = getContentResolver().acquireContentProviderClient(uri);try {int query = client.update(uri, values, null, null);Log.i("lxltest", "query:" + query);} catch (RemoteException e) {e.printStackTrace();}

ContentProviderClient简单来说,就是不用每次都去查询那个binder的引用,而直接使用同一个对象进行处理。

2.2 provider类型ANR监控原理

正常的provider的使用方法是没有ANR监控的,有监控的只存在于使用ContentProviderClient的类型中。

我们仍然以update为例,我们看一下ContentProviderClient的update方法:
 

@Overridepublic int update(@NonNull Uri url, @Nullable ContentValues values, @Nullable Bundle extras)throws RemoteException {Objects.requireNonNull(url, "url");beforeRemote();try {return mContentProvider.update(mAttributionSource, url, values, extras);} catch (DeadObjectException e) {if (!mStable) {mContentResolver.unstableProviderDied(mContentProvider);}throw e;} finally {afterRemote();}}

这里的核心就是beforeRemote,我们看一下这个方法:

private void beforeRemote() {if (mAnrRunnable != null) {sAnrHandler.postDelayed(mAnrRunnable, mAnrTimeout);}}

如果mAnrRunnable不为空,则就是通过一个延时任务去执行。而这个mAnrRunnable对象就是我们上面介绍的NotRespondingRunnable。所以我们接下来,就看下mAnrRunnable对象何时设置的,这个方法是setDetectNotResponding。

@SystemApi@RequiresPermission(android.Manifest.permission.REMOVE_TASKS)public void setDetectNotResponding(@DurationMillisLong long timeoutMillis) {synchronized (ContentProviderClient.class) {mAnrTimeout = timeoutMillis;if (timeoutMillis > 0) {if (mAnrRunnable == null) {mAnrRunnable = new NotRespondingRunnable();}if (sAnrHandler == null) {sAnrHandler = new Handler(Looper.getMainLooper(), null, true /* async */);}// If the remote process hangs, we're going to kill it, so we're// technically okay doing blocking calls.Binder.allowBlocking(mContentProvider.asBinder());} else {mAnrRunnable = null;// If we're no longer watching for hangs, revert back to default// blocking behavior.Binder.defaultBlocking(mContentProvider.asBinder());}}}

所以,就是Provider类型的ANR的秘密,只要通过ContentProviderClient的setDetectNotResponding方法进行配置,就可以让ContentProviderClient具体有ANR的功能。每次增删改查的时候,都记录一个延时任务,如果按时完成则取消任务,否则执行任务。而这个任务一旦执行,就会触发ANR的流程。

2.3 普通的APP可以用吗?

但是实际上,好像我们很少遇到provider类型的ANR,这又是为何呢?

其答案就在于这个功能,并非提供给所有应用的,而只是提供给系统级应用。

首先,2.2中的代码中我们也可以看到,这是一个SytemApi,普通应用是无法调用的。

其次,就算我们通过反射调用了setDetectNotResponding方法,仍然是无法生效的。因为上面1.1.2中讲到,只有具有REMOV_TASK权限的APP才能发送这样的通知,否则会给APP侧抛出异常。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_227316.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

管理最忌讳用权管人

阅读本文大概需要 1.66 分钟。最近星球在更新一些系列课程,其中有一节课叫「怎样从技术人转型管理者?」应该很适合大多读者,毕竟关注我的读者里,做技术做管理的居多,所以这篇也发这里给大家分享下。程序员做技术的&…

WebView2 通过 PuppeteerSharp 实现爬取 王者 壁纸 (案例版)

王者壁纸自动化获取逻辑分析 其实它的逻辑很简单, 就是王者的官网,打开后,在右下角就看到了皮肤页面部分。 这个时候,点击更多,就会打开全部英雄详情的页面。 这个时候,单点任意一个英雄,就会…

Rust机器学习之Linfa

Rust机器学习之Linfa 众所周知,Python之所以能成为机器学习的首选语言,与其丰富易用的库有很大关系。某种程度上可以说是诸如numpy、pandas、scikit-learn、matplotlib、pytorch、networks…等一系列科学计算和机器学习库成就了Python今天编程语言霸主的…

DDOS防护如何建设?

数字化转型发展也推动了云计算、人工智能、大数据、物联网等新一代信息技术应用普及,与此同时,新时代的发展也带来了新的网络威胁和新的安全需求。我们不难发现,近年网络攻击时间层出不穷,全球范围来看,企业因遭受网络…

CrossOver软件2022可以使苹果MAC电脑运行Windows软件应用

面对安装双系统时的繁琐步骤,以及虚拟机软件那庞大的体积,CrossOver的出现,让一切都变得简单起来。 CrossOver自带的一系列的Windows应用,涵盖游戏软件、办公软件、设计软件等多个种类。它轻巧的体积,便捷的操作步骤无…

国鸿氢能冲刺港股:年亏损7亿 云浮工业园与青岛城投是股东

雷递网 雷建平 11月28日国鸿氢能科技(嘉兴)股份有限公司(简称:“国鸿氢能”)日前递交招股书,准备在港交所上市。年亏损7亿国鸿氢能成立于2015年6月,是一家以氢燃料电池为核心产品的企业&#x…

字符串压缩(二)之LZ4

一、LZ4压缩与解压 LZ4有两个压缩函数。默认压缩函数原型: int LZ4_compress_default(const char* src, char* dst, int srcSize, int dstCapacity); 快速压缩函数原型: int LZ4_compress_fast (const char* src, char* dst, int srcSize, int dstCapaci…

如何用潜类别混合效应模型(Latent Class Mixed Model ,LCMM)分析老年痴呆年龄数据

全文下载链接:http://tecdat.cn/?p24647线性混合模型假设 N 个受试者的群体是同质的,并且在群体水平上由独特的曲线 Xi(t)β 描述(点击文末“阅读原文”获取完整代码数据)。相关视频背景和定义相比之下,潜在类别混合模…

【毕业设计】24-基于单片机的电子显示屏的设计与应用(原理图+源码+仿真工程+论文+答辩PPT)

【毕业设计】24-基于单片机的电子显示屏的设计与应用(原理图源码仿真工程论文答辩PPT) 文章目录任务书设计说明书摘要设计框架架构设计说明书及设计文件源码展示任务书 主要研究内容: 通过查阅资料,掌握单片机基本工作原理&#…

【STM32备忘录】二、FSMC做LCD控制器,使用stm32cube配置示例

文章目录1. FSMC框图2. 配置示例(1) cube配置(2) 代码参考*疑问1. FSMC框图 如果屏幕接口8位数据宽度访问,地址线FSMC_A[25:0], 一共26位,一个块22667108864Byte64MB,如果屏幕接口16位数据宽度访问,地址线FSMC_A[25:0], 一共26位&…

鸿蒙全量源代码在线阅读

目录 前言 下载方式复杂 占用空间大 搜索效率低 本项目目标 服务器地址 使用手册 源码浏览服务 标识符搜索 普通文本搜索 代码比较 写在最后 前言 当前,OpenHarmony项目持续发展,其代码量已经超过了20G字节的存储占用空间,对于一…

基于人工蜂群算法的线性规划求解matlab程序

基于人工蜂群算法的线性规划求解matlab程序 1 人工蜂群算法概述 2005年D. Karaboga教授仿照蜜蜂集群采蜜生物行为,提出了人工蜂群仿生算法,可以有效解决有关函数优化等相关难题。ABC算法仿照蜜蜂蜂群中不同蜂种相互协作,蜂群间进行角色转换的…

不同类型的 SSL 证书解释

了解不同类型的 SSL 证书:扩展验证 (EV)、组织验证 (OV) 和域名验证 (DV)。 查看用例及更多。 SSL/TLS 证书用于验证网站的身份并在服务器和浏览器之间创建安全连接。有许多不同类型的 SSL 证书选项可用,它们都有其独特的用例和价值主张。证书颁发机构 …

电磁仿真设计RMxprt-6p72s电励磁凸极同步电机分析案例

作者 | 电机设计青年 仿真秀专栏作者 导读:大家好,我是仿真秀专栏作者——电机设计青年,曾担任ANSYS低频电磁工程师一职,后入职电机企业,一直从事电机产品研发工作。研究的电机类型涉及电励磁同步电机、永磁同步电机、…

MIT发现语言模型内的事实知识可被修改??

文 | 小伟前言众所周知,自回归语言模型(如GPT-2)里存储着大量的事实知识,比如语言模型可以正确的预测出埃菲尔铁塔所在的城市是巴黎市。那么语言模型是在什么地方存储这些知识呢?我们是否可以修改存储在语言模型里的知识呢?来自于…

R语言分布滞后非线性模型(DLNM)研究发病率,死亡率和空气污染示例

全文下载链接:http://tecdat.cn/?p21317本文提供了运行分布滞后非线性模型的示例,同时描述了预测变量和结果之间的非线性和滞后效应,这种相互关系被定义为暴露-滞后-反应关联(点击文末“阅读原文”获取完整代码数据)。…

[附源码]计算机毕业设计springboot本地助农产品销售系统

项目运行 环境配置: Jdk1.8 Tomcat7.0 Mysql HBuilderX(Webstorm也行) Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。 项目技术: SSM mybatis Maven Vue 等等组成,B/S模式 M…

小程序上新(2022.11.15~11.28)

20221115 小程序基础库 2.27.3 更新 更新 框架 设备 VoIP 能力授权更新 框架 支持 worker 代码打包到小程序&小游戏分包 详情更新 组件 scroll-view 接近全屏尺寸时默认开启点击回到顶部更新 API createVKSession 在不需要用到摄像头的时候不再发起摄像头授权 详情修复 框…

【笔试强训】Day 4

🌈欢迎来到笔试强训专栏 (꒪ꇴ꒪(꒪ꇴ꒪ )🐣,我是Scort目前状态:大三非科班啃C中🌍博客主页:张小姐的猫~江湖背景快上车🚘,握好方向盘跟我有一起打天下嘞!送给自己的一句鸡汤&#x…

王道考研——操作系统(第三章 内存管理)

一、内存的基础知识 什么是内存?有何作用? 这么做的原因是,程序本来是放在外存中的,放在磁盘中的,但是磁盘的读写速度很慢,而cpu的处理速度又很快 存储单元就是存放数据的最小单元,每一个地址…