Compare commits

...
39 Commits
Author SHA1 Message Date
Max Lv 6ec8117e1c Update shadowsocks-libev 2016-09-20 18:01:10 +08:00
Max Lv 3c68a26794 Update DNS forwarding 2016-09-20 08:40:13 +08:00
Max Lv fda89933d0 Disable DNS forwarding in GFWList/ChinaList mode 2016-09-19 17:18:39 +08:00
Max Lv d8f721db3b Refine DNS resolve of GFWList and ChinaList, #887 2016-09-19 09:58:36 +08:00
Max Lv 28339ce7c1 Update DNS 2016-09-19 09:10:47 +08:00
Max Lv edda3179dd Add China List, close #886 2016-09-18 18:56:04 +08:00
Mygod 1d79990656 Remove workaround for libsuperuser#55 2016-09-15 12:22:21 +08:00
Mygod 2a47362195 Fix profile name not updated in ShadowsocksTileService 2016-09-15 00:11:37 +08:00
Mygod 02d5951f8b Auto reset when downgrading
While it's theoretically impossible to downgrade without reinstalling the app, there are ways to bypass this mechanism. And don't forget users can restore their app data as well.
2016-09-14 22:37:26 +08:00
Mygod b126c62365 Fix a crash in AppManager 2016-09-14 18:16:44 +08:00
Mygod bbaf1779ea Add missing translation for Russian 2016-09-14 17:18:10 +08:00
Max Lv 65ddd6f5d8 Bump version 2016-09-14 14:57:02 +08:00
Max Lv 772bc18eb8 Bump version 2016-09-12 10:28:25 +08:00
Max Lv d503818169 Add missing translation 2016-09-12 10:27:55 +08:00
Max Lv b209e73386 Bump version 2016-09-12 10:11:16 +08:00
Max Lv 6c381b0ecc Fix a crash reported by Goolge Play 2016-09-12 09:49:17 +08:00
Max Lv e3f0fa6756 Fix #871 2016-09-09 22:13:51 +08:00
Max Lv 35cb273592 SuppressLint 2016-09-09 16:47:47 +08:00
Max Lv b76f410c34 Refine header parser 2016-09-09 10:30:22 +08:00
Max Lv d3678531b7 Bump version 2016-09-08 19:23:50 +08:00
Max Lv 122ca599de Add GFWList support 2016-09-08 18:36:39 +08:00
Max Lv 96fcec788c Add issue template 2016-09-05 16:24:51 +08:00
Max Lv 1c67b39a3e Bump version 2016-09-04 10:31:33 +08:00
Max Lv 30fea4a705 Merge branch 'master' of github.com:shadowsocks/shadowsocks-android 2016-09-04 10:19:15 +08:00
Max Lv 7c0763c78a Fix #848 2016-09-01 14:00:23 +08:00
Mygod b8c593b110 Fix crash in GuardedProcess 2016-08-29 13:57:25 +08:00
Mygod 782af959a0 Fix #844 2016-08-29 12:54:55 +08:00
Max Lv 6df227d231 Update kcptun 2016-08-28 18:11:29 +08:00
Max Lv 5b1432e4e8 Handle stdout/stderr of GuardedProcess properly 2016-08-28 17:42:19 +08:00
Max Lv 7ca4e4ec74 Enable android log for kcptun 2016-08-28 08:00:35 +08:00
Mygod 655ef1eed6 Refine TFO 2016-08-27 23:39:06 +08:00
Mygod 04be60577a Revert "Revert "Fix #839 #838""
This reverts commit 264b177b38.
2016-08-27 23:32:13 +08:00
Mygod 63d2ec7b02 Revert "Fix #838 #839"
This reverts commit 32f4d6af47.

