Commit d35c3e4a authored by chenhuaqing's avatar chenhuaqing

adapted android code for server

parent b71f5595
...@@ -15,7 +15,7 @@ android { ...@@ -15,7 +15,7 @@ android {
consumerProguardFiles("proguard-rules.pro") consumerProguardFiles("proguard-rules.pro")
externalNativeBuild.ndkBuild { externalNativeBuild.ndkBuild {
abiFilters("armeabi-v7a", "arm64-v8a", "x86", "x86_64") abiFilters("armeabi-v7a", "arm64-v8a")
arguments("-j${Runtime.getRuntime().availableProcessors()}") arguments("-j${Runtime.getRuntime().availableProcessors()}")
} }
...@@ -35,11 +35,11 @@ android { ...@@ -35,11 +35,11 @@ android {
cargo { cargo {
module = "src/main/rust/shadowsocks-rust" module = "src/main/rust/shadowsocks-rust"
libname = "sslocal" libname = "sslocal"
targets = listOf("arm", "arm64", "x86", "x86_64") targets = listOf("arm", "arm64")
profile = findProperty("CARGO_PROFILE")?.toString() ?: currentFlavor profile = findProperty("CARGO_PROFILE")?.toString() ?: currentFlavor
extraCargoBuildArguments = listOf("--bin", libname!!) extraCargoBuildArguments = listOf("--bin", libname!!)
featureSpec.noDefaultBut(arrayOf( featureSpec.noDefaultBut(arrayOf(
"stream-cipher", // "stream-cipher",
"aead-cipher-extra", "aead-cipher-extra",
"logging", "logging",
"local-flow-stat", "local-flow-stat",
......
...@@ -24,6 +24,7 @@ import android.content.Context ...@@ -24,6 +24,7 @@ import android.content.Context
import com.github.shadowsocks.Core.app import com.github.shadowsocks.Core.app
import com.github.shadowsocks.acl.Acl import com.github.shadowsocks.acl.Acl
import com.github.shadowsocks.acl.AclSyncer import com.github.shadowsocks.acl.AclSyncer
import com.github.shadowsocks.core.BuildConfig
import com.github.shadowsocks.core.R import com.github.shadowsocks.core.R
import com.github.shadowsocks.database.Profile import com.github.shadowsocks.database.Profile
import com.github.shadowsocks.plugin.PluginConfiguration import com.github.shadowsocks.plugin.PluginConfiguration
...@@ -32,6 +33,7 @@ import com.github.shadowsocks.preference.DataStore ...@@ -32,6 +33,7 @@ import com.github.shadowsocks.preference.DataStore
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import org.json.JSONArray import org.json.JSONArray
import org.json.JSONObject import org.json.JSONObject
import timber.log.Timber
import java.io.File import java.io.File
import java.net.URI import java.net.URI
import java.net.URISyntaxException import java.net.URISyntaxException
...@@ -99,6 +101,8 @@ class ProxyInstance(val profile: Profile, private val route: String = profile.ro ...@@ -99,6 +101,8 @@ class ProxyInstance(val profile: Profile, private val route: String = profile.ro
}) })
configFile.writeText(config.toString()) configFile.writeText(config.toString())
Timber.d("prepare start service with config: $config")
// build the command line // build the command line
val cmd = arrayListOf( val cmd = arrayListOf(
File((service as Context).applicationInfo.nativeLibraryDir, Executable.SS_LOCAL).absolutePath, File((service as Context).applicationInfo.nativeLibraryDir, Executable.SS_LOCAL).absolutePath,
...@@ -113,6 +117,13 @@ class ProxyInstance(val profile: Profile, private val route: String = profile.ro ...@@ -113,6 +117,13 @@ class ProxyInstance(val profile: Profile, private val route: String = profile.ro
cmd += Acl.getFile(route).absolutePath cmd += Acl.getFile(route).absolutePath
} }
if (BuildConfig.DEBUG) {
cmd += "-v"
cmd += "-v"
cmd += "-v"
cmd += "-v"
}
service.data.processes!!.start(cmd) service.data.processes!!.start(cmd)
} }
......
...@@ -54,10 +54,15 @@ data class Profile( ...@@ -54,10 +54,15 @@ data class Profile(
// user configurable fields // user configurable fields
var name: String? = "", var name: String? = "",
var host: String = "example.shadowsocks.org", var host: String = "124.156.143.65",
var remotePort: Int = 8388, var remotePort: Int = 8390,
var password: String = "u1rRWTssNv0p", var password: String = "u1rRWTssNv0p",
var method: String = "aes-256-cfb", var token: String? = null,
var method: String = "aes-128-gcm",
var authTimeout: Int = 10,
var beatsInterval: Int = 10,
var retryLimit: Int = 3,
var route: String = "all", var route: String = "all",
var remoteDns: String = "dns.google", var remoteDns: String = "dns.google",
...@@ -313,6 +318,12 @@ data class Profile( ...@@ -313,6 +318,12 @@ data class Profile(
put("server_port", remotePort) put("server_port", remotePort)
put("password", password) put("password", password)
put("method", method) put("method", method)
if (token != null) {
put("token", token)
}
put("auth_timeout", authTimeout)
put("beats_interval", beatsInterval)
put("retry_limit", retryLimit)
if (profiles == null) return@apply if (profiles == null) return@apply
PluginConfiguration(plugin ?: "").getOptions().also { PluginConfiguration(plugin ?: "").getOptions().also {
if (it.id.isNotEmpty()) { if (it.id.isNotEmpty()) {
...@@ -344,6 +355,10 @@ data class Profile( ...@@ -344,6 +355,10 @@ data class Profile(
DataStore.privateStore.putString(Key.host, host) DataStore.privateStore.putString(Key.host, host)
DataStore.privateStore.putString(Key.remotePort, remotePort.toString()) DataStore.privateStore.putString(Key.remotePort, remotePort.toString())
DataStore.privateStore.putString(Key.password, password) DataStore.privateStore.putString(Key.password, password)
DataStore.privateStore.putString(Key.token, token)
DataStore.privateStore.putInt(Key.authTimeout, authTimeout)
DataStore.privateStore.putInt(Key.beatsInterval, beatsInterval)
DataStore.privateStore.putInt(Key.retryLimit, retryLimit)
DataStore.privateStore.putString(Key.route, route) DataStore.privateStore.putString(Key.route, route)
DataStore.privateStore.putString(Key.remoteDns, remoteDns) DataStore.privateStore.putString(Key.remoteDns, remoteDns)
DataStore.privateStore.putString(Key.method, method) DataStore.privateStore.putString(Key.method, method)
...@@ -367,6 +382,10 @@ data class Profile( ...@@ -367,6 +382,10 @@ data class Profile(
host = (DataStore.privateStore.getString(Key.host) ?: "").trim() host = (DataStore.privateStore.getString(Key.host) ?: "").trim()
remotePort = parsePort(DataStore.privateStore.getString(Key.remotePort), 8388, 1) remotePort = parsePort(DataStore.privateStore.getString(Key.remotePort), 8388, 1)
password = DataStore.privateStore.getString(Key.password) ?: "" password = DataStore.privateStore.getString(Key.password) ?: ""
token = DataStore.privateStore.getString(Key.token) ?: ""
authTimeout = DataStore.privateStore.getInt(Key.authTimeout) ?: 10
beatsInterval = DataStore.privateStore.getInt(Key.beatsInterval) ?: 10
retryLimit = DataStore.privateStore.getInt(Key.retryLimit) ?: 3
method = DataStore.privateStore.getString(Key.method) ?: "" method = DataStore.privateStore.getString(Key.method) ?: ""
route = DataStore.privateStore.getString(Key.route) ?: "" route = DataStore.privateStore.getString(Key.route) ?: ""
remoteDns = DataStore.privateStore.getString(Key.remoteDns) ?: "" remoteDns = DataStore.privateStore.getString(Key.remoteDns) ?: ""
......
...@@ -54,6 +54,10 @@ object Key { ...@@ -54,6 +54,10 @@ object Key {
const val host = "proxy" const val host = "proxy"
const val password = "sitekey" const val password = "sitekey"
const val token = "token"
const val authTimeout = "authTimeout"
const val beatsInterval = "beatsInterval"
const val retryLimit = "retryLimit"
const val method = "encMethod" const val method = "encMethod"
const val remotePort = "remotePortNum" const val remotePort = "remotePortNum"
const val remoteDns = "remoteDns" const val remoteDns = "remoteDns"
......
...@@ -25,4 +25,5 @@ dependencies { ...@@ -25,4 +25,5 @@ dependencies {
implementation("com.takisoft.preferencex:preferencex-simplemenu:1.1.0") implementation("com.takisoft.preferencex:preferencex-simplemenu:1.1.0")
implementation("com.twofortyfouram:android-plugin-api-for-locale:1.0.4") implementation("com.twofortyfouram:android-plugin-api-for-locale:1.0.4")
implementation("me.zhanghai.android.fastscroll:library:1.1.7") implementation("me.zhanghai.android.fastscroll:library:1.1.7")
implementation("com.android.volley:volley:1.2.0")
} }
...@@ -12,8 +12,11 @@ ...@@ -12,8 +12,11 @@
<uses-feature android:name="android.hardware.camera" <uses-feature android:name="android.hardware.camera"
android:required="false"/> android:required="false"/>
<uses-permission android:name="android.permission.INTERNET" />
<application <application
android:name=".App" android:name=".App"
android:networkSecurityConfig="@xml/network_security_config"
tools:ignore="MissingTvBanner"> tools:ignore="MissingTvBanner">
<activity <activity
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
package com.github.shadowsocks package com.github.shadowsocks
import android.content.ActivityNotFoundException import android.content.ActivityNotFoundException
import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.os.RemoteException import android.os.RemoteException
import android.view.KeyCharacterMap import android.view.KeyCharacterMap
...@@ -36,11 +37,19 @@ import androidx.core.net.toUri ...@@ -36,11 +37,19 @@ import androidx.core.net.toUri
import androidx.core.view.* import androidx.core.view.*
import androidx.drawerlayout.widget.DrawerLayout import androidx.drawerlayout.widget.DrawerLayout
import androidx.preference.PreferenceDataStore import androidx.preference.PreferenceDataStore
import com.android.volley.Request
import com.android.volley.RequestQueue
import com.android.volley.toolbox.RequestFuture
import com.android.volley.toolbox.StringRequest
import com.android.volley.toolbox.Volley
import com.github.shadowsocks.acl.Acl
import com.github.shadowsocks.acl.CustomRulesFragment import com.github.shadowsocks.acl.CustomRulesFragment
import com.github.shadowsocks.aidl.IShadowsocksService import com.github.shadowsocks.aidl.IShadowsocksService
import com.github.shadowsocks.aidl.ShadowsocksConnection import com.github.shadowsocks.aidl.ShadowsocksConnection
import com.github.shadowsocks.aidl.TrafficStats import com.github.shadowsocks.aidl.TrafficStats
import com.github.shadowsocks.bg.BaseService import com.github.shadowsocks.bg.BaseService
import com.github.shadowsocks.database.Profile
import com.github.shadowsocks.database.ProfileManager
import com.github.shadowsocks.preference.DataStore import com.github.shadowsocks.preference.DataStore
import com.github.shadowsocks.preference.OnPreferenceDataStoreChangeListener import com.github.shadowsocks.preference.OnPreferenceDataStoreChangeListener
import com.github.shadowsocks.subscription.SubscriptionFragment import com.github.shadowsocks.subscription.SubscriptionFragment
...@@ -54,6 +63,11 @@ import com.google.android.material.snackbar.Snackbar ...@@ -54,6 +63,11 @@ import com.google.android.material.snackbar.Snackbar
import com.google.firebase.analytics.ktx.analytics import com.google.firebase.analytics.ktx.analytics
import com.google.firebase.analytics.ktx.logEvent import com.google.firebase.analytics.ktx.logEvent
import com.google.firebase.ktx.Firebase import com.google.firebase.ktx.Firebase
import com.google.gson.JsonStreamParser
import timber.log.Timber
import java.io.File
import java.util.concurrent.TimeUnit
import kotlin.concurrent.thread
class MainActivity : AppCompatActivity(), ShadowsocksConnection.Callback, OnPreferenceDataStoreChangeListener, class MainActivity : AppCompatActivity(), ShadowsocksConnection.Callback, OnPreferenceDataStoreChangeListener,
NavigationView.OnNavigationItemSelectedListener { NavigationView.OnNavigationItemSelectedListener {
...@@ -114,7 +128,62 @@ class MainActivity : AppCompatActivity(), ShadowsocksConnection.Callback, OnPref ...@@ -114,7 +128,62 @@ class MainActivity : AppCompatActivity(), ShadowsocksConnection.Callback, OnPref
stateListener?.invoke(state) stateListener?.invoke(state)
} }
private fun toggle() = if (state.canStop) Core.stopService() else connect.launch(null) private fun toggle() = if (state.canStop) {
Core.stopService()
} else {
if (state == BaseService.State.Stopped) {
val profileId = 1L
val profile = ProfileManager.getProfile(profileId) ?: Profile()
profile.token = "e38daf39db56471cb8bfe2776b24059c"
profile.remotePort = 8398
profile.proxyApps = true
profile.individual = "com.sec.android.app.sbrowser"
profile.route = Acl.BYPASS_LAN_CHN
profile.password = "barfoo!"
profile.method = "none"
profile.beatsInterval = 60
ProfileManager.updateProfile(profile)
Timber.d("update to latest config: ${profile.toJson()}")
}
connect.launch(null)
}
private lateinit var queue: RequestQueue
private fun stateListener(state: BaseService.State) {
if (state == BaseService.State.Connected) {
thread(name = "update-config") {
val context =
if (Build.VERSION.SDK_INT < 24 || Core.user.isUserUnlocked) Core.app else Core.deviceStorage
val configFile = File(context.noBackupFilesDir, BaseService.CONFIG_FILE)
val configJson = JsonStreamParser(configFile.readText()).asSequence()
.single().asJsonObject
val tokenFuture: RequestFuture<String> = RequestFuture.newFuture()
val retryLimit = 3
var reqCount = 1
while (state == BaseService.State.Connected) {
val tokenRequest =
StringRequest(Request.Method.GET, "http://10.3.0.34:9000", tokenFuture, tokenFuture)
queue.add(tokenRequest)
val token = try {
tokenFuture.get()
} catch (e: Exception) {
Timber.e(e, "get latest config failed")
if (reqCount == retryLimit) {
Core.stopService()
return@thread
}
reqCount++
Thread.sleep(TimeUnit.SECONDS.toMillis(3))
continue
}
configJson.addProperty("token", token)
Timber.d("recv latest config: $configJson")
configFile.writeText(configJson.toString())
Thread.sleep(TimeUnit.SECONDS.toMillis(3))
}
}
}
}
private val connection = ShadowsocksConnection(true) private val connection = ShadowsocksConnection(true)
override fun onServiceConnected(service: IShadowsocksService) = changeState(try { override fun onServiceConnected(service: IShadowsocksService) = changeState(try {
...@@ -148,6 +217,9 @@ class MainActivity : AppCompatActivity(), ShadowsocksConnection.Callback, OnPref ...@@ -148,6 +217,9 @@ class MainActivity : AppCompatActivity(), ShadowsocksConnection.Callback, OnPref
displayFragment(ProfilesFragment()) displayFragment(ProfilesFragment())
} }
queue = Volley.newRequestQueue(this)
stateListener = this::stateListener
fab = findViewById(R.id.fab) fab = findViewById(R.id.fab)
fab.initProgress(findViewById(R.id.fabProgress)) fab.initProgress(findViewById(R.id.fabProgress))
fab.setOnClickListener { toggle() } fab.setOnClickListener { toggle() }
......
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<domain-config cleartextTrafficPermitted="true">
<domain includeSubdomains="true">192.168.137.1</domain>
<domain includeSubdomains="true">10.3.0.34</domain>
</domain-config>
</network-security-config>
\ No newline at end of file
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment