huangcm
2025-08-25 2f2fd745743ad500687c6985119d523146531958
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
/*
 * Copyright (C) 2016 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.util;
 
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiScanner;
import android.util.Log;
 
import com.android.server.wifi.WifiNative;
 
import java.util.ArrayList;
import java.util.Random;
 
/**
 * Provide utility functions for updating soft AP related configuration.
 */
public class ApConfigUtil {
    private static final String TAG = "ApConfigUtil";
 
    public static final int DEFAULT_AP_BAND = WifiConfiguration.AP_BAND_2GHZ;
    public static final int DEFAULT_AP_CHANNEL = 6;
 
    /* Return code for updateConfiguration. */
    public static final int SUCCESS = 0;
    public static final int ERROR_NO_CHANNEL = 1;
    public static final int ERROR_GENERIC = 2;
 
    /* Random number generator used for AP channel selection. */
    private static final Random sRandom = new Random();
 
    /**
     * Convert frequency to channel.
     * @param frequency frequency to convert
     * @return channel number associated with given frequency, -1 if no match
     */
    public static int convertFrequencyToChannel(int frequency) {
        if (frequency >= 2412 && frequency <= 2472) {
            return (frequency - 2412) / 5 + 1;
        } else if (frequency == 2484) {
            return 14;
        } else if (frequency >= 5170  &&  frequency <= 5825) {
            /* DFS is included. */
            return (frequency - 5170) / 5 + 34;
        }
 
        return -1;
    }
 
    /**
     * Return a channel number for AP setup based on the frequency band.
     * @param apBand one of the value of WifiConfiguration.AP_BAND_*.
     * @param allowed2GChannels list of allowed 2GHz channels
     * @param allowed5GFreqList list of allowed 5GHz frequencies
     * @return a valid channel number on success, -1 on failure.
     */
    public static int chooseApChannel(int apBand,
                                      ArrayList<Integer> allowed2GChannels,
                                      int[] allowed5GFreqList) {
        if (apBand != WifiConfiguration.AP_BAND_2GHZ
                && apBand != WifiConfiguration.AP_BAND_5GHZ
                        && apBand != WifiConfiguration.AP_BAND_ANY) {
            Log.e(TAG, "Invalid band: " + apBand);
            return -1;
        }
 
        // TODO(b/72120668): Create channel selection logic for AP_BAND_ANY.
        if (apBand == WifiConfiguration.AP_BAND_2GHZ
                || apBand == WifiConfiguration.AP_BAND_ANY)  {
            /* Select a channel from 2GHz band. */
            if (allowed2GChannels == null || allowed2GChannels.size() == 0) {
                Log.d(TAG, "2GHz allowed channel list not specified");
                /* Use default channel. */
                return DEFAULT_AP_CHANNEL;
            }
 
            /* Pick a random channel. */
            int index = sRandom.nextInt(allowed2GChannels.size());
            return allowed2GChannels.get(index).intValue();
        }
 
        /* 5G without DFS. */
        if (allowed5GFreqList != null && allowed5GFreqList.length > 0) {
            /* Pick a random channel from the list of supported channels. */
            return convertFrequencyToChannel(
                    allowed5GFreqList[sRandom.nextInt(allowed5GFreqList.length)]);
        }
 
        Log.e(TAG, "No available channels on 5GHz band");
        return -1;
    }
 
    /**
     * Update AP band and channel based on the provided country code and band.
     * This will also set
     * @param wifiNative reference to WifiNative
     * @param countryCode country code
     * @param allowed2GChannels list of allowed 2GHz channels
     * @param config configuration to update
     * @return an integer result code
     */
    public static int updateApChannelConfig(WifiNative wifiNative,
                                            String countryCode,
                                            ArrayList<Integer> allowed2GChannels,
                                            WifiConfiguration config) {
        /* Use default band and channel for device without HAL. */
        if (!wifiNative.isHalStarted()) {
            config.apBand = DEFAULT_AP_BAND;
            config.apChannel = DEFAULT_AP_CHANNEL;
            return SUCCESS;
        }
 
        /* Country code is mandatory for 5GHz band. */
        if (config.apBand == WifiConfiguration.AP_BAND_5GHZ
                && countryCode == null) {
            Log.e(TAG, "5GHz band is not allowed without country code");
            return ERROR_GENERIC;
        }
 
        /* Select a channel if it is not specified. */
        if (config.apChannel == 0) {
            config.apChannel = chooseApChannel(
                    config.apBand, allowed2GChannels,
                    wifiNative.getChannelsForBand(WifiScanner.WIFI_BAND_5_GHZ));
            if (config.apChannel == -1) {
                /* We're not able to get channel from wificond. */
                Log.e(TAG, "Failed to get available channel.");
                return ERROR_NO_CHANNEL;
            }
        }
 
        return SUCCESS;
    }
}