Merge "Passing padding information to the driver -- hal." into sc-dev
diff --git a/biometrics/fingerprint/aidl/default/Session.cpp b/biometrics/fingerprint/aidl/default/Session.cpp
index 9e6ac77..c035407 100644
--- a/biometrics/fingerprint/aidl/default/Session.cpp
+++ b/biometrics/fingerprint/aidl/default/Session.cpp
@@ -46,7 +46,7 @@
 
 void Session::enterStateOrCrash(int cookie, SessionState state) {
     CHECK(mScheduledState == state);
-    mCurrentState = mScheduledState;
+    mCurrentState = state;
     mScheduledState = SessionState::IDLING;
     mCb->onStateChanged(cookie, mCurrentState);
 }
diff --git a/biometrics/fingerprint/aidl/default/include/Session.h b/biometrics/fingerprint/aidl/default/include/Session.h
index d2f0c19..97d5645 100644
--- a/biometrics/fingerprint/aidl/default/include/Session.h
+++ b/biometrics/fingerprint/aidl/default/include/Session.h
@@ -82,13 +82,28 @@
     // by calling ISessionCallback#onStateChanged.
     void enterIdling(int cookie);
 
+    // The sensor and user IDs for which this session was created.
     int32_t mSensorId;
     int32_t mUserId;
+
+    // Callback for talking to the framework. This callback must only be called from non-binder
+    // threads to prevent nested binder calls and consequently a binder thread exhaustion.
+    // Practically, it means that this callback should always be called from the worker thread.
     std::shared_ptr<ISessionCallback> mCb;
+
+    // Module that communicates to the actual fingerprint hardware, keystore, TEE, etc. In real
+    // life such modules typically consume a lot of memory and are slow to initialize. This is here
+    // to showcase how such a module can be used within a Session without incurring the high
+    // initialization costs every time a Session is constructed.
     FakeFingerprintEngine* mEngine;
+
+    // Worker thread that allows to schedule tasks for asynchronous execution.
     WorkerThread* mWorker;
-    SessionState mScheduledState;
-    SessionState mCurrentState;
+
+    // Simple representation of the session's state machine. These are atomic because they can be
+    // modified from both the main and the worker threads.
+    std::atomic<SessionState> mScheduledState;
+    std::atomic<SessionState> mCurrentState;
 };
 
 }  // namespace aidl::android::hardware::biometrics::fingerprint
diff --git a/broadcastradio/2.0/vts/functional/VtsHalBroadcastradioV2_0TargetTest.cpp b/broadcastradio/2.0/vts/functional/VtsHalBroadcastradioV2_0TargetTest.cpp
index 5ba7a76..362ab41 100644
--- a/broadcastradio/2.0/vts/functional/VtsHalBroadcastradioV2_0TargetTest.cpp
+++ b/broadcastradio/2.0/vts/functional/VtsHalBroadcastradioV2_0TargetTest.cpp
@@ -495,7 +495,7 @@
  *    invoked carrying a proper selector;
  *  - program changes exactly to what was requested.
  */
