From ced463be7040585f327e44c1ea706ea17e38692c Mon Sep 17 00:00:00 2001 From: hajoha Date: Sun, 5 Jan 2025 20:56:20 +0100 Subject: [PATCH 01/43] add dep for MQTT lib --- app/build.gradle | 1 + settings.gradle | 1 + 2 files changed, 2 insertions(+) diff --git a/app/build.gradle b/app/build.gradle index 24db1da4..15f3339e 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -150,6 +150,7 @@ dependencies { implementation 'com.github.anastr:speedviewlib:1.6.1' implementation "androidx.viewpager2:viewpager2:1.1.0" implementation "androidx.compose.material3:material3:1.3.0" + implementation 'com.github.hannesa2:paho.mqtt.android:4.3' } configurations.implementation { diff --git a/settings.gradle b/settings.gradle index c77964c0..2a01f1ba 100644 --- a/settings.gradle +++ b/settings.gradle @@ -10,6 +10,7 @@ dependencyResolutionManagement { repositories { google() mavenCentral() + maven { url 'https://jitpack.io' } } } From e629b4a4547e31eea5c538cb55503e08d97ea95b Mon Sep 17 00:00:00 2001 From: hajoha Date: Sun, 5 Jan 2025 23:14:43 +0100 Subject: [PATCH 02/43] add basic setup for MQTT config --- app/build.gradle | 3 +- .../MainActivity.java | 3 + .../Preferences/SPType.java | 3 +- .../Preferences/SharedPreferencesGrouper.java | 7 ++- .../MQTTSettingsFragment.java | 33 ++++++++++ app/src/main/res/drawable/mqtt.xml | 5 ++ app/src/main/res/navigation/nav_graph.xml | 11 ++++ app/src/main/res/values/strings.xml | 13 ++++ app/src/main/res/xml/preference.xml | 6 ++ app/src/main/res/xml/preference_mqtt.xml | 61 +++++++++++++++++++ settings.gradle | 4 +- 11 files changed, 145 insertions(+), 4 deletions(-) create mode 100644 app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/SettingPreferences/MQTTSettingsFragment.java create mode 100644 app/src/main/res/drawable/mqtt.xml create mode 100644 app/src/main/res/xml/preference_mqtt.xml diff --git a/app/build.gradle b/app/build.gradle index 15f3339e..b1d06d87 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -150,7 +150,8 @@ dependencies { implementation 'com.github.anastr:speedviewlib:1.6.1' implementation "androidx.viewpager2:viewpager2:1.1.0" implementation "androidx.compose.material3:material3:1.3.0" - implementation 'com.github.hannesa2:paho.mqtt.android:4.3' + implementation 'org.eclipse.paho:org.eclipse.paho.client.mqttv3:1.1.0' + implementation 'org.eclipse.paho:org.eclipse.paho.android.service:1.1.1' } configurations.implementation { diff --git a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/MainActivity.java b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/MainActivity.java index 3f3e54ca..c95d0724 100644 --- a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/MainActivity.java +++ b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/MainActivity.java @@ -472,6 +472,9 @@ public boolean onPreferenceStartFragment(@NonNull PreferenceFragmentCompat calle case "shared_preferences_io": navController.navigate(R.id.fragment_shared_preferences_io); break; + case "mqtt_settings": + navController.navigate(R.id.mqttSettingsFragment); + break; } return true; } diff --git a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Preferences/SPType.java b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Preferences/SPType.java index 6607b0ab..772b92cd 100644 --- a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Preferences/SPType.java +++ b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Preferences/SPType.java @@ -6,7 +6,8 @@ public enum SPType { ping_sp, carrier_sp, mobile_network_sp, - default_sp; + default_sp, + mqtt_sp; public String toString() { diff --git a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Preferences/SharedPreferencesGrouper.java b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Preferences/SharedPreferencesGrouper.java index 99cbe84a..28881ca1 100644 --- a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Preferences/SharedPreferencesGrouper.java +++ b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Preferences/SharedPreferencesGrouper.java @@ -17,6 +17,7 @@ public class SharedPreferencesGrouper { private final SharedPreferences carrierSP; private final SharedPreferences iperf3SP; private final SharedPreferences mobileNetworkSP; + private final SharedPreferences mqttSP; private final SharedPreferences defaultSP; private final SharedPreferences pingSP; private final Context ct; @@ -32,12 +33,13 @@ public void clearConfig(){ } - private SharedPreferencesGrouper(Context ct) { + private SharedPreferencesGrouper( Context ct) { this.ct = ct; loggingSP = ct.getSharedPreferences(getSharedPreferenceIdentifier(SPType.logging_sp), Context.MODE_PRIVATE); carrierSP = ct.getSharedPreferences(getSharedPreferenceIdentifier(SPType.carrier_sp), Context.MODE_PRIVATE); iperf3SP = ct.getSharedPreferences(getSharedPreferenceIdentifier(SPType.iperf3_sp), Context.MODE_PRIVATE); pingSP = ct.getSharedPreferences(getSharedPreferenceIdentifier(SPType.ping_sp), Context.MODE_PRIVATE); + mqttSP = ct.getSharedPreferences(getSharedPreferenceIdentifier(SPType.mqtt_sp), Context.MODE_PRIVATE); mobileNetworkSP = ct.getSharedPreferences(getSharedPreferenceIdentifier(SPType.mobile_network_sp), Context.MODE_PRIVATE); defaultSP = PreferenceManager.getDefaultSharedPreferences(ct); } @@ -67,6 +69,9 @@ public SharedPreferences getSharedPreference(SPType key){ case mobile_network_sp: sp = mobileNetworkSP; break; + case mqtt_sp: + sp = mqttSP; + break; default: sp = defaultSP; break; diff --git a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/SettingPreferences/MQTTSettingsFragment.java b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/SettingPreferences/MQTTSettingsFragment.java new file mode 100644 index 00000000..b146313f --- /dev/null +++ b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/SettingPreferences/MQTTSettingsFragment.java @@ -0,0 +1,33 @@ +package de.fraunhofer.fokus.OpenMobileNetworkToolkit.SettingPreferences; + +import android.content.SharedPreferences; +import android.os.Bundle; +import android.text.InputType; + +import androidx.annotation.Nullable; +import androidx.preference.PreferenceFragmentCompat; + +import java.util.Objects; + +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Preferences.SPType; +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Preferences.SharedPreferencesGrouper; +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.R; + +public class MQTTSettingsFragment extends PreferenceFragmentCompat implements SharedPreferences.OnSharedPreferenceChangeListener { + @Override + public void onCreatePreferences(@Nullable Bundle savedInstanceState, @Nullable String rootKey) { + SharedPreferencesGrouper spg = SharedPreferencesGrouper.getInstance(requireContext()); + getPreferenceManager().setSharedPreferencesName(spg.getSharedPreferenceIdentifier(SPType.logging_sp)); + setPreferencesFromResource(R.xml.preference_mqtt, rootKey); + Objects.requireNonNull(getPreferenceScreen().getSharedPreferences()) + .registerOnSharedPreferenceChangeListener(this); + + + + } + + @Override + public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, @Nullable String key) { + + } +} diff --git a/app/src/main/res/drawable/mqtt.xml b/app/src/main/res/drawable/mqtt.xml new file mode 100644 index 00000000..64b84c3f --- /dev/null +++ b/app/src/main/res/drawable/mqtt.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/app/src/main/res/navigation/nav_graph.xml b/app/src/main/res/navigation/nav_graph.xml index 38072b60..9382344f 100644 --- a/app/src/main/res/navigation/nav_graph.xml +++ b/app/src/main/res/navigation/nav_graph.xml @@ -53,6 +53,7 @@ app:destination="@id/HomeFragment" /> + + + + + Android IMS> Log WiFi information> + + + + @@ -254,5 +258,14 @@ Standard Channel Bandwidth Security Type + MQTT Username + Enable MQTT + Enable MQTT on boot + Username provided by your MQTT-Broker + MQTT Client Username + Password provided by your MQTT-Broker + MQTT Client Password + MQTT-Broker Address, including Port + MQTT-Broker Address \ No newline at end of file diff --git a/app/src/main/res/xml/preference.xml b/app/src/main/res/xml/preference.xml index dc774fe2..ead89245 100644 --- a/app/src/main/res/xml/preference.xml +++ b/app/src/main/res/xml/preference.xml @@ -55,4 +55,10 @@ app:fragment="de.fraunhofer.fokus.OpenMobileNetworkToolkit.SettingPreferences.SharedPreferencesIOFragment" app:key="shared_preferences_io" app:title="Config" /> + + \ No newline at end of file diff --git a/app/src/main/res/xml/preference_mqtt.xml b/app/src/main/res/xml/preference_mqtt.xml new file mode 100644 index 00000000..d4f19db8 --- /dev/null +++ b/app/src/main/res/xml/preference_mqtt.xml @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/settings.gradle b/settings.gradle index 2a01f1ba..f8eb0850 100644 --- a/settings.gradle +++ b/settings.gradle @@ -10,7 +10,9 @@ dependencyResolutionManagement { repositories { google() mavenCentral() - maven { url 'https://jitpack.io' } + maven { + url "https://repo.eclipse.org/content/repositories/paho-snapshots/" + } } } From 7f7effd105a1097f3d7cada5b5eb9eaae7485a7b Mon Sep 17 00:00:00 2001 From: hajoha Date: Mon, 6 Jan 2025 23:29:49 +0100 Subject: [PATCH 03/43] add basic infrastructure for MQTT --- app/build.gradle | 8 +- app/proguard-rules.pro | 5 +- app/src/main/AndroidManifest.xml | 3 +- .../MQTT/MQTTService.java | 174 ++++++++++++++++++ .../MainActivity.java | 24 +++ .../Preferences/SPType.java | 4 + .../MQTTSettingsFragment.java | 14 +- app/src/main/res/values/strings.xml | 1 + app/src/main/res/xml/preference.xml | 11 +- app/src/main/res/xml/preference_mqtt.xml | 3 +- settings.gradle | 4 +- 11 files changed, 235 insertions(+), 16 deletions(-) create mode 100644 app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/MQTT/MQTTService.java diff --git a/app/build.gradle b/app/build.gradle index b1d06d87..66eb91b7 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -34,6 +34,11 @@ def getGitHash = { -> } android { + packagingOptions { + resources { + excludes += ['META-INF/INDEX.LIST', 'META-INF/io.netty.versions.properties'] + } + } signingConfigs { debug { keyAlias keystoreProperties['keyAlias'] @@ -150,8 +155,7 @@ dependencies { implementation 'com.github.anastr:speedviewlib:1.6.1' implementation "androidx.viewpager2:viewpager2:1.1.0" implementation "androidx.compose.material3:material3:1.3.0" - implementation 'org.eclipse.paho:org.eclipse.paho.client.mqttv3:1.1.0' - implementation 'org.eclipse.paho:org.eclipse.paho.android.service:1.1.1' + implementation("com.hivemq:hivemq-mqtt-client:1.3.4") } configurations.implementation { diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro index 9c325e21..a23a8beb 100644 --- a/app/proguard-rules.pro +++ b/app/proguard-rules.pro @@ -29,4 +29,7 @@ -assumenosideeffects class android.util.Log { public static *** d(...); public static *** v(...); -} \ No newline at end of file +} + +-keepclassmembernames class io.netty.** { *; } +-keepclassmembers class org.jctools.** { *; } \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 6a7f0749..fe1d1a36 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -65,7 +65,8 @@ android:foregroundServiceType="location" /> - + { + if(key == null) return; + if (key.equals("mqtt_host")) { + Log.d(TAG, "MQTT Host update: " + sharedPreferences.getString("mqtt_host", "")); + client.disconnect(); + client = Mqtt5Client.builder() + .identifier(UUID.randomUUID().toString()) + .serverHost(sharedPreferences.getString("mqtt_host", "tcp://localhost:1883")) + .buildAsync(); + } + }); + } + + public void createClient(){ + String addressString = mqttSP.getString("mqtt_host", "localhost:1883"); + String host = null; + int port = -1; + try { + host = addressString.split(":")[0]; + port = Integer.parseInt(addressString.split(":")[1]); + } catch (Exception e) { + Log.e(TAG, "createClient: Invalid address string: " + addressString); + return; + } + if(host == null || port == -1){ + Log.e(TAG, "createClient: Invalid address string: " + addressString); + return; + } + InetSocketAddress address = new InetSocketAddress(host, port); + client = Mqtt5Client.builder() + .identifier(UUID.randomUUID().toString()) + .serverAddress(address) + .buildAsync(); + Log.i(TAG, "createClient: Client created with address: " + addressString); + } + + + + + public void publishToTopic(String topic, String message){ + client.publishWith() + .topic(topic) + .qos(MqttQos.EXACTLY_ONCE) + .payload(message.getBytes()) + .send(); + } + + public void disconnectClient(){ + CompletableFuture disconnect = client.disconnect(); + disconnect.whenComplete((aVoid, throwable) -> { + if(throwable != null){ + Log.e(TAG, "disconnectClient: Error disconnecting from MQTT server: " + throwable.getMessage()); + } else { + Log.i(TAG, "disconnectClient: Disconnected from MQTT server"); + } + }); + } + + public void connectClient(){ + CompletableFuture connAck = client.connectWith() + .keepAlive(10) + .send(); + + connAck.whenComplete((mqtt5ConnAck, throwable) -> { + if(throwable != null){ + Log.e(TAG, "connectClient: Error connecting to MQTT server: " + throwable.getMessage()); + } else { + Log.i(TAG, "connectClient: Connected to MQTT server"); + } + }); + } + + private void handleConfigMessage(String topic, String payload){ + // TODO impl + } + + private void handleCommandMessage(String topic, String payload){ + // TODO implement + } + + private void subsribeToConfigTopic(String topic){ + client.subscribeWith() + .topicFilter(topic) + .qos(MqttQos.EXACTLY_ONCE) + .callback(publish -> { + Log.d(TAG, "Received message: " + publish.getTopic()); + String payload = StandardCharsets.UTF_8.decode(publish.getPayload().get()).toString(); + Log.d(TAG, "Received message: " + payload); + }) + .send(); + } + + private void subsribeToCommandTopic(String topic){ + client.subscribeWith() + .topicFilter(topic) + .qos(MqttQos.EXACTLY_ONCE) + .callback(publish -> { + Log.d(TAG, "Received message: " + publish.getTopic()); + String payload = StandardCharsets.UTF_8.decode(publish.getPayload().get()).toString(); + Log.d(TAG, "Received message: " + payload); + }) + .send(); + } + + private void subscribeToAllTopics(){ + // TODO fix hardcoded deviceID + subsribeToConfigTopic("device/OMNT3/config/#"); + subsribeToCommandTopic("device/OMNT3/command/#"); + } + + + @Override + public int onStartCommand(Intent intent, int flags, int startId) { + Log.d(TAG, "onStartCommand: Start logging service"); + GlobalVars gv = GlobalVars.getInstance(); + // setup class variables + context = getApplicationContext(); + mqttSP = SharedPreferencesGrouper.getInstance(context).getSharedPreference(SPType.mqtt_sp); + setupSharedPreferences(); + createClient(); + connectClient(); + + subscribeToAllTopics(); + + return START_STICKY; + } +} diff --git a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/MainActivity.java b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/MainActivity.java index c95d0724..ac2fd976 100644 --- a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/MainActivity.java +++ b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/MainActivity.java @@ -56,6 +56,7 @@ import de.fraunhofer.fokus.OpenMobileNetworkToolkit.DataProvider.DataProvider; import de.fraunhofer.fokus.OpenMobileNetworkToolkit.DataProvider.NetworkCallback; +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.MQTT.MQTTService; import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Preferences.SPType; import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Preferences.SharedPreferencesGrouper; import de.fraunhofer.fokus.OpenMobileNetworkToolkit.WorkProfile.WorkProfileActivity; @@ -69,6 +70,7 @@ public class MainActivity extends AppCompatActivity implements PreferenceFragmen public boolean cp = false; public boolean feature_telephony = false; Intent loggingServiceIntent; + Intent mqttServiceIntent; NavController navController; private Handler requestCellInfoUpdateHandler; private GlobalVars gv; @@ -211,7 +213,29 @@ protected void onCreate(Bundle savedInstanceState) { } } }, SPType.logging_sp); + + mqttServiceIntent = new Intent(this, MQTTService.class); + if (spg.getSharedPreference(SPType.mqtt_sp).getBoolean("enable_mqtt", false)) { + Log.d(TAG, "Start MQTT service"); + context.startService(mqttServiceIntent); + } + + spg.setListener((prefs, key) -> { + if (Objects.equals(key, "enable_mqtt")) { + if (prefs.getBoolean(key, false)) { + Log.d(TAG, "MQTT enabled"); + context.startForegroundService(mqttServiceIntent); + } else { + Log.d(TAG, "MQTT disabled"); + context.stopService(mqttServiceIntent); + } + } + }, SPType.mqtt_sp); + getAppSignature(); + + + } /** diff --git a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Preferences/SPType.java b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Preferences/SPType.java index 772b92cd..893fc16c 100644 --- a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Preferences/SPType.java +++ b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Preferences/SPType.java @@ -17,6 +17,7 @@ public String toString() { case logging_sp: case ping_sp: case carrier_sp: + case mqtt_sp: case mobile_network_sp: return super.toString(); default: @@ -38,12 +39,15 @@ public String toReadable(){ case logging_sp: case ping_sp: case carrier_sp: + case default_sp: return name.substring(0,1).toUpperCase() + name.substring(1); case mobile_network_sp: return "Mobile Network"; case iperf3_sp: return "iPerf3"; + case mqtt_sp: + return "MQTT"; default: return null; } diff --git a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/SettingPreferences/MQTTSettingsFragment.java b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/SettingPreferences/MQTTSettingsFragment.java index b146313f..86b3b564 100644 --- a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/SettingPreferences/MQTTSettingsFragment.java +++ b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/SettingPreferences/MQTTSettingsFragment.java @@ -3,9 +3,11 @@ import android.content.SharedPreferences; import android.os.Bundle; import android.text.InputType; +import android.util.Log; import androidx.annotation.Nullable; import androidx.preference.PreferenceFragmentCompat; +import androidx.preference.SwitchPreferenceCompat; import java.util.Objects; @@ -14,20 +16,26 @@ import de.fraunhofer.fokus.OpenMobileNetworkToolkit.R; public class MQTTSettingsFragment extends PreferenceFragmentCompat implements SharedPreferences.OnSharedPreferenceChangeListener { + private static final String TAG = "MQTTSettingsFragment"; + SwitchPreferenceCompat enable_mqtt_switch; @Override public void onCreatePreferences(@Nullable Bundle savedInstanceState, @Nullable String rootKey) { SharedPreferencesGrouper spg = SharedPreferencesGrouper.getInstance(requireContext()); - getPreferenceManager().setSharedPreferencesName(spg.getSharedPreferenceIdentifier(SPType.logging_sp)); + getPreferenceManager().setSharedPreferencesName(spg.getSharedPreferenceIdentifier(SPType.mqtt_sp)); setPreferencesFromResource(R.xml.preference_mqtt, rootKey); Objects.requireNonNull(getPreferenceScreen().getSharedPreferences()) .registerOnSharedPreferenceChangeListener(this); - + enable_mqtt_switch = findPreference("enable_mqtt"); } @Override public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, @Nullable String key) { - + if(key == null) return; + if (key.equals("enable_mqtt")) { + boolean logger = sharedPreferences.getBoolean("enable_mqtt", false); + Log.d(TAG, "Logger update: " + logger); + } } } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index f1627937..ef4ac27b 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -267,5 +267,6 @@ MQTT Client Password MQTT-Broker Address, including Port MQTT-Broker Address + tcp://192.168.213.89:1883 \ No newline at end of file diff --git a/app/src/main/res/xml/preference.xml b/app/src/main/res/xml/preference.xml index ead89245..679e5216 100644 --- a/app/src/main/res/xml/preference.xml +++ b/app/src/main/res/xml/preference.xml @@ -50,15 +50,16 @@ android:icon="@drawable/baseline_restart_alt_24" app:key="reset_modem" app:title="Reboot Modem" /> + - + \ No newline at end of file diff --git a/app/src/main/res/xml/preference_mqtt.xml b/app/src/main/res/xml/preference_mqtt.xml index d4f19db8..603df722 100644 --- a/app/src/main/res/xml/preference_mqtt.xml +++ b/app/src/main/res/xml/preference_mqtt.xml @@ -30,7 +30,7 @@ Date: Tue, 7 Jan 2025 18:39:37 +0100 Subject: [PATCH 04/43] remove double setupLocalFile() call --- .../fokus/OpenMobileNetworkToolkit/LoggingService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/LoggingService.java b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/LoggingService.java index 4cdf5bc4..ccb9b2e6 100644 --- a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/LoggingService.java +++ b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/LoggingService.java @@ -238,7 +238,7 @@ public int onStartCommand(Intent intent, int flags, int startId) { } if (spg.getSharedPreference(SPType.logging_sp).getBoolean("enable_local_influx_log", false)) { - setupLocalFile(); + //TODO } return START_STICKY; } From 13d9760043306f5875b78887151213a728447ee8 Mon Sep 17 00:00:00 2001 From: hajoha Date: Tue, 7 Jan 2025 22:32:07 +0100 Subject: [PATCH 05/43] update MQTTService --- .../MQTT/MQTTService.java | 252 +++++++++++++++--- .../LoggingSettingsFragment.java | 6 +- app/src/main/res/values/strings.xml | 3 +- 3 files changed, 224 insertions(+), 37 deletions(-) diff --git a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/MQTT/MQTTService.java b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/MQTT/MQTTService.java index 1d71d194..8fcd89a2 100644 --- a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/MQTT/MQTTService.java +++ b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/MQTT/MQTTService.java @@ -1,13 +1,22 @@ package de.fraunhofer.fokus.OpenMobileNetworkToolkit.MQTT; +import android.annotation.SuppressLint; +import android.app.Notification; +import android.app.NotificationManager; +import android.app.PendingIntent; import android.app.Service; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; +import android.graphics.Color; +import android.os.Build; +import android.os.Handler; import android.os.IBinder; +import android.os.Looper; import android.util.Log; import androidx.annotation.Nullable; +import androidx.core.app.NotificationCompat; import com.hivemq.client.mqtt.MqttGlobalPublishFilter; @@ -20,19 +29,24 @@ import java.net.InetAddress; import java.net.InetSocketAddress; import java.nio.charset.StandardCharsets; +import java.util.Objects; import java.util.UUID; import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; import de.fraunhofer.fokus.OpenMobileNetworkToolkit.GlobalVars; +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.MainActivity; import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Preferences.SPType; import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Preferences.SharedPreferencesGrouper; +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.R; public class MQTTService extends Service { private static final String TAG = "MQTTService"; private Context context; private SharedPreferences mqttSP; - + private NotificationCompat.Builder builder; + public NotificationManager nm; + private Handler notificationHandler; private Mqtt5AsyncClient client; private SharedPreferencesGrouper spg; @@ -50,10 +64,8 @@ private void setupSharedPreferences(){ if (key.equals("mqtt_host")) { Log.d(TAG, "MQTT Host update: " + sharedPreferences.getString("mqtt_host", "")); client.disconnect(); - client = Mqtt5Client.builder() - .identifier(UUID.randomUUID().toString()) - .serverHost(sharedPreferences.getString("mqtt_host", "tcp://localhost:1883")) - .buildAsync(); + createClient(); + createNotification(); } }); } @@ -77,12 +89,66 @@ public void createClient(){ client = Mqtt5Client.builder() .identifier(UUID.randomUUID().toString()) .serverAddress(address) + .automaticReconnect() + .initialDelay(200, TimeUnit.MILLISECONDS) + .maxDelay(30, TimeUnit.SECONDS) + .applyAutomaticReconnect() + .addConnectedListener(context -> { + Log.i(TAG, "createClient: Connected to MQTT server"); + createNotification(); + }) + .addDisconnectedListener(context -> { + Log.i(TAG, "createClient: Disconnected from MQTT server"); + createNotification(); + }) .buildAsync(); + Log.i(TAG, "createClient: Client created with address: " + addressString); } + private void createNotification(){ + StringBuilder s = new StringBuilder(); + String address = spg.getSharedPreference(SPType.mqtt_sp).getString("mqtt_host", "None"); + if(address.equals("None")){ + s.append("MQTT Host: None\n"); + } else { + s.append("Host: ").append(address).append("\n"); + s.append("State: ").append(client.getState().toString()).append("\n"); + } + builder.setStyle(new NotificationCompat.BigTextStyle() + .bigText(s)); + nm.notify(3, builder.build()); + } + @Override + public void onCreate() { + super.onCreate(); + nm = getSystemService(NotificationManager.class); + Intent notificationIntent = new Intent(this, MainActivity.class); + PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, PendingIntent.FLAG_IMMUTABLE); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + // create notification + builder = new NotificationCompat.Builder(this, "OMNT_notification_channel") + .setContentTitle(getText(R.string.mqtt_service_running)) + .setSmallIcon(R.mipmap.ic_launcher_foreground) + .setColor(Color.WHITE) + .setContentIntent(pendingIntent) + // prevent to swipe the notification away + .setOngoing(true) + // don't wait 10 seconds to show the notification + .setForegroundServiceBehavior(Notification.FOREGROUND_SERVICE_IMMEDIATE); + } else { + // create notification + builder = new NotificationCompat.Builder(this, "OMNT_notification_channel") + .setContentTitle(getText(R.string.mqtt_service_running)) + .setSmallIcon(R.mipmap.ic_launcher_foreground) + .setColor(Color.WHITE) + .setContentIntent(pendingIntent) + // prevent to swipe the notification away + .setOngoing(true); + } + } public void publishToTopic(String topic, String message){ client.publishWith() @@ -117,58 +183,180 @@ public void connectClient(){ }); } - private void handleConfigMessage(String topic, String payload){ - // TODO impl + private boolean parseBoolean(String value){ + switch (value.toLowerCase()){ + case "true": + case "1": + return true; + case "false": + case "0": + return false; + } + return false; } - private void handleCommandMessage(String topic, String payload){ - // TODO implement - } + private void handleConfigMessage(String topic, String payload){ - private void subsribeToConfigTopic(String topic){ - client.subscribeWith() - .topicFilter(topic) - .qos(MqttQos.EXACTLY_ONCE) - .callback(publish -> { - Log.d(TAG, "Received message: " + publish.getTopic()); - String payload = StandardCharsets.UTF_8.decode(publish.getPayload().get()).toString(); - Log.d(TAG, "Received message: " + payload); - }) - .send(); + + // config logging service + if(topic.contains("/logging/enable")){ + Log.d(TAG, "handleConfigMessage: Enable Logging: " + payload); + spg.getSharedPreference(SPType.logging_sp).edit().putBoolean("enable_logging", parseBoolean(payload)).apply(); + return; + } + + if(topic.contains("/logging/start_on_boot")){ + Log.d(TAG, "handleConfigMessage: Start on Boot: " + payload); + spg.getSharedPreference(SPType.logging_sp).edit().putBoolean("start_logging_on_boot", parseBoolean(payload)).apply(); + return; + } + if(topic.contains("/logging/notification_update_enabled")){ + Log.d(TAG, "handleConfigMessage: Notification Update: " + payload); + spg.getSharedPreference(SPType.logging_sp).edit().putBoolean("enable_notification_update", parseBoolean(payload)).apply(); + return; + } + if(topic.contains("/logging/interval_ms")){ + Log.d(TAG, "handleConfigMessage: Logging Interval: " + payload); + spg.getSharedPreference(SPType.logging_sp).edit().putString("logging_interval", payload).apply(); + return; + } + + // config influxdv_v2 parameter + if(topic.contains("/influxv2/enabled")){ + Log.d(TAG, "handleConfigMessage: Enable Influx: " + payload); + spg.getSharedPreference(SPType.logging_sp).edit().putBoolean("enable_influx", parseBoolean(payload)).apply(); + return; + } + if(topic.contains("/influxv2/address")){ + Log.d(TAG, "handleConfigMessage: Influx Address: " + payload); + spg.getSharedPreference(SPType.logging_sp).edit().putString("influx_URL", payload).apply(); + return; + } + if(topic.contains("/influxv2/token")){ + Log.d(TAG, "handleConfigMessage: Influx Token received!"); + spg.getSharedPreference(SPType.logging_sp).edit().putString("influx_token", payload).apply(); + return; + } + if(topic.contains("/influxv2/bucket")){ + Log.d(TAG, "handleConfigMessage: Influx Bucket: " + payload); + spg.getSharedPreference(SPType.logging_sp).edit().putString("influx_bucket", payload).apply(); + return; + } + if(topic.contains("/influxv2/org")){ + Log.d(TAG, "handleConfigMessage: Influx Org: " + payload); + spg.getSharedPreference(SPType.logging_sp).edit().putString("influx_org", payload).apply(); + return; + } + if(topic.contains("/influxv2/tags")){ + Log.d(TAG, "handleConfigMessage: Influx Tags: " + payload); + //spg.getSharedPreference(SPType.logging_sp).edit().putString("influx_org", payload).apply(); + //TODO + return; + } + + + // config log file + if(topic.contains("/file/enabled")){ + Log.d(TAG, "handleConfigMessage: Enable Local File Log: " + payload); + spg.getSharedPreference(SPType.logging_sp).edit().putBoolean("enable_local_file_log", parseBoolean(payload)).apply(); + return; + } + + // config logging content + if(topic.contains("/content/network_information")){ + Log.d(TAG, "handleConfigMessage: Network Information: " + payload); + spg.getSharedPreference(SPType.logging_sp).edit().putBoolean("influx_network_data", parseBoolean(payload)).apply(); + return; + } + if(topic.contains("/content/signal_information")){ + Log.d(TAG, "handleConfigMessage: Signal Information: " + payload); + spg.getSharedPreference(SPType.logging_sp).edit().putBoolean("log_signal_data", parseBoolean(payload)).apply(); + return; + } + if(topic.contains("/content/cell_information")){ + Log.d(TAG, "handleConfigMessage: Cell Information: " + payload); + spg.getSharedPreference(SPType.logging_sp).edit().putBoolean("influx_cell_data", parseBoolean(payload)).apply(); + return; + } + if(topic.contains("/content/neighbour_cells")){ + Log.d(TAG, "handleConfigMessage: Neighbour Cells: " + payload); + spg.getSharedPreference(SPType.logging_sp).edit().putBoolean("log_neighbour_cells", parseBoolean(payload)).apply(); + return; + } + if(topic.contains("/content/throughput_information")){ + Log.d(TAG, "handleConfigMessage: Throughput Information: " + payload); + spg.getSharedPreference(SPType.logging_sp).edit().putBoolean("influx_throughput_data", parseBoolean(payload)).apply(); + return; + } + if(topic.contains("/content/wifi_information")){ + Log.d(TAG, "handleConfigMessage: Wifi Information: " + payload); + spg.getSharedPreference(SPType.logging_sp).edit().putBoolean("log_wifi_data", parseBoolean(payload)).apply(); + return; + } + if(topic.contains("/content/battery_information")){ + Log.d(TAG, "handleConfigMessage: Battery Information: " + payload); + spg.getSharedPreference(SPType.logging_sp).edit().putBoolean("influx_battery_data", parseBoolean(payload)).apply(); + return; + } + if(topic.contains("/content/ip_information")){ + Log.d(TAG, "handleConfigMessage: IP Information: " + payload); + spg.getSharedPreference(SPType.logging_sp).edit().putBoolean("influx_ip_address_data", parseBoolean(payload)).apply(); + return; + } + + + Log.d(TAG, "handleConfigMessage: No matching topic found: " + topic); + + return; } - private void subsribeToCommandTopic(String topic){ + private void subsribetoTopic(String topic){ client.subscribeWith() .topicFilter(topic) - .qos(MqttQos.EXACTLY_ONCE) + .qos(MqttQos.AT_LEAST_ONCE) .callback(publish -> { - Log.d(TAG, "Received message: " + publish.getTopic()); - String payload = StandardCharsets.UTF_8.decode(publish.getPayload().get()).toString(); - Log.d(TAG, "Received message: " + payload); + if (!publish.getPayload().isPresent()){ + Log.e(TAG, "Received empty payload from topic: " + publish.getTopic()); + return; + }; + new Runnable(){ + @Override + public void run() { + Log.d(TAG, "Received config message: " + publish.getTopic()); + String payload = StandardCharsets.UTF_8.decode(publish.getPayload().get()).toString(); + handleConfigMessage(publish.getTopic().toString(), payload); + } + }.run(); }) - .send(); + .send() + .whenComplete((subAck, throwable) -> { + if(throwable != null){ + Log.e(TAG, "Error subscribing to topic: " + topic + " Error: " + throwable.getMessage()); + } else { + Log.i(TAG, "Subscribed to topic: " + topic); + } + }); } + private void subscribeToAllTopics(){ // TODO fix hardcoded deviceID - subsribeToConfigTopic("device/OMNT3/config/#"); - subsribeToCommandTopic("device/OMNT3/command/#"); + subsribetoTopic("device/OMNT3/#"); } + @Override public int onStartCommand(Intent intent, int flags, int startId) { - Log.d(TAG, "onStartCommand: Start logging service"); - GlobalVars gv = GlobalVars.getInstance(); - // setup class variables + Log.d(TAG, "onStartCommand: Start MQTT service"); context = getApplicationContext(); mqttSP = SharedPreferencesGrouper.getInstance(context).getSharedPreference(SPType.mqtt_sp); setupSharedPreferences(); createClient(); connectClient(); - subscribeToAllTopics(); return START_STICKY; } + } diff --git a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/SettingPreferences/LoggingSettingsFragment.java b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/SettingPreferences/LoggingSettingsFragment.java index d98d2629..d53dea92 100644 --- a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/SettingPreferences/LoggingSettingsFragment.java +++ b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/SettingPreferences/LoggingSettingsFragment.java @@ -33,9 +33,6 @@ public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { getPreferenceScreen().getSharedPreferences() .registerOnSharedPreferenceChangeListener(this); - enable_influx_switch = findPreference("enable_influx"); - - androidx.preference.EditTextPreference editTextPreference = getPreferenceManager().findPreference("logging_interval"); editTextPreference.setOnBindEditTextListener( @@ -45,9 +42,10 @@ public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { @Override public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String s) { if(s == null) return; + Log.d(TAG, "onSharedPreferenceChanged: " + s); if (s.equals("enable_logging")) { boolean logger = sharedPreferences.getBoolean("enable_logging", false); - Log.d(TAG, "Logger update: " + logger); + Log.d(TAG, "onSharedPreferenceChanged: " + logger); } } } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index ef4ac27b..0558064c 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -17,7 +17,7 @@ iPerf3 Send -c 172.17.0.1 - OpenMobileNetworkToolkit logging + Logging Service This app is provided by NGNI a department of Fraunhofer FOKUS. \n\nhttps://www.fokus.fraunhofer.de/go/ngni \n\nThis software is licensed under BSD 3-Clause Clear License https://spdx.org/licenses/BSD-3-Clause-Clear.html \n\nAuthors: \n\nPeter Hasse \nMohsin Nisar \nJohann Hackler OpenMobileNetworkToolkit @@ -268,5 +268,6 @@ MQTT-Broker Address, including Port MQTT-Broker Address tcp://192.168.213.89:1883 + MQTT Service \ No newline at end of file From 97dd0a1debcfe714a7bbc722206c19dc39178a5d Mon Sep 17 00:00:00 2001 From: hajoha Date: Sun, 12 Jan 2025 12:51:32 +0100 Subject: [PATCH 06/43] add Service Type --- app/src/main/AndroidManifest.xml | 6 ++++-- .../OpenMobileNetworkToolkit/MQTT/MQTTService.java | 11 +++++++++++ 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index fe1d1a36..e853c5b6 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -64,9 +64,11 @@ android:name="de.fraunhofer.fokus.OpenMobileNetworkToolkit.LoggingService" android:foregroundServiceType="location" /> + android:name="de.fraunhofer.fokus.OpenMobileNetworkToolkit.Ping.PingService" + android:foregroundServiceType="location"/> + android:name="de.fraunhofer.fokus.OpenMobileNetworkToolkit.MQTT.MQTTService" + android:foregroundServiceType="location"/> connAck = client.connectWith() .keepAlive(10) + .willPublish() + .topic("device/OMNT3/status") + .qos(MqttQos.AT_MOST_ONCE) + .payload("offline".getBytes()) + .retain(true) + .payloadFormatIndicator(Mqtt5PayloadFormatIndicator.UTF_8) + .contentType("text/plain") + .noMessageExpiry() + .applyWillPublish() .send(); connAck.whenComplete((mqtt5ConnAck, throwable) -> { @@ -351,6 +361,7 @@ public int onStartCommand(Intent intent, int flags, int startId) { Log.d(TAG, "onStartCommand: Start MQTT service"); context = getApplicationContext(); mqttSP = SharedPreferencesGrouper.getInstance(context).getSharedPreference(SPType.mqtt_sp); + startForeground(3, builder.build()); setupSharedPreferences(); createClient(); connectClient(); From e843e52a6e1c634fc4884cf8b6bbbb53dd0720b0 Mon Sep 17 00:00:00 2001 From: hajoha Date: Mon, 13 Jan 2025 14:44:20 +0100 Subject: [PATCH 07/43] receive last will exactly once --- .../fokus/OpenMobileNetworkToolkit/MQTT/MQTTService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/MQTT/MQTTService.java b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/MQTT/MQTTService.java index 6f8b6653..dcd299a1 100644 --- a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/MQTT/MQTTService.java +++ b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/MQTT/MQTTService.java @@ -175,7 +175,7 @@ public void connectClient(){ .keepAlive(10) .willPublish() .topic("device/OMNT3/status") - .qos(MqttQos.AT_MOST_ONCE) + .qos(MqttQos.EXACTLY_ONCE) .payload("offline".getBytes()) .retain(true) .payloadFormatIndicator(Mqtt5PayloadFormatIndicator.UTF_8) From c1f340c79219d9ae5d1a24d1955dd47a6c35f9db Mon Sep 17 00:00:00 2001 From: hajoha Date: Tue, 28 Jan 2025 14:15:31 +0100 Subject: [PATCH 08/43] fix typo --- app/src/main/res/values/strings.xml | 4 ++-- app/src/main/res/xml/preference.xml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index a90da53e..a5dfdd99 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -269,8 +269,8 @@ Standard Channel Bandwidth Security Type - Serving Cell Parameter: PCI, RSRP... - Enable Cell Notification + Serving Cell Parameter: PCI, RSRP... + Enable Cell Notification Serving Cell ICMP / Ping Special Codes diff --git a/app/src/main/res/xml/preference.xml b/app/src/main/res/xml/preference.xml index edd39438..332d8d44 100644 --- a/app/src/main/res/xml/preference.xml +++ b/app/src/main/res/xml/preference.xml @@ -25,8 +25,8 @@ + app:summary="@string/enable_radio_notification_summary" + app:title="@string/enable_radio_notification" /> Date: Tue, 28 Jan 2025 14:36:18 +0100 Subject: [PATCH 09/43] move device name setting to main Setting preference and force user to set it before using Logging/MQTT --- .../DataProvider/DataProvider.java | 4 ++++ app/src/main/res/values/strings.xml | 3 +++ app/src/main/res/xml/preference.xml | 17 +++++++++++++++-- 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/DataProvider/DataProvider.java b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/DataProvider/DataProvider.java index 7bfd06c2..9ee6cfd5 100644 --- a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/DataProvider/DataProvider.java +++ b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/DataProvider/DataProvider.java @@ -70,6 +70,7 @@ import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.UUID; import de.fraunhofer.fokus.OpenMobileNetworkToolkit.DataProvider.CellInformations.CDMAInformation; import de.fraunhofer.fokus.OpenMobileNetworkToolkit.DataProvider.CellInformations.CellInformation; @@ -730,6 +731,9 @@ public Map getTagsMap() { tags_map_modifiable.put("sdk_version", String.valueOf(di.getAndroidSDK())); tags_map_modifiable.put("android_version", di.getAndroidRelease()); tags_map_modifiable.put("security_patch", di.getSecurityPatchLevel()); + String device = spg.getSharedPreference(SPType.default_sp).getString("device_name", "null").strip(); + if(device.equals("null")) device = UUID.randomUUID().toString(); + tags_map.put("device", device); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { tags_map_modifiable.put("soc_model", di.getSOCModel()); } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index a5dfdd99..7942d427 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -276,5 +276,8 @@ Special Codes Subscriptions\n About + Notification settings + Unique Device Name + \ No newline at end of file diff --git a/app/src/main/res/xml/preference.xml b/app/src/main/res/xml/preference.xml index 332d8d44..f0b603ba 100644 --- a/app/src/main/res/xml/preference.xml +++ b/app/src/main/res/xml/preference.xml @@ -22,22 +22,33 @@ app:allowDividerAbove="false" app:allowDividerBelow="false" app:iconSpaceReserved="false" /> + + + - + - + + \ No newline at end of file From cee64ce2b20b175a30d7c252b64df5161e9acf38 Mon Sep 17 00:00:00 2001 From: hajoha Date: Tue, 28 Jan 2025 14:42:04 +0100 Subject: [PATCH 10/43] remove UUID generation --- .../OpenMobileNetworkToolkit/DataProvider/DataProvider.java | 2 +- .../fokus/OpenMobileNetworkToolkit/MQTT/MQTTService.java | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/DataProvider/DataProvider.java b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/DataProvider/DataProvider.java index 9ee6cfd5..ef87d8b3 100644 --- a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/DataProvider/DataProvider.java +++ b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/DataProvider/DataProvider.java @@ -732,7 +732,7 @@ public Map getTagsMap() { tags_map_modifiable.put("android_version", di.getAndroidRelease()); tags_map_modifiable.put("security_patch", di.getSecurityPatchLevel()); String device = spg.getSharedPreference(SPType.default_sp).getString("device_name", "null").strip(); - if(device.equals("null")) device = UUID.randomUUID().toString(); + //if(device.equals("null")); TODO handle this tags_map.put("device", device); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { tags_map_modifiable.put("soc_model", di.getSOCModel()); diff --git a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/MQTT/MQTTService.java b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/MQTT/MQTTService.java index dcd299a1..15902768 100644 --- a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/MQTT/MQTTService.java +++ b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/MQTT/MQTTService.java @@ -50,6 +50,7 @@ public class MQTTService extends Service { private Handler notificationHandler; private Mqtt5AsyncClient client; private SharedPreferencesGrouper spg; + private String deviceName; @Nullable @Override @@ -174,7 +175,7 @@ public void connectClient(){ CompletableFuture connAck = client.connectWith() .keepAlive(10) .willPublish() - .topic("device/OMNT3/status") + .topic(String.format("device/%s/status", deviceName)) .qos(MqttQos.EXACTLY_ONCE) .payload("offline".getBytes()) .retain(true) @@ -351,7 +352,7 @@ public void run() { private void subscribeToAllTopics(){ // TODO fix hardcoded deviceID - subsribetoTopic("device/OMNT3/#"); + subsribetoTopic(String.format("device/%s/#", deviceName)); } @@ -361,6 +362,7 @@ public int onStartCommand(Intent intent, int flags, int startId) { Log.d(TAG, "onStartCommand: Start MQTT service"); context = getApplicationContext(); mqttSP = SharedPreferencesGrouper.getInstance(context).getSharedPreference(SPType.mqtt_sp); + deviceName = SharedPreferencesGrouper.getInstance(context).getSharedPreference(SPType.default_sp).getString("device_name", "null").strip(); startForeground(3, builder.build()); setupSharedPreferences(); createClient(); From fb554950ee29d5d78de1783209ff1adfe7288364 Mon Sep 17 00:00:00 2001 From: hajoha Date: Tue, 28 Jan 2025 17:56:55 +0100 Subject: [PATCH 11/43] update LoggingFragment --- .../DataProvider/DataProvider.java | 2 +- .../MQTT/MQTTService.java | 7 ++- .../LoggingSettingsFragment.java | 62 ++++++++++++++++++- .../MQTTSettingsFragment.java | 3 + 4 files changed, 71 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/DataProvider/DataProvider.java b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/DataProvider/DataProvider.java index ef87d8b3..7fb27ced 100644 --- a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/DataProvider/DataProvider.java +++ b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/DataProvider/DataProvider.java @@ -733,7 +733,7 @@ public Map getTagsMap() { tags_map_modifiable.put("security_patch", di.getSecurityPatchLevel()); String device = spg.getSharedPreference(SPType.default_sp).getString("device_name", "null").strip(); //if(device.equals("null")); TODO handle this - tags_map.put("device", device); + tags_map_modifiable.put("device", device); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { tags_map_modifiable.put("soc_model", di.getSOCModel()); } diff --git a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/MQTT/MQTTService.java b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/MQTT/MQTTService.java index 15902768..6775544b 100644 --- a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/MQTT/MQTTService.java +++ b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/MQTT/MQTTService.java @@ -89,7 +89,7 @@ public void createClient(){ } InetSocketAddress address = new InetSocketAddress(host, port); client = Mqtt5Client.builder() - .identifier(UUID.randomUUID().toString()) + .identifier(deviceName) .serverAddress(address) .automaticReconnect() .initialDelay(200, TimeUnit.MILLISECONDS) @@ -274,6 +274,11 @@ private void handleConfigMessage(String topic, String payload){ } // config logging content + if(topic.contains("/content/measurement_name")){ + Log.d(TAG, "handleConfigMessage: Measurement Name: " + payload); + spg.getSharedPreference(SPType.logging_sp).edit().putString("measurement_name", payload).apply(); + return; + } if(topic.contains("/content/network_information")){ Log.d(TAG, "handleConfigMessage: Network Information: " + payload); spg.getSharedPreference(SPType.logging_sp).edit().putBoolean("influx_network_data", parseBoolean(payload)).apply(); diff --git a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/SettingPreferences/LoggingSettingsFragment.java b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/SettingPreferences/LoggingSettingsFragment.java index d53dea92..e2e73caf 100644 --- a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/SettingPreferences/LoggingSettingsFragment.java +++ b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/SettingPreferences/LoggingSettingsFragment.java @@ -13,9 +13,13 @@ import android.text.InputType; import android.util.Log; +import androidx.fragment.app.FragmentTransaction; +import androidx.preference.EditTextPreference; import androidx.preference.PreferenceFragmentCompat; import androidx.preference.SwitchPreferenceCompat; +import java.util.Objects; + import de.fraunhofer.fokus.OpenMobileNetworkToolkit.R; import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Preferences.SPType; import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Preferences.SharedPreferencesGrouper; @@ -30,7 +34,7 @@ public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { SharedPreferencesGrouper spg = SharedPreferencesGrouper.getInstance(requireContext()); getPreferenceManager().setSharedPreferencesName(spg.getSharedPreferenceIdentifier(SPType.logging_sp)); setPreferencesFromResource(R.xml.preference_logging, rootKey); - getPreferenceScreen().getSharedPreferences() + Objects.requireNonNull(getPreferenceScreen().getSharedPreferences()) .registerOnSharedPreferenceChangeListener(this); androidx.preference.EditTextPreference editTextPreference = @@ -38,6 +42,21 @@ public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { editTextPreference.setOnBindEditTextListener( editText -> editText.setInputType(InputType.TYPE_CLASS_NUMBER)); } + @Override + public void onResume() { + super.onResume(); + // Register the listener + Objects.requireNonNull(getPreferenceManager().getSharedPreferences()) + .registerOnSharedPreferenceChangeListener(this); + } + + @Override + public void onPause() { + super.onPause(); + // Unregister the listener to prevent memory leaks + Objects.requireNonNull(getPreferenceManager().getSharedPreferences()) + .unregisterOnSharedPreferenceChangeListener(this); + } @Override public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String s) { @@ -47,5 +66,46 @@ public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, Strin boolean logger = sharedPreferences.getBoolean("enable_logging", false); Log.d(TAG, "onSharedPreferenceChanged: " + logger); } + + switch (s){ + case "enable_logging": + case "start_logging_on_boot": + case "enable_local_influx_log": + case "enable_local_file_log": + case "enable_influx": + case "fake_location": + case "influx_network_data": + case "log_signal_data": + case "influx_cell_data": + case "log_neighbour_cells": + case "influx_throughput_data": + case "log_wifi_data": + case "influx_battery_data": + case "influx_ip_address_data": + boolean booleanValue = sharedPreferences.getBoolean(s, false); + SwitchPreferenceCompat switchPreferenceCompat = findPreference(s); + if (switchPreferenceCompat != null) { + switchPreferenceCompat.setChecked(booleanValue); + } + break; + case "logging_interval": + case "influx_URL": + case "influx_token": + case "influx_org": + case "influx_bucket": + case "measurement_name": + case "tags": + String stringValue = sharedPreferences.getString(s, ""); + EditTextPreference editTextPreference = findPreference(s); + if (editTextPreference != null) { + editTextPreference.setText(stringValue); + } + + break; + + } + } + + } diff --git a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/SettingPreferences/MQTTSettingsFragment.java b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/SettingPreferences/MQTTSettingsFragment.java index 86b3b564..b65c902c 100644 --- a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/SettingPreferences/MQTTSettingsFragment.java +++ b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/SettingPreferences/MQTTSettingsFragment.java @@ -37,5 +37,8 @@ public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, @Null boolean logger = sharedPreferences.getBoolean("enable_mqtt", false); Log.d(TAG, "Logger update: " + logger); } + + + } } From 6722fd541faecff94a47f6d3829d1a47487eab65 Mon Sep 17 00:00:00 2001 From: hajoha Date: Wed, 5 Feb 2025 15:55:00 +0100 Subject: [PATCH 12/43] update --- .../fokus/OpenMobileNetworkToolkit/MQTT/MQTTService.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/MQTT/MQTTService.java b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/MQTT/MQTTService.java index 6775544b..594eac27 100644 --- a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/MQTT/MQTTService.java +++ b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/MQTT/MQTTService.java @@ -320,6 +320,14 @@ private void handleConfigMessage(String topic, String payload){ return; } + if(topic.contains("iperf3/command")){ + Log.d(TAG, "handleConfigMessage: Iperf3 Command: " + payload); + return; + } + if(topic.contains("/iperf3/enable")){ + Log.d(TAG, "handleConfigMessage: Enable Iperf3: " + payload); + return; + } Log.d(TAG, "handleConfigMessage: No matching topic found: " + topic); @@ -356,7 +364,6 @@ public void run() { private void subscribeToAllTopics(){ - // TODO fix hardcoded deviceID subsribetoTopic(String.format("device/%s/#", deviceName)); } From b15c29976b5aaa5e8534e4bfdfe3c4cdc171a736 Mon Sep 17 00:00:00 2001 From: hajoha Date: Fri, 7 Feb 2025 21:06:20 +0100 Subject: [PATCH 13/43] update --- app/build.gradle | 15 +- app/src/main/AndroidManifest.xml | 49 +- .../OpenMobileNetworkToolkit/Application.java | 15 + .../RunResult}/Iperf3ResultsDataBase.java | 6 +- .../RunResult}/Iperf3RunResult.java | 5 +- .../RunResult}/Iperf3RunResultDao.java | 2 +- .../Iperf3/Iperf3Fragment.java | 8 +- .../Iperf3/Iperf3Input.java | 243 +++ .../Iperf3/Iperf3LibLoader.java | 2 +- .../Iperf3/Iperf3ListFragment.java | 4 + .../Iperf3/Iperf3LogFragment.java | 2 + .../Iperf3/Iperf3Parameter.java | 1777 +++++++++++++++++ .../Iperf3/Iperf3Parser.java | 2 +- .../Iperf3/Iperf3RecyclerViewAdapter.java | 5 +- .../Iperf3/Iperf3Worker.java | 121 -- .../Service/Iperf3ServiceWorkerFour.java | 7 + .../Service/Iperf3ServiceWorkerOne.java | 7 + .../Service/Iperf3ServiceWorkerThree.java | 7 + .../Service/Iperf3ServiceWorkerTwo.java | 7 + .../Iperf3/Worker/Iperf3ExecutorWorker.java | 129 ++ .../Iperf3ToLineProtocolWorker.java | 124 +- .../{ => Worker}/Iperf3UploadWorker.java | 18 +- .../MQTT/Handler/Iperf3Handler.java | 103 + .../MQTT/Handler/PingHandler.java | 4 + .../MQTT/MQTTService.java | 19 +- 25 files changed, 2438 insertions(+), 243 deletions(-) create mode 100644 app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Application.java rename app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/{ => Database/RunResult}/Iperf3ResultsDataBase.java (83%) rename app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/{ => Database/RunResult}/Iperf3RunResult.java (84%) rename app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/{ => Database/RunResult}/Iperf3RunResultDao.java (95%) create mode 100644 app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Iperf3Input.java create mode 100644 app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Iperf3Parameter.java delete mode 100644 app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Iperf3Worker.java create mode 100644 app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Service/Iperf3ServiceWorkerFour.java create mode 100644 app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Service/Iperf3ServiceWorkerOne.java create mode 100644 app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Service/Iperf3ServiceWorkerThree.java create mode 100644 app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Service/Iperf3ServiceWorkerTwo.java create mode 100644 app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Worker/Iperf3ExecutorWorker.java rename app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/{ => Worker}/Iperf3ToLineProtocolWorker.java (63%) rename app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/{ => Worker}/Iperf3UploadWorker.java (81%) create mode 100644 app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/MQTT/Handler/Iperf3Handler.java create mode 100644 app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/MQTT/Handler/PingHandler.java diff --git a/app/build.gradle b/app/build.gradle index f9a3a2b3..d2895c99 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -127,10 +127,20 @@ spdxSbom { } dependencies { - implementation 'androidx.preference:preference:1.2.1' - implementation 'androidx.work:work-runtime:2.10.0' + def work_version = "2.10.0" def room_version = "2.6.1" + + implementation "androidx.work:work-runtime:$work_version" + implementation "androidx.work:work-runtime-ktx:$work_version" + implementation "androidx.work:work-rxjava2:$work_version" + implementation "androidx.work:work-gcm:$work_version" + androidTestImplementation "androidx.work:work-testing:$work_version" + implementation "androidx.work:work-multiprocess:$work_version" + + + implementation 'androidx.preference:preference:1.2.1' + implementation "androidx.room:room-runtime:$room_version" annotationProcessor "androidx.room:room-compiler:$room_version" implementation 'androidx.appcompat:appcompat:1.7.0' @@ -157,6 +167,7 @@ dependencies { implementation "androidx.compose.material3:material3:1.3.0" implementation("com.hivemq:hivemq-mqtt-client:1.3.4") implementation "androidx.compose.material3:material3:1.3.1" + } configurations.implementation { diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 684e49b2..bf0063fd 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -40,6 +40,7 @@ + + + + + + + + + + + + + + + + + + - \ No newline at end of file diff --git a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Application.java b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Application.java new file mode 100644 index 00000000..c392e698 --- /dev/null +++ b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Application.java @@ -0,0 +1,15 @@ +package de.fraunhofer.fokus.OpenMobileNetworkToolkit; + +import androidx.annotation.NonNull; +import androidx.work.Configuration; + +public class Application extends android.app.Application implements Configuration.Provider { + @NonNull + @Override + public Configuration getWorkManagerConfiguration() { + return new Configuration.Builder() + .setDefaultProcessName(getPackageName()) + .setMinimumLoggingLevel(android.util.Log.DEBUG) + .build(); + } +} diff --git a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Iperf3ResultsDataBase.java b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Database/RunResult/Iperf3ResultsDataBase.java similarity index 83% rename from app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Iperf3ResultsDataBase.java rename to app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Database/RunResult/Iperf3ResultsDataBase.java index d9b01a29..4ec1f138 100644 --- a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Iperf3ResultsDataBase.java +++ b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Database/RunResult/Iperf3ResultsDataBase.java @@ -6,7 +6,7 @@ * SPDX-License-Identifier: BSD-3-Clause-Clear */ -package de.fraunhofer.fokus.OpenMobileNetworkToolkit.Iperf3; +package de.fraunhofer.fokus.OpenMobileNetworkToolkit.Iperf3.Database.RunResult; import android.content.Context; @@ -14,6 +14,8 @@ import androidx.room.Room; import androidx.room.RoomDatabase; +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Iperf3.Iperf3InputConverter; + @Database( entities = {Iperf3RunResult.class}, version = 3 @@ -21,7 +23,7 @@ public abstract class Iperf3ResultsDataBase extends RoomDatabase { private static volatile Iperf3ResultsDataBase INSTANCE; - static Iperf3ResultsDataBase getDatabase(final Context context) { + public static Iperf3ResultsDataBase getDatabase(final Context context) { if (INSTANCE == null) { synchronized (Iperf3ResultsDataBase.class) { if (INSTANCE == null) { diff --git a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Iperf3RunResult.java b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Database/RunResult/Iperf3RunResult.java similarity index 84% rename from app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Iperf3RunResult.java rename to app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Database/RunResult/Iperf3RunResult.java index 1a7f9854..aa30329d 100644 --- a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Iperf3RunResult.java +++ b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Database/RunResult/Iperf3RunResult.java @@ -6,7 +6,7 @@ * SPDX-License-Identifier: BSD-3-Clause-Clear */ -package de.fraunhofer.fokus.OpenMobileNetworkToolkit.Iperf3; +package de.fraunhofer.fokus.OpenMobileNetworkToolkit.Iperf3.Database.RunResult; import androidx.annotation.NonNull; import androidx.room.ColumnInfo; @@ -16,6 +16,9 @@ import java.sql.Timestamp; +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Iperf3.Iperf3Fragment; +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Iperf3.Iperf3InputConverter; + @Entity(tableName = "iperf3_result_database") public class Iperf3RunResult { @NonNull diff --git a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Iperf3RunResultDao.java b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Database/RunResult/Iperf3RunResultDao.java similarity index 95% rename from app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Iperf3RunResultDao.java rename to app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Database/RunResult/Iperf3RunResultDao.java index 158823aa..d909e77c 100644 --- a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Iperf3RunResultDao.java +++ b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Database/RunResult/Iperf3RunResultDao.java @@ -6,7 +6,7 @@ * SPDX-License-Identifier: BSD-3-Clause-Clear */ -package de.fraunhofer.fokus.OpenMobileNetworkToolkit.Iperf3; +package de.fraunhofer.fokus.OpenMobileNetworkToolkit.Iperf3.Database.RunResult; import androidx.lifecycle.LiveData; import androidx.room.Dao; diff --git a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Iperf3Fragment.java b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Iperf3Fragment.java index ff16e37c..6ee2773e 100644 --- a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Iperf3Fragment.java +++ b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Iperf3Fragment.java @@ -59,6 +59,12 @@ import java.util.List; import java.util.UUID; +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Iperf3.Database.RunResult.Iperf3ResultsDataBase; +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Iperf3.Database.RunResult.Iperf3RunResult; +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Iperf3.Database.RunResult.Iperf3RunResultDao; +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Iperf3.Worker.Iperf3ExecutorWorker; +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Iperf3.Worker.Iperf3ToLineProtocolWorker; +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Iperf3.Worker.Iperf3UploadWorker; import de.fraunhofer.fokus.OpenMobileNetworkToolkit.R; import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Preferences.SPType; import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Preferences.SharedPreferencesGrouper; @@ -458,7 +464,7 @@ public void executeIperfCommand(View view) { OneTimeWorkRequest iperf3WR = new OneTimeWorkRequest - .Builder(Iperf3Worker.class) + .Builder(Iperf3ExecutorWorker.class) .setInputData(iperf3Data.build()) .addTag("iperf3Run") .addTag(iperf3WorkerID) diff --git a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Iperf3Input.java b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Iperf3Input.java new file mode 100644 index 00000000..20dc68bd --- /dev/null +++ b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Iperf3Input.java @@ -0,0 +1,243 @@ +package de.fraunhofer.fokus.OpenMobileNetworkToolkit.Iperf3; + +import static androidx.work.multiprocess.RemoteListenableWorker.ARGUMENT_CLASS_NAME; +import static androidx.work.multiprocess.RemoteListenableWorker.ARGUMENT_PACKAGE_NAME; + +import android.content.ComponentName; +import android.os.Environment; +import android.os.Parcel; +import android.os.Parcelable; + +import androidx.annotation.NonNull; +import androidx.work.Data; +import androidx.work.OneTimeWorkRequest; +import androidx.work.multiprocess.RemoteWorkerService; + + +import com.google.gson.GsonBuilder; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.sql.Timestamp; + +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Iperf3.Service.Iperf3ServiceWorkerFour; +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Iperf3.Service.Iperf3ServiceWorkerThree; +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Iperf3.Service.Iperf3ServiceWorkerTwo; +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Iperf3.Worker.Iperf3ExecutorWorker; +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Iperf3.Service.Iperf3ServiceWorkerOne; +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Iperf3.Worker.Iperf3ToLineProtocolWorker; +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Iperf3.Worker.Iperf3UploadWorker; + + +public class Iperf3Input implements Parcelable { + public static final String[] EXCLUDED_FIELDS = { + "measurementName", "rawFile", "logFileName", "command", "lineProtocolFile", + "context", "timestamp", "uuid", "cardView", "main", "EXCLUDED_FIELDS" + }; + + + public static final String rootPath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS).getAbsolutePath(); + public static final String jsonDirPath = rootPath+"/omnt/iperf3/json/"; + public static final String lineProtocolDirPath = rootPath+"/omnt/iperf3/lineprotocol/"; + private static final String TAG = "Iperf3Input"; + public static final String IPERF3INPUT = "iperf3input"; + public static final String TESTUUID = "testUUID"; + public static final String SEQUENCEUUID = "sequenceUUID"; + public static final String MEASUREMENTUUID = "measurementUUID"; + public static final String CAMPAIGNUUID = "campaignUUID"; + public static final String IPERF3UUID = "iPerf3UUID"; + protected Iperf3Input(Parcel in) { + rawFile = in.readString(); + iperf3Parameter = in.readParcelable(Iperf3Parameter.class.getClassLoader()); + testUUID = in.readString(); + logFileName = in.readString(); + measurementName = in.readString(); + lineProtocolFile = in.readString(); + timestamp = (Timestamp) in.readSerializable(); + } + + public static final Creator CREATOR = new Creator<>() { + @Override + public Iperf3Input createFromParcel(Parcel in) { + return new Iperf3Input(in); + } + + @Override + public Iperf3Input[] newArray(int size) { + return new Iperf3Input[size]; + } + }; + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(@NonNull Parcel parcel, int i) { + + parcel.writeString(rawFile); + parcel.writeParcelable(iperf3Parameter, i); + parcel.writeString(testUUID); + parcel.writeString(logFileName); + parcel.writeString(measurementName); + parcel.writeString(lineProtocolFile); + parcel.writeSerializable(timestamp); + } + private String rawFile; + private Iperf3Parameter iperf3Parameter; + private String testUUID; + private String logFileName; + private String measurementName; + private String lineProtocolFile; + private Timestamp timestamp; + private String campaignUUID; + private String sequenceUUID; + private String measurementUUID; + public Iperf3Input(Iperf3Parameter iperf3Parameter, + String testUUID, + String sequenceUUID, + String measurementUUID, + String campaignUUID) { + try { + this.iperf3Parameter = iperf3Parameter; + } catch (IllegalArgumentException e) { + e.printStackTrace(); + return; + } + this.testUUID = testUUID; + this.sequenceUUID = sequenceUUID; + this.measurementUUID = measurementUUID; + this.campaignUUID = campaignUUID; + this.rawFile = jsonDirPath+this.testUUID +".json"; + this.lineProtocolFile = lineProtocolDirPath+this.testUUID +".txt"; + this.timestamp = new Timestamp(System.currentTimeMillis()); + } + + public Iperf3Parameter getIperf3Parameter() { + return iperf3Parameter; + } + + public String getTestUUID() { + return testUUID; + } + + public String getSequenceUUID() { + return sequenceUUID; + } + + public String getCampaignUUID() { + return campaignUUID; + } + + public String getMeasurementUUID() { + return measurementUUID; + } + + public String getRawFile() { + return rawFile; + } + + public String getLogFileName() { + return logFileName; + } + + public String getLineProtocolFile() { + return lineProtocolFile; + } + + public Timestamp getTimestamp() { + return timestamp; + } + + public Data.Builder getInputAsDataBuilder(int i, String packageName) { + Data.Builder data = new Data.Builder(); + String serviceName = ""; + switch (i){ + case 0: + serviceName = Iperf3ServiceWorkerOne.class.getName(); + break; + case 1: + serviceName = Iperf3ServiceWorkerTwo.class.getName(); + break; + case 2: + serviceName = Iperf3ServiceWorkerThree.class.getName(); + break; + case 3: + serviceName = Iperf3ServiceWorkerFour.class.getName(); + break; + default: + break; + + } + ComponentName componentName = new ComponentName(packageName, serviceName); + + data.putString(ARGUMENT_PACKAGE_NAME, componentName.getPackageName()); + data.putString(ARGUMENT_CLASS_NAME, componentName.getClassName()); + data.putInt("notificationNumber", i); + data.putString(IPERF3INPUT, new GsonBuilder().create().toJson(this, Iperf3Input.class)); + return data; + } + + public OneTimeWorkRequest getWorkRequestExecutor(int i, String packageName) { + OneTimeWorkRequest workRequest = new OneTimeWorkRequest.Builder(Iperf3ExecutorWorker.class) + .addTag(testUUID) + .addTag(iperf3Parameter.getiPerf3UUID()) + .addTag(measurementUUID) + .addTag(sequenceUUID) + .addTag(campaignUUID) + .setInputData(getInputAsDataBuilder(i, packageName).build()) + .build(); + return workRequest; + } + + public OneTimeWorkRequest getWorkRequestLineProtocol() { + OneTimeWorkRequest workRequest = new OneTimeWorkRequest.Builder(Iperf3ToLineProtocolWorker.class) + .addTag(testUUID) + .addTag(iperf3Parameter.getiPerf3UUID()) + .addTag(measurementUUID) + .addTag(sequenceUUID) + .addTag(campaignUUID) + // .setInputData(getInputAsDataBuilder().build()) + .build(); + return workRequest; + } + + public OneTimeWorkRequest getWorkRequestUpload() { + OneTimeWorkRequest workRequest = new OneTimeWorkRequest.Builder(Iperf3UploadWorker.class) + .addTag(testUUID) + .addTag(iperf3Parameter.getiPerf3UUID()) + .addTag(measurementUUID) + .addTag(sequenceUUID) + .addTag(campaignUUID) + //.setInputData(getInputAsDataBuilder().build()) + .build(); + return workRequest; + } + + + public static byte[] convertToBytes(Iperf3Input object) throws IOException { + try (ByteArrayOutputStream bos = new ByteArrayOutputStream(); + ObjectOutputStream out = new ObjectOutputStream(bos)) { + out.writeObject(object); + return bos.toByteArray(); + } + } + + public static Object convertFromBytes(byte[] bytes) throws IOException, ClassNotFoundException { + try (ByteArrayInputStream bis = new ByteArrayInputStream(bytes); + ObjectInputStream in = new ObjectInputStream(bis)) { + return in.readObject(); + } + } + + + + + + + +} \ No newline at end of file diff --git a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Iperf3LibLoader.java b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Iperf3LibLoader.java index c8d20e25..96075272 100644 --- a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Iperf3LibLoader.java +++ b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Iperf3LibLoader.java @@ -27,7 +27,7 @@ public class Iperf3LibLoader { "iperf3.17.1" ); - protected static synchronized void load() { + public static synchronized void load() { if (done) { return; } diff --git a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Iperf3ListFragment.java b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Iperf3ListFragment.java index 6ae30a5d..ef896f0d 100644 --- a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Iperf3ListFragment.java +++ b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Iperf3ListFragment.java @@ -32,6 +32,10 @@ import java.util.ArrayList; +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Iperf3.Database.RunResult.Iperf3ResultsDataBase; +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Iperf3.Database.RunResult.Iperf3RunResult; +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Iperf3.Database.RunResult.Iperf3RunResultDao; +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Iperf3.Worker.Iperf3ToLineProtocolWorker; import de.fraunhofer.fokus.OpenMobileNetworkToolkit.R; import de.fraunhofer.fokus.OpenMobileNetworkToolkit.SwipeController; import de.fraunhofer.fokus.OpenMobileNetworkToolkit.SwipeControllerActions; diff --git a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Iperf3LogFragment.java b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Iperf3LogFragment.java index d6364041..c8372b74 100644 --- a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Iperf3LogFragment.java +++ b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Iperf3LogFragment.java @@ -29,6 +29,8 @@ import androidx.core.widget.TextViewCompat; import androidx.fragment.app.Fragment; +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Iperf3.Database.RunResult.Iperf3ResultsDataBase; +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Iperf3.Database.RunResult.Iperf3RunResult; import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Iperf3.JSON.Error; import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Iperf3.JSON.Interval.Interval; import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Iperf3.JSON.Interval.Sum.SUM_TYPE; diff --git a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Iperf3Parameter.java b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Iperf3Parameter.java new file mode 100644 index 00000000..c115ed01 --- /dev/null +++ b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Iperf3Parameter.java @@ -0,0 +1,1777 @@ +package de.fraunhofer.fokus.OpenMobileNetworkToolkit.Iperf3; + +import android.os.Parcel; +import android.os.Parcelable; +import android.util.Log; + +import androidx.annotation.NonNull; + +import org.json.JSONException; +import org.json.JSONObject; + +import java.util.ArrayList; + +public class Iperf3Parameter implements Parcelable { + public static final String HOST = "host"; + public static final String PORT = "port"; + public static final String BANDWIDTH = "bandwidth"; + public static final String INTERVAL = "interval"; + public static final String BYTES = "bytes"; + public static final String STREAMS = "streams"; + public static final String DIRECTION = "direction"; + public static final String ONEOFF = "oneOff"; + public static final String CPORT = "cport"; + public static final String TESTUUID = "testUUID"; + public static final String USERNAME = "username"; + public static final String RSAPUBLICKEYPATH = "rsaPublicKeyPath"; + public static final String EXTRADATA = "extraData"; + public static final String TITLE = "title"; + public static final String OMIT = "omit"; + public static final String ZEROCOPY = "zerocopy"; + public static final String FLOWLABEL = "flowlabel"; + public static final String DSCP = "dscp"; + public static final String TOS = "tos"; + public static final String VERSION6 = "version6"; + public static final String VERSION4 = "version4"; + public static final String NODELAY = "noDelay"; + public static final String SETMSS = "setMss"; + public static final String CONGESTION = "congestion"; + public static final String WINDOW = "window"; + public static final String PARALLEL = "parallel"; + public static final String BLOCKCOUNT = "blockcount"; + public static final String TIME = "time"; + public static final String FQRATE = "fqRate"; + public static final String PACINGTIMER = "pacingTimer"; + public static final String CONNECTTIMEOUT = "connectTimeout"; + public static final String UDP = "udp"; + public static final String XBIND = "xbind"; + public static final String SCTP = "sctp"; + public static final String USEPKCS1PADDING = "usePkcs1Padding"; + public static final String TIMESKEWTHRESHOLD = "timeSkewThreshold"; + public static final String AUTHORIZEDUSERSPATH = "authorizedUsersPath"; + public static final String RSAPRIVATEKEYPATH = "rsaPrivateKeyPath"; + public static final String IDLETIMEOUT = "idleTimeout"; + public static final String SERVERBITRATELIMIT = "serverBitrateLimit"; + + public static final String SERVER = "server"; + public static final String CLIENT = "client"; + public static final String DAEMON = "daemon"; + public static final String HELP = "help"; + public static final String VERSION = "version"; + public static final String DEBUG = "debug"; + public static final String SNDTIMEOUT = "sndTimeout"; + public static final String RCVTIMEOUT = "rcvTimeout"; + public static final String TIMESTAMPS = "timestamps"; + public static final String FORCEFLUSH = "forceflush"; + public static final String LOGFILE = "logfile"; + + public static final String JSON = "json"; + public static final String VERBOSE = "verbose"; + public static final String BINDDEV = "bindDev"; + public static final String BIND = "bind"; + public static final String AFFINITY = "affinity"; + public static final String FILE = "file"; + public static final String MODE = "mode"; + public static final String PROTOCOL = "protocol"; + public static final String IPERF3UUID = "iperf3UUID"; + + private static final String TAG = "Iperf3Parameter"; + + protected Iperf3Parameter(Parcel in) { + host = in.readString(); + iPerf3UUID = in.readString(); + duration = in.readInt(); + port = in.readInt(); + interval = in.readDouble(); + bitrate = in.readString(); + length = in.readInt(); + pidfile = in.readString(); + file = in.readString(); + affinity = in.readString(); + bind = in.readString(); + bindDev = in.readString(); + byte tmpVerbose = in.readByte(); + verbose = tmpVerbose == 0 ? null : tmpVerbose == 1; + byte tmpJson = in.readByte(); + json = tmpJson == 0 ? null : tmpJson == 1; + byte tmpJsonStream = in.readByte(); + jsonStream = tmpJsonStream == 0 ? null : tmpJsonStream == 1; + logfile = in.readString(); + byte tmpForceflush = in.readByte(); + forceflush = tmpForceflush == 0 ? null : tmpForceflush == 1; + timestamps = in.readString(); + if (in.readByte() == 0) { + rcvTimeout = null; + } else { + rcvTimeout = in.readInt(); + } + if (in.readByte() == 0) { + sndTimeout = null; + } else { + sndTimeout = in.readInt(); + } + if (in.readByte() == 0) { + debug = null; + } else { + debug = in.readInt(); + } + byte tmpVersion = in.readByte(); + version = tmpVersion == 0 ? null : tmpVersion == 1; + byte tmpHelp = in.readByte(); + help = tmpHelp == 0 ? null : tmpHelp == 1; + byte tmpDaemon = in.readByte(); + daemon = tmpDaemon == 0 ? null : tmpDaemon == 1; + byte tmpOneOff = in.readByte(); + oneOff = tmpOneOff == 0 ? null : tmpOneOff == 1; + serverBitrateLimit = in.readString(); + if (in.readByte() == 0) { + idleTimeout = null; + } else { + idleTimeout = in.readInt(); + } + rsaPrivateKeyPath = in.readString(); + authorizedUsersPath = in.readString(); + if (in.readByte() == 0) { + timeSkewThreshold = null; + } else { + timeSkewThreshold = in.readInt(); + } + byte tmpUsePkcs1Padding = in.readByte(); + usePkcs1Padding = tmpUsePkcs1Padding == 0 ? null : tmpUsePkcs1Padding == 1; + byte tmpSctp = in.readByte(); + sctp = tmpSctp == 0 ? null : tmpSctp == 1; + xbind = in.readString(); + if (in.readByte() == 0) { + nstreams = null; + } else { + nstreams = in.readInt(); + } + if (in.readByte() == 0) { + connectTimeout = null; + } else { + connectTimeout = in.readInt(); + } + pacingTimer = in.readString(); + fqRate = in.readString(); + if (in.readByte() == 0) { + time = null; + } else { + time = in.readInt(); + } + bytes = in.readString(); + blockcount = in.readString(); + if (in.readByte() == 0) { + cport = null; + } else { + cport = in.readInt(); + } + if (in.readByte() == 0) { + parallel = null; + } else { + parallel = in.readInt(); + } + byte tmpReverse = in.readByte(); + reverse = tmpReverse == 0 ? null : tmpReverse == 1; + byte tmpBidir = in.readByte(); + bidir = tmpBidir == 0 ? null : tmpBidir == 1; + window = in.readString(); + congestion = in.readString(); + if (in.readByte() == 0) { + setMss = null; + } else { + setMss = in.readInt(); + } + byte tmpNoDelay = in.readByte(); + noDelay = tmpNoDelay == 0 ? null : tmpNoDelay == 1; + byte tmpVersion4 = in.readByte(); + version4 = tmpVersion4 == 0 ? null : tmpVersion4 == 1; + byte tmpVersion6 = in.readByte(); + version6 = tmpVersion6 == 0 ? null : tmpVersion6 == 1; + if (in.readByte() == 0) { + tos = null; + } else { + tos = in.readInt(); + } + dscp = in.readString(); + if (in.readByte() == 0) { + flowlabel = null; + } else { + flowlabel = in.readInt(); + } + byte tmpZerocopy = in.readByte(); + zerocopy = tmpZerocopy == 0 ? null : tmpZerocopy == 1; + if (in.readByte() == 0) { + omit = null; + } else { + omit = in.readInt(); + } + title = in.readString(); + extraData = in.readString(); + byte tmpGetServerOutput = in.readByte(); + getServerOutput = tmpGetServerOutput == 0 ? null : tmpGetServerOutput == 1; + byte tmpUdpCounters64bit = in.readByte(); + udpCounters64bit = tmpUdpCounters64bit == 0 ? null : tmpUdpCounters64bit == 1; + byte tmpRepeatingPayload = in.readByte(); + repeatingPayload = tmpRepeatingPayload == 0 ? null : tmpRepeatingPayload == 1; + byte tmpDontFragment = in.readByte(); + dontFragment = tmpDontFragment == 0 ? null : tmpDontFragment == 1; + username = in.readString(); + rsaPublicKeyPath = in.readString(); + } + + public static final Creator CREATOR = new Creator() { + @Override + public Iperf3Parameter createFromParcel(Parcel in) { + return new Iperf3Parameter(in); + } + + @Override + public Iperf3Parameter[] newArray(int size) { + return new Iperf3Parameter[size]; + } + }; + + public Iperf3Parameter(String ip, + String iPerf3UUID, + int duration, + Iperf3Protocol protocol, + int port, + double interval, + String bitrate, + int length, + Iperf3Mode mode, + Iperf3Direction direction, + String pidfile, + String file, + String affinity, + String bind, + String bindDev, + Boolean verbose, + Boolean json, + Boolean jsonStream, + String logfile, + Boolean forceflush, + String timestamps, + Integer rcvTimeout, + Integer sndTimeout, + Integer debug, + Boolean version, + Boolean help, + Boolean daemon, + Boolean oneOff, + String serverBitrateLimit, + Integer idleTimeout, + String rsaPrivateKeyPath, + String authorizedUsersPath, + Integer timeSkewThreshold, + Boolean usePkcs1Padding, + Boolean sctp, + String xbind, + Integer nstreams, + Integer connectTimeout, + String pacingTimer, + String fqRate, + Integer time, + String bytes, + String blockcount, + Integer cport, + Integer parallel, + Boolean reverse, + Boolean bidir, + String window, + String congestion, + Integer setMss, + Boolean noDelay, + Boolean version4, + Boolean version6, + Integer tos, + String dscp, + Integer flowlabel, + Boolean zerocopy, + Integer omit, + String title, + String extraData, + Boolean getServerOutput, + Boolean udpCounters64bit, + Boolean repeatingPayload, + Boolean dontFragment, + String username, + String rsaPublicKeyPath) { + this.host = ip; + this.iPerf3UUID = iPerf3UUID; + this.duration = duration; + this.protocol = protocol; + this.port = port; + this.interval = interval; + this.bitrate = bitrate; + this.length = length; + this.mode = mode; + this.direction = direction; + this.pidfile = pidfile; + this.file = file; + this.affinity = affinity; + this.bind = bind; + this.bindDev = bindDev; + this.verbose = verbose; + this.json = json; + this.jsonStream = jsonStream; + this.logfile = logfile; + this.forceflush = forceflush; + this.timestamps = timestamps; + this.rcvTimeout = rcvTimeout; + this.sndTimeout = sndTimeout; + this.debug = debug; + this.version = version; + this.help = help; + this.daemon = daemon; + this.oneOff = oneOff; + this.serverBitrateLimit = serverBitrateLimit; + this.idleTimeout = idleTimeout; + this.rsaPrivateKeyPath = rsaPrivateKeyPath; + this.authorizedUsersPath = authorizedUsersPath; + this.timeSkewThreshold = timeSkewThreshold; + this.usePkcs1Padding = usePkcs1Padding; + this.sctp = sctp; + this.xbind = xbind; + this.nstreams = nstreams; + this.connectTimeout = connectTimeout; + this.pacingTimer = pacingTimer; + this.fqRate = fqRate; + this.time = time; + this.bytes = bytes; + this.blockcount = blockcount; + this.cport = cport; + this.parallel = parallel; + this.reverse = reverse; + this.bidir = bidir; + this.window = window; + this.congestion = congestion; + this.setMss = setMss; + this.noDelay = noDelay; + this.version4 = version4; + this.version6 = version6; + this.tos = tos; + this.dscp = dscp; + this.flowlabel = flowlabel; + this.zerocopy = zerocopy; + this.omit = omit; + this.title = title; + this.extraData = extraData; + this.getServerOutput = getServerOutput; + this.udpCounters64bit = udpCounters64bit; + this.repeatingPayload = repeatingPayload; + this.dontFragment = dontFragment; + this.username = username; + this.rsaPublicKeyPath = rsaPublicKeyPath; + } + + public Iperf3Parameter(JSONObject jsonObject) { + try { + this.host = jsonObject.getString(HOST); + } catch (JSONException e) { + return; + } + try { + this.iPerf3UUID = jsonObject.getString(IPERF3UUID); + } catch (JSONException e) { + throw new IllegalArgumentException("Iperf3Parameter: iPerf3UUID is required."); + } + try { + this.port = jsonObject.getInt(PORT); + } catch (JSONException e) { + Log.d(TAG, "port is not set. Defaulting to iPerf3 default Port."); + } + try { + this.bitrate = jsonObject.getString(BANDWIDTH); + } catch (JSONException e) { + Log.d(TAG, "bitrate is not set. Defaulting to iPerf3 default bitrate."); + } + try { + this.time = jsonObject.getInt(TIME); + } catch (JSONException e) { + Log.d(TAG, "duration is not set. Defaulting to iPerf3 default duration."); + } + + try { + this.interval = jsonObject.getDouble(INTERVAL); + } catch (JSONException e) { + Log.d(TAG, "interval is not set. Defaulting to iPerf3 default interval."); + } + try { + this.length = jsonObject.getInt(BYTES); + } catch (JSONException e) { + Log.d(TAG, "Length not set."); + } + try { + this.nstreams = jsonObject.getInt(STREAMS); + } catch (JSONException e) { + Log.d(TAG, "nstreams not set."); + } + try { + this.direction = Iperf3Direction.valueOf(jsonObject.getString(DIRECTION).toUpperCase().trim()); + } catch (JSONException e) { + this.direction = Iperf3Direction.UP; + Log.d(TAG, "direction not set."); + } + try { + this.oneOff = jsonObject.getBoolean(ONEOFF); + } catch (JSONException e) { + Log.d(TAG, "oneOff not set."); + } + try { + this.protocol = Iperf3Protocol.valueOf(jsonObject.getString(PROTOCOL).toUpperCase().trim()); + } catch (JSONException | IllegalArgumentException e) { + Log.d(TAG, "protocol not set."+e.getMessage()); + Log.e(TAG, "Iperf3Parameter: No matching Protocol found! Using TCP as default."); + this.protocol = Iperf3Protocol.TCP; + } + try { + boolean isServer = false, isClient = false; + try { + // check if server + isServer = jsonObject.getBoolean(SERVER); + } catch (JSONException e) { + Log.d(TAG, "mode not set."); + } + try { + //check if client + jsonObject.getString(HOST); + isClient = true; + } catch (JSONException e) { + isClient = false; + Log.d(TAG, "mode not set."); + } + // check if both are set + if(isServer && isClient){ + throw new IllegalArgumentException("Iperf3Parameter: Server and Client mode cannot be set at the same time."); + } + // check if none is set + if(isServer){ + this.mode = Iperf3Mode.SERVER; + } else if(isClient){ + this.mode = Iperf3Mode.CLIENT; + } else { + throw new IllegalArgumentException("Iperf3Parameter: Server or Client mode must be set."); + } + } catch (IllegalArgumentException e) { + Log.d(TAG, "mode not set."); + Log.e(TAG, e.getMessage()); + } + try { + this.cport = jsonObject.getInt(CPORT); + } catch (JSONException e) { + Log.d(TAG, "cport not set."); + } + + try{ + this.username = jsonObject.getString(USERNAME); + } catch (JSONException e) { + Log.d(TAG, "username not set."); + } + try{ + this.rsaPublicKeyPath = jsonObject.getString(RSAPUBLICKEYPATH); + } catch (JSONException e) { + Log.d(TAG, "rsaPublicKeyPath not set."); + } + try{ + this.extraData = jsonObject.getString(EXTRADATA); + } catch (JSONException e) { + Log.d(TAG, "extraData not set."); + } + try{ + this.title = jsonObject.getString(TIME); + } catch (JSONException e) { + Log.d(TAG, "title not set."); + } + try{ + this.omit = jsonObject.getInt(OMIT); + } catch (JSONException e) { + Log.d(TAG, "omit not set."); + } + try{ + this.zerocopy = jsonObject.getBoolean(ZEROCOPY); + } catch (JSONException e) { + Log.d(TAG, "zerocopy not set."); + } + try{ + this.flowlabel = jsonObject.getInt(FLOWLABEL); + } catch (JSONException e) { + Log.d(TAG, "flowlabel not set."); + } + try{ + this.dscp = jsonObject.getString(DSCP); + } catch (JSONException e) { + Log.d(TAG, "dscp not set."); + } + try{ + this.tos = jsonObject.getInt(TOS); + } catch (JSONException e) { + Log.d(TAG, "tos not set."); + } + try{ + this.version6 = jsonObject.getBoolean(VERSION6); + } catch (JSONException e) { + Log.d(TAG, "version6 not set."); + } + try{ + this.version4 = jsonObject.getBoolean(VERSION4); + } catch (JSONException e) { + Log.d(TAG, "version4 not set."); + } + try{ + this.noDelay = jsonObject.getBoolean(NODELAY); + } catch (JSONException e) { + Log.d(TAG, "noDelay not set."); + } + try{ + this.setMss = jsonObject.getInt(SETMSS); + } catch (JSONException e) { + Log.d(TAG, "setMss not set."); + } + try{ + this.congestion = jsonObject.getString(CONGESTION); + } catch (JSONException e) { + Log.d(TAG, "congestion not set."); + } + try{ + this.window = jsonObject.getString(WINDOW); + } catch (JSONException e) { + Log.d(TAG, "window not set."); + } + + try{ + this.parallel = jsonObject.getInt(PARALLEL); + } catch (JSONException e) { + Log.d(TAG, "parallel not set."); + } + try{ + this.cport = jsonObject.getInt(STREAMS); + } catch (JSONException e) { + Log.d(TAG, "cport not set."); + } + try{ + this.blockcount = jsonObject.getString(BLOCKCOUNT); + } catch (JSONException e) { + Log.d(TAG, "blockcount not set."); + } + try{ + this.bytes = jsonObject.getString(BYTES); + } catch (JSONException e) { + Log.d(TAG, "bytes not set."); + } + try{ + this.time = jsonObject.getInt(TIME); + } catch (JSONException e) { + Log.d(TAG, "time not set."); + } + try{ + this.fqRate = jsonObject.getString(FQRATE); + } catch (JSONException e) { + Log.d(TAG, "fqRate not set."); + } + try{ + this.pacingTimer = jsonObject.getString(PACINGTIMER); + } catch (JSONException e) { + Log.d(TAG, "pacingTimer not set."); + } + try{ + this.connectTimeout = jsonObject.getInt(CONNECTTIMEOUT); + } catch (JSONException e) { + Log.d(TAG, "connectTimeout not set."); + } + try{ + this.xbind = jsonObject.getString(XBIND); + } catch (JSONException e) { + Log.d(TAG, "xbind not set."); + } + try{ + this.sctp = jsonObject.getBoolean(SCTP); + } catch (JSONException e) { + Log.d(TAG, "sctp not set."); + } + try{ + this.usePkcs1Padding = jsonObject.getBoolean(USEPKCS1PADDING); + } catch (JSONException e) { + Log.d(TAG, "usePkcs1Padding not set."); + } + try{ + this.timeSkewThreshold = jsonObject.getInt(TIMESKEWTHRESHOLD); + } catch (JSONException e) { + Log.d(TAG, "timeSkewThreshold not set."); + } + try{ + this.authorizedUsersPath = jsonObject.getString(AUTHORIZEDUSERSPATH); + } catch (JSONException e) { + Log.d(TAG, "authorizedUsersPath not set."); + } + try{ + this.rsaPrivateKeyPath = jsonObject.getString(RSAPRIVATEKEYPATH); + } catch (JSONException e) { + Log.d(TAG, "rsaPrivateKeyPath not set."); + } + try{ + this.idleTimeout = jsonObject.getInt(IDLETIMEOUT); + } catch (JSONException e) { + Log.d(TAG, "idleTimeout not set."); + } + try{ + this.serverBitrateLimit = jsonObject.getString(SERVERBITRATELIMIT); + } catch (JSONException e) { + Log.d(TAG, "serverBitrateLimit not set."); + } + try{ + this.oneOff = jsonObject.getBoolean(ONEOFF); + } catch (JSONException e) { + Log.d(TAG, "oneOff not set."); + } + try{ + this.daemon = jsonObject.getBoolean(DAEMON); + } catch (JSONException e) { + Log.d(TAG, "daemon not set."); + } + try{ + this.help = jsonObject.getBoolean(HELP); + } catch (JSONException e) { + Log.d(TAG, "help not set."); + } + try{ + this.version = jsonObject.getBoolean(VERSION); + } catch (JSONException e) { + Log.d(TAG, "version not set."); + } + try{ + this.debug = jsonObject.getInt(DEBUG); + } catch (JSONException e) { + Log.d(TAG, "debug not set."); + } + try{ + this.sndTimeout = jsonObject.getInt(SNDTIMEOUT); + } catch (JSONException e) { + Log.d(TAG, "sndTimeout not set."); + } + try{ + this.rcvTimeout = jsonObject.getInt(RCVTIMEOUT); + } catch (JSONException e) { + Log.d(TAG, "rcvTimeout not set."); + } + try{ + this.timestamps = jsonObject.getString(TIMESTAMPS); + } catch (JSONException e) { + Log.d(TAG, "timestamps not set."); + } + try{ + this.forceflush = jsonObject.getBoolean(FORCEFLUSH); + } catch (JSONException e) { + Log.d(TAG, "forceflush not set."); + } + try{ + this.logfile = jsonObject.getString(LOGFILE); + } catch (JSONException e) { + Log.d(TAG, "logfile not set."); + } + this.jsonStream = true; + try{ + this.verbose = jsonObject.getBoolean(VERBOSE); + } catch (JSONException e) { + Log.d(TAG, "verbose not set."); + } + try{ + this.bindDev = jsonObject.getString(BINDDEV); + } catch (JSONException e) { + Log.d(TAG, "bindDev not set."); + } + try{ + this.affinity = jsonObject.getString(AFFINITY); + } catch (JSONException e) { + Log.d(TAG, "affinity not set."); + } + try{ + this.file = jsonObject.getString(FILE); + } catch (JSONException e) { + Log.d(TAG, "file not set."); + } + try { + this.direction = Iperf3Direction.valueOf(jsonObject.getString(DIRECTION)); + } catch (JSONException e) { + Log.d(TAG, "direction not set."); + } + try { + this.mode = Iperf3Mode.valueOf(jsonObject.getString(MODE)); + } catch (JSONException e) { + Log.d(TAG, "mode not set."); + } + try{ + this.bind = jsonObject.getString(BIND); + } catch (JSONException e) { + Log.d(TAG, "bind not set."); + } + try{ + this.title = jsonObject.getString(TITLE); + } catch (JSONException e) { + Log.d(TAG, "title not set."); + } + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeString(host); + dest.writeString(iPerf3UUID); + dest.writeInt(duration); + dest.writeInt(port); + dest.writeDouble(interval); + dest.writeString(bitrate); + dest.writeInt(length); + dest.writeString(mode.name()); + dest.writeString(direction.name()); + dest.writeString(pidfile); + dest.writeString(file); + dest.writeString(affinity); + dest.writeString(bind); + dest.writeString(bindDev); + dest.writeBoolean(verbose); + dest.writeBoolean(json); + dest.writeBoolean(jsonStream); + dest.writeString(logfile); + dest.writeBoolean(forceflush); + dest.writeString(timestamps); + dest.writeInt(rcvTimeout); + dest.writeInt(sndTimeout); + dest.writeInt(debug); + dest.writeBoolean(version); + dest.writeBoolean(help); + dest.writeBoolean(daemon); + dest.writeBoolean(oneOff); + dest.writeString(serverBitrateLimit); + dest.writeInt(idleTimeout); + dest.writeString(rsaPrivateKeyPath); + dest.writeString(authorizedUsersPath); + dest.writeInt(timeSkewThreshold); + dest.writeBoolean(usePkcs1Padding); + dest.writeBoolean(sctp); + dest.writeString(xbind); + dest.writeInt(nstreams); + dest.writeInt(connectTimeout); + dest.writeString(pacingTimer); + dest.writeString(fqRate); + dest.writeInt(time); + dest.writeString(bytes); + dest.writeString(blockcount); + dest.writeInt(cport); + dest.writeInt(parallel); + dest.writeBoolean(reverse); + dest.writeBoolean(bidir); + dest.writeString(window); + dest.writeString(congestion); + dest.writeInt(setMss); + dest.writeBoolean(noDelay); + dest.writeBoolean(version4); + dest.writeBoolean(version6); + dest.writeInt(tos); + dest.writeString(dscp); + dest.writeInt(flowlabel); + dest.writeBoolean(zerocopy); + dest.writeInt(omit); + dest.writeString(title); + dest.writeString(extraData); + dest.writeBoolean(getServerOutput); + dest.writeBoolean(udpCounters64bit); + dest.writeBoolean(repeatingPayload); + dest.writeBoolean(dontFragment); + dest.writeString(username); + dest.writeString(rsaPublicKeyPath); + } + + public String getHost() { + return host; + } + + // --- Enums --- + public enum Iperf3Mode { + CLIENT, + SERVER, + UNDEFINED; + public String toPrettyPrint() { + return this.name().substring(0, 1).toUpperCase() + this.name().toLowerCase().substring(1); + } + } + + public enum Iperf3Protocol { + TCP, + UDP, + UNDEFINED; + } + + public enum Iperf3Direction { + UP, + DOWN, + BIDIR, + UNDEFINED; + public String toPrettyPrint() { + return this.name().toLowerCase(); + } + } + + // --- Fields --- + // Required field. + private String host; + private String iPerf3UUID; + + // Optional fields with defaults based on iperf3. + private int duration = 10; // Default duration: 10 seconds. + private Iperf3Protocol protocol = Iperf3Protocol.TCP; // Default protocol: TCP. + private int port = 5201; // Default port: 5201. + private double interval = 1.0; // Default interval: 1.0 second. + // For UDP mode: if not set, default bitrate is "1M". + private String bitrate; + // For TCP mode: if not set, default buffer length is 131072 (128 KB). + private int length = 131072; + + // Mode selection fields. + // The mode field indicates whether the test is run in CLIENT or SERVER mode. + // When mode is CLIENT, the client field (host) must be provided. + private Iperf3Mode mode = Iperf3Mode.UNDEFINED; + + + private Iperf3Direction direction = Iperf3Direction.UNDEFINED; + + // Additional optional parameters. + private String pidfile; + private String file; + private String affinity; + private String bind; + private String bindDev; + private Boolean verbose; + private Boolean json; + private Boolean jsonStream = true; + private String logfile; + private Boolean forceflush; + private String timestamps; + private Integer rcvTimeout; + private Integer sndTimeout; + private Integer debug; + private Boolean version; + private Boolean help; + private Boolean daemon; + private Boolean oneOff; + private String serverBitrateLimit; + private Integer idleTimeout; + private String rsaPrivateKeyPath; + private String authorizedUsersPath; + private Integer timeSkewThreshold; + private Boolean usePkcs1Padding; + private Boolean sctp; + private String xbind; + private Integer nstreams; + + private Integer connectTimeout; + private String pacingTimer; + private String fqRate; + private Integer time = 10; + private String bytes; + private String blockcount; + private Integer cport; + private Integer parallel; + private Boolean reverse; + private Boolean bidir; + private String window; + private String congestion; + private Integer setMss; + private Boolean noDelay; + private Boolean version4; + private Boolean version6; + private Integer tos; + private String dscp; + private Integer flowlabel; + private Boolean zerocopy; + private Integer omit; + private String title; + private String extraData; + private Boolean getServerOutput; + private Boolean udpCounters64bit; + private Boolean repeatingPayload; + private Boolean dontFragment; + private String username; + private String rsaPublicKeyPath; + + // --- Constructors --- + public Iperf3Parameter() { + // Defaults are set via field initialization. + } + + // --- Getters and Setters --- + + public String getiPerf3UUID() { + return iPerf3UUID; + } + + public void setiPerf3UUID(String iPerf3UUID) { + this.iPerf3UUID = iPerf3UUID; + } + + public int getDuration() { + return duration; + } + + public void setDuration(int duration) { + this.duration = duration; + } + + public Iperf3Protocol getProtocol() { + return protocol; + } + + /** + * Set the protocol. If the input is not null, the protocol is set accordingly. + * Otherwise, it defaults to TCP. + */ + public void setProtocol(Iperf3Protocol protocol) { + this.protocol = (protocol != null) ? protocol : Iperf3Protocol.TCP; + } + + public int getPort() { + return port; + } + + public void setPort(int port) { + this.port = port; + } + + public double getInterval() { + return interval; + } + + public void setInterval(double interval) { + this.interval = interval; + } + + public String getBitrate() { + return bitrate; + } + + public void setBitrate(String bitrate) { + this.bitrate = bitrate; + } + + public int getLength() { + return length; + } + + public void setLength(int length) { + this.length = length; + } + + public Iperf3Mode getMode() { + return mode; + } + + /** + * Set the mode. If the mode is set to SERVER, the client field is cleared. + */ + public void setMode(Iperf3Mode mode) { + this.mode = (mode != null) ? mode : Iperf3Mode.UNDEFINED; + } + + + + public Iperf3Direction getDirection() { + return direction; + } + + public void setDirection(Iperf3Direction direction) { + this.direction = (direction != null) ? direction : Iperf3Direction.UNDEFINED; + } + + // Additional getters and setters for remaining fields... + + public String getPidfile() { + return pidfile; + } + + public void setPidfile(String pidfile) { + this.pidfile = pidfile; + } + + public String getFile() { + return file; + } + + public void setFile(String file) { + this.file = file; + } + + public String getAffinity() { + return affinity; + } + + public void setAffinity(String affinity) { + this.affinity = affinity; + } + + public String getBind() { + return bind; + } + + public void setBind(String bind) { + this.bind = bind; + } + + public String getBindDev() { + return bindDev; + } + + public void setBindDev(String bindDev) { + this.bindDev = bindDev; + } + + public Boolean getVerbose() { + return verbose; + } + + public void setVerbose(Boolean verbose) { + this.verbose = verbose; + } + + public Boolean getJson() { + return json; + } + + public void setJson(Boolean json) { + this.json = json; + } + + public Boolean getJsonStream() { + return jsonStream; + } + + public void setJsonStream(Boolean jsonStream) { + this.jsonStream = jsonStream; + } + + public String getLogfile() { + return logfile; + } + + public void setLogfile(String logfile) { + this.logfile = logfile; + } + + public Boolean getForceflush() { + return forceflush; + } + + public void setForceflush(Boolean forceflush) { + this.forceflush = forceflush; + } + + public String getTimestamps() { + return timestamps; + } + + public void setTimestamps(String timestamps) { + this.timestamps = timestamps; + } + + public Integer getRcvTimeout() { + return rcvTimeout; + } + + public void setRcvTimeout(Integer rcvTimeout) { + this.rcvTimeout = rcvTimeout; + } + + public Integer getSndTimeout() { + return sndTimeout; + } + + public void setSndTimeout(Integer sndTimeout) { + this.sndTimeout = sndTimeout; + } + + public Integer getDebug() { + return debug; + } + + public void setDebug(Integer debug) { + this.debug = debug; + } + + public Boolean getVersion() { + return version; + } + + public void setVersion(Boolean version) { + this.version = version; + } + + public Boolean getHelp() { + return help; + } + + public void setHelp(Boolean help) { + this.help = help; + } + + public Boolean getDaemon() { + return daemon; + } + + public void setDaemon(Boolean daemon) { + this.daemon = daemon; + } + + public Boolean getOneOff() { + return oneOff; + } + + public void setOneOff(Boolean oneOff) { + this.oneOff = oneOff; + } + + public String getServerBitrateLimit() { + return serverBitrateLimit; + } + + public void setServerBitrateLimit(String serverBitrateLimit) { + this.serverBitrateLimit = serverBitrateLimit; + } + + public Integer getIdleTimeout() { + return idleTimeout; + } + + public void setIdleTimeout(Integer idleTimeout) { + this.idleTimeout = idleTimeout; + } + + public String getRsaPrivateKeyPath() { + return rsaPrivateKeyPath; + } + + public void setRsaPrivateKeyPath(String rsaPrivateKeyPath) { + this.rsaPrivateKeyPath = rsaPrivateKeyPath; + } + + public String getAuthorizedUsersPath() { + return authorizedUsersPath; + } + + public void setAuthorizedUsersPath(String authorizedUsersPath) { + this.authorizedUsersPath = authorizedUsersPath; + } + + public Integer getTimeSkewThreshold() { + return timeSkewThreshold; + } + + public void setTimeSkewThreshold(Integer timeSkewThreshold) { + this.timeSkewThreshold = timeSkewThreshold; + } + + public Boolean getUsePkcs1Padding() { + return usePkcs1Padding; + } + + public void setUsePkcs1Padding(Boolean usePkcs1Padding) { + this.usePkcs1Padding = usePkcs1Padding; + } + + public Boolean getSctp() { + return sctp; + } + + public void setSctp(Boolean sctp) { + this.sctp = sctp; + } + + public String getXbind() { + return xbind; + } + + public void setXbind(String xbind) { + this.xbind = xbind; + } + + public Integer getNstreams() { + return nstreams; + } + + public void setNstreams(Integer nstreams) { + this.nstreams = nstreams; + } + + + public Integer getConnectTimeout() { + return connectTimeout; + } + + public void setConnectTimeout(Integer connectTimeout) { + this.connectTimeout = connectTimeout; + } + + public String getPacingTimer() { + return pacingTimer; + } + + public void setPacingTimer(String pacingTimer) { + this.pacingTimer = pacingTimer; + } + + public String getFqRate() { + return fqRate; + } + + public void setFqRate(String fqRate) { + this.fqRate = fqRate; + } + + public Integer getTime() { + return time; + } + + public void setTime(Integer time) { + this.time = time; + } + + public String getBytes() { + return bytes; + } + + public void setBytes(String bytes) { + this.bytes = bytes; + } + + public String getBlockcount() { + return blockcount; + } + + public void setBlockcount(String blockcount) { + this.blockcount = blockcount; + } + + public Integer getCport() { + return cport; + } + + public void setCport(Integer cport) { + this.cport = cport; + } + + public Integer getParallel() { + return parallel; + } + + public void setParallel(Integer parallel) { + this.parallel = parallel; + } + + public Boolean getReverse() { + return reverse; + } + + public void setReverse(Boolean reverse) { + this.reverse = reverse; + } + + public Boolean getBidir() { + return bidir; + } + + public void setBidir(Boolean bidir) { + this.bidir = bidir; + } + + public String getWindow() { + return window; + } + + public void setWindow(String window) { + this.window = window; + } + + public String getCongestion() { + return congestion; + } + + public void setCongestion(String congestion) { + this.congestion = congestion; + } + + public Integer getSetMss() { + return setMss; + } + + public void setSetMss(Integer setMss) { + this.setMss = setMss; + } + + public Boolean getNoDelay() { + return noDelay; + } + + public void setNoDelay(Boolean noDelay) { + this.noDelay = noDelay; + } + + public Boolean getVersion4() { + return version4; + } + + public void setVersion4(Boolean version4) { + this.version4 = version4; + } + + public Boolean getVersion6() { + return version6; + } + + public void setVersion6(Boolean version6) { + this.version6 = version6; + } + + public Integer getTos() { + return tos; + } + + public void setTos(Integer tos) { + this.tos = tos; + } + + public String getDscp() { + return dscp; + } + + public void setDscp(String dscp) { + this.dscp = dscp; + } + + public Integer getFlowlabel() { + return flowlabel; + } + + public void setFlowlabel(Integer flowlabel) { + this.flowlabel = flowlabel; + } + + public Boolean getZerocopy() { + return zerocopy; + } + + public void setZerocopy(Boolean zerocopy) { + this.zerocopy = zerocopy; + } + + public Integer getOmit() { + return omit; + } + + public void setOmit(Integer omit) { + this.omit = omit; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getExtraData() { + return extraData; + } + + public void setExtraData(String extraData) { + this.extraData = extraData; + } + + public Boolean getGetServerOutput() { + return getServerOutput; + } + + public void setGetServerOutput(Boolean getServerOutput) { + this.getServerOutput = getServerOutput; + } + + public Boolean getUdpCounters64bit() { + return udpCounters64bit; + } + + public void setUdpCounters64bit(Boolean udpCounters64bit) { + this.udpCounters64bit = udpCounters64bit; + } + + public Boolean getRepeatingPayload() { + return repeatingPayload; + } + + public void setRepeatingPayload(Boolean repeatingPayload) { + this.repeatingPayload = repeatingPayload; + } + + public Boolean getDontFragment() { + return dontFragment; + } + + public void setDontFragment(Boolean dontFragment) { + this.dontFragment = dontFragment; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getRsaPublicKeyPath() { + return rsaPublicKeyPath; + } + + public void setRsaPublicKeyPath(String rsaPublicKeyPath) { + this.rsaPublicKeyPath = rsaPublicKeyPath; + } + + @Override + public String toString() { + return "Params{" + + "iPerf3UUID='" + iPerf3UUID + '\'' + + ", duration=" + duration + + ", protocol=" + protocol + + ", port=" + port + + ", interval=" + interval + + ", bitrate='" + bitrate + '\'' + + ", length=" + length + + ", mode=" + mode + + ", direction=" + direction + + ", pidfile='" + pidfile + '\'' + + ", file='" + file + '\'' + + ", affinity='" + affinity + '\'' + + ", bind='" + bind + '\'' + + ", bindDev='" + bindDev + '\'' + + ", verbose=" + verbose + + ", json=" + json + + ", jsonStream=" + jsonStream + + ", logfile='" + logfile + '\'' + + ", forceflush=" + forceflush + + ", timestamps='" + timestamps + '\'' + + ", rcvTimeout=" + rcvTimeout + + ", sndTimeout=" + sndTimeout + + ", debug=" + debug + + ", version=" + version + + ", help=" + help + + ", daemon=" + daemon + + ", oneOff=" + oneOff + + ", serverBitrateLimit='" + serverBitrateLimit + '\'' + + ", idleTimeout=" + idleTimeout + + ", rsaPrivateKeyPath='" + rsaPrivateKeyPath + '\'' + + ", authorizedUsersPath='" + authorizedUsersPath + '\'' + + ", timeSkewThreshold=" + timeSkewThreshold + + ", usePkcs1Padding=" + usePkcs1Padding + + ", sctp=" + sctp + + ", xbind='" + xbind + '\'' + + ", nstreams=" + nstreams + + ", connectTimeout=" + connectTimeout + + ", pacingTimer='" + pacingTimer + '\'' + + ", fqRate='" + fqRate + '\'' + + ", time=" + time + + ", bytes='" + bytes + '\'' + + ", blockcount='" + blockcount + '\'' + + ", cport=" + cport + + ", parallel=" + parallel + + ", reverse=" + reverse + + ", bidir=" + bidir + + ", window='" + window + '\'' + + ", congestion='" + congestion + '\'' + + ", setMss=" + setMss + + ", noDelay=" + noDelay + + ", version4=" + version4 + + ", version6=" + version6 + + ", tos=" + tos + + ", dscp='" + dscp + '\'' + + ", flowlabel=" + flowlabel + + ", zerocopy=" + zerocopy + + ", omit=" + omit + + ", title='" + title + '\'' + + ", extraData='" + extraData + '\'' + + ", getServerOutput=" + getServerOutput + + ", udpCounters64bit=" + udpCounters64bit + + ", repeatingPayload=" + repeatingPayload + + ", dontFragment=" + dontFragment + + ", username='" + username + '\'' + + ", rsaPublicKeyPath='" + rsaPublicKeyPath + '\'' + + '}'; + } + + public String[] getInputAsCommand() { + ArrayList command = new ArrayList<>(); + + // Mode: either CLIENT (-c host) or SERVER (-s) + switch (mode) { + case CLIENT: + command.add("-c"); + command.add(host); + break; + case SERVER: + command.add("-s"); + break; + default: + // Optionally, throw an exception or handle UNDEFINED mode + break; + } + + // Common options + if (port > 0) { + command.add("-p"); + command.add(String.valueOf(port)); + } + if (interval > 0) { + command.add("-i"); + command.add(String.valueOf(interval)); + } + if (pidfile != null && !pidfile.trim().isEmpty()) { + command.add("-I"); + command.add(pidfile); + } + if (file != null && !file.trim().isEmpty()) { + command.add("-F"); + command.add(file); + } + if (affinity != null && !affinity.trim().isEmpty()) { + command.add("-A"); + command.add(affinity); + } + if (bind != null && !bind.trim().isEmpty()) { + command.add("-B"); + command.add(bind); + } + if (bindDev != null && !bindDev.trim().isEmpty()) { + command.add("--bind-dev"); + command.add(bindDev); + } + if (verbose != null && verbose) { + command.add("-V"); + } + if (json != null && json) { + command.add("-J"); + } + + if (logfile != null && !logfile.trim().isEmpty()) { + command.add("--logfile"); + command.add(logfile); + } + if (forceflush != null && forceflush) { + command.add("--forceflush"); + } + if (timestamps != null && !timestamps.trim().isEmpty()) { + command.add("--timestamps"); + command.add(timestamps); + } + if (rcvTimeout != null && rcvTimeout > 0) { + command.add("--rcv-timeout"); + command.add(String.valueOf(rcvTimeout)); + } + if (sndTimeout != null && sndTimeout > 0) { + command.add("--snd-timeout"); + command.add(String.valueOf(sndTimeout)); + } + if (debug != null && debug > 0) { + command.add("-d"); + command.add(String.valueOf(debug)); + } + if (version != null && version) { + command.add("-v"); + } + if (help != null && help) { + command.add("-h"); + } + + // Server-specific options + if (daemon != null && daemon) { + command.add("-D"); + } + if (oneOff != null && oneOff) { + command.add("-1"); + } + if (serverBitrateLimit != null && !serverBitrateLimit.trim().isEmpty()) { + command.add("--server-bitrate-limit"); + command.add(serverBitrateLimit); + } + if (idleTimeout != null && idleTimeout > 0) { + command.add("--idle-timeout"); + command.add(String.valueOf(idleTimeout)); + } + if (rsaPrivateKeyPath != null && !rsaPrivateKeyPath.trim().isEmpty()) { + command.add("--rsa-private-key-path"); + command.add(rsaPrivateKeyPath); + } + if (authorizedUsersPath != null && !authorizedUsersPath.trim().isEmpty()) { + command.add("--authorized-users-path"); + command.add(authorizedUsersPath); + } + if (timeSkewThreshold != null && timeSkewThreshold > 0) { + command.add("--time-skew-threshold"); + command.add(String.valueOf(timeSkewThreshold)); + } + if (usePkcs1Padding != null && usePkcs1Padding) { + command.add("--use-pkcs1-padding"); + } + + // Client-specific options + if (sctp != null && sctp) { + command.add("--sctp"); + } + if (xbind != null && !xbind.trim().isEmpty()) { + command.add("-X"); + command.add(xbind); + } + if (nstreams != null && nstreams > 0) { + command.add("--nstreams"); + command.add(String.valueOf(nstreams)); + } + switch (protocol){ + case UDP: + command.add("-u"); + break; + case TCP: + default: + break; + } + if (connectTimeout != null && connectTimeout > 0) { + command.add("--connect-timeout"); + command.add(String.valueOf(connectTimeout)); + } + if (bitrate != null && !bitrate.trim().isEmpty()) { + command.add("-b"); + command.add(bitrate); + } + if (pacingTimer != null && !pacingTimer.trim().isEmpty()) { + command.add("--pacing-timer"); + command.add(pacingTimer); + } + if (fqRate != null && !fqRate.trim().isEmpty()) { + command.add("--fq-rate"); + command.add(fqRate); + } + if (time > 0) { + command.add("-t"); + command.add(String.valueOf(time)); + } + if (bytes != null && !bytes.trim().isEmpty()) { + command.add("-n"); + command.add(bytes); + } + if (blockcount != null && !blockcount.trim().isEmpty()) { + command.add("-k"); + command.add(blockcount); + } + if (length > 0) { + command.add("-l"); + command.add(String.valueOf(length)); + } + if (cport != null && cport > 0) { + command.add("--cport"); + command.add(String.valueOf(cport)); + } + if (parallel != null && parallel > 0) { + command.add("-P"); + command.add(String.valueOf(parallel)); + } + + // Data direction options (client-specific) + if (direction != null) { + switch (direction) { + case DOWN: + command.add("--reverse"); + break; + case BIDIR: + command.add("--bidir"); + break; + default: + // UP direction requires no flag. + break; + } + } + + if (window != null && !window.trim().isEmpty()) { + command.add("-w"); + command.add(window); + } + if (congestion != null && !congestion.trim().isEmpty()) { + command.add("-C"); + command.add(congestion); + } + if (setMss != null && setMss > 0) { + command.add("-M"); + command.add(String.valueOf(setMss)); + } + if (noDelay != null && noDelay) { + command.add("-N"); + } + if (version4 != null && version4) { + command.add("-4"); + } + if (version6 != null && version6) { + command.add("-6"); + } + if (tos != null && tos > 0) { + command.add("-S"); + command.add(String.valueOf(tos)); + } + if (dscp != null && !dscp.trim().isEmpty()) { + command.add("--dscp"); + command.add(dscp); + } + if (flowlabel != null && flowlabel > 0) { + command.add("-L"); + command.add(String.valueOf(flowlabel)); + } + if (zerocopy != null && zerocopy) { + command.add("-Z"); + } + if (omit != null && omit > 0) { + command.add("-O"); + command.add(String.valueOf(omit)); + } + if (title != null && !title.trim().isEmpty()) { + command.add("-T"); + command.add(title); + } + if (extraData != null && !extraData.trim().isEmpty()) { + command.add("--extra-data"); + command.add(extraData); + } + if (getServerOutput != null && getServerOutput) { + command.add("--get-server-output"); + } + if (udpCounters64bit != null && udpCounters64bit) { + command.add("--udp-counters-64bit"); + } + if (repeatingPayload != null && repeatingPayload) { + command.add("--repeating-payload"); + } + if (dontFragment != null && dontFragment) { + command.add("--dont-fragment"); + } + if (username != null && !username.trim().isEmpty()) { + command.add("--username"); + command.add(username); + } + if (rsaPublicKeyPath != null && !rsaPublicKeyPath.trim().isEmpty()) { + command.add("--rsa-public-key-path"); + command.add(rsaPublicKeyPath); + } + + // Always add these extra fixed options. + command.add("--json-stream"); + + + return command.toArray(new String[0]); + } + +} diff --git a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Iperf3Parser.java b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Iperf3Parser.java index 781ade6b..263a9fc6 100644 --- a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Iperf3Parser.java +++ b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Iperf3Parser.java @@ -22,7 +22,7 @@ public class Iperf3Parser { private PropertyChangeSupport support; private Start start; private final Intervals intervals = new Intervals(); - Iperf3Parser(String pathToFile) { + public Iperf3Parser(String pathToFile) { this.pathToFile = pathToFile; this.file = new File(this.pathToFile); try { diff --git a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Iperf3RecyclerViewAdapter.java b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Iperf3RecyclerViewAdapter.java index 0ab33dce..459be435 100644 --- a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Iperf3RecyclerViewAdapter.java +++ b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Iperf3RecyclerViewAdapter.java @@ -26,7 +26,6 @@ import androidx.cardview.widget.CardView; import androidx.core.content.ContextCompat; import androidx.fragment.app.FragmentActivity; -import androidx.preference.PreferenceManager; import androidx.recyclerview.widget.RecyclerView; import androidx.work.Data; import androidx.work.OneTimeWorkRequest; @@ -38,6 +37,10 @@ import java.util.HashMap; import java.util.Map; +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Iperf3.Database.RunResult.Iperf3ResultsDataBase; +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Iperf3.Database.RunResult.Iperf3RunResult; +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Iperf3.Database.RunResult.Iperf3RunResultDao; +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Iperf3.Worker.Iperf3UploadWorker; import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Preferences.SPType; import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Preferences.SharedPreferencesGrouper; import de.fraunhofer.fokus.OpenMobileNetworkToolkit.R; diff --git a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Iperf3Worker.java b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Iperf3Worker.java deleted file mode 100644 index 1a228178..00000000 --- a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Iperf3Worker.java +++ /dev/null @@ -1,121 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2023 Peter Hasse - * SPDX-FileCopyrightText: 2023 Johann Hackler - * SPDX-FileCopyrightText: 2023 Fraunhofer FOKUS - * - * SPDX-License-Identifier: BSD-3-Clause-Clear - */ - -package de.fraunhofer.fokus.OpenMobileNetworkToolkit.Iperf3; - -import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC; -import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_LOCATION; -import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_SPECIAL_USE; - -import android.app.Notification; -import android.app.PendingIntent; -import android.content.Context; -import android.graphics.Color; -import android.os.Build; -import android.util.Log; - -import android.widget.TextView; -import androidx.annotation.NonNull; -import androidx.annotation.RequiresApi; -import androidx.core.app.NotificationCompat; -import androidx.room.util.StringUtil; -import androidx.work.Data; -import androidx.work.ForegroundInfo; -import androidx.work.WorkManager; -import androidx.work.Worker; -import androidx.work.WorkerParameters; - -import de.fraunhofer.fokus.OpenMobileNetworkToolkit.R; -import java.util.Locale; - -public class Iperf3Worker extends Worker { - private static final String TAG = "iperf3Worker"; - - static { - Iperf3LibLoader.load(); - } - - private final String[] cmd; - private final String iperf3WorkerID; - private final String measurementName; - private final String timestamp; - private final int notificationID; - private final String client; - private final String protocol; - private String serverPort; - private final String ip; - private final int FOREGROUND_SERVICE_TYPE = FOREGROUND_SERVICE_TYPE_SPECIAL_USE; - - public Iperf3Worker(@NonNull Context context, @NonNull WorkerParameters workerParams) { - super(context, workerParams); - cmd = getInputData().getStringArray("commands"); - measurementName = getInputData().getString("measurementName"); - iperf3WorkerID = getInputData().getString("iperf3WorkerID"); - timestamp = getInputData().getString("timestamp"); - notificationID = 100; - client = getInputData().getString("client"); - ip = getInputData().getString("ip"); - serverPort = getInputData().getString("port"); - protocol = getInputData().getString("protocol"); - - } - - private native int iperf3Wrapper(String[] argv, String cache); - - private native int iperf3Stop(); - - private ForegroundInfo createForegroundInfo(@NonNull String progress) { - - Context context = getApplicationContext(); - String id = "OMNT_notification_channel"; - PendingIntent intent = WorkManager.getInstance(context) - .createCancelPendingIntent(getId()); - Notification notification = new NotificationCompat.Builder(context, id) - .setContentTitle("iPerf3 "+ client.substring(0, 1).toUpperCase() + client.substring(1).toLowerCase()) - .setContentText(progress) - .setOngoing(true) - .setColor(Color.WHITE) - .setSmallIcon(R.mipmap.ic_launcher_foreground) - .setForegroundServiceBehavior(Notification.FOREGROUND_SERVICE_DEFAULT) - .addAction(R.drawable.ic_close, "Cancel", intent) - .build(); - return new ForegroundInfo(notificationID, notification, FOREGROUND_SERVICE_TYPE); - } - - @Override - public void onStopped() { - Log.d(TAG, "onStopped: called!"); - iperf3Stop(); - } - - @NonNull - @Override - public Result doWork() { - if (serverPort == null) serverPort = "5201"; - String progress = String.format("Connected to %s:%s with %s", ip, serverPort, protocol); - if (client.equals("server")) { - progress = String.format("Running on %s:%s", ip, serverPort); - } - - setForegroundAsync(createForegroundInfo(progress)); - - int result = - iperf3Wrapper(cmd, getApplicationContext().getApplicationInfo().nativeLibraryDir); - Log.d(TAG, "doWork: " + result); - - - Data.Builder output = new Data.Builder() - .putInt("iperf3_result", result) - .putString("iperf3WorkerID", iperf3WorkerID); - if (result == 0) { - return Result.success(output.build()); - } - return Result.failure(output - .build()); - } -} diff --git a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Service/Iperf3ServiceWorkerFour.java b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Service/Iperf3ServiceWorkerFour.java new file mode 100644 index 00000000..9156f220 --- /dev/null +++ b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Service/Iperf3ServiceWorkerFour.java @@ -0,0 +1,7 @@ +package de.fraunhofer.fokus.OpenMobileNetworkToolkit.Iperf3.Service; + +import androidx.work.multiprocess.RemoteWorkerService; + +public class Iperf3ServiceWorkerFour extends RemoteWorkerService { + +} diff --git a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Service/Iperf3ServiceWorkerOne.java b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Service/Iperf3ServiceWorkerOne.java new file mode 100644 index 00000000..974c568d --- /dev/null +++ b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Service/Iperf3ServiceWorkerOne.java @@ -0,0 +1,7 @@ +package de.fraunhofer.fokus.OpenMobileNetworkToolkit.Iperf3.Service; + +import androidx.work.multiprocess.RemoteWorkerService; + +public class Iperf3ServiceWorkerOne extends RemoteWorkerService { + +} diff --git a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Service/Iperf3ServiceWorkerThree.java b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Service/Iperf3ServiceWorkerThree.java new file mode 100644 index 00000000..8f341358 --- /dev/null +++ b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Service/Iperf3ServiceWorkerThree.java @@ -0,0 +1,7 @@ +package de.fraunhofer.fokus.OpenMobileNetworkToolkit.Iperf3.Service; + +import androidx.work.multiprocess.RemoteWorkerService; + +public class Iperf3ServiceWorkerThree extends RemoteWorkerService { + +} diff --git a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Service/Iperf3ServiceWorkerTwo.java b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Service/Iperf3ServiceWorkerTwo.java new file mode 100644 index 00000000..d365fcba --- /dev/null +++ b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Service/Iperf3ServiceWorkerTwo.java @@ -0,0 +1,7 @@ +package de.fraunhofer.fokus.OpenMobileNetworkToolkit.Iperf3.Service; + +import androidx.work.multiprocess.RemoteWorkerService; + +public class Iperf3ServiceWorkerTwo extends RemoteWorkerService { + +} diff --git a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Worker/Iperf3ExecutorWorker.java b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Worker/Iperf3ExecutorWorker.java new file mode 100644 index 00000000..886cb234 --- /dev/null +++ b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Worker/Iperf3ExecutorWorker.java @@ -0,0 +1,129 @@ +/* + * SPDX-FileCopyrightText: 2023 Peter Hasse + * SPDX-FileCopyrightText: 2023 Johann Hackler + * SPDX-FileCopyrightText: 2023 Fraunhofer FOKUS + * + * SPDX-License-Identifier: BSD-3-Clause-Clear + */ + +package de.fraunhofer.fokus.OpenMobileNetworkToolkit.Iperf3.Worker; + +import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_SPECIAL_USE; + +import android.app.Notification; +import android.app.PendingIntent; +import android.content.Context; +import android.graphics.Color; +import android.util.Log; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.concurrent.futures.CallbackToFutureAdapter; +import androidx.core.app.NotificationCompat; +import androidx.work.CoroutineWorker; +import androidx.work.Data; +import androidx.work.ForegroundInfo; +import androidx.work.WorkManager; +import androidx.work.Worker; +import androidx.work.WorkerParameters; +import androidx.work.multiprocess.RemoteCoroutineWorker; +import androidx.work.multiprocess.RemoteListenableWorker; + +import com.google.common.util.concurrent.ListenableFuture; +import com.google.gson.Gson; + +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Iperf3.Iperf3Input; +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Iperf3.Iperf3LibLoader; +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.R; +import kotlin.coroutines.Continuation; + +import java.io.IOException; + +public class Iperf3ExecutorWorker extends RemoteCoroutineWorker { + private static final String TAG = "iperf3Worker"; + private static final int NOTIFICATIONID = 1003; + + static { + Iperf3LibLoader.load(); + } + + private final int FOREGROUND_SERVICE_TYPE = FOREGROUND_SERVICE_TYPE_SPECIAL_USE; + private Iperf3Input iperf3Input; + private int notificationNumber; + public Iperf3ExecutorWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) { + super(context, workerParams); + Gson gson = new Gson(); + String iperf3InputString = getInputData().getString(Iperf3Input.IPERF3INPUT); + notificationNumber = getInputData().getInt("notificationNumber", 0); + iperf3Input = gson.fromJson(iperf3InputString, Iperf3Input.class); + + } + + @NonNull + @Override + public ListenableFuture startRemoteWork() { + return CallbackToFutureAdapter.getFuture(completer -> { + Log.i(TAG, "Starting ExampleRemoteListenableWorker"); + + setForegroundAsync(createForegroundInfo()); + + int result = + iperf3Wrapper(iperf3Input.getIperf3Parameter().getInputAsCommand(), getApplicationContext().getApplicationInfo().nativeLibraryDir); + Log.d(TAG, "doWork: " + result); + + + Data.Builder output = new Data.Builder() + .putInt("result", result) + .putString("testUUID", iperf3Input.getTestUUID()); + if (result == 0) { + return completer.set(Result.success(output.build())); + } + return completer.set(Result.failure(output + .build())); + }); + + } + + private native int iperf3Wrapper(String[] argv, String cache); + + private native int iperf3Stop(); + + private ForegroundInfo createForegroundInfo() { + + Context context = getApplicationContext(); + String id = "OMNT_notification_channel"; + PendingIntent intent = WorkManager.getInstance(context) + .createCancelPendingIntent(getId()); + Notification notification = new NotificationCompat.Builder(context, id) + .setContentTitle("iPerf3") + .setContentText("Host " + iperf3Input.getIperf3Parameter().getHost() + " Port " + iperf3Input.getIperf3Parameter().getPort()) + .setOngoing(true) + .setColor(Color.WHITE) + .setSmallIcon(R.mipmap.ic_launcher_foreground) + .setForegroundServiceBehavior(Notification.FOREGROUND_SERVICE_DEFAULT) + .build(); + return new ForegroundInfo(NOTIFICATIONID+notificationNumber, notification, FOREGROUND_SERVICE_TYPE); + } + + @Nullable + @Override + public Object doRemoteWork(@NonNull Continuation continuation) { + Log.i(TAG, "Starting ExampleRemoteListenableWorker"); + + setForegroundAsync(createForegroundInfo()); + + int result = + iperf3Wrapper(iperf3Input.getIperf3Parameter().getInputAsCommand(), getApplicationContext().getApplicationInfo().nativeLibraryDir); + Log.d(TAG, "doWork: " + result); + + + Data.Builder output = new Data.Builder() + .putInt("result", result) + .putString("testUUID", iperf3Input.getTestUUID()); + if (result == 0) { + return Result.success(output.build()); + } + return Result.failure(output + .build()); + } +} diff --git a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Iperf3ToLineProtocolWorker.java b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Worker/Iperf3ToLineProtocolWorker.java similarity index 63% rename from app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Iperf3ToLineProtocolWorker.java rename to app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Worker/Iperf3ToLineProtocolWorker.java index 86cf58fc..5a5b4d35 100644 --- a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Iperf3ToLineProtocolWorker.java +++ b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Worker/Iperf3ToLineProtocolWorker.java @@ -6,7 +6,7 @@ * SPDX-License-Identifier: BSD-3-Clause-Clear */ -package de.fraunhofer.fokus.OpenMobileNetworkToolkit.Iperf3; +package de.fraunhofer.fokus.OpenMobileNetworkToolkit.Iperf3.Worker; import android.content.Context; import android.os.Build; @@ -19,6 +19,7 @@ import androidx.work.WorkerParameters; import com.google.common.base.Splitter; +import com.google.gson.Gson; import com.influxdb.client.domain.WritePrecision; import com.influxdb.client.write.Point; @@ -34,6 +35,9 @@ import de.fraunhofer.fokus.OpenMobileNetworkToolkit.GlobalVars; import de.fraunhofer.fokus.OpenMobileNetworkToolkit.InfluxDB2x.InfluxdbConnection; import de.fraunhofer.fokus.OpenMobileNetworkToolkit.InfluxDB2x.InfluxdbConnections; +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Iperf3.Iperf3Input; +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Iperf3.Iperf3Parameter; +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Iperf3.Iperf3Parser; import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Iperf3.JSON.Interval.Interval; import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Iperf3.JSON.Interval.Streams.Stream; import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Iperf3.JSON.Interval.Streams.TCP.TCP_UL_STREAM; @@ -44,68 +48,15 @@ public class Iperf3ToLineProtocolWorker extends Worker { private static final String TAG = "Iperf3UploadWorker"; InfluxdbConnection influx; - private String rawIperf3file; - private String measurementName; - private String ip; private SharedPreferencesGrouper spg; - private String port; - private String bandwidth; - private String duration; - private String intervalIperf; - private String bytes; - private final String protocol; - private final String iperf3LineProtocolFile; - private final DeviceInformation di = GlobalVars.getInstance().get_dp().getDeviceInformation(); - - private final boolean rev; - private final boolean biDir; - private final boolean oneOff; - private final boolean client; - - private final String runID; + private Iperf3Input iperf3Input; public Iperf3ToLineProtocolWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) { super(context, workerParams); - rawIperf3file = getInputData().getString("rawIperf3file"); - - ip = getInputData().getString("ip"); - measurementName = getInputData().getString("measurementName"); - iperf3LineProtocolFile = getInputData().getString("iperf3LineProtocolFile"); - port = getInputData().getString("port"); - if(port == null) - port = "5201"; - protocol = getInputData().getString("protocol"); - bandwidth = getInputData().getString("bandwidth"); - - if(bandwidth == null){ - if(protocol.equals("TCP")) { - bandwidth = "unlimited"; - } else { - bandwidth = "1000"; - } - } - - duration = getInputData().getString("duration"); - if(duration == null) - duration = "10"; - intervalIperf = getInputData().getString("interval"); - if(intervalIperf == null) - intervalIperf = "1"; - bytes = getInputData().getString("bytes"); - if(bytes == null){ - if(protocol.equals("TCP")) { - bytes = "8"; - } else { - bytes = "1470"; - } - } - - rev = getInputData().getBoolean("rev", false); - biDir = getInputData().getBoolean("biDir",false); - oneOff = getInputData().getBoolean("oneOff",false); - client = getInputData().getBoolean("client",false); - runID = getInputData().getString("iperf3WorkerID"); + Gson gson = new Gson(); + String iperf3InputString = getInputData().getString(Iperf3Input.IPERF3INPUT); + iperf3Input = gson.fromJson(iperf3InputString, Iperf3Input.class); spg = SharedPreferencesGrouper.getInstance(getApplicationContext()); } @@ -114,30 +65,6 @@ private void setup(){ } - public Map getTagsMap() { - String tags = spg.getSharedPreference(SPType.logging_sp).getString("tags", "").strip().replace(" ", ""); - Map tags_map = Collections.emptyMap(); - if (!tags.isEmpty()) { - try { - tags_map = Splitter.on(',').withKeyValueSeparator('=').split(tags); - } catch (IllegalArgumentException e) { - Log.d(TAG, "can't parse tags, ignoring"); - } - } - Map tags_map_modifiable = new HashMap<>(tags_map); - tags_map_modifiable.put("measurement_name", spg.getSharedPreference(SPType.logging_sp).getString("measurement_name", "OMNT")); - tags_map_modifiable.put("manufacturer", di.getManufacturer()); - tags_map_modifiable.put("model", di.getModel()); - tags_map_modifiable.put("sdk_version", String.valueOf(di.getAndroidSDK())); - tags_map_modifiable.put("android_version", di.getAndroidRelease()); - tags_map_modifiable.put("secruity_patch", di.getSecurityPatchLevel()); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { - tags_map_modifiable.put("soc_model", di.getSOCModel()); - } - tags_map_modifiable.put("radio_version", Build.getRadioVersion()); - return tags_map_modifiable; - } - @NonNull @Override @@ -145,7 +72,7 @@ public Result doWork() { setup(); Data output = new Data.Builder().putBoolean("iperf3_upload", false).build(); - Iperf3Parser iperf3Parser = new Iperf3Parser(rawIperf3file); + Iperf3Parser iperf3Parser = new Iperf3Parser(iperf3Input.getRawFile()); iperf3Parser.parse(); @@ -163,16 +90,25 @@ public Result doWork() { int intervalIdx = iperf3Parser.getIntervals().getIntervalArrayList().indexOf(interval); for (Stream stream: interval.getStreams().getStreamArrayList()){ Point point = new Point("Iperf3"); - point.addTag("run_uid", runID); - point.addTag("bidir", String.valueOf(biDir)); + + point.addTag(Iperf3Input.TESTUUID, iperf3Input.getTestUUID()); + point.addTag(Iperf3Input.SEQUENCEUUID, iperf3Input.getSequenceUUID()); + point.addTag(Iperf3Input.MEASUREMENTUUID, iperf3Input.getMeasurementUUID()); + point.addTag(Iperf3Input.CAMPAIGNUUID, iperf3Input.getCampaignUUID()); + point.addTag(Iperf3Input.IPERF3UUID, iperf3Input.getIperf3Parameter().getiPerf3UUID()); + + + + + point.addTag("bidir", String.valueOf(iperf3Input.getIperf3Parameter().getBidir())); point.addTag("sender", String.valueOf(stream.getSender())); point.addTag("role", role); point.addTag("socket", String.valueOf(stream.getSocket())); - point.addTag("protocol", protocol); - point.addTag("interval", intervalIperf); + point.addTag("protocol", iperf3Parser.getStart().getTest_start().protocol); + point.addTag("interval", String.valueOf(iperf3Input.getIperf3Parameter().getInterval())); point.addTag("version", iperf3Parser.getStart().getVersion()); - point.addTag("reversed", String.valueOf(rev)); - point.addTag("oneOff", String.valueOf(oneOff)); + point.addTag("reversed", String.valueOf(iperf3Input.getIperf3Parameter().getReverse())); + point.addTag("oneOff", String.valueOf(iperf3Input.getIperf3Parameter().getOneOff())); point.addTag("connectingToHost", iperf3Parser .getStart() .getConnecting_to() @@ -181,9 +117,9 @@ public Result doWork() { .getStart() .getConnecting_to() .getPort())); - point.addTag("bandwidth", bandwidth); - point.addTag("duration", duration); - point.addTag("bytesToTransmit", bytes); + point.addTag("bandwidth", iperf3Input.getIperf3Parameter().getBitrate()); + point.addTag("duration", String.valueOf(iperf3Input.getIperf3Parameter().getDuration())); + point.addTag("bytesToTransmit", String.valueOf(iperf3Input.getIperf3Parameter().getBytes())); point.addTag("streams", String.valueOf(interval.getStreams().size())); point.addTag("streamIdx", String.valueOf(interval.getStreams().getStreamArrayList().indexOf(stream))); point.addTag("intervalIdx", String.valueOf(intervalIdx)); @@ -227,7 +163,7 @@ public Result doWork() { // is needed when only --udp is, otherwise no lostpackets/lostpercent parsed if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { for (Point point:points) { - point.addTags(getTagsMap()); + point.addTags(GlobalVars.getInstance().get_dp().getTagsMap()); } } @@ -235,7 +171,7 @@ public Result doWork() { FileOutputStream iperf3Stream = null; try { - iperf3Stream = new FileOutputStream(iperf3LineProtocolFile, true); + iperf3Stream = new FileOutputStream(iperf3Input.getLineProtocolFile(), true); } catch (FileNotFoundException e) { Toast.makeText(getApplicationContext(), "logfile not created", Toast.LENGTH_SHORT).show(); Log.d(TAG,e.toString()); diff --git a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Iperf3UploadWorker.java b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Worker/Iperf3UploadWorker.java similarity index 81% rename from app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Iperf3UploadWorker.java rename to app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Worker/Iperf3UploadWorker.java index b3ff8d43..2b4e9af0 100644 --- a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Iperf3UploadWorker.java +++ b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Worker/Iperf3UploadWorker.java @@ -6,7 +6,7 @@ * SPDX-License-Identifier: BSD-3-Clause-Clear */ -package de.fraunhofer.fokus.OpenMobileNetworkToolkit.Iperf3; +package de.fraunhofer.fokus.OpenMobileNetworkToolkit.Iperf3.Worker; import android.content.Context; import android.util.Log; @@ -16,6 +16,8 @@ import androidx.work.Worker; import androidx.work.WorkerParameters; +import com.google.gson.Gson; + import java.io.BufferedReader; import java.io.FileNotFoundException; import java.io.FileReader; @@ -25,16 +27,18 @@ import de.fraunhofer.fokus.OpenMobileNetworkToolkit.InfluxDB2x.InfluxdbConnection; import de.fraunhofer.fokus.OpenMobileNetworkToolkit.InfluxDB2x.InfluxdbConnections; +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Iperf3.Iperf3Input; public class Iperf3UploadWorker extends Worker { private static final String TAG = "Iperf3UploadWorker"; InfluxdbConnection influx; - private final String iperf3LineProtocolFile; - + private Iperf3Input iperf3Input; public Iperf3UploadWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) { super(context, workerParams); - iperf3LineProtocolFile = getInputData().getString("iperf3LineProtocolFile"); + Gson gson = new Gson(); + String iperf3InputString = getInputData().getString(Iperf3Input.IPERF3INPUT); + iperf3Input = gson.fromJson(iperf3InputString, Iperf3Input.class); } private void setup(){ influx = InfluxdbConnections.getRicInstance(getApplicationContext()); @@ -61,17 +65,17 @@ public Result doWork() { } BufferedReader br; try { - br = new BufferedReader(new FileReader(iperf3LineProtocolFile)); + br = new BufferedReader(new FileReader(iperf3Input.getLineProtocolFile())); } catch (FileNotFoundException | NullPointerException e) { Log.d(TAG,e.toString()); return Result.failure(output); } List points = br.lines().collect(Collectors.toList()); try { - Log.d(TAG, String.format("doWork: uploading %s", iperf3LineProtocolFile)); + Log.d(TAG, String.format("doWork: uploading %s", iperf3Input.getLineProtocolFile())); influx.writeRecords(points); } catch (IOException e) { - Log.d(TAG, String.format("doWork: upload of %s failed!", iperf3LineProtocolFile)); + Log.d(TAG, String.format("doWork: upload of %s failed!", iperf3Input.getLineProtocolFile())); return Result.failure(output); } diff --git a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/MQTT/Handler/Iperf3Handler.java b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/MQTT/Handler/Iperf3Handler.java new file mode 100644 index 00000000..98cfb5ba --- /dev/null +++ b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/MQTT/Handler/Iperf3Handler.java @@ -0,0 +1,103 @@ +package de.fraunhofer.fokus.OpenMobileNetworkToolkit.MQTT.Handler; + +import android.app.Application; +import android.content.Context; +import android.util.Log; + +import androidx.annotation.NonNull; +import androidx.work.Configuration; +import androidx.work.OneTimeWorkRequest; +import androidx.work.WorkManager; +import androidx.work.WorkRequest; +import androidx.work.multiprocess.RemoteCoroutineWorker; +import androidx.work.multiprocess.RemoteWorkContinuation; +import androidx.work.multiprocess.RemoteWorkManager; + +import com.google.common.collect.Streams; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + + +import java.util.ArrayList; + +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Iperf3.Iperf3Input; +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Iperf3.Iperf3Parameter; + +public class Iperf3Handler{ + private final String TAG = "Iperf3Handler"; + private ArrayList iperf3Inputs = new ArrayList<>(); + private void parsePayload(String payload) throws JSONException { + iperf3Inputs.clear(); + JSONArray tests = new JSONArray(payload); + for (int i = 0; i < tests.length(); i++) { + JSONObject test = tests.getJSONObject(i); + String testUUID = test.getString("testUUID"); + String measurementUUUID = test.getString("measurementUUID"); + String sequenceUUID = test.getString("sequenceUUID"); + String campaignUUID = test.getString("campaignUUID"); + String device = test.getString("device"); + String testType = test.getString("type"); + if(!testType.equals("iperf3")) continue; + JSONObject params = test.getJSONObject("params"); + + Iperf3Parameter iperf3Parameter = new Iperf3Parameter(params); + if(iperf3Parameter == null) continue; + Iperf3Input iperf3Input = new Iperf3Input(iperf3Parameter, testUUID, sequenceUUID, measurementUUUID,campaignUUID); + iperf3Inputs.add(iperf3Input); + } + } + + public Iperf3Handler(String payload) { + try { + parsePayload(payload); + } catch (JSONException e){ + Log.e(TAG, "Error parsing payload: " + e.getMessage()); + return; + } + } + + + + public void enableSequence(Context context){ + if(iperf3Inputs.isEmpty()) { + Log.e(TAG, "No iperf3 tests to run"); + return; + }; + + WorkManager.getInstance(context); + ArrayList> workRequestss = new ArrayList<>(); + RemoteWorkManager remoteWorkManager = RemoteWorkManager.getInstance(context); + for(Iperf3Input iperf3Input: iperf3Inputs){ + ArrayList workRequests = new ArrayList<>(); + workRequests.add(iperf3Input.getWorkRequestExecutor(iperf3Inputs.indexOf(iperf3Input), context.getPackageName())); +// workRequests.add(iperf3Input.getWorkRequestLineProtocol()); +// workRequests.add(iperf3Input.getWorkRequestUpload()); + workRequestss.add(workRequests); + + } + + ArrayList continuations = new ArrayList<>(); + + for(ArrayList workRequests: workRequestss){ + RemoteWorkContinuation remoteWorkContinuation = remoteWorkManager.beginWith(workRequests.get(0));//.then(workRequests.get(1)).then(workRequests.get(2)); + continuations.add(remoteWorkContinuation); + } + RemoteWorkContinuation mainRemoteWorkContinuation = RemoteWorkContinuation.combine(continuations); + mainRemoteWorkContinuation.enqueue(); + + } + + public void disableSequence(Context context){ + RemoteWorkManager workManager = RemoteWorkManager.getInstance(context); + for(Iperf3Input iperf3Input: iperf3Inputs){ + workManager.cancelAllWorkByTag(iperf3Input.getTestUUID()); + } + } +} + + + + + diff --git a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/MQTT/Handler/PingHandler.java b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/MQTT/Handler/PingHandler.java new file mode 100644 index 00000000..b6849086 --- /dev/null +++ b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/MQTT/Handler/PingHandler.java @@ -0,0 +1,4 @@ +package de.fraunhofer.fokus.OpenMobileNetworkToolkit.MQTT.Handler; + +public class PingHandler { +} diff --git a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/MQTT/MQTTService.java b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/MQTT/MQTTService.java index 594eac27..263ae4c9 100644 --- a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/MQTT/MQTTService.java +++ b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/MQTT/MQTTService.java @@ -1,6 +1,5 @@ package de.fraunhofer.fokus.OpenMobileNetworkToolkit.MQTT; -import android.annotation.SuppressLint; import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; @@ -12,30 +11,24 @@ import android.os.Build; import android.os.Handler; import android.os.IBinder; -import android.os.Looper; import android.util.Log; import androidx.annotation.Nullable; import androidx.core.app.NotificationCompat; -import com.hivemq.client.mqtt.MqttGlobalPublishFilter; import com.hivemq.client.mqtt.datatypes.MqttQos; import com.hivemq.client.mqtt.mqtt5.Mqtt5AsyncClient; -import com.hivemq.client.mqtt.mqtt5.Mqtt5BlockingClient; import com.hivemq.client.mqtt.mqtt5.Mqtt5Client; import com.hivemq.client.mqtt.mqtt5.message.connect.connack.Mqtt5ConnAck; import com.hivemq.client.mqtt.mqtt5.message.publish.Mqtt5PayloadFormatIndicator; -import java.net.InetAddress; import java.net.InetSocketAddress; import java.nio.charset.StandardCharsets; -import java.util.Objects; -import java.util.UUID; import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; -import de.fraunhofer.fokus.OpenMobileNetworkToolkit.GlobalVars; +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.MQTT.Handler.Iperf3Handler; import de.fraunhofer.fokus.OpenMobileNetworkToolkit.MainActivity; import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Preferences.SPType; import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Preferences.SharedPreferencesGrouper; @@ -51,7 +44,7 @@ public class MQTTService extends Service { private Mqtt5AsyncClient client; private SharedPreferencesGrouper spg; private String deviceName; - + private Iperf3Handler iperf3Handler; @Nullable @Override public IBinder onBind(Intent intent) { @@ -322,10 +315,17 @@ private void handleConfigMessage(String topic, String payload){ if(topic.contains("iperf3/command")){ Log.d(TAG, "handleConfigMessage: Iperf3 Command: " + payload); + iperf3Handler = new Iperf3Handler(payload); return; } if(topic.contains("/iperf3/enable")){ Log.d(TAG, "handleConfigMessage: Enable Iperf3: " + payload); + + if(iperf3Handler != null && parseBoolean(payload)){ + iperf3Handler.enableSequence(getApplicationContext()); + } else if(iperf3Handler != null && !parseBoolean(payload)){ + iperf3Handler.disableSequence(getApplicationContext()); + } return; } @@ -380,7 +380,6 @@ public int onStartCommand(Intent intent, int flags, int startId) { createClient(); connectClient(); subscribeToAllTopics(); - return START_STICKY; } From 25e12be5f1c42a1686cde3b0b32c878aa0a82c66 Mon Sep 17 00:00:00 2001 From: hajoha Date: Fri, 7 Feb 2025 23:38:06 +0100 Subject: [PATCH 14/43] update --- .../Worker/InfluxDB2xUploadWorker.java | 88 +++++++ .../Inputs/Inputs.java | 150 +++++++++++ .../Inputs/Iperf3Input.java | 143 +++++++++++ .../Inputs/PingInput.java | 103 ++++++++ .../Iperf3/Iperf3Input.java | 243 ------------------ .../Iperf3/Worker/Iperf3ExecutorWorker.java | 9 +- .../Worker/Iperf3ToLineProtocolWorker.java | 10 +- .../Iperf3/Worker/Iperf3UploadWorker.java | 4 +- .../MQTT/Handler/Handler.java | 30 +++ .../MQTT/Handler/Iperf3Handler.java | 28 +- .../MQTT/Handler/PingHandler.java | 63 ++++- .../MQTT/MQTTService.java | 39 ++- .../Iperf3Parameter.java | 2 +- .../Parameter/Parameter.java | 19 ++ .../Parameter/PingParameter.java | 52 ++++ 15 files changed, 701 insertions(+), 282 deletions(-) create mode 100644 app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/InfluxDB2x/Worker/InfluxDB2xUploadWorker.java create mode 100644 app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Inputs/Inputs.java create mode 100644 app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Inputs/Iperf3Input.java create mode 100644 app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Inputs/PingInput.java delete mode 100644 app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Iperf3Input.java create mode 100644 app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/MQTT/Handler/Handler.java rename app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/{Iperf3 => Parameter}/Iperf3Parameter.java (99%) create mode 100644 app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Parameter/Parameter.java create mode 100644 app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Parameter/PingParameter.java diff --git a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/InfluxDB2x/Worker/InfluxDB2xUploadWorker.java b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/InfluxDB2x/Worker/InfluxDB2xUploadWorker.java new file mode 100644 index 00000000..fb50890e --- /dev/null +++ b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/InfluxDB2x/Worker/InfluxDB2xUploadWorker.java @@ -0,0 +1,88 @@ +/* + * SPDX-FileCopyrightText: 2023 Peter Hasse + * SPDX-FileCopyrightText: 2023 Johann Hackler + * SPDX-FileCopyrightText: 2023 Fraunhofer FOKUS + * + * SPDX-License-Identifier: BSD-3-Clause-Clear + */ + +package de.fraunhofer.fokus.OpenMobileNetworkToolkit.InfluxDB2x.Worker; + +import android.content.Context; +import android.util.Log; + +import androidx.annotation.NonNull; +import androidx.work.Data; +import androidx.work.Worker; +import androidx.work.WorkerParameters; + +import com.google.gson.Gson; + +import java.io.BufferedReader; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.IOException; +import java.util.List; +import java.util.stream.Collectors; + +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.InfluxDB2x.InfluxdbConnection; +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.InfluxDB2x.InfluxdbConnections; +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Inputs.Inputs; +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Inputs.Iperf3Input; + +public class InfluxDB2xUploadWorker extends Worker { + private static final String TAG = "InfDB2xUploadWorker"; + InfluxdbConnection influx; + private Inputs input; + public static final String UPLOAD = "influxdb2x_upload"; + + public InfluxDB2xUploadWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) { + super(context, workerParams); + Gson gson = new Gson(); + String inputString = getInputData().getString(Inputs.INPUT); + input = gson.fromJson(inputString, Inputs.class); + } + private void setup(){ + influx = InfluxdbConnections.getRicInstance(getApplicationContext()); + } + + @NonNull + @Override + public Result doWork() { + setup(); + Data output = new Data.Builder().putBoolean(UPLOAD, false).build(); + if(influx == null){ + return Result.failure(output); + } + if(influx.getWriteApi() == null){ + influx.open_write_api(); + if(influx.getWriteApi() == null) + return Result.failure(output); + } + + if(!influx.ping()){ + return Result.failure(output); + } + BufferedReader br; + try { + br = new BufferedReader(new FileReader(input.getLineProtocolFile())); + } catch (FileNotFoundException | NullPointerException e) { + Log.d(TAG,e.toString()); + return Result.failure(output); + } + List points = br.lines().collect(Collectors.toList()); + try { + Log.d(TAG, String.format("doWork: uploading %s", input.getLineProtocolFile())); + influx.writeRecords(points); + } catch (IOException e) { + Log.d(TAG, String.format("doWork: upload of %s failed!", input.getLineProtocolFile())); + return Result.failure(output); + } + + + influx.flush(); + + output = new Data.Builder().putBoolean(UPLOAD, true).build(); + return Result.success(output); + } +} diff --git a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Inputs/Inputs.java b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Inputs/Inputs.java new file mode 100644 index 00000000..c226352b --- /dev/null +++ b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Inputs/Inputs.java @@ -0,0 +1,150 @@ +package de.fraunhofer.fokus.OpenMobileNetworkToolkit.Inputs; + +import android.os.Environment; +import android.os.Parcel; +import android.os.Parcelable; + +import androidx.annotation.NonNull; +import androidx.work.Data; +import androidx.work.OneTimeWorkRequest; + +import java.sql.Timestamp; + +public abstract class Inputs implements Parcelable { + + public static final String rootPath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS).getAbsolutePath(); + public static final String INPUT = "input"; + public static final String TESTUUID = "testUUID"; + public static final String SEQUENCEUUID = "sequenceUUID"; + public static final String MEASUREMENTUUID = "measurementUUID"; + public static final String CAMPAIGNUUID = "campaignUUID"; + private String rawFile; + private String testUUID; + private String logFileName; + private String measurementName; + private String lineProtocolFile; + private Timestamp timestamp; + private String campaignUUID; + private String sequenceUUID; + private String measurementUUID; + + public String getRawFile() { + return rawFile; + } + + public void setRawFile(String rawFile) { + this.rawFile = rawFile; + } + + public String getTestUUID() { + return testUUID; + } + + public void setTestUUID(String testUUID) { + this.testUUID = testUUID; + } + + public String getLogFileName() { + return logFileName; + } + + public void setLogFileName(String logFileName) { + this.logFileName = logFileName; + } + + public String getMeasurementName() { + return measurementName; + } + + public void setMeasurementName(String measurementName) { + this.measurementName = measurementName; + } + + public String getLineProtocolFile() { + return lineProtocolFile; + } + + public void setLineProtocolFile(String lineProtocolFile) { + this.lineProtocolFile = lineProtocolFile; + } + + public Timestamp getTimestamp() { + return timestamp; + } + + public void setTimestamp(Timestamp timestamp) { + this.timestamp = timestamp; + } + + public String getCampaignUUID() { + return campaignUUID; + } + + public String getSequenceUUID() { + return sequenceUUID; + } + + public String getMeasurementUUID() { + return measurementUUID; + } + protected Inputs(Parcel in) { + rawFile = in.readString(); + logFileName = in.readString(); + measurementName = in.readString(); + lineProtocolFile = in.readString(); + timestamp = (Timestamp) in.readSerializable(); + campaignUUID = in.readString(); + sequenceUUID = in.readString(); + measurementUUID = in.readString(); + testUUID = in.readString(); + } + public Inputs(String rawFile, String logFileName, String measurementName, String lineProtocolFile, String campaignUUID, String sequenceUUID, String measurementUUID, String testUUID) { + + this.rawFile = rawFile; + this.logFileName = logFileName; + this.measurementName = measurementName; + this.lineProtocolFile = lineProtocolFile; + this.timestamp = new Timestamp(System.currentTimeMillis()); + + this.campaignUUID = campaignUUID; + this.sequenceUUID = sequenceUUID; + this.measurementUUID = measurementUUID; + this.testUUID = testUUID; + } + + public Inputs(String campaignUUID, String sequenceUUID, String measurementUUID, String testUUID) { + this.rawFile = ""; + this.logFileName = ""; + this.measurementName = ""; + this.lineProtocolFile = ""; + this.timestamp = new Timestamp(System.currentTimeMillis()); + + this.campaignUUID = campaignUUID; + this.sequenceUUID = sequenceUUID; + this.measurementUUID = measurementUUID; + this.testUUID = testUUID; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeString(rawFile); + dest.writeString(logFileName); + dest.writeString(measurementName); + dest.writeString(lineProtocolFile); + dest.writeSerializable(timestamp); + dest.writeString(campaignUUID); + dest.writeString(sequenceUUID); + dest.writeString(measurementUUID); + dest.writeString(testUUID); + } + public abstract Data.Builder getInputAsDataBuilder(int i, String packageName); + public abstract OneTimeWorkRequest getWorkRequestExecutor(int i, String packageName); + public abstract OneTimeWorkRequest getWorkRequestLineProtocol(int i, String packageName); + public abstract OneTimeWorkRequest getWorkRequestUpload(int i, String packageName); + +} diff --git a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Inputs/Iperf3Input.java b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Inputs/Iperf3Input.java new file mode 100644 index 00000000..598b4e25 --- /dev/null +++ b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Inputs/Iperf3Input.java @@ -0,0 +1,143 @@ +package de.fraunhofer.fokus.OpenMobileNetworkToolkit.Inputs; + +import static androidx.work.multiprocess.RemoteListenableWorker.ARGUMENT_CLASS_NAME; +import static androidx.work.multiprocess.RemoteListenableWorker.ARGUMENT_PACKAGE_NAME; + +import android.content.ComponentName; +import android.os.Parcel; + +import androidx.annotation.NonNull; +import androidx.work.Data; +import androidx.work.OneTimeWorkRequest; + + +import com.google.gson.GsonBuilder; + + +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Parameter.Iperf3Parameter; +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Iperf3.Service.Iperf3ServiceWorkerFour; +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Iperf3.Service.Iperf3ServiceWorkerThree; +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Iperf3.Service.Iperf3ServiceWorkerTwo; +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Iperf3.Worker.Iperf3ExecutorWorker; +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Iperf3.Service.Iperf3ServiceWorkerOne; +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Iperf3.Worker.Iperf3ToLineProtocolWorker; +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Iperf3.Worker.Iperf3UploadWorker; + + +public class Iperf3Input extends Inputs { + public static final String rawDirPath = rootPath+"/omnt/iperf3/raw/"; + public static final String lineProtocolDirPath = rootPath+"/omnt/iperf3/lineprotocol/"; + private static final String TAG = "Iperf3Input"; + public static final String IPERF3UUID = "iPerf3UUID"; + + private Iperf3Parameter iperf3Parameter; + protected Iperf3Input(Parcel in) { + super(in); + iperf3Parameter = in.readParcelable(Iperf3Parameter.class.getClassLoader()); + } + + public static final Creator CREATOR = new Creator<>() { + @Override + public Iperf3Input createFromParcel(Parcel in) { + return new Iperf3Input(in); + } + + @Override + public Iperf3Input[] newArray(int size) { + return new Iperf3Input[size]; + } + }; + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(@NonNull Parcel parcel, int i) { + super.writeToParcel(parcel, i); + parcel.writeParcelable(iperf3Parameter, i); + } + + public Iperf3Input(Iperf3Parameter iperf3Parameter, + String testUUID, + String sequenceUUID, + String measurementUUID, + String campaignUUID) { + super(testUUID, sequenceUUID, measurementUUID, campaignUUID); + super.setRawFile(rawDirPath +testUUID+".json"); + super.setLineProtocolFile(lineProtocolDirPath+testUUID+".txt"); + this.iperf3Parameter = iperf3Parameter; + } + + public Iperf3Parameter getIperf3Parameter() { + return iperf3Parameter; + } + + public Data.Builder getInputAsDataBuilder(int i, String packageName) { + Data.Builder data = new Data.Builder(); + String serviceName = ""; + switch (i){ + case 0: + serviceName = Iperf3ServiceWorkerOne.class.getName(); + break; + case 1: + serviceName = Iperf3ServiceWorkerTwo.class.getName(); + break; + case 2: + serviceName = Iperf3ServiceWorkerThree.class.getName(); + break; + case 3: + serviceName = Iperf3ServiceWorkerFour.class.getName(); + break; + default: + break; + + } + ComponentName componentName = new ComponentName(packageName, serviceName); + + data.putString(ARGUMENT_PACKAGE_NAME, componentName.getPackageName()); + data.putString(ARGUMENT_CLASS_NAME, componentName.getClassName()); + data.putInt("notificationNumber", i); + data.putString(Inputs.INPUT, new GsonBuilder().create().toJson(this, Iperf3Input.class)); + return data; + } + + @Override + public OneTimeWorkRequest getWorkRequestExecutor(int i, String packageName) { + OneTimeWorkRequest workRequest = new OneTimeWorkRequest.Builder(Iperf3ExecutorWorker.class) + .addTag(super.getTestUUID()) + .addTag(super.getMeasurementUUID()) + .addTag(super.getSequenceUUID()) + .addTag(super.getCampaignUUID()) + .addTag(iperf3Parameter.getiPerf3UUID()) + .setInputData(getInputAsDataBuilder(i, packageName).build()) + .build(); + return workRequest; + } + @Override + public OneTimeWorkRequest getWorkRequestLineProtocol(int i, String packageName) { + OneTimeWorkRequest workRequest = new OneTimeWorkRequest.Builder(Iperf3ToLineProtocolWorker.class) + .addTag(super.getTestUUID()) + .addTag(super.getMeasurementUUID()) + .addTag(super.getSequenceUUID()) + .addTag(super.getCampaignUUID()) + .addTag(iperf3Parameter.getiPerf3UUID()) + .setInputData(getInputAsDataBuilder(i, packageName).build()) + .build(); + return workRequest; + } + + @Override + public OneTimeWorkRequest getWorkRequestUpload(int i, String packageName) { + OneTimeWorkRequest workRequest = new OneTimeWorkRequest.Builder(Iperf3UploadWorker.class) + .addTag(super.getTestUUID()) + .addTag(super.getMeasurementUUID()) + .addTag(super.getSequenceUUID()) + .addTag(super.getCampaignUUID()) + .addTag(iperf3Parameter.getiPerf3UUID()) + .setInputData(getInputAsDataBuilder(i, packageName).build()) + .build(); + return workRequest; + } +} \ No newline at end of file diff --git a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Inputs/PingInput.java b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Inputs/PingInput.java new file mode 100644 index 00000000..dc3161e4 --- /dev/null +++ b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Inputs/PingInput.java @@ -0,0 +1,103 @@ +package de.fraunhofer.fokus.OpenMobileNetworkToolkit.Inputs; + +import android.os.Parcel; + +import androidx.work.Data; +import androidx.work.OneTimeWorkRequest; + +import com.google.gson.Gson; + +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.InfluxDB2x.Worker.InfluxDB2xUploadWorker; +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Iperf3.Worker.Iperf3ExecutorWorker; +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Iperf3.Worker.Iperf3ToLineProtocolWorker; +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Iperf3.Worker.Iperf3UploadWorker; +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Parameter.PingParameter; +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Ping.PingWorker; + + +public class PingInput extends Inputs { + PingParameter pingParameter; + public static final String rawDirPath = rootPath+"/omnt/ping/raw/"; + public static final String lineProtocolDirPath = rootPath+"/omnt/ping/lineprotocol/"; + protected PingInput(Parcel in) { + super(in); + + } + public PingInput(PingParameter pingParameter, + String testUUID, + String sequenceUUID, + String measurementUUID, + String campaignUUID) { + super(testUUID, sequenceUUID, measurementUUID, campaignUUID); + super.setRawFile(rawDirPath +testUUID+".json"); + super.setLineProtocolFile(lineProtocolDirPath+testUUID+".txt"); + this.pingParameter = pingParameter; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + super.writeToParcel(dest, flags); + } + + @Override + public Data.Builder getInputAsDataBuilder(int i, String packageName) { + Data.Builder data = new Data.Builder(); + Gson gson = new Gson(); + data.putString(INPUT, gson.toJson(pingParameter)); + return data; + } + + @Override + public int describeContents() { + return 0; + } + + public static final Creator CREATOR = new Creator() { + @Override + public PingInput createFromParcel(Parcel in) { + return new PingInput(in); + } + + @Override + public PingInput[] newArray(int size) { + return new PingInput[size]; + } + }; + + + @Override + public OneTimeWorkRequest getWorkRequestLineProtocol(int i, String packageName) { + OneTimeWorkRequest workRequest = new OneTimeWorkRequest.Builder(Iperf3ToLineProtocolWorker.class) + .addTag(super.getTestUUID()) + .addTag(super.getMeasurementUUID()) + .addTag(super.getSequenceUUID()) + .addTag(super.getCampaignUUID()) + .setInputData(getInputAsDataBuilder(i, packageName).build()) + .build(); + return workRequest; + } + + @Override + public OneTimeWorkRequest getWorkRequestUpload(int i, String packageName) { + OneTimeWorkRequest workRequest = new OneTimeWorkRequest.Builder(InfluxDB2xUploadWorker.class) + .addTag(super.getTestUUID()) + .addTag(super.getMeasurementUUID()) + .addTag(super.getSequenceUUID()) + .addTag(super.getCampaignUUID()) + .setInputData(getInputAsDataBuilder(i, packageName).build()) + .build(); + return workRequest; + } + + @Override + public OneTimeWorkRequest getWorkRequestExecutor(int i, String packageName) { + OneTimeWorkRequest workRequest = new OneTimeWorkRequest.Builder(PingWorker.class) + .addTag(super.getTestUUID()) + .addTag(super.getMeasurementUUID()) + .addTag(super.getSequenceUUID()) + .addTag(super.getCampaignUUID()) + .setInputData(getInputAsDataBuilder(i, packageName).build()) + .build(); + return workRequest; + } +} diff --git a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Iperf3Input.java b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Iperf3Input.java deleted file mode 100644 index 20dc68bd..00000000 --- a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Iperf3Input.java +++ /dev/null @@ -1,243 +0,0 @@ -package de.fraunhofer.fokus.OpenMobileNetworkToolkit.Iperf3; - -import static androidx.work.multiprocess.RemoteListenableWorker.ARGUMENT_CLASS_NAME; -import static androidx.work.multiprocess.RemoteListenableWorker.ARGUMENT_PACKAGE_NAME; - -import android.content.ComponentName; -import android.os.Environment; -import android.os.Parcel; -import android.os.Parcelable; - -import androidx.annotation.NonNull; -import androidx.work.Data; -import androidx.work.OneTimeWorkRequest; -import androidx.work.multiprocess.RemoteWorkerService; - - -import com.google.gson.GsonBuilder; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -import java.sql.Timestamp; - -import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Iperf3.Service.Iperf3ServiceWorkerFour; -import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Iperf3.Service.Iperf3ServiceWorkerThree; -import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Iperf3.Service.Iperf3ServiceWorkerTwo; -import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Iperf3.Worker.Iperf3ExecutorWorker; -import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Iperf3.Service.Iperf3ServiceWorkerOne; -import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Iperf3.Worker.Iperf3ToLineProtocolWorker; -import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Iperf3.Worker.Iperf3UploadWorker; - - -public class Iperf3Input implements Parcelable { - public static final String[] EXCLUDED_FIELDS = { - "measurementName", "rawFile", "logFileName", "command", "lineProtocolFile", - "context", "timestamp", "uuid", "cardView", "main", "EXCLUDED_FIELDS" - }; - - - public static final String rootPath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS).getAbsolutePath(); - public static final String jsonDirPath = rootPath+"/omnt/iperf3/json/"; - public static final String lineProtocolDirPath = rootPath+"/omnt/iperf3/lineprotocol/"; - private static final String TAG = "Iperf3Input"; - public static final String IPERF3INPUT = "iperf3input"; - public static final String TESTUUID = "testUUID"; - public static final String SEQUENCEUUID = "sequenceUUID"; - public static final String MEASUREMENTUUID = "measurementUUID"; - public static final String CAMPAIGNUUID = "campaignUUID"; - public static final String IPERF3UUID = "iPerf3UUID"; - protected Iperf3Input(Parcel in) { - rawFile = in.readString(); - iperf3Parameter = in.readParcelable(Iperf3Parameter.class.getClassLoader()); - testUUID = in.readString(); - logFileName = in.readString(); - measurementName = in.readString(); - lineProtocolFile = in.readString(); - timestamp = (Timestamp) in.readSerializable(); - } - - public static final Creator CREATOR = new Creator<>() { - @Override - public Iperf3Input createFromParcel(Parcel in) { - return new Iperf3Input(in); - } - - @Override - public Iperf3Input[] newArray(int size) { - return new Iperf3Input[size]; - } - }; - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(@NonNull Parcel parcel, int i) { - - parcel.writeString(rawFile); - parcel.writeParcelable(iperf3Parameter, i); - parcel.writeString(testUUID); - parcel.writeString(logFileName); - parcel.writeString(measurementName); - parcel.writeString(lineProtocolFile); - parcel.writeSerializable(timestamp); - } - private String rawFile; - private Iperf3Parameter iperf3Parameter; - private String testUUID; - private String logFileName; - private String measurementName; - private String lineProtocolFile; - private Timestamp timestamp; - private String campaignUUID; - private String sequenceUUID; - private String measurementUUID; - public Iperf3Input(Iperf3Parameter iperf3Parameter, - String testUUID, - String sequenceUUID, - String measurementUUID, - String campaignUUID) { - try { - this.iperf3Parameter = iperf3Parameter; - } catch (IllegalArgumentException e) { - e.printStackTrace(); - return; - } - this.testUUID = testUUID; - this.sequenceUUID = sequenceUUID; - this.measurementUUID = measurementUUID; - this.campaignUUID = campaignUUID; - this.rawFile = jsonDirPath+this.testUUID +".json"; - this.lineProtocolFile = lineProtocolDirPath+this.testUUID +".txt"; - this.timestamp = new Timestamp(System.currentTimeMillis()); - } - - public Iperf3Parameter getIperf3Parameter() { - return iperf3Parameter; - } - - public String getTestUUID() { - return testUUID; - } - - public String getSequenceUUID() { - return sequenceUUID; - } - - public String getCampaignUUID() { - return campaignUUID; - } - - public String getMeasurementUUID() { - return measurementUUID; - } - - public String getRawFile() { - return rawFile; - } - - public String getLogFileName() { - return logFileName; - } - - public String getLineProtocolFile() { - return lineProtocolFile; - } - - public Timestamp getTimestamp() { - return timestamp; - } - - public Data.Builder getInputAsDataBuilder(int i, String packageName) { - Data.Builder data = new Data.Builder(); - String serviceName = ""; - switch (i){ - case 0: - serviceName = Iperf3ServiceWorkerOne.class.getName(); - break; - case 1: - serviceName = Iperf3ServiceWorkerTwo.class.getName(); - break; - case 2: - serviceName = Iperf3ServiceWorkerThree.class.getName(); - break; - case 3: - serviceName = Iperf3ServiceWorkerFour.class.getName(); - break; - default: - break; - - } - ComponentName componentName = new ComponentName(packageName, serviceName); - - data.putString(ARGUMENT_PACKAGE_NAME, componentName.getPackageName()); - data.putString(ARGUMENT_CLASS_NAME, componentName.getClassName()); - data.putInt("notificationNumber", i); - data.putString(IPERF3INPUT, new GsonBuilder().create().toJson(this, Iperf3Input.class)); - return data; - } - - public OneTimeWorkRequest getWorkRequestExecutor(int i, String packageName) { - OneTimeWorkRequest workRequest = new OneTimeWorkRequest.Builder(Iperf3ExecutorWorker.class) - .addTag(testUUID) - .addTag(iperf3Parameter.getiPerf3UUID()) - .addTag(measurementUUID) - .addTag(sequenceUUID) - .addTag(campaignUUID) - .setInputData(getInputAsDataBuilder(i, packageName).build()) - .build(); - return workRequest; - } - - public OneTimeWorkRequest getWorkRequestLineProtocol() { - OneTimeWorkRequest workRequest = new OneTimeWorkRequest.Builder(Iperf3ToLineProtocolWorker.class) - .addTag(testUUID) - .addTag(iperf3Parameter.getiPerf3UUID()) - .addTag(measurementUUID) - .addTag(sequenceUUID) - .addTag(campaignUUID) - // .setInputData(getInputAsDataBuilder().build()) - .build(); - return workRequest; - } - - public OneTimeWorkRequest getWorkRequestUpload() { - OneTimeWorkRequest workRequest = new OneTimeWorkRequest.Builder(Iperf3UploadWorker.class) - .addTag(testUUID) - .addTag(iperf3Parameter.getiPerf3UUID()) - .addTag(measurementUUID) - .addTag(sequenceUUID) - .addTag(campaignUUID) - //.setInputData(getInputAsDataBuilder().build()) - .build(); - return workRequest; - } - - - public static byte[] convertToBytes(Iperf3Input object) throws IOException { - try (ByteArrayOutputStream bos = new ByteArrayOutputStream(); - ObjectOutputStream out = new ObjectOutputStream(bos)) { - out.writeObject(object); - return bos.toByteArray(); - } - } - - public static Object convertFromBytes(byte[] bytes) throws IOException, ClassNotFoundException { - try (ByteArrayInputStream bis = new ByteArrayInputStream(bytes); - ObjectInputStream in = new ObjectInputStream(bis)) { - return in.readObject(); - } - } - - - - - - - -} \ No newline at end of file diff --git a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Worker/Iperf3ExecutorWorker.java b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Worker/Iperf3ExecutorWorker.java index 886cb234..739a8fe5 100644 --- a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Worker/Iperf3ExecutorWorker.java +++ b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Worker/Iperf3ExecutorWorker.java @@ -20,25 +20,20 @@ import androidx.annotation.Nullable; import androidx.concurrent.futures.CallbackToFutureAdapter; import androidx.core.app.NotificationCompat; -import androidx.work.CoroutineWorker; import androidx.work.Data; import androidx.work.ForegroundInfo; import androidx.work.WorkManager; -import androidx.work.Worker; import androidx.work.WorkerParameters; import androidx.work.multiprocess.RemoteCoroutineWorker; -import androidx.work.multiprocess.RemoteListenableWorker; import com.google.common.util.concurrent.ListenableFuture; import com.google.gson.Gson; -import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Iperf3.Iperf3Input; +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Inputs.Iperf3Input; import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Iperf3.Iperf3LibLoader; import de.fraunhofer.fokus.OpenMobileNetworkToolkit.R; import kotlin.coroutines.Continuation; -import java.io.IOException; - public class Iperf3ExecutorWorker extends RemoteCoroutineWorker { private static final String TAG = "iperf3Worker"; private static final int NOTIFICATIONID = 1003; @@ -53,7 +48,7 @@ public class Iperf3ExecutorWorker extends RemoteCoroutineWorker { public Iperf3ExecutorWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) { super(context, workerParams); Gson gson = new Gson(); - String iperf3InputString = getInputData().getString(Iperf3Input.IPERF3INPUT); + String iperf3InputString = getInputData().getString(Iperf3Input.INPUT); notificationNumber = getInputData().getInt("notificationNumber", 0); iperf3Input = gson.fromJson(iperf3InputString, Iperf3Input.class); diff --git a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Worker/Iperf3ToLineProtocolWorker.java b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Worker/Iperf3ToLineProtocolWorker.java index 5a5b4d35..9f6b9605 100644 --- a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Worker/Iperf3ToLineProtocolWorker.java +++ b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Worker/Iperf3ToLineProtocolWorker.java @@ -18,7 +18,6 @@ import androidx.work.Worker; import androidx.work.WorkerParameters; -import com.google.common.base.Splitter; import com.google.gson.Gson; import com.influxdb.client.domain.WritePrecision; import com.influxdb.client.write.Point; @@ -26,23 +25,18 @@ import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; -import java.util.Collections; -import java.util.HashMap; import java.util.LinkedList; -import java.util.Map; import de.fraunhofer.fokus.OpenMobileNetworkToolkit.DataProvider.DeviceInformation; import de.fraunhofer.fokus.OpenMobileNetworkToolkit.GlobalVars; import de.fraunhofer.fokus.OpenMobileNetworkToolkit.InfluxDB2x.InfluxdbConnection; import de.fraunhofer.fokus.OpenMobileNetworkToolkit.InfluxDB2x.InfluxdbConnections; -import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Iperf3.Iperf3Input; -import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Iperf3.Iperf3Parameter; +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Inputs.Iperf3Input; import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Iperf3.Iperf3Parser; import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Iperf3.JSON.Interval.Interval; import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Iperf3.JSON.Interval.Streams.Stream; import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Iperf3.JSON.Interval.Streams.TCP.TCP_UL_STREAM; import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Iperf3.JSON.Interval.Streams.UDP.UDP_DL_STREAM; -import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Preferences.SPType; import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Preferences.SharedPreferencesGrouper; public class Iperf3ToLineProtocolWorker extends Worker { @@ -55,7 +49,7 @@ public class Iperf3ToLineProtocolWorker extends Worker { public Iperf3ToLineProtocolWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) { super(context, workerParams); Gson gson = new Gson(); - String iperf3InputString = getInputData().getString(Iperf3Input.IPERF3INPUT); + String iperf3InputString = getInputData().getString(Iperf3Input.INPUT); iperf3Input = gson.fromJson(iperf3InputString, Iperf3Input.class); spg = SharedPreferencesGrouper.getInstance(getApplicationContext()); } diff --git a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Worker/Iperf3UploadWorker.java b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Worker/Iperf3UploadWorker.java index 2b4e9af0..f2ab9edf 100644 --- a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Worker/Iperf3UploadWorker.java +++ b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Worker/Iperf3UploadWorker.java @@ -27,7 +27,7 @@ import de.fraunhofer.fokus.OpenMobileNetworkToolkit.InfluxDB2x.InfluxdbConnection; import de.fraunhofer.fokus.OpenMobileNetworkToolkit.InfluxDB2x.InfluxdbConnections; -import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Iperf3.Iperf3Input; +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Inputs.Iperf3Input; public class Iperf3UploadWorker extends Worker { private static final String TAG = "Iperf3UploadWorker"; @@ -37,7 +37,7 @@ public class Iperf3UploadWorker extends Worker { public Iperf3UploadWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) { super(context, workerParams); Gson gson = new Gson(); - String iperf3InputString = getInputData().getString(Iperf3Input.IPERF3INPUT); + String iperf3InputString = getInputData().getString(Iperf3Input.INPUT); iperf3Input = gson.fromJson(iperf3InputString, Iperf3Input.class); } private void setup(){ diff --git a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/MQTT/Handler/Handler.java b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/MQTT/Handler/Handler.java new file mode 100644 index 00000000..2a1d3e60 --- /dev/null +++ b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/MQTT/Handler/Handler.java @@ -0,0 +1,30 @@ +package de.fraunhofer.fokus.OpenMobileNetworkToolkit.MQTT.Handler; + +import android.content.Context; +import android.util.Log; + +import androidx.work.OneTimeWorkRequest; +import androidx.work.WorkManager; +import androidx.work.multiprocess.RemoteWorkContinuation; +import androidx.work.multiprocess.RemoteWorkManager; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import java.util.ArrayList; + +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Inputs.Iperf3Input; +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Parameter.Iperf3Parameter; + +abstract public class Handler { + private final String TAG = "Handler"; + abstract public void parsePayload(String payload) throws JSONException; + + public Handler() { + } + + abstract public void enableSequence(Context context); + + abstract public void disableSequence(Context context); +} diff --git a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/MQTT/Handler/Iperf3Handler.java b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/MQTT/Handler/Iperf3Handler.java index 98cfb5ba..2ab5bbdc 100644 --- a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/MQTT/Handler/Iperf3Handler.java +++ b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/MQTT/Handler/Iperf3Handler.java @@ -1,20 +1,13 @@ package de.fraunhofer.fokus.OpenMobileNetworkToolkit.MQTT.Handler; -import android.app.Application; import android.content.Context; import android.util.Log; -import androidx.annotation.NonNull; -import androidx.work.Configuration; import androidx.work.OneTimeWorkRequest; import androidx.work.WorkManager; -import androidx.work.WorkRequest; -import androidx.work.multiprocess.RemoteCoroutineWorker; import androidx.work.multiprocess.RemoteWorkContinuation; import androidx.work.multiprocess.RemoteWorkManager; -import com.google.common.collect.Streams; - import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; @@ -22,13 +15,15 @@ import java.util.ArrayList; -import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Iperf3.Iperf3Input; -import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Iperf3.Iperf3Parameter; +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Inputs.Iperf3Input; +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Parameter.Iperf3Parameter; -public class Iperf3Handler{ +public class Iperf3Handler extends Handler { private final String TAG = "Iperf3Handler"; private ArrayList iperf3Inputs = new ArrayList<>(); - private void parsePayload(String payload) throws JSONException { + + @Override + public void parsePayload(String payload) throws JSONException { iperf3Inputs.clear(); JSONArray tests = new JSONArray(payload); for (int i = 0; i < tests.length(); i++) { @@ -49,17 +44,13 @@ private void parsePayload(String payload) throws JSONException { } } - public Iperf3Handler(String payload) { - try { - parsePayload(payload); - } catch (JSONException e){ - Log.e(TAG, "Error parsing payload: " + e.getMessage()); - return; - } + public Iperf3Handler() { + super(); } + @Override public void enableSequence(Context context){ if(iperf3Inputs.isEmpty()) { Log.e(TAG, "No iperf3 tests to run"); @@ -89,6 +80,7 @@ public void enableSequence(Context context){ } + @Override public void disableSequence(Context context){ RemoteWorkManager workManager = RemoteWorkManager.getInstance(context); for(Iperf3Input iperf3Input: iperf3Inputs){ diff --git a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/MQTT/Handler/PingHandler.java b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/MQTT/Handler/PingHandler.java index b6849086..9aefd017 100644 --- a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/MQTT/Handler/PingHandler.java +++ b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/MQTT/Handler/PingHandler.java @@ -1,4 +1,65 @@ package de.fraunhofer.fokus.OpenMobileNetworkToolkit.MQTT.Handler; -public class PingHandler { +import android.content.Context; + +import androidx.work.OneTimeWorkRequest; +import androidx.work.WorkManager; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import java.util.ArrayList; + +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Inputs.PingInput; +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Parameter.PingParameter; + +public class PingHandler extends Handler { + + private ArrayList pingInputs = new ArrayList<>(); + @Override + public void parsePayload(String payload) throws JSONException { + pingInputs.clear(); + JSONArray tests = new JSONArray(payload); + for (int i = 0; i < tests.length(); i++) { + JSONObject test = tests.getJSONObject(i); + String testUUID = test.getString("testUUID"); + String measurementUUUID = test.getString("measurementUUID"); + String sequenceUUID = test.getString("sequenceUUID"); + String campaignUUID = test.getString("campaignUUID"); + String device = test.getString("device"); + String testType = test.getString("type"); + if(!testType.equals("ping")) continue; + JSONObject params = test.getJSONObject("params"); + + PingParameter pingParameter = new PingParameter(params); + if(pingParameter == null) continue; + PingInput pingInput = new PingInput(pingParameter, testUUID, sequenceUUID, measurementUUUID,campaignUUID); + pingInputs.add(pingInput); + } + } + + @Override + public void enableSequence(Context context) { + + WorkManager workManager = WorkManager.getInstance(context); + ArrayList executorWorkRequests = new ArrayList<>(); + ArrayList toLineProtocolWorkRequests = new ArrayList<>(); + ArrayList uploadWorkRequests = new ArrayList<>(); + for(PingInput pingInput : pingInputs) { + executorWorkRequests.add(pingInput.getWorkRequestExecutor(pingInputs.indexOf(pingInput), context.getPackageName())); + toLineProtocolWorkRequests.add(pingInput.getWorkRequestLineProtocol(pingInputs.indexOf(pingInput), context.getPackageName())); + uploadWorkRequests.add(pingInput.getWorkRequestUpload(pingInputs.indexOf(pingInput), context.getPackageName())); + } + + workManager.beginWith(executorWorkRequests) + .then(toLineProtocolWorkRequests) + .then(uploadWorkRequests) + .enqueue(); + } + + @Override + public void disableSequence(Context context) { + + } } diff --git a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/MQTT/MQTTService.java b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/MQTT/MQTTService.java index 263ae4c9..f3c5a865 100644 --- a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/MQTT/MQTTService.java +++ b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/MQTT/MQTTService.java @@ -29,6 +29,7 @@ import java.util.concurrent.TimeUnit; import de.fraunhofer.fokus.OpenMobileNetworkToolkit.MQTT.Handler.Iperf3Handler; +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.MQTT.Handler.PingHandler; import de.fraunhofer.fokus.OpenMobileNetworkToolkit.MainActivity; import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Preferences.SPType; import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Preferences.SharedPreferencesGrouper; @@ -45,6 +46,7 @@ public class MQTTService extends Service { private SharedPreferencesGrouper spg; private String deviceName; private Iperf3Handler iperf3Handler; + private PingHandler pingHandler; @Nullable @Override public IBinder onBind(Intent intent) { @@ -313,9 +315,15 @@ private void handleConfigMessage(String topic, String payload){ return; } - if(topic.contains("iperf3/command")){ + if(topic.contains("/iperf3/command")){ Log.d(TAG, "handleConfigMessage: Iperf3 Command: " + payload); - iperf3Handler = new Iperf3Handler(payload); + iperf3Handler = new Iperf3Handler(); + try { + iperf3Handler.parsePayload(payload); + } catch (Exception e) { + Log.e(TAG, "handleConfigMessage: Error parsing iperf3 payload: " + e.getMessage()); + //TODO PUBLISH ERROR + } return; } if(topic.contains("/iperf3/enable")){ @@ -323,8 +331,35 @@ private void handleConfigMessage(String topic, String payload){ if(iperf3Handler != null && parseBoolean(payload)){ iperf3Handler.enableSequence(getApplicationContext()); + //TODO PUBLISH iperf3 sequence enabled } else if(iperf3Handler != null && !parseBoolean(payload)){ iperf3Handler.disableSequence(getApplicationContext()); + //TODO PUBLISH iperf3 sequence disabled + } + return; + } + + if(topic.contains("/ping/command")){ + Log.d(TAG, "handleConfigMessage: Ping Command: " + payload); + pingHandler = new PingHandler(); + try { + pingHandler.parsePayload(payload); + } catch (Exception e) { + Log.e(TAG, "handleConfigMessage: Error parsing ping payload: " + e.getMessage()); + //TODO PUBLISH ERROR + } + return; + } + + if(topic.contains("/ping/enable")){ + Log.d(TAG, "handleConfigMessage: Enable Ping: " + payload); + + if(pingHandler != null && parseBoolean(payload)){ + pingHandler.enableSequence(getApplicationContext()); + //TODO PUBLISH ping sequence enabled + } else if(pingHandler != null && !parseBoolean(payload)){ + pingHandler.disableSequence(getApplicationContext()); + //TODO PUBLISH ping sequence disabled } return; } diff --git a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Iperf3Parameter.java b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Parameter/Iperf3Parameter.java similarity index 99% rename from app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Iperf3Parameter.java rename to app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Parameter/Iperf3Parameter.java index c115ed01..6db6f6f4 100644 --- a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Iperf3Parameter.java +++ b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Parameter/Iperf3Parameter.java @@ -1,4 +1,4 @@ -package de.fraunhofer.fokus.OpenMobileNetworkToolkit.Iperf3; +package de.fraunhofer.fokus.OpenMobileNetworkToolkit.Parameter; import android.os.Parcel; import android.os.Parcelable; diff --git a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Parameter/Parameter.java b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Parameter/Parameter.java new file mode 100644 index 00000000..da4a0bc8 --- /dev/null +++ b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Parameter/Parameter.java @@ -0,0 +1,19 @@ +package de.fraunhofer.fokus.OpenMobileNetworkToolkit.Parameter; + +import android.os.Parcel; +import android.os.Parcelable; + +public abstract class Parameter implements Parcelable { + protected Parameter(Parcel in) { + } + + + public int describeContents() { + return 0; + } + + public void writeToParcel(android.os.Parcel dest, int flags) { + + } + +} diff --git a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Parameter/PingParameter.java b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Parameter/PingParameter.java new file mode 100644 index 00000000..4f3ca6c7 --- /dev/null +++ b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Parameter/PingParameter.java @@ -0,0 +1,52 @@ +package de.fraunhofer.fokus.OpenMobileNetworkToolkit.Parameter; + +import android.os.Parcel; +import android.os.Parcelable; +import android.util.Log; + +import androidx.annotation.NonNull; + +import org.json.JSONException; +import org.json.JSONObject; + +public class PingParameter extends Parameter { + private static final String TAG = "PingParameter"; + private String command; + + public PingParameter(JSONObject command) { + super(null); + try { + this.command = command.getString("command"); + } catch (JSONException e) { + Log.d(TAG, e.toString()); + Log.w(TAG, "could not create PingParameter!"); + } + } + + protected PingParameter(Parcel in) { + super(in); + command = in.readString(); + } + + public static final Creator CREATOR = new Creator() { + @Override + public PingParameter createFromParcel(Parcel in) { + return new PingParameter(in); + } + + @Override + public PingParameter[] newArray(int size) { + return new PingParameter[size]; + } + }; + + @Override + public int describeContents() { + return super.describeContents(); + } + + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeString(command); + } +} From de333d6d844553d48f2a7ba7c62dd76b033d9a12 Mon Sep 17 00:00:00 2001 From: hajoha Date: Sun, 9 Feb 2025 02:49:31 +0100 Subject: [PATCH 15/43] update --- app/build.gradle | 3 +- app/src/main/AndroidManifest.xml | 1 - .../CustomEventListener.java | 11 + .../Worker/InfluxDB2xUploadWorker.java | 8 +- .../Inputs/Inputs.java | 67 +----- .../Inputs/Iperf3Input.java | 20 +- .../Inputs/PingInput.java | 31 +-- .../Iperf3/Worker/Iperf3ExecutorWorker.java | 78 +++---- .../Worker/Iperf3ToLineProtocolWorker.java | 6 +- .../Iperf3/Worker/Iperf3UploadWorker.java | 8 +- .../MQTT/Handler/Handler.java | 7 + .../MQTT/Handler/Iperf3Handler.java | 48 +++- .../MQTT/Handler/PingHandler.java | 52 ++++- .../MQTT/MQTTService.java | 101 ++++++++- .../Parameter/Iperf3Parameter.java | 49 ++-- .../Parameter/Parameter.java | 2 + .../Parameter/PingParameter.java | 151 ++++++++++++- .../Ping/PingFragment.java | 7 +- .../Ping/PingParser.java | 8 +- .../Ping/PingService.java | 31 +-- .../Ping/PingWorker.java | 210 ------------------ .../Ping/Worker/PingToLineProtocolWorker.java | 155 +++++++++++++ .../Ping/Worker/PingWorker.java | 163 ++++++++++++++ .../RemoteWorkInfoChecker.java | 97 ++++++++ app/src/main/res/values/strings.xml | 1 + 25 files changed, 878 insertions(+), 437 deletions(-) create mode 100644 app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/CustomEventListener.java delete mode 100644 app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Ping/PingWorker.java create mode 100644 app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Ping/Worker/PingToLineProtocolWorker.java create mode 100644 app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Ping/Worker/PingWorker.java create mode 100644 app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/RemoteWorkInfoChecker.java diff --git a/app/build.gradle b/app/build.gradle index d2895c99..66c24795 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -138,9 +138,8 @@ dependencies { androidTestImplementation "androidx.work:work-testing:$work_version" implementation "androidx.work:work-multiprocess:$work_version" - + implementation "org.jetbrains.kotlinx:kotlinx-coroutines-guava:1.6.0" implementation 'androidx.preference:preference:1.2.1' - implementation "androidx.room:room-runtime:$room_version" annotationProcessor "androidx.room:room-compiler:$room_version" implementation 'androidx.appcompat:appcompat:1.7.0' diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index bf0063fd..e3212ab6 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -38,7 +38,6 @@ - workInfos); +} diff --git a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/InfluxDB2x/Worker/InfluxDB2xUploadWorker.java b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/InfluxDB2x/Worker/InfluxDB2xUploadWorker.java index fb50890e..46d38767 100644 --- a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/InfluxDB2x/Worker/InfluxDB2xUploadWorker.java +++ b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/InfluxDB2x/Worker/InfluxDB2xUploadWorker.java @@ -31,7 +31,7 @@ import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Inputs.Iperf3Input; public class InfluxDB2xUploadWorker extends Worker { - private static final String TAG = "InfDB2xUploadWorker"; + public static final String TAG = "InfDB2xUploadWorker"; InfluxdbConnection influx; private Inputs input; public static final String UPLOAD = "influxdb2x_upload"; @@ -65,17 +65,17 @@ public Result doWork() { } BufferedReader br; try { - br = new BufferedReader(new FileReader(input.getLineProtocolFile())); + br = new BufferedReader(new FileReader("")); } catch (FileNotFoundException | NullPointerException e) { Log.d(TAG,e.toString()); return Result.failure(output); } List points = br.lines().collect(Collectors.toList()); try { - Log.d(TAG, String.format("doWork: uploading %s", input.getLineProtocolFile())); + // Log.d(TAG, String.format("doWork: uploading %s", input.getLineProtocolFile())); influx.writeRecords(points); } catch (IOException e) { - Log.d(TAG, String.format("doWork: upload of %s failed!", input.getLineProtocolFile())); + // Log.d(TAG, String.format("doWork: upload of %s failed!", input.getLineProtocolFile())); return Result.failure(output); } diff --git a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Inputs/Inputs.java b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Inputs/Inputs.java index c226352b..77abfe0a 100644 --- a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Inputs/Inputs.java +++ b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Inputs/Inputs.java @@ -12,29 +12,25 @@ public abstract class Inputs implements Parcelable { - public static final String rootPath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS).getAbsolutePath(); + public static final String INPUT = "input"; public static final String TESTUUID = "testUUID"; public static final String SEQUENCEUUID = "sequenceUUID"; public static final String MEASUREMENTUUID = "measurementUUID"; public static final String CAMPAIGNUUID = "campaignUUID"; - private String rawFile; + public static final String DEVICE = "device"; + public static final String TYPE = "type"; + public static final String PARAMS = "params"; + public static final String NOTIFICATIONUMBER = "notificationNumber"; private String testUUID; - private String logFileName; - private String measurementName; - private String lineProtocolFile; + private Timestamp timestamp; private String campaignUUID; private String sequenceUUID; private String measurementUUID; - public String getRawFile() { - return rawFile; - } - public void setRawFile(String rawFile) { - this.rawFile = rawFile; - } + public String getTestUUID() { return testUUID; @@ -44,29 +40,6 @@ public void setTestUUID(String testUUID) { this.testUUID = testUUID; } - public String getLogFileName() { - return logFileName; - } - - public void setLogFileName(String logFileName) { - this.logFileName = logFileName; - } - - public String getMeasurementName() { - return measurementName; - } - - public void setMeasurementName(String measurementName) { - this.measurementName = measurementName; - } - - public String getLineProtocolFile() { - return lineProtocolFile; - } - - public void setLineProtocolFile(String lineProtocolFile) { - this.lineProtocolFile = lineProtocolFile; - } public Timestamp getTimestamp() { return timestamp; @@ -88,37 +61,15 @@ public String getMeasurementUUID() { return measurementUUID; } protected Inputs(Parcel in) { - rawFile = in.readString(); - logFileName = in.readString(); - measurementName = in.readString(); - lineProtocolFile = in.readString(); timestamp = (Timestamp) in.readSerializable(); campaignUUID = in.readString(); sequenceUUID = in.readString(); measurementUUID = in.readString(); testUUID = in.readString(); } - public Inputs(String rawFile, String logFileName, String measurementName, String lineProtocolFile, String campaignUUID, String sequenceUUID, String measurementUUID, String testUUID) { - - this.rawFile = rawFile; - this.logFileName = logFileName; - this.measurementName = measurementName; - this.lineProtocolFile = lineProtocolFile; - this.timestamp = new Timestamp(System.currentTimeMillis()); - - this.campaignUUID = campaignUUID; - this.sequenceUUID = sequenceUUID; - this.measurementUUID = measurementUUID; - this.testUUID = testUUID; - } public Inputs(String campaignUUID, String sequenceUUID, String measurementUUID, String testUUID) { - this.rawFile = ""; - this.logFileName = ""; - this.measurementName = ""; - this.lineProtocolFile = ""; this.timestamp = new Timestamp(System.currentTimeMillis()); - this.campaignUUID = campaignUUID; this.sequenceUUID = sequenceUUID; this.measurementUUID = measurementUUID; @@ -132,10 +83,6 @@ public int describeContents() { @Override public void writeToParcel(@NonNull Parcel dest, int flags) { - dest.writeString(rawFile); - dest.writeString(logFileName); - dest.writeString(measurementName); - dest.writeString(lineProtocolFile); dest.writeSerializable(timestamp); dest.writeString(campaignUUID); dest.writeString(sequenceUUID); diff --git a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Inputs/Iperf3Input.java b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Inputs/Iperf3Input.java index 598b4e25..de49735e 100644 --- a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Inputs/Iperf3Input.java +++ b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Inputs/Iperf3Input.java @@ -25,9 +25,9 @@ public class Iperf3Input extends Inputs { - public static final String rawDirPath = rootPath+"/omnt/iperf3/raw/"; - public static final String lineProtocolDirPath = rootPath+"/omnt/iperf3/lineprotocol/"; + private static final String TAG = "Iperf3Input"; + public static final String IPERF3UUID = "iPerf3UUID"; private Iperf3Parameter iperf3Parameter; @@ -65,8 +65,6 @@ public Iperf3Input(Iperf3Parameter iperf3Parameter, String measurementUUID, String campaignUUID) { super(testUUID, sequenceUUID, measurementUUID, campaignUUID); - super.setRawFile(rawDirPath +testUUID+".json"); - super.setLineProtocolFile(lineProtocolDirPath+testUUID+".txt"); this.iperf3Parameter = iperf3Parameter; } @@ -98,46 +96,46 @@ public Data.Builder getInputAsDataBuilder(int i, String packageName) { data.putString(ARGUMENT_PACKAGE_NAME, componentName.getPackageName()); data.putString(ARGUMENT_CLASS_NAME, componentName.getClassName()); - data.putInt("notificationNumber", i); + data.putInt(NOTIFICATIONUMBER, i); data.putString(Inputs.INPUT, new GsonBuilder().create().toJson(this, Iperf3Input.class)); return data; } @Override public OneTimeWorkRequest getWorkRequestExecutor(int i, String packageName) { - OneTimeWorkRequest workRequest = new OneTimeWorkRequest.Builder(Iperf3ExecutorWorker.class) + return new OneTimeWorkRequest.Builder(Iperf3ExecutorWorker.class) .addTag(super.getTestUUID()) .addTag(super.getMeasurementUUID()) .addTag(super.getSequenceUUID()) .addTag(super.getCampaignUUID()) + .addTag(Iperf3ExecutorWorker.TAG) .addTag(iperf3Parameter.getiPerf3UUID()) .setInputData(getInputAsDataBuilder(i, packageName).build()) .build(); - return workRequest; } @Override public OneTimeWorkRequest getWorkRequestLineProtocol(int i, String packageName) { - OneTimeWorkRequest workRequest = new OneTimeWorkRequest.Builder(Iperf3ToLineProtocolWorker.class) + return new OneTimeWorkRequest.Builder(Iperf3ToLineProtocolWorker.class) .addTag(super.getTestUUID()) .addTag(super.getMeasurementUUID()) .addTag(super.getSequenceUUID()) .addTag(super.getCampaignUUID()) + .addTag(Iperf3ToLineProtocolWorker.TAG) .addTag(iperf3Parameter.getiPerf3UUID()) .setInputData(getInputAsDataBuilder(i, packageName).build()) .build(); - return workRequest; } @Override public OneTimeWorkRequest getWorkRequestUpload(int i, String packageName) { - OneTimeWorkRequest workRequest = new OneTimeWorkRequest.Builder(Iperf3UploadWorker.class) + return new OneTimeWorkRequest.Builder(Iperf3UploadWorker.class) .addTag(super.getTestUUID()) .addTag(super.getMeasurementUUID()) .addTag(super.getSequenceUUID()) .addTag(super.getCampaignUUID()) + .addTag(Iperf3UploadWorker.TAG) .addTag(iperf3Parameter.getiPerf3UUID()) .setInputData(getInputAsDataBuilder(i, packageName).build()) .build(); - return workRequest; } } \ No newline at end of file diff --git a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Inputs/PingInput.java b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Inputs/PingInput.java index dc3161e4..526a4eac 100644 --- a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Inputs/PingInput.java +++ b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Inputs/PingInput.java @@ -8,17 +8,14 @@ import com.google.gson.Gson; import de.fraunhofer.fokus.OpenMobileNetworkToolkit.InfluxDB2x.Worker.InfluxDB2xUploadWorker; -import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Iperf3.Worker.Iperf3ExecutorWorker; import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Iperf3.Worker.Iperf3ToLineProtocolWorker; -import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Iperf3.Worker.Iperf3UploadWorker; import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Parameter.PingParameter; -import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Ping.PingWorker; +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Ping.Worker.PingWorker; public class PingInput extends Inputs { - PingParameter pingParameter; - public static final String rawDirPath = rootPath+"/omnt/ping/raw/"; - public static final String lineProtocolDirPath = rootPath+"/omnt/ping/lineprotocol/"; + private PingParameter pingParameter; + protected PingInput(Parcel in) { super(in); @@ -29,8 +26,6 @@ public PingInput(PingParameter pingParameter, String measurementUUID, String campaignUUID) { super(testUUID, sequenceUUID, measurementUUID, campaignUUID); - super.setRawFile(rawDirPath +testUUID+".json"); - super.setLineProtocolFile(lineProtocolDirPath+testUUID+".txt"); this.pingParameter = pingParameter; } @@ -43,10 +38,15 @@ public void writeToParcel(Parcel dest, int flags) { public Data.Builder getInputAsDataBuilder(int i, String packageName) { Data.Builder data = new Data.Builder(); Gson gson = new Gson(); - data.putString(INPUT, gson.toJson(pingParameter)); + data.putInt(NOTIFICATIONUMBER, i); + data.putString(INPUT, gson.toJson(this)); return data; } + public PingParameter getPingParameter() { + return pingParameter; + } + @Override public int describeContents() { return 0; @@ -67,37 +67,38 @@ public PingInput[] newArray(int size) { @Override public OneTimeWorkRequest getWorkRequestLineProtocol(int i, String packageName) { - OneTimeWorkRequest workRequest = new OneTimeWorkRequest.Builder(Iperf3ToLineProtocolWorker.class) + // TODO FIX + return new OneTimeWorkRequest.Builder(Iperf3ToLineProtocolWorker.class) .addTag(super.getTestUUID()) .addTag(super.getMeasurementUUID()) .addTag(super.getSequenceUUID()) .addTag(super.getCampaignUUID()) + .addTag("Ping") // TODO FIX .setInputData(getInputAsDataBuilder(i, packageName).build()) .build(); - return workRequest; } @Override public OneTimeWorkRequest getWorkRequestUpload(int i, String packageName) { - OneTimeWorkRequest workRequest = new OneTimeWorkRequest.Builder(InfluxDB2xUploadWorker.class) + return new OneTimeWorkRequest.Builder(InfluxDB2xUploadWorker.class) .addTag(super.getTestUUID()) .addTag(super.getMeasurementUUID()) .addTag(super.getSequenceUUID()) .addTag(super.getCampaignUUID()) + .addTag(InfluxDB2xUploadWorker.TAG) .setInputData(getInputAsDataBuilder(i, packageName).build()) .build(); - return workRequest; } @Override public OneTimeWorkRequest getWorkRequestExecutor(int i, String packageName) { - OneTimeWorkRequest workRequest = new OneTimeWorkRequest.Builder(PingWorker.class) + return new OneTimeWorkRequest.Builder(PingWorker.class) .addTag(super.getTestUUID()) .addTag(super.getMeasurementUUID()) .addTag(super.getSequenceUUID()) .addTag(super.getCampaignUUID()) + .addTag(PingWorker.TAG) .setInputData(getInputAsDataBuilder(i, packageName).build()) .build(); - return workRequest; } } diff --git a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Worker/Iperf3ExecutorWorker.java b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Worker/Iperf3ExecutorWorker.java index 739a8fe5..a71f692c 100644 --- a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Worker/Iperf3ExecutorWorker.java +++ b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Worker/Iperf3ExecutorWorker.java @@ -11,6 +11,7 @@ import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_SPECIAL_USE; import android.app.Notification; +import android.app.NotificationManager; import android.app.PendingIntent; import android.content.Context; import android.graphics.Color; @@ -22,45 +23,54 @@ import androidx.core.app.NotificationCompat; import androidx.work.Data; import androidx.work.ForegroundInfo; +import androidx.work.ListenableWorker; import androidx.work.WorkManager; import androidx.work.WorkerParameters; import androidx.work.multiprocess.RemoteCoroutineWorker; +import androidx.work.multiprocess.RemoteListenableWorker; import com.google.common.util.concurrent.ListenableFuture; import com.google.gson.Gson; +import java.util.concurrent.ExecutionException; + import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Inputs.Iperf3Input; +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Inputs.PingInput; import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Iperf3.Iperf3LibLoader; import de.fraunhofer.fokus.OpenMobileNetworkToolkit.R; import kotlin.coroutines.Continuation; -public class Iperf3ExecutorWorker extends RemoteCoroutineWorker { - private static final String TAG = "iperf3Worker"; - private static final int NOTIFICATIONID = 1003; +public class Iperf3ExecutorWorker extends RemoteListenableWorker { + public static final String TAG = "Iperf3ExecutorWorker"; static { Iperf3LibLoader.load(); } - + private final String channelId = "OMNT_notification_channel"; private final int FOREGROUND_SERVICE_TYPE = FOREGROUND_SERVICE_TYPE_SPECIAL_USE; private Iperf3Input iperf3Input; - private int notificationNumber; + private int notificationID; + private NotificationCompat.Builder notificationBuilder; + private Notification notification; public Iperf3ExecutorWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) { super(context, workerParams); Gson gson = new Gson(); String iperf3InputString = getInputData().getString(Iperf3Input.INPUT); - notificationNumber = getInputData().getInt("notificationNumber", 0); iperf3Input = gson.fromJson(iperf3InputString, Iperf3Input.class); + int notificationNumber = getInputData().getInt(PingInput.NOTIFICATIONUMBER, 0); + notificationID += notificationNumber; + notificationBuilder = new NotificationCompat.Builder(context, channelId); } @NonNull @Override public ListenableFuture startRemoteWork() { + return CallbackToFutureAdapter.getFuture(completer -> { - Log.i(TAG, "Starting ExampleRemoteListenableWorker"); - setForegroundAsync(createForegroundInfo()); + Log.i(TAG, "Starting "+TAG); + setForegroundAsync(createForegroundInfo(iperf3Input.getIperf3Parameter().getHost()+":"+iperf3Input.getIperf3Parameter().getPort())); int result = iperf3Wrapper(iperf3Input.getIperf3Parameter().getInputAsCommand(), getApplicationContext().getApplicationInfo().nativeLibraryDir); @@ -76,49 +86,23 @@ public ListenableFuture startRemoteWork() { return completer.set(Result.failure(output .build())); }); - } + private native int iperf3Wrapper(String[] argv, String cache); private native int iperf3Stop(); - private ForegroundInfo createForegroundInfo() { - - Context context = getApplicationContext(); - String id = "OMNT_notification_channel"; - PendingIntent intent = WorkManager.getInstance(context) - .createCancelPendingIntent(getId()); - Notification notification = new NotificationCompat.Builder(context, id) - .setContentTitle("iPerf3") - .setContentText("Host " + iperf3Input.getIperf3Parameter().getHost() + " Port " + iperf3Input.getIperf3Parameter().getPort()) - .setOngoing(true) - .setColor(Color.WHITE) - .setSmallIcon(R.mipmap.ic_launcher_foreground) - .setForegroundServiceBehavior(Notification.FOREGROUND_SERVICE_DEFAULT) - .build(); - return new ForegroundInfo(NOTIFICATIONID+notificationNumber, notification, FOREGROUND_SERVICE_TYPE); - } - - @Nullable - @Override - public Object doRemoteWork(@NonNull Continuation continuation) { - Log.i(TAG, "Starting ExampleRemoteListenableWorker"); - - setForegroundAsync(createForegroundInfo()); - - int result = - iperf3Wrapper(iperf3Input.getIperf3Parameter().getInputAsCommand(), getApplicationContext().getApplicationInfo().nativeLibraryDir); - Log.d(TAG, "doWork: " + result); - - - Data.Builder output = new Data.Builder() - .putInt("result", result) - .putString("testUUID", iperf3Input.getTestUUID()); - if (result == 0) { - return Result.success(output.build()); - } - return Result.failure(output - .build()); + private ForegroundInfo createForegroundInfo(String progress) { + notification = notificationBuilder + .setContentTitle("iPerf3") + .setContentText(progress) + .setOngoing(true) + .setOnlyAlertOnce(true) + .setColor(Color.WHITE) + .setSmallIcon(R.mipmap.ic_launcher_foreground) + .setForegroundServiceBehavior(Notification.FOREGROUND_SERVICE_IMMEDIATE) + .build(); + return new ForegroundInfo(notificationID, notification, FOREGROUND_SERVICE_TYPE); } -} +} \ No newline at end of file diff --git a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Worker/Iperf3ToLineProtocolWorker.java b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Worker/Iperf3ToLineProtocolWorker.java index 9f6b9605..d135cf79 100644 --- a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Worker/Iperf3ToLineProtocolWorker.java +++ b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Worker/Iperf3ToLineProtocolWorker.java @@ -40,7 +40,7 @@ import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Preferences.SharedPreferencesGrouper; public class Iperf3ToLineProtocolWorker extends Worker { - private static final String TAG = "Iperf3UploadWorker"; + public static final String TAG = "Iperf3ToLineProtocolWorker"; InfluxdbConnection influx; private SharedPreferencesGrouper spg; @@ -66,7 +66,7 @@ public Result doWork() { setup(); Data output = new Data.Builder().putBoolean("iperf3_upload", false).build(); - Iperf3Parser iperf3Parser = new Iperf3Parser(iperf3Input.getRawFile()); + Iperf3Parser iperf3Parser = new Iperf3Parser(iperf3Input.getIperf3Parameter().getLogfile()); iperf3Parser.parse(); @@ -165,7 +165,7 @@ public Result doWork() { FileOutputStream iperf3Stream = null; try { - iperf3Stream = new FileOutputStream(iperf3Input.getLineProtocolFile(), true); + iperf3Stream = new FileOutputStream(iperf3Input.getIperf3Parameter().getLineProtocolFile(), true); } catch (FileNotFoundException e) { Toast.makeText(getApplicationContext(), "logfile not created", Toast.LENGTH_SHORT).show(); Log.d(TAG,e.toString()); diff --git a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Worker/Iperf3UploadWorker.java b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Worker/Iperf3UploadWorker.java index f2ab9edf..d2851231 100644 --- a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Worker/Iperf3UploadWorker.java +++ b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Worker/Iperf3UploadWorker.java @@ -30,7 +30,7 @@ import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Inputs.Iperf3Input; public class Iperf3UploadWorker extends Worker { - private static final String TAG = "Iperf3UploadWorker"; + public static final String TAG = "Iperf3UploadWorker"; InfluxdbConnection influx; private Iperf3Input iperf3Input; @@ -65,17 +65,17 @@ public Result doWork() { } BufferedReader br; try { - br = new BufferedReader(new FileReader(iperf3Input.getLineProtocolFile())); + br = new BufferedReader(new FileReader(iperf3Input.getIperf3Parameter().getLineProtocolFile())); } catch (FileNotFoundException | NullPointerException e) { Log.d(TAG,e.toString()); return Result.failure(output); } List points = br.lines().collect(Collectors.toList()); try { - Log.d(TAG, String.format("doWork: uploading %s", iperf3Input.getLineProtocolFile())); + Log.d(TAG, String.format("doWork: uploading %s", iperf3Input.getIperf3Parameter().getLineProtocolFile())); influx.writeRecords(points); } catch (IOException e) { - Log.d(TAG, String.format("doWork: upload of %s failed!", iperf3Input.getLineProtocolFile())); + Log.d(TAG, String.format("doWork: upload of %s failed!", iperf3Input.getIperf3Parameter().getLineProtocolFile())); return Result.failure(output); } diff --git a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/MQTT/Handler/Handler.java b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/MQTT/Handler/Handler.java index 2a1d3e60..30b22154 100644 --- a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/MQTT/Handler/Handler.java +++ b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/MQTT/Handler/Handler.java @@ -4,6 +4,7 @@ import android.util.Log; import androidx.work.OneTimeWorkRequest; +import androidx.work.WorkInfo; import androidx.work.WorkManager; import androidx.work.multiprocess.RemoteWorkContinuation; import androidx.work.multiprocess.RemoteWorkManager; @@ -15,6 +16,7 @@ import java.util.ArrayList; import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Inputs.Iperf3Input; +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Inputs.PingInput; import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Parameter.Iperf3Parameter; abstract public class Handler { @@ -23,6 +25,11 @@ abstract public class Handler { public Handler() { } + abstract public ArrayList getExecutorWorkRequests(Context context); + + abstract public ArrayList getToLineProtocolWorkRequests(Context context); + + abstract public ArrayList getUploadWorkRequests(Context context); abstract public void enableSequence(Context context); diff --git a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/MQTT/Handler/Iperf3Handler.java b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/MQTT/Handler/Iperf3Handler.java index 2ab5bbdc..3e35302a 100644 --- a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/MQTT/Handler/Iperf3Handler.java +++ b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/MQTT/Handler/Iperf3Handler.java @@ -4,6 +4,7 @@ import android.util.Log; import androidx.work.OneTimeWorkRequest; +import androidx.work.WorkInfo; import androidx.work.WorkManager; import androidx.work.multiprocess.RemoteWorkContinuation; import androidx.work.multiprocess.RemoteWorkManager; @@ -16,12 +17,13 @@ import java.util.ArrayList; import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Inputs.Iperf3Input; +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Inputs.PingInput; import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Parameter.Iperf3Parameter; public class Iperf3Handler extends Handler { private final String TAG = "Iperf3Handler"; private ArrayList iperf3Inputs = new ArrayList<>(); - + private boolean isEnable = false; @Override public void parsePayload(String payload) throws JSONException { iperf3Inputs.clear(); @@ -37,16 +39,50 @@ public void parsePayload(String payload) throws JSONException { if(!testType.equals("iperf3")) continue; JSONObject params = test.getJSONObject("params"); - Iperf3Parameter iperf3Parameter = new Iperf3Parameter(params); + Iperf3Parameter iperf3Parameter = new Iperf3Parameter(params, testUUID); if(iperf3Parameter == null) continue; Iperf3Input iperf3Input = new Iperf3Input(iperf3Parameter, testUUID, sequenceUUID, measurementUUUID,campaignUUID); iperf3Inputs.add(iperf3Input); } } + public ArrayList getTestUUIDs() { + ArrayList testUUIDs = new ArrayList<>(); + for(Iperf3Input iperf3Input : iperf3Inputs) { + testUUIDs.add(iperf3Input.getTestUUID()); + } + return testUUIDs; + } public Iperf3Handler() { super(); } + @Override + public ArrayList getExecutorWorkRequests(Context context) { + ArrayList executorWorkRequests = new ArrayList<>(); + for(Iperf3Input iperf3Input : iperf3Inputs) { + executorWorkRequests.add(iperf3Input.getWorkRequestExecutor(iperf3Inputs.indexOf(iperf3Input), context.getPackageName())); + } + return executorWorkRequests; + } + + + + @Override + public ArrayList getToLineProtocolWorkRequests(Context context) { + ArrayList lineProtocolWorkRequests = new ArrayList<>(); + for(Iperf3Input iperf3Input : iperf3Inputs) { + lineProtocolWorkRequests.add(iperf3Input.getWorkRequestLineProtocol(iperf3Inputs.indexOf(iperf3Input), context.getPackageName())); + } + return lineProtocolWorkRequests; + } + @Override + public ArrayList getUploadWorkRequests(Context context) { + ArrayList uploadWorkRequests = new ArrayList<>(); + for(Iperf3Input iperf3Input : iperf3Inputs) { + uploadWorkRequests.add(iperf3Input.getWorkRequestUpload(iperf3Inputs.indexOf(iperf3Input), context.getPackageName())); + } + return uploadWorkRequests; + } @@ -87,6 +123,14 @@ public void disableSequence(Context context){ workManager.cancelAllWorkByTag(iperf3Input.getTestUUID()); } } + + public boolean isEnable() { + return isEnable; + } + + public void setEnable(boolean enable) { + isEnable = enable; + } } diff --git a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/MQTT/Handler/PingHandler.java b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/MQTT/Handler/PingHandler.java index 9aefd017..5afa69ed 100644 --- a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/MQTT/Handler/PingHandler.java +++ b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/MQTT/Handler/PingHandler.java @@ -3,7 +3,6 @@ import android.content.Context; import androidx.work.OneTimeWorkRequest; -import androidx.work.WorkManager; import org.json.JSONArray; import org.json.JSONException; @@ -16,7 +15,9 @@ public class PingHandler extends Handler { + public static final String TAG = "PingHandler"; private ArrayList pingInputs = new ArrayList<>(); + private boolean isEnable = false; @Override public void parsePayload(String payload) throws JSONException { pingInputs.clear(); @@ -32,34 +33,63 @@ public void parsePayload(String payload) throws JSONException { if(!testType.equals("ping")) continue; JSONObject params = test.getJSONObject("params"); - PingParameter pingParameter = new PingParameter(params); + PingParameter pingParameter = new PingParameter(params, testUUID); if(pingParameter == null) continue; PingInput pingInput = new PingInput(pingParameter, testUUID, sequenceUUID, measurementUUUID,campaignUUID); pingInputs.add(pingInput); } + } - @Override - public void enableSequence(Context context) { + public ArrayList getTestUUIDs() { + ArrayList testUUIDs = new ArrayList<>(); + for(PingInput pingInput : pingInputs) { + testUUIDs.add(pingInput.getTestUUID()); + } + return testUUIDs; + } - WorkManager workManager = WorkManager.getInstance(context); + @Override + public ArrayList getExecutorWorkRequests(Context context) { ArrayList executorWorkRequests = new ArrayList<>(); - ArrayList toLineProtocolWorkRequests = new ArrayList<>(); - ArrayList uploadWorkRequests = new ArrayList<>(); for(PingInput pingInput : pingInputs) { executorWorkRequests.add(pingInput.getWorkRequestExecutor(pingInputs.indexOf(pingInput), context.getPackageName())); + } + return executorWorkRequests; + } + @Override + public ArrayList getToLineProtocolWorkRequests(Context context) { + ArrayList toLineProtocolWorkRequests = new ArrayList<>(); + for(PingInput pingInput : pingInputs) { toLineProtocolWorkRequests.add(pingInput.getWorkRequestLineProtocol(pingInputs.indexOf(pingInput), context.getPackageName())); + } + return toLineProtocolWorkRequests; + } + @Override + public ArrayList getUploadWorkRequests(Context context) { + ArrayList uploadWorkRequests = new ArrayList<>(); + for(PingInput pingInput : pingInputs) { uploadWorkRequests.add(pingInput.getWorkRequestUpload(pingInputs.indexOf(pingInput), context.getPackageName())); } + return uploadWorkRequests; + } + + @Override + public void enableSequence(Context context) { - workManager.beginWith(executorWorkRequests) - .then(toLineProtocolWorkRequests) - .then(uploadWorkRequests) - .enqueue(); } @Override public void disableSequence(Context context) { + + } + + public boolean isEnable() { + return isEnable; + } + + public void setEnable(boolean enable) { + isEnable = enable; } } diff --git a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/MQTT/MQTTService.java b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/MQTT/MQTTService.java index f3c5a865..fecf98d5 100644 --- a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/MQTT/MQTTService.java +++ b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/MQTT/MQTTService.java @@ -15,6 +15,11 @@ import androidx.annotation.Nullable; import androidx.core.app.NotificationCompat; +import androidx.work.Data; +import androidx.work.ExistingWorkPolicy; +import androidx.work.OneTimeWorkRequest; +import androidx.work.WorkInfo; +import androidx.work.multiprocess.RemoteWorkManager; import com.hivemq.client.mqtt.datatypes.MqttQos; @@ -25,15 +30,20 @@ import java.net.InetSocketAddress; import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.UUID; import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.CustomEventListener; import de.fraunhofer.fokus.OpenMobileNetworkToolkit.MQTT.Handler.Iperf3Handler; import de.fraunhofer.fokus.OpenMobileNetworkToolkit.MQTT.Handler.PingHandler; import de.fraunhofer.fokus.OpenMobileNetworkToolkit.MainActivity; import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Preferences.SPType; import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Preferences.SharedPreferencesGrouper; import de.fraunhofer.fokus.OpenMobileNetworkToolkit.R; +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.RemoteWorkInfoChecker; public class MQTTService extends Service { private static final String TAG = "MQTTService"; @@ -47,6 +57,8 @@ public class MQTTService extends Service { private String deviceName; private Iperf3Handler iperf3Handler; private PingHandler pingHandler; + private boolean isEnabled = false; + @Nullable @Override public IBinder onBind(Intent intent) { @@ -364,6 +376,12 @@ private void handleConfigMessage(String topic, String payload){ return; } + if(topic.contains("/sequence/enable")){ + Log.d(TAG, "handleConfigMessage: Enable Sequence: " + payload); + setEnabled(parseBoolean(payload)); + return; + } + Log.d(TAG, "handleConfigMessage: No matching topic found: " + topic); return; @@ -378,14 +396,9 @@ private void subsribetoTopic(String topic){ Log.e(TAG, "Received empty payload from topic: " + publish.getTopic()); return; }; - new Runnable(){ - @Override - public void run() { - Log.d(TAG, "Received config message: " + publish.getTopic()); - String payload = StandardCharsets.UTF_8.decode(publish.getPayload().get()).toString(); - handleConfigMessage(publish.getTopic().toString(), payload); - } - }.run(); + Log.d(TAG, "Received message: " + publish.getTopic()); + String payload = StandardCharsets.UTF_8.decode(publish.getPayload().get()).toString(); + handleConfigMessage(publish.getTopic().toString(), payload); }) .send() .whenComplete((subAck, throwable) -> { @@ -415,7 +428,79 @@ public int onStartCommand(Intent intent, int flags, int startId) { createClient(); connectClient(); subscribeToAllTopics(); + return START_STICKY; } + private void executeWork() { + ArrayList oneTimeWorkExecutorRequests = new ArrayList<>(); + ArrayList oneTimeWorkLineProtocolRequests = new ArrayList<>(); + ArrayList oneTimeWorkUploadRequests = new ArrayList<>(); + + RemoteWorkManager remoteWorkManager = RemoteWorkManager.getInstance(context); + + if (iperf3Handler != null && isEnabled) { + oneTimeWorkExecutorRequests.addAll(iperf3Handler.getExecutorWorkRequests(context)); + oneTimeWorkLineProtocolRequests.addAll(iperf3Handler.getToLineProtocolWorkRequests(context)); + oneTimeWorkUploadRequests.addAll(iperf3Handler.getUploadWorkRequests(context)); + } else { + Log.d(TAG, "executeWork: Iperf3 Handler is either null or not enabled"); + } + + if (pingHandler != null && isEnabled) { + oneTimeWorkExecutorRequests.addAll(pingHandler.getExecutorWorkRequests(context)); + oneTimeWorkLineProtocolRequests.addAll(pingHandler.getToLineProtocolWorkRequests(context)); + oneTimeWorkUploadRequests.addAll(pingHandler.getUploadWorkRequests(context)); + } else { + Log.d(TAG, "executeWork: Ping Handler is either null or not enabled"); + } + + enqueueWorkRequests(remoteWorkManager, oneTimeWorkExecutorRequests, oneTimeWorkLineProtocolRequests, oneTimeWorkUploadRequests); + } + + private void enqueueWorkRequests(RemoteWorkManager remoteWorkManager, + ArrayList executorRequests, + ArrayList lineProtocolRequests, + ArrayList uploadRequests) { + + + Log.d(TAG, "enqueueWorkRequests: Enqueueing work Executor requests "+executorRequests.size()); + Log.d(TAG, "enqueueWorkRequests: Enqueueing work LineProtocol requests "+lineProtocolRequests.size()); + Log.d(TAG, "enqueueWorkRequests: Enqueueing work Upload requests "+uploadRequests.size()); + remoteWorkManager.beginUniqueWork("foobar", ExistingWorkPolicy.REPLACE, executorRequests) + .then(lineProtocolRequests) + // .then(uploadRequests) + .enqueue(); + + CustomEventListener listener = new CustomEventListener() { + @Override + public void onChange(HashMap workInfos) { + for (WorkInfo info : workInfos.values()) { + WorkInfo.State state = info.getState(); + Log.d(TAG, "onChange: WorkInfo: " + info.getTags() + " State: " + state); + Data data = info.getOutputData(); + Log.i(TAG, "onChange: "+data.toString()); + } + + } + }; + startWorkInfoChecker(remoteWorkManager, executorRequests, listener); + //startWorkInfoChecker(remoteWorkManager, lineProtocolRequests, listener); + //startWorkInfoChecker(remoteWorkManager, uploadRequests, listener); + } + + private void startWorkInfoChecker(RemoteWorkManager remoteWorkManager, ArrayList workRequests, CustomEventListener listener) { + ArrayList workIdGroups = new ArrayList<>(); + for (OneTimeWorkRequest workRequest : workRequests) { + workIdGroups.add(workRequest.getId()); + } + RemoteWorkInfoChecker remoteWorkInfoChecker = new RemoteWorkInfoChecker(remoteWorkManager, workIdGroups); + remoteWorkInfoChecker.setListener(listener); + remoteWorkInfoChecker.start(); + } + + private void setEnabled(boolean isEnabled) { + this.isEnabled = isEnabled; + executeWork(); + } } diff --git a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Parameter/Iperf3Parameter.java b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Parameter/Iperf3Parameter.java index 6db6f6f4..a9485e32 100644 --- a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Parameter/Iperf3Parameter.java +++ b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Parameter/Iperf3Parameter.java @@ -1,5 +1,6 @@ package de.fraunhofer.fokus.OpenMobileNetworkToolkit.Parameter; +import android.os.Environment; import android.os.Parcel; import android.os.Parcelable; import android.util.Log; @@ -9,9 +10,15 @@ import org.json.JSONException; import org.json.JSONObject; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; import java.util.ArrayList; public class Iperf3Parameter implements Parcelable { + public static final String rootPath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS).getAbsolutePath(); + public static final String rawDirPath = rootPath+"/omnt/iperf3/raw/"; + public static final String lineProtocolDirPath = rootPath+"/omnt/iperf3/lineprotocol/"; public static final String HOST = "host"; public static final String PORT = "port"; public static final String BANDWIDTH = "bandwidth"; @@ -76,8 +83,10 @@ public class Iperf3Parameter implements Parcelable { public static final String IPERF3UUID = "iperf3UUID"; private static final String TAG = "Iperf3Parameter"; + private String lineProtocolFile; protected Iperf3Parameter(Parcel in) { + lineProtocolFile = in.readString(); host = in.readString(); iPerf3UUID = in.readString(); duration = in.readInt(); @@ -365,7 +374,12 @@ public Iperf3Parameter(String ip, this.rsaPublicKeyPath = rsaPublicKeyPath; } - public Iperf3Parameter(JSONObject jsonObject) { + public Iperf3Parameter(JSONObject jsonObject, String testUUID) { + this.testUUID = testUUID; + this.logfile = rawDirPath+testUUID+".json"; + this.lineProtocolFile = lineProtocolDirPath+testUUID+".txt"; + this.jsonStream = true; + try { this.host = jsonObject.getString(HOST); } catch (JSONException e) { @@ -479,7 +493,7 @@ public Iperf3Parameter(JSONObject jsonObject) { Log.d(TAG, "extraData not set."); } try{ - this.title = jsonObject.getString(TIME); + this.title = jsonObject.getString(TITLE); } catch (JSONException e) { Log.d(TAG, "title not set."); } @@ -664,12 +678,7 @@ public Iperf3Parameter(JSONObject jsonObject) { } catch (JSONException e) { Log.d(TAG, "forceflush not set."); } - try{ - this.logfile = jsonObject.getString(LOGFILE); - } catch (JSONException e) { - Log.d(TAG, "logfile not set."); - } - this.jsonStream = true; + try{ this.verbose = jsonObject.getBoolean(VERBOSE); } catch (JSONException e) { @@ -710,6 +719,12 @@ public Iperf3Parameter(JSONObject jsonObject) { } catch (JSONException e) { Log.d(TAG, "title not set."); } + try { + Files.createDirectories(Paths.get(rawDirPath)); + Files.createDirectories(Paths.get(lineProtocolDirPath)); + } catch (IOException e) { + Log.d(TAG, "Could not create directories."); + } } @Override @@ -719,6 +734,7 @@ public int describeContents() { @Override public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeString(lineProtocolFile); dest.writeString(host); dest.writeString(iPerf3UUID); dest.writeInt(duration); @@ -790,6 +806,10 @@ public String getHost() { return host; } + public String getLineProtocolFile() { + return lineProtocolFile; + } + // --- Enums --- public enum Iperf3Mode { CLIENT, @@ -820,7 +840,7 @@ public String toPrettyPrint() { // Required field. private String host; private String iPerf3UUID; - + private String testUUID; // Optional fields with defaults based on iperf3. private int duration = 10; // Default duration: 10 seconds. private Iperf3Protocol protocol = Iperf3Protocol.TCP; // Default protocol: TCP. @@ -932,7 +952,9 @@ public Iperf3Protocol getProtocol() { public void setProtocol(Iperf3Protocol protocol) { this.protocol = (protocol != null) ? protocol : Iperf3Protocol.TCP; } - + public void setTestUUID(String testUUID) { + this.testUUID = testUUID; + } public int getPort() { return port; } @@ -1561,10 +1583,6 @@ public String[] getInputAsCommand() { command.add("-J"); } - if (logfile != null && !logfile.trim().isEmpty()) { - command.add("--logfile"); - command.add(logfile); - } if (forceflush != null && forceflush) { command.add("--forceflush"); } @@ -1769,6 +1787,9 @@ public String[] getInputAsCommand() { // Always add these extra fixed options. command.add("--json-stream"); + command.add("--logfile"); + command.add(logfile); + return command.toArray(new String[0]); diff --git a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Parameter/Parameter.java b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Parameter/Parameter.java index da4a0bc8..3b267bf3 100644 --- a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Parameter/Parameter.java +++ b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Parameter/Parameter.java @@ -1,9 +1,11 @@ package de.fraunhofer.fokus.OpenMobileNetworkToolkit.Parameter; +import android.os.Environment; import android.os.Parcel; import android.os.Parcelable; public abstract class Parameter implements Parcelable { + public static final String rootPath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS).getAbsolutePath(); protected Parameter(Parcel in) { } diff --git a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Parameter/PingParameter.java b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Parameter/PingParameter.java index 4f3ca6c7..47119eab 100644 --- a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Parameter/PingParameter.java +++ b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Parameter/PingParameter.java @@ -1,7 +1,7 @@ package de.fraunhofer.fokus.OpenMobileNetworkToolkit.Parameter; +import android.net.Network; import android.os.Parcel; -import android.os.Parcelable; import android.util.Log; import androidx.annotation.NonNull; @@ -9,23 +9,152 @@ import org.json.JSONException; import org.json.JSONObject; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.ArrayList; + public class PingParameter extends Parameter { + public static final String rawDirPath = rootPath+"/omnt/ping/raw/"; + public static final String lineProtocolDirPath = rootPath+"/omnt/ping/lineprotocol/"; private static final String TAG = "PingParameter"; - private String command; - public PingParameter(JSONObject command) { + public static final String PING = "ping"; + public static final String DESTINATION = "destination"; + public static final String COUNT = "count"; + public static final String TIMEOUT = "timeout"; // in seconds + public static final String PACKET_SIZE = "packetSize"; + public static final String INTERVAL = "interval"; // in seconds + + public String getDestination() { + return destination; + } + + public int getCount() { + return count; + } + + public int getTimeoutMillis() { + return timeoutMillis; + } + + public int getPacketSize() { + return packetSize; + } + + public long getIntervalMillis() { + return intervalMillis; + } + + public String getLogfile() { + return logfile; + } + + public Network getNetwork() { + return network; + } + + private String destination; + private int count; + private int timeoutMillis; + private int packetSize; + private long intervalMillis; + private Network network; + private int deadline; + private String lineProtocolFile; + private String logfile; + private String testUUID; + + + public String[] getInputAsCommand() { + ArrayList command = new ArrayList<>(); + command.add("/system/bin/ping"); + if (count > 0) { + command.add("-c"); + command.add(String.valueOf(count)); + } + if (timeoutMillis > 0) { + command.add("-W"); + command.add(String.valueOf(timeoutMillis)); + } + if (packetSize > 0) { + command.add("-s"); + command.add(String.valueOf(packetSize)); + } + if (intervalMillis > 0) { + command.add("-i"); + command.add(String.valueOf(intervalMillis)); + } + if (deadline > 0) { + command.add("-w"); + command.add(String.valueOf(deadline)); + } + command.add("-D"); + command.add(destination); + + return command.toArray(new String[0]); + } + public PingParameter(JSONObject parameter, String testUUID) { super(null); + this.testUUID = testUUID; try { - this.command = command.getString("command"); + destination = parameter.getString(DESTINATION); } catch (JSONException e) { Log.d(TAG, e.toString()); Log.w(TAG, "could not create PingParameter!"); + throw new IllegalArgumentException("Destination is missing"); + } + try { + count = parameter.getInt(COUNT); + } catch (JSONException e) { + Log.d(TAG, e.toString()); + Log.i(TAG, "No count set."); + } + try { + timeoutMillis = parameter.getInt(TIMEOUT); + } catch (JSONException e) { + Log.d(TAG, e.toString()); + Log.i(TAG, "no timeout set."); + } + try { + packetSize = parameter.getInt(PACKET_SIZE); + } catch (JSONException e) { + Log.d(TAG, e.toString()); + Log.i(TAG, "no packet size set."); + } + try { + intervalMillis = parameter.getLong(INTERVAL); + } catch (JSONException e) { + Log.d(TAG, e.toString()); + Log.i(TAG, "no interval set."); } + try { + deadline = parameter.getInt("deadline"); + } catch (JSONException e) { + Log.d(TAG, e.toString()); + Log.i(TAG, "no deadline set."); + } + + try { + Files.createDirectories(Paths.get(rawDirPath)); + Files.createDirectories(Paths.get(lineProtocolDirPath)); + } catch (IOException e) { + Log.d(TAG, "Could not create directories."); + } + + logfile = rawDirPath + this.testUUID + ".txt"; + lineProtocolFile = lineProtocolDirPath + this.testUUID + ".txt"; + } protected PingParameter(Parcel in) { super(in); - command = in.readString(); + destination = in.readString(); + count = in.readInt(); + timeoutMillis = in.readInt(); + packetSize = in.readInt(); + intervalMillis = in.readLong(); + network = in.readParcelable(Network.class.getClassLoader()); } public static final Creator CREATOR = new Creator() { @@ -47,6 +176,16 @@ public int describeContents() { @Override public void writeToParcel(@NonNull Parcel dest, int flags) { - dest.writeString(command); + super.writeToParcel(dest, flags); + dest.writeString(destination); + dest.writeInt(count); + dest.writeInt(timeoutMillis); + dest.writeInt(packetSize); + dest.writeLong(intervalMillis); + dest.writeParcelable(network, flags); + } + + public String getLineProtocolFile() { + return lineProtocolFile; } } diff --git a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Ping/PingFragment.java b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Ping/PingFragment.java index 0947055d..1995e60c 100644 --- a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Ping/PingFragment.java +++ b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Ping/PingFragment.java @@ -174,8 +174,9 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container, horizontalLL1.addView(metricsLL); - - PingParser pingParser = PingParser.getInstance(null); + //ToDO + /* + PingParser pingParser = PingParser; pingParser.addPropertyChangeListener(evt -> { PingInformation pi = (PingInformation) evt.getNewValue(); switch (pi.getLineType()) { @@ -188,7 +189,7 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container, break; } }); - + */ //packetLossMetric.setVisibility(View.INVISIBLE); return v; } diff --git a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Ping/PingParser.java b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Ping/PingParser.java index 78fc4fa4..c0f40c99 100644 --- a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Ping/PingParser.java +++ b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Ping/PingParser.java @@ -18,17 +18,13 @@ public class PingParser { private final PropertyChangeSupport support; private PropertyChangeListener listener; - private PingParser(BufferedReader br) { + public PingParser(BufferedReader br) { this.br = br; this.lines = new ArrayList<>(); support = new PropertyChangeSupport(this); } - public static PingParser getInstance(BufferedReader br){ - if (instance == null) instance = new PingParser(br); - if(br != null); instance.setBr(br); - return instance; - } + private LINEType getLineType(String line){ if (line.contains("bytes from")) { return LINEType.RTT; diff --git a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Ping/PingService.java b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Ping/PingService.java index aa895bcc..34f0bca0 100644 --- a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Ping/PingService.java +++ b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Ping/PingService.java @@ -41,6 +41,7 @@ import de.fraunhofer.fokus.OpenMobileNetworkToolkit.InfluxDB2x.InfluxdbConnection; import de.fraunhofer.fokus.OpenMobileNetworkToolkit.InfluxDB2x.InfluxdbConnections; import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Ping.PingInformations.PingInformation; +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Ping.Worker.PingWorker; import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Preferences.SPType; import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Preferences.SharedPreferencesGrouper; @@ -129,38 +130,8 @@ private void setupPing(){ } spg.getSharedPreference(SPType.ping_sp).edit().putBoolean("ping", true).apply(); pingLogging = new Handler(Objects.requireNonNull(Looper.myLooper())); - PingParser pingParser = PingParser.getInstance(null); - propertyChangeListener = pingParser.getListener(); - if(propertyChangeListener != null){ - pingParser.removePropertyChangeListener(propertyChangeListener); - } - propertyChangeListener = new PropertyChangeListener() { - @Override - public void propertyChange(PropertyChangeEvent evt) { - PingInformation pi = (PingInformation) evt.getNewValue(); - - Point point = pi.getPoint(); - point.addTags(dp.getTagsMap()); - Log.d(TAG, "propertyChange: "+point.toLineProtocol()); - try { - ping_stream.write((point.toLineProtocol() + "\n").getBytes()); - } catch (IOException e) { - Log.d(TAG,e.toString()); - } - - if (spg.getSharedPreference(SPType.logging_sp).getBoolean("enable_influx", false) && influx.getWriteApi() != null) { - try { - influx.writePoints(List.of(point)); - } catch (IOException e) { - Log.d(TAG,e.toString()); - } - } - } - }; - pingParser.addPropertyChangeListener(propertyChangeListener); - pingParser.setListener(propertyChangeListener); pingLogging.post(pingUpdate); } public void parsePingCommand() { diff --git a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Ping/PingWorker.java b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Ping/PingWorker.java deleted file mode 100644 index dd1d04d7..00000000 --- a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Ping/PingWorker.java +++ /dev/null @@ -1,210 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2023 Peter Hasse - * SPDX-FileCopyrightText: 2023 Johann Hackler - * SPDX-FileCopyrightText: 2023 Fraunhofer FOKUS - * - * SPDX-License-Identifier: BSD-3-Clause-Clear - */ - -package de.fraunhofer.fokus.OpenMobileNetworkToolkit.Ping; - -import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_SPECIAL_USE; - -import android.app.Notification; -import android.app.NotificationManager; -import android.app.PendingIntent; -import android.content.Context; -import android.content.Intent; -import android.graphics.Color; -import android.os.Bundle; -import android.util.Log; - -import androidx.annotation.NonNull; -import androidx.core.app.NotificationCompat; -import androidx.work.Data; -import androidx.work.ForegroundInfo; -import androidx.work.WorkManager; -import androidx.work.Worker; -import androidx.work.WorkerParameters; - -import java.beans.PropertyChangeEvent; -import java.beans.PropertyChangeListener; -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStreamReader; -import java.util.ArrayList; -import java.util.HashMap; - -import de.fraunhofer.fokus.OpenMobileNetworkToolkit.MainActivity; -import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Ping.PingInformations.PingInformation; -import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Ping.PingInformations.RTTLine; -import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Preferences.SPType; -import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Preferences.SharedPreferencesGrouper; -import de.fraunhofer.fokus.OpenMobileNetworkToolkit.R; - - -public class PingWorker extends Worker { - - private static final String TAG = "PingWorker"; - Runtime runtime; - private ArrayList lines; - private Process pingProcess; - private final int notificationID = 102; - HashMap parsedCommand = new HashMap<>(); - private String pingCommand; - private final int FOREGROUND_SERVICE_TYPE = FOREGROUND_SERVICE_TYPE_SPECIAL_USE; - private final Context ct; - private final String channelId = "OMNT_notification_channel"; - private NotificationCompat.Builder notificationBuilder; - private Notification notification; - private final String timeRegex = "\\btime=([0-9]+\\.[0-9]+)\\s+ms\\b"; - private double rtt; - private NotificationManager notificationManager; - private SharedPreferencesGrouper spg; - - - public void parsePingCommand() { - - String[] commandParts = pingCommand.split("\\s+"); - - String previousPart = null; - for (String part : commandParts) { - switch (part) { - case "ping": - parsedCommand.put("command", part); - break; - case "-w": - if (previousPart != null) { - parsedCommand.put("timeout", previousPart); - } - break; - default: - parsedCommand.put("target", part); - break; - } - previousPart = part; - } - } - - public PingWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) { - super(context, workerParams); - runtime = Runtime.getRuntime(); - ct = context; - spg = SharedPreferencesGrouper.getInstance(ct); - } - - - @Override - public void onStopped() { - super.onStopped(); - Log.d(TAG, "onStopped: worker stopped!"); - if(pingProcess.isAlive()) pingProcess.destroy(); - spg.getSharedPreference(SPType.ping_sp).edit().putBoolean("ping_running", false).apply(); - - } - - private ForegroundInfo createForegroundInfo(@NonNull String progress) { - // Create an Intent to launch the main activity - Intent launchIntent = new Intent(ct, MainActivity.class); - launchIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); - - // Add a Bundle to the Intent to indicate that the PingFragment should be opened - Bundle bundle = new Bundle(); - bundle.putString("openFragment", "PingFragment"); - launchIntent.putExtras(bundle); - - // Create a PendingIntent with the Intent - PendingIntent pendingIntent = PendingIntent.getActivity(ct, 0, launchIntent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE); - - PendingIntent cancelIntent = WorkManager.getInstance(ct) - .createCancelPendingIntent(getId()); - - notification = notificationBuilder - .setContentTitle("Ping " + parsedCommand.get("target")) - .setContentText(progress) - .setOngoing(true) - .setOnlyAlertOnce(true) - .setColor(Color.WHITE) - .setSmallIcon(R.mipmap.ic_launcher_foreground) - .setForegroundServiceBehavior(Notification.FOREGROUND_SERVICE_DEFAULT) - .addAction(R.drawable.ic_close, "Cancel", cancelIntent) - .setContentIntent(pendingIntent) // Set the content intent - .build(); - return new ForegroundInfo(notificationID, notification, FOREGROUND_SERVICE_TYPE); - } - - Runnable updateNotification = new Runnable() { - @Override - public void run() { - if(notification != null){ - notificationBuilder.setContentText(rtt+" ms"); - notificationManager.notify(notificationID, notificationBuilder.build()); - } else { - setForegroundAsync(createForegroundInfo(rtt+" ms")); - } - } - }; - - @NonNull - @Override - public Result doWork() { - lines = new ArrayList<>(); - Data data = null; - notificationBuilder = new NotificationCompat.Builder(ct, channelId); - notificationManager = ct.getSystemService(NotificationManager.class); - try { - - StringBuilder stringBuilder = new StringBuilder(); - stringBuilder.append("/system/bin/ping ") - .append("-D ") - .append(getInputData().getString("input")); - - pingCommand = stringBuilder.toString(); - parsePingCommand(); - pingProcess = runtime.exec(stringBuilder.toString()); - - BufferedReader outputReader = - new BufferedReader(new InputStreamReader(pingProcess.getInputStream())); - - - - PingParser pingParser = PingParser.getInstance(outputReader); - - pingParser.addPropertyChangeListener(new PropertyChangeListener() { - @Override - public void propertyChange(PropertyChangeEvent evt) { - PingInformation pi = (PingInformation) evt.getNewValue(); - switch(pi.getLineType()){ - case PACKET_LOSS: - break; - case RTT: - rtt = ((RTTLine)pi).getRtt(); - break; - } - updateNotification.run(); - } - }); - pingParser.parse(); - int result = pingProcess.waitFor(); - - if(isStopped()){ - Log.d(TAG, "doWork: got cancelled because Worker got stopped!"); - - return Result.success(); - } - - - Log.d(TAG, "doWork: result " + result); - if (result != 0) { - return Result.failure(); - } - } catch (IOException e) { - Log.d(TAG,e.toString()); - System.out.printf(e.toString()); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } - - return Result.success(); - } -} diff --git a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Ping/Worker/PingToLineProtocolWorker.java b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Ping/Worker/PingToLineProtocolWorker.java new file mode 100644 index 00000000..a1fda46c --- /dev/null +++ b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Ping/Worker/PingToLineProtocolWorker.java @@ -0,0 +1,155 @@ +/* + * SPDX-FileCopyrightText: 2023 Peter Hasse + * SPDX-FileCopyrightText: 2023 Johann Hackler + * SPDX-FileCopyrightText: 2023 Fraunhofer FOKUS + * + * SPDX-License-Identifier: BSD-3-Clause-Clear + */ + +package de.fraunhofer.fokus.OpenMobileNetworkToolkit.Ping.Worker; + +import android.content.Context; +import android.os.Build; +import android.util.Log; +import android.widget.Toast; + +import androidx.annotation.NonNull; +import androidx.work.Data; +import androidx.work.Worker; +import androidx.work.WorkerParameters; + +import com.google.gson.Gson; +import com.influxdb.client.domain.WritePrecision; +import com.influxdb.client.write.Point; + +import java.io.BufferedInputStream; +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.FileWriter; +import java.io.IOException; +import java.io.InputStreamReader; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.Scanner; + +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.DataProvider.DeviceInformation; +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.GlobalVars; +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.InfluxDB2x.InfluxdbConnection; +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.InfluxDB2x.InfluxdbConnections; +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Inputs.Iperf3Input; +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Inputs.PingInput; +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Iperf3.Iperf3Parser; +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Iperf3.JSON.Interval.Interval; +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Iperf3.JSON.Interval.Streams.Stream; +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Iperf3.JSON.Interval.Streams.TCP.TCP_UL_STREAM; +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Iperf3.JSON.Interval.Streams.UDP.UDP_DL_STREAM; +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Parameter.PingParameter; +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Ping.PingInformations.LINEType; +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Ping.PingInformations.PacketLossLine; +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Ping.PingInformations.PingInformation; +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Ping.PingInformations.RTTLine; +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Ping.PingParser; +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Preferences.SharedPreferencesGrouper; + +public class PingToLineProtocolWorker extends Worker { + public static final String TAG = "Iperf3ToLineProtocolWorker"; + InfluxdbConnection influx; + private SharedPreferencesGrouper spg; + + private final DeviceInformation di = GlobalVars.getInstance().get_dp().getDeviceInformation(); + private PingInput pingInput; + public PingToLineProtocolWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) { + super(context, workerParams); + Gson gson = new Gson(); + String iperf3InputString = getInputData().getString(PingInput.INPUT); + pingInput = gson.fromJson(iperf3InputString, PingInput.class); + spg = SharedPreferencesGrouper.getInstance(getApplicationContext()); + } + + + private LINEType getLineType(String line){ + if (line.contains("bytes from")) { + return LINEType.RTT; + } else if (line.contains("Unreachable")) { + return LINEType.UNREACHABLE; + } else if (line.contains("Request timeout")) { + return LINEType.TIMEOUT; + } else if (line.contains("packets transmitted")){ + return LINEType.PACKET_LOSS; + } else { + return LINEType.UNKNOWN; + } + } + + @NonNull + @Override + public Result doWork() { +; + Data.Builder output = new Data.Builder().putBoolean("pingUpload", false); + File myObj = new File(pingInput.getPingParameter().getLogfile()); + Scanner scanner = null; + try { + scanner = new Scanner(myObj); + } catch (FileNotFoundException e) { + return Result.failure(output.putString("error", "File not found").build()); + } + ArrayList points = new ArrayList<>(); + while (scanner.hasNextLine()) { + String line = scanner.nextLine(); + PingInformation pi = null; + switch (getLineType(line)) { + case RTT: + pi = new RTTLine(line); + case UNREACHABLE: + //TDODO + break; + case TIMEOUT: + //TODO + break; + case PACKET_LOSS: + pi = new PacketLossLine(line); + break; + case UNKNOWN: + break; + } + if (pi == null) continue; + pi.parse(); + points.add(pi); + } + scanner.close(); + try { + Files.createDirectories(Paths.get(PingParameter.lineProtocolDirPath)); + } catch (IOException e) { + Log.d(TAG, "doWork: "+e.toString()); + } + try { + Files.createFile(Paths.get(pingInput.getPingParameter().getLineProtocolFile())); + } catch (IOException e) { + Log.d(TAG, "doWork: "+e.toString()); + return Result.failure(output.putString("error", "File not created").build()); + } + BufferedWriter writer = null; + try { + writer = new BufferedWriter(new FileWriter(pingInput.getPingParameter().getLineProtocolFile())); + } catch (IOException e) { + Log.d(TAG, "doWork: "+e.toString()); + return Result.failure(output.putString("error", "File not created").build()); + } + for (PingInformation pi : points) { + try { + writer.write(pi.getPoint().toLineProtocol() + "\n"); + } catch (IOException e) { + Log.d(TAG, "doWork: "+e.toString()); + return Result.failure(output.putString("error", "File not written").build()); + } + } + return Result.success(output.build()); + } + +} diff --git a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Ping/Worker/PingWorker.java b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Ping/Worker/PingWorker.java new file mode 100644 index 00000000..7a631319 --- /dev/null +++ b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Ping/Worker/PingWorker.java @@ -0,0 +1,163 @@ +/* + * SPDX-FileCopyrightText: 2023 Peter Hasse + * SPDX-FileCopyrightText: 2023 Johann Hackler + * SPDX-FileCopyrightText: 2023 Fraunhofer FOKUS + * + * SPDX-License-Identifier: BSD-3-Clause-Clear + */ + +package de.fraunhofer.fokus.OpenMobileNetworkToolkit.Ping.Worker; + +import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_SPECIAL_USE; + +import android.app.Notification; +import android.app.NotificationManager; +import android.content.Context; +import android.graphics.Color; +import android.util.Log; + +import androidx.annotation.NonNull; +import androidx.core.app.NotificationCompat; +import androidx.work.Data; +import androidx.work.ForegroundInfo; +import androidx.work.Worker; +import androidx.work.WorkerParameters; + +import com.google.gson.Gson; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.Objects; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Inputs.PingInput; +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Parameter.PingParameter; +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.R; + +public class PingWorker extends Worker { + + public static final String PING = "ping"; + public static final String REASON = "reason"; + public static final String LINE = "line"; + public static final String TAG = "PingWorker"; + + private int notificationID = 102; + private final int FOREGROUND_SERVICE_TYPE = FOREGROUND_SERVICE_TYPE_SPECIAL_USE; + private final Context ct; + private NotificationManager notificationManager; + private final String channelId = "OMNT_notification_channel"; + private NotificationCompat.Builder notificationBuilder; + private float rtt; // round-trip time + private PingInput pingInput; + private Notification notification; + public PingWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) { + super(context, workerParams); + ct = context; + + // Retrieve the PingInput from the Worker's input data. + String pingInputString = getInputData().getString(PingInput.INPUT); + pingInput = new Gson().fromJson(pingInputString, PingInput.class); + + int notificationNumber = getInputData().getInt(PingInput.NOTIFICATIONUMBER, 0); + notificationID += notificationNumber; + + notificationManager = (NotificationManager) ct.getSystemService(Context.NOTIFICATION_SERVICE); + notificationBuilder = new NotificationCompat.Builder(ct, channelId); + setForegroundAsync(createForegroundInfo("")); + } + + private ForegroundInfo createForegroundInfo(String progress) { + notification = notificationBuilder + .setContentTitle("Ping") + .setContentText(pingInput.getPingParameter().getDestination()+": "+progress) + .setOngoing(true) + .setOnlyAlertOnce(true) + .setColor(Color.WHITE) + .setSmallIcon(R.mipmap.ic_launcher_foreground) + .setForegroundServiceBehavior(Notification.FOREGROUND_SERVICE_DEFAULT) + .build(); + return new ForegroundInfo(notificationID, notification, FOREGROUND_SERVICE_TYPE); + } + + + @NonNull + @Override + public Result doWork() { + Data.Builder output = new Data.Builder().putBoolean(PING, false); + + if (pingInput == null) { + Log.e(TAG, "PingInput is null"); + return Result.failure(output.putString(REASON, "PingInput is null").build()); + } + PingParameter pingParameter = pingInput.getPingParameter(); + if (pingParameter == null) { + Log.e(TAG, "PingParameter is null"); + return Result.failure(output.putString(REASON, "PingParameter is null").build()); + } + String[] command = pingParameter.getInputAsCommand(); + if (command == null) { + Log.e(TAG, "Command is null"); + return Result.failure(output.putString(REASON, "Command is null").build()); + } + + Log.d(TAG, "doWork: executing " + String.join(" ", command)); + int result = -1; + try { + String timeRegex = "time=(\\d+(?:\\.\\d+)?)\\s*ms"; + Pattern pattern = Pattern.compile(timeRegex); + + + ProcessBuilder processBuilder = new ProcessBuilder(command); + Process process = processBuilder.start(); + + BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream())); + BufferedWriter writer = new BufferedWriter(new FileWriter(getApplicationContext().getFilesDir()+pingInput.getTestUUID()+".txt")); + + String line; + while ((line = reader.readLine()) != null) { + System.out.println(line); + writer.write(line + "\n"); + Matcher matcher = pattern.matcher(line); + if (matcher.find()) { + try { + rtt = Float.parseFloat(Objects.requireNonNull(matcher.group(1))); + Log.d(TAG, "Updated RTT: " + rtt); + new Runnable() { + @Override + public void run() { + setForegroundAsync(createForegroundInfo( rtt + " ms")); + } + }.run(); + } catch (NumberFormatException e) { + Log.e(TAG, "Error parsing RTT value: " + e.toString()); + } + } + // Optionally, report progress with the output line. + setProgressAsync(output.putString(LINE, line).build()); + } + + writer.close(); + reader.close(); + + result = process.waitFor(); + } catch (IOException e) { + Log.e(TAG, "Error while executing ping command: " + e.toString()); + return Result.failure(output.putString(REASON, "Error while executing ping command.").build()); + } catch (InterruptedException e) { + Log.e(TAG, "Error while waiting for ping command: " + e.toString()); + return Result.failure(output.putString(REASON, "Error while waiting for ping command.").build()); + } + + if (result != 0) { + Log.e(TAG, "Ping command failed with result: " + result); + return Result.failure(output.putString(REASON, "Ping command failed with result: " + result).build()); + } + + return Result.success(output.putBoolean(PING, true).build()); + } +} diff --git a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/RemoteWorkInfoChecker.java b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/RemoteWorkInfoChecker.java new file mode 100644 index 00000000..91333b22 --- /dev/null +++ b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/RemoteWorkInfoChecker.java @@ -0,0 +1,97 @@ +package de.fraunhofer.fokus.OpenMobileNetworkToolkit; + +import android.os.Handler; +import android.os.Looper; +import android.util.Log; + +import androidx.annotation.NonNull; +import androidx.work.WorkInfo; +import androidx.work.WorkQuery; +import androidx.work.multiprocess.RemoteWorkManager; + +import com.google.common.util.concurrent.Futures; +import com.google.common.util.concurrent.ListenableFuture; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.UUID; +import java.util.concurrent.Executor; + + +public class RemoteWorkInfoChecker implements Runnable { + private static final String TAG = "WorkInfoChecker"; + private final Handler handler = new Handler(Looper.getMainLooper()); + private final HashMap workInfors = new HashMap<>(); + private final RemoteWorkManager remoteWorkManager; + private final ArrayList workIdGroups; + private boolean isDone = false; + private final Executor executor; + private CustomEventListener listener; + + private int workCount = 0; + public RemoteWorkInfoChecker(RemoteWorkManager remoteWorkManager, ArrayList workIdGroups) { + this.remoteWorkManager = remoteWorkManager; + this.workIdGroups = workIdGroups; + this.executor = Runnable::run; + } + + + private void update(WorkInfo workInfo) { + workInfors.put(workInfo.getId(), workInfo); + if(listener != null) { + listener.onChange(new HashMap<>(workInfors)); + } + } + + private void checkWorkInfos(UUID workIds) { + ListenableFuture> future = remoteWorkManager.getWorkInfos(WorkQuery.fromIds(workIds)); + Futures.addCallback(future, new com.google.common.util.concurrent.FutureCallback>() { + @Override + public void onSuccess(List workInfos) { + Log.d(TAG, "onSuccess: WorkInfos: " + workInfos.size()); + for (WorkInfo workInfo : workInfos) { + Log.d(TAG, "onSuccess: WorkInfo: " + workInfo.getId() + " State: " + workInfo.getState()); + update(workInfo); + } + } + + @Override + public void onFailure(@NonNull Throwable throwable) { + Log.e(TAG, " executeWork: Error getting work info: " + throwable.getMessage()); + } + }, executor); + } + + private void isAllWorkDone() { + for (WorkInfo info : workInfors.values()) { + WorkInfo.State state = info.getState(); + isDone = (state != WorkInfo.State.RUNNING) && (state != WorkInfo.State.ENQUEUED); + } + } + + @Override + public void run() { + for (int i = 0; i < workIdGroups.size(); i++) { + checkWorkInfos(workIdGroups.get(i)); + } + + executor.execute(this::isAllWorkDone); + + if (isDone || workIdGroups.isEmpty()) { + Log.d(TAG, "run: All work done"); + handler.removeCallbacks(this); + } else { + handler.postDelayed(this, 1000); + } + } + + public void setListener(CustomEventListener listener) { + this.listener = listener; + } + + public void start() { + handler.postDelayed(this, 200); + } + +} diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 7942d427..372026da 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -278,6 +278,7 @@ About Notification settings Unique Device Name + iPerf3 \ No newline at end of file From aee5182ef2395d0c0dc481f8e304a15ff56e9d75 Mon Sep 17 00:00:00 2001 From: hajoha Date: Sun, 9 Feb 2025 15:05:40 +0100 Subject: [PATCH 16/43] working --- app/proguard-rules.pro | 4 +- .../Worker/InfluxDB2xUploadWorker.java | 6 +-- .../Inputs/Inputs.java | 44 ++++++++++++++++--- .../Inputs/Iperf3Input.java | 13 ++++-- .../Inputs/PingInput.java | 7 +-- .../Iperf3/Worker/Iperf3ExecutorWorker.java | 7 ++- .../Worker/Iperf3ToLineProtocolWorker.java | 35 ++++++++++++--- .../MQTT/MQTTService.java | 4 +- .../Parameter/Iperf3Parameter.java | 39 +++++----------- .../Parameter/Parameter.java | 33 +++++++++++++- .../Parameter/PingParameter.java | 13 +----- .../Ping/PingInformations/PacketLossLine.java | 7 ++- .../Ping/Worker/PingToLineProtocolWorker.java | 32 +++++++------- .../Ping/Worker/PingWorker.java | 12 ++--- gradle.properties | 2 +- 15 files changed, 168 insertions(+), 90 deletions(-) diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro index a23a8beb..09374eb0 100644 --- a/app/proguard-rules.pro +++ b/app/proguard-rules.pro @@ -32,4 +32,6 @@ } -keepclassmembernames class io.netty.** { *; } --keepclassmembers class org.jctools.** { *; } \ No newline at end of file +-keepclassmembers class org.jctools.** { *; } + + diff --git a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/InfluxDB2x/Worker/InfluxDB2xUploadWorker.java b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/InfluxDB2x/Worker/InfluxDB2xUploadWorker.java index 46d38767..55115321 100644 --- a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/InfluxDB2x/Worker/InfluxDB2xUploadWorker.java +++ b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/InfluxDB2x/Worker/InfluxDB2xUploadWorker.java @@ -65,17 +65,17 @@ public Result doWork() { } BufferedReader br; try { - br = new BufferedReader(new FileReader("")); + br = new BufferedReader(new FileReader(input.getParameter().getLineProtocolFile())); } catch (FileNotFoundException | NullPointerException e) { Log.d(TAG,e.toString()); return Result.failure(output); } List points = br.lines().collect(Collectors.toList()); try { - // Log.d(TAG, String.format("doWork: uploading %s", input.getLineProtocolFile())); + Log.d(TAG, String.format("doWork: uploading %s", input.getParameter().getLineProtocolFile())); influx.writeRecords(points); } catch (IOException e) { - // Log.d(TAG, String.format("doWork: upload of %s failed!", input.getLineProtocolFile())); + Log.d(TAG, String.format("doWork: upload of %s failed!", input.getParameter().getLineProtocolFile())); return Result.failure(output); } diff --git a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Inputs/Inputs.java b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Inputs/Inputs.java index 77abfe0a..fd9caea9 100644 --- a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Inputs/Inputs.java +++ b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Inputs/Inputs.java @@ -10,7 +10,9 @@ import java.sql.Timestamp; -public abstract class Inputs implements Parcelable { +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Parameter.Parameter; + +public class Inputs implements Parcelable { public static final String INPUT = "input"; @@ -28,9 +30,20 @@ public abstract class Inputs implements Parcelable { private String campaignUUID; private String sequenceUUID; private String measurementUUID; + private Parameter parameter; + public static final Creator CREATOR = new Creator() { + @Override + public Inputs createFromParcel(Parcel in) { + return new Inputs(in); + } + @Override + public Inputs[] newArray(int size) { + return new Inputs[size]; + } + }; public String getTestUUID() { return testUUID; @@ -66,14 +79,20 @@ protected Inputs(Parcel in) { sequenceUUID = in.readString(); measurementUUID = in.readString(); testUUID = in.readString(); + parameter = in.readParcelable(Parameter.class.getClassLoader()); } - public Inputs(String campaignUUID, String sequenceUUID, String measurementUUID, String testUUID) { + public Inputs(String campaignUUID, String sequenceUUID, String measurementUUID, String testUUID, Parameter parameter) { this.timestamp = new Timestamp(System.currentTimeMillis()); this.campaignUUID = campaignUUID; this.sequenceUUID = sequenceUUID; this.measurementUUID = measurementUUID; this.testUUID = testUUID; + this.parameter = parameter; + } + + public Parameter getParameter() { + return parameter; } @Override @@ -88,10 +107,23 @@ public void writeToParcel(@NonNull Parcel dest, int flags) { dest.writeString(sequenceUUID); dest.writeString(measurementUUID); dest.writeString(testUUID); + dest.writeParcelable(parameter, flags); + } + + public Data.Builder getInputAsDataBuilder(int i, String packageName) { + return null; + } + + public OneTimeWorkRequest getWorkRequestExecutor(int i, String packageName) { + return null; + } + + public OneTimeWorkRequest getWorkRequestLineProtocol(int i, String packageName) { + return null; + } + + public OneTimeWorkRequest getWorkRequestUpload(int i, String packageName) { + return null; } - public abstract Data.Builder getInputAsDataBuilder(int i, String packageName); - public abstract OneTimeWorkRequest getWorkRequestExecutor(int i, String packageName); - public abstract OneTimeWorkRequest getWorkRequestLineProtocol(int i, String packageName); - public abstract OneTimeWorkRequest getWorkRequestUpload(int i, String packageName); } diff --git a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Inputs/Iperf3Input.java b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Inputs/Iperf3Input.java index de49735e..03074eeb 100644 --- a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Inputs/Iperf3Input.java +++ b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Inputs/Iperf3Input.java @@ -64,7 +64,7 @@ public Iperf3Input(Iperf3Parameter iperf3Parameter, String sequenceUUID, String measurementUUID, String campaignUUID) { - super(testUUID, sequenceUUID, measurementUUID, campaignUUID); + super(testUUID, sequenceUUID, measurementUUID, campaignUUID, iperf3Parameter); this.iperf3Parameter = iperf3Parameter; } @@ -101,6 +101,13 @@ public Data.Builder getInputAsDataBuilder(int i, String packageName) { return data; } + public Data.Builder getInputAsDataBuilder(int i) { + Data.Builder data = new Data.Builder(); + data.putInt(NOTIFICATIONUMBER, i); + data.putString(Inputs.INPUT, new GsonBuilder().create().toJson(this, Iperf3Input.class)); + return data; + } + @Override public OneTimeWorkRequest getWorkRequestExecutor(int i, String packageName) { return new OneTimeWorkRequest.Builder(Iperf3ExecutorWorker.class) @@ -122,7 +129,7 @@ public OneTimeWorkRequest getWorkRequestLineProtocol(int i, String packageName) .addTag(super.getCampaignUUID()) .addTag(Iperf3ToLineProtocolWorker.TAG) .addTag(iperf3Parameter.getiPerf3UUID()) - .setInputData(getInputAsDataBuilder(i, packageName).build()) + .setInputData(getInputAsDataBuilder(i).build()) .build(); } @@ -135,7 +142,7 @@ public OneTimeWorkRequest getWorkRequestUpload(int i, String packageName) { .addTag(super.getCampaignUUID()) .addTag(Iperf3UploadWorker.TAG) .addTag(iperf3Parameter.getiPerf3UUID()) - .setInputData(getInputAsDataBuilder(i, packageName).build()) + .setInputData(getInputAsDataBuilder(i).build()) .build(); } } \ No newline at end of file diff --git a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Inputs/PingInput.java b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Inputs/PingInput.java index 526a4eac..cb37252e 100644 --- a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Inputs/PingInput.java +++ b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Inputs/PingInput.java @@ -10,6 +10,7 @@ import de.fraunhofer.fokus.OpenMobileNetworkToolkit.InfluxDB2x.Worker.InfluxDB2xUploadWorker; import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Iperf3.Worker.Iperf3ToLineProtocolWorker; import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Parameter.PingParameter; +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Ping.Worker.PingToLineProtocolWorker; import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Ping.Worker.PingWorker; @@ -25,7 +26,7 @@ public PingInput(PingParameter pingParameter, String sequenceUUID, String measurementUUID, String campaignUUID) { - super(testUUID, sequenceUUID, measurementUUID, campaignUUID); + super(testUUID, sequenceUUID, measurementUUID, campaignUUID, pingParameter); this.pingParameter = pingParameter; } @@ -68,12 +69,12 @@ public PingInput[] newArray(int size) { @Override public OneTimeWorkRequest getWorkRequestLineProtocol(int i, String packageName) { // TODO FIX - return new OneTimeWorkRequest.Builder(Iperf3ToLineProtocolWorker.class) + return new OneTimeWorkRequest.Builder(PingToLineProtocolWorker.class) .addTag(super.getTestUUID()) .addTag(super.getMeasurementUUID()) .addTag(super.getSequenceUUID()) .addTag(super.getCampaignUUID()) - .addTag("Ping") // TODO FIX + .addTag(PingToLineProtocolWorker.TAG) // TODO FIX .setInputData(getInputAsDataBuilder(i, packageName).build()) .build(); } diff --git a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Worker/Iperf3ExecutorWorker.java b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Worker/Iperf3ExecutorWorker.java index a71f692c..74d98009 100644 --- a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Worker/Iperf3ExecutorWorker.java +++ b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Worker/Iperf3ExecutorWorker.java @@ -32,6 +32,7 @@ import com.google.common.util.concurrent.ListenableFuture; import com.google.gson.Gson; +import java.io.File; import java.util.concurrent.ExecutionException; import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Inputs.Iperf3Input; @@ -68,7 +69,11 @@ public Iperf3ExecutorWorker(@NonNull Context context, @NonNull WorkerParameters public ListenableFuture startRemoteWork() { return CallbackToFutureAdapter.getFuture(completer -> { - + File f = new File(iperf3Input.getIperf3Parameter().getLogfile()); + if(f.exists() && !f.isDirectory()) { + //weird hack otherwise the worker gets enqueued two times + return completer.set(Result.success(new Data.Builder().putString("testUUID", iperf3Input.getTestUUID()).build())); + } Log.i(TAG, "Starting "+TAG); setForegroundAsync(createForegroundInfo(iperf3Input.getIperf3Parameter().getHost()+":"+iperf3Input.getIperf3Parameter().getPort())); diff --git a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Worker/Iperf3ToLineProtocolWorker.java b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Worker/Iperf3ToLineProtocolWorker.java index d135cf79..2ea1e42e 100644 --- a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Worker/Iperf3ToLineProtocolWorker.java +++ b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Worker/Iperf3ToLineProtocolWorker.java @@ -8,13 +8,19 @@ package de.fraunhofer.fokus.OpenMobileNetworkToolkit.Iperf3.Worker; +import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_SPECIAL_USE; + +import android.app.Notification; import android.content.Context; +import android.graphics.Color; import android.os.Build; import android.util.Log; import android.widget.Toast; import androidx.annotation.NonNull; +import androidx.core.app.NotificationCompat; import androidx.work.Data; +import androidx.work.ForegroundInfo; import androidx.work.Worker; import androidx.work.WorkerParameters; @@ -25,6 +31,7 @@ import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; +import java.util.ArrayList; import java.util.LinkedList; import de.fraunhofer.fokus.OpenMobileNetworkToolkit.DataProvider.DeviceInformation; @@ -38,32 +45,46 @@ import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Iperf3.JSON.Interval.Streams.TCP.TCP_UL_STREAM; import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Iperf3.JSON.Interval.Streams.UDP.UDP_DL_STREAM; import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Preferences.SharedPreferencesGrouper; +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.R; public class Iperf3ToLineProtocolWorker extends Worker { public static final String TAG = "Iperf3ToLineProtocolWorker"; InfluxdbConnection influx; + private final int FOREGROUND_SERVICE_TYPE = FOREGROUND_SERVICE_TYPE_SPECIAL_USE; private SharedPreferencesGrouper spg; + private Notification notification; + private NotificationCompat.Builder notificationBuilder; private final DeviceInformation di = GlobalVars.getInstance().get_dp().getDeviceInformation(); + private int notificationID; private Iperf3Input iperf3Input; public Iperf3ToLineProtocolWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) { super(context, workerParams); Gson gson = new Gson(); String iperf3InputString = getInputData().getString(Iperf3Input.INPUT); iperf3Input = gson.fromJson(iperf3InputString, Iperf3Input.class); + notificationBuilder = new NotificationCompat.Builder(getApplicationContext(), "OMNT_notification_channel"); + notificationID = 200+getInputData().getInt(Iperf3Input.NOTIFICATIONUMBER, 0); spg = SharedPreferencesGrouper.getInstance(getApplicationContext()); + setForegroundAsync(createForegroundInfo("Processing iPerf3 data")); } - - private void setup(){ - influx = InfluxdbConnections.getRicInstance(getApplicationContext()); + private ForegroundInfo createForegroundInfo(String progress) { + notification = notificationBuilder + .setContentTitle("iPerf32LineProtocol") + .setContentText(progress) + .setOngoing(true) + .setOnlyAlertOnce(true) + .setColor(Color.WHITE) + .setSmallIcon(R.mipmap.ic_launcher_foreground) + .setForegroundServiceBehavior(Notification.FOREGROUND_SERVICE_DEFAULT) + .build(); + return new ForegroundInfo(notificationID, notification, FOREGROUND_SERVICE_TYPE); } - @NonNull @Override public Result doWork() { - setup(); Data output = new Data.Builder().putBoolean("iperf3_upload", false).build(); Iperf3Parser iperf3Parser = new Iperf3Parser(iperf3Input.getIperf3Parameter().getLogfile()); @@ -79,7 +100,8 @@ public Result doWork() { } LinkedList points = new LinkedList(); - for (Interval interval: iperf3Parser.getIntervals().getIntervalArrayList()) { + ArrayList intervals = iperf3Parser.getIntervals().getIntervalArrayList(); + for (Interval interval: intervals) { long tmpTimestamp = timestamp + (long) (interval.getSum().getEnd() * 1000); int intervalIdx = iperf3Parser.getIntervals().getIntervalArrayList().indexOf(interval); for (Stream stream: interval.getStreams().getStreamArrayList()){ @@ -151,6 +173,7 @@ public Result doWork() { point.time(tmpTimestamp, WritePrecision.MS); points.add(point); + setForegroundAsync(createForegroundInfo("Processing iPerf3 data: "+intervalIdx+"/"+intervals.size())); } } diff --git a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/MQTT/MQTTService.java b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/MQTT/MQTTService.java index fecf98d5..aa8d0e39 100644 --- a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/MQTT/MQTTService.java +++ b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/MQTT/MQTTService.java @@ -467,9 +467,9 @@ private void enqueueWorkRequests(RemoteWorkManager remoteWorkManager, Log.d(TAG, "enqueueWorkRequests: Enqueueing work Executor requests "+executorRequests.size()); Log.d(TAG, "enqueueWorkRequests: Enqueueing work LineProtocol requests "+lineProtocolRequests.size()); Log.d(TAG, "enqueueWorkRequests: Enqueueing work Upload requests "+uploadRequests.size()); - remoteWorkManager.beginUniqueWork("foobar", ExistingWorkPolicy.REPLACE, executorRequests) + remoteWorkManager.beginWith(executorRequests) .then(lineProtocolRequests) - // .then(uploadRequests) + .then(uploadRequests) .enqueue(); CustomEventListener listener = new CustomEventListener() { diff --git a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Parameter/Iperf3Parameter.java b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Parameter/Iperf3Parameter.java index a9485e32..11b38c31 100644 --- a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Parameter/Iperf3Parameter.java +++ b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Parameter/Iperf3Parameter.java @@ -15,13 +15,13 @@ import java.nio.file.Paths; import java.util.ArrayList; -public class Iperf3Parameter implements Parcelable { +public class Iperf3Parameter extends Parameter { public static final String rootPath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS).getAbsolutePath(); public static final String rawDirPath = rootPath+"/omnt/iperf3/raw/"; public static final String lineProtocolDirPath = rootPath+"/omnt/iperf3/lineprotocol/"; public static final String HOST = "host"; public static final String PORT = "port"; - public static final String BANDWIDTH = "bandwidth"; + public static final String BITRATE = "bitrate"; public static final String INTERVAL = "interval"; public static final String BYTES = "bytes"; public static final String STREAMS = "streams"; @@ -83,10 +83,10 @@ public class Iperf3Parameter implements Parcelable { public static final String IPERF3UUID = "iperf3UUID"; private static final String TAG = "Iperf3Parameter"; - private String lineProtocolFile; + protected Iperf3Parameter(Parcel in) { - lineProtocolFile = in.readString(); + super(in); host = in.readString(); iPerf3UUID = in.readString(); duration = in.readInt(); @@ -105,7 +105,6 @@ protected Iperf3Parameter(Parcel in) { json = tmpJson == 0 ? null : tmpJson == 1; byte tmpJsonStream = in.readByte(); jsonStream = tmpJsonStream == 0 ? null : tmpJsonStream == 1; - logfile = in.readString(); byte tmpForceflush = in.readByte(); forceflush = tmpForceflush == 0 ? null : tmpForceflush == 1; timestamps = in.readString(); @@ -306,6 +305,7 @@ public Iperf3Parameter(String ip, Boolean dontFragment, String username, String rsaPublicKeyPath) { + super(rawDirPath+iPerf3UUID+".txt", lineProtocolDirPath+iPerf3UUID+".txt"); this.host = ip; this.iPerf3UUID = iPerf3UUID; this.duration = duration; @@ -324,7 +324,6 @@ public Iperf3Parameter(String ip, this.verbose = verbose; this.json = json; this.jsonStream = jsonStream; - this.logfile = logfile; this.forceflush = forceflush; this.timestamps = timestamps; this.rcvTimeout = rcvTimeout; @@ -375,9 +374,9 @@ public Iperf3Parameter(String ip, } public Iperf3Parameter(JSONObject jsonObject, String testUUID) { + super(rawDirPath+testUUID+".txt", lineProtocolDirPath+testUUID+".txt"); + this.testUUID = testUUID; - this.logfile = rawDirPath+testUUID+".json"; - this.lineProtocolFile = lineProtocolDirPath+testUUID+".txt"; this.jsonStream = true; try { @@ -396,7 +395,7 @@ public Iperf3Parameter(JSONObject jsonObject, String testUUID) { Log.d(TAG, "port is not set. Defaulting to iPerf3 default Port."); } try { - this.bitrate = jsonObject.getString(BANDWIDTH); + this.bitrate = jsonObject.getString(BITRATE); } catch (JSONException e) { Log.d(TAG, "bitrate is not set. Defaulting to iPerf3 default bitrate."); } @@ -734,7 +733,6 @@ public int describeContents() { @Override public void writeToParcel(@NonNull Parcel dest, int flags) { - dest.writeString(lineProtocolFile); dest.writeString(host); dest.writeString(iPerf3UUID); dest.writeInt(duration); @@ -752,7 +750,6 @@ public void writeToParcel(@NonNull Parcel dest, int flags) { dest.writeBoolean(verbose); dest.writeBoolean(json); dest.writeBoolean(jsonStream); - dest.writeString(logfile); dest.writeBoolean(forceflush); dest.writeString(timestamps); dest.writeInt(rcvTimeout); @@ -806,9 +803,6 @@ public String getHost() { return host; } - public String getLineProtocolFile() { - return lineProtocolFile; - } // --- Enums --- public enum Iperf3Mode { @@ -849,7 +843,7 @@ public String toPrettyPrint() { // For UDP mode: if not set, default bitrate is "1M". private String bitrate; // For TCP mode: if not set, default buffer length is 131072 (128 KB). - private int length = 131072; + private int length; // Mode selection fields. // The mode field indicates whether the test is run in CLIENT or SERVER mode. @@ -868,7 +862,6 @@ public String toPrettyPrint() { private Boolean verbose; private Boolean json; private Boolean jsonStream = true; - private String logfile; private Boolean forceflush; private String timestamps; private Integer rcvTimeout; @@ -918,10 +911,6 @@ public String toPrettyPrint() { private String username; private String rsaPublicKeyPath; - // --- Constructors --- - public Iperf3Parameter() { - // Defaults are set via field initialization. - } // --- Getters and Setters --- @@ -1074,13 +1063,6 @@ public void setJsonStream(Boolean jsonStream) { this.jsonStream = jsonStream; } - public String getLogfile() { - return logfile; - } - - public void setLogfile(String logfile) { - this.logfile = logfile; - } public Boolean getForceflush() { return forceflush; @@ -1479,7 +1461,6 @@ public String toString() { ", verbose=" + verbose + ", json=" + json + ", jsonStream=" + jsonStream + - ", logfile='" + logfile + '\'' + ", forceflush=" + forceflush + ", timestamps='" + timestamps + '\'' + ", rcvTimeout=" + rcvTimeout + @@ -1788,7 +1769,7 @@ public String[] getInputAsCommand() { // Always add these extra fixed options. command.add("--json-stream"); command.add("--logfile"); - command.add(logfile); + command.add(super.getLogfile()); diff --git a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Parameter/Parameter.java b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Parameter/Parameter.java index 3b267bf3..4c126c79 100644 --- a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Parameter/Parameter.java +++ b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Parameter/Parameter.java @@ -4,18 +4,47 @@ import android.os.Parcel; import android.os.Parcelable; -public abstract class Parameter implements Parcelable { +public class Parameter implements Parcelable { public static final String rootPath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS).getAbsolutePath(); + private String lineProtocolFile; + private String logfile; protected Parameter(Parcel in) { + lineProtocolFile = in.readString(); + logfile = in.readString(); } + public Parameter(String logfile, String lineProtocolFile) { + this.logfile = logfile; + this.lineProtocolFile = lineProtocolFile; + } + + public static final Creator CREATOR = new Creator() { + @Override + public Parameter createFromParcel(Parcel in) { + return new Parameter(in); + } + + @Override + public Parameter[] newArray(int size) { + return new Parameter[size]; + } + }; + + public String getLineProtocolFile() { + return lineProtocolFile; + } + + public String getLogfile() { + return logfile; + } public int describeContents() { return 0; } public void writeToParcel(android.os.Parcel dest, int flags) { - + dest.writeString(lineProtocolFile); + dest.writeString(logfile); } } diff --git a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Parameter/PingParameter.java b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Parameter/PingParameter.java index 47119eab..74b2137c 100644 --- a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Parameter/PingParameter.java +++ b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Parameter/PingParameter.java @@ -16,6 +16,7 @@ public class PingParameter extends Parameter { public static final String rawDirPath = rootPath+"/omnt/ping/raw/"; + public static final String lineProtocolDirPath = rootPath+"/omnt/ping/lineprotocol/"; private static final String TAG = "PingParameter"; @@ -46,9 +47,6 @@ public long getIntervalMillis() { return intervalMillis; } - public String getLogfile() { - return logfile; - } public Network getNetwork() { return network; @@ -61,8 +59,6 @@ public Network getNetwork() { private long intervalMillis; private Network network; private int deadline; - private String lineProtocolFile; - private String logfile; private String testUUID; @@ -95,7 +91,7 @@ public String[] getInputAsCommand() { return command.toArray(new String[0]); } public PingParameter(JSONObject parameter, String testUUID) { - super(null); + super(rawDirPath + testUUID + ".txt", lineProtocolDirPath + testUUID + ".txt"); this.testUUID = testUUID; try { destination = parameter.getString(DESTINATION); @@ -142,8 +138,6 @@ public PingParameter(JSONObject parameter, String testUUID) { Log.d(TAG, "Could not create directories."); } - logfile = rawDirPath + this.testUUID + ".txt"; - lineProtocolFile = lineProtocolDirPath + this.testUUID + ".txt"; } @@ -185,7 +179,4 @@ public void writeToParcel(@NonNull Parcel dest, int flags) { dest.writeParcelable(network, flags); } - public String getLineProtocolFile() { - return lineProtocolFile; - } } diff --git a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Ping/PingInformations/PacketLossLine.java b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Ping/PingInformations/PacketLossLine.java index 33bbc2d7..9f31057d 100644 --- a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Ping/PingInformations/PacketLossLine.java +++ b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Ping/PingInformations/PacketLossLine.java @@ -1,5 +1,6 @@ package de.fraunhofer.fokus.OpenMobileNetworkToolkit.Ping.PingInformations; +import com.influxdb.client.domain.WritePrecision; import com.influxdb.client.write.Point; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -15,12 +16,14 @@ public PacketLossLine(String line) { this.setLineType(LINEType.PACKET_LOSS); } public void parse(){ + super.parse(); matcher = pattern.matcher(this.getLine()); if(matcher.find()){ packetsTransmitted = Long.parseLong(matcher.group(1)); packetsReceived = Long.parseLong(matcher.group(2)); packetLoss = Double.parseDouble(matcher.group(3).replace("%", "")); } + } public long getPacketsReceived() { return packetsReceived; @@ -36,6 +39,8 @@ public Point getPoint(){ return super.getPoint() .addField("packets_transmitted", this.getPacketsTransmitted()) .addField("packets_received", this.getPacketsReceived()) - .addField("packet_loss", this.getPacketLoss()); + .addField("packet_loss", this.getPacketLoss()) + .time(System.currentTimeMillis(), WritePrecision.MS); + //ping does not provide timestamp for packet loss line } } diff --git a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Ping/Worker/PingToLineProtocolWorker.java b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Ping/Worker/PingToLineProtocolWorker.java index a1fda46c..a6f4047e 100644 --- a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Ping/Worker/PingToLineProtocolWorker.java +++ b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Ping/Worker/PingToLineProtocolWorker.java @@ -58,7 +58,7 @@ import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Preferences.SharedPreferencesGrouper; public class PingToLineProtocolWorker extends Worker { - public static final String TAG = "Iperf3ToLineProtocolWorker"; + public static final String TAG = "PingToLineProtocolWorker"; InfluxdbConnection influx; private SharedPreferencesGrouper spg; @@ -90,7 +90,6 @@ private LINEType getLineType(String line){ @NonNull @Override public Result doWork() { -; Data.Builder output = new Data.Builder().putBoolean("pingUpload", false); File myObj = new File(pingInput.getPingParameter().getLogfile()); Scanner scanner = null; @@ -99,7 +98,7 @@ public Result doWork() { } catch (FileNotFoundException e) { return Result.failure(output.putString("error", "File not found").build()); } - ArrayList points = new ArrayList<>(); + ArrayList pingInformations = new ArrayList<>(); while (scanner.hasNextLine()) { String line = scanner.nextLine(); PingInformation pi = null; @@ -120,30 +119,31 @@ public Result doWork() { } if (pi == null) continue; pi.parse(); - points.add(pi); + pingInformations.add(pi); } scanner.close(); - try { - Files.createDirectories(Paths.get(PingParameter.lineProtocolDirPath)); - } catch (IOException e) { - Log.d(TAG, "doWork: "+e.toString()); - } try { Files.createFile(Paths.get(pingInput.getPingParameter().getLineProtocolFile())); } catch (IOException e) { Log.d(TAG, "doWork: "+e.toString()); return Result.failure(output.putString("error", "File not created").build()); } - BufferedWriter writer = null; + FileOutputStream pingStream = null; try { - writer = new BufferedWriter(new FileWriter(pingInput.getPingParameter().getLineProtocolFile())); - } catch (IOException e) { - Log.d(TAG, "doWork: "+e.toString()); - return Result.failure(output.putString("error", "File not created").build()); + pingStream = new FileOutputStream(pingInput.getPingParameter().getLineProtocolFile(), true); + } catch (FileNotFoundException e) { + Log.d(TAG, "doWork: " + e.toString()); + Log.e(TAG, "doWork: Could not create FileOutputStream"); } - for (PingInformation pi : points) { + + for (PingInformation pi : pingInformations) { try { - writer.write(pi.getPoint().toLineProtocol() + "\n"); + Point point = pi.getPoint(); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + point.addTags(GlobalVars.getInstance().get_dp().getTagsMap()); + } + pingStream.write((point.toLineProtocol() + "\n").getBytes()); + } catch (IOException e) { Log.d(TAG, "doWork: "+e.toString()); return Result.failure(output.putString("error", "File not written").build()); diff --git a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Ping/Worker/PingWorker.java b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Ping/Worker/PingWorker.java index 7a631319..1f9e30de 100644 --- a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Ping/Worker/PingWorker.java +++ b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Ping/Worker/PingWorker.java @@ -28,9 +28,12 @@ import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; +import java.io.FileOutputStream; import java.io.FileWriter; import java.io.IOException; import java.io.InputStreamReader; +import java.nio.file.Files; +import java.nio.file.Paths; import java.util.Objects; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -114,14 +117,13 @@ public Result doWork() { ProcessBuilder processBuilder = new ProcessBuilder(command); Process process = processBuilder.start(); - BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream())); - BufferedWriter writer = new BufferedWriter(new FileWriter(getApplicationContext().getFilesDir()+pingInput.getTestUUID()+".txt")); + FileOutputStream pingStream = new FileOutputStream(pingInput.getPingParameter().getLogfile(), true); String line; while ((line = reader.readLine()) != null) { - System.out.println(line); - writer.write(line + "\n"); + Log.d(TAG, "doWork: "+line); + pingStream.write((line + "\n").getBytes()); Matcher matcher = pattern.matcher(line); if (matcher.find()) { try { @@ -141,7 +143,7 @@ public void run() { setProgressAsync(output.putString(LINE, line).build()); } - writer.close(); + pingStream.close(); reader.close(); result = process.waitFor(); diff --git a/gradle.properties b/gradle.properties index f49b2417..2c57a4ed 100644 --- a/gradle.properties +++ b/gradle.properties @@ -26,4 +26,4 @@ android.useAndroidX=true # Automatically convert third-party libraries to use AndroidX android.enableJetifier=false android.nonTransitiveRClass=false -android.nonFinalResIds=false \ No newline at end of file +android.nonFinalResIds=false From 5b86e5cba28b3072e115d06e5ff4ca211ec972fa Mon Sep 17 00:00:00 2001 From: hajoha Date: Sun, 9 Feb 2025 19:43:18 +0100 Subject: [PATCH 17/43] fix monitoring of status --- .../MQTT/MQTTService.java | 23 ++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/MQTT/MQTTService.java b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/MQTT/MQTTService.java index aa8d0e39..abd94f59 100644 --- a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/MQTT/MQTTService.java +++ b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/MQTT/MQTTService.java @@ -28,6 +28,8 @@ import com.hivemq.client.mqtt.mqtt5.message.connect.connack.Mqtt5ConnAck; import com.hivemq.client.mqtt.mqtt5.message.publish.Mqtt5PayloadFormatIndicator; +import org.json.JSONObject; + import java.net.InetSocketAddress; import java.nio.charset.StandardCharsets; import java.util.ArrayList; @@ -105,11 +107,21 @@ public void createClient(){ .addConnectedListener(context -> { Log.i(TAG, "createClient: Connected to MQTT server"); createNotification(); + publishToTopic(String.format("device/%s/status", deviceName), "1", false); }) .addDisconnectedListener(context -> { Log.i(TAG, "createClient: Disconnected from MQTT server"); createNotification(); }) + .willPublish() + .topic(String.format("device/%s/status", deviceName)) + .qos(MqttQos.EXACTLY_ONCE) + .payload("0".getBytes()) + .retain(true) + .payloadFormatIndicator(Mqtt5PayloadFormatIndicator.UTF_8) + .contentType("text/plain") + .noMessageExpiry() + .applyWillPublish() .buildAsync(); Log.i(TAG, "createClient: Client created with address: " + addressString); @@ -159,11 +171,12 @@ public void onCreate() { } - public void publishToTopic(String topic, String message){ + public void publishToTopic(String topic, String message, boolean retain){ client.publishWith() .topic(topic) .qos(MqttQos.EXACTLY_ONCE) .payload(message.getBytes()) + .retain(retain) .send(); } @@ -179,12 +192,13 @@ public void disconnectClient(){ } public void connectClient(){ + CompletableFuture connAck = client.connectWith() - .keepAlive(10) + .keepAlive(1) .willPublish() .topic(String.format("device/%s/status", deviceName)) .qos(MqttQos.EXACTLY_ONCE) - .payload("offline".getBytes()) + .payload("0".getBytes()) .retain(true) .payloadFormatIndicator(Mqtt5PayloadFormatIndicator.UTF_8) .contentType("text/plain") @@ -197,6 +211,7 @@ public void connectClient(){ Log.e(TAG, "connectClient: Error connecting to MQTT server: " + throwable.getMessage()); } else { Log.i(TAG, "connectClient: Connected to MQTT server"); + publishToTopic(String.format("device/%s/status", deviceName), "1", true); } }); } @@ -427,6 +442,7 @@ public int onStartCommand(Intent intent, int flags, int startId) { setupSharedPreferences(); createClient(); connectClient(); + subscribeToAllTopics(); return START_STICKY; @@ -480,6 +496,7 @@ public void onChange(HashMap workInfos) { Log.d(TAG, "onChange: WorkInfo: " + info.getTags() + " State: " + state); Data data = info.getOutputData(); Log.i(TAG, "onChange: "+data.toString()); + publishToTopic("device/"+deviceName+"/campaign/status", state.toString(), false); } } From 7d3d615ec6b2e0485ebf707a6c195a502c417d7e Mon Sep 17 00:00:00 2001 From: hajoha Date: Thu, 6 Mar 2025 16:04:16 +0100 Subject: [PATCH 18/43] update --- .../CellInformations/NRInformation.java | 2 +- .../Iperf3/Iperf3LibLoader.java | 3 +- .../Iperf3/Worker/Iperf3ExecutorWorker.java | 71 ++++++++++++++++--- .../Worker/Iperf3ToLineProtocolWorker.java | 2 +- .../MQTT/MQTTService.java | 3 +- .../Parameter/Iperf3Parameter.java | 42 +++-------- 6 files changed, 78 insertions(+), 45 deletions(-) diff --git a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/DataProvider/CellInformations/NRInformation.java b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/DataProvider/CellInformations/NRInformation.java index 110706f7..97825ba1 100644 --- a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/DataProvider/CellInformations/NRInformation.java +++ b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/DataProvider/CellInformations/NRInformation.java @@ -297,7 +297,7 @@ public StringBuilder getStringBuilder(){ if(!this.getSsrsrpString().equals(max)) stringBuilder.append(" SSRSRP: ").append(this.getSsrsrpString()).append(" dBm").append("\n"); - if(!this.getSssinrString().equals(max)) stringBuilder.append(" SSRSRP: ").append(this.getSssinrString()).append(" dBm").append("\n"); + if(!this.getSssinrString().equals(max)) stringBuilder.append(" SSSINR: ").append(this.getSssinrString()).append(" dBm").append("\n"); if(!this.getFirstCqiString().equals(max)) stringBuilder.append(" CQI: ").append(this.getFirstCqiString()).append("\n"); diff --git a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Iperf3LibLoader.java b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Iperf3LibLoader.java index 96075272..7b6b5de6 100644 --- a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Iperf3LibLoader.java +++ b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Iperf3LibLoader.java @@ -24,7 +24,8 @@ public class Iperf3LibLoader { "iperf3.12", "iperf3.15", "iperf3.16", - "iperf3.17.1" + "iperf3.17.1", + "iperf3.18" ); public static synchronized void load() { diff --git a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Worker/Iperf3ExecutorWorker.java b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Worker/Iperf3ExecutorWorker.java index 74d98009..4da97bbf 100644 --- a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Worker/Iperf3ExecutorWorker.java +++ b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Worker/Iperf3ExecutorWorker.java @@ -15,6 +15,9 @@ import android.app.PendingIntent; import android.content.Context; import android.graphics.Color; +import android.os.FileObserver; +import android.os.Handler; +import android.os.Looper; import android.util.Log; import androidx.annotation.NonNull; @@ -32,8 +35,18 @@ import com.google.common.util.concurrent.ListenableFuture; import com.google.gson.Gson; +import java.io.BufferedReader; import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.IOException; +import java.nio.Buffer; import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Inputs.Iperf3Input; import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Inputs.PingInput; @@ -50,9 +63,10 @@ public class Iperf3ExecutorWorker extends RemoteListenableWorker { private final String channelId = "OMNT_notification_channel"; private final int FOREGROUND_SERVICE_TYPE = FOREGROUND_SERVICE_TYPE_SPECIAL_USE; private Iperf3Input iperf3Input; - private int notificationID; + private int notificationID = 2000; private NotificationCompat.Builder notificationBuilder; private Notification notification; + private FileObserver observer; public Iperf3ExecutorWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) { super(context, workerParams); Gson gson = new Gson(); @@ -64,28 +78,67 @@ public Iperf3ExecutorWorker(@NonNull Context context, @NonNull WorkerParameters notificationBuilder = new NotificationCompat.Builder(context, channelId); } + + @NonNull @Override public ListenableFuture startRemoteWork() { return CallbackToFutureAdapter.getFuture(completer -> { - File f = new File(iperf3Input.getIperf3Parameter().getLogfile()); - if(f.exists() && !f.isDirectory()) { + File logFile = new File(iperf3Input.getIperf3Parameter().getLogfile()); + if(logFile.exists() && !logFile.isDirectory()) { //weird hack otherwise the worker gets enqueued two times return completer.set(Result.success(new Data.Builder().putString("testUUID", iperf3Input.getTestUUID()).build())); } + try { + logFile.createNewFile(); + } catch (Exception e) { + Log.d(TAG, "startRemoteWork: "+e); + return completer.set(Result.failure()); + } Log.i(TAG, "Starting "+TAG); setForegroundAsync(createForegroundInfo(iperf3Input.getIperf3Parameter().getHost()+":"+iperf3Input.getIperf3Parameter().getPort())); - int result = - iperf3Wrapper(iperf3Input.getIperf3Parameter().getInputAsCommand(), getApplicationContext().getApplicationInfo().nativeLibraryDir); - Log.d(TAG, "doWork: " + result); - + final int[] result = {-1}; + Handler handler = new Handler(Looper.myLooper()); + + Log.d(TAG, "startRemoteWork: running thread"); + + + ScheduledExecutorService executorService = Executors.newScheduledThreadPool(2); + Runnable iperf3 = new Runnable(){ + @Override + public void run() { + result[0] = iperf3Wrapper(iperf3Input.getIperf3Parameter().getInputAsCommand(), getApplicationContext().getApplicationInfo().nativeLibraryDir); + Log.d(TAG, "doWork: " + result[0]); + } + }; + + Runnable read = new Runnable() { + @Override + public void run() { + try (BufferedReader reader = new BufferedReader(new FileReader(logFile))) { + String line; + while ((line = reader.readLine()) != null) { + Log.d(TAG, "Log entry: " + line); + setForegroundAsync(createForegroundInfo(line)); + } + Log.d(TAG, "run: finished reading"); + } catch (IOException e) { + e.printStackTrace(); + } + } + }; + Log.d(TAG, "startRemoteWork: running thread"); + executorService.execute(iperf3); + executorService.schedule(read, (long) (iperf3Input.getIperf3Parameter().getInterval()+0.5), TimeUnit.SECONDS); + executorService.awaitTermination(iperf3Input.getIperf3Parameter().getTime()+4, TimeUnit.SECONDS); + Log.d(TAG, "doWork: " + result[0]); Data.Builder output = new Data.Builder() - .putInt("result", result) + .putInt("result", result[0]) .putString("testUUID", iperf3Input.getTestUUID()); - if (result == 0) { + if (result[0] == 0) { return completer.set(Result.success(output.build())); } return completer.set(Result.failure(output diff --git a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Worker/Iperf3ToLineProtocolWorker.java b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Worker/Iperf3ToLineProtocolWorker.java index 2ea1e42e..5a2392e1 100644 --- a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Worker/Iperf3ToLineProtocolWorker.java +++ b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Worker/Iperf3ToLineProtocolWorker.java @@ -134,7 +134,7 @@ public Result doWork() { .getConnecting_to() .getPort())); point.addTag("bandwidth", iperf3Input.getIperf3Parameter().getBitrate()); - point.addTag("duration", String.valueOf(iperf3Input.getIperf3Parameter().getDuration())); + point.addTag("duration", String.valueOf(iperf3Input.getIperf3Parameter().getTime())); point.addTag("bytesToTransmit", String.valueOf(iperf3Input.getIperf3Parameter().getBytes())); point.addTag("streams", String.valueOf(interval.getStreams().size())); point.addTag("streamIdx", String.valueOf(interval.getStreams().getStreamArrayList().indexOf(stream))); diff --git a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/MQTT/MQTTService.java b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/MQTT/MQTTService.java index abd94f59..d5b69387 100644 --- a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/MQTT/MQTTService.java +++ b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/MQTT/MQTTService.java @@ -496,7 +496,8 @@ public void onChange(HashMap workInfos) { Log.d(TAG, "onChange: WorkInfo: " + info.getTags() + " State: " + state); Data data = info.getOutputData(); Log.i(TAG, "onChange: "+data.toString()); - publishToTopic("device/"+deviceName+"/campaign/status", state.toString(), false); + + publishToTopic("device/"+deviceName+"/campaign/status", String.valueOf(state.ordinal()), false); } } diff --git a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Parameter/Iperf3Parameter.java b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Parameter/Iperf3Parameter.java index 11b38c31..1b3c7953 100644 --- a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Parameter/Iperf3Parameter.java +++ b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Parameter/Iperf3Parameter.java @@ -89,7 +89,6 @@ protected Iperf3Parameter(Parcel in) { super(in); host = in.readString(); iPerf3UUID = in.readString(); - duration = in.readInt(); port = in.readInt(); interval = in.readDouble(); bitrate = in.readString(); @@ -241,7 +240,6 @@ public Iperf3Parameter[] newArray(int size) { public Iperf3Parameter(String ip, String iPerf3UUID, - int duration, Iperf3Protocol protocol, int port, double interval, @@ -308,7 +306,6 @@ public Iperf3Parameter(String ip, super(rawDirPath+iPerf3UUID+".txt", lineProtocolDirPath+iPerf3UUID+".txt"); this.host = ip; this.iPerf3UUID = iPerf3UUID; - this.duration = duration; this.protocol = protocol; this.port = port; this.interval = interval; @@ -401,8 +398,9 @@ public Iperf3Parameter(JSONObject jsonObject, String testUUID) { } try { this.time = jsonObject.getInt(TIME); + Log.d(TAG, "Iperf3Parameter: time: "+time); } catch (JSONException e) { - Log.d(TAG, "duration is not set. Defaulting to iPerf3 default duration."); + Log.d(TAG, "time is not set. Defaulting to iPerf3 default time."); } try { @@ -421,7 +419,9 @@ public Iperf3Parameter(JSONObject jsonObject, String testUUID) { Log.d(TAG, "nstreams not set."); } try { - this.direction = Iperf3Direction.valueOf(jsonObject.getString(DIRECTION).toUpperCase().trim()); + String direction = jsonObject.getString(DIRECTION); + Log.d(TAG, "Iperf3Parameter: direction: "+direction); + this.direction = Iperf3Direction.valueOf(direction.toUpperCase().trim()); } catch (JSONException e) { this.direction = Iperf3Direction.UP; Log.d(TAG, "direction not set."); @@ -557,11 +557,6 @@ public Iperf3Parameter(JSONObject jsonObject, String testUUID) { } catch (JSONException e) { Log.d(TAG, "parallel not set."); } - try{ - this.cport = jsonObject.getInt(STREAMS); - } catch (JSONException e) { - Log.d(TAG, "cport not set."); - } try{ this.blockcount = jsonObject.getString(BLOCKCOUNT); } catch (JSONException e) { @@ -572,11 +567,6 @@ public Iperf3Parameter(JSONObject jsonObject, String testUUID) { } catch (JSONException e) { Log.d(TAG, "bytes not set."); } - try{ - this.time = jsonObject.getInt(TIME); - } catch (JSONException e) { - Log.d(TAG, "time not set."); - } try{ this.fqRate = jsonObject.getString(FQRATE); } catch (JSONException e) { @@ -699,14 +689,13 @@ public Iperf3Parameter(JSONObject jsonObject, String testUUID) { Log.d(TAG, "file not set."); } try { - this.direction = Iperf3Direction.valueOf(jsonObject.getString(DIRECTION)); - } catch (JSONException e) { - Log.d(TAG, "direction not set."); - } - try { - this.mode = Iperf3Mode.valueOf(jsonObject.getString(MODE)); + String mode = jsonObject.getString(MODE); + Log.d(TAG, "Iperf3Parameter: mode: "+mode); + this.mode = Iperf3Mode.valueOf(mode.toUpperCase().trim()); } catch (JSONException e) { Log.d(TAG, "mode not set."); + Log.i(TAG, "Iperf3Parameter: No mode set. Defaulting to Client."); + this.mode = Iperf3Mode.CLIENT; } try{ this.bind = jsonObject.getString(BIND); @@ -735,7 +724,6 @@ public int describeContents() { public void writeToParcel(@NonNull Parcel dest, int flags) { dest.writeString(host); dest.writeString(iPerf3UUID); - dest.writeInt(duration); dest.writeInt(port); dest.writeDouble(interval); dest.writeString(bitrate); @@ -836,7 +824,6 @@ public String toPrettyPrint() { private String iPerf3UUID; private String testUUID; // Optional fields with defaults based on iperf3. - private int duration = 10; // Default duration: 10 seconds. private Iperf3Protocol protocol = Iperf3Protocol.TCP; // Default protocol: TCP. private int port = 5201; // Default port: 5201. private double interval = 1.0; // Default interval: 1.0 second. @@ -922,14 +909,6 @@ public void setiPerf3UUID(String iPerf3UUID) { this.iPerf3UUID = iPerf3UUID; } - public int getDuration() { - return duration; - } - - public void setDuration(int duration) { - this.duration = duration; - } - public Iperf3Protocol getProtocol() { return protocol; } @@ -1445,7 +1424,6 @@ public void setRsaPublicKeyPath(String rsaPublicKeyPath) { public String toString() { return "Params{" + "iPerf3UUID='" + iPerf3UUID + '\'' + - ", duration=" + duration + ", protocol=" + protocol + ", port=" + port + ", interval=" + interval + From 1697b8f14fd3ccd8a6e16cbeeedf98f607bab46a Mon Sep 17 00:00:00 2001 From: hajoha Date: Sat, 15 Mar 2025 00:06:41 +0100 Subject: [PATCH 19/43] update --- .../Inputs/Iperf3Input.java | 12 +- .../Database/RunResult/Iperf3RunResult.java | 6 +- .../Iperf3/Fragments/Iperf3Fragment.java | 330 +++++++ .../Fragments/Output/Iperf3ListFragment.java | 150 +++ .../Fragments/Output/Iperf3LogFragment.java | 435 +++++++++ .../Iperf3/Iperf3Fragment.java | 863 ------------------ .../Iperf3/Iperf3InputConverter.java | 9 +- .../Iperf3/Iperf3ListFragment.java | 42 +- .../Iperf3/Iperf3LogFragment.java | 68 +- .../Iperf3/Iperf3RecyclerViewAdapter.java | 5 +- .../Iperf3/Worker/Iperf3ExecutorWorker.java | 10 +- .../Worker/Iperf3ToLineProtocolWorker.java | 20 +- .../Iperf3/Worker/Iperf3UploadWorker.java | 6 +- .../LoggingService.java | 4 +- .../Parameter/Iperf3Parameter.java | 12 +- .../main/res/layout/fragment_iperf3_input.xml | 543 ++++++----- app/src/main/res/navigation/nav_graph.xml | 2 +- app/src/main/res/values/styles.xml | 59 +- 18 files changed, 1323 insertions(+), 1253 deletions(-) create mode 100644 app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Fragments/Iperf3Fragment.java create mode 100644 app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Fragments/Output/Iperf3ListFragment.java create mode 100644 app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Fragments/Output/Iperf3LogFragment.java delete mode 100644 app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Iperf3Fragment.java diff --git a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Inputs/Iperf3Input.java b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Inputs/Iperf3Input.java index 03074eeb..a97fd0e3 100644 --- a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Inputs/Iperf3Input.java +++ b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Inputs/Iperf3Input.java @@ -14,6 +14,8 @@ import com.google.gson.GsonBuilder; +import java.util.UUID; + import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Parameter.Iperf3Parameter; import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Iperf3.Service.Iperf3ServiceWorkerFour; import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Iperf3.Service.Iperf3ServiceWorkerThree; @@ -58,18 +60,20 @@ public void writeToParcel(@NonNull Parcel parcel, int i) { super.writeToParcel(parcel, i); parcel.writeParcelable(iperf3Parameter, i); } - + public Iperf3Input(Iperf3Parameter iperf3Parameter) { + this(iperf3Parameter, UUID.randomUUID().toString(), "", "", ""); + } public Iperf3Input(Iperf3Parameter iperf3Parameter, String testUUID, String sequenceUUID, String measurementUUID, String campaignUUID) { super(testUUID, sequenceUUID, measurementUUID, campaignUUID, iperf3Parameter); - this.iperf3Parameter = iperf3Parameter; } - public Iperf3Parameter getIperf3Parameter() { - return iperf3Parameter; + @Override + public Iperf3Parameter getParameter() { + return (Iperf3Parameter) super.getParameter(); } public Data.Builder getInputAsDataBuilder(int i, String packageName) { diff --git a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Database/RunResult/Iperf3RunResult.java b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Database/RunResult/Iperf3RunResult.java index aa30329d..5fbbee94 100644 --- a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Database/RunResult/Iperf3RunResult.java +++ b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Database/RunResult/Iperf3RunResult.java @@ -16,7 +16,7 @@ import java.sql.Timestamp; -import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Iperf3.Iperf3Fragment; +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Inputs.Iperf3Input; import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Iperf3.Iperf3InputConverter; @Entity(tableName = "iperf3_result_database") @@ -36,9 +36,9 @@ public class Iperf3RunResult { @ColumnInfo(name = "input") @TypeConverters({Iperf3InputConverter.class}) - public Iperf3Fragment.Iperf3Input input; + public Iperf3Input input; - public Iperf3RunResult(String uid, int result, boolean upload, Iperf3Fragment.Iperf3Input input, + public Iperf3RunResult(String uid, int result, boolean upload, Iperf3Input input, Timestamp timestamp) { this.uid = uid; this.result = result; diff --git a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Fragments/Iperf3Fragment.java b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Fragments/Iperf3Fragment.java new file mode 100644 index 00000000..1e5e3707 --- /dev/null +++ b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Fragments/Iperf3Fragment.java @@ -0,0 +1,330 @@ +package de.fraunhofer.fokus.OpenMobileNetworkToolkit.Iperf3.Fragments; + +import android.content.Context; +import android.graphics.Color; +import android.os.Bundle; +import android.text.Editable; +import android.text.TextWatcher; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.FrameLayout; +import android.widget.LinearLayout; +import android.widget.ProgressBar; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.fragment.app.Fragment; + +import com.google.android.material.bottomsheet.BottomSheetBehavior; +import com.google.android.material.bottomsheet.BottomSheetDialog; +import com.google.android.material.button.MaterialButton; +import com.google.android.material.button.MaterialButtonToggleGroup; +import com.google.android.material.textfield.TextInputEditText; + + +import java.util.UUID; +import java.util.function.Consumer; + +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Inputs.Iperf3Input; + +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Parameter.Iperf3Parameter; +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Preferences.SPType; +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Preferences.SharedPreferencesGrouper; +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.R; + +public class Iperf3Fragment extends Fragment { + + private static final String ARG_POSITION = "position"; + private ProgressBar progressBar; + private Iperf3Input iperf3Input; + private Context ct; + private MaterialButton sendBtn; + private View view; + //todo start iperf3 as a service + private TextInputEditText ip; + private TextInputEditText port; + private TextInputEditText bitrate; + private TextInputEditText duration; + private TextInputEditText interval; + private TextInputEditText bytes; + private TextInputEditText streams; + private TextInputEditText cport; + + + private MaterialButtonToggleGroup mode; + private MaterialButtonToggleGroup protocol; + private MaterialButtonToggleGroup direction; + + private MaterialButton modeClient; + private MaterialButton modeServer; + private MaterialButton protocolTCP; + private MaterialButton protocolUDP; + private MaterialButton directionUp; + private MaterialButton directionDown; + private MaterialButton directonBidir; + + private SharedPreferencesGrouper spg; + + private FrameLayout frameLayout; + private String TAG = "Iperf3CardFragment"; + + @Override + public void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + this.ct = requireContext(); + } + + /** + * Create a text watcher + * @param consumer + * @param name + * @return + */ + private TextWatcher createTextWatcher(Consumer consumer, String name) { + return new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) { + + } + + @Override + public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) { + consumer.accept(charSequence.toString()); + spg.getSharedPreference(SPType.iperf3_sp).edit().putString(name, charSequence.toString()).apply(); + } + + @Override + public void afterTextChanged(Editable editable) { + } + }; + } + + /** + * Set up the text watchers + */ + private void setupTextWatchers() { + ip.addTextChangedListener(createTextWatcher(s -> iperf3Input.getParameter().setHost(s), Iperf3Parameter.HOST)); + port.addTextChangedListener(createTextWatcher(s -> iperf3Input.getParameter().setPort(Integer.parseInt("0"+s)), Iperf3Parameter.PORT)); + bitrate.addTextChangedListener(createTextWatcher(s -> iperf3Input.getParameter().setBandwidth(s), Iperf3Parameter.BITRATE)); + duration.addTextChangedListener(createTextWatcher(s -> iperf3Input.getParameter().setTime(Integer.parseInt("0"+s)), Iperf3Parameter.TIME)); + interval.addTextChangedListener(createTextWatcher(s -> iperf3Input.getParameter().setInterval(Integer.parseInt("0"+s)), Iperf3Parameter.INTERVAL)); + bytes.addTextChangedListener(createTextWatcher(s -> iperf3Input.getParameter().setBytes(s), Iperf3Parameter.BYTES)); + streams.addTextChangedListener(createTextWatcher(s -> iperf3Input.getParameter().setNstreams(Integer.parseInt("0"+s)), Iperf3Parameter.STREAMS)); + cport.addTextChangedListener(createTextWatcher(s -> iperf3Input.getParameter().setCport(Integer.parseInt("0"+s) ), Iperf3Parameter.CPORT)); + } + + /** + * Set the text from the shared preferences + * @param editText + * @param key + */ + private void setTextFromSharedPreferences(TextInputEditText editText, String key) { + if (spg.getSharedPreference(SPType.iperf3_sp).contains(key)) { + editText.setText(spg.getSharedPreference(SPType.iperf3_sp).getString(key, "")); + } + } + + /** + * Set the texts from the shared preferences + */ + private void setTextsFromSharedPreferences(){ + setTextFromSharedPreferences(ip, Iperf3Parameter.HOST); + setTextFromSharedPreferences(port, Iperf3Parameter.PORT); + setTextFromSharedPreferences(bitrate, Iperf3Parameter.BITRATE); + setTextFromSharedPreferences(duration, Iperf3Parameter.TIME); + setTextFromSharedPreferences(interval, Iperf3Parameter.INTERVAL); + setTextFromSharedPreferences(bytes, Iperf3Parameter.BYTES); + setTextFromSharedPreferences(streams, Iperf3Parameter.STREAMS); + setTextFromSharedPreferences(cport, Iperf3Parameter.CPORT); + } + @Override + public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + view = inflater.inflate(R.layout.fragment_iperf3_input, container, false); + // Initialize the TextView + progressBar = view.findViewById(R.id.iperf3_progress); + progressBar.setVisibility(View.INVISIBLE); + String iperf3UUID = UUID.randomUUID().toString(); + Iperf3Parameter iperf3Parameter = new Iperf3Parameter(iperf3UUID); + iperf3Input = new Iperf3Input(iperf3Parameter); + sendBtn = view.findViewById(R.id.iperf3_send); + spg = SharedPreferencesGrouper.getInstance(ct); + sendBtn.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + //TODO + } + }); + BottomSheetBehavior bottomSheetBehavior = BottomSheetBehavior.from(view.findViewById(R.id.standard_bottom_sheet)); + bottomSheetBehavior.setPeekHeight(20); + bottomSheetBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED); + bottomSheetBehavior.setHideable(false); + ip = view.findViewById(R.id.iperf3_ip); + port = view.findViewById(R.id.iperf3_port); + bitrate = view.findViewById(R.id.iperf3_bandwidth); + duration = view.findViewById(R.id.iperf3_duration); + interval = view.findViewById(R.id.iperf3_interval); + bytes = view.findViewById(R.id.iperf3_bytes); + streams = view.findViewById(R.id.iperf3_streams); + cport = view.findViewById(R.id.iperf3_cport); + + + mode = view.findViewById(R.id.iperf3_mode_toggle_group); + protocol = view.findViewById(R.id.iperf3_protocol_toggle_group); + direction = view.findViewById(R.id.iperf3_direction_toggle_group); + + modeClient = view.findViewById(R.id.iperf3_client_button); + modeServer = view.findViewById(R.id.iperf3_server_button); + + protocolTCP = view.findViewById(R.id.iperf3_tcp_button); + protocolUDP = view.findViewById(R.id.iperf3_udp_button); + + directionDown = view.findViewById(R.id.iperf3_download_button); + directionUp = view.findViewById(R.id.iperf3_upload_button); + directonBidir = view.findViewById(R.id.iperf3_bidir_button); + + setupTextWatchers(); + setTextsFromSharedPreferences(); + + try { + switch (Iperf3Parameter.Iperf3Mode.valueOf(spg.getSharedPreference(SPType.iperf3_sp).getString(Iperf3Parameter.MODE, String.valueOf(Iperf3Parameter.Iperf3Mode.UNDEFINED)))){ + case CLIENT: + updateModeState(modeClient, modeServer, Iperf3Parameter.Iperf3Mode.CLIENT); + break; + case SERVER: + updateModeState(modeServer, modeClient, Iperf3Parameter.Iperf3Mode.SERVER); + break; + case UNDEFINED: + default: + modeClient.setBackgroundColor(Color.TRANSPARENT); + modeServer.setBackgroundColor(Color.TRANSPARENT); + spg.getSharedPreference(SPType.iperf3_sp).edit().putString(Iperf3Parameter.MODE, Iperf3Parameter.Iperf3Mode.UNDEFINED.toString()).apply(); + break; + } + } catch (IllegalArgumentException e) { + Log.e(TAG, "onCreateView: ", e); + } + try { + switch (Iperf3Parameter.Iperf3Protocol.valueOf(spg.getSharedPreference(SPType.iperf3_sp).getString(Iperf3Parameter.PROTOCOL, Iperf3Parameter.Iperf3Protocol.UNDEFINED.toString()))){ + case TCP: + updateProtocolState(protocolTCP, protocolUDP, Iperf3Parameter.Iperf3Protocol.TCP); + break; + case UDP: + updateProtocolState(protocolUDP, protocolTCP, Iperf3Parameter.Iperf3Protocol.UDP); + break; + case UNDEFINED: + default: + protocolTCP.setBackgroundColor(Color.TRANSPARENT); + protocolUDP.setBackgroundColor(Color.TRANSPARENT); + spg.getSharedPreference(SPType.iperf3_sp).edit().putString(Iperf3Parameter.PROTOCOL, Iperf3Parameter.Iperf3Protocol.UNDEFINED.toString()).apply(); + break; + } + } catch (IllegalArgumentException e) { + Log.e(TAG, "onCreateView: ", e); + } + try { + switch (Iperf3Parameter.Iperf3Direction.valueOf(spg.getSharedPreference(SPType.iperf3_sp).getString(Iperf3Parameter.DIRECTION, Iperf3Parameter.Iperf3Direction.UNDEFINED.toString()))) { + case UP: + updateDirectionState(directionUp, directionDown, directonBidir, Iperf3Parameter.Iperf3Direction.UP); + break; + case DOWN: + updateDirectionState(directionDown, directionUp, directonBidir, Iperf3Parameter.Iperf3Direction.DOWN); + break; + case BIDIR: + updateDirectionState(directonBidir, directionUp, directionDown, Iperf3Parameter.Iperf3Direction.BIDIR); + break; + case UNDEFINED: + default: + directionUp.setBackgroundColor(Color.TRANSPARENT); + directionDown.setBackgroundColor(Color.TRANSPARENT); + directonBidir.setBackgroundColor(Color.TRANSPARENT); + break; + } + } catch (IllegalArgumentException e) { + Log.e(TAG, "onCreateView: ", e); + } + + mode.addOnButtonCheckedListener(new MaterialButtonToggleGroup.OnButtonCheckedListener() { + @Override + public void onButtonChecked(MaterialButtonToggleGroup group, int checkedId, boolean isChecked) { + if (isChecked) { + switch (checkedId) { + case R.id.iperf3_client_button: + updateModeState(modeClient, modeServer, Iperf3Parameter.Iperf3Mode.CLIENT); + break; + case R.id.iperf3_server_button: + updateModeState(modeServer, modeClient, Iperf3Parameter.Iperf3Mode.SERVER); + break; + } + } + } + }); + protocol.addOnButtonCheckedListener(new MaterialButtonToggleGroup.OnButtonCheckedListener() { + @Override + public void onButtonChecked(MaterialButtonToggleGroup group, int checkedId, boolean isChecked) { + if (isChecked) { + switch (checkedId) { + case R.id.iperf3_tcp_button: + updateProtocolState(protocolTCP, protocolUDP, Iperf3Parameter.Iperf3Protocol.TCP); + break; + case R.id.iperf3_udp_button: + updateProtocolState(protocolUDP, protocolTCP, Iperf3Parameter.Iperf3Protocol.UDP); + break; + } + } + } + }); + direction.addOnButtonCheckedListener(new MaterialButtonToggleGroup.OnButtonCheckedListener() { + @Override + public void onButtonChecked(MaterialButtonToggleGroup group, int checkedId, boolean isChecked) { + if (isChecked) { + switch (checkedId) { + case R.id.iperf3_upload_button: + updateDirectionState(directionUp, directionDown, directonBidir, Iperf3Parameter.Iperf3Direction.UP); + break; + case R.id.iperf3_download_button: + updateDirectionState(directionDown, directionUp, directonBidir, Iperf3Parameter.Iperf3Direction.DOWN); + break; + case R.id.iperf3_bidir_button: + updateDirectionState(directonBidir, directionUp, directionDown, Iperf3Parameter.Iperf3Direction.BIDIR); + break; + } + } + } + }); + + return view; + } + + @Override + public void onResume() { + super.onResume(); + view.requestLayout(); + } + + + + private void updateModeState(MaterialButton activeButton, MaterialButton inactiveButton, Iperf3Parameter.Iperf3Mode protocol) { + activeButton.setBackgroundColor(getResources().getColor(R.color.purple_500, null)); + inactiveButton.setBackgroundColor(Color.TRANSPARENT); + iperf3Input.getParameter().setMode(protocol); + spg.getSharedPreference(SPType.iperf3_sp).edit().putString(Iperf3Parameter.MODE, protocol.toString()).apply(); + } + + private void updateProtocolState(MaterialButton activeButton, MaterialButton inactiveButton, Iperf3Parameter.Iperf3Protocol protocol) { + activeButton.setBackgroundColor(getResources().getColor(R.color.purple_500, null)); + inactiveButton.setBackgroundColor(Color.TRANSPARENT); + iperf3Input.getParameter().setProtocol(protocol); + spg.getSharedPreference(SPType.iperf3_sp).edit().putString(Iperf3Parameter.PROTOCOL, protocol.toString()).apply(); + } + + private void updateDirectionState(MaterialButton activeButton, MaterialButton inactiveButton1, MaterialButton inactiveButton2, Iperf3Parameter.Iperf3Direction direction) { + activeButton.setBackgroundColor(getResources().getColor(R.color.purple_500, null)); + inactiveButton1.setBackgroundColor(Color.TRANSPARENT); + inactiveButton2.setBackgroundColor(Color.TRANSPARENT); + iperf3Input.getParameter().setDirection(direction); + spg.getSharedPreference(SPType.iperf3_sp).edit().putString(Iperf3Parameter.DIRECTION, direction.toString()).apply(); + } +} \ No newline at end of file diff --git a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Fragments/Output/Iperf3ListFragment.java b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Fragments/Output/Iperf3ListFragment.java new file mode 100644 index 00000000..ea7a05b8 --- /dev/null +++ b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Fragments/Output/Iperf3ListFragment.java @@ -0,0 +1,150 @@ +/* + * SPDX-FileCopyrightText: 2023 Peter Hasse + * SPDX-FileCopyrightText: 2023 Johann Hackler + * SPDX-FileCopyrightText: 2023 Fraunhofer FOKUS + * + * SPDX-License-Identifier: BSD-3-Clause-Clear + */ + +//from https://codeburst.io/android-swipe-menu-with-recyclerview-8f28a235ff28 + +package de.fraunhofer.fokus.OpenMobileNetworkToolkit.Iperf3.Fragments.Output; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.graphics.Canvas; +import android.os.Bundle; +import android.os.Handler; +import android.os.Looper; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import androidx.annotation.Nullable; +import androidx.fragment.app.Fragment; +import androidx.lifecycle.Observer; +import androidx.recyclerview.widget.ItemTouchHelper; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; +import androidx.work.Data; +import androidx.work.OneTimeWorkRequest; +import androidx.work.WorkManager; + +import com.google.android.material.floatingactionbutton.FloatingActionButton; + +import java.util.ArrayList; +import java.util.List; + +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Iperf3.Database.RunResult.Iperf3ResultsDataBase; +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Iperf3.Database.RunResult.Iperf3RunResult; +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Iperf3.Database.RunResult.Iperf3RunResultDao; +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Iperf3.Iperf3RecyclerViewAdapter; +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Iperf3.Worker.Iperf3ToLineProtocolWorker; +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.R; +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.SwipeController; +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.SwipeControllerActions; + + +public class Iperf3ListFragment extends Fragment { + private final String TAG = "Iperf3ListFragment"; + private SwipeController swipeController = null; + private RecyclerView recyclerView; + private Iperf3RecyclerViewAdapter adapter; + private LinearLayoutManager linearLayoutManager; + private FloatingActionButton uploadBtn; + private Iperf3ResultsDataBase db; + private Context context; + + + + public static Iperf3ListFragment newInstance() { + Iperf3ListFragment fragment = new Iperf3ListFragment(); + Bundle args = new Bundle(); + fragment.setArguments(args); + return fragment; + } + + + + private void observeDatabaseChanges() { + if(db == null) return; + db.iperf3RunResultDao().getAll().observe(getViewLifecycleOwner(), new Observer>() { + @Override + public void onChanged(@Nullable List runResults) { + updateIperf3ListAdapter(); + } + }); + } + + + @Override + public void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + } + + @SuppressLint("NotifyDataSetChanged") + public void updateIperf3ListAdapter() { + if (this.adapter != null) this.adapter.notifyDataSetChanged(); + } + + @SuppressLint("ClickableViewAccessibility") + public View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState) { + View v = inflater.inflate(R.layout.fragment_iperf3_list, parent, false); + this.context = requireContext(); + + recyclerView = v.findViewById(R.id.runners_list); + uploadBtn = v.findViewById(R.id.iperf3_upload_button); + db = Iperf3ResultsDataBase.getDatabase(this.context); + + observeDatabaseChanges(); + + + linearLayoutManager = + new LinearLayoutManager(getContext(), LinearLayoutManager.VERTICAL, false); + this.adapter = new Iperf3RecyclerViewAdapter(getActivity(), + new ArrayList(db.iperf3RunResultDao().getIDs()), + uploadBtn); + + + recyclerView.setLayoutManager(linearLayoutManager); + recyclerView.setAdapter(adapter); + + swipeController = new SwipeController(new SwipeControllerActions() { + @SuppressLint("NotifyDataSetChanged") + @Override + public void onRightClicked(int position) { + //TODO + } + + @Override + public void onLeftClicked(int position) { + Bundle input = new Bundle(); + input.putString("uid", new ArrayList(db.iperf3RunResultDao().getIDs()).get(position)); + getActivity().getSupportFragmentManager().setFragmentResult("input", input); + getActivity().getSupportFragmentManager().popBackStack(); + } + }); + + ItemTouchHelper itemTouchhelper = new ItemTouchHelper(swipeController); + itemTouchhelper.attachToRecyclerView(recyclerView); + + recyclerView.addItemDecoration(new RecyclerView.ItemDecoration() { + @Override + public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) { + swipeController.onDraw(c); + } + }); + + + return v; + } + + @Override + public void onViewCreated(View v, Bundle savedInstanceState) { + super.onViewCreated(v, savedInstanceState); + } + + public void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + } +} \ No newline at end of file diff --git a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Fragments/Output/Iperf3LogFragment.java b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Fragments/Output/Iperf3LogFragment.java new file mode 100644 index 00000000..e84e348f --- /dev/null +++ b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Fragments/Output/Iperf3LogFragment.java @@ -0,0 +1,435 @@ +/* + * SPDX-FileCopyrightText: 2023 Peter Hasse + * SPDX-FileCopyrightText: 2023 Johann Hackler + * SPDX-FileCopyrightText: 2023 Fraunhofer FOKUS + * + * SPDX-License-Identifier: BSD-3-Clause-Clear + */ + +package de.fraunhofer.fokus.OpenMobileNetworkToolkit.Iperf3.Fragments.Output; + +import android.content.Context; +import android.graphics.drawable.Drawable; +import android.os.Bundle; +import android.os.Handler; +import android.os.Looper; +import android.util.Log; +import android.util.TypedValue; +import android.view.Gravity; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.FrameLayout; +import android.widget.ImageButton; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.ScrollView; +import android.widget.TextView; + +import androidx.cardview.widget.CardView; +import androidx.core.widget.TextViewCompat; +import androidx.fragment.app.Fragment; + +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Inputs.Iperf3Input; +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Iperf3.Database.RunResult.Iperf3ResultsDataBase; +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Iperf3.Database.RunResult.Iperf3RunResult; +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Iperf3.Iperf3Utils; +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Metric.METRIC_TYPE; +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Metric.Metric; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileReader; + +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Parameter.Iperf3Parameter; +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.R; + +public class Iperf3LogFragment extends Fragment { + + private static final String TAG = "Iperf3LogFragment"; + private View v; + private Iperf3ResultsDataBase db; + private Handler logHandler; + private File file; + private String uid; + private Drawable runIcon; + private Drawable uploadIcon; + private ImageView runIconView; + private ImageView uploadIconView; + + private TextView iperf3OutputViewer; + private LinearLayout parameterLL; + private Context ct; + private LinearLayout metricLL; + private Metric defaultReverseThroughput; + private Metric defaultThroughput; + private Metric defaultRTT; + private Metric defaultJITTER; + private Metric PACKET_LOSS; + private Context context; + + public Iperf3LogFragment() { + } + + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + this.db = Iperf3ResultsDataBase.getDatabase(getActivity().getApplicationContext()); + this.context = requireContext(); + } + + private void setFields(Iperf3RunResult iperf3RunResult) { + + } + private final Runnable logUpdate = new Runnable() { + @Override + public void run() { + Iperf3RunResult iperf3RunResult = db.iperf3RunResultDao().getRunResult(uid); + Log.d(TAG, "run: " + iperf3RunResult.result); + runIcon = Iperf3Utils.getDrawableResult(requireContext(), iperf3RunResult.result); + runIconView.setImageDrawable(runIcon); + uploadIcon = Iperf3Utils.getDrawableUpload(ct, iperf3RunResult.result, iperf3RunResult.uploaded); + uploadIconView.setImageDrawable(uploadIcon); + + BufferedReader br = null; + StringBuilder text = new StringBuilder(); + + try { + br = new BufferedReader(new FileReader(file)); + } catch (FileNotFoundException e) { + iperf3OutputViewer.setText(String.format("no iPerf3 file found, with following path: \n %s", iperf3RunResult.input.getParameter().getLogfile())); + logHandler.removeCallbacks(logUpdate); + return; + } + String line; + /* + Iperf3Parser iperf3Parser = new Iperf3Parser(iperf3RunResult.input.getRawFile()); + iperf3Parser.addPropertyChangeListener(new PropertyChangeListener() { + + private void parseSum(Sum sum, Metric throughput){ + SUM_TYPE sumType = sum.getSumType(); + throughput.update(sum.getBits_per_second()); + switch (sumType){ + case UDP_DL: + defaultJITTER.update(((UDP_DL_SUM)sum).getJitter_ms()); + PACKET_LOSS.update(((UDP_DL_SUM) sum).getLost_percent()); + case TCP_DL: + if(throughput.getDirectionName().getText().equals("Throughput")){ + throughput.getDirectionName().setText("Downlink Mbit/s"); + } + break; + case UDP_UL: + case TCP_UL: + if(throughput.getDirectionName().getText().equals("Throughput")){ + throughput.getDirectionName().setText("Uplink Mbit/s"); + } + break; + } + + } + public void propertyChange(PropertyChangeEvent evt) { + + switch (evt.getPropertyName()){ + case "interval": + Interval interval = (Interval) evt.getNewValue(); + parseSum(interval.getSum(), defaultThroughput); + if(interval.getSumBidirReverse() != null) parseSum(interval.getSumBidirReverse(), + defaultReverseThroughput); + break; + case "start": + break; + case "end": + break; + case "error": + Error error = (Error) evt.getNewValue(); + TextView errorView = new TextView(ct); + errorView.setText(error.getError()); + errorView.setTextColor(ct.getColor(R.color.crimson)); + errorView.setPadding(10, 10, 10, 10); + errorView.setTextSize(20); + metricLL.addView(errorView); + break; + } + } + }); + + iperf3Parser.parse();*/ + if (iperf3RunResult.result != -100) { + logHandler.removeCallbacks(logUpdate); + return; + } + setFields(iperf3RunResult); + logHandler.removeCallbacks(logUpdate); + logHandler.postDelayed(this, 1000); + } + }; + + private TextView createTextView(Context ct, String text, float weight) { + TextView textView = new TextView(ct); + textView.setText(text); + LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(0, ViewGroup.LayoutParams.WRAP_CONTENT); + layoutParams.weight = weight; + textView.setLayoutParams(layoutParams); + return textView; + } + + + private LinearLayout getTextView(String name, String value) { + if(value == null) return null; + if(value.equals("")) return null; + LinearLayout mainLL = new LinearLayout(context); + mainLL.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)); + mainLL.setOrientation(LinearLayout.HORIZONTAL); + + TextView parameterName = createTextView(context, name, 0.25F); + TextView parameterValue = createTextView(context, value, 0.75F); + + mainLL.addView(parameterName); + mainLL.addView(parameterValue); + return mainLL; + } + + private void addTextView(LinearLayout ll, String name, String value) { + LinearLayout mainLL = getTextView(name, value); + if(mainLL != null) ll.addView(mainLL); + } + + public LinearLayout getInputAsLinearLayoutKeyValue(Iperf3Input input) { + LinearLayout main = new LinearLayout(context); + main.setOrientation(LinearLayout.VERTICAL); + LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams( + 0, + FrameLayout.LayoutParams.WRAP_CONTENT); + layoutParams.weight = 8f; + main.setLayoutParams(layoutParams); + + addTextView(main, Iperf3Parameter.HOST, input.getParameter().getHost()); + addTextView(main, Iperf3Parameter.PORT, String.valueOf(input.getParameter().getPort())); + addTextView(main, Iperf3Parameter.PROTOCOL, input.getParameter().getProtocol().toString()); + addTextView(main, Iperf3Parameter.MODE, input.getParameter().getMode().toPrettyPrint()); + addTextView(main, Iperf3Parameter.DIRECTION, input.getParameter().getDirection().toPrettyPrint()); + addTextView(main, Iperf3Parameter.BITRATE, input.getParameter().getBitrate()); + addTextView(main, Iperf3Parameter.TIME, String.valueOf(input.getParameter().getTime())); + addTextView(main, Iperf3Parameter.IPERF3UUID, input.getParameter().getiPerf3UUID()); + addTextView(main, Iperf3Parameter.STREAMS, String.valueOf(input.getParameter().getNstreams())); + addTextView(main, Iperf3Parameter.TIMESTAMPS, input.getTimestamp().toString()); + + return main; + } + + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + v = inflater.inflate(R.layout.fragment_iperf3_log, container, false); + Iperf3RunResult iperf3RunResult = + db.iperf3RunResultDao().getRunResult(this.getArguments().getString("uid")); + ct = requireContext(); + LinearLayout mainLL = v.findViewById(R.id.iperf3_list_fragment); + mainLL.setOrientation(LinearLayout.VERTICAL); + + LinearLayout firstRow = new LinearLayout(ct); + firstRow.setOrientation(LinearLayout.HORIZONTAL); + + LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.MATCH_PARENT); + mainLL.setLayoutParams(layoutParams); + + LinearLayout.LayoutParams foo = new LinearLayout.LayoutParams( + LinearLayout.LayoutParams.MATCH_PARENT, + LinearLayout.LayoutParams.WRAP_CONTENT); + foo.setMargins(30, 10, 0, 0); + firstRow.setLayoutParams(foo); + + + runIconView = new ImageView(ct); + LinearLayout.LayoutParams runIconViewLayout = new LinearLayout.LayoutParams(0, ViewGroup.LayoutParams.WRAP_CONTENT); + runIconViewLayout.weight = 0.2F; + runIconViewLayout.height = 100; + runIconViewLayout.gravity = Gravity.RIGHT; + runIconView.setLayoutParams(runIconViewLayout); + runIcon = Iperf3Utils.getDrawableResult(ct, iperf3RunResult.result); + runIconView.setImageDrawable(runIcon); + runIconView.setTooltipText(String.format("Indicates the result of the iPerf3 run: %s", iperf3RunResult.result)); + runIconView.setLayoutParams(runIconViewLayout); + + + uploadIconView = new ImageView(ct); + uploadIconView.setTooltipText(String.format("Indicates if the iPerf3 run was uploaded to the server: %s", iperf3RunResult.uploaded)); + LinearLayout.LayoutParams uploadIconViewLayout = new LinearLayout.LayoutParams(0, ViewGroup.LayoutParams.WRAP_CONTENT); + uploadIconViewLayout.weight = 0.2F; + uploadIconViewLayout.height = 100; + uploadIconViewLayout.gravity = Gravity.RIGHT; + uploadIcon = Iperf3Utils.getDrawableUpload(ct, iperf3RunResult.result, iperf3RunResult.uploaded); + uploadIconView.setImageDrawable(uploadIcon); + uploadIconView.setLayoutParams(uploadIconViewLayout); + + + + + + LinearLayout headerWrapper = new LinearLayout(ct); + LinearLayout.LayoutParams headerWrapperLayout = new LinearLayout.LayoutParams( + LinearLayout.LayoutParams.WRAP_CONTENT, + LinearLayout.LayoutParams.WRAP_CONTENT); + headerWrapper.setLayoutParams(headerWrapperLayout); + headerWrapper.setOrientation(LinearLayout.VERTICAL); + CardView cardView = new CardView(ct); + CardView.LayoutParams cardViewLayout = new CardView.LayoutParams( + CardView.LayoutParams.MATCH_PARENT, + CardView.LayoutParams.WRAP_CONTENT); + headerWrapper.setPadding(30, 30, 30, 30); + cardView.setLayoutParams(cardViewLayout); + cardView.setRadius(10); + cardView.setCardElevation(10); + cardView.setUseCompatPadding(true); + cardView.addView(headerWrapper); + cardView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + //TODO: implement click on card, goto input fragmet + } + }); + + LinearLayout header = new LinearLayout(ct); + LinearLayout.LayoutParams headerLayout = new LinearLayout.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, 100); + header.setLayoutParams(headerLayout); + header.setOrientation(LinearLayout.HORIZONTAL); + + firstRow.addView(getInputAsLinearLayoutKeyValue(iperf3RunResult.input)); + + + TextView headerName = new TextView(ct); + headerName.setText("iPerf3 run"); + LinearLayout.LayoutParams headerNameLayout = new LinearLayout.LayoutParams(0, ViewGroup.LayoutParams.WRAP_CONTENT); + headerNameLayout.weight = 0.6F; + headerName.setLayoutParams(headerNameLayout); + header.addView(headerName); + header.addView(runIconView); + header.addView(uploadIconView); + ImageButton expandButton = new ImageButton(ct); + expandButton.setImageResource(R.drawable.baseline_expand_more_24); + firstRow.setVisibility(View.GONE); + expandButton.setOnClickListener(new View.OnClickListener() { + public void onClick(View v) { + if (firstRow.getVisibility() == View.VISIBLE) { + firstRow.setVisibility(View.GONE); + expandButton.setImageResource(R.drawable.baseline_expand_more_24); + } else { + firstRow.setVisibility(View.VISIBLE); + expandButton.setImageResource(R.drawable.baseline_expand_less_24); + } + + } + }); + LinearLayout.LayoutParams imageButtonLayout = new LinearLayout.LayoutParams(0, ViewGroup.LayoutParams.WRAP_CONTENT); + imageButtonLayout.weight = 0.2F; + expandButton.setLayoutParams(imageButtonLayout); + + header.addView(expandButton); + headerWrapper.addView(header); + headerWrapper.addView(firstRow); + + uid = iperf3RunResult.uid; + + mainLL.addView(cardView); + + LinearLayout secondRow = new LinearLayout(ct); + LinearLayout.LayoutParams secondRowLayoutParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.MATCH_PARENT); + secondRow.setOrientation(LinearLayout.HORIZONTAL); + secondRowLayoutParams.setMargins(0, 20, 0, 20); + secondRow.setLayoutParams(secondRowLayoutParams); + ScrollView scrollView = new ScrollView(ct); + iperf3OutputViewer = new TextView(ct); + iperf3OutputViewer.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)); + TextViewCompat.setAutoSizeTextTypeUniformWithConfiguration(iperf3OutputViewer, + 1, 10, 1, + TypedValue.COMPLEX_UNIT_SP); + iperf3OutputViewer.setTextIsSelectable(true); + + metricLL = new LinearLayout(ct); + metricLL.setOrientation(LinearLayout.VERTICAL); + metricLL.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)); + + + + defaultThroughput = new Metric(METRIC_TYPE.THROUGHPUT, ct); + defaultReverseThroughput = new Metric(METRIC_TYPE.THROUGHPUT, ct); + + metricLL.addView(defaultThroughput.createMainLL("Throughput")); + + + + switch (iperf3RunResult.input.getParameter().getDirection()){ + case UP: + defaultThroughput.getDirectionName().setText("Uplink Mbit/s"); + //display RTT when available - https://github.com/esnet/iperf/issues/1724 + break; + case DOWN: + defaultThroughput.getDirectionName().setText("Downlink Mbit/s"); + switch (iperf3RunResult.input.getParameter().getProtocol()){ + case TCP: + break; + case UDP: + defaultJITTER = new Metric(METRIC_TYPE.JITTER, ct); + metricLL.addView(defaultJITTER.createMainLL("Jitter ms")); + PACKET_LOSS = new Metric(METRIC_TYPE.PACKET_LOSS, ct); + metricLL.addView(PACKET_LOSS.createMainLL("Packet Loss %")); + break; + } + break; + case BIDIR: + metricLL.addView(defaultReverseThroughput.createMainLL("Throughput")); + switch (iperf3RunResult.input.getParameter().getProtocol()){ + case TCP: + defaultThroughput.getDirectionName().setText("Downlink Mbit/s"); + defaultReverseThroughput.getDirectionName().setText("Uplink Mbit/s"); + break; + case UDP: + defaultThroughput.getDirectionName().setText("Downlink Mbit/s"); + defaultReverseThroughput.getDirectionName().setText("Uplink Mbit/s"); + defaultJITTER = new Metric(METRIC_TYPE.JITTER, ct); + metricLL.addView(defaultJITTER.createMainLL("Jitter ms")); + PACKET_LOSS = new Metric(METRIC_TYPE.PACKET_LOSS, ct); + metricLL.addView(PACKET_LOSS.createMainLL("Packet Loss %")); + break; + } + + break; + } + + mainLL.addView(metricLL); + + + + + mainLL.addView(secondRow); + if(iperf3RunResult.input.getParameter().getLogfile() == null){ + iperf3OutputViewer.setText("iPerf3 file path empty!"); + return v; + } + file = new File(iperf3RunResult.input.getParameter().getLogfile()); + + + logHandler = new Handler(Looper.myLooper()); + logHandler.post(logUpdate); + return v; + } + + @Override + public void onResume() { + super.onResume(); + v.requestLayout(); + } + + public void onPause() { + super.onPause(); + if(logHandler != null) logHandler.removeCallbacks(logUpdate); + } + + +} \ No newline at end of file diff --git a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Iperf3Fragment.java b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Iperf3Fragment.java deleted file mode 100644 index 6ee2773e..00000000 --- a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Iperf3Fragment.java +++ /dev/null @@ -1,863 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2023 Peter Hasse - * SPDX-FileCopyrightText: 2023 Johann Hackler - * SPDX-FileCopyrightText: 2023 Fraunhofer FOKUS - * - * SPDX-License-Identifier: BSD-3-Clause-Clear - */ - -package de.fraunhofer.fokus.OpenMobileNetworkToolkit.Iperf3; - -import android.content.Context; -import android.content.SharedPreferences; -import android.os.Bundle; -import android.os.Environment; -import android.os.Handler; -import android.os.Looper; -import android.system.ErrnoException; -import android.system.Os; -import android.text.Editable; -import android.text.TextWatcher; -import android.util.Log; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ArrayAdapter; -import android.widget.Button; -import android.widget.CheckBox; -import android.widget.EditText; -import android.widget.LinearLayout; -import android.widget.Spinner; -import android.widget.TextView; -import android.widget.Toast; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.fragment.app.Fragment; -import androidx.fragment.app.FragmentResultListener; -import androidx.lifecycle.MutableLiveData; -import androidx.lifecycle.Observer; -import androidx.navigation.NavController; -import androidx.navigation.fragment.NavHostFragment; -import androidx.work.Data; -import androidx.work.OneTimeWorkRequest; -import androidx.work.WorkInfo; -import androidx.work.WorkManager; - -import com.google.android.material.progressindicator.LinearProgressIndicator; -import com.google.common.util.concurrent.ListenableFuture; - -import java.io.File; -import java.io.IOException; -import java.lang.reflect.Field; -import java.nio.file.Files; -import java.nio.file.Paths; -import java.sql.Timestamp; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.LinkedList; -import java.util.List; -import java.util.UUID; - -import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Iperf3.Database.RunResult.Iperf3ResultsDataBase; -import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Iperf3.Database.RunResult.Iperf3RunResult; -import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Iperf3.Database.RunResult.Iperf3RunResultDao; -import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Iperf3.Worker.Iperf3ExecutorWorker; -import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Iperf3.Worker.Iperf3ToLineProtocolWorker; -import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Iperf3.Worker.Iperf3UploadWorker; -import de.fraunhofer.fokus.OpenMobileNetworkToolkit.R; -import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Preferences.SPType; -import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Preferences.SharedPreferencesGrouper; - -public class Iperf3Fragment extends Fragment { - private static final String TAG = "iperf3InputFragment"; - private final int SHOW_PROGRESSBAR = 3000; - private final String IPERF3IP = "iperf3IP"; - private final String IPERF3PORT = "iperf3Port"; - private final String IPERF3BANDWIDTH = "iperf3Bandwidth"; - private final String IPERF3DURATION = "iperf3Duration"; - private final String IPERF3INTERVAL = "iperf3Interval"; - private final String IPERF3BYTES = "iperf3Bytes"; - private final String IPERF3STREAMS = "iperf3Streams"; - private final String IPERF3BIDIR = "iperf3BiDir"; - private final String IPERF3REVERSE = "iperf3Reverse"; - private final String IPERF3JSON = "iperf3Json"; - private final String IPERF3ONEOFF = "iperf3OneOff"; - private final String IPERF3IDXPROTOCOL = "iperf3IdxProtocol"; - private final String IPERF3IDXMODE = "iperf3IdxMode"; - private final String IPERF3CPORT = "iperf3cport"; - private CheckBox iperf3BiDir; - private CheckBox iperf3Reverse; - - private CheckBox iperf3OneOff; - private EditText iperf3EtIp; - private EditText iperf3EtPort; - private EditText iperf3EtBandwidth; - private EditText iperf3EtDuration; - private EditText iperf3EtInterval; - private EditText iperf3EtBytes; - private EditText iperf3EtStreams; - private EditText iperf3Cport; - private Button sendBtn; - private Button instancesBtn; - private Spinner protocolSpinner; - private Spinner iperf3ModeSpinner; - private Iperf3RunResultDao iperf3RunResultDao; - private LinearProgressIndicator progressIndicator; - private int[] failedColors; - private int[] runningColors; - private int[] succesColors; - private LinkedList editTexts; - private String rawIperf3file; - private String logFileDir; - private String logFileName; - private View v; - private SharedPreferencesGrouper spg; - private Iperf3Input input; - private WorkManager iperf3WM; - private Iperf3ResultsDataBase db; - private ArrayList uids; - private Context ct; - private final Runnable progressbarUpdate = new Runnable() { - @Override - public void run() { - progressIndicator.setVisibility(LinearProgressIndicator.INVISIBLE); - progressIndicator.setIndicatorColor(runningColors); - } - }; - - @Override - public void onPause() { - super.onPause(); - } - - @Override - public void onCreate(@Nullable Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - this.input = new Iperf3Input(); - this.db = Iperf3ResultsDataBase.getDatabase(getActivity().getApplicationContext()); - this.uids = new ArrayList<>(this.db.iperf3RunResultDao().getIDs()); - this.iperf3WM = WorkManager.getInstance(getActivity().getApplicationContext()); - this.logFileDir = - Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS) - .getAbsolutePath() + "/omnt/iperf3RawLogs/"; - this.iperf3RunResultDao = db.iperf3RunResultDao(); - File iperf3Path = new File(this.logFileDir); - if (!iperf3Path.exists()) { - iperf3Path.mkdir(); - } - this.ct = requireContext(); - this.spg = SharedPreferencesGrouper.getInstance(this.ct); - } - - @Override - public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { - super.onViewCreated(view, savedInstanceState); - - - NavController navController = NavHostFragment.findNavController(this); - MutableLiveData liveData = navController.getCurrentBackStackEntry() - .getSavedStateHandle() - .getLiveData("uid"); - - - - liveData.observe(getViewLifecycleOwner(), new Observer() { - @Override - public void onChanged(String s) { - Iperf3RunResult iperf3RunResult = db.iperf3RunResultDao().getRunResult(s); - - iperf3EtIp.setText(iperf3RunResult.input.iperf3IP); - iperf3EtPort.setText(iperf3RunResult.input.iperf3Port); - iperf3EtBandwidth.setText(iperf3RunResult.input.iperf3Bandwidth); - iperf3EtDuration.setText(iperf3RunResult.input.iperf3Duration); - iperf3EtInterval.setText(iperf3RunResult.input.iperf3Interval); - iperf3EtBytes.setText(iperf3RunResult.input.iperf3Bytes); - iperf3Cport.setText(iperf3RunResult.input.iperf3Cport); - - iperf3Reverse.setChecked(iperf3RunResult.input.iperf3Reverse); - iperf3BiDir.setChecked(iperf3RunResult.input.iperf3BiDir); - iperf3OneOff.setChecked(iperf3RunResult.input.iperf3OneOff); - protocolSpinner.setSelection(iperf3RunResult.input.iperf3IdxProtocol); - iperf3ModeSpinner.setSelection(iperf3RunResult.input.iperf3IdxMode); - - - } - }); - } - - - private void saveTextInputToSharedPreferences(EditText field, String name) { - field.addTextChangedListener(new TextWatcher() { - @Override - public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) { - - } - - @Override - public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) { - spg.getSharedPreference(SPType.iperf3_sp).edit().putString(name, field.getText().toString()).apply(); - } - - @Override - public void afterTextChanged(Editable editable) { - - } - }); - - } - - - - private void saveCheckboxInputToSharedPreferences(CheckBox box, String name) { - box.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - spg.getSharedPreference(SPType.iperf3_sp).edit().putBoolean(name, box.isChecked()).apply(); - } - }); - } - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState) { - v = inflater.inflate(R.layout.fragment_iperf3_input, parent, false); - iperf3EtIp = v.findViewById(R.id.iperf3_ip); - iperf3EtPort = v.findViewById(R.id.iperf3_port); - iperf3EtBandwidth = v.findViewById(R.id.iperf3_bandwidth); - iperf3EtDuration = v.findViewById(R.id.iperf3_duration); - - - - - iperf3EtInterval = v.findViewById(R.id.iperf3_interval); - iperf3EtBytes = v.findViewById(R.id.iperf3_bytes); - iperf3EtStreams = v.findViewById(R.id.iperf3_streams); - iperf3Cport = v.findViewById(R.id.iperf3_cport); - progressIndicator = v.findViewById(R.id.iperf3_progress); - - iperf3EtDuration.addTextChangedListener(new TextWatcher() { - @Override - public void beforeTextChanged(CharSequence s, int start, int count, int after) { - - } - - @Override - public void onTextChanged(CharSequence s, int start, int before, int count) { - iperf3EtBytes.setEnabled(s.length() <= 0); - } - - @Override - public void afterTextChanged(Editable s) { - - } - }); - - - iperf3EtBytes.addTextChangedListener(new TextWatcher() { - @Override - public void beforeTextChanged(CharSequence s, int start, int count, int after) { - - } - - @Override - public void onTextChanged(CharSequence s, int start, int before, int count) { - iperf3EtDuration.setEnabled(s.length() <= 0); - } - - @Override - public void afterTextChanged(Editable s) { - - } - }); - - saveTextInputToSharedPreferences(iperf3EtIp, IPERF3IP); - saveTextInputToSharedPreferences(iperf3EtPort, IPERF3PORT); - saveTextInputToSharedPreferences(iperf3EtBandwidth, IPERF3BANDWIDTH); - saveTextInputToSharedPreferences(iperf3EtDuration, IPERF3DURATION); - saveTextInputToSharedPreferences(iperf3EtInterval, IPERF3INTERVAL); - saveTextInputToSharedPreferences(iperf3EtBytes, IPERF3BYTES); - saveTextInputToSharedPreferences(iperf3EtStreams, IPERF3STREAMS); - saveTextInputToSharedPreferences(iperf3Cport, IPERF3CPORT); - - failedColors = new int[] {getContext().getColor(R.color.crimson), - getContext().getColor(R.color.crimson), getContext().getColor(R.color.crimson)}; - runningColors = new int[] {getContext().getColor(R.color.purple_500), - getContext().getColor(R.color.crimson), getContext().getColor(R.color.forestgreen)}; - succesColors = new int[] {getContext().getColor(R.color.forestgreen), - getContext().getColor(R.color.forestgreen), getContext().getColor(R.color.forestgreen)}; - - progressIndicator.setIndicatorColor(runningColors); - progressIndicator.setIndeterminateAnimationType( - LinearProgressIndicator.INDETERMINATE_ANIMATION_TYPE_CONTIGUOUS); - progressIndicator.setVisibility(LinearProgressIndicator.INVISIBLE); - - editTexts = new LinkedList<>(); - editTexts.add(iperf3EtIp); - editTexts.add(iperf3EtPort); - editTexts.add(iperf3EtBandwidth); - editTexts.add(iperf3EtDuration); - editTexts.add(iperf3EtInterval); - editTexts.add(iperf3EtBytes); - editTexts.add(iperf3EtStreams); - editTexts.add(iperf3Cport); - sendBtn = v.findViewById(R.id.iperf3_send); - instancesBtn = v.findViewById(R.id.iperf3_instances_button); - - sendBtn.setOnClickListener(this::executeIperfCommand); - instancesBtn.setOnClickListener(this::showInstances); - - iperf3BiDir = v.findViewById(R.id.iperf_bidir); - iperf3Reverse = v.findViewById(R.id.iperf3_reverse); - iperf3OneOff = v.findViewById(R.id.iperf3_one_off); - - saveCheckboxInputToSharedPreferences(iperf3BiDir, IPERF3BIDIR); - saveCheckboxInputToSharedPreferences(iperf3Reverse, IPERF3REVERSE); - saveCheckboxInputToSharedPreferences(iperf3OneOff, IPERF3ONEOFF); - - protocolSpinner = v.findViewById(R.id.iperf3_protocol_spinner); - ArrayAdapter adapter = - ArrayAdapter.createFromResource(getContext(), R.array.iperf_protocol, - R.layout.support_simple_spinner_dropdown_item); - adapter.setDropDownViewResource(R.layout.support_simple_spinner_dropdown_item); - protocolSpinner.setAdapter(adapter); - - iperf3ModeSpinner = v.findViewById(R.id.iperf3_mode_spinner); - ArrayAdapter mode_adapter = - ArrayAdapter.createFromResource(getContext(), R.array.iperf_mode, - R.layout.support_simple_spinner_dropdown_item); - adapter.setDropDownViewResource(R.layout.support_simple_spinner_dropdown_item); - iperf3ModeSpinner.setAdapter(mode_adapter); - - - getActivity().getSupportFragmentManager() - .setFragmentResultListener("input", getViewLifecycleOwner(), - new FragmentResultListener() { - @Override - public void onFragmentResult(@NonNull String requestKey, - @NonNull Bundle result) { - - Iperf3RunResult iperf3RunResult = - db.iperf3RunResultDao().getRunResult(result.getString("uid")); - String logFileName = iperf3RunResult.input.iperf3LogFileName.split("_")[0]; - if (logFileName.equals("iperf3")) { - logFileName = ""; - } - - iperf3EtIp.setText(iperf3RunResult.input.iperf3IP); - iperf3EtPort.setText(iperf3RunResult.input.iperf3Port); - iperf3EtBandwidth.setText(iperf3RunResult.input.iperf3Bandwidth); - iperf3EtDuration.setText(iperf3RunResult.input.iperf3Duration); - iperf3EtInterval.setText(iperf3RunResult.input.iperf3Interval); - iperf3EtBytes.setText(iperf3RunResult.input.iperf3Bytes); - iperf3EtStreams.setText(iperf3RunResult.input.streams); - iperf3Cport.setText(iperf3RunResult.input.iperf3Cport); - - iperf3Reverse.setChecked(iperf3RunResult.input.iperf3Reverse); - iperf3BiDir.setChecked(iperf3RunResult.input.iperf3BiDir); - iperf3OneOff.setChecked(iperf3RunResult.input.iperf3OneOff); - protocolSpinner.setSelection(iperf3RunResult.input.iperf3IdxProtocol); - iperf3ModeSpinner.setSelection(iperf3RunResult.input.iperf3IdxMode); - - writeToSP(); - } - }); - iperf3EtIp.setText(spg.getSharedPreference(SPType.iperf3_sp).getString(IPERF3IP, null)); - iperf3EtPort.setText(spg.getSharedPreference(SPType.iperf3_sp).getString(IPERF3PORT, null)); - iperf3EtBandwidth.setText(spg.getSharedPreference(SPType.iperf3_sp).getString(IPERF3BANDWIDTH, null)); - iperf3EtDuration.setText(spg.getSharedPreference(SPType.iperf3_sp).getString(IPERF3DURATION, null)); - iperf3EtInterval.setText(spg.getSharedPreference(SPType.iperf3_sp).getString(IPERF3INTERVAL, null)); - iperf3EtBytes.setText(spg.getSharedPreference(SPType.iperf3_sp).getString(IPERF3BYTES, null)); - iperf3EtStreams.setText(spg.getSharedPreference(SPType.iperf3_sp).getString(IPERF3STREAMS, null)); - iperf3Cport.setText(spg.getSharedPreference(SPType.iperf3_sp).getString(IPERF3CPORT, null)); - - iperf3BiDir.setChecked(spg.getSharedPreference(SPType.iperf3_sp).getBoolean(IPERF3BIDIR, false)); - iperf3Reverse.setChecked(spg.getSharedPreference(SPType.iperf3_sp).getBoolean(IPERF3REVERSE, false)); - iperf3OneOff.setChecked(spg.getSharedPreference(SPType.iperf3_sp).getBoolean(IPERF3ONEOFF, false)); - protocolSpinner.setSelection(spg.getSharedPreference(SPType.iperf3_sp).getInt(IPERF3IDXPROTOCOL, 0)); - iperf3ModeSpinner.setSelection(spg.getSharedPreference(SPType.iperf3_sp).getInt(IPERF3IDXMODE, 0)); - - - try { - Os.setenv("TMPDIR", String.valueOf(getActivity().getCacheDir()), true); - } catch (ErrnoException e) { - Log.d(TAG,e.toString()); - } - return v; - } - - public void showInstances(View view) { - Bundle bundle = new Bundle(); - bundle.putStringArrayList("iperf3List", uids); - - NavController navController; - - NavHostFragment navHostFragment = - (NavHostFragment) getActivity().getSupportFragmentManager() - .findFragmentById(R.id.fragmentContainerView); - navController = navHostFragment.getNavController(); - - navController.navigate(R.id.runners_list, bundle); - } - - private boolean isModeSpinnerClient() { - String status = iperf3ModeSpinner.getSelectedItem().toString(); - return status.equals("Client"); - } - - public void executeIperfCommand(View view) { - String[] command = parseInput().split(" "); - - String path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS).getAbsolutePath() + "/omnt/iperf3LP/"; - - if(input.iperf3Json){ - try { - Files.createDirectories(Paths.get(path)); - } catch (IOException e) { - Toast.makeText(requireContext(),"Could not create Dir files!", Toast.LENGTH_SHORT).show(); - } - } - - // create the log file; - - String iperf3WorkerID = input.uuid; - - input.iperf3LineProtocolFile = path + iperf3WorkerID + ".txt"; - Data.Builder iperf3Data = new Data.Builder(); - iperf3Data.putStringArray("commands", command); - iperf3Data.putString("iperf3WorkerID", iperf3WorkerID); - iperf3Data.putString("rawIperf3file", rawIperf3file); - iperf3Data.putString("iperf3LineProtocolFile", input.iperf3LineProtocolFile); - iperf3Data.putString("measurementName", input.measurementName); - iperf3Data.putString("ip", input.iperf3IP); - iperf3Data.putString("port", input.iperf3Port); - iperf3Data.putString("bandwidth", input.iperf3Bandwidth); - iperf3Data.putString("duration", input.iperf3Duration); - iperf3Data.putString("interval", input.iperf3Interval); - iperf3Data.putString("bytes", input.iperf3Bytes); - iperf3Data.putString("protocol", protocolSpinner.getSelectedItem().toString()); - iperf3Data.putBoolean("rev", input.iperf3Reverse); - iperf3Data.putBoolean("biDir", input.iperf3BiDir); - iperf3Data.putBoolean("oneOff", input.iperf3OneOff); - iperf3Data.putString("client", iperf3ModeSpinner.getSelectedItem().toString()); - iperf3Data.putString("timestamp", input.timestamp.toString()); - iperf3Data.putString("protocol", protocolSpinner.getSelectedItem().toString()); - iperf3Data.putString("cport", input.iperf3Cport); - - ListenableFuture> status = iperf3WM.getWorkInfosByTag("iperf3Run"); - -/* try { - for (WorkInfo workInfo : status.get()) { - if (workInfo.getState().equals(WorkInfo.State.RUNNING)) { - Toast.makeText(getContext(), "iperf3 Test is running!", Toast.LENGTH_SHORT) - .show(); - return; - } - } - } catch (ExecutionException | InterruptedException e) { - Log.d(TAG,e.toString()); -; - }*/ - - uids.add(0, iperf3WorkerID); - iperf3Data.putInt("notificationID", uids.size()); - - - OneTimeWorkRequest iperf3WR = - new OneTimeWorkRequest - .Builder(Iperf3ExecutorWorker.class) - .setInputData(iperf3Data.build()) - .addTag("iperf3Run") - .addTag(iperf3WorkerID) - .build(); - OneTimeWorkRequest iperf3LP = - new OneTimeWorkRequest - .Builder(Iperf3ToLineProtocolWorker.class) - .setInputData(iperf3Data.build()) - .build(); - OneTimeWorkRequest iperf3UP = - new OneTimeWorkRequest - .Builder(Iperf3UploadWorker.class) - .setInputData(iperf3Data.build()) - .addTag("iperf3") - .build(); - - iperf3RunResultDao.insert( - new Iperf3RunResult(iperf3WorkerID, -100, false, input, input.timestamp)); - - - - if (spg.getSharedPreference(SPType.logging_sp).getBoolean("enable_influx", false) && input.iperf3Json) { - iperf3WM.beginWith(iperf3WR).then(iperf3LP).then(iperf3UP).enqueue(); - } else if(input.iperf3Json) { - iperf3WM.beginWith(iperf3WR).then(iperf3LP).enqueue(); - } else { - iperf3WM.beginWith(iperf3WR).enqueue(); - } - - - - Handler progressbarHandler = new Handler(Looper.myLooper()); - - iperf3WM.getWorkInfoByIdLiveData(iperf3WR.getId()).observeForever(workInfo -> { - int iperf3_result; - iperf3_result = workInfo.getOutputData().getInt("iperf3_result", -100); - if (workInfo.getState().equals(WorkInfo.State.CANCELLED)) { - iperf3_result = -1; - } - iperf3RunResultDao.updateResult(iperf3WorkerID, iperf3_result); - Log.d(TAG, "onChanged: iperf3_result: " + iperf3_result); - if (iperf3_result == -100) { - progressIndicator.setVisibility(LinearProgressIndicator.VISIBLE); - if (!isModeSpinnerClient()) { - progressbarHandler.postDelayed(progressbarUpdate, SHOW_PROGRESSBAR); - } - } else if (iperf3_result != 0) { - progressIndicator.setIndicatorColor(failedColors); - progressbarHandler.postDelayed(progressbarUpdate, SHOW_PROGRESSBAR); - - } else { - progressIndicator.setIndicatorColor(succesColors); - progressbarHandler.postDelayed(progressbarUpdate, SHOW_PROGRESSBAR); - } - - }); - iperf3WM.getWorkInfoByIdLiveData(iperf3UP.getId()).observeForever(workInfo -> { - boolean iperf3_upload; - iperf3_upload = workInfo.getOutputData().getBoolean("iperf3_upload", false); - Log.d(TAG, "onChanged: iperf3_upload: " + iperf3_upload); - iperf3RunResultDao.updateUpload(iperf3WorkerID, iperf3_upload); - }); - - - } - - private String getKeyFromId(String s, String value) { - String key = ""; - switch (s) { - case "iperf3_logfile": - key = "--logfile"; - input.measurementName = value; - break; - case "iperf3_streams": - key = "-P"; - input.streams = value; - break; - case "iperf3_ip": - key = "-c"; - input.iperf3IP = value; - break; - case "iperf3_port": - key = "-p"; - input.iperf3Port = value; - break; - case "iperf3_bandwidth": - key = "-b"; - input.iperf3Bandwidth = value; - break; - case "iperf3_duration": - key = "-t"; - input.iperf3Duration = value; - break; - case "iperf3_interval": - key = "-i"; - input.iperf3Interval = value; - break; - case "iperf3_bytes": - key = "-n"; - input.iperf3Bytes = value; - break; - case "iperf3_cport": - key = "--cport"; - input.iperf3Cport = value; - break; - } - return key; - } - - private String parseInput() { - List stb = new LinkedList<>(); - for (EditText et : editTexts) { - String value = et.getText().toString(); - if (!value.equals("")) { - String s = getResources().getResourceEntryName(et.getId()); - String key = getKeyFromId(s, value); - if (s.equals("iperf3_bandwidth")) { - value += "M"; - } - stb.add(key); - stb.add(value); - } - } - - String protocol = protocolSpinner.getSelectedItem().toString(); - if (!protocol.equals("TCP")) { - stb.add("--" + protocol.toLowerCase()); - } - input.iperf3IdxProtocol = protocolSpinner.getSelectedItemPosition(); - - input.timestamp = new Timestamp(System.currentTimeMillis()); - String iperf3TS = input.timestamp.toString().replace(" ", "_").replace(":", "_"); - - input.uuid = UUID.randomUUID().toString(); - - input.measurementName = "Iperf3"; - this.logFileName = String.format("iperf3_%s_%s.json", iperf3TS, input.uuid); - - input.iperf3LogFileName = this.logFileName; - this.rawIperf3file = this.logFileDir + this.logFileName; - input.iperf3rawIperf3file = this.rawIperf3file; - - stb.add("--logfile"); - stb.add(this.rawIperf3file); - - input.iperf3BiDir = false; - input.iperf3Reverse = false; - input.iperf3OneOff = false; - input.iperf3Json = true; - - if (!isModeSpinnerClient()) { - stb.add("-s"); - input.iperf3IdxMode = iperf3ModeSpinner.getSelectedItemPosition(); - } - if (iperf3BiDir.isChecked()) { - stb.add("--bidir"); - input.iperf3BiDir = true; - } - if (iperf3Reverse.isChecked()) { - stb.add("--reverse"); - input.iperf3Reverse = true; - } - if (iperf3OneOff.isChecked()) { - stb.add("--one-off"); - input.iperf3OneOff = true; - } - stb.add("--json-stream"); - - stb.add("--connect-timeout"); - stb.add("500"); - - - String joined = String.join(" ", stb); - - Log.d(TAG, "parseInput: joined command " + joined); - input.iperf3Command = joined; - - - return joined; - } - - @Override - public void onSaveInstanceState(@NonNull Bundle outState) { - super.onSaveInstanceState(outState); - } - - private void writeToSP() { - SharedPreferences.Editor editor = spg.getSharedPreference(SPType.iperf3_sp).edit(); - editor.putInt(IPERF3IDXPROTOCOL, protocolSpinner.getSelectedItemPosition()); - editor.putInt(IPERF3IDXMODE, iperf3ModeSpinner.getSelectedItemPosition()); - editor.putString(IPERF3IP, iperf3EtIp.getText().toString()); - editor.putString(IPERF3PORT, iperf3EtPort.getText().toString()); - editor.putString(IPERF3BANDWIDTH, iperf3EtBandwidth.getText().toString()); - editor.putString(IPERF3DURATION, iperf3EtDuration.getText().toString()); - editor.putString(IPERF3INTERVAL, iperf3EtInterval.getText().toString()); - editor.putString(IPERF3BYTES, iperf3EtBytes.getText().toString()); - editor.putString(IPERF3STREAMS, iperf3EtStreams.getText().toString()); - editor.putString(IPERF3CPORT, iperf3Cport.getText().toString()); - - editor.putBoolean(IPERF3BIDIR, iperf3BiDir.isChecked()); - editor.putBoolean(IPERF3REVERSE, iperf3Reverse.isChecked()); - editor.putBoolean(IPERF3ONEOFF, iperf3OneOff.isChecked()); - editor.apply(); - } - - @Override - public void onDestroy() { - super.onDestroy(); - if(this.isResumed()) - writeToSP(); - } - - - - public static class Iperf3Input { - public boolean iperf3BiDir; - public boolean iperf3Reverse; - public boolean iperf3Json; - public boolean iperf3OneOff; - public int iperf3IdxMode; - public int iperf3IdxProtocol; - public String uuid; - public String iperf3Command; - public String iperf3rawIperf3file; - public String iperf3LogFileName; - public String measurementName; - public String iperf3IP; - public String iperf3Port; - public String iperf3Bandwidth; - public String iperf3LineProtocolFile; - public String iperf3Duration; - public String iperf3Interval; - public String iperf3Bytes; - public Timestamp timestamp; - public String streams; - public String iperf3Cport; - private List getFields(){ - List fields = Arrays.asList(Iperf3Input.class.getDeclaredFields()); - fields.sort((o1, o2) -> { - return o1.toGenericString().compareTo(o2.toGenericString()); - }); - return fields; - } - private LinearLayout getTextView(String name, String value, Context ct){ - LinearLayout mainLL = new LinearLayout(ct); - mainLL.setOrientation(LinearLayout.HORIZONTAL); - - - LinearLayout.LayoutParams parameterLayoutName = new LinearLayout.LayoutParams( - 0, - ViewGroup.LayoutParams.WRAP_CONTENT); - parameterLayoutName.weight = 1F; - TextView parameterName = new TextView(ct); - parameterName.setTextIsSelectable(true); - parameterName.setText(String.format("%s", name)); - parameterName.setLayoutParams(parameterLayoutName); - TextView parameterValue = new TextView(ct); - parameterValue.setTextIsSelectable(true); - parameterValue.setText(String.format("%s", value)); - LinearLayout.LayoutParams parameterLayoutValue = new LinearLayout.LayoutParams( - 0, - ViewGroup.LayoutParams.WRAP_CONTENT); - parameterLayoutValue.weight = 3F; - parameterValue.setLayoutParams(parameterLayoutValue); - - mainLL.addView(parameterName); - mainLL.addView(parameterValue); - return mainLL; - } - private LinearLayout getTextViewValue(String key, String value, Context ct){ - LinearLayout mainLL = new LinearLayout(ct); - mainLL.setOrientation(LinearLayout.HORIZONTAL); - mainLL.setFocusable(false); - mainLL.setFocusedByDefault(false); - - TextView parameterValue = new TextView(ct); - - parameterValue.setTextIsSelectable(true); - parameterValue.setText(String.format("%s", value)); - LinearLayout.LayoutParams parameterLayoutValue = new LinearLayout.LayoutParams( - 0, - ViewGroup.LayoutParams.WRAP_CONTENT); - parameterValue.setPadding(5, 5, 5, 5); - parameterLayoutValue.setMargins(0, 0, 10, 10); - parameterLayoutValue.weight = 1F; - parameterValue.setLayoutParams(parameterLayoutValue); - - mainLL.addView(parameterValue); - return mainLL; - } - public LinearLayout getInputAsLinearLayoutKeyValue(LinearLayout mainLL, Context ct){ - mainLL.setOrientation(LinearLayout.VERTICAL); - LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams( - 0, - ViewGroup.LayoutParams.WRAP_CONTENT); - layoutParams.weight = 8F; - mainLL.setLayoutParams(layoutParams); - String[] protocol = - ct.getResources().getStringArray(R.array.iperf_protocol); - String[] mode = ct.getResources().getStringArray(R.array.iperf_mode); - for(Field parameter: getFields()){ - try { - Object parameterValueObj = parameter.get(this); - if(parameterValueObj == null){ - continue; - } - - String parameterName = parameter.getName().replace("iperf3", ""); - if(parameterName.equals("measurementName") - || parameterName.equals("rawIperf3file") - || parameterName.equals("LogFileName") - || parameterName.equals("Command") - || parameterName.equals("LineProtocolFile")) continue; - - String parameterValue = parameter.get(this).toString(); - if(parameterValue.equals("false")){ - continue; - } - if(parameterName.equals("IdxProtocol")){ - parameterName = "Protocol"; - parameterValue = protocol[Integer.parseInt(parameterValue)]; - } - - if(parameterName.equals("IdxMode")){ - parameterName = "Mode"; - parameterValue = mode[Integer.parseInt(parameterValue)]; - } - mainLL.addView(getTextView( - parameterName, - parameterValue, - ct)); - - } catch (IllegalAccessException e) { - throw new RuntimeException(e); - } - } - return mainLL; - } - - public LinearLayout getInputAsLinearLayoutValue(LinearLayout mainLL, Context ct){ - mainLL.setOrientation(LinearLayout.HORIZONTAL); - LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams( - 0, - ViewGroup.LayoutParams.WRAP_CONTENT); - layoutParams.weight = 10F; - mainLL.setLayoutParams(layoutParams); - String[] protocol = - ct.getResources().getStringArray(R.array.iperf_protocol); - String[] mode = ct.getResources().getStringArray(R.array.iperf_mode); - for(Field parameter: getFields()){ - try { - Object parameterValueObj = parameter.get(this); - if(parameterValueObj == null){ - continue; - } - - String parameterName = parameter.getName().replace("iperf3", ""); - if(parameterName.equals("measurementName") - || parameterName.equals("rawIperf3file") - || parameterName.equals("LogFileName") - || parameterName.equals("Command") - || parameterName.equals("LineProtocolFile") - || parameterName.equals("timestamp") - || parameterName.equals("uuid")) continue; - - String parameterValue = parameter.get(this).toString(); - if(parameterValue.equals("false")){ - continue; - } - if(parameterName.equals("IdxProtocol")){ - parameterName = "Protocol"; - parameterValue = protocol[Integer.parseInt(parameterValue)]; - } - - if(parameterName.equals("IdxMode")){ - parameterName = "Mode"; - parameterValue = mode[Integer.parseInt(parameterValue)]; - } - - if(parameterValue.equals("true")){ - parameterValue = parameterName; - } - - mainLL.addView(getTextViewValue( - parameterName, - parameterValue, - ct)); - - } catch (IllegalAccessException e) { - throw new RuntimeException(e); - } - } - return mainLL; - } - } -} \ No newline at end of file diff --git a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Iperf3InputConverter.java b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Iperf3InputConverter.java index 61c014c5..d763256b 100644 --- a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Iperf3InputConverter.java +++ b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Iperf3InputConverter.java @@ -13,15 +13,18 @@ import com.google.gson.Gson; +import de.fraunhofer.fokus.OpenMobileNetworkToolkit.Inputs.Iperf3Input; + + @ProvidedTypeConverter public class Iperf3InputConverter { @TypeConverter - public Iperf3Fragment.Iperf3Input StringToIperf3Input(String string) { - return new Gson().fromJson(string, Iperf3Fragment.Iperf3Input.class); + public Iperf3Input StringToIperf3Input(String string) { + return new Gson().fromJson(string, Iperf3Input.class); } @TypeConverter - public String Iperf3InputToString(Iperf3Fragment.Iperf3Input example) { + public String Iperf3InputToString(Iperf3Input example) { return new Gson().toJson(example); } } diff --git a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Iperf3ListFragment.java b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Iperf3ListFragment.java index ef896f0d..dc3b9f2c 100644 --- a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Iperf3ListFragment.java +++ b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Iperf3ListFragment.java @@ -79,47 +79,7 @@ public View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle saved @SuppressLint("NotifyDataSetChanged") @Override public void onRightClicked(int position) { - WorkManager iperf3WM = WorkManager.getInstance(getContext()); - String uid = uids.get(position); - iperf3WM.cancelAllWorkByTag(uid); - Iperf3RunResultDao iperf3RunResultDao = Iperf3ResultsDataBase.getDatabase(requireContext()).iperf3RunResultDao(); - Iperf3RunResult runResult = iperf3RunResultDao.getRunResult(uid); - - - Data.Builder iperf3Data = new Data.Builder(); - - iperf3Data.putString("rawIperf3file", runResult.input.iperf3rawIperf3file); - iperf3Data.putString("iperf3LineProtocolFile", runResult.input.iperf3LineProtocolFile); - iperf3Data.putString("measurementName", runResult.input.measurementName); - iperf3Data.putString("ip", runResult.input.iperf3IP); - iperf3Data.putString("port", runResult.input.iperf3Port); - iperf3Data.putString("bandwidth", runResult.input.iperf3Bandwidth); - iperf3Data.putString("duration", runResult.input.iperf3Duration); - iperf3Data.putString("interval", runResult.input.iperf3Interval); - iperf3Data.putString("bytes", runResult.input.iperf3Bytes); - iperf3Data.putString("protocol", Iperf3Utils.getProtocolString(runResult.input.iperf3IdxProtocol)); - iperf3Data.putBoolean("rev", runResult.input.iperf3Reverse); - iperf3Data.putBoolean("biDir", runResult.input.iperf3BiDir); - iperf3Data.putBoolean("oneOff", runResult.input.iperf3OneOff); - iperf3Data.putString("client", Iperf3Utils.getModeString(runResult.input.iperf3IdxMode)); - iperf3Data.putString("timestamp", runResult.input.timestamp.toString()); - - OneTimeWorkRequest iperf3LP = - new OneTimeWorkRequest - .Builder(Iperf3ToLineProtocolWorker.class) - .setInputData(iperf3Data.build()) - .build(); - iperf3WM.enqueue(iperf3LP); - - - if(runResult.result != 0) - iperf3RunResultDao.updateResult(uid, 1); - new Handler(Looper.getMainLooper()).postDelayed(new Runnable() { - @Override - public void run() { - adapter.notifyDataSetChanged(); - } - }, 100); + //TODO } @Override diff --git a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Iperf3LogFragment.java b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Iperf3LogFragment.java index c8372b74..d9c349da 100644 --- a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Iperf3LogFragment.java +++ b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Iperf3LogFragment.java @@ -99,13 +99,13 @@ public void run() { try { br = new BufferedReader(new FileReader(file)); } catch (FileNotFoundException e) { - iperf3OutputViewer.setText(String.format("no iPerf3 file found, with following path: \n %s", iperf3RunResult.input.iperf3rawIperf3file)); + iperf3OutputViewer.setText(String.format("no iPerf3 file found, with following path: \n %s", iperf3RunResult.input.getParameter().getLogfile())); logHandler.removeCallbacks(logUpdate); return; } String line; - Iperf3Parser iperf3Parser = new Iperf3Parser(iperf3RunResult.input.iperf3rawIperf3file); + Iperf3Parser iperf3Parser = new Iperf3Parser(iperf3RunResult.input.getParameter().getLogfile()); iperf3Parser.addPropertyChangeListener(new PropertyChangeListener() { private void parseSum(Sum sum, Metric throughput){ @@ -217,7 +217,7 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container, uploadIconView.setLayoutParams(uploadIconViewLayout); - parameterLL = iperf3RunResult.input.getInputAsLinearLayoutKeyValue(new LinearLayout(ct), ct); + //parameterLL = iperf3RunResult.input.getInputAsLinearLayoutKeyValue(new LinearLayout(ct), ct); @@ -314,45 +314,51 @@ public void onClick(View v) { defaultReverseThroughput = new Metric(METRIC_TYPE.THROUGHPUT, ct); metricLL.addView(defaultThroughput.createMainLL("Throughput")); - - if(iperf3RunResult.input.iperf3BiDir) { - metricLL.addView(defaultReverseThroughput.createMainLL("Throughput")); - if(iperf3RunResult.input.iperf3IdxProtocol == 0) { - //defaultRTT = new Metric(METRIC_TYPE.RTT); - //metricLL.addView(defaultRTT.createOneDirection("RTT")); - } - if(iperf3RunResult.input.iperf3IdxProtocol == 1) { - defaultJITTER = new Metric(METRIC_TYPE.JITTER, ct); - metricLL.addView(defaultJITTER.createMainLL("Jitter ms")); - PACKET_LOSS = new Metric(METRIC_TYPE.PACKET_LOSS, ct); - metricLL.addView(PACKET_LOSS.createMainLL("Packet Loss %")); - } - } - if(iperf3RunResult.input.iperf3Reverse) { - if(iperf3RunResult.input.iperf3IdxProtocol == 1) { - defaultJITTER = new Metric(METRIC_TYPE.JITTER, ct); - metricLL.addView(defaultJITTER.createMainLL("Jitter ms")); - PACKET_LOSS = new Metric(METRIC_TYPE.JITTER, ct); - metricLL.addView(PACKET_LOSS.createMainLL("Packet Loss %")); - } - } else if(!iperf3RunResult.input.iperf3BiDir) { - if(iperf3RunResult.input.iperf3IdxProtocol == 0) { - //defaultRTT = new Metric(METRIC_TYPE.RTT); - //metricLL.addView(defaultRTT.createOneDirection("RTT ms")); - } + switch (iperf3RunResult.input.getParameter().getDirection()){ + case BIDIR: + metricLL.addView(defaultReverseThroughput.createMainLL("Throughput")); + switch (iperf3RunResult.input.getParameter().getProtocol()){ + case TCP: + break; + case UDP: + defaultJITTER = new Metric(METRIC_TYPE.JITTER, ct); + metricLL.addView(defaultJITTER.createMainLL("Jitter ms")); + PACKET_LOSS = new Metric(METRIC_TYPE.PACKET_LOSS, ct); + metricLL.addView(PACKET_LOSS.createMainLL("Packet Loss %")); + default: + break; + } + break; + case UP: + break; + case DOWN: + switch (iperf3RunResult.input.getParameter().getProtocol()){ + case TCP: + break; + case UDP: + defaultJITTER = new Metric(METRIC_TYPE.JITTER, ct); + metricLL.addView(defaultJITTER.createMainLL("Jitter ms")); + PACKET_LOSS = new Metric(METRIC_TYPE.JITTER, ct); + metricLL.addView(PACKET_LOSS.createMainLL("Packet Loss %")); + break; + } + break; + default: + break; } + mainLL.addView(metricLL); mainLL.addView(secondRow); - if(iperf3RunResult.input.iperf3rawIperf3file == null){ + if(iperf3RunResult.input.getParameter().getLogfile() == null){ iperf3OutputViewer.setText("iPerf3 file path empty!"); return v; } - file = new File(iperf3RunResult.input.iperf3rawIperf3file); + file = new File(iperf3RunResult.input.getParameter().getLogfile()); logHandler = new Handler(Looper.myLooper()); diff --git a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Iperf3RecyclerViewAdapter.java b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Iperf3RecyclerViewAdapter.java index 459be435..59cc0d13 100644 --- a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Iperf3RecyclerViewAdapter.java +++ b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Iperf3RecyclerViewAdapter.java @@ -86,7 +86,7 @@ public void onClick(View view) { Iperf3RunResult runResult = iperf3RunResultDao.getRunResult(uid); Data.Builder data = new Data.Builder(); - data.putString("iperf3LineProtocolFile", runResult.input.iperf3LineProtocolFile); + data.putString("iperf3LineProtocolFile", runResult.input.getParameter().getLineProtocolFile()); OneTimeWorkRequest iperf3UP = new OneTimeWorkRequest.Builder(Iperf3UploadWorker.class) .setInputData(data.build()) @@ -152,11 +152,10 @@ public void onBindViewHolder(@NonNull ViewHolder holder, int position) { } holder.measurement.setText("iPerf3"); - holder.timestamp.setText(test.input.timestamp.toString()); + holder.timestamp.setText(test.input.getParameter().getTimestamps().toString()); holder.runIcon.setImageDrawable(Iperf3Utils.getDrawableResult(context, test.result)); holder.uploadIcon.setImageDrawable(Iperf3Utils.getDrawableUpload(context, test.result, test.uploaded)); - holder.iPerf3Parameters = test.input.getInputAsLinearLayoutValue(holder.iPerf3Parameters, context); } private Iperf3RunResult getItemByPosition(int position) { return this.db.iperf3RunResultDao().getRunResult(this.uids.get(position)); diff --git a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Worker/Iperf3ExecutorWorker.java b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Worker/Iperf3ExecutorWorker.java index 4da97bbf..bf7c727f 100644 --- a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Worker/Iperf3ExecutorWorker.java +++ b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Worker/Iperf3ExecutorWorker.java @@ -85,7 +85,7 @@ public Iperf3ExecutorWorker(@NonNull Context context, @NonNull WorkerParameters public ListenableFuture startRemoteWork() { return CallbackToFutureAdapter.getFuture(completer -> { - File logFile = new File(iperf3Input.getIperf3Parameter().getLogfile()); + File logFile = new File(iperf3Input.getParameter().getLogfile()); if(logFile.exists() && !logFile.isDirectory()) { //weird hack otherwise the worker gets enqueued two times return completer.set(Result.success(new Data.Builder().putString("testUUID", iperf3Input.getTestUUID()).build())); @@ -97,7 +97,7 @@ public ListenableFuture startRemoteWork() { return completer.set(Result.failure()); } Log.i(TAG, "Starting "+TAG); - setForegroundAsync(createForegroundInfo(iperf3Input.getIperf3Parameter().getHost()+":"+iperf3Input.getIperf3Parameter().getPort())); + setForegroundAsync(createForegroundInfo(iperf3Input.getParameter().getHost()+":"+iperf3Input.getParameter().getPort())); final int[] result = {-1}; Handler handler = new Handler(Looper.myLooper()); @@ -109,7 +109,7 @@ public ListenableFuture startRemoteWork() { Runnable iperf3 = new Runnable(){ @Override public void run() { - result[0] = iperf3Wrapper(iperf3Input.getIperf3Parameter().getInputAsCommand(), getApplicationContext().getApplicationInfo().nativeLibraryDir); + result[0] = iperf3Wrapper(iperf3Input.getParameter().getInputAsCommand(), getApplicationContext().getApplicationInfo().nativeLibraryDir); Log.d(TAG, "doWork: " + result[0]); } }; @@ -131,8 +131,8 @@ public void run() { }; Log.d(TAG, "startRemoteWork: running thread"); executorService.execute(iperf3); - executorService.schedule(read, (long) (iperf3Input.getIperf3Parameter().getInterval()+0.5), TimeUnit.SECONDS); - executorService.awaitTermination(iperf3Input.getIperf3Parameter().getTime()+4, TimeUnit.SECONDS); + executorService.schedule(read, (long) (iperf3Input.getParameter().getInterval()+0.5), TimeUnit.SECONDS); + executorService.awaitTermination(iperf3Input.getParameter().getTime()+4, TimeUnit.SECONDS); Log.d(TAG, "doWork: " + result[0]); Data.Builder output = new Data.Builder() diff --git a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Worker/Iperf3ToLineProtocolWorker.java b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Worker/Iperf3ToLineProtocolWorker.java index 5a2392e1..c5d1d705 100644 --- a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Worker/Iperf3ToLineProtocolWorker.java +++ b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Worker/Iperf3ToLineProtocolWorker.java @@ -87,7 +87,7 @@ private ForegroundInfo createForegroundInfo(String progress) { public Result doWork() { Data output = new Data.Builder().putBoolean("iperf3_upload", false).build(); - Iperf3Parser iperf3Parser = new Iperf3Parser(iperf3Input.getIperf3Parameter().getLogfile()); + Iperf3Parser iperf3Parser = new Iperf3Parser(iperf3Input.getParameter().getLogfile()); iperf3Parser.parse(); @@ -111,20 +111,20 @@ public Result doWork() { point.addTag(Iperf3Input.SEQUENCEUUID, iperf3Input.getSequenceUUID()); point.addTag(Iperf3Input.MEASUREMENTUUID, iperf3Input.getMeasurementUUID()); point.addTag(Iperf3Input.CAMPAIGNUUID, iperf3Input.getCampaignUUID()); - point.addTag(Iperf3Input.IPERF3UUID, iperf3Input.getIperf3Parameter().getiPerf3UUID()); + point.addTag(Iperf3Input.IPERF3UUID, iperf3Input.getParameter().getiPerf3UUID()); - point.addTag("bidir", String.valueOf(iperf3Input.getIperf3Parameter().getBidir())); + point.addTag("bidir", String.valueOf(iperf3Input.getParameter().getBidir())); point.addTag("sender", String.valueOf(stream.getSender())); point.addTag("role", role); point.addTag("socket", String.valueOf(stream.getSocket())); point.addTag("protocol", iperf3Parser.getStart().getTest_start().protocol); - point.addTag("interval", String.valueOf(iperf3Input.getIperf3Parameter().getInterval())); + point.addTag("interval", String.valueOf(iperf3Input.getParameter().getInterval())); point.addTag("version", iperf3Parser.getStart().getVersion()); - point.addTag("reversed", String.valueOf(iperf3Input.getIperf3Parameter().getReverse())); - point.addTag("oneOff", String.valueOf(iperf3Input.getIperf3Parameter().getOneOff())); + point.addTag("reversed", String.valueOf(iperf3Input.getParameter().getReverse())); + point.addTag("oneOff", String.valueOf(iperf3Input.getParameter().getOneOff())); point.addTag("connectingToHost", iperf3Parser .getStart() .getConnecting_to() @@ -133,9 +133,9 @@ public Result doWork() { .getStart() .getConnecting_to() .getPort())); - point.addTag("bandwidth", iperf3Input.getIperf3Parameter().getBitrate()); - point.addTag("duration", String.valueOf(iperf3Input.getIperf3Parameter().getTime())); - point.addTag("bytesToTransmit", String.valueOf(iperf3Input.getIperf3Parameter().getBytes())); + point.addTag("bandwidth", iperf3Input.getParameter().getBitrate()); + point.addTag("duration", String.valueOf(iperf3Input.getParameter().getTime())); + point.addTag("bytesToTransmit", String.valueOf(iperf3Input.getParameter().getBytes())); point.addTag("streams", String.valueOf(interval.getStreams().size())); point.addTag("streamIdx", String.valueOf(interval.getStreams().getStreamArrayList().indexOf(stream))); point.addTag("intervalIdx", String.valueOf(intervalIdx)); @@ -188,7 +188,7 @@ public Result doWork() { FileOutputStream iperf3Stream = null; try { - iperf3Stream = new FileOutputStream(iperf3Input.getIperf3Parameter().getLineProtocolFile(), true); + iperf3Stream = new FileOutputStream(iperf3Input.getParameter().getLineProtocolFile(), true); } catch (FileNotFoundException e) { Toast.makeText(getApplicationContext(), "logfile not created", Toast.LENGTH_SHORT).show(); Log.d(TAG,e.toString()); diff --git a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Worker/Iperf3UploadWorker.java b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Worker/Iperf3UploadWorker.java index d2851231..54e9cbcf 100644 --- a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Worker/Iperf3UploadWorker.java +++ b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Iperf3/Worker/Iperf3UploadWorker.java @@ -65,17 +65,17 @@ public Result doWork() { } BufferedReader br; try { - br = new BufferedReader(new FileReader(iperf3Input.getIperf3Parameter().getLineProtocolFile())); + br = new BufferedReader(new FileReader(iperf3Input.getParameter().getLineProtocolFile())); } catch (FileNotFoundException | NullPointerException e) { Log.d(TAG,e.toString()); return Result.failure(output); } List points = br.lines().collect(Collectors.toList()); try { - Log.d(TAG, String.format("doWork: uploading %s", iperf3Input.getIperf3Parameter().getLineProtocolFile())); + Log.d(TAG, String.format("doWork: uploading %s", iperf3Input.getParameter().getLineProtocolFile())); influx.writeRecords(points); } catch (IOException e) { - Log.d(TAG, String.format("doWork: upload of %s failed!", iperf3Input.getIperf3Parameter().getLineProtocolFile())); + Log.d(TAG, String.format("doWork: upload of %s failed!", iperf3Input.getParameter().getLineProtocolFile())); return Result.failure(output); } diff --git a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/LoggingService.java b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/LoggingService.java index 330590fc..c3e0b2f7 100644 --- a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/LoggingService.java +++ b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/LoggingService.java @@ -609,7 +609,9 @@ private void stopLocalInfluxDB() { public void run() { if (ic == null) return; boolean newInfluxConnectionStatus = ic.ping(); - Log.d(TAG, "run: monitorInfluxDBConnectionStatus: "+newInfluxConnectionStatus); + if(!newInfluxConnectionStatus) { + Log.d(TAG, "InfluxDB not reachable"); + } if(newInfluxConnectionStatus != influxConnectionStatus) { influxConnectionStatus = newInfluxConnectionStatus; updateNotification(); diff --git a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Parameter/Iperf3Parameter.java b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Parameter/Iperf3Parameter.java index 1b3c7953..63fffe1d 100644 --- a/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Parameter/Iperf3Parameter.java +++ b/app/src/main/java/de/fraunhofer/fokus/OpenMobileNetworkToolkit/Parameter/Iperf3Parameter.java @@ -237,7 +237,9 @@ public Iperf3Parameter[] newArray(int size) { return new Iperf3Parameter[size]; } }; - + public Iperf3Parameter(String iPerf3UUID){ + super(rawDirPath+iPerf3UUID+".txt", lineProtocolDirPath+iPerf3UUID+".txt"); + } public Iperf3Parameter(String ip, String iPerf3UUID, Iperf3Protocol protocol, @@ -791,6 +793,14 @@ public String getHost() { return host; } + public void setHost(String s) { + this.host = s; + } + + public void setBandwidth(String s) { + this.bitrate = s ; + } + // --- Enums --- public enum Iperf3Mode { diff --git a/app/src/main/res/layout/fragment_iperf3_input.xml b/app/src/main/res/layout/fragment_iperf3_input.xml index 84d8b895..ddcaa5aa 100644 --- a/app/src/main/res/layout/fragment_iperf3_input.xml +++ b/app/src/main/res/layout/fragment_iperf3_input.xml @@ -1,293 +1,280 @@ - - + + xmlns:app="http://schemas.android.com/apk/res-auto" + android:orientation="vertical"> + - - - - - - - - - - - - - - - - - - - - -