草庐IT

Android 时间同步机制及常见问题分析

GuangZhi- 2023-04-09 原文

近期Android设备多次遇到时间不准的问题,借此机会分析Android 时间同步更新机制。

此篇文章将分析Android 时间同步更新机制的构成及常见导致时间不准的情况。

一.Android 时间同步更新机制的构成:

1.由android启动流程可知,系统服务由SystemServer启动,在SystemServer查找到时间更新服务。

SystemServer->startOtherServices->networkTimeUpdaterF.systemRunning();

 2.NetworkTimeUpdateService启动后首先发出EVENT_POLL_NETWORK_TIME调用onPollNetworkTime()尝试更新时间,

看样子onPollNetworkTime()似乎是时间更新的核心,看看它干了什么。

①处首先检查是否开启了时间同步更新,也就是设置里时间自动选项,开启了才会更新时间。

②处对距离上次时间更新的时间间隔有要求,mPollingIntervalMs从配置文件获取到时间间隔24h,也就是距离上次更新不到24h不会再次更新时间

此处mNitzTimeSetTime !=NOT_SET有什么作用,后面再表,先往下看。

③处,满足更新条件后mTime.forceRefresh()更新时间,往下看forceRefresh()

看样子是调用client.requestTime(mServer, (int)mTimeout)访问地址为mServer的服务器发出sntp请求,sntp通过什么方式请求呢?继续往下看:

到这里我们可以知道sntp实质是向host name 为mServer的主机发出UDP来更新时间,更新到的时间赋值给了mNtpTime,在onPollNetworkTime()通过④处SystemClock.setCurrentTimeMillis(ntp)设置系统时间,到这里时间更新完成。

就这么结束了吗?当然不是!如果时间同步失败,有重试机制吗?同步更新成功,下次什么时候更新?

第⑤处回答了我们,有重试机制,最大重试次数mTryAgainTimesMax=3,间隔时间mPollingIntervalShorterMs为1分钟;同步成功的话,间隔mPollingIntervalMs再次检查更新,也就是24h(当然了,如果重试3次仍然失败也会24h后尝试更新).

如果设备网络不通,最大重试次数mTryAgainTimesMax用完,就得24h后再更新???

当时不是,android替你想好了,回顾下systemRunning():

systemRunning()注册了网络状态监听,网络变化时发出EVENT_NETWORK_CHANGED->onPollNetworkTime()尝试更新时间.

到这里,我们已经知道Android 可以通过sntp从网络更新时间。Android时间更新似乎也就仅此而已。

等等,在②处有个疑问还没解开,mNitzTimeSetTime !=NOT_SET有什么用处?

回头看:

mNitzTimeSetTime 初始值为NOT_SET,我们自然可以通过sntp从网络更新时间,那么为什么要设置这个条件?

除非还有另一种时间更新机制,如果这种机制同步了时间,自然不必再通过sntp同步时间!

那就看看mNitzTimeSetTime 在哪里被赋值为!=NOT_SET

是谁发出了这个ACTION_NETWORK_SET_TIME广播告诉NetworkTimeUpdateService不必多此一举通过sntp更新时间?再看:

原来是GsmServiceStateTracker接收到EVENT_NITZ_TIME->setTimeFromNITZString()->setAndBroadcastNetworkSetTime()设置了时间并发出广播告知NetworkTimeUpdateService不必多次一举,弟弟已替你更新了时间,哥哥就不必徒劳了!

一探究竟,GsmServiceStateTracke实质只是个Handler,传递信息罢了,谁发送的消息呢?顺着EVENT_NITZ_TIME这一线索继续看。

找到CommandsInterface实现类BaseCommands

GsmServiceStateTracke把自身以及EVENT_NITZ_TIME这一Message设置进了BaseCommands包装成了Registrant对象mNITZTimeRegistrant,

那么好办了,找到mNITZTimeRegistrant哪里被调用就知道谁发出的消息。

原来是RIL processUnsolicited()接收到RIL_UNSOL_NITZ_TIME_RECEIVED事件发出,继续往下看:

