Skip to content

Commit

Permalink
fix: improve tunnel reliability (#298)
Browse files Browse the repository at this point in the history
- Attempts to fix tunnel and auto-tunnel reliability by removing the tunnel foreground service and circumventing the limitation of starting the vpn service from by background by using a broadcast receiver.

- Removes tunnel foreground notification.

- Improves the reliability auto-tunnel start on reboot by adding an additional notification launch calls.

- Fixes bug where pin feature could be turned on without the pin being set.

- Improves quick tile reliability and sync.

- Improves reliability of app shortcuts.

- Improves kernel mode

- Improves permissions flow

- Adds support for dynamic app colors Android 12+

- Add support for light/dark system modes
  • Loading branch information
zaneschepke authored Aug 11, 2024
1 parent 19961ca commit bfb8d59
Show file tree
Hide file tree
Showing 80 changed files with 2,065 additions and 1,807 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -71,3 +71,4 @@ app/release/output.json
.idea/codeStyles/
# where we keep our signing secrets locally
app/signing.properties
/.kotlin/
1 change: 1 addition & 0 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ dependencies {
debugImplementation(libs.androidx.compose.manifest)

// get tunnel lib from github packages or mavenLocal
// implementation(fileTree(mapOf("dir" to "libs", "include" to listOf("*.aar"))))
implementation(libs.tunnel)
implementation(libs.amneziawg.android)
coreLibraryDesugaring(libs.desugar.jdk.libs)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
{
"formatVersion": 1,
"database": {
"version": 9,
"identityHash": "e2c91dbf1885a9da592d3f54f1e08302",
"entities": [
{
"tableName": "Settings",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_tunnel_enabled` INTEGER NOT NULL, `is_tunnel_on_mobile_data_enabled` INTEGER NOT NULL, `trusted_network_ssids` TEXT NOT NULL, `is_always_on_vpn_enabled` INTEGER NOT NULL, `is_tunnel_on_ethernet_enabled` INTEGER NOT NULL, `is_shortcuts_enabled` INTEGER NOT NULL DEFAULT false, `is_tunnel_on_wifi_enabled` INTEGER NOT NULL DEFAULT false, `is_kernel_enabled` INTEGER NOT NULL DEFAULT false, `is_restore_on_boot_enabled` INTEGER NOT NULL DEFAULT false, `is_multi_tunnel_enabled` INTEGER NOT NULL DEFAULT false, `is_auto_tunnel_paused` INTEGER NOT NULL DEFAULT false, `is_ping_enabled` INTEGER NOT NULL DEFAULT false, `is_amnezia_enabled` INTEGER NOT NULL DEFAULT false)",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "isAutoTunnelEnabled",
"columnName": "is_tunnel_enabled",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "isTunnelOnMobileDataEnabled",
"columnName": "is_tunnel_on_mobile_data_enabled",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "trustedNetworkSSIDs",
"columnName": "trusted_network_ssids",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "isAlwaysOnVpnEnabled",
"columnName": "is_always_on_vpn_enabled",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "isTunnelOnEthernetEnabled",
"columnName": "is_tunnel_on_ethernet_enabled",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "isShortcutsEnabled",
"columnName": "is_shortcuts_enabled",
"affinity": "INTEGER",
"notNull": true,
"defaultValue": "false"
},
{
"fieldPath": "isTunnelOnWifiEnabled",
"columnName": "is_tunnel_on_wifi_enabled",
"affinity": "INTEGER",
"notNull": true,
"defaultValue": "false"
},
{
"fieldPath": "isKernelEnabled",
"columnName": "is_kernel_enabled",
"affinity": "INTEGER",
"notNull": true,
"defaultValue": "false"
},
{
"fieldPath": "isRestoreOnBootEnabled",
"columnName": "is_restore_on_boot_enabled",
"affinity": "INTEGER",
"notNull": true,
"defaultValue": "false"
},
{
"fieldPath": "isMultiTunnelEnabled",
"columnName": "is_multi_tunnel_enabled",
"affinity": "INTEGER",
"notNull": true,
"defaultValue": "false"
},
{
"fieldPath": "isAutoTunnelPaused",
"columnName": "is_auto_tunnel_paused",
"affinity": "INTEGER",
"notNull": true,
"defaultValue": "false"
},
{
"fieldPath": "isPingEnabled",
"columnName": "is_ping_enabled",
"affinity": "INTEGER",
"notNull": true,
"defaultValue": "false"
},
{
"fieldPath": "isAmneziaEnabled",
"columnName": "is_amnezia_enabled",
"affinity": "INTEGER",
"notNull": true,
"defaultValue": "false"
}
],
"primaryKey": {
"autoGenerate": true,
"columnNames": [
"id"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "TunnelConfig",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `name` TEXT NOT NULL, `wg_quick` TEXT NOT NULL, `tunnel_networks` TEXT NOT NULL DEFAULT '', `is_mobile_data_tunnel` INTEGER NOT NULL DEFAULT false, `is_primary_tunnel` INTEGER NOT NULL DEFAULT false, `am_quick` TEXT NOT NULL DEFAULT '', `is_Active` INTEGER NOT NULL DEFAULT false)",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "name",
"columnName": "name",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "wgQuick",
"columnName": "wg_quick",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "tunnelNetworks",
"columnName": "tunnel_networks",
"affinity": "TEXT",
"notNull": true,
"defaultValue": "''"
},
{
"fieldPath": "isMobileDataTunnel",
"columnName": "is_mobile_data_tunnel",
"affinity": "INTEGER",
"notNull": true,
"defaultValue": "false"
},
{
"fieldPath": "isPrimaryTunnel",
"columnName": "is_primary_tunnel",
"affinity": "INTEGER",
"notNull": true,
"defaultValue": "false"
},
{
"fieldPath": "amQuick",
"columnName": "am_quick",
"affinity": "TEXT",
"notNull": true,
"defaultValue": "''"
},
{
"fieldPath": "isActive",
"columnName": "is_Active",
"affinity": "INTEGER",
"notNull": true,
"defaultValue": "false"
}
],
"primaryKey": {
"autoGenerate": true,
"columnNames": [
"id"
]
},
"indices": [
{
"name": "index_TunnelConfig_name",
"unique": true,
"columnNames": [
"name"
],
"orders": [],
"createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_TunnelConfig_name` ON `${TABLE_NAME}` (`name`)"
}
],
"foreignKeys": []
}
],
"views": [],
"setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'e2c91dbf1885a9da592d3f54f1e08302')"
]
}
}
53 changes: 34 additions & 19 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,12 @@
<!--start service on boot permission-->
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<!--android tv support-->

