aosp12 framework重大bug:contentprovider获取低概率偶现延时10s问题修复经验分享

news2024/11/24 14:00:34

问题背景:

在android12的版本上,陆陆续续发现一个低概率偶现的问题,那就是桌面第一次启动会存在显示空白10s以上,正常空白一般在1-2s,在个空白10s以上确实就属于非常严重的问题,但这个是一个低概率偶现问题,而且只有一例,所以说一直也没有引起重视。直到陆续确实有测试都报有这个同样问题,这个时候就开始要着力重点解决,这里分享一下针对这种低概率偶现问题的处理方式,这种方式适合所有framework端的一些低概率的偶现问题解决。
更多framework干货知识手把手教学

Log.i("千里马qq群",“422901085);

framework层面低概率偶现问题处理方法

这里主要分享一下公司里面是如何处理低概率偶现问题的:
1、需要在对应的怀疑地方加追踪日志,等待下一次测试复现时候可以有更多的log依据
2、如果概率较高,比如可以几十次复现一次,那么就需要组织测试人力进行集中复现该问题
3、只要可以概率复现,和测试合作复现,就不断的加日志缩小范围,追踪到根本原因
4、知道了根本原因后,考虑修改代码故意触发错误,然后让问题必现,看看现象是否和低概率问题一致
5、确定波及最小的修改问题方案进行修改,修改后验证可以先考虑让代码故意触发bug看看是否 修改已经生效,然后再去除故意触发bug代码,提交给测试验证测试

contentprovider的具体问题揭秘

首先来看看android 12上的acquireProvider代码:

@UnsupportedAppUsage
    public final IContentProvider acquireProvider(
            Context c, String auth, int userId, boolean stable) {
        final IContentProvider provider = acquireExistingProvider(c, auth, userId, stable);
        if (provider != null) {
            return provider;
        }
        ContentProviderHolder holder = null;
        final ProviderKey key = getGetProviderKey(auth, userId);
        try {
            synchronized (key) {
            //这里从ams查询又没有改provider
                holder = ActivityManager.getService().getContentProvider(
                        getApplicationThread(), c.getOpPackageName(), auth, userId, stable);
               //如果没有查询到provider,那么就需要等待ams发布provider即notifyContentProviderPublishStatus执行
                if (holder != null && holder.provider == null && !holder.mLocal) {
                    synchronized (key.mLock) {//注意这里加锁进行下面操作
                    		//注意这里就有wait 10s的操作
                        key.mLock.wait(ContentResolver.CONTENT_PROVIDER_READY_TIMEOUT_MILLIS);
                        holder = key.mHolder;
                    }
                    if (holder != null && holder.provider == null) {
                        // probably timed out
                        holder = null;
                    }
                }
            }
        } 
        //省略
        return holder.provider;
    }
//ams端回调app进程通知provider已经准备好了
     @Override
        public void notifyContentProviderPublishStatus(@NonNull ContentProviderHolder holder,
                @NonNull String authorities, int userId, boolean published) {
            final String auths[] = authorities.split(";");
            for (String auth: auths) {
                final ProviderKey key = getGetProviderKey(auth, userId);
                synchronized (key.mLock) {
                //注意这里进行对应的mHolder设置填充
                    key.mHolder = holder;
                    key.mLock.notifyAll();
                }
            }
        }

乍一看好像代码没有问题,代码想要实现流程如下:
在这里插入图片描述

但是为啥有会有这个等待10s问题,而且等了10s后确实有相应的provider值
问题关键,多线程并发,没有注意锁的范围控制:
在这里插入图片描述

同时看看notifyContentProviderPublishStatus的锁也是这个key.mLock

 public void notifyContentProviderPublishStatus(@NonNull ContentProviderHolder holder,
                @NonNull String authorities, int userId, boolean published) {
         //省略
                synchronized (key.mLock) {
                    key.mHolder = holder;
                    key.mLock.notifyAll();
                }
         
        }

但是呢?大家看看
在这里插入图片描述

那么也就存在可能

     holder = ActivityManager.getService().getContentProvider(
                        getApplicationThread(), c.getOpPackageName(), auth, userId, stable);

