Compare commits

...
21 Commits
Author SHA1 Message Date
Max Lv 4817539ca2 Fix UDP forward 2016-08-07 10:43:25 +08:00
Max Lv 03c857536d Fix the build scripts 2016-08-07 08:16:55 +08:00
Eva Kane 14038cd152 Fix remove problem (#793) 2016-08-06 23:10:04 +08:00
Syrone Wong 935314a1c5 Fix kcptun license in about page (#792)
Signed-off-by: Syrone Wong <wong.syrone@gmail.com>
2016-08-06 22:37:41 +08:00
Max Lv 7263bf11a4 Update license 2016-08-06 19:36:10 +08:00
Max Lv e766ae2244 Fix the build sequence 2016-08-06 19:15:25 +08:00
Max Lv f3ed157145 Fix travis path 2016-08-06 19:00:45 +08:00
Max Lv eb0d5ceccc Fix travis 2016-08-06 18:57:09 +08:00
Max Lv 2ffbf4c56f Fix a typo 2016-08-06 18:55:48 +08:00
Max Lv 9ee3bab7e0 Update build scripts 2016-08-06 18:47:07 +08:00
Max Lv 70a7317a1e Update kcptun 2016-08-06 18:41:56 +08:00
Max Lv 43caaa684f Add submodules for kcptun 2016-08-06 18:22:27 +08:00
Max Lv 586c5e2ae4 Bump version 2016-08-06 17:25:10 +08:00
Max Lv 416d93062f Update kcptun 2016-08-06 13:01:40 +08:00
Max Lv 66ceed8607 Restart kcptun when switching network 2016-08-06 10:55:33 +08:00
Max Lv a073f850d6 Tune yamux parameters for kcptun 2016-08-06 09:24:22 +08:00
Max Lv 6ab4540726 Update shadowsocks-libev 2016-08-05 20:17:08 +08:00
Max Lv 9e59201596 Strip the binary 2016-08-05 13:16:46 +08:00
Max Lv b9a33cf1db Add KCP support (#788)
Add KCP support for shadowsocks.

KCPTUN should be setup on a different port to avoid conflicts with Shadowsocks' UDP support.
2016-08-04 23:43:18 -05:00
Mygod bae5e9d06b Check bgService in ShadowsocksTileService 2016-07-22 15:44:11 +08:00
Mygod 455aa15f18 Update Android Support Library 2016-07-19 12:37:56 +08:00
29 changed files with 373 additions and 79 deletions
+3 -4
View File
@@ -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/
#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
+6
View File
@@ -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
+1
View File
@@ -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}
+4 -23
View File
@@ -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.
* 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
@@ -26,33 +28,11 @@ A [shadowsocks](http://shadowsocks.org) client for Android, written in Scala.
```bash ```bash
git submodule update --init git submodule update --init
# Build the App # Build the App
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.
* 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
+5 -3
View File
@@ -39,9 +39,9 @@ libraryDependencies ++= Seq(
"net.glxn.qrgen" % "android" % "2.0", "net.glxn.qrgen" % "android" % "2.0",
"com.google.android.gms" % "play-services-ads" % "9.2.1", "com.google.android.gms" % "play-services-ads" % "9.2.1",
"com.google.android.gms" % "play-services-analytics" % "9.2.1", "com.google.android.gms" % "play-services-analytics" % "9.2.1",
"com.android.support" % "design" % "24.0.0", "com.android.support" % "design" % "24.1.0",
"com.android.support" % "gridlayout-v7" % "24.0.0", "com.android.support" % "gridlayout-v7" % "24.1.0",
"com.android.support" % "cardview-v7" % "24.0.0", "com.android.support" % "cardview-v7" % "24.1.0",
"com.github.jorgecastilloprz" % "fabprogresscircle" % "1.01", "com.github.jorgecastilloprz" % "fabprogresscircle" % "1.01",
"com.j256.ormlite" % "ormlite-android" % "4.48", "com.j256.ormlite" % "ormlite-android" % "4.48",
"com.twofortyfouram" % "android-plugin-api-for-locale" % "1.0.2", "com.twofortyfouram" % "android-plugin-api-for-locale" % "1.0.2",
@@ -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.**",
+10 -6
View File
@@ -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
Submodule
+1
Submodule kcptun/go added at f3e7e7b69f
Submodule
+1
Submodule kcptun/kcptun added at eced3949b2
+65
View File
@@ -0,0 +1,65 @@
#!/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"
+1 -1
View File
@@ -1,4 +1,4 @@
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")
+2 -2
View File
@@ -1,7 +1,7 @@
<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"/>
+1
View File
@@ -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>
+7
View File
@@ -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>
+7
View File
@@ -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>
+7
View File
@@ -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>
+8
View File
@@ -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>
+25
View File
@@ -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}
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 {
} }
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 {
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 {
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 {
@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,9 +77,13 @@ class GuardedProcess(cmd: Seq[String]) extends Process {
semaphore.release semaphore.release
process.waitFor process.waitFor
if (currentTimeMillis - startTime < 1000) { if (isRestart) {
Log.w(TAG, "process exit too fast, stop guard: " + cmd) isRestart = false
isDestroyed = true } else {
if (currentTimeMillis - startTime < 1000) {
Log.w(TAG, "process exit too fast, stop guard: " + cmd)
isDestroyed = true
}
} }
} }
} catch { } catch {
@@ -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 {
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 {
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 {
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 {
}) })
} }
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 {
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 {
, "-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 {
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 {
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 {
/** 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 {
} }
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 {
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 {
// 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,8 +36,10 @@ object ShadowsocksSettings {
} }
def updateSummaryEditTextPreference(pref: Preference, value: String) { def updateSummaryEditTextPreference(pref: Preference, value: String) {
pref.setSummary(value) if (value != null) {
pref.asInstanceOf[SummaryEditTextPreference].setText(value) pref.setSummary(value)
pref.asInstanceOf[SummaryEditTextPreference].setText(value)
}
} }
def updateSwitchPreference(pref: Preference, value: Boolean) { def updateSwitchPreference(pref: Preference, value: Boolean) {
@@ -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
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]))
@@ -46,7 +46,7 @@ final class ShadowsocksTileService extends TileService with ServiceBoundContext
} }
} }
override def onServiceConnected = callback.stateChanged(bgService.getState, null) override def onServiceConnected() = callback.stateChanged(bgService.getState, null)
override def onCreate { override def onCreate {
super.onCreate super.onCreate
@@ -66,9 +66,9 @@ final class ShadowsocksTileService extends TileService with ServiceBoundContext
detachService // just in case the user switches to NAT mode, also saves battery detachService // just in case the user switches to NAT mode, also saves battery
} }
override def onClick = if (isLocked) unlockAndRun(toggle) else toggle() override def onClick() = if (isLocked) unlockAndRun(toggle) else toggle()
private def toggle() = bgService.getState match { private def toggle() = if (bgService != null) bgService.getState match {
case State.STOPPED => Utils.startSsService(this) case State.STOPPED => Utils.startSsService(this)
case State.CONNECTED => Utils.stopSsService(this) case State.CONNECTED => Utils.stopSsService(this)
case _ => // ignore case _ => // ignore
@@ -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 {
/** 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 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() { 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 {
}) })
} }
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 {
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 {
} }
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 {
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 {
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 {
} }
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)
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 {
@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 {
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 {
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 {
+9
View File
@@ -1,6 +1,7 @@
#!/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
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