keunyoung | cc449f7 | 2015-08-12 10:46:27 -0700 | [diff] [blame] | 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 | |
keunyoung | cc449f7 | 2015-08-12 10:46:27 -0700 | [diff] [blame] | 19 | import android.os.HandlerThread; |
Keun-young Park | 97e46eb | 2016-04-09 15:02:38 -0700 | [diff] [blame] | 20 | import android.os.SystemClock; |
keunyoung | fe30ba0 | 2015-09-17 17:56:35 -0700 | [diff] [blame] | 21 | import android.util.ArraySet; |
keunyoung | cc449f7 | 2015-08-12 10:46:27 -0700 | [diff] [blame] | 22 | import android.util.Log; |
| 23 | import android.util.SparseArray; |
| 24 | |
| 25 | import com.android.car.CarLog; |
keunyoung | fe30ba0 | 2015-09-17 17:56:35 -0700 | [diff] [blame] | 26 | import com.android.car.vehiclenetwork.VehicleNetwork; |
| 27 | import com.android.car.vehiclenetwork.VehicleNetwork.VehicleNetworkListener; |
keunyoung | a74b9ca | 2015-10-21 13:33:58 -0700 | [diff] [blame] | 28 | import com.android.car.vehiclenetwork.VehicleNetworkConsts; |
| 29 | import com.android.car.vehiclenetwork.VehicleNetworkConsts.VehiclePropAccess; |
| 30 | import com.android.car.vehiclenetwork.VehicleNetworkConsts.VehiclePropChangeMode; |
keunyoung | fe30ba0 | 2015-09-17 17:56:35 -0700 | [diff] [blame] | 31 | import com.android.car.vehiclenetwork.VehicleNetworkProto.VehiclePropConfig; |
| 32 | import com.android.car.vehiclenetwork.VehicleNetworkProto.VehiclePropConfigs; |
| 33 | import com.android.car.vehiclenetwork.VehicleNetworkProto.VehiclePropValue; |
| 34 | import com.android.car.vehiclenetwork.VehicleNetworkProto.VehiclePropValues; |
Keun-young Park | fd3fbf7 | 2016-01-22 17:00:17 -0800 | [diff] [blame] | 35 | import com.android.internal.annotations.VisibleForTesting; |
keunyoung | cc449f7 | 2015-08-12 10:46:27 -0700 | [diff] [blame] | 36 | |
| 37 | import java.io.PrintWriter; |
Steve Paik | 4d6088c | 2016-07-20 20:27:55 -0700 | [diff] [blame] | 38 | import java.util.ArrayList; |
keunyoung | a74b9ca | 2015-10-21 13:33:58 -0700 | [diff] [blame] | 39 | import java.util.Collection; |
keunyoung | e4c90c4 | 2015-11-16 18:42:52 -0800 | [diff] [blame] | 40 | import java.util.HashMap; |
keunyoung | cc449f7 | 2015-08-12 10:46:27 -0700 | [diff] [blame] | 41 | import java.util.LinkedList; |
| 42 | import java.util.List; |
| 43 | |
| 44 | /** |
| 45 | * Abstraction for vehicle HAL. This class handles interface with native HAL and do basic parsing |
| 46 | * of received data (type check). Then each event is sent to corresponding {@link HalServiceBase} |
| 47 | * implementation. It is responsibility of {@link HalServiceBase} to convert data to corresponding |
| 48 | * Car*Service for Car*Manager API. |
| 49 | */ |
keunyoung | fe30ba0 | 2015-09-17 17:56:35 -0700 | [diff] [blame] | 50 | public class VehicleHal implements VehicleNetworkListener { |
keunyoung | cc449f7 | 2015-08-12 10:46:27 -0700 | [diff] [blame] | 51 | |
Vitalii Tomkiv | 1b1247b | 2016-09-30 11:27:19 -0700 | [diff] [blame] | 52 | private static final boolean DBG = false; |
keunyoung | cc449f7 | 2015-08-12 10:46:27 -0700 | [diff] [blame] | 53 | |
keunyoung | cc449f7 | 2015-08-12 10:46:27 -0700 | [diff] [blame] | 54 | static { |
keunyoung | fe30ba0 | 2015-09-17 17:56:35 -0700 | [diff] [blame] | 55 | createInstance(); |
keunyoung | cc449f7 | 2015-08-12 10:46:27 -0700 | [diff] [blame] | 56 | } |
| 57 | |
| 58 | private static VehicleHal sInstance; |
| 59 | |
keunyoung | fe30ba0 | 2015-09-17 17:56:35 -0700 | [diff] [blame] | 60 | public static synchronized VehicleHal getInstance() { |
keunyoung | cc449f7 | 2015-08-12 10:46:27 -0700 | [diff] [blame] | 61 | if (sInstance == null) { |
keunyoung | fe30ba0 | 2015-09-17 17:56:35 -0700 | [diff] [blame] | 62 | createInstance(); |
keunyoung | cc449f7 | 2015-08-12 10:46:27 -0700 | [diff] [blame] | 63 | } |
| 64 | return sInstance; |
| 65 | } |
| 66 | |
keunyoung | fe30ba0 | 2015-09-17 17:56:35 -0700 | [diff] [blame] | 67 | private static synchronized void createInstance() { |
| 68 | sInstance = new VehicleHal(); |
| 69 | // init is handled in a separate thread to prevent blocking the calling thread for too |
| 70 | // long. |
keunyoung | e4c90c4 | 2015-11-16 18:42:52 -0800 | [diff] [blame] | 71 | sInstance.init(); |
keunyoung | fe30ba0 | 2015-09-17 17:56:35 -0700 | [diff] [blame] | 72 | } |
| 73 | |
keunyoung | cc449f7 | 2015-08-12 10:46:27 -0700 | [diff] [blame] | 74 | public static synchronized void releaseInstance() { |
| 75 | if (sInstance != null) { |
| 76 | sInstance.release(); |
| 77 | sInstance = null; |
| 78 | } |
| 79 | } |
| 80 | |
keunyoung | e4c90c4 | 2015-11-16 18:42:52 -0800 | [diff] [blame] | 81 | private final HandlerThread mHandlerThread; |
keunyoung | fe30ba0 | 2015-09-17 17:56:35 -0700 | [diff] [blame] | 82 | private final VehicleNetwork mVehicleNetwork; |
keunyoung | cc449f7 | 2015-08-12 10:46:27 -0700 | [diff] [blame] | 83 | private final SensorHalService mSensorHal; |
keunyoung | a3b28d8 | 2015-08-25 13:05:15 -0700 | [diff] [blame] | 84 | private final InfoHalService mInfoHal; |
keunyoung | d32f4e6 | 2015-09-21 11:33:06 -0700 | [diff] [blame] | 85 | private final AudioHalService mAudioHal; |
Steve Paik | 43c04a7 | 2016-07-08 19:12:09 -0700 | [diff] [blame] | 86 | private final CabinHalService mCabinHal; |
Sanket Agarwal | 3cf096a | 2015-10-13 14:46:31 -0700 | [diff] [blame] | 87 | private final RadioHalService mRadioHal; |
keunyoung | 4b0212c | 2015-10-29 17:11:57 -0700 | [diff] [blame] | 88 | private final PowerHalService mPowerHal; |
Steve Paik | 6648198 | 2015-10-27 15:22:38 -0700 | [diff] [blame] | 89 | private final HvacHalService mHvacHal; |
Keun-young Park | a28d7b2 | 2016-02-29 16:54:29 -0800 | [diff] [blame] | 90 | private final InputHalService mInputHal; |
Pavel Maltsev | 634e1ff | 2016-07-14 15:41:26 -0700 | [diff] [blame] | 91 | private final VendorExtensionHalService mVendorExtensionHal; |
keunyoung | cc449f7 | 2015-08-12 10:46:27 -0700 | [diff] [blame] | 92 | |
| 93 | /** stores handler for each HAL property. Property events are sent to handler. */ |
| 94 | private final SparseArray<HalServiceBase> mPropertyHandlers = new SparseArray<HalServiceBase>(); |
| 95 | /** This is for iterating all HalServices with fixed order. */ |
| 96 | private final HalServiceBase[] mAllServices; |
keunyoung | fe30ba0 | 2015-09-17 17:56:35 -0700 | [diff] [blame] | 97 | private final ArraySet<Integer> mSubscribedProperties = new ArraySet<Integer>(); |
Steve Paik | 4d6088c | 2016-07-20 20:27:55 -0700 | [diff] [blame] | 98 | private final HashMap<Integer, VehiclePropConfig> mAllProperties = new HashMap<>(); |
Keun-young Park | 97e46eb | 2016-04-09 15:02:38 -0700 | [diff] [blame] | 99 | private final HashMap<Integer, VehiclePropertyEventInfo> mEventLog = new HashMap<>(); |
| 100 | |
keunyoung | fe30ba0 | 2015-09-17 17:56:35 -0700 | [diff] [blame] | 101 | private VehicleHal() { |
keunyoung | e4c90c4 | 2015-11-16 18:42:52 -0800 | [diff] [blame] | 102 | mHandlerThread = new HandlerThread("VEHICLE-HAL"); |
keunyoung | cc449f7 | 2015-08-12 10:46:27 -0700 | [diff] [blame] | 103 | mHandlerThread.start(); |
keunyoung | cc449f7 | 2015-08-12 10:46:27 -0700 | [diff] [blame] | 104 | // passing this should be safe as long as it is just kept and not used in constructor |
keunyoung | 4b0212c | 2015-10-29 17:11:57 -0700 | [diff] [blame] | 105 | mPowerHal = new PowerHalService(this); |
keunyoung | cc449f7 | 2015-08-12 10:46:27 -0700 | [diff] [blame] | 106 | mSensorHal = new SensorHalService(this); |
keunyoung | a3b28d8 | 2015-08-25 13:05:15 -0700 | [diff] [blame] | 107 | mInfoHal = new InfoHalService(this); |
keunyoung | d32f4e6 | 2015-09-21 11:33:06 -0700 | [diff] [blame] | 108 | mAudioHal = new AudioHalService(this); |
Steve Paik | 43c04a7 | 2016-07-08 19:12:09 -0700 | [diff] [blame] | 109 | mCabinHal = new CabinHalService(this); |
Sanket Agarwal | 3cf096a | 2015-10-13 14:46:31 -0700 | [diff] [blame] | 110 | mRadioHal = new RadioHalService(this); |
Steve Paik | 6648198 | 2015-10-27 15:22:38 -0700 | [diff] [blame] | 111 | mHvacHal = new HvacHalService(this); |
Keun-young Park | a28d7b2 | 2016-02-29 16:54:29 -0800 | [diff] [blame] | 112 | mInputHal = new InputHalService(); |
Pavel Maltsev | 634e1ff | 2016-07-14 15:41:26 -0700 | [diff] [blame] | 113 | mVendorExtensionHal = new VendorExtensionHalService(this); |
keunyoung | a3b28d8 | 2015-08-25 13:05:15 -0700 | [diff] [blame] | 114 | mAllServices = new HalServiceBase[] { |
keunyoung | 4b0212c | 2015-10-29 17:11:57 -0700 | [diff] [blame] | 115 | mPowerHal, |
keunyoung | d32f4e6 | 2015-09-21 11:33:06 -0700 | [diff] [blame] | 116 | mAudioHal, |
Steve Paik | 43c04a7 | 2016-07-08 19:12:09 -0700 | [diff] [blame] | 117 | mCabinHal, |
Steve Paik | 6648198 | 2015-10-27 15:22:38 -0700 | [diff] [blame] | 118 | mHvacHal, |
keunyoung | a3b28d8 | 2015-08-25 13:05:15 -0700 | [diff] [blame] | 119 | mInfoHal, |
Sanket Agarwal | 3cf096a | 2015-10-13 14:46:31 -0700 | [diff] [blame] | 120 | mSensorHal, |
Keun-young Park | a28d7b2 | 2016-02-29 16:54:29 -0800 | [diff] [blame] | 121 | mRadioHal, |
Pavel Maltsev | 634e1ff | 2016-07-14 15:41:26 -0700 | [diff] [blame] | 122 | mInputHal, |
| 123 | mVendorExtensionHal |
Keun-young Park | a28d7b2 | 2016-02-29 16:54:29 -0800 | [diff] [blame] | 124 | }; |
keunyoung | fe30ba0 | 2015-09-17 17:56:35 -0700 | [diff] [blame] | 125 | mVehicleNetwork = VehicleNetwork.createVehicleNetwork(this, mHandlerThread.getLooper()); |
keunyoung | cc449f7 | 2015-08-12 10:46:27 -0700 | [diff] [blame] | 126 | } |
| 127 | |
Keun-young Park | fd3fbf7 | 2016-01-22 17:00:17 -0800 | [diff] [blame] | 128 | /** Dummy version only for testing */ |
| 129 | @VisibleForTesting |
| 130 | public VehicleHal(PowerHalService powerHal, SensorHalService sensorHal, InfoHalService infoHal, |
Steve Paik | 43c04a7 | 2016-07-08 19:12:09 -0700 | [diff] [blame] | 131 | AudioHalService audioHal, CabinHalService cabinHal, RadioHalService radioHal, |
| 132 | HvacHalService hvacHal, VehicleNetwork vehicleNetwork) { |
Keun-young Park | fd3fbf7 | 2016-01-22 17:00:17 -0800 | [diff] [blame] | 133 | mHandlerThread = null; |
| 134 | mPowerHal = powerHal; |
| 135 | mSensorHal = sensorHal; |
| 136 | mInfoHal = infoHal; |
| 137 | mAudioHal = audioHal; |
Steve Paik | 43c04a7 | 2016-07-08 19:12:09 -0700 | [diff] [blame] | 138 | mCabinHal = cabinHal; |
Keun-young Park | fd3fbf7 | 2016-01-22 17:00:17 -0800 | [diff] [blame] | 139 | mRadioHal = radioHal; |
| 140 | mHvacHal = hvacHal; |
Keun-young Park | a28d7b2 | 2016-02-29 16:54:29 -0800 | [diff] [blame] | 141 | mInputHal = null; |
Pavel Maltsev | 634e1ff | 2016-07-14 15:41:26 -0700 | [diff] [blame] | 142 | mVendorExtensionHal = null; |
Keun-young Park | fd3fbf7 | 2016-01-22 17:00:17 -0800 | [diff] [blame] | 143 | mAllServices = null; |
| 144 | mVehicleNetwork = vehicleNetwork; |
| 145 | } |
| 146 | |
Keun-young Park | 021310d | 2016-04-25 21:09:39 -0700 | [diff] [blame] | 147 | public void init() { |
keunyoung | fe30ba0 | 2015-09-17 17:56:35 -0700 | [diff] [blame] | 148 | VehiclePropConfigs properties = mVehicleNetwork.listProperties(); |
| 149 | // needs copy as getConfigsList gives unmodifiable one. |
| 150 | List<VehiclePropConfig> propertiesList = |
| 151 | new LinkedList<VehiclePropConfig>(properties.getConfigsList()); |
Steve Paik | 4d6088c | 2016-07-20 20:27:55 -0700 | [diff] [blame] | 152 | |
| 153 | synchronized (this) { |
| 154 | // Create map of all properties |
| 155 | for (VehiclePropConfig p : propertiesList) { |
| 156 | mAllProperties.put(p.getProp(), p); |
| 157 | } |
| 158 | } |
| 159 | |
keunyoung | cc449f7 | 2015-08-12 10:46:27 -0700 | [diff] [blame] | 160 | for (HalServiceBase service: mAllServices) { |
keunyoung | fe30ba0 | 2015-09-17 17:56:35 -0700 | [diff] [blame] | 161 | List<VehiclePropConfig> taken = service.takeSupportedProperties(propertiesList); |
keunyoung | a3b28d8 | 2015-08-25 13:05:15 -0700 | [diff] [blame] | 162 | if (taken == null) { |
| 163 | continue; |
| 164 | } |
keunyoung | cc449f7 | 2015-08-12 10:46:27 -0700 | [diff] [blame] | 165 | if (DBG) { |
| 166 | Log.i(CarLog.TAG_HAL, "HalService " + service + " take properties " + taken.size()); |
| 167 | } |
keunyoung | e4c90c4 | 2015-11-16 18:42:52 -0800 | [diff] [blame] | 168 | synchronized (this) { |
| 169 | for (VehiclePropConfig p: taken) { |
| 170 | mPropertyHandlers.append(p.getProp(), service); |
| 171 | } |
keunyoung | cc449f7 | 2015-08-12 10:46:27 -0700 | [diff] [blame] | 172 | } |
keunyoung | fe30ba0 | 2015-09-17 17:56:35 -0700 | [diff] [blame] | 173 | propertiesList.removeAll(taken); |
keunyoung | cc449f7 | 2015-08-12 10:46:27 -0700 | [diff] [blame] | 174 | service.init(); |
| 175 | } |
| 176 | } |
| 177 | |
Keun-young Park | 021310d | 2016-04-25 21:09:39 -0700 | [diff] [blame] | 178 | public void release() { |
keunyoung | cc449f7 | 2015-08-12 10:46:27 -0700 | [diff] [blame] | 179 | // release in reverse order from init |
| 180 | for (int i = mAllServices.length - 1; i >= 0; i--) { |
| 181 | mAllServices[i].release(); |
| 182 | } |
keunyoung | e4c90c4 | 2015-11-16 18:42:52 -0800 | [diff] [blame] | 183 | synchronized (this) { |
| 184 | for (int p : mSubscribedProperties) { |
| 185 | mVehicleNetwork.unsubscribe(p); |
| 186 | } |
| 187 | mSubscribedProperties.clear(); |
Keun-young Park | 450faba | 2016-02-10 18:15:12 -0800 | [diff] [blame] | 188 | mAllProperties.clear(); |
keunyoung | fe30ba0 | 2015-09-17 17:56:35 -0700 | [diff] [blame] | 189 | } |
keunyoung | fe30ba0 | 2015-09-17 17:56:35 -0700 | [diff] [blame] | 190 | // keep the looper thread as should be kept for the whole life cycle. |
keunyoung | cc449f7 | 2015-08-12 10:46:27 -0700 | [diff] [blame] | 191 | } |
| 192 | |
| 193 | public SensorHalService getSensorHal() { |
| 194 | return mSensorHal; |
| 195 | } |
| 196 | |
keunyoung | a3b28d8 | 2015-08-25 13:05:15 -0700 | [diff] [blame] | 197 | public InfoHalService getInfoHal() { |
| 198 | return mInfoHal; |
| 199 | } |
| 200 | |
keunyoung | d32f4e6 | 2015-09-21 11:33:06 -0700 | [diff] [blame] | 201 | public AudioHalService getAudioHal() { |
| 202 | return mAudioHal; |
| 203 | } |
| 204 | |
Steve Paik | 43c04a7 | 2016-07-08 19:12:09 -0700 | [diff] [blame] | 205 | public CabinHalService getCabinHal() { |
| 206 | return mCabinHal; |
| 207 | } |
| 208 | |
Sanket Agarwal | 3cf096a | 2015-10-13 14:46:31 -0700 | [diff] [blame] | 209 | public RadioHalService getRadioHal() { |
| 210 | return mRadioHal; |
| 211 | } |
| 212 | |
keunyoung | 4b0212c | 2015-10-29 17:11:57 -0700 | [diff] [blame] | 213 | public PowerHalService getPowerHal() { |
| 214 | return mPowerHal; |
| 215 | } |
| 216 | |
Steve Paik | 6648198 | 2015-10-27 15:22:38 -0700 | [diff] [blame] | 217 | public HvacHalService getHvacHal() { |
| 218 | return mHvacHal; |
| 219 | } |
| 220 | |
Keun-young Park | a28d7b2 | 2016-02-29 16:54:29 -0800 | [diff] [blame] | 221 | public InputHalService getInputHal() { |
| 222 | return mInputHal; |
| 223 | } |
| 224 | |
Pavel Maltsev | 634e1ff | 2016-07-14 15:41:26 -0700 | [diff] [blame] | 225 | public VendorExtensionHalService getVendorExtensionHal() { |
| 226 | return mVendorExtensionHal; |
| 227 | } |
| 228 | |
keunyoung | e4c90c4 | 2015-11-16 18:42:52 -0800 | [diff] [blame] | 229 | private void assertServiceOwnerLocked(HalServiceBase service, int property) { |
keunyoung | d32f4e6 | 2015-09-21 11:33:06 -0700 | [diff] [blame] | 230 | if (service != mPropertyHandlers.get(property)) { |
Pavel Maltsev | 1bfbaef | 2016-07-25 14:23:51 -0700 | [diff] [blame] | 231 | throw new IllegalArgumentException("Property 0x" + Integer.toHexString(property) |
| 232 | + " is not owned by service: " + service); |
keunyoung | fe30ba0 | 2015-09-17 17:56:35 -0700 | [diff] [blame] | 233 | } |
keunyoung | cc449f7 | 2015-08-12 10:46:27 -0700 | [diff] [blame] | 234 | } |
| 235 | |
keunyoung | fe30ba0 | 2015-09-17 17:56:35 -0700 | [diff] [blame] | 236 | /** |
| 237 | * Subscribe given property. Only Hal service owning the property can subscribe it. |
| 238 | * @param service |
| 239 | * @param property |
| 240 | * @param samplingRateHz |
| 241 | */ |
keunyoung | d32f4e6 | 2015-09-21 11:33:06 -0700 | [diff] [blame] | 242 | public void subscribeProperty(HalServiceBase service, int property, |
keunyoung | fe30ba0 | 2015-09-17 17:56:35 -0700 | [diff] [blame] | 243 | float samplingRateHz) throws IllegalArgumentException { |
Steve Paik | 4d6088c | 2016-07-20 20:27:55 -0700 | [diff] [blame] | 244 | VehiclePropConfig config; |
keunyoung | e4c90c4 | 2015-11-16 18:42:52 -0800 | [diff] [blame] | 245 | synchronized (this) { |
Steve Paik | 4d6088c | 2016-07-20 20:27:55 -0700 | [diff] [blame] | 246 | config = mAllProperties.get(property); |
keunyoung | e4c90c4 | 2015-11-16 18:42:52 -0800 | [diff] [blame] | 247 | } |
Steve Paik | 4d6088c | 2016-07-20 20:27:55 -0700 | [diff] [blame] | 248 | |
| 249 | if (config == null) { |
| 250 | throw new IllegalArgumentException("subscribe error: config is null for property " + |
| 251 | property); |
| 252 | } else if (isPropertySubscribable(config)) { |
| 253 | synchronized (this) { |
| 254 | assertServiceOwnerLocked(service, property); |
| 255 | mSubscribedProperties.add(property); |
| 256 | } |
| 257 | mVehicleNetwork.subscribe(property, samplingRateHz); |
| 258 | } else { |
| 259 | Log.e(CarLog.TAG_HAL, "Cannot subscribe to property: " + property); |
| 260 | } |
keunyoung | a3b28d8 | 2015-08-25 13:05:15 -0700 | [diff] [blame] | 261 | } |
| 262 | |
keunyoung | d32f4e6 | 2015-09-21 11:33:06 -0700 | [diff] [blame] | 263 | public void unsubscribeProperty(HalServiceBase service, int property) { |
Steve Paik | 4d6088c | 2016-07-20 20:27:55 -0700 | [diff] [blame] | 264 | VehiclePropConfig config; |
keunyoung | e4c90c4 | 2015-11-16 18:42:52 -0800 | [diff] [blame] | 265 | synchronized (this) { |
Steve Paik | 4d6088c | 2016-07-20 20:27:55 -0700 | [diff] [blame] | 266 | config = mAllProperties.get(property); |
keunyoung | e4c90c4 | 2015-11-16 18:42:52 -0800 | [diff] [blame] | 267 | } |
Steve Paik | 4d6088c | 2016-07-20 20:27:55 -0700 | [diff] [blame] | 268 | |
| 269 | if (config == null) { |
| 270 | Log.e(CarLog.TAG_HAL, "unsubscribeProperty: property " + property + " does not exist"); |
| 271 | } else if (isPropertySubscribable(config)) { |
| 272 | synchronized (this) { |
| 273 | assertServiceOwnerLocked(service, property); |
| 274 | mSubscribedProperties.remove(property); |
| 275 | } |
| 276 | mVehicleNetwork.unsubscribe(property); |
| 277 | } else { |
| 278 | Log.e(CarLog.TAG_HAL, "Cannot unsubscribe property: " + property); |
| 279 | } |
keunyoung | a3b28d8 | 2015-08-25 13:05:15 -0700 | [diff] [blame] | 280 | } |
| 281 | |
keunyoung | d32f4e6 | 2015-09-21 11:33:06 -0700 | [diff] [blame] | 282 | public VehicleNetwork getVehicleNetwork() { |
| 283 | return mVehicleNetwork; |
keunyoung | cc449f7 | 2015-08-12 10:46:27 -0700 | [diff] [blame] | 284 | } |
| 285 | |
keunyoung | a74b9ca | 2015-10-21 13:33:58 -0700 | [diff] [blame] | 286 | public static boolean isPropertySubscribable(VehiclePropConfig config) { |
Keun-young Park | 4c6834a | 2016-06-28 12:58:23 -0700 | [diff] [blame] | 287 | if ((config.getAccess() & VehiclePropAccess.VEHICLE_PROP_ACCESS_READ) == 0 || |
| 288 | (config.getChangeMode() == |
| 289 | VehiclePropChangeMode.VEHICLE_PROP_CHANGE_MODE_STATIC)) { |
keunyoung | a74b9ca | 2015-10-21 13:33:58 -0700 | [diff] [blame] | 290 | return false; |
| 291 | } |
| 292 | return true; |
| 293 | } |
| 294 | |
| 295 | public static void dumpProperties(PrintWriter writer, Collection<VehiclePropConfig> configs) { |
| 296 | for (VehiclePropConfig config : configs) { |
| 297 | writer.println("property " + |
| 298 | VehicleNetworkConsts.getVehiclePropertyName(config.getProp())); |
| 299 | } |
| 300 | } |
| 301 | |
keunyoung | fe30ba0 | 2015-09-17 17:56:35 -0700 | [diff] [blame] | 302 | private final ArraySet<HalServiceBase> mServicesToDispatch = new ArraySet<HalServiceBase>(); |
keunyoung | e4c90c4 | 2015-11-16 18:42:52 -0800 | [diff] [blame] | 303 | |
keunyoung | fe30ba0 | 2015-09-17 17:56:35 -0700 | [diff] [blame] | 304 | @Override |
| 305 | public void onVehicleNetworkEvents(VehiclePropValues values) { |
keunyoung | e4c90c4 | 2015-11-16 18:42:52 -0800 | [diff] [blame] | 306 | synchronized (this) { |
| 307 | for (VehiclePropValue v : values.getValuesList()) { |
| 308 | HalServiceBase service = mPropertyHandlers.get(v.getProp()); |
| 309 | service.getDispatchList().add(v); |
| 310 | mServicesToDispatch.add(service); |
Keun-young Park | 97e46eb | 2016-04-09 15:02:38 -0700 | [diff] [blame] | 311 | VehiclePropertyEventInfo info = mEventLog.get(v.getProp()); |
| 312 | if (info == null) { |
| 313 | info = new VehiclePropertyEventInfo(v); |
| 314 | mEventLog.put(v.getProp(), info); |
| 315 | } else { |
| 316 | info.addNewEvent(v); |
| 317 | } |
keunyoung | e4c90c4 | 2015-11-16 18:42:52 -0800 | [diff] [blame] | 318 | } |
keunyoung | cc449f7 | 2015-08-12 10:46:27 -0700 | [diff] [blame] | 319 | } |
keunyoung | fe30ba0 | 2015-09-17 17:56:35 -0700 | [diff] [blame] | 320 | for (HalServiceBase s : mServicesToDispatch) { |
| 321 | s.handleHalEvents(s.getDispatchList()); |
| 322 | s.getDispatchList().clear(); |
| 323 | } |
| 324 | mServicesToDispatch.clear(); |
keunyoung | cc449f7 | 2015-08-12 10:46:27 -0700 | [diff] [blame] | 325 | } |
| 326 | |
Keun-young Park | 28dd470 | 2015-11-19 18:06:04 -0800 | [diff] [blame] | 327 | @Override |
Pavel Maltsev | b0324b4 | 2016-09-27 21:00:41 -0700 | [diff] [blame] | 328 | public void onPropertySet(VehiclePropValue value) { |
| 329 | // No need to handle on-property-set events in HAL service yet. |
| 330 | } |
| 331 | |
| 332 | @Override |
Keun-young Park | 28dd470 | 2015-11-19 18:06:04 -0800 | [diff] [blame] | 333 | public void onHalError(int errorCode, int property, int operation) { |
| 334 | Log.e(CarLog.TAG_HAL, "onHalError, errorCode:" + errorCode + |
| 335 | " property:0x" + Integer.toHexString(property) + |
| 336 | " operation:" + operation); |
| 337 | // TODO propagate per property error to HAL services and handle global error |
| 338 | } |
| 339 | |
| 340 | @Override |
| 341 | public void onHalRestart(boolean inMocking) { |
| 342 | Log.e(CarLog.TAG_HAL, "onHalRestart, inMocking:" + inMocking); |
| 343 | // TODO restart things as other components started mocking. For now, ignore. |
| 344 | } |
| 345 | |
keunyoung | cc449f7 | 2015-08-12 10:46:27 -0700 | [diff] [blame] | 346 | public void dump(PrintWriter writer) { |
| 347 | writer.println("**dump HAL services**"); |
| 348 | for (HalServiceBase service: mAllServices) { |
| 349 | service.dump(writer); |
| 350 | } |
Steve Paik | 4d6088c | 2016-07-20 20:27:55 -0700 | [diff] [blame] | 351 | |
| 352 | List<VehiclePropConfig> configList; |
| 353 | synchronized (this) { |
| 354 | configList = new ArrayList<>(mAllProperties.values()); |
| 355 | } |
| 356 | |
Keun-young Park | 450faba | 2016-02-10 18:15:12 -0800 | [diff] [blame] | 357 | writer.println("**All properties**"); |
Steve Paik | 4d6088c | 2016-07-20 20:27:55 -0700 | [diff] [blame] | 358 | for (VehiclePropConfig config : configList) { |
Keun-young Park | 450faba | 2016-02-10 18:15:12 -0800 | [diff] [blame] | 359 | StringBuilder builder = new StringBuilder(); |
Pavel Maltsev | 437ab41 | 2016-08-15 15:41:06 -0700 | [diff] [blame] | 360 | builder.append("Property:0x").append(Integer.toHexString(config.getProp())); |
Keun-young Park | 97e46eb | 2016-04-09 15:02:38 -0700 | [diff] [blame] | 361 | builder.append(",access:0x" + Integer.toHexString(config.getAccess())); |
| 362 | builder.append(",changeMode:0x" + Integer.toHexString(config.getChangeMode())); |
| 363 | builder.append(",valueType:0x" + Integer.toHexString(config.getValueType())); |
| 364 | builder.append(",permission:0x" + Integer.toHexString(config.getPermissionModel())); |
| 365 | builder.append(",config:0x" + Integer.toHexString(config.getConfigArray(0))); |
Keun-young Park | 450faba | 2016-02-10 18:15:12 -0800 | [diff] [blame] | 366 | builder.append(",fs min:" + config.getSampleRateMin()); |
Pavel Maltsev | 437ab41 | 2016-08-15 15:41:06 -0700 | [diff] [blame] | 367 | builder.append(",fs max:").append(config.getSampleRateMax()); |
Keun-young Park | 71b2f5c | 2016-03-10 18:44:40 -0800 | [diff] [blame] | 368 | for (int i = 0; i < config.getFloatMaxsCount(); i++) { |
| 369 | builder.append(",v min:" + config.getFloatMins(i)); |
| 370 | builder.append(",v max:" + config.getFloatMaxs(i)); |
Keun-young Park | 450faba | 2016-02-10 18:15:12 -0800 | [diff] [blame] | 371 | } |
Keun-young Park | 71b2f5c | 2016-03-10 18:44:40 -0800 | [diff] [blame] | 372 | for (int i = 0; i < config.getInt32MaxsCount(); i++) { |
| 373 | builder.append(",v min:" + config.getInt32Mins(i)); |
| 374 | builder.append(",v max:" + config.getInt32Maxs(i)); |
Keun-young Park | 450faba | 2016-02-10 18:15:12 -0800 | [diff] [blame] | 375 | } |
Keun-young Park | 71b2f5c | 2016-03-10 18:44:40 -0800 | [diff] [blame] | 376 | for (int i = 0; i < config.getInt64MaxsCount(); i++) { |
| 377 | builder.append(",v min:" + config.getInt64Mins(i)); |
| 378 | builder.append(",v max:" + config.getInt64Maxs(i)); |
Keun-young Park | 450faba | 2016-02-10 18:15:12 -0800 | [diff] [blame] | 379 | } |
| 380 | writer.println(builder.toString()); |
| 381 | } |
Keun-young Park | 97e46eb | 2016-04-09 15:02:38 -0700 | [diff] [blame] | 382 | writer.println(String.format("**All Events, now ns:%d**", |
| 383 | SystemClock.elapsedRealtimeNanos())); |
| 384 | for (VehiclePropertyEventInfo info : mEventLog.values()) { |
| 385 | writer.println(String.format("event count:%d, lastEvent:%s", |
| 386 | info.eventCount, dumpVehiclePropValue(info.lastEvent))); |
| 387 | } |
Pavel Maltsev | 437ab41 | 2016-08-15 15:41:06 -0700 | [diff] [blame] | 388 | |
| 389 | writer.println("**Property handlers**"); |
| 390 | for (int i = 0; i < mPropertyHandlers.size(); i++) { |
| 391 | int propId = mPropertyHandlers.keyAt(i); |
| 392 | HalServiceBase service = mPropertyHandlers.valueAt(i); |
| 393 | writer.println(String.format("Prop: 0x%08X, service: %s", propId, service)); |
| 394 | } |
Keun-young Park | 97e46eb | 2016-04-09 15:02:38 -0700 | [diff] [blame] | 395 | } |
| 396 | |
| 397 | public static String dumpVehiclePropValue(VehiclePropValue value) { |
| 398 | StringBuilder sb = new StringBuilder(); |
| 399 | sb.append("Property:0x" + Integer.toHexString(value.getProp())); |
| 400 | sb.append(",timestamp:" + value.getTimestamp()); |
| 401 | sb.append(",value type:0x" + Integer.toHexString(value.getValueType())); |
| 402 | sb.append(",zone:0x" + Integer.toHexString(value.getZone())); |
| 403 | if (value.getInt32ValuesCount() > 0) { |
| 404 | sb.append(",int32 values:"); |
| 405 | for (int i = 0; i < value.getInt32ValuesCount(); i++) { |
| 406 | sb.append("," + value.getInt32Values(i)); |
| 407 | } |
| 408 | } |
| 409 | if (value.hasInt64Value()) { |
| 410 | sb.append(",int64 value:" + value.getInt64Value()); |
| 411 | } |
| 412 | if (value.getFloatValuesCount() > 0) { |
| 413 | sb.append(",float values:"); |
| 414 | for (int i = 0; i < value.getFloatValuesCount(); i++) { |
| 415 | sb.append("," + value.getFloatValues(i)); |
| 416 | } |
| 417 | } |
| 418 | if (value.hasStringValue()) { |
| 419 | sb.append(",string value:" + value.getStringValue()); |
| 420 | } |
| 421 | if (value.hasBytesValue()) { |
| 422 | sb.append(",bytes value:" + value.getBytesValue()); |
| 423 | } |
| 424 | return sb.toString(); |
| 425 | } |
| 426 | private static class VehiclePropertyEventInfo { |
| 427 | private int eventCount; |
| 428 | private VehiclePropValue lastEvent; |
| 429 | |
| 430 | private VehiclePropertyEventInfo(VehiclePropValue event) { |
| 431 | eventCount = 1; |
| 432 | lastEvent = event; |
| 433 | } |
| 434 | |
| 435 | private void addNewEvent(VehiclePropValue event) { |
| 436 | eventCount++; |
| 437 | lastEvent = event; |
| 438 | } |
keunyoung | cc449f7 | 2015-08-12 10:46:27 -0700 | [diff] [blame] | 439 | } |
| 440 | } |