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

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 <android/log.h>
#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中添加相应权限:

<uses-permission android:name="android.permission.SET_TIME" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.INTERNET" />

对于Android 6.0+,还需要在运行时请求危险权限:

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车载系统各种时间同步方案的完整实现,您可以根据实际需求进行修改和扩展。

作者:一翼诚原文地址:https://www.cnblogs.com/hejing-michael/p/18990136/the-specific-implementation-of-android-vehicle-system-time-synchronization-solution-dib72

%s 个评论

要回复文章请先登录注册