安卓系统面经_安卓面经(14/20)网络时间专题
牛客高级系列专栏:
安卓(安卓系统开发也要掌握)
- 想通关安卓面试,请看:《150道安卓高频面试题目录及答案链接》
- 想通关安卓系统面试,请看:《140道安卓系统Framework面试题目录及答案链接》
- 想进阶安卓开发,请看:《Android进阶知识体系解析_15大安卓进阶必备知识点》
- 想了解安卓APP完整开发流程,请看:《安卓APP完整开发流程》
- 想掌握安卓App性能优化,请看:《安卓性能优化讲解和实战专栏》
- 想掌握Gradle语法,制作Gradle插件,请看:《安卓Gradle语法解析和实践大全》
嵌入式
- 想通关嵌入式面试,请看: 《111道嵌入式面试题目录及答案链接》
- 想多掌握几个嵌入式项目,请看:《6个嵌入式项目交流分享(附源码)》
- 本人是2020年毕业于广东工业大学研究生:许乔丹,有国内大厂CVTE和世界500强企业安卓开发经验,该专栏整理本人从嵌入式Linux转Android系统开发过程中对常见安卓系统开发面试题的理解;
- 1份外卖价格助您提高安卓面试准备效率,为您面试保驾护航!!
正文开始⬇
面试题预览
- 简述下NTP时间同步的原理?⭐⭐⭐
- 请简单解释下Android系统NTP网络时间同步的流程? ⭐⭐⭐
- 如果有个系统时间不对的问题,请给出你的问题定位思路。⭐⭐⭐⭐⭐
1 网络时间同步NTP流程
1.1 NTP介绍及原理分析
1.1.1 NTP简介
NTP(Network Time Protocol)是用来使计算机时间同步化的一种协议,它可以是计算机对其服务器或者时钟源(如石英钟,GPS等等)做同步化,它可以提供高精准度的时间校正(LAN上与标准间差小于1ms, WAN上几十毫秒),且可介由加密确认的方式来防止恶意的协议攻击。时间按NTP服务器的等级传播。按照离外部UTC源的远近把所有服务器归入不同的Startum层中。
1.1.2 NTP原理分析
系统时钟同步的工作过程如下:
1)Device A发送一个NTP报文给Device B,该报文带有它离开Device A时的时间戳,该时间戳为10:00:00am(T1)。
2)当此NTP报文到达Device B时,Device B加上自己的时间戳,该时间戳为11:00:01am(T2)。
3)当此NTP报文离开Device B时,Device B再加上自己的时间戳,该时间戳为11:00:02am(T3)。
4)当Device A接收到该响应报文时,Device A的本地时间为10:00:03am(T4)。
至此,Device A已经拥有足够的信息来计算两个重要的参数:
NTP报文的往返时延Delay=(T4-T1)-(T3-T2)=2秒。
Device A相对Device B的时间差offset=((T2-T1)+(T3-T4))/2=1小时。
这样,Device A就能够根据这些信息来设定自己的时钟,使之与Device B的时钟同步。
下面主要对Android系统源码的时间同步NTP流程进行分析:
1.2 NetworkTimeUpdateService启动
源码文件:frameworks/base/services/java/com/android/server/SystemServer.java
//这个是使能时间同步模块的配置,正常都是使能的,这句话也是使能的,一开始以为默认false,后来才知道,
//如果没有获取到这个配置,才会是false
boolean disableNetworkTime = SystemProperties.getBoolean("config.disable_networktime", false);
//这儿是将时间同步作为一个系统服务,system_server是一个进程,包括多个系统服务
if (!isWatch && !disableNetworkTime) {
t.traceBegin("StartNetworkTimeUpdateService");
try {
networkTimeUpdater = new NetworkTimeUpdateService(context);
ServiceManager.addService("network_time_update_service",
networkTimeUpdater);
} catch (Throwable e) {
reportWtf("starting NetworkTimeUpdate service", e);
}
}
//这边是启动时间同步服务
final NetworkTimeUpdateService networkTimeUpdaterF = networkTimeUpdater;
networkTimeUpdaterF.systemRunning();
1.3 同步时间的定时器设置(重试逻辑)
源码:frameworks/base/services/core/java/com/android/server/NetworkTimeUpdateService.java
1.3.1 注册定时器广播接收器
//首先在这儿注册一个广播接收器,接收定时器发过来的所有时间同步定时广播
private void registerForAlarms() {
mContext.registerReceiver(
new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
mHandler.obtainMessage(EVENT_POLL_NETWORK_TIME).sendToTarget();
}
}, new IntentFilter(ACTION_POLL));
}
//接收到定时器广播后,就处理定时器事件
private class MyHandler extends Handler {
public void handleMessage(Message msg) {
switch (msg.what) {
case EVENT_AUTO_TIME_ENABLED:
case EVENT_POLL_NETWORK_TIME:
case EVENT_NETWORK_CHANGED:
onPollNetworkTime(msg.what);
break;
}
}
}
1.3.2 时间同步间隔的设置
mPollingIntervalMs = mContext.getResources().getInteger(
com.android.internal.R.integer.config_ntpPollingInterval);
mPollingIntervalShorterMs = mContext.getResources().getInteger(
com.android.internal.R.integer.config_ntpPollingIntervalShorter);
mTryAgainTimesMax = mContext.getResources().getInteger(
com.android.internal.R.integer.config_ntpRetry);
com.android.internal.R.integer.config_ntpPollingInterval这个是在另一个资源文件里获取的,在frameworks/base/core/res/res/values/config.xml里
<!-- Remote server that can provide NTP responses. -->
<string translatable="false" name="config_ntpServer">ntp.aliyun.com</string>
<!-- Normal polling frequency in milliseconds -->
<integer name="config_ntpPollingInterval">300000</integer>
<!-- Try-again polling interval in milliseconds, in case the network request failed -->
<integer name="config_ntpPollingIntervalShorter">60000</integer>
<!-- Number of times to try again with the shorter interval, before backing
off until the normal polling interval. A value < 0 indicates infinite. -->
<integer name="config_ntpRetry">3</integer>
<!-- Timeout to wait for NTP server response in milliseconds. -->
<integer name="config_ntpTimeout">5000</integer>
在这个config.xml文件里,可以设置ntpserver,因为默认的地址在国内不能访问
config_ntpPollingInterval,这个配置是一个通用轮训间隔,默认是86400000,是24小时,我这儿改为了300秒暂时
config_ntpPollingIntervalShorter,这个是短时间轮训间隔
config_ntpRetry,这个是短时间轮训间隔的次数
1.3.3 同步时间间隔的逻辑
//NetworkTimeUpdateService构造函数定义了一个pollIntent,可以用于下面resetAlarm来设置定时器的发送广播的intent,这样在定时器时间来临时,定时器发送广播这边便可以知道已经到达定时时间
public NetworkTimeUpdateService(Context context) {
Intent pollIntent = new Intent(ACTION_POLL, null);
mPendingPollIntent = PendingIntent.getBroadcast(mContext, POLL_REQUEST, pollIntent, 0);
}
/**
* Cancel old alarm and starts a new one for the specified interval.
* @param interval when to trigger the alarm, starting from now.
*/
private void resetAlarm(long interval) {
mAlarmManager.cancel(mPendingPollIntent);
long now = SystemClock.elapsedRealtime();
long next = now + interval;
mAlarmManager.set(AlarmManager.ELAPSED_REALTIME, next, mPendingPollIntent);
}
//这边的处理是短时间多次轮询和长时间轮询的处理
//刚开机时,由于网络较系统启动较慢,所以需要多次轮询,轮询间隔也会比较小
//所以这里mPollingIntervalShorterMs是短时间轮询,设置定时器就用resetAlarm方法就行
//每次接收到定时器广播后,这边的mTryAgainCounter会加1,当短时间轮询超过一定次数,默认为3,
//就会切换为长时间轮询mPollingIntervalMs
private void onPollNetworkTimeUnderWakeLock(int event) {
if (cachedNtpResult != null && cachedNtpResult.getAgeMillis() < mPollingIntervalMs) {
} else {
mTryAgainCounter++;
if (mTryAgainTimesMax < 0 || mTryAgainCounter <= mTryAgainTimesMax) {
resetAlarm(mPollingIntervalShorterMs);
} else {
// Try much later
mTryAgainCounter = 0;
resetAlarm(mPollingIntervalMs);
}
}
}
1.4 时间同步请求
1.4.1 获取ntp时间,并且设置系统时间
源码:frameworks/base/core/java/android/util/NtpTrustedTime.java
同步时间的操作在forceRefresh方法里,首先获取getNtpConnectionInfo(),获取相关的配置,包括serverName和timeoutMillis,serverName默认是com.android,国内无法访问,我这里设置为了ntp.aliyun.com,具体细节可以参照第二节第2小节。
然后是创建一个SntpClient,通过sntp获取到的时间,创建一个TimeResult对象,这个对象可以通过getCachedTimeResult()函数获取到
public TimeResult getCachedTimeResult() {
return mTimeResult;
}
frameworks/base/core/java/android/util/NtpTrustedTime.java
public boolean forceRefresh() {
NtpConnectionInfo connectionInfo = getNtpConnectionInfo();
final SntpClient client = new SntpClient();
final String serverName = connectionInfo.getServer();
final int timeoutMillis = connectionInfo.getTimeoutMillis();
Log.d(TAG, "forceRefresh, serverName = " + serverName);
if (client.requestTime(serverName, timeoutMillis, network)) {
long ntpCertainty = client.getRoundTripTime() / 2;
mTimeResult = new TimeResult(
client.getNtpTime(), client.getNtpTimeReference(), ntpCertainty);
Log.d(TAG, "]forceRefresh()-->requestTime true");
return true;
} else {
Log.d(TAG, "forceRefresh()-->requestTime false");
return false;
}
}
1.4.2 根据拿到的ntp时间设置系统时间
再回到onPollNetworkTimeUnderWakeLock方法,mTime.forceRefresh后,我们看到再次获取了一下cachedNtpResult,此时cachedNtpResult不再是null,所以下面代码的
if (cachedNtpResult != null && cachedNtpResult.getAgeMillis() < mPollingIntervalMs)
分支可以执行到,里面调用timeSuggestion将获取到的ntp时间设置到系统时间里
frameworks/base/services/core/java/com/android/server/NetworkTimeUpdateService.java
private void onPollNetworkTimeUnderWakeLock(int event) {
NtpTrustedTime.TimeResult cachedNtpResult = mTime.getCachedTimeResult();
if (cachedNtpResult == null || cachedNtpResult.getAgeMillis() >= mPollingIntervalMs) {
mTime.forceRefresh();
cachedNtpResult = mTime.getCachedTimeResult();
}
if (cachedNtpResult != null && cachedNtpResult.getAgeMillis() < mPollingIntervalMs) {
resetAlarm(mPollingIntervalMs);
// Suggest the time to the time detector. It may choose use it to set the system clock.
TimestampedValue<Long> timeSignal = new TimestampedValue<>(
cachedNtpResult.getElapsedRealtimeMillis(), cachedNtpResult.getTimeMillis());
NetworkTimeSuggestion timeSuggestion = new NetworkTimeSuggestion(timeSignal);
timeSuggestion.addDebugInfo("Origin: NetworkTimeUpdateService. event=" + event);
mTimeDetector.suggestNetworkTime(timeSuggestion);
} else {}
}
1.4.3 Sntp获取ntp服务器的时间
ntp端口123,在SntpClient里,会组一个udp包向ntpserver发送,并且阻塞的等待返回结果
public boolean requestTime(InetAddress address, int port, int timeout, Network network) {
DatagramSocket socket = null;
final int oldTag = TrafficStats.getAndSetThreadStatsTag(
TrafficStatsConstants.TAG_SYSTEM_NTP);
socket = new DatagramSocket();
network.bindSocket(socket);
socket.setSoTimeout(timeout);
byte[] buffer = new byte[NTP_PACKET_SIZE];
DatagramPacket request = new DatagramPacket(buffer, buffer.length, address, port);
// set mode = 3 (client) and version = 3
// mode is in low 3 bits of first byte
// version is in bits 3-5 of first byte
buffer[0] = NTP_MODE_CLIENT | (NTP_VERSION << 3);
// get current time and write it to the request packet
final long requestTime = System.currentTimeMillis();
final long requestTicks = SystemClock.elapsedRealtime();
writeTimeStamp(buffer, TRANSMIT_TIME_OFFSET, requestTime);
socket.send(request);
// read the response
DatagramPacket response = new DatagramPacket(buffer, buffer.length);
socket.receive(response);
}
面试题解析
回答是作者根据自己知识来回答的,没有标准答案,仅供参考:
- 简述下NTP时间同步的原理?⭐⭐⭐
回答:NTP(Network Time Protocol)时间同步的原理是通过网络协议来获取准确的时间信息,以使设备与网络上的时间保持同步。NTP采用了一种分层的时间同步算法,其中包括客户端和服务器之间的时间同步过程。 基本原理如下:
a. 客户端向NTP服务器发送时间请求。
b. NTP服务器回复时间响应,包含服务器的时间信息。
c. 客户端接收响应后,计算与服务器之间的时间差,并将其应用于本地时间。NTP算法还包括了一些复杂的机制,如时钟频率补偿、时钟偏移调整和时钟漂移补偿等,以提高时间同步的准确性和稳定性。
- 请简单解释下Android系统NTP网络时间同步的流程? ⭐⭐⭐
回答:
a. Android设备向NTP服务器发送时间请求,可以通过ntpdate命令或SntpClient类来实现。
b. NTP服务器回复时间响应,包含服务器的时间信息。
c. Android设备接收响应后,通过计算与服务器之间的时间差,将其应用于本地时间。
d. Android系统会将同步后的时间保存在系统时钟中,并在需要时更新系统时间。Android系统还提供了一些系统服务和API,如AlarmManager和 SystemClock,用于管理和调整系统时间,以确保时间的准确性和同步性。
- 如果有个系统时间不对的问题,请给出你的问题定位思路。⭐⭐⭐⭐⭐
回答:
a. 检查网络连接:确保设备与网络连接正常,NTP时间同步需要通过网络进行。如果是在未联网下报的问题,首先考虑电路是否带RTC计时、时区是否正确等
b. 检查NTP服务器配置:确认设备是否正确配置了可用的NTP服务器地址。
c. 检查系统时间设置:检查设备的系统时间设置,确保自动同步时间的选项已启用。
d. 手动进行时间同步:尝试手动进行时间同步,可以通过系统设置中的时间和日期选项进行。
e. 检查系统日志:查看系统日志,寻找与时间同步相关的错误或警告信息。
f. 检查硬件时钟:如果问题持续存在,可能是硬件时钟出现问题,可能需要进行硬件故障排查或更换硬件。
通过以上步骤的排查,可以逐步定位和解决系统时间不对的问题。
#许乔丹安卓面经##24届软开秋招面试经验大赏##我发现了面试通关密码##如何判断面试是否凉了##第一次面试#