-TEST_F(BroadcastRadioHalTest, DabTune) {
+TEST_P(BroadcastRadioHalTest, DabTune) {
     ASSERT_TRUE(openSession());
 
     ProgramSelector sel = {};
diff --git a/power/stats/aidl/android/hardware/power/stats/IPowerStats.aidl b/power/stats/aidl/android/hardware/power/stats/IPowerStats.aidl
index 7a95f74..edc43ea 100644
--- a/power/stats/aidl/android/hardware/power/stats/IPowerStats.aidl
+++ b/power/stats/aidl/android/hardware/power/stats/IPowerStats.aidl
@@ -32,7 +32,7 @@
      * A PowerEntity is defined as a platform subsystem, peripheral, or power domain that impacts
      * the total device power consumption.
      *
-     * @return List of information on each PowerEntity
+     * @return List of information on each PowerEntity for which state residency can be requested.
      */
     PowerEntity[] getPowerEntityInfo();
 
@@ -52,11 +52,12 @@
      *     Passing an empty list will return state residency for all available PowerEntitys.
      *     ID of each PowerEntity is contained in PowerEntityInfo.
      *
-     * @return StateResidency since boot for each requested PowerEntity
+     * @return StateResidencyResults since boot for each requested and available PowerEntity. Note
+     * that StateResidencyResult for a given PowerEntity may not always be available. Clients shall
+     * not rely on StateResidencyResult always being returned for every request.
      *
-     * Returns the following service-specific exceptions in order of highest priority:
-     *  - STATUS_BAD_VALUE if an invalid powerEntityId is provided
-     *  - STATUS_FAILED_TRANSACTION if any StateResidencyResult fails to be returned
+     * Returns the following exception codes:
+     *  - EX_ILLEGAL_ARGUMENT if an invalid powerEntityId is provided
      */
     StateResidencyResult[] getStateResidency(in int[] powerEntityIds);
 
@@ -66,7 +67,7 @@
      * An EnergyConsumer is a device subsystem or peripheral that consumes energy. Energy
      * consumption data may be used by framework for the purpose of power attribution.
      *
-     * @return List of EnergyConsumers that are available.
+     * @return List of EnergyConsumers for which energy consumption can be requested.
      */
     EnergyConsumer[] getEnergyConsumerInfo();
 
@@ -74,38 +75,40 @@
      * Reports the energy consumed since boot by each requested EnergyConsumer.
      *
      * @param energyConsumerIds List of IDs of EnergyConsumers for which data is requested.
-     *     Passing an empty list will return state residency for all available EnergyConsumers.
+     *     Passing an empty list will return results for all available EnergyConsumers.
      *
-     * @return Energy consumed since boot for each requested EnergyConsumer
+     * @return Energy consumed since boot for each requested and available EnergyConsumer. Note
+     * that EnergyConsumerResult for a given EnergyConsumer may not always be available. Clients
+     * shall not rely on EnergyConsumerResult always being returned for every request.
      *
-     * Returns the following service-specific exceptions in order of highest priority:
-     *  - STATUS_BAD_VALUE if an invalid energyConsumerId is provided
-     *  - STATUS_FAILED_TRANSACTION if any EnergyConsumerResult fails to be returned
+     * Returns the following exception codes:
+     *  - EX_ILLEGAL_ARGUMENT if an invalid energyConsumerId is provided
      */
     EnergyConsumerResult[] getEnergyConsumed(in int[] energyConsumerIds);
 
     /**
-     * Return information related to all channels monitored by Energy Meters.
+     * Return information related to all Channels monitored by Energy Meters.
      *
      * An Energy Meter is a device that monitors energy and may support monitoring multiple
      * channels simultaneously. A channel may correspond a bus, sense resistor, or power rail.
      *
-     * @return Channels monitored by Energy Meters.
+     * @return All Channels for which energy measurements can be requested.
      */
     Channel[] getEnergyMeterInfo();
 
     /**
-     * Reports accumulated energy for each specified channel.
+     * Reports accumulated energy for each specified Channel.
      *
      * @param channelIds IDs of channels for which data is requested.
      *     Passing an empty list will return energy measurements for all available channels.
      *     ID of each channel is contained in ChannelInfo.
      *
-     * @return Energy measured since boot for each requested channel
+     * @return Energy measured since boot for each requested and available Channel. Note
+     * that EnergyMeasurement for a given Channel may not always be available. Clients
+     * shall not rely on EnergyMeasurement always being returned for every request.
      *
-     * Returns the following service-specific exceptions in order of highest priority:
-     *  - STATUS_BAD_VALUE if an invalid channelId is provided
-     *  - STATUS_FAILED_TRANSACTION if any EnergyMeasurement fails to be returned
+     * Returns the following exception codes:
+     *  - EX_ILLEGAL_ARGUMENT if an invalid channelId is provided
      */
     EnergyMeasurement[] readEnergyMeter(in int[] channelIds);
 }
diff --git a/power/stats/aidl/default/FakeEnergyMeter.h b/power/stats/aidl/default/FakeEnergyMeter.h
index f0d4ee7..56dcdcc 100644
--- a/power/stats/aidl/default/FakeEnergyMeter.h
+++ b/power/stats/aidl/default/FakeEnergyMeter.h
@@ -60,9 +60,12 @@
             *_aidl_return = mEnergyMeasurements;
         } else {
             for (int32_t id : in_channelIds) {
-                if (id >= 0 && id < mEnergyMeasurements.size()) {
-                    _aidl_return->push_back(mEnergyMeasurements[id]);
+                // check for invalid ids
+                if (id < 0 || id >= mEnergyMeasurements.size()) {
+                    return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_ILLEGAL_ARGUMENT));
                 }
+
+                _aidl_return->push_back(mEnergyMeasurements[id]);
             }
         }
 
diff --git a/power/stats/aidl/default/PowerStats.cpp b/power/stats/aidl/default/PowerStats.cpp
index 1373502..7cf591e 100644
--- a/power/stats/aidl/default/PowerStats.cpp
+++ b/power/stats/aidl/default/PowerStats.cpp
@@ -81,14 +81,12 @@
         return getStateResidency(v, _aidl_return);
     }
 
-    binder_status_t err = STATUS_OK;
-
     std::unordered_map<std::string, std::vector<StateResidency>> stateResidencies;
 
     for (const int32_t id : in_powerEntityIds) {
-        // skip any invalid ids
+        // check for invalid ids
         if (id < 0 || id >= mPowerEntityInfos.size()) {
-            continue;
+            return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_ILLEGAL_ARGUMENT));
         }
 
         // Check to see if we already have data for the given id
@@ -106,12 +104,12 @@
             };
             _aidl_return->emplace_back(res);
         } else {
-            // Failed to retrieve results for the given id.
-            err = STATUS_FAILED_TRANSACTION;
+            // Failed to get results for the given id.
+            LOG(ERROR) << "Failed to get results for " << powerEntityName;
         }
     }
 
-    return ndk::ScopedAStatus::fromStatus(err);
+    return ndk::ScopedAStatus::ok();
 }
 
 ndk::ScopedAStatus PowerStats::getEnergyConsumerInfo(std::vector<EnergyConsumer>* _aidl_return) {
@@ -132,12 +130,10 @@
         return getEnergyConsumed(v, _aidl_return);
     }
 
