2019年3月5日更新

进入下一步条件改为,时间大于>1970且网络已连接

之间校时存在的问题

1.无网出现几率太大

断电重启进入Launcher后,网路需要等待一会才会连接上传WiFi,这是页面大部分将会显示无网页面,之后校时成功后,整个Activity会把主要的页面重新提交,用户体验不好;

2.时区错误

经常重启几次后变成GMT+00:00时区,导致无论怎么做都会差8个小时;

日志分析

正常情况下的日志

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
01-02 08:00:07.300 579-579/com.onespax.launcher D/SyncTimeService: 启动了校时服务Fri Jan 02 08:00:07 GMT+08:00 1970
01-02 08:00:07.340 579-862/com.onespax.launcher D/SyncTimeService: 校时之前的时区:中国标准时间
01-02 08:00:07.400 579-862/com.onespax.launcher W/System.err: at com.spax.launcher.module.service.SyncTimeService$3.run(SyncTimeService.java:165)
01-02 08:00:07.400 579-862/com.onespax.launcher D/SyncTimeService: 网络校时失败
01-02 08:00:12.370 579-862/com.onespax.launcher D/SyncTimeService: 校时之前的时区:中国标准时间
01-02 08:00:12.380 579-862/com.onespax.launcher W/System.err: at com.spax.launcher.module.service.SyncTimeService$3.run(SyncTimeService.java:165)
01-02 08:00:12.380 579-862/com.onespax.launcher D/SyncTimeService: 网络校时失败
01-02 08:00:17.330 579-862/com.onespax.launcher D/SyncTimeService: 校时之前的时区:中国标准时间
01-02 08:00:17.380 579-862/com.onespax.launcher D/SyncTimeService: 没处理的网络时间:Mon Jan 14 14:33:33 GMT+08:00 2019
01-02 08:00:17.380 579-862/com.onespax.launcher D/SyncTimeService: 得到的网络时间:Mon Jan 14 14:33:33 GMT+08:00 2019
01-14 14:33:33.000 579-862/com.onespax.launcher D/SyncTimeService: 网络校时成功
01-14 14:33:33.000 579-862/com.onespax.launcher D/SyncTimeService: 执行的shell命令:date -s 20190114.143333
01-14 14:33:33.000 579-862/com.onespax.launcher D/SyncTimeService: 校时过后的时区:中国标准时间
01-14 14:33:33.030 579-579/com.onespax.launcher D/SyncTimeService: m_timeChangedReceiver onReceive()
01-14 14:33:33.060 579-862/com.onespax.launcher D/SyncTimeService: 校时之前的时区:中国标准时间
01-14 14:33:33.140 579-862/com.onespax.launcher D/SyncTimeService: 没处理的网络时间:Mon Jan 14 14:33:33 GMT+08:00 2019
01-14 14:33:33.140 579-862/com.onespax.launcher D/SyncTimeService: 得到的网络时间:Mon Jan 14 14:33:33 GMT+08:00 2019
01-14 14:33:33.150 579-862/com.onespax.launcher D/SyncTimeService: 系统的网络校时成功或者已经校对过时间

异常情况下的日志

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
01-02 08:00:07.250 579-853/com.onespax.launcher D/SyncTimeService: 校时之前的时区:GMT+00:00
01-02 08:00:07.260 579-853/com.onespax.launcher D/SyncTimeService: 网络校时失败
01-02 08:00:12.280 579-853/com.onespax.launcher D/SyncTimeService: 校时之前的时区:GMT+00:00
01-02 08:00:12.290 579-853/com.onespax.launcher D/SyncTimeService: 网络校时失败
01-02 08:00:17.240 579-853/com.onespax.launcher D/SyncTimeService: 校时之前的时区:GMT+00:00
01-02 08:00:17.290 579-853/com.onespax.launcher D/SyncTimeService: 没处理的网络时间:Mon Jan 14 07:35:30 GMT+00:00 2019
01-02 08:00:17.290 579-853/com.onespax.launcher D/SyncTimeService: 得到的网络时间:Mon Jan 14 07:35:30 GMT+00:00 2019
01-02 08:00:17.300 579-853/com.onespax.launcher D/SyncTimeService: 得到的系统时间:Fri Jan 02 00:00:17 GMT+00:00 1970
01-02 08:00:17.300 579-853/com.onespax.launcher D/SyncTimeService: 开始执行shell命令
01-14 07:35:30.000 579-853/com.onespax.launcher D/SyncTimeService: 网络校时成功
01-14 07:35:30.010 579-853/com.onespax.launcher D/SyncTimeService: 执行的shell命令:date -s 20190114.073530
01-14 07:35:30.010 579-853/com.onespax.launcher D/SyncTimeService: 校时过后的时区:GMT+00:00
01-14 07:35:30.060 579-853/com.onespax.launcher D/SyncTimeService: 校时之前的时区:GMT+00:00
01-14 07:35:30.070 579-579/com.onespax.launcher D/SyncTimeService: m_timeChangedReceiver onReceive()
01-14 07:35:30.100 579-853/com.onespax.launcher D/SyncTimeService: 没处理的网络时间:Mon Jan 14 07:35:30 GMT+00:00 2019
01-14 07:35:30.100 579-853/com.onespax.launcher D/SyncTimeService: 得到的网络时间:Mon Jan 14 07:35:30 GMT+00:00 2019
01-14 07:35:30.110 579-853/com.onespax.launcher D/SyncTimeService: 得到的系统时间:Sun Jan 13 23:35:30 GMT+00:00 2019
01-14 07:35:30.110 579-853/com.onespax.launcher D/SyncTimeService: 系统的网络校时成功或者已经校对过时间了

