Merge "Allow wificond to run as wifi:wifi"
diff --git a/service/java/com/android/server/wifi/WifiLoggerHal.java b/service/java/com/android/server/wifi/WifiLoggerHal.java
index 8a02764..0294e9b 100644
--- a/service/java/com/android/server/wifi/WifiLoggerHal.java
+++ b/service/java/com/android/server/wifi/WifiLoggerHal.java
@@ -46,4 +46,9 @@
     public static final byte RX_PKT_FATE_DRV_DROP_INVALID = 8;
     public static final byte RX_PKT_FATE_DRV_DROP_NOBUFS = 9;
     public static final byte RX_PKT_FATE_DRV_DROP_OTHER = 10;
+
+    /** These aren't formally part of the HAL. But they probably should be, eventually. */
+    public static final byte WIFI_ALERT_REASON_RESERVED = 0;
+    public static final byte WIFI_ALERT_REASON_MIN = 0;
+    public static final byte WIFI_ALERT_REASON_MAX = 64;
 }
diff --git a/service/java/com/android/server/wifi/WifiMetrics.java b/service/java/com/android/server/wifi/WifiMetrics.java
index 8a7cea4..e9d6a5a 100644
--- a/service/java/com/android/server/wifi/WifiMetrics.java
+++ b/service/java/com/android/server/wifi/WifiMetrics.java
@@ -76,11 +76,14 @@
      * combination. Indexed by WifiLog.WifiState * (1 + screenOn)
      */
     private final SparseIntArray mWifiSystemStateEntries = new SparseIntArray();
+    /** Mapping of RSSI values to counts. */
+    private final SparseIntArray mRssiPollCounts = new SparseIntArray();
+    /** Mapping of alert reason to the respective alert count. */
+    private final SparseIntArray mWifiAlertReasonCounts = new SparseIntArray();
     /**
      * Records the getElapsedSinceBootMillis (in seconds) that represents the beginning of data
      * capture for for this WifiMetricsProto
      */
-    private final SparseIntArray mRssiPollCounts = new SparseIntArray();
     private long mRecordStartTimeSec;
 
     class RouterFingerPrint {
@@ -807,6 +810,22 @@
     }
 
     /**
+     * Increments the count of alerts by alert reason.
+     *
+     * @param reason The cause of the alert. The reason values are driver-specific.
+     */
+    public void incrementAlertReasonCount(int reason) {
+        if (reason > WifiLoggerHal.WIFI_ALERT_REASON_MAX
+                || reason < WifiLoggerHal.WIFI_ALERT_REASON_MIN) {
+            reason = WifiLoggerHal.WIFI_ALERT_REASON_RESERVED;
+        }
+        synchronized (mLock) {
+            int alertCount = mWifiAlertReasonCounts.get(reason);
+            mWifiAlertReasonCounts.put(reason, alertCount + 1);
+        }
+    }
+
+    /**
      * Increment count of Watchdog successes.
      */
     public void incrementNumLastResortWatchdogSuccesses() {
@@ -941,6 +960,21 @@
                     sb.append(mRssiPollCounts.get(i) + " ");
                 }
                 pw.println("  " + sb.toString());
+                pw.print("mWifiLogProto.alertReasonCounts=");
+                sb.setLength(0);
+                for (int i = WifiLoggerHal.WIFI_ALERT_REASON_MIN;
+                        i <= WifiLoggerHal.WIFI_ALERT_REASON_MAX; i++) {
+                    int count = mWifiAlertReasonCounts.get(i);
+                    if (count > 0) {
+                        sb.append("(" + i + "," + count + "),");
+                    }
+                }
+                if (sb.length() > 1) {
+                    sb.setLength(sb.length() - 1);  // strip trailing comma
+                    pw.println(sb.toString());
+                } else {
+                    pw.println("()");
+                }
             }
         }
     }
