Android车载系统时间同步方案具体实现
下面我将详细介绍各种时间同步方案的具体实现代码,包括完整的实现逻辑和关键代码片段。
一、NTP时间同步实现
完整实现类
- public class NtpTimeSync {
- private static final String TAG = "NtpTimeSync";
- private static final String NTP_SERVER = "pool.ntp.org";
- private static final int TIMEOUT_MS = 10_000;
- public interface TimeSyncCallback {
- void onSuccess(long newTime);
- void onFailure(String error);
- }
- public static void syncSystemTime(Context context, TimeSyncCallback callback) {
- if (!isNetworkAvailable(context)) {
- callback.onFailure("Network not available");
- return;
- }
- new AsyncTask<Void, Void, Long>() {
- @Override
- protected Long doInBackground(Void... voids) {
- SntpClient client = new SntpClient();
- try {
- if (client.requestTime(NTP_SERVER, TIMEOUT_MS)) {
- long now = client.getNtpTime() + SystemClock.elapsedRealtime() -
- client.getNtpTimeReference();
- return now;
- }
- } catch (Exception e) {
- Log.e(TAG, "NTP sync failed", e);
- }
- return null;
- }
- @Override
- protected void onPostExecute(Long result) {
- if (result != null) {
- if (hasSetTimePermission(context)) {
- SystemClock.setCurrentTimeMillis(result);
- callback.onSuccess(result);
- } else {
- callback.onFailure("No SET_TIME permission");
- }
- } else {
- callback.onFailure("NTP sync failed");
- }
- }
- }.execute();
- }
- private static boolean isNetworkAvailable(Context context) {
- ConnectivityManager cm = (ConnectivityManager)
- context.getSystemService(Context.CONNECTIVITY_SERVICE);
- NetworkInfo netInfo = cm.getActiveNetworkInfo();
- return netInfo != null && netInfo.isConnected();
- }
- private static boolean hasSetTimePermission(Context context) {
- return context.checkSelfPermission(android.Manifest.permission.SET_TIME) ==
- PackageManager.PERMISSION_GRANTED;
- }
- }
复制代码 使用示例
- NtpTimeSync.syncSystemTime(context, new NtpTimeSync.TimeSyncCallback() {
- @Override
- public void onSuccess(long newTime) {
- Log.d(TAG, "Time synchronized successfully: " + new Date(newTime));
- }
- @Override
- public void onFailure(String error) {
- Log.e(TAG, "Time sync failed: " + error);
- }
- });
复制代码 二、GPS时间同步实现
完整实现类
- public class GpsTimeSync {
- private static final String TAG = "GpsTimeSync";
- private LocationManager locationManager;
- private GpsTimeListener listener;
- private Context context;
- public interface GpsTimeListener {
- void onGpsTimeReceived(long gpsTime);
- void onGpsStatusChanged(boolean available);
- }
- public GpsTimeSync(Context context, GpsTimeListener listener) {
- this.context = context.getApplicationContext();
- this.listener = listener;
- this.locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
- }
- public void startListening() {
- if (hasLocationPermission()) {
- try {
- locationManager.requestLocationUpdates(
- LocationManager.GPS_PROVIDER,
- 0,
- 0,
- locationListener
- );
-
- // 检查GPS状态变化
- locationManager.addGpsStatusListener(gpsStatusListener);
- } catch (Exception e) {
- Log.e(TAG, "Failed to request location updates", e);
- }
- } else {
- Log.w(TAG, "Location permission not granted");
- }
- }
- public void stopListening() {
- locationManager.removeUpdates(locationListener);
- locationManager.removeGpsStatusListener(gpsStatusListener);
- }
- private final LocationListener locationListener = new LocationListener() {
- @Override
- public void onLocationChanged(Location location) {
- if (location != null) {
- long gpsTime = location.getTime();
- listener.onGpsTimeReceived(gpsTime);
- }
- }
- @Override public void onStatusChanged(String provider, int status, Bundle extras) {}
- @Override public void onProviderEnabled(String provider) {}
- @Override public void onProviderDisabled(String provider) {}
- };
- private final GpsStatus.Listener gpsStatusListener = new GpsStatus.Listener() {
- @Override
- public void onGpsStatusChanged(int event) {
- boolean gpsFixed = false;
- if (event == GpsStatus.GPS_EVENT_SATELLITE_STATUS) {
- GpsStatus status = locationManager.getGpsStatus(null);
- Iterable<GpsSatellite> satellites = status.getSatellites();
- int satellitesCount = 0;
- for (GpsSatellite satellite : satellites) {
- if (satellite.usedInFix()) {
- satellitesCount++;
- }
- }
- gpsFixed = satellitesCount >= 3;
- }
- listener.onGpsStatusChanged(gpsFixed);
- }
- };
- private boolean hasLocationPermission() {
- return ContextCompat.checkSelfPermission(context,
- Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED;
- }
- }
复制代码 使用示例
- GpsTimeSync gpsTimeSync = new GpsTimeSync(context, new GpsTimeSync.GpsTimeListener() {
- @Override
- public void onGpsTimeReceived(long gpsTime) {
- // 同步系统时间
- if (hasSetTimePermission()) {
- SystemClock.setCurrentTimeMillis(gpsTime);
- }
- }
- @Override
- public void onGpsStatusChanged(boolean available) {
- Log.d(TAG, "GPS availability changed: " + available);
- }
- });
- // 开始监听
- gpsTimeSync.startListening();
- // 停止监听(在适当的时候调用)
- // gpsTimeSync.stopListening();
复制代码 三、CAN总线时间同步实现
JNI部分实现 (C代码)
- #include <jni.h>
- #include
- #include <canbus/can.h>
- #define TAG "CANTimeSync"
- // CAN接收回调
- void can_receive_callback(can_frame_t *frame) {
- if (frame->can_id == 0x123) { // 假设0x123是时间信息帧ID
- uint64_t vehicle_time = 0;
- memcpy(&vehicle_time, frame->data, sizeof(uint64_t));
-
- // 调用Java层方法
- JNIEnv *env;
- (*g_vm)->AttachCurrentThread(g_vm, &env, NULL);
-
- jclass cls = (*env)->GetObjectClass(env, g_java_obj);
- jmethodID method = (*env)->GetMethodID(env, cls, "onCanTimeReceived", "(J)V");
- (*env)->CallVoidMethod(env, g_java_obj, method, (jlong)vehicle_time);
-
- (*g_vm)->DetachCurrentThread(g_vm);
- }
- }
- // JNI初始化
- JNIEXPORT void JNICALL
- Java_com_example_CanTimeSync_initCanBus(JNIEnv *env, jobject instance) {
- // 保存Java对象和VM引用
- g_java_obj = (*env)->NewGlobalRef(env, instance);
- (*env)->GetJavaVM(env, &g_vm);
-
- // 初始化CAN总线
- if (can_init() != 0) {
- __android_log_write(ANDROID_LOG_ERROR, TAG, "CAN init failed");
- return;
- }
-
- // 设置接收回调
- can_set_receive_callback(can_receive_callback);
- }
- // JNI关闭
- JNIEXPORT void JNICALL
- Java_com_example_CanTimeSync_closeCanBus(JNIEnv *env, jobject instance) {
- can_close();
- (*env)->DeleteGlobalRef(env, g_java_obj);
- }
复制代码 Java层实现
- public class CanTimeSync {
- private static final String TAG = "CanTimeSync";
-
- static {
- System.loadLibrary("cantimesync");
- }
-
- public interface CanTimeListener {
- void onCanTimeReceived(long vehicleTime);
- void onCanError(String error);
- }
-
- private CanTimeListener listener;
-
- public CanTimeSync(CanTimeListener listener) {
- this.listener = listener;
- }
-
- public void start() {
- try {
- initCanBus();
- } catch (Exception e) {
- listener.onCanError("CAN init failed: " + e.getMessage());
- }
- }
-
- public void stop() {
- closeCanBus();
- }
-
- // 由JNI调用的方法
- private void onCanTimeReceived(long vehicleTime) {
- listener.onCanTimeReceived(vehicleTime);
- }
-
- // Native方法
- private native void initCanBus();
- private native void closeCanBus();
- }
复制代码 使用示例
- CanTimeSync canTimeSync = new CanTimeSync(new CanTimeSync.CanTimeListener() {
- @Override
- public void onCanTimeReceived(long vehicleTime) {
- // 转换时间格式并同步
- long systemTime = convertCanTimeToSystemTime(vehicleTime);
- if (hasSetTimePermission()) {
- SystemClock.setCurrentTimeMillis(systemTime);
- }
- }
- @Override
- public void onCanError(String error) {
- Log.e(TAG, "CAN error: " + error);
- }
- });
- // 启动CAN时间同步
- canTimeSync.start();
- // 停止同步(在适当的时候调用)
- // canTimeSync.stop();
复制代码 四、PTP时间同步实现
PTP客户端实现
- public class PtpTimeSync {
- private static final String TAG = "PtpTimeSync";
- private static final String PTP_IFACE = "eth0";
-
- public interface PtpSyncListener {
- void onPtpSyncComplete(long offsetNanos);
- void onPtpSyncError(String error);
- }
-
- public static void syncWithPtp(PtpSyncListener listener) {
- new Thread(() -> {
- try {
- Process process = Runtime.getRuntime().exec("ptp4l -i " + PTP_IFACE + " -m");
- BufferedReader reader = new BufferedReader(
- new InputStreamReader(process.getInputStream()));
-
- String line;
- while ((line = reader.readLine()) != null) {
- if (line.contains("offset")) {
- // 解析偏移量: master offset -1234 s2 freq
- String[] parts = line.split("\\s+");
- if (parts.length >= 4) {
- long offset = Long.parseLong(parts[3]);
- listener.onPtpSyncComplete(offset);
- }
- }
- }
-
- int exitCode = process.waitFor();
- if (exitCode != 0) {
- listener.onPtpSyncError("PTP process exited with code " + exitCode);
- }
- } catch (Exception e) {
- listener.onPtpSyncError("PTP sync failed: " + e.getMessage());
- }
- }).start();
- }
-
- public static void adjustSystemClock(long offsetNanos) {
- long millis = offsetNanos / 1_000_000;
- if (millis != 0) {
- long current = System.currentTimeMillis();
- SystemClock.setCurrentTimeMillis(current + millis);
- }
- }
- }
复制代码 使用示例
- PtpTimeSync.syncWithPtp(new PtpTimeSync.PtpSyncListener() {
- @Override
- public void onPtpSyncComplete(long offsetNanos) {
- Log.d(TAG, "PTP offset: " + offsetNanos + " ns");
- if (Math.abs(offsetNanos) > 100_000) { // 如果偏移大于100μs
- PtpTimeSync.adjustSystemClock(offsetNanos);
- }
- }
- @Override
- public void onPtpSyncError(String error) {
- Log.e(TAG, "PTP error: " + error);
- }
- });
复制代码 五、混合时间同步策略实现
综合时间同步管理器
- public class TimeSyncManager {
- private static final String TAG = "TimeSyncManager";
- private static final long SYNC_INTERVAL = 60_000; // 1分钟
-
- private Context context;
- private Handler handler;
- private NtpTimeSync.TimeSyncCallback ntpCallback;
- private GpsTimeSync gpsTimeSync;
- private CanTimeSync canTimeSync;
-
- private long lastSyncTime;
- private TimeSource currentSource = TimeSource.LOCAL;
-
- public enum TimeSource {
- GPS, NTP, CAN, PTP, LOCAL
- }
-
- public interface SyncStatusListener {
- void onSyncStatusChanged(TimeSource source, long time, long offset);
- }
-
- public TimeSyncManager(Context context) {
- this.context = context.getApplicationContext();
- this.handler = new Handler(Looper.getMainLooper());
-
- initCallbacks();
- initGpsSync();
- initCanSync();
- }
-
- private void initCallbacks() {
- ntpCallback = new NtpTimeSync.TimeSyncCallback() {
- @Override
- public void onSuccess(long newTime) {
- long offset = newTime - System.currentTimeMillis();
- updateTime(TimeSource.NTP, newTime, offset);
- }
- @Override
- public void onFailure(String error) {
- Log.w(TAG, "NTP sync failed: " + error);
- }
- };
- }
-
- private void initGpsSync() {
- gpsTimeSync = new GpsTimeSync(context, new GpsTimeSync.GpsTimeListener() {
- @Override
- public void onGpsTimeReceived(long gpsTime) {
- long offset = gpsTime - System.currentTimeMillis();
- updateTime(TimeSource.GPS, gpsTime, offset);
- }
- @Override
- public void onGpsStatusChanged(boolean available) {
- if (available) {
- Log.d(TAG, "GPS available, preferring GPS time");
- }
- }
- });
- gpsTimeSync.startListening();
- }
-
- private void initCanSync() {
- canTimeSync = new CanTimeSync(new CanTimeSync.CanTimeListener() {
- @Override
- public void onCanTimeReceived(long vehicleTime) {
- long systemTime = convertCanTimeToSystemTime(vehicleTime);
- long offset = systemTime - System.currentTimeMillis();
- updateTime(TimeSource.CAN, systemTime, offset);
- }
- @Override
- public void onCanError(String error) {
- Log.w(TAG, "CAN sync error: " + error);
- }
- });
- canTimeSync.start();
- }
-
- public void startPeriodicSync() {
- handler.postDelayed(syncRunnable, SYNC_INTERVAL);
- }
-
- public void stopPeriodicSync() {
- handler.removeCallbacks(syncRunnable);
- gpsTimeSync.stopListening();
- canTimeSync.stop();
- }
-
- private Runnable syncRunnable = new Runnable() {
- @Override
- public void run() {
- syncTime();
- handler.postDelayed(this, SYNC_INTERVAL);
- }
- };
-
- private void syncTime() {
- // 根据优先级尝试各种同步方法
- if (isGpsAvailable()) {
- // GPS时间已经通过回调处理
- } else if (isNetworkAvailable()) {
- NtpTimeSync.syncSystemTime(context, ntpCallback);
- } else if (isCanAvailable()) {
- // CAN时间已经通过回调处理
- } else {
- Log.w(TAG, "No time source available");
- }
-
- lastSyncTime = System.currentTimeMillis();
- }
-
- private void updateTime(TimeSource source, long newTime, long offset) {
- // 只接受合理的时间偏移
- if (Math.abs(offset) > 10_000) { // 10秒以上偏移
- Log.w(TAG, "Large time offset detected: " + offset + "ms");
-
- // 渐进式调整
- long adjustedTime = System.currentTimeMillis() + (offset / 2);
- if (hasSetTimePermission()) {
- SystemClock.setCurrentTimeMillis(adjustedTime);
- }
- }
-
- currentSource = source;
-
- // 通知监听器
- for (SyncStatusListener listener : listeners) {
- listener.onSyncStatusChanged(source, newTime, offset);
- }
- }
-
- // 工具方法
- private boolean isGpsAvailable() {
- LocationManager lm = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
- return lm.isProviderEnabled(LocationManager.GPS_PROVIDER);
- }
-
- private boolean isNetworkAvailable() {
- ConnectivityManager cm = (ConnectivityManager)
- context.getSystemService(Context.CONNECTIVITY_SERVICE);
- NetworkInfo netInfo = cm.getActiveNetworkInfo();
- return netInfo != null && netInfo.isConnected();
- }
-
- private boolean isCanAvailable() {
- // 实现检查CAN总线可用性的逻辑
- return true;
- }
-
- private boolean hasSetTimePermission() {
- return context.checkSelfPermission(Manifest.permission.SET_TIME) ==
- PackageManager.PERMISSION_GRANTED;
- }
-
- private long convertCanTimeToSystemTime(long canTime) {
- // 实现CAN时间到系统时间的转换逻辑
- return canTime;
- }
-
- // 监听器管理
- private List<SyncStatusListener> listeners = new ArrayList<>();
-
- public void addSyncStatusListener(SyncStatusListener listener) {
- if (!listeners.contains(listener)) {
- listeners.add(listener);
- }
- }
-
- public void removeSyncStatusListener(SyncStatusListener listener) {
- listeners.remove(listener);
- }
- }
复制代码 使用示例
- TimeSyncManager timeSyncManager = new TimeSyncManager(context);
- timeSyncManager.addSyncStatusListener(new TimeSyncManager.SyncStatusListener() {
- @Override
- public void onSyncStatusChanged(TimeSyncManager.TimeSource source,
- long time, long offset) {
- Log.d(TAG, "Time source: " + source +
- ", offset: " + offset + "ms");
- }
- });
- // 开始周期性同步
- timeSyncManager.startPeriodicSync();
- // 停止同步(在适当的时候调用)
- // timeSyncManager.stopPeriodicSync();
复制代码 六、权限配置
所有时间同步方案都需要在AndroidManifest.xml中添加相应权限:- [/code]对于Android 6.0+,还需要在运行时请求危险权限:
- [code]private static final int PERMISSION_REQUEST_CODE = 100;
- private String[] requiredPermissions = {
- Manifest.permission.ACCESS_FINE_LOCATION,
- Manifest.permission.SET_TIME
- };
- private void checkPermissions() {
- List<String> missingPermissions = new ArrayList<>();
- for (String perm : requiredPermissions) {
- if (ContextCompat.checkSelfPermission(this, perm)
- != PackageManager.PERMISSION_GRANTED) {
- missingPermissions.add(perm);
- }
- }
-
- if (!missingPermissions.isEmpty()) {
- ActivityCompat.requestPermissions(this,
- missingPermissions.toArray(new String[0]),
- PERMISSION_REQUEST_CODE);
- }
- }
- @Override
- public void onRequestPermissionsResult(int requestCode,
- String[] permissions,
- int[] grantResults) {
- if (requestCode == PERMISSION_REQUEST_CODE) {
- for (int i = 0; i < grantResults.length; i++) {
- if (grantResults[i] != PackageManager.PERMISSION_GRANTED) {
- Log.w(TAG, "Permission denied: " + permissions[i]);
- }
- }
- }
- }
复制代码 以上代码提供了Android车载系统各种时间同步方案的完整实现,您可以根据实际需求进行修改和扩展。
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |