Set the maximum version of Androids to 7.1 (API 25)

This commit is contained in:
albexk 2024-10-02 15:18:05 +03:00
parent 744b45476c
commit 4910dcfa96
14 changed files with 35 additions and 217 deletions

View file

@ -301,7 +301,7 @@ jobs:
env: env:
ANDROID_BUILD_PLATFORM: android-34 ANDROID_BUILD_PLATFORM: android-34
QT_VERSION: 6.7.3 QT_VERSION: 6.6.3
QT_MODULES: 'qtremoteobjects qt5compat qtimageformats qtshadertools' QT_MODULES: 'qtremoteobjects qt5compat qtimageformats qtshadertools'
PROD_AGW_PUBLIC_KEY: ${{ secrets.PROD_AGW_PUBLIC_KEY }} PROD_AGW_PUBLIC_KEY: ${{ secrets.PROD_AGW_PUBLIC_KEY }}
DEV_AGW_PUBLIC_KEY: ${{ secrets.DEV_AGW_PUBLIC_KEY }} DEV_AGW_PUBLIC_KEY: ${{ secrets.DEV_AGW_PUBLIC_KEY }}

View file

@ -3,10 +3,13 @@
<manifest <manifest
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
package="org.amnezia.vpn"
android:versionName="-- %%INSERT_VERSION_NAME%% --" android:versionName="-- %%INSERT_VERSION_NAME%% --"
android:versionCode="-- %%INSERT_VERSION_CODE%% --" android:versionCode="-- %%INSERT_VERSION_CODE%% --"
android:installLocation="auto"> android:installLocation="auto">
<uses-sdk android:maxSdkVersion="25" />
<uses-feature android:name="android.hardware.camera" android:required="false" /> <uses-feature android:name="android.hardware.camera" android:required="false" />
<uses-feature android:name="android.hardware.camera.any" android:required="false" /> <uses-feature android:name="android.hardware.camera.any" android:required="false" />
<uses-feature android:name="android.hardware.camera.autofocus" android:required="false" /> <uses-feature android:name="android.hardware.camera.autofocus" android:required="false" />
@ -67,6 +70,9 @@
android:name="android.app.lib_name" android:name="android.app.lib_name"
android:value="-- %%INSERT_APP_LIB_NAME%% --" /> android:value="-- %%INSERT_APP_LIB_NAME%% --" />
<meta-data
android:name="android.app.extract_android_style"
android:value="minimal" />
</activity> </activity>
<activity <activity

View file

@ -183,14 +183,6 @@ class OpenVpnClient(
// Never called more than once per tun_builder session. // Never called more than once per tun_builder session.
override fun tun_builder_set_proxy_http(host: String, port: Int): Boolean { override fun tun_builder_set_proxy_http(host: String, port: Int): Boolean {
Log.d(TAG, "tun_builder_set_proxy_http: $host, $port") Log.d(TAG, "tun_builder_set_proxy_http: $host, $port")
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
try {
configBuilder.setHttpProxy(ProxyInfo.buildDirectProxy(host, port))
} catch (e: Exception) {
Log.e(TAG, "Could not set proxy: ${e.message}")
return false
}
}
return true return true
} }

View file