<permission
android:name="${applicationId}.permission.CONTROL_TUNNELS"
android:icon="@mipmap/ic_launcher"
android:protectionLevel="dangerous" />

<uses-feature
android:name="android.software.leanback"
android:required="false" />
Expand Down Expand Up @@ -137,23 +143,23 @@
<action android:name="android.service.quicksettings.action.QS_TILE" />
</intent-filter>
</service>
<service
android:name=".service.tunnel.AlwaysOnVpnService"
android:enabled="true"
android:exported="false"
android:foregroundServiceType="systemExempted"
android:permission="android.permission.BIND_VPN_SERVICE"
android:persistent="true"
tools:node="merge">
<intent-filter>
<action android:name="android.net.VpnService" />
</intent-filter>
<meta-data
android:name="android.net.VpnService.SUPPORTS_ALWAYS_ON"
android:value="true" />
</service>
<service
android:name=".service.foreground.WireGuardTunnelService"
android:enabled="true"
android:exported="false"
android:foregroundServiceType="systemExempted"
android:permission="android.permission.BIND_VPN_SERVICE"
android:persistent="true"
tools:node="merge">
<intent-filter>
<action android:name="android.net.VpnService" />
</intent-filter>
<meta-data
android:name="android.net.VpnService.SUPPORTS_ALWAYS_ON"
android:value="true" />
</service>
<service
android:name=".service.foreground.WireGuardConnectivityWatcherService"
android:name=".service.foreground.AutoTunnelService"
android:enabled="true"
android:exported="false"
android:foregroundServiceType="systemExempted"
Expand All @@ -174,8 +180,17 @@
<action android:name="com.htc.intent.action.QUICKBOOT_POWERON" />
</intent-filter>
</receiver>
<receiver
android:name=".receiver.NotificationActionReceiver"
android:exported="false" />
<receiver
android:name=".receiver.BackgroundActionReceiver"
android:enabled="true"
android:exported="false"/>
<receiver
android:name=".receiver.KernelReceiver"
android:exported="false"
android:permission="${applicationId}.permission.CONTROL_TUNNELS">
<intent-filter>
<action android:name="com.wireguard.android.action.REFRESH_TUNNEL_STATES" />
</intent-filter>
</receiver>
</application>
</manifest>
Original file line number Diff line number Diff line change
@@ -1,19 +1,22 @@
package com.zaneschepke.wireguardautotunnel

