1 /* 2 * Copyright (C) 2015 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 android.os.HandlerThread; 20 import android.util.ArraySet; 21 import android.util.Log; 22 import android.util.SparseArray; 23 24 import com.android.car.CarLog; 25 import com.android.car.vehiclenetwork.VehicleNetwork; 26 import com.android.car.vehiclenetwork.VehicleNetwork.VehicleNetworkListener; 27 import com.android.car.vehiclenetwork.VehicleNetworkConsts; 28 import com.android.car.vehiclenetwork.VehicleNetworkConsts.VehiclePropAccess; 29 import com.android.car.vehiclenetwork.VehicleNetworkConsts.VehiclePropChangeMode; 30 import com.android.car.vehiclenetwork.VehicleNetworkProto.VehiclePropConfig; 31 import com.android.car.vehiclenetwork.VehicleNetworkProto.VehiclePropConfigs; 32 import com.android.car.vehiclenetwork.VehicleNetworkProto.VehiclePropValue; 33 import com.android.car.vehiclenetwork.VehicleNetworkProto.VehiclePropValues; 34 import com.android.car.vehiclenetwork.VehiclePropValueUtil; 35 import com.android.internal.annotations.VisibleForTesting; 36 37 import java.io.PrintWriter; 38 import java.util.Collection; 39 import java.util.HashMap; 40 import java.util.LinkedList; 41 import java.util.List; 42 43 /** 44 * Abstraction for vehicle HAL. This class handles interface with native HAL and do basic parsing 45 * of received data (type check). Then each event is sent to corresponding {@link HalServiceBase} 46 * implementation. It is responsibility of {@link HalServiceBase} to convert data to corresponding 47 * Car*Service for Car*Manager API. 48 */ 49 public class VehicleHal implements VehicleNetworkListener { 50 51 private static final boolean DBG = true; 52 53 static { createInstance()54 createInstance(); 55 } 56 57 private static VehicleHal sInstance; 58 getInstance()59 public static synchronized VehicleHal getInstance() { 60 if (sInstance == null) { 61 createInstance(); 62 } 63 return sInstance; 64 } 65 createInstance()66 private static synchronized void createInstance() { 67 sInstance = new VehicleHal(); 68 // init is handled in a separate thread to prevent blocking the calling thread for too 69 // long. 70 sInstance.init(); 71 } 72 releaseInstance()73 public static synchronized void releaseInstance() { 74 if (sInstance != null) { 75 sInstance.release(); 76 sInstance = null; 77 } 78 } 79 80 private final HandlerThread mHandlerThread; 81 private final VehicleNetwork mVehicleNetwork; 82 private final SensorHalService mSensorHal; 83 private final InfoHalService mInfoHal; 84 private final AudioHalService mAudioHal; 85 private final RadioHalService mRadioHal; 86 private final PowerHalService mPowerHal; 87 private final HvacHalService mHvacHal; 88 private final InputHalService mInputHal; 89 90 /** stores handler for each HAL property. Property events are sent to handler. */ 91 private final SparseArray<HalServiceBase> mPropertyHandlers = new SparseArray<HalServiceBase>(); 92 /** This is for iterating all HalServices with fixed order. */ 93 private final HalServiceBase[] mAllServices; 94 private final ArraySet<Integer> mSubscribedProperties = new ArraySet<Integer>(); 95 private final HashMap<Integer, VehiclePropConfig> mUnclaimedProperties = new HashMap<>(); 96 private final List<VehiclePropConfig> mAllProperties = new LinkedList<>(); 97 VehicleHal()98 private VehicleHal() { 99 mHandlerThread = new HandlerThread("VEHICLE-HAL"); 100 mHandlerThread.start(); 101 // passing this should be safe as long as it is just kept and not used in constructor 102 mPowerHal = new PowerHalService(this); 103 mSensorHal = new SensorHalService(this); 104 mInfoHal = new InfoHalService(this); 105 mAudioHal = new AudioHalService(this); 106 mRadioHal = new RadioHalService(this); 107 mHvacHal = new HvacHalService(this); 108 mInputHal = new InputHalService(); 109 mAllServices = new HalServiceBase[] { 110 mPowerHal, 111 mAudioHal, 112 mHvacHal, 113 mInfoHal, 114 mSensorHal, 115 mRadioHal, 116 mInputHal 117 }; 118 mVehicleNetwork = VehicleNetwork.createVehicleNetwork(this, mHandlerThread.getLooper()); 119 } 120 121 /** Dummy version only for testing */ 122 @VisibleForTesting VehicleHal(PowerHalService powerHal, SensorHalService sensorHal, InfoHalService infoHal, AudioHalService audioHal, RadioHalService radioHal, HvacHalService hvacHal, VehicleNetwork vehicleNetwork)123 public VehicleHal(PowerHalService powerHal, SensorHalService sensorHal, InfoHalService infoHal, 124 AudioHalService audioHal, RadioHalService radioHal, HvacHalService hvacHal, 125 VehicleNetwork vehicleNetwork) { 126 mHandlerThread = null; 127 mPowerHal = powerHal; 128 mSensorHal = sensorHal; 129 mInfoHal = infoHal; 130 mAudioHal = audioHal; 131 mRadioHal = radioHal; 132 mHvacHal = hvacHal; 133 mInputHal = null; 134 mAllServices = null; 135 mVehicleNetwork = vehicleNetwork; 136 } 137 init()138 private void init() { 139 VehiclePropConfigs properties = mVehicleNetwork.listProperties(); 140 // needs copy as getConfigsList gives unmodifiable one. 141 List<VehiclePropConfig> propertiesList = 142 new LinkedList<VehiclePropConfig>(properties.getConfigsList()); 143 for (HalServiceBase service: mAllServices) { 144 List<VehiclePropConfig> taken = service.takeSupportedProperties(propertiesList); 145 if (taken == null) { 146 continue; 147 } 148 if (DBG) { 149 Log.i(CarLog.TAG_HAL, "HalService " + service + " take properties " + taken.size()); 150 } 151 synchronized (this) { 152 for (VehiclePropConfig p: taken) { 153 mPropertyHandlers.append(p.getProp(), service); 154 } 155 } 156 propertiesList.removeAll(taken); 157 service.init(); 158 } 159 synchronized (this) { 160 for (VehiclePropConfig p: propertiesList) { 161 mUnclaimedProperties.put(p.getProp(), p); 162 } 163 mAllProperties.addAll(properties.getConfigsList()); 164 } 165 } 166 release()167 private void release() { 168 // release in reverse order from init 169 for (int i = mAllServices.length - 1; i >= 0; i--) { 170 mAllServices[i].release(); 171 } 172 synchronized (this) { 173 for (int p : mSubscribedProperties) { 174 mVehicleNetwork.unsubscribe(p); 175 } 176 mSubscribedProperties.clear(); 177 mUnclaimedProperties.clear(); 178 mAllProperties.clear(); 179 } 180 // keep the looper thread as should be kept for the whole life cycle. 181 } 182 startMocking()183 public void startMocking() { 184 reinitHals(); 185 } 186 stopMocking()187 public void stopMocking() { 188 reinitHals(); 189 } 190 reinitHals()191 private void reinitHals() { 192 release(); 193 init(); 194 } 195 getSensorHal()196 public SensorHalService getSensorHal() { 197 return mSensorHal; 198 } 199 getInfoHal()200 public InfoHalService getInfoHal() { 201 return mInfoHal; 202 } 203 getAudioHal()204 public AudioHalService getAudioHal() { 205 return mAudioHal; 206 } 207 getRadioHal()208 public RadioHalService getRadioHal() { 209 return mRadioHal; 210 } 211 getPowerHal()212 public PowerHalService getPowerHal() { 213 return mPowerHal; 214 } 215 getHvacHal()216 public HvacHalService getHvacHal() { 217 return mHvacHal; 218 } 219 getInputHal()220 public InputHalService getInputHal() { 221 return mInputHal; 222 } 223 assertServiceOwnerLocked(HalServiceBase service, int property)224 private void assertServiceOwnerLocked(HalServiceBase service, int property) { 225 if (service != mPropertyHandlers.get(property)) { 226 throw new IllegalArgumentException("not owned"); 227 } 228 } 229 230 /** 231 * Subscribe given property. Only Hal service owning the property can subscribe it. 232 * @param service 233 * @param property 234 * @param samplingRateHz 235 */ subscribeProperty(HalServiceBase service, int property, float samplingRateHz)236 public void subscribeProperty(HalServiceBase service, int property, 237 float samplingRateHz) throws IllegalArgumentException { 238 synchronized (this) { 239 assertServiceOwnerLocked(service, property); 240 mSubscribedProperties.add(property); 241 } 242 mVehicleNetwork.subscribe(property, samplingRateHz); 243 } 244 unsubscribeProperty(HalServiceBase service, int property)245 public void unsubscribeProperty(HalServiceBase service, int property) { 246 synchronized (this) { 247 assertServiceOwnerLocked(service, property); 248 mSubscribedProperties.remove(property); 249 } 250 mVehicleNetwork.unsubscribe(property); 251 } 252 getVehicleNetwork()253 public VehicleNetwork getVehicleNetwork() { 254 return mVehicleNetwork; 255 } 256 isPropertySubscribable(VehiclePropConfig config)257 public static boolean isPropertySubscribable(VehiclePropConfig config) { 258 if (config.hasAccess() & VehiclePropAccess.VEHICLE_PROP_ACCESS_READ == 0 || 259 config.getChangeMode() == 260 VehiclePropChangeMode.VEHICLE_PROP_CHANGE_MODE_STATIC) { 261 return false; 262 } 263 return true; 264 } 265 dumpProperties(PrintWriter writer, Collection<VehiclePropConfig> configs)266 public static void dumpProperties(PrintWriter writer, Collection<VehiclePropConfig> configs) { 267 for (VehiclePropConfig config : configs) { 268 writer.println("property " + 269 VehicleNetworkConsts.getVehiclePropertyName(config.getProp())); 270 } 271 } 272 273 private final ArraySet<HalServiceBase> mServicesToDispatch = new ArraySet<HalServiceBase>(); 274 275 @Override onVehicleNetworkEvents(VehiclePropValues values)276 public void onVehicleNetworkEvents(VehiclePropValues values) { 277 synchronized (this) { 278 for (VehiclePropValue v : values.getValuesList()) { 279 HalServiceBase service = mPropertyHandlers.get(v.getProp()); 280 service.getDispatchList().add(v); 281 mServicesToDispatch.add(service); 282 } 283 } 284 for (HalServiceBase s : mServicesToDispatch) { 285 s.handleHalEvents(s.getDispatchList()); 286 s.getDispatchList().clear(); 287 } 288 mServicesToDispatch.clear(); 289 } 290 291 @Override onHalError(int errorCode, int property, int operation)292 public void onHalError(int errorCode, int property, int operation) { 293 Log.e(CarLog.TAG_HAL, "onHalError, errorCode:" + errorCode + 294 " property:0x" + Integer.toHexString(property) + 295 " operation:" + operation); 296 // TODO propagate per property error to HAL services and handle global error 297 } 298 299 @Override onHalRestart(boolean inMocking)300 public void onHalRestart(boolean inMocking) { 301 Log.e(CarLog.TAG_HAL, "onHalRestart, inMocking:" + inMocking); 302 // TODO restart things as other components started mocking. For now, ignore. 303 } 304 dump(PrintWriter writer)305 public void dump(PrintWriter writer) { 306 writer.println("**dump HAL services**"); 307 for (HalServiceBase service: mAllServices) { 308 service.dump(writer); 309 } 310 writer.println("**All properties**"); 311 for (VehiclePropConfig config : mAllProperties) { 312 StringBuilder builder = new StringBuilder(); 313 builder.append("Property:" + Integer.toHexString(config.getProp())); 314 builder.append(",access:" + Integer.toHexString(config.getAccess())); 315 builder.append(",changeMode:" + Integer.toHexString(config.getChangeMode())); 316 builder.append(",valueType:" + Integer.toHexString(config.getValueType())); 317 builder.append(",permission:" + Integer.toHexString(config.getPermissionModel())); 318 builder.append(",config:" + Integer.toHexString(config.getConfigArray(0))); 319 builder.append(",fs min:" + config.getSampleRateMin()); 320 builder.append(",fs max:" + config.getSampleRateMax()); 321 for (int i = 0; i < config.getFloatMaxsCount(); i++) { 322 builder.append(",v min:" + config.getFloatMins(i)); 323 builder.append(",v max:" + config.getFloatMaxs(i)); 324 } 325 for (int i = 0; i < config.getInt32MaxsCount(); i++) { 326 builder.append(",v min:" + config.getInt32Mins(i)); 327 builder.append(",v max:" + config.getInt32Maxs(i)); 328 } 329 for (int i = 0; i < config.getInt64MaxsCount(); i++) { 330 builder.append(",v min:" + config.getInt64Mins(i)); 331 builder.append(",v max:" + config.getInt64Maxs(i)); 332 } 333 writer.println(builder.toString()); 334 } 335 } 336 } 337