@ -116,15 +116,10 @@ abstract class Protocol {
if (include) { if (include) {
Log.d(TAG, "addRoute: $inetNetwork") Log.d(TAG, "addRoute: $inetNetwork")
vpnBuilder.addRoute(inetNetwork) vpnBuilder.addRoute(inetNetwork)
} else {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
Log.d(TAG, "excludeRoute: $inetNetwork")
vpnBuilder.excludeRoute(inetNetwork)
} else { } else {
Log.e(TAG, "Trying to exclude route $inetNetwork on old Android") Log.e(TAG, "Trying to exclude route $inetNetwork on old Android")
} }
} }
}
for (app in config.includedApplications) { for (app in config.includedApplications) {
Log.d(TAG, "addAllowedApplication") Log.d(TAG, "addAllowedApplication")
@ -139,13 +134,6 @@ abstract class Protocol {
Log.d(TAG, "setMtu: ${config.mtu}") Log.d(TAG, "setMtu: ${config.mtu}")
vpnBuilder.setMtu(config.mtu) vpnBuilder.setMtu(config.mtu)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
config.httpProxy?.let {
Log.d(TAG, "setHttpProxy: $it")
vpnBuilder.setHttpProxy(it)
}
}
if (config.allowAllAF) { if (config.allowAllAF) {
Log.d(TAG, "allowFamily") Log.d(TAG, "allowFamily")
vpnBuilder.allowFamily(OsConstants.AF_INET) vpnBuilder.allowFamily(OsConstants.AF_INET)
@ -155,8 +143,6 @@ abstract class Protocol {
Log.d(TAG, "setBlocking: ${config.blockingMode}") Log.d(TAG, "setBlocking: ${config.blockingMode}")
vpnBuilder.setBlocking(config.blockingMode) vpnBuilder.setBlocking(config.blockingMode)
vpnBuilder.setUnderlyingNetworks(null) vpnBuilder.setUnderlyingNetworks(null)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q)
vpnBuilder.setMetered(false)
} }
} }

View file