@@ -954,6 +988,7 @@
     private void consolidateProto(boolean incremental) {
         List<WifiMetricsProto.ConnectionEvent> events = new ArrayList<>();
         List<WifiMetricsProto.RssiPollCount> rssis = new ArrayList<>();
+        List<WifiMetricsProto.AlertReasonCount> alertReasons = new ArrayList<>();
         synchronized (mLock) {
             for (ConnectionEvent event : mConnectionEventList) {
                 // If this is not incremental, dump full ConnectionEvent list
@@ -1011,6 +1046,18 @@
                 rssis.add(keyVal);
             }
             mWifiLogProto.rssiPollRssiCount = rssis.toArray(mWifiLogProto.rssiPollRssiCount);
+
+            /**
+             * Convert the SparseIntArray of alert reasons and counts to the proto's repeated
+             * IntKeyVal array.
+             */
+            for (int i = 0; i < mWifiAlertReasonCounts.size(); i++) {
+                WifiMetricsProto.AlertReasonCount keyVal = new WifiMetricsProto.AlertReasonCount();
+                keyVal.reason = mWifiAlertReasonCounts.keyAt(i);
+                keyVal.count = mWifiAlertReasonCounts.valueAt(i);
+                alertReasons.add(keyVal);
+            }
+            mWifiLogProto.alertReasonCount = alertReasons.toArray(mWifiLogProto.alertReasonCount);
         }
     }
 
@@ -1027,6 +1074,7 @@
             mWifiSystemStateEntries.clear();
             mRecordStartTimeSec = mClock.getElapsedSinceBootMillis() / 1000;
             mRssiPollCounts.clear();
+            mWifiAlertReasonCounts.clear();
             mWifiLogProto.clear();
         }
     }
diff --git a/service/java/com/android/server/wifi/WifiStateMachine.java b/service/java/com/android/server/wifi/WifiStateMachine.java
index 53382eb..c1f163d 100644
--- a/service/java/com/android/server/wifi/WifiStateMachine.java
+++ b/service/java/com/android/server/wifi/WifiStateMachine.java
@@ -3930,7 +3930,9 @@
                 case CMD_FIRMWARE_ALERT:
                     if (mWifiDiagnostics != null) {
                         byte[] buffer = (byte[])message.obj;
-                        mWifiDiagnostics.captureAlertData(message.arg1, buffer);
+                        int alertReason = message.arg1;
+                        mWifiDiagnostics.captureAlertData(alertReason, buffer);
+                        mWifiMetrics.incrementAlertReasonCount(alertReason);
                     }
                     break;
                 case CMD_GET_LINK_LAYER_STATS:
diff --git a/service/java/com/android/server/wifi/nan/WifiNanServiceImpl.java b/service/java/com/android/server/wifi/nan/WifiNanServiceImpl.java
index 4600318..9c13d8d 100644
--- a/service/java/com/android/server/wifi/nan/WifiNanServiceImpl.java
+++ b/service/java/com/android/server/wifi/nan/WifiNanServiceImpl.java
@@ -334,7 +334,7 @@
         enforceAccessPermission();
         enforceChangePermission();
 
-        if (retryCount < 0 || retryCount > WifiNanSession.MAX_SEND_RETRY_COUNT) {
+        if (retryCount < 0 || retryCount > WifiNanSession.getMaxSendRetryCount()) {
             throw new IllegalArgumentException("Invalid 'retryCount' must be non-negative "
                     + "and <= WifiNanSession.MAX_SEND_RETRY_COUNT");
         }
@@ -411,7 +411,7 @@
     }
 
     private void enforceLocationPermission() {
-        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_FINE_LOCATION,
+        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION,
                 TAG);
     }
 
diff --git a/service/java/com/android/server/wifi/nan/WifiNanStateManager.java b/service/java/com/android/server/wifi/nan/WifiNanStateManager.java
index 04f7268..ac2c0c9 100644
--- a/service/java/com/android/server/wifi/nan/WifiNanStateManager.java
+++ b/service/java/com/android/server/wifi/nan/WifiNanStateManager.java
@@ -1722,7 +1722,7 @@
         if (VDBG) {
             Log.v(TAG, "sendNanStateChangedBroadcast: enabled=" + enabled);
         }
