1 /*
2  * Copyright (C) 2021 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.car.hal;
18 
19 import static android.hardware.automotive.vehicle.V2_0.VehicleProperty.EPOCH_TIME;
20 
21 import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.DUMP_INFO;
22 
23 import static java.util.Objects.requireNonNull;
24 
25 import android.annotation.Nullable;
26 import android.content.BroadcastReceiver;
27 import android.content.Context;
28 import android.content.Intent;
29 import android.content.IntentFilter;
30 import android.hardware.automotive.vehicle.V2_0.VehicleArea;
31 import android.hardware.automotive.vehicle.V2_0.VehiclePropConfig;
32 import android.hardware.automotive.vehicle.V2_0.VehiclePropValue;
33 import android.hardware.automotive.vehicle.V2_0.VehiclePropertyStatus;
34 import android.util.IndentingPrintWriter;
35 
36 import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport;
37 
38 import java.io.PrintWriter;
39 import java.time.Instant;
40 import java.util.Collection;
41 import java.util.List;
42 
43 /** Writes the Android System time to EPOCH_TIME in the VHAL, if supported. */
44 public final class TimeHalService extends HalServiceBase {
45 
46     private static final int[] SUPPORTED_PROPERTIES = new int[]{EPOCH_TIME};
47 
48     private final Context mContext;
49 
50     private final VehicleHal mHal;
51 
52     private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
53         @Override
54         public void onReceive(Context context, Intent intent) {
55             if (Intent.ACTION_TIME_CHANGED.equals(intent.getAction())) {
56                 updateProperty(System.currentTimeMillis());
57             }
58         }
59     };
60 
61     private boolean mReceiverRegistered;
62 
63     @Nullable
64     private Instant mLastAndroidTimeReported;
65 
66     private boolean mAndroidTimeSupported;
67 
TimeHalService(Context context, VehicleHal hal)68     TimeHalService(Context context, VehicleHal hal) {
69         mContext = requireNonNull(context);
70         mHal = requireNonNull(hal);
71     }
72 
73     @Override
init()74     public void init() {
75         if (!mAndroidTimeSupported) {
76             return;
77         }
78 
79         updateProperty(System.currentTimeMillis());
80 
81         IntentFilter filter = new IntentFilter(Intent.ACTION_TIME_CHANGED);
82         mContext.registerReceiver(mReceiver, filter);
83         mReceiverRegistered = true;
84     }
85 
86     @Override
release()87     public void release() {
88         if (mReceiverRegistered) {
89             mContext.unregisterReceiver(mReceiver);
90             mReceiverRegistered = false;
91         }
92 
93         mAndroidTimeSupported = false;
94         mLastAndroidTimeReported = null;
95     }
96 
97     @Override
getAllSupportedProperties()98     public int[] getAllSupportedProperties() {
99         return SUPPORTED_PROPERTIES;
100     }
101 
102     @Override
takeProperties(Collection<VehiclePropConfig> properties)103     public void takeProperties(Collection<VehiclePropConfig> properties) {
104         for (VehiclePropConfig property : properties) {
105             switch (property.prop) {
106                 case EPOCH_TIME:
107                     mAndroidTimeSupported = true;
108                     return;
109             }
110         }
111     }
112 
113     @Override
onHalEvents(List<VehiclePropValue> values)114     public void onHalEvents(List<VehiclePropValue> values) {
115     }
116 
isAndroidTimeSupported()117     public boolean isAndroidTimeSupported() {
118         return mAndroidTimeSupported;
119     }
120 
updateProperty(long timeMillis)121     private void updateProperty(long timeMillis) {
122         VehiclePropValue propValue = new VehiclePropValue();
123         propValue.prop = EPOCH_TIME;
124         propValue.areaId = VehicleArea.GLOBAL;
125         propValue.status = VehiclePropertyStatus.AVAILABLE;
126         propValue.timestamp = timeMillis;
127         propValue.value.int64Values.add(timeMillis);
128 
129         mHal.set(propValue);
130         mLastAndroidTimeReported = Instant.ofEpochMilli(timeMillis);
131     }
132 
133     @Override
134     @ExcludeFromCodeCoverageGeneratedReport(reason = DUMP_INFO)
dump(PrintWriter printWriter)135     public void dump(PrintWriter printWriter) {
136         IndentingPrintWriter writer = new IndentingPrintWriter(printWriter);
137         writer.println("*ExternalTime HAL*");
138         writer.increaseIndent();
139         writer.printf(
140                 "mLastAndroidTimeReported: %d millis",
141                 mLastAndroidTimeReported.toEpochMilli());
142         writer.decreaseIndent();
143         writer.flush();
144     }
145 }
146