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 17package com.android.car.hal; 18 19import static com.android.car.CarServiceUtils.toByteArray; 20import static com.android.car.CarServiceUtils.toFloatArray; 21import static com.android.car.CarServiceUtils.toIntArray; 22import static java.lang.Integer.toHexString; 23 24import android.annotation.CheckResult; 25import android.car.annotation.FutureFeature; 26import android.hardware.automotive.vehicle.V2_0.IVehicle; 27import android.hardware.automotive.vehicle.V2_0.IVehicleCallback; 28import android.hardware.automotive.vehicle.V2_0.SubscribeFlags; 29import android.hardware.automotive.vehicle.V2_0.SubscribeOptions; 30import android.hardware.automotive.vehicle.V2_0.VehicleAreaConfig; 31import android.hardware.automotive.vehicle.V2_0.VehiclePropConfig; 32import android.hardware.automotive.vehicle.V2_0.VehiclePropValue; 33import android.hardware.automotive.vehicle.V2_0.VehicleProperty; 34import android.hardware.automotive.vehicle.V2_0.VehiclePropertyAccess; 35import android.hardware.automotive.vehicle.V2_0.VehiclePropertyChangeMode; 36import android.os.HandlerThread; 37import android.os.RemoteException; 38import android.os.SystemClock; 39import android.util.ArraySet; 40import android.util.Log; 41import android.util.SparseArray; 42 43import com.google.android.collect.Lists; 44 45import com.android.car.CarLog; 46import com.android.car.internal.FeatureConfiguration; 47import com.android.internal.annotations.VisibleForTesting; 48 49import java.io.PrintWriter; 50import java.lang.ref.WeakReference; 51import java.util.ArrayList; 52import java.util.Arrays; 53import java.util.Collection; 54import java.util.HashMap; 55import java.util.HashSet; 56import java.util.List; 57import java.util.Set; 58 59/** 60 * Abstraction for vehicle HAL. This class handles interface with native HAL and do basic parsing 61 * of received data (type check). Then each event is sent to corresponding {@link HalServiceBase} 62 * implementation. It is responsibility of {@link HalServiceBase} to convert data to corresponding 63 * Car*Service for Car*Manager API. 64 */ 65public class VehicleHal extends IVehicleCallback.Stub { 66 67 private static final boolean DBG = false; 68 69 private static final int NO_AREA = -1; 70 71 private final HandlerThread mHandlerThread; 72 private final SensorHalService mSensorHal; 73 private final InfoHalService mInfoHal; 74 private final AudioHalService mAudioHal; 75 private final CabinHalService mCabinHal; 76 private final RadioHalService mRadioHal; 77 private final PowerHalService mPowerHal; 78 private final HvacHalService mHvacHal; 79 private final InputHalService mInputHal; 80 private final VendorExtensionHalService mVendorExtensionHal; 81 @FutureFeature 82 private VmsHalService mVmsHal; 83 84 @FutureFeature 85 private DiagnosticHalService mDiagnosticHal = null; 86 87 /** Might be re-assigned if Vehicle HAL is reconnected. */ 88 private volatile HalClient mHalClient; 89 90 /** Stores handler for each HAL property. Property events are sent to handler. */ 91 private final SparseArray<HalServiceBase> mPropertyHandlers = new SparseArray<>(); 92 /** This is for iterating all HalServices with fixed order. */ 93 private final ArrayList<HalServiceBase> mAllServices = new ArrayList<>(); 94 private final HashMap<Integer, SubscribeOptions> mSubscribedProperties = new HashMap<>(); 95 private final HashMap<Integer, VehiclePropConfig> mAllProperties = new HashMap<>(); 96 private final HashMap<Integer, VehiclePropertyEventInfo> mEventLog = new HashMap<>(); 97 98 public VehicleHal(IVehicle vehicle) { 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 mCabinHal = new CabinHalService(this); 107 mRadioHal = new RadioHalService(this); 108 mHvacHal = new HvacHalService(this); 109 mInputHal = new InputHalService(this); 110 mVendorExtensionHal = new VendorExtensionHalService(this); 111 if (FeatureConfiguration.ENABLE_VEHICLE_MAP_SERVICE) { 112 mVmsHal = new VmsHalService(this); 113 } 114 if(FeatureConfiguration.ENABLE_DIAGNOSTIC) { 115 mDiagnosticHal = new DiagnosticHalService(this); 116 } 117 mAllServices.addAll(Arrays.asList(mPowerHal, 118 mSensorHal, 119 mInfoHal, 120 mAudioHal, 121 mCabinHal, 122 mRadioHal, 123 mHvacHal, 124 mInputHal, 125 mVendorExtensionHal)); 126 if (FeatureConfiguration.ENABLE_VEHICLE_MAP_SERVICE) { 127 mAllServices.add(mVmsHal); 128 } 129 if(FeatureConfiguration.ENABLE_DIAGNOSTIC) { 130 mAllServices.add(mDiagnosticHal); 131 } 132 133 mHalClient = new HalClient(vehicle, mHandlerThread.getLooper(), this /*IVehicleCallback*/); 134 } 135 136 /** Dummy version only for testing */ 137 @VisibleForTesting 138 public VehicleHal(PowerHalService powerHal, SensorHalService sensorHal, InfoHalService infoHal, 139 AudioHalService audioHal, CabinHalService cabinHal, 140 RadioHalService radioHal, HvacHalService hvacHal, HalClient halClient) { 141 mHandlerThread = null; 142 mPowerHal = powerHal; 143 mSensorHal = sensorHal; 144 mInfoHal = infoHal; 145 mAudioHal = audioHal; 146 mCabinHal = cabinHal; 147 mRadioHal = radioHal; 148 mHvacHal = hvacHal; 149 mInputHal = null; 150 mVendorExtensionHal = null; 151 152 if (FeatureConfiguration.ENABLE_VEHICLE_MAP_SERVICE) { 153 // TODO(antoniocortes): do we need a test version of VmsHalService? 154 mVmsHal = null; 155 } 156 if(FeatureConfiguration.ENABLE_DIAGNOSTIC) { 157 mDiagnosticHal = null; 158 } 159 160 mHalClient = halClient; 161 } 162 163 /** Dummy version only for testing */ 164 @VisibleForTesting 165 @FutureFeature 166 public VehicleHal(PowerHalService powerHal, SensorHalService sensorHal, InfoHalService infoHal, 167 AudioHalService audioHal, CabinHalService cabinHal, DiagnosticHalService diagnosticHal, 168 RadioHalService radioHal, HvacHalService hvacHal, HalClient halClient) { 169 mHandlerThread = null; 170 mPowerHal = powerHal; 171 mSensorHal = sensorHal; 172 mInfoHal = infoHal; 173 mAudioHal = audioHal; 174 mCabinHal = cabinHal; 175 mDiagnosticHal = diagnosticHal; 176 mRadioHal = radioHal; 177 mHvacHal = hvacHal; 178 mInputHal = null; 179 mVendorExtensionHal = null; 180 // TODO(antoniocortes): do we need a test version of VmsHalService? 181 mVmsHal = null; 182 mHalClient = halClient; 183 mDiagnosticHal = diagnosticHal; 184 } 185 186 public void vehicleHalReconnected(IVehicle vehicle) { 187 synchronized (this) { 188 mHalClient = new HalClient(vehicle, mHandlerThread.getLooper(), 189 this /*IVehicleCallback*/); 190 191 SubscribeOptions[] options = mSubscribedProperties.values() 192 .toArray(new SubscribeOptions[0]); 193 194 try { 195 mHalClient.subscribe(options); 196 } catch (RemoteException e) { 197 throw new RuntimeException("Failed to subscribe: " + Arrays.asList(options), e); 198 } 199 } 200 } 201 202 public void init() { 203 Set<VehiclePropConfig> properties; 204 try { 205 properties = new HashSet<>(mHalClient.getAllPropConfigs()); 206 } catch (RemoteException e) { 207 throw new RuntimeException("Unable to retrieve vehicle property configuration", e); 208 } 209 210 synchronized (this) { 211 // Create map of all properties 212 for (VehiclePropConfig p : properties) { 213 mAllProperties.put(p.prop, p); 214 } 215 } 216 217 for (HalServiceBase service: mAllServices) { 218 Collection<VehiclePropConfig> taken = service.takeSupportedProperties(properties); 219 if (taken == null) { 220 continue; 221 } 222 if (DBG) { 223 Log.i(CarLog.TAG_HAL, "HalService " + service + " take properties " + taken.size()); 224 } 225 synchronized (this) { 226 for (VehiclePropConfig p: taken) { 227 mPropertyHandlers.append(p.prop, service); 228 } 229 } 230 properties.removeAll(taken); 231 service.init(); 232 } 233 } 234 235 public void release() { 236 // release in reverse order from init 237 for (int i = mAllServices.size() - 1; i >= 0; i--) { 238 mAllServices.get(i).release(); 239 } 240 synchronized (this) { 241 for (int p : mSubscribedProperties.keySet()) { 242 try { 243 mHalClient.unsubscribe(p); 244 } catch (RemoteException e) { 245 // Ignore exceptions on shutdown path. 246 Log.w(CarLog.TAG_HAL, "Failed to unsubscribe", e); 247 } 248 } 249 mSubscribedProperties.clear(); 250 mAllProperties.clear(); 251 } 252 // keep the looper thread as should be kept for the whole life cycle. 253 } 254 255 public SensorHalService getSensorHal() { 256 return mSensorHal; 257 } 258 259 public InfoHalService getInfoHal() { 260 return mInfoHal; 261 } 262 263 public AudioHalService getAudioHal() { 264 return mAudioHal; 265 } 266 267 public CabinHalService getCabinHal() { 268 return mCabinHal; 269 } 270 271 @FutureFeature 272 public DiagnosticHalService getDiagnosticHal() { return mDiagnosticHal; } 273 274 public RadioHalService getRadioHal() { 275 return mRadioHal; 276 } 277 278 public PowerHalService getPowerHal() { 279 return mPowerHal; 280 } 281 282 public HvacHalService getHvacHal() { 283 return mHvacHal; 284 } 285 286 public InputHalService getInputHal() { 287 return mInputHal; 288 } 289 290 public VendorExtensionHalService getVendorExtensionHal() { 291 return mVendorExtensionHal; 292 } 293 294 @FutureFeature 295 public VmsHalService getVmsHal() { return mVmsHal; } 296 297 private void assertServiceOwnerLocked(HalServiceBase service, int property) { 298 if (service != mPropertyHandlers.get(property)) { 299 throw new IllegalArgumentException("Property 0x" + toHexString(property) 300 + " is not owned by service: " + service); 301 } 302 } 303 304 /** 305 * Subscribes given properties with sampling rate defaults to 0 and no special flags provided. 306 * 307 * @see #subscribeProperty(HalServiceBase, int, float, int) 308 */ 309 public void subscribeProperty(HalServiceBase service, int property) 310 throws IllegalArgumentException { 311 subscribeProperty(service, property, 0f, SubscribeFlags.DEFAULT); 312 } 313 314 /** 315 * Subscribes given properties with default subscribe flag. 316 * 317 * @see #subscribeProperty(HalServiceBase, int, float, int) 318 */ 319 public void subscribeProperty(HalServiceBase service, int property, float sampleRateHz) 320 throws IllegalArgumentException { 321 subscribeProperty(service, property, sampleRateHz, SubscribeFlags.DEFAULT); 322 } 323 324 /** 325 * Subscribe given property. Only Hal service owning the property can subscribe it. 326 * 327 * @param service HalService that owns this property 328 * @param property property id (VehicleProperty) 329 * @param samplingRateHz sampling rate in Hz for continuous properties 330 * @param flags flags from {@link android.hardware.automotive.vehicle.V2_0.SubscribeFlags} 331 * @throws IllegalArgumentException thrown if property is not supported by VHAL 332 */ 333 public void subscribeProperty(HalServiceBase service, int property, 334 float samplingRateHz, int flags) throws IllegalArgumentException { 335 if (DBG) { 336 Log.i(CarLog.TAG_HAL, "subscribeProperty, service:" + service 337 + ", property: 0x" + toHexString(property)); 338 } 339 VehiclePropConfig config; 340 synchronized (this) { 341 config = mAllProperties.get(property); 342 } 343 344 if (config == null) { 345 throw new IllegalArgumentException("subscribe error: config is null for property 0x" + 346 toHexString(property)); 347 } else if (isPropertySubscribable(config)) { 348 SubscribeOptions opts = new SubscribeOptions(); 349 opts.propId = property; 350 opts.sampleRate = samplingRateHz; 351 opts.flags = flags; 352 synchronized (this) { 353 assertServiceOwnerLocked(service, property); 354 mSubscribedProperties.put(property, opts); 355 } 356 try { 357 mHalClient.subscribe(opts); 358 } catch (RemoteException e) { 359 Log.e(CarLog.TAG_HAL, "Failed to subscribe to property: 0x" + property, e); 360 } 361 } else { 362 Log.e(CarLog.TAG_HAL, "Cannot subscribe to property: " + property); 363 } 364 } 365 366 public void unsubscribeProperty(HalServiceBase service, int property) { 367 if (DBG) { 368 Log.i(CarLog.TAG_HAL, "unsubscribeProperty, service:" + service 369 + ", property: 0x" + toHexString(property)); 370 } 371 VehiclePropConfig config; 372 synchronized (this) { 373 config = mAllProperties.get(property); 374 } 375 376 if (config == null) { 377 Log.e(CarLog.TAG_HAL, "unsubscribeProperty: property " + property + " does not exist"); 378 } else if (isPropertySubscribable(config)) { 379 synchronized (this) { 380 assertServiceOwnerLocked(service, property); 381 mSubscribedProperties.remove(property); 382 } 383 try { 384 mHalClient.unsubscribe(property); 385 } catch (RemoteException e) { 386 Log.e(CarLog.TAG_SERVICE, "Failed to unsubscribe from property: 0x" 387 + toHexString(property), e); 388 } 389 } else { 390 Log.e(CarLog.TAG_HAL, "Cannot unsubscribe property: " + property); 391 } 392 } 393 394 public boolean isPropertySupported(int propertyId) { 395 return mAllProperties.containsKey(propertyId); 396 } 397 398 public Collection<VehiclePropConfig> getAllPropConfigs() { 399 return mAllProperties.values(); 400 } 401 402 public VehiclePropValue get(int propertyId) throws PropertyTimeoutException { 403 return get(propertyId, NO_AREA); 404 } 405 406 public VehiclePropValue get(int propertyId, int areaId) throws PropertyTimeoutException { 407 if (DBG) { 408 Log.i(CarLog.TAG_HAL, "get, property: 0x" + toHexString(propertyId) 409 + ", areaId: 0x" + toHexString(areaId)); 410 } 411 VehiclePropValue propValue = new VehiclePropValue(); 412 propValue.prop = propertyId; 413 propValue.areaId = areaId; 414 return mHalClient.getValue(propValue); 415 } 416 417 public <T> T get(Class clazz, int propertyId) throws PropertyTimeoutException { 418 return get(clazz, createPropValue(propertyId, NO_AREA)); 419 } 420 421 public <T> T get(Class clazz, int propertyId, int areaId) throws PropertyTimeoutException { 422 return get(clazz, createPropValue(propertyId, areaId)); 423 } 424 425 @SuppressWarnings("unchecked") 426 public <T> T get(Class clazz, VehiclePropValue requestedPropValue) 427 throws PropertyTimeoutException { 428 VehiclePropValue propValue; 429 propValue = mHalClient.getValue(requestedPropValue); 430 431 if (clazz == Integer.class || clazz == int.class) { 432 return (T) propValue.value.int32Values.get(0); 433 } else if (clazz == Boolean.class || clazz == boolean.class) { 434 return (T) Boolean.valueOf(propValue.value.int32Values.get(0) == 1); 435 } else if (clazz == Float.class || clazz == float.class) { 436 return (T) propValue.value.floatValues.get(0); 437 } else if (clazz == Integer[].class) { 438 Integer[] intArray = new Integer[propValue.value.int32Values.size()]; 439 return (T) propValue.value.int32Values.toArray(intArray); 440 } else if (clazz == Float[].class) { 441 Float[] floatArray = new Float[propValue.value.floatValues.size()]; 442 return (T) propValue.value.floatValues.toArray(floatArray); 443 } else if (clazz == int[].class) { 444 return (T) toIntArray(propValue.value.int32Values); 445 } else if (clazz == float[].class) { 446 return (T) toFloatArray(propValue.value.floatValues); 447 } else if (clazz == byte[].class) { 448 return (T) toByteArray(propValue.value.bytes); 449 } else if (clazz == String.class) { 450 return (T) propValue.value.stringValue; 451 } else { 452 throw new IllegalArgumentException("Unexpected type: " + clazz); 453 } 454 } 455 456 public VehiclePropValue get(VehiclePropValue requestedPropValue) 457 throws PropertyTimeoutException { 458 return mHalClient.getValue(requestedPropValue); 459 } 460 461 void set(VehiclePropValue propValue) throws PropertyTimeoutException { 462 mHalClient.setValue(propValue); 463 } 464 465 @CheckResult 466 VehiclePropValueSetter set(int propId) { 467 return new VehiclePropValueSetter(mHalClient, propId, NO_AREA); 468 } 469 470 @CheckResult 471 VehiclePropValueSetter set(int propId, int areaId) { 472 return new VehiclePropValueSetter(mHalClient, propId, areaId); 473 } 474 475 static boolean isPropertySubscribable(VehiclePropConfig config) { 476 if ((config.access & VehiclePropertyAccess.READ) == 0 || 477 (config.changeMode == VehiclePropertyChangeMode.STATIC)) { 478 return false; 479 } 480 return true; 481 } 482 483 static void dumpProperties(PrintWriter writer, Collection<VehiclePropConfig> configs) { 484 for (VehiclePropConfig config : configs) { 485 writer.println(String.format("property 0x%x", config.prop)); 486 } 487 } 488 489 private final ArraySet<HalServiceBase> mServicesToDispatch = new ArraySet<>(); 490 491 @Override 492 public void onPropertyEvent(ArrayList<VehiclePropValue> propValues) { 493 synchronized (this) { 494 for (VehiclePropValue v : propValues) { 495 HalServiceBase service = mPropertyHandlers.get(v.prop); 496 if(service == null) { 497 Log.e(CarLog.TAG_HAL, "HalService not found for prop: 0x" 498 + toHexString(v.prop)); 499 continue; 500 } 501 service.getDispatchList().add(v); 502 mServicesToDispatch.add(service); 503 VehiclePropertyEventInfo info = mEventLog.get(v.prop); 504 if (info == null) { 505 info = new VehiclePropertyEventInfo(v); 506 mEventLog.put(v.prop, info); 507 } else { 508 info.addNewEvent(v); 509 } 510 } 511 } 512 for (HalServiceBase s : mServicesToDispatch) { 513 s.handleHalEvents(s.getDispatchList()); 514 s.getDispatchList().clear(); 515 } 516 mServicesToDispatch.clear(); 517 } 518 519 @Override 520 public void onPropertySet(VehiclePropValue value) { 521 // No need to handle on-property-set events in HAL service yet. 522 } 523 524 @Override 525 public void onPropertySetError(int errorCode, int propId, int areaId) { 526 Log.e(CarLog.TAG_HAL, String.format("onPropertySetError, errorCode: %d, prop: 0x%x, " 527 + "area: 0x%x", errorCode, propId, areaId)); 528 if (propId != VehicleProperty.INVALID) { 529 HalServiceBase service = mPropertyHandlers.get(propId); 530 if (service != null) { 531 service.handlePropertySetError(propId, areaId); 532 } 533 } 534 } 535 536 public void dump(PrintWriter writer) { 537 writer.println("**dump HAL services**"); 538 for (HalServiceBase service: mAllServices) { 539 service.dump(writer); 540 } 541 542 List<VehiclePropConfig> configList; 543 synchronized (this) { 544 configList = new ArrayList<>(mAllProperties.values()); 545 } 546 547 writer.println("**All properties**"); 548 for (VehiclePropConfig config : configList) { 549 StringBuilder builder = new StringBuilder() 550 .append("Property:0x").append(toHexString(config.prop)) 551 .append(",access:0x").append(toHexString(config.access)) 552 .append(",changeMode:0x").append(toHexString(config.changeMode)) 553 .append(",areas:0x").append(toHexString(config.supportedAreas)) 554 .append(",config:0x").append(Arrays.toString(config.configArray.toArray())) 555 .append(",fs min:").append(config.minSampleRate) 556 .append(",fs max:").append(config.maxSampleRate); 557 for (VehicleAreaConfig area : config.areaConfigs) { 558 builder.append(",areaId :").append(toHexString(area.areaId)) 559 .append(",f min:").append(area.minFloatValue) 560 .append(",f max:").append(area.maxFloatValue) 561 .append(",i min:").append(area.minInt32Value) 562 .append(",i max:").append(area.maxInt32Value) 563 .append(",i64 min:").append(area.minInt64Value) 564 .append(",i64 max:").append(area.maxInt64Value); 565 } 566 writer.println(builder.toString()); 567 } 568 writer.println(String.format("**All Events, now ns:%d**", 569 SystemClock.elapsedRealtimeNanos())); 570 for (VehiclePropertyEventInfo info : mEventLog.values()) { 571 writer.println(String.format("event count:%d, lastEvent:%s", 572 info.eventCount, dumpVehiclePropValue(info.lastEvent))); 573 } 574 575 writer.println("**Property handlers**"); 576 for (int i = 0; i < mPropertyHandlers.size(); i++) { 577 int propId = mPropertyHandlers.keyAt(i); 578 HalServiceBase service = mPropertyHandlers.valueAt(i); 579 writer.println(String.format("Prop: 0x%08X, service: %s", propId, service)); 580 } 581 } 582 583 /** 584 * Inject a fake boolean HAL event - for testing purposes. 585 * @param propId - VehicleProperty ID 586 * @param areaId - Vehicle Area ID 587 * @param value - true/false to inject 588 */ 589 public void injectBooleanEvent(int propId, int areaId, boolean value) { 590 VehiclePropValue v = createPropValue(propId, areaId); 591 v.value.int32Values.add(value? 1 : 0); 592 onPropertyEvent(Lists.newArrayList(v)); 593 } 594 595 /** 596 * Inject a fake Integer HAL event - for testing purposes. 597 * @param propId - VehicleProperty ID 598 * @param value - Integer value to inject 599 */ 600 public void injectIntegerEvent(int propId, int value) { 601 VehiclePropValue v = createPropValue(propId, 0); 602 v.value.int32Values.add(value); 603 v.timestamp = SystemClock.elapsedRealtimeNanos(); 604 onPropertyEvent(Lists.newArrayList(v)); 605 } 606 607 private static class VehiclePropertyEventInfo { 608 private int eventCount; 609 private VehiclePropValue lastEvent; 610 611 private VehiclePropertyEventInfo(VehiclePropValue event) { 612 eventCount = 1; 613 lastEvent = event; 614 } 615 616 private void addNewEvent(VehiclePropValue event) { 617 eventCount++; 618 lastEvent = event; 619 } 620 } 621 622 final class VehiclePropValueSetter { 623 final WeakReference<HalClient> mClient; 624 final VehiclePropValue mPropValue; 625 626 private VehiclePropValueSetter(HalClient client, int propId, int areaId) { 627 mClient = new WeakReference<>(client); 628 mPropValue = new VehiclePropValue(); 629 mPropValue.prop = propId; 630 mPropValue.areaId = areaId; 631 } 632 633 void to(boolean value) throws PropertyTimeoutException { 634 to(value ? 1 : 0); 635 } 636 637 void to(int value) throws PropertyTimeoutException { 638 mPropValue.value.int32Values.add(value); 639 submit(); 640 } 641 642 void to(int[] values) throws PropertyTimeoutException { 643 for (int value : values) { 644 mPropValue.value.int32Values.add(value); 645 } 646 submit(); 647 } 648 649 void to(Collection<Integer> values) throws PropertyTimeoutException { 650 mPropValue.value.int32Values.addAll(values); 651 submit(); 652 } 653 654 void submit() throws PropertyTimeoutException { 655 HalClient client = mClient.get(); 656 if (client != null) { 657 if (DBG) { 658 Log.i(CarLog.TAG_HAL, "set, property: 0x" + toHexString(mPropValue.prop) 659 + ", areaId: 0x" + toHexString(mPropValue.areaId)); 660 } 661 client.setValue(mPropValue); 662 } 663 } 664 } 665 666 private static String dumpVehiclePropValue(VehiclePropValue value) { 667 final int MAX_BYTE_SIZE = 20; 668 669 StringBuilder sb = new StringBuilder() 670 .append("Property:0x").append(toHexString(value.prop)) 671 .append(",timestamp:").append(value.timestamp) 672 .append(",zone:0x").append(toHexString(value.areaId)) 673 .append(",floatValues: ").append(Arrays.toString(value.value.floatValues.toArray())) 674 .append(",int32Values: ").append(Arrays.toString(value.value.int32Values.toArray())) 675 .append(",int64Values: ") 676 .append(Arrays.toString(value.value.int64Values.toArray())); 677 678 if (value.value.bytes.size() > MAX_BYTE_SIZE) { 679 Object[] bytes = Arrays.copyOf(value.value.bytes.toArray(), MAX_BYTE_SIZE); 680 sb.append(",bytes: ").append(Arrays.toString(bytes)); 681 } else { 682 sb.append(",bytes: ").append(Arrays.toString(value.value.bytes.toArray())); 683 } 684 sb.append(",string: ").append(value.value.stringValue); 685 686 return sb.toString(); 687 } 688 689 private static VehiclePropValue createPropValue(int propId, int areaId) { 690 VehiclePropValue propValue = new VehiclePropValue(); 691 propValue.prop = propId; 692 propValue.areaId = areaId; 693 return propValue; 694 } 695} 696