找回密码
 立即注册
首页 业界区 业界 Android车载系统时间同步方案具体实现

Android车载系统时间同步方案具体实现

归筠溪 2025-7-17 17:04:23
Android车载系统时间同步方案具体实现

下面我将详细介绍各种时间同步方案的具体实现代码,包括完整的实现逻辑和关键代码片段。
一、NTP时间同步实现

完整实现类
  1. public class NtpTimeSync {
  2.     private static final String TAG = "NtpTimeSync";
  3.     private static final String NTP_SERVER = "pool.ntp.org";
  4.     private static final int TIMEOUT_MS = 10_000;
  5.     public interface TimeSyncCallback {
  6.         void onSuccess(long newTime);
  7.         void onFailure(String error);
  8.     }
  9.     public static void syncSystemTime(Context context, TimeSyncCallback callback) {
  10.         if (!isNetworkAvailable(context)) {
  11.             callback.onFailure("Network not available");
  12.             return;
  13.         }
  14.         new AsyncTask<Void, Void, Long>() {
  15.             @Override
  16.             protected Long doInBackground(Void... voids) {
  17.                 SntpClient client = new SntpClient();
  18.                 try {
  19.                     if (client.requestTime(NTP_SERVER, TIMEOUT_MS)) {
  20.                         long now = client.getNtpTime() + SystemClock.elapsedRealtime() -
  21.                                  client.getNtpTimeReference();
  22.                         return now;
  23.                     }
  24.                 } catch (Exception e) {
  25.                     Log.e(TAG, "NTP sync failed", e);
  26.                 }
  27.                 return null;
  28.             }
  29.             @Override
  30.             protected void onPostExecute(Long result) {
  31.                 if (result != null) {
  32.                     if (hasSetTimePermission(context)) {
  33.                         SystemClock.setCurrentTimeMillis(result);
  34.                         callback.onSuccess(result);
  35.                     } else {
  36.                         callback.onFailure("No SET_TIME permission");
  37.                     }
  38.                 } else {
  39.                     callback.onFailure("NTP sync failed");
  40.                 }
  41.             }
  42.         }.execute();
  43.     }
  44.     private static boolean isNetworkAvailable(Context context) {
  45.         ConnectivityManager cm = (ConnectivityManager)
  46.             context.getSystemService(Context.CONNECTIVITY_SERVICE);
  47.         NetworkInfo netInfo = cm.getActiveNetworkInfo();
  48.         return netInfo != null && netInfo.isConnected();
  49.     }
  50.     private static boolean hasSetTimePermission(Context context) {
  51.         return context.checkSelfPermission(android.Manifest.permission.SET_TIME) ==
  52.                PackageManager.PERMISSION_GRANTED;
  53.     }
  54. }
复制代码
使用示例
  1. NtpTimeSync.syncSystemTime(context, new NtpTimeSync.TimeSyncCallback() {
  2.     @Override
  3.     public void onSuccess(long newTime) {
  4.         Log.d(TAG, "Time synchronized successfully: " + new Date(newTime));
  5.     }
  6.     @Override
  7.     public void onFailure(String error) {
  8.         Log.e(TAG, "Time sync failed: " + error);
  9.     }
  10. });
复制代码
二、GPS时间同步实现

