根据字符自动确定时区查找到Setting中对应的字符
packages/apps/Settings/res/values-zh-rCN/strings.xml: <string name="zone_auto" msgid="334783869352026648">"自动确定时区"</string>而后可以知道其对应的文件是:packages/apps/Settings/res/xml/date_time_prefs.xml,代码片段是:
<PreferenceCategory android:key="time_zone_preference_category" android:layout="@layout/preference_category_no_label"> <com.android.settingslib.RestrictedSwitchPreference android:key="auto_zone" android:title="@string/zone_auto" android:summaryOn="@string/zone_auto_summaryOn" android:summaryOff="@string/zone_auto_summaryOff" settings:userRestriction="no_config_date_time" /> <com.android.settingslib.RestrictedPreference android:fragment="com.android.settings.datetime.ZonePicker" android:key="timezone" android:title="@string/date_time_set_timezone" android:summary="@string/summary_placeholder" settings:userRestriction="no_config_date_time" /> </PreferenceCategory>根据以上的Key值auto_zone,可以知道所在的文件为: packages/apps/Settings/src/com/android/settings/datetime/AutoTimeZonePreferenceController.java 获取到关键的控制参数是:Settings.Global.AUTO_TIME_ZONE
@Override public boolean onPreferenceChange(Preference preference, Object newValue) { boolean autoZoneEnabled = (Boolean) newValue; Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.AUTO_TIME_ZONE, autoZoneEnabled ? 1 : 0); mCallback.updateTimeAndDateDisplay(mContext); return true; }在Service中有对Settings.Global.AUTO_TIME_ZONE的设置的反应,查找可以找到对应的Service是 frameworks/base/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@Override public boolean setTimeZone(ComponentName who, String timeZone) { Preconditions.checkNotNull(who, "ComponentName is null in setTimeZone"); getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER); // Don't allow set timezone when auto timezone is on. if (mInjector.settingsGlobalGetInt(Global.AUTO_TIME_ZONE, 0) == 1) { return false; } mInjector.binderWithCleanCallingIdentity(() -> mInjector.getAlarmManager().setTimeZone(timeZone)); return true; }对Settings.Global.AUTO_TIME_ZONE参数变化的监听是:frameworks/opt/telephony/src/java/com/android/internal/telephony/TimeServiceHelper.java
public interface Listener { /** * Automatic time detection has been enabled or disabled. */ void onTimeDetectionChange(boolean enabled); /** * Automatic time zone detection has been enabled or disabled. */ void onTimeZoneDetectionChange(boolean enabled); } /** * Sets a listener that will be called when the automatic time / time zone detection setting * changes. */ public void setListener(Listener listener) { if (listener == null) { throw new NullPointerException("listener==null"); } if (mListener != null) { throw new IllegalStateException("listener already set"); } this.mListener = listener; mCr.registerContentObserver( Settings.Global.getUriFor(Settings.Global.AUTO_TIME), true, new ContentObserver(new Handler()) { public void onChange(boolean selfChange) { listener.onTimeDetectionChange(isTimeDetectionEnabled()); } }); mCr.registerContentObserver( Settings.Global.getUriFor(Settings.Global.AUTO_TIME_ZONE), true, new ContentObserver(new Handler()) { public void onChange(boolean selfChange) { listener.onTimeZoneDetectionChange(isTimeZoneDetectionEnabled()); } }); }当时区开关改变时候,会有监听函数:onTimeZoneDetectionChange响应; 继续跟踪可以找到实现该代码的位置: frameworks/opt/telephony/src/java/com/android/internal/telephony/NitzStateMachine.java
mTimeServiceHelper.setListener(new TimeServiceHelper.Listener() { @Override public void onTimeDetectionChange(boolean enabled) { if (enabled) { handleAutoTimeEnabled(); } } @Override public void onTimeZoneDetectionChange(boolean enabled) { if (enabled) { handleAutoTimeZoneEnabled(); } } }); private void handleAutoTimeZoneEnabled() { String tmpLog = "handleAutoTimeZoneEnabled: Reverting to NITZ TimeZone:" + " mSavedTimeZoneId=" + mSavedTimeZoneId; if (DBG) { Rlog.d(LOG_TAG, tmpLog); } mTimeZoneLog.log(tmpLog); if (mSavedTimeZoneId != null) { setAndBroadcastNetworkSetTimeZone(mSavedTimeZoneId); } else { String iso = mDeviceState.getNetworkCountryIsoForPhone(); if (!TextUtils.isEmpty(iso)) { updateTimeZoneByNetworkCountryCode(iso); } } }接收到网络更新的时区更新:
/** * Handle a new NITZ signal being received. */ public void handleNitzReceived(TimeStampedValue<NitzData> nitzSignal) { handleTimeZoneFromNitz(nitzSignal); handleTimeFromNitz(nitzSignal); } private void handleTimeZoneFromNitz(TimeStampedValue<NitzData> nitzSignal) { try { NitzData newNitzData = nitzSignal.mValue; String iso = mDeviceState.getNetworkCountryIsoForPhone(); String zoneId; if (newNitzData.getEmulatorHostTimeZone() != null) { zoneId = newNitzData.getEmulatorHostTimeZone().getID(); } else { if (!mGotCountryCode) { zoneId = null; } else if (!TextUtils.isEmpty(iso)) { OffsetResult lookupResult = mTimeZoneLookupHelper.lookupByNitzCountry(newNitzData, iso); zoneId = lookupResult != null ? lookupResult.zoneId : null; } else { // We don't have a valid iso country code. This is // most likely because we're on a test network that's // using a bogus MCC (eg, "001"), so get a TimeZone // based only on the NITZ parameters. OffsetResult lookupResult = mTimeZoneLookupHelper.lookupByNitz(newNitzData); if (DBG) { Rlog.d(LOG_TAG, "handleTimeZoneFromNitz: guessZoneIdByNitz returned" + " lookupResult=" + lookupResult); } zoneId = lookupResult != null ? lookupResult.zoneId : null; } } if ((zoneId == null) || mLatestNitzSignal == null || offsetInfoDiffers(newNitzData, mLatestNitzSignal.mValue)) { // We got the time before the country, or the zone has changed // so we don't know how to identify the DST rules yet. Save // the information and hope to fix it up later. mNeedCountryCodeForNitz = true; mLatestNitzSignal = nitzSignal; } String tmpLog = "handleTimeZoneFromNitz: nitzSignal=" + nitzSignal + " zoneId=" + zoneId + " iso=" + iso + " mGotCountryCode=" + mGotCountryCode + " mNeedCountryCodeForNitz=" + mNeedCountryCodeForNitz + " isTimeZoneDetectionEnabled()=" + mTimeServiceHelper.isTimeZoneDetectionEnabled(); if (DBG) { Rlog.d(LOG_TAG, tmpLog); } mTimeZoneLog.log(tmpLog); if (zoneId != null) { if (mTimeServiceHelper.isTimeZoneDetectionEnabled()) { setAndBroadcastNetworkSetTimeZone(zoneId); } mNitzTimeZoneDetectionSuccessful = true; mSavedTimeZoneId = zoneId; } } catch (RuntimeException ex) { Rlog.e(LOG_TAG, "handleTimeZoneFromNitz: Processing NITZ data" + " nitzSignal=" + nitzSignal + " ex=" + ex); } } private static boolean offsetInfoDiffers(NitzData one, NitzData two) { return one.getLocalOffsetMillis() != two.getLocalOffsetMillis() || one.isDst() != two.isDst(); } private void handleTimeFromNitz(TimeStampedValue<NitzData> nitzSignal) { try { boolean ignoreNitz = mDeviceState.getIgnoreNitz(); if (ignoreNitz) { Rlog.d(LOG_TAG, "handleTimeFromNitz: Not setting clock because gsm.ignore-nitz is set"); return; } try { // Acquire the wake lock as we are reading the elapsed realtime clock and system // clock. mWakeLock.acquire(); // Validate the nitzTimeSignal to reject obviously bogus elapsedRealtime values. long elapsedRealtime = mTimeServiceHelper.elapsedRealtime(); long millisSinceNitzReceived = elapsedRealtime - nitzSignal.mElapsedRealtime; if (millisSinceNitzReceived < 0 || millisSinceNitzReceived > Integer.MAX_VALUE) { if (DBG) { Rlog.d(LOG_TAG, "handleTimeFromNitz: not setting time, unexpected" + " elapsedRealtime=" + elapsedRealtime + " nitzSignal=" + nitzSignal); } return; } // Adjust the NITZ time by the delay since it was received to get the time now. long adjustedCurrentTimeMillis = nitzSignal.mValue.getCurrentTimeInMillis() + millisSinceNitzReceived; long gained = adjustedCurrentTimeMillis - mTimeServiceHelper.currentTimeMillis(); if (mTimeServiceHelper.isTimeDetectionEnabled()) { String logMsg = "handleTimeFromNitz:" + " nitzSignal=" + nitzSignal + " adjustedCurrentTimeMillis=" + adjustedCurrentTimeMillis + " millisSinceNitzReceived= " + millisSinceNitzReceived + " gained=" + gained; if (mSavedNitzTime == null) { logMsg += ": First update received."; setAndBroadcastNetworkSetTime(logMsg, adjustedCurrentTimeMillis); } else { long elapsedRealtimeSinceLastSaved = mTimeServiceHelper.elapsedRealtime() - mSavedNitzTime.mElapsedRealtime; int nitzUpdateSpacing = mDeviceState.getNitzUpdateSpacingMillis(); int nitzUpdateDiff = mDeviceState.getNitzUpdateDiffMillis(); if (elapsedRealtimeSinceLastSaved > nitzUpdateSpacing || Math.abs(gained) > nitzUpdateDiff) { // Either it has been a while since we received an update, or the gain // is sufficiently large that we want to act on it. logMsg += ": New update received."; setAndBroadcastNetworkSetTime(logMsg, adjustedCurrentTimeMillis); } else { if (DBG) { Rlog.d(LOG_TAG, logMsg + ": Update throttled."); } // Return early. This means that we don't reset the // mSavedNitzTime for next time and that we may act on more // NITZ time signals overall but should end up with a system clock that // tracks NITZ more closely than if we saved throttled values (which // would reset mSavedNitzTime.elapsedRealtime used to calculate time // since the last NITZ signal was received). return; } } } // Save the last NITZ time signal used so we can return to it later // if auto-time detection is toggled. mSavedNitzTime = new TimeStampedValue<>( adjustedCurrentTimeMillis, nitzSignal.mElapsedRealtime); } finally { mWakeLock.release(); } } catch (RuntimeException ex) { Rlog.e(LOG_TAG, "handleTimeFromNitz: Processing NITZ data" + " nitzSignal=" + nitzSignal + " ex=" + ex); } } private void setAndBroadcastNetworkSetTimeZone(String zoneId) { if (DBG) { Rlog.d(LOG_TAG, "setAndBroadcastNetworkSetTimeZone: zoneId=" + zoneId); } mTimeServiceHelper.setDeviceTimeZone(zoneId); if (DBG) { Rlog.d(LOG_TAG, "setAndBroadcastNetworkSetTimeZone: called setDeviceTimeZone()" + " zoneId=" + zoneId); } } private void setAndBroadcastNetworkSetTime(String msg, long time) { if (!mWakeLock.isHeld()) { Rlog.w(LOG_TAG, "setAndBroadcastNetworkSetTime: Wake lock not held while setting device" + " time (msg=" + msg + ")"); } msg = "setAndBroadcastNetworkSetTime: [Setting time to time=" + time + "]:" + msg; if (DBG) { Rlog.d(LOG_TAG, msg); } mTimeLog.log(msg); mTimeServiceHelper.setDeviceTime(time); TelephonyMetrics.getInstance().writeNITZEvent(mPhone.getPhoneId(), time); }frameworks/opt/telephony/src/java/com/android/internal/telephony/ServiceStateTracker.java找到mNitzState.handleNitzReceived(nitzSignal)函数的调用:
/** * nitzReceiveTime is time_t that the NITZ time was posted */ private void setTimeFromNITZString(String nitzString, long nitzReceiveTime) { long start = SystemClock.elapsedRealtime(); if (DBG) { Rlog.d(LOG_TAG, "NITZ: " + nitzString + "," + nitzReceiveTime + " start=" + start + " delay=" + (start - nitzReceiveTime)); } NitzData newNitzData = NitzData.parse(nitzString); if (newNitzData != null) { try { TimeStampedValue<NitzData> nitzSignal = new TimeStampedValue<>(newNitzData, nitzReceiveTime); mNitzState.handleNitzReceived(nitzSignal); } finally { if (DBG) { long end = SystemClock.elapsedRealtime(); Rlog.d(LOG_TAG, "NITZ: end=" + end + " dur=" + (end - start)); } } } }ServiceStateTracker文件中对EVENT_NITZ_TIME事件的处理:
@Override public void handleMessage(Message msg) { AsyncResult ar; int[] ints; Message message; if (VDBG) log("received event " + msg.what); switch (msg.what) { case EVENT_SET_RADIO_POWER_OFF: synchronized(this) { if (mPendingRadioPowerOffAfterDataOff && (msg.arg1 == mPendingRadioPowerOffAfterDataOffTag)) { if (DBG) log("EVENT_SET_RADIO_OFF, turn radio off now."); hangupAndPowerOff(); mPendingRadioPowerOffAfterDataOffTag += 1; mPendingRadioPowerOffAfterDataOff = false; } else { log("EVENT_SET_RADIO_OFF is stale arg1=" + msg.arg1 + "!= tag=" + mPendingRadioPowerOffAfterDataOffTag); } } break; //省略较多代码.. case EVENT_NITZ_TIME: ar = (AsyncResult) msg.obj; String nitzString = (String)((Object[])ar.result)[0]; long nitzReceiveTime = ((Long)((Object[])ar.result)[1]).longValue(); setTimeFromNITZString(nitzString, nitzReceiveTime); break; case EVENT_SIGNAL_STRENGTH_UPDATE: // This is a notification from CommandsInterface.setOnSignalStrengthUpdate ar = (AsyncResult) msg.obj; // The radio is telling us about signal strength changes // we don't have to ask it mDontPollSignalStrength = true; onSignalStrengthResult(ar); break; public ServiceStateTracker(GsmCdmaPhone phone, CommandsInterface ci) { mNitzState = TelephonyComponentFactory.getInstance().makeNitzStateMachine(phone); mPhone = phone; mCi = ci; //省略较多代码 mCi.registerForImsNetworkStateChanged(this, EVENT_IMS_STATE_CHANGED, null); mCi.registerForRadioStateChanged(this, EVENT_RADIO_STATE_CHANGED, null); mCi.setOnNITZTime(this, EVENT_NITZ_TIME, null);frameworks/opt/telephony/src/java/com/android/internal/telephony/TelephonyComponentFactory.java
public static TelephonyComponentFactory getInstance() { if (sInstance == null) { String fullClsName = "com.qualcomm.qti.internal.telephony.QtiTelephonyComponentFactory"; String libPath = "/system/framework/qti-telephony-common.jar"; PathClassLoader classLoader = new PathClassLoader(libPath, ClassLoader.getSystemClassLoader()); Rlog.d(LOG_TAG, "classLoader = " + classLoader); if (fullClsName == null || fullClsName.length() == 0) { Rlog.d(LOG_TAG, "no customized TelephonyPlugin available, fallback to default"); fullClsName = "com.android.internal.telephony.TelephonyComponentFactory"; } Class<?> cls = null; try { cls = Class.forName(fullClsName, false, classLoader); Rlog.d(LOG_TAG, "cls = " + cls); Constructor custMethod = cls.getConstructor(); Rlog.d(LOG_TAG, "constructor method = " + custMethod); sInstance = (TelephonyComponentFactory) custMethod.newInstance(); } catch (NoClassDefFoundError e) { e.printStackTrace(); Rlog.e(LOG_TAG, "error loading TelephonyComponentFactory"); sInstance = new TelephonyComponentFactory(); } catch (Exception e) { e.printStackTrace(); Rlog.e(LOG_TAG, "Error loading TelephonyComponentFactory"); sInstance = new TelephonyComponentFactory(); } } return sInstance; } /** * Returns a new {@link NitzStateMachine} instance. */ public NitzStateMachine makeNitzStateMachine(GsmCdmaPhone phone) { return new NitzStateMachine(phone); }frameworks/opt/telephony/src/java/com/android/internal/telephony/RadioIndication.java
public void nitzTimeReceived(int indicationType, String nitzTime, long receivedTime) { mRil.processIndication(indicationType); if (RIL.RILJ_LOGD) mRil.unsljLogRet(RIL_UNSOL_NITZ_TIME_RECEIVED, nitzTime); // todo: Clean this up with a parcelable class for better self-documentation Object[] result = new Object[2]; result[0] = nitzTime; result[1] = receivedTime; boolean ignoreNitz = SystemProperties.getBoolean( TelephonyProperties.PROPERTY_IGNORE_NITZ, false); if (ignoreNitz) { if (RIL.RILJ_LOGD) mRil.riljLog("ignoring UNSOL_NITZ_TIME_RECEIVED"); } else { if (mRil.mNITZTimeRegistrant != null) { mRil.mNITZTimeRegistrant.notifyRegistrant(new AsyncResult (null, result, null)); } // in case NITZ time registrant isn't registered yet, or a new registrant // registers later mRil.mLastNITZTimeInfo = result; } }接着上述, 查看mTimeServiceHelper 的定义处: frameworks/opt/telephony/src/java/com/android/internal/telephony/TimeServiceHelper.java
/** * Set the device time zone and send out a sticky broadcast so the system can * determine if the timezone was set by the carrier. * * @param zoneId timezone set by carrier */ public void setDeviceTimeZone(String zoneId) { setDeviceTimeZoneStatic(mContext, zoneId); } /** * Static method for use by MccTable. See {@link #isTimeZoneSettingInitializedStatic()} for * explanation. */ static void setDeviceTimeZoneStatic(Context context, String zoneId) { AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); alarmManager.setTimeZone(zoneId); Intent intent = new Intent(TelephonyIntents.ACTION_NETWORK_SET_TIMEZONE); intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING); intent.putExtra("time-zone", zoneId); context.sendStickyBroadcastAsUser(intent, UserHandle.ALL); }根据广播TelephonyIntents.ACTION_NETWORK_SET_TIMEZONE找到文件: frameworks/base/telephony/java/com/android/internal/telephony/TelephonyIntents.java