1 /* 2 * Copyright (C) 2021 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 static android.car.evs.CarEvsManager.SERVICE_TYPE_REARVIEW; 20 import static android.car.evs.CarEvsManager.SERVICE_TYPE_SURROUNDVIEW; 21 import static android.hardware.automotive.vehicle.VehicleProperty.CAMERA_SERVICE_CURRENT_STATE; 22 import static android.hardware.automotive.vehicle.VehicleProperty.EVS_SERVICE_REQUEST; 23 24 import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.DUMP_INFO; 25 26 import android.car.builtin.util.Slogf; 27 import android.car.evs.CarEvsManager.CarEvsServiceState; 28 import android.car.evs.CarEvsManager.CarEvsServiceType; 29 import android.hardware.automotive.vehicle.EvsServiceRequestIndex; 30 import android.hardware.automotive.vehicle.EvsServiceState; 31 import android.hardware.automotive.vehicle.EvsServiceType; 32 import android.os.ServiceSpecificException; 33 import android.util.Log; 34 import android.util.SparseArray; 35 36 import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport; 37 import com.android.internal.annotations.GuardedBy; 38 39 import java.io.PrintWriter; 40 import java.util.Collection; 41 import java.util.List; 42 43 /* 44 * Translates HAL events, CarEvsService is interested in, into the higher-level semantic 45 * information. 46 */ 47 public class EvsHalService extends HalServiceBase { 48 49 private static final String TAG = EvsHalService.class.getSimpleName(); 50 private static final boolean DBG = Slogf.isLoggable(TAG, Log.DEBUG); 51 52 private static final int[] SUPPORTED_PROPERTIES = new int[] { 53 CAMERA_SERVICE_CURRENT_STATE, 54 EVS_SERVICE_REQUEST, 55 }; 56 57 private final Object mLock = new Object(); 58 59 @GuardedBy("mLock") 60 private final SparseArray<HalPropConfig> mProperties = new SparseArray(); 61 62 private final VehicleHal mHal; 63 private final HalPropValueBuilder mPropValueBuilder; 64 65 @GuardedBy("mLock") 66 private EvsHalEventListener mListener; 67 68 private boolean mIsEvsServiceRequestSupported; 69 private boolean mIsCameraServiceCurrentStateSupported; 70 EvsHalService(VehicleHal hal)71 public EvsHalService(VehicleHal hal) { 72 mHal = hal; 73 mPropValueBuilder = hal.getHalPropValueBuilder(); 74 } 75 76 /** 77 * Interface to be implemented by any client that wants to get notified upon a new EVS service 78 * request. 79 */ 80 public interface EvsHalEventListener { 81 /** Called when a value of monitoring VHAL property gets changed */ onEvent(@arEvsServiceType int id, boolean on)82 void onEvent(@CarEvsServiceType int id, boolean on); 83 } 84 85 /** 86 * Sets the event listener to receive Vehicle's EVS-related events. 87 * 88 * @param listener {@link EvsHalEventListener} 89 * @throws IllegalStateException if none of required VHAL properties are not supported 90 * on this device. 91 */ setListener(EvsHalEventListener listener)92 public void setListener(EvsHalEventListener listener) { 93 if (!mIsEvsServiceRequestSupported) { 94 throw new IllegalStateException( 95 "Any of required VHAL properties are not supported."); 96 } 97 98 synchronized (mLock) { 99 mListener = listener; 100 } 101 102 mHal.subscribePropertySafe(this, EVS_SERVICE_REQUEST); 103 } 104 105 /** Returns whether {@code EVS_SERVICE_REQUEST} is supported */ isEvsServiceRequestSupported()106 public boolean isEvsServiceRequestSupported() { 107 return mIsEvsServiceRequestSupported; 108 } 109 110 /** Returns whether {@code CAMERA_SERVICE_CURRENT_STATE} is supported */ isCameraServiceCurrentStateSupported()111 public boolean isCameraServiceCurrentStateSupported() { 112 return mIsCameraServiceCurrentStateSupported; 113 } 114 115 @Override init()116 public void init() { 117 synchronized (mLock) { 118 for (int i = 0; i < mProperties.size(); i++) { 119 HalPropConfig config = mProperties.valueAt(i); 120 if (VehicleHal.isPropertySubscribable(config)) { 121 mHal.subscribePropertySafe(this, config.getPropId()); 122 } 123 } 124 } 125 } 126 127 @Override release()128 public void release() { 129 synchronized (mLock) { 130 mListener = null; 131 mProperties.clear(); 132 } 133 } 134 135 @Override getAllSupportedProperties()136 public int[] getAllSupportedProperties() { 137 return SUPPORTED_PROPERTIES; 138 } 139 140 @Override takeProperties(Collection<HalPropConfig> configs)141 public void takeProperties(Collection<HalPropConfig> configs) { 142 if (configs.isEmpty()) { 143 return; 144 } 145 146 synchronized (mLock) { 147 for (HalPropConfig config : configs) { 148 mProperties.put(config.getPropId(), config); 149 } 150 151 mIsEvsServiceRequestSupported = mProperties.contains(EVS_SERVICE_REQUEST); 152 mIsCameraServiceCurrentStateSupported = 153 mProperties.contains(CAMERA_SERVICE_CURRENT_STATE); 154 } 155 } 156 157 @Override onHalEvents(List<HalPropValue> values)158 public void onHalEvents(List<HalPropValue> values) { 159 EvsHalEventListener listener; 160 synchronized (mLock) { 161 listener = mListener; 162 } 163 164 if (listener == null) { 165 Slogf.w(TAG, "EVS Hal event occurs while the listener is null."); 166 return; 167 } 168 169 dispatchHalEvents(values, listener); 170 } 171 172 /** 173 * Reports the current state of CarEvsService. 174 * 175 * @param state {@link android.car.evs.CarEvsManager.CarEvsServiceState} value that represents 176 * the current state of {@code CarEvsService}. 177 */ reportCurrentState(@arEvsServiceState int[] state)178 public void reportCurrentState(@CarEvsServiceState int[] state) { 179 HalPropValue currentStates = mPropValueBuilder.build(CAMERA_SERVICE_CURRENT_STATE, 180 /* areaId= */ 0, /* values= */ state); 181 182 try { 183 mHal.set(currentStates); 184 } catch (ServiceSpecificException | IllegalArgumentException e) { 185 Slogf.e(TAG, "Failed to set a hal property: %s, err: %s", currentStates, e); 186 } 187 } 188 dispatchHalEvents(List<HalPropValue> values, EvsHalEventListener listener)189 private void dispatchHalEvents(List<HalPropValue> values, EvsHalEventListener listener) { 190 for (int i = 0; i < values.size(); ++i) { 191 HalPropValue v = values.get(i); 192 boolean on = false; 193 @CarEvsServiceType int type; 194 switch (v.getPropId()) { 195 case EVS_SERVICE_REQUEST: 196 // Check 197 // android.hardware.automotive.vehicle.VehicleProperty.EVS_SERVICE_REQUEST 198 try { 199 int rawServiceType = v.getInt32Value(EvsServiceRequestIndex.TYPE); 200 type = rawServiceType == EvsServiceType.REARVIEW 201 ? SERVICE_TYPE_REARVIEW : SERVICE_TYPE_SURROUNDVIEW; 202 on = v.getInt32Value(EvsServiceRequestIndex.STATE) == EvsServiceState.ON; 203 if (DBG) { 204 Slogf.d(TAG, 205 "Received EVS_SERVICE_REQUEST: type = " + type + " on = " + on); 206 } 207 } catch (IndexOutOfBoundsException e) { 208 Slogf.e(TAG, "Received invalid EVS_SERVICE_REQUEST, missing type or state," 209 + " int32Values: " + v.dumpInt32Values()); 210 break; 211 } 212 listener.onEvent(type, on); 213 break; 214 215 case CAMERA_SERVICE_CURRENT_STATE: 216 // Nothing to do with this write-only property. 217 break; 218 219 default: 220 if (DBG) { 221 Slogf.d(TAG, "Received unknown property change: " + v); 222 } 223 break; 224 } 225 } 226 } 227 228 @Override 229 @ExcludeFromCodeCoverageGeneratedReport(reason = DUMP_INFO) dump(PrintWriter writer)230 public void dump(PrintWriter writer) { 231 writer.println("*EVSHALSERVICE*"); 232 writer.printf("Use EVS_SERVICE_REQUEST: %b\n", isEvsServiceRequestSupported()); 233 writer.printf("Use CAMERA_SERVICE_CURRENT_STATE: %b\n", 234 isCameraServiceCurrentStateSupported()); 235 } 236 } 237