使用NTP服务器同步Android设备时间

来源:互联网 发布:新网注册域名流程 编辑:程序博客网 时间:2024/05/18 02:07

一、概述

最近在搞机器人项目,Pad在断电后时间会被恢复到出厂时间,开启了从网络中获取时间,有时有效,有时无效。所以需要利用NTP服务器来同步Pad的时间。在Android中已经存在一个SntpClient用于获取NTP服务器时间的类,只不过是hide类,直接拷出来为我所用。

二、代码实现

private final int NTP_TIME_OUT_MILLISECOND = 30000;    private final String LOG_TAG = TimeCalibrateHelper.class.getSimpleName();    private boolean isStopCalibrate = false;    /**     * ntp服务器地址集     */    private String[] ntpServerHost = new String[]{            "dns1.synet.edu.cn",            "news.neu.edu.cn",            "dns.sjtu.edu.cn",            "dns2.synet.edu.cn",            "ntp.glnet.edu.cn",            "ntp-sz.chl.la",            "ntp.gwadar.cn",            "cn.pool.ntp.org"    };    /**     * 开始校准时间     */    public void startCalibrateTime() {        new Thread() {            @Override            public void run() {                while (!isStopCalibrate) {                    for (int i = 0; i < ntpServerHost.length; i++) {                        long time = getTimeFromNtpServer(ntpServerHost[i]);                        if (time != -1) {                            int tryCount = 3;                            while (tryCount > 0) {                                tryCount--;                                boolean isSetTimeSuccessful = setCurrentTimeMillis(time);                                if (isSetTimeSuccessful) {                                    tryCount = 0;                                    isStopCalibrate = true;                                    Log.i(LOG_TAG, "set time successful");                                } else {                                    Log.i(LOG_TAG, "set time failure");                                }                            }                            break;                        }                    }                }            }        }.start();    }    /**     * 停止校准时间     */    public void stopCalibrateTime() {        isStopCalibrate = true;    }    /**     * 从ntp服务器中获取时间     *     * @param ntpHost ntp服务器域名地址     * @return 如果失败返回-1,否则返回当前的毫秒数     */    private long getTimeFromNtpServer(String ntpHost) {        Log.i(LOG_TAG, "get time from " + ntpHost);        SntpClient client = new SntpClient();        boolean isSuccessful = client.requestTime(ntpHost, NTP_TIME_OUT_MILLISECOND);        if (isSuccessful) {            return client.getNtpTime();        }        return -1;    }    /**     * 设置当前的系统时间     *     * @param time     * @return true表示设置成功, false表示设置失败     */    public boolean setCurrentTimeMillis(long time) {        try {            if (ShellUtils.checkRootPermission()) {                TimeZone.setDefault(TimeZone.getTimeZone("GMT+8"));                Date current = new Date(time);                SimpleDateFormat df = new SimpleDateFormat("yyyyMMdd.HHmmss");                String datetime = df.format(current);                Process process = Runtime.getRuntime().exec("su");                DataOutputStream os = new DataOutputStream(process.getOutputStream());                //os.writeBytes("setprop persist.sys.timezone GMT\n");                os.writeBytes("/system/bin/date -s " + datetime + "\n");                os.writeBytes("clock -w\n");                os.writeBytes("exit\n");                os.flush();                return true;            } else {                return false;            }        } catch (Exception e) {            return false;        }    }    public static class SntpClient {        private static final String TAG = "SntpClient";        private static final int REFERENCE_TIME_OFFSET = 16;        private static final int ORIGINATE_TIME_OFFSET = 24;        private static final int RECEIVE_TIME_OFFSET = 32;        private static final int TRANSMIT_TIME_OFFSET = 40;        private static final int NTP_PACKET_SIZE = 48;        private static final int NTP_PORT = 123;        private static final int NTP_MODE_CLIENT = 3;        private static final int NTP_VERSION = 3;        // Number of seconds between Jan 1, 1900 and Jan 1, 1970        // 70 years plus 17 leap days        private static final long OFFSET_1900_TO_1970 = ((365L * 70L) + 17L) * 24L * 60L * 60L;        // system time computed from NTP server response        private long mNtpTime;        // value of SystemClock.elapsedRealtime() corresponding to mNtpTime        private long mNtpTimeReference;        // round trip time in milliseconds        private long mRoundTripTime;        /**         * Sends an SNTP request to the given host and processes the response.         *         * @param host    host name of the server.         * @param timeout network timeout in milliseconds.         * @return true if the transaction was successful.         */        public boolean requestTime(String host, int timeout) {            DatagramSocket socket = null;            try {                socket = new DatagramSocket();                socket.setSoTimeout(timeout);                InetAddress address = InetAddress.getByName(host);                byte[] buffer = new byte[NTP_PACKET_SIZE];                DatagramPacket request = new DatagramPacket(buffer, buffer.length, address, NTP_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                long requestTime = System.currentTimeMillis();                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);                long responseTicks = SystemClock.elapsedRealtime();                long responseTime = requestTime + (responseTicks - requestTicks);                // extract the results                long originateTime = readTimeStamp(buffer, ORIGINATE_TIME_OFFSET);                long receiveTime = readTimeStamp(buffer, RECEIVE_TIME_OFFSET);                long transmitTime = readTimeStamp(buffer, TRANSMIT_TIME_OFFSET);                long roundTripTime = responseTicks - requestTicks - (transmitTime - receiveTime);                // receiveTime = originateTime + transit + skew                // responseTime = transmitTime + transit - skew                // clockOffset = ((receiveTime - originateTime) + (transmitTime - responseTime))/2                //             = ((originateTime + transit + skew - originateTime) +                //                (transmitTime - (transmitTime + transit - skew)))/2                //             = ((transit + skew) + (transmitTime - transmitTime - transit + skew))/2                //             = (transit + skew - transit + skew)/2                //             = (2 * skew)/2 = skew                long clockOffset = ((receiveTime - originateTime) + (transmitTime - responseTime)) / 2;                // if (false) Log.d(TAG, "round trip: " + roundTripTime + " ms");                // if (false) Log.d(TAG, "clock offset: " + clockOffset + " ms");                // save our results - use the times on this side of the network latency                // (response rather than request time)                mNtpTime = responseTime + clockOffset;                mNtpTimeReference = responseTicks;                mRoundTripTime = roundTripTime;            } catch (Exception e) {                if (false) Log.d(TAG, "request time failed: " + e);                return false;            } finally {                if (socket != null) {                    socket.close();                }            }            return true;        }        /**         * Returns the time computed from the NTP transaction.         *         * @return time value computed from NTP server response.         */        public long getNtpTime() {            return mNtpTime;        }        /**         * Returns the reference clock value (value of SystemClock.elapsedRealtime())         * corresponding to the NTP time.         *         * @return reference clock corresponding to the NTP time.         */        public long getNtpTimeReference() {            return mNtpTimeReference;        }        /**         * Returns the round trip time of the NTP transaction         *         * @return round trip time in milliseconds.         */        public long getRoundTripTime() {            return mRoundTripTime;        }        /**         * Reads an unsigned 32 bit big endian number from the given offset in the buffer.         */        private long read32(byte[] buffer, int offset) {            byte b0 = buffer[offset];            byte b1 = buffer[offset + 1];            byte b2 = buffer[offset + 2];            byte b3 = buffer[offset + 3];            // convert signed bytes to unsigned values            int i0 = ((b0 & 0x80) == 0x80 ? (b0 & 0x7F) + 0x80 : b0);            int i1 = ((b1 & 0x80) == 0x80 ? (b1 & 0x7F) + 0x80 : b1);            int i2 = ((b2 & 0x80) == 0x80 ? (b2 & 0x7F) + 0x80 : b2);            int i3 = ((b3 & 0x80) == 0x80 ? (b3 & 0x7F) + 0x80 : b3);            return ((long) i0 << 24) + ((long) i1 << 16) + ((long) i2 << 8) + (long) i3;        }        /**         * Reads the NTP time stamp at the given offset in the buffer and returns         * it as a system time (milliseconds since January 1, 1970).         */        private long readTimeStamp(byte[] buffer, int offset) {            long seconds = read32(buffer, offset);            long fraction = read32(buffer, offset + 4);            return ((seconds - OFFSET_1900_TO_1970) * 1000) + ((fraction * 1000L) / 0x100000000L);        }        /**         * Writes system time (milliseconds since January 1, 1970) as an NTP time stamp         * at the given offset in the buffer.         */        private void writeTimeStamp(byte[] buffer, int offset, long time) {            long seconds = time / 1000L;            long milliseconds = time - seconds * 1000L;            seconds += OFFSET_1900_TO_1970;            // write seconds in big endian format            buffer[offset++] = (byte) (seconds >> 24);            buffer[offset++] = (byte) (seconds >> 16);            buffer[offset++] = (byte) (seconds >> 8);            buffer[offset++] = (byte) (seconds >> 0);            long fraction = milliseconds * 0x100000000L / 1000L;            // write fraction in big endian format            buffer[offset++] = (byte) (fraction >> 24);            buffer[offset++] = (byte) (fraction >> 16);            buffer[offset++] = (byte) (fraction >> 8);            // low order bits should be random data            buffer[offset++] = (byte) (Math.random() * 255.0);        }    }}
  • 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
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260
  • 261
  • 262
  • 263
  • 264
  • 265
  • 266
  • 267
  • 268
  • 269
  • 270
  • 271
  • 272
  • 273
  • 274
  • 275
  • 276
  • 277
  • 278
  • 279
  • 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
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260
  • 261
  • 262
  • 263
  • 264
  • 265
  • 266
  • 267
  • 268
  • 269
  • 270
  • 271
  • 272
  • 273
  • 274
  • 275
  • 276
  • 277
  • 278
  • 279

修改系统时间需要Root权限,所以必须要为应用授予Root权限,上面代码中的ShellUtils代码如下

/** * ShellUtils * <ul> * <strong>Check root</strong> * <li>{@link ShellUtils#checkRootPermission()}</li> * </ul> * <ul> * <strong>Execte command</strong> * <li>{@link ShellUtils#execCommand(String, boolean)}</li> * <li>{@link ShellUtils#execCommand(String, boolean, boolean)}</li> * <li>{@link ShellUtils#execCommand(List, boolean)}</li> * <li>{@link ShellUtils#execCommand(List, boolean, boolean)}</li> * <li>{@link ShellUtils#execCommand(String[], boolean)}</li> * <li>{@link ShellUtils#execCommand(String[], boolean, boolean)}</li> * </ul> *  * @author <a href="http://www.trinea.cn" target="_blank">Trinea</a> 2013-5-16 */public class ShellUtils {    public static final String COMMAND_SU       = "su";    public static final String COMMAND_SH       = "sh";    public static final String COMMAND_EXIT     = "exit\n";    public static final String COMMAND_LINE_END = "\n";    private ShellUtils() {        throw new AssertionError();    }    /**     * check whether has root permission     *      * @return     */    public static boolean checkRootPermission() {        return execCommand("echo root", true, false).result == 0;    }    /**     * execute shell command, default return result msg     *      * @param command command     * @param isRoot whether need to run with root     * @return     * @see ShellUtils#execCommand(String[], boolean, boolean)     */    public static CommandResult execCommand(String command, boolean isRoot) {        return execCommand(new String[] {command}, isRoot, true);    }    /**     * execute shell commands, default return result msg     *      * @param commands command list     * @param isRoot whether need to run with root     * @return     * @see ShellUtils#execCommand(String[], boolean, boolean)     */    public static CommandResult execCommand(List<String> commands, boolean isRoot) {        return execCommand(commands == null ? null : commands.toArray(new String[] {}), isRoot, true);    }    /**     * execute shell commands, default return result msg     *      * @param commands command array     * @param isRoot whether need to run with root     * @return     * @see ShellUtils#execCommand(String[], boolean, boolean)     */    public static CommandResult execCommand(String[] commands, boolean isRoot) {        return execCommand(commands, isRoot, true);    }    /**     * execute shell command     *      * @param command command     * @param isRoot whether need to run with root     * @param isNeedResultMsg whether need result msg     * @return     * @see ShellUtils#execCommand(String[], boolean, boolean)     */    public static CommandResult execCommand(String command, boolean isRoot, boolean isNeedResultMsg) {        return execCommand(new String[] {command}, isRoot, isNeedResultMsg);    }    /**     * execute shell commands     *      * @param commands command list     * @param isRoot whether need to run with root     * @param isNeedResultMsg whether need result msg     * @return     * @see ShellUtils#execCommand(String[], boolean, boolean)     */    public static CommandResult execCommand(List<String> commands, boolean isRoot, boolean isNeedResultMsg) {        return execCommand(commands == null ? null : commands.toArray(new String[] {}), isRoot, isNeedResultMsg);    }    /**     * execute shell commands     *      * @param commands command array     * @param isRoot whether need to run with root     * @param isNeedResultMsg whether need result msg     * @return <ul>     *         <li>if isNeedResultMsg is false, {@link CommandResult#successMsg} is null and     *         {@link CommandResult#errorMsg} is null.</li>     *         <li>if {@link CommandResult#result} is -1, there maybe some excepiton.</li>     *         </ul>     */    public static CommandResult execCommand(String[] commands, boolean isRoot, boolean isNeedResultMsg) {        int result = -1;        if (commands == null || commands.length == 0) {            return new CommandResult(result, null, null);        }        Process process = null;        BufferedReader successResult = null;        BufferedReader errorResult = null;        StringBuilder successMsg = null;        StringBuilder errorMsg = null;        DataOutputStream os = null;        try {            process = Runtime.getRuntime().exec(isRoot ? COMMAND_SU : COMMAND_SH);            os = new DataOutputStream(process.getOutputStream());            for (String command : commands) {                if (command == null) {                    continue;                }                // donnot use os.writeBytes(commmand), avoid chinese charset error                os.write(command.getBytes());                os.writeBytes(COMMAND_LINE_END);                os.flush();            }            os.writeBytes(COMMAND_EXIT);            os.flush();            result = process.waitFor();            // get command result            if (isNeedResultMsg) {                successMsg = new StringBuilder();                errorMsg = new StringBuilder();                successResult = new BufferedReader(new InputStreamReader(process.getInputStream()));                errorResult = new BufferedReader(new InputStreamReader(process.getErrorStream()));                String s;                while ((s = successResult.readLine()) != null) {                    successMsg.append(s);                }                while ((s = errorResult.readLine()) != null) {                    errorMsg.append(s);                }            }        } catch (IOException e) {            e.printStackTrace();        } catch (Exception e) {            e.printStackTrace();        } finally {            try {                if (os != null) {                    os.close();                }                if (successResult != null) {                    successResult.close();                }                if (errorResult != null) {                    errorResult.close();                }            } catch (IOException e) {                e.printStackTrace();            }            if (process != null) {                process.destroy();            }        }        return new CommandResult(result, successMsg == null ? null : successMsg.toString(), errorMsg == null ? null                : errorMsg.toString());    }    /**     * result of command     * <ul>     * <li>{@link CommandResult#result} means result of command, 0 means normal, else means error, same to excute in     * linux shell</li>     * <li>{@link CommandResult#successMsg} means success message of command result</li>     * <li>{@link CommandResult#errorMsg} means error message of command result</li>     * </ul>     *      * @author <a href="http://www.trinea.cn" target="_blank">Trinea</a> 2013-5-16     */    public static class CommandResult {        /** result of command **/        public int    result;        /** success message of command result **/        public String successMsg;        /** error message of command result **/        public String errorMsg;        public CommandResult(int result) {            this.result = result;        }        public CommandResult(int result, String successMsg, String errorMsg) {            this.result = result;            this.successMsg = successMsg;            this.errorMsg = errorMsg;        }    }}
0 0
原创粉丝点击