-        final Intent intent = new Intent(WifiNanManager.WIFI_NAN_STATE_CHANGED_ACTION);
+        final Intent intent = new Intent(WifiNanManager.ACTION_WIFI_NAN_STATE_CHANGED);
         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
         if (enabled) {
             intent.putExtra(WifiNanManager.EXTRA_WIFI_STATE, WifiNanManager.WIFI_NAN_STATE_ENABLED);
diff --git a/service/proto/wifi.proto b/service/proto/wifi.proto
index 2bd410c..862c866 100644
--- a/service/proto/wifi.proto
+++ b/service/proto/wifi.proto
@@ -193,6 +193,9 @@
   // Total number of times WiFi connected immediately after a Last Resort Watchdog trigger,
   // without new networks becoming available.
   optional int32 num_last_resort_watchdog_successes = 36;
+
+  // Counts the occurrences of each alert reason.
+  repeated AlertReasonCount alert_reason_count = 47;
 }
 
 // Information that gets logged for every WiFi connection.
@@ -353,3 +356,12 @@
   // Number of RSSI polls with 'rssi'
   optional int32 count = 2;
 }
+
+// Number of occurrences of a specific alert reason value
+message AlertReasonCount {
+  // Alert reason
+  optional int32 reason = 1;
+
+  // Number of alerts with |reason|.
+  optional int32 count = 2;
+}
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiMetricsTest.java b/tests/wifitests/src/com/android/server/wifi/WifiMetricsTest.java
index d7d5e85..6f4e106 100644
--- a/tests/wifitests/src/com/android/server/wifi/WifiMetricsTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/WifiMetricsTest.java
@@ -104,15 +104,32 @@
         mDeserializedWifiMetrics = WifiMetricsProto.WifiLog.parseFrom(protoBytes);
     }
 
+    /** Verifies that dump() includes the expected header */
     @Test
-    public void dumpHumanReadable() throws Exception {
-        ByteArrayOutputStream stream = new ByteArrayOutputStream();
-        PrintWriter writer = new PrintWriter(stream);
-        String[] args = new String[0];
-        mWifiMetrics.dump(null, writer, args);
-        writer.flush();
-        assertTrue("stream.toString().contains(\"WifiMetrics\")",
-                stream.toString().contains("WifiMetrics"));
+    public void stateDumpIncludesHeader() throws Exception {
+        assertStringContains(getStateDump(), "WifiMetrics");
+    }
+
+    /** Verifies that dump() includes correct alert count when there are no alerts. */
+    @Test
+    public void stateDumpAlertCountIsCorrectWithNoAlerts() throws Exception {
+        assertStringContains(getStateDump(), "mWifiLogProto.alertReasonCounts=()");
+    }
+
+    /** Verifies that dump() includes correct alert count when there is one alert. */
+    @Test
+    public void stateDumpAlertCountIsCorrectWithOneAlert() throws Exception {
+        mWifiMetrics.incrementAlertReasonCount(1);
+        assertStringContains(getStateDump(), "mWifiLogProto.alertReasonCounts=(1,1)");
+    }
+
+    /** Verifies that dump() includes correct alert count when there are multiple alerts. */
+    @Test
+    public void stateDumpAlertCountIsCorrectWithMultipleAlerts() throws Exception {
+        mWifiMetrics.incrementAlertReasonCount(1);
+        mWifiMetrics.incrementAlertReasonCount(1);
+        mWifiMetrics.incrementAlertReasonCount(16);
+        assertStringContains(getStateDump(), "mWifiLogProto.alertReasonCounts=(1,2),(16,1)");
     }
 
     @Test
@@ -247,6 +264,14 @@
                 mWifiMetrics.incrementRssiPollRssiCount(FIRST_RSSI_LEVEL + i);
             }
         }
