diff --git a/client/android/AndroidManifest.xml b/client/android/AndroidManifest.xml index 1115b74d..7671cecb 100644 --- a/client/android/AndroidManifest.xml +++ b/client/android/AndroidManifest.xml @@ -1,60 +1,52 @@ - + - - - - - - - + + + - - - - - + - + + + + + + + + + + + + - + android:roundIcon="@drawable/icon_round" + android:theme="@style/Theme.AppCompat.NoActionBar"> + - - - + - - + + - + @@ -62,73 +54,70 @@ - + android:value="-- %%INSERT_APP_LIB_NAME%% --" /> + - - - - - - + - + - + android:exported="true"> + - - - - - - - - - - - - + + + + + + + + + + + + + + - + - - - - - - - - - - - - + + + + + + + + + + + + + + - + - - - - - - - - - - - - + + + + + + + + + + + + + + @@ -136,30 +125,32 @@ android:name=".VPNService" android:process=":QtOnlyProcess" android:permission="android.permission.BIND_VPN_SERVICE" - android:foregroundServiceType="connectedDevice" + android:foregroundServiceType="specialUse" android:exported="true"> - - - - - + + + + + + - + - + + - + - + diff --git a/client/android/shadowsocks/build.gradle b/client/android/shadowsocks/build.gradle index 03737020..9c05307b 100644 --- a/client/android/shadowsocks/build.gradle +++ b/client/android/shadowsocks/build.gradle @@ -1,14 +1,17 @@ apply plugin: 'com.android.library' apply plugin: 'kotlin-android' -apply plugin: 'kotlin-android-extensions' apply plugin: 'kotlin-kapt' +apply plugin: 'kotlin-parcelize' //apply plugin: 'com.novoda.bintray-release' android { - compileSdkVersion 30 + buildFeatures { + aidl true + androidResources true + } + defaultConfig { - minSdkVersion 24 - targetSdkVersion 30 + namespace "org.amnezia.vpn.shadowsocks.core" versionCode 1 versionName "1.0.0" @@ -30,10 +33,6 @@ android { } } -androidExtensions { - experimental = true -} - //def lifecycleVersion = '2.0.0' def roomVersion = "2.4.3" //def preferencexVersion = '1.0.0' @@ -46,10 +45,9 @@ dependencies { implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.0" implementation "androidx.core:core-ktx:1.2.0" - implementation "androidx.lifecycle:lifecycle-extensions:2.2.0" - implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.4.0" - implementation "androidx.lifecycle:lifecycle-livedata-core-ktx:2.4.0" - implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0" + implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.5.1" + implementation "androidx.lifecycle:lifecycle-livedata-core-ktx:2.5.1" + implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.1" implementation "androidx.room:room-runtime:$roomVersion" // runtime implementation "androidx.preference:preference:1.1.0" implementation "androidx.work:work-runtime-ktx:2.7.1" diff --git a/client/android/shadowsocks/src/main/AndroidManifest.xml b/client/android/shadowsocks/src/main/AndroidManifest.xml index ee498ab8..b1c76391 100644 --- a/client/android/shadowsocks/src/main/AndroidManifest.xml +++ b/client/android/shadowsocks/src/main/AndroidManifest.xml @@ -1,6 +1,5 @@ 0) { - pendingRegistrations.poll()!!.apply { + pendingRegistrations.tryReceive().getOrNull()!!.apply { try { result.complete(registerInternal(channel, ops, listener)) } catch (e: Exception) { @@ -112,7 +113,7 @@ class ChannelMonitor : Thread("ChannelMonitor") { (key.attachment() as (SelectionKey) -> Unit)(key) } } - closeChannel.sendBlocking(Unit) + closeChannel.trySendBlocking(Unit) } fun close(scope: CoroutineScope) { diff --git a/client/android/shadowsocks/src/main/java/org/amnezia/vpn/shadowsocks/core/net/LocalSocketListener.kt b/client/android/shadowsocks/src/main/java/org/amnezia/vpn/shadowsocks/core/net/LocalSocketListener.kt index e6b06297..600e8e02 100644 --- a/client/android/shadowsocks/src/main/java/org/amnezia/vpn/shadowsocks/core/net/LocalSocketListener.kt +++ b/client/android/shadowsocks/src/main/java/org/amnezia/vpn/shadowsocks/core/net/LocalSocketListener.kt @@ -33,6 +33,7 @@ import kotlinx.coroutines.channels.sendBlocking import kotlinx.coroutines.launch import java.io.File import java.io.IOException +import kotlinx.coroutines.channels.trySendBlocking abstract class LocalSocketListener(name: String, socketFile: File) : Thread(name) { private val localSocket = LocalSocket().apply { @@ -60,7 +61,7 @@ abstract class LocalSocketListener(name: String, socketFile: File) : Thread(name } } } - closeChannel.sendBlocking(Unit) + closeChannel.trySendBlocking(Unit) } open fun shutdown(scope: CoroutineScope) { diff --git a/client/android/src/com/wireguard/config/InetEndpoint.java b/client/android/src/com/wireguard/config/InetEndpoint.java index 655835fb..d7802204 100644 --- a/client/android/src/com/wireguard/config/InetEndpoint.java +++ b/client/android/src/com/wireguard/config/InetEndpoint.java @@ -31,7 +31,7 @@ public final class InetEndpoint { private final boolean isResolved; private final Object lock = new Object(); private final int port; - private Instant lastResolution = Instant.EPOCH; + private long lastResolution; @Nullable private InetEndpoint resolved; private InetEndpoint(final String host, final boolean isResolved, final int port) { @@ -89,7 +89,7 @@ public final class InetEndpoint { return Optional.of(this); synchronized (lock) { // TODO(zx2c4): Implement a real timeout mechanism using DNS TTL - if (Duration.between(lastResolution, Instant.now()).toMinutes() > 1) { + if (System.currentTimeMillis() - lastResolution > 60000L) { try { // Prefer v4 endpoints over v6 to work around DNS64 and IPv6 NAT issues. final InetAddress[] candidates = InetAddress.getAllByName(host); @@ -101,7 +101,7 @@ public final class InetEndpoint { } } resolved = new InetEndpoint(address.getHostAddress(), true, port); - lastResolution = Instant.now(); + lastResolution = System.currentTimeMillis(); } catch (final UnknownHostException e) { resolved = null; } diff --git a/client/android/src/org/amnezia/vpn/NotificationUtil.kt b/client/android/src/org/amnezia/vpn/NotificationUtil.kt index ee679f65..efa7fb74 100644 --- a/client/android/src/org/amnezia/vpn/NotificationUtil.kt +++ b/client/android/src/org/amnezia/vpn/NotificationUtil.kt @@ -12,6 +12,7 @@ import android.content.Intent import android.os.Build import android.os.Parcel import androidx.core.app.NotificationCompat +import org.amnezia.vpn.shadowsocks.core.R import org.json.JSONObject object NotificationUtil { @@ -102,7 +103,7 @@ object NotificationUtil { val pendingIntent = PendingIntent.getActivity(service, 0, intent, PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT) // Build our notification sNotificationBuilder?.let { - it.setSmallIcon(org.amnezia.vpn.R.drawable.ic_amnezia_round) + it.setSmallIcon(R.drawable.ic_amnezia_round) .setContentTitle(header) .setContentText(message) .setOnlyAlertOnce(true) diff --git a/client/android/src/org/amnezia/vpn/OpenVPNThreadv3.kt b/client/android/src/org/amnezia/vpn/OpenVPNThreadv3.kt index b35face4..ad38c521 100644 --- a/client/android/src/org/amnezia/vpn/OpenVPNThreadv3.kt +++ b/client/android/src/org/amnezia/vpn/OpenVPNThreadv3.kt @@ -83,29 +83,32 @@ class OpenVPNThreadv3(var service: VPNService): ClientAPI_OpenVPNClient(), Runna if (jsonVpnConfig.getString("protocol") == "cloak") { val cloakConfigJson: JSONObject = jsonVpnConfig.getJSONObject("cloak_config_data") - if (cloakConfigJson.keySet().contains("NumConn")) { + if (cloakConfigJson.has("NumConn")) { cloakConfigJson.put("NumConn", 1) } - if (cloakConfigJson.keySet().contains("ProxyMethod")) { + if (cloakConfigJson.has("ProxyMethod")) { cloakConfigJson.put("ProxyMethod", "openvpn") } - if (cloakConfigJson.keySet().contains("port")) { + if (cloakConfigJson.has("port")) { val portValue = cloakConfigJson.get("port") cloakConfigJson.remove("port") cloakConfigJson.put("RemotePort", portValue) } - if (cloakConfigJson.keySet().contains("remote")) { + if (cloakConfigJson.has("remote")) { val hostValue = cloakConfigJson.get("remote") cloakConfigJson.remove("remote") cloakConfigJson.put("RemoteHost", hostValue) } - val cloakConfig = Base64.getEncoder().encodeToString( - jsonVpnConfig.getJSONObject("cloak_config_data").toString().toByteArray() - ) + val cloakConfigData = jsonVpnConfig.getJSONObject("cloak_config_data").toString().toByteArray() + val cloakConfig = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + Base64.getEncoder().encodeToString(cloakConfigData) + } else { + android.util.Base64.encodeToString(cloakConfigData, android.util.Base64.DEFAULT) + } resultingConfig.append("\n\n") resultingConfig.append(cloakConfig)