summaryrefslogtreecommitdiff
path: root/service
diff options
context:
space:
mode:
authorMukesh Agrawal <quiche@google.com>2016-04-06 20:07:38 +0000
committerAndroid (Google) Code Review <android-gerrit@google.com>2016-04-06 20:07:39 +0000
commitd1bd53369b88d91968c19dd0cc288d1d2db8b3c6 (patch)
tree1d9b3c124a5d0c8a3a02a8201f9bd3f4ff39cdc3 /service
parentc1be2851f1c54e6e047ac62d71c9feb7e8df1561 (diff)
parent066cc9f845897357886081fbd972ab36e74ce345 (diff)
Merge changes from topic 'packet-fate' into nyc-dev
* changes: WifiStateMachine: report failures to WifiLogger WifiLogger: add support for packet fate WifiNative: flesh out packet fate implementation WifiNative C++: add support for packet fate WifiNative: add infrastructure for packet fates jni_helper: add createObjectWithArgs
Diffstat (limited to 'service')
-rw-r--r--service/java/com/android/server/wifi/BaseWifiLogger.java4
-rw-r--r--service/java/com/android/server/wifi/WifiLogger.java79
-rw-r--r--service/java/com/android/server/wifi/WifiLoggerHal.java49
-rw-r--r--service/java/com/android/server/wifi/WifiNative.java199
-rw-r--r--service/java/com/android/server/wifi/WifiStateMachine.java42
-rw-r--r--service/jni/com_android_server_wifi_WifiNative.cpp141
-rw-r--r--service/jni/jni_helper.cpp21
-rw-r--r--service/jni/jni_helper.h7
8 files changed, 518 insertions, 24 deletions
diff --git a/service/java/com/android/server/wifi/BaseWifiLogger.java b/service/java/com/android/server/wifi/BaseWifiLogger.java
index 59a86ae69..43139d29c 100644
--- a/service/java/com/android/server/wifi/BaseWifiLogger.java
+++ b/service/java/com/android/server/wifi/BaseWifiLogger.java
@@ -28,6 +28,8 @@ public class BaseWifiLogger {
public synchronized void stopLogging() { }
+ synchronized void reportConnectionFailure() {}
+
public synchronized void captureBugReportData(int reason) { }
public synchronized void captureAlertData(int errorCode, byte[] alertData) { }
@@ -38,7 +40,7 @@ public class BaseWifiLogger {
pw.println("set config_wifi_enable_wifi_firmware_debugging to enable");
}
- public synchronized void dump(PrintWriter pw) {
+ protected synchronized void dump(PrintWriter pw) {
pw.println("Chipset information :-----------------------------------------------");
pw.println("FW Version is: " + mFirmwareVersion);
pw.println("Driver Version is: " + mDriverVersion);
diff --git a/service/java/com/android/server/wifi/WifiLogger.java b/service/java/com/android/server/wifi/WifiLogger.java
index 0d358314d..64c570cd8 100644
--- a/service/java/com/android/server/wifi/WifiLogger.java
+++ b/service/java/com/android/server/wifi/WifiLogger.java
@@ -30,6 +30,8 @@ import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Calendar;
+import java.util.Collections;
+import java.util.Comparator;
import java.util.HashMap;
import java.util.zip.Deflater;
@@ -116,6 +118,10 @@ class WifiLogger extends BaseWifiLogger {
stopLoggingAllBuffers();
startLoggingAllExceptPerPacketBuffers();
}
+
+ if (verboseEnabled && !mWifiNative.startPktFateMonitoring()) {
+ Log.e(TAG, "Failed to start packet fate monitoring");
+ }
}
@Override
@@ -153,6 +159,15 @@ class WifiLogger extends BaseWifiLogger {
}
@Override
+ synchronized void reportConnectionFailure() {
+ if (mLogLevel <= VERBOSE_NORMAL_LOG) {
+ return;
+ }
+
+ mPacketFatesForLastFailure = fetchPacketFates();
+ }
+
+ @Override
public synchronized void captureBugReportData(int reason) {
BugReport report = captureBugreport(reason, true);
mLastBugReports.addLast(report);
@@ -167,7 +182,7 @@ class WifiLogger extends BaseWifiLogger {
@Override
public synchronized void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- dump(pw);
+ super.dump(pw);
for (int i = 0; i < mLastAlerts.size(); i++) {
pw.println("--------------------------------------------------------------------");
@@ -183,6 +198,8 @@ class WifiLogger extends BaseWifiLogger {
pw.println("--------------------------------------------------------------------");
}
+ dumpPacketFates(pw);
+
pw.println("--------------------------------------------------------------------");
}
@@ -521,4 +538,64 @@ class WifiLogger extends BaseWifiLogger {
return lines;
}
+ /** Packet fate reporting */
+ private ArrayList<WifiNative.FateReport> mPacketFatesForLastFailure;
+
+ private ArrayList<WifiNative.FateReport> fetchPacketFates() {
+ ArrayList<WifiNative.FateReport> mergedFates = new ArrayList<WifiNative.FateReport>();
+ WifiNative.TxFateReport[] txFates =
+ new WifiNative.TxFateReport[WifiLoggerHal.MAX_FATE_LOG_LEN];
+ if (mWifiNative.getTxPktFates(txFates)) {
+ for (int i = 0; i < txFates.length && txFates[i] != null; i++) {
+ mergedFates.add(txFates[i]);
+ }
+ }
+
+ WifiNative.RxFateReport[] rxFates =
+ new WifiNative.RxFateReport[WifiLoggerHal.MAX_FATE_LOG_LEN];
+ if (mWifiNative.getRxPktFates(rxFates)) {
+ for (int i = 0; i < rxFates.length && rxFates[i] != null; i++) {
+ mergedFates.add(rxFates[i]);
+ }
+ }
+
+ Collections.sort(mergedFates, new Comparator<WifiNative.FateReport>() {
+ @Override
+ public int compare(WifiNative.FateReport lhs, WifiNative.FateReport rhs) {
+ return Long.compare(lhs.mDriverTimestampUSec, rhs.mDriverTimestampUSec);
+ }
+ });
+
+ return mergedFates;
+ }
+
+ private void dumpPacketFates(PrintWriter pw) {
+ dumpPacketFatesInternal(pw, "Last failed connection fates", mPacketFatesForLastFailure);
+ if (DBG) {
+ dumpPacketFatesInternal(pw, "Latest fates", fetchPacketFates());
+ }
+ }
+
+ private static void dumpPacketFatesInternal(
+ PrintWriter pw, String description, ArrayList<WifiNative.FateReport> fates) {
+ if (fates == null) {
+ pw.format("No fates fetched for \"%s\"\n", description);
+ return;
+ }
+
+ if (fates.size() == 0) {
+ pw.format("HAL provided zero fates for \"%s\"\n", description);
+ return;
+ }
+
+ int i = 0;
+ pw.format("--------------------- %s ----------------------\n", description);
+ for (WifiNative.FateReport fate : fates) {
+ pw.format("Frame number: %d\n", i + 1);
+ pw.print(fate);
+ pw.print("\n");
+ ++i;
+ }
+ pw.println("--------------------------------------------------------------------");
+ }
}
diff --git a/service/java/com/android/server/wifi/WifiLoggerHal.java b/service/java/com/android/server/wifi/WifiLoggerHal.java
new file mode 100644
index 000000000..1d542b87d
--- /dev/null
+++ b/service/java/com/android/server/wifi/WifiLoggerHal.java
@@ -0,0 +1,49 @@
+/*
+ * 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;
+
+class WifiLoggerHal {
+ // Must match wifi_logger.h
+ static final int MAX_FATE_LOG_LEN = 32;
+
+ static final byte FRAME_TYPE_UNKNOWN = 0;
+ static final byte FRAME_TYPE_ETHERNET_II = 1;
+ static final byte FRAME_TYPE_80211_MGMT = 2;
+
+ static final byte TX_PKT_FATE_ACKED = 0;
+ static final byte TX_PKT_FATE_SENT = 1;
+ static final byte TX_PKT_FATE_FW_QUEUED = 2;
+ static final byte TX_PKT_FATE_FW_DROP_INVALID = 3;
+ static final byte TX_PKT_FATE_FW_DROP_NOBUFS = 4;
+ static final byte TX_PKT_FATE_FW_DROP_OTHER = 5;
+ static final byte TX_PKT_FATE_DRV_QUEUED = 6;
+ static final byte TX_PKT_FATE_DRV_DROP_INVALID = 7;
+ static final byte TX_PKT_FATE_DRV_DROP_NOBUFS = 9;
+ static final byte TX_PKT_FATE_DRV_DROP_OTHER = 10;
+
+ static final byte RX_PKT_FATE_SUCCESS = 0;
+ static final byte RX_PKT_FATE_FW_QUEUED = 1;
+ static final byte RX_PKT_FATE_FW_DROP_FILTER = 2;
+ static final byte RX_PKT_FATE_FW_DROP_INVALID = 3;
+ static final byte RX_PKT_FATE_FW_DROP_NOBUFS = 4;
+ static final byte RX_PKT_FATE_FW_DROP_OTHER = 5;
+ static final byte RX_PKT_FATE_DRV_QUEUED = 6;
+ static final byte RX_PKT_FATE_DRV_DROP_FILTER = 7;
+ static final byte RX_PKT_FATE_DRV_DROP_INVALID = 8;
+ static final byte RX_PKT_FATE_DRV_DROP_NOBUFS = 9;
+ static final byte RX_PKT_FATE_DRV_DROP_OTHER = 10;
+}
diff --git a/service/java/com/android/server/wifi/WifiNative.java b/service/java/com/android/server/wifi/WifiNative.java
index 2c659ba3e..bcd00f0a2 100644
--- a/service/java/com/android/server/wifi/WifiNative.java
+++ b/service/java/com/android/server/wifi/WifiNative.java
@@ -44,6 +44,8 @@ import android.text.TextUtils;
import android.util.LocalLog;
import android.util.Log;
+import com.android.internal.annotations.Immutable;
+import com.android.internal.util.HexDump;
import com.android.server.connectivity.KeepalivePacketData;
import com.android.server.wifi.hotspot2.NetworkDetail;
import com.android.server.wifi.hotspot2.SupplicantBridge;
@@ -55,6 +57,8 @@ import libcore.util.HexEncoding;
import org.json.JSONException;
import org.json.JSONObject;
+import java.io.PrintWriter;
+import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
@@ -85,6 +89,9 @@ import java.util.Set;
public class WifiNative {
private static boolean DBG = false;
+ // Must match wifi_hal.h
+ public static final int WIFI_SUCCESS = 0;
+
/**
* Hold this lock before calling supplicant or HAL methods
* it is required to mutually exclude access to the driver
@@ -2772,6 +2779,198 @@ public class WifiNative {
}
//---------------------------------------------------------------------------------
+ /* Packet fate API */
+
+ @Immutable
+ abstract static class FateReport {
+ final byte mFate;
+ final long mDriverTimestampUSec;
+ final byte mFrameType;
+ final byte[] mFrameBytes;
+
+ FateReport(byte fate, long driverTimestampUSec, byte frameType, byte[] frameBytes) {
+ mFate = fate;
+ mDriverTimestampUSec = driverTimestampUSec;
+ mFrameType = frameType;
+ mFrameBytes = frameBytes;
+ }
+
+ @Override
+ public String toString() {
+ StringWriter sw = new StringWriter();
+ PrintWriter pw = new PrintWriter(sw);
+ pw.format("Frame direction: %s\n", directionToString());
+ pw.format("Frame timestamp: %d\n", mDriverTimestampUSec);
+ pw.format("Frame fate: %s\n", fateToString());
+ pw.format("Frame type: %s\n", frameTypeToString(mFrameType));
+ pw.format("Frame length: %d\n", mFrameBytes.length);
+ pw.append("Frame bytes");
+ pw.append(HexDump.dumpHexString(mFrameBytes));
+ pw.append("\n");
+ return sw.toString();
+ }
+
+ protected abstract String directionToString();
+
+ protected abstract String fateToString();
+
+ private static String frameTypeToString(byte frameType) {
+ switch (frameType) {
+ case WifiLoggerHal.FRAME_TYPE_UNKNOWN:
+ return "unknown";
+ case WifiLoggerHal.FRAME_TYPE_ETHERNET_II:
+ return "data";
+ case WifiLoggerHal.FRAME_TYPE_80211_MGMT:
+ return "802.11 management";
+ default:
+ return Byte.toString(frameType);
+ }
+ }
+ }
+
+ /**
+ * Represents the fate information for one outbound packet.
+ */
+ @Immutable
+ public static final class TxFateReport extends FateReport {
+ TxFateReport(byte fate, long driverTimestampUSec, byte frameType, byte[] frameBytes) {
+ super(fate, driverTimestampUSec, frameType, frameBytes);
+ }
+
+ @Override
+ protected String directionToString() {
+ return "TX";
+ }
+
+ @Override
+ protected String fateToString() {
+ switch (mFate) {
+ case WifiLoggerHal.TX_PKT_FATE_ACKED:
+ return "acked";
+ case WifiLoggerHal.TX_PKT_FATE_SENT:
+ return "sent";
+ case WifiLoggerHal.TX_PKT_FATE_FW_QUEUED:
+ return "firmware queued";
+ case WifiLoggerHal.TX_PKT_FATE_FW_DROP_INVALID:
+ return "firmware dropped (invalid frame)";
+ case WifiLoggerHal.TX_PKT_FATE_FW_DROP_NOBUFS:
+ return "firmware dropped (no bufs)";
+ case WifiLoggerHal.TX_PKT_FATE_FW_DROP_OTHER:
+ return "firmware dropped (other)";
+ case WifiLoggerHal.TX_PKT_FATE_DRV_QUEUED:
+ return "driver queued";
+ case WifiLoggerHal.TX_PKT_FATE_DRV_DROP_INVALID:
+ return "driver dropped (invalid frame)";
+ case WifiLoggerHal.TX_PKT_FATE_DRV_DROP_NOBUFS:
+ return "driver dropped (no bufs)";
+ case WifiLoggerHal.TX_PKT_FATE_DRV_DROP_OTHER:
+ return "driver dropped (other)";
+ default:
+ return Byte.toString(mFate);
+ }
+ }
+ }
+
+ /**
+ * Represents the fate information for one inbound packet.
+ */
+ @Immutable
+ public static final class RxFateReport extends FateReport {
+ RxFateReport(byte fate, long driverTimestampUSec, byte frameType, byte[] frameBytes) {
+ super(fate, driverTimestampUSec, frameType, frameBytes);
+ }
+
+ @Override
+ protected String directionToString() {
+ return "RX";
+ }
+
+ @Override
+ protected String fateToString() {
+ switch (mFate) {
+ case WifiLoggerHal.RX_PKT_FATE_SUCCESS:
+ return "success";
+ case WifiLoggerHal.RX_PKT_FATE_FW_QUEUED:
+ return "firmware queued";
+ case WifiLoggerHal.RX_PKT_FATE_FW_DROP_FILTER:
+ return "firmware dropped (filter)";
+ case WifiLoggerHal.RX_PKT_FATE_FW_DROP_INVALID:
+ return "firmware dropped (invalid frame)";
+ case WifiLoggerHal.RX_PKT_FATE_FW_DROP_NOBUFS:
+ return "firmware dropped (no bufs)";
+ case WifiLoggerHal.RX_PKT_FATE_FW_DROP_OTHER:
+ return "firmware dropped (other)";
+ case WifiLoggerHal.RX_PKT_FATE_DRV_QUEUED:
+ return "driver queued";
+ case WifiLoggerHal.RX_PKT_FATE_DRV_DROP_FILTER:
+ return "driver dropped (filter)";
+ case WifiLoggerHal.RX_PKT_FATE_DRV_DROP_INVALID:
+ return "driver dropped (invalid frame)";
+ case WifiLoggerHal.RX_PKT_FATE_DRV_DROP_NOBUFS:
+ return "driver dropped (no bufs)";
+ case WifiLoggerHal.RX_PKT_FATE_DRV_DROP_OTHER:
+ return "driver dropped (other)";
+ default:
+ return Byte.toString(mFate);
+ }
+ }
+ }
+
+ private static native int startPktFateMonitoringNative(int iface);
+ /**
+ * Ask the HAL to enable packet fate monitoring. Fails unless HAL is started.
+ */
+ public boolean startPktFateMonitoring() {
+ synchronized (sLock) {
+ if (isHalStarted()) {
+ return startPktFateMonitoringNative(sWlan0Index) == WIFI_SUCCESS;
+ } else {
+ return false;
+ }
+ }
+ }
+
+ private static native int getTxPktFatesNative(int iface, TxFateReport[] reportBufs);
+ /**
+ * Fetch the most recent TX packet fates from the HAL. Fails unless HAL is started.
+ */
+ public boolean getTxPktFates(TxFateReport[] reportBufs) {
+ synchronized (sLock) {
+ if (isHalStarted()) {
+ int res = getTxPktFatesNative(sWlan0Index, reportBufs);
+ if (res != WIFI_SUCCESS) {
+ Log.e(TAG, "getTxPktFatesNative returned " + res);
+ return false;
+ } else {
+ return true;
+ }
+ } else {
+ return false;
+ }
+ }
+ }
+
+ private static native int getRxPktFatesNative(int iface, RxFateReport[] reportBufs);
+ /**
+ * Fetch the most recent RX packet fates from the HAL. Fails unless HAL is started.
+ */
+ public boolean getRxPktFates(RxFateReport[] reportBufs) {
+ synchronized (sLock) {
+ if (isHalStarted()) {
+ int res = getRxPktFatesNative(sWlan0Index, reportBufs);
+ if (res != WIFI_SUCCESS) {
+ Log.e(TAG, "getRxPktFatesNative returned " + res);
+ return false;
+ } else {
+ return true;
+ }
+ } else {
+ return false;
+ }
+ }
+ }
+
+ //---------------------------------------------------------------------------------
/* Configure ePNO/PNO */
private static PnoEventHandler sPnoEventHandler;
private static int sPnoCmdId = 0;
diff --git a/service/java/com/android/server/wifi/WifiStateMachine.java b/service/java/com/android/server/wifi/WifiStateMachine.java
index 1fa247645..b3e6d960a 100644
--- a/service/java/com/android/server/wifi/WifiStateMachine.java
+++ b/service/java/com/android/server/wifi/WifiStateMachine.java
@@ -4449,6 +4449,22 @@ public class WifiStateMachine extends StateMachine implements WifiNative.PnoEven
mWifiNative.BLUETOOTH_COEXISTENCE_MODE_SENSE);
}
+ /**
+ * Inform other components (WifiMetrics, WifiLogger, etc.) that the current connection attempt
+ * has concluded.
+ */
+ private void reportConnectionAttemptEnd(int level2FailureCode, int connectivityFailureCode) {
+ mWifiMetrics.endConnectionEvent(level2FailureCode, connectivityFailureCode);
+ switch (level2FailureCode) {
+ case WifiMetrics.ConnectionEvent.FAILURE_NONE:
+ case WifiMetrics.ConnectionEvent.FAILURE_REDUNDANT_CONNECTION_ATTEMPT:
+ // WifiLogger doesn't care about success, or pre-empted connections.
+ break;
+ default:
+ mWifiLogger.reportConnectionFailure();
+ }
+ }
+
private void handleIPv4Success(DhcpResults dhcpResults) {
if (DBG) {
logd("handleIPv4Success <" + dhcpResults.toString() + ">");
@@ -4518,7 +4534,7 @@ public class WifiStateMachine extends StateMachine implements WifiNative.PnoEven
}
log("DHCP failure count=" + count);
}
- mWifiMetrics.endConnectionEvent(
+ reportConnectionAttemptEnd(
WifiMetrics.ConnectionEvent.FAILURE_DHCP,
WifiMetricsProto.ConnectionEvent.HLF_DHCP);
synchronized(mDhcpResultsLock) {
@@ -6132,7 +6148,7 @@ public class WifiStateMachine extends StateMachine implements WifiNative.PnoEven
mSupplicantStateTracker.sendMessage(WifiMonitor.ASSOCIATION_REJECTION_EVENT);
//If rejection occurred while Metrics is tracking a ConnnectionEvent, end it.
- mWifiMetrics.endConnectionEvent(
+ reportConnectionAttemptEnd(
WifiMetrics.ConnectionEvent.FAILURE_ASSOCIATION_REJECTION,
WifiMetricsProto.ConnectionEvent.HLF_NONE);
break;
@@ -6145,7 +6161,7 @@ public class WifiStateMachine extends StateMachine implements WifiNative.PnoEven
.DISABLED_AUTHENTICATION_FAILURE);
}
//If failure occurred while Metrics is tracking a ConnnectionEvent, end it.
- mWifiMetrics.endConnectionEvent(
+ reportConnectionAttemptEnd(
WifiMetrics.ConnectionEvent.FAILURE_AUTHENTICATION_FAILURE,
WifiMetricsProto.ConnectionEvent.HLF_NONE);
break;
@@ -6156,7 +6172,7 @@ public class WifiStateMachine extends StateMachine implements WifiNative.PnoEven
message.arg1,
WifiConfiguration.NetworkSelectionStatus
.DISABLED_AUTHENTICATION_FAILURE);
- mWifiMetrics.endConnectionEvent(
+ reportConnectionAttemptEnd(
WifiMetrics.ConnectionEvent.FAILURE_SSID_TEMP_DISABLED,
WifiMetricsProto.ConnectionEvent.HLF_NONE);
break;
@@ -6608,7 +6624,7 @@ public class WifiStateMachine extends StateMachine implements WifiNative.PnoEven
loge("Failed to connect config: " + config + " netId: " + netId);
replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED,
WifiManager.ERROR);
- mWifiMetrics.endConnectionEvent(
+ reportConnectionAttemptEnd(
WifiMetrics.ConnectionEvent.FAILURE_CONNECT_NETWORK_FAILED,
WifiMetricsProto.ConnectionEvent.HLF_NONE);
break;
@@ -6760,7 +6776,7 @@ public class WifiStateMachine extends StateMachine implements WifiNative.PnoEven
loge("Failed to connect config: " + config + " netId: " + netId);
replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED,
WifiManager.ERROR);
- mWifiMetrics.endConnectionEvent(
+ reportConnectionAttemptEnd(
WifiMetrics.ConnectionEvent.FAILURE_CONNECT_NETWORK_FAILED,
WifiMetricsProto.ConnectionEvent.HLF_NONE);
break;
@@ -7330,7 +7346,7 @@ public class WifiStateMachine extends StateMachine implements WifiNative.PnoEven
}
case CMD_IP_CONFIGURATION_SUCCESSFUL:
handleSuccessfulIpConfiguration();
- mWifiMetrics.endConnectionEvent(
+ reportConnectionAttemptEnd(
WifiMetrics.ConnectionEvent.FAILURE_NONE,
WifiMetricsProto.ConnectionEvent.HLF_NONE);
sendConnectedState();
@@ -7738,7 +7754,7 @@ public class WifiStateMachine extends StateMachine implements WifiNative.PnoEven
/* Defer any power mode changes since we must keep active power mode at DHCP */
case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
- mWifiMetrics.endConnectionEvent(
+ reportConnectionAttemptEnd(
WifiMetrics.ConnectionEvent.FAILURE_NETWORK_DISCONNECTION,
WifiMetricsProto.ConnectionEvent.HLF_NONE);
return NOT_HANDLED;
@@ -7886,7 +7902,7 @@ public class WifiStateMachine extends StateMachine implements WifiNative.PnoEven
sendNetworkStateChangeBroadcast(mLastBssid);
// Successful framework roam! (probably)
- mWifiMetrics.endConnectionEvent(
+ reportConnectionAttemptEnd(
WifiMetrics.ConnectionEvent.FAILURE_NONE,
WifiMetricsProto.ConnectionEvent.HLF_NONE);
// We used to transition to ObtainingIpState in an
@@ -8098,7 +8114,7 @@ public class WifiStateMachine extends StateMachine implements WifiNative.PnoEven
return NOT_HANDLED;
case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
long lastRoam = 0;
- mWifiMetrics.endConnectionEvent(
+ reportConnectionAttemptEnd(
WifiMetrics.ConnectionEvent.FAILURE_NETWORK_DISCONNECTION,
WifiMetricsProto.ConnectionEvent.HLF_NONE);
if (mLastDriverRoamAttempt != 0) {
@@ -8211,7 +8227,7 @@ public class WifiStateMachine extends StateMachine implements WifiNative.PnoEven
}
if (deferForUserInput(message, netId, false)) {
- mWifiMetrics.endConnectionEvent(
+ reportConnectionAttemptEnd(
WifiMetrics.ConnectionEvent.FAILURE_CONNECT_NETWORK_FAILED,
WifiMetricsProto.ConnectionEvent.HLF_NONE);
break;
@@ -8219,7 +8235,7 @@ public class WifiStateMachine extends StateMachine implements WifiNative.PnoEven
WifiConfiguration.USER_BANNED) {
replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED,
WifiManager.NOT_AUTHORIZED);
- mWifiMetrics.endConnectionEvent(
+ reportConnectionAttemptEnd(
WifiMetrics.ConnectionEvent.FAILURE_CONNECT_NETWORK_FAILED,
WifiMetricsProto.ConnectionEvent.HLF_NONE);
break;
@@ -8247,7 +8263,7 @@ public class WifiStateMachine extends StateMachine implements WifiNative.PnoEven
replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED,
WifiManager.ERROR);
messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
- mWifiMetrics.endConnectionEvent(
+ reportConnectionAttemptEnd(
WifiMetrics.ConnectionEvent.FAILURE_CONNECT_NETWORK_FAILED,
WifiMetricsProto.ConnectionEvent.HLF_NONE);
break;
diff --git a/service/jni/com_android_server_wifi_WifiNative.cpp b/service/jni/com_android_server_wifi_WifiNative.cpp
index 20c5b70e9..6dbb6064c 100644
--- a/service/jni/com_android_server_wifi_WifiNative.cpp
+++ b/service/jni/com_android_server_wifi_WifiNative.cpp
@@ -29,6 +29,11 @@
#include <sys/klog.h>
#include <linux/if.h>
#include <linux/if_arp.h>
+
+#include <algorithm>
+#include <limits>
+#include <vector>
+
#include "wifi.h"
#include "wifi_hal.h"
#include "jni_helper.h"
@@ -1919,6 +1924,137 @@ static jboolean android_net_wifi_reset_log_handler(JNIEnv *env, jclass cls, jint
return true;
}
+static jint android_net_wifi_start_pkt_fate_monitoring(JNIEnv *env, jclass cls, jint iface) {
+
+ JNIHelper helper(env);
+ return hal_fn.wifi_start_pkt_fate_monitoring(
+ getIfaceHandle(helper, cls, iface));
+}
+
+// Helper for make_default_fate().
+template<typename T> void set_to_max(T* value) {
+ if (!value) {
+ return;
+ }
+ *value = std::numeric_limits<T>::max();
+}
+
+// make_default_fate() has two purposes:
+// 1) Minimize the chances of data leakage. In case the HAL gives us an overlong long |frame_len|,
+// for example, we want to return zeros, rather than other data from this process.
+// 2) Make it obvious when the HAL doesn't set a field. We accomplish this by setting fields
+// to "impossible" values, where possible.
+// Normally, such work would be done in a ctor. However, doing so would make the HAL API
+// incompatible with C. So we use a free-standing function instead.
+//
+// TODO(quiche): Add unit test for this function. b/27726696
+template<typename FateReportT> FateReportT make_default_fate() {
+
+ FateReportT fate_report;
+ set_to_max(&fate_report.fate);
+ std::fill(std::begin(fate_report.md5_prefix), std::end(fate_report.md5_prefix), 0);
+ set_to_max(&fate_report.frame_inf.payload_type);
+ fate_report.frame_inf.frame_len = 0;
+ fate_report.frame_inf.driver_timestamp_usec = 0;
+ fate_report.frame_inf.firmware_timestamp_usec = 0;
+ std::fill(std::begin(fate_report.frame_inf.frame_content.ieee_80211_mgmt_bytes),
+ std::end(fate_report.frame_inf.frame_content.ieee_80211_mgmt_bytes), 0);
+ return fate_report;
+}
+
+// TODO(quiche): Add unit test for this function. b/27726696
+template<typename FateReportT, typename HalFateFetcherT> wifi_error get_pkt_fates(
+ HalFateFetcherT fate_fetcher_func, const char *java_fate_type,
+ JNIEnv *env, jclass cls, jint iface, jobjectArray reports) {
+
+ JNIHelper helper(env);
+ const size_t n_reports_wanted =
+ std::min(helper.getArrayLength(reports), MAX_FATE_LOG_LEN);
+
+ std::vector<FateReportT> report_bufs(n_reports_wanted, make_default_fate<FateReportT>());
+ size_t n_reports_provided = 0;
+ wifi_error result = fate_fetcher_func(
+ getIfaceHandle(helper, cls, iface),
+ report_bufs.data(),
+ n_reports_wanted,
+ &n_reports_provided);
+ if (result != WIFI_SUCCESS) {
+ return result;
+ }
+
+ if (n_reports_provided > n_reports_wanted) {
+ LOG_ALWAYS_FATAL(
+ "HAL data exceeds request; memory may be corrupt (provided: %zu, requested: %zu)",
+ n_reports_provided, n_reports_wanted);
+ }
+
+ for (size_t i = 0; i < n_reports_provided; ++i) {
+ const FateReportT& report(report_bufs[i]);
+
+ const char *frame_bytes_native = nullptr;
+ size_t max_frame_len;
+ switch (report.frame_inf.payload_type) {
+ case FRAME_TYPE_UNKNOWN:
+ case FRAME_TYPE_ETHERNET_II:
+ max_frame_len = MAX_FRAME_LEN_ETHERNET;
+ frame_bytes_native = report.frame_inf.frame_content.ethernet_ii_bytes;
+ break;
+ case FRAME_TYPE_80211_MGMT:
+ max_frame_len = MAX_FRAME_LEN_80211_MGMT;
+ frame_bytes_native = report.frame_inf.frame_content.ieee_80211_mgmt_bytes;
+ break;
+ default:
+ max_frame_len = 0;
+ frame_bytes_native = 0;
+ }
+
+ size_t copy_len = report.frame_inf.frame_len;
+ if (copy_len > max_frame_len) {
+ ALOGW("Overly long frame (len: %zu, max: %zu)", copy_len, max_frame_len);
+ copy_len = max_frame_len;
+ }
+
+ JNIObject<jbyteArray> frame_bytes_java = helper.newByteArray(copy_len);
+ if (frame_bytes_java.isNull()) {
+ ALOGE("Failed to allocate frame data buffer");
+ return WIFI_ERROR_OUT_OF_MEMORY;
+ }
+ helper.setByteArrayRegion(frame_bytes_java, 0, copy_len,
+ reinterpret_cast<const jbyte *>(frame_bytes_native));
+
+ JNIObject<jobject> fate_report = helper.createObjectWithArgs(
+ java_fate_type,
+ "(BJB[B)V", // byte, long, byte, byte array
+ static_cast<jbyte>(report.fate),
+ static_cast<jlong>(report.frame_inf.driver_timestamp_usec),
+ static_cast<jbyte>(report.frame_inf.payload_type),
+ frame_bytes_java.get());
+ if (fate_report.isNull()) {
+ ALOGE("Failed to create %s", java_fate_type);
+ return WIFI_ERROR_OUT_OF_MEMORY;
+ }
+ helper.setObjectArrayElement(reports, i, fate_report);
+ }
+
+ return result;
+}
+
+static jint android_net_wifi_get_tx_pkt_fates(JNIEnv *env, jclass cls, jint iface,
+ jobjectArray reports) {
+
+ return get_pkt_fates<wifi_tx_report>(
+ hal_fn.wifi_get_tx_pkt_fates, "com/android/server/wifi/WifiNative$TxFateReport",
+ env, cls, iface, reports);
+}
+
+static jint android_net_wifi_get_rx_pkt_fates(JNIEnv *env, jclass cls, jint iface,
+ jobjectArray reports) {
+
+ return get_pkt_fates<wifi_rx_report>(
+ hal_fn.wifi_get_rx_pkt_fates, "com/android/server/wifi/WifiNative$RxFateReport",
+ env, cls, iface, reports);
+}
+
// ----------------------------------------------------------------------------
// ePno framework
// ----------------------------------------------------------------------------
@@ -2412,6 +2548,11 @@ static JNINativeMethod gWifiMethods[] = {
(void*)android_net_wifi_setBssidBlacklist},
{"setLoggingEventHandlerNative", "(II)Z", (void *) android_net_wifi_set_log_handler},
{"resetLogHandlerNative", "(II)Z", (void *) android_net_wifi_reset_log_handler},
+ {"startPktFateMonitoringNative", "(I)I", (void*) android_net_wifi_start_pkt_fate_monitoring},
+ {"getTxPktFatesNative", "(I[Lcom/android/server/wifi/WifiNative$TxFateReport;)I",
+ (void*) android_net_wifi_get_tx_pkt_fates},
+ {"getRxPktFatesNative", "(I[Lcom/android/server/wifi/WifiNative$RxFateReport;)I",
+ (void*) android_net_wifi_get_rx_pkt_fates},
{ "startSendingOffloadedPacketNative", "(II[B[B[BI)I",
(void*)android_net_wifi_start_sending_offloaded_packet},
{ "stopSendingOffloadedPacketNative", "(II)I",
diff --git a/service/jni/jni_helper.cpp b/service/jni/jni_helper.cpp
index b4bf44cc2..c9b4edd28 100644
--- a/service/jni/jni_helper.cpp
+++ b/service/jni/jni_helper.cpp
@@ -569,26 +569,35 @@ jboolean JNIHelper::callStaticMethod(jclass cls, const char *method, const char
return result;
}
-JNIObject<jobject> JNIHelper::createObject(const char *className)
+JNIObject<jobject> JNIHelper::createObject(const char *className) {
+ return createObjectWithArgs(className, "()V");
+}
+
+JNIObject<jobject> JNIHelper::createObjectWithArgs(
+ const char *className, const char *signature, ...)
{
+ va_list params;
+ va_start(params, signature);
+
JNIObject<jclass> cls(*this, mEnv->FindClass(className));
if (cls == NULL) {
ALOGE("Error in finding class %s", className);
return JNIObject<jobject>(*this, NULL);
}
- jmethodID constructor = mEnv->GetMethodID(cls, "<init>", "()V");
+ jmethodID constructor = mEnv->GetMethodID(cls, "<init>", signature);
if (constructor == 0) {
ALOGE("Error in constructor ID for %s", className);
return JNIObject<jobject>(*this, NULL);
}
- JNIObject<jobject> obj(*this, mEnv->NewObject(cls, constructor));
+ JNIObject<jobject> obj(*this, mEnv->NewObjectV(cls, constructor, params));
if (obj == NULL) {
ALOGE("Could not create new object of %s", className);
return JNIObject<jobject>(*this, NULL);
}
+ va_end(params);
return obj;
}
@@ -653,15 +662,15 @@ void JNIHelper::setObjectArrayElement(jobjectArray array, int index, jobject obj
mEnv->SetObjectArrayElement(array, index, obj);
}
-void JNIHelper::setByteArrayRegion(jbyteArray array, int from, int to, jbyte *bytes) {
+void JNIHelper::setByteArrayRegion(jbyteArray array, int from, int to, const jbyte *bytes) {
mEnv->SetByteArrayRegion(array, from, to, bytes);
}
-void JNIHelper::setIntArrayRegion(jintArray array, int from, int to, jint *ints) {
+void JNIHelper::setIntArrayRegion(jintArray array, int from, int to, const jint *ints) {
mEnv->SetIntArrayRegion(array, from, to, ints);
}
-void JNIHelper::setLongArrayRegion(jlongArray array, int from, int to, jlong *longs) {
+void JNIHelper::setLongArrayRegion(jlongArray array, int from, int to, const jlong *longs) {
mEnv->SetLongArrayRegion(array, from, to, longs);
}
diff --git a/service/jni/jni_helper.h b/service/jni/jni_helper.h
index 80f51322d..bb65f1c27 100644
--- a/service/jni/jni_helper.h
+++ b/service/jni/jni_helper.h
@@ -96,6 +96,7 @@ public :
jboolean setStringField(jobject obj, const char *name, const char *value);
void reportEvent(jclass cls, const char *method, const char *signature, ...);
JNIObject<jobject> createObject(const char *className);
+ JNIObject<jobject> createObjectWithArgs(const char *className, const char *signature, ...);
JNIObject<jobjectArray> createObjectArray(const char *className, int size);
void setObjectField(jobject obj, const char *name, const char *type, jobject value);
void callMethod(jobject obj, const char *method, const char *signature, ...);
@@ -120,9 +121,9 @@ public :
JNIObject<jlongArray> newLongArray(int num);
JNIObject<jstring> newStringUTF(const char *utf);
void setObjectArrayElement(jobjectArray array, int index, jobject obj);
- void setByteArrayRegion(jbyteArray array, int from, int to, jbyte *bytes);
- void setIntArrayRegion(jintArray array, int from, int to, jint *ints);
- void setLongArrayRegion(jlongArray array, int from, int to, jlong *longs);
+ void setByteArrayRegion(jbyteArray array, int from, int to, const jbyte *bytes);
+ void setIntArrayRegion(jintArray array, int from, int to, const jint *ints);
+ void setLongArrayRegion(jlongArray array, int from, int to, const jlong *longs);
jobject newGlobalRef(jobject obj);
void deleteGlobalRef(jobject obj);