现在很清晰了,RIL里启动了线程RILReceiver,RILReceiver通过socket 与rild通信,读出了时间值->processResponse()向上分发,这种时间同步机制称为NITZ(通过基站同步时间)。

RILD何物?

RILD:Radio Interface Layer  Deamon,承接Android 上层 (RILJ)与 Modem的通信。草图如下:

至此,知道了Android时间同步更新机制有SNTP和NITZ两种方式。

二.常见导致时间不准的情况及解决途径:

常遇到的问题是NITZ时间不准,导致系统时间不准。

从Android时间同步机制分析知道,如果NITZ同步了时间,SNTP在24h内不会被触发。如果NITZ同步了错误的时间,短期内设备仍旧是错误的时间直到SNTP被触发。怎么确认呢?

分析GsmServiceStateTracker setTimeFromNITZString()可知,更新NITZ时间后,会通过SystemProperties.set("gsm.nitz.time", String.valueOf(c.getTimeInMillis()))写入临时变量并输出日志"setAndBroadcastNetworkSetTime: time",与设备开机时的时间比较便知NITZ时间是否有误。

解决:NITZ时间不准,通常是由基站导致,可以通过如下任意一种方式解决:

1.通过配置关闭NITZ机制只保留SNTP解决:

分析GsmServiceStateTracker setTimeFromNITZString()可知设置gsm.ignore-nitz为true,就不会设置NITZ时间为系统时间,这样就从SNTP同步时间。

这么做需要个前提,就是系统开放了管理员权限,这样才可以把gsm.ignore-nitz=true配置固化(build.prop)。

2.写个系统应用:

关闭自动同步时间开关,这样就关闭了系统时间同步机制,同时借鉴SNTP机制,写一套sntp,在应用上更新时间。