-    binder_status_t err = STATUS_OK;
-
     for (const auto id : in_energyConsumerIds) {
-        // skip any invalid ids
+        // check for invalid ids
         if (id < 0 || id >= mEnergyConsumers.size()) {
-            continue;
+            return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_ILLEGAL_ARGUMENT));
         }
 
         auto optionalResult = mEnergyConsumers[id]->getEnergyConsumed();
@@ -146,12 +142,12 @@
             result.id = id;
             _aidl_return->emplace_back(result);
         } else {
-            // Failed to retrieve results for the given id.
-            err = STATUS_FAILED_TRANSACTION;
+            // Failed to get results for the given id.
+            LOG(ERROR) << "Failed to get results for " << mEnergyConsumerInfos[id].name;
         }
     }
 
-    return ndk::ScopedAStatus::fromStatus(err);
+    return ndk::ScopedAStatus::ok();
 }
 
 ndk::ScopedAStatus PowerStats::getEnergyMeterInfo(std::vector<Channel>* _aidl_return) {
diff --git a/radio/1.6/types.hal b/radio/1.6/types.hal
index 6400c63..95eba69 100644
--- a/radio/1.6/types.hal
+++ b/radio/1.6/types.hal
@@ -813,6 +813,11 @@
      * see: 3GPP TS 24.501 Section 9.11.2.8.
      */
     int32_t mappedHplmnSD;
+
+    /**
+     * Field to indicate the current status of the slice.
+     */
+    SliceStatus status;
 };
 
 /**
@@ -986,9 +991,9 @@
      */
     vec<UrspRule> urspRules;
     /**
-     * Struct containing all NSSAIs (list of slice info).
+     * List of all slices.
      */
