Home | History | Annotate | Download | only in car
      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;
     18 
     19 import android.car.Car;
     20 import android.car.hardware.hvac.CarHvacEvent;
     21 import android.car.hardware.CarPropertyConfig;
     22 import android.car.hardware.CarPropertyValue;
     23 import android.car.hardware.hvac.ICarHvac;
     24 import android.car.hardware.hvac.ICarHvacEventListener;
     25 import android.content.Context;
     26 import android.os.IBinder;
     27 import android.os.RemoteException;
     28 import android.util.Log;
     29 
     30 import com.android.car.hal.HvacHalService;
     31 import com.android.car.hal.VehicleHal;
     32 
     33 import java.io.PrintWriter;
     34 import java.util.HashMap;
     35 import java.util.List;
     36 import java.util.Map;
     37 
     38 public class CarHvacService extends ICarHvac.Stub
     39         implements CarServiceBase, HvacHalService.HvacHalListener {
     40     public static final boolean DBG = true;
     41     public static final String  TAG = CarLog.TAG_HVAC + ".CarHvacService";
     42 
     43     private HvacHalService mHvacHal;
     44     private final Map<IBinder, ICarHvacEventListener> mListenersMap = new HashMap<>();
     45     private final Map<IBinder, HvacDeathRecipient> mDeathRecipientMap = new HashMap<>();
     46     private final Context mContext;
     47 
     48     public CarHvacService(Context context) {
     49         mHvacHal = VehicleHal.getInstance().getHvacHal();
     50         mContext = context;
     51     }
     52 
     53     class HvacDeathRecipient implements IBinder.DeathRecipient {
     54         private static final String TAG = CarHvacService.TAG + ".HvacDeathRecipient";
     55         private IBinder mListenerBinder;
     56 
     57         HvacDeathRecipient(IBinder listenerBinder) {
     58             mListenerBinder = listenerBinder;
     59         }
     60 
     61         /**
     62          * Client died. Remove the listener from HAL service and unregister if this is the last
     63          * client.
     64          */
     65         @Override
     66         public void binderDied() {
     67             if (DBG) {
     68                 Log.d(TAG, "binderDied " + mListenerBinder);
     69             }
     70             CarHvacService.this.unregisterListenerLocked(mListenerBinder);
     71         }
     72 
     73         void release() {
     74             mListenerBinder.unlinkToDeath(this, 0);
     75         }
     76     }
     77 
     78     @Override
     79     public synchronized void init() {
     80     }
     81 
     82     @Override
     83     public synchronized void release() {
     84         for (HvacDeathRecipient recipient : mDeathRecipientMap.values()) {
     85             recipient.release();
     86         }
     87         mDeathRecipientMap.clear();
     88         mListenersMap.clear();
     89     }
     90 
     91     @Override
     92     public void dump(PrintWriter writer) {
     93         // TODO
     94     }
     95 
     96     @Override
     97     public synchronized void registerListener(ICarHvacEventListener listener) {
     98         if (DBG) {
     99             Log.d(TAG, "registerListener");
    100         }
    101         ICarImpl.assertHvacPermission(mContext);
    102         if (listener == null) {
    103             Log.e(TAG, "registerListener: Listener is null.");
    104             throw new IllegalArgumentException("listener cannot be null.");
    105         }
    106 
    107         IBinder listenerBinder = listener.asBinder();
    108         if (mListenersMap.containsKey(listenerBinder)) {
    109             // Already registered, nothing to do.
    110             return;
    111         }
    112 
    113         HvacDeathRecipient deathRecipient = new HvacDeathRecipient(listenerBinder);
    114         try {
    115             listenerBinder.linkToDeath(deathRecipient, 0);
    116         } catch (RemoteException e) {
    117             Log.e(TAG, "Failed to link death for recipient. " + e);
    118             throw new IllegalStateException(Car.CAR_NOT_CONNECTED_EXCEPTION_MSG);
    119         }
    120         mDeathRecipientMap.put(listenerBinder, deathRecipient);
    121 
    122         if (mListenersMap.isEmpty()) {
    123             mHvacHal.setListener(this);
    124         }
    125 
    126         mListenersMap.put(listenerBinder, listener);
    127     }
    128 
    129     @Override
    130     public synchronized void unregisterListener(ICarHvacEventListener listener) {
    131         if (DBG) {
    132             Log.d(TAG, "unregisterListener");
    133         }
    134         ICarImpl.assertHvacPermission(mContext);
    135         if (listener == null) {
    136             Log.e(TAG, "unregisterListener: Listener is null.");
    137             throw new IllegalArgumentException("Listener is null");
    138         }
    139 
    140         IBinder listenerBinder = listener.asBinder();
    141         if (!mListenersMap.containsKey(listenerBinder)) {
    142             Log.e(TAG, "unregisterListener: Listener was not previously registered.");
    143         }
    144         unregisterListenerLocked(listenerBinder);
    145     }
    146 
    147     // Removes the listenerBinder from the current state.
    148     // The function assumes that the binder will exist both in listeners and death recipients list.
    149     private void unregisterListenerLocked(IBinder listenerBinder) {
    150         Object status = mListenersMap.remove(listenerBinder);
    151 
    152         if (status != null) {
    153             mDeathRecipientMap.get(listenerBinder).release();
    154             mDeathRecipientMap.remove(listenerBinder);
    155         }
    156 
    157         if (mListenersMap.isEmpty()) {
    158             mHvacHal.setListener(null);
    159         }
    160     }
    161 
    162     @Override
    163     public synchronized List<CarPropertyConfig> getHvacProperties() {
    164         ICarImpl.assertHvacPermission(mContext);
    165         return mHvacHal.getHvacProperties();
    166     }
    167 
    168     @Override
    169     public synchronized CarPropertyValue getProperty(int prop, int zone) {
    170         ICarImpl.assertHvacPermission(mContext);
    171         return mHvacHal.getHvacProperty(prop, zone);
    172     }
    173 
    174     @Override
    175     public synchronized void setProperty(CarPropertyValue prop) {
    176         ICarImpl.assertHvacPermission(mContext);
    177         mHvacHal.setHvacProperty(prop);
    178     }
    179 
    180     // Implement HvacHalListener interface
    181     @Override
    182     public synchronized void onPropertyChange(CarHvacEvent event) {
    183         for (ICarHvacEventListener l : mListenersMap.values()) {
    184             try {
    185                 l.onEvent(event);
    186             } catch (RemoteException ex) {
    187                 // If we could not send a record, its likely the connection snapped. Let the binder
    188                 // death handle the situation.
    189                 Log.e(TAG, "onEvent calling failed: " + ex);
    190             }
    191         }
    192     }
    193 
    194     @Override
    195     public synchronized void onError(int zone, int property) {
    196         // TODO:
    197     }
    198 }
    199