有关Android 时间同步机制及常见问题分析的更多相关文章

  1. ruby - 在 64 位 Snow Leopard 上使用 rvm、postgres 9.0、ruby 1.9.2-p136 安装 pg gem 时出现问题 - 2

    我想为Heroku构建一个Rails3应用程序。他们使用Postgres作为他们的数据库,所以我通过MacPorts安装了postgres9.0。现在我需要一个postgresgem并且共识是出于性能原因你想要pggem。但是我对我得到的错误感到非常困惑当我尝试在rvm下通过geminstall安装pg时。我已经非常明确地指定了所有postgres目录的位置可以找到但仍然无法完成安装:$envARCHFLAGS='-archx86_64'geminstallpg--\--with-pg-config=/opt/local/var/db/postgresql90/defaultdb/po

  2. ruby - 通过 rvm 升级 ruby​​gems 的问题 - 2

    尝试通过RVM将RubyGems升级到版本1.8.10并出现此错误:$rvmrubygemslatestRemovingoldRubygemsfiles...Installingrubygems-1.8.10forruby-1.9.2-p180...ERROR:Errorrunning'GEM_PATH="/Users/foo/.rvm/gems/ruby-1.9.2-p180:/Users/foo/.rvm/gems/ruby-1.9.2-p180@global:/Users/foo/.rvm/gems/ruby-1.9.2-p180:/Users/foo/.rvm/gems/rub

  3. ruby - 通过 RVM (OSX Mountain Lion) 安装 Ruby 2.0.0-p247 时遇到问题 - 2

    我的最终目标是安装当前版本的RubyonRails。我在OSXMountainLion上运行。到目前为止,这是我的过程:已安装的RVM$\curl-Lhttps://get.rvm.io|bash-sstable检查已知(我假设已批准)安装$rvmlistknown我看到当前的稳定版本可用[ruby-]2.0.0[-p247]输入命令安装$rvminstall2.0.0-p247注意:我也试过这些安装命令$rvminstallruby-2.0.0-p247$rvminstallruby=2.0.0-p247我很快就无处可去了。结果:$rvminstall2.0.0-p247Search

  4. ruby - Fast-stemmer 安装问题 - 2

    由于fast-stemmer的问题,我很难安装我想要的任何ruby​​gem。我把我得到的错误放在下面。Buildingnativeextensions.Thiscouldtakeawhile...ERROR:Errorinstallingfast-stemmer:ERROR:Failedtobuildgemnativeextension./System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/bin/rubyextconf.rbcreatingMakefilemake"DESTDIR="cleanmake"DESTDIR=

  5. ruby-on-rails - Ruby 检查日期时间是否为 iso8601 并保存 - 2

    我需要检查DateTime是否采用有效的ISO8601格式。喜欢:#iso8601?我检查了ruby​​是否有特定方法,但没有找到。目前我正在使用date.iso8601==date来检查这个。有什么好的方法吗?编辑解释我的环境,并改变问题的范围。因此,我的项目将使用jsapiFullCalendar,这就是我需要iso8601字符串格式的原因。我想知道更好或正确的方法是什么,以正确的格式将日期保存在数据库中,或者让ActiveRecord完成它们的工作并在我需要时间信息时对其进行操作。 最佳答案 我不太明白你的问题。我假设您想检查

  6. ruby - 安装 Ruby 时遇到问题(无法下载资源 "readline--patch") - 2

    当我尝试安装Ruby时遇到此错误。我试过查看this和this但无济于事➜~brewinstallrubyWarning:YouareusingOSX10.12.Wedonotprovidesupportforthispre-releaseversion.Youmayencounterbuildfailuresorotherbreakages.Pleasecreatepull-requestsinsteadoffilingissues.==>Installingdependenciesforruby:readline,libyaml,makedepend==>Installingrub

  7. ruby-on-rails - 将 Ruby 中的日期/时间格式化为 YYYY-MM-DD HH :MM:SS - 2

    这个问题在这里已经有了答案:Railsformattingdate(4个答案)关闭4年前。我想格式化Time.Now函数以显示YYYY-MM-DDHH:MM:SS而不是:“2018-03-0909:47:19+0000”该函数需要放在时间中.现在功能。require‘roo’require‘roo-xls’require‘byebug’file_name=ARGV.first||“Template.xlsx”excel_file=Roo::Spreadsheet.open(“./#{file_name}“,extension::xlsx)xml=Nokogiri::XML::Build

  8. ruby - 查找字符串中的内容类型(数字、日期、时间、字符串等) - 2

    我正在尝试解析一个CSV文件并使用SQL命令自动为其创建一个表。CSV中的第一行给出了列标题。但我需要推断每个列的类型。Ruby中是否有任何函数可以找到每个字段中内容的类型。例如,CSV行:"12012","Test","1233.22","12:21:22","10/10/2009"应该产生像这样的类型['integer','string','float','time','date']谢谢! 最佳答案 require'time'defto_something(str)if(num=Integer(str)rescueFloat(s

  9. java - 从 JRuby 调用 Java 类的问题 - 2

    我正在尝试使用boilerpipe来自JRuby。我看过guide从JRuby调用Java,并成功地将它与另一个Java包一起使用,但无法弄清楚为什么同样的东西不能用于boilerpipe。我正在尝试基本上从JRuby中执行与此Java等效的操作:URLurl=newURL("http://www.example.com/some-location/index.html");Stringtext=ArticleExtractor.INSTANCE.getText(url);在JRuby中试过这个:require'java'url=java.net.URL.new("http://www

  10. ruby-on-rails - 简单的 Ruby on Rails 问题——如何将评论附加到用户和文章? - 2

    我意识到这可能是一个非常基本的问题,但我现在已经花了几天时间回过头来解决这个问题,但出于某种原因,Google就是没有帮助我。(我认为部分问题在于我是一个初学者,我不知道该问什么......)我也看过O'Reilly的RubyCookbook和RailsAPI,但我仍然停留在这个问题上.我找到了一些关于多态关系的信息,但它似乎不是我需要的(尽管如果我错了请告诉我)。我正在尝试调整MichaelHartl'stutorial创建一个包含用户、文章和评论的博客应用程序(不使用脚手架)。我希望评论既属于用户又属于文章。我的主要问题是:我不知道如何将当前文章的ID放入评论Controller。

随机推荐