/* * Copyright (C) 2022 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.server.wifi.hal; import static android.hardware.wifi.V1_6.WifiChannelWidthInMhz.WIDTH_160; import static android.hardware.wifi.V1_6.WifiChannelWidthInMhz.WIDTH_320; import static android.hardware.wifi.V1_6.WifiChannelWidthInMhz.WIDTH_40; import static android.hardware.wifi.V1_6.WifiChannelWidthInMhz.WIDTH_80; import static android.hardware.wifi.V1_6.WifiChannelWidthInMhz.WIDTH_80P80; import static android.net.wifi.CoexUnsafeChannel.POWER_CAP_NONE; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; import android.content.res.Resources; import android.hardware.wifi.V1_0.IWifiChipEventCallback; import android.hardware.wifi.V1_0.IfaceType; import android.hardware.wifi.V1_0.WifiDebugHostWakeReasonStats; import android.hardware.wifi.V1_0.WifiDebugRingBufferFlags; import android.hardware.wifi.V1_0.WifiDebugRingBufferStatus; import android.hardware.wifi.V1_0.WifiStatus; import android.hardware.wifi.V1_0.WifiStatusCode; import android.hardware.wifi.V1_5.WifiBand; import android.hardware.wifi.V1_5.WifiIfaceMode; import android.hardware.wifi.V1_6.IfaceConcurrencyType; import android.hardware.wifi.V1_6.WifiAntennaMode; import android.hardware.wifi.V1_6.WifiRadioCombination; import android.hardware.wifi.V1_6.WifiRadioConfiguration; import android.net.wifi.CoexUnsafeChannel; import android.net.wifi.OuiKeyedData; import android.net.wifi.ScanResult; import android.net.wifi.WifiAnnotations; import android.net.wifi.WifiAvailableChannel; import android.net.wifi.WifiManager; import android.net.wifi.WifiScanner; import android.os.RemoteException; import android.util.Log; import android.util.SparseIntArray; import com.android.internal.annotations.VisibleForTesting; import com.android.modules.utils.build.SdkLevel; import com.android.server.wifi.SarInfo; import com.android.server.wifi.SsidTranslator; import com.android.server.wifi.WifiNative; import com.android.server.wifi.WlanWakeReasonAndCounts; import com.android.server.wifi.util.BitMask; import com.android.server.wifi.util.GeneralUtil.Mutable; import com.android.server.wifi.util.NativeUtil; import com.android.wifi.resources.R; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.function.Supplier; /** * HIDL implementation of the WifiChip interface. */ public class WifiChipHidlImpl implements IWifiChip { private static final String TAG = "WifiChipHidlImpl"; private android.hardware.wifi.V1_0.IWifiChip mWifiChip; private android.hardware.wifi.V1_0.IWifiChipEventCallback mHalCallback10; private android.hardware.wifi.V1_2.IWifiChipEventCallback mHalCallback12; private android.hardware.wifi.V1_4.IWifiChipEventCallback mHalCallback14; private WifiChip.Callback mFrameworkCallback; private Context mContext; private SsidTranslator mSsidTranslator; private boolean mIsBridgedSoftApSupported; private boolean mIsStaWithBridgedSoftApConcurrencySupported; public WifiChipHidlImpl(@NonNull android.hardware.wifi.V1_0.IWifiChip chip, @NonNull Context context, @NonNull SsidTranslator ssidTranslator) { mWifiChip = chip; mContext = context; mSsidTranslator = ssidTranslator; Resources res = context.getResources(); mIsBridgedSoftApSupported = res.getBoolean(R.bool.config_wifiBridgedSoftApSupported); mIsStaWithBridgedSoftApConcurrencySupported = res.getBoolean(R.bool.config_wifiStaWithBridgedSoftApConcurrencySupported); } /** * See comments for {@link IWifiChip#configureChip(int)} */ @Override public boolean configureChip(int modeId) { String methodStr = "configureChip"; return validateAndCall(methodStr, false, () -> configureChipInternal(methodStr, modeId)); } /** * See comments for {@link IWifiChip#createApIface(List)} */ @Override @Nullable public WifiApIface createApIface(@NonNull List vendorData) { String methodStr = "createApIface"; return validateAndCall(methodStr, null, () -> createApIfaceInternal(methodStr)); } /** * See comments for {@link IWifiChip#createBridgedApIface(List)} */ @Override @Nullable public WifiApIface createBridgedApIface(@NonNull List vendorData) { String methodStr = "createBridgedApIface"; return validateAndCall(methodStr, null, () -> createBridgedApIfaceInternal(methodStr)); } /** * See comments for {@link IWifiChip#createNanIface()} */ @Override @Nullable public WifiNanIface createNanIface() { String methodStr = "createNanIface"; return validateAndCall(methodStr, null, () -> createNanIfaceInternal(methodStr)); } /** * See comments for {@link IWifiChip#createP2pIface()} */ @Override @Nullable public WifiP2pIface createP2pIface() { String methodStr = "createP2pIface"; return validateAndCall(methodStr, null, () -> createP2pIfaceInternal(methodStr)); } /** * See comments for {@link IWifiChip#createRttController()} */ @Override @Nullable public WifiRttController createRttController() { String methodStr = "createRttController"; return validateAndCall(methodStr, null, () -> createRttControllerInternal(methodStr)); } /** * See comments for {@link IWifiChip#createStaIface()} */ @Override @Nullable public WifiStaIface createStaIface() { String methodStr = "createStaIface"; return validateAndCall(methodStr, null, () -> createStaIfaceInternal(methodStr)); } /** * See comments for {@link IWifiChip#enableDebugErrorAlerts(boolean)} */ @Override public boolean enableDebugErrorAlerts(boolean enable) { String methodStr = "enableDebugErrorAlerts"; return validateAndCall(methodStr, false, () -> enableDebugErrorAlertsInternal(methodStr, enable)); } /** * See comments for {@link IWifiChip#flushRingBufferToFile()} */ @Override public boolean flushRingBufferToFile() { String methodStr = "flushRingBufferToFile"; return validateAndCall(methodStr, false, () -> flushRingBufferToFileInternal(methodStr)); } /** * See comments for {@link IWifiChip#forceDumpToDebugRingBuffer(String)} */ @Override public boolean forceDumpToDebugRingBuffer(String ringName) { String methodStr = "forceDumpToDebugRingBuffer"; return validateAndCall(methodStr, false, () -> forceDumpToDebugRingBufferInternal(methodStr, ringName)); } /** * See comments for {@link IWifiChip#getApIface(String)} */ @Override @Nullable public WifiApIface getApIface(String ifaceName) { String methodStr = "getApIface"; return validateAndCall(methodStr, null, () -> getApIfaceInternal(methodStr, ifaceName)); } /** * See comments for {@link IWifiChip#getApIfaceNames()} */ @Override @Nullable public List getApIfaceNames() { String methodStr = "getApIfaceNames"; return validateAndCall(methodStr, null, () -> getApIfaceNamesInternal(methodStr)); } /** * See comments for {@link IWifiChip#getAvailableModes()} */ @Override @Nullable public List getAvailableModes() { String methodStr = "getAvailableModes"; return validateAndCall(methodStr, null, () -> getAvailableModesInternal(methodStr)); } /** * See comments for {@link IWifiChip#getCapabilitiesBeforeIfacesExist()} */ @Override public WifiChip.Response getCapabilitiesBeforeIfacesExist() { String methodStr = "getCapabilitiesBeforeIfacesExist"; return validateAndCall(methodStr, new WifiChip.Response<>(0L), () -> getCapabilitiesBeforeIfacesExistInternal(methodStr)); } /** * See comments for {@link IWifiChip#getCapabilitiesAfterIfacesExist()} */ @Override public WifiChip.Response getCapabilitiesAfterIfacesExist() { String methodStr = "getCapabilitiesAfterIfacesExist"; return validateAndCall(methodStr, new WifiChip.Response<>(0L), () -> getCapabilitiesAfterIfacesExistInternal(methodStr)); } /** * See comments for {@link IWifiChip#getDebugHostWakeReasonStats()} */ @Override @Nullable public WlanWakeReasonAndCounts getDebugHostWakeReasonStats() { String methodStr = "getDebugHostWakeReasonStats"; return validateAndCall(methodStr, null, () -> getDebugHostWakeReasonStatsInternal(methodStr)); } /** * See comments for {@link IWifiChip#getDebugRingBuffersStatus()} */ @Override @Nullable public List getDebugRingBuffersStatus() { String methodStr = "getDebugRingBuffersStatus"; return validateAndCall(methodStr, null, () -> getDebugRingBuffersStatusInternal(methodStr)); } /** * See comments for {@link IWifiChip#getId()} */ @Override public int getId() { String methodStr = "getId"; return validateAndCall(methodStr, -1, () -> getIdInternal(methodStr)); } /** * See comments for {@link IWifiChip#getMode()} */ @Override public WifiChip.Response getMode() { String methodStr = "getMode"; return validateAndCall(methodStr, new WifiChip.Response<>(0), () -> getModeInternal(methodStr)); } /** * See comments for {@link IWifiChip#getNanIface(String)} */ @Override @Nullable public WifiNanIface getNanIface(String ifaceName) { String methodStr = "getNanIface"; return validateAndCall(methodStr, null, () -> getNanIfaceInternal(methodStr, ifaceName)); } /** * See comments for {@link IWifiChip#getNanIfaceNames()} */ @Override @Nullable public List getNanIfaceNames() { String methodStr = "getNanIfaceNames"; return validateAndCall(methodStr, null, () -> getNanIfaceNamesInternal(methodStr)); } /** * See comments for {@link IWifiChip#getP2pIface(String)} */ @Override @Nullable public WifiP2pIface getP2pIface(String ifaceName) { String methodStr = "getP2pIface"; return validateAndCall(methodStr, null, () -> getP2pIfaceInternal(methodStr, ifaceName)); } /** * See comments for {@link IWifiChip#getP2pIfaceNames()} */ @Override @Nullable public List getP2pIfaceNames() { String methodStr = "getP2pIfaceNames"; return validateAndCall(methodStr, null, () -> getP2pIfaceNamesInternal(methodStr)); } /** * See comments for {@link IWifiChip#getStaIface(String)} */ @Override @Nullable public WifiStaIface getStaIface(String ifaceName) { String methodStr = "getStaIface"; return validateAndCall(methodStr, null, () -> getStaIfaceInternal(methodStr, ifaceName)); } /** * See comments for {@link IWifiChip#getStaIfaceNames()} */ @Override @Nullable public List getStaIfaceNames() { String methodStr = "getStaIfaceNames"; return validateAndCall(methodStr, null, () -> getStaIfaceNamesInternal(methodStr)); } /** * See comments for {@link IWifiChip#getSupportedRadioCombinations()} */ @Override @Nullable public List getSupportedRadioCombinations() { String methodStr = "getSupportedRadioCombinations"; return validateAndCall(methodStr, null, () -> getSupportedRadioCombinationsInternal(methodStr)); } /** * See comments for {@link IWifiChip#getWifiChipCapabilities()} */ public WifiChip.WifiChipCapabilities getWifiChipCapabilities() { return null; } /** * See comments for {@link IWifiChip#getUsableChannels(int, int, int)} */ @Override @Nullable public List getUsableChannels(@WifiScanner.WifiBand int band, @WifiAvailableChannel.OpMode int mode, @WifiAvailableChannel.Filter int filter) { String methodStr = "getUsableChannels"; return validateAndCall(methodStr, null, () -> getUsableChannelsInternal(methodStr, band, mode, filter)); } /** * See comments for {@link IWifiChip#registerCallback(WifiChip.Callback)} */ @Override public boolean registerCallback(WifiChip.Callback callback) { String methodStr = "registerCallback"; return validateAndCall(methodStr, false, () -> registerCallbackInternal(methodStr, callback)); } /** * See comments for {@link IWifiChip#removeApIface(String)} */ @Override public boolean removeApIface(String ifaceName) { String methodStr = "removeApIface"; return validateAndCall(methodStr, false, () -> removeApIfaceInternal(methodStr, ifaceName)); } /** * See comments for {@link IWifiChip#removeIfaceInstanceFromBridgedApIface(String, String)} */ @Override public boolean removeIfaceInstanceFromBridgedApIface(String brIfaceName, String ifaceName) { String methodStr = "removeIfaceInstanceFromBridgedApIface"; return validateAndCall(methodStr, false, () -> removeIfaceInstanceFromBridgedApIfaceInternal(methodStr, brIfaceName, ifaceName)); } /** * See comments for {@link IWifiChip#removeNanIface(String)} */ @Override public boolean removeNanIface(String ifaceName) { String methodStr = "removeNanIface"; return validateAndCall(methodStr, false, () -> removeNanIfaceInternal(methodStr, ifaceName)); } /** * See comments for {@link IWifiChip#removeP2pIface(String)} */ @Override public boolean removeP2pIface(String ifaceName) { String methodStr = "removeP2pIface"; return validateAndCall(methodStr, false, () -> removeP2pIfaceInternal(methodStr, ifaceName)); } /** * See comments for {@link IWifiChip#removeStaIface(String)} */ @Override public boolean removeStaIface(String ifaceName) { String methodStr = "removeStaIface"; return validateAndCall(methodStr, false, () -> removeStaIfaceInternal(methodStr, ifaceName)); } /** * See comments for {@link IWifiChip#requestChipDebugInfo()} */ @Override @Nullable public WifiChip.ChipDebugInfo requestChipDebugInfo() { String methodStr = "requestChipDebugInfo"; return validateAndCall(methodStr, null, () -> requestChipDebugInfoInternal(methodStr)); } /** * See comments for {@link IWifiChip#requestDriverDebugDump()} */ @Override @Nullable public byte[] requestDriverDebugDump() { String methodStr = "requestDriverDebugDump"; return validateAndCall(methodStr, null, () -> requestDriverDebugDumpInternal(methodStr)); } /** * See comments for {@link IWifiChip#requestFirmwareDebugDump()} */ @Override @Nullable public byte[] requestFirmwareDebugDump() { String methodStr = "requestFirmwareDebugDump"; return validateAndCall(methodStr, null, () -> requestFirmwareDebugDumpInternal(methodStr)); } /** * See comments for {@link IWifiChip#selectTxPowerScenario(SarInfo)} */ @Override public boolean selectTxPowerScenario(SarInfo sarInfo) { String methodStr = "selectTxPowerScenario"; return validateAndCall(methodStr, false, () -> selectTxPowerScenarioInternal(methodStr, sarInfo)); } /** * See comments for {@link IWifiChip#setCoexUnsafeChannels(List, int)} */ @Override public boolean setCoexUnsafeChannels(List unsafeChannels, int restrictions) { String methodStr = "setCoexUnsafeChannels"; return validateAndCall(methodStr, false, () -> setCoexUnsafeChannelsInternal(methodStr, unsafeChannels, restrictions)); } /** * See comments for {@link IWifiChip#setCountryCode(byte[])} */ @Override public boolean setCountryCode(byte[] code) { String methodStr = "setCountryCode"; return validateAndCall(methodStr, false, () -> setCountryCodeInternal(methodStr, code)); } /** * See comments for {@link IWifiChip#setLowLatencyMode(boolean)} */ @Override public boolean setLowLatencyMode(boolean enable) { String methodStr = "setLowLatencyMode"; return validateAndCall(methodStr, false, () -> setLowLatencyModeInternal(methodStr, enable)); } /** * See comments for {@link IWifiChip#setMultiStaPrimaryConnection(String)} */ @Override public boolean setMultiStaPrimaryConnection(String ifaceName) { String methodStr = "setMultiStaPrimaryConnection"; return validateAndCall(methodStr, false, () -> setMultiStaPrimaryConnectionInternal(methodStr, ifaceName)); } /** * See comments for {@link IWifiChip#setMultiStaUseCase(int)} */ @Override public boolean setMultiStaUseCase(@WifiNative.MultiStaUseCase int useCase) { String methodStr = "setMultiStaUseCase"; return validateAndCall(methodStr, false, () -> setMultiStaUseCaseInternal(methodStr, useCase)); } /** * See comments for {@link IWifiChip#startLoggingToDebugRingBuffer(String, int, int, int)} */ @Override public boolean startLoggingToDebugRingBuffer(String ringName, int verboseLevel, int maxIntervalInSec, int minDataSizeInBytes) { String methodStr = "startLoggingToDebugRingBuffer"; return validateAndCall(methodStr, false, () -> startLoggingToDebugRingBufferInternal(methodStr, ringName, verboseLevel, maxIntervalInSec, minDataSizeInBytes)); } /** * See comments for {@link IWifiChip#stopLoggingToDebugRingBuffer()} */ @Override public boolean stopLoggingToDebugRingBuffer() { String methodStr = "stopLoggingToDebugRingBuffer"; return validateAndCall(methodStr, false, () -> stopLoggingToDebugRingBufferInternal(methodStr)); } /** * See comments for {@link IWifiChip#triggerSubsystemRestart()} */ @Override public boolean triggerSubsystemRestart() { String methodStr = "triggerSubsystemRestart"; return validateAndCall(methodStr, false, () -> triggerSubsystemRestartInternal(methodStr)); } /** * See comments for {@link IWifiChip#setMloMode(int)}. */ @Override public @android.hardware.wifi.WifiStatusCode int setMloMode(@WifiManager.MloMode int mode) { return android.hardware.wifi.WifiStatusCode.ERROR_NOT_SUPPORTED; } /** * See comments for {@link IWifiChip#enableStaChannelForPeerNetwork(boolean, boolean)} */ @Override public boolean enableStaChannelForPeerNetwork(boolean enableIndoorChannel, boolean enableDfsChannel) { Log.d(TAG, "enableStaChannelForPeerNetwork() is not implemented in hidl."); return false; } /** * See comments for {@link IWifiChip#setAfcChannelAllowance(WifiChip.AfcChannelAllowance)} */ @Override public boolean setAfcChannelAllowance(WifiChip.AfcChannelAllowance afcChannelAllowance) { Log.d(TAG, "setAfcChannelAllowance() is not implemented in hidl."); return false; } // Internal Implementations private boolean configureChipInternal(String methodStr, int modeId) { try { WifiStatus status = mWifiChip.configureChip(modeId); return isOk(status, methodStr); } catch (RemoteException e) { handleRemoteException(e, methodStr); return false; } } private WifiApIface createApIfaceInternal(String methodStr) { Mutable ifaceResp = new Mutable<>(); try { mWifiChip.createApIface((status, iface) -> { if (isOk(status, methodStr)) { ifaceResp.value = new WifiApIface(iface); } }); } catch (RemoteException e) { handleRemoteException(e, methodStr); } return ifaceResp.value; } private WifiApIface createBridgedApIfaceInternal(String methodStr) { Mutable ifaceResp = new Mutable<>(); try { android.hardware.wifi.V1_5.IWifiChip chip15 = getWifiChipV1_5Mockable(); if (chip15 == null) return null; chip15.createBridgedApIface((status, iface) -> { if (isOk(status, methodStr)) { ifaceResp.value = new WifiApIface(iface); } }); } catch (RemoteException e) { handleRemoteException(e, methodStr); } return ifaceResp.value; } private WifiNanIface createNanIfaceInternal(String methodStr) { Mutable ifaceResp = new Mutable<>(); try { mWifiChip.createNanIface((status, iface) -> { if (isOk(status, methodStr)) { ifaceResp.value = new WifiNanIface(iface); } }); } catch (RemoteException e) { handleRemoteException(e, methodStr); } return ifaceResp.value; } private WifiP2pIface createP2pIfaceInternal(String methodStr) { Mutable ifaceResp = new Mutable<>(); try { mWifiChip.createP2pIface((status, iface) -> { if (isOk(status, methodStr)) { ifaceResp.value = new WifiP2pIface(iface); } }); } catch (RemoteException e) { handleRemoteException(e, methodStr); } return ifaceResp.value; } private WifiRttController createRttControllerInternal(String methodStr) { Mutable controllerResp = new Mutable<>(); try { android.hardware.wifi.V1_6.IWifiChip chip16 = getWifiChipV1_6Mockable(); android.hardware.wifi.V1_4.IWifiChip chip14 = getWifiChipV1_4Mockable(); if (chip16 != null) { chip16.createRttController_1_6(null, (status, controller) -> { if (isOk(status, methodStr)) { controllerResp.value = new WifiRttController(controller); } }); } else if (chip14 != null) { chip14.createRttController_1_4(null, (status, controller) -> { if (isOk(status, methodStr)) { controllerResp.value = new WifiRttController(controller); } }); } else { mWifiChip.createRttController(null, (status, controller) -> { if (isOk(status, methodStr)) { controllerResp.value = new WifiRttController(controller); } }); } } catch (RemoteException e) { handleRemoteException(e, methodStr); } return controllerResp.value; } private WifiStaIface createStaIfaceInternal(String methodStr) { Mutable ifaceResp = new Mutable<>(); try { mWifiChip.createStaIface((status, iface) -> { if (isOk(status, methodStr)) { ifaceResp.value = new WifiStaIface(iface, mContext, mSsidTranslator); } }); } catch (RemoteException e) { handleRemoteException(e, methodStr); } return ifaceResp.value; } private boolean enableDebugErrorAlertsInternal(String methodStr, boolean enable) { try { WifiStatus status = mWifiChip.enableDebugErrorAlerts(enable); return isOk(status, methodStr); } catch (RemoteException e) { handleRemoteException(e, methodStr); return false; } } private boolean flushRingBufferToFileInternal(String methodStr) { try { android.hardware.wifi.V1_3.IWifiChip chip13 = getWifiChipV1_3Mockable(); if (chip13 == null) return false; WifiStatus status = chip13.flushRingBufferToFile(); return isOk(status, methodStr); } catch (RemoteException e) { handleRemoteException(e, methodStr); return false; } } private boolean forceDumpToDebugRingBufferInternal(String methodStr, String ringName) { try { WifiStatus status = mWifiChip.forceDumpToDebugRingBuffer(ringName); return isOk(status, methodStr); } catch (RemoteException e) { handleRemoteException(e, methodStr); return false; } } private WifiApIface getApIfaceInternal(String methodStr, String ifaceName) { Mutable ifaceResp = new Mutable<>(); try { mWifiChip.getApIface(ifaceName, (status, iface) -> { if (isOk(status, methodStr)) { ifaceResp.value = new WifiApIface(iface); } }); } catch (RemoteException e) { handleRemoteException(e, methodStr); } return ifaceResp.value; } private List getApIfaceNamesInternal(String methodStr) { Mutable> ifaceNameResp = new Mutable<>(); try { mWifiChip.getApIfaceNames((status, ifaceNames) -> { if (isOk(status, methodStr)) { ifaceNameResp.value = ifaceNames; } }); } catch (RemoteException e) { handleRemoteException(e, methodStr); } return ifaceNameResp.value; } private List getAvailableModesInternal(String methodStr) { Mutable> modeResp = new Mutable<>(); try { android.hardware.wifi.V1_6.IWifiChip chip16 = getWifiChipV1_6Mockable(); if (chip16 != null) { chip16.getAvailableModes_1_6((status, modes) -> { if (isOk(status, methodStr)) { modeResp.value = halToFrameworkChipModeListV1_6(modes); } }); } else { mWifiChip.getAvailableModes((status, modes) -> { if (isOk(status, methodStr)) { modeResp.value = halToFrameworkChipModeListV1_0(modes); } }); } } catch (RemoteException e) { handleRemoteException(e, methodStr); } return modeResp.value; } private WifiChip.Response getCapabilitiesBeforeIfacesExistInternal(String methodStr) { WifiChip.Response capsResp = new WifiChip.Response<>(0L); try { // HAL newer than v1.5 supports getting capabilities before creating an interface. android.hardware.wifi.V1_5.IWifiChip chip15 = getWifiChipV1_5Mockable(); if (chip15 != null) { chip15.getCapabilities_1_5((status, caps) -> { if (isOk(status, methodStr)) { capsResp.setValue(wifiFeatureMaskFromChipCapabilities_1_5(caps)); capsResp.setStatusCode(WifiHal.WIFI_STATUS_SUCCESS); } else { capsResp.setStatusCode( WifiHalHidlImpl.halToFrameworkWifiStatusCode(status.code)); } }); } } catch (RemoteException e) { handleRemoteException(e, methodStr); capsResp.setStatusCode(WifiHal.WIFI_STATUS_ERROR_REMOTE_EXCEPTION); } return capsResp; } private WifiChip.Response getCapabilitiesAfterIfacesExistInternal(String methodStr) { WifiChip.Response capsResp = new WifiChip.Response<>(0L); try { android.hardware.wifi.V1_5.IWifiChip chip15 = getWifiChipV1_5Mockable(); android.hardware.wifi.V1_3.IWifiChip chip13 = getWifiChipV1_3Mockable(); if (chip15 != null) { chip15.getCapabilities_1_5((status, caps) -> { if (isOk(status, methodStr)) { capsResp.setValue(wifiFeatureMaskFromChipCapabilities_1_5(caps)); capsResp.setStatusCode(WifiHal.WIFI_STATUS_SUCCESS); } else { capsResp.setStatusCode( WifiHalHidlImpl.halToFrameworkWifiStatusCode(status.code)); } }); } else if (chip13 != null) { chip13.getCapabilities_1_3((status, caps) -> { if (isOk(status, methodStr)) { capsResp.setValue(wifiFeatureMaskFromChipCapabilities_1_3(caps)); capsResp.setStatusCode(WifiHal.WIFI_STATUS_SUCCESS); } else { capsResp.setStatusCode( WifiHalHidlImpl.halToFrameworkWifiStatusCode(status.code)); } }); } else { mWifiChip.getCapabilities((status, caps) -> { if (isOk(status, methodStr)) { capsResp.setValue((long) wifiFeatureMaskFromChipCapabilities(caps)); capsResp.setStatusCode(WifiHal.WIFI_STATUS_SUCCESS); } else { capsResp.setStatusCode( WifiHalHidlImpl.halToFrameworkWifiStatusCode(status.code)); } }); } } catch (RemoteException e) { handleRemoteException(e, methodStr); capsResp.setStatusCode(WifiHal.WIFI_STATUS_ERROR_REMOTE_EXCEPTION); } return capsResp; } private WlanWakeReasonAndCounts getDebugHostWakeReasonStatsInternal(String methodStr) { Mutable debugResp = new Mutable<>(); try { mWifiChip.getDebugHostWakeReasonStats((status, debugStats) -> { if (isOk(status, methodStr)) { debugResp.value = halToFrameworkWakeReasons(debugStats); } }); } catch (RemoteException e) { handleRemoteException(e, methodStr); } return debugResp.value; } private List getDebugRingBuffersStatusInternal(String methodStr) { Mutable> ringBufResp = new Mutable<>(); try { mWifiChip.getDebugRingBuffersStatus((status, ringBuffers) -> { if (isOk(status, methodStr)) { WifiNative.RingBufferStatus[] ringBufArray = makeRingBufferStatusArray(ringBuffers); ringBufResp.value = Arrays.asList(ringBufArray); } }); } catch (RemoteException e) { handleRemoteException(e, methodStr); } return ringBufResp.value; } private int getIdInternal(String methodStr) { Mutable idResp = new Mutable<>(-1); try { mWifiChip.getId((status, id) -> { if (isOk(status, methodStr)) { idResp.value = id; } }); } catch (RemoteException e) { handleRemoteException(e, methodStr); } return idResp.value; } private WifiChip.Response getModeInternal(String methodStr) { WifiChip.Response modeResp = new WifiChip.Response<>(0); try { mWifiChip.getMode((status, mode) -> { if (isOk(status, methodStr)) { modeResp.setValue(mode); modeResp.setStatusCode(WifiHal.WIFI_STATUS_SUCCESS); } else { modeResp.setStatusCode( WifiHalHidlImpl.halToFrameworkWifiStatusCode(status.code)); } }); } catch (RemoteException e) { handleRemoteException(e, methodStr); modeResp.setStatusCode(WifiHal.WIFI_STATUS_ERROR_REMOTE_EXCEPTION); } return modeResp; } private WifiNanIface getNanIfaceInternal(String methodStr, String ifaceName) { Mutable ifaceResp = new Mutable<>(); try { mWifiChip.getNanIface(ifaceName, (status, iface) -> { if (isOk(status, methodStr)) { ifaceResp.value = new WifiNanIface(iface); } }); } catch (RemoteException e) { handleRemoteException(e, methodStr); } return ifaceResp.value; } private List getNanIfaceNamesInternal(String methodStr) { Mutable> ifaceNameResp = new Mutable<>(); try { mWifiChip.getNanIfaceNames((status, ifaceNames) -> { if (isOk(status, methodStr)) { ifaceNameResp.value = ifaceNames; } }); } catch (RemoteException e) { handleRemoteException(e, methodStr); } return ifaceNameResp.value; } private WifiP2pIface getP2pIfaceInternal(String methodStr, String ifaceName) { Mutable ifaceResp = new Mutable<>(); try { mWifiChip.getP2pIface(ifaceName, (status, iface) -> { if (isOk(status, methodStr)) { ifaceResp.value = new WifiP2pIface(iface); } }); } catch (RemoteException e) { handleRemoteException(e, methodStr); } return ifaceResp.value; } private List getP2pIfaceNamesInternal(String methodStr) { Mutable> ifaceNameResp = new Mutable<>(); try { mWifiChip.getP2pIfaceNames((status, ifaceNames) -> { if (isOk(status, methodStr)) { ifaceNameResp.value = ifaceNames; } }); } catch (RemoteException e) { handleRemoteException(e, methodStr); } return ifaceNameResp.value; } private WifiStaIface getStaIfaceInternal(String methodStr, String ifaceName) { Mutable ifaceResp = new Mutable<>(); try { mWifiChip.getStaIface(ifaceName, (status, iface) -> { if (isOk(status, methodStr)) { ifaceResp.value = new WifiStaIface(iface, mContext, mSsidTranslator); } }); } catch (RemoteException e) { handleRemoteException(e, methodStr); } return ifaceResp.value; } private List getStaIfaceNamesInternal(String methodStr) { Mutable> ifaceNameResp = new Mutable<>(); try { mWifiChip.getStaIfaceNames((status, ifaceNames) -> { if (isOk(status, methodStr)) { ifaceNameResp.value = ifaceNames; } }); } catch (RemoteException e) { handleRemoteException(e, methodStr); } return ifaceNameResp.value; } private List getSupportedRadioCombinationsInternal( String methodStr) { Mutable> radioComboResp = new Mutable<>(); try { android.hardware.wifi.V1_6.IWifiChip chip16 = getWifiChipV1_6Mockable(); if (chip16 == null) return null; chip16.getSupportedRadioCombinationsMatrix((status, matrix) -> { if (matrix != null) { radioComboResp.value = halToFrameworkRadioCombinations(matrix.radioCombinations); } }); } catch (RemoteException e) { handleRemoteException(e, methodStr); } return radioComboResp.value; } private List getUsableChannelsInternal(String methodStr, @WifiScanner.WifiBand int band, @WifiAvailableChannel.OpMode int mode, @WifiAvailableChannel.Filter int filter) { Mutable> channelResp = new Mutable<>(); try { android.hardware.wifi.V1_5.IWifiChip chip15 = getWifiChipV1_5Mockable(); android.hardware.wifi.V1_6.IWifiChip chip16 = getWifiChipV1_6Mockable(); if (chip15 == null && chip16 == null) return null; if (chip16 != null) { chip16.getUsableChannels_1_6( frameworkToHalWifiBand(band), frameworkToHalIfaceMode(mode), frameworkToHalUsableFilter_1_6(filter), (status, channels) -> { if (isOk(status, methodStr)) { channelResp.value = new ArrayList<>(); for (android.hardware.wifi.V1_6.WifiUsableChannel ch : channels) { channelResp.value.add(new WifiAvailableChannel(ch.channel, halToFrameworkIfaceMode(ch.ifaceModeMask), halToFrameworkChannelWidth(ch.channelBandwidth))); } } }); } else { chip15.getUsableChannels( frameworkToHalWifiBand(band), frameworkToHalIfaceMode(mode), frameworkToHalUsableFilter(filter), (status, channels) -> { if (isOk(status, methodStr)) { channelResp.value = new ArrayList<>(); for (android.hardware.wifi.V1_5.WifiUsableChannel ch : channels) { channelResp.value.add(new WifiAvailableChannel(ch.channel, halToFrameworkIfaceMode(ch.ifaceModeMask), halToFrameworkChannelWidth(ch.channelBandwidth))); } } }); } } catch (RemoteException e) { handleRemoteException(e, methodStr); } return channelResp.value; } private @WifiAnnotations.ChannelWidth int halToFrameworkChannelWidth(int channelBandwidth) { switch (channelBandwidth) { case WIDTH_40: return ScanResult.CHANNEL_WIDTH_40MHZ; case WIDTH_80: return ScanResult.CHANNEL_WIDTH_80MHZ; case WIDTH_160: return ScanResult.CHANNEL_WIDTH_160MHZ; case WIDTH_80P80: return ScanResult.CHANNEL_WIDTH_80MHZ_PLUS_MHZ; case WIDTH_320: return ScanResult.CHANNEL_WIDTH_320MHZ; default: return ScanResult.CHANNEL_WIDTH_20MHZ; } } private boolean registerCallbackInternal(String methodStr, WifiChip.Callback callback) { if (mFrameworkCallback != null) { Log.e(TAG, "Framework callback is already registered"); return false; } else if (callback == null) { Log.e(TAG, "Cannot register a null callback"); return false; } try { android.hardware.wifi.V1_2.IWifiChip chip12 = getWifiChipV1_2Mockable(); android.hardware.wifi.V1_4.IWifiChip chip14 = getWifiChipV1_4Mockable(); mHalCallback10 = new ChipEventCallback(); WifiStatus status; if (chip14 != null) { mHalCallback12 = new ChipEventCallbackV12(); mHalCallback14 = new ChipEventCallbackV14(); status = chip14.registerEventCallback_1_4(mHalCallback14); } else if (chip12 != null) { mHalCallback12 = new ChipEventCallbackV12(); status = chip12.registerEventCallback_1_2(mHalCallback12); } else { status = mWifiChip.registerEventCallback(mHalCallback10); } if (!isOk(status, methodStr)) return false; mFrameworkCallback = callback; return true; } catch (RemoteException e) { handleRemoteException(e, methodStr); return false; } } private boolean removeApIfaceInternal(String methodStr, String ifaceName) { try { WifiStatus status = mWifiChip.removeApIface(ifaceName); return isOk(status, methodStr); } catch (RemoteException e) { handleRemoteException(e, methodStr); return false; } } private boolean removeIfaceInstanceFromBridgedApIfaceInternal(String methodStr, String brIfaceName, String ifaceName) { try { android.hardware.wifi.V1_5.IWifiChip chip15 = getWifiChipV1_5Mockable(); if (chip15 == null) return false; WifiStatus status = chip15.removeIfaceInstanceFromBridgedApIface(brIfaceName, ifaceName); return isOk(status, methodStr); } catch (RemoteException e) { handleRemoteException(e, methodStr); return false; } } private boolean removeNanIfaceInternal(String methodStr, String ifaceName) { try { WifiStatus status = mWifiChip.removeNanIface(ifaceName); return isOk(status, methodStr); } catch (RemoteException e) { handleRemoteException(e, methodStr); return false; } } private boolean removeP2pIfaceInternal(String methodStr, String ifaceName) { try { WifiStatus status = mWifiChip.removeP2pIface(ifaceName); return isOk(status, methodStr); } catch (RemoteException e) { handleRemoteException(e, methodStr); return false; } } private boolean removeStaIfaceInternal(String methodStr, String ifaceName) { try { WifiStatus status = mWifiChip.removeStaIface(ifaceName); return isOk(status, methodStr); } catch (RemoteException e) { handleRemoteException(e, methodStr); return false; } } private WifiChip.ChipDebugInfo requestChipDebugInfoInternal(String methodStr) { Mutable debugResp = new Mutable<>(); try { mWifiChip.requestChipDebugInfo((status, halInfo) -> { if (isOk(status, methodStr)) { debugResp.value = new WifiChip.ChipDebugInfo( halInfo.driverDescription, halInfo.firmwareDescription); } }); } catch (RemoteException e) { handleRemoteException(e, methodStr); } return debugResp.value; } private byte[] requestDriverDebugDumpInternal(String methodStr) { Mutable debugResp = new Mutable<>(); try { mWifiChip.requestDriverDebugDump((status, blob) -> { if (isOk(status, methodStr)) { debugResp.value = NativeUtil.byteArrayFromArrayList(blob); } }); } catch (RemoteException e) { handleRemoteException(e, methodStr); } return debugResp.value; } private byte[] requestFirmwareDebugDumpInternal(String methodStr) { Mutable debugResp = new Mutable<>(); try { mWifiChip.requestFirmwareDebugDump((status, blob) -> { if (isOk(status, methodStr)) { debugResp.value = NativeUtil.byteArrayFromArrayList(blob); } }); } catch (RemoteException e) { handleRemoteException(e, methodStr); } return debugResp.value; } private boolean selectTxPowerScenarioInternal(String methodStr, SarInfo sarInfo) { if (getWifiChipV1_2Mockable() != null) { return selectTxPowerScenarioInternal_1_2(methodStr, sarInfo); } else if (getWifiChipV1_1Mockable() != null) { return selectTxPowerScenarioInternal_1_1(methodStr, sarInfo); } return false; } private boolean selectTxPowerScenarioInternal_1_1(String methodStr, SarInfo sarInfo) { methodStr += "_1_1"; try { WifiStatus status; android.hardware.wifi.V1_1.IWifiChip chip11 = getWifiChipV1_1Mockable(); if (sarPowerBackoffRequired_1_1(sarInfo)) { // Power backoff is needed, so calculate the required scenario // and attempt to set it. int halScenario = frameworkToHalTxPowerScenario_1_1(sarInfo); if (sarInfo.setSarScenarioNeeded(halScenario)) { Log.d(TAG, "Attempting to set SAR scenario to " + halScenario); status = chip11.selectTxPowerScenario(halScenario); return isOk(status, methodStr); } // Reaching here means setting SAR scenario would be redundant, // do nothing and return with success. return true; } // We don't need to perform power backoff, so attempt to reset the SAR scenario. if (sarInfo.resetSarScenarioNeeded()) { status = chip11.resetTxPowerScenario(); Log.d(TAG, "Attempting to reset the SAR scenario"); return isOk(status, methodStr); } // Resetting SAR scenario would be redundant; do nothing and return with success. return true; } catch (RemoteException e) { handleRemoteException(e, methodStr); return false; } catch (IllegalArgumentException e) { Log.e(TAG, "IllegalArgumentException in " + methodStr); return false; } } private boolean selectTxPowerScenarioInternal_1_2(String methodStr, SarInfo sarInfo) { methodStr += "_1_2"; try { WifiStatus status; android.hardware.wifi.V1_2.IWifiChip chip12 = getWifiChipV1_2Mockable(); if (sarPowerBackoffRequired_1_2(sarInfo)) { // Power backoff is needed, so calculate the required scenario // and attempt to set it. int halScenario = frameworkToHalTxPowerScenario_1_2(sarInfo); if (sarInfo.setSarScenarioNeeded(halScenario)) { Log.d(TAG, "Attempting to set SAR scenario to " + halScenario); status = chip12.selectTxPowerScenario_1_2(halScenario); return isOk(status, methodStr); } // Reaching here means setting SAR scenario would be redundant, // do nothing and return with success. return true; } // We don't need to perform power backoff, so attempt to reset the SAR scenario. if (sarInfo.resetSarScenarioNeeded()) { status = chip12.resetTxPowerScenario(); Log.d(TAG, "Attempting to reset the SAR scenario"); return isOk(status, methodStr); } // Resetting SAR scenario would be redundant; do nothing and return with success. return true; } catch (RemoteException e) { handleRemoteException(e, methodStr); return false; } catch (IllegalArgumentException e) { Log.e(TAG, "IllegalArgumentException in " + methodStr); return false; } } private boolean setCoexUnsafeChannelsInternal(String methodStr, List unsafeChannels, int restrictions) { try { android.hardware.wifi.V1_5.IWifiChip chip15 = getWifiChipV1_5Mockable(); if (chip15 == null) return false; WifiStatus status = chip15.setCoexUnsafeChannels( frameworkCoexUnsafeChannelsToHidl(unsafeChannels), frameworkCoexRestrictionsToHidl(restrictions)); return isOk(status, methodStr); } catch (RemoteException e) { handleRemoteException(e, methodStr); return false; } } private boolean setCountryCodeInternal(String methodStr, byte[] code) { try { android.hardware.wifi.V1_5.IWifiChip chip15 = getWifiChipV1_5Mockable(); if (chip15 == null) return false; WifiStatus status = chip15.setCountryCode(code); return isOk(status, methodStr); } catch (RemoteException e) { handleRemoteException(e, methodStr); return false; } } private boolean setLowLatencyModeInternal(String methodStr, boolean enable) { try { android.hardware.wifi.V1_3.IWifiChip chip13 = getWifiChipV1_3Mockable(); if (chip13 == null) return false; int mode; if (enable) { mode = android.hardware.wifi.V1_3.IWifiChip.LatencyMode.LOW; } else { mode = android.hardware.wifi.V1_3.IWifiChip.LatencyMode.NORMAL; } WifiStatus status = chip13.setLatencyMode(mode); return isOk(status, methodStr); } catch (RemoteException e) { handleRemoteException(e, methodStr); return false; } } private boolean setMultiStaPrimaryConnectionInternal(String methodStr, String ifaceName) { try { android.hardware.wifi.V1_5.IWifiChip chip15 = getWifiChipV1_5Mockable(); if (chip15 == null) return false; WifiStatus status = chip15.setMultiStaPrimaryConnection(ifaceName); return isOk(status, methodStr); } catch (RemoteException e) { handleRemoteException(e, methodStr); return false; } } private boolean setMultiStaUseCaseInternal(String methodStr, @WifiNative.MultiStaUseCase int useCase) { try { android.hardware.wifi.V1_5.IWifiChip chip15 = getWifiChipV1_5Mockable(); if (chip15 == null) return false; WifiStatus status = chip15.setMultiStaUseCase(frameworkMultiStaUseCaseToHidl(useCase)); return isOk(status, methodStr); } catch (RemoteException e) { handleRemoteException(e, methodStr); } catch (IllegalArgumentException e) { Log.e(TAG, "Invalid argument " + useCase + " in " + methodStr); } return false; } private boolean startLoggingToDebugRingBufferInternal(String methodStr, String ringName, int verboseLevel, int maxIntervalInSec, int minDataSizeInBytes) { try { WifiStatus status = mWifiChip.startLoggingToDebugRingBuffer(ringName, verboseLevel, maxIntervalInSec, minDataSizeInBytes); return isOk(status, methodStr); } catch (RemoteException e) { handleRemoteException(e, methodStr); return false; } } private boolean stopLoggingToDebugRingBufferInternal(String methodStr) { try { WifiStatus status = mWifiChip.stopLoggingToDebugRingBuffer(); return isOk(status, methodStr); } catch (RemoteException e) { handleRemoteException(e, methodStr); return false; } } private boolean triggerSubsystemRestartInternal(String methodStr) { try { android.hardware.wifi.V1_5.IWifiChip chip15 = getWifiChipV1_5Mockable(); if (chip15 == null) return false; WifiStatus status = chip15.triggerSubsystemRestart(); return isOk(status, methodStr); } catch (RemoteException e) { handleRemoteException(e, methodStr); return false; } } /** * Callback for events on the chip. */ private class ChipEventCallback extends IWifiChipEventCallback.Stub { @Override public void onChipReconfigured(int modeId) { if (mFrameworkCallback == null) return; mFrameworkCallback.onChipReconfigured(modeId); } @Override public void onChipReconfigureFailure(WifiStatus status) { if (mFrameworkCallback == null) return; mFrameworkCallback.onChipReconfigureFailure( WifiHalHidlImpl.halToFrameworkWifiStatusCode(status.code)); } @Override public void onIfaceAdded(int type, String name) { if (mFrameworkCallback == null) return; mFrameworkCallback.onIfaceAdded(halToFrameworkIfaceType(type), name); } @Override public void onIfaceRemoved(int type, String name) { if (mFrameworkCallback == null) return; mFrameworkCallback.onIfaceRemoved(halToFrameworkIfaceType(type), name); } @Override public void onDebugRingBufferDataAvailable( WifiDebugRingBufferStatus status, java.util.ArrayList data) { if (mFrameworkCallback == null) return; mFrameworkCallback.onDebugRingBufferDataAvailable( halToFrameworkRingBufferStatus(status), NativeUtil.byteArrayFromArrayList(data)); } @Override public void onDebugErrorAlert(int errorCode, java.util.ArrayList debugData) { if (mFrameworkCallback == null) return; mFrameworkCallback.onDebugErrorAlert(errorCode, NativeUtil.byteArrayFromArrayList(debugData)); } } /** * Callback for events on the 1.2 chip. */ private class ChipEventCallbackV12 extends android.hardware.wifi.V1_2.IWifiChipEventCallback.Stub { @Override public void onChipReconfigured(int modeId) throws RemoteException { mHalCallback10.onChipReconfigured(modeId); } @Override public void onChipReconfigureFailure(WifiStatus status) throws RemoteException { mHalCallback10.onChipReconfigureFailure(status); } public void onIfaceAdded(int type, String name) throws RemoteException { mHalCallback10.onIfaceAdded(type, name); } @Override public void onIfaceRemoved(int type, String name) throws RemoteException { mHalCallback10.onIfaceRemoved(type, name); } @Override public void onDebugRingBufferDataAvailable( WifiDebugRingBufferStatus status, java.util.ArrayList data) throws RemoteException { mHalCallback10.onDebugRingBufferDataAvailable(status, data); } @Override public void onDebugErrorAlert(int errorCode, java.util.ArrayList debugData) throws RemoteException { mHalCallback10.onDebugErrorAlert(errorCode, debugData); } @Override public void onRadioModeChange(ArrayList radioModeInfoList) { if (mFrameworkCallback == null) return; List frameworkRadioModeInfos = new ArrayList<>(); for (RadioModeInfo radioInfo : radioModeInfoList) { List frameworkIfaceInfos = new ArrayList<>(); for (IfaceInfo ifaceInfo : radioInfo.ifaceInfos) { frameworkIfaceInfos.add( new WifiChip.IfaceInfo(ifaceInfo.name, ifaceInfo.channel)); } frameworkRadioModeInfos.add( new WifiChip.RadioModeInfo( radioInfo.radioId, radioInfo.bandInfo, frameworkIfaceInfos)); } mFrameworkCallback.onRadioModeChange(frameworkRadioModeInfos); } } /** * Callback for events on the 1.4 chip. */ private class ChipEventCallbackV14 extends android.hardware.wifi.V1_4.IWifiChipEventCallback.Stub { @Override public void onChipReconfigured(int modeId) throws RemoteException { mHalCallback10.onChipReconfigured(modeId); } @Override public void onChipReconfigureFailure(WifiStatus status) throws RemoteException { mHalCallback10.onChipReconfigureFailure(status); } public void onIfaceAdded(int type, String name) throws RemoteException { mHalCallback10.onIfaceAdded(type, name); } @Override public void onIfaceRemoved(int type, String name) throws RemoteException { mHalCallback10.onIfaceRemoved(type, name); } @Override public void onDebugRingBufferDataAvailable( WifiDebugRingBufferStatus status, java.util.ArrayList data) throws RemoteException { mHalCallback10.onDebugRingBufferDataAvailable(status, data); } @Override public void onDebugErrorAlert(int errorCode, java.util.ArrayList debugData) throws RemoteException { mHalCallback10.onDebugErrorAlert(errorCode, debugData); } @Override public void onRadioModeChange( ArrayList radioModeInfoList) throws RemoteException { mHalCallback12.onRadioModeChange(radioModeInfoList); } @Override public void onRadioModeChange_1_4(ArrayList radioModeInfoList) { if (mFrameworkCallback == null) return; List frameworkRadioModeInfos = new ArrayList<>(); for (RadioModeInfo radioInfo : radioModeInfoList) { List frameworkIfaceInfos = new ArrayList<>(); for (IfaceInfo ifaceInfo : radioInfo.ifaceInfos) { frameworkIfaceInfos.add( new WifiChip.IfaceInfo(ifaceInfo.name, ifaceInfo.channel)); } frameworkRadioModeInfos.add( new WifiChip.RadioModeInfo( radioInfo.radioId, radioInfo.bandInfo, frameworkIfaceInfos)); } mFrameworkCallback.onRadioModeChange(frameworkRadioModeInfos); } } // Helper Functions protected boolean isBridgedSoftApSupportedMockable() { return mIsBridgedSoftApSupported; } protected boolean isStaWithBridgedSoftApConcurrencySupportedMockable() { return mIsStaWithBridgedSoftApConcurrencySupported; } private static final SparseIntArray IFACE_TYPE_TO_CONCURRENCY_TYPE_MAP = new SparseIntArray() {{ put(IfaceType.STA, android.hardware.wifi.V1_6.IfaceConcurrencyType.STA); put(IfaceType.AP, android.hardware.wifi.V1_6.IfaceConcurrencyType.AP); put(IfaceType.P2P, android.hardware.wifi.V1_6.IfaceConcurrencyType.P2P); put(IfaceType.NAN, android.hardware.wifi.V1_6.IfaceConcurrencyType.NAN); }}; private List upgradeV1_0ChipModesToV1_6( List oldChipModes) { ArrayList newChipModes = new ArrayList<>(); for (android.hardware.wifi.V1_0.IWifiChip.ChipMode oldChipMode : oldChipModes) { android.hardware.wifi.V1_6.IWifiChip.ChipMode newChipMode = new android.hardware.wifi.V1_6.IWifiChip.ChipMode(); newChipMode.id = oldChipMode.id; newChipMode.availableCombinations = new ArrayList<>(); for (android.hardware.wifi.V1_0.IWifiChip.ChipIfaceCombination oldCombo : oldChipMode.availableCombinations) { android.hardware.wifi.V1_6.IWifiChip.ChipConcurrencyCombination newCombo = new android.hardware.wifi.V1_6.IWifiChip .ChipConcurrencyCombination(); newCombo.limits = new ArrayList<>(); // Define a duplicate combination list with AP converted to AP_BRIDGED android.hardware.wifi.V1_6.IWifiChip.ChipConcurrencyCombination newComboWithBridgedAp = new android.hardware.wifi.V1_6.IWifiChip.ChipConcurrencyCombination(); newComboWithBridgedAp.limits = new ArrayList<>(); android.hardware.wifi.V1_6.IWifiChip.ChipConcurrencyCombinationLimit bridgedApLimit = new android.hardware.wifi.V1_6.IWifiChip .ChipConcurrencyCombinationLimit(); bridgedApLimit.maxIfaces = 1; bridgedApLimit.types = new ArrayList<>(); bridgedApLimit.types.add(IfaceConcurrencyType.AP_BRIDGED); newComboWithBridgedAp.limits.add(bridgedApLimit); boolean apInCombo = false; // Populate both the combo with AP_BRIDGED and the combo without AP_BRIDGED for (android.hardware.wifi.V1_0.IWifiChip.ChipIfaceCombinationLimit oldLimit : oldCombo.limits) { android.hardware.wifi.V1_6.IWifiChip.ChipConcurrencyCombinationLimit newLimit = new android.hardware.wifi.V1_6 .IWifiChip.ChipConcurrencyCombinationLimit(); newLimit.types = new ArrayList<>(); newLimit.maxIfaces = oldLimit.maxIfaces; for (int oldType : oldLimit.types) { newLimit.types.add(IFACE_TYPE_TO_CONCURRENCY_TYPE_MAP.get(oldType)); } newCombo.limits.add(newLimit); android.hardware.wifi.V1_6.IWifiChip.ChipConcurrencyCombinationLimit newLimitForBridgedApCombo = new android.hardware.wifi.V1_6.IWifiChip .ChipConcurrencyCombinationLimit(); newLimitForBridgedApCombo.types = new ArrayList<>(newLimit.types); newLimitForBridgedApCombo.maxIfaces = newLimit.maxIfaces; if (newLimitForBridgedApCombo.types.contains(IfaceConcurrencyType.AP)) { // Skip the limit if it contains AP, since this corresponds to the // AP_BRIDGED in the duplicate AP_BRIDGED combo. apInCombo = true; } else if (!isStaWithBridgedSoftApConcurrencySupportedMockable() && newLimitForBridgedApCombo.types.contains(IfaceConcurrencyType.STA)) { // Don't include STA in the AP_BRIDGED combo if STA + AP_BRIDGED is not // supported. newLimitForBridgedApCombo.types.remove((Integer) IfaceConcurrencyType.STA); if (!newLimitForBridgedApCombo.types.isEmpty()) { newComboWithBridgedAp.limits.add(newLimitForBridgedApCombo); } } else { newComboWithBridgedAp.limits.add(newLimitForBridgedApCombo); } } newChipMode.availableCombinations.add(newCombo); if (isBridgedSoftApSupportedMockable() && apInCombo) { newChipMode.availableCombinations.add(newComboWithBridgedAp); } } newChipModes.add(newChipMode); } return newChipModes; } private List halToFrameworkChipModeListV1_0( List halModes) { List modes16 = upgradeV1_0ChipModesToV1_6(halModes); return halToFrameworkChipModeListV1_6(modes16); } private static List halToFrameworkChipModeListV1_6( List halModes) { List frameworkModes = new ArrayList<>(); for (android.hardware.wifi.V1_6.IWifiChip.ChipMode halMode : halModes) { frameworkModes.add(halToFrameworkChipModeV1_6(halMode)); } return frameworkModes; } private static WifiChip.ChipMode halToFrameworkChipModeV1_6( android.hardware.wifi.V1_6.IWifiChip.ChipMode halMode) { List frameworkCombos = new ArrayList<>(); for (android.hardware.wifi.V1_6.IWifiChip.ChipConcurrencyCombination halCombo : halMode.availableCombinations) { frameworkCombos.add(halToFrameworkChipConcurrencyCombinationV1_6(halCombo)); } return new WifiChip.ChipMode(halMode.id, frameworkCombos); } private static WifiChip.ChipConcurrencyCombination halToFrameworkChipConcurrencyCombinationV1_6( android.hardware.wifi.V1_6.IWifiChip.ChipConcurrencyCombination halCombo) { List frameworkLimits = new ArrayList<>(); for (android.hardware.wifi.V1_6.IWifiChip.ChipConcurrencyCombinationLimit halLimit : halCombo.limits) { frameworkLimits.add(halToFrameworkChipConcurrencyCombinationLimitV1_6(halLimit)); } return new WifiChip.ChipConcurrencyCombination(frameworkLimits); } private static WifiChip.ChipConcurrencyCombinationLimit halToFrameworkChipConcurrencyCombinationLimitV1_6( android.hardware.wifi.V1_6.IWifiChip.ChipConcurrencyCombinationLimit halLimit) { List frameworkTypes = new ArrayList<>(); for (int halType : halLimit.types) { frameworkTypes.add(halToFrameworkIfaceConcurrencyType(halType)); } return new WifiChip.ChipConcurrencyCombinationLimit(halLimit.maxIfaces, frameworkTypes); } private static @WifiChip.IfaceConcurrencyType int halToFrameworkIfaceConcurrencyType(int type) { switch (type) { case IfaceConcurrencyType.STA: return WifiChip.IFACE_CONCURRENCY_TYPE_STA; case IfaceConcurrencyType.AP: return WifiChip.IFACE_CONCURRENCY_TYPE_AP; case IfaceConcurrencyType.AP_BRIDGED: return WifiChip.IFACE_CONCURRENCY_TYPE_AP_BRIDGED; case IfaceConcurrencyType.P2P: return WifiChip.IFACE_CONCURRENCY_TYPE_P2P; case IfaceConcurrencyType.NAN: return WifiChip.IFACE_CONCURRENCY_TYPE_NAN; default: Log.e(TAG, "Invalid IfaceConcurrencyType received: " + type); return -1; } } private static @WifiChip.IfaceType int halToFrameworkIfaceType(int type) { switch (type) { case IfaceType.STA: return WifiChip.IFACE_TYPE_STA; case IfaceType.AP: return WifiChip.IFACE_TYPE_AP; case IfaceType.P2P: return WifiChip.IFACE_TYPE_P2P; case IfaceType.NAN: return WifiChip.IFACE_TYPE_NAN; default: Log.e(TAG, "Invalid IfaceType received: " + type); return -1; } } private static final long[][] sChipFeatureCapabilityTranslation = { {WifiManager.WIFI_FEATURE_TX_POWER_LIMIT, android.hardware.wifi.V1_1.IWifiChip.ChipCapabilityMask.SET_TX_POWER_LIMIT }, {WifiManager.WIFI_FEATURE_D2D_RTT, android.hardware.wifi.V1_1.IWifiChip.ChipCapabilityMask.D2D_RTT }, {WifiManager.WIFI_FEATURE_D2AP_RTT, android.hardware.wifi.V1_1.IWifiChip.ChipCapabilityMask.D2AP_RTT } }; /** * Translation table used by getSupportedFeatureSet for translating IWifiChip caps for * additional capabilities introduced in V1.5 */ private static final long[][] sChipFeatureCapabilityTranslation15 = { {WifiManager.WIFI_FEATURE_INFRA_60G, android.hardware.wifi.V1_5.IWifiChip.ChipCapabilityMask.WIGIG } }; /** * Translation table used by getSupportedFeatureSet for translating IWifiChip caps for * additional capabilities introduced in V1.3 */ private static final long[][] sChipFeatureCapabilityTranslation13 = { {WifiManager.WIFI_FEATURE_LOW_LATENCY, android.hardware.wifi.V1_3.IWifiChip.ChipCapabilityMask.SET_LATENCY_MODE }, {WifiManager.WIFI_FEATURE_P2P_RAND_MAC, android.hardware.wifi.V1_3.IWifiChip.ChipCapabilityMask.P2P_RAND_MAC } }; /** * Feature bit mask translation for Chip V1.1 * * @param capabilities bitmask defined IWifiChip.ChipCapabilityMask * @return bitmask defined by WifiManager.WIFI_FEATURE_* */ @VisibleForTesting int wifiFeatureMaskFromChipCapabilities(int capabilities) { int features = 0; for (int i = 0; i < sChipFeatureCapabilityTranslation.length; i++) { if ((capabilities & sChipFeatureCapabilityTranslation[i][1]) != 0) { features |= sChipFeatureCapabilityTranslation[i][0]; } } return features; } /** * Feature bit mask translation for Chip V1.5 * * @param capabilities bitmask defined IWifiChip.ChipCapabilityMask * @return bitmask defined by WifiManager.WIFI_FEATURE_* */ @VisibleForTesting long wifiFeatureMaskFromChipCapabilities_1_5(int capabilities) { // First collect features from previous versions long features = wifiFeatureMaskFromChipCapabilities_1_3(capabilities); // Next collect features for V1_5 version for (int i = 0; i < sChipFeatureCapabilityTranslation15.length; i++) { if ((capabilities & sChipFeatureCapabilityTranslation15[i][1]) != 0) { features |= sChipFeatureCapabilityTranslation15[i][0]; } } return features; } /** * Feature bit mask translation for Chip V1.3 * * @param capabilities bitmask defined IWifiChip.ChipCapabilityMask * @return bitmask defined by WifiManager.WIFI_FEATURE_* */ @VisibleForTesting long wifiFeatureMaskFromChipCapabilities_1_3(int capabilities) { // First collect features from previous versions long features = wifiFeatureMaskFromChipCapabilities(capabilities); // Next collect features for V1_3 version for (int i = 0; i < sChipFeatureCapabilityTranslation13.length; i++) { if ((capabilities & sChipFeatureCapabilityTranslation13[i][1]) != 0) { features |= sChipFeatureCapabilityTranslation13[i][0]; } } return features; } /** * Translates from Hal version of wake reason stats to the framework version of same * * @param h - Hal version of wake reason stats * @return framework version of same */ private static WlanWakeReasonAndCounts halToFrameworkWakeReasons( WifiDebugHostWakeReasonStats h) { if (h == null) return null; WlanWakeReasonAndCounts ans = new WlanWakeReasonAndCounts(); ans.totalCmdEventWake = h.totalCmdEventWakeCnt; ans.totalDriverFwLocalWake = h.totalDriverFwLocalWakeCnt; ans.totalRxDataWake = h.totalRxPacketWakeCnt; ans.rxUnicast = h.rxPktWakeDetails.rxUnicastCnt; ans.rxMulticast = h.rxPktWakeDetails.rxMulticastCnt; ans.rxBroadcast = h.rxPktWakeDetails.rxBroadcastCnt; ans.icmp = h.rxIcmpPkWakeDetails.icmpPkt; ans.icmp6 = h.rxIcmpPkWakeDetails.icmp6Pkt; ans.icmp6Ra = h.rxIcmpPkWakeDetails.icmp6Ra; ans.icmp6Na = h.rxIcmpPkWakeDetails.icmp6Na; ans.icmp6Ns = h.rxIcmpPkWakeDetails.icmp6Ns; ans.ipv4RxMulticast = h.rxMulticastPkWakeDetails.ipv4RxMulticastAddrCnt; ans.ipv6Multicast = h.rxMulticastPkWakeDetails.ipv6RxMulticastAddrCnt; ans.otherRxMulticast = h.rxMulticastPkWakeDetails.otherRxMulticastAddrCnt; ans.cmdEventWakeCntArray = intsFromArrayList(h.cmdEventWakeCntPerType); ans.driverFWLocalWakeCntArray = intsFromArrayList(h.driverFwLocalWakeCntPerType); return ans; } /** * Creates array of RingBufferStatus from the Hal version */ private static WifiNative.RingBufferStatus[] makeRingBufferStatusArray( ArrayList ringBuffers) { WifiNative.RingBufferStatus[] ans = new WifiNative.RingBufferStatus[ringBuffers.size()]; int i = 0; for (WifiDebugRingBufferStatus b : ringBuffers) { ans[i++] = halToFrameworkRingBufferStatus(b); } return ans; } /** * Creates RingBufferStatus from the Hal version */ private static WifiNative.RingBufferStatus halToFrameworkRingBufferStatus( WifiDebugRingBufferStatus h) { WifiNative.RingBufferStatus ans = new WifiNative.RingBufferStatus(); ans.name = h.ringName; ans.flag = frameworkRingBufferFlagsFromHal(h.flags); ans.ringBufferId = h.ringId; ans.ringBufferByteSize = h.sizeInBytes; ans.verboseLevel = h.verboseLevel; // Remaining fields are unavailable // writtenBytes; // readBytes; // writtenRecords; return ans; } /** * Translates a hal wifiDebugRingBufferFlag to the WifiNative version */ private static int frameworkRingBufferFlagsFromHal(int wifiDebugRingBufferFlag) { BitMask checkoff = new BitMask(wifiDebugRingBufferFlag); int flags = 0; if (checkoff.testAndClear(WifiDebugRingBufferFlags.HAS_BINARY_ENTRIES)) { flags |= WifiNative.RingBufferStatus.HAS_BINARY_ENTRIES; } if (checkoff.testAndClear(WifiDebugRingBufferFlags.HAS_ASCII_ENTRIES)) { flags |= WifiNative.RingBufferStatus.HAS_ASCII_ENTRIES; } if (checkoff.testAndClear(WifiDebugRingBufferFlags.HAS_PER_PACKET_ENTRIES)) { flags |= WifiNative.RingBufferStatus.HAS_PER_PACKET_ENTRIES; } if (checkoff.value != 0) { throw new IllegalArgumentException("Unknown WifiDebugRingBufferFlag " + checkoff.value); } return flags; } private static List halToFrameworkRadioCombinations( List halCombos) { List frameworkCombos = new ArrayList<>(); for (WifiRadioCombination combo : halCombos) { frameworkCombos.add(halToFrameworkRadioCombination(combo)); } return frameworkCombos; } private static WifiChip.WifiRadioCombination halToFrameworkRadioCombination( WifiRadioCombination halCombo) { List frameworkConfigs = new ArrayList<>(); for (WifiRadioConfiguration config : halCombo.radioConfigurations) { frameworkConfigs.add(halToFrameworkRadioConfiguration(config)); } return new WifiChip.WifiRadioCombination(frameworkConfigs); } private static WifiChip.WifiRadioConfiguration halToFrameworkRadioConfiguration( WifiRadioConfiguration halConfig) { return new WifiChip.WifiRadioConfiguration(halToFrameworkWifiBand(halConfig.bandInfo), halToFrameworkAntennaMode(halConfig.antennaMode)); } /** * Makes the Hal flavor of WifiScanner's band indication * * Note: This method is only used by background scan which does not * support 6GHz, hence band combinations including 6GHz are considered invalid * * @param frameworkBand one of WifiScanner.WIFI_BAND_* * @return A WifiBand value * @throws IllegalArgumentException if frameworkBand is not recognized */ private static int frameworkToHalWifiBand(int frameworkBand) { switch (frameworkBand) { case WifiScanner.WIFI_BAND_UNSPECIFIED: return WifiBand.BAND_UNSPECIFIED; case WifiScanner.WIFI_BAND_24_GHZ: return WifiBand.BAND_24GHZ; case WifiScanner.WIFI_BAND_5_GHZ: return WifiBand.BAND_5GHZ; case WifiScanner.WIFI_BAND_5_GHZ_DFS_ONLY: return WifiBand.BAND_5GHZ_DFS; case WifiScanner.WIFI_BAND_5_GHZ_WITH_DFS: return WifiBand.BAND_5GHZ_WITH_DFS; case WifiScanner.WIFI_BAND_BOTH: return WifiBand.BAND_24GHZ_5GHZ; case WifiScanner.WIFI_BAND_BOTH_WITH_DFS: return WifiBand.BAND_24GHZ_5GHZ_WITH_DFS; case WifiScanner.WIFI_BAND_6_GHZ: return WifiBand.BAND_6GHZ; case WifiScanner.WIFI_BAND_24_5_6_GHZ: return WifiBand.BAND_24GHZ_5GHZ_6GHZ; case WifiScanner.WIFI_BAND_24_5_WITH_DFS_6_GHZ: return WifiBand.BAND_24GHZ_5GHZ_WITH_DFS_6GHZ; case WifiScanner.WIFI_BAND_60_GHZ: return WifiBand.BAND_60GHZ; case WifiScanner.WIFI_BAND_24_5_6_60_GHZ: return WifiBand.BAND_24GHZ_5GHZ_6GHZ_60GHZ; case WifiScanner.WIFI_BAND_24_5_WITH_DFS_6_60_GHZ: return WifiBand.BAND_24GHZ_5GHZ_WITH_DFS_6GHZ_60GHZ; case WifiScanner.WIFI_BAND_24_GHZ_WITH_5GHZ_DFS: default: throw new IllegalArgumentException("bad band " + frameworkBand); } } private static boolean bitmapContains(int bitmap, int expectedBit) { return (bitmap & expectedBit) != 0; } private static int halToFrameworkWifiBand(int halBand) { int frameworkBand = 0; if (bitmapContains(halBand, WifiBand.BAND_24GHZ)) { frameworkBand |= WifiScanner.WIFI_BAND_24_GHZ; } if (bitmapContains(halBand, WifiBand.BAND_5GHZ)) { frameworkBand |= WifiScanner.WIFI_BAND_5_GHZ; } if (bitmapContains(halBand, WifiBand.BAND_5GHZ_DFS)) { frameworkBand |= WifiScanner.WIFI_BAND_5_GHZ_DFS_ONLY; } if (bitmapContains(halBand, WifiBand.BAND_6GHZ)) { frameworkBand |= WifiScanner.WIFI_BAND_6_GHZ; } if (bitmapContains(halBand, WifiBand.BAND_60GHZ)) { frameworkBand |= WifiScanner.WIFI_BAND_60_GHZ; } return frameworkBand; } private static @WifiChip.WifiAntennaMode int halToFrameworkAntennaMode(int mode) { switch (mode) { case WifiAntennaMode.WIFI_ANTENNA_MODE_UNSPECIFIED: return WifiChip.WIFI_ANTENNA_MODE_UNSPECIFIED; case WifiAntennaMode.WIFI_ANTENNA_MODE_1X1: return WifiChip.WIFI_ANTENNA_MODE_1X1; case WifiAntennaMode.WIFI_ANTENNA_MODE_2X2: return WifiChip.WIFI_ANTENNA_MODE_2X2; case WifiAntennaMode.WIFI_ANTENNA_MODE_3X3: return WifiChip.WIFI_ANTENNA_MODE_3X3; case WifiAntennaMode.WIFI_ANTENNA_MODE_4X4: return WifiChip.WIFI_ANTENNA_MODE_4X4; default: Log.e(TAG, "Invalid WifiAntennaMode: " + mode); return -1; } } /** * Convert framework's operational mode to HAL's operational mode. */ private int frameworkToHalIfaceMode(@WifiAvailableChannel.OpMode int mode) { int halMode = 0; if ((mode & WifiAvailableChannel.OP_MODE_STA) != 0) { halMode |= WifiIfaceMode.IFACE_MODE_STA; } if ((mode & WifiAvailableChannel.OP_MODE_SAP) != 0) { halMode |= WifiIfaceMode.IFACE_MODE_SOFTAP; } if ((mode & WifiAvailableChannel.OP_MODE_WIFI_DIRECT_CLI) != 0) { halMode |= WifiIfaceMode.IFACE_MODE_P2P_CLIENT; } if ((mode & WifiAvailableChannel.OP_MODE_WIFI_DIRECT_GO) != 0) { halMode |= WifiIfaceMode.IFACE_MODE_P2P_GO; } if ((mode & WifiAvailableChannel.OP_MODE_WIFI_AWARE) != 0) { halMode |= WifiIfaceMode.IFACE_MODE_NAN; } if ((mode & WifiAvailableChannel.OP_MODE_TDLS) != 0) { halMode |= WifiIfaceMode.IFACE_MODE_TDLS; } return halMode; } /** * Convert framework's WifiAvailableChannel.FILTER_* to HAL's UsableChannelFilter. */ private int frameworkToHalUsableFilter(@WifiAvailableChannel.Filter int filter) { int halFilter = 0; // O implies no additional filter other than regulatory (default) if ((filter & WifiAvailableChannel.FILTER_CONCURRENCY) != 0) { halFilter |= android.hardware.wifi.V1_6.IWifiChip.UsableChannelFilter.CONCURRENCY; } if ((filter & WifiAvailableChannel.FILTER_CELLULAR_COEXISTENCE) != 0) { halFilter |= android.hardware.wifi.V1_6.IWifiChip.UsableChannelFilter .CELLULAR_COEXISTENCE; } return halFilter; } /** * Convert framework's WifiAvailableChannel.FILTER_* to HAL's UsableChannelFilter 1.6. */ private int frameworkToHalUsableFilter_1_6(@WifiAvailableChannel.Filter int filter) { int halFilter = 0; // O implies no additional filter other than regulatory (default) if ((filter & WifiAvailableChannel.FILTER_CONCURRENCY) != 0) { halFilter |= android.hardware.wifi.V1_6.IWifiChip.UsableChannelFilter.CONCURRENCY; } if ((filter & WifiAvailableChannel.FILTER_CELLULAR_COEXISTENCE) != 0) { halFilter |= android.hardware.wifi.V1_6.IWifiChip.UsableChannelFilter .CELLULAR_COEXISTENCE; } if ((filter & WifiAvailableChannel.FILTER_NAN_INSTANT_MODE) != 0) { halFilter |= android.hardware.wifi.V1_6.IWifiChip.UsableChannelFilter.NAN_INSTANT_MODE; } return halFilter; } /** * Convert from HAL's operational mode to framework's operational mode. */ private @WifiAvailableChannel.OpMode int halToFrameworkIfaceMode(int halMode) { int mode = 0; if ((halMode & WifiIfaceMode.IFACE_MODE_STA) != 0) { mode |= WifiAvailableChannel.OP_MODE_STA; } if ((halMode & WifiIfaceMode.IFACE_MODE_SOFTAP) != 0) { mode |= WifiAvailableChannel.OP_MODE_SAP; } if ((halMode & WifiIfaceMode.IFACE_MODE_P2P_CLIENT) != 0) { mode |= WifiAvailableChannel.OP_MODE_WIFI_DIRECT_CLI; } if ((halMode & WifiIfaceMode.IFACE_MODE_P2P_GO) != 0) { mode |= WifiAvailableChannel.OP_MODE_WIFI_DIRECT_GO; } if ((halMode & WifiIfaceMode.IFACE_MODE_NAN) != 0) { mode |= WifiAvailableChannel.OP_MODE_WIFI_AWARE; } if ((halMode & WifiIfaceMode.IFACE_MODE_TDLS) != 0) { mode |= WifiAvailableChannel.OP_MODE_TDLS; } return mode; } @NonNull private ArrayList frameworkCoexUnsafeChannelsToHidl( @NonNull List frameworkUnsafeChannels) { final ArrayList hidlList = new ArrayList<>(); if (!SdkLevel.isAtLeastS()) { return hidlList; } for (android.net.wifi.CoexUnsafeChannel frameworkUnsafeChannel : frameworkUnsafeChannels) { final android.hardware.wifi.V1_5.IWifiChip.CoexUnsafeChannel hidlUnsafeChannel = new android.hardware.wifi.V1_5.IWifiChip.CoexUnsafeChannel(); switch (frameworkUnsafeChannel.getBand()) { case (WifiScanner.WIFI_BAND_24_GHZ): hidlUnsafeChannel.band = WifiBand.BAND_24GHZ; break; case (WifiScanner.WIFI_BAND_5_GHZ): hidlUnsafeChannel.band = WifiBand.BAND_5GHZ; break; case (WifiScanner.WIFI_BAND_6_GHZ): hidlUnsafeChannel.band = WifiBand.BAND_6GHZ; break; case (WifiScanner.WIFI_BAND_60_GHZ): hidlUnsafeChannel.band = WifiBand.BAND_60GHZ; break; default: Log.e(TAG, "Tried to set unsafe channel with unknown band: " + frameworkUnsafeChannel.getBand()); continue; } hidlUnsafeChannel.channel = frameworkUnsafeChannel.getChannel(); final int powerCapDbm = frameworkUnsafeChannel.getPowerCapDbm(); if (powerCapDbm != POWER_CAP_NONE) { hidlUnsafeChannel.powerCapDbm = powerCapDbm; } else { hidlUnsafeChannel.powerCapDbm = android.hardware.wifi.V1_5.IWifiChip.PowerCapConstant.NO_POWER_CAP; } hidlList.add(hidlUnsafeChannel); } return hidlList; } private int frameworkCoexRestrictionsToHidl(@WifiManager.CoexRestriction int restrictions) { int hidlRestrictions = 0; if (!SdkLevel.isAtLeastS()) { return hidlRestrictions; } if ((restrictions & WifiManager.COEX_RESTRICTION_WIFI_DIRECT) != 0) { hidlRestrictions |= android.hardware.wifi.V1_5.IWifiChip.CoexRestriction.WIFI_DIRECT; } if ((restrictions & WifiManager.COEX_RESTRICTION_SOFTAP) != 0) { hidlRestrictions |= android.hardware.wifi.V1_5.IWifiChip.CoexRestriction.SOFTAP; } if ((restrictions & WifiManager.COEX_RESTRICTION_WIFI_AWARE) != 0) { hidlRestrictions |= android.hardware.wifi.V1_5.IWifiChip.CoexRestriction.WIFI_AWARE; } return hidlRestrictions; } private byte frameworkMultiStaUseCaseToHidl(@WifiNative.MultiStaUseCase int useCase) throws IllegalArgumentException { switch (useCase) { case WifiNative.DUAL_STA_TRANSIENT_PREFER_PRIMARY: return android.hardware.wifi.V1_5.IWifiChip .MultiStaUseCase.DUAL_STA_TRANSIENT_PREFER_PRIMARY; case WifiNative.DUAL_STA_NON_TRANSIENT_UNBIASED: return android.hardware.wifi.V1_5.IWifiChip .MultiStaUseCase.DUAL_STA_NON_TRANSIENT_UNBIASED; default: throw new IllegalArgumentException("Invalid use case " + useCase); } } /** * This method checks if we need to backoff wifi Tx power due to SAR requirements. * It handles the case when the device is running the V1_1 version of WifiChip HAL * In that HAL version, it is required to perform wifi Tx power backoff only if * a voice call is ongoing. */ private static boolean sarPowerBackoffRequired_1_1(SarInfo sarInfo) { /* As long as no voice call is active (in case voice call is supported), * no backoff is needed */ if (sarInfo.sarVoiceCallSupported) { return (sarInfo.isVoiceCall || sarInfo.isEarPieceActive); } else { return false; } } /** * This method maps the information inside the SarInfo instance into a SAR scenario * when device is running the V1_1 version of WifiChip HAL. * In this HAL version, only one scenario is defined which is for VOICE_CALL (if voice call is * supported). * Otherwise, an exception is thrown. */ private static int frameworkToHalTxPowerScenario_1_1(SarInfo sarInfo) { if (sarInfo.sarVoiceCallSupported && (sarInfo.isVoiceCall || sarInfo.isEarPieceActive)) { return android.hardware.wifi.V1_1.IWifiChip.TxPowerScenario.VOICE_CALL; } else { throw new IllegalArgumentException("bad scenario: voice call not active/supported"); } } /** * This method checks if we need to backoff wifi Tx power due to SAR requirements. * It handles the case when the device is running the V1_2 version of WifiChip HAL */ private static boolean sarPowerBackoffRequired_1_2(SarInfo sarInfo) { if (sarInfo.sarSapSupported && sarInfo.isWifiSapEnabled) { return true; } if (sarInfo.sarVoiceCallSupported && (sarInfo.isVoiceCall || sarInfo.isEarPieceActive)) { return true; } return false; } /** * This method maps the information inside the SarInfo instance into a SAR scenario * when device is running the V1_2 version of WifiChip HAL. * If SAR SoftAP input is supported, * we make these assumptions: * - All voice calls are treated as if device is near the head. * - SoftAP scenario is treated as if device is near the body. * In case SoftAP is not supported, then we should revert to the V1_1 HAL * behavior, and the only valid scenario would be when a voice call is ongoing. */ private static int frameworkToHalTxPowerScenario_1_2(SarInfo sarInfo) { if (sarInfo.sarSapSupported && sarInfo.sarVoiceCallSupported) { if (sarInfo.isVoiceCall || sarInfo.isEarPieceActive) { return android.hardware.wifi.V1_2.IWifiChip .TxPowerScenario.ON_HEAD_CELL_ON; } else if (sarInfo.isWifiSapEnabled) { return android.hardware.wifi.V1_2.IWifiChip .TxPowerScenario.ON_BODY_CELL_ON; } else { throw new IllegalArgumentException("bad scenario: no voice call/softAP active"); } } else if (sarInfo.sarVoiceCallSupported) { /* SAR SoftAP input not supported, act like V1_1 */ if (sarInfo.isVoiceCall || sarInfo.isEarPieceActive) { return android.hardware.wifi.V1_1.IWifiChip.TxPowerScenario.VOICE_CALL; } else { throw new IllegalArgumentException("bad scenario: voice call not active"); } } else { throw new IllegalArgumentException("Invalid case: voice call not supported"); } } protected android.hardware.wifi.V1_1.IWifiChip getWifiChipV1_1Mockable() { return android.hardware.wifi.V1_1.IWifiChip.castFrom(mWifiChip); } protected android.hardware.wifi.V1_2.IWifiChip getWifiChipV1_2Mockable() { return android.hardware.wifi.V1_2.IWifiChip.castFrom(mWifiChip); } protected android.hardware.wifi.V1_3.IWifiChip getWifiChipV1_3Mockable() { return android.hardware.wifi.V1_3.IWifiChip.castFrom(mWifiChip); } protected android.hardware.wifi.V1_4.IWifiChip getWifiChipV1_4Mockable() { return android.hardware.wifi.V1_4.IWifiChip.castFrom(mWifiChip); } protected android.hardware.wifi.V1_5.IWifiChip getWifiChipV1_5Mockable() { return android.hardware.wifi.V1_5.IWifiChip.castFrom(mWifiChip); } protected android.hardware.wifi.V1_6.IWifiChip getWifiChipV1_6Mockable() { return android.hardware.wifi.V1_6.IWifiChip.castFrom(mWifiChip); } private static int[] intsFromArrayList(ArrayList a) { if (a == null) return null; int[] b = new int[a.size()]; int i = 0; for (Integer e : a) b[i++] = e; return b; } private boolean isOk(WifiStatus status, String methodStr) { if (status.code == WifiStatusCode.SUCCESS) return true; Log.e(TAG, methodStr + " failed with status: " + status); return false; } private void handleRemoteException(RemoteException e, String methodStr) { Log.e(TAG, methodStr + " failed with remote exception: " + e); mWifiChip = null; } private T validateAndCall(String methodStr, T defaultVal, @NonNull Supplier supplier) { if (mWifiChip == null) { Log.e(TAG, "Cannot call " + methodStr + " because mWifiChip is null"); return defaultVal; } return supplier.get(); } }