DiagnosticHalService.java revision 20f13f7b883e4df807e1614f167cef21cc88ff1c
1/* 2 * Copyright (C) 2017 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 17package com.android.car.hal; 18 19import android.annotation.Nullable; 20import android.car.annotation.FutureFeature; 21import android.car.hardware.CarDiagnosticEvent; 22import android.car.hardware.CarDiagnosticManager; 23import android.car.hardware.CarSensorManager; 24import android.hardware.automotive.vehicle.V2_0.VehiclePropConfig; 25import android.hardware.automotive.vehicle.V2_0.VehiclePropValue; 26import android.hardware.automotive.vehicle.V2_0.VehiclePropertyChangeMode; 27import android.hardware.automotive.vehicle.V2_1.Obd2FloatSensorIndex; 28import android.hardware.automotive.vehicle.V2_1.Obd2IntegerSensorIndex; 29import android.hardware.automotive.vehicle.V2_1.VehicleProperty; 30import android.util.Log; 31import android.util.SparseArray; 32import com.android.car.CarLog; 33import com.android.car.CarServiceUtils; 34import com.android.car.vehiclehal.VehiclePropValueBuilder; 35import java.io.PrintWriter; 36import java.util.ArrayList; 37import java.util.Arrays; 38import java.util.BitSet; 39import java.util.Collections; 40import java.util.LinkedList; 41import java.util.List; 42import java.util.concurrent.CopyOnWriteArraySet; 43 44/** 45 * Diagnostic HAL service supporting gathering diagnostic info from VHAL and translating it into 46 * higher-level semantic information 47 */ 48public class DiagnosticHalService extends SensorHalServiceBase { 49 public static class DiagnosticCapabilities { 50 private final CopyOnWriteArraySet<Integer> mProperties = new CopyOnWriteArraySet<>(); 51 52 void setSupported(int propertyId) { 53 mProperties.add(propertyId); 54 } 55 56 boolean isSupported(int propertyId) { 57 return mProperties.contains(propertyId); 58 } 59 60 public boolean isLiveFrameSupported() { 61 return isSupported(VehicleProperty.OBD2_LIVE_FRAME); 62 } 63 64 public boolean isFreezeFrameSupported() { 65 return isSupported(VehicleProperty.OBD2_FREEZE_FRAME); 66 } 67 68 public boolean isFreezeFrameInfoSupported() { 69 return isSupported(VehicleProperty.OBD2_FREEZE_FRAME_INFO); 70 } 71 72 public boolean isFreezeFrameClearSupported() { 73 return isSupported(VehicleProperty.OBD2_FREEZE_FRAME_CLEAR); 74 } 75 76 void clear() { 77 mProperties.clear(); 78 } 79 } 80 81 private final DiagnosticCapabilities mDiagnosticCapabilities = new DiagnosticCapabilities(); 82 private DiagnosticListener mDiagnosticListener; 83 protected final SparseArray<VehiclePropConfig> mVehiclePropertyToConfig = new SparseArray<>(); 84 85 public DiagnosticHalService(VehicleHal hal) { 86 super(hal); 87 } 88 89 @Override 90 protected int getTokenForProperty(VehiclePropConfig propConfig) { 91 switch (propConfig.prop) { 92 case VehicleProperty.OBD2_LIVE_FRAME: 93 mDiagnosticCapabilities.setSupported(propConfig.prop); 94 mVehiclePropertyToConfig.put(propConfig.prop, propConfig); 95 Log.i(CarLog.TAG_DIAGNOSTIC, String.format("configArray for OBD2_LIVE_FRAME is %s", 96 propConfig.configArray)); 97 return CarDiagnosticManager.FRAME_TYPE_LIVE; 98 case VehicleProperty.OBD2_FREEZE_FRAME: 99 mDiagnosticCapabilities.setSupported(propConfig.prop); 100 mVehiclePropertyToConfig.put(propConfig.prop, propConfig); 101 Log.i(CarLog.TAG_DIAGNOSTIC, String.format("configArray for OBD2_FREEZE_FRAME is %s", 102 propConfig.configArray)); 103 return CarDiagnosticManager.FRAME_TYPE_FREEZE; 104 case VehicleProperty.OBD2_FREEZE_FRAME_INFO: 105 mDiagnosticCapabilities.setSupported(propConfig.prop); 106 return propConfig.prop; 107 case VehicleProperty.OBD2_FREEZE_FRAME_CLEAR: 108 mDiagnosticCapabilities.setSupported(propConfig.prop); 109 return propConfig.prop; 110 default: 111 return SENSOR_TYPE_INVALID; 112 } 113 } 114 115 @Override 116 public synchronized void release() { 117 super.release(); 118 mDiagnosticCapabilities.clear(); 119 } 120 121 private VehiclePropConfig getPropConfig(int halPropId) { 122 return mVehiclePropertyToConfig.get(halPropId, null); 123 } 124 125 private List<Integer> getPropConfigArray(int halPropId) { 126 VehiclePropConfig propConfig = getPropConfig(halPropId); 127 return propConfig.configArray; 128 } 129 130 private int getNumIntegerSensors(int halPropId) { 131 int count = Obd2IntegerSensorIndex.LAST_SYSTEM_INDEX + 1; 132 List<Integer> configArray = getPropConfigArray(halPropId); 133 if(configArray.size() < 2) { 134 Log.e(CarLog.TAG_DIAGNOSTIC, String.format( 135 "property 0x%x does not specify the number of vendor-specific properties." + 136 "assuming 0.", halPropId)); 137 } 138 else { 139 count += configArray.get(0); 140 } 141 return count; 142 } 143 144 private int getNumFloatSensors(int halPropId) { 145 int count = Obd2FloatSensorIndex.LAST_SYSTEM_INDEX + 1; 146 List<Integer> configArray = getPropConfigArray(halPropId); 147 if(configArray.size() < 2) { 148 Log.e(CarLog.TAG_DIAGNOSTIC, String.format( 149 "property 0x%x does not specify the number of vendor-specific properties." + 150 "assuming 0.", halPropId)); 151 } 152 else { 153 count += configArray.get(1); 154 } 155 return count; 156 } 157 158 private CarDiagnosticEvent createCarDiagnosticEvent(VehiclePropValue value) { 159 if (null == value) 160 return null; 161 162 final boolean isFreezeFrame = value.prop == VehicleProperty.OBD2_FREEZE_FRAME; 163 164 CarDiagnosticEvent.Builder builder = 165 (isFreezeFrame 166 ? CarDiagnosticEvent.Builder.newFreezeFrameBuilder() 167 : CarDiagnosticEvent.Builder.newLiveFrameBuilder()) 168 .atTimestamp(value.timestamp); 169 170 BitSet bitset = BitSet.valueOf(CarServiceUtils.toByteArray(value.value.bytes)); 171 172 int numIntegerProperties = getNumIntegerSensors(value.prop); 173 int numFloatProperties = getNumFloatSensors(value.prop); 174 175 for (int i = 0; i < numIntegerProperties; ++i) { 176 if (bitset.get(i)) { 177 builder.withIntValue(i, value.value.int32Values.get(i)); 178 } 179 } 180 181 for (int i = 0; i < numFloatProperties; ++i) { 182 if (bitset.get(numIntegerProperties + i)) { 183 builder.withFloatValue(i, value.value.floatValues.get(i)); 184 } 185 } 186 187 builder.withDtc(value.value.stringValue); 188 189 return builder.build(); 190 } 191 192 /** Listener for monitoring diagnostic event. */ 193 public interface DiagnosticListener { 194 /** 195 * Diagnostic events are available. 196 * 197 * @param events 198 */ 199 void onDiagnosticEvents(List<CarDiagnosticEvent> events); 200 } 201 202 // Should be used only inside handleHalEvents method. 203 private final LinkedList<CarDiagnosticEvent> mEventsToDispatch = new LinkedList<>(); 204 205 @Override 206 public void handleHalEvents(List<VehiclePropValue> values) { 207 for (VehiclePropValue value : values) { 208 CarDiagnosticEvent event = createCarDiagnosticEvent(value); 209 if (event != null) { 210 mEventsToDispatch.add(event); 211 } 212 } 213 214 DiagnosticListener listener = null; 215 synchronized (this) { 216 listener = mDiagnosticListener; 217 } 218 if (listener != null) { 219 listener.onDiagnosticEvents(mEventsToDispatch); 220 } 221 mEventsToDispatch.clear(); 222 } 223 224 public synchronized void setDiagnosticListener(DiagnosticListener listener) { 225 mDiagnosticListener = listener; 226 } 227 228 public DiagnosticListener getDiagnosticListener() { 229 return mDiagnosticListener; 230 } 231 232 @Override 233 public void dump(PrintWriter writer) { 234 writer.println("*Diagnostic HAL*"); 235 } 236 237 @Override 238 protected float fixSamplingRateForProperty(VehiclePropConfig prop, int carSensorManagerRate) { 239 //TODO(egranata): tweak this for diagnostics 240 switch (prop.changeMode) { 241 case VehiclePropertyChangeMode.ON_CHANGE: 242 case VehiclePropertyChangeMode.ON_SET: 243 return 0; 244 } 245 float rate = 1.0f; 246 switch (carSensorManagerRate) { 247 case CarSensorManager.SENSOR_RATE_FASTEST: 248 case CarSensorManager.SENSOR_RATE_FAST: 249 rate = 10f; 250 break; 251 case CarSensorManager.SENSOR_RATE_UI: 252 rate = 5f; 253 break; 254 default: // fall back to default. 255 break; 256 } 257 if (rate > prop.maxSampleRate) { 258 rate = prop.maxSampleRate; 259 } 260 if (rate < prop.minSampleRate) { 261 rate = prop.minSampleRate; 262 } 263 return rate; 264 } 265 266 public DiagnosticCapabilities getDiagnosticCapabilities() { 267 return mDiagnosticCapabilities; 268 } 269 270 @Nullable 271 public CarDiagnosticEvent getCurrentLiveFrame() { 272 try { 273 VehiclePropValue value = mHal.get(VehicleProperty.OBD2_LIVE_FRAME); 274 return createCarDiagnosticEvent(value); 275 } catch (PropertyTimeoutException e) { 276 Log.e(CarLog.TAG_DIAGNOSTIC, "timeout trying to read OBD2_LIVE_FRAME"); 277 return null; 278 } catch (IllegalArgumentException e) { 279 Log.e(CarLog.TAG_DIAGNOSTIC, "illegal argument trying to read OBD2_LIVE_FRAME", e); 280 return null; 281 } 282 } 283 284 @Nullable 285 public long[] getFreezeFrameTimestamps() { 286 try { 287 VehiclePropValue value = mHal.get(VehicleProperty.OBD2_FREEZE_FRAME_INFO); 288 long[] timestamps = new long[value.value.int64Values.size()]; 289 for (int i = 0; i < timestamps.length; ++i) { 290 timestamps[i] = value.value.int64Values.get(i); 291 } 292 return timestamps; 293 } catch (PropertyTimeoutException e) { 294 Log.e(CarLog.TAG_DIAGNOSTIC, "timeout trying to read OBD2_FREEZE_FRAME_INFO"); 295 return null; 296 } catch (IllegalArgumentException e) { 297 Log.e(CarLog.TAG_DIAGNOSTIC, 298 "illegal argument trying to read OBD2_FREEZE_FRAME_INFO", e); 299 return null; 300 } 301 } 302 303 @Nullable 304 public CarDiagnosticEvent getFreezeFrame(long timestamp) { 305 VehiclePropValueBuilder builder = VehiclePropValueBuilder.newBuilder( 306 VehicleProperty.OBD2_FREEZE_FRAME); 307 builder.setInt64Value(timestamp); 308 try { 309 VehiclePropValue value = mHal.get(builder.build()); 310 return createCarDiagnosticEvent(value); 311 } catch (PropertyTimeoutException e) { 312 Log.e(CarLog.TAG_DIAGNOSTIC, "timeout trying to read OBD2_FREEZE_FRAME"); 313 return null; 314 } catch (IllegalArgumentException e) { 315 Log.e(CarLog.TAG_DIAGNOSTIC, 316 "illegal argument trying to read OBD2_FREEZE_FRAME", e); 317 return null; 318 } 319 } 320 321 public void clearFreezeFrames(long... timestamps) { 322 VehiclePropValueBuilder builder = VehiclePropValueBuilder.newBuilder( 323 VehicleProperty.OBD2_FREEZE_FRAME_CLEAR); 324 builder.setInt64Value(timestamps); 325 try { 326 mHal.set(builder.build()); 327 } catch (PropertyTimeoutException e) { 328 Log.e(CarLog.TAG_DIAGNOSTIC, "timeout trying to write OBD2_FREEZE_FRAME_CLEAR"); 329 } catch (IllegalArgumentException e) { 330 Log.e(CarLog.TAG_DIAGNOSTIC, 331 "illegal argument trying to write OBD2_FREEZE_FRAME_CLEAR", e); 332 } 333 } 334} 335