+        // Test alert-reason clamping.
+        mWifiMetrics.incrementAlertReasonCount(WifiLoggerHal.WIFI_ALERT_REASON_MIN - 1);
+        mWifiMetrics.incrementAlertReasonCount(WifiLoggerHal.WIFI_ALERT_REASON_MAX + 1);
+        // Simple cases for alert reason.
+        mWifiMetrics.incrementAlertReasonCount(1);
+        mWifiMetrics.incrementAlertReasonCount(1);
+        mWifiMetrics.incrementAlertReasonCount(1);
+        mWifiMetrics.incrementAlertReasonCount(2);
     }
 
     /**
@@ -330,6 +355,10 @@
             assertEquals(FIRST_RSSI_LEVEL + i, mDeserializedWifiMetrics.rssiPollRssiCount[i].rssi);
             assertEquals(i + 1, mDeserializedWifiMetrics.rssiPollRssiCount[i].count);
         }
+        assertEquals(2, mDeserializedWifiMetrics.alertReasonCount[0].count);  // Clamped reasons.
+        assertEquals(3, mDeserializedWifiMetrics.alertReasonCount[1].count);
+        assertEquals(1, mDeserializedWifiMetrics.alertReasonCount[2].count);
+        assertEquals(3, mDeserializedWifiMetrics.alertReasonCount.length);
     }
 
     /**
@@ -467,6 +496,8 @@
         dumpProtoAndDeserialize();
         //Check there are only 3 connection events
         assertEquals(mDeserializedWifiMetrics.connectionEvent.length, 4);
+        assertEquals(mDeserializedWifiMetrics.rssiPollRssiCount.length, 0);
+        assertEquals(mDeserializedWifiMetrics.alertReasonCount.length, 0);
 
         // Create 2 ConnectionEvents
         mWifiMetrics.startConnectionEvent(null,  "BLUE",
@@ -485,4 +516,21 @@
         //Check there are only 2 connection events
         assertEquals(mDeserializedWifiMetrics.connectionEvent.length, 2);
     }
+
+    private void assertStringContains(
+            String actualString, String expectedSubstring) {
+        assertTrue("Expected text not found in: " + actualString,
+                actualString.contains(expectedSubstring));
+    }
+
+    private String getStateDump() {
+        ByteArrayOutputStream stream = new ByteArrayOutputStream();
+        PrintWriter writer = new PrintWriter(stream);
+        String[] args = new String[0];
+        mWifiMetrics.dump(null, writer, args);
+        writer.flush();
+        return stream.toString();
+    }
 }
+
+
diff --git a/tests/wifitests/src/com/android/server/wifi/nan/WifiNanDataPathStateManagerTest.java b/tests/wifitests/src/com/android/server/wifi/nan/WifiNanDataPathStateManagerTest.java
index 839b5e8..574584a 100644
--- a/tests/wifitests/src/com/android/server/wifi/nan/WifiNanDataPathStateManagerTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/nan/WifiNanDataPathStateManagerTest.java
@@ -607,7 +607,7 @@
         when(mMockNanService.connect(any(IBinder.class), anyString(),
                 any(IWifiNanEventCallback.class), any(ConfigRequest.class))).thenReturn(clientId);
 
-        mgr.connect(mMockLooper.getLooper(), mockCallback, configRequest);
+        mgr.connect(mMockLooper.getLooper(), configRequest, mockCallback);
         verify(mMockNanService).connect(any(IBinder.class), anyString(),
                 clientProxyCallback.capture(), eq(configRequest));
         clientProxyCallback.getValue().onConnectSuccess();
@@ -648,7 +648,7 @@
         when(mMockNanService.connect(any(IBinder.class), anyString(),
                 any(IWifiNanEventCallback.class), any(ConfigRequest.class))).thenReturn(clientId);
 
-        mgr.connect(mMockLooper.getLooper(), mockCallback, configRequest);
+        mgr.connect(mMockLooper.getLooper(), configRequest, mockCallback);
         verify(mMockNanService).connect(any(IBinder.class), anyString(),
                 clientProxyCallback.capture(), eq(configRequest));
         clientProxyCallback.getValue().onConnectSuccess();
diff --git a/tests/wifitests/src/com/android/server/wifi/nan/WifiNanManagerTest.java b/tests/wifitests/src/com/android/server/wifi/nan/WifiNanManagerTest.java
index 4291b32..bc7d62d 100644
--- a/tests/wifitests/src/com/android/server/wifi/nan/WifiNanManagerTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/nan/WifiNanManagerTest.java
@@ -296,7 +296,7 @@
                 .forClass(WifiNanPublishSession.class);
 
         // (0) connect + success
-        mDut.connect(mMockLooper.getLooper(), mockCallback, configRequest);
+        mDut.connect(mMockLooper.getLooper(), configRequest, mockCallback);
         inOrder.verify(mockNanService).connect(any(IBinder.class), anyString(),
                 clientProxyCallback.capture(), eq(configRequest));
         clientProxyCallback.getValue().onConnectSuccess();
@@ -375,7 +375,7 @@
                 .forClass(WifiNanPublishSession.class);
 
         // (1) connect successfully
-        mDut.connect(mMockLooper.getLooper(), mockCallback, configRequest);
+        mDut.connect(mMockLooper.getLooper(), configRequest, mockCallback);
         inOrder.verify(mockNanService).connect(any(IBinder.class), anyString(),
                 clientProxyCallback.capture(), eq(configRequest));
         clientProxyCallback.getValue().onConnectSuccess();
@@ -430,7 +430,7 @@
                 .forClass(WifiNanSubscribeSession.class);
 
         // (0) connect + success
-        mDut.connect(mMockLooper.getLooper(), mockCallback, configRequest);
+        mDut.connect(mMockLooper.getLooper(), configRequest, mockCallback);
         inOrder.verify(mockNanService).connect(any(IBinder.class), anyString(),
                 clientProxyCallback.capture(), eq(configRequest));
         clientProxyCallback.getValue().onConnectSuccess();
@@ -509,7 +509,7 @@
                 .forClass(WifiNanSubscribeSession.class);
 
         // (1) connect successfully
-        mDut.connect(mMockLooper.getLooper(), mockCallback, configRequest);
+        mDut.connect(mMockLooper.getLooper(), configRequest, mockCallback);
         inOrder.verify(mockNanService).connect(any(IBinder.class), anyString(),
                 clientProxyCallback.capture(), eq(configRequest));
         clientProxyCallback.getValue().onConnectSuccess();
@@ -884,7 +884,7 @@
                 .forClass(RttManager.RttResult[].class);
 
         // (1) connect successfully
-        mDut.connect(mMockLooper.getLooper(), mockCallback, configRequest);
+        mDut.connect(mMockLooper.getLooper(), configRequest, mockCallback);
         inOrder.verify(mockNanService).connect(any(IBinder.class), anyString(),
                 clientProxyCallback.capture(), eq(configRequest));
         clientProxyCallback.getValue().onConnectSuccess();
@@ -958,7 +958,7 @@
                 mockPublishSession, mockRttListener);
 
         // (1) connect successfully
-        mDut.connect(mMockLooper.getLooper(), mockCallback, configRequest);
+        mDut.connect(mMockLooper.getLooper(), configRequest, mockCallback);
         inOrder.verify(mockNanService).connect(any(IBinder.class), anyString(),
                 clientProxyCallback.capture(), eq(configRequest));
         clientProxyCallback.getValue().onConnectSuccess();
@@ -1018,7 +1018,7 @@
                 mockPublishSession, mockRttListener);
 
         // (1) connect successfully
-        mDut.connect(mMockLooper.getLooper(), mockCallback, configRequest);
+        mDut.connect(mMockLooper.getLooper(), configRequest, mockCallback);
         inOrder.verify(mockNanService).connect(any(IBinder.class), anyString(),
                 clientProxyCallback.capture(), eq(configRequest));
         clientProxyCallback.getValue().onConnectSuccess();
diff --git a/tests/wifitests/src/com/android/server/wifi/nan/WifiNanStateManagerTest.java b/tests/wifitests/src/com/android/server/wifi/nan/WifiNanStateManagerTest.java
index d7b7042..62c809b 100644
--- a/tests/wifitests/src/com/android/server/wifi/nan/WifiNanStateManagerTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/nan/WifiNanStateManagerTest.java
@@ -2489,7 +2489,7 @@
         inOrder.verify(mMockContext).sendBroadcastAsUser(intent.capture(), eq(UserHandle.ALL));
 
         collector.checkThat("intent action", intent.getValue().getAction(),
-                equalTo(WifiNanManager.WIFI_NAN_STATE_CHANGED_ACTION));
+                equalTo(WifiNanManager.ACTION_WIFI_NAN_STATE_CHANGED));
         collector.checkThat("intent contains wifi status key",
                 intent.getValue().getExtras().containsKey(WifiNanManager.EXTRA_WIFI_STATE),
                 equalTo(true));