-    Nssais nssais;
+    vec<SliceInfo> sliceInfo;
 };
 
 /**
@@ -1011,7 +1016,6 @@
     vec<RouteSelectionDescriptor> routeSelectionDescriptor;
 };
 
-
 /**
  * This struct represents a single route selection descriptor as defined in
  * 3GPP TS 24.526.
@@ -1067,47 +1071,13 @@
     SscMode value;
 };
 
-/**
- * This struct contains all NSSAIs (lists of slices).
- */
-struct Nssais {
-    /**
-     * These are all the slices configured by the network. This includes allowed
-     * and rejected slices, as well as slices that are neither allowed nor rejected
-     * yet. Empty vector indicates that no slices are configured, and in that case
-     * allowed and rejected vectors must be empty as well.
-     */
-    vec<SliceInfo> configured;
-    /**
-     * These are all the slices that the UE is allowed to use. All these slices
-     * must be configured as well. Empty vector indicates that no slices are
-     * allowed yet.
-     */
-    vec<SliceInfo> allowed;
-    /**
-     * These are all the slices that the UE is not allowed to use. All these slices
-     * must be configured as well. Empty vector indicates that no slices are
-     * rejected yet.
-     */
-    vec<RejectedSliceInfo> rejected;
-    /**
-     * Default configured NSSAI
-     */
-    vec<SliceInfo> defaultConfigured;
-};
-
-/**
- * This struct represents a network slice rejected by the network. It contains a
- * rejectionCause corresponding to a rejected network slice.
- */
-struct RejectedSliceInfo {
-    SliceInfo sliceInfo;
-    SliceRejectionCause rejectionCause;
-};
-
-enum SliceRejectionCause : int32_t {
-    NOT_AVAILABLE_IN_PLMN,
-    NOT_AVAILABLE_IN_REG_AREA,
+enum SliceStatus : int32_t {
+    UNKNOWN,
+    CONFIGURED, // Configured but not allowed or rejected yet
+    ALLOWED,    // Allowed to be used
+    REJECTED_NOT_AVAILABLE_IN_PLMN,     // Rejected because not available in PLMN
+    REJECTED_NOT_AVAILABLE_IN_REG_AREA, // Rejected because not available in reg area
+    DEFAULT_CONFIGURED,     // Considered valid when configured/allowed slices are not available
 };
 
 /**
diff --git a/wifi/1.5/default/hidl_struct_util.cpp b/wifi/1.5/default/hidl_struct_util.cpp
index cd0edbe..baa898e 100644
--- a/wifi/1.5/default/hidl_struct_util.cpp
+++ b/wifi/1.5/default/hidl_struct_util.cpp
@@ -1077,6 +1077,17 @@
         legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].contention_num_samples;
     hidl_stats->iface.timeSliceDutyCycleInPercent =
         legacy_stats.iface.info.time_slicing_duty_cycle_percent;
+    // peer info legacy_stats conversion.
+    std::vector<StaPeerInfo> hidl_peers_info_stats;
+    for (const auto& legacy_peer_info_stats : legacy_stats.peers) {
+        StaPeerInfo hidl_peer_info_stats;
+        if (!convertLegacyPeerInfoStatsToHidl(legacy_peer_info_stats,
+                                              &hidl_peer_info_stats)) {
+            return false;
+        }
+        hidl_peers_info_stats.push_back(hidl_peer_info_stats);
+    }
+    hidl_stats->iface.peers = hidl_peers_info_stats;
     // radio legacy_stats conversion.
     std::vector<V1_3::StaLinkLayerRadioStats> hidl_radios_stats;
     for (const auto& legacy_radio_stats : legacy_stats.radios) {
@@ -1094,6 +1105,35 @@
     return true;
 }
 
+bool convertLegacyPeerInfoStatsToHidl(
+    const legacy_hal::WifiPeerInfo& legacy_peer_info_stats,
+    StaPeerInfo* hidl_peer_info_stats) {
+    if (!hidl_peer_info_stats) {
+        return false;
+    }
+    *hidl_peer_info_stats = {};
+    hidl_peer_info_stats->staCount =
+        legacy_peer_info_stats.peer_info.bssload.sta_count;
+    hidl_peer_info_stats->chanUtil =
+        legacy_peer_info_stats.peer_info.bssload.chan_util;
+
+    std::vector<StaRateStat> hidlRateStats;
+    for (const auto& legacy_rate_stats : legacy_peer_info_stats.rate_stats) {
+        StaRateStat rateStat;
+        if (!convertLegacyWifiRateInfoToHidl(legacy_rate_stats.rate,
+                                             &rateStat.rateInfo)) {
+            return false;
+        }
+        rateStat.txMpdu = legacy_rate_stats.tx_mpdu;
+        rateStat.rxMpdu = legacy_rate_stats.rx_mpdu;
+        rateStat.mpduLost = legacy_rate_stats.mpdu_lost;
+        rateStat.retries = legacy_rate_stats.retries;
+        hidlRateStats.push_back(rateStat);
+    }
+    hidl_peer_info_stats->rateStats = hidlRateStats;
+    return true;
+}
+
 bool convertLegacyRoamingCapabilitiesToHidl(
     const legacy_hal::wifi_roaming_capabilities& legacy_caps,
     StaRoamingCapabilities* hidl_caps) {
diff --git a/wifi/1.5/default/hidl_struct_util.h b/wifi/1.5/default/hidl_struct_util.h
index 8b81033..352f213 100644
--- a/wifi/1.5/default/hidl_struct_util.h
+++ b/wifi/1.5/default/hidl_struct_util.h
@@ -212,6 +212,11 @@
 bool convertLegacyWifiUsableChannelsToHidl(
     const std::vector<legacy_hal::wifi_usable_channel>& legacy_usable_channels,
     std::vector<V1_5::WifiUsableChannel>* hidl_usable_channels);
+bool convertLegacyPeerInfoStatsToHidl(
+    const legacy_hal::WifiPeerInfo& legacy_peer_info_stats,
+    StaPeerInfo* hidl_peer_info_stats);
+bool convertLegacyWifiRateInfoToHidl(const legacy_hal::wifi_rate& legacy_rate,
+                                     V1_4::WifiRateInfo* hidl_rate);
 }  // namespace hidl_struct_util
 }  // namespace implementation
 }  // namespace V1_5
diff --git a/wifi/1.5/default/tests/hidl_struct_util_unit_tests.cpp b/wifi/1.5/default/tests/hidl_struct_util_unit_tests.cpp
index 6391a6a..e70d7ba 100644
--- a/wifi/1.5/default/tests/hidl_struct_util_unit_tests.cpp
+++ b/wifi/1.5/default/tests/hidl_struct_util_unit_tests.cpp
@@ -132,6 +132,8 @@
     legacy_hal::LinkLayerStats legacy_stats{};
     legacy_stats.radios.push_back(legacy_hal::LinkLayerRadioStats{});
     legacy_stats.radios.push_back(legacy_hal::LinkLayerRadioStats{});
+    legacy_stats.peers.push_back(legacy_hal::WifiPeerInfo{});
+    legacy_stats.peers.push_back(legacy_hal::WifiPeerInfo{});
     legacy_stats.iface.beacon_rx = rand();
     legacy_stats.iface.rssi_mgmt = rand();
     legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].rx_mpdu = rand();
@@ -175,6 +177,7 @@
         rand();
 
     legacy_stats.iface.info.time_slicing_duty_cycle_percent = rand();
+    legacy_stats.iface.num_peers = 1;
 
     for (auto& radio : legacy_stats.radios) {
         radio.stats.on_time = rand();
@@ -204,6 +207,31 @@
         radio.channel_stats.push_back(channel_stat2);
     }
 
+    for (auto& peer : legacy_stats.peers) {
+        peer.peer_info.bssload.sta_count = rand();
+        peer.peer_info.bssload.chan_util = rand();
+        wifi_rate_stat rate_stat1 = {
+            .rate = {3, 1, 2, 5, 0, 0},
+            .tx_mpdu = 0,
+            .rx_mpdu = 1,
+            .mpdu_lost = 2,
+            .retries = 3,
+            .retries_short = 4,
+            .retries_long = 5,
+        };
+        wifi_rate_stat rate_stat2 = {
+            .rate = {2, 2, 1, 6, 0, 1},
+            .tx_mpdu = 6,
+            .rx_mpdu = 7,
+            .mpdu_lost = 8,
+            .retries = 9,
+            .retries_short = 10,
+            .retries_long = 11,
+        };
+        peer.rate_stats.push_back(rate_stat1);
+        peer.rate_stats.push_back(rate_stat2);
+    }
+
     V1_5::StaLinkLayerStats converted{};
     hidl_struct_util::convertLegacyLinkLayerStatsToHidl(legacy_stats,
                                                         &converted);
@@ -330,6 +358,37 @@
                       converted.radios[i].channelStats[k].onTimeInMs);
         }
     }
+
+    EXPECT_EQ(legacy_stats.peers.size(), converted.iface.peers.size());
+    for (size_t i = 0; i < legacy_stats.peers.size(); i++) {
+        EXPECT_EQ(legacy_stats.peers[i].peer_info.bssload.sta_count,
+                  converted.iface.peers[i].staCount);
+        EXPECT_EQ(legacy_stats.peers[i].peer_info.bssload.chan_util,
+                  converted.iface.peers[i].chanUtil);
+        for (size_t j = 0; j < legacy_stats.peers[i].rate_stats.size(); j++) {
+            EXPECT_EQ(legacy_stats.peers[i].rate_stats[j].rate.preamble,
+                      (uint32_t)converted.iface.peers[i]
+                          .rateStats[j]
+                          .rateInfo.preamble);
+            EXPECT_EQ(
+                legacy_stats.peers[i].rate_stats[j].rate.nss,
+                (uint32_t)converted.iface.peers[i].rateStats[j].rateInfo.nss);
+            EXPECT_EQ(
+                legacy_stats.peers[i].rate_stats[j].rate.bw,
+                (uint32_t)converted.iface.peers[i].rateStats[j].rateInfo.bw);
+            EXPECT_EQ(
+                legacy_stats.peers[i].rate_stats[j].rate.rateMcsIdx,
+                converted.iface.peers[i].rateStats[j].rateInfo.rateMcsIdx);
+            EXPECT_EQ(legacy_stats.peers[i].rate_stats[j].tx_mpdu,
+                      converted.iface.peers[i].rateStats[j].txMpdu);
+            EXPECT_EQ(legacy_stats.peers[i].rate_stats[j].rx_mpdu,
+                      converted.iface.peers[i].rateStats[j].rxMpdu);
+            EXPECT_EQ(legacy_stats.peers[i].rate_stats[j].mpdu_lost,
+                      converted.iface.peers[i].rateStats[j].mpduLost);
+            EXPECT_EQ(legacy_stats.peers[i].rate_stats[j].retries,
+                      converted.iface.peers[i].rateStats[j].retries);
+        }
+    }
 }
 
 TEST_F(HidlStructUtilTest, CanConvertLegacyFeaturesToHidl) {
diff --git a/wifi/1.5/default/wifi_legacy_hal.cpp b/wifi/1.5/default/wifi_legacy_hal.cpp
index 260f186..45ad84b 100644
--- a/wifi/1.5/default/wifi_legacy_hal.cpp
+++ b/wifi/1.5/default/wifi_legacy_hal.cpp
@@ -719,9 +719,29 @@
                           wifi_iface_stat* iface_stats_ptr, int num_radios,
                           wifi_radio_stat* radio_stats_ptr) {
             wifi_radio_stat* l_radio_stats_ptr;
+            wifi_peer_info* l_peer_info_stats_ptr;
 
             if (iface_stats_ptr != nullptr) {
                 link_stats_ptr->iface = *iface_stats_ptr;
+                l_peer_info_stats_ptr = iface_stats_ptr->peer_info;
+                for (uint32_t i = 0; i < iface_stats_ptr->num_peers; i++) {
+                    WifiPeerInfo peer;
+                    peer.peer_info = *l_peer_info_stats_ptr;
+                    if (l_peer_info_stats_ptr->num_rate > 0) {
+                        /* Copy the rate stats */
+                        peer.rate_stats.assign(
+                            l_peer_info_stats_ptr->rate_stats,
+                            l_peer_info_stats_ptr->rate_stats +
+                                l_peer_info_stats_ptr->num_rate);
+                    }
+                    peer.peer_info.num_rate = 0;
+                    link_stats_ptr->peers.push_back(peer);
+                    l_peer_info_stats_ptr =
+                        (wifi_peer_info*)((u8*)l_peer_info_stats_ptr +
+                                          sizeof(wifi_peer_info) +
+                                          (sizeof(wifi_rate_stat) *
+                                           l_peer_info_stats_ptr->num_rate));
+                }
                 link_stats_ptr->iface.num_peers = 0;
             } else {
                 LOG(ERROR) << "Invalid iface stats in link layer stats";
diff --git a/wifi/1.5/default/wifi_legacy_hal.h b/wifi/1.5/default/wifi_legacy_hal.h
index 2372535..8ebc66a 100644
--- a/wifi/1.5/default/wifi_legacy_hal.h
+++ b/wifi/1.5/default/wifi_legacy_hal.h
@@ -340,9 +340,15 @@
     std::vector<wifi_channel_stat> channel_stats;
 };
 
