由ContactsProvider的升级引发的OTA首次开机卡白米问题分析

article/2025/10/20 10:19:43

上午的宁静被一个OTA卡白米问题打破,接下来不断有人反馈不同机型都复现了OTA后卡白米,10.9号OTA升级到10.10号的版本,全机型问题,线刷没有问题,好吧,接下来就根据这些信息开始初步分析log吧!

初步分析

查看问题log,发现Boot phase到了PHASE_SYSTEM_SERVICES_READY
PHASE_SYSTEM_SERVICES_READY
并且走到了PackageManagerService.systemReady

10-10 15:26:47.762  3152  3152 W ContextImpl: 
Calling a method in the system process without a qualified user: 
android.app.ContextImpl.bindService:1295 
miui.provider.ExtraGuard.init:69 
com.android.server.pm.PackageManagerServiceInjector.initExtraGuard:429 
com.android.server.pm.PackageManagerService.systemReady:15195 
com.android.server.SystemServer.startOtherServices:1133 

继续看log发现以下异常信息

10-10 15:27:07.784  3152  3221 E ActivityManager: 
Attempt to launch receivers of broadcast intent Intent 
{ act=android.net.conn.DATA_ACTIVITY_CHANGE (has extras) } before boot completion

这说明系统启动没有正常完成,ActivityManager的状态还没有就绪,难道system server的启动流程出现了异常?
赶紧打出system server的traces看一下

"main" prio=5 tid=1 Native| group="main" sCount=1 dsCount=0 obj=0x75f14fb8 self=0x558db1ec10| sysTid=3152 nice=-2 cgrp=default sched=0/0 handle=0x7fb6a3afc8| state=S schedstat=( 5043600992 157397768 10523 ) utm=367 stm=137 core=5 HZ=100| stack=0x7fe85de000-0x7fe85e0000 stackSize=8MB| held mutexes=kernel: __switch_to+0x70/0x7ckernel: SyS_epoll_wait+0x2a0/0x32ckernel: SyS_epoll_pwait+0xa4/0x120kernel: cpu_switch_to+0x48/0x4cnative: #00 pc 0000000000069be4  /system/lib64/libc.so (__epoll_pwait+8)native: #01 pc 000000000001cca4  /system/lib64/libc.so (epoll_pwait+32)native: #02 pc 000000000001be88  /system/lib64/libutils.so (_ZN7android6Looper9pollInnerEi+144)native: #03 pc 000000000001c268  /system/lib64/libutils.so (_ZN7android6Looper8pollOnceEiPiS1_PPv+80)native: #04 pc 00000000000d2580  /system/lib64/libandroid_runtime.so (_ZN7android18NativeMessageQueue8pollOnceEP7_JNIEnvP8_jobjecti+48)native: #05 pc 000000000000082c  /data/dalvik-cache/arm64/system@framework@boot.oat (Java_android_os_MessageQueue_nativePollOnce__JI+144)at android.os.MessageQueue.nativePollOnce(Native method)at android.os.MessageQueue.next(MessageQueue.java:323)at android.os.Looper.loop(Looper.java:135)at com.android.server.SystemServer.run(SystemServer.java:299)at com.android.server.SystemServer.main(SystemServer.java:181)at java.lang.reflect.Method.invoke!(Native method)at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:738)at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:628)

看起来主线程没有什么异常,已经进入主消息循环了,也就是说startOtherServices已经走完了,都走完了为啥activitymanager的状态还没有就绪?看代码吧
startOtherServices
systemready
systemready_runnable

已知PMS的systemready已经走了,整个startOtherServices也走完了,所以AMS的systemready一定调用了,但是调用了为什么没有ready?

仔细看上面的代码可以看到一些端倪,因为调用AMS的systemready时传入的是一个runnable,runnable里面是启动systemui并通知一堆系统service running,从代码中可以看到这个runnable是在systemready函数的后半部分执行的,而当前出问题的状态是这个runnable并没有执行。

除了这个runnable之外还有一个关键的状态就是AMS的mSystemReady,通过am start发现log中打出来AMS没有ready的信息,产生这种状态的唯一的可能就是在AMS的systemready函数中没有正常执行完毕。

查看代码发现OTA后第一次调用到AMS的systemready之后mDidUpdate为false,mWaitingUpdate也是false,继续往下走到deliverPreBootCompleted,这里又传入了一个runnable,非常关键的一步,如果是OTA后第一次调用deliverPreBootCompleted会返回true给mWaitingUpdate,以为在deliverPreBootCompleted里面会发送ACTION_PRE_BOOT_COMPLETED给所有注册的receiver,并且添加FLAG_RECEIVER_BOOT_UPGRADE,在发送广播的时候就从同步调用变成了异步,返回后继续执行,mWaitingUpdate为true,然后return出去,mSystemReady在这一次没有机会设置为true,那什么时候设置呢?AMS ready的剩余代码什么时候执行呢?带着问题继续看代码

深入分析

