拡張可能時刻管理

Android Automotive オペレーティング システム(AAOS)は、自動車のインテリジェントなタイムソースであることが求められます。自動車における時刻のゲートウェイであることで、特有の課題がもたらされます。車両によっては、AAOS が他の車載システムでの車両のタイムソースとして機能し、複数の入力(TCU など)からインテリジェントに時計を設定する機能を提供する必要があります。

Android 時刻管理アーキテクチャをそのまま維持するために、このセクションではプラットフォーム レベルで解決される一般的な時刻に関する課題について説明します

*拡張可能時刻管理(ETM)*では、AAOS と Android 外の他の車両システムとの間で時刻を同期できるようにするメカニズムと API がパートナーに提供されます。この機能は、他の車両システム(ECU、BCM ユニット、ダッシュボード上の時計を含む)が VHAL に、CAN、イーサネットまたは他の手段で接続されていることを前提としています。そのため、AAOS が VHAL と時刻を同期できるようにすれば、主な目標は達成できます。

ここで以下のことは行いません

  • SystemTimevDisplayTime を分けるなど、複数種類の時刻を Android に追加すること。
  • VHAL がどのように他の車両システム、ECU、BCM、またはダッシュボード上の時計から時刻値を取得して設定するかについての説明。これは各 VHAL の実装の詳細と考えられます。このコンテンツでは、時刻同期機能を有効にするために必要な AAOS と VHAL の間のやり取りのみを明示しています。
  • TimeDetectorServiceTimeDetectorStrategy の設計上の選択と実装の詳細については、自動時刻検出をご覧ください。
  • 必要に応じて複数のタイムソースを自動車に追加し、カスタムの VHAL 実装に統合できます。この VHAL は、EXTERNAL_CAR_TIME プロパティを通じて単一の統合された時刻値を渡します。
  • Android での金融取引のための NIST の精密計時など、時刻精度の基準のサポートを明示的に追加することはありません。OEM は正確なタイムソースをシステムに提供する必要があります。

Android における時刻の機能強化

Android 12 では、提供されているロケーション マネージャー サービスを通じて衛星から時刻を取得できます。タイムソースの優先度設定オーバーレイを使用すると、ベンダーは、有効な時刻候補の優先度を設定するためのオーバーレイを提供できます。Android の主なタイムソースは次のとおりです。

  1. テレフォニー スタック、ネットワーク ID とタイムゾーン(NITZ)
  2. 手動時刻選択
  3. シンプル ネットワーク タイム プロトコル(SNTP)
  4. 全地球航法衛星システム(GNSS)(Android 12 の新機能)
  5. ExternalTime(Android Automotive OS の新機能)

用語

以下の用語は、このページ全体で使用されています。

用語 定義
ボディ コントロール モジュール(BCM) 車両の電子アクセサリのモニタリングと制御を担当する電子コントロール ユニットの総称。
コントローラ エリア ネットワーク(CAN) シリアル通信プロトコル。
電子コントロール ユニット(ECU) ECU は、ユーザー HAL プロパティを介して Android ベースのインフォテインメント システムとやり取りできます。
全地球航法衛星システム(GNSS) 測位と計時のデータを宇宙から GNSS 受信機に送信する衛星。
国立標準技術研究所(NIST) 正確なタイムスタンプ設定が可能になります。
ネットワーク ID とタイムゾーン(NITZ) 現地日時、タイムゾーンと DST オフセット、ネットワーク プロバイダの ID 情報を、ワイヤレス ネットワークを介してモバイル デバイスにプロビジョニングするためのメカニズム。
リアルタイム通信(RTC) すべてのユーザーが瞬時にまたはほとんど遅延なく情報を交換できる通信モード。
シンプル ネットワーク タイム プロトコル(SNTP) ネットワーク タイム プロトコル(NTP)の簡略版。
テレマティクス コントロール ユニット(TCU) 車両の追跡を制御する、車両に搭載された組み込みシステムのこと。

時刻を同期するための新しい VHAL プロパティ

拡張可能時刻管理では、Android とさまざまな ECU、または車載ユニットとの間で時刻を同期するために、2 つの新しいプロパティが VHAL に追加されました。

  • EXTERNAL_CAR_TIME: ECU や BCM などの車両システム(AAOS の外部)から AAOS に時刻を同期。
  • EPOCH_TIME AAOS から ECU や BCM などの車両システムに時刻を同期。

