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