1. 程式人生 > >[android原始碼日記]當系統時間小於1970年

[android原始碼日記]當系統時間小於1970年

我們知道,計算機的時間是從1970年開始的,而java獲取時間的方法System.currentTimeMillis()的返回值也是從0開始的,0就代表1970年一月一日。

那麼這個如果值為負數會怎麼樣?1969年?

今天在讀SystemServer原始碼的時候看到其中run方法修復時間的一段。它是這麼處理的。

// If a device's clock is before 1970 (before 0), a lot of
// APIs crash dealing with negative numbers, notably
// java.io.File#setLastModified, so instead we fake it and
// hope that time from cell towers or NTP fixes it shortly.
if (System.currentTimeMillis() < EARLIEST_SUPPORTED_TIME) {
    Slog.w(TAG, "System clock is before 1970; setting to 1970.");
    SystemClock.setCurrentTimeMillis(EARLIEST_SUPPORTED_TIME);
}

也就是手機的時鐘可能是小於1970年的,但如果小於這個值的話java.io.File#setLastModified則會引起崩潰,因此android原始碼在這裡加了個判斷,如果時間小於1970,則把時間設定為1970年。。(註釋是說1970年,但實際上拿EARLIEST_SUPPORTED_TIME這個時間戳計算是1972/9/27 8:0:0,不知道為什麼是這個時間,難道這就是口是心非??)

具體就是:

// The earliest supported time.  We pick one day into 1970, to
    // give any timezone code room without going into negative time.
    private static final long EARLIEST_SUPPORTED_TIME = 86400 * 1000;

實現設定CurrentTimeMillis的程式碼:

/**
 * Sets the current wall time, in milliseconds.  Requires the calling
 * process to have appropriate permissions.
 *
 * @return if the clock was successfully set to the specified time.
 */
public static boolean setCurrentTimeMillis(long millis) {
    IBinder b = ServiceManager.getService(Context.ALARM_SERVICE);
    IAlarmManager mgr = IAlarmManager.Stub.asInterface(b);
    if (mgr == null) {
        return false;
    }

    try {
        return mgr.setTime(millis);
    } catch (RemoteException e) {
        Slog.e(TAG, "Unable to set RTC", e);
    } catch (SecurityException e) {
        Slog.e(TAG, "Unable to set RTC", e);
    }

    return false;
}

關鍵的就是mgr.setTime(millis);設定了時間

public boolean setTime(long millis) throws RemoteException {
    Parcel _data = Parcel.obtain();
    Parcel _reply = Parcel.obtain();

    boolean _result;
    try {
        _data.writeInterfaceToken("android.app.IAlarmManager");
        _data.writeLong(millis);
        this.mRemote.transact(2, _data, _reply, 0);
        _reply.readException();
        _result = 0 != _reply.readInt();
    } finally {
        _reply.recycle();
        _data.recycle();
    }

    return _result;
}