完整实现类
  1. public class GpsTimeSync {
  2.     private static final String TAG = "GpsTimeSync";
  3.     private LocationManager locationManager;
  4.     private GpsTimeListener listener;
  5.     private Context context;
  6.     public interface GpsTimeListener {
  7.         void onGpsTimeReceived(long gpsTime);
  8.         void onGpsStatusChanged(boolean available);
  9.     }
  10.     public GpsTimeSync(Context context, GpsTimeListener listener) {
  11.         this.context = context.getApplicationContext();
  12.         this.listener = listener;
  13.         this.locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
  14.     }
  15.     public void startListening() {
  16.         if (hasLocationPermission()) {
  17.             try {
  18.                 locationManager.requestLocationUpdates(
  19.                     LocationManager.GPS_PROVIDER,
  20.                     0,
  21.                     0,
  22.                     locationListener
  23.                 );
  24.             
  25.                 // 检查GPS状态变化
  26.                 locationManager.addGpsStatusListener(gpsStatusListener);
  27.             } catch (Exception e) {
  28.                 Log.e(TAG, "Failed to request location updates", e);
  29.             }
  30.         } else {
  31.             Log.w(TAG, "Location permission not granted");
  32.         }
  33.     }
  34.     public void stopListening() {
  35.         locationManager.removeUpdates(locationListener);
  36.         locationManager.removeGpsStatusListener(gpsStatusListener);
  37.     }
  38.     private final LocationListener locationListener = new LocationListener() {
  39.         @Override
  40.         public void onLocationChanged(Location location) {
  41.             if (location != null) {
  42.                 long gpsTime = location.getTime();
  43.                 listener.onGpsTimeReceived(gpsTime);
  44.             }
  45.         }
  46.         @Override public void onStatusChanged(String provider, int status, Bundle extras) {}
  47.         @Override public void onProviderEnabled(String provider) {}
  48.         @Override public void onProviderDisabled(String provider) {}
  49.     };
  50.     private final GpsStatus.Listener gpsStatusListener = new GpsStatus.Listener() {
  51.         @Override
  52.         public void onGpsStatusChanged(int event) {
  53.             boolean gpsFixed = false;
  54.             if (event == GpsStatus.GPS_EVENT_SATELLITE_STATUS) {
  55.                 GpsStatus status = locationManager.getGpsStatus(null);
  56.                 Iterable<GpsSatellite> satellites = status.getSatellites();
  57.                 int satellitesCount = 0;
  58.                 for (GpsSatellite satellite : satellites) {
  59.                     if (satellite.usedInFix()) {
  60.                         satellitesCount++;
  61.                     }
  62.                 }
  63.                 gpsFixed = satellitesCount >= 3;
  64.             }
  65.             listener.onGpsStatusChanged(gpsFixed);
  66.         }
  67.     };
  68.     private boolean hasLocationPermission() {
  69.         return ContextCompat.checkSelfPermission(context,
  70.                Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED;
  71.     }
  72. }
复制代码
使用示例
  1. GpsTimeSync gpsTimeSync = new GpsTimeSync(context, new GpsTimeSync.GpsTimeListener() {
  2.     @Override
  3.     public void onGpsTimeReceived(long gpsTime) {
  4.         // 同步系统时间
  5.         if (hasSetTimePermission()) {
  6.             SystemClock.setCurrentTimeMillis(gpsTime);
  7.         }
  8.     }
  9.     @Override
  10.     public void onGpsStatusChanged(boolean available) {
  11.         Log.d(TAG, "GPS availability changed: " + available);
  12.     }
  13. });
  14. // 开始监听
  15. gpsTimeSync.startListening();
  16. // 停止监听(在适当的时候调用)
  17. // gpsTimeSync.stopListening();
复制代码
三、CAN总线时间同步实现

JNI部分实现 (C代码)
  1. #include <jni.h>
  2. #include
  3. #include <canbus/can.h>
  4. #define TAG "CANTimeSync"
  5. // CAN接收回调
  6. void can_receive_callback(can_frame_t *frame) {
  7.     if (frame->can_id == 0x123) { // 假设0x123是时间信息帧ID
  8.         uint64_t vehicle_time = 0;
  9.         memcpy(&vehicle_time, frame->data, sizeof(uint64_t));
  10.    
  11.         // 调用Java层方法
  12.         JNIEnv *env;
  13.         (*g_vm)->AttachCurrentThread(g_vm, &env, NULL);
  14.    
  15.         jclass cls = (*env)->GetObjectClass(env, g_java_obj);
  16.         jmethodID method = (*env)->GetMethodID(env, cls, "onCanTimeReceived", "(J)V");
  17.         (*env)->CallVoidMethod(env, g_java_obj, method, (jlong)vehicle_time);
  18.    
  19.         (*g_vm)->DetachCurrentThread(g_vm);
  20.     }
  21. }
  22. // JNI初始化
  23. JNIEXPORT void JNICALL
  24. Java_com_example_CanTimeSync_initCanBus(JNIEnv *env, jobject instance) {
  25.     // 保存Java对象和VM引用
  26.     g_java_obj = (*env)->NewGlobalRef(env, instance);
  27.     (*env)->GetJavaVM(env, &g_vm);
  28.   
  29.     // 初始化CAN总线
  30.     if (can_init() != 0) {
  31.         __android_log_write(ANDROID_LOG_ERROR, TAG, "CAN init failed");
  32.         return;
  33.     }
  34.   
  35.     // 设置接收回调
  36.     can_set_receive_callback(can_receive_callback);
  37. }
  38. // JNI关闭
  39. JNIEXPORT void JNICALL
  40. Java_com_example_CanTimeSync_closeCanBus(JNIEnv *env, jobject instance) {
  41.     can_close();
  42.     (*env)->DeleteGlobalRef(env, g_java_obj);
  43. }
复制代码
Java层实现
  1. public class CanTimeSync {
  2.     private static final String TAG = "CanTimeSync";
  3.   
  4.     static {
  5.         System.loadLibrary("cantimesync");
  6.     }
  7.   
  8.     public interface CanTimeListener {
  9.         void onCanTimeReceived(long vehicleTime);
  10.         void onCanError(String error);
  11.     }
  12.   
  13.     private CanTimeListener listener;
  14.   
  15.     public CanTimeSync(CanTimeListener listener) {
  16.         this.listener = listener;
  17.     }
  18.   
  19.     public void start() {
  20.         try {
  21.             initCanBus();
  22.         } catch (Exception e) {
  23.             listener.onCanError("CAN init failed: " + e.getMessage());
  24.         }
  25.     }
  26.   
  27.     public void stop() {
  28.         closeCanBus();
  29.     }
  30.   
  31.     // 由JNI调用的方法
  32.     private void onCanTimeReceived(long vehicleTime) {
  33.         listener.onCanTimeReceived(vehicleTime);
  34.     }
  35.   
  36.     // Native方法
  37.     private native void initCanBus();
  38.     private native void closeCanBus();
  39. }
复制代码
使用示例
  1. CanTimeSync canTimeSync = new CanTimeSync(new CanTimeSync.CanTimeListener() {
  2.     @Override
  3.     public void onCanTimeReceived(long vehicleTime) {
  4.         // 转换时间格式并同步
  5.         long systemTime = convertCanTimeToSystemTime(vehicleTime);
  6.         if (hasSetTimePermission()) {
  7.             SystemClock.setCurrentTimeMillis(systemTime);
  8.         }
  9.     }
  10.     @Override
  11.     public void onCanError(String error) {
  12.         Log.e(TAG, "CAN error: " + error);
  13.     }
  14. });
  15. // 启动CAN时间同步
  16. canTimeSync.start();
  17. // 停止同步(在适当的时候调用)
  18. // canTimeSync.stop();
复制代码
四、PTP时间同步实现

PTP客户端实现
  1. public class PtpTimeSync {
  2.     private static final String TAG = "PtpTimeSync";
  3.     private static final String PTP_IFACE = "eth0";
  4.   
  5.     public interface PtpSyncListener {
  6.         void onPtpSyncComplete(long offsetNanos);
  7.         void onPtpSyncError(String error);
  8.     }
  9.   
  10.     public static void syncWithPtp(PtpSyncListener listener) {
  11.         new Thread(() -> {
  12.             try {
  13.                 Process process = Runtime.getRuntime().exec("ptp4l -i " + PTP_IFACE + " -m");
  14.                 BufferedReader reader = new BufferedReader(
  15.                     new InputStreamReader(process.getInputStream()));
  16.             
  17.                 String line;
  18.                 while ((line = reader.readLine()) != null) {
  19.                     if (line.contains("offset")) {
  20.                         // 解析偏移量: master offset -1234 s2 freq
  21.                         String[] parts = line.split("\\s+");
  22.                         if (parts.length >= 4) {
  23.                             long offset = Long.parseLong(parts[3]);
  24.                             listener.onPtpSyncComplete(offset);
  25.                         }
  26.                     }
  27.                 }
  28.             
  29.                 int exitCode = process.waitFor();
  30.                 if (exitCode != 0) {
  31.                     listener.onPtpSyncError("PTP process exited with code " + exitCode);
  32.                 }
  33.             } catch (Exception e) {
  34.                 listener.onPtpSyncError("PTP sync failed: " + e.getMessage());
  35.             }
  36.         }).start();
  37.     }
  38.   
  39.     public static void adjustSystemClock(long offsetNanos) {
  40.         long millis = offsetNanos / 1_000_000;
  41.         if (millis != 0) {
  42.             long current = System.currentTimeMillis();
  43.             SystemClock.setCurrentTimeMillis(current + millis);
  44.         }
  45.     }
  46. }
复制代码
使用示例
  1. PtpTimeSync.syncWithPtp(new PtpTimeSync.PtpSyncListener() {
  2.     @Override
  3.     public void onPtpSyncComplete(long offsetNanos) {
  4.         Log.d(TAG, "PTP offset: " + offsetNanos + " ns");
  5.         if (Math.abs(offsetNanos) > 100_000) { // 如果偏移大于100μs
  6.             PtpTimeSync.adjustSystemClock(offsetNanos);
  7.         }
  8.     }
  9.     @Override
  10.     public void onPtpSyncError(String error) {
  11.         Log.e(TAG, "PTP error: " + error);
  12.     }
  13. });
复制代码
五、混合时间同步策略实现

综合时间同步管理器
  1. public class TimeSyncManager {
  2.     private static final String TAG = "TimeSyncManager";
  3.     private static final long SYNC_INTERVAL = 60_000; // 1分钟
  4.   
  5.     private Context context;
  6.     private Handler handler;
  7.     private NtpTimeSync.TimeSyncCallback ntpCallback;
  8.     private GpsTimeSync gpsTimeSync;
  9.     private CanTimeSync canTimeSync;
  10.   
  11.     private long lastSyncTime;
  12.     private TimeSource currentSource = TimeSource.LOCAL;
  13.   
  14.     public enum TimeSource {
  15.         GPS, NTP, CAN, PTP, LOCAL
  16.     }
  17.   
  18.     public interface SyncStatusListener {
  19.         void onSyncStatusChanged(TimeSource source, long time, long offset);
  20.     }
  21.   
  22.     public TimeSyncManager(Context context) {
  23.         this.context = context.getApplicationContext();
  24.         this.handler = new Handler(Looper.getMainLooper());
  25.    
  26.         initCallbacks();
  27.         initGpsSync();
  28.         initCanSync();
  29.     }
  30.   
  31.     private void initCallbacks() {
  32.         ntpCallback = new NtpTimeSync.TimeSyncCallback() {
  33.             @Override
  34.             public void onSuccess(long newTime) {
  35.                 long offset = newTime - System.currentTimeMillis();
  36.                 updateTime(TimeSource.NTP, newTime, offset);
  37.             }
  38.             @Override
  39.             public void onFailure(String error) {
  40.                 Log.w(TAG, "NTP sync failed: " + error);
  41.             }
  42.         };
  43.     }
  44.   
  45.     private void initGpsSync() {
  46.         gpsTimeSync = new GpsTimeSync(context, new GpsTimeSync.GpsTimeListener() {
  47.             @Override
  48.             public void onGpsTimeReceived(long gpsTime) {
  49.                 long offset = gpsTime - System.currentTimeMillis();
  50.                 updateTime(TimeSource.GPS, gpsTime, offset);
  51.             }
  52.             @Override
  53.             public void onGpsStatusChanged(boolean available) {
  54.                 if (available) {
  55.                     Log.d(TAG, "GPS available, preferring GPS time");
  56.                 }
  57.             }
  58.         });
  59.         gpsTimeSync.startListening();
  60.     }
  61.   
  62.     private void initCanSync() {
  63.         canTimeSync = new CanTimeSync(new CanTimeSync.CanTimeListener() {
  64.             @Override
  65.             public void onCanTimeReceived(long vehicleTime) {
  66.                 long systemTime = convertCanTimeToSystemTime(vehicleTime);
  67.                 long offset = systemTime - System.currentTimeMillis();
  68.                 updateTime(TimeSource.CAN, systemTime, offset);
  69.             }
  70.             @Override
  71.             public void onCanError(String error) {
  72.                 Log.w(TAG, "CAN sync error: " + error);
  73.             }
  74.         });
  75.         canTimeSync.start();
  76.     }
  77.   
  78.     public void startPeriodicSync() {
  79.         handler.postDelayed(syncRunnable, SYNC_INTERVAL);
  80.     }
  81.   
  82.     public void stopPeriodicSync() {
  83.         handler.removeCallbacks(syncRunnable);
  84.         gpsTimeSync.stopListening();
  85.         canTimeSync.stop();
  86.     }
  87.   
  88.     private Runnable syncRunnable = new Runnable() {
  89.         @Override
  90.         public void run() {
  91.             syncTime();
  92.             handler.postDelayed(this, SYNC_INTERVAL);
  93.         }
  94.     };
  95.   
  96.     private void syncTime() {
  97.         // 根据优先级尝试各种同步方法
  98.         if (isGpsAvailable()) {
  99.             // GPS时间已经通过回调处理
  100.         } else if (isNetworkAvailable()) {
  101.             NtpTimeSync.syncSystemTime(context, ntpCallback);
  102.         } else if (isCanAvailable()) {
  103.             // CAN时间已经通过回调处理
  104.         } else {
  105.             Log.w(TAG, "No time source available");
  106.         }
  107.    
  108.         lastSyncTime = System.currentTimeMillis();
  109.     }
  110.   
  111.     private void updateTime(TimeSource source, long newTime, long offset) {
  112.         // 只接受合理的时间偏移
  113.         if (Math.abs(offset) > 10_000) { // 10秒以上偏移
  114.             Log.w(TAG, "Large time offset detected: " + offset + "ms");
  115.         
  116.             // 渐进式调整
  117.             long adjustedTime = System.currentTimeMillis() + (offset / 2);
  118.             if (hasSetTimePermission()) {
  119.                 SystemClock.setCurrentTimeMillis(adjustedTime);
  120.             }
  121.         }
  122.    
  123.         currentSource = source;
  124.    
  125.         // 通知监听器
  126.         for (SyncStatusListener listener : listeners) {
  127.             listener.onSyncStatusChanged(source, newTime, offset);
  128.         }
  129.     }
  130.   
  131.     // 工具方法
  132.     private boolean isGpsAvailable() {
  133.         LocationManager lm = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
  134.         return lm.isProviderEnabled(LocationManager.GPS_PROVIDER);
  135.     }
  136.   
  137.     private boolean isNetworkAvailable() {
  138.         ConnectivityManager cm = (ConnectivityManager)
  139.             context.getSystemService(Context.CONNECTIVITY_SERVICE);
  140.         NetworkInfo netInfo = cm.getActiveNetworkInfo();
  141.         return netInfo != null && netInfo.isConnected();
  142.     }
  143.   
  144.     private boolean isCanAvailable() {
  145.         // 实现检查CAN总线可用性的逻辑
  146.         return true;
  147.     }
  148.   
  149.     private boolean hasSetTimePermission() {
  150.         return context.checkSelfPermission(Manifest.permission.SET_TIME) ==
  151.                PackageManager.PERMISSION_GRANTED;
  152.     }
  153.   
  154.     private long convertCanTimeToSystemTime(long canTime) {
  155.         // 实现CAN时间到系统时间的转换逻辑
  156.         return canTime;
  157.     }
  158.   
  159.     // 监听器管理
  160.     private List<SyncStatusListener> listeners = new ArrayList<>();
  161.   
  162.     public void addSyncStatusListener(SyncStatusListener listener) {
  163.         if (!listeners.contains(listener)) {
  164.             listeners.add(listener);
  165.         }
  166.     }
  167.   
  168.     public void removeSyncStatusListener(SyncStatusListener listener) {
  169.         listeners.remove(listener);
  170.     }
  171. }
复制代码
使用示例
  1. TimeSyncManager timeSyncManager = new TimeSyncManager(context);
  2. timeSyncManager.addSyncStatusListener(new TimeSyncManager.SyncStatusListener() {
  3.     @Override
  4.     public void onSyncStatusChanged(TimeSyncManager.TimeSource source,
  5.                                   long time, long offset) {
  6.         Log.d(TAG, "Time source: " + source +
  7.               ", offset: " + offset + "ms");
  8.     }
  9. });
  10. // 开始周期性同步
  11. timeSyncManager.startPeriodicSync();
  12. // 停止同步(在适当的时候调用)
  13. // timeSyncManager.stopPeriodicSync();
复制代码
六、权限配置

所有时间同步方案都需要在AndroidManifest.xml中添加相应权限:
  1. [/code]对于Android 6.0+,还需要在运行时请求危险权限:
  2. [code]private static final int PERMISSION_REQUEST_CODE = 100;
  3. private String[] requiredPermissions = {
  4.     Manifest.permission.ACCESS_FINE_LOCATION,
  5.     Manifest.permission.SET_TIME
  6. };
  7. private void checkPermissions() {
  8.     List<String> missingPermissions = new ArrayList<>();
  9.     for (String perm : requiredPermissions) {
  10.         if (ContextCompat.checkSelfPermission(this, perm)
  11.             != PackageManager.PERMISSION_GRANTED) {
  12.             missingPermissions.add(perm);
  13.         }
  14.     }
  15.   
  16.     if (!missingPermissions.isEmpty()) {
  17.         ActivityCompat.requestPermissions(this,
  18.             missingPermissions.toArray(new String[0]),
  19.             PERMISSION_REQUEST_CODE);
  20.     }
  21. }
  22. @Override
  23. public void onRequestPermissionsResult(int requestCode,
  24.                                      String[] permissions,
  25.                                      int[] grantResults) {
  26.     if (requestCode == PERMISSION_REQUEST_CODE) {
  27.         for (int i = 0; i < grantResults.length; i++) {
  28.             if (grantResults[i] != PackageManager.PERMISSION_GRANTED) {
  29.                 Log.w(TAG, "Permission denied: " + permissions[i]);
  30.             }
  31.         }
  32.     }
  33. }
复制代码
以上代码提供了Android车载系统各种时间同步方案的完整实现,您可以根据实际需求进行修改和扩展。

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
您需要登录后才可以回帖 登录 | 立即注册