Home | History | Annotate | Download | only in hal
      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 {
     54         createInstance();
     55     }
     56 
     57     private static VehicleHal sInstance;
     58 
     59     public static synchronized VehicleHal getInstance() {
     60         if (sInstance == null) {
     61             createInstance();
     62         }
     63         return sInstance;
     64     }
     65 
     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 
     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 
     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
    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 
    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 
    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 
    183     public void startMocking() {
    184         reinitHals();
    185     }
    186 
    187     public void stopMocking() {
    188         reinitHals();
    189     }
    190 
    191     private void reinitHals() {
    192         release();
    193         init();
    194     }
    195 
    196     public SensorHalService getSensorHal() {
    197         return mSensorHal;
    198     }
    199 
    200     public InfoHalService getInfoHal() {
    201         return mInfoHal;
    202     }
    203 
    204     public AudioHalService getAudioHal() {
    205         return mAudioHal;
    206     }
    207 
    208     public RadioHalService getRadioHal() {
    209         return mRadioHal;
    210     }
    211 
    212     public PowerHalService getPowerHal() {
    213         return mPowerHal;
    214     }
    215 
    216     public HvacHalService getHvacHal() {
    217         return mHvacHal;
    218     }
    219 
    220     public InputHalService getInputHal() {
    221         return mInputHal;
    222     }
    223 
    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      */
    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 
    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 
    253     public VehicleNetwork getVehicleNetwork() {
    254         return mVehicleNetwork;
    255     }
    256 
    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 
    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
    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
    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
    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 
    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