+struct WifiPeerInfo {
+    wifi_peer_info peer_info;
+    std::vector<wifi_rate_stat> rate_stats;
+};
+
 struct LinkLayerStats {
     wifi_iface_stat iface;
     std::vector<LinkLayerRadioStats> radios;
+    std::vector<WifiPeerInfo> peers;
 };
 #pragma GCC diagnostic pop
 
diff --git a/wifi/1.5/types.hal b/wifi/1.5/types.hal
index e1c0d32..0543004 100644
--- a/wifi/1.5/types.hal
+++ b/wifi/1.5/types.hal
@@ -26,6 +26,7 @@
 import @1.3::StaLinkLayerRadioStats;
 import @1.0::WifiChannelInMhz;
 import @1.0::WifiChannelWidthInMhz;
+import @1.4::WifiRateInfo;
 
 /**
  * Wifi bands defined in 80211 spec.
@@ -162,6 +163,54 @@
 };
 
 /**
+ * Per rate statistics.  The rate is characterized by the combination of preamble, number of spatial
+ * streams, transmission bandwidth, and modulation and coding scheme (MCS).
+ */
+struct StaRateStat{
+    /**
+     * Wifi rate information: preamble, number of spatial streams, bandwidth, MCS, etc.
+     */
+    WifiRateInfo rateInfo;
+    /**
+     * Number of successfully transmitted data packets (ACK received)
+     */
+    uint32_t txMpdu;
+    /**
+     * Number of received data packets
+     */
+    uint32_t rxMpdu;
+    /**
+     * Number of data packet losses (no ACK)
+     */
+    uint32_t mpduLost;
+    /**
+     * Number of data packet retries
+     */
+    uint32_t retries;
+};
+
+/**
+ * Per peer statistics.  The types of peer include the Access Point (AP), the Tunneled Direct Link
+ * Setup (TDLS), the Group Owner (GO), the Neighbor Awareness Networking (NAN), etc.
+ */
+struct StaPeerInfo {
+    /**
+     * Station count: The total number of stations currently associated with the peer.
+     */
+    uint16_t staCount;
+    /**
+     * Channel utilization: The percentage of time (normalized to 255, i.e., x% corresponds to
+     * (int) x * 255 / 100) that the medium is sensed as busy measured by either physical or
+     * virtual carrier sense (CS) mechanism.
+     */
+    uint16_t chanUtil;
+    /**
+     * Per rate statistics
+     */
+    vec<StaRateStat> rateStats;
+};
+
+/**
  * Iface statistics for the current connection.
  */
 struct StaLinkLayerIfaceStats {
@@ -197,6 +246,11 @@
      * WME Voice (VO) Access Category (AC) contention time statistics.
      */
     StaLinkLayerIfaceContentionTimeStats wmeVoContentionTimeStats;
+
+    /**
+     * Per peer statistics.
+     */
+    vec<StaPeerInfo> peers;
 };
 
 /**
diff --git a/wifi/supplicant/1.4/Android.bp b/wifi/supplicant/1.4/Android.bp
index b486687..c988fdb 100644
--- a/wifi/supplicant/1.4/Android.bp
+++ b/wifi/supplicant/1.4/Android.bp
@@ -16,6 +16,7 @@
         "types.hal",
         "ISupplicant.hal",
         "ISupplicantP2pIface.hal",
+        "ISupplicantP2pIfaceCallback.hal",
         "ISupplicantStaIface.hal",
         "ISupplicantStaNetwork.hal",
         "ISupplicantStaNetworkCallback.hal",
diff --git a/wifi/supplicant/1.4/ISupplicantP2pIface.hal b/wifi/supplicant/1.4/ISupplicantP2pIface.hal
index 65c761d..28846de 100644
--- a/wifi/supplicant/1.4/ISupplicantP2pIface.hal
+++ b/wifi/supplicant/1.4/ISupplicantP2pIface.hal
@@ -17,6 +17,7 @@
 package android.hardware.wifi.supplicant@1.4;
 
 import @1.2::ISupplicantP2pIface;
+import ISupplicantP2pIfaceCallback;
 
 /**
  * Interface exposed by the supplicant for each P2P mode network
@@ -48,4 +49,36 @@
      * @return enabled true if set, false otherwise.
      */
     getEdmg() generates (SupplicantStatus status, bool enabled);
