Androidのtimestampについて勉強したこと
SensorEventのtimestampについてのメモの続きっぽいもの。いわゆるRTCとセンサとかGPSのタイムスタンプはそれぞれ違うものだという話。このへんはLinuxの基本的なことだと思うがよくわかってなかったし、今もいまいちよくわかっていないので、間違ってたら教えて下さい。
timestampの基本的な話
ほとんどSystemClock
のAPIリファレンスに書いてあることですが。。。
Androidにはスタートがそれぞれ違うタイムスタンプが3つある。ざっくりいうとこんな感じ。
System.currentTimeMillis()
: 1970.1.1からの経過時間uptimeMillis()
: システム起動時からの経過時間。システムがdeep sleepになったりした間はカウントが止まる。elapsedRealtime()
,elapsedRealtimeNanos()
: システム起動時からの経過時間。システムがdeep sleepになってた間の分もカウントに含まれる。
1は壁掛け時計と同じで、ユーザやシステムが値を変更できる。だからいつの間にか時間が戻っていたり思っていたより進んでいた、なんてことが起こる。値が変わったことは次のブロードキャストインテントで教えてもらえる。
ACTION_TIMER_TICK
: 時間が変わったことを1分毎に通知する。manifestファイルではなく、Context.registerReceiver()
でレジスタを登録する。ACTION_TIME_CHANGED
: 時間がセットされたことを通知する。ACTION_TIMEZONE_CHANGED
: タイムゾーンが変わったことを通知する。
一方、2や3は単調であること(数値の変化が単純に増えることだと思う)が保証されている。
GPSのtimestamp
位置情報はLocation
クラスで渡されるが、測位した時間を知るメソッドとして、UTC時間がもらえるgetTime()
と、前述のgetElapsedRealtimeNanos()
がある。ただし、getElapsedRealtimeNanos()
はAPI Level 17からなのでちょっと使いづらい。
センサのtimestamp
加速度センサとかの値(SensorEvent
)に入ってるtimestampは、APIリファレンスには
イベントが起きた時間(ナノ秒)
程度の説明しかなくて正直なんのこっちゃわからん。ナノ秒ということなのでシステム起動からの経過時間だと思われる。ここはソースを追いかけたけどよくわからなかった。
前に書いたものではセンサの時間をSystem.nanoTime()
とみなそうとしていたのだが、果たして正しいのか。
Androidでナノ秒のタイムスタンプをもらうならSystem.nanoTime()
かelapsedRealtimeNanos()
だが、中で呼んでいるネイティブなコードがそれぞれ違うようだ。
System.nanoTime()
:clock_gettime()
にCLOCK_MONOTONIC
を渡しているelapsedRealtimeNanos()
:ioctl()
に/dev/alarm
のファイルディスクリプタとANDROID_ALARM_GET_TIME(ANDROID_ALARM_ELAPSED_REALTIME)
を渡している
clock_gettime(CLOCK_MONOTONIC, )
はLinuxでよく使われる時間関数で、ここによるとNTPなどの時間調整の影響を受けると書いてある。だが、ioctl()
が何をしているのかわからない。。。ざんねん!私の冒険はここで終わってしまった!
引き続き調査します。なにかわかったら続きを書きます。
おまけ
SystemClock.cpp
(4.3.0_r2.2)のelapsedRealtimeNanos()
を読んでいたら気になる記述があった。
- clock_gettime appears to have clock skews and can sometimes return
- backwards values. Disable its use until we find out what's wrong.
clock_gettime
はときどき時間が歪んだり過去の値を返したりするから、何が悪いかわかるまで使えないようにしておくよ、とのこと。ioctl()
はその代わりに使われている様子。
おまけ2
書いてる最中、某アイドルの声で「elapseRealtimeなの!」が脳内再生されていたんだが明らかに某社畜botの影響です本当にありがとうございました。