summaryrefslogtreecommitdiff
path: root/service/java/com/android/server/wifi/HostapdHal.java
diff options
context:
space:
mode:
Diffstat (limited to 'service/java/com/android/server/wifi/HostapdHal.java')
-rw-r--r--service/java/com/android/server/wifi/HostapdHal.java1067
1 files changed, 0 insertions, 1067 deletions
diff --git a/service/java/com/android/server/wifi/HostapdHal.java b/service/java/com/android/server/wifi/HostapdHal.java
deleted file mode 100644
index 1ff8368e3..000000000
--- a/service/java/com/android/server/wifi/HostapdHal.java
+++ /dev/null
@@ -1,1067 +0,0 @@
-/*
- * Copyright (C) 2017 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;
-
-
-import android.annotation.NonNull;
-import android.content.Context;
-import android.hardware.wifi.hostapd.V1_0.HostapdStatus;
-import android.hardware.wifi.hostapd.V1_0.HostapdStatusCode;
-import android.hardware.wifi.hostapd.V1_0.IHostapd;
-import android.hardware.wifi.hostapd.V1_2.DebugLevel;
-import android.hardware.wifi.hostapd.V1_2.Ieee80211ReasonCode;
-import android.hidl.manager.V1_0.IServiceManager;
-import android.hidl.manager.V1_0.IServiceNotification;
-import android.net.MacAddress;
-import android.net.wifi.SoftApConfiguration;
-import android.net.wifi.SoftApConfiguration.BandType;
-import android.net.wifi.WifiManager;
-import android.os.Handler;
-import android.os.IHwBinder.DeathRecipient;
-import android.os.RemoteException;
-import android.text.TextUtils;
-import android.util.Log;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.server.wifi.WifiNative.HostapdDeathEventHandler;
-import com.android.server.wifi.util.ApConfigUtil;
-import com.android.server.wifi.util.NativeUtil;
-import com.android.wifi.resources.R;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.NoSuchElementException;
-import java.util.Random;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-
-import javax.annotation.concurrent.ThreadSafe;
-
-/**
- * To maintain thread-safety, the locking protocol is that every non-static method (regardless of
- * access level) acquires mLock.
- */
-@ThreadSafe
-public class HostapdHal {
- private static final String TAG = "HostapdHal";
- @VisibleForTesting
- public static final String HAL_INSTANCE_NAME = "default";
- @VisibleForTesting
- public static final long WAIT_FOR_DEATH_TIMEOUT_MS = 50L;
-
- private final Object mLock = new Object();
- private boolean mVerboseLoggingEnabled = false;
- private final Context mContext;
- private final Handler mEventHandler;
- private boolean mForceApChannel = false;
- private int mForcedApBand;
- private int mForcedApChannel;
- private String mConfig2gChannelList;
- private String mConfig5gChannelList;
- private String mConfig6gChannelList;
-
- // Hostapd HAL interface objects
- private IServiceManager mIServiceManager = null;
- private IHostapd mIHostapd;
- private HashMap<String, Runnable> mSoftApFailureListeners = new HashMap<>();
- private HostapdDeathEventHandler mDeathEventHandler;
- private ServiceManagerDeathRecipient mServiceManagerDeathRecipient;
- private HostapdDeathRecipient mHostapdDeathRecipient;
- // Death recipient cookie registered for current supplicant instance.
- private long mDeathRecipientCookie = 0;
-
- private final IServiceNotification mServiceNotificationCallback =
- new IServiceNotification.Stub() {
- public void onRegistration(String fqName, String name, boolean preexisting) {
- synchronized (mLock) {
- if (mVerboseLoggingEnabled) {
- Log.i(TAG, "IServiceNotification.onRegistration for: " + fqName
- + ", " + name + " preexisting=" + preexisting);
- }
- if (!initHostapdService()) {
- Log.e(TAG, "initalizing IHostapd failed.");
- hostapdServiceDiedHandler(mDeathRecipientCookie);
- } else {
- Log.i(TAG, "Completed initialization of IHostapd.");
- }
- }
- }
- };
- private class ServiceManagerDeathRecipient implements DeathRecipient {
- @Override
- public void serviceDied(long cookie) {
- mEventHandler.post(() -> {
- synchronized (mLock) {
- Log.w(TAG, "IServiceManager died: cookie=" + cookie);
- hostapdServiceDiedHandler(mDeathRecipientCookie);
- mIServiceManager = null; // Will need to register a new ServiceNotification
- }
- });
- }
- }
- private class HostapdDeathRecipient implements DeathRecipient {
- @Override
- public void serviceDied(long cookie) {
- mEventHandler.post(() -> {
- synchronized (mLock) {
- Log.w(TAG, "IHostapd/IHostapd died: cookie=" + cookie);
- hostapdServiceDiedHandler(cookie);
- }
- });
- }
- }
-
- public HostapdHal(Context context, Handler handler) {
- mContext = context;
- mEventHandler = handler;
- mServiceManagerDeathRecipient = new ServiceManagerDeathRecipient();
- mHostapdDeathRecipient = new HostapdDeathRecipient();
- }
-
- /**
- * Enable/Disable verbose logging.
- *
- * @param enable true to enable, false to disable.
- */
- void enableVerboseLogging(boolean enable) {
- synchronized (mLock) {
- mVerboseLoggingEnabled = enable;
- setLogLevel();
- }
- }
-
- /**
- * Uses the IServiceManager to check if the device is running V1_1 of the HAL from the VINTF for
- * the device.
- * @return true if supported, false otherwise.
- */
- private boolean isV1_1() {
- return checkHalVersionByInterfaceName(
- android.hardware.wifi.hostapd.V1_1.IHostapd.kInterfaceName);
- }
-
- /**
- * Uses the IServiceManager to check if the device is running V1_2 of the HAL from the VINTF for
- * the device.
- * @return true if supported, false otherwise.
- */
- private boolean isV1_2() {
- return checkHalVersionByInterfaceName(
- android.hardware.wifi.hostapd.V1_2.IHostapd.kInterfaceName);
- }
-
- private boolean checkHalVersionByInterfaceName(String interfaceName) {
- if (interfaceName == null) {
- return false;
- }
- synchronized (mLock) {
- if (mIServiceManager == null) {
- Log.e(TAG, "checkHalVersionByInterfaceName called but mServiceManager is null!?");
- return false;
- }
- try {
- return (mIServiceManager.getTransport(
- interfaceName,
- HAL_INSTANCE_NAME)
- != IServiceManager.Transport.EMPTY);
- } catch (RemoteException e) {
- Log.e(TAG, "Exception while operating on IServiceManager: " + e);
- handleRemoteException(e, "getTransport");
- return false;
- }
- }
- }
-
- /**
- * Link to death for IServiceManager object.
- * @return true on success, false otherwise.
- */
- private boolean linkToServiceManagerDeath() {
- synchronized (mLock) {
- if (mIServiceManager == null) return false;
- try {
- if (!mIServiceManager.linkToDeath(mServiceManagerDeathRecipient, 0)) {
- Log.wtf(TAG, "Error on linkToDeath on IServiceManager");
- hostapdServiceDiedHandler(mDeathRecipientCookie);
- mIServiceManager = null; // Will need to register a new ServiceNotification
- return false;
- }
- } catch (RemoteException e) {
- Log.e(TAG, "IServiceManager.linkToDeath exception", e);
- mIServiceManager = null; // Will need to register a new ServiceNotification
- return false;
- }
- return true;
- }
- }
-
- /**
- * Registers a service notification for the IHostapd service, which triggers intialization of
- * the IHostapd
- * @return true if the service notification was successfully registered
- */
- public boolean initialize() {
- synchronized (mLock) {
- if (mVerboseLoggingEnabled) {
- Log.i(TAG, "Registering IHostapd service ready callback.");
- }
- mIHostapd = null;
- if (mIServiceManager != null) {
- // Already have an IServiceManager and serviceNotification registered, don't
- // don't register another.
- return true;
- }
- try {
- mIServiceManager = getServiceManagerMockable();
- if (mIServiceManager == null) {
- Log.e(TAG, "Failed to get HIDL Service Manager");
- return false;
- }
- if (!linkToServiceManagerDeath()) {
- return false;
- }
- /* TODO(b/33639391) : Use the new IHostapd.registerForNotifications() once it
- exists */
- if (!mIServiceManager.registerForNotifications(
- IHostapd.kInterfaceName, "", mServiceNotificationCallback)) {
- Log.e(TAG, "Failed to register for notifications to "
- + IHostapd.kInterfaceName);
- mIServiceManager = null; // Will need to register a new ServiceNotification
- return false;
- }
- } catch (RemoteException e) {
- Log.e(TAG, "Exception while trying to register a listener for IHostapd service: "
- + e);
- hostapdServiceDiedHandler(mDeathRecipientCookie);
- mIServiceManager = null; // Will need to register a new ServiceNotification
- return false;
- }
- return true;
- }
- }
-
- /**
- * Link to death for IHostapd object.
- * @return true on success, false otherwise.
- */
- private boolean linkToHostapdDeath(DeathRecipient deathRecipient, long cookie) {
- synchronized (mLock) {
- if (mIHostapd == null) return false;
- try {
- if (!mIHostapd.linkToDeath(deathRecipient, cookie)) {
- Log.wtf(TAG, "Error on linkToDeath on IHostapd");
- hostapdServiceDiedHandler(mDeathRecipientCookie);
- return false;
- }
- } catch (RemoteException e) {
- Log.e(TAG, "IHostapd.linkToDeath exception", e);
- return false;
- }
- return true;
- }
- }
-
- private boolean registerCallback(
- android.hardware.wifi.hostapd.V1_1.IHostapdCallback callback) {
- synchronized (mLock) {
- String methodStr = "registerCallback_1_1";
- try {
- android.hardware.wifi.hostapd.V1_1.IHostapd iHostapdV1_1 = getHostapdMockableV1_1();
- if (iHostapdV1_1 == null) return false;
- HostapdStatus status = iHostapdV1_1.registerCallback(callback);
- return checkStatusAndLogFailure(status, methodStr);
- } catch (RemoteException e) {
- handleRemoteException(e, methodStr);
- return false;
- }
- }
- }
-
- /**
- * Initialize the IHostapd object.
- * @return true on success, false otherwise.
- */
- private boolean initHostapdService() {
- synchronized (mLock) {
- try {
- mIHostapd = getHostapdMockable();
- } catch (RemoteException e) {
- Log.e(TAG, "IHostapd.getService exception: " + e);
- return false;
- } catch (NoSuchElementException e) {
- Log.e(TAG, "IHostapd.getService exception: " + e);
- return false;
- }
- if (mIHostapd == null) {
- Log.e(TAG, "Got null IHostapd service. Stopping hostapd HIDL startup");
- return false;
- }
- if (!linkToHostapdDeath(mHostapdDeathRecipient, ++mDeathRecipientCookie)) {
- Log.e(TAG, "Fail to link to Hostapd Death, Stopping hostapd HIDL startup");
- mIHostapd = null;
- return false;
- }
- // Register for callbacks for 1.1 hostapd.
- if (isV1_1() && !registerCallback(new HostapdCallback())) {
- Log.e(TAG, "Fail to regiester Callback, Stopping hostapd HIDL startup");
- mIHostapd = null;
- return false;
- }
-
- // Setup log level
- setLogLevel();
- }
- return true;
- }
-
- /**
- * Enable force-soft-AP-channel mode which takes effect when soft AP starts next time
- * @param forcedApChannel The forced IEEE channel number
- */
- void enableForceSoftApChannel(int forcedApChannel, int forcedApBand) {
- mForceApChannel = true;
- mForcedApChannel = forcedApChannel;
- mForcedApBand = forcedApBand;
- }
-
- /**
- * Disable force-soft-AP-channel mode which take effect when soft AP starts next time
- */
- void disableForceSoftApChannel() {
- mForceApChannel = false;
- }
-
- private boolean isSendFreqRangesNeeded(@BandType int band) {
- // Fist we check if one of the selected bands has restrictions in the overlay file.
- // Note,
- // - We store the config string here for future use, hence we need to check all bands.
- // - If there is no OEM restriction, we store the full band
- boolean retVal = false;
- if ((band & SoftApConfiguration.BAND_2GHZ) != 0) {
- mConfig2gChannelList =
- mContext.getResources().getString(R.string.config_wifiSoftap2gChannelList);
- if (TextUtils.isEmpty(mConfig2gChannelList)) {
- mConfig2gChannelList = "1-14";
- } else {
- retVal = true;
- }
- }
-
- if ((band & SoftApConfiguration.BAND_5GHZ) != 0) {
- mConfig5gChannelList =
- mContext.getResources().getString(R.string.config_wifiSoftap5gChannelList);
- if (TextUtils.isEmpty(mConfig5gChannelList)) {
- mConfig5gChannelList = "34-173";
- } else {
- retVal = true;
- }
- }
-
- if ((band & SoftApConfiguration.BAND_6GHZ) != 0) {
- mConfig6gChannelList =
- mContext.getResources().getString(R.string.config_wifiSoftap6gChannelList);
- if (TextUtils.isEmpty(mConfig6gChannelList)) {
- mConfig6gChannelList = "1-254";
- } else {
- retVal = true;
- }
- }
-
- // If any of the selected band has restriction in the overlay file, we return true.
- if (retVal) {
- return true;
- }
-
- // Next, if only one of 5G or 6G is selected, then we need freqList to separate them
- // Since there is no other way.
- if (((band & SoftApConfiguration.BAND_5GHZ) != 0)
- && ((band & SoftApConfiguration.BAND_6GHZ) == 0)) {
- return true;
- }
- if (((band & SoftApConfiguration.BAND_5GHZ) == 0)
- && ((band & SoftApConfiguration.BAND_6GHZ) != 0)) {
- return true;
- }
-
- // In all other cases, we don't need to set the freqList
- return false;
- }
-
- /**
- * Add and start a new access point.
- *
- * @param ifaceName Name of the interface.
- * @param config Configuration to use for the AP.
- * @param onFailureListener A runnable to be triggered on failure.
- * @return true on success, false otherwise.
- */
- public boolean addAccessPoint(@NonNull String ifaceName, @NonNull SoftApConfiguration config,
- @NonNull Runnable onFailureListener) {
- synchronized (mLock) {
- final String methodStr = "addAccessPoint";
- IHostapd.IfaceParams ifaceParams = new IHostapd.IfaceParams();
- ifaceParams.ifaceName = ifaceName;
- ifaceParams.hwModeParams.enable80211N = true;
- ifaceParams.hwModeParams.enable80211AC =
- mContext.getResources().getBoolean(
- R.bool.config_wifi_softap_ieee80211ac_supported);
- int band;
- boolean enableAcs = ApConfigUtil.isAcsSupported(mContext) && config.getChannel() == 0
- && !mForceApChannel;
- if (enableAcs) {
- ifaceParams.channelParams.enableAcs = true;
- ifaceParams.channelParams.acsShouldExcludeDfs = !mContext.getResources()
- .getBoolean(R.bool.config_wifiSoftapAcsIncludeDfs);
- }
- ifaceParams.channelParams.channel =
- mForceApChannel ? mForcedApChannel : config.getChannel();
- band = mForceApChannel ? mForcedApBand : config.getBand();
-
- android.hardware.wifi.hostapd.V1_2.IHostapd.NetworkParams nwParamsV1_2 =
- prepareNetworkParams(config);
- if (nwParamsV1_2 == null) return false;
- if (!checkHostapdAndLogFailure(methodStr)) return false;
- try {
- HostapdStatus status;
- if (!isV1_1() && !isV1_2()) {
- ifaceParams.channelParams.band = getHalBand(band);
- status = mIHostapd.addAccessPoint(ifaceParams, nwParamsV1_2.V1_0);
- if (!checkStatusAndLogFailure(status, methodStr)) {
- return false;
- }
- } else {
- android.hardware.wifi.hostapd.V1_1.IHostapd.IfaceParams ifaceParams1_1 =
- new android.hardware.wifi.hostapd.V1_1.IHostapd.IfaceParams();
- ifaceParams1_1.V1_0 = ifaceParams;
- if (!isV1_2()) {
- ifaceParams.channelParams.band = getHalBand(band);
-
- if (ifaceParams.channelParams.enableAcs) {
- if ((band & SoftApConfiguration.BAND_2GHZ) != 0) {
- ifaceParams1_1.channelParams.acsChannelRanges.addAll(
- toAcsChannelRanges(mContext.getResources().getString(
- R.string.config_wifiSoftap2gChannelList)));
- }
- if ((band & SoftApConfiguration.BAND_5GHZ) != 0) {
- ifaceParams1_1.channelParams.acsChannelRanges.addAll(
- toAcsChannelRanges(mContext.getResources().getString(
- R.string.config_wifiSoftap5gChannelList)));
- }
- }
-
- android.hardware.wifi.hostapd.V1_1.IHostapd iHostapdV1_1 =
- getHostapdMockableV1_1();
- if (iHostapdV1_1 == null) return false;
-
- status = iHostapdV1_1.addAccessPoint_1_1(ifaceParams1_1, nwParamsV1_2.V1_0);
- if (!checkStatusAndLogFailure(status, methodStr)) {
- return false;
- }
- } else {
- android.hardware.wifi.hostapd.V1_2.HostapdStatus status12;
- android.hardware.wifi.hostapd.V1_2.IHostapd.IfaceParams ifaceParams1_2 =
- new android.hardware.wifi.hostapd.V1_2.IHostapd.IfaceParams();
- ifaceParams1_2.V1_1 = ifaceParams1_1;
-
- ifaceParams1_2.hwModeParams.enable80211AX =
- mContext.getResources().getBoolean(
- R.bool.config_wifiSoftapIeee80211axSupported);
- ifaceParams1_2.hwModeParams.enable6GhzBand =
- mContext.getResources().getBoolean(
- R.bool.config_wifiSoftap6ghzSupported);
- ifaceParams1_2.hwModeParams.enableHeSingleUserBeamformer =
- mContext.getResources().getBoolean(
- R.bool.config_wifiSoftapHeSuBeamformerSupported);
- ifaceParams1_2.hwModeParams.enableHeSingleUserBeamformee =
- mContext.getResources().getBoolean(
- R.bool.config_wifiSoftapHeSuBeamformeeSupported);
- ifaceParams1_2.hwModeParams.enableHeMultiUserBeamformer =
- mContext.getResources().getBoolean(
- R.bool.config_wifiSoftapHeMuBeamformerSupported);
- ifaceParams1_2.hwModeParams.enableHeTargetWakeTime =
- mContext.getResources().getBoolean(
- R.bool.config_wifiSoftapHeTwtSupported);
- ifaceParams1_2.channelParams.bandMask = getHalBandMask(band);
-
- // Prepare freq ranges/lists if needed
- if (ifaceParams.channelParams.enableAcs
- && isSendFreqRangesNeeded(band)) {
- if ((band & SoftApConfiguration.BAND_2GHZ) != 0) {
- ifaceParams1_2.channelParams.acsChannelFreqRangesMhz.addAll(
- toAcsFreqRanges(SoftApConfiguration.BAND_2GHZ));
- }
- if ((band & SoftApConfiguration.BAND_5GHZ) != 0) {
- ifaceParams1_2.channelParams.acsChannelFreqRangesMhz.addAll(
- toAcsFreqRanges(SoftApConfiguration.BAND_5GHZ));
- }
- if ((band & SoftApConfiguration.BAND_6GHZ) != 0) {
- ifaceParams1_2.channelParams.acsChannelFreqRangesMhz.addAll(
- toAcsFreqRanges(SoftApConfiguration.BAND_6GHZ));
- }
- }
-
- android.hardware.wifi.hostapd.V1_2.IHostapd iHostapdV1_2 =
- getHostapdMockableV1_2();
- if (iHostapdV1_2 == null) return false;
- status12 = iHostapdV1_2.addAccessPoint_1_2(ifaceParams1_2, nwParamsV1_2);
- if (!checkStatusAndLogFailure12(status12, methodStr)) {
- return false;
- }
- }
- }
-
- mSoftApFailureListeners.put(ifaceName, onFailureListener);
- return true;
- } catch (IllegalArgumentException e) {
- Log.e(TAG, "Unrecognized apBand: " + band);
- return false;
- } catch (RemoteException e) {
- handleRemoteException(e, methodStr);
- return false;
- }
- }
- }
-
- /**
- * Remove a previously started access point.
- *
- * @param ifaceName Name of the interface.
- * @return true on success, false otherwise.
- */
- public boolean removeAccessPoint(@NonNull String ifaceName) {
- synchronized (mLock) {
- final String methodStr = "removeAccessPoint";
- if (!checkHostapdAndLogFailure(methodStr)) return false;
- try {
- HostapdStatus status = mIHostapd.removeAccessPoint(ifaceName);
- if (!checkStatusAndLogFailure(status, methodStr)) {
- return false;
- }
- mSoftApFailureListeners.remove(ifaceName);
- return true;
- } catch (RemoteException e) {
- handleRemoteException(e, methodStr);
- return false;
- }
- }
- }
-
- /**
- * Remove a previously connected client.
- *
- * @param ifaceName Name of the interface.
- * @param client Mac Address of the client.
- * @param reasonCode One of disconnect reason code which defined in {@link WifiManager}.
- * @return true on success, false otherwise.
- */
- public boolean forceClientDisconnect(@NonNull String ifaceName,
- @NonNull MacAddress client, int reasonCode) {
- final String methodStr = "forceClientDisconnect";
- if (isV1_2()) {
- try {
- android.hardware.wifi.hostapd.V1_2.IHostapd iHostapdV1_2 =
- getHostapdMockableV1_2();
- if (iHostapdV1_2 == null) return false;
- byte[] clientMacByteArray = client.toByteArray();
- short disconnectReason;
- switch (reasonCode) {
- case WifiManager.SAP_CLIENT_BLOCK_REASON_CODE_BLOCKED_BY_USER:
- disconnectReason = Ieee80211ReasonCode.WLAN_REASON_PREV_AUTH_NOT_VALID;
- break;
- case WifiManager.SAP_CLIENT_BLOCK_REASON_CODE_NO_MORE_STAS:
- disconnectReason = Ieee80211ReasonCode.WLAN_REASON_DISASSOC_AP_BUSY;
- break;
- case WifiManager.SAP_CLIENT_DISCONNECT_REASON_CODE_UNSPECIFIED:
- disconnectReason = Ieee80211ReasonCode.WLAN_REASON_UNSPECIFIED;
- break;
- default:
- throw new IllegalArgumentException(
- "Unknown disconnect reason code:" + reasonCode);
- }
- android.hardware.wifi.hostapd.V1_2.HostapdStatus status =
- iHostapdV1_2.forceClientDisconnect(ifaceName,
- clientMacByteArray, disconnectReason);
- if (status.code == HostapdStatusCode.SUCCESS) {
- return true;
- }
- Log.d(TAG, "Error when call forceClientDisconnect, status.code = " + status.code);
- } catch (RemoteException e) {
- handleRemoteException(e, methodStr);
- }
- } else {
- Log.d(TAG, "HIDL doesn't support forceClientDisconnect");
- }
- return false;
- }
-
- /**
- * Registers a death notification for hostapd.
- * @return Returns true on success.
- */
- public boolean registerDeathHandler(@NonNull HostapdDeathEventHandler handler) {
- if (mDeathEventHandler != null) {
- Log.e(TAG, "Death handler already present");
- }
- mDeathEventHandler = handler;
- return true;
- }
-
- /**
- * Deregisters a death notification for hostapd.
- * @return Returns true on success.
- */
- public boolean deregisterDeathHandler() {
- if (mDeathEventHandler == null) {
- Log.e(TAG, "No Death handler present");
- }
- mDeathEventHandler = null;
- return true;
- }
-
- /**
- * Clear internal state.
- */
- private void clearState() {
- synchronized (mLock) {
- mIHostapd = null;
- }
- }
-
- /**
- * Handle hostapd death.
- */
- private void hostapdServiceDiedHandler(long cookie) {
- synchronized (mLock) {
- if (mDeathRecipientCookie != cookie) {
- Log.i(TAG, "Ignoring stale death recipient notification");
- return;
- }
- clearState();
- if (mDeathEventHandler != null) {
- mDeathEventHandler.onDeath();
- }
- }
- }
-
- /**
- * Signals whether Initialization completed successfully.
- */
- public boolean isInitializationStarted() {
- synchronized (mLock) {
- return mIServiceManager != null;
- }
- }
-
- /**
- * Signals whether Initialization completed successfully.
- */
- public boolean isInitializationComplete() {
- synchronized (mLock) {
- return mIHostapd != null;
- }
- }
-
- /**
- * Start the hostapd daemon.
- *
- * @return true on success, false otherwise.
- */
- public boolean startDaemon() {
- synchronized (mLock) {
- try {
- // This should startup hostapd daemon using the lazy start HAL mechanism.
- getHostapdMockable();
- } catch (RemoteException e) {
- Log.e(TAG, "Exception while trying to start hostapd: "
- + e);
- hostapdServiceDiedHandler(mDeathRecipientCookie);
- return false;
- } catch (NoSuchElementException e) {
- // We're starting the daemon, so expect |NoSuchElementException|.
- Log.d(TAG, "Successfully triggered start of hostapd using HIDL");
- }
- return true;
- }
- }
-
- /**
- * Terminate the hostapd daemon & wait for it's death.
- */
- public void terminate() {
- synchronized (mLock) {
- // Register for a new death listener to block until hostapd is dead.
- final long waitForDeathCookie = new Random().nextLong();
- final CountDownLatch waitForDeathLatch = new CountDownLatch(1);
- linkToHostapdDeath((cookie) -> {
- Log.d(TAG, "IHostapd died: cookie=" + cookie);
- if (cookie != waitForDeathCookie) return;
- waitForDeathLatch.countDown();
- }, waitForDeathCookie);
-
- final String methodStr = "terminate";
- if (!checkHostapdAndLogFailure(methodStr)) return;
- try {
- mIHostapd.terminate();
- } catch (RemoteException e) {
- handleRemoteException(e, methodStr);
- }
-
- // Now wait for death listener callback to confirm that it's dead.
- try {
- if (!waitForDeathLatch.await(WAIT_FOR_DEATH_TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
- Log.w(TAG, "Timed out waiting for confirmation of hostapd death");
- }
- } catch (InterruptedException e) {
- Log.w(TAG, "Failed to wait for hostapd death");
- }
- }
- }
-
- /**
- * Wrapper functions to access static HAL methods, created to be mockable in unit tests
- */
- @VisibleForTesting
- protected IServiceManager getServiceManagerMockable() throws RemoteException {
- synchronized (mLock) {
- return IServiceManager.getService();
- }
- }
-
- @VisibleForTesting
- protected IHostapd getHostapdMockable() throws RemoteException {
- synchronized (mLock) {
- return IHostapd.getService();
- }
- }
-
- @VisibleForTesting
- protected android.hardware.wifi.hostapd.V1_1.IHostapd getHostapdMockableV1_1()
- throws RemoteException {
- synchronized (mLock) {
- try {
- return android.hardware.wifi.hostapd.V1_1.IHostapd.castFrom(mIHostapd);
- } catch (NoSuchElementException e) {
- Log.e(TAG, "Failed to get IHostapd", e);
- return null;
- }
- }
- }
-
- @VisibleForTesting
- protected android.hardware.wifi.hostapd.V1_2.IHostapd getHostapdMockableV1_2()
- throws RemoteException {
- synchronized (mLock) {
- try {
- return android.hardware.wifi.hostapd.V1_2.IHostapd.castFrom(mIHostapd);
- } catch (NoSuchElementException e) {
- Log.e(TAG, "Failed to get IHostapd", e);
- return null;
- }
- }
- }
-
- private android.hardware.wifi.hostapd.V1_2.IHostapd.NetworkParams
- prepareNetworkParams(SoftApConfiguration config) {
- android.hardware.wifi.hostapd.V1_2.IHostapd.NetworkParams nwParamsV1_2 =
- new android.hardware.wifi.hostapd.V1_2.IHostapd.NetworkParams();
- nwParamsV1_2.V1_0.ssid.addAll(NativeUtil.stringToByteArrayList(config.getSsid()));
- nwParamsV1_2.V1_0.isHidden = config.isHiddenSsid();
- int encryptionType = getEncryptionType(config);
- nwParamsV1_2.encryptionType = encryptionType;
- nwParamsV1_2.passphrase = (config.getPassphrase() != null)
- ? config.getPassphrase() : "";
- if (encryptionType
- == android.hardware.wifi.hostapd.V1_2.IHostapd.EncryptionType.WPA3_SAE
- || encryptionType == android.hardware.wifi.hostapd.V1_2.IHostapd
- .EncryptionType.WPA3_SAE_TRANSITION) {
- if (!isV1_2()) {
- // It should not happen since we should reject configuration in SoftApManager
- Log.e(TAG, "Unsupported Configuration found: " + config);
- return null;
- }
- } else {
- // Fill old parameter for old hidl.
- nwParamsV1_2.V1_0.encryptionType = encryptionType;
- nwParamsV1_2.V1_0.pskPassphrase = (config.getPassphrase() != null)
- ? config.getPassphrase() : "";
- }
- return nwParamsV1_2;
- }
-
- private static int getEncryptionType(SoftApConfiguration localConfig) {
- int encryptionType;
- switch (localConfig.getSecurityType()) {
- case SoftApConfiguration.SECURITY_TYPE_OPEN:
- encryptionType = IHostapd.EncryptionType.NONE;
- break;
- case SoftApConfiguration.SECURITY_TYPE_WPA2_PSK:
- encryptionType = IHostapd.EncryptionType.WPA2;
- break;
- case SoftApConfiguration.SECURITY_TYPE_WPA3_SAE_TRANSITION:
- encryptionType = android.hardware.wifi.hostapd.V1_2
- .IHostapd.EncryptionType.WPA3_SAE_TRANSITION;
- break;
- case SoftApConfiguration.SECURITY_TYPE_WPA3_SAE:
- encryptionType = android.hardware.wifi.hostapd.V1_2
- .IHostapd.EncryptionType.WPA3_SAE;
- break;
- default:
- // We really shouldn't default to None, but this was how NetworkManagementService
- // used to do this.
- encryptionType = IHostapd.EncryptionType.NONE;
- break;
- }
- return encryptionType;
- }
-
- private static int getHalBandMask(int apBand) {
- int bandMask = 0;
-
- if (!ApConfigUtil.isBandValid(apBand)) {
- throw new IllegalArgumentException();
- }
-
- if (ApConfigUtil.containsBand(apBand, SoftApConfiguration.BAND_2GHZ)) {
- bandMask |= android.hardware.wifi.hostapd.V1_2.IHostapd.BandMask.BAND_2_GHZ;
- }
- if (ApConfigUtil.containsBand(apBand, SoftApConfiguration.BAND_5GHZ)) {
- bandMask |= android.hardware.wifi.hostapd.V1_2.IHostapd.BandMask.BAND_5_GHZ;
- }
- if (ApConfigUtil.containsBand(apBand, SoftApConfiguration.BAND_6GHZ)) {
- bandMask |= android.hardware.wifi.hostapd.V1_2.IHostapd.BandMask.BAND_6_GHZ;
- }
-
- return bandMask;
- }
-
- private static int getHalBand(int apBand) {
- if (!ApConfigUtil.isBandValid(apBand)) {
- throw new IllegalArgumentException();
- }
-
- switch (apBand) {
- case SoftApConfiguration.BAND_2GHZ:
- return IHostapd.Band.BAND_2_4_GHZ;
- case SoftApConfiguration.BAND_5GHZ:
- return IHostapd.Band.BAND_5_GHZ;
- default:
- return IHostapd.Band.BAND_ANY;
- }
- }
-
- /**
- * Convert channel list string like '1-6,11' to list of AcsChannelRanges
- */
- private List<android.hardware.wifi.hostapd.V1_1.IHostapd.AcsChannelRange>
- toAcsChannelRanges(String channelListStr) {
- ArrayList<android.hardware.wifi.hostapd.V1_1.IHostapd.AcsChannelRange> acsChannelRanges =
- new ArrayList<>();
-
- for (String channelRange : channelListStr.split(",")) {
- android.hardware.wifi.hostapd.V1_1.IHostapd.AcsChannelRange acsChannelRange =
- new android.hardware.wifi.hostapd.V1_1.IHostapd.AcsChannelRange();
- try {
- if (channelRange.contains("-")) {
- String[] channels = channelRange.split("-");
- if (channels.length != 2) {
- Log.e(TAG, "Unrecognized channel range, length is " + channels.length);
- continue;
- }
- int start = Integer.parseInt(channels[0].trim());
- int end = Integer.parseInt(channels[1].trim());
- if (start > end) {
- Log.e(TAG, "Invalid channel range, from " + start + " to " + end);
- continue;
- }
- acsChannelRange.start = start;
- acsChannelRange.end = end;
- } else {
- acsChannelRange.start = Integer.parseInt(channelRange.trim());
- acsChannelRange.end = acsChannelRange.start;
- }
- } catch (NumberFormatException e) {
- // Ignore malformed value
- Log.e(TAG, "Malformed channel value detected: " + e);
- continue;
- }
- acsChannelRanges.add(acsChannelRange);
- }
- return acsChannelRanges;
- }
-
- /**
- * Convert channel list string like '1-6,11' to list of AcsFreqRange
- */
- private List<android.hardware.wifi.hostapd.V1_2.IHostapd.AcsFrequencyRange>
- toAcsFreqRanges(@BandType int band) {
- List<android.hardware.wifi.hostapd.V1_2.IHostapd.AcsFrequencyRange>
- acsFrequencyRanges = new ArrayList<>();
-
- if (!ApConfigUtil.isBandValid(band) || ApConfigUtil.isMultiband(band)) {
- Log.e(TAG, "Invalid band : " + band);
- return acsFrequencyRanges;
- }
-
- String channelListStr;
- switch (band) {
- case SoftApConfiguration.BAND_2GHZ:
- channelListStr = mConfig2gChannelList;
- break;
- case SoftApConfiguration.BAND_5GHZ:
- channelListStr = mConfig5gChannelList;
- break;
- case SoftApConfiguration.BAND_6GHZ:
- channelListStr = mConfig6gChannelList;
- break;
- default:
- return acsFrequencyRanges;
- }
-
- for (String channelRange : channelListStr.split(",")) {
- android.hardware.wifi.hostapd.V1_2.IHostapd.AcsFrequencyRange acsFrequencyRange =
- new android.hardware.wifi.hostapd.V1_2.IHostapd.AcsFrequencyRange();
- try {
- if (channelRange.contains("-")) {
- String[] channels = channelRange.split("-");
- if (channels.length != 2) {
- Log.e(TAG, "Unrecognized channel range, length is " + channels.length);
- continue;
- }
- int start = Integer.parseInt(channels[0].trim());
- int end = Integer.parseInt(channels[1].trim());
- if (start > end) {
- Log.e(TAG, "Invalid channel range, from " + start + " to " + end);
- continue;
- }
- acsFrequencyRange.start = ApConfigUtil.convertChannelToFrequency(start, band);
- acsFrequencyRange.end = ApConfigUtil.convertChannelToFrequency(end, band);
- } else {
- int channel = Integer.parseInt(channelRange.trim());
- acsFrequencyRange.start = ApConfigUtil.convertChannelToFrequency(channel, band);
- acsFrequencyRange.end = acsFrequencyRange.start;
- }
- } catch (NumberFormatException e) {
- // Ignore malformed value
- Log.e(TAG, "Malformed channel value detected: " + e);
- continue;
- }
- acsFrequencyRanges.add(acsFrequencyRange);
- }
- return acsFrequencyRanges;
- }
-
- /**
- * Returns false if Hostapd is null, and logs failure to call methodStr
- */
- private boolean checkHostapdAndLogFailure(String methodStr) {
- synchronized (mLock) {
- if (mIHostapd == null) {
- Log.e(TAG, "Can't call " + methodStr + ", IHostapd is null");
- return false;
- }
- return true;
- }
- }
-
- /**
- * Returns true if provided status code is SUCCESS, logs debug message and returns false
- * otherwise
- */
- private boolean checkStatusAndLogFailure(HostapdStatus status,
- String methodStr) {
- synchronized (mLock) {
- if (status.code != HostapdStatusCode.SUCCESS) {
- Log.e(TAG, "IHostapd." + methodStr + " failed: " + status.code
- + ", " + status.debugMessage);
- return false;
- } else {
- if (mVerboseLoggingEnabled) {
- Log.d(TAG, "IHostapd." + methodStr + " succeeded");
- }
- return true;
- }
- }
- }
-
- /**
- * Returns true if provided status code is SUCCESS, logs debug message and returns false
- * otherwise
- */
- private boolean checkStatusAndLogFailure12(
- android.hardware.wifi.hostapd.V1_2.HostapdStatus status, String methodStr) {
- synchronized (mLock) {
- if (status.code != HostapdStatusCode.SUCCESS) {
- Log.e(TAG, "IHostapd." + methodStr + " failed: " + status.code
- + ", " + status.debugMessage);
- return false;
- } else {
- if (mVerboseLoggingEnabled) {
- Log.d(TAG, "IHostapd." + methodStr + " succeeded");
- }
- return true;
- }
- }
- }
-
- private void handleRemoteException(RemoteException e, String methodStr) {
- synchronized (mLock) {
- hostapdServiceDiedHandler(mDeathRecipientCookie);
- Log.e(TAG, "IHostapd." + methodStr + " failed with exception", e);
- }
- }
-
- private class HostapdCallback extends
- android.hardware.wifi.hostapd.V1_1.IHostapdCallback.Stub {
- @Override
- public void onFailure(String ifaceName) {
- Log.w(TAG, "Failure on iface " + ifaceName);
- Runnable onFailureListener = mSoftApFailureListeners.get(ifaceName);
- if (onFailureListener != null) {
- onFailureListener.run();
- }
- }
- }
-
- /**
- * Set the debug log level for hostapd.
- *
- * @return true if request is sent successfully, false otherwise.
- */
- public boolean setLogLevel() {
- synchronized (mLock) {
- final String methodStr = "setDebugParams";
- if (!checkHostapdAndLogFailure(methodStr)) return false;
- if (isV1_2()) {
- try {
- android.hardware.wifi.hostapd.V1_2.IHostapd iHostapdV1_2 =
- getHostapdMockableV1_2();
- if (iHostapdV1_2 == null) return false;
- android.hardware.wifi.hostapd.V1_2.HostapdStatus status =
- iHostapdV1_2.setDebugParams(mVerboseLoggingEnabled
- ? DebugLevel.DEBUG
- : DebugLevel.INFO);
- return checkStatusAndLogFailure12(status, methodStr);
- } catch (RemoteException e) {
- handleRemoteException(e, methodStr);
- }
- } else {
- Log.d(TAG, "HIDL doesn't support setDebugParams");
- }
- return false;
- }
- }
-}