@ -145,7 +145,7 @@ open class ProtocolConfig protected constructor(
} }
// for older versions of Android, build a list of subnets without excluded routes // for older versions of Android, build a list of subnets without excluded routes
// and add them to routes // and add them to routes
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU && routes.any { !it.include }) { if (routes.any { !it.include }) {
val ipRangeSet = IpRangeSet() val ipRangeSet = IpRangeSet()
routes.forEach { routes.forEach {
if (it.include) ipRangeSet.add(IpRange(it.inetNetwork)) if (it.include) ipRangeSet.add(IpRange(it.inetNetwork))

View file

@ -21,5 +21,5 @@ android {
} }
dependencies { dependencies {
api(fileTree(mapOf("dir" to "../libs", "include" to listOf("*.jar")))) implementation(fileTree(mapOf("dir" to "../libs", "include" to listOf("*.jar"))))
} }

View file

@ -3,8 +3,6 @@ package org.amnezia.vpn
import android.Manifest import android.Manifest
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.app.AlertDialog import android.app.AlertDialog
import android.app.NotificationManager
import android.content.BroadcastReceiver
import android.content.ComponentName import android.content.ComponentName
import android.content.Intent import android.content.Intent
import android.content.Intent.EXTRA_MIME_TYPES import android.content.Intent.EXTRA_MIME_TYPES
@ -68,7 +66,6 @@ class AmneziaActivity : QtActivity() {
private var isWaitingStatus = true private var isWaitingStatus = true
private var isServiceConnected = false private var isServiceConnected = false
private var isInBoundState = false private var isInBoundState = false
private var notificationStateReceiver: BroadcastReceiver? = null
private lateinit var vpnServiceMessenger: IpcMessenger private lateinit var vpnServiceMessenger: IpcMessenger
private val actionResultHandlers = mutableMapOf<Int, ActivityResultHandler>() private val actionResultHandlers = mutableMapOf<Int, ActivityResultHandler>()
@ -176,7 +173,6 @@ class AmneziaActivity : QtActivity() {
doBindService() doBindService()
} }
) )
registerBroadcastReceivers()
intent?.let(::processIntent) intent?.let(::processIntent)
runBlocking { vpnProto = proto.await() } runBlocking { vpnProto = proto.await() }
} }
@ -192,26 +188,6 @@ class AmneziaActivity : QtActivity() {
} }
} }
private fun registerBroadcastReceivers() {
notificationStateReceiver = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
registerBroadcastReceiver(
arrayOf(
NotificationManager.ACTION_NOTIFICATION_CHANNEL_BLOCK_STATE_CHANGED,
NotificationManager.ACTION_APP_BLOCK_STATE_CHANGED
)
) {
Log.d(
TAG, "Notification state changed: ${it?.action}, blocked = " +
"${it?.getBooleanExtra(NotificationManager.EXTRA_BLOCKED_STATE, false)}"
)
mainScope.launch {
qtInitialized.await()
QtAndroidController.onNotificationStateChanged()
}
}
} else null
}
override fun onNewIntent(intent: Intent?) { override fun onNewIntent(intent: Intent?) {
super.onNewIntent(intent) super.onNewIntent(intent)
Log.d(TAG, "onNewIntent: $intent") Log.d(TAG, "onNewIntent: $intent")
@ -257,8 +233,6 @@ class AmneziaActivity : QtActivity() {
override fun onDestroy() { override fun onDestroy() {
Log.d(TAG, "Destroy Amnezia activity") Log.d(TAG, "Destroy Amnezia activity")
unregisterBroadcastReceiver(notificationStateReceiver)
notificationStateReceiver = null
mainScope.cancel() mainScope.cancel()
super.onDestroy() super.onDestroy()
} }
@ -664,7 +638,7 @@ class AmneziaActivity : QtActivity() {
} }
@Suppress("unused") @Suppress("unused")
fun isNotificationPermissionGranted(): Boolean = applicationContext.isNotificationPermissionGranted() fun isNotificationPermissionGranted(): Boolean = true
@Suppress("unused") @Suppress("unused")
fun requestNotificationPermission() { fun requestNotificationPermission() {

View file

@ -1,12 +1,9 @@
package org.amnezia.vpn package org.amnezia.vpn
import android.annotation.SuppressLint
import android.app.PendingIntent
import android.content.ComponentName import android.content.ComponentName
import android.content.Intent import android.content.Intent
import android.content.ServiceConnection import android.content.ServiceConnection
import android.net.VpnService import android.net.VpnService
import android.os.Build
import android.os.IBinder import android.os.IBinder
import android.os.Messenger import android.os.Messenger
import android.service.quicksettings.Tile import android.service.quicksettings.Tile
@ -148,7 +145,8 @@ class AmneziaTileService : TileService() {
Intent(this, AmneziaActivity::class.java).apply { Intent(this, AmneziaActivity::class.java).apply {
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
}.also { }.also {
startActivityAndCollapseCompat(it) @Suppress("DEPRECATION")
startActivityAndCollapse(it)
} }
} }
} }
@ -192,7 +190,8 @@ class AmneziaTileService : TileService() {
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
putExtra(EXTRA_PROTOCOL, vpnProto) putExtra(EXTRA_PROTOCOL, vpnProto)
}.also { }.also {
startActivityAndCollapseCompat(it) @Suppress("DEPRECATION")
startActivityAndCollapse(it)
} }
false false
} else { } else {
@ -216,23 +215,6 @@ class AmneziaTileService : TileService() {
private fun stopVpn() = vpnServiceMessenger.send(Action.DISCONNECT) private fun stopVpn() = vpnServiceMessenger.send(Action.DISCONNECT)
@SuppressLint("StartActivityAndCollapseDeprecated")
private fun startActivityAndCollapseCompat(intent: Intent) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
startActivityAndCollapse(
PendingIntent.getActivity(
applicationContext,
0,
intent,
PendingIntent.FLAG_IMMUTABLE
)
)
} else {
@Suppress("DEPRECATION")
startActivityAndCollapse(intent)
}
}
private fun updateVpnState(state: ProtocolState) = private fun updateVpnState(state: ProtocolState) =
scope.launch { VpnStateStore.store { it.copy(protocolState = state) } } scope.launch { VpnStateStore.store { it.copy(protocolState = state) } }
@ -249,17 +231,14 @@ class AmneziaTileService : TileService() {
when (val protocolState = vpnState.protocolState) { when (val protocolState = vpnState.protocolState) {
CONNECTED -> { CONNECTED -> {
state = Tile.STATE_ACTIVE state = Tile.STATE_ACTIVE
subtitleCompat = null
} }
DISCONNECTED, UNKNOWN -> { DISCONNECTED, UNKNOWN -> {
state = Tile.STATE_INACTIVE state = Tile.STATE_INACTIVE
subtitleCompat = null
} }
CONNECTING, DISCONNECTING, RECONNECTING -> { CONNECTING, DISCONNECTING, RECONNECTING -> {
state = Tile.STATE_UNAVAILABLE state = Tile.STATE_UNAVAILABLE
subtitleCompat = getString(protocolState)
} }
} }
updateTile() updateTile()
@ -267,17 +246,4 @@ class AmneziaTileService : TileService() {
// double update to fix weird visual glitches // double update to fix weird visual glitches
tile.updateTile() tile.updateTile()
} }
private var Tile.subtitleCompat: CharSequence?
set(value) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
this.subtitle = value
}
}
get() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
return this.subtitle
}
return null
}
} }