Never mind then! I changed my mind.
2016-08-27 23:31:50 +08:00
Mygod 06b6afd557 Update sbt-android 2016-08-27 23:23:58 +08:00
Mygod 32f4d6af47 Fix #838 #839 2016-08-27 23:23:08 +08:00
Mygod 264b177b38 Revert "Fix #839 #838"
This reverts commit 069cc152ca.
2016-08-27 23:15:25 +08:00
Syrone Wong 67a1c5460a Drop redundant rule (#840)
[info] Android NDK: WARNING:jni/Android.mk:mbedtls: LOCAL_LDLIBS is always ignored for static libraries
2016-08-27 20:42:16 +08:00
Max Lv a20b7821f2 Bump version 2016-08-27 17:11:05 +08:00
Max Lv 069cc152ca Fix #839 #838 2016-08-27 17:10:12 +08:00
48 changed files with 4316 additions and 126 deletions
+18
View File
@@ -0,0 +1,18 @@
Please answer these questions before submitting your issue. Thanks!
### What version of Shadowsocks are you using?
### What Android OS version and device are you using?
### What did you do?
### What did you expect to see?
### What did you see instead?
### What is your config in detail (with all sensitive info masked)?
+3
View File
@@ -30,3 +30,6 @@
[submodule "src/main/jni/mbedtls"]
path = src/main/jni/mbedtls
url = https://github.com/ARMmbed/mbedtls
[submodule "src/main/jni/pcre"]
path = src/main/jni/pcre
url = https://android.googlesource.com/platform/external/pcre
+3 -3
View File
@@ -31,8 +31,8 @@ resolvers += Resolver.jcenterRepo
useSupportVectors
libraryDependencies ++= Seq(
"com.android.support" % "design" % "24.2.0",
"com.android.support" % "gridlayout-v7" % "24.2.0",
"com.android.support" % "design" % "24.2.1",
"com.android.support" % "gridlayout-v7" % "24.2.1",
"com.github.clans" % "fab" % "1.6.4",
"com.github.jorgecastilloprz" % "fabprogresscircle" % "1.01",
"com.github.kevinsawicki" % "http-request" % "6.0",
@@ -41,7 +41,7 @@ libraryDependencies ++= Seq(
"com.j256.ormlite" % "ormlite-android" % "5.0",
"com.twofortyfouram" % "android-plugin-api-for-locale" % "1.0.2",
"dnsjava" % "dnsjava" % "2.1.7",
"eu.chainfire" % "libsuperuser" % "1.0.0.201607041850",
"eu.chainfire" % "libsuperuser" % "1.0.0.201608240809",
"me.dm7.barcodescanner" % "zxing" % "1.9",
"net.glxn.qrgen" % "android" % "2.0"
)
+1
View File
@@ -52,6 +52,7 @@ pushd kcptun/client
echo "Get dependences for kcptun"
go get -u github.com/xtaci/kcp-go
go get -u github.com/xtaci/smux
go get
echo "Cross compile kcptun for arm"
+1 -1
View File
@@ -1,4 +1,4 @@
addSbtPlugin("org.scala-android" % "sbt-android" % "1.6.13")
addSbtPlugin("org.scala-android" % "sbt-android" % "1.6.18")
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"
xmlns:tools="http://schemas.android.com/tools" package="com.github.shadowsocks"
android:versionCode="148"
android:versionName="3.0.6">
android:versionCode="157"
android:versionName="3.1.5">
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
@@ -4,6 +4,7 @@ import com.github.shadowsocks.aidl.IShadowsocksServiceCallback;
interface IShadowsocksService {
int getState();
String getProfileName();
oneway void registerCallback(IShadowsocksServiceCallback cb);
oneway void unregisterCallback(IShadowsocksServiceCallback cb);
@@ -1,6 +1,6 @@
package com.github.shadowsocks.aidl;
interface IShadowsocksServiceCallback {
oneway void stateChanged(int state, String msg);
oneway void stateChanged(int state, String profileName, String msg);
oneway void trafficUpdated(long txRate, long rxRate, long txTotal, long rxTotal);
}
File diff suppressed because it is too large Load Diff
+53 -9
View File
@@ -371,7 +371,9 @@ PDNSD_SOURCES := $(wildcard $(LOCAL_PATH)/pdnsd/src/*.c)
LOCAL_MODULE := pdnsd
LOCAL_SRC_FILES := $(PDNSD_SOURCES:$(LOCAL_PATH)/%=%)
LOCAL_CFLAGS := -DANDROID -Wall -O2 -I$(LOCAL_PATH)/pdnsd \
-I$(LOCAL_PATH)/include/pdnsd
-I$(LOCAL_PATH)/include/pdnsd -I$(LOCAL_PATH)/libancillary
LOCAL_STATIC_LIBRARIES := libancillary
LOCAL_LDLIBS := -llog
include $(BUILD_EXECUTABLE)
@@ -381,25 +383,29 @@ include $(BUILD_EXECUTABLE)
include $(CLEAR_VARS)
SHADOWSOCKS_SOURCES := local.c cache.c udprelay.c encrypt.c utils.c netutils.c json.c jconf.c acl.c android.c
SHADOWSOCKS_SOURCES := local.c cache.c udprelay.c encrypt.c \
utils.c netutils.c json.c jconf.c acl.c http.c tls.c rule.c \
android.c
LOCAL_MODULE := ss-local
LOCAL_SRC_FILES := $(addprefix shadowsocks-libev/src/, $(SHADOWSOCKS_SOURCES))
LOCAL_CFLAGS := -Wall -O2 -fno-strict-aliasing -DMODULE_LOCAL \
-DUSE_CRYPTO_MBEDTLS -DANDROID -DHAVE_CONFIG_H \
-DCONNECT_IN_PROGRESS=EINPROGRESS \
-I$(LOCAL_PATH)/include/shadowsocks-libev \
-I$(LOCAL_PATH)/include \
-I$(LOCAL_PATH)/libancillary \
-I$(LOCAL_PATH)/mbedtls/include \
-I$(LOCAL_PATH)/pcre \
-I$(LOCAL_PATH)/shadowsocks-libev/libudns \
-I$(LOCAL_PATH)/shadowsocks-libev/libcork/include \
-I$(LOCAL_PATH)/shadowsocks-libev/libsodium/src/libsodium/include \
-I$(LOCAL_PATH)/shadowsocks-libev/libsodium/src/libsodium/include/sodium \
-I$(LOCAL_PATH)/shadowsocks-libev/libipset/include \
-I$(LOCAL_PATH)/shadowsocks-libev/libev \
-I$(LOCAL_PATH)/include/shadowsocks-libev
-I$(LOCAL_PATH)/shadowsocks-libev/libev
LOCAL_STATIC_LIBRARIES := libev libmbedtls libipset libcork libudns libsodium libancillary
LOCAL_STATIC_LIBRARIES := libev libmbedtls libipset libcork libudns \
libsodium libancillary libpcre
LOCAL_LDLIBS := -llog
@@ -551,17 +557,55 @@ include $(BUILD_EXECUTABLE)
include $(CLEAR_VARS)
LOCAL_MODULE:= mbedtls
LOCAL_MODULE := mbedtls
LOCAL_C_INCLUDES:= $(LOCAL_PATH)/mbedtls/include
LOCAL_C_INCLUDES := $(LOCAL_PATH)/mbedtls/include
MBEDTLS_SOURCES := $(wildcard $(LOCAL_PATH)/mbedtls/library/*.c)
MBEDTLS_SOURCES := $(wildcard $(LOCAL_PATH)/mbedtls/library/*.c)
LOCAL_SRC_FILES := $(MBEDTLS_SOURCES:$(LOCAL_PATH)/%=%)
LOCAL_LDLIBS := -ldl -llog
include $(BUILD_STATIC_LIBRARY)
########################################################
## pcre
########################################################
include $(CLEAR_VARS)
LOCAL_MODULE := pcre
LOCAL_CFLAGS += -DHAVE_CONFIG_H
LOCAL_C_INCLUDES := $(LOCAL_PATH)/pcre/dist $(LOCAL_PATH)/pcre
libpcre_src_files := \
pcre_chartables.c \
dist/pcre_byte_order.c \
dist/pcre_compile.c \
dist/pcre_config.c \
dist/pcre_dfa_exec.c \
dist/pcre_exec.c \
dist/pcre_fullinfo.c \
dist/pcre_get.c \
dist/pcre_globals.c \
dist/pcre_jit_compile.c \
dist/pcre_maketables.c \
dist/pcre_newline.c \
dist/pcre_ord2utf8.c \
dist/pcre_refcount.c \
dist/pcre_string_utils.c \
dist/pcre_study.c \
dist/pcre_tables.c \
dist/pcre_ucd.c \
dist/pcre_valid_utf8.c \
dist/pcre_version.c \
dist/pcre_xclass.c
LOCAL_SRC_FILES := $(addprefix pcre/, $(libpcre_src_files))
include $(BUILD_STATIC_LIBRARY)
# Import cpufeatures
$(call import-module,android/cpufeatures)
@@ -417,3 +417,9 @@
/* Define as `fork' if `vfork' does not work. */
/* #undef vfork */
/* Define to 1 if you have the <pcre.h> header file. */
#define HAVE_PCRE_H 1
/* Define to 1 if you have the <pcre/pcre.h> header file. */
/* #undef HAVE_PCRE_PCRE_H */
+1
Submodule src/main/jni/pcre added at 0ea9883633
@@ -1,3 +1,4 @@
<!--suppress NewApi -->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
+1
View File
@@ -1,3 +1,4 @@
<!--suppress NewApi -->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
@@ -1,3 +1,4 @@
<!--suppress NewApi -->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
@@ -1,3 +1,4 @@
<!--suppress NewApi -->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
@@ -1,3 +1,4 @@
<!--suppress NewApi -->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
+1
View File
@@ -1,3 +1,4 @@
<!--suppress NewApi -->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
+1
View File
@@ -1,3 +1,4 @@
<!--suppress NewApi -->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
@@ -1,3 +1,4 @@
<!--suppress NewApi -->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
@@ -1,3 +1,4 @@
<!--suppress NewApi -->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
+2 -1
View File
@@ -1,4 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<!--suppress NewApi -->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
@@ -11,4 +12,4 @@
<path
android:fillColor="#fff"
android:pathData="M 9.45 17.56 L 9.46 22 L 12.09 18.41 L 9.45 17.56 L 9.45 17.56 Z" />
</vector>
</vector>
+2 -1
View File
@@ -1,4 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<!--suppress NewApi -->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
@@ -11,4 +12,4 @@
<path
android:fillColor="#fff"
android:pathData="M 9.45 17.56 L 12.09 18.41 L 9.46 22 L 9.45 17.56 Z" />
</vector>
</vector>
+2 -1
View File
@@ -1,4 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<!--suppress NewApi -->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
@@ -22,4 +23,4 @@
<path
android:fillColor="#fff"
android:pathData="M8.56,8.56L0,12.8l6.83,2.57,4.64-3.9ZM6.44,13.08L5,12.55l5-2.47Z" />
</vector>
</vector>
+7
View File
@@ -46,6 +46,13 @@
<string name="auto_set_gfwlist">CHN Маршрут</string>
<string name="auto_set_gfwlist_summary">Игнорировать все сайты находящиеся в Китае</string>
<string name="route_list">Маршрут</string>
<string-array name="route_entry">
<item>Все</item>
<item>Обход LAN</item>
<item>Обходной Китай</item>
<item>Обход LAN и Китай</item>
<item>Список GFW</item>
</string-array>
<string name="proxied_apps">Прокси для выбранных приложений</string>
<string name="proxied_apps_summary">Установить прокси для выбранных приложений, требует режим NAT под Android 4.x</string>
<string name="on">Вкл</string>
+2
View File
@@ -110,6 +110,8 @@
<item>绕过局域网地址</item>
<item>绕过中国大陆地址</item>
<item>绕过局域网及中国大陆地址</item>
<item>仅代理中国大陆无法访问的地址</item>
<item>仅代理中国大陆地址</item>
</string-array>
<string name="action_apply_all">应用设置到所有配置文件</string>
+2
View File
@@ -112,6 +112,8 @@
<item>略過區域網路位址</item>
<item>略過中國大陸位址</item>
<item>略過區域網路及中國大陸位址</item>
<item>僅代理大陸屏蔽位址</item>
<item>僅代理大陸位址</item>
</string-array>
<string name="action_apply_all">應用設置到所有配置文件</string>
+2 -7
View File
@@ -38,18 +38,13 @@
<item>chacha20-ietf</item>
</string-array>
<string-array name="route_entry">
<item>All</item>
<item>Bypass LAN</item>
<item>Bypass China</item>
<item>Bypass LAN &amp; China</item>
</string-array>
<string-array name="route_value">
<item>all</item>
<item>bypass-lan</item>
<item>bypass-china</item>
<item>bypass-lan-china</item>
<item>gfwlist</item>
<item>china-list</item>
</string-array>
<string-array name="private_route">
+8
View File
@@ -52,6 +52,14 @@
<string name="auto_set_gfwlist_summary">Bypass all sites located in China
</string>
<string name="route_list">Route</string>
<string-array name="route_entry">
<item>All</item>
<item>Bypass LAN</item>
<item>Bypass China</item>
<item>Bypass LAN &amp; China</item>
<item>GFW List</item>
<item>China List</item>
</string-array>
<string name="proxied_apps">Per-App Proxy</string>
<string name="proxied_apps_summary">Set proxy for selected apps, requires NAT mode under Android 4.x</string>
<string name="on">On</string>
+1
View File
@@ -7,6 +7,7 @@
</style>
<style name="Theme.Material" parent="Theme.AppCompat.Light.NoActionBar">
<!--suppress NewApi -->
<item name="android:navigationBarColor">@color/material_accent_700</item>
<item name="colorAccent">@color/material_accent_500</item>
<item name="colorButtonNormal">@color/material_accent_500</item>
-1
View File
@@ -112,7 +112,6 @@
<SwitchPreference
android:key="tcp_fastopen"
android:persistent="false"
android:summary="@string/tcp_fastopen_summary"
android:title="TCP Fast Open"/>
@@ -46,14 +46,13 @@ import android.content._
import android.content.pm.PackageManager
import android.graphics.drawable.Drawable
import android.os.{Bundle, Handler}
import android.preference.PreferenceManager
import android.support.v7.app.AppCompatActivity
import android.support.v7.widget.Toolbar.OnMenuItemClickListener
import android.support.v7.widget.{DefaultItemAnimator, LinearLayoutManager, RecyclerView, Toolbar}
import android.view._
import android.widget._
import com.github.shadowsocks.utils.{Key, Utils}
import com.github.shadowsocks.ShadowsocksApplication.app
import com.github.shadowsocks.utils.{Key, Utils}
import scala.collection.JavaConversions._
import scala.collection.mutable
@@ -143,7 +142,7 @@ class AppManager extends AppCompatActivity with OnMenuItemClickListener {
private var loadingView: View = _
private val appsLoading = new AtomicBoolean
private var handler: Handler = _
private val profile = app.currentProfile.get
private val profile = app.currentProfile.orNull
private def initProxiedApps(str: String = profile.individual) = proxiedApps = str.split('\n').to[mutable.HashSet]
@@ -213,6 +212,8 @@ class AppManager extends AppCompatActivity with OnMenuItemClickListener {
protected override def onCreate(savedInstanceState: Bundle) {
super.onCreate(savedInstanceState)
if (profile == null) finish()
handler = new Handler()
this.setContentView(R.layout.layout_apps)
@@ -91,6 +91,8 @@ trait BaseService extends Service {
state
}
override def getProfileName: String = if (profile == null) null else profile.name
override def unregisterCallback(cb: IShadowsocksServiceCallback) {
if (cb != null && callbacks.unregister(cb)) {
callbacksCount -= 1
@@ -282,7 +284,7 @@ trait BaseService extends Service {
val n = callbacks.beginBroadcast()
for (i <- 0 until n) {
try {
callbacks.getBroadcastItem(i).stateChanged(s, msg)
callbacks.getBroadcastItem(i).stateChanged(s, binder.getProfileName, msg)
} catch {
case _: Exception => // Ignore
}
@@ -39,18 +39,35 @@
package com.github.shadowsocks
import java.io.{IOException, InputStream, OutputStream}
import java.io._
import java.lang.System.currentTimeMillis
import java.util.concurrent.Semaphore
import android.util.Log
import scala.collection.JavaConversions._
import scala.collection.immutable.Stream
import scala.util.control.Exception._
class StreamLogger(is: InputStream, tag: String) extends Thread {
def withCloseable[T <: Closeable, R](t: T)(f: T => R): R = {
allCatch.andFinally{t.close} apply { f(t) }
}
override def run() {
withCloseable(new BufferedReader(new InputStreamReader(is))) {
br => try Stream.continually(br.readLine()).takeWhile(_ != null).foreach(Log.i(tag, _)) catch {
case ignore: IOException =>
}
}
}
}
/**
* @author ayanamist@gmail.com
*/
class GuardedProcess(cmd: Seq[String]) extends Process {
class GuardedProcess(cmd: Seq[String]) {
private val TAG = classOf[GuardedProcess].getSimpleName
@volatile private var guardThread: Thread = _
@@ -72,19 +89,25 @@ class GuardedProcess(cmd: Seq[String]) extends Process {
process = new ProcessBuilder(cmd).redirectErrorStream(true).start
val is = process.getInputStream
new StreamLogger(is, TAG).start
if (callback == null) callback = onRestartCallback else callback()
semaphore.release
process.waitFor
if (isRestart) {
isRestart = false
} else {
if (currentTimeMillis - startTime < 1000) {
Log.w(TAG, "process exit too fast, stop guard: " + cmd)
isDestroyed = true
this.synchronized {
if (isRestart) {
isRestart = false
} else {
if (currentTimeMillis - startTime < 1000) {
Log.w(TAG, "process exit too fast, stop guard: " + cmd)
isDestroyed = true
}
}
}
}
} catch {
case ignored: InterruptedException =>
@@ -114,15 +137,12 @@ class GuardedProcess(cmd: Seq[String]) extends Process {
}
def restart() {
isRestart = true
process.destroy()
this.synchronized {
isRestart = true
process.destroy()
}
}
def exitValue: Int = throw new UnsupportedOperationException
def getErrorStream: InputStream = throw new UnsupportedOperationException
def getInputStream: InputStream = throw new UnsupportedOperationException
def getOutputStream: OutputStream = throw new UnsupportedOperationException
@throws(classOf[InterruptedException])
def waitFor = {
guardThread.join()
@@ -235,7 +235,7 @@ final class ProfileManagerActivity extends AppCompatActivity with OnMenuItemClic
}).attachToRecyclerView(profilesList)
attachService(new IShadowsocksServiceCallback.Stub {
def stateChanged(state: Int, msg: String) = () // ignore
def stateChanged(state: Int, profileName: String, msg: String) = () // ignore
def trafficUpdated(txRate: Long, rxRate: Long, txTotal: Long, rxTotal: Long) =
if (selectedItem != null) selectedItem.updateText(txTotal, rxTotal)
})
@@ -276,7 +276,7 @@ final class ProfileManagerActivity extends AppCompatActivity with OnMenuItemClic
updateNfcState()
}
override def onNewIntent(intent: Intent): Unit ={
override def onNewIntent(intent: Intent) {
super.onNewIntent(intent)
handleShareIntent(intent)
}
@@ -111,7 +111,7 @@ class Shadowsocks extends AppCompatActivity with ServiceBoundContext {
// Services
private val callback = new IShadowsocksServiceCallback.Stub {
def stateChanged(s: Int, m: String) {
def stateChanged(s: Int, profileName: String, m: String) {
handler.post(() => {
s match {
case State.CONNECTING =>
@@ -186,8 +186,8 @@ class Shadowsocks extends AppCompatActivity with ServiceBoundContext {
snackbar.show
}
if (!app.settings.getBoolean(BuildConfig.VERSION_NAME, false)) {
app.editor.putBoolean(BuildConfig.VERSION_NAME, true).apply()
if (app.settings.getInt(Key.currentVersionCode, -1) != BuildConfig.VERSION_CODE) {
app.editor.putInt(Key.currentVersionCode, BuildConfig.VERSION_CODE).apply()
recovery()
@@ -514,6 +514,7 @@ class Shadowsocks extends AppCompatActivity with ServiceBoundContext {
crashRecovery()
copyAssets(System.getABI)
copyAssets("acl")
val ab = new ArrayBuffer[String]
for (executable <- EXECUTABLES) {
@@ -46,7 +46,7 @@ import android.app.Application
import android.preference.PreferenceManager
import android.support.v7.app.AppCompatDelegate
import com.github.shadowsocks.database.{DBHelper, ProfileManager}
import com.github.shadowsocks.utils.{Key, Utils}
import com.github.shadowsocks.utils.{Key, Utils, TcpFastOpen}
import com.google.android.gms.analytics.{GoogleAnalytics, HitBuilders, StandardExceptionParser}
import com.google.android.gms.common.api.ResultCallback
import com.google.android.gms.tagmanager.{ContainerHolder, TagManager}
@@ -111,6 +111,8 @@ class ShadowsocksApplication extends Application {
}
}
pending.setResultCallback(callback, 2, TimeUnit.SECONDS)
TcpFastOpen.enabled(settings.getBoolean(Key.tfo, false))
}
def refreshContainerHolder {
@@ -40,7 +40,6 @@
package com.github.shadowsocks
import java.io.File
import java.lang.Process
import java.net.{Inet6Address, InetAddress}
import java.util.Locale
@@ -65,22 +64,24 @@ class ShadowsocksNatService extends BaseService {
private var notification: ShadowsocksNotification = _
val myUid = android.os.Process.myUid()
var sslocalProcess: Process = _
var sstunnelProcess: Process = _
var redsocksProcess: Process = _
var pdnsdProcess: Process = _
var sslocalProcess: GuardedProcess = _
var sstunnelProcess: GuardedProcess = _
var redsocksProcess: GuardedProcess = _
var pdnsdProcess: GuardedProcess = _
var su: Shell.Interactive = _
def startShadowsocksDaemon() {
if (profile.route != Route.ALL) {
val acl: Array[Array[String]] = profile.route match {
case Route.BYPASS_LAN => Array(getResources.getStringArray(R.array.private_route))
case Route.BYPASS_CHN => Array(getResources.getStringArray(R.array.chn_route))
if (profile.route != Route.ALL && profile.route != Route.GFWLIST) {
val acl: Array[String] = profile.route match {
case Route.BYPASS_LAN => getResources.getStringArray(R.array.private_route)
case Route.BYPASS_CHN => getResources.getStringArray(R.array.chn_route)
case Route.BYPASS_LAN_CHN =>
Array(getResources.getStringArray(R.array.private_route), getResources.getStringArray(R.array.chn_route))
getResources.getStringArray(R.array.private_route) ++ getResources.getStringArray(R.array.chn_route)
case Route.CHINALIST =>
Array("[bypass_all]", "[white_list]") ++ getResources.getStringArray(R.array.chn_route)
}
Utils.printToFile(new File(getApplicationInfo.dataDir + "/acl.list"))(p => {
acl.flatten.foreach(p.println)
acl.foreach(p.println)
})
}
@@ -109,7 +110,10 @@ class ShadowsocksNatService extends BaseService {
if (profile.route != Route.ALL) {
cmd += "--acl"
cmd += (getApplicationInfo.dataDir + "/acl.list")
if (profile.route == Route.GFWLIST)
cmd += (getApplicationInfo.dataDir + "/gfwlist.acl")
else
cmd += (getApplicationInfo.dataDir + "/acl.list")
}
if (BuildConfig.DEBUG) Log.d(TAG, cmd.mkString(" "))
@@ -185,12 +189,23 @@ class ShadowsocksNatService extends BaseService {
def startDnsDaemon() {
val conf = if (profile.route == Route.BYPASS_CHN || profile.route == Route.BYPASS_LAN_CHN) {
ConfigUtils.PDNSD_DIRECT.formatLocal(Locale.ENGLISH, getApplicationInfo.dataDir,
"127.0.0.1", profile.localPort + 53, getBlackList, profile.localPort + 63, "")
} else {
ConfigUtils.PDNSD_LOCAL.formatLocal(Locale.ENGLISH, getApplicationInfo.dataDir,
"127.0.0.1", profile.localPort + 53, profile.localPort + 63, "")
val conf = profile.route match {
case Route.BYPASS_CHN | Route.BYPASS_LAN_CHN => {
ConfigUtils.PDNSD_DIRECT.formatLocal(Locale.ENGLISH, getApplicationInfo.dataDir,
"127.0.0.1", profile.localPort + 53, getBlackList, profile.localPort + 63, "")
}
case Route.GFWLIST => {
ConfigUtils.PDNSD_UDP.formatLocal(Locale.ENGLISH, getApplicationInfo.dataDir,
"127.0.0.1", profile.localPort + 53, "1.2.4.8, 208.67.222.222", profile.localPort + 63, "")
}
case Route.CHINALIST => {
ConfigUtils.PDNSD_UDP.formatLocal(Locale.ENGLISH, getApplicationInfo.dataDir,
"127.0.0.1", profile.localPort + 53, "8.8.8.8, 208.67.222.222", profile.localPort + 63, "")
}
case _ => {
ConfigUtils.PDNSD_LOCAL.formatLocal(Locale.ENGLISH, getApplicationInfo.dataDir,
"127.0.0.1", profile.localPort + 53, profile.localPort + 63, "")
}
}
Utils.printToFile(new File(getApplicationInfo.dataDir + "/pdnsd-nat.conf"))(p => {
@@ -299,23 +314,15 @@ class ShadowsocksNatService extends BaseService {
su.addCommand((init_sb ++ http_sb).toArray)
}
override def startRunner(profile: Profile) = if (su == null) {
override def startRunner(profile: Profile) = if (su == null)
su = new Shell.Builder().useSU().setWantSTDERR(true).setWatchdogTimeout(10).open((_, exitCode, _) =>
if (exitCode == 0) super.startRunner(profile) else {
if (su != null) {
Log.wtf(TAG, "libsuperuser#55 has been fixed. Please remove the redundant code.")
su.close()
su = null
}
super.stopRunner(true, getString(R.string.nat_no_root))
})
su.waitForIdle()
if (!su.isRunning) {
su.close()
su = null
super.stopRunner(true, getString(R.string.nat_no_root))
}
}
override def connect() {
super.connect()
@@ -19,7 +19,7 @@ class ShadowsocksNotification(private val service: BaseService, profileName: Str
private val keyGuard = service.getSystemService(Context.KEYGUARD_SERVICE).asInstanceOf[KeyguardManager]
private lazy val nm = service.getSystemService(Context.NOTIFICATION_SERVICE).asInstanceOf[NotificationManager]
private lazy val callback = new Stub {
override def stateChanged(state: Int, msg: String) = () // ignore
override def stateChanged(state: Int, profileName: String, msg: String) = () // ignore
override def trafficUpdated(txRate: Long, rxRate: Long, txTotal: Long, rxTotal: Long) {
val txr = TrafficMonitor.formatTraffic(txRate)
val rxr = TrafficMonitor.formatTraffic(rxRate)
@@ -68,7 +68,7 @@ class ShadowsocksQuickSwitchActivity extends AppCompatActivity {
profilesList.setItemAnimator(new DefaultItemAnimator)
profilesList.setAdapter(profilesAdapter)
if (app.profileId >= 0) lm.scrollToPosition(profilesAdapter.profiles.zipWithIndex.collectFirst {
case (profile, i) if profile.id == app.profileId => i + 1
case (profile, i) if profile.id == app.profileId => i
}.getOrElse(0))
}
}
@@ -155,7 +155,7 @@ class ShadowsocksSettings extends PreferenceFragment with OnSharedPreferenceChan
}
switch.setChecked(BootReceiver.getEnabled(activity))
val tfo = findPreference("tcp_fastopen").asInstanceOf[SwitchPreference]
val tfo = findPreference(Key.tfo).asInstanceOf[SwitchPreference]
tfo.setChecked(TcpFastOpen.sendEnabled)
tfo.setOnPreferenceChangeListener((_, v) => {
val value = v.asInstanceOf[Boolean]
@@ -207,7 +207,19 @@ class ShadowsocksSettings extends PreferenceFragment with OnSharedPreferenceChan
}
def refreshProfile() {
profile = app.currentProfile.get
profile = app.currentProfile match {
case Some(p) => p
case None =>
app.profileManager.getFirstProfile match {
case Some(p) =>
app.profileId(p.id)
p
case None =>
val default = app.profileManager.createDefault()
app.profileId(default.id)
default
}
}
isProxyApps.setChecked(profile.proxyApps)
}
@@ -5,7 +5,6 @@ import android.graphics.drawable.Icon
import android.service.quicksettings.{Tile, TileService}
import com.github.shadowsocks.aidl.IShadowsocksServiceCallback
import com.github.shadowsocks.utils.{State, Utils}
import com.github.shadowsocks.ShadowsocksApplication.app
/**
* @author Mygod
@@ -23,7 +22,7 @@ final class ShadowsocksTileService extends TileService with ServiceBoundContext
private lazy val iconConnected = Icon.createWithResource(this, R.drawable.ic_start_connected)
private lazy val callback = new IShadowsocksServiceCallback.Stub {
def trafficUpdated(txRate: Long, rxRate: Long, txTotal: Long, rxTotal: Long) = ()
def stateChanged(state: Int, msg: String) {
def stateChanged(state: Int, profileName: String, msg: String) {
val tile = getQsTile
if (tile != null) {
state match {
@@ -33,10 +32,7 @@ final class ShadowsocksTileService extends TileService with ServiceBoundContext
tile.setState(Tile.STATE_INACTIVE)
case State.CONNECTED =>
tile.setIcon(iconConnected)
tile.setLabel(app.currentProfile match {
case Some(profile) => profile.name
case None => getString(R.string.app_name)
})
tile.setLabel(if (profileName == null) getString(R.string.app_name) else profileName)
tile.setState(Tile.STATE_ACTIVE)
case _ =>
tile.setIcon(iconBusy)
@@ -48,7 +44,7 @@ final class ShadowsocksTileService extends TileService with ServiceBoundContext
}
}
override def onServiceConnected() = callback.stateChanged(bgService.getState, null)
override def onServiceConnected() = callback.stateChanged(bgService.getState, bgService.getProfileName, null)
override def onCreate {
super.onCreate
@@ -40,9 +40,9 @@
package com.github.shadowsocks
import java.io.File
import java.lang.Process
import java.util.Locale
import android.annotation.SuppressLint
import android.content._
import android.content.pm.PackageManager.NameNotFoundException
import android.net.VpnService
@@ -63,10 +63,10 @@ class ShadowsocksVpnService extends VpnService with BaseService {
var vpnThread: ShadowsocksVpnThread = _
private var notification: ShadowsocksNotification = _
var sslocalProcess: Process = _
var sstunnelProcess: Process = _
var pdnsdProcess: Process = _
var tun2socksProcess: Process = _
var sslocalProcess: GuardedProcess = _
var sstunnelProcess: GuardedProcess = _
var pdnsdProcess: GuardedProcess = _
var tun2socksProcess: GuardedProcess = _
override def onBind(intent: Intent): IBinder = {
val action = intent.getAction
@@ -226,15 +226,17 @@ class ShadowsocksVpnService extends VpnService with BaseService {
}
def startShadowsocksDaemon() {
if (profile.route != Route.ALL) {
val acl: Array[Array[String]] = profile.route match {
case Route.BYPASS_LAN => Array(getResources.getStringArray(R.array.private_route))
case Route.BYPASS_CHN => Array(getResources.getStringArray(R.array.chn_route))
if (profile.route != Route.ALL && profile.route != Route.GFWLIST) {
val acl: Array[String] = profile.route match {
case Route.BYPASS_LAN => getResources.getStringArray(R.array.private_route)
case Route.BYPASS_CHN => getResources.getStringArray(R.array.chn_route)
case Route.BYPASS_LAN_CHN =>
Array(getResources.getStringArray(R.array.private_route), getResources.getStringArray(R.array.chn_route))
getResources.getStringArray(R.array.private_route) ++ getResources.getStringArray(R.array.chn_route)
case Route.CHINALIST =>
Array("[bypass_all]", "[white_list]") ++ getResources.getStringArray(R.array.chn_route)
}
Utils.printToFile(new File(getApplicationInfo.dataDir + "/acl.list"))(p => {
acl.flatten.foreach(p.println)
acl.foreach(p.println)
})
}
@@ -263,7 +265,10 @@ class ShadowsocksVpnService extends VpnService with BaseService {
if (profile.route != Route.ALL) {
cmd += "--acl"
cmd += (getApplicationInfo.dataDir + "/acl.list")
if (profile.route == Route.GFWLIST)
cmd += (getApplicationInfo.dataDir + "/gfwlist.acl")
else
cmd += (getApplicationInfo.dataDir + "/acl.list")
}
if (TcpFastOpen.sendEnabled) cmd += "--fast-open"
@@ -303,11 +308,20 @@ class ShadowsocksVpnService extends VpnService with BaseService {
def startDnsDaemon() {
val ipv6 = if (profile.ipv6) "" else "reject = ::/0;"
val conf = {
if (profile.route == Route.BYPASS_CHN || profile.route == Route.BYPASS_LAN_CHN) {
val conf = profile.route match {
case Route.BYPASS_CHN | Route.BYPASS_LAN_CHN => {
ConfigUtils.PDNSD_DIRECT.formatLocal(Locale.ENGLISH, getApplicationInfo.dataDir,
"0.0.0.0", profile.localPort + 53, getBlackList, profile.localPort + 63, ipv6)
} else {
}
case Route.GFWLIST => {
ConfigUtils.PDNSD_UDP.formatLocal(Locale.ENGLISH, getApplicationInfo.dataDir,
"0.0.0.0", profile.localPort + 53, "1.2.4.8, 208.67.222.222", profile.localPort + 63, "")
}
case Route.CHINALIST => {
ConfigUtils.PDNSD_UDP.formatLocal(Locale.ENGLISH, getApplicationInfo.dataDir,
"0.0.0.0", profile.localPort + 53, "8.8.8.8, 208.67.222.222", profile.localPort + 63, ipv6)
}
case _ => {
ConfigUtils.PDNSD_LOCAL.formatLocal(Locale.ENGLISH, getApplicationInfo.dataDir,
"0.0.0.0", profile.localPort + 53, profile.localPort + 63, ipv6)
}
@@ -322,6 +336,7 @@ class ShadowsocksVpnService extends VpnService with BaseService {
pdnsdProcess = new GuardedProcess(cmd).start()
}
@SuppressLint(Array("NewApi"))
def startVpn(): Int = {
val builder = new Builder()
@@ -329,7 +344,8 @@ class ShadowsocksVpnService extends VpnService with BaseService {
.setSession(profile.name)
.setMtu(VPN_MTU)
.addAddress(PRIVATE_VLAN.formatLocal(Locale.ENGLISH, "1"), 24)
.addDnsServer("8.8.8.8")
builder.addDnsServer("8.8.8.8")
if (profile.ipv6) {
builder.addAddress(PRIVATE_VLAN6.formatLocal(Locale.ENGLISH, "1"), 126)
@@ -116,7 +116,7 @@ object ConfigUtils {
|
|server {
| label = "china-servers";
| ip = 114.114.114.114, 112.124.47.27;
| ip = 1.2.4.8, 208.67.222.222, 114.114.114.114;
| timeout = 4;
| exclude = %s;
| policy = included;
@@ -141,6 +141,47 @@ object ConfigUtils {
| soa=localhost,root.localhost,42,86400,900,86400,86400;
|}
""".stripMargin
val PDNSD_UDP =
"""
|global {
| perm_cache = 2048;
| cache_dir = "%s";
| server_ip = %s;
| server_port = %d;
| query_method = udp_tcp;
| run_ipv4 = on;
| min_ttl = 15m;
| max_ttl = 1w;
| timeout = 10;
| daemon = off;
|}
|
|server {
| label = "remote-servers";
| ip = %s;
| timeout = 5;
| uptest = none;
| preset = on;
|}
|
|server {
| label = "local-server";
| ip = 127.0.0.1;
| port = %d;
| %s
| reject_policy = negate;
| reject_recursively = on;
|}
|
|rr {
| name=localhost;
| reverse=on;
| a=127.0.0.1;
| owner=localhost;
| soa=localhost,root.localhost,42,86400,900,86400,86400;
|}
""".stripMargin
}
object Key {
@@ -171,6 +212,9 @@ object Key {
val kcp = "kcp"
val kcpPort = "kcpPort"
val kcpcli = "kcpcli"
val tfo = "tcp_fastopen"
val currentVersionCode = "currentVersionCode"
}
object State {
@@ -192,4 +236,6 @@ object Route {
val BYPASS_LAN = "bypass-lan"
val BYPASS_CHN = "bypass-china"
val BYPASS_LAN_CHN = "bypass-lan-china"
val GFWLIST = "gfwlist"
val CHINALIST = "china-list"
}
@@ -28,23 +28,13 @@ object TcpFastOpen {
file.canRead && (Utils.readAllLines(file).toInt & 1) > 0
}
def enabled(value: Boolean) =
Shell.run("su", Array(
def enabled(value: Boolean): String = if (sendEnabled != value) {
val res = Shell.run("su", Array(
"if echo " + (if (value) 3 else 0) + " > /proc/sys/net/ipv4/tcp_fastopen; then",
" success=-1",
" if mount -o rw,remount /dev/block/platform/msm_sdcc.1/by-name/system /system; then",
if (value) " echo '#!/system/bin/sh\n" +
"echo 3 > /proc/sys/net/ipv4/tcp_fastopen' > /etc/init.d/tcp_fastopen && chmod 755 /etc/init.d/tcp_fastopen"
else "rm -f /etc/init.d/tcp_fastopen",
" success=$?",
" mount -o ro,remount /dev/block/platform/msm_sdcc.1/by-name/system /system",
" fi",
" if [ $success -eq 0 ]; then",
" echo Success.",
" else",
" echo Warning: Unable to create boot script.",
" fi",
" echo Success.",
"else",
" echo Failed.",
"fi"), null, true).asScala.mkString("\n")
"fi"), null, true)
if (res != null) res.asScala.mkString("\n") else null
} else null
}