1 /* 2 * Copyright (C) 2016 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 package com.android.car.hal; 17 18 import static com.android.car.hal.CarPropertyUtils.toCarPropertyValue; 19 import static com.android.car.hal.CarPropertyUtils.toVehiclePropValue; 20 import static java.lang.Integer.toHexString; 21 22 import android.annotation.Nullable; 23 import android.car.hardware.CarPropertyConfig; 24 import android.car.hardware.CarPropertyValue; 25 import android.car.hardware.property.CarPropertyEvent; 26 import android.hardware.automotive.vehicle.V2_0.VehiclePropConfig; 27 import android.hardware.automotive.vehicle.V2_0.VehiclePropValue; 28 import android.util.Log; 29 30 import com.android.car.CarLog; 31 import com.android.internal.annotations.GuardedBy; 32 33 import java.io.PrintWriter; 34 import java.util.ArrayList; 35 import java.util.Collection; 36 import java.util.LinkedList; 37 import java.util.List; 38 import java.util.concurrent.ConcurrentHashMap; 39 40 /** 41 * Common interface for HAL services that send Vehicle Properties back and forth via ICarProperty. 42 * Services that communicate by passing vehicle properties back and forth via ICarProperty should 43 * extend this class. 44 */ 45 public abstract class PropertyHalServiceBase extends HalServiceBase { 46 private final boolean mDbg; 47 private final ConcurrentHashMap<Integer, CarPropertyConfig<?>> mProps = 48 new ConcurrentHashMap<>(); 49 private final String mTag; 50 private final VehicleHal mVehicleHal; 51 52 @GuardedBy("mLock") 53 private PropertyHalListener mListener; 54 private final Object mLock = new Object(); 55 56 public interface PropertyHalListener { onPropertyChange(CarPropertyEvent event)57 void onPropertyChange(CarPropertyEvent event); onPropertySetError(int property, int area)58 void onPropertySetError(int property, int area); 59 } 60 PropertyHalServiceBase(VehicleHal vehicleHal, String tag, boolean dbg)61 protected PropertyHalServiceBase(VehicleHal vehicleHal, String tag, boolean dbg) { 62 mVehicleHal = vehicleHal; 63 mTag = "PropertyHalServiceBase." + tag; 64 mDbg = dbg; 65 66 if (mDbg) { 67 Log.d(mTag, "started PropertyHalServiceBase!"); 68 } 69 } 70 setListener(PropertyHalListener listener)71 public void setListener(PropertyHalListener listener) { 72 synchronized (mLock) { 73 mListener = listener; 74 } 75 } 76 getPropertyList()77 public List<CarPropertyConfig> getPropertyList() { 78 return new ArrayList<>(mProps.values()); 79 } 80 81 /** 82 * Returns property or null if property is not ready yet. 83 */ 84 @Nullable getProperty(int mgrPropId, int areaId)85 public CarPropertyValue getProperty(int mgrPropId, int areaId) { 86 int halPropId = managerToHalPropId(mgrPropId); 87 if (halPropId == NOT_SUPPORTED_PROPERTY) { 88 throw new IllegalArgumentException("Invalid property Id : 0x" + toHexString(mgrPropId)); 89 } 90 91 VehiclePropValue value = null; 92 try { 93 value = mVehicleHal.get(halPropId, areaId); 94 } catch (PropertyTimeoutException e) { 95 Log.e(CarLog.TAG_PROPERTY, "get, property not ready 0x" + toHexString(halPropId), e); 96 } 97 98 return value == null ? null : toCarPropertyValue(value, mgrPropId); 99 } 100 setProperty(CarPropertyValue prop)101 public void setProperty(CarPropertyValue prop) { 102 int halPropId = managerToHalPropId(prop.getPropertyId()); 103 if (halPropId == NOT_SUPPORTED_PROPERTY) { 104 throw new IllegalArgumentException("Invalid property Id : 0x" 105 + toHexString(prop.getPropertyId())); 106 } 107 VehiclePropValue halProp = toVehiclePropValue(prop, halPropId); 108 try { 109 mVehicleHal.set(halProp); 110 } catch (PropertyTimeoutException e) { 111 Log.e(CarLog.TAG_PROPERTY, "set, property not ready 0x" + toHexString(halPropId), e); 112 throw new RuntimeException(e); 113 } 114 } 115 116 @Override init()117 public void init() { 118 if (mDbg) { 119 Log.d(mTag, "init()"); 120 } 121 // Subscribe to each of the properties 122 for (Integer prop : mProps.keySet()) { 123 mVehicleHal.subscribeProperty(this, prop); 124 } 125 } 126 127 @Override release()128 public void release() { 129 if (mDbg) { 130 Log.d(mTag, "release()"); 131 } 132 133 for (Integer prop : mProps.keySet()) { 134 mVehicleHal.unsubscribeProperty(this, prop); 135 } 136 137 // Clear the property list 138 mProps.clear(); 139 140 synchronized (mLock) { 141 mListener = null; 142 } 143 } 144 145 @Override takeSupportedProperties( Collection<VehiclePropConfig> allProperties)146 public Collection<VehiclePropConfig> takeSupportedProperties( 147 Collection<VehiclePropConfig> allProperties) { 148 List<VehiclePropConfig> taken = new LinkedList<>(); 149 150 for (VehiclePropConfig p : allProperties) { 151 int mgrPropId = halToManagerPropId(p.prop); 152 153 if (mgrPropId == NOT_SUPPORTED_PROPERTY) { 154 continue; // The property is not handled by this HAL. 155 } 156 157 CarPropertyConfig config = CarPropertyUtils.toCarPropertyConfig(p, mgrPropId); 158 159 taken.add(p); 160 mProps.put(p.prop, config); 161 162 if (mDbg) { 163 Log.d(mTag, "takeSupportedProperties: " + toHexString(p.prop)); 164 } 165 } 166 return taken; 167 } 168 169 @Override handleHalEvents(List<VehiclePropValue> values)170 public void handleHalEvents(List<VehiclePropValue> values) { 171 PropertyHalListener listener; 172 synchronized (mLock) { 173 listener = mListener; 174 } 175 if (listener != null) { 176 for (VehiclePropValue v : values) { 177 int prop = v.prop; 178 int mgrPropId = halToManagerPropId(prop); 179 180 if (mgrPropId == NOT_SUPPORTED_PROPERTY) { 181 Log.e(mTag, "Property is not supported: 0x" + toHexString(prop)); 182 continue; 183 } 184 185 CarPropertyEvent event; 186 CarPropertyValue<?> propVal = toCarPropertyValue(v, mgrPropId); 187 event = new CarPropertyEvent(CarPropertyEvent.PROPERTY_EVENT_PROPERTY_CHANGE, 188 propVal); 189 190 listener.onPropertyChange(event); 191 if (mDbg) { 192 Log.d(mTag, "handleHalEvents event: " + event); 193 } 194 } 195 } 196 } 197 198 @Override handlePropertySetError(int property, int area)199 public void handlePropertySetError(int property, int area) { 200 PropertyHalListener listener; 201 synchronized (mLock) { 202 listener = mListener; 203 } 204 if (listener != null) { 205 listener.onPropertySetError(property, area); 206 } 207 } 208 209 @Override dump(PrintWriter writer)210 public void dump(PrintWriter writer) { 211 writer.println(mTag); 212 writer.println(" Properties available:"); 213 for (CarPropertyConfig prop : mProps.values()) { 214 writer.println(" " + prop.toString()); 215 } 216 } 217 218 /** 219 * Converts manager property ID to Vehicle HAL property ID. 220 * If property is not supported, it will return {@link #NOT_SUPPORTED_PROPERTY}. 221 */ managerToHalPropId(int managerPropId)222 abstract protected int managerToHalPropId(int managerPropId); 223 224 /** 225 * Converts Vehicle HAL property ID to manager property ID. 226 * If property is not supported, it will return {@link #NOT_SUPPORTED_PROPERTY}. 227 */ halToManagerPropId(int halPropId)228 abstract protected int halToManagerPropId(int halPropId); 229 } 230