VHAL は単一のタイムソースを決定し、他のユニットにリレーします。AAOS が信頼できるタイムソースである場合もあれば、そうでない場合もあります。

  • Android が信頼できるタイムソースとして選択されている場合、VHAL は、Android からの時刻の変更を伝えて他の車両システム(ECU、BCM など)に渡す、書き込み専用の EPOCH_TIME プロパティをサポートします。
  • Android が信頼できるタイムソースとして選択されていない場合、VHAL は、Android からの時刻の変更を伝えて他の車両システム(ECU、BCM などを含む)に渡すために、読み取り専用の EXTERNAL_CAR_TIME プロパティをサポートします。
EXTERNAL_CAR_TIME EPOCH_TIME
(master ブランチの ANDROID_TIME
VHAL > Android Android > VHAL

エポック時刻(Android)

サポートされている場合、AAOS はこのプロパティに書き込み、Android システムの時刻を VHAL に渡します。AAOS は、CarServices が初期化されたときに 1 回プロパティに書き込み、AAOS タイムソースが変更されるたびにプロパティに書き込みます(INTENT_ACTION_TIME_CHANGED で示されます)。これは、他の車両システム(ダッシュボード上の時計など)や ECU を Android の時刻と同期させる場合に便利です。VHAL 実装は、他の接続されたシステムや ECU に渡すことができる時刻値と更新を Android から受け取ります。このプロパティがサポートされている場合は、Android が信頼できるタイムソースであることが一般的です。

EPOCH_TIME(Android から ECU への通信用)と EXTERNAL_CAR_TIME(ECU から Android への通信用)という 2 つの新しい VHAL プロパティが提供されます。OEM は通常、これらのプロパティのいずれか 1 つだけを実装する必要があります。

AAOS 固有のベンダー、ハードウェア、インターフェース、カスタム ベンダーのタイムソースは次のとおりです。

時刻(ToD) OEM バックエンド
シンプル ネットワーク タイム プロトコル(SNTP) OEM バックエンド
次のような機能を持つ車載 ECU(BCM など)

OEM は、これらを単一の時刻に統合し、EXTERNAL_CAR_TIME を使用して Android に渡す必要があります。Android はこの値を使用して、設定された優先度に基づいてシステム時刻を検討します。

EPOCH_TIME

  /**
     * Current date and time, encoded as Unix time (in milliseconds).
     * This value denotes the number of milliseconds seconds that have
     * elapsed since 1/1/1970 UTC.
     *
     * AAOS will write to this value to give VHAL the Android system's time,
     * if the VHAL supports this property. This can be useful to synchronize
     * other vehicle systems (dash clock etc) with Android's time.
     *
     * AAOS writes to this property once during boot, and
     * will thereafter write only when some time-source changes are propagated.
     * AAOS will fill in VehiclePropValue.timestamp correctly.
     * Note that AAOS will not send updates for natural elapse of time.
     *     int64Values[0] = provided Unix time (in milliseconds)
     *
     * Note that the property may take >0 ms to get propagated through the stack
     * and, having a timestamped property helps reduce any time drift. So,
     * for all writes to the property, the timestamp can be used to negate this
     * drift:
     *     drift = currentTimeMillis - PropValue.timestamp
     *     effectiveTime = PropValue.value.int64Values[0] + diff
     *
     * Aside, this property could have been better named ANDROID_EPOCH_TIME, but it
     * continues to be called EPOCH_TIME for legacy reasons. We will try to fix
     * this naming discrepancy when we migrate to AIDL.
     *
     * @change_mode VehiclePropertyChangeMode:ON_CHANGE
     * @access VehiclePropertyAccess:WRITE_ONLY
     * @unit VehicleUnit:MILLI_SECS
     */
    EPOCH_TIME = (
        0xxxxx
        | VehiclePropertyGroup:SYSTEM
        | VehiclePropertyType:INT64
        | VehicleArea:GLOBAL),

車外の時刻

コンパイル時に OEM が設定した場合、Android では、システム時刻を設定するために外部時刻を使用できます。AAOS はこのプロパティをサブスクライブして読み込み、ExternalTimeSuggestion を生成して TimeManager サービスに渡します。これは、Android の時刻を他の車両システム(ダッシュボード上の時計など)や ECU と同期させる場合に便利です。VHAL 実装は起動時に、また時刻同期が変更されるたびに、このプロパティに書き込むことが想定されています。VHAL 実装が時間の経過に伴ってこのプロパティに書き込むことは想定されていません。このプロパティがサポートされている場合は、Android が信頼できるタイムソースでないことが一般的です。

  /**
     * Current date and time for the Car, encoded as Unix time (in milliseconds).
     * This value denotes the number of milliseconds seconds that have
     * elapsed since 1/1/1970 UTC.
     *
     * This property signals a change in CarTime to Android. VHAL must report the
     * most accurate current CarTime when this property is read, and publish a
     * change to this property when the CarTime value has changed.
     * Android will read and subscribe to this property to fetch time from VHAL,
     * if the property is supported. This can be useful to synchronize Android's
     * time with other vehicle systems (dash clock etc).
     *     int64Values[0] = provided Unix time (in milliseconds)
     *
     * Whenever a new Value for the property is received, AAOS will create
     * and send an "ExternalTimeSuggestion" to the "TimeDetectorService".
     * If other sources do not have a higher priority, Android will use this
     * to set the system time. For information on how to adjust time source
     * priorities and how time suggestions are handled (including how Android
     * handles gitter, drift, and minimum resolution) see Time Detector Service
     * documentation.
     *
     * Note that the property may take >0 ms to get propagated through the stack
     * and, having a timestamped property helps reduce any time drift. So,
     * for all writes to the property, the timestamp can be used to negate this
     * drift:
     *     drift = currentTimeMillis - PropValue.timestamp
     *     effectiveTime = PropValue.value.int64Values[0] + diff
     *
     * WARNING: It is recommended to use Android's own systems for GNSS, NTP,
     * Telephony etc. instead of wiring those through the VHAL using this property.
     *
     * @change_mode VehiclePropertyChangeMode:ON_CHANGE
     * @access VehiclePropertyAccess:READ_ONLY
     * @unit VehicleUnit:MILLI_SECS
     */
    EXTERNAL_CAR_TIME = (
        0xxxxx
        | VehiclePropertyGroup:SYSTEM
        | VehiclePropertyType:INT64
        | VehicleArea:GLOBAL),

ExternalTime と ExternalTimeSuggestion

TimeManager サービスに ExternalTime を提案するための新しいパスが追加されました。TimeDetectorService は(それに応じて TimeManager も)、複数種類のタイムソースを使用します。現在のところ、Android でシステム クロックを設定するために使用できるタイムソースは、テレフォニー スタックのネットワーク ID とタイムゾーン(NITZ)、ネットワーク タイム プロトコル(NTP)、ユーザーが手動で設定する時刻、の 3 つです。

ExternalTime は、AAOS プラットフォームをターゲットとして作成された新しいタイムソースです。これは、Android の時刻を車内の ECU または BCM ユニットと同期させる場合に便利です(ただし Android の外部)。ExternalTime はシステム タイムソースとして適切にプラグインされ、優先度を設定できます。TimeDetectorStrategy で適切に設定すると、外部時刻が他のタイムソースよりも優先されます。

次のシーケンス図に、新しい設計を示します。

図 1: シーケンス図

複数のプロパティのサポート

OEM は、EPOCH_TIMEEXTERNAL_CAR_TIME の両方のプロパティをサポートできます。

たとえば、自動車の ECU がなんらかのタイムソース(DCF77 など)に接続されているものの、Android 内の他のタイムソース(GNSS、NTP、テレフォニーなど)で解決するために値を Android に渡す必要がある場合です。この場合、OEM は ECU から EXTERNAL_CAR_TIME を介して Android に時刻値を渡し、EPOCH_TIME を使用して解決されたシステム時刻を受け取ることができます。次に、その時刻を使用して他の周辺機器の時刻を設定します。

Android システムと VHAL 実装の間での情報の流れにおいてフィードバック ループが発生しないようにすることが重要です。そのため、EXTERNAL_CAR_TIME を通じて提供される値が EPOCH_TIME から受け取る値に依存してはならないということが、両方のプロパティをサポートする OEM に対する唯一の制約となります。

Intent.ACTION_TIME_CHANGED に BroadcastReceiver を登録する

TimeHalService(Car サービスの新しいクラス)は、Intent.ACTION_TIME_CHANGEDBroadcastReceiver を登録し、VHAL プロパティ EPOCH_TIME に書き込んで Android システム時刻の変更を VHAL に通知できるようにします。

外部時刻を提案する新しい TimeManager API

時刻提案機能は、android.app.time.TimeManager#suggestExternalTime() という新しい Android @SystemAPI を通じて公開されます。このメソッドは、提案を TimeDetectorService#suggestExternalTime に転送してから TimeDetectorStrategy#suggestExternalTime に転送します。TimeDetectorStrategy は、最後の ExternalTimeSuggestion インスタンスを追跡し、時刻検出戦略設定で元の外部が優先されている場合、この提案を使用します。

新しい SUGGEST_EXTERNAL_TIME 権限

SUGGEST_EXTERNAL_TIME という新しい権限が追加されました。TimeManager.sugestExternalTime() API はこの権限で制限されているため、サードパーティ デベロッパーは SUGGEST_EXTERNAL_TIME 権限を使用して呼び出します。新しい権限は保護レベル privileged としてマークされます。これにより、システム イメージにプリインストールされているサードパーティ アプリがこの権限を取得する可能性はありますが、許容範囲内です。

  • サードパーティ アプリにこの権限を付与するには OEM の調整が必要であるため、「privileged」を追加しても実質的なリスクは生じません。
  • この API は、提案されたタイムスタンプが新しいシステム タイムスタンプとしてすぐに使用されることを保証するものではありません。ExternalTimeSuggestion を使用するには、外部のタイムソースを他のタイムソース(GNSS など)よりも優先するようにシステムを設定する必要があります。この設定は OEM が行います。
  • アプリは TimeManager.setTime() を直接使用してシステム時刻を設定できます。これには SET_TIME 権限が必要です。この新しい権限と API モデルも特権であり、既存の API との整合性があります。

時刻の拡張性の実装

この新機能を高品質で実装するために、OEM は、新しい VHAL プロパティを使用して値を正しく反映するように AAOS を設定する方法について把握しておく必要があります。このセクションは、OEM が何をどのようにデプロイして時刻の拡張性を設定するかを決定できるよう、提供されています。

AAOS タイムソースの設定

AAOS は、2 つの VHAL プロパティ(EPOCH_TIMEEXTERNAL_CAR_TIME)をサポートしており、OEM が自動車のさまざまなユニット間(Android、ECR、BCM を含む)で時刻を同期する方法を決定できるように、設定可能な TimeDetectorStrategy もサポートしています。まず、OEM は単一の信頼できるタイムソースを決定する必要があります。Android の観点では、これは Android か外部ソース(ECU、BCM、ダッシュボード上の時計など)のいずれかです。

このような場合、OEM は他の自動車システム(ECU、BCM など)を AAOS の時刻と同期させることができます。そのためには、VHAL が書き込み専用のプロパティ EPOCH_TIME をサポートし、AAOS がシステム時刻をこのプロパティに書き込むたびに、受け取った更新を処理または転送する必要があります。

フローは次のとおりです。

  1. VHAL が、EPOCH_TIME VHAL プロパティを介して Android のシステム時刻を受け取ります。
  2. TimeHalService が、起動時や、Android のタイムソースが同期されるたびにシステム時刻を読み取り、プロパティに書き込みます。
  3. VHAL は、受け取った時刻値をさまざまな ECU と BCM ユニットに反映できます。

Android がタイムソースとして機能しない場合

このような場合、OEM は、信頼できるタイムソースである自動車システム(ECU や BCM など)と AAOS 時刻を同期させることができます。そのためには、VHAL が読み取り専用のプロパティ EXTERNAL_CAR_TIME をサポートし、タイムソースが変更されるか時計が再校正されるたびに、このプロパティの更新を公開する必要があります。

OEM は TimeDetectorStrategy の設定で、外部時刻に適切な優先度を設定する必要もあります。

<!-- Specifies priority of automatic time sources. Suggestions from higher entries in the list take precedence over lower ones.
See com.android.server.timedetector.TimeDetectorStrategy for available sources. -->
     <string-array name="config_autoTimeSourcesPriority">
        <item>external</item>
        <item>gnss</item>
        <item>network</item>
        <item>telephony</item>
    </string-array>

フローをまとめると次のようになります。

  1. VHAL が EXTERNAL_CAR_TIME プロパティを更新します。
  2. TimeHalService(CarServices 内)が、サブスクリプションを通じてプロパティを読み取ります。
  3. TimeHalServiceExternalTimeSuggestion を作成して TimeManager. に送信します。
  4. TimeManager が提案を TimeDetectorService. に転送します。
  5. TimeDetectorServiceTimeDetectorStrategy を使用して新しいシステム時刻を選択します。

付録 A、プロパティの変更

EPOCH_TIME

TimeHalService は、プロパティが VHAL でサポートされることが報告されている場合、EPOCH_TIME をサポートする次の機能を提供します。

  1. 起動時にシステム時刻を EPOCH_TIME プロパティに書き込む。
  2. Intent.ACTION_TIME_CHANGED に BroadcastReceiver を登録し、ブロードキャストを受け取るたびにシステム時刻を EPOCH_TIME プロパティに書き込む。
public class TimeHalService extends HalServiceBase {
    …

    @Override
    public void init() {
        updateProperty(System.currentTimeMillis());

        IntentFilter filter = new IntentFilter();
        filter.addAction(Intent.ACTION_TIME_CHANGED);

        mReceiver = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                if (Intent.ACTION_TIME_CHANGED.equals(intent.getAction())) {
                    updateProperty(System.currentTimeMillis());
                }
            }
        };

        mContext.registerReceiver(
                mReceiver, filter, /* broadcastPermissions = */ null,
                new Handler(Looper.myLooper()));
    }

    private void updateProperty(long timeMillis) {
        VehiclePropValue propValue = new VehiclePropValue();
        propValue.prop = VehicleProperty.EPOCH_TIME;
        propValue.areaId = VehicleArea.GLOBAL;
        propValue.status = VehiclePropertyStatus.AVAILABLE;
        propValue.timestamp = timeMillis;
        propValue.value.int64Values.add(timeMillis);

        Slogf.d(TAG, "Sending Android Time: " + propValue);
        mHal.set(propValue);
    }
}