import android.app.Application
import android.content.ComponentName
import android.content.pm.PackageManager
import android.os.StrictMode
import android.os.StrictMode.ThreadPolicy
import android.service.quicksettings.TileService
import com.zaneschepke.wireguardautotunnel.service.tile.AutoTunnelControlTile
import com.zaneschepke.wireguardautotunnel.service.tile.TunnelControlTile
import com.zaneschepke.wireguardautotunnel.module.ApplicationScope
import com.zaneschepke.wireguardautotunnel.util.ReleaseTree
import dagger.hilt.android.HiltAndroidApp
import kotlinx.coroutines.CoroutineScope
import timber.log.Timber
import javax.inject.Inject

@HiltAndroidApp
class WireGuardAutoTunnel : Application() {

@Inject
@ApplicationScope
lateinit var applicationScope: CoroutineScope

override fun onCreate() {
super.onCreate()
instance = this
Expand All @@ -35,23 +38,5 @@ class WireGuardAutoTunnel : Application() {
companion object {
lateinit var instance: WireGuardAutoTunnel
private set

fun isRunningOnAndroidTv(): Boolean {
return instance.packageManager.hasSystemFeature(PackageManager.FEATURE_LEANBACK)
}

fun requestTunnelTileServiceStateUpdate() {
TileService.requestListeningState(
instance,
ComponentName(instance, TunnelControlTile::class.java),
)
}

fun requestAutoTunnelTileServiceUpdate() {
TileService.requestListeningState(
instance,
ComponentName(instance, AutoTunnelControlTile::class.java),
)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import com.zaneschepke.wireguardautotunnel.data.domain.TunnelConfig

@Database(
entities = [Settings::class, TunnelConfig::class],
version = 8,
version = 9,
autoMigrations =
[
AutoMigration(from = 1, to = 2),
Expand All @@ -34,6 +34,7 @@ import com.zaneschepke.wireguardautotunnel.data.domain.TunnelConfig
spec = RemoveLegacySettingColumnsMigration::class,
),
AutoMigration(7, 8),
AutoMigration(8, 9),
],
exportSchema = true,
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import com.zaneschepke.wireguardautotunnel.data.domain.TunnelConfig
import com.zaneschepke.wireguardautotunnel.util.TunnelConfigs
import com.zaneschepke.wireguardautotunnel.util.extensions.TunnelConfigs
import kotlinx.coroutines.flow.Flow

@Dao
Expand All @@ -23,6 +23,9 @@ interface TunnelConfigDao {
@Query("SELECT * FROM TunnelConfig WHERE name=:name")
suspend fun getByName(name: String): TunnelConfig?

@Query("SELECT * FROM TunnelConfig WHERE is_Active=1")
suspend fun getActive(): TunnelConfigs

@Query("SELECT * FROM TunnelConfig")
suspend fun getAll(): TunnelConfigs

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,7 @@ class DataStoreManager(
companion object {
val LOCATION_DISCLOSURE_SHOWN = booleanPreferencesKey("LOCATION_DISCLOSURE_SHOWN")
val BATTERY_OPTIMIZE_DISABLE_SHOWN = booleanPreferencesKey("BATTERY_OPTIMIZE_DISABLE_SHOWN")
val TUNNEL_RUNNING_FROM_MANUAL_START =
booleanPreferencesKey("TUNNEL_RUNNING_FROM_MANUAL_START")
val ACTIVE_TUNNEL = intPreferencesKey("ACTIVE_TUNNEL")
val LAST_ACTIVE_TUNNEL = intPreferencesKey("LAST_ACTIVE_TUNNEL")
val CURRENT_SSID = stringPreferencesKey("CURRENT_SSID")
val IS_PIN_LOCK_ENABLED = booleanPreferencesKey("PIN_LOCK_ENABLED")
}
Expand Down
Loading

0 comments on commit bfb8d59

Please sign in to comment.