diff options
10 files changed, 910 insertions, 130 deletions
diff --git a/service/java/com/android/server/wifi/DummyWifiLogger.java b/service/java/com/android/server/wifi/DummyWifiLogger.java new file mode 100644 index 000000000..2727b8c07 --- /dev/null +++ b/service/java/com/android/server/wifi/DummyWifiLogger.java @@ -0,0 +1,29 @@ + +package com.android.server.wifi; + +import android.util.Log; + +import java.io.FileDescriptor; +import java.io.PrintWriter; + +class DummyWifiLogger { + + public DummyWifiLogger() { } + + public synchronized void startLogging(boolean verboseEnabled) { } + + public synchronized void startPacketLog() { } + + public synchronized void stopPacketLog() { } + + public synchronized void stopLogging() { } + + public synchronized void captureBugReportData(int reason) { } + + public synchronized void captureAlertData(int errorCode, byte[] alertData) { } + + public synchronized void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + pw.println("*** firmware logging disabled, no debug data ****"); + pw.println("set config_wifi_enable_wifi_firmware_debugging to enable"); + } +}
\ No newline at end of file diff --git a/service/java/com/android/server/wifi/WifiConfigStore.java b/service/java/com/android/server/wifi/WifiConfigStore.java index dd47b0805..76a1ca5b8 100644 --- a/service/java/com/android/server/wifi/WifiConfigStore.java +++ b/service/java/com/android/server/wifi/WifiConfigStore.java @@ -469,7 +469,7 @@ public class WifiConfigStore extends IpConfigStore { WifiEnterpriseConfig.CA_CERT_KEY, WifiEnterpriseConfig.SUBJECT_MATCH_KEY, WifiEnterpriseConfig.ENGINE_KEY, WifiEnterpriseConfig.ENGINE_ID_KEY, WifiEnterpriseConfig.PRIVATE_KEY_ID_KEY, WifiEnterpriseConfig.ALTSUBJECT_MATCH_KEY, - WifiEnterpriseConfig.DOM_SUFFIX_MATCH_KEY + WifiEnterpriseConfig.DOM_SUFFIX_MATCH_KEY, WifiEnterpriseConfig.PHASE1_KEY }; @@ -1024,6 +1024,8 @@ public class WifiConfigStore extends IpConfigStore { } } + mWifiNative.setHs20(config.isPasspoint()); + if (updatePriorities) mWifiNative.saveConfig(); else @@ -1313,7 +1315,7 @@ public class WifiConfigStore extends IpConfigStore { // Sort by descending priority Collections.sort(sortedWifiConfigurations, new Comparator<WifiConfiguration>() { public int compare(WifiConfiguration a, WifiConfiguration b) { - return a.priority >= b.priority ? 1 : -1; + return a.priority - b.priority; } }); } @@ -1330,6 +1332,109 @@ public class WifiConfigStore extends IpConfigStore { } } + /** + * Returns whether the provided network config is enabled for autojoin or not. + */ + private static boolean isNetworkEnabled(WifiConfiguration config) { + return (config.status == Status.ENABLED && !config.ephemeral + && (config.autoJoinStatus == WifiConfiguration.AUTO_JOIN_ENABLED)); + } + + /** + * Returns whether the provided network config is only temporarily disabled for autojoin or not. + */ + private static boolean isNetworkTempDisabled(WifiConfiguration config) { + return (config.status == Status.ENABLED && !config.ephemeral + && ((config.autoJoinStatus <= WifiConfiguration.AUTO_JOIN_DISABLED_ON_AUTH_FAILURE) + && (config.autoJoinStatus > WifiConfiguration.AUTO_JOIN_ENABLED))); + } + + /** + * Returns an integer representing a score for each configuration. The scores are assigned based + * on the status of the configuration. The scores are assigned according to this order: + * Fully enabled network > Temporarily disabled network > Permanently disabled network. + */ + private static int getPnoNetworkSortScore(WifiConfiguration config) { + // Do we need static constants for these scores? We're not using them anywhere else though. + if (isNetworkEnabled(config)) { + return 3; + } else if (isNetworkTempDisabled(config)) { + return 2; + } else { + return 1; + } + } + + /** + * PnoNetwork list sorting algorithm: + * 1, Place the fully enabled networks first. Among the fully enabled networks, + * sort them in descending order of their |numAssociation| values. If networks have + * the same |numAssociation|, then sort them in descending order of their |priority| + * values. + * 2. Next place all the temporarily disabled networks. Among the temporarily disabled + * networks, sort them in the same order as the fully enabled networks. + * 3. Place the permanently disabled networks last. The order among permanently disabled + * networks doesn't matter. + */ + private static final Comparator<WifiConfiguration> sPnoListSortComparator = + new Comparator<WifiConfiguration>() { + public int compare(WifiConfiguration a, WifiConfiguration b) { + int configAScore = getPnoNetworkSortScore(a); + int configBScore = getPnoNetworkSortScore(b); + if (configAScore == configBScore) { + // If 2 networks have the same saved |numAssociation| value, sort them + // according to their priority. + if (a.numAssociation != b.numAssociation) { + return Long.compare(b.numAssociation, a.numAssociation); + } else { + return Integer.compare(b.priority, a.priority); + } + } else { + return Integer.compare(configBScore, configAScore); + } + } + }; + + /** + * Retrieves an updated list of priorities for all the saved networks before + * enabling/disabling PNO. + * + * wpa_supplicant uses the priority of networks to build the list of SSID's to monitor + * during PNO. If there are a lot of saved networks, this list will be truncated and we + * might end up not connecting to the networks we use most frequently. So, We want the networks + * to be re-sorted based on the relative |numAssociation| values. + * + * @param enablePno boolean indicating whether PNO is being enabled or disabled. + * @return list of networks with updated priorities. + */ + ArrayList<WifiNative.PnoNetworkPriority> retrievePnoNetworkPriorityList(boolean enablePno) { + ArrayList<WifiNative.PnoNetworkPriority> pnoList = + new ArrayList<WifiNative.PnoNetworkPriority>(); + ArrayList<WifiConfiguration> wifiConfigurations = + new ArrayList<WifiConfiguration>(mConfiguredNetworks.values()); + if (enablePno) { + Collections.sort(wifiConfigurations, sPnoListSortComparator); + // Let's use the network list size as the highest priority and then go down from there. + // So, the most frequently connected network has the highest priority now. + int priority = wifiConfigurations.size(); + if (DBG) { + Log.d(TAG, "Retrieve network priorities before PNO. Max priority: " + priority); + } + for (WifiConfiguration config : wifiConfigurations) { + pnoList.add(new WifiNative.PnoNetworkPriority(config.networkId, priority)); + priority--; + } + } else { + // Revert the priorities back to the saved config values after PNO. + if (DBG) Log.d(TAG, "Retrieve network priorities after PNO."); + for (WifiConfiguration config : wifiConfigurations) { + pnoList.add(new WifiNative.PnoNetworkPriority(config.networkId, config.priority)); + } + } + return pnoList; + } + + String[] getWhiteListedSsids(WifiConfiguration config) { int num_ssids = 0; String nonQuoteSSID; @@ -1792,7 +1897,7 @@ public class WifiConfigStore extends IpConfigStore { mLastPriority = 0; mConfiguredNetworks.clear(); - + List<WifiConfiguration> configTlsResetList = new ArrayList<WifiConfiguration>(); int last_id = -1; boolean done = false; while (!done) { @@ -1861,6 +1966,14 @@ public class WifiConfigStore extends IpConfigStore { if (showNetworks) log("Ignoring loaded configured for network " + config.networkId + " because config are not valid"); } + + if (config != null && config.enterpriseConfig != null && + config.enterpriseConfig.getEapMethod() < WifiEnterpriseConfig.Eap.PWD) { + if (!config.enterpriseConfig.getTls12Enable()) { + //re-enable the TLS1.2 every time when load the network + configTlsResetList.add(config); + } + } } done = (lines.length == 1); @@ -1884,6 +1997,12 @@ public class WifiConfigStore extends IpConfigStore { logContents(SUPPLICANT_CONFIG_FILE_BACKUP); logContents(networkHistoryConfigFile); } + + //reset TLS default to 1.2 + for (WifiConfiguration config : configTlsResetList) { + config.enterpriseConfig.setTls12Enable(true); + addOrUpdateNetwork(config, WifiConfiguration.UNKNOWN_UID); + } } private void logContents(String file) { diff --git a/service/java/com/android/server/wifi/WifiController.java b/service/java/com/android/server/wifi/WifiController.java index 3b41e3b81..9a8967bf2 100644 --- a/service/java/com/android/server/wifi/WifiController.java +++ b/service/java/com/android/server/wifi/WifiController.java @@ -116,6 +116,9 @@ class WifiController extends StateMachine { static final int CMD_USER_PRESENT = BASE + 12; static final int CMD_AP_START_FAILURE = BASE + 13; + private static final int WIFI_DISABLED = 0; + private static final int WIFI_ENABLED = 1; + private DefaultState mDefaultState = new DefaultState(); private StaEnabledState mStaEnabledState = new StaEnabledState(); private ApStaDisabledState mApStaDisabledState = new ApStaDisabledState(); @@ -441,6 +444,10 @@ class WifiController extends StateMachine { break; case CMD_SET_AP: if (msg.arg1 == 1) { + if (msg.arg2 == 0) { // previous wifi state has not been saved yet + Settings.Global.putInt(mContext.getContentResolver(), + Settings.Global.WIFI_SAVED_STATE, WIFI_DISABLED); + } mWifiStateMachine.setHostApRunning((WifiConfiguration) msg.obj, true); transitionTo(mApEnabledState); @@ -509,6 +516,15 @@ class WifiController extends StateMachine { transitionTo(mEcmState); break; } + case CMD_SET_AP: + if (msg.arg1 == 1) { + // remeber that we were enabled + Settings.Global.putInt(mContext.getContentResolver(), + Settings.Global.WIFI_SAVED_STATE, WIFI_ENABLED); + deferMessage(obtainMessage(msg.what, msg.arg1, 1, msg.obj)); + transitionTo(mApStaDisabledState); + } + break; default: return NOT_HANDLED; @@ -567,7 +583,9 @@ class WifiController extends StateMachine { case CMD_SET_AP: // Before starting tethering, turn off supplicant for scan mode if (msg.arg1 == 1) { - deferMessage(msg); + Settings.Global.putInt(mContext.getContentResolver(), + Settings.Global.WIFI_SAVED_STATE, WIFI_DISABLED); + deferMessage(obtainMessage(msg.what, msg.arg1, 1, msg.obj)); transitionTo(mApStaDisabledState); } break; @@ -617,9 +635,27 @@ class WifiController extends StateMachine { case CMD_SET_AP: if (msg.arg1 == 0) { mWifiStateMachine.setHostApRunning(null, false); - transitionTo(mApStaDisabledState); + int wifiSavedState = Settings.Global.getInt(mContext.getContentResolver(), + Settings.Global.WIFI_SAVED_STATE, WIFI_DISABLED); + if (wifiSavedState == WIFI_ENABLED) { + transitionTo(mStaEnabledState); + } + else { + if (mSettingsStore.isScanAlwaysAvailable()) { + transitionTo(mStaDisabledWithScanState); + } + else { + transitionTo(mApStaDisabledState); + } + } } break; + case CMD_EMERGENCY_MODE_CHANGED: + if (msg.arg1 == 1) { + mWifiStateMachine.setHostApRunning(null, false); + transitionTo(mEcmState); + break; + } case CMD_AP_START_FAILURE: if(!mSettingsStore.isScanAlwaysAvailable()) { transitionTo(mApStaDisabledState); @@ -637,6 +673,7 @@ class WifiController extends StateMachine { @Override public void enter() { mWifiStateMachine.setSupplicantRunning(false); + mWifiStateMachine.clearANQPCache(); } @Override diff --git a/service/java/com/android/server/wifi/WifiLogger.java b/service/java/com/android/server/wifi/WifiLogger.java index 8add77970..c3f651039 100644 --- a/service/java/com/android/server/wifi/WifiLogger.java +++ b/service/java/com/android/server/wifi/WifiLogger.java @@ -35,7 +35,7 @@ import java.util.zip.Deflater; /** * Tracks various logs for framework */ -class WifiLogger { +class WifiLogger extends DummyWifiLogger { private static final String TAG = "WifiLogger"; private static final boolean DBG = false; @@ -92,6 +92,7 @@ class WifiLogger { mWifiStateMachine = wifiStateMachine; } + @Override public synchronized void startLogging(boolean verboseEnabled) { mFirmwareVersion = WifiNative.getFirmwareVersion(); mDriverVersion = WifiNative.getDriverVersion(); @@ -112,6 +113,7 @@ class WifiLogger { } } + @Override public synchronized void startPacketLog() { if (mPerPacketRingBuffer != null) { startLoggingRingBuffer(mPerPacketRingBuffer); @@ -120,6 +122,7 @@ class WifiLogger { } } + @Override public synchronized void stopPacketLog() { if (mPerPacketRingBuffer != null) { stopLoggingRingBuffer(mPerPacketRingBuffer); @@ -128,6 +131,7 @@ class WifiLogger { } } + @Override public synchronized void stopLogging() { if (mLogLevel != VERBOSE_NO_LOG) { //resetLogHandler only can be used when you terminate all logging since all handler will @@ -143,17 +147,20 @@ class WifiLogger { } } + @Override public synchronized void captureBugReportData(int reason) { BugReport report = captureBugreport(reason, true); mLastBugReports.addLast(report); } + @Override public synchronized void captureAlertData(int errorCode, byte[] alertData) { BugReport report = captureBugreport(errorCode, /* captureFWDump = */ true); report.alertData = alertData; mLastAlerts.addLast(report); } + @Override public synchronized void dump(FileDescriptor fd, PrintWriter pw, String[] args) { pw.println("Chipset information :-----------------------------------------------"); pw.println("FW Version is: " + mFirmwareVersion); @@ -236,7 +243,7 @@ class WifiLogger { } } - static class LimitedCircularArray<E> { + private static class LimitedCircularArray<E> { private CircularArray<E> mArray; private int mMax; LimitedCircularArray(int max) { diff --git a/service/java/com/android/server/wifi/WifiMonitor.java b/service/java/com/android/server/wifi/WifiMonitor.java index 9758d5769..ffca502d4 100644 --- a/service/java/com/android/server/wifi/WifiMonitor.java +++ b/service/java/com/android/server/wifi/WifiMonitor.java @@ -230,6 +230,10 @@ public class WifiMonitor { private static final String BSS_REMOVED_STR = "BSS-REMOVED"; /** + * This indicate supplicant encounter RSN PMKID mismatch error + */ + private static final String RSN_PMKID_STR = "RSN: PMKID mismatch"; + /** * Regex pattern for extracting an Ethernet-style MAC address from a string. * Matches a strings like the following:<pre> * CTRL-EVENT-CONNECTED - Connection to 00:1e:58:ec:d5:6d completed (reauth) [id=1 id_str=]</pre> @@ -502,6 +506,7 @@ public class WifiMonitor { public static final int HS20_REMEDIATION_EVENT = BASE + 61; public static final int HS20_DEAUTH_EVENT = BASE + 62; + public static final int RSN_PMKID_MISMATCH_EVENT = BASE + 63; /** * This indicates a read error on the monitor socket conenction */ @@ -829,6 +834,8 @@ public class WifiMonitor { } else if (eventStr.startsWith(AUTH_EVENT_PREFIX_STR) && eventStr.endsWith(AUTH_TIMEOUT_STR)) { mStateMachine.sendMessage(AUTHENTICATION_FAILURE_EVENT); + } else if (eventStr.startsWith(RSN_PMKID_STR)) { + mStateMachine.sendMessage(RSN_PMKID_MISMATCH_EVENT); } else { if (DBG) Log.w(TAG, "couldn't identify event type - " + eventStr); } diff --git a/service/java/com/android/server/wifi/WifiNative.java b/service/java/com/android/server/wifi/WifiNative.java index 899529ddd..620f8b505 100644 --- a/service/java/com/android/server/wifi/WifiNative.java +++ b/service/java/com/android/server/wifi/WifiNative.java @@ -36,6 +36,8 @@ import android.util.Base64; import android.util.LocalLog; import android.util.Log; +import com.android.server.connectivity.KeepalivePacketData; + import java.io.ByteArrayOutputStream; import java.io.IOException; import java.nio.ByteBuffer; @@ -654,8 +656,47 @@ public class WifiNative { return doBooleanCommand("DRIVER COUNTRY"); } - public boolean enableBackgroundScan(boolean enable) { + /** + * Object holding the network ID and the corresponding priority to be set before enabling/ + * disabling PNO. + */ + public static class PnoNetworkPriority { + public int networkId; + public int priority; + + PnoNetworkPriority(int networkId, int priority) { + this.networkId = networkId; + this.priority = priority; + } + + @Override + public String toString() { + StringBuilder sbuf = new StringBuilder(); + sbuf.append(" Network ID=").append(this.networkId); + sbuf.append(" Priority=").append(this.priority); + return sbuf.toString(); + } + } + + public boolean enableBackgroundScan( + boolean enable, + List<PnoNetworkPriority> pnoNetworkList) { boolean ret; + // TODO: Couple of cases yet to be handled: + // 1. What if the network priority update fails, should we bail out of PNO setting? + // 2. If PNO setting fails below, should we go back and revert this priority change? + if (pnoNetworkList != null) { + if (DBG) Log.i(mTAG, "Update priorities for PNO. Enable: " + enable); + for (PnoNetworkPriority pnoNetwork : pnoNetworkList) { + // What if this fails? Should we bail out? + boolean isSuccess = setNetworkVariable(pnoNetwork.networkId, + WifiConfiguration.priorityVarName, + Integer.toString(pnoNetwork.priority)); + if (!isSuccess) { + Log.e(mTAG, "Update priority failed for :" + pnoNetwork.networkId); + } + } + } if (enable) { ret = doBooleanCommand("SET pno 1"); } else { @@ -676,6 +717,14 @@ public class WifiNative { doBooleanCommand("SCAN_INTERVAL " + scanInterval); } + public void setHs20(boolean hs20) { + if (hs20) { + doBooleanCommand("SET HS20 1"); + } else { + doBooleanCommand("SET HS20 0"); + } + } + public void startTdls(String macAddr, boolean enable) { if (enable) { doBooleanCommand("TDLS_DISCOVER " + macAddr); @@ -1466,8 +1515,8 @@ public class WifiNative { int secondChanelOffset = 0; byte channelMode = 0; - byte centerFreqIndex1 = 0; - byte centerFreqIndex2 = 0; + int centerFreqIndex1 = 0; + int centerFreqIndex2 = 0; boolean is80211McRTTResponder = false; @@ -1490,8 +1539,8 @@ public class WifiNative { secondChanelOffset = bytes[inforStart + 1] & 0x3; } else if(type == EID_VHT_OPERATION) { channelMode = bytes[inforStart]; - centerFreqIndex1 = bytes[inforStart + 1]; - centerFreqIndex2 = bytes[inforStart + 2]; + centerFreqIndex1 = bytes[inforStart + 1] & 0xFF; + centerFreqIndex2 = bytes[inforStart + 2] & 0xFF; } else if (type == EID_EXTENDED_CAPS) { int tempIndex = RTT_RESP_ENABLE_BIT / 8; byte offset = RTT_RESP_ENABLE_BIT % 8; @@ -1604,7 +1653,9 @@ public class WifiNative { synchronized public static void stopScan() { synchronized (mLock) { if (isHalStarted()) { - stopScanNative(sWlan0Index, sScanCmdId); + if (sScanCmdId != 0) { + stopScanNative(sWlan0Index, sScanCmdId); + } sScanSettings = null; sScanEventHandler = null; sScanCmdId = 0; @@ -2391,4 +2442,98 @@ public class WifiNative { } } } + + private native static int startSendingOffloadedPacketNative(int iface, int idx, + byte[] srcMac, byte[] dstMac, byte[] pktData, int period); + + synchronized public int + startSendingOffloadedPacket(int slot, KeepalivePacketData keepAlivePacket, int period) { + Log.d(TAG, "startSendingOffloadedPacket slot=" + slot + " period=" + period); + + String[] macAddrStr = getMacAddress().split(":"); + byte[] srcMac = new byte[6]; + for(int i = 0; i < 6; i++) { + Integer hexVal = Integer.parseInt(macAddrStr[i], 16); + srcMac[i] = hexVal.byteValue(); + } + synchronized (mLock) { + if (isHalStarted()) { + return startSendingOffloadedPacketNative(sWlan0Index, slot, srcMac, + keepAlivePacket.dstMac, keepAlivePacket.data, period); + } else { + return -1; + } + } + } + + private native static int stopSendingOffloadedPacketNative(int iface, int idx); + + synchronized public int + stopSendingOffloadedPacket(int slot) { + Log.d(TAG, "stopSendingOffloadedPacket " + slot); + synchronized (mLock) { + if (isHalStarted()) { + return stopSendingOffloadedPacketNative(sWlan0Index, slot); + } else { + return -1; + } + } + } + + public static interface WifiRssiEventHandler { + void onRssiThresholdBreached(byte curRssi); + } + + private static WifiRssiEventHandler sWifiRssiEventHandler; + + synchronized static void onRssiThresholdBreached(int id, byte curRssi) { + sWifiRssiEventHandler.onRssiThresholdBreached(curRssi); + } + + private native static int startRssiMonitoringNative(int iface, int id, + byte maxRssi, byte minRssi); + + private static int sRssiMonitorCmdId = 0; + + synchronized public int startRssiMonitoring(byte maxRssi, byte minRssi, + WifiRssiEventHandler rssiEventHandler) { + Log.d(TAG, "startRssiMonitoring: maxRssi=" + maxRssi + " minRssi=" + minRssi); + sWifiRssiEventHandler = rssiEventHandler; + synchronized (mLock) { + if (isHalStarted()) { + if (sRssiMonitorCmdId != 0) { + stopRssiMonitoring(); + } + + sRssiMonitorCmdId = getNewCmdIdLocked(); + Log.d(TAG, "sRssiMonitorCmdId = " + sRssiMonitorCmdId); + int ret = startRssiMonitoringNative(sWlan0Index, sRssiMonitorCmdId, + maxRssi, minRssi); + if (ret != 0) { // if not success + sRssiMonitorCmdId = 0; + } + return ret; + } else { + return -1; + } + } + } + + private native static int stopRssiMonitoringNative(int iface, int idx); + + synchronized public int stopRssiMonitoring() { + Log.d(TAG, "stopRssiMonitoring, cmdId " + sRssiMonitorCmdId); + synchronized (mLock) { + if (isHalStarted()) { + int ret = 0; + if (sRssiMonitorCmdId != 0) { + ret = stopRssiMonitoringNative(sWlan0Index, sRssiMonitorCmdId); + } + sRssiMonitorCmdId = 0; + return ret; + } else { + return -1; + } + } + } } diff --git a/service/java/com/android/server/wifi/WifiScanningServiceImpl.java b/service/java/com/android/server/wifi/WifiScanningServiceImpl.java index 8f2cd3bd7..a0f506113 100644 --- a/service/java/com/android/server/wifi/WifiScanningServiceImpl.java +++ b/service/java/com/android/server/wifi/WifiScanningServiceImpl.java @@ -658,6 +658,17 @@ public class WifiScanningServiceImpl extends IWifiScanner.Stub { reportScanWorkUpdate(); } + void removeAllScanRequests() { + Iterator<Map.Entry<Integer, ScanSettings>> it = mScanSettings.entrySet().iterator(); + while (it.hasNext()) { + Map.Entry<Integer, ScanSettings> entry = it.next(); + ScanSettings settings = entry.getValue(); + Log.d(TAG, "Pending scan removed, handler=" + entry.getKey() + + ", period=" + settings.periodInMs); + it.remove(); + } + } + Iterator<Map.Entry<Integer, ScanSettings>> getScans() { return mScanSettings.entrySet().iterator(); } @@ -1249,6 +1260,7 @@ public class WifiScanningServiceImpl extends IWifiScanner.Stub { } logScanRequest("addScanRequest", ci, handler, settings); + removeAllScanRequests(); ci.addScanRequest(settings, handler); if (resetBuckets()) { return true; @@ -1272,6 +1284,7 @@ public class WifiScanningServiceImpl extends IWifiScanner.Stub { } logScanRequest("addSingleScanRequest", ci, handler, settings); + removeAllScanRequests(); ci.addScanRequest(settings, handler); if (resetBuckets()) { /* reset periodInMs to 0 to indicate single shot scan */ @@ -1292,6 +1305,13 @@ public class WifiScanningServiceImpl extends IWifiScanner.Stub { } } + void removeAllScanRequests() { + Collection<ClientInfo> clients = mClients.values(); + for (ClientInfo ci : clients) { + ci.removeAllScanRequests(); + } + } + boolean reportScanResults() { ScanData results[] = WifiNative.getScanResults(/* flush = */ true); Collection<ClientInfo> clients = mClients.values(); diff --git a/service/java/com/android/server/wifi/WifiServiceImpl.java b/service/java/com/android/server/wifi/WifiServiceImpl.java index ca85fbc50..33ce852e2 100644 --- a/service/java/com/android/server/wifi/WifiServiceImpl.java +++ b/service/java/com/android/server/wifi/WifiServiceImpl.java @@ -69,6 +69,7 @@ import android.util.Slog; import com.android.internal.R; import com.android.internal.app.IBatteryStats; +import com.android.internal.telephony.IccCardConstants; import com.android.internal.telephony.TelephonyIntents; import com.android.internal.util.AsyncChannel; import com.android.server.am.BatteryStatsService; @@ -358,10 +359,27 @@ public final class WifiServiceImpl extends IWifiManager.Stub { if (mSettingsStore.handleAirplaneModeToggled()) { mWifiController.sendMessage(CMD_AIRPLANE_TOGGLED); } + if (mSettingsStore.isAirplaneModeOn()) { + Log.d(TAG, "resetting country code because Airplane mode is ON"); + mWifiStateMachine.resetCountryCode(); + } } }, new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED)); + mContext.registerReceiver( + new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + String state = intent.getStringExtra(IccCardConstants.INTENT_KEY_ICC_STATE); + if (state.equals(IccCardConstants.INTENT_VALUE_ICC_ABSENT)) { + Log.d(TAG, "resetting country code because SIM is removed"); + mWifiStateMachine.resetCountryCode(); + } + } + }, + new IntentFilter(TelephonyIntents.ACTION_SIM_STATE_CHANGED)); + // Adding optimizations of only receiving broadcasts when wifi is enabled // can result in race conditions when apps toggle wifi in the background // without active user involvement. Always receive broadcasts. @@ -970,7 +988,7 @@ public final class WifiServiceImpl extends IWifiManager.Stub { long ident = Binder.clearCallingIdentity(); try { if (!canReadPeerMacAddresses && !isActiveNetworkScorer - && !isLocationEnabled()) { + && !isLocationEnabled(callingPackage)) { return new ArrayList<ScanResult>(); } if (!canReadPeerMacAddresses && !isActiveNetworkScorer @@ -990,9 +1008,12 @@ public final class WifiServiceImpl extends IWifiManager.Stub { } } - private boolean isLocationEnabled() { - return Settings.Secure.getInt(mContext.getContentResolver(), Settings.Secure.LOCATION_MODE, - Settings.Secure.LOCATION_MODE_OFF) != Settings.Secure.LOCATION_MODE_OFF; + private boolean isLocationEnabled(String callingPackage) { + boolean legacyForegroundApp = !isMApp(mContext, callingPackage) + && isForegroundApp(callingPackage); + return legacyForegroundApp || Settings.Secure.getInt(mContext.getContentResolver(), + Settings.Secure.LOCATION_MODE, Settings.Secure.LOCATION_MODE_OFF) + != Settings.Secure.LOCATION_MODE_OFF; } /** @@ -1101,7 +1122,7 @@ public final class WifiServiceImpl extends IWifiManager.Stub { */ public String getCountryCode() { enforceConnectivityInternalPermission(); - String country = mWifiStateMachine.getCountryCode(); + String country = mWifiStateMachine.getCurrentCountryCode(); return country; } /** @@ -2046,29 +2067,18 @@ public final class WifiServiceImpl extends IWifiManager.Stub { private boolean checkCallerCanAccessScanResults(String callingPackage, int uid) { if (ActivityManager.checkUidPermission(Manifest.permission.ACCESS_FINE_LOCATION, uid) == PackageManager.PERMISSION_GRANTED - && isAppOppAllowed(AppOpsManager.OP_FINE_LOCATION, callingPackage, uid)) { + && checkAppOppAllowed(AppOpsManager.OP_FINE_LOCATION, callingPackage, uid)) { return true; } if (ActivityManager.checkUidPermission(Manifest.permission.ACCESS_COARSE_LOCATION, uid) == PackageManager.PERMISSION_GRANTED - && isAppOppAllowed(AppOpsManager.OP_COARSE_LOCATION, callingPackage, uid)) { + && checkAppOppAllowed(AppOpsManager.OP_COARSE_LOCATION, callingPackage, uid)) { return true; } - // Enforce location permission for apps targeting M and later versions - boolean enforceLocationPermission = true; - try { - enforceLocationPermission = mContext.getPackageManager().getApplicationInfo( - callingPackage, 0).targetSdkVersion >= Build.VERSION_CODES.M; - } catch (PackageManager.NameNotFoundException e) { - // In case of exception, enforce permission anyway - } - if (enforceLocationPermission) { - throw new SecurityException("Need ACCESS_COARSE_LOCATION or " - + "ACCESS_FINE_LOCATION permission to get scan results"); - } + boolean apiLevel23App = isMApp(mContext, callingPackage); // Pre-M apps running in the foreground should continue getting scan results - if (isForegroundApp(callingPackage)) { + if (!apiLevel23App && isForegroundApp(callingPackage)) { return true; } Log.e(TAG, "Permission denial: Need ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION " @@ -2076,10 +2086,20 @@ public final class WifiServiceImpl extends IWifiManager.Stub { return false; } - private boolean isAppOppAllowed(int op, String callingPackage, int uid) { + private boolean checkAppOppAllowed(int op, String callingPackage, int uid) { return mAppOps.noteOp(op, uid, callingPackage) == AppOpsManager.MODE_ALLOWED; } + private static boolean isMApp(Context context, String pkgName) { + try { + return context.getPackageManager().getApplicationInfo(pkgName, 0) + .targetSdkVersion >= Build.VERSION_CODES.M; + } catch (PackageManager.NameNotFoundException e) { + // In case of exception, assume M app (more strict checking) + } + return true; + } + /** * Return true if the specified package name is a foreground app. * diff --git a/service/java/com/android/server/wifi/WifiStateMachine.java b/service/java/com/android/server/wifi/WifiStateMachine.java index 4bc62b324..4e40f7353 100644 --- a/service/java/com/android/server/wifi/WifiStateMachine.java +++ b/service/java/com/android/server/wifi/WifiStateMachine.java @@ -110,6 +110,7 @@ import com.android.internal.util.AsyncChannel; import com.android.internal.util.Protocol; import com.android.internal.util.State; import com.android.internal.util.StateMachine; +import com.android.server.connectivity.KeepalivePacketData; import com.android.server.net.NetlinkTracker; import com.android.server.wifi.hotspot2.NetworkDetail; import com.android.server.wifi.hotspot2.SupplicantBridge; @@ -125,6 +126,7 @@ import java.io.PrintWriter; import java.net.Inet4Address; import java.net.InetAddress; import java.util.ArrayList; +import java.util.Arrays; import java.util.Calendar; import java.util.HashSet; import java.util.LinkedList; @@ -147,7 +149,8 @@ import java.util.regex.Pattern; * * @hide */ -public class WifiStateMachine extends StateMachine implements WifiNative.WifiPnoEventHandler { +public class WifiStateMachine extends StateMachine implements WifiNative.WifiPnoEventHandler, + WifiNative.WifiRssiEventHandler { private static final String NETWORKTYPE = "WIFI"; private static final String NETWORKTYPE_UNTRUSTED = "WIFI_UT"; @@ -191,7 +194,7 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiPno private WifiAutoJoinController mWifiAutoJoinController; private INetworkManagementService mNwService; private ConnectivityManager mCm; - private WifiLogger mWifiLogger; + private DummyWifiLogger mWifiLogger; private WifiApConfigStore mWifiApConfigStore; private final boolean mP2pSupported; private final AtomicBoolean mP2pConnected = new AtomicBoolean(false); @@ -209,7 +212,7 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiPno private int mNumScanResultsReturned; private boolean mScreenOn = false; - + private int mCurrentAssociateNetworkId = -1; /* Chipset supports background scan */ private final boolean mBackgroundScanSupported; @@ -269,6 +272,37 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiPno mRestartAutoJoinOffloadCounter++; } + @Override + public void onRssiThresholdBreached(byte curRssi) { + if (DBG) { + Log.e(TAG, "onRssiThresholdBreach event. Cur Rssi = " + curRssi); + } + sendMessage(CMD_RSSI_THRESHOLD_BREACH, curRssi); + } + + public void processRssiThreshold(byte curRssi, int reason) { + if (curRssi == Byte.MAX_VALUE || curRssi == Byte.MIN_VALUE) { + Log.wtf(TAG, "processRssiThreshold: Invalid rssi " + curRssi); + return; + } + for (int i = 0; i < mRssiRanges.length; i++) { + if (curRssi < mRssiRanges[i]) { + // Assume sorted values(ascending order) for rssi, + // bounded by high(127) and low(-128) at extremeties + byte maxRssi = mRssiRanges[i]; + byte minRssi = mRssiRanges[i-1]; + // This value of hw has to be believed as this value is averaged and has breached + // the rssi thresholds and raised event to host. This would be eggregious if this + // value is invalid + mWifiInfo.setRssi((int) curRssi); + updateCapabilities(getCurrentWifiConfiguration()); + int ret = startRssiMonitoringOffload(maxRssi, minRssi); + Log.d(TAG, "Re-program RSSI thresholds for " + smToString(reason) + + ": [" + minRssi + ", " + maxRssi + "], curRssi=" + curRssi + " ret=" + ret); + break; + } + } + } public void registerNetworkDisabled(int netId) { // Restart legacy PNO and autojoin offload if needed sendMessage(CMD_RESTART_AUTOJOIN_OFFLOAD, 0, @@ -542,6 +576,8 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiPno private String[] mWhiteListedSsids = null; + private byte[] mRssiRanges; + // Keep track of various statistics, for retrieval by System Apps, i.e. under @SystemApi // We should really persist that into the networkHistory.txt file, and read it back when // WifiStateMachine starts up @@ -786,6 +822,22 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiPno /* used to log if GSCAN was started */ static final int CMD_STARTED_GSCAN_DBG = BASE + 159; + /* used to offload sending IP packet */ + static final int CMD_START_IP_PACKET_OFFLOAD = BASE + 160; + + /* used to stop offload sending IP packet */ + static final int CMD_STOP_IP_PACKET_OFFLOAD = BASE + 161; + + /* used to start rssi monitoring in hw */ + static final int CMD_START_RSSI_MONITORING_OFFLOAD = BASE + 162; + + /* used to stop rssi moniroting in hw */ + static final int CMD_STOP_RSSI_MONITORING_OFFLOAD = BASE + 163; + + /* used to indicated RSSI threshold breach in hw */ + static final int CMD_RSSI_THRESHOLD_BREACH = BASE + 164; + + /* Wifi state machine modes of operation */ /* CONNECT_MODE - connect to any 'known' AP when it becomes available */ @@ -870,9 +922,13 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiPno private int mDelayedStopCounter; private boolean mInDelayedStop = false; - // there is a delay between StateMachine change country code and Supplicant change country code - // here save the current WifiStateMachine set country code - private volatile String mSetCountryCode = null; + // config option that indicate whether or not to reset country code to default when + // cellular radio indicates country code loss + private boolean mRevertCountryCodeOnCellularLoss = false; + + private String mDefaultCountryCode; + + private static final String BOOT_DEFAULT_WIFI_COUNTRY_CODE = "ro.boot.wificountrycode"; // Supplicant doesn't like setting the same country code multiple times (it may drop // currently connected network), so we save the current device set country code here to avoid @@ -1052,8 +1108,6 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiPno WifiTrafficPoller trafficPoller) { super("WifiStateMachine"); mContext = context; - mSetCountryCode = Settings.Global.getString( - mContext.getContentResolver(), Settings.Global.WIFI_COUNTRY_CODE); mInterfaceName = wlanInterface; mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_WIFI, 0, NETWORKTYPE, ""); mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService( @@ -1070,7 +1124,15 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiPno mWifiAutoJoinController = new WifiAutoJoinController(context, this, mWifiConfigStore, mWifiConnectionStatistics, mWifiNative); mWifiMonitor = new WifiMonitor(this, mWifiNative); - mWifiLogger = new WifiLogger(this); + + boolean enableFirmwareLogs = mContext.getResources().getBoolean( + R.bool.config_wifi_enable_wifi_firmware_debugging); + + if (enableFirmwareLogs) { + mWifiLogger = new WifiLogger(this); + } else { + mWifiLogger = new DummyWifiLogger(); + } mWifiInfo = new WifiInfo(); mSupplicantStateTracker = new SupplicantStateTracker(context, this, mWifiConfigStore, @@ -1122,6 +1184,27 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiPno mPrimaryDeviceType = mContext.getResources().getString( R.string.config_wifi_p2p_device_type); + mRevertCountryCodeOnCellularLoss = mContext.getResources().getBoolean( + R.bool.config_wifi_revert_country_code_on_cellular_loss); + + mDefaultCountryCode = SystemProperties.get(BOOT_DEFAULT_WIFI_COUNTRY_CODE); + if (TextUtils.isEmpty(mDefaultCountryCode) == false) { + mDefaultCountryCode = mDefaultCountryCode.toUpperCase(Locale.ROOT); + } + + if (mRevertCountryCodeOnCellularLoss && TextUtils.isEmpty(mDefaultCountryCode)) { + logw("config_wifi_revert_country_code_on_cellular_loss is set, " + + "but there is no default country code!! Resetting ..."); + mRevertCountryCodeOnCellularLoss = false; + } else if (mRevertCountryCodeOnCellularLoss) { + logd("initializing with and will revert to " + mDefaultCountryCode + " on MCC loss"); + } + + if (mRevertCountryCodeOnCellularLoss) { + Settings.Global.putString(mContext.getContentResolver(), + Settings.Global.WIFI_COUNTRY_CODE, mDefaultCountryCode); + } + mUserWantsSuspendOpt.set(Settings.Global.getInt(mContext.getContentResolver(), Settings.Global.WIFI_SUSPEND_OPTIMIZATIONS_ENABLED, 1) == 1); @@ -1272,7 +1355,7 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiPno PendingIntent getPrivateBroadcast(String action, int requestCode) { Intent intent = new Intent(action, null); intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); - //intent.setPackage(this.getClass().getPackage().getName()); + // TODO: Find the correct value so this is not hard coded intent.setPackage("android"); return PendingIntent.getBroadcast(mContext, requestCode, intent, 0); } @@ -1783,8 +1866,40 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiPno } } + int startWifiIPPacketOffload(int slot, KeepalivePacketData packetData, int intervalSeconds) { + int ret = mWifiNative.startSendingOffloadedPacket(slot, packetData, intervalSeconds * 1000); + if (ret != 0) { + loge("startWifiIPPacketOffload(" + slot + ", " + intervalSeconds + + "): hardware error " + ret); + return ConnectivityManager.PacketKeepalive.ERROR_HARDWARE_ERROR; + } else { + return ConnectivityManager.PacketKeepalive.SUCCESS; + } + } + + int stopWifiIPPacketOffload(int slot) { + int ret = mWifiNative.stopSendingOffloadedPacket(slot); + if (ret != 0) { + loge("stopWifiIPPacketOffload(" + slot + "): hardware error " + ret); + return ConnectivityManager.PacketKeepalive.ERROR_HARDWARE_ERROR; + } else { + return ConnectivityManager.PacketKeepalive.SUCCESS; + } + } + + int startRssiMonitoringOffload(byte maxRssi, byte minRssi) { + return mWifiNative.startRssiMonitoring(maxRssi, minRssi, WifiStateMachine.this); + } + + int stopRssiMonitoringOffload() { + return mWifiNative.stopRssiMonitoring(); + } + // If workSource is not null, blame is given to it, otherwise blame is given to callingUid. private void noteScanStart(int callingUid, WorkSource workSource) { + if (lastStartScanTimeStamp != 0) { + noteScanEnd(); + } long now = System.currentTimeMillis(); lastStartScanTimeStamp = now; lastScanDuration = 0; @@ -1804,14 +1919,13 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiPno || workSource != null)) { mScanWorkSource = workSource != null ? workSource : new WorkSource(callingUid); - WorkSource batteryWorkSource = mScanWorkSource; if (mScanWorkSource.size() == 1 && mScanWorkSource.get(0) < 0) { // WiFi uses negative UIDs to mean special things. BatteryStats don't care! - batteryWorkSource = new WorkSource(Process.WIFI_UID); + mScanWorkSource = new WorkSource(Process.WIFI_UID); } try { - mBatteryStats.noteWifiScanStartedFromSource(batteryWorkSource); + mBatteryStats.noteWifiScanStartedFromSource(mScanWorkSource); } catch (RemoteException e) { log(e.toString()); } @@ -1819,6 +1933,7 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiPno } private void noteScanEnd() { + closeRadioScanStats(); long now = System.currentTimeMillis(); if (lastStartScanTimeStamp != 0) { lastScanDuration = now - lastStartScanTimeStamp; @@ -2242,7 +2357,9 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiPno if (enable) { mWifiConfigStore.enableAllNetworks(); } - boolean ret = mWifiNative.enableBackgroundScan(enable); + List<WifiNative.PnoNetworkPriority> pnoList = + mWifiConfigStore.retrievePnoNetworkPriorityList(enable); + boolean ret = mWifiNative.enableBackgroundScan(enable, pnoList); if (ret) { mLegacyPnoEnabled = enable; } else { @@ -2328,25 +2445,31 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiPno // for now (it is unclear what the chipset should do when // country code is reset) + // if mCountryCodeSequence == 0, it is the first time to set country code, always set + // else only when the new country code is different from the current one to set + if (TextUtils.isEmpty(countryCode)) { - log("Ignoring resetting of country code"); + if (DBG) log("Ignoring resetting of country code"); } else { - // if mCountryCodeSequence == 0, it is the first time to set country code, always set - // else only when the new country code is different from the current one to set int countryCodeSequence = mCountryCodeSequence.get(); - if (countryCodeSequence == 0 || countryCode.equals(mSetCountryCode) == false) { + String currentCountryCode = getCurrentCountryCode(); + if (countryCodeSequence == 0 + || TextUtils.equals(countryCode, currentCountryCode) == false) { countryCodeSequence = mCountryCodeSequence.incrementAndGet(); - mSetCountryCode = countryCode; - sendMessage(CMD_SET_COUNTRY_CODE, countryCodeSequence, persist ? 1 : 0, + sendMessage(CMD_SET_COUNTRY_CODE, countryCodeSequence, persist ? 1 : 0, countryCode); } + } + } - if (persist) { - Settings.Global.putString(mContext.getContentResolver(), - Settings.Global.WIFI_COUNTRY_CODE, - countryCode); - } + /** + * reset the country code to default + */ + public synchronized void resetCountryCode() { + if (mRevertCountryCodeOnCellularLoss && TextUtils.isEmpty(mDefaultCountryCode) == false) { + logd("resetting country code to " + mDefaultCountryCode); + setCountryCode(mDefaultCountryCode, /* persist = */ true); } } @@ -2365,13 +2488,13 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiPno /** * Get the country code * - * @param countryCode following ISO 3166 format + * @return countryCode following ISO 3166 format */ - public String getCountryCode() { - return mSetCountryCode; + public String getCurrentCountryCode() { + return Settings.Global.getString( + mContext.getContentResolver(), Settings.Global.WIFI_COUNTRY_CODE); } - /** * Set the operational frequency band * @@ -2499,7 +2622,6 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiPno pw.println("mSuspendOptNeedsDisabled " + mSuspendOptNeedsDisabled); pw.println("Supplicant status " + mWifiNative.status(true)); pw.println("mLegacyPnoEnabled " + mLegacyPnoEnabled); - pw.println("mSetCountryCode " + mSetCountryCode); pw.println("mDriverSetCountryCode " + mDriverSetCountryCode); pw.println("mConnectedModeGScanOffloadStarted " + mConnectedModeGScanOffloadStarted); pw.println("mGScanPeriodMilli " + mGScanPeriodMilli); @@ -3123,6 +3245,14 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiPno sb.append(Integer.toString(msg.arg2)); sb.append(" cur=").append(disconnectingWatchdogCount); break; + case CMD_START_RSSI_MONITORING_OFFLOAD: + case CMD_STOP_RSSI_MONITORING_OFFLOAD: + case CMD_RSSI_THRESHOLD_BREACH: + sb.append(" rssi="); + sb.append(Integer.toString(msg.arg1)); + sb.append(" thresholds="); + sb.append(Arrays.toString(mRssiRanges)); + break; default: sb.append(" "); sb.append(Integer.toString(msg.arg1)); @@ -3426,7 +3556,6 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiPno + " suppState:" + mSupplicantStateTracker.getSupplicantStateName()); } enableRssiPolling(screenOn); - if (screenOn) enableAllNetworks(); if (mUserWantsSuspendOpt.get()) { if (screenOn) { sendMessage(CMD_SET_SUSPEND_OPT_ENABLED, 0, 0); @@ -3588,9 +3717,8 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiPno /** * Set the country code from the system setting value, if any. */ - private void setCountryCode() { - String countryCode = Settings.Global.getString(mContext.getContentResolver(), - Settings.Global.WIFI_COUNTRY_CODE); + private void initializeCountryCode() { + String countryCode = getCurrentCountryCode(); if (countryCode != null && !countryCode.isEmpty()) { setCountryCode(countryCode, false); } else { @@ -3615,8 +3743,6 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiPno } } - - private void setSuspendOptimizationsNative(int reason, boolean enabled) { if (DBG) { log("setSuspendOptimizationsNative: " + reason + " " + enabled @@ -3711,21 +3837,6 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiPno mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); } - /* - void ageOutScanResults(int age) { - synchronized(mScanResultCache) { - // Trim mScanResults, which prevent WifiStateMachine to return - // obsolete scan results to queriers - long now = System.CurrentTimeMillis(); - for (int i = 0; i < mScanResults.size(); i++) { - ScanResult result = mScanResults.get(i); - if ((result.seen > now || (now - result.seen) > age)) { - mScanResults.remove(i); - } - } - } - }*/ - private static final String IE_STR = "ie="; private static final String ID_STR = "id="; private static final String BSSID_STR = "bssid="; @@ -3737,8 +3848,6 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiPno private static final String DELIMITER_STR = "===="; private static final String END_STR = "####"; - int emptyScanResultCount = 0; - // Used for matching BSSID strings, at least one characteer must be a non-zero number private static Pattern mNotZero = Pattern.compile("[1-9a-fA-F]"); @@ -3798,23 +3907,13 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiPno if (sid == -1) break; } - // Age out scan results, we return all scan results found in the last 12 seconds, - // and NOT all scan results since last scan. - // ageOutScanResults(12000); - scanResults = scanResultsBuf.toString(); + if (TextUtils.isEmpty(scanResults)) { - emptyScanResultCount++; - if (emptyScanResultCount > 10) { - // If we got too many empty scan results, the current scan cache is stale, - // hence clear it. - mScanResults = new ArrayList<>(); - } + mScanResults = new ArrayList<>(); return; } - emptyScanResultCount = 0; - mWifiConfigStore.trimANQPCache(false); // note that all these splits and substrings keep references to the original @@ -3929,7 +4028,8 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiPno || state == SupplicantState.GROUP_HANDSHAKE || (/* keep autojoin enabled if user has manually selected a wifi network, so as to make sure we reliably remain connected to this network */ - mConnectionRequests == 0 && selection == null)) { + mConnectionRequests == 0 && selection == null) + || mInDelayedStop) { // Dont attempt auto-joining again while we are already attempting to join // and/or obtaining Ip address attemptAutoJoin = false; @@ -3974,9 +4074,9 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiPno * Fetch RSSI, linkspeed, and frequency on current connection */ private void fetchRssiLinkSpeedAndFrequencyNative() { - int newRssi = -1; - int newLinkSpeed = -1; - int newFrequency = -1; + Integer newRssi = null; + Integer newLinkSpeed = null; + Integer newFrequency = null; String signalPoll = mWifiNative.signalPoll(); @@ -4000,12 +4100,11 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiPno } if (PDBG) { - logd("fetchRssiLinkSpeedAndFrequencyNative rssi=" - + Integer.toString(newRssi) + " linkspeed=" - + Integer.toString(newLinkSpeed)); + logd("fetchRssiLinkSpeedAndFrequencyNative rssi=" + newRssi + + " linkspeed=" + newLinkSpeed + " freq=" + newFrequency); } - if (newRssi > WifiInfo.INVALID_RSSI && newRssi < WifiInfo.MAX_RSSI) { + if (newRssi != null && newRssi > WifiInfo.INVALID_RSSI && newRssi < WifiInfo.MAX_RSSI) { // screen out invalid values /* some implementations avoid negative values by adding 256 * so we need to adjust for that here. @@ -4024,17 +4123,19 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiPno */ int newSignalLevel = WifiManager.calculateSignalLevel(newRssi, WifiManager.RSSI_LEVELS); if (newSignalLevel != mLastSignalLevel) { + updateCapabilities(getCurrentWifiConfiguration()); sendRssiChangeBroadcast(newRssi); } mLastSignalLevel = newSignalLevel; } else { mWifiInfo.setRssi(WifiInfo.INVALID_RSSI); + updateCapabilities(getCurrentWifiConfiguration()); } - if (newLinkSpeed != -1) { + if (newLinkSpeed != null) { mWifiInfo.setLinkSpeed(newLinkSpeed); } - if (newFrequency > 0) { + if (newFrequency != null && newFrequency > 0) { if (ScanResult.is5GHz(newFrequency)) { mWifiConnectionStatistics.num5GhzConnected++; } @@ -4856,6 +4957,7 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiPno + " - " + Thread.currentThread().getStackTrace()[4].getMethodName() + " - " + Thread.currentThread().getStackTrace()[5].getMethodName()); + stopRssiMonitoringOffload(); clearCurrentConfigBSSID("handleNetworkDisconnect"); @@ -5204,8 +5306,10 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiPno //not available, like razor, we regress to original implementaion (2GHz, channel 6) if (mWifiNative.isHalStarted()) { //set country code through HAL Here - if (mSetCountryCode != null) { - if (!mWifiNative.setCountryCodeHal(mSetCountryCode.toUpperCase(Locale.ROOT))) { + String countryCode = getCurrentCountryCode(); + + if (countryCode != null) { + if (!mWifiNative.setCountryCodeHal(countryCode.toUpperCase(Locale.ROOT))) { if (config.apBand != 0) { Log.e(TAG, "Fail to set country code. Can not setup Softap on 5GHz"); //countrycode is mandatory for 5GHz @@ -5264,6 +5368,19 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiPno }).start(); } + private byte[] macAddressFromString(String macString) { + String[] macBytes = macString.split(":"); + if (macBytes.length != 6) { + throw new IllegalArgumentException("MAC address should be 6 bytes long!"); + } + byte[] mac = new byte[6]; + for (int i = 0; i < macBytes.length; i++) { + Integer hexVal = Integer.parseInt(macBytes[i], 16); + mac[i] = hexVal.byteValue(); + } + return mac; + } + /* * Read a MAC address in /proc/arp/table, used by WifistateMachine * so as to record MAC address of default gateway. @@ -5492,7 +5609,6 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiPno case CMD_BLACKLIST_NETWORK: case CMD_CLEAR_BLACKLIST: case CMD_SET_OPERATIONAL_MODE: - case CMD_SET_COUNTRY_CODE: case CMD_SET_FREQUENCY_BAND: case CMD_RSSI_POLL: case CMD_ENABLE_ALL_NETWORKS: @@ -5526,6 +5642,24 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiPno case CMD_UPDATE_ASSOCIATED_SCAN_PERMISSION: messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD; break; + case CMD_SET_COUNTRY_CODE: + String country = (String) message.obj; + final boolean persist = (message.arg2 == 1); + final int sequence = message.arg1; + if (sequence != mCountryCodeSequence.get()) { + if (DBG) log("set country code ignored due to sequnce num"); + break; + } + + if (persist) { + country = country.toUpperCase(Locale.ROOT); + if (DBG) log("set country code " + (country == null ? "(null)" : country)); + Settings.Global.putString(mContext.getContentResolver(), + Settings.Global.WIFI_COUNTRY_CODE, + country == null ? "" : country); + } + + break; case DhcpStateMachine.CMD_ON_QUIT: mDhcpStateMachine = null; break; @@ -5613,6 +5747,22 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiPno case CMD_REMOVE_USER_CONFIGURATIONS: deferMessage(message); break; + case CMD_START_IP_PACKET_OFFLOAD: + if (mNetworkAgent != null) mNetworkAgent.onPacketKeepaliveEvent( + message.arg1, + ConnectivityManager.PacketKeepalive.ERROR_INVALID_NETWORK); + break; + case CMD_STOP_IP_PACKET_OFFLOAD: + if (mNetworkAgent != null) mNetworkAgent.onPacketKeepaliveEvent( + message.arg1, + ConnectivityManager.PacketKeepalive.ERROR_INVALID_NETWORK); + break; + case CMD_START_RSSI_MONITORING_OFFLOAD: + messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD; + break; + case CMD_STOP_RSSI_MONITORING_OFFLOAD: + messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD; + break; default: loge("Error! unhandled message" + message); break; @@ -5843,7 +5993,7 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiPno WifiNative.setDfsFlag(true); /* set country code */ - setCountryCode(); + initializeCountryCode(); setRandomMacOui(); mWifiNative.enableAutoConnect(false); @@ -5876,7 +6026,6 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiPno case WifiMonitor.SCAN_RESULTS_EVENT: case WifiMonitor.SCAN_FAILED_EVENT: maybeRegisterNetworkFactory(); // Make sure our NetworkFactory is registered - closeRadioScanStats(); noteScanEnd(); setScanResults(); if (mIsFullScanOngoing || mSendScanResultsBroadcast) { @@ -5924,18 +6073,18 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiPno break; case CMD_SET_COUNTRY_CODE: String country = (String) message.obj; - final boolean persist = (message.arg2 == 1); final int sequence = message.arg1; - if (sequence != mCountryCodeSequence.get()) { if (DBG) log("set country code ignored due to sequnce num"); break; } - if (DBG) log("set country code " + country); + country = country.toUpperCase(Locale.ROOT); - if (mDriverSetCountryCode == null || !mDriverSetCountryCode.equals(country)) { + if (DBG) log("set country code " + (country == null ? "(null)" : country)); + + if (!TextUtils.equals(mDriverSetCountryCode, country)) { if (mWifiNative.setCountryCode(country)) { mDriverSetCountryCode = country; } else { @@ -5943,6 +6092,12 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiPno } } + if (persist) { + Settings.Global.putString(mContext.getContentResolver(), + Settings.Global.WIFI_COUNTRY_CODE, + country == null ? "" : country); + } + mWifiP2pChannel.sendMessage(WifiP2pServiceImpl.SET_COUNTRY_CODE, country); break; default: @@ -6241,7 +6396,7 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiPno /* send regular delayed shut down */ Intent driverStopIntent = new Intent(ACTION_DELAYED_DRIVER_STOP, null); - driverStopIntent.setPackage(this.getClass().getPackage().getName()); + driverStopIntent.setPackage("android"); driverStopIntent.putExtra(DELAYED_STOP_COUNTER, mDelayedStopCounter); mDriverStopIntent = PendingIntent.getBroadcast(mContext, DRIVER_STOP_REQUEST, driverStopIntent, @@ -6320,6 +6475,14 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiPno case WifiMonitor.ANQP_DONE_EVENT: mWifiConfigStore.notifyANQPDone((Long) message.obj, message.arg1 != 0); break; + case CMD_STOP_IP_PACKET_OFFLOAD: { + int slot = message.arg1; + int ret = stopWifiIPPacketOffload(slot); + if (mNetworkAgent != null) { + mNetworkAgent.onPacketKeepaliveEvent(slot, ret); + } + break; + } default: return NOT_HANDLED; } @@ -6505,6 +6668,10 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiPno case CMD_START_SCAN: handleScanRequest(WifiNative.SCAN_WITHOUT_CONNECTION_SETUP, message); break; + case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: + SupplicantState state = handleSupplicantStateChange(message); + if(DBG) log("SupplicantState= " + state); + break; default: return NOT_HANDLED; } @@ -6760,6 +6927,9 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiPno case WifiMonitor.GAS_QUERY_START_EVENT: s = "WifiMonitor.GAS_QUERY_START_EVENT"; break; + case WifiMonitor.RSN_PMKID_MISMATCH_EVENT: + s = "WifiMonitor.RSN_PMKID_MISMATCH_EVENT"; + break; case CMD_SET_OPERATIONAL_MODE: s = "CMD_SET_OPERATIONAL_MODE"; break; @@ -6877,6 +7047,21 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiPno case CMD_UPDATE_ASSOCIATED_SCAN_PERMISSION: s = "CMD_UPDATE_ASSOCIATED_SCAN_PERMISSION"; break; + case CMD_START_IP_PACKET_OFFLOAD: + s = "CMD_START_IP_PACKET_OFFLOAD"; + break; + case CMD_STOP_IP_PACKET_OFFLOAD: + s = "CMD_STOP_IP_PACKET_OFFLOAD"; + break; + case CMD_START_RSSI_MONITORING_OFFLOAD: + s = "CMD_START_RSSI_MONITORING_OFFLOAD"; + break; + case CMD_STOP_RSSI_MONITORING_OFFLOAD: + s = "CMD_STOP_RSSI_MONITORING_OFFLOAD"; + break; + case CMD_RSSI_THRESHOLD_BREACH: + s = "CMD_RSSI_THRESHOLD_BREACH"; + break; default: s = "what:" + Integer.toString(what); break; @@ -7065,6 +7250,13 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiPno mIpReachabilityMonitor.probeAll(); } } + + if (state == SupplicantState.ASSOCIATED) { + StateChangeResult stateChangeResult = (StateChangeResult) message.obj; + if (stateChangeResult != null) { + mCurrentAssociateNetworkId = stateChangeResult.networkId; + } + } break; case WifiP2pServiceImpl.DISCONNECT_WIFI_REQUEST: if (message.arg1 == 1) { @@ -7769,13 +7961,17 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiPno } private void updateCapabilities(WifiConfiguration config) { - if (config.ephemeral) { - mNetworkCapabilities.removeCapability( - NetworkCapabilities.NET_CAPABILITY_TRUSTED); - } else { - mNetworkCapabilities.addCapability( - NetworkCapabilities.NET_CAPABILITY_TRUSTED); + if (config != null) { + if (config.ephemeral) { + mNetworkCapabilities.removeCapability( + NetworkCapabilities.NET_CAPABILITY_TRUSTED); + } else { + mNetworkCapabilities.addCapability( + NetworkCapabilities.NET_CAPABILITY_TRUSTED); + } } + mNetworkCapabilities.setSignalStrength(mWifiInfo.getRssi() != WifiInfo.INVALID_RSSI ? + mWifiInfo.getRssi() : NetworkCapabilities.SIGNAL_STRENGTH_UNSPECIFIED); mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities); } @@ -7813,6 +8009,59 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiPno } @Override + protected void startPacketKeepalive(Message msg) { + WifiStateMachine.this.sendMessage( + CMD_START_IP_PACKET_OFFLOAD, msg.arg1, msg.arg2, msg.obj); + } + + @Override + protected void stopPacketKeepalive(Message msg) { + WifiStateMachine.this.sendMessage( + CMD_STOP_IP_PACKET_OFFLOAD, msg.arg1, msg.arg2, msg.obj); + } + + @Override + protected void setSignalStrengthThresholds(int[] thresholds) { + // 0. If there are no thresholds, or if the thresholds are invalid, stop RSSI monitoring. + // 1. Tell the hardware to start RSSI monitoring here, possibly adding MIN_VALUE and + // MAX_VALUE at the start/end of the thresholds array if necessary. + // 2. Ensure that when the hardware event fires, we fetch the RSSI from the hardware + // event, call mWifiInfo.setRssi() with it, and call updateCapabilities(), and then + // re-arm the hardware event. This needs to be done on the state machine thread to + // avoid race conditions. The RSSI used to re-arm the event (and perhaps also the one + // sent in the NetworkCapabilities) must be the one received from the hardware event + // received, or we might skip callbacks. + // 3. Ensure that when we disconnect, RSSI monitoring is stopped. + log("Received signal strength thresholds: " + Arrays.toString(thresholds)); + if (thresholds.length == 0) { + WifiStateMachine.this.sendMessage(CMD_STOP_RSSI_MONITORING_OFFLOAD, + mWifiInfo.getRssi()); + return; + } + int [] rssiVals = Arrays.copyOf(thresholds, thresholds.length + 2); + rssiVals[rssiVals.length - 2] = Byte.MIN_VALUE; + rssiVals[rssiVals.length - 1] = Byte.MAX_VALUE; + Arrays.sort(rssiVals); + byte[] rssiRange = new byte[rssiVals.length]; + for (int i = 0; i < rssiVals.length; i++) { + int val = rssiVals[i]; + if (val <= Byte.MAX_VALUE && val >= Byte.MIN_VALUE) { + rssiRange[i] = (byte) val; + } else { + Log.e(TAG, "Illegal value " + val + " for RSSI thresholds: " + + Arrays.toString(rssiVals)); + WifiStateMachine.this.sendMessage(CMD_STOP_RSSI_MONITORING_OFFLOAD, + mWifiInfo.getRssi()); + return; + } + } + // TODO: Do we quash rssi values in this sorted array which are very close? + mRssiRanges = rssiRange; + WifiStateMachine.this.sendMessage(CMD_START_RSSI_MONITORING_OFFLOAD, + mWifiInfo.getRssi()); + } + + @Override protected void preventAutomaticReconnect() { if (this != mNetworkAgent) return; unwantedNetwork(NETWORK_STATUS_UNWANTED_DISABLE_AUTOJOIN); @@ -7963,6 +8212,7 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiPno try { mIpReachabilityMonitor = new IpReachabilityMonitor( + mContext, mInterfaceName, new IpReachabilityMonitor.Callback() { @Override @@ -8227,8 +8477,14 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiPno break; } return NOT_HANDLED; - /* Ignore */ case WifiMonitor.NETWORK_CONNECTION_EVENT: + mWifiInfo.setBSSID((String) message.obj); + mLastNetworkId = message.arg1; + mWifiInfo.setNetworkId(mLastNetworkId); + if(!mLastBssid.equals((String) message.obj)) { + mLastBssid = (String) message.obj; + sendNetworkStateChangeBroadcast(mLastBssid); + } break; case CMD_RSSI_POLL: if (message.arg1 == mRssiPollToken) { @@ -8310,6 +8566,14 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiPno sendNetworkStateChangeBroadcast(mLastBssid); } break; + case CMD_START_RSSI_MONITORING_OFFLOAD: + case CMD_RSSI_THRESHOLD_BREACH: + byte currRssi = (byte) message.arg1; + processRssiThreshold(currRssi, message.what); + break; + case CMD_STOP_RSSI_MONITORING_OFFLOAD: + stopRssiMonitoringOffload(); + break; default: return NOT_HANDLED; } @@ -8928,6 +9192,27 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiPno break; } break; + case CMD_START_IP_PACKET_OFFLOAD: { + int slot = message.arg1; + int intervalSeconds = message.arg2; + KeepalivePacketData pkt = (KeepalivePacketData) message.obj; + byte[] dstMac; + try { + InetAddress gateway = RouteInfo.selectBestRoute( + mLinkProperties.getRoutes(), pkt.dstAddress).getGateway(); + String dstMacStr = macAddressFromRoute(gateway.getHostAddress()); + dstMac = macAddressFromString(dstMacStr); + } catch (NullPointerException|IllegalArgumentException e) { + loge("Can't find MAC address for next hop to " + pkt.dstAddress); + mNetworkAgent.onPacketKeepaliveEvent(slot, + ConnectivityManager.PacketKeepalive.ERROR_INVALID_IP_ADDRESS); + break; + } + pkt.dstMac = dstMac; + int result = startWifiIPPacketOffload(slot, pkt, intervalSeconds); + mNetworkAgent.onPacketKeepaliveEvent(slot, result); + break; + } default: return NOT_HANDLED; } @@ -9033,9 +9318,9 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiPno } else { if (mScreenOn) { /** - * screen lit and => delayed timer + * screen lit and => start scan immediately */ - startDelayedScan(500, null, null); + startScan(UNKNOWN_SCAN_SOURCE, 0, null, null); } else { /** * screen dark and PNO supported => scan alarm disabled @@ -9284,6 +9569,22 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiPno case CMD_SCREEN_STATE_CHANGED: handleScreenStateChanged(message.arg1 != 0); break; + case WifiMonitor.RSN_PMKID_MISMATCH_EVENT: + //WAR: In release M, there is a TLS bugs for some radius. M upgrade the TLS to + // 1.2. However,some old radius can not support it. So if possibly disconnected + // due to TLS failure, we will toggler the TLS version between 1.1 and 1.2 for + // next retry connection + int nid = mCurrentAssociateNetworkId; + WifiConfiguration currentNet = mWifiConfigStore.getWifiConfiguration(nid); + if (currentNet != null && currentNet.enterpriseConfig != null) { + currentNet.enterpriseConfig.setTls12Enable( + !currentNet.enterpriseConfig.getTls12Enable()); + mWifiConfigStore.saveNetwork(currentNet, WifiConfiguration.UNKNOWN_UID); + Log.e(TAG, "NetWork ID =" + nid + " switch to TLS1.2: " + + currentNet.enterpriseConfig.getTls12Enable()); + } + + break; default: ret = NOT_HANDLED; } diff --git a/service/jni/com_android_server_wifi_WifiNative.cpp b/service/jni/com_android_server_wifi_WifiNative.cpp index bf073f7cd..4c450b3b3 100644 --- a/service/jni/com_android_server_wifi_WifiNative.cpp +++ b/service/jni/com_android_server_wifi_WifiNative.cpp @@ -32,7 +32,7 @@ #include "jni_helper.h" #include "rtt.h" #include "wifi_hal_stub.h" -#define REPLY_BUF_SIZE 4096 // wpa_supplicant's maximum size. +#define REPLY_BUF_SIZE 4096 + 1 // wpa_supplicant's maximum size + 1 for nul #define EVENT_BUF_SIZE 2048 namespace android { @@ -138,7 +138,12 @@ static jboolean doBooleanCommand(JNIEnv* env, jstring javaCommand) { if (!doCommand(env, javaCommand, reply, sizeof(reply))) { return JNI_FALSE; } - return (strcmp(reply, "OK") == 0); + jboolean result = (strcmp(reply, "OK") == 0); + if (!result) { + ScopedUtfChars command(env, javaCommand); + ALOGI("command '%s' returned '%s", command.c_str(), reply); + } + return result; } // Send a command to the supplicant, and return the reply as a String. @@ -2080,6 +2085,88 @@ static jboolean android_net_wifi_setSsidWhitelist( return hal_fn.wifi_set_ssid_white_list(id, handle, num_ssids, ssids) == WIFI_SUCCESS; } +static jint android_net_wifi_start_sending_offloaded_packet(JNIEnv *env, jclass cls, jint iface, + jint idx, jbyteArray srcMac, jbyteArray dstMac, jbyteArray pkt, jint period) { + JNIHelper helper(env); + wifi_interface_handle handle = getIfaceHandle(helper, cls, iface); + ALOGD("Start packet offload [%d] = %p", idx, handle); + wifi_error ret; + wifi_request_id id = idx; + + ScopedBytesRO pktBytes(env, pkt), srcMacBytes(env, srcMac), dstMacBytes(env, dstMac); + + byte * pkt_data = (byte*) pktBytes.get(); + unsigned short pkt_len = env->GetArrayLength(pkt); + byte* src_mac_addr = (byte*) srcMacBytes.get(); + byte* dst_mac_addr = (byte*) dstMacBytes.get(); + int i; + char macAddr[32]; + sprintf(macAddr, "%0x:%0x:%0x:%0x:%0x:%0x", src_mac_addr[0], src_mac_addr[1], + src_mac_addr[2], src_mac_addr[3], src_mac_addr[4], src_mac_addr[5]); + ALOGD("src_mac_addr %s", macAddr); + sprintf(macAddr, "%0x:%0x:%0x:%0x:%0x:%0x", dst_mac_addr[0], dst_mac_addr[1], + dst_mac_addr[2], dst_mac_addr[3], dst_mac_addr[4], dst_mac_addr[5]); + ALOGD("dst_mac_addr %s", macAddr); + ALOGD("pkt_len %d\n", pkt_len); + ALOGD("Pkt data : "); + for(i = 0; i < pkt_len; i++) { + ALOGD(" %x ", pkt_data[i]); + } + ALOGD("\n"); + ret = hal_fn.wifi_start_sending_offloaded_packet(id, handle, pkt_data, pkt_len, + src_mac_addr, dst_mac_addr, period); + ALOGD("ret= %d\n", ret); + return ret; +} + +static jint android_net_wifi_stop_sending_offloaded_packet(JNIEnv *env, jclass cls, + jint iface, jint idx) { + int ret; + JNIHelper helper(env); + wifi_interface_handle handle = getIfaceHandle(helper, cls, iface); + ALOGD("Stop packet offload [%d] = %p", idx, handle); + ret = hal_fn.wifi_stop_sending_offloaded_packet(idx, handle); + ALOGD("ret= %d\n", ret); + return ret; +} + +static void onRssiThresholdbreached(wifi_request_id id, u8 *cur_bssid, s8 cur_rssi) { + + ALOGD("RSSI threshold breached, cur RSSI - %d!!\n", cur_rssi); + ALOGD("BSSID %02x:%02x:%02x:%02x:%02x:%02x\n", + cur_bssid[0], cur_bssid[1], cur_bssid[2], + cur_bssid[3], cur_bssid[4], cur_bssid[5]); + JNIHelper helper(mVM); + //ALOGD("onRssiThresholdbreached called, vm = %p, obj = %p, env = %p", mVM, mCls, env); + helper.reportEvent(mCls, "onRssiThresholdBreached", "(IB)V", id, cur_rssi); +} + +static jint android_net_wifi_start_rssi_monitoring_native(JNIEnv *env, jclass cls, jint iface, + jint idx, jbyte maxRssi, jbyte minRssi) { + + JNIHelper helper(env); + wifi_interface_handle handle = getIfaceHandle(helper, cls, iface); + ALOGD("Start Rssi monitoring = %p", handle); + ALOGD("MinRssi %d MaxRssi %d", minRssi, maxRssi); + wifi_error ret; + wifi_request_id id = idx; + wifi_rssi_event_handler eh; + eh.on_rssi_threshold_breached = onRssiThresholdbreached; + ret = hal_fn.wifi_start_rssi_monitoring(id, handle, maxRssi, minRssi, eh); + return ret; +} + +static jint android_net_wifi_stop_rssi_monitoring_native(JNIEnv *env, jclass cls, + jint iface, jint idx) { + JNIHelper helper(env); + wifi_interface_handle handle = getIfaceHandle(helper, cls, iface); + ALOGD("Stop Rssi monitoring = %p", handle); + wifi_error ret; + wifi_request_id id = idx; + ret = hal_fn.wifi_stop_rssi_monitoring(id, handle); + return ret; +} + // ---------------------------------------------------------------------------- /* @@ -2167,6 +2254,14 @@ static JNINativeMethod gWifiMethods[] = { (void*)android_net_wifi_setSsidWhitelist}, {"setLoggingEventHandlerNative", "(II)Z", (void *) android_net_wifi_set_log_handler}, {"resetLogHandlerNative", "(II)Z", (void *) android_net_wifi_reset_log_handler}, + { "startSendingOffloadedPacketNative", "(II[B[B[BI)I", + (void*)android_net_wifi_start_sending_offloaded_packet}, + { "stopSendingOffloadedPacketNative", "(II)I", + (void*)android_net_wifi_stop_sending_offloaded_packet}, + {"startRssiMonitoringNative", "(IIBB)I", + (void*)android_net_wifi_start_rssi_monitoring_native}, + {"stopRssiMonitoringNative", "(II)I", + (void*)android_net_wifi_stop_rssi_monitoring_native}, {"isGetChannelsForBandSupportedNative", "()Z", (void*)android_net_wifi_is_get_channels_for_band_supported} }; |