CTS test for WiFi watchdog - framework support.

The new WiFi watchdog requires kernel/driver to export some packet loss
counters. This CTS tests whether those counters are correctly exported.

Change-Id: I41999676f8488e86f35f1f8214ce668f1a2b5638
diff --git a/services/java/com/android/server/WifiService.java b/services/java/com/android/server/WifiService.java
index e1c05b5..edbc624 100644
--- a/services/java/com/android/server/WifiService.java
+++ b/services/java/com/android/server/WifiService.java
@@ -303,6 +303,10 @@
                     mWifiStateMachine.sendMessage(Message.obtain(msg));
                     break;
                 }
+                case WifiManager.RSSI_PKTCNT_FETCH: {
+                    mWifiStateMachine.sendMessage(Message.obtain(msg));
+                    break;
+                }
                 default: {
                     Slog.d(TAG, "WifiServicehandler.handleMessage ignoring msg=" + msg);
                     break;
diff --git a/wifi/java/android/net/wifi/RssiPacketCountInfo.java b/wifi/java/android/net/wifi/RssiPacketCountInfo.java
new file mode 100644
index 0000000..f549e1d
--- /dev/null
+++ b/wifi/java/android/net/wifi/RssiPacketCountInfo.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2012 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 android.net.wifi;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Bundle of RSSI and packet count information, for WiFi watchdog
+ *
+ * @see WifiWatchdogStateMachine
+ *
+ * @hide
+ */
+public class RssiPacketCountInfo implements Parcelable {
+
+    public int rssi;
+
+    public int txgood;
+
+    public int txbad;
+
+    public RssiPacketCountInfo() {
+        rssi = txgood = txbad = 0;
+    }
+
+    private RssiPacketCountInfo(Parcel in) {
+        rssi = in.readInt();
+        txgood = in.readInt();
+        txbad = in.readInt();
+    }
+
+    @Override
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeInt(rssi);
+        out.writeInt(txgood);
+        out.writeInt(txbad);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    public static final Parcelable.Creator<RssiPacketCountInfo> CREATOR =
+            new Parcelable.Creator<RssiPacketCountInfo>() {
+        @Override
+        public RssiPacketCountInfo createFromParcel(Parcel in) {
+            return new RssiPacketCountInfo(in);
+        }
+
+        @Override
+        public RssiPacketCountInfo[] newArray(int size) {
+            return new RssiPacketCountInfo[size];
+        }
+    };
+}
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 6e58a2d..3579b86 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -906,6 +906,17 @@
     }
 
     /**
+     * Return TX packet counter, for CTS test of WiFi watchdog.
+     * @param listener is the interface to receive result
+     *
+     * @hide for CTS test only
+     */
+    public void getTxPacketCount(TxPacketCountListener listener) {
+        validateChannel();
+        mAsyncChannel.sendMessage(RSSI_PKTCNT_FETCH, 0, putListener(listener));
+    }
+
+    /**
      * Calculates the level of the signal. This should be used any time a signal
      * is being shown.
      *
@@ -1143,11 +1154,18 @@
     /** @hide */
     public static final int DISABLE_NETWORK_SUCCEEDED       = BASE + 19;
 
+    /** @hide */
+    public static final int RSSI_PKTCNT_FETCH               = BASE + 20;
+    /** @hide */
+    public static final int RSSI_PKTCNT_FETCH_SUCCEEDED     = BASE + 21;
+    /** @hide */
+    public static final int RSSI_PKTCNT_FETCH_FAILED        = BASE + 22;
+
     /* For system use only */
     /** @hide */
-    public static final int ENABLE_TRAFFIC_STATS_POLL       = BASE + 21;
+    public static final int ENABLE_TRAFFIC_STATS_POLL       = BASE + 31;
     /** @hide */
