diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..53c5262
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,4 @@
+**/.vscode/
+**/target/
+**/build/
+**/bin/
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..aa36aa2
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2024 iamywang
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..2160d46
--- /dev/null
+++ b/README.md
@@ -0,0 +1,87 @@
+# EavesDroid: Eavesdropping User Behaviors via OS Side Channels on Smartphones
+
+This repo contains the source code and dataset of our paper "EavesDroid: Eavesdropping User Behaviors via OS Side Channels on Smartphones" published in IEEE Internet of Things Journal (IoT-J).
+
+![EavesDroid](./overview.png)
+
+## 0x01 Getting Started
+
+Prerequisites:
+
+- Android Studio
+- Android NDK
+- Python 3.11
+ - numpy
+ - matplotlib
+ - keras
+ - django
+ - cydtw
+
+## 0x02 Repo Structure
+
+**1. Android App**
+
+- `app/` contains the source code of our Android app.
+
+- Please rename it to `Sampler` and import it into Android Studio to build the app.
+
+- Note: `val api = "http://192.168.1.2:8000"` in `MainActivity.kt` should be changed to the proper server address.
+
+**2. Server**
+
+- `backend/` contains the source code of our Django server.
+
+- Please run `python manage.py runserver` to start the server.
+
+**3. Data Collection**
+
+- `collection/` contains the source code of emulated data collection tool.
+
+- Please run `python sample.py/sample2.py` to collect data from your own devices.
+
+- Note: parameters should be changed to the proper values.
+
+**4. Data Classification**
+
+- `classification/` contains the source code of user behavior classification tool.
+
+- `all_model.py` contains the baseline models used in our paper: 1D-CNN, LSTM, GRU.
+
+- `dtw_model.py` contains the DTW-KNN algorithm used in our paper.
+
+- `classify.py` is the main script to infer user behaviors with our CNN-GRU model.
+
+**4. Dataset**
+
+- `dataset/` contains the dataset used in our paper.
+
+- Data in this directory can be used to train classification models and reproduce our results.
+
+**5. Figures**
+
+- `figures/` contains the figure generation scripts used in our paper.
+
+- Files in this directory can be used to reproduce the figures in our paper.
+
+## 0x03 Copyright and License
+
+This project is licensed under the terms of the MIT License.
+
+## 0x04 Contact and Citation
+
+If you have any questions, please contact me through `GitHub Issues` or email: wangquancheng@whu.edu.cn.
+
+If our work is useful for your research, please consider citing our paper:
+
+```bibtex
+@ARTICLE{wang2024eavesdroid,
+ author={Wang, Quancheng and Tang, Ming and Fu, Jianming},
+ journal={IEEE Internet of Things Journal (IoT-J)},
+ title={EavesDroid: Eavesdropping User Behaviors via OS Side Channels on Smartphones},
+ year={2024},
+ volume={11},
+ number={3},
+ pages={3979-3993},
+ doi={10.1109/JIOT.2023.3298992}
+}
+```
diff --git a/app/.gitignore b/app/.gitignore
new file mode 100755
index 0000000..57a997f
--- /dev/null
+++ b/app/.gitignore
@@ -0,0 +1,18 @@
+*.iml
+.gradle
+/local.properties
+/.idea/caches
+/.idea/libraries
+/.idea/modules.xml
+/.idea/workspace.xml
+/.idea/navEditor.xml
+/.idea/assetWizardSettings.xml
+.DS_Store
+/build
+/captures
+.externalNativeBuild
+.cxx
+local.properties
+build/
+.idea
+
diff --git a/app/app/.gitignore b/app/app/.gitignore
new file mode 100755
index 0000000..42afabf
--- /dev/null
+++ b/app/app/.gitignore
@@ -0,0 +1 @@
+/build
\ No newline at end of file
diff --git a/app/app/build.gradle b/app/app/build.gradle
new file mode 100755
index 0000000..2a33df3
--- /dev/null
+++ b/app/app/build.gradle
@@ -0,0 +1,64 @@
+plugins {
+ id 'com.android.application'
+ id 'org.jetbrains.kotlin.android'
+}
+
+android {
+ compileSdk 33
+
+ defaultConfig {
+ applicationId "com.iamywang.sampler"
+ minSdk 29
+ targetSdk 33
+ versionCode 22070709
+ versionName "1.1.20220707"
+
+ testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
+ externalNativeBuild {
+ cmake {
+ cppFlags '-std=c++11'
+ }
+ }
+
+ ndk {
+ moduleName "app"
+ abiFilters "arm64-v8a"
+ }
+ }
+
+ buildTypes {
+ release {
+ minifyEnabled true
+ proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+ }
+ }
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_1_8
+ targetCompatibility JavaVersion.VERSION_1_8
+ }
+ kotlinOptions {
+ jvmTarget = '1.8'
+ }
+ externalNativeBuild {
+ cmake {
+ path file('src/main/cpp/CMakeLists.txt')
+ version '3.18.1'
+ }
+ }
+ buildFeatures {
+ viewBinding true
+ }
+}
+
+dependencies {
+
+ implementation 'androidx.core:core-ktx:1.8.0'
+ implementation 'androidx.appcompat:appcompat:1.4.2'
+ implementation 'com.google.android.material:material:1.6.1'
+ implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
+ testImplementation 'junit:junit:4.13.2'
+ androidTestImplementation 'androidx.test.ext:junit:1.1.3'
+ androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
+ implementation 'com.squareup.okhttp3:okhttp:4.9.3'
+ implementation 'com.alibaba:fastjson:1.2.83'
+}
\ No newline at end of file
diff --git a/app/app/proguard-rules.pro b/app/app/proguard-rules.pro
new file mode 100755
index 0000000..481bb43
--- /dev/null
+++ b/app/app/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
\ No newline at end of file
diff --git a/app/app/src/androidTest/java/com/iamywang/sampler/ExampleInstrumentedTest.kt b/app/app/src/androidTest/java/com/iamywang/sampler/ExampleInstrumentedTest.kt
new file mode 100755
index 0000000..4b79692
--- /dev/null
+++ b/app/app/src/androidTest/java/com/iamywang/sampler/ExampleInstrumentedTest.kt
@@ -0,0 +1,24 @@
+package com.iamywang.sampler
+
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.ext.junit.runners.AndroidJUnit4
+
+import org.junit.Test
+import org.junit.runner.RunWith
+
+import org.junit.Assert.*
+
+/**
+ * Instrumented test, which will execute on an Android device.
+ *
+ * See [testing documentation](http://d.android.com/tools/testing).
+ */
+@RunWith(AndroidJUnit4::class)
+class ExampleInstrumentedTest {
+ @Test
+ fun useAppContext() {
+ // Context of the app under test.
+ val appContext = InstrumentationRegistry.getInstrumentation().targetContext
+ assertEquals("com.iamywang.sampler", appContext.packageName)
+ }
+}
\ No newline at end of file
diff --git a/app/app/src/main/AndroidManifest.xml b/app/app/src/main/AndroidManifest.xml
new file mode 100755
index 0000000..70e7aec
--- /dev/null
+++ b/app/app/src/main/AndroidManifest.xml
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/app/src/main/cpp/CMakeLists.txt b/app/app/src/main/cpp/CMakeLists.txt
new file mode 100755
index 0000000..0b8dc4b
--- /dev/null
+++ b/app/app/src/main/cpp/CMakeLists.txt
@@ -0,0 +1,48 @@
+# For more information about using CMake with Android Studio, read the
+# documentation: https://d.android.com/studio/projects/add-native-code.html
+
+# Sets the minimum version of CMake required to build the native library.
+
+cmake_minimum_required(VERSION 3.18.1)
+
+# Declares and names the project.
+
+project("sampler")
+
+# Creates and names a library, sets it as either STATIC
+# or SHARED, and provides the relative paths to its source code.
+# You can define multiple libraries, and CMake builds them for you.
+# Gradle automatically packages shared libraries with your APK.
+
+add_library( # Sets the name of the library.
+ sampler
+
+ # Sets the library as a shared library.
+ SHARED
+
+ # Provides a relative path to your source file(s).
+ native-lib.cpp)
+
+# Searches for a specified prebuilt library and stores the path as a
+# variable. Because CMake includes system libraries in the search path by
+# default, you only need to specify the name of the public NDK library
+# you want to add. CMake verifies that the library exists before
+# completing its build.
+
+find_library( # Sets the name of the path variable.
+ log-lib
+
+ # Specifies the name of the NDK library that
+ # you want CMake to locate.
+ log)
+
+# Specifies libraries CMake should link to your target library. You
+# can link multiple libraries, such as libraries you define in this
+# build script, prebuilt third-party libraries, or system libraries.
+
+target_link_libraries( # Specifies the target library.
+ sampler
+
+ # Links the target library to the log library
+ # included in the NDK.
+ ${log-lib})
\ No newline at end of file
diff --git a/app/app/src/main/cpp/native-lib.cpp b/app/app/src/main/cpp/native-lib.cpp
new file mode 100755
index 0000000..5a109a3
--- /dev/null
+++ b/app/app/src/main/cpp/native-lib.cpp
@@ -0,0 +1,58 @@
+// ============================================================================
+// This file is part of EavesDroid.
+//
+// Author: iamywang
+// Date Created: Jan 27, 2024
+// ============================================================================
+#include
+#include
+#include
+#include
+#include
+
+extern "C" JNIEXPORT jint JNICALL
+Java_com_iamywang_sampler_BackService_sysinfo_1procs(JNIEnv *env, jobject thiz) {
+ struct sysinfo info{};
+ sysinfo(&info);
+ return info.procs;
+}
+
+extern "C" JNIEXPORT jlong JNICALL
+Java_com_iamywang_sampler_BackService_statvfs_1f_1bavail(JNIEnv *env, jobject thiz) {
+ struct statvfs st{};
+ statvfs("/sdcard", &st);
+ return st.f_bavail;
+}
+
+extern "C"
+JNIEXPORT jlong JNICALL
+Java_com_iamywang_sampler_BackService_sysconf_1avphys_1pages(JNIEnv *env, jobject thiz) {
+ return sysconf(_SC_AVPHYS_PAGES);
+}
+
+extern "C"
+JNIEXPORT jlong JNICALL
+Java_com_iamywang_sampler_BackService_statvfs_1f_1ffree(JNIEnv *env, jobject thiz) {
+ struct statvfs st{};
+ statvfs("/sdcard", &st);
+ return st.f_ffree;
+}
+
+extern "C" JNIEXPORT jlong JNICALL
+Java_com_iamywang_sampler_BackService_sysinfo_1freeram(JNIEnv *env, jobject thiz) {
+ struct sysinfo info{};
+ sysinfo(&info);
+ return info.freeram;
+}
+
+extern "C" JNIEXPORT jlong JNICALL
+Java_com_iamywang_sampler_BackService_sysinfo_1sharedram(JNIEnv *env, jobject thiz) {
+ struct sysinfo info{};
+ sysinfo(&info);
+ return info.sharedram;
+}
+
+extern "C" JNIEXPORT jlong JNICALL
+Java_com_iamywang_sampler_BackService_get_1avphys_1pages(JNIEnv *env, jobject thiz) {
+ return get_avphys_pages();
+}
diff --git a/app/app/src/main/ic_launcher-playstore.png b/app/app/src/main/ic_launcher-playstore.png
new file mode 100755
index 0000000..11c5334
Binary files /dev/null and b/app/app/src/main/ic_launcher-playstore.png differ
diff --git a/app/app/src/main/java/com/iamywang/sampler/BackService.kt b/app/app/src/main/java/com/iamywang/sampler/BackService.kt
new file mode 100755
index 0000000..289a139
--- /dev/null
+++ b/app/app/src/main/java/com/iamywang/sampler/BackService.kt
@@ -0,0 +1,129 @@
+// ============================================================================
+// This file is part of EavesDroid.
+//
+// Author: iamywang
+// Date Created: Jan 27, 2024
+// ============================================================================
+package com.iamywang.sampler
+
+import android.app.Service
+import android.content.Intent
+import android.os.Build
+import android.os.IBinder
+import com.alibaba.fastjson.JSON
+import com.alibaba.fastjson.JSONObject
+import java.util.*
+
+import okhttp3.*
+import okhttp3.MediaType.Companion.toMediaType
+import okhttp3.RequestBody.Companion.toRequestBody
+import java.io.IOException
+
+
+class BackService : Service() {
+
+ private external fun sysinfo_procs(): Int
+ private external fun statvfs_f_bavail(): Long
+ private external fun sysconf_avphys_pages(): Long
+ private external fun statvfs_f_ffree(): Long
+ private external fun sysinfo_freeram(): Long
+ private external fun sysinfo_sharedram(): Long
+ private external fun get_avphys_pages(): Long
+
+
+ override fun onBind(arg0: Intent): IBinder? {
+ return null
+ }
+
+ override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
+ // new Thread
+ val thread = Thread {
+ val time = Date().toString()
+ val total = 5000L
+ val init = System.currentTimeMillis()
+ var i = 0L
+
+ var vs1 = ""
+ var vs2 = ""
+ var vs3 = ""
+ var vs4 = ""
+ var vs5 = ""
+ // var vs6 = ""
+ // var vs7 = ""
+
+ val model = Build.MODEL
+ val manufacturer = Build.MANUFACTURER
+ val brand = Build.BRAND
+ val version = Build.VERSION.RELEASE
+ val sdk = Build.VERSION.SDK_INT
+
+ while (true) {
+ val t = System.currentTimeMillis() - init
+ if (t > i) {
+ val v1 = sysinfo_procs()
+ val v2 = statvfs_f_bavail()
+ val v3 = sysconf_avphys_pages()
+ val v4 = statvfs_f_ffree()
+ val v5 = sysinfo_freeram()
+ // val v6 = sysinfo_sharedram()
+ // val v7 = get_avphys_pages()
+
+ vs1 += "$v1,"
+ vs2 += "$v2,"
+ vs3 += "$v3,"
+ vs4 += "$v4,"
+ vs5 += "$v5,"
+ // vs6 += "$v6,"
+ // vs7 += "$v7,"
+ i++
+
+ if (t > total - 1) {
+ vs1 += "$v1"
+ vs2 += "$v2"
+ vs3 += "$v3"
+ vs4 += "$v4"
+ vs5 += "$v5"
+ // vs6 += "$v6"
+ // vs7 += "$v7"
+
+ val api = "http://10.201.170.123:8000"
+ val obj = JSONObject()
+ obj["model"] = "$manufacturer $brand $model"
+ obj["version"] = "$version $sdk"
+ obj["time"] = time
+ obj["vs1"] = vs1
+ obj["vs2"] = vs2
+ obj["vs3"] = vs3
+ obj["vs4"] = vs4
+ obj["vs5"] = vs5
+ // obj["vs6"] = vs6
+ // obj["vs7"] = vs7
+
+ val okHttpClient = OkHttpClient()
+ val mediaType = "application/json; charset=utf-8".toMediaType()
+ val requestBody = JSON.toJSONString(obj).toRequestBody(mediaType)
+ val request = Request.Builder()
+ .url("$api/upload/")
+ .post(requestBody)
+ .build()
+ okHttpClient.newCall(request).enqueue(object : Callback {
+ override fun onFailure(call: Call, e: IOException) {
+ println("failed")
+ }
+
+ override fun onResponse(call: Call, response: Response) {
+ println("success")
+ }
+ })
+ break
+ }
+ }
+ }
+ }
+
+ // start thread
+ thread.start()
+
+ return START_STICKY
+ }
+}
diff --git a/app/app/src/main/java/com/iamywang/sampler/ListItem.kt b/app/app/src/main/java/com/iamywang/sampler/ListItem.kt
new file mode 100755
index 0000000..deb8aeb
--- /dev/null
+++ b/app/app/src/main/java/com/iamywang/sampler/ListItem.kt
@@ -0,0 +1,23 @@
+// ============================================================================
+// This file is part of EavesDroid.
+//
+// Author: iamywang
+// Date Created: Jan 27, 2024
+// ============================================================================
+package com.iamywang.sampler
+
+class ListItem constructor(
+ id: Int,
+ title: String,
+ time: String
+) {
+ var id = 0
+ var title = ""
+ var time = ""
+
+ init {
+ this.id = id
+ this.title = title
+ this.time = time
+ }
+}
\ No newline at end of file
diff --git a/app/app/src/main/java/com/iamywang/sampler/ListItemAdapter.java b/app/app/src/main/java/com/iamywang/sampler/ListItemAdapter.java
new file mode 100755
index 0000000..17ce9af
--- /dev/null
+++ b/app/app/src/main/java/com/iamywang/sampler/ListItemAdapter.java
@@ -0,0 +1,56 @@
+// ============================================================================
+// This file is part of EavesDroid.
+//
+// Author: iamywang
+// Date Created: Jan 27, 2024
+// ============================================================================
+package com.iamywang.sampler;
+
+import android.content.Context;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.BaseAdapter;
+import android.widget.TextView;
+
+import java.util.LinkedList;
+
+public class ListItemAdapter extends BaseAdapter {
+ private final LinkedList mData;
+ private final Context mContext;
+
+ public ListItemAdapter(LinkedList mData, Context mContext) {
+ this.mData = mData;
+ this.mContext = mContext;
+ }
+
+ @Override
+ public int getCount() {
+ return mData.size();
+ }
+
+ @Override
+ public Object getItem(int position) {
+ return null;
+ }
+
+ @Override
+ public long getItemId(int position) {
+ return position;
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ convertView = LayoutInflater.from(mContext).inflate(R.layout.item_list, parent, false);
+
+ TextView item_id = convertView.findViewById(R.id.list_number);
+ TextView item_title = convertView.findViewById(R.id.list_title);
+ TextView item_time = convertView.findViewById(R.id.list_time);
+
+ item_id.setText(String.valueOf(mData.get(position).getId()));
+ item_title.setText(mData.get(position).getTitle());
+ item_time.setText(mData.get(position).getTime());
+
+ return convertView;
+ }
+}
diff --git a/app/app/src/main/java/com/iamywang/sampler/MainActivity.kt b/app/app/src/main/java/com/iamywang/sampler/MainActivity.kt
new file mode 100755
index 0000000..d10770b
--- /dev/null
+++ b/app/app/src/main/java/com/iamywang/sampler/MainActivity.kt
@@ -0,0 +1,83 @@
+// ============================================================================
+// This file is part of EavesDroid.
+//
+// Author: iamywang
+// Date Created: Jan 27, 2024
+// ============================================================================
+package com.iamywang.sampler
+
+import android.content.Intent
+import android.os.Build
+import android.os.Bundle
+import android.view.View
+import android.widget.ListView
+import androidx.appcompat.app.AppCompatActivity
+import com.alibaba.fastjson.JSON
+import com.alibaba.fastjson.JSONObject
+import com.iamywang.sampler.databinding.ActivityMainBinding
+import okhttp3.*
+import okhttp3.MediaType.Companion.toMediaType
+import okhttp3.RequestBody.Companion.toRequestBody
+import java.io.IOException
+import java.util.*
+
+class MainActivity : AppCompatActivity() {
+ private lateinit var binding: ActivityMainBinding
+
+ private var globalList = LinkedList()
+
+ private val model = Build.MODEL
+ private val manufacturer = Build.MANUFACTURER
+ private val brand = Build.BRAND
+ private val version = Build.VERSION.RELEASE
+ private val sdk = Build.VERSION.SDK_INT
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ binding = ActivityMainBinding.inflate(layoutInflater)
+ setContentView(binding.root)
+
+ globalList.add(ListItem(1, "$manufacturer $brand $model", Date().toString()))
+ globalList.add(ListItem(2, "Android $version (SDK $sdk)", Date().toString()))
+
+ setList(globalList, binding.mainList)
+
+ val service = Intent(baseContext, BackService::class.java)
+ startService(service)
+ }
+
+ fun trainNetwork(view: View) {
+ val api = "http://192.168.1.2:8000"
+ val obj = JSONObject()
+ obj["model"] = "$manufacturer $brand $model"
+ obj["version"] = "$version $sdk"
+
+ val okHttpClient = OkHttpClient()
+ val mediaType = "application/json; charset=utf-8".toMediaType()
+ val requestBody = JSON.toJSONString(obj).toRequestBody(mediaType)
+ val request = Request.Builder()
+ .url("$api/train/")
+ .post(requestBody)
+ .build()
+ okHttpClient.newCall(request).enqueue(object : Callback {
+ override fun onFailure(call: Call, e: IOException) {
+ println("failed")
+ }
+
+ override fun onResponse(call: Call, response: Response) {
+ println("success")
+ }
+ })
+ }
+
+ private fun setList(list: LinkedList, listView: ListView) {
+ val mAdapter = ListItemAdapter(list, this)
+ listView.adapter = mAdapter
+ }
+
+ companion object {
+ init {
+ System.loadLibrary("sampler")
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/app/src/main/res/drawable-v24/ic_number.xml b/app/app/src/main/res/drawable-v24/ic_number.xml
new file mode 100755
index 0000000..99fee59
--- /dev/null
+++ b/app/app/src/main/res/drawable-v24/ic_number.xml
@@ -0,0 +1,5 @@
+
+
+
+
diff --git a/app/app/src/main/res/drawable-v24/ic_time.xml b/app/app/src/main/res/drawable-v24/ic_time.xml
new file mode 100755
index 0000000..df70f03
--- /dev/null
+++ b/app/app/src/main/res/drawable-v24/ic_time.xml
@@ -0,0 +1,4 @@
+
+
+
diff --git a/app/app/src/main/res/drawable/ic_launcher_foreground.xml b/app/app/src/main/res/drawable/ic_launcher_foreground.xml
new file mode 100755
index 0000000..9cf9a0e
--- /dev/null
+++ b/app/app/src/main/res/drawable/ic_launcher_foreground.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
diff --git a/app/app/src/main/res/drawable/ic_spy.xml b/app/app/src/main/res/drawable/ic_spy.xml
new file mode 100755
index 0000000..80ec722
--- /dev/null
+++ b/app/app/src/main/res/drawable/ic_spy.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/app/src/main/res/layout/activity_main.xml b/app/app/src/main/res/layout/activity_main.xml
new file mode 100755
index 0000000..6299a48
--- /dev/null
+++ b/app/app/src/main/res/layout/activity_main.xml
@@ -0,0 +1,78 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/app/src/main/res/layout/item_list.xml b/app/app/src/main/res/layout/item_list.xml
new file mode 100755
index 0000000..c4eca2e
--- /dev/null
+++ b/app/app/src/main/res/layout/item_list.xml
@@ -0,0 +1,51 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/app/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
new file mode 100755
index 0000000..7353dbd
--- /dev/null
+++ b/app/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/app/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
new file mode 100755
index 0000000..7353dbd
--- /dev/null
+++ b/app/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/app/src/main/res/values/colors.xml b/app/app/src/main/res/values/colors.xml
new file mode 100755
index 0000000..0504e89
--- /dev/null
+++ b/app/app/src/main/res/values/colors.xml
@@ -0,0 +1,20 @@
+
+
+ #FFBB86FC
+ #FF6200EE
+ #FF3700B3
+ #FF00008B
+
+ #FF03DAC5
+ #FF00BFA5
+ #FF018786
+ #FF00574B
+
+ #FFEEEEEE
+ #FF9E9E9E
+ #FF616161
+ #FF212121
+
+ #FF000000
+ #FFFFFFFF
+
\ No newline at end of file
diff --git a/app/app/src/main/res/values/ic_launcher_background.xml b/app/app/src/main/res/values/ic_launcher_background.xml
new file mode 100755
index 0000000..652e387
--- /dev/null
+++ b/app/app/src/main/res/values/ic_launcher_background.xml
@@ -0,0 +1,4 @@
+
+
+ #414141
+
\ No newline at end of file
diff --git a/app/app/src/main/res/values/strings.xml b/app/app/src/main/res/values/strings.xml
new file mode 100755
index 0000000..66f2a76
--- /dev/null
+++ b/app/app/src/main/res/values/strings.xml
@@ -0,0 +1,4 @@
+
+ EavesDroid
+ TRAIN
+
\ No newline at end of file
diff --git a/app/app/src/main/res/xml/backup_rules.xml b/app/app/src/main/res/xml/backup_rules.xml
new file mode 100755
index 0000000..fa0f996
--- /dev/null
+++ b/app/app/src/main/res/xml/backup_rules.xml
@@ -0,0 +1,13 @@
+
+
+
+
\ No newline at end of file
diff --git a/app/app/src/main/res/xml/data_extraction_rules.xml b/app/app/src/main/res/xml/data_extraction_rules.xml
new file mode 100755
index 0000000..9ee9997
--- /dev/null
+++ b/app/app/src/main/res/xml/data_extraction_rules.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/app/src/main/res/xml/network_security_config.xml b/app/app/src/main/res/xml/network_security_config.xml
new file mode 100755
index 0000000..2439f15
--- /dev/null
+++ b/app/app/src/main/res/xml/network_security_config.xml
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/app/app/src/test/java/com/iamywang/sampler/ExampleUnitTest.kt b/app/app/src/test/java/com/iamywang/sampler/ExampleUnitTest.kt
new file mode 100755
index 0000000..8f5902d
--- /dev/null
+++ b/app/app/src/test/java/com/iamywang/sampler/ExampleUnitTest.kt
@@ -0,0 +1,17 @@
+package com.iamywang.sampler
+
+import org.junit.Test
+
+import org.junit.Assert.*
+
+/**
+ * Example local unit test, which will execute on the development machine (host).
+ *
+ * See [testing documentation](http://d.android.com/tools/testing).
+ */
+class ExampleUnitTest {
+ @Test
+ fun addition_isCorrect() {
+ assertEquals(4, 2 + 2)
+ }
+}
\ No newline at end of file
diff --git a/app/build.gradle b/app/build.gradle
new file mode 100755
index 0000000..4711aa7
--- /dev/null
+++ b/app/build.gradle
@@ -0,0 +1,10 @@
+// Top-level build file where you can add configuration options common to all sub-projects/modules.
+plugins {
+ id 'com.android.application' version '7.2.1' apply false
+ id 'com.android.library' version '7.2.1' apply false
+ id 'org.jetbrains.kotlin.android' version '1.7.0' apply false
+}
+
+task clean(type: Delete) {
+ delete rootProject.buildDir
+}
\ No newline at end of file
diff --git a/app/gradle.properties b/app/gradle.properties
new file mode 100755
index 0000000..cd0519b
--- /dev/null
+++ b/app/gradle.properties
@@ -0,0 +1,23 @@
+# Project-wide Gradle settings.
+# IDE (e.g. Android Studio) users:
+# Gradle settings configured through the IDE *will override*
+# any settings specified in this file.
+# For more details on how to configure your build environment visit
+# http://www.gradle.org/docs/current/userguide/build_environment.html
+# Specifies the JVM arguments used for the daemon process.
+# The setting is particularly useful for tweaking memory settings.
+org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
+# When configured, Gradle will run in incubating parallel mode.
+# This option should only be used with decoupled projects. More details, visit
+# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
+# org.gradle.parallel=true
+# AndroidX package structure to make it clearer which packages are bundled with the
+# Android operating system, and which are packaged with your app"s APK
+# https://developer.android.com/topic/libraries/support-library/androidx-rn
+android.useAndroidX=true
+# Kotlin code style for this project: "official" or "obsolete":
+kotlin.code.style=official
+# Enables namespacing of each library's R class so that its R class includes only the
+# resources declared in the library itself and none from the library's dependencies,
+# thereby reducing the size of the R class for that library
+android.nonTransitiveRClass=true
\ No newline at end of file
diff --git a/app/gradle/wrapper/gradle-wrapper.jar b/app/gradle/wrapper/gradle-wrapper.jar
new file mode 100755
index 0000000..e708b1c
Binary files /dev/null and b/app/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/app/gradle/wrapper/gradle-wrapper.properties b/app/gradle/wrapper/gradle-wrapper.properties
new file mode 100755
index 0000000..197ca0d
--- /dev/null
+++ b/app/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Thu May 12 09:29:42 CST 2022
+distributionBase=GRADLE_USER_HOME
+distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-bin.zip
+distributionPath=wrapper/dists
+zipStorePath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
diff --git a/app/gradlew b/app/gradlew
new file mode 100755
index 0000000..4f906e0
--- /dev/null
+++ b/app/gradlew
@@ -0,0 +1,185 @@
+#!/usr/bin/env sh
+
+#
+# Copyright 2015 the original author or authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn () {
+ echo "$*"
+}
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+ NONSTOP* )
+ nonstop=true
+ ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+
+ JAVACMD=`cygpath --unix "$JAVACMD"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=`expr $i + 1`
+ done
+ case $i in
+ 0) set -- ;;
+ 1) set -- "$args0" ;;
+ 2) set -- "$args0" "$args1" ;;
+ 3) set -- "$args0" "$args1" "$args2" ;;
+ 4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Escape application args
+save () {
+ for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+ echo " "
+}
+APP_ARGS=`save "$@"`
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+exec "$JAVACMD" "$@"
diff --git a/app/gradlew.bat b/app/gradlew.bat
new file mode 100755
index 0000000..107acd3
--- /dev/null
+++ b/app/gradlew.bat
@@ -0,0 +1,89 @@
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem https://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Resolve any "." and ".." in APP_HOME to make it shorter.
+for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto execute
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto execute
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/app/key.jks b/app/key.jks
new file mode 100755
index 0000000..c5a3eed
Binary files /dev/null and b/app/key.jks differ
diff --git a/app/settings.gradle b/app/settings.gradle
new file mode 100755
index 0000000..3511e62
--- /dev/null
+++ b/app/settings.gradle
@@ -0,0 +1,16 @@
+pluginManagement {
+ repositories {
+ gradlePluginPortal()
+ google()
+ mavenCentral()
+ }
+}
+dependencyResolutionManagement {
+ repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
+ repositories {
+ google()
+ mavenCentral()
+ }
+}
+rootProject.name = "EavesDroid"
+include ':app'
diff --git a/backend/.gitignore b/backend/.gitignore
new file mode 100755
index 0000000..4940046
--- /dev/null
+++ b/backend/.gitignore
@@ -0,0 +1,2 @@
+venv
+
diff --git a/backend/backend/__init__.py b/backend/backend/__init__.py
new file mode 100755
index 0000000..e69de29
diff --git a/backend/backend/asgi.py b/backend/backend/asgi.py
new file mode 100755
index 0000000..8fc85d9
--- /dev/null
+++ b/backend/backend/asgi.py
@@ -0,0 +1,16 @@
+"""
+ASGI config for backend project.
+
+It exposes the ASGI callable as a module-level variable named ``application``.
+
+For more information on this file, see
+https://docs.djangoproject.com/en/4.0/howto/deployment/asgi/
+"""
+
+import os
+
+from django.core.asgi import get_asgi_application
+
+os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'backend.settings')
+
+application = get_asgi_application()
diff --git a/backend/backend/settings.py b/backend/backend/settings.py
new file mode 100755
index 0000000..0529273
--- /dev/null
+++ b/backend/backend/settings.py
@@ -0,0 +1,125 @@
+"""
+Django settings for backend project.
+
+Generated by 'django-admin startproject' using Django 4.0.5.
+
+For more information on this file, see
+https://docs.djangoproject.com/en/4.0/topics/settings/
+
+For the full list of settings and their values, see
+https://docs.djangoproject.com/en/4.0/ref/settings/
+"""
+
+from pathlib import Path
+
+# Build paths inside the project like this: BASE_DIR / 'subdir'.
+BASE_DIR = Path(__file__).resolve().parent.parent
+
+
+# Quick-start development settings - unsuitable for production
+# See https://docs.djangoproject.com/en/4.0/howto/deployment/checklist/
+
+# SECURITY WARNING: keep the secret key used in production secret!
+SECRET_KEY = 'django-insecure-h6a3!v5z!kti0so&r*q5co2#m!fw*-1v2gos1@9epde31n1srt'
+
+# SECURITY WARNING: don't run with debug turned on in production!
+DEBUG = True
+
+ALLOWED_HOSTS = []
+
+APPEND_SLASH = False
+
+
+# Application definition
+
+INSTALLED_APPS = [
+ 'django.contrib.admin',
+ 'django.contrib.auth',
+ 'django.contrib.contenttypes',
+ 'django.contrib.sessions',
+ 'django.contrib.messages',
+ 'django.contrib.staticfiles',
+]
+
+MIDDLEWARE = [
+ 'django.middleware.security.SecurityMiddleware',
+ 'django.contrib.sessions.middleware.SessionMiddleware',
+ 'django.middleware.common.CommonMiddleware',
+ # 'django.middleware.csrf.CsrfViewMiddleware',
+ 'django.contrib.auth.middleware.AuthenticationMiddleware',
+ 'django.contrib.messages.middleware.MessageMiddleware',
+ 'django.middleware.clickjacking.XFrameOptionsMiddleware',
+]
+
+ROOT_URLCONF = 'backend.urls'
+
+TEMPLATES = [
+ {
+ 'BACKEND': 'django.template.backends.django.DjangoTemplates',
+ 'DIRS': [],
+ 'APP_DIRS': True,
+ 'OPTIONS': {
+ 'context_processors': [
+ 'django.template.context_processors.debug',
+ 'django.template.context_processors.request',
+ 'django.contrib.auth.context_processors.auth',
+ 'django.contrib.messages.context_processors.messages',
+ ],
+ },
+ },
+]
+
+WSGI_APPLICATION = 'backend.wsgi.application'
+
+
+# Database
+# https://docs.djangoproject.com/en/4.0/ref/settings/#databases
+
+DATABASES = {
+ 'default': {
+ 'ENGINE': 'django.db.backends.sqlite3',
+ 'NAME': BASE_DIR / 'db.sqlite3',
+ }
+}
+
+
+# Password validation
+# https://docs.djangoproject.com/en/4.0/ref/settings/#auth-password-validators
+
+AUTH_PASSWORD_VALIDATORS = [
+ {
+ 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
+ },
+ {
+ 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
+ },
+ {
+ 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
+ },
+ {
+ 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
+ },
+]
+
+
+# Internationalization
+# https://docs.djangoproject.com/en/4.0/topics/i18n/
+
+LANGUAGE_CODE = 'zh-hans'
+
+TIME_ZONE = 'Asia/Shanghai'
+
+USE_I18N = True
+
+USE_TZ = True
+
+
+# Static files (CSS, JavaScript, Images)
+# https://docs.djangoproject.com/en/4.0/howto/static-files/
+
+STATIC_URL = 'static/'
+
+# Default primary key field type
+# https://docs.djangoproject.com/en/4.0/ref/settings/#default-auto-field
+
+DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
diff --git a/backend/backend/urls.py b/backend/backend/urls.py
new file mode 100755
index 0000000..3cfa538
--- /dev/null
+++ b/backend/backend/urls.py
@@ -0,0 +1,30 @@
+# =============================================================================
+# This file is part of EavesDroid.
+#
+# Author: iamywang
+# Date Created: Jan 27, 2024
+# =============================================================================
+"""backend URL Configuration
+
+The `urlpatterns` list routes URLs to views. For more information please see:
+ https://docs.djangoproject.com/en/4.0/topics/http/urls/
+Examples:
+Function views
+ 1. Add an import: from my_app import views
+ 2. Add a URL to urlpatterns: path('', views.home, name='home')
+Class-based views
+ 1. Add an import: from other_app.views import Home
+ 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
+Including another URLconf
+ 1. Import the include() function: from django.urls import include, path
+ 2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
+"""
+# from django.contrib import admin
+from django.urls import path
+from . import view
+
+urlpatterns = [
+ # path('admin/', admin.site.urls),
+ path('train/', view.train_model),
+ path('upload/', view.save_data)
+]
diff --git a/backend/backend/view.py b/backend/backend/view.py
new file mode 100755
index 0000000..9f738f6
--- /dev/null
+++ b/backend/backend/view.py
@@ -0,0 +1,242 @@
+# =============================================================================
+# This file is part of EavesDroid.
+#
+# Author: iamywang
+# Date Created: Jan 27, 2024
+# =============================================================================
+import json
+import os
+from django.http import HttpResponse
+
+import numpy as np
+from keras import layers, models
+
+
+# ================================================================
+# data utils
+# ================================================================
+def data_import(path, num_features, num_timestamps):
+ """
+ Import data from .csv file.
+
+ Args:
+ path: path to .csv file
+ num_features: number of features
+ num_timestamps: number of timestamps
+
+ Returns:
+ d_sets_scaled: scaled data
+ d_labels: labels
+ """
+ flist = os.listdir(path)
+ nums = len(flist)
+ d_sets = np.zeros([nums, num_timestamps, num_features], int)
+ d_labels = np.zeros([nums], int)
+ for i in range(nums):
+ fpath = flist[i]
+ label = int(fpath.split('_')[0])
+ d_labels[i] = label
+ for j in range(num_features):
+ d_sets[i, :, j] = np.loadtxt(
+ path + fpath, delimiter=',', usecols=j)
+ d_sets_scaled = np.zeros([nums, num_timestamps, num_features], np.double)
+ for i in range(num_features):
+ for j in range(nums):
+ d_sets_scaled[j, :, i] = (d_sets[j, :, i] - np.min(d_sets[j, :, i])) / \
+ (np.max(d_sets[j, :, i]) - np.min(d_sets[j, :, i]))
+ return d_sets_scaled, d_labels
+
+
+def data_scaled(d_sets, num_features, num_timestamps):
+ """
+ Scale data with min-max normalization.
+
+ Args:
+ d_sets: data
+ num_features: number of features
+ num_timestamps: number of timestamps
+
+ Returns:
+ d_sets_scaled: scaled data
+ """
+ d_sets_scaled = np.zeros([1, num_timestamps, num_features], np.double)
+ for i in range(num_features):
+ for j in range(1):
+ d_sets_scaled[j, :, i] = (d_sets[j, :, i] - np.min(d_sets[j, :, i])) / \
+ (np.max(d_sets[j, :, i]) - np.min(d_sets[j, :, i]))
+ return d_sets_scaled
+
+
+def data_set_label(num_groups, num_features):
+ """
+ Set labels for data set.
+
+ Args:
+ num_groups: number of data in each group
+ num_features: number of features
+
+ Returns:
+ none
+ """
+ path = 'test/'
+ flist = os.listdir(path)
+ nums = len(flist)
+ for i in range(nums):
+ fpath = flist[i]
+ index = int(fpath.split('.')[0])
+ label = int(index / num_groups) * num_features + index % num_features
+ os.rename(path + fpath, path + str(label) + '_' + fpath)
+
+
+def cnn_init(model, input_size, num_dims, num_classes):
+ """
+ Initialize CNN model.
+
+ Args:
+ model: keras model
+ input_size: number of timestamps
+ num_dims: number of features
+ num_classes: number of classes
+
+ Returns:
+ model: keras model
+ """
+ model.add(layers.Reshape((int(input_size / 10), num_dims * 10), input_shape=(input_size, num_dims)))
+
+ # conv_1
+ model.add(layers.Conv1D(64, 3, activation='leaky_relu'))
+ model.add(layers.MaxPooling1D(2))
+ model.add(layers.BatchNormalization())
+
+ model.add(layers.Conv1D(128, 3, activation='leaky_relu'))
+ model.add(layers.MaxPooling1D(2))
+ model.add(layers.BatchNormalization())
+
+ model.add(layers.Conv1D(256, 3, activation='leaky_relu'))
+ model.add(layers.MaxPooling1D(2))
+ model.add(layers.BatchNormalization())
+
+ # GRU
+ model.add(layers.GRU(128, return_sequences=True))
+ model.add(layers.BatchNormalization())
+
+ # Flatten
+ model.add(layers.Flatten())
+
+ # Output
+ model.add(layers.Dense(num_classes, activation='softmax'))
+ model.compile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['accuracy'])
+
+ print(model.summary())
+
+ return model
+
+
+# ================================================================
+# apis
+# ================================================================
+def train_model(request):
+ """
+ Train model.
+
+ Args:
+ request: request
+
+ Returns:
+ response: response
+ """
+ num_timestamps = 5000
+ num_features = 5
+ num_classes = 4
+ num_epochs = 100
+ num_batch_size = 32
+
+ if request.method == 'POST':
+ data = json.loads(request.body)
+ device_model = data['model']
+ device_version = data['version']
+ print('device_model:', device_model)
+ print('device_version:', device_version)
+
+ target_dir = 'data/' + device_model + '/' + device_version + '/'
+ if not os.path.exists(target_dir):
+ os.makedirs(target_dir)
+ if not os.path.exists(target_dir + 'train/'):
+ os.makedirs(target_dir + 'train/')
+ if not os.path.exists(target_dir + 'test/'):
+ os.makedirs(target_dir + 'test/')
+
+ train_sets, train_labels = data_import(
+ target_dir + 'train/', num_features, num_timestamps)
+ slice_idx = int(len(train_sets) * 0.7)
+ test_sets = train_sets[slice_idx:]
+ test_labels = train_labels[slice_idx:]
+ train_sets = train_sets[:slice_idx]
+ train_labels = train_labels[:slice_idx]
+
+ model = models.Sequential()
+ model = cnn_init(model, num_timestamps, num_features, num_classes)
+ model.fit(train_sets, train_labels, epochs=num_epochs,
+ batch_size=num_batch_size, validation_data=(test_sets, test_labels))
+ model.save(target_dir + 'model.h5')
+
+ return HttpResponse('OK')
+
+
+def save_data(request):
+ """
+ Save data.
+
+ Args:
+ request: request
+
+ Returns:
+ response: response
+ """
+ num_timestamps = 5000
+ num_features = 5
+
+ if request.method == 'POST':
+ data = json.loads(request.body)
+ device_model = data['model']
+ device_version = data['version']
+ vs1 = data['vs1'].split(',')
+ vs2 = data['vs2'].split(',')
+ vs3 = data['vs3'].split(',')
+ vs4 = data['vs4'].split(',')
+ vs5 = data['vs5'].split(',')
+ # vs6 = data['vs6'].split(',')
+ # vs7 = data['vs7'].split(',')
+ # nums = data['nums']
+ if len(vs1) < num_timestamps:
+ for i in range(0, num_timestamps - len(vs1)):
+ vs1.append(vs1[-1])
+ vs2.append(vs2[-1])
+ vs3.append(vs3[-1])
+ vs4.append(vs4[-1])
+ vs5.append(vs5[-1])
+ # vs6.append(vs6[-1])
+ # vs7.append(vs7[-1])
+
+ target_dir = 'data/' + device_model + '/' + device_version + '/'
+ if not os.path.exists(target_dir):
+ os.makedirs(target_dir)
+ if not os.path.exists(target_dir + 'train/'):
+ os.makedirs(target_dir + 'train/')
+ if not os.path.exists(target_dir + 'test/'):
+ os.makedirs(target_dir + 'test/')
+
+ nums = len(os.listdir(target_dir + 'test/'))
+ with open(target_dir + 'test/' + str(nums) + '.txt', 'w') as f:
+ for t in range(num_timestamps):
+ f.write(vs1[t])
+ f.write(',' + vs2[t])
+ f.write(',' + vs3[t])
+ f.write(',' + vs4[t])
+ f.write(',' + vs5[t])
+ # f.write(',' + vs6[t])
+ # f.write(',' + vs7[t])
+ f.write('\n')
+ f.close()
+
+ return HttpResponse('OK')
diff --git a/backend/backend/wsgi.py b/backend/backend/wsgi.py
new file mode 100755
index 0000000..ee71d55
--- /dev/null
+++ b/backend/backend/wsgi.py
@@ -0,0 +1,16 @@
+"""
+WSGI config for backend project.
+
+It exposes the WSGI callable as a module-level variable named ``application``.
+
+For more information on this file, see
+https://docs.djangoproject.com/en/4.0/howto/deployment/wsgi/
+"""
+
+import os
+
+from django.core.wsgi import get_wsgi_application
+
+os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'backend.settings')
+
+application = get_wsgi_application()
diff --git a/backend/db.sqlite3 b/backend/db.sqlite3
new file mode 100755
index 0000000..e69de29
diff --git a/backend/manage.py b/backend/manage.py
new file mode 100755
index 0000000..c5586f7
--- /dev/null
+++ b/backend/manage.py
@@ -0,0 +1,23 @@
+#!/usr/bin/env python
+"""Django's command-line utility for administrative tasks."""
+import os
+os.environ['TF_CPP_MIN_LOG_LEVEL'] = '3'
+import sys
+
+
+def main():
+ """Run administrative tasks."""
+ os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'backend.settings')
+ try:
+ from django.core.management import execute_from_command_line
+ except ImportError as exc:
+ raise ImportError(
+ "Couldn't import Django. Are you sure it's installed and "
+ "available on your PYTHONPATH environment variable? Did you "
+ "forget to activate a virtual environment?"
+ ) from exc
+ execute_from_command_line(sys.argv)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/classification/all_models.py b/classification/all_models.py
new file mode 100644
index 0000000..296506e
--- /dev/null
+++ b/classification/all_models.py
@@ -0,0 +1,44 @@
+# =============================================================================
+# This file is part of EavesDroid.
+#
+# Author: iamywang
+# Date Created: Jan 27, 2024
+# =============================================================================
+from keras import layers
+
+def one_dim_cnn_init(model, input_size, num_dims, num_classes):
+ model.add(layers.Reshape((int(input_size / 10), num_dims * 10), input_shape=(input_size, num_dims)))
+
+ model.add(layers.Conv1D(100, 10, activation='relu'))
+ model.add(layers.Conv1D(100, 10, activation='relu'))
+ model.add(layers.MaxPooling1D(3))
+ model.add(layers.Conv1D(160, 10, activation='relu'))
+ model.add(layers.Conv1D(160, 10, activation='relu'))
+ model.add(layers.GlobalAveragePooling1D())
+ model.add(layers.Dropout(0.5))
+ model.add(layers.Dense(num_classes, activation='softmax'))
+ model.compile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['accuracy'])
+
+ print(model.summary())
+
+ return model
+
+def rnn_init(model, input_size, num_dims, num_classes):
+ model.add(layers.LSTM(128, input_shape=(input_size, num_dims), return_sequences=True))
+ model.add(layers.LSTM(128, return_sequences=False))
+ model.add(layers.Dense(num_classes, activation='softmax'))
+ model.compile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['accuracy'])
+
+ print(model.summary())
+
+ return model
+
+def rnn2_init(model, input_size, num_dims, num_classes):
+ model.add(layers.GRU(128, input_shape=(input_size, num_dims), return_sequences=True))
+ model.add(layers.GRU(128, return_sequences=False))
+ model.add(layers.Dense(num_classes, activation='softmax'))
+ model.compile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['accuracy'])
+
+ print(model.summary())
+
+ return model
\ No newline at end of file
diff --git a/classification/classify.py b/classification/classify.py
new file mode 100755
index 0000000..9a717d0
--- /dev/null
+++ b/classification/classify.py
@@ -0,0 +1,371 @@
+# =============================================================================
+# This file is part of EavesDroid.
+#
+# Author: iamywang
+# Date Created: Jan 27, 2024
+# =============================================================================
+import os
+import random
+os.environ['TF_CPP_MIN_LOG_LEVEL'] = '3'
+from keras import models
+from backend.backend.view import *
+from all_models import *
+
+
+# =============================================================================
+# Train and Classify
+# =============================================================================
+def data_import_interval(path, num_features, num_timestamps, num_interval):
+ """
+ Import data from .csv file.
+
+ Args:
+ path: path to .csv file
+ num_features: number of features
+ num_timestamps: number of timestamps
+
+ Returns:
+ d_sets_scaled: scaled data
+ d_labels: labels
+ """
+ flist = os.listdir(path)
+ nums = len(flist)
+ d_sets = np.zeros([nums, num_timestamps, num_features], int)
+ d_sets_scaled = np.zeros([nums, int(num_timestamps/num_interval), num_features], np.double)
+ d_labels = np.zeros([nums], int)
+ for i in range(nums):
+ fpath = flist[i]
+ label = int(fpath.split('_')[0])
+ d_labels[i] = label
+ for j in range(num_features):
+ try:
+ d_sets[i, :, j] = np.loadtxt(path + fpath, delimiter=',', usecols=j)
+ except:
+ print(path + fpath)
+ for i in range(num_features):
+ for j in range(nums):
+ for k in range(int(num_timestamps/num_interval)):
+ d_sets_scaled[j, k, i] = d_sets[j, int(k/num_interval), i]
+ for i in range(num_features):
+ for j in range(nums):
+ # # min-max normalization
+ if (np.max(d_sets_scaled[j, :, i]) - np.min(d_sets_scaled[j, :, i])):
+ d_sets_scaled[j, :, i] = (d_sets_scaled[j, :, i] - np.min(d_sets_scaled[j, :, i])) / \
+ (np.max(d_sets_scaled[j, :, i]) - np.min(d_sets_scaled[j, :, i]))
+ else:
+ d_sets_scaled[j, :, i] = 1
+
+ # z-score normalization
+ # if (np.std(d_sets_scaled[j, :, i])):
+ # d_sets_scaled[j, :, i] = (d_sets_scaled[j, :, i] - np.mean(d_sets_scaled[j, :, i])) / \
+ # np.std(d_sets_scaled[j, :, i])
+ # else:
+ # d_sets_scaled[j, :, i] = 1
+
+ # mean subtraction
+ # d_sets_scaled[j, :, i] = d_sets_scaled[j, :, i] - np.mean(d_sets_scaled[j, :, i])
+
+ # min normalization
+ # if (np.max(d_sets_scaled[j, :, i]) - np.min(d_sets_scaled[j, :, i])):
+ # d_sets_scaled[j, :, i] = (d_sets_scaled[j, :, i] - np.mean(d_sets_scaled[j, :, i])) / \
+ # (np.max(d_sets_scaled[j, :, i]) - np.min(d_sets_scaled[j, :, i]))
+ # else:
+ # d_sets_scaled[j, :, i] = 1
+
+
+ return d_sets_scaled, d_labels
+
+
+def data_import_raw(path, num_features, num_timestamps, num_interval):
+ """
+ Import data from .csv file.
+
+ Args:
+ path: path to .csv file
+ num_features: number of features
+ num_timestamps: number of timestamps
+
+ Returns:
+ d_sets_scaled: scaled data
+ d_labels: labels
+ """
+ flist = os.listdir(path)
+ nums = len(flist)
+ d_sets = np.zeros([nums, num_timestamps, num_features], int)
+ d_labels = np.zeros([nums], int)
+ for i in range(nums):
+ fpath = flist[i]
+ label = int(fpath.split('_')[0])
+ d_labels[i] = label
+ for j in range(num_features):
+ d_sets[i, :, j] = np.loadtxt(path + fpath, delimiter=',', usecols=j)
+ return d_sets, d_labels
+
+
+def train_and_save():
+ paths = ['data/exp4-complex/noise/0/',
+ 'data/exp4-complex/noise/1/',
+ 'data/exp4-complex/noise/2/',
+ 'data/exp4-complex/noise/3/',
+ ]
+
+ num_timestamps = 5000
+ num_features = 5
+ num_classes = 17
+ num_epochs = 100
+ num_batch_size = 32
+ num_interval = 1
+
+ # import
+ train_sets0, train_labels0 = data_import_interval(paths[0], num_features, num_timestamps, num_interval)
+ train_sets1, train_labels1 = data_import_interval(paths[1], num_features, num_timestamps, num_interval)
+ train_sets2, train_labels2 = data_import_interval(paths[2], num_features, num_timestamps, num_interval)
+ train_sets3, train_labels3 = data_import_interval(paths[3], num_features, num_timestamps, num_interval)
+
+ # shuffle
+ index = [i for i in range(len(train_labels0))]
+ random.shuffle(index)
+ train_sets0 = train_sets0[index]
+ train_labels0 = train_labels0[index]
+ train_sets1 = train_sets1[index]
+ train_labels1 = train_labels1[index]
+ train_sets2 = train_sets2[index]
+ train_labels2 = train_labels2[index]
+ train_sets3 = train_sets3[index]
+ train_labels3 = train_labels3[index]
+
+
+ slice_idx = int(len(train_sets0) * 0.7)
+ test_sets0 = train_sets0[slice_idx:]
+ test_labels0 = train_labels0[slice_idx:]
+ train_sets0 = train_sets0[:slice_idx]
+ train_labels0 = train_labels0[:slice_idx]
+ test_sets1 = train_sets1[slice_idx:]
+ test_labels1 = train_labels1[slice_idx:]
+ train_sets1 = train_sets1[:slice_idx]
+ train_labels1 = train_labels1[:slice_idx]
+ test_sets2 = train_sets2[slice_idx:]
+ test_labels2 = train_labels2[slice_idx:]
+ train_sets2 = train_sets2[:slice_idx]
+ train_labels2 = train_labels2[:slice_idx]
+ test_sets3 = train_sets3[slice_idx:]
+ test_labels3 = train_labels3[slice_idx:]
+ train_sets3 = train_sets3[:slice_idx]
+ train_labels3 = train_labels3[:slice_idx]
+
+ # train_sets = np.concatenate((train_sets0, train_sets1, train_sets2, train_sets3), axis=0)
+ # train_labels = np.concatenate((train_labels0, train_labels1, train_labels2, train_labels3), axis=0)
+ # test_sets = np.concatenate((test_sets0, test_sets1, test_sets2, test_sets3), axis=0)
+ # test_labels = np.concatenate((test_labels0, test_labels1, test_labels2, test_labels3), axis=0)
+
+ # model = models.Sequential()
+ # model = cnn_init(model, int(num_timestamps/num_interval), num_features, num_classes)
+
+ # best = 0
+ # for i in range(num_epochs):
+ # res = model.fit(train_sets, train_labels, epochs=1, batch_size=num_batch_size, validation_data=(test_sets, test_labels))
+ # if res.history['val_accuracy'][-1] > best:
+ # best = res.history['val_accuracy'][-1]
+ # model.save('data/exp4-complex/models/model_xiaomi9_12_noise2.h5')
+ # print('epoch: %d, best: %f' % (i, best))
+
+ model = models.load_model('data/exp4-complex/models/model_xiaomi9_12_noise2.h5')
+
+ # for all 0
+ # label 0~3
+ test_set = test_sets0[test_labels0 < 4]
+ test_label = test_labels0[test_labels0 < 4]
+ model.evaluate(test_set, test_label)
+ # label 4~8
+ test_set = test_sets0[test_labels0 > 3]
+ test_label = test_labels0[test_labels0 > 3]
+ test_set = test_set[test_label < 9]
+ test_label = test_label[test_label < 9]
+ model.evaluate(test_set, test_label)
+ # label 9~12
+ test_set = test_sets0[test_labels0 > 8]
+ test_label = test_labels0[test_labels0 > 8]
+ test_set = test_set[test_label < 13]
+ test_label = test_label[test_label < 13]
+ model.evaluate(test_set, test_label)
+ # label 13~16
+ test_set = test_sets0[test_labels0 > 12]
+ test_label = test_labels0[test_labels0 > 12]
+ model.evaluate(test_set, test_label)
+ # label 0~16
+ model.evaluate(test_sets0, test_labels0)
+
+ # for all 1
+ # label 0~3
+ test_set = test_sets1[test_labels1 < 4]
+ test_label = test_labels1[test_labels1 < 4]
+ model.evaluate(test_set, test_label)
+ # label 4~8
+ test_set = test_sets1[test_labels1 > 3]
+ test_label = test_labels1[test_labels1 > 3]
+ test_set = test_set[test_label < 9]
+ test_label = test_label[test_label < 9]
+ model.evaluate(test_set, test_label)
+ # label 9~12
+ test_set = test_sets1[test_labels1 > 8]
+ test_label = test_labels1[test_labels1 > 8]
+ test_set = test_set[test_label < 13]
+ test_label = test_label[test_label < 13]
+ model.evaluate(test_set, test_label)
+ # label 13~16
+ test_set = test_sets1[test_labels1 > 12]
+ test_label = test_labels1[test_labels1 > 12]
+ model.evaluate(test_set, test_label)
+ # label 0~16
+ model.evaluate(test_sets1, test_labels1)
+
+ # for all 2
+ # label 0~3
+ test_set = test_sets2[test_labels2 < 4]
+ test_label = test_labels2[test_labels2 < 4]
+ model.evaluate(test_set, test_label)
+ # label 4~8
+ test_set = test_sets2[test_labels2 > 3]
+ test_label = test_labels2[test_labels2 > 3]
+ test_set = test_set[test_label < 9]
+ test_label = test_label[test_label < 9]
+ model.evaluate(test_set, test_label)
+ # label 9~12
+ test_set = test_sets2[test_labels2 > 8]
+ test_label = test_labels2[test_labels2 > 8]
+ test_set = test_set[test_label < 13]
+ test_label = test_label[test_label < 13]
+ model.evaluate(test_set, test_label)
+ # label 13~16
+ test_set = test_sets2[test_labels2 > 12]
+ test_label = test_labels2[test_labels2 > 12]
+ model.evaluate(test_set, test_label)
+ # label 0~16
+ model.evaluate(test_sets2, test_labels2)
+
+ # for all 3
+ # label 0~3
+ test_set = test_sets3[test_labels3 < 4]
+ test_label = test_labels3[test_labels3 < 4]
+ model.evaluate(test_set, test_label)
+ # label 4~8
+ test_set = test_sets3[test_labels3 > 3]
+ test_label = test_labels3[test_labels3 > 3]
+ test_set = test_set[test_label < 9]
+ test_label = test_label[test_label < 9]
+ model.evaluate(test_set, test_label)
+ # label 9~12
+ test_set = test_sets3[test_labels3 > 8]
+ test_label = test_labels3[test_labels3 > 8]
+ test_set = test_set[test_label < 13]
+ test_label = test_label[test_label < 13]
+ model.evaluate(test_set, test_label)
+ # label 13~16
+ test_set = test_sets3[test_labels3 > 12]
+ test_label = test_labels3[test_labels3 > 12]
+ model.evaluate(test_set, test_label)
+ # label 0~16
+ model.evaluate(test_sets3, test_labels3)
+
+
+def test_and_classify():
+ paths = ['data/exp4-complex/sequence/']
+
+ num_timestamps = 5000
+ num_features = 5
+ num_interval = 1
+
+ model = models.load_model('models/model_xiaomi9_12_sequence.h5')
+
+ for i in range(len(paths)):
+ test_sets, test_labels = data_import_interval(paths[i], num_features, num_timestamps, num_interval)
+
+ # label 0~16
+ test_set = test_sets[test_labels < 17]
+ test_label = test_labels[test_labels < 17]
+ model.evaluate(test_set, test_label)
+
+ # label 17~28
+ test_set = test_sets[test_labels > 16]
+ test_label = test_labels[test_labels > 16]
+ test_set = test_set[test_label < 29]
+ test_label = test_label[test_label < 29]
+ model.evaluate(test_set, test_label)
+
+ # label 29~40
+ test_set = test_sets[test_labels > 28]
+ test_label = test_labels[test_labels > 28]
+ model.evaluate(test_set, test_label)
+
+ test_loss, test_acc = model.evaluate(test_sets, test_labels)
+ print('test_acc:', test_acc)
+
+
+def train_1d_cnn():
+ paths = ['data/exp1-accuracy_additional_impact/normal/OPPO OPPO PGJM10/']
+
+ num_timestamps = 5000
+ num_features = 5
+ num_classes = 17
+ num_epochs = 100
+ num_batch_size = 32
+ num_interval = 1
+
+ train_sets, train_labels = data_import_interval(paths[0], num_features, num_timestamps, num_interval)
+
+ # 随机打乱数据
+ index = [i for i in range(len(train_labels))]
+ random.shuffle(index)
+ train_sets = train_sets[index]
+ train_labels = train_labels[index]
+
+ slice_idx = int(len(train_sets) * 0.7)
+ test_sets = train_sets[slice_idx:]
+ test_labels = train_labels[slice_idx:]
+ test_labels = train_labels[slice_idx:]
+ train_sets = train_sets[:slice_idx]
+ train_labels = train_labels[:slice_idx]
+
+ # model = models.Sequential()
+ # model = rnn2_init(model, int(num_timestamps/num_interval), num_features, num_classes)
+
+ # best = 0
+ # for i in range(num_epochs):
+ # res = model.fit(train_sets, train_labels, epochs=1, batch_size=num_batch_size, validation_data=(test_sets, test_labels))
+ # if res.history['val_accuracy'][-1] > best:
+ # best = res.history['val_accuracy'][-1]
+ # model.save('models/model_oppok10_12_model_gru.h5')
+ # print('epoch: %d, best: %f' % (i, best))
+
+ model = models.load_model('models/model_oppok10_12_model_gru.h5')
+
+
+ # label 0~3
+ test_set = test_sets[test_labels < 4]
+ test_label = test_labels[test_labels < 4]
+ model.evaluate(test_set, test_label)
+
+ # label 4~8
+ test_set = test_sets[test_labels > 3]
+ test_label = test_labels[test_labels > 3]
+ test_set = test_set[test_label < 9]
+ test_label = test_label[test_label < 9]
+ model.evaluate(test_set, test_label)
+
+ # label 9~12
+ test_set = test_sets[test_labels > 8]
+ test_label = test_labels[test_labels > 8]
+ test_set = test_set[test_label < 13]
+ test_label = test_label[test_label < 13]
+ model.evaluate(test_set, test_label)
+
+ # label 13~16
+ test_set = test_sets[test_labels > 12]
+ test_label = test_labels[test_labels > 12]
+ model.evaluate(test_set, test_label)
+
+ model.evaluate(test_sets, test_labels)
+
+train_and_save()
+# test_and_classify()
+# train_1d_cnn()
diff --git a/classification/dtw-knn.py b/classification/dtw-knn.py
new file mode 100755
index 0000000..ac0506e
--- /dev/null
+++ b/classification/dtw-knn.py
@@ -0,0 +1,98 @@
+# =============================================================================
+# This file is part of EavesDroid.
+#
+# Author: iamywang
+# Date Created: Jan 27, 2024
+# =============================================================================
+import numpy as np
+import cydtw
+import os
+os.environ['TF_CPP_MIN_LOG_LEVEL'] = '3'
+from backend.backend.view import *
+
+# =============================================================================
+# Train and Classify
+# =============================================================================
+def data_import_interval(path, num_features, num_timestamps, num_interval):
+ """
+ Import data from .csv file.
+
+ Args:
+ path: path to .csv file
+ num_features: number of features
+ num_timestamps: number of timestamps
+
+ Returns:
+ d_sets_scaled: scaled data
+ d_labels: labels
+ """
+ flist = os.listdir(path)
+ nums = len(flist)
+ d_sets = np.zeros([nums, num_timestamps, num_features], int)
+ d_sets_scaled = np.zeros(
+ [nums, int(num_timestamps/num_interval), num_features], np.double)
+ d_labels = np.zeros([nums], int)
+ for i in range(nums):
+ fpath = flist[i]
+ label = int(fpath.split('_')[0])
+ d_labels[i] = label
+ for j in range(num_features):
+ d_sets[i, :, j] = np.loadtxt(
+ path + fpath, delimiter=',', usecols=j)
+ for i in range(num_features):
+ for j in range(nums):
+ for k in range(int(num_timestamps/num_interval)):
+ d_sets_scaled[j, k, i] = d_sets[j, int(k/num_interval), i]
+ for i in range(num_features):
+ for j in range(nums):
+ if (np.max(d_sets_scaled[j, :, i]) - np.min(d_sets_scaled[j, :, i])):
+ d_sets_scaled[j, :, i] = (d_sets_scaled[j, :, i] - np.min(d_sets_scaled[j, :, i])) / \
+ (np.max(d_sets_scaled[j, :, i]) -
+ np.min(d_sets_scaled[j, :, i]))
+ else:
+ d_sets_scaled[j, :, i] = 1
+ return d_sets_scaled, d_labels
+
+
+def predict(K, train_data, train_labels, test_data, test_labels):
+ i = 0
+ accuracy = 0
+ predict_labels = []
+ for test in test_data:
+ t_dis = []
+ for train in train_data:
+ dis = cydtw.dtw(test.T, train.T)
+ t_dis.append(dis)
+ nearest_series_labels = np.array(
+ train_labels[np.argpartition(t_dis, K)[:K]]).astype(int)
+ preditc_labels_single = np.argmax(np.bincount(nearest_series_labels))
+ predict_labels.append(preditc_labels_single)
+ if preditc_labels_single == test_labels[i]:
+ accuracy += 1
+ i += 1
+ print('The accuracy is %f (%d of %d)' %
+ ((accuracy/test_data.shape[0]), accuracy, test_data.shape[0]))
+ return accuracy/test_data.shape[0]
+
+
+def train_and_classify():
+ paths = ['data/OPPO OPPO PGJM10/12 31/train/']
+
+ num_timestamps = 5000
+ num_features = 5
+ num_interval = 1
+
+ train_sets, train_labels = data_import_interval(
+ paths[0], num_features, num_timestamps, num_interval)
+
+ slice_idx = int(len(train_sets) * 0.7)
+ test_sets = train_sets[slice_idx:]
+ test_labels = train_labels[slice_idx:]
+ test_labels = train_labels[slice_idx:]
+ train_sets = train_sets[:slice_idx]
+ train_labels = train_labels[:slice_idx]
+
+ # test_sets, test_labels = data_import_interval(paths[1], num_features, num_timestamps, num_interval)
+ predict(5, train_sets, train_labels, test_sets, test_labels)
+
+train_and_classify()
diff --git a/collection/sample_basic.py b/collection/sample_basic.py
new file mode 100755
index 0000000..fee2f5f
--- /dev/null
+++ b/collection/sample_basic.py
@@ -0,0 +1,621 @@
+# =============================================================================
+# This file is part of EavesDroid.
+#
+# Author: iamywang
+# Date Created: Jan 27, 2024
+# =============================================================================
+import os
+os.environ['TF_CPP_MIN_LOG_LEVEL'] = '3'
+import time
+from backend.backend.view import *
+
+
+# =============================================================================
+# Telegram
+# =============================================================================
+args_oppo_k10_telegram = ["600 600", "600 400", "200 2350", "1000 1500",
+ "100 200", "200 300", "data/OPPO OPPO PGJM10/12 31/test/"]
+args_redmi_k50_telegram = ["600 600", "600 400", "200 3000", "1350 1950",
+ "100 200", "200 300", "data/Xiaomi Redmi 22041211AC/12 31/test/"]
+args_xiaomi_9_telegram = ["600 500", "600 300", "200 2250", "1000 1450", # miui 1350
+ "100 150", "150 200", "data/Xiaomi Xiaomi MI 9/12 32/test/"]
+
+
+def telegram(nums, args):
+ timestamp1 = time.time()
+ rounds = 0
+
+ # kind 0: launch
+ for i in range(nums):
+ rounds += 1
+ timestamp2 = time.time()
+ print("round %d: %fs" % (rounds, timestamp2 - timestamp1))
+
+ while not os.path.exists(args[-1] + str(rounds - 1) + '.txt'):
+ os.system(
+ 'adb shell am start org.telegram.messenger.web/org.telegram.ui.LaunchActivity')
+ time.sleep(3)
+ os.system('adb shell am start com.iamywang.sampler/.MainActivity')
+ time.sleep(1)
+ os.system(
+ 'adb shell am start org.telegram.messenger.web/org.telegram.ui.LaunchActivity')
+ time.sleep(5)
+
+ os.system('adb shell am force-stop com.iamywang.sampler')
+ os.system('adb shell am force-stop org.telegram.messenger.web')
+ time.sleep(1)
+
+ # kind 1: view
+ rounds += 1
+ timestamp2 = time.time()
+ print("round %d: %fs" % (rounds, timestamp2 - timestamp1))
+
+ while not os.path.exists(args[-1] + str(rounds - 1) + '.txt'):
+ os.system(
+ 'adb shell am start org.telegram.messenger.web/org.telegram.ui.LaunchActivity')
+ time.sleep(3)
+ os.system('adb shell am start com.iamywang.sampler/.MainActivity')
+ time.sleep(1)
+ os.system(
+ 'adb shell am start org.telegram.messenger.web/org.telegram.ui.LaunchActivity')
+ time.sleep(1)
+ os.system("adb shell input tap" + " " + args[0])
+ time.sleep(5)
+
+ os.system('adb shell am force-stop com.iamywang.sampler')
+ os.system('adb shell am force-stop org.telegram.messenger.web')
+ time.sleep(1)
+
+ # kind 2: send
+ rounds += 1
+ timestamp2 = time.time()
+ print("round %d: %fs" % (rounds, timestamp2 - timestamp1))
+
+ while not os.path.exists(args[-1] + str(rounds - 1) + '.txt'):
+ os.system(
+ 'adb shell am start org.telegram.messenger.web/org.telegram.ui.LaunchActivity')
+ time.sleep(3)
+ os.system("adb shell input tap" + " " + args[1])
+ time.sleep(1)
+ os.system('adb shell am start com.iamywang.sampler/.MainActivity')
+ time.sleep(1)
+ os.system(
+ 'adb shell am start org.telegram.messenger.web/org.telegram.ui.LaunchActivity')
+ time.sleep(1)
+ os.system("adb shell input tap" + " " + args[2])
+ os.system("adb shell input text 'hello:" + str(i) + "'")
+ time.sleep(0.5)
+ os.system("adb shell input keyevent 62")
+ time.sleep(0.5)
+ os.system("adb shell input tap" + " " + args[3])
+ time.sleep(5)
+
+ os.system('adb shell am force-stop com.iamywang.sampler')
+ os.system('adb shell am force-stop org.telegram.messenger.web')
+ time.sleep(1)
+
+ # kind 3: info
+ rounds += 1
+ timestamp2 = time.time()
+ print("round %d: %fs" % (rounds, timestamp2 - timestamp1))
+
+ while not os.path.exists(args[-1] + str(rounds - 1) + '.txt'):
+ os.system(
+ 'adb shell am start org.telegram.messenger.web/org.telegram.ui.LaunchActivity')
+ time.sleep(3)
+ os.system('adb shell am start com.iamywang.sampler/.MainActivity')
+ time.sleep(1)
+ os.system(
+ 'adb shell am start org.telegram.messenger.web/org.telegram.ui.LaunchActivity')
+ time.sleep(1)
+ os.system("adb shell input tap" + " " + args[4])
+ time.sleep(1)
+ os.system("adb shell input tap" + " " + args[5])
+ time.sleep(3)
+
+ os.system('adb shell am force-stop com.iamywang.sampler')
+ os.system('adb shell am force-stop org.telegram.messenger.web')
+ time.sleep(1)
+
+
+# =============================================================================
+# Youtube
+# =============================================================================
+args_oppo_k10_youtube = ["500 500 500 1000", "600 1700",
+ "300 2350", "850 200", "data/OPPO OPPO PGJM10/12 31/test/"]
+args_redmi_k50_youtube = ["500 500 500 1500", "700 2000",
+ "450 3050", "1150 180", "data/Xiaomi Redmi 22041211AC/12 31/test/"]
+args_xiaomi_9_youtube = ["500 500 500 1500", "600 1700",
+ "300 2250", "850 150", "data/Xiaomi Xiaomi MI 9/12 32/test/"]
+
+
+def youtube(nums, args):
+ timestamp1 = time.time()
+ rounds = 0
+
+ # kind 0: launch
+ for i in range(nums):
+ rounds += 1
+ timestamp2 = time.time()
+ print("round %d: %fs" % (rounds, timestamp2 - timestamp1))
+
+ while not os.path.exists(args[-1] + str(rounds - 1) + '.txt'):
+ os.system(
+ 'adb shell am start com.google.android.youtube/.HomeActivity')
+ time.sleep(3)
+ os.system('adb shell am start com.iamywang.sampler/.MainActivity')
+ time.sleep(1)
+ os.system(
+ 'adb shell am start com.google.android.youtube/.HomeActivity')
+ time.sleep(5)
+
+ os.system('adb shell am force-stop com.iamywang.sampler')
+ os.system('adb shell am force-stop com.google.android.youtube')
+ time.sleep(1)
+
+ # kind 1: refersh
+ rounds += 1
+ timestamp2 = time.time()
+ print("round %d: %fs" % (rounds, timestamp2 - timestamp1))
+
+ while not os.path.exists(args[-1] + str(rounds - 1) + '.txt'):
+ os.system('adb shell am start com.google.android.youtube/.HomeActivity')
+ time.sleep(3)
+ os.system('adb shell am start com.iamywang.sampler/.MainActivity')
+ time.sleep(1)
+ os.system('adb shell am start com.google.android.youtube/.HomeActivity')
+ time.sleep(1)
+ os.system("adb shell input swipe" + " " + args[0])
+ time.sleep(0.5)
+ os.system("adb shell input swipe" + " " + args[0])
+ os.system("adb shell input swipe" + " " + args[0])
+ time.sleep(4)
+
+ os.system('adb shell am force-stop com.iamywang.sampler')
+ os.system('adb shell am force-stop com.google.android.youtube')
+ time.sleep(1)
+
+ # kind 2: view
+ rounds += 1
+ timestamp2 = time.time()
+ print("round %d: %fs" % (rounds, timestamp2 - timestamp1))
+
+ while not os.path.exists(args[-1] + str(rounds - 1) + '.txt'):
+ os.system('adb shell am start com.google.android.youtube/.HomeActivity')
+ time.sleep(3)
+ os.system('adb shell am start com.iamywang.sampler/.MainActivity')
+ time.sleep(1)
+ os.system('adb shell am start com.google.android.youtube/.HomeActivity')
+ time.sleep(2)
+ os.system("adb shell input tap" + " " + args[1])
+ time.sleep(4)
+
+ os.system('adb shell am force-stop com.iamywang.sampler')
+ os.system('adb shell am force-stop com.google.android.youtube')
+ time.sleep(1)
+
+ # kind 3: short
+ rounds += 1
+ timestamp2 = time.time()
+ print("round %d: %fs" % (rounds, timestamp2 - timestamp1))
+
+ while not os.path.exists(args[-1] + str(rounds - 1) + '.txt'):
+ os.system('adb shell am start com.google.android.youtube/.HomeActivity')
+ time.sleep(3)
+ os.system('adb shell am start com.iamywang.sampler/.MainActivity')
+ time.sleep(1)
+ os.system('adb shell am start com.google.android.youtube/.HomeActivity')
+ time.sleep(1)
+ os.system("adb shell input tap" + " " + args[2])
+ time.sleep(5)
+
+ os.system('adb shell am force-stop com.iamywang.sampler')
+ os.system('adb shell am force-stop com.google.android.youtube')
+ time.sleep(1)
+
+ # kind 4: search
+ rounds += 1
+ timestamp2 = time.time()
+ print("round %d: %fs" % (rounds, timestamp2 - timestamp1))
+ while not os.path.exists(args[-1] + str(rounds - 1) + '.txt'):
+ os.system(
+ 'adb shell am start com.google.android.youtube/.HomeActivity')
+ time.sleep(3)
+ os.system('adb shell am start com.iamywang.sampler/.MainActivity')
+ time.sleep(1)
+ os.system('adb shell am start com.google.android.youtube/.HomeActivity')
+ time.sleep(1)
+ os.system("adb shell input tap" + " " + args[3])
+ time.sleep(1)
+ os.system("adb shell input text 'computer'")
+ time.sleep(0.5)
+ os.system("adb shell input keyevent 66")
+ os.system("adb shell input keyevent 66")
+ time.sleep(3)
+
+ os.system('adb shell am force-stop com.iamywang.sampler')
+ os.system('adb shell am force-stop com.google.android.youtube')
+ time.sleep(1)
+
+
+# =============================================================================
+# Gmail
+# =============================================================================
+args_oppo_k10_gmail = ["300 500", "800 2200", "900 200",
+ "300 200", "data/OPPO OPPO PGJM10/12 31/test/"]
+args_redmi_k50_gmail = ["300 500", "1100 2800", "1200 200",
+ "300 200", "data/Xiaomi Redmi 22041211AC/12 31/test/"]
+args_xiaomi_9_gmail = ["300 500", "800 2050", "900 150",
+ "300 150", "data/Xiaomi Xiaomi MI 9/12 32/test/"]
+
+
+def gmail(nums, args):
+ timestamp1 = time.time()
+ rounds = 0
+
+ # kind 0: launch
+ for i in range(nums):
+ rounds += 1
+ timestamp2 = time.time()
+ print("round %d: %fs" % (rounds, timestamp2 - timestamp1))
+
+ while not os.path.exists(args[-1] + str(rounds - 1) + '.txt'):
+ os.system('adb shell am start com.google.android.gm/.GmailActivity')
+ time.sleep(3)
+ os.system('adb shell am start com.iamywang.sampler/.MainActivity')
+ time.sleep(1)
+ os.system('adb shell am start com.google.android.gm/.GmailActivity')
+ time.sleep(5)
+
+ os.system('adb shell am force-stop com.iamywang.sampler')
+ os.system('adb shell am force-stop com.google.android.gm')
+ time.sleep(1)
+
+ # kind 1: view
+ rounds += 1
+ timestamp2 = time.time()
+ print("round %d: %fs" % (rounds, timestamp2 - timestamp1))
+
+ while not os.path.exists(args[-1] + str(rounds - 1) + '.txt'):
+ os.system('adb shell am start com.google.android.gm/.GmailActivity')
+ time.sleep(3)
+ os.system('adb shell am start com.iamywang.sampler/.MainActivity')
+ time.sleep(1)
+ os.system('adb shell am start com.google.android.gm/.GmailActivity')
+ time.sleep(1)
+ os.system("adb shell input tap" + " " + args[0])
+ time.sleep(5)
+
+ os.system('adb shell am force-stop com.iamywang.sampler')
+ os.system('adb shell am force-stop com.google.android.gm')
+ time.sleep(1)
+
+ # kind 2: send
+ rounds += 1
+ timestamp2 = time.time()
+ print("round %d: %fs" % (rounds, timestamp2 - timestamp1))
+
+ while not os.path.exists(args[-1] + str(rounds - 1) + '.txt'):
+ os.system('adb shell am start com.google.android.gm/.GmailActivity')
+ time.sleep(3)
+ os.system('adb shell am start com.iamywang.sampler/.MainActivity')
+ time.sleep(1)
+ os.system('adb shell am start com.google.android.gm/.GmailActivity')
+ time.sleep(1)
+ os.system("adb shell input tap" + " " + args[1])
+ time.sleep(1)
+ os.system("adb shell input text 'kingwang2021@gmail.com'")
+ time.sleep(0.5)
+ os.system("adb shell input tap" + " " + args[2])
+ time.sleep(4)
+
+ os.system('adb shell am force-stop com.iamywang.sampler')
+ os.system('adb shell am force-stop com.google.android.gm')
+ time.sleep(1)
+
+ # kind 3: search
+ rounds += 1
+ timestamp2 = time.time()
+ print("round %d: %fs" % (rounds, timestamp2 - timestamp1))
+
+ while not os.path.exists(args[-1] + str(rounds - 1) + '.txt'):
+ os.system('adb shell am start com.google.android.gm/.GmailActivity')
+ time.sleep(3)
+ os.system('adb shell am start com.iamywang.sampler/.MainActivity')
+ time.sleep(1)
+ os.system('adb shell am start com.google.android.gm/.GmailActivity')
+ time.sleep(1)
+ os.system("adb shell input tap" + " " + args[3])
+ time.sleep(1)
+ os.system("adb shell input text 'onedrive'")
+ time.sleep(0.5)
+ os.system("adb shell input keyevent 66")
+ time.sleep(4)
+
+ os.system('adb shell am force-stop com.iamywang.sampler')
+ os.system('adb shell am force-stop com.google.android.gm')
+ time.sleep(1)
+
+
+# =============================================================================
+# OneNote
+# =============================================================================
+args_oppo_k10_onenote = ["200 300", "950 2150", "550 2350", "data/OPPO OPPO PGJM10/12 31/test/"]
+args_redmi_k50_onenote = ["200 400", "1250 2750", "750 3050", "data/Xiaomi Redmi 22041211AC/12 31/test/"]
+args_xiaomi_9_onenote = ["200 300", "950 2000", "550 2250", "data/Xiaomi Xiaomi MI 9/12 32/test/"]
+args_xiaomi_9_onenote2 = ["200 500", "150 2200", "1000 150", "data/Xiaomi Xiaomi MI 9/12 32/test/"]
+
+def onenote(nums, args):
+ timestamp1 = time.time()
+ rounds = 0
+
+ # kind 0: launch
+ for i in range(nums):
+ rounds += 1
+ timestamp2 = time.time()
+ print("round %d: %fs" % (rounds, timestamp2 - timestamp1))
+
+ while not os.path.exists(args[-1] + str(rounds - 1) + '.txt'):
+ os.system(
+ 'adb shell am start com.microsoft.office.onenote/.ui.EntryActivity')
+ time.sleep(3)
+ os.system('adb shell am start com.iamywang.sampler/.MainActivity')
+ time.sleep(1)
+ os.system(
+ 'adb shell am start com.microsoft.office.onenote/.ui.EntryActivity')
+ time.sleep(5)
+
+ os.system('adb shell am force-stop com.iamywang.sampler')
+ os.system('adb shell am force-stop com.microsoft.office.onenote')
+ time.sleep(1)
+
+ # kind 1: view
+ rounds += 1
+ timestamp2 = time.time()
+ print("round %d: %fs" % (rounds, timestamp2 - timestamp1))
+
+ while not os.path.exists(args[-1] + str(rounds - 1) + '.txt'):
+ os.system(
+ 'adb shell am start com.microsoft.office.onenote/.ui.EntryActivity')
+ time.sleep(3)
+ os.system('adb shell am start com.iamywang.sampler/.MainActivity')
+ time.sleep(1)
+ os.system(
+ 'adb shell am start com.microsoft.office.onenote/.ui.EntryActivity')
+ time.sleep(1)
+ os.system("adb shell input tap" + " " + args[0])
+ time.sleep(5)
+
+ os.system('adb shell am force-stop com.iamywang.sampler')
+ os.system('adb shell am force-stop com.microsoft.office.onenote')
+ time.sleep(1)
+
+ # kind 2: new
+ rounds += 1
+ timestamp2 = time.time()
+ print("round %d: %fs" % (rounds, timestamp2 - timestamp1))
+
+ while not os.path.exists(args[-1] + str(rounds - 1) + '.txt'):
+ os.system(
+ 'adb shell am start com.microsoft.office.onenote/.ui.EntryActivity')
+ time.sleep(3)
+ os.system('adb shell am start com.iamywang.sampler/.MainActivity')
+ time.sleep(1)
+ os.system(
+ 'adb shell am start com.microsoft.office.onenote/.ui.EntryActivity')
+ time.sleep(1)
+ os.system("adb shell input tap" + " " + args[1])
+ time.sleep(1)
+ os.system("adb shell input text 'new note: " + str(i) + "'")
+ time.sleep(5)
+
+ os.system('adb shell am force-stop com.iamywang.sampler')
+ os.system('adb shell am force-stop com.microsoft.office.onenote')
+ time.sleep(1)
+
+ # kind 3: search
+ rounds += 1
+ timestamp2 = time.time()
+ print("round %d: %fs" % (rounds, timestamp2 - timestamp1))
+
+ while not os.path.exists(args[-1] + str(rounds - 1) + '.txt'):
+ os.system(
+ 'adb shell am start com.microsoft.office.onenote/.ui.EntryActivity')
+ time.sleep(3)
+ os.system('adb shell am start com.iamywang.sampler/.MainActivity')
+ time.sleep(1)
+ os.system(
+ 'adb shell am start com.microsoft.office.onenote/.ui.EntryActivity')
+ time.sleep(1)
+ os.system("adb shell input tap" + " " + args[2])
+ time.sleep(1)
+ os.system("adb shell input text 'aaaa'")
+ time.sleep(0.5)
+ os.system("adb shell input keyevent 66")
+ time.sleep(4)
+
+ os.system('adb shell am force-stop com.iamywang.sampler')
+ os.system('adb shell am force-stop com.microsoft.office.onenote')
+ time.sleep(1)
+
+
+# =============================================================================
+# Telegram - patterns 6.7.3
+# =============================================================================
+def telegram_patterns(nums, args):
+ timestamp1 = time.time()
+ rounds = 0
+
+ intervals = [0.2, 0.4, 0.6, 0.8, 1.0]
+ characters = [1, 2, 3, 4]
+
+ # 0~199: 0.2s, 1 character
+ # 200~399: 0.2s, 2 characters
+ # 400~599: 0.2s, 3 characters
+ # 600~799: 0.2s, 4 characters
+ # 800~999: 0.4s, 1 character
+ # 1000~1199: 0.4s, 2 characters
+ # 1200~1399: 0.4s, 3 characters
+ # 1400~1599: 0.4s, 4 characters
+ # 1600~1799: 0.6s, 1 character
+ # 1800~1999: 0.6s, 2 characters
+ # 2000~2199: 0.6s, 3 characters
+ # 2200~2399: 0.6s, 4 characters
+ # 2400~2599: 0.8s, 1 character
+ # 2600~2799: 0.8s, 2 characters
+ # 2800~2999: 0.8s, 3 characters
+ # 3000~3199: 0.8s, 4 characters
+ # 3200~3399: 1.0s, 1 character
+ # 3400~3599: 1.0s, 2 characters
+ # 3600~3799: 1.0s, 3 characters
+ # 3800~3999: 1.0s, 4 characters
+
+ # kind 2: send
+ for iv in intervals:
+ for cr in characters:
+ for i in range(nums):
+ rounds += 1
+ timestamp2 = time.time()
+ print("round %d: %fs" % (rounds, timestamp2 - timestamp1))
+
+ while not os.path.exists(args[-1] + str(rounds - 1) + '.txt'):
+ os.system('adb shell am start org.telegram.messenger.web/org.telegram.ui.LaunchActivity')
+ time.sleep(3)
+ os.system("adb shell input tap" + " " + args[1])
+ time.sleep(1)
+ os.system("adb shell input text '" + str(rounds - 1) + ": '")
+ time.sleep(0.5)
+ os.system('adb shell am start com.iamywang.sampler/.MainActivity')
+ time.sleep(1)
+ os.system('adb shell am start org.telegram.messenger.web/org.telegram.ui.LaunchActivity')
+ time.sleep(1)
+ os.system("adb shell input tap" + " " + args[2])
+ for c in range(cr):
+ os.system("adb shell input text 'a'")
+ time.sleep(iv)
+ os.system("adb shell input keyevent 62")
+ time.sleep(iv)
+ os.system("adb shell input tap" + " " + args[3])
+ time.sleep(4)
+
+ os.system('adb shell am force-stop com.iamywang.sampler')
+ os.system('adb shell am force-stop org.telegram.messenger.web')
+ time.sleep(1)
+
+# =============================================================================
+# Set label
+# =============================================================================
+def data_set_label(path, num_groups, num_features, offset):
+ """
+ Set labels for data set.
+
+ Args:
+ num_groups: number of data in each group
+ num_features: number of features
+
+ Returns:
+ none
+ """
+ # test/ files
+ flist = os.listdir(path)
+ nums = len(flist)
+ for i in range(nums):
+ fpath = flist[i]
+ index = int(fpath.split('.')[0])
+ label = int(index / num_groups) * num_features + index % num_features + offset
+ # rename
+ print(str(index), '->', label, str(int(index / num_features)))
+ os.rename(path + fpath, path + str(label) + '_' +
+ str(int(index / num_features)) + '.txt')
+
+
+# =============================================================================
+# Revert label
+# =============================================================================
+def data_revert_label(path, num_groups, num_features):
+ flist = os.listdir(path)
+ nums = len(flist)
+ for i in range(nums):
+ fpath = flist[i]
+ label = int(fpath.split('_')[0]) - 9
+ pos = int(fpath.split('_')[1].split('.')[0])
+ index = pos * num_features + label
+ # rename
+ print(str(label), str(pos), '->', str(index))
+ os.rename(path + fpath, path + str(index) + '.txt')
+
+# =============================================================================
+# Move
+# =============================================================================
+def data_move(path_1, path_2):
+ """
+ Move data from path_1 to path_2.
+
+ Args:
+ path_1: source path
+ path_2: destination path
+ """
+ flist = os.listdir(path_1)
+ nums = len(flist)
+ for i in range(nums):
+ fpath = flist[i]
+ os.rename(path_1 + fpath, path_2 + fpath)
+
+# =============================================================================
+# Main - 4 apps in total
+# =============================================================================
+def exp_noise(background_processes):
+ if not os.path.exists('data/exp-noise/'+ str(background_processes) + '/0_0.txt'):
+ telegram(200, args_xiaomi_9_telegram)
+ data_set_label('data/Xiaomi Xiaomi MI 9/12 32/test/', 800, 4, 0)
+ data_move('data/Xiaomi Xiaomi MI 9/12 32/test/', 'data/exp-noise/' + str(background_processes) + '/')
+
+ if not os.path.exists('data/exp-noise/'+ str(background_processes) + '/4_0.txt'):
+ youtube(200, args_xiaomi_9_youtube)
+ data_set_label('data/Xiaomi Xiaomi MI 9/12 32/test/', 1000, 5, 4)
+ data_move('data/Xiaomi Xiaomi MI 9/12 32/test/', 'data/exp-noise/' + str(background_processes) + '/')
+
+ if not os.path.exists('data/exp-noise/'+ str(background_processes) + '/9_0.txt'):
+ gmail(200, args_xiaomi_9_gmail)
+ data_set_label('data/Xiaomi Xiaomi MI 9/12 32/test/', 800, 4, 9)
+ data_move('data/Xiaomi Xiaomi MI 9/12 32/test/', 'data/exp-noise/' + str(background_processes) + '/')
+
+ if not os.path.exists('data/exp-noise/'+ str(background_processes) + '/13_0.txt'):
+ onenote(200, args_xiaomi_9_onenote2)
+ data_set_label('data/Xiaomi Xiaomi MI 9/12 32/test/', 800, 4, 13)
+ data_move('data/Xiaomi Xiaomi MI 9/12 32/test/', 'data/exp-noise/' + str(background_processes) + '/')
+
+
+def exp_noise_main():
+ os.system('adb shell am force-stop com.android.chrome')
+ os.system('adb shell am force-stop com.taobao.taobao')
+ os.system('adb shell am force-stop com.sina.weibo')
+ exp_noise(0)
+ time.sleep(3)
+
+ os.system('adb shell am force-stop com.android.chrome')
+ os.system('adb shell am force-stop com.taobao.taobao')
+ os.system('adb shell am force-stop com.sina.weibo')
+ os.system('adb shell am start com.android.chrome/com.google.android.apps.chrome.Main')
+ exp_noise(1)
+ time.sleep(3)
+
+
+ os.system('adb shell am force-stop com.android.chrome')
+ os.system('adb shell am force-stop com.taobao.taobao')
+ os.system('adb shell am force-stop com.sina.weibo')
+ os.system('adb shell am start com.android.chrome/com.google.android.apps.chrome.Main')
+ os.system('adb shell am start com.taobao.taobao/com.taobao.tao.TBMainActivity')
+ exp_noise(2)
+ time.sleep(3)
+
+ os.system('adb shell am force-stop com.android.chrome')
+ os.system('adb shell am force-stop com.taobao.taobao')
+ os.system('adb shell am force-stop com.sina.weibo')
+ os.system('adb shell am start com.android.chrome/com.google.android.apps.chrome.Main')
+ os.system('adb shell am start com.taobao.taobao/com.taobao.tao.TBMainActivity')
+ os.system('adb shell am start com.sina.weibo/com.sina.weibo.SplashActivity')
+ exp_noise(3)
+ time.sleep(3)
+
+exp_noise_main()
diff --git a/collection/sample_complex.py b/collection/sample_complex.py
new file mode 100755
index 0000000..7744078
--- /dev/null
+++ b/collection/sample_complex.py
@@ -0,0 +1,611 @@
+# =============================================================================
+# This file is part of EavesDroid.
+#
+# Author: iamywang
+# Date Created: Jan 27, 2024
+# =============================================================================
+import os
+os.environ['TF_CPP_MIN_LOG_LEVEL'] = '3'
+import time
+from backend.backend.view import *
+
+
+# =============================================================================
+# Arguments
+# =============================================================================
+args_xiaomi_9 = ["data/Xiaomi Xiaomi MI 9/12 32/test/"]
+
+
+# =============================================================================
+# Set label
+# =============================================================================
+def data_set_label(path, num_groups, num_features, offset):
+ """
+ Set labels for data set.
+
+ Args:
+ num_groups: number of data in each group
+ num_features: number of features
+
+ Returns:
+ none
+ """
+ flist = os.listdir(path)
+ nums = len(flist)
+ for i in range(nums):
+ fpath = flist[i]
+ index = int(fpath.split('.')[0])
+ label = int(index / num_groups) * num_features + index % num_features + offset
+ print(str(index), '->', label, str(int(index / num_features)))
+ os.rename(path + fpath, path + str(label) + '_' +
+ str(int(index / num_features)) + '.txt')
+
+
+# =============================================================================
+# Move
+# =============================================================================
+def data_move(path_1, path_2):
+ """
+ Move data from path_1 to path_2.
+
+ Args:
+ path_1: source path
+ path_2: destination path
+ """
+ flist = os.listdir(path_1)
+ nums = len(flist)
+ for i in range(nums):
+ fpath = flist[i]
+ os.rename(path_1 + fpath, path_2 + fpath)
+
+
+def seq_2b(nums, args):
+ timestamp1 = time.time()
+ rounds = 0
+
+ for i in range(nums):
+ # kind 17: tg yt
+ rounds += 1
+ timestamp2 = time.time()
+ print("round %d: %fs" % (rounds, timestamp2 - timestamp1))
+
+ while not os.path.exists(args[-1] + str(rounds - 1) + '.txt'):
+ os.system('adb shell am start org.telegram.messenger.web/org.telegram.ui.LaunchActivity')
+ os.system('adb shell am start com.google.android.youtube/.HomeActivity')
+ time.sleep(3)
+ os.system('adb shell am start com.iamywang.sampler/.MainActivity')
+ time.sleep(1)
+ os.system('adb shell am start org.telegram.messenger.web/org.telegram.ui.LaunchActivity')
+ time.sleep(1)
+ os.system('adb shell am start com.google.android.youtube/.HomeActivity')
+ time.sleep(4)
+ os.system('adb shell am force-stop com.iamywang.sampler')
+ os.system('adb shell am force-stop org.telegram.messenger.web')
+ os.system('adb shell am force-stop com.google.android.youtube')
+ time.sleep(1)
+
+ # kind 18: tg gm
+ rounds += 1
+ timestamp2 = time.time()
+ print("round %d: %fs" % (rounds, timestamp2 - timestamp1))
+
+ while not os.path.exists(args[-1] + str(rounds - 1) + '.txt'):
+ os.system('adb shell am start org.telegram.messenger.web/org.telegram.ui.LaunchActivity')
+ os.system('adb shell am start com.google.android.gm/.GmailActivity')
+ time.sleep(3)
+ os.system('adb shell am start com.iamywang.sampler/.MainActivity')
+ time.sleep(1)
+ os.system('adb shell am start org.telegram.messenger.web/org.telegram.ui.LaunchActivity')
+ time.sleep(1)
+ os.system('adb shell am start com.google.android.gm/.GmailActivity')
+ time.sleep(4)
+ os.system('adb shell am force-stop com.iamywang.sampler')
+ os.system('adb shell am force-stop org.telegram.messenger.web')
+ os.system('adb shell am start com.google.android.gm/.GmailActivity')
+
+ # kind 19: tg on
+ rounds += 1
+ timestamp2 = time.time()
+ print("round %d: %fs" % (rounds, timestamp2 - timestamp1))
+
+ while not os.path.exists(args[-1] + str(rounds - 1) + '.txt'):
+ os.system('adb shell am start org.telegram.messenger.web/org.telegram.ui.LaunchActivity')
+ os.system('adb shell am start com.microsoft.office.onenote/.ui.EntryActivity')
+ time.sleep(3)
+ os.system('adb shell am start com.iamywang.sampler/.MainActivity')
+ time.sleep(1)
+ os.system('adb shell am start org.telegram.messenger.web/org.telegram.ui.LaunchActivity')
+ time.sleep(1)
+ os.system('adb shell am start com.microsoft.office.onenote/.ui.EntryActivity')
+ time.sleep(4)
+ os.system('adb shell am force-stop com.iamywang.sampler')
+ os.system('adb shell am force-stop org.telegram.messenger.web')
+ os.system('adb shell am force-stop com.microsoft.office.onenote')
+ time.sleep(1)
+
+ # kind 20: yt tg
+ rounds += 1
+ timestamp2 = time.time()
+ print("round %d: %fs" % (rounds, timestamp2 - timestamp1))
+
+ while not os.path.exists(args[-1] + str(rounds - 1) + '.txt'):
+ os.system('adb shell am start com.google.android.youtube/.HomeActivity')
+ os.system('adb shell am start org.telegram.messenger.web/org.telegram.ui.LaunchActivity')
+ time.sleep(3)
+ os.system('adb shell am start com.iamywang.sampler/.MainActivity')
+ time.sleep(1)
+ os.system('adb shell am start com.google.android.youtube/.HomeActivity')
+ time.sleep(1)
+ os.system('adb shell am start org.telegram.messenger.web/org.telegram.ui.LaunchActivity')
+ time.sleep(4)
+ os.system('adb shell am force-stop com.iamywang.sampler')
+ os.system('adb shell am force-stop com.google.android.youtube')
+ os.system('adb shell am force-stop org.telegram.messenger.web')
+ time.sleep(1)
+
+ # kind 21: yt gm
+ rounds += 1
+ timestamp2 = time.time()
+ print("round %d: %fs" % (rounds, timestamp2 - timestamp1))
+
+ while not os.path.exists(args[-1] + str(rounds - 1) + '.txt'):
+ os.system('adb shell am start com.google.android.youtube/.HomeActivity')
+ os.system('adb shell am start com.google.android.gm/.GmailActivity')
+ time.sleep(3)
+ os.system('adb shell am start com.iamywang.sampler/.MainActivity')
+ time.sleep(1)
+ os.system('adb shell am start com.google.android.youtube/.HomeActivity')
+ time.sleep(1)
+ os.system('adb shell am start com.google.android.gm/.GmailActivity')
+ time.sleep(4)
+ os.system('adb shell am force-stop com.iamywang.sampler')
+ os.system('adb shell am force-stop com.google.android.youtube')
+ os.system('adb shell am force-stop com.google.android.gm')
+ time.sleep(1)
+
+ # kind 22: yt on
+ rounds += 1
+ timestamp2 = time.time()
+ print("round %d: %fs" % (rounds, timestamp2 - timestamp1))
+
+ while not os.path.exists(args[-1] + str(rounds - 1) + '.txt'):
+ os.system('adb shell am start com.google.android.youtube/.HomeActivity')
+ os.system('adb shell am start com.microsoft.office.onenote/.ui.EntryActivity')
+ time.sleep(3)
+ os.system('adb shell am start com.iamywang.sampler/.MainActivity')
+ time.sleep(1)
+ os.system('adb shell am start com.google.android.youtube/.HomeActivity')
+ time.sleep(1)
+ os.system('adb shell am start com.microsoft.office.onenote/.ui.EntryActivity')
+ time.sleep(4)
+ os.system('adb shell am force-stop com.iamywang.sampler')
+ os.system('adb shell am force-stop com.google.android.youtube')
+ os.system('adb shell am force-stop com.microsoft.office.onenote')
+ time.sleep(1)
+
+ # kind 23: gm tg
+ rounds += 1
+ timestamp2 = time.time()
+ print("round %d: %fs" % (rounds, timestamp2 - timestamp1))
+
+ while not os.path.exists(args[-1] + str(rounds - 1) + '.txt'):
+ os.system('adb shell am start com.google.android.gm/.GmailActivity')
+ os.system('adb shell am start org.telegram.messenger.web/org.telegram.ui.LaunchActivity')
+ time.sleep(3)
+ os.system('adb shell am start com.iamywang.sampler/.MainActivity')
+ time.sleep(1)
+ os.system('adb shell am start com.google.android.gm/.GmailActivity')
+ time.sleep(1)
+ os.system('adb shell am start org.telegram.messenger.web/org.telegram.ui.LaunchActivity')
+ time.sleep(4)
+ os.system('adb shell am force-stop com.iamywang.sampler')
+ os.system('adb shell am force-stop com.google.android.gm')
+ os.system('adb shell am force-stop org.telegram.messenger.web')
+ time.sleep(1)
+
+ # kind 24: gm yt
+ rounds += 1
+ timestamp2 = time.time()
+ print("round %d: %fs" % (rounds, timestamp2 - timestamp1))
+
+ while not os.path.exists(args[-1] + str(rounds - 1) + '.txt'):
+ os.system('adb shell am start com.google.android.gm/.GmailActivity')
+ os.system('adb shell am start com.google.android.youtube/.HomeActivity')
+ time.sleep(3)
+ os.system('adb shell am start com.iamywang.sampler/.MainActivity')
+ time.sleep(1)
+ os.system('adb shell am start com.google.android.gm/.GmailActivity')
+ time.sleep(1)
+ os.system('adb shell am start com.google.android.youtube/.HomeActivity')
+ time.sleep(4)
+ os.system('adb shell am force-stop com.iamywang.sampler')
+ os.system('adb shell am force-stop com.google.android.gm')
+ os.system('adb shell am force-stop com.google.android.youtube')
+ time.sleep(1)
+
+ # kind 25: gm on
+ rounds += 1
+ timestamp2 = time.time()
+ print("round %d: %fs" % (rounds, timestamp2 - timestamp1))
+
+ while not os.path.exists(args[-1] + str(rounds - 1) + '.txt'):
+ os.system('adb shell am start com.google.android.gm/.GmailActivity')
+ os.system('adb shell am start com.microsoft.office.onenote/.ui.EntryActivity')
+ time.sleep(3)
+ os.system('adb shell am start com.iamywang.sampler/.MainActivity')
+ time.sleep(1)
+ os.system('adb shell am start com.google.android.gm/.GmailActivity')
+ time.sleep(1)
+ os.system('adb shell am start com.microsoft.office.onenote/.ui.EntryActivity')
+ time.sleep(4)
+ os.system('adb shell am force-stop com.iamywang.sampler')
+ os.system('adb shell am force-stop com.google.android.gm')
+ os.system('adb shell am force-stop com.microsoft.office.onenote')
+ time.sleep(1)
+
+ # kind 26: on tg
+ rounds += 1
+ timestamp2 = time.time()
+ print("round %d: %fs" % (rounds, timestamp2 - timestamp1))
+
+ while not os.path.exists(args[-1] + str(rounds - 1) + '.txt'):
+ os.system('adb shell am start com.microsoft.office.onenote/.ui.EntryActivity')
+ os.system('adb shell am start org.telegram.messenger.web/org.telegram.ui.LaunchActivity')
+ time.sleep(3)
+ os.system('adb shell am start com.iamywang.sampler/.MainActivity')
+ time.sleep(1)
+ os.system('adb shell am start com.microsoft.office.onenote/.ui.EntryActivity')
+ time.sleep(1)
+ os.system('adb shell am start org.telegram.messenger.web/org.telegram.ui.LaunchActivity')
+ time.sleep(4)
+ os.system('adb shell am force-stop com.iamywang.sampler')
+ os.system('adb shell am force-stop com.microsoft.office.onenote')
+ os.system('adb shell am force-stop org.telegram.messenger.web')
+ time.sleep(1)
+
+ # kind 27: on yt
+ rounds += 1
+ timestamp2 = time.time()
+ print("round %d: %fs" % (rounds, timestamp2 - timestamp1))
+
+ while not os.path.exists(args[-1] + str(rounds - 1) + '.txt'):
+ os.system('adb shell am start com.microsoft.office.onenote/.ui.EntryActivity')
+ os.system('adb shell am start com.google.android.youtube/.HomeActivity')
+ time.sleep(3)
+ os.system('adb shell am start com.iamywang.sampler/.MainActivity')
+ time.sleep(1)
+ os.system('adb shell am start com.microsoft.office.onenote/.ui.EntryActivity')
+ time.sleep(1)
+ os.system('adb shell am start com.google.android.youtube/.HomeActivity')
+ time.sleep(4)
+ os.system('adb shell am force-stop com.iamywang.sampler')
+ os.system('adb shell am force-stop com.microsoft.office.onenote')
+ os.system('adb shell am force-stop com.google.android.youtube')
+ time.sleep(1)
+
+ # kind 28: on gm
+ rounds += 1
+ timestamp2 = time.time()
+ print("round %d: %fs" % (rounds, timestamp2 - timestamp1))
+
+ while not os.path.exists(args[-1] + str(rounds - 1) + '.txt'):
+ os.system('adb shell am start com.microsoft.office.onenote/.ui.EntryActivity')
+ os.system('adb shell am start com.google.android.gm/.GmailActivity')
+ time.sleep(3)
+ os.system('adb shell am start com.iamywang.sampler/.MainActivity')
+ time.sleep(1)
+ os.system('adb shell am start com.microsoft.office.onenote/.ui.EntryActivity')
+ time.sleep(1)
+ os.system('adb shell am start com.google.android.gm/.GmailActivity')
+ time.sleep(4)
+ os.system('adb shell am force-stop com.iamywang.sampler')
+ os.system('adb shell am force-stop com.microsoft.office.onenote')
+ os.system('adb shell am force-stop com.google.android.gm')
+ time.sleep(1)
+
+
+def seq_3b(nums, args):
+ timestamp1 = time.time()
+ rounds = 0
+
+ for i in range(nums):
+ # kind 29: tg yt gm
+ rounds += 1
+ timestamp2 = time.time()
+ print("round %d: %fs" % (rounds, timestamp2 - timestamp1))
+
+ while not os.path.exists(args[-1] + str(rounds - 1) + '.txt'):
+ os.system('adb shell am start org.telegram.messenger.web/org.telegram.ui.LaunchActivity')
+ os.system('adb shell am start com.google.android.youtube/.HomeActivity')
+ os.system('adb shell am start com.google.android.gm/.GmailActivity')
+ time.sleep(3)
+ os.system('adb shell am start com.iamywang.sampler/.MainActivity')
+ time.sleep(1)
+ os.system('adb shell am start org.telegram.messenger.web/org.telegram.ui.LaunchActivity')
+ time.sleep(1)
+ os.system('adb shell am start com.google.android.youtube/.HomeActivity')
+ time.sleep(1)
+ os.system('adb shell am start com.google.android.gm/.GmailActivity')
+ time.sleep(3)
+ os.system('adb shell am force-stop com.iamywang.sampler')
+ os.system('adb shell am force-stop org.telegram.messenger.web')
+ os.system('adb shell am force-stop com.google.android.youtube')
+ os.system('adb shell am force-stop com.google.android.gm')
+ time.sleep(1)
+
+ # kind 30: tg gm on
+ rounds += 1
+ timestamp2 = time.time()
+ print("round %d: %fs" % (rounds, timestamp2 - timestamp1))
+
+ while not os.path.exists(args[-1] + str(rounds - 1) + '.txt'):
+ os.system('adb shell am start org.telegram.messenger.web/org.telegram.ui.LaunchActivity')
+ os.system('adb shell am start com.google.android.gm/.GmailActivity')
+ os.system('adb shell am start com.microsoft.office.onenote/.ui.EntryActivity')
+ time.sleep(3)
+ os.system('adb shell am start com.iamywang.sampler/.MainActivity')
+ time.sleep(1)
+ os.system('adb shell am start org.telegram.messenger.web/org.telegram.ui.LaunchActivity')
+ time.sleep(1)
+ os.system('adb shell am start com.google.android.gm/.GmailActivity')
+ time.sleep(1)
+ os.system('adb shell am start com.microsoft.office.onenote/.ui.EntryActivity')
+ time.sleep(3)
+ os.system('adb shell am force-stop com.iamywang.sampler')
+ os.system('adb shell am force-stop org.telegram.messenger.web')
+ os.system('adb shell am start com.google.android.gm/.GmailActivity')
+ os.system('adb shell am force-stop com.microsoft.office.onenote')
+
+ # kind 31: tg on yt
+ rounds += 1
+ timestamp2 = time.time()
+ print("round %d: %fs" % (rounds, timestamp2 - timestamp1))
+
+ while not os.path.exists(args[-1] + str(rounds - 1) + '.txt'):
+ os.system('adb shell am start org.telegram.messenger.web/org.telegram.ui.LaunchActivity')
+ os.system('adb shell am start com.microsoft.office.onenote/.ui.EntryActivity')
+ os.system('adb shell am start com.google.android.youtube/.HomeActivity')
+ time.sleep(3)
+ os.system('adb shell am start com.iamywang.sampler/.MainActivity')
+ time.sleep(1)
+ os.system('adb shell am start org.telegram.messenger.web/org.telegram.ui.LaunchActivity')
+ time.sleep(1)
+ os.system('adb shell am start com.microsoft.office.onenote/.ui.EntryActivity')
+ time.sleep(1)
+ os.system('adb shell am start com.google.android.youtube/.HomeActivity')
+ time.sleep(3)
+ os.system('adb shell am force-stop com.iamywang.sampler')
+ os.system('adb shell am force-stop org.telegram.messenger.web')
+ os.system('adb shell am force-stop com.microsoft.office.onenote')
+ os.system('adb shell am force-stop com.google.android.youtube')
+ time.sleep(1)
+
+ # kind 32: yt tg gm
+ rounds += 1
+ timestamp2 = time.time()
+ print("round %d: %fs" % (rounds, timestamp2 - timestamp1))
+
+ while not os.path.exists(args[-1] + str(rounds - 1) + '.txt'):
+ os.system('adb shell am start com.google.android.youtube/.HomeActivity')
+ os.system('adb shell am start org.telegram.messenger.web/org.telegram.ui.LaunchActivity')
+ os.system('adb shell am start com.google.android.gm/.GmailActivity')
+ time.sleep(3)
+ os.system('adb shell am start com.iamywang.sampler/.MainActivity')
+ time.sleep(1)
+ os.system('adb shell am start com.google.android.youtube/.HomeActivity')
+ time.sleep(1)
+ os.system('adb shell am start org.telegram.messenger.web/org.telegram.ui.LaunchActivity')
+ time.sleep(1)
+ os.system('adb shell am start com.google.android.gm/.GmailActivity')
+ time.sleep(3)
+ os.system('adb shell am force-stop com.iamywang.sampler')
+ os.system('adb shell am force-stop com.google.android.youtube')
+ os.system('adb shell am force-stop org.telegram.messenger.web')
+ os.system('adb shell am force-stop com.google.android.gm')
+ time.sleep(1)
+
+ # kind 33: yt gm on
+ rounds += 1
+ timestamp2 = time.time()
+ print("round %d: %fs" % (rounds, timestamp2 - timestamp1))
+
+ while not os.path.exists(args[-1] + str(rounds - 1) + '.txt'):
+ os.system('adb shell am start com.google.android.youtube/.HomeActivity')
+ os.system('adb shell am start com.google.android.gm/.GmailActivity')
+ os.system('adb shell am start com.microsoft.office.onenote/.ui.EntryActivity')
+ time.sleep(3)
+ os.system('adb shell am start com.iamywang.sampler/.MainActivity')
+ time.sleep(1)
+ os.system('adb shell am start com.google.android.youtube/.HomeActivity')
+ time.sleep(1)
+ os.system('adb shell am start com.google.android.gm/.GmailActivity')
+ time.sleep(1)
+ os.system('adb shell am start com.microsoft.office.onenote/.ui.EntryActivity')
+ time.sleep(3)
+ os.system('adb shell am force-stop com.iamywang.sampler')
+ os.system('adb shell am force-stop com.google.android.youtube')
+ os.system('adb shell am force-stop com.google.android.gm')
+ os.system('adb shell am force-stop com.microsoft.office.onenote')
+ time.sleep(1)
+
+ # kind 34: yt on tg
+ rounds += 1
+ timestamp2 = time.time()
+ print("round %d: %fs" % (rounds, timestamp2 - timestamp1))
+
+ while not os.path.exists(args[-1] + str(rounds - 1) + '.txt'):
+ os.system('adb shell am start com.google.android.youtube/.HomeActivity')
+ os.system('adb shell am start com.microsoft.office.onenote/.ui.EntryActivity')
+ os.system('adb shell am start org.telegram.messenger.web/org.telegram.ui.LaunchActivity')
+ time.sleep(3)
+ os.system('adb shell am start com.iamywang.sampler/.MainActivity')
+ time.sleep(1)
+ os.system('adb shell am start com.google.android.youtube/.HomeActivity')
+ time.sleep(1)
+ os.system('adb shell am start com.microsoft.office.onenote/.ui.EntryActivity')
+ time.sleep(1)
+ os.system('adb shell am start org.telegram.messenger.web/org.telegram.ui.LaunchActivity')
+ time.sleep(3)
+ os.system('adb shell am force-stop com.iamywang.sampler')
+ os.system('adb shell am force-stop com.google.android.youtube')
+ os.system('adb shell am force-stop com.microsoft.office.onenote')
+ os.system('adb shell am force-stop org.telegram.messenger.web')
+ time.sleep(1)
+
+ # kind 35: gm tg yt
+ rounds += 1
+ timestamp2 = time.time()
+ print("round %d: %fs" % (rounds, timestamp2 - timestamp1))
+
+ while not os.path.exists(args[-1] + str(rounds - 1) + '.txt'):
+ os.system('adb shell am start com.google.android.gm/.GmailActivity')
+ os.system('adb shell am start org.telegram.messenger.web/org.telegram.ui.LaunchActivity')
+ os.system('adb shell am start com.google.android.youtube/.HomeActivity')
+ time.sleep(3)
+ os.system('adb shell am start com.iamywang.sampler/.MainActivity')
+ time.sleep(1)
+ os.system('adb shell am start com.google.android.gm/.GmailActivity')
+ time.sleep(1)
+ os.system('adb shell am start org.telegram.messenger.web/org.telegram.ui.LaunchActivity')
+ time.sleep(1)
+ os.system('adb shell am start com.google.android.youtube/.HomeActivity')
+ time.sleep(3)
+ os.system('adb shell am force-stop com.iamywang.sampler')
+ os.system('adb shell am force-stop com.google.android.gm')
+ os.system('adb shell am force-stop org.telegram.messenger.web')
+ os.system('adb shell am force-stop com.google.android.youtube')
+ time.sleep(1)
+
+ # kind 36: gm yt on
+ rounds += 1
+ timestamp2 = time.time()
+ print("round %d: %fs" % (rounds, timestamp2 - timestamp1))
+
+ while not os.path.exists(args[-1] + str(rounds - 1) + '.txt'):
+ os.system('adb shell am start com.google.android.gm/.GmailActivity')
+ os.system('adb shell am start com.google.android.youtube/.HomeActivity')
+ os.system('adb shell am start com.microsoft.office.onenote/.ui.EntryActivity')
+ time.sleep(3)
+ os.system('adb shell am start com.iamywang.sampler/.MainActivity')
+ time.sleep(1)
+ os.system('adb shell am start com.google.android.gm/.GmailActivity')
+ time.sleep(1)
+ os.system('adb shell am start com.google.android.youtube/.HomeActivity')
+ time.sleep(1)
+ os.system('adb shell am start com.microsoft.office.onenote/.ui.EntryActivity')
+ time.sleep(3)
+ os.system('adb shell am force-stop com.iamywang.sampler')
+ os.system('adb shell am force-stop com.google.android.gm')
+ os.system('adb shell am force-stop com.google.android.youtube')
+ os.system('adb shell am force-stop com.microsoft.office.onenote')
+ time.sleep(1)
+
+ # kind 37: gm on tg
+ rounds += 1
+ timestamp2 = time.time()
+ print("round %d: %fs" % (rounds, timestamp2 - timestamp1))
+
+ while not os.path.exists(args[-1] + str(rounds - 1) + '.txt'):
+ os.system('adb shell am start com.google.android.gm/.GmailActivity')
+ os.system('adb shell am start com.microsoft.office.onenote/.ui.EntryActivity')
+ os.system('adb shell am start org.telegram.messenger.web/org.telegram.ui.LaunchActivity')
+ time.sleep(3)
+ os.system('adb shell am start com.iamywang.sampler/.MainActivity')
+ time.sleep(1)
+ os.system('adb shell am start com.google.android.gm/.GmailActivity')
+ time.sleep(1)
+ os.system('adb shell am start com.microsoft.office.onenote/.ui.EntryActivity')
+ time.sleep(1)
+ os.system('adb shell am start org.telegram.messenger.web/org.telegram.ui.LaunchActivity')
+ time.sleep(3)
+ os.system('adb shell am force-stop com.iamywang.sampler')
+ os.system('adb shell am force-stop com.google.android.gm')
+ os.system('adb shell am force-stop com.microsoft.office.onenote')
+ os.system('adb shell am force-stop org.telegram.messenger.web')
+ time.sleep(1)
+
+ # kind 38: on tg yt
+ rounds += 1
+ timestamp2 = time.time()
+ print("round %d: %fs" % (rounds, timestamp2 - timestamp1))
+
+ while not os.path.exists(args[-1] + str(rounds - 1) + '.txt'):
+ os.system('adb shell am start com.microsoft.office.onenote/.ui.EntryActivity')
+ os.system('adb shell am start org.telegram.messenger.web/org.telegram.ui.LaunchActivity')
+ os.system('adb shell am start com.google.android.youtube/.HomeActivity')
+ time.sleep(3)
+ os.system('adb shell am start com.iamywang.sampler/.MainActivity')
+ time.sleep(1)
+ os.system('adb shell am start com.microsoft.office.onenote/.ui.EntryActivity')
+ time.sleep(1)
+ os.system('adb shell am start org.telegram.messenger.web/org.telegram.ui.LaunchActivity')
+ time.sleep(1)
+ os.system('adb shell am start com.google.android.youtube/.HomeActivity')
+ time.sleep(3)
+ os.system('adb shell am force-stop com.iamywang.sampler')
+ os.system('adb shell am force-stop com.microsoft.office.onenote')
+ os.system('adb shell am force-stop org.telegram.messenger.web')
+ os.system('adb shell am force-stop com.google.android.youtube')
+ time.sleep(1)
+
+ # kind 39: on yt gm
+ rounds += 1
+ timestamp2 = time.time()
+ print("round %d: %fs" % (rounds, timestamp2 - timestamp1))
+
+ while not os.path.exists(args[-1] + str(rounds - 1) + '.txt'):
+ os.system('adb shell am start com.microsoft.office.onenote/.ui.EntryActivity')
+ os.system('adb shell am start com.google.android.youtube/.HomeActivity')
+ os.system('adb shell am start com.google.android.gm/.GmailActivity')
+ time.sleep(3)
+ os.system('adb shell am start com.iamywang.sampler/.MainActivity')
+ time.sleep(1)
+ os.system('adb shell am start com.microsoft.office.onenote/.ui.EntryActivity')
+ time.sleep(1)
+ os.system('adb shell am start com.google.android.youtube/.HomeActivity')
+ time.sleep(1)
+ os.system('adb shell am start com.google.android.gm/.GmailActivity')
+ time.sleep(3)
+ os.system('adb shell am force-stop com.iamywang.sampler')
+ os.system('adb shell am force-stop com.microsoft.office.onenote')
+ os.system('adb shell am force-stop com.google.android.youtube')
+ os.system('adb shell am force-stop com.google.android.gm')
+ time.sleep(1)
+
+ # kind 40: on gm tg
+ rounds += 1
+ timestamp2 = time.time()
+ print("round %d: %fs" % (rounds, timestamp2 - timestamp1))
+
+ while not os.path.exists(args[-1] + str(rounds - 1) + '.txt'):
+ os.system('adb shell am start com.microsoft.office.onenote/.ui.EntryActivity')
+ os.system('adb shell am start com.google.android.gm/.GmailActivity')
+ os.system('adb shell am start org.telegram.messenger.web/org.telegram.ui.LaunchActivity')
+ time.sleep(3)
+ os.system('adb shell am start com.iamywang.sampler/.MainActivity')
+ time.sleep(1)
+ os.system('adb shell am start com.microsoft.office.onenote/.ui.EntryActivity')
+ time.sleep(1)
+ os.system('adb shell am start com.google.android.gm/.GmailActivity')
+ time.sleep(1)
+ os.system('adb shell am start org.telegram.messenger.web/org.telegram.ui.LaunchActivity')
+ time.sleep(3)
+ os.system('adb shell am force-stop com.iamywang.sampler')
+ os.system('adb shell am force-stop com.microsoft.office.onenote')
+ os.system('adb shell am force-stop com.google.android.gm')
+ os.system('adb shell am force-stop org.telegram.messenger.web')
+ time.sleep(1)
+
+
+# =============================================================================
+# Main
+# =============================================================================
+if __name__ == '__main__':
+ if not os.path.exists('data/exp4-complex/sequence/17_0.txt'):
+ seq_2b(200, args_xiaomi_9)
+ data_set_label('data/Xiaomi Xiaomi MI 9/12 32/test/', 2400, 12, 17)
+ data_move('data/Xiaomi Xiaomi MI 9/12 32/test/', 'data/exp4-complex/sequence/')
+ if not os.path.exists('data/exp4-complex/sequence/29_0.txt'):
+ seq_3b(200, args_xiaomi_9)
+ data_set_label('data/Xiaomi Xiaomi MI 9/12 32/test/', 2400, 12, 29)
+ data_move('data/Xiaomi Xiaomi MI 9/12 32/test/', 'data/exp4-complex/sequence/')
diff --git a/figures/fig15-overhead.py b/figures/fig15-overhead.py
new file mode 100755
index 0000000..9ecc610
--- /dev/null
+++ b/figures/fig15-overhead.py
@@ -0,0 +1,142 @@
+# =============================================================================
+# This file is part of EavesDroid.
+#
+# Author: iamywang
+# Date Created: Jan 27, 2024
+# =============================================================================
+import os
+import numpy as np
+import matplotlib.pyplot as plt
+
+types = ['time', 'power', 'traffic', 'compute']
+
+def time_overhead():
+ accu = np.loadtxt('data/exp2-overhead/time_total.txt', delimiter=',')
+ accu = accu * 1000
+ accu = accu.astype(int)
+
+ less_40 = 0
+ for i in range(25, 40):
+ less_40 += np.sum(accu == i)
+ print(less_40, len(accu), less_40/len(accu))
+ print(np.average(accu))
+ print(np.min(accu), np.max(accu))
+
+ plt.rc('font', family='Arial', size=28)
+ for i in range(25, 81):
+ colors = ['tab:blue', 'tab:orange', 'tab:green', 'tab:red']
+ plt.bar(i, np.sum(accu == i), color=colors[0], edgecolor='black')
+ plt.ylabel('Number of behaviors')
+ plt.xlabel('Inference time (ms)')
+ plt.xticks(np.arange(26, 81, 18))
+ plt.tight_layout()
+ plt.savefig("../paper/ieee/fig15.pdf", format='pdf')
+ plt.close()
+
+
+def power_overhead():
+ devices = ['OPPO K10', 'Redmi K50']
+ labels = ['With EavesDroid', 'Without EavesDroid']
+ accu = [
+ [320.6, 377.1],
+ [295.7, 348.6]
+ ]
+
+ print(accu[0][0]-accu[1][0], (accu[0][0]-accu[1][0])/accu[0][0])
+ print(accu[0][1]-accu[1][1], (accu[0][1]-accu[1][1])/accu[0][1])
+ print(((accu[0][0]-accu[1][0])/accu[0][0] + (accu[0][1]-accu[1][1])/accu[0][1])/2)
+
+ plt.rc('font', family='Arial', size=28)
+ colors = ['tab:blue', 'tab:orange', 'tab:green', 'tab:red']
+ bar_width = 0.3
+ bar_x = np.arange(len(labels))
+ for i in range(2):
+ bar1 = plt.bar(bar_x[i] - bar_width/2 - 0.02, accu[0][i], width=bar_width, color=colors[0], edgecolor='black', hatch='/')
+ bar2 = plt.bar(bar_x[i] + bar_width/2 + 0.02, accu[1][i], width=bar_width, color=colors[1], edgecolor='black', hatch='\\')
+ plt.legend((bar1, bar2), labels, fontsize=20, labelspacing=0.2)
+ plt.ylabel('Power consumption (mA)')
+ plt.xticks(bar_x, devices)
+ plt.ylim(0, 599)
+ plt.tight_layout()
+ plt.savefig("../paper/ieee/fig16.pdf", format='pdf')
+ plt.close()
+
+
+def compute_overhead():
+ labels = ['CPU', 'Memory']
+
+ cpu_overhead = np.loadtxt('data/exp2-overhead/cpu_overhead.txt')[0:960]
+ cpu_overhead = cpu_overhead / 10
+ print(np.min(cpu_overhead), np.max(cpu_overhead), np.average(cpu_overhead))
+ cpu_overhead = cpu_overhead.reshape(-1, 60)
+ cpu_overhead = np.average(cpu_overhead, axis=1)
+ mem_overhead = np.loadtxt('data/exp2-overhead/memory_overhead.txt')[0:960]
+ mem_overhead = mem_overhead / 10
+ print(np.min(mem_overhead), np.max(mem_overhead), np.average(mem_overhead))
+ mem_overhead = mem_overhead.reshape(-1, 60)
+ mem_overhead = np.average(mem_overhead, axis=1)
+ index = np.arange(len(cpu_overhead))
+ index += 1
+
+ plt.rc('font', family='Arial', size=28)
+ colors = ['tab:blue', 'tab:orange', 'tab:green', 'tab:red']
+ plt.xlabel('Time (min)')
+
+ ax1 = plt.subplot(111)
+ ax1.plot(index, cpu_overhead, color=colors[0], marker='o', lw=2, label=labels[0])
+ ax1.set_ylabel('CPU overhead (%)')
+ ax1.set_ylim(0, 149)
+
+ ax2 = ax1.twinx()
+ ax2.bar(index, mem_overhead, width=0.6, color=colors[1], label=labels[1], edgecolor='black')
+ ax2.set_ylabel('Memory overhead (MB)')
+ ax2.set_ylim(0, 59)
+
+ plt.legend((ax1.lines[0], ax2.patches[0]), labels, fontsize=20, labelspacing=0.2)
+
+ plt.xticks(np.arange(1, 17, 5))
+ plt.tight_layout()
+ plt.savefig("../paper/ieee/fig17.pdf", format='pdf')
+ plt.close()
+
+
+def network_overhead():
+ path = ['data/exp3-adaptability/cross/OPPO OPPO PGJM10/', 'data/exp3-adaptability/cross/Xiaomi Redmi 22041211AC/', 'data/exp3-adaptability/cross/Xiaomi Xiaomi MI 9/12 32/']
+ devices = ['OPPO K10', 'Redmi K50', 'Xiaomi 9']
+ sizes = []
+ plt.rc('font', family='Arial', size=28)
+ for i in range(len(devices)):
+ files = os.listdir(path[i])
+
+ files_size = []
+ for file in files:
+ files_size.append(os.path.getsize(path[i] + file))
+ files_size = np.array(files_size)
+ files_size = files_size / 1024
+ sizes.append(files_size)
+
+
+ colors = ['tab:blue', 'tab:orange', 'tab:green', 'tab:red']
+ bar_width = 0.3
+ bar_x = np.arange(len(devices))
+ plt.barh(bar_x[0], np.max(sizes[0]) - np.min(sizes[0]), height=bar_width, color=colors[0], edgecolor='black', left=np.min(sizes[0]))
+ plt.barh(bar_x[1], np.max(sizes[1]) - np.min(sizes[1]), height=bar_width, color=colors[0], edgecolor='black', left=np.min(sizes[1]))
+ plt.barh(bar_x[2], np.max(sizes[2]) - np.min(sizes[2]), height=bar_width, color=colors[0], edgecolor='black', left=np.min(sizes[2]))
+ plt.vlines(np.mean(sizes[0]), bar_x[0] - bar_width/2, bar_x[0] + bar_width/2, color=colors[1], linestyles='--', linewidth=2)
+ plt.vlines(np.mean(sizes[1]), bar_x[1] - bar_width/2, bar_x[1] + bar_width/2, color=colors[1], linestyles='--', linewidth=2)
+ plt.vlines(np.mean(sizes[2]), bar_x[2] - bar_width/2, bar_x[2] + bar_width/2, color=colors[1], linestyles='--', linewidth=2)
+ plt.xlabel('Packet size (KB)')
+ plt.yticks(bar_x, devices)
+ plt.xlim(181, 196)
+ plt.xticks(np.arange(181, 197, 5))
+ plt.tight_layout()
+ plt.savefig("../paper/ieee/fig18.pdf", format='pdf')
+ plt.close()
+
+ print(np.mean(sizes[0]), np.mean(sizes[1]), np.mean(sizes[2]), np.mean(sizes))
+ print(np.min(sizes), np.max(sizes))
+
+time_overhead()
+power_overhead()
+network_overhead()
+compute_overhead()
\ No newline at end of file
diff --git a/figures/fig19-adaptability.py b/figures/fig19-adaptability.py
new file mode 100755
index 0000000..b736ea0
--- /dev/null
+++ b/figures/fig19-adaptability.py
@@ -0,0 +1,35 @@
+# =============================================================================
+# This file is part of EavesDroid.
+#
+# Author: iamywang
+# Date Created: Jan 27, 2024
+# =============================================================================
+import numpy as np
+import matplotlib.pyplot as plt
+
+apps = ['Telegram', 'Youtube', 'Gmail', 'OneNote', 'All']
+devices = ['SM SV', 'SM DV', 'DM SV', 'DM DV']
+accu = [
+ [0.9792, 0.9667, 1.0000, 0.9750, 0.9755],
+ [0.5663, 0.4590, 0.6025, 0.3025, 0.3076],
+ [0.9688, 0.9060, 0.9388, 0.9262, 0.8212],
+ [0.6162, 0.3650, 0.5028, 0.6700, 0.2183]
+ ]
+
+plt.rc('font', family='Arial', size=20)
+for i in range(5):
+ plt.ylabel('Accuracy')
+ colors = ['tab:blue', 'tab:orange', 'tab:green', 'tab:red']
+ bar_width = 0.15
+ bar_x = np.arange(len(apps))
+ bar1 = plt.bar(bar_x[i] - 3 * bar_width/2 - 0.06, accu[0][i], width=bar_width, color=colors[0], edgecolor='black', hatch='/')
+ bar2 = plt.bar(bar_x[i] - bar_width/2 - 0.02, accu[1][i], width=bar_width, color=colors[1], edgecolor='black', hatch='\\')
+ bar3 = plt.bar(bar_x[i] + bar_width/2 + 0.02, accu[2][i], width=bar_width, color=colors[2], edgecolor='black', hatch='o')
+ bar4 = plt.bar(bar_x[i] + 3 * bar_width/2 + 0.06, accu[3][i], width=bar_width, color=colors[3], edgecolor='black', hatch='*')
+plt.legend((bar1, bar2, bar3, bar4), devices, fontsize=16, labelspacing=0.2, ncol=2)
+plt.xticks(bar_x, apps, rotation=30)
+plt.ylim(0, 1.4)
+plt.yticks(np.arange(0, 1.5, 0.5))
+plt.tight_layout()
+plt.savefig("../paper/ieee/fig19.pdf", format='pdf')
+plt.close()
diff --git a/figures/fig2-verify.py b/figures/fig2-verify.py
new file mode 100755
index 0000000..54f1835
--- /dev/null
+++ b/figures/fig2-verify.py
@@ -0,0 +1,58 @@
+# =============================================================================
+# This file is part of EavesDroid.
+#
+# Author: iamywang
+# Date Created: Jan 27, 2024
+# =============================================================================
+import numpy as np
+import matplotlib.pyplot as plt
+
+file1 = 'data/exp0-figures/OPPO OPPO PGJM10/2_286.txt'
+file2 = 'data/exp0-figures/OPPO OPPO PGJM10/2_202.txt'
+file3 = 'data/exp0-figures/OPPO OPPO PGJM10/2_142.txt'
+file4 = 'data/exp0-figures/OPPO OPPO PGJM10/1_157.txt'
+file5 = 'data/exp0-figures/OPPO OPPO PGJM10/2_226.txt'
+file6 = 'data/exp0-figures/OPPO OPPO PGJM10/3_159.txt'
+
+
+# norm
+d_sets = np.zeros([6, 5000, 4], np.double)
+colors = ['tab:blue', 'tab:red', 'tab:green']
+for i in range(4):
+ d_sets[0, :, i] = np.loadtxt(file1, delimiter=',', usecols=i)
+ d_sets[1, :, i] = np.loadtxt(file2, delimiter=',', usecols=i)
+ d_sets[2, :, i] = np.loadtxt(file3, delimiter=',', usecols=i)
+ d_sets[3, :, i] = np.loadtxt(file4, delimiter=',', usecols=i)
+ d_sets[4, :, i] = np.loadtxt(file5, delimiter=',', usecols=i)
+ d_sets[5, :, i] = np.loadtxt(file6, delimiter=',', usecols=i)
+
+
+plt.rc('font', family='Arial', size=28)
+plt.ylabel('processes (number)')
+plt.xlabel('timestamp (ms)')
+line_styles = ['-', '--', '-.']
+markers = ['o', 's', 'D']
+plt.plot(d_sets[3, :, 0], lw = 3, color = colors[0], linestyle=line_styles[0], marker=markers[0], markevery=500)
+plt.plot(d_sets[4, :, 0], lw = 3, color = colors[1], linestyle=line_styles[1], marker=markers[1], markevery=500)
+plt.plot(d_sets[5, :, 0], lw = 3, color = colors[2], linestyle=line_styles[2], marker=markers[2], markevery=500)
+plt.legend(['View', 'Send', 'Info'], fontsize=20, labelspacing=0.2, ncol=1)
+plt.ylim(4490, 4650)
+plt.xticks(np.arange(0, 5001, 2500))
+plt.tight_layout()
+plt.savefig("../paper/ieee/fig2a.pdf", format='pdf')
+plt.close()
+
+plt.rc('font', family='Arial', size=28)
+plt.ylabel('processes (number)')
+plt.xlabel('timestamp (ms)')
+line_styles = ['-', '--', '-.']
+markers = ['o', 's', 'D']
+plt.plot(d_sets[0, :, 0], lw = 3, color = colors[0], linestyle=line_styles[0], marker=markers[0], markevery=500)
+plt.plot(d_sets[1, :, 0], lw = 3, color = colors[1], linestyle=line_styles[1], marker=markers[1], markevery=500)
+plt.plot(d_sets[2, :, 0], lw = 3, color = colors[2], linestyle=line_styles[2], marker=markers[2], markevery=500)
+plt.legend(['Send (1)', 'Send (2)', 'Send (3)'], fontsize=20, labelspacing=0.2, ncol=1)
+plt.ylim(4540, 4620)
+plt.xticks(np.arange(0, 5001, 2500))
+plt.tight_layout()
+plt.savefig("../paper/ieee/fig2b.pdf", format='pdf')
+plt.close()
diff --git a/figures/fig20-complex.py b/figures/fig20-complex.py
new file mode 100755
index 0000000..777863a
--- /dev/null
+++ b/figures/fig20-complex.py
@@ -0,0 +1,98 @@
+# =============================================================================
+# This file is part of EavesDroid.
+#
+# Author: iamywang
+# Date Created: Jan 27, 2024
+# =============================================================================
+import numpy as np
+import matplotlib.pyplot as plt
+
+def noise():
+ apps = ['Telegram', 'Youtube', 'Gmail', 'OneNote', 'All']
+ devices = ['0 proc', '1 proc', '2 procs', '3 procs']
+ accu = [
+ [1.0000, 1.0000, 0.9887, 0.9438, 0.9841], # 0
+ [0.9663, 0.8380, 0.8525, 0.8112, 0.8653], # 1
+ [0.8375, 0.7010, 0.6913, 0.7188, 0.7350], # 2
+ [0.8062, 0.6850, 0.6000, 0.7575, 0.6993], # 3
+ ]
+
+ plt.rc('font', family='Arial', size=24)
+ for i in range(5):
+ plt.ylabel('Accuracy')
+ colors = ['tab:blue', 'tab:orange', 'tab:green', 'tab:red']
+ bar_width = 0.15
+ bar_x = np.arange(len(apps))
+ bar1 = plt.bar(bar_x[i] - 3 * bar_width/2 - 0.06, accu[0][i], width=bar_width, color=colors[0], edgecolor='black', hatch='/')
+ bar2 = plt.bar(bar_x[i] - bar_width/2 - 0.02, accu[1][i], width=bar_width, color=colors[1], edgecolor='black', hatch='\\')
+ bar3 = plt.bar(bar_x[i] + bar_width/2 + 0.02, accu[2][i], width=bar_width, color=colors[2], edgecolor='black', hatch='o')
+ bar4 = plt.bar(bar_x[i] + 3 * bar_width/2 + 0.06, accu[3][i], width=bar_width, color=colors[3], edgecolor='black', hatch='*')
+ plt.legend((bar1, bar2, bar3, bar4), devices, fontsize=18, labelspacing=0.2, ncol=2)
+ plt.xticks(bar_x, apps, rotation=30)
+ plt.ylim(0, 1.499999)
+ plt.tight_layout()
+ plt.savefig("../paper/ieee/fig20.pdf", format='pdf')
+ plt.close()
+
+
+def noise2():
+ apps = ['Telegram', 'Youtube', 'Gmail', 'OneNote', 'All']
+ devices = ['0 proc', '1 proc', '2 procs', '3 procs']
+ accu = [
+ [0.9711, 0.9641, 0.9877, 0.9912, 0.9775], # 0
+ [0.9959, 0.9837, 0.9754, 0.9605, 0.9794], # 1
+ [0.9380, 0.9379, 0.9221, 0.8947, 0.9245], # 2
+ [0.9421, 0.8529, 0.8975, 0.9298, 0.9020], # 3
+ ]
+
+ plt.rc('font', family='Arial', size=24)
+ for i in range(5):
+ plt.ylabel('Accuracy')
+ colors = ['tab:blue', 'tab:orange', 'tab:green', 'tab:red']
+ bar_width = 0.15
+ bar_x = np.arange(len(apps))
+ bar1 = plt.bar(bar_x[i] - 3 * bar_width/2 - 0.06, accu[0][i], width=bar_width, color=colors[0], edgecolor='black', hatch='/')
+ bar2 = plt.bar(bar_x[i] - bar_width/2 - 0.02, accu[1][i], width=bar_width, color=colors[1], edgecolor='black', hatch='\\')
+ bar3 = plt.bar(bar_x[i] + bar_width/2 + 0.02, accu[2][i], width=bar_width, color=colors[2], edgecolor='black', hatch='o')
+ bar4 = plt.bar(bar_x[i] + 3 * bar_width/2 + 0.06, accu[3][i], width=bar_width, color=colors[3], edgecolor='black', hatch='*')
+ plt.legend((bar1, bar2, bar3, bar4), devices, fontsize=18, labelspacing=0.2, ncol=2)
+ plt.xticks(bar_x, apps, rotation=30)
+ plt.ylim(0, 1.499999)
+ plt.tight_layout()
+ plt.savefig("../paper/ieee/fig21.pdf", format='pdf')
+ plt.close()
+
+
+def pattern():
+ apps = ['1 char', '2 chars', '3 chars', '4 chars']
+ devices = ['0.2s', '0.4s', '0.6s', '0.8s', '1.0s']
+ accu = [
+ [0.9550, 0.9450, 0.9700, 0.9700], # 0.2
+ [0.9900, 0.9700, 0.9650, 0.9600], # 0.4
+ [0.9400, 0.9600, 0.9400, 0.9600], # 0.6
+ [0.9400, 0.9700, 0.9400, 0.9600], # 0.8
+ [0.9400, 0.9200, 0.9300, 0.9200], # 1.0
+ ]
+
+ plt.rc('font', family='Arial', size=24)
+ for i in range(4):
+ plt.ylabel('Accuracy')
+ colors = ['tab:blue', 'tab:orange', 'tab:green', 'tab:red', 'tab:purple']
+ bar_width = 0.12
+ bar_x = np.arange(len(apps))
+ bar1 = plt.bar(bar_x[i] - 4 * bar_width/2 - 0.08, accu[0][i], width=bar_width, color=colors[0], edgecolor='black', hatch='/')
+ bar2 = plt.bar(bar_x[i] - 2 * bar_width/2 - 0.04, accu[1][i], width=bar_width, color=colors[1], edgecolor='black', hatch='\\')
+ bar3 = plt.bar(bar_x[i], accu[2][i], width=bar_width, color=colors[2], edgecolor='black', hatch='o')
+ bar4 = plt.bar(bar_x[i] + 2 * bar_width/2 + 0.04, accu[3][i], width=bar_width, color=colors[3], edgecolor='black', hatch='*')
+ bar5 = plt.bar(bar_x[i] + 4 * bar_width/2 + 0.08, accu[4][i], width=bar_width, color=colors[4], edgecolor='black', hatch='xx')
+ plt.legend((bar1, bar2, bar3, bar4, bar5), devices, fontsize=18, labelspacing=0.2, ncol=2)
+ plt.xticks(bar_x, apps, rotation=30)
+ plt.ylim(0, 1.599999)
+ plt.yticks(np.arange(0, 1.5, 0.5))
+ plt.tight_layout()
+ plt.savefig("../paper/ieee/fig22.pdf", format='pdf')
+ plt.close()
+
+noise()
+noise2()
+pattern()
\ No newline at end of file
diff --git a/figures/fig25-realworld.py b/figures/fig25-realworld.py
new file mode 100755
index 0000000..98f0333
--- /dev/null
+++ b/figures/fig25-realworld.py
@@ -0,0 +1,32 @@
+# =============================================================================
+# This file is part of EavesDroid.
+#
+# Author: iamywang
+# Date Created: Jan 27, 2024
+# =============================================================================
+import numpy as np
+import matplotlib.pyplot as plt
+
+# accuracy
+apps = ['User 1', 'User 2', 'User 3', 'User 4', 'User 5', 'User 6']
+devices = ['Model with noisy data', 'Model without noisy data']
+accu = [
+ [0.6667, 0.6875, 0.6316, 0.6190, 0.6842, 0.7059], # 0.6658
+ [0.8571, 0.9412, 0.8125, 0.8333, 0.8750, 0.8421], # 0.8602
+]
+
+plt.rc('font', family='Arial', size=20)
+for i in range(6):
+ plt.ylabel('Accuracy')
+ colors = ['tab:blue', 'tab:orange']
+ bar_width = 0.3
+ bar_x = np.arange(len(apps))
+ bar1 = plt.bar(bar_x[i] - bar_width/2 - 0.02, accu[0][i], width=bar_width, color=colors[0], edgecolor='black', hatch='/')
+ bar2 = plt.bar(bar_x[i] + bar_width/2 + 0.02, accu[1][i], width=bar_width, color=colors[1], edgecolor='black', hatch='\\')
+plt.legend((bar1, bar2), devices, fontsize=16, labelspacing=0.2)
+plt.xticks(bar_x, apps, rotation=30)
+plt.ylim(0, 1.3)
+plt.yticks(np.arange(0, 1.5, 0.5))
+plt.tight_layout()
+plt.savefig("../paper/ieee/fig25.pdf", format='pdf')
+plt.close()
diff --git a/figures/fig3-syscall.py b/figures/fig3-syscall.py
new file mode 100755
index 0000000..54cc271
--- /dev/null
+++ b/figures/fig3-syscall.py
@@ -0,0 +1,109 @@
+# =============================================================================
+# This file is part of EavesDroid.
+#
+# Author: iamywang
+# Date Created: Jan 27, 2024
+# =============================================================================
+import os
+import numpy as np
+import matplotlib.pyplot as plt
+
+path = 'data/exp1-accuracy_additional_impact/normal/OPPO OPPO PGJM10/'
+flist = os.listdir(path)
+d_sets = np.zeros([len(flist), 5000, 5], int)
+d_sets_scaled = np.zeros([len(flist), 5000, 5], np.double)
+d_labels = np.zeros([len(flist)], int)
+
+ab = ['a', 'b', 'c', 'd']
+
+for i in range(len(flist)):
+ d_labels[i] = int(flist[i].split('_')[0])
+ for j in range(5):
+ d_sets[i, :, j] = np.loadtxt(path + flist[i], delimiter=',', usecols=j)
+ d_sets_scaled[i, :, j] = (d_sets[i, :, j] - np.min(d_sets[i, :, j])) / (np.max(d_sets[i, :, j]) - np.min(d_sets[i, :, j]))
+
+plt.rc('font', family='Arial', size=28)
+y_labels = ["free inodes (number)", "avail memory (Byte)"]
+for i in range(2):
+ # 4 feature
+ plt.ylabel(y_labels[i])
+ plt.xlabel('timestamp (ms)')
+ colors = ['tab:blue', 'tab:red', 'tab:green']
+ line_styles = ['-', '--']
+ markers = ['o', 's', 'D']
+ for c in range(2):
+ # 4 category
+ plt.plot(np.mean(d_sets[d_labels == c+1, :, i+3], axis=0), lw=3, color=colors[c],
+ linestyle=line_styles[c], marker=markers[c], markevery=500)
+
+ plt.legend(['View', 'Send'], fontsize=20, labelspacing=0.2)
+ # plt.title('feature ' + str(i))
+ plt.xticks(np.arange(0, 5001, 2500))
+ if i == 1:
+ plt.gca().yaxis.set_major_formatter(lambda x, pos: str(int(x/1e6)) + 'M')
+ plt.ylim(3e8, 4.5e8)
+ plt.gca().tick_params(axis='y')
+ if i == 0:
+ plt.gca().yaxis.set_major_formatter(lambda x, pos: str(int(x - 1.27911e7)))
+ plt.ylim(15 + 1.27911e7, 45 + 1.27911e7)
+ plt.text(0.00, 1.02, '+12.7911M', transform=plt.gca().transAxes, ha='left')
+ plt.gca().tick_params(axis='y')
+ plt.tight_layout()
+ plt.savefig("../paper/ieee/fig3" + ab[i] + ".pdf", format='pdf')
+ plt.close()
+
+d_sets_0 = np.zeros([int(len(flist)/2), 5000, 5], int)
+d_sets_1 = np.zeros([int(len(flist)/2), 5000, 5], int)
+d_labels_0 = np.zeros([int(len(flist)/2)], int)
+d_labels_1 = np.zeros([int(len(flist)/2)], int)
+
+for i in range(int(len(flist)/2)):
+ d_labels_0[i] = d_labels[i]
+ d_labels_1[i] = d_labels[i+int(len(flist)/2)]
+ for j in range(5):
+ d_sets_0[i, :, j] = d_sets[i, :, j]
+ d_sets_1[i, :, j] = d_sets[i+int(len(flist)/2), :, j]
+
+def fig4c():
+ plt.rc('font', family='Arial', size=28)
+ plt.ylabel(y_labels[0])
+ plt.xlabel('timestamp (ms)')
+ colors = ['tab:blue', 'tab:red', 'tab:green']
+ line_styles = ['-', '--']
+ markers = ['o', 's', 'D']
+ plt.plot(np.mean(d_sets_0[d_labels_0 == 1, :, 3], axis=0), lw=3, color=colors[0],
+ linestyle=line_styles[0], marker=markers[0], markevery=500)
+ plt.plot(np.mean(d_sets_1[d_labels_1 == 1, :, 3], axis=0), lw=3, color=colors[1],
+ linestyle=line_styles[1], marker=markers[1], markevery=500)
+ plt.legend(['View (1)', 'View (2)'], fontsize=20, labelspacing=0.2)
+ plt.xticks(np.arange(0, 5001, 2500))
+ plt.gca().yaxis.set_major_formatter(lambda x, pos: str(int(x - 1.27911e7)))
+ plt.ylim(15 + 1.27911e7, 45 + 1.27911e7)
+ plt.text(0.00, 1.02, '+12.7911M', transform=plt.gca().transAxes, ha='left')
+ plt.gca().tick_params(axis='y')
+ plt.tight_layout()
+ plt.savefig("../paper/ieee/fig3c.pdf", format='pdf')
+ plt.close()
+
+def fig4d():
+ plt.rc('font', family='Arial', size=28)
+ plt.ylabel(y_labels[1])
+ plt.xlabel('timestamp (ms)')
+ colors = ['tab:blue', 'tab:red', 'tab:green']
+ line_styles = ['-', '--']
+ markers = ['o', 's', 'D']
+ plt.plot(np.mean(d_sets_0[d_labels_0 == 1, :, 4], axis=0), lw=3, color=colors[0],
+ linestyle=line_styles[0], marker=markers[0], markevery=500)
+ plt.plot(np.mean(d_sets_1[d_labels_1 == 1, :, 4], axis=0), lw=3, color=colors[1],
+ linestyle=line_styles[1], marker=markers[1], markevery=500)
+ plt.legend(['View (1)', 'View (2)'], fontsize=20, labelspacing=0.2)
+ plt.xticks(np.arange(0, 5001, 2500))
+ plt.gca().yaxis.set_major_formatter(lambda x, pos: str(int(x/1e6)) + 'M')
+ plt.ylim(3e8, 4.5e8)
+ plt.gca().tick_params(axis='y')
+ plt.tight_layout()
+ plt.savefig("../paper/ieee/fig3d.pdf", format='pdf')
+ plt.close()
+
+fig4c()
+fig4d()
diff --git a/figures/fig5-normalize.py b/figures/fig5-normalize.py
new file mode 100755
index 0000000..817d367
--- /dev/null
+++ b/figures/fig5-normalize.py
@@ -0,0 +1,54 @@
+# =============================================================================
+# This file is part of EavesDroid.
+#
+# Author: iamywang
+# Date Created: Jan 27, 2024
+# =============================================================================
+import numpy as np
+import matplotlib.pyplot as plt
+
+file1 = 'data/exp0-figures/OPPO OPPO PGJM10/0_280.txt'
+file2 = 'data/exp0-figures/OPPO OPPO PGJM10/0_224.txt'
+file3 = 'data/exp0-figures/OPPO OPPO PGJM10/0_136.txt'
+
+# norm
+d_sets = np.zeros([4, 5000, 4], np.double)
+d_sets_scaled = np.zeros([4, 5000, 4], np.double)
+colors = ['tab:blue', 'tab:red', 'tab:green']
+for i in range(4):
+ d_sets[0, :, i] = np.loadtxt(file1, delimiter=',', usecols=i)
+ d_sets[1, :, i] = np.loadtxt(file2, delimiter=',', usecols=i)
+ d_sets[2, :, i] = np.loadtxt(file3, delimiter=',', usecols=i)
+
+ d_sets_scaled[0, :, i] = (d_sets[0, :, i] - np.min(d_sets[0, :, i])) / (np.max(d_sets[0, :, i]) - np.min(d_sets[0, :, i]))
+ d_sets_scaled[1, :, i] = (d_sets[1, :, i] - np.min(d_sets[1, :, i])) / (np.max(d_sets[1, :, i]) - np.min(d_sets[1, :, i]))
+ d_sets_scaled[2, :, i] = (d_sets[2, :, i] - np.min(d_sets[2, :, i])) / (np.max(d_sets[2, :, i]) - np.min(d_sets[2, :, i]))
+
+plt.rc('font', family='Arial', size=28)
+plt.ylabel('processes (number)')
+plt.xlabel('timestamp (ms)')
+line_styles = ['-', '--', '-.']
+markers = ['o', 's', 'D']
+plt.plot(d_sets[0, :, 0], lw = 3, color = colors[0], linestyle=line_styles[0], marker=markers[0], markevery=500)
+plt.plot(d_sets[1, :, 0], lw = 3, color = colors[1], linestyle=line_styles[1], marker=markers[1], markevery=500)
+plt.plot(d_sets[2, :, 0], lw = 3, color = colors[2], linestyle=line_styles[2], marker=markers[2], markevery=500)
+plt.legend(['Launch (1)', 'Launch (2)', 'Launch (3)'], fontsize=20, labelspacing=0.2)
+plt.tight_layout()
+plt.ylim(4490, 4555)
+plt.xticks(np.arange(0, 5001, 2500))
+plt.savefig("../paper/ieee/fig5a.pdf", format='pdf')
+plt.close()
+
+plt.ylabel('normalized value')
+plt.xlabel('timestamp (ms)')
+line_styles = ['-', '--', '-.']
+markers = ['o', 's', 'D']
+plt.plot(d_sets_scaled[0, :, 0], lw = 3, color = colors[0], linestyle=line_styles[0], marker=markers[0], markevery=500)
+plt.plot(d_sets_scaled[1, :, 0], lw = 3, color = colors[1], linestyle=line_styles[1], marker=markers[1], markevery=500)
+plt.plot(d_sets_scaled[2, :, 0], lw = 3, color = colors[2], linestyle=line_styles[2], marker=markers[2], markevery=500)
+plt.legend(['Launch (1)', 'Launch (2)', 'Launch (3)'], fontsize=20, labelspacing=0.2)
+plt.tight_layout()
+plt.ylim(0, 1.199999)
+plt.xticks(np.arange(0, 5001, 2500))
+plt.savefig("../paper/ieee/fig5b.pdf", format='pdf')
+plt.close()
diff --git a/figures/fig6-combine.py b/figures/fig6-combine.py
new file mode 100755
index 0000000..a208a02
--- /dev/null
+++ b/figures/fig6-combine.py
@@ -0,0 +1,64 @@
+# =============================================================================
+# This file is part of EavesDroid.
+#
+# Author: iamywang
+# Date Created: Jan 27, 2024
+# =============================================================================
+import os
+import numpy as np
+import matplotlib.pyplot as plt
+
+path = 'data/exp0-figures/OnePlus OnePlus GM1910/'
+flist = os.listdir(path)
+d_sets = np.zeros([len(flist), 5000, 4], int)
+d_sets_scaled = np.zeros([len(flist), 5000, 4], np.double)
+d_labels = np.zeros([len(flist)], int)
+
+ab = ['a', 'b', 'c', 'd']
+
+for i in range(len(flist)):
+ d_labels[i] = flist[i].split('_')[0]
+ for j in range(4):
+ d_sets[i, :, j] = np.loadtxt(path + flist[i], delimiter=',', usecols=j)
+ d_sets_scaled[i, :, j] = (d_sets[i, :, j] - np.min(d_sets[i, :, j])) / (np.max(d_sets[i, :, j]) - np.min(d_sets[i, :, j]))
+
+plt.rc('font', family='Arial', size=28)
+for i in range(2):
+ # 4 feature
+ plt.ylabel('normalized value')
+ plt.xlabel('timestamp (ms)')
+ colors = ['tab:blue', 'tab:red', 'tab:green']
+ line_styles = ['-', '--']
+ markers = ['o', 's', 'D']
+ for c in range(2):
+ # 4 category
+ plt.plot(np.mean(d_sets_scaled[d_labels == (c+1)*4, :, i], axis=0),
+ lw=3, color=colors[c], linestyle=line_styles[c],
+ marker=markers[c], markevery=500)
+ plt.legend(['Playing', 'Pausing'], fontsize=20, labelspacing=0.2)
+ # plt.title('feature ' + str(i))
+ plt.tight_layout()
+ plt.ylim(0, 1.49999)
+ plt.xticks(np.arange(0, 5001, 2500))
+ plt.savefig("../paper/ieee/fig6" + ab[i] + ".pdf", format='pdf')
+ plt.close()
+
+plt.rc('font', family='Arial', size=28)
+for i in range(2):
+ # 4 feature
+ plt.ylabel('normalized value')
+ plt.xlabel('timestamp (ms)')
+ colors = ['tab:blue', 'tab:red', 'tab:green']
+ line_styles = ['-', '--']
+ for c in range(2):
+ # 4 category
+ plt.plot(np.mean(d_sets_scaled[d_labels == 4 + c, :, i], axis=0),
+ lw=3, color=colors[c], linestyle=line_styles[c],
+ marker=markers[c], markevery=500)
+ plt.legend(['Launch', 'View'], fontsize=20, labelspacing=0.2, loc='upper right')
+ # plt.title('feature ' + str(i))
+ plt.tight_layout()
+ plt.ylim(0, 1.49999)
+ plt.xticks(np.arange(0, 5001, 2500))
+ plt.savefig("../paper/ieee/fig6" + ab[i+2] + ".pdf", format='pdf')
+ plt.close()
\ No newline at end of file
diff --git a/figures/fig7-accuracy.py b/figures/fig7-accuracy.py
new file mode 100755
index 0000000..e3ab6d0
--- /dev/null
+++ b/figures/fig7-accuracy.py
@@ -0,0 +1,32 @@
+# =============================================================================
+# This file is part of EavesDroid.
+#
+# Author: iamywang
+# Date Created: Jan 27, 2024
+# =============================================================================
+import numpy as np
+import matplotlib.pyplot as plt
+
+
+apps = ['Telegram', 'Youtube', 'Gmail', 'OneNote', 'All']
+devices = ['OPPO K10', 'Redmi K50']
+accu = [
+ [0.9792, 0.9667, 1.0000, 0.9750, 0.9755],
+ [0.9958, 0.9700, 1.0000, 0.9917, 0.9863]
+]
+
+plt.rc('font', family='Arial', size=20)
+for i in range(5):
+ plt.ylabel('Accuracy')
+ colors = ['tab:blue', 'tab:orange']
+ bar_width = 0.3
+ bar_x = np.arange(len(apps))
+ bar1 = plt.bar(bar_x[i] - bar_width/2 - 0.02, accu[0][i], width=bar_width, color=colors[0], edgecolor='black', hatch='/')
+ bar2 = plt.bar(bar_x[i] + bar_width/2 + 0.02, accu[1][i], width=bar_width, color=colors[1], edgecolor='black', hatch='\\')
+plt.legend((bar1, bar2), devices, fontsize=16, labelspacing=0.2, ncol=2)
+plt.xticks(bar_x, apps, rotation=30)
+plt.ylim(0, 1.3)
+plt.yticks(np.arange(0, 1.5, 0.5))
+plt.tight_layout()
+plt.savefig("../paper/ieee/fig7.pdf", format='pdf')
+plt.close()
\ No newline at end of file
diff --git a/figures/fig8-additional.py b/figures/fig8-additional.py
new file mode 100755
index 0000000..53fdaf2
--- /dev/null
+++ b/figures/fig8-additional.py
@@ -0,0 +1,32 @@
+# =============================================================================
+# This file is part of EavesDroid.
+#
+# Author: iamywang
+# Date Created: Jan 27, 2024
+# =============================================================================
+import numpy as np
+import matplotlib.pyplot as plt
+
+
+apps = ['None', 'PiP (play)', 'PiP (pause)', 'music (play)']
+devices = ['OPPO K10', 'Redmi K50']
+accu = [
+ [0.7751, 0.9560, 0.7265, 0.6831], # 0.7781
+ [0.9557, 0.9732, 0.7428, 0.6094] # 0.8156
+]
+
+plt.rc('font', family='Arial', size=20)
+for i in range(4):
+ plt.ylabel('Accuracy')
+ colors = ['tab:blue', 'tab:orange']
+ bar_width = 0.3
+ bar_x = np.arange(len(apps))
+ bar1 = plt.bar(bar_x[i] - bar_width/2 - 0.02, accu[0][i], width=bar_width, color=colors[0], edgecolor='black', hatch='/')
+ bar2 = plt.bar(bar_x[i] + bar_width/2 + 0.02, accu[1][i], width=bar_width, color=colors[1], edgecolor='black', hatch='\\')
+plt.legend((bar1, bar2), devices, fontsize=16, labelspacing=0.2, ncol=2)
+plt.xticks(bar_x, apps, rotation=30)
+plt.ylim(0, 1.3)
+plt.yticks(np.arange(0, 1.5, 0.5))
+plt.tight_layout()
+plt.savefig("../paper/ieee/fig8.pdf", format='pdf')
+plt.close()
\ No newline at end of file
diff --git a/figures/fig9-impact.py b/figures/fig9-impact.py
new file mode 100755
index 0000000..dd6b568
--- /dev/null
+++ b/figures/fig9-impact.py
@@ -0,0 +1,188 @@
+# =============================================================================
+# This file is part of EavesDroid.
+#
+# Author: iamywang
+# Date Created: Jan 27, 2024
+# =============================================================================
+import numpy as np
+import matplotlib.pyplot as plt
+
+types = ['minmax', 'cnngru', 'dimension', 'interval', 'minmax2']
+
+
+def minmax():
+ apps = ['Telegram', 'Youtube', 'Gmail', 'OneNote', 'All']
+ devices = ['D-K (raw)', 'D-K (nor)', 'C-G (raw)', 'C-G (nor)']
+ accu = [
+ # DTW-KNN
+ [0.8833, 0.7767, 0.9292, 0.5500, 0.6892],
+ [0.9542, 0.8833, 0.9833, 0.7375, 0.8510],
+ # CNN-GRU
+ [0.9167, 0.9200, 0.9708, 0.9375, 0.9206],
+ [0.9792, 0.9667, 1.0000, 0.9750, 0.9755]
+ ]
+
+ plt.rc('font', family='Arial', size=24)
+ for i in range(5):
+ plt.ylabel('Accuracy')
+ colors = ['tab:blue', 'tab:orange', 'tab:green', 'tab:red']
+ bar_width = 0.15
+ bar_x = np.arange(len(apps))
+ bar1 = plt.bar(bar_x[i] - 3 * bar_width/2 - 0.06, accu[0][i], width=bar_width, color=colors[0], edgecolor='black', hatch='/')
+ bar2 = plt.bar(bar_x[i] - bar_width/2 - 0.02, accu[1][i], width=bar_width, color=colors[1], edgecolor='black', hatch='\\')
+ bar3 = plt.bar(bar_x[i] + bar_width/2 + 0.02, accu[2][i], width=bar_width, color=colors[2], edgecolor='black', hatch='o')
+ bar4 = plt.bar(bar_x[i] + 3 * bar_width/2 + 0.06, accu[3][i], width=bar_width, color=colors[3], edgecolor='black', hatch='*')
+ plt.legend((bar1, bar2, bar3, bar4), devices, fontsize=18, labelspacing=0.2, ncol=2)
+ plt.xticks(bar_x, apps, rotation=30)
+ plt.ylim(0, 1.499999)
+ plt.tight_layout()
+ plt.savefig("../paper/ieee/fig11.pdf", format='pdf')
+ plt.close()
+
+
+def cnngru():
+ apps = ['Telegram', 'Youtube', 'Gmail', 'OneNote', 'All']
+ devices = ['D-K (1)', 'D-K (3)', 'D-K (5)', 'CNN-GRU']
+ accu = [
+ [0.9542, 0.8833, 0.9833, 0.7375, 0.8510],
+ [0.9500, 0.8767, 0.9875, 0.7542, 0.8441],
+ [0.9375, 0.8867, 0.9875, 0.7333, 0.8461],
+ [0.9792, 0.9667, 1.0000, 0.9750, 0.9755]
+ ]
+
+ plt.rc('font', family='Arial', size=24)
+ for i in range(5):
+ plt.ylabel('Accuracy')
+ colors = ['tab:blue', 'tab:orange', 'tab:green', 'tab:red']
+ bar_width = 0.15
+ bar_x = np.arange(len(apps))
+ bar1 = plt.bar(bar_x[i] - 3 * bar_width/2 - 0.06, accu[0][i], width=bar_width, color=colors[0], edgecolor='black', hatch='/')
+ bar2 = plt.bar(bar_x[i] - bar_width/2 - 0.02, accu[1][i], width=bar_width, color=colors[1], edgecolor='black', hatch='\\')
+ bar3 = plt.bar(bar_x[i] + bar_width/2 + 0.02, accu[2][i], width=bar_width, color=colors[2], edgecolor='black', hatch='o')
+ bar4 = plt.bar(bar_x[i] + 3 * bar_width/2 + 0.06, accu[3][i], width=bar_width, color=colors[3], edgecolor='black', hatch='*')
+ plt.legend((bar1, bar2, bar3, bar4), devices, fontsize=18, labelspacing=0.2, ncol=2)
+ plt.xticks(bar_x, apps, rotation=30)
+ plt.ylim(0, 1.499999)
+ plt.tight_layout()
+ plt.savefig("../paper/ieee/fig9.pdf", format='pdf')
+ plt.close()
+
+
+def cnngru2():
+ apps = ['Telegram', 'Youtube', 'Gmail', 'OneNote', 'All']
+ devices = ['1d-CNN', 'LSTM', 'GRU', 'CNN-GRU']
+ accu = [
+ [0.9050, 0.9033, 0.9698, 0.8740, 0.9118],
+ [0.7185, 0.7491, 0.8213, 0.5731, 0.7137],
+ [0.9757, 0.9661, 0.9487, 0.9508, 0.9608],
+ [0.9792, 0.9667, 1.0000, 0.9750, 0.9755]
+ ]
+
+ plt.rc('font', family='Arial', size=24)
+ for i in range(5):
+ plt.ylabel('Accuracy')
+ colors = ['tab:blue', 'tab:orange', 'tab:green', 'tab:red']
+ bar_width = 0.15
+ bar_x = np.arange(len(apps))
+ bar1 = plt.bar(bar_x[i] - 3 * bar_width/2 - 0.06, accu[0][i], width=bar_width, color=colors[0], edgecolor='black', hatch='/')
+ bar2 = plt.bar(bar_x[i] - bar_width/2 - 0.02, accu[1][i], width=bar_width, color=colors[1], edgecolor='black', hatch='\\')
+ bar3 = plt.bar(bar_x[i] + bar_width/2 + 0.02, accu[2][i], width=bar_width, color=colors[2], edgecolor='black', hatch='o')
+ bar4 = plt.bar(bar_x[i] + 3 * bar_width/2 + 0.06, accu[3][i], width=bar_width, color=colors[3], edgecolor='black', hatch='*')
+ plt.legend((bar1, bar2, bar3, bar4), devices, fontsize=18, labelspacing=0.2, ncol=2)
+ plt.xticks(bar_x, apps, rotation=30)
+ plt.ylim(0, 1.499999)
+ plt.tight_layout()
+ plt.savefig("../paper/ieee/fig10.pdf", format='pdf')
+ plt.close()
+
+
+def dimension():
+ apps = ['Telegram', 'Youtube', 'Gmail', 'OneNote', 'All']
+ devices = ['1 feature', '2 features', '5 features']
+ accu = [
+ [0.8875, 0.8867, 0.9250, 0.8875, 0.9029],
+ [0.9708, 0.9367, 0.9708, 0.9375, 0.9255],
+ [0.9958, 0.9700, 1.0000, 0.9917, 0.9863]
+ ]
+
+ plt.rc('font', family='Arial', size=24)
+ for i in range(5):
+ plt.ylabel('Accuracy')
+ colors = ['tab:blue', 'tab:orange', 'tab:green', 'tab:red']
+ bar_width = 0.2
+ bar_x = np.arange(len(apps))
+ bar1 = plt.bar(bar_x[i] - bar_width - 0.04, accu[0][i], width=bar_width, color=colors[0], edgecolor='black', hatch='/')
+ bar2 = plt.bar(bar_x[i], accu[1][i], width=bar_width, color=colors[1], edgecolor='black', hatch='\\')
+ bar3 = plt.bar(bar_x[i] + bar_width + 0.04, accu[2][i], width=bar_width, color=colors[2], edgecolor='black', hatch='o')
+ plt.legend((bar1, bar2, bar3), devices, fontsize=18, labelspacing=0.2, ncol=2)
+ plt.xticks(bar_x, apps, rotation=30)
+ plt.ylim(0, 1.499999)
+ plt.tight_layout()
+ plt.savefig("../paper/ieee/fig13.pdf", format='pdf')
+ plt.close()
+
+
+def interval():
+ apps = ['Telegram', 'Youtube', 'Gmail', 'OneNote', 'All']
+ devices = ['1ms', '2ms', '4ms', '5ms']
+ accu = [
+ [0.9958, 0.9700, 1.0000, 0.9917, 0.9863],
+ [0.8083, 0.4967, 0.6500, 0.3833, 0.5902],
+ [0.5375, 0.3167, 0.3375, 0.2625, 0.3549],
+ [0.5250, 0.3167, 0.3000, 0.2292, 0.3363]
+ ]
+
+ plt.rc('font', family='Arial', size=24)
+ for i in range(5):
+ plt.ylabel('Accuracy')
+ colors = ['tab:blue', 'tab:orange', 'tab:green', 'tab:red']
+ bar_width = 0.15
+ bar_x = np.arange(len(apps))
+ bar1 = plt.bar(bar_x[i] - 3 * bar_width/2 - 0.06, accu[0][i], width=bar_width, color=colors[0], edgecolor='black', hatch='/')
+ bar2 = plt.bar(bar_x[i] - bar_width/2 - 0.02, accu[1][i], width=bar_width, color=colors[1], edgecolor='black', hatch='\\')
+ bar3 = plt.bar(bar_x[i] + bar_width/2 + 0.02, accu[2][i], width=bar_width, color=colors[2], edgecolor='black', hatch='o')
+ bar4 = plt.bar(bar_x[i] + 3 * bar_width/2 + 0.06, accu[3][i], width=bar_width, color=colors[3], edgecolor='black', hatch='*')
+ plt.legend((bar1, bar2, bar3, bar4), devices, fontsize=18, labelspacing=0.2, ncol=2)
+ plt.xticks(bar_x, apps, rotation=30)
+ plt.ylim(0, 1.499999)
+ plt.tight_layout()
+ plt.savefig("../paper/ieee/fig14.pdf", format='pdf')
+ plt.close()
+
+
+def minmax2():
+ apps = ['Telegram', 'Youtube', 'Gmail', 'OneNote', 'All']
+ devices = ['raw', 'min-max nor', 'mean nor', 'z-score', 'mean sub']
+ accu = [
+ [0.9167, 0.9200, 0.9708, 0.9375, 0.9206], # raw
+ [0.9792, 0.9667, 1.0000, 0.9750, 0.9755], # min-max nor
+ [0.9848, 0.9545, 0.9297, 0.9821, 0.9588], # mean nor
+ [0.9747, 0.9389, 0.9375, 0.9821, 0.9480], # z-score
+ [0.9394, 0.9279, 0.9028, 0.9342, 0.9255] # mean sub
+ ]
+
+ plt.rc('font', family='Arial', size=24)
+ for i in range(5):
+ plt.ylabel('Accuracy')
+ colors = ['tab:blue', 'tab:orange', 'tab:green', 'tab:red', 'tab:purple']
+ bar_width = 0.12
+ bar_x = np.arange(len(apps))
+ bar1 = plt.bar(bar_x[i] - 4 * bar_width/2 - 0.08, accu[0][i], width=bar_width, color=colors[0], edgecolor='black', hatch='/')
+ bar2 = plt.bar(bar_x[i] - 2 * bar_width/2 - 0.04, accu[1][i], width=bar_width, color=colors[1], edgecolor='black', hatch='\\')
+ bar3 = plt.bar(bar_x[i], accu[2][i], width=bar_width, color=colors[2], edgecolor='black', hatch='o')
+ bar4 = plt.bar(bar_x[i] + 2 * bar_width/2 + 0.04, accu[3][i], width=bar_width, color=colors[3], edgecolor='black', hatch='*')
+ bar5 = plt.bar(bar_x[i] + 4 * bar_width/2 + 0.08, accu[4][i], width=bar_width, color=colors[4], edgecolor='black', hatch='xx')
+ plt.legend((bar1, bar2, bar3, bar4, bar5), devices, fontsize=18, labelspacing=0.2, ncol=2)
+ plt.xticks(bar_x, apps, rotation=30)
+ plt.ylim(0, 1.65)
+ plt.yticks(np.arange(0, 1.5, 0.5))
+ plt.tight_layout()
+ plt.savefig("../paper/ieee/fig12.pdf", format='pdf')
+ plt.close()
+
+minmax()
+cnngru()
+cnngru2()
+dimension()
+interval()
+minmax2()
diff --git a/figures/tab-cnngru.py b/figures/tab-cnngru.py
new file mode 100755
index 0000000..d4646ed
--- /dev/null
+++ b/figures/tab-cnngru.py
@@ -0,0 +1,13 @@
+# =============================================================================
+# This file is part of EavesDroid.
+#
+# Author: iamywang
+# Date Created: Jan 27, 2024
+# =============================================================================
+from backend.backend.view import *
+from keras.utils import plot_model
+
+model = models.Sequential()
+model = cnn_init(model, 5000, 3, 4)
+
+plot_model(model, to_file='figures/tab2.eps', show_shapes=True)
diff --git a/overview.png b/overview.png
new file mode 100644
index 0000000..1f81ae4
Binary files /dev/null and b/overview.png differ