View file

@ -3,14 +3,10 @@ package org.amnezia.vpn
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.app.ActivityManager import android.app.ActivityManager
import android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE import android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE
import android.app.NotificationManager
import android.content.BroadcastReceiver import android.content.BroadcastReceiver
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_MANIFEST
import android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_SYSTEM_EXEMPTED
import android.net.VpnService import android.net.VpnService
import android.os.Build
import android.os.Handler import android.os.Handler
import android.os.IBinder import android.os.IBinder
import android.os.Looper import android.os.Looper
@ -104,7 +100,6 @@ open class AmneziaVpnService : VpnService() {
private lateinit var networkState: NetworkState private lateinit var networkState: NetworkState
private lateinit var trafficStats: TrafficStats private lateinit var trafficStats: TrafficStats
private var controlReceiver: BroadcastReceiver? = null private var controlReceiver: BroadcastReceiver? = null
private var notificationStateReceiver: BroadcastReceiver? = null
private var screenOnReceiver: BroadcastReceiver? = null private var screenOnReceiver: BroadcastReceiver? = null
private var screenOffReceiver: BroadcastReceiver? = null private var screenOffReceiver: BroadcastReceiver? = null
private val clientMessengers = ConcurrentHashMap<Messenger, IpcMessenger>() private val clientMessengers = ConcurrentHashMap<Messenger, IpcMessenger>()
@ -189,16 +184,6 @@ open class AmneziaVpnService : VpnService() {
Messenger(actionMessageHandler) Messenger(actionMessageHandler)
} }
/**
* Notification setup
*/
private val foregroundServiceTypeCompat
get() = when {
Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE -> FOREGROUND_SERVICE_TYPE_SYSTEM_EXEMPTED
Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q -> FOREGROUND_SERVICE_TYPE_MANIFEST
else -> 0
}
private val serviceNotification: ServiceNotification by lazy(NONE) { ServiceNotification(this) } private val serviceNotification: ServiceNotification by lazy(NONE) { ServiceNotification(this) }
/** /**
@ -232,7 +217,7 @@ open class AmneziaVpnService : VpnService() {
ServiceCompat.startForeground( ServiceCompat.startForeground(
this, NOTIFICATION_ID, this, NOTIFICATION_ID,
serviceNotification.buildNotification(serverName, vpnProto?.label, protocolState.value), serviceNotification.buildNotification(serverName, vpnProto?.label, protocolState.value),
foregroundServiceTypeCompat 0
) )
return START_REDELIVER_INTENT return START_REDELIVER_INTENT
} }
@ -309,23 +294,6 @@ open class AmneziaVpnService : VpnService() {
} }
} }
notificationStateReceiver = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
registerBroadcastReceiver(
arrayOf(
NotificationManager.ACTION_NOTIFICATION_CHANNEL_BLOCK_STATE_CHANGED,
NotificationManager.ACTION_APP_BLOCK_STATE_CHANGED
)
) {
val state = it?.getBooleanExtra(NotificationManager.EXTRA_BLOCKED_STATE, false)
Log.d(TAG, "Notification state changed: ${it?.action}, blocked = $state")
if (state == false) {
enableNotification()
} else {
disableNotification()
}
}
} else null
registerScreenStateBroadcastReceivers() registerScreenStateBroadcastReceivers()
} }
@ -353,10 +321,8 @@ open class AmneziaVpnService : VpnService() {
private fun unregisterBroadcastReceivers() { private fun unregisterBroadcastReceivers() {
Log.d(TAG, "Unregister broadcast receivers") Log.d(TAG, "Unregister broadcast receivers")
unregisterBroadcastReceiver(controlReceiver) unregisterBroadcastReceiver(controlReceiver)
unregisterBroadcastReceiver(notificationStateReceiver)
unregisterScreenStateBroadcastReceivers() unregisterScreenStateBroadcastReceivers()
controlReceiver = null controlReceiver = null
notificationStateReceiver = null
} }
/** /**

View file

@ -1,19 +1,15 @@
package org.amnezia.vpn package org.amnezia.vpn
import android.Manifest.permission
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.app.Notification import android.app.Notification
import android.app.NotificationManager
import android.app.PendingIntent import android.app.PendingIntent
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.pm.PackageManager
import android.os.Build import android.os.Build
import androidx.core.app.NotificationChannelCompat.Builder import androidx.core.app.NotificationChannelCompat.Builder
import androidx.core.app.NotificationCompat import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationCompat.Action import androidx.core.app.NotificationCompat.Action
import androidx.core.app.NotificationManagerCompat import androidx.core.app.NotificationManagerCompat
import androidx.core.content.ContextCompat
import org.amnezia.vpn.protocol.ProtocolState import org.amnezia.vpn.protocol.ProtocolState
import org.amnezia.vpn.protocol.ProtocolState.CONNECTED import org.amnezia.vpn.protocol.ProtocolState.CONNECTED
import org.amnezia.vpn.protocol.ProtocolState.DISCONNECTED import org.amnezia.vpn.protocol.ProtocolState.DISCONNECTED
@ -85,30 +81,18 @@ class ServiceNotification(private val context: Context) {
.setSubText(getSpeedString(speed)) .setSubText(getSpeedString(speed))
.build() .build()
fun isNotificationEnabled(): Boolean { fun isNotificationEnabled(): Boolean = notificationManager.areNotificationsEnabled()
if (!context.isNotificationPermissionGranted()) return false
if (!notificationManager.areNotificationsEnabled()) return false
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
return notificationManager.getNotificationChannel(NOTIFICATION_CHANNEL_ID)
?.let { it.importance != NotificationManager.IMPORTANCE_NONE } ?: true
}
return true
}
@SuppressLint("MissingPermission") @SuppressLint("MissingPermission")
fun updateNotification(serverName: String?, protocol: String?, state: ProtocolState) { fun updateNotification(serverName: String?, protocol: String?, state: ProtocolState) {
if (context.isNotificationPermissionGranted()) {
Log.d(TAG, "Update notification: $serverName, $state") Log.d(TAG, "Update notification: $serverName, $state")
notificationManager.notify(NOTIFICATION_ID, buildNotification(serverName, protocol, state)) notificationManager.notify(NOTIFICATION_ID, buildNotification(serverName, protocol, state))
} }
}
@SuppressLint("MissingPermission") @SuppressLint("MissingPermission")
fun updateSpeed(speed: TrafficData) { fun updateSpeed(speed: TrafficData) {
if (context.isNotificationPermissionGranted()) {
notificationManager.notify(NOTIFICATION_ID, buildNotification(speed)) notificationManager.notify(NOTIFICATION_ID, buildNotification(speed))
} }
}
private fun getSpeedString(traffic: TrafficData) = private fun getSpeedString(traffic: TrafficData) =
if (traffic == TrafficData.ZERO) zeroSpeed if (traffic == TrafficData.ZERO) zeroSpeed
@ -168,8 +152,3 @@ class ServiceNotification(private val context: Context) {
} }
} }
} }
fun Context.isNotificationPermissionGranted(): Boolean =
Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU ||
ContextCompat.checkSelfPermission(this, permission.POST_NOTIFICATIONS) ==
PackageManager.PERMISSION_GRANTED

View file

@ -7,7 +7,6 @@ import android.content.Intent
import android.content.res.Configuration.UI_MODE_NIGHT_MASK import android.content.res.Configuration.UI_MODE_NIGHT_MASK
import android.content.res.Configuration.UI_MODE_NIGHT_YES import android.content.res.Configuration.UI_MODE_NIGHT_YES
import android.net.VpnService import android.net.VpnService
import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.provider.Settings import android.provider.Settings
import android.widget.Toast import android.widget.Toast
@ -31,12 +30,9 @@ class VpnRequestActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
Log.d(TAG, "Start request activity") Log.d(TAG, "Start request activity")
vpnProto = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
intent.extras?.getSerializable(EXTRA_PROTOCOL, VpnProto::class.java)
} else {
@Suppress("DEPRECATION") @Suppress("DEPRECATION")
intent.extras?.getSerializable(EXTRA_PROTOCOL) as VpnProto vpnProto = intent.extras?.getSerializable(EXTRA_PROTOCOL) as VpnProto
}
val requestIntent = VpnService.prepare(applicationContext) val requestIntent = VpnService.prepare(applicationContext)
if (requestIntent != null) { if (requestIntent != null) {
if (getSystemService<KeyguardManager>()!!.isKeyguardLocked) { if (getSystemService<KeyguardManager>()!!.isKeyguardLocked) {

View file

@ -10,8 +10,6 @@ import java.io.IOException
import java.io.RandomAccessFile import java.io.RandomAccessFile
import java.nio.channels.FileChannel import java.nio.channels.FileChannel
import java.nio.channels.FileLock import java.nio.channels.FileLock
import java.time.LocalDateTime
import java.time.format.DateTimeFormatter
import java.util.Date import java.util.Date
import java.util.Locale import java.util.Locale
import java.util.concurrent.locks.ReentrantLock import java.util.concurrent.locks.ReentrantLock
@ -41,9 +39,7 @@ private const val LOG_MAX_FILE_SIZE = 1024 * 1024
* | | | create a report and/or terminate the process | * | | | create a report and/or terminate the process |
*/ */
object Log { object Log {
private val dateTimeFormat: Any = private val dateTimeFormat = object : ThreadLocal<DateFormat>() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) DateTimeFormatter.ofPattern(DATE_TIME_PATTERN)
else object : ThreadLocal<DateFormat>() {
override fun initialValue(): DateFormat = SimpleDateFormat(DATE_TIME_PATTERN, Locale.US) override fun initialValue(): DateFormat = SimpleDateFormat(DATE_TIME_PATTERN, Locale.US)
} }
@ -143,12 +139,7 @@ object Log {
} }
private fun formatLogMsg(tag: String, msg: String, priority: Priority): String { private fun formatLogMsg(tag: String, msg: String, priority: Priority): String {
val date = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { val date = dateTimeFormat.get()?.format(Date())
LocalDateTime.now().format(dateTimeFormat as DateTimeFormatter)
} else {
@Suppress("UNCHECKED_CAST")
(dateTimeFormat as ThreadLocal<DateFormat>).get()?.format(Date())
}
return "$date ${Process.myPid()} ${Process.myTid()} $priority [${Thread.currentThread().name}] " + return "$date ${Process.myPid()} ${Process.myTid()} $priority [${Thread.currentThread().name}] " +
"$tag: $msg\n" "$tag: $msg\n"
} }