-    public static final int TRAFFIC_STATS_POLL              = BASE + 22;
+    public static final int TRAFFIC_STATS_POLL              = BASE + 32;
 
 
     /**
@@ -1212,6 +1230,21 @@
         public void onFailure(int reason);
     }
 
+    /** Interface for callback invocation on a TX packet count poll action {@hide} */
+    public interface TxPacketCountListener {
+        /**
+         * The operation succeeded
+         * @param count TX packet counter
+         */
+        public void onSuccess(int count);
+        /**
+         * The operation failed
+         * @param reason The reason for failure could be one of
+         * {@link #ERROR}, {@link #IN_PROGRESS} or {@link #BUSY}
+         */
+        public void onFailure(int reason);
+    }
+
     private class ServiceHandler extends Handler {
         ServiceHandler(Looper looper) {
             super(looper);
@@ -1281,6 +1314,20 @@
                         ((WpsListener) listener).onFailure(message.arg1);
                     }
                     break;
+                case WifiManager.RSSI_PKTCNT_FETCH_SUCCEEDED:
+                    if (listener != null) {
+                        RssiPacketCountInfo info = (RssiPacketCountInfo) message.obj;
+                        if (info != null)
+                            ((TxPacketCountListener) listener).onSuccess(info.txgood + info.txbad);
+                        else
+                            ((TxPacketCountListener) listener).onFailure(ERROR);
+                    }
+                    break;
+                case WifiManager.RSSI_PKTCNT_FETCH_FAILED:
+                    if (listener != null) {
+                        ((TxPacketCountListener) listener).onFailure(message.arg1);
+                    }
+                    break;
                 default:
                     //ignore
                     break;
diff --git a/wifi/java/android/net/wifi/WifiStateMachine.java b/wifi/java/android/net/wifi/WifiStateMachine.java
index 28c1c5c..6abca65 100644
--- a/wifi/java/android/net/wifi/WifiStateMachine.java
+++ b/wifi/java/android/net/wifi/WifiStateMachine.java
@@ -52,7 +52,7 @@
 import android.net.NetworkInfo;
 import android.net.NetworkInfo.DetailedState;
 import android.net.NetworkUtils;
-import android.net.wifi.WifiWatchdogStateMachine.RssiPktcntStat;
+import android.net.wifi.RssiPacketCountInfo;
 import android.net.wifi.WpsResult.Status;
 import android.net.wifi.p2p.WifiP2pManager;
 import android.net.wifi.p2p.WifiP2pService;
@@ -1189,7 +1189,7 @@
             case CMD_RSSI_POLL:
             case CMD_DELAYED_STOP_DRIVER:
             case WifiMonitor.SCAN_RESULTS_EVENT:
-            case WifiWatchdogStateMachine.RSSI_PKTCNT_FETCH:
+            case WifiManager.RSSI_PKTCNT_FETCH:
                 return false;
             default:
                 return true;
@@ -1543,7 +1543,7 @@
     /*
      * Fetch TX packet counters on current connection
      */
-    private void fetchPktcntNative(RssiPktcntStat stat) {
+    private void fetchPktcntNative(RssiPacketCountInfo info) {
         String pktcntPoll = mWifiNative.pktcntPoll();
 
         if (pktcntPoll != null) {
@@ -1553,9 +1553,9 @@
                 if (prop.length < 2) continue;
                 try {
                     if (prop[0].equals("TXGOOD")) {
-                        stat.txgood = Integer.parseInt(prop[1]);
+                        info.txgood = Integer.parseInt(prop[1]);
                     } else if (prop[0].equals("TXBAD")) {
-                        stat.txbad = Integer.parseInt(prop[1]);
+                        info.txbad = Integer.parseInt(prop[1]);
                     }
                 } catch (NumberFormatException e) {
                     //Ignore
@@ -1972,8 +1972,9 @@
                     replyToMessage(message, WifiManager.DISABLE_NETWORK_FAILED,
                             WifiManager.BUSY);
                     break;
-                case WifiWatchdogStateMachine.RSSI_PKTCNT_FETCH:
-                    replyToMessage(message, WifiWatchdogStateMachine.RSSI_PKTCNT_FETCH_FAILED);
+                case WifiManager.RSSI_PKTCNT_FETCH:
+                    replyToMessage(message, WifiManager.RSSI_PKTCNT_FETCH_FAILED,
+                            WifiManager.BUSY);
                     break;
                 default:
                     loge("Error! unhandled message" + message);
@@ -3176,13 +3177,12 @@
                                 mRssiPollToken, 0), POLL_RSSI_INTERVAL_MSECS);
                     }
                     break;
-                case WifiWatchdogStateMachine.RSSI_PKTCNT_FETCH:
-                    RssiPktcntStat stat = (RssiPktcntStat) message.obj;
+                case WifiManager.RSSI_PKTCNT_FETCH:
+                    RssiPacketCountInfo info = new RssiPacketCountInfo();
                     fetchRssiAndLinkSpeedNative();
-                    stat.rssi = mWifiInfo.getRssi();
-                    fetchPktcntNative(stat);
-                    replyToMessage(message, WifiWatchdogStateMachine.RSSI_PKTCNT_FETCH_SUCCEEDED,
-                            stat);
+                    info.rssi = mWifiInfo.getRssi();
+                    fetchPktcntNative(info);
+                    replyToMessage(message, WifiManager.RSSI_PKTCNT_FETCH_SUCCEEDED, info);
                     break;
                 default:
                     return NOT_HANDLED;
diff --git a/wifi/java/android/net/wifi/WifiWatchdogStateMachine.java b/wifi/java/android/net/wifi/WifiWatchdogStateMachine.java
index 7b4d113..29a53b6 100644
--- a/wifi/java/android/net/wifi/WifiWatchdogStateMachine.java
+++ b/wifi/java/android/net/wifi/WifiWatchdogStateMachine.java
@@ -30,6 +30,7 @@
 import android.net.LinkProperties;
 import android.net.NetworkInfo;
 import android.net.Uri;
+import android.net.wifi.RssiPacketCountInfo;
 import android.os.Message;
 import android.os.SystemClock;
 import android.provider.Settings;
@@ -105,9 +106,6 @@
     /* Notifications from/to WifiStateMachine */
     static final int POOR_LINK_DETECTED                             = BASE + 21;
     static final int GOOD_LINK_DETECTED                             = BASE + 22;
-    static final int RSSI_PKTCNT_FETCH                              = BASE + 23;
-    static final int RSSI_PKTCNT_FETCH_SUCCEEDED                    = BASE + 24;
-    static final int RSSI_PKTCNT_FETCH_FAILED                       = BASE + 25;
 
     /*
      * RSSI levels as used by notification icon
@@ -123,7 +121,7 @@
      * <p>
      * Larger threshold is more adaptive but increases sampling cost.
      */
-    private static final int LINK_MONITOR_LEVEL_THRESHOLD = 4;
+    private static final int LINK_MONITOR_LEVEL_THRESHOLD = WifiManager.RSSI_LEVELS - 1;
 
     /**
      * Remember packet loss statistics of how many BSSIDs.
@@ -228,8 +226,8 @@
      * Adaptive good link target to avoid flapping.
      * When a poor link is detected, a good link target is calculated as follows:
      * <p>
-     *      targetRSSI = min{ rssi | loss(rssi) < GOOD_LINK_LOSS_THRESHOLD } + rssi_adj[i],
-     *                   where rssi is in the above GOOD_LINK_RSSI_RANGE.
+     *      targetRSSI = min { rssi | loss(rssi) < GOOD_LINK_LOSS_THRESHOLD } + rssi_adj[i],
+     *                   where rssi is within the above GOOD_LINK_RSSI_RANGE.
      *      targetCount = sample_count[i] .
      * <p>
      * While WiFi is being avoided, we keep monitoring its signal strength.
@@ -241,7 +239,7 @@
      * <p>
      * Intuitively, larger index i makes it more difficult to get back to WiFi, avoiding flapping.
      * In experiments, (+9 dB / 30 counts) makes it quite difficult to achieve.
-     * Avoid using it unless flapping is really bad (say, last poor link is only 1min ago).
+     * Avoid using it unless flapping is really bad (say, last poor link is < 1 min ago).
      */
     private static final GoodLinkTarget[] GOOD_LINK_TARGET = {
         /*                  rssi_adj,       sample_count,   reduce_time */
@@ -591,8 +589,8 @@
                 case EVENT_BSSID_CHANGE:
                 case CMD_DELAYED_WALLED_GARDEN_CHECK:
                 case CMD_RSSI_FETCH:
-                case RSSI_PKTCNT_FETCH_SUCCEEDED:
-                case RSSI_PKTCNT_FETCH_FAILED:
+                case WifiManager.RSSI_PKTCNT_FETCH_SUCCEEDED:
+                case WifiManager.RSSI_PKTCNT_FETCH_FAILED:
                     // ignore
                     break;
                 case EVENT_SCREEN_ON:
@@ -764,15 +762,15 @@
 
                 case CMD_RSSI_FETCH:
                     if (msg.arg1 == mRssiFetchToken) {
-                        mWsmChannel.sendMessage(RSSI_PKTCNT_FETCH, new RssiPktcntStat());
+                        mWsmChannel.sendMessage(WifiManager.RSSI_PKTCNT_FETCH);
                         sendMessageDelayed(obtainMessage(CMD_RSSI_FETCH, ++mRssiFetchToken, 0),
                                 LINK_SAMPLING_INTERVAL_MS);
                     }
                     break;
 
-                case RSSI_PKTCNT_FETCH_SUCCEEDED:
-                    RssiPktcntStat stat = (RssiPktcntStat) msg.obj;
-                    int rssi = stat.rssi;
+                case WifiManager.RSSI_PKTCNT_FETCH_SUCCEEDED:
+                    RssiPacketCountInfo info = (RssiPacketCountInfo) msg.obj;
+                    int rssi = info.rssi;
                     if (DBG) logd("Fetch RSSI succeed, rssi=" + rssi);
 
                     long time = mCurrentBssid.mBssidAvoidTimeMax - SystemClock.elapsedRealtime();
@@ -795,7 +793,7 @@
                     }
                     break;
 
-                case RSSI_PKTCNT_FETCH_FAILED:
+                case WifiManager.RSSI_PKTCNT_FETCH_FAILED:
                     if (DBG) logd("RSSI_FETCH_FAILED");
                     break;
 
@@ -944,18 +942,18 @@
                     if (!mIsScreenOn) {
                         transitionTo(mOnlineState);
                     } else if (msg.arg1 == mRssiFetchToken) {
-                        mWsmChannel.sendMessage(RSSI_PKTCNT_FETCH, new RssiPktcntStat());
+                        mWsmChannel.sendMessage(WifiManager.RSSI_PKTCNT_FETCH);
                         sendMessageDelayed(obtainMessage(CMD_RSSI_FETCH, ++mRssiFetchToken, 0),
                                 LINK_SAMPLING_INTERVAL_MS);
                     }
                     break;
 
-                case RSSI_PKTCNT_FETCH_SUCCEEDED:
-                    RssiPktcntStat stat = (RssiPktcntStat) msg.obj;
-                    int rssi = stat.rssi;
+                case WifiManager.RSSI_PKTCNT_FETCH_SUCCEEDED:
+                    RssiPacketCountInfo info = (RssiPacketCountInfo) msg.obj;
+                    int rssi = info.rssi;
                     int mrssi = (mLastRssi + rssi) / 2;
-                    int txbad = stat.txbad;
-                    int txgood = stat.txgood;
+                    int txbad = info.txbad;
+                    int txgood = info.txgood;
                     if (DBG) logd("Fetch RSSI succeed, rssi=" + rssi + " mrssi=" + mrssi + " txbad="
                             + txbad + " txgood=" + txgood);
 
@@ -1003,7 +1001,7 @@
                     mLastRssi = rssi;
                     break;
 
-                case RSSI_PKTCNT_FETCH_FAILED:
+                case WifiManager.RSSI_PKTCNT_FETCH_FAILED:
                     // can happen if we are waiting to get a disconnect notification
                     if (DBG) logd("RSSI_FETCH_FAILED");
                     break;
@@ -1159,15 +1157,6 @@
     }
 
     /**
-     * Bundle of RSSI and packet count information
-     */
-    public class RssiPktcntStat {
-        public int rssi;
-        public int txgood;
-        public int txbad;
-    }
-
-    /**
      * Bundle of good link count parameters
      */
     private static class GoodLinkTarget {