1 /* 2 * Copyright (C) 2022 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.hal; 18 19 import android.annotation.NonNull; 20 import android.hardware.wifi.V1_0.WifiStatus; 21 import android.hardware.wifi.V1_0.WifiStatusCode; 22 import android.net.MacAddress; 23 import android.os.RemoteException; 24 import android.util.Log; 25 26 import com.android.server.wifi.util.GeneralUtil; 27 28 import java.util.ArrayList; 29 import java.util.List; 30 import java.util.function.Supplier; 31 32 /** 33 * HIDL implementation of the IWifiApIface interface. 34 */ 35 public class WifiApIfaceHidlImpl implements IWifiApIface { 36 private static final String TAG = "WifiApIfaceHidlImpl"; 37 private android.hardware.wifi.V1_0.IWifiApIface mWifiApIface; 38 private String mIfaceName; 39 WifiApIfaceHidlImpl(@onNull android.hardware.wifi.V1_0.IWifiApIface apIface)40 public WifiApIfaceHidlImpl(@NonNull android.hardware.wifi.V1_0.IWifiApIface apIface) { 41 mWifiApIface = apIface; 42 } 43 44 /** 45 * See comments for {@link IWifiApIface#getName()} 46 */ getName()47 public String getName() { 48 final String methodStr = "getName"; 49 return validateAndCall(methodStr, null, 50 () -> getNameInternal(methodStr)); 51 } 52 53 /** 54 * See comments for {@link IWifiApIface#getBridgedInstances()} 55 */ getBridgedInstances()56 public List<String> getBridgedInstances() { 57 final String methodStr = "getBridgedInstances"; 58 return validateAndCall(methodStr, null, 59 () -> getBridgedInstancesInternal(methodStr)); 60 } 61 62 /** 63 * See comments for {@link IWifiApIface#getFactoryMacAddress()} 64 */ getFactoryMacAddress()65 public MacAddress getFactoryMacAddress() { 66 final String methodStr = "getFactoryMacAddress"; 67 return validateAndCall(methodStr, null, 68 () -> getFactoryMacAddressInternal(methodStr)); 69 } 70 71 /** 72 * See comments for {@link IWifiApIface#setCountryCode(byte[])} 73 */ setCountryCode(byte[] countryCode)74 public boolean setCountryCode(byte[] countryCode) { 75 final String methodStr = "setCountryCode"; 76 return validateAndCall(methodStr, false, 77 () -> setCountryCodeInternal(methodStr, countryCode)); 78 } 79 80 /** 81 * See comments for {@link IWifiApIface#resetToFactoryMacAddress()} 82 * 83 * Note: If HAL < 1.5, will only reset the MAC address for this interface. 84 */ resetToFactoryMacAddress()85 public boolean resetToFactoryMacAddress() { 86 final String methodStr = "resetToFactoryMacAddress"; 87 return validateAndCall(methodStr, false, 88 () -> resetToFactoryMacAddressInternal(methodStr)); 89 } 90 91 /** 92 * See comments for {@link IWifiApIface#isSetMacAddressSupported()} 93 */ isSetMacAddressSupported()94 public boolean isSetMacAddressSupported() { 95 if (mWifiApIface == null) return false; 96 return getWifiApIfaceV1_4Mockable() != null; 97 } 98 99 /** 100 * See comments for {@link IWifiApIface#setMacAddress(MacAddress)} 101 */ setMacAddress(MacAddress mac)102 public boolean setMacAddress(MacAddress mac) { 103 final String methodStr = "setMacAddress"; 104 return validateAndCall(methodStr, false, 105 () -> setMacAddressInternal(methodStr, mac)); 106 } 107 108 109 // Internal Implementations 110 getNameInternal(String methodStr)111 private String getNameInternal(String methodStr) { 112 if (mIfaceName != null) return mIfaceName; 113 GeneralUtil.Mutable<String> nameResp = new GeneralUtil.Mutable<>(); 114 try { 115 mWifiApIface.getName((WifiStatus status, String name) -> { 116 if (isOk(status, methodStr)) { 117 nameResp.value = name; 118 mIfaceName = name; 119 } 120 }); 121 } catch (RemoteException e) { 122 handleRemoteException(e, methodStr); 123 } 124 return nameResp.value; 125 } 126 getBridgedInstancesInternal(String methodStr)127 private List<String> getBridgedInstancesInternal(String methodStr) { 128 GeneralUtil.Mutable<List<String>> instancesResp = new GeneralUtil.Mutable<>(); 129 try { 130 android.hardware.wifi.V1_5.IWifiApIface ap15 = getWifiApIfaceV1_5Mockable(); 131 if (ap15 == null) return null; 132 ap15.getBridgedInstances((status, instances) -> { 133 if (isOk(status, methodStr)) { 134 instancesResp.value = new ArrayList<>(instances); 135 } 136 }); 137 } catch (RemoteException e) { 138 handleRemoteException(e, methodStr); 139 } 140 return instancesResp.value; 141 } 142 getFactoryMacAddressInternal(String methodStr)143 private MacAddress getFactoryMacAddressInternal(String methodStr) { 144 GeneralUtil.Mutable<MacAddress> macResp = new GeneralUtil.Mutable<>(); 145 try { 146 android.hardware.wifi.V1_4.IWifiApIface ap14 = getWifiApIfaceV1_4Mockable(); 147 if (ap14 == null) return null; 148 ap14.getFactoryMacAddress((status, macBytes) -> { 149 if (isOk(status, methodStr)) { 150 macResp.value = MacAddress.fromBytes(macBytes); 151 } 152 }); 153 } catch (RemoteException e) { 154 handleRemoteException(e, methodStr); 155 } 156 return macResp.value; 157 } 158 setCountryCodeInternal(String methodStr, byte[] countryCode)159 private boolean setCountryCodeInternal(String methodStr, byte[] countryCode) { 160 try { 161 WifiStatus status = mWifiApIface.setCountryCode(countryCode); 162 return isOk(status, methodStr); 163 } catch (RemoteException e) { 164 handleRemoteException(e, methodStr); 165 return false; 166 } 167 } 168 resetToFactoryMacAddressInternal(String methodStr)169 private boolean resetToFactoryMacAddressInternal(String methodStr) { 170 try { 171 android.hardware.wifi.V1_5.IWifiApIface ap15 = getWifiApIfaceV1_5Mockable(); 172 if (ap15 == null) { 173 MacAddress mac = getFactoryMacAddress(); 174 return mac != null && setMacAddress(mac); 175 } 176 WifiStatus status = ap15.resetToFactoryMacAddress(); 177 return isOk(status, methodStr); 178 } catch (RemoteException e) { 179 handleRemoteException(e, methodStr); 180 return false; 181 } 182 } 183 setMacAddressInternal(String methodStr, MacAddress mac)184 private boolean setMacAddressInternal(String methodStr, MacAddress mac) { 185 try { 186 android.hardware.wifi.V1_4.IWifiApIface ap14 = getWifiApIfaceV1_4Mockable(); 187 if (ap14 == null) return false; 188 WifiStatus status = ap14.setMacAddress(mac.toByteArray()); 189 return isOk(status, methodStr); 190 } catch (RemoteException e) { 191 handleRemoteException(e, methodStr); 192 return false; 193 } 194 } 195 196 197 // Helper Functions 198 getWifiApIfaceV1_4Mockable()199 protected android.hardware.wifi.V1_4.IWifiApIface getWifiApIfaceV1_4Mockable() { 200 return android.hardware.wifi.V1_4.IWifiApIface.castFrom(mWifiApIface); 201 } 202 getWifiApIfaceV1_5Mockable()203 protected android.hardware.wifi.V1_5.IWifiApIface getWifiApIfaceV1_5Mockable() { 204 return android.hardware.wifi.V1_5.IWifiApIface.castFrom(mWifiApIface); 205 } 206 isOk(WifiStatus status, String methodStr)207 private boolean isOk(WifiStatus status, String methodStr) { 208 if (status.code == WifiStatusCode.SUCCESS) return true; 209 Log.e(TAG, methodStr + " failed with status: " + status); 210 return false; 211 } 212 handleRemoteException(RemoteException e, String methodStr)213 private void handleRemoteException(RemoteException e, String methodStr) { 214 Log.e(TAG, methodStr + " failed with remote exception: " + e); 215 mWifiApIface = null; 216 } 217 validateAndCall(String methodStr, T defaultVal, @NonNull Supplier<T> supplier)218 private <T> T validateAndCall(String methodStr, T defaultVal, @NonNull Supplier<T> supplier) { 219 if (mWifiApIface == null) { 220 Log.wtf(TAG, "Cannot call " + methodStr + " because mWifiApIface is null"); 221 return defaultVal; 222 } 223 return supplier.get(); 224 } 225 } 226