場景目的
最近有一個需求,需要修改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實作的,具體可以去看這個類的原始碼,自行分析,
結束語:本文僅用來學習記錄,參考查閱,
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/246579.html
標籤:其他
上一篇:Android OTA升級詳細流程分析(non-AB)
下一篇:了解android studio