发现问题

之前老是断电重启系统时间差八小时,是此时系统的时区变成GMT+00:00,所以才有上篇文章提到的使用每次都用shell命令设置时区,这种做法加大了GMT+00:00出现的可能性。

1
setprop persist.sys.timezone Asia/Shanghai

尝试怀疑是我写的有问题,重新写一个显示时间的程序,install到板子上发现程序时间是正确的,但是我们的launcher的时间仍是差8小时,故将我们的launcher kill掉重新启动,时间正常,故应该是当系统启动后马上启动我们的launcher,时区没有设置好,默认的是GMT+00:00,而此时我们的launcher已把之前的系统时区加载到进程中了,不会再次加载,故需要kill掉进程后,重新加载一遍

改进中心思想

之前5秒一次校时的Service逻辑不变,不手动设置时区,用shell设置时间

在InitActivity中每秒检查当前时间年份是否大于1970,再做下一步

实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
private void next() {
/**
* 检查时间是否正确
*/
DebugLogger.d(TAG, "开始检查时间是否正确");
CountDownLatch countDownLatch = new CountDownLatch(1);
TimeHandler timeHandler = new TimeHandler(countDownLatch);
timeHandler.start();
try {
countDownLatch.await(30, TimeUnit.SECONDS);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
DebugLogger.d(TAG, "时间检查结束");
jumpToNextActivity();
}
}

private void jumpToNextActivity() {
/**
* 时区不正确但是时间是正确的需要重启一下app
*/
if (TimeZone.getDefault().getDisplayName().equals("GMT+00:00") && Calendar.getInstance().get(Calendar.YEAR) > 1970){
DebugLogger.d(TAG, "时区获取的不正确,需要退出重启APP");
Intent LaunchIntent = getPackageManager().getLaunchIntentForPackage(getApplication().getPackageName());
LaunchIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(LaunchIntent);
System.exit(0);
return;
}
/**
* 跳转到其他页面
*/
final boolean checkRet = SharedPrefsUtil.getConfig(App.getInstance(), Constants.Config.IS_NEED_UPDATE, false);
Logger.t(TAG).d("checkRet:" + checkRet);
Class<? extends Context> clazz = checkRet ? UpgradeActivity.class : SplashActivity.class;
if (!checkRet) {
InstallFilePolicy installFilePolicy = new InstallFilePolicy(null);
SpaxInstallConfig restore = installFilePolicy.restore();
if (restore != null) {
RootCmd.execRootCmd("rm -rf " + restore.getApkPath());
}
}
Intent intent = new Intent(InitConfigActivity.this, clazz);
startActivity(intent);
finish();
}
private static final class TimeHandler extends Thread {
private CountDownLatch countDownLatch;
private int count;
private boolean flag = true;

private TimeHandler(CountDownLatch countDownLatch) {
this.countDownLatch = countDownLatch;
}

@Override
public void run() {
while (flag){
try {
if (count == 30){
countDownLatch.countDown();
flag = false;
return;
}
Thread.sleep(1000);
// 在android5.1.1上表现为校时成功后但是没有连上网,所以要加一个条件限制
if (Calendar.getInstance().get(Calendar.YEAR) > 1970
&& CommonUtil.isNetworkAvailable(App.getInstance())){
countDownLatch.countDown();
flag = false;
}
} catch (InterruptedException e) {
e.printStackTrace();
countDownLatch.countDown();
flag = false;
}
count ++;
}
}
}

开一个线程每秒轮询,符合条件下次结束,同时countDownLatch.countDown();唤醒主线程

同时主线有超时等待,最后在finally中进入下一步