场景目的

最近有一个需求,需要修改Android设备的时间服务器。如果是普通的Android手机可以通过GPS或者其它的方法在没有网的情况下同步时间,但是对于只是搭载了Android系统的设备(如门禁、售货机之类)在无法连接外网的环境中就不那么容易做到了。

在内网服务器请求IP地址通过头部或者回复携带参数,可以让时间下发到设备上,不过就需要我们用代码时常去校准,使用能 ping 通的时间服务器可以让系统进行自动处理。

命令修改

刚开始的时候,我想使用的是通过在Android程序中调用adb shell命令来修改时间服务器,也确实有这样的命令存在。

settings put global ntp_server ntp1.aliyun.com

ntp1.aliyun.com是阿里的时间服务器域名,可以设置成其它的或者ip。

网上说要使用这条命令需要先执行 su 命令,我按照说的去做,给Android设备设置了一个没有网络的局域网IP,然后让设备去通过网络同步时间确实是做到了,说明这条命令是有效的。

但是命令行窗口能够成功修改,在 APP 中调用却未必能够同样生效。

Process process = Runtime.getRuntime().exec(isRoot ? "su" : "sh");

在执行上面代码的时候,报了如下错误:

Cannot run program "su": error=13,Premission denied

它说不能执行su,但我的设备已经root了,应该是不会出现这个问题的。我搜索了一下,大多说需要修改Android源码,在alps\system\extras\su下的su.c中有这样一句代码:

if (current_uid != AID_ROOT && current_uid != AID_SHELL) error(1, 0, "not allowed");

似乎和这个有关系,但就算能成功,我的需求也不能通过修改源码来实现。

如果不执行su命令,好像有时也能修改时间服务器,因为我在搜索过程中想到了另一种方法,所以这个没有验证,有兴趣的朋友可以自己研究。

通过id设置

因为使用shell命令不能正常修改,我就想到能不能获取到当前使用的时间服务器是哪个。根据查找资料,我知道系统默认的是设置在frameworks\base\core\res\res\values下的config.xml中:

<string translatable="false" name="config_ntpServer">asia.pool.ntp.org</string>

在代码中可以通过com.android.internal.R.string.config_ntpServer引用到,因为各种Android系统版本不同,所以这么写编译是不通过的,我们需要通过id(config_ntpServer)获取。

int id = Resources.getSystem().getIdentifier("config_ntpServer", "string", "android");String defaultServer = Resources.getSystem().getString(id);

config.xml是我们可以获取到的资源文件,可以通过id获取到,defaultServer就是默认的时间服务器asia.pool.ntp.org。

除了系统默认的,还有一个用户设置的,也就是我们要修改的那个时间服务器,没有配置过的时候它是NULL,逻辑如下:

    public static synchronized NtpTrustedTime getInstance(Context context) {             if (sSingleton == null) {                 final Resources res = context.getResources();            final ContentResolver resolver = context.getContentResolver();            final String defaultServer = res.getString(                    com.android.internal.R.string.config_ntpServer);            final long defaultTimeout = res.getInteger(                    com.android.internal.R.integer.config_ntpTimeout);            final String secureServer = Settings.Global.getString(                    resolver, Settings.Global.NTP_SERVER);            final long timeout = Settings.Global.getLong(                    resolver, Settings.Global.NTP_TIMEOUT, defaultTimeout);            final String server = secureServer != null ? secureServer : defaultServer;            sSingleton = new NtpTrustedTime(server, timeout);            sContext = context;        }        return sSingleton;    }

这是frameworks\base\core\java\android\util\NtpTrustedTime.java中代码,这个类便是ntp更新时间的相关类。从上我们可以看到时间服务器是优先选择secureServer,也就是我们来设置的那个。

源码中使用Settings.Global.NTP_SERVER存储用户设置的服务器值,我们可以找到这个NTP_SERVER,frameworks\base\core\java\android\provider\Settings.java。

public static final String NTP_SERVER = "ntp_server";

我们来调用的代码为:

ContentResolver resolver = context.getContentResolver();Settings.Global.putString(resolver, "ntp_server", address);//address为你想要配置的服务器域名String secureServer = Settings.Global.getString(resolver, "ntp_server");

用上面的代码就可以配置并且确认是否修改成功,我将自己的电脑设置成NTP服务器后修改了电脑时间(网上有教程),用上面的方法将Android设备的时间服务器修改成电脑的IP,设备重启后时间确实同步了。

当然,你的App必须设置为系统应用才能进行修改的操作。

这里再介绍一点,在NtpTrustedTime中有调用SntpClient这个类:

    final SntpClient client = new SntpClient();    if (client.requestTime(mServer, (int) mTimeout)) {             mHasCache = true;        mCachedNtpTime = client.getNtpTime();        mCachedNtpElapsedRealtime = client.getNtpTimeReference();        mCachedNtpCertainty = client.getRoundTripTime() / 2;        return true;    } else {             return false;    }

关于时间服务器如何校准时间的逻辑便是由SntpClient实现的,具体可以去看这个类的源码,自行分析。

结束语:本文仅用来学习记录,参考查阅。

更多相关文章

  1. Android(安卓)自定义自由选择时间区间的日历控件
  2. Android(安卓)优化电池使用时间 ——监控电池电量和充电状态
  3. 两部android设备通过服务器转发实现通信简单demo
  4. Eclipse下修改Android里的apk包名
  5. Android(安卓)手机端与服务器端通过http交换数据 Json
  6. Android(安卓)进阶——实现周期性任务调度的几种攻略详解
  7. Android(安卓)在测试阶段当出现多个测试服务器地址时打包的小技
  8. 修改android 4.4系统下面的休眠时间,只留下永不休眠选项
  9. Launcher功能的修改及添加,本篇是一些小功能的展示,通知栏显隐,dock

随机推荐

  1. 相对布局控制控件居右显示
  2. android-环境
  3. android 自定义TextView实现秒级数字时钟
  4. Android之自定义适配器
  5. android 生成密钥 签名
  6. mono for android Main.axml
  7. Error: Could not find gradle wrapper w
  8. android developers api guides 文档学习
  9. android api
  10. 在android应用市场中直接定位到自己的应