EXTERNAL_TIME

TimeHalService は、プロパティが VHAL でサポートされることが報告されている場合、EXTERNAL_CAR_TIME をサポートするために次の機能を提供します。

  1. 可能な場合は EXTERNAL_CAR_TIME プロパティをサブスクライブする。
  2. EXTERNAL_CAR_TIME の新しい値を受け取ったら、ExternalTimeSuggestion を作成して TimeManager サービスに送信する。
public class TimeHalService extends HalServiceBase {
    private static final float SAMPLE_FREQ_HZ = 1.0 / 60 / 60;

    …

    @Override
    public void init() {
        VehiclePropValue propValue = mHal.get(VehicleProperty.EXTERNAL_CAR_TIME);
        suggestExternalTime(propValue);

        mHal.subscribeProperty(this, EPOCH_TIME, SAMPLE_FREQ_HZ);
    }

    @Override
    public void onHalEvents(List<VehiclePropValue> values) {
        for (VehiclePropValue value : values) {
            suggestExternalTime(value);
        }
    }

    private void suggestExternalTime(VehiclePropValue value) {
        if (value.prop != VehicleProperty.EXTERNAL_CAR_TIME
             || value.status != VehiclePropertyStatus.AVAILABLE) {
            return;
        }

        long epochTime = value.value.int64Values.get(0);
        // timestamp is stored in nanoseconds but the suggest API uses
        // milliseconds.
        long elapsedRealtime = value.timestamp / 1_000_000;

        mLastExternalTimeSuggestion =
            new ExternalTimeSuggestion(elapsedRealtime, epochTime);

        Slogf.d(TAG, "Sending Time Suggestion: " + mLastExternalTimeSuggestion);
        mTimeManager.suggestExternalTime(mLastExternalTimeSuggestion);
    }
}