Home | History | Annotate | Download | only in aware
      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.server.wifi.aware;
     18 
     19 import android.annotation.NonNull;
     20 import android.hardware.wifi.V1_0.IWifiNanIface;
     21 import android.hardware.wifi.V1_0.IfaceType;
     22 import android.hardware.wifi.V1_0.WifiStatus;
     23 import android.hardware.wifi.V1_0.WifiStatusCode;
     24 import android.os.Handler;
     25 import android.os.RemoteException;
     26 import android.util.Log;
     27 
     28 import com.android.internal.annotations.VisibleForTesting;
     29 import com.android.server.wifi.HalDeviceManager;
     30 
     31 import java.io.FileDescriptor;
     32 import java.io.PrintWriter;
     33 
     34 /**
     35  * Manages the interface to Wi-Fi Aware HIDL (HAL).
     36  */
     37 public class WifiAwareNativeManager {
     38     private static final String TAG = "WifiAwareNativeManager";
     39     private static final boolean VDBG = false;
     40     /* package */ boolean mDbg = false;
     41 
     42     // to be used for synchronizing access to any of the WifiAwareNative objects
     43     private final Object mLock = new Object();
     44 
     45     private WifiAwareStateManager mWifiAwareStateManager;
     46     private HalDeviceManager mHalDeviceManager;
     47     private Handler mHandler;
     48     private WifiAwareNativeCallback mWifiAwareNativeCallback;
     49     private IWifiNanIface mWifiNanIface = null;
     50     private InterfaceDestroyedListener mInterfaceDestroyedListener;
     51     private InterfaceAvailableForRequestListener mInterfaceAvailableForRequestListener =
     52             new InterfaceAvailableForRequestListener();
     53     private int mReferenceCount = 0;
     54 
     55     WifiAwareNativeManager(WifiAwareStateManager awareStateManager,
     56             HalDeviceManager halDeviceManager,
     57             WifiAwareNativeCallback wifiAwareNativeCallback) {
     58         mWifiAwareStateManager = awareStateManager;
     59         mHalDeviceManager = halDeviceManager;
     60         mWifiAwareNativeCallback = wifiAwareNativeCallback;
     61     }
     62 
     63     /**
     64      * (HIDL) Cast the input to a 1.2 NAN interface (possibly resulting in a null).
     65      *
     66      * Separate function so can be mocked in unit tests.
     67      */
     68     public android.hardware.wifi.V1_2.IWifiNanIface mockableCastTo_1_2(IWifiNanIface iface) {
     69         return android.hardware.wifi.V1_2.IWifiNanIface.castFrom(iface);
     70     }
     71 
     72     /**
     73      * Initialize the class - intended for late initialization.
     74      *
     75      * @param handler Handler on which to execute interface available callbacks.
     76      */
     77     public void start(Handler handler) {
     78         mHandler = handler;
     79         mHalDeviceManager.initialize();
     80         mHalDeviceManager.registerStatusListener(
     81                 new HalDeviceManager.ManagerStatusListener() {
     82                     @Override
     83                     public void onStatusChanged() {
     84                         if (VDBG) Log.v(TAG, "onStatusChanged");
     85                         // only care about isStarted (Wi-Fi started) not isReady - since if not
     86                         // ready then Wi-Fi will also be down.
     87                         if (mHalDeviceManager.isStarted()) {
     88                             // 1. no problem registering duplicates - only one will be called
     89                             // 2. will be called immediately if available
     90                             mHalDeviceManager.registerInterfaceAvailableForRequestListener(
     91                                     IfaceType.NAN, mInterfaceAvailableForRequestListener, mHandler);
     92                         } else {
     93                             awareIsDown();
     94                         }
     95                     }
     96                 }, mHandler);
     97         if (mHalDeviceManager.isStarted()) {
     98             mHalDeviceManager.registerInterfaceAvailableForRequestListener(
     99                     IfaceType.NAN, mInterfaceAvailableForRequestListener, mHandler);
    100         }
    101     }
    102 
    103     /**
    104      * Returns the native HAL WifiNanIface through which commands to the NAN HAL are dispatched.
    105      * Return may be null if not initialized/available.
    106      */
    107     @VisibleForTesting
    108     public IWifiNanIface getWifiNanIface() {
    109         synchronized (mLock) {
    110             return mWifiNanIface;
    111         }
    112     }
    113 
    114     /**
    115      * Attempt to obtain the HAL NAN interface.
    116      */
    117     public void tryToGetAware() {
    118         synchronized (mLock) {
    119             if (mDbg) {
    120                 Log.d(TAG, "tryToGetAware: mWifiNanIface=" + mWifiNanIface + ", mReferenceCount="
    121                         + mReferenceCount);
    122             }
    123 
    124             if (mWifiNanIface != null) {
    125                 mReferenceCount++;
    126                 return;
    127             }
    128             if (mHalDeviceManager == null) {
    129                 Log.e(TAG, "tryToGetAware: mHalDeviceManager is null!?");
    130                 awareIsDown();
    131                 return;
    132             }
    133 
    134             mInterfaceDestroyedListener = new InterfaceDestroyedListener();
    135             IWifiNanIface iface = mHalDeviceManager.createNanIface(mInterfaceDestroyedListener,
    136                     mHandler);
    137             if (iface == null) {
    138                 Log.e(TAG, "Was not able to obtain an IWifiNanIface (even though enabled!?)");
    139                 awareIsDown();
    140             } else {
    141                 if (mDbg) Log.v(TAG, "Obtained an IWifiNanIface");
    142 
    143                 try {
    144                     android.hardware.wifi.V1_2.IWifiNanIface iface12 = mockableCastTo_1_2(iface);
    145                     WifiStatus status;
    146                     if (iface12 == null) {
    147                         mWifiAwareNativeCallback.mIsHal12OrLater = false;
    148                         status = iface.registerEventCallback(mWifiAwareNativeCallback);
    149                     } else {
    150                         mWifiAwareNativeCallback.mIsHal12OrLater = true;
    151                         status = iface12.registerEventCallback_1_2(mWifiAwareNativeCallback);
    152                     }
    153                     if (status.code != WifiStatusCode.SUCCESS) {
    154                         Log.e(TAG, "IWifiNanIface.registerEventCallback error: " + statusString(
    155                                 status));
    156                         mHalDeviceManager.removeIface(iface);
    157                         awareIsDown();
    158                         return;
    159                     }
    160                 } catch (RemoteException e) {
    161                     Log.e(TAG, "IWifiNanIface.registerEventCallback exception: " + e);
    162                     awareIsDown();
    163                     return;
    164                 }
    165                 mWifiNanIface = iface;
    166                 mReferenceCount = 1;
    167             }
    168         }
    169     }
    170 
    171     /**
    172      * Release the HAL NAN interface.
    173      */
    174     public void releaseAware() {
    175         if (mDbg) {
    176             Log.d(TAG, "releaseAware: mWifiNanIface=" + mWifiNanIface + ", mReferenceCount="
    177                     + mReferenceCount);
    178         }
    179 
    180         if (mWifiNanIface == null) {
    181             return;
    182         }
    183         if (mHalDeviceManager == null) {
    184             Log.e(TAG, "releaseAware: mHalDeviceManager is null!?");
    185             return;
    186         }
    187 
    188         synchronized (mLock) {
    189             mReferenceCount--;
    190             if (mReferenceCount != 0) {
    191                 return;
    192             }
    193             mInterfaceDestroyedListener.active = false;
    194             mInterfaceDestroyedListener = null;
    195             mHalDeviceManager.removeIface(mWifiNanIface);
    196             mWifiNanIface = null;
    197         }
    198     }
    199 
    200     private void awareIsDown() {
    201         synchronized (mLock) {
    202             if (mDbg) {
    203                 Log.d(TAG, "awareIsDown: mWifiNanIface=" + mWifiNanIface + ", mReferenceCount ="
    204                         + mReferenceCount);
    205             }
    206             mWifiNanIface = null;
    207             mReferenceCount = 0;
    208             mWifiAwareStateManager.disableUsage();
    209         }
    210     }
    211 
    212     private class InterfaceDestroyedListener implements
    213             HalDeviceManager.InterfaceDestroyedListener {
    214         public boolean active = true;
    215 
    216         @Override
    217         public void onDestroyed(@NonNull String ifaceName) {
    218             if (mDbg) {
    219                 Log.d(TAG, "Interface was destroyed: mWifiNanIface=" + mWifiNanIface + ", active="
    220                         + active);
    221             }
    222             if (active && mWifiNanIface != null) {
    223                 awareIsDown();
    224             } // else: we released it locally so no need to disable usage
    225         }
    226     }
    227 
    228     private class InterfaceAvailableForRequestListener implements
    229             HalDeviceManager.InterfaceAvailableForRequestListener {
    230         @Override
    231         public void onAvailabilityChanged(boolean isAvailable) {
    232             if (mDbg) {
    233                 Log.d(TAG, "Interface availability = " + isAvailable + ", mWifiNanIface="
    234                         + mWifiNanIface);
    235             }
    236             synchronized (mLock) {
    237                 if (isAvailable) {
    238                     mWifiAwareStateManager.enableUsage();
    239                 } else if (mWifiNanIface == null) { // not available could mean already have NAN
    240                     mWifiAwareStateManager.disableUsage();
    241                 }
    242             }
    243         }
    244     }
    245 
    246     private static String statusString(WifiStatus status) {
    247         if (status == null) {
    248             return "status=null";
    249         }
    250         StringBuilder sb = new StringBuilder();
    251         sb.append(status.code).append(" (").append(status.description).append(")");
    252         return sb.toString();
    253     }
    254 
    255     /**
    256      * Dump the internal state of the class.
    257      */
    258     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
    259         pw.println("WifiAwareNativeManager:");
    260         pw.println("  mWifiNanIface: " + mWifiNanIface);
    261         pw.println("  mReferenceCount: " + mReferenceCount);
    262         mWifiAwareNativeCallback.dump(fd, pw, args);
    263         mHalDeviceManager.dump(fd, pw, args);
    264     }
    265 }
    266