Home | History | Annotate | Download | only in test
      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 
     17 package com.android.car.vehiclehal.test;
     18 
     19 import static java.lang.Integer.toHexString;
     20 import static junit.framework.Assert.assertEquals;
     21 import static junit.framework.Assert.assertNotNull;
     22 import static junit.framework.Assert.fail;
     23 
     24 import android.hardware.automotive.vehicle.V2_0.IVehicle;
     25 import android.hardware.automotive.vehicle.V2_0.IVehicleCallback;
     26 import android.hardware.automotive.vehicle.V2_0.StatusCode;
     27 import android.hardware.automotive.vehicle.V2_0.SubscribeOptions;
     28 import android.hardware.automotive.vehicle.V2_0.VehiclePropConfig;
     29 import android.hardware.automotive.vehicle.V2_0.VehiclePropValue;
     30 import android.hardware.automotive.vehicle.V2_0.VehiclePropertyAccess;
     31 import android.os.RemoteException;
     32 import android.os.SystemClock;
     33 
     34 import com.google.android.collect.Lists;
     35 
     36 import java.util.ArrayList;
     37 import java.util.HashMap;
     38 import java.util.List;
     39 import java.util.Map;
     40 
     41 /**
     42  * Mocked implementation of {@link IVehicle}.
     43  */
     44 public class MockedVehicleHal extends IVehicle.Stub {
     45     /**
     46      * Interface for handler of each property.
     47      */
     48     public interface VehicleHalPropertyHandler {
     49         default void onPropertySet(VehiclePropValue value) {}
     50         default VehiclePropValue onPropertyGet(VehiclePropValue value) { return null; }
     51         default void onPropertySubscribe(int property, int zones, float sampleRate) {}
     52         default void onPropertyUnsubscribe(int property) {}
     53 
     54         VehicleHalPropertyHandler NOP = new VehicleHalPropertyHandler() {};
     55     }
     56 
     57     private final Map<Integer, VehicleHalPropertyHandler> mPropertyHandlerMap = new HashMap<>();
     58     private final Map<Integer, VehiclePropConfig> mConfigs = new HashMap<>();
     59     private final Map<Integer, List<IVehicleCallback>> mSubscribers = new HashMap<>();
     60 
     61     public synchronized void addProperties(VehiclePropConfig... configs) {
     62         for (VehiclePropConfig config : configs) {
     63             addProperty(config, new DefaultPropertyHandler(config, null));
     64         }
     65     }
     66 
     67     public synchronized void addProperty(VehiclePropConfig config,
     68             VehicleHalPropertyHandler handler) {
     69         mPropertyHandlerMap.put(config.prop, handler);
     70         mConfigs.put(config.prop, config);
     71     }
     72 
     73     public synchronized void addStaticProperty(VehiclePropConfig config,
     74             VehiclePropValue value) {
     75         addProperty(config, new StaticPropertyHandler(value));
     76     }
     77 
     78     public boolean waitForSubscriber(int propId, long timeoutMillis) {
     79         long startTime = SystemClock.elapsedRealtime();
     80         try {
     81             synchronized (this) {
     82                 while (mSubscribers.get(propId) == null) {
     83                     long waitMillis = startTime - SystemClock.elapsedRealtime() + timeoutMillis;
     84                     if (waitMillis < 0) break;
     85                     wait(waitMillis);
     86                 }
     87 
     88                 return mSubscribers.get(propId) != null;
     89             }
     90         } catch (InterruptedException e) {
     91             return false;
     92         }
     93     }
     94 
     95     public synchronized void injectEvent(VehiclePropValue value) {
     96         List<IVehicleCallback> callbacks = mSubscribers.get(value.prop);
     97         assertNotNull("Injecting event failed for property: " + value.prop
     98                         + ". No listeners found", callbacks);
     99         for (IVehicleCallback callback : callbacks) {
    100             try {
    101                 callback.onPropertyEvent(Lists.newArrayList(value));
    102             } catch (RemoteException e) {
    103                 e.printStackTrace();
    104                 fail("Remote exception while injecting events.");
    105             }
    106         }
    107     }
    108 
    109     public synchronized void injectError(int errorCode, int propertyId, int areaId) {
    110         List<IVehicleCallback> callbacks = mSubscribers.get(propertyId);
    111         assertNotNull("Injecting error failed for property: " + propertyId
    112                         + ". No listeners found", callbacks);
    113         for (IVehicleCallback callback : callbacks) {
    114             try {
    115                 callback.onPropertySetError(errorCode, propertyId, areaId);
    116             } catch (RemoteException e) {
    117                 e.printStackTrace();
    118                 fail("Remote exception while injecting errors.");
    119             }
    120         }
    121     }
    122 
    123     @Override
    124     public synchronized ArrayList<VehiclePropConfig> getAllPropConfigs() {
    125         return new ArrayList<>(mConfigs.values());
    126     }
    127 
    128     @Override
    129     public synchronized void getPropConfigs(ArrayList<Integer> props, getPropConfigsCallback cb) {
    130         ArrayList<VehiclePropConfig> res = new ArrayList<>();
    131         for (Integer prop : props) {
    132             VehiclePropConfig config = mConfigs.get(prop);
    133             if (config == null) {
    134                 cb.onValues(StatusCode.INVALID_ARG, new ArrayList<>());
    135                 return;
    136             }
    137             res.add(config);
    138         }
    139         cb.onValues(StatusCode.OK, res);
    140     }
    141 
    142     @Override
    143     public synchronized void get(VehiclePropValue requestedPropValue, getCallback cb) {
    144         VehicleHalPropertyHandler handler = mPropertyHandlerMap.get(requestedPropValue.prop);
    145         if (handler == null) {
    146             cb.onValues(StatusCode.INVALID_ARG, null);
    147         } else {
    148             cb.onValues(StatusCode.OK, handler.onPropertyGet(requestedPropValue));
    149         }
    150     }
    151 
    152     @Override
    153     public synchronized int set(VehiclePropValue propValue) {
    154         VehicleHalPropertyHandler handler = mPropertyHandlerMap.get(propValue.prop);
    155         if (handler == null) {
    156             return StatusCode.INVALID_ARG;
    157         } else {
    158             handler.onPropertySet(propValue);
    159             return StatusCode.OK;
    160         }
    161     }
    162 
    163     @Override
    164     public synchronized int subscribe(IVehicleCallback callback,
    165             ArrayList<SubscribeOptions> options) {
    166         for (SubscribeOptions opt : options) {
    167             VehicleHalPropertyHandler handler = mPropertyHandlerMap.get(opt.propId);
    168             if (handler == null) {
    169                 return StatusCode.INVALID_ARG;
    170             }
    171 
    172             handler.onPropertySubscribe(opt.propId, opt.vehicleAreas, opt.sampleRate);
    173             List<IVehicleCallback>  subscribers = mSubscribers.get(opt.propId);
    174             if (subscribers == null) {
    175                 subscribers = new ArrayList<>();
    176                 mSubscribers.put(opt.propId, subscribers);
    177                 notifyAll();
    178             }
    179             subscribers.add(callback);
    180         }
    181         return StatusCode.OK;
    182     }
    183 
    184     @Override
    185     public synchronized int unsubscribe(IVehicleCallback callback, int propId) {
    186         VehicleHalPropertyHandler handler = mPropertyHandlerMap.get(propId);
    187         if (handler == null) {
    188             return StatusCode.INVALID_ARG;
    189         }
    190 
    191         handler.onPropertyUnsubscribe(propId);
    192         List<IVehicleCallback>  subscribers = mSubscribers.get(propId);
    193         if (subscribers != null) {
    194             subscribers.remove(callback);
    195             if (subscribers.size() == 0) {
    196                 mSubscribers.remove(propId);
    197             }
    198         }
    199         return StatusCode.OK;
    200     }
    201 
    202     @Override
    203     public String debugDump() {
    204         return null;
    205     }
    206 
    207     public static class FailingPropertyHandler implements VehicleHalPropertyHandler {
    208         @Override
    209         public void onPropertySet(VehiclePropValue value) {
    210             fail("Unexpected onPropertySet call");
    211         }
    212 
    213         @Override
    214         public VehiclePropValue onPropertyGet(VehiclePropValue value) {
    215             fail("Unexpected onPropertyGet call");
    216             return null;
    217         }
    218 
    219         @Override
    220         public void onPropertySubscribe(int property, int zones, float sampleRate) {
    221             fail("Unexpected onPropertySubscribe call");
    222         }
    223 
    224         @Override
    225         public void onPropertyUnsubscribe(int property) {
    226             fail("Unexpected onPropertyUnsubscribe call");
    227         }
    228     }
    229 
    230     public static class StaticPropertyHandler extends FailingPropertyHandler {
    231         private final VehiclePropValue mValue;
    232 
    233         public StaticPropertyHandler(VehiclePropValue value) {
    234             mValue = value;
    235         }
    236 
    237         @Override
    238         public synchronized VehiclePropValue onPropertyGet(VehiclePropValue value) {
    239             return mValue;
    240         }
    241     }
    242 
    243     public static class DefaultPropertyHandler implements VehicleHalPropertyHandler {
    244         private final VehiclePropConfig mConfig;
    245         private VehiclePropValue mValue;
    246         private boolean mSubscribed = false;
    247 
    248         public DefaultPropertyHandler(VehiclePropConfig config, VehiclePropValue initialValue) {
    249             mConfig = config;
    250             mValue = initialValue;
    251         }
    252 
    253         @Override
    254         public synchronized void onPropertySet(VehiclePropValue value) {
    255             assertEquals(mConfig.prop, value.prop);
    256             assertEquals(VehiclePropertyAccess.WRITE, mConfig.access & VehiclePropertyAccess.WRITE);
    257             mValue = value;
    258         }
    259 
    260         @Override
    261         public synchronized VehiclePropValue onPropertyGet(VehiclePropValue value) {
    262             assertEquals(mConfig.prop, value.prop);
    263             assertEquals(VehiclePropertyAccess.READ, mConfig.access & VehiclePropertyAccess.READ);
    264             return mValue;
    265         }
    266 
    267         @Override
    268         public synchronized void onPropertySubscribe(int property, int zones, float sampleRate) {
    269             assertEquals(mConfig.prop, property);
    270             mSubscribed = true;
    271         }
    272 
    273         @Override
    274         public synchronized void onPropertyUnsubscribe(int property) {
    275             assertEquals(mConfig.prop, property);
    276             if (!mSubscribed) {
    277                 throw new IllegalArgumentException("Property was not subscribed 0x"
    278                         + toHexString( property));
    279             }
    280             mSubscribed = false;
    281         }
    282     }
    283 }
    284