Commit a6e87cf6 authored by Mygod's avatar Mygod

Merge branch 'master' of github.com:shadowsocks/shadowsocks-android

parents 81295e4a 4817539c
...@@ -14,6 +14,7 @@ gen_* ...@@ -14,6 +14,7 @@ gen_*
*.class *.class
*.o *.o
local.sbt local.sbt
.deps
#Intellij IDEA #Intellij IDEA
*.iml *.iml
...@@ -26,8 +27,6 @@ out/ ...@@ -26,8 +27,6 @@ out/
#NDK #NDK
src/main/obj src/main/obj
src/main/libs src/main/libs
src/main/assets/armeabi src/main/assets/armeabi-v7a/*
src/main/assets/armeabi-v7a src/main/assets/x86/*
src/main/assets/x86
src/main/assets/api-16/
jni/Application.mk jni/Application.mk
...@@ -24,3 +24,9 @@ ...@@ -24,3 +24,9 @@
path = src/main/jni/pdnsd path = src/main/jni/pdnsd
url = https://github.com/shadowsocks/pdnsd.git url = https://github.com/shadowsocks/pdnsd.git
branch = shadowsocks-android branch = shadowsocks-android
[submodule "kcptun/kcptun"]
path = kcptun/kcptun
url = https://github.com/shadowsocks/kcptun
[submodule "kcptun/go"]
path = kcptun/go
url = https://github.com/shadowsocks/go
...@@ -31,6 +31,7 @@ install: ...@@ -31,6 +31,7 @@ install:
- ./travis-ci/setup.sh - ./travis-ci/setup.sh
- export NDK_CCACHE=ccache - export NDK_CCACHE=ccache
- export ARCH=`uname -m` - export ARCH=`uname -m`
- export GOROOT_BOOTSTRAP=$HOME/.android/go
- export ANDROID_NDK_HOME=$HOME/.android/android-ndk-r12b - export ANDROID_NDK_HOME=$HOME/.android/android-ndk-r12b
- export ANDROID_HOME=$HOME/.android/android-sdk-linux - export ANDROID_HOME=$HOME/.android/android-sdk-linux
- export PATH=${ANDROID_NDK_HOME}:${ANDROID_HOME}/tools:${ANDROID_HOME}/platform-tools:${PATH} - export PATH=${ANDROID_NDK_HOME}:${ANDROID_HOME}/tools:${ANDROID_HOME}/platform-tools:${PATH}
......
...@@ -12,6 +12,7 @@ A [shadowsocks](http://shadowsocks.org) client for Android, written in Scala. ...@@ -12,6 +12,7 @@ A [shadowsocks](http://shadowsocks.org) client for Android, written in Scala.
* JDK 1.8 * JDK 1.8
* SBT 0.13.0+ * SBT 0.13.0+
* GO 1.4+
* Android SDK r25+ * Android SDK r25+
* Android NDK r12b+ * Android NDK r12b+
...@@ -19,6 +20,7 @@ A [shadowsocks](http://shadowsocks.org) client for Android, written in Scala. ...@@ -19,6 +20,7 @@ A [shadowsocks](http://shadowsocks.org) client for Android, written in Scala.
* Set environment variable `ANDROID_HOME` to `/path/to/android-sdk` * Set environment variable `ANDROID_HOME` to `/path/to/android-sdk`
* Set environment variable `ANDROID_NDK_HOME` to `/path/to/android-ndk` * Set environment variable `ANDROID_NDK_HOME` to `/path/to/android-ndk`
* Set environment variable `GOROOT_BOOTSTRAP` to `/path/to/go`
* Create your key following the instructions at https://developer.android.com/studio/publish/app-signing.html * Create your key following the instructions at https://developer.android.com/studio/publish/app-signing.html
* Put your key in ~/.keystore * Put your key in ~/.keystore
* Create `local.properties` from `local.properties.example` with your own key information * Create `local.properties` from `local.properties.example` with your own key information
...@@ -31,28 +33,6 @@ A [shadowsocks](http://shadowsocks.org) client for Android, written in Scala. ...@@ -31,28 +33,6 @@ A [shadowsocks](http://shadowsocks.org) client for Android, written in Scala.
sbt native-build clean android:package-release sbt native-build clean android:package-release
``` ```
#### BUILD on Mac OS X (with HomeBrew)
* Install Android SDK and NDK by run `brew install android-ndk android-sdk`
* Add `export ANDROID_HOME=/usr/local/Cellar/android-sdk/$version` to your .bashrc , then reopen the shell to load it.
* Add `export ANDROID_NDK_HOME=/usr/local/Cellar/android-ndk/$version` to your .bashrc , then reopen the shell to load it.
* echo "y" | android update sdk --filter tools,platform-tools,build-tools-23.0.2,android-23,extra-google-m2repository --no-ui -a
* echo "y" | android update sdk --filter extra-android-m2repository --no-ui --no-https -a
* Create your key following the instructions at http://developer.android.com/guide/publishing/app-signing.html#cert
* Put your key in ~/.keystore
* Create `local.properties` from `local.properties.example` with your own key information .
* Invoke the building like this
```bash
git submodule update --init
# Build native binaries
./build.sh
# Build the apk
sbt clean android:package-release
```
## OPEN SOURCE LICENSES ## OPEN SOURCE LICENSES
* shadowsocks-libev: [GPLv3](https://github.com/shadowsocks/shadowsocks-libev/blob/master/LICENSE) * shadowsocks-libev: [GPLv3](https://github.com/shadowsocks/shadowsocks-libev/blob/master/LICENSE)
...@@ -62,6 +42,7 @@ A [shadowsocks](http://shadowsocks.org) client for Android, written in Scala. ...@@ -62,6 +42,7 @@ A [shadowsocks](http://shadowsocks.org) client for Android, written in Scala.
* pdnsd: [GPLv3](https://github.com/shadowsocks/shadowsocks-android/blob/master/src/main/jni/pdnsd/COPYING) * pdnsd: [GPLv3](https://github.com/shadowsocks/shadowsocks-android/blob/master/src/main/jni/pdnsd/COPYING)
* libev: [GPLv2](https://github.com/shadowsocks/shadowsocks-android/blob/master/src/main/jni/libev/LICENSE) * libev: [GPLv2](https://github.com/shadowsocks/shadowsocks-android/blob/master/src/main/jni/libev/LICENSE)
* libevent: [BSD](https://github.com/shadowsocks/libevent/blob/master/LICENSE) * libevent: [BSD](https://github.com/shadowsocks/libevent/blob/master/LICENSE)
* kcptun: [MIT](https://github.com/xtaci/kcptun)
### LICENSE ### LICENSE
......
...@@ -55,6 +55,8 @@ proguardCache in Android := Seq() ...@@ -55,6 +55,8 @@ proguardCache in Android := Seq()
proguardOptions in Android ++= Seq( proguardOptions in Android ++= Seq(
"-keep class com.github.shadowsocks.System { *; }", "-keep class com.github.shadowsocks.System { *; }",
"-dontwarn com.google.android.gms.**",
"-keep class com.google.android.gms.**",
"-dontnote com.google.android.gms.internal.**", "-dontnote com.google.android.gms.internal.**",
"-dontnote com.j256.ormlite.**", "-dontnote com.j256.ormlite.**",
"-dontnote me.dm7.barcodescannerview.**", "-dontnote me.dm7.barcodescannerview.**",
......
...@@ -4,21 +4,25 @@ function try () { ...@@ -4,21 +4,25 @@ function try () {
"$@" || exit -1 "$@" || exit -1
} }
try pushd src/main # Build native binaries
pushd src/main
# Build
#try $ANDROID_NDK_HOME/ndk-build clean
try $ANDROID_NDK_HOME/ndk-build -j8 try $ANDROID_NDK_HOME/ndk-build -j8
# copy executables
rm -rf assets/armeabi-v7a rm -rf assets/armeabi-v7a
rm -rf assets/x86 rm -rf assets/x86
mkdir -p assets/armeabi-v7a mkdir -p assets/armeabi-v7a
mkdir -p assets/x86 mkdir -p assets/x86
#copy executables
for app in pdnsd redsocks ss-local ss-tunnel tun2socks for app in pdnsd redsocks ss-local ss-tunnel tun2socks
do do
echo $app
try mv libs/armeabi-v7a/$app assets/armeabi-v7a/ try mv libs/armeabi-v7a/$app assets/armeabi-v7a/
try mv libs/x86/$app assets/x86/ try mv libs/x86/$app assets/x86/
done done
popd
try popd # Build kcptun
pushd kcptun
try ./make.bash
popd
Subproject commit f3e7e7b69f0fd0c22858d09b4dd3764ed703d140
Subproject commit eced3949b2f33e1801aec6124a01922482358f3e
#!/bin/bash
function try () {
"$@" || exit -1
}
[ -z "$ANDROID_NDK_HOME" ] && ANDROID_NDK_HOME=~/android-ndk-r12b
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
DEPS=$DIR/.deps
ANDROID_ARM_TOOLCHAIN=$DEPS/android-toolchain-16-arm
ANDROID_X86_TOOLCHAIN=$DEPS/android-toolchain-16-x86
ANDROID_ARM_CC=$ANDROID_ARM_TOOLCHAIN/bin/arm-linux-androideabi-gcc
ANDROID_ARM_STRIP=$ANDROID_ARM_TOOLCHAIN/bin/arm-linux-androideabi-strip
ANDROID_X86_CC=$ANDROID_X86_TOOLCHAIN/bin/i686-linux-android-gcc
ANDROID_X86_STRIP=$ANDROID_X86_TOOLCHAIN/bin/i686-linux-android-strip
if [ ! -d "$DEPS" ]; then
mkdir -p $DEPS
fi
if [ ! -d "$ANDROID_ARM_TOOLCHAIN" ]; then
echo "Make standalone toolchain for ARM arch"
$ANDROID_NDK_HOME/build/tools/make_standalone_toolchain.py --arch arm \
--api 16 --install-dir $ANDROID_ARM_TOOLCHAIN
fi
if [ ! -d "$ANDROID_X86_TOOLCHAIN" ]; then
echo "Make standalone toolchain for X86 arch"
$ANDROID_NDK_HOME/build/tools/make_standalone_toolchain.py --arch x86 \
--api 16 --install-dir $ANDROID_X86_TOOLCHAIN
fi
if [ ! -d "$DIR/go/bin" ]; then
echo "Build the custom go"
pushd $DIR/go/src
try ./make.bash
popd
fi
export GOROOT=$DIR/go
export GOPATH=$DEPS
export PATH=$GOROOT/bin:$PATH
pushd kcptun/client
echo "Get dependences for kcptun"
go get
echo "Cross compile kcptun for arm"
try env CGO_ENABLED=1 CC=$ANDROID_ARM_CC GOOS=android GOARCH=arm GOARM=7 go build
try $ANDROID_ARM_STRIP client
try mv client $DIR/../src/main/assets/armeabi-v7a/kcptun
echo "Cross compile kcptun for x86"
try env CGO_ENABLED=1 CC=$ANDROID_X86_CC GOOS=android GOARCH=386 go build
try $ANDROID_X86_STRIP client
try mv client $DIR/../src/main/assets/x86/kcptun
popd
echo "Successfully build kcptun"
addSbtPlugin("org.scala-android" % "sbt-android" % "1.6.8") addSbtPlugin("org.scala-android" % "sbt-android" % "1.6.10")
addSbtPlugin("com.timushev.sbt" % "sbt-updates" % "0.1.10") addSbtPlugin("com.timushev.sbt" % "sbt-updates" % "0.1.10")
......
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" package="com.github.shadowsocks" xmlns:tools="http://schemas.android.com/tools" package="com.github.shadowsocks"
android:versionCode="141" android:versionCode="144"
android:versionName="2.10.8"> android:versionName="3.0.2">
<uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
......
...@@ -296,6 +296,7 @@ along with this program. If not, see <a href="http://www.gnu.org/licenses/">http ...@@ -296,6 +296,7 @@ along with this program. If not, see <a href="http://www.gnu.org/licenses/">http
<li>pdnsd: <a href="https://github.com/shadowsocks/shadowsocks-android/blob/master/src/main/jni/pdnsd/COPYING">GPLv3</a></li> <li>pdnsd: <a href="https://github.com/shadowsocks/shadowsocks-android/blob/master/src/main/jni/pdnsd/COPYING">GPLv3</a></li>
<li>libev: <a href="https://github.com/shadowsocks/libevent/blob/shadowsocks-android/LICENSE">GPLv2</a></li> <li>libev: <a href="https://github.com/shadowsocks/libevent/blob/shadowsocks-android/LICENSE">GPLv2</a></li>
<li>libevent: <a href="https://github.com/shadowsocks/shadowsocks-android/blob/master/src/main/jni/libevent/LICENSE">BSD</a></li> <li>libevent: <a href="https://github.com/shadowsocks/shadowsocks-android/blob/master/src/main/jni/libevent/LICENSE">BSD</a></li>
<li>kcptun: <a href="https://github.com/xtaci/kcptun/commits/master/LICENSE.md">MIT</a></li>
</ul> </ul>
</body> </body>
......
Subproject commit d4aabcb40b4bcbca352269a1474a19de691950d0 Subproject commit 915047e957d5bd581be8e144ed92a1bb05441af5
...@@ -134,4 +134,11 @@ ...@@ -134,4 +134,11 @@
<!-- status --> <!-- status -->
<string name="sent">Отправлено:</string> <string name="sent">Отправлено:</string>
<string name="received">Получено:</string> <string name="received">Получено:</string>
<!-- kcp -->
<string name="kcp_summary">Включить Shadowsocks над KCPTUN</string>
<string name="kcp_port">KCP порт</string>
<string name="kcp_port_summary">%d (KCPTUN омер порта удалённого сервера)</string>
<string name="kcpcli">KCP параметры</string>
<string name="kcpcli_summary">Командная строка KCPTUN</string>
</resources> </resources>
...@@ -134,4 +134,11 @@ ...@@ -134,4 +134,11 @@
<string name="sent">发送:</string> <string name="sent">发送:</string>
<string name="received">接收:</string> <string name="received">接收:</string>
<!-- kcp -->
<string name="kcp_summary">启用 KCP 协议</string>
<string name="kcp_port">KCP 端口</string>
<string name="kcp_port_summary">%d(远端 KCPTUN 服务器的端口号)</string>
<string name="kcpcli">KCP 参数</string>
<string name="kcpcli_summary">KCPTUN 的命令行参数</string>
</resources> </resources>
...@@ -136,4 +136,11 @@ ...@@ -136,4 +136,11 @@
<string name="sent">傳送:</string> <string name="sent">傳送:</string>
<string name="received">接收:</string> <string name="received">接收:</string>
<!-- kcp -->
<string name="kcp_summary">啟用 KCP 協定</string>
<string name="kcp_port">KCP 連接埠</string>
<string name="kcp_port_summary">%d(遠端 KCPTUN 伺服器的連接埠號碼)</string>
<string name="kcpcli">KCP 參數</string>
<string name="kcpcli_summary">KCPTUN 的命令行參數</string>
</resources> </resources>
...@@ -139,4 +139,12 @@ ...@@ -139,4 +139,12 @@
<!-- status --> <!-- status -->
<string name="sent">Sent:</string> <string name="sent">Sent:</string>
<string name="received">Received:</string> <string name="received">Received:</string>
<!-- kcp -->
<string name="kcp" translatable="false">KCP</string>
<string name="kcp_summary">Enable Shadowsocks over KCP</string>
<string name="kcp_port">KCP Port</string>
<string name="kcp_port_summary">%d (port number of the remote KCPTUN server)</string>
<string name="kcpcli">KCP Parameters (CLI)</string>
<string name="kcpcli_summary">The command line of KCPTUN</string>
</resources> </resources>
...@@ -77,6 +77,31 @@ ...@@ -77,6 +77,31 @@
</PreferenceCategory> </PreferenceCategory>
<PreferenceCategory
android:title="@string/kcp">
<SwitchPreference
android:key="kcp"
android:persistent="false"
android:summary="@string/kcp_summary"
android:title="@string/kcp"/>
<com.github.shadowsocks.preferences.NumberPickerPreference
app:min="1"
app:max="65535"
android:key="kcpPort"
android:persistent="false"
android:summary="@string/kcp_port_summary"
android:title="@string/kcp_port"/>
<com.github.shadowsocks.preferences.SummaryEditTextPreference
android:key="kcpcli"
android:persistent="false"
android:summary="@string/kcpcli_summary"
android:title="@string/kcpcli"/>
</PreferenceCategory>
<PreferenceCategory android:title="@string/misc_cat"> <PreferenceCategory android:title="@string/misc_cat">
<SwitchPreference <SwitchPreference
......
...@@ -43,10 +43,12 @@ import java.util.{Timer, TimerTask} ...@@ -43,10 +43,12 @@ import java.util.{Timer, TimerTask}
import android.app.Service import android.app.Service
import android.content.{BroadcastReceiver, Context, Intent, IntentFilter} import android.content.{BroadcastReceiver, Context, Intent, IntentFilter}
import android.net.ConnectivityManager
import android.os.{Handler, RemoteCallbackList} import android.os.{Handler, RemoteCallbackList}
import android.text.TextUtils import android.text.TextUtils
import android.util.Log import android.util.Log
import android.widget.Toast import android.widget.Toast
import com.github.kevinsawicki.http.HttpRequest import com.github.kevinsawicki.http.HttpRequest
import com.github.shadowsocks.aidl.{IShadowsocksService, IShadowsocksServiceCallback} import com.github.shadowsocks.aidl.{IShadowsocksService, IShadowsocksServiceCallback}
import com.github.shadowsocks.utils._ import com.github.shadowsocks.utils._
...@@ -71,6 +73,16 @@ trait BaseService extends Service { ...@@ -71,6 +73,16 @@ trait BaseService extends Service {
} }
var closeReceiverRegistered: Boolean = _ var closeReceiverRegistered: Boolean = _
var kcptunProcess: GuardedProcess = _
private val networkReceiver: BroadcastReceiver = (context: Context, intent: Intent) => {
val cm = context.getSystemService(Context.CONNECTIVITY_SERVICE).asInstanceOf[ConnectivityManager]
val activeNetwork = cm.getActiveNetworkInfo()
val isConnected = activeNetwork != null && activeNetwork.isConnected()
if (isConnected && profile.kcp && kcptunProcess != null) kcptunProcess.restart()
}
var networkReceiverRegistered: Boolean = _
val binder = new IShadowsocksService.Stub { val binder = new IShadowsocksService.Stub {
override def getState: Int = { override def getState: Int = {
state state
...@@ -162,6 +174,14 @@ trait BaseService extends Service { ...@@ -162,6 +174,14 @@ trait BaseService extends Service {
closeReceiverRegistered = true closeReceiverRegistered = true
} }
if (profile.kcp && !networkReceiverRegistered) {
// register network change receiver
val filter = new IntentFilter()
filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION)
registerReceiver(networkReceiver, filter)
networkReceiverRegistered = true
}
app.track(getClass.getSimpleName, "start") app.track(getClass.getSimpleName, "start")
changeState(State.CONNECTING) changeState(State.CONNECTING)
...@@ -177,6 +197,10 @@ trait BaseService extends Service { ...@@ -177,6 +197,10 @@ trait BaseService extends Service {
unregisterReceiver(closeReceiver) unregisterReceiver(closeReceiver)
closeReceiverRegistered = false closeReceiverRegistered = false
} }
if (networkReceiverRegistered) {
unregisterReceiver(networkReceiver)
networkReceiverRegistered = false
}
// Make sure update total traffic when stopping the runner // Make sure update total traffic when stopping the runner
updateTrafficTotal(TrafficMonitor.txTotal, TrafficMonitor.rxTotal) updateTrafficTotal(TrafficMonitor.txTotal, TrafficMonitor.rxTotal)
......
...@@ -56,6 +56,7 @@ class GuardedProcess(cmd: Seq[String]) extends Process { ...@@ -56,6 +56,7 @@ class GuardedProcess(cmd: Seq[String]) extends Process {
@volatile private var guardThread: Thread = _ @volatile private var guardThread: Thread = _
@volatile private var isDestroyed: Boolean = _ @volatile private var isDestroyed: Boolean = _
@volatile private var process: Process = _ @volatile private var process: Process = _
@volatile private var isRestart = false
def start(onRestartCallback: () => Unit = null): GuardedProcess = { def start(onRestartCallback: () => Unit = null): GuardedProcess = {
val semaphore = new Semaphore(1) val semaphore = new Semaphore(1)
...@@ -76,11 +77,15 @@ class GuardedProcess(cmd: Seq[String]) extends Process { ...@@ -76,11 +77,15 @@ class GuardedProcess(cmd: Seq[String]) extends Process {
semaphore.release semaphore.release
process.waitFor process.waitFor
if (isRestart) {
isRestart = false
} else {
if (currentTimeMillis - startTime < 1000) { if (currentTimeMillis - startTime < 1000) {
Log.w(TAG, "process exit too fast, stop guard: " + cmd) Log.w(TAG, "process exit too fast, stop guard: " + cmd)
isDestroyed = true isDestroyed = true
} }
} }
}
} catch { } catch {
case ignored: InterruptedException => case ignored: InterruptedException =>
Log.i(TAG, "thread interrupt, destroy process: " + cmd) Log.i(TAG, "thread interrupt, destroy process: " + cmd)
...@@ -108,6 +113,11 @@ class GuardedProcess(cmd: Seq[String]) extends Process { ...@@ -108,6 +113,11 @@ class GuardedProcess(cmd: Seq[String]) extends Process {
} }
} }
def restart() {
isRestart = true
process.destroy()
}
def exitValue: Int = throw new UnsupportedOperationException def exitValue: Int = throw new UnsupportedOperationException
def getErrorStream: InputStream = throw new UnsupportedOperationException def getErrorStream: InputStream = throw new UnsupportedOperationException
def getInputStream: InputStream = throw new UnsupportedOperationException def getInputStream: InputStream = throw new UnsupportedOperationException
......
...@@ -94,7 +94,7 @@ object Shadowsocks { ...@@ -94,7 +94,7 @@ object Shadowsocks {
private final val TAG = "Shadowsocks" private final val TAG = "Shadowsocks"
private final val REQUEST_CONNECT = 1 private final val REQUEST_CONNECT = 1
private val EXECUTABLES = Array(Executable.PDNSD, Executable.REDSOCKS, Executable.SS_TUNNEL, Executable.SS_LOCAL, private val EXECUTABLES = Array(Executable.PDNSD, Executable.REDSOCKS, Executable.SS_TUNNEL, Executable.SS_LOCAL,
Executable.TUN2SOCKS) Executable.TUN2SOCKS, Executable.KCPTUN)
} }
class Shadowsocks extends AppCompatActivity with ServiceBoundContext { class Shadowsocks extends AppCompatActivity with ServiceBoundContext {
...@@ -286,7 +286,7 @@ class Shadowsocks extends AppCompatActivity with ServiceBoundContext { ...@@ -286,7 +286,7 @@ class Shadowsocks extends AppCompatActivity with ServiceBoundContext {
def crashRecovery() { def crashRecovery() {
val cmd = new ArrayBuffer[String]() val cmd = new ArrayBuffer[String]()
for (task <- Array("ss-local", "ss-tunnel", "pdnsd", "redsocks", "tun2socks")) { for (task <- Array("ss-local", "ss-tunnel", "pdnsd", "redsocks", "tun2socks", "kcptun")) {
cmd.append("killall %s".formatLocal(Locale.ENGLISH, task)) cmd.append("killall %s".formatLocal(Locale.ENGLISH, task))
cmd.append("rm -f %1$s/%2$s-nat.conf %1$s/%2$s-vpn.conf" cmd.append("rm -f %1$s/%2$s-nat.conf %1$s/%2$s-vpn.conf"
.formatLocal(Locale.ENGLISH, getApplicationInfo.dataDir, task)) .formatLocal(Locale.ENGLISH, getApplicationInfo.dataDir, task))
...@@ -481,7 +481,7 @@ class Shadowsocks extends AppCompatActivity with ServiceBoundContext { ...@@ -481,7 +481,7 @@ class Shadowsocks extends AppCompatActivity with ServiceBoundContext {
private def updatePreferenceScreen(profile: Profile) { private def updatePreferenceScreen(profile: Profile) {
if (profile.host == "198.199.101.152") if (adView == null) { if (profile.host == "198.199.101.152") if (adView == null) {
adView = new AdView(this) adView = new AdView(this)
adView.setAdUnitId("ca-app-pub-9097031975646651/7760346322") adView.setAdUnitId("ca-app-pub-4984938374218635/1433320509")
adView.setAdSize(AdSize.SMART_BANNER) adView.setAdSize(AdSize.SMART_BANNER)
preferences.getView.asInstanceOf[ViewGroup].addView(adView, 1) preferences.getView.asInstanceOf[ViewGroup].addView(adView, 1)
adView.loadAd(new AdRequest.Builder().build()) adView.loadAd(new AdRequest.Builder().build())
......
...@@ -84,9 +84,15 @@ class ShadowsocksNatService extends BaseService { ...@@ -84,9 +84,15 @@ class ShadowsocksNatService extends BaseService {
}) })
} }
val conf = ConfigUtils val conf = if (profile.kcp) {
ConfigUtils
.SHADOWSOCKS.formatLocal(Locale.ENGLISH, "127.0.0.1", profile.localPort + 90, profile.localPort,
profile.password, profile.method, 600)
} else {
ConfigUtils
.SHADOWSOCKS.formatLocal(Locale.ENGLISH, profile.host, profile.remotePort, profile.localPort, .SHADOWSOCKS.formatLocal(Locale.ENGLISH, profile.host, profile.remotePort, profile.localPort,
profile.password, profile.method, 600) profile.password, profile.method, 600)
}
Utils.printToFile(new File(getApplicationInfo.dataDir + "/ss-local-nat.conf"))(p => { Utils.printToFile(new File(getApplicationInfo.dataDir + "/ss-local-nat.conf"))(p => {
p.println(conf) p.println(conf)
}) })
...@@ -109,10 +115,23 @@ class ShadowsocksNatService extends BaseService { ...@@ -109,10 +115,23 @@ class ShadowsocksNatService extends BaseService {
sslocalProcess = new GuardedProcess(cmd).start() sslocalProcess = new GuardedProcess(cmd).start()
} }
def startTunnel() { def startKcptunDaemon() {
val cmd = new ArrayBuffer[String]
cmd += (getApplicationInfo.dataDir + "/kcptun"
, "-r", profile.host + ":" + profile.kcpPort
, "-l", "127.0.0.1:" + (profile.localPort + 90)
, profile.kcpcli)
if (BuildConfig.DEBUG) Log.d(TAG, cmd.mkString(" "))
kcptunProcess = new GuardedProcess(cmd.mkString(" ").split(" ").toSeq).start()
}
def startDNSTunnel() {
if (profile.udpdns) { if (profile.udpdns) {
val conf = ConfigUtils val conf = ConfigUtils
.SHADOWSOCKS.formatLocal(Locale.ENGLISH, profile.host, profile.remotePort, 8153, .SHADOWSOCKS.formatLocal(Locale.ENGLISH, profile.host, profile.remotePort, profile.localPort + 53,
profile.password, profile.method, 10) profile.password, profile.method, 10)
Utils.printToFile(new File(getApplicationInfo.dataDir + "/ss-tunnel-nat.conf"))(p => { Utils.printToFile(new File(getApplicationInfo.dataDir + "/ss-tunnel-nat.conf"))(p => {
p.println(conf) p.println(conf)
...@@ -123,11 +142,10 @@ class ShadowsocksNatService extends BaseService { ...@@ -123,11 +142,10 @@ class ShadowsocksNatService extends BaseService {
, "-t" , "10" , "-t" , "10"
, "-b" , "127.0.0.1" , "-b" , "127.0.0.1"
, "-L" , "8.8.8.8:53" , "-L" , "8.8.8.8:53"
, "-l" , (profile.localPort + 53).toString
, "-P" , getApplicationInfo.dataDir , "-P" , getApplicationInfo.dataDir
, "-c" , getApplicationInfo.dataDir + "/ss-tunnel-nat.conf") , "-c" , getApplicationInfo.dataDir + "/ss-tunnel-nat.conf")
cmd += ("-l" , "8153")
if (profile.auth) cmd += "-A" if (profile.auth) cmd += "-A"
if (BuildConfig.DEBUG) Log.d(TAG, cmd.mkString(" ")) if (BuildConfig.DEBUG) Log.d(TAG, cmd.mkString(" "))
...@@ -135,18 +153,23 @@ class ShadowsocksNatService extends BaseService { ...@@ -135,18 +153,23 @@ class ShadowsocksNatService extends BaseService {
sstunnelProcess = new GuardedProcess(cmd).start() sstunnelProcess = new GuardedProcess(cmd).start()
} else { } else {
val conf = ConfigUtils val conf = if (profile.kcp) {
.SHADOWSOCKS.formatLocal(Locale.ENGLISH, profile.host, profile.remotePort, 8163, ConfigUtils
.SHADOWSOCKS.formatLocal(Locale.ENGLISH, "127.0.0.1", profile.localPort + 90,
profile.localPort + 63, profile.password, profile.method, 10)
} else {
ConfigUtils
.SHADOWSOCKS.formatLocal(Locale.ENGLISH, profile.host, profile.remotePort, profile.localPort + 63,
profile.password, profile.method, 10) profile.password, profile.method, 10)
}
Utils.printToFile(new File(getApplicationInfo.dataDir + "/ss-tunnel-nat.conf"))(p => { Utils.printToFile(new File(getApplicationInfo.dataDir + "/ss-tunnel-nat.conf"))(p => {
p.println(conf) p.println(conf)
}) })
val cmdBuf = new ArrayBuffer[String] val cmdBuf = new ArrayBuffer[String]
cmdBuf += (getApplicationInfo.dataDir + "/ss-tunnel" cmdBuf += (getApplicationInfo.dataDir + "/ss-tunnel"
, "-u"
, "-t" , "10" , "-t" , "10"
, "-b" , "127.0.0.1" , "-b" , "127.0.0.1"
, "-l" , "8163" , "-l" , (profile.localPort + 63).toString
, "-L" , "8.8.8.8:53" , "-L" , "8.8.8.8:53"
, "-P", getApplicationInfo.dataDir , "-P", getApplicationInfo.dataDir
, "-c" , getApplicationInfo.dataDir + "/ss-tunnel-nat.conf") , "-c" , getApplicationInfo.dataDir + "/ss-tunnel-nat.conf")
...@@ -163,10 +186,10 @@ class ShadowsocksNatService extends BaseService { ...@@ -163,10 +186,10 @@ class ShadowsocksNatService extends BaseService {
val conf = if (profile.route == Route.BYPASS_CHN || profile.route == Route.BYPASS_LAN_CHN) { val conf = if (profile.route == Route.BYPASS_CHN || profile.route == Route.BYPASS_LAN_CHN) {
ConfigUtils.PDNSD_DIRECT.formatLocal(Locale.ENGLISH, getApplicationInfo.dataDir, ConfigUtils.PDNSD_DIRECT.formatLocal(Locale.ENGLISH, getApplicationInfo.dataDir,
"127.0.0.1", 8153, getBlackList, 8163, "") "127.0.0.1", profile.localPort + 53, getBlackList, profile.localPort + 63, "")
} else { } else {
ConfigUtils.PDNSD_LOCAL.formatLocal(Locale.ENGLISH, getApplicationInfo.dataDir, ConfigUtils.PDNSD_LOCAL.formatLocal(Locale.ENGLISH, getApplicationInfo.dataDir,
"127.0.0.1", 8153, 8163, "") "127.0.0.1", profile.localPort + 53, profile.localPort + 63, "")
} }
Utils.printToFile(new File(getApplicationInfo.dataDir + "/pdnsd-nat.conf"))(p => { Utils.printToFile(new File(getApplicationInfo.dataDir + "/pdnsd-nat.conf"))(p => {
...@@ -194,10 +217,13 @@ class ShadowsocksNatService extends BaseService { ...@@ -194,10 +217,13 @@ class ShadowsocksNatService extends BaseService {
/** Called when the activity is first created. */ /** Called when the activity is first created. */
def handleConnection { def handleConnection {
startTunnel() startDNSTunnel()
if (!profile.udpdns) startDnsDaemon()
startRedsocksDaemon() startRedsocksDaemon()
startShadowsocksDaemon() startShadowsocksDaemon()
if (!profile.udpdns) startDnsDaemon()
if (profile.kcp) startKcptunDaemon()
setupIptables() setupIptables()
} }
...@@ -212,6 +238,10 @@ class ShadowsocksNatService extends BaseService { ...@@ -212,6 +238,10 @@ class ShadowsocksNatService extends BaseService {
} }
def killProcesses() { def killProcesses() {
if (kcptunProcess != null) {
kcptunProcess.destroy()
kcptunProcess = null
}
if (sslocalProcess != null) { if (sslocalProcess != null) {
sslocalProcess.destroy() sslocalProcess.destroy()
sslocalProcess = null sslocalProcess = null
...@@ -247,7 +277,8 @@ class ShadowsocksNatService extends BaseService { ...@@ -247,7 +277,8 @@ class ShadowsocksNatService extends BaseService {
init_sb.append(cmd_bypass.replace("-p tcp -d 0.0.0.0", "-m owner --uid-owner " + myUid)) init_sb.append(cmd_bypass.replace("-p tcp -d 0.0.0.0", "-m owner --uid-owner " + myUid))
init_sb.append(cmd_bypass.replace("-d 0.0.0.0", "--dport 53")) init_sb.append(cmd_bypass.replace("-d 0.0.0.0", "--dport 53"))
init_sb.append("iptables -t nat -A OUTPUT -p udp --dport 53 -j DNAT --to-destination 127.0.0.1:8153") init_sb.append("iptables -t nat -A OUTPUT -p udp --dport 53 -j DNAT --to-destination 127.0.0.1:"
+ (profile.localPort + 53))
if (!profile.proxyApps || profile.bypass) { if (!profile.proxyApps || profile.bypass) {
http_sb.append(CMD_IPTABLES_DNAT_ADD_SOCKS) http_sb.append(CMD_IPTABLES_DNAT_ADD_SOCKS)
......
...@@ -18,7 +18,7 @@ object ShadowsocksSettings { ...@@ -18,7 +18,7 @@ object ShadowsocksSettings {
// Constants // Constants
private final val TAG = "ShadowsocksSettings" private final val TAG = "ShadowsocksSettings"
private val PROXY_PREFS = Array(Key.name, Key.host, Key.remotePort, Key.localPort, Key.password, Key.method, private val PROXY_PREFS = Array(Key.name, Key.host, Key.remotePort, Key.localPort, Key.password, Key.method,
Key.auth) Key.auth, Key.kcp, Key.kcpPort, Key.kcpcli)
private val FEATURE_PREFS = Array(Key.route, Key.proxyApps, Key.udpdns, Key.ipv6) private val FEATURE_PREFS = Array(Key.route, Key.proxyApps, Key.udpdns, Key.ipv6)
// Helper functions // Helper functions
...@@ -36,9 +36,11 @@ object ShadowsocksSettings { ...@@ -36,9 +36,11 @@ object ShadowsocksSettings {
} }
def updateSummaryEditTextPreference(pref: Preference, value: String) { def updateSummaryEditTextPreference(pref: Preference, value: String) {
if (value != null) {
pref.setSummary(value) pref.setSummary(value)
pref.asInstanceOf[SummaryEditTextPreference].setText(value) pref.asInstanceOf[SummaryEditTextPreference].setText(value)
} }
}
def updateSwitchPreference(pref: Preference, value: Boolean) { def updateSwitchPreference(pref: Preference, value: Boolean) {
pref.asInstanceOf[SwitchPreference].setChecked(value) pref.asInstanceOf[SwitchPreference].setChecked(value)
...@@ -57,6 +59,9 @@ object ShadowsocksSettings { ...@@ -57,6 +59,9 @@ object ShadowsocksSettings {
case Key.udpdns => updateSwitchPreference(pref, profile.udpdns) case Key.udpdns => updateSwitchPreference(pref, profile.udpdns)
case Key.auth => updateSwitchPreference(pref, profile.auth) case Key.auth => updateSwitchPreference(pref, profile.auth)
case Key.ipv6 => updateSwitchPreference(pref, profile.ipv6) case Key.ipv6 => updateSwitchPreference(pref, profile.ipv6)
case Key.kcp => updateSwitchPreference(pref, profile.kcp)
case Key.kcpPort => updateNumberPickerPreference(pref, profile.kcpPort)
case Key.kcpcli => updateSummaryEditTextPreference(pref, profile.kcpcli)
} }
} }
} }
...@@ -103,6 +108,19 @@ class ShadowsocksSettings extends PreferenceFragment with OnSharedPreferenceChan ...@@ -103,6 +108,19 @@ class ShadowsocksSettings extends PreferenceFragment with OnSharedPreferenceChan
app.profileManager.updateProfile(profile) app.profileManager.updateProfile(profile)
}) })
findPreference(Key.kcp).setOnPreferenceChangeListener((_, value) => {
profile.kcp = value.asInstanceOf[Boolean]
app.profileManager.updateProfile(profile)
})
findPreference(Key.kcpPort).setOnPreferenceChangeListener((_, value) => {
profile.kcpPort = value.asInstanceOf[Int]
app.profileManager.updateProfile(profile)
})
findPreference(Key.kcpcli).setOnPreferenceChangeListener((_, value) => {
profile.kcpcli = value.asInstanceOf[String]
app.profileManager.updateProfile(profile)
})
isProxyApps = findPreference(Key.proxyApps).asInstanceOf[SwitchPreference] isProxyApps = findPreference(Key.proxyApps).asInstanceOf[SwitchPreference]
isProxyApps.setOnPreferenceClickListener(_ => { isProxyApps.setOnPreferenceClickListener(_ => {
startActivity(new Intent(activity, classOf[AppManager])) startActivity(new Intent(activity, classOf[AppManager]))
......
...@@ -109,6 +109,10 @@ class ShadowsocksVpnService extends VpnService with BaseService { ...@@ -109,6 +109,10 @@ class ShadowsocksVpnService extends VpnService with BaseService {
} }
def killProcesses() { def killProcesses() {
if (kcptunProcess != null) {
kcptunProcess.destroy()
kcptunProcess = null
}
if (sslocalProcess != null) { if (sslocalProcess != null) {
sslocalProcess.destroy() sslocalProcess.destroy()
sslocalProcess = null sslocalProcess = null
...@@ -177,18 +181,65 @@ class ShadowsocksVpnService extends VpnService with BaseService { ...@@ -177,18 +181,65 @@ class ShadowsocksVpnService extends VpnService with BaseService {
/** Called when the activity is first created. */ /** Called when the activity is first created. */
def handleConnection: Boolean = { def handleConnection: Boolean = {
val fd = startVpn()
if (!sendFd(fd)) return false
if (profile.kcp) {
startKcptunDaemon()
}
startShadowsocksDaemon() startShadowsocksDaemon()
if (profile.udpdns && profile.kcp) {
startShadowsocksUDPDaemon()
}
if (!profile.udpdns) { if (!profile.udpdns) {
startDnsDaemon() startDnsDaemon()
startDnsTunnel() startDnsTunnel()
} }
val fd = startVpn() true
sendFd(fd)
} }
def startShadowsocksDaemon() { def startKcptunDaemon() {
val cmd = new ArrayBuffer[String]
cmd += (getApplicationInfo.dataDir + "/kcptun"
, "-r", profile.host + ":" + profile.kcpPort
, "-l", "127.0.0.1:" + (profile.localPort + 90)
, "--path", getApplicationInfo.dataDir + "/protect_path"
, profile.kcpcli)
if (BuildConfig.DEBUG)
Log.d(TAG, cmd.mkString(" "))
kcptunProcess = new GuardedProcess(cmd.mkString(" ").split(" ").toSeq).start()
}
def startShadowsocksUDPDaemon() {
val conf = ConfigUtils
.SHADOWSOCKS.formatLocal(Locale.ENGLISH, profile.host, profile.remotePort, profile.localPort,
profile.password, profile.method, 600)
Utils.printToFile(new File(getApplicationInfo.dataDir + "/ss-local-udp-vpn.conf"))(p => {
p.println(conf)
})
val cmd = new ArrayBuffer[String]
cmd += (getApplicationInfo.dataDir + "/ss-local", "-V", "-U"
, "-b", "127.0.0.1"
, "-t", "600"
, "-P", getApplicationInfo.dataDir
, "-c", getApplicationInfo.dataDir + "/ss-local-udp-vpn.conf")
if (profile.auth) cmd += "-A"
if (BuildConfig.DEBUG) Log.d(TAG, cmd.mkString(" "))
sstunnelProcess = new GuardedProcess(cmd).start()
}
def startShadowsocksDaemon() {
if (profile.route != Route.ALL) { if (profile.route != Route.ALL) {
val acl: Array[Array[String]] = profile.route match { val acl: Array[Array[String]] = profile.route match {
case Route.BYPASS_LAN => Array(getResources.getStringArray(R.array.private_route)) case Route.BYPASS_LAN => Array(getResources.getStringArray(R.array.private_route))
...@@ -201,15 +252,21 @@ class ShadowsocksVpnService extends VpnService with BaseService { ...@@ -201,15 +252,21 @@ class ShadowsocksVpnService extends VpnService with BaseService {
}) })
} }
val conf = ConfigUtils val conf = if (profile.kcp) {
ConfigUtils
.SHADOWSOCKS.formatLocal(Locale.ENGLISH, "127.0.0.1", profile.localPort + 90, profile.localPort,
profile.password, profile.method, 600)
} else {
ConfigUtils
.SHADOWSOCKS.formatLocal(Locale.ENGLISH, profile.host, profile.remotePort, profile.localPort, .SHADOWSOCKS.formatLocal(Locale.ENGLISH, profile.host, profile.remotePort, profile.localPort,
profile.password, profile.method, 600) profile.password, profile.method, 600)
}
Utils.printToFile(new File(getApplicationInfo.dataDir + "/ss-local-vpn.conf"))(p => { Utils.printToFile(new File(getApplicationInfo.dataDir + "/ss-local-vpn.conf"))(p => {
p.println(conf) p.println(conf)
}) })
val cmd = new ArrayBuffer[String] val cmd = new ArrayBuffer[String]
cmd += (getApplicationInfo.dataDir + "/ss-local", "-V", "-u" cmd += (getApplicationInfo.dataDir + "/ss-local", "-V"
, "-b", "127.0.0.1" , "-b", "127.0.0.1"
, "-t", "600" , "-t", "600"
, "-P", getApplicationInfo.dataDir , "-P", getApplicationInfo.dataDir
...@@ -217,6 +274,8 @@ class ShadowsocksVpnService extends VpnService with BaseService { ...@@ -217,6 +274,8 @@ class ShadowsocksVpnService extends VpnService with BaseService {
if (profile.auth) cmd += "-A" if (profile.auth) cmd += "-A"
if (profile.udpdns && !profile.kcp) cmd += "-u"
if (profile.route != Route.ALL) { if (profile.route != Route.ALL) {
cmd += "--acl" cmd += "--acl"
cmd += (getApplicationInfo.dataDir + "/acl.list") cmd += (getApplicationInfo.dataDir + "/acl.list")
...@@ -228,19 +287,23 @@ class ShadowsocksVpnService extends VpnService with BaseService { ...@@ -228,19 +287,23 @@ class ShadowsocksVpnService extends VpnService with BaseService {
} }
def startDnsTunnel() = { def startDnsTunnel() = {
val conf = ConfigUtils val conf = if (profile.kcp) {
.SHADOWSOCKS.formatLocal(Locale.ENGLISH, profile.host, profile.remotePort, 8163, ConfigUtils
.SHADOWSOCKS.formatLocal(Locale.ENGLISH, "127.0.0.1", profile.localPort + 90, profile.localPort + 63,
profile.password, profile.method, 10) profile.password, profile.method, 10)
} else {
ConfigUtils
.SHADOWSOCKS.formatLocal(Locale.ENGLISH, profile.host, profile.remotePort, profile.localPort + 63,
profile.password, profile.method, 10)
}
Utils.printToFile(new File(getApplicationInfo.dataDir + "/ss-tunnel-vpn.conf"))(p => { Utils.printToFile(new File(getApplicationInfo.dataDir + "/ss-tunnel-vpn.conf"))(p => {
p.println(conf) p.println(conf)
}) })
val cmd = new ArrayBuffer[String] val cmd = new ArrayBuffer[String]
cmd += (getApplicationInfo.dataDir + "/ss-tunnel" cmd += (getApplicationInfo.dataDir + "/ss-tunnel"
, "-V" , "-V"
, "-u"
, "-t", "10" , "-t", "10"
, "-b", "127.0.0.1" , "-b", "127.0.0.1"
, "-l", "8163"
, "-L", "8.8.8.8:53" , "-L", "8.8.8.8:53"
, "-P", getApplicationInfo.dataDir , "-P", getApplicationInfo.dataDir
, "-c", getApplicationInfo.dataDir + "/ss-tunnel-vpn.conf") , "-c", getApplicationInfo.dataDir + "/ss-tunnel-vpn.conf")
...@@ -257,10 +320,10 @@ class ShadowsocksVpnService extends VpnService with BaseService { ...@@ -257,10 +320,10 @@ class ShadowsocksVpnService extends VpnService with BaseService {
val conf = { val conf = {
if (profile.route == Route.BYPASS_CHN || profile.route == Route.BYPASS_LAN_CHN) { if (profile.route == Route.BYPASS_CHN || profile.route == Route.BYPASS_LAN_CHN) {
ConfigUtils.PDNSD_DIRECT.formatLocal(Locale.ENGLISH, getApplicationInfo.dataDir, ConfigUtils.PDNSD_DIRECT.formatLocal(Locale.ENGLISH, getApplicationInfo.dataDir,
"0.0.0.0", 8153, getBlackList, 8163, ipv6) "0.0.0.0", profile.localPort + 53, getBlackList, profile.localPort + 63, ipv6)
} else { } else {
ConfigUtils.PDNSD_LOCAL.formatLocal(Locale.ENGLISH, getApplicationInfo.dataDir, ConfigUtils.PDNSD_LOCAL.formatLocal(Locale.ENGLISH, getApplicationInfo.dataDir,
"0.0.0.0", 8153, 8163, ipv6) "0.0.0.0", profile.localPort + 53, profile.localPort + 63, ipv6)
} }
} }
Utils.printToFile(new File(getApplicationInfo.dataDir + "/pdnsd-vpn.conf"))(p => { Utils.printToFile(new File(getApplicationInfo.dataDir + "/pdnsd-vpn.conf"))(p => {
...@@ -354,7 +417,8 @@ class ShadowsocksVpnService extends VpnService with BaseService { ...@@ -354,7 +417,8 @@ class ShadowsocksVpnService extends VpnService with BaseService {
if (profile.udpdns) if (profile.udpdns)
cmd += " --enable-udprelay" cmd += " --enable-udprelay"
else else
cmd += " --dnsgw %s:8153".formatLocal(Locale.ENGLISH, PRIVATE_VLAN.formatLocal(Locale.ENGLISH, "1")) cmd += " --dnsgw %s:%d".formatLocal(Locale.ENGLISH, PRIVATE_VLAN.formatLocal(Locale.ENGLISH, "1"),
profile.localPort + 53)
if (BuildConfig.DEBUG) Log.d(TAG, cmd) if (BuildConfig.DEBUG) Log.d(TAG, cmd)
......
...@@ -64,7 +64,7 @@ object DBHelper { ...@@ -64,7 +64,7 @@ object DBHelper {
} }
class DBHelper(val context: Context) class DBHelper(val context: Context)
extends OrmLiteSqliteOpenHelper(context, DBHelper.PROFILE, null, 16) { extends OrmLiteSqliteOpenHelper(context, DBHelper.PROFILE, null, 18) {
import DBHelper._ import DBHelper._
lazy val profileDao: Dao[Profile, Int] = getDao(classOf[Profile]) lazy val profileDao: Dao[Profile, Int] = getDao(classOf[Profile])
...@@ -125,6 +125,15 @@ class DBHelper(val context: Context) ...@@ -125,6 +125,15 @@ class DBHelper(val context: Context)
if (oldVersion < 16) { if (oldVersion < 16) {
profileDao.executeRawNoArgs("UPDATE `profile` SET route = 'bypass-lan-china' WHERE route = 'bypass-china'") profileDao.executeRawNoArgs("UPDATE `profile` SET route = 'bypass-lan-china' WHERE route = 'bypass-china'")
} }
if (oldVersion < 17) {
profileDao.executeRawNoArgs("ALTER TABLE `profile` ADD COLUMN kcp SMALLINT;")
profileDao.executeRawNoArgs("ALTER TABLE `profile` ADD COLUMN kcpcli VARCHAR;")
}
if (oldVersion < 18) {
profileDao.executeRawNoArgs("ALTER TABLE `profile` ADD COLUMN kcpPort INTEGER;")
}
} }
} }
} }
...@@ -99,6 +99,15 @@ class Profile { ...@@ -99,6 +99,15 @@ class Profile {
@DatabaseField @DatabaseField
var userOrder: Long = _ var userOrder: Long = _
@DatabaseField
var kcp: Boolean = false
@DatabaseField
var kcpPort: Int = 8399
@DatabaseField
var kcpcli: String = ""
override def toString = "ss://" + Base64.encodeToString("%s%s:%s@%s:%d".formatLocal(Locale.ENGLISH, override def toString = "ss://" + Base64.encodeToString("%s%s:%s@%s:%d".formatLocal(Locale.ENGLISH,
method, if (auth) "-auth" else "", password, host, remotePort).getBytes, Base64.NO_PADDING | Base64.NO_WRAP) method, if (auth) "-auth" else "", password, host, remotePort).getBytes, Base64.NO_PADDING | Base64.NO_WRAP)
......
...@@ -45,6 +45,7 @@ object Executable { ...@@ -45,6 +45,7 @@ object Executable {
val SS_LOCAL = "ss-local" val SS_LOCAL = "ss-local"
val SS_TUNNEL = "ss-tunnel" val SS_TUNNEL = "ss-tunnel"
val TUN2SOCKS = "tun2socks" val TUN2SOCKS = "tun2socks"
val KCPTUN = "kcptun"
} }
object ConfigUtils { object ConfigUtils {
...@@ -166,6 +167,10 @@ object Key { ...@@ -166,6 +167,10 @@ object Key {
val localPort = "localPortNum" val localPort = "localPortNum"
val profileTip = "profileTip" val profileTip = "profileTip"
val kcp = "kcp"
val kcpPort = "kcpPort"
val kcpcli = "kcpcli"
} }
object State { object State {
......
#!/bin/bash #!/bin/bash
export ARCH=`uname -m` export ARCH=`uname -m`
export GOROOT_BOOTSTRAP=$HOME/.android/go
export ANDROID_NDK_HOME=$HOME/.android/android-ndk-r12b export ANDROID_NDK_HOME=$HOME/.android/android-ndk-r12b
export ANDROID_HOME=$HOME/.android/android-sdk-linux export ANDROID_HOME=$HOME/.android/android-sdk-linux
export PATH=${ANDROID_NDK_HOME}:${ANDROID_HOME}/tools:${ANDROID_HOME}/platform-tools:${PATH} export PATH=${ANDROID_NDK_HOME}:${ANDROID_HOME}/tools:${ANDROID_HOME}/platform-tools:${PATH}
...@@ -21,5 +22,13 @@ if [ ! -d "$ANDROID_NDK_HOME" ]; then ...@@ -21,5 +22,13 @@ if [ ! -d "$ANDROID_NDK_HOME" ]; then
popd popd
fi fi
if [ ! -d "$GOROOT_BOOTSTRAP" ]; then
mkdir -p $GOROOT_BOOTSTRAP
pushd $HOME/.android
wget https://storage.googleapis.com/golang/go1.6.3.linux-amd64.tar.gz
tar xf go1.6.3.linux-amd64.tar.gz
popd
fi
( sleep 5 && while [ 1 ]; do sleep 1; echo y; done ) | android update sdk --filter tools,platform-tools,build-tools-24.0.0,android-23,android-24,extra-google-m2repository --no-ui -a ( sleep 5 && while [ 1 ]; do sleep 1; echo y; done ) | android update sdk --filter tools,platform-tools,build-tools-24.0.0,android-23,android-24,extra-google-m2repository --no-ui -a
( sleep 5 && while [ 1 ]; do sleep 1; echo y; done ) | android update sdk --filter extra-android-m2repository --no-ui -a ( sleep 5 && while [ 1 ]; do sleep 1; echo y; done ) | android update sdk --filter extra-android-m2repository --no-ui -a
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