View file

@ -8,11 +8,9 @@ import android.net.NetworkCapabilities
import android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET import android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET
import android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED import android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED
import android.net.NetworkRequest import android.net.NetworkRequest
import android.os.Build
import android.os.Handler import android.os.Handler
import androidx.core.content.getSystemService import androidx.core.content.getSystemService
import kotlin.LazyThreadSafetyMode.NONE import kotlin.LazyThreadSafetyMode.NONE
import kotlinx.coroutines.delay
import org.amnezia.vpn.util.Log import org.amnezia.vpn.util.Log
private const val TAG = "NetworkState" private const val TAG = "NetworkState"
@ -47,14 +45,10 @@ class NetworkState(
override fun onCapabilitiesChanged(network: Network, networkCapabilities: NetworkCapabilities) { override fun onCapabilitiesChanged(network: Network, networkCapabilities: NetworkCapabilities) {
Log.d(TAG, "onCapabilitiesChanged: $network, $networkCapabilities") Log.d(TAG, "onCapabilitiesChanged: $network, $networkCapabilities")
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
checkNetworkState(network, networkCapabilities)
} else {
handler.post { handler.post {
checkNetworkState(network, networkCapabilities) checkNetworkState(network, networkCapabilities)
} }
} }
}
private fun checkNetworkState(network: Network, networkCapabilities: NetworkCapabilities) { private fun checkNetworkState(network: Network, networkCapabilities: NetworkCapabilities) {
if (currentNetwork == null) { if (currentNetwork == null) {
@ -82,35 +76,10 @@ class NetworkState(
} }
} }
suspend fun bindNetworkListener() { fun bindNetworkListener() {
if (isListenerBound) return if (isListenerBound) return
Log.d(TAG, "Bind network listener") Log.d(TAG, "Bind network listener")
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
connectivityManager.registerBestMatchingNetworkCallback(networkRequest, networkCallback, handler)
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val numberAttempts = 300
var attemptCount = 0
while(true) {
try {
connectivityManager.requestNetwork(networkRequest, networkCallback, handler)
break
} catch (e: SecurityException) {
Log.e(TAG, "Failed to bind network listener: $e")
// Android 11 bug: https://issuetracker.google.com/issues/175055271
if (e.message?.startsWith("Package android does not belong to") == true) {
if (++attemptCount > numberAttempts) {
throw e
}
delay(1000)
continue
} else {
throw e
}
}
}
} else {
connectivityManager.requestNetwork(networkRequest, networkCallback) connectivityManager.requestNetwork(networkRequest, networkCallback)
}
isListenerBound = true isListenerBound = true
} }

View file

@ -1,7 +1,6 @@
package org.amnezia.vpn.util.net package org.amnezia.vpn.util.net
import android.net.TrafficStats import android.net.TrafficStats
import android.os.Build
import android.os.Process import android.os.Process
import android.os.SystemClock import android.os.SystemClock
import kotlin.math.roundToLong import kotlin.math.roundToLong
@ -17,13 +16,7 @@ class TrafficStats {
private var lastTrafficData = TrafficData.ZERO private var lastTrafficData = TrafficData.ZERO
private var lastTimestamp = 0L private var lastTimestamp = 0L
private val getTrafficDataCompat: () -> TrafficData = private val getTrafficDataCompat: () -> TrafficData = run {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
val iface = "tun0"
fun(): TrafficData {
return TrafficData(TrafficStats.getRxBytes(iface), TrafficStats.getTxBytes(iface))
}
} else {
val uid = Process.myUid() val uid = Process.myUid()
fun(): TrafficData { fun(): TrafficData {
return TrafficData(TrafficStats.getUidRxBytes(uid), TrafficStats.getUidTxBytes(uid)) return TrafficData(TrafficStats.getUidRxBytes(uid), TrafficStats.getUidTxBytes(uid))