+
+    /**
+     * Register for callbacks from this interface.
+     *
+     * These callbacks are invoked for events that are specific to this interface.
+     * Registration of multiple callback objects is supported. These objects must
+     * be automatically deleted when the corresponding client process is dead or
+     * if this interface is removed.
+     *
+     * @param callback An instance of the |ISupplicantP2pIfaceCallback| HIDL
+     *        interface object.
+     * @return status Status of the operation.
+     *         Possible status codes:
+     *         |SupplicantStatusCode.SUCCESS|,
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_IFACE_INVALID|
+     */
+    registerCallback_1_4(ISupplicantP2pIfaceCallback callback)
+        generates (SupplicantStatus status);
+
+    /*
+     * Set Wifi Display R2 device info.
+     *
+     * @param info WFD R2 device info as described in section 5.1.12 of WFD technical
+     *        specification v2.1.
+     * @return status Status of the operation.
+     *         Possible status codes:
+     *         |SupplicantStatusCode.SUCCESS|,
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_IFACE_INVALID|
+     */
+    setWfdR2DeviceInfo(uint8_t[4] info) generates (SupplicantStatus status);
 };
diff --git a/wifi/supplicant/1.4/ISupplicantP2pIfaceCallback.hal b/wifi/supplicant/1.4/ISupplicantP2pIfaceCallback.hal
new file mode 100644
index 0000000..a091274
--- /dev/null
+++ b/wifi/supplicant/1.4/ISupplicantP2pIfaceCallback.hal
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2021 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.hardware.wifi.supplicant@1.4;
+
+import @1.0::ISupplicantP2pIfaceCallback;
+import @1.0::MacAddress;
+import @1.0::WpsConfigMethods;
+import @1.0::P2pGroupCapabilityMask;
+
+/**
+ * Callback Interface exposed by the supplicant service
+ * for each P2P mode interface (ISupplicantP2pIface).
+ *
+ * Clients need to host an instance of this HIDL interface object and
+ * pass a reference of the object to the supplicant via the
+ * corresponding |ISupplicantP2pIface.registerCallback| method.
+ */
+interface ISupplicantP2pIfaceCallback extends @1.0::ISupplicantP2pIfaceCallback {
+    /**
+     * Used to indicate that a P2P Wi-Fi Display R2 device has been found. Refer to
+     * Wi-Fi Display Technical Specification Version 2.0.
+     *
+     * @param srcAddress MAC address of the device found. This must either
+     *        be the P2P device address for a peer which is not in a group,
+     *        or the P2P interface address for a peer which is a Group Owner.
+     * @param p2pDeviceAddress P2P device address.
+     * @param primaryDeviceType Type of device. Refer to section B.1 of Wifi P2P
+     *        Technical specification v1.2.
+     * @param deviceName Name of the device.
+     * @param configMethods Mask of WPS configuration methods supported by the
+     *        device.
+     * @param deviceCapabilities Refer to section 4.1.4 of Wifi P2P Technical
+     *        specification v1.2.
+     * @param groupCapabilites Refer to section 4.1.4 of Wifi P2P Technical
+     *        specification v1.2.
+     * @param wfdDeviceInfo WFD device info as described in section 5.1.2 of WFD
+     *        technical specification v1.0.0.
+     * @param wfdR2DeviceInfo WFD R2 device info as described in section 5.1.12 of WFD
+     *        technical specification v2.1.
+     */
+    oneway onR2DeviceFound(
+        MacAddress srcAddress, MacAddress p2pDeviceAddress,
+        uint8_t[8] primaryDeviceType, string deviceName,
+        bitfield<WpsConfigMethods> configMethods, uint8_t deviceCapabilities,
+        bitfield<P2pGroupCapabilityMask> groupCapabilities, uint8_t[6] wfdDeviceInfo,
+        uint8_t[2] wfdR2DeviceInfo);
+};
diff --git a/wifi/supplicant/1.4/types.hal b/wifi/supplicant/1.4/types.hal
index c39de6e..b72eb42 100644
--- a/wifi/supplicant/1.4/types.hal
+++ b/wifi/supplicant/1.4/types.hal
@@ -107,6 +107,10 @@
      * WPA3 SAE Public-Key.
      */
     SAE_PK = 1 << 2,
