代码摘抄至系统源码
frameworks\base\core\java\android\app\timedetector\TimeDetector.java
if (when / 1000 < Integer.MAX_VALUE) {
TimeDetector timeDetector = mContext.getSystemService(TimeDetector.class);
ManualTimeSuggestion manualTimeSuggestion =
TimeDetector.createManualTimeSuggestion(when, "Settings: Set time");
timeDetector.suggestManualTime(manualTimeSuggestion);
}
/**
* A shared utility method to create a {@link ManualTimeSuggestion}.
*
* @hide
*/
static ManualTimeSuggestion createManualTimeSuggestion(long when, String why) {
TimestampedValue<Long> utcTime =
new TimestampedValue<>(SystemClock.elapsedRealtime(), when);
ManualTimeSuggestion manualTimeSuggestion = new ManualTimeSuggestion(utcTime);
manualTimeSuggestion.addDebugInfo(why);
return manualTimeSuggestion;
}
@RequiresPermission(android.Manifest.permission.SUGGEST_MANUAL_TIME_AND_ZONE)
boolean suggestManualTime(@NonNull ManualTimeSuggestion timeSuggestion);
frameworks\base\core\java\android\app\timedetector\TimeDetectorImpl.java
@Override
public boolean suggestManualTime(@NonNull ManualTimeSuggestion timeSuggestion) {
if (DEBUG) {
Log.d(TAG, "suggestManualTime called: " + timeSuggestion);
}
try {
return mITimeDetectorService.suggestManualTime(timeSuggestion);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
通过aidl调用mITimeDetectorService的suggestManualTime方法
frameworks\base\services\core\java\com\android\server\timedetector\TimeDetectorService.java
@Override
public boolean suggestManualTime(@NonNull ManualTimeSuggestion timeSignal) {
enforceSuggestManualTimePermission();
Objects.requireNonNull(timeSignal);
final long token = Binder.clearCallingIdentity();
try {
return mTimeDetectorStrategy.suggestManualTime(timeSignal);
} finally {
Binder.restoreCallingIdentity(token);
}
}
@Override
public synchronized boolean suggestManualTime(@NonNull ManualTimeSuggestion suggestion) {
final TimestampedValue<Long> newUnixEpochTime = suggestion.getUnixEpochTime();
if (!validateSuggestionTime(newUnixEpochTime, suggestion)) {
return false;
}
String cause = "Manual time suggestion received: suggestion=" + suggestion;
return setSystemClockIfRequired(ORIGIN_MANUAL, newUnixEpochTime, cause);
}
@GuardedBy("this")
private boolean setSystemClockIfRequired(
@Origin int origin, @NonNull TimestampedValue<Long> time, @NonNull String cause) {
boolean isOriginAutomatic = isOriginAutomatic(origin);
if (isOriginAutomatic) {
if (!mEnvironment.isAutoTimeDetectionEnabled()) {
if (DBG) {
Slog.d(LOG_TAG, "Auto time detection is not enabled."
+ " origin=" + originToString(origin)
+ ", time=" + time
+ ", cause=" + cause);
}
return false;
}
} else {
if (mEnvironment.isAutoTimeDetectionEnabled()) {
if (DBG) {
Slog.d(LOG_TAG, "Auto time detection is enabled."
+ " origin=" + originToString(origin)
+ ", time=" + time
+ ", cause=" + cause);
}
return false;
}
}
mEnvironment.acquireWakeLock();
try {
return setSystemClockUnderWakeLock(origin, time, cause);
} finally {
mEnvironment.releaseWakeLock();
}
}
private static boolean isOriginAutomatic(@Origin int origin) {
return origin != ORIGIN_MANUAL;
}
@GuardedBy("this")
private boolean setSystemClockUnderWakeLock(
@Origin int origin, @NonNull TimestampedValue<Long> newTime, @NonNull String cause) {
long elapsedRealtimeMillis = mEnvironment.elapsedRealtimeMillis();
boolean isOriginAutomatic = isOriginAutomatic(origin);
long actualSystemClockMillis = mEnvironment.systemClockMillis();
if (isOriginAutomatic) {
// CLOCK_PARANOIA : Check to see if this class owns the clock or if something else
// may be setting the clock.
if (mLastAutoSystemClockTimeSet != null) {
long expectedTimeMillis = TimeDetectorStrategy.getTimeAt(
mLastAutoSystemClockTimeSet, elapsedRealtimeMillis);
long absSystemClockDifference =
Math.abs(expectedTimeMillis - actualSystemClockMillis);
if (absSystemClockDifference > SYSTEM_CLOCK_PARANOIA_THRESHOLD_MILLIS) {
Slog.w(LOG_TAG,
"System clock has not tracked elapsed real time clock. A clock may"
+ " be inaccurate or something unexpectedly set the system"
+ " clock."
+ " elapsedRealtimeMillis=" + elapsedRealtimeMillis
+ " expectedTimeMillis=" + expectedTimeMillis
+ " actualTimeMillis=" + actualSystemClockMillis
+ " cause=" + cause);
}
}
}
// Adjust for the time that has elapsed since the signal was received.
long newSystemClockMillis = TimeDetectorStrategy.getTimeAt(newTime, elapsedRealtimeMillis);
// Check if the new signal would make sufficient difference to the system clock. If it's
// below the threshold then ignore it.
long absTimeDifference = Math.abs(newSystemClockMillis - actualSystemClockMillis);
long systemClockUpdateThreshold = mEnvironment.systemClockUpdateThresholdMillis();
if (absTimeDifference < systemClockUpdateThreshold) {
if (DBG) {
Slog.d(LOG_TAG, "Not setting system clock. New time and"
+ " system clock are close enough."
+ " elapsedRealtimeMillis=" + elapsedRealtimeMillis
+ " newTime=" + newTime
+ " cause=" + cause
+ " systemClockUpdateThreshold=" + systemClockUpdateThreshold
+ " absTimeDifference=" + absTimeDifference);
}
return true;
}
mEnvironment.setSystemClock(newSystemClockMillis);
String logMsg = "Set system clock using time=" + newTime
+ " cause=" + cause
+ " elapsedRealtimeMillis=" + elapsedRealtimeMillis
+ " (old) actualSystemClockMillis=" + actualSystemClockMillis
+ " newSystemClockMillis=" + newSystemClockMillis;
if (DBG) {
Slog.d(LOG_TAG, logMsg);
}
mTimeChangesLog.log(logMsg);
// CLOCK_PARANOIA : Record the last time this class set the system clock due to an auto-time
// signal, or clear the record it is being done manually.
if (isOriginAutomatic(origin)) {
mLastAutoSystemClockTimeSet = newTime;
} else {
mLastAutoSystemClockTimeSet = null;
}
return true;
}
mEnvironment.setSystemClock(newSystemClockMillis);
frameworks\base\services\core\java\com\android\server\timedetector\EnvironmentImpl.java
@Override
public void setSystemClock(long newTimeMillis) {
checkWakeLockHeld();
mAlarmManager.setTime(newTimeMillis);
}
@RequiresPermission(android.Manifest.permission.SET_TIME)
public void setTime(long millis) {
try {
mService.setTime(millis);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
}
IAlarmManager 通过aidl通信
frameworks\base\apex\jobscheduler\service\java\com\android\server\alarm\AlarmManagerService.java
@Override
public boolean setTime(long millis) {
getContext().enforceCallingOrSelfPermission(
"android.permission.SET_TIME",
"setTime");
return setTimeImpl(millis);
}
boolean setTimeImpl(long millis) {
if (!mInjector.isAlarmDriverPresent()) {
Slog.w(TAG, "Not setting time since no alarm driver is available.");
return false;
}
synchronized (mLock) {
final long currentTimeMillis = mInjector.getCurrentTimeMillis();
mInjector.setKernelTime(millis);
final TimeZone timeZone = TimeZone.getDefault();
final int currentTzOffset = timeZone.getOffset(currentTimeMillis);
final int newTzOffset = timeZone.getOffset(millis);
if (currentTzOffset != newTzOffset) {
Slog.i(TAG, "Timezone offset has changed, updating kernel timezone");
mInjector.setKernelTimezone(-(newTzOffset / 60000));
}
// The native implementation of setKernelTime can return -1 even when the kernel
// time was set correctly, so assume setting kernel time was successful and always
// return true.
return true;
}
}
Injector为内部类
void setKernelTime(long millis) {
if (mNativeData != 0) {
AlarmManagerService.setKernelTime(mNativeData, millis);
}
}
private static native int setKernelTime(long nativeData, long millis);
转到native层
framework/base/apex/jobscheduler/service/jni/com_android_server_alarm_AlarmManagerService.cpp
static jint android_server_alarm_AlarmManagerService_setKernelTime(JNIEnv*, jobject, jlong nativeData, jlong millis)
{
AlarmImpl *impl = reinterpret_cast<AlarmImpl *>(nativeData);
if (millis <= 0 || millis / 1000LL >= std::numeric_limits<time_t>::max()) {
return -1;
}
struct timeval tv;
tv.tv_sec = (millis / 1000LL);
tv.tv_usec = ((millis % 1000LL) * 1000LL);
ALOGD("Setting time of day to sec=%ld", tv.tv_sec);
int ret = impl->setTime(&tv);
if (ret < 0) {
ALOGW("Unable to set rtc to %ld: %s", tv.tv_sec, strerror(errno));
ret = -1;
}
return ret;
}
int AlarmImpl::setTime(struct timeval *tv)
{
if (settimeofday(tv, NULL) == -1) {
ALOGV("settimeofday() failed: %s", strerror(errno));
return -1;
}
android::base::unique_fd fd{open(rtc_dev.c_str(), O_RDWR)};
if (!fd.ok()) {
ALOGE("Unable to open %s: %s", rtc_dev.c_str(), strerror(errno));
return -1;
}
struct tm tm;
if (!gmtime_r(&tv->tv_sec, &tm)) {
ALOGV("gmtime_r() failed: %s", strerror(errno));
return -1;
}
struct rtc_time rtc = {};
rtc.tm_sec = tm.tm_sec;
rtc.tm_min = tm.tm_min;
rtc.tm_hour = tm.tm_hour;
rtc.tm_mday = tm.tm_mday;
rtc.tm_mon = tm.tm_mon;
rtc.tm_year = tm.tm_year;
rtc.tm_wday = tm.tm_wday;
rtc.tm_yday = tm.tm_yday;
rtc.tm_isdst = tm.tm_isdst;
if (ioctl(fd, RTC_SET_TIME, &rtc) == -1) {
ALOGV("RTC_SET_TIME ioctl failed: %s", strerror(errno));
return -1;
}
return 0;
}