diff options
Diffstat (limited to 'service')
-rw-r--r-- | service/java/com/android/server/wifi/WifiNative.java | 82 | ||||
-rw-r--r-- | service/java/com/android/server/wifi/WifiStateMachine.java | 209 | ||||
-rw-r--r-- | service/jni/com_android_server_wifi_WifiNative.cpp | 84 |
3 files changed, 374 insertions, 1 deletions
diff --git a/service/java/com/android/server/wifi/WifiNative.java b/service/java/com/android/server/wifi/WifiNative.java index 899529ddd..d762f4727 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; @@ -2391,4 +2393,84 @@ 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()) { + sRssiMonitorCmdId = getNewCmdIdLocked(); + Log.d(TAG, "sRssiMonitorCmdId = " + sRssiMonitorCmdId); + return startRssiMonitoringNative(sWlan0Index, sRssiMonitorCmdId, maxRssi, minRssi); + } 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()) { + return stopRssiMonitoringNative(sWlan0Index, sRssiMonitorCmdId); + } else { + return -1; + } + } + } } diff --git a/service/java/com/android/server/wifi/WifiStateMachine.java b/service/java/com/android/server/wifi/WifiStateMachine.java index 60148be53..aa1750c52 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"; @@ -269,6 +272,34 @@ 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) { + 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(-127) at extremeties + byte maxRssi = mRssiRanges[i]; + byte minRssi = mRssiRanges[i-1]; + Log.d(TAG, "Re-program rssi thresholds" + "maxRssi=" + maxRssi + + " minRssi=" + minRssi + " curRssi=" + curRssi); + // 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, "Post re-programming rssi threshold ret = " + ret); + break; + } + } + } public void registerNetworkDisabled(int netId) { // Restart legacy PNO and autojoin offload if needed sendMessage(CMD_RESTART_AUTOJOIN_OFFLOAD, 0, @@ -542,6 +573,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 +819,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 */ @@ -1783,6 +1832,22 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiPno } } + int startWifiIPPacketOffload(int slot, KeepalivePacketData packetData, int intervalSeconds) { + return mWifiNative.startSendingOffloadedPacket(slot, packetData, intervalSeconds * 1000); + } + + int stopWifiIPPacketOffload(int slot) { + return mWifiNative.stopSendingOffloadedPacket(slot); + } + + 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) { long now = System.currentTimeMillis(); @@ -2316,6 +2381,14 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiPno sendMessage(CMD_SET_HIGH_PERF_MODE, enable ? 1 : 0, 0); } + public int stopRssiMonitoring(AsyncChannel channel) { + Message resultMsg = channel.sendMessageSynchronously(CMD_STOP_RSSI_MONITORING_OFFLOAD, + mRssiRanges); + int ret = (int)resultMsg.obj; + resultMsg.recycle(); + return ret; + } + /** * Set the country code * @@ -4014,11 +4087,13 @@ 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) { @@ -5243,6 +5318,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. @@ -5592,6 +5680,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; @@ -6299,6 +6403,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; } @@ -6856,6 +6968,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; @@ -7740,6 +7867,10 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiPno case CMD_PNO_NETWORK_FOUND: processPnoNetworkFound((ScanResult[])message.obj); break; + case CMD_RSSI_THRESHOLD_BREACH: + byte curRssi = (byte)message.arg1; + processRssiThreshold(curRssi); + break; default: return NOT_HANDLED; } @@ -7755,6 +7886,8 @@ public class WifiStateMachine extends StateMachine implements WifiNative.WifiPno mNetworkCapabilities.addCapability( NetworkCapabilities.NET_CAPABILITY_TRUSTED); } + mNetworkCapabilities.setSignalStrength(mWifiInfo.getRssi() != WifiInfo.INVALID_RSSI ? + mWifiInfo.getRssi() : NetworkCapabilities.SIGNAL_STRENGTH_UNSPECIFIED); mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities); } @@ -7792,6 +7925,52 @@ 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) { + // 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)); + 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 values for rssi thresholds " + val); + } + } + // ToDo: Do we quash rssi values in this sorted array which are very close? + mRssiRanges = rssiRange; + //In the degenerate case when the input range has no values, the + //rssiRange will have only 2 values(127, -128), which when armed to + //any chipset can never trigger a rssi breach + WifiStateMachine.this.sendMessage(CMD_START_RSSI_MONITORING_OFFLOAD, + mWifiInfo.getRssi()); + } + + @Override protected void preventAutomaticReconnect() { if (this != mNetworkAgent) return; unwantedNetwork(NETWORK_STATUS_UNWANTED_DISABLE_AUTOJOIN); @@ -8907,6 +9086,34 @@ 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; + } + case CMD_START_RSSI_MONITORING_OFFLOAD: + byte currRssi = (byte)message.arg1; + processRssiThreshold(currRssi); + break; + case CMD_STOP_RSSI_MONITORING_OFFLOAD: + stopRssiMonitoringOffload(); + break; default: return NOT_HANDLED; } diff --git a/service/jni/com_android_server_wifi_WifiNative.cpp b/service/jni/com_android_server_wifi_WifiNative.cpp index 7556b1e67..92bd3cd77 100644 --- a/service/jni/com_android_server_wifi_WifiNative.cpp +++ b/service/jni/com_android_server_wifi_WifiNative.cpp @@ -2114,6 +2114,82 @@ 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) { + wifi_interface_handle handle = getIfaceHandle(env, cls, iface); + ALOGD("Start packet offload [%d] = %p", idx, handle); + wifi_error ret; + wifi_request_id id = idx; + byte * pkt_data = (byte *)env->GetByteArrayElements(pkt, NULL); + unsigned short pkt_len = env->GetArrayLength(pkt); + byte* src_mac_addr = (byte *)env->GetByteArrayElements(srcMac, NULL); + byte* dst_mac_addr = (byte *)env->GetByteArrayElements(dstMac, NULL); + 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; + wifi_interface_handle handle = getIfaceHandle(env, 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]); + JNIEnv *env = NULL; + mVM->AttachCurrentThread(&env, NULL); + //ALOGD("onRssiThresholdbreached called, vm = %p, obj = %p, env = %p", mVM, mCls, env); + reportEvent(env, 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) { + + wifi_interface_handle handle = getIfaceHandle(env, 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) { + wifi_interface_handle handle = getIfaceHandle(env, 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; +} + // ---------------------------------------------------------------------------- /* @@ -2201,6 +2277,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} }; |