android 设置系统时间的流程

简介: android 设置系统时间的方法

代码摘抄至系统源码
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;
}
目录
相关文章
|
2月前
|
XML API Android开发
码农之重学安卓:利用androidx.preference 快速创建一、二级设置菜单(demo)
本文介绍了如何使用androidx.preference库快速创建具有一级和二级菜单的Android设置界面的步骤和示例代码。
60 1
码农之重学安卓:利用androidx.preference 快速创建一、二级设置菜单(demo)
|
4天前
|
XML 前端开发 Android开发
Android View的绘制流程和原理详细解说
Android View的绘制流程和原理详细解说
14 3
|
21天前
|
消息中间件 Android开发 索引
Android面试高频知识点(4) 详解Activity的启动流程
讲解Activity的启动流程了,Activity的启动流程相对复杂一下,涉及到了Activity中的生命周期方法,涉及到了Android体系的CS模式,涉及到了Android中进程通讯Binder机制等等, 首先介绍一下Activity,这里引用一下Android guide中对Activity的介绍:
33 4
|
1月前
|
Android开发
Android经典实战之Textview文字设置不同颜色、下划线、加粗、超链接等效果
本文介绍了 `SpannableString` 在 Android 开发中的强大功能,包括如何在单个字符串中应用多种样式,如颜色、字体大小、风格等,并提供了详细代码示例,展示如何设置文本颜色、添加点击事件等,助你实现丰富文本效果。
121 3
|
21天前
|
Android开发 开发者
Android面试之Activity启动流程简述
每个Android开发者都熟悉的Activity,但你是否了解它的启动流程呢?本文将带你深入了解。启动流程涉及四个关键角色:Launcher进程、SystemServer的AMS、应用程序的ActivityThread及Zygote进程。核心在于AMS与ActivityThread间的通信。文章详细解析了从Launcher启动Activity的过程,包括通过AIDL获取AMS、Zygote进程启动以及ActivityThread与AMS的通信机制。接着介绍了如何创建Application及Activity的具体步骤。整体流程清晰明了,帮助你更深入理解Activity的工作原理。
25 0
|
2月前
|
Android开发
我的Android进阶修炼:安卓启动流程之init(1)
本文深入分析了Android系统中的init进程,包括其源码结构、主要功能以及启动流程的详细注解,旨在帮助读者理解init作为用户空间的1号进程在Android启动过程中的关键作用。
37 1
|
2月前
|
Java 网络安全 开发工具
UNITY与安卓⭐一、Android Studio初始设置
UNITY与安卓⭐一、Android Studio初始设置
|
1月前
|
图形学 iOS开发 Android开发
从Unity开发到移动平台制胜攻略:全面解析iOS与Android应用发布流程,助你轻松掌握跨平台发布技巧,打造爆款手游不是梦——性能优化、广告集成与内购设置全包含
【8月更文挑战第31天】本书详细介绍了如何在Unity中设置项目以适应移动设备,涵盖性能优化、集成广告及内购功能等关键步骤。通过具体示例和代码片段,指导读者完成iOS和Android应用的打包与发布,确保应用顺利上线并获得成功。无论是性能调整还是平台特定的操作,本书均提供了全面的解决方案。
120 0
|
3月前
|
XML Android开发 数据格式
Android 中如何设置activity的启动动画,让它像dialog一样从底部往上出来
在 Android 中实现 Activity 的对话框式过渡动画:从底部滑入与从顶部滑出。需定义两个 XML 动画文件 `activity_slide_in.xml` 和 `activity_slide_out.xml`,分别控制 Activity 的进入与退出动画。使用 `overridePendingTransition` 方法在启动 (`startActivity`) 或结束 (`finish`) Activity 时应用这些动画。为了使前 Activity 保持静止,可定义 `no_animation.xml` 并在启动新 Activity 时仅设置新 Activity 的进入动画。
66 12
|
2月前
|
XML 前端开发 Android开发
Android面试高频知识点(3) 详解Android View的绘制流程
View的绘制和事件处理是两个重要的主题,上一篇《图解 Android事件分发机制》已经把事件的分发机制讲得比较详细了,这一篇是针对View的绘制,View的绘制如果你有所了解,基本分为measure、layout、draw 过程,其中比较难理解就是measure过程,所以本篇文章大幅笔地分析measure过程,相对讲得比较详细,文章也比较长,如果你对View的绘制还不是很懂,对measure过程掌握得不是很深刻,那么耐心点,看完这篇文章,相信你会有所收获的。
95 2