还记得上面调用deliverPreBootCompleted时传入的runnable吗?当OTA后第一开机的ACTION_PRE_BOOT_COMPLETED广播发送给所有的receiver之后就会调用这个runnable,它里面会将mDidUpdate置为true并再次调用AMS的systemready函数,这次会正常执行完所以的流程,包括设置mSystemReady等状态为true,调用startOtherServices传入的runnable启动systemui和notify systemservice running,启动home等,但是现在这些都没有做。。。好吧,一言不合说不做就不做,Android就是任性!

赶紧看看它为啥没做,deliverPreBootCompleted也调用了,runnable也传过去,那问题就出在deliverPreBootCompleted里面的广播发送了?要想知道,还得看代码和log

deliverPreBootCompleted
deliverPreBootCompleted_preboot

deliverPreBootCompleted_preboot_receiver

preboot_log
好了,代码和log看到这里,基本定位到了大概原因,这个广播是有序发送的,并且是显式指定component的方式,每个发送完了都会把结果给PreBootContinuation并调用performReceive发送下一个,如果都发完了会把之前传入的runnable post 到消息队列里面,显而易见,没有走到post这一步,也就是说上面的广播在发送过程中出问题了,出什么问题了呢?还好这个问题可以必现,赶紧复现追一下代码,发现需要给6个receiver发送广播,出问题时只发送到第二个contactsproviders的时候就断了,log也对应了这一点,并且log中发现了contactsproviders升级数据库版本的信息,同时又仔细看了一下system server的trace,发现有个关于getprovider的线程不是太正常,一直处于waiting状态
binder_waiting_forever

contactsproviders执行之后一直没有完成,而AMS这么又有一个binder 线程一直在等待provider,这是不是有某种对应关系?赶紧看一下contactsproviders所在进程的traces,发现真有关系,在ContactsUpgradeReceiver里面执行数据库升级之后去请求一个content provider的时候block住了

contractsprovider_blocked
真是踏破铁鞋无觅处,得来好不费功夫啊,system server一直在等待你完成通知它,你却在这睡大觉,但是又引来一个问题,这里的调用为什么会一直block?继续看代码,断点追代码,在getContentProviderImpl里发现了蹊跷,为contactsprovider 请求的yellowpage provider去startProcessLocked的时候由于system还没有ready所以start的操作被hold住了,所以导致contactsprovider的query操作被一直block

startProcess
通过分析代码发现,不允许yellowpageprovider的进程起来是合理的,不合理的是contactsprovider在OTA过第一次开机upgrade的过程中不合理的请求了query yellowpageprovider,从而block整个系统启动,导致卡白米

后续问题

到这里可能有细心的同学会问,为什么之前OTA没问题,今天就有问题了?

原因是contactprovider的数据库版本有升级,在升级的同时触发了T9索引重建,重建的过程中用到了yellowpageprovider,来一下change再配合上面的traces可能会更直观
change
这个索引重建不是不能做,而是不能在OTA第一次开机过程中调用upgradereceiver的做,可以等正常开机后,BOOT_COMPLETED广播发出去的时候再触发做

可能还有更细心的同学会问,为什么卡住之后再重启一下就好了呢?

这是因为在ContactsUpgradeReceiver中会先判断DB VERSION,第一次因为升级了所以不相等,就走升级流程,升级之前先把最新的DB VERSION put到了preference中,这样第二次的时候因为相等了就不会再走升级流程了,所以就不会卡白米了
db_version


http://chatgpt.dhexx.cn/article/CL8PE9Cw.shtml

相关文章

Android Content Providers(二)——Contacts Provider

Contacts Provider是Android中一个强大并且灵活的组件,负责管理系统通讯录的数据,对外提供访问接口来对系统通讯录进行访问和操作。 以下是Contacts Provider的组织结构图: 可以看出Android的系统通讯录是三层架构,通过URI进行访…

API Guides Contacts Provider (二)

Data From Sync Adapters 用户直接输入联系人的数据到设备中,但是也可以通过sync adapters从服务器上获取联系人的数据。sync adapter 会自动同步设备和服务器上的数据。sync adapter运行在后台,由系统来控制。系统调用ContentResolver去管理数据。 在A…

Android 7.0后SettingProvider ContactsProvider TelephonyProvider MediaProvider数据库位置

在Android7.0之后,很多Provider数据库的位置都发生了改变,在这记录下,免得以后又忘记了,找起来费劲。 1、SettingsProvider 在之前SettingsProvider是是以settings.db的方法存在,在Android N之后SettingsProvider数据存…

利用Contacts Provider读取手机联系人信息

参考:https://developer.android.google.cn/guide/topics/providers/contacts-provider.html Contacts Provider组织结构 Contacts Provider组织结构由三部分构成,如下图所示: (联系人)Contact:代表联系人,包含了多种联系渠道。(原始联系人)RawContact:每个原始联…

API Guides Contacts Provider

