Merge "Update source for Rust 1.78.0" into main
diff --git a/Android.bp b/Android.bp
index 9a95b6f..907f567 100644
--- a/Android.bp
+++ b/Android.bp
@@ -73,11 +73,13 @@
"libpica",
"libprotobuf",
"libprotobuf_json_mapping",
+ "librand",
"libregex",
"libserde",
"libserde_json",
"libthiserror",
"libtokio",
+ "libtokio_stream",
"libtungstenite",
"liblazy_static",
"liblog_rust",
@@ -377,7 +379,7 @@
"libnetsim_common",
"libnetsim_proto",
"libprotobuf",
- "libtracing"
+ "libtracing",
],
}
diff --git a/proto/Android.bp b/proto/Android.bp
index 294118a..e23ea9c 100644
--- a/proto/Android.bp
+++ b/proto/Android.bp
@@ -113,6 +113,7 @@
"netsim/model.proto",
"netsim/packet_streamer.proto",
"netsim/startup.proto",
+ "netsim/stats.proto",
":rootcanal-protos",
],
}
diff --git a/proto/netsim/stats.proto b/proto/netsim/stats.proto
index 2d372cc..fd8b049 100644
--- a/proto/netsim/stats.proto
+++ b/proto/netsim/stats.proto
@@ -23,6 +23,7 @@
PARSE_ERROR = 1;
UNSUPPORTED = 2;
OTHERS = 3;
+ DELAYED = 4;
}
optional Reason reason = 1;
optional string description = 2;
@@ -56,6 +57,20 @@
repeated InvalidPacket invalid_packets = 8;
}
+// Frontend statistics for a netsim session representing count of API calls
+message NetsimFrontendStats {
+ optional uint32 get_version = 1;
+ optional uint32 create_device = 2;
+ optional uint32 delete_chip = 3;
+ optional uint32 patch_device = 4;
+ optional uint32 reset = 5;
+ optional uint32 list_device = 6;
+ optional uint32 subscribe_device = 7;
+ optional uint32 patch_capture = 8;
+ optional uint32 list_capture = 9;
+ optional uint32 get_capture = 10;
+}
+
// Statistics for a netsim session.
message NetsimStats {
// The length of the session in seconds
@@ -68,4 +83,6 @@
repeated NetsimRadioStats radio_stats = 4;
// The version of netsim daemon
optional string version = 5;
+ // Frontend API statistics
+ optional NetsimFrontendStats frontend_stats = 6;
}
\ No newline at end of file
diff --git a/rust/cli/Cargo.toml b/rust/cli/Cargo.toml
index 82b7916..1fa1a3a 100644
--- a/rust/cli/Cargo.toml
+++ b/rust/cli/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "netsim-cli"
-version = "0.3.7"
+version = "0.3.8"
edition = "2021"
build = "build.rs"
diff --git a/rust/common/Cargo.toml b/rust/common/Cargo.toml
index f3438bf..b118761 100644
--- a/rust/common/Cargo.toml
+++ b/rust/common/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "netsim-common"
-version = "0.3.7"
+version = "0.3.8"
edition = "2021"
[lib]
diff --git a/rust/daemon/Cargo.toml b/rust/daemon/Cargo.toml
index 1fcd9a8..1aefc7c 100644
--- a/rust/daemon/Cargo.toml
+++ b/rust/daemon/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "netsim-daemon"
-version = "0.3.7"
+version = "0.3.8"
edition = "2021"
build = "build.rs"
@@ -21,6 +21,8 @@
protobuf = "3.2.0"
protobuf-json-mapping = "3.2.0"
regex = "1.6.0"
+tokio = { verison = "1.32.0", features = ["fs", "io-util", "macros", "net", "rt"] }
+tokio-stream = { version = "0.1.14", features = ["sync"] }
thiserror = { version = ">=1.0.40"}
tungstenite = { version = ">=0.19.0", default-features = false }
lazy_static = "1.4.0"
diff --git a/rust/daemon/src/echip/bluetooth.rs b/rust/daemon/src/echip/bluetooth.rs
index 71d4611..65a9a43 100644
--- a/rust/daemon/src/echip/bluetooth.rs
+++ b/rust/daemon/src/echip/bluetooth.rs
@@ -199,6 +199,35 @@
ffi_bluetooth::bluetooth_stop();
}
+/// Report Invalid Packet
+pub fn report_invalid_packet(
+ rootcanal_id: RootcanalIdentifier,
+ reason: InvalidPacketReason,
+ description: String,
+ packet: Vec<u8>,
+) {
+ // TODO(b/330726276): spawn task on tokio once context is provided from rust_main
+ let _ = std::thread::Builder::new().name("report_invalid_packet".to_string()).spawn(move || {
+ match BLUETOOTH_INVALID_PACKETS.lock().unwrap().get_mut(&rootcanal_id) {
+ Some(v) => {
+ // Remove the earliest reported packet if length greater than 5
+ if v.len() >= 5 {
+ v.remove(0);
+ }
+ // append error packet
+ let mut invalid_packet = InvalidPacket::new();
+ invalid_packet.set_reason(reason);
+ invalid_packet.set_description(description.clone());
+ invalid_packet.set_packet(packet.clone());
+ v.push(invalid_packet);
+ // Log the report
+ info!("Invalid Packet for rootcanal_id: {rootcanal_id}, reason: {reason:?}, description: {description:?}, packet: {packet:?}");
+ }
+ None => error!("Bluetooth EmulatedChip not created for rootcanal_id: {rootcanal_id}"),
+ }
+ });
+}
+
/// (Called by C++) Report Invalid Packet
pub fn report_invalid_packet_cxx(
rootcanal_id: RootcanalIdentifier,
@@ -206,23 +235,10 @@
description: &CxxString,
packet: &CxxVector<u8>,
) {
- match BLUETOOTH_INVALID_PACKETS.lock().unwrap().get_mut(&rootcanal_id) {
- Some(v) => {
- // Remove the earliest reported packet if length greater than 5
- if v.len() >= 5 {
- v.remove(0);
- }
- // append error packet
- let mut invalid_packet = InvalidPacket::new();
- invalid_packet.set_reason(
- InvalidPacketReason::from_i32(reason).unwrap_or(InvalidPacketReason::UNKNOWN),
- );
- invalid_packet.set_description(description.to_string());
- invalid_packet.set_packet(packet.as_slice().to_vec());
- v.push(invalid_packet);
- // Log the report
- info!("Reported Invalid Packet for Bluetooth EmulatedChip with rootcanal_id: {rootcanal_id}, reason:{reason}, description: {description:?}, packet: {packet:?}");
- }
- None => error!("Bluetooth EmulatedChip not created for rootcanal_id: {rootcanal_id}"),
- }
+ report_invalid_packet(
+ rootcanal_id,
+ InvalidPacketReason::from_i32(reason).unwrap_or(InvalidPacketReason::UNKNOWN),
+ description.to_string(),
+ packet.as_slice().to_vec(),
+ );
}
diff --git a/rust/daemon/src/echip/mod.rs b/rust/daemon/src/echip/mod.rs
index 222bc63..4e8f955 100644
--- a/rust/daemon/src/echip/mod.rs
+++ b/rust/daemon/src/echip/mod.rs
@@ -27,4 +27,4 @@
pub use crate::echip::emulated_chip::EmulatedChip;
pub use crate::echip::emulated_chip::SharedEmulatedChip;
pub use crate::echip::emulated_chip::{get, new, remove};
-pub use crate::echip::packet::{handle_request, handle_request_cxx, handle_response};
+pub use crate::echip::packet::{handle_request, handle_request_cxx, handle_response_cxx};
diff --git a/rust/daemon/src/echip/packet.rs b/rust/daemon/src/echip/packet.rs
index 16db730..7954c85 100644
--- a/rust/daemon/src/echip/packet.rs
+++ b/rust/daemon/src/echip/packet.rs
@@ -101,7 +101,7 @@
}
/// Handle requests from gRPC transport in C++.
-pub fn handle_response(chip_id: ChipIdentifier, packet: &cxx::CxxVector<u8>, packet_type: u8) {
+pub fn handle_response_cxx(chip_id: ChipIdentifier, packet: &cxx::CxxVector<u8>, packet_type: u8) {
// TODO(b/314840701):
// 1. Per EChip Struct should contain private field of channel & facade_id
// 2. Lookup from ECHIPS with given chip_id
@@ -123,34 +123,12 @@
}
// Handle response from rust libraries
-#[cfg(feature = "cuttlefish")]
-pub fn handle_response_rust(chip_id: ChipIdentifier, packet: Bytes) {
+pub fn handle_response(chip_id: ChipIdentifier, packet: &Bytes) {
let packet_type = PacketType::HCI_PACKET_UNSPECIFIED.value() as u8;
- captures_handler::handle_packet_response(chip_id, &packet, packet_type.into());
+ captures_handler::handle_packet_response(chip_id, packet, packet_type.into());
let result = if let Some(transport) = MANAGER.transports.read().unwrap().get(&chip_id) {
- transport.send(ResponsePacket { packet, packet_type })
- } else {
- warn!("handle_response: chip {chip_id} not found");
- Ok(())
- };
- // transports lock is now released
- if let Err(e) = result {
- warn!("handle_response: error {:?}", e);
- unregister_transport(chip_id);
- }
-}
-
-// Send HwsimCmd packets to guest OS.
-pub fn hwsim_cmd_response(chip_id: u32, packet: &[u8]) {
- let packet_type = PacketType::HCI_PACKET_UNSPECIFIED;
- captures_handler::handle_packet_response(chip_id, packet, packet_type as u32);
-
- let result = if let Some(transport) = MANAGER.transports.read().unwrap().get(&chip_id) {
- transport.send(ResponsePacket {
- packet: Bytes::from(packet.to_vec()),
- packet_type: packet_type as u8,
- })
+ transport.send(ResponsePacket { packet: packet.clone(), packet_type })
} else {
warn!("handle_response: chip {chip_id} not found");
Ok(())
diff --git a/rust/daemon/src/echip/uwb.rs b/rust/daemon/src/echip/uwb.rs
index f7ce279..75d49c7 100644
--- a/rust/daemon/src/echip/uwb.rs
+++ b/rust/daemon/src/echip/uwb.rs
@@ -13,7 +13,7 @@
// limitations under the License.
use bytes::Bytes;
-use futures::{channel::mpsc::UnboundedSender, sink::SinkExt};
+use futures::{channel::mpsc::UnboundedSender, sink::SinkExt, StreamExt};
use lazy_static::lazy_static;
use pica::{Handle, Pica};
@@ -22,7 +22,7 @@
use netsim_proto::stats::{netsim_radio_stats, NetsimRadioStats as ProtoRadioStats};
use crate::devices::chip::ChipIdentifier;
-use crate::echip::packet::handle_response_rust;
+use crate::echip::packet::handle_response;
use crate::uwb::ranging_estimator::{SharedState, UwbRangingEstimator};
use std::sync::{Arc, Mutex};
@@ -53,7 +53,7 @@
uci_stream_writer: UnboundedSender<Vec<u8>>,
state: bool,
tx_count: i32,
- rx_count: i32, // TODO(b/330788870): Increment rx_count after handle_response_rust
+ rx_count: i32, // TODO(b/330788870): Increment rx_count after handle_response
}
impl EmulatedChip for Uwb {
@@ -133,13 +133,13 @@
rx_count: 0,
};
- // Thread for obtaining packet from pica and invoking handle_response_rust
- let _ =
- thread::Builder::new().name(format!("uwb_packet_response_{chip_id}")).spawn(move || {
- for packet in futures::executor::block_on_stream(uci_sink_receiver) {
- handle_response_rust(chip_id, packet.into());
- }
- });
+ // Spawn a future for obtaining packet from pica and invoking handle_response_rust
+ PICA_RUNTIME.spawn(async move {
+ let mut uci_sink_receiver = uci_sink_receiver;
+ while let Some(packet) = uci_sink_receiver.next().await {
+ handle_response(chip_id, &Bytes::from(packet));
+ }
+ });
Arc::new(Box::new(echip))
}
diff --git a/rust/daemon/src/echip/wifi.rs b/rust/daemon/src/echip/wifi.rs
index 7448c75..6df26c1 100644
--- a/rust/daemon/src/echip/wifi.rs
+++ b/rust/daemon/src/echip/wifi.rs
@@ -13,7 +13,7 @@
// limitations under the License.
use crate::devices::chip::ChipIdentifier;
-use crate::echip::{packet::hwsim_cmd_response, EmulatedChip, SharedEmulatedChip};
+use crate::echip::{packet::handle_response, EmulatedChip, SharedEmulatedChip};
use crate::ffi::ffi_wifi;
use crate::wifi::medium::Medium;
use bytes::Bytes;
@@ -23,6 +23,7 @@
use netsim_proto::model::Chip as ProtoChip;
use netsim_proto::stats::{netsim_radio_stats, NetsimRadioStats as ProtoRadioStats};
use protobuf::{Message, MessageField};
+use std::sync::atomic::Ordering;
use std::sync::Arc;
use std::thread;
use std::time::{Duration, Instant};
@@ -48,7 +49,7 @@
let (request_sender, rx) = std::sync::mpsc::channel::<(u32, Bytes)>();
thread::spawn(move || {
- const POLL_INTERVAL: Duration = Duration::from_micros(10);
+ const POLL_INTERVAL: Duration = Duration::from_millis(1);
let mut next_instant = Instant::now() + POLL_INTERVAL;
loop {
@@ -65,6 +66,7 @@
|| !WIFI_MANAGER.medium.process(chip_id, &packet)
{
ffi_wifi::handle_wifi_request(chip_id, &packet.to_vec());
+ ffi_wifi::libslirp_main_loop_wait();
}
}
_ => {
@@ -76,14 +78,11 @@
});
let (response_sender, rx) = std::sync::mpsc::channel::<Bytes>();
- thread::spawn(move || {
- loop {
- // rx.recv() should either returns packets or timeout after 1 second.
- let packet = rx.recv().unwrap();
- WIFI_MANAGER.medium.process_response(&packet);
- }
+ thread::spawn(move || loop {
+ let packet = rx.recv().unwrap();
+ WIFI_MANAGER.medium.process_response(&packet);
});
- WifiManager { medium: Medium::new(hwsim_cmd_response), request_sender, response_sender }
+ WifiManager { medium: Medium::new(handle_response), request_sender, response_sender }
}
}
@@ -104,9 +103,9 @@
fn get(&self) -> ProtoChip {
let mut chip_proto = ProtoChip::new();
if let Some(client) = WIFI_MANAGER.medium.get(self.chip_id) {
- chip_proto.mut_wifi().state = Some(client.enabled);
- chip_proto.mut_wifi().tx_count = client.tx_count as i32;
- chip_proto.mut_wifi().rx_count = client.rx_count as i32;
+ chip_proto.mut_wifi().state = Some(client.enabled.load(Ordering::Relaxed));
+ chip_proto.mut_wifi().tx_count = client.tx_count.load(Ordering::Relaxed) as i32;
+ chip_proto.mut_wifi().rx_count = client.rx_count.load(Ordering::Relaxed) as i32;
}
chip_proto
}
diff --git a/rust/daemon/src/ffi.rs b/rust/daemon/src/ffi.rs
index 24dcc5c..c9edd2c 100644
--- a/rust/daemon/src/ffi.rs
+++ b/rust/daemon/src/ffi.rs
@@ -28,7 +28,7 @@
add_chip_cxx, get_distance_cxx, handle_device_cxx, remove_chip_cxx, AddChipResultCxx,
};
use crate::echip::wifi::handle_wifi_response;
-use crate::echip::{bluetooth::report_invalid_packet_cxx, handle_request_cxx, handle_response};
+use crate::echip::{bluetooth::report_invalid_packet_cxx, handle_request_cxx, handle_response_cxx};
use crate::ranging::*;
use crate::transport::grpc::{register_grpc_transport, unregister_grpc_transport};
use crate::version::*;
@@ -41,7 +41,7 @@
fn handle_request_cxx(chip_id: u32, packet: &CxxVector<u8>, packet_type: u8);
#[cxx_name = HandleResponse]
- fn handle_response(chip_id: u32, packet: &CxxVector<u8>, packet_type: u8);
+ fn handle_response_cxx(chip_id: u32, packet: &CxxVector<u8>, packet_type: u8);
}
}
diff --git a/rust/daemon/src/uwb/mod.rs b/rust/daemon/src/uwb/mod.rs
index 7c1a6b2..5787f6e 100644
--- a/rust/daemon/src/uwb/mod.rs
+++ b/rust/daemon/src/uwb/mod.rs
@@ -12,4 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+// TODO(b/325298096): Use RangingDataSet in ranging_estimator
+#[allow(dead_code)]
+mod ranging_data;
pub(crate) mod ranging_estimator;
diff --git a/rust/daemon/src/uwb/ranging_data.rs b/rust/daemon/src/uwb/ranging_data.rs
new file mode 100644
index 0000000..c442d45
--- /dev/null
+++ b/rust/daemon/src/uwb/ranging_data.rs
@@ -0,0 +1,117 @@
+// Copyright 2024 Google LLC
+//
+// 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
+//
+// https://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.
+
+use rand::{prelude::SliceRandom, rngs::ThreadRng, thread_rng};
+
+use std::collections::BTreeMap;
+
+type TrueDistance = f64; // meters
+type EstimatedDistance = f64; // meters
+
+/// The data is organized as a `BTreeMap` for efficient lookup and interpolation.
+struct RangingDataSet {
+ /// Stores ranging data in the form of (true distance, [estimated distances]) pairs.
+ /// The map keys are true distances in u16 centimeters.
+ data: BTreeMap<u16, Vec<EstimatedDistance>>,
+}
+
+impl RangingDataSet {
+ /// Creates a new `RangingDataSet` instance by loading ranging data.
+ /// Data is in a format where each entry is a tuple of
+ /// (true distance, estimated distance), typically representing samples from a
+ /// ranging sensor.
+ pub fn new(ranging_data: Option<Vec<(TrueDistance, EstimatedDistance)>>) -> Self {
+ // Use sample_ranging_data.csv if ranging_data is not provided.
+ let sample_ranging_data: Vec<(TrueDistance, EstimatedDistance)> =
+ ranging_data.unwrap_or(include!("sample_ranging_data.csv"));
+
+ // Process the sample_raning_data into BTreeMap
+ let mut data: BTreeMap<u16, Vec<EstimatedDistance>> = BTreeMap::new();
+ for (true_distance, estimated_distance) in sample_ranging_data {
+ // Convert true_distance into u16 centimeters
+ data.entry((true_distance * 100.0).round() as u16)
+ .or_default()
+ .push(estimated_distance);
+ }
+ RangingDataSet { data }
+ }
+
+ /// Samples an estimated distance for the given true distance.
+ ///
+ /// # Arguments
+ ///
+ /// * `distance` - The true distance for which an estimated distance is required.
+ /// * `option_rng` - An optional random number generator
+ /// (if not provided, a default one will be used)
+ ///
+ /// # Returns
+ ///
+ /// An estimated distance sampled from the dataset.
+ /// If the exact true distance is found in the dataset,
+ /// a random estimated distance is chosen from its associated values.
+ /// If the true distance falls between known values,
+ /// linear interpolation is used to estimate a distance.
+ /// If the true distance is outside the range of known values,
+ /// the distance itself is returned as the estimated distance.
+ pub fn sample(
+ &self,
+ distance: TrueDistance,
+ option_rng: Option<ThreadRng>,
+ ) -> EstimatedDistance {
+ // Generate a new ThreadRng if not provided
+ let mut rng = option_rng.unwrap_or(thread_rng());
+ // Convert TrueDistance into u16 centimeters.
+ let distance_u16 = (distance * 100.0).round() as u16;
+
+ // Random sampling if distance is an existing data key
+ if let Some(vec_estimated_distance) = self.data.get(&distance_u16) {
+ return *vec_estimated_distance.choose(&mut rng).unwrap();
+ }
+
+ // Linear Interpolation if provided TrueDistance lies in between data keys
+ let lower = self.data.range(..=&distance_u16).next_back();
+ let upper = self.data.range(&distance_u16..).next();
+ match (lower, upper) {
+ (Some((lower_key, lower_vals)), Some((upper_key, upper_vals))) => {
+ let x1 = *lower_key as f64 / 100.0;
+ let y1 = *lower_vals.choose(&mut rng).unwrap();
+ let x2 = *upper_key as f64 / 100.0;
+ let y2 = *upper_vals.choose(&mut rng).unwrap();
+ y1 + (distance - x1) * (y2 - y1) / (x2 - x1)
+ }
+ _ => distance,
+ }
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ fn sample_ranging_data_set() -> RangingDataSet {
+ let ranging_data = vec![(0.0, 0.2), (1.0, 0.9), (2.0, 1.9), (2.0, 2.1)];
+ RangingDataSet::new(Some(ranging_data))
+ }
+
+ #[test]
+ fn test_sample_ranging_data_set() {
+ let ranging_data_set = sample_ranging_data_set();
+ // Linear Interpolation
+ assert_eq!(ranging_data_set.sample(0.5, None), 0.55);
+ // Exact distance found in dataset
+ assert!([1.9, 2.1].contains(&ranging_data_set.sample(2.0, None)));
+ // Out of Range
+ assert_eq!(ranging_data_set.sample(3.0, None), 3.0);
+ }
+}
diff --git a/rust/daemon/src/uwb/sample_ranging_data.csv b/rust/daemon/src/uwb/sample_ranging_data.csv
new file mode 100644
index 0000000..c9a9fd9
--- /dev/null
+++ b/rust/daemon/src/uwb/sample_ranging_data.csv
@@ -0,0 +1,83 @@
+vec![
+ (0.5, 0.224999994),
+ (0.5, 0.1679999977),
+ (0.5, 0.2150000036),
+ (0.5, 0.201000005),
+ (0.5, 0.1959999949),
+ (1.0, 0.7450000048),
+ (1.0, 0.7450000048),
+ (1.0, 0.7829999924),
+ (1.0, 0.7450000048),
+ (1.5, 1.271000028),
+ (1.5, 1.340999961),
+ (1.5, 1.261000037),
+ (1.5, 1.274999976),
+ (1.5, 1.274999976),
+ (1.5, 1.312999964),
+ (1.5, 1.332000017),
+ (2.0, 1.866000056),
+ (2.0, 1.889999986),
+ (2.0, 1.866000056),
+ (2.0, 1.899000049),
+ (2.0, 1.894000053),
+ (2.0, 1.889999986),
+ (2.5, 2.302000046),
+ (2.5, 2.292999983),
+ (2.5, 2.279000044),
+ (2.5, 2.292999983),
+ (3.0, 2.832000017),
+ (3.0, 2.822999954),
+ (3.0, 2.809000015),
+ (3.0, 2.869999886),
+ (3.0, 2.828000069),
+ (3.0, 2.818000078),
+ (3.5, 3.40899992),
+ (3.5, 3.41899991),
+ (3.5, 3.40899992),
+ (3.5, 3.40899992),
+ (3.5, 3.404999971),
+ (3.5, 3.41899991),
+ (3.5, 3.41899991),
+ (3.5, 3.41899991),
+ (3.5, 3.40899992),
+ (4.0, 4.024000168),
+ (4.0, 3.990999937),
+ (4.0, 3.986000061),
+ (4.0, 4.0),
+ (4.0, 3.982000113),
+ (4.0, 3.996000051),
+ (4.0, 4.013999939),
+ (4.0, 3.996000051),
+ (4.0, 3.967999935),
+ (4.0, 3.990999937),
+ (4.5, 4.446000099),
+ (4.5, 4.451000214),
+ (4.5, 4.460000038),
+ (4.5, 4.418000221),
+ (4.5, 4.446000099),
+ (4.5, 4.436999798),
+ (4.5, 4.422999859),
+ (4.5, 4.451000214),
+ (4.5, 4.436999798),
+ (5.0, 4.934000015),
+ (5.0, 4.938000202),
+ (5.0, 4.938000202),
+ (5.0, 4.914999962),
+ (5.0, 4.94299984),
+ (5.0, 4.914999962),
+ (5.5, 5.426000118),
+ (5.5, 5.43599987),
+ (6.0, 6.392000198),
+ (6.0, 6.396999836),
+ (6.0, 6.388000011),
+ (6.0, 6.368999958),
+ (6.5, 6.899000168),
+ (6.5, 6.918000221),
+ (6.5, 6.889999866),
+ (6.5, 6.913000107),
+ (6.5, 6.903999805),
+ (6.5, 6.899000168),
+ (6.5, 6.885000229),
+ (6.5, 6.899000168),
+ (6.5, 6.913000107)
+]
diff --git a/rust/daemon/src/version.rs b/rust/daemon/src/version.rs
index af5816b..b8d679a 100644
--- a/rust/daemon/src/version.rs
+++ b/rust/daemon/src/version.rs
@@ -14,7 +14,7 @@
/// Version library.
-pub const VERSION: &str = "0.3.7";
+pub const VERSION: &str = "0.3.8";
pub fn get_version() -> String {
VERSION.to_owned()
diff --git a/rust/daemon/src/wifi/medium.rs b/rust/daemon/src/wifi/medium.rs
index aa8f4fe..256fc7c 100644
--- a/rust/daemon/src/wifi/medium.rs
+++ b/rust/daemon/src/wifi/medium.rs
@@ -17,11 +17,12 @@
use crate::wifi::frame::Frame;
use crate::wifi::hwsim_attr_set::HwsimAttrSet;
use anyhow::{anyhow, Context};
+use bytes::Bytes;
use log::{debug, info, warn};
use pdl_runtime::Packet;
use std::collections::{HashMap, HashSet};
-use std::sync::{Arc, Mutex};
-
+use std::sync::atomic::{AtomicBool, AtomicU32, Ordering};
+use std::sync::{Arc, RwLock};
const NLMSG_MIN_TYPE: u16 = 0x10;
// Default values for mac80211_hwsim.
const RX_RATE: u32 = 0;
@@ -59,29 +60,33 @@
#[derive(Clone)]
pub struct Client {
- pub enabled: bool,
- pub tx_count: u32,
- pub rx_count: u32,
+ pub enabled: Arc<AtomicBool>,
+ pub tx_count: Arc<AtomicU32>,
+ pub rx_count: Arc<AtomicU32>,
}
impl Client {
fn new() -> Self {
- Self { enabled: true, tx_count: 0, rx_count: 0 }
+ Self {
+ enabled: Arc::new(AtomicBool::new(true)),
+ tx_count: Arc::new(AtomicU32::new(0)),
+ rx_count: Arc::new(AtomicU32::new(0)),
+ }
}
}
pub struct Medium {
callback: HwsimCmdCallback,
// Ieee80211 source address
- stations: Mutex<HashMap<MacAddress, Arc<Station>>>,
- clients: Mutex<HashMap<u32, Client>>,
+ stations: RwLock<HashMap<MacAddress, Arc<Station>>>,
+ clients: RwLock<HashMap<u32, Client>>,
// BSSID. MAC address of the access point in WiFi Service.
hostapd_bssid: MacAddress,
// Simulate the re-transmission of frames sent to hostapd
ap_simulation: bool,
}
-type HwsimCmdCallback = fn(u32, &[u8]);
+type HwsimCmdCallback = fn(u32, &Bytes);
impl Medium {
pub fn new(callback: HwsimCmdCallback) -> Medium {
// Defined in external/qemu/android-qemu2-glue/emulation/WifiService.cpp
@@ -89,51 +94,51 @@
let bssid_bytes: [u8; 6] = [0x00, 0x13, 0x10, 0x85, 0xfe, 0x01];
Self {
callback,
- stations: Mutex::new(HashMap::new()),
- clients: Mutex::new(HashMap::new()),
+ stations: RwLock::new(HashMap::new()),
+ clients: RwLock::new(HashMap::new()),
hostapd_bssid: MacAddress::from(&bssid_bytes),
ap_simulation: true,
}
}
pub fn add(&self, client_id: u32) {
- let _ = self.clients.lock().unwrap().entry(client_id).or_insert_with(|| {
+ let _ = self.clients.write().unwrap().entry(client_id).or_insert_with(|| {
info!("Insert client {}", client_id);
Client::new()
});
}
pub fn remove(&self, client_id: u32) {
- self.stations.lock().unwrap().retain(|_, s| s.client_id != client_id);
- self.clients.lock().unwrap().remove(&client_id);
+ self.stations.write().unwrap().retain(|_, s| s.client_id != client_id);
+ self.clients.write().unwrap().remove(&client_id);
}
pub fn reset(&self, client_id: u32) {
- if let Some(client) = self.clients.lock().unwrap().get_mut(&client_id) {
- client.enabled = true;
- client.tx_count = 0;
- client.rx_count = 0;
+ if let Some(client) = self.clients.read().unwrap().get(&client_id) {
+ client.enabled.store(true, Ordering::Relaxed);
+ client.tx_count.store(0, Ordering::Relaxed);
+ client.rx_count.store(0, Ordering::Relaxed);
}
}
pub fn get(&self, client_id: u32) -> Option<Client> {
- self.clients.lock().unwrap().get(&client_id).map(|c| c.to_owned())
+ self.clients.read().unwrap().get(&client_id).map(|c| c.to_owned())
}
fn contains_client(&self, client_id: u32) -> bool {
- self.clients.lock().unwrap().contains_key(&client_id)
+ self.clients.read().unwrap().contains_key(&client_id)
}
fn stations(&self) -> impl Iterator<Item = Arc<Station>> {
- self.stations.lock().unwrap().clone().into_values()
+ self.stations.read().unwrap().clone().into_values()
}
fn contains_station(&self, addr: &MacAddress) -> bool {
- self.stations.lock().unwrap().contains_key(addr)
+ self.stations.read().unwrap().contains_key(addr)
}
fn get_station(&self, addr: &MacAddress) -> anyhow::Result<Arc<Station>> {
- self.stations.lock().unwrap().get(addr).context("get station").cloned()
+ self.stations.read().unwrap().get(addr).context("get station").cloned()
}
/// Process commands from the kernel's mac80211_hwsim subsystem.
@@ -148,7 +153,7 @@
///
/// * 802.11 multicast frames are re-broadcast to connected stations.
///
- pub fn process(&self, client_id: u32, packet: &[u8]) -> bool {
+ pub fn process(&self, client_id: u32, packet: &Bytes) -> bool {
self.process_internal(client_id, packet).unwrap_or_else(move |e| {
// TODO: add this error to the netsim_session_stats
warn!("error processing wifi {e}");
@@ -156,7 +161,7 @@
})
}
- fn process_internal(&self, client_id: u32, packet: &[u8]) -> anyhow::Result<bool> {
+ fn process_internal(&self, client_id: u32, packet: &Bytes) -> anyhow::Result<bool> {
let hwsim_msg = HwsimMsg::parse(packet)?;
// The virtio handler only accepts HWSIM_CMD_FRAME, HWSIM_CMD_TX_INFO_FRAME and HWSIM_CMD_REPORT_PMSR
@@ -186,7 +191,7 @@
// new networks. This block associates the new mac with the station.
let source = self
.stations
- .lock()
+ .write()
.unwrap()
.entry(src_addr)
.or_insert_with(|| {
@@ -213,17 +218,17 @@
/// Handle Wi-Fi MwsimMsg from libslirp and hostapd.
/// Send it to clients.
- pub fn process_response(&self, packet: &[u8]) {
+ pub fn process_response(&self, packet: &Bytes) {
if let Err(e) = self.send_response(packet) {
warn!("{}", e);
}
}
/// Determine the client id based on Ieee80211 destination and send to client.
- fn send_response(&self, packet: &[u8]) -> anyhow::Result<()> {
+ fn send_response(&self, packet: &Bytes) -> anyhow::Result<()> {
// When Wi-Fi P2P is disabled, send all packets from WifiService to all clients.
if crate::config::get_disable_wifi_p2p() {
- for client_id in self.clients.lock().unwrap().keys() {
+ for client_id in self.clients.read().unwrap().keys() {
(self.callback)(*client_id, packet);
}
return Ok(());
@@ -240,7 +245,7 @@
Ok(())
}
- fn send_frame_response(&self, packet: &[u8], hwsim_msg: &HwsimMsg) -> anyhow::Result<()> {
+ fn send_frame_response(&self, packet: &Bytes, hwsim_msg: &HwsimMsg) -> anyhow::Result<()> {
let frame = Frame::parse(hwsim_msg)?;
let dest_addr = frame.ieee80211.get_destination();
if let Ok(destination) = self.get_station(&dest_addr) {
@@ -258,7 +263,7 @@
/// Send frame from DS to STA.
fn send_from_ds_frame(
&self,
- packet: &[u8],
+ packet: &Bytes,
frame: &Frame,
destination: &Station,
) -> anyhow::Result<()> {
@@ -269,13 +274,13 @@
let hwsim_msg = self
.create_hwsim_msg(frame, &destination.hwsim_addr)
.context("Create HwsimMsg from WifiService")?;
- (self.callback)(destination.client_id, &hwsim_msg.to_vec());
+ (self.callback)(destination.client_id, &hwsim_msg.to_vec().into());
}
self.incr_rx(destination.client_id)?;
Ok(())
}
- fn send_tx_info_response(&self, packet: &[u8], hwsim_msg: &HwsimMsg) -> anyhow::Result<()> {
+ fn send_tx_info_response(&self, packet: &Bytes, hwsim_msg: &HwsimMsg) -> anyhow::Result<()> {
let attrs = HwsimAttrSet::parse(hwsim_msg.get_attributes()).context("HwsimAttrSet")?;
let hwsim_addr = attrs.transmitter.context("missing transmitter")?;
let client_ids = self
@@ -295,36 +300,49 @@
}
pub fn set_enabled(&self, client_id: u32, enabled: bool) {
- if let Some(client) = self.clients.lock().unwrap().get_mut(&client_id) {
- client.enabled = enabled;
+ if let Some(client) = self.clients.read().unwrap().get(&client_id) {
+ client.enabled.store(enabled, Ordering::Relaxed);
}
}
fn enabled(&self, client_id: u32) -> anyhow::Result<bool> {
Ok(self
.clients
- .lock()
+ .read()
.unwrap()
.get(&client_id)
.context(format!("client {client_id} is missing"))?
- .enabled)
+ .enabled
+ .load(Ordering::Relaxed))
}
/// Create tx info frame to station to ack HwsimMsg.
fn send_tx_info_frame(&self, frame: &Frame) -> anyhow::Result<()> {
let client_id = self.get_station(&frame.ieee80211.get_source())?.client_id;
let hwsim_msg_tx_info = build_tx_info(&frame.hwsim_msg).unwrap().to_vec();
- (self.callback)(client_id, &hwsim_msg_tx_info);
+ (self.callback)(client_id, &hwsim_msg_tx_info.into());
Ok(())
}
fn incr_tx(&self, client_id: u32) -> anyhow::Result<()> {
- self.clients.lock().unwrap().get_mut(&client_id).context("incr_tx")?.tx_count += 1;
+ self.clients
+ .read()
+ .unwrap()
+ .get(&client_id)
+ .context("incr_tx")?
+ .tx_count
+ .fetch_add(1, Ordering::Relaxed);
Ok(())
}
fn incr_rx(&self, client_id: u32) -> anyhow::Result<()> {
- self.clients.lock().unwrap().get_mut(&client_id).context("incr_rx")?.rx_count += 1;
+ self.clients
+ .read()
+ .unwrap()
+ .get(&client_id)
+ .context("incr_rx")?
+ .rx_count
+ .fetch_add(1, Ordering::Relaxed);
Ok(())
}
@@ -342,7 +360,7 @@
if let Some(packet) = self.create_hwsim_msg(frame, &destination.hwsim_addr) {
self.incr_tx(source.client_id)?;
self.incr_rx(destination.client_id)?;
- (self.callback)(destination.client_id, &packet.clone().to_vec());
+ (self.callback)(destination.client_id, &packet.into());
log_hwsim_msg(frame, source.client_id, destination.client_id);
}
}
@@ -368,20 +386,20 @@
let destination = self.get_station(&dest_addr)?;
self.send_from_sta_frame(&frame, source, &destination)?;
Ok(true)
- } else if dest_addr.is_broadcast() {
- debug!("Frame broadcast {}", frame.ieee80211);
- self.broadcast_from_sta_frame(&frame, source)?;
- // Stations send Probe Request management frame to the broadcast address to scan network actively.
- // Pass to WiFiService so hostapd will send Probe Response for AndroidWiFi.
- // TODO: Only pass necessary packets to hostapd.
- Ok(false)
} else if dest_addr.is_multicast() {
debug!("Frame multicast {}", frame.ieee80211);
self.send_tx_info_frame(&frame)?;
self.broadcast_from_sta_frame(&frame, source)?;
- Ok(true)
+ // Forward multicast packets to WifiService:
+ // 1. Stations send probe Request management frame scan network actively,
+ // so hostapd will send Probe Response for AndroidWiFi.
+ // 2. DNS packets.
+ // TODO: Only pass necessary packets to hostapd and libslirp. (e.g.: Don't forward mDNS packet.)
+ self.incr_tx(source.client_id)?;
+ Ok(false)
} else {
// pass to libslirp
+ self.incr_tx(source.client_id)?;
Ok(false)
}
}
@@ -529,7 +547,7 @@
let callback: HwsimCmdCallback = |_, _| {};
let medium = Medium {
callback,
- stations: Mutex::new(HashMap::from([
+ stations: RwLock::new(HashMap::from([
(addr, Arc::new(Station { client_id: test_client_id, addr, hwsim_addr })),
(
other_addr,
@@ -540,7 +558,7 @@
}),
),
])),
- clients: Mutex::new(HashMap::from([
+ clients: RwLock::new(HashMap::from([
(test_client_id, Client::new()),
(other_client_id, Client::new()),
])),
@@ -604,7 +622,7 @@
assert_eq!(hwsim_msg_tx_info.get_hwsim_hdr().hwsim_cmd, HwsimCmd::TxInfoFrame);
}
- fn build_tx_info_and_compare(frame_bytes: &[u8], tx_info_expected_bytes: &[u8]) {
+ fn build_tx_info_and_compare(frame_bytes: &Bytes, tx_info_expected_bytes: &Bytes) {
let frame = HwsimMsg::parse(frame_bytes).unwrap();
let tx_info = build_tx_info(&frame).unwrap();
@@ -627,17 +645,17 @@
#[test]
fn test_build_tx_info_and_compare() {
- let frame_bytes: Vec<u8> = include!("test_packets/hwsim_cmd_frame_request.csv");
- let tx_info_expected_bytes: Vec<u8> =
- include!("test_packets/hwsim_cmd_tx_info_response.csv");
+ let frame_bytes = Bytes::from(include!("test_packets/hwsim_cmd_frame_request.csv"));
+ let tx_info_expected_bytes =
+ Bytes::from(include!("test_packets/hwsim_cmd_tx_info_response.csv"));
build_tx_info_and_compare(&frame_bytes, &tx_info_expected_bytes);
}
#[test]
fn test_build_tx_info_and_compare_mdns() {
- let frame_bytes: Vec<u8> = include!("test_packets/hwsim_cmd_frame_request_mdns.csv");
- let tx_info_expected_bytes: Vec<u8> =
- include!("test_packets/hwsim_cmd_tx_info_response_mdns.csv");
+ let frame_bytes = Bytes::from(include!("test_packets/hwsim_cmd_frame_request_mdns.csv"));
+ let tx_info_expected_bytes =
+ Bytes::from(include!("test_packets/hwsim_cmd_tx_info_response_mdns.csv"));
build_tx_info_and_compare(&frame_bytes, &tx_info_expected_bytes);
}
}
diff --git a/rust/proto/src/stats.rs b/rust/proto/src/stats.rs
index a3613ca..90a3c93 100644
--- a/rust/proto/src/stats.rs
+++ b/rust/proto/src/stats.rs
@@ -290,6 +290,8 @@
UNSUPPORTED = 2,
// @@protoc_insertion_point(enum_value:netsim.stats.InvalidPacket.Reason.OTHERS)
OTHERS = 3,
+ // @@protoc_insertion_point(enum_value:netsim.stats.InvalidPacket.Reason.DELAYED)
+ DELAYED = 4,
}
impl ::protobuf::Enum for Reason {
@@ -305,6 +307,7 @@
1 => ::std::option::Option::Some(Reason::PARSE_ERROR),
2 => ::std::option::Option::Some(Reason::UNSUPPORTED),
3 => ::std::option::Option::Some(Reason::OTHERS),
+ 4 => ::std::option::Option::Some(Reason::DELAYED),
_ => ::std::option::Option::None
}
}
@@ -314,6 +317,7 @@
Reason::PARSE_ERROR,
Reason::UNSUPPORTED,
Reason::OTHERS,
+ Reason::DELAYED,
];
}
@@ -805,6 +809,480 @@
}
#[derive(PartialEq,Clone,Default,Debug)]
+// @@protoc_insertion_point(message:netsim.stats.NetsimFrontendStats)
+pub struct NetsimFrontendStats {
+ // message fields
+ // @@protoc_insertion_point(field:netsim.stats.NetsimFrontendStats.get_version)
+ pub get_version: ::std::option::Option<u32>,
+ // @@protoc_insertion_point(field:netsim.stats.NetsimFrontendStats.create_device)
+ pub create_device: ::std::option::Option<u32>,
+ // @@protoc_insertion_point(field:netsim.stats.NetsimFrontendStats.delete_chip)
+ pub delete_chip: ::std::option::Option<u32>,
+ // @@protoc_insertion_point(field:netsim.stats.NetsimFrontendStats.patch_device)
+ pub patch_device: ::std::option::Option<u32>,
+ // @@protoc_insertion_point(field:netsim.stats.NetsimFrontendStats.reset)
+ pub reset: ::std::option::Option<u32>,
+ // @@protoc_insertion_point(field:netsim.stats.NetsimFrontendStats.list_device)
+ pub list_device: ::std::option::Option<u32>,
+ // @@protoc_insertion_point(field:netsim.stats.NetsimFrontendStats.subscribe_device)
+ pub subscribe_device: ::std::option::Option<u32>,
+ // @@protoc_insertion_point(field:netsim.stats.NetsimFrontendStats.patch_capture)
+ pub patch_capture: ::std::option::Option<u32>,
+ // @@protoc_insertion_point(field:netsim.stats.NetsimFrontendStats.list_capture)
+ pub list_capture: ::std::option::Option<u32>,
+ // @@protoc_insertion_point(field:netsim.stats.NetsimFrontendStats.get_capture)
+ pub get_capture: ::std::option::Option<u32>,
+ // special fields
+ // @@protoc_insertion_point(special_field:netsim.stats.NetsimFrontendStats.special_fields)
+ pub special_fields: ::protobuf::SpecialFields,
+}
+
+impl<'a> ::std::default::Default for &'a NetsimFrontendStats {
+ fn default() -> &'a NetsimFrontendStats {
+ <NetsimFrontendStats as ::protobuf::Message>::default_instance()
+ }
+}
+
+impl NetsimFrontendStats {
+ pub fn new() -> NetsimFrontendStats {
+ ::std::default::Default::default()
+ }
+
+ // optional uint32 get_version = 1;
+
+ pub fn get_version(&self) -> u32 {
+ self.get_version.unwrap_or(0)
+ }
+
+ pub fn clear_get_version(&mut self) {
+ self.get_version = ::std::option::Option::None;
+ }
+
+ pub fn has_get_version(&self) -> bool {
+ self.get_version.is_some()
+ }
+
+ // Param is passed by value, moved
+ pub fn set_get_version(&mut self, v: u32) {
+ self.get_version = ::std::option::Option::Some(v);
+ }
+
+ // optional uint32 create_device = 2;
+
+ pub fn create_device(&self) -> u32 {
+ self.create_device.unwrap_or(0)
+ }
+
+ pub fn clear_create_device(&mut self) {
+ self.create_device = ::std::option::Option::None;
+ }
+
+ pub fn has_create_device(&self) -> bool {
+ self.create_device.is_some()
+ }
+
+ // Param is passed by value, moved
+ pub fn set_create_device(&mut self, v: u32) {
+ self.create_device = ::std::option::Option::Some(v);
+ }
+
+ // optional uint32 delete_chip = 3;
+
+ pub fn delete_chip(&self) -> u32 {
+ self.delete_chip.unwrap_or(0)
+ }
+
+ pub fn clear_delete_chip(&mut self) {
+ self.delete_chip = ::std::option::Option::None;
+ }
+
+ pub fn has_delete_chip(&self) -> bool {
+ self.delete_chip.is_some()
+ }
+
+ // Param is passed by value, moved
+ pub fn set_delete_chip(&mut self, v: u32) {
+ self.delete_chip = ::std::option::Option::Some(v);
+ }
+
+ // optional uint32 patch_device = 4;
+
+ pub fn patch_device(&self) -> u32 {
+ self.patch_device.unwrap_or(0)
+ }
+
+ pub fn clear_patch_device(&mut self) {
+ self.patch_device = ::std::option::Option::None;
+ }
+
+ pub fn has_patch_device(&self) -> bool {
+ self.patch_device.is_some()
+ }
+
+ // Param is passed by value, moved
+ pub fn set_patch_device(&mut self, v: u32) {
+ self.patch_device = ::std::option::Option::Some(v);
+ }
+
+ // optional uint32 reset = 5;
+
+ pub fn reset(&self) -> u32 {
+ self.reset.unwrap_or(0)
+ }
+
+ pub fn clear_reset(&mut self) {
+ self.reset = ::std::option::Option::None;
+ }
+
+ pub fn has_reset(&self) -> bool {
+ self.reset.is_some()
+ }
+
+ // Param is passed by value, moved
+ pub fn set_reset(&mut self, v: u32) {
+ self.reset = ::std::option::Option::Some(v);
+ }
+
+ // optional uint32 list_device = 6;
+
+ pub fn list_device(&self) -> u32 {
+ self.list_device.unwrap_or(0)
+ }
+
+ pub fn clear_list_device(&mut self) {
+ self.list_device = ::std::option::Option::None;
+ }
+
+ pub fn has_list_device(&self) -> bool {
+ self.list_device.is_some()
+ }
+
+ // Param is passed by value, moved
+ pub fn set_list_device(&mut self, v: u32) {
+ self.list_device = ::std::option::Option::Some(v);
+ }
+
+ // optional uint32 subscribe_device = 7;
+
+ pub fn subscribe_device(&self) -> u32 {
+ self.subscribe_device.unwrap_or(0)
+ }
+
+ pub fn clear_subscribe_device(&mut self) {
+ self.subscribe_device = ::std::option::Option::None;
+ }
+
+ pub fn has_subscribe_device(&self) -> bool {
+ self.subscribe_device.is_some()
+ }
+
+ // Param is passed by value, moved
+ pub fn set_subscribe_device(&mut self, v: u32) {
+ self.subscribe_device = ::std::option::Option::Some(v);
+ }
+
+ // optional uint32 patch_capture = 8;
+
+ pub fn patch_capture(&self) -> u32 {
+ self.patch_capture.unwrap_or(0)
+ }
+
+ pub fn clear_patch_capture(&mut self) {
+ self.patch_capture = ::std::option::Option::None;
+ }
+
+ pub fn has_patch_capture(&self) -> bool {
+ self.patch_capture.is_some()
+ }
+
+ // Param is passed by value, moved
+ pub fn set_patch_capture(&mut self, v: u32) {
+ self.patch_capture = ::std::option::Option::Some(v);
+ }
+
+ // optional uint32 list_capture = 9;
+
+ pub fn list_capture(&self) -> u32 {
+ self.list_capture.unwrap_or(0)
+ }
+
+ pub fn clear_list_capture(&mut self) {
+ self.list_capture = ::std::option::Option::None;
+ }
+
+ pub fn has_list_capture(&self) -> bool {
+ self.list_capture.is_some()
+ }
+
+ // Param is passed by value, moved
+ pub fn set_list_capture(&mut self, v: u32) {
+ self.list_capture = ::std::option::Option::Some(v);
+ }
+
+ // optional uint32 get_capture = 10;
+
+ pub fn get_capture(&self) -> u32 {
+ self.get_capture.unwrap_or(0)
+ }
+
+ pub fn clear_get_capture(&mut self) {
+ self.get_capture = ::std::option::Option::None;
+ }
+
+ pub fn has_get_capture(&self) -> bool {
+ self.get_capture.is_some()
+ }
+
+ // Param is passed by value, moved
+ pub fn set_get_capture(&mut self, v: u32) {
+ self.get_capture = ::std::option::Option::Some(v);
+ }
+
+ fn generated_message_descriptor_data() -> ::protobuf::reflect::GeneratedMessageDescriptorData {
+ let mut fields = ::std::vec::Vec::with_capacity(10);
+ let mut oneofs = ::std::vec::Vec::with_capacity(0);
+ fields.push(::protobuf::reflect::rt::v2::make_option_accessor::<_, _>(
+ "get_version",
+ |m: &NetsimFrontendStats| { &m.get_version },
+ |m: &mut NetsimFrontendStats| { &mut m.get_version },
+ ));
+ fields.push(::protobuf::reflect::rt::v2::make_option_accessor::<_, _>(
+ "create_device",
+ |m: &NetsimFrontendStats| { &m.create_device },
+ |m: &mut NetsimFrontendStats| { &mut m.create_device },
+ ));
+ fields.push(::protobuf::reflect::rt::v2::make_option_accessor::<_, _>(
+ "delete_chip",
+ |m: &NetsimFrontendStats| { &m.delete_chip },
+ |m: &mut NetsimFrontendStats| { &mut m.delete_chip },
+ ));
+ fields.push(::protobuf::reflect::rt::v2::make_option_accessor::<_, _>(
+ "patch_device",
+ |m: &NetsimFrontendStats| { &m.patch_device },
+ |m: &mut NetsimFrontendStats| { &mut m.patch_device },
+ ));
+ fields.push(::protobuf::reflect::rt::v2::make_option_accessor::<_, _>(
+ "reset",
+ |m: &NetsimFrontendStats| { &m.reset },
+ |m: &mut NetsimFrontendStats| { &mut m.reset },
+ ));
+ fields.push(::protobuf::reflect::rt::v2::make_option_accessor::<_, _>(
+ "list_device",
+ |m: &NetsimFrontendStats| { &m.list_device },
+ |m: &mut NetsimFrontendStats| { &mut m.list_device },
+ ));
+ fields.push(::protobuf::reflect::rt::v2::make_option_accessor::<_, _>(
+ "subscribe_device",
+ |m: &NetsimFrontendStats| { &m.subscribe_device },
+ |m: &mut NetsimFrontendStats| { &mut m.subscribe_device },
+ ));
+ fields.push(::protobuf::reflect::rt::v2::make_option_accessor::<_, _>(
+ "patch_capture",
+ |m: &NetsimFrontendStats| { &m.patch_capture },
+ |m: &mut NetsimFrontendStats| { &mut m.patch_capture },
+ ));
+ fields.push(::protobuf::reflect::rt::v2::make_option_accessor::<_, _>(
+ "list_capture",
+ |m: &NetsimFrontendStats| { &m.list_capture },
+ |m: &mut NetsimFrontendStats| { &mut m.list_capture },
+ ));
+ fields.push(::protobuf::reflect::rt::v2::make_option_accessor::<_, _>(
+ "get_capture",
+ |m: &NetsimFrontendStats| { &m.get_capture },
+ |m: &mut NetsimFrontendStats| { &mut m.get_capture },
+ ));
+ ::protobuf::reflect::GeneratedMessageDescriptorData::new_2::<NetsimFrontendStats>(
+ "NetsimFrontendStats",
+ fields,
+ oneofs,
+ )
+ }
+}
+
+impl ::protobuf::Message for NetsimFrontendStats {
+ const NAME: &'static str = "NetsimFrontendStats";
+
+ fn is_initialized(&self) -> bool {
+ true
+ }
+
+ fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::Result<()> {
+ while let Some(tag) = is.read_raw_tag_or_eof()? {
+ match tag {
+ 8 => {
+ self.get_version = ::std::option::Option::Some(is.read_uint32()?);
+ },
+ 16 => {
+ self.create_device = ::std::option::Option::Some(is.read_uint32()?);
+ },
+ 24 => {
+ self.delete_chip = ::std::option::Option::Some(is.read_uint32()?);
+ },
+ 32 => {
+ self.patch_device = ::std::option::Option::Some(is.read_uint32()?);
+ },
+ 40 => {
+ self.reset = ::std::option::Option::Some(is.read_uint32()?);
+ },
+ 48 => {
+ self.list_device = ::std::option::Option::Some(is.read_uint32()?);
+ },
+ 56 => {
+ self.subscribe_device = ::std::option::Option::Some(is.read_uint32()?);
+ },
+ 64 => {
+ self.patch_capture = ::std::option::Option::Some(is.read_uint32()?);
+ },
+ 72 => {
+ self.list_capture = ::std::option::Option::Some(is.read_uint32()?);
+ },
+ 80 => {
+ self.get_capture = ::std::option::Option::Some(is.read_uint32()?);
+ },
+ tag => {
+ ::protobuf::rt::read_unknown_or_skip_group(tag, is, self.special_fields.mut_unknown_fields())?;
+ },
+ };
+ }
+ ::std::result::Result::Ok(())
+ }
+
+ // Compute sizes of nested messages
+ #[allow(unused_variables)]
+ fn compute_size(&self) -> u64 {
+ let mut my_size = 0;
+ if let Some(v) = self.get_version {
+ my_size += ::protobuf::rt::uint32_size(1, v);
+ }
+ if let Some(v) = self.create_device {
+ my_size += ::protobuf::rt::uint32_size(2, v);
+ }
+ if let Some(v) = self.delete_chip {
+ my_size += ::protobuf::rt::uint32_size(3, v);
+ }
+ if let Some(v) = self.patch_device {
+ my_size += ::protobuf::rt::uint32_size(4, v);
+ }
+ if let Some(v) = self.reset {
+ my_size += ::protobuf::rt::uint32_size(5, v);
+ }
+ if let Some(v) = self.list_device {
+ my_size += ::protobuf::rt::uint32_size(6, v);
+ }
+ if let Some(v) = self.subscribe_device {
+ my_size += ::protobuf::rt::uint32_size(7, v);
+ }
+ if let Some(v) = self.patch_capture {
+ my_size += ::protobuf::rt::uint32_size(8, v);
+ }
+ if let Some(v) = self.list_capture {
+ my_size += ::protobuf::rt::uint32_size(9, v);
+ }
+ if let Some(v) = self.get_capture {
+ my_size += ::protobuf::rt::uint32_size(10, v);
+ }
+ my_size += ::protobuf::rt::unknown_fields_size(self.special_fields.unknown_fields());
+ self.special_fields.cached_size().set(my_size as u32);
+ my_size
+ }
+
+ fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::Result<()> {
+ if let Some(v) = self.get_version {
+ os.write_uint32(1, v)?;
+ }
+ if let Some(v) = self.create_device {
+ os.write_uint32(2, v)?;
+ }
+ if let Some(v) = self.delete_chip {
+ os.write_uint32(3, v)?;
+ }
+ if let Some(v) = self.patch_device {
+ os.write_uint32(4, v)?;
+ }
+ if let Some(v) = self.reset {
+ os.write_uint32(5, v)?;
+ }
+ if let Some(v) = self.list_device {
+ os.write_uint32(6, v)?;
+ }
+ if let Some(v) = self.subscribe_device {
+ os.write_uint32(7, v)?;
+ }
+ if let Some(v) = self.patch_capture {
+ os.write_uint32(8, v)?;
+ }
+ if let Some(v) = self.list_capture {
+ os.write_uint32(9, v)?;
+ }
+ if let Some(v) = self.get_capture {
+ os.write_uint32(10, v)?;
+ }
+ os.write_unknown_fields(self.special_fields.unknown_fields())?;
+ ::std::result::Result::Ok(())
+ }
+
+ fn special_fields(&self) -> &::protobuf::SpecialFields {
+ &self.special_fields
+ }
+
+ fn mut_special_fields(&mut self) -> &mut ::protobuf::SpecialFields {
+ &mut self.special_fields
+ }
+
+ fn new() -> NetsimFrontendStats {
+ NetsimFrontendStats::new()
+ }
+
+ fn clear(&mut self) {
+ self.get_version = ::std::option::Option::None;
+ self.create_device = ::std::option::Option::None;
+ self.delete_chip = ::std::option::Option::None;
+ self.patch_device = ::std::option::Option::None;
+ self.reset = ::std::option::Option::None;
+ self.list_device = ::std::option::Option::None;
+ self.subscribe_device = ::std::option::Option::None;
+ self.patch_capture = ::std::option::Option::None;
+ self.list_capture = ::std::option::Option::None;
+ self.get_capture = ::std::option::Option::None;
+ self.special_fields.clear();
+ }
+
+ fn default_instance() -> &'static NetsimFrontendStats {
+ static instance: NetsimFrontendStats = NetsimFrontendStats {
+ get_version: ::std::option::Option::None,
+ create_device: ::std::option::Option::None,
+ delete_chip: ::std::option::Option::None,
+ patch_device: ::std::option::Option::None,
+ reset: ::std::option::Option::None,
+ list_device: ::std::option::Option::None,
+ subscribe_device: ::std::option::Option::None,
+ patch_capture: ::std::option::Option::None,
+ list_capture: ::std::option::Option::None,
+ get_capture: ::std::option::Option::None,
+ special_fields: ::protobuf::SpecialFields::new(),
+ };
+ &instance
+ }
+}
+
+impl ::protobuf::MessageFull for NetsimFrontendStats {
+ fn descriptor() -> ::protobuf::reflect::MessageDescriptor {
+ static descriptor: ::protobuf::rt::Lazy<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::Lazy::new();
+ descriptor.get(|| file_descriptor().message_by_package_relative_name("NetsimFrontendStats").unwrap()).clone()
+ }
+}
+
+impl ::std::fmt::Display for NetsimFrontendStats {
+ fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
+ ::protobuf::text_format::fmt(self, f)
+ }
+}
+
+impl ::protobuf::reflect::ProtobufValue for NetsimFrontendStats {
+ type RuntimeType = ::protobuf::reflect::rt::RuntimeTypeMessage<Self>;
+}
+
+#[derive(PartialEq,Clone,Default,Debug)]
// @@protoc_insertion_point(message:netsim.stats.NetsimStats)
pub struct NetsimStats {
// message fields
@@ -818,6 +1296,8 @@
pub radio_stats: ::std::vec::Vec<NetsimRadioStats>,
// @@protoc_insertion_point(field:netsim.stats.NetsimStats.version)
pub version: ::std::option::Option<::std::string::String>,
+ // @@protoc_insertion_point(field:netsim.stats.NetsimStats.frontend_stats)
+ pub frontend_stats: ::protobuf::MessageField<NetsimFrontendStats>,
// special fields
// @@protoc_insertion_point(special_field:netsim.stats.NetsimStats.special_fields)
pub special_fields: ::protobuf::SpecialFields,
@@ -928,7 +1408,7 @@
}
fn generated_message_descriptor_data() -> ::protobuf::reflect::GeneratedMessageDescriptorData {
- let mut fields = ::std::vec::Vec::with_capacity(5);
+ let mut fields = ::std::vec::Vec::with_capacity(6);
let mut oneofs = ::std::vec::Vec::with_capacity(0);
fields.push(::protobuf::reflect::rt::v2::make_option_accessor::<_, _>(
"duration_secs",
@@ -955,6 +1435,11 @@
|m: &NetsimStats| { &m.version },
|m: &mut NetsimStats| { &mut m.version },
));
+ fields.push(::protobuf::reflect::rt::v2::make_message_field_accessor::<_, NetsimFrontendStats>(
+ "frontend_stats",
+ |m: &NetsimStats| { &m.frontend_stats },
+ |m: &mut NetsimStats| { &mut m.frontend_stats },
+ ));
::protobuf::reflect::GeneratedMessageDescriptorData::new_2::<NetsimStats>(
"NetsimStats",
fields,
@@ -988,6 +1473,9 @@
42 => {
self.version = ::std::option::Option::Some(is.read_string()?);
},
+ 50 => {
+ ::protobuf::rt::read_singular_message_into_field(is, &mut self.frontend_stats)?;
+ },
tag => {
::protobuf::rt::read_unknown_or_skip_group(tag, is, self.special_fields.mut_unknown_fields())?;
},
@@ -1016,6 +1504,10 @@
if let Some(v) = self.version.as_ref() {
my_size += ::protobuf::rt::string_size(5, &v);
}
+ if let Some(v) = self.frontend_stats.as_ref() {
+ let len = v.compute_size();
+ my_size += 1 + ::protobuf::rt::compute_raw_varint64_size(len) + len;
+ }
my_size += ::protobuf::rt::unknown_fields_size(self.special_fields.unknown_fields());
self.special_fields.cached_size().set(my_size as u32);
my_size
@@ -1037,6 +1529,9 @@
if let Some(v) = self.version.as_ref() {
os.write_string(5, v)?;
}
+ if let Some(v) = self.frontend_stats.as_ref() {
+ ::protobuf::rt::write_message_field_with_cached_size(6, v, os)?;
+ }
os.write_unknown_fields(self.special_fields.unknown_fields())?;
::std::result::Result::Ok(())
}
@@ -1059,6 +1554,7 @@
self.peak_concurrent_devices = ::std::option::Option::None;
self.radio_stats.clear();
self.version = ::std::option::Option::None;
+ self.frontend_stats.clear();
self.special_fields.clear();
}
@@ -1069,6 +1565,7 @@
peak_concurrent_devices: ::std::option::Option::None,
radio_stats: ::std::vec::Vec::new(),
version: ::std::option::Option::None,
+ frontend_stats: ::protobuf::MessageField::none(),
special_fields: ::protobuf::SpecialFields::new(),
};
&instance
@@ -1093,28 +1590,39 @@
}
static file_descriptor_proto_data: &'static [u8] = b"\
- \n\x12netsim/stats.proto\x12\x0cnetsim.stats\"\xca\x01\n\rInvalidPacket\
+ \n\x12netsim/stats.proto\x12\x0cnetsim.stats\"\xd7\x01\n\rInvalidPacket\
\x12:\n\x06reason\x18\x01\x20\x01(\x0e2\".netsim.stats.InvalidPacket.Rea\
sonR\x06reason\x12\x20\n\x0bdescription\x18\x02\x20\x01(\tR\x0bdescripti\
- on\x12\x16\n\x06packet\x18\x03\x20\x01(\x0cR\x06packet\"C\n\x06Reason\
+ on\x12\x16\n\x06packet\x18\x03\x20\x01(\x0cR\x06packet\"P\n\x06Reason\
\x12\x0b\n\x07UNKNOWN\x10\0\x12\x0f\n\x0bPARSE_ERROR\x10\x01\x12\x0f\n\
- \x0bUNSUPPORTED\x10\x02\x12\n\n\x06OTHERS\x10\x03\"\xb5\x03\n\x10NetsimR\
- adioStats\x12\x1b\n\tdevice_id\x18\x01\x20\x01(\rR\x08deviceId\x127\n\
- \x04kind\x18\x02\x20\x01(\x0e2#.netsim.stats.NetsimRadioStats.KindR\x04k\
- ind\x12#\n\rduration_secs\x18\x03\x20\x01(\x04R\x0cdurationSecs\x12\x19\
- \n\x08tx_count\x18\x04\x20\x01(\x05R\x07txCount\x12\x19\n\x08rx_count\
- \x18\x05\x20\x01(\x05R\x07rxCount\x12\x19\n\x08tx_bytes\x18\x06\x20\x01(\
- \x05R\x07txBytes\x12\x19\n\x08rx_bytes\x18\x07\x20\x01(\x05R\x07rxBytes\
- \x12D\n\x0finvalid_packets\x18\x08\x20\x03(\x0b2\x1b.netsim.stats.Invali\
- dPacketR\x0einvalidPackets\"t\n\x04Kind\x12\x0f\n\x0bUNSPECIFIED\x10\0\
- \x12\x18\n\x14BLUETOOTH_LOW_ENERGY\x10\x01\x12\x15\n\x11BLUETOOTH_CLASSI\
- C\x10\x02\x12\x0e\n\nBLE_BEACON\x10\x03\x12\x08\n\x04WIFI\x10\x04\x12\
- \x07\n\x03UWB\x10\x05\x12\x07\n\x03NFC\x10\x06\"\xe8\x01\n\x0bNetsimStat\
- s\x12#\n\rduration_secs\x18\x01\x20\x01(\x04R\x0cdurationSecs\x12!\n\x0c\
- device_count\x18\x02\x20\x01(\x05R\x0bdeviceCount\x126\n\x17peak_concurr\
- ent_devices\x18\x03\x20\x01(\x05R\x15peakConcurrentDevices\x12?\n\x0brad\
- io_stats\x18\x04\x20\x03(\x0b2\x1e.netsim.stats.NetsimRadioStatsR\nradio\
- Stats\x12\x18\n\x07version\x18\x05\x20\x01(\tR\x07version\
+ \x0bUNSUPPORTED\x10\x02\x12\n\n\x06OTHERS\x10\x03\x12\x0b\n\x07DELAYED\
+ \x10\x04\"\xb5\x03\n\x10NetsimRadioStats\x12\x1b\n\tdevice_id\x18\x01\
+ \x20\x01(\rR\x08deviceId\x127\n\x04kind\x18\x02\x20\x01(\x0e2#.netsim.st\
+ ats.NetsimRadioStats.KindR\x04kind\x12#\n\rduration_secs\x18\x03\x20\x01\
+ (\x04R\x0cdurationSecs\x12\x19\n\x08tx_count\x18\x04\x20\x01(\x05R\x07tx\
+ Count\x12\x19\n\x08rx_count\x18\x05\x20\x01(\x05R\x07rxCount\x12\x19\n\
+ \x08tx_bytes\x18\x06\x20\x01(\x05R\x07txBytes\x12\x19\n\x08rx_bytes\x18\
+ \x07\x20\x01(\x05R\x07rxBytes\x12D\n\x0finvalid_packets\x18\x08\x20\x03(\
+ \x0b2\x1b.netsim.stats.InvalidPacketR\x0einvalidPackets\"t\n\x04Kind\x12\
+ \x0f\n\x0bUNSPECIFIED\x10\0\x12\x18\n\x14BLUETOOTH_LOW_ENERGY\x10\x01\
+ \x12\x15\n\x11BLUETOOTH_CLASSIC\x10\x02\x12\x0e\n\nBLE_BEACON\x10\x03\
+ \x12\x08\n\x04WIFI\x10\x04\x12\x07\n\x03UWB\x10\x05\x12\x07\n\x03NFC\x10\
+ \x06\"\xea\x02\n\x13NetsimFrontendStats\x12\x1f\n\x0bget_version\x18\x01\
+ \x20\x01(\rR\ngetVersion\x12#\n\rcreate_device\x18\x02\x20\x01(\rR\x0ccr\
+ eateDevice\x12\x1f\n\x0bdelete_chip\x18\x03\x20\x01(\rR\ndeleteChip\x12!\
+ \n\x0cpatch_device\x18\x04\x20\x01(\rR\x0bpatchDevice\x12\x14\n\x05reset\
+ \x18\x05\x20\x01(\rR\x05reset\x12\x1f\n\x0blist_device\x18\x06\x20\x01(\
+ \rR\nlistDevice\x12)\n\x10subscribe_device\x18\x07\x20\x01(\rR\x0fsubscr\
+ ibeDevice\x12#\n\rpatch_capture\x18\x08\x20\x01(\rR\x0cpatchCapture\x12!\
+ \n\x0clist_capture\x18\t\x20\x01(\rR\x0blistCapture\x12\x1f\n\x0bget_cap\
+ ture\x18\n\x20\x01(\rR\ngetCapture\"\xb2\x02\n\x0bNetsimStats\x12#\n\rdu\
+ ration_secs\x18\x01\x20\x01(\x04R\x0cdurationSecs\x12!\n\x0cdevice_count\
+ \x18\x02\x20\x01(\x05R\x0bdeviceCount\x126\n\x17peak_concurrent_devices\
+ \x18\x03\x20\x01(\x05R\x15peakConcurrentDevices\x12?\n\x0bradio_stats\
+ \x18\x04\x20\x03(\x0b2\x1e.netsim.stats.NetsimRadioStatsR\nradioStats\
+ \x12\x18\n\x07version\x18\x05\x20\x01(\tR\x07version\x12H\n\x0efrontend_\
+ stats\x18\x06\x20\x01(\x0b2!.netsim.stats.NetsimFrontendStatsR\rfrontend\
+ Stats\
";
/// `FileDescriptorProto` object which was a source for this generated file
@@ -1132,9 +1640,10 @@
file_descriptor.get(|| {
let generated_file_descriptor = generated_file_descriptor_lazy.get(|| {
let mut deps = ::std::vec::Vec::with_capacity(0);
- let mut messages = ::std::vec::Vec::with_capacity(3);
+ let mut messages = ::std::vec::Vec::with_capacity(4);
messages.push(InvalidPacket::generated_message_descriptor_data());
messages.push(NetsimRadioStats::generated_message_descriptor_data());
+ messages.push(NetsimFrontendStats::generated_message_descriptor_data());
messages.push(NetsimStats::generated_message_descriptor_data());
let mut enums = ::std::vec::Vec::with_capacity(2);
enums.push(invalid_packet::Reason::generated_enum_descriptor_data());
diff --git a/scripts/build_tools.py b/scripts/build_tools.py
index ff7e478..3a36b29 100755
--- a/scripts/build_tools.py
+++ b/scripts/build_tools.py
@@ -106,6 +106,16 @@
" emulator-linux_x64"
),
)
+ parser.add_argument(
+ "--local_emulator_dir",
+ type=str,
+ default="",
+ help=(
+ "For providing an emulator build artifact in a directory."
+ " This will install the emulator from local_emulator_dir instead of"
+ " fetching the artifacts"
+ ),
+ )
args = parser.parse_args()
diff --git a/scripts/tasks/install_emulator_task.py b/scripts/tasks/install_emulator_task.py
index 6df4904..e3a9c90 100644
--- a/scripts/tasks/install_emulator_task.py
+++ b/scripts/tasks/install_emulator_task.py
@@ -45,10 +45,12 @@
self.out_dir = args.out_dir
# Local fetching use only - default to emulator-linux_x64
self.target = args.emulator_target
+ # Local Emulator directory
+ self.local_emulator_dir = args.local_emulator_dir
def do_run(self):
install_emulator_manager = InstallEmulatorManager(
- self.buildbot, self.out_dir, self.target
+ self.buildbot, self.out_dir, self.target, self.local_emulator_dir
)
return install_emulator_manager.process()
@@ -67,7 +69,7 @@
used for Android Build Bots.
"""
- def __init__(self, buildbot, out_dir, target):
+ def __init__(self, buildbot, out_dir, target, local_emulator_dir):
"""Initializes the instances based on environment
Args:
@@ -78,6 +80,7 @@
self.buildbot = buildbot
self.out_dir = out_dir
self.target = target
+ self.local_emulator_dir = local_emulator_dir
def __os_name_fetch(self):
"""Obtains the os substring of the emulator artifact"""
@@ -158,7 +161,7 @@
os.remove(EMULATOR_ARTIFACT_PATH / file)
return True
- def __copy_artifacts(self):
+ def __copy_artifacts(self, emulator_filepath):
"""Copy artifacts into desired location
In the local case, the emulator artifacts get copied into objs/
@@ -167,7 +170,6 @@
Note that the downloaded netsim artifacts are removed before copying.
"""
- emulator_filepath = EMULATOR_ARTIFACT_PATH / "emulator"
# Remove all downloaded netsim artifacts
files = glob.glob(str(emulator_filepath / "netsim*"))
for fname in files:
@@ -213,30 +215,34 @@
if not self.__prerequisites():
return False
- # Artifact fetching for local case
- if not self.buildbot:
- # Simulating the shell command
- run(
- [
- "/google/data/ro/projects/android/fetch_artifact",
- "--latest",
- "--target",
- self.target,
- "--branch",
- "aosp-emu-master-dev",
- "sdk-repo-linux-emulator-*.zip",
- ],
- get_default_environment(AOSP_ROOT),
- "install_emulator",
- cwd=EMULATOR_ARTIFACT_PATH,
- )
+ if self.local_emulator_dir:
+ # If local_emulator_dir is provided, copy the artifacts from this directory.
+ self.__copy_artifacts(Path(self.local_emulator_dir))
+ else:
+ # Artifact fetching for local case
+ if not self.buildbot:
+ # Simulating the shell command
+ run(
+ [
+ "/google/data/ro/projects/android/fetch_artifact",
+ "--latest",
+ "--target",
+ self.target,
+ "--branch",
+ "aosp-emu-master-dev",
+ "sdk-repo-linux-emulator-*.zip",
+ ],
+ get_default_environment(AOSP_ROOT),
+ "install_emulator",
+ cwd=EMULATOR_ARTIFACT_PATH,
+ )
- # Unzipping emulator artifacts and remove zip files
- if not self.__unzip_emulator_artifacts(os_name_artifact):
- return False
+ # Unzipping emulator artifacts and remove zip files
+ if not self.__unzip_emulator_artifacts(os_name_artifact):
+ return False
- # Copy artifacts after removing downloaded netsim artifacts
- self.__copy_artifacts()
+ # Copy artifacts after removing downloaded netsim artifacts
+ self.__copy_artifacts(EMULATOR_ARTIFACT_PATH / "emulator")
# Remove the EMULATOR_ARTIFACT_PATH in local case
if not self.buildbot:
diff --git a/src/hci/hci_packet_transport.cc b/src/hci/hci_packet_transport.cc
index 81de642..277df91 100644
--- a/src/hci/hci_packet_transport.cc
+++ b/src/hci/hci_packet_transport.cc
@@ -21,6 +21,7 @@
#include "model/hci/hci_transport.h"
#include "netsim-daemon/src/ffi.rs.h"
#include "netsim/hci_packet.pb.h"
+#include "netsim/stats.pb.h"
#include "rust/cxx.h"
#include "util/log.h"
@@ -92,9 +93,25 @@
// HCIPacket_PacketType to rootcanal::PacketType is safe.
rootcanal::PacketType rootcanal_packet_type =
static_cast<rootcanal::PacketType>(packet_type);
- mAsyncManager->Synchronize([this, rootcanal_packet_type, packet]() {
- mPacketCallback(rootcanal_packet_type, packet);
- });
+ auto beforeScheduleTime = std::chrono::steady_clock::now();
+ mAsyncManager->Synchronize(
+ [this, rootcanal_packet_type, packet, beforeScheduleTime]() {
+ auto elapsedTime =
+ std::chrono::duration_cast<std::chrono::milliseconds>(
+ std::chrono::steady_clock::now() - beforeScheduleTime)
+ .count();
+ // If the elapsed time of the packet delivery is greater than 5ms,
+ // report invalid packet with DELAYED reasoning.
+ if (elapsedTime > 5) {
+ netsim::hci::facade::ReportInvalidPacket(
+ this->rootcanalId.value(),
+ stats::InvalidPacket_Reason::InvalidPacket_Reason_DELAYED,
+ "Delayed packet with " + std::to_string(elapsedTime) +
+ " milliseconds",
+ *packet);
+ }
+ mPacketCallback(rootcanal_packet_type, packet);
+ });
}
void HciPacketTransport::Add(