这一行代码查询时候确实没有,但是查询完了后如果多线程产生并发notifyContentProviderPublishStatus又同时执行了,那么notifyContentProviderPublishStatus先获取了mLock,而且给provider赋值了,导致自己的mLock就再也不会有notifyContentProviderPublishStatus来解锁

 synchronized (key) {
                holder = ActivityManager.getService().getContentProvider(
                        getApplicationThread(), c.getOpPackageName(), auth, userId, stable);
                if (holder != null && holder.provider == null && !holder.mLocal) {
                
							//查询完成后,还没有执行下面的代码,马上有ams回调执行了notifyContentProviderPublishStatus,导致了这个key.mLock执行在notifyContentProviderPublishStatus后面
                    synchronized (key.mLock) {
                        key.mLock.wait(ContentResolver.CONTENT_PROVIDER_READY_TIMEOUT_MILLIS);
                        holder = key.mHolder;
                    }
                    if (holder != null && holder.provider == null) {
                        // probably timed out
                        holder = null;
                    }
                }

那么问题就明白了相当于本质其实就是锁范围不对,导致了这个10s问题

解决方案

这里为了最小的波及范围,不采用修改锁的范围方式,采用如下检测修改方案

 synchronized (key) {
                holder = ActivityManager.getService().getContentProvider(
                        getApplicationThread(), c.getOpPackageName(), auth, userId, stable);
                if (holder != null && holder.provider == null && !holder.mLocal) {
                    synchronized (key.mLock) {
                    if (key.mHolder== null) {//这里需要加个再判断是否这个mHolder还为null,才进行等待
                        key.mLock.wait(ContentResolver.CONTENT_PROVIDER_READY_TIMEOUT_MILLIS);
                    }
                        holder = key.mHolder;
                    }
                    if (holder != null && holder.provider == null) {
                        // probably timed out
                        holder = null;
                    }
                }

发现aosp 13已经有官方修复的patch,和上面修改方案差不多:
在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Linux - 第21节 - 网络基础(数据链路层)

1.数据链路层 数据链路层解决的问题: • IP拥有将数据跨网络从一台主机送到另一台主机的能力,但IP并不能保证每次都能够将数据可靠的送到对端主机,因此IP需要上层TCP为其提供可靠性保证,比如数据丢包后TCP可以让IP重新发送数据&am…

SpringBoot使用用户输入的自定义数据源启动【附源码】

一、项目背景 不知道小伙伴们有没有遇到过这样的需求,就是一个项目启动时不知道数据源,需要项目无数据源启动后,用户在画面自定义录入数据源信息,然后项目再初始化数据库链接,初始化管理员用户。最后项目进入正常使用…

cuda2 向量加法

向量加法 向量加法程序解读 #include<stdio.h> #include<cuda.h>typedef float FLOAT; #define USE_UNIX 1 区别不同系统 get thread id 1D block and 2D grid #define get_tid() (block)get block id&#xff0c; 2D gridwarm up 可选的&#xff0c;让gpu先运作…

2023年湖北住建厅八大员怎么考取施工员质量员资料员等岗位???

2023年湖北住建厅八大员怎么考取施工员质量员资料员等岗位&#xff1f;&#xff1f;&#xff1f; 2023年湖北住建厅八大员具体包含哪些岗位呢&#xff0c;可以选择的有施工员&#xff0c;质量员&#xff0c;资料员&#xff0c;材料员&#xff0c;机械员&#xff0c;标准员&…

用python进行办公自动化都需要学习什么知识呢?

本文先来分享Python实现自动化办公需要学什么&#xff0c;从哪里学&#xff01;以及自动化办公技巧的资源整理… 很多非IT职场人&#xff0c;想要把Python用到工作中&#xff0c;却不知道如何下手。其实自动化办公无非就是Excel、PPT、Word、邮件、文件处理、数据分析处理、爬虫…

chatgpt赋能python:Python写模拟器脚本

Python写模拟器脚本 Python是一种强大的编程语言&#xff0c;适用于各种任务&#xff0c;包括模拟器编写。模拟器是一种软件程序&#xff0c;能够模拟硬件或软件系统的行为。这篇文章将介绍Python编写模拟器脚本时需要关注的一些关键点。 为什么选择Python编写模拟器脚本 Py…

Vue+springboot个人博客网站系统的设计与实现3virm

本课题采用Java Web技术来设计开发一个可以发表文章、浏览文章的博客系统。课题主要包括前台博客系统以及后台管理系统&#xff1a;前台博客系统应该具备浏览文章&#xff08;能够实现分类查找、关键字查找、首页推荐等&#xff09;、评论文章&#xff08;用户能够对自己喜爱的…

chatgpt赋能python:Python的几次幂

Python的几次幂 Python是一种适用于多种任务的高级编程语言&#xff0c;可以用于网站开发&#xff0c;数据分析&#xff0c;机器学习以及人工智能等。其优越的设计和灵活的语法使其成为程序员众所周知和喜爱的语言。其中&#xff0c;Python中的乘方运算是其中一个非常常用的算…

OA系统开发设计

项目介绍 基于开源流程引擎camunda开发的办公自动化系统。采用前后端分离架构&#xff0c;基于可视化的表单建模、流程建模工具&#xff0c;零代码快速构建业务OA应用。 项目演示 演示地址请私信作者。 技术栈 后端&#xff1a;SpringBootJWTShiromybatis-plus 流程引擎&a…

mysql多级分类设计

简介 在数据库设计中&#xff0c;经常会遇到需要存储多级分类信息的情况&#xff0c;如商品分类、地区分类等。本文将详细介绍如何在MySQL中设计和管理多级分类数据 解决方案 一. 层级字段&#xff08;Hierarchy Field&#xff09;方法 层级字段方法是最常见和简单的多级分…

用redis的消息订阅功能更新应用内的caffeine本地缓存

1、为什么要更新caffeine缓存&#xff1f; 1.1&#xff0c;caffeine缓存的优点和缺点 生产环境中&#xff0c;caffeine缓存是我们在应用中使用的本地缓存&#xff0c; 它的优势在于存在于应用内&#xff0c;访问速度最快&#xff0c;通常都不到1ms就能做出响应&#xff0c; 缺…

Gitlab数据自动备

【场景】&#xff1a;将Gitlab服务器定时备份到Gitlab备份服务器 1.设置Gitlab服务器以及Gitlab备份服务器时间 1.1查看系统时间&#xff1a; date 1.2修改具体时间&#xff1a; date -s "2023-06-02 15:15:00" 1.3把时间写入CMOS&#xff1a; clock -w 1.4把…

深入了解Altium Designer 2023的规则设置

在PCB设计中&#xff0c;规则设置是确保PCB设计符合标准和规范的关键步骤&#xff0c;Altium Designer 2023作为一款强大的PCB设计软件&#xff0c;提供了丰富的规则设置功能&#xff0c;可帮助电子工程师实现高效准确的设计。下面将详细介绍AD 2023中的规则设置功能&#xff0…

【OpenMMLab AI实战营第二期笔记】人体关键点检测与MMPose

人体关键点检测与MMPose 介绍 人体姿态估计&#xff08;Human Pose Estimation&#xff09;是计算机视觉领域中的一个重要研究方向&#xff0c;也是计算机理解人类动作、行为必不可少的一步&#xff0c;人体姿态估计是指通过计算机算法在图像或视频中定位人体关键点&#xff…

TDEngine3.0环境搭建总结

TDEngine3.0环境搭建总结 一、TDengine 介绍二、TDengine的下载三、TDengine Server安装及配置3.1 安装3.2 taos的参数配置3.3 启动3.4 taosAdapter 四、TDengine Client 安装4.1 linux客户端安装4.2 windows客户端安装 一、TDengine 介绍 TDengine 官网 TDengine的介绍   T…

算法工程师的岗位职责(合集)

算法工程师的岗位职责1 职责&#xff1a; 1、负责运动控制的数据采集、信号处理、仪器控制等模块研发和维护,包括关键技术方案设计/详细设计/调试/验证/测试/现场调试 2、编写软件使用说明书等相关技术性文件 3、完成项目中有关机器人轨迹设计、分析、控制的需求分析(7轴机械手…

Maven依赖传递

Maven 依赖传递是 Maven 的核心机制之一&#xff0c;它能够一定程度上简化 Maven 的依赖配置。本节我们将详细介绍依赖传递及其相关概念。 依赖传递 如下图所示&#xff0c;项目 A 依赖于项目 B&#xff0c;B 又依赖于项目 C&#xff0c;此时 B 是 A 的直接依赖&#xff0c;C…

java爬虫详解及简单实例

java爬虫是一种自动化程序&#xff0c;可以模拟人类在互联网上的行为&#xff0c;从网站上抓取数据并进行处理。下面是Java爬虫的详细解释&#xff1a; 1、爬虫的基本原理 Java爬虫的基本原理是通过HTTP协议模拟浏览器发送请求&#xff0c;获取网页的HTML代码&#xff0c;然后…

PS2024后期调色滤镜插件Alien Skin Exposure7

Exposure是一款常见的ps调色滤镜插件&#xff0c;相信许多朋友都曾经用过它。一张普通的图片经过后期调色处理后&#xff0c;可以得到更加靓丽的效果。因此选择一款专业性强、操作简单的后期调色软件很重要。那么&#xff0c;我们应该如何选择后期调色软件呢&#xff1f;下面给…

第三大章docker的部署

1. 红为写的命令 systemctl stop firewalld.service setenforce 0 #安装依赖包yum install -y yum-utils device-mapper-persistent-data lvm2 -------------------------------------------------------------------------------------------- yum-utils&#xff1a;提供了…