+    /**
+     * Wi-Fi Display R2
+     */
+    WFD_R2 = 1 << 3,
 };
 
 /**
diff --git a/wifi/supplicant/1.4/vts/functional/supplicant_p2p_iface_hidl_test.cpp b/wifi/supplicant/1.4/vts/functional/supplicant_p2p_iface_hidl_test.cpp
index 9185279..4427c390 100644
--- a/wifi/supplicant/1.4/vts/functional/supplicant_p2p_iface_hidl_test.cpp
+++ b/wifi/supplicant/1.4/vts/functional/supplicant_p2p_iface_hidl_test.cpp
@@ -28,16 +28,23 @@
 #include "supplicant_hidl_test_utils_1_4.h"
 
 using ::android::sp;
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
 using ::android::hardware::Void;
 using ::android::hardware::wifi::supplicant::V1_0::SupplicantStatus;
 using ::android::hardware::wifi::supplicant::V1_0::SupplicantStatusCode;
 using ::android::hardware::wifi::supplicant::V1_4::ISupplicantP2pIface;
+using ::android::hardware::wifi::supplicant::V1_4::ISupplicantP2pIfaceCallback;
 
 using SupplicantStatusV1_4 =
     ::android::hardware::wifi::supplicant::V1_4::SupplicantStatus;
 using SupplicantStatusCodeV1_4 =
     ::android::hardware::wifi::supplicant::V1_4::SupplicantStatusCode;
 
+constexpr uint8_t kTestWfdR2DeviceInfo[] = {[0 ... 3] = 0x01};
+
 class SupplicantP2pIfaceHidlTest : public SupplicantHidlTestBaseV1_4 {
    public:
     virtual void SetUp() override {
@@ -51,6 +58,100 @@
     sp<ISupplicantP2pIface> p2p_iface_;
 };
 
+class IfaceCallback : public ISupplicantP2pIfaceCallback {
+    Return<void> onNetworkAdded(uint32_t /* id */) override { return Void(); }
+    Return<void> onNetworkRemoved(uint32_t /* id */) override { return Void(); }
+    Return<void> onDeviceFound(
+        const hidl_array<uint8_t, 6>& /* srcAddress */,
+        const hidl_array<uint8_t, 6>& /* p2pDeviceAddress */,
+        const hidl_array<uint8_t, 8>& /* primaryDeviceType */,
+        const hidl_string& /* deviceName */, uint16_t /* configMethods */,
+        uint8_t /* deviceCapabilities */, uint32_t /* groupCapabilities */,
+        const hidl_array<uint8_t, 6>& /* wfdDeviceInfo */) override {
+        return Void();
+    }
+    Return<void> onDeviceLost(
+        const hidl_array<uint8_t, 6>& /* p2pDeviceAddress */) override {
+        return Void();
+    }
+    Return<void> onFindStopped() override { return Void(); }
+    Return<void> onGoNegotiationRequest(
+        const hidl_array<uint8_t, 6>& /* srcAddress */,
+        ISupplicantP2pIfaceCallback::WpsDevPasswordId /* passwordId */)
+        override {
+        return Void();
+    }
+    Return<void> onGoNegotiationCompleted(
+        ISupplicantP2pIfaceCallback::P2pStatusCode /* status */) override {
+        return Void();
+    }
+    Return<void> onGroupFormationSuccess() override { return Void(); }
+    Return<void> onGroupFormationFailure(
+        const hidl_string& /* failureReason */) override {
+        return Void();
+    }
+    Return<void> onGroupStarted(
+        const hidl_string& /* groupIfname */, bool /* isGo */,
+        const hidl_vec<uint8_t>& /* ssid */, uint32_t /* frequency */,
+        const hidl_array<uint8_t, 32>& /* psk */,
+        const hidl_string& /* passphrase */,
+        const hidl_array<uint8_t, 6>& /* goDeviceAddress */,
+        bool /* isPersistent */) override {
+        return Void();
+    }
+    Return<void> onGroupRemoved(const hidl_string& /* groupIfname */,
+                                bool /* isGo */) override {
+        return Void();
+    }
+    Return<void> onInvitationReceived(
+        const hidl_array<uint8_t, 6>& /* srcAddress */,
+        const hidl_array<uint8_t, 6>& /* goDeviceAddress */,
+        const hidl_array<uint8_t, 6>& /* bssid */,
+        uint32_t /* persistentNetworkId */,
+        uint32_t /* operatingFrequency */) override {
+        return Void();
+    }
+    Return<void> onInvitationResult(
+        const hidl_array<uint8_t, 6>& /* bssid */,
+        ISupplicantP2pIfaceCallback::P2pStatusCode /* status */) override {
+        return Void();
+    }
+    Return<void> onProvisionDiscoveryCompleted(
+        const hidl_array<uint8_t, 6>& /* p2pDeviceAddress */,
+        bool /* isRequest */,
+        ISupplicantP2pIfaceCallback::P2pProvDiscStatusCode /* status */,
+        uint16_t /* configMethods */,
+        const hidl_string& /* generatedPin */) override {
+        return Void();
+    }
+    Return<void> onServiceDiscoveryResponse(
+        const hidl_array<uint8_t, 6>& /* srcAddress */,
+        uint16_t /* updateIndicator */,
+        const hidl_vec<uint8_t>& /* tlvs */) override {
+        return Void();
+    }
+    Return<void> onStaAuthorized(
+        const hidl_array<uint8_t, 6>& /* srcAddress */,
+        const hidl_array<uint8_t, 6>& /* p2pDeviceAddress */) override {
+        return Void();
+    }
+    Return<void> onStaDeauthorized(
+        const hidl_array<uint8_t, 6>& /* srcAddress */,
+        const hidl_array<uint8_t, 6>& /* p2pDeviceAddress */) override {
+        return Void();
+    }
+    Return<void> onR2DeviceFound(
+        const hidl_array<uint8_t, 6>& /* srcAddress */,
+        const hidl_array<uint8_t, 6>& /* p2pDeviceAddress */,
+        const hidl_array<uint8_t, 8>& /* primaryDeviceType */,
+        const hidl_string& /* deviceName */, uint16_t /* configMethods */,
+        uint8_t /* deviceCapabilities */, uint32_t /* groupCapabilities */,
+        const hidl_array<uint8_t, 6>& /* wfdDeviceInfo */,
+        const hidl_array<uint8_t, 2>& /* wfdR2DeviceInfo */) override {
+        return Void();
+    }
+};
+
 /*
  * SetGetEdmg
  */
@@ -71,6 +172,26 @@
     });
 }
 
+/*
+ * RegisterCallback_1_4
+ */
+TEST_P(SupplicantP2pIfaceHidlTest, RegisterCallback_1_4) {
+    p2p_iface_->registerCallback_1_4(
+        new IfaceCallback(), [](const SupplicantStatusV1_4& status) {
+            EXPECT_EQ(SupplicantStatusCodeV1_4::SUCCESS, status.code);
+        });
+}
+
+/*
+ * SetWfdR2DeviceInfo
+ */
+TEST_P(SupplicantP2pIfaceHidlTest, SetWfdR2DeviceInfo) {
+    p2p_iface_->setWfdR2DeviceInfo(
+        kTestWfdR2DeviceInfo, [&](const SupplicantStatusV1_4& status) {
+            EXPECT_EQ(SupplicantStatusCodeV1_4::SUCCESS, status.code);
+        });
+}
+
 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(SupplicantP2pIfaceHidlTest);
 INSTANTIATE_TEST_CASE_P(
     PerInstance, SupplicantP2pIfaceHidlTest,