Wifi (Android): fixes Android 17 support

Fixes the Wifi transmit link speed being read from a field a vendor writes in front of it, rather than from the transmit speed itself
This commit is contained in:
Carter Li
2026-10-13 20:48:36 +08:00
parent 2aa053a904
commit 8a0c1d2f6c
+30 -25
View File
@@ -109,17 +109,18 @@
// more accurate -- pays nothing for it. // more accurate -- pays nothing for it.
// //
// Three things about the call are positional rather than negotiated, and all three were measured // Three things about the call are positional rather than negotiated, and all three were measured
// on an Android 16 device and an Android 11 device: // across the Android 11, 13, 16 and 17 devices:
// //
// * The transaction code is a build-time constant of the `.aidl` (`getConnectionInfo` is 29 on // * The transaction code is a build-time constant of the `.aidl` (`getConnectionInfo` is 29 on
// Android 11 and 41 on Android 16) -- see common/android/dex.h. // Android 11, 36 on Android 13 and 41 on Android 16 and 17) -- see common/android/dex.h.
// * The reply layout drifts, and not only by release. Android 12 dropped the duplicate length word // * The reply layout drifts, and not only by release. Android 12 dropped the duplicate length word
// that Android 11 and 10 wrote in front of the SSID octets, and the Android 16 device fills an // that Android 11 and 10 wrote in front of the SSID octets, and the Android 17 device writes a
// int between the transmit and the receive speed that the Android 11 device leaves out -- while // word of its own between the link speed and the transmit speed that the Android 11 and 13
// AOSP's own Android 16 writes the head exactly the Android 11 way, so that one int is a vendor // devices leave out -- a vendor addition rather than a release difference, since AOSP's own
// addition rather than a release difference. Frequency is the only channel centre in the head, so // Android 16 writes the head the Android 11 way. Frequency is the only channel centre in the
// it is located by value, with the whole result validated before it is used. A wrong guess shows // head, so it is located by value, with the whole result validated before it is used, and the
// up as a rejected layout, not as a plausible wrong number. // two direction specific speeds are read as its neighbours. A wrong guess shows up as a
// rejected layout, not as a plausible wrong number.
// * The tail of the parcel, which holds the Wi-Fi standard, is not laid out the same way by every // * The tail of the parcel, which holds the Wi-Fi standard, is not laid out the same way by every
// vendor: the Android 11 device carries three words there that AOSP's own Android 11 // vendor: the Android 11 device carries three words there that AOSP's own Android 11
// does not. It is located by shape for that reason. // does not. It is located by shape for that reason.
@@ -171,13 +172,14 @@ typedef enum FFWifiAndroidRadioState : int32_t
} FFWifiAndroidRadioState; } FFWifiAndroidRadioState;
// An AIDL reply opens with the exception code and, for a Parcelable return, a non-null marker; // An AIDL reply opens with the exception code and, for a Parcelable return, a non-null marker;
// WifiInfo itself then starts at 8. The network id, the RSSI and the link speed have held those // WifiInfo itself then starts at 8. The network id, the RSSI and the link speed are the first three
// offsets from Android 9 to 16, and the transmit speed joined them in Android 10 without moving // fields `writeToParcel` writes, so nothing a release or a vendor adds behind them can move them --
// since, so all four are read at fixed offsets. Everything after them is located by shape. // they have held those offsets from Android 9 to 17 and are read there. The two direction specific
// speeds sit behind them but are located from the frequency instead, because a vendor does write a
// word of its own in front of that pair: see the note at FF_WIFI_ANDROID_FREQ_TX_LINK_SPEED.
#define FF_WIFI_ANDROID_OFF_NET_ID 8 #define FF_WIFI_ANDROID_OFF_NET_ID 8
#define FF_WIFI_ANDROID_OFF_RSSI 12 #define FF_WIFI_ANDROID_OFF_RSSI 12
#define FF_WIFI_ANDROID_OFF_LINK_SPEED 16 #define FF_WIFI_ANDROID_OFF_LINK_SPEED 16
#define FF_WIFI_ANDROID_OFF_TX_LINK_SPEED 20
// A `WifiInfo` with no connection to describe carries the sentinels for the two fields that are // A `WifiInfo` with no connection to describe carries the sentinels for the two fields that are
// always at a fixed offset: -1 for a network id it does not have and -127 for a signal it cannot // always at a fixed offset: -1 for a network id it does not have and -127 for a signal it cannot
@@ -206,11 +208,15 @@ typedef enum FFWifiAndroidRadioState : int32_t
#define FF_WIFI_ANDROID_FREQ_SSID_BASE_NO_IP 0x08 #define FF_WIFI_ANDROID_FREQ_SSID_BASE_NO_IP 0x08
#define FF_WIFI_ANDROID_SSID_LENGTH 0x04 #define FF_WIFI_ANDROID_SSID_LENGTH 0x04
// The receive speed is the word in front of Frequency; the transmit speed is the word after the link // The transmit speed and the receive speed are the two words in front of Frequency, in that order:
// speed. The Android 16 device writes one extra word between those two that AOSP does not -- it repeats the // `mTxLinkSpeed, mRxLinkSpeed, mFrequency` are written back to back by every head this file has
// transmit speed -- so the receive speed can only be reached from Frequency, and Frequency cannot be // been checked against, from Android 11 through 17. The pair is read from Frequency rather than
// reached by stepping over the two link speeds. Both were checked against `cmd wifi status` at the // stepped to from the link speed, because the Android 17 device writes a word of its own between
// same moment: 131/219 on the Android 16 device, 86/-1 on the Android 11 device. // the link speed and the transmit speed: its dex names that word `mCurrentLinkSpeed`, so the word
// after the link speed is not the transmit speed there and the pair sits one word further along.
// Both were checked against `cmd wifi status` at the same moment: 131/219 on the Android 16 device,
// 86/-1 on the Android 11 device.
#define FF_WIFI_ANDROID_FREQ_TX_LINK_SPEED 0x08
#define FF_WIFI_ANDROID_FREQ_RX_LINK_SPEED 0x04 #define FF_WIFI_ANDROID_FREQ_RX_LINK_SPEED 0x04
#define FF_WIFI_ANDROID_SSID 0x08 // Android 12 and later #define FF_WIFI_ANDROID_SSID 0x08 // Android 12 and later
#define FF_WIFI_ANDROID_SSID_LEGACY 0x0c // Android 11 and older #define FF_WIFI_ANDROID_SSID_LEGACY 0x0c // Android 11 and older
@@ -643,7 +649,7 @@ static void debugDumpReply(const uint8_t* data, size_t size) {
#endif #endif
static const char* parseConnectionInfo(const uint8_t* data, size_t size, FFWifiAndroidConnection* connection) { static const char* parseConnectionInfo(const uint8_t* data, size_t size, FFWifiAndroidConnection* connection) {
if (size < FF_WIFI_ANDROID_OFF_TX_LINK_SPEED + 4) { if (size < FF_WIFI_ANDROID_FREQ_SCAN_FROM + 4) {
FF_DEBUG("The reply is %zu bytes, too short to hold a WifiInfo", size); FF_DEBUG("The reply is %zu bytes, too short to hold a WifiInfo", size);
return "The reply is too short to hold a WifiInfo"; return "The reply is too short to hold a WifiInfo";
} }
@@ -666,12 +672,11 @@ static const char* parseConnectionInfo(const uint8_t* data, size_t size, FFWifiA
FF_DEBUG("The reply is %zu bytes and carries no WifiInfo", size); FF_DEBUG("The reply is %zu bytes and carries no WifiInfo", size);
return nullptr; return nullptr;
} }
FF_DEBUG("Reply is %zu bytes: netId %d, rssi %d, link speed %d, tx link speed %d", FF_DEBUG("Reply is %zu bytes: netId %d, rssi %d, link speed %d",
size, size,
ffBinderReadI32(data, size, FF_WIFI_ANDROID_OFF_NET_ID), ffBinderReadI32(data, size, FF_WIFI_ANDROID_OFF_NET_ID),
ffBinderReadI32(data, size, FF_WIFI_ANDROID_OFF_RSSI), ffBinderReadI32(data, size, FF_WIFI_ANDROID_OFF_RSSI),
ffBinderReadI32(data, size, FF_WIFI_ANDROID_OFF_LINK_SPEED), ffBinderReadI32(data, size, FF_WIFI_ANDROID_OFF_LINK_SPEED));
ffBinderReadI32(data, size, FF_WIFI_ANDROID_OFF_TX_LINK_SPEED));
// The two orders WifiSsid has written its length in: once before the octets on Android 11 and // The two orders WifiSsid has written its length in: once before the octets on Android 11 and
// older, not at all on Android 12 and later, which leaves the octets one word earlier. The one // older, not at all on Android 12 and later, which leaves the octets one word earlier. The one
@@ -755,7 +760,7 @@ static const char* parseConnectionInfo(const uint8_t* data, size_t size, FFWifiA
connection->frequency = frequency; connection->frequency = frequency;
connection->rssi = ffBinderReadI32(data, size, FF_WIFI_ANDROID_OFF_RSSI); connection->rssi = ffBinderReadI32(data, size, FF_WIFI_ANDROID_OFF_RSSI);
connection->linkSpeed = ffBinderReadI32(data, size, FF_WIFI_ANDROID_OFF_LINK_SPEED); connection->linkSpeed = ffBinderReadI32(data, size, FF_WIFI_ANDROID_OFF_LINK_SPEED);
connection->txLinkSpeed = ffBinderReadI32(data, size, FF_WIFI_ANDROID_OFF_TX_LINK_SPEED); connection->txLinkSpeed = ffBinderReadI32(data, size, base - FF_WIFI_ANDROID_FREQ_TX_LINK_SPEED);
connection->rxLinkSpeed = ffBinderReadI32(data, size, base - FF_WIFI_ANDROID_FREQ_RX_LINK_SPEED); connection->rxLinkSpeed = ffBinderReadI32(data, size, base - FF_WIFI_ANDROID_FREQ_RX_LINK_SPEED);
findStrings(data, size, stringsFrom, connection); findStrings(data, size, stringsFrom, connection);
@@ -777,9 +782,9 @@ static const char* parseConnectionInfo(const uint8_t* data, size_t size, FFWifiA
if (!findSecurityType(data, size, connection)) { if (!findSecurityType(data, size, connection)) {
FF_DEBUG("No security type could be located in this reply, so the field stays empty"); FF_DEBUG("No security type could be located in this reply, so the field stays empty");
} }
FF_DEBUG("Standard %d (%s), rx link speed %d, connected %s", FF_DEBUG("Standard %d (%s), tx link speed %d, rx link speed %d, connected %s",
connection->standard, wifiStandardName(connection->standard) ?: "unknown", connection->rxLinkSpeed, connection->standard, wifiStandardName(connection->standard) ?: "unknown", connection->txLinkSpeed,
connection->connected ? "yes" : "no"); connection->rxLinkSpeed, connection->connected ? "yes" : "no");
return nullptr; return nullptr;
} }