Contacts Provider Contacts Provider是Android的一个强大组件,它管理联系人的核心数据。你在手机联系人看到联系人信息,来源于Contact Provider。当然,你可以在自己的应用用访问ContactProvider的数据,也可以同步手机和服务…

Android官方文档—APP组件(Content Providers)(Contacts Provider)

通讯录内容提供者 Contacts Provider是一个功能强大且灵活的Android组件,用于管理设备的人员数据中​​央存储库。联系人提供程序是您在设备的联系人应用程序中看到的数据源,您还可以在自己的应用程序中访问其数据,并在设备和在线服务之间传…

理清contactsprovider

初步了解android contact provider android的联系人数据单独拿出来做成ContactsProvider,众多的table和view整体看下来,使得联系人的数据错综复杂。但是我们在开发的过程并不需要将所有的table都搞清楚。用到最多的是 ContactsContract.Contacts、Contac…

Android ContactsProvider源码分析

Android源码目录packages\providers下的应用是下载,通话等内置基本应用提供数据存储和操作的provider应用,本文章将针对ContactsProvider源码的架构和实现展开分析。(注:本文使用使用android4.0版本进行分析) 1、架构设…

ContactsProvider2

本篇不全也不细,只是根据按照个人理解和工作中遇到的问题,总结了个人认为的要点。 1. Android的数据库体系 1.1. 概述1.2 uri结构 2. ContactsProvider2 2.1. 概述2.2. Contacts2.db中的表2.3. ContactProvider2中的实现2.4. 批量访问 1. Android的数…

Android ContactProvider码源解析

Android Contacts源码解析2 4 ContactsProvider模块 1ContactsProvider简介2数据库创建3主要数据库的表结构相互关系 1data表2raw_contacts表3contacts表4mimetypes5其他表 文章转载自:https://blog.csdn.net/kafka_88/article/details/58585607 4,…

Contacts Provider基础

作为四大组件之一的ContentProvider工作中我们很少会用到自己自定义的ContentProvider,用到的最多的就是系统提供的。官方文档提供了两种系统ContentProvider,一种是CalendarProvider,一种是Contacts Provider。今天我们的主角就是Contact Provider。 The Contacts Provider is…

Error: invalid code, hints: [ req_id: * ]

1、问题描述:这个问题是在处理订单支付时需要用户登录遇到的,具体报错信息如下: 2、报错原因: 当前开发者的appid没有支付权限导致 3、解决方案: 需要负责人给分配对应的权限

This application’s bundle identifier does not match its code signing identifier.

今天使用carthage更新第三方后莫名出现真机云心失败,提示 This application’s bundle identifier does not match its code signing identifier. 解决方法: /usr/local/bin/carthage copy-frameworks 进入Building Phases 单击并在New Run Script Phase中添加脚本 将/usr/lo…

Code Sign error: a valid provisioning profile matching the application's Identifier 'com.yourcompany

出现这个错误的原因是因为:appid和provisioning profile不匹配 !有两种解决的办法:重新下载provisioning profile,或者可能因为:生成证书和appid 所用的根证书不同,最好重新都生成然后下载。(这…

ANTD react 手机号(验证码)登陆 + 账号登陆(图形验证码)

这种页面可能是大家常用的,但重写比较费时间,之前没有搜到完整的,在这里自己总结一下,方面复用 代码: <LoginFormformRef{formRef}initialValues{{autoLogin: false}}onFinish{async values > {await handleSubmit(values as LoginParams)}}><Tabs activeKey{type…

Springboot+axios+vue使用VerifyCodeUtils工具类实现验证码图片功能

一、环境准备 ideajava 1.8maven 3.6.3操作系统&#xff1a;window10vue.min.jsaxios.min.js 二、VerifyCodeUtils工具类 import java.awt.Color; import java.awt.Font; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.RenderingHints; import ja…

Identity and Authentication - Common Authentication Methods

Username and Passwords This is the most common method of identifying users in the age of Software as a Service (SaaS) 解释上面的图中的步骤&#xff1a; Login Request: POST /login postuser {username: users,password: pws }Find users: SELECT * FROM databa…

iOS code signing identity 配置

PROJECT 和 TARGET 中都要选:code signing identity: 调试统一都选 developer, 发布统一都选 distribution provisioning Profile 也要选. 过期和无效的证书及时删除, 避免 ambiguous 警告. 选择正确的证书配置后仍然报错, clean 一下重启 xcode 还不行~~~重启电脑

Invalid CAPTCHA response. Please try again. (Code: 1201)

项目场景&#xff1a; Invalid CAPTCHA response. Please try again. (Code: 1201) 解决方案&#xff1a; 直接使用隐私浏览器打开即可。

经典的Embedding方法Word2vec

提起Embedding,就不得不提Word2vec,它不仅让词向量在自然语言处理领域再度流行&#xff0c;更为关键的是&#xff0c;自2013年谷歌提出Word2vec以来&#xff0c;Embedding 技术从自然语言处理领域推广到广告、搜索、图像、推荐等深度学习应用领域&#xff0c; 成了深度学习知识…